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

时间:2013-12-22 20:33:49

标签: true-type-fonts bezier glyph

我正在写一个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>

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

1 个答案:

答案 0 :(得分:23)

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

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

考虑这个贝塞尔序列:

P1 - C1 - P2 - C2 - P3 - C3 - P4

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

P1 - C1 - P2 - C2 - P3 - C3 - P4
1  -  0 -  1 -  0 -  1 -  0 -  1

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

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

P1 - C1 - C2 - C3 - P4
 1 -  0 -  0 -  0 -  1

节省可观的空间,而不会损失精度。如果您查看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)

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

for(i=0, i<arr.length, i+=2):
  curve(array[i], array[i+1], array[i+2]) 
经过一些搜索后,

编辑http://chanae.walon.org/pub/ttf/ttf_glyphs.htm涵盖了如何以非常好的细节处理glyf表数据(ascii图形有点傻,但仍然足够清晰)

经过几年的努力,

进一步编辑我设法在https://developer.apple.com/fonts/TrueType-Reference-Manual/RM01/Chap1.html#necessary上找到了实际上解释(或者至少暗示)在TTF上的Apple文档中的文档。 13“表示:

  

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

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

  

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