PDFBox: A Powerful Open‑Source Java Library for PDF Manipulation

This article introduces Apache PDFBox, an open‑source Java library for creating, modifying, and extracting content from PDFs, and provides step‑by‑step Spring Boot 3.5 examples covering text extraction, region extraction, metadata handling, image insertion, form creation, JavaScript actions, and bookmark generation.

Spring Full-Stack Practical Cases
Spring Full-Stack Practical Cases
Spring Full-Stack Practical Cases
PDFBox: A Powerful Open‑Source Java Library for PDF Manipulation

1. Introduction

Apache PDFBox® is an open‑source Java library for creating, modifying and extracting content from PDF documents. It also provides several command‑line utilities.

Core Features

Extract Text – Unicode text extraction and page‑wise parsing.

Split & Merge – Split a PDF into multiple files or merge several PDFs into one.

Fill Forms – Read form data, populate interactive fields.

Preflight – Validate PDF/A‑1b compliance.

Print – Directly print PDFs via Java’s standard printing API.

Save as Image – Export pages to PNG, JPEG, etc.

Create PDFs – Generate PDFs from scratch, embed fonts, images, draw graphics.

Signing – Apply digital signatures for tamper‑proofing.

2. Practical Examples (Spring Boot 3.5.0)

2.1 Extract Text

File file = new File("e:/技术架构.pdf");
try (PDDocument document = Loader.loadPDF(file)) {
    AccessPermission ap = document.getCurrentAccessPermission();
    if (!ap.canExtractContent()) {
        throw new IOException("没有权限抽取文本内容");
    }
    PDFTextStripper stripper = new PDFTextStripper();
    stripper.setSortByPosition(true);
    for (int p = 1; p <= document.getNumberOfPages(); ++p) {
        stripper.setStartPage(p);
        stripper.setEndPage(p);
        String text = stripper.getText(document);
        System.out.println(String.format("page %d:", p));
        System.out.println("----------");
        System.out.println(text.trim());
        System.out.println();
    }
}

2.2 Extract Region Text

File file = new File("e:/技术架构.pdf");
try (PDDocument document = Loader.loadPDF(file)) {
    PDFTextStripperByArea stripper = new PDFTextStripperByArea();
    stripper.setSortByPosition(true);
    Rectangle rect = new Rectangle(10, 280, 275, 60);
    stripper.addRegion("f-region", rect);
    PDPage firstPage = document.getPage(0);
    stripper.extractRegions(firstPage);
    System.out.println("该区域的文本内容: %s".formatted(rect));
    System.out.println(stripper.getTextForRegion("f-region"));
}

2.3 Extract Metadata

public static void main(String[] args) throws IOException, XmpParsingException, BadFieldValueException {
    File file = new File("e:/技术架构.pdf");
    try (PDDocument document = Loader.loadPDF(file)) {
        PDDocumentCatalog catalog = document.getDocumentCatalog();
        PDMetadata meta = catalog.getMetadata();
        if (meta != null) {
            DomXmpParser xmpParser = new DomXmpParser();
            try {
                XMPMetadata metadata = xmpParser.parse(meta.toByteArray());
                showDublinCoreSchema(metadata);
                showAdobePDFSchema(metadata);
                showXMPBasicSchema(metadata);
            } catch (XmpParsingException e) {
                System.err.println("An error occurred when parsing the metadata: " + e.getMessage());
            }
        } else {
            PDDocumentInformation information = document.getDocumentInformation();
            if (information != null) {
                showDocumentInformation(information);
            }
        }
    }
}
// helper methods omitted for brevity

2.4 Add Image to PDF

public class AddImageToPdf {
    public void createPDFFromImage(String inputFile, String imagePath, String outputFile) throws IOException {
        try (PDDocument doc = Loader.loadPDF(new File(inputFile))) {
            PDPage page = doc.getPage(0);
            PDImageXObject pdImage = PDImageXObject.createFromFile(imagePath, doc);
            try (PDPageContentStream contentStream = new PDPageContentStream(doc, page, AppendMode.APPEND, true, true)) {
                float scale = 1f;
                contentStream.drawImage(pdImage, 20, 20, pdImage.getWidth() * scale, pdImage.getHeight() * scale);
            }
            doc.save(outputFile);
        }
    }
    public static void main(String[] args) throws IOException {
        new AddImageToPdf().createPDFFromImage("e:/技术架构.pdf", "d:/images/8.png", "e:/技术架构2.pdf");
    }
}

2.5 Add Text Message to Each Page

public class AddMessageToEachPage {
    public void doIt(String src, String message, String outfile) throws IOException {
        try (PDDocument doc = Loader.loadPDF(new File(src))) {
            File fontFile = new File("C:/Windows/Fonts/simhei.ttf");
            FileInputStream fis = new FileInputStream(fontFile);
            PDType0Font font = PDType0Font.load(doc, fis, true);
            float fontSize = 22.0f;
            for (PDPage page : doc.getPages()) {
                PDRectangle pageSize = page.getMediaBox();
                float stringWidth = font.getStringWidth(message) * fontSize / 1000f;
                int rotation = page.getRotation();
                boolean rotate = rotation == 90 || rotation == 270;
                float pageWidth = rotate ? pageSize.getHeight() : pageSize.getWidth();
                float pageHeight = rotate ? pageSize.getWidth() : pageSize.getHeight();
                float centerX = rotate ? pageHeight / 2f : (pageWidth - stringWidth) / 2f;
                float centerY = rotate ? (pageWidth - stringWidth) / 2f : pageHeight / 2f;
                try (PDPageContentStream contentStream = new PDPageContentStream(doc, page, AppendMode.PREPEND, true, true)) {
                    contentStream.beginText();
                    contentStream.setFont(font, fontSize);
                    contentStream.setNonStrokingColor(Color.red);
                    if (rotate) {
                        contentStream.setTextMatrix(Matrix.getRotateInstance(Math.PI / 2, centerX, centerY));
                    } else {
                        contentStream.setTextMatrix(Matrix.getTranslateInstance(centerX, centerY));
                    }
                    contentStream.showText(message);
                    contentStream.endText();
                }
            }
            doc.save(outfile);
        }
    }
    public static void main(String[] args) throws IOException {
        new AddMessageToEachPage().doIt("e:/技术架构.pdf", "Spring Boot3实战案例300讲", "e:/技术架构2.pdf");
    }
}

2.6 Create Interactive Form

public class CreateForm {
    public static void main(String[] args) throws IOException {
        try (PDDocument document = new PDDocument()) {
            PDPage page = new PDPage(PDRectangle.A4);
            document.addPage(page);
            File fontFile = new File("C:/Windows/Fonts/simhei.ttf");
            FileInputStream fis = new FileInputStream(fontFile);
            PDType0Font chineseFont = PDType0Font.load(document, fis, true);
            PDResources resources = new PDResources();
            resources.put(COSName.getPDFName("SimHei"), chineseFont);
            PDAcroForm acroForm = new PDAcroForm(document);
            document.getDocumentCatalog().setAcroForm(acroForm);
            acroForm.setDefaultResources(resources);
            acroForm.setDefaultAppearance("/SimHei 10 Tf 0 0 0 rg");
            float pageWidth = PDRectangle.A4.getWidth();
            float formWidth = 460;
            float left = (pageWidth - formWidth) / 2f;
            float labelWidth = 130;
            float fieldX = left + labelWidth;
            float fieldW = formWidth - labelWidth - 10;
            float rowHeight = 42;
            float baseY = page.getMediaBox().getHeight() - 80;
            try (PDPageContentStream cs = new PDPageContentStream(document, page)) {
                cs.beginText();
                cs.setFont(chineseFont, 16);
                cs.newLineAtOffset(left, baseY + 10);
                cs.showText("用户问卷调查");
                cs.endText();
                cs.setFont(chineseFont, 11);
                // 1. 姓名
                drawText(cs, left, baseY, "1. 姓名:");
                addTextField(document, acroForm, page, "name", fieldX, baseY - 14, fieldW, 24);
                baseY -= rowHeight;
                // 2. 联系电话
                drawText(cs, left, baseY, "2. 联系电话:");
                addTextField(document, acroForm, page, "phone", fieldX, baseY - 14, fieldW, 24);
                baseY -= rowHeight;
                // 3. 年龄
                drawText(cs, left, baseY, "3. 年龄:");
                addTextField(document, acroForm, page, "age", fieldX, baseY - 14, fieldW, 24);
                baseY -= rowHeight;
                // 4. 产品满意度意见
                drawText(cs, left, baseY, "4. 产品满意度意见:");
                addMultilineField(document, acroForm, page, "satisfyOpinion", fieldX, baseY - 70, fieldW, 60);
                baseY -= 88;
                // 5. 是否愿意继续使用
                drawText(cs, left, baseY, "5. 是否愿意继续使用:");
                float checkBoxSize = 18;
                float textOffsetY = 4;
                addCheckBox(document, acroForm, page, "useYes", fieldX, baseY - 10, checkBoxSize, checkBoxSize);
                cs.beginText();
                cs.setFont(chineseFont, 11);
                cs.newLineAtOffset(fieldX + 22, baseY + textOffsetY);
                cs.showText("愿意");
                cs.endText();
                float noX = fieldX + 90;
                addCheckBox(document, acroForm, page, "useNo", noX, baseY - 10, checkBoxSize, checkBoxSize);
                cs.beginText();
                cs.setFont(chineseFont, 11);
                cs.newLineAtOffset(noX + 22, baseY + textOffsetY);
                cs.showText("不愿意");
                cs.endText();
                baseY -= rowHeight;
                // 6. 其他备注
                drawText(cs, left, baseY, "6. 其他备注:");
                addMultilineField(document, acroForm, page, "otherRemark", fieldX, baseY - 70, fieldW, 60);
            }
            document.save("e:/survey_form.pdf");
            System.out.println("问卷表单生成完成:e:/survey_form.pdf");
        }
    }
    // helper methods drawText, addTextField, addMultilineField, addCheckBox omitted for brevity
}

2.7 Add JavaScript Action

try (PDDocument document = Loader.loadPDF(new File("e:/技术架构.pdf"))) {
    PDActionJavaScript javascript = new PDActionJavaScript(
        "app.alert( {cMsg: 'PDFBox rocks!', nIcon: 3, nType: 0, cTitle: 'PDFBox Javascript' } );");
    document.getDocumentCatalog().setOpenAction(javascript);
    if (document.isEncrypted()) {
        throw new IOException("Encrypted documents are not supported for this example");
    }
    document.save("e:/技术架构2.pdf");
}

2.8 Add Bookmarks (Outline)

try (PDDocument document = Loader.loadPDF(new File("e:/技术架构.pdf"))) {
    PDDocumentOutline outline = new PDDocumentOutline();
    document.getDocumentCatalog().setDocumentOutline(outline);
    PDOutlineItem pagesOutline = new PDOutlineItem();
    pagesOutline.setTitle("前后端技术架构");
    outline.addLast(pagesOutline);
    int pageNum = 0;
    for (PDPage page : document.getPages()) {
        pageNum++;
        PDPageDestination dest = new PDPageFitWidthDestination();
        dest.setPage(page);
        PDOutlineItem bookmark = new PDOutlineItem();
        bookmark.setDestination(dest);
        bookmark.setTitle("Page " + pageNum);
        pagesOutline.addLast(bookmark);
    }
    pagesOutline.openNode();
    outline.openNode();
    document.getDocumentCatalog().setPageMode(PageMode.USE_OUTLINES);
    document.save("e:/技术架构2.pdf");
}
Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

JavaSpring BootPDF manipulationPDFBoxPDF processing
Spring Full-Stack Practical Cases
Written by

Spring Full-Stack Practical Cases

Full-stack Java development with Vue 2/3 front-end suite; hands-on examples and source code analysis for Spring, Spring Boot 2/3, and Spring Cloud.

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.