using pyinstaller keep the fonts on all systems

Question:

I made a GUI using tkinter.

I created onefile exe with pyinstaller, but seted font (font = freesans.ttf) is not applied to other computers.

I think I need to adddata a font, but I don’t understand the answers of pygame or pyqt in cases similar to mine.

Asked By: JAY100

||

Answers:

Here’s a solution for adding custom fonts to pyinstaller executables on Windows. You’ll need to add your font path to the pyinstaller build with --add-data so it can be picked up in the MEI folder used by the executable.

import ctypes
import sys
from pathlib import Path


def fetch_resource(rsrc_path):
    """Loads resources from the temp dir used by pyinstaller executables"""
    try:
        base_path = Path(sys._MEIPASS)
    except AttributeError:
        return rsrc_path  # not running as exe, just return the unaltered path
    else:
        return base_path.joinpath(rsrc_path)


def load_font(font_path, private=True, enumerable=False):
    """Add the font at 'font_path' as a Windows font resource"""
    FR_PRIVATE = 0x10
    FR_NOT_ENUM = 0x20
    flags = (FR_PRIVATE * int(private)) | (FR_NOT_ENUM * int(1 - enumerable))
    font_fetch = str(fetch_resource(font_path))
    path_buf = ctypes.create_unicode_buffer(font_fetch)
    add_font = ctypes.windll.gdi32.AddFontResource.ExW
    font_added = add_font(ctypes.byref(path_buf), flags, 0)
    return bool(font_added)  # True if the font was added successfully

Then in your main Python file (or wherever you’re trying to use freesans), you can load the font like so

import tkinter.font as font

custom_font = 'Freesans'  # check the name your system uses, I'm just gussing here

if custom_font not in font.families() and not load_font('<path/to/freesans.ttf>'):
    custom_font = 'Fallback font name here'  # if freesans can't be loaded...

An important note is that my fetch_resource function can be used for just about any app asset you need, like icons or images. Just remember to add them to pyinstaller via --add-data, and wherever you’re using them in your Python file, get their paths via my_icon = fetch_resource('path/to/my_icon.ico') for example/ That way, you can use my_icon when running as a script or when running as a built exe!

Answered By: JRiggles
Categories: questions Tags: , ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.