Java Tips | I/O・ネットワーク:PDF読込

Java Java
スポンサーリンク
スポンサーリンク

PDF読込ユーティリティが業務で必要になる理由

PDFは「改ざんされにくい」「どの環境でも同じ見た目で表示できる」という特性から、請求書・契約書・レポート・帳票など、業務システムの“受け取る側”として非常に多く使われています。 そのため、Java で PDFを読み込んでテキスト抽出する・ページ数を調べる・画像を取り出す といった処理は、実務で必須になります。

しかし、初心者がやりがちな「PDFを文字列として扱う」「正規表現で解析する」といった実装は、PDFの構造を理解していないため必ず破綻します。 PDFは“描画命令の集まり”であり、内部構造はHTMLやテキストファイルとはまったく異なります。

そこで役に立つのが PDF読込ユーティリティ です。 Javaでは Apache PDFBox が事実上の標準ライブラリで、初心者でも扱いやすく、業務でも十分使える品質です。

PDF読込の基本発想

PDFは「ページ → 描画命令 → テキスト抽出」という構造で読む

PDFは次の階層構造でできています。

  • PDDocument(PDFファイル)
  • PDPage(ページ)
  • PDFTextStripper(テキスト抽出器)

PDFは“テキストファイル”ではなく、“描画命令の集合体”です。 そのため、テキスト抽出には専用の抽出器(PDFTextStripper)を使う必要があります。

PDF読込の最小構成(初心者向け)

まずは「PDFからテキストを抽出する」だけのシンプルな例

import org.apache.pdfbox.pdmodel.PDDocument;
import org.apache.pdfbox.text.PDFTextStripper;
import java.nio.file.Files;
import java.nio.file.Path;

public class SimplePdfReader {

    public static String readText(Path path) throws Exception {
        try (PDDocument doc = PDDocument.load(Files.readAllBytes(path))) {
            PDFTextStripper stripper = new PDFTextStripper();
            return stripper.getText(doc);
        }
    }
}
Java

使い方の例です。

String text = SimplePdfReader.readText(Path.of("data/sample.pdf"));
System.out.println(text);
Java

ここで重要なのは 「PDFをバイト列として読み込む」 という点です。 PDFはバイナリ形式なので、文字コードを意識する必要はありません。

PDFのページ数を取得する

PDDocument の getNumberOfPages を使う

try (PDDocument doc = PDDocument.load(Files.readAllBytes(path))) {
    int pages = doc.getNumberOfPages();
    System.out.println("ページ数: " + pages);
}
Java

ページ数は帳票処理やレポート解析でよく使います。

PDFの特定ページだけを読む

PDFTextStripper の範囲指定を使う

PDFTextStripper stripper = new PDFTextStripper();
stripper.setStartPage(2);
stripper.setEndPage(2);

String pageText = stripper.getText(doc);
Java

ここで深掘りしたいポイントは 「PDFはページ単位で抽出できる」 ということです。 大量のPDFを扱う場合、必要なページだけ抽出することで処理が高速になります。

PDFから画像を抽出する

PDResources → XObject → PDImageXObject の流れ

import org.apache.pdfbox.pdmodel.PDPage;
import org.apache.pdfbox.pdmodel.graphics.PDXObject;
import org.apache.pdfbox.pdmodel.graphics.image.PDImageXObject;

public static void extractImages(Path path) throws Exception {
    try (PDDocument doc = PDDocument.load(Files.readAllBytes(path))) {
        int pageIndex = 0;
        for (PDPage page : doc.getPages()) {
            var resources = page.getResources();
            for (COSName name : resources.getXObjectNames()) {
                PDXObject xobj = resources.getXObject(name);
                if (xobj instanceof PDImageXObject) {
                    PDImageXObject img = (PDImageXObject) xobj;
                    Path out = Path.of("out/image_" + pageIndex + "_" + name.getName() + ".png");
                    ImageIO.write(img.getImage(), "png", out.toFile());
                }
            }
            pageIndex++;
        }
    }
}
Java

ここで深掘りしたいポイントは 「PDFの画像はXObjectとして埋め込まれている」 ということです。 PDFは画像を“描画命令”として持っているため、画像抽出は少し特殊な処理になります。

実務向け PDF読込ユーティリティ(テンプレート)

テキスト抽出・ページ数取得・画像抽出をまとめた形

import org.apache.pdfbox.pdmodel.*;
import org.apache.pdfbox.text.PDFTextStripper;
import org.apache.pdfbox.pdmodel.graphics.image.PDImageXObject;
import org.apache.pdfbox.pdmodel.graphics.PDXObject;
import org.apache.pdfbox.cos.COSName;

import javax.imageio.ImageIO;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.List;

public class PdfUtils {

    public static String extractText(Path path) throws Exception {
        try (PDDocument doc = PDDocument.load(Files.readAllBytes(path))) {
            PDFTextStripper stripper = new PDFTextStripper();
            return stripper.getText(doc);
        }
    }

    public static int getPageCount(Path path) throws Exception {
        try (PDDocument doc = PDDocument.load(Files.readAllBytes(path))) {
            return doc.getNumberOfPages();
        }
    }

    public static List<Path> extractImages(Path path, Path outDir) throws Exception {
        List<Path> results = new ArrayList<>();

        try (PDDocument doc = PDDocument.load(Files.readAllBytes(path))) {
            int pageIndex = 0;
            for (PDPage page : doc.getPages()) {
                var resources = page.getResources();
                for (COSName name : resources.getXObjectNames()) {
                    PDXObject xobj = resources.getXObject(name);
                    if (xobj instanceof PDImageXObject) {
                        PDImageXObject img = (PDImageXObject) xobj;
                        Path out = outDir.resolve("image_" + pageIndex + "_" + name.getName() + ".png");
                        ImageIO.write(img.getImage(), "png", out.toFile());
                        results.add(out);
                    }
                }
                pageIndex++;
            }
        }
        return results;
    }
}
Java

使い方の例です。

String text = PdfUtils.extractText(Path.of("data/report.pdf"));
int pages = PdfUtils.getPageCount(Path.of("data/report.pdf"));
List<Path> images = PdfUtils.extractImages(Path.of("data/report.pdf"), Path.of("out"));
Java

PDF読込で必ず意識すべき重要ポイント

1. PDFは“テキストファイルではない”

内部は描画命令の集合体であり、テキスト抽出は専用の処理が必要です。

2. テキスト抽出は完全ではない

PDFの構造によっては、テキストが正しく抽出できない場合があります。 (画像として埋め込まれた文字など)

3. 画像抽出はページごとにXObjectを調べる

PDFは画像を“リソース”として持っているため、抽出処理は特殊です。

4. PDFはバイナリ形式なので文字コードを意識しなくてよい

ただし、抽出したテキストは UTF-8 で扱うのが一般的です。

PDF読込ユーティリティの実務的な使いどころ

外部ベンダーからのPDF帳票解析

請求書・契約書・レポートなどを自動解析できます。

管理画面でのPDFアップロード

アップロードされたPDFからテキストを抽出し、データベースに登録できます。

バッチ処理でのPDF解析

夜間バッチで大量のPDFを読み込み、テキスト抽出や画像抽出を行うことができます。

まとめ:PDF読込ユーティリティで身につけてほしい感覚

PDF読込ユーティリティは、業務データを“PDFという特殊な形式”から安全に取り出すための重要な仕組みです。 そこには次のようなポイントがあります。

  • PDFは「ページ → 描画命令 → テキスト抽出」という構造で読む
  • テキスト抽出は PDFTextStripper を使う
  • ページ数取得は PDDocument の getNumberOfPages
  • 画像抽出は XObject を調べる
  • PDFはバイナリ形式なので文字コードを意識しなくてよい

タイトルとURLをコピーしました