Chrome es compatible con createImageBitmap() en Chrome 50

Decodificar imágenes para usar con un lienzo es bastante común, ya sea para permitir que los usuarios personalicen un avatar, recorte una imagen o simplemente acerquen el zoom a una imagen. El problema con la decodificación de imágenes es que puede hacer un uso intensivo de la CPU y, a veces, puede generar bloqueos o verificaciones. A partir de Chrome 50 (y en Firefox 42 y versiones posteriores), ahora tienes otra opción: createImageBitmap(). Te permite decodificar una imagen en segundo plano y acceder a una nueva primitiva ImageBitmap, que puedes dibujar en un lienzo de la misma manera que lo harías con un elemento <img>, otro lienzo o un video.

Cómo dibujar BLOB con createImageBitmap()

Supongamos que descargas una imagen BLOB con fetch() (o XHR) y quieres dibujarla en un lienzo. Sin createImageBitmap(), tendrías que crear un elemento de imagen y una URL BLOB para obtener la imagen en un formato que puedas usar. Con él, obtienes una ruta mucho más directa a la pintura:

fetch(url)
    .then(response => response.blob())
    .then(blob => createImageBitmap(blob))
    .then(imageBitmap => ctx.drawImage(imageBitmap, 0, 0));

Este enfoque también funcionará con imágenes almacenadas como BLOB en IndexedDB, lo que hace que los BLOB tengan un formato intermedio conveniente. Al momento, Chrome 50 también admite el método .toBlob() en elementos de lienzo, lo que significa que puedes, por ejemplo, generar BLOB a partir de elementos de lienzo.

Cómo usar createImageBitmap() en trabajadores web

Una de las mejores funciones de createImageBitmap() es que también está disponible en Workers, lo que significa que ahora puedes decodificar imágenes donde quieras. Si tienes muchas imágenes para decodificar que consideras no esenciales, enviarías sus URLs a un trabajador web, que las descargará y decodificará a medida que el tiempo lo permita. Luego, las transferiría al subproceso principal para dibujarlas en un lienzo.

Flujo de datos con createImageBitmap y trabajadores web.

El código para hacer esto puede ser similar al siguiente:

// In the worker.
fetch(imageURL)
    .then(response => response.blob())
    .then(blob => createImageBitmap(blob))
    .then(imageBitmap => {
    // Transfer the imageBitmap back to main thread.
    self.postMessage({ imageBitmap }, [imageBitmap]);
    }, err => {
    self.postMessage({ err });
    });

// In the main thread.
worker.onmessage = (evt) => {
    if (evt.data.err)
    throw new Error(evt.data.err);

    canvasContext.drawImage(evt.data.imageBitmap, 0, 0);
}

Hoy en día, si llamas a createImageBitmap() en el subproceso principal, se realizará la decodificación exactamente. Sin embargo, está previsto que Chrome realice la decodificación automáticamente en otro subproceso, lo que ayudará a mantener inactiva la carga de trabajo del subproceso principal. Mientras tanto, sin embargo, debes tener cuidado con realizar la decodificación en el subproceso principal, ya que es un trabajo intensivo que podría bloquear otras tareas esenciales, como JavaScript, cálculos de estilo, diseño, pintura o composición.

Una biblioteca auxiliar

Para simplificar un poco la vida, creé una biblioteca auxiliar que controla la decodificación en un trabajador, devuelve la imagen decodificada al subproceso principal y la dibuja en un lienzo. Por supuesto que no dudes en aplicar ingeniería inversa al modelo y aplicarlo a tus propias apps. El principal beneficio es un mayor control, pero, como de costumbre, incluye más código, más para depurar y más casos extremos a considerar que usar un elemento <img>.

Si necesitas más control con la decodificación de imágenes, createImageBitmap() es tu nuevo mejor amigo. Pruébalo en Chrome 50 y cuéntanos cómo te va.