PNG画像の圧縮にOptiPNGとZopfli圧縮を導入

サーバーのストレージ節約のため、保存されているPNG画像の圧縮をしたいと思い手法を調べてみたところ、OptiPNGを使った圧縮と、Zopfliを使った圧縮のどちらかが良さそうな感じでした。Zopfliは、PHPから使えるphp-ext-zopfliというライブラリがあるので、そちらを。

とりあえずどっちもサーバーにインストールしてみました。

インストール

■OptiPNGのインストール

yum install optipng

■php-ext-zopfliのインストール

git clone https://github.com/cubicdaiya/php-ext-zopfli.git
git clone https://code.google.com/p/zopfli/

cp -r /[user]/zopfli/src/zopfli/ /[user]/php-ext-zopfli/

phpize
./configure
make
make install

更にモジュールを読み込むため、php.d/にzopfli.iniというファイルを作成し、下記を書き込み保存します。

extension=zopfli.so

OptiPNGはyumにリポジトリがあるのでそのままインストール出来ます。この時点ではVer0.6.4がインストールされました。
php-ext-zopfliは、まずZopfli本体も必要なのでそちらもダウンロードし、php-ext-zopfliを展開した中のディレクトリにあるzopfliディレクトリに、zopfli/src/zopfli/の中身をコピーします。これをしないとmake installでエラーになります。

使ってみる

■OptiPNGを使う

OptiPNGはこんな感じのコマンドを入力すると、色々自動で最適化してくれます。

optipng sample.png

上記のコマンドで下記のようなログが出て最適化されます。

OptiPNG 0.6.4: Advanced PNG optimizer.
Copyright (C) 2001-2010 Cosmin Truta.

** Processing: sample_opti.png
74x74 pixels, 4x8 bits/pixel, RGB+alpha
Input IDAT size = 5159 bytes
Input file size = 5216 bytes

Trying:
  zc = 9  zm = 8  zs = 0  f = 0		IDAT size = 4227
  zc = 9  zm = 8  zs = 1  f = 0		IDAT size = 4223
  zc = 1  zm = 8  zs = 2  f = 0
  zc = 9  zm = 8  zs = 3  f = 0
  zc = 9  zm = 8  zs = 0  f = 5
  zc = 9  zm = 8  zs = 1  f = 5
  zc = 1  zm = 8  zs = 2  f = 5
  zc = 9  zm = 8  zs = 3  f = 5

Selecting parameters:
  zc = 9  zm = 8  zs = 1  f = 0		IDAT size = 4223

Output IDAT size = 4223 bytes (936 bytes decrease)
Output file size = 4280 bytes (936 bytes = 17.94% decrease)

ファイルサイズが17.94%低下しました。

sample sample_opti

左が元ファイルで、右が最適化後のファイルです。見た目ほとんど変わっていません。
なお、オプションで圧縮処理の仕方について色々指定も出来るので、用途に合わせてオプションをつけるといいです。

OptiPNGのオプション一覧: 小粋空間

■Zopfliを使う

無事にインストールできていれば、zopfli_png_recompressというIDATチャンクを圧縮してくれる関数が追加されていますので、下記のように使うとPNGファイルが圧縮されます。

$origin_file = dirname(__FILE__) . '/sample.png';
$recompress_file = dirname(__FILE__) . '/sample-recomp.png';

$data = file_get_contents($origin_file);
$recompress = zopfli_png_recompress($data);
file_put_contents($recompress_file, $recompress);

同じファイルを使っての結果は下記のようになりました。

*** Testing zopfli_png_recompress() ***
ORIGIN: 5216
RECOMPRESS: 4920

sample_comp比較

先ほどのサンプルのような、非常に単純な小さい画像だとOptiPNGの方が良いようですが、イラストのような画像の場合は以下のようになりました。

*** Testing zopfli_png_recompress() ***
ORIGIN: 19653
RECOMPRESS: 18092
OPTIPNG: 18868

neco neco_comp neco_opti

左がオリジナルファイル、中央がZopfli(8.0%圧縮)、右がOptiPNG(4.0%圧縮)です。

OptiPNGの方もオプションの値次第で色々と変わってくると思いますが、色数を減らさずあまり見た目変わらない程度の圧縮方法では、特徴としてはOptiPNGが単調な画像向き、Zopfliが複雑な画像向きかな、と思いました。

実装について

以上のような結果から、内容によって使い分けるのが良いだろうということで、iconDecotterでは、フレーム画像のサムネイルにはOptiPNG圧縮を、ユーザーのbeforeアイコン画像についてはZopfli圧縮をかけるようにしました。投稿されたフレーム素材画像については、とりあえずは未圧縮としています。

参考

PNG画像を最適化するツール「OptiPNG」: 小粋空間
php-ext-zopfliでPNG画像を再圧縮 – pixiv engineering blog

追記

そもそもアルゴリズムが違うんだから両方かければいいよ、というツッコミをいただき。

*** Testing zopfli_png_recompress() ***
ORIGIN: 19653
RECOMPRESS: 18092
OPTIPNG: 18868
RECOMPRESS - OPTIPNG: 18068
OPTIPNG - RECOMPRESS: 18068

neco_opti-comp

どっちを先に処理しても同じかな?
あんまりたくさん走らない処理なら、両方掛けてしまうのが良いみたいでした。

コメント

  1. […] ※なおそれのせいか、Zopfli圧縮処理をかけるとタイムアウトエラーが出るように  なったっぽいので、今は一旦Zopfli圧縮は経由しないようにしてます…。 […]

タイトルとURLをコピーしました