sipsを使ってHEICファイルをJPEGファイルに変換する。かつ、EXIF情報も削除する【mac環境のみ・Python使用】

## HEICファイルとは
HEICファイル(High Efficiency Image File Format)とは新しい画像形式で、iOS 11から採用されている、ファイル形式です。
画質はそのままにJPEGファイルの半分くらいのファイルサイズとなるように設計されているようです。

HEICファイルの説明についての日本語の記事だと、下記のポストが分かりやすそうでしたので貼っておきます。

[WindowsでHEICファイルを開く方法](https://www.apowersoft.jp/open-heic-photos-in-windows.html)

## sipsを使ってHEICファイルをJPEGファイルに変換する

macには標準で`sips`というコマンドがついています。
使い方については

```bash
sips --help
```

で見るのが手っ取り早いです。

また、使い方の例として記事下部の参照欄に`sips`コマンドについて書かれている方の記事を貼らせていただきました。


この`sips`を使って、HEICからjpegに変換していきます
コマンドライン上で実行するなら、下記でOKです。

```bash
sips --setProperty format jpeg hogehoge.HEIC --out hogehoge.jpeg
```

これで`hogehoge.HEIC`を`hogehoge.jpeg`に変換できます。

今回は、ディレクトリ単位でまとめて`HEIC`から`jpeg`に変換するPythonスクリプトを書いてみました。

```python
from os import path
from glob import glob
import subprocess

CURRENT_PATH = path.dirname(path.abspath(__file__))
WORK_DIR = 'work' # 変換対象のディレクトリ
RESULT_DIR = 'result' # JPEGに変換したファイルを格納するディレクトリ

files = [r.split('/')[-1] for r in glob(path.join(CURRENT_PATH, WORK_DIR,'*.HEIC'))]

for f in files:
    inputFile = path.join(CURRENT_PATH, WORK_DIR, f)
    outputFile = path.join(CURRENT_PATH, RESULT_DIR, f.replace('.HEIC','.jpeg'))

    command = 'sips --setProperty format jpeg ' + inputFile +  ' --out ' + outputFile
    print(command)
    subprocess.call(command, shell=True)
```

やはり`JPEG`に変換するとファイル容量も２倍近くに増えるようです。

## 画像をリサイズしながら、jpegに変換する

`sips`コマンドの中でアスペクト比を変えずにリサイズする方法がありましたので、今回はそれをそのままに使います。
オプションで `-Z {リサイズ値}` でアスペクト比を保ったまま、リサイズしてくれるようです。

先程のPythonスクリプトを修正します。
横が `1024px` になるようにリサイズしたいので、下記のように修正します。

```python
from os import path
from glob import glob
import subprocess

CURRENT_PATH = path.dirname(path.abspath(__file__))
WORK_DIR = 'work' # 変換対象のディレクトリ
RESULT_DIR = 'result' # JPEGに変換したファイルを格納するディレクトリ

files = [r.split('/')[-1] for r in glob(path.join(CURRENT_PATH, WORK_DIR,'*.HEIC'))]

for f in files:
    inputFile = path.join(CURRENT_PATH, WORK_DIR, f)
    outputFile = path.join(CURRENT_PATH, RESULT_DIR, f.replace('.HEIC','.jpeg'))

    command = 'sips -Z 1024 --setProperty format jpeg ' + inputFile +  ' --out ' + outputFile
    print(command)
    subprocess.call(command, shell=True)
```

画像を収縮させると、一気にファイルサイズも減ります。

## JPEGに変換した上でEXIF情報も削除したい
`sips`コマンドの中で`EXIF`情報も併せて削除できないものかと思い、調べてみましたが、~~できなそうでした。~~
 大変ありがたいことにコメントを頂き、`sips`コマンドの中で完結できることができました！！
https://qiita.com/shinshin86/items/ae896113e97a0b8e4f94#comment-16864547d761e2ed88b3

`sips`コマンドで完結させるやり方は、下記の`sipsコマンドだけを用いて、JPEGに変換した上でEXIF情報も削除したい`に書きましたので、そちらをご参照ください

そのため、Exif情報の削除についてはPythonのライブラリである`Pillow`を使って処理を書いていくことにしました。

下記のスクリプトを実行することで、以下３つの処理を実施します

* `sips`から`jpeg`への変換
* 画像を幅`1024px`にリサイズ
* `Exif`情報を削除

```python
from os import path
from glob import glob
import subprocess
from PIL import Image
from PIL.ExifTags import TAGS

CURRENT_PATH = path.dirname(path.abspath(__file__))
WORK_DIR = 'work' # 変換対象のディレクトリ
RESULT_DIR = 'result' # JPEGに変換したファイルを格納するディレクトリ

files = [r.split('/')[-1] for r in glob(path.join(CURRENT_PATH, WORK_DIR,'*.HEIC'))]

for f in files:
    inputFile = path.join(CURRENT_PATH, WORK_DIR, f)
    outputFile = path.join(CURRENT_PATH, RESULT_DIR, f.replace('.HEIC','.jpeg'))

    try:
        command = 'sips -Z 1024 --setProperty format jpeg ' + inputFile  +  ' --out ' + outputFile
        print(command)
        subprocess.call(command, shell=True)

        ret = {}
        targetFile = Image.open(outputFile)
        info = targetFile._getexif()

        if(info == None):
            print("This file does not process : " + file)
            continue

        for tag, value in info.items():
            decoded = TAGS.get(tag, tag)
            ret[decoded] = value
        ret['XResolution'] = 0
        ret['WhiteBalance'] = 0
        ret['ResolutionUnit'] = 0
        ret['SubsecTimeOriginal'] = 0
        ret['Model'] = 0
        ret['Orientation'] = 0
        ret['DateTimeDigitized'] = 0
        ret['ExposureMode'] = 0
        ret['DateTime'] = 0
        ret['YResolution'] = 0
        ret['Make'] = 0
        ret['ComponentsConfiguration'] = 0
        ret['ApertureValue'] = 0
        ret['ColorSpace'] = 0
        ret['ExposureProgram'] = 0
        ret['FNumber'] = 0
        ret['ShutterSpeedValue'] = 0
        ret['MeteringMode'] = 0
        ret['LensModel'] = 0
        ret['LensMake'] = 0
        ret['ExifVersion'] = 0
        ret['FlashPixVersion'] = 0
        ret['FocalLength'] = 0
        ret['ExposureTime'] = 0
        ret['SensingMethod'] = 0
        ret['MakerNote'] = 0
        ret['ExifOffset'] = 0
        ret['SubjectLocation'] = 0
        ret['FocalLengthIn35mmFilm'] = 0
        ret['Software'] = 0
        ret['Flash'] = 0
        ret['ISOSpeedRatings'] = 0
        ret['SubsecTimeDigitized'] = 0

        targetFile.save(outputFile)
        targetFile.close()
        print("=== SUCCESS => ", outputFile)
    except Exception as ex:
        print("=== ERROR => This file cannot be processed!! ===")
        print("FILE NAME : " + f)
        print(ex)
        print("================================================")
```


ちなみに、`EXIF`情報の削除部分については、手前味噌ですが、自身で元々書いていた`EXIF`削除用のPythonスクリプト内での処理をほぼほぼそのまま流用しています。

[shinshin86/Delete-Exif(Github)](https://github.com/shinshin86/Delete-Exif)

(`cli`と`web`、２つのバージョンがこのリポジトリにはあるのですが、わかりにくいので、後々リポジトリ内の構成を整理しようかと思っています。)

## sipsコマンドだけを用いて、JPEGに変換した上でEXIF情報も削除したい

コメント頂きました @KEINOS さんに感謝です！
https://qiita.com/shinshin86/items/ae896113e97a0b8e4f94#comment-16864547d761e2ed88b3

> 一旦 EXIF を持たないロスレス画像（PNG や BMP など）に変換してから JPEG にしてはどうでしょう？

EXIFを持たない画像を経由してから`JPEG`に変換することで、EXIF情報の削除が行えるのは、目からウロコでした。とても勉強になりました。

というわけで、`sips`コマンドのみを用いて`jpeg変換＆exif削除`を実現したコードは下記となります。

```bash
#!/bin/bash
WORKDIR='work'
RESULTDIR='result'

for heicfile in $(ls $WORKDIR/*.HEIC); do
    bmpfile=${heicfile%.HEIC}.bmp
    jpegfile=${heicfile%.HEIC}.jpeg
    bmpfile_path=$RESULTDIR/${bmpfile##*/}
    jpegfile_path=$RESULTDIR/${jpegfile##*/}
    sips --setProperty format bmp $heicfile --out $bmpfile_path && sips --setProperty format jpeg $_ --out $jpegfile_path && rm $bmpfile_path
done
```

ちなみにリサイズを行いたいときは`-Z {リサイズしたい幅}`を`sips`コマンドのオプションとして渡せばよいだけなので、下記のようになりますね！
(幅を`1024px`にリサイズしたいとき)

```bash
#!/bin/bash
WORKDIR='work'
RESULTDIR='result'

for heicfile in $(ls $WORKDIR/*.HEIC); do
    bmpfile=${heicfile%.HEIC}.bmp
    jpegfile=${heicfile%.HEIC}.jpeg
    bmpfile_path=$RESULTDIR/${bmpfile##*/}
    jpegfile_path=$RESULTDIR/${jpegfile##*/}
    sips -Z 1024 --setProperty format bmp $heicfile --out $bmpfile_path && sips --setProperty format jpeg $_ --out $jpegfile_path && rm $bmpfile_path
done
```

## まとめ： sipsコマンド便利、Linuxだとimagemagick?

`sips`はmac環境でしか使えないコマンドですが、かなり便利なコマンドですね。
`Linux`環境になると、`sips`の代替コマンドは`imagemagick`とかになるのでしょうか？

`imagemagick`の様々な使い方が書かれているポストを見つけたので、こちらを最後に貼っておきます。

[How to Quickly Resize, Convert & Modify Images from the Linux Terminal](https://www.howtogeek.com/109369/how-to-quickly-resize-convert-modify-images-from-the-linux-terminal/)

## 参照
[WindowsでHEICファイルを開く方法](https://www.apowersoft.jp/open-heic-photos-in-windows.html)

[Macのターミナルで簡単に画像処理できるsipsの使い方](https://qiita.com/livlea/items/53b755e5067d4ebc5b43)

[macOS Mojave の標準コマンドで Jpeg 画像を PNG に変換するワンライナー](https://qiita.com/KEINOS/items/8bbf7217904ea832e1b4)

[Pythonを使ってHEICファイルをjpegに変換する](https://qiita.com/grm/items/c3af6ab6ea4ce8349a90)

[shinshin86/Delete-Exif(Github)](https://github.com/shinshin86/Delete-Exif)

[How to Quickly Resize, Convert & Modify Images from the Linux Terminal](https://www.howtogeek.com/109369/how-to-quickly-resize-convert-modify-images-from-the-linux-terminal/)