添加页面级 enabled 布尔参数,用于临时禁用整个幻灯片,无需删除或注释 YAML 内容。
与元素级 visible 条件渲染独立工作,提供两层控制机制。
主要变更:
- 在 yaml2pptx.py 主循环中检查 enabled 参数,跳过禁用的幻灯片
- 实现独立的 slide_index 计数器,准确统计实际渲染的幻灯片数量
- 在 yaml_loader.py 中添加 enabled 字段验证,确保类型为布尔值
- 添加 11 个测试用例,覆盖各种使用场景
- 更新 README.md 和 README_DEV.md 文档,说明 enabled 和 visible 的区别
- 创建新的 slide-enabled-control capability 规范
- 更新 template-system 规范,添加 enabled 字段支持
使用示例:
slides:
- template: title-slide
vars:
title: "正常页面"
- enabled: false
template: work-in-progress
vars:
title: "临时禁用的页面"
测试:所有 282 个单元测试通过
560 lines
14 KiB
Markdown
560 lines
14 KiB
Markdown
# yaml2pptx
|
||
|
||
使用 YAML 声明式语法创建 PowerPoint 演示文稿的工具。
|
||
|
||
## ✨ 功能特性
|
||
|
||
- 📝 **YAML 声明式语法** - 使用简单易读的 YAML 定义演示文稿
|
||
- ✅ **智能验证** - 转换前自动检查 YAML 文件,提前发现问题
|
||
- 🎨 **模板系统** - 支持参数化模板,复用幻灯片布局
|
||
- 🧩 **丰富的元素类型** - 文本、图片、形状、表格
|
||
- 👁️ **实时预览** - 浏览器预览模式,支持热重载
|
||
- 📐 **灵活尺寸** - 支持 16:9 和 4:3 两种宽高比
|
||
- 🔧 **模块化架构** - 易于扩展和维护
|
||
|
||
## 🚀 快速开始
|
||
|
||
### 安装
|
||
|
||
本工具使用 [uv](https://github.com/astral-sh/uv) 管理依赖。项目依赖在 pyproject.toml 中声明,运行时会自动安装所需的 Python 包。
|
||
|
||
### 基本用法
|
||
|
||
```bash
|
||
# 转换 YAML 为 PPTX
|
||
uv run yaml2pptx.py convert presentation.yaml output.pptx
|
||
|
||
# 自动生成输出文件名
|
||
uv run yaml2pptx.py convert presentation.yaml
|
||
|
||
# 使用模板
|
||
uv run yaml2pptx.py convert presentation.yaml output.pptx --template-dir ./templates
|
||
```
|
||
|
||
### 实时预览
|
||
|
||
```bash
|
||
# 启动预览服务器(自动打开浏览器)
|
||
uv run yaml2pptx.py preview presentation.yaml
|
||
|
||
# 指定端口
|
||
uv run yaml2pptx.py preview presentation.yaml --port 8080
|
||
|
||
# 允许局域网访问
|
||
uv run yaml2pptx.py preview presentation.yaml --host 0.0.0.0
|
||
|
||
# 不自动打开浏览器
|
||
uv run yaml2pptx.py preview presentation.yaml --no-browser
|
||
```
|
||
|
||
预览模式会自动监听文件变化,修改 YAML 文件后浏览器会自动刷新。
|
||
|
||
### 验证功能
|
||
|
||
在转换前验证 YAML 文件,提前发现问题:
|
||
|
||
```bash
|
||
# 独立验证命令
|
||
uv run yaml2pptx.py check presentation.yaml
|
||
|
||
# 使用模板时验证
|
||
uv run yaml2pptx.py check presentation.yaml --template-dir ./templates
|
||
```
|
||
|
||
验证功能会检查:
|
||
- ✅ YAML 语法和结构
|
||
- ✅ 元素是否超出页面范围
|
||
- ✅ 图片和模板文件是否存在
|
||
- ✅ 颜色格式是否正确
|
||
- ✅ 字体大小是否合理
|
||
- ✅ 表格数据是否一致
|
||
|
||
**自动验证**:转换时默认会自动验证,如果发现错误会终止转换。可以使用 `--skip-validation` 跳过验证:
|
||
|
||
```bash
|
||
# 跳过自动验证
|
||
uv run yaml2pptx.py convert presentation.yaml --skip-validation
|
||
```
|
||
|
||
**验证结果示例**:
|
||
|
||
```
|
||
🔍 正在检查 YAML 文件...
|
||
|
||
❌ 错误 (2):
|
||
[幻灯片 2, 元素 1] 无效的颜色格式: red (应为 #RRGGBB)
|
||
[幻灯片 3, 元素 2] 图片文件不存在: logo.png
|
||
|
||
⚠️ 警告 (1):
|
||
[幻灯片 1, 元素 1] 元素右边界超出: 10.50 > 10
|
||
|
||
检查完成: 发现 2 个错误, 1 个警告
|
||
```
|
||
|
||
- **ERROR**:阻止转换的严重问题(文件不存在、语法错误等)
|
||
- **WARNING**:影响视觉效果的问题(元素超出页面、字体太小等)
|
||
- **INFO**:优化建议
|
||
|
||
## 📖 YAML 语法
|
||
|
||
### 最小示例
|
||
|
||
```yaml
|
||
metadata:
|
||
size: "16:9" # 或 "4:3"
|
||
|
||
slides:
|
||
- background:
|
||
color: "#ffffff"
|
||
elements:
|
||
- type: text
|
||
box: [1, 1, 8, 1]
|
||
content: "Hello, World!"
|
||
font:
|
||
size: 44
|
||
bold: true
|
||
color: "#333333"
|
||
align: center
|
||
```
|
||
|
||
### 使用模板
|
||
|
||
```yaml
|
||
metadata:
|
||
size: "16:9"
|
||
|
||
slides:
|
||
- template: title-slide
|
||
vars:
|
||
title: "我的演示文稿"
|
||
subtitle: "使用 yaml2pptx 创建"
|
||
author: "张三"
|
||
|
||
- template: content-slide
|
||
vars:
|
||
title: "功能概览"
|
||
content: "yaml2pptx 支持多种元素类型..."
|
||
```
|
||
|
||
## 🎨 元素类型
|
||
|
||
### 文本元素
|
||
|
||
```yaml
|
||
- type: text
|
||
box: [x, y, width, height] # 位置和尺寸(英寸)
|
||
content: "文本内容"
|
||
font:
|
||
size: 18 # 字号(磅)
|
||
bold: true # 粗体
|
||
italic: false # 斜体
|
||
color: "#ff0000" # 颜色
|
||
align: center # left/center/right
|
||
```
|
||
|
||
**特性**:文本框默认启用自动换行,文字超出宽度时会自动换行。
|
||
|
||
### 图片元素
|
||
|
||
```yaml
|
||
- type: image
|
||
box: [x, y, width, height]
|
||
src: "path/to/image.png" # 支持相对路径和绝对路径
|
||
```
|
||
|
||
### 形状元素
|
||
|
||
```yaml
|
||
- type: shape
|
||
box: [x, y, width, height]
|
||
shape: rectangle # rectangle/ellipse/rounded_rectangle
|
||
fill: "#4a90e2" # 填充颜色
|
||
line:
|
||
color: "#000000" # 边框颜色
|
||
width: 2 # 边框宽度(磅)
|
||
```
|
||
|
||
### 表格元素
|
||
|
||
```yaml
|
||
- type: table
|
||
position: [x, y]
|
||
col_widths: [2, 2, 2] # 每列宽度(英寸)
|
||
data:
|
||
- ["表头1", "表头2", "表头3"]
|
||
- ["数据1", "数据2", "数据3"]
|
||
- ["数据4", "数据5", "数据6"]
|
||
style:
|
||
font_size: 14
|
||
header_bg: "#4a90e2"
|
||
header_color: "#ffffff"
|
||
```
|
||
|
||
## 📋 模板系统
|
||
|
||
模板允许你定义可复用的幻灯片布局。yaml2pptx 支持两种模板方式:
|
||
|
||
- **外部模板**:独立的 YAML 文件,适合跨文档复用
|
||
- **内联模板**:在源文件中定义,适合单文档使用
|
||
|
||
### 内联模板
|
||
|
||
内联模板允许你在 YAML 源文件中直接定义模板,无需创建单独的模板文件。
|
||
|
||
#### 定义内联模板
|
||
|
||
在 YAML 文件顶层添加 `templates` 字段:
|
||
|
||
```yaml
|
||
metadata:
|
||
size: "16:9"
|
||
|
||
templates:
|
||
title-slide:
|
||
vars:
|
||
- name: title
|
||
required: true
|
||
- name: subtitle
|
||
required: false
|
||
default: ""
|
||
elements:
|
||
- type: text
|
||
box: [1, 2, 8, 1]
|
||
content: "{title}"
|
||
font:
|
||
size: 44
|
||
bold: true
|
||
align: center
|
||
- type: text
|
||
box: [1, 3.5, 8, 0.5]
|
||
content: "{subtitle}"
|
||
visible: "{subtitle != ''}"
|
||
font:
|
||
size: 24
|
||
align: center
|
||
|
||
slides:
|
||
- template: title-slide
|
||
vars:
|
||
title: "我的演示文稿"
|
||
subtitle: "使用内联模板"
|
||
```
|
||
|
||
#### 内联模板特性
|
||
|
||
- ✅ 支持变量替换和条件渲染
|
||
- ✅ 可以与外部模板混合使用
|
||
- ✅ 无需指定 `--template-dir` 参数
|
||
- ⚠️ 内联模板不能相互引用
|
||
- ⚠️ 内联和外部模板不能同名(会报错)
|
||
|
||
#### 何时使用内联模板
|
||
|
||
**适合使用内联模板**:
|
||
- 模板仅在单个文档中使用
|
||
- 快速原型开发
|
||
- 简单的模板定义(1-3 个元素)
|
||
- 文档自包含,无需外部依赖
|
||
|
||
**适合使用外部模板**:
|
||
- 需要跨多个文档复用
|
||
- 复杂的模板定义(>5 个元素)
|
||
- 团队共享的模板库
|
||
- 需要版本控制和独立维护
|
||
|
||
**最佳实践**:
|
||
|
||
1. **命名规范**:
|
||
- 内联模板使用描述性名称(如 `title-slide`, `content-slide`)
|
||
- 避免与外部模板同名,否则会报错
|
||
- 使用一致的命名风格(kebab-case 推荐)
|
||
|
||
2. **模板大小**:
|
||
- 内联模板建议不超过 50 行
|
||
- 超过 50 行考虑拆分或使用外部模板
|
||
- 保持 YAML 文件可读性
|
||
|
||
3. **混合使用**:
|
||
- 可以在同一文档中混合使用内联和外部模板
|
||
- 通用模板使用外部模板(如标题页、结束页)
|
||
- 文档特定模板使用内联模板
|
||
|
||
4. **迁移策略**:
|
||
- 原型阶段使用内联模板快速迭代
|
||
- 模板稳定后,如需复用则迁移到外部模板
|
||
- 使用 `--template-dir` 参数指定外部模板目录
|
||
|
||
#### 内联模板限制
|
||
|
||
- ⚠️ 内联模板不能相互引用(会报错)
|
||
- ⚠️ 内联和外部模板不能同名(会报错)
|
||
- ⚠️ 内联模板不支持继承或组合
|
||
|
||
### 创建外部模板
|
||
|
||
创建模板文件 `templates/title-slide.yaml`:
|
||
|
||
```yaml
|
||
vars:
|
||
- name: title
|
||
required: true
|
||
- name: subtitle
|
||
required: false
|
||
default: ""
|
||
- name: author
|
||
required: false
|
||
default: ""
|
||
|
||
elements:
|
||
- type: text
|
||
box: [1, 2, 8, 1]
|
||
content: "{title}"
|
||
font:
|
||
size: 44
|
||
bold: true
|
||
align: center
|
||
|
||
- type: text
|
||
box: [1, 3.5, 8, 0.5]
|
||
content: "{subtitle}"
|
||
visible: "{subtitle != ''}" # 条件渲染
|
||
font:
|
||
size: 24
|
||
align: center
|
||
|
||
- type: text
|
||
box: [1, 5, 8, 0.5]
|
||
content: "{author}"
|
||
font:
|
||
size: 18
|
||
align: center
|
||
```
|
||
|
||
### 使用外部模板
|
||
|
||
```yaml
|
||
slides:
|
||
- template: title-slide
|
||
vars:
|
||
title: "我的演示文稿"
|
||
subtitle: "副标题"
|
||
author: "作者"
|
||
```
|
||
|
||
### 条件渲染
|
||
|
||
#### 元素级条件渲染
|
||
|
||
使用 `visible` 属性控制元素显示:
|
||
|
||
```yaml
|
||
- type: text
|
||
content: "{subtitle}"
|
||
visible: "{subtitle != ''}" # 仅当 subtitle 不为空时显示
|
||
```
|
||
|
||
#### 页面级启用控制
|
||
|
||
使用 `enabled` 参数控制整个幻灯片是否渲染:
|
||
|
||
```yaml
|
||
slides:
|
||
# 正常渲染的幻灯片
|
||
- template: title-slide
|
||
vars:
|
||
title: "主标题"
|
||
|
||
# 临时禁用的幻灯片(开发调试)
|
||
- enabled: false
|
||
template: work-in-progress
|
||
vars:
|
||
title: "未完成的内容"
|
||
|
||
# 继续渲染后续幻灯片
|
||
- template: content-slide
|
||
vars:
|
||
title: "内容页"
|
||
```
|
||
|
||
**enabled 参数说明**:
|
||
- 类型:布尔值(`true` 或 `false`)
|
||
- 默认值:`true`(未指定时默认启用)
|
||
- 用途:临时禁用幻灯片,无需删除或注释 YAML 内容
|
||
- 场景:开发调试、版本控制、A/B 测试
|
||
|
||
**enabled vs visible 的区别**:
|
||
|
||
| 特性 | `enabled`(页面级) | `visible`(元素级) |
|
||
|------|-------------------|-------------------|
|
||
| 作用范围 | 整个幻灯片 | 单个元素 |
|
||
| 类型 | 布尔值 | 条件表达式 |
|
||
| 判断时机 | 加载时(静态) | 渲染时(动态) |
|
||
| 使用场景 | 临时禁用页面 | 条件显示元素 |
|
||
|
||
**示例**:
|
||
|
||
```yaml
|
||
slides:
|
||
# 页面启用,但副标题元素可能隐藏
|
||
- enabled: true
|
||
template: title-slide
|
||
vars:
|
||
title: "标题"
|
||
subtitle: "" # 空字符串,元素级 visible 会隐藏副标题
|
||
|
||
# 整页禁用,不渲染
|
||
- enabled: false
|
||
elements:
|
||
- type: text
|
||
content: "这一页不会出现在最终 PPTX 中"
|
||
box: [1, 1, 8, 1]
|
||
font: {size: 44}
|
||
```
|
||
|
||
## 🎯 命令行选项
|
||
|
||
### check 命令
|
||
|
||
验证 YAML 文件的正确性。
|
||
|
||
| 选项 | 说明 |
|
||
|------|------|
|
||
| `input` | 输入的 YAML 文件路径(必需) |
|
||
| `--template-dir` | 模板文件目录 |
|
||
|
||
### convert 命令
|
||
|
||
将 YAML 文件转换为 PPTX 文件。
|
||
|
||
| 选项 | 说明 |
|
||
|------|------|
|
||
| `input` | 输入的 YAML 文件路径(必需) |
|
||
| `output` | 输出的 PPTX 文件路径(可选) |
|
||
| `--template-dir` | 模板文件目录 |
|
||
| `--skip-validation` | 跳过自动验证 |
|
||
| `--force` / `-f` | 强制覆盖已存在文件 |
|
||
|
||
### preview 命令
|
||
|
||
启动预览服务器,实时查看演示文稿效果。
|
||
|
||
| 选项 | 说明 |
|
||
|------|------|
|
||
| `input` | 输入的 YAML 文件路径(必需) |
|
||
| `--template-dir` | 模板文件目录 |
|
||
| `--port` | 服务器端口(默认:随机端口 30000-40000) |
|
||
| `--host` | 主机地址(默认:127.0.0.1) |
|
||
| `--no-browser` | 不自动打开浏览器 |
|
||
|
||
## 📐 坐标系统
|
||
|
||
- **单位**:英寸 (inch)
|
||
- **原点**:幻灯片左上角 (0, 0)
|
||
- **方向**:X 轴向右,Y 轴向下
|
||
|
||
**幻灯片尺寸**:
|
||
- 16:9 → 10" × 5.625"
|
||
- 4:3 → 10" × 7.5"
|
||
|
||
**示例**:`box: [1, 2, 8, 1]` 表示:
|
||
- 左上角位置:(1", 2")
|
||
- 尺寸:宽 8",高 1"
|
||
|
||
## 🎨 颜色格式
|
||
|
||
支持两种十六进制格式:
|
||
- **短格式**:`#RGB`(如 `#fff` = 白色)
|
||
- **完整格式**:`#RRGGBB`(如 `#ffffff` = 白色)
|
||
|
||
## 💡 使用技巧
|
||
|
||
1. **开发流程**:使用 `--preview` 模式实时查看效果,确认无误后再生成 PPTX
|
||
2. **模板复用**:为常用布局创建模板,保持演示文稿风格一致
|
||
3. **相对路径**:图片路径相对于 YAML 文件位置,便于项目管理
|
||
4. **模板目录**:使用模板时必须指定 `--template-dir` 参数
|
||
5. **文本换行**:文本框默认启用自动换行,无需手动处理长文本
|
||
|
||
## 📚 完整示例
|
||
|
||
查看 `temp/` 目录下的示例文件:
|
||
- `temp/test_refactor.yaml` - 基本示例
|
||
- `temp/template_demo.yaml` - 模板使用示例
|
||
- `temp/complex_presentation.yaml` - 复杂演示文稿示例
|
||
|
||
## ⚠️ 常见错误
|
||
|
||
| 错误信息 | 原因 | 解决方法 |
|
||
|---------|------|---------|
|
||
| `文件不存在: xxx.yaml` | 找不到输入文件 | 检查文件路径是否正确 |
|
||
| `YAML 语法错误: 第 X 行` | YAML 格式错误 | 检查缩进和语法 |
|
||
| `模板文件不存在: xxx` | 模板文件未找到 | 检查模板名称和 `--template-dir` |
|
||
| `缺少必需变量: xxx` | 未提供必需的模板变量 | 在 `vars` 中提供该变量 |
|
||
| `图片文件未找到: xxx` | 图片文件不存在 | 检查图片路径 |
|
||
|
||
## 🔧 扩展性
|
||
|
||
yaml2pptx 采用模块化架构,易于扩展:
|
||
|
||
- **添加新元素类型**:定义新的元素数据类和渲染方法
|
||
- **添加新渲染器**:支持输出到其他格式(如 PDF)
|
||
- **自定义模板**:创建符合你需求的模板库
|
||
|
||
详见 [开发文档](README_DEV.md)。
|
||
|
||
## 📦 依赖项
|
||
|
||
- `python-pptx` - PowerPoint 文件生成
|
||
- `pyyaml` - YAML 解析
|
||
- `flask` - 预览服务器
|
||
- `watchdog` - 文件监听
|
||
|
||
依赖在 pyproject.toml 中声明,由 uv 自动管理,无需手动安装。
|
||
|
||
## 🧪 测试
|
||
|
||
项目包含完整的测试套件,使用 pytest 框架。
|
||
|
||
### 运行测试
|
||
|
||
```bash
|
||
# 安装测试依赖
|
||
uv pip install -e ".[dev]"
|
||
|
||
# 运行所有测试
|
||
uv run pytest
|
||
|
||
# 运行特定类型的测试
|
||
uv run pytest tests/unit/ # 单元测试
|
||
uv run pytest tests/integration/ # 集成测试
|
||
uv run pytest tests/e2e/ # 端到端测试
|
||
|
||
# 运行特定测试文件
|
||
uv run pytest tests/unit/test_elements.py
|
||
|
||
# 显示详细输出
|
||
uv run pytest -v
|
||
|
||
# 显示测试覆盖率
|
||
uv run pytest --cov=. --cov-report=html
|
||
```
|
||
|
||
### 测试结构
|
||
|
||
```
|
||
tests/
|
||
├── unit/ # 单元测试 - 测试各模块独立功能
|
||
├── integration/ # 集成测试 - 测试模块间协作
|
||
├── e2e/ # 端到端测试 - 测试完整用户场景
|
||
└── fixtures/ # 测试数据
|
||
```
|
||
|
||
## 🤝 贡献
|
||
|
||
欢迎贡献代码、报告问题或提出建议!
|
||
|
||
开发者请参阅 [开发文档](README_DEV.md) 了解代码结构和开发规范。
|
||
|
||
## 📄 许可证
|
||
|
||
MIT License
|