怎么用脚本获取字体列表

wen 实用脚本 3

开发者必备的系统字体遍历指南

目录导读

  • 为什么需要获取字体列表?——应用场景与意义
  • 基础原理:操作系统如何管理字体?
  • Python脚本获取字体列表(跨平台)
  • JavaScript在浏览器中获取可用字体
  • 命令行脚本(Windows/Mac/Linux)
  • 常见问题解答(Q&A)
  • 实战案例:筛选中文字体并生成报告
  • SEO优化贴士与最佳实践

为什么需要获取字体列表?

在图形设计、网页开发、文档处理或GUI应用开发中,获取系统已安装的字体列表是一个常见需求。

怎么用脚本获取字体列表

  • 设计软件(如Photoshop替代品)需要显示字体选择器
  • 网页前端需要检测用户设备是否支持特定字体
  • 排版工具批量检测缺失字体
  • 自动化脚本为PDF或报告生成添加文本样式

但不同操作系统管理字体的方式各异,手动翻看字体文件夹既不高效也不可靠,这时,用脚本自动化获取字体列表就成了最佳方案。


基础原理:操作系统如何管理字体?

操作系统 字体存储路径 格式支持
Windows C:\Windows\Fonts + 用户目录 %APPDATA%\Microsoft\Windows\Fonts .ttf, .otf, .fon
macOS /System/Library/Fonts + /Library/Fonts + ~/Library/Fonts .ttf, .otf, .dfont
Linux /usr/share/fonts + ~/.fonts(或~/.local/share/fonts .ttf, .otf, .woff

脚本的核心逻辑通常是:遍历指定目录中的所有字体文件,提取字体名称(Family Name),但字体名称不一定等于文件名,这需要解析字体元数据。


Python脚本获取字体列表(跨平台)

Python拥有丰富的第三方库,可以轻松实现跨平台字体扫描,以下是一个结合osPIL(Pillow)的示例:

import os
from PIL import ImageFont
def get_font_list(folder_path=None):
    """获取指定目录或系统默认路径下的所有字体名称"""
    if folder_path is None:
        # 根据操作系统自动选择默认路径
        if os.name == 'nt':  # Windows
            folder_path = [os.path.join(os.environ['WINDIR'], 'Fonts'),
                           os.path.join(os.environ['APPDATA'], 'Microsoft', 'Windows', 'Fonts')]
        elif os.sys.platform == 'darwin':  # macOS
            folder_path = ['/System/Library/Fonts', '/Library/Fonts',
                           os.path.expanduser('~/Library/Fonts')]
        else:  # Linux
            folder_path = ['/usr/share/fonts', os.path.expanduser('~/.fonts'),
                           os.path.expanduser('~/.local/share/fonts')]
    fonts = []
    for base_dir in (folder_path if isinstance(folder_path, list) else [folder_path]):
        if not os.path.isdir(base_dir):
            continue
        for root, dirs, files in os.walk(base_dir):
            for f in files:
                if f.lower().endswith(('.ttf', '.otf', '.ttc')):
                    font_path = os.path.join(root, f)
                    try:
                        # 尝试解析字体名称
                        font = ImageFont.truetype(font_path, 14)
                        # 获取字体家族名称(部分字体可能需要调TTF模块直接解析)
                        fonts.append(font.get_name())
                    except Exception:
                        # 若无法解析,使用文件名(不含扩展名)
                        fonts.append(os.path.splitext(f)[0])
    return sorted(set(fonts))
# 使用示例
if __name__ == "__main__":
    all_fonts = get_font_list()
    print(f"共发现 {len(all_fonts)} 种字体")
    for name in all_fonts[:10]:  # 只打印前10个
        print(name)

深入优化:如果PIL无法准确获取中文或特殊字体名称,可使用fonttools库(pip install fonttools)直接解析TTF元数据:

from fontTools.ttLib import TTFont
def get_font_family(font_path):
    try:
        tt = TTFont(font_path)
        name_table = tt['name']
        for record in name_table.names:
            if record.nameID == 1:  # 字体家族名称
                return record.toUnicode()
    except Exception:
        return None

JavaScript在浏览器中获取可用字体

在Web环境中,无法直接访问文件系统,但可以通过Canvas+测量API来探测字体是否存在,下面是经典的字体列表获取实现:

function getInstalledFonts() {
    // 常见测试字符串(包含中英文及特殊字符)
    const testString = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!@#$%^&*()_+-=[]{}|;:,.<>?/~`中文测试';
    const baseFont = 'serif';  // 基准字体
    const testSize = '72px';   // 足够大的字号以放大差异
    // 获取Canvas上下文
    const canvas = document.createElement('canvas');
    const ctx = canvas.getContext('2d');
    // 预测量基准字体的宽度
    ctx.font = testSize + ' ' + baseFont;
    const baseWidth = ctx.measureText(testString).width;
    // 常见字体列表(可根据需求自定义)
    const fontList = [
        'Arial', 'Helvetica', 'Times New Roman', 'Georgia', 'Verdana',
        '微软雅黑', '宋体', '黑体', '楷体', 'SimSun', 'SimHei',
        'Noto Sans SC', 'Source Han Sans', 'PingFang SC', 'STHeiti',
        'Courier New', 'Impact', 'Comic Sans MS', 'Trebuchet MS'
    ];
    const installed = [];
    fontList.forEach(fontName => {
        ctx.font = testSize + ' "' + fontName + '", ' + baseFont;
        const newWidth = ctx.measureText(testString).width;
        // 如果宽度不等于基准宽度,说明该字体存在
        if (newWidth !== baseWidth) {
            installed.push(fontName);
        }
    });
    return installed;
}
// 使用
console.log('已安装字体:', getInstalledFonts());

注意:此方法只能检测清单中的预设字体,无法获取所有已安装字体,若需完整列表,必须使用后端方案(如Node.js调用系统API)。


命令行脚本(Windows/Mac/Linux)

对于运维人员,一行命令即可获取字体列表:

Windows (PowerShell)

Get-ChildItem -Path "$env:WINDIR\Fonts" -Recurse | Select-Object BaseName
# 或更详细:Get-ChildItem -Path "$env:WINDIR\Fonts","$env:LOCALAPPDATA\Microsoft\Windows\Fonts" -Recurse | Select-Object Name, Length

macOS

# 列出所有字体文件(含路径)
find /System/Library/Fonts /Library/Fonts ~/Library/Fonts -name "*.ttf" -o -name "*.otf" 2>/dev/null | while read f; do basename "$f"; done
# 使用系统工具显示更友好列表
system_profiler SPFontsDataType | grep "Family: " | sed 's/.*Family: //'

Linux (Ubuntu/Debian)

# 方式1:直接搜索字体目录
find /usr/share/fonts ~/.fonts ~/.local/share/fonts -type f \( -name "*.ttf" -o -name "*.otf" \) 2>/dev/null | xargs -I {} basename {} | sort -u
# 方式2:使用fc-list(更推荐)
fc-list :lang=en | cut -d: -f2 | sort -u
# 查看中文字体:fc-list :lang=zh | cut -d: -f2 | sort -u

常见问题解答(Q&A)

Q1:为什么我的Python脚本只能获取部分字体?
A:通常是因为字体格式不兼容(如.woff无法被PIL解析),或者字体文件受损,建议先确定脚本支持的格式,对于.woff/.woff2需事先转换为.ttf。

Q2:如何区分中文字体和英文字体?
A:可结合字体名称特征(包含“SC”、“CN”、“中文”)、使用字体库的cmap表检测是否包含CJK统一汉字字符(Unicode范围0x4E00-0x9FFF),示例代码片段:

def is_cjk_font(font_path):
    try:
        tt = TTFont(font_path)
        cmap = tt.getBestCmap()
        # 检查是否包含常见汉字
        return 0x4E00 in cmap
    except:
        return False

Q3:在网页端如何完整获取所有字体?
A:受浏览器安全限制,前端无法直接枚举系统字体,替代方案:1)使用Flash(已弃用);2)调用后端API(如Node.js返回字体列表);3)使用渐进增强技术(预设常用字体库并回退),当前最佳实践是开发阶段使用Electron等框架获取系统字体

Q4:脚本跑得很慢,如何优化?
A:1)只扫描常见目录,不递归搜索隐藏文件夹;2)缓存结果(写入JSON文件);3)使用多线程并行解析字体文件(Python的concurrent.futures);4)对于TTC集合文件,只提取第一个字体名称。


实战案例:筛选中文字体并生成报告

结合上述知识,写一个综合脚本,它能够:

  1. 跨平台扫描字体目录
  2. 提取所有字体名称
  3. 筛选出系统支持中文的字体
  4. 输出为Markdown格式报告
import os
import json
from fontTools.ttLib import TTFont
def scan_and_report(output_file='fonts_report.md'):
    fonts_info = []
    # 字体目录配置(同上文)
    search_dirs = [...]
    for base_dir in search_dirs:
        if not os.path.exists(base_dir):
            continue
        for root, dirs, files in os.walk(base_dir):
            for f in files:
                if f.lower().endswith(('.ttf', '.otf')):
                    path = os.path.join(root, f)
                    try:
                        tt = TTFont(path)
                        name_table = tt['name']
                        family_name = ''
                        for record in name_table.names:
                            if record.nameID == 1:
                                family_name = record.toUnicode()
                                break
                        # 检测是否支持中文
                        cmap = tt.getBestCmap()
                        supports_cjk = any(0x4E00 <= ch <= 0x9FFF for ch in cmap)
                        fonts_info.append({
                            'filename': f,
                            'family': family_name,
                            'supports_cjk': supports_cjk,
                            'path': path
                        })
                    except Exception as e:
                        continue
    # 生成报告
    with open(output_file, 'w', encoding='utf-8') as f:
        f.write('# 系统字体列表报告\n\n')
        f.write(f'共发现 {len(fonts_info)} 种字体\n\n')
        f.write('## 中文字体支持\n')
        cjk_fonts = [x for x in fonts_info if x['supports_cjk']]
        for font in cjk_fonts:
            f.write(f"- {font['family']} ({font['filename']})\n")
        f.write('\n## 所有字体列表\n')
        for font in fonts_info:
            f.write(f"| {font['family']} | {font['filename']} | {'是' if font['supports_cjk'] else '否'} |\n")
    print(f'报告已生成:{output_file}')
scan_and_report()

SEO优化贴士与最佳实践

关键词**:文章标题包含“脚本获取字体列表”、“字体遍历”、“系统字体检测”等高搜索量词组。

  • 内链与外链:合理连接相关技术文章(如Python基础教程、CSS字体回退策略),增强权威性。
  • 结构化数据:使用<h2><ul>等语义化标签组织内容,并添加FAQ Schema标记。
  • 移动端适配:代码示例使用代码块(markdown或前端的<pre>),确保在手机端可横向滚动。
  • 原创性与深度:避免直接复制Stack Overflow或官方文档;结合个人开发经验解释陷阱与优化点。

通过本文的方法,你可以根据实际需求选择最适合的脚本方式,无论是桌面应用开发、Web前端检测还是服务器批量处理,都能高效获取字体列表,建议将常用脚本封装为模块或CLI工具,以便随时调用。

抱歉,评论功能暂时关闭!