こんなコメントをいただきました。
1 2 3 4 |
初めましてこんにちは。記事のテーマと違うコメントですみません。 「画像ファイルの色を置換したい」を使わせて頂いて、自分の目的と合いそうだなと、ありがたく思っております。 こちらのソフトですが、入力対象のフォルダを指定またはドラッグ&ドロップして、出力フォルダも指定し、入力のサブフォルダまで一括で置換、というようなバージョンアップは今後ありませんでしょうか・・・。もしあったら嬉しく存じます・・・。 勝手なお願い申し上げて失礼しました。 |
Contents
「画像ファイルの色を置換したい」とは?
「画像ファイルの色を置換したい」とはVectorにアップロードした鳩でもわかるC#管理人作成のフリーソフトのことです。
Vectorとは「ソフト登録数国内最大規模のオンラインソフトウェア流通サイト。充実したダウンロードライブラリに加え、ソフトの紹介記事、メールニュース等で常に最新のコンテンツを発信」しています。
画像ファイルの色を置換したいの詳細情報 : Vector ソフトを探す!
Vector: ソフトライブラリ&PCショップ – 国内最大級の フリーソフト ダウンロードサイト
「バージョンアップはしない」つもりだったのですが、ブログ記事のネタを提供してくれたわけですからやってみましょう。
これまでの仕様
これまでの「画像ファイルの色を置換したい」は以下のような仕様になっています。
■■■■ 画像ファイルの色を置換したい ■■■■
画像ファイルの色を入れ替えてくれるフリーソフトテキストエディタで文字列の置換があるのだから画像編集ソフトにも色を置換する機能があってもよいのではないか? 本ソフトウェアはそんな考えから生まれました。置換元の色と置換先の色を指定して複数のファイルを処理することもできます。また似たような色を同じと見なして置き換えることもできます。
■ インストール
ダウンロードし展開したあと適当なフォルダ内にコピーして使用してください。
フォルダの中のColorReplace.exeをダブルクリックすると
アプリケーションが起動します。アンインストールはフォルダを削除してください。
■ 使い方
メニュー [ファイル] ⇒ [ファイルを開く]か画像ファイルをドラッグアンドドロップすることでファイルを開きます。
画像をクリックするとその部分の色が[クリックされた色]にコピーされます。[置換前の色]または[置換先の色]の[コピー]ボタンをクリックすることで[クリックされた色]をコピーすることができます。
メニュー [色の置換]をクリックすると色の置換がおこなわれます。ただし少しでも色が違うと置換されません。
メニュー [設定] ⇒ [色の誤差の設定]で設定した値以内のズレであれば置換前の色と同じ色として置き換えの対象にすることができます。
メニュー [ファイル] ⇒ [保存]を選択するとファイルを保存することができます。
事前に[置換前の色]または[置換先の色]を指定して、[D&Dで複数のファイルを処理する]にチェックを入れた状態で画像ファイルをドラッグアンドドロップすると複数のファイルを処理することができます。その場合は同じフォルダ内に Output + [現在日時]というフォルダが生成され、そこにファイルが保存されます。
変更点
やってほしいこととしてあげられているのは
複数のファイルだけでなくフォルダ単位で指定できるようにする
ドラッグアンドドロップでフォルダも指定できるようにする
サブフォルダがある場合、それらも指定対象とする
出力フォルダも指定できるようにする
このなかで「出力フォルダも指定できるようにする」はやりません。理由は指定された出力フォルダのなかに出力ファイルと同名のものがあると上書きされてしまう可能性があるからです。それから入力フォルダと出力フォルダが親子関係にあるとややこしいことになるからです。
そこで処理の対象となるファイルを
メニューからファイル単体だけでなくフォルダも選択できるようにする
ドラッグアンドドロップでファイルまたはフォルダで指定できるようにする
ように改良します。
それからVectorに登録したフリーソフトの一部はソースコードも掲載しているのですが、「画像ファイルの色を置換したい」は掲載されていないのでソースコードも掲載することにします。
編集する画像ファイルを読み込む
デザイナで以下のようなものをつくります。
左側のくぼんだ部分はPanel(panel1)です。そのなかの点線で囲まれている部分はPictureBox(pictureBox1)です。右側に3箇所くぼんだ部分がありますが、これもPictureBox(pictureBoxClickedColor, pictureBoxBeforeColor, pictureBoxAfterColor)です。それぞれがなにかわかるようにLabel(labelClickedColor, labelBeforeColor, labelAfterColor)を配置しています。
pictureBox1のSizeModeプロパティにはPictureBoxSizeMode.AutoSizeを、panel1のAutoScrollプロパティにはtrueを設定します。これで大きな画像が表示されるときにはスクロールバーが自動でつきます。
ファイルを開くを選択したら編集対象になるファイルを開く処理を示します。
選択されたファイルは画像ファイルではないかもしれません(拡張子だけで判断するのは不安)。そこで例外処理をしています。もし画像ファイルではないものを開こうとした場合はエラーメッセージが表示されます。画像ファイルであればBitmapオブジェクトを生成してBitmapプロパティに設定します。
Bitmapプロパティは古いオブジェクトがフィールド変数に格納されていたらDisposeします。そのあと渡されたBitmapオブジェクトを格納します。それと同時にpictureBox1.Imageプロパティにも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 |
public partial class Form1 : Form { OpenFileDialog openFileDialog = new OpenFileDialog(); private void MenuItemOpenFile_Click(object sender, EventArgs e) { openFileDialog.Filter = "Image Files png(*.png) bmp(*.bmp) gif(*.gif) jpg(*.jpg *.jepg) tiff(*.tiff *.tif)|*.png;*.bmp;*.gif;*.jpg;*.jepg;*.tiff;*.tif"; if (openFileDialog.ShowDialog() == DialogResult.OK) { try { Bitmap bitmap = new Bitmap(openFileDialog.FileName); Bitmap = new Bitmap(bitmap); bitmap.Dispose(); } catch { MessageBox.Show("選択されたファイルは画像ファイルではありません!", "", MessageBoxButtons.OK, MessageBoxIcon.Error); } } } Bitmap _bitmap = null; Bitmap Bitmap { get { return _bitmap; } set { if (_bitmap != null) _bitmap.Dispose(); _bitmap = value; pictureBox1.Image = value; } } } |
置換の対象となる色情報を取得する
置換の対象となる色情報を取得する処理を示します。取得する手段として画像に使われている色をクリックすることで取得できれば便利ではないかと考えました。クリックした位置にある色を置換前または置換後の色として指定できるようにするのです。
またユーザー自身がカラーダイアログをつかって自由に設定できる機能も追加しました。
色情報を画像から取得する
pictureBox1がクリックされたらクリックされた座標の色を取得し、これをClickedColorプロパティに設定します。
ClickedColorプロパティは渡された色をフィールド変数に格納するとともに、pictureBoxClickedColorの背景色も変更し、そのカラーコードをラベルに表示します。これでクリックされた場所にある色がなにか視覚的にわかるようになります。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
public partial class Form1 : Form { private void pictureBox1_MouseDown(object sender, MouseEventArgs e) { if (Bitmap == null) return; ClickedColor = Bitmap.GetPixel(e.X, e.Y); } Color _clickedColor = Color.Empty; Color ClickedColor { get { return _clickedColor; } set { _clickedColor = value; pictureBoxClickedColor.BackColor = value; labelClickedColor.Text = "クリックされた色 #" + value.A.ToString("x2") + value.R.ToString("x2") + value.G.ToString("x2") + value.B.ToString("x2"); } } } |
コピーするボタンがクリックされたらクリックされた色として保存されている色をを置換前または置換後の色として記憶します。これもラベルにカラーコードを表示させるとともにPictureBoxの背景色を変更することで視覚的にもわかるようにします。
以下は置換前の色を記憶させる処理です。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
public partial class Form1 : Form { private void buttonCopyBeforeColor_Click(object sender, EventArgs e) { BeforeColor = ClickedColor; } Color _beforeColor = Color.Empty; Color BeforeColor { get { return _beforeColor; } set { _beforeColor = value; pictureBoxBeforeColor.BackColor = value; labelBeforeColor.Text = "置換前の色 #" + value.A.ToString("x2") + value.R.ToString("x2") + value.G.ToString("x2") + value.B.ToString("x2"); } } } |
以下は置換後の色を記憶させる処理です。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
public partial class Form1 : Form { private void buttonCopyAfterColor_Click(object sender, EventArgs e) { AfterColor = ClickedColor; } Color _afterColor = Color.Empty; Color AfterColor { get { return _afterColor; } set { _afterColor = value; pictureBoxAfterColor.BackColor = value; labelAfterColor.Text = "置換後の色 #" + value.A.ToString("x2") + value.R.ToString("x2") + value.G.ToString("x2") + value.B.ToString("x2"); } } } |
色情報をユーザー自身が設定する
[自分で選択]ボタンをクリックすれば置換前または置換後の色を画像ファイルにある色から選ぶのではなく、ユーザー自身で自由に設定できます。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
public partial class Form1 : Form { ColorDialog beforeColorDialog = new ColorDialog(); private void buttonSelectBeforeColor_Click(object sender, EventArgs e) { beforeColorDialog.Color = BeforeColor; if (beforeColorDialog.ShowDialog() == DialogResult.OK) BeforeColor = beforeColorDialog.Color; } ColorDialog afterColorDialog = new ColorDialog(); private void buttonSelectAfterColor_Click(object sender, EventArgs e) { afterColorDialog.Color = AfterColor; if (afterColorDialog.ShowDialog() == DialogResult.OK) AfterColor = afterColorDialog.Color; } } |
設定した情報をクリアする
以下は記憶させていた置換前または置換後の色をクリアする処理です。
1 2 3 4 5 6 7 8 9 10 11 12 |
public partial class Form1 : Form { private void buttonClearBeforeColor_Click(object sender, EventArgs e) { BeforeColor = Color.Empty; } private void buttonClearAfterColor_Click(object sender, EventArgs e) { AfterColor = Color.Empty; } } |
画像ファイルの色を置換する
メニューの[置換する]を選択した場合は現在開かれている画像ファイルの各ピクセルで置換前で指定されているものがあれば置換後の色に変更します。GetReplaceBitmapメソッドは後述します。
1 2 3 4 5 6 7 8 9 10 |
public partial class Form1 : Form { private void MenuItemReplace_Click(object sender, EventArgs e) { if (Bitmap == null) return; Bitmap = GetReplaceBitmap(Bitmap); } } |
GetReplaceBitmapメソッドは以下のように定義されています。IsBeforeColorメソッド(後述)は引数で渡された色が置換前の色と一致するかを調べています。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
public partial class Form1 : Form { Bitmap GetReplaceBitmap(Bitmap sourceBitmap) { Bitmap newBitmap = new Bitmap(sourceBitmap.Width, sourceBitmap.Height); for (int x = 0; x < sourceBitmap.Width; x++) { for (int y = 0; y < sourceBitmap.Height; y++) { Color color = sourceBitmap.GetPixel(x, y); if (IsBeforeColor(color)) newBitmap.SetPixel(x, y, AfterColor); else newBitmap.SetPixel(x, y, color); } } return newBitmap; } } |
引数で渡された色が置換前の色と一致するかを調べるIsBeforeColorメソッドを示します。
設定で引数でわたされた色と完全一致していなくてもだいたい合っている場合も置換対象とします。
その許容される誤差がフィールド変数 DifferenceRed、DifferenceGreen、DifferenceBlueに格納されています。この3つがすべて0のときは完全一致でないと置換されません。
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 |
public partial class Form1 : Form { int DifferenceRed = 0; int DifferenceGreen = 0; int DifferenceBlue = 0; bool IsBeforeColor(Color color) { if (BeforeColor.ToArgb() == 0) { if (color.ToArgb() == 0) return true; else return false; } else { if (color.ToArgb() == 0) return false; int red = BeforeColor.R; int green = BeforeColor.G; int blue = BeforeColor.B; if (!(red - DifferenceRed <= color.R && color.R <= red + DifferenceRed)) return false; if (!(green - DifferenceGreen <= color.G && color.G <= green + DifferenceGreen)) return false; if (!(blue - DifferenceBlue <= color.B && color.B <= blue + DifferenceBlue)) return false; return true; } } } |
編集後の画像を保存する
メニューで[保存]が選択されたときの処理を示します。
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 |
public partial class Form1 : Form { SaveFileDialog saveFileDialog = new SaveFileDialog(); private void MenuItemSaveFile_Click(object sender, EventArgs e) { if (Bitmap == null) return; saveFileDialog.Filter = "png(*.png)|*.png|bmp(*.bmp)|*.bmp|gif(*.gif)|*.gif|jpg(*.jpg *.jepg)|*.jpg;*.jepg|tiff(*.tiff *.tif)|*.tiff;*.tif"; if (saveFileDialog.ShowDialog() == DialogResult.OK) { string path = saveFileDialog.FileName; FileInfo info = new FileInfo(path); if (info.Extension.ToLower() == ".png") Bitmap.Save(path, ImageFormat.Png); else if (info.Extension.ToLower() == ".bmp") Bitmap.Save(path, ImageFormat.Bmp); else if (info.Extension.ToLower() == ".gif") Bitmap.Save(path, ImageFormat.Gif); else if (info.Extension.ToLower() == ".jpg" || info.Extension.ToLower() == ".jepg") Bitmap.Save(path, ImageFormat.Jpeg); else if (info.Extension.ToLower() == ".tiff" || info.Extension.ToLower() == ".tif") Bitmap.Save(path, ImageFormat.Tiff); else Bitmap.Save(saveFileDialog.FileName); } } } |
許容できる誤差を設定する
許容できる誤差を設定できるようにする
[OK]ボタンがクリックされた場合はフィールド変数にNumericUpDownコントロールの値を格納して閉じるようにします。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
public partial class Form2 : Form { public Form2() { InitializeComponent(); // OKボタンをクリックしたらダイアログが閉じるようにする button1.DialogResult = DialogResult.OK; } public int Red = 0; public int Green = 0; public int Blue = 0; private void button1_Click(object sender, EventArgs e) { Red = (int)numericUpDownRed.Value; Green = (int)numericUpDownGreen.Value; Blue = (int)numericUpDownBlue.Value; } } |
メニューで[設定]が選択されたときの処理を示します。
上記のダイアログを表示させて[OK]ボタンがクリックされた場合はForm2クラスのフィールド変数に格納されている値を取得してフィールド変数 DifferenceRed、DifferenceGreen、DifferenceBlueに格納します。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
public partial class Form1 : Form { Form2 form2 = new Form2(); private void MenuItemColorError_Click(object sender, EventArgs e) { form2.Red = DifferenceRed; form2.Green = DifferenceGreen; form2.Blue = DifferenceBlue; if (form2.ShowDialog() == DialogResult.OK) { DifferenceRed = form2.Red; DifferenceGreen = form2.Green; DifferenceBlue = form2.Blue; } } } |
次回はファイルをまとめて保存する処理を実装します。