PHP function to convert HSL to RGB or Hex

人走茶凉 提交于 2019-12-06 01:51:48
enhzflep

Taking the code from one of the answers in the link of Jim's comment (PHP HSV to RGB formula comprehension), we can compute it as follows:

<?php    
    $hue = 209;
    $sat = 75;
    $lum = 60;

    $hue /= 360;
    $sat /= 100;
    $lum /= 100;

    $result = ColorHSLToRGB($hue, $sat, $lum);
    var_dump($result); echo '<br>';
    printf("rgb = %d,%d,%d<br>", $result['r'], $result['g'], $result['b']);




function ColorHSLToRGB($h, $s, $l){

        $r = $l;
        $g = $l;
        $b = $l;
        $v = ($l <= 0.5) ? ($l * (1.0 + $s)) : ($l + $s - $l * $s);
        if ($v > 0){
              $m;
              $sv;
              $sextant;
              $fract;
              $vsf;
              $mid1;
              $mid2;

              $m = $l + $l - $v;
              $sv = ($v - $m ) / $v;
              $h *= 6.0;
              $sextant = floor($h);
              $fract = $h - $sextant;
              $vsf = $v * $sv * $fract;
              $mid1 = $m + $vsf;
              $mid2 = $v - $vsf;

              switch ($sextant)
              {
                    case 0:
                          $r = $v;
                          $g = $mid1;
                          $b = $m;
                          break;
                    case 1:
                          $r = $mid2;
                          $g = $v;
                          $b = $m;
                          break;
                    case 2:
                          $r = $m;
                          $g = $v;
                          $b = $mid1;
                          break;
                    case 3:
                          $r = $m;
                          $g = $mid2;
                          $b = $v;
                          break;
                    case 4:
                          $r = $mid1;
                          $g = $m;
                          $b = $v;
                          break;
                    case 5:
                          $r = $v;
                          $g = $m;
                          $b = $mid2;
                          break;
              }
        }
        return array('r' => $r * 255.0, 'g' => $g * 255.0, 'b' => $b * 255.0);
}
?>

Output:

array(3) { ["r"]=> float(76.5) ["g"]=> float(155.55) ["b"]=> float(229.5) } 
rgb = 76,155,229

Putting this together (which helped me produce this chart)

/**
 * convert a HSL colorscheme to either Hexadecimal (default) or RGB.
 * 
 * We want a method where we can programmatically generate a series of colors
 * between two values (eg. red to green) which is easy to do with HSL because
 * you just change the hue. (0 = red, 120 = green).  You can use this function
 * to convert those hsl color values to either the rgb or hexadecimal color scheme.
 * e.g. You have
 *   hsl(50, 100%, 50%)
 * To convert,
 * $hex = convertHSL(50,100,50);  // returns #ffd500
 * or 
 * $rgb = convertHSL(50,100,50, false);  // returns rgb(255, 213, 0)
 *  
 * see https://coderwall.com/p/dvsxwg/smoothly-transition-from-green-to-red
 * @param int $h the hue
 * @param int $s the saturation
 * @param int $l the luminance
 * @param bool $toHex whether you want hexadecimal equivalent or rgb equivalent
 * @return string usable in HTML or CSS
 */

function convertHSL($h, $s, $l, $toHex=true){
    $h /= 360;
    $s /=100;
    $l /=100;

    $r = $l;
    $g = $l;
    $b = $l;
    $v = ($l <= 0.5) ? ($l * (1.0 + $s)) : ($l + $s - $l * $s);
    if ($v > 0){
          $m;
          $sv;
          $sextant;
          $fract;
          $vsf;
          $mid1;
          $mid2;

          $m = $l + $l - $v;
          $sv = ($v - $m ) / $v;
          $h *= 6.0;
          $sextant = floor($h);
          $fract = $h - $sextant;
          $vsf = $v * $sv * $fract;
          $mid1 = $m + $vsf;
          $mid2 = $v - $vsf;

          switch ($sextant)
          {
                case 0:
                      $r = $v;
                      $g = $mid1;
                      $b = $m;
                      break;
                case 1:
                      $r = $mid2;
                      $g = $v;
                      $b = $m;
                      break;
                case 2:
                      $r = $m;
                      $g = $v;
                      $b = $mid1;
                      break;
                case 3:
                      $r = $m;
                      $g = $mid2;
                      $b = $v;
                      break;
                case 4:
                      $r = $mid1;
                      $g = $m;
                      $b = $v;
                      break;
                case 5:
                      $r = $v;
                      $g = $m;
                      $b = $mid2;
                      break;
          }
    }
    $r = round($r * 255, 0);
    $g = round($g * 255, 0);
    $b = round($b * 255, 0);

    if ($toHex) {
        $r = ($r < 15)? '0' . dechex($r) : dechex($r);
        $g = ($g < 15)? '0' . dechex($g) : dechex($g);
        $b = ($b < 15)? '0' . dechex($b) : dechex($b);
        return "#$r$g$b";
    } else {
        return "rgb($r, $g, $b)";    
    }

The PEAR package Image_Color2 has methods to transform between color models - see convertTo.

Swiss Mister

My tests of all other implementations showed only weird and possibly unplausible results. Here is a PHP implementation of @Mohsen's code from https://stackoverflow.com/a/9493060/1598477. Plus a test to show the full beauty...

Sorry to cross-post this. But I really haven't seen any other implementation that gives the quality I needed.

/**
 * Converts an HSL color value to RGB. Conversion formula
 * adapted from http://en.wikipedia.org/wiki/HSL_color_space.
 * Assumes h, s, and l are contained in the set [0, 1] and
 * returns r, g, and b in the set [0, 255].
 *
 * @param   {number}  h       The hue
 * @param   {number}  s       The saturation
 * @param   {number}  l       The lightness
 * @return  {Array}           The RGB representation
 */

function hue2rgb($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 hslToRgb($h, $s, $l){
    if($s == 0){
        $r = $l;
        $g = $l;
        $b = $l; // achromatic
    }else{
        $q = $l < 0.5 ? $l * (1 + $s) : $l + $s - $l * $s;
        $p = 2 * $l - $q;
        $r = hue2rgb($p, $q, $h + 1/3);
        $g = hue2rgb($p, $q, $h);
        $b = hue2rgb($p, $q, $h - 1/3);
    }

    return array(round($r * 255), round($g * 255), round($b * 255));
}

/* Uncomment to test * /
for ($i=0;$i<360;$i++) {
  $rgb=hslToRgb($i/360, 1, .9);
  echo '<div style="background-color:rgb(' .$rgb[0] . ', ' . $rgb[1] . ', ' . $rgb[2] . ');padding:2px;"></div>';
}
/* End Test */

Here is my solution

HSV value restrictions: $H [0-359], $S [0-100], $V [0-100]

function hsv_to_rgb($iH, $iS, $iV) {

    if($iH < 0)   $iH = 0;
    if($iH > 360) $iH = 360;
    if($iS < 0)   $iS = 0;
    if($iS > 100) $iS = 100;
    if($iV < 0)   $iV = 0;
    if($iV > 100) $iV = 100;
    $dS = $iS/100.0;
    $dV = $iV/100.0;
    $dC = $dV*$dS;
    $dH = $iH/60.0;
    $dT = $dH;
    while($dT >= 2.0) $dT -= 2.0; // php modulus does not work with float
    $dX = $dC*(1-abs($dT-1));     // as used in the Wikipedia link
    switch($dH) {
      case($dH >= 0.0 && $dH < 1.0):
        $dR = $dC; $dG = $dX; $dB = 0.0; break;
      case($dH >= 1.0 && $dH < 2.0):
        $dR = $dX; $dG = $dC; $dB = 0.0; break;
      case($dH >= 2.0 && $dH < 3.0):
        $dR = 0.0; $dG = $dC; $dB = $dX; break;
      case($dH >= 3.0 && $dH < 4.0):
        $dR = 0.0; $dG = $dX; $dB = $dC; break;
      case($dH >= 4.0 && $dH < 5.0):
        $dR = $dX; $dG = 0.0; $dB = $dC; break;
      case($dH >= 5.0 && $dH < 6.0):
        $dR = $dC; $dG = 0.0; $dB = $dX; break;
      default:
        $dR = 0.0; $dG = 0.0; $dB = 0.0; break;
    }
    $dM  = $dV - $dC;
    $dR += $dM; $dG += $dM; $dB += $dM;
    $dR *= 255; $dG *= 255; $dB *= 255;
    return array(round($dR), round($dG), round($dB));
  }

If you have decimal RGB values (enhzflep showed how to get them), you can easily get the #ab01cd hex web string:

$rgb['r'] = ($t = round($rgb['r'] * 255, 0)) < 15 ? '0'.dechex($t) : dechex($t);
$rgb['g'] = ($t = round($rgb['g'] * 255, 0)) < 15 ? '0'.dechex($t) : dechex($t);
$rgb['b'] = ($t = round($rgb['b'] * 255, 0)) < 15 ? '0'.dechex($t) : dechex($t);
$hexweb = "#".$rgb['r'].$rgb['g'].$rgb['b'];
标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!