HTML5裁剪圖片並上傳至服務器實現原理講解
第一步:獲取文件
HTML5 支持從 input[type=file]
元素中直接獲取文件信息,也可以讀取文件內容。我們用下面代碼就可以實現:
$('input[type=file]').change(function(){ var file=this.files[0]; // continue ... });
第二部:讀取文件,並生成 Image
元素
這一步就需要用到 FileReader
了,這個類是專門用來讀取本地文件的。純文本或者二進制都可以讀取,但是本地文件必須是經過用戶允許才能讀取,也就是說用戶要在input[type=file]
中選擇了這個文件,你才能讀取到它。
通過 FileReader
我們可以將圖片文件轉化成 DataURL
,就是以 data:image/png;base64,
開頭的一種URL,然后可以直接放在 image.src
里,這樣本地圖片就顯示出來了。
$('input[type=file]').change(function(){ var file=this.files[0]; var reader=new FileReader(); reader.onload=function(){ // 通過 reader.result 來訪問生成的 DataURL var url=reader.result; setImageURL(url); }; reader.readAsDataURL(file); }); var image=new Image(); function setImageURL(url){ image.src=url; }
Image
就是在 html
里的 <img>
標簽,所以可以直接插入到文檔流里。
第三步:獲取裁剪坐標
這一步沒啥好說的,實現的方法也很多,需要獲得下面四個裁剪框的坐標:
- Y坐標
- X坐標
- 高度
- 寬度
如下圖所示:
第四部:裁剪圖片
這是時候我們就需要用到 canvas
了,canvas
和圖片一樣,所以新建 canvas
時就要確定其高寬。這里我們還運用到image.naturalHeight
和 image.naturalWidth
這兩個屬性來獲取圖片原始尺寸。
將圖片放置入 canvas
時需要調用 drawImage
,這個接口參數比較多,在 MDN 上有詳細的說明。
drawImage(image, sx, sy, sWidth, sHeight, dx, dy, dWidth, dHeight)
因為我們用 canvas
只是用於裁剪圖片的,所以需要新建一個 canvas
讓它的尺寸和裁剪之后圖片的尺寸相等,此時canvas
就相當與我們的裁剪框。運用這個函數還可以將大圖縮放成小圖,同學們自己研究吧。
// 以下四個參數由第三步獲得 var x, y, width, height; var canvas=$('<canvas width="'+width+'" height="'+height+'"></canvas>')[0], ctx=canvas.getContext('2d'); ctx.drawImage(image,x,y,width,height,0,0,width,height); $(document.body).append(canvas);
將 canvas
加入文檔流之后,就可以看到裁剪后的效果了。不過我們還需要將圖片上傳至服務器里。
第五步:讀取裁剪后的圖片並上傳
這時我們要獲取 canvas
中圖片的信息,用 toDataURL
就可以轉換成上面用到的 DataURL
。 然后取出其中 base64 信息,再用 window.atob
轉換成由二進制字符串。但 window.atob
轉換后的結果仍然是字符串,直接給 Blob
還是會出錯。所以又要用 Uint8Array
轉換一下。總之這里挺麻煩的。。
var data=canvas.toDataURL(); // dataURL 的格式為 “data:image/png;base64,****”,逗號之前都是一些說明性的文字,我們只需要逗號之后的就行了 data=data.split(',')[1]; data=window.atob(data); var ia = new Uint8Array(data.length); for (var i = 0; i < data.length; i++) { ia[i] = data.charCodeAt(i); }; // canvas.toDataURL 返回的默認格式就是 image/png var blob=new Blob([ia], {type:"image/png"});
這時候裁剪后的文件就儲存在 blob
里了,我們可以把它當作是普通文件一樣,加入到 FormData
里,並上傳至服務器了。
FormData
顧名思義,就是用來創建表單數據的,用 append
以鍵值的形式將數據加入進去即可。但他最大的特點就是可以手工添加文件或者 Blob
類型的數據,Blob
數據也會被當作文件來處理。原生 js 可以直接傳遞給 xhr.send(fd)
, jquery 可以放入 data
里請求。
var fd=new FormData(); fd.append('file',blob); $.ajax({ url:"your.server.com", type:"POST", data:fd, success:function(){} });
然后你服務器里應該就可以收到這個文件了~