自炊の画像形式をPNGからWebPに移行する

# はじめに

かつて筆者は大量に「自炊」を行っていた。「自炊」といってもドキュメントスキャナを使って所有する雑誌や書籍をデジタルデータに変換するほうだ。その際，JPEG 画像のブロックノイズを嫌い，可逆圧縮の PNG 形式を愛用していた。

近年 Google 製の WebP フォーマットが徐々に普及している印象であり，WebP フォーマットは可逆圧縮（lossless）モードもサポートしていることから，これを評価してみたい。

# WebPユーティリティのインストール

[WebP のダウンロードリポジトリ](https://storage.googleapis.com/downloads.webmproject.org/releases/webp/index.html) よりダウンロードする。Windows 向けにはコンパイル済みのバイナリが用意されている。64bit 版のバイナリしか置いていないので，32bit 版が必要な人は自分でビルドする必要がある。なお，画像ファイルの入出力に WIC（Windows Image Component）を使用するか否かによってバイナリが分かれているが，WIC を使用するほうで良いと思う。

- libwebp-1.4.0-windows-x64.zip（WIC を使用する）
- libwebp-1.4.0-windows-x64-no-wic.zip（WIC を使用しない）

# cwebp のオプションについて

WebP 形式の画像ファイルを生成するツールとしては cwebp という実装サンプルが提供されており，これがとても高機能なので大抵の人にとってはこのツールで十分だろう。このうち可逆圧縮モードに関するオプションを以下に示す。

<dl>
<dt>-lossless</dt>
<dd>可逆圧縮を行う際には必須である。</dd>
<dt>-m [整数]</dt>
<dd>圧縮方法 method を選択する。0～6 の整数を与える。小さい値は高速，大きい値は高圧縮になる。デフォルトは 4 である。</dd>
<dt>-q [実数]</dt>
<dd>圧縮品質 quality を選択する。0～100 の実数を与える。小さい値は高速，大きい値は高圧縮になる。デフォルトは 75 である。</dd>
<dt>-z [整数]</dt>
<dd>可逆圧縮モードのプリセットを選択する。0～9 の整数を与える。小さい値は高速，大きい値は高圧縮になる。デフォルトは 6 である。なお，オプション <b>-m</b> または <b>-q</b> を使用するとオプション <b>-z</b> の指定は無効になる。詳しくは表１参照のこと。</dd>
<dt>-mt</dt>
<dd>可能な限り，マルチスレッドを使用する。</dd>
<dt><font color=silver>-preset [文字列]</font></dt>
<dd>圧縮パラメータのプリセットを選択する。文字列には default, photo, picture, drawing, icon, text が入る。ソースコードを読む限り，可逆圧縮モードでは無効のようだ。</dd>
<dt><font color=silver>-hint [文字列]</font></dt>
<dd>入力画像のヒントを与える。文字列には photo, picture, graph のいずれかが入る。ソースコードを読む限り，最初にバッファを確保する大きさをヒントに応じて変えている程度であり，ほぼ動作に影響を及ぼさないと考えられる。</dd>
</dl>

ソースコードを読む限り，オプション <b>-z</b> とオプション <b>-m</b> および <b>-q</b> の関係は以下のようになっている。すなわち，圧縮パラメータは事実上オプション <b>-z</b> だけの一つを調整すれば済むようになっている。デフォルト値を<font color=red><b>赤色</b></font>で示す。

ソースコードは `src\enc\config_enc.c` を参照した。

<table>
<thead>
<tr><th colspan=11 style="text-align:center">表１　可逆圧縮モードのプリセット表</th></tr>
</thead>
<tbody>
<tr></tr>
<tr><th style="text-align:center">-z</th>
    <td style="text-align:right">0</td>
    <td style="text-align:right">1</td>
    <td style="text-align:right">2</td>
    <td style="text-align:right">3</td>
    <td style="text-align:right">4</td>
    <td style="text-align:right">5</td>
    <tD style="text-align:right"><font color=red><b>6</b></font></td>
    <td style="text-align:right">7</tD>
    <td style="text-align:right">8</td>
    <td style="text-align:right">9</td></tr>
<tr></tr>
<tr><th style="text-align:center">-m</th>
    <td style="text-align:right">0</td>
    <td style="text-align:right">1</td>
    <td style="text-align:right">2</td>
    <td style="text-align:right">3</td>
    <td style="text-align:right">3</td>
    <td style="text-align:right">4</td>
    <td style="text-align:right"><font color=red><b>4</b></font></td>
    <td style="text-align:right">4</td>
    <td style="text-align:right">5</td>
    <td style="text-align:right">6</td></tr>
<tr></tr>
<tr><th style="text-align:center">-q</th>
    <td style="text-align:right">0</td>
    <td style="text-align:right">20</td>
    <td style="text-align:right">25</td>
    <td style="text-align:right">30</td>
    <td style="text-align:right">50</td>
    <td style="text-align:right">50</td>
    <td style="text-align:right"><font color=red><b>75</b></font></td>
    <td style="text-align:right">90</td>
    <td style="text-align:right">90</td>
    <td style="text-align:right">100</td></tr>
</tbody>
</table>

# サンプル画像

ゆうきまさみ原作「新九郎、奔る！」第一話（月刊スピリッツ2018年3月号掲載分）を題材にした。カラー4頁，白黒36頁を300dpiでスキャンした。ページによって大きさは微妙に異なるが，概ね 2100×3000px のサイズになる。

https://bigcomicbros.net/work/6369/

試し読みだと全ページ白黒だが，雑誌掲載時，冒頭の４ページはカラーだった。

# 実行結果

参考のため PNG とも比較する。ZLIB の圧縮レベルは最高の `level=9`，ZOPFLI のパラメータは `blocksplittingmax=15` および `numiterations=5` とした。一方，WebP の圧縮レベルは標準の `z=6` と最高の `z=9` の二種類を試行した。加えてマルチスレッドオプション <b>-mt</b> も比較することにした。

比較結果を以下に示す。カラーは 4 個のカラー画像の平均値，白黒は 36 個の白黒画像の平均値である。PNG，ZLIB 方式を基準 100 とした相対値で示す。

<table>
<caption><b>表２　各種オプションと圧縮率・計算時間の関係</b></caption>
<thead>
<tr><th colspan=2 rowspan=2>
    <th colspan=2 style="text-align:center">PNG</th>
    <th colspan=4 style="text-align:center">WebP</th>
<tr><th style="text-align:center">ZLIB</th>
    <th style="text-align:center">ZOPFLI</th>
    <th style="text-align:center">z=6</th>
    <th style="text-align:center">z=6,mt</th>
    <th style="text-align:center">z=9</th>
    <th style="text-align:center">z=9,mt</th></tr>
</thead>
<tbody>
<tr></tr>
<tr><th rowspan=3 style="text-align:center">カラー</th>
    <th style="text-align:center">圧縮率</th>
    <td style="text-align:right">100.0</td>
    <td style="text-align:right">94.6</td>
    <td style="text-align:right">87.9</td>
    <td style="text-align:right">87.9</td>
    <td style="text-align:right">87.6</td>
    <td style="text-align:right">87.6</td></tr>
<tr></tr>
<tr><th style="text-align:center">計算時間</th>
    <td style="text-align:right">100.0</td>
    <td style="text-align:right">1,421.2</td>
    <td style="text-align:right">142.0</td>
    <td style="text-align:right">141.5</td>
    <td style="text-align:right">3,363.7</td>
    <td style="text-align:right">2,308.5</td></tr>
<tr></tr>
<tr><th rowspan=3 style="text-align:center">白黒</th>
    <th style="text-align:center">圧縮率</th>
    <td style="text-align:right">100.0</td>
    <td style="text-align:right">96.4</td>
    <td style="text-align:right">92.8</td>
    <td style="text-align:right">92.8</td>
    <td style="text-align:right">92.6</td>
    <td style="text-align:right">92.6</td></tr>
<tr></tr>
<tr><th style="text-align:center">計算時間</th>
    <td style="text-align:right">100.0</td>
    <td style="text-align:right">1,156.1</td>
    <td style="text-align:right">75.6</td>
    <td style="text-align:right">75.6</td>
    <td style="text-align:right">2,039.8</td>
    <td style="text-align:right">1,558.9</td></tr>
</tbody>
</table>

当たり前だが，オプション <b>-mt</b> の有無によって圧縮率は変わらない。

```plantuml
@startuml
<style>
root {
  margin 0
  padding 0
}
title {
  fontColor black
  fontSize 16
}
</style>
title
<img:https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3490655/96ed4113-8c75-bd4d-f199-4df4454948f0.png>

図１　各種オプションと圧縮率の関係
end title
@enduml
```

一方，オプション <b>-mt</b> を付けると計算時間は少し短縮する。ざっくり30～40%といったところか。

```plantuml
@startuml
<style>
root {
  margin 0
  padding 0
}
title {
  fontColor black
  fontSize 16
}
</style>
title
<img:https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3490655/e82e98c5-19e6-7291-0697-2c6cb9e88b4c.png>

図２　各種オプションと計算時間の関係
end title
@enduml
```

測定マシンは Windows10 22H2，Core i7-13700（16コア，24スレッド）メモリ32GB である。

# まとめ

google 謹製の cwebp の可逆圧縮モードを評価した。

- 可逆圧縮モードにおける圧縮オプションはいろいろ用意されてはいるが，オプション <b>-z</b> の一つだけで調整できる。逆に調整要素は一つしかないと考えても良い。プリセットやヒント情報は少なくとも可逆圧縮モードでは無効に等しい。
- WebP 形式およびその実装サンプルである cwebp は素晴らしい。標準の圧縮レベルでも ZLIB と同等のスピードながら，圧縮率は ZOPFLI をはるかに上回るからだ。
- 一方，圧縮レベルを最高にしても，膨大に増える計算時間に対して圧縮率の向上は非常に僅かであった。パラメータのデフォルト値の設定が絶妙とも言える。
- マルチスレッドオプション <b>-mt</b> を指定しても，目を見張るような高速化が行われなかったのは残念である。16コア，24スレッド使用可能なプロセッサを用いても最大 1.6 倍程度であった。ただし，これは致命的な弱点ではない。画像ファイルは多数あるので，画像ファイル毎の並列処理が可能だからだ。

# おまけ

現在，ゆうきまさみ氏の「新九郎、奔る！」は連載を週刊スピリッツ誌に移している。月刊スピリッツ誌はその辺のコンビニに置いておらず県内一の大型書店に出かけて購入していたが，週刊誌に移動してくれたおかげで入手が楽になった。ただし，紙質および印字品質は月刊誌のほうが格段に良かったと思う。

なお，2023年における日本の書店数は約1万1000店舗，コンビニエンスストアは約5万7000店舗，合わせて約7万店舗なので，どこのコンビニでも数冊置いている雑誌の発行部数は少なくとも10万部以上となるはずだ。だが，昨今は週刊スピリッツですらどこのコンビニでも置いている状況ではなくなった。

# 参考文献

- [WebP Lossless はちゃんと Lossless してます - Qiita](https://qiita.com/yoya/items/a000c2e123d448a37f47)

- [libwebp を Windows (VC++) でビルドしたメモ - Qiita](https://qiita.com/softgate/items/a0508d0162b83fe891a7)

- [libwebp のバージョンをあげると速くなる - Qiita](https://qiita.com/yoya/items/bd5f8ff3be6a57586d03)

- [WebP Advanced API の使い方 - Qiita](https://qiita.com/usagi/items/846aa3dcfe4a087f4ad3)

- [WebP のダウンロードとインストール - google](https://developers.google.com/speed/webp/download?hl=ja)

- [WebP API ドキュメント - google](https://developers.google.com/speed/webp/docs/api?hl=ja)

- [日本の書店数 - 出版科学研究所](https://shuppankagaku.com/knowledge/bookstores/)

- [【2023年版】コンビニエンスストアの店舗数ランキング - 日本ソフト販売株式](https://www.nipponsoft.co.jp/blog/analysis/chain-conveniencestore2023/)