MozJPEGでJPEGを圧縮

PNGの圧縮にはpngquantを使っている。JPEGは放置していた。数GBのJPEG画像を圧縮しようと思い、ツールを探した。Mozillaが作っているMozJPEGが良さそうだったので使ってみた。macOSではbrew install mozjpegで簡単にインストールできた。

つぎのようにコマンドラインツールのcjpegで不可逆圧縮できる。

cjpeg before.jpg > after.jpg

圧縮品質オプションである-qualityのデフォルトは75。ハフマンテーブル最適化オプションである-optimizeのデフォルトは有効。プログレッシブオプションである-progressiveのデフォルトは有効。カラープロファイルは引き継がれる。

-qualityをどうするか。Googleの開発者向けドキュメントでは85が提案されている。cjpegのmanページでは-qualityについて、つぎのようなことが書いてある。

つまり75から95ぐらいで調整すると良さそう。Googleが提案する85は丁度真ん中で、使い勝手が良さそう。したがって、つぎのコマンドを使うことにした。

find -E . -iregex ".+\.jpe?g$" -type f -print0 | xargs -0 -I{} -P 0 /usr/local/opt/mozjpeg/bin/cjpeg -quality 85 -outfile "{}-q85.jpg" "{}"

find -E -iregexによって拡張正規表現で小文字大文字を区別せずに、拡張子でJPEGファイルを検索している。ファイルパスにスペースや制御文字が含まれる可能性があるのでfind -print0 | xargs -0としてNUL文字区切りで引数を渡している。xargs -P 0で可能なかぎり多くのプロセスで並列実行をしている。

出力されるファイル名をもっと綺麗にしたかった…。しかし、ファイルパスに含まれる可能性がある制御文字に対応しつつ、ワンライナーでシンプルに書く方法が思いつかなかった。 ショートカットアプリに登録したので、JPEGファイルやフォルダを選択したときのコンテキストメニューから呼び出せて便利になった。3.43GBのJPEG画像群が、圧縮して1.82GBになった。

-qualityの値によってクロマサブサンプリングの設定が変わることに気がついた。mozjpeg/rdswitch.cやmanページによると以下の仕様であることが分かった。

クロマサブサンプリングは-sampleオプションで指定可能。Googleは4:2:0を提案している。クロマサブサンプリングを無効にしたい場合は-sample 1x1を指定する。-qualityが80以上で4:2:0にしたい場合は-sample 2x2を指定する。