2015年9月28日月曜日

ASP.NETで動的に画像を生成して返す(IHttpHandler版)

ASP.NETで動的に画像を生成して返すようなときは、WebFormを使用するのが一般的なようです。

この記事ではIHttpHandlerインターフェイスを実装して画像を生成して返す方法を紹介します。
以下2つの手順に従います。

  1. IHttpHandlerインターフェイスを実装した画像を出力するクラスを実装する
  2. 1のクラスをweb.configファイルへ登録する
まず「IHttpHandlerインターフェイスを実装した画像を出力するクラスを実装する」について説明します。このクラスのポイントは3つあります。
  1. IHttpHandlerインターフェイスを実装すること
  2. 画像のバイナリデータをHTTPレスポンスへ出力すること
  3. Content-Typeヘッダを適切に設定すること
次のサンプルプログラム(一部)をご覧ください。
namespace HttpHandlerSample
{
    // 動的にPNG画像を生成するクラス
    public class PngHandler : IHttpHandler
    {
        // このオブジェクトが再利用可能かを返すプロパティ
        public bool IsReusable
        {
            get
            {
                return true;
            }
        }

        // ...略...

        // HTTPリクエストを処理するメソッド
        public void ProcessRequest(HttpContext context)
        {
            // 画像を生成する
            using (var image = GenerateImage())
            {
                // PNG形式でHTTPレスポンスへ出力する
                var output = context.Response.OutputStream;
                image.Save(output, ImageFormat.Png);
                output.Flush();
            }

            // Content-TypeヘッダをPNG形式に設定する
            context.Response.ContentType = "image/png";
        }

        // ...略...

    }
}

IHttpHandlerにはIsReusableプロパティとProcessRequestメソッドが定義されています。このProcessRequestメソッドを実装することで機能を実現します。
画像のバイナリデータを出力するには、Image#Saveメソッドを使用します。
Content-Typeヘッダを指定するには、HttpResponse#ContentTypeプロパティを使用します。画像の形式が一致するように設定します。

次に、上のクラスをweb.configへ以下のように設定します。
<configuration>
  <system.webServer>
    <handlers>
      <add name="PngHandler" path="*.png" verb="GET" type="HttpHandlerSample.PngHandler"/>
    </handlers>
  </system.webServer>
</configuration>
ちなみに

以上で動的な画像の生成が実現できます。
以下、サンプルコード全体です。


using System;
using System.Drawing;
using System.Drawing.Imaging;
using System.IO;
using System.Web;

namespace HttpHandlerSample
{
    // 動的にPNG画像を生成するクラス
    public class PngHandler : IHttpHandler
    {
        // 画像の幅
        public const int Width = 200;

        // 画像の高さ
        public const int Height = 20;

        // フォントサイズ
        public const float FontSize = 10f;

        private readonly Font font;

        private readonly Brush brush;

        // このオブジェクトが再利用可能かを返すプロパティ
        public bool IsReusable
        {
            get
            {
                return true;
            }
        }

        public PngHandler()
        {
            font  = new Font(FontFamily.GenericMonospace, FontSize);
            brush = Brushes.Red;
        }

        // HTTPリクエストを処理するメソッド
        public void ProcessRequest(HttpContext context)
        {
            // 画像を生成する
            using (var image = GenerateImage())
            {
                // PNG形式でHTTPレスポンスへ出力する
                var output = context.Response.OutputStream;
                image.Save(output, ImageFormat.Png);
                output.Flush();
            }

            // Content-TypeヘッダをPNG形式に設定する
            context.Response.ContentType = "image/png";
        }

        // 画像を生成する
        private Image GenerateImage()
        {
            // このサンプルでは現在時刻を表示する画像を生成する
            var now = DateTime.Now;
            var strNow = now.ToString();

            var bmp = new Bitmap(Width, Height);
            using (var graphic = Graphics.FromImage(bmp))
            {
                graphic.DrawString(strNow, font, brush, 0f, 0f);
            }
            return bmp;

        }
    }
}

0 件のコメント:

コメントを投稿