-
Notifications
You must be signed in to change notification settings - Fork 4
/
cairoft.py
154 lines (132 loc) · 5.42 KB
/
cairoft.py
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
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
#!/usr/bin/python3
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
import platform
if platform.system() == "Darwin":
_freetype_so = ct.CDLL("libfreetype.dylib")
_cairo_so = ct.CDLL("libcairo.dylib")
else:
_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
if __name__ == "__main__":
import sys
face = create_cairo_font_face_for_file(sys.argv[1], 0)
surface = cairo.ImageSurface(cairo.FORMAT_ARGB32, 128, 128)
ctx = cairo.Context(surface)
ctx.set_font_face(face)
ctx.set_font_size(30)
ctx.move_to(0, 44)
ctx.show_text("Hello,")
ctx.move_to(30, 74)
ctx.show_text("world!")
del ctx
surface.write_to_png("hello.png")
# end if