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

Reply via email to