2
:mod:`fontconfig` -- Pythonic interface to fontconfig
3
=====================================================
7
:synopsis: Pythonic interface to the fontconfig library
9
.. moduleauthor:: Kovid Goyal <kovid@kovidgoyal.net> Copyright 2009
13
#define PY_SSIZE_T_CLEAN
17
#include <fontconfig.h>
20
fontconfig_initialize(PyObject *self, PyObject *args) {
26
if (!PyArg_ParseTuple(args, "z", &path))
29
_save = PyEval_SaveThread();
31
PyEval_RestoreThread(_save);
33
config = FcConfigCreate();
34
if (config == NULL) return PyErr_NoMemory();
35
_save = PyEval_SaveThread();
36
ok = FcConfigParseAndLoad(config, path, FcTrue);
37
if (ok) ok = FcConfigBuildFonts(config);
38
if (ok) ok = FcConfigSetCurrent(config);
39
PyEval_RestoreThread(_save);
40
if (!ok) return PyErr_NoMemory();
43
if (ok) Py_RETURN_TRUE;
48
fontconfig_cleanup_find(FcPattern *p, FcObjectSet *oset, FcFontSet *fs) {
49
if (p != NULL) FcPatternDestroy(p);
50
if (oset != NULL) FcObjectSetDestroy(oset);
51
if (fs != NULL) FcFontSetDestroy(fs);
56
fontconfig_find_font_families(PyObject *self, PyObject *args) {
60
Py_ssize_t l, j, extlen;
62
FcPattern *pat, *temp;
66
PyObject *ans, *exts, *t;
69
fs = NULL; oset = NULL; pat = NULL;
71
if (ans == NULL) return PyErr_NoMemory();
73
if (!PyArg_ParseTuple(args, "O", &exts))
76
if (!PySequence_Check(exts)) {
77
PyErr_SetString(PyExc_ValueError, "Must pass sequence of extensions");
80
l = PySequence_Size(exts);
83
pat = FcPatternCreate();
84
if (pat == NULL) { fontconfig_cleanup_find(pat, oset, fs); return PyErr_NoMemory(); }
86
oset = FcObjectSetCreate();
87
if (oset == NULL) { fontconfig_cleanup_find(pat, oset, fs); return PyErr_NoMemory(); }
88
if (!FcObjectSetAdd(oset, FC_FILE)) { fontconfig_cleanup_find(pat, oset, fs); return PyErr_NoMemory(); }
89
if (!FcObjectSetAdd(oset, FC_FAMILY)) { fontconfig_cleanup_find(pat, oset, fs); return PyErr_NoMemory(); }
91
fs = FcFontList(FcConfigGetCurrent(), pat, oset);
92
if (fs == NULL) { fontconfig_cleanup_find(pat, oset, fs); return PyErr_NoMemory(); }
94
for (i = 0; i < fs->nfont; i++) {
97
if (temp == NULL) continue;
98
if (FcPatternGet(temp, FC_FILE, 0, &v) != FcResultMatch) continue;
100
if (v.type == FcTypeString) {
101
flen = strlen((char *)v.u.s);
103
if (l == 0) ok = FcTrue;
104
for ( j = 0; j < l && !ok; j++) {
105
ext = PyBytes_AS_STRING(PySequence_ITEM(exts, j));
106
extlen = PyBytes_GET_SIZE(PySequence_ITEM(exts, j));
107
ok = flen > extlen && extlen > 0 &&
108
PyOS_strnicmp(ext, v.u.s + (flen - extlen), extlen) == 0;
112
if (FcPatternGet(temp, FC_FAMILY, 0, &w) != FcResultMatch) continue;
113
if (w.type != FcTypeString) continue;
114
t = PyString_FromString(w.u.s);
115
if (t == NULL) { fontconfig_cleanup_find(pat, oset, fs); return PyErr_NoMemory(); }
116
if (PyList_Append(ans, t) != 0)
117
{ fontconfig_cleanup_find(pat, oset, fs); return PyErr_NoMemory(); }
122
fontconfig_cleanup_find(pat, oset, fs);
128
fontconfig_files_for_family(PyObject *self, PyObject *args) {
133
FcValue file, weight, fullname, style, slant, family2;
134
PyObject *ans, *temp, *t;
136
if (!PyArg_ParseTuple(args, "s", &family))
140
if (ans == NULL) return PyErr_NoMemory();
142
fs = NULL; oset = NULL; pat = NULL;
144
pat = FcPatternBuild(0, FC_FAMILY, FcTypeString, family, (char *) 0);
145
if (pat == NULL) { fontconfig_cleanup_find(pat, oset, fs); return PyErr_NoMemory(); }
147
oset = FcObjectSetCreate();
148
if (oset == NULL) { fontconfig_cleanup_find(pat, oset, fs); return PyErr_NoMemory(); }
149
if (!FcObjectSetAdd(oset, FC_FILE)) { fontconfig_cleanup_find(pat, oset, fs); return PyErr_NoMemory(); }
150
if (!FcObjectSetAdd(oset, FC_STYLE)) { fontconfig_cleanup_find(pat, oset, fs); return PyErr_NoMemory(); }
151
if (!FcObjectSetAdd(oset, FC_SLANT)) { fontconfig_cleanup_find(pat, oset, fs); return PyErr_NoMemory(); }
152
if (!FcObjectSetAdd(oset, FC_WEIGHT)) { fontconfig_cleanup_find(pat, oset, fs); return PyErr_NoMemory(); }
153
if (!FcObjectSetAdd(oset, FC_FAMILY)) { fontconfig_cleanup_find(pat, oset, fs); return PyErr_NoMemory(); }
154
if (!FcObjectSetAdd(oset, "fullname")) { fontconfig_cleanup_find(pat, oset, fs); return PyErr_NoMemory(); }
156
fs = FcFontList(FcConfigGetCurrent(), pat, oset);
157
if (fs == NULL) { fontconfig_cleanup_find(pat, oset, fs); return PyErr_NoMemory(); }
159
for (i = 0; i < fs->nfont; i++) {
162
if (tp == NULL) continue;
163
if (FcPatternGet(tp, FC_FILE, 0, &file) != FcResultMatch) continue;
164
if (FcPatternGet(tp, FC_STYLE, 0, &style) != FcResultMatch) continue;
165
if (FcPatternGet(tp, FC_WEIGHT, 0, &weight) != FcResultMatch) continue;
166
if (FcPatternGet(tp, FC_SLANT, 0, &slant) != FcResultMatch) continue;
167
if (FcPatternGet(tp, FC_FAMILY, 0, &family2) != FcResultMatch) continue;
168
if (FcPatternGet(tp, "fullname", 0, &fullname) != FcResultMatch) continue;
170
temp = PyTuple_New(6);
171
if(temp == NULL) { fontconfig_cleanup_find(pat, oset, fs); return PyErr_NoMemory(); }
172
t = PyBytes_FromString(fullname.u.s);
173
if(t == NULL) { fontconfig_cleanup_find(pat, oset, fs); return PyErr_NoMemory(); }
174
PyTuple_SET_ITEM(temp, 0, t);
175
t = PyBytes_FromString(file.u.s);
176
if(t == NULL) { fontconfig_cleanup_find(pat, oset, fs); return PyErr_NoMemory(); }
177
PyTuple_SET_ITEM(temp, 1, t);
178
t = PyBytes_FromString(style.u.s);
179
if(t == NULL) { fontconfig_cleanup_find(pat, oset, fs); return PyErr_NoMemory(); }
180
PyTuple_SET_ITEM(temp, 2, t);
181
t = PyBytes_FromString(family2.u.s);
182
if(t == NULL) { fontconfig_cleanup_find(pat, oset, fs); return PyErr_NoMemory(); }
183
PyTuple_SET_ITEM(temp, 3, t);
184
t = PyInt_FromLong((long)weight.u.i);
185
if(t == NULL) { fontconfig_cleanup_find(pat, oset, fs); return PyErr_NoMemory(); }
186
PyTuple_SET_ITEM(temp, 4, t);
187
t = PyInt_FromLong((long)slant.u.i);
188
if(t == NULL) { fontconfig_cleanup_find(pat, oset, fs); return PyErr_NoMemory(); }
189
PyTuple_SET_ITEM(temp, 5, t);
190
if (PyList_Append(ans, temp) != 0)
191
{ fontconfig_cleanup_find(pat, oset, fs); return PyErr_NoMemory(); }
193
fontconfig_cleanup_find(pat, oset, fs);
199
fontconfig_match(PyObject *self, PyObject *args) {
200
char *namespec; int i;
204
FcValue file, weight, fullname, style, slant, family;
206
PyObject *ans, *temp, *t, *all, *verbose;
208
if (!PyArg_ParseTuple(args, "sOO", &namespec, &all, &verbose))
212
if (ans == NULL) return PyErr_NoMemory();
214
fs = NULL; oset = NULL; pat = NULL; fs2 = NULL;
216
pat = FcNameParse(namespec);
217
if (pat == NULL) { fontconfig_cleanup_find(pat, oset, fs); return PyErr_NoMemory(); }
218
if (PyObject_IsTrue(verbose)) FcPatternPrint(pat);
220
if (!FcConfigSubstitute(FcConfigGetCurrent(), pat, FcMatchPattern))
221
{ fontconfig_cleanup_find(pat, oset, fs); return PyErr_NoMemory(); }
222
FcDefaultSubstitute(pat);
224
fs = FcFontSetCreate();
225
if (fs == NULL) { fontconfig_cleanup_find(pat, oset, fs); return PyErr_NoMemory(); }
226
if (PyObject_IsTrue(all)) {
227
fs2 = FcFontSort(FcConfigGetCurrent(), pat, FcTrue, NULL, &res);
228
if (fs2 == NULL) { fontconfig_cleanup_find(pat, oset, fs); return PyErr_NoMemory(); }
230
for (i = 0; i < fs2->nfont; i++) {
232
if (tp == NULL) continue;
233
tp = FcFontRenderPrepare(FcConfigGetCurrent(), pat, tp);
234
if (tp == NULL) { fontconfig_cleanup_find(pat, oset, fs); return PyErr_NoMemory(); }
235
if (!FcFontSetAdd(fs, tp))
236
{ fontconfig_cleanup_find(pat, oset, fs); return PyErr_NoMemory(); }
238
if (fs2 != NULL) FcFontSetDestroy(fs2);
240
tp = FcFontMatch(FcConfigGetCurrent(), pat, &res);
241
if (tp == NULL) { fontconfig_cleanup_find(pat, oset, fs); return PyErr_NoMemory(); }
242
if (!FcFontSetAdd(fs, tp))
243
{ fontconfig_cleanup_find(pat, oset, fs); return PyErr_NoMemory(); }
246
for (i = 0; i < fs->nfont; i++) {
248
if (tp == NULL) continue;
249
if (FcPatternGet(tp, FC_FILE, 0, &file) != FcResultMatch) continue;
250
if (FcPatternGet(tp, FC_STYLE, 0, &style) != FcResultMatch) continue;
251
if (FcPatternGet(tp, FC_WEIGHT, 0, &weight) != FcResultMatch) continue;
252
if (FcPatternGet(tp, FC_SLANT, 0, &slant) != FcResultMatch) continue;
253
if (FcPatternGet(tp, FC_FAMILY, 0, &family) != FcResultMatch) continue;
254
if (FcPatternGet(tp, "fullname", 0, &fullname) != FcResultMatch) continue;
256
temp = PyTuple_New(6);
257
if(temp == NULL) { fontconfig_cleanup_find(pat, oset, fs); return PyErr_NoMemory(); }
258
t = PyBytes_FromString(fullname.u.s);
259
if(t == NULL) { fontconfig_cleanup_find(pat, oset, fs); return PyErr_NoMemory(); }
260
PyTuple_SET_ITEM(temp, 0, t);
261
t = PyBytes_FromString(file.u.s);
262
if(t == NULL) { fontconfig_cleanup_find(pat, oset, fs); return PyErr_NoMemory(); }
263
PyTuple_SET_ITEM(temp, 1, t);
264
t = PyBytes_FromString(style.u.s);
265
if(t == NULL) { fontconfig_cleanup_find(pat, oset, fs); return PyErr_NoMemory(); }
266
PyTuple_SET_ITEM(temp, 2, t);
267
t = PyBytes_FromString(family.u.s);
268
if(t == NULL) { fontconfig_cleanup_find(pat, oset, fs); return PyErr_NoMemory(); }
269
PyTuple_SET_ITEM(temp, 3, t);
270
t = PyInt_FromLong((long)weight.u.i);
271
if(t == NULL) { fontconfig_cleanup_find(pat, oset, fs); return PyErr_NoMemory(); }
272
PyTuple_SET_ITEM(temp, 4, t);
273
t = PyInt_FromLong((long)slant.u.i);
274
if(t == NULL) { fontconfig_cleanup_find(pat, oset, fs); return PyErr_NoMemory(); }
275
PyTuple_SET_ITEM(temp, 5, t);
276
if (PyList_Append(ans, temp) != 0)
277
{ fontconfig_cleanup_find(pat, oset, fs); return PyErr_NoMemory(); }
280
fontconfig_cleanup_find(pat, oset, fs);
288
PyMethodDef fontconfig_methods[] = {
289
{"initialize", fontconfig_initialize, METH_VARARGS,
290
"initialize(path_to_config_file)\n\n"
291
"Initialize the library. If path to config file is specified it is used instead of the "
292
"default configuration. Returns True iff the initialization succeeded."
295
{"find_font_families", fontconfig_find_font_families, METH_VARARGS,
296
"find_font_families(allowed_extensions)\n\n"
297
"Find all font families on the system for fonts of the specified types. If no "
298
"types are specified all font families are returned."
301
{"files_for_family", fontconfig_files_for_family, METH_VARARGS,
302
"files_for_family(family, normalize)\n\n"
303
"Find all the variants in the font family `family`. "
304
"Returns a list of tuples. Each tuple is of the form "
305
"(fullname, path, style, family, weight, slant). "
308
{"match", fontconfig_match, METH_VARARGS,
309
"match(namespec,all,verbose)\n\n"
310
"Find all system fonts that match namespec, in decreasing order "
312
"Returns a list of tuples. Each tuple is of the form "
313
"(fullname, path, style, family, weight, slant). "
317
{NULL, NULL, 0, NULL}
323
initfontconfig(void) {
326
"fontconfig", fontconfig_methods,
329
if (m == NULL) return;