読者です 読者をやめる 読者になる 読者になる

Make Local Happiness

自分の幸せは自分で作る!!!

AWSのLambda上でSVGをPNG画像に変換する〜Phantomjs編〜

API Gateway AWS Phantomjs svg2png Lambda

前回はFabricを利用し、LambdaでSVGPNG画像に変換するということを試しましたが、 今回はPhantomjsを使って同じことをやっていきます。

ganeza.hatenablog.com

Phantomjs とは?

http://phantomjs.org/

簡単に言うとディスプレイ不要のJavascriptAPIを備えたWebkit実行環境です。 ネイティブブラウザと同じようにDOM操作、CSSセレクター、JSONCanvasSVGもサポートしています。

PhantomJS is a headless WebKit scriptable with a JavaScript API. It has fast and native support for various web standards: DOM handling, CSS selector, JSON, Canvas, and SVG.

主な使い方として、以下の4つが公式ページに記載されています。

  • HEADLESS WEBSITE TESTING
  • SCREEN CAPTURE
  • PAGE AUTOMATION
  • NETWORK MONITORING

今回は2番目のスクリーンキャプチャの機能を使って、 SVGPNG画像に変換していきます。

実装

コードを見てもらうとわかるのですが、 Fabric編のコードよりもさらに簡単になりました。 svg2pngというPhantomjsを利用したパッケージを使っていますが、 CLIでも試すことができ、かなり便利でした。

github.com

さらに、Fabricで描画されなかったforeignObjectも表示されました。
これはかなり嬉しいです。

#hander.js

'use strict';

const aws = require('aws-sdk'),
  s3 = new aws.S3({ apiVersion: '2006-03-01' }),
  md5 = require('md5'),
  svg2png = require("svg2png"),
  env = require('./env.js'),
  hash = md5(new Date().getTime()),
  imageKey = `${hash}.png`,
  phantomjsCmd = './phantomjs';

module.exports.convert = (event, context) => {
  const params = event.body;

  if (params === undefined) {
    return context.done(null,{
      status: 'error',
      msg: 'you should check params.',
      your_params: event,
      sample_params: {
        "body": {
          svgString: 'xxx',
        }
      }
    });
  }

  const svgString = decodeURIComponent(params.svgString);
  const sourceBuffer = new Buffer(svgString);
  const options = params.local ? {} : { phantomjsPath: phantomjsCmd };

  svg2png(sourceBuffer, options)
    .then(buffer => {
      s3.putObject(
        {
          'Bucket': env.BUKKET,
          'ACL': 'public-read',
          'Key': imageKey,
          'ContentType': 'image/png',
          'Body': buffer
        },
        function (error) {
          if(error === null) {
            return context.done(null,{
              status: 'success',
              msg: `https://s3-${env.REGION}.amazonaws.com/${env.BUKKET}/${imageKey}`,
            });
          } else {
            return context.done(null, {
              status: 'error',
              msg: error
            });
          }
        }
      );
    })
    .catch(e => {
      return context.done(null, {
        status: 'error',
        msg: e
      });
    });
};

【問題1】svg2pngがES6の記法で書かれており、LambdaではES6の記法が使えない

このFunctionの初期値の設定で利用している部分の書き方でエラーになっていました。

なので、Lambdaで使いたいから修正をPullRequestで送ったのですが、 古い書き方に対応するつもりはないよって言われあっさり断られました。

なので、Forkしたプロジェクトをnpmで利用することにしました。

github.com

【問題2】MacでビルドしたPhantomjsのモジュールではLambda上では動作しない

svg2pngのoptionsにパラメータを渡した際に、
Phantomjsのパスを変更できるように変更しました。

こちらの修正も先程のPullRequestに含まれています。

Linux用のモジュールはこちらからダウンロードできます。

$ wget https://bitbucket.org/ariya/phantomjs/downloads/phantomjs-2.1.1-linux-x86_64.tar.bz2
$ tar -xjvf ./phantomjs-2.1.1-linux-x86_64.tar.bz2
$ mv phantomjs-2.1.1-linux-x86_64/bin/phantomjs ./

まとめ

画像処理系のパッケージは環境依存のライブラリーを使うので、 Lambdaで使う際には少し面倒くさいですね。

Phantomjsは今回初めて使いました。
今まで、テストで使うものと思っていましたが、 コマンドライン上で動くブラウザと考えると色々なことができそうですね。