Converting HTML to PDF in Java may be challenging.

To make such a conversion, start by properly rendering HTML and then convert it into a PDF. While this may sound easy, the HTML rendering alone is an extremely complicated task.

Luckily, popular libraries like Flying Saucer not only decently render HTML but can also create PDF files from it. Sadly, there is a drawback these libraries share: they can’t keep up with the web standards.

If you need to use CSS3, WebGL, or another present-day technology, these libraries are not for you. They cannot execute JavaScript either.

In this article, we explore how to convert HTML to PDF in Java and be able to use the latest web standards.

Approach to the problem 

We suggest using JxBrowser to render web pages and convert them to PDF.

JxBrowser is an integrated browser engine for Java applications. It is based on Chromium and thus can render any page exactly as Google Chrome would. It also gives developers API to use many of Chromium’s capabilities. One of which is converting web pages into PDFs.

With JxBrowser, the conversion takes two steps:

  • Load the page.
  • Print the page to PDF.

Let’s see how it looks in the code.

HTML to PDF code sample 

This code sample demonstrates how to load the page, configure the printing, and print the HTML to PDF all in one method:

private static void convert(Path htmlFile, Path pdfFile) {
    var whenCompleted = new CompletableFuture<Void>();

    // Create a browser engine.
    try (var engine = Engine.newInstance(HARDWARE_ACCELERATED)) {
        var browser = engine.newBrowser();

        // Tell the engine to configure printing from code instead of 
        // showing the print preview dialog.
        browser.set(PrintCallback.class, (params, action) -> action.print());
        
        // Configure printing.
        browser.set(PrintHtmlCallback.class, (params, action) -> {
            var printer = params.printers().pdfPrinter();
            var job = printer.printJob();
            job.settings()
               .paperSize(ISO_A4)
               .pageMargins(none()) // No empty spaces on the edges.
               .pdfFilePath(pdfFile) // The result file location.
               .disablePrintingHeaderFooter() // No additional information that wasn't on the page.
               .apply();
            job.on(PrintCompleted.class, event -> whenCompleted.complete(null));
            action.proceed(printer);
        });

        // Load the file in the browser. This can be any URL.
        browser.navigation().loadUrlAndWait(htmlFile.toString());

        // As soon as the page is loaded, print the web page.
        browser.mainFrame().ifPresent(Frame::print);

        // Wait until the PDF is created.
        whenCompleted.join();
    }
}

The resulting method is very easy to use:

convert(Paths.get("/path/to/file.html"), Paths.get("/path/to/file.pdf"));

HTML converted to PDF with JxBrowser

HTML converted to PDF with JxBrowser.

Spinner

Sending…

Sorry, the sending was interrupted

Please try again. If the issue persists, contact us at info@teamdev.com.

Read and agree to the terms to continue.

Your personal JxBrowser trial key and quick start guide will arrive in your Email Inbox in a few minutes.

Practical advice 

The example above fits applications that convert HTML to PDF occasionally. For applications that convert HTML to PDF frequently and at volume, see tips in this section.

1. Reuse the Engine instance. Creating and closing the Engine is expensive because it starts and stops the main Chromium process. We recommend creating the Engine once and reusing it.

2. Use profiles to achieve isolation. It may be necessary to load each page in the browser free of stale cache and data left by previously loaded pages. Create a new Profile for every conversion to open a page in a blank isolated environment.

Here’s an example:

public final class HtmlToPdf {

    private static Engine engine;

    private static void convert(Path htmlFile, Path pdfFile) {
        ...
        if (engine == null) {
            // Create a browser engine only once.
            engine = Engine.newInstance(HARDWARE_ACCELERATED);
        }
        var profile = engine.profiles().newIncognitoProfile("temporary profile name");
        var browser = profile.newBrowser();
        ...
    }
}

3. Read our article on how to deploy JxBrowser in Docker. This may come in handy when using JxBrowser in the cloud environments.

Conclusion 

This article demonstrated how to convert HTML to PDF in Java using JxBrowser.

For this task, we suggested using JxBrowser because it can render HTML pages that use the latest web technologies and execute JavaScript — a feature other libraries lack.

Learn what else you can do with JxBrowser on the product page.