1 回答

TA貢獻1786條經驗 獲得超11個贊
最新版本的 Roboto-Medium確實包含按大小繪制的小寫字母,但它們并未映射到 Unicode 代碼點。這意味著在簡單字符串中指定字符的常規方法行不通。
OpenType 感知軟件可以通過 OpenType 功能訪問字形c2sc(將大寫字母替換為等效的小型大寫字母)和smcp(其作用相同,但僅適用于小寫字母)。這些翻譯表位于 TrueTypeGSUB表中的字體內——它們以一種特別不正當的格式編碼。這可能是 PIL 程序員從不費心去實現它的原因(以及其他可能有用的 OpenType 功能,例如上標和下標、字距調整和每種語言的本地化字母形式)。
Python 模塊freetype 可以訪問原始字形。但是,同樣地,FreeType 開發人員曾短暫考慮將 OpenType 功能解析添加到他們的庫中,但最終決定放棄,讓 FreeType 只專注于繪圖。盡管如此,您仍然可以使用freetype來獲取和柵格化所有字體中的任何字形。唯一的事情是,您將對字形索引進行硬編碼。
“字形索引”只不過是“什么編碼值對應于哪個圖像”,從 0 開始,一直到最后一個字形。字體的可能編碼位于字體數據中的其他位置;它可能包含確定的 Windows 編碼(舊的“代碼頁”東西——但更大)、完整的 Unicode 編碼、MacRoman 以及其他一些。您只需要選擇一種編碼并告訴您想要該編碼中的freetype什么字符代碼,就會為您查找正確的字形。
但是 OpenType 功能可以推翻這一點。它是一組單獨的翻譯,由您選擇的功能(以及哪種腳本,甚至是哪種語言)驅動。一個完全支持 OpenType 的界面會看到你的字形,用所需的特性提高賭注,并返回一個原始的字形索引。
由于單個字體文件中可能有很多原始字形,因此并非每個編碼都會指向字體中的每個字形。想象一下可憐的老 MacRoman,例如,只有 256 個可能的字符。你不可能用它來處理 Roboto 的所有 1294 個字形。即使 Unicode 具有成千上萬個已定義的條目,也無法解決所有問題,因為可以為某些字符(例如花體大寫字母)創建風格替代品,就 Unicode 而言,它們與它們的原始字符相同,并且用作連字的字符組合,其中完整的序列例如Zapfino被繪制為單個復雜的字形(那個是字體“Zapfino”;它很棒)。
一些字體設計師允許通過“私有”Unicode 代碼點訪問特殊字符(意思是“每個人都可以自由定義”),但我認為 Roboto 沒有這個。
可以向 FreeType 詢問完整的GSUB表格,然后對其進行解析以找到適合小型大寫字母的翻譯,如果這樣做,您會很高興地發現您的代碼將適用于任何帶有真正小型大寫字母的字體 (! ),但這是一項巨大的工作。
所以我作弊了。有些軟件允許按字形檢查字體,我使用 Adobe InDesign 查找所有A..Z小寫字母的字形索引。
不過,這確實有一個缺點。它只能(可靠地)與一個特定版本的 Roboto-Medium 一起工作,因為設計者可以為每個新版本隨意添加、刪除和移動字形。請記住,這對其他軟件處理字體的方式沒有任何影響!編碼表和 OpenType 表已調整為匹配,因此軟件不需要了解每種字體的字形索引的任何信息。
也無法保證這些相同的索引可以與 Roboto 系列中的其他字體一起使用。設計師可能使用了完全相同的布局,也可能沒有。實際上,如上所述,他們甚至不必關心它。
我已經下載了最新的 2.137 版;2017;如果你沒有那個,請先下載它!
下面是一些示例代碼,用于按順序打印出所有小型大寫字母字形的灰度值,它們與字形起點的水平偏移(左偏移)和以像素為單位的垂直高度(從基線測量)。隨意調整,匹配PIL自己的文字繪制套路;可能需要一些修飾才能讓它恰到好處?。
(為相當基本的代碼示例道歉。我設法弄亂了 Python 2.7 和 3 的 PIL 安裝(某些東西),所以我無法以圖形方式顯示某些東西;幸運的是,該freetype模塊仍然有效。)
import freetype
import os.path
smcapGlyphs = [563,562,561,560,552,486,485,484,483,482,481,480,479,
478,477,476,475,474,473,472,471,470,469,468,467,466]
def dump_bytes(buf,wide,high):
for y in range(high):
for x in range(wide):
print ('%02x ' % buf[y*wide+x], end='')
print ()
face = freetype.Face(os.path.expanduser('~')+"/Library/Fonts/Roboto-Medium.ttf")
face.set_char_size( 48*64 )
for index,i in enumerate(smcapGlyphs):
face.load_glyph(i)
print (chr(65+index))
bitmap = face.glyph.bitmap
width = face.glyph.bitmap.width
rows = face.glyph.bitmap.rows
pitch = face.glyph.bitmap.pitch
print (face.glyph.bitmap_left)
print (face.glyph.bitmap_top)
dump_bytes (bitmap.buffer, pitch,rows)
print ()
添加回答
舉報