Использование веб-работников для рисования с использованием встроенных функций холста - PullRequest
27 голосов
/ 17 ноября 2011

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

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

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

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

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

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

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

Ответы [ 4 ]

36 голосов
/ 28 ноября 2011

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

Веб-работники могут только вычислять, не изменять DOM или делать какие-либо вызовырисовать на холсте.Однако, как вы говорите, вы можете отправить массив пикселей веб-работнику, чтобы обработать его и опубликовать обратно.Поскольку это асинхронно, я не понимаю, почему это может привести к какому-либо замедлению потока пользовательского интерфейса, если только вы намеренно не заблокируете его, пока веб-работник не ответит (а вы не должны).* звонки занимают так много времени, что это влияет на пользовательский интерфейс.В наши дни большинство холстов работают с аппаратным ускорением, поэтому их следует пропустить.Я предполагаю, что вы рисуете через веб-работника в массив пикселей холста каждый кадр , что фактически означает, что вы программно визуализируете холст в javascript .Javascript все еще слишком медленный, чтобы делать это - даже рендеры программного обеспечения на C ++ работают довольно медленно, поэтому аппаратное ускорение важно.Таким образом, вы можете визуализировать что-то в массив пикселей холста в веб-работнике один раз , а затем, когда вы получите результат, кэшировать его в Image один раз , а затем нарисовать это1017 * на холст сколько угодно.Это все еще должно быть очень быстро.

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

12 голосов
/ 28 ноября 2011

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

Нельзя передать объект холста или контекст холста рабочему потоку, поскольку холст является частью DOM.

10 голосов
/ 07 июля 2015

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

Например:

  1. Создание веб-работника:

    this.renderer = new Worker("renderer.js");
  2. Публикация ImageData созданного из холста веб-работника:

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

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

    this.renderer.onmessage = function (e) {
       var ctx = this.canvas.getContext('2d');
       ctx.putImageData(e.data.image, 0, 0);
    }
5 голосов
/ 08 февраля 2016

Для этого есть новый API (в настоящее время поддерживается только в Firefox, если вы включите pref).

См. https://developer.mozilla.org/en-US/docs/Web/API/OffscreenCanvas и https://hacks.mozilla.org/2016/01/webgl-off-the-main-thread/.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...