You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

如何在Windows系统中无需重启,使用Python批量安装字体?

如何在Windows系统中无需重启,使用Python批量安装字体?

我完全懂你的困扰——手动点安装字体效率太低,自己写的批量脚本虽然能把字体文件复制到系统Fonts目录、更新注册表,但必须重启电脑才能让系统认出新字体,这对要即时用字体的场景实在太不友好了。

其实问题出在:Windows不会自动监测Fonts目录和注册表的字体更新,得主动通知它刷新字体缓存才行。下面就给你解决方法,直接修改你的代码就能实现无需重启生效。

关键原理:发送系统刷新消息

Windows提供了WM_FONTCHANGE消息,只要把这个消息广播给所有顶层窗口,系统就会立刻重新加载字体列表,不用重启。另外配合AddFontResource API可以进一步确保字体被正确注册。

修改后的完整代码

我在你的代码基础上添加了字体刷新的逻辑,还补了一些细节优化(比如跳过已存在的字体文件):

from fontTools.ttLib import TTFont
import winreg
import os
import ctypes
from ctypes import wintypes

def list_fonts(folder):
    result = {}
    for file in os.scandir(folder):
        if file.is_file() and file.name.endswith((".otf", ".ttf")):
            path = file.path.replace("\\", "/")
            try:
                name = TTFont(path)["name"]
                result.setdefault(name.getDebugName(1), {})[name.getDebugName(2)] = (
                    name.getDebugName(4),
                    path,
                )
            except Exception as e:
                print(f"处理字体文件失败 {file.name}: {e}")
    return result

def refresh_font_cache():
    # 广播字体更新消息给系统
    HWND_BROADCAST = 0xFFFF
    WM_FONTCHANGE = 0x001D
    user32 = ctypes.WinDLL('user32', use_last_error=True)
    user32.SendMessageW.argtypes = (wintypes.HWND, wintypes.UINT, wintypes.WPARAM, wintypes.LPARAM)
    user32.SendMessageW(HWND_BROADCAST, WM_FONTCHANGE, 0, 0)
    
    # 可选:调用AddFontResource确保字体被系统识别(针对部分特殊字体)
    gdi32 = ctypes.WinDLL('gdi32', use_last_error=True)
    gdi32.AddFontResourceW.argtypes = (wintypes.LPCWSTR,)

HKLM = winreg.ConnectRegistry(None, winreg.HKEY_LOCAL_MACHINE)
FONTS_KEY = winreg.OpenKey(
    HKLM,
    r"SOFTWARE\Microsoft\Windows NT\CurrentVersion\Fonts",
    0,
    winreg.KEY_ALL_ACCESS,
)

def install_fonts(folder):
    fonts_list = list_fonts(folder)
    fonts_dir = os.path.join(os.environ["WINDIR"], "Fonts")
    
    for styles in fonts_list.values():
        for font_name, path in styles.values():
            font_filename = os.path.basename(path)
            target_path = os.path.join(fonts_dir, font_filename)
            
            # 跳过已存在的字体,避免覆盖
            if os.path.exists(target_path):
                print(f"字体 {font_filename} 已存在,跳过安装")
                continue
            
            # 复制字体文件到系统Fonts目录
            try:
                with open(path, "rb") as reader, open(target_path, "wb") as writer:
                    writer.write(reader.read())
                print(f"已复制字体文件: {font_filename}")
            except Exception as e:
                print(f"复制字体文件失败 {font_filename}: {e}")
                continue
            
            # 更新注册表
            try:
                reg_value_name = f"{font_name} (TrueType)" if font_filename.endswith(".ttf") else font_name
                winreg.SetValueEx(
                    FONTS_KEY,
                    reg_value_name,
                    0,
                    winreg.REG_SZ,
                    font_filename,
                )
                print(f"已更新注册表: {reg_value_name}")
            except Exception as e:
                print(f"更新注册表失败 {reg_value_name}: {e}")
                # 若注册表更新失败,删除已复制的字体文件
                if os.path.exists(target_path):
                    os.remove(target_path)
    
    # 安装完成后刷新字体缓存
    refresh_font_cache()
    print("字体缓存已刷新,无需重启即可使用新字体!")

注意事项

  1. 必须以管理员权限运行脚本:因为要写入系统Fonts目录和修改HKLM下的注册表,普通权限会报错。右键点击Python脚本,选择「以管理员身份运行」即可。
  2. 测试验证:安装完成后,打开Word、PS等软件,就能直接在字体列表里找到新安装的字体了;如果系统自带的Fonts文件夹没立刻显示,关闭再重新打开就能看到。
  3. 字体文件兼容性:确保你的字体文件是标准的.ttf.otf格式,损坏的字体文件会被脚本跳过并提示错误。

备注:内容来源于stack exchange,提问作者Ξένη Γήινος

火山引擎 最新活动