HEIC(HEIF) から JPG への変換方法

概要

最近の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のデメリットはハードウェアやソフトウェアの互換性のみであり、こちらはいずれ解消していくことと思われます。

https://www.adobe.com/jp/creativecloud/file-types/image/comparison/heic-vs-jpeg.html

Windows拡張機能の導入

まずは、Windows10、11 を使用している場合、Windows拡張機能を導入するのが良いと思います。 お金がかかってしまいますが、少額です。

HEIF 画像拡張機能(無料)、HEVC ビデオ拡張機能(120円)の両方を導入することで、エクスプローラから参照、フォトアプリで表示、ペイントで編集、等を行うことができます。

ペイントで開き、JPGで別名保存すればEXIFを維持したまま変換することができます。

Windows での HEVC および HEIF メディアの使用
Windows での HEVC および HEIF デコードを有効にするための、必要システム構成、拡張機能およびその他の重要な情報について説明します。

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 においては heif に関連するプロジェクトがあり、コンセプトは良いと思いました。 (heic-cli は heic-convert をバックエンドとした CLI としての位置付けのようです)

sharp

sharpでHEICをJPEGに変換する - toshiro110’s diary
概要 sharpでHEICをJPEGに変換する方法を記述します。 準備 今回は、dockerのnodeの公式のイメージを利用します。 $ docker run --rm -it -v $(pwd):/home/node/test-sharp -w /home/node/test-sharp node bash 「-v」...

上記が非常に参考になりました。

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ビルドを行っていたのですが、手順通りにやってもビルドができませんでした。

そんな中でいろいろと調べていたところ、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)

最終的にこのやり方が上手く動作し、要件を満たしました。 下記をご覧ください。

Copied title and URL