移動端web頭像上傳實現截取和照片方向修復


實戰所需js包:

jQuery、Jcrop、EXIF
 
本次實戰功能是在 app 中的 我的客戶 的客戶信息頁面中實現移動端web的頭像上傳,本次沒有實現圖像拖拽、縮放的觸摸事件功能(Jcrop在這方面的擴展支持實在不夠良好,弄了半天沒弄出來),若后續有更好的移動端web頭像上傳插件,可考慮后續替代升級。
 
demo主要實現的關鍵功能: 圖像的方向修正及圖像截取
雖然沒有實現圖像拖拽和雙指縮放,但其縮放后的相對於圖像的比例計算和拖拽坐標計算規則是一致的,可以參考。同時圖像的旋轉功能也可參考其中的核心代碼。(對於圖像旋轉及坐標計算真的是一個大坑,特別在移動端頁面代碼的調試困難比較大,主要來自於無法詳盡地獲取移動端頁面的控制台信息而導致的。。目前的移動端web遠程調試技術又僅限於windows+安卓機或mac+iphone,對於我這種windows+iphone的真是傷不起啊、、只能靠alert、、、)。以下demo代碼可以說不算長。但其中某些坑爬了很久才爬出來。。有點小郁悶。
 
好,簡單地介紹下截取圖像及方向旋轉吧。
 
首先我們的思路是利用Jcrop和canvas在前台完成圖像截取,利用exif獲得圖像方向信息再利用canvas旋轉圖像至正確方向,隨后把處理完后的圖像由canvas轉成base64傳給后台,再存為圖片文件。具體步驟:
 
1、通過input調用相機或相冊,在app內獲取到用戶想要上傳的源圖像;
2、讀取圖像方向信息,以便於對圖像進行截取區域的坐標轉換,如下圖例:

如上圖,綠色為圖像原本(真實)方向,紅色為圖像應該展示的方向;所以當我們取圖像左上角區域的時候,實際上應該取圖片真實方向的左下角;因為img標簽它自己會修復展示的方向,但是實際圖片的存放方向仍如綠色區域所示,所以如果我們直接將紅色區域的坐標用在img中進行截取時,就會存在截取區域對應不上的問題;所以我們要進行坐標轉換。
3、利用canvas獲取截取區域圖像數據信息,進行坐標轉換后畫入canvas中去;
4、進行方向修正,利用 canvas的rotate方法將已截取的圖像旋轉至正確方向,再重新畫入canvas中;
5、從canvas中獲取正確圖像的base64碼,並傳給后台。
 
以下是分布代碼展示:
h5部分:
在頁面上畫出一個span區域和一個隱藏的input:
1 <div class="header-img">
2 <span id="uploadImg"><!-- 自定義頭像上傳 -->
3 </span>
4 <input accept="image/gif,image/jpeg,image/jpg,image/png,image/bmp" type="file" style="display:none;" id="uploadImgInput">
5 <img id="myimg" src="${ctx }/resource/wo/img/man_1.png">
6 </div>
js部分:
用戶點擊span的時候手動觸發input的click事件來調用相冊或相機:
  1 //頭像上傳
  2 $("#uploadImg").on('click',function(){
  3 //input file的change事件只能觸發一次,因此每次點擊頭像后都將原input綁定的事件解除,重新賦值並綁定。
  4 $("#uploadImgInput").off('change');
  5 $('#uploadImgInput').val('');
  6 $("#uploadImgInput").on('change',uploadImgInputChangeHandler);
  7 $("#uploadImgInput").click();//手動觸發input點擊事件
  8 });
  9 //頭像上傳點擊事件觸發方法
 10 function uploadImgInputChangeHandler(){
 11 var input = this;
 12 if (input.files && input.files[0]) {
 13 var reader = new FileReader();
 14 reader.readAsDataURL(input.files[0]); //獲取選中的第一個圖片文件
 15 //獲取照片方向角屬性,也可用於用戶旋轉控制
 16 EXIF.getData(input.files[0], function() {
 17 // alert(EXIF.pretty(this));
 18 EXIF.getAllTags(this);
 19 //alert("Orientation:"+EXIF.getTag(this, 'Orientation'));
 20 pageData.Orientation = EXIF.getTag(this, 'Orientation'); //將方向信息存入對象中
 21 //return;
 22 });
 23 reader.onload = function (e) {
 24 $("#displayImgDiv").show();
 25 $("#popupContent").hide();
 26 $('#displayImg').attr('src', e.target.result);
 27 $('#displayImg')[0].onload = function(){
 28 //調用Jcrop進行圖像截取,具體參數配置可查看相關教程
 29 $('#displayImg').Jcrop( {
 30 allowSelect: true,
 31 allowMove: true,
 32 allowResize: true,
 33 setSelect: [ 10, 10, screenWidth-10, screenWidth-10],
 34 aspectRatio: 1 ,
 35 minSize: [200, 200 ],
 36 maxSize: [screenWidth, screenWidth ],
 37 dragEdges: true,
 38 onSelect: updateCoords,//截取框每次移動后的調用的方法
 39 trackDocument: false
 40 } ,function(){
 41 pageData.jcropApi = this;//將jcrop對象存入全局變量中,以便后續獲取
 42 }
 43 );
 44 }
 45 }
 46 }
 47 }
 48  
 49 //jcrop選框選擇后處理事件
 50 function updateCoords(c){
 51 var img = document.getElementById("displayImg");
 52 var canvas = document.createElement('canvas');
 53 var ctx = canvas.getContext("2d");
 54 var imgW_ori = eval(img.width);//無視方向后的img標簽中圖片的原始方向角度的寬
 55 var imgH_ori = eval(img.height);//無視方向后的img標簽中圖片的原始方向角度的高
 56 var imgW_css = $(img).width();
 57 var imgH_css = $(img).height();
 58 //修復手機圖像方向問題
 59 //1、坐標確定:由於img標簽在瀏覽器中會根據Orientation屬性自動調整展示方向
 60 //故修復方向實際上則是根據當前圖像截取框與偽修復圖像整體的位置,判斷應該截取得區域於真實圖片中的位置關系后,
 61 //對相關數據進行處理,canvas的drawImage一共有9個傳參,其中需要根據方向調整的有4個:
 62 var sx,sy,sw,sh,wRatio,hRatio,tx,ty,degree;
 63 var Orientation = eval(pageData.Orientation);
 64 if(Orientation != 1 && typeof(Orientation)!="undefined" && Orientation != "" ){
 65 //如果方向角不為1,都需要進行旋轉
 66 switch(Orientation){
 67 case 6://需要順時針(向左)90度旋轉
 68 //對於圖片縮放過后,需獲取圖片實際縮放比例
 69 wRatio = imgW_ori/imgH_css;
 70 hRatio = imgH_ori/imgW_css;
 71 //alert(imgW_ori+","+imgH_ori+","+imgW_css+","+imgH_css);
 72 sx = c.y*wRatio;
 73 sy = (imgW_css-c.x-c.w)*hRatio;
 74 sw = c.h*wRatio;
 75 sh = c.w*hRatio;
 76 degree = 90 * Math.PI / 180;
 77 tx = 0;
 78 ty = -200;
 79 /* tx = 0;
 80 ty = -imgH_ori;
 81 canvas.width = imgH_ori;
 82 canvas.height = imgW_ori; */
 83 break;
 84 case 8://需要逆時針(向右)90度旋轉
 85 wRatio = imgW_ori/imgH_css;
 86 hRatio = imgH_ori/imgW_css;
 87 sx = (imgH_css-c.y-c.h)*wRatio;
 88 sy = c.x*hRatio;
 89 sw = c.h*wRatio;
 90 sh = c.w*hRatio;
 91 degree = 3 * 90 * Math.PI / 180;
 92 tx = -200;
 93 ty = 0;
 94 /* tx = -imgW_ori;
 95 ty = 0;
 96 canvas.width = imgH_ori;
 97 canvas.height = imgW_ori; */
 98 break;
 99 case 3://需要180度旋轉
100 wRatio = imgW_ori/imgW_css;
101 hRatio = imgH_ori/imgH_css;
102 sx = (imgW_css-c.x-c.w)*wRatio;
103 sy = (imgH_css-c.y-c.h)*hRatio;
104 sw = c.w*wRatio;
105 sh = c.h*hRatio;
106 degree = Math.PI;
107 tx = -200;
108 ty = -200;
109 /*tx = -imgW_ori;
110 ty = -imgH_ori;
111 canvas.width = imgW_ori;
112 canvas.height = imgH_ori; */
113 break;
114 }
115 }else{
116 wRatio = imgW_ori/imgW_css;
117 hRatio = imgH_ori/imgH_css;
118 sx = c.x*wRatio;
119 sy = c.y*hRatio;
120 sw = c.w*wRatio;
121 sh = c.h*hRatio;
122 tx = 0;
123 ty = 0;
124 }
125 var tempImage = new Image();//新建一個image對象,用於存放不帶exif信息的圖像數據,新建image的原因是若直接使用原來的image對象,會有圖片展示區域與真實區域錯位不一致從而導致無法獲取正確的圖像源數據
126 tempImage.src = img.src;
127 tempImage.onload = function(){//確保圖像加載完畢后再進行下一步,不然可能會導致獲取不到圖片寬高
128 //將canvas畫布的大小設為200x200大小並裁剪成圓形作為頭像
129 canvas.width = 200;
130 canvas.height = 200;
131 ctx.arc(100, 100, 100, 0 ,2*Math.PI);
132 ctx.clip();
133 //alert("Orientation:"+Orientation+","+sx+","+sy+","+sw+","+sh+","+tx+","+ty+","+degree);
134 ctx.drawImage(tempImage, sx, sy, sw, sh, 0, 0, 200, 200); //在canvas中將裁剪后圖片重新畫出來
135 //ctx.drawImage(img, 0, 0, 3024, 4032, 0, 0, 200, 200);
136 var base64 = canvas.toDataURL('image/jpeg',0.5);
137 //window.open(base64);
138 //2、接下來進行旋轉
139 var resultImg = new Image();//新建一個image對象,用於存放截圖后的數據
140 resultImg.src = base64;
141 resultImg.onload = function(){
142 if(degree){
143 ctx.rotate(degree);//對方向進行修正
144 }
145 ctx.drawImage(resultImg, tx, ty);
146 pageData.base64 = canvas.toDataURL('image/jpeg');//將base64碼存入全局變量中
147 //window.open(pageData.base64);
148 }
149 }
150 }

 

這樣就拿到了每次截取后的截取區域的正確base64碼,當用戶點擊確定的時候將該數據傳給后台即可;
 
這種前台截取得方式適合用於圖像清晰度要求低,否則圖像太大還是建議使用輸入輸出流傳給后台后再進行圖像處理;優點是前台直接完成了圖像處理工作,減輕了服務器的壓力,同時能用js實現的為什么要麻煩后台呢對吧。
 
水平有限,以上經驗僅供參考,若有不同意見或建議歡迎一起討論和學習~

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM