通过WEB修改服务器上图片的色调
效果如下:
需求:
很久很久以前,还在做asp的时候,在我网站的客户都会自动创建一个2级名的网站,设置了相应的模块。但有些客户喜欢某个模块的样式,不喜欢它的颜色,便要求我们改成他所喜欢的颜色。修改其实也很容易,无法就是把图片DOWN下来利用PS修改一下色调。但是,客户数量的庞大使得我们无暇一一满足。所以便想到客户可以自己通过web修改为自己喜欢的颜色。这样,普通的CSS很方便,但是模块中的图片颜色却不能修改。现在做.net了,又想这样做,折腾了好几天,终于实现了。
原理:
其实,修改简单修改图片的颜色,就是修改图片的色调(色相)。做过ps的人都知道,简单的拖动色掉的滚动条,图片就变为不同的颜色。而改变图片的色调,其实质也就是改变图片的R、G、B值,大家都知道无论任何色彩都是由RGB的不同比例组合而得到的。所以通过改变RGB然后重新组合就达到了改变图片颜色的效果,但是,除非专业的色彩搭配的人员,一般不可能通过单独一一调整R/G/B来达到自己想要的色彩效果,所以,就出现了色调这个名词,通过一定的计算公式,把色调的调整值换算为R/G/B的值,然后修改R/G/B来达到预期的效果。同样,修改图片的饱和度、明暗也是同样的原理(下两个专题可以陆续详细介绍)。
具体代码:
代码的关键,就是把色调值换算为R/G/B对应的值。
1、页面HTML
<%@ Page language="c#" Codebehind="PS.aspx.cs" AutoEventWireup="false" Inherits="BxgTest.PS" %>
二、***.aspx.cs
*.aspx.cs
1using System;
2using System.Collections;
3using System.ComponentModel;
4using System.Data;
5using System.Drawing;
6using System.Web;
7using System.Web.SessionState;
8using System.Web.UI;
9using System.Web.UI.WebControls;
10using System.Web.UI.HtmlControls;
11
12namespace BxgTest
13{
14 /**//// <summary>
15 /// PS 的摘要说明。
16 /// </summary>
17 public class PS : System.Web.UI.Page
18 {
19 protected System.Web.UI.WebControls.Image Image1;
20 protected System.Web.UI.WebControls.Image Image2;
21 protected System.Web.UI.WebControls.Button Button1;
22 protected System.Web.UI.WebControls.TextBox TextBox1;
23 protected System.Web.UI.HtmlControls.HtmlForm Form1;
24
25 private void Page_Load(object sender, System.EventArgs e)
26 {
27 if(!Page.IsPostBack)
28 bindPIC();
29 }
30
31 private void bindPIC()
32 {
33 Image1.ImageUrl = Server.MapPath("112.jpg");
34 Image2.ImageUrl = Server.MapPath("112P.jpg");
35 }
36
37 Web 窗体设计器生成的代码#region Web 窗体设计器生成的代码
38 override protected void OnInit(EventArgs e)
39 {
40 //
41 // CODEGEN: 该调用是 ASP.NET Web 窗体设计器所必需的。
42 //
43 InitializeComponent();
44 base.OnInit(e);
45 }
46
47 /**//// <summary>
48 /// 设计器支持所需的方法 - 不要使用代码编辑器修改
49 /// 此方法的内容。
50 /// </summary>
51 private void InitializeComponent()
52 {
53 this.Button1.Click += new System.EventHandler(this.Button1_Click);
54 this.Load += new System.EventHandler(this.Page_Load);
55
56 }
57 #endregion
58
59 private void Button1_Click(object sender, System.EventArgs e)
60 {
61 System.Drawing.Image image = System.Drawing.Image.FromFile(System.Web.HttpContext.Current.Server.MapPath("112.jpg"));
62 //取高和宽
63 int phWidth = image.Width;
64 int phHeight =image.Height;
65 //建新图,指定格式为每像素 24 位;红色、绿色和蓝色分量各使用 8 位。
66 System.Drawing.Bitmap bmPhoto = new System.Drawing.Bitmap(phWidth, phHeight, System.Drawing.Imaging.PixelFormat.Format24bppRgb);
67 //设置分辨率
68 bmPhoto.SetResolution(image.HorizontalResolution,image.VerticalResolution);
69 //准备Graphics
70 System.Drawing.Graphics grPhoto = System.Drawing.Graphics.FromImage(bmPhoto);
71
72
73 //指定消除锯齿的呈现。
74 grPhoto.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.HighQuality;
75 grPhoto.TextRenderingHint = System.Drawing.Text.TextRenderingHint.AntiAlias;
76 grPhoto.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.HighQualityBicubic;
77 grPhoto.CompositingQuality = System.Drawing.Drawing2D.CompositingQuality.HighSpeed;
78
79 //拷贝原图到做图区
80 grPhoto.DrawImage(
81 image,
82 new System.Drawing.Rectangle(0, 0, phWidth, phHeight),
83 0,
84 0,
85 phWidth,
86 phHeight,
87 System.Drawing.GraphicsUnit.Pixel);
88
89
90 HueModifier h = new HueModifier();
91 h.Hue = Convert.ToInt32(TextBox1.Text);
92
93 Bitmap imgnew = h.Apply(bmPhoto);
94
95 imgnew.Save(Server.MapPath("112P.jpg"), System.Drawing.Imaging.ImageFormat.Jpeg);
96
97 imgnew.Dispose();
98 grPhoto.Dispose();
99 bmPhoto.Dispose();
100 image.Dispose();
101 }
102 }
103}
这里需要注意的是,必须是每象素24位的图片,所以,我先新建了和原来图片一样大的图,然后复制过去。
3、处理类(部分代码来自网络)
CLASS
1using System;
2using System.Drawing;
3using System.Drawing.Imaging;
4
5namespace BxgTest
6{
7 public class RGB
8 {
9 public const short R = 2;
10 public const short G = 1;
11 public const short B = 0;
12
13 public byte Red;
14 public byte Green;
15 public byte Blue;
16
17 public System.Drawing.Color Color
18 {
19 get { return System.Drawing.Color.FromArgb(Red, Green, Blue); }
20 set
21 {
22 Red = value.R;
23 Green = value.G;
24 Blue = value.B;
25 }
26 }
27
28 public RGB(){}
29
30 public RGB(byte red, byte green, byte blue)
31 {
32 this.Red = red;
33 this.Green = green;
34 this.Blue = blue;
35 }
36 };
37
38
39
40
41
42
43 public class HSL
44 {
45 public int Hue; // 0-359 : 色调
46 public double Saturation; // 0-1 : 饱和度
47 public double Luminance; // 0-1 : 明暗度
48
49 public HSL(){}
50
51 public HSL(int hue, double saturation, double luminance)
52 {
53 this.Hue = hue;
54 this.Saturation = saturation;
55 this.Luminance = luminance;
56 }
57 };
58
59
60
61
62
63
64
65 public class ColorConverter
66 {
67 public static void RGB2HSL(RGB rgb, HSL hsl)
68 {
69 double r = (rgb.Red / 255.0);
70 double g = (rgb.Green / 255.0);
71 double b = (rgb.Blue / 255.0);
72
73 double min = Math.Min(Math.Min(r, g), b);
74 double max = Math.Max(Math.Max(r, g), b);
75 double delta = max - min;
76
77 hsl.Luminance = (max + min) / 2;
78
79 if (delta == 0)
80 {
81 hsl.Hue = 0;
82 hsl.Saturation = 0.0;
83 }
84 else
85 {
86 hsl.Saturation = (hsl.Luminance < 0.5) ? (delta / (max + min)) : (delta / (2 - max - min));
87
88 double del_r = (((max - r) / 6) + (delta / 2)) / delta;
89 double del_g = (((max - g) / 6) + (delta / 2)) / delta;
90 double del_b = (((max - b) / 6) + (delta / 2)) / delta;
91 double hue;
92
93 if (r == max)
94 hue = del_b - del_g;
95 else if (g == max)
96 hue = (1.0 / 3) + del_r - del_b;
97 else
98 hue = (2.0 / 3) + del_g - del_r;
99
100 if (hue < 0)
101 hue += 1;
102 if (hue > 1)
103 hue -= 1;
104
105 hsl.Hue = (int) (hue * 360);
106 }
107 }
108
109 /**//// <summary>
110 /// 把HSH转成对应的RGB
111 /// </summary>
112 /// <param name="hsl"></param>
113 /// <param name="rgb"></param>
114 public static void HSL2RGB(HSL hsl, RGB rgb)
115 {
116 if (hsl.Saturation == 0)
117 {
118 rgb.Red = rgb.Green = rgb.Blue = (byte) (hsl.Luminance * 255);
119 }
120 else
121 {
122 double v1, v2;
123 double hue = (double) hsl.Hue / 360;
124
125 v2 = (hsl.Luminance < 0.5) ? (hsl.Luminance * (1 + hsl.Saturation)) : ((hsl.Luminance + hsl.Saturation) - (hsl.Luminance * hsl.Saturation));
126 v1 = 2 * hsl.Luminance - v2;
127
128 rgb.Red = (byte)(255 * Hue_2_RGB(v1, v2, hue + (1.0 / 3)));
129 rgb.Green = (byte)(255 * Hue_2_RGB(v1, v2, hue));
130 rgb.Blue = (byte)(255 * Hue_2_RGB(v1, v2, hue - (1.0 / 3)));
131 }
132 }
133
134
135 Private members#region Private members
136 private static double Hue_2_RGB(double v1, double v2, double vH)
137 {
138 if (vH < 0)
139 vH += 1;
140 if (vH > 1)
141 vH -= 1;
142 if ((6 * vH) < 1)
143 return (v1 + (v2 - v1) * 6 * vH);
144 if ((2 * vH) < 1)
145 return v2;
146 if ((3 * vH) < 2)
147 return (v1 + (v2 - v1) * ((2.0 / 3) - vH) * 6);
148 return v1;
149 }
150 #endregion
151 }
152
153
154
155
156 public class HueModifier
157 {
158 private int hue = 0;
159
160 public int Hue
161 {
162 get { return hue; }
163 set { hue = System.Math.Max(0, System.Math.Min(359, value)); }
164 }
165
166 public HueModifier()
167 {
168 }
169
170 public HueModifier(int hue)
171 {
172 this.hue = hue;
173 }
174
175
176 public Bitmap Apply(Bitmap srcImg)
177 {
178 if (srcImg.PixelFormat != PixelFormat.Format24bppRgb)
179 throw new Exception("Sorry!");
180
181 int width = srcImg.Width;
182 int height = srcImg.Height;
183
184 BitmapData srcData = srcImg.LockBits(
185 new Rectangle(0, 0, width, height),
186 ImageLockMode.ReadOnly, PixelFormat.Format24bppRgb);
187
188 Bitmap dstImg = new Bitmap(width, height, PixelFormat.Format24bppRgb);
189
190 BitmapData dstData = dstImg.LockBits(
191 new Rectangle(0, 0, width, height),
192 ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb);
193
194 RGB rgb = new RGB();
195 HSL hsl = new HSL();
196 int offset = srcData.Stride - width * 3;
197
198 unsafe
199 {
200 byte * src = (byte *) srcData.Scan0.ToPointer();
201 byte * dst = (byte *) dstData.Scan0.ToPointer();
202
203 for (int y = 0; y < height; y++) //循环,一个象素一个象素的转
204 {
205 for (int x = 0; x < width; x++, src += 3, dst += 3)
206 {
207 rgb.Red = src[RGB.R];
208 rgb.Green = src[RGB.G];
209 rgb.Blue = src[RGB.B];
210
211 ColorConverter.RGB2HSL(rgb, hsl);
212
213 hsl.Hue = hsl.Hue + hue;
214
215 ColorConverter.HSL2RGB(hsl, rgb);
216
217 dst[RGB.R] = rgb.Red;
218 dst[RGB.G] = rgb.Green;
219 dst[RGB.B] = rgb.Blue;
220 }
221 src += offset;
222 dst += offset;
223 }
224 }
225 dstImg.UnlockBits(dstData);
226 srcImg.UnlockBits(srcData);
227
228 return dstImg;
229 }
230 }
231}
![](/images/cnblogs_com/ziyang/example.jpg)
需求:
很久很久以前,还在做asp的时候,在我网站的客户都会自动创建一个2级名的网站,设置了相应的模块。但有些客户喜欢某个模块的样式,不喜欢它的颜色,便要求我们改成他所喜欢的颜色。修改其实也很容易,无法就是把图片DOWN下来利用PS修改一下色调。但是,客户数量的庞大使得我们无暇一一满足。所以便想到客户可以自己通过web修改为自己喜欢的颜色。这样,普通的CSS很方便,但是模块中的图片颜色却不能修改。现在做.net了,又想这样做,折腾了好几天,终于实现了。
原理:
其实,修改简单修改图片的颜色,就是修改图片的色调(色相)。做过ps的人都知道,简单的拖动色掉的滚动条,图片就变为不同的颜色。而改变图片的色调,其实质也就是改变图片的R、G、B值,大家都知道无论任何色彩都是由RGB的不同比例组合而得到的。所以通过改变RGB然后重新组合就达到了改变图片颜色的效果,但是,除非专业的色彩搭配的人员,一般不可能通过单独一一调整R/G/B来达到自己想要的色彩效果,所以,就出现了色调这个名词,通过一定的计算公式,把色调的调整值换算为R/G/B的值,然后修改R/G/B来达到预期的效果。同样,修改图片的饱和度、明暗也是同样的原理(下两个专题可以陆续详细介绍)。
具体代码:
代码的关键,就是把色调值换算为R/G/B对应的值。
1、页面HTML
<%@ Page language="c#" Codebehind="PS.aspx.cs" AutoEventWireup="false" Inherits="BxgTest.PS" %>
1
<%@ Page language="c#" Codebehind="PS.aspx.cs" AutoEventWireup="false" Inherits="BxgTest.PS" %>
2
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" >
3
<HTML>
4
<HEAD>
5
<title>PS</title>
6
<meta content="Microsoft Visual Studio .NET 7.1" name="GENERATOR">
7
<meta content="C#" name="CODE_LANGUAGE">
8
<meta content="JavaScript" name="vs_defaultClientScript">
9
<meta content="http://schemas.microsoft.com/intellisense/ie5" name="vs_targetSchema">
10
<SCRIPT language="JavaScript">
11
12
var changedNotApplied = false;
13
var hueText = "";
14
15
function hueClick()
16
{
17
hue = event.offsetX;
18
//changedNotApplied = true;
19
20
document.Form1.TextBox1.value=hue;
21
return false;
22
}
23
</SCRIPT>
24
</HEAD>
25
<body MS_POSITIONING="GridLayout">
26
<form id="Form1" method="post" runat="server">
27
<TABLE id="Table1" style="WIDTH: 912px; HEIGHT: 158px" cellSpacing="0" cellPadding="0"
28
width="912" border="1">
29
<TR>
30
<TD style="WIDTH: 139px"><FONT face="宋体">原始图象</FONT></TD>
31
<TD><asp:image id="Image1" runat="server"></asp:image></TD>
32
</TR>
33
<TR>
34
<TD style="WIDTH: 139px"><FONT face="宋体">修改后的图象</FONT></TD>
35
<TD><FONT face="宋体"><asp:image id="Image2" runat="server"></asp:image></FONT></TD>
36
</TR>
37
<TR>
38
<TD style="WIDTH: 139px"><FONT face="宋体">设置值</FONT></TD>
39
<TD><IMG alt="simp" src="imgs.png" style="CURSOR: hand" onclick="hueClick()" name="huebar">
40
<asp:TextBox id="TextBox1" runat="server" Width="48px"></asp:TextBox><FONT face="宋体"> 0~360</FONT></TD>
41
</TR>
42
<TR>
43
<TD style="WIDTH: 139px">
44
<asp:Button id="Button1" runat="server" Text="Button"></asp:Button></TD>
45
<TD></TD>
46
</TR>
47
</TABLE>
48
</form>
49
</body>
50
</HTML>
51
其中有段JS,实质就是把选择的颜色转变为色掉,这个很简单。你预先弄张七彩图,长度为360(色调范围)然后取X位置就是对应的值了。 ![](/Images/OutliningIndicators/ExpandedBlockStart.gif)
2
![](/Images/OutliningIndicators/None.gif)
3
![](/Images/OutliningIndicators/None.gif)
4
![](/Images/OutliningIndicators/None.gif)
5
![](/Images/OutliningIndicators/None.gif)
6
![](/Images/OutliningIndicators/None.gif)
7
![](/Images/OutliningIndicators/None.gif)
8
![](/Images/OutliningIndicators/None.gif)
9
![](/Images/OutliningIndicators/None.gif)
10
![](/Images/OutliningIndicators/ExpandedBlockStart.gif)
11
![](/Images/OutliningIndicators/InBlock.gif)
12
![](/Images/OutliningIndicators/InBlock.gif)
13
![](/Images/OutliningIndicators/InBlock.gif)
14
![](/Images/OutliningIndicators/InBlock.gif)
15
![](/Images/OutliningIndicators/InBlock.gif)
16
![](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
17
![](/Images/OutliningIndicators/InBlock.gif)
18
![](/Images/OutliningIndicators/InBlock.gif)
19
![](/Images/OutliningIndicators/InBlock.gif)
20
![](/Images/OutliningIndicators/InBlock.gif)
21
![](/Images/OutliningIndicators/InBlock.gif)
22
![](/Images/OutliningIndicators/ExpandedSubBlockEnd.gif)
23
![](/Images/OutliningIndicators/ExpandedBlockEnd.gif)
24
![](/Images/OutliningIndicators/None.gif)
25
![](/Images/OutliningIndicators/None.gif)
26
![](/Images/OutliningIndicators/None.gif)
27
![](/Images/OutliningIndicators/None.gif)
28
![](/Images/OutliningIndicators/None.gif)
29
![](/Images/OutliningIndicators/None.gif)
30
![](/Images/OutliningIndicators/None.gif)
31
![](/Images/OutliningIndicators/None.gif)
32
![](/Images/OutliningIndicators/None.gif)
33
![](/Images/OutliningIndicators/None.gif)
34
![](/Images/OutliningIndicators/None.gif)
35
![](/Images/OutliningIndicators/None.gif)
36
![](/Images/OutliningIndicators/None.gif)
37
![](/Images/OutliningIndicators/None.gif)
38
![](/Images/OutliningIndicators/None.gif)
39
![](/Images/OutliningIndicators/None.gif)
40
![](/Images/OutliningIndicators/None.gif)
41
![](/Images/OutliningIndicators/None.gif)
42
![](/Images/OutliningIndicators/None.gif)
43
![](/Images/OutliningIndicators/None.gif)
44
![](/Images/OutliningIndicators/None.gif)
45
![](/Images/OutliningIndicators/None.gif)
46
![](/Images/OutliningIndicators/None.gif)
47
![](/Images/OutliningIndicators/None.gif)
48
![](/Images/OutliningIndicators/None.gif)
49
![](/Images/OutliningIndicators/None.gif)
50
![](/Images/OutliningIndicators/None.gif)
51
![](/Images/OutliningIndicators/None.gif)
二、***.aspx.cs
*.aspx.cs
1using System;
2using System.Collections;
3using System.ComponentModel;
4using System.Data;
5using System.Drawing;
6using System.Web;
7using System.Web.SessionState;
8using System.Web.UI;
9using System.Web.UI.WebControls;
10using System.Web.UI.HtmlControls;
11
12namespace BxgTest
13{
14 /**//// <summary>
15 /// PS 的摘要说明。
16 /// </summary>
17 public class PS : System.Web.UI.Page
18 {
19 protected System.Web.UI.WebControls.Image Image1;
20 protected System.Web.UI.WebControls.Image Image2;
21 protected System.Web.UI.WebControls.Button Button1;
22 protected System.Web.UI.WebControls.TextBox TextBox1;
23 protected System.Web.UI.HtmlControls.HtmlForm Form1;
24
25 private void Page_Load(object sender, System.EventArgs e)
26 {
27 if(!Page.IsPostBack)
28 bindPIC();
29 }
30
31 private void bindPIC()
32 {
33 Image1.ImageUrl = Server.MapPath("112.jpg");
34 Image2.ImageUrl = Server.MapPath("112P.jpg");
35 }
36
37 Web 窗体设计器生成的代码#region Web 窗体设计器生成的代码
38 override protected void OnInit(EventArgs e)
39 {
40 //
41 // CODEGEN: 该调用是 ASP.NET Web 窗体设计器所必需的。
42 //
43 InitializeComponent();
44 base.OnInit(e);
45 }
46
47 /**//// <summary>
48 /// 设计器支持所需的方法 - 不要使用代码编辑器修改
49 /// 此方法的内容。
50 /// </summary>
51 private void InitializeComponent()
52 {
53 this.Button1.Click += new System.EventHandler(this.Button1_Click);
54 this.Load += new System.EventHandler(this.Page_Load);
55
56 }
57 #endregion
58
59 private void Button1_Click(object sender, System.EventArgs e)
60 {
61 System.Drawing.Image image = System.Drawing.Image.FromFile(System.Web.HttpContext.Current.Server.MapPath("112.jpg"));
62 //取高和宽
63 int phWidth = image.Width;
64 int phHeight =image.Height;
65 //建新图,指定格式为每像素 24 位;红色、绿色和蓝色分量各使用 8 位。
66 System.Drawing.Bitmap bmPhoto = new System.Drawing.Bitmap(phWidth, phHeight, System.Drawing.Imaging.PixelFormat.Format24bppRgb);
67 //设置分辨率
68 bmPhoto.SetResolution(image.HorizontalResolution,image.VerticalResolution);
69 //准备Graphics
70 System.Drawing.Graphics grPhoto = System.Drawing.Graphics.FromImage(bmPhoto);
71
72
73 //指定消除锯齿的呈现。
74 grPhoto.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.HighQuality;
75 grPhoto.TextRenderingHint = System.Drawing.Text.TextRenderingHint.AntiAlias;
76 grPhoto.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.HighQualityBicubic;
77 grPhoto.CompositingQuality = System.Drawing.Drawing2D.CompositingQuality.HighSpeed;
78
79 //拷贝原图到做图区
80 grPhoto.DrawImage(
81 image,
82 new System.Drawing.Rectangle(0, 0, phWidth, phHeight),
83 0,
84 0,
85 phWidth,
86 phHeight,
87 System.Drawing.GraphicsUnit.Pixel);
88
89
90 HueModifier h = new HueModifier();
91 h.Hue = Convert.ToInt32(TextBox1.Text);
92
93 Bitmap imgnew = h.Apply(bmPhoto);
94
95 imgnew.Save(Server.MapPath("112P.jpg"), System.Drawing.Imaging.ImageFormat.Jpeg);
96
97 imgnew.Dispose();
98 grPhoto.Dispose();
99 bmPhoto.Dispose();
100 image.Dispose();
101 }
102 }
103}
这里需要注意的是,必须是每象素24位的图片,所以,我先新建了和原来图片一样大的图,然后复制过去。
3、处理类(部分代码来自网络)
CLASS
1using System;
2using System.Drawing;
3using System.Drawing.Imaging;
4
5namespace BxgTest
6{
7 public class RGB
8 {
9 public const short R = 2;
10 public const short G = 1;
11 public const short B = 0;
12
13 public byte Red;
14 public byte Green;
15 public byte Blue;
16
17 public System.Drawing.Color Color
18 {
19 get { return System.Drawing.Color.FromArgb(Red, Green, Blue); }
20 set
21 {
22 Red = value.R;
23 Green = value.G;
24 Blue = value.B;
25 }
26 }
27
28 public RGB(){}
29
30 public RGB(byte red, byte green, byte blue)
31 {
32 this.Red = red;
33 this.Green = green;
34 this.Blue = blue;
35 }
36 };
37
38
39
40
41
42
43 public class HSL
44 {
45 public int Hue; // 0-359 : 色调
46 public double Saturation; // 0-1 : 饱和度
47 public double Luminance; // 0-1 : 明暗度
48
49 public HSL(){}
50
51 public HSL(int hue, double saturation, double luminance)
52 {
53 this.Hue = hue;
54 this.Saturation = saturation;
55 this.Luminance = luminance;
56 }
57 };
58
59
60
61
62
63
64
65 public class ColorConverter
66 {
67 public static void RGB2HSL(RGB rgb, HSL hsl)
68 {
69 double r = (rgb.Red / 255.0);
70 double g = (rgb.Green / 255.0);
71 double b = (rgb.Blue / 255.0);
72
73 double min = Math.Min(Math.Min(r, g), b);
74 double max = Math.Max(Math.Max(r, g), b);
75 double delta = max - min;
76
77 hsl.Luminance = (max + min) / 2;
78
79 if (delta == 0)
80 {
81 hsl.Hue = 0;
82 hsl.Saturation = 0.0;
83 }
84 else
85 {
86 hsl.Saturation = (hsl.Luminance < 0.5) ? (delta / (max + min)) : (delta / (2 - max - min));
87
88 double del_r = (((max - r) / 6) + (delta / 2)) / delta;
89 double del_g = (((max - g) / 6) + (delta / 2)) / delta;
90 double del_b = (((max - b) / 6) + (delta / 2)) / delta;
91 double hue;
92
93 if (r == max)
94 hue = del_b - del_g;
95 else if (g == max)
96 hue = (1.0 / 3) + del_r - del_b;
97 else
98 hue = (2.0 / 3) + del_g - del_r;
99
100 if (hue < 0)
101 hue += 1;
102 if (hue > 1)
103 hue -= 1;
104
105 hsl.Hue = (int) (hue * 360);
106 }
107 }
108
109 /**//// <summary>
110 /// 把HSH转成对应的RGB
111 /// </summary>
112 /// <param name="hsl"></param>
113 /// <param name="rgb"></param>
114 public static void HSL2RGB(HSL hsl, RGB rgb)
115 {
116 if (hsl.Saturation == 0)
117 {
118 rgb.Red = rgb.Green = rgb.Blue = (byte) (hsl.Luminance * 255);
119 }
120 else
121 {
122 double v1, v2;
123 double hue = (double) hsl.Hue / 360;
124
125 v2 = (hsl.Luminance < 0.5) ? (hsl.Luminance * (1 + hsl.Saturation)) : ((hsl.Luminance + hsl.Saturation) - (hsl.Luminance * hsl.Saturation));
126 v1 = 2 * hsl.Luminance - v2;
127
128 rgb.Red = (byte)(255 * Hue_2_RGB(v1, v2, hue + (1.0 / 3)));
129 rgb.Green = (byte)(255 * Hue_2_RGB(v1, v2, hue));
130 rgb.Blue = (byte)(255 * Hue_2_RGB(v1, v2, hue - (1.0 / 3)));
131 }
132 }
133
134
135 Private members#region Private members
136 private static double Hue_2_RGB(double v1, double v2, double vH)
137 {
138 if (vH < 0)
139 vH += 1;
140 if (vH > 1)
141 vH -= 1;
142 if ((6 * vH) < 1)
143 return (v1 + (v2 - v1) * 6 * vH);
144 if ((2 * vH) < 1)
145 return v2;
146 if ((3 * vH) < 2)
147 return (v1 + (v2 - v1) * ((2.0 / 3) - vH) * 6);
148 return v1;
149 }
150 #endregion
151 }
152
153
154
155
156 public class HueModifier
157 {
158 private int hue = 0;
159
160 public int Hue
161 {
162 get { return hue; }
163 set { hue = System.Math.Max(0, System.Math.Min(359, value)); }
164 }
165
166 public HueModifier()
167 {
168 }
169
170 public HueModifier(int hue)
171 {
172 this.hue = hue;
173 }
174
175
176 public Bitmap Apply(Bitmap srcImg)
177 {
178 if (srcImg.PixelFormat != PixelFormat.Format24bppRgb)
179 throw new Exception("Sorry!");
180
181 int width = srcImg.Width;
182 int height = srcImg.Height;
183
184 BitmapData srcData = srcImg.LockBits(
185 new Rectangle(0, 0, width, height),
186 ImageLockMode.ReadOnly, PixelFormat.Format24bppRgb);
187
188 Bitmap dstImg = new Bitmap(width, height, PixelFormat.Format24bppRgb);
189
190 BitmapData dstData = dstImg.LockBits(
191 new Rectangle(0, 0, width, height),
192 ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb);
193
194 RGB rgb = new RGB();
195 HSL hsl = new HSL();
196 int offset = srcData.Stride - width * 3;
197
198 unsafe
199 {
200 byte * src = (byte *) srcData.Scan0.ToPointer();
201 byte * dst = (byte *) dstData.Scan0.ToPointer();
202
203 for (int y = 0; y < height; y++) //循环,一个象素一个象素的转
204 {
205 for (int x = 0; x < width; x++, src += 3, dst += 3)
206 {
207 rgb.Red = src[RGB.R];
208 rgb.Green = src[RGB.G];
209 rgb.Blue = src[RGB.B];
210
211 ColorConverter.RGB2HSL(rgb, hsl);
212
213 hsl.Hue = hsl.Hue + hue;
214
215 ColorConverter.HSL2RGB(hsl, rgb);
216
217 dst[RGB.R] = rgb.Red;
218 dst[RGB.G] = rgb.Green;
219 dst[RGB.B] = rgb.Blue;
220 }
221 src += offset;
222 dst += offset;
223 }
224 }
225 dstImg.UnlockBits(dstData);
226 srcImg.UnlockBits(srcData);
227
228 return dstImg;
229 }
230 }
231}