I'm trying to use GDI+ (via ctypes) to draw text. It works for some fonts but messes up with others. Using Times, for example, it seems to be using the glyphs for one character earlier in the code sequence, so that "Times" comes out as "Shldr" -- except that it uses the widths of the original characters for positioning.
Can someone please run the attached code and tell me whether it works for them or not? And any ideas on what I could be doing wrong to cause this? -- Greg
import os, traceback from ctypes import * from ctypes.wintypes import * gdiplus = windll.gdiplus SW_HIDE = 0 SW_SHOW = 5 GWL_WNDPROC = -4 GWL_STYLE = -16 CS_VREDRAW = 0x0001 CS_HREDRAW = 0x0002 CS_GLOBALCLASS = 0x4000 WS_OVERLAPPEDWINDOW = 13565952 WS_VISIBLE = 0x10000000 WS_SYSMENU = 0x00080000 WM_QUIT = 0x0012 WM_PAINT = 0x000f WM_CLOSE = 0x0010 LF_FACESIZE = 32 WNDPROC = WINFUNCTYPE(c_long, c_int, c_uint, c_int, c_int) class WNDCLASS(Structure): _fields_ = [ ('style', c_uint), ('lpfnWndProc', WNDPROC), ('cbClsExtra', c_int), ('cbWndExtra', c_int), ('hInstance', c_int), ('hIcon', c_int), ('hCursor', c_int), ('hbrBackground', c_int), ('lpszMenuName', c_char_p), ('lpszClassName', c_char_p), ] class PAINTSTRUCT(Structure): _fields_ = [ ('hdc', c_int), ('fErase', c_int), ('rcPaint', RECT), ('fRestore', c_int), ('fIncUpdate', c_int), ('rgbReserved', c_char * 32), ] lo_byte = lambda x : x & 0xff hi_byte = lambda x : x >> 8 & 0xff lo_word = lambda x : x & 0xffff hi_word = lambda x : x >> 16 & 0xffff class RectF(Structure): _fields_ = [ ('x', c_float), ('y', c_float), ('w', c_float), ('h',c_float), ] class LOGFONT(Structure): _fields_ = [ ('lfHeight', c_long), ('lfWidth', c_long), ('lfEscapement', c_long), ('lfOrientation', c_long), ('lfWeight', c_long), ('lfItalic', c_byte), ('lfUnderline', c_byte), ('lfStrikeOut', c_byte), ('lfCharSet', c_byte), ('lfOutPrecision', c_byte), ('lfClipPrecision', c_byte), ('lfQuality', c_byte), ('lfPitchAndFamily', c_byte), ('lfFaceName', c_char * LF_FACESIZE), ] def __init__(self): self.lfHeight, self.lfWidth = 10, 10 self.lfEscapement = 10 self.lfOrientation = 0 self.lfUnderline = 0 self.lfStrikeOut = 0 self.lfCharSet = 0 # ANSI_CHARSET self.lfPitchAndFamily = 0 self.lfOutPrecision = 0 self.lfClipPrecision = 0 self.lfQuality = 0 self.lfPitchAndFamily = 2 class GdiplusStartupInput(Structure): _fields_ = [ ('GdiplusVersion', c_uint), ('DebugEventCallback', c_void_p), ('SuppressBackgroundThread', BOOL), ('SuppressExternalCodecs', BOOL), ] def __init__(self): Structure.__init__(self) self.GdiplusVersion = 1 self.DebugEventCallback = None self.SuppressBackgroundThread = 0 self.SuppressExternalCodecs = 0 StartupInput = GdiplusStartupInput() token = c_ulong() gdiplus.GdiplusStartup(pointer(token), pointer(StartupInput), None) class Font(object): def __init__(self, family, size = 12, style = []): logfont = LOGFONT() logfont.lfFaceName = family logfont.lfHeight = -size logfont.lfWidth = 0 if 'italic' in style: logfont.lfItalic = 1 else: logfont.lfItalic = 0 if 'bold' in style: logfont.lfWeight = 10 else: logfont.lfWeight = 0 self._size = size self._win32_object = windll.gdi32.CreateFontIndirectA(byref(logfont)) self._free_object = True self._family = family # should came elsewhere class Canvas(object): def __init__(self, hdc): self._hdc = hdc self._GpGraphics = c_void_p() gdiplus.GdipCreateFromHDC(hdc, byref(self._GpGraphics)) self._GpFont = c_void_p() self._GpBrush = c_void_p() gdiplus.GdipCreateSolidFill(0xff000000, byref(self._GpBrush)) print "Canvas: brush =", self._GpBrush.value ### self._GpPen = c_void_p() gdiplus.GdipCreatePen1(0xff000000, c_float(1.0), 2, byref(self._GpPen)) def set_font(self, f): windll.gdi32.SelectObject(self._hdc, f._win32_object) gdiplus.GdipDeleteFont(self._GpFont) gdiplus.GdipCreateFontFromDC(self._hdc, byref(self._GpFont)) self._font = f def show_text(self, x, y, text): font = self._font _rect = RectF(x, y, 0, 0) size = len(text) gdiplus.GdipDrawString(self._GpGraphics, unicode(text), size, self._GpFont, byref(_rect), None, self._GpBrush) def set_forecolor(self, color): gdiplus.GdipSetSolidFillColor(self._GpBrush, c_int(color)) gdiplus.GdipSetPenColor(self._GpPen, c_int(color)) def fill_rect(self, rect): print "fill_rect", rect, "with", self._GpBrush.value ### l, t, r, b = rect gdiplus.GdipFillRectangle(self._GpGraphics, self._GpBrush, c_float(l), c_float(t), c_float(r - l), c_float(b - t)) class Test(object): def __init__(self): self.cname = "FOO" wcls = WNDCLASS() wcls.style = 0 #CS_GLOBALCLASS | CS_HREDRAW | CS_VREDRAW wcls.lpfnWndProc = WNDPROC(window_proc) wcls.cbClsExtra = wcls.cbWndExtra = 0 wcls.hInstance = windll.kernel32.GetModuleHandleA(c_int(0)) wcls.hbrBackground = 0 #wc.COLOR_WINDOW + 1 wcls.lpszMenuName = None wcls.lpszClassName = self.cname self.wcls = wcls windll.user32.RegisterClassA(byref(wcls)) hwnd = windll.user32.CreateWindowExA( 0, # styleEx "FOO", # className "Test GDI+ Text - ctypes", # windowTitle WS_OVERLAPPEDWINDOW | WS_VISIBLE, # style 100, 100, 400, 100, # x, y, width, height, 0, # parent 0, # menu 0, # hinstance 0 # reserved ) self.hwnd = hwnd # def OnClose(self): # gui.PostQuitMessage(0) def OnPaint(self): print "OnPaint" hwnd = self.hwnd ps = PAINTSTRUCT() hdc = windll.user32.BeginPaint(hwnd, byref(ps)) yellow = 0xffffff00 black = 0xff000000 canvas = Canvas(hdc) canvas.set_forecolor(yellow) canvas.fill_rect((0, 0, 400, 100)) canvas.set_forecolor(black) font = Font("Times", 48, []) canvas.set_font(font) canvas.show_text(0, 0, "Times Italic 48") windll.user32.EndPaint(hwnd, byref(ps)) def window_proc(hwnd, msg, lparam, wparam): try: print "window_proc:", hwnd, msg, lparam, wparam ### if msg == WM_CLOSE: os._exit(0) elif msg == WM_PAINT: test.OnPaint() return 1 return windll.user32.DefWindowProcA(hwnd, msg, lparam, wparam) except: traceback.print_exc() os._exit(1) test = Test() msg = MSG() while 1: windll.user32.GetMessageA(byref(msg), 0, 0, 0) windll.user32.TranslateMessage(byref(msg)) windll.user32.DispatchMessageA(byref(msg))
_______________________________________________ python-win32 mailing list python-win32@python.org http://mail.python.org/mailman/listinfo/python-win32