Chrome est compatible avec createImageBitmap() dans Chrome 50

Le décodage d'images à utiliser avec un canevas est assez courant, que ce soit pour permettre aux utilisateurs de personnaliser un avatar, de recadrer une image ou simplement de faire un zoom avant sur une image. Le problème avec le décodage des images est qu'il peut solliciter beaucoup le processeur, et cela peut parfois entraîner des à-coups ou un damier. À partir de la version 50 de Chrome (et de Firefox 42 et versions ultérieures), vous avez désormais une autre option: createImageBitmap(). Elle vous permet de décoder une image en arrière-plan et d'accéder à une nouvelle primitive ImageBitmap, que vous pouvez dessiner dans un canevas de la même manière que vous le feriez pour un élément <img>, un autre canevas ou une vidéo.

Dessiner des blobs avec createImageBitmap()

Imaginons que vous téléchargez une image blob avec fetch() (ou XHR) et que vous souhaitiez la dessiner dans un canevas. Sans createImageBitmap(), vous devriez créer un élément image et une URL Blob pour convertir l'image dans un format que vous pouvez utiliser. Vous obtenez ainsi un itinéraire beaucoup plus direct pour peindre:

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

Cette approche fonctionne également avec les images stockées sous forme de blobs dans IndexedDB, ce qui fait des blobs un format intermédiaire pratique. Chrome 50 est également compatible avec la méthode .toBlob() sur les éléments de canevas, ce qui signifie que vous pouvez, par exemple, générer des blobs à partir d'éléments canevas.

Utiliser createImageBitmap() dans les workers Web

L'une des fonctionnalités les plus intéressantes de createImageBitmap() est sa disponibilité dans les workers, ce qui signifie que vous pouvez désormais décoder les images où vous le souhaitez. Si vous avez beaucoup d'images à décoder et que vous considérez comme non essentielles, vous devez envoyer leurs URL à un web worker, qui les téléchargera et les décodera au fur et à mesure. Il les retransmett ensuite dans le thread principal pour les dessiner dans un canevas.

Flux de données avec createImageBitmap et les workers Web

Le code permettant d'effectuer cette opération peut se présenter comme suit:

// 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);
}

Aujourd'hui, si vous appelez createImageBitmap() sur le thread principal, c'est exactement ici que le décodage sera effectué. Nous prévoyons toutefois que Chrome effectue automatiquement le décodage dans un autre thread, ce qui contribuera à réduire la charge de travail du thread principal. En attendant, vous devez toutefois veiller à effectuer le décodage sur le thread principal, car il s'agit d'un travail intensif pouvant bloquer d'autres tâches essentielles, telles que JavaScript, les calculs de style, la mise en page, la peinture ou la composition.

Une bibliothèque d'aide

Pour simplifier un peu plus la vie, j'ai créé une bibliothèque d'aide qui gère le décodage sur un worker, puis renvoie l'image décodée au thread principal et la dessine dans un canevas. Bien entendu, n'hésitez pas à effectuer la rétro-ingénierie de ce modèle et à l'appliquer à vos propres applications. Le principal avantage est un contrôle accru, mais cela (comme d'habitude) s'accompagne de plus de code, de tâches à déboguer et de cas particuliers à prendre en compte que d'utiliser un élément <img>.

Si vous avez besoin de plus de contrôle sur le décodage de vos images, createImageBitmap() est votre nouveau meilleur ami. Découvrez-la dans Chrome 50 et donnez-nous votre avis !