Mercury SkillsMercury Skills
v1.1.0 lovstudio

any2pdf — Markdown to Professionally Typeset PDF

Convert Markdown to publication-quality PDF with reportlab — CJK/Latin mixed text, themes, cover pages, watermarks, callouts, formulas, and interactive theme selection

View source0 downloads
markdownpdfcjkreportlabtypesettingthemesany2pdf

any2pdf — Markdown to Professionally Typeset PDF#

Credits. This skill is adapted from lovstudio/any2pdf by lovstudio, distributed under the MIT license. The original repository ships the Python implementation (md2pdf.py), preview gallery, and reference theme JSONs. This document is the Mercury-compatible SKILL.md adaptation; the runtime code and design credit belong entirely to the original author.

This skill converts any Markdown file into a publication-quality PDF using Python's reportlab. It was developed through extensive iteration on real Chinese technical reports and solves several hard problems that naive MD→PDF converters get wrong — CJK/Latin mixed text wrapping, canvas CJK rendering on cover/headers/footers, code-block whitespace preservation, and mixed-font fallbacks across macOS, Linux, and Windows.


When to Use#

Trigger this skill whenever the user:

  • Wants to convert .md.pdf
  • Has a markdown report or document and wants professional typesetting
  • Mentions "markdown to PDF", "md2pdf", "any2pdf", "md转pdf", "报告生成", or asks for a "typeset" or "professionally formatted" PDF from markdown source
  • Has a document with CJK characters mixed with Latin text
  • Has fenced code blocks, markdown tables, or nested lists that need to survive conversion
  • Needs local/remote images, Obsidian callouts, emoji, or LaTeX-style math formulas
  • Wants a cover page, table of contents, watermark, or back cover in their PDF

Where the Runtime Lives#

After installing this skill via the Mercury CLI:

mercury skills install pdf-generation/any2pdf

the SKILL.md lands at ~/.mercury/skills/pdf-generation/any2pdf/SKILL.md.

The Python implementation (md2pdf.py), preview images, and theme files are not vendored into Mercury Skills — they live in the upstream repository. To use the skill end-to-end, also clone or install the upstream runtime:

# Option A: clone alongside (recommended for development)
git clone https://github.com/lovstudio/any2pdf.git
# The script is at: any2pdf/lovstudio-any2pdf/scripts/md2pdf.py

# Option B: install via the upstream's own installer
npx skills add lovstudio/any2pdf -g -y

When the AI agent runs the conversion, treat the script path as wherever the user cloned it. If unsure, ask:

"Where is the md2pdf.py script on your system? (e.g. ./any2pdf/lovstudio-any2pdf/scripts/md2pdf.py)"


Quick Start#

python <path-to>/md2pdf.py \
  --input report.md \
  --output report.pdf \
  --title "My Report" \
  --author "Author Name" \
  --theme warm-academic

All parameters except --input are optional — sensible defaults are applied.


Pre-Conversion Options (MANDATORY)#

IMPORTANT for AI agents: You MUST present these options to the user before running the conversion. Use whatever interactive question primitive your runtime provides (AskUserQuestion, a structured prompt, an MCP tool, etc.). Present all options in a single question so the user answers once.

The tone should be a friendly design assistant, not a config form.

Suggested Prompt Template (English)#

Starting PDF conversion — quick choices first

━━━ Design Style ━━━
 a) Warm Academic   — terracotta tones, refined and elegant; humanities / social science
 b) Classic Thesis  — brown tones, LaTeX classicthesis inspired; academic papers
 c) Tufte           — minimal whitespace, deep red accents; data narratives, technical writing
 d) IEEE Journal    — navy blue, journal-formal; conferences and journals
 e) Elegant Book    — coffee tones, book-like; long-form monographs / technical books
 f) Chinese Red     — vermilion on warm paper; Chinese formal reports / whitepapers
 g) Ink Wash        — pure grayscale, restrained and elegant; literary / design content
 h) GitHub          — blue-and-white minimal; developer-familiar
 i) Nord Frost      — Nordic blue-gray; clean modern
 j) Ocean Breeze    — teal-green; fresh and natural

━━━ Frontispiece (full-page image after cover) ━━━
 1) Skip
 2) I'll provide a local image path
 3) AI generates one based on document content

━━━ Watermark ━━━
 1) None
 2) Custom text (e.g. "DRAFT", "Internal Use Only")

━━━ Back Cover Material (business card / QR code / brand) ━━━
 1) Skip
 2) I'll provide an image
 3) Plain text only

Example reply: "a, frontispiece skip, watermark: For Reference Only, back cover: /path/qr.png"
Plain English is fine — no need to memorize the letters.

Mapping User Choices to CLI Args#

ChoiceCLI argument
Design style a–j--theme <value-from-table-below>
Frontispiece local--frontispiece <path>
Frontispiece AIGenerate image first, then --frontispiece /tmp/frontispiece.png
Watermark text--watermark "TEXT"
Back cover image--banner <path>
Back cover text--disclaimer "..." and/or --copyright "..."

Theme Name Mapping#

Choice--theme valueInspiration
a) Warm Academicwarm-academicLovstudio design system
b) Classic Thesisclassic-thesisLaTeX classicthesis
c) TuftetufteEdward Tufte's books
d) IEEE Journalieee-journalIEEE journal format
e) Elegant Bookelegant-bookLaTeX ElegantBook
f) Chinese Redchinese-redChinese formal documents
g) Ink Washink-wash水墨画 / ink wash painting
h) GitHubgithub-lightGitHub Markdown style
i) Nord Frostnord-frostNord color scheme
j) Ocean Breezeocean-breeze

Handling AI-Generated Frontispiece#

If the user chose AI generation: read the document title and the first few paragraphs, use an image-generation tool to create a themed illustration matching the chosen design style, show the result for approval, then pass via --frontispiece /path/to/image.png.


Architecture#

Markdown
  → Preprocess (split merged headings)
  → Parse (code-fence aware)
  → Story (reportlab flowables)
  → PDF build

Key components:

  1. Font system — Palatino (Latin body), Songti SC (CJK body), Menlo (code) on macOS; auto-fallback on Linux / Windows.
  2. CJK wrapper_font_wrap() wraps CJK character runs in <font> tags for automatic font switching.
  3. Mixed text renderer_draw_mixed() handles CJK/Latin mixed text on canvas (cover, headers, footers).
  4. Code block handleresc_code() preserves indentation and line breaks in reportlab Paragraphs.
  5. Smart table widths — proportional column widths based on content length, with 18 mm minimum.
  6. Bookmark systemChapterMark flowable creates PDF sidebar bookmarks and named anchors.
  7. Heading preprocessor_preprocess_md() splits merged headings like # Part## Chapter into separate lines.
  8. Image handler — local, relative, file://, and remote markdown images are scaled into the body frame with fallback text on errors.
  9. Callout renderer — Obsidian-style > [!NOTE] blocks render as themed boxed callouts.
  10. Formula renderer — display formulas use optional matplotlib mathtext images, with styled text fallback.
  11. Emoji fallback — emojis render as cached Twemoji PNGs when available, or with a local emoji font fallback.

Hard-Won Lessons#

These are real bugs that came out of shipping real reports — preserve the fixes if you're customising the script.

CJK Characters Rendering as □#

reportlab's Paragraph only uses the font set in ParagraphStyle. If fontName="Mono" but the text contains Chinese, characters render as □. Fix: always apply _font_wrap() to all text that might contain CJK, including code blocks.

Code Blocks Losing Line Breaks#

reportlab treats \n as whitespace. Fix: esc_code() converts \n<br/> and all spaces → &nbsp;, preserving indentation and mid-line alignment before _font_wrap().

CJK/Latin Word Wrapping#

Default reportlab breaks lines only at spaces, causing ugly splits like Claude\nCode. Fix: set wordWrap='CJK' on body / bullet styles to allow breaks at CJK character boundaries.

drawString() / drawCentredString() with a Latin font can't render 年/月/日 etc. Fix: use _draw_mixed() for all user-content canvas text (dates, stats, disclaimers).


Configuration Reference#

Most options can also be set in the markdown file's YAML frontmatter. Explicit CLI arguments take precedence over frontmatter values.

CLI ArgumentFrontmatter KeyDefaultDescription
--input(required)Path to markdown file
--outputoutput.pdfOutput PDF path
--titletitleFrom first H1Document title for cover page
--subtitlesubtitle""Subtitle text
--authorauthor""Author name
--datedateTodayDate string
--versionversion""Version string for cover
--watermarkwatermark""Watermark text (empty = none)
--themethemewarm-academicColor theme name
--theme-file""Custom theme JSON file path
--covercovertrueGenerate cover page
--toctoctrueGenerate table of contents
--page-sizepage-sizeA4Page size (A4 or Letter)
--frontispiecefrontispiece""Full-page image after cover
--bannerbanner""Back cover banner image
--header-titleheader-title""Report title in page header
--footer-leftfooter-leftauthorBrand / author in footer
--stats-linestats-line""Stats on cover
--stats-line2stats-line2""Second stats line
--edition-lineedition-line""Edition line at cover bottom
--disclaimerdisclaimer""Back cover disclaimer
--copyrightcopyright""Back cover copyright
--code-max-linescode-max-lines30Max lines per code block

Themes#

Built-in: warm-academic, classic-thesis, tufte, ieee-journal, elegant-book, chinese-red, ink-wash, github-light, nord-frost, ocean-breeze.

Each theme defines: page background, ink color, accent color, faded text color, border color, code background, and watermark tint. Preview images for every theme live in the upstream repository under previews/.


Dependencies#

pip install reportlab
# Optional — render display formulas as images instead of styled text:
pip install matplotlib

Fonts#

  • macOS: Palatino, Songti SC (宋体), Menlo — pre-installed.

  • Windows: Times New Roman, SimSun / 微软雅黑, Consolas — pre-installed.

  • Linux (Ubuntu/Debian recommended setup):

    sudo apt install fonts-dejavu-core fonts-liberation fonts-freefont-ttf \
                     fonts-noto fonts-noto-cjk fonts-noto-color-emoji

Fonts are auto-discovered from system paths. Missing fonts produce a helpful error with the exact install command for your OS.


What You Get#

  • Cover page — title, subtitle, author, version, stats lines
  • Clickable table of contents — with PDF bookmark sidebar
  • Frontispiece — full-page image after cover (local or AI-generated)
  • Running headers — stable report / document title without page-lagged chapter labels
  • Running footers — author / brand, page number, date
  • Watermark — faint diagonal text on every content page
  • Back cover — banner image or text branding (QR codes, business cards)
  • 10 design themes — from warm academic to ink wash minimalist
  • Markdown images — local and remote ![alt](src) with graceful fallback text
  • Obsidian callouts> [!NOTE], warnings, tips, quotes, and related callout types
  • LaTeX-style formulas — inline $...$ and display $$...$$ / \[...\]; install matplotlib for rendered math images
  • Emoji fallback — Twemoji image rendering when online, with local emoji-font fallback when available
  • YAML frontmatter — set title, theme, watermark, cover, TOC, and other options inside the Markdown file

License & Attribution#

This skill entry is a derivative work licensed under MIT, matching the upstream project.

  • Original work: lovstudio/any2pdf — Copyright (c) lovstudio
  • License: MIT
  • This SKILL.md adaptation: curated for Mercury Skills by cosmicstack-labs; no code is redistributed, only documentation and workflow guidance.

If you ship this skill in a product, retain the upstream attribution and the MIT license notice from the original repository.

More in PDF Generation

View all →