Альтернатива createImageBitmap в Safari

#javascript #html #image #safari #web-worker

#javascript #HTML #изображение #safari #веб-работник

Вопрос:

Я хотел бы генерировать изображения в asm.js код, выполняемый на веб-работнике. И я хотел бы регулярно составлять последнее состояние этого вычисления на видимом пользователем 2d-холсте вместе с некоторым другим контентом. В настоящее время у меня есть код, который

  1. создает ImageData объект с помощью его конструктора на основе части буфера массива, используемого asm.js код,
  2. вызовы createImageBitmap для превращения ImageData в ImageBitmap ,
  3. переносит это растровое изображение из рабочего в поток графического интерфейса и
  4. использует это 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);
}
  

http://plnkr.co/edit/N0v1YQHQX2rdFfHcOKeR?p=preview

Комментарии:

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 на основной.