Converting Markdown to PDF in Java

Converting Markdown to PDF in Java

Hi everyone! Markdown is a lightweight markup language widely used for documentation, README files, and blogs. However, sometimes you need to convert Markdown into a more portable format like PDF for printing or sharing. In this article, we'll explore how to convert Markdown to PDF in Java using two popular libraries: Flexmark for Markdown-to-HTML conversion and iText for HTML-to-PDF rendering.

But all of this is just beautiful words. Why is this article you need? I have a simple Telegram Bot on Java, which saves my message in a file. This is like a notebook, or diary, but lately I notice that without images it is not so cool. Earlier Bot saved text in a simple file .txt and this is a problem because .txt doesn't work with images. At work we use .adoc for our manuals, a simple format which can be converted to .pdf including images. But I like Markdown, .md is beautiful. Just add a link to the image in the file, and all. New problem, how to convert .md to .pdf? Now I'll tell you...

We’ll cover:

  • Required dependencies (Maven/Gradle)
  • Step-by-step implementation
  • Code explanation
  • Possible optimizations
  • Alternatives and limitations

Prerequisites

  • Java 8 or later
  • Maven or Gradle build system
  • Basic knowledge of Markdown syntax

Dependencies

We’ll use:

  1. Flexmark – A flexible Markdown parser for Java.
  2. iText (OpenPDF fork) – A PDF generation library (fork of iText 2.1.7, maintained as OpenPDF).

Maven Dependencies

<dependencies>
    <!-- Flexmark for Markdown → HTML -->
    <dependency>
        <groupId>com.vladsch.flexmark</groupId>
        <artifactId>flexmark-all</artifactId>
        <version>0.64.8</version>
    </dependency>

    <!-- OpenPDF (iText fork) for HTML → PDF -->
    <dependency>
        <groupId>com.github.librepdf</groupId>
        <artifactId>openpdf</artifactId>
        <version>1.3.30</version>
    </dependency>
</dependencies>

Gradle Dependencies

dependencies {
    // Flexmark
    implementation 'com.vladsch.flexmark:flexmark-all:0.64.8'
    
    // OpenPDF (iText fork)
    implementation 'com.github.librepdf:openpdf:1.3.30'
}

Implementation

We’ll create a Java class that:

  1. Converts Markdown → HTML (using Flexmark)
  2. Converts HTML → PDF (using OpenPDF)

1. Markdown to HTML Conversion

Flexmark provides a simple API to parse and render Markdown as HTML.

import com.vladsch.flexmark.util.data.MutableDataSet;
import com.vladsch.flexmark.html.HtmlRenderer;
import com.vladsch.flexmark.parser.Parser;
import com.vladsch.flexmark.util.ast.Node;

public class MarkdownToPdfConverter {

    public String markdownToHtml(String markdown) {
        MutableDataSet options = new MutableDataSet();
        Parser parser = Parser.builder(options).build();
        HtmlRenderer renderer = HtmlRenderer.builder(options).build();

        Node document = parser.parse(markdown);
        return renderer.render(document);
    }
}

2. HTML to PDF Conversion

We’ll use OpenPDF (a maintained fork of iText 2.1.7) to generate a PDF from HTML.

import com.lowagie.text.Document;
import com.lowagie.text.DocumentException;
import com.lowagie.text.html.simpleparser.HTMLWorker;
import com.lowagie.text.pdf.PdfWriter;

import java.io.*;
import java.nio.file.Files;
import java.nio.file.Paths;

public class MarkdownToPdfConverter {

    // ... (previous markdownToHtml method)

    public void htmlToPdf(String html, String outputPdfPath) throws IOException, DocumentException {
        Document document = new Document();
        try (OutputStream os = Files.newOutputStream(Paths.get(outputPdfPath))) {
            PdfWriter writer = PdfWriter.getInstance(document, os);
            document.open();
            HTMLWorker htmlWorker = new HTMLWorker(document);
            htmlWorker.parse(new StringReader(html));
            document.close();
        }
    }
}

3. Full Conversion Method

Now, let’s combine both steps:

public void convertMarkdownToPdf(String markdown, String outputPdfPath) 
    throws IOException, DocumentException {
    String html = markdownToHtml(markdown);
    htmlToPdf(html, outputPdfPath);
}

Complete Example

Here’s a full working example:

import com.vladsch.flexmark.html.HtmlRenderer;
import com.vladsch.flexmark.parser.Parser;
import com.vladsch.flexmark.util.ast.Node;
import com.vladsch.flexmark.util.data.MutableDataSet;
import com.lowagie.text.Document;
import com.lowagie.text.DocumentException;
import com.lowagie.text.html.simpleparser.HTMLWorker;
import com.lowagie.text.pdf.PdfWriter;

import java.io.*;
import java.nio.file.Files;
import java.nio.file.Paths;

public class MarkdownToPdfConverter {

    public static void main(String[] args) {
        String markdown = "# Hello, Markdown to PDF!\n\n" +
                          "This is a **sample** Markdown text.\n" +
                          "- List item 1\n" +
                          "- List item 2\n\n" +
                          "`Code snippet`";

        String outputPath = "output.pdf";

        MarkdownToPdfConverter converter = new MarkdownToPdfConverter();
        try {
            converter.convertMarkdownToPdf(markdown, outputPath);
            System.out.println("PDF generated at: " + outputPath);
        } catch (IOException | DocumentException e) {
            System.err.println("Error generating PDF: " + e.getMessage());
        }
    }

    public String markdownToHtml(String markdown) {
        MutableDataSet options = new MutableDataSet();
        Parser parser = Parser.builder(options).build();
        HtmlRenderer renderer = HtmlRenderer.builder(options).build();

        Node document = parser.parse(markdown);
        return renderer.render(document);
    }

    public void htmlToPdf(String html, String outputPdfPath) 
        throws IOException, DocumentException {
        Document document = new Document();
        try (OutputStream os = Files.newOutputStream(Paths.get(outputPdfPath))) {
            PdfWriter writer = PdfWriter.getInstance(document, os);
            document.open();
            HTMLWorker htmlWorker = new HTMLWorker(document);
            htmlWorker.parse(new StringReader(html));
            document.close();
        }
    }

    public void convertMarkdownToPdf(String markdown, String outputPdfPath) 
        throws IOException, DocumentException {
        String html = markdownToHtml(markdown);
        htmlToPdf(html, outputPdfPath);
    }
}

Limitations & Improvements

Limitations

  1. Basic HTML SupportHTMLWorker in OpenPDF has limited CSS support.
  2. Complex Layouts: Tables, advanced styling may not render perfectly.
  3. Performance: Large documents may require optimizations.

Possible Improvements

  1. Use iText 7 + pdfHTML (modern alternative with better HTML support).
  2. Add CSS Styling: Pre-process HTML with a CSS-inliner.
  3. Async Processing: For large documents, use async conversion.

Conclusion

We’ve built a pure Java solution for converting Markdown to PDF using Flexmark and OpenPDF. This approach works entirely inside the JVM without external tools. While it has some limitations, it’s a solid starting point for basic conversions.