PDF文档生成Skill pdf-generation

PDF文档生成技能,提供专业的Markdown到PDF转换服务。支持自定义模板、样式、目录生成、交叉引用、图像优化和PDF/A归档合规性。适用于生成用户手册、技术文档、品牌化文档和多章节手册。关键词:PDF生成,Markdown转PDF,文档转换,PDF模板,目录生成,PDF/A归档,技术文档,用户手册。

DevOps 0 次安装 2 次浏览 更新于 2/26/2026

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}

工作流程

  1. 收集源文件 - 收集Markdown文件
  2. 预处理 - 处理包含和变量
  3. 转换 - 将Markdown转换为中间格式
  4. 应用模板 - 添加样式和结构
  5. 生成目录 - 构建目录
  6. 渲染PDF - 输出最终PDF
  7. 优化 - 压缩图像和字体

依赖项

{
  "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阅读器上测试

参考

目标流程

  • docs-versioning.js
  • user-guide-docs.js
  • runbook-docs.js
  • adr-docs.js