Gradation

 サイトの趣旨上グラデーションという言葉をよく耳にしますが、グラデーションとは図1のようなものを言います。
Black to White
スペクトル
RGB
図 1. グラデーションの例
つまり、色でいうならば、ある規則に基づいて諧調的に変化しているもののことです。グラデーションは大概は見た目的に美しいものが多く、これらを Web ページデザインに用いることで華やかさを演出することが出来ると思います。
 DHTML においてもグラデーションを使用することは多々あり、とくにオブジェクトの透明度(α値)を設定できない InternetExplorer 以外のブラウザにおいて フェードイン、フェードアウト を実現する一番手軽な代替手段となります。また「明るさ」が変化するようなスクリプトでは必須ともいえるでしょう。
 ここでは先ず HTML の色指定で非常に重要な16進数6桁のカラー表記について考え、グラデーション配列生成のアルゴリズムについて詳しく説明したいと思います。

 HTML での色の指定方法は CSS を含めると多数ありますが、一番汎用な16進数6桁のカラー表現に注目したいと思います。16進数6桁のカラーとは #000000, #ffffff, #ff0000, #c0c0c0 などのことをいいますが、一応説明いたしますと #000000 は黒、#ffffff は白、#ff0000 は赤、#c0c0c0 は銀色を表します。# に続く6文字を色を表す識別コードなどと思っていた方はその意味を全く理解できないでしょうな。この6桁の文字は数字です(Netscape ではこれがあからさまで、例えばページの背景色 document.bgColor を参照すると、10進数に変換されたものが得られます)。それが16進数表記されているだけのことです(n進数については他サイトを参考にするか中学生の教科書に載っています)。

 ではこの6桁の数字はどういう構造になっているのでしょうか?結論から言いますと、2桁, 2桁, 2桁, の3セットで表現され、それぞれは赤、緑、青を表しています。例えば金色を表す #ffd700 は赤要素が ff(=255), 緑の要素が d7(=224), 青の要素が 00(=0) の色である、ということが出来ます。
 各要素(赤、緑、青)は 0 〜 ff までの 256 個なので全組み合わせは 256^3 で 16'777'216 の色が存在することになります。( 256^3 = 2^24 つまり 24bit で表現されている。この色数は人間が識別できる色の範囲をほぼ網羅しているため、これを True Color などと呼ぶ)。この赤緑青は光の3原色であり(TVのブラウン管をよく見よ!)、Red, Green, Blue なのでこれを RGB カラーといいます。
 光の特色の1つについてですが、絵の具などの3原色は赤黄青ですが(ちなみにプリンタはシアン、マゼンタ、イエロー+ブラックで CMYK)、例えば黄色と青色を混ぜ合わせると緑色になり、赤色、黄色、青色を全て混ぜると(ほぼ)黒色になります。一方、光の3原色はこれとは全く違い、赤と緑を混ぜると黄色になり、赤緑青を全て混ぜると白になります(舞台やコンサートのピンスポをよく観察してみよう!)。
 この「光と光を混ぜる」とはどういうことでしょうか?パソコンなどのディスプレイの色は数字で表現されていると書きましたが、この「混ぜる」という操作は数字を足し算することに値します。この足し算においての注意点は RGB の各要素を独立させて計算しなければいけないということです。
 例えば光は赤と緑を混ぜると黄色になると上記しましたが、赤は ff0000 で、これを RGB 各要素に分解し、それらを Rr,Gr,Br とすると、
Rr = 255, Gr = 0, Br = 0
緑は 00ff00 なので、同様にして
Rg = 0, Gg = 255, Bg = 0
となります。各要素を足すと
R = Rr+Rg = 255+0 = 255
G = Gr+Gg = 0+255 = 255
B = Br+Bg = 0+0 = 0
よって
R = 255, G = 255, B = 0
これを16進数6桁に戻すと ffff00。つまり、黄色となるわけです。
また、赤緑青を混ぜるとどうなるでしょうか?赤は ff0000, 緑は 00ff00, 青は 0000ff でした。合成した各要素を R, G, B とすると、
赤のR要素 Rr = 255, 緑のR要素 Rg = 0, 青のR要素 Rb = 0
よって
R = Rr+Rg+Rb = 255+0+0 = 255
同様にして
G = Gr+Gg+Gb = 0+255+0 = 255
B = Br+Bg+Bb = 0+0+255 = 255
よってこれらを16進数6桁で表すと ffffff。これは白となります。

 今まで混ぜるという言葉を使って説明しましたが、これを正式に合成という言い方をしたいと思います。光と光を合成するには RGB の各要素を独立させて足し算すれば良いということが分かりました。合成があれば、これを逆に分解することも出来ます。合成が理解できていれば分解は簡単です。
 例えば #ffffff(白)の光を #ffff00 と #0000ff、黄色と青色に分解できるといったことです。勿論、分解で得られた色を合成すると元の色が復元されます。
 ここで、#ffffff の色を3つに分解することを考えます。最初に思いつく分解の仕方はやっぱり、#ff0000, #00ff00, #0000ff でしょう。#9933cc を3つに分けるとしたら、#990000, #003300, #0000cc となると思います。光の合成に関して今まで各RGB要素を独立させて計算すると書きましたが、これはつまり3つの RGB 要素に分解して計算していたということになりますよね。

 色の合成に関することですが、注意しないといけないことがあります。例えば #ff0000(赤) と #ffff00(黄) を混ぜるとどうなるでしょうか?今まで通りにいくと R=255+255=510, G=0+255=255, B=0+0=0 となり R要素が 255 を越えてしまいます。これはまずいです。この辺は絵の具と一緒で赤に赤を混ぜても赤なように、(計算で得られる色というのは)ある一定の3原色の値を越えないようになっています。つまりディスプレイは 0 〜 ff の範囲がそれにあたり、上限の ff(=255) を越える要素は存在できません。つまり、255+255 は 255 ということになり、255 より大きい値は全て 255 として処理をしなければいけません。分解に関しても負の値は存在しません。0 より小さい値は全て 0 となります。つまり、#ff0000+#ffff00 は #ffff00:黄色 となります。

 ここまで RGBカラー について説明しましたが理解できたでしょうか?ここからは色座標というものについて書きたいと思います。例えばここにR要素しか持たない色の集合が存在するとします。R要素は 0〜255 の範囲の任意の整数値を取れるものとします。この集合を一本の軸(1次元)で表してみましょう(図2)。
Black to Red
図 2. R要素のみのカラー:1次元軸
Black to Green
図 3. G要素のみのカラー:1次元軸
Black to Blue
図 4. B要素のみのカラー:1次元軸
この図は左端のR要素が 00(=0), 右端が ff(=255) になっています。色要素はR要素のみであるので、つまり、左端の色が #000000, 右端が #ff0000 ということになります(画像をクリックすると DHTML で確認できます)。
 ここで気付いて欲しいことは、「色は座標で表せる」ということです。この軸をX軸やY軸と同じように R軸と呼び、置き換えてみましょう。図2でいうなら左端(原点)は 0 つまり、#000000 を表し、右端は 255 つまり、#ff0000 となります。そして、0 〜 255 を綺麗に保管するとそれはグラデーションになるということです。保管というのは #000000, #010000, #020000 ... #0f0000, #100000 ... #fe0000, #ff0000 というような色を連続して繋げることです。ここである関数を定義したいと思います。それは以下のような関数です。
colorR(r) 但し、0 <= r <= 255
これは r=0 のとき colorR(0) = #000000, r=16 のとき colorR(16) = #100000, r=255 のとき、colorR(255) = #ff0000 となるような関数です。
 この図2の軸(0〜255)を8分割することを考えます。分割点の座標は
0, 32, 64, 96, 128, 160, 192, 224, 255(≒256)
となります。この値をもとに色になおしてみましょう。
colorR(0)=#000000, colorR(32)=#200000, colorR(64)=#400000 ... colorR(224)=#e00000, colorR(255)=#ff0000
気付きましたか? これがグラデーションです。#000000 から始まり、等ステップ(この場合、ステップ量は32)で #ff0000 まで変化しています。もう一度言います。
色を座標でとらえ、ある色の座標から等量ずつ値を加えるとそれはグラデーションになるのです。
同じようにG軸、B軸に関しても関数を定義しておきます。
colorR( r ) ただし 0 ≦ r ≦ 255
colorG( g ) ただし 0 ≦ g ≦ 255 ・・・@
colorG( b ) ただし 0 ≦ b ≦ 255

ここで説明したものは RGB のある特定要素のみを考えた1次元のグラデーションでした。次項からは2つの要素を考えた二次元の色座標を説明していきたいと思います。

 色の RGB要素は独立していると書きました。ここで図2のR軸を横軸にとり、図3のG軸を縦軸にとりたいと思います。そして、正方形になるまで線を広げると図5、図6のような面になるはずです(画像は2分の1に縮小しています。128×128)。
X - Red Y - Green Red-Green
図 5. R面(横方向) 図 6. G面(縦方向) 図 7. R−G面
さて、いきなりですがこの2つの面を合成します。合成するというのは面と面を合わせるということですが、その際、色の合成も行います。図5.R面の右上端の色は #ff0000 で、図6.G面の右上端の色は #00ff00 です。この2点を合成すると #ffff00(=#ff0000+#00ff00) つまり、黄色が現れます。また、R面の右下端の色は #ff000000、G面の右下端の色は #000000 なので合成すると #ff0000、これは赤色です。同様にして左上端の合成色は #000000+#00ff00 で #00ff00、緑色となります。もう一つ、左下端(原点)の合成色は #000000 となります。このように面内に存在する全ての点に対して色の合成を行い、2面を合わせたものが図7になります(図7をクリックするとDHTMLで確認できます)。この図はR要素とG要素で構成される全ての色を網羅しています。ここでもう1回この図を座標で考えてみましょう。中学校で習ったように横軸をx軸、縦軸をy軸とする。原点は左下端です。なんとなく考え方が分かりましたか? この場合、横軸がR、縦軸がGになります。
 ここで座標 r,g をもとに色を返す関数を定義しましょう。以下のような関数です。
colorRG( r, g ) ただし 0 ≦ r ≦ 255, 0 ≦ g ≦ 255
例えば、r=255,g=255 のとき colorRG(255,255)=#ffff00、r=0,g=0 のとき colorRG(0,0)=#000000、r=128,g=64 では colorRG(128,64)=#804000 となるような関数です。この関数を使うと図5のR面は colorRG(r,0)、G面は colorRG(0,g) で表すことができます。また、colorRG(r,g) = colorRG(r,0)+colorRG(0,g) と表されます。例えば、colorRG(255,128)=colorRG(255,0)+colorRG(0,128)=#ff0000+#008000=#ff8000 となります。また、@式を使用すると
colorRG( r, g ) = colorR( r )+colorG( g ) ただし 0 ≦ r ≦ 255, 0 ≦ g ≦ 255
も成り立ちます。