Подтвердить что ты не робот

Использование веб-рабочих для рисования с использованием встроенных функций холста

Возможно отправить CanvasPixelArray, полученный с помощью getImageData рабочему script, и позволить рабочему script манипулировать пикселями в фоновом потоке и, в конце концов, отправить обратно обработанный массив пикселей.

Однако я использую собственные функции рисования холста, например drawImage. В настоящее время вызовы drawImage блокируют поток пользовательского интерфейса. Это приводит к медленному перерисовке кнопок и заметной задержке при нажатии кнопки, чтобы назвать несколько недостатков. (Изменить: теперь можно выполнить небольшое улучшение с помощью ctx.imageSmoothingEnabled = false, по крайней мере, на WebKit с префиксом webkit.)

Я хотел бы переместить чертеж из основного потока в фоновый поток с помощью веб-рабочих. Однако, похоже, я не могу отправить холст или контекст рабочему.

Я нашел это уведомление о MDN:

Примечание. Как обычно, фоновые потоки, включая рабочих, не могут манипулировать DOM. Если действия, выполняемые фоновым потоком, должны привести к изменениям в DOM, они должны отправлять сообщения своим создателям для выполнения этой работы.

Но я хотел бы оставить DOM как есть; Я просто хочу рисовать вещи на элементе холста. Возможно ли это, или веб-работникам действительно разрешено вычислять и не рисовать?

(Или возможно ли использовать функции типа drawImage для управления CanvasPixelArray вместо рисования на холсте?)

4b9b3361

Ответ 1

[community edit: Этот ответ был написан и принят в 2011 году. Появились (или появляются новые технологии), которые могут позволить Web Workers и Canvas сосуществовать лучше; читатель должен знать все ответы на этой странице, кроме этого ответа.]

Вы не можете передать объект canvas или canvas в рабочий поток, потому что холст является частью DOM.

Ответ 2

[Edit ~ 5 лет спустя: некоторые из них начинают меняться, и есть новые возможности веб-платформы, которые фактически позволяют рендерить холст от Рабочего! См. Этот блог для получения дополнительной информации: https://hacks.mozilla.org/2016/01/webgl-off-the-main-thread/ - остальная часть ответа предоставлена ​​для информации в эпоху 2011 года;)]

Работники Web могут вычислять, а не изменять DOM или делать любые призывы к рисованию на холст. Однако, как вы говорите, вы можете отправить массив пикселей веб-работнику, чтобы обработать его там и опубликовать обратно. Поскольку это асинхронно, я не понимаю, почему это может вызвать замедление в потоке пользовательского интерфейса, если вы не намеренно блокируете до тех пор, пока веб-рабочий не ответит (что вам не нужно).

Так что кажется странным, что ваши вызовы drawImage занимают так много времени, что влияют на пользовательский интерфейс. В настоящее время большинство полотенец ускоряют аппаратное ускорение, поэтому они должны хорошо пропустить. Мое предположение заключается в том, что вы рисуете через веб-рабочего на массив пиксельных пикселей каждый кадр, что фактически означает, что вы программно визуализируете холст в javascript. Javascript по-прежнему слишком медленный, чтобы сделать это - даже программные рендереры С++ выглядят медленными, поэтому важно ускорить аппаратное ускорение. Таким образом, вы можете сделать что-то для массива пикселей холста в веб-работнике один раз, а затем, когда вы получите свой кэш результатов в Image один раз, а затем нарисуйте Image на холст столько, сколько хотите. Это должно быть очень быстро.

Изменить: вы можете захотеть заглянуть в WebGL, где вы можете писать фрагментарные шейдеры, которые практически не работают для обработки пиксельных эффектов. Они полностью работают на графической карте, поэтому они тупо быстро.

Ответ 3

Вы можете отправить ImageData веб-работнику, который отправляет управляемый ImageData обратно в поток вызывающего (основного интерфейса).

например:.

  • Создайте веб-исполнителя:

    this.renderer = new Worker("renderer.js");
  • Отправьте ImageData, созданный с холста, веб-работнику:

    var ctx = this.canvas.getContext('2d');
    var imageData = ctx.createImageData(width, height);
    this.renderer.postMessage({ image: imageData });
  • Сделайте ImageData манипуляцию в Web Worker и отправьте ее обратно в главный поток:

    onmessage = function(e) {
       var processedImage = self.doImageProcessing(e.data.image);
       postMessage({ image: processedImage });
    };
  • Установите управляемый ImageData на холст в основном потоке:

    this.renderer.onmessage = function (e) {
       var ctx = this.canvas.getContext('2d');
       ctx.putImageData(e.data.image, 0, 0);
    }