PDFBox3.0を用いたPDFへの描画(応用編)

2025 年 8 月 4 日 by nishimoton

この記事単体でも読めますが、PDFBox3.0を用いたPDFへの描画(基本編)を前提としています。

目次

  1. PDFBoxとは
  2. やりたいこと概要
  3. 事前準備:Adobe Acrobat ReaderでのPDF編集
  4. テキストコメントの座標取得
  5. 文字列等描画

1. PDFBoxとは

PDFドキュメントを操作するためのオープンソースのJavaツールです。
新しいPDFドキュメントの作成、既存のPDFの操作、PDFからのコンテンツの抽出、PDFへの描画などができます。
以下からダウンロードできます。
https://pdfbox.apache.org/downloads.html
2025年4月現在、3.0.xと2.0.xのふたつのバージョンがサポートされていますが、今回は3.0.xを使用します。

2. やりたいこと概要

この記事の目的は、以下のテンプレートPDFの枠内に文字列を描画することです。

このPDFはExcelで作成したのちPDFに変換したものです。
プログラムを用いて枠内に指定の文字列を描画することは、Excelに行うのは比較的簡単ですがPDFに行うのは難しいです。
直接座標を指定することも可能ですが実用的ではないため、テンプレートPDFを操作することで座標問題を解決しました。

3. 事前準備:Adobe Acrobat ReaderでのPDF編集

Adobe Acrobat ReaderでPDFの操作を行います。
流れとしては、

●Adobe Acrobat Reader

  1. テキストボックス型のコメントを用意する
  2. コメントのプロパティを編集する

●プログラム

  1. PDFに配置したコメントを取得する
  2. コメントの座標を取得する
  3. 取得した座標に文字列を描画する

まず、コメントを配置します。
メニューから「コメントを追加」を選択します。

次に、テキストボックス型のコメントを配置します。
複数あるアイコンから吹き出しマークを選び、さらに「テキストコメントを追加」を選択します。

描画したい枠にちょうど合うように、テキストコメントを配置します。

テキストコメントのプロパティを、プログラムで扱いやすいように変更します。
番号や描画する文字列の情報など、一意に決まる名前をタイトルに指定します。

4. テキストコメントの座標取得

コメントを配置したPDFをプログラム側で読み込みます。
まず、テキストコメントを取得します。
今回は管理の都合上、key:タイトル、value:テキストコメント情報となる連想配列としています。

try{
    // PDFの指定したページにあるオブジェクトをすべて取得する
    List<PDAnnotation> annotations = page.getAnnotations();

    for(PDAnnotation annotation : annotations){
            // 複数のオブジェクトから、テキストコメントのみを取得する
        if(annotation instanceof PDAnnotationFreeText) {
            COSString subject = (COSString)annotation.getCOSObject().getDictionaryObject(COSName.SUBJ);
            if(subject != null){
                freeTexts.put(subject.getString(), annotation);
            }
        }
    }
} catch (Exception e) {
    e.printStackTrace();
}

そして、3で変更したタイトルから特定のテキストコメントを取得します。
さらに取得したテキストコメントのその左下端、右上端の座標を取得します。

// タイトルが連想配列のkeyにある場合、valueとなるテキストコメントの座標を取得する
if(key.equals(/*タイトル*/)){
    PDAnnotation annotation = freeTexts.get(/*タイトル*/);
    COSArray rectArray = (COSArray) annotation.getCOSObject().getDictionaryObject(COSName.RECT);

    // 左下端座標の取得
    llx = ((COSFloat) rectArray.get(0)).floatValue();
    lly = ((COSFloat) rectArray.get(1)).floatValue();
    // 右上端座標の取得
    urx = ((COSFloat) rectArray.get(2)).floatValue();
    ury = ((COSFloat) rectArray.get(3)).floatValue();
}

5. 文字列等描画

指定したテキストコメントの場所に文字列を描画します。

まず、文字列の描画開始位置を計算します。
文字列の描画開始位置の計算には文字列の実質的な長さが必要であるため、そちらから求めます。
文字列の実質的な長さは、以下で求められます。

/*フォント*/.getStringWidth(/*文字列*/) / 1000 * /*フォントサイズ*/

これを踏まえて、文字列の描画開始位置のx座標を求めます。
MARGINが0だとスペースがなく窮屈に感じるため、必要に応じてMARGINの値を調整します。

// 左揃え
x = llx[ + MARGIN];
// 中央揃え
x = (llx + ury) / 2 - /*文字列の長さ*/ / 2;
// 右揃え
x = ury - /*文字列の長さ*/ / 2[ - MARGIN];

また、文字列の描画開始位置のy座標を求めます。

y = (lly + ury) / 2 - /*フォントサイズ*/ / 2 + /*フォントサイズ*/ / 2[ + MARGIN];

そして、算出した座標に描画します。
こちらはほとんどPDFBox3.0を用いたPDFへの描画(基本編)に示しているコードです。

// PDPageContentStreamを作成してテキストを追加する
PDPageContentStream contentStream = new PDPageContentStream(pdfDocument, page, PDPageContentStream.AppendMode.APPEND, true, true);

contentStream.beginText();
contentStream.setFont(/*フォント*/, /*フォントサイズ*/);
contentStream.newLineAtOffset(/*算出したx座標*/, /*算出したy座標*/);
contentStream.showText(/*描画するテキスト*/);
contentStream.endText();

contentStream.close();

今回は、枠に収まらない長さの文字列の処理まではしていません。
また、複数人がプログラムにアクセスすることやその他のエラーを想定していません。
実際に使えるプログラムにする場合、枠に収まらない長文の折り返しや複数のテキストコメントの配置を考慮しなければならないと思います。

タグ: , ,

TrackBack