Skip to content

Instantly share code, notes, and snippets.

@mRB0
Created June 2, 2015 17:35
Show Gist options
  • Star 4 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save mRB0/740c25fdae3dc0b0ee7a to your computer and use it in GitHub Desktop.
Save mRB0/740c25fdae3dc0b0ee7a to your computer and use it in GitHub Desktop.
why aren't all objective-C programs written in python?
#!/usr/bin/env python
# -*- coding: utf-8 -*-
from contextlib import contextmanager
import ctypes
import ctypes.util
from ctypes import CFUNCTYPE
objc = ctypes.cdll.LoadLibrary(ctypes.util.find_library('objc'))
Foundation = ctypes.CDLL(ctypes.util.find_library('Foundation'))
CoreText = ctypes.CDLL(ctypes.util.find_library('CoreText'))
CFTypeRef = ctypes.c_void_p
CFIndex = ctypes.c_long
CFStringEncoding = ctypes.c_uint32
Boolean = ctypes.c_uint8
kCFStringEncodingUTF8 = 0x08000100
CGFontRef = CFTypeRef
CFStringRef = CFTypeRef
class CFRange(ctypes.Structure):
_fields_ = [('location', CFIndex),
('length', CFIndex)]
CFStringGetBytes = CFUNCTYPE(CFIndex, CFStringRef, CFRange, CFStringEncoding, ctypes.c_char, ctypes.c_uint8, ctypes.POINTER(ctypes.c_char), CFIndex, ctypes.POINTER(CFIndex))(('CFStringGetBytes', Foundation))
CFStringGetLength = CFUNCTYPE(CFIndex, CFStringRef)(('CFStringGetLength', Foundation))
CFStringCreateWithBytes = CFUNCTYPE(CFStringRef, ctypes.c_void_p, ctypes.POINTER(ctypes.c_char), CFIndex, CFStringEncoding, Boolean)(('CFStringCreateWithBytes', Foundation))
CFRelease = CFUNCTYPE(None, CFTypeRef)(('CFRelease', Foundation))
CGFontCreateWithFontName = CFUNCTYPE(CGFontRef, CFStringRef)(('CGFontCreateWithFontName', CoreText))
CGFontGetXHeight = CFUNCTYPE(ctypes.c_int32, CGFontRef)(('CGFontGetXHeight', CoreText))
CGFontGetUnitsPerEm = CFUNCTYPE(ctypes.c_int32, CGFontRef)(('CGFontGetUnitsPerEm', CoreText))
CGFontGetNumberOfGlyphs = CFUNCTYPE(ctypes.c_int32, CGFontRef)(('CGFontGetNumberOfGlyphs', CoreText))
CGFontCopyFullName = CFUNCTYPE(CFStringRef, CGFontRef)(('CGFontCopyFullName', CoreText))
def decodeCFString(stringRef):
length = CFStringGetBytes(stringRef,
CFRange(0, CFStringGetLength(stringRef)),
kCFStringEncodingUTF8,
'?',
0,
None,
0,
None)
stringBuf = (ctypes.c_char * length)()
CFStringGetBytes(stringRef,
CFRange(0, CFStringGetLength(stringRef)),
kCFStringEncodingUTF8,
'?',
0,
stringBuf,
length,
None)
return ''.join(stringBuf).decode('utf-8')
def createCFString(unistring):
s = unistring.encode('utf-8') if isinstance(unistring, unicode) else unistring
length = len(s)
bytesArray = (ctypes.c_char * length)(*list(s))
return CFStringCreateWithBytes(None, bytesArray, length, kCFStringEncodingUTF8, False)
@contextmanager
def autoreleasepool():
objc.objc_getClass.restype = ctypes.c_void_p
objc.sel_registerName.restype = ctypes.c_void_p
objc.objc_msgSend.restype = ctypes.c_void_p
objc.objc_msgSend.argtypes = [ctypes.c_void_p, ctypes.c_void_p]
NSAutoreleasePool = objc.objc_getClass('NSAutoreleasePool')
pool = objc.objc_msgSend(NSAutoreleasePool, objc.sel_registerName('alloc'))
pool = objc.objc_msgSend(pool, objc.sel_registerName('init'))
yield
objc.objc_msgSend(pool, objc.sel_registerName('drain'))
def main():
with autoreleasepool():
import sys
font_name = sys.argv[1]
cf_font_name = createCFString(font_name)
font_ref = CGFontCreateWithFontName(cf_font_name)
CFRelease(cf_font_name)
if not font_ref:
print "Font named {!r} not found".format(font_name)
return
cf_font_name = CGFontCopyFullName(font_ref)
print decodeCFString(cf_font_name)
CFRelease(cf_font_name)
print "Glyphs: {}".format(CGFontGetNumberOfGlyphs(font_ref))
CFRelease(font_ref)
if __name__ == '__main__':
main()
@mRB0
Copy link
Author

mRB0 commented Jun 2, 2015

$ ./fonts.py Times
Times Roman
Glyphs: 1443

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment