public
Last active

Encode an ArrayBuffer as a base64 string

  • Download Gist
gistfile1.js
JavaScript
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55
// Converts an ArrayBuffer directly to base64, without any intermediate 'convert to string then
// use window.btoa' step. According to my tests, this appears to be a faster approach:
// http://jsperf.com/encoding-xhr-image-data/5
 
function base64ArrayBuffer(arrayBuffer) {
var base64 = ''
var encodings = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'
 
var bytes = new Uint8Array(arrayBuffer)
var byteLength = bytes.byteLength
var byteRemainder = byteLength % 3
var mainLength = byteLength - byteRemainder
 
var a, b, c, d
var chunk
 
// Main loop deals with bytes in chunks of 3
for (var i = 0; i < mainLength; i = i + 3) {
// Combine the three bytes into a single integer
chunk = (bytes[i] << 16) | (bytes[i + 1] << 8) | bytes[i + 2]
 
// Use bitmasks to extract 6-bit segments from the triplet
a = (chunk & 16515072) >> 18 // 16515072 = (2^6 - 1) << 18
b = (chunk & 258048) >> 12 // 258048 = (2^6 - 1) << 12
c = (chunk & 4032) >> 6 // 4032 = (2^6 - 1) << 6
d = chunk & 63 // 63 = 2^6 - 1
 
// Convert the raw binary segments to the appropriate ASCII encoding
base64 += encodings[a] + encodings[b] + encodings[c] + encodings[d]
}
 
// Deal with the remaining bytes and padding
if (byteRemainder == 1) {
chunk = bytes[mainLength]
 
a = (chunk & 252) >> 2 // 252 = (2^6 - 1) << 2
 
// Set the 4 least significant bits to zero
b = (chunk & 3) << 4 // 3 = 2^2 - 1
 
base64 += encodings[a] + encodings[b] + '=='
} else if (byteRemainder == 2) {
chunk = (bytes[mainLength] << 8) | bytes[mainLength + 1]
 
a = (chunk & 64512) >> 10 // 64512 = (2^6 - 1) << 10
b = (chunk & 1008) >> 4 // 1008 = (2^6 - 1) << 4
 
// Set the 2 least significant bits to zero
c = (chunk & 15) << 2 // 15 = 2^4 - 1
 
base64 += encodings[a] + encodings[b] + encodings[c] + '='
}
return base64
}

I kind of need the reverse. A base64 encoded utf8 string to an ArrayBuffer. How can I do that?

I guess you would need to write this function sort of in reverse. So iterate over each 4 characters, converting them to three bytes which you append to the ArrayBuffer, and then with special handling for the padding at the end. I don't have code for that though :)

As you just saved my life, I just wanted to say THANK YOU

And CryptoJS has a method to transform to a WordArray as well: CryptoJS.enc.Base64.parse

@joscha, the "reverse" (see comment https://gist.github.com/jonleighton/958841/#comment-733469) seems to be 3x slower than atob in my tests.

This is a pretty nifty method! Is there any chance you might add a license to it? I would really like to include it in a project of mine but am not allowed to do so without a proper license ;-)

It's amazing, I'm working on >10 000 000 arrays (audio files) and performance was serious bottleneck, thanks

This function is flaw. Everything turns out as "AAAAAAAAA" for small number like [0.000354254885, -0.521365849254, 0.002453687924].

Please sign in to comment on this gist.

Something went wrong with that request. Please try again.