Convert local Markdown files to PDF via headless Chromium (CJK-friendly, mermaid + math + code highlighting).
Project description
md2pdf
Convert local Markdown files to PDF via headless Chromium — the same engine your editor preview uses, so what you see is what you get.
Built to fix the things other converters get wrong:
- Chinese / CJK text renders correctly (UTF-8 + BOM handling, CJK font stack) — no mojibake.
- Tables don't get sliced across pages; the header row repeats on each page.
- Images don't break — relative paths resolve against the source file, or can be embedded as data URIs.
- mermaid diagrams, LaTeX math (KaTeX), and syntax-highlighted code (Pygments) all render.
- Full control over styling via CSS themes and a TOML config file, plus page headers/footers and page numbers.
Install
Requires Python 3.12+. The package is published on PyPI as markdown-to-pdf;
the command and import package are both md2pdf.
As a user
# with uv (installs the `md2pdf` command globally, isolated)
uv tool install markdown-to-pdf
uv tool run --from markdown-to-pdf playwright install chromium # one-time browser download
# or with pip
pip install markdown-to-pdf
playwright install chromium # one-time browser download
Why the extra browser step? md2pdf renders through headless Chromium (via Playwright). Chromium is not a pip dependency — it's a ~120 MB browser binary downloaded once into a shared cache (
~/.cache/ms-playwright). If you skip it, md2pdf prints the exact command to run.
From source (development)
uv sync
uv run playwright install chromium
Usage
# Simplest: PDF written next to the input
uv run md2pdf report.md
# Choose output path
uv run md2pdf report.md -o out/report.pdf
# Common options
uv run md2pdf report.md --page-size Letter --margin 1.5cm --code-style monokai --toc
uv run md2pdf report.md --css custom.css --no-mermaid
md2pdf <file> is shorthand for md2pdf convert <file>.
Config file
Scaffold a starter config and theme:
uv run md2pdf init
This writes md2pdf.toml and theme.css. md2pdf auto-loads md2pdf.toml
from the current directory (override with -c path/to/config.toml). CLI flags
override the config file, which overrides built-in defaults.
[output]
page_size = "A4"
margin = { top = "2cm", bottom = "2cm", left = "1.8cm", right = "1.8cm" }
[theme]
css = ["theme.css"]
code_style = "default" # any Pygments style
# font_family = '"Noto Sans CJK TC", "Microsoft JhengHei", sans-serif'
[features]
math = true
mermaid = true
toc = false
embed_images = false # inline images for a self-contained PDF
[footer]
enabled = true
template = '<span class="pageNumber"></span> / <span class="totalPages"></span>'
[header]
enabled = false
template = '<span class="title"></span>'
Header/footer templates may use these Chromium placeholders: pageNumber,
totalPages, title, date, url.
How it works
.md ──▶ markdown-it-py (+ Pygments, dollarmath) ──▶ self-contained HTML
──▶ Chromium (KaTeX + mermaid render, fonts load) ──▶ page.pdf() ──▶ .pdf
All assets (theme CSS, Pygments CSS, KaTeX with fonts, mermaid) are inlined, so conversion works fully offline and reproducibly.
Development
uv run pytest # full suite (the end-to-end test launches Chromium)
uv run pytest -m "not slow" # skip the browser-based end-to-end test
Troubleshooting
Chromium is not installed for Playwright— runplaywright install chromium(oruv tool run --from markdown-to-pdf playwright install chromiumfor a uv-tool install).- Images show as broken — md2pdf resolves relative image paths against the
Markdown file's directory; make sure the paths are correct relative to the
.mdfile. Remotehttp(s)images are fetched at render time.
License
MIT
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
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file md_to_pdf_cli-0.1.0.tar.gz.
File metadata
- Download URL: md_to_pdf_cli-0.1.0.tar.gz
- Upload date:
- Size: 1.1 MB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.10.11 {"installer":{"name":"uv","version":"0.10.11","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
72e8e36c92ebe55ce4c73d5bb2a91b74a36008f556b61e19a7474a258f04c35d
|
|
| MD5 |
9e2f6406e96180be700a80ab4cad907d
|
|
| BLAKE2b-256 |
cdb35e3a6069694e146adf3186c093b96e6e395b442891683e80376c6bc2f970
|
File details
Details for the file md_to_pdf_cli-0.1.0-py3-none-any.whl.
File metadata
- Download URL: md_to_pdf_cli-0.1.0-py3-none-any.whl
- Upload date:
- Size: 1.1 MB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.10.11 {"installer":{"name":"uv","version":"0.10.11","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
5e27fa94ce57982f2dd4c9723443838f036a90ed85d80d18a315cc73d8082c0a
|
|
| MD5 |
73dde6c5498f05f072f465cb4d5e9257
|
|
| BLAKE2b-256 |
65a8c3b3f57c762997fa962e1900ff392e9fab7b6caf19138cf5ee64306a32da
|