DataURL,Blob和File是常用的前端存放二进制数据的对象,它们用在不同地方,有时候需要三者之间的相互转换
转为DataURL
Blob ==> DataURL
首先最简单的方法是使用FileReader来解析Blob对象:
const blob = new Blob([JSON.stringify({ hello: 'javascript' }, null, 2)], {type : 'application/json'});
const fr = new FileReader();
fr.onload = function (e) {
console.log(e.target.result); // data:application/json;base64,ewogICJoZWxsbyI6ICJqYXZhc2NyaXB0Igp9
}
fr.readAsDataURL(blob)
当然,你也可以选择将Blob转换为字符串,再使用btoa转换为base64编码的DataURL
需要注意的是,btoa对原始字符串有要求,字符编码必须为Latin-1,Latin-1是单字节编码字符集,也就是每个字符的编码不能超过255,否则会报错
const blob = new Blob([JSON.stringify({ hello: 'javascript' }, null, 2)], {type : 'application/json'});
async function readAsDataURL(blob) {
const str = await blob.text();
const dataURL = 'data:' + blob.type + ';base64,' + btoa(str);
return dataURL;
}
readAsDataURL(blob).then(dataurl => {
console.log(dataurl); // data:application/json;base64,ewogICJoZWxsbyI6ICJqYXZhc2NyaXB0Igp9
})
ArrayBuffer ==> DataURL
与上面通过Blob转为DataURL类似,也可以通过btoa来将ArrayBuffer转换为DataUrl
const arrBuf = await fetch('test.png').then(res => res.arrayBuffer()); // 假设数据 arrBuf 为 ArrayBuffer
function readAsDataURL(arraybuffer, type) {
let str = '';
new Uint8Array(arraybuffer).forEach(code => {
str += String.fromCodePoint(code);
});
return 'data:' + type + ';base64,' + btoa(str);
}
const dataURL = readAsDataURL(arrBuf, 'image/png');
Image ==> DataURL
如果你想转换的是图像,那么还有一种通过canvas间接转换的方法:
有一点需要注意的是,img需要显式地添加img.crossOrigin = 'Anonymous',否则当canvas执行toDataURL(), toBlob(), getImageData()时,由于跨域安全性问题,会抛出错误:
Uncaught DOMException: Failed to execute 'toDataURL' on 'HTMLCanvasElement': Tainted canvases may not be exported.
function imageToDataURL(imgurl) {
return new Promise((resolve, reject) => {
const canvas = document.createElement('canvas');
const img = new Image();
img.src = imgurl;
img.crossOrigin = 'Anonymous';
img.onload = function() {
canvas.width = img.naturalWidth * window.devicePixelRatio;
canvas.height = img.naturalHeight * window.devicePixelRatio;
const ctx = canvas.getContext('2d');
ctx.drawImage(img, 0, 0, canvas.width, canvas.height);
const dataURL = canvas.toDataURL();
resolve(dataURL);
}
img.onerror = reject;
});
}
const dataURL = await imageToDataURL('http://test.com/image.png');
转为Blob
DataURL ==> Blob
如果你的dataurl包含的是image数据,那么同样可以通过canvas进行中转
function dataURLToBlob(dataurl) {
return new Promise((resolve, reject) => {
const canvas = document.createElement('canvas');
const img = new Image();
img.src = dataurl;
img.crossOrigin = 'Anonymous';
img.onload = function() {
canvas.width = img.naturalWidth * window.devicePixelRatio;
canvas.height = img.naturalHeight * window.devicePixelRatio;
const ctx = canvas.getContext('2d');
ctx.drawImage(img, 0, 0, canvas.width, canvas.height);
canvas.toBlob(blob => resolve(blob));
}
img.onerror = reject;
});
}
const blob = dataURLToBlob('data:image/png;base64,xxxxxxx');
第二种方法是通过atob函数来转换
function dataURLToBlob(dataurl) {
const type = dataurl.match(/data:(.+);/)[1];
const base64 = dataurl.split(',')[1];
const binStr = atob(base64);
const u8a = new Uint8Array(binStr.length);
let p = binStr.length;
while (p) {
p--;
u8a[p] = binStr.codePointAt(p);
}
return new Blob([u8a], { type });
}
ArrayBuffer ==> Blob
Blob对象可以直接使用arrayBuffer构建
const blob = new Blob([arrayBuffer], { type: 'image/png' });
转为ArrayBuffer
DataURL ==> ArrayBuffer
只要对dataURL转blob的方法稍作修改
function dataURLToBlob(dataurl) {
const type = dataurl.match(/data:(.+);/)[1];
const base64 = dataurl.split(',')[1];
const binStr = atob(base64);
const u8a = new Uint8Array(binStr.length);
let p = binStr.length;
while (p) {
p--;
u8a[p] = binStr.codePointAt(p);
}
return u8a.buffer;
}
Blob ==> ArrayBuffer
blob对象有一个arrayBuffer()方法可以直接转换,需要注意,这个方法返回的是Promise对象,其resolve之后的值才是arrayBuffer
const blob = new Blob([1,2,3,4]);
const arrBuf = await blob.arrayBuffer();