不少狀況下用戶上傳的圖片都須要通過裁剪,好比頭像啊什麼的。但之前實現這類需求都很複雜,每每須要先把圖片上傳到服務器,而後返回給用戶,讓用戶肯定裁剪座標,發送給服務器,服務器裁剪完再返回給用戶,來回須要 5 步。步驟繁瑣不說,當不少用戶上傳圖片的時候也很影響服務器性能。javascript
HTML5 的出現讓咱們能夠更方便的實現這一需求。雖然這裏所說的技術都貌似有點過期了(前端界的「過期」,你懂的),但仍是有些許參考價值。在這裏我只說一下要點,具體實現同窗們慢慢研究。html
下面奉上我本身寫的一個demo,在輸入框中選好本身服務器 url, 生成好圖片後點擊 Submit 上傳,而後本身去服務器裏看看效果吧~~前端
瀏覽器要求支持如下 Feature:java
代碼直接從現有項目移植過來,沒有通過「太多的」測試,寫的很亂,也沒註釋,你們就慢慢看吧。。。重點就在 js 腳本的 28 行,clipImage
函數中,同窗們能夠直接跳過去看。jquery
http://jsfiddle.net/windwhinny/d5qan0q7/ajax
HTML5 支持從 input[type=file]
元素中直接獲取文件信息,也能夠讀取文件內容。咱們用下面代碼就能夠實現:canvas
javascript$('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
裏,這樣本地圖片就顯示出來了。服務器
javascript$('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>
標籤,因此能夠直接插入到文檔流裏。app
這一步沒啥好說的,實現的方法也不少,須要得到下面四個裁剪框的座標:
以下圖所示:
這是時候咱們就須要用到 canvas
了,canvas
和圖片同樣,因此新建 canvas
時就要肯定其高寬。這裏咱們還運用到 image.naturalHeight
和 image.naturalWidth
這兩個屬性來獲取圖片原始尺寸。
將圖片放置入 canvas
時須要調用 drawImage
,這個接口參數比較多,在 MDN 上有詳細的說明。
javascriptdrawImage(image, sx, sy, sWidth, sHeight, dx, dy, dWidth, dHeight)
由於咱們用 canvas
只是用於裁剪圖片的,因此須要新建一個 canvas
讓它的尺寸和裁剪以後圖片的尺寸相等,此時 canvas
就至關與咱們的裁剪框。運用這個函數還能夠將大圖縮放成小圖,同窗們本身研究吧。
javascript// 如下四個參數由第三步得到 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
轉換一下。總之這裏挺麻煩的。。
javascriptvar 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
裏請求。
javascriptvar fd=new FormData(); fd.append('file',blob); $.ajax({ url:"your.server.com", type:"POST", data:fd, success:function(){} });
而後你服務器裏應該就能夠收到這個文件了~