问题
I'm writing a TTF parser. For a better understanding of the TTF format, I used TTX to extract the ".notdef" glyph data of C:\Windows\calibri.ttf as follow.
<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>
You can see more than one off-curve control points in a row. But I've learned that TrueType Font are made of Quadratic Beziers, each of which has two on-curve points (end points) and only one off-curve point (control point). How to interpret these consecutive off-curve points?
回答1:
TTF parsing requires applying http://www.microsoft.com/typography/otspec/glyf.htm as well as the tech docs about the TTF format from the microsoft site. These tell us that there are two types of points for a curve: on-curve and off-curve points. on-curve points are "real" points, through which a curve passes, and off-curve points are control points that guide the bezier curvature.
Now, what you describe as "a bezier curve" is correct: a single bezier curve goes from 1 real point, guided by 1 control point, to 1 real point. However, quadratic curves are generally crap for design work because they are really bad at approximating circular arcs, but they're also much cheaper to work with than cubic curves, so we're stuck with them for fonts with truetype outlines. To get around this, TTF outlines generally use sequences of bezier curves to get decent looking uniform curves, and those sequences tend to have a nice property: the on- and off-curve points are spaced in a very particular pattern.
Consider this Bezier sequence:
P1 - C1 - P2 - C2 - P3 - C3 - P4
If we add the on
information, we'd encode it in TTF as:
P1 - C1 - P2 - C2 - P3 - C3 - P4
1 - 0 - 1 - 0 - 1 - 0 - 1
Now for the trick: if each Pn is an on-curve point, and each Cn is a control point, and P2 lies exactly midway between C1 and C2, P3 lies between C2 and C3, and so on, then this is a compactable curve: if we know C1 and C2, we know P2, so we don't have to list it explicitly, we can just leave that up to whatever parses the glyph outline.
So TTF will encode long bezier sequences for uniform curves as:
P1 - C1 - C2 - C3 - P4
1 - 0 - 0 - 0 - 1
saving considerable space, without loss of precision. If you look at your TTX dump, you'll see this reflected in the on
values for each point. To get the P2, P3, etc, all we do is this:
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)
after running this procedure, the points
array will have alternating on-curve and off-curve points, and the beziers are constructed as
for(i=0, i<arr.length, i+=2):
curve(array[i], array[i+1], array[i+2])
edit after a bit of searching, http://chanae.walon.org/pub/ttf/ttf_glyphs.htm covers how to work with the glyf
table data in pretty good detail (the ascii graphics are a bit silly, but still legible enough)
further edit after several years I managed to find documentation that actually explains (or, at least implies) it in the Apple documentation on TTF, over on https://developer.apple.com/fonts/TrueType-Reference-Manual/RM01/Chap1.html#necessary, which in "Figure 13" states that:
In particular the on-curve points, located at the midpoints of the tangents to the curve, add no extra information and might have been omitted.
even further edit ShreevatsaR points out that the text between Figures 2 and 3 in the apple documentation is also relevant:
It would also be possible to specify the curve shown in FIGURE 2 with one fewer point by removing point p2. Point p2 is not strictly needed to define the curve because its existence implied and its location can be reconstructed from the data given by the other points. After renumbering the remaining points, we have [FIGURE 3].
来源:https://stackoverflow.com/questions/20733790/truetype-fonts-glyph-are-made-of-quadratic-bezier-why-do-more-than-one-consecu