name: pdf-generation description: 专业的PDF文档生成。使用自定义模板、样式、目录、交叉引用,将Markdown转换为PDF,并优化打印和归档输出。 allowed-tools: Read, Write, Edit, Bash, Glob, Grep backlog-id: SK-020 metadata: author: babysitter-sdk version: “1.0.0”
PDF生成技能
专业的PDF文档生成。
能力
- Markdown到PDF的转换
- 自定义PDF模板和样式
- 目录生成
- 交叉引用和链接处理
- 打印图像优化
- 用于归档的PDF/A合规性
- 多章节文档组装
- 封面页和页眉/页脚
使用场景
在以下情况下调用此技能:
- 从Markdown生成PDF文档
- 创建可打印的用户指南
- 将文档归档为PDF
- 生成品牌化的PDF输出
- 构建多章节手册
输入参数
| 参数 | 类型 | 必需 | 描述 |
|---|---|---|---|
| inputPath | string | 是 | Markdown源文件的路径 |
| outputPath | string | 是 | 输出PDF文件的路径 |
| template | string | 否 | PDF模板的路径 |
| config | object | 否 | PDF生成选项 |
| metadata | object | 否 | 文档元数据 |
| toc | boolean | 否 | 生成目录 |
输入示例
{
"inputPath": "./docs",
"outputPath": "./output/documentation.pdf",
"template": "./templates/manual.html",
"toc": true,
"metadata": {
"title": "产品文档",
"author": "文档团队",
"version": "1.0.0"
}
}
输出结构
单一PDF输出
output/
└── documentation.pdf
├── 封面页
├── 目录
├── 第1章:入门指南
│ ├── 安装
│ └── 快速开始
├── 第2章:用户指南
│ ├── 配置
│ └── 功能
├── 第3章:API参考
└── 附录
多PDF输出
output/
├── getting-started.pdf
├── user-guide.pdf
├── api-reference.pdf
└── complete-manual.pdf
Pandoc配置
pandoc-defaults.yaml
from: markdown+smart+yaml_metadata_block+implicit_figures+table_captions
to: pdf
pdf-engine: xelatex
variables:
documentclass: report
papersize: letter
fontsize: 11pt
geometry:
- margin=1in
- top=1.25in
- bottom=1.25in
mainfont: "Source Serif Pro"
sansfont: "Source Sans Pro"
monofont: "Source Code Pro"
linkcolor: blue
urlcolor: blue
toccolor: black
toc-depth: 3
include-before-body:
- cover.tex
include-in-header:
- preamble.tex
metadata:
title: "文档"
author: "文档团队"
date: "2026-01-24"
lang: en-US
toc: true
toc-title: "目录"
number-sections: true
colorlinks: true
highlight-style: pygments
LaTeX前言 (preamble.tex)
% 自定义样式
\usepackage{fancyhdr}
\usepackage{titlesec}
\usepackage{xcolor}
\usepackage{listings}
\usepackage{graphicx}
% 页眉/页脚
\pagestyle{fancy}
\fancyhf{}
\fancyhead[L]{\leftmark}
\fancyhead[R]{\thepage}
\fancyfoot[C]{\small 文档 v1.0}
% 代码块样式
\lstset{
basicstyle=\ttfamily\small,
breaklines=true,
frame=single,
backgroundcolor=\color{gray!10}
}
% 标题样式
\titleformat{\chapter}[display]
{
ormalfont\huge\bfseries}
{\chaptertitlename\ \thechapter}{20pt}{\Huge}
% 链接颜色
\definecolor{linkblue}{RGB}{0,102,204}
WeasyPrint配置
weasyprint-config.css
@page {
size: letter;
margin: 1in;
margin-top: 1.25in;
margin-bottom: 1.25in;
@top-center {
content: string(chapter-title);
font-size: 10pt;
color: #666;
}
@bottom-center {
content: "第 " counter(page) " 页,共 " counter(pages) " 页";
font-size: 9pt;
}
}
@page :first {
@top-center { content: none; }
@bottom-center { content: none; }
}
/* 封面页 */
.cover {
page: cover;
text-align: center;
padding-top: 3in;
}
.cover h1 {
font-size: 36pt;
color: #333;
}
.cover .version {
font-size: 14pt;
color: #666;
margin-top: 1in;
}
/* 目录 */
#toc {
page-break-after: always;
}
#toc h2 {
font-size: 24pt;
margin-bottom: 0.5in;
}
#toc a {
text-decoration: none;
color: inherit;
}
#toc a::after {
content: leader('.') target-counter(attr(href), page);
}
/* 章节 */
h1 {
string-set: chapter-title content();
page-break-before: always;
font-size: 28pt;
border-bottom: 2px solid #333;
padding-bottom: 0.25in;
}
h2 { font-size: 20pt; margin-top: 0.5in; }
h3 { font-size: 16pt; margin-top: 0.3in; }
/* 代码块 */
pre {
background-color: #f5f5f5;
padding: 0.5em;
border-radius: 4px;
font-size: 9pt;
overflow-x: auto;
page-break-inside: avoid;
}
code {
font-family: "Source Code Pro", monospace;
background-color: #f0f0f0;
padding: 0.1em 0.3em;
border-radius: 3px;
}
/* 表格 */
table {
width: 100%;
border-collapse: collapse;
margin: 1em 0;
page-break-inside: avoid;
}
th, td {
border: 1px solid #ddd;
padding: 0.5em;
text-align: left;
}
th {
background-color: #f5f5f5;
font-weight: bold;
}
/* 图片 */
img {
max-width: 100%;
height: auto;
}
figure {
text-align: center;
page-break-inside: avoid;
}
figcaption {
font-style: italic;
color: #666;
margin-top: 0.5em;
}
/* 链接 */
a {
color: #0066cc;
text-decoration: none;
}
/* 打印优化 */
@media print {
a[href^="http"]::after {
content: " (" attr(href) ")";
font-size: 0.8em;
color: #666;
}
}
封面页模板
cover.html
<!DOCTYPE html>
<html>
<head>
<style>
body {
font-family: "Source Sans Pro", sans-serif;
text-align: center;
padding-top: 200px;
}
.logo {
max-width: 200px;
margin-bottom: 50px;
}
h1 {
font-size: 48px;
color: #333;
margin-bottom: 20px;
}
.subtitle {
font-size: 24px;
color: #666;
margin-bottom: 100px;
}
.version {
font-size: 18px;
color: #999;
}
.date {
font-size: 14px;
color: #999;
margin-top: 10px;
}
.footer {
position: absolute;
bottom: 50px;
width: 100%;
text-align: center;
color: #666;
}
</style>
</head>
<body>
<img src="logo.png" alt="公司Logo" class="logo">
<h1>{{title}}</h1>
<p class="subtitle">{{subtitle}}</p>
<p class="version">版本 {{version}}</p>
<p class="date">{{date}}</p>
<div class="footer">
<p>{{company}}</p>
<p>保密</p>
</div>
</body>
</html>
多章节组装
build-manual.js
const pandoc = require('pandoc');
const fs = require('fs');
const path = require('path');
async function buildManual(config) {
const chapters = [
{ title: '入门指南', files: ['intro.md', 'installation.md', 'quickstart.md'] },
{ title: '用户指南', files: ['configuration.md', 'features.md', 'advanced.md'] },
{ title: 'API参考', files: ['api/*.md'] },
{ title: '附录', files: ['glossary.md', 'changelog.md'] }
];
// 合并所有Markdown文件
let combined = '';
for (const chapter of chapters) {
combined += `# ${chapter.title}
`;
for (const filePattern of chapter.files) {
const files = glob.sync(filePattern, { cwd: config.docsDir });
for (const file of files) {
const content = fs.readFileSync(path.join(config.docsDir, file), 'utf8');
// 调整标题级别
const adjusted = adjustHeadings(content, 1);
combined += adjusted + '
';
}
}
}
// 写入合并文件
const tempFile = '/tmp/combined.md';
fs.writeFileSync(tempFile, combined);
// 运行Pandoc
await pandoc({
input: tempFile,
output: config.outputPath,
args: [
'--defaults', config.pandocDefaults,
'--metadata-file', config.metadataFile
]
});
return { output: config.outputPath };
}
PDF/A合规性
生成归档PDF
# 使用Pandoc生成PDF/A输出
pandoc input.md \
-o output.pdf \
--pdf-engine=xelatex \
-V 'pdfa=1b' \
--include-in-header=pdfa-header.tex
# pdfa-header.tex
\usepackage{hyperref}
\hypersetup{
pdfstartview=,
colorlinks=false,
pdfpagelayout=SinglePage
}
\usepackage[a-1b]{pdfx}
工作流程
- 收集源文件 - 收集Markdown文件
- 预处理 - 处理包含和变量
- 转换 - 将Markdown转换为中间格式
- 应用模板 - 添加样式和结构
- 生成目录 - 构建目录
- 渲染PDF - 输出最终PDF
- 优化 - 压缩图像和字体
依赖项
{
"devDependencies": {
"pandoc": "^0.2.0",
"weasyprint": "via pip",
"puppeteer": "^21.0.0",
"pdf-lib": "^1.17.0"
}
}
系统依赖项
# macOS
brew install pandoc
brew install --cask basictex
pip install weasyprint
# Ubuntu
sudo apt install pandoc texlive-xetex texlive-fonts-recommended
pip install weasyprint
# Windows (通过Chocolatey)
choco install pandoc miktex
pip install weasyprint
CLI命令
# 使用Pandoc处理单个文件
pandoc input.md -o output.pdf --defaults pandoc-defaults.yaml
# 合并多个文件
pandoc docs/*.md -o manual.pdf --toc --number-sections
# 使用WeasyPrint
weasyprint input.html output.pdf -s style.css
# 使用Puppeteer(用于基于HTML的PDF)
node generate-pdf.js --input docs/ --output manual.pdf
最佳实践
- 尽可能使用矢量图形
- 优化打印图像(300 DPI)
- 包含页码和页眉
- 生成带超链接的目录
- 处理代码块的页面分断
- 嵌入字体以确保一致性
- 在不同的PDF阅读器上测试
参考
- Pandoc: https://pandoc.org/
- WeasyPrint: https://weasyprint.org/
- LaTeX: https://www.latex-project.org/
- PDF/A: https://www.pdfa.org/
目标流程
- docs-versioning.js
- user-guide-docs.js
- runbook-docs.js
- adr-docs.js