System.Drawing.Bitmap から System.Runtime.InteropServices.Marshal.Copy で取り出した byte 配列から画素値を取り出す

Marshal.Copy についてはBitmapの内部データにアクセスする ( ソフトウェア ) - おきらくエンジニア - Yahoo!ブログを見て解決する.image っていうクラスを作って,getByte() メソッドを記述してみた.

private void getByte(Bitmap bmp)
{
	// Bitmapの内部データにアクセスする
	// http://blogs.yahoo.co.jp/spike_spike690/4735887.html
	// Pixelデータにアクセスする領域を設定する
	Rectangle rect = new Rectangle(0, 0, imageSize.X, imageSize.Y);
	// BitmapDataクラスのインスタンスを生成し、LockBits関数でBitmapをLockする。
	BitmapData bmpData = bmp.LockBits(rect, ImageLockMode.ReadOnly, PixelFormat.Format24bppRgb);
	// BitmapData内の各種項目を抜き出す。
	IntPtr ptr = bmpData.Scan0;
	this.imageStride = Math.Abs(bmpData.Stride);
	// コピーするデータ量を設定.PixelFormat に関わらず stride * 高さ
	int bytes = this.imageStride * imageSize.Y;
	this.imageData = new byte[bytes];
	// 確保したデータ配列にBitmap内のデータをコピー
	System.Runtime.InteropServices.Marshal.Copy(ptr, this.imageData, 0, bytes);
	// Bitmapのロックを解除する。
	bmp.UnlockBits(bmpData);
}

参照元との違いは,

  • 画素値書き換えをしないから ImageLockMode.ReadOnly で読み出した
  • カラー画像として盲目的に読み込む

this.imageData に byte が入った.getPixel() メソッドを作る.以下の3ページを参考にした.

public enum ColorIndex { Gray, Blue = 0, Green, Red };

public int getPixel(Point p, ColorIndex colorIndex)
{
	return (int)imageData[p.X * 3 + p.Y * imageStride + (int)colorIndex];
}

LockBits() したときに PixelFormat.Format24bppRgb と指定していたから,3個ごとに読み出すため p.X を3倍している.