Convert Markdown to a styled, Chinese-friendly A4 PDF with QA previews.
Project description
md2pdf
A Markdown-to-PDF tool tuned for Chinese / CJK documents:
- Pandoc converts Markdown to standalone HTML with a table of contents.
md2pdf/style.csshandles CJK fonts, the cover page, TOC, headings, blockquotes, tables, and page breaks.- Playwright / headless Chrome prints the HTML to an A4 PDF.
- PyMuPDF + Pillow render QA images and a
summary.txtto check page count, page size, garbled (replacement) characters, and spot-check pages.
The PyPI distribution name is
md2pdf-tool(the plainmd2pdfname was already taken on PyPI). The installed command is stillmd2pdf.
Install
Two system dependencies must be installed first (pip cannot install them):
- pandoc —
brew install pandoc(macOS) /apt install pandoc(Debian/Ubuntu). - A headless browser — after installing the Python package, run
playwright install chromiumto download Playwright's bundled Chromium. On macOS an existing Google Chrome is reused automatically.
Then install the tool. For end users:
# Homebrew (personal tap)
brew install ethanzhrepo/md2pdf/md2pdf
playwright install chromium
# or pipx
pipx install md2pdf-tool
playwright install chromium
From source / for development:
pipx install . # install from the repo, gives a global `md2pdf` command
# or an editable install:
python -m venv .venv && source .venv/bin/activate
pip install -e .
playwright install chromium
Usage
After installing, use the md2pdf command:
md2pdf docs/requirements.md
Without --output, the PDF is written next to the source with a .pdf suffix. Without --title, the filename stem is used.
There is also a gen_pdf.sh wrapper that reads the first level-1 Markdown heading as the cover title:
./gen_pdf.sh docs/requirements.md docs/requirements.pdf
./gen_pdf.sh --dry-run docs/requirements.md # print the command without running it
To set the title, subtitle, date, or required text explicitly, pass the matching flags:
md2pdf docs/requirements.md \
--output docs/requirements.pdf \
--title "项目需求说明" \
--subtitle "Private-deployment authoring, publishing, and playback platform" \
--date "2026-06-03" \
--required-text "Final one-line goal"
Without installing, you can also run it as a module from the repo root (requires pip install -e . or PYTHONPATH=src):
python -m md2pdf.build_pdf path/to/input.md --output path/to/output.pdf
Output
A run produces (using requirements as an example):
- PDF:
docs/requirements.pdf - Intermediate HTML:
<build-dir>/requirements.html - QA summary:
<build-dir>/qa/summary.txt - Spot-check page images and thumbnails:
<build-dir>/qa/*.png
<build-dir> defaults to .build/<stem>/ next to the output PDF (user-writable, never written into a read-only install location). Use --build-dir to point it elsewhere, e.g. --build-dir ./.md2pdf-build.
Dependencies
pandoc- Python packages:
playwright,PyMuPDF(fitz),Pillow(installed automatically bypip install) - Google Chrome or Playwright Chromium
Pandoc may print Could not load translations for zh-CN; this is harmless and does not affect Chinese content or PDF text extraction.
Tests
pip install -e .
python -m unittest discover -s tests -v
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 md2pdf_tool-0.1.1.tar.gz.
File metadata
- Download URL: md2pdf_tool-0.1.1.tar.gz
- Upload date:
- Size: 12.7 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
8cadd49620c0e869d30f29feb18596d900c91d7868c32187688b56900c43045b
|
|
| MD5 |
c1d357956055527f4e0759d98f26a7d8
|
|
| BLAKE2b-256 |
b39e244d3dae80665af8ce1aeeeaf4e2e686e4f7be761d9e2bf09fb7b1f383dd
|
Provenance
The following attestation bundles were made for md2pdf_tool-0.1.1.tar.gz:
Publisher:
release.yml on ethanzhrepo/md2pdf
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
md2pdf_tool-0.1.1.tar.gz -
Subject digest:
8cadd49620c0e869d30f29feb18596d900c91d7868c32187688b56900c43045b - Sigstore transparency entry: 2161365395
- Sigstore integration time:
-
Permalink:
ethanzhrepo/md2pdf@8042288d137ff0d745ac8b81998b6457c3ed7240 -
Branch / Tag:
refs/tags/v0.1.1 - Owner: https://github.com/ethanzhrepo
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@8042288d137ff0d745ac8b81998b6457c3ed7240 -
Trigger Event:
push
-
Statement type:
File details
Details for the file md2pdf_tool-0.1.1-py3-none-any.whl.
File metadata
- Download URL: md2pdf_tool-0.1.1-py3-none-any.whl
- Upload date:
- Size: 10.1 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
c29914779e74caba4952671555600ce39c8e9798a8e369025dcc2b6aa312f6af
|
|
| MD5 |
cb6967fdddcd186f045bb9eb1d340f84
|
|
| BLAKE2b-256 |
3a275faa65f6241dd518691debea520d61569c3bc8383930cab121e187e7eb82
|
Provenance
The following attestation bundles were made for md2pdf_tool-0.1.1-py3-none-any.whl:
Publisher:
release.yml on ethanzhrepo/md2pdf
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
md2pdf_tool-0.1.1-py3-none-any.whl -
Subject digest:
c29914779e74caba4952671555600ce39c8e9798a8e369025dcc2b6aa312f6af - Sigstore transparency entry: 2161365515
- Sigstore integration time:
-
Permalink:
ethanzhrepo/md2pdf@8042288d137ff0d745ac8b81998b6457c3ed7240 -
Branch / Tag:
refs/tags/v0.1.1 - Owner: https://github.com/ethanzhrepo
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@8042288d137ff0d745ac8b81998b6457c3ed7240 -
Trigger Event:
push
-
Statement type: