I need an efficient (read native) way to convert an ArrayBuffer
to a base64 string which needs to be used on a multipart post.
19 Answers
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
-
17I 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. – cshu Jun 28 '13 at 18:12
-
4I 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): http://jsperf.com/tobase64-implementations – JLRishe May 14 '14 at 09:30
-
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: http://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.` – bawejakunal Jul 11 '15 at 13:27
-
this is not worked this JSZip. i find another way https://github.com/michael/github/issues/137 – RouR Jul 23 '15 at 17:09
-
1I 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 Nov 14 '16 at 09:14
-
1This is not binary safe. Does anyone know about a binary safe option? – hg. Nov 27 '16 at 11:37
-
1Not safe. See @chemoish answer – Kugel Aug 24 '17 at 04:56
-
Unfortunately won't work in node.js. Because of node.js' Utf-8 string encoding `String.fromCharCode()` behave different for byte values >= 0x80. – Joe Oct 07 '17 at 17:49
-
@bawejakunal Seems to work find for me: https://jsfiddle.net/5cf7bpdu/ Open devtools console and you'll see it's working. – David Callanan Feb 19 '20 at 10:13
-
4I'm wondering why everyone is avoiding the native buffer `toString('base64')` method. – João Eduardo Feb 20 '20 at 13:56
-
16@JoãoEduardoSoareseSilva because not everyone is using Node - Node's `Buffer` doesn't exist in the browser. – Andrew Apr 05 '21 at 23:03
-
@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. – João Eduardo Apr 06 '21 at 04:49
-
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. – AMDI Feb 23 '22 at 00:35
-
Hello from 2022 in Firefox. So it seems like Alex and @cuixiping's solutions are the fastest and most preferred as of 2022? – Xunnamius May 26 '22 at 09:38
-
btoa converts array to string before converting it to base64 – Nikolay Makhonin Jun 08 '22 at 06:54
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.

- 42,323
- 22
- 125
- 158
-
60I like this method better for conciseness, but get a "maximum call stack size exceeded error". The loop technique above gets around that. – Jason Sep 07 '12 at 12:26
-
15I'm also getting a stack size error, so I used mobz's answer and it worked great. – David Jones Sep 03 '13 at 01:34
-
26It 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)},''))` – laggingreflex Nov 12 '15 at 22:06
-
2I 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 Nov 14 '16 at 11:53
-
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))); – BelgoCanadian Mar 23 '17 at 15:48
-
@BelgoCanadian I don't see what's wrong with that expression. See [here](http://stackoverflow.com/questions/1207190/embedding-base64-images) for your question. If this doesn't help then you should ask a new question and provide some more information. – GOTO 0 Mar 23 '17 at 17:25
-
-
9@Kugel `btoa` is safe for characters in the code range 0-255, as this is here the case (Think about the 8 in `Uint8Array`). – GOTO 0 Aug 24 '17 at 06:59
-
1
-
2FWIW, on Chrome 104 using `...` is much slower than using `apply`. – JP Sugarbroad Aug 19 '22 at 06:40
-
a very good answer in many cases (small buffers like crypto keys, signatures...) – Supersharp May 11 '23 at 14:27
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), '')
);

- 1,375
- 10
- 7
-
10Not sure if that's really sexy. After all, you're creating `
` new strings. – Neonit Mar 28 '18 at 07:22 -
1How about `btoa(new Uint8Array(arraybuffer).reduce((data,byte)=>(data.push(String.fromCharCode(byte)),data),[]).join(''))`? – Roy Tinker Sep 12 '18 at 00:30
-
2Another alternative: `btoa(Array.from(new Uint8Array(arraybuffer)).map(b => String.fromCharCode(b)).join(''))`. – e741af0d41bc74bf854041f1fbdbf Sep 19 '20 at 07:00
-
1Failed to execute 'btoa' on 'Window': The string to be encoded contains characters outside of the Latin1 range – RouR Sep 24 '21 at 14:22
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"

- 24,167
- 8
- 82
- 93
-
Use `dataurl.split(',', 2)[1]`instead of `dataurl.substr(dataurl.indexOf(',')+1)`. – Carter Medlin Oct 31 '18 at 21:40
-
3This doesn't seem to be guaranteed to work. According to https://w3c.github.io/FileAPI/#issue-f80bda5b `readAsDataURL` could theoretically return a percent encoded dataURI (And it seems it is actually the case in [jsdom](https://github.com/jsdom/jsdom/issues/2269)) – T S Aug 22 '19 at 19:00
-
-
split is shorter. but dataurl may contains one or more commas(,), split is not safe. – cuixiping Aug 28 '19 at 09:55
This example uses the built-in FileReader readDataURL() to do the conversion to base64 encoding. Data URLs are structured data:[<mediatype>][;base64],<data>
, so we split that url at the comma and return only the base64 encoded characters.
const blob = new Blob([array]);
const reader = new FileReader();
reader.onload = (event) => {
const dataUrl = event.target.result;
const [_, base64] = dataUrl.split(',');
// do something with base64
};
reader.readAsDataURL(blob);
Or as a promisified utility:
async function encode(array) {
return new Promise((resolve) => {
const blob = new Blob([array]);
const reader = new FileReader();
reader.onload = (event) => {
const dataUrl = event.target.result;
const [_, base64] = dataUrl.split(',');
resolve(base64);
};
reader.readAsDataURL(blob);
});
}
const encoded = await encode(typedArray);

- 3,844
- 3
- 19
- 16

- 388
- 3
- 4
-
4
-
Similar [helpful MDN example](https://developer.mozilla.org/en-US/docs/Web/API/Blob#Extracting_data_from_a_Blob). – spenceryue Dec 16 '19 at 11:53
-
1this is by far the fastest approach - tens of times faster than the other ones in my limited testing – jitin Dec 28 '19 at 15:55
-
i wish i'd found this solution like 8 hours again. my day would not have been wasted ;( thank you – Kaiser Shahid Jan 20 '20 at 16:02
-
5I think you also need to remove the DataURL header (`data:*/*;base64,`) to obtain just the Base64 string. See [MDN docs](https://developer.mozilla.org/en-US/docs/Web/API/FileReader/readAsDataURL) – Larry K Feb 23 '21 at 11:17
-
How do you convert the base64 back to the array (after using this method to encode to base64) ? – Metric Rat Mar 06 '23 at 10:41
-
Ah, may have found the answer here: https://stackoverflow.com/a/54123275/2030549 – Metric Rat Mar 06 '23 at 10:48
The OP did not specify the Running Environment but if you are using Node.JS there is a very simple way to do such thing.
According 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.

- 7,761
- 16
- 33
- 49

- 738
- 7
- 21
-
-
5@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. – João Eduardo Mar 10 '20 at 17:50
-
I came to realize recently that the Question date precedes NodeJS itself, which is more reason that the Mods should add an addendum to the question, because these days most people are looking for a solution on nodeJS and get mislead by the popularity of the old answers. – João Eduardo Nov 24 '22 at 08:39
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;
}

- 1,126
- 1
- 18
- 32
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.
-
-
3Very 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 Aug 24 '17 at 04:53
-
14All 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. – Jamesernator Apr 29 '19 at 06:44
-
This is the correct answer when btoa or Buffer are not available (react-native) – cancerbero May 14 '21 at 18:42
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)));
}

- 323
- 2
- 2
-
2This is a confusing answer. That does not look look like valid JavaScript and is a Uint8Array an ArrayBuffer? – user1153660 Oct 20 '18 at 15:06
-
@user1153660 Add the `function` keyword and it should work in a modern browser. – Yeti Nov 16 '18 at 07:40
-
Awesome! btoa(String.fromCharCode(...a)); is shortest version I have seen so far to encode Uint8Array. – Nicolo Jun 27 '19 at 08:37
-
4This looks good but if the array is too huge it will throw maximum call stack size exceeded error. – Pawel Uchida-Psztyc Oct 16 '19 at 17:54
If you're okay with adding a library, base64-arraybuffer:
yarn add base64-arraybuffer
then:
encode(buffer)
- Encodes ArrayBuffer into base64 stringdecode(str)
- Decodes base64 string to ArrayBuffer

- 20,498
- 11
- 103
- 114
This worked for me:
Buffer.from(myArrayBuffer).toString("base64");

- 39
- 3
-
Is this specific to NodeJS, and does it perform a copy in the `from` method? – Maarten Bodewes Apr 14 '23 at 15:32
-
-
If I knew the answer I would not have asked, I'd have improved your answer instead :) – Maarten Bodewes Jul 05 '23 at 12:47
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.

- 21,572
- 15
- 83
- 95
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.

- 22,886
- 11
- 59
- 90
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")

- 254
- 1
- 12
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)

- 135
- 1
- 12
var uint8Array = new Uint8Array(BytesArray);
var base64Str = btoa(String.fromCharCode(...uint8Array));
Or,
var base64Str = btoa(uint8Array.reduce((x, y) => x + String.fromCharCode(y), ''));

- 2,072
- 22
- 11
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;}

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

- 6,136
- 3
- 34
- 25