WWDC17で新しく発表された画像フォーマットHEIFを使ってみた

  • 29
    いいね
  • 2
    コメント

HEIFとは

HEIFとはHigh Efficiency Image File Formatの略でMPEGよって開発された画像フォーマットの標準規格です。ちなみにヒーフと呼ぶ場合が多いようです。iOS11から公式にサポートされ、JPEG以上の圧縮率深度情報透過処理タイル化アニメーションなどJPEGにはなかった機能や改善点がある新しい画像フォーマットです。JPEGなどとの詳しい差分はwikiに載っています。

この資料は HEIFでアプリの通信量を削減するという発表の補足です。

H.265/HEVCとは

まずHEIFを語る上で避けて通れない事として、H.265/HEVC(High Efficiency Video Coding)があります。ISO/IECのMPEGとITU-TのVCEGによる研究開発チームJCT-VC によって提案され、ITU-Tは2013年に承認されました。

HEIFはHEVCのコーデックが選択可能(というかこれ以外ありえない?)でHEIFとHEVCの違いはなんとなくでも理解しておきましょう。

Working with HEIF and HEVCによると
HEVCのエンコードは以下の環境でエンコード可能で

iOS
8-bit Hardware Encode A10 Fusion chip(iPhone7iPhone7 Plus
10-bit Software Encode 無理

逆にデコードに関しては

iOS
8/10-bit Hardware Decode A9 chip(iPhone6siPhone6s Plus)以上
8/10-bit Software Decode All iOS Devices

の端末で読み込む事が可能です。
なんか動かねーぞという場合には以上の内容を参考にしてください。
あっあともちろんiOS11以上でAPIは使用可能です

実際にHEIFを作成するには

HEIFを作成するには大まかに2つの方法があって、

  1. iPhone7, iPhone7 Plus, macOSのAPIを用いてエンコードする
  2. FFmpegNokiaのHEIFの実装を利用する

正直1.は研究段階ならともかく現実的ではないので2.を選択するのが無難だと思います。

FFmpegはHomebrewからインストールできます。

1. H.265/HEVCのエンコーダーが必要なのでまず以下のコマンドを入力します

brew install x265

2. FFmpegをオプションをつけてインストールします

brew uninstall ffmpeg
brew install ffmpeg --with-x265

3. NokiaのHEIFの実装をビルドします

git clone https://github.com/nokiatech/heif.git
cd heif
cmake .
make

4. FFmpegを用いてJPEGやPNGをHVECのbytestreamに変換します

crfは画像のQualityなのでスケールの範囲は0から51で、0ではLossless、23がデフォルト、51は最低です。 より小さい値でよりよい画質となります。
(追記)どうやらH.264ドキュメントを見ていたようです、@yohhoy さんの通りなので、間違えのないように

ffmpeg -i ./your-image.png -crf 12 -preset slower -pix_fmt yuv420p -f hevc bitstream.265

5. configファイルを作成します

詳しい内容はwikiのリンクで説明してありますので、こちらをどうぞ。HEIFは画像の中にサムネイルの情報を入れることができるのですが、今回は必要ないので除外してます(あってるのかな?)。

{
    "general": {
        "output": {
            "file_path": "output.heic"
        },
        "brands": {
            "major": "mif1",
            "other": ["mif1", "heic", "hevc"]
        }
    },
    "content": [{
        "master": {
            "file_path": "./path-to/bitstream.265",
            "hdlr_type": "pict",
            "code_type": "hvc1",
            "encp_type": "meta"
        }
    }]
}

6. 3でビルドした実行ファイルに5で作成したconfig.jsonを指定して実行します。

./Bins/writerapp ./path/to/config.json

作成したHEIFファイルの中身はHEIFのブランチ gh-pagesで確認することができます。

iOSでHEIFを読み込むには

iOSでローカルのHEIFファイルを読み込むには以下のコードを書きます。

// Read a jpeg image from file

let inputURL = URL(fileURLWithPath: "/tmp/image.heic")

if let source = CGImageSourceCreateWithURL(inputURL as CFURL, nil) {
    let image = CGImageSourceCreateImageAtIndex(source, 0, nil)
    // set image
}

ちなみにHEIFファイルがWEB上にある場合には

let inputURL = URL(string: "https://../image.heic")

// 何かのダウンローダー
downloader.download(url: inputURL) { (data: Data?, error: Error) in
    if let data = data, let source = CGImageSourceCreateWithData(data as CFData, nil) {
        let image = CGImageSourceCreateImageAtIndex(source, 0, nil)
        // set image
    }
}

でっ実際どれくらい圧縮されんのよ

記事の一覧を表示するための192x192のサムネイル画像を30個ほど圧縮してみましたが、JPEGと比べると15~20%近く合計で圧縮されていました。
画像サイズはffmpegのQualityのオプションによって上下すると思うので、一概には言えませんがWebPとも遜色ない圧縮率です。

HEIF最高や!!WebPなんて最初っからいらんかったんや!!

実験はiPhone 7Plusで行いましたが、デコード時間もハードウェアアクセラレーションを使っているおかげもあるのか、違和感なく表示されていました。

最後に

今回調べる上で技術的なドキュメントやWebの資料が少ないので、多少苦労しました。とくにHEVCなどのコーデック周りは専門家がいたほうがやりやすいと思います。何か情報クレ...クレメンス...。

自分たちが作っているアプリの要件やサポートOSや運用なども含めて、今後導入するかどうかを検討するといいと思います。