怎么使用 Pandoc将 Markdown 文件转成中文 PDF 文件
这一周收获挺多。在寻找和比较各个可以将 Markdown 转成 PDF 的编辑器的同时,对于 Markdown 语法的认识和理解又进了一步。以往一些狭窄的应用,以及错误的理解都得到了纠正。同时,再一次捡起了 Pandoc 这样的口碑神器,从头到尾尝试了一次后,觉得应该把这个有益的尝试记录下来,以备后查或者他人借鉴。
第一阶段:怎么得不到我想要的 PDF 文件呢?
对于 Markdown 方便的排版功能及四个空白原则有了更多认识之后,我觉得使用 Markdown 来生成要写的报告是一件轻松愉快的事情。整个过程本来是顺利的。但是在需要最后生成结果时我发现目前的工具并不能真正满足我的需要。
遇到的主要问题
- 内部链接失效。
因为 Byword 提供了快速简单的引用链接方式[描述][链接]
。在文件中这样编写之后,发现导出的 PDF 文件并不能真正跳转到相应的文件部分。这个问题在上一次提交的 PDF 报告中已经发现了,但是并没有引起注意。
尝试在网上搜索如何将 Markdown 中的内部链接转为 PDF 时不失效,却没有找到太多有用的答案。 -
脚注失效。
在测试 HTML 的导出文件时,脚注这些系统自动生成的链接是可以完全正常工作的,但是在导出为 PDF 文件之后,脚注不能正常工作。
解决办法及过程
首先是考虑 Byword 为什么不能很好地支持 PDF 文件的导出。在写邮件给 Byword 的客服人员未果之后,自己也 Google 了一些内容。这才发现在书写 Markdown 文件时,我对于链接引用的写法和使用是完全错误的。正确的链接引用写法为[描述](链接)
。天知道我上面的写法是怎么学来的?似乎还是在 Byword 的帮助文件里看到的。
于是转向 StackEdit Markdown 编辑器。然后在这个编辑器里我将相关的 Markdown 文件进行 PDF 转换之后发现,StackEdit 可以完美地生成目录,和脚注都是可以正常工作的。但是内部链接却不论如何设置都无法成功。进一步研究 PDF 导出的选项,却没有更多的内容。所以这个版本虽然已经部分解决了我上面遇到的两个问题,但还是不够完美:
- 分页时遇到表格,会自动添加表头。但是表头与表格内容重叠了。
- 脚注的返回链接变成一个乱码,虽然可以工作,但是不够美观。
- 内部链接的跳转还是不行。
查看StackEdit的选项设置时,作者推荐了新的 Markdown 的写作 App:Classeur。 Classeur除了颜值高外,编写的流畅度和顺利程度都是令人喜欢的。当时没有坚持使用它的原因只有一个:Emacs 神器将永远是我的第一选择。但是此时,Classeur的确能够提供一个明确的 PDF 导出器 — Pandoc,而这个和它预览出来的东西是完全不一样的!它支持无限的 PDF 导出,但是每小时限制三次。如果不希望这个限制,其实可以直接将预览的页面用 PDF 直接导出出来,它是 Okay 的!但是从完美的角度来说,页头,页尾,链接,表格的渲染和字体的输出效果都距离远甚,和用 Pandoc导出的效果不可相提并论。我尝试了一下使用Pandoc来导出的 PDF 文件,这完完全全就是我想要的 PDF 文件嘛!为什么我不早一点考虑使用Pandoc呢?
第二阶段:开启Pandoc转档的工作流
在刚刚开始接触 Emacs 工作的时候,因为希望处理 org 格式的文件也接触过Pandoc 的东西,但是当时觉得配置还蛮多的,所以并没有真正利用起来。这次因为Classeur 是使用Pandoc 来完成 PDF 的导出工作,而且效果非常好,因此沉下心来好好研究了一下。
基本的安装、配置、及成功地导出 PDF 文件
如果你需要将一个标记文件格式转化成为另外一个格式,Pandoc 就是你手中的瑞士军刀。
我的系统是:OS X EI Capitan 10.11.6. 以下的安装过程均以 Mac 系统为基础。
安装
- 在Pandoc 的网站上有 Pandoc的下载页面下载安装包。如果之后有需要卸载整个包,你还可以下载 卸载脚本,然后运行命令
perl uninstall-pandoc.pl
。 - 使用 Homebrew安装Pandoc:
brew install pandoc
。 - 如果要导出 PDF 格式,则必须安装 LaTeX。完整的 MacTex 包占用数 GigaBates 的磁盘空间,因此你可能只需要下载 BasicTex 安装包就可以了。之后可能会需要 使用
tlmgr
进行缺少部分的额外包的安装。例如提示某个字体文件无法找到,可以使用如下命令进行安装:
tlmgr install collection-fontsrecommended
使用
如果正确安装,命令行上将显示出Pandoc 的基本介绍和支持的标记语言种类。
- 建立一个自己的目录,存放 markdown 的源文件,如:
$ cd
$ mkdir pandoc-test
$ cd ~/pandoc-test - 使用自己喜欢的文本编辑器在上面的目录里创建一个 Markdown 文件,如
test.md
。 - 使用Pandoc 的命令行导出一个 PDF 文件:
$ pandoc ~/pandoc-test/test.md -o test.pdf
Pandoc 使用 LaTeX 的引擎来导出 PDF 文件,因此 LaTeX 的包需要提前安装。如果 markdown 文件不包含中文,以上的命令将使用pdftex
包来导出。这个引擎可以由选项--latex-engine
来指定。之后导出中文PDF 时必须用到。
导出中文 PDF 文件
以下的介绍是为了简单正确地导出 PDF 文件所记录的相应步骤。当第一次完成了整个模板的准备之后,即可反复地使用而不会出现问题了。以下假设:
安装 BasicTex 不包括的几个包,如果不安装则在导出中文 PDF 时一定会出错。
$ sudo tlmgr install titling
$ sudo tlmgr install lastpage
导出缺省的Pandoc 模板
$ cd ~\pandoc-test
$ pandoc -D latex > template.tex
模板的文件名可以任意指定,很多人在这个地方借用了 tzengyuxio的pm-template.latex
的模板。我的使用中有一些问题,因此先使用缺省的模板进行导出。
修改缺省的模板
假设已经创建了一个test.md
的 markdown文件,并且包含中文,现在即可使用Pandoc 的命令进行导出了:
$ pandoc test.md -o test.pdf –latex-engine=xelatex –template=template.tex
如无意外,该命令已经能够将 PDF 文件导出了。但是打开时,会发现里面没有中文字符。原因是因为在模板中没有设定相应的字体设置。因此,在借鉴了tzengyuxio 的模板文件之后,在缺省的模板里加入以下的内容:
在第一行\documentclass
后插入:
\usepackage{geometry} % 設定邊界 \geometry{ top=1in, inner=1in, outer=1in, bottom=1in, headheight=3ex, headsep=2ex }
找到缺省模板中的\else % if luatex or xelate
的位置,插入下面的代码:
\usepackage{fontspec} % 允許設定字體 \usepackage{xeCJK} % 分開設置中英文字型 \setCJKmainfont{PingFangSC-Light} % 設定中文字型 \setmainfont{HelveticaNeue-Thin} % 設定英文字型 \setromanfont{HelveticaNeue-Thin} % 字型 \setmonofont{Courier New} \linespread{1.2}\selectfont % 行距 \XeTeXlinebreaklocale "zh" % 針對中文自動換行 \XeTeXlinebreakskip = 0pt plus 1pt % 字與字之間加入0pt至1pt的間距,確保左右對整齊 \parindent 0em % 段落縮進 \setlength{\parskip}{20pt} % 段落之間的距離 \ifxetex \usepackage{xltxtra,xunicode} \fi \defaultfontfeatures{Mapping=tex-text,Scale=MatchLowercase} \newcommand{\euro}{€}
该段代码来自于tzengyuxio 的pm-template.latex
文件,这其中,根据自己的喜好设置了中文字体、英文字体、等宽字体等等,确定了中文的换行。前面的代码确定了 PDF 文件的边距。此时,再重新运行之前的导出命令,我们就可以得到一份比较完美的 PDF 文件了。
常用的Pandoc 导出时的参数
在整个导出的过程中,参考了很多别人的经验。其中 CaryaLiu的 pandoc 转换中文 pdf 攻略帮助甚多。以下参考自己的需要列出一些参数:
-
--latex-engine = pdflatex|lualatex|xelatex
latex-engine用来指定转换PDF格式时LaTeX引擎,默认情况下是pdflatex,但是由于pdflatex不支持中文,因此需要将引擎设置为xelatex -
--template = filename.ext
可以根据自己的需要生成模板文件,并在命令行中加以指定 -
--toc | –table-of-contents
使用该参数后,会在输出文档开头自动产生文件目录,对于输出格式是man, docbook, slidy, slideous, s5, docx 或者odt的文档,该参数不起任何作用。 -
--toc-depth=NUMBER
指定文件目录中包含的章节级别,默认NUMBER=3,表示一级标题、二级标题、三级标题都会被在目录中展示。 -
--number-sections=NUMBER
对于转换输出LaTeX, ConTeXt, HTML, EPUB格式文档时,对文中章节进行编号。默认情况下,文章的章节是不会被编号的。对于使用了class unnumbered 的章节肯定不会被标号,即使使用了–number-sections选项。
导出过程中遇到的问题及解决
-
使用命令行导出时报错
这个即是前面需要安装包的问题。我同时发现,使用tzengyuxio 的模板文件,即或是安装了完整的包,也会在文件不同的行出现一些无法解决的问题。即使 Google 百次,也没有找到真正有用的解决方案。所以才决定直接导出缺省默认的模板文件,然后一步步修改,看看问题可能出在什么地方。事实上证明,只修改自己关注位置的设置是正确的。
对于命令行报错的问题,主要看是不缺少什么包,然后使用tlmgr install
命令进行安装。如果respository
找不到,以上的链接里也提供了更换包位置的办法,我觉得科学上网即可。
有一次,我特地设置了需要按照某个代码高亮导出,结果发现之前可以工作的模板此次出错,根据出错提示,安装相应包后问题即解决。 -
内部链接的问题
这个本来是我主要要解决的问题。在充分学习了解了pandoc-markdown
之后,这个问题迎刃而解。Pandoc 在导出时会自动为目录编写id
,同时我们也可以自己创建id
,如:
## 标题 {#my-id}
此时,在 markdown 文件里面使用[文字说明](#my-id)
的链接形式,即可使内部链接正常工作。简单地让我捶足顿胸,因为之前为了这了个问题,搞了两个晚上好不好。 -
分页的问题
PDF 文件的导出需要按章节分页。之前以为需要在模板里加上什么指令啥的,结果后来发现在 Markdown 的源文件中直接插入 LaTeX 的代码\newpage
,即可满足要求。简单到我已经把这个加入为 Alfred 的一个 Snippet 来工作了。 -
页眉的漂亮问题
这个问题还是学习自tzengyuxio 的模板文件即可。既然中文可以完美导出,英文自也不在话下,所以一直使用xelatex
做为导出引擎就很好了。