首页
学习
活动
专区
工具
TVP
发布
社区首页 >问答首页 >在JavaScript中从Base64字符串创建BLOB

在JavaScript中从Base64字符串创建BLOB
EN

Stack Overflow用户
提问于 2013-04-27 05:51:20
回答 12查看 666.8K关注 0票数 569

我在字符串中有base64编码的二进制数据:

代码语言:javascript
复制
const contentType = 'image/png';
const b64Data = 'iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAYAAACNbyblAAAAHElEQVQI12P4//8/w38GIAXDIBKE0DHxgljNBAAO9TXL0Y4OHwAAAABJRU5ErkJggg==';

我想创建一个包含此数据的blob: URL,并将其显示给用户:

代码语言:javascript
复制
const blob = new Blob(????, {type: contentType});
const blobUrl = URL.createObjectURL(blob);

window.location = blobUrl;

我还不能想出如何创建斑点。

在某些情况下,我可以通过使用data: URL来避免这种情况:

代码语言:javascript
复制
const dataUrl = `data:${contentType};base64,${b64Data}`;

window.location = dataUrl;

但是,在大多数情况下,data: URL非常大。

如何在JavaScript中将Base64字符串解码为BLOB对象?

EN

回答 12

Stack Overflow用户

回答已采纳

发布于 2013-04-27 05:51:20

atob函数将base64编码的字符串解码为一个新字符串,其中二进制数据的每个字节都有一个字符。

代码语言:javascript
复制
const byteCharacters = atob(b64Data);

每个字符的代码点(charCode)将是字节的值。我们可以通过对字符串中的每个字符使用.charCodeAt方法来应用此方法来创建字节值数组。

代码语言:javascript
复制
const byteNumbers = new Array(byteCharacters.length);
for (let i = 0; i < byteCharacters.length; i++) {
    byteNumbers[i] = byteCharacters.charCodeAt(i);
}

通过将此字节值数组传递给Uint8Array构造函数,可以将其转换为实际类型的字节数组。

代码语言:javascript
复制
const byteArray = new Uint8Array(byteNumbers);

反过来,通过将其包装在数组中并将其传递给Blob构造函数,可以将其转换为BLOB。

代码语言:javascript
复制
const blob = new Blob([byteArray], {type: contentType});

上面的代码可以工作。但是,通过在较小的切片中处理byteCharacters,而不是一次处理全部,可以略微提高性能。在我的粗略测试中,512字节似乎是一个很好的切片大小。这为我们提供了以下函数。

代码语言:javascript
复制
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;
}
代码语言:javascript
复制
const blob = b64toBlob(b64Data, contentType);
const blobUrl = URL.createObjectURL(blob);

window.location = blobUrl;

完整示例:

代码语言:javascript
复制
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);

票数 954
EN

Stack Overflow用户

发布于 2016-03-24 00:04:07

这里是一个更小的方法,没有任何依赖或库。

它需要新的fetch API。(Can I use it?)

代码语言:javascript
复制
var url = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAYAAACNbyblAAAAHElEQVQI12P4//8/w38GIAXDIBKE0DHxgljNBAAO9TXL0Y4OHwAAAABJRU5ErkJggg=="

fetch(url)
.then(res => res.blob())
.then(console.log)

使用这种方法,您还可以轻松地获取ReadableStream、ArrayBuffer、文本和JSON。

(仅供参考,这也适用于节点中的node-fetch )

作为函数:

代码语言:javascript
复制
const b64toBlob = (base64, type = 'application/octet-stream') => 
  fetch(`data:${type};base64,${base64}`).then(res => res.blob())

我对Jeremy的ES6同步版本做了一个简单的性能测试。

同步版本将在一段时间内阻止UI。保持devtool打开可能会降低获取性能

代码语言:javascript
复制
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 = 500
  console.time('blocking b64')
  while (i--) {
    await b64toBlob(b64Data)
  }
  console.timeEnd('blocking b64')
  
  // bench non blocking
  i = 500

  // 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()

票数 440
EN

Stack Overflow用户

发布于 2013-11-23 02:23:14

优化(但可读性较差)的实现:

代码语言:javascript
复制
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 });
}
票数 96
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/16245767

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档