Skip to main content
Deno 2 is finally here 🎉️
Learn more

base64to

This library is not relevant anymore. In the past it outperformed embedded btoa() and atob() functions in Deno. Current Deno and Bun demonstrate higher results.

This library provides alternative functions to btoa() and atob().

Bonus features:

  • Custom characters for +, / and =.
  • Padding char (=) can be disabled in encoding, and it’s optional in decoding (any non-ABC char at the end will be ignored by the base64 decoder).
  • Convert string|Uint8Array -> string|Uint8Array.
  • Convert into existing Uint8Array buffer.
  • Convert Uint8Array inplace within the same memory block (for encoding there must be extra space at the end).
  • Convert Deno.Reader -> Deno.Reader.

The alternative functions to btoa() and atob()

btoa = encode64

atob = decode64ToString

encode64(data: string|Uint8Array, cPlus='+', cSlash='/', padding='='): string
decode64ToString(ascii: string|Uint8Array, cPlus='+', cSlash='/'): string
  • cPlus is the custom char for code 62 (default ‘+’).
  • cSlash is the custom char for code 63 (default ‘/’).
  • padding is the custom char for padding (default ‘=’). This can be empty string, to disable the padding.

Example:

import {encode64, decode64ToString} from 'https://deno.land/x/base64to@v1.0.1/mod.ts';

console.log(btoa('Data string'));     // prints: RGF0YSBzdHJpbmc=
console.log(encode64('Data string')); // prints: RGF0YSBzdHJpbmc=

console.log(atob('RGF0YSBzdHJpbmc='));             // prints: Data string
console.log(decode64ToString('RGF0YSBzdHJpbmc=')); // prints: Data string

console.log(encode64('Data string', '-', '_', '#')); // prints: RGF0YSBzdHJpbmc#
console.log(decode64ToString('RGF0YSBzdHJpbmc#####!!')); // prints: Data string

decode64ToString() ignores non-ABC characters at the end (treats them as padding chars).

Base64 encoding and decoding Uint8Array

encode64(data: string|Uint8Array, cPlus='+', cSlash='/', padding='='): string
decode64(ascii: string|Uint8Array, into?: Uint8Array, cPlus='+', cSlash='/'): Uint8Array

encode64ToBytes(data: string|Uint8Array, into?: Uint8Array, cPlus='+', cSlash='/', padding='='): Uint8Array
decode64ToString(ascii: string|Uint8Array, cPlus='+', cSlash='/'): string

The most common use is:

  • encode64(): Uint8Array -> string
  • decode64(): string -> back to Uint8Array

Basicly, these 4 functions allow to base64-encode and base64-decode string|Uint8Array <-> string|Uint8Array in all directions.

Functions that return Uint8Array by default create new Uint8Array buffers for the result. But they also can receive an existing buffer (through the argument called into), and if the provided object is big enough, it will be used for the result. In this case these functions return the into object. If into was not big enough for the result, a new object is created and returned.

It’s possible to pass the same object to both data (ascii) and into, or they can be subarrays of the same underlying buffer. In this case the base64 encoding/decoding will occure inplace, overwriting the original data.

Because decoding process produces shorter result (each 4 input bytes are converted to 3 output bytes), for decode64(ascii, into) the ascii and the into can be the same object.

import {decode64} from 'https://deno.land/x/base64to@v1.0.1/mod.ts';

let encoded = new TextEncoder().encode('RGF0YSBzdHJpbmc=');

// decode inplace
let decoded = decode64(encoded, encoded);

console.log(decoded.buffer == encoded.buffer); // prints: true
console.log(String.fromCharCode(...decoded));     // prints: Data string

For encode64ToBytes(data, into) you need to care, that the into object is at least Math.ceil(data.length * 4/3) + 2 long (there can be up to 2 padding characters) for inplace encoding.

import {encode64ToBytes} from 'https://deno.land/x/base64to@v1.0.1/mod.ts';

let data = new TextEncoder().encode('Data string');

let buffer = new Uint8Array(Math.ceil(data.length * 4 / 3) + 2);
buffer.set(data);

// now buffer[0 .. data.length] is the 'Data string' string, but there's enough extra space for encoding

// encode inplace
let encoded = encode64ToBytes(buffer.subarray(0, data.length), buffer);

console.log(encoded.buffer == buffer.buffer); // prints: true
console.log(String.fromCharCode(...encoded));     // prints: RGF0YSBzdHJpbmc=

Base64 encoding and decoding Deno.Reader streams

encode64Reader(reader: Deno.Reader, cPlus='+', cSlash='/', padding='='): Deno.Reader
decode64Reader(reader: Deno.Reader, cPlus='+', cSlash='/'): Deno.Reader

The following example base64-encodes your /etc/passwd file, and prints it to the Deno.stdout:

import {encode64Reader} from 'https://deno.land/x/base64to@v1.0.1/mod.ts';
import {copy} from 'https://deno.land/std@0.106.0/io/util.ts';

using fh = await Deno.open('/etc/passwd');
await copy(encode64Reader(fh), Deno.stdout);

The following example chains /etc/passwd -> encode64Reader -> decode64Reader -> Deno.stdout.

import {encode64Reader, decode64Reader} from 'https://deno.land/x/base64to@v1.0.1/mod.ts';
import {copy} from 'https://deno.land/std@0.106.0/io/util.ts';

using fh = await Deno.open('/etc/passwd');
await copy(decode64Reader(encode64Reader(fh)), Deno.stdout);