La atob
función decodificará una cadena codificada en Base64 en una nueva cadena con un carácter para cada byte de los datos binarios.
const byteCharacters = atob(b64Data);
El punto de código de cada carácter (charCode) será el valor del byte. Podemos crear una matriz de valores de bytes aplicando esto usando el .charCodeAt
método para cada carácter en la cadena.
const byteNumbers = new Array(byteCharacters.length);
for (let i = 0; i < byteCharacters.length; i++) {
byteNumbers[i] = byteCharacters.charCodeAt(i);
}
Puede convertir esta matriz de valores de bytes en una matriz de bytes tipificada real pasándola al Uint8Array
constructor.
const byteArray = new Uint8Array(byteNumbers);
Esto a su vez se puede convertir en un BLOB envolviéndolo en una matriz y pasándolo al Blob
constructor.
const blob = new Blob([byteArray], {type: contentType});
El código anterior funciona. Sin embargo, el rendimiento se puede mejorar un poco procesando los byteCharacters
segmentos más pequeños, en lugar de todos a la vez. En mi prueba aproximada, 512 bytes parece ser un buen tamaño de segmento. Esto nos da la siguiente función.
const b64toBlob = (b64Data, contentType='', sliceSize=512) => {
const byteCharacters = atob(b64Data);
const byteArrays = [];
for (let offset = 0; offset < byteCharacters.length; offset += sliceSize) {
const slice = byteCharacters.slice(offset, offset + sliceSize);
const byteNumbers = new Array(slice.length);
for (let i = 0; i < slice.length; i++) {
byteNumbers[i] = slice.charCodeAt(i);
}
const byteArray = new Uint8Array(byteNumbers);
byteArrays.push(byteArray);
}
const blob = new Blob(byteArrays, {type: contentType});
return blob;
}
const blob = b64toBlob(b64Data, contentType);
const blobUrl = URL.createObjectURL(blob);
window.location = blobUrl;
Ejemplo completo:
const b64toBlob = (b64Data, contentType='', sliceSize=512) => {
const byteCharacters = atob(b64Data);
const byteArrays = [];
for (let offset = 0; offset < byteCharacters.length; offset += sliceSize) {
const slice = byteCharacters.slice(offset, offset + sliceSize);
const byteNumbers = new Array(slice.length);
for (let i = 0; i < slice.length; i++) {
byteNumbers[i] = slice.charCodeAt(i);
}
const byteArray = new Uint8Array(byteNumbers);
byteArrays.push(byteArray);
}
const blob = new Blob(byteArrays, {type: contentType});
return blob;
}
const contentType = 'image/png';
const b64Data = 'iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAYAAACNbyblAAAAHElEQVQI12P4//8/w38GIAXDIBKE0DHxgljNBAAO9TXL0Y4OHwAAAABJRU5ErkJggg==';
const blob = b64toBlob(b64Data, contentType);
const blobUrl = URL.createObjectURL(blob);
const img = document.createElement('img');
img.src = blobUrl;
document.body.appendChild(img);
Aquí hay un método más mínimo sin dependencias o bibliotecas.
Requiere la nueva API de recuperación. ( ¿Puedo usarlo? )
Con este método también puede obtener fácilmente un ReadableStream, ArrayBuffer, texto y JSON.
Como una función:
Hice una prueba de rendimiento simple para la versión de sincronización ES6 de Jeremy.
La versión de sincronización bloqueará la interfaz de usuario por un tiempo. mantener abierto el devtool puede ralentizar el rendimiento de recuperación
Mostrar fragmento de código
fuente
createObjectURL
en lugar dereadAsDataURL
es mucho mejor, por ejemplo. Y si sube archivos usando ajax, elija enFormData
lugar deJSON
, o use encanvas.toBlob
lugar detoDataURL
await (await fetch(imageDataURL)).blob()
await fetch(url).then(r=>r.blob())
es clasificadorAccess is denied.
error. Supongo quefetch
expone blob bajo blob url, de la misma maneraURL.createObjectUrl
, que no funcionará en ie11. referencia . ¿Quizás haya alguna solución alternativa para usar fetch con IE11? Se ve mucho mejor que otras soluciones de sincronización :)Implementación optimizada (pero menos legible):
fuente
Para todo el soporte del navegador, especialmente en Android, quizás pueda agregar esto:
fuente
Para los datos de imagen, me resulta más fácil de usar
canvas.toBlob
(asíncrono)fuente
image/jpg
de la cadena base64 y luego pasarlo como un segundo parámetro a latoBlob
función para que el resultado sea del mismo tipo. Aparte de eso, creo que esto es perfecto: ahorra el 30% del tráfico y el espacio en disco en el servidor (en comparación con base64) y funciona bien incluso con PNG transparente.Vea este ejemplo: https://jsfiddle.net/pqhdce2L/
fuente
Noté que Internet Explorer 11 se vuelve increíblemente lento al cortar los datos como sugirió Jeremy. Esto es cierto para Chrome, pero Internet Explorer parece tener un problema al pasar los datos divididos al Blob-Constructor. En mi máquina, pasar 5 MB de datos hace que Internet Explorer falle y el consumo de memoria se está yendo por las nubes. Chrome crea la burbuja en poco tiempo.
Ejecute este código para una comparación:
Así que decidí incluir ambos métodos descritos por Jeremy en una función. Los créditos van a él por esto.
fuente
Para todos los amantes de copiar y pegar como yo, aquí hay una función de descarga que funciona en Chrome, Firefox y Edge:
fuente
createObjectURL
no acepta un segundo argumento ...Si puede soportar agregar una dependencia a su proyecto, está el excelente
blob-util
paquete npm que proporciona unabase64StringToBlob
función práctica . Una vez agregado a tupackage.json
puedes usarlo así:fuente
Estoy publicando una forma más declarativa de sincronización de conversión de Base64. Si bien la sincronización asíncrona
fetch().blob()
es muy ordenada y me gusta mucho esta solución, no funciona en Internet Explorer 11 (y probablemente Edge, no lo he probado), incluso con el polyfill, mira mi comentario a Endless ' Publicar para más detalles.Prima
Si desea imprimirlo, puede hacer algo como:
Bonus x 2: abrir un archivo BLOB en una nueva pestaña para Internet Explorer 11
Si puede hacer un preprocesamiento de la cadena Base64 en el servidor, puede exponerla bajo alguna URL y usar el enlace en
printJS
:)fuente
El siguiente es mi código TypeScript que se puede convertir fácilmente en JavaScript y puede usar
fuente
Typescript code
código solo tiene un tipo SINGLE y ese tipo esany
. ¿Por qué molestarse?El método con fetch es la mejor solución, pero si alguien necesita usar un método sin fetch, aquí está, ya que los mencionados anteriormente no funcionaron para mí:
fuente