10

バックグラウンド設定

他の一連の画像から画像を作成する Web アプリケーションがあります。私が選択した方法は、一連の画像を読み込んで HTML キャンバスに配置することです。次に、各キャンバスを jpeg としてサードパーティ API にエクスポートし、それを使用toDataURLして Blob に変換します。私が直面している問題は、これらのキャンバスの多くがすべてデータを jpg としてエクスポートしていて、多くのリソースを消費していることです。各キャンバスが を呼び出そうとすると、アプリケーションの速度が低下し、応答しなくなりますtoDataURL

質問

特にキャンバスのサイズが大きい場合、キャンバスのtoDataUrl()orを呼び出すと非常に遅くなることがわかりました。toBlob()Web ワーカーのマルチスレッドの性質を利用したいと考えています。

まず、canvas オブジェクトを渡そうとしましたが、エラーがスローされました。オブジェクトが問題であることが判明し、文字列に変換されるか、複製できない場合に失敗するようです。いずれにせよ、コンテキストの画像データを渡すとうまくいくことがわかりました。Uint8ClampedArrayデータは、キャンバス コンテキストの method から生の RGB 値の形式で渡されますgetImageData()

Main.js

var canvas = document.createElement('canvas');
var context = canvas.getContext('2d');
var worker = new Worker('myWorker.js');
worker.postMessage({
  image: context.getImageData(0, 0, canvas.width, canvas.height)
});

myWorker.js

this.onmessage = function(e) {
  // GOAL: turn e.data.image into an image blob or dataUrl and return it.
  // e.g. this.postMessage(new Blob([e.data.image.data], {type: 'image/jpg'});
}

Uint8ClampedArrayRGB情報を保持するaをjpg/pngデータに変換する方法を知ることになると思います。

これが便利だと思う理由はgetImageData、キャンバス コンテキストから既存のデータ構造をコピーするだけなので、toDataUrl. 以下のコード ブロックに似たものを呼び出しながら、CPU プロファイルをキャプチャしました。

var image = context.getImageData(0, 0, canvas.width, canvas.height)
var dataUrl = canvas.toDataURL('image/jpeg');

そして得た:

getImageData と toDataURL のパフォーマンス結果

そのため、プロセスの負荷を Web ワーカーにオフロードしたいと思います。別のプロセスで発生している限り、Web ワーカー内で時間がかかってもかまいません。

それについてのいくつかの追加の考え:

  • 変換を行うために追加のライブラリを追加することは問題ありませんが、Web ワーカー ファイルへの依存関係として外部ライブラリを追加する方法を提供するためのボーナス ポイントです。現在、アプリケーションに browserify を使用しています。おそらく、Web ワーカー用に別のブラウザ化されたバンドルを作成しますか?
  • 最後に(サードパーティのAPI用に)jpegが必要なので、pngに変換するのは、jpegへの変換のステップになるだけです。
  • encoderOptionsプロセスを高速化する方法として、 の 2 番目のオプションである を下げてtoDataURLみましたが、あまり変化が見られませんでした。
4

1 に答える 1

6

- - アップデート - -

自分のソリューションを npm ライブラリとして共有すると思いました: https://www.npmjs.com/package/jpeg-web-worker。提供された web-worker を利用して面倒な作業を行う方法について説明します。

----------------------

新しい画像を生成しながら、アプリケーションとページの応答性を高速化する、私にとってはうまくいくソリューションを手に入れました。

アプリのコードは次のとおりです。

アプリ

var canvas = $('#myCanvas')[0];
var context = canvas.getContext('2d');
var imageData = context.getImageData(0, 0, canvas.width, canvas.height);
var worker = new Worker('myWorker.js');
worker.postMessage({
  image: imageData
});
worker.onmessage = function(e) {
  var blob = new Blob( [e.data.data], {type: 'image/jpeg'} );
  // use blob
}

そして、ここにワーカーコードがあります:

ワーカー

this.onmessage = function(e) {
  var jpgInfo = encode(e.data.image, 50);
  this.postMessage(jpgInfo);
}

function encode() { ... } // ported from jpeg-js

明らかに、この答えの大部分は関数から来ていencodeます。この関数は、npm モジュールjpeg-jsから変更されました。具体的には、encoder.jsファイルから変更されました。Encoder.js ファイル全体を myWorker.js にコピーして、encode 関数を移植しました。小さくはありませんが、非常に自己完結型であるため、簡単に作成できます。私が残した唯一の問題は、ビルドされた node.js 環境の外で動作するようにコードを変更することでした。

これは比較的簡単であることが判明しました。

  1. 「const」変数宣言を「var」に変換
  2. への参照を削除しBufferます。これは 2 段階のプロセスでした。最初に、上部の atob 定義を削除します (必要ないため)。次に、new Unit8Arraythis.encode 関数の最後で a を返します。現在のバージョンでは、実際にはこれがバッファ参照のすぐ上でコメントアウトされています。それを使用して、その下にあるものをすべて取り外します。
  3. module.export への参照を削除しています。この関数はこのファイル内でのみ必要なので、これはその行を削除するのと同じくらい簡単です。

正確なタイミング測定値はありませんが、画像が生成されたときのラグ タイムが 10 秒から 1 秒未満になりました。ここで「ラグ タイム」とは、ページの使用中にパフォーマンスが低下することを意味します。

于 2016-01-27T23:11:25.747 に答える