System.AccessViolationException при попытке скопировать последнюю строку растрового изображения - PullRequest
0 голосов
/ 05 января 2011

Я извлекаю ряды пикселей из изображения в массив int, используя Marshal.Copy. Все работает нормально, пока я не достигну последней строки изображения. Если я попытаюсь извлечь его, я получу хорошее исключение:

System.AccessViolationException: Attempted to read or write protected memory. This is often an indication that other memory is corrupt.

Вот небольшой тестовый пример, который воспроизводит ошибку. Что я делаю не так?

[Test]
public void testMarshalCopy() {
    Bitmap image = new Bitmap("../../TestResources/barcode.jpg");

    int left = 0;
    int top = image.Height - 1;
    int width = image.Width;
    int height = 1;

    Rectangle zone = new Rectangle(left, top, width, height);
    BitmapData data = image.LockBits(zone, System.Drawing.Imaging.ImageLockMode.ReadOnly, image.PixelFormat);

    IntPtr pointer = data.Scan0;
    int[] pixels = new int[width * height];

    Marshal.Copy(pointer, pixels, 0, pixels.Length); // throws System.AccessViolationException

    image.UnlockBits(data);
}

Ответы [ 3 ]

2 голосов
/ 05 января 2011

Вы не учитываете свой формат пикселей при копировании.

Посмотрите на этот пример:

http://msdn.microsoft.com/en-us/library/ms229672(v=vs.80).aspx

Обратите внимание, что они копируют буфер шириной * высотой * 3.

Изображение в этом примере имеет формат RGB, один байт на цветовой канал.

Смотрите эту строку здесь, вверху:

PixelFormat pxf = PixelFormat.Format24bppRgb;

Еще одно редактирование -

Вам также следует обратить внимание на значение Stride растрового изображения.

http://msdn.microsoft.com/en-us/library/system.drawing.imaging.bitmapdata.stride.aspx

1 голос
/ 05 января 2011

Изображение, которое я загружал, использовало Format24bppRgb в качестве формата пикселей.Как сказал Ганс, работа с Format32bppRgb позволяет работать напрямую с int[] вместо byte[].

Я изменил формат пикселя на Format32bppRgb и теперь он работает!

1 голос
/ 05 января 2011

Количество байтов в вашей заблокированной зоне растрового изображения зависит от формата изображения, попытка извлечь больше байтов вызовет исключение. Чтобы упростить задачу, вы можете использовать байтовый массив, который будет работать с любым форматом изображения, но вы должны отрегулировать множитель - в приведенном ниже примере предполагается 3-байтовый (24 бит / с) формат изображения.

        int bytesNeeded =  zone.Width * zone.Height * 3; 
        byte[] pixels = new byte[bytesNeeded];

        Marshal.Copy(pointer, pixels, 0, pixels.Length); 
        image.UnlockBits(data);
...