0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

JavaScriptでPDFからテキストを抽出し、PDFをテキストに変換する

Posted at

近年、Webアプリケーションの開発において、クライアント側でPDFファイルを処理するニーズが増加しています。特に、PDFからテキストを抽出し、表示・分析・さらなる処理を行う場面が多く見られます。Reactフレームワーク上でJavaScriptを使用してPDFのテキストを抽出することで、ユーザーエクスペリエンスを向上させるだけでなく、サーバー側の負荷を軽減し、データ処理の即時性と効率を高めることができます。この方法により、開発者はより動的で応答性の高いアプリケーションを構築でき、ユーザーはサーバーからの応答を待つことなく、必要な情報を迅速に取得できます。

本記事では、JavaScriptを使用してReactでPDF文書のテキストを抽出する方法を紹介します。

主な内容

本記事で紹介する方法では、Spire.PDF for JavaScriptを使用します。
NPMインストールコマンド:npm install spire.pdf

JavaScriptでPDFのテキストを抽出する基本手順

Spire.PDF for JavaScriptには、PDF文書を処理するWebAssemblyモジュールが提供されています。このモジュールのPdfTextExtractorを使用すると、簡単にPDFのテキストを抽出できます。以下は、基本的な操作手順です。

  1. WebAssembly環境の初期化
    Spire.Pdf.Base.jsを読み込み、WebAssemblyモジュールを初期化します。

  2. PDFファイルの読み込み
    wasmModule.FetchFileToVFS()を使用して、PDFファイルを仮想ファイルシステム(VFS)に保存します。

  3. PDFドキュメントオブジェクトの作成
    wasmModule.PdfDocument.Create()PdfDocumentインスタンスを作成し、PdfDocument.LoadFromFile()でVFSからPDFを読み込みます。

  4. テキスト抽出オプションの設定
    wasmModule.PdfTextExtractOptions.Create()を使用してPdfTextExtractOptionsインスタンスを作成し、抽出オプションを設定します。

  5. PDFページの取得
    PdfDocument.Pages.get_Item()またはPagesコレクションをループ処理して、必要なページを取得します。

  6. テキスト抽出器の作成
    wasmModule.PdfTextExtractor.Create()を使用して、取得したページオブジェクトからPdfTextExtractorインスタンスを作成します。

  7. テキストの抽出
    PdfTextExtractor.ExtractText()を呼び出し、PDFページからテキストを取得します。

  8. テキストの処理・エクスポート
    抽出したテキストを必要に応じて処理し、ローカルに保存します。

PdfTextExtractOptionsには、IsSimpleExtractionIsExtractAllTextExtractAreaIsShowHiddenTextなどのプロパティがあり、多様なカスタム抽出が可能です。

レイアウトを保持したPDFテキストの抽出

PdfTextExtractor.ExtractText()をデフォルトオプションで使用すると、ページ全体のテキストを抽出し、空白を保持することでレイアウトが維持されます。

コード例:

import React, { useState, useEffect } from 'react';

function App() {

  // ロードされたWASMモジュールの状態を保存するためのステート
  const [wasmModule, setWasmModule] = useState(null);

  // useEffectフックを使用して、コンポーネントがマウントされたときにWASMモジュールをロード
  useEffect(() => {
    const loadWasm = async () => {
      try {
        // グローバルwindowオブジェクトからModuleとspirepdfを取得
        const { Module, spirepdf } = window;

        // 実行時に初期化された際にwasmModuleステートを設定
        Module.onRuntimeInitialized = () => {
          setWasmModule(spirepdf);
        };
      } catch (err) {
        // モジュールのロード中に発生したエラーを記録
        console.error('WASMモジュールのロードに失敗しました:', err);
      }
    };

    // WASM JavaScriptファイルをロードするためのスクリプト要素を作成
    const script = document.createElement('script');
    script.src = `${process.env.PUBLIC_URL}/Spire.Pdf.Base.js`;
    script.onload = loadWasm;

    // スクリプトをドキュメントのbodyに追加
    document.body.appendChild(script);

    // クリーンアップ関数:コンポーネントがアンマウントされた際にスクリプトを削除
    return () => {
      document.body.removeChild(script);
    };
  }, []);

  // PDFドキュメントからすべてのテキストを抽出する関数
  const ExtractPDFText = async () => {
    if (wasmModule) {
      // 入力ファイル名と出力ファイル名を指定
      const inputFileName = 'Sample.pdf';
      const outputFileName = 'PDFTextWithLayout.txt';

      // 入力ファイルを取得してVFSに追加
      await wasmModule.FetchFileToVFS(inputFileName, '', `${process.env.PUBLIC_URL}/`);

      // PdfDocumentクラスのインスタンスを作成
      const pdf = wasmModule.PdfDocument.Create();

      // VFSからPDFドキュメントをロード
      pdf.LoadFromFile(inputFileName);

      // 抽出したテキストを保存するための文字列オブジェクトを作成
      let text = '';

      // PdfTextExtractOptionsクラスのインスタンスを作成
      const extractOptions = wasmModule.PdfTextExtractOptions.Create();

      // PDFドキュメントの各ページをループ
      for (let i = 0; i < pdf.Pages.Count; i++) {
        // 現在のページを取得
        const page = pdf.Pages.get_Item(i);
        // PdfTextExtractorクラスのインスタンスを作成
        const textExtractor = wasmModule.PdfTextExtractor.Create(page);
        // 現在のページからテキストを抽出して文字列に追加
        text += textExtractor.ExtractText(extractOptions);
      }

      // テキスト文字列からBlobオブジェクトを作成し、ダウンロード
      const blob = new Blob([text], { type: 'text/plain' });
      const url = URL.createObjectURL(blob);
      const a = document.createElement('a');
      a.href = url;
      a.download = `${outputFileName}`;
      document.body.appendChild(a);
      a.click();
      document.body.removeChild(a);
      URL.revokeObjectURL(url);
    }
  };

  return (
      <div style={{ textAlign: 'center', height: '300px' }}>
        <h1>ReactでJavaScriptを使用してPDFからテキストを抽出</h1>
        <button onClick={ExtractPDFText} disabled={!wasmModule}>
          抽出してダウンロード
        </button>
      </div>
  );
}

export default App;

抽出結果:
レイアウトを保持したテキストが取得

空白を削除したPDFテキストの抽出

PdfTextExtractOptionsIsSimpleExtractiontrueに設定すると、不要な空白を削除し、テキストのレイアウトを保持せずに抽出できます。この方法は、抽出したテキストをさらに処理する場合に適しています。

コード例:

import React, { useState, useEffect } from 'react';

function App() {

  // ロードされたWASMモジュールの状態を保存するためのステート
  const [wasmModule, setWasmModule] = useState(null);

  // useEffectフックを使用して、コンポーネントがマウントされたときにWASMモジュールをロード
  useEffect(() => {
    const loadWasm = async () => {
      try {
        // グローバルwindowオブジェクトからModuleとspirepdfを取得
        const { Module, spirepdf } = window;

        // 実行時に初期化された際にwasmModuleステートを設定
        Module.onRuntimeInitialized = () => {
          setWasmModule(spirepdf);
        };
      } catch (err) {
        // モジュールのロード中に発生したエラーを記録
        console.error('WASMモジュールのロードに失敗しました:', err);
      }
    };

    // WASM JavaScriptファイルをロードするためのスクリプト要素を作成
    const script = document.createElement('script');
    script.src = `${process.env.PUBLIC_URL}/Spire.Pdf.Base.js`;
    script.onload = loadWasm;

    // スクリプトをドキュメントのbodyに追加
    document.body.appendChild(script);

    // クリーンアップ関数:コンポーネントがアンマウントされた際にスクリプトを削除
    return () => {
      document.body.removeChild(script);
    };
  }, []);

  // PDFドキュメントからテキストを抽出(レイアウトを保持しない)の関数
  const ExtractPDFText = async () => {
    if (wasmModule) {
      // 入力ファイル名と出力ファイル名を指定
      const inputFileName = 'Sample.pdf';
      const outputFileName = 'PDFTextWithoutLayout.txt';

      // 入力ファイルを取得してVFSに追加
      await wasmModule.FetchFileToVFS(inputFileName, '', `${process.env.PUBLIC_URL}/`);

      // PdfDocumentクラスのインスタンスを作成
      const pdf = wasmModule.PdfDocument.Create();

      // VFSからPDFドキュメントをロード
      pdf.LoadFromFile(inputFileName);

      // 抽出したテキストを保存するための文字列オブジェクトを作成
      let text = '';

      // PdfTextExtractOptionsクラスのインスタンスを作成
      const extractOptions = wasmModule.PdfTextExtractOptions.Create();

      // シンプルなテキスト抽出モードを有効化し、テキストのレイアウトを保持しない
      extractOptions.IsSimpleExtraction = true;

      // PDFドキュメントの各ページをループ
      for (let i = 0; i < pdf.Pages.Count; i++) {
        // 現在のページを取得
        const page = pdf.Pages.get_Item(i);
        // PdfTextExtractorクラスのインスタンスを作成
        const textExtractor = wasmModule.PdfTextExtractor.Create(page);
        // 現在のページからテキストを抽出して文字列に追加
        text += textExtractor.ExtractText(extractOptions);
      }

      // テキスト文字列からBlobオブジェクトを作成し、ダウンロード
      const blob = new Blob([text], { type: 'text/plain' });
      const url = URL.createObjectURL(blob);
      const a = document.createElement('a');
      a.href = url;
      a.download = `${outputFileName}`;
      document.body.appendChild(a);
      a.click();
      document.body.removeChild(a);
      URL.revokeObjectURL(url);
    }
  };

  return (
      <div style={{ textAlign: 'center', height: '300px' }}>
        <h1>ReactでJavaScriptを使用してPDFからテキストを抽出レイアウトを保持しない</h1>
        <button onClick={ExtractPDFText} disabled={!wasmModule}>
          抽出してダウンロード
        </button>
      </div>
  );
}

export default App;

抽出結果:
空白が削除されたテキストが取得

指定領域のPDFテキストの抽出

PdfTextExtractOptionsExtractAreaプロパティにRectangleFオブジェクトを設定することで、指定領域のテキストのみを抽出できます。これにより、ページ内の不要な固定コンテンツを避けることができます。

コード例:

import React, { useState, useEffect } from 'react';

function App() {

  // ロードされたWASMモジュールの状態を保存するためのステート
  const [wasmModule, setWasmModule] = useState(null);

  // useEffectフックを使用して、コンポーネントがマウントされたときにWASMモジュールをロード
  useEffect(() => {
    const loadWasm = async () => {
      try {
        // グローバルwindowオブジェクトからModuleとspirepdfを取得
        const { Module, spirepdf } = window;

        // 実行時に初期化された際にwasmModuleステートを設定
        Module.onRuntimeInitialized = () => {
          setWasmModule(spirepdf);
        };
      } catch (err) {
        // モジュールのロード中に発生したエラーを記録
        console.error('WASMモジュールのロードに失敗しました:', err);
      }
    };

    // WASM JavaScriptファイルをロードするためのスクリプト要素を作成
    const script = document.createElement('script');
    script.src = `${process.env.PUBLIC_URL}/Spire.Pdf.Base.js`;
    script.onload = loadWasm;

    // スクリプトをドキュメントのbodyに追加
    document.body.appendChild(script);

    // クリーンアップ関数:コンポーネントがアンマウントされた際にスクリプトを削除
    return () => {
      document.body.removeChild(script);
    };
  }, []);

  // PDFページの特定のエリアからテキストを抽出する関数
  const ExtractPDFText = async () => {
    if (wasmModule) {
      // 入力ファイル名と出力ファイル名を指定
      const inputFileName = 'Sample.pdf';
      const outputFileName = 'PDFTextPageArea.txt';

      // 入力ファイルを取得してVFSに追加
      await wasmModule.FetchFileToVFS(inputFileName, '', `${process.env.PUBLIC_URL}/`);

      // PdfDocumentクラスのインスタンスを作成
      const pdf = wasmModule.PdfDocument.Create();

      // VFSからPDFドキュメントをロード
      pdf.LoadFromFile(inputFileName);

      // 抽出したテキストを保存するための文字列オブジェクトを作成
      let text = '';

      // PDFドキュメントの特定のページを取得
      const page = pdf.Pages.get_Item(0);

      // PdfTextExtractOptionsクラスのインスタンスを作成
      const extractOptions = wasmModule.PdfTextExtractOptions.Create();

      // 抽出するテキストのページ領域を指定(RectangleFオブジェクトを使用)
      extractOptions.ExtractArea = wasmModule.RectangleF.Create({ x: 0, y: 500, width: page.Size.Width, height: 200 });

      // PdfTextExtractorクラスのインスタンスを作成
      const textExtractor = wasmModule.PdfTextExtractor.Create(page);

      // 指定された領域からテキストを抽出
      text = textExtractor.ExtractText(extractOptions);

      // テキスト文字列からBlobオブジェクトを作成し、ダウンロード
      const blob = new Blob([text], { type: 'text/plain' });
      const url = URL.createObjectURL(blob);
      const a = document.createElement('a');
      a.href = url;
      a.download = `${outputFileName}`;
      document.body.appendChild(a);
      a.click();
      document.body.removeChild(a);
      URL.revokeObjectURL(url);
    }
  };

  return (
      <div style={{ textAlign: 'center', height: '300px' }}>
        <h1>ReactでJavaScriptを使用してPDFページの特定のエリアからテキストを抽出</h1>
        <button onClick={ExtractPDFText} disabled={!wasmModule}>
          抽出してダウンロード
        </button>
      </div>
  );
}

export default App;

抽出結果:
指定領域のテキストのみが取得

強調表示されたPDFテキストの抽出

PDF内の強調表示テキストは、通常、注釈として追加されています。そのため、PdfPageBase.Annotationsを使用してPDFページのすべての注釈を取得し、PdfTextMarkupAnnotationWidgetインスタンスを識別することで、強調表示されたテキストを特定できます。その後、Boundsプロパティを使用して強調表示された範囲を取得し、抽出領域として設定することで、強調表示テキストを抽出できます。

コード例:

import React, { useState, useEffect } from 'react';

function App() {

  // ロードされたWASMモジュールの状態を保存するためのステート
  const [wasmModule, setWasmModule] = useState(null);

  // useEffectフックを使用して、コンポーネントがマウントされたときにWASMモジュールをロード
  useEffect(() => {
    const loadWasm = async () => {
      try {
        // グローバルwindowオブジェクトからModuleとspirepdfを取得
        const { Module, spirepdf } = window;

        // 実行時に初期化された際にwasmModuleステートを設定
        Module.onRuntimeInitialized = () => {
          setWasmModule(spirepdf);
        };
      } catch (err) {
        // モジュールのロード中に発生したエラーを記録
        console.error('WASMモジュールのロードに失敗しました:', err);
      }
    };

    // WASM JavaScriptファイルをロードするためのスクリプト要素を作成
    const script = document.createElement('script');
    script.src = `${process.env.PUBLIC_URL}/Spire.Pdf.Base.js`;
    script.onload = loadWasm;

    // スクリプトをドキュメントのbodyに追加
    document.body.appendChild(script);

    // クリーンアップ関数:コンポーネントがアンマウントされた際にスクリプトを削除
    return () => {
      document.body.removeChild(script);
    };
  }, []);

  // PDFからハイライトされたテキストを抽出する関数
  const ExtractPDFText = async () => {
    if (wasmModule) {
      // 入力ファイル名と出力ファイル名を指定
      const inputFileName = 'Sample.pdf';
      const outputFileName = 'PDFTextHighlighted.txt';

      // 入力ファイルを取得してVFSに追加
      await wasmModule.FetchFileToVFS(inputFileName, '', `${process.env.PUBLIC_URL}/`);

      // PdfDocumentクラスのインスタンスを作成
      const pdf = wasmModule.PdfDocument.Create();

      // VFSからPDFドキュメントをロード
      pdf.LoadFromFile(inputFileName);

      // 抽出したテキストを保存するための文字列オブジェクトを作成
      let text = '';

      // PDFドキュメントの各ページをループ
      for (const page of pdf.Pages) {
        // 現在のページのすべての注釈をループ
        for (let i = 0; i < page.Annotations.Count; i++) {
          // 現在の注釈を取得
          const annotation = page.Annotations.get_Item(i);
          // 注釈がPdfTextMarkupAnnotationのインスタンス(ハイライト)であるかをチェック
          if (annotation instanceof wasmModule.PdfTextMarkupAnnotationWidget) {
            // ハイライト注釈の境界を取得
            const bounds = annotation.Bounds;
            // PdfTextExtractOptionsのインスタンスを作成
            const extractOptions = wasmModule.PdfTextExtractOptions.Create();
            // ハイライト注釈の境界をテキスト抽出領域として設定
            extractOptions.ExtractArea = bounds;
            // PdfTextExtractorクラスのインスタンスを作成
            const textExtractor = wasmModule.PdfTextExtractor.Create(page);
            // ハイライトテキストを抽出し、text文字列に追加
            text += textExtractor.ExtractText(extractOptions);
          }
        }
      }

      // テキスト文字列からBlobオブジェクトを作成し、ダウンロード
      const blob = new Blob([text], { type: 'text/plain' });
      const url = URL.createObjectURL(blob);
      const a = document.createElement('a');
      a.href = url;
      a.download = `${outputFileName}`;
      document.body.appendChild(a);
      a.click();
      document.body.removeChild(a);
      URL.revokeObjectURL(url);
    }
  };

  return (
      <div style={{ textAlign: 'center', height: '300px' }}>
        <h1>ReactでJavaScriptを使用してPDF内のハイライトされたテキストを抽出</h1>
        <button onClick={ExtractPDFText} disabled={!wasmModule}>
          抽出してダウンロード
        </button>
      </div>
  );
}

export default App;

抽出結果:
強調表示されたテキストが取得

まとめ

本記事では、JavaScriptを使用してReact環境でPDFテキストを抽出する方法を紹介しました。また、レイアウトを保持した抽出、空白を削除した抽出、指定領域の抽出、強調表示テキストの抽出など、さまざまなカスタム抽出方法について解説しました。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?