PPTX → 单文件 HTML
概述
把 .pptx 变成一个 .html 文件:双击即开、无需联网、可直接分享。
两条渲染通道并存,由每条页面的内容自动选择:
| 通道 | 适用 | 输出特性 |
|---|---|---|
| 结构化重建(默认) | 文字、图片、表格、自选图形、连线、渐变、阴影、动画 | 文字可选中/可搜索/可复制,体积小,动画按 PPT 时序播放 |
| 矢量快照(自动降级) | 图表、SmartArt、公式、OLE、3D 等无法可靠重建的元素 | 用 PowerPoint 自己渲染成 SVG 整页嵌入,像素级保真,文字仍可选中 |
判定标准见 references/fidelity-rules.md。硬性不可还原元素所在页整页降级,其余页保持结构化。
放映交互(内置,无需配置)
播放器自带四套课堂交互,全部离线可用。工具栏在底端中央竖直三行:翻页(上)→ 画笔(中)→ 移动/视图(下),鼠标停留 2 秒自动隐藏。
| 功能 | 入口 | 说明 |
|---|---|---|
| 逐步导航 | 底部中央 ‹ / › 箭头按钮 | 语义是「上一步 / 下一步」而不是整页翻页:按 PPT 源文件的动画顺序逐格推进——先播完本页动画各步,步用尽才翻到下一页;回退同理,本页退到第 0 步才回上一页。页码右侧显示 动画 1/3 为本页动画进度;处于第一步/最后一步时对应箭头自动变暗 |
| 四条前进通道 | 均为下一步 / 上一步 | ① 单击 ‹ / › 箭头按钮;② 触屏或鼠标在空白处滑动:向左滑=下一步,向右滑=上一步(位移>50px 且明显横向才判定,上下拖不误触);③ 滚轮:下滚=下一步、上滚=上一步,触控板横向滑动同样有效(320ms 节流防一格连跳多步);④ 方向键 / 空格 / PageUp·Down。点文字或形状不触发,留给双击编辑 |
| 画笔批注 | P 或工具栏「画笔」 |
8 色色板(红橙黄绿青蓝紫黑,合并为一个颜色按钮,单击在按钮上方弹出)+ 荧光笔(H)+ 橡皮(E)+ 滑动条调粗细 + 撤销(Z)+ 清页。跟随鼠标的圆形光标实时反映笔尖/橡皮大小。每页独立画布,翻页保留笔迹,刷新后仍在(localStorage 持久化) |
| 移动素材 | V 或工具栏「移动」 |
拖拽任意形状/图片/表格/文本框。默认翻页自动复位;「锁定」可跨页保留;「复位素材」清当前页 |
| 编辑文字 | 双击任意文本框 | 进入 contenteditable 就地编辑,蓝色边框提示编辑态,Esc 或点空白退出。进入编辑时自动把首个 run 的字体/字号/颜色提升到容器,清空重打也不会丢样式 |
注意:带动画的页面,一次「下一步」只推进一个动画步,步用尽后才翻页——与 PowerPoint 放映语义一致。回退时只把最后一步置回未播放态,前面的步骤保持已显示,不会整屏闪一下重播。
Esc 一键退出工具模式回到放映。
> 实现约定(改渲染逻辑前必读):
> 1. 形状的 transform 以 translate(var(--p2h-dx,0px),var(--p2h-dy,0px)) 开头,
> 移动只改这两个 CSS 变量,不碰 rotate/flip,因此拖拽旋转过的元素也不会破坏原变换。
> 2. slide 的 transform 是 translate(-50%,-50%) scale(var(--p2h-fit)),--p2h-fit 由 JS 按视口计算。
> 画笔落点、拖拽位移、光标大小的坐标换算一律读 --p2h-fit。
> 3. 滑动条是画笔/橡皮复用的:画笔/荧光模式 min=1 max=40,橡皮模式 min=0 max=100,
> 切模式时由 reflectUI() 动态改 slider 的 min/max——新增粗细档位时改这里,不要加第二根滑动条。
> 4. 画笔画布 z-index 30,跟随光标 40,工具栏 50,色板 55(挂在颜色按钮内,absolute 定位到按钮上方)——画笔层在内容之上、工具栏之下。
> 5. 导航状态是 (cur, step) 二元组:next() 先 playStep(cur, step) 再 step++,步用尽才 show(cur+1);
> prev() 先 step-- 再 setStepState(cur, step, false)——回退只改终态、不重放前序动画(重放会整屏闪烁)。
> 跳页(缩略图 / Home / End)走 show(i, true),用 setStepState 直接落终态而非逐帧播放。
> 新增导航入口时统一调用 next() / prev(),不要直接操作 cur。
> 6. 元素的退出动画「延时隐藏」定时器挂在 el.__p2hExitT 上,resetSlide / setStepState 必须 clearTimeout——
> 否则翻页后定时器迟到触发,会把已重置的元素永久置为 hidden。
快速开始
# 环境(隔离 venv,首次会自动装 python-pptx)
PY="C:/Users/lixianyong/.workbuddy/binaries/python/envs/default/Scripts/python.exe"
SK="C:/Users/lixianyong/.workbuddy/skills/pptx-to-html"
# 转换(最常用)
"$PY" "$SK/scripts/convert.py" 课件.pptx -o out/
# → out/课件.html (单文件,含图片/动画/播放器)
# → out/report.json (保真报告:降级页、问题项、缺失字体)
工作流程
第 1 步:确认输入与意图
先确认三件事,缺一不可:
.pptx的绝对路径(.ppt旧格式需先另存为.pptx)。- 用途:放映(要动画/全屏)还是阅读(要能复制文字)——决定
--mode。 - 是否需要像素级一致:若用户说「一模一样」「不能有一点差别」,用
--mode snapshot。
第 2 步:选择模式
| 场景 | 命令 |
|---|---|
| 默认,最大兼容 | convert.py deck.pptx -o out/ |
| 全篇像素级保真,接受文字不可编辑 | --mode snapshot |
| 强制不调用 Office(无 PowerPoint / 需纯离线解析) | --mode structured |
| 结构优先但对艺术字等也要求严格 | --strict |
| 指定某些页必须快照 | --snapshot-pages 1,7,12 |
| 想改 HTML 源码而非单文件 | --external |
第 3 步:读取保真报告
转换结束必须读 out/report.json,并用自然语言向用户交代:
snapshot_slides:哪些页走了快照,为什么;issues:hard:*已由快照兜底;soft:*为近似还原,需主动说明;fonts.missing:缺失字体会导致浏览器替换、排版偏移,务必提示用户装字体或对这些页强制快照。
第 4 步:视觉校验(重要,不可跳过)
结构化重建存在近似项,交付前用无头浏览器逐页截图,与 PowerPoint 原稿比对:
EDGE="C:/Program Files (x86)/Microsoft/Edge/Application/msedge.exe"
# 逐页截图(hash 指定页码;截图路径用反斜杠,URL 用正斜杠)
"$EDGE" --headless=new --disable-gpu --hide-scrollbars --virtual-time-budget=3000 \
--screenshot="D:\\abs\\shot_2.png" --window-size=1400,800 \
--user-data-dir="C:\\Users\\lixianyong\\AppData\\Local\\Temp\\p2h2" \
'file:///D:/abs/out/deck.html#2'
重点核对:字号/字重/颜色是否生效、文本是否溢出或被裁切、形状几何(圆角/箭头/三角形)是否走形、表格列宽、图片位置与裁剪。
发现某页明显偏差 → 把该页加入 --snapshot-pages 重跑,这是最省事的收敛手段。
第 5 步:交付
用 present_files 展示 HTML 文件,并附一句保真说明(哪些页是重建、哪些页是快照、有无缺失字体)。
若用户场景是课堂讲评/放映,顺带提一句交互快捷键(P 画笔 / H 荧光 / E 橡皮 / V 移动素材 / 双击文字就地编辑 / ← → 上一步·下一步),这是该 skill 相对截图转 PPT 的核心增量。
关键约定与坑(务必遵守)
- 必须用隔离 venv 的 python 解释器(见上方
$PY),不要用裸python。 - 快照需要本机 PowerPoint(COM)。没有 Office 时
auto模式自动退化为全结构化渲染,不会失败,但复杂页会显示虚线占位框并计入issues。此时应主动告知用户。 - PowerPoint COM 会短暂启动后台进程。脚本已在
finally中Quit();若转换后 PowerPoint 残留进程,手动结束POWERPNT.EXE。 - 字体占位符:PPT 里的
+mn-ea/+mj-lt是主题字体引用,脚本会解析成真实字体名。若主题字体本机没有,浏览器会替换 —— 这是排版偏移最常见的根因。 - 不要试图手改
ir.json,它是中间产物;要调整样式请改scripts/下的解析/渲染逻辑,或对具体页用快照。 - 单文件 HTML 体积 ≈ 素材总量 × 1.37(base64)。超过约 40MB 时建议改用
--external输出目录形式。
参数速查
convert.py <deck.pptx> -o <outdir>
--mode {auto,structured,snapshot} 默认 auto
--strict soft 级问题也整页快照
--snapshot-pages 1,4 强制指定页快照(1-based)
--scale 2.0 PNG 快照倍率(SVG 不可用时兜底)
--external 媒体不内联,输出 html + media/
--name x.html 自定义输出文件名
--title "标题" 自定义网页标题
--no-office 禁止调用 PowerPoint COM
底层脚本也可单独调用:pptx2ir.py(PPTX→IR JSON)、ir2html.py(IR→HTML)、office_snapshot.py(COM 导出 SVG/PNG)。
资源
scripts/convert.py— 一键入口,编排全流程并产出保真报告scripts/pptx2ir.py— 解析引擎:主题色/字体、填充、几何、表格、组合、动画时序scripts/ir2html.py— 渲染引擎:绝对定位 + SVG 几何 + 内联单文件 + 动画时间轴scripts/office_snapshot.py— PowerPoint COM 导出(SVG 优先,PDF→SVG 兜底,PNG 保底)assets/viewer.css/assets/viewer.js— 播放器(逐步导航、动画序列、画笔批注、素材移动、文字编辑、缩略图、备注、全屏、打印)references/fidelity-rules.md— 降级判定规则、能力边界、已知近似项references/animation-map.md— PPT 动画 → CSS 映射表与时序模型references/troubleshooting.md— 常见故障与排查路径