using System; using System.Collections.Generic; using System.Text; using System.Drawing; namespace ColorDemo { public class HSLColor { // Private data members below are on scale 0-1 // They are scaled for use externally based on scale private double hue = 1.0; private double saturation = 1.0; private double luminosity = 1.0; private const double scale = 240.0; public double Hue { get { return hue * scale; } set { hue = CheckRange(value / scale); } } public double Saturation { get { return saturation * scale; } set { saturation = CheckRange(value / scale); } } public double Luminosity { get { return luminosity * scale; } set { luminosity = CheckRange(value / scale); } } private double CheckRange(double value) { if (value < 0.0) value = 0.0; else if (value > 1.0) value = 1.0; return value; } public override string ToString() { return String.Format("H: {0:#0.##} S: {1:#0.##} L: {2:#0.##}", Hue, Saturation, Luminosity); } public string ToRGBString() { Color color = (Color)this; return String.Format("R: {0:#0.##} G: {1:#0.##} B: {2:#0.##}", color.R, color.G, color.B); } #region Casts to/from System.Drawing.Color public static implicit operator Color(HSLColor hslColor) { double r = 0, g = 0, b = 0; if (hslColor.luminosity != 0) { if (hslColor.saturation == 0) r = g = b = hslColor.luminosity; else { double temp2 = GetTemp2(hslColor); double temp1 = 2.0 * hslColor.luminosity - temp2; r = GetColorComponent(temp1, temp2, hslColor.hue + 1.0 / 3.0); g = GetColorComponent(temp1, temp2, hslColor.hue); b = GetColorComponent(temp1, temp2, hslColor.hue - 1.0 / 3.0); } } return Color.FromArgb((int)(255 * r), (int)(255 * g), (int)(255 * b)); } private static double GetColorComponent(double temp1, double temp2, double temp3) { temp3 = MoveIntoRange(temp3); if (temp3 < 1.0 / 6.0) return temp1 + (temp2 - temp1) * 6.0 * temp3; else if (temp3 < 0.5) return temp2; else if (temp3 < 2.0 / 3.0) return temp1 + ((temp2 - temp1) * ((2.0 / 3.0) - temp3) * 6.0); else return temp1; } private static double MoveIntoRange(double temp3) { if (temp3 < 0.0) temp3 += 1.0; else if (temp3 > 1.0) temp3 -= 1.0; return temp3; } private static double GetTemp2(HSLColor hslColor) { double temp2; if (hslColor.luminosity < 0.5) //<=?? temp2 = hslColor.luminosity * (1.0 + hslColor.saturation); else temp2 = hslColor.luminosity + hslColor.saturation - (hslColor.luminosity * hslColor.saturation); return temp2; } public static implicit operator HSLColor(Color color) { HSLColor hslColor = new HSLColor(); hslColor.hue = color.GetHue() / 360.0; // we store hue as 0-1 as opposed to 0-360 hslColor.luminosity = color.GetBrightness(); hslColor.saturation = color.GetSaturation(); return hslColor; } #endregion public void SetRGB(int red, int green, int blue) { HSLColor hslColor = (HSLColor)Color.FromArgb(red, green, blue); this.hue = hslColor.hue; this.saturation = hslColor.saturation; this.luminosity = hslColor.luminosity; } public HSLColor() { } public HSLColor(Color color) { SetRGB(color.R, color.G, color.B); } public HSLColor(int red, int green, int blue) { SetRGB(red, green, blue); } public HSLColor(double hue, double saturation, double luminosity) { this.Hue = hue; this.Saturation = saturation; this.Luminosity = luminosity; } } }
HSLColor Class
18 Comments »
RSS feed for comments on this post. TrackBack URI


Awesome! Just what I was looking for, Thanks!
Comment by Felix D. — June 19, 2009 @ 8:54 pm
Perfect just what i was looking for, thanks !!
Comment by Boudewijn — May 21, 2010 @ 12:49 pm
Many thanks, just I was looking for.
Comment by Rytis Ūsalis — August 4, 2010 @ 8:29 pm
Brilliant thanks for sharing! Got to wonder why this isn’t built into .NET – or don’t .NET developers care about colors?
Comment by Luke Sampson — November 18, 2010 @ 7:38 am
Thanks for this.
@LukeSampson – haven’t you ever created a windows forms application?
Comment by David kemp — March 7, 2011 @ 12:09 pm
Rich,
Thank you very much. This code has been a godsend. I really wish that there was something native in .NET…
One minor point – in the cast from color to HSLColor you are directly casting the RGB values to int, which is truncating them (253.99 -> 253). So, if you do a round-trip conversion of a color to an HSLColor and back, you might get a different color. I discovered this when I started with “#fefffe” translated to HSL and back to HTML which came back as “#fdfffd”.
The correct code should be:
return Color.FromArgb(
Convert.ToInt32(255 * r),
Convert.ToInt32(255 * g),
Convert.ToInt32(255 * b));
Thanks again posting. Very much appreciated.
Comment by Steve Holmes — April 8, 2011 @ 7:13 pm
Fantastic work, my humble contrib
Hey you can remove the setRGB method by using constructor chaining
public HslColor(Color Color) : this(Color.R, Color.G, Color.B)
{
}
public HslColor(int Red, int Green, int Blue)
{
HslColor HslColor = Color.FromArgb(Red, Green, Blue);
_Hue = HslColor._Hue;
_Saturation = HslColor._Saturation;
_Luminosity = HslColor._Luminosity;
}
Comment by Chandru — June 7, 2011 @ 8:31 am
And you can remove the 4 redundant else keyword in GetColorComponent() and use the objectinitializer in Color to HSLColor implicit conversion method
Comment by Chandru — June 7, 2011 @ 8:39 am
Great, thanks! I need this for random hues with the same sat/lum.
Comment by Frankie Bagnardi — August 20, 2011 @ 12:25 am
I spoke too soon. It doesn’t seem to play nicely with XNA.
Comment by Frankie Bagnardi — August 20, 2011 @ 12:28 am
Great stuff, work like a charm, I was taken aback by the lack of functionality of the .NET color class. And HSV is just a much more intuitive color space!
Comment by Simon Ejsing — August 30, 2011 @ 10:20 am
I seem to be having problems getting certain colors to show up as anything but white.
Here’s an example (scale in hslcolor is 360):
System.Drawing.Color[] colorArray = new System.Drawing.Color[19];
for (int hue = 0; hue < 19; hue++)
{
colorArray[hue] = (System.Drawing.Color)new HSLColor(hue * 20, 0.25 * 360, 1.0 * 360);
}
Every single one of these colors will come out as RGB(255,255,255)
Comment by dewyroad — March 10, 2012 @ 10:11 am
Please what “value” represents in this code?
Comment by Anonymous — March 10, 2012 @ 4:47 pm
Can this be used to change the color of some part of the image? can anybody guide me how?
Comment by prashanth — May 22, 2012 @ 11:24 am
Hi guys,Can this be used to change the color of some part of the image? can anybody guide me how?
Comment by prashanth — May 22, 2012 @ 11:24 am
Thanks for sharing this code. It worked fine with a gradient coloring test app I made. I need to know, are there any license terms and conditions this listing is under?
Thanks!
Petar T.
Comment by Petar Todorov — December 4, 2012 @ 5:12 pm
Peter – No licensing terms apply, you are free to use how you want.
Comment by richnewman — December 16, 2012 @ 2:09 am
Does anyone have a VB version of this?
Comment by Adam — March 12, 2013 @ 6:40 am