Alternatives & Other Ecosystems

This content was generated with the assistance of AI and should be verified against the official documentation before being relied on in production.

The reference material consulted while preparing these pages is listed in the section bibliography.

The rest of this section builds Bookshelf Billing, a Spring Boot 4 service on Java 21, around iText 9.8 and JasperReports 7.0. Those two are not the only way to produce a PDF, and for some projects they are not the best way. This page surveys the alternatives so that the choice is made with the whole field in view: the other Java libraries, the tools that live in other ecosystems (.NET, Python, PHP, JavaScript) and the services you can run next to a Java application. It gives a comparison table (licence, version, approach and four capabilities), a figure that groups the tools by approach, and four short examples. The families themselves are introduced in Introduction & Approaches; this page is the reference that sits behind that decision flowchart.

Everything is stated as of 2026-10-09. Versions of the Maven Central, npm, PyPI, Packagist and NuGet artefacts and the latest GitHub release of Gotenberg, Typst and BIRT were read from the registries on that date. The capability columns are a summary of each project’s own documentation, which changes faster than a page like this. A cell marked "not re-verified" was not checked against the current documentation on that date, and a cell that says "none" means that the feature is not offered by the library itself, not that it is impossible to add with a second tool. Check the linked official pages before you commit to a library.

How the tools group

Twenty-odd tools reduce to five families, which is what matters when you choose. Within a family the trade-offs are similar, and the families differ in what they ask of the developer.

Matrix of five approach families against PDF/A, PDF/UA, AcroForms, signing, HTML/CSS input and data-driven layout
Programmatic APIs

You place text, images and tables with code. PDFBox, OpenPDF, QuestPDF, PDFsharp, ReportLab, PDFKit, pdf-lib and pdfmake belong here, as does iText. Control is total and the dependency is a library, but every layout rule is yours.

Template report engines

A designer lays out a report once and the engine binds data to it. JasperReports and BIRT are the Java examples, and DynamicJasper builds JasperReports reports from code instead of from a designer. These suit tabular, paginated output.

In-process HTML to PDF

You write HTML and CSS and a library paginates it: OpenHTMLtoPDF, Flying Saucer, WeasyPrint, Dompdf and mPDF. None is a browser, so modern CSS (flexbox, grid, custom properties) is partly or not at all supported, depending on the library.

Headless browser or service

Chromium prints the page: Playwright and Puppeteer drive it from code, and Gotenberg wraps Chromium and LibreOffice in an HTTP API. The CSS is as good as it gets, at the price of a browser process to run and to size.

Typesetting and XSL-FO

A separate language describes the document: XSL-FO for Apache FOP, Typst markup for Typst. Docx4j sits next to this family, because it builds Word documents and converts them.

Comparison

The table lists every library surveyed. "Version" is the latest release on the registry of the tool’s ecosystem (listed in References), and the official pages are listed there too. For licences, "permissive" means MIT, BSD or Apache-2.0, and "copyleft" means GPL or LGPL, whose obligations depend on whether you link, modify or redistribute.

Tool Licence Version Approach PDF/A PDF/UA Forms Signing

Apache PDFBox

Apache-2.0

3.0.8

Java, programmatic, plus parsing and manipulation

Producible by hand (embed fonts, an output intent and XMP metadata, as in the CreatePDFA example); the separate org.apache.pdfbox:preflight module still validates PDF/A-1b in 3.0.x

Manual tagging through the structure tree API

Yes (AcroForm)

Yes (CMS signing API, see Signing with Apache PDFBox and EU DSS)

OpenPDF

LGPL-2.1 or MPL-2.0

3.0.5

Java, programmatic, a community fork of the old iText 4 line

Limited, not re-verified

Basic tagging, not re-verified

Yes

Yes (stamper-based API)

OpenHTMLtoPDF

LGPL-3.0

1.1.97

Java, HTML/CSS to PDF on top of PDFBox

Yes (PDF/A standards listed by the project)

Yes (accessible output listed by the project)

Basic form controls

None; sign the result with PDFBox

Flying Saucer

LGPL-2.1

10.6.0

Java, XHTML/CSS 2.1 to PDF, with an OpenPDF back end

Not re-verified

Not re-verified

Limited

None

Apache FOP

Apache-2.0

2.11

Java, XSL-FO to PDF and other formats

Yes (documented in the FOP PDF/A page)

Yes (documented in the FOP accessibility page)

None

None

Eclipse BIRT

EPL-2.0

4.25.0 (GitHub release)

Java, template report engine with a designer

Not re-verified

Not re-verified

Not re-verified

None

DynamicJasper

LGPL

7.0.0

Java, builds JasperReports reports from code

Inherited from the JasperReports exporter

Inherited from the JasperReports exporter

Inherited from the JasperReports exporter

None

docx4j

Apache-2.0

17.3.2

Java, builds and converts Word documents; PDF through XSL-FO or an office suite

Follows the converter used

Follows the converter used

Word content controls, not AcroForms

Signs DOCX packages, not PDF

Gotenberg

MIT

8.37.0

HTTP service around Chromium and LibreOffice, with PDF merge and split

Yes (PDF/A-2 and PDF/A-3 variants)

Yes (PDF/UA-1)

None

None

Playwright page.pdf()

Apache-2.0

1.64.0

Headless Chromium driven from Node, Python, Java or .NET

None

Tagged PDF option since 1.42

None

None

Puppeteer page.pdf()

Apache-2.0

25.13.0

Headless Chromium driven from Node

None

Tagged PDF option, not re-verified

None

None

WeasyPrint

BSD-3-Clause

70.0

Python, HTML/CSS to PDF

Yes (PDF/A-1 to PDF/A-4 variants, not guaranteed valid)

Yes (PDF/UA-1 and PDF/UA-2 variants, with tags)

Yes (--pdf-forms)

None

ReportLab

BSD (open-source edition)

5.0.1

Python, programmatic; a commercial edition adds Plus features

Not re-verified

Not re-verified

Yes (AcroForm via the canvas)

None in the open-source edition

pdfmake

MIT

0.3.11

JavaScript, declarative document definition

Not re-verified

Not re-verified

None

None

PDFKit

MIT

0.20.2

JavaScript, programmatic

Yes (documented subsets)

Yes (documented checklist for PDF/UA)

Yes

None

pdf-lib

MIT

1.17.1, last published 2021-11-06, unmaintained

JavaScript, create and modify

None

None

Yes (strong form support)

None

QuestPDF

Revenue-based: a free community licence below a revenue threshold, paid above it (read the licence page)

2026.9.1

.NET, fluent programmatic layout

Yes (PDF/A-2 and PDF/A-3 variants)

Yes (PDF/UA-1)

None

None

PDFsharp and MigraDoc

MIT

6.2.4 (7.0.0 only as a preview)

.NET, programmatic (PDFsharp) and document model (MigraDoc)

Not re-verified

Not re-verified

Limited

Not re-verified

tc-lib-pdf

LGPL-3.0-or-later

8.78.2

PHP, the successor of TCPDF

Not re-verified

Not re-verified

Not re-verified

Not re-verified

Dompdf

LGPL-2.1

3.1.6

PHP, HTML/CSS to PDF

None

None

None

None

mPDF

GPL-2.0-only

8.3.1

PHP, HTML/CSS to PDF

Not re-verified

Not re-verified

Not re-verified

None

Typst

Apache-2.0

0.15.1

Command-line typesetter with its own markup language

Yes (several PDF/A parts, combinable with PDF/UA-1)

Yes (PDF/UA-1)

None

None

Reading the table by questions:

  • You cannot take the AGPL and need a free Java library. Apache PDFBox (Apache-2.0) is the safe base. OpenPDF is the option when the code you have is written against the old com.lowagie.text API. The licence consequences are explained in Introduction & Approaches.

  • You write HTML already. OpenHTMLtoPDF in process, or Gotenberg or Playwright out of process. The choice is mostly between a library you can call from a unit test and a browser whose CSS is complete.

  • You need conformance. Of the free tools, Apache FOP, Gotenberg, WeasyPrint, Typst and OpenHTMLtoPDF say that they generate PDF/A and PDF/UA. Their own documentation is clear that generation is not validation: run veraPDF, as described in PDF Standards & Conformance.

  • You need to sign. Nothing in the HTML families signs. Produce the PDF, then sign the bytes with PDFBox and EU DSS as in Signing with Apache PDFBox & EU DSS or with iText.

OpenPDF, iText and the licence history

A common source of confusion is that OpenPDF and iText share a past. The old iText 1 and 2 line (package com.lowagie.text) was licensed under the MPL and LGPL. From iText 5 onward the code moved to the AGPL, and iText 7 and later is a rewrite with a different API (kernel, layout and so on); iText 5 itself is end of life. Books and tutorials written for the com.lowagie API describe the old licence and the old classes, not what you get from Maven Central today under the name iText: iText 9 is AGPLv3 or commercial. OpenPDF is the LGPL and MPL community fork of the old API, still maintained, and its 3.0 line renames the packages from com.lowagie to org.openpdf, so migrating from 2.x or earlier to 3.x is a package rename plus a version bump. JasperReports 7 uses a separate OpenPDF-based fork for its PDF back end. Which of them you pick is therefore less about the code you can copy from the internet and more about the licence you can accept; the API mapping from the old classes to iText 9 is on iText Architecture & Modules.

Apache PDFBox

PDFBox is the Apache-licensed library for creating, reading, merging and filling PDFs. It does not lay out text for you: you set a font, a position and a string, and wrapping and pagination are your code. That is the right level when the document is small and fixed, such as a label, a cover sheet or a stamp, and PDFBox is also the library that the rest of this section uses for signing and for form filling. Maven coordinates (first use on this page):

<dependency>
    <groupId>org.apache.pdfbox</groupId>
    <artifactId>pdfbox</artifactId>
    <version>3.0.8</version>
</dependency>
package com.example.alt;

import java.io.IOException;
import java.nio.file.Path;
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;
import org.apache.pdfbox.pdmodel.font.Standard14Fonts;

public final class PdfBoxHello {

    public static void main(String[] args) throws IOException {
        try (PDDocument document = new PDDocument()) {
            PDPage page = new PDPage();
            document.addPage(page);
            PDType1Font font = new PDType1Font(Standard14Fonts.FontName.HELVETICA_BOLD);
            try (PDPageContentStream content = new PDPageContentStream(document, page)) {
                content.beginText();
                content.setFont(font, 18);
                content.newLineAtOffset(72, 720);
                content.showText("Invoice INV-2026-0001");
                content.endText();
            }
            document.save(Path.of("target", "pdfbox-hello.pdf").toFile());
        }
    }
}

This example was compiled and run against PDFBox 3.0.8 on Java 21 language level, and produced a one-page PDF. Since PDFBox 3 the standard 14 fonts are created from Standard14Fonts.FontName; the old PDType1Font.HELVETICA_BOLD constants are gone. A standard font has no embedding and only a Latin character set, so use PDType0Font.load with a TrueType file for anything else. Official documentation: PDFBox getting started and the 3.0 migration guide.

OpenHTMLtoPDF

OpenHTMLtoPDF renders XHTML and CSS to a PDF through PDFBox. Input must be well-formed XML (use an HTML cleaner such as jsoup to convert from HTML5), and the CSS support is a CSS 2.1 subset with some extensions, not a browser. The project publishes under the group io.github.openhtmltopdf. Maven coordinates (first use on this page):

<dependency>
    <groupId>io.github.openhtmltopdf</groupId>
    <artifactId>openhtmltopdf-pdfbox</artifactId>
    <version>1.1.97</version>
</dependency>
package com.example.alt;

import com.openhtmltopdf.pdfboxout.PdfRendererBuilder;
import java.io.IOException;
import java.io.OutputStream;
import java.nio.file.Files;
import java.nio.file.Path;

public final class HtmlToPdf {

    private static final String XHTML = """
            <html xmlns="http://www.w3.org/1999/xhtml">
            <head><style>
              body { font-family: sans-serif; }
              table { border-collapse: collapse; width: 100%; }
              td, th { border: 1px solid #444; padding: 4px; }
            </style></head>
            <body>
              <h1>Invoice INV-2026-0001</h1>
              <table><tr><th>Item</th><th>Total</th></tr>
              <tr><td>Book</td><td>12.50</td></tr></table>
            </body></html>
            """;

    public static void main(String[] args) throws IOException {
        try (OutputStream out = Files.newOutputStream(Path.of("target", "html-hello.pdf"))) {
            PdfRendererBuilder builder = new PdfRendererBuilder();
            builder.useFastMode();
            builder.withHtmlContent(XHTML, null);
            builder.toStream(out);
            builder.run();
        }
    }
}

This example was compiled and run against OpenHTMLtoPDF 1.1.97 together with PDFBox 3.0.8, producing a one-page PDF. For conformance, the builder has usePdfAConformance and usePdfUaAccessibility options; they are listed in the project README but were not exercised here. Official documentation: OpenHTMLtoPDF on GitHub and its wiki.

Gotenberg

Gotenberg is a Docker image that exposes Chromium and LibreOffice conversions as HTTP routes. From Java you call it with any HTTP client; the pattern is to keep the PDF engine out of the application’s JVM and container, so a browser crash or a memory spike does not take the service down. The request below converts an HTML file with curl; the image tag follows the major version.

docker run --rm -p 3000:3000 gotenberg/gotenberg:8

curl --request POST http://localhost:3000/forms/chromium/convert/html \
  --form files=@index.html \
  --form paperWidth=8.27 \
  --form paperHeight=11.7 \
  --form pdfa=PDF/A-2b \
  --form pdfua=true \
  --output invoice.pdf

This request follows the route reference and was not run on the machine used to write this page, because no container runtime was available; verify the field names against the version of the image you deploy. Gotenberg needs an index.html file in the multipart request, and referenced assets are sent as extra files in the same request. Official documentation: Convert HTML with Chromium.

Playwright and Puppeteer

Both drive Chromium from code. page.pdf() prints the page using the print stylesheet and works only in headless Chromium, so the same HTML you review in a browser is what is printed. The example is Node because that is the reference API; Playwright also has Java, Python and .NET bindings with the same method.

import { chromium } from 'playwright';

const browser = await chromium.launch();
const page = await browser.newPage();
await page.goto('http://localhost:8080/invoices/INV-2026-0001');
await page.pdf({
  path: 'invoice.pdf',
  format: 'A4',
  printBackground: true,
  tagged: true,
});
await browser.close();

This snippet was not run on the machine used to write this page; the tagged option is documented for Playwright 1.42 and later. Treat Chromium as a heavy dependency: a pool of reused browsers, a timeout per page and a memory limit per container are not optional in production. Official documentation: Playwright page.pdf() and Puppeteer page.pdf().

Other ecosystems

The tools below are not callable from a Java service without an extra process, but they are what a team in that ecosystem will use, and knowing them helps when you share a document pipeline.

  • .NET: QuestPDF, PDFsharp and MigraDoc. QuestPDF is a fluent layout API with a revenue-based licence; read the terms before you use it in a company. PDFsharp and MigraDoc are MIT: PDFsharp draws pages, MigraDoc adds a paragraph and table model on top.

  • Python: WeasyPrint and ReportLab. WeasyPrint is the closest to a browser for print CSS among the in-process tools and states plainly that its PDF/A and PDF/UA output is not guaranteed valid. ReportLab is the long-standing programmatic library, with a commercial edition for the template language.

  • PHP: Dompdf, mPDF and tc-lib-pdf. Dompdf and mPDF convert HTML. mPDF is GPL, so check that before bundling it into closed-source software. tc-lib-pdf is the actively developed successor of TCPDF.

  • JavaScript: pdfmake, PDFKit and pdf-lib. pdfmake takes a JSON document definition, PDFKit is imperative and has documented PDF/UA support, and pdf-lib is strong at forms and at modifying existing files but has not been published since 2021, so treat it as unmaintained.

  • Typst. A modern typesetting system with a scripting language, strong at documents with a lot of structure and maths, and run as a command-line tool.

Apache POI (Excel, Word and PowerPoint) is covered by a separate issue, #262, and is not part of this section.

Choosing, in brief

Start from the constraint, not from the library:

  • Licence blocks the AGPL: PDFBox, OpenPDF, OpenHTMLtoPDF or Gotenberg.

  • The design already exists as HTML: Gotenberg or Playwright for fidelity, OpenHTMLtoPDF for an in-process library.

  • Long tabular reports with grouping and paging: JasperReports or BIRT, as in Generating Reports from Databases & Services.

  • A regulated invoice, with PDF/A, tagging and signing: iText or PDFBox with EU DSS, with a validation step.

  • A one-off page or a stamp on an existing file: PDFBox.

The simplest check is the one the rest of this section uses: build the same Bookshelf Billing invoice with two candidates and compare the output, the code and the dependencies. A day of that costs less than a wrong choice.