【问题标题】:Extract area from bitmap results in AccessViolationException when using Marshal.Copy使用 Marshal.Copy 时从位图中提取区域导致 AccessViolationException
【发布时间】:2021-12-18 18:15:40
【问题描述】:

我正在尝试从位图中提取特定区域以进行进一步处理。在极少数情况下,调用 Marshal.Copy 时会发生错误。这可以通过以下示例代码重现:

Bitmap bitmap = new Bitmap(1741, 2141, PixelFormat.Format1bppIndexed);

int zoneWidth = 50;
int zoneHeight = 50;
int x = 168;
int y = bitmap.Height - zoneHeight;
Rectangle zone = new Rectangle(x, y, zoneWidth, zoneHeight);

BitmapData bitmapData = bitmap.LockBits(zone, ImageLockMode.ReadOnly, bitmap.PixelFormat);
int byteCount = Math.Abs(bitmapData.Stride) * bitmapData.Height;
byte[] pixels = new byte[byteCount];

Marshal.Copy(bitmapData.Scan0, pixels, 0, byteCount);

// some further processing

bitmap.UnlockBits(bitmapData);

在我读过的其他帖子中,Stride 可能是负面的。这里不是这样。

为什么会发生错误,我该如何预防?


编辑 1:

我已经实施了 JonasH 的第二个建议。但这也因 AccessViolationException 而失败。可能我没有正确地做到这一点。

Bitmap bitmap = new Bitmap(1741, 2141, PixelFormat.Format1bppIndexed);

int zoneWidth = 50;
int zoneHeight = 50;
int zoneX = 168;
int zoneY = bitmap.Height - zoneHeight;
Rectangle zone = new Rectangle(zoneX, zoneY, zoneWidth, zoneHeight);

BitmapData bitmapData = bitmap.LockBits(zone, ImageLockMode.ReadOnly, bitmap.PixelFormat);

int rowSize = Math.Abs(bitmapData.Stride);
byte[] pixels = new byte[bitmapData.Height * rowSize];
IntPtr iptr = bitmapData.Scan0;

for (int y = 0; y < bitmapData.Height; y++)
{
    Marshal.Copy(IntPtr.Add(iptr, y * rowSize),
        pixels,
        y * rowSize,
        rowSize);
}

bitmap.UnlockBits(bitmapData);

【问题讨论】:

    标签: c# memory bitmap marshalling access-violation


    【解决方案1】:

    这可能是因为您只锁定了位图的一部分。用new Rectangle(0, 0, bitmap.Width , bitmap.Height); 替换该区域,我希望您的问题会消失。

    替代方法是将复制操作限制在位图的锁定部分,但这需要逐行复制,而不是一次复制整个位图。

    逐行复制需要谨慎使用偏移量,您需要跟踪源数据和目标数据的水平和垂直偏移量。我认为这样的事情应该可行:

    
    for (int y = 0; y < zoneHeight ; y++)
    {
        Marshal.Copy(
            IntPtr.Add(iptr,(y + zoneY ) * bitmapData.Stride + zoneX)
            pixels,
            y * zoneWidth,
            zoneWidth );
    }
    

    【讨论】:

    • 感谢您的回答。我试图实施你的第二个建议。不幸的是,这也不起作用。
    • @Jens Meyer 您的复制代码本质上仍然是复制整个位图,只是逐行复制。您需要添加偏移量以仅复制感兴趣的区域。添加了一个示例。
    • 对于您的示例,是锁定整个位图还是锁定区域? x 是 ZoneX?
    • @Jens Meyer 我不认为这很重要,因为只访问该区域内的像素。我可能只是因为它更简单而锁定整个图像。是的,x 是 ZoneX。
    • 好的,这对我有用。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-06-15
    • 2021-01-13
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多