查看: 123|回复: 3

HarmonyOS矢量图SVG/PNG双导出:离屏Canvas与字体回

[复制链接]
发表于 2 小时前 | 显示全部楼层 |阅读模式
在HarmonyOS上实现矢量图形编辑器的导出功能,通常会遇到两个核心问题:如何从同一份数据同时输出SVG和PNG,以及如何确保两者在取景框、字体和主题上保持一致。本文基于一个实际项目梳理了双格式导出的完整实现,重点解析离屏Canvas栅格化、PixelMap内存管理、字体回退方案以及文件I/O设计。

一、SVG导出:文本拼接与viewBox计算
SVG导出本质上是不依赖Canvas的文本拼接。遍历文档中所有Shape,调用每个Shape的toSvg()方法,将返回的XML片段拼接到标准SVG根元素下。关键点是viewBox的计算——通过SvgExportViewport.fromDocument()方法遍历所有图形的世界包围盒,取最小外接矩形并加上padding(默认20px),保证图形不贴边。这个viewport在后续PNG导出中同样被复用,从而确保两种格式的取景框完全一致。

字体回退是SVG导出的一个典型陷阱:HarmonyOS Sans在桌面浏览器中并不存在,如果SVG的font-family只写"HarmonyOS Sans",导出的图在桌面端会显示空白。解决方案是在字体声明末尾追加通用无衬线回退,例如"HarmonyOS Sans", Helvetica, Arial, sans-serif。实现时通过escapeXml()对字体名进行转义,确保特殊字符不会破坏XML结构。

二、PNG导出:离屏Canvas与PixelMap打包
PNG导出采用栅格化路径:先克隆文档,然后创建离屏Canvas,将矢量图形绘制到Canvas上,再通过getPixelMap()获取像素数据,最后用ImagePacker打包为PNG ArrayBuffer。其中文档克隆是必须的,因为绘制过程需要重算连线路由(refreshConnections),这会修改原始数据;SVG导出因为是只读拼接,所以不需要克隆。

输出尺寸计算遵循最长边限制原则(经验值2048px)。等比缩放公式为:scalePx = maxSide / longest,输出宽高分别乘以scalePx。2048px在大多数设备上能将PNG编码时间控制在500ms以内,内存占用约28MB(RGBA 9.4MB × 3倍峰值)。

离屏Canvas绘制时,通过scale和translate将世界坐标映射到像素坐标,并忽略网格、选中框等UI元素,仅绘制图形本体和背景色。连线需要根据主题色临时调整描边颜色(默认#1F2933在深色背景上不可见),通过ConnectionTheming类实现临时套用与恢复。

三、内存管理关键点
PixelMap持有原生内存,必须在使用后调用release()释放。最佳实践是将release()放在finally块中,确保即使packing抛出异常也能回收。Canvas引用在函数返回后由GC回收。对于2048×1152的输出,OffscreenCanvas、PixelMap、PNG编码缓冲区三者同时存在时峰值约22MB。如果仍然紧张,可以在绘制完成后显式释放Canvas引用,只保留PixelMap等待编码。

四、文件I/O:保存与分享
SVG和PNG的文件I/O结构相同:保存时调用picker.DocumentSaveOptions调起系统文件选择器,用户指定位置后通过fs.openSync写入;分享时先写入缓存目录(文件名加时间戳避免冲突),再通过sendData调起系统分享面板。文件名需经sanitize处理,只保留中英文、数字、下划线、连字符。

五、常见踩坑与优化建议
1. 忘记克隆文档:PNG导出前必须clone,否则连线路由会被污染。
2. 忘记release PixelMap:会导致内存泄漏,务必使用try/finally。
3. 字体回退不够:只写HarmonyOS Sans会导致桌面显示空白,必须追加通用回退。
4. SVG与PNG取景不一致:共用SvgExportViewport.fromDocument即可保证。
5. ImagePacker的quality参数:对PNG无意义(无损格式),只影响编码速度,推荐98作为平衡点。

六、总结
双格式导出的核心是“同一数据,两种渲染”:SVG走文本路径,保留矢量无损特性但依赖阅读器;PNG走像素路径,兼容任何设备但有分辨率损失。通过复用viewBox和主题适配逻辑,两种格式在视觉上完全对齐。整套系统不足500行TypeScript,却实现了矢量图和位图两种主流输出,对HarmonyOS上的图形编辑器类应用有直接参考价值。
回复

使用道具 举报

发表于 2 小时前 | 显示全部楼层

Re: HarmonyOS矢量图SVG/PNG双导出:离屏Canvas与字体回

感谢楼主非常详细的技术分享!双格式导出的思路很清晰,特别是离屏Canvas和SVG文本拼接两种路径的对比,以及共用viewport保证取景一致的技巧,非常实用。字体回退和PixelMap内存管理的提醒也很关键,踩坑经验对做图形编辑的同仁很有帮助。
回复 支持 反对

使用道具 举报

发表于 2 小时前 | 显示全部楼层

Re: HarmonyOS矢量图SVG/PNG双导出:离屏Canvas与字体回

感谢分享!这个双导出方案很实用,尤其“同一数据,两种渲染”的思路清晰。离屏Canvas加PixelMap的内存管理细节(try/finally释放)和字体回退陷阱(追加通用回退)都是实战中容易忽视的点,很有参考价值。另外,SVG和PNG共用viewBox保证取景一致这个设计也值得学习。
回复 支持 反对

使用道具 举报

发表于 2 小时前 | 显示全部楼层

Re: HarmonyOS矢量图SVG/PNG双导出:离屏Canvas与字体回

这篇分享非常有价值,特别是离屏Canvas和PixelMap内存管理的细节——很多人容易忽略release()的finally保障。想请教一下:在文档克隆后绘制连线时,ConnectionTheming临时调整描边颜色,如果用户自定义了多种主题色,这部分是怎么做映射收敛的?另外,SVG导出时对复杂渐变或路径特效(比如阴影)的toSvg()支持情况如何,有没有遇到过图形丢失的问题?
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 注册

本版积分规则

指导单位

江苏省公安厅

江苏省通信管理局

浙江省台州刑侦支队

DEFCON GROUP 86025

Hacking Group 021A

旗下站点

态势感知中心

应急响应中心

红盟安全

联系我们

官方QQ群:112851260

官方邮箱:security#ihonker.org(#改成@)

官方核心成员

关注微信公众号

Archiver|手机版|小黑屋| ( 沪ICP备2021026908号 )

GMT+8, 2026-7-17 19:57 , Processed in 0.024945 second(s), 17 queries , Gzip On, Redis On.

Powered by ihonker.com

Copyright © 2015-现在.

  • 返回顶部