在JavaScript中从base64字符串创建Blob

本文翻译自:Creating a Blob from a base64 string in JavaScript

I have base64-encoded binary data in a string. 我在一个字符串中有base64编码的二进制数据。

const contentType = 'image/png';
const b64Data = 'iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAYAAACNbyblAAAAHElEQVQI12P4//8/w38GIAXDIBKE0DHxgljNBAAO9TXL0Y4OHwAAAABJRU5ErkJggg==';

I would like to create a blob: URL containing this data and display it to the user. 我想创建一个blob:包含此数据的URL并将其显示给用户。

const blob = new Blob(????, {type: contentType});
const blobUrl = URL.createObjectURL(blob);

window.location = blobUrl;

I haven't been been able to figure out how to create the Blob . 我一直无法弄清楚如何创建Blob

In some cases I am able to avoid this by using a data: URL instead. 在某些情况下,我可以使用data: URL来避免这种情况。

const dataUrl = `data:${contentType};base64,${b64Data}`;

window.location = dataUrl;

However in most cases the data: URLs are prohibitively large. 但是,在大多数情况下, data: URL太大了。


How can I decode a base64 string to a Blob object in JavaScript? 如何在JavaScript中将base64字符串解码为Blob对象?


#1楼

参考:https://stackoom.com/question/16AGV/在JavaScript中从base-字符串创建Blob


#2楼

The atob function will decode a base64-encoded string into a new string with a character for each byte of the binary data. atob函数会将base64编码的字符串解码为一个新的字符串,并为二进制数据的每个字节添加一个字符。

const byteCharacters = atob(b64Data);

Each character's code point (charCode) will be the value of the byte. 每个字符的代码点(charCode)将是字节的值。 We can create an array of byte values by applying this using the .charCodeAt method for each character in the string. 我们可以使用.charCodeAt方法为字符串中的每个字符应用字节值数组。

const byteNumbers = new Array(byteCharacters.length);
for (let i = 0; i < byteCharacters.length; i++) {
    byteNumbers[i] = byteCharacters.charCodeAt(i);
}

You can convert this array of byte values into a real typed byte array by passing it to the Uint8Array constructor. 您可以将该字节值数组传递给Uint8Array构造函数,以将其转换为实型字节数组。

const byteArray = new Uint8Array(byteNumbers);

This in turn can be converted to a Blob by wrapping it in an array and passing it to the Blob constructor. 这又可以被转换成一个Blob通过在阵列中包裹它,并将其传递到Blob构造。

const blob = new Blob([byteArray], {type: contentType});

The code above works. 上面的代码有效。 However the performance can be improved a little by processing the byteCharacters in smaller slices, rather than all at once. 但是,通过在较小的片中而不是一次全部处理byteCharacters可以稍微提高性能。 In my rough testing 512 bytes seems to be a good slice size. 在我的粗略测试中,512字节似乎是一个不错的切片大小。 This gives us the following function. 这为我们提供了以下功能。

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 blob = b64toBlob(b64Data, contentType);
const blobUrl = URL.createObjectURL(blob);

window.location = blobUrl;

Full Example: 完整示例:

 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); 


#3楼

Optimized (but less readable) implementation: 优化(但可读性较差)的实现:

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 });
}

#4楼

For image data, I find it simpler to use canvas.toBlob (asynchronous) 对于图像数据,我发现使用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楼

For all browser support, especially on android. 对于所有浏览器支持,尤其是在android上。 Perhaps you can add this 也许你可以添加这个

   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   
        }
    }

#6楼

I noticed, that Internet Explorer 11 gets incredibly slow when slicing the data like jeremy suggested. 我注意到,像jeremy建议的那样对数据进行切片时,Internet Explorer 11的速度变得异常慢。 This is true for Chrome, but IE seems to have a problem when passing the sliced data to the Blob-Constructor. 对于Chrome来说确实如此,但是将切片的数据传递给Blob构造函数时,IE似乎存在问题。 On my machine, passing 5 MB of data makes IE crash and memory consumption is going through the roof. 在我的机器上,传递5 MB的数据会使IE崩溃,并且内存消耗正在迅速增加。 Chrome creates the blob in no time. Chrome会立即创建Blob。

Run this code for a comparism: 运行以下代码进行比较:

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

So I decided to include both methods described by jeremy in one function. 因此,我决定将jeremy描述的两种方法都包含在一个函数中。 Credits go to him for this. 这归功于他。

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;
    }
}
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值