LoginSignup
1
1

More than 1 year has passed since last update.

Nodejs: multerでファイルアップロードし、sharpでファイルをリサイズして、S3へファイルをアップロード

Posted at

背景

写真アプリを作っていて、一覧画面を作ったが、ファイルサイズが大きくて表示に時間がかかってしまう。そのため、オリジナルファイルの表示ではなく、サムネールを表示し、選択したもののみをダウンロード表示するような仕組みに変更することにした。そこで、サムネールの作る必要があったため、そのメモとなる。

仕組み的には、Multerでファイルをアップロードし、アップロードしたファイルをSharpでリサイズして、私が利用しているS3へオリジナルファイルとサムネールの両方をアップロードする仕組み。

Multer

Multer自体は上記の説明が詳しいですが、私は単一ファイルのアップロードを利用して、特にStorageなども使ってはない。
RoutesでMulterを定義した。

route.js
// ファイルをアップロードし、一時保管するフォルダを定義
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を利用した。

Controller.js
  // 上記の参照した文章では、下記のコードでファイルを参照していたが、私は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でエンコードしたファイルになるようです。
そのため下記のような変換が必要となる。

Conntroller.js

   // 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へファイルをアップロードするコードも添付。

s3method.js

    // 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();


以上です。

1
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
1