javascript

Convertir HTML a imagen con html2canvas – Tomar screenshot de página web

En este post voy a explicar y a dar algunos ejemplos para convertir el contenido de una página web a una imagen, es decir, tomarle una “captura de pantalla” a la página web usando únicamente JavaScript del lado del cliente y la maravillosa librería de html2canvas.

Voy a mostrar cómo adjuntar el elemento canvas al documento, descargar la imagen, ignorar algunos elementos al tomar la captura de pantalla, respetar los estilos CSS y poner el resultado sobre un canvas existente.

HTML convertido a imagen con html2canvas

La imagen anterior fue generada por esta librería, respetando estilos de la tabla, imágenes, colores, fuentes y más.

El funcionamiento de esta librería es sencillo: lee todo el DOM, es decir, todo el documento HTML y construye una representación del mismo en un elemento canvas, leyendo los estilos y formas que tiene. Los resultados, si bien no son siempre perfectos, son bastante aceptables.

Citando al autor:

En otras palabras, no toma realmente una captura de pantalla de la página, sino que construye una representación de la misma en función de las propiedades que lee del DOM.

Después de tener el elemento canvas podemos adjuntarlo a la página web o convertirlo a imagen.

Nota: todos los ejemplos que expondré puedes probarlos aquí, y el código completo de todos y cada uno están en mi GitHub. Tal vez en ocasiones me salte algún fragmento de código, pero puedes revisar el repositorio y ahí estará todo lo necesario.

Incluir librería

Incluye la librería de html2canvas como un script normal. Puedes descargarlo por tu cuenta, en la página oficial hay dos enlaces, uno a la versión normal y otro a la minificada, la normal es para que analices el código y la minificada lista para ser usada en producción.

También puedes incluirla desde jsdelivr como lo hago en los ejemplos:

<!--
    Cargar el script de html2canvas, podría ser desde un servidor
    propio o como yo lo hago: desde jsdelivr
  -->
<script type="text/javascript" src="https://cdn.jsdelivr.net/npm/html2canvas@1.0.0-rc.1/dist/html2canvas.min.js"></script>

Al final todo queda en el tipo de aplicación que hagas.

Capturas de pantalla con JavaScript: primer vistazo

Veamos un primer ejemplo. Para capturar la página web llamamos a la función html2canvas pasándole un elemento HTML.

Este elemento puede ser document.body o cualquier otro obtenido, por ejemplo, con querySelector.

/**
 * Ejemplo 1 de html2canvas para convertir el HTML de una web
 * a un elemento canvas y adjuntarlo al contenido actual
 * 
 * @author parzibyte
 *///Definimos el botón para escuchar su click, y también el contenedor del canvas
const $boton = document.querySelector("#btnCapturar"), // El botón que desencadena
  $objetivo = document.querySelector("#contenedor"), // A qué le tomamos la foto
  $contenedorCanvas = document.querySelector("#contenedorCanvas"); // En dónde ponemos el elemento canvas

// Agregar el listener al botón
$boton.addEventListener("click", () => {
  html2canvas($objetivo) // Llamar a html2canvas y pasarle el elemento
    .then(canvas => {
      // Cuando se resuelva la promesa traerá el canvas
      $contenedorCanvas.appendChild(canvas); // Lo agregamos como hijo del div
    });
});
<!DOCTYPE html>
<html>

<head>
 <meta charset="utf-8">
 <meta name="viewport" content="width=device-width">
 <title>Tomar captura de página web</title>
</head>

<body>
 <!--
    En este caso le "tomamos" la foto al div. Podría ser a un div o 
    a cualquier elemento HTML
  -->
 <div id="contenedor">
  <h1>Tomar captura de pantalla con html2canvas</h1>
  <a href="//parzibyte.me/blog" target="_blank">By Parzibyte</a>
  <p>Estamos probando la conversión de HTML a una imagen con html2canvas</p>
  <img style="max-width: 100%;" src="cosmos-4112660_1280.jpg">
 </div>
  <!--
    El botón no aparece porque está fuera del div
  -->
  
 <button id="btnCapturar">Tomar captura</button>
  <!--
    En este elemento vamos a poner al canvas que será generado.
  -->
  <div id="contenedorCanvas" style="border: 1px solid red;">
  </div>
  <!--
    Cargar el script de html2canvas, podría ser desde un servidor
    propio o como yo lo hago: desde jsdelivr
  -->
    <script type="text/javascript" src="https://cdn.jsdelivr.net/npm/html2canvas@1.0.0-rc.1/dist/html2canvas.min.js"></script> 

    <!--
      Después de eso, cargar el script que contiene nuestra lógica
    -->
    <script src="script.js"></script>
  </body>
</html>

html2canvas devolverá una promesa que, al resolverse, traerá un elemento canvas. Ese elemento podemos montarlo en el documento o convertirlo a imagen.

Puedes probar el ejemplo aquí.

Tomar captura respetando estilos CSS

La librería soporta muy bien los estilos del documento. En el siguiente ejemplo uso los estilos de Bulma CSS y agrego una notificación y una tabla.

<!DOCTYPE html>
<html>

<head>
 <meta charset="utf-8">
 <meta name="viewport" content="width=device-width">
 <title>Tomar captura de página web</title>
 <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/bulma/0.7.4/css/bulma.min.css" />
</head>

<body>
 <!--
    En este caso le "tomamos" la foto al div. Podría ser a un div o 
    a cualquier elemento HTML
  -->
 <div id="contenedor">
  <h1 class="is-size-1">Tomar captura de pantalla con html2canvas</h1>
  <a href="//parzibyte.me/blog" target="_blank">By Parzibyte</a>
  <div class="notification is-primary">
   <p>Estamos probando la conversión de HTML a una imagen con html2canvas</p>
  </div>
  <table class="table is-bordered">
   <thead>
    <tr>
     <th>Nombre</th>
     <th>Versión</th>
    </tr>
   </thead>
   <tbody>
    <tr>
     <td>KitKat</td>
     <td>4.4</td>
    </tr>
    <tr>
     <td>Lollipop</td>
     <td>5</td>
    </tr>
    <tr>
     <td>Marshmallow</td>
     <td>6</td>
    </tr>
    <tr>
     <td>Nougat</td>
     <td>7</td>
    </tr>
    <tr>
     <td>Oreo</td>
     <td>8</td>
    </tr>
    <tr>
     <td>Pie</td>
     <td>9</td>
    </tr>
   </tbody>
  </table>
  <img style="max-width: 100%;" src="cosmos-4112660_1280.jpg">
 </div>
  <!--
    El botón no aparece porque está fuera del div
  -->
  
 <button id="btnCapturar">Tomar captura</button>
  <!--
    En este elemento vamos a poner al canvas que será generado.
  -->
  <div id="contenedorCanvas" style="border: 1px solid red;">
  </div>
  <!--
    Cargar el script de html2canvas, podría ser desde un servidor
    propio o como yo lo hago: desde jsdelivr
  -->
    <script type="text/javascript" src="https://cdn.jsdelivr.net/npm/html2canvas@1.0.0-rc.1/dist/html2canvas.min.js"></script> 

    <!--
      Después de eso, cargar el script que contiene nuestra lógica
    -->
    <script src="script.js"></script>
  </body>
</html>

Puedes probarlo aquí.

Capturar todo el cuerpo

En los ejemplos anteriores capturamos un div, no todo el cuerpo. Si queremos capturar todo el cuerpo simplemente pasamos document.body a html2canvas.

/**
 * Ejemplo 3 de html2canvas para convertir el HTML de una web
 * a un elemento canvas - Capturar todo el cuerpo del HTML, no solo un div
 * 
 * @author parzibyte
 *///Definimos el botón para escuchar su click, y también el contenedor del canvas
const $boton = document.querySelector("#btnCapturar"), // El botón que desencadena
  $objetivo = document.body, // A qué le tomamos la foto
  $contenedorCanvas = document.querySelector("#contenedorCanvas"); // En dónde ponemos el elemento canvas

// Agregar el listener al botón
$boton.addEventListener("click", () => {
  html2canvas($objetivo) // Llamar a html2canvas y pasarle el elemento
    .then(canvas => {
      // Cuando se resuelva la promesa traerá el canvas
      $contenedorCanvas.appendChild(canvas); // Lo agregamos como hijo del div
    });
});

Pruébalo aquí.

Si quieres ignorar algunos elementos más tarde veremos cómo hcaerlo.

Descargar imagen generada

Si no te interesa el elemento canvas y quieres una imagen PNG entonces hay que aplicar algunos trucos para convertir el canvas a imagen, lo cual ya expliqué anteriormente.

El código es el siguiente:

/**
 * Ejemplo 4 de html2canvas para convertir el HTML de una web
 * a un elemento canvas - Descargar la captura como imagen PNG
 * 
 * @author parzibyte
 *///Definimos el botón para escuchar su click
const $boton = document.querySelector("#btnCapturar"), // El botón que desencadena
  $objetivo = document.body; // A qué le tomamos la fotocanvas
// Nota: no necesitamos contenedor, pues vamos a descargarla

// Agregar el listener al botón
$boton.addEventListener("click", () => {
  html2canvas($objetivo) // Llamar a html2canvas y pasarle el elemento
    .then(canvas => {
      // Cuando se resuelva la promesa traerá el canvas
      // Crear un elemento <a>
      let enlace = document.createElement('a');
      enlace.download = "Captura de página web - Parzibyte.me.png";
      // Convertir la imagen a Base64
      enlace.href = canvas.toDataURL();
      // Hacer click en él
      enlace.click();
    });
});

De esta manera no podemos el canvas en el cuerpo ni en un contenedor, sino que simplemente descargamos la imagen y la guardamos como PNG.

Prueba el ejemplo de descarga de imagen aquí.

Ignorar algunos elementos al tomar la captura

La librería html2canvas permite ignorar algunos elementos a través de una función que se especifica en las opciones.

Esta función recibe el argumento del elemento HTML que está a punto de renderizarse. Si regresamos true, el elemento se va a ignorar. Si no, el elemento se renderiza.

En el ejemplo se ignoran los elementos de imagen y encabezados, pero podríamos hacer una selección más precisa por clases, ids, etcétera; ya que tenemos al elemento completo.

/**
 * Ejemplo 5 de html2canvas para convertir el HTML de una web
 * a un elemento canvas - Ignorar algunos elementos al tomar la captura
 * 
 * Nota: también puedes agregar el atributo data-html2canvas-ignore al elemento en cuestión
 * 
 * @author parzibyte
 *///Definimos el botón para escuchar su click, y también el contenedor del canvas
const $boton = document.querySelector("#btnCapturar"), // El botón que desencadena
  $objetivo = document.querySelector("#contenedor"), // A qué le tomamos la foto
  $contenedorCanvas = document.querySelector("#contenedorCanvas"); // En dónde ponemos el elemento canvas

// Agregar el listener al botón
$boton.addEventListener("click", () => {
  const opciones = {
    ignoreElements: elemento => {
      // Una función que ignora elementos. Regresa true si quieres que
      // el elemento se ignore, y false en caso contrario
      const tipo = elemento.nodeName.toLowerCase();
      // Si es imagen o encabezado h1, ignorar
      if (tipo === "img" || tipo === "h1") {
        return true;
      }
      // Para todo lo demás, no ignorar
      return false
    }
  };
  html2canvas($objetivo, opciones) // Llamar a html2canvas y pasarle el elemento
    .then(canvas => {
      // Cuando se resuelva la promesa traerá el canvas
      $contenedorCanvas.appendChild(canvas); // Lo agregamos como hijo del div
    });
});

Por cierto, la documentación dice que si ponemos el atributo data-html2canvas-ignore a un elemento, el mismo será ignorado.

Prueba el código aquí.

Colocar captura de pantalla en canvas existente

Si ya tenemos un canvas definido, podemos poner la captura de pantalla tomada con html2canvas sobre el mismo, usando las opciones.

Específicamente indicamos la clave “canvas” en las opciones, el valor debe ser un elemento HTML de canvas.

/**
 * Ejemplo 6 de html2canvas para convertir el HTML de una web
 * a un elemento canvas - Poner resultado sobre canvas existente
 * 
 * @author parzibyte
 *///Definimos el botón para escuchar su click, y también el contenedor del canvas
const $boton = document.querySelector("#btnCapturar"), // El botón que desencadena
  $objetivo = document.querySelector("#contenedor"), // A qué le tomamos la foto
  $canvas = document.querySelector("#canvas"); // En dónde ponemos el resultado (debe ser un canvas)

// Agregar el listener al botón
$boton.addEventListener("click", () => {
  const opciones = {
    canvas: $canvas, // Indicar el elemento HTML
  };
  html2canvas($objetivo, opciones) // Llamar a html2canvas y pasarle el elemento con las opciones
    .then(canvas => {
      // Aquí ha terminado y ha puesto resultado en el canvas que le indicamos
    });
});

Pruébalo aquí.

Conclusión

Solo resta decir que esta librería es muy poderosa y útil en varios aspectos. Te dejo un enlace a la documentación oficial para las opciones, en donde puedes ver cómo cambiar el color de fondo, cortar el canvas, etcétera.

Muy pronto traeré algunos otros ejemplos de esta librería, te invito a suscribirte al blog y seguirme en todas las redes.

Estoy aquí para ayudarte 🤝💻


Estoy aquí para ayudarte en todo lo que necesites. Si requieres alguna modificación en lo presentado en este post, deseas asistencia con tu tarea, proyecto o precisas desarrollar un software a medida, no dudes en contactarme. Estoy comprometido a brindarte el apoyo necesario para que logres tus objetivos. Mi correo es parzibyte(arroba)gmail.com, estoy como@parzibyte en Telegram o en mi página de contacto

No te pierdas ninguno de mis posts 🚀🔔

Suscríbete a mi canal de Telegram para recibir una notificación cuando escriba un nuevo tutorial de programación.
parzibyte

Programador freelancer listo para trabajar contigo. Aplicaciones web, móviles y de escritorio. PHP, Java, Go, Python, JavaScript, Kotlin y más :) https://parzibyte.me/blog/software-creado-por-parzibyte/

Ver comentarios

  • Hola, muchas gracias. Me puedes ayudar para lograr que en lugar de ponerla en contenedor y descargarla, se pueda agregar un botón para enviar por whatsapp? Gracias.

    • Por supuesto, estaré encantado de ayudarle más a fondo. Ofrezco servicios de consultoría personalizados para resolver problemas específicos. Si está interesado, envíeme un mensaje a https://parzibyte.me/#contacto y podemos conversar sobre cómo puedo ayudarle.

  • hace poco que estoy aprendiendo programación web
    acabo de usar lo del ejemplo 4 en un pequeño proyecto

    gracias

  • Estoy intentando hacer funcionar html2canvas para guardar un div en una imagen y no funciona, lo probe en diferentes navegadores y no hace nada.
    No me arroja ningun error tampoco al presionar el boton de tomar captura. no me hace nada.
    Lo unico que se me ocurre es que le falte alguna libreria js.
    Podrian ayudarme facilitandomelas o de donde las estan usando?

  • lindo post, el tema es que me esta poniendo muy nervioso el tema del cors, ya que el todataurl no funciona con referencias cruzadas , tengo entendido que se pueden usr proxys pero la verdad que no pude lograrlo

    • Me da gusto que haya funcionado. Te invito a seguirme en mis redes sociales para estar al tanto de mi contenido.
      Saludos :)

  • Hola, muchísimas gracias por le tutorial, me valió bastante como ayuda.
    Tengo una pregunta, el .png generado, ¿podemos usarlo para guardarla en una ruta especifica del servidor? De ser así, ¿Cómo sería?
    Muchas gracias de antemano.

Entradas recientes

Creador de credenciales web – Aplicación gratuita

Hoy te voy a presentar un creador de credenciales que acabo de programar y que…

1 semana hace

Desplegar PWA creada con Vue 3, Vite y SQLite3 en Apache

Ya te enseñé cómo convertir una aplicación web de Vue 3 en una PWA. Al…

2 semanas hace

Arquitectura para wasm con Go, Vue 3, Pinia y Vite

En este artículo voy a documentar la arquitectura que yo utilizo al trabajar con WebAssembly…

2 semanas hace

Vue 3 y Vite: crear PWA (Progressive Web App)

En un artículo anterior te enseñé a crear un PWA. Al final, cualquier aplicación que…

2 semanas hace

Errores de Comlink y algunas soluciones

Al usar Comlink para trabajar con los workers usando JavaScript me han aparecido algunos errores…

2 semanas hace

Esperar promesa para inicializar Store de Pinia con Vue 3

En este artículo te voy a enseñar cómo usar un "top level await" esperando a…

2 semanas hace

Esta web usa cookies.