Skip to content

@jonleighton /gist:958841
Created

Embed URL

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Encode an ArrayBuffer as a base64 string
// 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
}
@tsenart

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

@jonleighton
Owner

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

@n1k0

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

@joscha

kinda late, but here is the reverse

@joscha

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

@tonikitoo

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

@sparrowprince

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

@lapsio

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

@ketting00

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

@gfranko

Thank you very much, works like a charm! Would you mind adding a license to this?

@hogetsuyoshi

Thank you for this useful script. Which license is this? GPL? BSD?

@andreagulino

You made my day.

@yamaneko1212

You are my hero!

@GeorgeGardiner

Boom, thanks.

@mrmaffen

Thanks a lot! Would be awesome if you could state under which license you published this.

@thomthom

+1 for a license statement.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Something went wrong with that request. Please try again.