使用 Earcut 对 OpenType.js 中的路径数据进行三角测量
Posted
技术标签:
【中文标题】使用 Earcut 对 OpenType.js 中的路径数据进行三角测量【英文标题】:Triangulate path data from OpenType.js using Earcut 【发布时间】:2018-11-06 08:45:03 【问题描述】:我有一个用例,我需要在画布元素上呈现大量(约 50,000 个字形)清晰、可扩展的文本字符串。到目前为止,我尝试过的 最佳 解决方案包括对画布元素上绘制的文本进行三角测量(使用 fillText 方法绘制文本),通过 WebGL 将矩阵制服和表示该字符串的三角形 Float32Array 上传到 GPU。使用这种方法,我能够以大约 30fps 的速度渲染 100,000 个字形。字形在非常高的缩放级别下会变得块状,但这对我的用例来说很好。
但是,这种方法每个字符串的开销约为 250 毫秒,因为我首先将字符串绘制到内存中的画布元素,读取像素数据,将位图图像转换为矢量,然后对矢量数据进行三角测量。在网上搜索解决方案时,我发现了两个有趣的开源项目:
OpenType.js:https://opentype.js.org/ 耳切:https://github.com/mapbox/earcut所以现在我想重写我最初的概念证明以使用 OpenType 和 Earcut。 OpenType 用于将曲线数据输入 Earcut,而 Earcut 用于对数据进行三角剖分并返回一个表示每个三角形点的数组。
我的问题是,我不知道如何获取 OpenType 提供的数据并将其转换为 Earcut 接受的格式。任何人都可以为此提供帮助吗?
更多信息:
这个 *** 问题有一些很好的信息,但缺少一些实现细节:Better Quality Text in WebGL。我想我想要完成的是第一个答案中描述的“作为几何图形的字体”方法。
【问题讨论】:
这听起来像XY problem;为什么需要在一个画布上同时渲染这么多字形? 感谢您的评论。我的用例是一个项目管理 Web 应用程序,其中每个任务可以在最大缩放级别上有五个不同的字符串,并且用户可以围绕时间表进行平移/缩放。已经存在剔除,因此屏幕外的字形不会像细节级别系统那样呈现,因此在放大时会呈现更多细节。但是,文本以相对较低的缩放级别显示,其中一行任务描述可见。一次可见 1,000 多个任务是很常见的。 我认为问题是——你真的需要 WebGL 吗?常规 2d 画布使用相同的硬件加速,并具有更复杂的算法来填充轮廓,而无需将曲线分解为段并进行三角剖分。 所以我的第一次尝试是使用两个画布元素。一个带有 WebGL 上下文,一个带有 CanvasRenderingContext2D。所有文本都绘制在 CanvasRenderingContext2D 上,然后覆盖在主 GL 上下文画布上。这在 Chrome 和 ios Safari 上效果很好,但是在 Firefox 和 Edge 上绘制文本的速度要慢得多,字符串数量很多(使用 5,000 个作为测试用例),这对我们来说最终是不行的。 【参考方案1】:您可以使用Font.getPath
创建路径。路径由移至、行至、曲线至、四至和关闭指令组成,可通过path.commands
访问。当然,您需要先将贝塞尔曲线指令转换成小段。
一旦你有一组封闭的路径,你需要确定哪些是洞。内部轮廓的方向与外部轮廓相反,您可以将它们分配给包含它们的最小外部轮廓。一旦你有了一组
这是一个假设没有交叉点的简单实现。对我来说,它适用于大多数字体,除了极少数具有相交路径的“花式”字体。
这是一个工作示例:https://jsbin.com/gecakub/edit?html,js,output
您也可以为单个字符创建网格,而不是为每个字符串创建网格,然后使用库中的字距调整数据自行定位它们。
编辑:此解决方案仅适用于 TTF 字体,但可以通过忽略路径方向并使用更好的“路径 A 在路径 B 内”轻松调整 CCF (.otf
)检查,除非字体有相交的路径。
【讨论】:
谢谢!这是一个很棒的答案,正是我想要的。 在 OpenType 字体中,CFF 轮廓使用交叉数来确定孔,而 TTF 轮廓使用路径方向来确定孔,而 SVG 轮廓实际上使用“随便你,只要适当地设置fillrule
”每个字形。所以,我不知道 OpenType.js 是否忽略了这些差异并只是重写了路径,或者它是否尊重原始字形类型,但如果你知道它是这两者中的哪一个,那么值得更新你解释如何确定哪些子路径可能代表孔
啊,说得好,我只使用了 TTF 字体,不知道库是否对其他字体类型进行任何处理(我在原始项目中使用了 FreeType,所以我对 OpenType 的了解更少。 js)。这个解决方案肯定会打破缠绕方向无关紧要的轮廓,但可以通过用更健壮的代码替换方向检查来检查路径 X 是否在路径 Y 内来修复它(尽管无法处理自相交) .以上是关于使用 Earcut 对 OpenType.js 中的路径数据进行三角测量的主要内容,如果未能解决你的问题,请参考以下文章
将 paper.js 路径转换为 opentype.js 路径
如何使用httpclient作为二进制文件以角度加载字体文件(ttf和otf)以使用opentype.js进行处理
iconfont:借助opentype.js生成android/iOS/RN三端的unicode定义文件