【Web】前端裁剪图片,并上传到服务器(Jcrop+canvas)

  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                        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                        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>
View Code

   图片上传接口可以参照:【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