1
0
Files
PPTX/openspec/specs/html-rendering/spec.md
lanyuanxiaoyao f34405be36 feat: 移除图片适配模式功能
移除图片 fit 和 background 参数支持,简化图片渲染逻辑。系统恢复到直接使用 python-pptx 原生图片添加功能,图片将被拉伸到指定尺寸。

变更内容:
- 移除 ImageElement 的 fit 和 background 字段
- 移除 metadata.dpi 配置
- 删除 utils/image_utils.py 图片处理工具模块
- 删除 validators/image_config.py 验证器
- 简化 PPTX 和 HTML 渲染器的图片处理逻辑
- HTML 渲染器使用硬编码 DPI=96(Web 标准)
- 删除相关测试文件(单元测试、集成测试、e2e 测试)
- 更新规格文档和用户文档
- 保留 Pillow 依赖用于未来可能的图片处理需求

影响:
- 删除 11 个文件
- 修改 10 个文件
- 净减少 1558 行代码
- 所有 402 个测试通过

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2026-03-04 14:23:12 +08:00

12 KiB
Raw Blame History

HTML Rendering

Purpose

HTML Rendering 系统负责将 YAML 中定义的各类元素(文本、图片、形状、表格)转换为 HTML/CSS 代码,在浏览器中显示。它复用现有的 YAML 解析和模板渲染逻辑,但将输出目标从 PPTX 改为 HTML/CSS提供快速的预览体验。

Requirements

Requirement: 系统必须将 YAML 元素转换为 HTML

系统 SHALL 将解析后的 YAML 元素转换为 HTML 代码,在浏览器中渲染。

Scenario: 生成完整的 HTML 页面

  • WHEN 浏览器请求预览页面
  • THEN 系统生成包含 HTML、CSS 和 JavaScript 的完整页面

Scenario: 动态生成 HTML

  • WHEN YAML 文件变化
  • THEN 系统重新解析 YAML动态生成新的 HTML 内容,无需生成中间文件

Scenario: HTML 页面包含 SSE 客户端代码

  • WHEN 生成 HTML 页面
  • THEN 页面包含 JavaScript 代码,连接到 SSE 端点,监听更新事件

Requirement: 系统必须使用固定 DPI 进行单位转换

系统 SHALL 使用固定 DPI (96) 将 YAML 中的英寸单位转换为 CSS 像素单位。

Scenario: 英寸转换为像素

  • WHEN 元素定义 box: [1, 2, 8, 3](单位为英寸)
  • THEN 系统转换为 CSSleft: 96px; top: 192px; width: 768px; height: 288px

Scenario: 幻灯片尺寸固定

  • WHEN 渲染 16:9 幻灯片
  • THEN 系统使用固定尺寸 960x540 像素10 英寸 x 5.625 英寸 x 96 DPI

Scenario: 4:3 幻灯片尺寸

  • WHEN 渲染 4:3 幻灯片
  • THEN 系统使用固定尺寸 960x720 像素10 英寸 x 7.5 英寸 x 96 DPI

Requirement: 系统必须渲染文本元素

系统 SHALL 将 YAML 中的文本元素转换为 HTML <div> 标签,应用相应的样式,并默认启用文字自动换行。

Scenario: 渲染基本文本元素

  • WHEN 元素定义为 {type: text, content: "Hello", box: [1, 2, 8, 3]}
  • THEN 系统生成 <div> 标签,内容为 "Hello",位置为 (96px, 192px),尺寸为 768x288 像素

Scenario: 应用文本字体样式

  • WHEN 文本元素定义了 font: {size: 32, bold: true, color: "#333333"}
  • THEN 系统应用 CSSfont-size: 32pt; font-weight: bold; color: #333333

Scenario: 应用文本对齐方式

  • WHEN 文本元素定义了 font: {align: center}
  • THEN 系统应用 CSStext-align: center

Scenario: 支持多行文本(保留换行符)

  • WHEN 文本内容包含换行符(\n
  • THEN 系统使用 white-space: pre-wrap 保留换行符

Scenario: 文本元素默认启用自动换行

  • WHEN 系统渲染任何文本元素
  • THEN 系统应用 CSSwhite-space: normal,允许文字在容器边界处自动换行

Scenario: 使用 pt 单位表示字体大小

  • WHEN 文本字体大小为 44
  • THEN 系统使用 CSSfont-size: 44pt(与 PPTX 保持一致)

Requirement: 系统必须渲染形状元素

系统 SHALL 将 YAML 中的形状元素转换为 HTML <div> 标签,使用 CSS 样式模拟形状。

Scenario: 渲染矩形形状

  • WHEN 元素定义为 {type: shape, shape: rectangle, box: [1, 2, 3, 1], fill: "#4a90e2"}
  • THEN 系统生成 <div> 标签,背景色为 #4a90e2border-radius: 0

Scenario: 渲染圆形形状

  • WHEN 元素的 shape 字段为 ellipse
  • THEN 系统应用 CSSborder-radius: 50%

Scenario: 渲染圆角矩形

  • WHEN 元素的 shape 字段为 rounded_rectangle
  • THEN 系统应用 CSSborder-radius: 8px

Scenario: 应用形状边框样式

  • WHEN 形状定义了 line: {color: "#000000", width: 2}
  • THEN 系统应用 CSSborder: 2pt solid #000000

Scenario: 形状无填充色时透明

  • WHEN 形状未定义 fill 字段
  • THEN 系统应用 CSSbackground: transparent

Requirement: 系统必须渲染表格元素

系统 SHALL 将 YAML 中的表格元素转换为 HTML <table> 标签。

Scenario: 渲染基本表格

  • WHEN 元素定义为 {type: table, position: [1, 2], data: [["A", "B"], ["C", "D"]], col_widths: [2, 2]}
  • THEN 系统生成 <table> 标签,位置为 (96px, 192px),包含 2 行 2 列

Scenario: 应用表格样式

  • WHEN 表格定义了 style: {font_size: 14, header_bg: "#4a90e2", header_color: "#ffffff"}
  • THEN 系统将第一行设置为表头样式,背景色为 #4a90e2文字颜色为白色字体大小为 14pt

Scenario: 表格单元格边框

  • WHEN 渲染表格
  • THEN 系统为所有单元格添加边框:border: 1px solid #ddd

Scenario: 表格单元格内边距

  • WHEN 渲染表格
  • THEN 系统为所有单元格添加内边距:padding: 8px

Requirement: 系统必须渲染图片元素

系统 SHALL 将 YAML 中的图片元素转换为 HTML <img> 标签,使用固定 DPI 进行尺寸转换。

Scenario: 渲染本地图片

  • WHEN 元素定义为 {type: image, src: "images/logo.png", box: [2, 3, 4, 3]}
  • THEN 系统生成 <img> 标签src 为图片的文件路径,位置为 (192px, 288px),尺寸为 384x288 像素

Scenario: 处理相对路径

  • WHEN 图片 src 使用相对路径 "assets/logo.png"
  • THEN 系统基于 YAML 文件所在目录解析相对路径

Scenario: 图片不存在时显示占位符

  • WHEN 图片文件不存在
  • THEN 系统显示占位符或错误提示,而不是崩溃

Requirement: 图片元素的 box 参数必须存在

系统 SHALL 要求图片元素必须包含 box 参数,否则验证失败。

Scenario: 缺少 box 参数时报错

  • WHEN 图片元素未定义 box 参数
  • THEN 系统抛出 ERROR提示 box 参数为必需

Scenario: box 参数转换为像素

  • WHEN 图片元素定义了 box: [1, 2, 4, 3] 且 DPI 为 96
  • THEN 系统转换为 CSSleft: 96px; top: 192px; width: 384px; height: 288px

Requirement: 系统必须渲染幻灯片背景

系统 SHALL 支持为幻灯片设置纯色背景。

Scenario: 设置纯色背景

  • WHEN 幻灯片定义了 background: {color: "#ffffff"}
  • THEN 系统为幻灯片容器应用 CSSbackground: #ffffff

Scenario: 无背景时使用白色

  • WHEN 幻灯片未定义 background 字段
  • THEN 系统使用默认白色背景

Requirement: 系统必须使用绝对定位

系统 SHALL 使用 CSS 绝对定位(position: absolute)渲染所有元素,模拟 PPTX 的坐标系统。

Scenario: 元素使用绝对定位

  • WHEN 渲染任何元素
  • THEN 系统应用 CSSposition: absolute

Scenario: 幻灯片容器使用相对定位

  • WHEN 渲染幻灯片容器
  • THEN 系统应用 CSSposition: relative,作为元素的定位上下文

Scenario: 元素层次按定义顺序

  • WHEN elements 列表为 [shape1, text1, image1]
  • THEN 系统按顺序渲染,后定义的元素显示在前面元素之上(通过 DOM 顺序控制)

Requirement: 系统必须提供视觉反馈

系统 SHALL 在预览页面中提供视觉反馈,帮助用户了解预览状态。

Scenario: 幻灯片添加阴影效果

  • WHEN 渲染幻灯片
  • THEN 系统为幻灯片容器添加阴影:box-shadow: 0 2px 8px rgba(0,0,0,0.1)

Scenario: 幻灯片之间有间距

  • WHEN 渲染多个幻灯片
  • THEN 每个幻灯片之间有 20px 的垂直间距

Requirement: HTML 渲染必须使用独立的 HtmlRenderer 类

系统 SHALL 将 HTML 渲染逻辑重构为独立的 HtmlRenderer 类,而不是内联函数。

Scenario: HtmlRenderer 类定义在独立模块

  • WHEN 开发者查看项目结构
  • THEN HtmlRenderer 类应定义在 renderers/html_renderer.py 文件中

Scenario: HtmlRenderer 包含渲染方法

  • WHEN 开发者查看 HtmlRenderer 类
  • THEN 应包含 render_slide(), render_text(), render_image(), render_shape(), render_table() 等方法

Scenario: 预览服务器使用 HtmlRenderer

  • WHEN 预览服务器生成 HTML
  • THEN 应创建 HtmlRenderer 实例并调用其渲染方法

Requirement: HTML 渲染必须接收元素对象

系统 SHALL 使 HtmlRenderer 的渲染方法接收元素对象TextElement, ImageElement 等),而不是字典。

Scenario: render_text 接收 TextElement 对象

  • WHEN 调用 renderer.render_text(elem)
  • THEN elem 参数应为 TextElement 对象

Scenario: render_image 接收 ImageElement 对象

  • WHEN 调用 renderer.render_image(elem, base_path)
  • THEN elem 参数应为 ImageElement 对象

Scenario: render_shape 接收 ShapeElement 对象

  • WHEN 调用 renderer.render_shape(elem)
  • THEN elem 参数应为 ShapeElement 对象

Scenario: render_table 接收 TableElement 对象

  • WHEN 调用 renderer.render_table(elem)
  • THEN elem 参数应为 TableElement 对象

Requirement: HTML 渲染必须通过元素属性访问数据

系统 SHALL 通过元素对象的属性(如 elem.content, elem.box)访问数据,而不是通过字典的 get() 方法。

Scenario: 访问文本元素属性

  • WHEN 渲染文本元素
  • THEN 应使用 elem.content, elem.box, elem.font 等属性

Scenario: 访问图片元素属性

  • WHEN 渲染图片元素
  • THEN 应使用 elem.src, elem.box 等属性

Scenario: 访问形状元素属性

  • WHEN 渲染形状元素
  • THEN 应使用 elem.shape, elem.box, elem.fill, elem.line 等属性

Scenario: 访问表格元素属性

  • WHEN 渲染表格元素
  • THEN 应使用 elem.data, elem.position, elem.col_widths, elem.style 等属性

Requirement: HtmlRenderer 必须与 PptxRenderer 共享元素抽象层

系统 SHALL 使 HtmlRenderer 和 PptxRenderer 都基于相同的元素数据类(定义在 core/elements.py确保一致性。

Scenario: 两个渲染器使用相同的元素类型

  • WHEN 开发者查看 HtmlRenderer 和 PptxRenderer
  • THEN 两者都应导入并使用 from core.elements import TextElement, ImageElement, ShapeElement, TableElement

Scenario: 元素验证在创建时完成

  • WHEN 元素对象传递给 HtmlRenderer
  • THEN 元素已经在创建时完成验证HtmlRenderer 不需要再次验证

Scenario: 添加新元素类型时两个渲染器同步更新

  • WHEN 在 core/elements.py 中添加新元素类型(如 VideoElement
  • THEN 需要在 HtmlRenderer 和 PptxRenderer 中都实现对应的渲染方法

Requirement: 系统必须复用现有的解析逻辑

系统 SHALL 复用 yaml2pptx.py 中现有的 Presentation 类和模板渲染逻辑。

Scenario: 使用 Presentation 类解析 YAML

  • WHEN 预览模式启动
  • THEN 系统使用 Presentation 类加载和解析 YAML 文件

Scenario: 使用 render_slide 方法渲染幻灯片

  • WHEN 生成预览 HTML
  • THEN 系统调用 Presentation.render_slide() 方法获取渲染后的幻灯片数据

Scenario: 支持模板系统

  • WHEN YAML 文件使用模板(如 template: title_slide
  • THEN 系统正确解析模板变量,渲染模板元素

Requirement: 系统必须处理渲染错误

系统 SHALL 在元素渲染失败时,显示错误信息,而不是崩溃。

Scenario: 元素类型不支持时显示错误

  • WHEN 元素的 type 为未定义的值(如 "video"
  • THEN 系统在预览页面显示错误信息,提示不支持该元素类型

Scenario: 元素缺少必需字段时显示错误

  • WHEN 元素缺少必需字段(如文本元素缺少 content
  • THEN 系统在预览页面显示错误信息,提示缺少字段

Scenario: 部分元素错误不影响其他元素

  • WHEN 某个元素渲染失败
  • THEN 系统继续渲染其他元素,仅在失败位置显示错误提示