猫の手ツール

Geometry & Performance

ベジェ曲線による花びら描画と
キャッシュ戦略の最適化

「桜の花びら」を外部画像を使わずにCanvas上で生成。一見単純なフィルタに見えますが、スライダー操作を滑らかにし、かつ「エモい」質感を損なわないためのフロントエンド特有の工夫が詰まっています。

このツールの入力から出力まで

現行コードの確認日:

入力
写真を選び、花びらの量とサイズを調整します。
処理
花びらの位置や角度をキャッシュし、量に応じた数の図形をCanvasへ重ねます。
出力
入力は長辺 2000px 以下に縮小し、1000×1000px の正方形 JPEG(品質指定 0.85)を保存します。

まず確認する点:量と大きさを両方増やすと被写体が隠れます。顔の上に重なる花びらを含めて、完成画像の構図を確認します。

仕上がりの例

写真に桜の花びらを重ねた例です。

加工前・加工後
左は緑のかぶりものを着けた愛猫の写真。右は猫の周囲に淡いピンクの桜の花びらを加えた写真。

加工前・加工後

左は緑のかぶりものを着けた愛猫の写真。右は猫の周囲に淡いピンクの桜の花びらを加えた写真。

掲載画像はサイトにある既存の公開作例です。保存済みの資料では運営者の愛猫の写真を使用しています。今回の確認日が、この作例を実行した日を表すわけではありません。

保存済み検証記録の条件を見る

資料の種類は「ツールの出力画像を保存した記録」です。公開作例と保存済み記録で素材や色などが異なる場合があるため、下の数値は保存済み検証記録の条件として読んでください。

記録の入力画像
800×1066px (JPEG)
記録の出力画像
1000×1000px (JPEG)
保存済み記録の主な操作・出力条件
画面の項目記録の値現行コードの初期値・範囲
花びらの量80初期値 80 / 範囲 0〜200
花びらの大きさ100初期値 100 / 範囲 50〜250
明るさ0初期値 0 / 範囲 -50〜50
写真のズーム100初期値 100 / 範囲 50〜300

記録では「花びら舞う画像を生成!」から完成表示へ進んでいます。初期値と記録値を比べてから、効果を1項目ずつ変えると作用を確認しやすくなります。

資料ファイルの作成日は実行日として扱っていません。個別端末の処理速度や、ほかの写真に対する検出・加工の精度を測定した資料でもありません。

実装の確認箇所:src/pages/image/cherry-blossom/index.astro。以下のコード抜粋と出力条件は、この本番実装に基づいて説明します。

仕組みを読み進めるときは、Canvas APIと画像処理(画像寸法、drawImage、画素と透明度の扱い)、File APIとObject URL(選んだ画像の読み込みとBlob URLの解放)が参考になります。

1. ベジェ曲線によるプロセジャル・シェイプ生成

桜の花びら特有の「ハート型の切れ込み」を再現するために、外部のPNG画像を使用するのではなく、Canvasの bezierCurveTo を用いた動的な描画アルゴリズムを採用しています。

メリット: 画像アセットのロード待ちが発生せず、写真の上に重ねる花びらをパスで描けます。また、描画時に解像度が劣化しないため、拡大に合わせてパスを描けます。ただし、最終出力は 1000×1000px の画像になります。

実装の花びらの輪郭を原点付近に描く例です。呼び出し側で translate・rotate・scale を使うと配置やサイズを変えられます。

function petal(ctx) {
  ctx.beginPath();
  ctx.moveTo(0, 0);
  ctx.bezierCurveTo(-15, -15, -20, -35, -5, -40);
  ctx.lineTo(0, -32);
  ctx.lineTo(5, -40);
  ctx.bezierCurveTo(20, -35, 15, -15, 0, 0);
  ctx.fill();
}

2. 決定論的ランダム(キャッシュ配列)による安定性向上

花びらの「量」をスライダーで調整する際、描画のたびに Math.random() を呼んでしまうと、スライダーを動かすたびに既存の花びらの位置まで激しく入れ替わり、不快な「チカチカ(フリッカー)」が発生します。本ツールでは、写真の読み込み時に花びらのデータを「キャッシュ配列」として事前生成しています。

メリット: スライダーで「量」を増やしても、既にある花びらは元の位置に固定されたまま「新しい花びらが追加される」という自然なUI体験を提供できます。ランダムでありながら「配置の固定」を実現するための必須テクニックです。

3. GlobalCompositeOperation による光の質感調整

単に花びらを「上に置く」だけでは、写真となじまず浮いて見えてしまいます。本ツールでは、背景写真の明るさ調整(露出補正)を行う際に、Canvasの合成モード lighter や multiply を使い分けています。

メリット: ピクセル単位の重い重畳演算をブラウザのネイティブな合成エンジンに委ねることで、スライダー変更時にプレビューを描き直します。処理時間は端末や描画する花びらの数によって変わります。これにより「春の光が差し込むような暖かさ」や「夕暮れの切なさ」をスライダー一つで表現可能にしました。

出力の仕様と確認する点

入力は長辺 2000px 以下に縮小し、1000×1000px の正方形 JPEG(品質指定 0.85)を保存します。花びらが動く動画ではありません。写真の位置とズームで切り取る範囲を調整します。

花びらの量は 0〜200、サイズは基準の 50〜250% です。同じ写真を編集中はキャッシュした位置を使うため、量を増やしても先に描かれた花びらの位置は変わりません。読み込み直すと配置が変わります。

明るさを正にすると白を lighter で加え、負にすると黒を multiply で重ねます。カメラの露出や色温度を復元する補正ではなく、白飛び・黒つぶれが起きる場合があります。