the online not imagen funciona failed encoded decodificar decoded correctly como codificacion btoa atob javascript google-chrome

online - decodificar imagen base64 javascript



Error al ejecutar ''btoa'' en ''Ventana'': la cadena que se codifica contiene caracteres fuera del rango Latin1. (7)

Usa una biblioteca en su lugar

No tenemos que reinventar la rueda. Solo use una biblioteca para ahorrar tiempo y dolor de cabeza.

js-base64

https://github.com/dankogai/js-base64 es bueno y confirmo que soporta 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-''); // 小飼弾

El error en el título se arroja solo en Google Chrome, de acuerdo con mis pruebas. Estoy base64 codificando un gran archivo XML para que se pueda descargar:

this.loader.src = "data:application/x-forcedownload;base64,"+ btoa("<?xml version=/"1.0/" encoding=/"utf-8/"?>" +"<"+this.gamesave.tagName+">" +this.xml.firstChild.innerHTML +"</"+this.gamesave.tagName+">");

this.loader está oculto iframe.

Este error es realmente un gran cambio porque, normalmente, Google Chrome se btoa llamar a btoa . Mozilla Firefox no tiene problemas aquí, por lo que el problema está relacionado con el navegador. No estoy al tanto de ningún personaje extraño en el archivo. De hecho, creo que no hay personajes no ascii.

P: ¿Cómo encuentro los personajes problemáticos y los reemplazo para que Chrome deje de quejarse?

Intenté usar Downloadify para iniciar la descarga, pero no funciona. No es confiable y no arroja errores para permitir la depuración.


Como complemento a la respuesta de Stefan Steiger: (ya que no se ve bien como un comentario)

Extender el prototipo de cadena:

String.prototype.b64encode = function() { return btoa(unescape(encodeURIComponent(this))); }; String.prototype.b64decode = function() { return decodeURIComponent(escape(atob(this))); };

Uso:

var str = "äöüÄÖÜçéèñ"; var encoded = str.b64encode(); console.log( encoded.b64decode() );


Me encontré con este problema yo mismo.

Primero, modifique su código levemente:

var download = "<?xml version=/"1.0/" encoding=/"utf-8/"?>" +"<"+this.gamesave.tagName+">" +this.xml.firstChild.innerHTML +"</"+this.gamesave.tagName+">"; this.loader.src = "data:application/x-forcedownload;base64,"+ btoa(download);

Luego use su inspector web favorito, ponga un punto de interrupción en la línea de código que asigna this.loader.src, luego ejecute este código:

for (var i = 0; i < download.length; i++) { if (download[i].charCodeAt(0) > 255) { console.warn(''found character '' + download[i].charCodeAt(0) + '' "'' + download[i] + ''" at position '' + i); } }

Dependiendo de su aplicación, puede que los caracteres que están fuera de rango funcionen o no, ya que estará modificando 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


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 ese 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 hacer que esto funcione en el safari móvil, es posible que necesite quitar 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 nuevamente.
La verdad es que atob realmente no maneja cadenas UTF8, solo es 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 }


Solo pensé que debería compartir cómo realmente resolví el problema y por qué creo que esta es la solución correcta (siempre que no optimices para el viejo navegador).

Conversión de datos a dataURL ( data: ... )

var blob = new Blob( // I''m using page innerHTML as data // note that you can use the array // to concatenate many long strings EFFICIENTLY [document.body.innerHTML], // Mime type is important for data url {type : ''text/html''} ); // This FileReader works asynchronously, so it doesn''t lag // the web application var a = new FileReader(); a.onload = function(e) { // Capture result here console.log(e.target.result); }; a.readAsDataURL(blob);

Permitir al usuario guardar datos

Además de la solución obvia: al abrir una nueva ventana con su URL de datos como URL, puede hacer otras dos cosas.

1. Utiliza fileSaver.js

File Saver puede crear un cuadro de diálogo Guardar archivo con un nombre de archivo predefinido. También puede recurrir al enfoque normal de dataURL.

2. Utilice (experimental) URL.createObjectURL

Esto es ideal para reutilizar datos codificados en base64. Crea una URL corta para tu dataURL:

console.log(URL.createObjectURL(blob)); //Prints: blob:http://.com/7c18953f-f5f8-41d2-abf5-e9cbced9bc42

No olvides usar la URL que incluye el prefijo de blob inicial. Utilicé document.body nuevo:

Puede usar esta URL corta como destino AJAX, fuente <script> o <a> ubicación href. Usted es responsable de destruir la URL, aunque:

URL.revokeObjectURL(''blob:http://.com/7c18953f-f5f8-41d2-abf5-e9cbced9bc42'')


Usar btoa con btoa y encodeURIComponent no funcionó para mí. Reemplazar todos los caracteres especiales por entidades XML / HTML y luego convertir a la representación base64 fue la única forma de resolver este problema para mí. Cierto código:

base64 = btoa(str.replace(/[/u00A0-/u2666]/g, function(c) { return ''&#'' + c.charCodeAt(0) + '';''; }));


btoa () solo admite caracteres de String.fromCodePoint (0) hasta String.fromCodePoint (255). Para los caracteres Base64 con un punto de código 256 o superior, necesita codificarlos / descodificarlos antes y después.

Y en este punto se vuelve complicado ...

Todos los signos posibles se organizan en una tabla Unicode. La tabla Unicode está dividida en diferentes planos (idiomas, símbolos matemáticos, etc.). Cada signo en un avión tiene un número de código único. Teóricamente, el número puede llegar a ser arbitrariamente grande.

Una computadora almacena los datos en bytes (8 bit, hexadecimal 0x00 - 0xff, binario 00000000 - 11111111, decimal 0 - 255). Este rango normalmente se usa para guardar caracteres básicos (rango Latin1).

Para 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 de sustitución para almacenar 20bits en dos celdas de 16 bits. El primer sustituto más alto comienza con 110110xxxxxxxxxx , el segundo más bajo con 110111xxxxxxxxxx . Unicode reservó planos propios para esto: https://unicode-table.com/de/#high-surrogates

Para almacenar caracteres en bytes (rango Latin1) los procedimientos estandarizados usan UTF-8 .

Lamento decirlo, pero creo que no hay otra forma de implementar esta función.

function stringToUTF8(str) { let bytes = []; for(let character of str) { let code = character.codePointAt(0); if(code <= 127) { let byte1 = code; bytes.push(byte1); } else if(code <= 2047) { let byte1 = 0xC0 | (code >> 6); let byte2 = 0x80 | (code & 0x3F); bytes.push(byte1, byte2); } else if(code <= 65535) { let byte1 = 0xE0 | (code >> 12); let byte2 = 0x80 | ((code >> 6) & 0x3F); let byte3 = 0x80 | (code & 0x3F); bytes.push(byte1, byte2, byte3); } else if(code <= 2097151) { let byte1 = 0xF0 | (code >> 18); let byte2 = 0x80 | ((code >> 12) & 0x3F); let byte3 = 0x80 | ((code >> 6) & 0x3F); let byte4 = 0x80 | (code & 0x3F); bytes.push(byte1, byte2, byte3, byte4); } } return bytes; } function utf8ToString(bytes, fallback) { let valid = undefined; let codePoint = undefined; let codeBlocks = [0, 0, 0, 0]; let result = ""; for(let offset = 0; offset < bytes.length; offset++) { let byte = bytes[offset]; if((byte & 0x80) == 0x00) { codeBlocks[0] = byte & 0x7F; codePoint = codeBlocks[0]; } else if((byte & 0xE0) == 0xC0) { codeBlocks[0] = byte & 0x1F; byte = bytes[++offset]; if(offset >= bytes.length || (byte & 0xC0) != 0x80) { valid = false; break; } codeBlocks[1] = byte & 0x3F; codePoint = (codeBlocks[0] << 6) + codeBlocks[1]; } else if((byte & 0xF0) == 0xE0) { codeBlocks[0] = byte & 0xF; for(let blockIndex = 1; blockIndex <= 2; blockIndex++) { byte = bytes[++offset]; if(offset >= bytes.length || (byte & 0xC0) != 0x80) { valid = false; break; } codeBlocks[blockIndex] = byte & 0x3F; } if(valid === false) { break; } codePoint = (codeBlocks[0] << 12) + (codeBlocks[1] << 6) + codeBlocks[2]; } else if((byte & 0xF8) == 0xF0) { codeBlocks[0] = byte & 0x7; for(let blockIndex = 1; blockIndex <= 3; blockIndex++) { byte = bytes[++offset]; if(offset >= bytes.length || (byte & 0xC0) != 0x80) { valid = false; break; } codeBlocks[blockIndex] = byte & 0x3F; } if(valid === false) { break; } codePoint = (codeBlocks[0] << 18) + (codeBlocks[1] << 12) + (codeBlocks[2] << 6) + (codeBlocks[3]); } else { valid = false; break; } result += String.fromCodePoint(codePoint); } if(valid === false) { if(!fallback) { throw new TypeError("Malformed utf-8 encoding."); } result = ""; for(let offset = 0; offset != bytes.length; offset++) { result += String.fromCharCode(bytes[offset] & 0xFF); } } return result; } function decodeBase64(text, binary) { if(/[^0-9a-zA-Z/+///=]/.test(text)) { throw new TypeError("The string to be decoded contains characters outside of the valid base64 range."); } let codePointA = ''A''.codePointAt(0); let codePointZ = ''Z''.codePointAt(0); let codePointa = ''a''.codePointAt(0); let codePointz = ''z''.codePointAt(0); let codePointZero = ''0''.codePointAt(0); let codePointNine = ''9''.codePointAt(0); let codePointPlus = ''+''.codePointAt(0); let codePointSlash = ''/''.codePointAt(0); function getCodeFromKey(key) { let keyCode = key.codePointAt(0); if(keyCode >= codePointA && keyCode <= codePointZ) { return keyCode - codePointA; } else if(keyCode >= codePointa && keyCode <= codePointz) { return keyCode + 26 - codePointa; } else if(keyCode >= codePointZero && keyCode <= codePointNine) { return keyCode + 52 - codePointZero; } else if(keyCode == codePointPlus) { return 62; } else if(keyCode == codePointSlash) { return 63; } return undefined; } let codes = Array.from(text).map(character => getCodeFromKey(character)); let bytesLength = Math.ceil(codes.length / 4) * 3; if(codes[codes.length - 2] == undefined) { bytesLength = bytesLength - 2; } else if(codes[codes.length - 1] == undefined) { bytesLength--; } let bytes = new Uint8Array(bytesLength); for(let offset = 0, index = 0; offset < bytes.length;) { let code1 = codes[index++]; let code2 = codes[index++]; let code3 = codes[index++]; let code4 = codes[index++]; let byte1 = (code1 << 2) | (code2 >> 4); let byte2 = ((code2 & 0xf) << 4) | (code3 >> 2); let byte3 = ((code3 & 0x3) << 6) | code4; bytes[offset++] = byte1; bytes[offset++] = byte2; bytes[offset++] = byte3; } if(binary) { return bytes; } return utf8ToString(bytes, true); } function encodeBase64(bytes) { if(bytes === undefined || bytes === null) { return ""; } if(bytes instanceof Array) { bytes = bytes.filter(item => { return Number.isFinite(item) && item >= 0 && item <= 255; }); } if(!(bytes instanceof Uint8Array || bytes instanceof Uint8ClampedArray || bytes instanceof Array)) { if(typeof(bytes) == "string") { let str = bytes; bytes = Array.from(unescape(encodeURIComponent(str))).map(ch => ch.codePointAt(0)); } else { throw new TypeError("bytes must be of type Uint8Array or String."); } } let keys = [''A'', ''B'', ''C'', ''D'', ''E'', ''F'', ''G'', ''H'', ''I'', ''J'', ''K'', ''L'', ''M'', ''N'', ''O'', ''P'', ''Q'', ''R'', ''S'', ''T'', ''U'', ''V'', ''W'', ''X'', ''Y'', ''Z'', ''a'', ''b'', ''c'', ''d'', ''e'', ''f'', ''g'', ''h'', ''i'', ''j'', ''k'', ''l'', ''m'', ''n'', ''o'', ''p'', ''q'', ''r'', ''s'', ''t'', ''u'', ''v'', ''w'', ''x'', ''y'', ''z'', ''0'', ''1'', ''2'', ''3'', ''4'', ''5'', ''6'', ''7'', ''8'', ''9'', ''+'', ''/'']; let fillKey = ''=''; let byte1 = undefined, byte2 = undefined, byte3 = undefined; let sign1 = '' '', sign2 = '' '', sign3 = '' '', sign4 = '' ''; let result = ""; for(let index = 0; index < bytes.length; ) { let fillUpAt = false; byte1 = bytes[index++]; byte2 = bytes[index++]; byte3 = bytes[index++]; if(byte2 === undefined) { byte2 = 0; fillUpAt = 2; } if(byte3 === undefined) { byte3 = 0; if(!fillUpAt) { fillUpAt = 3; } } sign1 = keys[byte1 >> 2]; sign2 = keys[((byte1 & 0x3) << 4) + (byte2 >> 4)]; sign3 = keys[((byte2 & 0xf) << 2) + (byte3 >> 6)]; sign4 = keys[byte3 & 0x3f]; if(fillUpAt > 0) { if(fillUpAt <= 2) { sign3 = fillKey; } if(fillUpAt <= 3) { sign4 = fillKey; } } result += sign1 + sign2 + sign3 + sign4; if(fillUpAt) { break; } } return result; } let base64 = encodeBase64("/u{1F604}"); // unicode code point escapes for smiley let str = decodeBase64(base64); console.log("base64", base64); console.log("str", str); document.body.innerText = str;

cómo usarlo: decodeBase64(encodeBase64("/u{1F604}"))

demo: https://jsfiddle.net/qrLadeb8/