web网站中常常有的功能:上传头像、上传封面等;一般图片都有一定的比例限制,所以需要前端在上传图片时,进行裁剪,并把裁剪后的图片进行上传。
本例采用Jcrop插件实现裁剪效果,canvas裁剪图片,并把base64位的toDataURL图片转换成blob(二进制数据),最后使用XMLHttpRequest上传到服务器。
Jcrop演示及下载地址:http://code.ciaoca.com/jquery/jcrop/demo/
Jcrop的使用
本例做Jcrop的简单预览功能(同理可以实现网页的放大镜功能)
- 载入 CSS 文件
1 <link rel="stylesheet" href="jquery.Jcrop.css">
- 载入 JavaScript 文件
1 <script src="jquery.js"></script> 2 <script src="jquery.Jcrop.js"></script>
- 给 IMG 标签加上 ID
1 <img id="element_id" src="pic.jpg">
- 调用 Jcrop
1 $('#element_id').Jcrop();
实例代码
1 <!DOCTYPE html>
2 <html lang="en">
3 <head>
4 <meta charset="UTF-8">
5 <title>图像裁剪-Jcrop</title>
6 <link rel="stylesheet" href="css/jquery.Jcrop.css" type="text/css" />
7 <style>
8 img {
9 border: 0px;
10 }
11 * {
12 margin: 0;
13 padding: 0;
14 }
15 .head {
16 width: 600px;
17 height: 600px;
18 background-color: gray;
19 }
20 #target{
21 max-width: 600px;
22 max-height: 600px;
23 }
24
25 #preview-pane {
26 position: fixed;
27 top: 0;
28 right: 0;
29 width: 300px;
30 height: 300px;
31 overflow: hidden;
32 border: 1px solid purple;
33 }
34 #preview-pane .preview-container {
35 width: 100%;
36 height: 100%;
37 }
38 #preview-pane .preview-container img{
39 max-width: 100%;
40 max-height: 100%;
41
42 }
43 </style>
44 </head>
45 <body>
46
47 <!-- 头像 -->
48 <div class="head" >
49 <img src="images/IMG_0109.JPG" id="target" alt="[Jcrop Example]" />
50 </div>
51
52 <!-- 预览盒子 -->
53 <div id="preview-pane">
54 <div class="preview-container">
55 <img src="images/IMG_0109.JPG" class="jcrop-preview" alt="Preview" id="Preview"/>
56 </div>
57 </div>
58
59 <script src="js/jquery.min.js"></script>
60 <script src="js/jquery.Jcrop.js"></script>
61 <script type="text/javascript">
62
63 // 定义一些使用的变量
64 var jcrop_api,//jcrop对象
65 boundx,//图片实际显示宽度
66 boundy,//图片实际显示高度
67 realWidth,// 真实图片宽度
68 realHeight, //真实图片高度
69
70 // 使用的jquery对象
71 $target = $('#target'),
72 $preview = $('#preview-pane'),
73 $pcnt = $('#preview-pane .preview-container'),
74 $pimg = $('#preview-pane .preview-container img'),
75
76 xsize = $pcnt.width(),
77 ysize = $pcnt.height();
78
79 //初始化Jcrop插件
80 function initJcrop(){
81
82 console.log('init',[xsize,ysize]);
83 $target.removeAttr("style");//清空上一次初始化设置的样式
84 $target.Jcrop({
85 onChange: updatePreview,
86 onSelect: updatePreview,
87 aspectRatio: xsize / ysize
88 },function(){
89 //初始化后回调函数
90 // 获取图片实际显示的大小
91 var bounds = this.getBounds();
92 boundx = bounds[0];//图片实际显示宽度
93 boundy = bounds[1];//图片实际显示高度
94
95 // 保存jcrop_api变量
96 jcrop_api = this;
97
98 });
99 }
100
101 //更新显示预览内容
102 function updatePreview(c){
103 if (parseInt(c.w) > 0)
104 {
105 var rx = xsize / c.w;
106 var ry = ysize / c.h;
107
108 $pimg.css({
109 maxWidth: Math.round(rx * boundx) + 'px',
110 maxHeight: Math.round(ry * boundy) + 'px',
111 width: Math.round(rx * boundx) + 'px',
112 height: Math.round(ry * boundy) + 'px',
113 marginLeft: '-' + Math.round(rx * c.x) + 'px',
114 marginTop: '-' + Math.round(ry * c.y) + 'px'
115 });
116 }
117 }
118
119 window.onload = function () {
120 initJcrop();
121 };
122
123 </script>
124 </body>
125 </html>
预览效果

Canvas的使用
定义:<canvas> 标签定义图形,比如图表和其他图像。
注意:canvas标签的宽高与标签样式的宽高问题,把Canvas 比作是一个画板和一张画纸,标签宽高相当于画板,样式宽高相当于画纸。
canvas裁剪图片,准备上传
1 <!DOCTYPE html>
2 <html lang="en">
3 <head>
4 <meta charset="UTF-8">
5 <title>图像裁剪-Jcrop</title>
6 <link rel="stylesheet" href="css/jquery.Jcrop.css" type="text/css" />
7 <style>
8 img {
9 border: 0px;
10 }
11 * {
12 margin: 0;
13 padding: 0;
14 }
15 .head {
16 width: 600px;
17 height: 600px;
18 background-color: gray;
19 }
20 #target{
21 max-width: 600px;
22 max-height: 600px;
23 }
24 canvas {
25 position: fixed;
26 top: 0;
27 right: 0;
28 border: 1px solid red;
29 width: 200px;
30 height: 200px;
31 }
32 </style>
33
34
35 </head>
36 <body>
37
38 <!-- 头像 -->
39 <div class="head" >
40 <img src="images/IMG_0109.JPG" id="target" alt="[Jcrop Example]" />
41 </div>
42
43
44 <!-- 画板 -->
45 <canvas id="myCan" width="200" height="200"></canvas>
46
47 <script src="js/jquery.min.js"></script>
48 <script type="text/javascript">
49
50
51 initCanvas();
52
53 //初始化canvas画板内容
54 function initCanvas(){
55 //更新canvas画板内容
56 var img= document.getElementById("target");
57 var ct= document.getElementById("myCan");
58 var ctx = ct.getContext("2d");
59
60 //清空画板
61 ctx.clearRect(0,0, ct.width, ct.height);
62 //.drawImage(图像对象,原图像截取的起始X坐标,原图像截取的起始Y坐标,原图像截取的宽度,原图像截取的高度,绘制图像的起始X坐标,绘制图像的起始Y坐标,绘制图像所需要的宽度,绘制图像所需要的高度);
63 //矩形框[150,150,200,200]--原图像截取的起始X坐标,原图像截取的起始Y坐标,原图像截取的宽度,原图像截取的高度
64 ctx.drawImage(img, 150, 150, 200, 200, 0,0, ct.width , ct.height);
65 }
66
67 </script>
68 </body>
69 </html>
预览

完整代码展示
html代码

1 <!DOCTYPE html>
2 <html lang="en">
3 <head>
4 <meta charset="UTF-8">
5 <title>图像裁剪-Jcrop</title>
6 <link rel="stylesheet" href="css/jquery.Jcrop.css" type="text/css" />
7 <style>
8 img {
9 border: 0px;
10 }
11 * {
12 margin: 0;
13 padding: 0;
14 }
15 .head {
16 width: 600px;
17 height: 600px;
18 background-color: gray;
19 }
20 #target{
21 max-width: 600px;
22 max-height: 600px;
23 }
24
25 #preview-pane {
26 position: fixed;
27 top: 0;
28 right: 0;
29 width: 300px;
30 height: 300px;
31 overflow: hidden;
32 border: 1px solid purple;
33 }
34 #preview-pane .preview-container {
35 width: 100%;
36 height: 100%;
37
38 }
39
40
41 canvas {
42 position: fixed;
43 top: 400px;
44 right: 0;
45 border: 1px solid red;
46 width: 200px;
47 height: 200px;
48 }
49 </style>
50
51
52 </head>
53 <body>
54
55 <!-- 头像 -->
56 <div class="head" >
57 <img src="" id="target" alt="[Jcrop Example]" />
58 <input type="file" id="file" onchange="changeFile()" style="display: none;"/>
59 </div>
60 <button onClick="openBrowse()">上传图片</button>
61 <button onClick="uploadFile()">确认</button>
62
63 <!-- 预览盒子 -->
64 <div id="preview-pane">
65 <div class="preview-container">
66 <img src="" class="jcrop-preview" alt="Preview" id="Preview"/>
67 </div>
68 </div>
69
70 <!-- 画板 -->
71 <canvas id="myCan" width="200" height="200"></canvas>
72
73 <script src="js/jquery.min.js"></script>
74 <script src="js/jquery.Jcrop.js"></script>
75 <script type="text/javascript">
76
77 // 定义一些使用的变量
78 var jcrop_api,//jcrop对象
79 boundx,//图片实际显示宽度
80 boundy,//图片实际显示高度
81 realWidth,// 真实图片宽度
82 realHeight, //真实图片高度
83
84 // 使用的jquery对象
85 $target = $('#target'),
86 $preview = $('#preview-pane'),
87 $pcnt = $('#preview-pane .preview-container'),
88 $pimg = $('#preview-pane .preview-container img'),
89
90 xsize = $pcnt.width(),
91 ysize = $pcnt.height();
92
93
94
95 //1、打开浏览器
96 function openBrowse(){
97 var ie=navigator.appName=="Microsoft Internet Explorer" ? true : false;
98 if(ie){
99 document.getElementById("file").click();
100 }else{
101 var a=document.createEvent("MouseEvents");
102 a.initEvent("click", true, true);
103 document.getElementById("file").dispatchEvent(a);
104 }
105 }
106
107 //2、从 file 域获取 本地图片 url
108 function getFileUrl(sourceId) {
109 var url;
110 if (navigator.userAgent.indexOf("MSIE")>=1) { // IE
111 url = document.getElementById(sourceId).value;
112 } else if(navigator.userAgent.indexOf("Firefox")>0) { // Firefox
113 url = window.URL.createObjectURL(document.getElementById(sourceId).files.item(0));
114 } else if(navigator.userAgent.indexOf("Chrome")>0) { // Chrome
115 url = window.URL.createObjectURL(document.getElementById(sourceId).files.item(0));
116 } else if(navigator.userAgent.indexOf("Safari")>0) { // Chrome
117 url = window.URL.createObjectURL(document.getElementById(sourceId).files.item(0));
118 }
119 return url;
120 }
121 //选择文件事件
122 function changeFile() {
123 var url = getFileUrl("file");//根据id获取文件路径
124 preImg(url);
125 return false;
126 }
127
128 //3、将本地图片 显示到浏览器上
129 function preImg(url) {
130
131 console.log('url===' + url);
132 //图片裁剪逻辑
133 if(jcrop_api)//判断jcrop_api是否被初始化过
134 {
135 jcrop_api.destroy();
136 }
137
138 //初始化预览div内容
139 initPreview();
140 var p = document.getElementById('Preview');
141 p.src = url;
142
143 //初始化图片
144 initTarget();
145 var image = document.getElementById('target');
146 image.onload=function(){//图片加载是一个异步的过程
147 //获取图片文件真实宽度和大小
148 var img = new Image();
149 img.onload=function(){
150 realWidth = img.width;
151 realHeight = img.height;
152
153 //获取图片真实高度之后
154 initJcrop();//初始化Jcrop插件
155 initCanvas();//初始化Canvas内容
156 };
157 img.src = url;
158 };
159 image.src = url;
160 }
161
162 //初始化Jcrop插件
163 function initJcrop(){
164
165 console.log('init',[xsize,ysize]);
166 $target.removeAttr("style");//清空上一次初始化设置的样式
167 $target.Jcrop({
168 onChange: updatePreview,
169 onSelect: updatePreview,
170 aspectRatio: xsize / ysize
171 },function(){
172 //初始化后回调函数
173 // 获取图片实际显示的大小
174 var bounds = this.getBounds();
175 boundx = bounds[0];//图片实际显示宽度
176 boundy = bounds[1];//图片实际显示高度
177
178 // 保存jcrop_api变量
179 jcrop_api = this;
180
181 });
182 }
183
184
185 //更新显示预览内容
186 function updatePreview(c){
187 if (parseInt(c.w) > 0)
188 {
189 var rx = xsize / c.w;
190 var ry = ysize / c.h;
191
192 $pimg.css({
193 maxWidth: Math.round(rx * boundx) + 'px',
194 maxHeight: Math.round(ry * boundy) + 'px',
195 width: Math.round(rx * boundx) + 'px',
196 height: Math.round(ry * boundy) + 'px',
197 marginLeft: '-' + Math.round(rx * c.x) + 'px',
198 marginTop: '-' + Math.round(ry * c.y) + 'px'
199 });
200
201 //更新canvas画板内容
202 var img=document.getElementById("target");
203 var ct=document.getElementById("myCan");
204 var ctx=ct.getContext("2d");
205 //清空画板
206 ctx.clearRect(0,0, ct.width, ct.height);
207 //.drawImage(图像对象,原图像截取的起始X坐标,原图像截取的起始Y坐标,原图像截取的宽度,原图像截取的高度,绘制图像的起始X坐标,绘制图像的起始Y坐标,绘制图像所需要的宽度,绘制图像所需要的高度);
208 ctx.drawImage(img, c.x/boundx * realWidth,c.y/boundy * realHeight, c.w/boundx * realWidth, c.h/boundy * realHeight,0,0, ct.width, ct.height);
209 }
210 }
211
212 //初始化预览div内容
213 function initTarget(){
214 $target.removeAttr("style");//清空上一次初始化设置的样式
215 $target.css({
216 maxWidth: '100%',
217 maxHeight: '100%'
218 });
219 }
220 //初始化预览div内容
221 function initPreview(){
222 $pimg.removeAttr("style");//清空上一次初始化设置的样式
223 $pimg.css({
224 maxWidth: xsize + 'px',
225 maxHeight: ysize + 'px'
226 });
227 }
228
229 //初始化canvas画板内容
230 function initCanvas(){
231 //更新canvas画板内容
232 var img= document.getElementById("target");
233 var ct= document.getElementById("myCan");
234 var ctx = ct.getContext("2d");
235
236 var myCanWidth = $('#myCan').width();
237 var myCanHeight = $('#myCan').height();
238
239 //清空画板
240 ctx.clearRect(0,0, ct.width, ct.height);
241
242 //.drawImage(图像对象,原图像截取的起始X坐标,原图像截取的起始Y坐标,原图像截取的宽度,原图像截取的高度,绘制图像的起始X坐标,绘制图像的起始Y坐标,绘制图像所需要的宽度,绘制图像所需要的高度);
243 var dWidth = realWidth;//绘制实际宽度
244 var dHeight = realHeight;//绘制实际高度
245 if(dWidth > myCanWidth)
246 {
247 dHeight = myCanWidth / dWidth * dHeight;
248 dWidth = myCanWidth;
249 }
250 if(dHeight > myCanHeight)
251 {
252 dWidth = myCanHeight / dHeight * dWidth ;
253 dHeight = myCanHeight;
254 }
255 ctx.drawImage(img,0,0, realWidth, realHeight, 0,0, dWidth, dHeight);
256 }
257
258 //文件上传
259 function uploadFile(){
260 //获取裁剪完后的base64图片url,转换为blob
261 var data=document.getElementById("myCan").toDataURL();
262 var formData=new FormData();
263 formData.append("imageName",dataURLtoBlob(data));
264 var httprequest= null;
265 if (window.XMLHttpRequest) {
266 httprequest = new XMLHttpRequest();
267 } else {
268 httprequest = new ActiveXObject('MicroSoft.XMLHTTP');
269 }
270 var apiurl= ""; //上传图片的api接口,自行填写
271 httprequest.open('POST',apiurl,true);
272 httprequest.send(formData);
273 httprequest.onreadystatechange= function () {
274
275 if(httprequest.readyState == 4 ){
276
277 if(httprequest.status == 200)
278 {
279 var json=JSON.parse(httprequest.responseText);
280 console.log(json);
281
282 }else
283 {
284 alert('获取数据错误,错误代码:' + httprequest.status + '错误信息:' + httprequest.statusText);
285 }
286 }
287 };
288 }
289
290 //把base64位的toDataURL图片转换成blob
291 function dataURLtoBlob(dataurl) {
292 var arr = dataurl.split(','), mime = arr[0].match(/:(.*?);/)[1],
293 bstr = atob(arr[1]), n = bstr.length, u8arr = new Uint8Array(n);
294 while (n--) {
295 u8arr[n] = bstr.charCodeAt(n);
296 }
297 return new Blob([u8arr], { type: mime });
298 }
299
300 window.onload = function () {
301 //初始化图片
302 preImg('images/IMG_0109.JPG');
303 };
304
305 </script>
306 </body>
307 </html>
图片上传接口可以参照:【Java】JavaWeb文件上传和下载
注意:canvas在裁剪图片的时候有跨域的问题,如果裁剪网络图片,会报异常:Failed to execute 'toDataURL' on 'HTMLCanvasElement': Tainted canvases may not be exported.
本例服务端采用的方法是:服务器转发网络图片,进行图片访问。
页面上访问:<img src="img/getImg?imgUrl=http://test.example.net/a/b/c/123456.jpg"/>
服务端JAVA代码:
1 @RequestMapping(value = "/getImg")
2 public void getImg(HttpServletRequest request, HttpServletResponse response, String imgUrl) throws Exception
3 {
4 // 统一资源
5 URL url = new URL(imgUrl);
6 // 连接类的父类,抽象类
7 URLConnection urlConnection = url.openConnection();
8 // http的连接类
9 HttpURLConnection httpURLConnection = (HttpURLConnection) urlConnection;
10 // 设定请求的方法,默认是GET
11 httpURLConnection.setRequestMethod("POST");
12 // 设置字符编码
13 httpURLConnection.setRequestProperty("Charset", "UTF-8");
14 // 打开到此 URL 引用的资源的通信链接(如果尚未建立这样的连接)。
15 httpURLConnection.connect();
16
17 BufferedInputStream bin = new BufferedInputStream(httpURLConnection.getInputStream());
18 ServletOutputStream outputStream = response.getOutputStream();
19
20 int size = 0;
21 byte[] buf = new byte[1024*10];
22 while ((size = bin.read(buf)) != -1) {
23 outputStream.write(buf, 0, size);
24 }
25 bin.close();
26 outputStream.close();
27 }
预览效果

来源:https://www.cnblogs.com/h--d/p/7801230.html
