#-------------------------------------------------------------------- # # PyGUI - Win32 - GDI Plus # #-------------------------------------------------------------------- from ctypes import * from ctypes.wintypes import BOOL try: from numpy import ndarray, float32 except ImportError: class ndarray(object): pass #wg = windll.gdiplus wg = oledll.gdiplus #-------------------------------------------------------------------- # enum Unit UnitWorld = 0 UnitDisplay = 1 UnitPixel = 2 UnitPoint = 3 # enum FillMode FillModeAlternate = 0 # enum CombineMode CombineModeIntersect = 1 # enum MatrixOrder MatrixOrderPrepend = 0 MatrixOrderAppend = 1 # Pixel Formats # In-memory pixel data formats: # bits 0-7 = format index # bits 8-15 = pixel size (in bits) # bits 16-23 = flags # bits 24-31 = reserved PixelFormatIndexed = 0x00010000 # Indexes into a palette PixelFormatGDI = 0x00020000 # Is a GDI-supported format PixelFormatAlpha = 0x00040000 # Has an alpha component PixelFormatPAlpha = 0x00080000 # Pre-multiplied alpha PixelFormatExtended = 0x00100000 # Extended color 16 bits/channel PixelFormatCanonical = 0x00200000 PixelFormat1bppIndexed = (1 | ( 1 << 8) | PixelFormatIndexed | PixelFormatGDI) PixelFormat4bppIndexed = (2 | ( 4 << 8) | PixelFormatIndexed | PixelFormatGDI) PixelFormat8bppIndexed = (3 | ( 8 << 8) | PixelFormatIndexed | PixelFormatGDI) PixelFormat16bppGrayScale = (4 | (16 << 8) | PixelFormatExtended) PixelFormat16bppRGB555 = (5 | (16 << 8) | PixelFormatGDI) PixelFormat16bppRGB565 = (6 | (16 << 8) | PixelFormatGDI) PixelFormat16bppARGB1555 = (7 | (16 << 8) | PixelFormatAlpha | PixelFormatGDI) PixelFormat24bppRGB = (8 | (24 << 8) | PixelFormatGDI) PixelFormat32bppRGB = (9 | (32 << 8) | PixelFormatGDI) PixelFormat32bppARGB = (10 | (32 << 8) | PixelFormatAlpha | PixelFormatGDI | PixelFormatCanonical) PixelFormat32bppPARGB = (11 | (32 << 8) | PixelFormatAlpha | PixelFormatPAlpha | PixelFormatGDI) PixelFormat48bppRGB = (12 | (48 << 8) | PixelFormatExtended) PixelFormat64bppARGB = (13 | (64 << 8) | PixelFormatAlpha | PixelFormatCanonical | PixelFormatExtended) PixelFormat64bppPARGB = (14 | (64 << 8) | PixelFormatAlpha | PixelFormatPAlpha | PixelFormatExtended) # enum FontStyle FontStyleBold = 1 FontStyleItalic = 2 FontStyleUnderline = 4 FontStyleStrikeout = 8 class PointF(Structure): _fields_ = [("x", c_float), ("y", c_float)] class RectF(Structure): _fields_ = [ ("x", c_float), ("y", c_float), ("width", c_float), ("height", c_float)] #-------------------------------------------------------------------- def rect_args(rect): l, t, r, b = rect return c_float(l), c_float(t), c_float(r - l), c_float(b - t) def points_args(points): if isinstance(points, ndarray) and points.flags['C_CONTIGUOUS'] and points.dtype == float32: #print "GDIPlus.points_args: using ndarray" ### n = points.size // 2 buf = points.ctypes.data else: n = len(points) buf = (PointF * n)() for i, p in enumerate(points): buf[i].x, buf[i].y = p return buf, n def arc_args(c, r, a0, a1): x, y = c d = c_float(2 * r) return c_float(x - r), c_float(y - r), d, d, \ c_float(a0), c_float((a1 - a0) % 360.0) #-------------------------------------------------------------------- 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() wg.GdiplusStartup(pointer(token), pointer(StartupInput), None) #-------------------------------------------------------------------- class Pen(object): def __init__(self, argb, size): ptr = c_void_p() wg.GdipCreatePen1(argb, c_float(size), UnitWorld, byref(ptr)) self.ptr = ptr def __del__(self, wg = wg): wg.GdipDeletePen(self.ptr) #-------------------------------------------------------------------- class SolidBrush(object): def __init__(self, argb): ptr = c_void_p() wg.GdipCreateSolidFill(argb, byref(ptr)) self.ptr = ptr def __del__(self, wg = wg): wg.GdipDeleteBrush(self.ptr) def __str__(self): argb = c_ulong() wg.GdipGetSolidFillColor(self.ptr, byref(argb)) return "" % argb.value #-------------------------------------------------------------------- class TextureBrush(object): def __init__(self, image): ptr = c_void_p() wg.GdipCreateTexture(image.ptr, 4, byref(ptr)) self.ptr = ptr def __del__(self, wg = wg): wg.GdipDeleteBrush(self.ptr) def __str__(self): return "" #-------------------------------------------------------------------- class Font(object): def __init__(self, family, size, style): uname = create_unicode_buffer(family) fam = c_void_p() wg.GdipCreateFontFamilyFromName(uname, None, byref(fam)) flags = 0 if 'bold' in style: flags |= FontStyleBold if 'italic' in style: flags |= FontStyleItalic ptr = c_void_p() wg.GdipCreateFont(fam, c_float(size), flags, UnitWorld, byref(ptr)) self.ptr = ptr wg.GdipDeleteFontFamily(fam) def from_hdc(cls, hdc): self = cls.__new__(cls) ptr = c_void_p() wg.GdipCreateFontFromDC(hdc, byref(ptr)) self.ptr = ptr return self from_hdc = classmethod(from_hdc) def __del__(self, wg = wg): wg.GdipDeleteFont(self.ptr) #-------------------------------------------------------------------- class Image(object): def __str__(self): return "" % self.ptr.value def from_file(cls, path): self = cls.__new__(cls) ptr = c_void_p() upath = create_unicode_buffer(path) self._create_from_file(upath, ptr) self.ptr = ptr return self from_file = classmethod(from_file) def _create_from_file(self, upath, ptr): wg.GdipLoadImageFromFile(upath, byref(ptr)) def __del__(self, wg = wg): wg.GdipDisposeImage(self.ptr) def GetWidth(self): uint = c_uint() wg.GdipGetImageWidth(self.ptr, byref(uint)) return uint.value def GetHeight(self): uint = c_uint() wg.GdipGetImageHeight(self.ptr, byref(uint)) return uint.value #-------------------------------------------------------------------- class Bitmap(Image): def __init__(self, width, height): ptr = c_void_p() format = PixelFormat32bppARGB wg.GdipCreateBitmapFromScan0(width, height, 0, format, None, byref(ptr)) self.ptr = ptr #print "GDIPlus.Bitmap:", (width, height), repr(self), "ptr =", self.ptr ### def _create_from_file(self, upath, ptr): wg.GdipCreateBitmapFromFile(upath, byref(ptr)) def from_data(cls, width, height, format, data): self = cls.__new__(cls) ptr = c_void_p() bits_per_pixel = (format >> 8) & 0xff row_stride = (width * bits_per_pixel) >> 3 wg.GdipCreateBitmapFromScan0(width, height, row_stride, format, data, byref(ptr)) self.ptr = ptr return self from_data = classmethod(from_data) def __str__(self): return "" % self.ptr.value def GetHICON(self): hicon = c_ulong() wg.GdipCreateHICONFromBitmap(self.ptr, byref(hicon)) return hicon.value def GetPixel(self, x, y): c = c_ulong() wg.GdipBitmapGetPixel(self.ptr, x, y, byref(c)) return c.value def SetPixel(self, x, y, c): wg.GdipBitmapSetPixel(self.ptr, x, y, c) #-------------------------------------------------------------------- class GraphicsPath(object): def __init__(self): ptr = c_void_p() wg.GdipCreatePath(FillModeAlternate, byref(ptr)) self.ptr = ptr def __del__(self, wg = wg): wg.GdipDeletePath(self.ptr) def Reset(self): wg.GdipResetPath(self.ptr) def StartFigure(self): wg.GdipStartPathFigure(self.ptr) def AddLine_4f(self, x0, y0, x1, y1): wg.GdipAddPathLine(self.ptr, c_float(x0), c_float(y0), c_float(x1), c_float(y1)) def AddBezier_4p(self, p0, p1, p2, p3): x0, y0 = p0 x1, y1 = p1 x2, y2 = p2 x3, y3 = p3 wg.GdipAddPathBezier(self.ptr, c_float(x0), c_float(y0), c_float(x1), c_float(y1), c_float(x2), c_float(y2), c_float(x3), c_float(y3)) def AddBeziers_pv(self, points): wg.GdipAddPathBeziers(self.ptr, *points_args(points)) def AddRectangle_r(self, rect): wg.GdipAddPathRectangle(self.ptr, *rect_args(rect)) def AddEllipse_r(self, rect): wg.GdipAddPathEllipse(self.ptr, *rect_args(rect)) def AddArc_p3f(self, c, r, a0, a1): wg.GdipAddPathArc(self.ptr, *arc_args(c, r, a0, a1)) def AddPie_p3f(self, c, r, a0, a1): wg.GdipAddPathPie(self.ptr, *arc_args(c, r, a0, a1)) def AddLines_pv(self, points): wg.GdipAddPathLine2(self.ptr, *points_args(points)) def AddPolygon_pv(self, points): wg.GdipAddPathPolygon(self.ptr, *points_args(points)) def CloseFigure(self): wg.GdipClosePathFigure(self.ptr) def GetLastPoint(self): p = PointF() wg.GdipGetPathLastPoint(self.ptr, byref(p)) return p.x, p.y #-------------------------------------------------------------------- class Graphics(object): def from_hdc(cls, hdc): self = cls.__new__(cls) ptr = c_void_p() wg.GdipCreateFromHDC(c_ulong(hdc), byref(ptr)) self.ptr = ptr return self from_hdc = classmethod(from_hdc) def from_dc(cls, dc): return cls.from_hdc(dc.GetSafeHdc()) from_dc = classmethod(from_dc) def from_image(cls, image): #print "Graphics.from_image:", repr(image) ### #print "...", image ### self = cls.__new__(cls) ptr = c_void_p() wg.GdipGetImageGraphicsContext(image.ptr, byref(ptr)) self.ptr = ptr return self from_image = classmethod(from_image) def __del__(self, wg = wg): wg.GdipDeleteGraphics(self.ptr) def __str__(self): return "" % self.ptr.value def GetHDC(self): hdc = c_long() wg.GdipGetDC(self.ptr, byref(hdc)) return hdc.value def ReleaseHDC(self, hdc): wg.GdipReleaseDC(self.ptr, hdc) def GetDpiX(self): result = c_float() wg.GdipGetDpiX(self.ptr, byref(result)) return result.value def GetDpiY(self): result = c_float() wg.GdipGetDpiY(self.ptr, byref(result)) return result.value def SetPageUnit(self, unit): self.unit = unit wg.GdipSetPageUnit(self.ptr, unit) def GetClipBounds(self): r = RectF() wg.GdipGetClipBounds(self.ptr, byref(r)) return (r.x, r.y, r.x + r.width, r.y + r.height) def Save(self): state = c_uint() wg.GdipSaveGraphics(self.ptr, byref(state)) return state.value def Restore(self, state): wg.GdipRestoreGraphics(self.ptr, state) def DrawImage_rr(self, image, dst_rect, src_rect): sl, st, sr, sb = src_rect dl, dt, dr, db = dst_rect wg.GdipDrawImageRectRect(self.ptr, image.ptr, c_float(dl), c_float(dt), c_float(dr - dl), c_float(db - dt), c_float(sl), c_float(st), c_float(sr - sl), c_float(sb - st), UnitPixel, None, None, None) def DrawPath(self, pen, path): wg.GdipDrawPath(self.ptr, pen.ptr, path.ptr) def FillPath(self, brush, path): wg.GdipFillPath(self.ptr, brush.ptr, path.ptr) def DrawAndMeasureStringWidth_2f(self, text, font, x, y, brush): wtext = unicode(text) n = len(text) pos = PointF(x, y) flags = 5 # DriverStringOptions CmapLookup+RealizedAdvance b = RectF() wg.GdipDrawDriverString(self.ptr, wtext, n, font.ptr, brush.ptr, byref(pos), flags, None) wg.GdipMeasureDriverString(self.ptr, wtext, n, font.ptr, byref(pos), flags, None, byref(b)) return b.width def MeasureStringWidth(self, text, font): wtext = unicode(text) n = len(text) pos = PointF(0, 0) flags = 5 # DriverStringOptions CmapLookup+RealizedAdvance b = RectF() wg.GdipMeasureDriverString(self.ptr, wtext, n, font.ptr, byref(pos), flags, None, byref(b)) return b.width def SetClip_PI(self, path): wg.GdipSetClipPath(self.ptr, path.ptr, CombineModeIntersect) def SetClip_rI(self, rect): x, y, w, h = rect_args(rect) wg.GdipSetClipRect(self.ptr, x, y, w, h, CombineModeIntersect) def DrawRectangle_r(self, pen, rect): wg.GdipDrawRectangle(self.ptr, pen.ptr, *rect_args(rect)) def FillRectangle_r(self, brush, rect): #print "Graphics.FillRectangle_r:", self, brush, rect ### #print "... clip bounds =", self.GetClipBounds() ### wg.GdipFillRectangle(self.ptr, brush.ptr, *rect_args(rect)) def DrawEllipse_r(self, pen, rect): wg.GdipDrawEllipse(self.ptr, pen.ptr, *rect_args(rect)) def FillEllipse_r(self, brush, rect): wg.GdipFillEllipse(self.ptr, brush.ptr, *rect_args(rect)) def DrawArc_3pf(self, pen, c, r, a0, a1): wg.GdipDrawArc(self.ptr, pen.ptr, *arc_args(c, r, a0, a1)) def DrawPie_p3f(self, pen, c, r, a0, a1): wg.GdipDrawPie(self.ptr, pen.ptr, *arc_args(c, r, a0, a1)) def FillPie_p3f(self, brush, c, r, a0, a1): wg.GdipFillPie(self.ptr, brush.ptr, *arc_args(c, r, a0, a1)) def DrawPolygon_pv(self, pen, points): wg.GdipDrawPolygon(self.ptr, pen.ptr, *points_args(points)) def FillPolygon_pv(self, brush, points): buf, n = points_args(points) wg.GdipFillPolygon(self.ptr, brush.ptr, buf, n, FillModeAlternate) def DrawBeziers_pv(self, pen, points): wg.GdipDrawBeziers(self.ptr, pen.ptr, *points_args(points)) def DrawLines_pv(self, pen, points): wg.GdipDrawLines(self.ptr, pen.ptr, *points_args(points)) def Translate_2f(self, dx, dy): wg.GdipTranslateWorldTransform(self.ptr, c_float(dx), c_float(dy), MatrixOrderAppend) def Scale_2f(self, sx, sy): wg.GdipScaleWorldTransform(self.ptr, c_float(sx), c_float(sy), MatrixOrderAppend) def Rotate_1f(self, r): wg.GdipRotateWorldTransform(self.ptr, c_float(r), MatrixOrderAppend) def GetTransform(self): matrix = c_void_p() elems = (c_float * 6)() wg.GdipCreateMatrix(byref(matrix)) wg.GdipGetWorldTransform(self.ptr, matrix) wg.GdipGetMatrixElements(matrix, elems) wg.GdipDeleteMatrix(matrix) return list(elems)