# Fontscope 操作情報

公開パスは `/patto-tools/fontscope/`。この文書の相対リンクは文書URLを基準に解決し、[ツール一覧](../)へ戻れる。

画像から切り出した1文字と対応する文字を使い、似たフォントを比較する試作。工程は画像・文字範囲の調整・結果の3つ。作業枠の位置・高さを固定し、工程の移動でページをスクロールしない。

## 画像

- `#image-file`：PNG/JPEG/WebP、15 MB以下。長辺1600pxを超える画像は縮小する。
- `#choose-first` で選択、ドロップ・貼り付けも可能。`#sample` はローカルの提供画像を使う。
- 追加後は画像工程に留まり、範囲を選ぶ。画像全体が初期範囲、サンプルは指定済みの範囲になる。確定前は抽出・OCRを実行しない。点・濁点は本体へまとめる。外周から単色背景を推定し、濃い背景の白・淡色文字も自動抽出する。背景を判別できる場合だけ、十分な頻度・色差がある複数色を拾う。`extractInk().colors`に採用色を返し、複数色の自動抽出では「文字色 自動（N色）」と表示する。明示的な色指定は1色、暗い部分モードは従来の輝度閾値を使う。OCRには背景除去・回転前の元画像を使い、検出した行と文字列、画の間隔から文字を対応付ける。文字と画の対応は行ごとに判断し、対応できない行があっても他の行の結合を保持する。対応できない部品は未入力のまま残し、手入力で直す。文字間の離れた小さい点は結合せず残す。離れた画を自動で結合する場合も画素は変更しない。認識中に手直しを始めたら自動結合を適用しない。
- `#crop-mode`「四角形」／`#freehand-mode`「手書き」で画像範囲の選び方を切り替える。手書きはドラッグを離すと線を閉じ、内側だけを抽出・OCRへ渡す。点だけ・中断した描画は前の範囲を保持する。曲線の制御点を置く方式は追加しない。
- `#source` をドラッグして調べたい範囲を囲む。設置後は枠内で移動、辺・四隅で拡縮、枠外で囲み直す。画像全体の範囲では内側のドラッグも囲み直しになる。画像内へ制限し、中断では元の範囲を保持する。調整中はOCRを開始しない。画像全体のままでも進める。手書きの輪郭は四角形モードの移動・拡縮や数値変更でも保持し、新しい四角形の描画・全体選択・画像差し替えで解除する。`#image-next`「この範囲で自動選択」、または編集工程への移動で範囲を確定し、文字を自動抽出・認識する。同じ画像で範囲を変えない往復は手直しを保持する。新しい画像では前の枠・履歴・認識を破棄する。

## 編集

- `#sample-board`：クリックで文字を選び、Shiftクリックまたは空白からのドラッグで複数選択する。文字をドラッグして表示位置を移動し、四隅のハンドルで拡縮する。表示位置・サイズは比較画素を変更しない。レイヤーや座標パネルはない。
- `#object-character`：選択した文字の近くに現れる入力欄。画像に写っている1文字を指定する。自動入力は信頼度によらず「自動認識・要確認」。既存の入力欄で修正する。Enter／Shift+Enterで次／前の文字、IME確定では移動しない。`#character-next/previous` はクリック・Enter・Spaceで利用できる。移動先の字形が見えるようキャンバス内だけをスクロールする。編集ツールはキャンバス下の専用行にあり、入力欄とは重ならない。
- `#object-included`：検索に使うか切り替える。入力と字形が揃った枠が1つ以上あれば検索できる。未入力・複数文字入力・画素なし・除外サンプルは比較しない。
- `#sample-recrop`：選択した文字を元の配置で拡大・中央表示する。`#source-caption` が対象名、`#selection-shape` が矩形／手書き／曲線。矩形・手書きは離すと確定し、曲線は3点以上置いてEnter・ダブルクリック・`#selection-finish` で確定する。`#selection-cancel` またはEscで変更せず戻る。囲み直し開始時を100%として `#sample-zoom` またはCtrl／Command＋ホイールで対象を中心に拡縮できる。確定・取消後は直前の表示と倍率に戻る。スクロール後のホバー・ドラッグ再描画でも表示位置を保つ。
- `[data-sample-mode="add"]`：元の配置で新しい文字を囲む。点・濁点も同じ範囲に含める。連続で追加できる。
- `#source-layout`：元の配置、同じボタンでもう一度押すと編集へ戻る。`#arrange-samples`：再整列。
- `#sample-merge`：複数の部品を1文字にまとめる。複数文字が1枠に入った場合は、枠を削除して文字ごとに囲み直す。
- Backspace／Deleteで選んだ枠を削除する。枠を右クリック、またはShift+F10で `#sample-context-menu` を開き、`#sample-context-delete` からも削除できる。複数選択中の枠の右クリックは選択を保つ。タッチ端末は `#sample-context-open`（⋯）から同じメニューを開く。入力中のキー操作は枠を削除しない。Esc／余白のクリックで選択を解除する。`#sample-undo/redo`：20操作まで取り消し・やり直し。⌘/Ctrl+Z、Shift併用でやり直し。矢印キーで1px移動、Shift併用で10px。V/R/E/H、Spaceドラッグで画面移動。`#sample-zoom`、Ctrl/⌘＋ホイールで拡大。
- `#clean-tools`：消しゴム・復元の使用中だけ表示するブラシ寸法。ツールの切り替えは下部に集約する。選択範囲外の画素は復元しない。
- `#preparation`：抽出する色・傾きの調整。抽出時の角度は既定0度で、元画像を自動回転しない。`#rotation`の手動指定または`#auto-rotation`の明示操作だけで補正する。画像・範囲変更時は0度に戻し、変更のない工程往復では設定を保持する。`#auto-samples` で明示的に反映。`.transcription` の `#transcription` は画像の文字と同じ改行を入力し、`#build-samples` でまとめて切り出す任意機能。失敗時は既存の手直しを保持する。
- `#ocr-status`：自動認識の状態。実行中は `aria-busy="true"`、終了時は `false`。手動で再認識するボタンは置かず、範囲確定・自動切り出し時に実行する。手入力・変更した範囲・画素を古い結果で上書きしない。資産の取得失敗や120秒の時間切れでは処理中を解除し、手入力の案内を出す。検索・字形出力へは手入力で進める。
- `.library`：検索対象と設定。手持ちフォントの追加は扱わない。Google Fonts全1,950ファミリー＋作者の公式配布29ファミリー。合計1,979、うち日本語対応97（仮名のみを含む）。日本語のGoogle Fontsは公開全187スタイル、公式配布29スタイル。日本語は97ファミリー・216スタイル、登録全体は1,979ファミリー・2,098スタイル。ほかの言語は代表1スタイル。可変ウェイトは公開メタデータの比較点だけを使う。複数スタイルの候補名にはウェイトを表示する。`#catalog` は内訳と更新日を表示する。

## 検索・結果

- 各工程の主な操作は作業枠上端のバー右側にある（`#image-next`・`#samples-next`・`#cancel`/`#search`）。工程を戻るときは `.phase-nav` の工程を押す。
- `#samples-next`「検索する」：結果へ移動して同時に比較を開始する。結果工程へ入る時、利用可能な結果がなければ検索を開始する。
- `#cancel`：比較を中止。`#search`「検索を再開」：中止・失敗の後だけ表示する。結果がある間は、文字や画素を変えるか、傾きの許可を切り替えて再検索するまで同じ結果を使う。
- `#status`：エラー・結果の破棄・比較の完了を数秒表示する知らせ。読み上げ対象として常に残る。
- 検索中は `#search-specimen` に比較中の書体と利用者の字形の重ね刷り、`#search-font` に書体名を表示する（表示専用）。
- `#results`：上位10件。各行が1つのボタン（`aria-pressed` で選択状態）で、比較対象を選ぶ。`#overlay` に文字ごとの比較と、その文字の形の近さを表示。`#comparison-source` は選んだ候補の配布元を新しいタブで開く。
- `[data-comparison-mode]`：重ねる・元の文字・候補の文字を切り替える。採点・候補表示とも実フォントの字形と縦横比を保持し、等比拡縮・位置合わせ・文字全体の回転だけを行う。回転照合は既定でOFF。許可した検索だけ±20度まで2度刻みで照合し、同点では0度、絶対値の小さい角度を優先する。人工的な太らせ・幅変更・シアーは行わない。各セルの `.glyph-rotation` に時計回り／反時計回りの矢印と度数を小さく表示する。0度と「元の文字」表示では出さない。回転角は抽出・編集後の元の文字に対する角度である。中央と一覧は同じウェイト・スタイルで描く。形の近さは識別確率ではない。
- `#retry-rotation`：通常検索後は「文字の傾きを許可して再検索」、許可済みの結果では「文字の傾きを許可せず再検索」。その回だけ条件を変え、保存設定は変えない。`#rotation-search-status` に表示中の結果の条件を示す。
- `[data-rotation-default]`：編集・結果の「検索設定」にある「次回以降も文字の傾きを許可する」。同じ設定を同期し、`localStorage` の `patto-tools-fontscope-allow-rotation-v1` に真偽値を保存する。未保存・不正値・読み取り失敗はOFF。既存の結果は変更せず、次の通常検索に適用する。中止後の再開は中止した検索の条件を使う。保存できない場合は通知し、タブ内で適用する。表示中の検索条件は `#rotation-search-status` で確認する。
- `#catalog-summary`：登録数・比較できた数・対応言語外の数・取得失敗または文字がない数。除外した書体名の一覧と検索結果のJSONダウンロードは置かない。
- 検索候補は公開メタデータの対応言語で絞る。CJK文字では日本語・中国語・韓国語・拡張仮名の候補を残す。対応言語が不明なもの、欧文・数字・記号など絞り込みを定義していない文字体系は実描画で判定する。複数文字体系が混ざる場合はすべてに対応する候補を選ぶ。読み込みは同時4件までで、候補件数の上限は設けない。実描画では端末内で生成した形の異なる検証用フォントをフォールバックに使い、未収録文字のOS代替字形を候補に混ぜない。
- `[data-go-phase="2"]` で編集へ戻っても、文字・画素を保持する。検索中に戻ると中止する。

## データ

画像・文字は端末外へ送らない。Macのローカルを含め同梱PaddleOCR.js 0.4.2とPP-OCRv5 mobileの日本語対応モデルをブラウザで動かす。画像・入力文字・処理結果をリクエスト本文やURLへ含めない。OCR APIはない。OCRは背景除去前の元画像から行を読み、位置と文字列を文字枠へ対応付ける。検出の長辺上限は960px。部品ごとの再認識は行わず、対応できない範囲は手入力で直す。OCR資産はHTTPキャッシュの対象だが、画像・入力・結果をIndexedDBに保存しない。読みやすい印字を主対象とし、手書き・筆文字は精度評価の対象外。候補取得ではGoogle Fontsへ接続し、入力を含む `text=` は使わない。傾き検索の既定値だけはこのブラウザに保存する。画像・文字の入力は自動保存せず、再読み込み・ページを閉じると失われる。同じタブで別のページへ移る前は、比較の実行中か、画像を開いた直後（自動の切り出し・読み取りのまま）または最後のダウンロードの時点から文字の枠・入力・消去・検索の対象を直したか、最後のダウンロード以降に検索を完了したときに確認を出す（取り消しでその時点に戻せば出さない）。

## SVG・フォントとして出力

- 作業枠上端の検索ボタンの横にある、編集工程の `#glyph-export-open` と結果工程の `#result-glyph-export-open`「SVG・フォント保存」（共通属性 `[data-glyph-export]`）から同じ確認ダイアログを開く。画像と文字要素があれば有効になる。検索中・完了後・中止後・候補なしでも使える。出力元は画像から抽出・編集した文字で、候補の字形や照合の回転は適用しない。`#glyph-export-close` またはEscで開いた工程へ戻り、検索結果・候補選択・比較モードとフォーカスを保持する。
- `#glyph-format`：`svg` / `font`（OpenType OTF）。SVGは文字未入力でも利用可能。フォントは各サンプルに1文字が必要で、複数コードポイントの未正規化文字は対応しない。
- `#glyph-duplicates select`：同じ文字が複数ある場合、フォントに収録する代表字形を選ぶ。値はサンプルID。SVG/JSONには各出現を残す。
- `#glyph-proof`：保存する字形を黒でプレビューする。SVGは出力パス、フォントは生成した実OTFを描画する。比較切り替え・色分け・凡例は置かない。形式・必要時の代表字形選択・件数・プレビュー・ダウンロードだけを表示し、説明はページの使い方へ置く。
- `#glyph-smoothing`：保存時だけ輪郭を二次ベジェ曲線にする。強さは「控えめ」「しっかり」で、初期OFF。SVG・OTF・対応JSONとプレビューに反映し、元の編集画素・OCR・検索には作用しない。点・穴の輪郭は削除しない。OFFで未加工に戻せる。同じページ内では設定を保持し、再読み込みでOFFに戻る。ON時のJSONに`smoothing`を記録する。
- `#glyph-asset-download`：SVG形式では一括ZIP。個別SVGと元の配置のSVG、対応JSONを含む。文字ごとのダウンロードボタンは置かない。個別SVGは字形の余白を切り詰め、抽出・傾き補正後の形で出力する。サンプルIDで同じ文字の出現を区別する。フォント形式ではOTFを出力する。
- `#glyph-data-download`：フォント形式のみ、対応JSONを別途出力する。SVG形式ではJSONはZIP内にあるため非表示。`#glyph-export-status`に出力数・省いた枠・エラーを表示する。
- `#object-included`は検索と字形出力の両方に作用する。空の枠は省く。範囲・消去・復元後の形を使用し、編集キャンバス上の配置・倍率は使わない。
- JSONは`type: fontscope-glyphs`、`version: 1`。`glyphs[].path`は枠内の座標、`box`は抽出画像の座標、`extraction.toSource`は元画像へ戻す6要素行列。`source`に元画像と作業画像の寸法を持つ。`glyphs[].svg`には個別SVGの`filename`と、枠内座標の`viewBox`（x・y・width・height）を持つ。フォント出力時は`font.glyphs`に採用サンプルと正規化の寸法を持つ。
- 出力はローカル処理。OpenType.jsを同梱し、CDNやフォント検索を必要としない。フォントに未収録の文字は生成しない。画素の輪郭を保持し、自動の平滑化は行わない。

消しゴム・復元は、枠外から押してドラッグしても最初に横切った文字を編集する。1ストロークで1文字が対象。途中で別の文字へ切り替わらない。取り消しは1ストローク単位で、ポインター操作の中断ではそのストロークを戻す。

自動選択は各文字に所属すると判断した連結成分だけを編集画素にする。矩形が重なる他の文字の端や、無視した小成分を取り込まない。点・濁点の結合条件とノイズの大きさの基準は従来通り。細い偏と幅のある旁、上下に分かれた偏と背の高い旁も、部品の比率・重なり・距離・結合後の大きさからまとめる。文字列が読めることは条件にしない。元画像は保持し、手動の囲み直しや復元に使う。修正前から開いている画像には自動で適用せず、再読み込み・画像の追加または自動選択し直す操作で反映する。

OCR配布資産は `npm --prefix tools/fontscope ci`、`npm --prefix tools/fontscope run prepare:ocr`、`npm --prefix tools/fontscope run check:ocr` の順に生成・検証し、`dist/vendor/ocr/` も配信する。方式の切り替えUIはない。

1文字の入力と字形が揃った枠が1つ以上あれば検索できる。未入力・不正な入力・画素なしの枠と明示的に除外した文字は検索しない。検索ボタンに使用する文字数を表示する。ゲージは入力済み数／対象数を示し、プロパティ欄で「ゲージを押して枠へ移動し、画像と同じ文字を入力する」と案内する。不足があるゲージを押すと該当の枠へ移動する。SVG保存は未入力でも利用できる。

消しゴムと復元は下部のツールバーに各1つだけ置く。使用中だけ右側にブラシの大きさを表示する。「元の配置」は上部の同じボタンで「編集へ戻る」に切り替える。範囲指定中は配置切り替えを隠し、終了／キャンセルを1つにする。

スムージングをONにすると強さを「控えめ」「しっかり」から選べる。控えめは従来の最大0.5画素の角の曲線化。しっかりは最大1画素の許容差で階段状の輪郭を単純化してから、各辺に沿って最大8画素の範囲で曲線化する。小さい点・穴・細い輪郭には控えめな処理を使い、潰れ・向きの反転・自己交差を生む単純化は採用しない。強さを変えても元の輪郭から作り直し、加工を積み重ねない。強い場合はJSONの`smoothing.method`を`simplified-quadratic-corners`とし、許容差と半径の上限を記録する。元の字形から変化するため、保存プレビューで確認する。

保存設定の変更中は現在のプレビューと操作欄を保持し、生成完了後に一括で差し替える。準備中の古いファイルのダウンロードは無効にし、連続した変更では最後の設定だけを反映する。

セレクトボックスは右端から10pxに矢印を置き、文字との間に余白を確保する。ネイティブの選択操作は維持し、強制カラーモードでは標準の矢印を使う。

編集・結果の保存ボタンは「今回の字形をそのまま／SVG・フォントデータで保存」と2行で表示し、青で強調する。画像から抽出・編集した字形を保存する操作であり、検索候補のフォントファイルは保存しない。スマホでも検索の横に配置し、工程間で操作バーの高さを保つ。

検索結果の各候補と比較ヘッダーにGoogle Fontsまたは作者の配布元リンクを表示する。公式配布は固定の `sourceUrl`、Google Fontsは書体名から公開ページのURLを作り、新しいタブで開く。候補の選択ボタンとは独立したリンクとし、画像・入力文字・結果はURLに含めない。


## 公式配布フォントの追加（2026-10-08）

`bundled-font-catalog.js` をGoogle Fontsカタログと併用する。源暎・ButTaiwan・GL・FLOP DESIGN・なぎのを29ファミリー追加した。作者の配布物とライセンスは `scripts/font-sources.json` のURL・SHA-256で固定する。OFLの予約名を避けた内部名を使い、画面には元の書体名を表示する。固定Unicodeブロックの同梱WOFF2を必要時だけ読み込み、字形・メトリクスを保持する。画像・入力・結果はリクエストへ含めない。文字欠落は実描画で検査し、代替フォントを候補に混ぜない。

配布前はREADMEどおり `prepare:fonts` → `check:fonts`。`dist/vendor/fonts/` はgit管理外の必須配布資産。生成時だけPythonとFontTools/Brotliが必要。実行時にサーバー処理は不要。


自動選択は部品の結合後、文字の行から離れた小さい孤立点を除く。大きい字形が近くに3つ以上ある場合に限定し、行内の中点・句点や、同程度の小さい字形が並ぶ領域は残す。元の画素は保持し、再選択で使える。行内の星の点を自動で消す保証はしない。

## 保守時のファイル構成

`dist/` は配信する製品コード、`scripts/` は配布資産・カタログ生成、`tests/` は回帰テスト、`experiments/` は本番未採用の方式・性能調査を置く。実験の手順は `experiments/README.md` を参照する。実験の特徴量索引はアプリから読み込まない。検索結果の状態は比較用の文字・字形・回転条件と順位に絞り、出力用の座標・編集画素はサンプル編集器が保持する。
