<?php
// Copyright (c) 2023 Timon Wimmer-Cuport
// This code is licensed under MIT license (see LICENSE.txt for details)
class Colors {
private $H;
private $S;
private $L;
// H = hue, S = saturation, L = lightness
public $darkest;
public $primary;
public $primaryLight;
public $primaryDark;
public $complementary;
function __construct($h = false, $s = false, $l = false) {
if (!$h) $this->H = ($this->random() * 360);
else $this->H = $h;
if (!$s) $this->S = 40;
else $this->S = $s;
if (!$l) $this->L = 40;
else $this->L = $l;
$this->setColors();
}
function random() {
return (float)rand()/(float)getrandmax();
}
function fHSL($n = false, $h, $s, $l, $rgb = true) {
if ($n === false) return false;
$s /= 100;
$l /= 100;
$a = $s * min($l, 1 - $l);
$k = (($n + ($h / 30)) % 12);
$x = $l - $a * max(min($k - 3, 9 - $k, 1), -1);
if ($rgb) $x *= 255;
return $x;
}
function HSLtoRGB($h = false, $s = false, $l = false) {
if (!$h) return false;
if (!$s) return false;
if (!$l) return false;
return [$this->fHSL(0, $h, $s, $l), $this->fHSL(8, $h, $s, $l), $this->fHSL(4, $h, $s, $l)];
}
function RGBtoHex($r, $g, $b) {
$hex = sprintf("#%02x%02x%02x", $r, $g, $b);
return $hex;
}
function contrastYIQ($rgb, $reverse = false) {
$yiq = (($rgb[0] * 299) + ($rgb[1] * 587) + ($rgb[2] * 114)) / 1000;
if (!$reverse) return ($yiq >= 128) ? "#000000" : "#ffffff";
else return ($yiq >= 128) ? "#ffffff" : "#000000";
}
function hueToRGB($p, $q, $t) {
if ($t < 0) $t += 1;
if ($t > 1) $t -= 1;
if ($t < 1/6) return $p + ($q - $p) * 6 * $t;
if ($t < 1/2) return $q;
if ($t < 2/3) return $p + ($q - $p) * (2/3 - $t) * 6;
return $p;
}
function getComplementary($rgb) {
$r = $rgb[0];
$g = $rgb[1];
$b = $rgb[2];
$r /= 255.0;
$g /= 255.0;
$b /= 255.0;
$max = max($r, $g, $b);
$min = min($r, $g, $b);
$h = ($max + $min) / 2.0;
$s = ($max + $min) / 2.0;
$l = ($max + $min) / 2.0;
if ($max == $min) {
$h = 0;
$s = 0;
}
else {
$d = $max - $min;
$s = ($l > 0.5 ? $d / (2.0 - $max - $min) : $d / ($max + $min));
if ($max == $r && $g >= $b) $h = 1.0472 * ($g - $b) / $d;
else if ($max == $r && $g < $b) $h = 1.0472 * ($g - $b) / $d + 6.2832;
else if ($max == $g) $h = 1.0472 * ($b - $r) / $d + 2.0944;
else if ($max == $b) $h = 1.0472 * ($r - $g) / $d + 4.1888;
}
$h = $h / 6.2832 * 360.0 + 0;
$h += 180;
if ($h > 360) $h -= 360;
$h /= 360;
if ($s === 0) {
$r = $g = $b = $l;
}
else {
$q = $l < 0.5 ? $l * (1 + $s) : $l + $s - $l * $s;
$p = 2 * $l - $q;
$r = $this->hueToRGB($p, $q, $h + 1/3);
$g = $this->hueToRGB($p, $q, $h);
$b = $this->hueToRGB($p, $q, $h - 1/3);
}
$r = round($r * 255);
$b = round($b * 255);
$g = round($g * 255);
return [$r, $g, $b];
}
function setColors() {
$rgb = $this->HSLtoRGB($this->H, $this->S, $this->L);
$this->primary = $rgb;
$this->primaryText = $this->contrastYIQ($rgb);
$this->primaryLight = $this->HSLtoRGB($this->H, $this->S, 85);
$this->primaryDark = $this->HSLtoRGB($this->H, $this->S, 25);
$this->darkest = $this->HSLtoRGB($this->H, 80, 6);
$rgbComplementary = $this->HSLtoRGB($this->H, 55, 70);
$this->complementary = $this->getComplementary($rgbComplementary);
}
function getColor($rgb, $alpha = false, $toHex = false) {
if (!$rgb) return false;
$rgbStr = "rgb(";
if ($alpha) $rgbStr = "rgba(";
$rgbStr .= $rgb[0] . ", " . $rgb[1] . ", " . $rgb[2];
if ($alpha) $rgbStr .= ", " . $alpha;
$rgbStr .= ")";
return $rgbStr;
}
}
$colors = new Colors(/* $h, $s, $l */);
echo 'Darkest: ' . $colors->getColor($colors->darkest);
echo 'Primary: ' . $colors->getColor($colors->primary);
echo 'Primary Light: ' . $colors->getColor($colors->primaryLight);
echo 'Primary Dark: ' . $colors->getColor($colors->primaryDark);
echo 'Secondary (Complementary): ' . $colors->getColor($colors->complementary);
Darkest: rgb(3.06, 27.54, 15.3)
Primary: rgb(61.2, 142.8, 102)
Check for inverse text color...
Primary Light: rgb(201.45, 232.05, 216.75)
Primary Dark: rgb(38.25, 89.25, 63.75)
Secondary (Complementary): rgb(221, 136, 179)