---
url: /pdf-agent-stack/ja/reference/mcp/pdf-reader.md
description: pdf-reader-mcp v0.17.0 の全 18 ツールの引数・型・既定値・戻り値（tools/list から自動生成）
---

# pdf-reader-mcp — ツールリファレンス

::: info
**v0.17.0** の `tools/list` ハンドシェイクから自動生成（18 ツール）。手で編集しない — 再生成は `node scripts/generate-reference.mjs`。日本語訳は翻訳メモリ（scripts/i18n）から適用され、原文が更新された項目は同期されるまで英語で表示される。
:::

**このページは自動生成リファレンス** — 全ツールの引数・型・既定値・戻り値を `tools/list`（正典 = サーバー実装）から写したもの。責務・設計思想・使いどころの解説は[解説ページ](/ja/mcp/pdf-reader)へ。

## ツール一覧

| ツール | 概要 |
|---|---|
| [`get_page_count`](#get-page-count) | PDF 文書の総ページ数を取得する。 |
| [`get_metadata`](#get-metadata) | タイトル・作成者・作成日・ページ数・PDF バージョン・構造情報など、PDF 文書のメタデータを抽出する。 |
| [`read_text`](#read-text) | Y 座標に基づく読み順を保って PDF 文書からテキストを抽出する。 |
| [`search_text`](#search-text) | PDF 文書内のテキストを検索する。 |
| [`read_images`](#read-images) | PDF 文書から埋め込み画像を PNG または JPEG ファイルとして抽出する。 |
| [`read_url`](#read-url) | URL から PDF を取得してテキストを抽出する。 |
| [`render_page`](#render-page) | PDF のページを PNG または JPEG 画像にラスタライズし、MCP の image コンテンツブロックで返す。 |
| [`summarize`](#summarize) | PDF 文書の概観レポートを手早く生成する。 |
| [`inspect_structure`](#inspect-structure) | カタログのエントリ・ページツリー・オブジェクト統計など、PDF の内部オブジェクト構造を調べる。 |
| [`inspect_catalog`](#inspect-catalog) | catalog 辞書（ISO 32000-2 §7.7.2、Table 29）に連なる文書レベルの構成要素を一覧する —— ページ内容ではなく、ページ単位で読むリーダーが落としてしまう部分: しおり、レイヤー、添付ファイル、XMP パケット、文書を開いたときに実行されるアクション。 |
| [`inspect_tags`](#inspect-tags) | アクセシビリティ評価のために、タグ付き PDF の構造ツリーを分析する。 |
| [`inspect_fonts`](#inspect-fonts) | PDF 文書で使われている全フォントをプロパティ付きで一覧する。 |
| [`inspect_annotations`](#inspect-annotations) | PDF 文書内の全注釈を抽出して種類別に分類する。 |
| [`inspect_signatures`](#inspect-signatures) | PDF 文書のデジタル署名フィールドを調べる。 |
| [`extract_tables`](#extract-tables) | タグ付き PDF の全 `<Table>` サブツリーを、構造化された行/セルのリストとして抽出する。 |
| [`extract_structured_text`](#extract-structured-text) | タグ付き PDF のテキストを論理コンテンツ順で抽出し、各断片に構造タイプのラベルを付ける。 |
| [`locate_objects`](#locate-objects) | 指定したオブジェクトがページ上のどこにあるかを報告する。 |
| [`compare_structure`](#compare-structure) | 2 つの PDF 文書の内部構造を比較し、差分を特定する。 |

## get_page_count

**Get PDF Page Count**

PDF 文書の総ページ数を取得する。

PDF ヘッダのみを読む軽量な操作で、本文全体は読まない。

### 引数

| 引数 | 型 | 必須 | 既定値 | 説明 |
|---|---|---|---|---|
| `file_path` | string (minLength 1) | **必須** |  | ローカル PDF ファイルへの絶対パス（例: "/path/to/document.pdf"） |

### 戻り値

ページ数（数値）。

例:

* どのページを抽出するか決める前の簡易チェック
* PDF ファイルが読めるかの確認

::: details 呼び出し例 — 「ページ数だけ教えて」

* 実測: v0.15.0
* 標本: `docs/specimens/publish-demo.pdf`（呼び出すときは絶対パス）

ヘッダだけ読む軽い操作です。

**パラメータ**

```jsonc
{
  "file_path": "/absolute/path/to/docs/specimens/publish-demo.pdf"
}
```

**返る値**

```jsonc
1
```

:::

## get_metadata

**Get PDF Metadata**

タイトル・作成者・作成日・ページ数・PDF バージョン・構造情報など、PDF 文書のメタデータを抽出する。

### 引数

| 引数 | 型 | 必須 | 既定値 | 説明 |
|---|---|---|---|---|
| `file_path` | string (minLength 1) | **必須** |  | ローカル PDF ファイルへの絶対パス（例: "/path/to/document.pdf"） |
| `response_format` | `"markdown"` | `"json"` | 任意 | `"markdown"` | 出力形式: "markdown" は人が読む用、"json" は構造化データ |

### 戻り値

メタデータ一式: タイトル・作成者・件名・キーワード・作成アプリ・生成アプリ・作成/更新日時・ページ数・PDF バージョン・linearized/暗号化/タグ付き/署名フラグ・ファイルサイズ。

例:

* 台帳管理用に文書プロパティを取得
* タグ付き PDF か確認（アクセシビリティ）
* PDF バージョン互換性の確認

::: details 呼び出し例 — 「タイトルとタグの有無を」

* 実測: v0.15.0
* 標本: `docs/specimens/publish-demo.pdf`（呼び出すときは絶対パス）
* `response_format`: `"json"`

**パラメータ**

```jsonc
{
  "file_path": "/absolute/path/to/docs/specimens/publish-demo.pdf",
  "response_format": "json"
}
```

**返る JSON**

```jsonc
{
  "title": "請求書（サンプル）— pdf-publish デモ",
  "author": "PDF Agent Stack",
  "pageCount": 1,
  "pdfVersion": "1.7",
  "isEncrypted": false,
  "isTagged": true,
  "hasSignatures": false,
  "fileSize": 88943
}
```

`isTagged` は観測です。PDF/UA かどうかの判定ではありません。
:::

## read_text

**Read PDF Text**

Y 座標に基づく読み順を保って PDF 文書からテキストを抽出する。

テキストはページごとに抽出され、垂直位置（上→下）、次いで水平位置（左→右）で並べ替えられ、自然な読み順になる。

`/ActualText` 置換（ISO 32000-2 §14.9.4）は、同条項が定義する 2 つの経路 — 構造要素の `/ActualText` と、`Span` マーク付きコンテンツのプロパティリスト内のもの — の両方で解決される。後者はタグなし文書にも現れる。そのため ActualText として運ばれる語（合字の置換・ハイフネーション処理）は、グリフの形ではなく、ページを見る人が目にする綴りで読める。

**タグ付き** PDF で順序が重要な場合は、依然として `extract_structured_text` の方が適している。あちらは論理コンテンツ順（ISO 32000-2 §14.8.2.5）で返すのに対し、read_text は座標で並べ替えるだけだからである。タグ付き PDF の表は `extract_tables` で読むのが最善。

**タグなし**の多段組 PDF（構造ツリーを持たない旧式の新旧対照表 PDF など）では、`split_columns: 2` または `3` を渡すと X 座標で左から右へ項目を振り分ける。

U+3000 全角空白を視覚的な字下げに使う日本語の帳票・様式 PDF では、`compact_whitespace: true` を渡すと連続する空白が 1 つの ASCII 空白に畳まれる。内容を失わずにトークン消費を 20〜40% 削減できる。

### 引数

| 引数 | 型 | 必須 | 既定値 | 説明 |
|---|---|---|---|---|
| `file_path` | string (minLength 1) | **必須** |  | ローカル PDF ファイルへの絶対パス（例: "/path/to/document.pdf"） |
| `pages` | string | 任意 |  | 処理するページ範囲。形式: "1-5"・"3"・"1,3,5-7"。省略時は全ページ。 |
| `response_format` | `"markdown"` | `"json"` | 任意 | `"markdown"` | 出力形式: "markdown" は人が読む用、"json" は構造化データ |
| `split_columns` | integer (1–3) | 任意 |  | テキスト並べ替えに使う段数。1（既定）= 従来の Y ソート。2 または 3 = X 座標で左から右へ振り分け。Y ソートでは段が交錯するタグなしの新旧対照表 / 2 段組 PDF に使う。適切な `<Table>` マークアップを持つタグ付き PDF は extract_tables を使うこと。 |
| `compact_whitespace` | boolean | 任意 |  | true にすると連続空白（全角空白 U+3000 含む）を 1 つの ASCII 空白に畳み、各行をトリムする。日本語の帳票様式 PDF でトークン消費を削減する。既定: false（空白の正規化なし）。 |

### 戻り値

`{ scope, pages }`。`pages` はページ番号ごとに整理された抽出テキストで、冒頭に抽出可能性の集計が付く。`split_columns >= 2` では列の間が空行で区切られ、下流の LLM が列を見分けられる。

例:

* 全テキスト抽出: { file_path: "/path/to/doc.pdf" }
* タグなしの新旧対照表: { file_path: "/path/to/older-shinkyu.pdf", split_columns: 2 }
* 日本語の帳票・様式: { file_path: "/path/to/form.pdf", compact_whitespace: true }

::: details 呼び出し例 — 「1 ページ目のテキストを」

* 実測: v0.15.0
* 標本: `docs/specimens/publish-demo.pdf`（呼び出すときは絶対パス）
* `pages`: `"1"`
* `response_format`: `"json"`

この標本はタグ付きなので、順序が要るときは [`extract_structured_text`](#extract-structured-text) が先です。

**パラメータ**

```jsonc
{
  "file_path": "/absolute/path/to/docs/specimens/publish-demo.pdf",
  "pages": "1",
  "response_format": "json"
}
```

**返る JSON**

```jsonc
{
  "scope": {
    "textExtraction": { "status": "read" },
    "extractabilityObservation": { "status": "read" }
  },
  "pages": [
    {
      "page": 1,
      "text": "請求書（サンプル）— pdf-publish デモ\n請求書（サンプル）\n株式会社サンプル商事 御中\n…",
      "extractability": {
        "page": 1,
        "unmappableFonts": [],
        "state": "extracted"
      }
    }
  ]
}
```

`extractability.state` が `no_text_layer` または `not_extractable` なら、次は [`render_page`](#render-page) です。
:::

## search_text

**Search PDF Text**

PDF 文書内のテキストを検索する。一致位置を前後の文脈付きで返す。

全ページまたは指定ページを対象に、大文字小文字を区別せず検索する。各一致にはページ番号・一致テキスト・設定可能な前後文脈が含まれる。

検索は `read_text` が返すのと同じテキストに対して走るため、`/ActualText` 置換（ISO 32000-2 §14.9.4）後の綴りでヒットする。ActualText として運ばれる語（合字の置換・ハイフネーション処理）は、グリフの形ではなくビューアが表示する綴りで見つかる。まれにページのマーク付きコンテンツを抽出テキストと突き合わせられず、置換が未解決のまま残ることがある。ヒット 0 件の検索でそれが起きた場合、結果に該当ページを名指しする `note` が付く。

### 引数

| 引数 | 型 | 必須 | 既定値 | 説明 |
|---|---|---|---|---|
| `file_path` | string (minLength 1) | **必須** |  | ローカル PDF ファイルへの絶対パス（例: "/path/to/document.pdf"） |
| `query` | string (minLength 1) | **必須** |  | 検索するテキスト（大文字小文字を区別しない） |
| `pages` | string | 任意 |  | 処理するページ範囲。形式: "1-5"・"3"・"1,3,5-7"。省略時は全ページ。 |
| `context_chars` | integer (0–500) | 任意 | `80` | 各一致の前後に表示する文字数 |
| `max_results` | integer (1–100) | 任意 | `20` | 返す一致の最大数 |
| `response_format` | `"markdown"` | `"json"` | 任意 | `"markdown"` | 出力形式: "markdown" は人が読む用、"json" は構造化データ |

### 戻り値

ページ番号・一致テキスト・前後文脈付きの検索結果と、`scope`。`scope` はこの答えの背後にある 2 つの読みのどちらが行われたかを言う —— ページの文字を探すことと、その文字が Unicode に変換できるかを観測すること（ISO 32000-2 §9.10.1）である。検索そのものが行えなかったときは、`totalMatches` と `matches` が `0` と `[]` ではなく `null` になる。「探せなかった」と「探して見つからなかった」は別の答えである。

例:

* PDF 全体を検索: { file_path: "/path/to/doc.pdf", query: "digital signature" }
* ページを絞って検索: { file_path: "/path/to/doc.pdf", query: "error", pages: "1-10" }

::: details 呼び出し例 — 「『請求明細』は何ページ？」

* 実測: v0.15.0
* 標本: `docs/specimens/publish-demo.pdf`（呼び出すときは絶対パス）
* `query`: `"請求明細"`
* `response_format`: `"json"`

検索対象は `read_text` と同じテキストです。

**パラメータ**

```jsonc
{
  "file_path": "/absolute/path/to/docs/specimens/publish-demo.pdf",
  "query": "請求明細",
  "max_results": 3,
  "response_format": "json"
}
```

**返る JSON**

```jsonc
{
  "scope": {
    "textExtraction": { "status": "read" },
    "extractabilityObservation": { "status": "read" }
  },
  "query": "請求明細",
  "totalMatches": 1,
  "matches": [
    {
      "page": 1,
      "lineIndex": 5,
      "text": "請求明細",
      "contextBefore": "",
      "contextAfter": ""
    }
  ],
  "truncated": false
}
```

:::

## read_images

**Read PDF Images**

PDF 文書から埋め込み画像を PNG または JPEG ファイルとして抽出する。

各画像は MCP の image コンテンツブロックで返るため、視覚対応モデルがそのまま見られる。text ブロックには全画像のメタ情報（ページ・インデックス・ファイル内の寸法・返した寸法・色空間・エンコード後バイト数）を一覧する。

返すのはページが描く画像 XObject であって、ページの絵ではない。内容がベクタ描画のページや、見たいものがテキストであるページは、このツールの対象外。

応答サイズには上限がある: 1 回の呼び出しにつきエンコード済み画像データで最大 4 MB。予算を超えた画像は text ブロックに理由付きで名指しされ、返されない — 黙って落とされることはない。200 dpi の A4 スキャンはそれだけで約 11.6 MB のピクセルになるため、スキャンを扱うときは `pages`・`max_width`・`max_height` を渡すこと。

### 引数

| 引数 | 型 | 必須 | 既定値 | 説明 |
|---|---|---|---|---|
| `file_path` | string (minLength 1) | **必須** |  | ローカル PDF ファイルへの絶対パス（例: "/path/to/document.pdf"） |
| `pages` | string | 任意 |  | 処理するページ範囲。形式: "1-5"・"3"・"1,3,5-7"。省略時は全ページ。 |
| `format` | `"png"` | `"jpeg"` | 任意 |  | 返す画像のエンコード形式。png（既定）は可逆。jpeg は小さく、アルファは白に合成して落とす。 |
| `quality` | integer (1–100) | 任意 |  | JPEG 品質 1-100（既定 80）。format が png のときは無視される。 |
| `max_width` | integer (1–10000) | 任意 |  | この幅を超える画像を縮小する（元ピクセルの面積平均）。拡大は決してしない。省略時は各画像を元の寸法のまま返す。 |
| `max_height` | integer (1–10000) | 任意 |  | この高さを超える画像を縮小する。拡大は決してしない。 |

### 戻り値

メタ情報の表と省略の一覧を載せた text ブロック、続いて返す画像 1 つにつき 1 つの image コンテンツブロック。

例:

* 全画像抽出: { file_path: "/path/to/doc.pdf" }
* スキャンページを見られる大きさで: { file_path: "/path/to/scan.pdf", pages: "1", max_width: 1200, format: "jpeg" }

## read_url

**Read PDF from URL**

URL から PDF を取得してテキストを抽出する。このツールが返すのは**テキストだけ**である — 下記の射程の注記を参照。

指定 URL から PDF をダウンロードし、Y 座標に基づく読み順でテキストを抽出する。HTTP / HTTPS に対応。最大ファイルサイズ 50MB、タイムアウト 30 秒。

**射程 (#25):** 取得したバイト列は抽出後に破棄される — このツールは意図的に保存しない。本サーバの他のツールはすべて `file_path` を取るため、URL 上の PDF に search_text・inspect_structure・extract_tables・render_page などを使うには、**先に**ファイルをローカルディスクへダウンロードし（呼び出し側環境が持つ取得手段で）、そのパスを渡すこと。これにより本サーバの全ツールはファイルシステムに対して read-only のままでいられる — ファイルを書くのは reader の仕事ではない。read_url は 1 回きりの問い「この URL の文書には何が書いてあるか」のためにある。

`read_text` と同様に、**タグなし**の多段組 PDF 向けの `split_columns: 2 | 3` と、U+3000 / ASCII の連続空白を畳む `compact_whitespace: true` を受け付ける。タグ付き PDF は代わりに `extract_tables` を使うこと。

### 引数

| 引数 | 型 | 必須 | 既定値 | 説明 |
|---|---|---|---|---|
| `url` | string | **必須** |  | PDF ファイルを指す URL（HTTP または HTTPS） |
| `pages` | string | 任意 |  | 処理するページ範囲。形式: "1-5"・"3"・"1,3,5-7"。省略時は全ページ。 |
| `response_format` | `"markdown"` | `"json"` | 任意 | `"markdown"` | 出力形式: "markdown" は人が読む用、"json" は構造化データ |
| `split_columns` | integer (1–3) | 任意 |  | テキスト並べ替えに使う段数。1（既定）= 従来の Y ソート。2 または 3 = X 座標で左から右へ振り分け。Y ソートでは段が交錯するタグなしの新旧対照表 / 2 段組 PDF に使う。適切な `<Table>` マークアップを持つタグ付き PDF は extract_tables を使うこと。 |
| `compact_whitespace` | boolean | 任意 |  | true にすると連続空白（全角空白 U+3000 含む）を 1 つの ASCII 空白に畳み、各行をトリムする。日本語の帳票様式 PDF でトークン消費を削減する。既定: false（空白の正規化なし）。 |

### 戻り値

`{ scope, pages }`。read_text と同じ形で、`pages` はページ番号ごとの抽出テキスト、`scope` はその背後にある 2 つの読みのどちらが行われたかを言う —— ページから文字を取り出すことと、その文字が Unicode に変換できるかを観測すること（ISO 32000-2 §9.10.1）である。どちらも単独で失敗しうる。両方とも行えなかったときだけエラーになり、そのときは 2 つの理由を両方載せる。

例:

* リモート PDF を読む: { url: "https://example.com/document.pdf" }
* タグなし 2 段組 PDF: { url: "https://...", split_columns: 2 }
* 日本語の帳票: { url: "https://...", compact_whitespace: true }

## render_page

**Render PDF Page**

PDF のページを PNG または JPEG 画像にラスタライズし、MCP の image コンテンツブロックで返す。

テキストとして読めない文書のためのツールである: `read_text` が `no_text_layer` や `not_extractable` と報告するページ、ベクタ図形、フォーム、手書き、印影。`read_images` がページの埋め込む画像 XObject を取り出すだけなのに対し、こちらは**ページそのもの** — その上のすべて — を描く。

描画には WebAssembly にコンパイルされた PDFium（optionalDependencies の `@hyzyla/pdfium`）を使う。これは本サーバがテキストを読むのに使う pdf.js とは**別のエンジン**である点に注意 — 壊れたファイルに対する両者の挙動が異なる場合、一方の出力はもう一方の証拠にならない。依存が未インストールなら、このツールはその旨を返し、他のツールはすべて通常どおり動く。

`pages` は必須 — 描画はこのサーバで最も高価な操作であり、大きなスキャンの「全ページ」は既定値ではなく判断であるべきだから。応答が運ぶエンコード済み画像は最大 4 MB。予算を超えたページは理由付きで名指しされ、黙って落とされることはない。

### 引数

| 引数 | 型 | 必須 | 既定値 | 説明 |
|---|---|---|---|---|
| `file_path` | string (minLength 1) | **必須** |  | ローカル PDF ファイルへの絶対パス（例: "/path/to/document.pdf"） |
| `pages` | string (minLength 1) | **必須** |  | 描画するページ範囲。必須: 全ページの描画が暗黙に起きることはない。 |
| `dpi` | integer (36–600) | 任意 |  | ラスタライズ密度（既定 150）。PDF のポイントは 1/72 インチ。 |
| `max_width` | integer (1–10000) | 任意 |  | 描画幅のピクセル上限。dpi より小さくなる場合はこちらが優先。 |
| `format` | `"png"` | `"jpeg"` | 任意 |  | png（既定・可逆）または jpeg（小さい — スキャンには通常こちら）。 |
| `quality` | integer (1–100) | 任意 |  | JPEG 品質 1-100（既定 80）。png では無視される。 |

### 戻り値

ページごとのメタ情報（pt 寸法・ピクセル寸法・実効 dpi・バイト数）と省略の一覧を載せた text ブロック、続いて描画したページ 1 つにつき 1 つの image コンテンツブロック。

ページのラスタライズには上限のない時間がかかることがある。タイリングパターン（ISO 32000-2 §8.7.3.1）の `/XStep` や `/YStep` が 0 に近い大きさだと、天文学的な枚数のタイルを敷くことになる —— 条文が禁じているのは 0 だけである。そのため 1 ページにつき 20 秒の予算を置いてある（`PDF_READER_RENDER_TIMEOUT_MS` で変えられる）。描画は主スレッドの外で走るので、終わらないページがあってもサーバは応答を返し続ける。そのページはそこで止めて、省略の一覧に理由とともに出す。その前に描けたページはそのまま返り、後ろのページは「始めなかった」として別に報告される —— 「描けなかった」と「始めなかった」は別の答えである。

例:

* スキャンページ: { file_path: "/path/to/scan.pdf", pages: "1", format: "jpeg" }
* 図面を高精細で: { file_path: "/path/to/doc.pdf", pages: "3", dpi: 300 }

## summarize

**Summarize PDF**

PDF 文書の概観レポートを手早く生成する。

メタデータ・テキスト有無の確認・画像数・1 ページ目のテキストプレビューを 1 つの要約にまとめる。どの詳細ツールを使うか決める前の最初の一手に向く。

### 引数

| 引数 | 型 | 必須 | 既定値 | 説明 |
|---|---|---|---|---|
| `file_path` | string (minLength 1) | **必須** |  | ローカル PDF ファイルへの絶対パス（例: "/path/to/document.pdf"） |
| `response_format` | `"markdown"` | `"json"` | 任意 | `"markdown"` | 出力形式: "markdown" は人が読む用、"json" は構造化データ |

### 戻り値

要約の内容: ページ数・PDF バージョン・ファイルサイズ・タグ付き/暗号化/署名フラグ・テキスト有無・文書全体のテキスト抽出可能性・完全には抽出できないページ一覧・画像数・1 ページ目のテキストプレビュー・`next` の提案。

この要約は 5 つの別々の読みから作られる —— 文書情報・1 ページ目のテキスト・画像数・抽出可能性の観測・XMP の宣言 —— で、どれも単独で失敗しうる。どれが行われたかは `scope` が言う。読みが行われなかった項目は `null` であり、`0` でも `false` でも `""` でもない。「読んでいない」と「読んで無かった」は別の答えである。`next` も、観測できなかった前提については何も述べない。

例:

* 概観を手早く: { file_path: "/path/to/doc.pdf" }
* 機械可読で: { file_path: "/path/to/doc.pdf", response_format: "json" }

::: details 呼び出し例 — 「この PDF の概要を見せて」

* 実測: v0.15.0
* 標本: `docs/specimens/publish-demo.pdf`（呼び出すときは絶対パス）
* `response_format`: `"json"`

**パラメータ**

```jsonc
{
  "file_path": "/absolute/path/to/docs/specimens/publish-demo.pdf",
  "response_format": "json"
}
```

**返る JSON**（`textPreview` は省略）

```jsonc
{
  "scope": {
    "metadata": { "status": "read" },
    "textPreview": { "status": "read" },
    "imageCount": { "status": "read" },
    "extractabilityObservation": { "status": "read" }
  },
  "metadata": {
    "title": "請求書（サンプル）— pdf-publish デモ",
    "pageCount": 1,
    "pdfVersion": "1.7",
    "isEncrypted": false,
    "isTagged": true,
    "hasSignatures": false,
    "fileSize": 88943
  },
  "imageCount": 0,
  "hasText": true,
  "textExtractability": "extracted",
  "unreadablePages": [],
  "next": [
    "isTagged is true: extract_structured_text returns the body in logical content order …"
  ]
}
```

`isTagged: true` と `textExtractability: "extracted"` なので、次は [`extract_structured_text`](#extract-structured-text) です。`next` は提案であり、強制ではありません。
:::

## inspect_structure

**Inspect PDF Structure**

カタログのエントリ・ページツリー・オブジェクト統計など、PDF の内部オブジェクト構造を調べる。

### 引数

| 引数 | 型 | 必須 | 既定値 | 説明 |
|---|---|---|---|---|
| `file_path` | string (minLength 1) | **必須** |  | ローカル PDF ファイルへの絶対パス（例: "/path/to/document.pdf"） |
| `response_format` | `"markdown"` | `"json"` | 任意 | `"markdown"` | 出力形式: "markdown" は人が読む用、"json" は構造化データ |

### 戻り値

カタログのエントリ（キーと COS の型）・ページツリー情報（ページ数・MediaBox のサンプル）・オブジェクト統計・暗号化状態。

オブジェクト統計は 3 つの数を別々に返す:

* byType: 各間接オブジェクトの COS の型（ISO 32000-2 §7.3）。dict / stream / array / name /
  string / integer / real / boolean / null / ref のいずれか
* byDocType: 各辞書の /Type（Catalog, Pages, Page, Font, ObjStm, XRef, ...）
* unreadable: 相互参照表が名指ししているが読めなかったオブジェクトの数。
  totalObjects とは別に数える —— 0 は「全部読めた」であって「何も見ていない」ではない。

例:

* 構造的特徴を見るためにカタログを調べる
* PDF のオブジェクトとストリームを数える
* 文書全体のページ寸法を確認する

::: details 呼び出し例 — 「カタログに何があるか」

* 実測: v0.15.0
* 標本: `docs/specimens/publish-demo.pdf`（呼び出すときは絶対パス）
* `response_format`: `"json"`

`catalog` は一部だけ残しています。

**パラメータ**

```jsonc
{
  "file_path": "/absolute/path/to/docs/specimens/publish-demo.pdf",
  "response_format": "json"
}
```

**返る JSON**

```jsonc
{
  "catalog": [
    { "key": "Type", "type": "name", "value": "Catalog" },
    { "key": "Pages", "type": "ref", "value": "ref(1)" },
    { "key": "StructTreeRoot", "type": "ref", "value": "ref(5)" },
    { "key": "Lang", "type": "string", "value": "ja" }
  ],
  "pageTree": {
    "totalPages": 1,
    "mediaBoxSamples": [{ "page": 1, "width": 595.28, "height": 841.89 }]
  },
  "objectStats": {
    "totalObjects": 52,
    "unreadable": 0
  },
  "isEncrypted": false,
  "pdfVersion": "1.7"
}
```

`unreadable: 0` は「全オブジェクトを読んだ」です。「何も調べていない」ではありません。
:::

## inspect_catalog

**Inspect PDF Catalog**

catalog 辞書（ISO 32000-2 §7.7.2、Table 29）に連なる文書レベルの構成要素を一覧する —— ページ内容ではなく、ページ単位で読むリーダーが落としてしまう部分: しおり、レイヤー、添付ファイル、XMP パケット、文書を開いたときに実行されるアクション。

### 引数

| 引数 | 型 | 必須 | 既定値 | 説明 |
|---|---|---|---|---|
| `file_path` | string (minLength 1) | **必須** |  | ローカル PDF ファイルへの絶対パス（例: "/path/to/document.pdf"） |
| `max_outline_items` | integer (1–500) | 任意 | `50` | 一覧に載せるアウトライン（しおり）項目の数。件数と深さは常にツリー全体で計算する。 |
| `include_xmp` | boolean | 任意 | `false` | XMP パケットの本文そのものを返す（上限 64 KiB）。既定はオフ。宣言された値はどちらでも抽出する。 |
| `response_format` | `"markdown"` | `"json"` | 任意 | `"markdown"` | 出力形式: "markdown" は人が読む用、"json" は構造化データ |

## inspect_tags

**Inspect Tagged PDF Structure**

アクセシビリティ評価のために、タグ付き PDF の構造ツリーを分析する。

### 引数

| 引数 | 型 | 必須 | 既定値 | 説明 |
|---|---|---|---|---|
| `file_path` | string (minLength 1) | **必須** |  | ローカル PDF ファイルへの絶対パス（例: "/path/to/document.pdf"） |
| `response_format` | `"markdown"` | `"json"` | 任意 | `"markdown"` | 出力形式: "markdown" は人が読む用、"json" は構造化データ |

### 戻り値

タグ付きかどうか・role 付き構造ツリー階層・最大ネスト深さ・要素総数・role 分布（例: Document, P, H1, Table, Figure）。

例:

* アクセシビリティ（PDF/UA）向けにタグ付きか確認
* タグ階層と role 分布を調べる
* 文書構造の品質を評価する

::: details 呼び出し例 — 「タグ構造を観測して」

* 実測: v0.15.0
* 標本: `docs/specimens/publish-demo.pdf`（呼び出すときは絶対パス）
* `response_format`: `"json"`

木の全体は省略し、集計だけ示します。

**パラメータ**

```jsonc
{
  "file_path": "/absolute/path/to/docs/specimens/publish-demo.pdf",
  "response_format": "json"
}
```

**返る JSON**

```jsonc
{
  "isTagged": true,
  "maxDepth": 5,
  "totalElements": 29,
  "roleCounts": {
    "Document": 1,
    "H1": 2,
    "P": 3,
    "H2": 2,
    "Table": 1,
    "TR": 4,
    "TH": 4,
    "TD": 12
  }
}
```

合否は返しません。PDF/UA の判定は pdf-verify-mcp の `validate_conformance` です。
:::

## inspect_fonts

**Inspect PDF Fonts**

PDF 文書で使われている全フォントをプロパティ付きで一覧する。

### 引数

| 引数 | 型 | 必須 | 既定値 | 説明 |
|---|---|---|---|---|
| `file_path` | string (minLength 1) | **必須** |  | ローカル PDF ファイルへの絶対パス（例: "/path/to/document.pdf"） |
| `response_format` | `"markdown"` | `"json"` | 任意 | `"markdown"` | 出力形式: "markdown" は人が読む用、"json" は構造化データ |

### 戻り値

フォント名・型（TrueType, Type1, CIDFont 等）・エンコーディング・埋め込み/サブセット状況・使用ページ。

例:

* 全フォント埋め込みか確認（PDF/A・PDF/X の前提）
* フォントの型とエンコーディングを特定
* 特定フォントを使うページを探す

::: details 呼び出し例 — 「どんなフォントが埋め込まれている？」

* 実測: v0.15.0
* 標本: `docs/specimens/publish-demo.pdf`（呼び出すときは絶対パス）
* `response_format`: `"json"`

**パラメータ**

```jsonc
{
  "file_path": "/absolute/path/to/docs/specimens/publish-demo.pdf",
  "response_format": "json"
}
```

**返る JSON**

```jsonc
{
  "fonts": [
    {
      "name": "OAFEEB+NotoSansJP-Regular",
      "type": "Type0",
      "encoding": "Identity-H",
      "isEmbedded": true,
      "isSubset": true,
      "pagesUsed": [1]
    }
  ],
  "totalFontCount": 1,
  "embeddedCount": 1,
  "subsetCount": 1,
  "pagesScanned": 1
}
```

:::

## inspect_annotations

**Inspect PDF Annotations**

PDF 文書内の全注釈を抽出して種類別に分類する。

### 引数

| 引数 | 型 | 必須 | 既定値 | 説明 |
|---|---|---|---|---|
| `file_path` | string (minLength 1) | **必須** |  | ローカル PDF ファイルへの絶対パス（例: "/path/to/document.pdf"） |
| `pages` | string | 任意 |  | 処理するページ範囲。形式: "1-5"・"3"・"1,3,5-7"。省略時は全ページ。 |
| `response_format` | `"markdown"` | `"json"` | 任意 | `"markdown"` | 出力形式: "markdown" は人が読む用、"json" は構造化データ |

### 戻り値

注釈総数・種類別（Link, Widget, Highlight, Text 等）とページ別の内訳・リンク/フォーム/マークアップ有無のフラグ・個別詳細。

例:

* フォームフィールド（Widget 注釈）の有無を確認
* 文書内の全リンクを探す
* マークアップ注釈（ハイライト・コメント）の棚卸し

::: details 呼び出し例 — 「注釈はあるか」

* 実測: v0.15.0
* 標本: `docs/specimens/publish-demo.pdf`（呼び出すときは絶対パス）
* `response_format`: `"json"`

0 件は「読めなかった」ではなく「読んで無い」です。

**パラメータ**

```jsonc
{
  "file_path": "/absolute/path/to/docs/specimens/publish-demo.pdf",
  "response_format": "json"
}
```

**返る JSON**

```jsonc
{
  "totalAnnotations": 0,
  "bySubtype": {},
  "byPage": { "1": 0 },
  "annotations": [],
  "hasLinks": false,
  "hasForms": false,
  "hasMarkup": false
}
```

:::

## inspect_signatures

**Inspect PDF Digital Signatures**

PDF 文書のデジタル署名フィールドを調べる。

### 引数

| 引数 | 型 | 必須 | 既定値 | 説明 |
|---|---|---|---|---|
| `file_path` | string (minLength 1) | **必須** |  | ローカル PDF ファイルへの絶対パス（例: "/path/to/document.pdf"） |
| `response_format` | `"markdown"` | `"json"` | 任意 | `"markdown"` | 出力形式: "markdown" は人が読む用、"json" は構造化データ |

### 戻り値

署名フィールド総数・署名済み/未署名の内訳・各フィールドの詳細（署名者名・理由・場所・署名日時・filter/subFilter）。

注意: 本ツールは署名フィールドの構造を調べるだけで、暗号学的な署名検証は行わない。

例:

* PDF が電子署名されているか確認
* 署名者情報と署名日時を調べる
* 署名フィールドの構造を確認

::: details 呼び出し例 — 「署名フィールドの構造を見せて」

* 実測: v0.15.0
* 標本: `docs/specimens/selfmade-pades-lta.pdf`（呼び出すときは絶対パス）
* `response_format`: `"json"`

暗号学的検証はしません。

**パラメータ**

```jsonc
{
  "file_path": "/absolute/path/to/docs/specimens/selfmade-pades-lta.pdf",
  "response_format": "json"
}
```

**返る JSON**

```jsonc
{
  "totalFields": 2,
  "signedCount": 2,
  "unsignedCount": 0,
  "fields": [
    {
      "fieldName": "Sig1",
      "isSigned": true,
      "reason": "known-good specimen",
      "signingTime": "D:20260811163237+09'00'",
      "filter": "Adobe.PPKLite",
      "subFilter": "ETSI.CAdES.detached"
    },
    {
      "fieldName": "Timestamp-938ea022-8782-4761-b0a2-a5ba44d069e4",
      "isSigned": true,
      "filter": "Adobe.PPKLite",
      "subFilter": "ETSI.RFC3161"
    }
  ],
  "note": "Cryptographic signature verification is not performed. Only field structure is inspected."
}
```

署名が数学的に有効かは pdf-verify-mcp の `verify_signatures` / `verify_integrity` です。
:::

## extract_tables

**Extract Tables (Tagged PDF)**

タグ付き PDF の全 `<Table>` サブツリーを、構造化された行/セルのリストとして抽出する。オプションで Markdown 表としても描画できる。

仕組み: 文書の StructTreeRoot を深さ優先で走査し（`extract_structured_text` / `inspect_tags` と同じウォーカー）、各 `<TR>` → `<TH>`/`<TD>` のセルテキストを取り出し、カーニング空白を畳む（例: "消 費 税 法" → "消費税法"）。これにより多段組の表（新旧対照表 PDF に典型）で読み順抽出が陥る失敗モードを回避する。

改ページをまたいで続く表は 1 つの表である（ISO 32000-2 §14.8.2.5 NOTE 2）— `pages` は配列であり、指定ページ範囲に触れる表は丸ごと返る。セルテキストは `/ActualText` 置換（§14.9.4）を反映する。

### 引数

| 引数 | 型 | 必須 | 既定値 | 説明 |
|---|---|---|---|---|
| `file_path` | string (minLength 1) | **必須** |  | ローカル PDF ファイルへの絶対パス（例: "/path/to/document.pdf"） |
| `pages` | string | 任意 |  | 処理するページ範囲。形式: "1-5"・"3"・"1,3,5-7"。省略時は全ページ。 |
| `response_format` | `"markdown"` | `"json"` | 任意 | `"markdown"` | 出力形式: "markdown" は人が読む用、"json" は構造化データ |

### 戻り値

Markdown — `# Extracted Tables` の要約ブロックに続き、表ごとに GFM 表付きの `## Table N — Page(s) …` 節。

JSON — `{ isTagged, tables: [{ pages, index, headerRows, bodyRows, footerRows }], totalTables, pagesScanned, note? }`。`index` は文書全体の論理コンテンツ順での 1 始まりの位置。

制限:

* タグなし PDF は空の結果と `note` を返す。
* colspan/rowspan は反映されない（セルはソース順に列挙）。
* 入れ子の表は個別に出力されない（テキストは外側のセルに現れる）。

例:

* 改正通達 PDF から新旧対照表を取り出して差分を取る
* 帳票（様式）の表を構造化データに変換する

::: details 呼び出し例 — 「この表を構造化して」

* 実測: v0.15.0
* 標本: `docs/specimens/publish-demo.pdf`（呼び出すときは絶対パス）
* `response_format`: `"json"`

**パラメータ**

```jsonc
{
  "file_path": "/absolute/path/to/docs/specimens/publish-demo.pdf",
  "response_format": "json"
}
```

**返る JSON**

```jsonc
{
  "isTagged": true,
  "tables": [
    {
      "pages": [1],
      "index": 1,
      "headerRows": [],
      "bodyRows": [
        {
          "cells": [
            { "text": "品目", "isHeader": true },
            { "text": "数量", "isHeader": true },
            { "text": "単価", "isHeader": true },
            { "text": "金額", "isHeader": true }
          ]
        },
        {
          "cells": [
            { "text": "PDF監査サービス", "isHeader": false },
            { "text": "1", "isHeader": false },
            { "text": "50,000", "isHeader": false },
            { "text": "50,000", "isHeader": false }
          ]
        }
        // … 「タグ付きPDF生成」「合計」の行が続く
      ],
      "footerRows": []
    }
  ],
  "totalTables": 1,
  "pagesScanned": 1
}
```

タグ無し PDF では表は空で、`note` が付きます。
:::

## extract_structured_text

**Extract Structured Text**

タグ付き PDF のテキストを論理コンテンツ順で抽出し、各断片に構造タイプのラベルを付ける。

「H1 のテキストは何か」に答えるツールである — read_text（フラット・座標順）、inspect_tags（構造のみ・テキストなし）、extract_tables（テキストは表のみ）のいずれにもできない。

### 引数

| 引数 | 型 | 必須 | 既定値 | 説明 |
|---|---|---|---|---|
| `file_path` | string (minLength 1) | **必須** |  | ローカル PDF ファイルへの絶対パス（例: "/path/to/document.pdf"） |
| `pages` | string | 任意 |  | 処理するページ範囲。形式: "1-5"・"3"・"1,3,5-7"。省略時は全ページ。範囲に触れる要素は、範囲外に続いていても丸ごと返る。 |
| `roles` | string\[] | 任意 |  | 含める構造タイプ。例: アウトライン抽出なら \["H1","H2"]。省略時は全 role。 |
| `include_bbox` | boolean | 任意 | `false` | 各要素の描画位置も boxes として報告する: PDF 既定ユーザー空間（原点は左下・pt・正規化済み）でページごとに 1 矩形 — pdf-writer-mcp の add_annotation が受け取る形。各矩形には basis が付く: "layout-attribute-bbox"（ファイルが宣言する /BBox）または "text-extent"（要素のテキストから実測。画像・ベクター描画は寄与しない）。矩形の無い要素には理由を述べる boxNote が付く。既定は off: 全ページをもう一巡するコストがかかる。 |
| `response_format` | `"markdown"` | `"json"` | 任意 | `"markdown"` | 出力形式: "markdown" は人が読む用、"json" は構造化データ |

### 戻り値

isTagged・文書の言語・論理コンテンツ順の要素のフラットなリスト。
各要素は role・depth（ネスト。トップレベルは 0）・text・pages と、必要に応じて alt / label / rows / boxes / boxNote を持つ。

`scope` は、この答えの背後にある 2 つの読みのどちらが行われたかを言う —— 構造ツリーを読むことと、その下の文字が Unicode に変換できるかを観測すること（ISO 32000-2 §9.10.1）である。構造ツリーを読めなかったときは、`isTagged` と `elements` が `false` と `[]` ではなく `null` になる。「読んでいない」と「読んでタグが無かった」は別の答えである。

リストは入れ子ではなく depth フィールド付きのフラット構造である — 深さ優先の行きがけ順 + depth で木は正確に符号化され、失われるものはない。例外は Table で、rows を持つ。表は二次元であり、depth では「2 行目の 3 列目」を表せないからである。

主な性質:

* 順序は文書の構造ツリーの深さ優先走査で、ISO 32000-2 §14.8.2.5 が定義する論理コンテンツ順そのものである。
* ページをまたぐ要素は 1 つの要素のまま（pages は配列）。改ページで分かれた段落は 2 つではなく 1 つの段落として返る。
* ActualText があればグリフを置き換える（§14.9.4:「説明ではなく置換」）。Alt は alt に分けて報告され、text には決して入らない — テキストを持たない内容の説明であり（§14.9.3）、本文に漏れてはならない。
* Lbl（リストの行頭記号や番号）は label に報告され、text には混ざらない。
* アーティファクト（ページ番号・柱）は除外される: §14.8.2.5 NOTE 3 が論理コンテンツ順の外に置いている。

include_bbox 付き（「この段落はどこにあるか」に答え、注釈を置けるようにする）:
各要素に boxes が付く — ページごとに 1 矩形。ページをまたぐ要素に単一の矩形は無いからである。各矩形は PDF 既定ユーザー空間（原点は左下・pt・正規化済み）の { page, rect: {x1,y1,x2,y2}, basis } で、pdf-writer-mcp の add_annotation がそのまま受け取る形 — 途中で座標系を解釈し直す必要はない。/Rotate やずれた /CropBox の影響も受けない。

basis は主張の強さを示し、両者は同じ種類の主張ではない:

* layout-attribute-bbox — ファイルが要素について宣言する /BBox（ISO 32000-2 Table 379）。生成者による自己申告の幾何で、そのまま報告される。テキストを持たない内容ではこれが唯一の情報源。
* text-extent — 要素が持つテキストから実測した値: ベースライン原点とフォントの ascent/descent。つまり行ボックスであり、グリフの輪郭ではない。画像やベクター描画は寄与しない。

宣言された /BBox が中で実測されたテキストを覆わない場合、その食い違いは均されず boxNote で報告される。

矩形を持たない要素は boxes を持たず、理由を述べる boxNote が付く — 画像 1 つを持つ Figure が典型である（§14.8.4.8.5: そのような要素は「BBox 属性を持つべき」）。「無い」は「大きさゼロ」ではなく、推測もしない。

タグなし PDF は理由付きの isTagged: false を返し、要素は返さない。座標からの推測は行わない — §14.8.2.5 NOTE 1 はページ順が論理順と一致するとは限らないと明記しており、推測は信頼できないからである。構造の足場を足すには pdf-writer-mcp の ensure_tagged を使って再試行すること。

例:

* 文書のアウトラインを抽出: { file_path: "/doc.pdf", roles: \["H1","H2","H3"] }
* リフロー/変換用に構造を保ったまま内容を取得: { file_path: "/doc.pdf" }
* 特定の節のページのテキストを読む: { file_path: "/doc.pdf", pages: "4-6" }
* 注釈を置く場所を探す:
  { file_path: "/doc.pdf", roles: \["P"], include_bbox: true } → 矩形をそのまま pdf-writer-mcp の add_annotation へ。逆方向（差分が報告したオブジェクト番号 → 矩形）は locate_objects を使う。

::: details 呼び出し例 — 「見出しと段落を論理読み順で、位置付きで」

* 実測: v0.15.0
* 標本: `docs/specimens/publish-demo.pdf`（呼び出すときは絶対パス）
* `pages`: `"1"`
* `include_bbox`: `true`
* `response_format`: `"json"`

`elements` は先頭 2 件だけ残しています。

**パラメータ**

```jsonc
{
  "file_path": "/absolute/path/to/docs/specimens/publish-demo.pdf",
  "pages": "1",
  "include_bbox": true,
  "response_format": "json"
}
```

**返る JSON**

```jsonc
{
  "scope": {
    "textExtraction": { "status": "read" },
    "extractabilityObservation": { "status": "read" }
  },
  "isTagged": true,
  "lang": "ja",
  "elements": [
    {
      "role": "H1",
      "depth": 1,
      "text": "請求書（サンプル）— pdf-publish デモ",
      "pages": [1],
      "boxes": [
        {
          "page": 1,
          "rect": { "x1": 56, "y1": 766.306, "x2": 375.194, "y2": 792.37 },
          "basis": "text-extent"
        }
      ]
    },
    {
      "role": "P",
      "depth": 1,
      "text": "株式会社サンプル商事 御中",
      "pages": [1],
      "boxes": [
        {
          "page": 1,
          "rect": { "x1": 56, "y1": 699.322, "x2": 190.464, "y2": 715.25 },
          "basis": "text-extent"
        }
      ]
    }
    // … H2「請求明細」、Table、備考 が続く
  ]
}
```

`rect` は PDF 座標系（左下原点・pt）です。pdf-writer-mcp の `add_annotation` にそのまま渡せます。`basis` が `text-extent` なので、テキストからの実測です。
:::

## locate_objects

**Locate PDF Objects (object number → page and rectangle)**

指定したオブジェクトがページ上のどこにあるかを報告する。

「どのオブジェクトか」を「どの座標か」へ橋渡しする: pdf-verify-mcp の verify_integrity は増分更新が変更したオブジェクトを名指しし、pdf-writer-mcp の add_annotation はページ番号と矩形を要求する。矩形は PDF ユーザー空間（原点は左下・pt・x1 < x2 かつ y1 < y2 — ISO 32000-1 §7.9.5 の正規化形）で返り、これはまさに add_annotation が受け取る形である。

### 引数

| 引数 | 型 | 必須 | 既定値 | 説明 |
|---|---|---|---|---|
| `file_path` | string (minLength 1) | **必須** |  | ローカル PDF ファイルへの絶対パス（例: "/path/to/document.pdf"） |
| `object_numbers` | integer (1–9007199254740991)\[] | **必須** |  | 位置を特定するオブジェクト番号。例: \[25, 27]。通常は pdf-verify-mcp の verify_integrity が「変更された」と報告したオブジェクト。 |
| `response_format` | `"markdown"` | `"json"` | 任意 | `"markdown"` | 出力形式: "markdown" は人が読む用、"json" は構造化データ |

### 戻り値

オブジェクトごとに: 存在の有無・/Type と /Subtype・占める場所。各場所には座標の根拠（basis）が付く:

* annotation-rect — オブジェクト自身の /Rect。正確。
* page-box — オブジェクトはページで、矩形はその crop/media box。
* page-content-stream — オブジェクトはページを描く。矩形はページ全体であり、変わった部分ではない。
* page-resource — ページが使うフォント・画像・色空間。矩形は存在しない。

限界（観測であり判定ではない）:

* コンテンツストリームを移動した段落まで絞り込むにはグラフィックス状態付きのストリーム走査が要る。本ツールはそれを行わず、矩形を発明する代わりにそう言う。
* 存在しないオブジェクト（後のリビジョンで解放）は found: false で返る —「座標なし」としてではなく。
* 暗号化文書でも座標と型は信頼できる（数値と名前は暗号化されない。ISO 32000-1 §7.6.2）が、フィールド名は文字化けの代わりに null で報告される。

例:

* verify_integrity の「obj 27 が署名後に追加された」をページと矩形に変換する
* 変更されたフォームフィールドの Widget がどのページにあるか、注釈を付ける前に特定する

::: details 呼び出し例 — 「オブジェクト 7 と 9 と 4 はどこか」

* 実測: v0.15.0
* 標本: `docs/specimens/publish-demo.pdf`（呼び出すときは絶対パス）
* `object_numbers`: `[7, 9, 4]`
* `response_format`: `"json"`

pdf-verify-mcp の `verify_integrity` が返した番号を渡す想定です。

**パラメータ**

```jsonc
{
  "file_path": "/absolute/path/to/docs/specimens/publish-demo.pdf",
  "object_numbers": [7, 9, 4],
  "response_format": "json"
}
```

**返る JSON**

```jsonc
{
  "objects": [
    {
      "objectNumber": 7,
      "found": true,
      "type": "Page",
      "locations": [
        {
          "page": 1,
          "rect": { "x1": 0, "y1": 0, "x2": 595.28, "y2": 841.89 },
          "basis": "page-box"
        }
      ]
    },
    {
      "objectNumber": 9,
      "found": true,
      "type": null,
      "locations": [
        {
          "page": 1,
          "rect": { "x1": 0, "y1": 0, "x2": 595.28, "y2": 841.89 },
          "basis": "page-content-stream"
        }
      ],
      "reason": "This is the page's content stream, so the rectangle is the whole page. …"
    },
    {
      "objectNumber": 4,
      "found": true,
      "type": "Font",
      "subtype": "Type0",
      "locations": [{ "page": 1, "rect": null, "basis": "page-resource" }],
      "reason": "A resource is used by the page but has no rectangle of its own; …"
    }
  ],
  "isEncrypted": false
}
```

`page-content-stream` の矩形はページ全体です。段落を指すなら [`extract_structured_text`](#extract-structured-text) の `include_bbox` です。
:::

## compare_structure

**Compare PDF Structures**

2 つの PDF 文書の内部構造を比較し、差分を特定する。

### 引数

| 引数 | 型 | 必須 | 既定値 | 説明 |
|---|---|---|---|---|
| `file_path_1` | string (minLength 1) | **必須** |  | 比較する 1 つ目の PDF ファイルへの絶対パス |
| `file_path_2` | string (minLength 1) | **必須** |  | 比較する 2 つ目の PDF ファイルへの絶対パス |
| `response_format` | `"markdown"` | `"json"` | 任意 | `"markdown"` | 出力形式: "markdown" は人が読む用、"json" は構造化データ |

### 戻り値

構造比較: 項目ごとの差分（ページ数・PDF バージョン・暗号化・タグ付き状態・オブジェクト数・ページ寸法・ファイルサイズ・カタログエントリ・署名）、フォント比較（各ファイル固有のフォントと共有フォント）、要約。

比較には 2 つとも要るので、読めないファイルがあるとエラーになる —— ただしそのエラーは、**どちらのファイルが読めなかったか**を名指しし、もう一方は読めていたことを述べる。

例:

* 同じ文書の 2 版を比較
* PDF 出力間の構造的一貫性を確認
* PDF 生成パイプラインの違いを特定
