关于 lov-any2pdf
使用 Python 的 reportlab 将 Markdown 文件转换为适合出版的 PDF,适用于包含中日韩文字与拉丁文、代码、表格和图片的文档,并支持封面、水印等排版元素。
主要功能
- 01Markdown 转 PDF
- 02中日韩文字与拉丁文混排
- 03代码块和表格排版
- 04图片与提示框处理
- 05主题、封面和水印
- 06PDF 书签与公式
适用场景
- 01将中文技术报告排版为 PDF
- 02导出含代码和表格的 Markdown
- 03制作带主题、封面和水印的 PDF
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ lovstudio/ skills --skill lov-any2pdf安装后在 Claude Code 中输入/lov-any2pdf确认已加载。
包含的文件
除 SKILL.md 外,安装时一起下载的参考资料和脚本。
CHANGELOG.mdREADME.mdskill.yamlcases/cases.jsonissue-regressions.mdreferences/themes.mdscripts/md2pdf.pytests/test_adaptive_theme.pytest_songti_reading.py详细介绍
PDF 大师 · PDF Master
这项技能使用 Python 的 reportlab 库,将任意 Markdown 文件转换为出版级 PDF。它经过大量真实中文技术报告的反复迭代开发,解决了朴素的 MD→PDF 转换器常常处理不当的多个难题。
触发条件
在以下情况下激活
- 用户想将
.md→.pdf - 用户有一份 Markdown 报告/文档,并希望进行专业排版
- 文档包含中日韩字符,且与拉丁文本混排
- 文档包含围栏代码块、Markdown 表格或嵌套列表
- 文档包含本地/远程图片、Obsidian 提示框、表情符号或数学公式
- 用户想在 PDF 中添加封面、目录或水印
在以下情况下不要激活
- 用户只想修改 Markdown 内容,不需要输出 PDF。
- 源文件是 HTML、DOCX 或其他格式,且用户未授权执行 Markdown 转换步骤。
- 用户需要的是幻灯片、可编辑的 Word 文档或图像导出,而不是 PDF。
快速开始
python md2pdf/scripts/md2pdf.py \
--input report.md \
--output report.pdf \
--title "My Report" \
--author "Author Name"
除 --input 外,所有参数均为可选项。如果未指定主题,渲染器会根据文档的内容和结构选择主题。
配置解析(必需)
每次转换前,不要都先展示完整的配置表单。请按以下顺序逐项解析设置:
- 用户在当前请求中的明确指示,然后是 CLI 参数或文档 frontmatter;
- 用户上次在
lov_any2pdf偏好命名空间中明确确认的值; - 根据内容选择主题,或对非视觉设置采用文档中说明的安全默认值。
只要通过上述步骤可以确定转换方式,就直接继续,无需询问。只有在未确定的选项会对结果造成实质性影响时,才最多提出一个简短问题,例如缺少本地素材路径或是否允许生成新图片。除非用户明确要求查看主题目录,否则不要让用户从所有主题中选择。
用户明确确认或更改可复用参数后,请将该值记录为最新偏好。用户下次未作说明时,沿用该值。切勿将推断出的值当作用户已确认的偏好保存,并应遵从用户重置或忽略已保存偏好的请求。
可复用参数包括主题、封面/目录、页面大小、扉页模式、水印文字及位置、图片封面模式、封底模式/横幅、免责声明、版权声明、页眉和页脚。使用前请重新验证已保存的文件路径;如果素材已不存在,请询问用户提供替代文件,而不要默默换用其他文件。
根据内容选择主题
如果当前请求和已保存偏好均未指定主题,请阅读标题、开篇、各级标题、文档长度、代码块、表格、图片和出版场景,然后选择最适合该文章的主题。以下是选择参考,而非固定的关键词路由:
| 内容特点 | 合适的起始主题 |
|---|---|
| 篇幅较长的中文文章、知识笔记、密集表格 | songti-reading |
| 战略、商业、市场或研究报告 | consulting-navy |
| 含摘要/方法/结果/参考文献的学术论文 | ieee-journal 或 classic-thesis |
| 代码较多的技术指南或 API 文档 | github-light |
| 包含图表和指标的数据叙述 | tufte |
| 文学、艺术、摄影或设计随笔 | ink-wash |
| 正式的中国政策或机构文件 | chinese-red |
| 中性英文文章或以印刷为先的文档 | paper-classic |
如果文章确实适合 warm-academic 的风格,仍可使用该主题;但绝不能仅仅因为用户未指定风格,就将其设为默认主题。
将用户选择映射为 CLI 参数
| 选择 | CLI 参数 |
|---|---|
| 设计风格 | --theme,取值见下表(latex-clean 使用 pandoc 引擎) |
| 本地扉页 | --frontispiece <path> |
| AI 扉页 | 先生成图片,然后使用 --frontispiece /tmp/frontispiece.png |
| 水印文字 | --watermark "文字" |
| 水印样式 | --wm-size 30 --wm-opacity 0.1 --wm-angle 45(均为可选) |
| 图片作为封面 | --image-cover true(需要 --frontispiece) |
| 封底图片 | --banner <path> |
| 封底文字 | --disclaimer "声明" 和/或 --copyright "© 信息" |
主题名称映射
| 风格 | --theme 取值 | 灵感来源 |
|---|---|---|
| 暖学术 | warm-academic | 温暖的编辑式学术配色 |
| 经典论文 | classic-thesis | LaTeX classicthesis |
| Tufte | tufte | Edward Tufte 的书籍 |
| 期刊蓝 | ieee-journal | IEEE 期刊格式 |
| 精装书 | elegant-book | LaTeX ElegantBook |
| 中国红 | chinese-red | 中国正式文档 |
| 水墨 | ink-wash | 水墨画/水墨画风格 |
| GitHub | github-light | GitHub Markdown 风格 |
| Nord | nord-frost | Nord 配色方案 |
| 海洋 | ocean-breeze | 清爽的青绿色编辑式配色 |
| LaTeX 清爽 | latex-clean | pandoc+XeLaTeX 原生排版,无封面 |
| 咨询深蓝 | consulting-navy | 咨询研究报告 |
| 宋黑阅读 | songti-reading | 中文出版物常见的宋体正文 + 黑体标题层级 |
处理 AI 生成的扉页
如果用户选择 AI 生成:读取文档标题和首段内容,使用图像生成工具创作与所选设计风格相符的主题插画,供用户审核,然后通过 --frontispiece /path/to/image.png 传入
架构
Markdown → Preprocess (split merged headings) → Parse (code-fence-aware) → Story (reportlab flowables) → PDF build
关键组件:
- 字体系统:macOS 上使用 Palatino(拉丁文正文)、Songti SC Regular(CJK 正文)、可选的衬线/无衬线 CJK 强调字体,以及 Menlo(代码);在 Linux/Windows 上自动回退
- CJK 包装器:
_font_wrap()将连续的 CJK 字符包裹在<font>标签中,以自动切换字体 - 混合文本渲染器:
_draw_mixed()在画布上处理 CJK/拉丁文混合文本(封面、页眉、页脚) - 代码块处理器:
esc_code()在 reportlab Paragraph 中保留缩进、行内对齐和换行 - 智能表格宽度:根据内容长度按比例设置列宽,最小宽度为 18mm
- 书签系统:
ChapterMarkflowable 创建 PDF 侧边栏书签和具名锚点 - 标题预处理器:
_preprocess_md()将# Part## Chapter这类合并标题拆分为单独的行 - 图片处理器:本地、相对路径、
file://和远程 Markdown 图片会缩放到正文区域内;出错时显示回退文本 - 提示框渲染器:Obsidian 风格的
> [!NOTE]块会渲染为带主题样式的方框提示 - 公式渲染器:显示公式可使用可选的 matplotlib mathtext 图片;不可用时回退为带样式的文本
- Emoji 回退:如有可用的缓存 Twemoji PNG,则使用其渲染 Emoji;否则回退到本地 Emoji 字体
经验教训
CJK 字符显示为 □
reportlab 的 Paragraph 只使用 ParagraphStyle 中指定的字体。如果 fontName="Mono",但文本中包含中文,中文会显示为 □。解决方法:始终对所有可能包含 CJK 的文本应用 _font_wrap(),包括代码块。
代码块丢失换行
reportlab 会将 \n 视为空白。解决方法:esc_code() 将 \n 转换为 <br/>,并将所有空格转换为 ,然后再应用 _font_wrap(),从而保留缩进和行内对齐。
CJK/拉丁文自动换行
reportlab 默认只会在空格处断行,导致出现“Claude\nCode”这类不自然的拆分。解决方法:在正文和项目符号样式上设置 wordWrap='CJK',允许在 CJK 字符边界处换行。
宋体阅读需要无衬线字体层级
在所有地方使用同一种无衬线字体,会让内容密集的中文报告显得色调沉闷;而处处使用宋体,则会削弱标题和表头的醒目度。解决方法:使用 songti-reading 主题,正文采用 Songti SC Regular,拉丁字母正文采用 Palatino,中文标题和强调内容采用无衬线字体,代码采用 Menlo,加宽行距,表格正文采用衬线字体。将其作为显式主题,而不是悄然更改所有报告。
在 macOS 上,Songti.ttc 的索引 0 对应 Songti SC Black,而非 Regular。清晰易读的字形位于索引 6。✓、✗ 和 → 等常见报告符号需要显式指定符号字体回退,否则即使周围的中文显示正确,这些符号也可能显示为 □。
含 CJK 字符的画布文本(封面/页脚)
使用拉丁字体调用 drawString() / drawCentredString() 无法渲染 年/月/日 等字符。
解决方法:对所有画布上的用户内容文本(日期、统计数据、免责声明)使用 _draw_mixed()。
图片被静默跳过(相对路径)
过去,Markdown 文件中指向 charts/chart_01.png 的图片引用会被静默跳过,因为图片路径是相对于当前工作目录而非 Markdown 文件所在目录解析的。解决方法:main() 现在会将 input_dir(.md 所在目录)传递给构建器,图片处理器会据此解析相对路径。找不到图片时,现在也会向 stderr 输出 WARN: image not found: ...,而不是静默跳过。
多行图片引用(pandoc --wrap=auto)
将 pandoc 的输出传给 md2pdf 时,pandoc 默认的 --wrap=auto(72 列)会把指向 path.png 等路径的长图片引用拆成多行,从而导致单行图片正则表达式无法匹配。解决方法:现在 _preprocess_md() 会在解析前将多行图片引用合并为一行(代码围栏外)。
**流水线提示:**如果要通过 pandoc 将 HTML 转换为 Markdown,请使用
pandoc --wrap=none input.html -o output.md,以避免图片和表格出现换行相关的解析问题。
输入格式
此技能仅接受 Markdown 文件作为输入。如果你有 HTML、DOCX 或其他格式,请先将其转换为 Markdown(例如,使用 pandoc --wrap=none)。
Markdown 中嵌入的 HTML 块会作为文本原样传递——调用 md2pdf 前,请先将图表、复杂表格等可视内容预处理为纯 Markdown 表格或图片引用。
配置参考
大多数选项也可以在文件开头的 YAML 风格 frontmatter 中设置。显式 CLI 参数优先于 frontmatter 值。
| 参数 | Frontmatter 键 | 默认值 | 说明 |
|---|---|---|---|
--input | — | (必填) | Markdown 文件路径 |
--output | — | output.pdf | 输出 PDF 路径 |
--title | title | 取自第一个 H1 | 封面上的文档标题 |
--subtitle | subtitle | "" | 副标题文本 |
--author | author | "" | 作者姓名 |
--date | date | 今天 | 日期字符串 |
--version | version | "" | 封面上的版本字符串 |
--watermark | watermark | "" | 水印文本(空值 = 无) |
--theme | theme | 内容感知的 auto | 配色主题名称;显式设置和已保存的偏好优先 |
--theme-file | — | "" | 自定义主题 JSON 文件路径 |
--cover | cover | true | 生成封面 |
--toc | toc | true | 生成目录 |
--page-size | page-size | A4 | 页面尺寸(A4 或 Letter) |
--frontispiece | frontispiece | "" | 封面后的整页图片 |
--banner | banner | 捆绑的 assets/backcover-banner.jpg | 封底横幅图片(传入 none 可禁用) |
--header-title | header-title | "" | 页眉中的报告标题 |
--footer-left | footer-left | 作者 | 页脚中的品牌/作者 |
--stats-line | stats-line | "" | 封面上的统计信息 |
--stats-line2 | stats-line2 | "" | 第二行统计信息 |
--edition-line | edition-line | "" | 封面底部的版本行 |
--disclaimer | disclaimer | "" | 封底免责声明 |
--copyright | copyright | "" | 封底版权信息 |
--code-max-lines | code-max-lines | 30 | 每个代码块的最大行数 |
--image-cover | image-cover | false | 将封面图用作满版封面(第 1 页),文本封面移至第 2 页 |
--heading-top-spacer | heading-top-spacer | 5 | H1/H2 章节标题前的顶部间距,单位为 mm |
--wm-size | wm-size | 自动(页面宽度的一半) | 水印字号;自动缩放,使文本宽度 ≈ 页面宽度的 50% |
--wm-opacity | wm-opacity | 0.1 | 水印不透明度(0.0–1.0) |
--wm-angle | wm-angle | 35 | 水印旋转角度,单位为度 |
--wm-spacing-x | wm-spacing-x | 9999 | 水印水平间距,单位为 pt(≥2000 = 每页居中显示一个) |
--wm-spacing-y | wm-spacing-y | 9999 | 水印垂直间距,单位为 pt(≥2000 = 每页居中显示一个) |
主题
可用主题:songti-reading、warm-academic、nord-frost、github-light、
solarized-light、paper-classic、ocean-breeze、monokai-warm、
dracula-soft、tufte、classic-thesis、ieee-journal、elegant-book、
chinese-red、ink-wash 和 consulting-navy。
每个主题定义:页面背景、墨色、强调色、淡化文本、边框、代码背景和水印色调。
回退方案:pandoc + XeLaTeX
当 reportlab 失败时(例如,宽表格/复杂表格导致表格宽度计算陷入无限循环),可回退到 pandoc 和 XeLaTeX。这样可以生成高质量的 CJK PDF,并正确处理表格。
何时使用 pandoc 引擎
- 用户选择了
latex-clean主题(k)——pandoc 是主要引擎,而非回退方案 - 文档包含许多宽幅多列表格(reportlab 的表格布局可能会卡住)
- 文档需要 LaTeX 级别的排版质量(两端对齐、断词)
- reportlab md2pdf.py 处理输入时卡住或崩溃
基本命令
pandoc input.md -o output.pdf \
--pdf-engine=xelatex \
-V CJKmainfont="Songti SC" -V mainfont="Palatino" -V monofont="Menlo" \
-V geometry:margin=2.5cm -V fontsize=11pt \
--toc -V toc-title="目录" -V documentclass=article
添加水印 + 页眉/页脚
pandoc input.md -o output.pdf \
--pdf-engine=xelatex \
-V CJKmainfont="Songti SC" -V mainfont="Palatino" -V monofont="Menlo" \
-V geometry:margin=2.5cm -V fontsize=11pt \
-V colorlinks=true -V linkcolor=red -V toccolor=red -V urlcolor=red \
--toc -V toc-title="目录" -V documentclass=article \
-V header-includes='
\usepackage{fancyhdr}
\pagestyle{fancy}
\fancyhf{}
\fancyhead[L]{\small 页眉左侧文字}
\fancyhead[R]{\small 页眉右侧文字}
\fancyfoot[C]{\thepage}
\usepackage{draftwatermark}
\SetWatermarkText{水印文字}
\SetWatermarkScale{0.5}
\SetWatermarkColor[gray]{0.9}
'
Pandoc 主题预设
每个预设都定义了一套完整的 pandoc -V 参数。使用上方“添加水印 + 页眉/页脚”中的完整命令,并根据预设替换颜色/链接参数。
| 主题 | linkcolor | toccolor | urlcolor | 水印颜色 | 备注 |
|---|---|---|---|---|---|
| chinese-red | red | red | red | [gray]{0.9} | 朱红正式,适合政企报告、白皮书 |
| warm-academic | brown | brown | brown | [gray]{0.9} | 陶土色调,温润的学术风格 |
| classic-thesis | brown | brown | brown | [gray]{0.85} | 灵感来自 LaTeX classicthesis |
| ieee-journal | blue | blue | blue | [gray]{0.9} | 藏蓝严谨,期刊风格 |
| github-light | blue | blue | blue | [gray]{0.92} | 极简蓝白,适合程序员 |
| ink-wash | black | black | black | [gray]{0.92} | 水墨素雅,适合文学/设计类 |
| nord-frost | teal | teal | teal | [gray]{0.9} | 北欧冰霜蓝灰 |
| consulting-navy | blue | blue | blue | [gray]{0.88} | 咨询深蓝,研究报告风格 |
chinese-red 完整示例(本次一滕项目实际使用)
pandoc input.md -o output.pdf \
--pdf-engine=xelatex \
-V CJKmainfont="Songti SC" -V mainfont="Palatino" -V monofont="Menlo" \
-V geometry:margin=2.5cm -V fontsize=11pt \
-V colorlinks=true -V linkcolor=red -V toccolor=red -V urlcolor=red \
--toc -V toc-title="目录" -V documentclass=article \
-V header-includes='
\usepackage{fancyhdr}
\pagestyle{fancy}
\fancyhf{}
\fancyhead[L]{\small 报告标题 | 品牌名}
\fancyhead[R]{\small 商业机密}
\fancyfoot[C]{\thepage}
\usepackage{draftwatermark}
\SetWatermarkText{商业机密}
\SetWatermarkScale{0.5}
\SetWatermarkColor[gray]{0.9}
'
latex-clean 完整示例(最简洁的 LaTeX 学术风格)
选择 latex-clean 时,跳过 reportlab,直接使用 pandoc 生成。特点:无封面、无扉页、
无装饰色块,纯 LaTeX 排版 + 点线 TOC 引导符,适合内容为王的学术/技术文档。
pandoc input.md -o output.pdf \
--pdf-engine=xelatex \
-V CJKmainfont="Songti SC" -V mainfont="Palatino" -V monofont="Menlo" \
-V geometry:margin=2.5cm -V fontsize=11pt \
-V colorlinks=true -V linkcolor=brown -V toccolor=brown -V urlcolor=brown \
--toc -V toc-title="目录" -V documentclass=article
如需添加页眉、页脚或水印,请参考上方“添加水印 + 页眉/页脚”,追加 -V header-includes。
已知限制(pandoc 回退方案)
- 无封面(pandoc article 类没有内置封面;如有需要,可使用 LaTeX 代码片段配合
--include-before-body) - 不支持扉页/封底(请使用 md2pdf.py)
→★☆符号在 Palatino 中可能会发出警告——它们通过 CJK 字体回退渲染,可忽略- ASCII 艺术图会渲染为代码块(与 md2pdf.py 相同)
依赖项(pandoc 回退方案)
需要 pandoc 和包含 XeLaTeX 的 TeX 发行版:
brew install pandoc
brew install --cask mactex-no-gui # or basictex
依赖项
pip install reportlab --break-system-packages
# Optional formula rendering:
pip install matplotlib --break-system-packages
推荐的 Ubuntu/Debian 字体:
sudo apt install fonts-dejavu-core fonts-liberation fonts-freefont-ttf fonts-noto fonts-noto-cjk fonts-noto-color-emoji
运行时上下文(共享)
运行前读取本 Skill 包的 skill.yaml,由宿主提供 skill-runtime/v1 上下文。字段解析顺序为:当前请求、项目上下文、个人 Preferences、品牌 Profile、通用默认值。
- 仅使用 Manifest 声明的字段;Profile 保存公开品牌事实,Preferences 保存个人工作偏好。
- 缺少
required: true字段时,按照 Manifest 的问题配置向用户提出一个聚焦问题;用户明确同意后再保存回答。 - 报错时提供可复制的
context_id、字段路径与来源;诊断内容须避开秘密、完整私人路径和原始配置。
通用反馈闭环
用户在 Skill 驱动任务中提出修改意见时,继续当前产物前必须执行:
- 先判断意见是
task-specific(仅本次)还是reusable(可跨任务复用)。 task-specific只修改当前任务,不改 Skill。reusable先确定作用域:领域规则先更新对应 canonical Skill;适用于所有 Skill 的规则先更新共享规范。- 完成规则更新、版本、lint 与分发核验后,再把修改应用到当前任务。
reusable修改会使此前的“确认”“继续”“发吧”失效;完成当前产物修改和回读后必须停下,等待用户下一步指示,不自动进入发布、提交或其他外部写入。