Converting for RGB to HSL color space and back again

I’ve been searching the net for many hours, finding functions that convert from one color space to the other but I have not yet found a set op functions that can help me convert, and convert back again.

about color spaces:

I believe this is an accurate function that does RGB->HSL but it’s way above my level of programming, I haven’t been able to figure out how to revert it:


function rgb2hsl($rgb){
    $clrR = ($rgb[0]);
    $clrG = ($rgb[1]);
    $clrB = ($rgb[2]);
     
    $clrMin = min($clrR, $clrG, $clrB);
    $clrMax = max($clrR, $clrG, $clrB);
    $deltaMax = $clrMax - $clrMin;
     
    $L = ($clrMax + $clrMin) / 510;
     
    if (0 == $deltaMax){
        $H = 0;
        $S = 0;
    }
    else{
        if (0.5 > $L){
            $S = $deltaMax / ($clrMax + $clrMin);
        }
        else{
            $S = $deltaMax / (510 - $clrMax - $clrMin);
        }

        if ($clrMax == $clrR) {
            $H = ($clrG - $clrB) / (6.0 * $deltaMax);
        }
        else if ($clrMax == $clrG) {
            $H = 1/3 + ($clrB - $clrR) / (6.0 * $deltaMax);
        }
        else {
            $H = 2 / 3 + ($clrR - $clrG) / (6.0 * $deltaMax);
        }

        if (0 > $H) $H += 1;
        if (1 < $H) $H -= 1;
    }
    return array($H, $S,$L);
}

If anyone knows of a set of PHP HSL/RGB color space conversion functions, plz link me up! Or if anyone wants to have a go at reversing this rgb2hsl function, good luck! :slight_smile:

Here are the color conversion functions from color module in Drupal CMS, but I keep getting greys when I try to do RGB->HSL, it seems to never give me a non-zero saturation level:


/**
 * Convert a HSL triplet into RGB
 */
function _color_hsl2rgb($hsl) {
  $h = $hsl[0];
  $s = $hsl[1];
  $l = $hsl[2];
  $m2 = ($l <= 0.5) ? $l * ($s + 1) : $l + $s - $l*$s;
  $m1 = $l * 2 - $m2;
  return array(_color_hue2rgb($m1, $m2, $h + 0.33333),
               _color_hue2rgb($m1, $m2, $h),
               _color_hue2rgb($m1, $m2, $h - 0.33333));
}

/**
 * Helper function for _color_hsl2rgb().
 */
function _color_hue2rgb($m1, $m2, $h) {
  $h = ($h < 0) ? $h + 1 : (($h > 1) ? $h - 1 : $h);
  if ($h * 6 < 1) return $m1 + ($m2 - $m1) * $h * 6;
  if ($h * 2 < 1) return $m2;
  if ($h * 3 < 2) return $m1 + ($m2 - $m1) * (0.66666 - $h) * 6;
  return $m1;
}

/**
 * Convert an RGB triplet to HSL.
 */
function _color_rgb2hsl($rgb) {
  $r = $rgb[0];
  $g = $rgb[1];
  $b = $rgb[2];
  $min = min($r, min($g, $b));
  $max = max($r, max($g, $b));
  $delta = $max - $min;
  $l = ($min + $max) / 2;
  $s = 0;
  if ($l > 0 && $l < 1) {
    $s = $delta / ($l < 0.5 ? (2 * $l) : (2 - 2 * $l));
  }
  $h = 0;
  if ($delta > 0) {
    if ($max == $r && $max != $g) $h += ($g - $b) / $delta;
    if ($max == $g && $max != $b) $h += (2 + ($b - $r) / $delta);
    if ($max == $b && $max != $r) $h += (4 + ($r - $g) / $delta);
    $h /= 6;
  }
  return array($h, $s, $l);
}

Is this any good?

<?php
function RGB_TO_HSV ($R, $G, $B)  // RGB Values:Number 0-255
{                                 // HSV Results:Number 0-1
   $HSL = array();

   $var_R = ($R / 255);
   $var_G = ($G / 255);
   $var_B = ($B / 255);

   $var_Min = min($var_R, $var_G, $var_B);
   $var_Max = max($var_R, $var_G, $var_B);
   $del_Max = $var_Max - $var_Min;

   $V = $var_Max;

   if ($del_Max == 0)
   {
      $H = 0;
      $S = 0;
   }
   else
   {
      $S = $del_Max / $var_Max;

      $del_R = ( ( ( $max - $var_R ) / 6 ) + ( $del_Max / 2 ) ) / $del_Max;
      $del_G = ( ( ( $max - $var_G ) / 6 ) + ( $del_Max / 2 ) ) / $del_Max;
      $del_B = ( ( ( $max - $var_B ) / 6 ) + ( $del_Max / 2 ) ) / $del_Max;

      if      ($var_R == $var_Max) $H = $del_B - $del_G;
      else if ($var_G == $var_Max) $H = ( 1 / 3 ) + $del_R - $del_B;
      else if ($var_B == $var_Max) $H = ( 2 / 3 ) + $del_G - $del_R;

      if (H<0) $H++;
      if (H>1) $H--;
   }

   $HSL['H'] = $H;
   $HSL['S'] = $S;
   $HSL['V'] = $V;

   return $HSL;
}

function HSV_TO_RGB ($H, $S, $V)  // HSV Values:Number 0-1
{                                 // RGB Results:Number 0-255
    $RGB = array();

    if($S == 0)
    {
        $R = $G = $B = $V * 255;
    }
    else
    {
        $var_H = $H * 6;
        $var_i = floor( $var_H );
        $var_1 = $V * ( 1 - $S );
        $var_2 = $V * ( 1 - $S * ( $var_H - $var_i ) );
        $var_3 = $V * ( 1 - $S * (1 - ( $var_H - $var_i ) ) );

        if       ($var_i == 0) { $var_R = $V     ; $var_G = $var_3  ; $var_B = $var_1 ; }
        else if  ($var_i == 1) { $var_R = $var_2 ; $var_G = $V      ; $var_B = $var_1 ; }
        else if  ($var_i == 2) { $var_R = $var_1 ; $var_G = $V      ; $var_B = $var_3 ; }
        else if  ($var_i == 3) { $var_R = $var_1 ; $var_G = $var_2  ; $var_B = $V     ; }
        else if  ($var_i == 4) { $var_R = $var_3 ; $var_G = $var_1  ; $var_B = $V     ; }
        else                   { $var_R = $V     ; $var_G = $var_1  ; $var_B = $var_2 ; }

        $R = $var_R * 255;
        $G = $var_G * 255;
        $B = $var_B * 255;
    }

    $RGB['R'] = $R;
    $RGB['G'] = $G;
    $RGB['B'] = $B;

    return $RGB;
}
?> 

Source

dont think so, it does HSV conversion, HSV is a different color space like Hue/Saturation/Brightness, in which both saturation and brightness are very different values.

I need HSL because 100% lightness has to be white and 0% Lightness has to be black, with HSV 100% of value V can be a bright orange :slight_smile:

depiction of the difference:

Ah, I see.

Sorry, I misread your post, far to many acronyms and not enough coffee!

Good luck :smiley:

in case anyone is interested, I did manage to make it work using just the functions in Drupal. Those functions are open source so you may use them, if you comply to the GNU license.

the important thing I forgot that in 2 of the functions you have to supply a second argument that enable normalization of color values from 0-255 to fractions.


<?php
function _color_rgb2hsl($rgb) {
  $r = $rgb[0];
  $g = $rgb[1];
  $b = $rgb[2];
  $min = min($r, min($g, $b));
  $max = max($r, max($g, $b));
  $delta = $max - $min;
  $l = ($min + $max) / 2;
  $s = 0;
  if ($l > 0 && $l < 1) {
    $s = $delta / ($l < 0.5 ? (2 * $l) : (2 - 2 * $l));
  }
  $h = 0;
  if ($delta > 0) {
    if ($max == $r && $max != $g) $h += ($g - $b) / $delta;
    if ($max == $g && $max != $b) $h += (2 + ($b - $r) / $delta);
    if ($max == $b && $max != $r) $h += (4 + ($r - $g) / $delta);
    $h /= 6;
  }
  return array($h, $s, $l);
}

function _color_hsl2rgb($hsl) {
  $h = $hsl[0];
  $s = $hsl[1];
  $l = $hsl[2];
  $m2 = ($l <= 0.5) ? $l * ($s + 1) : $l + $s - $l*$s;
  $m1 = $l * 2 - $m2;
  return array(_color_hue2rgb($m1, $m2, $h + 0.33333),
               _color_hue2rgb($m1, $m2, $h),
               _color_hue2rgb($m1, $m2, $h - 0.33333));
}
/**
 * Helper function for _color_hsl2rgb().
 */
function _color_hue2rgb($m1, $m2, $h) {
  $h = ($h < 0) ? $h + 1 : (($h > 1) ? $h - 1 : $h);
  if ($h * 6 < 1) return $m1 + ($m2 - $m1) * $h * 6;
  if ($h * 2 < 1) return $m2;
  if ($h * 3 < 2) return $m1 + ($m2 - $m1) * (0.66666 - $h) * 6;
  return $m1;
}
/**
 * Convert a hex color into an RGB triplet.
 */
function _color_unpack($hex, $normalize = false) {
  if (strlen($hex) == 4) {
    $hex = $hex[1] . $hex[1] . $hex[2] . $hex[2] . $hex[3] . $hex[3];
  }
  $c = hexdec($hex);
  for ($i = 16; $i >= 0; $i -= 8) {
    $out[] = (($c >> $i) & 0xFF) / ($normalize ? 255 : 1);
  }
  return $out;
}
/**
 * Convert an RGB triplet to a hex color.
 */
function _color_pack($rgb, $normalize = false) {
  foreach ($rgb as $k => $v) {
    $out |= (($v * ($normalize ? 255 : 1)) << (16 - $k * 8));
  }
  return '#'. str_pad(dechex($out), 6, 0, STR_PAD_LEFT);
}

/* $testrgb = array(0.2,0.75,0.4); //RGB to start with
print_r($testrgb); */

  print "Hex: ";
  $testhex = "#C5003E";
  print $testhex;
  $testhex2rgb = _color_unpack($testhex,true);
  print "<br />RGB: ";
  var_dump($testhex2rgb);
  print "<br />HSL color module: ";
  $testrgb2hsl = _color_rgb2hsl($testhex2rgb); //Converteren naar HSL
  var_dump($testrgb2hsl);
  print "<br />RGB: ";
  $testhsl2rgb = _color_hsl2rgb($testrgb2hsl); // En weer terug naar RGB
  var_dump($testhsl2rgb);
  print "<br />Hex: ";
  $testrgb2hex = _color_pack($testhsl2rgb,true);
  var_dump($testrgb2hex);
  ?>

There seems to be an error, input hex is #C5003E output hex is #C5003D might have to do with float rounding errors.

BTW with some PHP 5.3 and closure love…


function _color_hsl2rgb ( $hsl )
{
    $h = $hsl[0]; $s = $hsl[1]; $l = $hsl[2];

    $m2 = ( $l <= 0.5 ) ? $l * ( $s + 1 ) : $l + $s - $l * $s;
    $m1 = $l * 2 - $m2;

    $hue = function ( $base ) use ( $m1, $m2 ) {
        $base = ( $base < 0 ) ? $base + 1 : ( ( $base > 1 ) ? $base - 1 : $base );
        if ( $base * 6 < 1 ) return $m1 + ( $m2 - $m1 ) * $base * 6;
        if ( $base * 2 < 1 ) return $m2;
        if ( $base * 3 < 2 ) return $m1 + ( $m2 - $m1 ) * ( 0.66666 - $base ) * 6;
        return $m1;
    }

    return array( $hue( $h + 0.33333 ), $hue( $h ), $hue( $h - 0.33333 ) );
}

:smiley: