C++でPDF文書を操作する方法

C++でPDF文書を操作する方法

Aspose.PDF FOSS for C++ は MIT ライセンスの、依存関係のない C++20 ライブラリで、CMake でビルドおよびリンクされます — 追加するパッケージマネージャーからのインポートは不要です。このガイドでは、コア Document 中心のワークフローを順に解説します:既存の PDF を開く、ページとメタデータを検査する、テキストを抽出する、そしてページをラスタ画像としてレンダリングする。

ステップバイステップガイド

ステップ 1: パッケージをインストール

リポジトリをクローンし、サブディレクトリとして CMake プロジェクトに追加します:

git clone https://github.com/aspose-pdf-foss/Aspose.PDF-FOSS-for-Cpp.git
add_subdirectory(Aspose.PDF-FOSS-for-Cpp)
target_link_libraries(your_app PRIVATE aspose_pdf_foss)

または、スタンドアロンで構成してビルドします:

cmake -S . -B build -DCMAKE_BUILD_TYPE=Release
cmake --build build

ヘッダーに対して最小限のプログラムをコンパイルし、ツールチェーンが解決できることを確認します:

#include <aspose/pdf/document.hpp>
#include <iostream>

int main() {
    Aspose::Pdf::Document doc;
    std::cout << "Linked OK - pages: " << doc.Pages().Count() << "\n";
}

新しく作成された空の Document に対して pages: 0 を出力するビルドが成功すれば、ライブラリが正しくリンクされていることが確認できます。


ステップ 2: 必要なクラスをインポートする

#include <aspose/pdf/document.hpp>
#include <aspose/pdf/document_info.hpp>
#include <aspose/pdf/page.hpp>
#include <aspose/pdf/page_collection.hpp>
#include <aspose/pdf/text_absorber.hpp>
#include <aspose/pdf/bmp_device.hpp>
#include <aspose/pdf/resolution.hpp>
#include <fstream>
#include <iostream>

ステップ 3: PDF ドキュメントを開き、ページ数をカウントする

ファイルパスから Document を作成して既存の PDF を開きます。Document::Pages() は PageCollection を返し、Count() はそのページ数を報告します:

Aspose::Pdf::Document doc("input.pdf");
std::cout << "Page count: " << doc.Pages().Count() << "\n";

ステップ 4: ドキュメントのメタデータを読み取る

Document::Info() は、標準の /Info 辞書エントリ用の型付き読み書きアクセサを備えた DocumentInfo オブジェクトを返します:

auto& info = doc.Info();
std::cout << "Title: "    << info.Title()    << "\n";
std::cout << "Author: "   << info.Author()   << "\n";
std::cout << "Producer: " << info.Producer() << "\n";

ステップ 5: ページからテキストを抽出する

Aspose::Pdf::Text::TextAbsorber は Document または単一の Page を走査し、遭遇したテキストを蓄積します;Text() はその後結果を返します。PageCollection は 1 から始まるインデックスなので、Pages()[1] が最初のページです:

auto page = doc.Pages()[1];

Aspose::Pdf::Text::TextAbsorber absorber;
absorber.Visit(page);
std::cout << absorber.Text() << "\n";

Visit() は、単一ページではなくすべてのページのテキストを連結したい場合に、全体の Document を直接 (absorber.Visit(doc)) で受け付けます。


ステップ 6: ページをラスタ画像にレンダリングする

BmpDevice は Page を非圧縮 BMP 画像にレンダリングします。そのコンストラクタは出力 DPI を制御する Resolution を受け取り、Process() はレンダリングされたバイト列を任意の std::ostream に書き込みます:

Aspose::Pdf::Devices::BmpDevice device(Aspose::Pdf::Devices::Resolution(150));

std::ofstream imageOut("page1.bmp", std::ios::binary);
device.Process(page, imageOut);

ステップ 7: メタデータを更新し、ドキュメントを保存する

DocumentInfo のセッターは変更をステージングし、所有する Document 上で次に Save() が実行されたときにフラッシュされます:

doc.Info().Title("Processed by Aspose.PDF FOSS for C++");
doc.Save("output.pdf");

一般的な問題と対策

Accessing Pages()[0] throws std::out_of_range

PageCollection は 1 インデックスで、標準的な Aspose.PDF のセマンティクスと一致します — 最初のページは Pages()[1] です。1 未満または Count() より大きいインデックスはエラーになります。

TextAbsorber::Text() 空文字列を返す

Text() は、直近の Visit() 呼び出しで蓄積されたものを返します。Text() を読む前に Visit() が実際に呼び出されたことを確認し、訪れたページまたはドキュメントがスキャン画像だけでなく抽出可能なテキストを含んでいることを確認してください。

レンダリングされた BMP ファイルが予期せず小さい、または空白に見えます

低い Resolution 値は小さなラスタ画像を生成します。Resolution に渡す DPI を上げてください — 例えば、印刷品質の出力には Resolution(300) を使用します — そして、Process() に渡したページインデックスが意図したものか確認してください。

DocumentInfo フィールドが空文字列として読み戻される

すべての PDF 製作者が標準的な /Info エントリを書き込むわけではありません。メタデータ抽出が失敗したと仮定する前に、Producer() と Creator() が空白でないか確認してください — キーが存在しない場合の定義結果は空文字列です。

変更は Info().Title(...) 保存されたファイルに現れません

DocumentInfo の変異はメモリ内でステージングされ、同じ Document インスタンス上で次回 Save() が実行されたときにのみ永続化されます。メタデータの編集は Save() の前に行い、後にしないでください。

よくある質問

Aspose.PDF FOSS for C++ のページインデックスはゼロベースですか、それともワンベースですか?

ワンベースです。doc.Pages()[1] は常に最初のページです。

TextAbsorber は文書全体ではなく単一ページからテキストを抽出できますか?

はい。Visit() は Document — すべてのページのテキストを抽出する — または単一の Page、そのページのテキストだけを抽出する、のいずれかを受け取れるようにオーバーロードされています。

文書からデータを読み取るだけの場合、Save() を呼び出す必要がありますか?

いいえ。Save() は、DocumentInfo フィールドの編集など、ファイルに書き戻す必要がある変更を行った後にのみ必要です。ページ数の取得、テキストの抽出、ページのレンダリングは文書を変更しません。

レンダリングされたページの解像度をどのように制御しますか?

デバイスのコンストラクタに Resolution 値を渡します — 例として、150 DPI の場合は Resolution(150) を使用します。値が大きいほど、より大きく、より高忠実度のラスタ画像が生成されます。

BmpDevice が生成するフォーマットは何ですか?

未圧縮の BMP 画像が、Process() に渡された std::ostream に直接書き込まれます。

参照

 日本語