JA EN

Canvas API 応用テクニック - フィルター、合成、ピクセル操作の実践

· 約 9 分で読めます

Canvas API による画像処理の基礎アーキテクチャ

HTML5 の Canvas API は、ブラウザ上でピクセルレベルの画像処理を実現する強力なインターフェースです。サーバーサイドに画像を送信することなく、クライアントサイドで完結する画像編集機能を構築できます。

Canvas での画像処理の基本フロー:

  1. 画像を Image オブジェクトまたは <img> 要素として読み込む
  2. drawImage() で Canvas に描画する
  3. getImageData() でピクセルデータ (ImageData) を取得する
  4. ピクセルデータを JavaScript で加工する
  5. putImageData() で加工結果を Canvas に書き戻す
  6. toDataURL() または toBlob() で結果を出力する

ImageData オブジェクトの構造:

ImageData.dataUint8ClampedArray で、各ピクセルが R, G, B, A の 4 バイトで表現されます。1,920 × 1,080の画像なら 1920 * 1080 * 4 = 8,294,400 バイトの配列になります。

特定ピクセルへのアクセス:

const index = (y * width + x) * 4; で座標 (x, y) のピクセルの開始インデックスを計算します。data[index] が R、data[index+1] が G、data[index+2] が B、data[index+3] が A (透明度) です。

この基本構造を理解すれば、あらゆる画像フィルターやエフェクトを JavaScript で実装できます。

カスタムフィルターの実装 - グレースケール、セピア、反転

Canvas API を使えば、CSS フィルターでは実現できないカスタムフィルターを自由に実装できます。基本的なフィルターから始めて、原理を理解しましょう。

グレースケール変換:

カラー画像をグレースケールに変換するには、各ピクセルの RGB 値から輝度を計算します。人間の目の感度に合わせた加重平均が最も自然な結果を生みます:

const gray = 0.299 * r + 0.587 * g + 0.114 * b;

この係数は ITU-R BT.601 規格に基づいており、人間の目が緑に最も敏感で、青に最も鈍感であることを反映しています。

セピア調変換:

セピアフィルターは、グレースケール化した後に暖色系の色味を加えます:

const newR = Math.min(255, gray * 1.2 + 40);
const newG = Math.min(255, gray * 1.0 + 20);
const newB = Math.min(255, gray * 0.8);

色反転 (ネガティブ):

各チャンネルの値を 255 から引くだけで実現できます: data[i] = 255 - data[i];

明るさ・コントラスト調整:

パフォーマンスの注意点:

ピクセル単位のループは大量の計算を伴います。1,920 × 1,080の画像では約 800 万回のイテレーションが必要です。for ループ内での関数呼び出しを最小化し、ルックアップテーブル (LUT) を事前計算することで高速化できます。

畳み込みフィルター - ぼかし、シャープ、エッジ検出

畳み込み (Convolution) は、周囲のピクセル値を重み付けして合算する処理で、ぼかし、シャープネス、エッジ検出など多くの画像処理の基礎となる技術です。

畳み込みの仕組み:

カーネル (重み行列) を画像上でスライドさせ、各位置で周囲のピクセルとカーネルの積和を計算します。3x3 カーネルなら、対象ピクセルとその周囲 8 ピクセルの計 9 ピクセルを使用します。

代表的なカーネル:

ボックスブラー (均等ぼかし): [[1/9, 1/9, 1/9], [1/9, 1/9, 1/9], [1/9, 1/9, 1/9]]

ガウシアンブラー (3x3 近似): [[1/16, 2/16, 1/16], [2/16, 4/16, 2/16], [1/16, 2/16, 1/16]]

シャープネス: [[0, -1, 0], [-1, 5, -1], [0, -1, 0]]

エッジ検出 (Sobel 水平): [[-1, 0, 1], [-2, 0, 2], [-1, 0, 1]]

実装上の注意点:

ガウシアンブラーの最適化:

ガウシアンカーネルは分離可能 (separable) なため、NxN の 2D 畳み込みを N の 1D 畳み込み 2 回に分解できます。これにより計算量が O(N²) から O(2N) に削減されます。

合成モード (globalCompositeOperation) の活用

Canvas の globalCompositeOperation プロパティは、新しく描画する図形と既存のキャンバス内容をどのように合成するかを制御します。Photoshop のレイヤーブレンドモードに相当する機能です。

主要な合成モード:

実用的な活用例:

画像のマスク処理:

  1. Canvas に画像を描画
  2. globalCompositeOperation = 'destination-in' に設定
  3. マスク形状 (円、多角形、テキストなど) を描画
  4. マスク形状と重なる部分のみが残る

カラーオーバーレイ:

  1. Canvas に画像を描画
  2. globalCompositeOperation = 'multiply' に設定
  3. 半透明の色付き矩形を描画
  4. 画像に色味が加わる (Instagram フィルター風)

注意点:

合成モードは putImageData() には適用されません。putImageData() は常にピクセルを直接上書きします。合成モードを活用するには drawImage() を使用してください。

OffscreenCanvas と Web Worker による高速化

大きな画像のピクセル処理はメインスレッドをブロックし、UI がフリーズする原因になります。OffscreenCanvasWeb Worker を組み合わせることで、画像処理をバックグラウンドスレッドに移し、UI の応答性を維持できます。

OffscreenCanvas の基本:

OffscreenCanvas は DOM に紐づかない Canvas で、Web Worker 内で使用できます:

const offscreen = new OffscreenCanvas(width, height);
const ctx = offscreen.getContext('2d');

Web Worker での画像処理パターン:

  1. メインスレッドで画像を読み込み、ImageBitmap に変換
  2. ImageBitmap を Worker に transferable として転送 (コピーではなく所有権移転)
  3. Worker 内で OffscreenCanvas に描画し、ピクセル処理を実行
  4. 処理結果を ImageBitmap として メインスレッドに返送
  5. メインスレッドで表示用 Canvas に描画

Transferable Objects の活用:

postMessage() で大きなデータを送る際、通常はデータがコピーされます。ArrayBufferImageBitmap を transferable として指定すると、コピーではなく所有権の移転が行われ、転送コストがほぼゼロになります:

worker.postMessage({ imageData }, [imageData.data.buffer]);

パフォーマンス比較:

実践プロジェクト - リアルタイム画像エディタの構築

ここまでの技術を組み合わせて、ブラウザ上で動作するリアルタイム画像エディタの設計パターンを紹介します。

アーキテクチャ設計:

パフォーマンス最適化のテクニック:

出力とエクスポート:

canvas.toBlob() で処理結果を Blob として取得し、ダウンロードリンクを生成します:

canvas.toBlob((blob) => { const url = URL.createObjectURL(blob); /* download link */ }, 'image/png');

JPEG で出力する場合は品質パラメータを指定: canvas.toBlob(callback, 'image/jpeg', 0.85);

制限事項と対策:

関連記事

ブラウザでの画像処理の仕組み - Canvas API、ImageData、Web Workers 活用ガイド

ブラウザ内で画像処理を行う技術的な仕組みを解説。Canvas API によるピクセル操作、ImageData の構造、Web Workers によるオフスレッド処理、OffscreenCanvas の活用方法を紹介します。

画像圧縮アルゴリズムの深層 - DCT、ウェーブレット変換、予測符号化の仕組み

画像圧縮の核心技術を深掘り解説。JPEG の DCT、JPEG 2000 のウェーブレット変換、H.265/AV1 の予測符号化、エントロピー符号化の数学的原理を理解します。

画像の遅延読み込み実装ガイド - loading=lazy と IntersectionObserver の使い分け

Web ページの初期表示速度を改善する画像遅延読み込みの実装方法を、ネイティブ API と JavaScript の両アプローチで解説します。

WebAssembly で高速画像処理を実現する - Wasm による画像変換とフィルタ適用

WebAssembly を活用したブラウザ内高速画像処理の実装方法を解説。Rust/C++ から Wasm へのコンパイル、Canvas API との連携、パフォーマンス比較を具体的なコード例で紹介します。

スマホでの画像編集ベストプラクティス - モバイル環境での効率的な写真加工術

スマートフォンでの画像編集を効率化するテクニック。モバイルブラウザでの処理制約、メモリ管理、タッチ UI 設計、PWA での実装方法を実践的に解説します。

カラーピッカーの活用術 - デザインワークフローを加速する色抽出テクニック

画像からの色抽出を効率化するカラーピッカー活用法を解説。ブラウザ API、デザインツール連携、カラーパレット自動生成、アクセシビリティ対応まで実践的に紹介します。

関連用語