比較対象ファイルとしてこちらの http://orangestar.hatenadiary.jp/entry/2017/06/18/163900 「231kb:jpg高画質(10)h812」を利用する。
% openssl sha1 20170618160637.jpg
SHA1(20170618160637.jpg)= 3b42635ecd046473c89bde8021efa810a5f6ade8
zsh % ls -l --human --sort=size 2017*
-rw-r--r-- 1 shyouhei wheel 231K 6 19 12:33 20170618160637.jpg
231KiBがスタートだ。
ちなみに余談となるが、このファイルは枠線が絶妙にナナメっておりファイルサイズ増加の理由の一端になっていると思う。
上記ファイル(部分、600%に拡大) ©2017 小島アジコ
今回はオリジナルをリスペクトし、そういうファイルのコンテンツの部分に関しては手を入れないことにする。
まずそのままpngに変換する。pngは可逆圧縮(以下lossless)なのでデータは欠損しない。
zsh % convert --version
Version: ImageMagick 7.0.5-10 Q16 x86_64 2017-06-04 http://www.imagemagick.org
Copyright: © 1999-2017 ImageMagick Studio LLC
License: http://www.imagemagick.org/script/license.php
Features: Cipher DPC HDRI Modules
Delegates (built-in): bzlib freetype jng jpeg ltdl lzma png tiff xml zlib
zsh % convert 20170618160637.jpg 20170618160637.png
zsh % ls -l --human --sort=size 2017*
-rw-r--r-- 1 shyouhei wheel 231K 6 19 12:33 20170618160637.jpg
-rw-r--r-- 1 shyouhei wheel 189K 6 19 13:07 20170618160637.png
これだけで189KiBまで減る。pngの圧縮は優秀だ。
しかし上記はpngの真の実力ではない。google/zopfli という圧縮ツールのソースコードをきわめてよく観察すると、実はzopfling(1)
という隠しコマンドが潜んでおり。これが実は最強のpng圧縮ツールだったりする(ただしクソ重い)。
zsh % ~/bin/zopflipng --filters=01234mepb --lossy_8bit --lossy_transparent 20170618160637.png 20170618160637.zopfli.png
Optimizing 20170618160637.png
Input size: 193469 (188K)
Result size: 156691 (153K). Percentage of original: 80.990%
Result is smaller
zsh % ls -l --human --sort=size 2017*
-rw-r--r-- 1 shyouhei wheel 231K 6 19 12:33 20170618160637.jpg
-rw-r--r-- 1 shyouhei wheel 189K 6 19 13:07 20170618160637.png
-rw-r--r-- 1 shyouhei wheel 154K 6 19 14:16 20170618160637.zopfli.png
154KiBまで減った。--lossy_8bit
とかいうオプションにギョッとするけど、もとの絵がそもそも8bitなので今回は問題ない。
Mozillaの優秀な頭脳たちが結集して作成した高圧縮jpegエンコーダー mozilla/mozjpeg
zsh % convert -compress None -type GrayScale -colors 256 -density 500 20170618160637.jpg BMP3:20170618160637.bmp
zsh % cjpeg -grayscale -outfile 20170618160637.cjpeg.jpg 20170618160637.bmp
zsh % ls -l --human --sort=size 2017*
-rw-r--r-- 1 shyouhei wheel 449K 6 19 13:21 20170618160637.bmp
-rw-r--r-- 1 shyouhei wheel 231K 6 19 12:33 20170618160637.jpg
-rw-r--r-- 1 shyouhei wheel 189K 6 19 13:07 20170618160637.png
-rw-r--r-- 1 shyouhei wheel 154K 6 19 14:16 20170618160637.zopfli.png
-rw-r--r-- 1 shyouhei wheel 114K 6 19 13:21 20170618160637.cjpeg.jpg
なんか手元では一旦bmpを経由しなければいけなかった(理由不明)が、もとの半分まで減った。jpgで戦うなら最強に近いのではないか。ただしこいつは非可逆圧縮 なので、上下にリストアップされている他の圧縮と比べて、ルールが違う というのは指摘しておくべきだろう。実際、元の絵にはなかったモスキートノイズが出る。
左:zopfli(部分、400%に拡大) 右:mozjpeg(部分、400%に拡大) 共に ©2017 小島アジコ
上記の過程で意図せずbmpが生成されてしまったためbrotliでいいのでは仮説が急浮上する。google/brotli というのはgoogleの作った圧縮フォーマットで、chromeおよびそれ系の派生ブラウザであればインライン表示できる。
zsh % ~/bin/brotli --best --keep 20170618160637.bmp
zsh % ls -l --human --sort=size 2017*
-rw-r--r-- 1 shyouhei wheel 449K 6 19 13:21 20170618160637.bmp
-rw-r--r-- 1 shyouhei wheel 231K 6 19 12:33 20170618160637.jpg
-rw-r--r-- 1 shyouhei wheel 189K 6 19 13:07 20170618160637.png
-rw-r--r-- 1 shyouhei wheel 154K 6 19 14:16 20170618160637.zopfli.png
-rw-r--r-- 1 shyouhei wheel 136K 6 19 13:21 20170618160637.bmp.br
-rw-r--r-- 1 shyouhei wheel 114K 6 19 13:21 20170618160637.cjpeg.jpg
136KiB。これはかなり優秀と言っていいと思う。zopflipngよりも減ってる。ただmozjpegには及ばないな(比較がフェアではないが)。
これもgoogle製なのでchromeとか系で表示できるやつだが、webmproject/libwebpというものもある。
zsh % cwebp -noalpha 20170618160637.jpg -o 20170618160637.webp
Saving file '20170618160637.webp'
File: 20170618160637.jpg
Dimension: 563 x 812
Output: 75126 bytes Y-U-V-All-PSNR 39.09 99.00 99.00 40.85 dB
block count: intra4: 1313
intra16: 523 (-> 28.49%)
skipped block: 384 (20.92%)
bytes used: header: 365 (0.5%)
mode-partition: 6021 (8.0%)
Residuals bytes |segment 1|segment 2|segment 3|segment 4| total
macroblocks: | 8%| 19%| 46%| 24%| 1836
quantizer: | 36 | 30 | 25 | 18 |
filter level: | 11 | 6 | 4 | 2 |
zsh % ls -l --human --sort=size 2017*
-rw-r--r-- 1 shyouhei wheel 449K 6 19 13:21 20170618160637.bmp
-rw-r--r-- 1 shyouhei wheel 231K 6 19 12:33 20170618160637.jpg
-rw-r--r-- 1 shyouhei wheel 189K 6 19 13:07 20170618160637.png
-rw-r--r-- 1 shyouhei wheel 154K 6 19 14:16 20170618160637.zopfli.png
-rw-r--r-- 1 shyouhei wheel 136K 6 19 13:21 20170618160637.bmp.br
-rw-r--r-- 1 shyouhei wheel 114K 6 19 13:21 20170618160637.cjpeg.jpg
-rw-r--r-- 1 shyouhei wheel 74K 6 19 14:29 20170618160637.webp
一気に74KiBまで減る。マジか? と思うが、これは実は罠で、cwebp
では可逆圧縮がデフォルトであった(そういう意味ではmozjpegよりも圧倒的に優秀であるとは言えると思う)。ロスレスにするには-lossless
とする必要がある。
zsh % cwebp -noalpha -lossless 20170618160637.jpg -o 20170618160637.lsss0.webp
Saving file '20170618160637.lsss0.webp'
File: 20170618160637.jpg
Dimension: 563 x 812
Output: 157128 bytes
Lossless-ARGB compressed size: 157128 bytes
* Header size: 469 bytes, image data size: 156634
* Lossless features used: PALETTE
* Precision Bits: histogram=5 transform=5 cache=0
* Palette size: 256
zsh % ls -l --human --sort=size 2017*
-rw-r--r-- 1 shyouhei wheel 449K 6 19 13:21 20170618160637.bmp
-rw-r--r-- 1 shyouhei wheel 231K 6 19 12:33 20170618160637.jpg
-rw-r--r-- 1 shyouhei wheel 189K 6 19 13:07 20170618160637.png
-rw-r--r-- 1 shyouhei wheel 154K 6 19 14:44 20170618160637.lsss0.webp
-rw-r--r-- 1 shyouhei wheel 154K 6 19 14:16 20170618160637.zopfli.png
-rw-r--r-- 1 shyouhei wheel 136K 6 19 13:21 20170618160637.bmp.br
-rw-r--r-- 1 shyouhei wheel 114K 6 19 13:21 20170618160637.cjpeg.jpg
-rw-r--r-- 1 shyouhei wheel 74K 6 19 14:29 20170618160637.webp
154KiB。まあzopfliと大差ない。逆に言うとpngで用が足りるなら、わざわざロスレスのwebpを採用する意味はないだろう。このフォーマットは強いjpegとして使うべきっぽい。
- 圧縮による劣化を避けたい場合
- Androidネイティブアプリ広告などchrome系という前提を置けるなら、bmpをbrotliで圧縮するのがなんだかんだで一番ギガが減らない
- そうじゃなくて閲覧環境を特定できないなら、zopflipngが一番ギガの減りが少ない
- 圧縮で画像が劣化していいなら
- Chrome系という前提を置けるなら、非可逆圧縮のwebpが圧倒的。jpegよりもかなり小さく、かつ、jpegよりもかなりきれい。
- そうじゃなくて閲覧環境を特定できないなら、mozjpegを使うのが良さそう。
もとネタの小島先生は減色によるサイズ圧縮を使っていたので、これを試すとどうなるか。
zsh % convert 20170618160637.jpg -resize '416x600' -strip -colors 8 20170618160637.3bit.png
zsh % ~/bin/zopflipng --filters=01234mepb --lossy_transparent 20170618160637.3bit.png 20170618160637.3bit.zopfli.png
Optimizing 20170618160637.3bit.png
Input size: 56712 (55K)
Result size: 34454 (33K). Percentage of original: 60.753%
Result is smaller
zsh % ls -l --human --sort=size *3bit*
-rw-r--r-- 1 shyouhei wheel 56K 6 19 17:24 20170618160637.3bit.png
-rw-r--r-- 1 shyouhei wheel 34K 6 19 17:24 20170618160637.3bit.zopfli.png
いきなり34KiBまで減った。これは小島先生が手で作成したgif画像より僅差で小さいくらいなので、ようは2017年の現在あえて gifを選ぶメリットはない ということでもある。
zsh % convert 20170618160637.jpg -resize '416x600' -strip -colors 8 BMP3:20170618160637.3bit.bmp
zsh % ~/bin/brotli --best --keep --verbose 20170618160637.3bit.bmp
zsh % ls -l --human --sort=size *3bit*
-rw-r--r-- 1 shyouhei wheel 122K 6 19 17:26 20170618160637.3bit.bmp
-rw-r--r-- 1 shyouhei wheel 56K 6 19 17:24 20170618160637.3bit.png
-rw-r--r-- 1 shyouhei wheel 34K 6 19 17:24 20170618160637.3bit.zopfli.png
-rw-r--r-- 1 shyouhei wheel 32K 6 19 17:26 20170618160637.3bit.bmp.br
32KiB、まあ減ったけど小改善かな。
zsh % cwebp -noalpha -m 6 -q 0 pass 10 -lossless 20170618160637.3bit.zopfli.png -o 20170618160637.3bit.loss0.webp
Saving file '20170618160637.3bit.loss0.webp'
File: 20170618160637.3bit.zopfli.png
Dimension: 416 x 600
Output: 34914 bytes
Lossless-ARGB compressed size: 34914 bytes
* Header size: 222 bytes, image data size: 34667
* Lossless features used: PALETTE
* Precision Bits: histogram=4 transform=4 cache=0
* Palette size: 7
zsh % cwebp -noalpha -m 6 pass 10 20170618160637.3bit.zopfli.png -o 20170618160637.3bit.webp
Saving file '20170618160637.3bit.webp'
File: 20170618160637.3bit.zopfli.png
Dimension: 416 x 600
Output: 51734 bytes Y-U-V-All-PSNR 38.49 99.00 99.00 40.25 dB
block count: intra4: 798
intra16: 190 (-> 19.23%)
skipped block: 133 (13.46%)
bytes used: header: 307 (0.6%)
mode-partition: 3649 (7.1%)
Residuals bytes |segment 1|segment 2|segment 3|segment 4| total
macroblocks: | 92%| 0%| 7%| 0%| 988
quantizer: | 27 | 23 | 15 | 15 |
filter level: | 8 | 5 | 2 | 2 |
zsh % ls -l --human --sort=size *3bit*
-rw-r--r-- 1 shyouhei wheel 732K 6 19 17:37 20170618160637.3bit.tif
-rw-r--r-- 1 shyouhei wheel 122K 6 19 17:26 20170618160637.3bit.bmp
-rw-r--r-- 1 shyouhei wheel 56K 6 19 17:24 20170618160637.3bit.png
-rw-r--r-- 1 shyouhei wheel 51K 6 19 17:39 20170618160637.3bit.webp
-rw-r--r-- 1 shyouhei wheel 35K 6 19 17:35 20170618160637.3bit.loss0.webp
-rw-r--r-- 1 shyouhei wheel 34K 6 19 17:24 20170618160637.3bit.zopfli.png
-rw-r--r-- 1 shyouhei wheel 32K 6 19 17:26 20170618160637.3bit.bmp.br
losslessで32KiB、lossyでは逆に51Kと増えてしまったが、これはおそらく使い方が悪くて、losslessはきちんとPALETTE
って出力されてるからindexed colorになってるけど、たぶんlossyはそうなってない。
- いまどきgifを選択する必要はない
- webpと減色の相性は調査不足を感じる
どちらも、256色に原色して減らすというものなので、元絵がパレットを使ってなくて色数が多い絵じゃないと効果はないですね。