The following is my RGB to HSL one way color conversion method, written in C#. It is closely based on code from the open source program, "Meazure" (which is the tool I am using for my project, thus I need my HSL color to be formatted the same as it is in Meazure).
public String rgbToHsl(int r, int g, int b)
{
double h, s, l;
double rDecimal = r / 255;
double gDecimal = g / 255;
double bDecimal = b / 255;
double cMin = Math.Min(r, Math.Min(g, b));
double cMax = Math.Max(r, Math.Max(g, b));
double delta = cMax - cMin;
l = (cMax + cMin) / 2;
if (cMax == cMin)
{
s = 0;
h = 0; // It's really undefined
}
else
{
if (l < .5)
{
s = delta / (cMax + cMin);
}
else
{
s = delta / (2 - cMax - cMin);
}
if (r == cMax)
{
h = (g - b) / delta;
}
else if (g == cMax)
{
h = 2 + (b - r) / delta;
}
else
{
h = 4 + (r - g) / delta;
}
h /= 6;
if (h < 0)
{
h += 1;
}
}
return h.ToString().PadLeft(3, '0') + s.ToString().PadLeft(3, '0') + l.ToString().PadLeft(3, '0');
}
The following is the open source, C++ Meazure code I used as a reference.
void MeaColors::RGBtoHSL(COLORREF rgb, HSL& hsl)
{
double h, s, l;
double r = GetRValue(rgb) / 255.0;
double g = GetGValue(rgb) / 255.0;
double b = GetBValue(rgb) / 255.0;
double cmax = Max(r, Max(g, b));
double cmin = Min(r, Min(g, b));
l = (cmax + cmin) / 2.0;
if (MEA_DBL_EQL(cmax, cmin)) {
s = 0.0;
h = 0.0; // it's really undefined
} else {
if (l < 0.5) {
s = (cmax - cmin) / (cmax + cmin);
} else {
s = (cmax - cmin) / (2.0 - cmax - cmin);
}
double delta = cmax - cmin;
if (MEA_DBL_EQL(r, cmax)) {
h = (g - b) / delta;
} else if (MEA_DBL_EQL(g, cmax)) {
h = 2.0 + (b - r) / delta;
} else {
h = 4.0 + (r - g) / delta;
}
h /= 6.0;
if (h < 0.0) {
h += 1.0;
}
}
hsl.hue = h;
hsl.lightness = l;
hsl.saturation = s;
}
The problem is that my method does not output the expected values. It does compile and run, without crashing. However, for the input RGB value 214, 219, 233, my method produces the HSL value .6, 228, 70, while the expected value, obtained by measuring the same pixel in HSL format using Meazure, is 149, 72, 210. I noticed a few similar questions on this site, but none with a functional solution, at least in the format desired here.
This is my code that calls my method. It happens to convert 25 RGB values from a single input, by building a 5x5 box centered around the input pixel (just mentioned it to avoid confusion).
Bitmap screenShot = takeScreenShot();
const int squareSideSize = 5;
Color[] firstPixelSquare = new Color[(int)Math.Pow(squareSideSize, 2)];
hslColor[] hslFirstPixelSquare = new hslColor[(int)Math.Pow(squareSideSize, 2)];
for (int hOffset = -2, i = 0; hOffset <= 2; hOffset++, i += squareSideSize)
{
for (int vOffset = -2, j = i; vOffset <= 2; vOffset++, j++)
{
firstPixelSquare[j] = screenShot.GetPixel((int)numericUpDownX1.Value + hOffset, (int)numericUpDownY1.Value + vOffset);
hslFirstPixelSquare[j].h = Convert.ToDouble(rgbToHsl(firstPixelSquare[j].R, firstPixelSquare[j].G, firstPixelSquare[j].B).Substring(0, 3));
hslFirstPixelSquare[j].s = Convert.ToDouble(rgbToHsl(firstPixelSquare[j].R, firstPixelSquare[j].G, firstPixelSquare[j].B).Substring(3, 3));
hslFirstPixelSquare[j].l = Convert.ToDouble(rgbToHsl(firstPixelSquare[j].R, firstPixelSquare[j].G, firstPixelSquare[j].B).Substring(6, 3));
}
}