Web 本地圖片 canvas 截取上傳
我做了一個 Web 本地圖片 canvas 截取上傳 的demo。發現了幾個問題,記錄下:
1. Canvas 元素大小 (css width height) 和表面大小(canvas 自身的 width height 屬性)兩個概念是不一樣的,當兩個大小不一致時,坐標需要進行轉換計算。
// 其中 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. a ndroid 老的原生 手機瀏覽器 Blob 構造函數有 bug (比如使用微信或qq瀏覽器, new Blob() 會拋出異常) , 我的解決方法是使用 base64 上傳,服務端解碼。由于 base64 大小為原來的 4/3 倍,自然會想能不能像 c 語言那樣接把字符當作 unsigned char 來看待。仔細一想 js 是不行的。因 text+=1 ,數字 1 將被轉換為字符串 "1" ,而 text[i] 是僅可讀,不修改!
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.");
}
});
}</pre> </div>