2013-12-22 9 views
9

我在寫一個TTF解析器。爲了更好地理解TTF格式,我使用了TTX來提取C:\ Windows \ calibri.ttf的「.notdef」字形數據,如下所示。TrueType字體的字形是由二次Bezier構成的。爲什麼在字形輪廓中出現多個連續的曲線外點?

<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字體是由二次貝塞爾曲線構成的,每一曲線都有兩個曲線上的點(終點)和一個曲線上的點(控制點)。如何解釋這些連續的離線曲線點?

+0

它們是Bezier曲線的離曲線*控制點*。 [Wikipedia文章](http://en.wikipedia.org/wiki/B%C3%A9zier_curve)中的點P1和P2。 –

+4

嗨漢斯。感謝您的回覆。你提到的點P1和P2是三次Bezier。我知道n階貝塞爾有(n-1)個控制點。特別地,二次貝塞爾只需要一個控制點。爲什麼TTF由二次Bezier生成,有多個控制點? – Moon

+0

@HansPassant,見上。 – Moon

回答

15

TTF解析需要應用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 

現在的把戲:如果每個個人是上曲線點,每個Cn是一個控制點, P2恰好位於C1和C2的中間,P3位於C2和C3之間等等,那麼這是一條可壓縮的曲線:如果我們知道C1和C2,知道P2,所以我們不必明確列出它,w e可以把它留給解析字形輪廓的任何東西。

所以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碼圖形是有點傻,但仍不夠清晰)

經過幾年的10

進一步編輯我設法找到文件,實際上解釋(或者至少暗示),它TTF蘋果的文檔中,過上https://developer.apple.com/fonts/TrueType-Reference-Manual/RM01/Chap1.html#necessary,這在「圖13」指出:

特別是位於曲線切線中點的曲線上點不會添加任何額外信息,因此可能已被省略。

甚至進一步編輯 ShreevatsaR指出圖2和圖3中的蘋果文檔之間的文本也是相關的:

也將是可能的,以指定在圖2與示出的曲線刪除點p2減少一個點。點p2不是嚴格需要來定義曲線,因爲它的存在隱含,並且它的位置可以從其他點給出的數據重建。重新編號後,我們有[圖3]。

+1

哇!感謝您的回答!我猜想這個輪廓是以某種方式壓縮的,但不知道如何。你的答案似乎是正確的。我使用了你的方法,並正確解釋了輪廓。你知道這個技巧在哪裏正式記錄嗎?我沒有在TTF規範中找到這個(我認爲規範不是很具體)。 – Moon

+0

我找不到https://developer.apple.com/fonts/TTRefMan/RM06/Chap6glyf.html或http://www.microsoft.com/typography/otspec/glyf.htm中的技巧。 – Moon

+0

hm,我不記得我用什麼文件來實現自己的TTF解析,也可能在usenet或opentype郵件列表中解釋過,當我也跑回來的時候。 –