使用 pandoc 和 typst 将 markdown 转换为 pdf
目录
你是否有使用 markdown 编写文档,但又不想使用繁琐的 latex 转换成 pdf 的烦恼?那么你可以试试 pandoc 和 typst。这是一款文档模板程序,可以将 markdown 转换为漂亮的 pdf 文件,同时支持强调(斜体粗体)、无序列表、有序列表、任务列表、表情符号 emoji、链接、图片、脚注、定义列表、数学公式、代码高亮 fenced code block、表格、表格宽度与列宽、引用 quote|blocktext、alerts、水平线、标题等多种格式。想要查看文档效果?请点击 用户帮助手册 ,它也是由本文档模板程序生成。支持多种代码高亮颜色主题,
大约十年前,有悟就喜欢使用 markdown 编写文档,原因只是 microsoft office 或 wps 过于笨重,后来也渐渐发现,日常的技术文档、小组工作计划等小体裁文档,使用 office word 或者 wps 确实有点杀鸡用牛刀,常用的格式无非是标题、列表、表格、文本段落,并不需要使用老旧的电脑来运行庞大的文档编辑器程序。有悟有一定的编程基础,也知道文字内容与格式分离,可更有利于专注写作。
但是,在使用 markdown 编写完内容后,要将其分发时,一直遇到这样的困难,使用 pandoc 转换成 pdf,需要安装庞大的 latex 引擎。使用 pandoc 将 markdown 文件转换为 docx ,然后在 wps 或 microsoft office 打开再导出 pdf,操作繁琐,不符合文档写作工作流简易性要求。
直到 2024年,发现已经开源了一段时间的 typst,它非常本人习惯,将文档内容的 markdown 文件,转换成 pdf,仅需要安装几十M的 typst,仅消耗秒级的时间,即可生产质量非常高的 pdf 文档 或者 png 图片。非常感谢 tyspt 团队的贡献。
有悟将原来基于
pandoc
的 markdown 转 docx 转 pdf
的工作流,在 pandoc 和
typst
加持下,简化为 markdown 转 pdf 或 png
。当然,也花费了两个多月的时间来学习 typst 的编程语法,并编制文档模板程序。
文档模板的设计初衷,是满足本人日常工作的文档写作要求,非常自以为是,这些文档的主要类型的有:
- 技术方案说明
- 工作计划
- 总结
- 日志
书籍出版、 学术论文,暂不在考虑的范围。
从哪里获得本文档模板程序,见 如何获得本模板
模板中支持的格式有 #
文档中支持的格式类型有:
- 强调(斜体粗体)
- 无序列表
- 有序列表
- 任务列表
- 表情符号 emoji
- 链接
- 图片
- 脚注
- 定义列表
- 数学公式
- 代码高亮 fenced code block
- 表格
- 表格宽度与列宽
- 引用 quote|blocktext
- alerts
- 水平线
- 标题
模板中的颜色设定 #
文档有暗黑、浅色两个版本。文档页面分为 A4 与适用手机浏览的长宽比 650/300 两种尺寸。
代码高亮颜色主题有:
-
ayu
:
- ayu-mirage
- ayu-dark
- ayu-light
-
Catppuccin
- Catppuccin Frappe
- Catppuccin Latte
- Catppuccin Macchiato
- Catppuccin Mocha
模板程序中已经包含以上所有情况的组合。
效果示例 #
可直接下载 userguide.dark.ayu-dark.pdf 浏览效果。
强调 #
markdown 内容如下:
强调,又称斜体,使用 *星号* 或 _下划线_。
强调,又称粗体,使用 **星号** 或 __下划线__。
结合使用 **星号和 _下划线_** 来强调。
删除线使用两个波浪号。 ~~划掉这个。~~
**这是粗体文本**
__这是粗体文本__
*这是斜体文本*
_这是斜体文本_
~~删除线~~
渲染成:
无序列表 #
markdown 内容如下:
* 无序列表可以使用星号(`*`)
- 或减号(`-`)
+ 或加号(`+`)
+ 通过在行开头使用 `+`、`-` 或 `*` 创建列表
+ 通过缩进 2 个空格来创建子列表:
- 标记字符更改强制开始新列表:
* Ac tristique libero volutpat at
+ Facilisis in pretium nisl aliquet
- Nulla volutpat aliquam velit
+ 非常简单!
+ 无序列表也可以
+ 与序列列表混合
1. 缩进并创建一个序号列表项
2. 再来一个序号项
+ 另一个无充列表项
渲染成:
有序列表 #
markdown 内容如下:
1. 第一个有序列表项
2. 另一个项
* 无序列表
1. 实际数字无关紧要,只要它是一个数字
1. 序号会重新编排
4. 另一个项。
你还可以在列表项中正确缩进段落。
5. 多空一行
除了可以正确缩进段落外,在段落前多空一行,还可以形成一个新的缩进段落,首行缩进。
除了可以正确缩进段落外,在段落前多空一行,还可以形成一个新的缩进段落,首行缩进。
7. 再来一个项
1. 进行更改
1. 修复错误
2. 改进格式
- 使标题更大
2. 将我的提交推送到 GitHub
3. 打开拉取请求
* 描述我的更改
* 提及我团队的所有成员
* 征求反馈
*
渲染成:
任务列表 #
markdown 内容如下:
- [x] 完成我的更改
- [ ] 将我的提交推送到 GitHub
- [ ] 打开拉取请求
- [x] 支持 \@mentions、#refs、[links]()、**formatting** 和 <del>tags</del>
- [x] 需要列表语法(支持任何无序或有序列表)
- [ ] 这是一个完整的项目
- [ ] 这是一个不完整的项目
- ✅ 这一行不是 task list 项,但也属于列表项
渲染成:
emoji #
markdown 内容如下:
*emoji 标记*: 😄 😡 😓 👇
*emoji 符号*: 😀😃😄😁🐶🐱🐭🐹
🍏🍐🍉🍇🍓
⚽️🏐🏈🏀
🚗🚕🚙🚌
⌚️📱📲💻⌨️
🩷❤️🧡💛🉐㊙️㊗️🈴🉑☢️☣️
🏳️🏴🏴☠️🏁
⚠️🌟🔥👍✅
渲染成:
链接 #
markdown 内容如下:
[我是内联样式链接](https://www.google.com)
[我是带有标题的内联样式链接](https://www.google.com "Google 的主页")
[我是引用样式链接][任意不区分大小写的引用文本]
[我是存储库文件的相对引用](../blob/master/LICENSE)
[您可以使用数字进行引用样式链接定义][1]
或者将其留空并使用 [链接文本本身]。
URL 和尖括号中的 URL 将自动转换为链接。http://www.example.com 或 <http://www.example.com>,有时是 example.com(但不是 Github 上的)。
一些文字表明参考链接可以稍后跟进。
[任意不区分大小写的引用文本]: https://www.mozilla.org
[1]: http://slashdot.org
[链接文本本身]: http://www.reddit.com
渲染成:
图片 #
markdown 内容如下:
这是徽标:
内联样式:
![替代文本](./images/icon48.png "徽标标题文本 1")
引用样式:
![替代文本][徽标]
[徽标]: ./images/icon48.png "徽标标题文本2"
图片下方没有题注,并且图片紧靠着文字:
![Minion](./images/minion.png){width=20%}
![Stormtroopocat](./images/stormtroopocat.png "The Stormtroopocat"){width=20%}
还可以在图片下方添加题注,需要单独成为段落,即前后各空一行:
![图片标题,来点说明][id]
在文档后面的引用中定义图片位置:
[id]: ./images/dojocat.jpg "The Dojocat"
还可以指定图片大小:
![Minion](./images/minion.png){width=5%} ![Minion](./images/minion.png){width=10%}
![Minion](./images/minion.png){width=20%}![Minion](./images/minion.png){width=30%}
渲染成:
脚注 #
markdown 内容如下:
脚注 1 链接[^1]。
脚注 2 链接[^2]。
~内联脚注^[内联脚注的文本] 定义。
重复的脚注引用[^2]。
[^1]: 脚注 **可以有标记** 和多个段落。
[^2]: 脚注文本。
渲染成:
定义列表 #
markdown 内容如下:
术语
: 术语名称独立一行,第二行以冒号定格(`: `)开头,紧接是术语定义的描述
又一个术语
: 还是以冒号定格(`: `)开头,紧接还是术语定义的描述。*定义列表*经常用在文档,对专业术语、业务术语、名词进行统一的定义。
术语条目换行
: 与 markdown 的换行解释有关,如果是 `hard_linkbreak`,即条目间需要空出一行。
这不是一个定义
: 定义名称没有与上个条目空行分隔,无法成为新的条目。
术语定义段落
: 术语内容作为整体段落,向右缩进。
渲染成:
数学公式 #
markdown 内容如下:
单独行显示
: $$
e=mc^2
$$
内联
: 这是一个小兔子,紧接一个公式,$e=mc^2$。紧接着后面还可以有文字。
渲染成:
代码高亮 #
markdown 内容如下:
```
内联 `代码` 周围有 `反引号`。
```
内联 `代码` 周围有 `反引号`。
代码块使用一对 三反引号 ```
示例代码:
````
```css
@font-face {
font-family: Chunkfive; src: url('Chunkfive.otf');
}
body, .usertext {
color: #F0F0F0; background: #600;
font-family: Chunkfive, sans;
}
@import url(print.css);
@media print {
a[href^=http]::after {
content: attr(href)
}
}
```
````
代码高亮效果:
```css
@font-face {
font-family: Chunkfive; src: url('Chunkfive.otf');
}
body, .usertext {
color: #F0F0F0; background: #600;
font-family: Chunkfive, sans;
}
@import url(print.css);
@media print {
a[href^=http]::after {
content: attr(href)
}
}
```
示例代码:
````
```javascript
function $initHighlight(block, cls) {
try {
if (cls.search(/\bno\-highlight\b/) != -1)
return process(block, true, 0x0F) +
` class="${cls}"`;
} catch (e) {
/* handle exception */
}
for (var i = 0 / 2; i < classes.length; i++) {
if (checkCondition(classes[i]) === undefined)
console.log('undefined');
}
}
export $initHighlight;
```
````
代码高亮效果:
```javascript
function $initHighlight(block, cls) {
try {
if (cls.search(/\bno\-highlight\b/) != -1)
return process(block, true, 0x0F) +
` class="${cls}"`;
} catch (e) {
/* handle exception */
}
for (var i = 0 / 2; i < classes.length; i++) {
if (checkCondition(classes[i]) === undefined)
console.log('undefined');
}
}
export $initHighlight;
```
渲染成:
表格 #
markdown 内容如下:
冒号可用于对齐列。
| 表格 | 很 | 酷 |
| ------------- |:-------------:| -----:|
| 列 3 是 | 右对齐 | $1600 |
| 列 2 是 | 居中 | $12 |
| 斑马条纹 | 整齐 | $1 |
每个标题单元格之间必须至少有 3 个破折号(`-`) 。
外部管道 (`|`) 是可选的,您不需要让
原始 Markdown 排列得很漂亮。您还可以使用内联 Markdown。
表格示例,外部管道符(|)可省略:
Markdown | 少也 | 漂亮
--- | --- | ---
*仍然* | `呈现` | **很好**
1 | 2 | 3
| 第一个标题 | 第二个标题 |
| ------------- | ------------- |
| 内容单元格 | 内容单元格 |
| 内容单元格 | 内容单元格 |
表格示例,单元格内容可以标记样式:
| 命令 | 描述 |
| --- | --- |
| git status | 列出所有新的或修改过的文件 |
| git diff | 显示尚未暂存的文件差异 |
| 命令 | 说明 |
| --- | --- |
| `git status` | 列出所有 *新的或修改过的* 文件 |
| `git diff` | 显示**尚未**暂存的文件差异 |
表格示例,表格各列可自由对齐:
| 左对齐 | 居中对齐 | 右对齐 |
| :--- | :---: | ---: |
| git status | git status | git status |
| git diff | git diff | git diff |
表格示例,单元格中的特殊符号:
| 名称 | 字符 |
| --- | --- |
| 反引号 | ` |
| 管道符 | \| |
渲染成:
表格宽度与列宽 #
pandoc markdown 解析器,支持两格可以控制表格宽度和列宽的表格格式,multiline tables
和 grid tables
。默认行 72个 scii 字符宽度则可占满页面正文宽度。
以 grid_stables
为例:
: 2 列 72 字符数
+-----------------------------------+----------------------------------+
| Fruit Price | Advantages |
+===================================+:=================================+
| Oranges $2.10 | - cures scurvy |
| | - tasty |
+-----------------------------------+----------------------------------+
: 3 列 72 字符数
+---------------+-------------------+----------------------------------+
| Fruit | Price | Advantages |
+===============+===================+:=================================+
| Oranges | $2.10 | - cures scurvy |
| | | - tasty |
+---------------+-------------------+----------------------------------+
: 2 列 37 字符数
+---------------+-------------------+
| Fruit | Price |
+===============+===================+
| Oranges | $2.10 |
| | |
+---------------+-------------------+
渲染成:
以 multiline_tables
为例:
: 4列,72 字符数
------------------------
Centered Default Right Left
Header Aligned Aligned Aligned
---------- ------- --------------- -------------------------------------
First row 12.0 Example of a row that
spans multiple lines.
------------------------
: 3列,34 字符数
------------------------
Centered Default Right
Header Aligned Aligned
---------- ------- ---------------
First row 12.0
------------------------
: 2列 72 字符数
------------------------
Centered Default Right Left
Header Aligned Aligned Aligned
----------------------------- ------------------------------------
First row 12.0 Example of a row that
spans multiple lines.
------------------------
渲染成:
引用 #
markdown 内容如下:
> 文本区块引用在电子邮件中非常方便,可以模拟回复文本。
> 此行是同一引文的一部分。
引文分隔符。
> 这是一行非常长的行,换行时仍会正确引用。哦,让我们继续写,以确保它足够长,实际上可以为每个人换行。哦,你可以*将* **Markdown** 放入区块引用中。
> 块引用也可以嵌套...
>> ...通过使用紧挨着彼此的附加大于号...
> > > ...或者在箭头之间留有空格。
渲染成:
gfm alerts #
alerts 是 GitHub-Flavored markdown 中专用的 html css 样式。本模板做了兼容性处理,支持除了 gfm 本身所规定的 note、tip、important、caution, warning 外,还支持 idea、error、success、goal、notification,大小写均可。
markdown 内容如下:
> [!NOTE]
> 这是一个 note
> [!TIP]
> 这是一个提示
> [!IMPORTANT]
> 这很重要
> [!CAUTION]
> 要小心这里所描述的问题
> [!WARNING]
> 警告
>
>[!Idea]
> 这是一个想法
>
>
> [!Error]
> 这里错误了
>
> [!Success]
> 成功的时候
> [!Goal]
> 这是目标
>
> [!Notification]
> 这里有一个通知
>
渲染成:
水平线 #
markdown 内容如下:
三个符号或更多
三个连字符 `---`
---
三个星号 `***`
***
三个下划线 `___`
___
渲染成:
标题 #
markdown 内容如下:
# (示例需要,请忽略) h1 标题
## h2 标题
### h3 标题
#### h4 标题
##### h5 标题
###### h6 标题
或者,对于 H1 和 H2,使用下划线样式:
(示例需要,请忽略) Alt-H1
======
Alt-H2
------
渲染成:
使用方法 #
将本模板安装为 typst local package,即复制或链接到用户本地目录下 {data_dir}/typst/packages/local
下,使在使用 pandoc 转换 markdown 为 pdf 时,指定 --template
参数为模板文件夹 themekit/{版本号}/pandoc/
中的某一个模板。
{data_dir}
与操作系统有关
具体详细操作,见模板程序的 《用户帮助与说明手册》
如何获得本模板 #
若上面演示的效果满足你日常使用要求,或者你有需求自己开发维护一套这样的程序但又不想从零开始的话,可以参考本模板。
本markdown 转 pdf 的 pandoc typst 模板程序,暂没有开源的计划。你可以从以下的链接中获取授权版本。