1

Given a base64 string, what is the safest and most efficient way to create an ArrayBuffer. Specifically a typeless array buffer in pure modern JavaScript.

The first SO result is this question from 2014. The accepted answer is

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

It already assumes a type and there are comments which suggest that this is not always correct.

Is this still the best solution today? Do we have to iterate over all elements in a for loop? Is there a better and more efficient way using vanilla JS where we can pass a blob of the string?

An example problem is processing a GLTF buffer which is provided as a base64 encoded string:

let str = 'data:application/octet-stream;base64,AAABAAIAAAAAAAAAAAAAAAAAAAAAAIA/AAAAAAAAAAAAAAAAAACAPwAAAAA=';

This has two separate views of scalar (unsigned short) and vec3 (float) data, requiring further processing.

[edit]

So the most popular answer is not of use here as it creates a TypedArray but the data in the base64 string does not represent a homogenous data set.

dubious
  • 155
  • 2
  • 7
  • Your last line makes no sense at all. Is that left over from another post? Nowhere in your question is there anything about views, unsigned short, vec3 or float, and none of those things would seem to be Javascript concepts. – Tim Roberts Nov 13 '21 at 18:24
  • @TimRoberts The last line is to add context. The issue is that the most popular answer creates a `Uint8Array` and not a typeless `ArrayBuffer` on which further operations can be made. It's really to iterate that I don't want a `TypedArray` because that will lock you into a single view of the binary data. – dubious Nov 13 '21 at 18:31

1 Answers1

4

Since your str is a data:uri, you might use fetch:

let str = 'data:application/octet-stream;base64,AAABAAIAAAAAAAAAAAAAAAAAAAAAAIA/AAAAAAAAAAAAAAAAAACAPwAAAAA=';

fetch(str)
  .then(b => b.arrayBuffer())
  .then(buff => console.log( new Int8Array(buff) /* just for a view purpose */ ))
  .catch(e => console.log(e))
Kosh
  • 16,966
  • 2
  • 19
  • 34
  • Is the `.then(r => r.blob())` step necessary? Can we use `arrayBuffer()` immediately? – dubious Nov 13 '21 at 19:50
  • 1
    Fetch response seems to have an `arrayBuffer()` method for convenience. Is there a difference between these two? https://developer.mozilla.org/en-US/docs/Web/API/Response/arrayBuffer – dubious Nov 13 '21 at 19:56
  • 1
    @dubious, you're right! No need to `blob()` – Kosh Nov 13 '21 at 20:04