AWS Lambda with Node.js で S3 におかれた画像を即座に WebP に変換する関数を作りました。画像や画質の設定にもよりますが、同じクオリティの JPEG 比でだいたい半分くらいの容量になります。
たとえば s3://a/b/c.jpg
にアップロードされたら、 s3://a/b/c.webp
が生成されるようなイメージです。
cwebp を用意する
WebP を生成するにあたって、cwebp をラップしたライブラリ node-webp を使います。node-webp は、cwebp をラップするライブラリで、
- cwebp
- libwebp.so.5
の 2 つが必要です。Lambda はこの 2 つをデフォルトで持っていないので、デプロイ時に zip の中に含めておいて、コードの中でこちらを参照するようにしています。
if (!fs.existsSync("/usr/local/bin/cwebp")) {
const LIB_DIR = path.join(__dirname, "lib"); // ここに cwebp と libwebp.so.5 をおいた
process.env.PATH += `:${LIB_DIR}`;
process.env.LD_LIBRARY_PATH += `:${LIB_DIR}`;
}
Lambda でのバイナリの扱い
Lambda は Amazon Linux で稼働するので、Mac でコンパイルしたバイナリは実行できません。なので、EC2 や docker などで予め cwebp
と libwebp.so.5
を生成しておく必要がありました。
使ってみる
"サンプル画像"でググッて一番上にきた画像を拝借して変換してみます。
引用: http://wwwjp.kodak.com/JP/images/ja/digital/digitalcamera/standard/c330/sample/C330_02.jpg)
2304×1728 の場合
Duration: 8041.82 ms Billed Duration: 8100 ms Memory Size: 128 MB Max Memory Used: 48 MB
最小の 128 MB インスタンスでだいたい 8 秒くらい。
640×480 の場合
Duration: 2305.42 ms Billed Duration: 2400 ms Memory Size: 128 MB Max Memory Used: 30 MB
おなじく 128MB のインスタンスで、2.5秒くらい。
感想
若干時間はかかりましたが、多くの場合、EC2 で変換サーバを立てるよりはきっとお手軽・お手頃でお財布にも優しいはず。たとえば東京リージョンにおける 128MB の Lambda 関数は 100ms あたり $0.000000208 (2015/11/12現在) なので、1ドル120円としたら、ざっくりとした計算で 640x480 の変換は1枚あたり 0.00059904 円です。無料利用分を考えると、100万枚の変換までは 0 円で利用できます。
Lambda には同アカウント同リージョンで同時に 100 インスタンスまで立てられないという制限はありますが、この制限を超えたとしても、S3 からのイベントでは 24 時間リトライしてくれるので、変換できる画像であれば確実に変換してくれるはず。
バッチ処理で s3 にアップロードした画像を webp にも変換しておく、ような使い方にもあっているのではないかと思います。
以下のようなサムネイル生成と組み合わせることで、サムネイルを生成 + WebP も用意、というフローもかんたんに実現できます。