C# RGB颜色与HSL颜色的转换与HSL颜色的应用
RGB颜色,就是用红、绿、蓝三个分量组成的颜色,.NET中用Color类来表示,HSL颜色,就是用色调(Hue)、饱和度(Saturation)、亮度(Lightness)来描绘一个颜色,这两种颜色的介绍网上很多,我就不具体介绍了。RGB颜色和HSL颜色的转化时有固定公式的,大家可以参考WIKI上的介绍(HSL and HSV),下面来介绍一下HSLColor类,它主要实现以下功能,RGB颜色跟HSL颜色的相互转换,传入一个RGB颜色,我们可以得到这个颜色的色调(Hue)、饱和度(Saturation)、亮度(Lightness),我们可以调节这3个量,得到一个新的颜色,利用这个类,通过调节图片的每个像素的颜色,就可以得到不同效果的图片了。来看看HSLColor类的详细源码:
1 /// <summary>
2 /// RGB 与 HSL 颜色的相互转换。
3 /// 转换算法参考:
4 /// http://en.wikipedia.org/wiki/HSL_color_space。
5 /// </summary>
6 public class HSLColor
7 {
8 private int _alpha = 255;
9 private int _hue = 0;
10 private double _saturation = 1d;
11 private double _lightness = 1d;
12
13 public HSLColor()
14 {
15 }
16
17 /// <summary>
18 /// 用一个RGB颜色构造HSLColor。
19 /// </summary>
20 /// <param name="color"></param>
21 public HSLColor(Color color)
22 {
23 _alpha = color.A;
24 FromRGB(color);
25 }
26
27 /// <summary>
28 /// 用色彩、饱和度、亮度构造HSLColor。
29 /// </summary>
30 /// <param name="hue">色彩。</param>
31 /// <param name="saturation">饱和度。</param>
32 /// <param name="lightness">亮度。</param>
33 public HSLColor(
34 int hue,
35 double saturation,
36 double lightness)
37 {
38 Hue = hue;
39 Saturation = saturation;
40 Lightness = lightness;
41 }
42
43 public int Hue
44 {
45 get { return _hue; }
46 set
47 {
48 if (value < 0)
49 {
50 _hue = value + 360;
51 }
52 else if (_hue > 360)
53 {
54 _hue = value % 360;
55 }
56 else
57 {
58 _hue = value;
59 }
60 }
61 }
62
63 public double Saturation
64 {
65 get { return _saturation; }
66 set
67 {
68 if (_saturation < 0)
69 {
70 _saturation = 0;
71 }
72 else
73 {
74 _saturation = Math.Min(value, 1d);
75 }
76 }
77 }
78
79 public double Lightness
80 {
81 get { return _lightness; }
82 set
83 {
84 if (_lightness < 0)
85 {
86 _lightness = 0;
87 }
88 else
89 {
90 _lightness = Math.Min(value, 1d);
91 }
92 }
93 }
94
95 public Color Color
96 {
97 get { return ToRGB(); }
98 set { FromRGB(value); }
99 }
100
101 public static bool operator ==(HSLColor left, HSLColor right)
102 {
103 return (left.Hue == right.Hue &&
104 left.Lightness == right.Lightness &&
105 left.Saturation == right.Saturation);
106 }
107
108 public static bool operator !=(HSLColor left, HSLColor right)
109 {
110 return !(left == right);
111 }
112
113 public override bool Equals(object obj)
114 {
115 if (obj == null && !(obj is HSLColor))
116 {
117 return false;
118 }
119
120 HSLColor color = (HSLColor)obj;
121 return this == color;
122 }
123
124 public override int GetHashCode()
125 {
126 return Color.GetHashCode();
127 }
128
129 public override string ToString()
130 {
131 return string.Format(
132 "HSL({0:f2}, {1:f2}, {2:f2})",
133 Hue, Saturation, Lightness);
134 }
135
136 private void FromRGB(Color color)
137 {
138 double r = ((double)color.R) / 255;
139 double g = ((double)color.G) / 255;
140 double b = ((double)color.B) / 255;
141
142 double min = Math.Min(Math.Min(r, g), b);
143 double max = Math.Max(Math.Max(r, g), b);
144 double distance = max - min;
145
146 _lightness = (max + min) / 2;
147 if (distance == 0)
148 {
149 _hue = 0;
150 _saturation = 0;
151 }
152 else
153 {
154 double hueTmp;
155 _saturation =
156 (_lightness < 0.5) ?
157 (distance / (max + min)) : (distance / ((2 - max) - min));
158 double tempR = (((max - r) / 6) + (distance / 2)) / distance;
159 double tempG = (((max - g) / 6) + (distance / 2)) / distance;
160 double tempB = (((max - b) / 6) + (distance / 2)) / distance;
161 if (r == max)
162 {
163 hueTmp = tempB - tempG;
164 }
165 else if (g == max)
166 {
167 hueTmp = (0.33333333333333331 + tempR) - tempB;
168 }
169 else
170 {
171 hueTmp = (0.66666666666666663 + tempG) - tempR;
172 }
173 if (hueTmp < 0)
174 {
175 hueTmp += 1;
176 }
177 if (hueTmp > 1)
178 {
179 hueTmp -= 1;
180 }
181 _hue = (int)(hueTmp * 360);
182 }
183 }
184
185 private Color ToRGB()
186 {
187 byte r;
188 byte g;
189 byte b;
190
191 if (_saturation == 0)
192 {
193 r = (byte)(_lightness * 255);
194 g = r;
195 b = r;
196 }
197 else
198 {
199 double vH = ((double)_hue) / 360;
200 double v2 =
201 (_lightness < 0.5) ?
202 (_lightness * (1 + _saturation)) :
203 ((_lightness + _saturation) - (_lightness * _saturation));
204 double v1 = (2 * _lightness) - v2;
205 r = (byte)(255 * HueToRGB(v1, v2, vH + 0.33333333333333331));
206 g = (byte)(255 * HueToRGB(v1, v2, vH));
207 b = (byte)(255 * HueToRGB(v1, v2, vH - 0.33333333333333331));
208 }
209 return Color.FromArgb(r, g, b);
210 }
211
212 private double HueToRGB(double v1, double v2, double vH)
213 {
214 if (vH < 0)
215 {
216 vH += 1;
217 }
218 if (vH > 1)
219 {
220 vH -= 1;
221 }
222 if ((6 * vH) < 1)
223 {
224 return v1 + (((v2 - v1) * 6) * vH);
225 }
226 if ((2 * vH) < 1)
227 {
228 return v2;
229 }
230 if ((3 * vH) < 2)
231 {
232 return v1 + (((v2 - v1) * (0.66666666666666663 - vH)) * 6);
233 }
234 return v1;
235 }
236 }
在项目中,为了演示用HSL颜色调节图片效果,还实现了一个HSLModifier类,这个类的功能就是利用HSLColor类,可以对图片的色调、饱和度和亮度进行调节,需要注意的是,为了提高图片调节的效率,在实现中使用了指针,所以在编译的时候需要选择允许不安全代码。看看HSLModifier类的详细源码:
1 public class HSLModifier : FilterColorToColor
2 {
3 private int _hue;
4 private double _saturation;
5 private double _lightness;
6
7 public HSLModifier()
8 {
9 }
10
11 public HSLModifier(
12 int hue,
13 double saturation,
14 double lightness)
15 {
16 Hue = hue;
17 Saturation = saturation;
18 Lightness = lightness;
19 }
20
21 public int Hue
22 {
23 get { return _hue; }
24 set
25 {
26 _hue = Math.Max(0, Math.Min(value, 360));
27 }
28 }
29
30 public double Saturation
31 {
32 get { return _saturation; }
33 set
34 {
35 _saturation = Math.Max(-1, Math.Min(value, 1));
36 }
37 }
38
39 public double Lightness
40 {
41 get { return _lightness; }
42 set
43 {
44 _lightness = Math.Max(-1, Math.Min(value, 1));
45 }
46 }
47
48 protected override unsafe void ProcessFilter(BitmapData imageData)
49 {
50 int width = imageData.Width;
51 int height = imageData.Height;
52 int perPixelLength = base.GetPerPixelFormatLength(
53 imageData.PixelFormat);
54 int offset = imageData.Stride - (width * perPixelLength);
55 Color rgb;
56 HSLColor hsl = new HSLColor();
57
58 byte* csan0 = (byte*)imageData.Scan0.ToPointer();
59
60 for (int i = 0; i < height; i++)
61 {
62 int widthOffset = 0;
63 while (widthOffset < width)
64 {
65 rgb = Color.FromArgb(csan0[2], csan0[1], csan0[0]);
66 hsl.Color = rgb;
67
68 hsl.Hue += _hue;
69 hsl.Saturation += _saturation;
70 hsl.Lightness += _lightness;
71
72 rgb = hsl.Color;
73
74 csan0[2] = rgb.R;
75 csan0[1] = rgb.G;
76 csan0[0] = rgb.B;
77
78 widthOffset++;
79 csan0 += perPixelLength;
80 }
81 csan0 += offset;
82 }
83 }
84 }
最后来看看例子的效果:
(1)图像调节前
(2)图像调节后
源码下载地址:http://d.namipan.com/d/a028b7ff50ebd55a0c6430f4673a1196616a22e3eca00500
来自:CS 程序员之窗