PHP Work out colour saturation - php

lets say i have the following RGB values:
R:129
G:98
B:87
Photoshop says the saturation of that colour is 33%
How would i work out that percentage using PHP and the RGB values?

See RGB to HSV in PHP
Taking only the saturation bits from that code, and converting into a percentage:
function saturation($R, $G, $B) { // 0-255
$Min = min($R, $G, $B);
$Max = max($R, $G, $B);
return $Max == 0 ? 0 : (($Max - $Min) / $Max) * 100;
}
Alternately you could use the original code in the link above - the HSV values it returns are between 0.0 and 1.0, so you just need to multiply the saturation value by 100 to get your percentage.

PEAR (PHP Extensions And Application Repository) has a nice package called Image_Color2 which allows you do to quick conversions between different color models:
include "Image/Color2.php";
$color = new Image_Color2(array(129,98,87));
$hsv = $color->convertTo('hsv');
$hsvArray = $hsv->getArray();
echo "Hue is " . $hsvArray[0] . "\n";
echo "Saturation is: " . $hsvArray[1] . "\n";
echo "Brightness is: " . $hsvArray[2];

Related

PHP longhand hex to RGB not working correctly

How do I convert longhand hex to RGB(A)?
For example, I have the following code to convert all formats of hex, colorname, etc.. to RGBA for background opacity, but for some reason longhand hex does not work, but instead takes the shorthand from the longhand (eg. background-color: #0000ff; becomes background-color: #000;).
Alot of the code below is based off of Convert hex color to RGB values in PHP but that question and similar questions are not able to resolve my issue. I spent 2 weeks looking for an answer to this, and have yet to find one, so I come here.
Color name to hex function:
function color_name_to_hex($color_name) {
$colors = array(
'aliceblue'=>'F0F8FF',
'antiquewhite'=>'FAEBD7',
'aqua'=>'00FFFF',
'aquamarine'=>'7FFFD4',
'azure'=>'F0FFFF',
'beige'=>'F5F5DC',
'bisque'=>'FFE4C4',
'black'=>'000000',
'blanchedalmond '=>'FFEBCD',
'blue'=>'0000FF',
'blueviolet'=>'8A2BE2',
'brown'=>'A52A2A',
'burlywood'=>'DEB887',
'cadetblue'=>'5F9EA0',
'chartreuse'=>'7FFF00',
'chocolate'=>'D2691E',
'coral'=>'FF7F50',
'cornflowerblue'=>'6495ED',
'cornsilk'=>'FFF8DC',
'crimson'=>'DC143C',
'cyan'=>'00FFFF',
'darkblue'=>'00008B',
'darkcyan'=>'008B8B',
'darkgoldenrod'=>'B8860B',
'darkgray'=>'A9A9A9',
'darkgreen'=>'006400',
'darkgrey'=>'A9A9A9',
'darkkhaki'=>'BDB76B',
'darkmagenta'=>'8B008B',
'darkolivegreen'=>'556B2F',
'darkorange'=>'FF8C00',
'darkorchid'=>'9932CC',
'darkred'=>'8B0000',
'darksalmon'=>'E9967A',
'darkseagreen'=>'8FBC8F',
'darkslateblue'=>'483D8B',
'darkslategray'=>'2F4F4F',
'darkslategrey'=>'2F4F4F',
'darkturquoise'=>'00CED1',
'darkviolet'=>'9400D3',
'deeppink'=>'FF1493',
'deepskyblue'=>'00BFFF',
'dimgray'=>'696969',
'dimgrey'=>'696969',
'dodgerblue'=>'1E90FF',
'firebrick'=>'B22222',
'floralwhite'=>'FFFAF0',
'forestgreen'=>'228B22',
'fuchsia'=>'FF00FF',
'gainsboro'=>'DCDCDC',
'ghostwhite'=>'F8F8FF',
'gold'=>'FFD700',
'goldenrod'=>'DAA520',
'gray'=>'808080',
'green'=>'008000',
'greenyellow'=>'ADFF2F',
'grey'=>'808080',
'honeydew'=>'F0FFF0',
'hotpink'=>'FF69B4',
'indianred'=>'CD5C5C',
'indigo'=>'4B0082',
'ivory'=>'FFFFF0',
'khaki'=>'F0E68C',
'lavender'=>'E6E6FA',
'lavenderblush'=>'FFF0F5',
'lawngreen'=>'7CFC00',
'lemonchiffon'=>'FFFACD',
'lightblue'=>'ADD8E6',
'lightcoral'=>'F08080',
'lightcyan'=>'E0FFFF',
'lightgoldenrodyellow'=>'FAFAD2',
'lightgray'=>'D3D3D3',
'lightgreen'=>'90EE90',
'lightgrey'=>'D3D3D3',
'lightpink'=>'FFB6C1',
'lightsalmon'=>'FFA07A',
'lightseagreen'=>'20B2AA',
'lightskyblue'=>'87CEFA',
'lightslategray'=>'778899',
'lightslategrey'=>'778899',
'lightsteelblue'=>'B0C4DE',
'lightyellow'=>'FFFFE0',
'lime'=>'00FF00',
'limegreen'=>'32CD32',
'linen'=>'FAF0E6',
'magenta'=>'FF00FF',
'maroon'=>'800000',
'mediumaquamarine'=>'66CDAA',
'mediumblue'=>'0000CD',
'mediumorchid'=>'BA55D3',
'mediumpurple'=>'9370D0',
'mediumseagreen'=>'3CB371',
'mediumslateblue'=>'7B68EE',
'mediumspringgreen'=>'00FA9A',
'mediumturquoise'=>'48D1CC',
'mediumvioletred'=>'C71585',
'midnightblue'=>'191970',
'mintcream'=>'F5FFFA',
'mistyrose'=>'FFE4E1',
'moccasin'=>'FFE4B5',
'navajowhite'=>'FFDEAD',
'navy'=>'000080',
'oldlace'=>'FDF5E6',
'olive'=>'808000',
'olivedrab'=>'6B8E23',
'orange'=>'FFA500',
'orangered'=>'FF4500',
'orchid'=>'DA70D6',
'palegoldenrod'=>'EEE8AA',
'palegreen'=>'98FB98',
'paleturquoise'=>'AFEEEE',
'palevioletred'=>'DB7093',
'papayawhip'=>'FFEFD5',
'peachpuff'=>'FFDAB9',
'peru'=>'CD853F',
'pink'=>'FFC0CB',
'plum'=>'DDA0DD',
'powderblue'=>'B0E0E6',
'purple'=>'800080',
'red'=>'FF0000',
'rosybrown'=>'BC8F8F',
'royalblue'=>'4169E1',
'saddlebrown'=>'8B4513',
'salmon'=>'FA8072',
'sandybrown'=>'F4A460',
'seagreen'=>'2E8B57',
'seashell'=>'FFF5EE',
'sienna'=>'A0522D',
'silver'=>'C0C0C0',
'skyblue'=>'87CEEB',
'slateblue'=>'6A5ACD',
'slategray'=>'708090',
'slategrey'=>'708090',
'snow'=>'FFFAFA',
'springgreen'=>'00FF7F',
'steelblue'=>'4682B4',
'tan'=>'D2B48C',
'teal'=>'008080',
'thistle'=>'D8BFD8',
'tomato'=>'FF6347',
'turquoise'=>'40E0D0',
'violet'=>'EE82EE',
'wheat'=>'F5DEB3',
'white'=>'FFFFFF',
'whitesmoke'=>'F5F5F5',
'yellow'=>'FFFF00',
'yellowgreen'=>'9ACD32');
$color_name = strtolower($color_name);
if (isset($colors[$color_name]))
{
return ('#' . $colors[$color_name]);
}
else
{
return ($color_name);
}
}
Get that function and don't do if already RGB:
$content__background_color = '#0000FF';
if(strpos($content__background_color, 'rgb') !== false){
$rgbarr = explode(",",$content__background_color,3);
$colorname = sprintf("#%02x%02x%02x", $rgbarr[0], $rgbarr[1], $rgbarr[2]);
} else {
$colorname = self::color_name_to_hex($content__background_color);
}
Convert to RGBA:
list($r, $g, $b) = array_map(function($c){return hexdec(str_pad($c, 2, $c));}, str_split(ltrim($colorname, '#'), strlen($colorname > 4 ? 2 : 1)));
$send_to_less_example[ 'content-opacity-level' ] = "rgba($r, $g, $b, " . '75' / 100.00 . ')';
return $send_to_less_example;
Any ideas would be greatly appreciated.
The algorithm is fine, you just have a wrong closing parenthesis at strlen($colorname > 4 ? 2 : 1) it should be strlen($colorname) > 4 ? 2 : 1 so change it to be like this and you'll have it working:
list($r, $g, $b) = array_map(
function($c) {
return hexdec(str_pad($c, 2, $c));
},
str_split(ltrim($colorname, '#'), strlen($colorname) > 4 ? 2 : 1)
);
You can see it working at sandbox.onlinephpfunctions.com.

Experiencing an issue with rounding [duplicate]

This question already has answers here:
Compare floats in php
(17 answers)
Closed 8 years ago.
Why does $x1 not equal $z2? I've tried round() as well as explicitly changing the precision to 8. $x1 should equal $z2
$x1 = 251.47267993;
$y1 = 3861.62758730;
$z1 = $x1 / $y1;
echo "{$x1} / {$y1} = {$z1}\n\n"; // ok looks good
$x2 = .06512090;
$y2 = 3861.62758730;
$z2 = $x2 * $y2;
echo "{$x2} x {$y2} = {$z2}\n\n"; // hmm no - $z2 should be === to $x1
// why do these numbers NOT match? and how can I make them match?
// set some precision somewhere?
echo $x1 . " = " . $z2 . "\n";
More info:
_251.47267993_ /3861.62758730 =.06512090
.06512090 *3861.62758730 =_251.47266394_
251.47267993 - 251.47266394 = .00001599
Note that the 2 underlined numbers should be identical we divided then
multiplied by the same number. Should be inverses ... right ... but not when we
don't have an infinite number of digits to play with - as is, they are not even
close, they differ by "0.00001599"
Don't know what your purpose is, but why are you not doing this?
$x = 251.47267993;
$y = 3861.62758730;
$z1 = $x / $y;
$z2 = $z1 * $y;
echo $x . " = " . $z2 . "\n";
Equals everytime
There is another problem: echoing float value. You have to increase your precision.
echo 1 / 3, PHP_EOL; // 0.33333333333333
ini_set('precision', 60);
echo 1 / 3, PHP_EOL; // 0.333333333333333314829616256247390992939472198486328125
Why are you trying to use value from screen but not from variable?
In PHP built-in functions are not exactly the best for that kind of calculations. For example:
echo (int) ((0.1 + 0.7) * 10);
will output 7 instead of 8.
Anyways, 251.47267993 / 3861.62758730 is not 0.06512090. Depending on the computer architecture when doing this computing it will print different results. For me it printed 0.065120904138202, which is perfectly fine because the precision is about ~14 decimal digits in a floating point.
What you can do, is use BCMath library, which is documented really good in the php.net manual. For this particular situation, you could use:
$z1 = bcdiv($x1, $y1, 200);
instead of:
$z1 = $x1 / $y1;
And see that this number is not that small what you've been thinking. For more information, check this out BCMath library.

Php function order color by lightness

Is it possible to sort colors by php on lightness .
Now i calc the differenct with this function
public function colorDiff($rgb1,$rgb2)
{
// do the math on each tuple
// could use bitwise operates more efeceintly but just do strings for now.
$red1 = hexdec(substr($rgb1,0,2));
$green1 = hexdec(substr($rgb1,2,2));
$blue1 = hexdec(substr($rgb1,4,2));
$red2 = hexdec(substr($rgb2,0,2));
$green2 = hexdec(substr($rgb2,2,2));
$blue2 = hexdec(substr($rgb2,4,2));
return abs($red1 - $red2) + abs($rgreen1 - $green2) + abs($blue2 - $blue2) ;
}
But this will not sort images on lightness.
You can get a decent value for luminance (the perceived lightness) with the following formula:
$red * .3 + $green * .59 + $blue * .11
Quoting from the linked article:
The explanation for these weights is due to the fact that for equal amounts of color the eye is most sensitive to green, then red, and then blue. This means that for equal amounts of green and blue light the green will, nevertheless, seem much brighter."
1) You need math defination of lightness. So it should function from color to integer that represent lightness
2) If you suppose (for example) than it is sum of $red+$green+$blue you can use this kind of sort
usort($colors,function ($rgb1,$rgb2){
$red1 = hexdec(substr($rgb1,0,2));
$green1 = hexdec(substr($rgb1,2,2));
$blue1 = hexdec(substr($rgb1,4,2));
$red2 = hexdec(substr($rgb2,0,2));
$green2 = hexdec(substr($rgb2,2,2));
$blue2 = hexdec(substr($rgb2,4,2));
return ($red1+$green1+$blue1) - ($reg2+$green2+$blue2);
})
You could convert your RGB color to HSL colorspace and the sort on the L component:
http://axonflux.com/handy-rgb-to-hsl-and-rgb-to-hsv-color-model-c

Hex Code Brightness PHP?

I want users on my website to be able to pick a hex colour, and I just want to display white text for dark colours and black text for light colours. Can you work out the brightness from a hex code (preferably PHP)?
$hex = "78ff2f"; //Bg color in hex, without any prefixing #!
//break up the color in its RGB components
$r = hexdec(substr($hex,0,2));
$g = hexdec(substr($hex,2,2));
$b = hexdec(substr($hex,4,2));
//do simple weighted avarage
//
//(This might be overly simplistic as different colors are perceived
// differently. That is a green of 128 might be brighter than a red of 128.
// But as long as it's just about picking a white or black text color...)
if($r + $g + $b > 382){
//bright color, use dark font
}else{
//dark color, use bright font
}
I made one similar - but based on weightings of each colour (based on the C# version of this thread)
function readableColour($bg){
$r = hexdec(substr($bg,0,2));
$g = hexdec(substr($bg,2,2));
$b = hexdec(substr($bg,4,2));
$contrast = sqrt(
$r * $r * .241 +
$g * $g * .691 +
$b * $b * .068
);
if($contrast > 130){
return '000000';
}else{
return 'FFFFFF';
}
}
echo readableColour('000000'); // Output - FFFFFF
EDIT:
Small optimisation:
Sqrt is known as an expensive math operation, which is probably neglectable in most scenarios, but anyway, it could be avoided by doing something like this.
function readableColour($bg){
$r = hexdec(substr($bg,0,2));
$g = hexdec(substr($bg,2,2));
$b = hexdec(substr($bg,4,2));
$squared_contrast = (
$r * $r * .299 +
$g * $g * .587 +
$b * $b * .114
);
if($squared_contrast > pow(130, 2)){
return '000000';
}else{
return 'FFFFFF';
}
}
echo readableColour('000000'); // Output - FFFFFF
It simply doesn't apply the sqrt, instead it powers the desired cut off contrast by two, which is a much cheaper calculation
I know this is a very old topic, but for users who came from "Google Search", this link may be what they are looking for. I've searched for something like this and I think it's a good idea to post it here:
https://github.com/mexitek/phpColors
use Mexitek\PHPColors\Color;
// Initialize my color
$myBlue = new Color("#336699");
echo $myBlue->isLight(); // false
echo $myBlue->isDark(); // true
That's it.
You need to convert the RGB values to HLS/HSL (Hue Lightness and Saturation) you can then use the Lightness to determine whether you need light text or dark text.
This page has some details on how to the conversion in PHP as well as selecting complementary colour from this.
I've only just spotted that the site is an astrology site - so apologies if anyone's offended.
If you have imagemagick extension activated, you can simply create an ImagickPixel object, call setColor with your hex value, and then call getHSL() (and get the last item of the obtained array I suppose)...
I tried a different approach to this, I used HSL (hue, saturation & lightness) lightness percentage to check if the color is dark or light. (like #chrisf said in his answer)
function:
function colorislight($hex) {
$hex = str_replace('#', '', $hex);
$r = (hexdec(substr($hex, 0, 2)) / 255);
$g = (hexdec(substr($hex, 2, 2)) / 255);
$b = (hexdec(substr($hex, 4, 2)) / 255);
$lightness = round((((max($r, $g, $b) + min($r, $g, $b)) / 2) * 100));
return ($lightness >= 50 ? true : false);
}
On the return line it checks if the lightness percentage is higher than 50% and returns true otherwise false is returned. You can easily change it to return true if the color has 30% lightness and so on. The $lightness variable can return from 0 to 100 0 being the darkest and 100 being the lightest.
how to use the function:
$color = '#111111';
if ( colorislight($color) ) {
echo 'this color is light';
}
else {
echo 'this color is dark';
}

Adjust algorithm for generating random strength values

A few days ago, you helped me to find out an algorithm for generating random strength values in an online game (thx especially John Rasch).
function getRandomStrength($quality) {
$rand = mt_rand()/mt_getrandmax();
$value = round(pow(M_E, ($rand - 1.033) / -0.45), 1);
return $value;
}
This function generates values between 1.1 and 9.9. Now I want to adjust this function so that it gives me values of the same probability but in another interval, e.g. 1.5 to 8.0. It would be perfect if you could achieve this with additional parameters.
It would be great if you could help me. Thanks in advance!
The values 1.033 and -0.45 in the original code are the magic numbers that provide the scale 1.1 - 9.9. You should get the same results if you pass in 1.1 and 9.9 as the parameters $low and $high in the following code.
function getRandomStrength($low, $high) {
// TODO: validate the input
$ln_low = log( $low, M_E );
$ln_high = log( $high, M_E );
$scale = $ln_high - $ln_low;
$rand = ( mt_rand() / mt_getrandmax() ) * $scale + $ln_low;
$value = round( pow( M_E, $rand), 1 );
return $value;
}
You should be able to pass in any range for $low and $high and get a logarithmic distribution in that range. (I'll leave range validity checking to you, but 0 < $low < $high should be true.)
This works by back calculating the linear scale necessary to generate the logarithmic scale in the provided range. If I want my log scale to be 1.1 - 9.9, for example, I take the natural log of each of those values, giving me 0.0953 - 2.2925. I then generate a random number in this linear range, and raise e to the random power to convert it back to the log range.
One way would just be to scale the values:
function getRandomStrength($quality,$min,$max) {
$rand = mt_rand()/mt_getrandmax();
$value = round(pow(M_E, ($rand - 1.033) / -0.45), 1);
$value = $value - 1.1
$value = $value * ((max-min) / 8.8)
$value = $value + $min
return $value;
}
Scale and displace the distribution in a normalized range:
D(a,b) = (D(0,1)*(b-a))+a
To get D(0,1) first from the original function D(c,d), do the inverse:
D(0,1) = (D(c,d)-c)/(d-c)
In your case, D is the original function (an exponential function), a is 1.5, b is 8.5, c is 1.1 and d is 9.9

Categories