概要
最近のiPhone では、デフォルトの設定では写真が *.HEIC (HEIF) で保存されます。 PC(Windows10、11)上で参照する場合に困る場合があります。
JPG形式に変換する方法をまとめました。
HEIF(HEIC) と JPEG
まず、HEIF(HEIC) と JPEG の違いと、どちらを使うべきかについてです。
iPhoneでは設定によって下記を選択できます。
- 保存方式をどちらにするか
- 設定→カメラ→フォーマット で 高効率(HEIF)/互換性優先(JPG)
- PCに転送する際にどちらにするか
- 設定→写真→MACまたはPCに転送 で 自動(JPG)/元のフォーマットのまま(HEIF)
明らかに JPGに対して、HEIFの方が効率がよい(高画質かつ、データが小さい方向)ので、今後はできるかぎりHEIFを使用した方が良いと思います。
HEIFのデメリットはハードウェアやソフトウェアの互換性のみであり、こちらはいずれ解消していくことと思われます。
Windows拡張機能の導入
まずは、Windows10、11 を使用している場合、Windows拡張機能を導入するのが良いと思います。 お金がかかってしまいますが、少額です。
HEIF 画像拡張機能(無料)、HEVC ビデオ拡張機能(120円)の両方を導入することで、エクスプローラから参照、フォトアプリで表示、ペイントで編集、等を行うことができます。
ペイントで開き、JPGで別名保存すればEXIFを維持したまま変換することができます。
OSSの利用
概要
前述のやりかたで、1枚ずつ変換することができます。
私は、iPhoneから転送した画像をまとめて変換したかったので、OSS(Open Source Software)を利用する方法を探りました。
- 必須要件
- 変換に失敗しないこと
- EXIF(撮影日時、場所、画像方向)が引き継がれること
- 必須ではないが考慮する要件
- 変換後のファイルサイズ
結論としては、heif-convert(libheif) を使うことで上手くいきました。詳細については、下記を参照ください。
goheif(by jdeng)
変換が成功した場合には、EXIFを含めて正しく変換できました。ファイルサイズはHEIFよりも小さくなりました。 ただ、ファイルによっては変換に失敗する場合があるので、要件を満たしませんでした。
heic-cli(by catdad-experiments)
こちらは Node.js(JavaScript)環境にて実行可能でした。
変換に失敗することも無かったのですが、HEIFに対してJPGのファイルサイズがかなり大きくなる(例:3MBに対して8MB)ことと、EXIFが引き継がれないという問題があり、要件を満たしませんでした。
npx heic-cli < input.heic > result.jpg
- catdad-experiments/heic-cli: ???????? convert heic/heif images to jpeg or png from the command line
なお、catdad-experiments においては heif に関連するプロジェクトがあり、コンセプトは良いと思いました。 (heic-cli は heic-convert をバックエンドとした CLI としての位置付けのようです)
- catdad-experiments/heic-convert: ???? convert heic/heif images to jpeg and png
- catdad-experiments/heic-app: ???? convert HEIC images to JPEG and PNG in the browser or as a PWA
- catdad-experiments/heic-decode: ???? decode heic images to extracts the raw pixel data
- catdad-experiments/libheif-js: ???? libheif as an npm module
sharp
上記が非常に参考になりました。
sharpもNode.jsのライブラリであり、下記のように呼び出すことでEXIFを保持したまま変換ができそうなのですが、
const sharp = require('sharp'); async function convertHeicToJpeg(inputPath, outputPath) { try { // HEIC から JPEG に変換し、Exif メタデータを保持する await sharp(inputPath) .jpeg({ quality: 90, progressive: true, withMetadata: true }) .toFile(outputPath); console.log('変換が完了しました。'); } catch (error) { console.error('変換中にエラーが発生しました:', error); } } // 使用例 const inputPath = 'input.heic'; // 入力 HEIC ファイルのパス const outputPath = 'output.jpg'; // 出力 JPEG ファイルのパス convertHeicToJpeg(inputPath, outputPath);
下記のメッセージが表示され変換できませんでした。
heif: Unsupported feature: Unsupported codec (4.3000)
これは前述の投稿にもある通り、sharpが libvipsに依存しており、更にlibvipsがlibde265、x265、libheifに依存しており、これをそれぞれソースからコンパイルしてインストールし、HEIFに対応させればよさそうです。
node:21 をベースイメージとして、Dockerビルドを行っていたのですが、手順通りにやってもビルドができませんでした。
- libvips
- libheif
- Node.js
- pkg-config
そんな中でいろいろと調べていたところ、libheif に対応する heif-convert という CLIコマンドがあり、下記オプションにて対応しているdecoderを表示できることがわかりました。 少なくとも、これにより HEIF(HEIC)に対応していることを確認する必要があります。
heif-convert --list-decoders
最終的には、libx265-dev、libde265-dev をaptでインストールし、最新の libheif (v1.17.6) をビルドすることで libvips v8.11.3 のビルドが通り、下記の通り libheif が HEICデコードに対応していることを確認した上で、sharpを使ったのですが、やはり「heif: Unsupported feature: Unsupported codec (4.3000)」のままでした。
$ heif-convert --list-decoders heif-convert --list-decoders HEIC decoders: - libde265 = libde265 HEVC decoder, version 1.0.11 AVIF decoders: JPEG decoders: - jpeg = libjpeg-turbo 2.1.5 (libjpeg 6.2) JPEG 2000 decoders: - openjpeg = OpenJPEG 2.5.0 uncompressed: yes
$ heif-convert --version heif-convert --version 1.17.6 libheif: 1.17.6 plugin path: /usr/local/lib/libheif
ここで、今回の用途(画像変換)に対しては、libvips、sharp を使わずとも、heif-convert(libheif)がそのまま使えるのではないかということに思い当たりました。
heif-convert(libheif)
最終的にこのやり方が上手く動作し、要件を満たしました。 下記をご覧ください。