猫の手ツール

Algorithm & UI/UX

グリッド分割の数学:クライアントサイドで実現する正確な画像切り出し

選択した範囲を3列と1〜3行の正方形に分け、3・6・9枚のJPEGを作ります。ブラウザでの座標計算と、選択範囲を暗幕から浮かび上がらせる描画方法、画像ごとの書き出しを説明します。

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

現行コードの確認日:

入力
1枚の写真と分割する行数を選び、ズームや位置で切り出す範囲を決めます。
処理
3列のグリッドを基準に選択範囲をCanvasで切り出し、各タイルを1080×1080pxへ描きます。
出力
各画像は1080×1080px、JPEG品質0.9で保存されます。

まず確認する点:完成画面の番号は投稿順の案内です。生成画像がつながっていても、SNS側の表示切取りが変わるとプロフィール上でずれることがあります。

仕上がりの例

猫の写真を3×3の9枚に分割した例です。

加工前・加工後
左は愛猫2匹が並ぶ元写真。右は写真を縦3列・横3段の9枚に分けた表示。

各画像は個別に保存されます。比較画像の白い間隔は保存画像に含まれません。

加工前・加工後

左は愛猫2匹が並ぶ元写真。右は写真を縦3列・横3段の9枚に分けた表示。

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

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

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

記録の入力画像
800×667px (JPEG)
記録の出力画像
1080×1080px (JPEG)、1080×1080px (JPEG)、1080×1080px (JPEG)、1080×1080px (JPEG)、1080×1080px (JPEG)、1080×1080px (JPEG)、1080×1080px (JPEG)、1080×1080px (JPEG)、1080×1080px (JPEG)
保存済み記録の主な操作・出力条件
画面の項目記録の値現行コードの初期値・範囲
記録の盤面3 columns × 3 rows—
記録の写真ズーム100%—

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

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

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

1. メモリ不足を防ぐための「プリ・スケーリング」処理

スマートフォンの高画質な写真は、解像度が数千ピクセルを超えることが一般的です。これらをそのままCanvasで頻繁に再描画したり、一気に分割処理を行うと、特にモバイルブラウザではメモリ上限に達して強制終了(クラッシュ)するリスクがあります。本ツールでは、読み込み時に独自のしきい値に基づいてリサイズを行う「プリ・スケーリング」を実装しています。

メリット: 入力画像を長辺2500px以下に抑え、編集中のCanvasの画素数を減らします。保存時には分割数だけ別の画像を生成するため、入力縮小だけですべてのメモリ負荷がなくなるわけではありません。

分割画像の切り出しを1枚分にした例です。x、y、sizeは選択範囲の左上と横幅、rowとcolは0始まりの位置です。

function cropTile(image, x, y, size, row, col) {
  const tile = size / 3;
  const canvas = document.createElement('canvas');
  canvas.width = canvas.height = 1080;
  const ctx = canvas.getContext('2d');
  if (!ctx) return null;
  ctx.drawImage(image, x + col * tile, y + row * tile,
    tile, tile, 0, 0, 1080, 1080);
  return canvas.toDataURL('image/jpeg', 0.9);
}

2. 「逆引き」座標計算による動的プレビュー

ユーザーがプレビュー上で枠をドラッグしたり、スライダーでズーム(拡大・縮小)したりする際、Canvas上の「どこを切り抜くか」をリアルタイムに計算し続ける必要があります。本ツールでは、画像の中心点を軸にした相対的な座標計算を採用し、ズーム時でも「見ている場所」が変わらないように工夫しています。

メリット: 直感的な操作感を実現。また、分割数(3/6/9)を変更しても、可能な限り現在の選択範囲を維持することができます。

3. ネガティブスペースを活用した視覚的フィードバック

編集画面では、切り抜かれる範囲を「明るく」、除外される範囲を「暗く(半透明の黒)」表示しています。まず元画像を描き、その全体に半透明の黒を重ねます。その後、選択範囲だけ元画像をもう一度描くことで、そこだけ明るく見せています。選択範囲を透明に消去する処理ではありません。

メリット: 重ね塗りによる色味の変化を防ぎ、ユーザーが「どの部分が書き出されるか」を最も鮮明かつ正確に認識できるようになります。

出力の仕様と確認する点

各画像は1080×1080px、JPEG品質0.9で保存されます。小さな選択範囲を拡大しても細部は増えないため、ズームを強くした場合には文字や顔の輪郭を確認します。

完成画面には投稿順の番号が表示されます。写真は個別に保存する方式で、ZIP一括保存やSNSへの自動投稿はありません。並び順と実際のプロフィール表示は、投稿先の画面でも確認してください。

3列の正方形タイルを作るツールなので、SNS側で縦長のサムネイルや別の切取りが使われるとつながり方が変わることがあります。生成したJPEGの内容と、サービスが表示する範囲は分けて考えます。