PictureBoxのImageプロパティに関するよくある勘違いこのサイトではPictureBoxに画像を表示する方法として、PictureBoxのImageプロパティを使う方法と、GraphicsのDrawImageメソッドを使う方法を紹介していますが、掲示板に寄せられる質問を拝見しますと、この2つの方法を混同し、正しく理解していない方が多いようです。 例えば、画像ファイルに文字列を合成した画像を作成し、保存しようとして、次のようなコードを書く方がいらっしゃいます。 'フォームのLoadイベントハンドラ Private Sub Form1_Load(ByVal sender As Object, _ ByVal e As EventArgs) _ Handles MyBase.Load '画像ファイルを表示する PictureBox1.Image = New Bitmap("C:\test.jpg") End Sub 'PictureBox1のPaintイベントハンドラ Private Sub PictureBox1_Paint(ByVal sender As Object, _ ByVal e As PaintEventArgs) _ Handles PictureBox1.Paint '画像の上に文字列を描画する e.Graphics.DrawString("DOBON.NET", Me.Font, Brushes.White, 1, 1) e.Graphics.DrawString("DOBON.NET", Me.Font, Brushes.Black, 0, 0) End Sub 'Button1のClickイベントハンドラ Private Sub Button1_Click(ByVal sender As Object, _ ByVal e As System.EventArgs) _ Handles Button1.Click 'PictureBox1に表示されている画像を保存する PictureBox1.Image.Save("C:\test2.jpg", _ System.Drawing.Imaging.ImageFormat.Jpeg) End Sub //フォームのLoadイベントハンドラ private void Form1_Load(object sender, System.EventArgs e) { //画像ファイルを表示する PictureBox1.Image = new Bitmap(@"C:\test.jpg"); } //PictureBox1のPaintイベントハンドラ private void PictureBox1_Paint(object sender, PaintEventArgs e) { //画像の上に文字列を描画する e.Graphics.DrawString("DOBON.NET", this.Font, Brushes.White, 1, 1); e.Graphics.DrawString("DOBON.NET", this.Font, Brushes.Black, 0, 0); } //Button1のClickイベントハンドラ private void Button1_Click(object sender, System.EventArgs e) { //PictureBox1に表示されている画像を保存する PictureBox1.Image.Save(@"C:\test2.jpg", System.Drawing.Imaging.ImageFormat.Jpeg); } このコードを書いた人は、PictureBox.Imageプロパティの画像にPaintイベントハンドラで描いた文字列が合成されるため、"PictureBox1.Image.Save"で画像を保存すると、保存された画像は元の画像に文字列が合成された画像になると期待しています。しかし実際に保存された画像は元の画像"C:\test.jpg"のままで、文字列は合成されません。PictureBoxには、画像に文字列が合成された画像が確かに表示されているにもかかわらずです。 「なぜ?」と思った方は、まさに勘違いされています。PictureBoxのGraphicsオブジェクトに何を描画しようが、それがPictureBoxのImageプロパティに反映されることはありません。この2つは全くの別物だと思ってください。 このような勘違いをされている方(もしくは、よく理解されていない方)には、どちらかの方法しか使わないようにすることをおすすめします。つまり、以下のどちらかです。
PictureBoxのImageプロパティを一切使用しない方法まずは、PictureBoxのImageプロパティを一切使用しないで、上記のコードを書き換えてみましょう。 画像に文字列を合成してPictureBoxに表示するだけならば、次のようになります。 '表示する画像を読み込む Private originalImaga As Image = New Bitmap("C:\test.jpg") 'PictureBox1のPaintイベントハンドラ Private Sub PictureBox1_Paint(ByVal sender As Object, _ ByVal e As PaintEventArgs) _ Handles PictureBox1.Paint 'PictureBoxに画像を表示する e.Graphics.DrawImage(Me.originalImaga, _ 0, 0, Me.originalImaga.Width, Me.originalImaga.Height) 'さらに文字列を描画する e.Graphics.DrawString("DOBON.NET", Me.Font, Brushes.White, 1, 1) e.Graphics.DrawString("DOBON.NET", Me.Font, Brushes.Black, 0, 0) End Sub //表示する画像を読み込む private Image originalImaga = new Bitmap(@"C:\test.jpg"); //PictureBox1のPaintイベントハンドラ private void PictureBox1_Paint(object sender, PaintEventArgs e) { //PictureBoxに画像を表示する e.Graphics.DrawImage(this.originalImaga, 0, 0, this.originalImaga.Width, this.originalImaga.Height); //さらに文字列を描画する e.Graphics.DrawString("DOBON.NET", this.Font, Brushes.White, 1, 1); e.Graphics.DrawString("DOBON.NET", this.Font, Brushes.Black, 0, 0); } これは、説明するまでもないでしょう。問題は、PictureBoxに表示されている画像をどうやって保存するかという点です。一つの方法としては、Graphicsオブジェクトに描画する部分をメソッドにするという方法があります。つまり、次のような感じです。 '表示する画像 Private originalImaga As Image = New Bitmap("C:\test.jpg") '指定されたGraphicsに画像と文字列を描画するメソッド Private Sub DrawImageAndString(ByVal g As Graphics) '画像を描画する g.DrawImage(Me.originalImaga, _ 0, 0, Me.originalImaga.Width, Me.originalImaga.Height) 'さらに文字列を描画する g.DrawString("DOBON.NET", Me.Font, Brushes.White, 1, 1) g.DrawString("DOBON.NET", Me.Font, Brushes.Black, 0, 0) End Sub 'PictureBox1のPaintイベントハンドラ Private Sub PictureBox1_Paint(ByVal sender As Object, _ ByVal e As PaintEventArgs) _ Handles PictureBox1.Paint Me.DrawImageAndString(e.Graphics) End Sub 'Button1のClickイベントハンドラ Private Sub Button1_Click(ByVal sender As Object, _ ByVal e As System.EventArgs) _ Handles Button1.Click '保存する画像を描画するBitmapを作成する Dim saveImg As New Bitmap(Me.originalImaga.Width, Me.originalImaga.Height) 'Bitmapに描画する Dim g As Graphics = Graphics.FromImage(saveImg) Me.DrawImageAndString(g) g.Dispose() 'Bitmapをファイルに保存する saveImg.Save("C:\test2.jpg", System.Drawing.Imaging.ImageFormat.Jpeg) '後始末する saveImg.Dispose() End Sub //表示する画像 private Image originalImaga = new Bitmap(@"C:\test.jpg"); //指定されたGraphicsに画像と文字列を描画するメソッド private void DrawImageAndString(Graphics g) { //画像を描画する g.DrawImage(this.originalImaga, 0, 0, this.originalImaga.Width, this.originalImaga.Height); //さらに文字列を描画する g.DrawString("DOBON.NET", this.Font, Brushes.White, 1, 1); g.DrawString("DOBON.NET", this.Font, Brushes.Black, 0, 0); } //PictureBox1のPaintイベントハンドラ private void PictureBox1_Paint(object sender, PaintEventArgs e) { this.DrawImageAndString(e.Graphics); } //Button1のClickイベントハンドラ private void Button1_Click(object sender, System.EventArgs e) { //保存する画像を描画するBitmapを作成する Bitmap saveImg = new Bitmap( this.originalImaga.Width, this.originalImaga.Height); //Bitmapに描画する Graphics g = Graphics.FromImage(saveImg); this.DrawImageAndString(g); g.Dispose(); //Bitmapをファイルに保存する saveImg.Save(@"C:\test2.jpg", System.Drawing.Imaging.ImageFormat.Jpeg); //後始末する saveImg.Dispose(); } このようなメソッドを作成する以外の方法としては、
PictureBoxのGraphicsオブジェクトを一切使用しない方法この場合は、PictureBoxのImageプロパティに設定されたイメージに直接描画します。 この方法により、上記のコードを書き換えると、次のようになります。 'フォームのLoadイベントハンドラ Private Sub Form1_Load(ByVal sender As Object, _ ByVal e As EventArgs) _ Handles MyBase.Load '画像ファイルを表示する PictureBox1.Image = New Bitmap("C:\test.jpg") 'PictureBox1.Imageのイメージに文字列を描画する Dim g As Graphics = Graphics.FromImage(PictureBox1.Image) g.DrawString("DOBON.NET", Me.Font, Brushes.White, 1, 1) g.DrawString("DOBON.NET", Me.Font, Brushes.Black, 0, 0) g.Dispose() 'PictureBoxを再描画する '(ここではまだPictureBox1が表示されていないので無意味だが、 'Imageプロパティに描画した後に再描画しないと更新された画像が表示されない) PictureBox1.Invalidate() End Sub 'Button1のClickイベントハンドラ Private Sub Button1_Click(ByVal sender As Object, _ ByVal e As System.EventArgs) _ Handles Button1.Click 'PictureBox1に表示されている画像を保存する PictureBox1.Image.Save("C:\test2.jpg", _ System.Drawing.Imaging.ImageFormat.Jpeg) End Sub //フォームのLoadイベントハンドラ private void Form1_Load(object sender, System.EventArgs e) { //画像ファイルを表示する PictureBox1.Image = new Bitmap(@"C:\test.jpg"); //PictureBox1.Imageのイメージに文字列を描画する Graphics g = Graphics.FromImage(PictureBox1.Image); g.DrawString("DOBON.NET", this.Font, Brushes.White, 1, 1); g.DrawString("DOBON.NET", this.Font, Brushes.Black, 0, 0); g.Dispose(); //PictureBoxを再描画する //(ここではまだPictureBox1が表示されていないので無意味だが、 //Imageプロパティに描画した後に再描画しないと更新された画像が表示されない) PictureBox1.Invalidate(); } //Button1のClickイベントハンドラ private void Button1_Click(object sender, System.EventArgs e) { //PictureBox1に表示されている画像を保存する PictureBox1.Image.Save(@"C:\test2.jpg", System.Drawing.Imaging.ImageFormat.Jpeg); } この方法では、PictureBox.ImageプロパティがNothing(C#では、null)であってはいけません。もし、はじめにPictureBox.Imageプロパティに設定する画像がない場合は、「画像を動的に作成する」で紹介したように新しくイメージを作成し、Imageプロパティに設定します。 'フォームのLoadイベントハンドラ Private Sub Form1_Load(ByVal sender As Object, _ ByVal e As EventArgs) _ Handles MyBase.Load '300x300の大きさのイメージ作成し、Imageプロパティに設定する PictureBox1.Image = New Bitmap(300, 300) 'PictureBox1.Imageのイメージに文字列を描画する Dim g As Graphics = Graphics.FromImage(PictureBox1.Image) g.DrawString("DOBON.NET", Me.Font, Brushes.White, 1, 1) g.DrawString("DOBON.NET", Me.Font, Brushes.Black, 0, 0) g.Dispose() 'PictureBoxを再描画する PictureBox1.Invalidate() End Sub //フォームのLoadイベントハンドラ private void Form1_Load(object sender, System.EventArgs e) { //300x300の大きさのイメージ作成し、Imageプロパティに設定する PictureBox1.Image = new Bitmap(300, 300); //PictureBox1.Imageのイメージに文字列を描画する Graphics g = Graphics.FromImage(PictureBox1.Image); g.DrawString("DOBON.NET", this.Font, Brushes.White, 1, 1); g.DrawString("DOBON.NET", this.Font, Brushes.Black, 0, 0); g.Dispose(); //PictureBoxを再描画する PictureBox1.Invalidate(); } 2つの方法の違い実は、PictureBox.Imageプロパティで画像を表示する方法は、Paintイベントで画像を描画する方法と全く同じことを内部で行っています。ピクチャボックスのImageプロパティに設定された画像は、ピクチャボックスのPaintイベントが発生する直前(OnPaintメソッド)にDrawImageメソッドを使って描画されているだけです。よって「2つの方法」というのは正確ではなく、実際には1つの方法しかありません。PictureBox.Imageプロパティは、画像をPictureBoxに簡単に表示する方法として用意されているだけと考えてよいでしょう。
注意:この記事では、基本的な事柄の説明が省略されているかもしれません。初心者の方は、特に以下の点にご注意ください。 |
|
Copyright(C) DOBON!. All rights reserved.
|