Skip to content
Advertisement

Why doesn’t this Javascript RGB to HSL code work?

I found this RGB to HSL script over at http://www.mjijackson.com/2008/02/rgb-to-hsl-and-rgb-to-hsv-color-model-conversion-algorithms-in-javascript. I can’t find any other small decent ones. The issue is that this code doesn’t even really work. Would anybody know why? (I don’t know a bit of color math, but maybe it’s returning the complementary?)

function rgbToHsl(r, g, b){
    r /= 255, g /= 255, b /= 255;
    var max = Math.max(r, g, b), min = Math.min(r, g, b);
    var h, s, l = (max + min) / 2;

    if(max == min){
        h = s = 0; // achromatic
    }else{
        var d = max - min;
        s = l > 0.5 ? d / (2 - max - min) : d / (max + min);
        switch(max){
            case r: h = (g - b) / d + (g < b ? 6 : 0); break;
            case g: h = (b - r) / d + 2; break;
            case b: h = (r - g) / d + 4; break;
        }
        h /= 6;
    }

    return [h, s, l];
}

Edit: when I run rgbToHsl(126,210,22) it’s giving me [ .24, .81, .45 ], which is the HSL for an orange color.

Advertisement

Answer

The resulting HSV array has to be interpreted as three fractions. For some programs, if you want to express HSV as integers, you multiply the “H” value by 360 and the “S” and “V” values by 100. The HSV value you quote for your green shade RGB[126, 210, 22] is HSV [87, 81, 45] in integers. You could change the function to return such integers if you want to:

function rgbToHsl(r, g, b){
    r /= 255, g /= 255, b /= 255;
    var max = Math.max(r, g, b), min = Math.min(r, g, b);
    var h, s, l = (max + min) / 2;

    if(max == min){
        h = s = 0; // achromatic
    }else{
        var d = max - min;
        s = l > 0.5 ? d / (2 - max - min) : d / (max + min);
        switch(max){
            case r: h = (g - b) / d + (g < b ? 6 : 0); break;
            case g: h = (b - r) / d + 2; break;
            case b: h = (r - g) / d + 4; break;
        }
        h /= 6;
    }

    return [Math.floor(h * 360), Math.floor(s * 100), Math.floor(l * 100)];
}

[edit] that said, it’s still giving me something with a brightness (“L” or “V”) that’s considerably too dark; Gimp says that the HSV value should be [90, 80, 82], or in fractional terms [.20, .80, .82].

[another edit] well one problem could be that HSL and HSV are different schemes … still looking around.

OK in case anybody wants RGB to HSV (like you’d see in Gimp for example) here’s a version of that:

function rgbToHsv(r, g, b) {
    var
        min = Math.min(r, g, b),
        max = Math.max(r, g, b),
        delta = max - min,
        h, s, v = max;

    v = Math.floor(max / 255 * 100);
    if ( max != 0 )
        s = Math.floor(delta / max * 100);
    else {
        // black
        return [0, 0, 0];
    }

    if( r == max )
        h = ( g - b ) / delta;         // between yellow & magenta
    else if( g == max )
        h = 2 + ( b - r ) / delta;     // between cyan & yellow
    else
        h = 4 + ( r - g ) / delta;     // between magenta & cyan

    h = Math.floor(h * 60);            // degrees
    if( h < 0 ) h += 360;

    return [h, s, v];
}

edit note that a couple comments suggest that Math.round() might give better answers than Math.floor(), if anybody wants to experiment.

User contributions licensed under: CC BY-SA
5 People found this is helpful
Advertisement