ExtractPDF4J
Java PDF table extraction & OCR library. Extract structured tables from text-based and scanned PDFs using stream, lattice (OpenCV-style grid detection), and hybrid parsing.
Install / Use
npx skills add ExtractPDF4J/ExtractPDF4JInstalls into whichever agent you are using.
README
<br /> <p align="center"> <a href="https://extractpdf4j.github.io/ExtractPDF4J/"> <picture> <source media="(prefers-color-scheme: dark)" srcset="./docs/images/extractpdf4j-banner-dark.png"> <img alt="ExtractPDF4J - Java-native PDF table extraction for real-world documents" width="900" src="./docs/images/extractpdf4j-banner-light.png" /> </picture> </a> </p> <p align="center"> <a href="https://extractpdf4j.github.io/ExtractPDF4J/" target="_blank">→ extractpdf4j.github.io/ExtractPDF4J ←</a> </p> <p align="center"> Java-native PDF table extraction for text-based, scanned, and image-heavy documents. <br /> <br /> <a href="https://search.maven.org/search?q=io.github.extractpdf4j"> <img src="https://img.shields.io/badge/Maven%20Central-io.github.extractpdf4j-1565C0?style=for-the-badge" alt="Maven Central" /> </a> <a href="https://github.com/ExtractPDF4J/ExtractPDF4J"> <img src="https://img.shields.io/badge/Java-17%2B-1976D2?style=for-the-badge&logo=openjdk&logoColor=white" alt="Java 17+" /> </a> <a href="https://github.com/ExtractPDF4J/ExtractPDF4J/releases/tag/v2.1.0"> <img src="https://img.shields.io/badge/release-v2.1.0-616161?style=for-the-badge" alt="Release v2.1.0" /> </a> <a href="https://github.com/ExtractPDF4J/ExtractPDF4J"> <img src="https://img.shields.io/badge/OCR-supported-5E35B1?style=for-the-badge" alt="OCR Supported" /> </a> <a href="https://extractpdf4j.github.io/ExtractPDF4J/"> <img src="https://img.shields.io/badge/Docs-live-1E88E5?style=for-the-badge" alt="Docs" /> </a> </p> <p align="center"> <a href="https://github.com/ExtractPDF4J/ExtractPDF4J/stargazers"> <img src="https://img.shields.io/github/stars/ExtractPDF4J/ExtractPDF4J?style=for-the-badge" alt="GitHub Stars" /> </a> <a href="https://github.com/ExtractPDF4J/ExtractPDF4J/network/members"> <img src="https://img.shields.io/github/forks/ExtractPDF4J/ExtractPDF4J?style=for-the-badge" alt="GitHub Forks" /> </a> <a href="https://github.com/ExtractPDF4J/ExtractPDF4J/actions"> <img src="https://img.shields.io/github/actions/workflow/status/ExtractPDF4J/ExtractPDF4J/ci.yml?style=for-the-badge&label=build" alt="Build Status" /> </a> <a href="https://github.com/ExtractPDF4J/ExtractPDF4J"> <img src="https://img.shields.io/badge/Downloads-4K%2B-3949AB?style=for-the-badge" alt="Downloads" /> </a> </p> <br /> <p align="center"> <img src="./docs/images/extractpdf4j-demo.gif" alt="ExtractPDF4J demo" width="100%" /> </p>
ExtractPDF4J
A production-focused Java library for extracting tables and structured data from PDFs. Extract tables from scanned/image PDFs in Java using OCR + table structure detection.
import com.extractpdf4j.helpers.Table;
import com.extractpdf4j.parsers.HybridParser;
import java.util.List;
public class QuickStart {
public static void main(String[] args) throws Exception {
// Works for BOTH text-based and scanned PDFs (OCR fallback)
List<Table> tables = new HybridParser("scanned_invoice.pdf")
.dpi(300f)
.parse();
if (!tables.isEmpty()) {
System.out.println(tables.get(0).toCSV(','));
}
}
}
What problem it solves
Stop hand-retyping tables from scanned invoices, bank statements, or reports. Extract clean rows + columns even when the PDF has no text layer.
Supported Document Types
ExtractPDF4J works well with documents such as:
- bank statements
- financial reports
- invoices
- operational documents
- structured business reports
Production Use Cases
ExtractPDF4J is designed for production environments such as:
- fintech and banking platforms
- document processing pipelines
- analytics platforms
- enterprise ingestion workflows
- AI / ML data preparation pipelines
Magic snippet
The copy/paste quick start is at the top of this README under the project description.
Install (Maven + Gradle)
Maven
Recommended: Using the BOM
<dependencyManagement>
<dependencies>
<dependency>
<groupId>io.github.extractpdf4j</groupId>
<artifactId>extractpdf4j-bom</artifactId>
<version>2.1.0</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<dependency>
<groupId>io.github.extractpdf4j</groupId>
<artifactId>extractpdf4j-service</artifactId>
</dependency>
</dependencies>
Direct Module Usage
If you prefer not to use the BOM:
<dependency>
<groupId>io.github.extractpdf4j</groupId>
<artifactId>extractpdf4j-core</artifactId>
<version>2.1.0</version>
</dependency>
<dependency>
<groupId>io.github.extractpdf4j</groupId>
<artifactId>extractpdf4j-cli</artifactId>
<version>2.1.0</version>
</dependency>
<dependency>
<groupId>io.github.extractpdf4j</groupId>
<artifactId>extractpdf4j-service</artifactId>
<version>2.1.0</version>
</dependency>
Gradle
implementation("io.github.extractpdf4j:extractpdf4j-core:2.1.0")
implementation("io.github.extractpdf4j:extractpdf4j-cli:2.1.0")
implementation("io.github.extractpdf4j:extractpdf4j-service:2.1.0")
Documentation
Project documentation lives in /docs and is published to GitHub Pages.
For contributor-focused MkDocs workflow details, see docs/docs-development.md.
Build docs locally
pip install -r docs/requirements.txt
mkdocs build --strict
Serve docs locally
mkdocs serve
Docs dependencies are pinned to MkDocs 1.x in docs/requirements.txt because MkDocs 2.0 currently warns as incompatible with Material for MkDocs.
Why this vs Tabula/PDFBox (comparison table)
| Feature | ExtractPDF4J | Tabula-Java | PDFBox | | ------------------ | --------------------------- | ----------- | ------------ | | Text-based PDFs | ✅ | ✅ | ✅ | | Scanned/Image PDFs | ✅ Native OCR | ❌ | ❌ | | Table recognition | ✅ Stream/Lattice/OCR-hybrid | ✅ | ❌ (raw text) | | “Hello world” time | Low (single entrypoint) | Medium | High |
Use cases (3 quick examples)
Extract from scanned PDF (OCR)
import com.extractpdf4j.helpers.Table;
import com.extractpdf4j.parsers.OcrStreamParser;
import java.util.List;
List<Table> tables = new OcrStreamParser("scanned_invoice.pdf")
.dpi(300f)
.parse();
Extract from text-based PDF (stream/lattice)
import com.extractpdf4j.helpers.Table;
import com.extractpdf4j.parsers.StreamParser;
import java.util.List;
List<Table> tables = new StreamParser("statement.pdf")
.pages("1-2")
.parse();
Batch extraction (folder → CSV)
import com.extractpdf4j.helpers.Table;
import com.extractpdf4j.parsers.HybridParser;
import java.io.File;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.List;
for (File pdf : new File("./invoices").listFiles(f -> f.getName().endsWith(".pdf"))) {
List<Table> tables = new HybridParser(pdf.getPath())
.dpi(300f)
.parse();
if (!tables.isEmpty()) {
Files.writeString(Path.of("./out/" + pdf.getName() + ".csv"), tables.get(0).toCSV(','));
}
}
Custom CSV Delimiter
import com.extractpdf4j.helpers.CsvExporter;
CsvExporter exporter = new CsvExporter();
exporter.setDelimiter(";");
exporter.export(data);
Annotation-based configuration
If you prefer declarative configuration, you can annotate a class and build the parser from that annotation.
import com.extractpdf4j.annotations.ExtractPdfAnnotations;
import com.extractpdf4j.annotations.ExtractPdfConfig;
import com.extractpdf4j.annotations.ParserMode;
import com.extractpdf4j.parsers.BaseParser;
@ExtractPdfConfig(
parser = ParserMode.HYBRID,
pages = "all",
dpi = 300f,
debug = true
)
class InvoiceParserConfig {}
BaseParser parser = ExtractPdfAnnotations.parserFrom(InvoiceParserConfig.class, "invoice.pdf");
Tesseract/OpenCV setup (only what’s necessary)
- Recommended: use the Bytedeco
*-platformartifacts so native binaries are bundled. - If you bring your own OCR/OpenCV install, ensure native libraries are on the OS path (
LD_LIBRARY_PATH/DYLD_LIBRARY_PATH/PATH). - For OCR, set
TESSDATA_PREFIXif Tesseract language data is not found.
API reference (Javadocs link)
Sample PDFs
The /examples directory contains publicly available, non-sensitive PDF files
that can be used to test and understand different extraction scenarios supported
by ExtractPDF4J.
-
sample_utility_bill.pdf
A sample utility bill demonstrating structured text extraction, including dates, addresses, account identifiers, and billing totals. -
sample_monthly_statement.pdf
A multi-page sample financial statement demonstrating table extraction from repeated layouts and tabular data. All content is explicitly marked as sample data.
Visual examples


Developer documentation
This section keeps the full project details (architecture, CLI, configuration, and setup) for contributors.
Architecture
PDF (text-based) ──► PDFBox text positions ─┐
├─► StreamParser ──► Table (cells)
PDF (scanned) ──► Render to image ──► OpenCV lines/grids ──► LatticeParser ──► Table
Related Skills
node-connect
385.5kDiagnose OpenClaw Android, iOS, or macOS node pairing, QR/setup code, route, auth, and connection failures.
blender-python-addon
40.5kBlender Python add-on rules for operators, panels, properties, registration, testing, and API-safe scripting
flutter-development-guidelines-cursorrules-prompt-file
40.5kCursor rules for Flutter development with MVVM architecture, Riverpod state management, Material widgets, and Dart style guidelines.
commit-push-pr
140.7kCommit, push, and open a PR
