いつのまにかZOPFLIのバージョンが新しくなっていた件（ただし4年前）

といっても最新版 1.0.3 のリリースは 2019 年 11 月 28 日である。気づくの遅えよと言われても仕方ない。

https://github.com/google/zopfli

# ZOPFLI とは
ZOPFLI とは deflate，gzip，zlib 互換で高い圧縮率を誇る（代わりに膨大な時間を要する）google 謹製のライブラリである。PNG ファイルも deflate を採用しているし，マイクロソフトオフィスのファイル形式（docx，xlsx, pptx など）は ZIP 形式そのものだ。

# バージョン履歴
どうやら，今まで自分が使っていたのは 1.0.1 らしい。

<table>
<thead>
<tr><th style="text-align:center;">Version</th>
    <th style="text-align:center;">Release</th></tr>
</thead>
<tbody>
<tr></tr>
<tr><td style="text-align:center;">1.0.0</td>
    <td style="text-align:center;">2013 年 04 月 25 日</td></tr>
<tr></tr>
<tr><td style="text-align:center;">1.0.1</td>
    <td style="text-align:center;">2015 年 08 月 22 日</td></tr>
<tr></tr>
<tr><td style="text-align:center;">1.0.2</td>
    <td style="text-align:center;">2018 年 05 月 18 日</td></tr>
<tr></tr>
<tr><td style="text-align:center;">1.0.3</td>
    <td style="text-align:center;">2019 年 11 月 28 日</td></tr>
</tbody>
</table>

# ソースコード比較
ざっくりソースコードを比較してみると，全般的に手を入れているようだ。

<details><summary>ファイルサイズの比較</summary>

※内容が同一のセルはグレイで示す
<table>
<caption><b>ファイルサイズの比較（単位はバイト）</b></caption>
<thead>
<tr><th style="text-align:center;">ファイル名</th>
    <th style="text-align:center;">1.0.1</th>
    <th style="text-align:center;">1.0.3</th></tr>
</thead>
<tbody>
<tr></tr>
<tr><td style="text-align:left;">BLOCKSPLITTER.H</td>
    <td style="text-align:right;">2,818</td>
    <td style="text-align:right;">2,656</td></tr>
<tr></tr>
<tr><td style="text-align:left;">BLOCKSPLITTER.C</td>
    <td style="text-align:right;">9,579</td>
    <td style="text-align:right;">9,285</td></tr>
<tr><td style="text-align:left;">CACHE.H</td>
    <td style="text-align:right;">2,256</td>
    <td style="text-align:right;">2,256</td></tr>
<tr><td style="text-align:left;">CACHE.C</td>
    <td style="text-align:right;">3,912</td>
    <td style="text-align:right;">3,928</td></tr>
<tr></tr>
<tr><td style="text-align:left;">DEFLATE.H</td>
    <td style="text-align:right;">2,932</td>
    <td style="text-align:right;">3,099</td></tr>
<tr></tr>
<tr><td style="text-align:left;">DEFLATE.C</td>
    <td style="text-align:right;">29,521</td>
    <td style="text-align:right;">32,950</td></tr>
<tr><td style="text-align:left;">GZIP_CONTAINER.H</td>
    <td style="text-align:right;">1,402</td>
    <td style="text-align:right;">1,402</td></tr>
<tr><td style="text-align:left;">GZIP_CONTAINER.C</td>
    <td style="text-align:right;">3,563</td>
    <td style="text-align:right;">6,208</td></tr>
<tr></tr>
<tr><td style="text-align:left;">HASH.H</td>
    <td style="text-align:right;">2,309</td>
    <td style="text-align:right;">2,377</td></tr>
<tr></tr>
<tr><td style="text-align:left;">HASH.C</td>
    <td style="text-align:right;">3,821</td>
    <td style="text-align:right;">3,958</td></tr>
<tr><td style="text-align:left;">KATAJAINEN.H</td>
    <td style="text-align:right;">1,497</td>
    <td style="text-align:right;">1,497</td></tr>
<tr><td style="text-align:left;">KATAJAINEN.C</td>
    <td style="text-align:right;">7,919</td>
    <td style="text-align:right;">7,993</td></tr>
<tr></tr>
<tr><td style="text-align:left;">LZ77.H</td>
    <td style="text-align:right;">4,801</td>
    <td style="text-align:right;">5,645</td></tr>
<tr></tr>
<tr><td style="text-align:left;">LZ77.C</td>
    <td style="text-align:right;">15,067</td>
    <td style="text-align:right;">20,577</td></tr>
<tr></tr>
<tr><td style="text-align:left;">SQUEEZE.H</td>
    <td style="text-align:right;">2,175</td>
    <td style="text-align:right;">2,217</td></tr>
<tr></tr>
<tr><td style="text-align:left;">SQUEEZE.C</td>
    <td style="text-align:right;">18,102</td>
    <td style="text-align:right;">18,844</td></tr>
<tr></tr>
<tr><td style="text-align:left;">SYMBOLS.H</td>
    <td style="text-align:right;"></td>
    <td style="text-align:right;">8,654</td></tr>
<tr><td style="text-align:left;">TREE.H</td>
    <td style="text-align:right;">1,677</td>
    <td style="text-align:right;">1,677</td></tr>
<tr></tr>
<tr><td style="text-align:left;">TREE.C</td>
    <td style="text-align:right;">3,375</td>
    <td style="text-align:right;">3,375</td></tr>
<tr><td style="text-align:left;">UTIL.H</td>
    <td style="text-align:right;">6,142</td>
    <td style="text-align:right;">5,482</td></tr>
<tr></tr>
<tr><td style="text-align:left;">UTIL.C</td>
    <td style="text-align:right;">7,474</td>
    <td style="text-align:right;">1,023</td></tr>
<tr><td style="text-align:left;">ZLIB_CONTAINER.H</td>
    <td style="text-align:right;">1,402</td>
    <td style="text-align:right;">1,402</td></tr>
<tr><td style="text-align:left;">ZLIB_CONTAINER.C</td>
    <td style="text-align:right;">2,415</td>
    <td style="text-align:right;">2,415</td></tr>
<tr></tr>
<tr><td style="text-align:left;">ZOPFLI.H</td>
    <td style="text-align:right;">2,790</td>
    <td style="text-align:right;">2,536</td></tr>
<tr></tr>
<tr><td style="text-align:left;">ZOPFLI_BIN.C</td>
    <td style="text-align:right;">6,319</td>
    <td style="text-align:right;">6,359</td></tr>
<tr><td style="text-align:left;">ZOPFLI_LIB.C</td>
    <td style="text-align:right;">1,428</td>
    <td style="text-align:right;">1,428</td></tr>
</tbody>
</table>
</details>

# パフォーマンス比較
さっそく最新版のコードを使って自作の BMP ⇒ PNG 変換ツールを再ビルドしてみたが，コンパイル自身は特に問題なく通った。※Visual Studio 2022 を使用

BMP ファイル 7 個（合計 20,295,546 バイト）を PNG ファイルに変換するのに要する時間を測定した。圧縮率は元の BMP ファイルサイズに対する比である。

<table>
<thead>
<tr><th style="text-align:center;">Version</th>
    <th style="text-align:center;">1.0.1</th>
    <th style="text-align:center;">1.0.3</th></tr>
</thead>
<tbody>
<tr></tr>
<tr><th style="text-align:center;">ファイルサイズ</th>
    <td style="text-align:center;">8,668,599 バイト</td>
    <td style="text-align:center;">8,644,447 バイト</td></tr>
<tr></tr>
<tr><th style="text-align:center;">圧縮率</th>
    <td style="text-align:center;">42.7%</td>
    <td style="text-align:center;">42.5%</td></tr>
<tr></tr>
<tr><th style="text-align:center;">計算時間</th>
    <td style="text-align:center;">61.0秒</td>
    <td style="text-align:center;">69.0秒</td></tr>
</tbody>
</table>

正直言うと高速化を期待したのであるが，圧縮率は少しだけ向上する代わりに計算時間はますます増える結果となった。ちなみにこの時のブロック分割数は 16，繰り返し回数は 15 である。

次にこちらも自作の ZIP 形式ファイルの再圧縮ツールを再ビルドして，マイクロソフトオフィスのファイル（EXCELファイル，2,460,374バイト）の再圧縮を試みた。ZOPFLI にはブロック分割数と繰り返し回数の２つの調整パラメータがある。繰り返し回数は圧縮を試行する回数であり，多ければ多いほど圧縮率は高くなる。ブロック分割数も同様に多くすれば多くするほど圧縮率は高くなるが，特別に 0 は無制限という意味になる。

最新版の 1.0.3 は全ての条件において 1.0.1 よりも圧縮率が高くなっている。計算時間と圧縮率のトレードオフを考えると，むやみに繰り返し回数を増やすよりはブロック分割数を増やしたほうが良いようだが，この辺りはデータによっても変わるだろう。

ちなみに ZLIB を用いた場合の圧縮率 83.09%，計算時間は 2 秒である。※最大圧縮レベル 9 のとき

いや，もう ZLIB でいいんじゃね？と思うと同時にマイクロソフト EXCEL はスピード重視のためか圧縮率は低いようだ。圧縮レベル 1 くらいか？

<table>
<caption>計算時間と圧縮率のトレードオフ</caption>
<thead>
<tr><th rowspan=2 style="text-align:center;">ブロック<br>分割数</th>
    <th rowspan=2 style="text-align:center;">繰り返し<br>回数</th>
    <th colspan=2 style="text-align:center;">1.0.1</th>
    <th colspan=2 style="text-align:center;">1.0.3</th></tr>
<tr><th style="text-align:center;">圧縮率</th>
    <th style="text-align:center;">時間</th>
    <th style="text-align:center;">圧縮率</th>
    <th style="text-align:center;">時間</th></tr>
</thead>
<tbody>
<tr></tr>
<tr><td rowspan=6 style="text-align:right;">16</td>
    <td style="text-align:right;">5</td>
    <td style="text-align:right;">80.00%</td>
    <td style="text-align:right;">75秒</td>
    <td style="text-align:right;">79.97%</td>
    <td style="text-align:right;">106秒</td></tr>
<tr></tr>
<tr><td style="text-align:right;">15</td>
    <td style="text-align:right;">79.80%</td>
    <td style="text-align:right;">109秒</td>
    <td style="text-align:right;">79.75%</td>
    <td style="text-align:right;">136秒</td></tr>
<tr></tr>
<tr><td style="text-align:right;">50</td>
    <td style="text-align:right;">79.72%</td>
    <td style="text-align:right;">223秒</td>
    <td style="text-align:right;">79.66%</td>
    <td style="text-align:right;">247秒</td></tr>
<tr></tr>
<tr><td rowspan=6 style="text-align:right;">0</td>
    <td style="text-align:right;">5</td>
    <td style="text-align:right;">79.64%</td>
    <td style="text-align:right;">111秒</td>
    <td style="text-align:right;">79.55%</td>
    <td style="text-align:right;">203秒</td></tr>
<tr></tr>
<tr><td style="text-align:right;">15</td>
    <td style="text-align:right;">79.48%</td>
    <td style="text-align:right;">157秒</td>
    <td style="text-align:right;">79.36%</td>
    <td style="text-align:right;">250秒</td></tr>
<tr></tr>
<tr><td style="text-align:right;">50</td>
    <td style="text-align:right;">79.34%</td>
    <td style="text-align:right;">337秒</td>
    <td style="text-align:right;">79.21%</td>
    <td style="text-align:right;">412秒</td></tr>
<tr></tr>
</tbody>
</table>

<font color=red>$○$</font> バージョン 1.0.1，ブロック分割数 16 のとき
<font color=red>$●$</font> バージョン 1.0.1，ブロック分割数 0 のとき
<font color=blue>$◇$</font> バージョン 1.0.3，ブロック分割数 16 のとき
<font color=blue>$◆$</font> バージョン 1.0.3，ブロック分割数 0 のとき

※マーカのラベルは（ブロック分割数，繰り返し回数）という意味

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3490655/f23ac393-65b6-1515-1e1e-5753a5839aa1.png" alt="計算時間と圧縮率のトレードオフ">

# おまけ
自作の ZIP ファイルの再圧縮ツール，PNG ファイルの再圧縮ツールについても公開しようと思ったが，同じようなことを考える先人は必ずいるものだ。

https://koturn.hatenablog.com/entry/2021/06/24/080000