mcpField
L
lov-any2pdf

lov-any2pdf

github.com/lovstudio文档处理7339 次安装今天更新
代码仓库

关于 lov-any2pdf

使用 Python 的 reportlab 将 Markdown 文件转换为适合出版的 PDF,适用于包含中日韩文字与拉丁文、代码、表格和图片的文档,并支持封面、水印等排版元素。

主要功能

  1. 01Markdown 转 PDF
  2. 02中日韩文字与拉丁文混排
  3. 03代码块和表格排版
  4. 04图片与提示框处理
  5. 05主题、封面和水印
  6. 06PDF 书签与公式

适用场景

  1. 01将中文技术报告排版为 PDF
  2. 02导出含代码和表格的 Markdown
  3. 03制作带主题、封面和水印的 PDF

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/lovstudio/skills --skill lov-any2pdf

安装后在 Claude Code 中输入/lov-any2pdf确认已加载。

包含的文件

除 SKILL.md 外,安装时一起下载的参考资料和脚本。

CHANGELOG.md
README.md
skill.yaml
cases/
cases.json
issue-regressions.md
references/
themes.md
scripts/
md2pdf.py
tests/
test_adaptive_theme.py
test_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 外,所有参数均为可选项。如果未指定主题,渲染器会根据文档的内容和结构选择主题。

配置解析(必需)

每次转换前,不要都先展示完整的配置表单。请按以下顺序逐项解析设置:

  1. 用户在当前请求中的明确指示,然后是 CLI 参数或文档 frontmatter;
  2. 用户上次在 lov_any2pdf 偏好命名空间中明确确认的值;
  3. 根据内容选择主题,或对非视觉设置采用文档中说明的安全默认值。

只要通过上述步骤可以确定转换方式,就直接继续,无需询问。只有在未确定的选项会对结果造成实质性影响时,才最多提出一个简短问题,例如缺少本地素材路径或是否允许生成新图片。除非用户明确要求查看主题目录,否则不要让用户从所有主题中选择。

用户明确确认或更改可复用参数后,请将该值记录为最新偏好。用户下次未作说明时,沿用该值。切勿将推断出的值当作用户已确认的偏好保存,并应遵从用户重置或忽略已保存偏好的请求。

可复用参数包括主题、封面/目录、页面大小、扉页模式、水印文字及位置、图片封面模式、封底模式/横幅、免责声明、版权声明、页眉和页脚。使用前请重新验证已保存的文件路径;如果素材已不存在,请询问用户提供替代文件,而不要默默换用其他文件。

根据内容选择主题

如果当前请求和已保存偏好均未指定主题,请阅读标题、开篇、各级标题、文档长度、代码块、表格、图片和出版场景,然后选择最适合该文章的主题。以下是选择参考,而非固定的关键词路由:

内容特点合适的起始主题
篇幅较长的中文文章、知识笔记、密集表格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-thesisLaTeX classicthesis
TuftetufteEdward Tufte 的书籍
期刊蓝ieee-journalIEEE 期刊格式
精装书elegant-bookLaTeX ElegantBook
中国红chinese-red中国正式文档
水墨ink-wash水墨画/水墨画风格
GitHubgithub-lightGitHub Markdown 风格
Nordnord-frostNord 配色方案
海洋ocean-breeze清爽的青绿色编辑式配色
LaTeX 清爽latex-cleanpandoc+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

关键组件:

  1. 字体系统:macOS 上使用 Palatino(拉丁文正文)、Songti SC Regular(CJK 正文)、可选的衬线/无衬线 CJK 强调字体,以及 Menlo(代码);在 Linux/Windows 上自动回退
  2. CJK 包装器:_font_wrap() 将连续的 CJK 字符包裹在 <font> 标签中,以自动切换字体
  3. 混合文本渲染器:_draw_mixed() 在画布上处理 CJK/拉丁文混合文本(封面、页眉、页脚)
  4. 代码块处理器:esc_code() 在 reportlab Paragraph 中保留缩进、行内对齐和换行
  5. 智能表格宽度:根据内容长度按比例设置列宽,最小宽度为 18mm
  6. 书签系统:ChapterMark flowable 创建 PDF 侧边栏书签和具名锚点
  7. 标题预处理器:_preprocess_md() 将 # Part## Chapter 这类合并标题拆分为单独的行
  8. 图片处理器:本地、相对路径、file:// 和远程 Markdown 图片会缩放到正文区域内;出错时显示回退文本
  9. 提示框渲染器:Obsidian 风格的 > [!NOTE] 块会渲染为带主题样式的方框提示
  10. 公式渲染器:显示公式可使用可选的 matplotlib mathtext 图片;不可用时回退为带样式的文本
  11. Emoji 回退:如有可用的缓存 Twemoji PNG,则使用其渲染 Emoji;否则回退到本地 Emoji 字体

经验教训

CJK 字符显示为 □

reportlab 的 Paragraph 只使用 ParagraphStyle 中指定的字体。如果 fontName="Mono",但文本中包含中文,中文会显示为 □。解决方法:始终对所有可能包含 CJK 的文本应用 _font_wrap(),包括代码块。

代码块丢失换行

reportlab 会将 \n 视为空白。解决方法:esc_code() 将 \n 转换为 <br/>,并将所有空格转换为 &nbsp;,然后再应用 _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 路径
--titletitle取自第一个 H1封面上的文档标题
--subtitlesubtitle""副标题文本
--authorauthor""作者姓名
--datedate今天日期字符串
--versionversion""封面上的版本字符串
--watermarkwatermark""水印文本(空值 = 无)
--themetheme内容感知的 auto配色主题名称;显式设置和已保存的偏好优先
--theme-file—""自定义主题 JSON 文件路径
--covercovertrue生成封面
--toctoctrue生成目录
--page-sizepage-sizeA4页面尺寸(A4 或 Letter)
--frontispiecefrontispiece""封面后的整页图片
--bannerbanner捆绑的 assets/backcover-banner.jpg封底横幅图片(传入 none 可禁用)
--header-titleheader-title""页眉中的报告标题
--footer-leftfooter-left作者页脚中的品牌/作者
--stats-linestats-line""封面上的统计信息
--stats-line2stats-line2""第二行统计信息
--edition-lineedition-line""封面底部的版本行
--disclaimerdisclaimer""封底免责声明
--copyrightcopyright""封底版权信息
--code-max-linescode-max-lines30每个代码块的最大行数
--image-coverimage-coverfalse将封面图用作满版封面(第 1 页),文本封面移至第 2 页
--heading-top-spacerheading-top-spacer5H1/H2 章节标题前的顶部间距,单位为 mm
--wm-sizewm-size自动(页面宽度的一半)水印字号;自动缩放,使文本宽度 ≈ 页面宽度的 50%
--wm-opacitywm-opacity0.1水印不透明度(0.0–1.0)
--wm-anglewm-angle35水印旋转角度,单位为度
--wm-spacing-xwm-spacing-x9999水印水平间距,单位为 pt(≥2000 = 每页居中显示一个)
--wm-spacing-ywm-spacing-y9999水印垂直间距,单位为 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 参数。使用上方“添加水印 + 页眉/页脚”中的完整命令,并根据预设替换颜色/链接参数。

主题linkcolortoccolorurlcolor水印颜色备注
chinese-redredredred[gray]{0.9}朱红正式,适合政企报告、白皮书
warm-academicbrownbrownbrown[gray]{0.9}陶土色调,温润的学术风格
classic-thesisbrownbrownbrown[gray]{0.85}灵感来自 LaTeX classicthesis
ieee-journalblueblueblue[gray]{0.9}藏蓝严谨,期刊风格
github-lightblueblueblue[gray]{0.92}极简蓝白,适合程序员
ink-washblackblackblack[gray]{0.92}水墨素雅,适合文学/设计类
nord-frosttealtealteal[gray]{0.9}北欧冰霜蓝灰
consulting-navyblueblueblue[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 驱动任务中提出修改意见时,继续当前产物前必须执行:

  1. 先判断意见是 task-specific(仅本次)还是 reusable(可跨任务复用)。
  2. task-specific 只修改当前任务,不改 Skill。
  3. reusable 先确定作用域:领域规则先更新对应 canonical Skill;适用于所有 Skill 的规则先更新共享规范。
  4. 完成规则更新、版本、lint 与分发核验后,再把修改应用到当前任务。
  5. reusable 修改会使此前的“确认”“继续”“发吧”失效;完成当前产物修改和回读后必须停下,等待用户下一步指示,不自动进入发布、提交或其他外部写入。

评论

支持 Markdown