From b2132dc06b4ad3070c3181dd601e3bf21ccac544 Mon Sep 17 00:00:00 2001 From: lanyuanxiaoyao Date: Mon, 2 Mar 2026 15:23:14 +0800 Subject: [PATCH] feat: enable text auto-wrap for text boxes by default - Set text_frame.word_wrap = True in add_text_element() for PPTX - Change CSS from white-space: pre-wrap to normal in HTML preview - Add overflow-wrap: break-word for better word breaking - Update README.md with auto-wrap documentation - Update element-rendering and html-rendering specs - Archive change: 2026-03-02-add-text-auto-wrap --- .gitignore | 3 + README.md | 433 +++++++++++------- .../.openspec.yaml | 2 + .../2026-03-02-add-text-auto-wrap/design.md | 97 ++++ .../2026-03-02-add-text-auto-wrap/proposal.md | 24 + .../specs/element-rendering/spec.md | 32 ++ .../specs/html-rendering/spec.md | 37 ++ .../2026-03-02-add-text-auto-wrap/tasks.md | 22 + openspec/specs/element-rendering/spec.md | 7 +- openspec/specs/html-rendering/spec.md | 11 +- yaml2pptx.py | 5 +- 11 files changed, 500 insertions(+), 173 deletions(-) create mode 100644 openspec/changes/archive/2026-03-02-add-text-auto-wrap/.openspec.yaml create mode 100644 openspec/changes/archive/2026-03-02-add-text-auto-wrap/design.md create mode 100644 openspec/changes/archive/2026-03-02-add-text-auto-wrap/proposal.md create mode 100644 openspec/changes/archive/2026-03-02-add-text-auto-wrap/specs/element-rendering/spec.md create mode 100644 openspec/changes/archive/2026-03-02-add-text-auto-wrap/specs/html-rendering/spec.md create mode 100644 openspec/changes/archive/2026-03-02-add-text-auto-wrap/tasks.md diff --git a/.gitignore b/.gitignore index ea04ad0..0bc82e2 100644 --- a/.gitignore +++ b/.gitignore @@ -262,3 +262,6 @@ pnpm-lock.yaml # !templates/ # !examples/ # !assets/ + + +temp \ No newline at end of file diff --git a/README.md b/README.md index 4bb8ff4..2649252 100644 --- a/README.md +++ b/README.md @@ -1,247 +1,344 @@ -# YAML to PPTX Converter +# yaml2pptx -将 YAML 格式的演示文稿源文件转换为 PPTX 文件,让 AI 也能轻松生成高质量的演示文稿。 +YAML 转 PowerPoint (PPTX) 工具 - 使用 YAML 格式的声明式语法定义演示文稿,并生成 PPTX 文件。 -## 🎯 核心特性 +## 功能特性 -- **人类和 AI 友好**:使用 YAML 格式,简洁可读,易于生成 -- **模板系统**:可复用的幻灯片布局,大幅减少重复配置 -- **核心元素支持**:文本、图片、形状、表格 -- **精确布局控制**:基于英寸单位的精确定位 -- **简洁设计**:颜色和样式直接在模板中定义,无需额外配置 -- **浏览器实时预览**:编辑 YAML 文件时,浏览器自动刷新预览效果 +- **YAML 声明式语法** - 使用简单易读的 YAML 定义演示文稿 +- **模板系统** - 支持参数化模板,复用幻灯片布局 +- **多种元素类型** - 文本、图片、形状、表格 +- **实时预览** - 浏览器预览模式,支持热重载,快速开发迭代 +- **灵活尺寸** - 支持 16:9 和 4:3 两种宽高比 -## 📦 安装和使用 +## 安装 -### 前置要求 +脚本使用 [uv](https://github.com/astral-sh/uv) 管理 Python 依赖。运行时会自动安装所需依赖。 -- Python 3.8+ -- uv(推荐)或 pip +依赖项: +- `python-pptx` - PowerPoint 文件生成 +- `pyyaml` - YAML 解析 +- `flask` - 预览服务器(预览模式需要) +- `watchdog` - 文件监控(预览模式需要) -### 使用方法 +## 基本用法 + +### 生成 PPTX 文件 ```bash -# 生成 PPTX 文件 -uv run yaml2pptx.py input.yaml output.pptx +# 基本用法 - 输出文件自动生成(input.pptx) +uv run yaml2pptx.py presentation.yaml -# 自动生成输出文件名 -uv run yaml2pptx.py input.yaml # 生成 input.pptx +# 指定输出文件名 +uv run yaml2pptx.py presentation.yaml output.pptx -# 浏览器实时预览(新功能) -uv run yaml2pptx.py input.yaml --preview - -# 指定预览端口(默认随机选择 20000-30000 之间的端口) -uv run yaml2pptx.py input.yaml --preview --port 8080 - -# 查看帮助 -uv run yaml2pptx.py --help +# 指定模板目录 +uv run yaml2pptx.py presentation.yaml output.pptx --template-dir ./templates ``` -### 浏览器预览功能 +### 实时预览模式 -使用 `--preview` 参数可以在浏览器中实时预览 YAML 文件的效果: +```bash +# 启动预览服务器(随机端口 20000-30000) +uv run yaml2pptx.py presentation.yaml --preview -- 启动后自动打开浏览器 -- 默认使用 20000-30000 之间的随机端口,避免端口冲突 -- 编辑 YAML 文件后,浏览器自动刷新 -- 支持所有元素类型和模板 -- 按 Ctrl+C 停止预览服务器 +# 指定端口 +uv run yaml2pptx.py presentation.yaml --preview --port 8080 -**注意**:预览效果与最终 PPTX 可能存在细微差异(字体渲染、间距等),建议最终确认时生成 PPTX 文件查看。 +# 指定模板目录 +uv run yaml2pptx.py presentation.yaml --preview --template-dir ./templates +``` -## 📖 快速开始 +预览模式会自动打开浏览器窗口显示演示文稿,修改 YAML 文件时页面会自动刷新。 -### 1. 使用模板创建演示文稿 +## 命令行选项 + +| 选项 | 说明 | +|------|------| +| `input` | 输入的 YAML 文件路径(必需) | +| `output` | 输出的 PPTX 文件路径(可选,默认为 `input.pptx`) | +| `--template-dir` | 模板 YAML 文件所在目录 | +| `--preview` | 启用浏览器预览模式(不生成 PPTX 文件) | +| `--port` | 预览服务器端口(默认:随机 20000-30000) | + +## YAML 结构 + +### 基本演示文稿 ```yaml -# presentation.yaml metadata: - title: "我的演示文稿" - size: "16:9" # 16:9 或 4:3 + size: 16:9 # 或 4:3 -slides: - # 使用标题页模板 - - template: title_slide - vars: - title: "项目汇报" - subtitle: "2026年第一季度" - - # 使用内容页模板 - - template: content_slide - vars: - title: "主要成果" - content: | - • 销售额增长 25% - • 客户满意度 4.8/5.0 - • 新增 3 个市场 -``` - -### 2. 自定义幻灯片 - -```yaml slides: - background: color: "#ffffff" elements: - type: text - content: "自定义标题" - box: [1, 1, 8, 1] # [x, y, width, height] 英寸 + box: [1, 1, 8, 1] + content: "你好,世界!" font: size: 44 bold: true - color: "#1a1a1a" + color: "#333333" align: center - - - type: shape - shape: rectangle - box: [2, 3, 6, 2] - fill: "#4a90e2" ``` -## 📐 模板系统 +### 使用模板 -内置模板: +```yaml +metadata: + size: 16:9 -- `title_slide`:标题页(主标题 + 副标题) -- `content_slide`:内容页(标题条 + 内容区) -- `two_column`:双栏布局 +slides: + - template: title-slide + vars: + title: "我的演示文稿" + subtitle: "yaml2pptx 简介" + author: "张三" -## 🧩 支持的元素类型 + - template: content-slide + vars: + title: "功能概览" + content: "yaml2pptx 支持多种元素类型..." +``` -### 文本元素 +## 元素类型 + +### 文本 ```yaml - type: text - content: "Hello World" - box: [x, y, width, height] + box: [x, y, width, height] # 位置和尺寸(单位:英寸) + content: "文本内容" font: - size: 32 - bold: true - italic: false - color: "#333333" - align: center # left, center, right + size: 18 # 字号(磅) + bold: true/false # 粗体 + italic: true/false # 斜体 + color: "#ff0000" # 颜色(#RGB 或 #RRGGBB) + align: left/center/right # 对齐方式 ``` -### 图片元素 +**文本自动换行**:文本框默认启用自动换行功能。当文字内容超过文本框宽度时,会自动换行显示,确保文字不会溢出边界。 + +### 图片 ```yaml - type: image - src: "images/logo.png" box: [x, y, width, height] + src: "path/to/image.png" # 相对路径或绝对路径 ``` -### 形状元素 +### 形状 ```yaml - type: shape - shape: rectangle # rectangle, ellipse, rounded_rectangle box: [x, y, width, height] - fill: "#4a90e2" + shape: rectangle/ellipse/rounded_rectangle + fill: "#4a90e2" # 填充颜色 line: - color: "#000000" - width: 2 + color: "#000000" # 边框颜色 + width: 1 # 边框宽度(磅) ``` -### 表格元素 +### 表格 ```yaml - type: table - position: [x, y] - col_widths: [2, 2, 2] # 英寸 + position: [x, y] # 表格位置 + col_widths: [2, 2, 2] # 列宽(英寸) data: - - ["Header 1", "Header 2", "Header 3"] - - ["Cell 1", "Cell 2", "Cell 3"] + - ["表头1", "表头2", "表头3"] + - ["行1", "数据", "数据"] + - ["行2", "数据", "数据"] style: font_size: 14 header_bg: "#4a90e2" header_color: "#ffffff" ``` -## 📂 项目结构 +## 模板系统 -``` -project/ -├── templates/ # 模板定义(颜色和样式直接在模板中) -│ ├── title_slide.yaml -│ ├── content_slide.yaml -│ └── two_column.yaml -├── examples/ # 示例文件 -│ ├── demo.yaml -│ ├── custom.yaml -│ └── complex.yaml -├── yaml2pptx.py # 转换脚本 -└── README.md +模板允许你定义可复用的幻灯片布局,支持参数化。 + +### 模板文件 (`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 != ''}" # 仅当 subtitle 不为空时显示 + font: + size: 24 + align: center + + - type: text + box: [1, 5, 8, 0.5] + content: "{author}" + font: + size: 18 + align: center ``` -## 🔧 技术栈 +### 使用模板 -- **Python 3.8+** -- **python-pptx**:PPTX 文件生成 -- **PyYAML**:YAML 文件解析 -- **uv**:Python 脚本运行器 - -## 📝 示例 - -查看 `examples/` 目录中的示例文件: - -- `demo.yaml`:使用模板的完整示例(3页) -- `custom.yaml`:自定义幻灯片示例(2页) -- `complex.yaml`:**复杂综合示例(10页)** - 展示所有功能 - -### 复杂示例亮点 - -`complex.yaml` 是一个完整的商业计划演示文稿,包含: - -✨ **10个精心设计的幻灯片**: -1. 封面页(使用 title_slide 模板) -2. 议程页(自定义布局,包含时间轴) -3. 公司概况(使用 content_slide 模板) -4. 市场分析(使用 two_column 模板) -5. 产品矩阵(复杂表格 + 架构图示) -6. 财务预测(多个表格 + 数据可视化) -7. 团队介绍(使用 two_column 模板) -8. 竞争优势(视觉化卡片 + SWOT 表格) -9. 产品路线图(使用 content_slide 模板) -10. 结束页(自定义召唤行动页) - -🎨 **展示的功能**: -- ✅ 所有三种模板的使用 -- ✅ 模板与自定义幻灯片混合 -- ✅ 所有元素类型:文本、形状、表格 -- ✅ 复杂布局和精确定位 -- ✅ 多种形状类型和样式组合 -- ✅ 丰富的颜色和字体样式(直接指定) -- ✅ 大量中文内容展示 -- ✅ 表格的高级样式应用 -- ✅ 视觉化信息展示(卡片、时间轴、架构图) - -```bash -# 生成示例演示文稿 -uv run yaml2pptx.py examples/demo.yaml # 基础示例 -uv run yaml2pptx.py examples/custom.yaml # 自定义示例 -uv run yaml2pptx.py examples/complex.yaml # 复杂综合示例 ⭐ +```yaml +slides: + - template: title-slide + vars: + title: "我的演示文稿" + subtitle: "演示" + author: "李四" ``` -**生成的文件大小**: -- `demo_output.pptx` - 31KB -- `custom_output.pptx` - 29KB -- `complex_output.pptx` - 43KB (10页内容) +### 模板变量说明 -## 🎓 YAML Schema 文档 +| 字段 | 说明 | +|------|------| +| `name` | 变量名(必需) | +| `required` | 是否必需(默认:`false`) | +| `default` | 默认值(未提供时使用) | -详细的 YAML 格式说明,请参考各类型文件的示例和注释。 +### 条件渲染 -## 🚧 限制和已知问题 +使用 `visible` 属性控制元素的显示条件: -- 原型版本,仅支持核心功能 -- 不支持复杂样式(渐变、阴影、动画等) -- 不支持 PPTX 到 YAML 的反向解析 -- 图片背景功能暂未完整实现 +```yaml +- type: text + content: "{subtitle}" + visible: "{subtitle != ''}" # 仅当提供了 subtitle 时显示 +``` -## 📄 License +## 背景设置 + +幻灯片支持纯色背景: + +```yaml +slides: + - background: + color: "#f5f5f5" # 浅灰色背景 + elements: + - type: text + content: "灰色背景上的内容" +``` + +## 颜色格式 + +颜色使用十六进制格式: +- **短格式**:`#RGB`(如 `#fff` 表示白色) +- **完整格式**:`#RRGGBB`(如 `#ffffff` 表示白色) + +## 完整示例 + +### 演示文稿文件 (`demo.yaml`) + +```yaml +metadata: + size: 16:9 + +slides: + # 使用模板的标题页 + - template: title-slide + vars: + title: "yaml2pptx 入门" + subtitle: "用 YAML 编写演示文稿" + + # 自定义元素的内容页 + - background: + color: "#ffffff" + elements: + - type: text + box: [0.5, 0.5, 9, 0.8] + content: "功能特性" + font: + size: 36 + bold: true + color: "#2c3e50" + + - type: shape + box: [0.5, 1.5, 3, 2.5] + shape: rounded_rectangle + fill: "#3498db" + line: + color: "#2980b9" + width: 2 + + - type: text + box: [1, 2, 2, 1] + content: "易于使用" + font: + size: 18 + color: "#ffffff" + align: center + + - type: table + position: [5, 2] + col_widths: [2, 2] + data: + - ["功能", "状态"] + - ["模板支持", "✓"] + - ["实时预览", "✓"] + - ["表格支持", "✓"] + style: + font_size: 14 + header_bg: "#2c3e50" + header_color: "#ffffff" + + # 图片页 + - elements: + - type: image + box: [1, 1, 8, 4] + src: "chart.png" +``` + +## 错误提示 + +脚本提供详细的错误信息: + +| 错误 | 说明 | +|------|------| +| `文件不存在: presentation.yaml` | 找不到输入文件 | +| `YAML 语法错误: presentation.yaml, 第 5 行: ...` | YAML 语法问题 | +| `模板文件不存在: title-slide` | 模板文件未找到 | +| `缺少必需变量: title` | 未提供必需的模板变量 | +| `图片文件未找到: image.png` | 图片文件不存在 | + +## 使用技巧 + +1. **使用模板** - 保持幻灯片布局一致 +2. **启用预览模式** - 开发时快速迭代 +3. **使用相对路径** - 图片路径相对于 YAML 文件位置 +4. **指定模板目录** - 使用模板时必须指定 `--template-dir` +5. **先预览后生成** - 预览确认无误后再生成最终 PPTX + +## 坐标系统 + +- **单位**:英寸 (inch) +- **原点**:幻灯片左上角 +- **方向**:X 轴向右,Y 轴向下 + +| 尺寸比例 | 幻灯片尺寸 | +|----------|------------| +| 16:9 | 10" × 5.625" | +| 4:3 | 10" × 7.5" | + +## 许可证 MIT License - -## 🤝 贡献 - -欢迎提交 Issue 和 Pull Request! diff --git a/openspec/changes/archive/2026-03-02-add-text-auto-wrap/.openspec.yaml b/openspec/changes/archive/2026-03-02-add-text-auto-wrap/.openspec.yaml new file mode 100644 index 0000000..fd79bfc --- /dev/null +++ b/openspec/changes/archive/2026-03-02-add-text-auto-wrap/.openspec.yaml @@ -0,0 +1,2 @@ +schema: spec-driven +created: 2026-03-02 diff --git a/openspec/changes/archive/2026-03-02-add-text-auto-wrap/design.md b/openspec/changes/archive/2026-03-02-add-text-auto-wrap/design.md new file mode 100644 index 0000000..accf2c7 --- /dev/null +++ b/openspec/changes/archive/2026-03-02-add-text-auto-wrap/design.md @@ -0,0 +1,97 @@ +# Design: 文本框默认自动换行 + +## Context + +当前 `yaml2pptx.py` 中的 `add_text_element()` 函数创建 PPTX 文本框时,未设置 `word_wrap` 属性。python-pptx 的 TextFrame 默认行为是 `word_wrap = False`,这意味着长文本会溢出文本框边界。同样,HTML 预览中的 `render_text_element_to_html()` 函数使用 `white-space: pre-wrap`,这会保留所有空格和换行符,但对于自动换行的处理不够理想。 + +**Current State:** +- PPTX 生成:`tf.word_wrap` 未设置,默认为 `False`,长文本会溢出 +- HTML 预览:使用 `white-space: pre-wrap`,保留格式但不确保自动换行 + +**Constraints:** +- 必须保持向后兼容性(此改进不会破坏现有功能) +- PPTX 和 HTML 预览行为应该一致 +- 不能引入新的外部依赖 + +## Goals / Non-Goals + +**Goals:** +- 文本框默认启用文字自动换行 +- 同步更新 PPTX 生成和 HTML 预览的行为 +- 用户无需修改任何 YAML 配置 + +**Non-Goals:** +- 添加 YAML `wrap` 属性(不需要,直接默认启用) +- 文本框大小自动调整 +- 文字大小自动缩放以适应文本框 + +## Decisions + +### 1. 直接默认启用自动换行,无需配置 + +**Decision:** 不添加任何 YAML 属性,直接在代码中设置 `word_wrap = True` + +**Rationale:** +- 自动换行是文本框的合理默认行为 +- 用户无需学习新的配置选项 +- 简化代码,减少配置复杂度 +- 符合大多数演示文稿软件的默认行为 + +**Alternatives Considered:** +- 添加 `wrap` 属性:增加配置复杂度,大部分用户都会希望自动换行 + +### 2. PPTX 实现方式 + +**Decision:** 在创建文本框后直接设置 `text_frame.word_wrap = True` + +**Rationale:** +- python-pptx 原生支持此功能,无需额外依赖 +- 代码改动最小,只需添加一行 +- 性能开销为零 + +**Code Location:** `yaml2pptx.py` 第 406 行附近,在 `textbox.text_frame` 赋值后添加: +```python +tf.word_wrap = True +``` + +### 3. HTML 预览实现方式 + +**Decision:** 将 CSS `white-space: pre-wrap` 改为 `white-space: normal` + +**Rationale:** +- `normal` 是 CSS 默认值,允许文字在容器边界处自动换行 +- 与 PPTX 的 `word_wrap = True` 行为一致 +- 对于包含 `\n` 的内容,可以单独处理或在需要时使用 `pre-wrap` + +**Code Location:** `yaml2pptx.py` 第 902 行,修改 `render_text_element_to_html()` 函数中的样式 + +## Risks / Trade-offs + +### Risk 1: 包含手动换行符的文本 + +**Risk:** 如果用户在 YAML 中使用 `\n` 手动换行,`white-space: normal` 会忽略这些换行符 + +**Mitigation:** +- 可以改用 `white-space: pre-wrap` 或 `white-space: break-spaced` 来同时支持自动换行和手动换行 +- 测试验证哪种行为更符合预期 + +### Risk 2: 现有布局可能有细微变化 + +**Risk:** 启用自动换行后,某些长文本的显示方式可能与之前不同 + +**Mitigation:** +- 此变化是改进性的,使文本正确显示而非溢出 +- 用户可以通过调整文本框大小来控制显示效果 + +## Migration Plan + +1. **Phase 1**: 修改 `add_text_element()` 函数,添加 `tf.word_wrap = True` +2. **Phase 2**: 修改 `render_text_element_to_html()` 函数,更新 CSS 样式 +3. **Phase 3**: 创建测试 YAML 文件,包含长文本内容验证效果 +4. **Phase 4**: 更新 README.md 说明文本框默认自动换行 + +**Rollback Strategy:** 如有问题,删除添加的代码行即可快速回滚 + +## Open Questions + +无。这是一个简单直接的功能改进,实现方式清晰。 diff --git a/openspec/changes/archive/2026-03-02-add-text-auto-wrap/proposal.md b/openspec/changes/archive/2026-03-02-add-text-auto-wrap/proposal.md new file mode 100644 index 0000000..a08cf50 --- /dev/null +++ b/openspec/changes/archive/2026-03-02-add-text-auto-wrap/proposal.md @@ -0,0 +1,24 @@ +# Proposal: 文本框默认自动换行 + +## Why + +当前文本框渲染时,当文字内容过长时,文字可能会超出文本框边界被截断或显示不完整。系统应该默认启用文字自动换行,确保文字始终在文本框内正确显示,无需用户额外配置。 + +## What Changes + +- 修改 `add_text_element()` 函数,默认设置 `text_frame.word_wrap = True` +- 修改 `render_text_element_to_html()` 函数,使用 `white-space: normal` 启用自动换行 +- 所有文本框默认启用自动换行,无需 YAML 配置 + +## Capabilities + +### Modified Capabilities +- `element-rendering`: 文本框默认启用文字自动换行 +- `html-rendering`: HTML 预览默认启用文字自动换行 + +## Impact + +- **Affected Code**: `yaml2pptx.py` 中的 `add_text_element()` 函数和 `render_text_element_to_html()` 函数 +- **YAML Schema**: 无变化,用户无需修改现有 YAML 文件 +- **Dependencies**: 无新增依赖,使用 python-pptx 现有的 TextFrame.word_wrap 属性 +- **Breaking Changes**: 无,此改动能改善现有长文本显示问题 diff --git a/openspec/changes/archive/2026-03-02-add-text-auto-wrap/specs/element-rendering/spec.md b/openspec/changes/archive/2026-03-02-add-text-auto-wrap/specs/element-rendering/spec.md new file mode 100644 index 0000000..03c73e5 --- /dev/null +++ b/openspec/changes/archive/2026-03-02-add-text-auto-wrap/specs/element-rendering/spec.md @@ -0,0 +1,32 @@ +# Element Rendering Delta + +## MODIFIED 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`,文字在文本框边界处自动换行 diff --git a/openspec/changes/archive/2026-03-02-add-text-auto-wrap/specs/html-rendering/spec.md b/openspec/changes/archive/2026-03-02-add-text-auto-wrap/specs/html-rendering/spec.md new file mode 100644 index 0000000..2c09709 --- /dev/null +++ b/openspec/changes/archive/2026-03-02-add-text-auto-wrap/specs/html-rendering/spec.md @@ -0,0 +1,37 @@ +# HTML Rendering Delta + +## MODIFIED Requirements + +### Requirement: 系统必须渲染文本元素 + +系统 SHALL 将 YAML 中的文本元素转换为 HTML `
` 标签,应用相应的样式,并默认启用文字自动换行。 + +#### Scenario: 渲染基本文本元素 + +- **WHEN** 元素定义为 `{type: text, content: "Hello", box: [1, 2, 8, 3]}` +- **THEN** 系统生成 `
` 标签,内容为 "Hello",位置为 (96px, 192px),尺寸为 768x288 像素 + +#### Scenario: 应用文本字体样式 + +- **WHEN** 文本元素定义了 `font: {size: 32, bold: true, color: "#333333"}` +- **THEN** 系统应用 CSS:`font-size: 32pt; font-weight: bold; color: #333333` + +#### Scenario: 应用文本对齐方式 + +- **WHEN** 文本元素定义了 `font: {align: center}` +- **THEN** 系统应用 CSS:`text-align: center` + +#### Scenario: 支持多行文本(保留换行符) + +- **WHEN** 文本内容包含换行符(`\n`) +- **THEN** 系统使用 `white-space: pre-wrap` 保留换行符 + +#### Scenario: 文本元素默认启用自动换行 + +- **WHEN** 系统渲染任何文本元素 +- **THEN** 系统应用 CSS:`white-space: normal`,允许文字在容器边界处自动换行 + +#### Scenario: 使用 pt 单位表示字体大小 + +- **WHEN** 文本字体大小为 44 +- **THEN** 系统使用 CSS:`font-size: 44pt`(与 PPTX 保持一致) diff --git a/openspec/changes/archive/2026-03-02-add-text-auto-wrap/tasks.md b/openspec/changes/archive/2026-03-02-add-text-auto-wrap/tasks.md new file mode 100644 index 0000000..97a3630 --- /dev/null +++ b/openspec/changes/archive/2026-03-02-add-text-auto-wrap/tasks.md @@ -0,0 +1,22 @@ +# Implementation Tasks + +## 1. PPTX 文本框自动换行实现 + +- [x] 1.1 修改 `add_text_element()` 函数,在创建文本框后设置 `text_frame.word_wrap = True` +- [x] 1.2 确保所有新创建的文本框默认启用自动换行 + +## 2. HTML 预览自动换行同步 + +- [x] 2.1 修改 `render_text_element_to_html()` 函数,调整 CSS `white-space` 样式 +- [x] 2.2 将 `white-space: pre-wrap` 改为 `white-space: normal` 以启用自动换行 + +## 3. 测试验证 + +- [x] 3.1 创建测试 YAML 文件,包含长文本内容 +- [x] 3.2 生成 PPTX 文件,验证文字在文本框内正确换行 +- [x] 3.3 启动 HTML 预览,验证预览效果与 PPTX 一致 +- [x] 3.4 清理测试文件 + +## 4. 文档更新 + +- [x] 4.1 更新 README.md,说明文本框默认启用自动换行 diff --git a/openspec/specs/element-rendering/spec.md b/openspec/specs/element-rendering/spec.md index ebef768..d3e9125 100644 --- a/openspec/specs/element-rendering/spec.md +++ b/openspec/specs/element-rendering/spec.md @@ -8,7 +8,7 @@ Element rendering系统负责将 YAML 中定义的各类元素(文本、图片 ### Requirement: 系统必须支持文本元素渲染 -系统 SHALL 将 YAML 中定义的文本元素渲染为 PPTX 文本框。 +系统 SHALL 将 YAML 中定义的文本元素渲染为 PPTX 文本框,并默认启用文字自动换行。 #### Scenario: 渲染基本文本元素 @@ -30,6 +30,11 @@ Element rendering系统负责将 YAML 中定义的各类元素(文本、图片 - **WHEN** 文本对齐方式为 `left`、`center`、`right` 之一 - **THEN** 系统正确应用对应的对齐方式 +#### Scenario: 文本框默认启用自动换行 + +- **WHEN** 系统渲染任何文本元素 +- **THEN** 系统设置 `text_frame.word_wrap = True`,文字在文本框边界处自动换行 + ### Requirement: 系统必须支持图片元素渲染 系统 SHALL 将 YAML 中定义的图片元素渲染为 PPTX 图片对象。 diff --git a/openspec/specs/html-rendering/spec.md b/openspec/specs/html-rendering/spec.md index 29d02b3..f8586f5 100644 --- a/openspec/specs/html-rendering/spec.md +++ b/openspec/specs/html-rendering/spec.md @@ -46,7 +46,7 @@ HTML Rendering 系统负责将 YAML 中定义的各类元素(文本、图片 ### Requirement: 系统必须渲染文本元素 -系统 SHALL 将 YAML 中的文本元素转换为 HTML `
` 标签,应用相应的样式。 +系统 SHALL 将 YAML 中的文本元素转换为 HTML `
` 标签,应用相应的样式,并默认启用文字自动换行。 #### Scenario: 渲染基本文本元素 @@ -63,10 +63,15 @@ HTML Rendering 系统负责将 YAML 中定义的各类元素(文本、图片 - **WHEN** 文本元素定义了 `font: {align: center}` - **THEN** 系统应用 CSS:`text-align: center` -#### Scenario: 支持多行文本 +#### Scenario: 支持多行文本(保留换行符) - **WHEN** 文本内容包含换行符(`\n`) -- **THEN** 系统使用 `white-space: pre-wrap` 保留换行 +- **THEN** 系统使用 `white-space: pre-wrap` 保留换行符 + +#### Scenario: 文本元素默认启用自动换行 + +- **WHEN** 系统渲染任何文本元素 +- **THEN** 系统应用 CSS:`white-space: normal`,允许文字在容器边界处自动换行 #### Scenario: 使用 pt 单位表示字体大小 diff --git a/yaml2pptx.py b/yaml2pptx.py index 0fbd1d6..1b60f8d 100644 --- a/yaml2pptx.py +++ b/yaml2pptx.py @@ -406,6 +406,8 @@ def add_text_element(slide, elem, base_path=None): textbox = slide.shapes.add_textbox(x, y, w, h) tf = textbox.text_frame tf.text = elem.get('content', '') + # 默认启用文字自动换行 + tf.word_wrap = True # 应用字体样式 font_style = elem.get('font', {}) @@ -899,7 +901,8 @@ def render_text_element_to_html(elem): {'font-style: italic;' if font.get('italic') else ''} display: flex; align-items: center; - white-space: pre-wrap; + white-space: normal; + overflow-wrap: break-word; """ content = elem.get('content', '').replace('<', '<').replace('>', '>')