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:
- Flexmark – A flexible Markdown parser for Java.
- 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:
- Converts Markdown → HTML (using Flexmark)
- 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
- Basic HTML Support:
HTMLWorker
in OpenPDF has limited CSS support. - Complex Layouts: Tables, advanced styling may not render perfectly.
- Performance: Large documents may require optimizations.
Possible Improvements
- Use iText 7 + pdfHTML (modern alternative with better HTML support).
- Add CSS Styling: Pre-process HTML with a CSS-inliner.
- 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.