使用 Marshal.Copy 时从位图中提取区域导致 AccessViolationException

Extract area from bitmap results in AccessViolationException when using Marshal.Copy

我正在尝试从位图中提取特定区域以进行进一步处理。在极少数情况下,调用 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);

这可能是因为您只锁定了位图的一部分。用 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 );
}