10

Webワーカーで画像を配列形式で拡大縮小する必要があります。Webワーカーの外にいる場合は、キャンバスとdrawImageを使用して、画像の特定の部分をコピーしたり、拡大縮小したりできます。

Webワーカーのように、キャンバスを使用できないので、どうすればよいですか?私を助けることができる純粋なJavascriptライブラリはありますか?

よろしくお願いします。

4

3 に答える 3

16

スケーリングはさまざまな方法で実行できますが、いずれも画像からピクセルを削除または作成することになります。画像は基本的にピクセル値の行列(配列としてサイズ変更)であるため、画像を拡大してその配列を拡大し、空白を埋め、画像を縮小して値を除外することで配列を縮小することができます。

そうは言っても、通常、配列で機能する独自のスケール関数をJavaScriptで作成することはそれほど難しくありません。すでにJavaScript配列の形式の画像があることを理解しているので、その配列をメッセージでWeb Workerに渡し、scale関数でスケーリングして、スケーリングされた配列をメインスレッドに送り返すことができます。

表現に関しては、RGBA(カラー、アルファチャネル付き)でエンコードされた画像用に設計されたUint8ClampedArrayを使用することをお勧めします。これは、通常のJavaScript配列よりも効率的です。Uint8ClampedArrayオブジェクトをメッセージでWebWorkerに簡単に送信することもできるので、問題はありません。もう1つの利点は、Canvas APIのImageDataデータ型(CanvasPixelArrayを置き換えた後)でUint8ClampedArrayが使用されることです。これは、ctx.getImageData()を使用してキャンバスの2Dコンテキストの現在のImageDataを取得し、そのデータ属性をスケーリングされたものに変更するだけで、スケーリングされた画像をキャンバスに戻すのが非常に簡単であることを意味します(必要な場合)。 Uint8ClampedArrayオブジェクト。

ちなみに、画像を配列として持っていない場合でも、同じ方法を使用できます。最初にキャンバスに画像を描画し、次に現在のImageDataオブジェクトのdata属性を使用して、Uint8ClampedArray内の画像を取得します。

画像をアップスケールするためのスケーリング方法に関しては、基本的に2つのコンポーネントを実装する必要があります。1つ目は、既知のピクセル(つまり、スケーリングしている画像のピクセル)を、作成したより大きな新しい配列に分割することです。明らかな方法は、スペース全体ですべてのピクセルを均等に分割することです。たとえば、画像の幅を2倍にする場合は、各ピクセルの後の位置をスキップして、間に空白を残します。

次に、2番目のコンポーネントは、これらの空白を埋めることです。これは、少し簡単ではない場合があります。ただし、かなり簡単なものがいくつかあります。(一方、コンピュータビジョンまたは画像処理の知識がある場合は、より高度な方法を検討することをお勧めします。)簡単でやや明白な方法は、最も近い隣接ピクセル(つまり、最も近いピクセル位置)を使用して未知の各ピクセル位置を補間することです。既知のピクセルの色を複製することにより、既知のピクセル値)。これは通常、画像を拡大縮小しすぎると、より大きなピクセル(同じ色のより大きなブロック)の効果をもたらします。最も近いピクセルの色を複製する代わりに、近くにあるいくつかの既知のピクセルの平均を取ることもできます。おそらく重みと組み合わせても、遠くにあるピクセルよりも近くにあるピクセルの方が平均で多くカウントされるようになります。他の方法には、ガウス分布を使用して画像をぼかすことが含まれます。アプリケーションに最適な方法を知りたい場合は、画像の補間に関するいくつかのページをご覧ください。もちろん、スケールアップとは、実際には存在しないものを埋めることを常に意味することを忘れないでください。あなたがそれをやりすぎると、それは常に悪く見えるでしょう。

スケールダウンに関する限り、通常は、選択したピクセルのみを現在の配列から小さい配列に転送することにより、ピクセルを削除します。たとえば、画像のwithを2倍小さくしたい場合は、現在の配列を2ステップで大まかに繰り返します(これは、画像のサイズ、偶数または奇数、および自分の表現に少し依存します)使用)。最も見逃される可能性のあるピクセルを削除することで、これをさらに改善する方法があります。しかし、私はそれらについて十分に知りません。

ちなみに、これはすべてWebワーカーとは実質的に無関係です。メインスレッドでJavaScriptの画像を拡大縮小する場合は、まったく同じ方法で行います。またはそのことについては他の言語で。ただし、Webワーカーは、UIスレッドではなく、別のスレッドでこれらの計算を実行するための非常に優れた方法です。つまり、Webサイト自体が応答していないようには見えません。ただし、あなたが言ったように、canvas要素に関連するすべてはメインスレッドで実行する必要がありますが、配列のスケーリングはどこでも実行できます。

また、これを実行できるJavaScriptライブラリがあると確信しています。それらのメソッドによっては、importScriptsを使用してWebワーカーにロードすることもできます。しかし、この場合、自分で作成して目的に合わせて作成する方が簡単で、はるかに楽しいかもしれません。

また、プログラミングスキルの高度とスケーリングが必要な速度に応じて、WebGLを使用するCPUではなくGPUでいつでもこれを実行できます。しかし、この場合、それは少しやり過ぎのようです。また、画像をいくつかの部分に分割し、複数のWebワーカーで個別の部分をスケーリングしてマルチスレッドにすることもできます。後でパーツを組み合わせるのは確かに簡単ではありませんが。クライアント側でスケーリングする必要のある画像がたくさんある場合は、おそらくマルチスレッドの方が理にかなっています。

それはすべてあなたのアプリケーション、画像、そしてあなた自身のスキルと欲求に本当に依存します。

とにかく、それがあなたの質問に大まかに答えることを願っています。

于 2012-06-14T20:16:02.230 に答える
5

「…単に…データ属性をスケーリングされたUint8ClampedArrayオブジェクトに変更する」方法を理解するために、6時間費やしたばかりなので、mslatourの回答にいくつかの詳細が必要だと感じています。これをする:

①アレイをWebワーカーから返送します。次のフォームを使用します。

self.postMessage(bufferToReturn, [bufferToReturn]);

必要がない場合は、バッファのコピーを作成せずにWebワーカーとの間でバッファを渡します。(この方法の方が高速です。)(MDNドキュメントがいくつかあります。しかし、担当者がいないため、リンクできません。ごめん。)とにかく、次のように、最初のbufferToReturnをリストまたはマップ内に配置することもできます。

self.postMessage({buffer:bufferToReturn, width:500, height:500}, [bufferToReturn]);

あなたは次のようなものを使用します

webWorker.addEventListener('message', function(event) {your code here})

投稿されたメッセージをリッスンします。(この場合、投稿されるイベントはWebワーカーからのものであり、リスニングを行うイベントは通常のJSコードにあります。他の方法でも同じように機能します。「self」変数と「webWorker」変数を切り替えるだけです。)

②ブラウザ側のJavascript(ワーカー側ではなく)では、imageData .data.set()を使用して、データ属性を「単に」変更し、キャンバスに戻すことができます。

var imageData = context2d.createImageData(width, height);
imageData.data.set(new Uint8ClampedArray(bufferToReturn));
context2d.putImageData(imageData, x_offset, y_offset);

data.set()メソッドの存在を警告してくれたhacks.mozilla.orgに感謝します。

psこれを支援するライブラリを私は知りません…まだ。ごめん。

于 2013-03-12T01:57:32.990 に答える
2

私はまだそれを自分でテストしていませんが、ここで役立つかもしれない純粋なJSライブラリがあります:

https://github.com/taisel/JS-Image-Resizer

于 2014-10-30T02:45:42.107 に答える