Skip to content

Instantly share code, notes, and snippets.

@jasonbot
Created January 31, 2012 21:50
Show Gist options
  • Star 3 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save jasonbot/1713202 to your computer and use it in GitHub Desktop.
Save jasonbot/1713202 to your computer and use it in GitHub Desktop.
Get the width and height (in inches) of a string using the Win32 CTypes APIs.
import ctypes
import ctypes.wintypes
class Constants(object):
"Container for constants found in win32 headers"
WS_OVERLAPPED = 0x00000000L
WS_POPUP = 0x80000000L
WS_CHILD = 0x40000000L
WS_MINIMIZE = 0x20000000L
WS_VISIBLE = 0x10000000L
WS_DISABLED = 0x08000000L
WS_CLIPSIBLINGS = 0x04000000L
WS_CLIPCHILDREN = 0x02000000L
WS_MAXIMIZE = 0x01000000L
WS_CAPTION = 0x00C00000L
WS_BORDER = 0x00800000L
WS_DLGFRAME = 0x00400000L
WS_VSCROLL = 0x00200000L
WS_HSCROLL = 0x00100000L
WS_SYSMENU = 0x00080000L
WS_THICKFRAME = 0x00040000L
WS_GROUP = 0x00020000L
WS_TABSTOP = 0x00010000L
WS_MINIMIZEBOX = 0x00020000L
WS_MAXIMIZEBOX = 0x00010000L
WS_OVERLAPPEDWINDOW = (WS_OVERLAPPED |
WS_CAPTION |
WS_SYSMENU |
WS_THICKFRAME |
WS_MINIMIZEBOX |
WS_MAXIMIZEBOX)
SM_XVIRTUALSCREEN = 76
SM_YVIRTUALSCREEN = 77
SM_CXVIRTUALSCREEN = 78
SM_CYVIRTUALSCREEN = 79
SM_CMONITORS = 80
SM_SAMEDISPLAYFORMAT = 81
ANSI_CHARSET = 0
DEFAULT_CHARSET = 1
OUT_DEFAULT_PRECIS = 0x00000000
OUT_STRING_PRECIS = 0x00000001
OUT_STROKE_PRECIS = 0x00000003
OUT_TT_PRECIS = 0x00000004
OUT_DEVICE_PRECIS = 0x00000005
OUT_RASTER_PRECIS = 0x00000006
OUT_TT_ONLY_PRECIS = 0x00000007
OUT_OUTLINE_PRECIS = 0x00000008
OUT_SCREEN_OUTLINE_PRECIS = 0x00000009
OUT_PS_ONLY_PRECIS = 0x0000000A
LOGPIXELSX = 88
LOGPIXELSY = 90
class SIZE(ctypes.Structure):
_fields_ = [("cx", ctypes.c_long),
("cy", ctypes.c_long)]
ctypes.windll.user32.CreateWindowExA.restype = ctypes.wintypes.HWND
ctypes.windll.user32.GetDC.restype = ctypes.wintypes.HDC
ctypes.windll.gdi32.CreateFontA.argtypes = [ctypes.c_int,
ctypes.c_int,
ctypes.c_int,
ctypes.c_int,
ctypes.c_int,
ctypes.wintypes.DWORD,
ctypes.wintypes.DWORD,
ctypes.wintypes.DWORD,
ctypes.wintypes.DWORD,
ctypes.wintypes.DWORD,
ctypes.wintypes.DWORD,
ctypes.wintypes.DWORD,
ctypes.wintypes.DWORD,
ctypes.wintypes.LPCSTR]
ctypes.windll.gdi32.CreateFontA.restype = ctypes.wintypes.HFONT
ctypes.windll.gdi32.SelectObject.argtypes = [ctypes.wintypes.HDC, ctypes.wintypes.HANDLE]
class FontMetrics(object):
def __init__(self):
self.hwnd = ctypes.windll.user32.CreateWindowExA(0,
"STATIC",
"",
Constants.WS_OVERLAPPEDWINDOW,
ctypes.windll.user32.GetSystemMetrics(Constants.SM_CXVIRTUALSCREEN),
ctypes.windll.user32.GetSystemMetrics(Constants.SM_CYVIRTUALSCREEN),
640, 480, 0, 0, 0, 0)
def __del__(self):
if ctypes:
ctypes.windll.user32.DestroyWindow(self.hwnd)
def get_dimensions(self, text, fontname, fontsize):
hdc = ctypes.windll.user32.GetDC(self.hwnd)
#print "HDC:", hdc
fontheight = -ctypes.windll.kernel32.MulDiv(fontsize,
ctypes.windll.gdi32.GetDeviceCaps(hdc,
Constants.LOGPIXELSY),
72)
#print "Size:", fontsize, "Height:", fontheight
fontheight = fontsize
hfont = ctypes.windll.gdi32.CreateFontA(fontheight,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
fontname)
#print "FONT", hfont
ctypes.windll.gdi32.SelectObject(hdc, hfont)
size = Constants.SIZE(0, 0)
ctypes.windll.gdi32.GetTextExtentPoint32A(hdc, text, len(text), ctypes.byref(size))
dpix = ctypes.windll.gdi32.GetDeviceCaps(hdc, Constants.LOGPIXELSX)
dpiy = ctypes.windll.gdi32.GetDeviceCaps(hdc, Constants.LOGPIXELSY)
ctypes.windll.gdi32.DeleteObject(hfont)
ctypes.windll.user32.ReleaseDC(self.hwnd, hdc)
return (float(size.cx) / dpix, float(size.cy) / dpiy)
if __name__ == "__main__":
fm = FontMetrics()
for size in range(10, 40):
for text in ("Helol", "wghsg", "245 245245245 245 245 245"):
print "String", repr(text), "at", size, "pt"
for font in ("Arial", "Consolas", "Calibri", "Fixedsys"):
print "In", font, "dimensions are", fm.get_dimensions(text, font, size)
print '--'
del fm
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment