9

重複の可能性:
websocket を介して画像を受信する

使用する

imageData = context.getImageData(0, 0, width, height);
JSON.stringify(imageData.data);

ピクセル データを取得して文字列に変換し、WebSocket 経由で送信します。ただし、キャンバス オブジェクトのサイズによっては、この文字列がかなり大きくなる場合があります。ここにある圧縮手法を使用してみました: JavaScript implementation of Gzip but socket.io throws the error Websocket message contains invalid character(s).Is there an effective way to compress this data so that can be sent over websockets?

4

4 に答える 4

7

必要な効率の軸 (帯域幅と CPU 効率) に応じて、いくつかの方法をお勧めします。

オプション 1:キャンバスの toDataURL メソッドを使用できます。これは、キャンバス イメージ データの base64 でエンコードされたイメージを返します。指定した画像形式 (またはデフォルトでは PNG) を使用して圧縮され、WebSocket 経由で送信するために base64 に事前にエンコードされます。

canvas = document.getElementById("mycanvas");
b64png = canvas.toDataURL();

ws.send(b64png);

オプション 2:非可逆圧縮を許容できる場合は、 toDataURL メソッドから base64 でエンコードされた JPEG として画像を要求できます。

canvas = document.getElementById("mycanvas");
b64jpeg = canvas.toDataURL("image/jpeg");

ws.send(b64jpeg);

オプション 3:バイナリ WebSocket データ (Chrome、Firefox、IE 10) をサポートするブラウザーを使用している場合は、キャンバス配列バッファーを WebSocket 経由で直接送信できます。

canvas = document.getElementById("mycanvas");
ctx = canvas.getContext('2d');
imgdata = ctx.getImageData(0,0, width, height).data; // This is a Uint8ClampedArray
ws.send(imgdata.buffer); // Send the ArrayBuffer from the Uint8ClampedArray

オプション 3 は、帯域幅の点では最も効率的ではありませんが、クライアント側とサーバー側の処理能力の点では最も効率的です。これは、画像データが生で送信され、前処理と後処理がほとんど必要ないためです。

帯域幅効率が最も高いオプションはおそらく #2 ですが、画像データを JPEG 形式に変換する際に画質がいくらか低下します。さらに、base64 でデータを arraybuffer または blob にデコードし、それをバイナリ WebSocket 経由で送信して、base64 帯域幅の 33% のオーバーヘッドが発生しないようにすることもできますが、これにより CPU オーバーヘッドがさらに増加し​​ます。

画質を損なうことなく効率的な帯域幅が必要な場合は、オプション #2 が最適です。

いくつかのメモ/警告:

toDataURL は、base64 データの前に次のようなプレフィックスを付けます。

"data:image/png;base64,iVBORw0KGgoAAAA..."

データ URL 形式の優れた点の 1 つは、全体を取得してブラウザーのアドレス バーに貼り付けると、ブラウザーが画像をレンダリングすることです。

toDataURL の詳細については、MDN Canvas ページを参照してください。

于 2012-06-25T21:45:35.340 に答える
4

最も帯域幅効率の良い方法は、写真のようなデータを送信することです。データは JPEG エンコードされたバイナリをブロブとして送信します。

<canvas>バイナリ JPEG blob としてデータを取得できます。

https://github.com/miohtama/Krusovice/blob/master/src/tools/resizer.js#L51

(写真以外のコンテンツの場合は、PNG blob を取得することもできます)

Blob は常に生のバイナリであり、UTF-8 や base64 のがらくたは含まれていません。

WebSocket.send() は入力として blob をサポートします。

https://developer.mozilla.org/en/WebSockets/WebSockets_reference/WebSocket

HTTP Blob 送信:

https://developer.mozilla.org/en/DOM/XMLHttpRequest/Sending_and_Recoming_Binary_Data

異なるブラウザでのマイレージは異なる場合があります。

于 2012-06-25T21:58:35.453 に答える
3

あなたがより効率的な方法を求めたので、私は閉鎖の試みに同意しません。私たちにできることは、あなたがより効率的な方法を考え出すのを手伝うことです。

それは本当にあなたがしていることに依存します。クライアントにもっと仕事をさせることができますか?

本当にすべてのキャンバスピクセルデータを送信する必要がありますか?代わりに、変更されたピクセルのみを送信できますか?(またはそれはそれらのほぼすべてですか?)

変更のみを前後に送信すると、大量のデータオーバーザワイヤの問題ではなく、コンピューティングの問題になります。


アプリによっては、変更された地域を追跡できますか?キャンバス上で変更された2〜3個の小さな長方形がある場合は、キャンバス全体よりも送信する方がはるかに小さいはずです。


他の効率性の質問と同様に、そもそも正しいことをしているのかどうかを尋ねる価値があります。本当に大量のピクセルデータをネットワーク上に投げる必要がありますか?多くの場合、キャンバスでは、ビットマップ自体を送信するよりも、シーンを変更したコマンドを送信する方がサーバー上でシーンを再作成する方が簡単です。Websocketはこれに適しているはずです。これは、多くの描画アプリケーションやゲームに適したソリューションになる可能性がありますが、ここでも、ここで何を達成しようとしているかによって異なります。

于 2012-06-25T21:04:02.693 に答える
0

ネットワーク経由で送信されていたデータを大幅に削減する方法に気付きました。

このgetImageDataメソッドは、dataそれ自体がピクセルのインデックスとしてのキーと、個々の赤、緑、青、またはアルファとしての値を持つオブジェクトであるプロパティを持つオブジェクトを返します。特に 300x300 キャンバス オブジェクトには 300x300x4 = 360,000 個のオブジェクト キーと値のペアがあるため、キーがオブジェクトを非常に大きくしていました。

したがって、色の値だけを抽出して配列にプッシュすることにより、次のようになります。

function extractValues(obj){
  var array = [];
  for (var key in obj){
    array.push(obj[key]);
  }
  return array;
}

データを 50% 以上削減することができ、パフォーマンスが大幅に向上しました。

于 2012-06-25T21:13:27.527 に答える