PNGをよんで表示したい!
動機
- 作者: Lara Callender Hogan,西脇靖紘,星野靖子
- 出版社/メーカー: オライリージャパン
- 発売日: 2016/06/25
- メディア: 単行本(ソフトカバー)
- この商品を含むブログ (1件) を見る
「パフォーマンス向上のためのデザイン設計」という本を読んでいると、縦グラデーションの GIF と横グラデーションの GIF ではファイルサイズが大きく違うことが載っていた。水平方向の冗長性を取り除く圧縮アルゴリズムになっているらしく、気になったので軽く調べてみた。
調べていると、PNG は水平方向だけでなく垂直方向にもつよいことが書いてあった。PNG は CTF の問題でヘッダとか見たことあったので PNG で遊んでみようと思った。
つくったもの
スクショだけ見てもわからんな… RGB じゃないと動かないのは仕様だしめっちゃ重いのも仕様!!!
フィルタリング形式の実装をミスるとこんなふうにアートになってたのしいあばばばば〜〜〜
バイナリをよんで Tk ってやつで 1 ピクセルずつ四角を描いてる(ほかにやりようが思いつかなかった)。Ruby/Tk のドキュメントが殆どなかったので Python 実装 Tkinter の使い方を読んでオプション名とかを知った。
PNG の中身(超ざっくり)
仕様書はこれかな…?
Portable Network Graphics (PNG) Specification (Second Edition)
日本語訳(PNG 1.0 仕様書の改訂版)は Web アーカイブとして残っている
PNG (Portable Network Graphics) Specification
N 番煎じなんだけど、メモとして。
シグネチャ
PNG のシグネチャは 8 byte で、決まっている。 50 4e 47
で PNG
を表している。
89 50 4e 47 0d 0a 1a 0a
チャンク
I***はチャンクと呼ばれて、以下でワンセットになっている。
- 長さ
- チャンクの名前
- データ
- CRC
チャンクの名前 | なに |
---|---|
IHDR | サイズとか、画像の情報 |
IDAT | 画像データ本体。複数あっても良い |
IEND | おしまいを表す |
画像データ本体が大きすぎたら分割されて IDAT が複数できるのかな(よくしらない)
フィルタリング
PNG は Deflation 圧縮という圧縮方式みたいで、フィルタリングで工夫すると圧縮効率が良くなるらしい。フィルタリング形式は 0 から 4 まで 5 つあって、これは行ごとに好きなものを選べる。256 を法として modulo をとるので、255 を超えることはない。
値 | フィルタリング形式 | なに |
---|---|---|
0 | None | そのまま出す |
1 | Sub | 左ピクセルとの差分 |
2 | Up | 上ピクセルとの差分 |
3 | Average | 左ピクセル・上ピクセルの平均をとったものとの差分 |
4 | Paeth | 左ピクセル・上ピクセル・左上ピクセルを Paeth predictor したものとの差分 |
上に貼った事故画像は None と Sub を正しく実装したもので、1 行目だけ正しく表示されている。
None だと「圧縮とは??」ってなるしまあ Sub しかねーかって感じがした
— やましー (@yamasy1549) 2017年9月13日
Paeth predictor
Paeth predictor はざっくり言うと、左・上・左上のうちどれが一番近いかなーというのを調べる。縦方向と横方向で変化の小さいほうを選び、縦と横で全く違う感じに変化してたら中間として左上をとるような…
# a: 左 # b: 上 # c: 左上 def paeth_predictor(a, b, c) p = a + b - c pa = (p - a).abs pb = (p - b).abs pc = (p - c).abs if pa <= pb && pa <= pc then a elsif pb <= pc then b else c end end
雰囲気こんなかんじで、これを R / G / B についてやる。
PNG Specification: Filter Algorithms
かんそう
たのしかった。気が向いたら、実装飛ばしてるところをもうちょっと書きたい。