IO_PNG 1.2.3 をリリースしました

filter dump 対応です。

  • 前回の記事

yoya.hatenadiary.jp

PNG は圧縮の前処理として RGB のまま圧縮するか、RGB の差分を圧縮するかの選択が画像の1行毎に出来ます。
今回追加した pngfilter.php はその行毎の filter 値を表示します。なお、結果として filter 値の数は height と一致します。

詳しくは、こちらの記事をどうぞ。(PNG filter でググって一番上にきた記事)

uno036.starfree.jp

使い方

% composer require yoya/io_png
(略)
% php vendor/yoya/io_png/sample/pngfilter.php -f test1.png
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
% php vendor/yoya/io_png/sample/pngfilter.php -f test2.png
1 1 4 2 2 2 1 2 4 2 2 2 2 1 2 4 1 4 2 2 2 2 4 2 2 1 2 1 4 1 4 1 4 4 3 3 1 4 4 4 2 4 3 2 3 2 4 2 1 4 4 2 4 4 4 1 2 4 2 2 2 1 2 4 1 4 1 1 4 1 1 4 2 1 4 2 4 1 4 2 4 1 2 2 2 3 2 1 4 2 2 2 2 4 4 2 4 4 1 2

実験

自分の手元にある 800枚位の PNG 画像(イラスト絵)に対して実行してみました。wordhist.php はこちら >
github.com

% for f in ~/Pictures/Picture/*.png ; do php sample/pngfilter.php -f $f ; done > filter.txt
% php wordhist.php filter.txt
0 => 225389
1 => 167099
2 => 399666
3 => 14265
4 => 46279

2( Up) が多いです。
どうやらイラスト絵は上下にグラデーションをかける傾向があるようで。(手元での結果なので偏ってる可能性あり)

実装コード

https://github.com/yoya/IO_PNG/blob/1.2.3/IO/PNG.php#L294

IDAT chunk のデータ部を連結したものを丸ごと zlib 伸長して復元出来た画像の一行ごとに頭の 1byte を表示します。

$idat_inflated = gzuncompress($idat_data);
(略)
$stride = 1 + ceil($width * $ncomp * $bitdepth / 8);
$offset = 0;
for ($y = 0 ; $y < $height ; $y++) {
    $filter = ord(substr($idat_inflated, $offset, 1));
    $offset += $stride;
    echo "$filter ";
}

ceil で妙な事をしてるのは、grayscale と palette 形式では、 1, 2, 4 bit 深度が表現出来て、バイトのキリの良いとこで終わらない可能性があるからです。