нарушение прав доступа при копировании растровых данных в массив Int32 - PullRequest
0 голосов
/ 20 декабря 2011

Я хочу скопировать 24-битные данные цвета Bitmap в массив Int32, и я написал следующий код, чтобы сделать это.

Width of image = 200 pixels
Height of image = 150 pixels

 public static Int32[] readBitmap()
    {

        int rows = 150;
        int columns = 200;

        Bitmap myBmp = new Bitmap("puppy.bmp");
        BitmapData bmd = myBmp.LockBits(new Rectangle(0, 0, columns, rows), ImageLockMode.ReadWrite, myBmp.PixelFormat); 
        Console.WriteLine(myBmp.PixelFormat.ToString());

        int fileSize = 30000; // 200 * 150

        Int32[] fileBufferArray = new Int32[fileSize];

        unsafe
        {
            for (int j = 0; j < rows; j++)
            {

                Int32* row = (Int32*)bmd.Scan0 + (j * bmd.Stride);                

                for (int i = 0; i < columns; i++)
                {                    

                        try
                        {
                            fileBufferArray[j * columns + i] = row[i];
                        }
                        catch (Exception e)
                        {
                            Console.WriteLine(e.ToString() + " " + i.ToString() + " " + j.ToString());
                            break;

                        }                       
                }

            }

            myBmp.UnlockBits(bmd);

            return fileBufferArray;

        } //unsafe

    }

Но я получаю исключение нарушения доступа.

Может ли кто-нибудь помочь мне исправить эту ошибку?

Ответы [ 2 ]

2 голосов
/ 20 декабря 2011

Проблема заключается в том, что для растрового изображения, имеющего 30 000 пикселей, требуется 3 * 30 000 байтов для представления в 24-битном цвете.Каждый пиксель представлен тремя байтами.Ваш цикл копирует байты в целые числа.А поскольку ваш целочисленный массив имеет длину всего 30 000 целых чисел, он потерпит неудачу.

Это если вы написали:

var fileBufferArray = new int[30000];
for (int i = 0; i < 90000; ++i)
{
    fileBufferArray[i] = bitmapData[i];
}

Очевидно, что это не удастся.

Вам нужно объединить каждые три байта в одно 24-битное значение.Один из способов сделать это - изменить присваивание во внутреннем цикле следующим образом:

int r = i * 3;
int pixelvalue = row[r];
pixelValue = (pixelValue << 8) | row[r+1];
pixelValue = (pixelValue << 8) | row[r+2];
fileBufferArray[j * columns + i] = pixelValue;

Это не самый краткий и не самый эффективный способ сделать это, но он иллюстрирует концепцию.Я также не мог бы иметь порядок значений правильно.Они могут быть сохранены с младшим байтом, а не старшим байтом.Несмотря на это, концепция одна и та же.

1 голос
/ 20 декабря 2011

Вы переполнены файлом BufferArray. Посмотрите, может ли этот более общий подход помочь вам. Источник :

private unsafe byte[] BmpToBytes_Unsafe (Bitmap bmp)
{
    BitmapData bData = bmp.LockBits(new Rectangle (new Point(), bmp.Size),
        ImageLockMode.ReadOnly, 
        PixelFormat.Format24bppRgb);
    // number of bytes in the bitmap
    int byteCount = bData.Stride * bmp.Height;
    byte[] bmpBytes = new byte[byteCount];

    // Copy the locked bytes from memory
    Marshal.Copy (bData.Scan0, bmpBytes, 0, byteCount);

    // don't forget to unlock the bitmap!!
    bmp.UnlockBits (bData);

    return bmpBytes;
}

Существуют также более безопасные способы получения байтового массива с использованием потоков:

private byte[] BmpToBytes(Bitmap bmp)
{
    MemoryStream ms = new MemoryStream();
    // Save to memory using the bmp format
    bmp.Save (ms, ImageFormat.Bmp);

    // read to end
    byte[] bmpBytes = ms.GetBuffer();
    bmp.Dispose();
    ms.Close();

    return bmpBytes;
}
...