There seems to be 5 flavours of the “HSL”:
- HSL: Hue, Saturation, Lightness
- HSL: Hue, Saturation, Luminance
- HSV: Hue, Saturation, Value
- HSB: Hue, Saturation, Brightness
- HSI: Hue, Saturation, Intensity
I don’t understand why there are so many variants. I like RGB.
I needed a way to convert HSL (the luminance version) to RGB. Now .NET doesn’t have a way to convert any of the variants to its built-in System.Drawing.Color structure. Although the structure offers the GetHue(), GetSaturation() and GetBrightness() functions.
Generally speaking, the hue is between 0 and 360 degrees of a colour wheel. Saturation determines “how much” of that colour is displayed. And luminance determines “how bright/dark” that colour is.
So here’s the code to convert HSL to RGB (in the form of a System.Drawing.Color struct):
public System.Drawing.Color RgbFromHsl(double Hue, double Saturation, double Luminance) { double fChroma = (1.0 - Math.Abs(2.0 * Luminance - 1.0)) * Saturation; double fHue = Hue / 60.0; double fHueMod2 = fHue; while (fHueMod2 >= 2.0) fHueMod2 -= 2.0; double fTemp = fChroma * (1.0 - Math.Abs(fHueMod2 - 1.0)); double fRed = 0, fGreen = 0, fBlue = 0; if (fHue < 1.0) { fRed = fChroma; fGreen = fTemp; fBlue = 0; } else if (fHue < 2.0) { fRed = fTemp; fGreen = fChroma; fBlue = 0; } else if (fHue < 3.0) { fRed = 0; fGreen = fChroma; fBlue = fTemp; } else if (fHue < 4.0) { fRed = 0; fGreen = fTemp; fBlue = fChroma; } else if (fHue < 5.0) { fRed = fTemp; fGreen = 0; fBlue = fChroma; } else if (fHue < 6.0) { fRed = fChroma; fGreen = 0; fBlue = fTemp; } else { fRed = 0; fGreen = 0; fBlue = 0; } double fMin = Luminance - 0.5 * fChroma; fRed += fMin; fGreen += fMin; fBlue += fMin; fRed *= 255.0; fGreen *= 255.0; fBlue *= 255.0; int iRed = 0, iGreen = 0, iBlue = 0; // the default seems to be to truncate rather than round iRed = Convert.ToInt32(Math.Truncate(fRed)); iGreen = Convert.ToInt32(Math.Truncate(fGreen)); iBlue = Convert.ToInt32(Math.Truncate(fBlue)); if (iRed < 0) iRed = 0; if (iRed > 255) iRed = 255; if (iGreen < 0) iGreen = 0; if (iGreen > 255) iGreen = 255; if (iBlue < 0) iBlue = 0; if (iBlue > 255) iBlue = 255; return System.Drawing.Color.FromArgb(iRed, iGreen, iBlue); }
The algorithm is taken from the Wikipedia page on HSL and HSV. I added some checks at the end to make sure the RGB values are within 0 to 255.
About the only problem I had was the mod function. It’s not “integer modulus”, it’s “floating point modulus” (is that a thing?). So 5.5 mod 2 is 1.5 (because the remainder of 5.5/2 is 1.5). That took me a couple of hours to figure out. This is one of the few cases where thinking in programming terms instead of the mathematical terms cost me.