Skip to content

Instantly share code, notes, and snippets.

@brandonheyer
Last active June 12, 2021 06:49
Show Gist options
  • Star 29 You must be signed in to star a gist
  • Fork 7 You must be signed in to fork a gist
  • Save brandonheyer/5254516 to your computer and use it in GitHub Desktop.
Save brandonheyer/5254516 to your computer and use it in GitHub Desktop.
PHP snippet to convert RGB to HSL and HSL to RGB.
<?
function rgbToHsl( $r, $g, $b ) {
$oldR = $r;
$oldG = $g;
$oldB = $b;
$r /= 255;
$g /= 255;
$b /= 255;
$max = max( $r, $g, $b );
$min = min( $r, $g, $b );
$h;
$s;
$l = ( $max + $min ) / 2;
$d = $max - $min;
if( $d == 0 ){
$h = $s = 0; // achromatic
} else {
$s = $d / ( 1 - abs( 2 * $l - 1 ) );
switch( $max ){
case $r:
$h = 60 * fmod( ( ( $g - $b ) / $d ), 6 );
if ($b > $g) {
$h += 360;
}
break;
case $g:
$h = 60 * ( ( $b - $r ) / $d + 2 );
break;
case $b:
$h = 60 * ( ( $r - $g ) / $d + 4 );
break;
}
}
return array( round( $h, 2 ), round( $s, 2 ), round( $l, 2 ) );
}
function hslToRgb( $h, $s, $l ){
$r;
$g;
$b;
$c = ( 1 - abs( 2 * $l - 1 ) ) * $s;
$x = $c * ( 1 - abs( fmod( ( $h / 60 ), 2 ) - 1 ) );
$m = $l - ( $c / 2 );
if ( $h < 60 ) {
$r = $c;
$g = $x;
$b = 0;
} else if ( $h < 120 ) {
$r = $x;
$g = $c;
$b = 0;
} else if ( $h < 180 ) {
$r = 0;
$g = $c;
$b = $x;
} else if ( $h < 240 ) {
$r = 0;
$g = $x;
$b = $c;
} else if ( $h < 300 ) {
$r = $x;
$g = 0;
$b = $c;
} else {
$r = $c;
$g = 0;
$b = $x;
}
$r = ( $r + $m ) * 255;
$g = ( $g + $m ) * 255;
$b = ( $b + $m ) * 255;
return array( floor( $r ), floor( $g ), floor( $b ) );
}
?>
@ashleedawg
Copy link

Note that with the functions above, hslToRgb expects Saturation and Lightness in the range 0 to 1, and rgbToHsl returns the values the same way. Hue is 0 to 360. R/G/B are 0-255.

The first line 3 lines within rgbToHsl ("old" values) are not needed.

Below are "compressed" versions of both. (These ones take/give S and L in the 0 to 100 range but are otherwise the same.)

function rgb2hsl($r,$g,$b){$r/=255;$g/=255;$b/=255;$max=max($r,$g,$b);$min=min($r,$g,$b);$h;$s;$l=($max+$min)/2;$d=$max-$min;if($d==0){$h=$s=0;}else{$s=$d/(1-abs(2*$l-1));switch($max){case $r:$h=60*fmod((($g-$b)/$d),6);if($b>$g){$h+=360;}break;case $g:$h=60*(($b-$r)/$d+2);break;case $b:$h=60*(($r-$g)/$d+4);break;}}return[round($h,0),round($s*100,0),round($l*100,0)];}
function hsl2rgb($h,$s,$l){$c=(1-abs(2*($l/100)-1))*$s/100;$x=$c*(1-abs(fmod(($h/60),2)-1));$m=($l/100)-($c/2);if($h<60){$r=$c;$g=$x;$b=0;}elseif($h<120){$r=$x;$g=$c;$b=0;}elseif($h<180){$r=0;$g=$c;$b=$x;}elseif($h<240){$r=0;$g=$x;$b=$c;}elseif($h<300){$r=$x;$g=0;$b=$c;}else{$r=$c;$g=0;$b=$x;}return[floor(($r+$m)*255),floor(($g+$m)*255),floor(($b+$m)*255)];} 

@OrinZ
Copy link

OrinZ commented Jun 12, 2021

Hey, I successfully implemented this code for RGB hex (wasn't too hard) and I'm happy you shared it! Wanted to add discoveries I made for that use case, which is that if you slightly alter the final return statements, re-conversion can be perfect 1-to-1.

rgbToHsl's precision on round should be upped from 2 to 3, and hslToRgb's operation changed from floor to round.

Before I changed this I'd sometimes get small differences when converting RGB -> HSL -> RGB. I'm no expert on how performant this is, but I thought it'd be helpful to know. Cheers!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment