You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.02 09:57:57