2011-04-21 147 views
4

什麼是一個完整的例子,從無到有在內存中的位圖結束,打開一個特定的.ttf文件並使用該字體渲染一些文本,使用本機Windows API?我目前正在瀏覽Windows API,所以這是我和其他人之間的比賽。python:使用windows api來渲染使用ttf字體的文本

+0

你*有*使用本地的Windows API?如果沒有,您可以使用[PIL](http://www.pythonware.com/products/pil/)。 – 2011-04-21 23:31:40

+0

@哈里森:是的,看到我的[其他](http://stackoverflow.com/questions/5747739/python-render-non-anti-aliased-font-to-internal-image/5747805#5747805)[問題]( http://stackoverflow.com/questions/5748973/why-is-my-truetype-font-of-size-11-rendering-different-than-windows) – Claudiu 2011-04-21 23:35:34

回答

5

完成和渲染字體完成(需要PyWin32):

import ctypes 
import struct 
import win32con 
import win32gui 
import win32ui 

from PIL import Image 


def RGB(r, g, b):  
    return r | (g << 8) | (b << 16) 

def native_bmp_to_pil(hdc, bitmap_handle, width, height): 
    bmpheader = struct.pack("LHHHH", struct.calcsize("LHHHH"), 
          width, height, 1, 24) #w,h, planes=1, bitcount) 
    c_bmpheader = ctypes.c_buffer(bmpheader) 

    #3 bytes per pixel, pad lines to 4 bytes  
    c_bits = ctypes.c_buffer(" " * (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 = 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}) 

     #create a compatible DC we can use to draw: 
     self.desktopHwnd = win32gui.GetDesktopWindow() 
     self.desktopDC = win32gui.GetWindowDC(self.desktopHwnd) 
     self.mfcDC = win32ui.CreateDCFromHandle(self.desktopDC)   
     self.drawDC = self.mfcDC.CreateCompatibleDC() 

     #initialize it 
     self.drawDC.SelectObject(self.font) 

    def renderText(self, text): 
     """render text to a PIL image using the windows API.""" 
     self.drawDC.SetTextColor(RGB(255,0,0)) 

     #create the compatible bitmap: 
     w,h = self.drawDC.GetTextExtent(text) 

     saveBitMap = win32ui.CreateBitmap() 
     saveBitMap.CreateCompatibleBitmap(self.mfcDC, w, h)   
     self.drawDC.SelectObject(saveBitMap) 

     #draw it 
     self.drawDC.DrawText(text, (0, 0, w, h), win32con.DT_LEFT) 

     #convert to PIL image 
     im = native_bmp_to_pil(self.drawDC.GetSafeHdc(), saveBitMap.GetHandle(), w, h) 

     #clean-up 
     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()) 

    def __del__(self): 
     win32gui.DeleteObject(self.font.GetSafeHandle()) 

用法:

>>> f = Win32Font("Arial", 15) 
>>> im = f.renderText("this is just a test") 
>>> im.save("c:/hope.png") 

結果:

​​

輝煌!

要呈現特定的.ttf文件,我需要多挖掘一下。

更新:更新計算BMP大小:

woot http://i51.tinypic.com/s4rq7s.png

+0

你不想渲染一個ttf文件 – 2011-04-22 19:08:34

+1

@David :你可以閱讀我的想法!?!開開玩笑,你是什麼意思? – Claudiu 2011-04-22 19:18:49

+0

字體通常由多個ttf文件組成。一般你想渲染一個字體,例如Arial字體。查看構成arial的不同ttf文件。 – 2011-04-22 19:57:23