Created
June 2, 2015 17:35
-
-
Save mRB0/740c25fdae3dc0b0ee7a to your computer and use it in GitHub Desktop.
why aren't all objective-C programs written in python?
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/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() | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
$ ./fonts.py Times
Times Roman
Glyphs: 1443