15分で読めた気になるPNG
こんにちは
画像、色がすき。
/icons/いい話だ.iconakix.icondaiiz.icon
どうしてPNGを読みたい?
この世には様々な画像の形式があり、Gyazoにアップロードできる形式の中でもJPEG, PNG, GIFなどがある。 それらのアップロードされてくる画像には様々なメタデータが含まれていたりするので、それをパースして利用したりするため。
例えば、PNGの場合キャプチャされた画面の解像度を取得して、画面に出す時によしなにするなどに利用されている。 貴重なメタデータだakix.icon
おかしなファイル をアップロードされて500エラーが出たりした時に、どうしてそうなったかをデバッグしたりするため。
時々壊れたファイルがアップロードされてAlertが流れる。
あるあるakix.iconyuiseki.icon*2
普段扱っているファイル形式については、詳細なバイナリの上での配置とかまではともかく、おおまかな構造ぐらいはわかっていると良い気がする。 いい話part 2だwakix.icon
hiroshi.icon 読める、読めるぞ
楽しさが伝わってきてすごくいい... daiiz.icon
どうやってPNGを読むか?
バイナリを読んでいくためにはファイルの構造を知る必要がある。
テキストとは違い、見ただけではわからない。
そのためには仕様/specを読むのが良い。
こんなスライドを見てる場合じゃなく、元のspecを読むのが大切!!
これだけ覚えて帰ってください。
発表はこれにて終了。
wwwwwwwwwwakix.iconutgwkk.icon
とは言え、全体の見通しをなんとなく持っておくのは意味があるので続きをやっていく。
たしかに…wakix.icon
構造概略
https://gyazo.com/b873f2d6cf43cac956c3ff6a4d629f0e
実際のファイルではこんな感じ。
https://gyazo.com/fe0061e8c7bb8cc053af330c2d858b28
od -c out.png | head 先頭のほう。
https://gyazo.com/4141aa253f167480fb1a479e670223dc
最後まで聞けば、これが雰囲気ぐらいは目で読めるといいな。
!!P N G!!akix.icon
オシャレ!daiiz.icon
わかりやすいutgwkk.icon
詳細
ヘッダ(PNG file signature)
https://gyazo.com/a6534bd95b18f9ce775cdb6185f7c0f6
固定の8byte 89 50 4E 47 0D 0A 1A 0A
処理系は普通、これを見ることでそのファイルがPNGであることを認識する。
https://gyazo.com/857a74a18239b718586b9f2f97dcf8c7 https://ja.wikipedia.org/w/index.php?title=Portable_Network_Graphics&oldid=87975582#%E3%83%95%E3%82%A1%E3%82%A4%E3%83%AB%E3%83%98%E3%83%83%E3%83%80
メールでの転送時に最上位bitが落ちることがあったり、転送時に改行コードの変更が変換が行なわれていたりしていることを検知できるように考えられている。
https://gyazo.com/934f69527fc688ff333bbc08672edd72
shift_jisで0x89 0x50 は臼になる。 チャンクの概形
https://gyazo.com/ef1eaae7fc0c5011e6416d450c3cac66
これは箱の形なのでさらっと流すけれど、Chunk Typeというものがチャンクの構造としては大切であるということだけを覚えておいてもらえると良い。
Chunk Type
/[a-zA-Z]{4}/のアルファベット4文字
この4文字でチャンクの種別を判別する。
4文字で名前をつけるとともに、それぞれの文字のcaseに以下の情報が含まれる。
1文字目: 大文字であると、「必須チャンク」と言い、全ての処理系はそのチャンクを正しく解釈できる必要がある。 逆に、小文字であるチャンク(「補助チャンク」)のうち、意味を知らないチャンクは無視することが許されている。 これにより、互換性を破壊せずに拡張したりすることが可能となっている。
なるほどakix.iconyosider.icon
2文字目: spec等で定義されたチャンクは大文字。小文字にしておけば自由なチャンクを定義して使うことができる。
任意のdataを持つことができるので、例えばゲームのセーブデータを保持するようなチャンクを定義して、pngの画像に埋め込むなどの例などが思いつく。
(pngの画像にセーブデータを保存する某ゲームでこういう構造になっているのかと覗いてみたら、IENDの後ろにIDATとして構造を持つようになっていた……。確かにIENDで普通の処理系は処理を止めるから動くだろうが……という感じがする)
pngにセーブデータ黒魔術感しかしないtakker.iconutgwkk.icon 3文字目: 将来の拡張に予約されてて常に大文字。
4文字目: safe-to-copyの説明をするには余白が足りない。
wakix.icon
余白を作りました!(違う)takker.icon
case自体に意味が設定されているのすごいなakix.iconMijinko_SD.icontakker.icon
定数か変数かみたいな考え方とも違うルールで面白いakix.icon
これには感動した daiiz.icon
最小限の領域に如何に情報を詰め込むかを突き詰めているtakker.icon
* 基本的なチャンク
IHDR: 画像のサイズやビット深度などが入ってる。
https://gyazo.com/21713ccf705eff4e8ecab55f916c827d
IEND: このチャンクが来るとこの画像はここまでということを表す。
https://gyazo.com/4ea4ab69183090bb51c47e2014ce923f
IDAT: 画像データの「本丸」。ここにピクセルの情報が圧縮されて入る。
フィルタ
これらを解くとpixelの列が得られる。
https://gyazo.com/651553eb2d0a9aaad73542d3962f2243
おお〜なるほどakix.icondaiiz.iconMijinko_SD.icon
sub行の中央は0なのかなakix.icon
元々の範囲から外れている値は0扱い
おおおおなるほどakix.icon
実際うまくフィルタを当てるの難しそうMijinko_SD.icon
チャンクの列 という抽象化
これがよくできているので、後方互換性を保ったまま機能を追加できるので良い。 Future extensions to this specification will not add new fields to existing chunks; instead, new chunk types will be added to carry new information.
もし未来にspecが更新されて、拡張が入ったとしても、既存のチャンクに新たなフィールドが入ったりするようなことはない。そうせずに、新たなチャンクを定義することによって値を保持する。
Note that there is no version number in the signature, nor indeed anywhere in the file. This is intentional: the chunk mechanism provides a better, more flexible way to handle format extensions
PNGのバージョンナンバーのようなものをどこかのフィールドに入れたりする(それによって構造を定義する)のではなく、チャンクを使うのがフレキシブル。
GIFとかだと、file signature相当の位置に、GIF87a, GIF89aなどのバージョン番号が入っている。
これは、GIF87aしか知らない処理系はGIF89aであるような画像を受けとった時に諦めるほかないが、後述するようにPNGだとそのようなことにはならない。
2087年に新しいGIFの仕様つくれないのか〜akix.icon
PNGの仕様こんなに天才的だったの知らなかった・・・akix.icontakker.iconnishio.icontetsuya-k.icon
PNGのサムネイル偽装とかもこういう仕様だからかmtane0412.icon
“gAMA”チャンク
読める!!読めるぞ!!
APNGのファイル構造/APNGを理解する処理系から見たフォーマット https://gyazo.com/7f94d3c5b1c4ca9e6ea0a6439c5e87e4
https://gyazo.com/473dd3e929e5f8b21f309ba06524e00b
APNGを解さない処理系から見た同じファイル
https://gyazo.com/8def6e703c459767817391a0600b365e
知らない値は無視する方式takker.icon
チャンクというバージョンに対して不変な構造を用いている
読めない部分は無視できて便利な反面、ウイルスとかも仕込みやすそう…Mijinko_SD.icon
特定のデコーダーの脆弱性をつくデータとか
それはそれで面白いかMijinko_SD.icon
APNG対応の処理系ならアニメーション表示できる、APNG非対応の場合でも静止画を表示できる!hata6502.icon
凄いよくできた仕様だ daiiz.icontetsuya-k.icon
こんな感じのスケールする仕様すきMijinko_SD.icon
もし人生のうちにファイルフォーマットを考えるようなことがあれば、こういった拡張性を持たせられるような形式にしたいと願う。
エモいakix.icondaiiz.iconutgwkk.icon
まとめ
よく使われているフォーマットのバイナリを読むと楽しい。
ファイルの構造を読むにはそのspecにあたるのが大切。
PNGのファイルはヘッダの後にチャンクが並ぶような構造をしている。
この構造は後方互換性を持ったままの拡張に強い。
ステキだakix.icon
いろんなバイナリを読んでいこう。
Nota/Gyazoでは画像について詳しいエンジニアを募集しています。
途中で挫折したOTLtakker.icon
挫折の理由の大半が「知らない」
IEND