近年、Webアプリケーションの開発において、クライアント側でPDFファイルを処理するニーズが増加しています。特に、PDFからテキストを抽出し、表示・分析・さらなる処理を行う場面が多く見られます。Reactフレームワーク上でJavaScriptを使用してPDFのテキストを抽出することで、ユーザーエクスペリエンスを向上させるだけでなく、サーバー側の負荷を軽減し、データ処理の即時性と効率を高めることができます。この方法により、開発者はより動的で応答性の高いアプリケーションを構築でき、ユーザーはサーバーからの応答を待つことなく、必要な情報を迅速に取得できます。
本記事では、JavaScriptを使用してReactでPDF文書のテキストを抽出する方法を紹介します。
主な内容
- JavaScriptでPDFのテキストを抽出する基本手順
- レイアウトを保持したPDFテキストの抽出
- 空白を削除したPDFテキストの抽出
- 指定領域のPDFテキストの抽出
- 強調表示されたPDFテキストの抽出
本記事で紹介する方法では、Spire.PDF for JavaScriptを使用します。
NPMインストールコマンド:npm install spire.pdf
JavaScriptでPDFのテキストを抽出する基本手順
Spire.PDF for JavaScriptには、PDF文書を処理するWebAssemblyモジュールが提供されています。このモジュールのPdfTextExtractor
を使用すると、簡単にPDFのテキストを抽出できます。以下は、基本的な操作手順です。
-
WebAssembly環境の初期化
Spire.Pdf.Base.js
を読み込み、WebAssemblyモジュールを初期化します。 -
PDFファイルの読み込み
wasmModule.FetchFileToVFS()
を使用して、PDFファイルを仮想ファイルシステム(VFS)に保存します。 -
PDFドキュメントオブジェクトの作成
wasmModule.PdfDocument.Create()
でPdfDocument
インスタンスを作成し、PdfDocument.LoadFromFile()
でVFSからPDFを読み込みます。 -
テキスト抽出オプションの設定
wasmModule.PdfTextExtractOptions.Create()
を使用してPdfTextExtractOptions
インスタンスを作成し、抽出オプションを設定します。 -
PDFページの取得
PdfDocument.Pages.get_Item()
またはPages
コレクションをループ処理して、必要なページを取得します。 -
テキスト抽出器の作成
wasmModule.PdfTextExtractor.Create()
を使用して、取得したページオブジェクトからPdfTextExtractor
インスタンスを作成します。 -
テキストの抽出
PdfTextExtractor.ExtractText()
を呼び出し、PDFページからテキストを取得します。 -
テキストの処理・エクスポート
抽出したテキストを必要に応じて処理し、ローカルに保存します。
PdfTextExtractOptions
には、IsSimpleExtraction
、IsExtractAllText
、ExtractArea
、IsShowHiddenText
などのプロパティがあり、多様なカスタム抽出が可能です。
レイアウトを保持した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テキストの抽出
PdfTextExtractOptions
のIsSimpleExtraction
をtrue
に設定すると、不要な空白を削除し、テキストのレイアウトを保持せずに抽出できます。この方法は、抽出したテキストをさらに処理する場合に適しています。
コード例:
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テキストの抽出
PdfTextExtractOptions
のExtractArea
プロパティに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テキストを抽出する方法を紹介しました。また、レイアウトを保持した抽出、空白を削除した抽出、指定領域の抽出、強調表示テキストの抽出など、さまざまなカスタム抽出方法について解説しました。