Search code examples
pythonwinapictypespywin32

Load font file with Windows api Python


I was looking for a way to load a ttf file and print text with that font. While looking for some information, I found this question: load a ttf font with the Windows API

In that question they recommend adding a private font with AddFontResourceEx. But I didn't find any way to access such function with pywin32 module and ctypes.windll. Is there any way to access this function? Or failing that, another way to print text with a ttf font without using Pillow???

Next, I will leave a code so you can do the tests:

import win32print
import win32gui
import win32ui

hprinter = win32print.OpenPrinter("Microsoft Print to Pdf")

devmode = win32print.GetPrinter(hprinter, 2)["pDevMode"]

hdc = win32gui.CreateDC("WINSPOOL", printer, devmode)
dc = win32ui.CreateDCFromHandle(Self.hdc)

Edit

I managed to access the function with

ctypes.windll.gdi32.AddFontResourceExA

But now I want to access the FR_PRIVATE constant. How can I do it?

Edit 2

I found out that the function doesn't work even without that constant.


Solution

  • I adapted the code from this answer and got the answer!

    I will put the code below:

    def add_font_file(file):
        FR_PRIVATE = 0x10
        
        file = ctypes.byref(ctypes.create_unicode_buffer(file))
        font_count = gdi32.AddFontResourceExW(file, FR_PRIVATE, 0)
    
        if(font_count == 0):
            raise RuntimeError("Error durante la carga de la fuente.")
    

    In case the original link goes down, the original code was as follows:

    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):
        '''
        Makes fonts located in file `fontpath` available to the font system.
    
        `private`     if True, other processes cannot see this font, and this 
                      font will be unloaded when the process dies
        `enumerable`  if True, this font will appear when enumerating fonts
    
        See https://msdn.microsoft.com/en-us/library/dd183327(VS.85).aspx
    
        '''
        # This function was taken from
        # https://github.com/ifwe/digsby/blob/f5fe00244744aa131e07f09348d10563f3d8fa99/digsby/src/gui/native/win/winfonts.py#L15
        # This function is written for Python 2.x. For 3.x, you
        # have to convert the isinstance checks to bytes and str
        if isinstance(fontpath, str):
            pathbuf = create_string_buffer(fontpath)
            AddFontResourceEx = windll.gdi32.AddFontResourceExA
        elif isinstance(fontpath, unicode):
            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)