我在字符串中有base64编码的二进制数据。
const contentType = 'image/png';
const b64Data = 'iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAYAAACNbyblAAAAHElEQVQI12P4//8/w38GIAXDIBKE0DHxgljNBAAO9TXL0Y4OHwAAAABJRU5ErkJggg==';
我想创建一个包含此数据的blob:
网址,并将其显示给用户。
const blob = new Blob(????, {type: contentType});
const blobUrl = URL.createObjectURL(blob);
window.location = blobUrl;
我无法弄清楚如何创建Blob
。
在某些情况下,我可以通过使用data:
网址来避免这种情况。
const dataUrl = `data:${contentType};base64,${b64Data}`;
window.location = dataUrl;
但是,在大多数情况下,data:
网址过大。
如何在JavaScript中将base64字符串解码为Blob
对象?
答案 0 :(得分:658)
atob
函数会将base64编码的字符串解码为一个新字符串,其中包含二进制数据每个字节的字符。
const byteCharacters = atob(b64Data);
每个字符的代码点(charCode)将是字节的值。我们可以使用.charCodeAt
方法为字符串中的每个字符应用它来创建一个字节值数组。
const byteNumbers = new Array(byteCharacters.length);
for (let i = 0; i < byteCharacters.length; i++) {
byteNumbers[i] = byteCharacters.charCodeAt(i);
}
您可以将此字节值数组转换为实际类型的字节数组,方法是将其传递给Uint8Array
构造函数。
const byteArray = new Uint8Array(byteNumbers);
通过将其包装在数组中并将其传递给Blob
构造函数,可以将其转换为Blob
。
const blob = new Blob([byteArray], {type: contentType});
上面的代码有效。但是,通过在较小的切片中处理byteCharacters
而不是一次性处理const b64toBlob = (b64Data, contentType='', sliceSize=512) => {
const byteCharacters = atob(b64Data);
const byteArrays = [];
for (let offset = 0; offset < byteCharacters.length; offset += sliceSize) {
const slice = byteCharacters.slice(offset, offset + sliceSize);
const byteNumbers = new Array(slice.length);
for (let i = 0; i < slice.length; i++) {
byteNumbers[i] = slice.charCodeAt(i);
}
const byteArray = new Uint8Array(byteNumbers);
byteArrays.push(byteArray);
}
const blob = new Blob(byteArrays, {type: contentType});
return blob;
}
,可以稍微提高性能。在我的粗略测试中,512字节似乎是一个很好的切片大小。这给了我们以下功能。
const blob = b64toBlob(b64Data, contentType);
const blobUrl = URL.createObjectURL(blob);
window.location = blobUrl;
const b64toBlob = (b64Data, contentType='', sliceSize=512) => {
const byteCharacters = atob(b64Data);
const byteArrays = [];
for (let offset = 0; offset < byteCharacters.length; offset += sliceSize) {
const slice = byteCharacters.slice(offset, offset + sliceSize);
const byteNumbers = new Array(slice.length);
for (let i = 0; i < slice.length; i++) {
byteNumbers[i] = slice.charCodeAt(i);
}
const byteArray = new Uint8Array(byteNumbers);
byteArrays.push(byteArray);
}
const blob = new Blob(byteArrays, {type: contentType});
return blob;
}
const contentType = 'image/png';
const b64Data = 'iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAYAAACNbyblAAAAHElEQVQI12P4//8/w38GIAXDIBKE0DHxgljNBAAO9TXL0Y4OHwAAAABJRU5ErkJggg==';
const blob = b64toBlob(b64Data, contentType);
const blobUrl = URL.createObjectURL(blob);
const img = document.createElement('img');
img.src = blobUrl;
document.body.appendChild(img);
{{1}}
答案 1 :(得分:167)
这是一个没有任何依赖关系或库的更小的方法 它需要新的fetch API。 (Can I use it?)
var url = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAYAAACNbyblAAAAHElEQVQI12P4//8/w38GIAXDIBKE0DHxgljNBAAO9TXL0Y4OHwAAAABJRU5ErkJggg=="
fetch(url)
.then(res => res.blob())
.then(blob => console.log(blob))
&#13;
使用此方法,您还可以轻松获取ArrayBuffer,text和JSON。
作为异步功能:
const b64toBlob = async (b64Data, contentType='application/octet-stream') => {
const url = `data:${contentType};base64,${b64Data}`;
const response = await fetch(url);
const blob = await response.blob();
return blob;
};
我对Jeremy的ES6同步版进行了简单的性能测试 同步版本将阻止UI一段时间。 保持devtool打开会降低获取性能
document.body.innerHTML += '<input autofocus placeholder="try writing">'
// get some dummy gradient image
var img=function(){var a=document.createElement("canvas"),b=a.getContext("2d"),c=b.createLinearGradient(0,0,1500,1500);a.width=a.height=3000;c.addColorStop(0,"red");c.addColorStop(1,"blue");b.fillStyle=c;b.fillRect(0,0,a.width,a.height);return a.toDataURL()}();
async function perf() {
const blob = await fetch(img).then(res => res.blob())
// turn it to a dataURI
const url = img
const b64Data = url.split(',')[1]
// Jeremy Banks solution
const b64toBlob = (b64Data, contentType = '', sliceSize=512) => {
const byteCharacters = atob(b64Data);
const byteArrays = [];
for (let offset = 0; offset < byteCharacters.length; offset += sliceSize) {
const slice = byteCharacters.slice(offset, offset + sliceSize);
const byteNumbers = new Array(slice.length);
for (let i = 0; i < slice.length; i++) {
byteNumbers[i] = slice.charCodeAt(i);
}
const byteArray = new Uint8Array(byteNumbers);
byteArrays.push(byteArray);
}
const blob = new Blob(byteArrays, {type: contentType});
return blob;
}
// bench blocking method
let i = 1000
console.time('b64')
while (i--) {
await b64toBlob(b64Data)
}
console.timeEnd('b64')
// bench non blocking
i = 1000
// so that the function is not reconstructed each time
const toBlob = res => res.blob()
console.time('fetch')
while (i--) {
await fetch(url).then(toBlob)
}
console.timeEnd('fetch')
console.log('done')
}
perf()
&#13;
答案 2 :(得分:59)
优化(但不太可读)的实施:
function base64toBlob(base64Data, contentType) {
contentType = contentType || '';
var sliceSize = 1024;
var byteCharacters = atob(base64Data);
var bytesLength = byteCharacters.length;
var slicesCount = Math.ceil(bytesLength / sliceSize);
var byteArrays = new Array(slicesCount);
for (var sliceIndex = 0; sliceIndex < slicesCount; ++sliceIndex) {
var begin = sliceIndex * sliceSize;
var end = Math.min(begin + sliceSize, bytesLength);
var bytes = new Array(end - begin);
for (var offset = begin, i = 0; offset < end; ++i, ++offset) {
bytes[i] = byteCharacters[offset].charCodeAt(0);
}
byteArrays[sliceIndex] = new Uint8Array(bytes);
}
return new Blob(byteArrays, { type: contentType });
}
答案 3 :(得分:18)
对于所有浏览器支持,特别是在android上。 也许你可以添加这个
try{
blob = new Blob( byteArrays, {type : contentType});
}
catch(e){
// TypeError old chrome and FF
window.BlobBuilder = window.BlobBuilder ||
window.WebKitBlobBuilder ||
window.MozBlobBuilder ||
window.MSBlobBuilder;
if(e.name == 'TypeError' && window.BlobBuilder){
var bb = new BlobBuilder();
bb.append(byteArrays);
blob = bb.getBlob(contentType);
}
else if(e.name == "InvalidStateError"){
// InvalidStateError (tested on FF13 WinXP)
blob = new Blob(byteArrays, {type : contentType});
}
else{
// We're screwed, blob constructor unsupported entirely
}
}
答案 4 :(得分:13)
对于图像数据,我发现使用canvas.toBlob
(异步)
function b64toBlob(b64, onsuccess, onerror) {
var img = new Image();
img.onerror = onerror;
img.onload = function onload() {
var canvas = document.createElement('canvas');
canvas.width = img.width;
canvas.height = img.height;
var ctx = canvas.getContext('2d');
ctx.drawImage(img, 0, 0, canvas.width, canvas.height);
canvas.toBlob(onsuccess);
};
img.src = b64;
}
var base64Data = 'data:image/jpg;base64,/9j/4AAQSkZJRgABAQA...';
b64toBlob(base64Data,
function(blob) {
var url = window.URL.createObjectURL(blob);
// do something with url
}, function(error) {
// handle error
});
答案 5 :(得分:12)
请参阅此示例:https://jsfiddle.net/pqhdce2L/
function b64toBlob(b64Data, contentType, sliceSize) {
contentType = contentType || '';
sliceSize = sliceSize || 512;
var byteCharacters = atob(b64Data);
var byteArrays = [];
for (var offset = 0; offset < byteCharacters.length; offset += sliceSize) {
var slice = byteCharacters.slice(offset, offset + sliceSize);
var byteNumbers = new Array(slice.length);
for (var i = 0; i < slice.length; i++) {
byteNumbers[i] = slice.charCodeAt(i);
}
var byteArray = new Uint8Array(byteNumbers);
byteArrays.push(byteArray);
}
var blob = new Blob(byteArrays, {type: contentType});
return blob;
}
var contentType = 'image/png';
var b64Data = Your Base64 encode;
var blob = b64toBlob(b64Data, contentType);
var blobUrl = URL.createObjectURL(blob);
var img = document.createElement('img');
img.src = blobUrl;
document.body.appendChild(img);
答案 6 :(得分:9)
我注意到,在切换像jeremy建议的数据时,Internet Explorer 11变得非常慢。这适用于Chrome,但在将切片数据传递给Blob-Constructor时IE似乎有问题。在我的机器上,传递5 MB的数据会导致IE崩溃和内存消耗。 Chrome会立即创建blob。
运行此代码以进行比较:
var byteArrays = [],
megaBytes = 2,
byteArray = new Uint8Array(megaBytes*1024*1024),
block,
blobSlowOnIE, blobFastOnIE,
i;
for (i = 0; i < (megaBytes*1024); i++) {
block = new Uint8Array(1024);
byteArrays.push(block);
}
//debugger;
console.profile("No Slices");
blobSlowOnIE = new Blob(byteArrays, { type: 'text/plain' });
console.profileEnd();
console.profile("Slices");
blobFastOnIE = new Blob([byteArray], { type: 'text/plain' });
console.profileEnd();
所以我决定在一个函数中包含jeremy描述的两种方法。为此,他可以获得积分。
function base64toBlob(base64Data, contentType, sliceSize) {
var byteCharacters,
byteArray,
byteNumbers,
blobData,
blob;
contentType = contentType || '';
byteCharacters = atob(base64Data);
// Get blob data sliced or not
blobData = sliceSize ? getBlobDataSliced() : getBlobDataAtOnce();
blob = new Blob(blobData, { type: contentType });
return blob;
/*
* Get blob data in one slice.
* => Fast in IE on new Blob(...)
*/
function getBlobDataAtOnce() {
byteNumbers = new Array(byteCharacters.length);
for (var i = 0; i < byteCharacters.length; i++) {
byteNumbers[i] = byteCharacters.charCodeAt(i);
}
byteArray = new Uint8Array(byteNumbers);
return [byteArray];
}
/*
* Get blob data in multiple slices.
* => Slow in IE on new Blob(...)
*/
function getBlobDataSliced() {
var slice,
byteArrays = [];
for (var offset = 0; offset < byteCharacters.length; offset += sliceSize) {
slice = byteCharacters.slice(offset, offset + sliceSize);
byteNumbers = new Array(slice.length);
for (var i = 0; i < slice.length; i++) {
byteNumbers[i] = slice.charCodeAt(i);
}
byteArray = new Uint8Array(byteNumbers);
// Add slice
byteArrays.push(byteArray);
}
return byteArrays;
}
}
答案 7 :(得分:6)
对于像我这样的所有复制粘贴爱好者,这里有一个可在Chrome,Firefox和Edge上使用的熟下载功能:
window.saveFile = function (bytesBase64, mimeType, fileName) {
var fileUrl = "data:" + mimeType + ";base64," + bytesBase64;
fetch(fileUrl)
.then(response => response.blob())
.then(blob => {
var link = window.document.createElement("a");
link.href = window.URL.createObjectURL(blob, { type: mimeType });
link.download = fileName;
document.body.appendChild(link);
link.click();
document.body.removeChild(link);
});
}
答案 8 :(得分:3)
如果您愿意在项目中添加一个依赖项,那么不错的blob-util
npm package提供了方便的base64StringToBlob
函数。一旦添加到您的package.json
中,您就可以像这样使用它:
import { base64StringToBlob } from 'blob-util';
const contentType = 'image/png';
const b64Data = 'iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAYAAACNbyblAAAAHElEQVQI12P4//8/w38GIAXDIBKE0DHxgljNBAAO9TXL0Y4OHwAAAABJRU5ErkJggg==';
const blob = base64StringToBlob(b64Data, contentType);
// Do whatever you need with your blob...
答案 9 :(得分:1)
我发布了更具声明性的同步base64转换方法。当异步fetch().blob()
非常整洁并且我非常喜欢此解决方案时,即使使用了polyfill,它也无法在IE11上运行(并且可能是Edge-尚未测试过此解决方案)-请看一下我对Endless的评论发布以获取更多详细信息。
const blobPdfFromBase64String = base64String => {
const byteArray = Uint8Array.from(
atob(base64String)
.split('')
.map(char => char.charCodeAt(0))
);
return new Blob([byteArray], { type: 'application/pdf' });
};
奖金
如果要打印,可以执行以下操作:
const isIE11 = !!(window.navigator && window.navigator.msSaveOrOpenBlob); // or however you want to check it
const printPDF = blob => {
try {
isIE11
? window.navigator.msSaveOrOpenBlob(blob, 'documents.pdf')
: printJS(URL.createObjectURL(blob)); // http://printjs.crabbly.com/
} catch (e) {
throw PDFError;
}
};
BONUSx2-在新标签中为IE11打开blob文件
如果您可以在服务器上对base64字符串进行一些预处理,则可以在某些url下公开它,并使用printJS
中的链接:)
答案 10 :(得分:0)
使用fetch的方法是最好的解决方案,但是如果任何人都需要不使用fetch的方法,那么这里就是这样,因为上述方法对我不起作用
function makeblob(dataURL) {
const BASE64_MARKER = ';base64,';
const parts = dataURL.split(BASE64_MARKER);
const contentType = parts[0].split(':')[1];
const raw = window.atob(parts[1]);
const rawLength = raw.length;
const uInt8Array = new Uint8Array(rawLength);
for (let i = 0; i < rawLength; ++i) {
uInt8Array[i] = raw.charCodeAt(i);
}
return new Blob([uInt8Array], { type: contentType });
}
答案 11 :(得分:0)
以下是我的Typescript代码,可以轻松将其转换为javascript,并且可以使用
/**
* CONVERT BASE64 TO BLOB
* @param Base64Image Pass base64 image data to convert into the blob
*/
private convertBase64ToBlob(Base64Image: any) {
// SPLIT INTO TWO PARTS
const parts = Base64Image.split(';base64,');
// HOLD THE CONTENT TYPE
const imageType = parts[0].split(':')[1];
// DECODE BASE64 STRING
const decodedData = window.atob(parts[1]);
// CREATE UNIT8ARRAY OF SIZE SAME AS ROW DATA LENGTH
const uInt8Array = new Uint8Array(decodedData.length);
// INSERT ALL CHARACTER CODE INTO UINT8ARRAY
for (let i = 0; i < decodedData.length; ++i) {
uInt8Array[i] = decodedData.charCodeAt(i);
}
// RETURN BLOB IMAGE AFTER CONVERSION
return new Blob([uInt8Array], { type: imageType });
}
答案 12 :(得分:0)
这将被证明是一个非常简短的解决方案。
const byteArray = new Buffer(base64String.replace(/^[\w\d;:\/]+base64\,/g, ''), 'base64');
<块引用>
base64String 是包含 base 64 字符串的字符串。
<块引用>byteArray 是你需要的数组。
<块引用>正则表达式替换是可选的,只是为了处理前缀,就像 dataurl 字符串一样。