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.
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 brevity2.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");
}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.
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.
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.
