第 4 回 VC# と GDI+
~ Visual C# .NET による MSDNAA おもしろプログラミング ~
サンプルプログラムのダウンロード (msdnaa_Fun04.exe、102 KB)
4.1 はじめに
近年、情報技術の発展に伴い、複雑なグラフィックス処理が容易に行えるようになってきました。そのため、CG (Computer Graphics) などのグラフィックス処理の分野に注目が集まってきました。Visual C# では、容易にグラフィックス処理を行うためのクラスやコントロールを数多く用意されています。開発者は、これらのコンポーネントを利用することにより、開発コストを軽減できるため、大幅に開発効率が上昇します。そこで、本章では、Visual C# に用意されたグラフィックス処理のためのクラスやコントロールを紹介します。それに加えて、本章で解説した技術を利用し、簡易フォトレタッチソフト (画像加工ソフト) を作成します。
4.2 グラフィックス処理と GDI+
4.2.1 グラフィックス処理
グラフィックス処理とは、読み込んだ画像を表示、加工や保存などを行うことです。グラフィックス処理により、様々なシステム開発ができます。グラフィックス処理利用したシステムには、デジタルカメラで撮影した画像を加工するフォトレタッチソフトなどがあります。.NET Framework のクラスライブラリには、グラフィックス処理を実現するための便利なクラスやコントロールが多く用意されています。グラフィックス処理の概念を図 1 に示します。
.gif)
図 1 グラフィックス処理の概念
4.2.2 GDI+
(1) GDI
GDI (Graphics Device Interface) とは、Windows が提供しているグラフィックス処理を容易に行うためのコンポーネントのことです。GDI を理解するには、デバイスコンテキストの概念を把握しておく必要があります。デバイスコンテキストとは、特定のディスプレイデバイスの機能に関する情報やそのデバイスにおいて、どのように描画されるかを指定する属性を格納するメモリ領域です。デバイスコンテキストは、一つのウインドウに対して一つ作成されます。
(2) GDI+
GDI+ とは、従来の GDI で容易されていたコンポーネントのパフォーマンスをより強力にしたものです。また、GDI+ は、従来の GDI とは異なり、オブジェクト指向性が強くなっています。そのため、開発者にとって利用しやすいように設計されています。従来の GDI では、デバイスコンテキストが中核を担っていたのに対し、GDI+ では、Graphics クラスが中核として機能します。Graphics クラスとは、直線、曲線、図形、イメージ、およびテキストを描画するクラスです。GDI+ では、従来にはなかったテクスチャやグラデーションなどといった様々な効果を容易に作成できます。テクスチャやグラデーションなどの GDI+ に関する新技術については、第 4.2.3 項で解説します。
4.2.3 GDI+ と Visual C#
本項では、 GDI+ の新機能について紹介します。GDI+ の新機能を利用することにより、従来では実現することが困難であった図形の装飾などが容易に実現できます。
(1) グラデーション ブラシ
GDI+ では、図形や領域を塗りつぶすためのグラデーション ブラシが用意されています。グラデーション ブラシは、直線や曲線を描画することもできます。グラデーション ブラシを使用することにより、図形内を移動するにつれて色が段階的に変化するように図形を塗りつぶすことができます。グラデーション ブラシにより、塗りつぶした領域を図 2 に示します。
.gif)
図 2 グラデーション ブラシによる塗りつぶし
(2) パス グラデーション ブラシ
GDI+ では、図形にグラデーション効果をつけるには、グラデーション ブラシを利用するほかにも、パス グラデーション ブラシという技術が用意されています。パス グラデーション ブラシで図形を塗りつぶす場合、図形内の指定した位置から別の位置へ移動するにつれて、どのように色が変化するかをさまざまに指定できます。また、中央の色と外縁の色を指定することで、図形の中央から外縁へと移動するにつれてピクセルの色を段階的に変化させることができます。パス グラデーション ブラシは、グラデーション ブラシとは異なり、複雑な図形に対して高度なグラデーション効果を設定することができます。パス グラデーション ブラシにより、塗りつぶした図形を図 3 に示します。
.gif)
図 3 パス グラデーションによる図形
(3) テクスチャ ブラシ
GDI+ では、グラデーション ブラシ以外にも、テクスチャ ブラシという技術が用意されています。テクスチャとは、物体の質感を表現するために、その表面に貼り付けられる模様の画像データのことです。テクスチャ ブラシを使用することにより、図形にテクスチャを貼り付けることができます。テクスチャ ブラシにより作成した文字を図 4 に示します。
.gif)
図 4 テクスチャ ブラシによる文字
(4) アルファ ブレンド
GDI+ には、アルファ ブレンドという技術があります。アルファ ブレンドとは、塗りつぶす色の透明度を指定し、背景色と塗りつぶした色を混合させる技術です。塗りつぶす色の透明度が高いほど、その色を通して表示される背景がより明瞭に見えます。アルファ ブレンドを利用した図形の描画を図 5 に示します。
.gif)
図 5 アルファ ブレンドによる図形
(5) クリッピング
GDI+ では、クリッピングを容易に行うことができます。クリッピングとは、特定の図形または領域だけに描画を制限することです。クリッピングにより、特定の領域内に画像の表示や図形の描画ができます。クリッピングによる図形を図 6 に示します。
.gif)
図 6 クリッピングによる画像
4.2.4 Drawing 名前空間
第 4.2.3 項で紹介したように、GDI+ には、さまざまな高度なグラフィックス処理を行うことができます。GDI+ の技術を利用するには、Drawing 名前空間を利用します。Drawing 名前空間の中には、図形を描画するためのオブジェクトや図形を塗りつぶしたりするためのオブジェクトなど、グラフィック処理に関する様々なオブジェクトが用意されています。これらのオブジェクトを利用することにより、高度なグラフィックス処理を行うことができます。Drawing 名前空間に用意されている代表的なオブジェクトを表1に示します。
表 1 Drawing 名前空間の主なオブジェクト
| オブジェクト名 | 主な属性とメソッド | 説明 |
| Graphics | DrawLine、FillEllipse、FromImage、Save | GDI+ の中核を成すオブジェクト。線や円などの図形の描画ができる。 |
| Pen | Color、PenType | 線を描く場合に線種を取得するためのオブジェクト。 |
| Brush | | 図形を塗りつぶす場合に利用するオブジェクト。 |
| TextureBrush | Image、Transform、Clone | テクスチャを指定し、図形を描画するときに利用するオブジェクト。Brush クラスを継承。 |
| LinearGradientBrush | Blend、Rectangle、Clone | 2 つの色を使用して、グラデーションを作成するオブジェクト。Brush クラスを継承。 |
| PathGradientBrush | CenterColor、FocusScales 、SurroundColors | 複雑なグラデーション作成するために利用するオブジェクト。Brush クラスを継承。 |
| Bitmap | Clone、PixelFormat、GetPixel、Save、SaveAdd | ピクセルデータで定義したイメージを処理する場合に使用するオブジェクト |
| GraphicsPath | FillMode、AddLine、Transform | 複雑な図形を描画するために利用するオブジェクト |
4.3 簡易フォト レタッチ プログラム
4.3.1 簡易フォト レタッチ プログラムの概要
本節では、これまで解説した GDI+ の技術を利用して、簡易フォト レタッチ プログラムを作成します。今回作成するフォト レタッチ プログラムには、画像の読み込みや画像の保存、画像の加工の機能を実装します。画像の加工機能では、グラデーションやクリッピングによる装飾、テクスチャーテキストの挿入などの機能を実装します。本プログラムの実行イメージを図 7 に示します。
.gif)
図 7 プログラムの実行イメージ
4.3.2 フォームの作成
フォームには、画像や図形を表示するための PictureBox コントロールと処理を実行するための MainMenu コントロール、【ファイルを開く】ダイアログを表示する OpenFileDialog コントロール、【ファイルを保存】ダイアログを表示する SaveFileDialog コントロール、色情報を取得するための ColorDialog コントロール、フォント情報を取得するための FontDialog コントロールなどを配置します。
(1) コントロールの配置
フォームには、図 8 に示すようにコントロールを配置します。
.gif)
図 8 コントロール配置
(2) プロパティの設定
OpenFileDialog コントロールおよび SaveFileDialog コントロールには、ファイルを指定するための Filter の設定が必要です。各コントロールのプロパティの設定に表 2 を示します。
表 2 メインフォームに配置するコントロールのプロパティ設定
| コントロール名 | プロパティ | 設定値 |
| Form1 | Text | フォトレタッチソフト |
| pictureBox1 | BorderStyle | Fixed3D |
| | BackColor | White |
| pictureBox2 | BorderStyle | None |
| | BackColor | White |
| pictureBox2 | BorderStyle | None |
| | BackColor | White |
| label1 | Text | 追加する文字列 |
| groupBox1 | Text | グラデーション |
| openFileDialog1 | Filter | JPG ファイル|*.jpg|PNG ファイル|*.png|GIF ファイル|*.gif |
| saveFileDialog1 | Filter | JPG ファイル|*.jpg|PNG ファイル|*.png|GIF ファイル|*.gif |
また、mainMenu コントロールは、図 9 に示すように設定します。
.gif)
図 9 mainMenu コントロールの設定
(3) イベントハンドラの追加
本プログラムでは、PictureBox コントロールがクリックされたときに実行するイベントハンドラおよびマウスイベント処理を使用します。マウスイベント処理とは、ユーザがマウスを利用して何らかの動作を起こした時に実行する処理のことです。例えば、「マウスをクリックした」や「マウスをドラッグした」などの動作により、実行される処理がマウスイベント処理です。本プログラムに追加するイベントハンドラの一覧を表 3 に示します。
表 3 追加するイベントハンドラ一覧表
| コントロール名 | イベント名 | イベントハンドラ名 |
| pictureBox1 | MouseDown | mouseMove |
| pictureBox2 | Click | pictureBox2_Click |
| pictureBox3 | Click | pictureBox2_Click |
MouseDown イベントハンドラは、ユーザが、マウスクリックした時に処理を実行するイベントハンドラのことです。MouseDown イベントハンドラを追加するには、プロパティウィンドウにある【イベント】ボタンをクリックし、MouseDown イベントハンドラ名を入力します。MouseDown イベントハンドラの追加方法を図 1 に示します。
.gif)
図 10 MouseDown イベントハンドラ追加方法
4.3.3 ソースコードの追加
フォームに記述するソースコードを次に示します。
// グローバル変数
private String strFilename = "";
private Graphics g;
private int iDownX = 0;
private int iDownY = 0;
private int iGraFlag = 0;
private int iTexFlag = 0;
private void menuItem2_Click(object sender, System.EventArgs e)
{
// 【ファイルを開く】ダイアログの【OK】ボタンが押されたとき
if(openFileDialog1.ShowDialog() == DialogResult.OK)
{
strFilename = openFileDialog1.FileName; // ファイル名の格納
pictureBox1.Image = Bitmap.FromFile(strFilename); // ファイル名の引き渡し
g = Graphics.FromImage(pictureBox1.Image); // 描画用オブジェクトの生成
}
}
private void menuItem3_Click(object sender, System.EventArgs e)
{
// 画像が開かれていないとき
if(pictureBox1.Image == null)
{
MessageBox.Show("対象の画像はありません");
return;
}
// 【ファイルの保存】ダイアログの【OK】ボタンが押されたとき
if(saveFileDialog1.ShowDialog() == DialogResult.OK)
{
pictureBox1.Image.Save(saveFileDialog1.FileName); // ファイル名の引き渡し
MessageBox.Show("画像を保存しました");
}
}
private void menuItem5_Click(object sender, System.EventArgs e)
{
Close(); // プログラムの終了
}
private void menuItem7_Click(object sender, System.EventArgs e)
{
SetRegion(); // リージョンを設定
pictureBox1.Refresh(); // pictureBoxの再描画
}
private void menuItem8_Click(object sender, System.EventArgs e)
{
iTexFlag = 1; // 判定用フラグ
MessageBox.Show("文字を追加したい場所をマウスでクリックしてください");
}
private void menuItem9_Click(object sender, System.EventArgs e)
{
iGraFlag = 1; // 判定用フラグ
MessageBox.Show("文字を追加したい場所をマウスでクリックしてください");
}
private void pictureBox2_Click(object sender, System.EventArgs e)
{
Color myColor = getColor(); // 色情報の取得
pictureBox2.BackColor = myColor; // 取得した色情報をpictureboxに設定
}
private void pictureBox3_Click(object sender, System.EventArgs e)
{
Color myColor = getColor(); // 色情報の取得
pictureBox3.BackColor = myColor; // 取得した色情報をpictureboxに設定
}
private Color getColor()
{
Color myColor = new Color(); // 色情報格納用
// 【色の設定】ダイアログの【OK】ボタンが押されたとき
if(colorDialog1.ShowDialog() == DialogResult.OK)
{
myColor = colorDialog1.Color; // 色情報の引渡し
}
return myColor; // 戻り値
}
private void mouseDown(object sender, System.Windows.Forms.MouseEventArgs e)
{
iDownX = e.X; // マウスクリックしたときのX座標を格納
iDownY = e.Y; // マウスクリックしたときのY座標を格納
if(pictureBox1.Image == null)
{
MessageBox.Show("まず画像を開いてください");
return;
}
if((iTexFlag == 1 || iGraFlag == 1) && textBox1.Text == "")
{
MessageBox.Show("追加する文字を指定してください");
return;
}
if(iTexFlag == 1){
if(openFileDialog1.ShowDialog() == DialogResult.OK)
{
strFilename = openFileDialog1.FileName; // ファイル名の設定
Image texture = new Bitmap(strFilename); // 取得したファイルからテクスチャ情報取得
Brush textureBrush = new TextureBrush(texture); // テクスチャ オブジェクトの生成
g.DrawString(textBox1.Text, new Font("Impact", 40.0F),
textureBrush, iDownX, iDownY); // 文字列の描画
}
iTexFlag = 0; // 判定用フラグの初期化
}
else if(iGraFlag == 1)
{
Rectangle r = new Rectangle(0, 20, 100, 40); // 描画領域の確保
LinearGradientBrush myGradientBrush =
new LinearGradientBrush(r, pictureBox2.BackColor, pictureBox3.BackColor,
LinearGradientMode.BackwardDiagonal); // グラデーション ブラシオブジェクトの生成
// 【フォント】ダイアログの【OK】ボタンが押されたとき
if(fontDialog1.ShowDialog() == DialogResult.OK)
{
g.DrawString(textBox1.Text,fontDialog1.Font,myGradientBrush,iDownX,
iDownY,StringFormat.GenericDefault); // 文字列の描画
}
iGraFlag = 0; // 判定用フラグの初期化
}
pictureBox1.Refresh(); // pictureBoxの再描画
}
private void SetRegion()
{
GraphicsPath gPath = new GraphicsPath(); // グラフィックパスオブジェクトの生成
int r = System.Math.Min(this.pictureBox1.Width,
this.pictureBox1.Height)/2; // 半径の計算
// 座標の計算
Point[] points =
{
new Point((int)(r*Math.Sin(Math.PI*2*0.0)), (int)(r*-Math.Cos(Math.PI*2*0))),
new Point((int)(r*Math.Sin(Math.PI*2*1/5)), (int)(r*-Math.Cos(Math.PI*2*1/5))),
new Point((int)(r*Math.Sin(Math.PI*2*2/5)), (int)(r*-Math.Cos(Math.PI*2*2/5))),
new Point((int)(r*Math.Sin(Math.PI*2*3/5)), (int)(r*-Math.Cos(Math.PI*2*3/5))),
new Point((int)(r*Math.Sin(Math.PI*2*4/5)), (int)(r*-Math.Cos(Math.PI*2*4/5))),
};
gPath.FillMode = FillMode.Winding; // パス グラデーションのモード設定
gPath.AddLine(points[0], points[2]); // 計算した頂点を結ぶ
gPath.AddLine(points[2], points[4]); // 計算した頂点を結ぶ
gPath.AddLine(points[4], points[1]); // 計算した頂点を結ぶ
gPath.AddLine(points[1], points[3]); // 計算した頂点を結ぶ
gPath.AddLine(points[3], points[0]); // 計算した頂点を結ぶ
gPath.Transform(new Matrix(1,0,0,1,r,r)); // 座標系の変換
g.Clip = new Region(gPath); // 描画領域の設定
pictureBox1.Region = new Region(gPath); // pictureBoxの領域の設定
}
}
4.3.4 ソースコードの解説
(1) 描画用オブジェクトの生成
図形を描画するには、Graphics クラスのインスタンスである描画用のオブジェクトを生成する必要があります。描画用オブジェクトの生成には、CreateGraphics メソッドを使用する方法と FromImage メソッドを使用する方法があります。前者は、PictureBox コントロールやFormなどに図形を描画用オブジェクトとするためのもので、読み込んだ画像と文字列や図形を区別して管理します。そのため、画像に文字列や図形を描画することはできません。それに対し、後者は、読み込んだ画像を描画用オブジェクトとするため、実際に読み込んだ画像に図形や文字列を描画することができます。今回のプログラムでは、画像の加工を行うため、後者の描画オブジェクトを生成します。描画オブジェクトを生成する構文を次に示します。
Graphics g; g = pictureBox1.CreateGraphics(); g = Graphics.FromImage(pictureBox1.Image); |
(2) テクスチャの文字列追加
.NET Framework では、テクスチャ文字を追加ために TextureBrush クラスが用意されています。TextureBrush クラスを利用することにより、指定したテクスチャで図形や文字列を塗りつぶすことができます。TextureBrush オブジェクトの生成およびテクスチャ文字列の追加方法を次に示します。
- Bitmap クラスから派生した Image オブジェクトにテクスチャにするイメージファイル名を指定します。
- 作成した Image オブジェクトを TextureBrush クラスに引き渡します。
- Graphics オブジェクトの DrawString メソッドにより、文字列を追加します。
テクスチャ文字列の追加例を次に示します。
strFilename = openFileDialog1.FileName; Image texture = new Bitmap(strFilename); Brush textureBrush = new TextureBrush(texture); g.DrawString(textBox1.Text, //追加する文字列 new Font("Impact", 40.0F), // フォントの種類 textureBrush, // テクスチャ ブラシ オブジェクト iDownX, // マウスクリックしたX座標 iDownY // マウスクリックしたY座標 ); |
上記のように記述することで、自動的にテクスチャを設定し、文字列の装飾を行うことができます。
(3) グラデーションの文字列追加
.NET Framework には、グラデーション効果を作成するために LinearGradientBrush クラスが用意されています。LinearGradientBrush オブジェクトの生成方法およびテクスチャ文字列の追加方法を次に示します。
- Rectangle オブジェクトを生成し、描画領域を確保します。
- 作成した Rectangle オブジェクトや複数の色情報などを指定し、LinearGradientBrush オブジェクトを作成します。
- Graphics オブジェクトの DrawString メソッドにより、文字列を追加します。
グラデーション文字列の追加例を次に示します。
Rectangle myRectangle = new Rectangle(0, 20, 100, 40); LinearGradientBrush myGradientBrush = new LinearGradientBrush(myRectangle, pictureBox2.BackColor, pictureBox3.BackColor,LinearGradientMode.BackwardDiagonal);
if(fontDialog1.ShowDialog() == DialogResult.OK) { g.DrawString(textBox1.Text, //追加する文字列 fontDialog1.Font, // fontDialog コントロールで取得したフォントの種類 GradientBrush, // LinearGradientBrush オブジェクト iDownX, // マウスクリックした X 座標 iDownY, // マウスクリックした Y 座標 StringFormat.GenericDefault // グラデーション Mode ); } |
上記のように記述することで、自動的にグラデーションを設定し、文字列の装飾を行うことができます。
4.3.5 実行結果
プログラムの実行結果を図 11 に示します。
.gif)
図 11 プログラムの実行結果
4.4 おわりに
本章では、グラフィックス処理および GDI+ の概念やコントロールを説明し、簡易フォト レタッチ プログラムを作成しました。.NET Framework には、今回、紹介した以外にも GDI+ のクラスやコントロールが豊富に用意されています。そのため、開発者は、Visual C# に用意されたクラスやコントロールを利用することにより、ごく単純なプログラムで複雑なグラフィックス処理を実現できます。また、GDI+ は、オブジェクト指向性が強くなっているため、開発効率が大幅に上昇します。
Visual C# .NET による MSDNAA おもしろプログラミング
本コラムでは、MSDN や MSDNAA の中で公開されているリソースの中でも、プログラミングの楽しさを追及できるものを集めて紹介し、新しいオブジェクト指向言語 「Visual C#. NET」 での利用法を解説していきます。
著者略歴
田中 成典 (たなか しげのり)
| 1986 年 | 関西大学工学部土木工学科卒業 |
| 1988 年 | 関西大学大学院工学研究科 土木工学専攻博士課程前期課程修了 |
| 1996 年 | 博士 (工学) 授与,関西大学 |
| 1997 年 | 関西大学総合情報学部助教授 (現在に至る) |
| 主な著書: | やさしい C のはじめかた,オーム社,1993 年 |
| | 建設技術者のための知識情報処理の実践,関西大学出版部,1999 年 |
| | DirectX8,工学社,2001 年 |
| | ステップアップ XML,工学社,2002 年 |
| | Linux アプリケーション入門,森北出版,2002年 ほか |
中山 浩太郎 (なかやま こうたろう)
| 2001 年 3 月 | 関西大学総合情報学部総合情報学科卒業 |
| 2003 年 3 月 | 関西大学大学院総合情報学研究科 博士課程前期課程修了 |
| 2003 年 4 月 | 関西大学大学院総合情報学研究科 博士課程後期課程入学 (現在に至る) |
| 主な著書: | Web 工房シリーズ Perl の達人,森北出版,1999 年 |
| | 決定版 Visual Basic,共立出版,2000年 |
| | DirectX8,工学社,2001 年 |
| | Linux アプリケーション入門,森北出版,2002 年 |
| | ステップアップ Visual C# .NET 入門,工学社,2002 年 ほか |
中村 健二 (なかむら けんじ)
| 2000 年 4 月 | 関西大学総合情報学部総合情報学科入学 (現在に至る) |
| 主な著書: | DirectX8 & VC++ 3D の基礎とゲームの作り方,工学社,2002年 |
北川 悦司 (きたがわ えつじ)
| 2000 年 3 月 | 関西大学総合情報学部総合情報学科卒業 |
| 2002 年 3 月 | 関西大学大学院総合情報学研究科 博士課程前期課程修了 |
| 2002 年 4 月 | 関西大学大学院総合情報学研究科 博士課程後期課程入学 (現在に至る) |
| 主な著書: | Web 工房シリーズ Java の達人,森北出版,1999 年 |
| | デジカメ活用によるデジタル写真測量入門,森北出版,2000 年 |
| | ステップアップ XML 活用法,工学社,2002 年 |
上山 智士 (うえやま さとし)
| 2002 年 4 月 | 関西大学総合情報学部総合情報学科入学 (現在に至る) |
杉町 敏之 (すぎまち としゆき)
| 2003 年 3 月 | 関西大学総合情報学部総合情報学科卒業 |
| 2003 年 4 月 | 関西大学大学院総合情報学研究科入学 (現在に至る) |
| 主な著書: | ステップアップ Visual C# .NET 入門,工学社,2002 年 |
野中 一希 (のなか かずき)
| 2003 年 3 月 | 関西大学総合情報学部総合情報学科卒業 |
| 2003 年 4 月 | 関西大学大学院総合情報学研究科入学 (現在に至る) |
| 主な著書: | ステップアップ Visual C# .NET 入門,工学社,2002 年 |
ペー ジのトップへ