いまどきの非可逆画像コーデック比較

こんにちは、クロスマート開発部のうえだです。

サービスで画像を提供するとき、JPEGのような非可逆圧縮を使うことはよくあります。 いろいろな画像圧縮形式が出ている中で「どれを使えば良いのか」「品質係数はどのくらいの数値にすれば良いのか」は個人の経験で決めていたりデフォルト値を使っている人が多いかと思います。

現時点(2026年)で何がベストなのかを調べるためにいろいろな画像形式で比較してみました。

TL;DR

  1. エンコーダ間で品質係数の数字はバラバラ
    • libjpegの品質係数80相当はJPEG互換エンコーダでは80前後ですが、WebPでは83.0、AVIFでは64.7、HEICでは48.7でした
  2. libjpegの品質係数80相当に揃えると、HEICとAVIFは約25%小さく、WebPとJpegliは約12〜14%小さくなる
    • Jpegliは標準JPEGとしてデコードできる出力のまま同じ画質で約12%小さくできており、互換性を重視する用途ではかなり実用的です
    • WebPを使うよりもJpegliでJPEGファイルをエンコードする方が速く互換性も高い
  3. libjpeg-turboは名前通りエンコード速度は非常に速い
  4. 動画で品質比較によく使われるCVVDPでも試しましたが、高品質域では意外な結果になりこの用途では使いづらい
    • これはあとで補足します

比較方法

画像コーデックの比較で品質係数を同じにするのは適切ではありません。

圧縮時の引数 -q 80 の意味はエンコーダごとに違うからです。 そこで今回は次の手順にしました。

  1. 基準として、Kodakが公開しているテスト用画像群をlibjpegで品質係数80で符号化する
  2. その出力と元画像のSSIMULACRA2(人間の視覚モデルに基づく指標の一つ)を測る
  3. 他の各エンコーダについてSSIMULACRA2が同程度になる品質係数を二分探索で探す
  4. 揃った状態でのファイルサイズとエンコード時間を比較する
    • 画像ごとにlibjpeg q80のサイズを分母にして正規化し24枚平均を取る
    • WebP, HEIC, AVIFはJPEGとコンテナが異なるため、計測時はいったんPNGにデコードしてから元画像と比較

対象のコーデックは「一般的なWebブラウザで表示できるもの」として、JPEG互換とその他のメジャーな画像形式を採用しています。

JPEG互換

  1. libjpeg
    • 1991年にIndependent JPEG Groupによるリファレンス実装公開。いまも更新されておりv10は2026年1月にリリース。
  2. libjpeg-turbo
    • 2010年くらいにリリース。 libjpeg をSIMDを使って高速化
  3. MozJPEG
    • 2014年にMozillaがリリース。 libjpeg-turbo をベースに圧縮率向上を目指した
  4. Guetzli (グエッツリ)
    • 2017年にGoogleがリリース。心理視覚モデルを活用してサイズを小さくするという触れ込みだが......
  5. Jpegli (ジェーペグリ)
    • 2024年にGoogleがリリース。高画質設定で圧縮率が良い

その他の画像形式

  1. WebP (ウェッピー)
    • 2010年にGoogleがリリース
  2. HEIC (ヒーク・ヘイク)
    • 2017年に登場。Appleが強く推している
  3. AVIF (エイヴィフ)
    • 2019年に登場。ネット関連企業陣(Alliance for Open Media)が推進

計測結果

「サイズ(libjpeg比)」は同じ画像のlibjpeg q80出力と比べてどれだけ小さいかを表します。

エンコーダ 品質係数(平均) サイズ(libjpeg比) エンコード時間
HEIC 48.7 -25.6% 128 ms
AVIF 64.7 -24.9% 68 ms
WebP 83.0 -13.5% 35 ms
Jpegli 79.1 -12.4% 14 ms
MozJPEG 81.8 -7.8% 37 ms
libjpeg 80.0 0% 7 ms
libjpeg-turbo 80.1 +0.2% 2 ms

おおむね直感に合う結果になりました。

  • HEICとAVIFが最も小さく、WebPとJpegliがその次、MozJPEGは標準libjpegより少し小さい、という並び
  • HEICのq49とlibjpegのq80が同程度の見た目になるというだけでも、品質係数の数字を横並びに比較してはいけないことが分かる
  • Jpegliは既存のJPEGデコーダでそのまま開ける標準JPEGを出力するが、libjpegより12.4%小さくなっている
    • WebPやAVIFに移行できない場合でもエンコーダを差し替えるだけで1割程度削減できる
  • libjpeg-turboのエンコード時間は2ms程度で他のエンコーダよりも圧倒的に速い

Guetzliは対象外

Guetzliも試しましたが比較からは外しました。

Guetzliのエンコードは1枚あたり17〜20秒かかりました。他のエンコーダよりも2〜4桁ほど遅いです。 画質を揃えたときの圧縮率が良ければまだ用途があるんですが、そちらも他のJPEGエンコーダに比べてかなり見劣りするものになっており、早々に比較対象から外しました。

CVVDPでも試したが今回は使わず

最初はCVVDP (ColorVideoVDP)でも同じことを試しました。

CVVDPは人間の視覚モデルに基づく強力な指標で出力はJODスケールです。 JODの最良は10で、高いほど知覚的な差が小さいことを意味します。

ところが、libjpeg q80と同じCVVDPに揃えると次のような結果になりました。

エンコーダ サイズ(libjpeg比)
HEIC -18.4%
libjpeg 0%
libjpeg-turbo +0.1%
Jpegli +4.2%
WebP +4.8%
MozJPEG +5.0%
AVIF +5.4%

AVIFやWebPが標準JPEGより大きい、というかなり意外な結果です。

今回の主目的はCVVDPの評価ではないので深追いしませんが、原因は高品質域での飽和に見えます。 libjpegのCVVDPは、q75でJOD 9.55〜9.80、q80で9.63〜9.84まで上がります。 上限10に近い領域に多くの画像が集まるため、サイズ効率を順位付けする用途では差が出にくかったのだと思います。 少なくとも今回の条件では、CVVDPは「静止画コーデックを同一画質に揃えてサイズ効率を見る」用途には向きませんでした。

なおGuetzliについてもCVVDPベースで確認したところ、libjpegより+38〜41%大きい結果になってしまいました。

再現環境

全部入りの環境を作るのがそこそこ面倒だったので、 Dockerfile を記載しておきます。

  • エンコーダはすべてソースから個別ディレクトリにビルドしています
    • cjpeg という同名バイナリが複数コーデックで衝突するため、 /opt/libjpeg , /opt/mozjpeg , ...と分けてインストールしました
  • SSIMULACRA2実行ファイルはJpegliリポジトリから静的リンクでビルドしています
  • PyTorchの都合でPythonのバージョンは3.12を使っています
FROM ubuntu:26.04

RUN --mount=type=cache,target=/var/cache/apt,sharing=locked \
    --mount=type=cache,target=/var/lib/apt,sharing=locked \
    apt-get update && apt-get install -y --no-install-recommends \
    build-essential cmake nasm git wget ca-certificates pkg-config curl xz-utils \
    zlib1g-dev libpng-dev libjpeg-dev \
    python3 \
    libfreeimage3 \
    webp libavif-bin \
    libheif-examples \
    libheif-plugin-x265 libheif-plugin-libde265 libheif-plugin-aomenc

WORKDIR /build

# libjpeg
RUN wget -q https://www.ijg.org/files/jpegsrc.v10.tar.gz \
    && tar xf jpegsrc.v10.tar.gz \
    && cd jpeg-10 \
    && ./configure --prefix=/opt/libjpeg \
    && make -j"$(nproc)" && make install \
    && cd /build && rm -rf jpeg-10 jpegsrc.v10.tar.gz

# libjpeg-turbo
RUN git clone --depth 1 https://github.com/libjpeg-turbo/libjpeg-turbo.git \
    && cd libjpeg-turbo \
    && mkdir build \
    && cd build \
    && cmake -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX=/opt/libjpeg-turbo -DWITH_TURBOJPEG=OFF .. \
    && make -j"$(nproc)" \
    && make install \
    && cd /build \
    && rm -rf libjpeg-turbo

# MozJPEG
RUN git clone --depth 1 https://github.com/mozilla/mozjpeg.git \
    && cd mozjpeg \
    && mkdir build \
    && cd build \
    && cmake -G"Unix Makefiles" -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX=/opt/mozjpeg -DPNG_SUPPORTED=1 -DWITH_TURBOJPEG=OFF .. \
    && make -j"$(nproc)" && make install \
    && cd /build \
    && rm -rf mozjpeg

# Guetzli
RUN git clone --depth 1 https://github.com/google/guetzli.git \
    && cd guetzli \
    && make -j"$(nproc)" \
    && mkdir -p /opt/guetzli && cp bin/Release/guetzli /opt/guetzli/guetzli \
    && cd /build \
    && rm -rf guetzli

# Jpegli
RUN git clone --depth 1 --recursive --shallow-submodules https://github.com/google/jpegli.git \
    && cd jpegli \
    && mkdir build \
    && cd build \
    && cmake -DCMAKE_BUILD_TYPE=Release -DBUILD_TESTING=OFF -DBUILD_SHARED_LIBS=OFF -DJPEGLI_ENABLE_TOOLS=ON -DJPEGLI_ENABLE_DEVTOOLS=ON .. \
    && make -j"$(nproc)" cjpegli ssimulacra2 \
    && install -D tools/cjpegli /opt/jpegli/bin/cjpegli \
    && find . -type f -name ssimulacra2 -exec install -D {} /opt/jpegli/bin/ssimulacra2 \; \
    && test -x /opt/jpegli/bin/ssimulacra2 \
    && cd /build \
    && rm -rf jpegli

RUN curl -LsSf https://astral.sh/uv/install.sh | env UV_INSTALL_DIR=/usr/local/bin sh
RUN --mount=type=cache,target=/root/.cache/uv uv python install 3.12
RUN uv venv --python 3.12 /opt/venv
ENV VIRTUAL_ENV="/opt/venv"
ENV PATH="/opt/venv/bin:${PATH}"

RUN --mount=type=cache,target=/root/.cache/uv uv pip install torch torchvision --index-url https://download.pytorch.org/whl/cpu

COPY requirements.txt /tmp/requirements.txt
RUN --mount=type=cache,target=/root/.cache/uv uv pip install -r /tmp/requirements.txt

WORKDIR /work

結局どうするのがいいのか

圧縮率を考えるとAVIFかHEICになります。

HEICのWebブラウザサポート具合はかなりお寒いものになっているので、今から選ぶならAVIFを選ぶべきでしょう。 AVIFなら主要Webブラウザで表示可能です。

「AVIFファイル」と「Jpegliで圧縮したJPEGファイル」を用意しておき、「AVIFを表示できるならAVIF、ダメならJPEG」をHTMLファイルに書くのが良さそうです。

<picture>
  <source srcset="/images/apple.avif" type="image/avif">
  <img src="/images/apple.jpg" alt="りんご" width="800" height="600">
</picture>

最後に

最後までお読みいただきありがとうございました。

クロスマートでは現在、ソフトウェアエンジニアを積極的に採用しています。

興味を持っていただけた方は、ぜひお気軽にお問い合わせください。

www.notion.so