Bitmapクラスでは、ピクセル単位でイメージを操作できます。
メソッド | 読み込み元 |
---|---|
Bitmap(Image) | 他のImage |
Bitmap(Stream) | ストリーム |
Bitmap(String) | ファイル |
Bitmap(Type, String) | リソース |
Bitmap(Int32, Int32, Int32, PixelFormat, IntPtr) | ピクセル データを格納するbyte配列 |
Bitmap(Int32, Int32) | 読み込まず、新規に作成 |
対応するファイル形式は次の通りです。グラフィックス ファイル形式 - ビットマップの種類 | MSDN
非対応や破損したファイルを読み込ませると、「使用されたパラメーターが有効ではありません。」としてSystem.ArgumentException例外が投げられます。そのときのArgumentException.HResultは、0x80070057です。
内部ではGraphics.DrawImage()で、新しいImageに描画されます。Bitmap - Bitmap.cs
Imageオブジェクトのピクセルデータへの参照が複製 (コピー) されるわけではありません。また、メタデータなどは複製されません。
Image image = Image.FromFile("sample.bmp"); int len0 = image.PropertyItems.Length; // 3 image.Tag = 'A'; // Clone()による複製 Image copy1 = (Image)image.Clone(); int len1 = copy1.PropertyItems.Length; // 3 object tag1 = copy1.Tag; // null // new Bitmap()による生成 Image copy2 = new Bitmap(image); int len2 = copy2.PropertyItems.Length; // 0 … メタデータは複製されない object tag2 = copy2.Tag; // null
Bitmap(Image, Int32, Int32)の形式でサイズを指定すれば、それにリサイズされます。Bitmap(Image)も内部では、このメソッドを同一サイズを指定して呼んでいます。
public Bitmap(Image original, int width, int height) : this(width, height) { Graphics g = null; try { g = Graphics.FromImage(this); g.Clear(Color.Transparent); g.DrawImage(original, 0, 0, width, height); } finally { if (g != null) { g.Dispose(); } } }Bitmap - Bitmap.cs
このコンストラクタでは既定の補間モードで処理するため、画質が低下する恐れがあります。それが問題となるならばGraphicsオブジェクトを自身で取得し、InterpolationModeを指定して描画します。
public Bitmap( string filename )Bitmap(String) - Bitmap コンストラクター (System.Drawing) | Microsoft Learn
filenameが存在しないと、「使用されたパラメーターが有効ではありません。」としてArgumentExceptionが投げられます。
このコンストラクタには色補正を指定するオーバーロードBitmap(String, Boolean)もありますが、これで色補正をしないように指定するのは、この引数を取らないコンストラクタと同じ挙動となります。Bitmap - Bitmap.cs
Bitmap bitmap = new Bitmap("sample.bmp"); Graphics g = e.Graphics; g.DrawImage(bitmap, 0, 0);
public Bitmap ( System.IO.Stream stream );Bitmap(Stream) - Bitmap コンストラクター (System.Drawing) | Microsoft Learn
ファイルから読み込むならば、ファイル名を引数に取るコンストラクタを用いた方が高速です。
Bitmapが生存している間は、ストリームを開いたままにします。
FileStream fs = new FileStream("sample.bmp", FileMode.Open, FileAccess.Read);
Bitmap bitmap = new Bitmap(fs);
fs.Close();
bitmap.Save("sample2.bmp"); // ExternalException「GDI+ で汎用エラーが発生しました。」
渡したストリームは、自信で閉じます。c# - Bitmap class doesn't dispose stream? - Stack Overflow
FileStream fs = new FileStream(path, FileMode.Open, FileAccess.Read); using (Bitmap bitmap = new Bitmap(fs)) { bitmap.Save("sample1.bmp"); } // Bitmapと共にストリームが閉じられることはない using (Bitmap bitmap = new Bitmap(fs)) // ここでもストリームは有効 { bitmap.Save("sample2.bmp"); // ok }
ただし自身で閉じると、2回以上破棄されるとしてCA2202で警告されます。
using (FileStream fs = new FileStream(path, FileMode.Open, FileAccess.Read))
using (Bitmap bitmap = new Bitmap(fs))
{
bitmap.Save("sample.bmp");
} // warning CA2202: Microsoft.Usage : オブジェクト 'fs' は、メソッド '***' 内で 2 回以上破棄される可能性があります。System.ObjectDisposedException の生成を回避するには、オブジェクトに対して Dispose を 2 回以上呼び出さないようにしてください。
byte配列から作成するには、IntPtrを引数に取るコンストラクタを呼びます。Bitmap - Bitmap.cs
public Bitmap ( int width, int height, int stride, // 次のスキャンラインまでのバイトオフセットを示す整数 System.Drawing.Imaging.PixelFormat format, IntPtr scan0 // ピクセル データを格納しているbyte配列へのポインタ );Bitmap(Int32, Int32, Int32, PixelFormat, IntPtr) - Bitmap コンストラクター (System.Drawing) | Microsoft Learn
呼び出し元はscan0で指定されたメモリ ブロックの、割り当てと解放をしなければなりません。ただしこのBitmapを破棄するまでは解放してはならず、先に解放すると「保護されているメモリに読み取りまたは書き込み操作を行おうとしました。他のメモリが壊れていることが考えられます。」としてAccessViolationExceptionが投げられます。またscan0で確保されている領域のサイズが不足していると、「ヒープは壊れています。」としてコード -1073740940 (0xc0000374) でアプリケーションが終了します。
strideは普通、ピクセル形式のバイト数にビットマップの幅を乗算した値です。この値は4の倍数でなければなりません。
int width = 100; int height = 100; int bytesPerPixel = 24 / 8; // Format24bppRgb byte[] data = new byte[width * height * bytesPerPixel]; // データを作成 IntPtr ptr = Marshal.AllocHGlobal(data.Length); Marshal.Copy(data, 0, ptr, data.Length); Bitmap bitmap = new Bitmap(width, height, width * bytesPerPixel, PixelFormat.Format24bppRgb, ptr); // bitmapを使用する処理 bitmap.Dispose(); Marshal.FreeHGlobal(ptr);
またはLockBits()で取得したBitmapData.Scan0へbyte配列のデータをコピーすることでも、同様に作成できます。「byte配列からのBitmap作成」(1) Insider.NET - @IT
Bitmap bitmap = new Bitmap(width, height, PixelFormat.Format24bppRgb); BitmapData bitmapData = bitmap.LockBits( new Rectangle(Point.Empty, bitmap.Size), ImageLockMode.WriteOnly, bitmap.PixelFormat); Marshal.Copy(data, 0, bitmapData.Scan0, data.Length); bitmap.UnlockBits(bitmapData);
この方法で得られるBitmapData.Scan0で、scan0から作成したときのそのポインタのアドレスを得られます。
変換元のbyte配列が画像ファイルのデータそのものならば、TypeConverter.ConvertFrom()でBitmapへ変換できます。
サイズだけを指定すると、PixelFormatはFormat32bppArgbとなります。Bitmap(Int32, Int32) - Bitmap コンストラクター (System.Drawing) | Microsoft Learn
継承元のImageクラスのプロパティと同一で、追加されたものはありません。
メソッド | 機能 |
---|---|
GetHbitmap() | GDIビットマップ オブジェクトへのハンドルを取得できる |
イメージの指定部分だけを、指定のカラーデータ形式で取得できます。Clone - Bitmap.cs
public System.Drawing.Bitmap Clone ( System.Drawing.Rectangle rect, // 取得する部分 System.Drawing.Imaging.PixelFormat format // カラーデータ形式 );Clone(Rectangle, PixelFormat) - Bitmap.Clone メソッド (System.Drawing) | Microsoft Learn
カラーデータ形式を指定できることから、既存のBitmapのこれを変更したBitmapを作成できます。.net - Converting Bitmap PixelFormats in C# - Stack Overflow
Bitmap bitmap = new Bitmap("sample.bmp"); Bitmap copy = bitmap.Clone( new Rectangle(Point.Empty, bitmap.Size), PixelFormat.Format8bppIndexed);
イメージ全体の複製を取得するには、基本クラスのClone()から返されるobjectをBitmapへキャストします。
Bitmap copy = (Bitmap)bitmap.Clone();
Bitmapをシステム メモリにロックすることで、 SetPixel()で色を変更できるようになります。
public System.Drawing.Imaging.BitmapData LockBits ( System.Drawing.Rectangle rect, System.Drawing.Imaging.ImageLockMode flags, System.Drawing.Imaging.PixelFormat format );LockBits(Rectangle, ImageLockMode, PixelFormat) - Bitmap.LockBits メソッド (System.Drawing) | Microsoft Learn
ロックしたBitmapは、UnlockBits()でアンロックします。