Если у вас UTF8, используйте это (на самом деле работает с исходным кодом SVG), например:
btoa(unescape(encodeURIComponent(str)))
пример:
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;
Если вам нужно декодировать этот base64, используйте это:
var str2 = decodeURIComponent(escape(window.atob(b64)));
console.log(str2);
Пример:
var str = "äöüÄÖÜçéèñ";
var b64 = window.btoa(unescape(encodeURIComponent(str)))
console.log(b64);
var str2 = decodeURIComponent(escape(window.atob(b64)));
console.log(str2);
Примечание: если вам нужно заставить это работать в mobile-safari, вам может потребоваться удалить все пробелы из данных base64 ...
function b64_to_utf8( str ) {
str = str.replace(/\s/g, '');
return decodeURIComponent(escape(window.atob( str )));
}
Обновление 2017 г.
Эта проблема снова меня беспокоит.
Простая правда в том, что atob на самом деле не обрабатывает строки UTF8 - это только ASCII.
Кроме того, я бы не стал использовать раздутое ПО вроде js-base64.
Но у webtoolkit есть небольшая, красивая и очень удобная в обслуживании реализация:
/**
*
* 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
Для любого символа, равного или меньше 127 (шестнадцатеричный 0x7F), представление UTF-8 составляет один байт. Это всего лишь младшие 7 бит полного значения Unicode. Это также то же самое, что и значение ASCII.
Для символов, равных или меньше 2047 (шестнадцатеричный 0x07FF), представление UTF-8 распространяется на два байта. В первом байте будут установлены два старших бита, а в третьем будут сброшены (то есть от 0xC2 до 0xDF). Во втором байте будет установлен верхний бит, а второй бит будет очищен (т.е. от 0x80 до 0xBF).
Для всех символов, равных или больше 2048, но меньше 65535 (0xFFFF), представление UTF-8 распространяется на три байта.
escape
преобразует строку в строку, содержащую только допустимые символы URL. Это предотвращает ошибки.escape
иunescape
были объявлены устаревшими в JavaScript 1.5, и вместо них следует использоватьencodeURIComponent
илиdecodeURIComponent
, соответственно. Вы одновременно используете устаревшие и новые функции. Зачем? См .: w3schools.com/jsref/jsref_escape.aspИспользование
btoa
withunescape
иencodeURIComponent
не помогло мне. Замена всех специальных символов сущностями XML / HTML и последующее преобразование в представление base64 было для меня единственным способом решить эту проблему. Некоторый код:источник
Blob
объект для обработки преобразования.Blob
может обрабатывать любые двоичные данные.Вместо этого используйте библиотеку
Нам не нужно изобретать велосипед. Просто используйте библиотеку, чтобы сэкономить время и избавиться от головной боли.
JS-base64
https://github.com/dankogai/js-base64 - это хорошо, и я подтверждаю, что он очень хорошо поддерживает юникод.
источник
Я просто подумал, что должен рассказать, как я на самом деле решил проблему и почему считаю это правильным решением (при условии, что вы не оптимизируете его для старого браузера).
Преобразование данных в dataURL (
data: ...
)Разрешение пользователю сохранять данные
Помимо очевидного решения - открытия нового окна с вашим dataURL в качестве URL-адреса, вы можете сделать еще две вещи.
1. Используйте fileSaver.js
Хранитель файлов может создать фактический диалог сохранения файла с предопределенным именем файла. Он также может вернуться к обычному подходу dataURL.
2. Использование (экспериментальное)
URL.createObjectURL
Это отлично подходит для повторного использования данных в кодировке base64. Он создает короткий URL-адрес для вашего dataURL:
Не забудьте использовать URL-адрес, включая начальный
blob
префикс. Яdocument.body
снова использовал :Вы можете использовать этот короткий URL-адрес в качестве цели AJAX,
<script>
источника или<a>
местоположения href. Однако вы несете ответственность за уничтожение URL:источник
В качестве дополнения к ответу Стефана Штайгера: (поскольку это не выглядит красиво в качестве комментария)
Расширение прототипа String:
Использование:
НОТА:
Как указано в комментариях, использование
unescape
не рекомендуется, так как оно может быть удалено в будущем:источник
unescape
скоро будет устаревшим согласно MDN developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…btoa () поддерживает только символы от String.fromCodePoint (0) до String.fromCodePoint (255). Для символов Base64 с кодовой точкой 256 или выше вам необходимо кодировать / декодировать их до и после.
И тут становится сложно ...
Все возможные знаки расположены в таблице Unicode. Таблица Unicode разделена на разные плоскости (языки, математические символы и так далее ...). Каждый знак в самолете имеет уникальный номер кодовой точки. Теоретически количество может стать сколь угодно большим.
Компьютер хранит данные в байтах (8 бит, шестнадцатеричный 0x00 - 0xff, двоичный 00000000 - 11111111, десятичный 0-255). Этот диапазон обычно используется для сохранения основных символов (диапазон Latin1).
Для символов с более высоким кодом существуют 255 различных кодировок. В JavaScript используется 16 бит на знак (UTF-16), строка называется DOMString. Unicode может обрабатывать кодовые точки до 0x10fffff. Это означает, что должен существовать метод для хранения нескольких бит на расстоянии нескольких ячеек.
String.fromCodePoint(0x10000).length == 2
UTF-16 использует суррогатные пары для хранения 20 бит в двух 16-битных ячейках. Первый более высокий суррогат начинается с 110110xxxxxxxxxx , младший второй - с 110111xxxxxxxxxx . Unicode зарезервировал для этого собственные самолеты: https://unicode-table.com/de/#high-surrogates
Для хранения символов в байтах (диапазон Latin1) стандартные процедуры используют UTF-8 .
Извините за это, но я думаю, что другого способа реализовать эту функцию самостоятельно нет.
как это использовать:
decodeBase64(encodeBase64("\u{1F604}"))
демо: https://jsfiddle.net/qrLadeb8/
источник
stringToUTF8
иutf8ToString
хотяЯ сам столкнулся с этой проблемой.
Во-первых, немного измените свой код:
Затем используйте свой любимый веб-инспектор, установите точку останова в строке кода, которая назначает this.loader.src, а затем выполните этот код:
В зависимости от вашего приложения замена символов, выходящих за пределы допустимого диапазона, может работать, а может и не работать, поскольку вы будете изменять данные. См. Примечание к MDN о символах Юникода с методом btoa:
https://developer.mozilla.org/en-US/docs/Web/API/window.btoa
источник