I have a PHP script that can encode a PNG image to a Base64 string.
I'd like to do the same thing using JavaScript. I know how to open files, but I'm not sure how to do the encoding. I'm not used to working with binary data.
You can use btoa()
and atob()
to convert to and from base64 encoding.
There appears to be some confusion in the comments regarding what these functions accept/return, so…
btoa() accepts a “string” where each character represents an 8-bit byte – if you pass a string containing characters that can’t be represented in 8 bits, it will probably break. This isn’t a problem if you’re actually treating the string as a byte array, but if you’re trying to do something else then you’ll have to encode it first.
atob() returns a “string” where each character represents an 8-bit byte – that is, its value will be between 0 and 0xff. This does not mean it’s ASCII – presumably if you’re using this function at all, you expect to be working with binary data and not text.
See also:
How do I load binary image data using Javascript and XMLHttpRequest?
Most comments here are outdated. You can probably use both btoa()
and atob()
, unless you support really outdated browsers.
Check here:
https://caniuse.com/?search=atob
https://caniuse.com/?search=btoa
/**
*
* Base64 encode / decode
* http://www.webtoolkit.info/
*
**/
var Base64 = {
// private property
_keyStr : "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=",
// public method for encoding
encode : function (input) {
var output = "";
var chr1, chr2, chr3, enc1, enc2, enc3, enc4;
var i = 0;
input = Base64._utf8_encode(input);
while (i < input.length) {
chr1 = input.charCodeAt(i++);
chr2 = input.charCodeAt(i++);
chr3 = input.charCodeAt(i++);
enc1 = chr1 >> 2;
enc2 = ((chr1 & 3) << 4) | (chr2 >> 4);
enc3 = ((chr2 & 15) << 2) | (chr3 >> 6);
enc4 = chr3 & 63;
if (isNaN(chr2)) {
enc3 = enc4 = 64;
} else if (isNaN(chr3)) {
enc4 = 64;
}
output = output +
this._keyStr.charAt(enc1) + this._keyStr.charAt(enc2) +
this._keyStr.charAt(enc3) + this._keyStr.charAt(enc4);
}
return output;
},
// public method for decoding
decode : function (input) {
var output = "";
var chr1, chr2, chr3;
var enc1, enc2, enc3, enc4;
var i = 0;
input = input.replace(/[^A-Za-z0-9\+\/\=]/g, "");
while (i < input.length) {
enc1 = this._keyStr.indexOf(input.charAt(i++));
enc2 = this._keyStr.indexOf(input.charAt(i++));
enc3 = this._keyStr.indexOf(input.charAt(i++));
enc4 = this._keyStr.indexOf(input.charAt(i++));
chr1 = (enc1 << 2) | (enc2 >> 4);
chr2 = ((enc2 & 15) << 4) | (enc3 >> 2);
chr3 = ((enc3 & 3) << 6) | enc4;
output = output + String.fromCharCode(chr1);
if (enc3 != 64) {
output = output + String.fromCharCode(chr2);
}
if (enc4 != 64) {
output = output + String.fromCharCode(chr3);
}
}
output = Base64._utf8_decode(output);
return output;
},
// private method for UTF-8 encoding
_utf8_encode : function (string) {
string = string.replace(/\r\n/g,"\n");
var utftext = "";
for (var n = 0; n < string.length; n++) {
var c = string.charCodeAt(n);
if (c < 128) {
utftext += String.fromCharCode(c);
}
else if((c > 127) && (c < 2048)) {
utftext += String.fromCharCode((c >> 6) | 192);
utftext += String.fromCharCode((c & 63) | 128);
}
else {
utftext += String.fromCharCode((c >> 12) | 224);
utftext += String.fromCharCode(((c >> 6) & 63) | 128);
utftext += String.fromCharCode((c & 63) | 128);
}
}
return utftext;
},
// private method for UTF-8 decoding
_utf8_decode : function (utftext) {
var string = "";
var i = 0;
var c = c1 = c2 = 0;
while ( i < utftext.length ) {
c = utftext.charCodeAt(i);
if (c < 128) {
string += String.fromCharCode(c);
i++;
}
else if((c > 191) && (c < 224)) {
c2 = utftext.charCodeAt(i+1);
string += String.fromCharCode(((c & 31) << 6) | (c2 & 63));
i += 2;
}
else {
c2 = utftext.charCodeAt(i+1);
c3 = utftext.charCodeAt(i+2);
string += String.fromCharCode(((c & 15) << 12) | ((c2 & 63) << 6) | (c3 & 63));
i += 3;
}
}
return string;
}
}
Also, search for "JavaScript base64 encoding" turns up a lot of other options, and the above was the first one.
string = string.replace(/\r\n/g,"\n");
statement in the utf8 encoding method.
string = string.replace(/\r\n/g,"\n");
in the first place, lol. It's like "oh, lets encode this string, but first, why don't we just randomly normalize all the line breaks for no good reason at all". That should absolutely be removed from the class under all circumstances.
Internet Explorer 10+
// Define the string
var string = 'Hello World!';
// Encode the String
var encodedString = btoa(string);
console.log(encodedString); // Outputs: "SGVsbG8gV29ybGQh"
// Decode the String
var decodedString = atob(encodedString);
console.log(decodedString); // Outputs: "Hello World!"
Cross-Browser
// Create Base64 Object
var Base64={_keyStr:"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=",encode:function(e){var t="";var n,r,i,s,o,u,a;var f=0;e=Base64._utf8_encode(e);while(f<e.length){n=e.charCodeAt(f++);r=e.charCodeAt(f++);i=e.charCodeAt(f++);s=n>>2;o=(n&3)<<4|r>>4;u=(r&15)<<2|i>>6;a=i&63;if(isNaN(r)){u=a=64}else if(isNaN(i)){a=64}t=t+this._keyStr.charAt(s)+this._keyStr.charAt(o)+this._keyStr.charAt(u)+this._keyStr.charAt(a)}return t},decode:function(e){var t="";var n,r,i;var s,o,u,a;var f=0;e=e.replace(/[^A-Za-z0-9\+\/\=]/g,"");while(f<e.length){s=this._keyStr.indexOf(e.charAt(f++));o=this._keyStr.indexOf(e.charAt(f++));u=this._keyStr.indexOf(e.charAt(f++));a=this._keyStr.indexOf(e.charAt(f++));n=s<<2|o>>4;r=(o&15)<<4|u>>2;i=(u&3)<<6|a;t=t+String.fromCharCode(n);if(u!=64){t=t+String.fromCharCode(r)}if(a!=64){t=t+String.fromCharCode(i)}}t=Base64._utf8_decode(t);return t},_utf8_encode:function(e){e=e.replace(/\r\n/g,"\n");var t="";for(var n=0;n<e.length;n++){var r=e.charCodeAt(n);if(r<128){t+=String.fromCharCode(r)}else if(r>127&&r<2048){t+=String.fromCharCode(r>>6|192);t+=String.fromCharCode(r&63|128)}else{t+=String.fromCharCode(r>>12|224);t+=String.fromCharCode(r>>6&63|128);t+=String.fromCharCode(r&63|128)}}return t},_utf8_decode:function(e){var t="";var n=0;var r=c1=c2=0;while(n<e.length){r=e.charCodeAt(n);if(r<128){t+=String.fromCharCode(r);n++}else if(r>191&&r<224){c2=e.charCodeAt(n+1);t+=String.fromCharCode((r&31)<<6|c2&63);n+=2}else{c2=e.charCodeAt(n+1);c3=e.charCodeAt(n+2);t+=String.fromCharCode((r&15)<<12|(c2&63)<<6|c3&63);n+=3}}return t}}
// Define the string
var string = 'Hello World!';
// Encode the String
var encodedString = Base64.encode(string);
console.log(encodedString); // Outputs: "SGVsbG8gV29ybGQh"
// Decode the String
var decodedString = Base64.decode(encodedString);
console.log(decodedString); // Outputs: "Hello World!"
With Node.js
Here is how you encode normal text to base64 in Node.js:
//Buffer() requires a number, array or string as the first parameter, and an optional encoding type as the second parameter.
// The default is "utf8". Possible encoding types are "ascii", "utf8", "ucs2", "base64", "binary", and "hex"
var b = Buffer.from('JavaScript');
// If we don't use toString(), JavaScript assumes we want to convert the object to utf8.
// We can make it convert to other formats by passing the encoding type to toString().
var s = b.toString('base64');
And here is how you decode base64 encoded strings:
var b = new Buffer('SmF2YVNjcmlwdA==', 'base64')
var s = b.toString();
With Dojo.js
To encode an array of bytes using dojox.encoding.base64:
var str = dojox.encoding.base64.encode(myByteArray);
To decode a Base64-encoded string:
var bytes = dojox.encoding.base64.decode(str)
Bower install angular-base64
<script src="bower_components/angular-base64/angular-base64.js"></script>
angular
.module('myApp', ['base64'])
.controller('myController', [
'$base64', '$scope',
function($base64, $scope) {
$scope.encoded = $base64.encode('a string');
$scope.decoded = $base64.decode('YSBzdHJpbmc=');
}]);
new Buffer()
is deprecated, use Buffer.from()
instead
Sunny's code is great except it breaks in Internet Explorer 7 because of references to "this". It was fixed by replacing such references with "Base64":
var Base64 = {
// private property
_keyStr : "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=",
// public method for encoding
encode : function (input) {
var output = "";
var chr1, chr2, chr3, enc1, enc2, enc3, enc4;
var i = 0;
input = Base64._utf8_encode(input);
while (i < input.length) {
chr1 = input.charCodeAt(i++);
chr2 = input.charCodeAt(i++);
chr3 = input.charCodeAt(i++);
enc1 = chr1 >> 2;
enc2 = ((chr1 & 3) << 4) | (chr2 >> 4);
enc3 = ((chr2 & 15) << 2) | (chr3 >> 6);
enc4 = chr3 & 63;
if (isNaN(chr2)) {
enc3 = enc4 = 64;
} else if (isNaN(chr3)) {
enc4 = 64;
}
output = output +
Base64._keyStr.charAt(enc1) + Base64._keyStr.charAt(enc2) +
Base64._keyStr.charAt(enc3) + Base64._keyStr.charAt(enc4);
}
return output;
},
// public method for decoding
decode : function (input) {
var output = "";
var chr1, chr2, chr3;
var enc1, enc2, enc3, enc4;
var i = 0;
input = input.replace(/[^A-Za-z0-9\+\/\=]/g, "");
while (i < input.length) {
enc1 = Base64._keyStr.indexOf(input.charAt(i++));
enc2 = Base64._keyStr.indexOf(input.charAt(i++));
enc3 = Base64._keyStr.indexOf(input.charAt(i++));
enc4 = Base64._keyStr.indexOf(input.charAt(i++));
chr1 = (enc1 << 2) | (enc2 >> 4);
chr2 = ((enc2 & 15) << 4) | (enc3 >> 2);
chr3 = ((enc3 & 3) << 6) | enc4;
output = output + String.fromCharCode(chr1);
if (enc3 != 64) {
output = output + String.fromCharCode(chr2);
}
if (enc4 != 64) {
output = output + String.fromCharCode(chr3);
}
}
output = Base64._utf8_decode(output);
return output;
},
// private method for UTF-8 encoding
_utf8_encode : function (string) {
string = string.replace(/\r\n/g,"\n");
var utftext = "";
for (var n = 0; n < string.length; n++) {
var c = string.charCodeAt(n);
if (c < 128) {
utftext += String.fromCharCode(c);
}
else if((c > 127) && (c < 2048)) {
utftext += String.fromCharCode((c >> 6) | 192);
utftext += String.fromCharCode((c & 63) | 128);
}
else {
utftext += String.fromCharCode((c >> 12) | 224);
utftext += String.fromCharCode(((c >> 6) & 63) | 128);
utftext += String.fromCharCode((c & 63) | 128);
}
}
return utftext;
},
// private method for UTF-8 decoding
_utf8_decode : function (utftext) {
var string = "";
var i = 0;
var c = c1 = c2 = 0;
while ( i < utftext.length ) {
c = utftext.charCodeAt(i);
if (c < 128) {
string += String.fromCharCode(c);
i++;
}
else if((c > 191) && (c < 224)) {
c2 = utftext.charCodeAt(i+1);
string += String.fromCharCode(((c & 31) << 6) | (c2 & 63));
i += 2;
}
else {
c2 = utftext.charCodeAt(i+1);
c3 = utftext.charCodeAt(i+2);
string += String.fromCharCode(((c & 15) << 12) | ((c2 & 63) << 6) | (c3 & 63));
i += 3;
}
}
return string;
}
}
You can use btoa
(to Base64) and atob
(from Base64).
For Internet Explorer 9 and below, try the jquery-base64 plugin:
$.base64.encode("this is a test");
$.base64.decode("dGhpcyBpcyBhIHRlc3Q=");
base64.encode(...)
and base64.decode(...)
...attaching it to jQuery when it has zero jQuery specific functionality makes absolutely no sense...
From the comments (by SET and Stefan Steiger) below the accepted answer, here is a quick summary of how to encode/decode a string to/from Base64 without need of a library.
str = "The quick brown fox jumps over the lazy dog";
b64 = btoa(unescape(encodeURIComponent(str)));
str = decodeURIComponent(escape(window.atob(b64)));
Pure JavaScript Demo
const input = document.getElementsByTagName('input')[0]; const btnConv = document.getElementById('btnConv'); const btnDeConv = document.getElementById('btnDeConv'); input.value = "The quick brown fox jumps over the lazy dog"; btnConv.addEventListener('click', () => { const txt = input.value; const b64 = btoa(unescape(encodeURIComponent(txt))); input.value = b64; btnDeConv.style.display = 'block'; btnConv.style.display = 'none'; }); btnDeConv.addEventListener('click', () => { var b64 = input.value; var txt = decodeURIComponent(escape(window.atob(b64))); input.value = txt; btnConv.style.display = 'block'; btnDeConv.style.display = 'none'; }); input{width:500px;} #btnDeConv{display:none;}
.
jQuery Demo (uses the jQuery library for display, but not for encode/decode)
str = "The quick brown fox jumps over the lazy dog"; $('input').val(str); $('#btnConv').click(function(){ var txt = $('input').val(); var b64 = btoa(unescape(encodeURIComponent(txt))); $('input').val(b64); $('#btnDeConv').show(); }); $('#btnDeConv').click(function(){ var b64 = $('input').val(); var txt = decodeURIComponent(escape(window.atob(b64))); $('input').val(txt); }); #btnDeConv{display:none;}
Buffer.from(b64data, 'base64').toString();
unescape
and escape
are doing in this solution snipped?
There are a couple of bugs in both implementations of _utf8_decode
. c1
and c2
are assigned as global variables due to broken use of the var
statement, and c3
is not initialized or declared at all.
It works, but these variables will overwrite any existing ones with the same name outside this function.
Here's a version that won't do this:
// private method for UTF-8 decoding
_utf8_decode : function (utftext) {
var string = "";
var i = 0;
var c = 0, c1 = 0, c2 = 0;
while ( i < utftext.length ) {
c = utftext.charCodeAt(i);
if (c < 128) {
string += String.fromCharCode(c);
i++;
}
else if((c > 191) && (c < 224)) {
c1 = utftext.charCodeAt(i+1);
string += String.fromCharCode(((c & 31) << 6) | (c1 & 63));
i += 2;
}
else {
c1 = utftext.charCodeAt(i+1);
c2 = utftext.charCodeAt(i+2);
string += String.fromCharCode(((c & 15) << 12) | ((c1 & 63) << 6) | (c2 & 63));
i += 3;
}
}
return string;
}
This question and its answers pointed me in the right direction. Especially with Unicode, atob and btoa can not be used "vanilla" and these days everything is Unicode...
Directly from Mozilla, two nice functions for this purpose. Tested with Unicode and HTML tags inside:
function b64EncodeUnicode(str) {
return btoa(encodeURIComponent(str).replace(/%([0-9A-F]{2})/g, function(match, p1) {
return String.fromCharCode('0x' + p1);
}));
}
b64EncodeUnicode('✓ à la mode'); // "4pyTIMOgIGxhIG1vZGU="
b64EncodeUnicode('\n'); // "Cg=="
function b64DecodeUnicode(str) {
return decodeURIComponent(Array.prototype.map.call(atob(str), function(c) {
return '%' + ('00' + c.charCodeAt(0).toString(16)).slice(-2);
}).join(''));
}
b64DecodeUnicode('4pyTIMOgIGxhIG1vZGU='); // "✓ à la mode"
b64DecodeUnicode('Cg=='); // "\n"
These functions will perform lightning fast in comparison to raw Base64 decoding using a custom JavaScript function as btoa and atob are executed outside the interpreter.
If you can ignore old Internet Explorer and old mobile phones (like iPhone 3?) this should be a good solution.
For newer browsers to encode Uint8Array to string, and decode string to Uint8Array.
const base64 = {
decode: s => Uint8Array.from(atob(s), c => c.charCodeAt(0)),
encode: b => btoa(String.fromCharCode(...new Uint8Array(b)))
};
For Node.js you can use the following to encode string, Buffer, or Uint8Array to string, and decode from string, Buffer, or Uint8Array to Buffer.
const base64 = {
decode: s => Buffer.from(s, 'base64'),
encode: b => Buffer.from(b).toString('base64')
};
If you use Node.js, you can do this:
let a = Buffer.from('JavaScript').toString('base64');
console.log(a);
let b = Buffer.from(a, 'base64').toString();
console.log(b);
Basically I've just cleaned up the original code a little so JSLint doesn't complain quite as much, and I made the methods marked as private in the comments actually private. I also added two methods I needed in my own project, namely decodeToHex
and encodeFromHex
.
The code:
var Base64 = (function() {
"use strict";
var _keyStr = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";
var _utf8_encode = function (string) {
var utftext = "", c, n;
string = string.replace(/\r\n/g,"\n");
for (n = 0; n < string.length; n++) {
c = string.charCodeAt(n);
if (c < 128) {
utftext += String.fromCharCode(c);
} else if((c > 127) && (c < 2048)) {
utftext += String.fromCharCode((c >> 6) | 192);
utftext += String.fromCharCode((c & 63) | 128);
} else {
utftext += String.fromCharCode((c >> 12) | 224);
utftext += String.fromCharCode(((c >> 6) & 63) | 128);
utftext += String.fromCharCode((c & 63) | 128);
}
}
return utftext;
};
var _utf8_decode = function (utftext) {
var string = "", i = 0, c = 0, c1 = 0, c2 = 0;
while ( i < utftext.length ) {
c = utftext.charCodeAt(i);
if (c < 128) {
string += String.fromCharCode(c);
i++;
} else if((c > 191) && (c < 224)) {
c1 = utftext.charCodeAt(i+1);
string += String.fromCharCode(((c & 31) << 6) | (c1 & 63));
i += 2;
} else {
c1 = utftext.charCodeAt(i+1);
c2 = utftext.charCodeAt(i+2);
string += String.fromCharCode(((c & 15) << 12) | ((c1 & 63) << 6) | (c2 & 63));
i += 3;
}
}
return string;
};
var _hexEncode = function(input) {
var output = '', i;
for(i = 0; i < input.length; i++) {
output += input.charCodeAt(i).toString(16);
}
return output;
};
var _hexDecode = function(input) {
var output = '', i;
if(input.length % 2 > 0) {
input = '0' + input;
}
for(i = 0; i < input.length; i = i + 2) {
output += String.fromCharCode(parseInt(input.charAt(i) + input.charAt(i + 1), 16));
}
return output;
};
var encode = function (input) {
var output = "", chr1, chr2, chr3, enc1, enc2, enc3, enc4, i = 0;
input = _utf8_encode(input);
while (i < input.length) {
chr1 = input.charCodeAt(i++);
chr2 = input.charCodeAt(i++);
chr3 = input.charCodeAt(i++);
enc1 = chr1 >> 2;
enc2 = ((chr1 & 3) << 4) | (chr2 >> 4);
enc3 = ((chr2 & 15) << 2) | (chr3 >> 6);
enc4 = chr3 & 63;
if (isNaN(chr2)) {
enc3 = enc4 = 64;
} else if (isNaN(chr3)) {
enc4 = 64;
}
output += _keyStr.charAt(enc1);
output += _keyStr.charAt(enc2);
output += _keyStr.charAt(enc3);
output += _keyStr.charAt(enc4);
}
return output;
};
var decode = function (input) {
var output = "", chr1, chr2, chr3, enc1, enc2, enc3, enc4, i = 0;
input = input.replace(/[^A-Za-z0-9\+\/\=]/g, "");
while (i < input.length) {
enc1 = _keyStr.indexOf(input.charAt(i++));
enc2 = _keyStr.indexOf(input.charAt(i++));
enc3 = _keyStr.indexOf(input.charAt(i++));
enc4 = _keyStr.indexOf(input.charAt(i++));
chr1 = (enc1 << 2) | (enc2 >> 4);
chr2 = ((enc2 & 15) << 4) | (enc3 >> 2);
chr3 = ((enc3 & 3) << 6) | enc4;
output += String.fromCharCode(chr1);
if (enc3 !== 64) {
output += String.fromCharCode(chr2);
}
if (enc4 !== 64) {
output += String.fromCharCode(chr3);
}
}
return _utf8_decode(output);
};
var decodeToHex = function(input) {
return _hexEncode(decode(input));
};
var encodeFromHex = function(input) {
return encode(_hexDecode(input));
};
return {
'encode': encode,
'decode': decode,
'decodeToHex': decodeToHex,
'encodeFromHex': encodeFromHex
};
}());
Please note that this is not suitable for raw Unicode strings! See the Unicode section here.
Syntax for encoding
var encodedData = window.btoa(stringToEncode);
Syntax for decoding
var decodedData = window.atob(encodedData);
I have rewritten these encoding and decoding methods by hand with the exception of the hexadecimal one into a modular format for cross-platform / browser compatibility and also with real private scoping, and uses btoa
and atob
if they exist due to speed rather than utilize its own encoding:
https://gist.github.com/Nijikokun/5192472
Usage:
base64.encode(/* String */);
base64.decode(/* String */);
utf8.encode(/* String */);
utf8.decode(/* String */);
To make a Base64 encoded String URL friendly, in JavaScript you could do something like this:
// if this is your Base64 encoded string
var str = 'VGhpcyBpcyBhbiBhd2Vzb21lIHNjcmlwdA==';
// make URL friendly:
str = str.replace(/\+/g, '-').replace(/\//g, '_').replace(/\=+$/, '');
// reverse to original encoding
str = (str + '===').slice(0, str.length + (str.length % 4));
str = str.replace(/-/g, '+').replace(/_/g, '/');
See also this Fiddle: http://jsfiddle.net/magikMaker/7bjaT/
encodeURIComponent
may well result in a superior outcome with less expenditure of effort on the part of the developer.
If you need to encode an HTML image object, you can write a simple function like:
function getBase64Image(img) {
var canvas = document.createElement("canvas");
canvas.width = img.width;
canvas.height = img.height;
var ctx = canvas.getContext("2d");
ctx.drawImage(img, 0, 0);
var dataURL = canvas.toDataURL("image/png");
// escape data:image prefix
return dataURL.replace(/^data:image\/(png|jpg);base64,/, "");
// or just return dataURL
// return dataURL
}
To get the Base64 encoding of the image by id:
function getBase64ImageById(id){
return getBase64Image(document.getElementById(id));
}
More is here.
You can use window.btoa
and window.atob
...
const encoded = window.btoa('Alireza Dezfoolian'); // encode a string
const decoded = window.atob(encoded); // decode the string
Probably using the way which MDN is can do your job the best... Also accepting Unicode... using these two simple functions:
// UCS-2 string to Base64 encoded ASCII
function utoa(str) {
return window.btoa(unescape(encodeURIComponent(str)));
}
// Base64 encoded ASCII to UCS-2 string
function atou(str) {
return decodeURIComponent(escape(window.atob(str)));
}
// Usage:
utoa('✓ à la mode'); // 4pyTIMOgIGxhIG1vZGU=
atou('4pyTIMOgIGxhIG1vZGU='); // "✓ à la mode"
utoa('I \u2661 Unicode!'); // SSDimaEgVW5pY29kZSE=
atou('SSDimaEgVW5pY29kZSE='); // "I ♡ Unicode!"
I needed encoding of an UTF-8 string as Base64 for a project of mine. Most of the answers here don't seem to properly handle UTF-16 surrogate pairs when converting to UTF-8 so, for completion sake, I will post my solution:
function strToUTF8Base64(str) {
function decodeSurrogatePair(hi, lo) {
var resultChar = 0x010000;
resultChar += lo - 0xDC00;
resultChar += (hi - 0xD800) << 10;
return resultChar;
}
var bytes = [0, 0, 0];
var byteIndex = 0;
var result = [];
function output(s) {
result.push(s);
}
function emitBase64() {
var digits =
'ABCDEFGHIJKLMNOPQRSTUVWXYZ' +
'abcdefghijklmnopqrstuvwxyz' +
'0123456789+/';
function toDigit(value) {
return digits[value];
}
// --Byte 0-- --Byte 1-- --Byte 2--
// 1111 1122 2222 3333 3344 4444
var d1 = toDigit(bytes[0] >> 2);
var d2 = toDigit(
((bytes[0] & 0x03) << 4) |
(bytes[1] >> 4));
var d3 = toDigit(
((bytes[1] & 0x0F) << 2) |
(bytes[2] >> 6));
var d4 = toDigit(
bytes[2] & 0x3F);
if (byteIndex === 1) {
output(d1 + d2 + '==');
}
else if (byteIndex === 2) {
output(d1 + d2 + d3 + '=');
}
else {
output(d1 + d2 + d3 + d4);
}
}
function emit(chr) {
bytes[byteIndex++] = chr;
if (byteIndex == 3) {
emitBase64();
bytes[0] = 0;
bytes[1] = 0;
bytes[2] = 0;
byteIndex = 0;
}
}
function emitLast() {
if (byteIndex > 0) {
emitBase64();
}
}
// Converts the string to UTF8:
var i, chr;
var hi, lo;
for (i = 0; i < str.length; i++) {
chr = str.charCodeAt(i);
// Test and decode surrogate pairs in the string
if (chr >= 0xD800 && chr <= 0xDBFF) {
hi = chr;
lo = str.charCodeAt(i + 1);
if (lo >= 0xDC00 && lo <= 0xDFFF) {
chr = decodeSurrogatePair(hi, lo);
i++;
}
}
// Encode the character as UTF-8.
if (chr < 0x80) {
emit(chr);
}
else if (chr < 0x0800) {
emit((chr >> 6) | 0xC0);
emit(((chr >> 0) & 0x3F) | 0x80);
}
else if (chr < 0x10000) {
emit((chr >> 12) | 0xE0);
emit(((chr >> 6) & 0x3F) | 0x80);
emit(((chr >> 0) & 0x3F) | 0x80);
}
else if (chr < 0x110000) {
emit((chr >> 18) | 0xF0);
emit(((chr >> 12) & 0x3F) | 0x80);
emit(((chr >> 6) & 0x3F) | 0x80);
emit(((chr >> 0) & 0x3F) | 0x80);
}
}
emitLast();
return result.join('');
}
Note that the code is not thoroughly tested. I tested some inputs, including things like strToUTF8Base64('衠衢蠩蠨')
and compared with the output of an online encoding tool (https://www.base64encode.org/).
Here is a minified polyfill for window.atob
+ window.btoa
:
(function(){function t(t){this.message=t}var e="undefined"!=typeof exports?exports:this,r="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";t.prototype=Error(),t.prototype.name="InvalidCharacterError",e.btoa||(e.btoa=function(e){for(var o,n,a=0,i=r,c="";e.charAt(0|a)||(i="=",a%1);c+=i.charAt(63&o>>8-8*(a%1))){if(n=e.charCodeAt(a+=.75),n>255)throw new t("'btoa' failed: The string to be encoded contains characters outside of the Latin1 range.");o=o<<8|n}return c}),e.atob||(e.atob=function(e){if(e=e.replace(/=+$/,""),1==e.length%4)throw new t("'atob' failed: The string to be decoded is not correctly encoded.");for(var o,n,a=0,i=0,c="";n=e.charAt(i++);~n&&(o=a%4?64*o+n:n,a++%4)?c+=String.fromCharCode(255&o>>(6&-2*a)):0)n=r.indexOf(n);return c})})();
(function (root, factory) {
if (typeof define === 'function' && define.amd) {
// AMD. Register as an anonymous module.
define([], function() {factory(root);});
} else factory(root);
// node.js has always supported base64 conversions, while browsers that support
// web workers support base64 too, but you may never know.
})(typeof exports !== "undefined" ? exports : this, function(root) {
if (root.atob) {
// Some browsers' implementation of atob doesn't support whitespaces
// in the encoded string (notably, IE). This wraps the native atob
// in a function that strips the whitespaces.
// The original function can be retrieved in atob.original
try {
root.atob(" ");
} catch(e) {
root.atob = (function(atob) {
var func = function(string) {
return atob(String(string).replace(/[\t\n\f\r ]+/g, ""));
};
func.original = atob;
return func;
})(root.atob);
}
return;
}
// base64 character set, plus padding character (=)
var b64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=",
// Regular expression to check formal correctness of base64 encoded strings
b64re = /^(?:[A-Za-z\d+\/]{4})*?(?:[A-Za-z\d+\/]{2}(?:==)?|[A-Za-z\d+\/]{3}=?)?$/;
root.btoa = function(string) {
string = String(string);
var bitmap, a, b, c,
result = "", i = 0,
rest = string.length % 3; // To determine the final padding
for (; i < string.length;) {
if ((a = string.charCodeAt(i++)) > 255
|| (b = string.charCodeAt(i++)) > 255
|| (c = string.charCodeAt(i++)) > 255)
throw new TypeError("Failed to execute 'btoa' on 'Window': The string to be encoded contains characters outside of the Latin1 range.");
bitmap = (a << 16) | (b << 8) | c;
result += b64.charAt(bitmap >> 18 & 63) + b64.charAt(bitmap >> 12 & 63)
+ b64.charAt(bitmap >> 6 & 63) + b64.charAt(bitmap & 63);
}
// If there's need of padding, replace the last 'A's with equal signs
return rest ? result.slice(0, rest - 3) + "===".substring(rest) : result;
};
root.atob = function(string) {
// atob can work with strings with whitespaces, even inside the encoded part,
// but only \t, \n, \f, \r and ' ', which can be stripped.
string = String(string).replace(/[\t\n\f\r ]+/g, "");
if (!b64re.test(string))
throw new TypeError("Failed to execute 'atob' on 'Window': The string to be decoded is not correctly encoded.");
// Adding the padding if missing, for semplicity
string += "==".slice(2 - (string.length & 3));
var bitmap, result = "", r1, r2, i = 0;
for (; i < string.length;) {
bitmap = b64.indexOf(string.charAt(i++)) << 18 | b64.indexOf(string.charAt(i++)) << 12
| (r1 = b64.indexOf(string.charAt(i++))) << 6 | (r2 = b64.indexOf(string.charAt(i++)));
result += r1 === 64 ? String.fromCharCode(bitmap >> 16 & 255)
: r2 === 64 ? String.fromCharCode(bitmap >> 16 & 255, bitmap >> 8 & 255)
: String.fromCharCode(bitmap >> 16 & 255, bitmap >> 8 & 255, bitmap & 255);
}
return result;
};
});
Full version from https://github.com/MaxArt2501/base64-js/blob/master/base64.js
Here is an AngularJS Factory version of @user850789's one:
'use strict';
var ProjectNameBase64Factory = angular.module('project_name.factories.base64', []);
ProjectNameBase64Factory.factory('Base64', function () {
var Base64 = {
// private property
_keyStr: "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=",
// public method for encoding
encode: function (input) {
var output = "";
var chr1, chr2, chr3, enc1, enc2, enc3, enc4;
var i = 0;
input = Base64._utf8_encode(input);
while (i < input.length) {
chr1 = input.charCodeAt(i++);
chr2 = input.charCodeAt(i++);
chr3 = input.charCodeAt(i++);
enc1 = chr1 >> 2;
enc2 = ((chr1 & 3) << 4) | (chr2 >> 4);
enc3 = ((chr2 & 15) << 2) | (chr3 >> 6);
enc4 = chr3 & 63;
if (isNaN(chr2)) {
enc3 = enc4 = 64;
} else if (isNaN(chr3)) {
enc4 = 64;
}
output = output +
Base64._keyStr.charAt(enc1) + Base64._keyStr.charAt(enc2) +
Base64._keyStr.charAt(enc3) + Base64._keyStr.charAt(enc4);
}
return output;
},
// public method for decoding
decode: function (input) {
var output = "";
var chr1, chr2, chr3;
var enc1, enc2, enc3, enc4;
var i = 0;
input = input.replace(/[^A-Za-z0-9\+\/\=]/g, "");
while (i < input.length) {
enc1 = Base64._keyStr.indexOf(input.charAt(i++));
enc2 = Base64._keyStr.indexOf(input.charAt(i++));
enc3 = Base64._keyStr.indexOf(input.charAt(i++));
enc4 = Base64._keyStr.indexOf(input.charAt(i++));
chr1 = (enc1 << 2) | (enc2 >> 4);
chr2 = ((enc2 & 15) << 4) | (enc3 >> 2);
chr3 = ((enc3 & 3) << 6) | enc4;
output = output + String.fromCharCode(chr1);
if (enc3 != 64) {
output = output + String.fromCharCode(chr2);
}
if (enc4 != 64) {
output = output + String.fromCharCode(chr3);
}
}
output = Base64._utf8_decode(output);
return output;
},
// private method for UTF-8 encoding
_utf8_encode: function (string) {
string = string.replace(/\r\n/g, "\n");
var utftext = "";
for (var n = 0; n < string.length; n++) {
var c = string.charCodeAt(n);
if (c < 128) {
utftext += String.fromCharCode(c);
}
else if ((c > 127) && (c < 2048)) {
utftext += String.fromCharCode((c >> 6) | 192);
utftext += String.fromCharCode((c & 63) | 128);
}
else {
utftext += String.fromCharCode((c >> 12) | 224);
utftext += String.fromCharCode(((c >> 6) & 63) | 128);
utftext += String.fromCharCode((c & 63) | 128);
}
}
return utftext;
},
// private method for UTF-8 decoding
_utf8_decode: function (utftext) {
var string = "";
var i = 0;
var c = 0, c2 = 0, c3 = 0;
while (i < utftext.length) {
c = utftext.charCodeAt(i);
if (c < 128) {
string += String.fromCharCode(c);
i++;
}
else if ((c > 191) && (c < 224)) {
c2 = utftext.charCodeAt(i + 1);
string += String.fromCharCode(((c & 31) << 6) | (c2 & 63));
i += 2;
}
else {
c2 = utftext.charCodeAt(i + 1);
c3 = utftext.charCodeAt(i + 2);
string += String.fromCharCode(((c & 15) << 12) | ((c2 & 63) << 6) | (c3 & 63));
i += 3;
}
}
return string;
}
};
return Base64;
});
I'd rather use the Base64 encode/decode methods from CryptoJS, the most popular library for standard and secure cryptographic algorithms implemented in JavaScript using best practices and patterns.
Here is a LIVE DEMO of atob()
and btoa()
JavaScript built-in functions:
<!DOCTYPE html>
<html>
<head>
<style>
textarea{
width:30%;
height:100px;
}
</style>
<script>
// encode string to base64
function encode()
{
var txt = document.getElementById("txt1").value;
var result = btoa(txt);
document.getElementById("txt2").value = result;
}
// decode base64 back to original string
function decode()
{
var txt = document.getElementById("txt3").value;
var result = atob(txt);
document.getElementById("txt4").value = result;
}
</script>
</head>
<body>
<div>
<textarea id="txt1">Some text to decode
</textarea>
</div>
<div>
<input type="button" id="btnencode" value="Encode" onClick="encode()"/>
</div>
<div>
<textarea id="txt2">
</textarea>
</div>
<br/>
<div>
<textarea id="txt3">U29tZSB0ZXh0IHRvIGRlY29kZQ==
</textarea>
</div>
<div>
<input type="button" id="btndecode" value="Decode" onClick="decode()"/>
</div>
<div>
<textarea id="txt4">
</textarea>
</div>
</body>
</html>
For my project I still need to support IE7 and work with large input to encode.
Based on the code proposed by Joe Dyndale and as suggested in comment by Marius, it is possible to improve the performance with IE7 by constructing the result with an array instead of a string.
Here is the example for encode:
var encode = function (input) {
var output = [], chr1, chr2, chr3, enc1, enc2, enc3, enc4, i = 0;
input = _utf8_encode(input);
while (i < input.length) {
chr1 = input.charCodeAt(i++);
chr2 = input.charCodeAt(i++);
chr3 = input.charCodeAt(i++);
enc1 = chr1 >> 2;
enc2 = ((chr1 & 3) << 4) | (chr2 >> 4);
enc3 = ((chr2 & 15) << 2) | (chr3 >> 6);
enc4 = chr3 & 63;
if (isNaN(chr2)) {
enc3 = enc4 = 64;
} else if (isNaN(chr3)) {
enc4 = 64;
}
output.push(_keyStr.charAt(enc1));
output.push(_keyStr.charAt(enc2));
output.push(_keyStr.charAt(enc3));
output.push(_keyStr.charAt(enc4));
}
return output.join("");
};
Well, if you are using Dojo. It gives us direct way to encode or decode into Base64.
Try this:
To encode an array of bytes using dojox.encoding.base64:
var str = dojox.encoding.base64.encode(myByteArray);
To decode a Base64-encoded string:
var bytes = dojox.encoding.base64.decode(str);
While a bit more work, if you want a high performance native solution there are some HTML5 functions you can use.
If you can get your data into a Blob
, then you can use the FileReader.readAsDataURL() function to get a data://
URL and chop off the front of it to get at the Base64 data.
You may have to do further processing however to urldecode the data, as I'm not sure whether +
characters are escaped or not for the data://
URL, but this should be pretty trivial.
Use the js-base64 library as
btoa() doesn't work with emojis
var str = "I was funny 😂"; console.log("Original string:", str); var encodedStr = Base64.encode(str) console.log("Encoded string:", encodedStr); var decodedStr = Base64.decode(encodedStr) console.log("Decoded string:", decodedStr);
When I use
btoa("☸☹☺☻☼☾☿"))
I get:
Error InvalidCharacterError: The string to be encoded contains characters outside of the Latin1 range.
I found documentation, Unicode strings, was providing a solution as below.
function toBinary(string) { const codeUnits = new Uint16Array(string.length); for (let i = 0; i < codeUnits.length; i++) { codeUnits[i] = string.charCodeAt(i); } return String.fromCharCode(...new Uint8Array(codeUnits.buffer)); } function fromBinary(binary) { const bytes = new Uint8Array(binary.length); for (let i = 0; i < bytes.length; i++) { bytes[i] = binary.charCodeAt(i); } return String.fromCharCode(...new Uint16Array(bytes.buffer)); } const myString = "☸☹☺☻☼☾☿" // console.log(btoa(myString)) // Error InvalidCharacterError: The string to be encoded contains characters outside of the Latin1 range. const converted = toBinary(myString) const encoded = btoa(converted) console.log(encoded) const decoded = atob(encoded) const original = fromBinary(decoded) console.log(original);
2022 deprecation warning update
I saw deprecation warning on my vscode
This function is only provided for compatibility with legacy web platform APIs and should never be used in new code,
because they use strings to represent binary data and predate the introduction of typed arrays in JavaScript.
For code running using Node.js APIs,
converting between base64-encoded strings and binary data should be performed using Buffer.from(str, 'base64') andbuf.toString('base64').
After searching a bit more, I found this issue that says it isn't deprecated
https://github.com/microsoft/TypeScript/issues/45566
so the solution to the deprecation warning on web JS, use window.btoa
and the warning will disappear.
JavaScript without the btoa middlestep (no library)
In the question title you write about string conversion, but in the question you talk about binary data (picture) so here is a function which makes a proper conversion starting from PNG picture binary data (details and reversal conversion are here).
https://i.stack.imgur.com/g2aN7.png
function bytesArrToBase64(arr) {
const abc = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; // base64 alphabet
const bin = n => n.toString(2).padStart(8,0); // convert num to 8-bit binary string
const l = arr.length
let result = '';
for(let i=0; i<=(l-1)/3; i++) {
let c1 = i*3+1>=l; // case when "=" is on end
let c2 = i*3+2>=l; // case when "=" is on end
let chunk = bin(arr[3*i]) + bin(c1? 0:arr[3*i+1]) + bin(c2? 0:arr[3*i+2]);
let r = chunk.match(/.{1,6}/g).map((x,j)=> j==3&&c2 ? '=' :(j==2&&c1 ? '=':abc[+('0b'+x)]));
result += r.join('');
}
return result;
}
// TEST
const pic = [ // PNG binary data
0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a, 0x00, 0x00, 0x00, 0x0d,
0x49, 0x48, 0x44, 0x52, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x10,
0x08, 0x06, 0x00, 0x00, 0x00, 0x1f, 0xf3, 0xff, 0x61, 0x00, 0x00, 0x00,
0x01, 0x73, 0x52, 0x47, 0x42, 0x00, 0xae, 0xce, 0x1c, 0xe9, 0x00, 0x00,
0x01, 0x59, 0x69, 0x54, 0x58, 0x74, 0x58, 0x4d, 0x4c, 0x3a, 0x63, 0x6f,
0x6d, 0x2e, 0x61, 0x64, 0x6f, 0x62, 0x65, 0x2e, 0x78, 0x6d, 0x70, 0x00,
0x00, 0x00, 0x00, 0x00, 0x3c, 0x78, 0x3a, 0x78, 0x6d, 0x70, 0x6d, 0x65,
0x74, 0x61, 0x20, 0x78, 0x6d, 0x6c, 0x6e, 0x73, 0x3a, 0x78, 0x3d, 0x22,
0x61, 0x64, 0x6f, 0x62, 0x65, 0x3a, 0x6e, 0x73, 0x3a, 0x6d, 0x65, 0x74,
0x61, 0x2f, 0x22, 0x20, 0x78, 0x3a, 0x78, 0x6d, 0x70, 0x74, 0x6b, 0x3d,
0x22, 0x58, 0x4d, 0x50, 0x20, 0x43, 0x6f, 0x72, 0x65, 0x20, 0x35, 0x2e,
0x34, 0x2e, 0x30, 0x22, 0x3e, 0x0a, 0x20, 0x20, 0x20, 0x3c, 0x72, 0x64,
0x66, 0x3a, 0x52, 0x44, 0x46, 0x20, 0x78, 0x6d, 0x6c, 0x6e, 0x73, 0x3a,
0x72, 0x64, 0x66, 0x3d, 0x22, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f,
0x77, 0x77, 0x77, 0x2e, 0x77, 0x33, 0x2e, 0x6f, 0x72, 0x67, 0x2f, 0x31,
0x39, 0x39, 0x39, 0x2f, 0x30, 0x32, 0x2f, 0x32, 0x32, 0x2d, 0x72, 0x64,
0x66, 0x2d, 0x73, 0x79, 0x6e, 0x74, 0x61, 0x78, 0x2d, 0x6e, 0x73, 0x23,
0x22, 0x3e, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x3c, 0x72, 0x64,
0x66, 0x3a, 0x44, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f,
0x6e, 0x20, 0x72, 0x64, 0x66, 0x3a, 0x61, 0x62, 0x6f, 0x75, 0x74, 0x3d,
0x22, 0x22, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
0x20, 0x20, 0x20, 0x78, 0x6d, 0x6c, 0x6e, 0x73, 0x3a, 0x74, 0x69, 0x66,
0x66, 0x3d, 0x22, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x6e, 0x73,
0x2e, 0x61, 0x64, 0x6f, 0x62, 0x65, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x74,
0x69, 0x66, 0x66, 0x2f, 0x31, 0x2e, 0x30, 0x2f, 0x22, 0x3e, 0x0a, 0x20,
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x3c, 0x74, 0x69, 0x66,
0x66, 0x3a, 0x4f, 0x72, 0x69, 0x65, 0x6e, 0x74, 0x61, 0x74, 0x69, 0x6f,
0x6e, 0x3e, 0x31, 0x3c, 0x2f, 0x74, 0x69, 0x66, 0x66, 0x3a, 0x4f, 0x72,
0x69, 0x65, 0x6e, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x3e, 0x0a, 0x20,
0x20, 0x20, 0x20, 0x20, 0x20, 0x3c, 0x2f, 0x72, 0x64, 0x66, 0x3a, 0x44,
0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x3e, 0x0a,
0x20, 0x20, 0x20, 0x3c, 0x2f, 0x72, 0x64, 0x66, 0x3a, 0x52, 0x44, 0x46,
0x3e, 0x0a, 0x3c, 0x2f, 0x78, 0x3a, 0x78, 0x6d, 0x70, 0x6d, 0x65, 0x74,
0x61, 0x3e, 0x0a, 0x4c, 0xc2, 0x27, 0x59, 0x00, 0x00, 0x00, 0xf9, 0x49,
0x44, 0x41, 0x54, 0x38, 0x11, 0x95, 0x93, 0x3d, 0x0a, 0x02, 0x41, 0x0c,
0x85, 0xb3, 0xb2, 0x85, 0xb7, 0x10, 0x6c, 0x04, 0x1b, 0x0b, 0x4b, 0x6f,
0xe2, 0x76, 0x1e, 0xc1, 0xc2, 0x56, 0x6c, 0x2d, 0xbc, 0x85, 0xde, 0xc4,
0xd2, 0x56, 0xb0, 0x11, 0xbc, 0x85, 0x85, 0xa0, 0xfb, 0x46, 0xbf, 0xd9,
0x30, 0x33, 0x88, 0x06, 0x76, 0x93, 0x79, 0x93, 0xf7, 0x92, 0xf9, 0xab,
0xcc, 0xec, 0xd9, 0x7e, 0x7f, 0xd9, 0x63, 0x33, 0x8e, 0xf9, 0x75, 0x8c,
0x92, 0xe0, 0x34, 0xe8, 0x27, 0x88, 0xd9, 0xf4, 0x76, 0xcf, 0xb0, 0xaa,
0x45, 0xb2, 0x0e, 0x4a, 0xe4, 0x94, 0x39, 0x59, 0x0c, 0x03, 0x54, 0x14,
0x58, 0xce, 0xbb, 0xea, 0xdb, 0xd1, 0x3b, 0x71, 0x75, 0xb9, 0x9a, 0xe2,
0x7a, 0x7d, 0x36, 0x3f, 0xdf, 0x4b, 0x95, 0x35, 0x09, 0x09, 0xef, 0x73,
0xfc, 0xfa, 0x85, 0x67, 0x02, 0x3e, 0x59, 0x55, 0x31, 0x89, 0x31, 0x56,
0x8c, 0x78, 0xb6, 0x04, 0xda, 0x23, 0x01, 0x01, 0xc8, 0x8c, 0xe5, 0x77,
0x87, 0xbb, 0x65, 0x02, 0x24, 0xa4, 0xad, 0x82, 0xcb, 0x4b, 0x4c, 0x64,
0x59, 0x14, 0xa0, 0x72, 0x40, 0x3f, 0xbf, 0xe6, 0x68, 0xb6, 0x9f, 0x75,
0x08, 0x63, 0xc8, 0x9a, 0x09, 0x02, 0x25, 0x32, 0x34, 0x48, 0x7e, 0xcc,
0x7d, 0x10, 0xaf, 0xa6, 0xd5, 0xd2, 0x1a, 0x3d, 0x89, 0x38, 0xf5, 0xf1,
0x14, 0xb4, 0x69, 0x6a, 0x4d, 0x15, 0xf5, 0xc9, 0xf0, 0x5c, 0x1a, 0x61,
0x8a, 0x75, 0xd1, 0xe8, 0x3a, 0x2c, 0x41, 0x5d, 0x70, 0x41, 0x20, 0x29,
0xf9, 0x9b, 0xb1, 0x37, 0xc5, 0x4d, 0xfc, 0x45, 0x84, 0x7d, 0x08, 0x8f,
0x89, 0x76, 0x54, 0xf1, 0x1b, 0x19, 0x92, 0xef, 0x2c, 0xbe, 0x46, 0x8e,
0xa6, 0x49, 0x5e, 0x61, 0x89, 0xe4, 0x05, 0x5e, 0x4e, 0xa4, 0x5c, 0x10,
0x6e, 0x9f, 0xfc, 0x5b, 0x00, 0x00, 0x00, 0x00, 0x49, 0x45, 0x4e, 0x44,
0xae, 0x42, 0x60, 0x82
];
let b64pic = bytesArrToBase64(pic);
myPic.src = "data:image/png;base64,"+b64pic;
msg.innerHTML = "Base64 encoded pic data:
" + b64pic; img { zoom: 10; image-rendering: pixelated; }
#msg { word-break: break-all; }
Here is helper funktion to encode to base64url:
base64url (s) {
var to64url = btao(s);
// Replace non-url compatible chars with base64url standard chars and remove leading =
return to64url.replace(/\+/g, '_').replace(/\//g, '-').replace(/=+$/g, '');
}
btoa
not btao
You can use btoa()/atob() in browser, but some improvements required, as described here https://base64tool.com/uncaught-domexception-btoa-on-window/ and there https://developer.mozilla.org/en-US/docs/Web/API/WindowOrWorkerGlobalScope/btoa for UTF strings support!
Success story sharing
btoa(unescape(encodeURIComponent(str))))
if str is UFT8b to a
anda to b
, b standing for binary and a standing for ASCII