写在最前面
上周零零碎碎花了一周的时间研究水印的开发,现在终于写了个入门级的demo,做下笔记同时分享出来供大家参考。
demo是在我上次写的 java实用案例之文件导入导出(poi方式) 框架基础上搭建的,基于spring+springmvc。如果有错误还请大家指正。
最后源码地址在: https://github.com/allanzhuo/myport.git。
简单介绍
水印开发是web开发中一种比较常见的功能,实现的代码很简单,具体的实现步骤我也会以代码为基础详细讲述。其实以我个人的理解,我把水印的类型和开发流程分为以下几种。
水印的类型:
单文字水印
单图片水印
多文字水印
多图片水印
水印的开发流程:
- 创建图片缓存对象
- 创建java绘图工具对象
- 使用绘图工具工具对象将原图绘制到缓存图片对象
- 使用绘图工具对象将水印(文字/图片)绘制到缓存图片
- 创建图像编码工具类
- 使用图像编码工具类,输出缓存图像到目标文件
效果图:
上传页:
原图:
单文字水印:
单图片水印:
多文字水印:
多图片水印:
单文字水印开发
所谓但文字水印,就是在一张图片上添加一条文字水印。其中我们主要的流程是通过imageio工具类解码对应的图片,然后创建bufferimage对象,通过bufferimage对象创建graphics2d对象,再通过graphics2d对象绘制原图到bufferimage对象。然后,我们还可以使用graphics2d对象来设置水印的相关信息,如水印内容、字体大小、字体风格等。
这里需要说明的是我们需要计算水印文本的宽度,中文长度即文本宽度,英文长度为文本宽度的二分之一。具体可以参考我源码中的相关内容。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
//计算水印文本长度 //1、中文长度即文本长度 2、英文长度为文本长度二分之一 public int gettextlength(string text){ //水印文字长度 int length = text.length(); for ( int i = 0 ; i < text.length(); i++) { string s =string.valueof(text.charat(i)); if (s.getbytes().length> 1 ) { length++; } } length = length% 2 == 0 ?length/ 2 :length/ 2 + 1 ; return length; } |
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
|
//添加单条文字水印方法 public string textwatermark(multipartfile myfile,string imagefilename) { inputstream is = null ; outputstream os = null ; int x = 636 ; int y = 700 ; try { //使用imageio解码图片 image image = imageio.read(myfile.getinputstream()); //计算原始图片宽度长度 int width = image.getwidth( null ); int height = image.getheight( null ); //创建图片缓存对象 bufferedimage bufferedimage = new bufferedimage(width, height, bufferedimage.type_int_rgb); //创建java绘图工具对象 graphics2d graphics2d = bufferedimage.creategraphics(); //参数主要是,原图,坐标,宽高 graphics2d.drawimage(image, 0 , 0 , width, height, null ); graphics2d.setfont( new font(font_name, font_style, font_size)); graphics2d.setcolor(font_color); //使用绘图工具将水印绘制到图片上 //计算文字水印宽高值 int waterwidth = font_size*gettextlength(mark_text); int waterheight = font_size; //计算水印与原图高宽差 int widthdiff = width-waterwidth; int heightdiff = height-waterheight; //水印坐标设置 if (x > widthdiff) { x = widthdiff; } if (y > heightdiff) { y = heightdiff; } //水印透明设置 graphics2d.setcomposite(alphacomposite.getinstance(alphacomposite.src_atop, alpha)); //纵坐标在下方,不增加字体高度会靠上 graphics2d.drawstring(mark_text, x, y+font_size); graphics2d.dispose(); os = new fileoutputstream(upload_path+ "/" +imagefilename); //创建图像编码工具类 jpegimageencoder en = jpegcodec.createjpegencoder(os); //使用图像编码工具类,输出缓存图像到目标文件 en.encode(bufferedimage); if (is!= null ){ is.close(); } if (os!= null ){ os.close(); } } catch (ioexception e) { e.printstacktrace(); } return "success" ; } |
单图片水印开发
单图片水印和上面单文字的代码流程大致一致,这里只讲解不同之处。
首先我们需要获得水印图片的路径,然后创建水印文件对象,同样通过imageio工具类解码水印图片,中间我们就不需要计算文本长宽了,因为单文字中的长宽即是我们水印图片的长宽。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
|
//水印图片路径 //水印坐标设置 string logopath = "/img/logo.png" ; string realpath = request.getsession().getservletcontext().getrealpath(logopath); file logo = new file(realpath); image imagelogo = imageio.read(logo); int widthlogo = imagelogo.getwidth( null ); int heightlogo = imagelogo.getheight( null ); int widthdiff = width-widthlogo; int heightdiff = height-heightlogo; //水印坐标设置 if (x > widthdiff) { x = widthdiff; } if (y > heightdiff) { y = heightdiff; } //水印透明设置 graphics2d.setcomposite(alphacomposite.getinstance(alphacomposite.src_atop, alpha)); graphics2d.drawimage(imagelogo, x, y, null ); |
多文字水印开发
其实多文字水印开发和单文字也是类似的,主要的不同点是我们需要将bufferimage对象进行旋转。因为绘制水印并不支持旋转水印绘制,所以我们需要对原图进行旋转绘制,然后通过循环,我们就可以将一个文字水印多次绘制在原图上了。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
//旋转原图,注意旋转角度为弧度制。后面两个参数为旋转的坐标中心 graphics2d.rotate(math.toradians( 30 ), bufferedimage.getwidth()/ 2 , bufferedimage.getheight()/ 2 ); int x = -width/ 2 ; int y = -height/ 2 ; while (x < width* 1.5 ){ y = -height/ 2 ; while (y < height* 1.5 ){ graphics2d.drawstring(mark_text, x, y); y+=waterheight+ 100 ; } x+=waterwidth+ 100 ; } |
多图片水印开发
与上文相同,多图片水印需要先读取水印图片,然后对水印设置透明度,在对原图进行旋转,然后通过循环,我们就可以将一个图片水印多次绘制在原图上。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
|
//水印图片路径 string logopath = "/img/logo.png" ; string realpath = request.getsession().getservletcontext().getrealpath(logopath); file logo = new file(realpath); image imagelogo = imageio.read(logo); int widthlogo = imagelogo.getwidth( null ); int heightlogo = imagelogo.getheight( null ); //水印透明设置 graphics2d.setcomposite(alphacomposite.getinstance(alphacomposite.src_atop, alpha)); graphics2d.rotate(math.toradians( 30 ), bufferedimage.getwidth()/ 2 , bufferedimage.getheight()/ 2 ); int x = -width/ 2 ; int y = -height/ 2 ; while (x < width* 1.5 ){ y = -height/ 2 ; while (y < height* 1.5 ){ graphics2d.drawimage(imagelogo, x, y, null ); y+=heightlogo+ 100 ; } x+=widthlogo+ 100 ; } |
业务类完整代码:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
|
import java.awt.alphacomposite; import java.awt.color; import java.awt.font; import java.awt.graphics2d; import java.awt.image; import java.awt.image.bufferedimage; import java.io.file; import java.io.fileoutputstream; import java.io.ioexception; import java.io.inputstream; import java.io.outputstream; import javax.imageio.imageio; import javax.servlet.http.httpservletrequest; import org.springframework.stereotype.service; import org.springframework.web.multipart.multipartfile; import com.allan.service.watermarkservice; import com.sun.image.codec.jpeg.jpegcodec; import com.sun.image.codec.jpeg.jpegimageencoder; @service public class watermarkserviceimpl implements watermarkservice{ //定义上传的文件夹 private static final string upload_path = "e:/save" ; //定义水印文字样式 private static final string mark_text = "小卖铺的老爷爷" ; private static final string font_name = "微软雅黑" ; private static final int font_style = font.bold; private static final int font_size = 60 ; private static final color font_color = color.black; private static final float alpha = 0 .3f; //1、上传图片 public string uploadimage(multipartfile myfile,string imagefilename) { inputstream is = null ; outputstream os = null ; try { is = myfile.getinputstream(); os = new fileoutputstream(upload_path+ "/" +imagefilename); byte [] buffer = new byte [ 1024 ]; int len = 0 ; while ((len=is.read(buffer))> 0 ){ os.write(buffer); } } catch (exception e){ e.printstacktrace(); } finally { if (is!= null ){ try { is.close(); } catch (ioexception e) { e.printstacktrace(); } } if (os!= null ){ try { os.close(); } catch (ioexception e2) { e2.printstacktrace(); } } } return "success" ; } //添加单条文字水印 public string textwatermark(multipartfile myfile,string imagefilename) { inputstream is = null ; outputstream os = null ; int x = 636 ; int y = 700 ; try { image image = imageio.read(myfile.getinputstream()); //计算原始图片宽度长度 int width = image.getwidth( null ); int height = image.getheight( null ); //创建图片缓存对象 bufferedimage bufferedimage = new bufferedimage(width, height, bufferedimage.type_int_rgb); //创建java绘图工具对象 graphics2d graphics2d = bufferedimage.creategraphics(); //参数主要是,原图,坐标,宽高 graphics2d.drawimage(image, 0 , 0 , width, height, null ); graphics2d.setfont( new font(font_name, font_style, font_size)); graphics2d.setcolor(font_color); //使用绘图工具将水印绘制到图片上 //计算文字水印宽高值 int waterwidth = font_size*gettextlength(mark_text); int waterheight = font_size; //计算水印与原图高宽差 int widthdiff = width-waterwidth; int heightdiff = height-waterheight; //水印坐标设置 if (x > widthdiff) { x = widthdiff; } if (y > heightdiff) { y = heightdiff; } //水印透明设置 graphics2d.setcomposite(alphacomposite.getinstance(alphacomposite.src_atop, alpha)); graphics2d.drawstring(mark_text, x, y+font_size); graphics2d.dispose(); os = new fileoutputstream(upload_path+ "/" +imagefilename); //创建图像编码工具类 jpegimageencoder en = jpegcodec.createjpegencoder(os); //使用图像编码工具类,输出缓存图像到目标文件 en.encode(bufferedimage); if (is!= null ){ is.close(); } if (os!= null ){ os.close(); } } catch (ioexception e) { e.printstacktrace(); } return "success" ; } //添加单图片水印 public string imagewatermark(multipartfile myfile,string imagefilename,httpservletrequest request) { inputstream is = null ; outputstream os = null ; int x = 636 ; int y = 763 ; try { image image = imageio.read(myfile.getinputstream()); //计算原始图片宽度长度 int width = image.getwidth( null ); int height = image.getheight( null ); //创建图片缓存对象 bufferedimage bufferedimage = new bufferedimage(width, height, bufferedimage.type_int_rgb); //创建java绘图工具对象 graphics2d graphics2d = bufferedimage.creategraphics(); //参数主要是,原图,坐标,宽高 graphics2d.drawimage(image, 0 , 0 , width, height, null ); graphics2d.setfont( new font(font_name, font_style, font_size)); graphics2d.setcolor(font_color); //水印图片路径 string logopath = "/img/logo.png" ; string realpath = request.getsession().getservletcontext().getrealpath(logopath); file logo = new file(realpath); image imagelogo = imageio.read(logo); int widthlogo = imagelogo.getwidth( null ); int heightlogo = imagelogo.getheight( null ); int widthdiff = width-widthlogo; int heightdiff = height-heightlogo; //水印坐标设置 if (x > widthdiff) { x = widthdiff; } if (y > heightdiff) { y = heightdiff; } //水印透明设置 graphics2d.setcomposite(alphacomposite.getinstance(alphacomposite.src_atop, alpha)); graphics2d.drawimage(imagelogo, x, y, null ); graphics2d.dispose(); os = new fileoutputstream(upload_path+ "/" +imagefilename); //创建图像编码工具类 jpegimageencoder en = jpegcodec.createjpegencoder(os); //使用图像编码工具类,输出缓存图像到目标文件 en.encode(bufferedimage); if (is!= null ){ is.close(); } if (os!= null ){ os.close(); } } catch (ioexception e) { e.printstacktrace(); } return "success" ; } //添加多条文字水印 public string moretextwatermark(multipartfile myfile,string imagefilename) { inputstream is = null ; outputstream os = null ; int x = 636 ; int y = 763 ; try { image image = imageio.read(myfile.getinputstream()); //计算原始图片宽度长度 int width = image.getwidth( null ); int height = image.getheight( null ); //创建图片缓存对象 bufferedimage bufferedimage = new bufferedimage(width, height, bufferedimage.type_int_rgb); //创建java绘图工具对象 graphics2d graphics2d = bufferedimage.creategraphics(); //参数主要是,原图,坐标,宽高 graphics2d.drawimage(image, 0 , 0 , width, height, null ); graphics2d.setfont( new font(font_name, font_style, font_size)); graphics2d.setcolor(font_color); //使用绘图工具将水印绘制到图片上 //计算文字水印宽高值 int waterwidth = font_size*gettextlength(mark_text); int waterheight = font_size; //水印透明设置 graphics2d.setcomposite(alphacomposite.getinstance(alphacomposite.src_atop, alpha)); graphics2d.rotate(math.toradians( 30 ), bufferedimage.getwidth()/ 2 , bufferedimage.getheight()/ 2 ); int x = -width/ 2 ; int y = -height/ 2 ; while (x < width* 1.5 ){ y = -height/ 2 ; while (y < height* 1.5 ){ graphics2d.drawstring(mark_text, x, y); y+=waterheight+ 100 ; } x+=waterwidth+ 100 ; } graphics2d.dispose(); os = new fileoutputstream(upload_path+ "/" +imagefilename); //创建图像编码工具类 jpegimageencoder en = jpegcodec.createjpegencoder(os); //使用图像编码工具类,输出缓存图像到目标文件 en.encode(bufferedimage); if (is!= null ){ is.close(); } if (os!= null ){ os.close(); } } catch (ioexception e) { e.printstacktrace(); } return "success" ; } //多图片水印 public string moreimagewatermark(multipartfile myfile,string imagefilename,httpservletrequest request) { inputstream is = null ; outputstream os = null ; int x = 636 ; int y = 763 ; try { image image = imageio.read(myfile.getinputstream()); //计算原始图片宽度长度 int width = image.getwidth( null ); int height = image.getheight( null ); //创建图片缓存对象 bufferedimage bufferedimage = new bufferedimage(width, height, bufferedimage.type_int_rgb); //创建java绘图工具对象 graphics2d graphics2d = bufferedimage.creategraphics(); //参数主要是,原图,坐标,宽高 graphics2d.drawimage(image, 0 , 0 , width, height, null ); graphics2d.setfont( new font(font_name, font_style, font_size)); graphics2d.setcolor(font_color); //水印图片路径 string logopath = "/img/logo.png" ; string realpath = request.getsession().getservletcontext().getrealpath(logopath); file logo = new file(realpath); image imagelogo = imageio.read(logo); int widthlogo = imagelogo.getwidth( null ); int heightlogo = imagelogo.getheight( null ); //水印透明设置 graphics2d.setcomposite(alphacomposite.getinstance(alphacomposite.src_atop, alpha)); graphics2d.rotate(math.toradians( 30 ), bufferedimage.getwidth()/ 2 , bufferedimage.getheight()/ 2 ); int x = -width/ 2 ; int y = -height/ 2 ; while (x < width* 1.5 ){ y = -height/ 2 ; while (y < height* 1.5 ){ graphics2d.drawimage(imagelogo, x, y, null ); y+=heightlogo+ 100 ; } x+=widthlogo+ 100 ; } graphics2d.dispose(); os = new fileoutputstream(upload_path+ "/" +imagefilename); //创建图像编码工具类 jpegimageencoder en = jpegcodec.createjpegencoder(os); //使用图像编码工具类,输出缓存图像到目标文件 en.encode(bufferedimage); if (is!= null ){ is.close(); } if (os!= null ){ os.close(); } } catch (ioexception e) { e.printstacktrace(); } return "success" ; } //计算水印文本长度 //1、中文长度即文本长度 2、英文长度为文本长度二分之一 public int gettextlength(string text){ //水印文字长度 int length = text.length(); for ( int i = 0 ; i < text.length(); i++) { string s =string.valueof(text.charat(i)); if (s.getbytes().length> 1 ) { length++; } } length = length% 2 == 0 ?length/ 2 :length/ 2 + 1 ; return length; } } |
最后再说明下,本demo是在上次的文件导入导出的框架基础上编写的,源码中有些其它demo的代码,主要使用的类有watermarkcontroller.java、watermarkservice.java、watermarkserviceimpl.java,因为代码中我是硬编码到e:/save文件夹下的,如果要运行的话,还请先新建此文件夹,或者改为其他文件夹也行。
源码地址:https://github.com/allanzhuo/myport.git
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持服务器之家。
原文链接:http://www.cnblogs.com/allanzhang/p/7193309.html