使用Pandoc将Markdown转换成PDF文档

对于按段落组织的文档来说,Markdown可以说是最易于排版和使用的格式了,同时兼具机器可读性与人类可读性。

那么,在一些情况下,我们可能会希望将Markdown转换成PDF文档,方便打印也好方便传输也好,这个需求或许并不少见。

这篇文章将介绍如何使用工具Pandoc,借助LaTeX将Markdown转换为PDF文档。

值得一看的新项目: Typst

Typst大体上基于Markdown语法撰写文档,同时提供了许多额外命令调整格式等,且程序性能远远快于LaTeX。就私人文档与只提交PDF的简单排版场景来说,Typst无疑是LaTeX之外的一个不错选择。

Typst似乎目前的最大局限性在于,许多出版商要求最终提交Word或LaTeX工程文件。截止2025年2月,Typst暂时没有被主流出版商接受,也似乎暂时没有成熟的转换为LaTeX的方案。

工具选择

虽然我们介绍的方法是基于pandoc和LaTeX的,但其实条条大路通罗马,想要实现Markdown至PDF的转换并非只有这一条路。只要思想不滑坡,办法总比困难多。

  1. 本文介绍的方法,使用pandoc与LaTeX进行转换。可能效果是最好的,但也是最费事的。
  2. 由于Markdown到HTML的渲染工具极其丰富且高效,因此可以直接找个在线转换工具,将Markdown转成HTML,再用浏览器打开HTML,打印网页为PDF。
  3. 把Markdown导入到WPS云文档、飞书、Google Docs等任意在线文档中,再导出成PDF(没想到吧!)。
  4. 如果没有特殊文本格式要求,直接把Markdown全文复制粘贴到Word中,导出(最鸡肋的一条)。

Why Pandoc?

为啥我们在通往罗马的条条大路里,选了最费事的一条呢?因为:

  1. 这条路径涉及到的工具完全开源,完全可控地运行在本地。
  2. 提供了非常多的可配置参数,(理论上)可以任意配置导出PDF的格式,字体、边距啥的都不在话下。
  3. 吃饱了闲的。

但甜蜜常常是痛苦的来源,这一套方案麻烦就麻烦在,需要考虑的事情比较多,比较麻烦,不是开箱即用的方案。

如果你还有兴致继续研究,让我们往下看吧。

环境配置

环境配置之前需要先稍稍解释一下Pandoc+LaTeX方案的原理。

Pandoc是如何将Markdown转换成PDF的呢?实际上可以理解成两个步骤:

  1. Pandoc将Markdown转换成TeX文件。
  2. Pandoc再调用LaTeX组件根据第一步生成的TeX文件进一步生成PDF文件。

那么,很显然,我们需要安装的软件就是:

  1. Pandoc
  2. LaTeX发行版(TeXLive,或者MiKTex,或者其他啥都好)

如果有将 含有中文字符(中日韩语言字符) 的文档转换成PDF的需要,那么在安装LaTeX时,请记得安装xelatex组件(除非你打算折腾ctex)。

准备Markdown

接下来,需要先准备好要转换的Markdown文档。文档的主要内容可以都保持不变,只需要向Markdown文件开头添加一个YAML Metadata块,填入文章相关的一些信息如主标题、作者、日期等,这样生成的文档中就会像学术论文一样包含这些信息。

举个例子:

1
2
3
4
5
6
7
8
9
10
11
12
13
---
title: 文章的主标题
author: 作者名称
date: March 01, 2025
---

# 第一章

这是第一章的内容。

## 第一小节

这是第一小节的内容。

上面的例子中,两行---围住的,就是这个Markdown文件的Metadata块,这些信息将被传递给Pandoc的LaTeX模板,以生成LaTeX文件。

有哪些信息可以通过Metadata块进行传递呢?这取决于使用的模板文件。例如,转换成LaTeX的默认模板可见default.latex,有需要的可以进一步研究。

小试牛刀

好了,软件都装好了,Markdown文件也准备好了,那应该就可以开心地转换了吧?

pandoc命令并不复杂,如果输入的Markdown文件是input.md,期望输出的文件名是output.pdf,那么命令就是:

1
pandoc input.md -o output.pdf

执行命令,轰,报错了,怎么回事呢?

排错与常见问题

LaTeX Error: Unicode character

熟悉LaTeX的小伙伴都知道,常见的pdfLaTeX不支持中文字符的。对中文字符(或者说中日韩文字)支持最好的,应当是XeLaTeX,这一引擎可以直接使用系统中安装好的字体生成PDF。

所以,我们要告诉Pandoc,使用xelatex引擎为我们生成PDF文件。

1
pandoc input.md -o output.pdf --pdf-engine xelatex

但这还不够,Pandoc还是不太清楚怎么寻找中文字体,因此我们还要告诉Pandoc需要使用的中日韩文字字体。以思源宋体(Source Han Serif SC)为例:

1
pandoc input.md -o output.pdf --pdf-engine xelatex -V CJKmainfont="Source Han Serif SC"

再次编译,生成的PDF文件就应该正确包含中文字符啦。

除了在Pandoc命令中指定使用的字体,还可以通过Markdown文件中的YAML Metadata块进行指定。以上命令等价于修改Markdown文档如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
---
title: 文章的主标题
author: 作者名称
date: March 01, 2025
CJKmainfont: "Source Han Serif SC"
---

# 第一章

这是第一章的内容。

## 第一小节

这是第一小节的内容。

事实上,通过YAML Metadata块传递信息,与通过pandoc命令的-V参数传递信息,都是一样的,都是指定template variables的一部分。LateX字体设置的默认模板可以见font-settings.latex

PDF文件中文段落不换行

如果按照前面的步骤配置XeLaTeX和CJK字体,那么应该不会发生这一问题才是。

但如果你在看到这篇文章前已经搜索了很长时间,并且你在其他人那得到的命令是通过mainfont参数指定字体,那或许这就是原因。

请你将pandoc命令中的-V mainfont替换成上一个小节中给出的-V CJKmainfont,再次尝试。

这似乎是最简洁的方案,不需要像很多博客那样下载额外的模板文件。

PDF文件的外边距太宽

默认LaTeX模板的外边距非常宽,一页PDF下来没有多少空间留给内容。想要修改PDF文件的边距,同样可以通过传递参数实现。

1
2
3
4
5
6
---
# 其他template variables
geometry: margin=2cm
---

正文内容。