W3docs

Imágenes en Canvas

Aprende a dibujar imágenes en un canvas HTML: obtén una fuente de imagen, usa las tres formas de drawImage(), gestiona CORS y evita el canvas contaminado.

Una de las características del elemento <canvas> es la posibilidad de utilizar imágenes. Estas pueden emplearse para distintos propósitos. Puedes usar imágenes externas en cualquier formato compatible con el navegador (por ejemplo, PNG, GIF o JPEG). Como fuente también puedes usar la imagen creada por otros elementos canvas.

Este capítulo se apoya en los conceptos básicos de la introducción a Canvas y el dibujo en Canvas. Aquí aprenderás cómo obtener una fuente de imagen, cómo usar las tres formas del método drawImage() y cómo evitar el problema del "canvas contaminado" al cargar imágenes desde otros dominios.

Importar imágenes en un canvas es un proceso en dos pasos:

  1. Obtener una referencia a otro elemento canvas o a un objeto HTMLImageElement como fuente.
  2. Dibujar la imagen en el canvas con la función drawImage().

Como fuente de imagen, la API canvas puede usar cualquiera de los siguientes tipos de datos:

Tipo de datoDescripción
HTMLImageElementSon imágenes creadas con el constructor Image() o cualquier elemento <img>.
SVGImageElementSon imágenes incrustadas con el elemento <image>.
HTMLVideoElementUn elemento HTML <video> como fuente de imagen toma el fotograma actual del vídeo y lo usa como imagen.
HTMLCanvasElementComo fuente de imagen, puedes usar otro elemento <canvas>.

Estos tipos en conjunto se denominan con el tipo CanvasImageSource.

Existen muchas formas de obtener imágenes para usar en un canvas.

Usar imágenes de la misma página

Puedes obtener una referencia a las imágenes de la misma página que el canvas con alguna de las siguientes opciones:

  • La colección document.images
  • El método document.getElementsByTagName()
  • El método document.getElementById() si conoces el ID de la imagen que deseas usar

Por ejemplo, para tomar un elemento <img> existente por su ID y dibujarlo una vez que la página haya cargado:

<img id="photo" src="myImage.png" alt="My image" />
<canvas id="exampleCanvas" width="240" height="225"></canvas>
<script>
  window.onload = function () {
    const canvas = document.getElementById("exampleCanvas");
    const ctx = canvas.getContext("2d");
    const img = document.getElementById("photo");
    ctx.drawImage(img, 0, 0);
  };
</script>

Como el elemento <img> ya está en el documento, el navegador suele haber terminado de cargarlo cuando se dispara window.onload, por lo que es seguro dibujarlo de inmediato.

Usar imágenes de otros dominios

Usando el elemento <img> con el atributo crossorigin="anonymous", puedes solicitar permiso para cargar una imagen desde otro dominio. Si el dominio anfitrión permite el acceso entre dominios mediante cabeceras CORS, puedes usar la imagen en tu canvas sin contaminarlo.

<img id="remote" src="https://example.com/photo.jpg" crossorigin="anonymous" alt="Remote image" />

Cuando estableces crossorigin="anonymous", el navegador envía la solicitud sin credenciales (cookies). La imagen solo se puede colocar en un canvas limpio si el servidor responde con la cabecera:

Access-Control-Allow-Origin: *

(o un valor que incluya tu origen). Si creas la imagen en JavaScript, establece la propiedad antes que el src:

const img = new Image();
img.crossOrigin = "anonymous";
img.onload = function () {
  ctx.drawImage(img, 0, 0);
};
img.src = "https://example.com/photo.jpg";

Nota Si dibujas una imagen de origen cruzado sin la configuración CORS adecuada, el canvas queda "contaminado". Un canvas contaminado bloquea el acceso a sus datos de píxeles por razones de seguridad: llamar a toDataURL(), toBlob() o getImageData() lanzará un SecurityError. La solución está en el servidor: debe enviar la cabecera Access-Control-Allow-Origin. No hay forma de leer píxeles de un canvas contaminado desde el lado del cliente.

Usar otros elementos canvas

Se puede acceder a otros elementos canvas usando los métodos document.getElementById() o document.getElementsByTagName().

Incrustar una imagen mediante data: URL

Las URL de datos permiten especificar una imagen como una cadena de caracteres codificada en Base64 directamente en el código. La ventaja de la URL de datos es que la imagen resultante está disponible de inmediato. También es posible integrar todo tu CSS, HTML, JavaScript e imágenes en un solo archivo.

Sin embargo, también existe una desventaja: la imagen no se almacena en caché, y la URL codificada puede ser demasiado larga para imágenes de gran tamaño.

Para usar una URL de datos, asígnala al src de una imagen y dibújala una vez que haya cargado:

const img = new Image();
img.onload = function () {
  ctx.drawImage(img, 0, 0);
};
img.src =
  "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mP8z8BQDwAEhQGAhKmMIQAAAABJRU5ErkJggg==";

La cadena después de base64, es la imagen codificada. Como forma parte del script, no se realiza ninguna solicitud de red adicional: la imagen está lista en cuanto se decodifica.

Crear una imagen desde cero

También puedes crear un nuevo objeto HTMLImageElement en tu script. Para ello, usa el constructor Image():

Crear una imagen desde cero

const img = new Image();
img.onload = function () {
  ctx.drawImage(img, 0, 0);
};
img.src = "myImage.png";

La imagen comienza a cargarse en el momento en que se establece src, y la carga es asíncrona. Si llamas a drawImage() antes de que la imagen haya terminado de cargar, no se dibuja nada. Para asegurarte de que drawImage() se ejecute solo cuando la imagen esté lista, adjunta el controlador de evento onload antes de establecer src.

La función drawImage()

Una vez que se dispone de una referencia a la imagen fuente, puedes usar el método drawImage(). Viene en tres formas, cada una con más parámetros que la anterior:

1. Solo posición

ctx.drawImage(image, dx, dy);

Dibuja la imagen completa en su tamaño natural, colocando su esquina superior izquierda en el punto (dx, dy) del canvas.

2. Posición y tamaño (escalado)

ctx.drawImage(image, dx, dy, dWidth, dHeight);

Dibuja la imagen completa, escalada para ajustarse a un recuadro de dWidth × dHeight píxeles cuya esquina superior izquierda está en (dx, dy).

3. Recorte (rectángulo fuente a rectángulo destino)

ctx.drawImage(image, sx, sy, sWidth, sHeight, dx, dy, dWidth, dHeight);

Toma un fragmento rectangular de la imagen fuente y lo dibuja en un rectángulo de destino en el canvas. Esta es la forma más flexible: se usa para sprite sheets, recorte y zoom.

Los parámetros se dividen en dos grupos:

ParámetroGrupoSignificado
sx, syFuenteEsquina superior izquierda del fragmento recortado de la imagen fuente.
sWidth, sHeightFuenteAncho y alto de dicho fragmento.
dx, dyDestinoDónde se coloca el fragmento en el canvas.
dWidth, dHeightDestinoTamaño con el que se dibuja el fragmento en el canvas (se escala si difiere de sWidth/sHeight).

Los valores s* (fuente) se miden en los píxeles de la imagen original; los valores d* (destino) se miden en píxeles del canvas. La forma básica, drawImage(image, dx, dy), es simplemente la primera de estas tres.

En el siguiente ejemplo, usamos el método document.getElementById() para obtener una referencia a la imagen y luego la función drawImage() para dibujarla.

Ejemplo de dibujo de una imagen con la función drawImage():

<!DOCTYPE html>
<html>
  <head>
    <title>Title of the document</title>
  </head>
  <body>
    <h2>Image</h2>
    <img id="photo" src="/uploads/media/default/0001/01/25acddb3da54207bc6beb5838f65f022feaa81d7.jpeg" alt="Aleq" width="200" height="185" />
    <h2>Image with canvas:</h2>
    <canvas id="exampleCanvas" width="240" height="225" style="border:2px solid #cccccc;">
      Your browser doesn't support the canvas tag.
    </canvas>
    <script>
      window.onload = function() {
        const canvas = document.getElementById("exampleCanvas");
        const ctx = canvas.getContext("2d");
        const img = document.getElementById("photo");
        ctx.drawImage(img, 20, 20);
      };
    </script>
  </body>
</html>
Peligro

Las imágenes SVG deben definir el ancho y el alto en el elemento raíz <svg>.

Usar fotogramas de un vídeo

También es posible usar fotogramas de un vídeo presentado por un elemento <video>, incluso cuando el vídeo no está visible. Por ejemplo, si tienes un elemento <video> con el ID "videoCanvas", haz lo siguiente:

Ejemplo de dibujo de un vídeo con canvas:

Canvas Images

<!DOCTYPE html>
<html>
  <head>
    <title>Title of the document</title>
  </head>
  <body>
    <h2>Video</h2>
    <video id="videoCanvas" controls width="350" autoplay>
      <source src="/build/videos/arcnet.io(7-sec).mp4" type="video/mp4" />
    </video>
    <h2>Canvas  draws the current video:</h2>
    <canvas id="exampleCanvas" width="310" height="190" style="border:1px solid #d3d3d3;">
      Your browser doesn't support the canvas tag.
    </canvas>
    <script>
      const v = document.getElementById("videoCanvas");
      const c = document.getElementById("exampleCanvas");
      const ctx = c.getContext("2d");
      let animId;
      function drawFrame() {
        ctx.drawImage(v, 5, 5, 300, 180);
        animId = requestAnimationFrame(drawFrame);
      }
      v.addEventListener("play", function() {
        animId = requestAnimationFrame(drawFrame);
      }, false);
      v.addEventListener("pause", function() {
        cancelAnimationFrame(animId);
      }, false);
      v.addEventListener("ended", function() {
        cancelAnimationFrame(animId);
      }, false);
    </script>
  </body>
</html>

Práctica

Práctica
Cuando creas una imagen en JavaScript para dibujarla en el canvas, ¿cuál es el orden correcto de pasos?
Cuando creas una imagen en JavaScript para dibujarla en el canvas, ¿cuál es el orden correcto de pasos?
Was this page helpful?