画像ファイルのなかにはサイズが大きなものがあります。その画像ファイルの重要性が高画質であることであれば画像ファイルのサイズが多少大きくなることは仕方がないことなのかもしれません。
しかしその画像が単なる情報(たとえば領収書を写真にとったもの)であればどうでしょうか? 高画質である必要はありません。目的を達成できる画質をキープしているのであれば、サイズ的にも小さいほうがよいと考えられます。しかもこの画像をメールで他の人に送信するのであればなおさらです。
そこで今回は複数の画像を同時に変更するアプリを作成します。ひとつひとつ画像の大きさを手作業で変更しているようではいくら時間がかかるかわかりません。こういうことはコンピュータにやらせてしまいましょう。
複数の画像ファイルを選択して(もちろん一個でもよい)、フォームにドロップすれば出力用のフォルダのなかにサイズダウンした画像ファイルを保存します。
画像は一律サイズを50%にするとか、縦横の比を崩さず幅を500ピクセルにするといった要望にも応えられるアプリを作成します。
ではデザイナで以下のようなフォームを作成してみましょう。
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 |
public partial class Form1 : Form { public Form1() { InitializeComponent(); this.AllowDrop = true; this.DragOver += Form1_DragOver; this.DragDrop += Form1_DragDrop; } private void Form1_DragOver(object sender, DragEventArgs e) { if(e.Data.GetDataPresent(DataFormats.FileDrop)) { e.Effect = DragDropEffects.All; } } private void Form1_DragDrop(object sender, DragEventArgs e) { if(e.Data.GetDataPresent(DataFormats.FileDrop)) { string[] files = (string[])e.Data.GetData(DataFormats.FileDrop); foreach(string filePath in files) { // ここで画像ファイルのサイズ変更の処理をおこなう SaveSizeChangedImage(filePath); } } } } |
最初は「画像は一律サイズを50%」にすることを考えます。
まずドロップされたファイルは画像ファイルなのかどうかを確かめる必要があります。
GetBitmapIfImageFile(string filePath)メソッドは画像ファイルであればBitmapを返します。そうでない場合はnullを返します。
画像ファイルであれば画像の縦横を半分にします。
新しく作成されたファイルは元のファイルと同じフォルダ内にoututというフォルダを作成して、そこにファイル名は変えずに保存するすることにします。このときのファイルパスを求めるのがGetSaveFilePath(string filePath)メソッドです。
FileInfoクラスを使えば元のファイルが存在するフォルダはわかります。そこで
1 2 |
FileInfo info = new FileInfo(filePath); info.DirectoryName + "\\Output\\" + info.Name; |
これでよいと早合点。実際にテストしてみるとうまくいきません。処理をする前はOutputフォルダは存在しないので例外が発生していたのです。ファイルを保存するときは保存先のフォルダが存在することを確認しなければなりません。ない場合は作成すること。こういうケアレスミスには気をつけましょう。
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 79 80 81 82 |
using System.Drawing.Imaging; using System.IO; public partial class Form1 : Form { void SaveSizeChangedImage(string filePath) { // ドロップされたファイルは画像ファイルなのか? Bitmap orgBitmap = GetBitmapIfImageFile(filePath); if(orgBitmap == null) return; // 画像ファイルであれば画像の縦横を半分に int width = orgBitmap.Width; int height = orgBitmap.Height; int newWidth = width / 2; int newHeight = height / 2; // 縦横が半分の新しいBitmapを作成して、そこにorgBitmapを描画する Bitmap newBitmap = new Bitmap(newWidth, newHeight); Graphics g = Graphics.FromImage(newBitmap); g.DrawImage(orgBitmap, new Rectangle(0, 0, newWidth, newHeight)); g.Dispose(); // 処理後のファイルを保存するパスを取得する(ケアレスミスに注意!) string outputPath = GetSaveFilePath(filePath); // 拡張子を取得する Bitmap.Saveメソッドの第二引数で使う string ext = GetFileExtension(filePath); if(ext.ToLower() == ".png") newBitmap.Save(outputPath, ImageFormat.Png); else if(ext.ToLower() == ".bmp") newBitmap.Save(outputPath, ImageFormat.Bmp); else if(ext.ToLower() == ".gif") newBitmap.Save(outputPath, ImageFormat.Gif); else if(ext.ToLower() == ".jpg") newBitmap.Save(outputPath, ImageFormat.Jpeg); else if(ext.ToLower() == ".Tiff") newBitmap.Save(outputPath, ImageFormat.Tiff); else newBitmap.Save(outputPath); orgBitmap.Dispose(); newBitmap.Dispose(); } Bitmap GetBitmapIfImageFile(string filePath) { Image image; try { image = Image.FromFile(filePath); Bitmap bitmap = new Bitmap(image); image.Dispose(); // ファイルがロックしないようにする return bitmap; } catch { return null; } } string GetSaveFilePath(string filePath) { FileInfo info = new FileInfo(filePath); // ファイルと同じフォルダ内にoututというフォルダを作成して、そこにファイル名は同名で保存する // フォルダが存在しない場合は作成すること。さもなくばエラー if(!Directory.Exists(info.DirectoryName + "\\Output")) Directory.CreateDirectory(info.DirectoryName + "\\Output"); return info.DirectoryName + "\\Output\\" + info.Name; } string GetFileExtension(string filePath) { FileInfo info = new FileInfo(filePath); return info.Extension; } } |
一応これで完成です。
次に機械的に50%に縮小してしまうと小さい画像ファイルは小さくなりすぎてしまいます。そこで横は500ピクセル以下の場合はなにもしない、縮小するときは縦横比を崩さないように横は500ピクセルにするような処理をしたくなることもあると思います。そんなときはどうすればいいのでしょうか?
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 |
public partial class Form1 : Form { // 横は500ピクセル以下の場合はなにもしない、 // 縮小するときは縦横比を崩さないように横は500ピクセルにする void SaveSizeChangedImage2(string filePath) { Bitmap orgBitmap = GetBitmapIfImageFile(filePath); if(orgBitmap == null) return; // 画像ファイルであれば画像の横幅を調べる int width = orgBitmap.Width; int newWidth = width; int newHeight = height; // 縦横比を崩さないように幅を500ピクセルにしたとき // 適切な高さを計算する if(width > 500) { newWidth = 500; double div = 500d / width; newHeight = height * div; } // 縦横が半分の新しいBitmapを作成して、そこにorgBitmapを描画する Bitmap newBitmap = new Bitmap(newWidth, newHeight); Graphics g = Graphics.FromImage(newBitmap); g.DrawImage(orgBitmap, new Rectangle(0, 0, newWidth, newHeight)); g.Dispose(); // 処理後のファイルを保存するパスを取得する(ケアレスミスに注意!) string outputPath = GetSaveFilePath(filePath); // 拡張子を取得する Bitmap.Saveメソッドの第二引数で使う string ext = GetFileExtension(filePath); if(ext.ToLower() == ".png") newBitmap.Save(outputPath, ImageFormat.Png); else if(ext.ToLower() == ".bmp") newBitmap.Save(outputPath, ImageFormat.Bmp); else if(ext.ToLower() == ".gif") newBitmap.Save(outputPath, ImageFormat.Gif); else if(ext.ToLower() == ".jpg") newBitmap.Save(outputPath, ImageFormat.Jpeg); else if(ext.ToLower() == ".Tiff") newBitmap.Save(outputPath, ImageFormat.Tiff); else newBitmap.Save(outputPath); orgBitmap.Dispose(); newBitmap.Dispose(); } } |