サンプル・プログラムの実行例
サンプル・プログラム
complementaryColor.php | サンプル・プログラム本体 |
色相環と補色
色相環の180度反対側に位置する2色を補色と呼ぶ。
補色の組み合わせは互いの色を引き立て合う相乗効果がありることから、補色調和と呼ぶ。
準備
解説:補色を計算する
0300: /**
0301: * 補色を計算する
0302: * @param string $hex #xxxxxx 形式のカラーコード
0303: * @return string 補色のカラーコード/FALSE:入力値異常
0304: */
0305: function complementaryColor($hex) {
0306: $rgb = array();
0307:
0308: if (hex2rgb($hex, $rgb) == FALSE) return FALSE;
0309:
0310: $rgb_max = max($rgb['r'], $rgb['g'], $rgb['b']);
0311: $rgb_min = min($rgb['r'], $rgb['g'], $rgb['b']);
0312: $cc = $rgb_min + $rgb_max;
0313: $rgb['r'] = $cc - $rgb['r'];
0314: $rgb['g'] = $cc - $rgb['g'];
0315: $rgb['b'] = $cc - $rgb['b'];
0316:
0317: return rgb2hex($rgb);
0318: }
解説:RGB→HSL変換
0176: /**
0177: * RGB→HSL変換
0178: * @param int $r Red成分(0~255)
0179: * @param int $g Green成分(0~255)
0180: * @param int $b Blue成分(0~255)
0181: * @param array $hsl 結果を格納する配列
0182: * 'h'=>色相(0~360度
0183: * 's'=>彩度(0~100%)
0184: * 'l'=>明度(0~100%)
0185: * @return なし
0186: */
0187: function rgb2hsl($r, $g, $b, &$hsl) {
0188: $rgb_max = max($r, $g, $b);
0189: $rgb_min = min($r, $g, $b);
0190: $hsl['h'] = 0;
0191: $hsl['s'] = 0;
0192: $hsl['l'] = ($rgb_max + $rgb_min) / 2;
0193:
0194: if ($rgb_max != $rgb_min) {
0195: // H(色相)
0196: if ($rgb_max == $r) $hsl['h'] = 60 * ($g - $b) / ($rgb_max - $rgb_min);
0197: if ($rgb_max == $g) $hsl['h'] = 60 * ($b - $r) / ($rgb_max - $rgb_min) + 120;
0198: if ($rgb_max == $b) $hsl['h'] = 60 * ($r - $g) / ($rgb_max - $rgb_min) + 240;
0199: // S(彩度)
0200: if ($hsl['l'] <= 127) {
0201: $hsl['s'] = ($rgb_max - $rgb_min) / ($rgb_max + $rgb_min);
0202: } else {
0203: $hsl['s'] = ($rgb_max - $rgb_min) / (510 - $rgb_max - $rgb_min);
0204: }
0205: }
0206: if ($hsl['h'] < 0) $hsl['h'] += 360;
0207:
0208: $hsl['h'] = round($hsl['h']);
0209: $hsl['s'] = round($hsl['s'] * 100);
0210: $hsl['l'] = round(($hsl['l'] / 255) * 100);
0211: }
HSL色空間は、 H(色相;0~360度)、S(彩度;0~100%)、L(明度;0~100%)の3値でカラーを表す。RGBからHSLへの変換式は次の通りー。
解説:HSL→RGB変換
0213: /**
0214: * HSL→RGB変換
0215: * @param int $h 色相(0~360度)
0216: * @param int $s 彩度(0~100%)
0217: * @param int $l 明度(0~100%)
0218: * @param array $rgb 結果を格納する配列
0219: * 'r'=>Red成分(0~255)
0220: * 'g'=>Green成分(0~255)
0221: * 'b'=>Blue成分(0~255)
0222: */
0223: function hsl2rgb($h, $s, $l, &$rgb) {
0224: if ($h == 360) $h = 0;
0225:
0226: if ($l <= 49) {
0227: $hsl_max = 2.55 * ($l + $l * ($s / 100));
0228: $hsl_min = 2.55 * ($l - $l * ($s / 100));
0229: } else {
0230: $hsl_max = 2.55 * ($l + (100 - $l) * ($s / 100));
0231: $hsl_min = 2.55 * ($l - (100 - $l) * ($s / 100));
0232: }
0233:
0234: if ($h < 60) {
0235: $rgb['r'] = $hsl_max;
0236: $rgb['g'] = $hsl_min + ($hsl_max - $hsl_min) * ($h / 60) ;
0237: $rgb['b'] = $hsl_min;
0238: } else if ($h >= 60 && $h < 120) {
0239: $rgb['r'] = $hsl_min + ($hsl_max - $hsl_min) * ((120 - $h) / 60);
0240: $rgb['g'] = $hsl_max;
0241: $rgb['b'] = $hsl_min;
0242: } else if ($h >= 120 && $h < 180) {
0243: $rgb['r'] = $hsl_min;
0244: $rgb['g'] = $hsl_max ;
0245: $rgb['b'] = $hsl_min + ($hsl_max - $hsl_min) * (($h - 120) / 60);
0246: } else if ($h >= 180 && $h < 240) {
0247: $rgb['r'] = $hsl_min;
0248: $rgb['g'] = $hsl_min + ($hsl_max - $hsl_min) * ((240 - $h) / 60);
0249: $rgb['b'] = $hsl_max;
0250: } else if ($h >= 240 && $h < 300) {
0251: $rgb['r'] = $hsl_min + ($hsl_max - $hsl_min) * (($h - 240) / 60);
0252: $rgb['g'] = $hsl_min;
0253: $rgb['b'] = $hsl_max;
0254: } else if ($h >= 300 && $h < 360) {
0255: $rgb['r'] = $hsl_max;
0256: $rgb['g'] = $hsl_min;
0257: $rgb['b'] = $hsl_min + ($hsl_max - $hsl_min) * ((360 - $h) / 60);
0258: }
0259:
0260: $rgb['r'] = round($rgb['r']);
0261: $rgb['g'] = round($rgb['g']);
0262: $rgb['b'] = round($rgb['b']);
0263: }
解説:色相環を描く
0320: /**
0321: * 色相環を描画
0322: * @param float $r 半径
0323: * @param array $spots スポットする複数のカラーコード[省略可]
0324: ** #xxxxxx形式表記
0325: * @return array(最小年,最大年)
0326: */
0327: function drawColorCircle($r, $spots=NULL) {
0328: $rgb = array();
0329: $hsl = array();
0330:
0331: $canvas = imagecreatetruecolor($r * 2, $r * 2);
0332: $white = imagecolorallocate($canvas, 255, 255, 255);
0333: $black = imagecolorallocate($canvas, 0, 0, 0);
0334: imagecolortransparent($canvas, $black); //背景を透明に
0335:
0336: for ($h = 0; $h < 360; $h++) {
0337: hsl2rgb($h, 100, 50, $rgb);
0338: $color = imagecolorallocate($canvas, $rgb['r'], $rgb['g'], $rgb['b']);
0339: $start = $h - 90;
0340: imagefilledarc($canvas, $r, $r, $r * 2, $r * 2, $start, $start + 2, $color, 0);
0341: }
0342:
0343: //カラーコード(配列)をスポットする
0344: if ($spots != NULL) {
0345: foreach ($spots as $hex) {
0346: if (hex2rgb($hex, $rgb) == FALSE) continue;
0347: rgb2hsl($rgb['r'], $rgb['g'], $rgb['b'], $hsl);
0348: $th = deg2rad($hsl['h'] - 90);
0349: $x = ($r / 1.5) * cos($th);
0350: $y = ($r / 1.5) * sin($th);
0351: $c1 = imagecolorallocate($canvas, $rgb['r'], $rgb['g'], $rgb['b']);
0352: imagefilledellipse($canvas, $r + $x, $r + $y, $r / 2, $r / 2, $c1);
0353: imageellipse($canvas, $r + $x, $r + $y, $r / 2, $r / 2, $white);
0354: $hex = rgb2hex($rgb);
0355: $cc = complementaryColor($hex); //補色
0356: hex2rgb($cc, $rgb);
0357: $c2 = imagecolorallocate($canvas, $rgb['r'], $rgb['g'], $rgb['b']);
0358: imagettftext($canvas, $r / 16, 0, $r + $x - $r / 4 + $r / 16, $r + $y + $r / 32, $c2, FONTFILE, $hex);
0359: }
0360: }
0361:
0362: header('Content-type: image/png'); //MIMEはPNGで
0363: imagepng($canvas); //ブラウザ表示
0364: imagedestroy($canvas); //後処理
0365: }
まず、GD関数 imagecreatetruecolor を使ってキャンパスを用意。続いて、GD関数 imagecolortransparent を使って背景を透明にしておく。
色相環は、色相 $h を0度から359度まで回しながら、先ほど作ったユーザー関数 hsl2rgb によってRGBカラーを計算し、GD関数 imagefilledarc を使って円弧を塗りつぶしていく。
なお、色相環は通常、90度の位置を Red としていることから、色相 $h - 90 を角度として描画する。
次に、配列 $supots で受け取ったカラーコードにスポットを描画する。
先ほど作ったユーザー関数 rgb2hsl によって色相を算出し、これを角度として、先ほどの色相環の中のスポットする位置を三角関数によって求める。
そして、GD関数 imagefilledellipse を使って、塗りつぶした円を描いてスポットにする。また、GD関数 imagettftext を使ってカラーコードを文字として描画する。このとき、背景となるカラーコードから目立つように、文字カラーに補色を使った。
最期に、GD関数 imagepng を使って画像を出力する。
活用例
参考サイト
- 色相環:カラーコーディネート
- PHP: GD および Image 関数:PHP公式
- パワーポイントの色の使い方 ~色相環編~:岡山のパソコン教室やましん ありがとう日記
- Illustratorで補色:Illustrator入門
- マンセルは、色の基本の基本ですよ!:インテリアコーディネーター合格への道
今回はPHPを使い、あるカラーコードを指定すると、その補色を計算し、が色相環の上に位置をプロットするプログラムを作ってみることにする。