#javascript #html #image #safari #web-worker
#javascript #HTML #изображение #safari #веб-работник
Вопрос:
Я хотел бы генерировать изображения в asm.js код, выполняемый на веб-работнике. И я хотел бы регулярно составлять последнее состояние этого вычисления на видимом пользователем 2d-холсте вместе с некоторым другим контентом. В настоящее время у меня есть код, который
- создает
ImageData
объект с помощью его конструктора на основе части буфера массива, используемого asm.js код, - вызовы
createImageBitmap
для превращенияImageData
вImageBitmap
, - переносит это растровое изображение из рабочего в поток графического интерфейса и
- использует это
ImageBitmap
в качестве аргумента дляCanvasRenderingContext2D.drawImage
.
В последних версиях Chrome и Firefox все работает хорошо, но Safari 9.1.3, по-видимому, не имеет никакой createImageBitmap
функции. Как бы мне сделать что-то подобное описанному выше способом, который работает в Safari?
Существует ли какое-либо недорогое кодирование изображений, кроме создания data:image/png…
для него? Есть ли какой-нибудь другой способ превратить массив байтов во что-то, что вы можете передать drawImage
?
Кстати: http://caniuse.com / в настоящее время эта функция не указана. Существует запрос функции, который вы можете 👍, если хотите, чтобы эта функция отслеживалась там.
Если вы предпочитаете видеть код для моего текущего подхода, вот соответствующая часть моего рабочего:
var buffer = new ArrayBuffer(bufferSize);
var asm = Module.asm(self, {}, buffer);
var imgBytes = new Uint8ClampedArray(buffer, offset);
var imgData = new ImageData(imgBytes, width, height);
createImageBitmap(imgData).then(function(bmp) { // Not available on Safari!
postMessage(bmp, [bmp]);
});
и здесь соответствующий код потока GUI:
var worker = new Worker(‹url of worker›);
worker.onmessage = function(msg) {
var img = msg.data;
context2d.drawImage(img, 0, 0, width, height);
};
Фактический код без сокращений содержится в этом запросе на извлечение из GitHub, но есть много других вещей, которые не имеют отношения к рассматриваемому вопросу.
Ответ №1:
Есть ли какой-нибудь другой способ превратить массив байтов во что-то, что вы можете передать
drawImage
?
Вы можете опубликовать ArrayBuffer
Uint8ClampedArray
объект of в основном потоке; в основном потоке замените с помощью .putImageData()
for .drawImage()
. Как указано @Kaiido, нет необходимости создавать ImageData
объект в Worker
var imgBytes = new Uint8ClampedArray(buffer, offset);
postMessage(imgBytes.buffer, [imgBytes.buffer]);
в основном потоке
worker.onmessage = function(e) {
console.log(e.data); // `ArrayBuffer`
ctx.putImageData(new ImageData(new Uint8ClampedArray(e.data), width, height), 0, 0);
}
Комментарии:
1. Это загружает изображение из файла PNG. Таким образом, хотя он хранится в типизированном массиве, это не необработанные пиксельные данные. Если бы я дублировал этот подход, мне, вероятно, пришлось бы кодировать пиксельные данные в формате PNG, что занимает некоторое время и требует либо некоторых библиотек, либо некоторого самописного кода для заголовков PNG, вставки заголовка строки и минимальной кодировки deflate (например, используя только метод несжатого хранилища). Тем не менее, это может быть жизнеспособным вариантом, особенно если ничего лучшего не появится, так что спасибо!
2. @MvG Вы можете в качестве альтернативы перенести
buffer
изimgData
в основной поток вpostMessage
, заменить с помощью.putImageData
for.drawImage
; см. Обновленный пост.3. Если я правильно понял, для вашей последней части вам не нужно создавать объект ImageData в рабочем ( jsfiddle.net/Kaiido/234ekx4b )
4. @Kaiido Да, вы правы. plnkr.co/edit/N0v1YQHQX2rdFfHcOKeR?p=preview
5. Это звучит интересно. Поскольку мне нужно составить композицию с другим контентом, мне нужно
drawImage
, но я могуputImageData
перейти на внеэкранный холст, а затемdrawImage
на основной.