ASP.NET为图片添加水印功能示例详解
这两天主要在学习如何给图片添加水印,查找了一下相关的解决方案,其中有一个别人写好的水印dll,虽然能实现很多的功能,但很遗憾不能用于其他商业用途,没办法只能再找找别的办法,后面找到的这种方法比较简单,就是通过Graphics重新绘制bitmap的方法来绘制水印,当然,文字水印可能稍微要麻烦一点儿,需要设置字体相关的东东,比如字号、阴影、颜色啥的,但整体来看,思路基本是一样的。
至于具体的步骤说明,请查看源码上的注释即可,应该能够保证大家不至于太迷糊:
第一部分:水印相关参数结构体和枚举
View Code
1 /// <summary>
2 /// 水印位置枚举
3 /// </summary>
4 public enum ImagePosition
5 {
6 LeftTop, //左上
7 LeftBottom, //左下
8 RightTop, //右上
9 RigthBottom, //右下
10 TopMiddle, //顶部居中
11 BottomMiddle, //底部居中
12 Center //中心
13 }
14
15 /// <summary>
16 /// 图片水印参数结构体
17 /// </summary>
18 public struct ImageWatermarkParameters
19 {
20 /// <summary>
21 /// 源图片路径
22 /// </summary>
23 public string SourceImagePath;
24 /// <summary>
25 /// 水印图片路径
26 /// </summary>
27 public string WatermarkImagePath;
28 /// <summary>
29 /// 源图片数据流(即如果设置数据流,则忽略SourceImagePath属性值)
30 /// </summary>
31 public MemoryStream SourceImageStream;
32 /// <summary>
33 /// 水印图片数据流(即如果设置数据流,则忽略WatermarkImagePath属性值)
34 /// </summary>
35 public MemoryStream WatermarkImageStream;
36 /// <summary>
37 /// 透明度,数值介于0.1 - 1.0之间,不包括0.0
38 /// </summary>
39 public float Alpha;
40 /// <summary>
41 /// 水印位置
42 /// </summary>
43 public ImagePosition WmPosition;
44 private string _sourceImageFileExtensionName;
45 /// <summary>
46 /// 源图片文件扩展名
47 /// </summary>
48 public string SourceImageFileExtensionName
49 {
50 set { _sourceImageFileExtensionName = value; }
51 get
52 {
53 if (string.IsNullOrEmpty(this.SourceImagePath))
54 {
55 // 如果设置的图片扩展名为ContentType类型,则进行转化
56 if (_sourceImageFileExtensionName.IndexOf("/") > 0)
57 _sourceImageFileExtensionName = TransferContentTypeToUnifyExName(_sourceImageFileExtensionName);
58
59 return _sourceImageFileExtensionName;
60 }
61 else
62 return Path.GetExtension(SourceImagePath).ToLower();
63 }
64 }
65
66
67 public ImageWatermarkParameters(string sourceImagePath, string watermarkImagePath, float alpha, ImagePosition wmPosition)
68 {
69 this.SourceImageStream = null;
70 this.WatermarkImageStream = null;
71 this._sourceImageFileExtensionName = string.Empty;
72
73 this.SourceImagePath = sourceImagePath;
74 this.WatermarkImagePath = watermarkImagePath;
75 this.Alpha = alpha;
76 this.WmPosition = wmPosition;
77 }
78
79 public ImageWatermarkParameters(MemoryStream sourceImageStream, MemoryStream watermarkImageStream,
80 string sourceImageFileExtensionName, float alpha, ImagePosition wmPosition)
81 {
82 this.SourceImagePath = string.Empty;
83 this.WatermarkImagePath = string.Empty; ;
84
85 this.SourceImageStream = sourceImageStream;
86 this.WatermarkImageStream = watermarkImageStream;
87 this.Alpha = alpha;
88 this.WmPosition = wmPosition;
89 this._sourceImageFileExtensionName = sourceImageFileExtensionName;
90 }
91
92 /// <summary>
93 /// 参数检查并设定默认值
94 /// </summary>
95 /// <param name="errorMsg"></param>
96 /// <returns></returns>
97 public bool CheckAndSetDefault(out string errorMsg)
98 {
99 errorMsg = string.Empty;
100
101 // 前置检查
102 if ((string.IsNullOrEmpty(this.SourceImagePath) && SourceImageStream == null)
103 || (string.IsNullOrEmpty(this.WatermarkImagePath) && WatermarkImageStream == null)
104 || (SourceImageStream != null && string.IsNullOrEmpty(_sourceImageFileExtensionName))
105 || this.Alpha <= 0.0 || this.Alpha > 1.0
106 || this.WmPosition == null)
107 {
108 errorMsg = "文字水印参数实体中含有非法的参数项。";
109 return false;
110 }
111
112 // 检查图片路径是否合法
113 if ((SourceImageStream == null && !string.IsNullOrEmpty(this.SourceImagePath) && !File.Exists(this.SourceImagePath)) // 仅赋值源图片路径,且路径不存在的情况
114 || (WatermarkImageStream == null && !string.IsNullOrEmpty(this.WatermarkImagePath) && !File.Exists(this.WatermarkImagePath))) // 仅赋值水印图片路径,但文件不存在的情况
115 {
116 errorMsg = "输入的源图片或水印图片路径不存在。";
117 return false;
118 }
119
120
121 // 检查图片扩展名
122 bool validExName = true;
123 if (!string.IsNullOrEmpty(this.SourceImagePath) && !string.IsNullOrEmpty(this.WatermarkImagePath))
124 {
125 if (!CheckImageExtensionType(this.SourceImagePath) || !CheckImageExtensionType(this.WatermarkImagePath))
126 validExName = false;
127 }
128 else if (this.SourceImageStream != null && this.WatermarkImageStream != null)
129 {
130 if ((_sourceImageFileExtensionName != ".gif" && _sourceImageFileExtensionName != ".jpg" && _sourceImageFileExtensionName != ".png"))
131 validExName = false;
132 }
133 else
134 validExName = false;
135
136 if (!validExName)
137 {
138 errorMsg = "暂不支持源图片或水印图片的格式类型。";
139 return false;
140 }
141
142 return true;
143 }
144 }
145
146 /// <summary>
147 /// 文字水印参数结构体
148 /// </summary>
149 public struct TextWatermarkParameters
150 {
151 /// <summary>
152 /// 源图片路径
153 /// </summary>
154 public string SourceImagePath;
155 /// <summary>
156 /// 水印文字
157 /// </summary>
158 public string WatermarkText;
159 /// <summary>
160 /// 源图片数据流
161 /// </summary>
162 public MemoryStream SourceImageStream;
163 /// <summary>
164 /// 透明度,数值介于0.1 - 1.0之间,不包括0.0
165 /// </summary>
166 public float Alpha;
167 /// <summary>
168 /// 水印位置
169 /// </summary>
170 public ImagePosition WmPosition;
171 /// <summary>
172 /// 水印文字字体样式
173 /// </summary>
174 public Font WmTextFont;
175 /// <summary>
176 /// 水印文字阴影宽度
177 /// </summary>
178 public int TextShadowWidth;
179 private string _sourceImageFileExtensionName;
180 /// <summary>
181 /// 源图片文件扩展名
182 /// </summary>
183 public string SourceImageFileExtensionName
184 {
185 set { _sourceImageFileExtensionName = value; }
186 get
187 {
188 if (string.IsNullOrEmpty(this.SourceImagePath))
189 {
190 // 如果设置的图片扩展名为ContentType类型,则进行转化
191 if (_sourceImageFileExtensionName.IndexOf("/") > 0)
192 _sourceImageFileExtensionName = TransferContentTypeToUnifyExName(_sourceImageFileExtensionName);
193
194 return _sourceImageFileExtensionName;
195 }
196 else
197 return Path.GetExtension(SourceImagePath).ToLower();
198 }
199 }
200
201
202 public TextWatermarkParameters(MemoryStream sourceImageStream, string sourceImageFileExtensionName, string watermarkText, float alpha,
203 ImagePosition wmPosition, Font wmTextFont, int textShadowWidth = 5)
204 {
205 this.SourceImagePath = string.Empty ;
206
207 this.SourceImageStream = sourceImageStream;
208 this.WatermarkText = watermarkText;
209 this.Alpha = alpha;
210 this.WmPosition = wmPosition;
211 this.WmTextFont = wmTextFont;
212 this.TextShadowWidth = textShadowWidth;
213 this._sourceImageFileExtensionName = sourceImageFileExtensionName;
214 }
215
216 public TextWatermarkParameters(string sourceImagePath, string watermarkText, float alpha,
217 ImagePosition wmPosition, Font wmTextFont, int textShadowWidth = 5)
218 {
219 this.SourceImageStream = null;
220 this._sourceImageFileExtensionName = string.Empty;
221
222 this.SourceImagePath = sourceImagePath;
223 this.WatermarkText = watermarkText;
224 this.Alpha = alpha;
225 this.WmPosition = wmPosition;
226 this.WmTextFont = wmTextFont;
227 this.TextShadowWidth = textShadowWidth;
228 }
229
230 /// <summary>
231 /// 参数检查并设定默认值
232 /// </summary>
233 /// <param name="errorMsg"></param>
234 /// <returns></returns>
235 public bool CheckAndSetDefault(out string errorMsg)
236 {
237 errorMsg = string.Empty;
238
239 // 前置检查
240 if ((string.IsNullOrEmpty(this.SourceImagePath) && this.SourceImageStream == null) || (!string.IsNullOrEmpty(this.SourceImagePath) && !File.Exists(this.SourceImagePath))
241 || string.IsNullOrEmpty(this.WatermarkText)
242 || (SourceImageStream != null && string.IsNullOrEmpty(_sourceImageFileExtensionName))
243 || this.Alpha <= 0.0 || this.Alpha > 1.0
244 || this.WmPosition == null
245 || this.WmTextFont == null)
246 {
247 errorMsg = "文字水印参数实体中含有非法的参数项。";
248 return false;
249 }
250
251 // 检查图片路径是否合法
252 if ((SourceImageStream == null && !string.IsNullOrEmpty(this.SourceImagePath) && !File.Exists(this.SourceImagePath))) // 仅赋值源图片路径,且路径不存在的情况
253 {
254 errorMsg = "输入的源图片路径不存在。";
255 return false;
256 }
257
258 // 检查图片扩展名
259 bool validExName = true;
260 if (!string.IsNullOrEmpty(this.SourceImagePath))
261 {
262 if (!CheckImageExtensionType(this.SourceImagePath))
263 validExName = false;
264 }
265 else if (this.SourceImageStream != null)
266 {
267 if ((_sourceImageFileExtensionName != ".gif" && _sourceImageFileExtensionName != ".jpg" && _sourceImageFileExtensionName != ".png"))
268 validExName = false;
269 }
270 else
271 validExName = false;
272
273 if (!validExName)
274 {
275 errorMsg = "暂不支持源图片的格式类型。";
276 return false;
277 }
278
279 return true;
280 }
281
2 /// 水印位置枚举
3 /// </summary>
4 public enum ImagePosition
5 {
6 LeftTop, //左上
7 LeftBottom, //左下
8 RightTop, //右上
9 RigthBottom, //右下
10 TopMiddle, //顶部居中
11 BottomMiddle, //底部居中
12 Center //中心
13 }
14
15 /// <summary>
16 /// 图片水印参数结构体
17 /// </summary>
18 public struct ImageWatermarkParameters
19 {
20 /// <summary>
21 /// 源图片路径
22 /// </summary>
23 public string SourceImagePath;
24 /// <summary>
25 /// 水印图片路径
26 /// </summary>
27 public string WatermarkImagePath;
28 /// <summary>
29 /// 源图片数据流(即如果设置数据流,则忽略SourceImagePath属性值)
30 /// </summary>
31 public MemoryStream SourceImageStream;
32 /// <summary>
33 /// 水印图片数据流(即如果设置数据流,则忽略WatermarkImagePath属性值)
34 /// </summary>
35 public MemoryStream WatermarkImageStream;
36 /// <summary>
37 /// 透明度,数值介于0.1 - 1.0之间,不包括0.0
38 /// </summary>
39 public float Alpha;
40 /// <summary>
41 /// 水印位置
42 /// </summary>
43 public ImagePosition WmPosition;
44 private string _sourceImageFileExtensionName;
45 /// <summary>
46 /// 源图片文件扩展名
47 /// </summary>
48 public string SourceImageFileExtensionName
49 {
50 set { _sourceImageFileExtensionName = value; }
51 get
52 {
53 if (string.IsNullOrEmpty(this.SourceImagePath))
54 {
55 // 如果设置的图片扩展名为ContentType类型,则进行转化
56 if (_sourceImageFileExtensionName.IndexOf("/") > 0)
57 _sourceImageFileExtensionName = TransferContentTypeToUnifyExName(_sourceImageFileExtensionName);
58
59 return _sourceImageFileExtensionName;
60 }
61 else
62 return Path.GetExtension(SourceImagePath).ToLower();
63 }
64 }
65
66
67 public ImageWatermarkParameters(string sourceImagePath, string watermarkImagePath, float alpha, ImagePosition wmPosition)
68 {
69 this.SourceImageStream = null;
70 this.WatermarkImageStream = null;
71 this._sourceImageFileExtensionName = string.Empty;
72
73 this.SourceImagePath = sourceImagePath;
74 this.WatermarkImagePath = watermarkImagePath;
75 this.Alpha = alpha;
76 this.WmPosition = wmPosition;
77 }
78
79 public ImageWatermarkParameters(MemoryStream sourceImageStream, MemoryStream watermarkImageStream,
80 string sourceImageFileExtensionName, float alpha, ImagePosition wmPosition)
81 {
82 this.SourceImagePath = string.Empty;
83 this.WatermarkImagePath = string.Empty; ;
84
85 this.SourceImageStream = sourceImageStream;
86 this.WatermarkImageStream = watermarkImageStream;
87 this.Alpha = alpha;
88 this.WmPosition = wmPosition;
89 this._sourceImageFileExtensionName = sourceImageFileExtensionName;
90 }
91
92 /// <summary>
93 /// 参数检查并设定默认值
94 /// </summary>
95 /// <param name="errorMsg"></param>
96 /// <returns></returns>
97 public bool CheckAndSetDefault(out string errorMsg)
98 {
99 errorMsg = string.Empty;
100
101 // 前置检查
102 if ((string.IsNullOrEmpty(this.SourceImagePath) && SourceImageStream == null)
103 || (string.IsNullOrEmpty(this.WatermarkImagePath) && WatermarkImageStream == null)
104 || (SourceImageStream != null && string.IsNullOrEmpty(_sourceImageFileExtensionName))
105 || this.Alpha <= 0.0 || this.Alpha > 1.0
106 || this.WmPosition == null)
107 {
108 errorMsg = "文字水印参数实体中含有非法的参数项。";
109 return false;
110 }
111
112 // 检查图片路径是否合法
113 if ((SourceImageStream == null && !string.IsNullOrEmpty(this.SourceImagePath) && !File.Exists(this.SourceImagePath)) // 仅赋值源图片路径,且路径不存在的情况
114 || (WatermarkImageStream == null && !string.IsNullOrEmpty(this.WatermarkImagePath) && !File.Exists(this.WatermarkImagePath))) // 仅赋值水印图片路径,但文件不存在的情况
115 {
116 errorMsg = "输入的源图片或水印图片路径不存在。";
117 return false;
118 }
119
120
121 // 检查图片扩展名
122 bool validExName = true;
123 if (!string.IsNullOrEmpty(this.SourceImagePath) && !string.IsNullOrEmpty(this.WatermarkImagePath))
124 {
125 if (!CheckImageExtensionType(this.SourceImagePath) || !CheckImageExtensionType(this.WatermarkImagePath))
126 validExName = false;
127 }
128 else if (this.SourceImageStream != null && this.WatermarkImageStream != null)
129 {
130 if ((_sourceImageFileExtensionName != ".gif" && _sourceImageFileExtensionName != ".jpg" && _sourceImageFileExtensionName != ".png"))
131 validExName = false;
132 }
133 else
134 validExName = false;
135
136 if (!validExName)
137 {
138 errorMsg = "暂不支持源图片或水印图片的格式类型。";
139 return false;
140 }
141
142 return true;
143 }
144 }
145
146 /// <summary>
147 /// 文字水印参数结构体
148 /// </summary>
149 public struct TextWatermarkParameters
150 {
151 /// <summary>
152 /// 源图片路径
153 /// </summary>
154 public string SourceImagePath;
155 /// <summary>
156 /// 水印文字
157 /// </summary>
158 public string WatermarkText;
159 /// <summary>
160 /// 源图片数据流
161 /// </summary>
162 public MemoryStream SourceImageStream;
163 /// <summary>
164 /// 透明度,数值介于0.1 - 1.0之间,不包括0.0
165 /// </summary>
166 public float Alpha;
167 /// <summary>
168 /// 水印位置
169 /// </summary>
170 public ImagePosition WmPosition;
171 /// <summary>
172 /// 水印文字字体样式
173 /// </summary>
174 public Font WmTextFont;
175 /// <summary>
176 /// 水印文字阴影宽度
177 /// </summary>
178 public int TextShadowWidth;
179 private string _sourceImageFileExtensionName;
180 /// <summary>
181 /// 源图片文件扩展名
182 /// </summary>
183 public string SourceImageFileExtensionName
184 {
185 set { _sourceImageFileExtensionName = value; }
186 get
187 {
188 if (string.IsNullOrEmpty(this.SourceImagePath))
189 {
190 // 如果设置的图片扩展名为ContentType类型,则进行转化
191 if (_sourceImageFileExtensionName.IndexOf("/") > 0)
192 _sourceImageFileExtensionName = TransferContentTypeToUnifyExName(_sourceImageFileExtensionName);
193
194 return _sourceImageFileExtensionName;
195 }
196 else
197 return Path.GetExtension(SourceImagePath).ToLower();
198 }
199 }
200
201
202 public TextWatermarkParameters(MemoryStream sourceImageStream, string sourceImageFileExtensionName, string watermarkText, float alpha,
203 ImagePosition wmPosition, Font wmTextFont, int textShadowWidth = 5)
204 {
205 this.SourceImagePath = string.Empty ;
206
207 this.SourceImageStream = sourceImageStream;
208 this.WatermarkText = watermarkText;
209 this.Alpha = alpha;
210 this.WmPosition = wmPosition;
211 this.WmTextFont = wmTextFont;
212 this.TextShadowWidth = textShadowWidth;
213 this._sourceImageFileExtensionName = sourceImageFileExtensionName;
214 }
215
216 public TextWatermarkParameters(string sourceImagePath, string watermarkText, float alpha,
217 ImagePosition wmPosition, Font wmTextFont, int textShadowWidth = 5)
218 {
219 this.SourceImageStream = null;
220 this._sourceImageFileExtensionName = string.Empty;
221
222 this.SourceImagePath = sourceImagePath;
223 this.WatermarkText = watermarkText;
224 this.Alpha = alpha;
225 this.WmPosition = wmPosition;
226 this.WmTextFont = wmTextFont;
227 this.TextShadowWidth = textShadowWidth;
228 }
229
230 /// <summary>
231 /// 参数检查并设定默认值
232 /// </summary>
233 /// <param name="errorMsg"></param>
234 /// <returns></returns>
235 public bool CheckAndSetDefault(out string errorMsg)
236 {
237 errorMsg = string.Empty;
238
239 // 前置检查
240 if ((string.IsNullOrEmpty(this.SourceImagePath) && this.SourceImageStream == null) || (!string.IsNullOrEmpty(this.SourceImagePath) && !File.Exists(this.SourceImagePath))
241 || string.IsNullOrEmpty(this.WatermarkText)
242 || (SourceImageStream != null && string.IsNullOrEmpty(_sourceImageFileExtensionName))
243 || this.Alpha <= 0.0 || this.Alpha > 1.0
244 || this.WmPosition == null
245 || this.WmTextFont == null)
246 {
247 errorMsg = "文字水印参数实体中含有非法的参数项。";
248 return false;
249 }
250
251 // 检查图片路径是否合法
252 if ((SourceImageStream == null && !string.IsNullOrEmpty(this.SourceImagePath) && !File.Exists(this.SourceImagePath))) // 仅赋值源图片路径,且路径不存在的情况
253 {
254 errorMsg = "输入的源图片路径不存在。";
255 return false;
256 }
257
258 // 检查图片扩展名
259 bool validExName = true;
260 if (!string.IsNullOrEmpty(this.SourceImagePath))
261 {
262 if (!CheckImageExtensionType(this.SourceImagePath))
263 validExName = false;
264 }
265 else if (this.SourceImageStream != null)
266 {
267 if ((_sourceImageFileExtensionName != ".gif" && _sourceImageFileExtensionName != ".jpg" && _sourceImageFileExtensionName != ".png"))
268 validExName = false;
269 }
270 else
271 validExName = false;
272
273 if (!validExName)
274 {
275 errorMsg = "暂不支持源图片的格式类型。";
276 return false;
277 }
278
279 return true;
280 }
281
第二部分:水印功能处理类 -> 内部辅助函数部分
View Code
/// <summary>
/// 获取编码参数数组
/// </summary>
/// <returns></returns>
private static EncoderParameters GetEncoderParameters()
{
EncoderParameters eps = new EncoderParameters(1);
EncoderParameter ep = new EncoderParameter(Encoder.Quality, _imageSaveQualityValue);
eps.Param[0] = ep;
return eps;
}
/// <summary>
/// 根据图片格式获取编码信息
/// </summary>
/// <param name="mimeType">图片格式</param>
/// <returns>编码信息</returns>
private static ImageCodecInfo GetEncoderInfo(String mimeType)
{
int j;
ImageCodecInfo[] encoders;
encoders = ImageCodecInfo.GetImageEncoders();
for (j = 0; j < encoders.Length; ++j)
{
if (encoders[j].MimeType == mimeType)
return encoders[j];
}
return null;
}
/// <summary>
/// 获取最终图片保存的图像格式
/// </summary>
/// <param name="imageExtensionName">图片扩展名称</param>
/// <returns>图片格式</returns>
private static ImageCodecInfo GetFinalImageCodecInfo(string imageExtensionName)
{
switch (imageExtensionName)
{
case ".gif":
return GetEncoderInfo("image/gif");
case ".png":
return GetEncoderInfo("image/png");
case ".jpg":
default:
return GetEncoderInfo("image/jpeg");
}
}
/// <summary>
/// 获取文字画刷
/// </summary>
/// <param name="alpha">透明度</param>
/// <returns></returns>
private static SolidBrush GetTextBrush(float alpha)
{
// 从四个 ARGB 分量(alpha、红色、绿色和蓝色)值创建 Color 结构,这里设置透明度为153
// 这个画笔为描绘正式文字的笔刷,呈白色
SolidBrush semiTransBrush = new SolidBrush(Color.FromArgb(Convert.ToInt32(255 * alpha), Color.White));
return semiTransBrush;
}
/// <summary>
/// 获取阴影画刷
/// </summary>
/// <returns></returns>
private static SolidBrush GetShadowBrush()
{
// SolidBrush:定义单色画笔。画笔用于填充图形形状,如矩形、椭圆、扇形、多边形和封闭路径。
// 这个画笔为描绘阴影的画笔,呈灰色
return new SolidBrush(Color.FromArgb(153, Color.Blue));
}
/// <summary>
/// 获取文本布局信息
/// </summary>
/// <returns></returns>
private static StringFormat GetStringFormat()
{
// 封装文本布局信息(如对齐、文字方向和 Tab 停靠位),显示操作(如省略号插入和国家标准 (National) 数字替换)和 OpenType 功能
StringFormat StrFormat = new StringFormat();
StrFormat.Alignment = StringAlignment.Center;
return StrFormat;
}
/// <summary>
/// Get image attribute instance.
/// </summary>
/// <param name="alpha">transparency value</param>
/// <returns></returns>
private static ImageAttributes GetImageAttributesInstance(float alpha)
{
// imageattributes instance which will control the related infomations for image.
ImageAttributes imageAttributes = new ImageAttributes();
// 图片映射:水印图被定义成拥有绿色背景色的图片被替换成透明
ColorMap colorMap = new ColorMap();
colorMap.OldColor = Color.FromArgb(255, 0, 255, 0);
colorMap.NewColor = Color.FromArgb(0, 0, 0, 0);
imageAttributes.SetRemapTable(new ColorMap[] { colorMap }, ColorAdjustType.Bitmap);
float[][] colorMatrixElements = new float[][]
{
new float[] {1.0f, 0.0f, 0.0f, 0.0f, 0.0f}, // red红色
new float[] {0.0f, 1.0f, 0.0f, 0.0f, 0.0f}, // green绿色
new float[] {0.0f, 0.0f, 1.0f, 0.0f, 0.0f}, // blue蓝色
new float[] {0.0f, 0.0f, 0.0f, alpha, 0.0f}, // 透明度
new float[] {0.0f, 0.0f, 0.0f, 0.0f, 1.0f}
};
// ColorMatrix:定义包含 RGBA 空间坐标的 5 x 5 矩阵。
// ImageAttributes:类的若干方法通过使用颜色矩阵调整图像颜色。
imageAttributes.SetColorMatrix(new ColorMatrix(colorMatrixElements), ColorMatrixFlag.Default, ColorAdjustType.Bitmap);
return imageAttributes;
}
/// <summary>
/// Calculate the watermark image position.
/// </summary>
/// <param name="position">position</param>
/// <param name="srcWidth">source image width</param>
/// <param name="srcHeight">source image height</param>
/// <param name="wmWidth">watermark image width</param>
/// <param name="wmHeight">watermark image height</param>
/// <param name="xPosOfWm">final x position</param>
/// <param name="yPosOfWm">final y position</param>
private static void GetWatermarkImagePosition(ImagePosition position, int srcWidth, int srcHeight, int wmWidth, int wmHeight, out int xPosOfWm, out int yPosOfWm)
{
switch (position)
{
case ImagePosition.BottomMiddle:
xPosOfWm = (srcWidth - wmWidth) / 2;
yPosOfWm = srcHeight - wmHeight - 10;
break;
case ImagePosition.Center:
xPosOfWm = (srcWidth - wmWidth) / 2;
yPosOfWm = (srcHeight - wmHeight) / 2;
break;
case ImagePosition.LeftBottom:
xPosOfWm = 10;
yPosOfWm = srcHeight - wmHeight - 10;
break;
case ImagePosition.LeftTop:
xPosOfWm = 10;
yPosOfWm = 10;
break;
case ImagePosition.RightTop:
xPosOfWm = srcWidth - wmWidth - 10;
yPosOfWm = 10;
break;
case ImagePosition.RigthBottom:
xPosOfWm = srcWidth - wmWidth - 10;
yPosOfWm = srcHeight - wmHeight - 10;
break;
case ImagePosition.TopMiddle:
xPosOfWm = (srcWidth - wmWidth) / 2;
yPosOfWm = 10;
break;
default:
xPosOfWm = 10;
yPosOfWm = srcHeight - wmHeight - 10;
break;
}
}
/// <summary>
/// Calculate the watermark image position.
/// </summary>
/// <param name="position">position</param>
/// <param name="srcWidth">source image width</param>
/// <param name="srcHeight">source image height</param>
/// <param name="wmWidth">watermark image width</param>
/// <param name="wmHeight">watermark image height</param>
/// <param name="xPosOfWm">final x position</param>
/// <param name="yPosOfWm">final y position</param>
private static void GetWatermarkTextPosition(ImagePosition position, int srcWidth, int srcHeight, float wmWidth, float wmHeight, out float xPosOfWm, out float yPosOfWm)
{
switch (position)
{
case ImagePosition.BottomMiddle:
xPosOfWm = srcWidth / 2;
yPosOfWm = srcHeight - wmHeight - 10;
break;
case ImagePosition.Center:
xPosOfWm = srcWidth / 2;
yPosOfWm = srcHeight / 2;
break;
case ImagePosition.LeftBottom:
xPosOfWm = wmWidth;
yPosOfWm = srcHeight - wmHeight - 10;
break;
case ImagePosition.LeftTop:
xPosOfWm = wmWidth / 2;
yPosOfWm = wmHeight / 2;
break;
case ImagePosition.RightTop:
xPosOfWm = srcWidth - wmWidth - 10;
yPosOfWm = wmHeight;
break;
case ImagePosition.RigthBottom:
xPosOfWm = srcWidth - wmWidth - 10;
yPosOfWm = srcHeight - wmHeight - 10;
break;
case ImagePosition.TopMiddle:
xPosOfWm = srcWidth / 2;
yPosOfWm = wmWidth;
break;
default:
xPosOfWm = wmWidth;
yPosOfWm = srcHeight - wmHeight - 10;
break;
}
}
/// <summary>
/// Check image extension type.
/// </summary>
/// <param name="sourceImagePath">image path</param>
/// <returns>examine result</returns>
private static bool CheckImageExtensionType(string imagePath)
{
string fileExtensionType = System.IO.Path.GetExtension(imagePath).ToLower();
return (System.IO.File.Exists(imagePath) && (fileExtensionType == ".gif" || fileExtensionType == ".jpg" || fileExtensionType == ".png"));
}
/// <summary>
/// 获取Bitmap的MemoryStream
/// </summary>
/// <param name="finalImage"></param>
/// <returns></returns>
private static MemoryStream GetMemoryStreamFromBitmap(Bitmap finalImage, string sourceImageFileExName)
{
MemoryStream ms = new MemoryStream();
// 将位图保存到数据流中
finalImage.Save(ms, GetFinalImageCodecInfo(sourceImageFileExName), GetEncoderParameters());
return ms;
}
/// <summary>
/// 获取源图片和水印图片的数据流
/// </summary>
/// <param name="parameters">参数实例</param>
/// <param name="sourceImageStream">源图片数据流</param>
/// <param name="waterImageStream">水印图片数据流</param>
/// <param name="errorMsg">错误信息</param>
/// <returns>是否获取成功</returns>
private static bool GetSourceAndWatermarkImageStream(ImageWatermarkParameters parameters,
out MemoryStream sourceImageStream, out MemoryStream waterImageStream, out string errorMsg)
{
errorMsg = string.Empty;
// 根据是否设置图片路径来判断如何获取图片数据流,分别获取源图片和水印图片的数据流。
string scErrMsg = string.Empty, wmErrMsg = string.Empty;
sourceImageStream = parameters.SourceImageStream == null ?
GetImageMemoryStream(parameters.SourceImagePath, out scErrMsg) : parameters.SourceImageStream;
waterImageStream = parameters.WatermarkImageStream == null ?
GetImageMemoryStream(parameters.WatermarkImagePath, out wmErrMsg) : parameters.WatermarkImageStream;
if (!string.IsNullOrEmpty(scErrMsg) || !string.IsNullOrEmpty(wmErrMsg))
{
errorMsg = "通过图片路径获取数据流失败:" + scErrMsg + ";" + wmErrMsg;
return false;
}
return true;
}
/// <summary>
/// 判断图片的PixelFormat 是否在 引发异常的 PixelFormat 之中
/// </summary>
/// <param name="imgPixelFormat">原图片的PixelFormat</param>
/// <returns></returns>
private static bool IsPixelFormatIndexed(PixelFormat imgPixelFormat)
{
PixelFormat[] indexedPixelFormats = {
PixelFormat.Undefined,
PixelFormat.DontCare,
PixelFormat.Format16bppArgb1555,
PixelFormat.Format1bppIndexed,
PixelFormat.Format4bppIndexed,
PixelFormat.Format8bppIndexed
};
// 遍历匹配
foreach (PixelFormat pf in indexedPixelFormats)
if (pf.Equals(imgPixelFormat))
return true;
return false;
}
/// <summary>
/// 将原图未索引像素格式之类的Image转化为Bitmap
/// </summary>
/// <param name="image">图像实体</param>
/// <returns>位图实体</returns>
private static Bitmap RedrawBitmapByImage(Image image)
{
Bitmap bmp = new Bitmap(image.Width, image.Height, PixelFormat.Format32bppArgb);
using (Graphics g = Graphics.FromImage(bmp))
{
g.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.HighQualityBicubic;
g.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.HighQuality;
g.CompositingQuality = System.Drawing.Drawing2D.CompositingQuality.HighQuality;
g.DrawImage(image, 0, 0);
}
return bmp;
}
/// <summary>
/// 保证得到内部统一使用的文件扩展格式
/// </summary>
/// <param name="extensionName"></param>
/// <returns></returns>
private static string TransferContentTypeToUnifyExName(string contentType)
{
string exName = string.Empty;
switch (contentType.ToLower())
{
case "image/jpeg":
case "image/pjpeg":
exName = ".jpg";
break;
case "image/gif":
exName = ".gif";
break;
case "image/x-png":
case "image/png":
exName = ".png";
break;
default:
exName = contentType;
break;
}
return exName;
/// 获取编码参数数组
/// </summary>
/// <returns></returns>
private static EncoderParameters GetEncoderParameters()
{
EncoderParameters eps = new EncoderParameters(1);
EncoderParameter ep = new EncoderParameter(Encoder.Quality, _imageSaveQualityValue);
eps.Param[0] = ep;
return eps;
}
/// <summary>
/// 根据图片格式获取编码信息
/// </summary>
/// <param name="mimeType">图片格式</param>
/// <returns>编码信息</returns>
private static ImageCodecInfo GetEncoderInfo(String mimeType)
{
int j;
ImageCodecInfo[] encoders;
encoders = ImageCodecInfo.GetImageEncoders();
for (j = 0; j < encoders.Length; ++j)
{
if (encoders[j].MimeType == mimeType)
return encoders[j];
}
return null;
}
/// <summary>
/// 获取最终图片保存的图像格式
/// </summary>
/// <param name="imageExtensionName">图片扩展名称</param>
/// <returns>图片格式</returns>
private static ImageCodecInfo GetFinalImageCodecInfo(string imageExtensionName)
{
switch (imageExtensionName)
{
case ".gif":
return GetEncoderInfo("image/gif");
case ".png":
return GetEncoderInfo("image/png");
case ".jpg":
default:
return GetEncoderInfo("image/jpeg");
}
}
/// <summary>
/// 获取文字画刷
/// </summary>
/// <param name="alpha">透明度</param>
/// <returns></returns>
private static SolidBrush GetTextBrush(float alpha)
{
// 从四个 ARGB 分量(alpha、红色、绿色和蓝色)值创建 Color 结构,这里设置透明度为153
// 这个画笔为描绘正式文字的笔刷,呈白色
SolidBrush semiTransBrush = new SolidBrush(Color.FromArgb(Convert.ToInt32(255 * alpha), Color.White));
return semiTransBrush;
}
/// <summary>
/// 获取阴影画刷
/// </summary>
/// <returns></returns>
private static SolidBrush GetShadowBrush()
{
// SolidBrush:定义单色画笔。画笔用于填充图形形状,如矩形、椭圆、扇形、多边形和封闭路径。
// 这个画笔为描绘阴影的画笔,呈灰色
return new SolidBrush(Color.FromArgb(153, Color.Blue));
}
/// <summary>
/// 获取文本布局信息
/// </summary>
/// <returns></returns>
private static StringFormat GetStringFormat()
{
// 封装文本布局信息(如对齐、文字方向和 Tab 停靠位),显示操作(如省略号插入和国家标准 (National) 数字替换)和 OpenType 功能
StringFormat StrFormat = new StringFormat();
StrFormat.Alignment = StringAlignment.Center;
return StrFormat;
}
/// <summary>
/// Get image attribute instance.
/// </summary>
/// <param name="alpha">transparency value</param>
/// <returns></returns>
private static ImageAttributes GetImageAttributesInstance(float alpha)
{
// imageattributes instance which will control the related infomations for image.
ImageAttributes imageAttributes = new ImageAttributes();
// 图片映射:水印图被定义成拥有绿色背景色的图片被替换成透明
ColorMap colorMap = new ColorMap();
colorMap.OldColor = Color.FromArgb(255, 0, 255, 0);
colorMap.NewColor = Color.FromArgb(0, 0, 0, 0);
imageAttributes.SetRemapTable(new ColorMap[] { colorMap }, ColorAdjustType.Bitmap);
float[][] colorMatrixElements = new float[][]
{
new float[] {1.0f, 0.0f, 0.0f, 0.0f, 0.0f}, // red红色
new float[] {0.0f, 1.0f, 0.0f, 0.0f, 0.0f}, // green绿色
new float[] {0.0f, 0.0f, 1.0f, 0.0f, 0.0f}, // blue蓝色
new float[] {0.0f, 0.0f, 0.0f, alpha, 0.0f}, // 透明度
new float[] {0.0f, 0.0f, 0.0f, 0.0f, 1.0f}
};
// ColorMatrix:定义包含 RGBA 空间坐标的 5 x 5 矩阵。
// ImageAttributes:类的若干方法通过使用颜色矩阵调整图像颜色。
imageAttributes.SetColorMatrix(new ColorMatrix(colorMatrixElements), ColorMatrixFlag.Default, ColorAdjustType.Bitmap);
return imageAttributes;
}
/// <summary>
/// Calculate the watermark image position.
/// </summary>
/// <param name="position">position</param>
/// <param name="srcWidth">source image width</param>
/// <param name="srcHeight">source image height</param>
/// <param name="wmWidth">watermark image width</param>
/// <param name="wmHeight">watermark image height</param>
/// <param name="xPosOfWm">final x position</param>
/// <param name="yPosOfWm">final y position</param>
private static void GetWatermarkImagePosition(ImagePosition position, int srcWidth, int srcHeight, int wmWidth, int wmHeight, out int xPosOfWm, out int yPosOfWm)
{
switch (position)
{
case ImagePosition.BottomMiddle:
xPosOfWm = (srcWidth - wmWidth) / 2;
yPosOfWm = srcHeight - wmHeight - 10;
break;
case ImagePosition.Center:
xPosOfWm = (srcWidth - wmWidth) / 2;
yPosOfWm = (srcHeight - wmHeight) / 2;
break;
case ImagePosition.LeftBottom:
xPosOfWm = 10;
yPosOfWm = srcHeight - wmHeight - 10;
break;
case ImagePosition.LeftTop:
xPosOfWm = 10;
yPosOfWm = 10;
break;
case ImagePosition.RightTop:
xPosOfWm = srcWidth - wmWidth - 10;
yPosOfWm = 10;
break;
case ImagePosition.RigthBottom:
xPosOfWm = srcWidth - wmWidth - 10;
yPosOfWm = srcHeight - wmHeight - 10;
break;
case ImagePosition.TopMiddle:
xPosOfWm = (srcWidth - wmWidth) / 2;
yPosOfWm = 10;
break;
default:
xPosOfWm = 10;
yPosOfWm = srcHeight - wmHeight - 10;
break;
}
}
/// <summary>
/// Calculate the watermark image position.
/// </summary>
/// <param name="position">position</param>
/// <param name="srcWidth">source image width</param>
/// <param name="srcHeight">source image height</param>
/// <param name="wmWidth">watermark image width</param>
/// <param name="wmHeight">watermark image height</param>
/// <param name="xPosOfWm">final x position</param>
/// <param name="yPosOfWm">final y position</param>
private static void GetWatermarkTextPosition(ImagePosition position, int srcWidth, int srcHeight, float wmWidth, float wmHeight, out float xPosOfWm, out float yPosOfWm)
{
switch (position)
{
case ImagePosition.BottomMiddle:
xPosOfWm = srcWidth / 2;
yPosOfWm = srcHeight - wmHeight - 10;
break;
case ImagePosition.Center:
xPosOfWm = srcWidth / 2;
yPosOfWm = srcHeight / 2;
break;
case ImagePosition.LeftBottom:
xPosOfWm = wmWidth;
yPosOfWm = srcHeight - wmHeight - 10;
break;
case ImagePosition.LeftTop:
xPosOfWm = wmWidth / 2;
yPosOfWm = wmHeight / 2;
break;
case ImagePosition.RightTop:
xPosOfWm = srcWidth - wmWidth - 10;
yPosOfWm = wmHeight;
break;
case ImagePosition.RigthBottom:
xPosOfWm = srcWidth - wmWidth - 10;
yPosOfWm = srcHeight - wmHeight - 10;
break;
case ImagePosition.TopMiddle:
xPosOfWm = srcWidth / 2;
yPosOfWm = wmWidth;
break;
default:
xPosOfWm = wmWidth;
yPosOfWm = srcHeight - wmHeight - 10;
break;
}
}
/// <summary>
/// Check image extension type.
/// </summary>
/// <param name="sourceImagePath">image path</param>
/// <returns>examine result</returns>
private static bool CheckImageExtensionType(string imagePath)
{
string fileExtensionType = System.IO.Path.GetExtension(imagePath).ToLower();
return (System.IO.File.Exists(imagePath) && (fileExtensionType == ".gif" || fileExtensionType == ".jpg" || fileExtensionType == ".png"));
}
/// <summary>
/// 获取Bitmap的MemoryStream
/// </summary>
/// <param name="finalImage"></param>
/// <returns></returns>
private static MemoryStream GetMemoryStreamFromBitmap(Bitmap finalImage, string sourceImageFileExName)
{
MemoryStream ms = new MemoryStream();
// 将位图保存到数据流中
finalImage.Save(ms, GetFinalImageCodecInfo(sourceImageFileExName), GetEncoderParameters());
return ms;
}
/// <summary>
/// 获取源图片和水印图片的数据流
/// </summary>
/// <param name="parameters">参数实例</param>
/// <param name="sourceImageStream">源图片数据流</param>
/// <param name="waterImageStream">水印图片数据流</param>
/// <param name="errorMsg">错误信息</param>
/// <returns>是否获取成功</returns>
private static bool GetSourceAndWatermarkImageStream(ImageWatermarkParameters parameters,
out MemoryStream sourceImageStream, out MemoryStream waterImageStream, out string errorMsg)
{
errorMsg = string.Empty;
// 根据是否设置图片路径来判断如何获取图片数据流,分别获取源图片和水印图片的数据流。
string scErrMsg = string.Empty, wmErrMsg = string.Empty;
sourceImageStream = parameters.SourceImageStream == null ?
GetImageMemoryStream(parameters.SourceImagePath, out scErrMsg) : parameters.SourceImageStream;
waterImageStream = parameters.WatermarkImageStream == null ?
GetImageMemoryStream(parameters.WatermarkImagePath, out wmErrMsg) : parameters.WatermarkImageStream;
if (!string.IsNullOrEmpty(scErrMsg) || !string.IsNullOrEmpty(wmErrMsg))
{
errorMsg = "通过图片路径获取数据流失败:" + scErrMsg + ";" + wmErrMsg;
return false;
}
return true;
}
/// <summary>
/// 判断图片的PixelFormat 是否在 引发异常的 PixelFormat 之中
/// </summary>
/// <param name="imgPixelFormat">原图片的PixelFormat</param>
/// <returns></returns>
private static bool IsPixelFormatIndexed(PixelFormat imgPixelFormat)
{
PixelFormat[] indexedPixelFormats = {
PixelFormat.Undefined,
PixelFormat.DontCare,
PixelFormat.Format16bppArgb1555,
PixelFormat.Format1bppIndexed,
PixelFormat.Format4bppIndexed,
PixelFormat.Format8bppIndexed
};
// 遍历匹配
foreach (PixelFormat pf in indexedPixelFormats)
if (pf.Equals(imgPixelFormat))
return true;
return false;
}
/// <summary>
/// 将原图未索引像素格式之类的Image转化为Bitmap
/// </summary>
/// <param name="image">图像实体</param>
/// <returns>位图实体</returns>
private static Bitmap RedrawBitmapByImage(Image image)
{
Bitmap bmp = new Bitmap(image.Width, image.Height, PixelFormat.Format32bppArgb);
using (Graphics g = Graphics.FromImage(bmp))
{
g.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.HighQualityBicubic;
g.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.HighQuality;
g.CompositingQuality = System.Drawing.Drawing2D.CompositingQuality.HighQuality;
g.DrawImage(image, 0, 0);
}
return bmp;
}
/// <summary>
/// 保证得到内部统一使用的文件扩展格式
/// </summary>
/// <param name="extensionName"></param>
/// <returns></returns>
private static string TransferContentTypeToUnifyExName(string contentType)
{
string exName = string.Empty;
switch (contentType.ToLower())
{
case "image/jpeg":
case "image/pjpeg":
exName = ".jpg";
break;
case "image/gif":
exName = ".gif";
break;
case "image/x-png":
case "image/png":
exName = ".png";
break;
default:
exName = contentType;
break;
}
return exName;
第三部分:水印功能处理类 -> 主体处理函数部分
View Code
#region 添加水印功能主体函数
/// <summary>
/// 为图片添加文字水印
/// </summary>
/// <param name="parameters">文字水印相关参数体</param>
/// <param name="errMsg">错误信息</param>
/// <returns>添加完水印的位图对象</returns>
private static Bitmap AddWatermarkTextForSourceImage(TextWatermarkParameters parameters, out string errMsg)
{
Image srcImage = null;
Graphics srcGraphics = null;
errMsg = string.Empty;
try
{
//
// 获取源图片数据流
MemoryStream scMs = parameters.SourceImageStream == null ?
GetImageMemoryStream(parameters.SourceImagePath, out errMsg) : parameters.SourceImageStream;
if (scMs == null && !string.IsNullOrEmpty(errMsg))
throw new InvalidDataException("获取图片数据流失败!");
//
//
srcImage = Image.FromStream(scMs as Stream);
// 新建位图并设定分辨率,需要根据图像的像素格式来判断是否需要重新绘制该图像
Bitmap srcBitmap = (IsPixelFormatIndexed(srcImage.PixelFormat)) ?
RedrawBitmapByImage(srcImage) :
new Bitmap(srcImage.Width, srcImage.Height, srcImage.PixelFormat);
srcBitmap.SetResolution(srcImage.HorizontalResolution, srcImage.VerticalResolution);
// 封装一个GDI+绘图图面,并设置图形品质
srcGraphics = Graphics.FromImage(srcBitmap);
srcGraphics.SmoothingMode = SmoothingMode.AntiAlias;
// 向源图片绘制到位图中
srcGraphics.DrawImage(srcImage, new Rectangle(0, 0, srcImage.Width, srcImage.Height), 0, 0, srcImage.Width, srcImage.Height, GraphicsUnit.Pixel);
//
// 矩形的宽度和高度,SizeF有三个属性,分别为Height高,width宽,IsEmpty是否为空
SizeF crSize = srcGraphics.MeasureString(parameters.WatermarkText, parameters.WmTextFont);
// 获取水印文字的起始位置
float xPosOfWm, yPosOfWm = 0;
GetWatermarkTextPosition(parameters.WmPosition, srcImage.Width, srcImage.Height, crSize.Width, crSize.Height, out xPosOfWm, out yPosOfWm);
//
// 文本样式
StringFormat vmTextFormat = GetStringFormat();
// 阴影画刷
SolidBrush shadowBrush = GetShadowBrush();
// 文字画刷
SolidBrush semiTransBrush = GetTextBrush(parameters.Alpha);
// 第一步,绘制阴影
srcGraphics.DrawString(parameters.WatermarkText, parameters.WmTextFont, shadowBrush,
new PointF(xPosOfWm + parameters.TextShadowWidth, yPosOfWm + parameters.TextShadowWidth), vmTextFormat);
// 第二步,绘制文字
srcGraphics.DrawString(parameters.WatermarkText, parameters.WmTextFont, semiTransBrush, new PointF(xPosOfWm, yPosOfWm), vmTextFormat);
return srcBitmap;
}
catch (Exception e)
{
errMsg = e.Message.ToString();
return null;
}
finally
{ // 释放资源
if (srcImage != null)
srcImage.Dispose();
if (srcGraphics != null)
srcGraphics.Dispose();
}
}
/// <summary>
/// 为源图片添加图片水印
/// </summary>
/// <param name="parameters">参数集合</param>
/// <param name="errMsg">错误消息</param>
/// <returns>添加完水印的位图对象</returns>
private static Bitmap AddWatermarkImageForSourceImage(ImageWatermarkParameters parameters, out string errMsg)
{
Image sourceImage = null;
Bitmap sourceBitmap = null;
Graphics sourceGraphics = null;
Image watermarkImage = null;
Graphics watermarkGraphics = null;
errMsg = string.Empty;
try
{
// 获取源图片和水印图片的数据流
MemoryStream sourceImageStream, waterImageStream = null;
if (GetSourceAndWatermarkImageStream(parameters, out sourceImageStream, out waterImageStream, out errMsg) == false)
throw new InvalidDataException(errMsg);
sourceImage = Image.FromStream(sourceImageStream as Stream);
// 实例化一个与源图大小一样、分辨率一致的位图对象,并将其载入Graphics对象中,以便后续编辑;
// 需要根据图像的像素格式来判断是否需要重新绘制该图像
sourceBitmap = (IsPixelFormatIndexed(sourceImage.PixelFormat)) ?
RedrawBitmapByImage(sourceImage) :
new Bitmap(sourceImage.Width, sourceImage.Height, sourceImage.PixelFormat);
sourceBitmap.SetResolution(sourceImage.HorizontalResolution, sourceImage.VerticalResolution);
sourceGraphics = Graphics.FromImage(sourceBitmap);
// SmoothingMode:指定是否将平滑处理(消除锯齿)应用于直线、曲线和已填充区域的边缘。
// 成员名称 说明
// AntiAlias 指定消除锯齿的呈现。
// Default 指定不消除锯齿。
// HighQuality 指定高质量、低速度呈现。
// HighSpeed 指定高速度、低质量呈现。
// Invalid 指定一个无效模式。
// None 指定不消除锯齿。
sourceGraphics.SmoothingMode = SmoothingMode.AntiAlias;
// 将源图像Image对象添加到绘图板中
sourceGraphics.DrawImage(sourceImage, new Rectangle(0, 0, sourceImage.Width, sourceImage.Height),
0, 0, sourceImage.Width, sourceImage.Height, GraphicsUnit.Pixel);
//
// 按照源图片的操作方式,需要创建水印图片的Image对象、位图对象,
// 只是需要根据输入参数来调整水印图片在源图片中的位置、显示效果等。
watermarkImage = new Bitmap(waterImageStream);
// 这里尤其注意,生成新位图的时候,载入的是已经添加了源图片作为背景的位图哦!
// 并将设定好分辨率的位图载入到新的Graphics实例中,以进一步绘制水印。
Bitmap watermarkBitmap = new Bitmap(sourceBitmap);
watermarkBitmap.SetResolution(sourceImage.HorizontalResolution, sourceImage.VerticalResolution);
watermarkGraphics = Graphics.FromImage(watermarkBitmap);
// 通过imageAttributes实例来设定水印图片的绘制效果,包括位置和现实效果等
ImageAttributes imageAttributes = GetImageAttributesInstance(parameters.Alpha);
// 获取水印图片的起始位置
int xPosOfWm, yPosOfWm = 0;
GetWatermarkImagePosition(parameters.WmPosition, sourceImage.Width, sourceImage.Height, watermarkImage.Width, watermarkImage.Height, out xPosOfWm, out yPosOfWm);
// 绘制水印图片
watermarkGraphics.DrawImage(watermarkImage, new Rectangle(xPosOfWm, yPosOfWm, watermarkImage.Width, watermarkImage.Height),
0, 0, watermarkImage.Width, watermarkImage.Height, GraphicsUnit.Pixel, imageAttributes);
return watermarkBitmap;
}
catch (Exception e)
{
errMsg = e.Message.ToString();
return null;
}
finally
{
// 释放
if (sourceImage != null)
sourceImage.Dispose();
if (sourceBitmap != null)
sourceBitmap.Dispose();
if (sourceGraphics != null)
sourceGraphics.Dispose();
if (watermarkImage != null)
watermarkImage.Dispose();
if (watermarkGraphics != null)
watermarkGraphics.Dispose();
}
}
/// <summary>
/// 为图片添加文字水印
/// </summary>
/// <param name="parameters">文字水印相关参数体</param>
/// <param name="errMsg">错误信息</param>
/// <returns>添加完水印的位图对象</returns>
private static Bitmap AddWatermarkTextForSourceImage(TextWatermarkParameters parameters, out string errMsg)
{
Image srcImage = null;
Graphics srcGraphics = null;
errMsg = string.Empty;
try
{
//
// 获取源图片数据流
MemoryStream scMs = parameters.SourceImageStream == null ?
GetImageMemoryStream(parameters.SourceImagePath, out errMsg) : parameters.SourceImageStream;
if (scMs == null && !string.IsNullOrEmpty(errMsg))
throw new InvalidDataException("获取图片数据流失败!");
//
//
srcImage = Image.FromStream(scMs as Stream);
// 新建位图并设定分辨率,需要根据图像的像素格式来判断是否需要重新绘制该图像
Bitmap srcBitmap = (IsPixelFormatIndexed(srcImage.PixelFormat)) ?
RedrawBitmapByImage(srcImage) :
new Bitmap(srcImage.Width, srcImage.Height, srcImage.PixelFormat);
srcBitmap.SetResolution(srcImage.HorizontalResolution, srcImage.VerticalResolution);
// 封装一个GDI+绘图图面,并设置图形品质
srcGraphics = Graphics.FromImage(srcBitmap);
srcGraphics.SmoothingMode = SmoothingMode.AntiAlias;
// 向源图片绘制到位图中
srcGraphics.DrawImage(srcImage, new Rectangle(0, 0, srcImage.Width, srcImage.Height), 0, 0, srcImage.Width, srcImage.Height, GraphicsUnit.Pixel);
//
// 矩形的宽度和高度,SizeF有三个属性,分别为Height高,width宽,IsEmpty是否为空
SizeF crSize = srcGraphics.MeasureString(parameters.WatermarkText, parameters.WmTextFont);
// 获取水印文字的起始位置
float xPosOfWm, yPosOfWm = 0;
GetWatermarkTextPosition(parameters.WmPosition, srcImage.Width, srcImage.Height, crSize.Width, crSize.Height, out xPosOfWm, out yPosOfWm);
//
// 文本样式
StringFormat vmTextFormat = GetStringFormat();
// 阴影画刷
SolidBrush shadowBrush = GetShadowBrush();
// 文字画刷
SolidBrush semiTransBrush = GetTextBrush(parameters.Alpha);
// 第一步,绘制阴影
srcGraphics.DrawString(parameters.WatermarkText, parameters.WmTextFont, shadowBrush,
new PointF(xPosOfWm + parameters.TextShadowWidth, yPosOfWm + parameters.TextShadowWidth), vmTextFormat);
// 第二步,绘制文字
srcGraphics.DrawString(parameters.WatermarkText, parameters.WmTextFont, semiTransBrush, new PointF(xPosOfWm, yPosOfWm), vmTextFormat);
return srcBitmap;
}
catch (Exception e)
{
errMsg = e.Message.ToString();
return null;
}
finally
{ // 释放资源
if (srcImage != null)
srcImage.Dispose();
if (srcGraphics != null)
srcGraphics.Dispose();
}
}
/// <summary>
/// 为源图片添加图片水印
/// </summary>
/// <param name="parameters">参数集合</param>
/// <param name="errMsg">错误消息</param>
/// <returns>添加完水印的位图对象</returns>
private static Bitmap AddWatermarkImageForSourceImage(ImageWatermarkParameters parameters, out string errMsg)
{
Image sourceImage = null;
Bitmap sourceBitmap = null;
Graphics sourceGraphics = null;
Image watermarkImage = null;
Graphics watermarkGraphics = null;
errMsg = string.Empty;
try
{
// 获取源图片和水印图片的数据流
MemoryStream sourceImageStream, waterImageStream = null;
if (GetSourceAndWatermarkImageStream(parameters, out sourceImageStream, out waterImageStream, out errMsg) == false)
throw new InvalidDataException(errMsg);
sourceImage = Image.FromStream(sourceImageStream as Stream);
// 实例化一个与源图大小一样、分辨率一致的位图对象,并将其载入Graphics对象中,以便后续编辑;
// 需要根据图像的像素格式来判断是否需要重新绘制该图像
sourceBitmap = (IsPixelFormatIndexed(sourceImage.PixelFormat)) ?
RedrawBitmapByImage(sourceImage) :
new Bitmap(sourceImage.Width, sourceImage.Height, sourceImage.PixelFormat);
sourceBitmap.SetResolution(sourceImage.HorizontalResolution, sourceImage.VerticalResolution);
sourceGraphics = Graphics.FromImage(sourceBitmap);
// SmoothingMode:指定是否将平滑处理(消除锯齿)应用于直线、曲线和已填充区域的边缘。
// 成员名称 说明
// AntiAlias 指定消除锯齿的呈现。
// Default 指定不消除锯齿。
// HighQuality 指定高质量、低速度呈现。
// HighSpeed 指定高速度、低质量呈现。
// Invalid 指定一个无效模式。
// None 指定不消除锯齿。
sourceGraphics.SmoothingMode = SmoothingMode.AntiAlias;
// 将源图像Image对象添加到绘图板中
sourceGraphics.DrawImage(sourceImage, new Rectangle(0, 0, sourceImage.Width, sourceImage.Height),
0, 0, sourceImage.Width, sourceImage.Height, GraphicsUnit.Pixel);
//
// 按照源图片的操作方式,需要创建水印图片的Image对象、位图对象,
// 只是需要根据输入参数来调整水印图片在源图片中的位置、显示效果等。
watermarkImage = new Bitmap(waterImageStream);
// 这里尤其注意,生成新位图的时候,载入的是已经添加了源图片作为背景的位图哦!
// 并将设定好分辨率的位图载入到新的Graphics实例中,以进一步绘制水印。
Bitmap watermarkBitmap = new Bitmap(sourceBitmap);
watermarkBitmap.SetResolution(sourceImage.HorizontalResolution, sourceImage.VerticalResolution);
watermarkGraphics = Graphics.FromImage(watermarkBitmap);
// 通过imageAttributes实例来设定水印图片的绘制效果,包括位置和现实效果等
ImageAttributes imageAttributes = GetImageAttributesInstance(parameters.Alpha);
// 获取水印图片的起始位置
int xPosOfWm, yPosOfWm = 0;
GetWatermarkImagePosition(parameters.WmPosition, sourceImage.Width, sourceImage.Height, watermarkImage.Width, watermarkImage.Height, out xPosOfWm, out yPosOfWm);
// 绘制水印图片
watermarkGraphics.DrawImage(watermarkImage, new Rectangle(xPosOfWm, yPosOfWm, watermarkImage.Width, watermarkImage.Height),
0, 0, watermarkImage.Width, watermarkImage.Height, GraphicsUnit.Pixel, imageAttributes);
return watermarkBitmap;
}
catch (Exception e)
{
errMsg = e.Message.ToString();
return null;
}
finally
{
// 释放
if (sourceImage != null)
sourceImage.Dispose();
if (sourceBitmap != null)
sourceBitmap.Dispose();
if (sourceGraphics != null)
sourceGraphics.Dispose();
if (watermarkImage != null)
watermarkImage.Dispose();
if (watermarkGraphics != null)
watermarkGraphics.Dispose();
}
}
第四部分:水印功能处理类 -> 对外公开方法(即调用方法)
View Code
#region 主要公开方法
/// <summary>
/// 图片保存质量值
/// </summary>
private static int _imageSaveQualityValue = 100;
/// <summary>
/// 为图片添加图片水印
/// </summary>
/// <param name="parameters">添加图片水印相关参数体</param>
/// <param name="errorMsg">错误信息</param>
/// <returns>已加水印的图片数据流</returns>
public static MemoryStream DrawImage(ImageWatermarkParameters parameters, out string errorMsg)
{
errorMsg = string.Empty;
try
{
// 参数检查
if (!parameters.CheckAndSetDefault(out errorMsg))
throw new InvalidDataException(errorMsg);
// 为源图片添加图片水印
Bitmap finalImage = AddWatermarkImageForSourceImage(parameters, out errorMsg);
if (finalImage == null && !string.IsNullOrEmpty(errorMsg))
throw new InvalidDataException("生成水印图片失败:" + errorMsg);
// 获取Bitmap的MemoryStream
return GetMemoryStreamFromBitmap(finalImage, parameters.SourceImageFileExtensionName);
}
catch (Exception ex)
{
errorMsg = ex.Message.ToString();
return null;
}
}
/// <summary>
/// 为图片添加文字水印
/// </summary>
/// <param name="parameters">文字水印过程需要的参数体</param>
/// <param name="errorMsg">异常信息</param>
/// <returns>已加水印的图片数据流</returns>
public static MemoryStream DrawText(TextWatermarkParameters parameters, out string errorMsg)
{
errorMsg = string.Empty;
try
{
// 参数检查
if (!parameters.CheckAndSetDefault(out errorMsg))
throw new InvalidDataException(errorMsg);
// 为源图片添加文字水印
Bitmap finalImage = AddWatermarkTextForSourceImage(parameters, out errorMsg);
if (finalImage == null && !string.IsNullOrEmpty(errorMsg))
throw new InvalidDataException("生成水印图片失败:" + errorMsg);
return GetMemoryStreamFromBitmap(finalImage, parameters.SourceImageFileExtensionName);
}
catch (Exception ex)
{
errorMsg = ex.Message.ToString();
return null;
}
}
/// <summary>
/// 根据文件路径获取图片数据流
/// </summary>
/// <param name="filePath"></param>
/// <returns></returns>
private static MemoryStream GetImageMemoryStream(string filePath, out string errorMsg)
{
MemoryStream ms = null;
errorMsg = string.Empty;
try
{
using (FileStream fs = File.OpenRead(filePath))
{ // 读取图片数据流
byte[] buffer = new byte[fs.Length];
fs.Read(buffer, 0, buffer.Length);
ms.Write(buffer, 0, buffer.Length);
}
return ms;
}
catch (Exception e)
{
errorMsg = e.Message.ToString();
return null;
}
}
/// <summary>
/// 图片保存质量值
/// </summary>
private static int _imageSaveQualityValue = 100;
/// <summary>
/// 为图片添加图片水印
/// </summary>
/// <param name="parameters">添加图片水印相关参数体</param>
/// <param name="errorMsg">错误信息</param>
/// <returns>已加水印的图片数据流</returns>
public static MemoryStream DrawImage(ImageWatermarkParameters parameters, out string errorMsg)
{
errorMsg = string.Empty;
try
{
// 参数检查
if (!parameters.CheckAndSetDefault(out errorMsg))
throw new InvalidDataException(errorMsg);
// 为源图片添加图片水印
Bitmap finalImage = AddWatermarkImageForSourceImage(parameters, out errorMsg);
if (finalImage == null && !string.IsNullOrEmpty(errorMsg))
throw new InvalidDataException("生成水印图片失败:" + errorMsg);
// 获取Bitmap的MemoryStream
return GetMemoryStreamFromBitmap(finalImage, parameters.SourceImageFileExtensionName);
}
catch (Exception ex)
{
errorMsg = ex.Message.ToString();
return null;
}
}
/// <summary>
/// 为图片添加文字水印
/// </summary>
/// <param name="parameters">文字水印过程需要的参数体</param>
/// <param name="errorMsg">异常信息</param>
/// <returns>已加水印的图片数据流</returns>
public static MemoryStream DrawText(TextWatermarkParameters parameters, out string errorMsg)
{
errorMsg = string.Empty;
try
{
// 参数检查
if (!parameters.CheckAndSetDefault(out errorMsg))
throw new InvalidDataException(errorMsg);
// 为源图片添加文字水印
Bitmap finalImage = AddWatermarkTextForSourceImage(parameters, out errorMsg);
if (finalImage == null && !string.IsNullOrEmpty(errorMsg))
throw new InvalidDataException("生成水印图片失败:" + errorMsg);
return GetMemoryStreamFromBitmap(finalImage, parameters.SourceImageFileExtensionName);
}
catch (Exception ex)
{
errorMsg = ex.Message.ToString();
return null;
}
}
/// <summary>
/// 根据文件路径获取图片数据流
/// </summary>
/// <param name="filePath"></param>
/// <returns></returns>
private static MemoryStream GetImageMemoryStream(string filePath, out string errorMsg)
{
MemoryStream ms = null;
errorMsg = string.Empty;
try
{
using (FileStream fs = File.OpenRead(filePath))
{ // 读取图片数据流
byte[] buffer = new byte[fs.Length];
fs.Read(buffer, 0, buffer.Length);
ms.Write(buffer, 0, buffer.Length);
}
return ms;
}
catch (Exception e)
{
errorMsg = e.Message.ToString();
return null;
}
}
第五部分:添加水印功能调用示例
View Code
string errorMsg = string.Empty;
string origenalImagePath = "D:\\sourcePicture.jpg";
float alpha = 0.5F;
// 图片水印
string waterPicturePath = "D:\\watermarkPicture.jpg";
WatermarkImageManager.ImageWatermarkParameters image_parameters =
new WatermarkImageManager.ImageWatermarkParameters(FileToStream(origenalImagePath), FileToStream(waterPicturePath), ".jpg", alpha, WatermarkImageManager.ImagePosition.LeftBottom);
MemoryStream wmImageMS = WatermarkImageManager.DrawImage(image_parameters, out errorMsg);
// 文字水印
string wmText = "水印文字";
Font font = new Font("arial", 30, FontStyle.Bold);
WatermarkImageManager.TextWatermarkParameters text_parameters =
new WatermarkImageManager.TextWatermarkParameters(FileToStream(origenalImagePath), ".jpg", wmText, alpha, WatermarkImageManager.ImagePosition.Center, font);
MemoryStream wmTextMS = WatermarkImageManager.DrawText(text_parameters, out
string origenalImagePath = "D:\\sourcePicture.jpg";
float alpha = 0.5F;
// 图片水印
string waterPicturePath = "D:\\watermarkPicture.jpg";
WatermarkImageManager.ImageWatermarkParameters image_parameters =
new WatermarkImageManager.ImageWatermarkParameters(FileToStream(origenalImagePath), FileToStream(waterPicturePath), ".jpg", alpha, WatermarkImageManager.ImagePosition.LeftBottom);
MemoryStream wmImageMS = WatermarkImageManager.DrawImage(image_parameters, out errorMsg);
// 文字水印
string wmText = "水印文字";
Font font = new Font("arial", 30, FontStyle.Bold);
WatermarkImageManager.TextWatermarkParameters text_parameters =
new WatermarkImageManager.TextWatermarkParameters(FileToStream(origenalImagePath), ".jpg", wmText, alpha, WatermarkImageManager.ImagePosition.Center, font);
MemoryStream wmTextMS = WatermarkImageManager.DrawText(text_parameters, out
最后把该水印处理类的代码文件附上,方便大家调整,同时支持,传入MemoryStream或输入文件路径两种形式的数据,详情请看参数结构类部分。
点击下载WatermarkImageManager.cs类文件
希望有所帮助~