PPTX SVG 图片 PNG 兜底修复(可传播技能)
一、背景与根因
PowerPoint 插入 SVG 时,文件内部会同时存两份:
- SVG(矢量):清晰、可任意缩放,是"真正"的图片内容;
- PNG(光栅):SVG 的快照,作为"光栅兜底"——很多网站/在线解析器看不懂 SVG,就会回退显示这张 PNG。
正常 XML 形如:
<a:blip r:embed="PNG_rId">
<a:extLst>
<a:ext uri="...svgBlip">
<asvg:svgBlip r:embed="SVG_rId"/>
</a:ext>
</a:extLst>
</a:blip>
即 <a:blip> 用主 r:embed 指向 PNG,再用 <asvg:svgBlip> 指向 SVG 编辑副本。
故障形态:XML 里只写了 asvg:svgBlip、漏了主 r:embed,且 media 里根本没有那张兜底 PNG。PowerPoint 本地用 SVG 能显示,但网站渲染器找不到兜底 PNG → 整块空白。
二、判定(先看是不是这个病)
对任意 slide xml,找所有 <a:blip>:
- 含 <asvg:svgBlip>,且该 blip 没有主 r:embed(或主引用指向的不是有效 PNG)→ 即"SVG 缺兜底"。
- ⚠️ 普通 .jpg/.gif/.jpeg 光栅图本来就没有 svgBlip,不要误判为问题(早期误报的根因)。
快速检测:用 scan_dir.py 扫目录,或 validate.py 校验单个文件,或 fix_path.py(会自动预判、只修真有问题的)。
三、环境自检(代理人自动执行,用户无需手动)
技能被触发后,代理人先跑 check_env.py 检测环境,无需用户碰终端:
- Python 3:本脚本能运行即已满足(标准库即可,无需 pip 装包)。
- Node.js:调用 resvg 必需。优先探测 WorkBuddy managed 运行时(任意用户名/版本),其次 PATH。
- @resvg/resvg-js:纯 WASM 渲染库。若缺失且 Node 可用,代理人自动执行安装(setup.install_resvg),装好再继续。
- 仅当 Node.js 也缺失(连 managed runtime 都没有)时,代理人会明确提示用户安装 Node.js,无法自动继续。
> 关键点:fix_path.py 在修复前会调用 check_env.ensure_ready(),所以用户只要把文件拖进来,环境不够时代理会先装好依赖再修——全程用户不用自己敲命令。
>
> ⚠️ 用户不要自己去终端跑这些脚本。所有 python xxx.py 命令都由代理人在对话中执行,结果用 present_files 交回。
四、使用方法(拖拽即修,代理人代跑)
本技能的正确用法:用户把文件/文件夹拖进对话框(或说一句话),代理人一键完成「环境自检→修复→校验→交回」。
场景 A:拖入单个 .pptx
代理人执行:
python check_env.py # 环境不足会自动装依赖
python fix_path.py "D:/课程教研/.../xxx.pptx"
fix_path.py自动:needs_fix预判 → 有破 SVG 则fix_pptx.py生成xxx_已修复PNG兜底.pptx→validate.py校验(必须 0 问题)。- 代理人用
present_files把xxx_已修复PNG兜底.pptx交回用户(不覆盖原文件,原文件永远安全)。
场景 B:拖入一个文件夹(批量课程目录)
python check_env.py
python fix_path.py "D:/课程教研/.../一级课件V2.0"
- 递归扫描目录下所有
.pptx,只修复含破 SVG 的课件,自动跳过已完好、*_svg.pptx备份、*_已修复PNG兜底.pptx产物(防重复/递归)。 - 末尾打印汇总:
[fixed]/[skip]/[error]三态 + 每个修复产物路径。 - 全部修复产物仍用
present_files交回。
覆盖原文件的约定(可选,需用户确认)
默认交付 _已修复PNG兜底.pptx,不动原图。若用户明确要求覆盖正课:
cp 原.pptx 原_svg.pptx # 先备份真·原图
mv 原_已修复PNG兜底.pptx 原.pptx
对话示例(用户只看这一份就够了)
用户:(把文件夹「一级课件V2.0」拖进对话框)
帮我修一下这个课程文件夹里的 PPT,网站上看 SVG 图片都是空白的。
助手:收到。我先检测环境,再把缺 PNG 兜底的 SVG 全部补上。
▸ 运行 check_env.py
[Python] 3.13 OK [Node] v22 OK [resvg] @resvg/resvg-js OK
环境就绪,开始扫描并修复…
▸ 运行 fix_path.py "D:/…/一级课件V2.0"
=== 汇总 ===
[fixed] 新的伙伴-教案.pptx -> 新的伙伴-教案_已修复PNG兜底.pptx
[fixed] 距离测试.pptx -> 距离测试_已修复PNG兜底.pptx
[fixed] 凌波微步.pptx -> 凌波微步_已修复PNG兜底.pptx
[fixed] 遥控器按键-svg问题.pptx -> 遥控器按键-svg问题_已修复PNG兜底.pptx
完成: 修复 4 / 跳过 38 / 失败 0
全部修复产物已通过 validate.py(问题=0),网站解析可正常显示、不变形。
(调用 present_files 交回 4 个修复文件)
已生成 4 个修复文件(未覆盖原文件)。确认无误后我可帮你备份原图并覆盖正课,或直接手动替换。
用户:覆盖吧。
助手:▸ cp 原.pptx 原_svg.pptx;mv 原_已修复PNG兜底.pptx 原.pptx
已覆盖,原图均已备份为 *_svg.pptx,可随时回滚。
五、修复原理
- 扫描所有
.rels,找出被引用的*.svg(通过relationships/image类型 +.svg后缀)。 - 为每个 SVG 关系复制一份指向同名
.png的新关系,分配新 rId(SVG_rId → PNG_rId)。 - 用
@resvg/resvg-js(纯 WASM,无原生依赖)把每个 SVG 渲染成透明背景的 PNG,写入ppt/media/。 - 在每个 slide xml 里,给含
asvg:svgBlip的<a:blip>补上主r:embed="PNG_rId",保留<a:extLst>/<asvg:svgBlip>扩展(PowerPoint 仍能继续编辑矢量图)。 - 输出
<原名>_已修复PNG兜底.pptx(不覆盖原文件,安全)。
六、完整工作流(手动分步,便于排查)
针对想逐节精修/排错的场景(同样由代理人执行,非用户手动):
python check_env.py # 环境自检 + 缺依赖自动装
python scan_dir.py "一级课件V2.0" # 看哪些课件有破 SVG
python fix_pptx.py "机械爪.pptx" 3 # 生成 机械爪_已修复PNG兜底.pptx
python validate.py 机械爪_已修复PNG兜底.pptx ... # 必须 0 问题
七、关键坑(对话里逐个踩过、已修复,必读)
- 自闭合 blip 导致漏修(最致命):旧逻辑遇自闭合光栅图
<a:blip r:embed="rIdX"/>因找不到</a:blip>而break,漏修其后所有破 SVG。本技能fix_part_xml已正确处理自闭合 blip;validate.py查"兜底完整性"可 100% 暴露漏修。 - 渲染 PNG 比例变形(第28节 47/65 页根因):修复只改
<a:blip>引用、绝不改<p:xfrm>;resvg按 SVG 原始viewBox渲染,validate.py额外做比例一致性检查(误差<2%),变形立即报出。 - OOXML 相对路径基准:rels 里
Target="../media/imageX.png"相对部件目录ppt/slides/解析(非_rels/)。校验解析要用os.path.dirname(slide_part)。 - 不要把 jpg/gif 当 bug:只有带
asvg:svgBlip且缺有效主引用的才算破 SVG。 - 校验签名:修复后每个 SVG-blip 主
r:embed指向ppt/media/下以\x89PNG开头的真实 PNG(>100B)。validate.py已内置。 - 跨机器可传播:
find_node()与render_svg.js加载 resvg 时用glob/os.homedir()自动探测 WorkBuddy managed 运行时(任意用户名、任意版本),不再写死本机路径。拷贝到任何装有 Python3 + Node.js 的电脑均可直接运行。
八、依赖与安装
- 运行时:Python 3(标准库即可);Node.js(调用 resvg)。
- 依赖:
@resvg/resvg-js(纯 WASM)。无需用户手动安装——代理人首次使用时check_env.py/fix_path.py会自动探测并安装到技能目录。 - 离线/无网络:若目标机已具备 WorkBuddy managed node 运行时,
render_svg.js会优先回退到其node_modules,无需安装。
九、脚本清单(本技能目录,全部由代理人调用)
| 文件 | 作用 |
|---|---|
fix_path.py |
拖拽即修一键入口:吞下单个 .pptx 或文件夹,自动预判→修复→校验→汇总(最常用) |
check_env.py |
环境自检:检测 Python/Node/resvg,缺 resvg 自动安装;ensure_ready() 供 fix_path 复用 |
fix_pptx.py |
核心修复:补 PNG 主引用 + 渲染写入 media + 输出 _已修复PNG兜底.pptx |
render_svg.js |
SVG→透明 PNG 渲染器(resvg,scale 默认 3) |
validate.py |
严格校验:兜底完整性 + 比例不变形;退出码 0/1 |
scan_dir.py |
扫描目录,统计每个课件 SVG/破/已修,输出待修清单 |
setup.py |
安装依赖 @resvg/resvg-js(供 check_env 复用 find_node/install_resvg) |
十、验证标准(交付前必跑)
python validate.py 交付1.pptx 交付2.pptx ...
# 期望:每行 [OK] ... 问题=0;末尾 "✓ 全部通过"
只要 validate.py 报 0 问题,即可确认:所有破 SVG 都已加 PNG 兜底,且渲染 PNG 比例与图片框一致,网站解析能正常显示、不会变形。
十一、排障小贴士
- 中文路径报「路径不存在」:个别 shell 下 Python 对中文 argv 解码错位。命令前加
PYTHONUTF8=1即可(PYTHONUTF8=1 python fix_path.py "中文路径.pptx");或用 WorkBuddy 拖拽给出的完整字面值路径(通常无需此开关)。 validate.py报比例问题:说明某 SVG 渲染比例与图片框不一致(多为该 SVG 无 viewBox)。检查源 SVG,必要时为其补viewBox后重渲染(scale只影响清晰度、不变形)。check_env.py报找不到 node:目标机没装 Node.js 且没 WorkBuddy managed runtime。请用户安装 Node.js(含 npm)后重试,代理人会重新自检。