背景
Webページの高速化するためにはイメージサイズをできるだけ小さくすることが必要です。たとえば、最近のWebページのコンテンツタイプごとのサイズは以下のようのなっており、イメージが全体の半分程度を占めています。
さらにイメージの中でのフォーマットは、以下の図のようにJPEGで約半分、PNGとGIFがぞれぞれ1/4ずつとなっています。
JPEGは基本的に画質のトレードオフでコンテンツ作成者がサイズを決めていると思いますが、GIFやPNGは可逆圧縮のためサイズを小さくすることが難しいです。特に透明画像を使いたい場合はPNGしか選択肢はありませんが、パフォーマンスを考えるとPNGでもサイズをなるべく小さくしたいです。この秋に開催されたO'Reilly Velocity Euro Conferenceでもいつくかのセッションで挙げられていましたが、Lossy PNGを使うことで画像のサイズを小さくできます。
Lossy PNGの原理
PNGの圧縮にはRGBからindex colorに減色する方法がありますが、ここではRGBのままでの非可逆圧縮について説明します。なお、index colorの非可逆圧縮は以下の説明と違うアルゴリズムが必要です。
PNGの圧縮の原理
通常のPNGのエンコーダは、大きく分けて次の3段階の処理で行われます。
- スキャンライン化などの前処理
- フィルタ処理
- 圧縮処理
圧縮処理はDeflate方式で圧縮を行います。これは、よく使われるZIPとほとんど同じです。画像データをそのまま圧縮処理してもあまり圧縮されないため、フィルタ処理でより効率的に圧縮できるよう画像データを変換します。
フィルタ処理を簡単な例で説明します。
例としてR成分だけの赤い画像を考えます。R成分だけを抜き出すと、
190, 191, 192, 193, 194, 193, 192, 191, 190, 189
これを左隣との差分に置き換えると
190, 1, 1, 1, 1, -1, -1, -1, -1, -1
となります。左端は0との差分なのでそのままの値になります。このように変換することでより高い圧縮率を得られます。
非可逆圧縮
差分を計算するところで、少々「うそ」をついて
190, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
とすればどうでしょう? デコードした画像は
190, 190, 190, 190, 190, 190, 190, 190, 190, 190
となり、元の微妙な赤の陰影が単色の画像に劣化しますが、より圧縮することができます。
これがPNGの非可逆圧縮の原理です。
こうして出来上がったPNGファイルは通常のPNGファイルと全く同じです。言い換えれば、PNGファイルだけを見て非可逆圧縮されたものか、もともと単色の画像だったかは判別できません。
したがって、非可逆圧縮されたPNGファイルも通常のPNGデコーダでデコードできます。
これがLossy PNGの最大の利点です。WebPなど圧縮率を改善した新しいフォーマットが提案されていますが、使えるWebブラウザは限られています。しかし、Lossy PNGの場合、フォーマットそのものは通常のPNGであるため、ほとんどすべてのWebブラウザで表示できます。
#使用したツール
今回はソースコードが確認できる
lossypng
を使用しました。実際の圧縮アルゴリズムは上記より複雑です。
また、圧縮した画像の評価には
dssim
を使用しました。これは画像の評価で標準的に使われているstructual similairityを計算するツールで数字の小さいほど画像間の差がないことを表します。
#評価
##写真
まず、写真を圧縮してみました。
元画像です。
475KB
lossypngは-sオプションで圧縮率を指定できます。-s=0でlosslessで、数字が大きくなるほど圧縮率が大きくなります。以下は何種類かの圧縮率で圧縮した画像です。
-s=20 84KB (18%) DSSIM 0.033773
ファイルサイズは元画像の18%まで小さくなりましたが、パッと見た目はほとんど劣化が目立ちません。
-s=30 61KB (13%) DSSIM 0.055768
サイズは13%ですが、肌などで劣化がわかるようになりました。
-s=50 40KB (8%) DSSIM 0.101474
ここまで小さくすると劣化がはっきりと目立ちます。
-s=80 28KB (6%) DSSIM 0.169919
参考までにかなり圧縮率をあげた例です。
#まとめ
lossy PNGでサイズを大幅に小さくすることができます。また、表示するために特別なデコーダは必要ないので、PC、モバイルなどのほとんどのWebブラウザで表示可能です。