1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

HEIC(iPhoneの写真)をJPEGに変換する方法(JS heic2any / Python pillow-heif)

1
Posted at

iPhoneで撮った写真をPCに送ったら拡張子が .heic で、「開けない」「相手に送っても表示されない」——地味にあるあるです。HEIC(HEIF)はJPEGより高効率で容量も小さいのですが、ChromeやFirefox、少し前のWindowsではそのままではデコードできないことが多く、結局JPEGに変換したくなります。

この記事では、HEICをJPEGに変換する方法を、ブラウザ(JavaScript)とサーバー/スクリプト(Python)の両方でまとめます。

ゴール:HEIC画像を、環境を選ばず開けるJPEGに変換できるようになること。


なぜ変換にライブラリが要るのか

HEICの中身は HEVC(H.265)で圧縮された画像です。JPEG/PNGと違ってブラウザの <img> や canvas が標準では解釈できない(Safari以外)ため、libheif というデコーダを通す必要があります。JavaScriptなら heic2any(libheifのwasmを内包)、Pythonなら pillow-heif が定番です。


JavaScript:ブラウザだけで変換する(heic2any)

heic2any は libheif を内包しているので、これ1つでデコード〜JPEG出力までできます。

<script src="https://cdn.jsdelivr.net/npm/heic2any@0.0.4/dist/heic2any.min.js"></script>
// file: <input type="file"> で選ばれた HEIC ファイル
async function heicToJpeg(file, quality = 0.9) {
  const result = await heic2any({
    blob: file,
    toType: "image/jpeg",
    quality, // 0〜1
  });
  // 1枚なら Blob、複数画像を含むHEICなら Blob[] が返る
  return Array.isArray(result) ? result : [result];
}

あとは受け取ったBlobをダウンロードさせるだけです。

function download(blob, name) {
  const url = URL.createObjectURL(blob);
  const a = Object.assign(document.createElement("a"), { href: url, download: name });
  a.click();
  setTimeout(() => URL.revokeObjectURL(url), 1000);
}

document.querySelector("#file").addEventListener("change", async (e) => {
  for (const file of e.target.files) {
    const base = file.name.replace(/\.hei[cf]$/i, "");
    const blobs = await heicToJpeg(file, 0.9);
    blobs.forEach((b, i) => download(b, blobs.length > 1 ? `${base}_${i + 1}.jpg` : `${base}.jpg`));
  }
});

PNGにしたいときは toType: "image/png"(quality は無視されます)。


Python:スクリプト/サーバーで変換する(pillow-heif)

バッチ処理やサーバー側なら、Pillow に HEIF サポートを足す pillow-heif が手軽です。

pip install pillow pillow-heif
from PIL import Image
import pillow_heif

# これで Pillow が .heic / .heif を開けるようになる
pillow_heif.register_heif_opener()

img = Image.open("photo.heic")
img = img.convert("RGB")          # JPEGはアルファ非対応なのでRGBに
img.save("photo.jpg", quality=90)

フォルダ内を一括変換するならこう。

from pathlib import Path
from PIL import Image
import pillow_heif

pillow_heif.register_heif_opener()

for p in Path("photos").glob("*.heic"):
    Image.open(p).convert("RGB").save(p.with_suffix(".jpg"), quality=90)

つまずきやすいところ

  • 変換後にファイルが大きくなることがある。 HEICはJPEGより高効率なので、同じ画質だとJPEGの方が容量が増えるのはよくあることです(異常ではありません)。サイズを抑えたいなら quality を下げます。
  • ChromeやFirefoxはHEICをネイティブに開けない。 だからこそ libheif(heic2any / pillow-heif)でデコードします。Safariは開ける場合がありますが、依存すると環境差でハマります。
  • 向き(EXIF Orientation)。 変換で回転情報が落ちて画像が横倒しになることがあります。Pythonなら ImageOps.exif_transpose(img) を通してから保存すると安全です。
  • Live Photos などで複数画像を含むHEIC。 heic2any は配列を返すことがあるので、上のコードのように「配列も単体も受ける」形にしておくと安全です。
  • 透過・カラープロファイル。 JPEGはアルファを持てないため、Pythonでは convert("RGB") を忘れずに。

まとめ

  • HEICは中身がHEVC圧縮のため、変換には libheif 系のデコーダが要る
  • ブラウザだけなら heic2any(toType: "image/jpeg" + quality)
  • サーバー/スクリプトなら pillow-heif(register_heif_opener() → Pillowでそのまま開く)
  • サイズ増加・向き・複数画像・アルファの4点だけ気をつければ実用十分

「HEICが開けない・送れない」は変換ひとつで解決できます。参考になれば嬉しいです。


1
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?