###背景
写真アプリを作っていて、一覧画面を作ったが、ファイルサイズが大きくて表示に時間がかかってしまう。そのため、オリジナルファイルの表示ではなく、サムネールを表示し、選択したもののみをダウンロード表示するような仕組みに変更することにした。そこで、サムネールの作る必要があったため、そのメモとなる。
仕組み的には、Multerでファイルをアップロードし、アップロードしたファイルをSharpでリサイズして、私が利用しているS3へオリジナルファイルとサムネールの両方をアップロードする仕組み。
###Multer
Multer自体は上記の説明が詳しいですが、私は単一ファイルのアップロードを利用して、特にStorageなども使ってはない。
RoutesでMulterを定義した。
// ファイルをアップロードし、一時保管するフォルダを定義
var multer = require('multer');
var upload = multer({
dest: 'uploads/',
limits: {
fieldSize: 25 * 1024 * 1024
}
})
// Multerをミドルウェアとして利用しているコードの部分だけ抜粋。
router.post('/:albumid/upload', authenticateJWT, upload.single('formtest'), PicturesController.uploadNewPicture);
上記のように定義して、実際私とControllerにてアップロードしたファイルを参照したかったですが、
少し上記の文章と異なる部分があった。
req.fileでは、undefinedになっている。
そのため、req.fileではなく、req.body.fileを利用した。
// 上記の参照した文章では、下記のコードでファイルを参照していたが、私はUndefinedになっている。
file = req.file
// 私は下記のようにreqのbodyからファイルを取得することができた。
file = req.body.file
###Sharp
上記はSharpの公式ドキュメントである。
私が直面したエラーが一つあり、下記である。
Error: Input file contains unsupported image format
私はフロントエンドでFileReaderを利用して、ファイルを取得している。
最初は全然気にしていなかったが、下記のサイトで下記のようなコメントがある。
The blob's result cannot be directly decoded as Base64 without first removing the Data-URL declaration preceding the Base64-encoded data. To retrieve only the Base64 encoded string, first remove data:/;base64, from the result.
Data-URL宣言を削除してから、base64でエンコードしたファイルになるようです。
そのため下記のような変換が必要となる。
// req.body.fileをそのままSharpのinputとして入力するとエラーになる。
// Error: Input file contains unsupported image format
imagefile = Buffer.from(req.body.file.replace(/^data:image\/\w+;base64,/, ""),'base64');
sharp(imagefile)
.resize(200,200, {
// リサイズする時のオプション設定、詳しくは上記の公式サイトへ
// アスペクト比を維持しながら、画像のサイズをできるだけ大きくする
fit: sharp.fit.inside,
// ファイルサイズが指定のサイズより低ければ変更しない
withoutEnlargement: true
})
.toFormat('jpeg')
.toBuffer()
.then(function(outputBuffer){
// Upload image file to S3
// 実際、オリジナルファイルとサムネールを両方S3へアップロードしている。
// imagefile と outputbufferをs3.putObjectを利用してアップロードすれば良い。
}
###S3
次いでにS3へファイルをアップロードするコードも添付。
// Setting up S3 upload parameters
const params = {
Bucket: process.env.MyPhotoBucket,
Key: s3key,
ContentType: 'image/jpeg',
ContentEncoding: 'base64',
Body: bufferfile
};
// Uploading files to the bucket
var s3response = await s3.putObject(params, function(err, data) {
if (err) {
console.log("error happend when upload file to s3");
console.log(err);
throw err;
}
console.log(`File uploaded successfully. ${data}`);
}).promise();
以上です。