Reputation: 3073
I am working on a dynamic store project and I use a loop to print all color options for a product as color boxes, however I really need to add a "border" to these colors which are light. I tried something like the following but It is very limited, it is actually limited to white color only, it won't catch something like #ddd, #eea... etc
Here is my loop:
foreach($colors as $color) {
$color = trim($color);
if (!empty($color)) {
if (in_array($color, array('white','White','#fff','#FFF','#FFFFFF','#ffffff'))) {
$bordercolor = '#bbb';
} else {
$bordercolor = $color;
}
}
}
Colors is an array from backend like: White, #000, #cc0000, etc. It is not practical to add all exceptions in the if/else condition too, any quick idea?
Upvotes: 27
Views: 15287
Reputation: 411
Here’s a short derived version from @Luca C.’s answer for colors in HEX format (e.g. #FFFFFF or #FFF)
<?php
function isDark($hex){
$average = 381; // range 1 - 765
if(strlen(trim($hex)) == 4){
$hex = "#" . substr($hex,1,1) . substr($hex,1,1) . substr($hex,2,1) . substr($hex,2,1) . substr($hex,3,1) . substr($hex,3,1);
}
return ((hexdec(substr($hex,1,2))+hexdec(substr($hex,3,2))+hexdec(substr($hex,5,2)) < $average) ? true : false);
}
var_dump( isDark("#000000") ); // bool(true)
?>
Upvotes: 2
Reputation: 12564
Short way if you have RGB color as hexadecimal string:
$hexRGB = "4488BB";
if(hexdec(substr($hexRGB,0,2))+hexdec(substr($hexRGB,2,2))+hexdec(substr($hexRGB,4,2))> 381){
//bright color
}else{
//dark color
}
Note: The thereshold 381 is the sum of the values at average level. If you want the thereshold to be lighter or darker, upper or lower 381 in the range 1 - 765.
Upvotes: 7
Reputation: 145
There also is a simpler way with even less code:
<?php
//Functions
function getRGB($colorCode) {
//Turn html color code into RGB
$var_R = substr($colorCode, 0, 2);
$var_G = substr($colorCode, 2, 2);
$var_B = substr($colorCode, 4, 2);
//Get Hex values
$val_R = hexdec($var_R);
$val_G = hexdec($var_G);
$val_B = hexdec($var_B);
//Red is seen as light too, gets fixed with this
$remRed = hexdec('99');
if ($val_R > $remRed) {
$RGB = $val_G.' '.$val_B;
} else {
$RGB = $val_R.' '.$val_G.' '.$val_B;
}
return $RGB;
}
function getHSL($R = 255, $G = 255, $B = 255) {
$hsl = (max($R, $G, $B) + min($R, $G, $B)) / 510.0;
return $hsl;
}
?>
Now the calling:
$color = 0000FF; //Blue
$RGBcode = getRGB($color); //Returns 0 0 255
$RGBcode = str_replace(' ', ', ', $RGBcode); //Replaces an empty space with a ,
$val_HSL = getHSL($RGBcode); //Returns value from 0.5 to 1
if ($val_HSL >= 0.8) {
//Reject color
} else {
//Accept Color
$color = '#'.$color; //Sets it to html: #0000FF
}
Upvotes: 2
Reputation: 10047
What I'd do in this situation is detect the lightness of the color using HSL, and compare that against a certain percentage. For example, the lightness attribute in the HSL algorithm takes the chroma (M - m where M is the largest RGB value and m is the smallest RGB value) and divides that by 2.
function lightness($R = 255, $G = 255, $B = 255) {
return (max($R, $G, $B) + min($R, $G, $B)) / 510.0; // HSL algorithm
}
The above function would return a percentage of how light the color you've selected is (simple hex -> rgb conversions are required for this also, but that should be pretty easy). The reason I divided by 510 instead of 2 is because in order to get the percentage after dividing by 2, you divide by 255. To make it faster you can simply say: (x / 2) / 255 = x / 510
. Then I'd compare the value returned by the above function to, say, 80%.
$r = hexdec($hex[0].$hex[1]);
$g = hexdec($hex[2].$hex[3]);
$b = hexdec($hex[4].$hex[5]);
if(lightness($r, $g, $b) >= .8) {
// add border
} else {
// no border
}
Upvotes: 14
Reputation: 48284
In addition to other formulas given by other answers, you may want to consider Luma.
function luma($r, $g, $b)
{
return (0.2126 * $r + 0.7152 * $g + 0.0722 * $b) / 255;
}
$l = luma(0, 15, 255);
Values closer to 0 will be darker. Values closer to 1 will be lighter.
Upvotes: 10
Reputation: 16915
Transform HTML colour to RGB, then to Hue-Saturation-Lightnes (HSV)
<?php
function HTMLToRGB($htmlCode)
{
if($htmlCode[0] == '#')
$htmlCode = substr($htmlCode, 1);
if (strlen($htmlCode) == 3)
{
$htmlCode = $htmlCode[0] . $htmlCode[0] . $htmlCode[1] . $htmlCode[1] . $htmlCode[2] . $htmlCode[2];
}
$r = hexdec($htmlCode[0] . $htmlCode[1]);
$g = hexdec($htmlCode[2] . $htmlCode[3]);
$b = hexdec($htmlCode[4] . $htmlCode[5]);
return $b + ($g << 0x8) + ($r << 0x10);
}
function RGBToHSL($RGB) {
$r = 0xFF & ($RGB >> 0x10);
$g = 0xFF & ($RGB >> 0x8);
$b = 0xFF & $RGB;
$r = ((float)$r) / 255.0;
$g = ((float)$g) / 255.0;
$b = ((float)$b) / 255.0;
$maxC = max($r, $g, $b);
$minC = min($r, $g, $b);
$l = ($maxC + $minC) / 2.0;
if($maxC == $minC)
{
$s = 0;
$h = 0;
}
else
{
if($l < .5)
{
$s = ($maxC - $minC) / ($maxC + $minC);
}
else
{
$s = ($maxC - $minC) / (2.0 - $maxC - $minC);
}
if($r == $maxC)
$h = ($g - $b) / ($maxC - $minC);
if($g == $maxC)
$h = 2.0 + ($b - $r) / ($maxC - $minC);
if($b == $maxC)
$h = 4.0 + ($r - $g) / ($maxC - $minC);
$h = $h / 6.0;
}
$h = (int)round(255.0 * $h);
$s = (int)round(255.0 * $s);
$l = (int)round(255.0 * $l);
return (object) Array('hue' => $h, 'saturation' => $s, 'lightness' => $l);
}
$colour = '#F12346';
$rgb = HTMLToRGB($colour);
$hsl = RGBToHSL($rgb);
var_dump($hsl);
Usage:
$colour = '#F12346';
$rgb = HTMLToRGB($colour);
$hsl = RGBToHSL($rgb);
if($hsl->lightness > 200) {
// this is light colour!
}
Source:
Demo:
Upvotes: 36