A decodificação de imagens para uso com uma tela é bastante comum, seja para permitir que os usuários personalizem um avatar, recortem uma imagem ou apenas aumentem o zoom em uma foto. O problema com a decodificação de imagens é que ela pode exigir muito da CPU e, às vezes, pode causar instabilidade ou quadriculado. A partir do Chrome 50 (e no Firefox 42 e versões mais recentes), você tem outra opção: createImageBitmap()
. Ele permite decodificar uma imagem em segundo plano e ter acesso a uma nova primitiva ImageBitmap
, que pode ser desenhada em uma tela da mesma forma que um elemento <img>
, outra tela ou um vídeo.
Desenhar blobs com createImageBitmap()
Digamos que você faça o download de uma imagem blob com fetch()
(ou XHR) e queira desenhá-la em uma tela. Sem createImageBitmap()
, você precisaria criar um elemento de imagem e um URL do Blob para que a imagem ficasse em um formato que pudesse ser usado. Com ele, você tem um caminho muito mais direto para a pintura:
fetch(url)
.then(response => response.blob())
.then(blob => createImageBitmap(blob))
.then(imageBitmap => ctx.drawImage(imageBitmap, 0, 0));
Essa abordagem também funciona com imagens armazenadas como blobs no IndexedDB, tornando os blobs um formato intermediário conveniente. O Chrome 50 também oferece suporte ao método .toBlob()
em elementos de tela, o que significa que você pode, por exemplo, gerar blobs desses elementos.
Como usar createImageBitmap() em workers da Web
Um dos recursos mais legais do createImageBitmap()
é que ele também está disponível em workers, o que significa que agora você pode decodificar imagens onde quiser. Se você tiver muitas imagens para decodificar que considera não essenciais, envie os URLs delas para um worker da Web, que fará o download e a decodificação conforme o tempo permitir. Em seguida, ele as transfere de volta para a linha de execução principal para desenhar em uma tela.

O código para fazer isso pode ficar assim:
// 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);
}
Hoje, se você chamar createImageBitmap()
na linha de execução principal, é exatamente aí que a decodificação será feita. No entanto, os planos são para que o Chrome faça a decodificação automaticamente em outra linha de execução, ajudando a manter a carga de trabalho da linha de execução principal baixa. No entanto, faça a decodificação na linha de execução principal, porque é um trabalho intensivo que pode bloquear outras tarefas essenciais, como JavaScript, cálculos de estilo, layout, pintura ou composição.
Uma biblioteca auxiliar
Para simplificar um pouco as coisas, criei uma biblioteca auxiliar que processa a decodificação em um worker, envia a imagem decodificada de volta para a linha de execução principal e a desenha em uma tela. É claro que você pode fazer engenharia reversa e aplicar o modelo aos seus próprios apps. O principal benefício é mais controle, mas isso (como de costume) vem com mais código, mais depuração e mais casos extremos a serem considerados do que usar um elemento <img>
.
Se você precisar de mais controle com a decodificação de imagens, createImageBitmap()
será seu novo melhor amigo. Confira no Chrome 50 e nos conte o que achou.