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

如何将.ttf字体嵌入Python打包的.exe并在任意电脑生效

如何将自定义字体嵌入打包后的Tkinter exe文件

我有一个正常运行的Python Tkinter程序,使用本地下载的Trajan Pro Regular.ttf字体。目标是将该字体嵌入打包后的.exe文件,让任何电脑运行程序时都能正确显示该字体,无需额外安装或放置字体文件在exe同目录。

尝试过的方法及问题

1. pyglet加载字体

使用pyglet加载字体时触发FileNotFoundError,提示找不到字体文件:

Traceback (most recent call last):
  File "ModifierTool.py", line 66, in <module>
  File "pyglet\font\__init__.py", line 156, in add_file
FileNotFoundError: [Errno 2] No such file or directory: 'Trajan Pro Regular.ttf'

将字体放在exe同目录可消除错误,但未安装该字体的电脑仍无法正常显示;且这种方式不符合嵌入字体的需求。

2. 用resource_path加载字体

尝试用加载图片/资源的resource_path方法加载字体,代码片段如下:

import tkinter as tk
import tkinter.font as tkfont
import sys
import os

def resource_path(relative_path):
        try:
            base_path = sys._MEIPASS
        except Exception:
            base_path = os.path.abspath(".")
        return os.path.join(base_path, relative_path)

font_file = resource_path('Trajan Pro Regular.ttf')
trajan_pro = tkfont.Font(family='Trajan Pro', file=font_file, size=10, weight='bold')

def create_widgets(self):
    button_text = tk.Label(frame, text=option, font=trajan_pro, bg='#222222', fg='white')

该方法无效,字体仍无法正常加载。

3. tkextrafont加载字体

使用tkextrafont加载字体时直接失败,代码片段:

import tkinter as tk
import pathlib
import tkextrafont
from tkextrafont import Font
    
def create_widgets(self):
    fontpath = pathlib.Path(__file__).parent/"Trajan Pro Regular.ttf"
    font = tkextrafont.Font(file=str(fontpath), family= "Trajan Pro Regular", size= 12, weight= 'bold')
    all_button_label = tk.Label(frame, text='All', font=font, bg='#222222', fg='white')

if __name__ == '__main__':
    root = tk.Tk()

4. AddFontResourceEx函数加载字体

使用Windows API的AddFontResourceEx函数加载字体,能在未安装字体的电脑上运行.py和.exe文件,但字体必须放在exe同目录,无法实现嵌入。打包时已添加--add-data "D:/Desktop/Modifier Tool/Trajan Pro Regular.ttf;."参数,直接使用PyInstaller命令结果一致。

问题复现代码:

import tkinter as tk
import tkinter.font as tkfont
from ctypes import windll, byref, create_unicode_buffer, create_string_buffer

FR_PRIVATE  = 0x10
FR_NOT_ENUM = 0x20

def loadfont(fontpath, private=True, enumerable=False):
    if isinstance(fontpath, bytes):
        pathbuf = create_string_buffer(fontpath)
        AddFontResourceEx = windll.gdi32.AddFontResourceExA
    elif isinstance(fontpath, str):
        pathbuf = create_unicode_buffer(fontpath)
        AddFontResourceEx = windll.gdi32.AddFontResourceExW
    else:
        raise TypeError('fontpath must be of type str or unicode')
    
    flags = (FR_PRIVATE if private else 0) | (FR_NOT_ENUM if not enumerable else 0)
    numFontsAdded = AddFontResourceEx(byref(pathbuf), flags, 0)
    return bool(numFontsAdded)

class App(tk.Frame):
    def __init__(self, master=None, **kwargs):
        super().__init__(master, **kwargs)
        self.master = master
        self.create_widgets()

    def create_widgets(self):
        font_path = ("MyFont.ttf")
        loadfont(font_path)
        label = tk.Label(text='Hello', font=tkfont.Font(family='My Font'))
        label.pack()

root = tk.Tk()
app = App(root)
root.mainloop()

补充:pyglet问题复现

使用pyglet的代码,除非字体放在exe同目录否则报错,放在同目录则能正常加载:

import tkinter as tk
import tkinter.font as tkfont
import pyglet

pyglet.options['win32_gdi_font'] = True
pyglet.font.add_file('MyFont.ttf')

class App(tk.Frame):
    def __init__(self, master=None, **kwargs):
        super().__init__(master, **kwargs)
        self.master = master
        self.create_widgets()

    def create_widgets(self):
        label = tk.Label(text='Hello', font=tkfont.Font(family='My Font'))
        label.pack()

if __name__ == '__main__':
    root = tk.Tk()
    app = App(root)
    root.mainloop()

报错信息:

Traceback (most recent call last):
  File "Test.py", line 7, in <module>
  File "pyglet\font\__init__.py", line 156, in add_file
FileNotFoundError: [Errno 2] No such file or directory: 'MyFont.ttf'

内容的提问来源于stack exchange,提问作者Basile

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.22 14:18:09