2012-07-12 3 views
2

예상보다 더 많은 데이터를 포함System.Drawing.Bitmap 내가이처럼 보이는 System.Drawing.Bitmap에서 데이터를 복사하는 방법이

var readLock = image.LockBits(new Rectangle(0, 0, image.Width, image.Height), ImageLockMode.ReadOnly, PixelFormat.Format24bppRgb); 
byte[] data = new byte[3 * image.Width * image.Height]; 
if (data.Length != readLock.Stride * readLock.Height) 
    throw new InvalidOperationException("Incorrect number of bytes"); 
Marshal.Copy(readLock.Scan0, data , 0, data.Length); 
image.UnlockBits(readLock); 

이 아주 간단하고는 대부분의 작동 내 이미지들. 그러나 매우 작은 이미지 (14x14)의 경우 예외가 발생합니다. 실패한 경우 스트라이드는 예상대로 42 (14 * 3)가 아닌 44입니다.

픽셀 형식은 Format24bppRgb이므로 이미지의 모든 픽셀에 대해 3 바이트가 있어야합니다. 이 여분의 바이트는 어디에서 가져 오며 이미지 데이터를 처리 할 때 어떻게 처리 할 수 ​​있습니까?

관심있는 사람은 하이트 맵에서 일반 데이터를 생성하므로 정확하게 각 픽셀과 이웃을 얻을 수 있어야합니다.

답변

4

Bitmap의 모든 픽셀 라인이 정렬되어야합니다. 따라서 stride이 항상 width * bytes-per-pixel이되는 것은 아닙니다. 여분의 바이트는 무시해야합니다. 즉, 정렬되지 않은 데이터가있는 바이트 배열을 사용하여 작업하는 경우 단일 Marshal.Copy() 호출에서 항상 모든 이미지 데이터를 복사 할 수있는 것은 아닙니다. 픽셀의 모든 라인은 readLock.Scan0 + y * readLock.Stride에서 시작하여 의미있는 바이트 인 readLock.Width * bytes-per-pixel을 포함합니다.

솔루션 :

const int BYTES_PER_PIXEL = 3; 
var data = new byte[readLock.Width * readLock.Height * BYTES_PER_PIXEL]; 
if(readLock.Stride == readLock.Width * BYTES_PER_PIXEL) 
{ 
    Marshal.Copy(readLock.Scan0, data, 0, data.Length); 
} 
else 
{ 
    for(int y = 0; y < readLock.Height; ++y) 
    { 
     IntPtr startOfLine = (IntPtr)((long)readLock.Scan0 + (readLock.Stride * y)); 
     int dataOffset = y * readLock.Width * BYTES_PER_PIXEL; 
     Marshal.Copy(startOfLine, data, dataOffset, readLock.Width * BYTES_PER_PIXEL); 
    } 
} 
+0

나는이 사건을 감지한다면, 나는 readLock.Width * 바이트-BER 픽셀마다 복사, 다시 줄에 1 Marshal.Copy을 사용하는 사본 가을해야합니까? – Martin

+0

예. 나는 작동해야하는 코드 샘플을 추가했습니다. – max

+0

우수, 정말 고마워요! – Martin

관련 문제