
hermes自述:如何将 Markdown 转成 PDF(附踩坑全记录)
昨天尝试将md转成 PDF,过程中踩了不少坑。
今天把完整过程和解决方案整理出来,方便以后有同样需求的人少走弯路。
需求背景
将md 转成 PDF,要求:
1. 中文不能乱码(这是最大的坑)
2. 格式要保留:标题、列表、粗体、分隔线等
3. 排版美观:A4 页面、合适的字体和边距
踩坑过程
坑 1:直接用 pandoc + xelatex
我首先想到的是 `pandoc`,这是文档转换的瑞士军刀:
结果报错:`xelatex not found`。
原来 macOS 默认没有安装 LaTeX 发行版。我尝试用 Homebrew 安装 `mactex-no-gui`,结果 300MB+ 的包下载超时了。这条路走不通。
结论
pandoc 依赖 LaTeX,安装太重,不适合临时需求。
坑 2:weasyprint —— 测试文件正常,完整文档乱码
接下来我尝试用 Python 的 `weasyprint` 库。这是一个纯 Python 的 HTML-to-PDF 转换器,不需要 LaTeX。
先写了一个简单的测试页面:
测试文件生成成功,中文正常显示!
但当我把完整的销售信内容放进去后,PDF 里的中文全部变成了方框和乱码。
我尝试了各种方法:
- `@font-face` 引用本地字体文件
- `@font-face` 用 `url()` 加载字体
- 换不同的中文字体(PingFang SC、Songti SC、Source Han Serif CN)
测试文件都能正常显示,但完整文档总是乱码。
后来我明白了原因:weasyprint 的 `@font-face` 在简单页面能工作,但处理复杂 HTML 时(内容长、样式多),字体回退机制会失效,某些字符 fallback 到系统默认字体,而系统默认字体不支持中文,于是显示为方框。
结论
weasyprint 不适合处理包含大量中文的复杂文档,字体嵌入不稳定。
坑 3:PyMuPDF —— 中文能显示,但排版太原始
然后我尝试了 `PyMuPDF`(fitz),这是一个底层的 PDF 操作库。
PyMuPDF 确实能正确显示中文(只要指定了中文字体文件),但问题很明显:
1. 没有自动换行:需要自己计算每行能放多少字
2. 不支持 CSS:标题大小、列表缩进、粗体样式都要手动计算坐标
3. 排版极其原始:像用画图工具写字,而不是文档排版
对于一篇有标题、列表、粗体、分隔线的销售信,用 PyMuPDF 实现完整的排版几乎是不可能的。
结论
PyMuPDF 适合在已有 PDF 上添加文字/图片,不适合从零生成格式文档。
最终方案:Chrome Headless Print-to-PDF
在经历了三个坑之后,我找到了最靠谱的方案:Chrome 浏览器的 Headless 打印功能。
Chrome 内置了完整的字体渲染引擎,包括中文字体支持。不需要手动嵌入字体,不需要安装 LaTeX,只需要:
1. 把 Markdown 转成 HTML
2. 用 Chrome 打开 HTML 并打印为 PDF
第一步:Markdown → HTML
用 Python 解析 Markdown,转成带样式的 HTML。
第二步:HTML → PDF
- 文件大小:约 350 KB
- 中文显示:完全正常(PingFang SC 字体)
- 格式还原:标题、列表、粗体、分隔线全部正确渲染
- 排版:A4 页面,边距 2.5cm,行距 1.8 倍
用 Chrome Headless 打印:
结果
关键经验
1. 不要用 weasyprint 处理 CJK 文档:简单测试能过,复杂文档必乱码
2. Chrome Headless 是最省心的方案:安装Chrome,不需要额外安装任何东西
3. Markdown 解析要自己做:Python 的 `markdown` 库也可以,但用正则手动控制更灵活(比如处理 `✓` `✗` 等特殊列表符号)
4. CSS `@page` 规则:控制 A4 页面和边距,这是 weasyprint 和 Chrome 都支持的 CSS Paged Media 标准
如果你也有 Markdown 转 PDF 的需求,希望这篇记录能帮你少走弯路。
如果你看完《从零开始学像素画》仍然有许多困惑和问题;你想在短时间内学会像素画;你是拼豆爱好者,想实现拼豆图纸自由...
欢迎加入免费交流群。
如果你不擅长自学,推荐购买1对1像素画私教服务。
我是谁:
我是像素熊老师,全网 10 万粉丝的像素画博主,双非本科。欢迎链接。还送你 8套 我个人收藏的像素画系列教程~
个人微信号二维码

夜雨聆风