ArrayBuffer to base64 encoded string

305,077

Solution 1

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 e.g. https://gist.github.com/958841 see http://jsperf.com/encoding-xhr-image-data/6

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

Solution 2

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.

Solution 3

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

Solution 4

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"

Solution 5

var blob = new Blob([arrayBuffer])

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

reader.readAsDataURL(blob);
Share:
305,077

Related videos on Youtube

zaheer
Author by

zaheer

Updated on May 07, 2022

Comments

  • zaheer
    zaheer about 2 years

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

  • Jason
    Jason over 11 years
    I like this method better for conciseness, but get a "maximum call stack size exceeded error". The loop technique above gets around that.
  • cshu
    cshu almost 11 years
    I tried the non-native implementation from the link and it took 1min and half to convert a 1M size buffer while the loop code above only took 1sec.
  • David Jones
    David Jones over 10 years
    I'm also getting a stack size error, so I used mobz's answer and it worked great.
  • JLRishe
    JLRishe about 10 years
    I like the simplicity of this approach, but all that string concatenation can be costly. It looks like building an array of the characters and join()ing them at the end is significantly faster on Firefox, IE, and Safari (but quite a lot slower on Chrome): jsperf.com/tobase64-implementations
  • bawejakunal
    bawejakunal almost 9 years
    I am using this function for array buffer to base64 conversion but I am not able to get back the array buffer. I have wrriten a _base64ToArrayBuffer() function here: codeshare.io/PT4pb but that gives me an error as: Failed to execute 'atob' on 'Window': The string to be decoded is not correctly encoded.
  • RouR
    RouR almost 9 years
    this is not worked this JSZip. i find another way github.com/michael/github/issues/137
  • laggingreflex
    laggingreflex over 8 years
    It didn't work for large buffers. Slight modification to make it work: btoa([].reduce.call(new Uint8Array(bufferArray),function(p,c){return p+String.fromCharCode(c)},''))
  • prabhakaran S
    prabhakaran S over 7 years
    I am trying 50mb pdf file upload using angualrjs and webapi2. I am using above line code , after upload file, the page got crashed and hanged . Below line of code ,I was used but getting null value in webapi method. "var base64String = btoa(String.fromCharCode.apply(null, new Uint8Array(arrayBuffer)));" please suggest any idea ...
  • prabhakaran S
    prabhakaran S over 7 years
    I am trying 50mb pdf file upload using angualrjs and webapi2. I am using above line code , after upload file, the page got crashed and hanged . Below line of code ,I was used but getting null value in webapi method. "var base64String = btoa(String.fromCharCode.apply(null, new Uint8Array(arrayBuffer)));" please suggest any idea ...
  • hg.
    hg. over 7 years
    This is not binary safe. Does anyone know about a binary safe option?
  • BelgoCanadian
    BelgoCanadian about 7 years
    could you add the ultimate markup/image string to your answer as well by any chance? I have BMP images stored in SQL that I'm trying to display but this code isn't working: 'data:image/bmp;base64,' + btoa(String.fromCharCode.apply(null, new Uint8Array(arrayBuffer)));
  • GOTO 0
    GOTO 0 about 7 years
    @BelgoCanadian I don't see what's wrong with that expression. See here for your question. If this doesn't help then you should ask a new question and provide some more information.
  • tsh
    tsh almost 7 years
    btoa not works on String, but OP is asking ArrayBuffer.
  • Kugel
    Kugel over 6 years
    Very much this, so many snippets here that recommend the wrong thing! I've seen this error multiple times, where people blindly use atob and btoa.
  • Kugel
    Kugel over 6 years
    Not safe. See @chemoish answer
  • Kugel
    Kugel over 6 years
    Not safe. See @chemoish answer
  • Kugel
    Kugel over 6 years
    Not safe. See @chemoish answer
  • Kugel
    Kugel over 6 years
    Not safe. See @chemoish answer
  • GOTO 0
    GOTO 0 over 6 years
    @Kugel btoa is safe for characters in the code range 0-255, as this is here the case (Think about the 8 in Uint8Array).
  • Joe
    Joe over 6 years
    Unfortunately won't work in node.js. Because of node.js' Utf-8 string encoding String.fromCharCode() behave different for byte values >= 0x80.
  • Neonit
    Neonit about 6 years
    Not sure if that's really sexy. After all, you're creating <amount of Bytes in the buffer> new strings.
  • Roy Tinker
    Roy Tinker over 5 years
    How about btoa(new Uint8Array(arraybuffer).reduce((data,byte)=>(data.push(Strin‌​g.fromCharCode(byte)‌​),data),[]).join('')‌​)?
  • user1153660
    user1153660 over 5 years
    This is a confusing answer. That does not look look like valid JavaScript and is a Uint8Array an ArrayBuffer?
  • Carter Medlin
    Carter Medlin over 5 years
    Use dataurl.split(',', 2)[1]instead of dataurl.substr(dataurl.indexOf(',')+1).
  • Yeti
    Yeti over 5 years
    @user1153660 Add the function keyword and it should work in a modern browser.
  • Jamesernator
    Jamesernator about 5 years
    All array buffers should be encoded fine using the strategies in other answers, atob/btoa is only a problem for text that contains characters greater than 0xFF (which byte arrays by definition do not). The MDN warning doesn't apply because when using the strategy in the other answers you are guaranteed to have a string that only consists of ASCII characters as any value from a Uint8Array is guaranteed to be between 0 and 255 which means String.fromCharCode is guaranteed to return a character that is not out of range.
  • Nicolo
    Nicolo almost 5 years
    Awesome! btoa(String.fromCharCode(...a)); is shortest version I have seen so far to encode Uint8Array.
  • T S
    T S over 4 years
    This doesn't seem to be guaranteed to work. According to w3c.github.io/FileAPI/#issue-f80bda5b readAsDataURL could theoretically return a percent encoded dataURI (And it seems it is actually the case in jsdom)
  • T S
    T S over 4 years
    @CarterMedlin Why would split be better than substring?
  • cuixiping
    cuixiping over 4 years
    split is shorter. but dataurl may contains one or more commas(,), split is not safe.
  • Oscar
    Oscar over 4 years
    Add some explanation to your answer please. What does this code mean?
  • Pawel Psztyc
    Pawel Psztyc over 4 years
    This looks good but if the array is too huge it will throw maximum call stack size exceeded error.
  • spenceryue
    spenceryue over 4 years
  • jitin
    jitin over 4 years
    this is by far the fastest approach - tens of times faster than the other ones in my limited testing
  • Kaiser Shahid
    Kaiser Shahid over 4 years
    i wish i'd found this solution like 8 hours again. my day would not have been wasted ;( thank you
  • David Callanan
    David Callanan about 4 years
    @bawejakunal Seems to work find for me: jsfiddle.net/5cf7bpdu Open devtools console and you'll see it's working.
  • João Eduardo
    João Eduardo about 4 years
    I'm wondering why everyone is avoiding the native buffer toString('base64') method.
  • jvatic
    jvatic about 4 years
    Your answer only applies to NodeJS and will not work in the browser.
  • João Eduardo
    João Eduardo about 4 years
    @jvatic I see, the OP did not clearly specify the Running Environment, so my answer is not incorrect, he only tagged Javascript. So I updated my answer to make it more concise. I think this is an important answer because I was searching how to do this and could not get to the best answer to the problem.
  • e741af0d41bc74bf854041f1fbdbf
    e741af0d41bc74bf854041f1fbdbf over 3 years
    Another alternative: btoa(Array.from(new Uint8Array(arraybuffer)).map(b => String.fromCharCode(b)).join('')).
  • Ganesh umashankar
    Ganesh umashankar over 3 years
    how do you reverse this back to bytes array?
  • se22as
    se22as over 3 years
    This is the only solution i have found that worked for me.
  • Larry K
    Larry K about 3 years
    I think you also need to remove the DataURL header (data:*/*;base64,) to obtain just the Base64 string. See MDN docs
  • Andrew
    Andrew about 3 years
    @JoãoEduardoSoareseSilva because not everyone is using Node - Node's Buffer doesn't exist in the browser.
  • João Eduardo
    João Eduardo about 3 years
    @Andrew After I got better context to this question I learned that, I provided my own answer for Node users on this question, the issue is that this question is so popular that it overshadows the results for people that are using Node.
  • cancerbero
    cancerbero about 3 years
    This is the correct answer when btoa or Buffer are not available (react-native)
  • fjsj
    fjsj almost 3 years
    best answer for me since includes the decoding
  • RouR
    RouR over 2 years
    Failed to execute 'btoa' on 'Window': The string to be encoded contains characters outside of the Latin1 range
  • AMDI
    AMDI about 2 years
    I tried with "_arrayBufferToBase64" method and first time its uploading fine for 600MB and again i tried to upload 150MB file, browser is throwing "out of memory" page. Please let me now how can we avoid this or is there any limit to size or above method is storing in browser cache.
  • Xunnamius
    Xunnamius almost 2 years
    Hello from 2022 in Firefox. So it seems like Alex and @cuixiping's solutions are the fastest and most preferred as of 2022?
  • Nikolay Makhonin
    Nikolay Makhonin almost 2 years
    btoa converts array to string before converting it to base64