我作了一個 Web 本地圖片 canvas 截取上傳 的demo。發現了幾個問題,記錄下:css
1. Canvas 元素大小 (css width height) 和表面大小(canvas 自身的 width height 屬性)兩個概念是不同的,當兩個大小不一致時,座標須要進行轉換計算。android
// 其中 x, y 是視口座標 function windowToCanvas(canvas, x, y) { var bbox = canvas.getBoundingClientRect(); return { x: (x - bbox.left) * (canvas.width / bbox.width), y: (y - bbox.top) * (canvas.height / bbox.height) }; }
2. android 老的原生手機瀏覽器 Blob 構造函數有bug (好比使用微信或qq瀏覽器, new Blob() 會拋出異常), 個人解決方法是使用 base64 上傳,服務端解碼。因爲base64大小爲原來的4/3倍,天然會想能不能像c語言那樣接把字符看成unsigned char來看待。仔細一想 js 是不行的。因text+=1,數字1將被轉換爲字符串"1",而text[i]是僅可讀,不修改!ajax
var clearWidth, clearHeight; var imageLoaded = false; var cutPoint = {x:0, y:0}; var gFileName = ""; document.getElementById('uploadbtn').onclick = function(){ if(!imageLoaded){ return; } var originalCanvas = document.getElementById('original'); var canvas = document.createElement('canvas'); var context = canvas.getContext('2d'); canvas.width = clearWidth; canvas.height = clearHeight; context.drawImage(originalCanvas, cutPoint.x, cutPoint.y, clearWidth, clearHeight, 0, 0, clearWidth, clearHeight); // 注意 toDataURL 返回的默認是 png 格式 // data 是 base64 編碼 var data = canvas.toDataURL(); // 第二個參數的值若是在0.0和1.0之間的話, 會被看做是圖片質量參數 // 可是我測試大小沒什麼變化 //var data = canvas.toDataURL('image/png', 0.5); var encodeData = data.split(',')[1]; // 解 base64 編碼 var decodedData = window.atob(encodeData); var ia = new Uint8Array(decodedData.length); for (var i = 0; i < decodedData.length; i++) { ia[i] = decodedData.charCodeAt(i); }; var blob; try{ // toDataURL 返回的默認是 png 格式,因此這裏固定爲 image/png blob = new Blob([ia], {type:"image/png"}); }catch(e){ // 使用 http://haomou.net/2016/01/14/2016_android_blob/ 仍然沒法解決 // android 手機瀏覽器 Blob 構造函數 bug // 個人解決方法是使用 base64 上傳,服務端解碼 // alert("new Blob exception:" + e); // // TypeError old chrome and FF // var BlobBuilder = window.BlobBuilder || // window.WebKitBlobBuilder || // window.MozBlobBuilder || // window.MSBlobBuilder; // // alert("BlobBuilder:" + typeof(BlobBuilder)); // if(e.name == 'TypeError' && BlobBuilder){ // var bb = new BlobBuilder(); // bb.append([ia.buffer]); // blob = bb.getBlob("image/png"); // } else if(e.name == "InvalidStateError"){ // // InvalidStateError (tested on FF13 WinXP) // blob = new Blob( [ia.buffer], {type : "image/png"}); // } // else{ // // We're screwed, blob constructor unsupported entirely // alert("blob constructor unsupported entirely"); // return; // } } // 修改文件名後綴格式 var filename = gFileName; var index = filename.lastIndexOf('.'); if(index >= 0){ filename = filename.substring(0, index); filename += ".png"; } var fd = new FormData(); if(blob){ fd.append('image', blob, filename); }else{ // 採用 base64 上傳 fd.append("filename", filename); fd.append("image", encodeData); // 因爲 base64 大小爲原來的 4/3 倍,天然會想能不能像 c 語言那樣 // 直接把字符看成 unsigned char 來看待。js 是不行的。由於 // text += 1 ,數字1將被轉換爲字符串"1" ,而 text[i] 是僅可讀,不 // 可修改! } // 使用 ajax 發送 $.ajax({ url:"http://192.168.3.102:8080/upload", type:"POST", data:fd, processData: false, // 告訴jQuery不要去處理髮送的數據 contentType: false, // 告訴jQuery不要去設置Content-Type請求頭 success:function() { console.log("post success."); }, error: function(){ console.log("post failed."); } }); }