惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

有赞技术团队
有赞技术团队
Exploit-DB.com RSS Feed
Exploit-DB.com RSS Feed
aimingoo的专栏
aimingoo的专栏
IT之家
IT之家
G
Google Developers Blog
爱范儿
爱范儿
博客园 - 司徒正美
Recent Announcements
Recent Announcements
The Register - Security
The Register - Security
J
Java Code Geeks
The Cloudflare Blog
M
MIT News - Artificial intelligence
Apple Machine Learning Research
Apple Machine Learning Research
Microsoft Security Blog
Microsoft Security Blog
博客园 - Franky
雷峰网
雷峰网
酷 壳 – CoolShell
酷 壳 – CoolShell
Blog — PlanetScale
Blog — PlanetScale
Vercel News
Vercel News
宝玉的分享
宝玉的分享
CTFtime.org: upcoming CTF events
CTFtime.org: upcoming CTF events
B
Blog
小众软件
小众软件
Microsoft Azure Blog
Microsoft Azure Blog
让小产品的独立变现更简单 - ezindie.com
让小产品的独立变现更简单 - ezindie.com
WordPress大学
WordPress大学
T
Troy Hunt's Blog
Application and Cybersecurity Blog
Application and Cybersecurity Blog
H
Hacker News: Front Page
H
Help Net Security
S
Security @ Cisco Blogs
V
V2EX
Security Archives - TechRepublic
Security Archives - TechRepublic
Stack Overflow Blog
Stack Overflow Blog
O
OpenAI News
L
LINUX DO - 最新话题
Cyber Security Advisories - MS-ISAC
Cyber Security Advisories - MS-ISAC
S
Secure Thoughts
Help Net Security
Help Net Security
F
Full Disclosure
博客园 - 叶小钗
The Hacker News
The Hacker News
Spread Privacy
Spread Privacy
Threat Intelligence Blog | Flashpoint
Threat Intelligence Blog | Flashpoint
Jina AI
Jina AI
K
Kaspersky official blog
www.infosecurity-magazine.com
www.infosecurity-magazine.com
V
Vulnerabilities – Threatpost
P
Privacy International News Feed
Scott Helme
Scott Helme

jdhao's digital space

Conversion between base64 and OpenCV or PIL Image 腾讯云对象存储博客图床开启 CDN 加速(不需要购买额外域名) Search and Replace in Multiple Files in Vim/Neovim Change Table Column Width in LaTeX Image or Table Side by Side in LaTeX LaTeX 并排显示图像或表格 Firenvim: Neovim inside Your Browser Content inside HTML tags missing in Latest Hugo? Creating Markdown Front Matter with Ultisnips Labelme JSON 标注格式转 voc XML 格式 Nifty Nvim Techniques That Make My Life Easier -- Series 6 macOS 下如何为视频制作字幕 Running Command Asynchronously inside Neovim Resolving Merge Conflict after Git Stash Pop Pylint: command not found? A Hands-on Experience with Neovim's Built-in LSP Support How to Convert PDF to Images with Imagemagick 互联网上常用缩略语集锦 File Backup in Neovim Converting PDF Pages to Images with Poppler Nifty Nvim Techniques That Make My Life Easier -- Series 5 Neovim Configuration for System-wide Use How to sort a list of tuple or list in Python -- lambda or itemgetter? Building A Vim Statusline from Scratch 人类第一颗原子弹爆炸始末 Distributed Training in PyTorch with Horovod Learning Expect Programming Essential Knowledge about SSH Nifty LaTeX Techniques -- Series 1 更改 Adsense 邮寄地址,重新寄送 PIN Mintty Tips and Configurations Generating Table of Contents for Markdown with Tagbar Convert Python Script to Exe on Windows with Pyinstaller Ubuntu on Windows Missing after Windows Update 使用代理加速 Mac 终端下载速度 My Experience with Several Zsh Plugin Managers 深圳租房小记 How to Install zplug inside Docker Container Why don't settings inside bashrc or bash_profile take effect? Setting Up Locale in Linux 谷歌 Adsense 申请及在 Hugo 中的配置 How to Write Algorithm Pseudo Code in LaTeX Nifty Nvim Techniques That Make My Life Easier -- Series 4 A Few Grammar Questions in Writing How to Read and Write Images with Unicode Paths in OpenCV Creating A Professional Table in LaTeX with booktabs How to Create Proper Folding for Vim/Nvim Configuration Linux Tips and Tricks -- s1 JPEG Image Orientation and Exif How Do I Show the Current File Path In Neovim? JPEG Image Quality in PIL Difference between view, reshape, transpose and permute in PyTorch Convert PIL or OpenCV Image to Bytes without Saving to Disk Fast Movement and Navigation Inside Vim or Neovim Unintuitive Behaviour of Case Sensitivity in Python glob Binding Keys in Zsh 几把机械键盘试用体验 Nvim Autocompletion with Deoplete Converting Markdown to Beautiful PDF with Pandoc Exclusive and Inclusive Motion in Neovim/Vim Nifty Nvim Techniques Which Make My Life Easier -- Series 3 Why Doesn't Jedi Autocompletion Work for Some Methods Vim-like Editing inside Browser Markdown 生成 HTML 时汉字之间出现多余空格问题 小米 9 安装谷歌商店(Google Play Store)与相关配置 Create Mappings That Take A Count in Neovim Spell Checking in Nvim English Words Completion inside Neovim/Vim How to Use Python Inside Vim Script with Neovim Nifty Little Nvim Techniques to Make My Life Easier -- Series 2 Setting up Ultisnips for Neovim Mac 上罗技 M590 鼠标设置 Nifty Little Nvim Techniques to Make My Life Easier -- Series 1 A Complete Guide on Writing LaTeX with Vimtex in Neovim Manipulating Images with Alpha Channels in Pillow Sublime Text Regular Expression Cheat Sheet Cropping Rotated Rectangles from Image with OpenCV Boosting Your Productivity on Terminal with Zsh and Plugins 最新版 Rime 输入法使用 (2022 更新) Display Image with Pillow inside Ubuntu on Windows Faster Directory Navigation with z.lua Cmder Advanced Configurations Nvim-qt Settings on Windows 10 Tmux Plugin Install and Management How to Debug Python Code in Terminal Markdown Writing and Previewing in Neovim -- A Complete Guide Line Number Settings for More Efficient Movement in Neovim 两个大规模中文语料库介绍以及处理 Windows 系统下几款程序员不可不用的神器 我的 2018 阅读清单 A Complete Guide to Neovim Configuration for Python Development How Is Newline Handled in Python and Various Editors? Two Issues Related to ImageFont Module in PIL 在 Listary 中调用 GoldenDict 或欧路词典查单词 Reading and Writing Text Files on Windows The Mathematics behind Font Shapes --- Bézier Curves and More 快速识别图片字体:字体识别工具介绍 Deoplete Failed to Load at Startup after Updating Python neovim Package What Is The Difference between pip, pip3 and pip3.6 Shipped with Anaconda3? Windows 10 系统下 Neovim 安装与配置
纯文本做笔记 --- 使用 Pandoc 把 Markdown 转为 PDF 文件
2017-12-10 · via jdhao's digital space

update log
  • 2021-06-27: 补充标题如何生成的说明。

For English version of this post, click here.

本文主要写如何使用 Pandoc 从 Markdown 文件生成格式精美的 PDF 文件,也包含了一些遇到的问题的解决办法。

你需要什么#

在正式开始文章之前,首先你需要安装下面的这些工具才能在后续正常进行操作:

  • 首先当然是 Pandoc,下载最新的安装包,安装完以后,记得把 Pandoc 安装目录加入系统 PATH 变量。

  • TeX 发行版。请确保你的系统已经安装了 TeX 软件,你可以使用 TeX Live 或者 MiKTeX,安装完成之后可能需要设置 PATH,推荐安装 TeX Live。

  • 一个强大的文本编辑器,当然首推 Sublime Text.当然了,Visual Studio CodeGitHub Atom 也是不错的选择。

背景介绍#

Pandoc 可以很方便地对不同 Markup 语言的文件进行格式转换,因此被誉为格式转换的「瑞士军刀」。使用 Pandoc 把 Markdown 文件转为 PDF 文件,实际上包含两个步骤:

  • 第一步, Markdown 文件被转为 LaTeX 源文件。
  • 第二步,调用系统的 pdflatex, xelatex 或者其他 TeX 命令,将 .tex 文件转换为最终的 PDF 文件 (见上图)。

由于我的文档是中文,并且包含引用,表格等比较复杂的格式,在文件转换过程中遇到了一些问题,下面介绍具体解决办法。

如何处理中文#

Pandoc 默认使用的 pdflatex 命令无法处理 Unicode 字符,如果要把包含中文的Markdown 文件转为 PDF,在生成 PDF 的过程中会报错。我们需要使用 xelatex 来处理中文,并且需要使用 CJKmainfont 选项指定支持中文的字体。 在 Windows 系统中,对于 Pandoc 2.0 版本以上,可以使用以下的命令生成 PDF 文件:

pandoc --pdf-engine=xelatex -V CJKmainfont="KaiTi" test.md -o test1.pdf

CJKmainfont 后面跟的是支持中文的字体名称。那么如何找到支持中文的字体呢? 首先,你需要知道你所使用的语言的 language code, 例如,中文(即Chinese)的 language code 是 zh。 然后使用 fc-list 命令查看支持中文的字体(对于 Windows 系统,fc-list 命令在安装 TeX Live 完整版以后可以使用, Unix 系统一般会预装这个程序):

fc-list :lang=zh # zh 是中文的 「language code」

系统输出如下图所示:

字体的名称就是字体文件位置后面的字符串,由于字体名称可能会包含空格,因此在引用的时候需要加上引号,例如 -V CJKmainfont="Source Han Serif CN"

在 Pandoc 2.0 版本中, --pdf-engine 命令取代了原有的 --latex-engine 命令。对于Linux 系统,Pandoc 版本可能比较老,上述生成 PDF 的命令可能并不适合,正确的命令如下 (在 Pandoc 1.12.3.1 验证):

pandoc --latex-engine=xelatex -V mainfont='WenQuanYi Micro Hei' test.md -o test.pdf

在 Linux 系统上,找出支持中文的字体的方式与 Windows 系统是一样的。

使用问题以及技巧#

添加文档标题,作者,更新时间信息#

Pandoc 支持 YAML 格式的 header,通过 header 可以指定文章的标题,作者,更新时间等信息,一个示例 header 如下:

---
title: "My demo title"
author: "jdhao"
date: 2021-06-27
---

block quote, table 以及 list 未能正确渲染#

原因是在 Pandoc 中 block quote,list 以及 table 前需要空一行。另外 block quote 中每一行渲染成 PDF 未能正确换行,所有行的文字都跑到了一行,可以通过强制在原 block quote 的每一行后面加上空格来解决。

给 block code 加上 highlight#

Pandoc 支持给 block code 里面的代码加上背景高亮,并提供了不同的高亮主题,支持非常多的语言。要列出 Pandoc 提供的高亮方案,使用下面命令,

pandoc --list-highlight-styles

要列出所有支持的语言,使用下面命令,

pandoc --list-highlight-languages

要使用语法高亮,Markdown 文件中的 block code 必须指定语言,同时在命令行使用--highlight-style 选项,例如:

pandoc --pdf-engine=xelatex --highlight-style zenburn test.md -o test.pdf

以上命令,使用了 zenburn 主题, 另外,也推荐使用 tango, zenburn 或者breezedark 高亮主题。

给 section 加上编号以及给文章加上目录#

默认情况下,生成的 PDF 不含目录,同时各级标题不含编号,仅仅字体大小有变化,要给各个 section 加上编号,可以用 -N 选项;加上目录,可以使用 --toc 选项。 一个完整例子如下:

pandoc --pdf-engine=xelatex --toc -N -o test.pdf test.md

给链接加上颜色#

根据 Pandoc user guide 的说明,我们可以通过 colorlinks 选项给各种链接加上颜色,便于和普通文本区分开来:

colorlinks
    add color to link text; automatically enabled if any of linkcolor, filecolor, citecolor, urlcolor, or toccolor are set

同时,为了精确控制不同类型链接颜色,Pandoc 还提供了对不同链接颜色的个性化设置选项:

linkcolor, filecolor, citecolor, urlcolor, toccolor
    color for internal links, external links, citation links, linked URLs, and
    links in table of contents, respectively: uses options allowed by xcolor,
    including the dvipsnames, svgnames, and x11names lists

例如,如果我们想给 URL 链接加上颜色,并且 urlcolor 要设为 NavyBlue, 可以使用下面的命令:

pandoc --pdf-engine=xelatex -V colorlinks -V urlcolor=NavyBlue test.md -o test.pdf

其他链接的颜色可以按照上述方式设置。

值得注意的是,urlcolor 选项并不能给文中直接展示的 raw URL link 加上颜色。 要给直接展示的 URL link 加上颜色,可以用 <> 包围要展示的链接,例如<www.google.com>

另外,也可以使用选项 -f gfm,参考这里。完整命令如下,

pandoc --pdf-engine=xelatex -f gfm -Vurlcolor=cyan -o test.pdf test.md

使用 -f gfm 的一个缺点是 gfm 不支持公式,因此如果在 Markdown 中包含公式,将不能正确渲染。解决办法是去掉 -f gfm flag,或者使用 Pandoc 自带的 markdown格式。

更改 PDF 的 margin#

使用默认设置生成的 PDF margin 太大,根据 Pandoc 官方FAQ,可以使用下面的选项更改 margin:

-V geometry:"top=2cm, bottom=1.5cm, left=2cm, right=2cm"

完整命令为:

pandoc --pdf-engine=xelatex -V geometry:"top=2cm, bottom=1.5cm, left=2cm, right=2cm" -o test.pdf test.md

Markdown 文件中使用斜杠 backslash 会出错#

原始的 Markdown 格式,支持在文件中使用 backslash,但是 Pandoc 把 backslash 以及后面的内容理解成 LaTeX 命令,因此在编译包含 backslash 的文件时,可能会遇到undefined command 错误或者更加奇怪的错误。参考这里以及这里,解决办法是让 Pandoc 把 Markdown文件当成正常的 Markdown,不要解读 LaTeX 命令,使用下面的 flag:

pandoc -f markdown-raw_tex

或者,也可以用两个 backslash 表示字面意义的 backslash,例如 \\columnwidth 或者如果 backslash 及后面文字原本就是一个命令,用 inline code block 包含起来。

给 inline code 加上背景色#

将 Markdown 转为 PDF 时,由于 Pandoc 使用 LaTeX 中的 \textt 命令来表示 inline code,所以 inline code 是没有背景色的。为了增加 inline code 的可读性,我们可以修改 \texttt 命令,给文本添加背景色。首先建立 head.tex 文件,在其中加入以下命令:

% change background color for inline code in
% markdown files. The following code does not work well for
% long text as the text will exceed the page boundary
\definecolor{bgcolor}{HTML}{E0E0E0}
\let\oldtexttt\texttt

\renewcommand{\texttt}[1]{
  \colorbox{bgcolor}{\oldtexttt{#1}}
}

在使用 Pandoc 转换 Markdown 文件时,加上 -H 选项来引用 head.tex 文件,例如

pandoc --pdf-engine=xelatex -H head.tex test.md -o test.pdf

这样生成的 PDF 中,inline code 就会有灰色的背景色,背景颜色可以根据自己喜好修改。

更改引用 (block quote) 的风格#

默认情况下,当我们把 Markdown 文件转为 PDF 时,Pandoc 使用 LaTeX 中的 quote环境来表示 block quote。生成的 PDF 中,引用文字只是被缩进了,看起来很不明显。

我们可以自己定义一个 quotation 环境,给环境加上背景颜色和缩进。将下面的设置写入到 head.tex 中:

\usepackage{framed}
\usepackage{quoting}

\definecolor{bgcolor}{HTML}{DADADA}
\colorlet{shadecolor}{bgcolor}
% define a new environment shadedquotation. You can change leftmargin and
% rightmargin as you wish.
\newenvironment{shadedquotation}
 {\begin{shaded*}
  \quoting[leftmargin=1em, rightmargin=0pt, vskip=0pt, font=itshape]
 }
 {\endquoting
 \end{shaded*}
 }

%
\def\quote{\shadedquotation}
\def\endquote{\endshadedquotation}

当你想把 Markdown 转为 PDF 时,可以使用下面的命令:

pandoc -H head.tex test.md -o test.pdf

生成的 PDF 中引用的效果如下:

参考#

将设置放入 head.tex 文件中#

由于将 Markdown 转为 PDF 需要诸多选项与设置,将这些设置都写在命令行上,既浪费时间,也不利于小修小改,所以可以将常用的一些命令都放到 head.tex 文件中,然后在转换 Markdown 文件的时候引用该文件即可。

例如,可以将设置页面宽度的命令,给 inline code 着色的命令,以及设置链接颜色的命令统一放入 head.tex 中:

\usepackage{fancyvrb,newverbs}
\usepackage[top=2cm, bottom=1.5cm, left=2cm, right=2cm]{geometry}

% change background color for inline code in
% markdown files. The following code does not work well for
% long text as the text will exceed the page boundary
\definecolor{bgcolor}{HTML}{E0E0E0}
\let\oldtexttt\texttt

\renewcommand{\texttt}[1]{
  \colorbox{bgcolor}{\oldtexttt{#1}}
}

%% color and other settings for hyperref package
\hypersetup{
    bookmarksopen=true,
    linkcolor=blue,
    filecolor=magenta,
    urlcolor=RoyalBlue,
}

下次使用的时候,直接用 -H 选项引用以上文件即可。

List 嵌套层次太多的问题#

读者Karl Liu反应,如果使用 Markdown List 嵌套的层次太多(具体是超过六层),使用 Pandoc 生成的 PDF 文件的时候,会出现错误

! LaTeX Error: Too deeply nested.

具体讨论见这个 issue,作者提出的解决方法是,在 head.tex 文件中加上如下设置:

\usepackage{enumitem}
\setlistdepth{9}

\setlist[itemize,1]{label=$\bullet$}
\setlist[itemize,2]{label=$\bullet$}
\setlist[itemize,3]{label=$\bullet$}
\setlist[itemize,4]{label=$\bullet$}
\setlist[itemize,5]{label=$\bullet$}
\setlist[itemize,6]{label=$\bullet$}
\setlist[itemize,7]{label=$\bullet$}
\setlist[itemize,8]{label=$\bullet$}
\setlist[itemize,9]{label=$\bullet$}
\renewlist{itemize}{itemize}{9}

\setlist[enumerate,1]{label=$\arabic*.$}
\setlist[enumerate,2]{label=$\alph*.$}
\setlist[enumerate,3]{label=$\roman*.$}
\setlist[enumerate,4]{label=$\arabic*.$}
\setlist[enumerate,5]{label=$\alpha*$}
\setlist[enumerate,6]{label=$\roman*.$}
\setlist[enumerate,7]{label=$\arabic*.$}
\setlist[enumerate,8]{label=$\alph*.$}
\setlist[enumerate,9]{label=$\roman*.$}
\renewlist{enumerate}{enumerate}{9}

在编译 PDF 的时候,加上 -H head.tex 选项。

使用 Sublime Text build system 生成 PDF#

写完 Markdown,再切换到 terminal 使用 Pandoc 生成 PDF 以及预览,颇为麻烦,因此我使用 Sublime Text 的 build system 来简化编译生成 PDF 以及预览的整个过程。PDF 预览使用了轻量级的 Sumatra PDF reader

一个示例的 build system 如下,

{
    "shell_cmd": "pandoc --pdf-engine=xelatex --highlight-style=zenburn -V colorlinks -V CJKmainfont=KaiTi \"${file}\" -o \"${file_path}/${file_base_name}.pdf\" ",
    "file_regex": "^(..[^:]*):([0-9]+):?([0-9]+)?:? (.*)$",
    "working_dir": "${file_path}",
    "selector": "text.html.markdown",

    "variants":
    [
        {
            "name": "Convert to PDF and Preview",
            "shell_cmd": "pandoc --pdf-engine=xelatex --highlight-style=zenburn -V colorlinks  -V CJKmainfont=KaiTi \"${file}\" -o \"${file_path}/${file_base_name}.pdf\"  &&SumatraPDF \"${file_path}/${file_base_name}.pdf\" ",
            // "shell_cmd":   "start \"$file_base_name\" call $file_base_name"
        }
    ]
}

在命令中使用到了引号,必须使用 backslash escape。可以从这里 下载这个 build system。

系统无法识别 Pandoc 的问题#

不知什么原因,上述把 Markdown 文件转为 PDF 的 build system 在编译 Markdown 文件时,突然给出如下错误提示:

‘pandoc’ is not recognized as an internal or external command, operable program or batch file.

通过查询 sublime 文档,发现我们可以在 build system 里面加上 path 变量。因此,我对上述的 build system 进行了调整,新的 build system 如下:

{
    "shell_cmd": "pandoc --pdf-engine=xelatex --highlight-style=zenburn -V colorlinks -V CJKmainfont=\"Source Han Serif SC\" \"${file}\" -o \"${file_path}/${file_base_name}.pdf\" ",
    "path": "C:/Users/east/AppData/Local/Pandoc/;%PATH%",
    "file_regex": "^(..[^:]*):([0-9]+):?([0-9]+)?:? (.*)$",
    "working_dir": "${file_path}",
    "selector": "text.html.markdown",

    "variants":
    [
        {
            "name": "Convert to PDF and Preview",
            "shell_cmd": "pandoc --pdf-engine=xelatex --highlight-style=zenburn -V colorlinks  -V CJKmainfont=\"Source Han Serif SC\" \"${file}\" -o \"${file_path}/${file_base_name}.pdf\"  &&SumatraPDF \"${file_path}/${file_base_name}.pdf\" ",
            "path": "C:/Users/east/AppData/Local/Pandoc/;%PATH%",
            // "shell_cmd":   "start \"$file_base_name\" call $file_base_name"
        }
    ]
}

使用新的 build system 以后,一切恢复正常。

笔记云同步#

云同步可以选择坚果云。同步速度快,并且支持多个文件夹同步,每个月有 1G 免费上传流量,对于文档同步来说,足够使用了。当然也可以使用自己的网盘或者云存储,都是可以的,看自己喜好。

注:以后有更新的话,会优先更新文章开头提到的英文版本,由于精力有限,此版本更新将不会很频繁,以修复错误为主。

参考资料#