将位图数据复制到Int32数组时发生访问冲突

时间:2011-12-20 05:03:49

标签: c# bitmap bitmapdata

我想将24位彩色位图数据复制到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

    }

但是我遇到了访问冲突异常。

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

有人可以帮我纠正这个错误吗?

2 个答案:

答案 0 :(得分:2)

问题是具有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 :(得分:1)

你超越了fileBufferArray。看看这种更通用的方法是否可以帮助您。 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;
}

使用流来获取字节数组还有更安全的方法:

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