字的研究(2)fontTools-字體文件的解析


前言

本文主要介紹如果使用Python第三方庫fontTools對OpenType字體文件(包括TrueType輪廓和Postscript輪廓)的解析操作。

fontTools簡介

fontTools是由一組操作字體的庫和組件組成的Python第三方庫,要求Python3.6以及更高的版本。其中包括merge(字體合並)、subset(取字體子集)以及ttx(將OpenType轉化為XML)等。

安裝

pip install fontTools

本文中使用的版本為4.28.5

字體文件的解析

讀取

如前文所述,OpenType字體文件標准是有sfnt結構封裝的,基於sfnt的表結構,OpenType格式的字體文件可以分為多個表結構。

創建TTFont實例,通過keys()可以查看字體文件的所有表名:

from fontTools.ttLib.ttFont import TTFont
font = TTFont("Resources/simsun.ttf")
print(font.keys()) 

運行結果如下:

['GlyphOrder', 'head', 'hhea', 'maxp', 'OS/2', 'hmtx', 'cmap', 'fpgm', 'prep', 'cvt ', 'loca', 'glyf', 'name', 'post', 'gasp', 'EBDT', 'EBLC', 'GDEF', 'GPOS', 'GSUB', 'MERG', 'meta', 'vhea', 'vmtx']

表名中包含‘glyf‘,所以simsun.ttf是一個使用TrueType輪廓的字體文件。

換成使用Postscript輪廓的字體文件:

font = TTFont("Resources/AdobeSongStd-Light.otf")
print(font.keys())

運行結果如下:

['GlyphOrder', 'head', 'hhea', 'maxp', 'OS/2', 'name', 'cmap', 'post', 'CFF ', 'BASE', 'GPOS', 'GSUB', 'VORG', 'hmtx', 'vhea', 'vmtx', 'DSIG']

表名中沒有'glyf'而存在'CFF ',后者是存儲Postscript信息的表格。

對於TrueType Collection文件則可以使用如下方法讀取,返回一個TTFont實例的列表

from fontTools.ttLib.ttCollection import TTCollection
collection = TTCollection("Resources/simsun.ttc")
print(list(collection))

運行結果如下:

[<fontTools.ttLib.ttFont.TTFont object at 0x000001F8BA66A700>, <fontTools.ttLib.ttFont.TTFont object at 0x000001F8BE072AF0>]

直接從這些表格提取到具體信息是復雜的,但TTFont提供了一些方法以方便地獲取信息:

font.getGlyphOrder() # 返回一個字形名稱列表,以其在文件中的順序排序
font.getGlyphNames() # 返回一個字形名稱列表,以字母順序排序
font.getBestCmap() # 返回一個字形ID為鍵、字形名稱為值的字典
font.getReverseGlyphMap() # 返回一個字形名稱為鍵、字形ID為值的字典
font.getGlyphName(10000) # 輸入字形ID返回字形名稱
font.getGlyphID("uni70E0") # 輸入字形名稱返回字形ID
font.getGlyphSet() # 返回一個_TTGlyphSet對象,包含字形輪廓數據

上述方法中,最后一項與輪廓數據有關的方法是最重要的。可惜的是,官方文檔似乎並沒有對這個對象做進一步解釋,故下文是我讀源碼及其中注釋后的分析,如有錯漏,敬請指教。

Pen與_TTGlyphset

我認為,作者設計這一部分時的難點在於OpenType字體文件標准存在兩種不同輪廓描述方式。Pen和_TTGlyphset的存在使得兩種不同的輪廓描述方式可以用同一套方法解析和顯示。

The Pen Protocol

基於TrueType輪廓的字體文件和基於Postscript輪廓是兩種截然不同的數據格式。Pen是一個用於標准化的”畫"出輪廓的對象,或者是數據和實際輪廓間的媒介。

具體來說,Pen對象的子類包含將上述兩種輪廓數據轉化為畫線、移動等模擬實際輪廓的方法。在fontTools的pen庫中包含將輪廓數據轉化為qt、reportLab等第三方庫中實例的Pen子類。

_TTGlpyhset

_TTGlyphset是一個類似字典的,以字形名稱為鍵、_TTGlyph為值的對象。_TTGlyph中包含字形數據輪廓數據並可以通過draw方法“畫”出。_TTGlyph的兩個子類_TTGlyphGlyf和_TTGlyphCFF分別對應TrueType輪廓和Postscript輪廓。具體使用方法如下:

font = TTFont("Resources/simsun.ttf")
glyph = font.getGlyphSet()["uni70E0"]
glyph.draw(pen) # pen為實例化后的Pen子類

freetypePen

以freetype-py庫為例,使用freetypePen首先需要安裝freetype-py:

pip install freetype-py

以下代碼修改自自fontTools的官方文檔提供的范例程序:

from fontTools.ttLib import TTFont
from fontTools.pens.freetypePen import FreeTypePen
from fontTools.misc.transform import Offset

pen = FreeTypePen(None) # 實例化Pen子類
font = TTFont("Resources/simsun.ttf") # 實例化TTFont
glyph = font.getGlyphSet()["uni70E0"] # 通過字形名稱選擇某一字形對象
glyph.draw(pen) # “畫”出字形輪廓
width, ascender, descender = glyph.width, font['OS/2'].usWinAscent, -font['OS/2'].usWinDescent # 獲取字形的寬度和上沿以及下沿
height = ascender - descender # 利用上沿和下沿計算字形高度
pen.show(width=width, height=height, transform=Offset(0, -descender)) # 顯示以及矯正

運行結果如下:

注意,可能由於fontTools==4.28.5版本問題,通過pip安裝后freetypePen.py並沒有包含在pens文件夾下,需要使用的可以從fontTools的GitHub倉庫中下載,放到site-packages\fontTools\pens文件夾下,下載路徑為https://github.com/fonttools/fonttools/blob/main/Lib/fontTools/pens/freetypePen.py。該問題可能在后續版本中修復。

ttx

最后是我個人認為fontTools中最為實用的一個組件ttx,其功能為將TTFont實例轉化為XML格式以及將XML文件轉化為TTFont。基於這一組件,我們可以較為方便的實現對字體文件內容的修改。

from fontTools.ttLib import TTFont

font = TTFont("Resources/simsun.ttf") # 實例化TTFont
font.saveXML("simsun.xml") # TTFont實例轉化為XML文件,參數為XML文件路徑
font.importXML("simsun1.xml") # XML文件轉化為TTFont實例,參數為XML文件路徑

除了將整個字體文件轉化為XML文件,ttx還可以將文件中的單個表轉化為XML文件,避免多余的存儲和時間消耗:

from fontTools.ttLib.ttFont import TTFont

font = TTFont("Resources/simsun.ttf")
font.saveXML("temp2.xml",tables=["glyf"]) # tables為需要轉化的表名組成列表

單個表的XML文件直接導入TTFont時,只會影響XML文件存在的表,而其他表不變:

font.importXML("temp2.xml")

參考

https://fonttools.readthedocs.io/en/latest/index.html

https://github.com/fonttools/fonttools


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM