web網站中經常有的功能:上傳頭像、上傳封面等;通常圖片都有必定的比例限制,因此須要前端在上傳圖片時,進行裁剪,並把裁剪後的圖片進行上傳。javascript
本例採用Jcrop插件實現裁剪效果,canvas裁剪圖片,並把base64位的toDataURL圖片轉換成blob(二進制數據),最後使用XMLHttpRequest上傳到服務器。css
Jcrop演示及下載地址:http://code.ciaoca.com/jquery/jcrop/demo/html
本例作Jcrop的簡單預覽功能(同理能夠實現網頁的放大鏡功能)前端
1 <link rel="stylesheet" href="jquery.Jcrop.css">
1 <script src="jquery.js"></script> 2 <script src="jquery.Jcrop.js"></script>
1 <img id="element_id" src="pic.jpg">
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>
預覽效果java
定義:<canvas> 標籤訂義圖形,好比圖表和其餘圖像。jquery
注意:canvas標籤的寬高與標籤樣式的寬高問題,把Canvas 比做是一個畫板和一張畫紙,標籤寬高至關於畫板,樣式寬高至關於畫紙。web
canvas裁剪圖片,準備上傳json
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>
預覽
canvas
html代碼api
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 //一、打開瀏覽器 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 //二、從 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 //三、將本地圖片 顯示到瀏覽器上 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 }
預覽效果