3

次のような 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) の場合、例外が発生します。失敗した場合、ストライドは 44 であり、期待どおりの 42 (14 * 3) ではありません。

ピクセル形式は Format24bppRgb であるため、画像のピクセルごとに 3 バイトが必要です。これらの余分なバイトはどこから来ているのでしょうか?また、画像データを処理するときにどのように処理すればよいでしょうか?

興味のある人のために、私は高さマップから法線データを生成しているので、各ピクセルとその近傍を正確に取得できる必要があります)。

4

1 に答える 1

5

のすべてのピクセル行をBitmap揃える必要があるため、stride常に とは限りませんwidth * bytes-per-pixel。余分なバイトは無視してください。Marshal.Copy()これは、位置合わせされていないデータを含むバイト配列を操作している場合、1 回の呼び出しですべての画像データを常にコピーできるとは限らないことを意味します。ピクセルのすべての行は、意味のあるバイトで始まり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);
    }
}
于 2012-07-12T01:56:10.867 に答える