無需Flash實現圖片裁剪——HTML5中級進階

hubuke 9年前發布 | 33K 次閱讀 HTML5 圖片裁剪 前端技術

前言

圖片裁剪上傳,不僅是一個很貼合用戶體驗的功能,還能夠統一特定圖片尺寸,優化網站排版,一箭雙雕。

需求就是那么簡單,在瀏覽器里裁剪圖片并上傳到服務器。

我第一個想到的方法就是,將圖片和裁剪參數(x,y,scale,rotate)一并上傳給服務器,服務器來做圖片處理,so easy。
但是,這并不符合潮流發展的方向:能在前端做的處理,就放前端做吧。
與潮流妥協的結果就是,前端越來越復雜。

一開始我并不認為瀏覽器能夠讀取并生成圖片。想想看啊,要做”點擊復制”的這樣簡單的功能,都需要借助 Flash 的瀏覽器,權限哪有那么大。

參閱各類網站,只要把圖片放在本地處理的,基本上都借用了Flash。隨便抄一個吧,沒有API,就算能修改圖片,上傳路徑都不知道怎么改。更關鍵的是,我對Flash一竅不通。

好在我們的網站已經完全拋棄了IE9以下的瀏覽器,只兼容現代HTML5瀏覽器。(連Opera和微軟都開始走Webkit內核的路線了,潮流就是跟著Chrome走)只能寄希望與HTML5,于是鉆研了一番,發現如下流程可行。

 

以下將對每個環節詳解。

獲取原圖片 File 對象

每個圖片文件處理的開始,都是由onchange事件開始

<script>

function handler(e){

var originPhoto = e.target.files[0]; // IE10+ 單文件上傳取第一個

window.originFileType = originPhoto.type; //暫存圖片類型

window.originFileName = originPhoto.name; //暫存圖片名稱

...

}

</script>

<input type="file" name="demo" onchange='handler(event)' accept="image/*" >

<img id="preview">

<button onclick="cropAndUpload()">確定并上傳</button></code></pre>

 

初始化Cropper

在這里介紹一個非常好用的庫 cropper.js
https://github.com/fengyuanchen/cropper
生成遮罩、獲取裁剪參數、輸出canvas … 而且絕對輕量級,壓縮后的css和js代碼只有30KB。他是基于JQuery的,引入JQuery可能還要再大點。不過現在哪個網站沒有在用JQuery呢?
兼容IE9+,移動端體驗良好,能夠響應觸摸縮放,拖動。以下是安卓4.4 原生瀏覽器中的預覽圖

2

function handler(event){

...

var URL = window.URL || window.webkitURL , originPhotoURL;

originPhotoURL = URL.createObjectURL(originPhoto);   //Base64

$('#preview').cropper({

    aspectRatio: 1 / 1,                 // 固定裁剪比例1:1,裁剪后的圖片為正方形

}).cropper('replace', originPhotoURL);  // 動態設置圖片預覽

}</code></pre>

 

繪制Canvas

cropper.js 提供了生成Canvas的方法getCroppedCanvas,可以指定生成畫布的大小。
或者根據getData獲取裁剪信息(包括旋轉和縮放)用ctx.drawImage(image, sx, sy, sWidth, sHeight, dx, dy, dWidth, dHeight)進行手動繪制。后者自由性高一點,但是既然有現成的方法,那么就直接用好了。

function cropAndUpload(){

// 此處注意,生成的Canvas長寬比應與之前規定的裁剪比例一致

// 否則生成的圖片會有失真

var size = {

    width:100,

    height:100

}

var croppedCanvas = $('#preview').cropper("getCroppedCanvas",size);  // 生成 canvas 對象

var croppedCanvasUrl = croppedCanvas.toDataURL(originFileType); // Base64

...

}</code></pre>

應當注意的是width和height的值并不推薦設置成固定值。裁剪框的大小可能是會超過100*100(比如500*500)的,而實際生成的 圖片卻是100*100,這樣的后果就是直接將一個500*500的高清圖片,壓縮成了100*100的失真圖片。同樣的,裁剪框小于100*100,生 成的圖片就會模糊。

Base64 轉Blob對象

字符串轉為二進制?(前端本來是個做頁面的,現在也開始操作文件了。自從有了HTML5,就可以把瀏覽器當作一個操作系統了)官方并沒有出 DataURLtoBlob的方法,所以只能自己寫一個,轉化也挺簡單:拆解文件類型,將字符數據轉成16進制數據存數組,并用數據初始化一個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});

}

function cropAndUpload(){

...

var croppedBlob = dataURLtoBlob(croppedCanvasUrl);

croppedBlob.name = originFileName; // Blob對象沒有name

// Upload(croppedBlob);

}</code></pre>


現在就可以像處理FileObject一樣處理 這個blob對象了。

 

其實在最新的HTML5標準中是支持HTMLCanvasElement.toBlob(callback, mimeType, quality) 的

croppedCanvas.toBlob(function(croppedBlob){

// Upload(croppedBlob);

},originFileType)</code></pre>


繞了一個彎,不過還是學到了東西。

 

原文作者來自 MaxLeap 團隊_UX成員:John王

來自:https://blog.maxleap.cn/archives/705

 本文由用戶 hubuke 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
 轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
 本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!