需求:用戶上傳或者修改頭像的時候先將圖片裁剪,固定寬度和高度,這樣在不一樣的情景下顯示的時候不會出現壓縮失真。javascript
中間折騰過的方法:css
1.smartCorp.jshtml
國外一個大神寫的,根據圖像的飽和度裁剪最好看的照片,剛開始覺得很好用的,在官網上下載了源碼,demo跑起來還能夠,可是裁剪成小圖片的時候裁剪不了,項目是Java的,可是demo用的是PHP,我也不會PHP,也沒有運行環境,最後放棄了。前端
2.JS素材網上下載的插件。也是同樣的問題,裁剪成小圖片的後臺代碼運行不了,並且樣式也很差看,仍是選擇放棄。java
3.JCorp.js 這也是國外的開源軟件,第一眼看上去清新大方,有點意思。還有詳盡的使用方法,不錯不錯。可是最核心的裁剪問題依然存在。有博客上用的是後臺的Java代碼裁剪,demo支持直接本地讀取,和寫入,沒有問題,可是放在網頁上,圖片走服務器上傳是很麻煩的一個問題,除了上傳原圖,還要返回裁剪後的圖片base64碼,這樣子顯示是沒問題了 ,可是怎麼上傳到阿里雲服務器又是問題了。找啊找,終於找到一個博客寫的是用前端H5的<canvas>畫布裁剪,不走服務器,很nice。因而乎直接放在項目裏用了,集成好也沒問題,很開心。開心了一分鐘,而後,流文件怎麼上傳到阿里雲服務器呢,翻遍了阿里雲的社區和手冊也沒找到答案。而後簡書上的一篇文章講清楚了要怎麼處理上傳,搬過來,解決好了。最後還有一個問題,如何上傳到網易雲呢?翻了網易雲的開發文檔,用斷點走了幾遍js文件,找到了上傳的文件格式,一遍一遍的試,最後也搞好了。超級超級開心的。如下是實現代碼:jquery
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <!doctype html> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/> <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0"/> <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1"/> <meta name="description" id="description1" content="1"> <meta name="renderer" content="webkit"> <meta name="format-detection" content="telephone=no"> <title>圖片上傳</title> <style type="text/css"> .jcrop-holder { direction: ltr; text-align: center; margin: 0 auto; /* IE10 touch compatibility */ -ms-touch-action: none; } /* Selection Border */ .jcrop-vline, .jcrop-hline { background: #ffffff url("Jcrop.gif"); font-size: 0; position: absolute; } .jcrop-vline { height: 100%; width: 1px !important; } .jcrop-vline.right { right: 0; } .jcrop-hline { height: 1px !important; width: 100%; } .jcrop-hline.bottom { bottom: 0; } /* Invisible click targets */ .jcrop-tracker { height: 100%; width: 100%; /* "turn off" link highlight */ -webkit-tap-highlight-color: transparent; /* disable callout, image save panel */ -webkit-touch-callout: none; /* disable cut copy paste */ -webkit-user-select: none; } /* Selection Handles */ .jcrop-handle { background-color: #333333; border: 1px #eeeeee solid; width: 7px; height: 7px; font-size: 1px; } .jcrop-handle.ord-n { left: 50%; margin-left: -4px; margin-top: -4px; top: 0; } .jcrop-handle.ord-s { bottom: 0; left: 50%; margin-bottom: -4px; margin-left: -4px; } .jcrop-handle.ord-e { margin-right: -4px; margin-top: -4px; right: 0; top: 50%; } .jcrop-handle.ord-w { left: 0; margin-left: -4px; margin-top: -4px; top: 50%; } .jcrop-handle.ord-nw { left: 0; margin-left: -4px; margin-top: -4px; top: 0; } .jcrop-handle.ord-ne { margin-right: -4px; margin-top: -4px; right: 0; top: 0; } .jcrop-handle.ord-se { bottom: 0; margin-bottom: -4px; margin-right: -4px; right: 0; } .jcrop-handle.ord-sw { bottom: 0; left: 0; margin-bottom: -4px; margin-left: -4px; } /* Dragbars */ .jcrop-dragbar.ord-n, .jcrop-dragbar.ord-s { height: 7px; width: 100%; } .jcrop-dragbar.ord-e, .jcrop-dragbar.ord-w { height: 100%; width: 7px; } .jcrop-dragbar.ord-n { margin-top: -4px; } .jcrop-dragbar.ord-s { bottom: 0; margin-bottom: -4px; } .jcrop-dragbar.ord-e { margin-right: -4px; right: 0; } .jcrop-dragbar.ord-w { margin-left: -4px; } /* The "jcrop-light" class/extension */ .jcrop-light .jcrop-vline, .jcrop-light .jcrop-hline { background: #ffffff; filter: alpha(opacity=70) !important; opacity: .70!important; } .jcrop-light .jcrop-handle { -moz-border-radius: 3px; -webkit-border-radius: 3px; background-color: #000000; border-color: #ffffff; border-radius: 3px; } /* The "jcrop-dark" class/extension */ .jcrop-dark .jcrop-vline, .jcrop-dark .jcrop-hline { background: #000000; filter: alpha(opacity=70) !important; opacity: 0.7 !important; } .jcrop-dark .jcrop-handle { -moz-border-radius: 3px; -webkit-border-radius: 3px; background-color: #ffffff; border-color: #000000; border-radius: 3px; } /* Simple macro to turn off the antlines */ .solid-line .jcrop-vline, .solid-line .jcrop-hline { background: #ffffff; } /* Fix for twitter bootstrap et al. */ .jcrop-holder img, img.jcrop-preview { max-width: none; } .uploadPics { position: relative; width: 380px; background-color: #fff; height: 460px; overflow: hidden; } .uploadPics > img { position: absolute; top: 20px; right: 10px; cursor: pointer; } .uploadPics .picTil { padding: 20px; font-size: 16px; color: #323232; border-bottom: 1px solid #f3f3f3; } .uploadPics .picCont { margin: 20px; padding: 15px; width: 300px; height: 337px; background-color: #f2f2f5; } .uploadPics .picCont > p { margin-top: 20px; text-align: center; } .uploadPics .picFooter { text-align: center; } .uploadPics .picFooter{ display: inline-block; margin: 20px; width: 130px; height: 35px; font-size: 18px; line-height: 35px; color: #fff; border-radius: 5px; cursor: pointer; } .uploadPics .picFooter .upload { background-color: #aaa; } .uploadPics .picFooter .confirm { background-color: #ed2828; } #myCan{ position: absolute; top: 86px; right: 110px; } .info{ position: absolute; top: 16px; right: 196px; } </style> <link rel="stylesheet" href="<%=request.getContextPath()%>/Jcrop/css/jquery.Jcrop.css" type="text/css" /> <script type="text/javascript" src="<%=request.getContextPath()%>/Jcrop/js/jquery.Jcrop.js"></script> </head> <body> <div id="showbg" style="display: none;"> <div class="uploadPics"> <div class="picCont" style="width:300px;height:300px;margin:20px auto 0;padding:0;" > <div id=imgfield style=overflow:hidden;width:100%;height:100% ></div> </div> <div class="picFooter"> <input type="file" accept=".jpg,.jpeg,.png,.gif" id="fileimg" name="fileimg" style="display:none" onchange="imgchange()" /> <span class="layui-btn layui-btn-sm" onclick="getimg()">上傳原圖</span> <!-- <span class="btn confirm" onclick="subform()">確認</span> --> </div> </div> <div class="info">裁剪後圖片:<br>圖片大小:200 × 200</div> <canvas id="myCan" width="200" height="200"></canvas> </div> </body> <script type="text/javascript"> //上傳的文件名 var fileName =""; // var nim = ''; function subform() { if($("#imgfield").html()){ var ossurl = ""; //獲取裁剪完後的base64圖片url,轉換爲blob var urlData=document.getElementById("myCan").toDataURL(); var blob = dataURLtoBlob(urlData); // blob轉arrayBuffer var reader = new FileReader(); reader.readAsArrayBuffer(blob); reader.onload = function (event) { var opts = { url : "web?module=stwmgr&action=Advertisement&method=getOSSSecurityToken&tokenId=<%=request.getParameter("tokenId")%>", type : "POST", processData : false, contentType : false, dataType : "json", async:false, success : function(token) { var client = new OSS.Wrapper({ accessKeyId : token.accessKeyId,//key accessKeySecret : token.accessKeySecret,//密碼、 stsToken : token.securityToken, region : token.ossRegion,//阿里雲服務器地址 bucket : token.ossBucket,//上傳的到的文件夾 secure:true }); var key = "stw_mgr/images/portrait_images/" + getCurrentDate() + getExtension(fileName); //arrayBuffer轉buffer var buffer = new OSS.Buffer(event.target.result); //上傳接口改成put client.put(key, buffer).then(function(result) { console.log(result); var url = client.signatureUrl(key); $("input[name='portraitUri']").val(key); $("#portraitImage").attr("src", url); console.log(url); ossurl = url; }).catch(function(err) { console.log(err.message); }); } }; $.ajax(opts); } // uploadTitleImage(blob); //網易雲信上傳 nim.sendFile({ scene: 'p2p', to: 'account', type: 'image', blob: blob, // wxFilePath: neteaseFile, beginupload: function(upload) { // - 若是開發者傳入 fileInput, 在此回調以前不能修改 fileInput // - 在此回調以後能夠取消圖片上傳, 此回調會接收一個參數 `upload`, 調用 `upload.abort();` 來取消文件上傳 }, uploadprogress: function(obj) { console.log('文件總大小: ' + obj.total + 'bytes'); console.log('已經上傳的大小: ' + obj.loaded + 'bytes'); console.log('上傳進度: ' + obj.percentage); console.log('上傳進度文本: ' + obj.percentageText); }, uploaddone: function(error, file) { console.log(file); $('#neteaseUri').val(file.url); console.log('上傳' + (!error?'成功':'失敗')); } }); } } function getimg() { $("#fileimg").click(); } function imgchange() { var localimg = $("#fileimg").get(0).files[0]; if(!localimg){ return; } fileName = localimg.name; var fileSize = localimg.size; var fileType=fileName.substring(fileName.lastIndexOf('.'),fileName.length).toLowerCase(); if(fileType!='.gif' && fileType!='.jpeg' && fileType!='.png' && fileType!='.jpg') { alert("上傳失敗,請上傳jpg,jpeg,png格式的圖片"); return; } var size=10*1024*1024; if(fileSize>size){ alert("上傳失敗,請上傳10MB之內的圖片。"); return; } var reader=new FileReader(); //將文件讀取爲DataURL reader.readAsDataURL(localimg); reader.onload= function (e) { var localimghtml = '<img id="cropbox" src="' + e.target.result + '" >'; $("#imgfield").html(localimghtml); initJcrop(); }; } function initJcrop(){ $('#cropbox').Jcrop({ onSelect: updateCoords, aspectRatio: 1, boxWidth: 300, boxHeight: 300 }, function () { //圖片實際尺寸 var bb = this.getBounds(); var bWidth= Number(bb[0]) / 2; var bHeight= Number(bb[1]) / 2; this.setSelect([0, 0, bWidth,bHeight]); var ss = this.getWidgetSize(); var aheight = (300 - Number(ss[1])) / 2 + "px"; $(".jcrop-holder").css("margin-top", aheight); }); } function updateCoords(c){ // console.log(c); var img=document.getElementById("cropbox"); var ctx=document.getElementById("myCan").getContext("2d"); //img,開始剪切的x,Y座標寬高,放置圖像的x,y座標寬高。 ctx.drawImage(img,c.x,c.y, c.w, c.h,0,0,200,200); } //**dataURL to blob** function dataURLtoBlob(dataurl) { var arr = dataurl.split(','), mime = arr[0].match(/:(.*?);/)[1], bstr = atob(arr[1]), n = bstr.length, u8arr = new Uint8Array(n); while (n--) { u8arr[n] = bstr.charCodeAt(n); } return new Blob([u8arr], { type: mime }); } </script> </html>
//點擊頭像框觸發事件 $("#portraitImage").click(function(){ var c=document.getElementById("myCan"); var cxt=c.getContext("2d"); cxt.clearRect(0,0,c.width,c.height); var porsrc = this.src; var orginimg = '<img id="cropbox" src="" crossorigin="Anonymous" >'; //" crossorigin="Anonymous" //var image = new Image(); //image.setAttribute("crossOrigin",'Anonymous') //image.crossOrigin = "Anonymous"; //image.src = porsrc; $("#imgfield").html(orginimg); //把原有的頭像圖片添加到可編輯框裏 $("#cropbox").attr("src",porsrc); //初始化插件方法 initJcrop(); layer.open({ type: 1, scrollbar: false, title: ['頭像裁剪框', 'font-size:16px;'], area: ['800px', '500px'], btn: ['保存'], tipsMore: true, content: $("#showbg"), yes: function(index, layero){ subform(); $('#showbg').css('display','none'); layer.closeAll(); }, cancel: function(){ $('#showbg').css('display','none'); } }); });
最後想了一個改進的地方,就是以前已經有頭像的用戶,可能會複用之前的頭像,因此點擊修改的時候要把原來的圖片帶到圖片處理框裏。這裏遇到了圖片的跨越請求問題。解決辦法是在img標籤添加一個屬性:crossorigin="Anonymous"。web
先後大概5天的時間作了這麼一個小小的功能,收穫了圖像處理的知識,雖然理解上並無很深,可是能運用起來,也蠻有成就感的了。記錄下探索的歷程。望更進一步。ajax
JCrop官網地址:http://deepliquid.com/content/Jcrop_Download.htmlchrome