A fluent Java API for PDF generation, signing, and processing. Backed by the Folio Go engine via Panama FFI. Apache 2.0 licensed.
Requires JDK 22+ | Zero runtime dependencies | Bundles folio engine v0.6.2 | foliopdf.dev | Playground
Folio uses the Foreign Function & Memory API (Panama FFI) to call into the native engine. This requires two things:
- JDK 22 or later (Temurin, Corretto, GraalVM, or any OpenJDK distribution)
- The JVM flag
--enable-native-access=ALL-UNNAMED
Gradle:
tasks.withType<JavaExec> {
jvmArgs("--enable-native-access=ALL-UNNAMED")
}Maven (Surefire / exec-maven-plugin):
<argLine>--enable-native-access=ALL-UNNAMED</argLine>Command line:
java --enable-native-access=ALL-UNNAMED -jar myapp.jarNative libraries for Linux (x86_64, ARM64), macOS (x86_64, ARM64), and Windows (x86_64) are bundled in the JAR and extracted automatically at runtime.
<!-- Maven -->
<dependency>
<groupId>dev.foliopdf</groupId>
<artifactId>folio-java</artifactId>
<version>0.1.0</version>
</dependency>// Gradle
implementation("dev.foliopdf:folio-java:0.1.0")The simplest way to create a PDF:
Document.create("report.pdf", doc -> {
doc.add(Heading.of("Q3 Report", HeadingLevel.H1));
doc.add(Paragraph.of("Revenue grew 23% year over year."));
doc.add(Table.of(
new String[]{"Product", "Units", "Revenue"},
new String[]{"Widget A", "1,200", "$48,000"},
new String[]{"Widget B", "850", "$34,000"}
));
});For more control, use the builder:
try (var doc = Document.builder()
.a4()
.title("Q3 Report")
.margins(36)
.build()) {
doc.add(Heading.of("Q3 Report", HeadingLevel.H1));
doc.add(Paragraph.of("Revenue grew 23% year over year."));
doc.save("report.pdf");
}HtmlConverter.toPdf("<h1>Invoice</h1><p>Due: $1,200</p>", "invoice.pdf");
// Or get bytes directly for HTTP responses
byte[] pdf = HtmlConverter.toBytes("<h1>Hello</h1><p>World</p>");try (var reader = PdfReader.open("input.pdf")) {
System.out.println("Pages: " + reader.pageCount());
System.out.println("Title: " + reader.title());
System.out.println("Text: " + reader.extractAllText());
}PdfMerger.merge("annual.pdf", "q3-report.pdf", "q4-report.pdf");Or with more control:
try (var r1 = PdfReader.open("report-q3.pdf");
var r2 = PdfReader.open("report-q4.pdf");
var merged = PdfMerger.merge(r1, r2)) {
merged.setInfo("Annual Report", "ACME Corp");
merged.save("annual.pdf");
}Sign with PAdES B-B through B-LTA:
try (var signer = PdfSigner.fromPem(keyPem, certPem)) {
byte[] signed = signer.sign(pdfBytes, PadesLevel.B_B, opts -> opts
.name("Jane Doe")
.reason("Approval")
.location("Berlin"));
Files.write(Path.of("signed.pdf"), signed);
}Permanently remove sensitive text from PDFs:
try (var reader = PdfReader.open("confidential.pdf");
var opts = PdfRedactor.opts().fillColor(0, 0, 0).stripMetadata(true)) {
byte[] redacted = PdfRedactor.text(reader, List.of("SSN: 123-45-6789"), opts);
Files.write(Path.of("redacted.pdf"), redacted);
}doc.setHeaderText("CONFIDENTIAL", Font.helvetica(), 9, Align.RIGHT);
doc.setFooterText("Page {page} of {pages}", Font.helvetica(), 8, Align.CENTER);For full control, use callbacks:
doc.header((pageIndex, totalPages, page) ->
page.addText("Custom header", Font.helvetica(), 9, 72, 20));var flex = Flex.of()
.direction(FlexDirection.ROW)
.gap(10)
.justifyContent(JustifyContent.SPACE_BETWEEN);
flex.add(Paragraph.of("Left"));
flex.add(Paragraph.of("Right"));
doc.add(flex);var grid = Grid.of()
.templateColumns(
new GridTrackType[]{GridTrackType.FR, GridTrackType.FR},
new double[]{1, 2})
.gap(10, 10);
grid.addChild(Paragraph.of("Narrow column"));
grid.addChild(Paragraph.of("Wide column"));
doc.add(grid);try (var qr = Barcode.qr("https://example.com", 150)) {
qr.align(Align.CENTER);
doc.add(qr);
}try (var svg = SvgElement.parse("<svg>...</svg>")) {
svg.size(200, 200);
doc.add(svg);
}try (var form = Form.of()) {
form.addTextField("name", 72, 700, 300, 720, 0);
form.addCheckbox("agree", 72, 680, 90, 695, 0, false);
doc.form(form);
}doc.pdfA(PdfALevel.PDF_A_3B);
doc.encryption("user-pass", "owner-pass", EncryptionAlgorithm.AES_256);| Feature | Status |
|---|---|
| Document creation (paragraphs, headings, tables, images) | ✅ |
Fluent builder API with Document.create() one-liner |
✅ |
| HTML to PDF conversion | ✅ |
| PDF reading and text extraction | ✅ |
| PDF merging with page manipulation | ✅ |
| Digital signatures (PAdES B-B through B-LTA) | ✅ |
| PDF redaction (text, regex, regions) | ✅ |
| Tagged PDF / PDF/UA accessibility | ✅ |
| Page import for template workflows | ✅ |
| Flexbox and CSS Grid layout | ✅ |
| Multi-column layout | ✅ |
| Barcodes (QR, Code128, EAN-13) | ✅ |
| SVG rendering | ✅ |
| Hyperlinks and internal navigation | ✅ |
| Interactive forms (AcroForm) | ✅ |
| Form filling and flattening | ✅ |
| PDF/A compliance (1a/1b/2a/2b/2u/3b) | ✅ |
| Password encryption (RC4, AES-128/256) | ✅ |
| Granular permission flags | ✅ |
| Watermarks | ✅ |
| Headers and footers (text and callbacks) | ✅ |
| Bookmarks and outlines | ✅ |
| File attachments (PDF/A-3b) | ✅ |
| Drawing primitives (lines, rectangles) | ✅ |
| All 14 standard PDF fonts | ✅ |
| Custom TTF font embedding | ✅ |
| JPMS module support | ✅ |
| Thread safety | ✅ |
| Zero runtime dependencies | ✅ |
All layout elements implement the Element interface and can be added to a Document, Div, Flex, or Grid:
Paragraph · Heading · Table · Image · Div · ListElement · Link · Barcode · SvgElement · Flex · Grid · Columns · FloatElement · TabbedLine · LineSeparator · AreaBreak
There are 12 runnable examples in the examples/ directory:
./gradlew examples:run # Hello world
./gradlew examples:run -PmainClass=dev.foliopdf.examples.Report # Multi-page report
./gradlew examples:run -PmainClass=dev.foliopdf.examples.Invoice # HTML invoice
./gradlew examples:run -PmainClass=dev.foliopdf.examples.HtmlToPdf # HTML to PDF
./gradlew examples:run -PmainClass=dev.foliopdf.examples.Merge # PDF merging
./gradlew examples:run -PmainClass=dev.foliopdf.examples.Sign # Digital signatures
./gradlew examples:run -PmainClass=dev.foliopdf.examples.Redact # PDF redaction
./gradlew examples:run -PmainClass=dev.foliopdf.examples.ImportPage # Page import templates
./gradlew examples:run -PmainClass=dev.foliopdf.examples.Forms # Interactive forms
./gradlew examples:run -PmainClass=dev.foliopdf.examples.Fonts # Font showcase
./gradlew examples:run -PmainClass=dev.foliopdf.examples.Links # Hyperlinks and bookmarks
./gradlew examples:run -PmainClass=dev.foliopdf.examples.ZugferdInvoice # PDF/A-3B invoiceYour Java code
↓
dev.foliopdf.* ← fluent public API (this SDK)
↓
dev.foliopdf.internal.* ← Panama FFI bindings (372 method handles)
↓
libfolio.so / .dylib / .dll ← Folio Go engine (bundled in JAR)
All calls into the native library are serialized through a lock for thread safety.
git clone https://github.com/carlos7ags/folio-java.git
cd folio-java
./gradlew buildApache 2.0. See LICENSE.