Se você possui UTF8, use isso (realmente funciona com fonte SVG), como:
btoa(unescape(encodeURIComponent(str)))
exemplo:
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;
Se você precisar decodificar essa base64, use o seguinte:
var str2 = decodeURIComponent(escape(window.atob(b64)));
console.log(str2);
Exemplo:
var str = "äöüÄÖÜçéèñ";
var b64 = window.btoa(unescape(encodeURIComponent(str)))
console.log(b64);
var str2 = decodeURIComponent(escape(window.atob(b64)));
console.log(str2);
Nota: se você precisar fazer isso funcionar no safari móvel, poderá ser necessário remover todo o espaço em branco dos dados base64 ...
function b64_to_utf8( str ) {
str = str.replace(/\s/g, '');
return decodeURIComponent(escape(window.atob( str )));
}
Atualização de 2017
Esse problema está me incomodando novamente.
A verdade simples é que o atob realmente não lida com UTF8 - é apenas ASCII.
Além disso, eu não usaria bloatware como o js-base64.
Mas o webtoolkit possui uma implementação pequena, agradável e de fácil manutenção:
/**
*
* 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 qualquer caractere igual ou inferior a 127 (hex 0x7F), a representação UTF-8 é de um byte. São apenas os 7 bits mais baixos do valor unicode completo. Também é o mesmo que o valor ASCII.
Para caracteres iguais ou inferiores a 2047 (hex 0x07FF), a representação UTF-8 está espalhada por dois bytes. O primeiro byte terá os dois bits altos definidos e o terceiro bit limpo (ou seja, 0xC2 a 0xDF). O segundo byte terá o bit superior definido e o segundo bit limpo (ou seja, 0x80 a 0xBF).
Para todos os caracteres iguais ou superiores a 2048, mas inferiores a 65535 (0xFFFF), a representação UTF-8 está espalhada por três bytes.
escape
converte a string na que contém apenas caracteres válidos de URL. Isso evita os erros.escape
eunescape
foram preteridos no JavaScript 1.5 e deve-se usarencodeURIComponent
oudecodeURIComponent
, respectivamente, em vez disso. Você está usando as funções preterida e nova juntas. Por quê? Veja: w3schools.com/jsref/jsref_escape.aspUsando
btoa
comunescape
eencodeURIComponent
não funcionou para mim. Substituir todos os caracteres especiais por entidades XML / HTML e depois converter para a representação base64 foi a única maneira de resolver esse problema para mim. Algum código:fonte
Blob
object para manipular a conversão.Blob
pode lidar com qualquer dado binário.Use uma biblioteca
Não precisamos reinventar a roda. Basta usar uma biblioteca para economizar tempo e dor de cabeça.
js-base64
https://github.com/dankogai/js-base64 é bom e confirmo que ele suporta muito bem o unicode.
fonte
Apenas pensei em compartilhar como realmente resolvi o problema e por que acho que essa é a solução certa (desde que você não otimize o navegador antigo).
Convertendo dados em dataURL (
data: ...
)Permitindo que o usuário salve dados
Além da solução óbvia - abrindo uma nova janela com o dataURL como URL, você pode fazer duas outras coisas.
1. Use fileSaver.js
O economizador de arquivos pode criar uma caixa de diálogo fileSave real com o nome de arquivo predefinido. Também pode recorrer à abordagem normal de dataURL.
2. Uso (experimental)
URL.createObjectURL
Isso é ótimo para reutilizar dados codificados em base64. Ele cria uma URL curta para o seu dataURL:
Não se esqueça de usar o URL, incluindo o
blob
prefixo principal . Eu useidocument.body
novamente:Você pode usar esse URL curto como destino AJAX,
<script>
origem ou<a>
local href. Você é responsável por destruir o URL:fonte
Como complemento à resposta de Stefan Steiger: (como não parece bom como um comentário)
Protótipo de String de extensão:
Uso:
NOTA:
Conforme declarado nos comentários, o uso
unescape
não é recomendado, pois pode ser removido no futuro:fonte
unescape
será preterido em breve, de acordo com o MDN developer.mozilla.org/pt-BR/docs/Web/JavaScript/Reference/…btoa () suporta apenas caracteres de String.fromCodePoint (0) até String.fromCodePoint (255). Para caracteres Base64 com um ponto de código 256 ou superior, é necessário codificá-los / decodificá-los antes e depois.
E, neste ponto, torna-se complicado ...
Todo sinal possível é organizado em uma tabela Unicode. A tabela Unicode é dividida em diferentes planos (idiomas, símbolos matemáticos etc.). Cada sinal em um avião tem um número de ponto de código exclusivo. Teoricamente, o número pode se tornar arbitrariamente grande.
Um computador armazena os dados em bytes (8 bits, hexadecimal 0x00 - 0xff, binário 00000000 - 11111111, decimal 0 - 255). Esse intervalo normalmente é usado para salvar caracteres básicos (intervalo Latin1).
Para caracteres com maior ponto de código, existem 255 codificações diferentes. O JavaScript usa 16 bits por sinal (UTF-16), a sequência chamada DOMString. Unicode pode manipular pontos de código até 0x10fffff. Isso significa que um método deve existir para armazenar vários bits em várias células de distância.
String.fromCodePoint(0x10000).length == 2
O UTF-16 usa pares substitutos para armazenar 20 bits em duas células de 16 bits. O primeiro substituto superior começa com 110110xxxxxxxxxx , o segundo inferior com 110111xxxxxxxxxxxx . Unicode reservou aviões próprios para isso: https://unicode-table.com/de/#high-surrogates
Para armazenar caracteres em procedimentos padronizados de bytes (intervalo Latin1), use UTF-8 .
Desculpe dizer isso, mas acho que não há outra maneira de implementar essa função.
como usá-lo:
decodeBase64(encodeBase64("\u{1F604}"))
demo: https://jsfiddle.net/qrLadeb8/
fonte
stringToUTF8
e, noutf8ToString
entanto,Acabei de me deparar com esse problema.
Primeiro, modifique seu código levemente:
Em seguida, use seu inspetor da web favorito, coloque um ponto de interrupção na linha de código que atribui this.loader.src e execute este código:
Dependendo do seu aplicativo, a substituição dos caracteres que estão fora do intervalo pode ou não funcionar, pois você modificará os dados. Veja a nota no MDN sobre caracteres unicode com o método btoa:
https://developer.mozilla.org/en-US/docs/Web/API/window.btoa
fonte