HEIFとは
HEIFとはHigh Efficiency Image File Formatの略でMPEGよって開発された画像フォーマットの標準規格です。ちなみにヒーフと呼ぶ場合が多いようです。iOS11から公式にサポートされ、JPEG以上の圧縮率、深度情報、透過処理、タイル化、アニメーションなどJPEGにはなかった機能や改善点がある新しい画像フォーマットです。JPEGなどとの詳しい差分はwikiに載っています。
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 | |
---|---|
Hardware Encode | A10 Fusion chip(iPhone7、iPhone7 Plus) |
Software Encode | 無理 |
逆にデコードに関しては
iOS | |
---|---|
Hardware Decode | A9 chip(iPhone6s、iPhone6s Plus)以上 |
Software Decode | All iOS Devices |
の端末で読み込む事が可能です。
なんか動かねーぞという場合には以上の内容を参考にしてください。
あっあともちろんiOS11以上でAPIは使用可能です。
実際にHEIFを作成するには
HEIFを作成するには大まかに2つの方法があって、
- iPhone7, iPhone7 Plus, macOSのAPIを用いてエンコードする
- FFmpegとNokiaの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や運用なども含めて、今後導入するかどうかを検討するといいと思います。
(追記)HEVC及びHEIFのエンコーダには特許の問題がありffmpegなどを使用した実用化は難しいです。現状iPhoneでしかHEIFのエンコードが不可能なので、サーバサイドでの作成は将来に期待しましょう。