Tools + Simulatorsnanase.cc / tools

PNG

見本

ファイル

まだ選んでいません

対象

色の型

フィルタ

圧縮レベル

インターレース

ファイルの大きさ
—
1 画素あたり
—
圧縮率
—
ブラウザの zlib
—
文字
—
一致
—
CRC-32 · Adler-32
—

画像

SIZE —ROW —

None—
Sub—
Up—
Average—
Paeth—
適応—

ROW —X —FILTER —BITS —

BLOCK ——

ファイルの構成

チャンク位置長さ内容CRC-32

動作原理と式

符号化の手順

  1. 画素色の型・深度のバイトの並び
  2. Adam77 パスに並べ替え(選んだときだけ)
  3. フィルタ行ごとに予測との差
  4. DeflateLZ77 とハフマン符号
  5. zlibヘッダ 2 バイトと Adler-32
  6. チャンクIDAT に分けて CRC-32

PNG の圧縮は可逆です。フィルタは値を変えずに並びを圧縮しやすくし、Deflate が同じ並びの繰り返しと値の偏りを詰めます[1]。

チャンク

ファイルは 8 バイトの署名 89 50 4E 47 0D 0A 1A 0A と、チャンクの並びです[1]。

  1. 長さ4 バイト
  2. 種類英字 4 文字
  3. データ長さの分
  4. CRC-32種類とデータから
  • IHDR: 幅・高さ・深度・色の型・インターレース
  • PLTE: パレットの色(色の型 3)
  • tRNS: パレットの不透明度か、透明にする 1 色
  • IDAT: zlib のデータ。いくつに分けてもよい
  • IEND: 終わり
  • 種類の 1 文字目が小文字のチャンクは補助で、知らなければ読み飛ばしてよい

フィルタ

各行の先頭に種類 0〜4 のバイトを置き、行のバイト x を予測との差 r に置き換えます[1]。

  • a: 1 画素左の同じバイト(深度 8 未満は 1 バイト左)
  • b: 上の行の同じバイト
  • c: 左上
  • 行の外と最初の行の上は 0。Adam7 ではパスの中の上の行
rSub=(x−a)mod256rUp=(x−b)mod256rAverage=(x−⌊(a+b)/2⌋)mod256p=a+b−c,pa=|p−a|,pb=|p−b|,pc=|p−c|rPaeth=(x−{a,ifpa≤pb∧pa≤pcb,ifpb≤pcc,otherwise)mod256

適応は差を符号付きのバイト s とみなした絶対値の和が最小の種類を行ごとに選びます。仕様が勧める経験則で、libpng も同じです[1][5]。最小の大きさになるとは限りません。

t=arg mint∑i|st,i|,st,i∈[−128,127]

Deflate

フィルタ後の行の並びを LZ77 とハフマン符号で詰めます[2]。

  • LZ77: 32,768 バイト前までに同じ並びがあれば、長さ 3〜258 と距離 1〜32,768 の一致にする。なければ文字(1 バイト)
  • 記号: 文字 0〜255・ブロックの終わり 256・長さの符号 257〜285 を 1 つの表、距離の符号 0〜29 を別の表で符号にする。長さと距離の端数は付加ビット
  • ブロック: stored(そのまま)・固定の表・動的な表(表そのものを先頭に書く)の 3 種。符号の長さは 15 ビットまで
  • ビットの順: バイトの下位ビットから詰める。ハフマン符号だけは符号の先頭のビットから詰める

一致の探し方と圧縮レベルは zlib の deflate.c の表にならいます。レベル 1〜3 はすぐに一致を採り、4 以上は次の位置の一致と比べてから決めます(遅延一致)[4]。復号では符号長の表と符号を puff.c と同じ水準で検査します[6]。

Adam7

8×8 の区画の画素を 7 つのパスに分け、粗い格子から送ります[1]。読み込みの途中でも全体の荒い絵が出せる代わりに、隣の画素が離れるのでフィルタと LZ77 が効きにくくなります。

パス1234567
始まり (x, y)0, 04, 00, 42, 00, 21, 00, 1
間隔 (x, y)8, 88, 84, 84, 42, 42, 21, 2

CRC-32 と Adler-32

  • CRC-32: チャンクごとに種類とデータから求める。生成多項式は次の式で、初めの値と最後の値をすべて反転する[1]
  • Adler-32: zlib の末尾に、展開したデータ Di から求めて書く[3]
G(x)=x32+x26+x23+x22+x16+x12+x11+x10+x8+x7+x5+x4+x2+x+1A=(1+∑iDi)mod65521,B=(∑iAi)mod65521Adler-32=B×65536+A

出典

  1. 署名・チャンク・色の型・フィルタ(9 章)・適応の選び方(12.7)・Adam7(8.1)・CRC-32(5.5・付録 D)W3C, Portable Network Graphics (PNG) Specification (Third Edition), W3C Recommendation, 2025-06-24
  2. Deflate の LZ77・ハフマン符号・ブロック・ビットの順P. Deutsch, RFC 1951: DEFLATE Compressed Data Format Specification version 1.3, 1996
  3. zlib のヘッダと Adler-32P. Deutsch, J.-L. Gailly, RFC 1950: ZLIB Compressed Data Format Specification version 3.3, 1996
  4. 圧縮レベルの表(configuration_table)、ハッシュの連鎖、遅延一致J.-L. Gailly, M. Adler, zlib 1.3.1, deflate.c
  5. 適応のフィルタの選び方libpng, pngwutil.c の png_write_find_filter
  6. 復号の検査の水準M. Adler, puff.c(zlib の contrib/puff)

このツールで決めたこと

  • 見本は画素ごとの式と決まった種の乱数で描く。試験図の 5 つの段は、それぞれ Sub・Up・Paeth・Average・None で最も小さくなるように作った
  • Deflate のブロックは記号 16,384 個ごとに区切り、stored・固定・動的のうち最も短いものを使う
  • 残差の画像は 128 に差の 2 倍を足した灰色(RGB はチャンネルごと)。None は元のバイトのまま
  • 1 画素あたりのビット数は、記号のビットを記号が作るバイトに等分して配る
  • グレーは 0.299R + 0.587G + 0.114B を丸めた値
  • ブラウザの zlib は CompressionStream の deflate で、同じフィルタ後の並びを圧縮した大きさ
  • 符号化し直すときは長い辺を 1,024 画素まで、元のファイルのまま調べるのは 1,048,576 画素まで

関連ツール