[GUÍA] 11 min read

[GUÍA] Cómo previsualizar imágenes codificadas en Base64 en el navegador

Cinco maneras probadas de mostrar imágenes codificadas en Base64 en la página — asignación directa a src, FileReader, canvas, conversión a blob y patrones específicos por framework. Incluye consejos de depuración.

April 2026 | javascript

// LA RESPUESTA EN 30 SEGUNDOS

Si tienes una cadena de imagen codificada en Base64 y solo quieres verla en la página, el camino más corto es asignarla como un URI data: a img.src. Tres líneas de JavaScript:

const img = new Image();
img.src = 'data:image/png;base64,' + base64String;
document.body.appendChild(img);

// If the string already starts with 'data:image/...;base64,'
// — just assign it directly without prepending anything:
img.src = base64StringWithDataUriPrefix;

// MÉTODO 1: img.src — EL ENFOQUE DIRECTO

Cada elemento <img> trata un URI de datos como una URL regular. Asigna el URI a src y el navegador maneja por ti la decodificación, la detección del formato y el renderizado.

Esto funciona con cualquier formato de imagen que el navegador soporte de forma nativa: PNG, JPEG, GIF (animado y estático), WebP, SVG, BMP, ICO. La cadena Base64 puede provenir de cualquier lugar — una respuesta de API, localStorage, un pegado del portapapeles o una fila de la base de datos.

El tipo MIME en el URI de datos importa para navegadores antiguos y algunos WebViews embebidos. Si solo tienes una carga útil Base64 cruda (sin prefijo data:) y no conoces el formato, puedes inspeccionar los bytes mágicos (ver Método 5) o usar por defecto image/png — la mayoría de los navegadores olfateará y se recuperará incluso si el tipo MIME es incorrecto.

// Plain HTML — no JavaScript needed if the string is static
<img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUg..." alt="preview">

// Dynamic JavaScript — load from a variable, fetch, or input field
function renderBase64Image(base64, mimeType = 'image/png', containerId = 'preview') {
  const container = document.getElementById(containerId);
  const img = new Image();

  img.onload = () => {
    container.innerHTML = '';
    container.appendChild(img);
  };

  img.onerror = () => {
    container.textContent = 'Invalid image data';
  };

  // Tolerate both raw Base64 and full data: URIs
  img.src = base64.startsWith('data:')
    ? base64
    : `data:${mimeType};base64,${base64}`;
}

renderBase64Image(myBase64String, 'image/jpeg');

// MÉTODO 2: FILEREADER PARA ARCHIVOS SUBIDOS POR EL USUARIO

Si el usuario sube una imagen mediante <input type="file">, no necesitas codificarla manualmente en Base64. FileReader.readAsDataURL() te entrega un URI de datos completo que puedes asignar directamente a img.src:

<input type="file" id="fileInput" accept="image/*">
<img id="preview" alt="">

<script>
document.getElementById('fileInput').addEventListener('change', (e) => {
  const file = e.target.files[0];
  if (!file) return;

  const reader = new FileReader();

  reader.onload = (event) => {
    // event.target.result is a complete data URI
    // e.g. 'data:image/png;base64,iVBORw0KGgo...'
    document.getElementById('preview').src = event.target.result;
  };

  reader.onerror = () => {
    console.error('FileReader failed:', reader.error);
  };

  reader.readAsDataURL(file);
});
</script>

// MÉTODO 3: CANVAS PARA IMÁGENES GENERADAS O MODIFICADAS

Cuando dibujas o procesas una imagen en un <canvas>, canvas.toDataURL() exporta el resultado como un URI de datos en una sola llamada. Útil para: capturas de pantalla de gráficos, almohadillas de firma, códigos QR, marcas de agua o cualquier cosa generada del lado del cliente que quieras mostrar o descargar como imagen.

// 1. Draw on canvas
const canvas = document.createElement('canvas');
canvas.width = 200;
canvas.height = 200;
const ctx = canvas.getContext('2d');
ctx.fillStyle = '#00FF41';
ctx.fillRect(0, 0, 200, 200);
ctx.fillStyle = '#000';
ctx.font = '20px monospace';
ctx.fillText('Hello, Base64!', 20, 100);

// 2. Export to data URI
const pngDataURL = canvas.toDataURL('image/png');
// pngDataURL === 'data:image/png;base64,iVBORw0KGgo...'

// 3. Display directly
const img = new Image();
img.src = pngDataURL;
document.body.appendChild(img);

// JPEG with quality control (0–1)
const jpegDataURL = canvas.toDataURL('image/jpeg', 0.85);

// WebP if supported
const webpDataURL = canvas.toDataURL('image/webp', 0.9);

// MÉTODO 4: FETCH + BLOB PARA CARGAS BASE64 REMOTAS

Si la carga útil Base64 es grande (más de 50 KB) o la mostrarás muchas veces, convertirla a una URL Blob mediante URL.createObjectURL() es más eficiente en memoria que mantener el URI de datos completo en el DOM. La URL blob es corta (blob:https://example.com/12345-abcde), puede revocarse cuando ya no se necesita y evita la sobrecarga del 33% de Base64 en cadenas del DOM.

// Convert a Base64 string to a Blob, then to a blob: URL
function base64ToBlobURL(base64, mimeType = 'image/png') {
  // Strip the data: prefix if present
  const payload = base64.includes(',') ? base64.split(',')[1] : base64;

  // Decode Base64 to binary string
  const binary = atob(payload);

  // Convert binary string to Uint8Array
  const bytes = new Uint8Array(binary.length);
  for (let i = 0; i < binary.length; i++) {
    bytes[i] = binary.charCodeAt(i);
  }

  // Wrap in a Blob and create an object URL
  const blob = new Blob([bytes], { type: mimeType });
  return URL.createObjectURL(blob);
}

// Usage
const blobURL = base64ToBlobURL(myBase64, 'image/jpeg');
const img = new Image();
img.src = blobURL;
document.body.appendChild(img);

// IMPORTANT: free the memory when you're done with the image
img.onload = () => URL.revokeObjectURL(blobURL);

// MÉTODO 5: AUTODETECCIÓN DE FORMATO POR BYTES MÁGICOS

Si recibes una carga útil Base64 cruda (sin prefijo data:) y no sabes si es PNG, JPEG, GIF o WebP, observa los primeros bytes decodificados — cada formato tiene una firma única.

function detectImageFormat(base64) {
  // Look at the first ~12 characters of the Base64 string
  const head = base64.replace(/^data:[^,]+,/, '').slice(0, 16);

  if (head.startsWith('iVBORw0KGgo')) return 'image/png';
  if (head.startsWith('/9j/'))         return 'image/jpeg';
  if (head.startsWith('R0lGOD'))       return 'image/gif';
  if (head.startsWith('UklGR'))        return 'image/webp';
  if (head.startsWith('PHN2Zy') ||
      head.startsWith('PD94bWw'))      return 'image/svg+xml';
  if (head.startsWith('Qk'))           return 'image/bmp';
  if (head.startsWith('AAABAA'))       return 'image/x-icon';

  return 'application/octet-stream'; // unknown
}

// Build a correct data URI even when the user only gave us the payload
function toDataURI(base64) {
  if (base64.startsWith('data:')) return base64; // already complete
  const mime = detectImageFormat(base64);
  return `data:${mime};base64,${base64}`;
}

// REACT — MOSTRAR IMÁGENES BASE64 EN COMPONENTES

En React, trata el URI de datos como cualquier otra prop de tipo cadena. Memoriza la conversión si la entrada cambia rara vez:

import { useMemo } from 'react';

function Base64Image({ base64, mimeType = 'image/png', alt }) {
  const src = useMemo(() => {
    if (!base64) return '';
    return base64.startsWith('data:')
      ? base64
      : `data:${mimeType};base64,${base64}`;
  }, [base64, mimeType]);

  if (!src) return <div>No image</div>;
  return <img src={src} alt={alt} loading="lazy" />;
}

// Usage
<Base64Image
  base64={apiResponse.avatar}
  mimeType="image/jpeg"
  alt="User avatar"
/>

// For large images, prefer blob URLs (Method 4) and useEffect for cleanup:
function LargeBase64Image({ base64 }) {
  const [blobURL, setBlobURL] = useState('');

  useEffect(() => {
    const url = base64ToBlobURL(base64, 'image/png');
    setBlobURL(url);
    return () => URL.revokeObjectURL(url); // cleanup on unmount
  }, [base64]);

  return blobURL ? <img src={blobURL} alt="" /> : null;
}

// VUE 3 — EJEMPLO CON COMPOSITION API

La misma idea, sintaxis de Vue:

<script setup>
import { computed } from 'vue';

const props = defineProps({
  base64: String,
  mimeType: { type: String, default: 'image/png' },
  alt: { type: String, default: '' }
});

const src = computed(() => {
  if (!props.base64) return '';
  return props.base64.startsWith('data:')
    ? props.base64
    : `data:${props.mimeType};base64,${props.base64}`;
});
</script>

<template>
  <img v-if="src" :src="src" :alt="alt" loading="lazy" />
  <div v-else>No image</div>
</template>

// SVELTE — DECLARACIÓN REACTIVA

<script>
  export let base64 = '';
  export let mimeType = 'image/png';
  export let alt = '';

  $: src = base64
    ? (base64.startsWith('data:') ? base64 : `data:${mimeType};base64,${base64}`)
    : '';
</script>

{#if src}
  <img {src} {alt} loading="lazy" />
{:else}
  <div>No image</div>
{/if}

// MANEJO DE ERRORES — QUÉ FALLA Y POR QUÉ

La imagen se carga como un marcador de ícono roto. La carga útil Base64 está truncada, contiene espacios en blanco a mitad de la cadena o usa caracteres URL-safe (-_) dentro de un URI de datos estándar. Elimina los espacios con str.replace(/\s+/g, ''); convierte de URL-safe a estándar con str.replace(/-/g, '+').replace(/_/g, '/'); y verifica que la longitud sea correcta (la longitud de Base64 debe ser múltiplo de 4 con el relleno = adecuado).

La imagen se renderiza pero con el formato incorrecto. El prefijo data:image/png;base64, dice PNG, pero los bytes reales son JPEG. El navegador olfatea los bytes mágicos y la renderiza correctamente de todos modos — pero algunos navegadores headless y WebViews embebidos no lo hacen. Usa el Método 5 para detectar el formato real a partir de los bytes.

La imagen es enorme en el DOM y la página se siente lenta. Una cadena Base64 de 1 MB en un componente de React se vuelve a renderizar en cada actualización de estado. Cambia a una URL blob: (Método 4) — es una cadena de 50 caracteres en el DOM independientemente del tamaño de la imagen.

La imagen funciona en Chrome pero no en Safari. Safari tiene valores predeterminados de CSP más estrictos y rechaza los URI data: en algunos contextos (<a download>, fetches de service workers). Prueba en Safari y recurre a una URL blob: si es necesario.

La cadena Base64 misma es inválida. A veces el 'Base64' que recibes está doblemente codificado, codificado en hexadecimal o simplemente corrupto. Pégalo en nuestro decodificador de Base64 a imagen primero para confirmar que es válido antes de depurar tu código.

// RENDIMIENTO: URI data: VS URL blob: — UN BENCHMARK RÁPIDO

Para un JPEG de 500 KB mostrado en <img>:

URI data: en src: cadena de 668 KB en el DOM (33% de sobrecarga de Base64). El navegador analiza el URI, decodifica Base64, decodifica JPEG. ~80 ms al primer pintado en una laptop de gama media.
URL blob: vía URL.createObjectURL: cadena de 56 caracteres en el DOM. El navegador obtiene el blob en memoria, decodifica JPEG. ~40 ms al primer pintado. ~50% de ahorro de memoria.

Para un ícono de 5 KB, la diferencia es invisible — ambos se renderizan en < 5 ms. Conclusión: por debajo de ~50 KB, usa el que sea más conveniente. Por encima de eso, prefiere URLs blob.

// PROBANDO TU VISTA PREVIA DE FORMA AISLADA

Si sospechas de un bug, aísla la cadena Base64 del código de tu aplicación primero. Tres verificaciones rápidas:

1. Pégala en nuestra herramienta en línea. Suelta la cadena en el conversor de Base64 a imagen. Si la imagen se renderiza correctamente allí, los datos están bien y el bug está en tu código. Si tampoco se renderiza allí, los datos están corruptos aguas arriba.

2. Ábrela como una URL en una pestaña nueva. Copia el URI de datos (incluido el prefijo data:image/png;base64,), pégalo en una nueva pestaña del navegador y presiona Enter. Los navegadores modernos mostrarán la imagen directamente. (Algunos bloquean data: en la barra de direcciones — usa la prueba en línea del paso 1 si es así.)

3. Verifica la longitud. Una cadena Base64 válida tiene una longitud divisible por 4 (después de eliminar los espacios en blanco). El relleno (=) cubre la diferencia: de 0 a 2 caracteres = al final. Si tu longitud no es divisible por 4, la cadena está truncada o extendida.

// Quick validation snippet
function looksLikeValidBase64(str) {
  const cleaned = str.replace(/^data:[^,]+,/, '').replace(/\s+/g, '');
  if (cleaned.length === 0) return false;
  if (cleaned.length % 4 !== 0) return false;
  if (!/^[A-Za-z0-9+/]+={0,2}$/.test(cleaned)) return false;
  return true;
}

// HOJA DE TRUCOS DE 30 SEGUNDOS

Lo más rápido: asigna el URI de datos a img.src. Listo.

Desde una subida de archivo: FileReader.readAsDataURL(file).

Desde un canvas: canvas.toDataURL('image/png').

Para imágenes grandes o repetidas: conviértelas a un blob y usa URL.createObjectURL(blob).

Formato desconocido: olfatea los bytes mágicos (iVBORw0KGgo = PNG, /9j/ = JPEG, etc.) antes de construir el URI de datos.

Depuración: pega primero en el conversor de Base64 a imagen — descarta si el problema son los datos.

Lecturas relacionadas: Entendiendo los URI de datos · Incrustación de imágenes en Base64 · Base64 en JavaScript: navegador y Node