C#画像処理

【C#】Graphicsオブジェクトの作成

フォームのピクチャボックスなどに画像や線を描画するには、Graphicsオブジェクトに対して描画を行いますが、Graphicsオブジェクトの作成方法はいくつかあり、描画の際の挙動も異なります。

 

Graphicsオブジェクトの作成方法は以下の通り

 

●Imageオブジェクトから作成

●PaintイベントのPaintEventArgsから取得

●CreateGraphicsメソッドによる作成

●FromHwndメソッドによる作成

 

以下にフォームのPictureBoxをDockしたときにPictureBoxに描画するためのGraphicsオブジェクトの作成方法を例にとって説明したいと思います。

C# Graphicsオブジェクトの作成

 

Imageオブジェクト(Bitmapオブジェクト)から作成

以下の例ではフォームのリサイズイベント内でピクチャボックスと同じサイズのBitmapオブジェクトを作成し、ピクチャボックスのImageプロパティへBitmapオブジェクトを設定し、BitmapオブジェクトからGraphicオブジェクトを作成し、線を描画しています。

private void Form1_Resize(object sender, EventArgs e)
{
    if ((pictureBox1.Width == 0) || (pictureBox1.Height == 0)) return;

    var bmp = pictureBox1.Image as Bitmap;

    if (bmp != null)
    {
        bmp.Dispose();
    }

    bmp = new Bitmap(pictureBox1.Width, pictureBox1.Height,
        System.Drawing.Imaging.PixelFormat.Format24bppRgb);

    pictureBox1.Image = bmp;

    using (var g = Graphics.FromImage(bmp))
    {
        g.Clear(Color.White);

        g.DrawLine(Pens.Red, 0, 0, pictureBox1.Width, pictureBox1.Height);
        pictureBox1.Refresh();
    }
}

実行例

C# Graphicsオブジェクトの作成

 

ここではピクチャボックスのリサイズイベントではPictureBoxの大きさの取得に失敗する場合があるため、Formのリサイズイベントで処理を行っています。

 

PaintイベントのPaintEventArgsから取得

PictureBoxなどのコントロールのPaintイベントのPaintEventArgsからGraphicsオブジェクトを作成します。

private void pictureBox1_Paint(object sender, PaintEventArgs e)
{
    var g = e.Graphics;

    g.Clear(Color.White);

    g.DrawLine(Pens.Red, 0, 0, pictureBox1.Width, pictureBox1.Height);

}

実は上記コードだけでは問題があり、PictureBoxがリサイズされると、領域が更新された部分のみ線が描画されてしまうため、以下のようになってしまいます。

C# Graphicsオブジェクトの作成

 

このようにならないようにするには、コントロールのResizeイベントでコントロールのInvalidate()を実行することで、コントロール全体の領域が更新され、正しく描画されるようになります。

private void pictureBox1_Resize(object sender, EventArgs e)
{
    pictureBox1.Invalidate();
}

CreateImageメソッドで作成

var g = pictureBox1.CreateGraphics();

g.Clear(Color.White);

g.DrawLine(Pens.Red, 0, 0, pictureBox1.Width, pictureBox1.Height);

FromHwndメソッドで作成

var g = Graphics.FromHwnd(pictureBox1.Handle);

g.Clear(Color.White);

g.DrawLine(Pens.Red, 0, 0, pictureBox1.Width, pictureBox1.Height);

まとめ

基本的にはImageオブジェクトからFromImageメソッドによりGraphicsオブジェクトを作成する方法がおススメです。

この方法ではGraphicsオブジェクトへ画像や線を描画した内容はBitmapオブジェクトへ反映されるので、使い勝手も良いかと思います。

この方法で描画速度が遅く感じる場合は手動ダブルバッファという方法があるので、こちらのページを参照下さい。

 

【C#】手動ダブルバッファによる高速描画
先日、Graphicsオブジェクトの違いによる描画速度の比較として、割と一般的なGraphicsオブジェクトに対して、描画速度を比較を行いましたが、結果、DoubleBufferedが有効な時にPaintイベントで取得するGraphicsオ...

 

PaintイベントでGraphicsオブジェクトを取得する方法はプログラムが簡単なので、ちょっとした評価用のプログラムなどでは使用することはありますが、描画タイミングなど複雑なプログラムを作成しようとすると、Paintイベント内だけで描画するプログラムを作成するのは難しくなるので、私のブログでPaintイベントでGraphicsオブジェクトを取得しているコードがあったら、「手を抜いているんだな!」と思って下さい。

 

CreateImage、FromHwndメソッドを用いた方法では、なにせ描画が遅い!

線などたくさん描画するようなプログラムでは、線一本一本が描画される様子が見えるぐらいに遅いです。そのため、私は、この方法をほとんど使いません。

 

画像処理のためのC#テクニックへ戻る

コメント

タイトルとURLをコピーしました