2012-07-12 174 views
2

我必须将数据复制出一个System.Drawing.Bitmap它看起来像这样的方法:System.Drawing.Bitmap包含更多的数据比预期

var readLock = image.LockBits(new Rectangle(0, 0, image.Width, image.Height), ImageLockMode.ReadOnly, PixelFormat.Format24bppRgb); 
byte[] data = new byte[3 * image.Width * image.Height]; 
if (data.Length != readLock.Stride * readLock.Height) 
    throw new InvalidOperationException("Incorrect number of bytes"); 
Marshal.Copy(readLock.Scan0, data , 0, data.Length); 
image.UnlockBits(readLock); 

相当简单的,它适用于大多数的我的图片。然而,对于非常小的图像(14x14),它会遇到例外。在失败的情况下,步幅为44,而不是预期的42(14 * 3)。

像素格式是Format24bppRgb,因此图像中每个像素应该有三个字节。这些额外的字节来自哪里,在处理图像数据时如何处理它们?

对于任何有兴趣的人,我从高度图生成Normal数据,所以我需要能够准确地获取每个像素及其邻居。

回答

4

Bitmap的每个像素行都必须对齐,这就是为什么stride并不总是width * bytes-per-pixel。你应该忽略任何额外的字节。这意味着如果您使用的是未对齐数据的字节数组,则可能无法始终以单个Marshal.Copy()调用复制所有图像数据。每行像素开始于readLock.Scan0 + y * readLock.Stride并包含readLock.Width * bytes-per-pixel有意义的字节。

解决方案:

const int BYTES_PER_PIXEL = 3; 
var data = new byte[readLock.Width * readLock.Height * BYTES_PER_PIXEL]; 
if(readLock.Stride == readLock.Width * BYTES_PER_PIXEL) 
{ 
    Marshal.Copy(readLock.Scan0, data, 0, data.Length); 
} 
else 
{ 
    for(int y = 0; y < readLock.Height; ++y) 
    { 
     IntPtr startOfLine = (IntPtr)((long)readLock.Scan0 + (readLock.Stride * y)); 
     int dataOffset = y * readLock.Width * BYTES_PER_PIXEL; 
     Marshal.Copy(startOfLine, data, dataOffset, readLock.Width * BYTES_PER_PIXEL); 
    } 
} 
+0

所以,如果我发现这种情况下,我应该回落到其采用每行1个Marshal.Copy副本,每次复制readLock.Width *字节-BER像素? – Martin 2012-07-12 02:01:14

+0

是的。我已经添加了应该工作的代码示例。 – max 2012-07-12 02:03:53

+0

非常好,非常感谢! – Martin 2012-07-12 02:05:31

相关问题