How to convert uint8 Array to base64 Encoded String?

I got a webSocket comunication, I recieve base64 encoded string, convert it to uint8 and work on it, but now I need to send back, I got the uint8 array, and need to convert it to base64 string, so I can send it. How can I make this convertion?

Asked By: Caio Keto
||

Answer #1:

All solutions already proposed have severe problems. Some solutions fail to work on large arrays, some provide wrong output, some throw an error on btoa call if an intermediate string contains multibyte characters, some consume more memory than needed.

So I implemented a direct conversion function which just works regardless of the input. It converts about 5 million bytes per second on my machine.

https://gist.github.com/enepomnyaschih/72c423f727d395eeaa09697058238727

Answered By: Egor Nepomnyaschih

Answer #2:

If your data may contain multi-byte sequences (not a plain ASCII sequence) and your browser has TextDecoder, then you should use that to decode your data (specify the required encoding for the TextDecoder):

var u8 = new Uint8Array([65, 66, 67, 68]);
var decoder = new TextDecoder('utf8');
var b64encoded = btoa(decoder.decode(u8));

If you need to support browsers that do not have TextDecoder (currently just IE and Edge), then the best option is to use a TextDecoder polyfill.

If your data contains plain ASCII (not multibyte Unicode/UTF-8) then there is a simple alternative using String.fromCharCode that should be fairly universally supported:

var ascii = new Uint8Array([65, 66, 67, 68]);
var b64encoded = btoa(String.fromCharCode.apply(null, ascii));

And to decode the base64 string back to a Uint8Array:

var u8_2 = new Uint8Array(atob(b64encoded).split("").map(function(c) {
    return c.charCodeAt(0); }));

If you have very large array buffers then the apply may fail and you may need to chunk the buffer (based on the one posted by @RohitSengar). Again, note that this is only correct if your buffer only contains non-multibyte ASCII characters:

function Uint8ToString(u8a){
  var CHUNK_SZ = 0x8000;
  var c = [];
  for (var i=0; i < u8a.length; i+=CHUNK_SZ) {
    c.push(String.fromCharCode.apply(null, u8a.subarray(i, i+CHUNK_SZ)));
  }
  return c.join("");
}
// Usage
var u8 = new Uint8Array([65, 66, 67, 68]);
var b64encoded = btoa(Uint8ToString(u8));
Answered By: kanaka

Answer #3:

Very simple solution and test for JavaScript!

ToBase64 = function (u8) {
    return btoa(String.fromCharCode.apply(null, u8));
}

FromBase64 = function (str) {
    return atob(str).split('').map(function (c) { return c.charCodeAt(0); });
}

var u8 = new Uint8Array(256);
for (var i = 0; i < 256; i++)
    u8[i] = i;

var b64 = ToBase64(u8);
console.debug(b64);
console.debug(FromBase64(b64));
Answered By: impactro

Answer #4:

If you are using Node.js then you can use this code to convert Uint8Array to base64

var b64 = Buffer.from(u8).toString('base64');
Answered By: Fiach Reid

Answer #5:

function Uint8ToBase64(u8Arr){
  var CHUNK_SIZE = 0x8000; //arbitrary number
  var index = 0;
  var length = u8Arr.length;
  var result = '';
  var slice;
  while (index < length) {
    slice = u8Arr.subarray(index, Math.min(index + CHUNK_SIZE, length)); 
    result += String.fromCharCode.apply(null, slice);
    index += CHUNK_SIZE;
  }
  return btoa(result);
}

You can use this function if you have a very large Uint8Array. This is for Javascript, can be useful in case of FileReader readAsArrayBuffer.

Answered By: Rohit Singh Sengar

Answer #6:

To base64-encode a UInt8Array with arbitrary data (not necessarily UTF-8) using native browser functionality:

const base64_arraybuffer = async (data) => {
    // Use a FileReader to generate a base64 data URI
    const base64url = await new Promise((r) => {
        const reader = new FileReader()
        reader.onload = () => r(reader.result)
        reader.readAsDataURL(new Blob([data]))
    })

    /*
    The result looks like 
    "data:application/octet-stream;base64,<your base64 data>", 
    so we split off the beginning:
    */
    return base64url.split(",", 2)[1]
}

// example use:
await base64_arraybuffer(new UInt8Array([1,2,3,100,200]))
Answered By: Fons

Answer #7:

Use the following to convert uint8 array to base64 encoded string

function arrayBufferToBase64(buffer) {
            var binary = '';
            var bytes = [].slice.call(new Uint8Array(buffer));
            bytes.forEach((b) => binary += String.fromCharCode(b));
            return window.btoa(binary);
        };
Answered By: KARTHIKEYAN.A

Answer #8:

Here is a JS Function to this:

This function is needed because Chrome doesn't accept a base64 encoded string as value for applicationServerKey in pushManager.subscribe yet https://bugs.chromium.org/p/chromium/issues/detail?id=802280

function urlBase64ToUint8Array(base64String) {
  var padding = '='.repeat((4 - base64String.length % 4) % 4);
  var base64 = (base64String + padding)
    .replace(/-/g, '+')
    .replace(/_/g, '/');

  var rawData = window.atob(base64);
  var outputArray = new Uint8Array(rawData.length);

  for (var i = 0; i < rawData.length; ++i) {
    outputArray[i] = rawData.charCodeAt(i);
  }
  return outputArray;
}
Answered By: lucss

Answer #9:

Pure JS - no string middlestep (no btoa)

In below solution I omit conversion to string. IDEA is following:

  • join 3 bytes (3 array elements) and you get 24-bits
  • split 24bits to four 6-bit numbers (which take values from 0 to 63)
  • use that numbers as index in base64 alphabet
  • corner case: when input byte array the length is not divided by 3 then add = or == to result

Solution below works on 3-bytes chunks so it is good for large arrays. Similar solution to convert base64 to binary array (without atob) is HERE

Answered By: Kamil Kiełczewski

Answer #10:

See here https://developer.mozilla.org/en-US/docs/Web/JavaScript/Base64_encoding_and_decoding#Appendix.3A_Decode_a_Base64_string_to_Uint8Array_or_ArrayBuffer

(Decode a Base64 string to Uint8Array or ArrayBuffer with Unicode support)

Answered By: pascow

Answer #11:

If all you want is a JS implementation of a base64-encoder, so that you can send data back, you can try the btoa function.

b64enc = btoa(uint);

A couple of quick notes on btoa - it's non-standard, so browsers aren't forced to support it. However, most browsers do. The big ones, at least. atob is the opposite conversion.

If you need a different implementation, or you find an edge-case where the browser has no idea what you're talking about, searching for a base64 encoder for JS wouldn't be too hard.

I think there are 3 of them hanging around on my company's website, for some reason...

Answered By: Norguard

Answer #12:

npm install google-closure-library --save

require("google-closure-library");
goog.require('goog.crypt.base64');

var result =goog.crypt.base64.encodeByteArray(Uint8Array.of(1,83,27,99,102,66));
console.log(result);

$node index.js would write AVMbY2Y= to the console.

Answered By: mancini0
The answers/resolutions are collected from stackoverflow, are licensed under cc by-sa 2.5 , cc by-sa 3.0 and cc by-sa 4.0 .



# More Articles