接觸微信公衆號開發已經有一段時間了,發現其實和網頁開發差很少,可是由於瀏覽器的不一樣,本身也碰過一些坑,其中就有怎麼實現圖片裁剪功能。javascript
一開始我是用PC端的思路去作的,首先在本地獲取圖片路徑,而後在網頁中顯示,最後在本地裁剪,而後把裁剪好的圖片轉換成base64數據,上傳到服務器。作完以後,我爲css
了測試,我是直接把圖片路徑寫到img裏面的,省略了選擇圖片這個步驟,最後在微信測試是經過的。可是我把選擇圖片的步驟加上以後,就出了問題。html
我是用cropper框架(不支持jq的版本)實現的,由於這個框架支持移動端操做的,下面我就把這個過程當中出現的問題寫一下。java
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <meta name="viewport" content="initial-scale=1.0, maximum-scale=1.0, user-scalable=no" /> <title></title> <link rel="stylesheet" href="css/cropper.css" /> <style> .img-content img { max-width: 100%; } </style> </head> <body> <div class="img-content"> <!--src是微信的圖片ID,能夠直接在img裏面顯示--> <img id="photo" src="wxLocalResource://488970461173136"> </div> <button id="confirm">肯定</button> </body> <script type="text/javascript" src="js/cropper.js"></script> <script> var photo = document.getElementById("photo"); var cropper = new Cropper(photo, { aspectRatio: 1, }); document.getElementById('confirm').addEventListener('click', function() { var canvas=cropper.getCanvasData(); var base64Data=canvas.toDataURL("image/jpeg",1); alert(base64Data); }); </script> </html>
上面那段代碼在微信端運行的時候,js部分會報錯git
1,在cropper初始化的時候會報錯,報XMLHtmlRequest DOM 18的錯誤github
2,在獲取圖片數據 toDataURL的時候會報錯,報undefined function的錯誤ajax
其實這兩個問題我以爲應該是微信瀏覽器的問題。因此我用了另一種方式實現。仍是使用cropper裁剪插件json
一、把選擇到的圖片ID上傳到微信的服務器,獲取serverId(微信服務器的圖片ID)canvas
二、修改cropper的js,使得cropper在初始化的時候不報錯api
三、在本地裁剪,可是不獲取裁剪後的base64數據,獲取裁剪的區域參數,把serverId和那些參數發送到本身的服務器
四、從微信服務器下載圖片到本身的服務器,裁剪,壓縮,保存到本身的服務器。
下面我把全部的步驟都寫出來
首先要使用微信js-sdk獲取圖片的ID,圖片ID就是圖片的路徑,這個ID能夠直接在img標籤顯示。
1,初始化微信js-sdk
2,調用微信選擇圖片的js
3,從返回的數據中獲取圖片ID
爲了方便,我就寫js部分
//微信初始化 wx.config({ debug: false, appId: '${wx_app_id}', timestamp: ${wx_js_timestamp}, nonceStr: '${wx_js_noncestr}', signature: '${wx_js_mydata}', jsApiList: [ 'chooseImage', 'uploadImage', ] }); //微信初始化成功 wx.ready(function(){ document.getElementById("picture").addEventListener('click', function(){ wx.chooseImage({ count: 1, //一次性能夠選擇多少張圖片,默認9 sizeType: ['original','compressed'],//圖片的類型:原圖,壓縮圖 sourceType: ['album','camera'], //圖片來源:相冊,拍照 success: function(localRes){ var localIdVal = localRes.localIds[0]; //本地第一張圖片ID //獲取到圖片後,上傳的服務器,獲得服務器的ID wx.uploadImage({ localId: localIdVal, //本地圖片ID isShowProgressTips: 1, //顯示加載圈 success: function (serverRes) { var serverIdVal=serverRes.serverId; window.location.href="mine/photocrop?localId="+localIdVal+"&serverId="+serverIdVal, }, fail: function (res) { mui.alert(JSON.stringify(res)); } }); }, cancel: function () { // } }); }); }); //微信初始化失敗 wx.error(function(res){ document.getElementById("picture").addEventListener('tap', function(){ mui.alert("微信初始化失敗"); }); });
首先要初始化微信,調用wx.config的方法,若是初始化成功,那麼wx.ready就會調用,若是失敗,那麼就調用wx.error方法
初始化成功以後,給按鈕添加點擊的方法,這樣點擊的時候,就會調用wx.chooseImage的方法,在瀏覽器就會彈出選擇圖片的彈窗,選擇圖片以後,能夠獲取本地的圖片ID,而後上傳圖片到服務器,能夠獲取微信服務器的圖片ID。
如今說一下本地圖片ID和微信服務器圖片ID的用途,本地圖片ID要用於裁剪的,服務器的圖片ID是用於下載的。
下面修改cropper框架,其實初始化報錯實際上是由於cropper會去下載本地的圖片,因此咱們那段代碼刪掉
打開cropper.js,找到854行,把這段代碼刪掉,添加一句__this.clone(),這一句必須的。
其實咱們還須要禁掉滑輪縮放和手指縮放的功能,由於若是不由掉,那麼裁剪框的區域就不正確了,把下面的代碼註釋掉
滑輪縮放的代碼
手指縮放的代碼
好了,cropper已經修改完了,記得要引用修改後的cropper.js
下面裁剪圖片了
<!DOCTYPE html> <html> <head> <title>裁剪</title> <link rel="stylesheet" href="sources/css/cropper.css" /> <style> .img-content img { max-width: 100%; } </style> </head> <body> <div> <div class="img-content"> <img id="photo" src="${localId}"> </div> <button id="confirm"> 肯定 </button> </div> <script src="sources/js/cropper.js"></script> <script type="text/javascript" charset="utf-8"> mui.ready(function() { var photo = document.getElementById("photo"); var cropper = new Cropper(photo, { aspectRatio: 1, }); var btnConfirm = document.getElementById("confirm"); btnConfirm.addEventListener("tap", function() { btnConfirm.innerText = "正在處理..."; btnConfirm.disabled = true; var canvasData = cropper.getCanvasData(); var cropBoxData = cropper.getCropBoxData(); //要根據圖片的縮放計算實際的大小 var scale = canvasData.naturalWidth / canvasData.width; var topVal = (cropBoxData.top - canvasData.top) * scale; var leftVal = cropBoxData.left * scale; var widthVal = cropBoxData.width * scale; mui.ajax('mine/uploadPhoto', { data: { serverId: '${serverId}', top: topVal, left: leftVal, width: widthVal }, type: 'post', dataType: 'json', success: function(data) { mui.alert(data.msg, function() { if (!data.success) { btnConfirm.innerText = "肯定"; btnConfirm.disabled = false; } }); }, error: function(xhr, type, errorThrown) { mui.alert(type); btnConfirm.innerText = "肯定"; btnConfirm.disabled = false; } }); }); }); </script> </body> </html>
首先用本地的圖片ID顯示,而後裁剪,獲取裁剪的參數,而後把微信服務器的圖片ID也上傳到本身的服務器,而後在本身的服務器處理
下面這段代碼包括從微信服務器下載圖片,裁剪,壓縮,保存到服務器
public static final String downloadUserPhoto(String serverId, int left, int top, int width) { String path = "http://file.api.weixin.qq.com/cgi-bin/media/get?access_token=fasdfsaffasdfa&media_id=" + serverId; HttpURLConnection con = null; FileOutputStream fos = null; try { URL url = new URL(path); con = (HttpURLConnection) url.openConnection(); con.setConnectTimeout(5000); con.connect(); if (con.getResponseCode() == HttpURLConnection.HTTP_OK) { String type = con.getHeaderField("Content-Type"); //判斷是否是圖片類型 if (type != null && type.contains("image")) { String ext = type.substring(type.lastIndexOf("/") + 1); String filename = UUID.randomUUID().toString() + "." + ext; File file = new File("download/images/",filename); if (!file.getParentFile().exists()) { file.getParentFile().mkdirs(); } BufferedImage bufImg = ImageIO.read(con.getInputStream()); bufImg = bufImg.getSubimage(left, top, width, width); //壓縮圖片,若是圖片的像素寬度超過160 if (width > 160) { float wr = 160 * 1f / bufImg.getWidth(); AffineTransformOp ato = new AffineTransformOp(AffineTransform.getScaleInstance(wr, wr), null); bufImg = ato.filter(bufImg, null); } fos = new FileOutputStream(file); ImageIO.write(bufImg, ext, fos); String filepath = pathdir + "/" + filename; return filepath; } } } catch (Exception e) { e.printStackTrace(); try { if (fos != null) { fos.close(); } if (con != null) { con.disconnect(); } } catch (Exception el) { el.printStackTrace(); } } return null; }
其實最大的區別就是把本地裁剪移到服務器裁剪。沒有demo,這些代碼是從一個項目複製過來的