python:使用windows api使用ttf字体呈现文本

python:使用windows api使用ttf字体呈现文本,python,windows,winapi,fonts,rendering,Python,Windows,Winapi,Fonts,Rendering,打开一个特定的.ttf文件,并使用本机Windows API使用该字体呈现一些文本,从一无所有到最后在内存中显示位图,这是一个什么样的完整示例?我目前正在苦读windows API,因此这是我和stackoverflow其他人之间的竞争。完成并完成字体渲染(需要PyWin32): 结果: 太棒了 要呈现一个特定的.ttf文件,我需要深入研究 更新:更新以计算bmp大小: 这里是Python3的更新版本,已接受的答案(完全归功于@Claudiu)。我以“Segoe UI”为例,展示如何完美匹配本

打开一个特定的
.ttf
文件,并使用本机Windows API使用该字体呈现一些文本,从一无所有到最后在内存中显示位图,这是一个什么样的完整示例?我目前正在苦读windows API,因此这是我和stackoverflow其他人之间的竞争。

完成并完成字体渲染(需要PyWin32):

结果:

太棒了

要呈现一个特定的
.ttf
文件,我需要深入研究

更新:更新以计算bmp大小:


这里是Python3的更新版本,已接受的答案(完全归功于@Claudiu)。我以“Segoe UI”为例,展示如何完美匹配本机Windows用户界面:

import ctypes, struct, win32con, win32gui, win32ui, PIL.Image

def native_bmp_to_pil(hdc, bitmap_handle, width, height):
    bmpheader = struct.pack("LHHHH", struct.calcsize("LHHHH"), width, height, 1, 24)
    c_bmpheader = ctypes.c_buffer(bmpheader)
    c_bits = ctypes.c_buffer(b" " * (height * ((width*3 + 3) & -4)))
    res = ctypes.windll.gdi32.GetDIBits(hdc, bitmap_handle, 0, height, c_bits, c_bmpheader, win32con.DIB_RGB_COLORS)
    if not res:
        raise IOError("native_bmp_to_pil failed: GetDIBits")
    im = PIL.Image.frombuffer("RGB", (width, height), c_bits, "raw", "BGR", (width*3 + 3) & -4, -1)
    return im    

class Win32Font:
    def __init__(self, name, height, weight=win32con.FW_NORMAL, italic=False, underline=False):
        self.font = win32ui.CreateFont({'name': name, 'height': height, 'weight': weight, 'italic': italic, 'underline': underline})
        self.desktopHwnd = win32gui.GetDesktopWindow()
        self.desktopDC = win32gui.GetWindowDC(self.desktopHwnd)
        self.mfcDC = win32ui.CreateDCFromHandle(self.desktopDC)
        self.drawDC = self.mfcDC.CreateCompatibleDC()
        self.drawDC.SelectObject(self.font)

    def renderText(self, text):
        self.drawDC.SetTextColor(0)
        w,h = self.drawDC.GetTextExtent(text)
        saveBitMap = win32ui.CreateBitmap()
        saveBitMap.CreateCompatibleBitmap(self.mfcDC, w, h)        
        self.drawDC.SelectObject(saveBitMap)
        self.drawDC.DrawText(text, (0, 0, w, h), win32con.DT_LEFT)
        im = native_bmp_to_pil(self.drawDC.GetSafeHdc(), saveBitMap.GetHandle(), w, h)
        win32gui.DeleteObject(saveBitMap.GetHandle())
        return im

    def __del__(self):
        self.mfcDC.DeleteDC()
        self.drawDC.DeleteDC()
        win32gui.ReleaseDC(self.desktopHwnd, self.desktopDC)
        win32gui.DeleteObject(self.font.GetSafeHandle())

f = Win32Font("Segoe UI", 15)
im = f.renderText("Hello World")
im.save("test.png")

您必须使用本机Windows API吗?如果没有,您可以使用。@Harpyon:yes,请参阅我的“您不想渲染ttf”file@David:你能读懂我的心思!?!别开玩笑了,你是什么意思?字体通常由多个ttf文件组成。通常,您希望呈现字体,例如Arial。查看并查看组成arial的不同ttf文件。您应该安装字体并继续使用它。这是你应该做的。@David:那很好,但是如何从字体文件中获取字体?
>>> f = Win32Font("Arial", 15)
>>> im = f.renderText("this is just a test")
>>> im.save("c:/hope.png")
import ctypes, struct, win32con, win32gui, win32ui, PIL.Image

def native_bmp_to_pil(hdc, bitmap_handle, width, height):
    bmpheader = struct.pack("LHHHH", struct.calcsize("LHHHH"), width, height, 1, 24)
    c_bmpheader = ctypes.c_buffer(bmpheader)
    c_bits = ctypes.c_buffer(b" " * (height * ((width*3 + 3) & -4)))
    res = ctypes.windll.gdi32.GetDIBits(hdc, bitmap_handle, 0, height, c_bits, c_bmpheader, win32con.DIB_RGB_COLORS)
    if not res:
        raise IOError("native_bmp_to_pil failed: GetDIBits")
    im = PIL.Image.frombuffer("RGB", (width, height), c_bits, "raw", "BGR", (width*3 + 3) & -4, -1)
    return im    

class Win32Font:
    def __init__(self, name, height, weight=win32con.FW_NORMAL, italic=False, underline=False):
        self.font = win32ui.CreateFont({'name': name, 'height': height, 'weight': weight, 'italic': italic, 'underline': underline})
        self.desktopHwnd = win32gui.GetDesktopWindow()
        self.desktopDC = win32gui.GetWindowDC(self.desktopHwnd)
        self.mfcDC = win32ui.CreateDCFromHandle(self.desktopDC)
        self.drawDC = self.mfcDC.CreateCompatibleDC()
        self.drawDC.SelectObject(self.font)

    def renderText(self, text):
        self.drawDC.SetTextColor(0)
        w,h = self.drawDC.GetTextExtent(text)
        saveBitMap = win32ui.CreateBitmap()
        saveBitMap.CreateCompatibleBitmap(self.mfcDC, w, h)        
        self.drawDC.SelectObject(saveBitMap)
        self.drawDC.DrawText(text, (0, 0, w, h), win32con.DT_LEFT)
        im = native_bmp_to_pil(self.drawDC.GetSafeHdc(), saveBitMap.GetHandle(), w, h)
        win32gui.DeleteObject(saveBitMap.GetHandle())
        return im

    def __del__(self):
        self.mfcDC.DeleteDC()
        self.drawDC.DeleteDC()
        win32gui.ReleaseDC(self.desktopHwnd, self.desktopDC)
        win32gui.DeleteObject(self.font.GetSafeHandle())

f = Win32Font("Segoe UI", 15)
im = f.renderText("Hello World")
im.save("test.png")