C#で画像に文字を重ねたり画像同士を重ね合わせる処理をするにはどうすればよいでしょうか?
Contents
画像に文字を重ねる
まず画像ファイルからBitmapオブジェクトを取得します。そのあとそこからGraphicsオブジェクトを取得してDrawStringメソッドで文字列を書き込みます。Graphics.DrawStringメソッドでは書き込みたい文字列、使用するフォント、ブラシ、文字列の左上の座標を設定します。処理が終わったら生成したBitmapオブジェクト、Graphicsオブジェクト、フォント、ブラシをDisposeします。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 |
public partial class Form1 : Form { private void button1_Click(object sender, EventArgs e) { string srcFilePath = @"D:\source.png"; string destFilePath = @"D:\dest.png"; string text = "鳩でもわかるC#"; // 書き込みたい文字列 // 画像を読み込む Bitmap bitmap = new Bitmap(srcFilePath); Graphics graphics = Graphics.FromImage(bitmap); Font font = new Font("MS ゴシック", 24, FontStyle.Bold); // フォントはMS ゴシック 24ポイント 太字 Brush brush = new SolidBrush(Color.White); // 色は白 graphics.DrawString(text, font, brush, new Point(0, 0)); // 文字列の座標は(0, 0) // 終わったらリソースを解放 graphics.Dispose(); font.Dispose(); brush.Dispose(); // 画像をPNG形式で保存 bitmap.Save(destFilePath, System.Drawing.Imaging.ImageFormat.Png); // 画像リソースを解放 bitmap.Dispose(); } } |
Before
After
画像ファイルを読み込み、指定された文字列、フォント、色、座標に文字列を追加します。
デザイナで以下のようなものをつくります。左側にあるのはPictureBox、右には追加する文字列を指定するためのTextBoxと座標を指定するためのNumericUpDownコントロールを配置します。
各ボタンをクリックすると画像ファイルの読み込みとPictureBoxへの表示、フォントの選択、文字列の追加、ファイルの保存ができます。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 |
public partial class Form1 : Form { public Form1() { InitializeComponent(); } OpenFileDialog _openFileDialog = new OpenFileDialog(); Bitmap? _bitmap = null; private void ButtonOpenFile_Click(object sender, EventArgs e) { _openFileDialog.Filter = "PNGファイル(*.png)|*.png"; if (_openFileDialog.ShowDialog() == DialogResult.OK) { Image image = Image.FromFile(_openFileDialog.FileName); if (_bitmap != null) _bitmap.Dispose(); _bitmap = new Bitmap(image); image.Dispose(); pictureBox1.Image = _bitmap; } } Bitmap? _stringBitmap = null; private void ButtonDrawString_Click(object sender, EventArgs e) { if (_bitmap == null) return; Bitmap bitmap = new Bitmap(_bitmap); Graphics graphics = Graphics.FromImage(bitmap); SolidBrush brush = new SolidBrush(_fontDialog.Color); graphics.DrawString( textBox1.Text, _fontDialog.Font, brush, new Point((int)numericUpDown1.Value, (int)numericUpDown2.Value)); graphics.Dispose(); brush.Dispose(); if (_stringBitmap != null) _stringBitmap.Dispose(); _stringBitmap = bitmap; pictureBox1.Image = bitmap; } FontDialog _fontDialog = new FontDialog(); private void ButtonFont_Click(object sender, EventArgs e) { _fontDialog.ShowColor = true; _fontDialog.ShowDialog(); } SaveFileDialog _saveFileDialog = new SaveFileDialog(); private void ButtonSaveFile_Click(object sender, EventArgs e) { if (_stringBitmap == null) return; _saveFileDialog.Filter = "PNGファイル(*.png)|*.png"; if (_saveFileDialog.ShowDialog() == DialogResult.OK) _stringBitmap.Save(_saveFileDialog.FileName); } } |
画像同士を重ねたい
この場合もふたつの画像ファイルからBitmapオブジェクトをそれぞれ取得します。そのあとそこからGraphicsオブジェクトを取得してDrawImageメソッドでイメージを書き込みます。オーバーロードが複数あります。やりたいことにあわせて適切なものを使います。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 |
public partial class Form1 : Form { private void button1_Click(object sender, EventArgs e) { string srcFilePath1 = @"D:\source1.png"; string srcFilePath2 = @"D:\source2.png"; string destFilePath = @"D:\dest.png"; // 画像を読み込む Bitmap srcBitmap1 = new Bitmap(srcFilePath1); Bitmap srcBitmap2 = new Bitmap(srcFilePath2); Graphics graphics = Graphics.FromImage(srcBitmap1); // srcBitmap2をそのままのサイズで左上が(50, 50)になるように graphics.DrawImage(srcBitmap2, new Point(50, 50)); // srcBitmap2を左上が(50, 50)で幅150、高さ100の矩形内におさまるように(これならサイズ変更ができる) graphics.DrawImage(srcBitmap2, new Rectangle(50, 50, 150, 100)); // 終わったらgraphicsを解放 graphics.Dispose(); // 画像をPNG形式で保存 srcBitmap1.Save(destFilePath, System.Drawing.Imaging.ImageFormat.Png); // 画像リソースを解放 srcBitmap1.Dispose(); srcBitmap2.Dispose(); } } |
Before
After
上記の方法はひとつめの画像ファイルの外側にあるものは保存されません。ふたつの画像を並べて表示させたい場合はふたつの画像サイズから新しい画像のサイズを計算する必要があります。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 |
public partial class Form1 : Form { private void button4_Click(object sender, EventArgs e) { // 高さが違うふたつの画像を横に並べる string srcFilePath1 = @"D:\source1.png"; string srcFilePath2 = @"D:\source2.png"; string destFilePath = @"D:\dest.png"; // 画像を読み込む Bitmap srcBitmap1 = new Bitmap(srcFilePath1); Bitmap srcBitmap2 = new Bitmap(srcFilePath2); int newHeight = Math.Max(srcBitmap1.Height, srcBitmap2.Height); Bitmap destBitmap = new Bitmap(srcBitmap1.Width + srcBitmap2.Width, newHeight); Graphics graphics = Graphics.FromImage(destBitmap); // 横に並べたときにできる空白は白で塗りつぶす。この行がないと該当部分は透過となる graphics.Clear(Color.White); // srcBitmap1とsrcBitmap2を書き込む graphics.DrawImage(srcBitmap1, new Point(0, 0)); graphics.DrawImage(srcBitmap2, new Point(srcBitmap1.Width, 0)); graphics.Dispose(); // 画像をPNG形式で保存 destBitmap.Save(destFilePath, System.Drawing.Imaging.ImageFormat.Png); // 画像リソースを解放 srcBitmap1.Dispose(); srcBitmap2.Dispose(); destBitmap.Dispose(); } } |
Before
After
ふたつの画像ファイルを読み込み、ふたつめの画像を指定された座標と拡大率で合成します。
デザイナで以下のようなものをつくります。左側にあるのはPictureBox、右には合成するふたつの画像ファイルのパスを指定するためのTextBoxと座標、拡大率を指定するためのNumericUpDownコントロールを配置します。
選択ボタンをクリックするとファイル選択ダイアログが表示され、画像ファイルを選択することができます。選択されファイルのパスはTextBoxに表示されます。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
public partial class Form1 : Form { public Form1() { InitializeComponent(); } OpenFileDialog _openFileDialog = new OpenFileDialog(); private void ButtonSelectFile1_Click(object sender, EventArgs e) { _openFileDialog.Filter = "PNGファイル(*.png)|*.png"; if (_openFileDialog.ShowDialog() == DialogResult.OK) textBoxPath1.Text = _openFileDialog.FileName; } private void ButtonSelectFile2_Click(object sender, EventArgs e) { _openFileDialog.Filter = "PNGファイル(*.png)|*.png"; if (_openFileDialog.ShowDialog() == DialogResult.OK) textBoxPath2.Text = _openFileDialog.FileName; } } |
合成ボタンがクリックされるとTextBoxに表示されている文字列からBitmapオブジェクトを取得します。もし存在しないファイルや画像ファイルでないものが選択されている場合は例外が発生します。
NumericUpDownコントロールから二つ目の画像を合成する座標と拡大率を取得して、合成後のBitmapの適切なサイズを計算します。そして新しいBitmapが生成され、そのなかにgraphics.DrawImageによってふたつのBitmapが描画されます。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 |
public partial class Form1 : Form { Bitmap? _compositeImage = null; private void ButtonCompositeImages_Click(object sender, EventArgs e) { string srcFilePath1 = textBoxPath1.Text; string srcFilePath2 = textBoxPath2.Text; try { Image image1 = Image.FromFile(srcFilePath1); Bitmap bitmap1 = new Bitmap(image1); image1.Dispose(); Image image2 = Image.FromFile(srcFilePath2); Bitmap bitmap2 = new Bitmap(image2); image2.Dispose(); int width2 = bitmap2.Width * (int)numericUpDown3.Value / 100; int height2 = bitmap2.Height * (int)numericUpDown3.Value / 100; int newWidth = Math.Max(bitmap1.Width, (int)numericUpDown1.Value + width2); int newHeight = Math.Max(bitmap1.Height, (int)numericUpDown2.Value + height2); Bitmap newBitmap = new Bitmap(newWidth + 50, newHeight+ 50); Graphics graphics = Graphics.FromImage(newBitmap); graphics.DrawImage(bitmap1, new Point(0, 0)); Rectangle rect = new Rectangle((int)numericUpDown1.Value, (int)numericUpDown2.Value, width2, height2); graphics.DrawImage(bitmap2, rect); // リソースを解放する graphics.Dispose(); bitmap1.Dispose(); bitmap2.Dispose(); // 古いものがあれば解放する if (_compositeImage != null) _compositeImage.Dispose(); _compositeImage = newBitmap; pictureBox1.Image = newBitmap; } catch { MessageBox.Show("失敗"); } } SaveFileDialog _saveFileDialog = new SaveFileDialog(); private void ButtonSaveFile_Click(object sender, EventArgs e) { if (_compositeImage == null) return; _saveFileDialog.Filter = "PNGファイル(*.png)|*.png"; if (_saveFileDialog.ShowDialog() == DialogResult.OK) _compositeImage.Save(_saveFileDialog.FileName); } } |