Декодирование изображений для использования с холстом является довольно распространенным явлением, будь то возможность пользователям настраивать аватар, обрезать изображение или просто увеличивать изображение. Проблема с декодированием изображений заключается в том, что оно может нагружать процессор, а это иногда может означать зависание или шахматную доску. Начиная с Chrome 50 (и Firefox 42+) у вас теперь есть еще один вариант: createImageBitmap()
. Он позволяет вам декодировать изображение в фоновом режиме и получить доступ к новому примитиву ImageBitmap
, который вы можете нарисовать на холсте так же, как и элемент <img>
, другой холст или видео.
Рисование BLOB-объектов с помощью createImageBitmap()
Допустим, вы загружаете изображение большого двоичного объекта с помощью fetch()
(или XHR) и хотите нарисовать его на холсте. Без createImageBitmap()
вам пришлось бы создать элемент изображения и URL-адрес Blob, чтобы преобразовать изображение в формат, который вы могли бы использовать. С его помощью вы получите гораздо более прямой путь к рисованию:
fetch(url)
.then(response => response.blob())
.then(blob => createImageBitmap(blob))
.then(imageBitmap => ctx.drawImage(imageBitmap, 0, 0));
Этот подход также будет работать с изображениями, хранящимися в виде больших двоичных объектов в IndexedDB, что делает большие двоичные объекты своего рода удобным промежуточным форматом. Кстати , Chrome 50 также поддерживает метод .toBlob()
для элементов холста, что означает, что вы можете, например, генерировать большие двоичные объекты из элементов холста.
Использование createImageBitmap() в веб-воркерах
Одна из самых приятных особенностей createImageBitmap()
заключается в том, что она также доступна в рабочих процессах, а это означает, что теперь вы можете декодировать изображения где угодно. Если вам нужно декодировать много изображений, которые вы считаете несущественными, вы должны отправить их URL-адреса веб-работнику, который загрузит и декодирует их, как только позволит время. Затем он перенесет их обратно в основной поток для рисования на холсте.
Код для этого может выглядеть примерно так:
// 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);
}
Сегодня, если вы вызовете createImageBitmap()
в основном потоке, именно там и будет выполняться декодирование. Однако в планах Chrome автоматически выполнять декодирование в другом потоке , что поможет снизить нагрузку на основной поток. Тем временем, однако, вам следует помнить о выполнении декодирования в основном потоке, поскольку это интенсивная работа, которая может заблокировать другие важные задачи, такие как JavaScript, вычисления стилей, макетирование, рисование или композицию.
Вспомогательная библиотека
Чтобы немного упростить жизнь, я создал вспомогательную библиотеку , которая обрабатывает декодирование в рабочем потоке, отправляет обратно декодированное изображение в основной поток и рисует его на холсте. Вы, конечно, можете свободно перепроектировать ее и применить модель к своим собственным приложениям. Основным преимуществом является больший контроль, но при этом (как обычно) требуется больше кода, больше задач для отладки и больше крайних случаев, которые необходимо учитывать, чем при использовании элемента <img>
.
Если вам нужно больше контроля над декодированием изображений, createImageBitmap()
— ваш новый лучший друг. Проверьте это в Chrome 50 и дайте нам знать, как у вас дела!