2011-12-20 5 views
0

24 비트 Color 비트 맵 데이터를 Int32 배열에 복사하려고하는데 다음 코드를 작성했습니다.비트 맵 데이터를 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

문제는 30,000 픽셀의 비트 맵은 24 비트 색상으로 표현하기 위해 3 * 30,000 바이트가 필요하다는 것입니다. 각 픽셀은 3 바이트로 표시됩니다. 루프가 바이트를 정수로 복사하고 있습니다. 정수 배열은 길이가 30,000 개의 정수이기 때문에 실패 할 것입니다.

그것은 당신이 쓴 경우입니다 :

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

을 분명히, 그 실패 할 것입니다.

각 3 바이트를 하나의 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; 

. 나는 또한 가치의 순서가 맞지 않을 수도있다. 그것들은 상위 바이트보다는 하위 바이트 먼저 저장 될 수 있습니다. 관계없이 개념은 동일합니다.

+0

안녕 난이 30000 길이 int 배열을 사용했다. 아니 3000 – user581734

+0

@ user581734 : 고마워요. 네 말이 맞아, 30,000. 응답은 아직도 서있다. 비트 맵 데이터 배열의 값은 90,000 개이며 배열을 30,000 개의 값으로 복사하려고합니다. 실패 할 것입니다. –

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

안녕하세요, 어떻게 fileBufferArray를 오버런시킬 수 있습니까? 크기는 비트 맵 이미지와 동일합니다. – user581734

+0

@ user581734 : 아니요, 비트 맵 이미지에는 30,000 개의 픽셀이 있지만 이러한 픽셀을 나타내려면 90,000 바이트가 필요합니다. 이미지의 크기는 바이트 단위로 'bmd.Height * bmd.Stride'로 계산할 수 있습니다. 24 비트 이미지의 경우 이미지 크기의 3 배가 픽셀 단위로 'bmd.Height * bmd.Width'입니다. –

+1

이것이 제대로 작동할까요? bmp 형식으로 저장하면 여전히 비트 맵 헤더가 포함되어 있지 않습니까? 높이, 너비, 보폭 및 픽셀 데이터에 대한 포인터를 가져 오려면 비트 맵 머리글을 구문 분석해야합니다. –