KatsuYuzuのブログ

.NET の開発をメインとした日記です。

ASP.NETとImageMagickで動的画像サーバーを作る その2 #aspnetjp

この記事はC# Advent Calendar 2013 - Adventarの11日目の記事です。
先日のASP.NETとImageMagickで動的画像サーバーを作る #aspnetjp - KatsuYuzuのブログの続きです。某カレンダーの種類が変わっているけど気にしない……!
f:id:KatsuYuzu:20131224233030j:plain

ASP.NETImageMagickで動的画像サーバーを作る(改)

何が改か。*1
先日の紹介ではサーバーにImageMagickのインストールが必要でした。また、実行ファイルの呼び出しとファイルの読み取り、更にはStreamにしたって標準出力の読み取りが必要でした。
今回もImageMagickを使いますが上記のような面倒はすべて不要です。モダンにnugetでぽいっと、C#でさくっといきます。

MagickNet

ImageMagickの.net wrapperのMagickNetというものがcodeplexにありました。
Magick.NET - Home
こちらを使用すればサーバーへのインストールが不要だと書かれています。そしてnugetが公開されている。素晴らしい。

usage

codeplexのdocumentationでサンプルが示されているので、すぐに使えました。と、言うかこのライブラリが素敵すぎて簡単です。転載もアレなのでそちらを参照して頂きたいのですが感じてもらいたいので一部紹介。

// Read from file.
using (MagickImage image = new MagickImage("Snakeware.jpg"))
{
}

Magick.NET - Documentation

もちろん、各種オプションも可能です。下記からexamplesを参照してください。
Magick.NET - Documentation

ASP.NET

先日のサンプルプロジェクトにnugetでMagickNetをインストールします。
f:id:KatsuYuzu:20131211004243p:plain
上記のスクリーンショットで"x86"をインストールしていることに注目してください。x86かx64かはIISのアプリケーションプールに合わせる必要があります。始めに"x64"をインストールしてIIS Expressで実行したらエラーが出ました。

ファイルまたはアセンブリ 'Magick.NET-x64'、またはその依存関係の 1 つが読み込めませんでした。間違ったフォーマットのプログラムを読み込もうとしました。

ソースコードの修正はコントローラーのみです。

public ActionResult Thumbnail(string fileId, int width, int height, string fileName)
{
    // 基ファイルのパス
    var sourceFilePath = Path.Combine(Server.MapPath("~/Content"), fileId + ".jpg");
    
    // ImageMagick の設定を作成してインスタンスを初期化する
    // 先日のコマンド例:@"-define jpeg:size={2}x{3} -resize {2}x{3} ""{0}"" ""{1}"""
    var settings = new MagickReadSettings();

    // -define jpeg:size={0}x{1}
    settings.SetDefine(
        MagickFormat.Jpeg,
        "size",
        string.Format("{0}x{1}", width, height));
   
    using (var image = new MagickImage(sourceFilePath, settings))
    {
        // -resize {0}x{1}
        image.Resize(width,height);

        // FileContentResult のバイトを受け取るオーバーロード
        return File(image.ToByteArray(), "image/jpeg");
    }
}

とてもすっきりしました。コンストラクタはもちろんオーバーロードでStreamにも対応していますのでDBからの読出しなどでもいけるでしょう。
高速化オプションのdefineについては画像の読出し前、つまり、インスタンスを初期化する前に設定して引き渡す必要があります。

パフォーマンスは?

2MB~3MBの写真の応答で0.数秒です。
f:id:KatsuYuzu:20131211011505p:plain
ちなみにdefineの指定がないと2秒台まで落ちたので、10倍高速化という例の記事の通りですね。
f:id:KatsuYuzu:20131211011813p:plain

まとめ

.NET使いはMagickNetを使おう。

*1:余談ですが某艦隊ゲーは挫折しました。