Saltar al contenido

Creando un BLOB desde un Base64 string en JavaScript

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.

¡Haz clic para puntuar esta entrada!
(Votos: 0 Promedio: 0)



Utiliza Nuestro Buscador

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *