8

我想在 HTML5 中检索字体字形的轮廓信息作为贝塞尔路径。这将允许我随机化轮廓:

随机更改的字形轮廓

在 Cocoa 中,我会使用appendBezierPathWithGlyph:inFont:. 在 Java 中,我会使用TextLayout.getOutline(). 这在 JavaScript 中是如何工作的?

我发现 Mozilla 有,mozPathText但我无法让它工作。

4

3 回答 3

31

出于必要,我创建了自己的名为opentype.js的库。它解析 OpenType、TrueType、PostScript 和 WOFF 字体。

以下是它解析字体的方式:

  • 使用. .ttf_ .otf_XMLHttpRequest
  • 解析glyfandloca表以提取字母形状(字形)。
  • 解析cmap包含从字符到字形的映射的表。
  • 解析headandhmtx表格以获取指标,基本上是每个字母之间的间距。

然后它可以创建一个贝塞尔路径:

  • 将文本的字母转换为字形。
  • 将字形的坐标转换为二次曲线。
  • 使用字距调整信息调整间距。

这会产生一个您可以使用 HTML5 画布绘制的路径:

var font = opentype.parseFont(arrayBuffer);
var path = font.getPath("Hello, World!", {x:0, y:150, fontSize:72});
path.draw(ctx);

opentype.js 演示

演示网站有一个活生生的例子。

于 2013-09-27T18:19:02.740 回答
11

低级解析

在 JavaScript 中,您必须手动解析字体文件并提取所需的路径数据。AFAIK 目前没有帮助库,所以你只能自己做这件事。

要解析文件,您还需要手动上传并使用新的File API和可能的二进制字体格式 (ttf)类型数组将其解析为原始数据。

可以为此写一个很长的答案,因为这是相当低级的东西,并且在此处涵盖范围很广(恕我直言)。但是,以下是常见字体文件的文件格式规范:

但是,您可以采取另一种方法作为中间步骤,为您节省很多痛苦:

预解析

选择要使用的字体。通过 Java/Cocoa/.NET (WPF) 或任何您喜欢的方式运行它们,并构建包含您需要的信息的数组(例如,WPF 为您提供每个字形的路径数据)。将它们转换为 JavaScript 数组或 JSON 对象,并使用它们进行渲染和操作。结果点将em采用易于缩放的值。

现在您可以简单地遍历数组并渲染路径段类型(线、贝塞尔曲线等)并修改点位置。

mozPathText用于画布,仅保存文本路径(当前 Path API 未在任何浏览器中公开,但将来会 - 但是,它不能用于此,因为每个字形的低级路径数据不可用有很多原因,法律原因可能是一个)。

痕迹

第三种方法是通过跟踪每个单独的字形来对画布上的字形进行“OCR”排序,并尝试从它的跟踪轮廓构建路径。

这可以通过多种方式完成 - 一种方式是逐行解析并根据距离/连通性对像素进行分组,然后使用神经网络或填充算法遍历组/区域以找到字形的外部边界。

或者 - 您可以将文本绘制为轮廓,然后跟踪每个形状的连接像素并将其用作线条路径。

在这种情况下,您可能会遇到看似简单但事实并非如此的挑战。

示例:字母O由外部路径和内部路径组成。内部路径在外部路径上打了一个“洞”。您不能仅通过在画布中定义路径来直接定义此行为,因此您需要在确定它们属于彼此之后在两条路径之间添加“剪切”,然后在剪切处加入它们。

使用不同的复合模式可能有助于创造这种错觉,但您仍然需要确定哪条路径是实体部分,哪条路径将被绘制为“孔”。

翘曲/扭曲

最后一种方法是根本不使用字形路径,而只是使用插值和扭曲网格(通常与 3D 纹理一起使用)扭曲位图:

http://davis.wpi.edu/~matt/courses/morph/2d.htm
变形 (pdf)
变形 (pdf)

定义自己的字体/路径(手动跟踪)

更明显的选择可能是:从头开始定义自己的字体路径。在制作字体设计器或手动跟踪图像或手动定义路径方面需要做更多的工作。“字体绘图仪”(使用跟踪图像)并不复杂,但需要耐心。

您可以在浏览器中使用画布记录您正在绘制的线条,并使用平滑算法(基数样条 + 拐点检测)来获得漂亮的圆形曲线和尖角。

这一切都取决于你最终想要什么结果,以及你愿意放下多少工作。不幸的是,在这方面没有免费票,因为内部数据没有公开(将来也可能不会公开)。

于 2013-06-28T08:36:58.307 回答
0

使用 SVG 可以在某些浏览器中执行您所要求的相反操作:将自定义字体字形指定为贝塞尔路径,然后使用它们布置文本。您可以导入 SVG 字体,然后对其执行转换。但即使现在 SVG 得到广泛支持,SVG 字体也不是。目前只有 Safari、Chrome 和 Opera 支持它们。

如果您想以矢量方式使用系统字体进行这些类型的转换,那么在我所知道的任何浏览器中都是不可能的。HTML 或 SVG 中根本没有 API 来获取已安装字形的轮廓路径。(也许你可以在像 Flash 这样的插件中使用一些东西,我有一段时间没有检查他们的文本 API。)

如果您可以以光栅方式进行操作,则可以使用隐藏的画布元素将文本布局在屏幕外缓冲区中,然后获取结果的像素图。然后,您可以对其执行基于像素的转换并将其绘制到第二个可见的画布元素中。

于 2013-07-03T19:07:57.910 回答