1
0
Files
PPTX/openspec/specs/element-rendering/spec.md
lanyuanxiaoyao ed940f0690 refactor: modularize yaml2pptx into layered architecture
Refactor yaml2pptx.py from a 1,245-line monolithic script into a modular
architecture with clear separation of concerns. The entry point is now
127 lines, with business logic distributed across focused modules.

Architecture:
- core/: Domain models (elements, template, presentation)
- loaders/: YAML loading and validation
- renderers/: PPTX and HTML rendering
- preview/: Flask preview server
- utils.py: Shared utilities

Key improvements:
- Element abstraction layer using dataclass with validation
- Renderer logic built into generator classes
- Single-direction dependencies (no circular imports)
- Each module 150-300 lines for better readability
- Backward compatible CLI interface

Documentation:
- README.md: User-facing usage guide
- README_DEV.md: Developer documentation

OpenSpec:
- Archive refactor-yaml2pptx-modular change (63/70 tasks complete)
- Sync 5 delta specs to main specs (2 new + 3 updated)
2026-03-02 16:43:45 +08:00

237 lines
8.5 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Element Rendering
## Purpose
Element rendering系统负责将 YAML 中定义的各类元素(文本、图片、形状、表格)转换为 PPTX 文档中的实际对象。它处理元素的定位、样式应用、层次管理,以及幻灯片背景设置。
## Requirements
### Requirement: 系统必须支持文本元素渲染
系统 SHALL 将 YAML 中定义的文本元素渲染为 PPTX 文本框,并默认启用文字自动换行。
#### Scenario: 渲染基本文本元素
- **WHEN** 元素定义为 `{type: text, content: "Hello", box: [1, 2, 8, 3]}`
- **THEN** 系统在幻灯片的 (1, 2) 位置创建 8×3 英寸的文本框,内容为 "Hello"
#### Scenario: 应用文本字体样式
- **WHEN** 文本元素定义了 `font: {size: 32, bold: true, color: "#333333"}`
- **THEN** 系统将文本设置为 32pt、粗体、颜色为 #333333
#### Scenario: 应用文本对齐方式
- **WHEN** 文本元素定义了 `font: {align: center}`
- **THEN** 系统将文本设置为居中对齐
#### Scenario: 支持多种对齐方式
- **WHEN** 文本对齐方式为 `left``center``right` 之一
- **THEN** 系统正确应用对应的对齐方式
#### Scenario: 文本框默认启用自动换行
- **WHEN** 系统渲染任何文本元素
- **THEN** 系统设置 `text_frame.word_wrap = True`,文字在文本框边界处自动换行
### Requirement: 系统必须支持图片元素渲染
系统 SHALL 将 YAML 中定义的图片元素渲染为 PPTX 图片对象。
#### Scenario: 渲染本地图片
- **WHEN** 元素定义为 `{type: image, src: "images/logo.png", box: [2, 3, 4, 3]}`
- **THEN** 系统从指定路径加载图片,在 (2, 3) 位置渲染为 4×3 英寸大小
#### Scenario: 图片文件不存在时报错
- **WHEN** 图片 src 指向不存在的文件路径
- **THEN** 系统抛出错误,明确指出图片文件未找到
#### Scenario: 图片格式不支持时报错
- **WHEN** 图片文件格式不被 python-pptx 支持
- **THEN** 系统抛出错误,提示图片格式不支持,并列出支持的格式
#### Scenario: 相对路径处理
- **WHEN** 图片 src 使用相对路径 `"assets/images/logo.png"`
- **THEN** 系统基于演示文稿文件所在目录解析相对路径
### Requirement: 系统必须支持形状元素渲染
系统 SHALL 将 YAML 中定义的形状元素渲染为 PPTX 形状对象。
#### Scenario: 渲染矩形形状
- **WHEN** 元素定义为 `{type: shape, shape: rectangle, box: [1, 2, 3, 1], fill: "#4a90e2"}`
- **THEN** 系统在 (1, 2) 位置创建 3×1 英寸的矩形,填充颜色为 #4a90e2
#### Scenario: 渲染圆形形状
- **WHEN** 元素的 `shape` 字段为 `ellipse`
- **THEN** 系统渲染椭圆/圆形形状
#### Scenario: 渲染圆角矩形
- **WHEN** 元素的 `shape` 字段为 `rounded_rectangle`
- **THEN** 系统渲染圆角矩形形状
#### Scenario: 应用形状边框样式
- **WHEN** 形状定义了 `line: {color: "#000000", width: 2}`
- **THEN** 系统为形状添加黑色、2pt 宽度的边框
### Requirement: 系统必须支持表格元素渲染
系统 SHALL 将 YAML 中定义的表格元素渲染为 PPTX 表格对象。
#### Scenario: 渲染基本表格
- **WHEN** 元素定义为 `{type: table, position: [1, 2], data: [["A", "B"], ["C", "D"]], col_widths: [2, 2]}`
- **THEN** 系统在 (1, 2) 位置创建 2×2 表格,列宽各为 2 英寸
#### Scenario: 应用表格样式
- **WHEN** 表格定义了 `style: {font_size: 14, header_bg: "#4a90e2", header_color: "#ffffff"}`
- **THEN** 系统将第一行设置为表头样式,背景色为 #4a90e2,文字颜色为白色
#### Scenario: 表格数据为空时报错
- **WHEN** 表格的 `data` 字段为空数组
- **THEN** 系统抛出错误,提示表格数据不能为空
#### Scenario: 表格列宽不匹配时报错
- **WHEN** `col_widths` 数组长度与表格列数不一致
- **THEN** 系统抛出错误,要求列宽数量与列数匹配
### Requirement: 元素位置必须使用英寸单位
系统 SHALL 将元素的 box 或 position 字段中的数值解释为英寸单位。
#### Scenario: box 数组表示位置和尺寸
- **WHEN** 元素定义了 `box: [1, 2, 8, 3]`
- **THEN** 系统将其解释为 x=1英寸, y=2英寸, width=8英寸, height=3英寸
#### Scenario: position 数组表示位置
- **WHEN** 表格元素定义了 `position: [1, 2]`
- **THEN** 系统将其解释为 x=1英寸, y=2英寸
#### Scenario: 负数坐标值报错
- **WHEN** box 或 position 包含负数值
- **THEN** 系统抛出错误,要求坐标值必须为非负数
### Requirement: 系统必须支持幻灯片背景设置
系统 SHALL 支持为幻灯片设置纯色背景或图片背景。
#### Scenario: 设置纯色背景
- **WHEN** 幻灯片定义了 `background: {color: "#ffffff"}`
- **THEN** 系统将幻灯片背景设置为白色
#### Scenario: 设置图片背景
- **WHEN** 幻灯片定义了 `background: {image: "bg.png"}`
- **THEN** 系统使用指定图片作为幻灯片背景
#### Scenario: 背景图片不存在时报错
- **WHEN** 背景图片路径不存在
- **THEN** 系统抛出错误,提示背景图片文件未找到
### Requirement: 系统必须处理元素重叠和层次
系统 SHALL 按照元素在 elements 列表中的顺序渲染,后定义的元素显示在前面元素之上。
#### Scenario: 元素按定义顺序渲染
- **WHEN** elements 列表为 `[shape1, text1, image1]`
- **THEN** 系统先渲染 shape1再渲染 text1最后渲染 image1image1 在最上层)
#### Scenario: 重叠元素的显示层次
- **WHEN** 两个元素的位置有重叠
- **THEN** 后定义的元素遮盖先定义的元素
### Requirement: 系统必须使用元素数据类进行渲染
系统 SHALL 使用元素数据类TextElement, ImageElement, ShapeElement, TableElement进行渲染而不是直接处理字典数据。渲染器接收元素对象通过类型检查分发到对应的渲染方法。
#### Scenario: 渲染器接收元素对象
- **WHEN** 渲染器的 `_render_element()` 方法被调用
- **THEN** 系统应接收元素对象(如 TextElement 实例),而不是字典
#### Scenario: 通过类型检查分发渲染
- **WHEN** 渲染器处理元素对象
- **THEN** 系统应使用 `isinstance()` 检查元素类型,分发到对应的渲染方法(如 `_render_text()`, `_render_image()`
#### Scenario: 元素验证在创建时完成
- **WHEN** 元素对象被创建
- **THEN** 系统应在 `__post_init__` 方法中完成验证,渲染时不再需要验证
### Requirement: 渲染器必须内置在生成器中
系统 SHALL 将渲染逻辑内置在 PptxGenerator 类中,作为私有方法(`_render_text()`, `_render_image()` 等),而不是独立的函数。
#### Scenario: 渲染方法作为生成器的私有方法
- **WHEN** 开发者查看 PptxGenerator 类
- **THEN** 应包含 `_render_text()`, `_render_image()`, `_render_shape()`, `_render_table()` 等私有方法
#### Scenario: 渲染方法接收元素对象
- **WHEN** 调用 `_render_text(slide, elem)` 方法
- **THEN** `elem` 参数应为 TextElement 对象,包含 content、box、font 等属性
### Requirement: 元素渲染必须支持元素对象的属性访问
系统 SHALL 通过元素对象的属性(如 `elem.content`, `elem.box`, `elem.font`)访问数据,而不是通过字典的 `get()` 方法。
#### Scenario: 访问文本元素的属性
- **WHEN** 渲染文本元素
- **THEN** 系统应使用 `elem.content` 而不是 `elem.get('content', '')`
#### Scenario: 访问图片元素的属性
- **WHEN** 渲染图片元素
- **THEN** 系统应使用 `elem.src``elem.box` 而不是 `elem.get('src')``elem.get('box')`
#### Scenario: 访问形状元素的属性
- **WHEN** 渲染形状元素
- **THEN** 系统应使用 `elem.shape`, `elem.fill`, `elem.line` 等属性
#### Scenario: 访问表格元素的属性
- **WHEN** 渲染表格元素
- **THEN** 系统应使用 `elem.data`, `elem.position`, `elem.col_widths`, `elem.style` 等属性
### Requirement: 系统必须验证元素类型
系统 SHALL 验证每个元素的 type 字段,仅支持已定义的元素类型。
#### Scenario: 支持的元素类型
- **WHEN** 元素的 `type``text``image``shape``table` 之一
- **THEN** 系统正常渲染该元素
#### Scenario: 不支持的元素类型报错
- **WHEN** 元素的 `type` 为未定义的值(如 "video"
- **THEN** 系统抛出错误,提示不支持该元素类型,并列出支持的类型
#### Scenario: 缺少 type 字段报错
- **WHEN** 元素未定义 `type` 字段
- **THEN** 系统抛出错误,要求每个元素必须包含 type 字段