Si vous avez UTF8, utilisez ceci (fonctionne en fait avec la source SVG), comme:
btoa(unescape(encodeURIComponent(str)))
exemple:
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 vous avez besoin de décoder cette base64, utilisez ceci:
var str2 = decodeURIComponent(escape(window.atob(b64)));
console.log(str2);
Exemple:
var str = "äöüÄÖÜçéèñ";
var b64 = window.btoa(unescape(encodeURIComponent(str)))
console.log(b64);
var str2 = decodeURIComponent(escape(window.atob(b64)));
console.log(str2);
Remarque: si vous devez faire en sorte que cela fonctionne dans mobile-safari, vous devrez peut-être supprimer tout l'espace blanc des données base64 ...
function b64_to_utf8( str ) {
str = str.replace(/\s/g, '');
return decodeURIComponent(escape(window.atob( str )));
}
Mise à jour 2017
Ce problème me dérange à nouveau.
La simple vérité est que atob ne gère pas vraiment les chaînes UTF8 - c'est uniquement ASCII.
De plus, je n'utiliserais pas de bloatware comme js-base64.
Mais webtoolkit a une implémentation petite, agréable et très maintenable:
/**
*
* 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
Pour tout caractère égal ou inférieur à 127 (hex 0x7F), la représentation UTF-8 est d'un octet. Ce ne sont que les 7 bits les plus bas de la valeur unicode complète. C'est également la même que la valeur ASCII.
Pour les caractères égaux ou inférieurs à 2047 (hex 0x07FF), la représentation UTF-8 est répartie sur deux octets. Le premier octet aura les deux bits hauts définis et le troisième bit clair (c'est-à-dire 0xC2 à 0xDF). Le deuxième octet aura le bit supérieur défini et le deuxième bit clair (c'est-à-dire 0x80 à 0xBF).
Pour tous les caractères égaux ou supérieurs à 2048 mais inférieurs à 65535 (0xFFFF), la représentation UTF-8 est répartie sur trois octets.
escape
convertit la chaîne dans celle qui ne contient que des caractères valides d'URL. Cela évite les erreurs.escape
etunescape
étaient obsolètes dans JavaScript 1.5 et on devrait utiliserencodeURIComponent
oudecodeURIComponent
, respectivement, à la place. Vous utilisez ensemble les fonctions obsolètes et nouvelles. Pourquoi? Voir: w3schools.com/jsref/jsref_escape.aspUtiliser
btoa
avecunescape
etencodeURIComponent
n'a pas fonctionné pour moi. Le remplacement de tous les caractères spéciaux par des entités XML / HTML, puis la conversion vers la représentation base64 était le seul moyen de résoudre ce problème pour moi. Un peu de code:la source
Blob
object pour gérer la conversion.Blob
peut gérer toutes les données binaires.Utilisez plutôt une bibliothèque
Nous n'avons pas à réinventer la roue. Utilisez simplement une bibliothèque pour économiser du temps et des maux de tête.
js-base64
https://github.com/dankogai/js-base64 est bon et je confirme qu'il prend très bien en charge l'Unicode.
la source
J'ai juste pensé que je devrais partager comment j'ai résolu le problème et pourquoi je pense que c'est la bonne solution (à condition que vous n'optimisez pas pour l'ancien navigateur).
Conversion de données en dataURL (
data: ...
)Permettre à l'utilisateur d'enregistrer des données
Outre la solution évidente - ouvrir une nouvelle fenêtre avec votre dataURL comme URL, vous pouvez faire deux autres choses.
1. Utilisez fileSaver.js
L'économiseur de fichiers peut créer une boîte de dialogue FileSave réelle avec un nom de fichier prédéfini. Il peut également revenir à l'approche dataURL normale.
2. Utilisation (expérimentale)
URL.createObjectURL
C'est idéal pour réutiliser des données encodées en base64. Il crée une URL courte pour votre dataURL:
N'oubliez pas d'utiliser l'URL avec le
blob
préfixe principal . J'ai utilisé àdocument.body
nouveau:Vous pouvez utiliser cette URL courte comme cible AJAX,
<script>
source ou<a>
emplacement href. Vous êtes cependant responsable de la destruction de l'URL:la source
En complément de la réponse de Stefan Steiger: (car cela n'a pas l'air agréable en tant que commentaire)
Extension du prototype de chaîne:
Usage:
REMARQUE:
Comme indiqué dans les commentaires, l'utilisation
unescape
n'est pas recommandée car elle pourrait être supprimée à l'avenir:la source
unescape
sera bientôt obsolète selon MDN developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…btoa () ne prend en charge que les caractères de String.fromCodePoint (0) à String.fromCodePoint (255). Pour les caractères Base64 avec un point de code 256 ou supérieur, vous devez les encoder / décoder avant et après.
Et sur ce point cela devient délicat ...
Chaque signe possible est organisé dans une table Unicode. La table Unicode est divisée en différents plans (langues, symboles mathématiques, etc.). Chaque signe dans un avion a un numéro de point de code unique. Théoriquement, le nombre peut devenir arbitrairement grand.
Un ordinateur stocke les données en octets (8 bits, hexadécimal 0x00 - 0xff, binaire 00000000 - 11111111, décimal 0 - 255). Cette plage est normalement utilisée pour enregistrer les caractères de base (plage Latin1).
Pour les caractères avec un point de code plus élevé, il existe 255 encodages différents. JavaScript utilise 16 bits par signe (UTF-16), la chaîne appelée DOMString. Unicode peut gérer des points de code jusqu'à 0x10fffff. Cela signifie qu'une méthode doit exister pour stocker plusieurs bits sur plusieurs cellules.
String.fromCodePoint(0x10000).length == 2
UTF-16 utilise des paires de substitution pour stocker 20 bits dans deux cellules 16 bits. Le premier substitut supérieur commence par 110110xxxxxxxxxx , le second inférieur par 110111xxxxxxxxxx . Unicode a réservé ses propres avions pour cela: https://unicode-table.com/de/#high-surrogates
Pour stocker des caractères en octets (plage Latin1), les procédures normalisées utilisent UTF-8 .
Désolé de le dire, mais je pense qu'il n'y a pas d'autre moyen d'implémenter cette fonction soi-même.
comment l'utiliser:
decodeBase64(encodeBase64("\u{1F604}"))
démo: https://jsfiddle.net/qrLadeb8/
la source
stringToUTF8
etutf8ToString
cependantJe viens de rencontrer ce problème moi-même.
Tout d'abord, modifiez légèrement votre code:
Ensuite, utilisez votre inspecteur Web préféré, mettez un point d'arrêt sur la ligne de code qui affecte this.loader.src, puis exécutez ce code:
En fonction de votre application, le remplacement des caractères hors plage peut ou non fonctionner, car vous allez modifier les données. Voir la note sur MDN sur les caractères unicode avec la méthode btoa:
https://developer.mozilla.org/en-US/docs/Web/API/window.btoa
la source