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で問題あるなら5か10ずつ増やす
- 95ぐらいからファイルサイズが急激に増える
つまり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ページによると以下の仕様であることが分かった。
- 80以上は4:2:2(2x1)
- 90以上は4:4:4(1x1)
- 80未満は4:2:0(2x2)
クロマサブサンプリングは-sample
オプションで指定可能。Googleは4:2:0を提案している。クロマサブサンプリングを無効にしたい場合は-sample 1x1
を指定する。-quality
が80以上で4:2:0にしたい場合は-sample 2x2
を指定する。