以下の例は、BitmapクラスのLockBits/UnlockBitsメソッドの呼び出しをラップするクラスBitmapLockを作成し、usingステートメントで使用できるようにしたものです。 この例では、画像ファイルorigin.pngを読み込み、色を反転した結果をnegated.pngとして保存しています。
LockBits/UnlockBitsの呼び出しをラップしてusingステートメントで使えるようにする
using System;
using System.Drawing;
using System.Drawing.Imaging;
using System.Runtime.InteropServices;
// Bitmap.LockBits/UnlockBitsの処理をラップしたクラス
class BitmapLock : IDisposable {
private Bitmap bitmap;
private BitmapData data;
public BitmapLock(Bitmap bitmap, Rectangle rect, ImageLockMode mode, PixelFormat format)
{
this.bitmap = bitmap;
this.data = bitmap.LockBits(rect, mode, format);
}
public void Dispose()
{
if (data != null) {
bitmap.UnlockBits(data);
data = null;
bitmap = null;
}
}
// ラインyの先頭のポインタを取得する
public IntPtr GetScanLine(int y)
{
if (data == null) throw new ObjectDisposedException(GetType().FullName);
return new IntPtr(data.Scan0.ToInt32() + y * data.Stride);
}
}
class Sample {
static void Main()
{
using (Bitmap bitmap = (Bitmap)Image.FromFile("origin.png")) {
Rectangle rect = new Rectangle(0, 0, bitmap.Width, bitmap.Height);
// 画像全体のピクセルを読み書きできるようにロックする
using (BitmapLock locked = new BitmapLock(bitmap, rect, ImageLockMode.ReadWrite, PixelFormat.Format32bppArgb)) {
for (int y = 0; y < rect.Height; y++) {
IntPtr line = locked.GetScanLine(y);
for (int x = 0; x < rect.Width; x++) {
// 1ピクセル分読み込み
int col = Marshal.ReadInt32(line, x * 4);
// 反転した値を書き込む
Marshal.WriteInt32(line, x * 4, ~col);
}
}
}
bitmap.Save("negated.png", ImageFormat.Png);
}
}
}