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
[email protected]
http://mail.python.org/mailman/listinfo/python-win32