今回は、ブラウザ上で動作する高機能なモザイク・ぼかしツール「BrushMosaicPro」を開発する中で採用した、いくつかの技術的な工夫について解説します。
絵師やクリエイターが「安全に」「手軽に」投稿用画像を加工できることを目指したこのツールには、フロントエンドならではの最適化が詰まっています。
1. オフスクリーンCanvasの活用:非破壊的な動的パラメータ調整
このツールの最大の特徴は、**「一度塗った後からでも、スライダーでモザイクの粗さやぼかし強度を自在に変更できる」**点です。これを実現するために、表示用のCanvasとは別に、メモリ上に保持された複数の「計算用(オフスクリーン)Canvas」をフル活用しています。
アーキテクチャ
- Source Layer: オリジナルの画像データ(不変)
- Effect Layers: オリジナル画像に「全力の全体モザイク」および「全力の全体ぼかし」を施したオフスクリーンCanvas
- Mask Layers: ユーザーがブラシでなぞった軌跡を保存するCanvas
なぜ軽いのか?
ユーザーがスライダーを動かした際、Canvas全体を再計算して描画し直すと非常に重くなります。本ツールでは、パラメータ変更時にオフスクリーンのEffect Layerだけを更新し、表示Canvasにはそれらを「マスク」として合成するだけで済むため、高解像度の画像でもヌルヌルと動作します。
2. Dual-Mask構造のアルゴリズム:1ストロークで2つの処理を制御
「モザイクをかけた境界線がくっきりしすぎて不自然」という問題を解決するため、本ツールではDual-Mask構造を採用しています。
合成のロジック
1つのストロークデータ(mousedownからmouseupまでの一連の座標)に対し、内部では以下の2つのマスクを同時に生成しています。
- Core Mask (Mosaic用): ブラシサイズ通りの領域
- Wide Mask (Blur用): ブラシサイズに「パディング(余白)」を加えた一回り大きな領域
これを以下の数学的な優先順位で合成しています。
// 簡略化した合成ロジック
ctx.drawImage(originalImage, 0, 0);
// 1. 周囲をぼかす (Wide Mask + Blur Layer)
tempCtx.globalCompositeOperation = 'source-over';
tempCtx.drawImage(wideMask, 0, 0);
tempCtx.globalCompositeOperation = 'source-in';
tempCtx.drawImage(blurLayer, 0, 0);
ctx.drawImage(tempCanvas, 0, 0);
// 2. 中心をモザイク化 (Core Mask + Mosaic Layer)
tempCtx.globalCompositeOperation = 'source-over';
tempCtx.drawImage(coreMask, 0, 0);
tempCtx.globalCompositeOperation = 'source-in';
tempCtx.drawImage(mosaicLayer, 0, 0);
ctx.drawImage(tempCanvas, 0, 0);
この処理により、**「中心はしっかり隠しつつ、外側に向かって自然に周辺画像と馴染ませる」**という高度な加工が、ひと塗りで完結します。
3. Viteでのビルド最適化:サーバー不要のスタンドアロン配布
「ツールをダウンロードしてローカルで直接開きたい」というニーズに応えるため、Viteの設定を極限までチューニングしました。
詰まりどころ:絶対パスとCORS
モダンなWeb開発(Viteなど)では通常、アセットは絶対パス(/assets/...)として管理されます。しかし、これをブラウザで直接(file://プロトコルで)開くと、ブラウザのセキュリティ制限によって外部JSの読み込みがブロックされてしまいます。
解決策
-
相対パス設定:
base: './'を指定し、すべてのリソースを相対パスで解決させます。 -
シングルファイル化:
vite-plugin-singlefileを導入。JSやCSSをすべてindex.html内にインライン展開し、アセット読み込みという概念そのものを消去しました。 -
Polyfillの無効化:
modulePreload.polyfill: falseを設定。file://環境では不要(かつエラーの原因となる)なプリロード処理を排除しました。
これにより、**「ダブルクリックするだけですぐに起動する、1つのHTMLファイル」**としての書き出しを実現しました。
技術スタックまとめ
- Frontend: React (Hooksを活用した状態管理)
- Canvas Control: 2D Context API (合成モードをフル活用)
- Icons: Lucide-React
- Build Tool: Vite + TypeScript
-
Optimization:
vite-plugin-singlefile
サーバーに画像を一切送信せず、ブラウザのメモリのみで完結するプライバシー性能。そしてオフスクリーンCanvasによる軽快な操作性。これらが合わさることで、クリエイターにとって「痒い所に手が届く」ツールが完成しました。
今後はスマホ版をリリースできるように、さらなる改変に取り組みたいと思います!