本文
Image.FromHbitmap関数で作成したビットマップのような一部のビットマップではBitmap.LockBitsメソッドが返すBitmapDataのStrideが負の値になります。このようなビットマップはボトムアップ形式と呼ばれ、Scan0はビットマップの最終列の最初のピクセルを指しています*1。Strideが正のビットマップのようにScan0を使用したり、BitmapクラスのコンストラクタにScan0を指定した場合はメモリアクセス例外が発生します。
Strideが負のRGBビットマップを正のARGBビットマップに移す場合は以下のコードが使用可能です*2。
bmp1:事前に作成されたPixelFormat.Format32bppRgb形式のビットマップ。
var bmp2 = default(Bitmap); try { bmp2 = new Bitmap(bmp1.Width, bmp1.Height, PixelFormat.Format32bppArgb); var bound = new Rectangle(0, 0, bmp1.Width, bmp1.Height); var data1 = bmp1.LockBits(bound, ImageLockMode.ReadOnly, PixelFormat.Format32bppRgb); var data2 = bmp2.LockBits(bound, ImageLockMode.WriteOnly, PixelFormat.Format32bppArgb); if (data1.Stride > 0) { NativeMethod.RtlMoveMemory(data2.Scan0, data1.Scan0, data1.Stride * data1.Height); } else { var stride = -data1.Stride; var p1 = data1.Scan0 + data1.Stride * (data1.Height - 1); var p2 = data2.Scan0 + stride * (data1.Height - 1); for (var y = 0; y < data1.Height; y++) { NativeMethod.RtlMoveMemory(p2, p1, stride); p1 += stride; p2 -= stride; } } bmp2.UnlockBits(data2); bmp1.UnlockBits(data1); // TODO:ここでbmp2を処理します。 } catch { bmp2?.Dispose(); throw; } }
private static class NativeMethods { [DllImport("Kernel32.dll")] public static extern void RtlMoveMemory( IntPtr dest, IntPtr src, [MarshalAs(UnmanagedType.U4)]int size); }
参考
2021/3/10:この記事は別のブログで投稿した記事を移動したものです。