それでもスクリーンショットを繰り返すと色が変わる

前置き

以前、こんなツイートが話題になった。

https://x.com/refeia/status/1573753515172044800

これはスクリーンショットを取られた画面の色空間の情報がそのスクリーンショットに埋め込まれないからである。画像に色空間の情報がないとき、その画像はsRGBの色空間であるだとみなされることが多い。もし、Adobe RGBのモニターに赤色(R,G,B) = (255, 0, 0)を表示し、これのスクリーンショットをとったとき、そのスクリーンショットは当然、(255, 0, 0)という数字が記録されている。このスクリーンショットを同じモニターに貼ると、アプリケーションは(255, 0, 0)という数字の色をsRGBの色空間での数字だとみなし、これをAdobe RGBのモニターに表示するわけだから、モニターには(242, 0, 0)(この数字はsRGBの(255,0,0)と同じ色である))という信号を送る。これがスクリーンショットを貼ると色が変わる理由だ。

本題

前置きが長くなったがmスクリーンショットにそのモニターの色空間の情報(これにはICCプロファイルと呼ばれるものが広く使われている)が埋め込まれ、それが正しく解釈されたとしても計算精度の関係でわずかに色が変化する。左下の写真はテスト用の真っ赤な画像である。カラーコードは#FF0000で、Display P3のICCプロファイルを埋め込んでいる。これをiPhoneの写真アプリで表示し、スクリーンショットを撮り、そのスクリーンショットを表示する、という手順を40回繰り返して得た画像が右下の画像だ。

左 : Red.png 右 : Red40.png

広色域環境でよく見比べないと違いが分からないが、カラーコードを調べると、#E70403であった。かなり色が劣化していることがわかる。iPhoneスクリーンショットにDisplay P3のプロファイルを埋め込むため、この現象は前述した色空間の齟齬によるものではない。もう少し詳しく調べるためにこれらの差分をとってRGB値を50倍にし、(見た目が気持ち悪いので)グレースケールにしたimagemagickのコマンドを以下に示す。

composite -compose difference Red.png Red40.png diff.png
magick convert diff.png -color-matrix "50 0 0  0 50 0  0 0 50" diff50x.png
magick diff50x.png -colorspace Gray diff50xGray.png

このコマンドで生成したdiff50xGray.pngは下のようになった。

diff50xGray.png

この模様はカラーマネジメントの過程で244.43...のように整数ではなくなった色を表示するときに使われるディザリングによるものであると推測した。ディザリング処理にはノイズ、つまり乱数が用いられるが、乱数を逐次計算するよりも乱数テーブルを参照したほうが速いためこのような周期的な模様が現れると考えられる。

終わりに

Windows標準のスクリーンショットICCプロファイルを埋め込まないので、ICCプロファイルを設定した環境だと注意する必要があるが、実は埋め込まれていたとしても若干色が変わることが示せた。