高パフォーマンスなクライアントサイド画像処理
ブラウザでの画像処理は、今や標準的な要件となっています。フォトエディタ、アセットツールキット、あるいはアクセシビリティフィルターなどを構築する場合、UIのレスポンスを維持するために低レイテンシが求められます。
単純なタスクとして「色の反転」があります。これはRGB値をその負の値に反転させることを意味します。4K画像に対して標準的な手法を用いると、ハードウェアのボトルネックに直面します。
問題点:単純な反復処理
ほとんどの開発者は getImageData() メソッドを使用します。これは Uint8ClampedArray を返します。この配列は、ピクセルを赤 (Red)、緑 (Green)、青 (Blue)、アルファ (Alpha) の各チャンネル (RGBA) として保存します。
標準的なループは以下のようになります:
- すべてのバイトを一つずつループする。
- 各色の値から255を引く。
- アルファチャンネルをスキップする。
これは小さな画像には有効ですが、4Kアセットでは失敗します。4K画像には800万ピクセル以上が含まれています。標準的なループでは3,300万回以上の個別の書き込みが発生します。これによりメインスレッドがブロックされ、ブラウザのカクつきやフレームドロップの原因となります。
解決策:32ビットバッファ操作
ピクセルを4つの個別のチャンネルとして扱うのをやめましょう。代わりに、データバッファの上に Uint32Array を重ね合わせます。
32ビットビューを使用することで、R、G、B、Aを単一の整数としてグループ化できます。これにより、ループの回数は3,300万回ではなく、わずか820万回になります。4回ではなく、ピクセルごとに1回の操作で処理できるようになります。
ビット演算 XOR による高速な色反転
アルファ値に触れずに色を反転させるには、ビット演算の XOR 演算子 (^) を使用します。マスクとして 0x00FFFFFF を使用してください。
仕組み:
- マスクは色ビットのみを対象にします。
- アルファビットはそのまま維持されます。
- CPUはこれを単一のサイクルで処理します。
結果:
- 1080pアセット:3.8倍高速。
- 2Kテンプレート:4.1倍高速。
- 4K壁紙:4.4倍高速。
プロのヒント:Web Worker を使用する 高解像度のファイルを大量に処理する場合、32ビット操作であってもUIが遅くなる可能性があります。ロジックを Web Worker に移動しましょう。バッファを渡すには Transferable Objects を使用します。これによりデータのコピーを回避し、メインスレッドを自由に保つことができます。
重いループの使用はやめましょう。32ビットワードとビットフラグを活用して、軽量で高速な画像パイプラインを構築してください。