たまにPDF
たまに使うPDFツール
仕事やプライベートで たまにPDFを操作したいだけ の人のための、ブラウザ完結型のPDFツールです。
インストール不要・アカウント不要・アップロード不要。スマートフォンでもPCでも使えます。
→ https://masakiniwa.github.io/TaMaNi-PDF/
ファイルはあなたの端末から出ません
このツールには、ファイルを受け取るサーバーが存在しません。
PDFの読み込み・編集・書き出しはすべてブラウザの中で行われます。
これは方針としてだけでなく、技術的に外部送信の経路がない状態として担保しています。
| 担保方法 | 内容 |
|---|
| サーバ処理なし | バックエンドを持たない静的サイト。処理は pdf.js / pdf-lib によるクライアント処理のみ |
CSP connect-src 'self' | 外部への fetch / XHR / WebSocket をブラウザレベルで禁止 |
| 依存アセットの自己ホスト | フォント・アイコン・CMap・wasm を含め CDN を一切使わない (外部ドメインへの接続が0件) |
| 解析ツールなし | アクセス解析・エラー収集・広告タグを入れていない |
| 保存先はローカルのみ | 設定と墨消しテンプレート (範囲の座標) は localStorage。PDFそのものは保存しない。自動位置合わせをオンにしたときだけ、96px幅の白黒簡易画像がテンプレートに加わる (既定はオフ) |
「外部ドメインへの通信が0件であること」は
通しテスト で毎回検証しています。
できること
ページ整理
- ページの並べ替え (各カードのつまみをなぞるだけ / タッチ操作対応)
- ページの回転 (90°単位、ページごと・全体)
- ページの削除・複製、選択したページだけを残す (いらないページを1枚ずつ消さなくてよい)
- ページの追加 (別のPDF / JPEG・PNG画像 / 空白ページ)
- 追加するページを選べます — あとからPDFを足すとき、中身を見て必要なページだけ入れられます
(設定で「すべて追加する」にも切り替えられます)
- PDFがなくても、画像から新しいPDFを作り始められます (JPEG / PNG / WebP / AVIF / HEIC・HEIF)。
HEIC を読めるのは iPhone・Mac の Safari だけです (HEIC を読む部品は、特許とライセンスの事情から同梱していません)
- ページを画像で保存 — 選んだページ (選んでいなければ全ページ) を PNG / JPEG / WebP / AVIF にします。
1ページなら画像1枚、2ページ以上なら ZIP。解像度は 96 / 150 / 300dpi。回転とページ番号もそのまま画像になります。
AVIF はブラウザが書き出せないため、Squoosh の AVIF 書き出し器 (@jsquash/avif) を Web Worker で動かします
(AVIF を選んだときだけ読み込みます)
- 画像の取り込みが速く、PDFも小さくなります — 画像はブラウザで読める大きさのJPEGに刷り直してから
埋め込みます (A4相当のスキャン画像10枚・計51MBで、取り込み16.5秒→1.9秒 / 出力35.7MB→8.4MB)。
画質は設定で「ほどほど (既定) / 小さめ / 元のまま」から選べます
- 元に戻す・やり直す
- 書き出しは一覧の上のツールバーに常駐 (ページ数が多くても下までたどらなくてよい)
- ページ番号の付与 (位置6か所 / 書き方4種 / 開始番号 / 文字の大きさ / 1ページ目を飛ばす)。
元のページには触れないので文字は文字のまま残ります
- ページ数が多くても軽い — 数百ページでも、一覧は画面に入る行だけを描きます
- ページを全画面で確認 — サムネイルを押すと1ページだけ大きく表示します。
2本指のピンチ・ダブルタップで拡大でき、そのまま回転・削除・選択もできます
- サムネイルの大きさをその場で変更 (小 / 中 / 大 / 特大)。スマホでは「大」以上で1列になり、実際に大きく表示されます
- 出力は元のページ内容をそのままコピーするので、文字は文字のまま残ります
墨消し
隠したい範囲をドラッグで囲んで塗りつぶします。
黒い四角を重ねるだけの墨消しは、下にある文字がそのまま残ります。
コピー&ペーストや別のソフトで開くと読めてしまう、よくある事故です。
たまにPDF は全ページを一度 画像に変換してから 塗りつぶし、その画像だけで
PDFを作り直します。隠した部分の情報は出力されたPDFの中に残りません。
- 塗りつぶし色は黒 / 白
- 適用先は「このページのみ / 全ページ / 奇数ページ / 偶数ページ / 最終ページ」から選択
- 作った範囲はタップで選択 → ドラッグで移動、右下のつまみで大きさ変更
- 2本指のピンチで拡大・縮小、2本指のドラッグで上下左右に移動 (100〜400%)。
パソコンではホイールで移動、Ctrl+ホイールで拡大縮小。拡大時はページを描き直すのでぼやけません
- 取り消し / やり直しに対応
- PC・タブレットの横長の画面ではPDFが高さいっぱいに広がり、操作パネルが右に並びます (ツールバー・説明・範囲一覧を横のスペースに寄せた1画面レイアウト)。
スマホは向きを変えても縦長と同じ並びのままです
- ページ数とページサイズは維持されます
- 画像化するため、出力PDFは文字検索・テキスト選択ができなくなります (ヘルプにも明記)
サイズ圧縮
「PDFが大きすぎて、システムの上限に引っかかって出せない」ときのための機能です。
写真やスキャンでできたPDFを、読める品質のまま軽くします。
- 収めたい大きさ (1 / 2 / 3 / 5 / 10MB) を選ぶだけ — 届くまで画質を一段ずつ落として自動で試します
- 画質を自分で決めたいときは、4段 (きれいめ 200dpi / 標準 150dpi / 小さめ 110dpi / とにかく小さく 80dpi) から選べます
- 元と圧縮後を並べて見比べられます (押すと全画面)。粗くなりすぎていないか確かめてから保存できます
- 小さくならなかったときは、そう表示します (「圧縮しました」とは言いません)。
文字中心のPDFはもともと小さいため、画像化するとかえって大きくなることがあります
- 文字の多いPDFには、読み込んだ時点で注意を出します
- 墨消しと同じ仕組み (全ページを画像として刷り直す) なので、文字検索・テキスト選択は失われます
墨消しテンプレートと一括墨消し
同じ発行元・同じ書式のPDF (請求書や明細など) を繰り返し墨消しするための機能です。
- 指定した範囲をテンプレートとして保存・呼び出し
- 自動位置合わせ (既定はオフ) — 同じ書式でも中身がずれているPDFに、範囲を合わせてから適用します。
テンプレート保存時のページと適用先のページを見比べて、平行移動 (±12%) と拡大縮小 (±5%) を推定します。
補正量と一致度はプレビューと一覧に表示され、似た配置が見つからないときは補正しません。
オンにすると、テンプレートに 96px幅の白黒簡易画像 が保存されます
(本文が読める大きさではありませんが、大きな見出しなど内容の一部が判別できる場合があります)。
ずれを測るのは基準にした1ページだけで、その結果を全ページに当てます
- 複数のPDFにテンプレートをまとめて適用 (一括墨消し)
- 実行前に代表1件でプレビューして、テンプレートがどこに当たるか確認できます
- 出力は個別ダウンロード、または ZIP でまとめて保存
- テンプレートは JSON で書き出し / 読み込みが可能 (端末間の持ち運び用)
- 自動位置合わせは設定で切り替えます。オフのあいだは簡易画像を保存せず、座標だけのテンプレートになります
範囲はページに対する 割合 (0〜1の正規化座標) で保存しているため、
用紙サイズが違っても同じ位置に当たります。
作業を失わないための作り
- 画面を移っても作業は消えません — ヘルプや設定を見に行っても、読み込んだPDFと編集内容はそのまま残ります
- 範囲を指定したまま別のPDFへ切り替えるときは確認します
- 読み込んだPDFがあるあいだにタブを閉じようとすると、ブラウザの確認が出ます
- テンプレートを端末に保存できなかったときは、その旨をはっきり伝えます (「保存しました」とは出しません)
一括墨消しの安全策
- テンプレートや画質を変えると、前の条件で作った結果は破棄して作り直しを促します
(別のテンプレートで作ったPDFがZIPに混ざらないようにするため)
- 当たる範囲が1つもないPDFは失敗として止めます (何も隠れていないPDFを完了扱いにしない)
- 一部の指定が当たらないときは、その指定を結果に表示します
- 終了時は「完了○件 / 失敗○件」を表示します
処理の速さ (端末に合わせる)
- 数ページを同時に流します — 墨消し・サイズ圧縮・一括墨消しで、PDFの解釈 (pdf.js の Web Worker)・
画面への描画・JPEGへの書き出しが重なって進むようにしています。同時に流す数は端末の CPU の数と
メモリから自動で決め、設定で 1〜4 に変えられます
- 画像の取り込みは Web Worker で — 展開・縮小・JPEGへの書き出しを画面とは別のスレッドで行います
- GPU は用途ごとに — 画面の表示 (一覧・拡大表示) には GPU を使い、書き出し (墨消し・圧縮・画像で保存) には
ふだん使いません。書き出しでは描いた絵を GPU から読み戻す手間がかかり、実機 (Pixel 8 Pro) でも
「画像にする」工程がどの同時数でも 18〜40% 遅くなったためです。GPU を真似ているだけのソフトウェア描画は使いません
- この端末に合わせる — 押すと、見本のPDF (お手持ちのPDFは使いません) で組み合わせごとに測り、
いちばん速い組み合わせをそのまま設定にします。設定は端末に残るので、次からもその値で動きます
計測 (4コア・GPUなしの開発環境、150dpi):
| 処理 | v0.9.2 | v0.10 |
|---|
| サイズ圧縮 (写真10ページ・21.6MB) | 2.52秒 | 1.92秒 (−24%) |
| 画像の取り込み (スキャン風PNG 10枚・51MB) | 1.53秒 | 1.33秒 (−13%) |
PDFを開き直して作業役 (Web Worker) をページの数だけ増やす形も試しましたが、開き直す手間が上回り、
かえって遅くなったため採用していません。
大きなPDF (ストリーミング処理)
墨消し・サイズ圧縮・一括墨消しは、大きなPDFでもメモリを使いすぎないように、少しずつ読んで少しずつ書き出します。
- 読むとき — ファイル全体を読み込まず、pdf.js が必要とする部分だけを 1MB ずつ渡します
(部分的に読み直せないファイルのときは、これまでどおり全体を読み込みます)
- 書き出すとき — ページができるたびに、そのページの画像をPDFの部品として書き、手元には持ちません。
全ページを抱えてから組み立てる pdf-lib の手順を通らないので、出力の何倍ものメモリを使いません
- 一括墨消しのZIP — 各PDFを少しずつ読みながら ZIP にまとめます。出来上がったPDFも Blob で持ちます
計測 (150ページ・199MB の写真PDF、4コア・GPUなし、ブラウザ全体のメモリの増え方の最大):
| 処理 | v0.10 | v0.11 |
|---|
| 墨消し 300dpi (出力 238MB) | +1,675MB | +1,114MB (−33%) |
| サイズ圧縮 標準 (出力 14MB) | +1,072MB | +891MB (−17%) |
残りの多くは、高解像度で描くための作業用の領域 (ページ数によらずほぼ一定) と、
pdf.js が読んだ部分を手元に置いておく領域 (最大でファイルの大きさまで) です。
ページ整理の書き出しは pdf-lib でまとめて組み立てるため、まだ対象外です。
その他
- 設定 (テーマ / サムネイルの大きさ / 画像の取り込み画質 / 処理の速さ / 解像度 / 画像形式 /
既定の塗りつぶし色 / ファイル名の接尾辞 / 自動位置合わせ)
- ヘルプ (使い方・墨消しの仕組み・プライバシー・FAQ)。長い説明は見出しごとに折りたためます
- バージョン情報とリポジトリへのリンク
技術構成
アイコンはすべてインラインSVG、フォントは端末のシステムフォント。
外部リクエストを0件に保つため、UIライブラリや Web フォントの CDN は使っていません。
開発
npm install
npm run dev # 開発サーバ
npm run build # 本番ビルド (dist/)
npm run typecheck # 型チェック
npm run test:unit # 計算だけの部品のテスト (速さの計測の選び方・PDFの書き出し)
npm run test:e2e # ビルドして実ブラウザで通しテスト
npm run test:e2e は Playwright + Chromium で以下を検証します。
- 各画面が表示できること
- 説明の折りたたみ (最初は見出しだけが並び、押すと中身が開く・もう一度押すと閉じる)
- 作業内容が消えないこと (ヘルプ・設定を見て戻ってもページと範囲が残る・
隠れている画面のボタンがアプリバーに出ない・別PDFへの切り替え確認)
- 一括処理の結果管理 (当たる範囲がないPDFを止める・テンプレートを変えると前の結果を残さない)
- ダイアログ (入力しても焦点が入力欄に残る)
- トリミング済みPDF (ページ番号が表示範囲に入る)
- 壊れたテンプレートJSON (読み込まずに知らせる)
- ページ整理: 読み込み・削除・回転・並べ替え・Undo/Redo・書き出し (回転が出力に反映されるか)
- 一覧の大きさ変更と「選択以外を削除」 (ツールバーで大きさが変わり設定にも残るか・
選んだページだけが残るか・元に戻せるか)
- ページの拡大表示 (大きく描き直すか・ページ全体が枠に収まるか・ページ送り・拡大・
スマホでのピンチ・開いた直後の操作対象)
- 追加するページの選択 (最初の読み込みは全ページ・2件目からは選べる・設定で無効化・
複数ファイルで前の選択が残らないこと)
- 当たらない範囲の検出 (単体の墨消しでも書き出しを止めること)
- 全ページ削除しても「戻す」が残ること
- ページ番号 (指定した位置に実際に描かれるか・入れないときは描かれないか・
1ページ目を飛ばせるか・元の文字が文字のまま残るか)
- 150ページのPDF (一覧が間引かれること・下まで送ると最後のページが出ること・
間引いても全ページが書き出されること)
- 墨消し: 隠した文字が出力PDFから消えていること、塗った範囲が実際に黒くなっていること、
範囲の移動・サイズ変更・拡大表示・クリア
- テンプレートの保存と一括墨消し、ZIP出力
- 自動位置合わせ (既定がオフであること・オンにすると基準画像つきで保存されること・
中身をずらしたPDFで塗る位置が実際にずれに追従すること・オフだと補正しないこと・
ヘルプの説明がオンとオフで切り替わること)
- スマホのタッチ操作 (つまみをなぞると並べ替えられること、つまみ以外をなぞったときは
並べ替えではなくスクロールになること、指での範囲指定と移動、2本指のピンチ拡大)
- 一括墨消しの適用前プレビュー
- 表示がちらつかないこと (ピンチ中に表示領域の大きさが揺れない・描き直しが繰り返されない・
拡大後も絵の縦横比が保たれる)
- 横長の画面 (PCではPDFの横に操作パネルが並び、ページ全体が縦スクロールなしで収まること・
横向きのスマホでは縦長と同じ並びのままで、下のナビゲーションが残ること)
- 画像の取り込み (画質の設定でPDFの大きさが実際に変わること)
- サイズ圧縮 (スマホの拡大表示で紙全体が見えること・画像PDFが実際に小さくなること・ページ数が変わらないこと・
小さくならないPDFではそう伝えること・圧縮後に文字データが残らないこと)
- 並べて進める処理 (同時に3ページ流しても出力のページ順が崩れないこと・画像の取り込みが
Web Worker で行われていること・速さの計測と、その結果を設定に反映できること)
- 画像で保存 (PNG / JPEG / WebP / AVIF それぞれ中身がその形式であること・回したページの向き・解像度・
1ページなら画像1枚)と、画像の取り込み (WebP / AVIF を取り込める・読めない HEIC は理由を伝える)
- 少しずつ書き出したPDFの骨組み (索引の各行が本当にその部品を指しているか。
pdf-lib や pdf.js は索引が壊れていても開いてしまうため、別に確かめる) と、ZIP の中身が欠けていないこと
- 外部ドメインへの通信が0件であること / CSP違反が0件であること
Chromium の場所を指定したい場合は CHROMIUM_PATH を設定してください。
ディレクトリ構成
src/
app/ ルーティング・レイアウト・設定とテンプレートの共有状態
core/
pdf/ PDFの読み込み・描画・組み立て・墨消し
image/ 画像の刷り直し (Web Worker)
perf/ 端末に合わせた並べ方・GPUの判定・速さの計測
storage/ 設定とテンプレートの永続化
util/ 汎用ユーティリティ
ui/ デザインシステム部品 (Button / Dialog / Snackbar ...)
features/ home / organize / redact / batch / compress / settings / help
scripts/ pdf.jsアセットのコピー・通しテスト・スクリーンショット
docs/SPEC.md 仕様書
公開
main ブランチへの push で GitHub Actions が dist/ をビルドして GitHub Pages に公開します
(.github/workflows/deploy.yml)。
ロードマップ
- v0.1 — ページ整理 / 墨消し / テンプレート / 一括墨消し / 設定 / ヘルプ
- v0.2 — 墨消し範囲の移動・サイズ変更・拡大表示、並べ替え用つまみ、
主要操作のアプリバーへの集約、墨消しのクリア
- v0.2.1 — 2本指のピンチ拡大と上下左右の移動、墨消しの取り消し / やり直し、
アプリバーを「戻す / やり直す / クリア」に統一
- v0.3 — ピンチ操作のちらつき修正、墨消しの操作導線の整理
(ページ送りとテンプレートをツールバーへ)、一括墨消しの適用前プレビュー、
画像・空白ページから始める導線
- v0.4 — 書き出しを画面上部へ移動、クリアをアプリバーに一本化、
横長の画面向けの1画面レイアウト (PDFの横に操作パネル)
- v0.4.1 — 1画面レイアウトの適用条件を「幅と高さの両方に余裕がある画面」に変更。
横向きのスマホは縦長と同じ並びのままにする
- v0.5 — 墨消しテンプレートの自動位置合わせ
- v0.5.1 — 自動位置合わせを既定オフにし、何が保存されるかを設定画面で説明。
オン / オフで各画面の表記を切り替え
- v0.6 — ページ番号の付与、ページ一覧の間引き描画 (仮想スクロール)
- v0.6.1 — 長い説明を折りたためるようにした (ヘルプの各見出しと、設定の自動位置合わせ)
- v0.7 — 外部レビューでの指摘に対応。作業状態の保持、一括処理の結果管理、
ダイアログの焦点、保存失敗の通知、適用範囲ゼロの検出、トリミング済みPDFへの対応、
テンプレート読み込みの検証
- v0.7.1 — 一覧のサムネイルをその場で拡大縮小、「選択以外を削除」を追加
- v0.8 — ページの全画面表示 (ピンチ拡大つき)、追加するページの選択
- v0.8.1 — 外部レビューでの指摘に対応。拡大表示の収まり、複数ファイル追加、
全消し後の復帰、単体墨消しの適用範囲ゼロ、範囲一覧からの選択、拡大表示の焦点
- v0.9 — サイズ圧縮の追加、画像取り込みの高速化と画質の選択
- v0.9.1 — ナビの「圧縮」を「整理」と「墨消し」の間へ。全画面表示で紙が枠より少し大きく
計算されていたのを修正 (スマホで右端が切れる・縦横比がわずかに崩れる)。
設定の行で、選択肢が長いときは入力欄を次の行へ送る
- v0.9.2 — ファイル名が長いと、全画面表示が画面より横に広がって
紙の右側と右上のボタンが切れていたのを修正
- v0.10 — 端末に合わせた並列処理、画像取り込みの Web Worker 化、GPU の利用 (自動 / 使わない)、
「この端末で速さを測る」
- v0.11 — 大きなPDF向けのストリーミング処理 (ファイルを少しずつ読む・ページができた順に書き出す・
ZIP を少しずつ作る)
- v0.12 — ページを画像で保存 (PNG / JPEG / WebP / AVIF)、画像の取り込みに WebP / AVIF / HEIC を追加、
速さの計測を測り直しに強くした
- v0.12.1 — AVIF の書き出しを約5倍速く (書き出し器の速さ設定 6 → 8、大きさは同じ)、
経過時間の表示と、応答がなくなったときの打ち切りを追加
- v0.12.2 — 外部レビューでの指摘に対応。ファイルを部分的に読めないとき止まったままになる問題、
速さの計測が設定を書き換える問題、いちばん速い組み合わせの選び方、GPU 設定の反映、サムネイルの再描画と片付け、
中止の取りこぼし。最初に読み込む JS を 1.16MB → 0.29MB に
- v0.13 — GPU を用途ごとに分けた (画面の表示は使う・書き出しは測って速いときだけ使う)
- v0.13.1 (現在) — 「この端末で速さを測る」を「この端末に合わせる」に。押すと測って、そのまま設定になる
- 以降 — PWA化 (オフライン対応)、ページ整理の書き出しのストリーミング化
既知の制限
- パスワード保護されたPDFは扱えません
- 墨消しとサイズ圧縮の出力は画像PDFになるため、文字検索・テキスト選択・しおり・注釈は失われます
- すでに圧縮された画像PDFや、文字中心のPDFは、サイズ圧縮しても小さくならないことがあります
- ページ数が多いPDFや高解像度の指定は、端末のメモリを多く使います
(墨消し・圧縮・一括はストリーミング処理で抑えていますが、ページ整理の書き出しは全体を組み立てます)
ライセンス
MIT License — LICENSE を参照してください。
同梱しているライブラリのライセンス:
- pdf.js — Apache License 2.0
- pdf-lib — MIT
- dnd-kit — MIT
- fflate — MIT
- @jsquash/avif (Squoosh の AVIF 書き出し器 / libavif・libaom) — Apache-2.0 (libaom は BSD-2-Clause)
- React — MIT