Skip to main content

Convert Markdown to PDF in pure Python; no Pandoc, Node.js, or headless Chrome required

Project description

md2pdf — Markdown to PDF in Pure Python

md2pdf converts your Markdown documents into beautiful, print-ready PDFs using pure Python — no Pandoc, Node.js, or headless Chrome needed. Powered by ReportLab and mistletoe.

PyPI version Python License CI codecov


Why md2pdf?

Most Markdown-to-PDF tools require heavy system dependencies — and even then, getting diagrams or math to render often means installing additional packages. md2pdf works out of the box:

Tool Requires Pandoc Requires Chrome Diagrams & Math Pure Python
Pandoc-based ✅ Yes ❌ No ⚠️ Extra packages (e.g. mermaid-filter, LaTeX distribution) ❌ No
Puppeteer/Playwright ❌ No ✅ Yes ⚠️ Depends on setup ❌ No
md2pdf No No Built-in (via Kroki and matplotlib) Yes

Beyond zero system dependencies, you also get:

  • Diagrams & Math — Mermaid and LaTeX via Kroki (with SHA-256 disk caching); matplotlib used for offline LaTeX rendering when configured
  • PDF bookmarks — every heading clickable in your PDF viewer's navigation panel
  • Multi-page tables — split cleanly across pages with repeated headers
  • Colour emoji — Twemoji-powered PNG emoji in your PDFs
  • Extensible plugins — custom handlers, themes, and preprocessors

Installation

Using uv (recommended):

uv tool install pymd2pdf

Using pip:

pip install pymd2pdf

Heavy math documents (physics, engineering)? Install the optional matplotlib backend for faster offline LaTeX rendering:

pip install pymd2pdf[matplotlib]

Note: The PyPI package name is pymd2pdf, but the CLI command and Python import are both md2pdf.


Quick Start

# Convert a Markdown file to PDF
md2pdf input.md -o output.pdf

# Run validation checks without producing a PDF
md2pdf input.md --validate-only

# Work offline (diagrams show source code placeholder instead)
md2pdf input.md -o output.pdf --offline

That's it. For most use cases, the first command is all you need.


Key Features

  • Standard Elements: Headings (H1–H6), paragraphs, lists, blockquotes, horizontal rules, and hyperlinks.
  • Multi-page Tables: Tables split cleanly across page boundaries with repeated column headers on each page.
  • Diagrams & Math: Mermaid diagrams and LaTeX math blocks rendered via the Kroki API, with transparent margin cropping, offline fallbacks, and SHA-256 disk caching.
  • PDF Bookmarks & Outline Panel: Every heading (H1–H6) becomes a clickable, correctly nested entry in your PDF viewer's navigation/bookmarks panel.
  • Colour Emoji: Twemoji-powered PNG emoji rendering in PDFs, with graceful network fallbacks.
  • Admonitions & Callouts: GitHub-style alerts (> [!NOTE], > [!WARNING]) and MkDocs/Obsidian fenced containers (:::note).
  • Broad Unicode Support: Bundled DejaVu Sans fonts cover Latin Extended, Greek, Cyrillic, math operators, arrows, and box-drawing — no system font dependency needed.
  • Custom Fonts & Themes: Supply your own TTF fonts and TOML-based theme overrides.
  • Extensible Plugin System: Load custom element handlers, preprocessors, post-processors, and stylesheet/theme layers.
  • Typesetting Safeguards: Orphaned heading prevention, ghost page elimination, and widow/orphan protection.
  • Pre-render Validation: Catches nested tables, empty diagrams, and unsupported elements before committing to a render.

CLI Options

Flag Shortcut Description
--output -o Output PDF path (default: <input>.pdf).
--config -c Path to a custom md2pdf.toml config file.
--theme -t Theme name to apply (default: default).
--offline Skip Kroki API calls; use source code placeholders instead.
--validate-only Run validation and exit without producing a PDF.
--verbose -v Output debug-level logging to stderr.
--toc Prepend a dynamically generated Table of Contents page.
--header Running header template (supports {title} and {section}).
--header-on-first-page Render the running header on the first page too.
--min-image-scale Minimum image scale before moving to a new page (default: 0.8).
--emoji / --no-emoji Enable or disable Twemoji colour emoji (default: enabled).
--progress / --no-progress Show stage-level progress output on stderr (default: enabled).

Python API

from md2pdf import convert, Config, Pipeline

# One-liner conversion
convert("input.md", "output.pdf")

# Advanced: custom config and pipeline
config = Config(
    offline=False,
    cache_dir=".md2pdf_cache",
    output_file="my_document.pdf"
)
pipeline = Pipeline(config)

# Validate before rendering
issues = pipeline.validate("# Hello World")
for issue in issues:
    print(f"[{issue.severity}] {issue.code}: {issue.message}")

# Render
pipeline.run(raw_md="# Document Title\n\nSome body text.")

Configuration

md2pdf auto-discovers a md2pdf.toml config file in these locations (in order):

  1. ./md2pdf.toml (project-local)
  2. ~/.config/md2pdf/md2pdf.toml
  3. ~/.md2pdf.toml

You can also pass one explicitly with --config. See the annotated md2pdf.toml.example for all available options.


Documentation & Examples

Resource Description
User Guide Comprehensive features reference
Themes & Styling Custom themes, fonts, and stylesheet overrides
Plugin Authoring Writing custom handlers and preprocessors
User Manual (PDF) Consolidated print-ready manual
Examples Four production-grade templates with rendered PDFs

Example Templates

Example Showcases
academic_paper/ LaTeX math, citations, Mermaid flowcharts
business_invoice/ Tables, custom Corporate Blue theme
project_roadmap/ Task lists, admonitions, Gantt charts, code highlighting
simple_cv/ Resume layout, structural tables, clean margins

Tech Stack

Component Library Description
Core Language Python >= 3.11 Strict type-hinting throughout
PDF Generation ReportLab >= 4.0 Low-level document layout engine
Markdown Parsing mistletoe >= 1.3 Fast, extensible Markdown AST parser
HTTP Requests requests >= 2.31 Kroki API communication
CLI Framework typer >= 0.12 CLI builder with validation
Image Processing Pillow >= 10.0 Auto-cropping and dimension detection
LaTeX Rendering (optional) matplotlib >= 3.8 Offline LaTeX math rendering (pip install pymd2pdf[matplotlib])

Development Setup

# Clone the repository
git clone https://github.com/Hari31416/md2pdf.git
cd md2pdf

# Create virtual environment and install all dependencies (including dev)
uv sync
source .venv/bin/activate

# Install pre-commit hooks
uv run pre-commit install

# Run the test suite
uv run pytest

To rebuild all documentation PDFs and example renders:

make docs

Architecture Overview

md2pdf runs as a four-stage pipeline: preprocessing → parsing/validation → element rendering → layout composition.

graph TD
    Input[Markdown File] --> Pre[Preprocessors]
    Pre --> Parser[MarkdownParser]
    Parser --> Tokens[Token Stream]
    Tokens --> Val[DocumentValidator]
    Tokens --> Reg[Plugin/Handler Registry]
    Reg --> Handlers[Element Handlers]
    Handlers --> Kroki[Kroki API / Cache]
    Handlers --> Flowables[ReportLab Flowables]
    Flowables --> Layout[LayoutComposer]
    Layout --> Post[Postprocessors]
    Post --> Renderer[ReportLab PDF Engine]
    Renderer --> Output[Output PDF]

For detailed sequence-level logic, see the User Guide.


Project Structure

md2pdf/
├── docs/                   # Documentation suite (Markdown & consolidated PDF)
├── examples/               # Production-grade example templates with rendered PDFs
├── md2pdf/                 # Core source package
│   ├── assets/             # Kroki client, caching, and fallback elements
│   ├── core/               # Engine pipeline, parser, validator, layout, registry
│   ├── handlers/           # Element-specific flowable generators
│   ├── styles/             # Default stylesheet and theme configs
│   └── cli.py              # CLI entry point
├── scripts/                # Helper scripts (e.g. build_docs.py)
├── tests/                  # Automated test suite
├── md2pdf.toml.example     # Annotated configuration reference
└── pyproject.toml          # Build system and dependency declaration

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

pymd2pdf-0.4.3.tar.gz (3.6 MB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

pymd2pdf-0.4.3-py3-none-any.whl (1.7 MB view details)

Uploaded Python 3

File details

Details for the file pymd2pdf-0.4.3.tar.gz.

File metadata

  • Download URL: pymd2pdf-0.4.3.tar.gz
  • Upload date:
  • Size: 3.6 MB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for pymd2pdf-0.4.3.tar.gz
Algorithm Hash digest
SHA256 0d8a0e861de9ce0350585299ab9ae4d1cfb51e624db403b19e89e84f4d8d391a
MD5 9f268fed909a784f201870c1fb688bd9
BLAKE2b-256 2f5b8e586ec994149b6d0e23b38e86f18030239810a61189496f0e8fd52a98d8

See more details on using hashes here.

Provenance

The following attestation bundles were made for pymd2pdf-0.4.3.tar.gz:

Publisher: release.yml on Hari31416/md2pdf

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file pymd2pdf-0.4.3-py3-none-any.whl.

File metadata

  • Download URL: pymd2pdf-0.4.3-py3-none-any.whl
  • Upload date:
  • Size: 1.7 MB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for pymd2pdf-0.4.3-py3-none-any.whl
Algorithm Hash digest
SHA256 3aa959c46db002470daba9d6f84291f5f473df859615d4d8cc62a2c92d25f644
MD5 88939f1c49fd6033630e694f1ff86ca4
BLAKE2b-256 d8a5881d9bd2929ecaba83a460a02a2f4ea46cfa4f4965eda5ac1ada66a7ec64

See more details on using hashes here.

Provenance

The following attestation bundles were made for pymd2pdf-0.4.3-py3-none-any.whl:

Publisher: release.yml on Hari31416/md2pdf

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page