のような画像を作成したあと、色を変えて
のようなものも作りたいと考えたことはありませんか?
文字列の「赤白赤白赤白赤白赤白」を「赤青赤青赤青赤青赤青」に一括置換するように画像の色を一括置換できるアプリを作成することにします。
これは画像のなかにある赤を青に一括置換するプログラムです。フォームにドロップするとoutputというフォルダをつくってそこにファイルを出力します。
Contents
とりあえず作ってみる
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 72 73 74 75 76 77 78 |
public partial class Form1 : Form { public Form1() { InitializeComponent(); } protected override void OnDragOver(DragEventArgs e) { if(e.Data.GetDataPresent(DataFormats.FileDrop)) e.Effect = DragDropEffects.All; else e.Effect = DragDropEffects.None; } protected override void OnDragDrop(DragEventArgs e) { if(e.Data.GetDataPresent(DataFormats.FileDrop)) { string[] files = (string [])e.Data.GetData(DataFormats.FileDrop); foreach(string path in files) { // ファイルが存在するフォルダとファイルの名前を取得する FileInfo info = new FileInfo(path); // 出力先フォルダがないなら作成する string folderPath = info.DirectoryName + "\\output"; if(!Directory.Exists(folderPath)) Directory.CreateDirectory(folderPath); // 出力ファイルのパス string outFilePath = folderPath + "\\" + info.Name; // 色を入れ替えたビットマップを得る Bitmap bitmap = ReplaceColor(path); if(bitmap != null) { // ファイルに保存する bitmap.Save(outFilePath); bitmap.Dispose(); } } } } Bitmap ReplaceColor(string filePath) { // 画像ファイルでないものが渡されたら例外を投げる try { Bitmap bitmap = (Bitmap)Bitmap.FromFile(filePath); int width = bitmap.Width; int height = bitmap.Height; Bitmap bitmapDest = new Bitmap(width, height); for(int x = 0; x < width; x++) { for(int y = 0; y < height; y++) { Color color = bitmap.GetPixel(x, y); // 赤なら青にする if(color == Color.Red) color = Color.Blue; bitmapDest.SetPixel(x, y, color); } } bitmap.Dispose(); return bitmapDest; } catch { return null; } } } |
どの色を入れ替えるかを指定できるようにする
ただこれはあまり使い勝手がよくありません。どの色を入れ替えるかを指定できるようにしたいものです。
それでこのようにします。
カラーダイアログを表示してそこから色を選べたり、実際に画像ファイルから色を取得することができるようにしました。
カラーダイアログから設定できるようにする
置換前の色[カラーダイアログから設定]をクリックするとカラーダイアログが表示されます。ここから置換前の色を設定します。
1 2 3 4 5 6 7 8 9 10 11 12 |
public partial class Form1 : Form { private void buttonSetPrevColor1_Click(object sender, EventArgs e) { ColorDialog dialog = new ColorDialog(); if(dialog.ShowDialog() == DialogResult.OK) { pictureBox1.BackColor = dialog.Color; } dialog.Dispose(); } } |
置換後の色[カラーダイアログから設定]をクリックした場合はこのような処理になります。置換前と置換後の色を設定したあとReplaceColorメソッドをつかって画像内にある色を置換します。
1 2 3 4 5 6 7 8 9 10 11 12 |
public partial class Form1 : Form { private void buttonSetAfterColor_Click(object sender, EventArgs e) { ColorDialog dialog = new ColorDialog(); if(dialog.ShowDialog() == DialogResult.OK) { pictureBox2.BackColor = dialog.Color; } dialog.Dispose(); } } |
ReplaceColorメソッド
ReplaceColorメソッドはこのように変更します。同じ色かどうかはアルファ値は無視して考えます。
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 |
public partial class Form1 : Form { Bitmap ReplaceColor(string filePath) { try { Bitmap bitmap = (Bitmap)Bitmap.FromFile(filePath); int width = bitmap.Width; int height = bitmap.Height; Bitmap bitmapDest = new Bitmap(width, height); for(int x = 0; x < width; x++) { for(int y = 0; y < height; y++) { Color color = bitmap.GetPixel(x, y); if(IsEqualColor(color, pictureBox1.BackColor)) { color = pictureBox2.BackColor; } bitmapDest.SetPixel(x, y, color); } } bitmap.Dispose(); return bitmapDest; } catch { return null; } } bool IsEqualColor(Color color1, Color color2) { Text = color1.R.ToString() + " " + color2.R.ToString(); if(color1.R != color2.R) return false; if(color1.G != color2.G) return false; if(color1.B != color2.B) return false; return true; } } |
画像から置換前の色を設定する
次に実際に存在する画像から置換前の色を設定する方法ですが、別のフォームに画像を表示させ、画像をクリックすることで設定できるようにします。表示されるダイアログはこんな感じです。
まずはフィールド変数とコンストラクタについて。
フィールド変数Imageは画像ファイルのイメージです。Colorは設定したい色です。ピクチャーボックスがクリックされたらイベントハンドラPictureBox1_MouseDownが呼ばれるようにしています。そしてボタンがクリックされたらダイアログを閉じます([OK]がクリックされたときと同じ)。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
public partial class Form2 : Form { public Image Image = null; public Color Color = Color.Empty; public Form2() { InitializeComponent(); button1.DialogResult = DialogResult.OK; this.Load += Form2_Load; pictureBox1.MouseDown += PictureBox1_MouseDown; } } |
ダイアログが表示されたらピクチャーボックスに画像ファイルのイメージを表示させます。
1 2 3 4 5 6 7 |
public partial class Form2 : Form { private void Form2_Load(object sender, EventArgs e) { pictureBox1.Image = Image; } } |
ピクチャーボックスがクリックされたらその位置にあるピクセルの色を取得し、もうひとつのピクチャーボックスに表示させます。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
public partial class Form2 : Form { private void PictureBox1_MouseDown(object sender, MouseEventArgs e) { try { Bitmap bitmap = (Bitmap)Image; Color color = bitmap.GetPixel(e.X, e.Y); pictureBox2.BackColor = color; Color = color; } catch { } } } |
[画像ファイルから設定]がクリックされたときのイベントハンドラ
ではもう一度form1のメソッドをみてみましょう。これは置換前の色[画像ファイルから設定]がクリックされたときの処理です。ファイルを開くダイアログで選択されたファイルが画像ファイルではない場合もあるので例外処理をつかっています。
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 { private void buttonSetPrevColor2_Click(object sender, EventArgs e) { OpenFileDialog dialog = new OpenFileDialog(); if(dialog.ShowDialog() != DialogResult.OK) { dialog.Dispose(); return; } string filePath = dialog.FileName; dialog.Dispose(); try { Image image = Image.FromFile(filePath); Form2 f = new Form2(); f.Image = image; if(f.ShowDialog() == DialogResult.OK) { pictureBox1.BackColor = f.Color; } image.Dispose(); f.Dispose(); } catch { return; } } } |