像素格式 PixelFormat.Format32bppArgb 看起来字节顺序有误

31

我试图从一个位图(System.Drawing.Bitmap)中获取所有的字节值。因此,我锁定了这些字节并将它们复制:

public static byte[] GetPixels(Bitmap bitmap){
    if(bitmap-PixelFormat.Equals(PixelFormat.Format32.bppArgb)){
        var argbData = new byte[bitmap.Width*bitmap.Height*4];
        var bd = bitmap.LockBits(new Rectangle(0, 0, image.Width, image.Height), ImageLockMode.ReadOnly, bitmap.PixelFormat);
        System.Runtime.InteropServices.Marshal.Copy(bd.Scan0, argbData, 0, bitmap.Width * bitmap.Height * 4);
        bitmap.UnlockBits(bd);
    }
}

我用 Photoshop 制作了一个非常简单的 2x2 PNG 图像,其中包含像素 (红色,绿色,蓝色,白色),并对该图像进行了测试。由于格式的原因,我期望 argbData 中包含以下值:

255 255   0   0    255 0   255   0 
255 0     0 255    255 255 255 255 

但我得到了:

0     0 255 255     0 255   0 255
255   0   0 255   255 255 255 255

但这是BGRA格式。有人知道为什么字节似乎被交换了吗?另外,当我直接将图像用作Image.Source时,图像显示正确。那我的问题出在哪里呢?

<Image Source="D:/tmp/test2.png"/>
3个回答

57

像你的机器和许多其他机器一样,像素数据为ARGB,其中alpha占1个字节,红色占1个字节,绿色占1个字节,蓝色占1个字节。 alpha是最重要的字节,blue是最不重要的字节。在小端机器上,如您的计算机和许多其他计算机,小端先存储,因此字节顺序为bb gg rr aa。因此,0 0 255 255等于蓝色= 0,绿色= 0,红色= 255,alpha = 255。 这是红色。

当你将bd.Scan0转换为int*(指向整数的指针)时,这种大小端序的细节就消失了,因为整数也是按小端序存储的。


6
太好了!我只想补充一点,您可以通过BitConverter.IsLittleEndian字段来检查此计算机体系结构中数据存储的字节顺序(“字节序”)。 - DmitryG
3
这是关于BitConverter.IsLittleEndian的一个很好的观点,但我认为@HansPassant关于字节序的评论真的很有价值 - 这是另一个不应该考虑字节序的地方。这里有一篇关于这个主题的很棒的文章。 - Jonno

3

Bpp32Argb像素格式中,您不需要逐字节访问。

在不安全的上下文中将Scan0转换为Int32指针。

unsafe
{
    var ptr=(int*)bmData.Scan0;
}

您可以通过以下方式进行一些位操作,以访问第一个像素的颜色通道。

而且不需要考虑字节顺序。

var a=(ptr[0] & 0xFF000000)>>24;
var r=(ptr[0] & 0x00FF0000)>>16;
var g=(ptr[0] & 0x0000FF00)>>8;
var b=(ptr[0] & 0x000000FF);

顺便提一下,你可以轻松地使用Color.ToArgb()返回的int进行操作。


3
已经有答案提到了这一点,但是不幸的是,在某些情况下您不能使用不安全代码。例如,我曾在几家公司工作过,这些公司完全不允许使用不安全代码。 - 0xBADF00D
2
我很高兴你提到了ToArgb() - 这节省了我不少时间。 :) - Eric

2

如果我理解这个页面正确,那么每次读取 RGB 值时,它不表示真正的字节顺序。它总是代表 BGR 吗?还是有一种标志可以指示这一点? - 0xBADF00D

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接