摘要:前陣子七夕的時候搞了一個活動頁,需要做一個本地圖片的裁剪上傳功能,用于生成一些特定的表白圖片。還有就是是配合實現的,因為我是直接在項目中復制過來改改的,就懶得轉換了圖片讀取要裁剪首先肯定就是讀取圖片文件。
前陣子七夕的時候搞了一個h5活動頁,需要做一個本地圖片的裁剪上傳功能,用于生成一些特定的表白圖片。主要是用到了H5的FileApi 和 Canvas。個人感覺圖片裁剪功能還是很實用的,故寫篇文章分享一下。
demo地址:https://github.com/Bless-L/im...
效果gif:
(PS:這個demo本來是移動端的,但了為了方便錄制效果,所以我用chrome模擬地跑了一下。
還有就是demo是配合Vue實現的,因為我是直接在項目中復制過來改改的,就懶得轉換了)
要裁剪首先肯定就是讀取圖片文件。其實也很簡單,用一個input指定為file類型就可以了。
//Vue里面的methods clipImg(event){ this.clip = new Clip("container",this); this.clip.init(event.target.files[0]); this.isClip = true; document.body.addEventListener("touchmove",this.noScoll,false); },
然后就是處理獲得的文件
//這些方法是寫在Clip類里面的 handleFiles(file){ let t = this; let reader = new FileReader(); reader.readAsDataURL(file); reader.onload = function() { t.imgUrl = this.result; t.paintImg(this.result); } }
先新建一個FileReader類,然后把讀得的文件用readAsDataURL轉換為base64編碼,再通過paintImg方法進行繪制處理。
需要注意的是文件讀取是異步的,所以讀取后的操作需要在onload函數中進行。
繪制裁剪界面 初始化先是初始化一些基本參數
//初始化 init(file){ this.sx = 0; //裁剪框的初始x this.sy = 0; //裁剪框的初始y this.sWidth = 233; //裁剪框的寬 this.sHeight = 175; //裁剪框的高 this.chooseBoxScale = 233/175;//裁剪框的寬高比 this.handleFiles(file); }
在這里裁剪框的比例是固定的4:3,有需要的同學可以自行更改。至于寬高那個是先照著設計稿設一個數值,后面會根據不同的圖片而重新設置。
繪制裁剪界面paintImg(picUrl){ //other code //..... img.onload = function() { let imgScale = img.width / img.height; let boxScale = t.regional.offsetWidth / t.regional.offsetHeight; //判斷盒子與圖片的比列 if (imgScale < boxScale) { //設置圖片的像素 t.imgWidth = t.regional.offsetHeight * imgScale; t.imgHeight = t.regional.offsetHeight; } else { //設置圖片的像素 t.imgWidth = t.regional.offsetWidth; t.imgHeight = t.regional.offsetWidth / imgScale; } //判斷圖片與選擇框的比例大小,作出裁剪 if (imgScale < t.chooseBoxScale) { //設置選擇框的像素 t.sWidth = t.imgWidth; t.sHeight = t.imgWidth / t.chooseBoxScale; //設置初始框的位置 t.sx = 0; t.sy = (t.imgHeight - t.sHeight) / 2; } else { //設置選擇框的像素 t.sWidth = t.imgHeight * t.chooseBoxScale; t.sHeight = t.imgHeight; t.sx = (t.imgWidth - t.sWidth) / 2; t.sy = 0; } //(1) }
這段代碼比較長。
先說一下裁剪界面的結構。看那demo及動圖可以知道,裁剪界面中,首先有一個最外層的容器,裝著圖片,即id為container的div,稱為1;
然后是圖片容器,即id為image-box的canvas,稱為2;
最后是最外面被掏空裁剪區域的模糊層,即id為cover-box的canvas,稱為3。
這幾個容器中,1的寬高是固定的。而2則在保證比例不變的情況下有一邊占滿整個1。所以可以看到上面那段判斷盒子與圖片比列的代碼是在實現這個顯示方式。
同時可以看到3的裁剪區域也是同理的,在保證比例不變的情況下有一邊占滿整個2。亦即裁剪區域的比例是在事先就設計好的,在這里是4:3。
所以我在效果圖中將高填滿容器和寬填滿容器的圖片都演示了一遍。
一些處理//續上面(1) //高分屏下圖片模糊,需要2倍處理 t.getImage.height = 2 * t.imgHeight; t.getImage.width = 2 * t.imgWidth; t.getImage.style.width = t.imgWidth + "px"; t.getImage.style.height = t.imgHeight + "px"; let vertSquashRatio = t.detectVerticalSquash(img); cxt.drawImage(img, 0, 0,2 * t.imgWidth * vertSquashRatio, 2 * t.imgHeight * vertSquashRatio) t.cutImage(); t.drag();
第一個是高分屏下圖片模糊的問題,在高分屏下用canvas繪制某些圖片是會出現模糊,估計是和canvas的繪制機制有關,具體原因戳這里。解決辦法也比較簡單,將canvas的css寬高固定,容器寬高擴大兩倍。(我的理解,css寬高就是canvas標簽style樣式設置的寬高,容器寬高就是里面那個畫板的寬高,不是同一個東西)經過這樣的處理后,絕大多數圖片的模糊問題解決了。
第二個是圖片繪制壓縮問題,在低版本的ios機型下繪制1m多以上的圖片時會出現壓縮,翻轉等問題,詳情及解決辦法戳這里。我上面就是用了一個stackflow里面的fix方法。
從這兩個問題可以見到,canvas繪制還不是非常成熟,使用時要注意一些bug及相關修復辦法。
移動時繪制drag(){ let t = this; let draging = false; //記錄初始點擊的pageX,pageY。用于記錄位移 let pageX = 0; let pageY = 0; //初始位移 let startX = 0; let startY = 0; t.editBox.addEventListener("touchmove", function(ev) { let e = ev.touches[0]; let offsetX = e.pageX - pageX; let offsetY = e.pageY - pageY; if (draging) { if (t.imgHeight == t.sHeight) { t.sx = startX + offsetX; if (t.sx <= 0) { t.sx = 0; } else if (t.sx >= t.imgWidth - t.sWidth) { t.sx = t.imgWidth - t.sWidth; } } else { t.sy = startY + offsetY; if (t.sy <= 0) { t.sy = 0; } else if (t.sy >= t.imgHeight - t.sHeight) { t.sy = t.imgHeight - t.sHeight; } } t.cutImage(); } }); t.editBox.addEventListener("touchstart", function(ev) { let e = ev.touches[0]; draging = true; pageX = e.pageX; pageY = e.pageY; startX = t.sx; startY = t.sy; }) t.editBox.addEventListener("touchend", function() { draging = false; })
這里邏輯不算太復雜,先是記錄初始位置,然后判斷是左右移動還是上下移動(對應高填滿容器和寬填滿容器),再根據pageX,pageY這些判斷位置量即可。
保存圖片save(){ let t = this; let saveCanvas = document.createElement("canvas"); let ctx = saveCanvas.getContext("2d"); //圖片裁剪后的尺寸 saveCanvas.width = 466; saveCanvas.height = 350; let images = new Image(); images.src = t.imgUrl; images.onload = function(){ //計算裁剪尺寸比例,用于裁剪圖片 let cropWidthScale = images.width/t.imgWidth; let cropHeightScale = images.height/t.imgHeight; t.drawImageIOSFix(ctx, images,cropWidthScale * t.sx , cropHeightScale* t.sy, t.sWidth * cropWidthScale, t.sHeight * cropHeightScale, 0, 0, 466, 350); // ctx.drawImage(images,2 * t.sx, 2 * t.sy, t.sWidth * 2, t.sHeight * 2, 0, 0, 466, 350); t.$vm.clipUrl = saveCanvas.toDataURL(); t.regional.removeChild(t.getImage); t.regional.removeChild(t.editBox); } }
這部分也挺簡單的,裁剪框那里記錄了裁剪開始及結束的坐標,然后新建一個canvas裁出來,并用toDataURL方法轉換為base64編碼,就可以傳輸到后臺了。我這里裁剪后的尺寸是固定的,這是業務需求,有需要的可以更改
總結大致的流程就是這樣,感謝大家的閱讀,如有錯誤,多多包涵。
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/81115.html
摘要:有好多小伙伴私聊我問我新特性和用法,下面我給大家具體介紹一下都新加了哪些新特性,下面我給大家總結一下。簡單了解一下就可以。有好多小伙伴私聊我問我html5新特性 和用法,下面我給大家具體介紹一下html5都新加了哪些新特性,下面我給大家總結一下。 1)新的語義標簽 footer header 等等2)增強型表單 表單2.03)音頻和視頻4)canvas 繪圖5) SVG繪圖6)地理定位7)...
摘要:移動端圖片裁剪器,基于制作的簡單裁剪器項目地址案例演示部分裁剪案例開始裁剪部分演示案例手機模式查看,效果更佳。 h5-cropper 移動端圖片裁剪器,基于 cropperjs 制作的簡單裁剪器 項目地址 https://github.com/sayll/h5-cropper 案例演示 HTML部分: 裁剪案例 開始裁剪 JS...
摘要:在裁剪框外拖動鼠標會生成一個新的裁剪框。這個是裁剪框的縱橫比,默認是不限制的。初始化完成后是否自動顯示裁剪框自動顯示的裁剪框的大小。方法的使用格式為手動顯示裁剪框。 插件介紹 這是一個我在寫以前的項目的途中發現的一個國人寫的jQuery圖像裁剪插件,當時想實現用戶資料的頭像上傳功能,并且能夠預覽圖片,和對圖片進行簡單的裁剪、旋轉,花了不少時間才看到了這個插件,感覺功能挺全面,代碼實現起...
閱讀 2702·2023-04-25 14:59
閱讀 889·2021-11-22 11:59
閱讀 635·2021-11-17 09:33
閱讀 2468·2021-09-27 13:34
閱讀 3898·2021-09-09 11:55
閱讀 2321·2019-08-30 15:44
閱讀 1123·2019-08-30 14:06
閱讀 1925·2019-08-29 16:55