RGB値(255,255,255 など)からHTMLカラーコード(#FFFFFFなど)に変換する。
ついでにできるだけ最速の方法を模索してみたいと思います。
カラーコードは6桁の16進数です。
Red,Green,Blueの全ての値が255の場合、それらの値を色で表すと
#FFFFFFとなります。
これを2進数で表すと
111111111111111111111111となります。
つまり、10進数の255は16進数では"FF"、2進数では"11111111"となります。
Red,Green,Blueは最大255、つまり8ビットで表されることが理解できたところで以下の結果を見て下さい。
var digit = 255; alert(digit.toString(16)); //FF alert(digit.toString(2)); //11111111 var digit = 255 << 8; alert(digit); //65280 alert(digit.toString(16)); //FF00 alert(digit.toString(2)); //1111111100000000 var digit = 65280 << 8; alert(digit); //16711680 alert(digit.toString(16)); //FF0000 alert(digit.toString(2)); //111111110000000000000000以上のことから
var red = 255, green = 255, blue = 255; alert(((red << 16) + (green << 8) + blue).toString(16)); //FFFFFFとなることが理解できると思います。
つまり、
FFFFFF == FF0000 + FF00 + FFとなるような計算を行いたいわけですね。
ビットシフトを使って処理する
上の結果から想像できると思いますが、Greenの値は8桁ビットシフトします。Redの値は16桁ビットシフトします。そして全ての値を足した後、16進数に変換します。var x = 255; alert((x).toString(2)); //11111111 alert((x << 8).toString(2)); //1111111100000000 alert((x << 16).toString(2)); //111111110000000000000000 alert((16777216).toString(16)); //1000000
上記を踏まえた処理が以下になります。
function toColorCode(r, g, b){ return '#' + (((r << 8) + g << 8) + b).toString(16); } alert(toColorCode(0,0,128)); //#80これでは上の結果ように桁が合わない場合が出てしまいます。
この問題を解消するために2進数で表すところの『1000000000000000000000000』、10進数で『16777216』、16進数で『1000000』を足すことによって一時的に桁を合わせ、最後に先頭の"1"を取り除く、という処理を行います。
//713ms function toColorCode_1a(r,g,b){ return (((256 + r << 8) + g << 8) + b).toString(16).replace(/^1/,'#'); } //463ms function toColorCode_1b(r,g,b){ return '#' + (((256 + r << 8) + g << 8) + b).toString(16).substr(1, 6); }上はreplaceを使い先頭の"1"を"#"に置き換えています。下はsubstrで"1"より右側の文字列を取得しています。
コメントの計測タイムは以下の処理のとおり、loopで回して処理に掛った時間です。
var x = ''; console.time('test'); for (var i = 0; i < 1000 * 1000; i++) { x = toColorCode(255, 255, 255); } console.timeEnd('test'); console.log(x);
素直に処理してみる
ビットシフトを使わず、素直に数値を使って処理してみます。考え方は上と同じです。
256を掛けてやるとビットシフトと同じ効果になります。
//713ms function toColorCode_2a(r, g, b){ return (((256 + r) * 256 + g) * 256 + b).toString(16).replace(/^1/, '#'); } //478ms function toColorCode_2b(r, g, b){ return '#' + (((256 + r) * 256 + g) * 256 + b).toString(16).substr(1, 6); }以外にもビットシフトを使った方が処理が速いですね。
他の方法を試す
無駄と分かっていても一応いろいろと試してみたくなる衝動にまかせて書いてみる。//firefox3.5 //14443ms function toColorCode_3a(r, g, b){ return '#' + [r, g, b].map(function(cp){ return (cp > 16 ? '' : '0') + cp.toString(16); }).join(''); } //use jQuery //5380ms function toColorCode_3b(r, g, b){ return '#' + $.map([r, g, b], function(cp){ return (cp > 16 ? '' : '0') + cp.toString(16); }).join(''); } //2250ms function toColorCode_3c(r, g, b){ return (function(rgb){ var ret = '#'; for (var i = 0, len = rgb.length; i < len; i++) ret += (rgb[i] > 16 ? '' : '0') + rgb[i].toString(16); return ret; })([r, g, b]); } //623ms function toColorCode_3d(r, g, b){ return '#' + (r > 16 ? '' : '0') + r.toString(16) + (g > 16 ? '' : '0') + g.toString(16) + (b > 16 ? '' : '0') + b.toString(16); }どれも上の処理に比べると恐ろしく遅い。
最速はsliceを使った以下になりましたとさ。
function toColorCode(r,g,b){ return '#' + (((256 + r << 8) + g << 8) + b).toString(16).slice(1); }
0 Comments:
コメントを投稿