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;
}
}
}
}
鞋锤博客