Si tiene UTF8, use esto (en realidad funciona con 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 el safari móvil, es posible que deba eliminar todo el espacio en blanco de los datos de 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 de nuevo.
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)
{
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);
} // 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)
{
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);
}
} // 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(/\r\n/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) | 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);
}
} // 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 = 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;
}
} // Whend
return string;
} // End Function _utf8_decode
}
https://www.fileformat.info/info/unicode/utf8.htm
Para cualquier carácter igual o inferior a 127 (hex 0x7F), la representación UTF-8 es un byte. Son solo los 7 bits más bajos del valor Unicode completo. Esto también es lo 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 establecidos y el tercer bit libre (es decir, 0xC2 a 0xDF). El segundo byte tendrá el bit superior establecido y el segundo bit libre (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.
escape
convierte una cadena en la que solo contiene caracteres válidos de URL. Eso evita los errores.escape
yunescape
fueron desaprobados en JavaScript 1.5 y uno debería usarencodeURIComponent
odecodeURIComponent
, respectivamente, en su lugar. Estás utilizando las funciones obsoletas y nuevas juntas. ¿Por qué? Ver: w3schools.com/jsref/jsref_escape.aspUsar
btoa
conunescape
yencodeURIComponent
no funcionó para mí. Reemplazar todos los caracteres especiales con entidades XML / HTML y luego convertirlos a la representación base64 fue la única forma de resolver este problema para mí. Algún código:fuente
Blob
objeto para manejar la conversión.Blob
puede manejar cualquier dato binario.Use una biblioteca en su lugar
No tenemos que reinventar la rueda. Simplemente use una biblioteca para ahorrar tiempo y dolor de cabeza.
js-base64
https://github.com/dankogai/js-base64 es bueno y confirmo que admite muy bien unicode.
fuente
Solo pensé que debería compartir cómo resolví el problema y por qué creo que esta es la solución correcta (siempre que no optimice para el navegador antiguo).
Convertir datos a dataURL (
data: ...
)Permitir al usuario guardar datos
Además de la solución obvia: abrir una nueva ventana con su dataURL como URL, puede hacer otras dos cosas.
1. Use fileSaver.js
El protector de archivos puede crear un diálogo real de guardar archivos con un nombre de archivo predefinido. También puede recurrir al enfoque normal de dataURL.
2. Uso (experimental)
URL.createObjectURL
Esto es ideal para reutilizar datos codificados en base64. Crea una URL corta para su dataURL:
No olvides usar la URL que incluye el
blob
prefijo principal . Usé dedocument.body
nuevo:Puede usar esta URL corta como destino AJAX,
<script>
fuente o<a>
ubicación href. Sin embargo, eres responsable de destruir la URL:fuente
Como complemento a la respuesta de Stefan Steiger: (ya que no se ve bien como comentario)
Prototipo de cadena extensible:
Uso:
NOTA:
Como se indica en los comentarios,
unescape
no se recomienda el uso, ya que puede eliminarse en el futuro:fuente
unescape
pronto será desaprobado según MDN developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…btoa () solo admite caracteres desde String.fromCodePoint (0) hasta String.fromCodePoint (255). Para los caracteres Base64 con un punto de código 256 o superior, debe codificarlos / decodificarlos antes y después.
Y en este punto se vuelve complicado ...
Cada signo posible se organiza en una tabla Unicode. La tabla Unicode se divide en diferentes planos (idiomas, símbolos matemáticos, etc.). Cada signo en un avión tiene un número de punto de código único. Teóricamente, el número puede llegar a ser arbitrariamente grande.
Una computadora almacena los datos en bytes (8 bits, hexadecimal 0x00 - 0xff, binario 00000000 - 11111111, decimal 0 - 255). Este rango normalmente se usa para guardar caracteres básicos (rango Latin1).
Para los caracteres con un punto de código más alto, 255 existen diferentes codificaciones. JavaScript usa 16 bits por signo (UTF-16), la cadena llamada DOMString. Unicode puede manejar puntos de código de hasta 0x10fffff. Eso significa que debe existir un método para almacenar varios bits en varias celdas de distancia.
String.fromCodePoint(0x10000).length == 2
UTF-16 usa pares sustitutos para almacenar 20 bits en dos celdas de 16 bits. El primer sustituto superior comienza con 110110xxxxxxxxxx , el segundo inferior con 110111xxxxxxxxxx . Unicode reservó sus propios planos para esto: https://unicode-table.com/de/#high-surrogates
Para almacenar caracteres en bytes (rango Latin1), los procedimientos estandarizados utilizan UTF-8 .
Lamento decir eso, pero creo que no hay otra forma de implementar esta función por sí mismo.
cómo usarlo:
decodeBase64(encodeBase64("\u{1F604}"))
demostración: https://jsfiddle.net/qrLadeb8/
fuente
stringToUTF8
y,utf8ToString
sin embargoMe encontré con este problema yo mismo.
Primero, modifique su código ligeramente:
Luego use su inspector web favorito, coloque un punto de interrupción en la línea de código que asigna this.loader.src, luego ejecute este código:
Dependiendo de su aplicación, reemplazar los caracteres que están fuera del rango puede o no funcionar, ya que modificará los datos. Consulte la nota en MDN sobre los caracteres unicode con el método btoa:
https://developer.mozilla.org/en-US/docs/Web/API/window.btoa
fuente