在瀏覽器中操作文件,多數(shù)情況下用到的是 File 對象,從 <input type='file' /> 元素獲取,進而繼續(xù)操作(例如將選擇的圖片展示在頁面上,用ajax將文件上傳至服務(wù)器等)。這里介紹在HTTP獲取圖片URL創(chuàng)建圖片,canvas拼接文字,上傳到服務(wù)器。
一、canvas獲取dataURL
/**
* 根據(jù)二維碼畫canvas合成文字
* @param {string} src 二維碼圖片路徑
* @param {string} text 拼接的二維碼文字
* @return {string} src 合成后的圖片地址
*/
export async function drawImage(src, text) {
const img = await createImg(src);
const canvas = document.createElement('canvas');
let context = canvas.getContext('2d');
// 確保canvas的尺寸和圖片一樣
const width = img.width;
const height = img.height;
canvas.width = img.width;
canvas.height = img.height + 50;
context.drawImage(img, 0, 0, width, height);
context.fillStyle = '#FFF';
context.fillRect(0, img.height, width, 50);
const font = '20px Arial bolder';
context.font = font;
context.fillStyle = 'black';
context.fillText(text, width / 2 - (context.measureText(font).width / 2), img.height + 29);
let url = canvas.toDataURL();
// canvas 轉(zhuǎn)為blob類型 可直接傳入file
// canvas.toBlob((blob) => {
// console.log(blob);
// var myFile = new File([blob], 'aa.png', {
// type: 'mime'
// });
// });
return url;
}
/**
* 創(chuàng)建圖片
* @param {string} src 被創(chuàng)建圖片的src或者base64
* @return {Promise.<resolveType, rejectType>}
*/
function createImg(src) {
return new Promise((resolve, reject) => {
let image = new Image();
image.crossOrigin = 'anonymous';
image.onload = () => {
resolve(image);
};
image.onerror = () => {
reject({
errStr: '圖片加載失敗,請重試'
});
console.log('圖片加載失敗,請重試');
};
image.src = src;
});
}
二、二進制數(shù)據(jù)容器
-
blob:適用于讀取二進制數(shù)據(jù),比如圖片文件
- 表示不可變、原始數(shù)據(jù)的類文件對象(js都不一定認得)
- blob更偏重于整體操作(整個文件的二進制流)
-
ECMAScript二進制數(shù)組 按照數(shù)組的方式處理二進制數(shù)據(jù)
- js可以識別的二進制數(shù)據(jù)
可以做流的切割,所有注重于對二進制流中的字節(jié)進行處理
1. 第一種方式
我第一次采取的方法利用canvas的todataurl方法獲取dataurl后 :拿到dataurl后獲取逗號后面的編碼數(shù)據(jù)利用window.atob將編碼解碼,將解碼后的字符串使用charcodeat獲取每一個字符串的unicode字符,然后存入Uint8Array數(shù)組,創(chuàng)建文件對象,放入form表單中上傳到服務(wù)器。
dataURL是base64編碼的數(shù)據(jù)格式
(將 dataURL 轉(zhuǎn)為 blob對象:網(wǎng)上有用new Blob([u8arr], { type: mime }); 把Uint8Array轉(zhuǎn)為blob,再后續(xù)操作也可以,我給省去了)
/**
* 將base64轉(zhuǎn)換為文件
* @param {string} apiUrl 服務(wù)器地址
* @param {string} dataurl url
* @param {string} imageName 圖片名字
* @return {Object} response 文件信息
*/
export function dataURLtoFile(apiUrl, dataurl, imageName) {
// 將base64轉(zhuǎn)換為文件流
const arr = dataurl.split(',');
// 獲取逗號后面的編碼數(shù)據(jù)利用window.atob將編碼解碼
const mime = arr[0].match(/:(.*?);/)[1];
const bstr = atob(arr[1]);
// 解碼后的字符串使用charcodeat獲取每一個字符串的unicode字符
let n = bstr.length;
const u8arr = new Uint8Array(n);
while (n--) {
u8arr[n] = bstr.charCodeAt(n);
}
// 存入Uint8Array數(shù)組 創(chuàng)建文件對象
var myFile = new File([u8arr], imageName, {
type: mime
});
var formData = new FormData();
// 將文件轉(zhuǎn)二進制
formData.append('file', myFile);
let config = {
headers: {
'Content-Type': 'multipart/form-data'
}
};
// 通過axios將圖片上傳至服務(wù)器
return new Promise((resolve, reject) => {
axios.post(apiUrl, formData, config).then(res => {
const response = res.data;
if (response && response.errNo === 0) {
const {
data
} = response;
resolve(data);
}
else {
reject(response.errstr);
}
})
.catch(err => {
reject(err);
console.log(err);
});
});
}
- 第二種方法
后整理時發(fā)現(xiàn)file對象要求傳入的文件內(nèi)容也可以是Blob,想到canvas也可以轉(zhuǎn)為blob對象

于是就測試了canvas不用toDataURL(),用toBlob()直接把blob傳入new file()中,這樣代碼簡略了很多
var blob = canvas.toBlob((blob) => {
console.log(blob);
var myFile = new File([blob], 'aa.png', {
type: 'mime'
});
console.log(myFile);
});
對比結(jié)果
-第一種方式的file對象

-第二種的blob 和file對象

這是測試上傳到我本地自建的服務(wù)器中,是一樣的,size少了1 ,忽略掉圖片名字和后綴,測試寫死了, 正常都應(yīng)是動態(tài)傳進來的

再提供幾個常用的轉(zhuǎn)換參考
blob轉(zhuǎn)dataUrl:
用途:拿到blob對象后,希望展示這個數(shù)據(jù)
用法:使用window.URL.createObjectURL(blob)拿到dataUrl對象,然后進行展示
canvan轉(zhuǎn)blob:canvas 最新的方法 toblob
canvas轉(zhuǎn)dataurl:canvas的實例方法 todataurl
blob轉(zhuǎn)canvas:blob轉(zhuǎn)換為dataurl對象后 新疆一個圖片用來顯示dataurl數(shù)據(jù),然后將圖片放入canvas中
dataurl轉(zhuǎn)canvas:dataurl先變成圖片再放入canvas
img轉(zhuǎn)canvas:canvas的drawImage方法支持將img放入canvas
canvas轉(zhuǎn)img:利用canvas的todataurl方法獲取圖片數(shù)據(jù)后,新建圖片控件展示圖片