RGB色彩空间与HSL、HSV(HSB)色彩空间的数值转换。定义了三个结构:RGB、HSL、HSV,由于HSB与HSV的意义相同,我不清楚怎样为结构指定别名,于是又定义了一个HSB结构。然后写一个静态转换类Convertor来实现色彩空间的转换功能。没有写CMYK和LAB代码,网上说像CMYK这种算法会与PhotoShop中的算法有差别,我又没用得上CMYK打印,因此这部分没有写。算法可以统统去维基百科查到。只是注意,我这里定义RGB各分量的范围是0~255之间的整数,也就是一个字节,在“构造”时可以使用整形;H分量的区间是 [0, 360) ,S、L、V、B分量的区间是 [0, 1] 。具体代码如下:
using System; using System.Text; namespace Bobwei.Design { public static class ColorSpace { #region 结构 public struct RGB { public byte R { get {return r; } set { CheckByte(value,"Red"); r = value; } } public byte G { get {return g; } set { CheckByte(value,"Green"); g = value; } } public byte B { get {return b; } set { CheckByte(value,"Blue"); b = value; } } private byte r, g, b; public RGB(int r,int g,int b) :this() { R = (byte)r; G = (byte)g; B = (byte)b; } private static void CheckByte(int value,string name) { if ((value < 0) || (value > 0xff)) throw new ArgumentOutOfRangeException(string.Format("{0} valid range is {1}", name,"0~255")); } } public struct HSL { public float H { get {return h; } set { CheckHSL(value, 0, 0); h = value; } } public float S { get {return s; } set { CheckHSL(0, value, 0); s = value; } } public float L { get {return l; } set { CheckHSL(0, 0, value); l = value; } } private float h, s, l; public HSL(float h,float s,float l) :this() { H = h; S = s; L = l; } private static void CheckHSL(float h,float s,float l) { if (h < 0 || h > 360) { throw new ArgumentOutOfRangeException(string.Format("{0} valid range is {1}","Hue","0~360")); } if (s < 0 || s > 1) { throw new ArgumentOutOfRangeException(string.Format("{0} valid range is {1}","Saturation","0~1")); } if (l < 0 || l > 1) { throw new ArgumentOutOfRangeException(string.Format("{0} valid range is {1}","Lightness","0~1")); } } } public struct HSV { public float H { get {return h; } set { CheckHSV(value, 0, 0); h = value; } } public float S { get {return s; } set { CheckHSV(0, value, 0); s = value; } } public float V { get {return v; } set { CheckHSV(0, 0, value); v = value; } } private float h, s, v; public HSV(float h,float s,float v) :this() { H = h; S = s; V = v; } private static void CheckHSV(float h,float s,float v) { if (h < 0 || h > 360) { throw new ArgumentOutOfRangeException(string.Format("{0} valid range is {1}","Hue","0~360")); } if (s < 0 || s > 1) { throw new ArgumentOutOfRangeException(string.Format("{0} valid range is {1}","Saturation","0~1")); } if (v < 0 || v > 1) { throw new ArgumentOutOfRangeException(string.Format("{0} valid range is {1}","Value","0~1")); } } } public struct HSB { ... } #endregion //结构 public static class Convertor { public static HSV RGB2HSV(RGB Rgb) { float r = Rgb.R / 255f; float g = Rgb.G / 255f; float b = Rgb.B / 255f; HSV Hsv =new HSV(0, 0, 0); float max = Math.Max(r, Math.Max(g, b)); float min = Math.Min(r, Math.Min(g, b)); float dif = max - min; if (dif == 0) { Hsv.H = 0; } else if (max == r) { if (g >= b) { Hsv.H = (g - b) / dif * 60f; } else { Hsv.H = (g - b) / dif * 60f + 360f; } } else if (max == g) { Hsv.H = (b - r) / dif * 60f + 120f; } else { Hsv.H = (r - g) / dif * 60f + 240f; } Hsv.S = max == 0 ? 0 : dif / max; Hsv.V = max; return Hsv; } public static HSB RGB2HSB(RGB Rgb) { HSV Hsv = RGB2HSV(Rgb); return new HSB(Hsv.H, Hsv.S, Hsv.V); } public static HSL RGB2HSL(RGB Rgb) { float r = Rgb.R / 255f; float g = Rgb.G / 255f; float b = Rgb.B / 255f; HSL Hsl =new HSL(0, 0, 0); float max = Math.Max(r, Math.Max(g, b)); float min = Math.Min(r, Math.Min(g, b)); float dif = max - min; if (dif == 0) { Hsl.H = 0; } else if (max == r) { if (g >= b) { Hsl.H = (g - b) / dif * 60f; } else { Hsl.H = (g - b) / dif * 60f + 360f; } } else if (max == g) { Hsl.H = (b - r) / dif * 60f + 120f; } else { Hsl.H = (r - g) / dif * 60f + 240f; } Hsl.L = (max + min) / 2f; if (Hsl.L == 0 || max == min) { Hsl.S = 0; } else if (Hsl.L > 0.5f) { Hsl.S = dif / (2f - (max + min)); } else { Hsl.S = dif / (max + min); } return Hsl; } public static RGB HSV2RGB(HSV Hsv) { int hi = (int)(Hsv.H / 60f) % 6; float f, p, q, t; f = Hsv.H / 60f - hi; p = Hsv.V * (1f - Hsv.S); q = Hsv.V * (1f - f * Hsv.S); t = Hsv.V * (1f - (1f - f) * Hsv.S); float r = 0f, g = 0f, b = 0f; switch (hi) { case 0: r = Hsv.V; g = t; b = p; break; case 1: r = q; g = Hsv.V; b = p; break; case 2: r = p; g = Hsv.V; b = t; break; case 3: r = p; g = q; b = Hsv.V; break; case 4: r = t; g = p; b = Hsv.V; break; case 5: r = Hsv.V; g = p; b = q; break; } RGB Rgb =new RGB( (int)Math.Round(r * 255), (int)Math.Round(g * 255), (int)Math.Round(b * 255)); return Rgb; } public static RGB HSB2RGB(HSB Hsb) { HSV Hsv =new HSV(Hsb.H, Hsb.S, Hsb.B); return HSV2RGB(Hsv); } public static RGB HSL2RGB(HSL Hsl) { if (Hsl.S == 0) { int l = (int)(Hsl.L * 255); return new RGB(l, l, l); } float q, p, hk, tr, tg, tb; q = Hsl.L < 0.5f ? Hsl.L * (1f + Hsl.S) : Hsl.L + Hsl.S - (Hsl.L * Hsl.S); p = 2f * Hsl.L - q; hk = Hsl.H / 360f; tr = hk + 1f / 3f; tg = hk; tb = hk - 1f / 3f; if (tr < 0) tr += 1f; if (tr > 1) tr -= 1f; if (tg < 0) tg += 1f; if (tg > 1) tg -= 1f; if (tb < 0) tb += 1f; if (tb > 1) tb -= 1f; float colorr, colorg, colorb; colorr = calc_ColorC(tr, p, q); colorg = calc_ColorC(tg, p, q); colorb = calc_ColorC(tb, p, q); RGB Rgb =new RGB( (int)Math.Round(colorr * 255), (int)Math.Round(colorg * 255), (int)Math.Round(colorb * 255)); return Rgb; } private static float calc_ColorC(float tc,float p,float q) { float colorc; if (6f * tc < 1f) { colorc = p + ((q - p) * 6f * tc); } else if (6f * tc >= 1f && tc < 0.5f) { colorc = q; } else if (tc >= 0.5f && 3f * tc < 2f) { colorc = p + ((q - p) * 6f * (2f / 3f - tc)); } else { colorc = p; } return colorc; } } } }