简体   繁体   中英

ArrayBuffer to base64 encoded string

I need an efficient (read native) way to convert an ArrayBuffer to a base64 string which needs to be used on a multipart post.

function _arrayBufferToBase64( buffer ) {
    var binary = '';
    var bytes = new Uint8Array( buffer );
    var len = bytes.byteLength;
    for (var i = 0; i < len; i++) {
        binary += String.fromCharCode( bytes[ i ] );
    }
    return window.btoa( binary );
}

but, non-native implementations are faster eg https://gist.github.com/958841 see http://jsperf.com/encoding-xhr-image-data/6

Updated benchmarks: https://jsben.ch/wnaZC

This works fine for me:

var base64String = btoa(String.fromCharCode.apply(null, new Uint8Array(arrayBuffer)));

In ES6, the syntax is a little simpler:

const base64String = btoa(String.fromCharCode(...new Uint8Array(arrayBuffer)));

As pointed out in the comments, this method may result in a runtime error in some browsers when the ArrayBuffer is large. The exact size limit is implementation dependent in any case.

For those who like it short, here's an other one using Array.reduce which will not cause stack overflow:

var base64 = btoa(
  new Uint8Array(arrayBuffer)
    .reduce((data, byte) => data + String.fromCharCode(byte), '')
);

There is another asynchronous way use Blob and FileReader.

I didn't test the performance. But it is a different way of thinking.

function arrayBufferToBase64( buffer, callback ) {
    var blob = new Blob([buffer],{type:'application/octet-binary'});
    var reader = new FileReader();
    reader.onload = function(evt){
        var dataurl = evt.target.result;
        callback(dataurl.substr(dataurl.indexOf(',')+1));
    };
    reader.readAsDataURL(blob);
}

//example:
var buf = new Uint8Array([11,22,33]);
arrayBufferToBase64(buf, console.log.bind(console)); //"CxYh"
var blob = new Blob([arrayBuffer])

var reader = new FileReader();
reader.onload = function(event){
   var base64 =   event.target.result
};

reader.readAsDataURL(blob);

I used this and works for me.

function arrayBufferToBase64( buffer ) {
    var binary = '';
    var bytes = new Uint8Array( buffer );
    var len = bytes.byteLength;
    for (var i = 0; i < len; i++) {
        binary += String.fromCharCode( bytes[ i ] );
    }
    return window.btoa( binary );
}



function base64ToArrayBuffer(base64) {
    var binary_string =  window.atob(base64);
    var len = binary_string.length;
    var bytes = new Uint8Array( len );
    for (var i = 0; i < len; i++)        {
        bytes[i] = binary_string.charCodeAt(i);
    }
    return bytes.buffer;
}

My recommendation for this is to NOT use native btoa strategies—as they don't correctly encode all ArrayBuffer 's…

rewrite the DOMs atob() and btoa()

Since DOMStrings are 16-bit-encoded strings, in most browsers calling window.btoa on a Unicode string will cause a Character Out Of Range exception if a character exceeds the range of a 8-bit ASCII-encoded character.

While I have never encountered this exact error, I have found that many of the ArrayBuffer 's I have tried to encode have encoded incorrectly.

I would either use MDN recommendation or gist.

Below are 2 simple functions for converting Uint8Array to Base64 String and back again

arrayToBase64String(a) {
    return btoa(String.fromCharCode(...a));
}

base64StringToArray(s) {
    let asciiString = atob(s);
    return new Uint8Array([...asciiString].map(char => char.charCodeAt(0)));
}

The OP did not specify the Running Enviroment but if you are using Node.JS there is a very simple way to do such thing.

Accordig with the official Node.JS docs https://nodejs.org/api/buffer.html#buffer_buffers_and_character_encodings

// This step is only necessary if you don't already have a Buffer Object
const buffer = Buffer.from(yourArrayBuffer);

const base64String = buffer.toString('base64');

Also, If you are running under Angular for example, the Buffer Class will also be made available in a Browser Environment.

If you're okay with adding a library, base64-arraybuffer :

yarn add base64-arraybuffer

then:

  • encode(buffer) - Encodes ArrayBuffer into base64 string
  • decode(str) - Decodes base64 string to ArrayBuffer

You can derive a normal array from the ArrayBuffer by using Array.prototype.slice . Use a function like Array.prototype.map to convert bytes in to characters and join them together to forma string.

function arrayBufferToBase64(ab){

    var dView = new Uint8Array(ab);   //Get a byte view        

    var arr = Array.prototype.slice.call(dView); //Create a normal array        

    var arr1 = arr.map(function(item){        
      return String.fromCharCode(item);    //Convert
    });

    return window.btoa(arr1.join(''));   //Form a string

}

This method is faster since there are no string concatenations running in it.

ABtoB64(ab) {
    return new Promise(res => {
        const fr = new FileReader();
        fr.onload = ({target: {result: s}}) => res(s.slice(s.indexOf(';base64,') + 8));
        fr.readAsDataURL(new Blob([ab]));
    });
}

asynchronous method using file reader.

In the Browser suggested solutions with btoa seem fine. But in Node.js btoa is deprecated

It is recommended to use buffer.toString(encoding)

like

const myString = buffer.toString("base64")

i use TextDecode api to convert it to normal text and then convert it to Base64

const uint =  new Uint8Array([ 73, 32, 108, 111, 118, 101, 32, 121, 111, 117 ]).buffer
const decoder = new TextDecoder()
const decodedText = decoder.decode(uint)
const base64Code = btoa(decodedText)

This worked for me:

Buffer.from(myArrayBuffer).toString("base64");

使用uint8-to-b64包在浏览器和 Node.js 中进行编码/解码

By my side, using Chrome navigator, I had to use DataView() to read an arrayBuffer

function _arrayBufferToBase64( tabU8A ) {
var binary = '';
let lecteur_de_donnees = new DataView(tabU8A);
var len = lecteur_de_donnees.byteLength;
var chaine = '';
var pos1;
for (var i = 0; i < len; i++) {
    binary += String.fromCharCode( lecteur_de_donnees.getUint8( i ) );
}
chaine = window.btoa( binary )
return chaine;}
function _arrayBufferToBase64(uarr) {
    var strings = [], chunksize = 0xffff;
    var len = uarr.length;

    for (var i = 0; i * chunksize < len; i++){
        strings.push(String.fromCharCode.apply(null, uarr.subarray(i * chunksize, (i + 1) * chunksize)));
    }

    return strings.join("");
}

This is better, if you use JSZip for unpack archive from string

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM