いろいろないろ、みんなちがってみんないい。…どういうことなの?
画像をいじくる時に、ある元画像の上にレイヤーを重ねて、上のレイヤーの「不透明度」を変えて画像を加工するというのは、よくある事だと思います。GIMPだと「標準」というモードの処理です。んで、数値的にはどんな処理をしてるのかと調べてみたら、意外な結果だったのでメモしておきます。
「不透明度」を変化させて画像を加工する時、元画像の色を I、上にかぶせる画像の色 M、合成された画像の色を E とします*1。M の不透明度を変化させていくと、不透明度 100% の時 E(結果) = M(マスク) で結果の画像は上にかぶせた画像と一致し、0% で E(結果) = I(元) となり元画像と一致します。と、いう事はその中間では、M と I の RGB 成分の差を取って、その差に不透明度の値を掛けたものを元画像の色に足してやる、というのが一番素直だよなと考えて、以下の関数を書いて試してみました。
#Ruby #a, b は RGB を成分としたベクトルクラスのインスタンス。 #a は元画像の色、b はかぶせる画像の色を表す。n は不透明度。 def blend( a, b, n ) n = n / 100.0 ret = a + ((b - a) * n) end
この関数の n を変化させて出て来た値と、実際に画像を重ね合わせた時に出て来る色の値を比べたところ、「だいたい合ってる」んだけど、微妙に違います。その違いは以下の通り。
不透明度 | 生 | floor() | round() | ceil() | GIMP | PictBear | Firefox | Google Chrome |
---|---|---|---|---|---|---|---|---|
10% | 229.5, 235.8, 242.2 | 229, 235, 242 | 230, 236, 242 | 230, 236, 243 | 230, 236, 242 | 229, 235, 242 | 230, 236, 242 | 231, 237, 243 |
20% | 204.0, 216.6, 229.4 | 204, 216, 229 | 204, 217, 229 | 204, 217, 230 | 204, 216, 229 | 204, 216, 229 | 204, 217, 229 | 205, 217, 230 |
30% | 178.5, 197.4, 216.6 | 178, 197, 216 | 179, 197, 217 | 179, 198, 217 | 179, 197, 216 | 178, 197, 216 | 179, 198, 217 | 180, 198, 217 |
40% | 153.0, 178.2, 203.8 | 153, 178, 203 | 153, 178, 204 | 153, 179, 204 | 153, 178, 203 | 153, 178, 203 | 153, 178, 204 | 154, 179, 204 |
50% | 127.5, 159.0, 191.0 | 127, 159, 191 | 128, 159, 191 | 128, 159, 191 | 128, 159, 191 | 127, 159, 191 | 127, 159, 191 | 129, 160, 192 |
60% | 102.0, 139.8, 178.2 | 102, 139, 178 | 102, 140, 178 | 102, 140, 179 | 102, 139, 178 | 102, 139, 178 | 102, 140, 178 | 101, 138, 177 |
70% | 76.5, 120.6, 165.4 | 76, 120, 165 | 77, 121, 165 | 77, 121, 166 | 76, 120, 165 | 76, 120, 165 | 76, 120, 165 | 76, 120, 164 |
80% | 51.0, 101.4, 152.6 | 51, 101, 152 | 51, 101, 153 | 51, 102, 153 | 51, 101, 152 | 51, 101, 152 | 51, 101, 153 | 50, 100, 151 |
90% | 25.5, 82.2, 139.8 | 25, 82, 139 | 26, 82, 140 | 26, 83, 140 | 25, 81, 139 | 25, 82, 139 | 25, 82, 140 | 25, 81, 139 |
- GIMP 2.6.2, PictBear 1.74, Firefox 3.0.10, Google Chrome 2.0.172.28
- I(元画像)=#FFFFFF, M(マスク)=#003F7F, M の不透明度を 10% 刻みで変化。
表の内「生」は上の関数からの出力の値そのもの。次にその値を floor(切り下げ), round(四捨五入), ceil(切り上げ) の関数を使って整数に変換したもの。最後にそれぞれのアプリケーションで実際に変換された色の値です。floor:青, round:黄, ceil:赤 としてそれぞれの関数が出力した値と一致する場合、背景を一致する関数の色で塗り分けています(但し 50% の時 round と ceil の値は一致します)。
一見して分かるのは PictBear は floor の値と全てが一致しています。が、他のアプリケーションの場合見事なまでにばらばらです。内部の計算では RGB を使ってないのでしょうか。優勝は Google Chrome です。かすりもしません。
単純に不透明度を設定して画像を重ね合わせるってだけでも、こんなに違うもんなんですね。普段から画像や web サイトをあつかってる人にとっては常識なのかも知れませんが、ちょっと驚きました。
テストに使った html
<html> <head> <style type="text/css"> body { background: #fff} div { margin: 0.5em 0; padding: 1em; text-indent: 1em; line-height: 1.5; background: #003f7f;} #s_1 {opacity: 0.1;} #s_2 {opacity: 0.2;} #s_3 {opacity: 0.3;} #s_4 {opacity: 0.4;} #s_5 {opacity: 0.5;} #s_6 {opacity: 0.6;} #s_7 {opacity: 0.7;} #s_8 {opacity: 0.8;} #s_9 {opacity: 0.9;} </style> </head> <body> <div id="s_1"></div> <div id="s_2"></div> <div id="s_3"></div> <div id="s_4"></div> <div id="s_5"></div> <div id="s_6"></div> <div id="s_7"></div> <div id="s_8"></div> <div id="s_9"></div> </body> </html>
*1:2. Layer Modesの表記を拝借