在浏览器中操作文件,多数情况下用到的是 File 对象,从 元素获取,进而继续操作(例如将选择的图片展示在页面上,用ajax将文件上传至服务器等)。这里介绍在HTTP获取图片URL创建图片,canvas拼接文字,上传到服务器。
一、canvas获取dataURL
/**
* 根据二维码画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 转为blob类型 可直接传入file
// canvas.toBlob((blob) => {
// console.log(blob);
// var myFile = new File([blob], 'aa.png', {
// type: 'mime'
// });
// });
return url;
}
/**
* 创建图片
* @param {string} src 被创建图片的src或者base64
* @return {Promise.}
*/
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;
});
}
二、二进制数据容器
-
blob:适用于读取二进制数据,比如图片文件
- 表示不可变、原始数据的类文件对象(js都不一定认得)
- blob更偏重于整体操作(整个文件的二进制流)
-
ECMAScript二进制数组 按照数组的方式处理二进制数据
- js可以识别的二进制数据
可以做流的切割,所有注重于对二进制流中的字节进行处理
1. 第一种方式
我第一次采取的方法利用canvas的todataurl方法获取dataurl后 :拿到dataurl后获取逗号后面的编码数据利用window.atob将编码解码,将解码后的字符串使用charcodeat获取每一个字符串的unicode字符,然后存入Uint8Array数组,创建文件对象,放入form表单中上传到服务器。
dataURL是base64编码的数据格式
(将 dataURL 转为 blob对象:网上有用new Blob([u8arr], { type: mime }); 把Uint8Array转为blob,再后续操作也可以,我给省去了)
/**
* 将base64转换为文件
* @param {string} apiUrl 服务器地址
* @param {string} dataurl url
* @param {string} imageName 图片名字
* @return {Object} response 文件信息
*/
export function dataURLtoFile(apiUrl, dataurl, imageName) {
// 将base64转换为文件流
const arr = dataurl.split(',');
// 获取逗号后面的编码数据利用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数组 创建文件对象
var myFile = new File([u8arr], imageName, {
type: mime
});
var formData = new FormData();
// 将文件转二进制
formData.append('file', myFile);
let config = {
headers: {
'Content-Type': 'multipart/form-data'
}
};
// 通过axios将图片上传至服务器
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);
});
});
}
- 第二种方法
后整理时发现file对象要求传入的文件内容也可以是Blob,想到canvas也可以转为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);
});
对比结果
-第一种方式的file对象
-第二种的blob 和file对象
这是测试上传到我本地自建的服务器中,是一样的,size少了1 ,忽略掉图片名字和后缀,测试写死了, 正常都应是动态传进来的
再提供几个常用的转换参考
blob转dataUrl:
用途:拿到blob对象后,希望展示这个数据
用法:使用window.URL.createObjectURL(blob)拿到dataUrl对象,然后进行展示
canvan转blob:canvas 最新的方法 toblob
canvas转dataurl:canvas的实例方法 todataurl
blob转canvas:blob转换为dataurl对象后 新疆一个图片用来显示dataurl数据,然后将图片放入canvas中
dataurl转canvas:dataurl先变成图片再放入canvas
img转canvas:canvas的drawImage方法支持将img放入canvas
canvas转img:利用canvas的todataurl方法获取图片数据后,新建图片控件展示图片