Windows下用Python+fontTools提取TTF字体元数据的多样式字体问题
解决Windows字体列表生成兼容可变字体与传统字体的问题
问题根源
Arial这类传统字体属于单样式字体文件,没有可变字体特有的fvar表,直接访问font["fvar"]会触发KeyError;而Cascadia Code是可变字体,单个文件包含多种样式,需要读取fvar表获取所有实例样式。
修正后的代码
结合两种字体类型的处理逻辑,修改代码如下:
import os import pandas as pd from fontTools import ttLib table = [] fonts_dir = r'C:\Windows\fonts' # 遍历所有TTF字体文件 for file in os.listdir(fonts_dir): if file.lower().endswith('.ttf'): font_path = os.path.join(fonts_dir, file) try: font = ttLib.TTFont(font_path) # 获取字体家族名称 family_name = font['name'].getDebugName(1) if not family_name: family_name = font['name'].getName(1, 3, 1, 0x409).toUnicode() if 'name' in font else 'Unknown' # 判断是否为可变字体(存在fvar表) if 'fvar' in font: # 遍历可变字体的所有实例样式 for instance in font["fvar"].instances: style_name = font["name"].getName(instance.subfamilyNameID, 3, 1, 0x409) if style_name: style_name = style_name.toUnicode() full_name = f"{family_name} {style_name}" table.append({ 'family': family_name, 'name': full_name, 'style': style_name, 'path': font_path }) else: # 处理传统单样式字体 style_name = font['name'].getDebugName(2) or 'Regular' full_name = font['name'].getDebugName(3) or f"{family_name} {style_name}" table.append({ 'family': family_name, 'name': full_name, 'style': style_name, 'path': font_path }) except Exception as e: print(f"处理字体 {file} 时出错: {str(e)}") continue # 整理DataFrame并去重 df = pd.DataFrame(table, columns=['family', 'name', 'style', 'path']) df['name'] = df['name'].str.split(':').str[-1] df = df.drop_duplicates(subset=['family', 'name', 'style']) print(df.head())
关键改进点
- 兼容性判断:通过
'fvar' in font区分可变字体和传统字体,避免KeyError - 名称读取容错:同时使用
getDebugName和getName方法,确保在不同字体命名规范下都能获取有效名称 - 异常处理:捕获处理字体文件读取中的异常,避免程序中断
- 去重优化:指定
subset参数精准去重,保留唯一的字体家族-名称-样式组合
说明
- 可变字体的
fvar表存储了所有预设的样式实例(如ExtraLight、Bold等),遍历这些实例即可获取完整样式列表 - 传统字体每个文件对应一种样式,直接读取
name表中的子家族名称(ID=2)即可获取样式
内容的提问来源于stack exchange,提问作者ruthpozuelo
相关产品推荐
相关产品推荐

