修复svg2pptx转换器多项bug + 新增管线兼容性文档

svg2pptx.py:
- 修复image opacity不生效(通过OOXML alphaModFix)
- 修复环形图stroke渐变url(#id)引用不支持(fallback第一个stop颜色)
- 修复viewBox内缩放不传递(g组scale累积到所有子元素)
- 修复text baseline偏移(区分text-after-edge和auto)
- 修复text-anchor:middle/end的x坐标偏移
- 添加--html-dir参数支持

html2svg.py:
- 修复图片相对路径解析(以HTML文件所在目录为基准)
- 新增3种CSS兜底预处理(background-clip:text、text-fill-color、mask-image)

新增 references/pipeline-compat.md:
- HTML->SVG->PPTX管线兼容性规则文档
- CSS禁止清单、防偏移写法指南、防偏移checklist
- 已整合到SKILL.md和prompts.md中引用

prompts.md:
- 新增内联SVG防偏移约束(禁SVG text、用HTML叠加)

示例产物:
- ppt-output/ 包含SU7示例的完整HTML/SVG/PPTX产物
This commit is contained in:
sunbigfly
2026-03-21 03:57:23 +08:00
parent 7dcfe25603
commit e860485ec8
27 changed files with 7914 additions and 56 deletions

View File

@@ -0,0 +1,186 @@
# HTML -> SVG -> PPTX 管线兼容性规则
本文档汇总所有管线兼容性教训。**HTML 设计稿生成时必须遵守,在源头规避偏移问题。**
核心原则:**html2svg + svg2pptx 不是浏览器**,很多 CSS 特性和 SVG 属性在转换过程中会丢失或产生偏移。HTML 写法必须考虑到下游转换器的能力边界。
---
## 1. CSS 禁止清单
| 禁止特性 | 转换后现象 | 正确替代写法 |
|---------|---------|-----------|
| `background-clip: text` | 渐变变色块 + 白色文字 | `color: var(--accent-1)` 直接上色 |
| `-webkit-text-fill-color` | 文字颜色丢失 | 标准 `color` 属性 |
| `mask-image` / `-webkit-mask-image` | 图片完全消失 | `<div>` 遮罩层linear-gradient 背景) |
| `::before` / `::after`(视觉装饰用) | 内容消失 | 真实 `<div>` / `<span>` |
| `conic-gradient` | 不渲染 | 内联 SVG `<circle>` + stroke-dasharray |
| CSS border 三角形 (width:0 trick) | 形状丢失 | 内联 SVG `<polygon>` |
| `mix-blend-mode` | 不支持 | `opacity` 叠加 |
| `filter: blur()` | 光栅化变位图 | `opacity``box-shadow` |
| `content: '文字'` | 文字消失 | 真实 `<span>` |
| CSS `background-image: url(...)` | dom-to-svg 忽略 | `<img>` 标签 |
html2svg.py 兜底覆盖前3项 + 伪元素 + conic-gradient + border三角形共6种但兜底效果远不如正确写法。
---
## 2. 防偏移写法(关键章节)
svg2pptx 的文本定位基于 SVG text 元素的坐标,但 PPTX textbox 的坐标系与 SVG 不同SVG text y = baselinePPTX y = textbox 顶部)。以下写法可从 HTML 源头避免偏移:
### 2.1 内联 SVG 中的文本标注 -- 用 HTML 叠加替代 SVG text
**问题**:内联 SVG 中的 `<text>` 元素经过 dom-to-svg 转换后坐标是 viewBox 坐标系svg2pptx 在处理 baseline 偏移和 text-anchor 居中时有精度损失(约 +/- 3-5px导致标注位置偏移。
**HTML 防偏移写法**:把文字标注从 SVG `<text>` 移出来,用 HTML `<div>` 绝对定位叠加在 SVG 上方。HTML div 由 dom-to-svg 精确定位,不经过 viewBox 坐标转换,偏移风险为零。
```html
<!-- 正确HTML div 叠加标注,零偏移 -->
<div class="chart-container" style="position: relative;">
<svg viewBox="0 0 660 340" style="width:100%; height:100%;">
<!-- 只画柱子、线条等图形元素,不写 <text> -->
<rect x="80" y="100" width="60" height="200" fill="#FF6900"/>
</svg>
<!-- 标注用 HTML 绝对定位叠加 -->
<span style="position:absolute; left:12.5%; top:25%; font-size:14px; color:#fff;">720</span>
<span style="position:absolute; left:12.5%; bottom:5%; font-size:12px; color:rgba(255,255,255,0.6);">标准版</span>
</div>
```
```html
<!-- 禁止SVG text 在 PPTX 中会偏移 -->
<svg viewBox="0 0 660 340">
<rect x="80" y="100" width="60" height="200" fill="#FF6900"/>
<text x="110" y="90" text-anchor="middle" fill="#fff">720</text>
</svg>
```
### 2.2 不同字号混排 -- 必须用 flex 独立元素
**问题**:大小字号内嵌(`<div class="big">3.08<span class="small">s</span></div>`)经 dom-to-svg 转为独立 tspan 后svg2pptx 给每个 tspan 按各自字号做 baseline 偏移,小字会上移。
```html
<!-- 正确flex baseline 对齐 -->
<div style="display:flex; align-items:baseline; gap:4px;">
<span style="font-size:48px;">3.08</span>
<span style="font-size:18px;">s</span>
</div>
```
```html
<!-- 禁止:内嵌不同字号 span -->
<div class="big">3.08<span class="small">s</span></div>
```
### 2.3 环形图(圆弧进度条)-- SVG 画弧 + HTML 叠加文字
```html
<!-- 正确:环形图最佳实践 -->
<div class="ring-container" style="position: relative; width:120px; height:120px;">
<!-- SVG 只画圆环弧线 -->
<svg viewBox="0 0 120 120" style="width:100%; height:100%;">
<!-- 底圈 -->
<circle cx="60" cy="60" r="50" fill="none" stroke="rgba(255,255,255,0.1)" stroke-width="8"/>
<!-- 弧线:用 dasharray 两值格式,禁止 dashoffset -->
<circle cx="60" cy="60" r="50" fill="none" stroke="#FF6900" stroke-width="8"
stroke-dasharray="235 314" stroke-linecap="round"
transform="rotate(-90 60 60)"/>
</svg>
<!-- 中心文字用 HTML 叠加,不用 SVG text -->
<div style="position:absolute; top:50%; left:50%; transform:translate(-50%,-50%); text-align:center;">
<div style="font-size:22px; font-weight:700; color:#fff;">15</div>
<div style="font-size:10px; color:rgba(255,255,255,0.6);">分钟</div>
</div>
</div>
```
### 2.4 图例标签 -- 用 HTML flex 布局
```html
<!-- 正确HTML flex 图例,不用 SVG text -->
<div style="display:flex; gap:16px; font-size:12px;">
<div style="display:flex; align-items:center; gap:4px;">
<span style="display:inline-block; width:12px; height:12px; background:#999; border-radius:2px;"></span>
<span style="color:rgba(255,255,255,0.6);">初代SU7</span>
</div>
<div style="display:flex; align-items:center; gap:4px;">
<span style="display:inline-block; width:12px; height:12px; background:#FF6900; border-radius:2px;"></span>
<span style="color:rgba(255,255,255,0.6);">新一代SU7</span>
</div>
</div>
```
### 2.5 x 轴标签(标准版/Pro/Max-- 用 HTML 容器
```html
<!-- 正确: x 轴标签用 HTML -->
<div style="display:flex; justify-content:space-around; padding:0 10%;">
<span style="font-size:13px; color:rgba(255,255,255,0.6);">标准版</span>
<span style="font-size:13px; color:rgba(255,255,255,0.6);">Pro</span>
<span style="font-size:13px; color:rgba(255,255,255,0.6);">Max</span>
</div>
```
---
## 3. 图片路径
| 场景 | 错误写法 | 正确写法 |
|------|---------|---------|
| img src 引用 | 依赖浏览器 resolve | html2svg 以 HTML 文件所在目录为基准 resolve 相对路径 |
| CSS background-image | 会被 dom-to-svg 忽略 | 用 `<img>` 标签 |
---
## 4. SVG circle 环形图属性
| 属性 | svg2pptx 支持 | 说明 |
|------|-------------|------|
| `stroke-dasharray="arc gap"` | 支持 | 用两个值:弧线长度 + 间隔长度 |
| `stroke-dashoffset` | **不支持** | 禁止使用,改用 dasharray 的两值格式 |
| `stroke-linecap="round"` | 支持 | 圆角弧端 |
| `transform="rotate(-90 cx cy)"` | 支持 | 从12点钟方向开始 |
正确弧线写法:`stroke-dasharray="235 314"` (弧长=235, 圆周=2*pi*50=314
---
## 5. 底层氛围图
| 项目 | 规则 |
|------|------|
| opacity | 0.05 - 0.10(卡片内)/ 0.25 - 0.40(封面页) |
| 尺寸 | 限制在容器 40-60%,不要全覆盖 |
| z-index | 必须为 0 或 -1 |
| 实现方式 | 极低 opacity直接 `<img>` + opacity |
| | 封面级渐隐:`<div>` 容器内 img + 遮罩 div |
| **禁止** | div 遮罩在 PPTX 中层叠不可靠时,回退到纯 opacity |
---
## 6. 配图技法管线安全等级
| 技法 | 管线安全 | 原因 |
|------|---------|------|
| 渐隐融合div遮罩 | 安全 | 真实 div + linear-gradient |
| 色调蒙版 | 安全 | 真实 div + 半透明背景 |
| 氛围底图 | 最安全 | 纯 opacity |
| 裁切视窗 | 安全 | overflow:hidden + div 渐变 |
| 圆形裁切 | 安全 | border-radius |
| ~~CSS mask-image~~ | **禁止** | dom-to-svg 不支持 |
---
## 7. 总结HTML 设计稿防偏移 checklist
生成每页 HTML 时,对照以下清单:
- [ ] CSS 禁止清单中的特性未使用
- [ ] 所有图片用 `<img>` 标签,不用 CSS background-image
- [ ] 内联 SVG 中**不含 `<text>` 元素**,所有文字标注用 HTML div 叠加
- [ ] 不同字号混排用 flex + 独立 span不用嵌套 span
- [ ] 环形图用 stroke-dasharray 两值格式,不用 dashoffset
- [ ] 图例、x轴标签、数据标注全部用 HTML 元素,不用 SVG text
- [ ] 底层配图用低 opacity `<img>` 或 div 遮罩
- [ ] 伪元素 `::before`/`::after` 装饰已用真实元素替代

View File

@@ -410,9 +410,10 @@
- 关键词: 用 <strong> 或 <span class="highlight"> 包裹(背景 accent-primary 10% 透明度)
### data数据卡片
- 核心数字: font-size=36-48px, font-weight=800, 使用 accent-primary 渐变色(background: linear-gradient; -webkit-background-clip 除外)
- SVG 友好替代: 直接用 color=accent-primary不要用 -webkit-background-clip: text
- 单位/标签: font-size=14-16px, color=text-secondary
- 核心数字: font-size=36-48px, font-weight=800, **直接用 `color: var(--accent-1)`**
- **禁止** `background-clip: text` + `-webkit-text-fill-color: transparent` 渐变文字SVG转换后变成橙色色块+白色文字)
- html2svg.py 有兜底自动修复,但会丢失渐变效果只保留主色
- 单位/标签: font-size=14-16px, color=text-secondary 或 color=accent-2
- 补充说明: font-size=13px, 在数字下方
### list列表卡片
@@ -520,7 +521,9 @@
**核心原则**:图片是**氛围的一部分**,不是独立的内容块。
#### 5 种融入技法(全部管线安全)
> **SVG 管线兼容警告**:所有渐隐/遮罩效果必须用 **真实 `<div>` 遮罩层** 实现(`linear-gradient` 背景的 div 叠加在图片上方)。**禁止使用 CSS `mask-image` / `-webkit-mask-image`**,该属性在 dom-to-svg 转换中完全丢失。html2svg.py 有兜底(自动降级为 opacity但效果远不如 div 遮罩精细。
#### 5 种融入技法(全部管线安全 -- 均使用 div 遮罩而非 mask-image
##### 1. 渐隐融合 -- 封面页/章节封面的首选
@@ -599,12 +602,25 @@
- 渐变遮罩用**真实 `<div>`**(禁用 ::before/::after
- `object-fit: cover``border-radius` 与容器一致
- 图片使用**绝对路径**(由 agent 生成图片后填入)
- 底层氛围图的 opacity 必须足够低0.05-0.15),尺寸限制在容器的 45-60%,避免遮挡前景内容
**禁止**
- 禁止使用 CSS `mask-image` / `-webkit-mask-image`SVG 转换后完全丢失,必须用 div 遮罩层替代)
- 禁止使用 `-webkit-background-clip: text`SVG 中渐变变色块,必须用 `color` 直接上色)
- 禁止使用 `-webkit-text-fill-color`SVG 不识别,必须用标准 `color` 属性)
- 禁止图片直接裸露在卡片角落(无融入效果)
- 禁止图片占据整个卡片且无蒙版(文字不可读)
- 禁止图片与背景色有明显的矩形边界线
#### 内联 SVG 防偏移约束(详见 `pipeline-compat.md` 第 2 章)
svg2pptx 对 SVG `<text>` 元素的 baseline/text-anchor 定位有精度损失(+/- 3-5px会导致文字标注在 PPTX 中偏移。以下规则从 HTML 源头避免偏移:
1. **内联 SVG 中禁止写 `<text>` 元素**。所有文字标注数据标注、x 轴标签、图例文字、环形图中心文字)必须用 HTML `<div>` / `<span>` 绝对定位叠加在 SVG 上方
2. **不同字号混排必须用 flex 独立元素**`display:flex; align-items:baseline; gap:4px`),禁止嵌套不同字号的 span
3. **环形图中心文字用 HTML position:absolute 叠加**,不写在 SVG `<text>`
4. **SVG circle 弧线用 `stroke-dasharray="弧长 间隔"` 两值格式**,禁止 `stroke-dashoffset`
## 对比度安全规则(必须遵守)
文字颜色必须与其直接背景形成足够对比度,否则用户看不清:
@@ -895,7 +911,7 @@ Step 3 -> 使用 Prompt #2大纲架构师
Step 4 -> 使用 Prompt #3内容分配与策划稿
Step 5a -> 使用 style-system.md 选择风格
Step 5b -> 如有 generate_image为每页生成配图
Step 5c -> 使用 Prompt #4HTML 设计稿),逐页生成
后处理 -> scripts/html_packager.py 合并预览 + scripts/html2svg.py 转 SVG
Step 5c -> 使用 Prompt #4HTML 设计稿),逐页生成。**必须遵守 `pipeline-compat.md` 中的 CSS 禁止清单和管线兼容性规则**
后处理 -> scripts/html_packager.py 合并预览 + scripts/html2svg.py 转 SVG + scripts/svg2pptx.py 转 PPTX
可选 -> 使用 Prompt #5演讲备注
```