AWS Lambda(C#)でMagick.NETを使ってみる

はじめに

「Magick.NET」は「ImageMagick」の.NET向けライブラリです。

ImageMagick(イメージマジック)は画像を操作したり表示したりするためのソフトウェアスイートである。GIF、JPEG、JPEG 2000、PNG、PDF、Photo CD、TIFF、DPXなど100種類以上の画像ファイルフォーマットに対応している。GPL互換でより制限が緩い独自ライセンスが適用されている。

出典: フリー百科事典『ウィキペディア(Wikipedia)』

今回は、「Magick.NET」をAWS Lambda上で使えるか試してみようと思います。

実装

あらかじめNugetから「Magick.NET(AnyCPU)」パッケージをインストールしておきます。今回はQ8を選択しました。

また、Lambdaプロキシ統合を使用して動作確認をするため「APIGatewayEvents」パッケージも追加インストールしました。

以下、ソースコードのサンプルです。SVG(XML)形式でサンプル画像を作成し、Magick.NETを用いてPNG形式に変換後、呼び出し元のAPI Gatewayへ返却しています。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;

using Amazon.Lambda.Core;
using Amazon.Lambda.APIGatewayEvents;
using ImageMagick;

// Assembly attribute to enable the Lambda function's JSON input to be converted into a .NET class.
[assembly: LambdaSerializer(typeof(Amazon.Lambda.Serialization.SystemTextJson.DefaultLambdaJsonSerializer))]

namespace AWSLambda7
{
    public class Function
    {
        public APIGatewayProxyResponse FunctionHandler(APIGatewayProxyRequest input, ILambdaContext context)
        {
            MagickReadSettings settings = new MagickReadSettings();
            settings.Format = MagickFormat.Svg;

            MagickImage img = new MagickImage(System.Text.Encoding.UTF8.GetBytes(GetSampleSVG()), settings);

            img.Format = ImageMagick.MagickFormat.Png;

            var body = Convert.ToBase64String(img.ToByteArray());

            img.Dispose();

            var myHeaders = new Dictionary<string, string>();
            myHeaders.Add("Content-Type", "image/png");
            myHeaders.Add("Content-Disposition", "attachment; filename=sample.png");

            var response = new APIGatewayProxyResponse
            {
                StatusCode = 200
             ,
                Body = body
             ,
                IsBase64Encoded = true
             ,
                Headers = myHeaders
            };

            return response;
        }

        private string GetSampleSVG()
        {
            int layer_x = 8;
            int layer_y = 8;
            int size = 16;
            int vx = layer_x * size;
            int vy = layer_y * size;

            string svg = "";
            svg += "<svg xmlns=\"http://www.w3.org/2000/svg\"";
            svg += "     xmlns:xlink=\"http://www.w3.org/1999/xlink\"";
            svg += "     viewBox=\"0 0 " + vx + " " + vy + "\" ";
            svg += ">";

            for (int y = 0; y < layer_y; y++)
            {
                for (int x = 0; x < layer_x; x++)
                {
                    int gx = x * size;
                    int gy = y * size;
                    if ( (x+y) % 2 == 0 )
                    {
                        svg += "<rect x=\"" + gx.ToString() + "\" y=\"" + gy.ToString() + "\" width=\"" + size + "\" height=\"" + size + "\" fill=\"black\" />";
                    }
                }
            }
            svg += "</svg>";

            return svg;
        }
    }
}

早速上記Lambda関数をパブリッシュし、トリガーにAPI Gatewayを追加してみます。

ここで注意点です。

AWS Lambda プロキシ統合からバイナリメディアを返すには、base64 で Lambda 関数からのレスポンスをエンコードします。また、API のバイナリメディアタイプを設定する必要があります。

出典:Lambda プロキシ統合からバイナリメディアを返す – Amazon API Gateway

API Gatewayの設定画面を開き、「バイナリメディアタイプ」を設定します。今回は”*/*”(すべてのコンテンツタイプ)を設定しました。

設定保存後、APIのデプロイを忘れずにしましょう。

動作確認

ブラウザからエンドポイントのURLをたたくと、sample.pngファイルがダウンロードできます。

ファイルを開き、下記のような画像が表示されれば動作確認OKです。

以上です。