ASP.NETとImageMagickで動的画像サーバーを作る #aspnetjp
この記事はOne ASP.NET Advent Calendar 2013 - Adventarの9日目の記事です。遅くなって大変申し訳なく。
ASP.NETとImageMagickで画像サーバーを作る
ImageMagickってなんぞやって方もいらっしゃるかと思いますが、とても有名な画像変換ツールです。
ImageMagick(イメージマジック)は画像を操作したり表示したりするためのソフトウェアスイートである。
ImageMagick - Wikipedia
僕とImageMagickとの出会いは、Silverlight(遠い目)。Silverlightのハイパー素敵機能DeepZoomの基ファイルを図面ファイルから生成したり、システムのファイルのサムネイル作ったり、ラジバンダリ。
運用
何らかのファイルをアップロード→サムネイルを複数解像度で作成→ストレージに保存→何らかで参照→偉い方「@KatsuYuzu君、これもっと大きくならん?」→DBからオリジナルファイル出してきて、しこしこ変換。
実にだるい
動的にやりたいよねって調べてたら、まさにクックパッドさんがTOFUなんて素敵システム作ったりしてました。
tofuは動的にサムネイル生成をするシステムです。動的と聞くと遅そうに感じる人もいるかも知れませんが、意外といけます。しかもImageMagickで。
私がクックパッドの画像配信野郎です - 昼メシ物語
ImageMagick
今回はお手軽にImageMagickの実行ファイルを呼び出して、出力されたファイルを参照してしまいます。ImageMagick自体は下記のようなコマンドで実行可能です。
convert [オプション] 基ファイル 出力ファイル
オプションは本当に、本当に多いので、割愛。ただ、一つ、とても大事なポイントが。
いつもの convert に「-define jpeg:size=...」をつけるだけで10倍速くなる
本当は速いImageMagick: サムネイル画像生成を10倍速くする方法 - 昼メシ物語
基ファイルがJPEGの場合にのみ、あらかじめ画像を小さく開くことで省メモリーで高速化されます。小さく開いてもJPEGのアルゴリズム的に問題ないよううまくやってくれるようです。
ASP.NET
今回は事例紹介のようなものなのでコードは必要な要素を散りばめてあるだけです。
コントローラー。システム上でファイルを扱っているIDとサイズを受け取って変換、出来上がったファイルを返します。
public class ImageController : Controller { public ActionResult Thumbnail(string fileId, int width, int height, string fileName) { // 基ファイル var sourceFilePath = Path.Combine(Server.MapPath("~/Content"), fileId + ".jpg"); // 出力ファイル var resultFilePath = Path.Combine(Server.MapPath("~/App_Data"), fileName); // ImageMagick のパス var tool = @"C:\Program Files\ImageMagick-6.8.7-Q16\convert.exe"; // ImageMagick への引数 var arguments = string.Format( @"-define jpeg:size={2}x{3} -resize {2}x{3} ""{0}"" ""{1}""", sourceFilePath, resultFilePath, width, height); // コマンドの実行 ExecuteCommand(tool, arguments); // 結果 return File(resultFilePath, "image/jpeg"); } // コマンドの実行(コマンドプロンプトに引き渡すだけ) private static void ExecuteCommand(string tool, string arguments)... }
ルーティング。URL にコントローラーとアクションが登場しない場合は defaults での指定が必要です。
routes.MapRoute( name: "Image", url: "{fileId}/{width}x{height}/{fileName}", defaults: new { controller = "Image", action = "Thumbnail" } );
ビュー。適当に欲しいサイズで。
<div class="row"> <img src="~/image1/320x240/image1-320-240.jpg" /> <img src="~/image1/640x480/image1-640-480.jpg" /> <img src="~/image1/800x600/image1-800-600.jpg" /> </div>
結果
かわゆすなあ。
まとめ
やるだけであれば結構簡単にできちゃいます。ImageMagick便利。
ここからの発展では下記のようなことを考慮して、規模に合わせて*1運用していく必要がありますね。
- 変換の非同期化
- キャッシュ
追記 23:30
ああっと、お手軽紹介だけでストリームの紹介を忘れてました。
ImageMagickのコマンドは"jpg:-"*2とすることでStandardInputStreamにもStandardOutputStreamにも対応しているので、もっとおいしく使えますよ。
追記 12/11
続きを書きました。
nugetでインストールして.net wrapperから動かします。事前のインストールやコマンドライン実行などが不要となっています。
ASP.NETとImageMagickで動的画像サーバーを作る その2 #aspnetjp - KatsuYuzuのブログ