Remove the unused fontconfig bindings

This commit is contained in:
Kovid Goyal 2012-10-28 17:37:02 +05:30
parent 1af17f0c20
commit 9c62f0a21c
8 changed files with 5 additions and 678 deletions

View File

@ -87,8 +87,6 @@ ft_libs = []
ft_inc_dirs = [] ft_inc_dirs = []
jpg_libs = [] jpg_libs = []
jpg_lib_dirs = [] jpg_lib_dirs = []
fc_inc = '/usr/include/fontconfig'
fc_lib = '/usr/lib'
podofo_inc = '/usr/include/podofo' podofo_inc = '/usr/include/podofo'
podofo_lib = '/usr/lib' podofo_lib = '/usr/lib'
chmlib_inc_dirs = chmlib_lib_dirs = [] chmlib_inc_dirs = chmlib_lib_dirs = []
@ -107,8 +105,6 @@ if iswindows:
'source', 'i18n')] 'source', 'i18n')]
icu_lib_dirs = [os.path.join(ICU, 'source', 'lib')] icu_lib_dirs = [os.path.join(ICU, 'source', 'lib')]
sqlite_inc_dirs = [sw_inc_dir] sqlite_inc_dirs = [sw_inc_dir]
fc_inc = os.path.join(sw_inc_dir, 'fontconfig')
fc_lib = sw_lib_dir
chmlib_inc_dirs = consolidate('CHMLIB_INC_DIR', os.path.join(prefix, chmlib_inc_dirs = consolidate('CHMLIB_INC_DIR', os.path.join(prefix,
'build', 'chmlib-0.40', 'src')) 'build', 'chmlib-0.40', 'src'))
chmlib_lib_dirs = consolidate('CHMLIB_LIB_DIR', os.path.join(prefix, chmlib_lib_dirs = consolidate('CHMLIB_LIB_DIR', os.path.join(prefix,
@ -131,8 +127,6 @@ if iswindows:
podofo_inc = os.path.join(sw_inc_dir, 'podofo') podofo_inc = os.path.join(sw_inc_dir, 'podofo')
podofo_lib = sw_lib_dir podofo_lib = sw_lib_dir
elif isosx: elif isosx:
fc_inc = '/sw/include/fontconfig'
fc_lib = '/sw/lib'
podofo_inc = '/sw/podofo' podofo_inc = '/sw/podofo'
podofo_lib = '/sw/lib' podofo_lib = '/sw/lib'
magick_inc_dirs = consolidate('MAGICK_INC', magick_inc_dirs = consolidate('MAGICK_INC',
@ -166,13 +160,6 @@ else:
ft_libs = pkgconfig_libs('freetype2', '', '') ft_libs = pkgconfig_libs('freetype2', '', '')
fc_inc = os.environ.get('FC_INC_DIR', fc_inc)
fc_lib = os.environ.get('FC_LIB_DIR', fc_lib)
fc_error = None if os.path.exists(os.path.join(fc_inc, 'fontconfig.h')) else \
('fontconfig header files not found on your system. '
'Try setting the FC_INC_DIR and FC_LIB_DIR environment '
'variables.')
magick_error = None magick_error = None
if not magick_inc_dirs or not os.path.exists(os.path.join(magick_inc_dirs[0], if not magick_inc_dirs or not os.path.exists(os.path.join(magick_inc_dirs[0],
'wand')): 'wand')):

View File

@ -13,7 +13,7 @@ from multiprocessing import cpu_count
from PyQt4.pyqtconfig import QtGuiModuleMakefile from PyQt4.pyqtconfig import QtGuiModuleMakefile
from setup import Command, islinux, isbsd, isosx, SRC, iswindows from setup import Command, islinux, isbsd, isosx, SRC, iswindows
from setup.build_environment import (fc_inc, fc_lib, chmlib_inc_dirs, fc_error, from setup.build_environment import (chmlib_inc_dirs,
podofo_inc, podofo_lib, podofo_error, pyqt, OSX_SDK, NMAKE, QMAKE, podofo_inc, podofo_lib, podofo_error, pyqt, OSX_SDK, NMAKE, QMAKE,
msvc, MT, win_inc, win_lib, win_ddk, magick_inc_dirs, magick_lib_dirs, msvc, MT, win_inc, win_lib, win_ddk, magick_inc_dirs, magick_lib_dirs,
magick_libs, chmlib_lib_dirs, sqlite_inc_dirs, icu_inc_dirs, magick_libs, chmlib_lib_dirs, sqlite_inc_dirs, icu_inc_dirs,
@ -122,13 +122,6 @@ extensions = [
libraries=ft_libs, libraries=ft_libs,
lib_dirs=ft_lib_dirs), lib_dirs=ft_lib_dirs),
Extension('fontconfig',
['calibre/utils/fonts/fontconfig.c'],
inc_dirs = [fc_inc],
libraries=['fontconfig'],
lib_dirs=[fc_lib],
error=fc_error),
Extension('woff', Extension('woff',
['calibre/utils/fonts/woff/main.c', ['calibre/utils/fonts/woff/main.c',
'calibre/utils/fonts/woff/woff.c'], 'calibre/utils/fonts/woff/woff.c'],
@ -305,9 +298,6 @@ class Build(Command):
CFLAGS - Extra compiler flags CFLAGS - Extra compiler flags
LDFLAGS - Extra linker flags LDFLAGS - Extra linker flags
FC_INC_DIR - fontconfig header files
FC_LIB_DIR - fontconfig library
POPPLER_INC_DIR - poppler header files POPPLER_INC_DIR - poppler header files
POPPLER_LIB_DIR - poppler-qt4 library POPPLER_LIB_DIR - poppler-qt4 library

View File

@ -15,8 +15,6 @@ from setup import __version__ as VERSION, __appname__ as APPNAME, basenames, \
LICENSE = open('LICENSE', 'rb').read() LICENSE = open('LICENSE', 'rb').read()
MAGICK_HOME='@executable_path/../Frameworks/ImageMagick' MAGICK_HOME='@executable_path/../Frameworks/ImageMagick'
ENV = dict( ENV = dict(
FC_CONFIG_DIR='@executable_path/../Resources/fonts',
FC_CONFIG_FILE='@executable_path/../Resources/fonts/fonts.conf',
MAGICK_CONFIGURE_PATH=MAGICK_HOME+'/config', MAGICK_CONFIGURE_PATH=MAGICK_HOME+'/config',
MAGICK_CODER_MODULE_PATH=MAGICK_HOME+'/modules-Q16/coders', MAGICK_CODER_MODULE_PATH=MAGICK_HOME+'/modules-Q16/coders',
MAGICK_CODER_FILTER_PATH=MAGICK_HOME+'/modules-Q16/filter', MAGICK_CODER_FILTER_PATH=MAGICK_HOME+'/modules-Q16/filter',
@ -180,7 +178,7 @@ class Py2App(object):
self.add_poppler() self.add_poppler()
self.add_libjpeg() self.add_libjpeg()
self.add_libpng() self.add_libpng()
self.add_fontconfig() self.add_freetype()
self.add_imagemagick() self.add_imagemagick()
self.add_misc_libraries() self.add_misc_libraries()
@ -397,28 +395,11 @@ class Py2App(object):
@flush @flush
def add_fontconfig(self): def add_freetype(self):
info('\nAdding fontconfig') info('\nAdding freetype')
for x in ('fontconfig.1', 'freetype.6', 'expat.1'): for x in ('freetype.6', 'expat.1'):
src = os.path.join(SW, 'lib', 'lib'+x+'.dylib') src = os.path.join(SW, 'lib', 'lib'+x+'.dylib')
self.install_dylib(src) self.install_dylib(src)
dst = os.path.join(self.resources_dir, 'fonts')
if os.path.exists(dst):
shutil.rmtree(dst)
src = os.path.join(SW, 'etc', 'fonts')
shutil.copytree(src, dst, symlinks=False)
fc = os.path.join(dst, 'fonts.conf')
raw = open(fc, 'rb').read()
raw = raw.replace('<dir>/usr/share/fonts</dir>', '''\
<dir>/Library/Fonts</dir>
<dir>/Network/Library/Fonts</dir>
<dir>/System/Library/Fonts</dir>
<dir>/usr/X11R6/lib/X11/fonts</dir>
<dir>/usr/share/fonts</dir>
<dir>/var/root/Library/Fonts</dir>
<dir>/usr/share/fonts</dir>
''')
open(fc, 'wb').write(raw)
@flush @flush
def add_imagemagick(self): def add_imagemagick(self):

View File

@ -281,8 +281,6 @@ class Win32Freeze(Command, WixMixIn):
for x in ('zlib1.dll', 'libxml2.dll'): for x in ('zlib1.dll', 'libxml2.dll'):
shutil.copy2(self.j(bindir, x+'.manifest'), self.dll_dir) shutil.copy2(self.j(bindir, x+'.manifest'), self.dll_dir)
shutil.copytree(os.path.join(SW, 'etc', 'fonts'),
os.path.join(self.base, 'fontconfig'))
# Copy ImageMagick # Copy ImageMagick
for pat in ('*.dll', '*.xml'): for pat in ('*.dll', '*.xml'):
for f in glob.glob(self.j(IMAGEMAGICK, pat)): for f in glob.glob(self.j(IMAGEMAGICK, pat)):

View File

@ -276,27 +276,6 @@ cp build/kdewin32-msvc-0.3.9/build/bin/Release/*.exp lib/
cp -r build/kdewin32-msvc-0.3.9/include/msvc/ include/ cp -r build/kdewin32-msvc-0.3.9/include/msvc/ include/
cp build/kdewin32-msvc-0.3.9/include/*.h include/ cp build/kdewin32-msvc-0.3.9/include/*.h include/
fontconfig
---------------
Get it from http://www.winkde.org/pub/kde/ports/win32/repository/win32libs/
mkdir build
Remove subdirectory test from the bottom of CMakeLists.txt
run cmake
Set build type to release and project config to dll
Right click on the fontconfig project and select properties. Add sw/include/msvc to the include paths
Build only fontconfig
cp build/fontconfig-msvc-2.4.2-3/build/src/Release/*.dll bin
cp build/fontconfig-msvc-2.4.2-3/build/src/Release/*.lib lib
cp build/fontconfig-msvc-2.4.2-3/build/src/Release/*.exp lib
cp -r build/fontconfig-msvc-2.4.2-3/fontconfig/ include/
Also install the etc files from the font-config-bin archive from kde win32libs
It contains correct fonts.conf etc.
poppler poppler
------------- -------------

View File

@ -83,7 +83,6 @@ class Plugins(collections.Mapping):
'magick', 'magick',
'podofo', 'podofo',
'cPalmdoc', 'cPalmdoc',
'fontconfig',
'progress_indicator', 'progress_indicator',
'chmlib', 'chmlib',
'chm_extra', 'chm_extra',

View File

@ -1,233 +0,0 @@
#!/usr/bin/env python
# vim:fileencoding=UTF-8:ts=4:sw=4:sta:et:sts=4:ai
from __future__ import with_statement
__license__ = 'GPL v3'
__copyright__ = '2009, Kovid Goyal <kovid@kovidgoyal.net>'
__docformat__ = 'restructuredtext en'
import os, sys
from calibre.constants import plugins, islinux, isbsd, isosx, preferred_encoding
_fc, _fc_err = plugins['fontconfig']
if _fc is None:
raise RuntimeError('Failed to load fontconfig with error:'+_fc_err)
if islinux or isbsd:
Thread = object
else:
from threading import Thread
class FontConfig(Thread):
def __init__(self):
Thread.__init__(self)
self.daemon = True
self.failed = False
self.css_weight_map = {
_fc.FC_WEIGHT_THIN : u'100',
_fc.FC_WEIGHT_EXTRALIGHT : u'200', _fc.FC_WEIGHT_ULTRALIGHT : u'200',
_fc.FC_WEIGHT_LIGHT : u'300',
_fc.FC_WEIGHT_BOOK : u'normal', _fc.FC_WEIGHT_BOOK : u'normal', _fc.FC_WEIGHT_REGULAR : u'normal',
_fc.FC_WEIGHT_MEDIUM : u'500',
_fc.FC_WEIGHT_DEMIBOLD : u'600', _fc.FC_WEIGHT_SEMIBOLD : u'600',
_fc.FC_WEIGHT_BOLD : u'bold',
_fc.FC_WEIGHT_EXTRABOLD : u'800', _fc.FC_WEIGHT_ULTRABOLD : u'800',
_fc.FC_WEIGHT_HEAVY : u'900', _fc.FC_WEIGHT_BLACK : u'900', _fc.FC_WEIGHT_EXTRABLACK : u'900', _fc.FC_WEIGHT_ULTRABLACK : u'900'
}
self.css_slant_map = {
_fc.FC_SLANT_ROMAN : u'normal',
_fc.FC_SLANT_ITALIC : u'italic',
_fc.FC_SLANT_OBLIQUE : u'oblique'
}
self.css_stretch_map = {
_fc.FC_WIDTH_ULTRACONDENSED: u'ultra-condensed',
_fc.FC_WIDTH_EXTRACONDENSED : u'extra-condensed',
_fc.FC_WIDTH_CONDENSED: u'condensed',
_fc.FC_WIDTH_SEMICONDENSED: u'semi-condensed',
_fc.FC_WIDTH_NORMAL: u'normal',
_fc.FC_WIDTH_SEMIEXPANDED: u'semi-expanded',
_fc.FC_WIDTH_EXPANDED: u'expanded',
_fc.FC_WIDTH_EXTRAEXPANDED: u'extra-expanded',
_fc.FC_WIDTH_ULTRAEXPANDED: u'ultra-expanded',
}
def run(self):
config = None
if getattr(sys, 'frameworks_dir', False):
config_dir = os.path.join(os.path.dirname(
getattr(sys, 'frameworks_dir')), 'Resources', 'fonts')
if isinstance(config_dir, unicode):
config_dir = config_dir.encode(sys.getfilesystemencoding())
config = os.path.join(config_dir, 'fonts.conf')
try:
_fc.initialize(config)
except:
import traceback
traceback.print_exc()
self.failed = True
if not self.failed and hasattr(_fc, 'add_font_dir'):
_fc.add_font_dir(P('fonts/liberation'))
def is_scanning(self):
if isosx:
return self.is_alive()
return False
def wait(self):
if not (islinux or isbsd):
self.join()
if self.failed:
raise RuntimeError('Failed to initialize fontconfig')
def find_font_families(self, allowed_extensions={'ttf', 'otf'}):
'''
Return an alphabetically sorted list of font families available on the system.
`allowed_extensions`: A list of allowed extensions for font file types. Defaults to
`['ttf', 'otf']`. If it is empty, it is ignored.
'''
self.wait()
ans = _fc.find_font_families([bytes('.'+x) for x in allowed_extensions])
ans = sorted(set(ans), cmp=lambda x,y:cmp(x.lower(), y.lower()))
ans2 = []
for x in ans:
try:
ans2.append(x.decode('utf-8'))
except UnicodeDecodeError:
continue
return ans2
def files_for_family(self, family, normalize=True):
'''
Find all the variants in the font family `family`.
Returns a dictionary of tuples. Each tuple is of the form (path to font
file, Full font name).
The keys of the dictionary depend on `normalize`. If `normalize` is `False`,
they are a tuple (slant, weight) otherwise they are strings from the set
`('normal', 'bold', 'italic', 'bi', 'light', 'li')`
'''
self.wait()
if not isinstance(family, unicode):
family = family.decode(preferred_encoding)
fonts = {}
for entry in _fc.files_for_family(family):
slant, weight = entry['slant'], entry['weight']
fullname, path = entry['fullname'], entry['path']
nfamily = entry['family']
style = (slant, weight)
if normalize:
italic = slant > 0
normal = weight == 80
bold = weight > 80
if italic:
style = 'italic' if normal else 'bi' if bold else 'li'
else:
style = 'normal' if normal else 'bold' if bold else 'light'
try:
fullname, path = fullname.decode('utf-8'), path.decode('utf-8')
nfamily = nfamily.decode('utf-8')
except UnicodeDecodeError:
continue
if style in fonts:
if nfamily.lower().strip() == family.lower().strip() \
and 'Condensed' not in fullname and 'ExtraLight' not in fullname:
fonts[style] = (path, fullname)
else:
fonts[style] = (path, fullname)
return fonts
def faces_for_family(self, family):
'''
Return all the faces in a font family in a manner suitable for CSS 3.
'''
self.wait()
if not isinstance(family, unicode):
family = family.decode(preferred_encoding)
seen = set()
for entry in _fc.files_for_family(family):
slant, weight = entry['slant'], entry['weight']
fullname, path = entry['fullname'], entry['path']
nfamily, width = entry['family'], entry['width']
fingerprint = (slant, weight, width, nfamily)
if fingerprint in seen:
# Fontconfig returns the same font multiple times if it is
# present in multiple locations
continue
seen.add(fingerprint)
try:
nfamily = nfamily.decode('UTF-8')
fullname = fullname.decode('utf-8')
path = path.decode('utf-8')
except UnicodeDecodeError:
continue
face = {
'font-weight': self.css_weight_map[weight],
'font-style': self.css_slant_map[slant],
'font-stretch': self.css_stretch_map[width],
'font-family': nfamily,
'fullname': fullname, 'path':path
}
yield face
def match(self, name, all=False, verbose=False):
'''
Find the system font that most closely matches `name`, where `name` is a specification
of the form::
familyname-<pointsize>:<property1=value1>:<property2=value2>...
For example, `verdana:weight=bold:slant=italic`
Returns a list of dictionaries, or a single dictionary.
Each dictionary has the keys:
'weight', 'slant', 'family', 'file', 'fullname', 'style'
`all`: If `True` return a sorted list of matching fonts, where the sort
is in order of decreasing closeness of matching. If `False` only the
best match is returned. '''
self.wait()
if isinstance(name, unicode):
name = name.encode('utf-8')
fonts = []
for fullname, path, style, family, weight, slant in \
_fc.match(str(name), bool(all), bool(verbose)):
try:
fullname = fullname.decode('utf-8')
path = path.decode('utf-8')
style = style.decode('utf-8')
family = family.decode('utf-8')
fonts.append({
'fullname' : fullname,
'path' : path,
'style' : style,
'family' : family,
'weight' : weight,
'slant' : slant
})
except UnicodeDecodeError:
continue
return fonts if all else (fonts[0] if fonts else None)
fontconfig = FontConfig()
if islinux or isbsd:
# On X11 Qt also uses fontconfig, so initialization must happen in the
# main thread. In any case on X11 initializing fontconfig should be very
# fast
fontconfig.run()
else:
fontconfig.start()
def test():
from pprint import pprint;
pprint(fontconfig.find_font_families())
pprint(tuple(fontconfig.faces_for_family('liberation serif')))
m = 'liberation serif'
pprint(fontconfig.match(m+':slant=italic:weight=bold', verbose=True))
if __name__ == '__main__':
test()

View File

@ -1,374 +0,0 @@
/*
:mod:`fontconfig` -- Pythonic interface to fontconfig
=====================================================
.. module:: fontconfig
:platform: All
:synopsis: Pythonic interface to the fontconfig library
.. moduleauthor:: Kovid Goyal <kovid@kovidgoyal.net> Copyright 2009
*/
#define PY_SSIZE_T_CLEAN
#include <Python.h>
#include <stdio.h>
#include <string.h>
#include <fontconfig.h>
static PyObject *
fontconfig_initialize(PyObject *self, PyObject *args) {
FcChar8 *path;
FcBool ok;
FcConfig *config;
PyThreadState *_save;
if (!PyArg_ParseTuple(args, "z", &path))
return NULL;
if (path == NULL) {
_save = PyEval_SaveThread();
ok = FcInit();
PyEval_RestoreThread(_save);
} else {
config = FcConfigCreate();
if (config == NULL) return PyErr_NoMemory();
_save = PyEval_SaveThread();
ok = FcConfigParseAndLoad(config, path, FcTrue);
if (ok) ok = FcConfigBuildFonts(config);
if (ok) ok = FcConfigSetCurrent(config);
PyEval_RestoreThread(_save);
if (!ok) return PyErr_NoMemory();
ok = 1;
}
if (ok) Py_RETURN_TRUE;
Py_RETURN_FALSE;
}
static PyObject*
fontconfig_add_font_dir(PyObject *self, PyObject *args) {
FcChar8 *path;
if (!PyArg_ParseTuple(args, "s", &path)) return NULL;
if (FcConfigAppFontAddDir(NULL, path))
Py_RETURN_TRUE;
Py_RETURN_FALSE;
}
static void
fontconfig_cleanup_find(FcPattern *p, FcObjectSet *oset, FcFontSet *fs) {
if (p != NULL) FcPatternDestroy(p);
if (oset != NULL) FcObjectSetDestroy(oset);
if (fs != NULL) FcFontSetDestroy(fs);
}
static PyObject *
fontconfig_find_font_families(PyObject *self, PyObject *args) {
int i;
size_t flen;
char *ext;
Py_ssize_t l, j, extlen;
FcBool ok;
FcPattern *pat, *temp;
FcObjectSet *oset;
FcFontSet *fs;
FcValue v, w;
PyObject *ans, *exts, *t;
ans = PyList_New(0);
fs = NULL; oset = NULL; pat = NULL;
if (ans == NULL) return PyErr_NoMemory();
if (!PyArg_ParseTuple(args, "O", &exts))
return NULL;
if (!PySequence_Check(exts)) {
PyErr_SetString(PyExc_ValueError, "Must pass sequence of extensions");
return NULL;
}
l = PySequence_Size(exts);
pat = FcPatternCreate();
if (pat == NULL) { fontconfig_cleanup_find(pat, oset, fs); return PyErr_NoMemory(); }
oset = FcObjectSetCreate();
if (oset == NULL) { fontconfig_cleanup_find(pat, oset, fs); return PyErr_NoMemory(); }
if (!FcObjectSetAdd(oset, FC_FILE)) { fontconfig_cleanup_find(pat, oset, fs); return PyErr_NoMemory(); }
if (!FcObjectSetAdd(oset, FC_FAMILY)) { fontconfig_cleanup_find(pat, oset, fs); return PyErr_NoMemory(); }
fs = FcFontList(FcConfigGetCurrent(), pat, oset);
if (fs == NULL) { fontconfig_cleanup_find(pat, oset, fs); return PyErr_NoMemory(); }
for (i = 0; i < fs->nfont; i++) {
temp = fs->fonts[i];
if (temp == NULL) continue;
if (FcPatternGet(temp, FC_FILE, 0, &v) != FcResultMatch) continue;
if (v.type == FcTypeString) {
flen = strlen((char *)v.u.s);
ok = FcFalse;
if (l == 0) ok = FcTrue;
for ( j = 0; j < l && !ok; j++) {
ext = PyBytes_AS_STRING(PySequence_ITEM(exts, j));
extlen = PyBytes_GET_SIZE(PySequence_ITEM(exts, j));
ok = flen > extlen && extlen > 0 &&
PyOS_strnicmp(ext, ((char *)v.u.s) + (flen - extlen), extlen) == 0;
}
if (ok) {
if (FcPatternGet(temp, FC_FAMILY, 0, &w) != FcResultMatch) continue;
if (w.type != FcTypeString) continue;
t = PyString_FromString((char *)w.u.s);
if (t == NULL) { fontconfig_cleanup_find(pat, oset, fs); return PyErr_NoMemory(); }
if (PyList_Append(ans, t) != 0)
{ fontconfig_cleanup_find(pat, oset, fs); return PyErr_NoMemory(); }
}
}
}
fontconfig_cleanup_find(pat, oset, fs);
Py_INCREF(ans);
return ans;
}
static PyObject *
fontconfig_files_for_family(PyObject *self, PyObject *args) {
char *family; int i;
FcPattern *pat, *tp;
FcObjectSet *oset;
FcFontSet *fs;
FcValue file, weight, fullname, style, slant, family2, width;
PyObject *ans, *temp;
if (!PyArg_ParseTuple(args, "es", "UTF-8", &family))
return NULL;
ans = PyList_New(0);
if (ans == NULL) return PyErr_NoMemory();
fs = NULL; oset = NULL; pat = NULL;
pat = FcPatternBuild(0, FC_FAMILY, FcTypeString, family, (char *) 0);
if (pat == NULL) { fontconfig_cleanup_find(pat, oset, fs); return PyErr_NoMemory(); }
PyMem_Free(family); family = NULL;
oset = FcObjectSetCreate();
if (oset == NULL) { fontconfig_cleanup_find(pat, oset, fs); return PyErr_NoMemory(); }
if (!FcObjectSetAdd(oset, FC_FILE)) { fontconfig_cleanup_find(pat, oset, fs); return PyErr_NoMemory(); }
if (!FcObjectSetAdd(oset, FC_STYLE)) { fontconfig_cleanup_find(pat, oset, fs); return PyErr_NoMemory(); }
if (!FcObjectSetAdd(oset, FC_SLANT)) { fontconfig_cleanup_find(pat, oset, fs); return PyErr_NoMemory(); }
if (!FcObjectSetAdd(oset, FC_WEIGHT)) { fontconfig_cleanup_find(pat, oset, fs); return PyErr_NoMemory(); }
if (!FcObjectSetAdd(oset, FC_WIDTH)) { fontconfig_cleanup_find(pat, oset, fs); return PyErr_NoMemory(); }
if (!FcObjectSetAdd(oset, FC_FAMILY)) { fontconfig_cleanup_find(pat, oset, fs); return PyErr_NoMemory(); }
if (!FcObjectSetAdd(oset, FC_FULLNAME)) { fontconfig_cleanup_find(pat, oset, fs); return PyErr_NoMemory(); }
fs = FcFontList(FcConfigGetCurrent(), pat, oset);
if (fs == NULL) { fontconfig_cleanup_find(pat, oset, fs); return PyErr_NoMemory(); }
for (i = 0; i < fs->nfont; i++) {
tp = fs->fonts[i];
if (tp == NULL) continue;
if (FcPatternGet(tp, FC_FILE, 0, &file) != FcResultMatch) continue;
if (FcPatternGet(tp, FC_STYLE, 0, &style) != FcResultMatch) continue;
if (FcPatternGet(tp, FC_WEIGHT, 0, &weight) != FcResultMatch) continue;
if (FcPatternGet(tp, FC_WIDTH, 0, &width) != FcResultMatch) continue;
if (FcPatternGet(tp, FC_SLANT, 0, &slant) != FcResultMatch) continue;
if (FcPatternGet(tp, FC_FAMILY, 0, &family2) != FcResultMatch) continue;
if (FcPatternGet(tp, FC_FULLNAME, 0, &fullname) != FcResultMatch) continue;
temp = Py_BuildValue("{s:s, s:s, s:s, s:s, s:l, s:l, s:l}",
"fullname", (char*)fullname.u.s,
"path", (char*)file.u.s,
"style", (char*)style.u.s,
"family", (char*)family2.u.s,
"weight", (long)weight.u.i,
"slant", (long)slant.u.i,
"width", (long)width.u.i
);
if (temp == NULL) { fontconfig_cleanup_find(pat, oset, fs); return NULL; }
if (PyList_Append(ans, temp) != 0)
{ fontconfig_cleanup_find(pat, oset, fs); return PyErr_NoMemory(); }
}
fontconfig_cleanup_find(pat, oset, fs);
Py_INCREF(ans);
return ans;
}
static PyObject *
fontconfig_match(PyObject *self, PyObject *args) {
FcChar8 *namespec; int i;
FcPattern *pat, *tp;
FcObjectSet *oset;
FcFontSet *fs, *fs2;
FcValue file, weight, fullname, style, slant, family;
FcResult res;
PyObject *ans, *temp, *t, *all, *verbose;
if (!PyArg_ParseTuple(args, "sOO", &namespec, &all, &verbose))
return NULL;
ans = PyList_New(0);
if (ans == NULL) return PyErr_NoMemory();
fs = NULL; oset = NULL; pat = NULL; fs2 = NULL;
pat = FcNameParse(namespec);
if (pat == NULL) { fontconfig_cleanup_find(pat, oset, fs); return PyErr_NoMemory(); }
if (PyObject_IsTrue(verbose)) FcPatternPrint(pat);
if (!FcConfigSubstitute(FcConfigGetCurrent(), pat, FcMatchPattern))
{ fontconfig_cleanup_find(pat, oset, fs); return PyErr_NoMemory(); }
FcDefaultSubstitute(pat);
fs = FcFontSetCreate();
if (fs == NULL) { fontconfig_cleanup_find(pat, oset, fs); return PyErr_NoMemory(); }
if (PyObject_IsTrue(all)) {
fs2 = FcFontSort(FcConfigGetCurrent(), pat, FcTrue, NULL, &res);
if (fs2 == NULL) { fontconfig_cleanup_find(pat, oset, fs); return PyErr_NoMemory(); }
for (i = 0; i < fs2->nfont; i++) {
tp = fs2->fonts[i];
if (tp == NULL) continue;
tp = FcFontRenderPrepare(FcConfigGetCurrent(), pat, tp);
if (tp == NULL) { fontconfig_cleanup_find(pat, oset, fs); return PyErr_NoMemory(); }
if (!FcFontSetAdd(fs, tp))
{ fontconfig_cleanup_find(pat, oset, fs); return PyErr_NoMemory(); }
}
if (fs2 != NULL) FcFontSetDestroy(fs2);
} else {
tp = FcFontMatch(FcConfigGetCurrent(), pat, &res);
if (tp == NULL) { fontconfig_cleanup_find(pat, oset, fs); return PyErr_NoMemory(); }
if (!FcFontSetAdd(fs, tp))
{ fontconfig_cleanup_find(pat, oset, fs); return PyErr_NoMemory(); }
}
for (i = 0; i < fs->nfont; i++) {
tp = fs->fonts[i];
if (tp == NULL) continue;
if (FcPatternGet(tp, FC_FILE, 0, &file) != FcResultMatch) continue;
if (FcPatternGet(tp, FC_STYLE, 0, &style) != FcResultMatch) continue;
if (FcPatternGet(tp, FC_WEIGHT, 0, &weight) != FcResultMatch) continue;
if (FcPatternGet(tp, FC_SLANT, 0, &slant) != FcResultMatch) continue;
if (FcPatternGet(tp, FC_FAMILY, 0, &family) != FcResultMatch) continue;
if (FcPatternGet(tp, "fullname", 0, &fullname) != FcResultMatch) continue;
temp = PyTuple_New(6);
if(temp == NULL) { fontconfig_cleanup_find(pat, oset, fs); return PyErr_NoMemory(); }
t = PyBytes_FromString((char *)fullname.u.s);
if(t == NULL) { fontconfig_cleanup_find(pat, oset, fs); return PyErr_NoMemory(); }
PyTuple_SET_ITEM(temp, 0, t);
t = PyBytes_FromString((char *)file.u.s);
if(t == NULL) { fontconfig_cleanup_find(pat, oset, fs); return PyErr_NoMemory(); }
PyTuple_SET_ITEM(temp, 1, t);
t = PyBytes_FromString((char *)style.u.s);
if(t == NULL) { fontconfig_cleanup_find(pat, oset, fs); return PyErr_NoMemory(); }
PyTuple_SET_ITEM(temp, 2, t);
t = PyBytes_FromString((char *)family.u.s);
if(t == NULL) { fontconfig_cleanup_find(pat, oset, fs); return PyErr_NoMemory(); }
PyTuple_SET_ITEM(temp, 3, t);
t = PyInt_FromLong((long)weight.u.i);
if(t == NULL) { fontconfig_cleanup_find(pat, oset, fs); return PyErr_NoMemory(); }
PyTuple_SET_ITEM(temp, 4, t);
t = PyInt_FromLong((long)slant.u.i);
if(t == NULL) { fontconfig_cleanup_find(pat, oset, fs); return PyErr_NoMemory(); }
PyTuple_SET_ITEM(temp, 5, t);
if (PyList_Append(ans, temp) != 0)
{ fontconfig_cleanup_find(pat, oset, fs); return PyErr_NoMemory(); }
}
fontconfig_cleanup_find(pat, oset, fs);
Py_INCREF(ans);
return ans;
}
static
PyMethodDef fontconfig_methods[] = {
{"initialize", fontconfig_initialize, METH_VARARGS,
"initialize(path_to_config_file)\n\n"
"Initialize the library. If path to config file is specified it is used instead of the "
"default configuration. Returns True iff the initialization succeeded."
},
{"find_font_families", fontconfig_find_font_families, METH_VARARGS,
"find_font_families(allowed_extensions)\n\n"
"Find all font families on the system for fonts of the specified types. If no "
"types are specified all font families are returned."
},
{"files_for_family", fontconfig_files_for_family, METH_VARARGS,
"files_for_family(family, normalize)\n\n"
"Find all the variants in the font family `family`. "
"Returns a list of tuples. Each tuple is of the form "
"(fullname, path, style, family, weight, slant). "
},
{"match", fontconfig_match, METH_VARARGS,
"match(namespec,all,verbose)\n\n"
"Find all system fonts that match namespec, in decreasing order "
"of closeness. "
"Returns a list of tuples. Each tuple is of the form "
"(fullname, path, style, family, weight, slant). "
},
{"add_font_dir", fontconfig_add_font_dir, METH_VARARGS,
"add_font_dir(path_to_dir)\n\n"
"Add the fonts in the specified directory to the list of application specific fonts."
},
{NULL, NULL, 0, NULL}
};
PyMODINIT_FUNC
initfontconfig(void) {
PyObject *m;
m = Py_InitModule3(
"fontconfig", fontconfig_methods,
"Find fonts."
);
if (m == NULL) return;
PyModule_AddIntMacro(m, FC_WEIGHT_THIN);
PyModule_AddIntMacro(m, FC_WEIGHT_EXTRALIGHT);
PyModule_AddIntMacro(m, FC_WEIGHT_ULTRALIGHT);
PyModule_AddIntMacro(m, FC_WEIGHT_LIGHT);
PyModule_AddIntMacro(m, FC_WEIGHT_BOOK);
PyModule_AddIntMacro(m, FC_WEIGHT_REGULAR);
PyModule_AddIntMacro(m, FC_WEIGHT_NORMAL);
PyModule_AddIntMacro(m, FC_WEIGHT_MEDIUM);
PyModule_AddIntMacro(m, FC_WEIGHT_DEMIBOLD);
PyModule_AddIntMacro(m, FC_WEIGHT_SEMIBOLD);
PyModule_AddIntMacro(m, FC_WEIGHT_BOLD);
PyModule_AddIntMacro(m, FC_WEIGHT_EXTRABOLD);
PyModule_AddIntMacro(m, FC_WEIGHT_ULTRABOLD);
PyModule_AddIntMacro(m, FC_WEIGHT_BLACK);
PyModule_AddIntMacro(m, FC_WEIGHT_HEAVY);
PyModule_AddIntMacro(m, FC_WEIGHT_EXTRABLACK);
PyModule_AddIntMacro(m, FC_WEIGHT_ULTRABLACK);
PyModule_AddIntMacro(m, FC_SLANT_ROMAN);
PyModule_AddIntMacro(m, FC_SLANT_ITALIC);
PyModule_AddIntMacro(m, FC_SLANT_OBLIQUE);
PyModule_AddIntMacro(m, FC_WIDTH_ULTRACONDENSED);
PyModule_AddIntMacro(m, FC_WIDTH_EXTRACONDENSED);
PyModule_AddIntMacro(m, FC_WIDTH_CONDENSED);
PyModule_AddIntMacro(m, FC_WIDTH_SEMICONDENSED);
PyModule_AddIntMacro(m, FC_WIDTH_NORMAL);
PyModule_AddIntMacro(m, FC_WIDTH_SEMIEXPANDED);
PyModule_AddIntMacro(m, FC_WIDTH_EXPANDED);
PyModule_AddIntMacro(m, FC_WIDTH_EXTRAEXPANDED);
PyModule_AddIntMacro(m, FC_WIDTH_ULTRAEXPANDED);
#
}