using System;
using System.Collections.Generic;
using System.Windows.Media;
namespace CommonTools
{
public struct HSLColor
{
double m_hue;
double m_saturation;
double m_lightness;
// http://en.wikipedia.org/wiki/HSL_color_space
public double Hue
{
get { return m_hue; }
set { m_hue = value; }
}
public double Saturation
{
get { return m_saturation; }
set { m_saturation = value; }
}
public double Lightness
{
get { return m_lightness; }
set
{
m_lightness = value;
if (m_lightness < 0)
m_lightness = 0;
if (m_lightness > 1)
m_lightness = 1;
}
}
public HSLColor(double hue, double saturation, double lightness)
{
m_hue = Math.Min(360, hue);
m_saturation = Math.Min(1, saturation);
m_lightness = Math.Min(1, lightness);
m_avg = 0;
}
public HSLColor(Color color)
{
m_hue = 0;
m_saturation = 1;
m_lightness = 1;
m_avg = 0;
FromRGB(color);
}
public Color Color
{
get { return ToRGB(); }
set { FromRGB(value); }
}
double m_avg;
public double Avg {get { return m_avg; }}
void FromRGB(Color cc)
{
double r = (double)cc.R / 255d;
double g = (double)cc.G / 255d;
double b = (double)cc.B / 255d;
m_avg = (r*g*b)/3;
double min = Math.Min(Math.Min(r, g), b);
double max = Math.Max(Math.Max(r, g), b);
// calulate hue according formula given in
// "Conversion from RGB to HSL or HSV"
m_hue = 0;
if (min != max)
{
if (r == max && g >= b)
{
m_hue = 60 * ((g - b) / (max - min)) + 0;
}
else
if (r == max && g < b)
{
m_hue = 60 * ((g - b) / (max - min)) + 360;
}
else
if (g == max)
{
m_hue = 60 * ((b - r) / (max - min)) + 120;
}
else
if (b == max)
{
m_hue = 60 * ((r - g) / (max - min)) + 240;
}
}
// find lightness
m_lightness = (min+max)/2;
// find saturation
if (m_lightness == 0 ||min == max)
m_saturation = 0;
else
if (m_lightness > 0 && m_lightness <= 0.5)
m_saturation = (max-min)/(2*m_lightness);
else
if (m_lightness > 0.5)
m_saturation = (max-min)/(2-2*m_lightness);
}
Color ToRGB()
{
// convert to RGB according to
// "Conversion from HSL to RGB"
double r = m_lightness;
double g = m_lightness;
double b = m_lightness;
if (m_saturation == 0)
return Color.FromArgb(255, (byte)(r*255), (byte)(g*255), (byte)(b*255));
double q = 0;
if (m_lightness < 0.5)
q = m_lightness * (1 + m_saturation);
else
q = m_lightness + m_saturation - (m_lightness * m_saturation);
double p = 2 * m_lightness - q;
double hk = m_hue / 360;
// r,g,b colors
double[] tc = new double[3] { hk + (1d/3d), hk, hk-(1d/3d)};
double[] colors = new double[3] {0, 0, 0};
for (int color = 0; color < colors.Length; color++)
{
if (tc[color] < 0)
tc[color] += 1;
if (tc[color] > 1)
tc[color] -= 1;
if (tc[color] < (1d/6d))
colors[color] = p + ((q-p)*6*tc[color]);
else
if (tc[color] >= (1d/6d) && tc[color] < (1d/2d))
colors[color] = q;
else
if (tc[color] >= (1d/2d) && tc[color] < (2d/3d))
colors[color] = p + ((q-p)*6*(2d/3d - tc[color]));
else
colors[color] = p;
colors[color] *= 255; // convert to value expected by Color
}
return Color.FromArgb(255, (byte)colors[0], (byte)colors[1], (byte)colors[2]);
}
public static bool operator != (HSLColor left, HSLColor right)
{
return !(left == right);
}
public static bool operator == (HSLColor left, HSLColor right)
{
return (left.Hue == right.Hue &&
left.Lightness == right.Lightness &&
left.Saturation == right.Saturation);
}
public override bool Equals(object obj)
{
return base.Equals(obj);
}
public override int GetHashCode()
{
return base.GetHashCode();
}
public override string ToString()
{
string s = string.Format("HSL({0:f2}, {1:f2}, {2:f2})", Hue, Saturation, Lightness);
return s;
}
}
}