Luego de buscar en diversos repositorios y páginas al terminar hemos descubierto la resolución que te mostramos aquí.
Solución:
Si tiene UTF8, use esto (en realidad funciona con la fuente SVG), como:
btoa(unescape(encodeURIComponent(str)))
ejemplo:
var imgsrc = 'data:image/svg+xml;base64,' + btoa(unescape(encodeURIComponent(markup)));
var img = new Image(1, 1); // width, height values are optional params
img.src = imgsrc;
Si necesita decodificar esa base64, use esto:
var str2 = decodeURIComponent(escape(window.atob(b64)));
console.log(str2);
Ejemplo:
var str = "äöüÄÖÜçéèñ";
var b64 = window.btoa(unescape(encodeURIComponent(str)))
console.log(b64);
var str2 = decodeURIComponent(escape(window.atob(b64)));
console.log(str2);
Nota: si necesita que esto funcione en mobile-safari, es posible que deba eliminar todo el espacio en blanco de los datos base64 …
function b64_to_utf8( str )
str = str.replace(/s/g, '');
return decodeURIComponent(escape(window.atob( str )));
Actualización 2017
Este problema me ha estado molestando nuevamente.
La simple verdad es que atob realmente no maneja cadenas UTF8, es solo ASCII.
Además, no usaría bloatware como js-base64.
Pero webtoolkit tiene una implementación pequeña, agradable y muy fácil de mantener:
/**
*
* 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)
(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);
// Whend
return output;
// End Function encode
// 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)
(enc2 >> 4);
chr2 = ((enc2 & 15) << 4) // Whend
output = Base64._utf8_decode(output);
return output;
// End Function decode
// private method for UTF-8 encoding
,_utf8_encode: function (string)
var utftext = "";
string = string.replace(/rn/g, "n");
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)
else
utftext += String.fromCharCode((c >> 12)
// Next n
return utftext;
// End Function _utf8_encode
// private method for UTF-8 decoding
,_utf8_decode: function (utftext)
var string = "";
var i = 0;
var c, c1, c2, c3;
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 & 63));
i += 2;
else
c2 = utftext.charCodeAt(i + 1);
c3 = utftext.charCodeAt(i + 2);
string += String.fromCharCode(((c & 15) << 12)
// Whend
return string;
// End Function _utf8_decode
https://www.fileformat.info/info/unicode/utf8.htm
Para cualquier carácter igual o inferior a 127 (hexadecimal 0x7F), la representación UTF-8 es un byte. Son solo los 7 bits más bajos del valor Unicode completo. Este también es el mismo que el valor ASCII.
Para caracteres iguales o inferiores a 2047 (hexadecimal 0x07FF), la representación UTF-8 se distribuye en dos bytes. El primer byte tendrá los dos bits altos configurados y el tercer bit se borrará (es decir, 0xC2 a 0xDF). El segundo byte tendrá el bit superior establecido y el segundo bit limpio (es decir, 0x80 a 0xBF).
Para todos los caracteres iguales o mayores que 2048 pero menores que 65535 (0xFFFF), la representación UTF-8 se distribuye en tres bytes.
Use una biblioteca en su lugar
No tenemos que reinventar la rueda. Simplemente use una biblioteca para ahorrar tiempo y dolores de cabeza.
js-base64
https://github.com/dankogai/js-base64 es bueno y confirmo que es compatible con Unicode muy bien.
Base64.encode('dankogai'); // ZGFua29nYWk=
Base64.encode('小飼弾'); // 5bCP6aO85by+
Base64.encodeURI('小飼弾'); // 5bCP6aO85by-
Base64.decode('ZGFua29nYWk='); // dankogai
Base64.decode('5bCP6aO85by+'); // 小飼弾
// note .decodeURI() is unnecessary since it accepts both flavors
Base64.decode('5bCP6aO85by-'); // 小飼弾
Utilizando btoa
con unescape
y encodeURIComponent
no funcionó para mí. Reemplazar todos los caracteres especiales con entidades XML / HTML y luego convertir a la representación base64 fue la única forma de resolver este problema para mí. Algún código:
base64 = btoa(str.replace(/[u00A0-u2666]/g, function(c)
return '' + c.charCodeAt(0) + ';';
));
Tienes la opción de añadir valor a nuestro contenido informacional añadiendo tu veteranía en las observaciones.