繁体   English   中英

有没有办法在避免浮点数学的同时有效地将 16 位颜色转换为 24 位颜色?

[英]Is there a way to convert 16-bit color to 24-bit color efficiently while avoiding floating-point math?

我正在解码一个 .BMP 文件,我正处于需要处理 16 位颜色的地步。 整个代码库使用 32 位颜色(R、G、B、A),因此我需要将颜色转换为 24 位 RGB 值(每种颜色一个字节)。

根据规范,颜色的每个分量都是 5 位(浪费了 1 位)。 我的代码如下:

ushort color = BitConverter.ToUInt16(data, 54 + i);
byte blue  = (byte)((color | 0b0_00000_00000_11111) / 31f * 255);
byte green = (byte)(((color | 0b0_00000_11111_00000) >> 5) / 31f * 255);
byte red   = (byte)(((color | 0b0_11111_00000_00000) >> 10) / 31f * 255);

但是,这似乎并不是特别有效。 我尝试做color << (8 - 5) ,这使过程更快并避免了浮点转换,但它不准确 - 31 (11111) 的值转换为 248。有没有办法实现这一点与其他一些位操作技巧,还是我被迫将每个数字转换为浮点数只是为了改变色彩空间?

不仅可以避免浮点转换,还可以避免乘法和除法。 从我的实现

internal struct Color16Rgb555
{
    private const ushort redMask = 0b01111100_00000000;
    private const ushort greenMask = 0b00000011_11100000;
    private const ushort blueMask = 0b00011111;

    private ushort _value;

    internal Color16Rgb555(ushort value) => _value = value;

    internal byte R => (byte)(((_value & redMask) >> 7) | ((_value & redMask) >> 12));
    internal byte G => (byte)(((_value & greenMask) >> 2) | ((_value & greenMask) >> 7));
    internal byte B => (byte)(((_value & blueMask) << 3) | ((_value & blueMask) >> 2));
}

用法:

var color = new Color16Rgb555(BitConverter.ToUInt16(data, 54 + i));
byte blue  = color.B;
byte green = color.G;
byte red   = color.R;

它为 31 生成 255,因为它用实际 5 位值的 3 个 MSB 位填充了剩余的 3 位。

但是假设你的data是一个字节数组,如果你使用我的绘图库,你有一个更方便的选择:

// to interpret your data array as 16BPP pixels with RGB555 format:
var my16bppBitmap = BitmapDataFactory.CreateBitmapData(
    data, // your back buffer
    new Size(pixelWidth, pixelHeight), // size in pixels
    stride, // the size of one row in bytes
    KnownPixelFormat.Format16bppRgb555);

// now you can get/set pixels normally    
Color somePixel = my16bppBitmap.GetPixel(0, 0);

// For better performance obtain a row first.
var row = my16bppBitmap[0]; // or FirstRow (+MoveNextRow if you wish)
Color32 asColor32 = row[0]; // accessing pixels regardless of PixelFormat
ushort asUInt16 = row.ReadRaw<ushort>(0); // if you know that it's a 16bpp format

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM