iText 9: Java PDF Parsing Powerhouse — Encryption, Signatures, and Extraction
A hands-on guide to iText 9 for Java developers, covering new PDF 2.0 encryption (AES-GCM, PDF MAC), digital signature verification, PDF/A/UA compliance, Maven setup, and practical code for text extraction, page-by-page parsing, and image export.
Introduction to iText
iText is a low-level PDF SDK for Java and .NET. The community edition (iText Core/Community) is licensed under AGPL; commercial use in closed-source products requires a paid license. Core capabilities include generation (building pages with paragraphs, tables, images, headers/footers), parsing (extracting text, images, layers), manipulation (split, merge, stamp, fill forms), and compliance (PDF/A archiving, PDF/UA accessibility, digital signatures). Compared to Apache PDFBox, iText leans more toward production-grade typesetting and standards compliance, and unlike online converters it can be embedded directly in services — making it a standard choice for invoice recognition, contract archiving, and e-signature workflows in the Java ecosystem.
What's New in iText 9
iText 9.0 was released late 2024; the current version is 9.7.1. The major version breaks some 8.x compatibility, but migration is less painful than the 5-to-7 jump. Key changes developers will notice:
1. Encryption Catches Up to PDF 2.0 Standards
Version 9.0 adds support for two new ISO technical specifications:
ISO/TS 32003 : AES-GCM encryption in PDF 2.0 — faster and more secure than the legacy AES-CBC.
ISO/TS 32004 : PDF MAC — adds an integrity layer so any tampering with an encrypted document is immediately detectable.
In short: previously you could only lock a document; now you can also prove it hasn't been altered.
2. Digital Signatures: From Signing to Verification
iText 8 deepened signing capabilities; 9.0 completes the loop with a verification module. You can now verify a single signature, handle signatures inside encrypted documents, and traverse revision history and certificate chains — all without switching tools.
3. PDF/A and PDF/UA Creation Made Simpler
Accessibility and archiving have long been iText strengths. 9.0 streamlines creation and conformance checking for both standards. When signing a PDF/UA document, missing fonts or missing alternative text in the signature appearance now throw a conformance exception immediately, instead of leaving you to guess among a pile of property errors. A small but practical addition: an API to list which optional content groups (OCGs / layers) are actually used on a given page — handy for engineering drawings and layered design PDFs.
4. Minor Releases Keep Adding Value
9.5.0 : Brotli compression stream (future PDF spec), post-quantum signature algorithm experiments
9.7.0 : Native WebP image support, dynamic page margins, footnote layout, stronger decompression-bomb protection
9.7.1 : Fixed Jackson dependency security issue; upgrade from 9.7.0 recommended
Adding Dependencies in Five Minutes
The simplest Maven setup pulls the itext-core BOM plus the official Bouncy Castle adapter (required for crypto and signing):
<properties>
<itext.version>9.7.1</itext.version>
</properties>
<dependencies>
<dependency>
<groupId>com.itextpdf</groupId>
<artifactId>itext-core</artifactId>
<version>${itext.version}</version>
<type>pom</type>
</dependency>
<dependency>
<groupId>com.itextpdf</groupId>
<artifactId>bouncy-castle-adapter</artifactId>
<version>${itext.version}</version>
</dependency>
</dependencies>For lean projects that only need text extraction (no signing), you can depend on just kernel and layout:
<dependency>
<groupId>com.itextpdf</groupId>
<artifactId>kernel</artifactId>
<version>9.7.1</version>
</dependency>
<dependency>
<groupId>com.itextpdf</groupId>
<artifactId>layout</artifactId>
<version>9.7.1</version>
</dependency>Chinese PDFs require explicit font files (e.g., Source Han Sans, SimSun); iText does not synthesize CJK glyphs.
Three Most Common Parsing Tasks
Daily parsing work concentrates on three operations.
1. Extract All Visible Text from the Entire Document
Entry-level code and the go-to for checking whether a file contains selectable text:
import com.itextpdf.kernel.pdf.PdfDocument;
import com.itextpdf.kernel.pdf.PdfReader;
import com.itextpdf.kernel.pdf.canvas.parser.PdfTextExtractor;
import java.io.IOException;
public class ExtractAllText {
public static String extract(String pdfPath) throws IOException {
try (PdfDocument pdf = new PdfDocument(new PdfReader(pdfPath))) {
StringBuilder all = new StringBuilder();
int pages = pdf.getNumberOfPages();
for (int i = 1; i <= pages; i++) {
String pageText = PdfTextExtractor.getTextFromPage(pdf.getPage(i));
all.append("----- Page ").append(i).append(" -----
");
all.append(pageText).append('
');
}
return all.toString();
}
}
public static void main(String[] args) throws IOException {
String text = extract("invoice.pdf");
System.out.println(text);
}
} PdfTextExtractordefaults to a location-based strategy, which yields reading order closer to human perception than raw content-stream order. Scanned or image-only PDFs return empty strings — that's an OCR job, requiring pdfOCR or another recognition service.
2. Control Line Breaks and Reading Order with a Custom Strategy
When the default isn't enough, use LocationTextExtractionStrategy directly. In 9.x its delimiter is customizable, and the multi-page regex-based strategy ( RegexBasedLocationExtractionStrategy) has been fixed for cleaner results:
import com.itextpdf.kernel.pdf.PdfDocument;
import com.itextpdf.kernel.pdf.PdfReader;
import com.itextpdf.kernel.pdf.canvas.parser.PdfCanvasProcessor;
import com.itextpdf.kernel.pdf.canvas.parser.listener.LocationTextExtractionStrategy;
import java.io.IOException;
public class ExtractWithStrategy {
public static String extractFirstPage(String pdfPath) throws IOException {
try (PdfDocument pdf = new PdfDocument(new PdfReader(pdfPath))) {
LocationTextExtractionStrategy strategy = new LocationTextExtractionStrategy();
PdfCanvasProcessor processor = new PdfCanvasProcessor(strategy);
processor.processPageContent(pdf.getFirstPage());
return strategy.getResultantText();
}
}
}For invoices, the typical flow: extract full-page text, then regex-match anchors like invoice number and total amount. Once the layout is stable, this is far cheaper than invoking a large model.
3. Export Embedded Images from Pages
Common in receipt recognition and ID archiving — extract images first, then feed to OCR:
import com.itextpdf.kernel.pdf.PdfDocument;
import com.itextpdf.kernel.pdf.PdfPage;
import com.itextpdf.kernel.pdf.PdfReader;
import com.itextpdf.kernel.pdf.xobject.PdfImageXObject;
import com.itextpdf.kernel.pdf.PdfName;
import com.itextpdf.kernel.pdf.PdfDictionary;
import com.itextpdf.kernel.pdf.PdfStream;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
public class ExtractImages {
public static void dump(String pdfPath, String outputDir) throws IOException {
Path dir = Paths.get(outputDir);
Files.createDirectories(dir);
try (PdfDocument pdf = new PdfDocument(new PdfReader(pdfPath))) {
int seq = 1;
for (int i = 1; i <= pdf.getNumberOfPages(); i++) {
PdfPage page = pdf.getPage(i);
PdfDictionary resources = page.getResources().getPdfObject();
PdfDictionary xobjects = resources.getAsDictionary(PdfName.XObject);
if (xobjects == null) continue;
for (PdfName name : xobjects.keySet()) {
PdfStream stream = xobjects.getAsStream(name);
if (stream == null || !PdfName.Image.equals(stream.getAsName(PdfName.Subtype))) continue;
PdfImageXObject image = new PdfImageXObject(stream);
String ext = image.identifyImageFileExtension();
Path dest = dir.resolve("page-" + i + "-img-" + seq + "." + ext);
Files.write(dest, image.getImageBytes());
seq++;
}
}
}
}
}Check the extension after export — JPEG and PNG are most common; since 9.7 WebP can also appear in PDFs.
Parsing Pipeline Overview
Chaining the snippets above yields a short pipeline. iText does not "understand" business meaning; it only restores page content into raw material you can further process. One habit to remember: open with PdfReader, wrap in PdfDocument, and always close — the examples use try-with-resources; keep that pattern in production to avoid handle leaks during batch jobs on large files. If a file may be corrupt, create the PdfReader in non-strict mode; 9.x gives clearer diagnostics when xref table reconstruction fails.
Generating PDFs
Parsing is often followed by generating a receipt PDF. Minimal example:
import com.itextpdf.kernel.pdf.PdfDocument;
import com.itextpdf.kernel.pdf.PdfWriter;
import com.itextpdf.layout.Document;
import com.itextpdf.layout.element.Paragraph;
import com.itextpdf.kernel.font.PdfFont;
import com.itextpdf.kernel.font.PdfFontFactory;
import com.itextpdf.io.font.constants.StandardFonts;
import java.io.IOException;
public class CreateSimplePdf {
public static void create(String dest) throws IOException {
PdfFont font = PdfFontFactory.createFont(StandardFonts.HELVETICA);
try (PdfWriter writer = new PdfWriter(dest);
PdfDocument pdf = new PdfDocument(writer);
Document doc = new Document(pdf)) {
doc.setFont(font);
doc.add(new Paragraph("Hello, iText 9"));
doc.add(new Paragraph("This PDF was created by Java."));
}
}
}For Chinese, replace StandardFonts.HELVETICA with a disk font path, e.g.:
PdfFont font = PdfFontFactory.createFont(
"C:/Windows/Fonts/simsun.ttc,0",
"Identity-H",
PdfFontFactory.EmbeddingStrategy.PREFER_EMBEDDED
); Identity-Hdenotes Unicode horizontal writing; PREFER_EMBEDDED ensures the font is embedded so the PDF opens correctly on machines without that font installed.
Common Pitfalls
Scanned pages are not text. PdfTextExtractor returns empty; verify in Acrobat whether text is selectable first.
Chinese requires explicit fonts. Omitting them causes missing glyphs, tofu blocks, or exceptions.
Encrypted documents need passwords. Use new PdfReader(path, new ReaderProperties().setPassword(...)); empty password, user password, and owner password are distinct.
AGPL is not "free for any use". Internal tools and open-source projects are fine; closed-source commercial distribution requires a commercial license.
Upgrading from 8 to 9: read the Breaking Changes first. Conformance, signature, and layer APIs have been reorganized; following the official migration guide is faster than fixing compile errors one by one.
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.
java1234
Former senior programmer at a Fortune Global 500 company, dedicated to sharing Java expertise. Visit Feng's site: Java Knowledge Sharing, www.java1234.com
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.
