使用Python向字体添加Glyph时遇AttributeError问题求助
问题:FontTools添加Glyph时触发AttributeError: 'table__g_l_y_f' object has no attribute 'glyphs'
我用Python自定义Glyph创建新字体,已经实现了将SVG解析为FontTools的TTGlyph对象的函数,该函数返回TTGlyph对象、Glyph名称及码点。但调用create_font_from_glyphs脚本时出现以下错误,无法成功向字体添加Glyph:
原代码
import os from fontTools.ttLib import TTFont, newTable from fontTools.ttLib.tables._c_m_a_p import CmapSubtable from fontTools.ttLib.tables._n_a_m_e import NameRecord from fontTools.ttLib.tables._g_l_y_f import TTGlyph def parse_svg_to_glyph(svg_file_path): # 已实现的SVG解析逻辑,返回TTGlyph、glyph名称、码点列表 glyph = TTGlyph() glyph_name = os.path.splitext(os.path.basename(svg_file_path))[0] codepoints = [ord(glyph_name[0])] if glyph_name else [] return glyph, glyph_name, codepoints def create_font_from_glyphs(glyph_data, output_path): font = TTFont() font['head'] = newTable('head') font['head'].unitsPerEm = 1000 font['hhea'] = newTable('hhea') font['hhea'].ascent = 900 font['hhea'].descent = -100 font['maxp'] = newTable('maxp') font['maxp'].numGlyphs = len(glyph_data) + 1 font['glyf'] = newTable('glyf') for glyph, glyph_name, _ in glyph_data: font['glyf'][glyph_name] = glyph cmap = newTable('cmap') cmap.tableVersion = 0 cmap.tables = [] subtable = CmapSubtable.newSubtable(4) subtable.platformID = 3 subtable.platEncID = 1 subtable.language = 0 subtable.cmap = {unicode: glyph_name for _, glyph_name, unicodes in glyph_data for unicode in unicodes} cmap.tables.append(subtable) font['cmap'] = cmap font_name = "Example Font" name = newTable('name') name.names = [] nameRecord = NameRecord() nameRecord.nameID = 1 nameRecord.platformID = 3 nameRecord.platEncID = 1 nameRecord.langID = 0x409 nameRecord.string = font_name.encode('utf-16-be') name.names.append(nameRecord) font['name'] = name font['post'] = newTable('post') font['post'].italicAngle = 0 font['post'].underlinePosition = -100 font['post'].underlineThickness = 50 font['post'].isFixedPitch = 0 font.save(output_path) def main(): svg_dir_path = "data/svg" glyph_data = [] for filename in os.listdir(svg_dir_path): if filename.endswith('.svg'): svg_file_path = os.path.join(svg_dir_path, filename) glyph, glyph_name, codepoints = parse_svg_to_glyph(svg_file_path) glyph_data.append((glyph, glyph_name, codepoints)) create_font_from_glyphs(glyph_data, "test.ttf") if __name__ == "__main__": main()
错误信息
font['glyf'][glyph_name] = glyph ~~~~~~~~~~~~^^^^^^^^^^^^ self.glyphs[glyphName] = glyph ^^^^^^^^^^^ AttributeError: 'table__g_l_y_f' object has no attribute 'glyphs'
解决方案
1. 初始化glyf表的glyphs字典
通过newTable('glyf')创建的glyf表对象默认没有glyphs属性,而FontTools在通过下标访问font['glyf'][glyph_name]时会尝试操作这个字典。需要在创建glyf表后手动初始化:
font['glyf'] = newTable('glyf') font['glyf'].glyphs = {} # 初始化glyphs字典
2. 添加默认的.notdef Glyph
代码中maxp.numGlyphs设置为len(glyph_data)+1,意味着需要包含一个默认Glyph(通常是.notdef),否则字体结构不完整,可能导致保存或使用出错:
# 创建默认的.notdef glyph notdef_glyph = TTGlyph() font['glyf']['.notdef'] = notdef_glyph
3. 补充字体表的必要属性
原代码缺少部分字体表的必填属性,会导致保存时出现警告或错误,需要补充完整。以下是修正后的完整create_font_from_glyphs函数:
def create_font_from_glyphs(glyph_data, output_path): font = TTFont() # 初始化head表并补充必要属性 font['head'] = newTable('head') font['head'].unitsPerEm = 1000 font['head'].fontRevision = 1.0 font['head'].checkSumAdjustment = 0 font['head'].magicNumber = 0x5F0F3CF5 font['head'].flags = 0x0001 font['head'].created = 0 font['head'].modified = 0 # 初始化hhea表并补充必要属性 font['hhea'] = newTable('hhea') font['hhea'].ascent = 900 font['hhea'].descent = -100 font['hhea'].lineGap = 0 font['hhea'].advanceWidthMax = 1000 font['hhea'].minLeftSideBearing = 0 font['hhea'].minRightSideBearing = 0 font['hhea'].xMaxExtent = 1000 font['hhea'].caretSlopeRise = 1 font['hhea'].caretSlopeRun = 0 font['maxp'] = newTable('maxp') font['maxp'].numGlyphs = len(glyph_data) + 1 # 初始化glyf表及glyphs字典 font['glyf'] = newTable('glyf') font['glyf'].glyphs = {} # 添加默认.notdef glyph notdef_glyph = TTGlyph() font['glyf']['.notdef'] = notdef_glyph # 添加自定义glyphs for glyph, glyph_name, _ in glyph_data: font['glyf'][glyph_name] = glyph # 初始化cmap表 cmap = newTable('cmap') cmap.tableVersion = 0 cmap.tables = [] subtable = CmapSubtable.newSubtable(4) subtable.platformID = 3 subtable.platEncID = 1 subtable.language = 0 subtable.cmap = {unicode: glyph_name for _, glyph_name, unicodes in glyph_data for unicode in unicodes} cmap.tables.append(subtable) font['cmap'] = cmap # 初始化name表,补充PostScript名称 font_name = "Example Font" name = newTable('name') name.names = [] # 字体名称(nameID 1) nameRecord = NameRecord() nameRecord.nameID = 1 nameRecord.platformID = 3 nameRecord.platEncID = 1 nameRecord.langID = 0x409 nameRecord.string = font_name.encode('utf-16-be') name.names.append(nameRecord) # PostScript名称(nameID 6) nameRecord_ps = NameRecord() nameRecord_ps.nameID = 6 nameRecord_ps.platformID = 3 nameRecord_ps.platEncID = 1 nameRecord_ps.langID = 0x409 nameRecord_ps.string = "ExampleFont".encode('utf-16-be') name.names.append(nameRecord_ps) font['name'] = name # 初始化post表并补充必要属性 font['post'] = newTable('post') font['post'].italicAngle = 0 font['post'].underlinePosition = -100 font['post'].underlineThickness = 50 font['post'].isFixedPitch = 0 font['post'].formatType = 3 # 映射glyph名称到索引 glyph_names = ['.notdef'] + [g[1] for g in glyph_data] font['post'].mapping = {name: idx for idx, name in enumerate(glyph_names)} font.save(output_path)
内容的提问来源于stack exchange,提问作者10cal
相关产品推荐
相关产品推荐

