web-dev-qa-db-ja.com

ネイティブキャンバス関数を使用して描画するためのWebワーカーの使用

CanvasPixelArray経由で取得したgetImageDataをワーカースクリプトに送信し、ワーカースクリプトにバックグラウンドスレッドのピクセルを操作させ、最終的に操作したピクセル配列をポストバックすることが可能です。

ただし、私はdrawImageのようなネイティブのキャンバス描画関数を使用しています。 drawImage呼び出しは現在、UIスレッドをブロックしています。これにより、ボタンの再描画が遅くなり、いくつかの欠点を挙げれば、ボタンをクリックしたときに顕著な遅延が発生します。 (編集:小さな改善はctx.imageSmoothingEnabled = false、少なくともwebkit接頭辞が付いたWebKitで)。

Webワーカーを使用して、メインスレッドからバックグラウンドスレッドに図面を移動したいと思います。しかし、私はキャンバスもコンテキストもワーカーに送信できないようです。

私は見つけました MDNに関するこの通知

注:通常どおり、ワーカーを含むバックグラウンドスレッドはDOMを操作できません。バックグラウンドスレッドによって実行されたアクションの結果、DOMが変更される必要がある場合は、その作業を行うためにメッセージを作成者に投稿する必要があります。

しかし、DOMはそのままにしておきたいと思います。 canvas要素に物を描きたいだけです。これは可能ですか、それともWebワーカーは本当に計算のみを許可され、描画は許可されませんか?

(または、キャンバスに描画する代わりに、drawImageのような関数を使用してCanvasPixelArrayを操作することはおそらく可能ですか?)

30
pimvdb

[コミュニティ編集:この回答は2011年に作成および承認されました。WebワーカーとCanvasの共存を可能にする他のテクノロジーが出現(または出現)しています。読者はこれに関するすべての回答に注意する必要がありますこの回答以外のページ。]

キャンバスはDOMの一部であるため、キャンバスオブジェクトまたはキャンバスコンテキストをワーカースレッドに渡すことはできません。

12
John Watson

[約5年後の編集:この一部は変更され始めており、Workerからキャンバスへのレンダリングを実際に可能にする新しいWebプラットフォーム機能があります!詳細については、このブログを参照してください: https://hacks.mozilla.org/2016/01/webgl-off-the-main-thread/ -残りの答えは2011年の時代に提供されます情報 ;)]

WebワーカーはDOMの計算のみが可能で、変更や、キャンバスへの描画の呼び出しはできません。しかし、あなたが言うように、ピクセルの配列をWebワーカーに投稿してそこで処理し、投稿し直すことができます。これは非同期なので、Webワーカーが応答するまで意図的にブロックしない限り(そうすべきではありません)、UIスレッドの速度が低下する理由はわかりません。

したがって、drawImageの呼び出しに時間がかかりすぎてUIに影響しているのは奇妙に思われます。最近のほとんどのキャンバスはハードウェアアクセラレーションに対応しているため、うまくスキップできます。私の推測では、Webワーカーを介してキャンバスのピクセル配列ごとに描画しています(== --- ==)すべてのフレーム。これは、キャンバスjavascript。 Javascriptはまだこれを行うには遅すぎます-C++ソフトウェアレンダラーでさえ遅いので、ハードウェアアクセラレーションが重要です。したがって、何かをWebワーカーのキャンバスピクセル配列にレンダリングできます1回。次に、結果を取得したら、それをImageonce次に、そのImageを好きなだけキャンバスに描画します。それはまだ本当に速いはずです。

編集:WebGLを調べて、ピクセルエフェクトを処理するほとんど効果のないプログラムであるフラグメントシェーダーを作成することができます。それらは完全にグラフィックカードで実行されるので、ばかげて高速です。

36
AshleysBrain

ImageDataをWebワーカーに投稿すると、操作されたImageDataが呼び出し元(メインUI)スレッドに返されます。

例えば。:

  1. Webワーカーを作成します。

    this.renderer = new Worker( "renderer.js");
  2. キャンバスから作成したImageDataをWebワーカーに投稿します。

    var ctx = this.canvas.getContext( '2d'); 
     var imageData = ctx.createImageData(width、height); 
     this.renderer.postMessage({image:imageData});
  3. WebワーカーでImageData操作を行い、メインスレッドにポストバックします。

    onmessage = function(e){
     var processesImage = self.doImageProcessing(e.data.image); 
     postMessage({image:processingImage}); 
    };
  4. 操作されたImageDataをメインスレッドのキャンバスに設定します。

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

これを行うための新しいAPIがあります(現在、設定を有効にした場合にFirefoxでのみサポートされます)。

https://developer.mozilla.org/en-US/docs/Web/API/OffscreenCanvas および https://hacks.mozilla.org/2016/01/webgl-を参照してください。 off-the-main-thread /

5
Marco