1# from: http://cairographics.org/freetypepython/ 2 3import ctypes as ct 4import cairo 5 6 7class PycairoContext(ct.Structure): 8 _fields_ = \ 9 [ 10 ("PyObject_HEAD", ct.c_byte * object.__basicsize__), 11 ("ctx", ct.c_void_p), 12 ("base", ct.c_void_p), 13 ] 14 15 16_initialized = False 17 18 19def create_cairo_font_face_for_file(filename, faceindex=0, loadoptions=0): 20 """ Given the name of a font file, and optional faceindex to pass to FT_New_Face 21 and loadoptions to pass to cairo_ft_font_face_create_for_ft_face, creates 22 a cairo.FontFace object that may be used to render text with that font. """ 23 global _initialized 24 global _freetype_so 25 global _cairo_so 26 global _ft_lib 27 global _ft_destroy_key 28 global _surface 29 30 CAIRO_STATUS_SUCCESS = 0 31 FT_Err_Ok = 0 32 33 if not _initialized: 34 # find shared objects 35 _freetype_so = ct.CDLL("libfreetype.so.6") 36 _cairo_so = ct.CDLL("libcairo.so.2") 37 _cairo_so.cairo_ft_font_face_create_for_ft_face.restype = ct.c_void_p 38 _cairo_so.cairo_ft_font_face_create_for_ft_face.argtypes = [ct.c_void_p, ct.c_int] 39 _cairo_so.cairo_font_face_get_user_data.restype = ct.c_void_p 40 _cairo_so.cairo_font_face_get_user_data.argtypes = (ct.c_void_p, ct.c_void_p) 41 _cairo_so.cairo_font_face_set_user_data.argtypes = (ct.c_void_p, ct.c_void_p, ct.c_void_p, ct.c_void_p) 42 _cairo_so.cairo_set_font_face.argtypes = [ct.c_void_p, ct.c_void_p] 43 _cairo_so.cairo_font_face_status.argtypes = [ct.c_void_p] 44 _cairo_so.cairo_font_face_destroy.argtypes = (ct.c_void_p,) 45 _cairo_so.cairo_status.argtypes = [ct.c_void_p] 46 # initialize freetype 47 _ft_lib = ct.c_void_p() 48 status = _freetype_so.FT_Init_FreeType(ct.byref(_ft_lib)) 49 if status != FT_Err_Ok: 50 raise RuntimeError("Error %d initializing FreeType library." % status) 51 52 _surface = cairo.ImageSurface(cairo.FORMAT_A8, 0, 0) 53 _ft_destroy_key = ct.c_int() # dummy address 54 _initialized = True 55 56 ft_face = ct.c_void_p() 57 cr_face = None 58 try: 59 # load FreeType face 60 status = _freetype_so.FT_New_Face(_ft_lib, filename.encode("utf-8"), faceindex, ct.byref(ft_face)) 61 if status != FT_Err_Ok: 62 raise RuntimeError("Error %d creating FreeType font face for %s" % (status, filename)) 63 64 # create Cairo font face for freetype face 65 cr_face = _cairo_so.cairo_ft_font_face_create_for_ft_face(ft_face, loadoptions) 66 status = _cairo_so.cairo_font_face_status(cr_face) 67 if status != CAIRO_STATUS_SUCCESS: 68 raise RuntimeError("Error %d creating cairo font face for %s" % (status, filename)) 69 70 # Problem: Cairo doesn't know to call FT_Done_Face when its font_face object is 71 # destroyed, so we have to do that for it, by attaching a cleanup callback to 72 # the font_face. This only needs to be done once for each font face, while 73 # cairo_ft_font_face_create_for_ft_face will return the same font_face if called 74 # twice with the same FT Face. 75 # The following check for whether the cleanup has been attached or not is 76 # actually unnecessary in our situation, because each call to FT_New_Face 77 # will return a new FT Face, but we include it here to show how to handle the 78 # general case. 79 if _cairo_so.cairo_font_face_get_user_data(cr_face, ct.byref(_ft_destroy_key)) is None: 80 status = _cairo_so.cairo_font_face_set_user_data( 81 cr_face, 82 ct.byref(_ft_destroy_key), 83 ft_face, 84 _freetype_so.FT_Done_Face) 85 if status != CAIRO_STATUS_SUCCESS: 86 raise RuntimeError("Error %d doing user_data dance for %s" % (status, filename)) 87 ft_face = None # Cairo has stolen my reference 88 89 # set Cairo font face into Cairo context 90 cairo_ctx = cairo.Context(_surface) 91 cairo_t = PycairoContext.from_address(id(cairo_ctx)).ctx 92 _cairo_so.cairo_set_font_face(cairo_t, cr_face) 93 status = _cairo_so.cairo_font_face_status(cairo_t) 94 if status != CAIRO_STATUS_SUCCESS: 95 raise RuntimeError("Error %d creating cairo font face for %s" % (status, filename)) 96 97 finally: 98 _cairo_so.cairo_font_face_destroy(cr_face) 99 _freetype_so.FT_Done_Face(ft_face) 100 101 # get back Cairo font face as a Python object 102 face = cairo_ctx.get_font_face() 103 return face 104 105 106if __name__ == '__main__': 107 face = create_cairo_font_face_for_file("../../../pieces/ttf/harlequin.ttf", 108 0) 109 110 surface = cairo.ImageSurface(cairo.FORMAT_ARGB32, 200, 128) 111 112 ctx = cairo.Context(surface) 113 114 ctx.set_font_face(face) 115 ctx.set_font_size(30) 116 ctx.move_to(0, 44) 117 ctx.show_text("pnbrqk") 118 119 ctx.move_to(0, 74) 120 ctx.show_text("omvtwl") 121 122 del ctx 123 124 surface.write_to_png("0pieces.png") 125