使用
LockBits
和
Marshal.Copy
是从图像中获取图像数据的最快方法。
我
强烈建议不要使用
GetPixel
。你需要知道,
LockBits
通过保留内存来放置图像的字节并将图像的字节复制到其中。然后,
UnlockBits
将清除该保留的内存。
现在,问题是,
GetPixel
对于每个访问的像素执行相同的锁定和解锁操作。使用 LockBits 一次相当快,但是为了数万个像素而一遍又一遍地使用它会使速度变慢。
请注意,有两种使用
LockBits
的方式;或者你使用
sourceImage.PixelFormat
获取原始像素格式的数据,或者你使用 LockBits
转换 数据以满足你的需求,通过提供不同的像素格式。在这段代码中,我强制输出像素格式为
Format32bppArgb
。
public static Byte[] GetImageDataAs32bppArgb(Bitmap sourceImage)
{
BitmapData sourceData = sourceImage.LockBits(
new Rectangle(0, 0, sourceImage.Width, sourceImage.Height),
ImageLockMode.ReadOnly, PixelFormat.Format32bppArgb);
Byte[] data = new Byte[sourceData.Stride * sourceImage.Height];
Marshal.Copy(sourceData.Scan0, data, 0, data.Length);
sourceImage.UnlockBits(sourceData);
return data;
}
Stride
通常与width * bpp
不同,因为位图的行始终对齐到4字节的倍数,因此通常需要返回它并跟踪它,但由于这是32位格式,其数据始终对齐到4字节,因此实际上没有差异。
请注意,您的问题从未指定您需要数据的顺序。典型的ARGB数据实际上按字节顺序B、G、R、A排列,因为IBM PC架构上的正常整数保存是小端序,这意味着Int32值“FFEEDDCC”的实际字节在内存中被反转为[CC DD EE FF]。但是,您在这里给出的另一个答案的评论似乎表明您选择了字节顺序[RR,GG,BB,AA]或“ABGR”,这是我从未见过的格式。但是,如果您确实需要更改它,只需添加一个简单的额外循环来交换红色和蓝色即可:
for (Int32 i = 0; i < data.Length; i += 4)
{
Byte b = data[i];
data[i] = data[i + 2];
data[i + 2] = b;
}
Bitmap bitmap = new Bitmap("somefile.ext");
byte[] data = nbyte[imgLength]; int pixelPosition = 0; for (int i = 0; i < img.Width; i++) { for (int j = 0; j < img.Height; j++) { Color pixel = img.GetPixel(i, j); data[pixelPosition] = pixel.R; data[pixelPosition + 1] = pixel.G; data[pixelPosition + 2] = pixel.B; data[pixelPosition + 3] = pixel.A; pixelPosition = pixelPosition + 4; } } - Dileep