Question

I'm trying to get a HSL color value from my Database. Currently there is only a RGB value stored. Let's assume I got separate columns for rgb: red green blue with a number value 0-255 in them each.

Target result would be hue saturation lightness in the resultset, calculated from the rgb values. I've seen a lot of calculations but none of them seem easy enough to do in a query? Or I'm not deeply enough into SQL in general to know how to port something like a switch statement to SQL.

The best example for converting I've found is here: How do you get the hue of a #xxxxxx colour?

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];
}

But I'm completely stumped for an answer on how to do something like this calculation in SQL.

After it not working quite correctly (the code sample above is incorrect from what I can see on wikipedia for conversion of the hue, as well as I needed the hue in full degrees 0-360 rather than between 0 and 1) I've started with the solution from Arth and got to this, I've decided to to a /255 on r,g,b beforehand because that is just easier to follow through from the above code sample:

CASE 
  WHEN r>=g AND g>=b  THEN ((g-b)/(r-b))*60
  WHEN g>r AND r>=b THEN (2-(r-b)/(g-b))*60
  WHEN g>=b AND b>r THEN (2+(b-r)/(g-r))*60
  WHEN b>g AND g>r THEN (4-(g-r)/(b-r))*60
  WHEN b>r AND r>=g THEN (4+(r-g)/(b-g))*60
  WHEN r>=b AND b>g THEN (6-(b-g)/(r-g))*60
END h,
CASE 
  WHEN r=g  AND g=b  THEN 0
  WHEN r>=g AND g>=b AND  (r-b)>0.5 THEN (r-b)/(2-r-b)          
  WHEN r>=g AND g>=b THEN (r-b)/(r+b)
  WHEN r>=g AND b>g  AND  (r-g)>0.5 THEN (r-g)/(2-r-g)
  WHEN r>=g AND b>g  THEN (r-g)/(r+g) 
  WHEN g>=r AND r>=b AND  (g-b)>0.5 THEN (g-b)/(2-g-b) 
  WHEN g>=r AND r>=b THEN (g-b)/(g+b)
  WHEN g>=r AND b>r  AND  (g-r)>0.5 THEN (g-r)/(2-g-r) 
  WHEN g>=r AND b>r  THEN (g-r)/(g+r)
  WHEN b>=r AND r>=g AND  (b-g)>0.5 THEN (b-g)/(2-b-g) 
  WHEN b>=r AND r>=g THEN (b-g)/(b+g)
  WHEN b>=r AND g>r  AND  (b-r)>0.5 THEN (b-r)/(2-b-r) 
  WHEN b>=r AND g>r  THEN (b-r)/(b+r)
END s,
CASE 
  WHEN r=g  AND g=b  THEN r
  WHEN r>=g AND g>=b THEN (r+b)/2
  WHEN r>=g AND b>g  THEN (r+g)/2
  WHEN g>=r AND r>=b THEN (g+r)/2
  WHEN g>=r AND b>r  THEN (g+b)/2
  WHEN b>=r AND r>=g THEN (b+g)/2
  WHEN b>=r AND g>r  THEN (b+r)/2
END l
Was it helpful?

Solution

It is an absolute nightmare and not tested, but I've had a go:

SELECT 
    CASE 
      WHEN r=g  AND g=b  THEN 0
      WHEN r>=g AND g>b  THEN ((g-b)/(r-b))/6
      WHEN r>=g AND b>=g THEN ((g-b)/(r-g)+6)/6
      WHEN g>=r AND r>=b THEN ((b-r)/(g-b)+2)/6
      WHEN g>=r AND b>r  THEN ((b-r)/(g-r)+2)/6
      WHEN b>=r AND r>=g THEN ((r-g)/(b-g)+4)/6
      WHEN b>=r AND g>r  THEN ((r-g)/(b-r)+4)/6
    END h,
    CASE 
      WHEN r=g  AND g=b  THEN 0
      WHEN r>=g AND g>=b AND  (r-b)>0.5*255 THEN (r-b)/(510-r-b)          
      WHEN r>=g AND g>=b THEN (r-b)/(r+b)
      WHEN r>=g AND b>g  AND  (r-g)>0.5*255 THEN (r-g)/(510-r-g)
      WHEN r>=g AND b>g  THEN (r-g)/(r+g) 
      WHEN g>=r AND r>=b AND  (g-b)>0.5*255 THEN (g-b)/(510-g-b) 
      WHEN g>=r AND r>=b THEN (g-b)/(g+b)
      WHEN g>=r AND b>r  AND  (g-r)>0.5*255 THEN (g-r)/(510-g-r) 
      WHEN g>=r AND b>r  THEN (g-r)/(g+r)
      WHEN b>=r AND r>=g AND  (b-g)>0.5*255 THEN (b-g)/(510-b-g) 
      WHEN b>=r AND r>=g THEN (b-g)/(b+g)
      WHEN b>=r AND g>r  AND  (b-r)>0.5*255 THEN (b-r)/(510-b-r) 
      WHEN b>=r AND g>r  THEN (b-r)/(b+r)
    END s,
    CASE 
      WHEN r=g  AND g=b  THEN r/255
      WHEN r>=g AND g>=b THEN (r+b)/510
      WHEN r>=g AND b>g  THEN (r+g)/510
      WHEN g>=r AND r>=b THEN (g+r)/510
      WHEN g>=r AND b>r  THEN (g+b)/510
      WHEN b>=r AND r>=g THEN (b+g)/510
      WHEN b>=r AND g>r  THEN (b+r)/510
    END l
FROM table1

In conclusion, you are probably better off selecting the RGB values and running the conversion at the application level!

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top