简体   繁体   中英

access violation when copying bitmap data into Int32 array

I want to copy a 24 bit Color bitmap data onto a Int32 array and i wrote the following code to do it.

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

    }

But i get a access violation exception.

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

Could someone please help me correct this error ?

The problem is that a bitmap that has 30,000 pixels requires 3 * 30,000 bytes to represent in 24-bit color. Each pixel is represented by three bytes. Your loop is copying bytes to integers. And since your integer array is only 30,000 integers in length, it's going to fail.

It's if you had written:

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

Obviously, that's going to fail.

You need to combine each three bytes into a single 24-bit value. One way to do that would be to change the assignment in your inner loop to:

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;

That's not the most concise or most efficient way to do it, but it illustrates the concept. I also might not have the order of the values right. They might be stored with the low byte first rather than the high byte. Regardless, the concept is the same.

You overrunning fileBufferArray. See if this more generic approach can help you. The source :

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

There is also safer ways to get the byte array using streams:

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM