猫の手ツール

Algorithm & UI/UX

音楽プレイヤー風画像の仕組み:
Canvasで描く文字と再生バー

写真の上に曲名、アーティスト名、再生バーなどをCanvasで描くツールです。配置と文字サイズは画像幅から計算し、指でプレイヤーの位置を調整できます。音声を再生・合成する機能ではなく、完成物は静止画像です。

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

現行コードの確認日:

入力
写真に加え、曲名・アーティストなど表示したい文字を入力します。
処理
写真全体の上に、再生ボタンや進行バー、曲名・アーティスト名をCanvasで重ねます。
出力
長辺1500px以下の写真に曲名やプレイヤー風の表示を重ね、JPEG品質0.95の静止画を保存します。

まず確認する点:音源を読み込んで再生する機能ではありません。長い曲名や文字の配置を、完成画像で確認します。

仕上がりの例

写真に曲名と再生ボタン風の表示を重ねた例です。

加工前・加工後
左は横になった愛猫の写真。右は曲名、進行バー、再生ボタン風の表示を加えた画像。

加工前・加工後

左は横になった愛猫の写真。右は曲名、進行バー、再生ボタン風の表示を加えた画像。

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

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

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

記録の入力画像
800×751px (JPEG)
記録の出力画像
800×751px (JPEG)
保存済み記録の主な操作・出力条件
画面の項目記録の値現行コードの初期値・範囲
記録で選択されていた項目ホワイト—
曲のタイトルあの夏の思い出初期値 あの夏の思い出
アーティスト名Nekonote Band初期値 Nekonote Band
再生位置 (シークバー)35初期値 35 / 範囲 0〜100

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

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

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

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

1. 解像度非依存を実現する「相対スケーリング」ロジック

ユーザーが投稿する写真は、正方形もあれば縦長もあります。どのようなサイズでも「プレイヤーが馴染む」ようにするため、すべてのパーツ(フォントサイズ、バーの太さ、影のボケ具合)をプレイヤー全体の width に対する比率で計算しています。

例えば、タイトルのフォントサイズを 6.5% に設定することで、処理用に縮小された画像でも文字とバーの比率を合わせています。ただし、長い曲名や極端に横長の画像では、文字やプレイヤーが画像の端に近づくためプレビュー確認が必要です。

配置計算の抜粋です。width、heightには読み込み後の画像寸法を渡します。文字の大きさはプレイヤー幅の6.5%で計算します。

function playerLayout(width, height) {
  const playerWidth = Math.floor(width * 0.8);
  const playerHeight = Math.floor(width * 0.35);
  return {
    x: width / 2,
    y: height - playerHeight * 0.8,
    width: playerWidth,
    height: playerHeight,
    titleSize: Math.floor(playerWidth * 0.065)
  };
}

2. 外部画像を使わない「ピュアCanvasパス描画」

再生・一時停止・スキップボタンといったUIパーツは、SVGやPNGといった画像アセットを一切使用していません。すべて roundRect や arc、lineTo といったCanvasの低レベルパス描画命令で生成しています。

UI用の画像素材を別途読み込まず、移動のたびにパスを描き直せます。Canvas上では最終的に画素へ変換されるため、保存したJPEGを大きく拡大すれば輪郭はぼけます。

3. ユーザー体験(UX)を支える当たり判定アルゴリズム

Canvas上の図形はDOMではないため、標準のイベントリスナーでは「プレイヤーを掴む」ことができません。そのため、マウスやタッチの座標を取得し、プレイヤーのバウンディングボックス内に収まっているかを判定する「当たり判定」を独自実装しています。

操作性を高めるため、実際の表示領域よりもわずかに広い「判定用パディング」を設け、指での操作でもストレスなく位置調整ができるように工夫しています。

出力の仕様と確認する点

入力はJPG・PNG・WebPなどの写真で、HEICは変換して読み込みます。長辺が1500pxを超える写真は縮小し、完成画像はJPEG品質0.95で書き出します。透明背景の素材や動画、音声付きファイルは出力しません。

白いUIには暗い影、黒いUIには明るい影を付けています。明暗が混在する背景では文字が埋もれることがあるため、色の切替とドラッグによる配置を併用してください。曲名の長さに合わせた自動改行やフォント選択はありません。

「最初からやり直す」「別の画像を作る」はページを再読み込みする実装です。入力した曲名と配置も初期化されるため、完成画像を保存してから次の写真へ進みます。