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