猫の手ツール

Algorithm & UI/UX

Canvasによる「エモさ」の自動生成:比率制御と端末内完結処理の工夫

本ツールは、ユーザーのプライバシーを最優先しながら、写真の「エモさ」を最大限に引き出すために、Canvas APIを用いた高度な画像制御とブラウザ内完結の最適化を組み合わせています。その実装の裏側を少しだけ公開します。

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

現行コードの確認日:

入力
写真と余白に入れる短い文字を指定し、フレーム比率・書体・台紙色を選びます。
処理
写真を中央から固定の枠へ切り取り、台紙色と余白、文字を順番に描きます。
出力
入力は長辺 1500px 以下に縮小し、チェキ風は 800×1200px、ポラロイド風は 800×1000px の JPEG(品質指定 0.95)を保存します。

まず確認する点:写真の縦横比とフレームの縦横比が違うため切取りが生じます。顔の上や文字を端へ寄せすぎないことが大切です。

仕上がりの例

写真に白い枠とメモを加え、ポラロイド風にした例です。

加工前・加工後
左は横になった茶トラの愛猫の写真。右は白い写真枠の下に短いメモを加えた画像。

加工前・加工後

左は横になった茶トラの愛猫の写真。右は白い写真枠の下に短いメモを加えた画像。

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

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

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

記録の入力画像
800×805px (JPEG)
記録の出力画像
800×1200px (JPEG)
保存済み記録の主な操作・出力条件
画面の項目記録の値現行コードの初期値・範囲
記録で選択されていた項目チェキ風 (縦長)、手書き風 (よもぎ)、—
余白に入れる文字今日もお昼寝—

記録では「このデザインで保存する」から完成表示へ進んでいます。初期値と記録値を比べてから、効果を1項目ずつ変えると作用を確認しやすくなります。

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

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

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

1. 高速レスポンスを実現する「スケールファクタ制御」

リッチな画像加工ツールにおいて、高解像度の画像をそのまま編集Canvasに描画し続けると、メモリ不足や描画遅延が発生し、特にモバイル端末での操作性が著しく低下します。

この問題に対し、本実装では「プレビュー」と「最終書き出し」で共通のロジックを用いつつ、内部的にscale値を動的に切り替える手法を採用しました。編集画面では低解像度で高速に再描画を行い、保存時のみフレームの規定寸法でレンダリングすることで、プレビューは保存用フレームの縦横 50% で描画します。入力画像の元解像度をすべて保持するという意味ではありません。

フレーム内の写真領域を埋める計算例です。写真を歪ませず、余る部分を左右または上下から均等に切り出します。

function photoCover(iw, ih, pw, ph) {
  const scale = Math.max(pw / iw, ph / ih);
  return { width: iw * scale, height: ih * scale,
    x: (pw - iw * scale) / 2, y: (ph - ih * scale) / 2 };
}

2. アスペクト比を問わない「中央を切り出すクロップ」

チェキ風フレームの魅力は、特有の縦長・正方形比率にあります。しかし、ユーザーがアップロードする写真は千差万別です。

単に画像をリサイズして配置するのではなく、Math.maxを用いた「Cover(外接)」アルゴリズムをCanvas上で実装することで、どのようなアスペクト比の写真でも、フレームの指定範囲を隙間なく埋めつつ、中央部分を自動的に切り出す制御を行っています。

3. プライバシーを守る「端末内HEIC変換・リサイズ」

HEICを画像として読み込めるかはブラウザ環境に依存します。本ツールではHEICを選ぶと、ブラウザ内でJPEGへ変換してから合成に使用します。

そこで、heic2anyライブラリをブラウザ上で動的にインポートし、クライアントサイドのみでJPEGへ変換、さらにその後の処理負荷を抑えるために、一定以上の解像度を持つ画像は自動的に最適化(独自のしきい値によるリサイズ)を行うパイプラインを構築しました。

出力の仕様と確認する点

入力は長辺 1500px 以下に縮小し、チェキ風は 800×1200px、ポラロイド風は 800×1000px の JPEG(品質指定 0.95)を保存します。余白は選んだ背景色になり、透明 PNG 出力はありません。

写真は中央基準で切り出され、位置をドラッグして調整する処理はありません。端の人物が切れる場合は、あらかじめ余白を含む画像を用意するか別のフレーム比率を選びます。

下部の文字は1行で、幅の上限をフレーム幅の 80% に指定します。長い文字列はブラウザの描画で横幅が詰まる場合があるため、短いメッセージにすると読みやすくなります。