JPEG / PNG / zip / FLAC / H.264 …で実際に使われているアルゴリズムを、 フォーマット別ではなく層別に再現して測るための研究用リポジトリ。
主要フォーマットは、どれも同じ 6 層の組み合わせでできている。 フォーマットごとに実装すると同じ処理を何度も書くことになるし、 「どの選択がどれだけ効いているか」が測れない。
| 層 | やること | 実装 | 実物での例 |
|---|---|---|---|
| 1 予測 | 隣接から予測して残差にする | png_filter lpc |
PNG フィルタ / FLAC LPC / H.264 イントラ予測 |
| 2 変換 | 周波数領域へ移す | dct mdct dwt color |
JPEG DCT / MP3 MDCT / JPEG2000 DWT / YCbCr |
| 3 量子化 | ここだけが情報を捨てる | quant |
JPEG 量子化テーブル / MP3 心理音響 |
| 4 辞書 | 過去の出力を参照する | lz77 lzw deflate |
zip / gzip / GIF / zstd |
| 5 符号化 | 確率に応じてビットを割り当てる | huffman rice arith rans |
DEFLATE / FLAC / CABAC / FSE |
| 6 完全性 | 壊れ・同一性の検出 | crc32 sha256 |
zip CRC / PNG チャンク CRC |
「損失を減らす」で触るべきなのは第 3 層。DCT も MDCT も理屈上は可逆で、 捨てているのは量子化だけ。人間の知覚の穴(輝度より色差の解像度が低い、 高周波のコントラスト感度が落ちる、強い音の近傍が聞こえなくなる)を どこまで攻めるかは、量子化テーブルとマスキング閾値の設計に集約される。
FLAC 型の可逆は第 3 層を抜いた構成 = 「1 予測 → 5 符号化」だけ。
lpc.py がそのまま最小の FLAC になっている。
生バイト列に汎用圧縮をかけるだけでは、素材が持っている相関に届かない。
実物のフォーマットが強いのは層を重ねているからで、その合成が pipeline.py。
| 合成 | 層の順 | 実物 |
|---|---|---|
png_like |
予測 → 辞書 → 符号化 | PNG |
ycocg_png |
変換 → 予測 → 辞書 → 符号化 | H.264 可逆 / JPEG XL / WebP lossless |
png_rans |
予測 → 符号化 | 辞書層を抜いた PNG |
flac_like |
予測 → 符号化 | FLAC |
同じ 128x128 RGB で、生がけの lzma が 0.805 のところ PNG フィルタを 1 枚 挟むだけで 0.424 になる。順序も効く: YCoCg-R でチャンネル間の相関を先に 落とすと 0.325 まで下がる(色変換の後だからプレーン分離が効く。RGB のまま 分離すると 3 面が似すぎていて逆に悪化する)。
python test_codecs.py # 全層の自己検査(往復一致・既知実装との突き合わせ)
python bench.py # 圧縮率と速度を測って results.jsonl に追記
python bench.py --codec deflate --material text --note "chain_limit を 256 に"bench.py は往復不一致を即 FAIL にする。可逆コーデックの検証はこれが全て。
zlib lzma bz2 を同じ表に並べてあるので、自作がどこに立っているかが毎回出る。
| 素材 | 自作 | zlib | lzma |
|---|---|---|---|
| text 200KB | deflate 0.294 | 0.284 | 0.254 |
| source 200KB | deflate 0.017 | 0.017 | 0.005 |
| image_raw 48KB | ycocg_png 0.320 / png_like 0.430 | 0.915 | 0.805 |
| audio_le16 48KB | flac_like 0.464 | 0.938 | 0.625 |
Current Mac / Python 3.12 で 11 round-trip tests を通した同一 run の値。random data は約 1.001 で改善せず、層追加が効く領域と効かない領域を分離できる。
同じ commit 5b93e37 を6ノード(macOS 2台、Windows 4台、Python 3.12/3.13)で再実行し、全ノードで11 testsと全圧縮比が一致した。速度は ycocg_png が encode 0.13–0.39 MB/s / decode 0.80–2.53 MB/s、flac_like が encode 0.05–0.22 MB/s / decode 0.44–1.77 MB/s。したがって比率は再現可能だが、Python 実装の速度を単一ホスト値で代表させない。
汎用同士(text / source)は構造が同じなので数 % 差に収まる。桁で開くのは
素材の形を知っている合成コーデックの側で、lzma を image で 2.5 倍、
audio で 1.3 倍上回る。deflate と zlib の残差は符号長表の RLE 圧縮を
省いていることと、マッチ探索の深さ(chain_limit)から来ている。
- 実フォーマットと bit-exact ではない。構造を同じにして、コンテナと ビット詰めの細部を省いている。省略箇所は各モジュールの docstring に書いた。
- Python 実装は読むためのもの。速度が要る層だけ後で C / Rust / Go に落とす。 そのときの検証条件は「Python 版と 1 バイトも違わない出力」。
- 検証できていないものは ROADMAP.md の未実装欄に置いてある。実装済みと
書いてあるものは
test_codecs.pyが通っている。
- RFC 1951 (DEFLATE) / RFC 1950 (zlib) / RFC 2083 (PNG)
- ITU-T T.81 (JPEG) — Annex K に量子化テーブルとその由来
- ITU-T T.800 (JPEG2000) — CDF 5/3 と 9/7
- FIPS 180-4 (SHA-2)
- xiph.org の FLAC format specification
- ITU-T H.264 / H.265 仕様書
Apache License 2.0。MIT ではなく Apache-2.0 を選んだのは特許条項のため。 圧縮の分野は GIF/LZW、H.264/HEVC のパテントプールと、特許が普及を止めてきた歴史がある。 AV1 と zstd が permissive かつ特許明示のライセンスで出たのは技術判断ではなく戦略判断だった。 明示的な特許許諾がない MIT だと、同じ轍を踏む余地が残る。