比较 16 bpp 到 32 bpp 位图转换
Compare 16 bpp to 32 bpp bitmap conversions
我得到了一个 16 bpp 的位图 ,我通过以下代码将其转换为 32 bpp:
void Rgb555ToRgb8(const UChar* bitmapData, UInt32 width, UInt32 height, UChar* buf)
{
UInt32 dst_bytes_per_row = width * 4;
UInt32 src_bytes_per_row = ((width * 16 + 31) / 32) * 4;
UInt16 red_mask = 0x7C00;
UInt16 green_mask = 0x3E0;
UInt16 blue_mask = 0x1F;
for (UInt32 row = 0; row < height; ++row)
{
UInt32 dstCol = 0, srcCol = 0;
do
{
UInt16 rgb = *(UInt16*)(bitmapData + row * src_bytes_per_row + srcCol);
UChar red_value = (rgb & red_mask) >> 10;
UChar green_value = (rgb & green_mask) >> 5;
UChar blue_value = (rgb & blue_mask);
buf[row*dst_bytes_per_row + dstCol] = blue_value << 3;
buf[row*dst_bytes_per_row + dstCol + 1] = green_value << 3;
buf[row*dst_bytes_per_row + dstCol + 2] = red_value << 3;
buf[row*dst_bytes_per_row + dstCol + 3] = rgb >> 15;
srcCol += 2;
dstCol += 4;
} while (srcCol < src_bytes_per_row);
}
}
转换结果如下:[2]: https://i.stack.imgur.com/1ajO7.png
我还尝试通过 GdiPlus 转换此图像:
Gdiplus::Bitmap* bmp = new Gdiplus::Bitmap(w,h,PixelFormat32bppRGB);
生成的图像是 。
请注意,这 2 个结果看起来并不完全相同(例如,GdiPlus 结果中的背景是白色的)。如何修改我的代码以匹配 GdiPlus 结果?
有两个问题需要解决:
未使用的位
当从 5 位信息移动到 8 位信息时,您将获得额外的 3 位信息。实施时,代码不使用该额外范围,并且偏向于较暗的颜色分量。这是 blue_value << 3
实际作用的说明:
5 bits per channel 8 bits per channel
bbbbb -> bbbbb000
为了解决这个问题,最低有效的 3 位需要随着通道值变高而增长。一个简单的(但 somewhat inaccurate)就是将最高有效的 3 位复制到最低有效的 3 位,即
buf[row*dst_bytes_per_row + dstCol] = (blue_value << 3) | (blue_value >> 2);
buf[row*dst_bytes_per_row + dstCol + 1] = (green_value << 3) | (green_value >> 2);
buf[row*dst_bytes_per_row + dstCol + 2] = (red_value << 3) | (red_value >> 2);
确切的映射会更复杂一些,比如
blue_value = static_cast<UChar>((blue_value * 255.0) / 31.0 + 0.5);
从 5 位转换为最接近理想值的相应 8 位值,包括在上述位移解决方案中相差 1/255 的 4 个值。
如果您选择后者,您可以构建一个存储映射值的查找 table。这个 table 只有 32 个条目,每个条目一个字节,所以它适合一个缓存行。
Alpha 通道
假设源图像的 MSB 确实被解释为 alpha 值,您也将把它移到目标中。由于源只有 1 位信息,原始转换很简单:
buf[row*dst_bytes_per_row + dstCol + 3] = rgb & (1 << 15) ? 255 : 0;
这可能是也可能不是所需要的全部。 Windows 假定预乘 alpha,即颜色通道的存储值必须预乘 alpha 值(请参阅 BLENDFUNCTION 以供参考)。
如果 alpha 值为 255,则颜色通道值已经正确。如果 alpha 值为 0,则所有颜色通道都需要乘以零(或简单地设置为 0)。翻译不会产生任何其他 alpha 值。
我得到了一个 16 bpp 的位图
void Rgb555ToRgb8(const UChar* bitmapData, UInt32 width, UInt32 height, UChar* buf)
{
UInt32 dst_bytes_per_row = width * 4;
UInt32 src_bytes_per_row = ((width * 16 + 31) / 32) * 4;
UInt16 red_mask = 0x7C00;
UInt16 green_mask = 0x3E0;
UInt16 blue_mask = 0x1F;
for (UInt32 row = 0; row < height; ++row)
{
UInt32 dstCol = 0, srcCol = 0;
do
{
UInt16 rgb = *(UInt16*)(bitmapData + row * src_bytes_per_row + srcCol);
UChar red_value = (rgb & red_mask) >> 10;
UChar green_value = (rgb & green_mask) >> 5;
UChar blue_value = (rgb & blue_mask);
buf[row*dst_bytes_per_row + dstCol] = blue_value << 3;
buf[row*dst_bytes_per_row + dstCol + 1] = green_value << 3;
buf[row*dst_bytes_per_row + dstCol + 2] = red_value << 3;
buf[row*dst_bytes_per_row + dstCol + 3] = rgb >> 15;
srcCol += 2;
dstCol += 4;
} while (srcCol < src_bytes_per_row);
}
}
转换结果如下:[2]: https://i.stack.imgur.com/1ajO7.png
我还尝试通过 GdiPlus 转换此图像:
Gdiplus::Bitmap* bmp = new Gdiplus::Bitmap(w,h,PixelFormat32bppRGB);
生成的图像是
请注意,这 2 个结果看起来并不完全相同(例如,GdiPlus 结果中的背景是白色的)。如何修改我的代码以匹配 GdiPlus 结果?
有两个问题需要解决:
未使用的位
当从 5 位信息移动到 8 位信息时,您将获得额外的 3 位信息。实施时,代码不使用该额外范围,并且偏向于较暗的颜色分量。这是 blue_value << 3
实际作用的说明:
5 bits per channel 8 bits per channel
bbbbb -> bbbbb000
为了解决这个问题,最低有效的 3 位需要随着通道值变高而增长。一个简单的(但 somewhat inaccurate)就是将最高有效的 3 位复制到最低有效的 3 位,即
buf[row*dst_bytes_per_row + dstCol] = (blue_value << 3) | (blue_value >> 2);
buf[row*dst_bytes_per_row + dstCol + 1] = (green_value << 3) | (green_value >> 2);
buf[row*dst_bytes_per_row + dstCol + 2] = (red_value << 3) | (red_value >> 2);
确切的映射会更复杂一些,比如
blue_value = static_cast<UChar>((blue_value * 255.0) / 31.0 + 0.5);
从 5 位转换为最接近理想值的相应 8 位值,包括在上述位移解决方案中相差 1/255 的 4 个值。
如果您选择后者,您可以构建一个存储映射值的查找 table。这个 table 只有 32 个条目,每个条目一个字节,所以它适合一个缓存行。
Alpha 通道
假设源图像的 MSB 确实被解释为 alpha 值,您也将把它移到目标中。由于源只有 1 位信息,原始转换很简单:
buf[row*dst_bytes_per_row + dstCol + 3] = rgb & (1 << 15) ? 255 : 0;
这可能是也可能不是所需要的全部。 Windows 假定预乘 alpha,即颜色通道的存储值必须预乘 alpha 值(请参阅 BLENDFUNCTION 以供参考)。
如果 alpha 值为 255,则颜色通道值已经正确。如果 alpha 值为 0,则所有颜色通道都需要乘以零(或简单地设置为 0)。翻译不会产生任何其他 alpha 值。