mcpField
H
html2pptx

html2pptx

github.com/microsoft文档处理3.4k63 次安装5 周前更新
代码仓库

关于 html2pptx

html2pptx 是将渲染后的 HTML 页面转换为可编辑 PowerPoint 形状的技能,面向需要把海报交付为演示文稿的用户。它通过浏览器提取 DOM 并生成幻灯片,还可渲染结果、比较视觉差异并迭代修正。

主要功能

  1. 01将 HTML 转为可编辑 PPTX
  2. 02检测页面画布与字体
  3. 03渲染幻灯片并生成对照图
  4. 04视觉审计版面保真问题
  5. 05通过隔离副本运行自动修复

适用场景

  1. 01把 HTML 研究海报转成交付用 PPTX
  2. 02检查转换后页面与 HTML 的视觉差异
  3. 03针对单张海报迭代修复保真问题

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/microsoft/researchstudio --skill html2pptx

安装后在 Claude Code 中输入/html2pptx确认已加载。

包含的文件

除 SKILL.md 外,安装时一起下载的参考资料和脚本。

__init__.py
.gitignore
difference.md
GOTCHAS.md
README.md
requirements.txt
scripts/
__init__.py
auto_correct_loop.py
auto_fix_loop.py
font_embedder.py
font_resolver.py
html_to_pptx.py
vision_aggregate.py
vision_audit.py
vision_compare.py
vision_eval_harness.py

详细介绍

html2pptx

将渲染后的 HTML 页面转换为原生 PowerPoint .pptx,并保留可编辑形状(而非插入 PNG)。

适用场景

  • “将这个 HTML 海报转换为 PPT。”
  • “我需要这个 HTML 页面对应的可编辑 PowerPoint 版本。”
  • “按 1:1 还原 poster.html 到 PPT——字体、颜色和布局都要一致。”
  • “把海报交给不懂开发的人,让他们用 PPT 编辑。”

不适用场景

  • 需要纯 PNG 幻灯片 → 使用 paper2poster/demo/presentation/posters.pptx。
  • HTML 使用了大量 JS 动画或视频 → 这些内容无法转换为 PPT 形状。
  • 内容大量使用 KaTeX 数学公式 → 数学公式会通过栅格化作为后备方案处理(失去公式可编辑性)。

一次性设置

1. Python 依赖项
pip install python-pptx playwright pdf2image lxml Pillow pyphen cairosvg
playwright install chromium     # ~110MB headless browser
2. soffice(用于验证)
# Linux:
sudo apt install libreoffice-impress
# Mac:
brew install --cask libreoffice
3. Web 字体——对还原度至关重要(阅读 GOTCHAS.md)

默认字体 = Arial → 可以跳过本节。 paper2poster 的默认字体是 Arial,因此海报会以 Arial(或其他适用于 PPT 的字体系列:Calibri、 Aptos、Cambria、Times New Roman、Verdana、Georgia、Trebuchet MS)进行渲染。这些字体 已预装在所有 Mac 和 Windows PowerPoint 上,因此无需安装 下方提到的字体,且 .pptx 无需嵌入字体即可在不同设备间使用。 下方的 Inter / Source Serif 4 / JetBrains Mono 配置仅适用于海报使用可选的 Inter Web 字体覆盖设置进行渲染的情况。

如果未安装 Inter / Source Serif 4 / JetBrains Mono,soffice 会回退到 DejaVu Sans(Linux)或 Helvetica(Mac)——字符宽度会发生变化,文本换行也会不同,所有元素的位置都会随之偏移。

Linux:

# Download static-weight TTFs (variable fonts register under wrong family name)
mkdir -p /tmp/fonts-dl && cd /tmp/fonts-dl
curl -sL "https://github.com/rsms/inter/releases/download/v4.0/Inter-4.0.zip" -o Inter.zip
curl -sL "https://github.com/adobe-fonts/source-serif/releases/download/4.005R/source-serif-4.005_Desktop.zip" -o SourceSerif4.zip
curl -sL "https://github.com/JetBrains/JetBrainsMono/releases/download/v2.304/JetBrainsMono-2.304.zip" -o JetBrainsMono.zip
unzip -qo Inter.zip -d Inter/
unzip -qo SourceSerif4.zip -d SourceSerif4/
unzip -qo JetBrainsMono.zip -d JetBrainsMono/

mkdir -p ~/.local/share/fonts
cp Inter/extras/ttf/Inter-{Regular,Medium,SemiBold,Bold,Italic,SemiBoldItalic,BoldItalic}.ttf ~/.local/share/fonts/
cp SourceSerif4/source-serif-4.005_Desktop/TTF/SourceSerif4-{Regular,Semibold,Bold,It,SemiboldIt,BoldIt}.ttf ~/.local/share/fonts/
cp JetBrainsMono/fonts/ttf/JetBrainsMono-{Regular,Medium,Bold,Italic,BoldItalic}.ttf ~/.local/share/fonts/
fc-cache -f ~/.local/share/fonts/

# Verify: fc-match MUST return the font itself, not a fallback
fc-match "Inter" "Source Serif 4" "JetBrains Mono"

Mac: 下载方式相同,但请将字体复制到 ~/Library/Fonts/,并完全退出后重新打开 PowerPoint(Cmd+Q),以加载新字体。

对于使用默认 Arial(或任何适用于 PPT 的字体系列)的海报,查看者无需安装任何字体——这些字体已随 PowerPoint 提供,因此 pptx 可直接跨设备使用。只有在使用可选的 Inter 覆盖设置时,查看者才需要安装 Inter,或者通过可选的 scripts/font_embedder.py 步骤将字体嵌入 pptx(嵌入 4 种 Inter 字重;约 3 MB)。

快速开始 — 一条命令

cd skills/paper2poster/html2pptx
python -m scripts.auto_correct_loop --html /path/to/poster.html

默认情况下,输出文件会保存到输入 HTML 的父目录(同级存放约定,2026-06-12 规范)——例如,my_paper/poster.html → my_paper/poster.pptx。在同一目录中连续运行会覆盖之前的 .pptx。使用 --outdir /custom/path/ 覆盖默认路径。

*Bundle 契约(paper2 pipeline)。作为海报 pipeline 的最终交接步骤调用时,调用方传入 --outdir <bundle>/assets/_pptx_build/,以便所有 html2pptx 产物(DOM json、sanity PNG 和 soffice 渲染文件)都保存在 assets/ 下,然后再将演示文稿移至 bundle 根目录——cp <bundle>/assets/_pptx_build/poster.pptx <bundle>/poster.pptx——因为 poster.pptx 是顶层交付物(也是唯一会离开 assets/ 的 html2pptx 输出)。输入的 poster.html 使用以根目录为基准的 assets/… src 路径**引用图片、徽标和字体;转换器通过 file:// 加载 HTML,因此这些路径会自动相对于 HTML 所在的磁盘位置解析——转换器无需处理路径。

这是规范的入口。它会:

  1. 自动检测画布,根据 CSS @page { size: ... } 确定画布尺寸;如果海报超过 56"(PPT 限制),则按比例缩放至不超过 55"
  2. 自动检测同级目录中的 poster.pdf(如果存在):对其运行 pdffonts,构建 CSS 名称 → PDF 字体的别名映射。写入 fontconfig <match> 运行时覆盖项,使浏览器使用与参考 PDF 相同的字体——匹配一一对应。通过 atexit 清理。
  3. 自动下载 HTML 引用的其他 Google Fonts 字体(font_resolver.py)
  4. 提取 DOM(运行一次 playwright,并缓存为 <name>_dom.json)
  5. 构建 pptx → 通过 soffice 渲染 → 生成 PNG
  6. 保存对比 PNG:<name>_html_print.png(打印视口,与 PPT 画布一致)和 <name>_html_browser.png(1920×1080 浏览器视口,fullPage)
  7. 视觉审查(默认开启):调用 Claude vision 对比 <name>_html_print.png 与 <name>.png,并写入 <name>_audit.json,其中包含结构化的保真度问题(严重程度、类别、block_idx、位置、描述)。如果已有先前的审查 JSON,则会输出差异(例如 +/- 3 issues vs previous)。默认模型:Opus 4.8(每张海报约 $0.10;如果预算比检出率更重要,可使用 --vision-model claude-sonnet-4-6,每张海报约 $0.02);额外耗时约 70 秒。
模型选择(供调用此技能的编排器使用)

此技能提供两个相互独立的模型选项。用户说“使用 Opus”/“使用 Sonnet”/“使用更便宜的那个”等时,负责编排的 Claude 必须将其转换为正确的标志——技能脚本不支持自然语言解析。

用户意图要传入的标志适用范围
“使用 Opus”/“最高质量”/未指定模型(默认)(省略标志——默认使用 Opus 4.8)两者
“使用 Sonnet”/“更便宜”--vision-model claude-sonnet-4-6(如果运行 auto_fix_loop,还需传入 --fix-model claude-sonnet-4-6)两者
“不做审查”/“跳过视觉检查”/批量自动化--no-vision-auditauto_correct_loop
“视觉审查用 Opus,但修复用 Sonnet”(少见)--vision-model claude-opus-4-8 --fix-model claude-sonnet-4-6仅限 auto_fix_loop

两个独立选项,对应两个独立脚本:

  • scripts/auto_correct_loop.py(构建 + 审查)→ --vision-model <MODEL>
  • scripts/auto_fix_loop.py(构建 + 审查 + 自主代码修复子 Agent)→ --vision-model <MODEL> 和 --fix-model <MODEL>(两者默认均为 Opus 4.8;--fix-model 会明确传给 claude -p --model,确保子 Agent 不会悄然继承编排器的 CLI 配置)

可复现性:两个脚本都会在启动时记录模型选择。视觉审查日志会显示 [vision-audit] calling Claude vision (claude-opus-4-8, auth=...);auto_fix_loop 日志会显示 [fix-loop] models: vision-audit=..., fixer=...。如果用户报告异常行为,可在运行日志中查看所用模型。

Vision-audit 身份验证

有两种方式,任选其一即可:

模式环境变量使用场景
直接 APIANTHROPIC_AUTH_TOKEN(或 ANTHROPIC_API_KEY)个人密钥,直接连接 api.anthropic.com
Base-URL 代理ANTHROPIC_AUTH_TOKEN + ANTHROPIC_BASE_URL企业代理 / Vertex / Bedrock / 公司网关。本地开发机器使用此配置。

如果未配置任何身份验证,审核会静默跳过,并显示一行提示(因此离线 / CI 运行无需指定 --no-vision-audit)。在批处理自动化中传入 --no-vision-audit 可显式禁用(100 张海报 ≈ $2 + 额外约 2 小时)。

3 轮修订工作流(开发周期)

Vision audit 用更实用的信号取代了旧的基于 PIL 的 L2 循环:结构保真度差异,而非外观上的字体缩小。每次重新运行都会再次执行审核,并显示 +/- N issues vs previous——开发迭代循环如下:

# round 1: baseline (defaults to ./output/<timestamp>/)
python -m scripts.auto_correct_loop --html poster.html
# → look at output/<ts>/poster_audit.json, identify top systemic bug

# round 2: after fixing the bug in html_to_pptx.py
python -m scripts.auto_correct_loop --html poster.html --outdir output/<ts>/
# → output shows e.g. `[vision-audit] 2 issues (-9 vs previous)`

# round 3: fix next bug, target near-zero high-severity
python -m scripts.auto_correct_loop --html poster.html --outdir output/<ts>/

根据实际经验:新的 HTML 模板经过 2-3 轮即可解决大多数问题。每轮约需 1 分钟 + ~$0.02。

跨海报汇总:python -m scripts.vision_aggregate <root_dir> 会遍历所有 <poster>/poster_audit.json,并输出类别频次 + 每张海报的问题数 → 揭示值得通过修改代码来修复的 SYSTEMIC 错误(同一类别的问题出现在 N 张海报中),而非一次性问题。

自主修复循环(auto_fix_loop.py)——完全由 Agent 驱动

对于单张海报的保真度修复,如果不希望这些修复影响已发布的技能,请运行:

python -m scripts.auto_fix_loop --html /path/poster.html --max-rounds 3

每轮:

  1. 构建并审计(通过 output/<ts>/_skill_run_copy/ 下 scripts/ 的隔离副本)
  2. 从审计中选出最值得处理的问题(类别白名单会过滤掉容易受视觉判断影响的误报,例如 alignment_off)
  3. 启动 claude -p 子 Agent,并将其限制在副本中(--add-dir <copy>,仅提供 Read/Edit/Grep/Glob 工具——不提供 Bash、git,且无法越界)
  4. 子 Agent 读取 GOTCHAS.md 和副本中的 html_to_pptx.py,进行最小差异修改
  5. 重新构建并再次审计
  6. 如果问题数量减少 → 将更改保留在副本的内部 git 中 否则 → 在副本中执行 git reset --hard → 尝试下一个问题
  7. 循环终止条件:收敛(没有可处理的问题)、达到最大轮数,或达到连续失败上限

每次运行相互隔离是此设计的关键:已发布的 skills/paper2poster/html2pptx/ 永远不会被修改。每次运行都会生成:

  • output/<ts>/<name>.pptx — 最终修复后的 PPT
  • output/<ts>/<name>_audit.json — 最终审计结果(目标:0 个问题)
  • output/<ts>/<name>_run_patches.diff — 相对于基线的子 Agent 累积差异(请审阅!)
  • output/<ts>/_skill_run_copy/ — 修补后的技能副本(可使用相同 HTML 重新运行)
  • output/<ts>/<name>_fix_loop_summary.json — 每轮处理轨迹

如果审阅 .diff 后发现修复确实具有普遍适用性(而非针对特定海报),请通过常规 PR 将其 cherry-pick 到已发布的技能中。否则,补丁只会作用于该输出目录,不会影响其他海报或其他人的安装。

成本:使用默认模型时,每次收敛运行约为 1–3 美元(视觉审计和修复子 Agent 均使用 Opus 4.8)。可通过 --vision-model / --fix-model(例如 claude-sonnet-4-6)覆盖其中任一模型,以约 5 倍的成本降幅为代价,降低问题检出率并减弱根因分析能力。两种模型的选择都会在运行开始时记录,因此运行结果完全可复现。

身份验证:与 --vision-audit 相同(直接使用 ANTHROPIC_AUTH_TOKEN,或搭配 ANTHROPIC_BASE_URL 使用企业代理)。

已于 2026-06-05 移除:此前的“L2 闭环”字体缩小 轮次——PIL 预测的溢出与 soffice 的实际渲染结果脱节 (审计显示,paper_4_d 在 4 轮中的溢出数量始终为 17→17→17→17),而且 缩小器偶尔会误缩正常的正文段落。现已由默认启用的 --vision-audit 取代, 它能发现真正的保真度问题(缺失的 logo、丢失的 span、错误的换行)——这些问题 是 PIL 无法发现的。换行保真度问题现已在 DOM 提取阶段解决 (浏览器通过 CSS 行高阈值使用 extractWrapLines),而不是 事后处理。--rounds / --shrink-step 标志仍可解析(静默空操作), 因此不会破坏现有调用位置。

输出约定:默认情况下,输出会保存到 dirname(input_html)/(源 HTML 同级目录);传入 --outdir <path> 可覆盖此设置。

默认幻灯片尺寸为 47×33.1"(A0 横向)。可通过 --width-inch / --height-inch 覆盖。

字体工作流

该技能按以下优先级链解析字体:

  1. 存在同级的 poster.pdf(或使用 --reference-pdf 标志):该技能通过 pdffonts 提取 PDF 中实际使用的字体,构建别名映射(例如,CSS Inter → PDF Arimo),在本地安装 PDF 字体,并写入 fontconfig <match> 运行时覆盖规则,强制浏览器使用 PDF 字体(而不是 CSS 中指定名称的字体)进行渲染。PPT XML 字体名称 = PDF 字体名称。与同事已有的 PDF 渲染结果匹配时,这种方式的保真度最高,尤其是在其机器上使用的回退字体与 CSS 设计意图不同的情况下。

  2. 不存在同级 PDF:该技能会遍历 HTML 中所有 font-family 声明,并通过 font_resolver.py 自动从 Google Fonts 下载尚未安装的字体。设计意图中的字体(Inter、Source Serif 4、JetBrains Mono、Roboto、Playfair Display 等)只要在 Google Fonts 上提供,都会自动安装。

  3. CSS / Mac / Win 系统字体中没有 Google Fonts 对应字体的,会通过 html_to_pptx.py 中的 FONT_ALIASES 映射到已安装的等效字体(Inter、JetBrains Mono、Source Serif 4),同时用于浏览器端的 fontconfig 别名和 PPT 端的 run.font.name。

验证输出

# Open the last round's PNG; compare with the HTML render PNG:
ls /tmp/uframe_round_*.png
# soffice → PDF → PNG at 96 DPI to match playwright (DPI mismatch = false font-size-look-smaller bug)

重要:所有地方都使用 dpi=96。对比 PNG 中的 DPI 不匹配会造成视觉尺寸差异,看起来像是字体大小错误,但实际上并非如此。

soffice 渲染 ≠ PowerPoint 渲染。 务必在实际的 PowerPoint(Mac/Win)中检查最终的 .pptx。soffice 在阴影模糊、字体整形器字距调整和渐变色标方面经常存在差异。

架构

HTML
  ↓ [playwright chromium] render + DOM walk
  ↓ getComputedStyle on every visible element
  ↓ canvas.fillStyle = anyColor → normalized rgba()
DOM extract (cached as <name>_dom.json)
  ├─ elements   → boxes (bg/border/gradient/shadow) + images (with object-fit + decoration tile)
  └─ text_blocks → block-level (p/li/h1-h6/figcaption/td/th) with inline runs
                   (incl. ::before/::after pseudo-element content as inherited-style runs)
  ↓ [python-pptx + lxml] generate native shapes (Z-order by DOM depth)
PPTX
  - Picture (object-fit:contain math → centered, letterboxed inside content area = bbox - padding)
    + optional decoration tile UNDER picture (CSS background-color/border-radius/box-shadow)
    + SVG → PNG via cairosvg before embed
  - Rectangle / RoundedRect (CSS border-radius → exact roundRect adj)
    + solid fill / linear gradient (gradFill XML)
    + border (line.color/width)
    + box-shadow (outerShdw effect)
  - TextBox per block element
    + multiple inline Runs (one per <strong>/<em>/text node/pseudo-element)
    + CSS padding → tf.margin_*
    + CSS line-height → absolute Pt line_spacing
    + CSS text-transform applied per-run (so ::before uppercase doesn't inherit paragraph 'none')
    + CSS letter-spacing → OOXML rPr spc
    + CSS hyphens:auto → pyphen-inserted U+00AD soft hyphens
    + <li> → native OOXML <a:buChar> with hanging indent + section color marker
    + overflow:hidden + line-clamp → PIL-measured truncation + "…"
    + single-word short text (≤6 chars, no spaces) → word_wrap=False (honors browser-proven fit)
PPTX (final)
  ↓ [optional: --vision-audit] Claude vision diff (html_print.png vs ppt.png)
  ↓ structured fidelity report (<name>_audit.json): 12 categories × 3 severities
  ↓ delta vs previous audit if one exists → dev-cycle smoke test

功能表

功能状态
位置 / 尺寸像素级精准✓
计算后的颜色(oklab / color-mix / color() / hsl / 命名颜色)✓ 通过 canvas 实现
Alpha 合成(rgba 的 α<1 → 与白色合成)✓
同一段落中的行内 <strong>/<em> 作为文本运行✓
章节彩色横幅(h3 背景 + 文本 + 编号标记)✓
线性渐变✓ (gradFill)
盒阴影✓ (outerShdw)
圆角(精确 CSS px → roundRect adj)✓
各边单独设置边框(border-top/right/bottom/left、不对称)✓ 每个存在的边都使用细 Rect
行内文本背景 → 文本运行高亮(文本突出显示颜色)✓ 符合架构规范的 rPr 顺序
上标 / 下标(<sup>/<sub> 或 CSS vertical-align)✓ 基线偏移 + 可读性下限
图片 object-fit:contain(在边界框内留白)✓
CSS 内边距 → 文本框边距✓
CSS 绝对行高(消除尾随空白)(需要时采用)
CSS hyphens:auto(libhyphen → pyphen 软连字符)✓
带悬挂缩进和章节颜色的原生 OOXML 项目符号✓
overflow:hidden + line-clamp 截断✓
从 @page { size: ... } 自动检测画布尺寸✓
将幻灯片限制为 PPT 56" 并按比例缩放✓
从 Google Fonts 自动下载字体✓(通过 font_resolver)
自动检测同级 poster.pdf → 提取其中字体并建立别名映射✓ 存在时
将 CSS ::before/::after 生成内容作为继承样式的文本运行✓(支持“So what →”提示框、内容箭头图标)
每个文本运行的 text-transform 覆盖(伪内容大写,不受段落 'none' 影响)✓
<img> 装饰底板(透明 PNG logo 下方的白色圆角矩形)✓(CSS background-color + border-radius + padding)
SVG 嵌入(通过 cairosvg 栅格化 → PNG)✓
单词较短的文本 → word_wrap=False(如 ICLR/ICML 徽章)✓(≤6 个字符,且不含空格)
视觉审计保真度报告(Claude 视觉差异,12 个类别)✓ 默认开启(每张海报约 $0.02;无认证时静默跳过)
自主代码修复循环(在隔离的技能副本中运行 claude-p 子 Agent)✓ 通过 scripts/auto_fix_loop.py(每次运行约 $0.50-1.50;发布的技能文件不会被修改)
跨海报系统性错误聚合✓ 通过 scripts/vision_aggregate.py
溢出时闭环缩小字体(L2)✗ 已于 2026-06-05 移除(PIL 预测与 soffice 解耦,导致其不起作用且可能产生误报;已由 --vision-audit 替代)
匹配换行(强制 PPT 在浏览器位置换行)✗ 默认关闭;可通过标志启用
在 pptx 中嵌入字体(跨机器可移植性)✗(第 3 阶段待定)
KaTeX 数学公式✗(第 4 阶段使用 PNG 回退方案)
CSS transforms / filters✗(第 4 阶段使用 PNG 回退方案)

脚本

  • scripts/html_to_pptx.py — DOM 提取 + PPTX 构建(接受旧版 --corrections,以及用于强制浏览器换行位置的 --match-wrap)。支持提取 ::before/::after 伪元素内容(例如「所以呢 →」等 CSS 标注)、逐文本运行的 text-transform、<img> 装饰图块(透明 PNG 徽标下方的白色圆角矩形),以及通过 cairosvg 栅格化 SVG。
  • scripts/auto_correct_loop.py — 规范入口:单次执行 DOM 提取 → 构建 → 渲染 → 生成 PNG 对比图。处理同目录 PDF 的字体别名和 Google Fonts 自动下载。默认输出目录 = dirname(input_html)/(与输入文件位于同一目录)。启用 --vision-audit(默认开启)时,会在渲染后运行视觉差异检查。
  • scripts/auto_fix_loop.py — 自主修复循环:将技能脚本复制到隔离的 output/<ts>/_skill_run_copy/,每轮启动一次 claude -p,修复副本中的首要审计问题(通过 --add-dir 进行沙箱隔离),然后重新构建、重新审计,并通过副本内部的 git 保留或回滚。发布的技能保持不变;每次运行的差异会导出,供人工挑选合并。
  • scripts/vision_audit.py — Claude 视觉保真度审计器。接收 (html_truth.png, ppt.png, dom.json) → 结构化问题列表,归类为 12 个类别(missing_element、wrap_mismatch、text_clipped、color_drift 等),并标注严重程度和 block_idx。替代了已弃用的基于 PIL 的 L2 循环。
  • scripts/vision_aggregate.py — 跨海报类别频次汇总。遍历 <root>/*/poster_audit.json,打印反复出现的错误及其频次,从而揭示 SYSTEMIC(系统性)问题,而非单次问题。
  • scripts/font_resolver.py — Google Fonts 自动下载 + 同目录 PDF 字体检测 + fontconfig 运行时别名

为何优于基于像素的 PDF→PPTX 转换器

→ 参见 difference.md — 相较于 iLovePDF / Smallpdf 风格的栅格转换器的具体优势:行内文本高亮作为文本运行属性(而非浮动形状)、原生列表项目符号(而非孤立字形)、粗体保留字体系列(而非相似替代字体),以及其他原生语义相较于像素图像的保留优势。

注意事项

→ 参见 GOTCHAS.md — 记录了每种不易察觉的故障模式及其根本原因和修复方法,均源自生产环境中的实际问题。

快速链接:

  • G1:字体名称与字体系列(Inter Variable ≠ Inter)
  • G2:soffice ≠ PowerPoint(务必在 PowerPoint 中进行检查)
  • G3:PNG 对比的 DPI 一致性
  • G4:line_spacing 仅在字体正确时生效
  • G5:CSS color-mix 返回 oklab — 通过 canvas 进行规范化
  • G6:isInlineOnly 基于标签名称,而非 CSS display
  • G7:h3 编号标记(跳过装饰,重新着色文本)
  • G8:object-fit:contain — 手动计算留白
  • G9:通过 pyphen + U+00AD 实现 hyphens:auto
  • G10:::marker 是生成内容 — 使用 OOXML 原生项目符号
  • G11:Mac 版 PowerPoint 也需要安装字体
  • G12:可变字体会使 fontconfig 混淆 — 使用静态字重
  • G15:<img> 装饰图块必须渲染在图片下方(透明徽标下方放置白色图块)
  • G16:单词较短的文本 → 设置 word_wrap=False(ICLR/ICML 徽标)
  • G17:DOM 遍历器无法识别 ::before/::after — 通过 getComputedStyle(el, '::before') 获取
  • G18:视觉审计误报:宽边界框中的左对齐内容看起来像居中

依赖项

软件包用途
playwright用于 DOM 提取的 chromium
python-pptxOOXML 构建 API
lxmlpython-pptx 不支持时直接操作 OOXML(渐变、阴影、项目符号)
Pillow图像解码 + 文本测量
pdf2imagePDF → PNG 预览
pyphen插入软连字符以实现 CSS hyphens:auto
cairosvg嵌入前将 SVG <img> 栅格化为 PNG(PIL 无法解码 SVG)

可选(用于 --vision-audit): | ANTHROPIC_AUTH_TOKEN | 用于视觉差异检查的 Claude API 身份验证 |

用于验证:

libreoffice通过 soffice 将 PPTX 转换为 PDF
poppler-utilspdf2image 的二进制后端(pdftoppm)

路线图

  • Phase 3(待定):在 pptx 中嵌入 Web 字体(ppt/fonts/*.fntdata + embeddedFontLst)。此方案可解决 Mac/Win 上的“缺少字体”问题,但每个 pptx 文件会增加约 3 MB。
  • Phase 4(待定):为不受支持的子树(KaTeX 数学公式、复杂 SVG、CSS 变换)提供 PNG 备用方案。

评论

支持 Markdown