npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@gstypecode/pdf-field-extractor

v1.0.0

Published

PDF field extraction using configurable patterns and coordinates

Readme

PDF Region Extractor

npm version Node.js Version License

PDFから特定領域(region/field)を抽出するNode.jsパッケージ。設定ファイルベースで座標とパターンを指定し、効率的な情報抽出を実現します。

🚀 特徴

  • 設定ファイルベース: JSONファイルで座標・パターン・ページを指定
  • 正規表現対応: 複雑なパターンマッチングをサポート
  • 座標指定抽出: PDF内の特定領域からテキストを抽出
  • Web UI: 設定エディタは別リポジトリ pdf-config-editor で提供
  • 高性能: 大量のPDFファイルを効率的に処理
  • TypeScript対応: 型安全な開発体験

📦 インストール

npm install pdf-region-extractor

🔧 クイックスタート

1. 基本的な使用方法

const PdfFieldExtractor = require('pdf-region-extractor');
const fs = require('fs').promises;

const config = {
  fields: {
    invoiceNumber: {
      description: "請求書番号",
      pattern: "請求書番号[\\s::]*([A-Z0-9-]+)",
      pages: "all",
      region: { xMin: 100, xMax: 300, yMin: 50, yMax: 100 },
      method: "regex"
    }
  }
};

// Buffer から抽出(ライブラリ利用が主)
const pdfBuffer = await fs.readFile('./invoice.pdf');
const result = await PdfFieldExtractor.extract(pdfBuffer, config);

// または、ファイルパスから直接抽出(CLI利用など)
// const result = await PdfFieldExtractor.extractFromFile('./invoice.pdf', config);

console.log(result);
// {
//   success: true,
//   data: { invoiceNumber: "INV-2024-001" },
//   metadata: { processingTime: 120, extractionType: "field_extraction", ... }
// }

2. 設定ファイルを使用

const PdfFieldExtractor = require('pdf-region-extractor');
const fs = require('fs').promises;

// 設定ファイルを読み込み
const configData = await fs.readFile('./config/invoice_format.json', 'utf8');
const config = JSON.parse(configData);

// PDFから情報を抽出(Buffer系)
const pdfBuffer = await fs.readFile('./invoice.pdf');
const result = await PdfFieldExtractor.extract(pdfBuffer, config);

// または、ファイルパスから直接抽出(File系)
// const result = await PdfFieldExtractor.extractFromFile('./invoice.pdf', config);

3. Web UIを使用

設定エディタは別リポジトリ pdf-config-editor に移動しました。 詳細はそちらのREADMEを参照してください。

📋 設定ファイル形式

{
  "fields": {
    "invoiceNumber": {
      "description": "請求書番号",
      "pattern": "請求書番号[\\s::]*([A-Z0-9-]+)",
      "pages": "all",
      "region": {
        "xMin": 100,
        "xMax": 300,
        "yMin": 50,
        "yMax": 100
      },
      "method": "regex"
    },
    "totalAmount": {
      "description": "合計金額",
      "pattern": "合計[\\s::]*([\\d,]+)円",
      "pages": [1, 2],
      "region": {
        "xMin": 400,
        "xMax": 600,
        "yMin": 700,
        "yMax": 750
      },
      "method": "regex"
    }
  }
}

🏗️ API設計

Buffer系とFile系の使い分け

このライブラリは2種類のAPIを提供します:

Buffer系メソッド(主な用途:npmパッケージとして利用)

  • extract(pdfBuffer, config, options)
  • extractByPages(pdfBuffer, config, options)

File系メソッド(主な用途:CLI利用)

  • extractFromFile(pdfPath, config, options)
  • extractByPagesFromFile(pdfPath, config, options)

使用例

const PdfFieldExtractor = require('pdf-region-extractor');
const fs = require('fs').promises;

// ライブラリとして利用(Buffer系)
const pdfBuffer = await fs.readFile('./invoice.pdf');
const result = await PdfFieldExtractor.extract(pdfBuffer, config);

// CLIツールとして利用(File系)
const result = await PdfFieldExtractor.extractFromFile('./invoice.pdf', config);

推奨:ほとんどのケースではnpmパッケージとして利用するため、Buffer系メソッドを使用してください。

🎯 API仕様

extract(pdfBuffer, config, options)

PDFバッファから指定されたフィールドを抽出します(ライブラリ利用推奨)。

パラメータ:

  • pdfBuffer (Buffer): PDFファイルのバッファ
  • config (object): 設定オブジェクト
  • options (object, optional): 抽出オプション
    • debug (boolean): デバッグモード有効化
    • pageNumber (number): 特定ページのみ抽出
    • timeout (number): タイムアウト時間(ミリ秒)

戻り値:

  • Promise<object>: 抽出結果オブジェクト
    • success (boolean): 処理成功可否
    • data (object): 抽出されたデータ(形式は設定により異なる)
    • metadata (object): 処理情報(処理時間、ページ数、マッチ数など)
    • error (string): エラーメッセージ(失敗時のみ)

詳細な出力形式については 📤 出力スキーマ を参照してください。

例:

const pdfBuffer = await fs.readFile('./invoice.pdf');
const result = await PdfFieldExtractor.extract(pdfBuffer, config, {
  debug: true,
  timeout: 30000
});

// 結果例
// {
//   success: true,
//   data: { invoiceNumber: "INV-2024-001", totalAmount: "50,000" },
//   metadata: { processingTime: 150, pageCount: "auto", ... }
// }

extractFromFile(pdfPath, config, options)

PDFファイルパスから指定されたフィールドを抽出します(CLI利用など)。

パラメータ:

  • pdfPath (string): PDFファイルパス
  • config (object): 設定オブジェクト
  • options (object, optional): 抽出オプション(extractと同じ)

戻り値:

  • Promise<object>: extractと同じ形式の抽出結果オブジェクト

例:

const result = await PdfFieldExtractor.extractFromFile('./invoice.pdf', config, {
  debug: true
});

loadConfig(configPath)

設定ファイルを読み込みます。

パラメータ:

  • configPath (string): 設定ファイルパス

戻り値:

  • object: 設定オブジェクト

validateConfig(config)

設定オブジェクトの妥当性を検証します。

パラメータ:

  • config (object): 設定オブジェクト

戻り値:

  • boolean: 妥当性チェック結果

extract と extractByPages の使い分け

| メソッド | 用途 | 返り値 | ページ処理 | |---------|------|--------|----------| | extract | 全ページからマッチしたデータを取得 | マッチしたデータのみ | 一括処理 | | extractByPages | 各ページの成功・失敗を個別に取得 | 全ページ分の結果配列pageResults.length === totalPages | ページごと処理 |

extract を使うべき場合

  • マッチしたデータだけが必要
  • ページ情報は不要
  • シンプルな抽出

extractByPages を使うべき場合

  • 各ページの一致・不一致を確認したい
  • マッチしなかったページを特定したい
  • ページごとの処理結果が必要

重要な違い

// extract: マッチしたデータのみ
const result = await PdfFieldExtractor.extract(pdfBuffer, config);
// result.data.fieldName: マッチした値の配列(例:253個)

// extractByPages: 全ページ分の結果
const result = await PdfFieldExtractor.extractByPages(pdfBuffer, config);
// result.pageResults.length: 260(全ページ数)
// result.metadata.successfulPages: 253(マッチしたページ数)
// result.metadata.failedPages: 7(マッチしなかったページ数)

extractByPages(pdfBuffer, config, options)

PDFファイルの各ページごとに情報を抽出します。全ページの処理結果(成功・失敗含む)を取得できます

重要: extract メソッドと異なり、このメソッドは pageResults.length === totalPages となり、マッチしなかったページも含めて全ページ分の結果が返されます。

パラメータ:

  • pdfBuffer (Buffer): PDFファイルのバッファ
  • config (object): 抽出設定オブジェクト
  • options (object, optional): 抽出オプション
    • debug (boolean): デバッグモード有効化

戻り値:

  • Promise<object>: ページ別抽出結果オブジェクト
    • success (boolean): 処理成功可否
    • extractionType (string): "page-by-page"
    • totalPages (number): 総ページ数
    • pageResults (array): 各ページの抽出結果配列(pageResults.length === totalPages
      • page (number): ページ番号
      • result (object): extract メソッドと同じ形式の結果
    • consolidatedData (object): 全ページのデータを統合したオブジェクト
    • metadata (object): 処理情報
      • successfulPages (number): 抽出成功ページ数
      • failedPages (number): 抽出失敗ページ数

例:

const fs = require('fs').promises;
const pdfBuffer = await fs.readFile('./invoice.pdf');
const result = await PdfFieldExtractor.extractByPages(pdfBuffer, config, {
  debug: true
});

console.log(`総ページ数: ${result.totalPages}`);
console.log(`pageResults配列の長さ: ${result.pageResults.length}`);  // totalPagesと同じ
console.log(`成功: ${result.metadata.successfulPages}ページ`);
console.log(`失敗: ${result.metadata.failedPages}ページ`);

// 各ページの結果を確認
result.pageResults.forEach(({ page, result }) => {
  if (result.success && result.data) {
    // 抽出されたすべてのフィールドを表示
    const extractedFields = Object.keys(result.data).filter(key => result.data[key] !== null);
    console.log(`ページ${page}: ${extractedFields.join(', ')}`);
  } else {
    console.log(`ページ${page}: マッチなし`);
  }
});

使用例:全ページの一致・不一致を確認

const result = await PdfFieldExtractor.extractByPages(pdfBuffer, config);

// マッチしなかったページを特定
const unmatchedPages = result.pageResults
  .filter(({ result }) => !result.success || Object.values(result.data || {}).every(v => v === null))
  .map(({ page }) => page);

console.log('マッチしなかったページ:', unmatchedPages);
console.log(`全${result.totalPages}ページ中、${unmatchedPages.length}ページがマッチしませんでした`);

📤 出力スキーマ(Output Schema)

基本構造

すべての抽出結果は以下の統一された形式で返されます:

{
  success: true,           // 処理成功可否
  data: { ... },           // 抽出データ(形式はモードにより異なる)
  metadata: {
    processingTime: 150,   // 処理時間(ミリ秒)
    pageCount: "auto",     // 処理ページ数
    matchCount: 3,         // マッチ数
    formatName: "設定名",   // 設定ファイル名
    extractionType: "field_extraction"  // 抽出タイプ
  }
}

1. フィールド抽出モード(Field Extraction)

設定タイプ: field_extraction

出力ルール

  • マッチなし: null
  • 1要素のみマッチ: 文字列
  • 複数要素マッチ: 配列

例1: 単一マッチ

// 設定
{
  "fields": {
    "invoiceNumber": {
      "pattern": "INV-\\d+",
      "region": { "xMin": 100, "xMax": 300, "yMin": 50, "yMax": 100 }
    }
  }
}

// 出力
{
  "success": true,
  "data": {
    "invoiceNumber": "INV-2024-001"  // 文字列
  },
  "metadata": { ... }
}

例2: 複数テキストボックスマッチ

PDFの指定座標領域内に複数のテキストボックスが存在し、それぞれが正規表現にマッチした場合:

// 設定
{
  "fields": {
    "studentId": {
      "pattern": "\\d+.*",
      "region": { "xMin": 40, "xMax": 200, "yMin": 100, "yMax": 150 }
    }
  }
}

// PDF内のテキストボックス構造:
// - テキストボックス1: "31030 赤瀬 龍臣"
// - テキストボックス2: "]"

// 出力
{
  "success": true,
  "data": {
    "studentId": ["31030 赤瀬 龍臣", "]"]  // 配列
  },
  "metadata": { ... }
}

重要: 各テキストボックスは個別に正規表現チェックされ、マッチした要素が配列として返されます。

例3: マッチなし

{
  "success": true,
  "data": {
    "invoiceNumber": null  // マッチなし
  },
  "metadata": { ... }
}

2. 手動テーブル抽出モード(Manual Table)

設定タイプ: manual_table

出力構造

{
  "success": true,
  "data": {
    "テーブル名": [
      {
        "column1": "値1",
        "column2": "値2",
        "column3": "値3"
      },
      {
        "column1": "値4",
        "column2": "値5",
        "column3": "値6"
      }
    ]
  },
  "metadata": {
    "processingTime": 200,
    "extractionType": "manual_table",
    ...
  }
}

例: 請求書明細テーブル

// 設定
{
  "tableDefinition": {
    "tableName": "invoiceItems",
    "columns": [
      { "name": "itemName", "xRange": { "min": 40, "max": 200 }, "pattern": ".+" },
      { "name": "quantity", "xRange": { "min": 210, "max": 260 }, "pattern": "\\d+" },
      { "name": "amount", "xRange": { "min": 270, "max": 340 }, "pattern": "[\\d,]+" }
    ]
  }
}

// 出力
{
  "success": true,
  "data": {
    "invoiceItems": [
      {
        "itemName": "商品A",
        "quantity": "5",
        "amount": "10,000"
      },
      {
        "itemName": "商品B",
        "quantity": "3",
        "amount": "6,000"
      }
    ]
  },
  "metadata": { ... }
}

3. 自動テーブル検出モード(Auto Table Detection)

設定タイプ: auto_table

出力構造(table_matrix形式)

{
  "success": true,
  "data": {
    "テーブル名": {
      "matrix": [
        [
          {
            "row": 0,
            "column": 0,
            "combinedText": "セル内容",
            "textBoxes": [...],  // includeCoordinates: true の場合
            "avgX": 50.5,
            "avgY": 200.3
          },
          // ...
        ],
        // ...
      ],
      "metadata": {
        "detectedRows": 10,
        "detectedColumns": 5,
        "totalCells": 50,
        "clusteringInfo": {
          "verticalClusters": 10,
          "horizontalClusters": 5,
          "algorithm": "dbscan"
        }
      }
    }
  },
  "metadata": { ... }
}

出力構造(flat_list形式)

{
  "success": true,
  "data": {
    "テーブル名": {
      "cells": [
        { "row": 0, "column": 0, "combinedText": "A1" },
        { "row": 0, "column": 1, "combinedText": "B1" },
        { "row": 1, "column": 0, "combinedText": "A2" },
        // ...
      ],
      "metadata": { ... }
    }
  },
  "metadata": { ... }
}

例: 自動テーブル検出

// 設定
{
  "autoTableDetection": {
    "tableName": "detectedTable",
    "extractionRegion": { "xMin": 50, "xMax": 550, "yMin": 200, "yMax": 600 },
    "clustering": {
      "algorithm": "dbscan",
      "verticalClustering": { "epsilon": 5.0, "minPoints": 2 },
      "horizontalClustering": { "epsilon": 10.0, "minPoints": 1 }
    },
    "output": {
      "format": "table_matrix",        // "table_matrix" または "flat_list"
      "includeCoordinates": true,      // 座標情報を含める
      "includeMetadata": true          // メタデータを含める
    }
  }
}

// 出力
{
  "success": true,
  "data": {
    "detectedTable": {
      "matrix": [
        [
          { "row": 0, "column": 0, "combinedText": "ヘッダー1", "avgX": 60, "avgY": 210 },
          { "row": 0, "column": 1, "combinedText": "ヘッダー2", "avgX": 150, "avgY": 210 }
        ],
        [
          { "row": 1, "column": 0, "combinedText": "データ1", "avgX": 60, "avgY": 230 },
          { "row": 1, "column": 1, "combinedText": "データ2", "avgX": 150, "avgY": 230 }
        ]
      ],
      "metadata": {
        "detectedRows": 2,
        "detectedColumns": 2,
        "totalCells": 4,
        "clusteringInfo": {
          "verticalClusters": 2,
          "horizontalClusters": 2,
          "algorithm": "dbscan"
        }
      }
    }
  },
  "metadata": {
    "processingTime": 180,
    "extractionType": "auto_table",
    ...
  }
}

エラー時の出力

処理が失敗した場合は以下の形式で返されます:

{
  "success": false,
  "error": "エラーメッセージ",
  "metadata": {
    "processingTime": 50
  }
}

出力設定オプション

フィールドモード

  • 複数マッチ時は自動的に配列化
  • キャプチャグループ使用時は追加フィールド生成可能

テーブルモード(手動)

  • カラム定義に基づくオブジェクト配列
  • 正規表現マッチングによる値抽出

テーブルモード(自動)

| オプション | 説明 | デフォルト | |----------|------|---------| | format | 出力形式(table_matrix / flat_list) | table_matrix | | includeCoordinates | 座標情報を含める | true | | includeMetadata | メタデータを含める | true |

🔧 Web UI(設定エディタ)

設定エディタは別リポジトリ pdf-config-editor に移動しました。

🚨 重要な注意事項

座標系について

PDFの座標系は 左下原点 です。Web UIでは自動的に変換されますが、設定ファイルを手動作成する場合は注意してください。

// PDF座標系(左下原点)
{ xMin: 100, xMax: 300, yMin: 700, yMax: 750 }

// 画面座標系(左上原点)との変換
const pdfHeight = 842; // A4サイズの場合
const webY = pdfHeight - pdfY;

正規表現パターン

  • キャプチャグループ: () で囲んだ部分が抽出されます
  • エスケープ: JSONファイルでは \\ でエスケープが必要
  • マルチライン: 複数行にまたがるパターンは [\s\S]*? を使用
// 良い例
"pattern": "請求書番号[\\s::]*([A-Z0-9-]+)"

// 悪い例(エスケープ不足)
"pattern": "請求書番号[\s::]*([A-Z0-9-]+)"

ページ指定

// 全ページ
"pages": "all"

// 特定ページ
"pages": [1, 2, 3]

// 単一ページ
"pages": 1

🐛 トラブルシューティング

よくある問題

1. PDFが読み込めない

症状: PDFファイル選択後にエラーが発生

原因と解決策:

  • 破損したPDF: 別のPDFファイルで試す
  • 暗号化PDF: パスワード保護を解除
  • 大きなファイル: ファイルサイズを確認(推奨: 10MB以下)

2. 座標指定で正しく抽出できない

症状: 設定した座標からテキストが抽出されない

原因と解決策:

  • 座標系の間違い: PDFは左下原点、Web UIは左上原点
  • 拡大率の影響: 100%表示で座標を確認
  • フォントの問題: 画像化されたテキストは抽出不可

3. 正規表現がマッチしない

症状: パターンが正しいのにマッチしない

原因と解決策:

  • エスケープ不足: JSONファイルでは \\ が必要
  • 文字エンコーディング: 全角・半角の違いを確認
  • 改行・空白: [\s\S]*? で対応

4. Web UIがフリーズする

症状: 複数操作後にブラウザが応答しない

原因と解決策:

  • 無限ループ: 新しいタブで開き直す
  • メモリ不足: ページをリロード
  • 大きなPDF: PDFファイルサイズを確認

デバッグモード

const pdfBuffer = await fs.readFile('./invoice.pdf');
const result = await PdfFieldExtractor.extract(pdfBuffer, config, {
  debug: true,
  logLevel: 'verbose'
});

ログ出力

// 詳細ログを有効化
process.env.DEBUG = 'pdf-region-extractor:*';

🔬 技術仕様

依存関係

  • Node.js: 14.0.0以上
  • pdf-parse: PDF解析エンジン
  • PDF.js: フロントエンド用PDFレンダリング
  • Vue.js 3: Web UI フレームワーク
  • Express: Webサーバー

アーキテクチャ

pdf-region-extractor/
├── src/
│   ├── index.js              # メインAPI
│   ├── utils/
│   │   ├── pdf-parser.js     # PDF解析
│   │   ├── validator.js      # 設定検証
│   │   └── pdf-viewer-manager.js  # UI統合管理
│   └── extractor/
│       └── universal-detector.js  # 抽出エンジン
├── config/                   # 設定ファイル
└── tests/                    # テストスイート

パフォーマンス

| 指標 | 値 | |------|-----| | 平均処理時間 | < 100ms/page | | メモリ使用量 | < 50MB/PDF | | 対応ファイルサイズ | 最大 50MB | | 同時処理数 | 最大 10ファイル |

対応PDF形式

  • PDF バージョン: 1.4 - 2.0
  • テキストPDF: ✅ 対応
  • 画像PDF: ❌ 非対応(OCR必要)
  • 暗号化PDF: ❌ 非対応
  • フォーム付きPDF: ⚠️ 部分対応

🧪 開発者向け情報

開発環境セットアップ

# リポジトリクローン
git clone https://github.com/your-org/pdf-region-extractor.git
cd pdf-region-extractor

# 依存関係インストール
npm install

# 開発サーバー起動
npm run dev

# テスト実行
npm test

# カバレッジレポート
npm run test:coverage

TDD開発ルール

このプロジェクトは t-wada スタイルのTDD を採用しています。

RED-GREEN-REFACTOR サイクル

  1. RED: テストを書く(失敗することを確認)
  2. GREEN: テストを通す最小限の実装
  3. REFACTOR: テストを保持しながら改善

品質基準

  • テストカバレッジ: 最小80%、目標90%+
  • 関数分離: 1関数1責務
  • JSDoc: 日本語コメント必須

コントリビューション

  1. Issue作成: バグ報告・機能要求
  2. Fork: リポジトリをフォーク
  3. ブランチ作成: feature/xxx または fix/xxx
  4. テスト追加: 新機能にはテストを追加
  5. Pull Request: 詳細な説明を記載

コミット規約

feat: 新機能追加
fix: バグ修正
test: テスト追加・修正
refactor: リファクタリング
docs: ドキュメント更新

📊 テストスイート

単体テスト

# 全テスト実行
npm test

# 特定テスト実行
npm test -- --grep "PDF解析"

# ウォッチモード
npm run test:watch

統合テスト

# E2Eテスト実行
npm run test:e2e

# UI テスト実行
npm run test:ui

カバレッジ

# カバレッジレポート生成
npm run test:coverage

# HTMLレポート表示
open coverage/index.html

🔄 バージョン管理

リリース履歴

  • v1.0.0: 初期リリース
  • v1.1.0: Web UI追加
  • v1.2.0: 統合PDF管理システム

更新方法

# マイナーバージョンアップ
npm version minor

# パッチバージョンアップ
npm version patch

# リリース
npm publish

🆘 サポート

問題報告

  • GitHub Issues: https://github.com/your-org/pdf-region-extractor/issues
  • メールサポート: [email protected]
  • ドキュメント: https://pdf-region-extractor.readthedocs.io/

FAQ

Q: 画像化されたPDFは対応していますか? A: いいえ。テキストレイヤーがあるPDFのみ対応です。OCR処理が必要な場合は別途ツールをご利用ください。

Q: 暗号化されたPDFは処理できますか? A: 現在は非対応です。パスワード保護を解除してからご利用ください。

Q: 大量のPDFファイルを効率的に処理したい A: バッチ処理機能を準備中です。v1.3.0でリリース予定です。

📄 ライセンス

MIT License - 詳細は LICENSE をご確認ください。

🙏 謝辞

  • PDF.js: Mozilla Foundation
  • pdf-parse: modesty氏
  • Vue.js: Evan You氏
  • テスト手法: t-wada氏のTDD思想

PDF Region Extractor は効率的な情報抽出を実現するための包括的なソリューションです。