Skip to content

Apache PDFBox and HTML to PDF: what PDFBox can and cannot do in Java

Apache PDFBox has no HTML parser and no CSS engine, so it cannot convert HTML to PDF, and no version of it will. Here is what PDFBox is genuinely good at, why the gap exists, and which Java library to reach for when your document starts as markup.

Live demo

Runs in your browser. Nothing is uploaded.

Your PDF is downloading. Want this as one API call, with the page archived too?

Apache PDFBox cannot convert HTML to PDF. There is no HTML parser in it, no CSS engine, and the project has never claimed otherwise. If you arrived here after adding the PDFBox dependency and hunting for the method that takes an HTML string, that method does not exist, and no version of it is coming.

That is worth stating in the first paragraph because a lot of tutorials imply otherwise. What they are really doing is using a second library, usually Flying Saucer or Open HTML to PDF, to do the rendering, with PDFBox only writing the file at the end. This post covers what PDFBox is genuinely good at, why the HTML gap exists, and which Java library to reach for instead when your document starts as markup.

What is Apache PDFBox used for?

PDFBox is a toolkit for working with PDF files that already exist, and for building new ones page by page in code. The project README puts it in one sentence: "The Apache PDFBox library is an open source Java tool for working with PDF documents. This project allows creation of new PDF documents, manipulation of existing documents and the ability to extract content from documents."

Those three verbs are the whole scope. Creation means you place text, lines, images and shapes on a page yourself, in points, from an origin at the bottom left. Manipulation means merging, splitting, rotating, encrypting, filling form fields and stamping. Extraction means pulling text and metadata back out of a file somebody sent you. All three are things PDFBox does well and has done reliably for years.

try (PDDocument doc = new PDDocument()) {
    PDPage page = new PDPage(PDRectangle.LETTER);
    doc.addPage(page);

    try (PDPageContentStream cs = new PDPageContentStream(doc, page)) {
        cs.beginText();
        cs.setFont(new PDType1Font(Standard14Fonts.FontName.HELVETICA_BOLD), 20);
        cs.newLineAtOffset(72, 700);
        cs.showText("Invoice 8842");
        cs.endText();
    }

    doc.save("invoice-8842.pdf");
}

Notice what you are doing there: you chose the coordinates. Nothing measured the text, nothing wrapped a long line, nothing decided where the page should break. That is the actual difference between a PDF toolkit and a rendering engine, and it is the reason the HTML question comes up at all.

Can Apache PDFBox convert HTML to PDF?

No. PDFBox has no HTML parser and no CSS engine, so there is nothing in the library that could interpret a tag or a stylesheet. Converting HTML means parsing markup, resolving a cascade of CSS rules, measuring fonts, running a layout algorithm and paginating the result. PDFBox does none of those things, by design.

It helps to see the size of the gap. An HTML renderer has to answer questions like: how wide is this table column once the content is measured, does this row fit before the page break, what does margin: auto resolve to inside this container, which of these four competing CSS rules wins. That is a browser layout engine. PDFBox is a file format library, roughly the same category as a library that writes XLSX files, and asking it to lay out HTML is asking the wrong component.

Every code sample you find claiming to do it will, if you read the imports, pull in something else to render with. That is not a workaround, it is the correct architecture. PDFBox is often the layer underneath a renderer rather than the renderer itself.

Does PDFBox support CSS?

It does not, and this follows directly from the previous answer. There is no stylesheet parser, no cascade, no box model and no concept of a selector anywhere in the library. Font choice, size, color and position are arguments you pass to drawing calls in Java, not properties you declare in a stylesheet.

This trips people up most often when they are trying to reuse an existing template. If your invoice already exists as a Thymeleaf or Freemarker page that your designers maintain, there is no path from that template into PDFBox short of reading the design and reimplementing it as drawing commands, then maintaining two versions of the same document forever. That is the real cost, and it is why picking the right library at the start matters more here than in most decisions.

How do I convert HTML to PDF in Java without iText?

There are three pure Java options, and the choice between them comes down to how modern your CSS is.

OpenPDF is the LGPL and MPL licensed successor of iText, forked from iText 4.2.0, the last release published before iText 5.0 moved to the AGPL. Its README describes it as a library for "creating, editing, rendering, and encrypting PDF documents, as well as generating PDFs from HTML", with HTML conversion in a dedicated openpdf-html module aimed at styled reports and invoices. The current release is 3.0.5 and it requires Java 21 or later.

Flying Saucer describes itself as "a pure-Java library for rendering arbitrary well-formed XML (or XHTML) using CSS 2.1 for layout and formatting, output to Swing panels, PDF, and images." It is LGPL, still maintained, and version 10.0.0 also requires Java 21 or later.

Open HTML to PDF is the modernized descendant of Flying Saucer, handling XHTML and some HTML5, and it runs on Java 8 and up.

All three share one limit, and the Open HTML to PDF README states it more honestly than any vendor comparison will: "it's not a web browser. Specifically, it does not run javascript or implement many modern standards such as flex and grid layout." Read that literally before you commit. A layout built with display: flex or CSS grid will not lay out. A chart drawn by JavaScript after page load renders as an empty box, because nothing ever runs the script.

These engines work well when you write a print specific template for them: table or float based layout, plain CSS 2.1, absolute units, and every value resolved on the server before rendering starts. They fail when you point them at the page you already have. The Java PDF library comparison puts all of them side by side with their licenses, and the HTML to PDF in Java walkthrough has working code for each route.

Is Apache PDFBox free for commercial use?

Yes, without conditions. PDFBox is published under the Apache License, Version 2.0, which has no revenue threshold, no headcount limit, no disclosure obligation and an explicit patent grant. You can ship it inside a closed source commercial product at any scale and owe nothing.

That is a meaningful advantage in the Java PDF ecosystem, because the licenses around it are stricter. OpenPDF, Flying Saucer and Open HTML to PDF are LGPL, which is still fine for commercial use as long as you do not modify the library itself. iText is dual licensed AGPL and commercial, and under the AGPL you may not deploy it on a network without disclosing the source of your own application, which catches ordinary server side use. If you want to know what the commercial alternatives cost, the iText licensing breakdown works through the terms and prices, and the analysis applies to Java exactly as it does to .NET, because it is the same clause.

How do I extract text from a PDF in Java?

This is the direction PDFBox is genuinely best at, and it is worth separating from generation because people often conflate the two.

try (PDDocument doc = Loader.loadPDF(new File("statement.pdf"))) {
    PDFTextStripper stripper = new PDFTextStripper();
    stripper.setSortByPosition(true);
    String text = stripper.getText(doc);
}

setSortByPosition(true) is the setting most people miss. Without it you get text in the order it happens to appear in the content stream, which on a multi column layout interleaves the columns into nonsense.

Where this approach runs out is structure. PDFBox gives you the words and where they sit, not the meaning, so turning a supplier invoice into line items means writing and maintaining regular expressions per vendor layout, and they break the first time somebody redesigns their template. If the goal is data rather than text, a tool that turns invoice PDFs straight into a spreadsheet will get you there faster than a parser you own. Scanned documents rule out text extraction entirely, since there is no text layer to strip, only pixels.

What should I use instead of PDFBox for HTML?

Work down this list and stop at the first line that matches.

  • Your document is built from data, not markup. Stay on PDFBox. The Apache 2.0 license is the most permissive option available and the drawing API is fine for receipts and simple statements.
  • Your document is HTML and you can write a print specific template. OpenPDF with openpdf-html, or Open HTML to PDF. Free, pure Java, no browser process, no cold start.
  • Your template uses flexbox, grid, web fonts or JavaScript. No pure Java engine will render it. You need real Chromium, either driven yourself with Playwright for Java or called as a hosted rendering API.

That last case is more common than it looks, because most templates worth reusing were built for browsers. Driving Chromium yourself is free to license and costs you the infrastructure: system dependencies in the image, version upgrades, a concurrency cap, and a cold start on every fresh instance. Calling an API is one HTTPS request with none of that, and it works the same from a Spring Boot service, a container or a Lambda.

HttpRequest req = HttpRequest.newBuilder()
    .uri(URI.create("https://api.sitepdf.com/v1/render"))
    .header("Authorization", "Bearer " + System.getenv("SITEPDF_KEY"))
    .header("Content-Type", "application/json")
    .POST(HttpRequest.BodyPublishers.ofString("""
        {"url": "https://app.example.com/invoices/8842",
         "format": "Letter", "archive": true}"""))
    .build();

Whichever route you take, do not generate the document inside the HTTP request that asked for it. Queue the job and return a 202 the client can poll. A render of a real invoice takes one to three seconds, and under load those threads are the difference between an API that responds and one that times out. The Spring Boot HTML to PDF page covers that controller and worker split in detail.

The bottom line

PDFBox is a good library being asked to do a job it was never built for. Use it to create PDFs from data, to manipulate files you already have, and to extract text from documents you receive, and it will serve you for years under the friendliest license in the ecosystem. The moment your source document is HTML, you need a rendering engine, and the only question left is whether CSS 2.1 is enough for your template or whether you need a real browser.

Written by the team building Sitepdf, an HTML to PDF API that archives every page it renders. The in-browser converter is free to try; early access locks the launch pricing.

Early access

Get on the early-access list

The API opens to the list first, in order. Early access locks the planned launch rates for 12 months. No card required, launching soon.

Render + archive, one API