TrueType Font的字形由二次Bezier组成.为什么在字形轮廓中出现多个连续的曲线外点?

lzl*_*31x 13 bezier glyph truetype

我正在写一个TTF解析器.为了更好地理解TTF格式,我使用TTX提取C:\ Windows\calibri.ttf的".notdef"字形数据,如下所示.

<TTGlyph name=".notdef" xMin="0" yMin="-397" xMax="978" yMax="1294">
      <contour>
        <pt x="978" y="1294" on="1"/>
        <pt x="978" y="0" on="1"/>
        <pt x="44" y="0" on="1"/>
        <pt x="44" y="1294" on="1"/>
      </contour>
      <contour>
        <pt x="891" y="81" on="1"/>
        <pt x="891" y="1213" on="1"/>
        <pt x="129" y="1213" on="1"/>
        <pt x="129" y="81" on="1"/>
      </contour>
      <contour>
        <pt x="767" y="855" on="1"/>
        <pt x="767" y="796" on="0"/>
        <pt x="732" y="704" on="0"/>
        <pt x="669" y="641" on="0"/>
        <pt x="583" y="605" on="0"/>
        <pt x="532" y="602" on="1"/>
        <pt x="527" y="450" on="1"/>
        many more points
     </contour>
     ...some other xml
</TTGlyph>
Run Code Online (Sandbox Code Playgroud)

您可以连续看到多个曲线外控制点.但我了解到,TrueType字体由Quadratic Beziers组成,每个Beziers都有两个曲线上的点(终点)和一个曲线外点(控制点).如何解释这些连续的曲线外点?

Mik*_*ans 25

TTF解析需要从microsoft站点应用http://www.microsoft.com/typography/otspec/glyf.htm以及有关TTF格式的技术文档.这些告诉我们曲线有两种类型的点:曲线上和曲线外点.曲线上的点是曲线通过的"实际"点,而曲线外曲线点是引导贝塞尔曲率的控制点.

现在,您所描述的"贝塞尔曲线"是正确的:单个贝塞尔曲线从1个实际点(由1个控制点引导)变为1个实际点.然而,二次曲线通常是设计工作的废话,因为它们在逼近圆弧方面非常糟糕,但它们也比使用三次曲线便宜得多,因此对于具有truetype轮廓的字体我们坚持使用它们.为了解决这个问题,TTF概述通常使用贝塞尔曲线序列来获得看起来不错的均匀曲线,并且这些序列往往具有良好的性质:曲线上和曲线外的点以非常特殊的模式间隔开.

考虑一下这个贝塞尔序列:

P1 - C1 - P2 - C2 - P3 - C3 - P4
Run Code Online (Sandbox Code Playgroud)

如果我们添加on信息,我们会在TTF中将其编码为:

P1 - C1 - P2 - C2 - P3 - C3 - P4
1  -  0 -  1 -  0 -  1 -  0 -  1
Run Code Online (Sandbox Code Playgroud)

现在用于特技:如果每个Pn为一个曲线上的点,并且每个Cn为控制点,并且 P2恰好位于中途C1和C2之间,P3位于C2和C3之间,等等,那么这是一个可压缩曲线:如果我们知道C1和C2,我们知道P2,所以我们不必明确地列出它,我们可以把它留给任何解析字形轮廓的东西.

因此,TTF将编码长贝塞尔序列以获得均匀曲线:

P1 - C1 - C2 - C3 - P4
 1 -  0 -  0 -  0 -  1
Run Code Online (Sandbox Code Playgroud)

节省相当大的空间,不会损失精度.如果你查看你的TTX转储,你会看到这反映在on每个点的值中.要获得P2,P3等,我们所做的就是:

foreach(array as point):
  // do we have an implied on-curve point?
  if(mask_for_point == 0 && mask_for_previous_point === 0):
    missing_point = midpoint(point, previous_point)
    points.push(missing_point)
  // add the explicitly encoded point
  points.push(point)
Run Code Online (Sandbox Code Playgroud)

运行此程序后,points阵列将具有交替的曲线上和曲线外点,并且贝塞尔曲线构造为

for(i=0, i<arr.length, i+=2):
  curve(array[i], array[i+1], array[i+2]) 
Run Code Online (Sandbox Code Playgroud)

编辑有点搜索后,http://chanae.walon.org/pub/ttf/ttf_glyphs.htm介绍如何使用工作glyf表中的数据相当良好的细节(ASCII码图形是有点傻,但仍不够清晰)

进一步编辑经过几年我设法找到文件,实际上解释(或者至少暗示),它TTF苹果的文档中,过上https://developer.apple.com/fonts/TrueType-Reference-Manual/RM01/ Chap1.html#必需,在"图13"中指出:

特别是位于曲线切线中点的曲线上的点不会增加额外的信息,可能会被省略.

甚至进一步编辑 ShreevatsaR指出苹果文档中图2和图3之间的文本也是相关的:

通过去除点p2,还可以通过少一点来指定图2中所示的曲线.不需要点p2来定义曲线,因为它的存在暗示并且其位置可以从其他点给出的数据重建.在重新编号剩余的点之后,我们有[图3].

  • 非常感谢!而不是图 13 的标题似乎专门针对该图,而是参考中图 2 和图 3 之间的文本 (https://developer.apple.com/fonts/TrueType-Reference-Manual/RM01/Chap1.html #points) 似乎更相关:“也可以通过删除点 p2 来指定图 2 中显示的曲线少一个点。定义曲线并不严格需要点 p2,因为它隐含了它的存在并且它的位置可以重建来自其他点给出的数据。在对剩余点重新编号后,我们得到了[图 3]。” (2认同)
  • 图2中的@zwcloud p2是点p1和p3的中点.这是你评论的答案的主要教训:-) (2认同)