文字列をハッシュ化して、
それをRGBコードに利用しようと思います。
ハッシュ化して、色生成するので同じ文字列は同じ色になります。
文字列から自動で色付けしてくれると、
自分で配色を考える必要がありません。
名前ごとに色を用意しないと行けない場合、
名前の数が多くても使えるので便利だと思います。
文字列をハッシュ化
色に必要なのは、RGBの3要素だけあればいいので、
4バイト長のハッシュを生成してくれる
CRC32 というアルゴリズムを使うのが手軽だと思います。
Javaならもちろん標準で利用できます。
import java.util.zip.CRC32;
/**
* 指定文字列を、ハッシュ化したバイト配列を返す
*/
byte[] hashBytes(String s) {
CRC32 crc32 = new CRC32();
crc32.update(s.getBytes());
return ByteBuffer.allocate(Integer.BYTES)
.putInt((int) crc32.getValue())
.array();
}
RGB要素取り出し
ハッシュ化したバイト配列からRGBに使う要素を取り出します。
1バイトが1要素になるので、1バイト余ってしまいますが
それぞれ1バイトずつ取得します。
// ハッシュ化したバイト配列をRGBとして使う
byte[] bytes = hashBytes(s);
int bgR = bytes[0] & 0xff;
int bgG = bytes[1] & 0xff;
int bgB = bytes[2] & 0xff;
String background = String.format("%02x%02x%02x", bgR, bgG, bgB);
Javaのbyte型は、unsignedなどはなく、-128~127の範囲のため、後の計算で扱いにくくなるため、
intに代入しています。
また、byte を intにキャストする場合、
単純にキャストすると符号拡張(上位ビットが符号ビットで埋められる)が発生するため、& 0xff
というビット演算を使って、上位ビットがゼロ埋めされるようにしています。
この時点で色コードとして使うことができます。
背景/フォント色を用意する
これまでで、好きな文字列を色コードとして利用することができるようになりました。
それを背景色として使う場合、
フォント色を用意する必要があります。
単純に白や黒でもいいですが、背景色に合わせて見やすい色を選択したいので、反転色(色コードをビット反転したもの)を使うことにします。
反転色でもコントラスト差がない場合、とても見づらくなるので、その場合は、白か黒、見やすい方を採用することとします。
反転色をつくる
反転色は、ビット反転させるだけでできます。
int fcR = ~bgR & 0xff;
int fcG = ~bgG & 0xff;
int fcB = ~bgB & 0xff;
intのnot演算では、上位ビットも反転してしまうので、
必要な1バイト分にマスクして取得します。
明度差を計算する
中央値に近い色の場合は、反転色は変化が少なく見づらくなってしまいます。
また、明度が近いと明暗の差がなく、くっきりと見えなくなります。
明度差(0 - 255)が125未満だと見づらいそうです。
W3CにRGBから明度計算する式が書いてあります。
Color brightness is determined by the following formula:
((Red value X 299) + (Green value X 587) + (Blue value X 114)) / 1000
Note: This algorithm is taken from a formula for converting RGB values to YIQ values. This brightness value gives a perceived brightness for a color.
/**
* 0 - 255 の明度を返す
*/
int brightness(int r, int g, int b) {
return ((r * 299) + (g * 587) + (b * 114)) / 1000;
}
明度を求めたら、差が125未満かどうか判定し、
見づらい色であれば、白か黒にしています。
// 明るさ
int bgL = brightness(bgR, bgG, bgB);
int fcL = brightness(fcR, fcG, fcB);
// 背景とフォントの明度差が125未満なら、白または黒にする。(明度差が大きい方を採用)
if (Math.abs(bgL - fcL) < 125) {
fcR = fcG = fcB = ((0xff - bgL) > bgL) ? 0xff : 0x00;
}
String color = String.format("%02x%02x%02x", fcR, fcG, fcB);
白の明度は、255 (0xff)
黒の明度は、0 (0x00) です。
↑の三項演算は、背景色に対して、白の明度差と黒の明度差がどちらが大きいか判定しています。
(0xff - bgL) > (bgL - 0x00)
サンプル
以下は適当な単語をつかって、背景色とフォント色を生成したものです。
文字色が白か黒になっている箇所は、明度差が少ないために白黒に調整されたということです。
1件のコメント