14 Typst pdf写作
本文档总结了使用 Quarto 结合 Typst 引擎制作国际会议双语(英文/中文)邀请信的技术要点。重点记录了从 PDF 模板复刻到 Typst 代码实现过程中的布局技巧、字体处理及 Quarto 交互细节。
14.1 核心工作流
- 数据源 (.qmd): 撰写内容,通过 YAML header 指定输出格式。
- 样式模板 (.typ): 定义页面尺寸、页眉页脚、字体规范、自定义函数。
- 编译引擎: Quarto 调用 Pandoc 将 Markdown 转换为 Typst 代码,再由 Typst 编译器生成 PDF。
14.2 Typst 模板开发关键技术
14.2.1 页面布局与背景水印 (Page & Background)
在公文排版中,红头文件和盖章效果至关重要。
- 背景印章定位:使用
place函数结合dx/dy进行绝对定位。 - 透明度处理:
opacity是一个函数包裹内容,而非image的参数。
#set page(
paper: "a4",
margin: (top: 6cm, bottom: 3cm, left: 2cm, right: 2cm), // 留出头部给红头
background: [
#place(
bottom + left, // 基准位置
dx: 2.8cm, // 水平偏移
dy: -3.5cm, // 垂直偏移(向上)
// 正确的透明度写法
opacity(0.85, image("../../pic/logo/logo-seal.png", width: 4.8cm))
)
]
)14.2.2 复杂页眉设计 (Complex Header)
英文版页眉需要“左侧校徽 + 间隔 + 右侧校名/Logo”的组合,且要求高度对齐。
- Grid 布局:使用
#grid实现分列布局。 - Stack 堆叠:在某一列中使用
#stack实现垂直排列(如图片 + 文字)。 - 微调间距:使用
v(-0.3cm)等负值来强制拉近元素间距,解决图片自带留白过大的问题。
header: [
#grid(
columns: (auto, auto, 1fr), // 三列:空白占位 | 图标 | 文字堆叠
gutter: 0.8em,
box(width: 0.2cm)[ ], // 强制左侧留白
image("logo.png", height: 3.0cm),
align(center)[
#stack(
dir: ttb,
spacing: 0em,
image("name.png", height: 3.0cm),
v(-0.3cm), // 负边距,消除图片底部空白
text(weight: "bold")[Northwest A&F University]
)
]
)
#line(length: 100%, stroke: 0.75pt + blue) // 贯穿线
]14.3 中文排版难点与解决方案
14.3.1 中文字体回退机制 (Font Fallback)
如果没有相应字体(如方正小标宋),则可以考虑首先下载字体到本地。对于windows用户,把下载后的字体文件复制到 C:\Windows\Fonts 目录下完成字体安装。然后就使用 typst fonts 命令查看字体名称。例如,方正小标宋的PostScript名称是 FZXiaoBiaoSong-B05S。
Typst 对中文字体的识别依赖于系统字体的英文名称或PostScript名称。为保证兼容性,应使用字体数组。
// 优先级:方正小标宋 -> 方正粗黑宋 -> 系统宋体
#text(
font: ("FZXiaoBiaoSong-B05S", "FZXBSJW--GB1-0", "FZCuHeiSongS-B-GB", "SimSun"),
size: 34pt,
fill: red
)[西北农林科技大学]14.3.2 伪粗体实现 (Fake Bold)
许多中文字体(如仿宋 FangSong)本身不包含 Bold 字重。直接设置 weight: "bold" 无效(会回退到宋体或不显示粗体)。
- 解决方案:使用
stroke(描边) 来模拟加粗效果。
// 仿宋伪粗体:描边 0.5pt
#text(font: "FangSong_GB2312", size: 22pt, stroke: 0.5pt)[邀请函]14.3.3 首行缩进与例外处理
中文正文通常需要首行缩进 2 字符,但“尊敬的专家:”等称呼语需要顶格。
- 全局设置:
#set par(first-line-indent: 2em)- 例外处理(自定义函数): 在
.typ中定义 helper 函数:
#let indent(enable, content) = {
if not enable {
set par(first-line-indent: 0em)
content
} else {
content
}
}14.4 Quarto 与 Typst 的交互
14.4.1 嵌入原生 Typst 代码 (Raw Typst)
当 Markdown 语法不足以表达特定的排版需求(如调用上面的 indent 函数或复杂的落款布局)时,需要在 .qmd 中使用 ```{=typst} 块。
<!-- 在 qmd 文件中 -->
```{=typst}
#indent(false)[尊敬的专家:]
```14.4.2 落款样式的封装
为了让 .qmd 专注于内容,将复杂的落款布局(右对齐容器+内部居中)封装在 .typ 模板的函数中。
**Template (.typ):**
```{=typst}
#let sign(content) = {
v(1em)
align(right)[
#block(width: 50%)[ // 限制宽度块
#set align(center) // 块内文字居中
#set par(first-line-indent: 0em)
#text(size: 16pt)[#content]
]
]
}
```Quarto (.qmd):
```{=typst}
#sign[
西北农林科技大学\
2025年10月30日
]
```14.5 遇到的坑 (Pitfalls)
Typst 包版本依赖:
- 尝试使用
@preview/ctyp优化中文排版,但 Quarto 内置的 Typst 版本(如 0.13.0)可能滞后于包的最低要求(如 0.13.1)。 - 对策:暂时手动处理字体和缩进,或手动管理 Typst 编译器版本。
- 尝试使用
Markdown 解析干扰:
- 直接在 qmd 写
#func[]可能会被视为普通文本。必须包裹在```{=typst}中。
- 直接在 qmd 写
字体名称不匹配:
- Windows 下“方正小标宋”可能识别为
FZXBSJW--GB1-0,但也可能是FZXiaoBiaoSong-B05S。使用typst fonts命令检查本地实际名称至关重要。
- Windows 下“方正小标宋”可能识别为
14.6 应用案例
- 中俄中心2026CRC会议邀请信(英文版/中文版)的Typst实现。
14.7 方法总结
通过 Quarto + Typst,我们成功实现了:
- 样式分离:所有视觉噪音(字号、颜色、间距)保留在
.typ文件中。 - 内容专注:
.qmd文件仅包含文本内容,便于维护。 - 高保真输出:通过 Typst 强大的布局能力,完美复刻了 Word/PDF 模板的红头文件格式。