Fix color biases
色が変質する問題が幾つかあるのでその修正です。
1. GIF colormap のオプション追加 9e5f1b7
問題点
現在の master の端末の配色は Solarized (for xterm-256color) です。現在の GIF 出力は左のようになりますが、実際の Solarized (for xterm-256color) は右のようになるべきです。

原因と解決法
色が変化していますが、これは GIF に出力する際に、GIF の256色カラーテーブルから近い色を拾うためです。具体的には、今 GIF のカラーテーブルは rgb332 (R 3bit, G 3bit, B 2bit) の色立方体で初期化されています。これが端末の256色カラーテーブル (Solarized 16色 + 6x6x6色立方体 + 24色グレースケール) と一致しないのが色の変化の原因です。
GIF のカラーテーブルをオプション -m, --colormap=MAP で切り替えられる様にしました。元々のテーブル -m rgb332 とし、コメントアウトされていた端末のテーブルをコピーする方を -m xterm256 としました。Sixel 等を使わない場合は基本的には端末の256色しか使われないので、既定の設定では端末の256色テーブルを用いるように変更しました。
2. 減色 (pixel2index) のバイアス補正 06c81d1 afa21a4
問題点
現在の master ですと全体的に画像の明るさが変化します。以下の表の左側が元の画像・アニメーションで右側が seq2gif で生成した GIF です。- 上段の画像は tests/data/sixel.tty を元にしています。全体に(特に顔色が)白くなっています (左の画像が白背景なのは単にそのような端末で撮っただけなのでその違いは無視して頂けると幸いです)。- 下段の画像は libsixel の snake.bmp を元にしています。こちらは逆に全体的に暗く・濃くなっています。
| Original image | seq2gif master |
|---|---|
![]() |
![]() |
![]() |
![]() |
原因と解決法
master の pixel2index (rgb332) では以下の式(1)を用いて減色していますが、明るい色はより明るく、暗い色はより暗くなる様なバイアスがかかっています。図は量子化誤差 (= (減色後強度) - (減色前強度)) をグラフにした物です。06c81d1 で誤差がより均一な式(2)に変更します。
# (1) master
r = (r >> (8 - RED_MASK)) & bit_mask[RED_MASK];
# (2) This PR
r = (r * bit_mask[RED_MASK ] + bit_mask[7]) / bit_mask[8];

afa21a4 で -m xterm256 の pixel2index の方も同様に修正しています。

(続き)
3. 誤差拡散 76ce6e6
それでも色が微妙に変わるので誤差拡散も実装しました。Floyd-Steinberg 法です。既定で有効にしていますが、既定のカラーテーブル -m xterm256 では、端末の256色以外の色を使わない限りは誤差拡散がない場合と同じ結果になります。
| Original image | -d none | -d fs (誤差拡散) | |
|---|---|---|---|
| -m rgb332 | ![]() |
![]() |
![]() |
| -m xterm256 | ![]() |
![]() |
![]() |
| Original image | -d none | -d fs (誤差拡散) | |
|---|---|---|---|
| -m rgb332 | ![]() |
![]() |
![]() |
| -m xterm256 | ![]() |
![]() |
![]() |
Coverage increased (+1.5%) to 65.888% when pulling 502d20380982252f5a7eeedf6ea43210067afe33 on akinomyoga:support-dither into 886138ed6a682273bc70fec0823ec14f9069ba67 on saitoha:master.
This is another important fix that I believe should be merged at some point. Would like to hear opinions.
I'm recently thinking that we should perform the error diffusion in the linear RGB space rather than in the sRGB space while keeping the nearest color pickup in the sRGB space. The current PR performs the error diffusion in the sRGB space.











