猫の手ツール

Algorithm & UI/UX

映画の「情緒」をCanvasで再現する:
動的タイポグラフィと描画最適化の裏側

映画風の字幕を写真に重ねる際は、文字の縁取り、画像に対する文字サイズ、黒帯との位置関係が見え方を左右します。この解説では、実際に使っている比率と描画順を説明します。

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

現行コードの確認日:

入力
写真と字幕の文章を入力し、位置や文字の見た目を調整します。
処理
写真をキャンバスへ描いた上に、字幕の文字と縁取りを重ねます。
出力
長辺 1500px 以下に縮小した写真を、元の縦横比の JPEG(品質指定 0.95)で保存します。

まず確認する点:文字の内容から自動で映像を生成しません。長い行のはみ出しや、明るい背景での輪郭の読みやすさを確認します。

仕上がりの例

写真に黒い帯と字幕を加え、映画風にした例です。

加工前・加工後
左は座っている茶トラの愛猫の写真。右は上下の黒い帯と日本語・英語の字幕を加えた画像。

加工前・加工後

左は座っている茶トラの愛猫の写真。右は上下の黒い帯と日本語・英語の字幕を加えた画像。

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

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

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

記録の入力画像
800×1222px (JPEG)
記録の出力画像
800×1222px (JPEG)
保存済み記録の主な操作・出力条件
画面の項目記録の値現行コードの初期値・範囲
記録で選択されていた項目明朝体、あり、—
メイン字幕本当にこれでよかったのかな初期値 本当にこれでよかったのかな
サブ字幕 (英語など)Was this really the right choice?初期値 Was this really the right choice?

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

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

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

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

1. 視認性を極める「多重描画アルゴリズム」

映画の字幕において最も重要なのは、背景がいかなる色であっても文字がはっきりと読めることです。

本ツールでは、strokeText(外枠)と fillText(塗り)を組み合わせるだけでなく、外枠の太さをフォントサイズに比例して動的に算出(Dynamic Stroke Weight)しています。また、lineJoin = 'round' を適用することで、角の鋭利さを抑えた「フィルム上映」のような柔らかい質感を演出しています。

字幕の黒縁と塗りを重ねる最小例です。ctx の font・位置合わせは描画前に設定します。

function outlinedSubtitle(ctx, text, x, y, fontSize) {
  ctx.lineJoin = 'round';
  ctx.lineWidth = Math.max(3, fontSize * 0.12);
  ctx.strokeStyle = 'rgba(0,0,0,0.85)';
  ctx.fillStyle = '#fff';
  ctx.strokeText(text, x, y);
  ctx.fillText(text, x, y);
}

2. 画像の高さを基準にした文字サイズ

スマホの写真は、4Kクラスの高解像度から古い低解像度のものまで千差万別です。

フォントサイズを固定値にすると、高解像度画像では文字が豆粒のようになり、逆に低解像度では画面を埋め尽くしてしまいます。この問題を解決するため、画像の高さ(Height)を基準に「メイン字幕は5%」「サブ字幕は2.5%」といった比率計算を画像読み込み時に実行し、初期サイズを画像に合わせています。長文が必ず収まるという意味ではありません。

3. パフォーマンスと機能性を両立する「遅延インポート」

iPhoneで標準的なHEIC形式をブラウザで扱うには重量級の変換ライブラリが必要です。しかし、すべてのユーザーがHEICを使うわけではありません。

本ツールでは、ファイル読み込み時に拡張子を判定し、HEIC形式の場合のみ dynamic import を用いて heic2any モジュールを非同期でロードします。これにより、通常のJPG/PNG利用ユーザーのHEIC 用コードの取得を省けます。LCP の改善量を測定した説明ではありません。

出力の仕様と確認する点

長辺 1500px 以下に縮小した写真を、元の縦横比の JPEG(品質指定 0.95)で保存します。黒帯を有効にすると画像の上下 12% ずつを覆うため、その部分の写真は隠れます。

メインとサブの字幕はそれぞれ改行できます。行間は文字サイズの 1.3 倍で、メインとサブの間にも余白を入れます。自動折り返しはないため、横に長い文章は手動改行してください。

字幕はひとまとまりとしてドラッグします。字幕ファイル(SRT 等)や動画を書き出す機能ではなく、文字を写真へ焼き付けます。画像端と黒帯への重なりを保存前に確認します。