【Java】PDFBoxでPDF出力

使う用事があったのでPDFBox使った時の備忘録。

なんか前の職場でも書いた気がする。

準備

適当にIntelliJをインストールする。まぁエクリプスでもいいけどpom使う。
適当にMavenプロジェクトを作成。

pom.xml追記

pom.xml

<!-- https://mvnrepository.com/artifact/org.apache.pdfbox/pdfbox -->
<dependencies>
    <dependency>
        <groupId>org.apache.pdfbox</groupId>
        <artifactId>pdfbox</artifactId>
        <version>2.0.22</version>
    </dependency>
</dependencies>

適当にjavaファイル作成

PDFBoxTest.java

package com.oqiita;

public class PDFBoxTest {

    public static void main(String[] args) {
        System.out.println("PDFBoxTest");
    }
}

PDF出力

まずは空のPDFを出力

PDFBoxTest.java

package com.oqiita;

import org.apache.pdfbox.pdmodel.PDDocument;
import org.apache.pdfbox.pdmodel.PDPage;
import org.apache.pdfbox.pdmodel.PDPageContentStream;

import java.io.File;
import java.io.IOException;

public class PDFBoxTest {

    public static void main(String[] args) {
        // ドキュメントを作成
        try(PDDocument doc = new PDDocument())  {

            // ページを作成
            PDPage page = new PDPage();
            // ドキュメントにページを追加
            doc.addPage(page);
            // 保存
            doc.save("C:\\TEMP2\\PDFBox\\PDFBoxTest.pdf");

        }catch(IOException e) {
            e.printStackTrace();
        }
    }
}

文字出力

PDFBoxTest.java

package com.oqiita;

import org.apache.pdfbox.pdmodel.PDDocument;
import org.apache.pdfbox.pdmodel.PDPage;
import org.apache.pdfbox.pdmodel.PDPageContentStream;
import org.apache.pdfbox.pdmodel.font.PDFont;
import org.apache.pdfbox.pdmodel.font.PDType1Font;

import java.io.File;
import java.io.IOException;

public class PDFBoxTest {

    public static void main(String[] args) {
        // ドキュメントを作成
        try(PDDocument doc = new PDDocument())  {

            // ページを作成
            PDPage page = new PDPage();
            // ドキュメントにページを追加
            doc.addPage(page);
            // フォントを設定
            PDFont font = PDType1Font.HELVETICA_BOLD;

            // コンテンツを作成し、テキストを出力
            try (PDPageContentStream content = new PDPageContentStream(doc, page)) {
                content.beginText();
                content.setFont(font, 12);
                content.showText("HelloWorld");
                content.endText();
                font = null;
            }

            // 保存
            doc.save("C:\\TEMP2\\PDFBox\\PDFBoxTest.pdf");

        }catch(IOException e) {
            e.printStackTrace();
        }
    }
}

ページの左下に出ました。

文字の場所を変更

// コンテンツを作成し、テキストを出力
try (PDPageContentStream content = new PDPageContentStream(doc, page)) {
    content.beginText();
    content.setFont(font, 12);
    content.newLineAtOffset(200f, 500f);
    content.showText("HelloWorld");
    content.endText();
    font = null;
}

タイトル出力(文字列を中央に)

try (PDPageContentStream content = new PDPageContentStream(doc, page)) {
    // タイトル用の変数を設定
    String title = "PDFBox Sample Title";
    int marginTop = 20;
    int fontSize = 20;
    float titleWidth = font.getStringWidth(title) / 1000 * fontSize;
    float titleHeight = font.getFontDescriptor().getFontBoundingBox().getHeight() / 1000 * fontSize;

    // タイトル出力
    content.beginText();
    content.setFont(font, fontSize);
    content.newLineAtOffset((page.getMediaBox().getWidth() - titleWidth) / 2, page.getMediaBox().getHeight() - marginTop - titleHeight);
    content.showText(title);
    content.endText();

    ~~ 省略 ~~

}

ページ番号

ループでページを追加して、ページ下部にページ番号を出力

// ドキュメントを作成
try(PDDocument doc = new PDDocument())  {

    // フォントを読み込み
    PDFont font = PDType1Font.HELVETICA_BOLD;

    // タイトル用の変数を設定
    String title = "PDFBox Sample Title";
    int marginTop = 20;
    int fontSize = 20;
    float titleWidth = font.getStringWidth(title) / 1000 * fontSize;
    float titleHeight = font.getFontDescriptor().getFontBoundingBox().getHeight() / 1000 * fontSize;

    // ページ数
    String pageNumber = "";

    int pageNum = 10;
    for (int i = 0; i < pageNum; i++){
        // ページを作成
        PDPage page = new PDPage();

        // ドキュメントにページを追加
        doc.addPage(page);

        // コンテンツを作成し、テキストを出力
        try (PDPageContentStream content = new PDPageContentStream(doc, page)) {

            ~~ 省略 ~~

            // ページ数
            content.beginText();
            content.setFont(font, 10);
            pageNumber = Integer.toString(i + 1) + " / " + Integer.toString(pageNum);
            float pageNumberWidth = font.getStringWidth(pageNumber) / 1000 * 10;
            float pageNumberHeight = 5;
            content.newLineAtOffset((page.getMediaBox().getWidth() - pageNumberWidth) / 2, pageNumberHeight);
            content.showText(pageNumber);
            content.endText();

        }
    }

    font = null;
    // 保存
    doc.save("C:\\TEMP2\\PDFBox\\PDFBoxTest.pdf");

}catch(IOException e) {
    e.printStackTrace();
}

フォント埋め込み

PDFont font = PDType0Font.load(doc, new File("C:\\WINDOWS\\Fonts\\ARIAL.TTF"));

日本語

日本語出力するためには日本語表示用のフォントを埋め込む必要があります。
↑の方法で適当に日本語を表示できるTTFを埋め込みます。

今回はフリーフォントのやさしさゴシックを使わせてもらいました。
http://www.fontna.com/blog/736/

// フォントを設定
PDFont font = PDType0Font.load(doc, new File("C:\\USERS\\OQIITA\\APPDATA\\LOCAL\\MICROSOFT\\WINDOWS\\FONTS\\07やさしさゴシック.TTF"));

TTC フォント

File file = new File("C:\\WINDOWS\\Fonts\\meiryo.ttc");
try (TrueTypeCollection collection = new TrueTypeCollection(file)) {
    PDFont font = PDType0Font.load(doc, collection.getFontByName("Meiryo"), true);

    ~~ 省略 ~~
}

getFontByName で指定する名称ですが、これは調べてもよくわからなかった。
↓はインストールされているフォント名を全部出してくれる。getPSNameの部分を指定すればいいかと思うが、全部は検証してない。

Font [] fonts= GraphicsEnvironment.getLocalGraphicsEnvironment().getAllFonts();
for (int i = 0; i < fonts.length; i++) {
    System.out.println(fonts[i].getPSName() + ":" + fonts[i].getName() + ":" + fonts[i].getFamily());
}

画像埋め込み

// 画像を読み込み
PDImageXObject pdImage = PDImageXObject.createFromFile("C:\\TEMP2\\PDFBox\\oqiita.png", doc);

// 半分に縮小
float scale = 0.5f;
content.drawImage(pdImage, 20, 350, pdImage.getWidth()*scale, pdImage.getHeight()*scale);

// 1/4 に縮小
scale = 0.25f;
content.drawImage(pdImage, 20, 100, pdImage.getWidth()*scale, pdImage.getHeight()*scale);

PDFセキュリティ

PDF開いたときにパスワードが必要になったり、印刷とかができないようにセキュリティをかけれます。

// セキュリティ設定
AccessPermission ap = new AccessPermission();
ap.setCanAssembleDocument(false);
ap.setCanExtractContent(false);
ap.setCanExtractForAccessibility(false);
ap.setCanFillInForm(false);
ap.setCanModify(false);
ap.setCanModifyAnnotations(false);
ap.setCanPrint(false);
ap.setCanPrintDegraded(false);
StandardProtectionPolicy spp = new StandardProtectionPolicy("aaa","bbb",ap);
spp.setEncryptionKeyLength(128);
doc.protect(spp);

PDF画像変換

// 画像に変換
// パスを設定
Path imgPath = Paths.get("C:\\TEMP2\\PDFBox\\test.jpg");
Path pdfPath = Paths.get("C:\\TEMP2\\PDFBox\\PDFBoxTest.pdf");

try (InputStream in = new FileInputStream(pdfPath.toString());
     OutputStream out = Files.newOutputStream(imgPath);)
{
    try (PDDocument doc2 = PDDocument.load(in)) {
        PDFRenderer pdfRenderer = new PDFRenderer(doc2);
        BufferedImage bim = pdfRenderer.renderImageWithDPI(0, 300, ImageType.RGB);
        ImageIO.write(bim, "JPEG", out);
    }
}

PDF結合

try (PDDocument pdDocument = new PDDocument()) {
    PDFMergerUtility merger = new PDFMergerUtility();
    merger.addSource(new File("C:\\TEMP2\\PDFBox\\pdf1.pdf"));
    merger.addSource(new File("C:\\TEMP2\\PDFBox\\pdf2.pdf"));
    merger.setDestinationFileName("C:\\TEMP2\\PDFBox\\マージ.pdf");
    merger.mergeDocuments(MemoryUsageSetting.setupTempFileOnly());
} catch (IOException e) {
    e.printStackTrace();
}

まとめ

とりあえずいろいろできる!

以上です。

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です

このサイトはスパムを低減するために Akismet を使っています。コメントデータの処理方法の詳細はこちらをご覧ください