【HEIC AWS Mac】tifigを使ってHEICをJPEGに変換する

# 背景
iOS11から、写真がHEIC形式で保存されるようになりました。

そこで、HEIC形式の写真を弊社のサービスサイトにアップロードできるように、「.heic」に対応できるAPIをつくることになりました。

ついでに、iPhoneで撮影した写真をアップロードするとなぜか画像が横になってしまう現象もあったので、同時に対応します。

参考：https://qiita.com/RichardImaokaJP/items/385beb77eb39243e50a6

# 環境(ざっくり)
[ローカル]
mac, node
[本番]
AWS Linux

# 外部ライブラリ
・heicをjpegに変換するコマンド
[tifig] https://github.com/monostream/tifig
・画像の向きを正面にするために利用したライブラリ
[sharp] https://github.com/lovell/sharp
・shellコマンドを実行するライブラリ
[child_process] https://github.com/npm/security-holder

# tifigコマンドにPATHを通す
まずは、ローカル環境と本番環境それぞれでtifigコマンドをたたけるようにしなければなりません。

[Mac（ローカル環境）]
下記のURLの【macOS aka OSX】を参考に、コマンドを叩けるようになります。
https://github.com/monostream/tifig

[AWS　Linux（本番環境）]
下記のURLからバイナリファイルを取得。
https://github.com/monostream/tifig/releases
（現在最新：https://github.com/monostream/tifig/releases/download/0.2.2/tifig-static-0.2.2.tar.gz）

PATHが通ったかどうかは--versionで確認できます。

```terminal:terminal
tifig --version
tifig 0.2.2
```

# heicの変換
では実際に変換していきます。

処理の大きな流れとしては

```
1. アップロードされたheicを一時フォルダに保存する
2. 保存されたheicをtifigコマンドでjpegに変換する
3. iPhoneの写真なので、横向きを縦向きになおす
```

です。

１の「一時フォルダに保存」された状態からの処理を書いていくので、
以下、２と３の処理を書いていきます。

## heicをjpegに変換
```js:HeicConverter.js
const { execSync } = require('child_process');
const { unlinkSync } = require('fs');

const REGEX = /\.[^\.]+$/;
const TYPES = [
  'image/heif',
  'image/heic',
  'image/heif-sequence',
  'image/heic-sequence',
];

class HeicConverter {
  convert(path, name) {
    const oldFilePath = `${path}${name}`;
    const newName = name.replace(REGEX, '.jpg');
    const newFilePath = `${path}${newName}`;

    // ここにセキュリティを入れて！！！！！！！！！！！
    const command = `tifig ${oldFilePath} ${newFilePath}`;

    try {
      execSync(command);
      unlinkSync(path);
      return Promise.resolve();
    } catch (err) {
      return Promise.reject(new Error(err));
    }
  }

  isHeicFile(type) {
    return TYPES.includes(type);
  }
}

module.exports = HeicConverter;
```

こんな感じのHeicConverterクラスを作成しました。
isHeicFileでHEIC形式のイメージかどうかを判定するメソッドと、
JPEG形式に変換するconvertメソッドを用意しています。

convertメソッドでやっていることはシンプルで、
heicファイルの場所と新しいイメージのpathとnameを指定してあげるだけです。
あとはtifigがよしなにやってくれます。

結果、こんなコマンドが叩かれています。

```terminal
tifig ***/***/test.heic ***/***/test.jpeg
```

ここで注意してほしいのは、

```js
const command = `tifig ${oldFilePath} ${newFilePath}`;
```
ここの部分なのですが、
newFilePathにパイプでつないでshellを叩くことができてしまうので、
**しっかりセキュリティをいれてください！！**

参考：https://github.com/boutell/heic-to-jpeg-middleware

## 横向きを縦向きになおす
```js:Format.js
const sharp = require('sharp');
const fs = require('fs');

class Format {
  // 画像の向きを正面にする
  async toValidPosition(filePath) {
    try {
      // 正面画像のBufferを取得
      const outputBuffer = await this._getValidPositionImageBuffer(filePath)

      // Bufferを元画像に上書きする
      fs.writeFileSync(filePath, outputBuffer);

    } catch (err) {
      throw err;
    }
  }

  _getValidPositionImageBuffer(filePath) {
    return new Promise((resolve, reject) => {
      sharp(filePath)
      .rotate()
      .toBuffer((err, outputBuffer) => {
        if (err) {
          return reject(new Error(err));
        }
        return resolve(outputBuffer);
      });
    });
  }
}

module.exports = Format;
```

正面にするのは、これもよしなにsharp.reotate()でやってもらってます。
最後に.toBufferでBufferを返してもらい、
fsでもとのBufferを上書きします。

これで正面向きの画像に変換されます。

# まとめ
やっている内容は結構シンプルなんですが、ここまでheicについての調査や画像を正面にするためのライブラリを見つけるのに結構時間がかかりました。。。

tifigじゃなくて、npmで簡単に変換してくれるようなライブラリ出てきてくれないかな。。。