【问题标题】:Compare 16 bpp to 32 bpp bitmap conversions比较 16 bpp 和 32 bpp 位图转换
【发布时间】:2021-07-11 13:10:33
【问题描述】:

我得到了一个 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 结果?

【问题讨论】:

    标签: winapi bitmap gdi+ bmp


    【解决方案1】:

    有两个问题需要解决:

    未使用的位

    当从 5 位信息转移到 8 位信息时,您将获得额外的 3 位。在实现时,代码没有使用那个额外的范围,而是偏向于更深的颜色分量。这是blue_value &lt;&lt; 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 个值。

    如果您选择后者,您可以构建一个存储映射值的查找表。该表只有 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 值。

    【讨论】:

      猜你喜欢
      • 2023-03-23
      • 2011-01-31
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-10-11
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多