【问题标题】:System.Drawing.Bitmap contains more data than expectedSystem.Drawing.Bitmap 包含比预期更多的数据
【发布时间】:2012-07-12 10:03:33
【问题描述】:

我有一种方法可以从 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),它会遇到异常。在失败的情况下,Stride 是 44,而不是预期的 42 (14 * 3)。

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

对于任何感兴趣的人,我正在从高度图生成法线数据,因此我需要能够准确地获取每个像素及其邻居)。

【问题讨论】:

    标签: c# graphics gdi+


    【解决方案1】:

    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);
        }
    }
    

    【讨论】:

    • 所以如果我检测到这种情况,我应该回退到每行使用 1 个 Marshal.Copy 的副本,每次都复制 readLock.Width * bytes-ber-pixel?
    • 我假设同样的逻辑也适用于将数据复制到图像中?
    猜你喜欢
    • 2019-09-19
    • 1970-01-01
    • 1970-01-01
    • 2020-10-14
    • 2020-12-18
    • 1970-01-01
    • 2018-11-05
    • 1970-01-01
    • 2012-10-01
    相关资源
    最近更新 更多