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

根据规范, colored颜色 的每个分量为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.有没有其他位操作技巧来实现这一点,或者我只是为了改变 colored颜色 空间而被迫将每个数字转换为浮点?

推荐答案

不仅可以避免浮点转换,还可以避免乘法和除法.从implementation年款开始:

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是字节数组,如果您使用我的drawing libraries,则有一个更方便的选项:

// 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

Csharp相关问答推荐

下拉图片点击MudBlazor

如何使用Unity和MRTK3将手网添加到Hololens 2应用程序中

如何在没有额外副本的情况下将存储在IntPtr下的原始图像数据写入WinUI3中的Image控件?

Azure DEVOPS找不到定制的Nuget包

从c#列表中删除额外的对象&对象&>从ASP.NET WebForm返回json响应

如何使datagridview的列具有响应性,以便不是所有列都更改其宽度

获取具有AutoFaces的所有IOptions对象的集合

如何使用NumberFormatInfo

单元测试:模拟返回空

net中从位图获取坐标和绘制折线

带有可选参数的模拟方法返回意外的不同值,具体取决于可选的默认值

如何在CSharp中将json字符串转换为DataTable?

Google OAuth令牌交换在.Net中不起作用

将操作从编辑页重定向到带参数的索引页

C#静态抽象属性不能被子接口覆盖

Maui:更改代码中的绑定字符串不会更新UI,除非重新生成字符串(MVVM)

使用LibraryImport在多个dll中导入相同的函数

C#If条件格式

使用';UnityEngineering.Random.Range()';的IF语句仅适用于极高的最大值

现在是否有一个.NET SDK等效于AsyncEx的AsyncLock?