5.0 KiB
5.0 KiB
PPT 媒体导出经验总结
更新日期:2026-04-27
背景
PPT 导出不能只把画布里的图片、文本和形状转成静态元素。画布里的视频通常是“图片元素 + #video / isVideo 元数据”,音频可能是 type: 'audio' 节点,也可能是旧版音频图片卡。如果导出器只按普通图片分支处理,这些媒体要么被跳过,要么只剩一个不可播放的卡片。
这类问题的原则是:小媒体尽量嵌入,大媒体可见降级,失败不能静默消失。
经验原则
-
媒体识别要在普通图片分支之前。
- 视频元素经常仍是
type: 'image'。 - 识别信号包括
isVideo、videoType、#video、#merged-video和视频扩展名。 - 音频要同时兼容新音频节点和 legacy 音频图片卡。
- 视频元素经常仍是
-
嵌入前必须做大小保护。
- 默认单媒体上限保持 50MB。
- 先看
content-length,再流式读取并累计大小。 - 超限只降级当前元素,不中断整套 PPT 导出。
-
addMedia需要可看的封面。- PowerPoint 默认媒体封面容易变成灰色播放块。
- 视频优先使用
poster/previewImageUrl/thumbnail。 - 没有封面时,视频尝试用
<video> + canvas截 0.1s 首帧。 - 音频优先用封面图,没有封面时生成静态音频卡 PNG。
-
封面要转为稳定的 PNG。
pptxgenjs的媒体 cover 关系按 PNG 写入。- SVG、JPEG 或远程图片应尽量转成 PNG DataURL。
- 浏览器不支持 canvas 或跨域污染画布时,要回退默认封面或可见占位。
-
降级也要保留用户上下文。
- 超限、拉取失败、空文件都要有可见提示。
- 如果有原始 http(s) 链接,应给占位文本加 hyperlink。
- 有封面时先铺封面,再叠提示,避免导出页出现空白块。
代码层面固化的规则
1. 导出选项保持默认安全
ExportPPTOptions 中媒体相关选项应保持可选:
embedMedia?: boolean;
mediaSizeLimitBytes?: number;
默认策略:
embedMedia !== false时尝试嵌入。mediaSizeLimitBytes默认50 * 1024 * 1024。- UI 不额外暴露开关时,也能走默认安全策略。
2. 媒体拉取不能带站点凭据
导出媒体和封面时,fetch 应使用:
{
credentials: 'omit',
referrerPolicy: 'no-referrer',
}
这样能减少跨域资源请求时泄漏 cookie/referrer 的风险。
3. DataURL 是最终格式,不是读取策略
pptxgenjs.addMedia 需要 base64 DataURL,但读取阶段仍要控制内存:
- 远程媒体用 stream 逐块读。
- 达到上限立即取消 reader。
- 确认大小后再转 DataURL。
一句话:先限流,再编码。
4. 封面生成不应阻塞导出成功
媒体本体和封面可以并行解析,但封面失败不应让媒体嵌入失败。
推荐策略:
- 先试已有封面候选。
- 再试视频首帧或音频静态卡。
- 全部失败时让
pptxgenjs使用默认 cover。
5. 单元素失败局部降级
导出循环里每个元素都应独立 try/catch。媒体失败时:
- 添加可见占位。
- 尽量附原始链接。
- 继续导出后续元素和后续页面。
检查清单
- 视频 URL 带
#video时,导出后 PPT 中是可播放视频。 - 合并视频
#merged-video能清理 hash 后获取真实媒体。 - 新音频节点
type: 'audio' + audioUrl能导出为音频媒体。 - legacy 音频图片卡优先导出音频,而不是普通图片。
- 大于 50MB 的媒体不嵌入,但页面有封面/提示/链接。
- 封面优先使用现有 poster 或音频封面,避免灰色播放块。
- 无封面视频尽量截首帧,无封面音频生成静态音频卡。
- 单个媒体失败不影响其他页面导出。
验证建议
pnpm --filter @aitu/drawnix exec vitest run src/services/ppt/__tests__/ppt-export-service.test.ts
pnpm --filter @aitu/drawnix exec vitest run src/services/ppt/__tests__/ppt-frame-layout.test.ts src/services/ppt/__tests__/ppt-prompts.test.ts src/services/ppt/__tests__/ppt-export-service.test.ts
pnpm nx run drawnix:typecheck
git diff --check
提交备注模板
问题描述:
- PPT 下载导出时,画布视频和音频没有映射到 pptxgenjs.addMedia,下载后的 PPT 缺少可播放媒体。
- 媒体默认 cover 视觉效果差,容易出现灰色播放块。
修复思路:
- 在普通图片分支前识别视频和音频元素,小于上限时嵌入 PPT。
- 媒体拉取使用安全 fetch,并通过流式读取限制单媒体大小。
- 优先使用 poster/previewImageUrl/音频封面,没有封面时生成视频首帧或音频静态封面。
- 超限或失败时导出可见占位,并尽量保留原始链接。
更新代码架构:
- ExportPPTOptions 增加 embedMedia 和 mediaSizeLimitBytes。
- PPT 导出服务新增媒体解析、大小保护、封面解析和局部降级链路。
- 新增 ppt-export-service 单测覆盖视频、音频、legacy 音频卡和超限兜底。