Convert base64 string to ArrayBuffer

214,816

Solution 1

Try this:

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

Solution 2

Using TypedArray.from:

Uint8Array.from(atob(base64_string), c => c.charCodeAt(0))

Performance to be compared with the for loop version of Goran.it answer.

Solution 3

Goran.it's answer does not work because of unicode problem in javascript - https://developer.mozilla.org/en-US/docs/Web/API/WindowBase64/Base64_encoding_and_decoding.

I ended up using the function given on Daniel Guerrero's blog: http://blog.danguer.com/2011/10/24/base64-binary-decoding-in-javascript/

Function is listed on github link: https://github.com/danguer/blog-examples/blob/master/js/base64-binary.js

Use these lines

var uintArray = Base64Binary.decode(base64_string);  
var byteArray = Base64Binary.decodeArrayBuffer(base64_string); 

Solution 4

For Node.js users:

const myBuffer = Buffer.from(someBase64String, 'base64');

myBuffer will be of type Buffer which is a subclass of Uint8Array. Unfortunately, Uint8Array is NOT an ArrayBuffer as the OP was asking for. But when manipulating an ArrayBuffer I almost always wrap it with Uint8Array or something similar, so it should be close to what's being asked for.

Solution 5

Just found base64-arraybuffer, a small npm package with incredibly high usage, 5M downloads last month (2017-08).

https://www.npmjs.com/package/base64-arraybuffer

For anyone looking for something of a best standard solution, this may be it.

Share:
214,816

Related videos on Youtube

Tony
Author by

Tony

Updated on February 19, 2022

Comments

  • Tony
    Tony over 1 year

    I need to convert a base64 encode string into an ArrayBuffer. The base64 strings are user input, they will be copy and pasted from an email, so they're not there when the page is loaded. I would like to do this in javascript without making an ajax call to the server if possible.

    I found those links interesting, but they didt'n help me:

    ArrayBuffer to base64 encoded string

    this is about the opposite conversion, from ArrayBuffer to base64, not the other way round

    http://jsperf.com/json-vs-base64/2

    this looks good but i can't figure out how to use the code.

    Is there an easy (maybe native) way to do the conversion? thanks

  • Govinda Sakhare
    Govinda Sakhare almost 7 years
    Please explain me what is really happening here.
  • Goran.it
    Goran.it almost 7 years
    Well it's pretty straightforward, first we decode the base64 string (atob), then we create new array of 8-bit unsigned integers with the same length as the decoded string. After that we iterate the string and populate the array with Unicode value of each character in the string.
  • Govinda Sakhare
    Govinda Sakhare almost 7 years
    Why unsigned 8-bit? any specific reason?
  • Goran.it
    Goran.it almost 7 years
    From MDN : Base64 is a group of similar binary-to-text encoding schemes that represent binary data in an ASCII string format by translating it into a radix-64 representation. The Uint8Array typed array represents an array of 8-bit unsigned integers, and we are working with ASCII representation of the data (which is also an 8-bit table)..
  • IzumiSy
    IzumiSy over 6 years
    To who likes this kind of one liner, keep in mind that Uint8Array.from still has few compatibility with some browsers .
  • Kugel
    Kugel over 5 years
    Please do not recommend atob or btoa: developer.mozilla.org/en-US/docs/Web/API/WindowBase64/…
  • Avael Kross
    Avael Kross over 5 years
    rails compiler can't handle this string and fails with ExecJS::RuntimeError: SyntaxError: Unexpected token: operator (>); (rails 5)
  • ofavre
    ofavre over 5 years
    Get rid of the arrow function syntax by using this instead: Uint8Array.from(atob(base64_string), function(c) {return c.charCodeAt(0);}).
  • xiaoyu2er
    xiaoyu2er over 5 years
    This method is 2x faster than using atob.
  • oligofren
    oligofren over 5 years
    This isn't an array buffer. This is the typed array. You get access to the array buffer through the .buffer property of what is returned from Uint8Array
  • Tomáš Zato
    Tomáš Zato about 5 years
    This is not correct. It allows javascript to interpret bytes as string, that affects data which is actually true binary.
  • riv
    riv almost 5 years
    Can you give an example for which it wouldn't work? The article talks about encoding arbitrary strings, which might contain unicode characters, but does not apply to atob at all.
  • cs-NET over 4 years
    This was the perfect solution for me, simple and clean. I quickly tested it in Firefox, IE 11, Edge and worked fine!
  • mixture
    mixture over 4 years
    the problem is that a) not every byte sequence is valid unicode b) not every character in unicode is one byte so bytes[i] = binary_string.charCodeAt(i); can be wrong
  • ceztko
    ceztko over 4 years
    decodeArrayBuffer returns an ArrayBuffer that has size always divisible by 3, which I don't understand if it is by design or a bug. I will ask in the github project.
  • dubek
    dubek over 4 years
    Note that this doesn't perform any Base64 decoding/encoding. It just turns the 6 bytes of "base64" into a 6-element ArrayBuffer or Uint8Array.
  • multitask landscape over 4 years
    @dubek that's what have been asked.
  • Sergiu
    Sergiu about 4 years
    I'm not sure how it works for you in IE11, but I get an Access Denied error, which seems to be a CORS limitation.
  • Saites
    Saites over 3 years
    @Kugel, do you remember why you suggested to not use atob or btoa? The solutions given there seem to make use of those functions. In particular, Solution #3 on that page is essentially this solution + the final conversion to UTF-16.
  • AlwaysLearning
    AlwaysLearning over 3 years
    @ceztko It's probably by (accidental) design. The base64 encoding algorithm takes groups of 3 bytes and turns them into 4 characters. The decode method probably allocates an ArrayBuffer whose length is base64String.length/4*3 bytes and never truncates any unused bytes when finished.
  • ceztko
    ceztko over 3 years
    @AlwaysLearning which means it's probably bugged since leftover zero bytes may corrupt intended output content.
  • Berkyjay over 3 years
    @Saites, There's nothing wrong with atob or btoa, you just have to give them valid input. atob needs a valid base64 string, otherwise it will throw an error. And btoa needs a valid byte string (also called a binary string) which is a string containing characters in the range 0-255. If your string has characters outside that range, btoa will throw an error.
  • Gillsoft AB
    Gillsoft AB almost 3 years
    so no missing "."?
  • Gillsoft AB
    Gillsoft AB almost 3 years
    Test in a browser, I'm not sure this is the expected result? "Alice's Adventure in Wonderland�" (i.e. last character is NaN)
  • Kamil Kiełczewski
    Kamil Kiełczewski almost 3 years
    @GillsoftAB thank you for this info - you are right - I fix the problem
  • user202729
    user202729 over 2 years
    My benchmark shows that this is about 4 times slower than the for loop version. jsben.ch/p3Cbs
  • user202729
    user202729 over 2 years
    It appears that this method is the slowest according to my benchmark -- jsben.ch/aS6YU
  • Kamil Kiełczewski
    Kamil Kiełczewski over 2 years
    @TefoD Above code shows the input and output string length - and I test it for few cases - and input string length is always the same as output string length. So how to you detect trailing extra bx00 on output end? (provide example input and way of detection the problem)
  • TefoD
    TefoD over 2 years
    @KamilKiełczewski, sorry my bad - the trailing 0 zero were coming from a function before yours - I am going to delete my previous nonsense comment.
  • JKH about 2 years
    @ceztko yes! I saw the same thing. After using it in a download, my file was sometimes corrupted with extra characters. I fixed it with this in the decodeArrayBuffer function: if (input[input.length - 1] === "=") { bytes--; if (input[input.length - 2] === "=") { bytes--; } }
  • Marcel
    Marcel almost 2 years
    I used this with the Audio API, and it worked out of the box.
  • Xerix
    Xerix almost 2 years
    In my test for image base64, it returned length of 2947 (chars!!), when saved into byte array it became 4436 bytes, when the original image size is 3160 bytes!! - How come?? Very simple: Some of the "chars" produced by atob() became ABOVE 255 barrier, and as UTF-8 encoding suggests, it interpreted the binary data as UTF-8 string (or maybe UTF-16, I am not really sure).... Sorry, but the answer is NOT correct, or perhaps missing something....
  • Goran.it
    Goran.it almost 2 years
    Each Base64 digit represents exactly 6 bits of data. ... This means that the Base64 version of a string or file will be at most 133% the size of its source (a ~33% increase). The increase may be larger if the encoded data is small. In the same time, atob cannot produce chars above 255 barrier by design, you are free to look at the documentation. When you use atob / btoa, there is no UTF-8 interpretation as its name suggest its AsciiToBinnary and vice verca. (BTW. I wrongly stated that ASCII is a 8-bit table, its actually a 7 bit character set).
  • Florent B.
    Florent B. almost 2 years
    This answer is correct, I've tested all the possible values. The function window.atob decodes the input and then writes each decoded byte in an UTF-16 character which is 2 bytes. There's no loss possible since a byte only goes up to 255. Note that if the encoded content is UTF-8 text, you'll still have to decode it: new TextDecoder("utf-8").decode(_base64ToArrayBuffer("4oKs"));.
  • Jordan Mann
    Jordan Mann over 1 year
    This can be written more succinctly as await (await fetch("data:application/octet;base64," + base64data)).arrayBuffer() with async/await and the Fetch API.
  • gre_gor
    gre_gor about 1 year
    This doesn't work at all.
  • gre_gor
    gre_gor about 1 year
    It's clearly asking about Base64 decoding, not string encoding to binary.
  • multitask landscape about 1 year
    @gre_gor No, it is not asked about base64 decoding. User input is already in base64. And all is needed is ArrayBuffer representation of it. If you thought other way it is only your point of view and has nothing to do with answer. Convert means changing the type not a content. If you need decoding you then google for "js base64 decoding" and "js convert string to arraybuffer" for converting types.
  • gre_gor
    gre_gor about 1 year
    Based on other answers and downvotes on yours, I am clearly not the only one.
  • gre_gor
    gre_gor about 1 year
    Decoding base64 doesn't change the content. I am not sure if you even know what base64 encoding is.
  • Roy Shilkrot about 1 year
    Note that Buffer (nodejs.org/api/buffer.html) exists in Node.JS but not in the browser.
  • ShortFuse
    ShortFuse 11 months
    The problem with atob alone is that it will mangle unicode characters. For example atob('8J+ZiA==') returns 'ð\x9F\x99\x88' which you have to unmangle to get the proper '🙈' UTF8 string. But calling c.charCodeAt(0)` on every character is fine, and you can safely call new TextDecoder.decode(uint8array) and get the right UTF8 string.