Add PPTExporter with PPTX export support for PAGX documents#3361
Add PPTExporter with PPTX export support for PAGX documents#3361OnionsYu wants to merge 64 commits intoTencent:mainfrom
Conversation
…ile mode instead of stretch mode.
…ect ratio instead of tile mode.
…correct x-y order.
…tch when tileModeX or tileModeY is Repeat or Mirror.
…mage is smaller than the shape.
…mage pattern and shadow code.
1bc505f to
cdaf2a3
Compare
Codecov Report❌ Patch coverage is Additional details and impacted files@@ Coverage Diff @@
## main #3361 +/- ##
==========================================
+ Coverage 78.22% 80.23% +2.01%
==========================================
Files 529 540 +11
Lines 40527 45257 +4730
Branches 12234 12752 +518
==========================================
+ Hits 31701 36313 +4612
- Misses 6349 6376 +27
- Partials 2477 2568 +91 ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
…ents and shadows.
… methods and cache image type flags.
…and Keynote renderer compatibility.
# Conflicts: # src/pagx/PAGXExporter.cpp resolved by main version
… the removed size member.
56f6b20 to
664c2dd
Compare
… sites to descriptive method names.
…rt_ppt2 # Conflicts: # src/pagx/PAGXExporter.cpp resolved by origin/main(远端) version
…writeRawLine and writeComment methods.
…n and improve readability.
df0a742 to
4a3415f
Compare
…id test resource.
…sistent rendering across apps.
…ture constant, and extract tiled pattern render helper.
shlzxjp
left a comment
There was a problem hiding this comment.
Code Review 第二轮:之前的26条评论中绝大多数已确认修复(包括 const_cast、静态常量命名、Xform初始化、UTF-8字符数、lambda消除、幻灯片等比缩放、zipWrite返回值检查等),修复质量很好。本轮新发现 12 个问题(1 Critical、3 Major、8 Minor),详见行级评论。
| if (PAG_BUILD_SVG) | ||
| set(PAG_BUILD_PAGX ON) | ||
| endif () | ||
| if (PAG_BUILD_PPT) |
There was a problem hiding this comment.
[Critical] PAG_BUILD_CLI(第97行)自动启用了 PAG_BUILD_SVG 但未启用 PAG_BUILD_PPT。而 CommandExport.cpp 无条件 #include "pagx/PPTExporter.h" 并调用 PPTExporter::ToFile()。当以 -DPAG_BUILD_CLI=ON -DPAG_BUILD_PPT=OFF 构建时会编译/链接失败。建议在97行的 if (PAG_BUILD_CLI) 块中补上 set(PAG_BUILD_PPT ON),或在 CommandExport.cpp 中用 #ifdef PAG_BUILD_PPT 保护 PPT 代码路径。
| GetImageDPI(pattern->image, &imgDpiX, &imgDpiY); | ||
| double dpiCorrX = static_cast<double>(imgDpiX) / 96.0; | ||
| double dpiCorrY = static_cast<double>(imgDpiY) / 96.0; | ||
| auto sx = static_cast<int>(std::round(M.a * dpiCorrX * 100000.0)); |
There was a problem hiding this comment.
[Major] Tiling 分支直接用 M.a 和 M.d 作为缩放因子。当 pattern->matrix 含旋转时(如90度),M.a=0、M.d=0 导致 sx=0、sy=0。非 tiling 分支的 ComputeImagePatternRect(第151行)已修复为 sqrt(a*a+b*b) 提取缩放,但此处未同步。建议统一使用相同的缩放提取方式。
| void ReverseContour(PathContour& c) { | ||
| size_t n = c.segs.size(); | ||
| Point originalStart = c.start; | ||
| c.start = SegEndpoint(c.segs[n - 1]); |
There was a problem hiding this comment.
[Major] ReverseContour 未防御空 segs。当 n=0 时 c.segs[n-1] 访问 segs[SIZE_MAX] 触发未定义行为。虽然当前内部调用者有 segs.empty() 守卫,但此函数是头文件中的公开接口,外部调用者可能不做检查。建议入口加 if (c.segs.empty()) return;。
| if (memcmp(data, kPNGSignature, 8) != 0) { | ||
| return false; | ||
| } | ||
| *width = static_cast<int>((data[16] << 24) | (data[17] << 16) | (data[18] << 8) | data[19]); |
There was a problem hiding this comment.
[Major] PNG 维度解析存在有符号整数溢出(未定义行为)。data[16] 为 uint8_t,隐式提升为 int 后 << 24 在高位 >=0x80 时超出 int 范围。第329-330行的 GetPNGDPI 也有相同问题。建议先转 uint32_t 再移位:static_cast<uint32_t>(data[16]) << 24。对比第292行 WebP 解析已正确使用了 static_cast<uint32_t>。
| std::cerr << "pagx export: error: failed to load '" << options.inputFile << "'\n"; | ||
| return 1; | ||
| } | ||
| if (!document->errors.empty()) { |
There was a problem hiding this comment.
[Minor] ExportToPPT 缺少 hasUnresolvedImports() 检查。ExportToSVG(第145行)在有未解析导入时报错退出,但 PPT 导出完全没有此检查,可能导致不完整的 PPTX 被静默导出。建议添加与 SVG 相同的检查逻辑。
| std::shared_ptr<tgfx::Data> RenderMaskedLayer(const std::shared_ptr<tgfx::Layer>& root, | ||
| const std::shared_ptr<tgfx::Layer>& targetLayer) { | ||
| auto globalBounds = targetLayer->getBounds(root.get(), true); | ||
| auto device = tgfx::GLDevice::Make(); |
There was a problem hiding this comment.
[Minor] RenderMaskedLayer 每次调用都创建新的 GL 设备和上下文。文档中有多个 masked layer 时会反复创建/销毁 GL 上下文,性能开销较大。建议由调用方创建设备传入复用。
| using pag::DegreesToRadians; | ||
| using pag::FloatNearlyZero; | ||
|
|
||
| static const uint8_t kPNGSignature[8] = {0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A}; |
There was a problem hiding this comment.
[Minor] 静态常量 kPNGSignature 使用了 k 前缀,不符合项目命名规范(全大写下划线无 k 前缀),应改为 PNG_SIGNATURE。第323行也有同样问题。
| * elements when glyph outline data is unavailable. The default value is false. | ||
| */ | ||
| bool convertTextToPath = true; | ||
| bool convertTextToPath = false; |
There was a problem hiding this comment.
[Minor] convertTextToPath 默认值从 true 改为 false 是用户可感知的行为变更(Breaking Change)。所有通过 C++ API 调用 SVGExporter::ToFile() 且未显式设置此选项的下游代码,输出会从 path 元素变为 text 元素。建议在 PR 描述中明确标注。
| return seg.pts[0]; | ||
| } | ||
|
|
||
| float ComputeSignedArea(const PathContour& contour) { |
There was a problem hiding this comment.
[Minor] ComputeSignedArea 和 PointInsideContour(第77行)均为端点多边形近似,非精确几何计算。对于少量高曲率 bezier 段构成的路径(如4段 cubic 组成的圆),winding 方向和包含关系可能误判。建议在函数注释中说明此为端点近似的限制。
| } | ||
| int idx = static_cast<int>(_images.size()) + 1; | ||
| std::string relId = "rId" + std::to_string(_nextRelId++); | ||
| bool jpeg = IsJPEG(data->bytes(), data->size()); |
There was a problem hiding this comment.
[Minor] WebP 图片会以 .png 扩展名嵌入 PPTX(addImage 中只区分 JPEG 和非 JPEG 两条路径)。PowerPoint 不原生支持 WebP,且 GenerateContentTypes 中也缺少 WebP 的 ContentType 声明。建议识别 WebP 格式并进行格式转换或添加相应的 content type。
新增 PPT 导出功能,支持将 PAGX 文档导出为 PPTX 格式。
主要变更: