Recabamos en distintos sitios y así regalarte la respuesta a tu duda, en caso de alguna pregunta deja la inquietud y contestaremos con gusto, porque estamos para servirte.
Solución:
los atob
función decodificará un codificado en Base64 string en un nuevo string 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 un array de valores de bytes aplicando esto usando el .charCodeAt
método para cada carácter en el string.
const byteNumbers = new Array(byteCharacters.length);
for (let i = 0; i < byteCharacters.length; i++)
byteNumbers[i] = byteCharacters.charCodeAt(i);
Puedes convertir esto array de valores de byte en un byte con tipo real array al pasarlo al Uint8Array
constructor.
const byteArray = new Uint8Array(byteNumbers);
Esto, a su vez, se puede convertir en un BLOB envolviéndolo en un array y pasándoselo 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 el byteCharacters
en rebanadas más pequeñas, en lugar de todos a la vez. En mis pruebas aproximadas, 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 ni bibliotecas.
Requiere la nueva API de búsqueda. (¿Puedo usarlo?)
var url = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAYAAACNbyblAAAAHElEQVQI12P4//8/w38GIAXDIBKE0DHxgljNBAAO9TXL0Y4OHwAAAABJRU5ErkJggg=="
fetch(url)
.then(res => res.blob())
.then(console.log)
Con este método, también puede obtener fácilmente un ReadableStream, ArrayBuffer, texto y JSON.
(Para tu información, esto también funciona con node-fetch en Node)
Como una función:
const b64toBlob = (base64, type = 'application/octet-stream') =>
fetch(`data:$type;base64,$base64`).then(res => res.blob())
Hice una prueba de rendimiento simple hacia la versión de sincronización ES6 de Jeremy.
La versión de sincronización bloqueará la interfaz de usuario durante un tiempo. mantener el devtool abierto puede ralentizar el rendimiento de búsqueda
document.body.innerHTML += ''
// get some dummy gradient image
var img=function()var a=document.createElement("canvas"),b=a.getContext("2d"),c=b.createLinearGradient(0,0,1500,1500);a.width=a.height=3000;c.addColorStop(0,"red");c.addColorStop(1,"blue");b.fillStyle=c;b.fillRect(0,0,a.width,a.height);return a.toDataURL()();
async function perf()
const blob = await fetch(img).then(res => res.blob())
// turn it to a dataURI
const url = img
const b64Data = url.split(',')[1]
// Jeremy Banks solution
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;
// bench blocking method
let i = 500
console.time('blocking b64')
while (i--)
await b64toBlob(b64Data)
console.timeEnd('blocking b64')
// bench non blocking
i = 500
// so that the function is not reconstructed each time
const toBlob = res => res.blob()
console.time('fetch')
while (i--)
await fetch(url).then(toBlob)
console.timeEnd('fetch')
console.log('done')
perf()
Implementación optimizada (pero menos legible):
function base64toBlob(base64Data, contentType) '';
var sliceSize = 1024;
var byteCharacters = atob(base64Data);
var bytesLength = byteCharacters.length;
var slicesCount = Math.ceil(bytesLength / sliceSize);
var byteArrays = new Array(slicesCount);
for (var sliceIndex = 0; sliceIndex < slicesCount; ++sliceIndex)
var begin = sliceIndex * sliceSize;
var end = Math.min(begin + sliceSize, bytesLength);
var bytes = new Array(end - begin);
for (var offset = begin, i = 0; offset < end; ++i, ++offset)
bytes[i] = byteCharacters[offset].charCodeAt(0);
byteArrays[sliceIndex] = new Uint8Array(bytes);
return new Blob(byteArrays, type: contentType );
Finalizando este artículo puedes encontrar las críticas de otros administradores, tú también tienes la habilidad insertar el tuyo si lo crees conveniente.