Installer en skrifttype ved hjælp af python i Windows

Indlæg af Hanne Mølgaard Plasc

Problem



Jeg udvikler et python-script til at installere en liste over skrifttyper i Windows.
Jeg har en liste som denne,


fonts\_list = ["/path/to/file/myFont1.ttf", "/path/to/file/myFont1.ttf", "/path/to/file/myFont1.ttf"]


Jeg prøvede simpelthen at kopiere skrifttypefiler ved hjælp af både shutil og os, og derefter forsøgte jeg at tilføje det til Windows-registreringsdatabasen, selv med admin privilegierne, fungerede det ikke. Output fra scriptet viste ingen fejl, men der er ingen nogen font i Windows Fonts bibliotek, der er nævnt i listen.


os.system(reg add "HKLMSOFTWAREMicrosoftWindows NTCurrentVersionFonts" /v "FontName (TrueType)")


Så jeg begyndte at søge flere frø fra nettet, og så fandt jeg denne, installerer TTF-skrifttyper på windows med python. Men det fungerede også. Næste forsøgte jeg at kalde Windows fontview.exe, men for en liste over skrifttyper er det en katastrofe.


os.system("fontview " + fontsList[0])


Er der alligevel installeret en skrifttype i Windows programmatisk? Eller er der nogen brugerniveau mappe i Windows for simpelthen at kopiere skrifttype filer som Linux-systemer har ~/.fonter og Mac'er har ~/Bibliotek/Fonts? Hjælp venligst.

Bedste reference


Her er en install\_font funktion til at kopiere en skrifttype til systemfontsmappen, indlæse den i den aktuelle session, give besked til kørende programmer og opdatere registreringsdatabasen. Det afhænger kun af Pythons standardbibliotek og skal fungere i begge Python 2 og 3.


definitioner af ctypes


import os
import shutil
import ctypes
from ctypes import wintypes

try:
    import winreg
except ImportError:
    import \_winreg as winreg

user32 = ctypes.WinDLL('user32', use\_last\_error=True)
gdi32 = ctypes.WinDLL('gdi32', use\_last\_error=True)

FONTS\_REG\_PATH = r'SoftwareMicrosoftWindows NTCurrentVersionFonts'

HWND\_BROADCAST   = 0xFFFF
SMTO\_ABORTIFHUNG = 0x0002
WM\_FONTCHANGE    = 0x001D
GFRI\_DESCRIPTION = 1
GFRI\_ISTRUETYPE  = 3

if not hasattr(wintypes, 'LPDWORD'):
    wintypes.LPDWORD = ctypes.POINTER(wintypes.DWORD)

user32.SendMessageTimeoutW.restype = wintypes.LPVOID
user32.SendMessageTimeoutW.argtypes = (
    wintypes.HWND,   # hWnd
    wintypes.UINT,   # Msg
    wintypes.LPVOID, # wParam
    wintypes.LPVOID, # lParam
    wintypes.UINT,   # fuFlags
    wintypes.UINT,   # uTimeout
    wintypes.LPVOID) # lpdwResult

gdi32.AddFontResourceW.argtypes = (
    wintypes.LPCWSTR,) # lpszFilename

# http://www.undocprint.org/winspool/getfontresourceinfo
gdi32.GetFontResourceInfoW.argtypes = (
    wintypes.LPCWSTR, # lpszFilename
    wintypes.LPDWORD, # cbBuffer
    wintypes.LPVOID,  # lpBuffer
    wintypes.DWORD)   # dwQueryType


funktionsdefinition


def install\_font(src\_path):
    # copy the font to the Windows Fonts folder
    dst\_path = os.path.join(os.environ['SystemRoot'], 'Fonts',
                            os.path.basename(src\_path))
    shutil.copy(src\_path, dst\_path)
    # load the font in the current session
    if not gdi32.AddFontResourceW(dst\_path):
        os.remove(dst\_path)
        raise WindowsError('AddFontResource failed to load "\%s"' \% src\_path)
    # notify running programs
    user32.SendMessageTimeoutW(HWND\_BROADCAST, WM\_FONTCHANGE, 0, 0,
                               SMTO\_ABORTIFHUNG, 1000, None)
    # store the fontname/filename in the registry
    filename = os.path.basename(dst\_path)
    fontname = os.path.splitext(filename)[0]
    # try to get the font's real name
    cb = wintypes.DWORD()
    if gdi32.GetFontResourceInfoW(filename, ctypes.byref(cb), None,
                                  GFRI\_DESCRIPTION):
        buf = (ctypes.c\_wchar * cb.value)()
        if gdi32.GetFontResourceInfoW(filename, ctypes.byref(cb), buf,
                                      GFRI\_DESCRIPTION):
            fontname = buf.value
    is\_truetype = wintypes.BOOL()
    cb.value = ctypes.sizeof(is\_truetype)
    gdi32.GetFontResourceInfoW(filename, ctypes.byref(cb),
        ctypes.byref(is\_truetype), GFRI\_ISTRUETYPE)
    if is\_truetype:
        fontname += ' (TrueType)'
    with winreg.OpenKey(winreg.HKEY\_LOCAL\_MACHINE, FONTS\_REG\_PATH, 0,
                        winreg.KEY\_SET\_VALUE) as key:
        winreg.SetValueEx(key, fontname, 0, winreg.REG\_SZ, filename)