画像形式変換パイプライン:ICC/EXIF/回転/透明の整備
画像最適化の多くの事故は EXIF/ICC/Orientation/透明 の取り扱いに起因します。本稿は素材の取り込みから 正規化 → 形式変換 → 圧縮 → 配信 → 検証 までをひとつのパイプラインとして設計し、色ズレ・回転ミス・フリンジ・容量の後戻りをなくします。
要点(TL;DR)
- sRGBへ正規化 — 広色域は制作時のみ。配信はsRGB固定で“色ズレゼロ”。
- Orientationは画素適用 — EXIFに依存しない。タグは strip。
- 透明のフリンジ回避 — Premultipliedを理解し、背景マットを混ぜない。
- 形式の使い分け — 写真=AVIF/WebP、ロゴ/スクショ=PNG/AVIF(lossless)。
- 配信 — 指紋付きURL+immutable、準静的はs-maxage+SWR。配信ベストプラクティスも参照。
背景:色ズレ/回転/フリンジ/容量の四重苦を断つ
スマホ撮影の HEIC/広色域、EXIFの回転、半透明ロゴ、そして過去資産の混在…。単発の“最適化コマンド”では根治できません。最初に正規化の入口を設け、形式変換と圧縮を“同じ土俵”で行えるようにします。
この設計は sRGB固定の色パイプライン、HEIC変換フロー、透過縁対策 の要点を束ねています。
設計:取り込み→正規化→変換→圧縮→配信→検証
- 棚卸し — 拡張子/ICC/EXIF/Orientation/アルファ/ビット深度をスキャン。
- 正規化 — Orientation適用、ICCをsRGBへ、EXIF/ICCの不要タグを削除。
- 形式選定 — 写真=AVIF/WebP、イラスト/ロゴ=PNG/AVIF(lossless)。
- 圧縮 — Q/chroma/解像度を“観察→微調整→差分検証”で決定。
- 配信 — 指紋付きURL+immutable、準静的=SWR、srcset/sizes 設計。
- 検証 — SSIM/VMAF/ΔE/差分PNG、Retina/非Retina、ライト/ダークで最終確認。
実装:EXIF/ICC正規化と安全な書き出し
libvips(Sharp)は 高速・低メモリ で正規化と書き出しを一括処理できます。EXIFのOrientationは必ずピクセルへ適用し、EXIFタグ依存を排除します。
// Sharp (libvips) での正規化と書き出し例(Node)
import sharp from "sharp";
await sharp("input.jpg")
.withMetadata({ orientation: undefined }) // 以降の rotate で画素に適用、EXIFのtagは消す
.rotate() // EXIF Orientation をピクセルへ反映
.toColorspace("srgb") // 広色域→sRGB 変換(埋め込みICCに従い変換)
.flatten({ background: { r: 0, g: 0, b: 0, alpha: 0 } }) // 透明はそのまま、背景マットを入れない
.webp({ quality: 85, effort: 4 }) // 写真向けにWebP (lossy) 出力
.toFile("out.webp");
// 透過を保つ場合(ロゴ/アイコン)
await sharp("logo.png")
.toColorspace("srgb")
.avif({ quality: 60, effort: 4, lossless: false }) // 透明+少色なら AVIF/PNG を比較
.toFile("logo.avif");
メタの検査やバッチ削除は exiftool が便利です(取り扱い注意:ソースの保管コピーで実行)。
# exiftool でのメタ確認と削除(Windows PowerShell)
exiftool -a -G1 -s input.jpg | Select-String "Orientation|ICC|ColorSpace"
# Orientationを画素に適用後、EXIFを完全削除(ソース保管用コピーに限定)
exiftool -overwrite_original -Orientation#= input_rotated.jpg
exiftool -overwrite_original -all= input_rotated.jpg
形式の使い分け:AVIF / WebP / PNG / JPEG
- AVIF — 写真/イラスト両方に強い。透明〇、低ビットレート高品質。エンコード重い。
- WebP — 写真向けロッシーの安定解。透明〇。互換性も広い。
- PNG — 透明/少色/スクショ/ロゴで強い。可逆。インデックス/ディザ でさらに削減。
- JPEG — 依然として広互換。プログレッシブ で“先に見える”。
決め方の全体像は WebP/JPEG/PNGの使い分け と 次世代形式戦略 を参照。
配信:Cache-Control/immutable/SWR/ETag
ファイル名にハッシュ(指紋)を付け immutable を適用。差し替えがある準静的は s-maxage + stale-while-revalidate
で“切れ目”を隠します。詳細は キャッシュ設計ガイド を参照。
# Cache-Control の例(CDN配信)
Cache-Control: public, max-age=31536000, immutable # 指紋付きURLにのみ適用
# 差し替えがあり得る準静的画像
Cache-Control: public, max-age=300, s-maxage=86400, stale-while-revalidate=600
検証:差分/SSIM/ΔEと“見た目”の両輪
ロッシー変換では SSIM/VMAF と 差分ヒートマップ をセットで。色は ΔE、透明縁はライト/ダーク背景での視認チェックを必ず行います。CIでの自動化は ビジュアルリグレッション を参照。
NG/落とし穴
- ICC混在 — sRGB固定にしないと環境で色が変わる。
- EXIF依存 — Orientation未適用のまま配信し、プラットフォームで回転バグ。
- 背景マット混入 — 半透明縁が汚染されフリンジ発生。
- immutable乱用 — 指紋なしURLにimmutableを付与して更新不能。
公開前チェックリスト
- sRGB化 — すべての出力がsRGBである。
- 回転適用 — Orientationは画素適用済み、EXIFはstrip。
- 透明縁OK — ライト/ダークで縁ににじみなし。
- 形式選定 — 用途別の最小容量形式になっている。
- 配信設定 — 指紋+immutable、準静的はs-maxage+SWR、ETag有効。
まとめ
“壊れない最適化”の鍵は正規化→変換→配信→検証を一つの連続体にすること。この記事のテンプレをベースに、組織の素材/配信要件へ合わせてカスタマイズしてください。
FAQ(よくある質問)
1どの形式を優先すべき?
写真は AVIF/WebP(互換が必要ならJPEGも残す)。ロゴ/スクショ/イラストは PNG/AVIF(lossless) を比較。透明と小サイズはPNGが強いケースも。
2ICCタグは残す?
配信は sRGB固定 が基本。タグは省略可ですが、制作フロー上の検証には sRGB の明示が役立つ場合もあります。
3透過縁のにじみを避けるには?
Premultiplied/Unassociated の混在を避け、背景マットを入れずに出力。透過PNGのフリンジ対策を参照。