0

Feel like I'm missing something really simple here, but I can't get the formula posted from an answer from HSL to RGB color conversion to work. The function in question is:

function hslToRgb(h, s, l){
    var r, g, b;

    if(s == 0){
        r = g = b = l; // achromatic
    }else{
        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;
        }

        var q = l < 0.5 ? l * (1 + s) : l + s - l * s;
        var p = 2 * l - q;
        r = hue2rgb(p, q, h + 1/3);
        g = hue2rgb(p, q, h);
        b = hue2rgb(p, q, h - 1/3);
    }

    return [Math.round(r * 255), Math.round(g * 255), Math.round(b * 255)];
}

My issue, I believe, is in regard to what to enter as my 'h' parameter. Typically, when using HSL in CSS or Photoshop, the hue value is a number between 0 and 360, but this function calls for a value in between 0 and 1. Can someone explain to me how I would, for example, convert a hue value of 240 to the equivalent value between 0 and 1, so I can plug it into this formula? I tried dividing 240 by 360, but this did not work.

Community
  • 1
  • 1
Joe
  • 1,117
  • 1
  • 8
  • 13
  • What exactly about it didn't work? The only way to map [0 - 360] -> [0 - 1] is to divide by 360. See [similar question](http://stackoverflow.com/questions/15917495/incorrect-hue-returned-by-gethue-function) – Keenan Lidral-Porter Dec 26 '14 at 07:02
  • The resulting values for r, g, and b are not correct. When I plug the same hsl values into the color picker in Photoshop, the resulting rgb values are much different than what this function is returning. – Joe Dec 26 '14 at 15:37
  • I get the correct conversion when I divide hue by 360. I'm just taking a color from http://hslpicker.com/ and inputting the result of the conversion at http://www.rgbtool.com/ Are your s & l values also in the range of [0, 1]? – Keenan Lidral-Porter Dec 26 '14 at 15:48
  • Yes. For example, I'm just doing `console.log(hslToRgb(.27777777777778, .81, .45));` for a hue of 100. In both Photoshop and rgbtool.com, I get a resulting r53, g115, b22, but the function outputs r84, g208, b22. Weird. All I did was copy and paste the function, so I really don't see what could be going on. – Joe Dec 26 '14 at 16:26
  • I'm also getting unexpected jumps in the RGB from small changes in H. – Michael Douma Dec 14 '21 at 20:47

1 Answers1

4

Looks like the original algorithm is wrong. According to wikipedia, you can get the chroma & lightness adjustments independent of hue (hence the similar b value), but anything else requires a little more math—specifically modulo. It doesn't look like that algorithm handles that particular conversion well, especially considering it expects hue to be in the range [0, 1]. Try this algorithm instead:

// expected hue range: [0, 360)
// expected saturation range: [0, 1]
// expected lightness range: [0, 1]
var hslToRgb = function(hue, saturation, lightness){
  // based on algorithm from http://en.wikipedia.org/wiki/HSL_and_HSV#Converting_to_RGB
  if( hue == undefined ){
    return [0, 0, 0];
  }

  var chroma = (1 - Math.abs((2 * lightness) - 1)) * saturation;
  var huePrime = hue / 60;
  var secondComponent = chroma * (1 - Math.abs((huePrime % 2) - 1));

  huePrime = Math.floor(huePrime);
  var red;
  var green;
  var blue;

  if( huePrime === 0 ){
    red = chroma;
    green = secondComponent;
    blue = 0;
  }else if( huePrime === 1 ){
    red = secondComponent;
    green = chroma;
    blue = 0;
  }else if( huePrime === 2 ){
    red = 0;
    green = chroma;
    blue = secondComponent;
  }else if( huePrime === 3 ){
    red = 0;
    green = secondComponent;
    blue = chroma;
  }else if( huePrime === 4 ){
    red = secondComponent;
    green = 0;
    blue = chroma;    
  }else if( huePrime === 5 ){
    red = chroma;
    green = 0;
    blue = secondComponent;
  }

  var lightnessAdjustment = lightness - (chroma / 2);
  red += lightnessAdjustment;
  green += lightnessAdjustment;
  blue += lightnessAdjustment;

  return [Math.round(red * 255), Math.round(green * 255), Math.round(blue * 255)];

};

It may fail on a few edge cases, but those should be easy fixes

  • 1
    That's awesome man. Really appreciate that you took the time. I did try a few different settings, and most of them worked. But I did find one that did not (hslToRgb(320, 0.44, 0.54)), which seems to return 3 numbers that are right, but the green and blue values are switched. Not sure if this is what you meant by a few of the edge cases that could fail. Regardless, I really appreciate it. – Joe Dec 27 '14 at 05:49