猫の手ツール

Canvas Graphics & Memory Optimization

選挙ポスターの「記号性」をブラウザCanvasで動的に構築する

本ツールは、アップロードされた人物写真に対し、選挙ポスター特有のパーツ(タスキ、党名ボックス、名前)を、ユーザーの操作に合わせてリアルタイムにCanvas上で再構成します。今回は、その「デザインの動的合成」と「処理画像のサイズ制御」について掘り下げます。

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

現行コードの確認日:

入力
写真と名前・党名を入力し、写真位置・ズームと文字の配置を選びます。
処理
縦長のCanvasへ写真、固定角度のタスキ、横書きまたは1文字ずつの縦書きを合成します。
出力
入力は長辺 2500px 以下に縮小し、1000×1400px の JPEG(品質指定 0.85)を出力します。

まず確認する点:タスキは人体の肩を認識して置くものではありません。文字の長さと肩の位置を合わせ、枠からの欠けを確認します。

仕上がりの例

写真に名前や斜めの帯を加え、架空の選挙ポスター風にした例です。

加工前・加工後
左は横になった茶トラの愛猫の写真。右は青い名前欄と斜めのキャッチコピーを加えたポスター。

名前や文言は架空の作例です。

加工前・加工後

左は横になった茶トラの愛猫の写真。右は青い名前欄と斜めのキャッチコピーを加えたポスター。

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

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

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

記録の入力画像
800×805px (JPEG)
記録の出力画像
1000×1400px (JPEG)
保存済み記録の主な操作・出力条件
画面の項目記録の値現行コードの初期値・範囲
党名おひるね党初期値 猫の手党
名前ねこ 太郎初期値 ねこ 太郎
文字の配置下初期値 下
テーマ色ブルー(標準)初期値 ブルー(標準)
タスキの大きさ100初期値 100 / 範囲 50〜200
左右の位置0初期値 0 / 範囲 -500〜500

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

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

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

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

1. コンテクストの状態を分離した「タスキ」の幾何学的描画

選挙ポスターの象徴である「斜めのタスキ」は、静止画を載せるのではなく、Canvas APIの座標系を操作して描画しています。

単に矩形を描画するのではなく、save() と restore() を駆使して座標系を一時的に回転・スケールさせることで、他パーツ(写真や文字エリア)の描画ロジックに影響を与えずに、独立した角度(-35度など)でタスキを配置しています。

タスキの矩形を回転させる部分の例です。座標変換を save / restore で囲み、後続の文字配置に影響させません。

function sash(ctx, x, y, scale = 1) {
  ctx.save();
  ctx.translate(x, y);
  ctx.rotate(-35 * Math.PI / 180);
  ctx.scale(scale, scale);
  ctx.fillStyle = '#fff';
  ctx.fillRect(-800, -80, 1600, 160);
  ctx.restore();
}

この実装のメリットは、タスキの「大きさ」や「位置」をスライダーで変更しても、計算が非常にシンプルに済む点です。常に自身のローカルな座標軸で描画されるため、斜めの線に対する複雑な幾何学計算を排除し、パフォーマンスを稼いでいます。

2. モバイル端末を守る「長辺を制限するダウンサンプリング」

近年の高画質写真は数千万画素に及びますが、そのままCanvasに展開すると、iOS Safari等のモバイル環境では利用可能なメモリ上限を超え、メモリ不足になる場合があります。

本ツールでは、読み込み時に画像の長辺をチェックし、一定の閾値(セーフティガード)を超える場合は、描画用の適正サイズへ強制的にリサンプリングする処理を挟んでいます。

一度リサンプリングしてから描画ループ(render())に渡すことで、ユーザーがドラッグ操作を行う際の負荷を軽減し、処理に使う画素数を減らしています。

3. 汎用性を高める「文字配置の条件分岐」と縦書き処理

ポスターの種類によって「名前を下に大きく入れる」「左に縦書きする」といったニーズに応えるため、Canvasの textAlign とループ処理を組み合わせて動的にレイアウトを切り替えています。

特に縦書き(left/right配置)では、Canvasの標準機能に縦書きが存在しないため、一文字ずつループで回し、フォントサイズに基づいたY座標のインクリメントによって擬似的に縦書きを再現しています。

出力の仕様と確認する点

入力は長辺 2500px 以下に縮小し、1000×1400px の JPEG(品質指定 0.85)を出力します。写真の位置と 50〜300% のズームで、縦長の枠に収める範囲を調整します。

タスキは角度 −35° 固定、サイズは 50〜200%、位置は中心から上下左右に移動します。人物の肩や体を認識して自動で掛ける機能ではなく、文字「清き一票を」も固定です。

名前と党名は上下の横書き、左右の縦書きを選べます。長い文字を枠内へ自動で収める処理はないため、短い表記を使いプレビューで欠けを確認します。実際の掲示物の規格に適合することを判定するツールではありません。