Декодирование изображений для использования с холстом является довольно распространенным явлением, будь то возможность пользователям настраивать аватар, обрезать изображение или просто увеличивать изображение. Проблема с декодированием изображений заключается в том, что оно может нагружать процессор, а это иногда может означать зависание или шахматную доску. Начиная с 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 и дайте нам знать, как у вас дела!
Декодирование изображений для использования с холстом является довольно распространенным явлением, будь то возможность пользователям настраивать аватар, обрезать изображение или просто увеличивать изображение. Проблема с декодированием изображений заключается в том, что оно может нагружать процессор, а это иногда может означать зависание или шахматную доску. Начиная с 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 и дайте нам знать, как у вас дела!