- name
- any2pdf
- description
- Convert Markdown to publication-quality PDF with reportlab — CJK/Latin mixed text, themes, cover pages, watermarks, callouts, formulas, and interactive theme selection
- metadata
- {"author":"lovstudio","curator":"cosmicstack-labs","version":"1.1.0","category":"pdf-generation","tags":["markdown","pdf","cjk","reportlab","typesetting","themes","any2pdf"],"source":"https://github.com/lovstudio/any2pdf","license":"MIT"}
# any2pdf — Markdown to Professionally Typeset PDF
> **Credits.** This skill is adapted from [`lovstudio/any2pdf`](https://github.com/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.
>
> - Upstream: https://github.com/lovstudio/any2pdf
> - License: MIT (see upstream `LICENSE`)
> - Author: lovstudio
> - Curator (this entry): cosmicstack-labs
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:
```bash
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:
```bash
# 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
```bash
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
| Choice | CLI argument |
|---|---|
| Design style a–j | `--theme <value-from-table-below>` |
| Frontispiece local | `--frontispiece <path>` |
| Frontispiece AI | Generate 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` value | Inspiration |
|---|---|---|
| a) Warm Academic | `warm-academic` | Lovstudio design system |
| b) Classic Thesis | `classic-thesis` | LaTeX classicthesis |
| c) Tufte | `tufte` | Edward Tufte's books |
| d) IEEE Journal | `ieee-journal` | IEEE journal format |
| e) Elegant Book | `elegant-book` | LaTeX ElegantBook |
| f) Chinese Red | `chinese-red` | Chinese formal documents |
| g) Ink Wash | `ink-wash` | 水墨画 / ink wash painting |
| h) GitHub | `github-light` | GitHub Markdown style |
| i) Nord Frost | `nord-frost` | Nord color scheme |
| j) Ocean Breeze | `ocean-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 handler** — `esc_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 system** — `ChapterMark` 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 → ` `, 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.
### Canvas Text with CJK (Cover / Footer)
`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 Argument | Frontmatter Key | Default | Description |
|---|---|---|---|
| `--input` | — | (required) | Path to markdown file |
| `--output` | — | `output.pdf` | Output PDF path |
| `--title` | `title` | From first H1 | Document title for cover page |
| `--subtitle` | `subtitle` | `""` | Subtitle text |
| `--author` | `author` | `""` | Author name |
| `--date` | `date` | Today | Date string |
| `--version` | `version` | `""` | Version string for cover |
| `--watermark` | `watermark` | `""` | Watermark text (empty = none) |
| `--theme` | `theme` | `warm-academic` | Color theme name |
| `--theme-file` | — | `""` | Custom theme JSON file path |
| `--cover` | `cover` | `true` | Generate cover page |
| `--toc` | `toc` | `true` | Generate table of contents |
| `--page-size` | `page-size` | `A4` | Page size (`A4` or `Letter`) |
| `--frontispiece` | `frontispiece` | `""` | Full-page image after cover |
| `--banner` | `banner` | `""` | Back cover banner image |
| `--header-title` | `header-title` | `""` | Report title in page header |
| `--footer-left` | `footer-left` | author | Brand / author in footer |
| `--stats-line` | `stats-line` | `""` | Stats on cover |
| `--stats-line2` | `stats-line2` | `""` | Second stats line |
| `--edition-line` | `edition-line` | `""` | Edition line at cover bottom |
| `--disclaimer` | `disclaimer` | `""` | Back cover disclaimer |
| `--copyright` | `copyright` | `""` | Back cover copyright |
| `--code-max-lines` | `code-max-lines` | `30` | Max 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/`](https://github.com/lovstudio/any2pdf/tree/main/previews).
---
## Dependencies
```bash
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)**:
```bash
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 `` 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](https://github.com/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.
在 GitHub 查看