Skip to content

Add PPTExporter with PPTX export support for PAGX documents#3361

Open
OnionsYu wants to merge 66 commits intoTencent:mainfrom
OnionsYu:feature/onionsyu_export_ppt2
Open

Add PPTExporter with PPTX export support for PAGX documents#3361
OnionsYu wants to merge 66 commits intoTencent:mainfrom
OnionsYu:feature/onionsyu_export_ppt2

Conversation

@OnionsYu
Copy link
Copy Markdown
Contributor

@OnionsYu OnionsYu commented Apr 3, 2026

新增 PPT 导出功能,支持将 PAGX 文档导出为 PPTX 格式。

主要变更:

  • 新增 PPTExporter,支持形状、文本、图片填充、渐变、描边、阴影、蒙版等元素导出为 PPTX
  • 提取 ExporterUtils 公共工具模块,供 SVG 和 PPT 导出器共用
  • 重构 SVGExporter 和 SVGTextLayout 复用 ExporterUtils 中的共享方法
  • 在 CLI CommandExport 中集成 PPT 导出命令
  • 新增 PPT 导出测试用例

@OnionsYu OnionsYu force-pushed the feature/onionsyu_export_ppt2 branch from 1bc505f to cdaf2a3 Compare April 3, 2026 08:07
@codecov-commenter
Copy link
Copy Markdown

codecov-commenter commented Apr 3, 2026

Codecov Report

❌ Patch coverage is 88.69180% with 306 lines in your changes missing coverage. Please review.
✅ Project coverage is 80.18%. Comparing base (ed723d4) to head (3ef19a8).

Files with missing lines Patch % Lines
src/pagx/ppt/PPTExporter.cpp 85.29% 83 Missing and 42 partials ⚠️
src/pagx/utils/ExporterUtils.cpp 74.62% 62 Missing and 39 partials ⚠️
src/pagx/xml/XMLBuilder.h 77.65% 23 Missing and 17 partials ⚠️
src/cli/CommandExport.cpp 71.73% 7 Missing and 6 partials ⚠️
src/pagx/ppt/PPTContourUtils.cpp 91.94% 2 Missing and 10 partials ⚠️
src/pagx/ppt/PPTWriterContext.h 88.37% 3 Missing and 2 partials ⚠️
src/pagx/ppt/PPTBoilerplate.cpp 95.23% 0 Missing and 4 partials ⚠️
src/pagx/ppt/PPTGeomEmitter.cpp 96.61% 2 Missing and 2 partials ⚠️
src/pagx/svg/SVGExporter.cpp 88.23% 2 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main    #3361      +/-   ##
==========================================
+ Coverage   78.22%   80.18%   +1.96%     
==========================================
  Files         529      541      +12     
  Lines       40527    45295    +4768     
  Branches    12234    12767     +533     
==========================================
+ Hits        31701    36321    +4620     
- Misses       6349     6400      +51     
- Partials     2477     2574      +97     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

Comment thread src/pagx/ppt/PPTExporter.cpp Outdated
Comment thread test/src/PAGXPPTTest.cpp Outdated
@OnionsYu OnionsYu force-pushed the feature/onionsyu_export_ppt2 branch from 56f6b20 to 664c2dd Compare April 13, 2026 02:54
@OnionsYu OnionsYu force-pushed the feature/onionsyu_export_ppt2 branch from df0a742 to 4a3415f Compare April 13, 2026 06:33
Copy link
Copy Markdown
Collaborator

@shlzxjp shlzxjp left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review 第二轮:之前的26条评论中绝大多数已确认修复(包括 const_cast、静态常量命名、Xform初始化、UTF-8字符数、lambda消除、幻灯片等比缩放、zipWrite返回值检查等),修复质量很好。本轮新发现 12 个问题(1 Critical、3 Major、8 Minor),详见行级评论。

Comment thread CMakeLists.txt
Comment thread src/pagx/ppt/PPTExporter.cpp Outdated
Comment thread src/pagx/ppt/PPTContourUtils.cpp
Comment thread src/pagx/utils/ExporterUtils.cpp Outdated
Comment thread src/cli/CommandExport.cpp
Comment thread src/pagx/utils/ExporterUtils.cpp Outdated
Comment thread src/pagx/utils/ExporterUtils.cpp Outdated
Comment thread include/pagx/SVGExporter.h
Comment thread src/pagx/ppt/PPTContourUtils.cpp
Comment thread src/pagx/ppt/PPTWriterContext.h Outdated
Comment thread src/cli/CommandExport.cpp
Comment thread src/pagx/ppt/PPTExporter.cpp Outdated
Copy link
Copy Markdown
Collaborator

@shlzxjp shlzxjp left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review 第三轮:新发现 10 个问题(1 Critical、4 Major、5 Minor),详见行级评论。

ok = ok && AddZipString(zf, "ppt/slides/slide1.xml", slide);
ok = ok && AddZipString(zf, "ppt/slides/_rels/slide1.xml.rels", GenerateSlideRels(context));
ok = ok && AddZipString(zf, "ppt/slideMasters/slideMaster1.xml", GenerateSlideMaster());
ok = ok &&
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[Critical] ToFile 中16个 AddZipString 调用和 AddZipEntry 循环的返回值全部被丢弃。任何一步写入失败后仍继续写入后续条目,最终只靠 zipClose 判断成败,但此时已产生部分写入的损坏文件。建议用 bool ok = true; ok = ok && AddZipString(...); 链式检查,首次失败即 zipClose 并返回 false。

.closeElementSelfClosing();
out.closeElement(); // a:path
out.closeElement(); // a:gradFill
break;
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[Major] RadialGradient 导出硬编码 fillToRect l/t/r/b=50000,渐变中心始终在形状正中。但 RadialGradient 节点有 matrixstartPointendPoint 等属性控制渐变位置,全部被忽略。如果 PAGX 文档中径向渐变中心偏移,导出结果将不正确。

}
if (hasItalic) {
out.addRequiredAttribute("i", "1");
}
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[Major] writeNativeText 只处理 SolidColor 填充,遇到 LinearGradientRadialGradientImagePattern 时直接跳过,文本将以默认黑色显示且无任何警告。OOXML 的 a:rPr 支持 a:gradFill,建议至少对渐变填充做基本支持,或添加 fallback 提取渐变首色作为纯色近似。

out.openElement("a:ln").closeElementStart();
out.openElement("a:noFill").closeElementSelfClosing();
out.closeElement();
writeEffects(out, filters);
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[Major] writeEffectsp:spPr 内调用,阴影效果应用于整个文本框形状而非文本本身。OOXML 中文本阴影应通过 a:rPr 内的效果属性应用,否则阴影会出现在文本框边界而非文字轮廓上,视觉效果不正确。

Comment thread src/pagx/ppt/PPTGeomEmitter.h Outdated
void writePicture(XMLBuilder& out, const std::string& relId, int64_t offX, int64_t offY,
int64_t extCX, int64_t extCY);

// Write non-tiling ImagePattern fill as a separate p:pic element.
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[Minor] DecomposeScale 实现了关键的矩阵分解逻辑(被 decomposeXformwriteTextAsPath 使用),但作为文件级 static 函数无法被单元测试覆盖。建议移入 ExporterUtils 使其可测试。

Comment thread src/pagx/ppt/PPTExporter.cpp
float maxY = std::numeric_limits<float>::lowest();
for (const auto& contour : allContours) {
ExpandBounds(minX, minY, maxX, maxY, contour.start);
for (const auto& seg : contour.segs) {
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[Minor] writeTextAsPath 的 bounds 计算只遍历轮廓端点(start + seg endpoints),对于 cubic bezier 段,曲线实际范围可能超出端点围成的区域。字形路径段密度高,实际偏差很小,但在极端情况下可能导致裁剪。建议添加注释说明此为端点近似。

}
}
}

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[Minor] 内层轮廓归属查找用 break 选择第一个(按数组顺序)包含它的 depth=0 轮廓。如果存在多个不相交的外层轮廓,且因端点近似误差导致 PointInsideContour 误判,可能将内层轮廓归错组。概率低但逻辑上存在,建议添加注释说明此限制。

Comment thread src/pagx/ppt/PPTExporter.cpp
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants