# XNH WebApp PDF Editor

https://xenoah.github.io/tools/pdf-editor/pdf-editor.htm

ブラウザだけで動作する、ローカル処理完結型のPDFエディタです。

PDFファイルは外部サーバーへ送信せず、読み込み、表示、注釈追加、本文テキストの見た目編集、保存までをクライアント側で処理します。

## 現在の構成

このプロジェクトはビルド不要の静的Webアプリです。

```text
pdf-editor.htm
pdf-editor.css
pdf-editor.js
lib/
  pdf.min.mjs
  pdf.worker.min.mjs
  pdf-lib.min.js
```

以前のVite / React / TypeScript構成から、すぐ起動できるVanilla HTML / CSS / JavaScript構成へ移行しています。

## 起動方法

ES Modulesとpdf.js workerを使うため、ブラウザで直接 `pdf-editor.htm` を開くより、ローカルHTTPサーバー経由で開くことを推奨します。

```bash
python -m http.server 4173
```

その後、ブラウザで開きます。

```text
http://127.0.0.1:4173/
```

npm installやビルドは不要です。

## 主な機能

### 表示・読み込み

- ローカルPDFファイルの読み込み
- ドラッグ&ドロップでのPDF読み込み
- ページサムネイル表示
- メインビューアでのPDF表示
- 単ページ表示 / 連続表示
- ページ移動
- ズームイン / ズームアウト
- ページ全体表示 / 幅合わせ表示

### ページ編集

- サムネイルのドラッグ&ドロップによるページ並び替え
- ページ回転（左 / 右）
- ページ削除 / 複製
- 白紙ページの挿入（末尾 / 任意位置）
- 複数 PDF の結合
- 指定ページの抽出・別 PDF として保存
- 先頭へ移動 / 末尾へ移動
- 複数ページ選択（Shift / Ctrl + Click, Ctrl+A, Escape）
- 複数ページの一括削除・複製・回転・移動
- サムネイルへの種別バッジ表示（白紙 / 複製 / 結合）

### 注釈・編集

- 矩形注釈
- 楕円注釈
- 線注釈
- 矢印注釈
- フリーハンド注釈
- ハイライト
- テキスト注釈
- PDF本文テキストの見た目編集
- 注釈の選択、移動、削除
- 右クリックメニューからの基本操作、ページ操作、ツール切り替え

### 操作性・安全網

- Undo / Redo（注釈・ページ並び替え・回転・削除・複製・結合・抽出を含む）
- 未保存変更の検知（保存ボタンに変更マーカー表示）
- 未保存時の離脱警告 / 別 PDF を開く前の確認
- エラー・成功通知のトースト表示
- レンダリングタスクのキャンセル制御（連続ズーム / 高速スクロールに強い）
- 編集済みPDFの保存

## 本文テキスト編集について

PDFの本文はWordやGoogle Docsのような自然な文字列データではなく、ページ上の描画命令として保存されていることが多いです。

そのため、このエディタの本文編集は、既存のPDF内部構造を完全に再構成する方式ではなく、以下の方式で実装しています。

1. pdf.jsでページ上のテキスト位置を検出
2. 編集したい文字領域をクリック
3. 元の文字領域を背景色で塗り消す
4. 新しい文字をPDFページ上へ焼き込む

保存後のPDFには編集結果が反映されます。ただし、元のPDF内のテキスト命令そのものを意味的に置換するわけではありません。

日本語テキストにも対応しやすいよう、保存時のテキストは画像化してPDFへ埋め込む方式を採用しています。

## 保存方式

編集内容は `pdf-lib` を使って既存PDFへ反映し、新しいPDFとしてダウンロードします。

現在の保存は主に「見た目をPDFページへ焼き込む」方式です。

- 図形、線、矢印、ハイライトはPDF描画として追加
- フリーハンドはSVGパスとして追加
- テキスト注釈と本文編集テキストは画像化して追加
- 元ファイルは上書きせず、`*_edited.pdf` として保存

## 使用ライブラリ

- `pdf.js`: PDFの読み込み、解析、レンダリング
- `pdf-lib`: PDFへの描画、保存

どちらも `lib/` 配下に同梱しており、CDNには依存していません。

## セキュリティ方針

- PDFデータはブラウザ内でのみ処理
- 外部サーバーへのPDFアップロードなし
- 保存はブラウザのダウンロード機能で実行
- CDN非依存

## 既知の制約

- PDF本文の完全な意味的編集、再フロー、フォント情報の完全保持は未対応
- 編集後の本文テキストは画像として保存されるため、保存後PDF内でその部分の文字選択や検索はできない場合があります
- 複雑なPDF、暗号化PDF、特殊フォント、縦書き、回転文字などは位置検出がずれる場合があります
- PDF/A、電子署名、XFA、JavaScript埋め込みなどの特殊PDF機能は保証対象外
- 大容量PDFではブラウザのメモリ制限により動作が重くなる場合があります

## 今後の改善候補

- Before / After 1クリック比較（Phase 2）
- 注釈のリサイズ・回転・コピー&ペースト・整列（Phase 3）
- 画像 / 署名 / スタンプ / 透かし / ページ番号挿入（Phase 4）
- PDF内検索 / 墨消し / 本文編集領域のリサイズ（Phase 5）
- フラット化保存 / プロジェクト保存 / PDFメタデータ編集（Phase 6）
- キーボードショートカット拡充（Phase 7）
- サムネイル生成のキュー制御 / 暗号化 PDF 対応（Phase 8）

## Changelog

### 2026-05-11 (Phase 0 / Phase 1)

#### Phase 0: 基盤整理・安全網

- Undo / Redo の対象を注釈だけでなくページ並び替え・回転にも拡張しました。
- 未保存の変更があるとき、保存ボタンに変更マーカーを表示するようにしました。
- 未保存のままタブを閉じる / 別 PDF を開こうとした際に確認を出すようにしました。
- alert によるエラー表示を廃止し、トースト通知に統一しました。
- 大容量 PDF 向けに、レンダリングタスクのキャンセルと stale ガードを追加しました。
- 手動 QA チェックリストを整理しました。

#### Phase 1: ページ編集の完成

- ページ削除 / 複製 / 白紙挿入 / 位置指定挿入を追加しました。
- 複数 PDF の結合（pdf-lib の copyPages を使用）を追加しました。
- 指定ページのみを新しい PDF として抽出・保存できるようにしました。
- ページを先頭へ / 末尾へ移動するボタンを追加しました。
- 複数ページ選択（Shift / Ctrl + Click, Ctrl+A, Escape）と一括操作を追加しました。
- サムネイルの D&D 挿入位置表示を強化し、パネル末尾のドロップゾーンを追加しました。
- サムネイルに種別バッジ（白紙 / 複製 / 結合）を表示するようにしました。
- 内部的に `pageOrder` を論理ページ ID 配列へ移行（source / blank / duplicate / imported）。

### 2026-05-11

- サムネイルをドラッグ&ドロップしてページ順を並び替えられるようにしました。
- サムネイル上とツールバーからページを左回転 / 右回転できるようにしました。
- ページの並び替えと回転が、表示だけでなくPDF書き出し結果にも反映されるようにしました。
- 右クリックメニューを追加し、保存、Undo / Redo、ページ回転、ページ移動、ツール切り替え、注釈削除を呼び出せるようにしました。
- サムネイル、ページ表示、右クリックメニューに軽いアニメーションを追加しました。
- 本文テキスト編集やテキスト注釈の書き出し時に、文字画像が横方向へ圧縮されてフォントの縦横比が変わる問題を修正しました。

## 開発メモ

現在のメイン実装は [pdf-editor.js](pdf-editor.js) に集約されています。

UIは [pdf-editor.htm](pdf-editor.htm) と [pdf-editor.css](pdf-editor.css) で構成されています。

ビルドステップをなくして即時起動できることを優先しているため、現時点では依存管理ファイルやバンドラー設定はありません。
