How to Convert Markdown to PDF with Java

Use Java to create a styled, tagged PDF from Markdown content, tables, and uploaded images with pdfRest.
Share this page

This Java example converts Markdown into a styled, tagged PDF through the pdfRest Convert to PDF API Tool. It demonstrates multipart upload, document and table styling, and explicit image mapping for a complete server-side conversion workflow.

Why Convert Markdown to PDF with Java?

Enterprise applications often store procedures and product content as Markdown because it is easy to review, diff, and generate. The people consuming that material may instead need a paginated PDF for onboarding, deployment, approval, or offline access.

Consider a Java-based knowledge platform that maintains installation guides in Markdown. When a customer downloads a guide, the application can submit the article, its logo, and its configuration table to pdfRest. The resulting PDF preserves the document hierarchy, styles the table consistently, and embeds the supplied image without requiring the platform to maintain a separate PDF template.

Using one structured conversion request also reduces drift between online and downloadable documentation. Java services can control page geometry and visual presentation while retaining Markdown’s authoring advantages, and tagged output provides logical structure for assistive technology and downstream document processing.

Java Code Example for Converting Markdown to PDF

import io.github.cdimascio.dotenv.Dotenv;
import java.io.File;
import java.io.IOException;
import java.util.concurrent.TimeUnit;
import okhttp3.*;
import org.json.JSONObject;

public class PdfFromMarkdown {
  private static final String API_URL = "https://api.pdfrest.com";
  private static final String DEFAULT_API_KEY = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx";

  public static void main(String[] args) throws IOException {
    File inputFile = new File(args.length > 0 ? args[0] : "/path/to/sample.md");
    File imageFile = new File(args.length > 1 ? args[1] : "/path/to/logo.png");
    Dotenv dotenv = Dotenv.configure().ignoreIfMalformed().ignoreIfMissing().load();
    String apiKey = dotenv.get("PDFREST_API_KEY", DEFAULT_API_KEY);
    JSONObject options =
        new JSONObject(
            "{\"title\":\"Structured Content Sample\",\"language\":\"en-US\",\"enable_tagging\":true,\"page_setup\":{\"size\":\"Letter\",\"orientation\":\"portrait\",\"margin\":{\"top\":36,\"right\":42,\"bottom\":36,\"left\":42}},\"style\":{\"font\":\"Arial\",\"heading_font\":\"Arial\",\"code_font\":\"Courier\",\"text_size\":11,\"text_color_rgb\":[34,34,34],\"heading_scale\":1.35,\"table\":{\"column_width_weights\":[2,3,2],\"keep_header_with_first_row\":true,\"repeat_headers_on_overflow\":true,\"show_borders\":true,\"border_width\":0.75,\"border_color_rgb\":[180,188,200],\"header_fill_color_rgb\":[33,64,98],\"header_text_color_rgb\":[255,255,255],\"row_fill_color_rgb\":[250,250,252],\"alternate_row_fill_color_rgb\":[235,240,246],\"cell_padding\":{\"top\":6,\"right\":8,\"bottom\":6,\"left\":8}}},\"markdown\":{\"image_alt_text\":{\"sample-logo\":\"Sample logo\"},\"missing_image_alt_text\":\"fail\",\"image_sources\":{\"sample-logo\":{\"upload_index\":0}}}}");
    MultipartBody.Builder form =
        new MultipartBody.Builder()
            .setType(MultipartBody.FORM)
            .addFormDataPart(
                "file",
                inputFile.getName(),
                RequestBody.create(inputFile, MediaType.parse("application/octet-stream")))
            .addFormDataPart(
                "image_files",
                imageFile.getName(),
                RequestBody.create(imageFile, MediaType.parse("image/png")))
            .addFormDataPart("structured_text_options", options.toString());
    Request request =
        new Request.Builder()
            .url(API_URL + "/pdf")
            .header("Api-Key", apiKey)
            .post(form.build())
            .build();
    send(request);
  }

  private static void send(Request request) throws IOException {
    OkHttpClient client = new OkHttpClient.Builder().readTimeout(60, TimeUnit.SECONDS).build();
    try (Response response = client.newCall(request).execute()) {
      System.out.println("Result code " + response.code());
      if (response.body() != null) System.out.println(response.body().string());
      if (!response.isSuccessful()) System.exit(1);
    }
  }
}

Source: View the sample on GitHub

Breaking Down the Code

The code imports Dotenv to load the API key from environment configuration, OkHttp to make the HTTP request, and JSONObject to construct the structured-text conversion options.

File inputFile = new File(args.length > 0 ? args[0] : "/path/to/sample.md");
File imageFile = new File(args.length > 1 ? args[1] : "/path/to/logo.png");

These lines identify the Markdown source file and local image file. You can supply their paths as command-line arguments or replace the placeholder paths directly. The API determines that the source is Markdown from the uploaded file extension, so the options object does not need an input_format property.

Dotenv dotenv = Dotenv.configure().ignoreIfMalformed().ignoreIfMissing().load();
String apiKey = dotenv.get("PDFREST_API_KEY", DEFAULT_API_KEY);

This code loads PDFREST_API_KEY from a local environment file when available. Replace the placeholder value with a valid pdfRest API key if you do not use a .env file.

JSONObject options = new JSONObject("{\"title\":\"Structured Content Sample\",\"language\":\"en-US\", ... }");

The options object is sent as structured_text_options. It sets the PDF title and language, enables tagged output, configures the page, and applies typography and table styling. The table options control relative column widths, repeated headers, borders, colors, padding, and alternating row fills for Markdown tables.

The markdown.image_sources configuration maps the Markdown image target sample-logo to the first uploaded image, represented by "upload_index": 0. The Markdown source should contain the same target, such as ![Company logo](sample-logo). The image_alt_text setting supplies alternate text, while missing_image_alt_text is set to fail so that conversion stops if a meaningful image lacks alternate text.

MultipartBody.Builder form = new MultipartBody.Builder().setType(MultipartBody.FORM) ...

The multipart form includes the Markdown source as file, the local image as image_files, and the JSON configuration as structured_text_options. The uploaded image is available to the Markdown conversion through its zero-based upload index.

Request request = new Request.Builder().url(API_URL + "/pdf").header("Api-Key", apiKey).post(form.build()).build();

This constructs a POST request to the Convert to PDF endpoint and includes the API key and multipart form data.

private static void send(Request request) throws IOException { ... }

The send method executes the request with OkHttp, prints the response code and body, and returns a nonzero exit status when the API reports an error.

Beyond the Tutorial

This example shows how a Java application can create a polished, tagged PDF from Markdown while controlling document presentation and resolving a local image in the same request. Tagged output adds logical document structure that can support accessibility and downstream processing, but it does not by itself guarantee conformance with a specific accessibility standard.

A Java integration can omit image mapping, table styling, or other controls that its Markdown source does not use. Experiment with a smaller profile in API Lab, and consult the Convert to PDF documentation for accepted values and defaults.

Generate a self-service API Key now!
Create your FREE API Key to start processing PDFs in seconds, only possible with pdfRest.