Why Apache PDFBox Is Becoming the Go-To Java PDF Library
This article provides a comprehensive guide to Apache PDFBox, covering its licensing advantages, latest version, installation steps, core APIs for creating, editing, extracting, merging, encrypting and signing PDFs, underlying architecture, migration tips, performance considerations, and real‑world use cases.
Introduction
Apache PDFBox is an open‑source Java library for processing PDF documents. It is maintained by the Apache Software Foundation and released under the Apache 2.0 license.
As of July 2026 the latest version is 3.0.8 .
What PDFBox Is
PDFBox provides a one‑stop solution for PDF handling, including:
Create new PDF files
Edit existing PDFs
Extract text, images and metadata
Merge, split, encrypt, decrypt and sign PDFs
Why Choose PDFBox?
License: Apache 2.0 permits free use, modification and distribution in closed‑source commercial products, unlike iText’s AGPL.
Active Apache top‑level project: continuous releases (3.0.6, 3.0.7, 3.0.8 in 2026).
Feature completeness: covers text extraction, digital signatures, merging, encryption, etc.
Environment Setup (≈5 minutes)
Adding the Dependency
PDFBox 3.x requires Java 8+.
<dependency>
<groupId>org.apache.pdfbox</groupId>
<artifactId>pdfbox</artifactId>
<version>3.0.8</version>
</dependency>Gradle:
implementation 'org.apache.pdfbox:pdfbox:3.0.8'First Program – Extract Text
import org.apache.pdfbox.Loader;
import org.apache.pdfbox.pdmodel.PDDocument;
import org.apache.pdfbox.text.PDFTextStripper;
import java.io.File;
import java.io.IOException;
public class ExtractText {
public static void main(String[] args) throws IOException {
File file = new File("sample.pdf");
try (PDDocument document = Loader.loadPDF(file)) {
PDFTextStripper stripper = new PDFTextStripper();
String text = stripper.getText(document);
System.out.println(text);
}
}
}Key note: PDDocument.load() was removed in 3.0; use Loader.loadPDF() instead.
Extract a specific page range:
try (PDDocument document = Loader.loadPDF(new File("sample.pdf"))) {
PDFTextStripper stripper = new PDFTextStripper();
stripper.setStartPage(2);
stripper.setEndPage(4);
String text = stripper.getText(document);
System.out.println(text);
}Core Operations – From Basics to Advanced
Create a PDF Document
import org.apache.pdfbox.pdmodel.PDDocument;
import org.apache.pdfbox.pdmodel.PDPage;
import org.apache.pdfbox.pdmodel.PDPageContentStream;
import org.apache.pdfbox.pdmodel.font.PDType1Font;
public class CreatePDF {
public static void main(String[] args) {
try (PDDocument document = new PDDocument()) {
PDPage page = new PDPage();
document.addPage(page);
PDPageContentStream cs = new PDPageContentStream(document, page);
cs.setFont(PDType1Font.HELVETICA_BOLD, 12);
cs.beginText();
cs.newLineAtOffset(100, 700); // X=100, Y=700 from lower‑left
cs.showText("Hello, PDFBox!");
cs.endText();
cs.close();
document.save("HelloPDFBox.pdf");
} catch (Exception e) {
e.printStackTrace();
}
}
}Coordinate system: origin is at the lower‑left corner; X increases to the right, Y upwards.
Handling multiple lines:
cs.setLeading(14.5f);
cs.showText("First line");
cs.newLine();
cs.showText("Second line");Extract Images
import org.apache.pdfbox.pdmodel.PDDocument;
import org.apache.pdfbox.pdmodel.PDPage;
import org.apache.pdfbox.pdmodel.PDResources;
import org.apache.pdfbox.pdmodel.graphics.image.PDImageXObject;
import org.apache.pdfbox.cos.COSName;
import java.io.File;
import java.io.IOException;
public class ExtractImages {
public static void main(String[] args) throws IOException {
try (PDDocument doc = Loader.loadPDF(new File("sample.pdf"))) {
for (int i = 0; i < doc.getNumberOfPages(); i++) {
PDPage page = doc.getPage(i);
PDResources res = page.getResources();
for (COSName name : res.getXObjectNames()) {
if (res.isImageXObject(name)) {
PDImageXObject img = (PDImageXObject) res.getXObject(name);
System.out.println("Found image: " + name.getName());
}
}
}
}
}
}Merge PDFs
import org.apache.pdfbox.io.MemoryUsageSetting;
import org.apache.pdfbox.multipdf.PDFMergerUtility;
import java.io.File;
import java.io.IOException;
public class MergePDFs {
public static void main(String[] args) throws IOException {
PDFMergerUtility merger = new PDFMergerUtility();
merger.addSource(new File("file1.pdf"));
merger.addSource(new File("file2.pdf"));
merger.addSource(new File("file3.pdf"));
merger.setDestinationFileName("merged.pdf");
merger.mergeDocuments(MemoryUsageSetting.setupMainMemoryOnly());
}
}Encrypt a PDF
import org.apache.pdfbox.pdmodel.PDDocument;
import org.apache.pdfbox.pdmodel.encryption.AccessPermission;
import org.apache.pdfbox.pdmodel.encryption.StandardProtectionPolicy;
import java.io.File;
import java.io.IOException;
public class EncryptPDF {
public static void main(String[] args) throws IOException {
try (PDDocument doc = Loader.loadPDF(new File("sample.pdf"))) {
AccessPermission ap = new AccessPermission();
ap.setCanPrint(true);
ap.setCanModify(false);
StandardProtectionPolicy spp = new StandardProtectionPolicy(
"user_password", "owner_password", ap);
spp.setEncryptionKeyLength(128);
doc.protect(spp);
doc.save("encrypted.pdf");
}
}
}Fill an AcroForm
import org.apache.pdfbox.pdmodel.PDDocument;
import org.apache.pdfbox.pdmodel.interactive.form.PDAcroForm;
import org.apache.pdfbox.pdmodel.interactive.form.PDTextField;
import java.io.File;
import java.io.IOException;
public class FillForm {
public static void main(String[] args) throws IOException {
try (PDDocument doc = Loader.loadPDF(new File("form.pdf"))) {
PDAcroForm form = doc.getDocumentCatalog().getAcroForm();
PDTextField name = (PDTextField) form.getField("name");
if (name != null) name.setValue("张三");
PDTextField email = (PDTextField) form.getField("email");
if (email != null) email.setValue("[email protected]");
doc.save("filled_form.pdf");
}
}
}Underlying Principles
How does PDFBox turn a binary PDF into readable text and images?
Understanding the low‑level mechanics clarifies capability limits and performance bottlenecks.
Physical Structure of a PDF
File header – version marker (e.g., %PDF-1.7)
File body – stores all objects (pages, images, fonts, annotations)
Cross‑reference table – enables fast object lookup
File trailer – points to the cross‑reference table and the document root
PDFBox’s Two‑Layer Architecture
COS layer (low‑level): Direct mapping of PDF primitives such as COSDictionary, COSArray, COSStream. Provides full access to the file’s internals.
PD layer (high‑level): Developer‑friendly APIs – PDDocument (whole document), PDPage (a page), PDPageContentStream (content stream). Enables common tasks while allowing a drop‑down to the COS layer for fine‑grained control.
Three‑Tier Content Processing Pipeline
First tier – PDFStreamEngine (basic processing): Parses content streams into token sequences, dispatches operations, maintains graphic state and resources.
Second tier – PDFGraphicsStreamEngine (graphics abstraction): Defines abstract methods for path construction, filling, stroking and image drawing – describes *what* to draw, not *how*.
Third tier – Implementation layer: Concrete classes such as PageDrawer (renders to Graphics2D) and PDFTextStripper (extracts text). PDFTextStripper overrides showGlyph() to collect glyph positions.
This design gives PDFBox excellent extensibility; developers can subclass PDFStreamEngine for custom analysis or rendering.
Common Issues and Pitfalls
Migration from 2.x to 3.x
PDDocument.load() removed: replace with Loader.loadPDF().
IO module refactor: new Loader class and MemoryUsageSetting for memory control.
// PDFBox 2.x
PDDocument doc = PDDocument.load(new File("sample.pdf"));
// PDFBox 3.x
PDDocument doc = Loader.loadPDF(new File("sample.pdf"));Chinese Font Support
The default PDType1Font does not render Chinese characters. Load a TrueType font manually:
PDType0Font font = PDType0Font.load(document, new File("simsun.ttf"));
contentStream.setFont(font, 12);Large‑File Performance
When using Loader.loadPDF(), pass a MemoryUsageSetting to limit RAM consumption.
Process the document page‑by‑page for very large files.
Use try‑with‑resources to ensure streams are closed promptly.
Advantages
Apache 2.0 license – free for commercial closed‑source use.
Comprehensive feature set (text extraction, digital signatures, merging, encryption, etc.).
Active Apache top‑level project with frequent releases.
Intuitive API – easy for developers without prior PDF experience.
Command‑line tools for common tasks.
Pure Java implementation – runs on any Java‑compatible platform.
Disadvantages
Performance on very large or complex PDFs can be slower than commercial alternatives.
Table extraction is not built‑in; external tools such as Tabula‑java are required.
Chinese text requires manual font loading.
Version 3.0 introduces breaking API changes that need careful migration.
Recommended Scenarios
Document management systems – create, edit and extract PDF content.
Automated report generation – produce complex PDFs with charts and tables.
Contract/invoice parsing – extract structured data under a commercial‑friendly license.
E‑book readers – support text search and content extraction.
Digital signatures – standards‑compliant signing.
PDF encryption/decryption – dual‑password protection.
PDF merging/splitting – use PDFMergerUtility.
References
GitHub repository: https://github.com/apache/pdfbox
Official documentation: https://pdfbox.apache.org
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
Su San Talks Tech
Su San, former staff at several leading tech companies, is a top creator on Juejin and a premium creator on CSDN, and runs the free coding practice site www.susan.net.cn.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
