S3に画像をアップロードしたときにその画像のサムネイルを自動生成する…という類のものです。はじめは、本家のチュートリアルを参考にしてやってみたんですが、[Stream yields empty buffer]
というエラーが出て行き詰まり、解決を探しても見つからなかったので、結局自作しました。
ちなみに、AWS Lambdaでサムネイルを作る本家チュートリアルはこちら
[Stream yields empty buffer]
を調べて行き着いたのがこれら
- AWS Developer Forums: Stream yields empty buffer error when ...
- node.js - GraphicsMagick: toBuffer() Stream yields empty buffer
- node.js - gm Error in aws lambda: string yields empty buffer
- node.js - Got Error: Stream yields empty buffer when resizing images
で、結局以下のように自作した。
index.js
var AWS = require('aws-sdk');
var gm = require('gm').subClass({ imageMagick: true });
var util = require('util');
var s3 = new AWS.S3();
exports.handler = function(event, context, callback) {
var bucket = event.Records[0].s3.bucket.name; // 変換元画像のバケット名
var key = event.Records[0].s3.object.key; // 変換元画像のキー名
var thumbnailBucket = bucket + "-thumbnail"; // 変換後画像のバケット名(ここでは末尾にthumbnailを付け足すことにしてある)
var thumbnailKey = key; // 変換後画像のキー名(ここでは変換前と同じにしてある)
// 拡張子を抽出
var typeMatch = key.match(/\.([^.]*)$/);
if (!typeMatch) {
callback("Could not determine the image type.");
return;
}
// 拡張子がjpg, jpeg, pngのものだけ許可する
var imageType = typeMatch[1];
if (imageType != "jpg" && imageType != "jpeg" && imageType != "png") {
callback('Unsupported image type: ${imageType}');
return;
}
// S3の画像にアクセス
s3.getObject({Bucket: bucket, Key: key}, function(err, data){
if (err) { context.done('error getting object', err); }
// 画像処理 (http://qiita.com/komakomako/items/a33ff4e610e378d986ff と同じ)
gm(data.Body)
.resize(null, '350')
.borderColor('black')
.border('245', '245')
.gravity('Center')
.crop('490', '350')
.stream(function(err,stdout,stderr){ // ストリームで出力する
if(err){
console.log("gm process error");
console.log(err,stdout,stderr);
context.fail(err);
}
var chunks = []; // ストリームのチャンクを溜め込むための配列
stdout.on('data',function(chunk){
console.log('pushed');
chunks.push(chunk); // チャンクを溜め込む
});
stdout.on('end',function(){
console.log('end');
var buffer = Buffer.concat(chunks); // 最後まで溜め込んだら結合してバッファに書き出す
var params = {
Bucket: thumbnailBucket,
Key: thumbnailKey,
ContentType: imageType,
Body: buffer
};
s3.putObject(params, function(err, data) { // S3に書き出す
if(err){
console.log("gm upload error");
context.fail(err);
}
context.succeed({
"error":false
});
});
});
stderr.on('data',function(data){
console.log('stderr data: ' + data);
});
});
});
};
Lambdaへのデプロイの仕方
外部ライブラリgm
を使用しているので、上記のindex.js
と同じディレクトリで以下のコマンドを打ってこれらをインストール
npm install gm
すると、以下のようなディレクトリ構造になる。
- hogehoge/
- index.js
- node_modules/
次にindex.js
と同じディレクトリで以下のコマンドを打ってzipを作る。
zip a.zip *
すると、以下のようなディレクトリ構造になる。
- hogehoge/
- a.zip
- index.js
- node_modules/
このa.zip
をLambdaのブラウザコンソールからアップロードすればおk