mirror of
https://github.com/kovidgoyal/calibre.git
synced 2025-07-09 03:04:10 -04:00
Use fontconfig to manage fonts
This commit is contained in:
parent
261bf8021a
commit
94736825ca
@ -240,6 +240,9 @@ _check_symlinks_prescript()
|
||||
os.link(os.path.expanduser('~/pdftohtml'), os.path.join(frameworks_dir, 'pdftohtml'))
|
||||
print 'Adding plugins'
|
||||
module_dir = os.path.join(resource_dir, 'lib', 'python2.5', 'lib-dynload')
|
||||
print 'Adding fontconfig'
|
||||
for f in glob.glob(os.path.expanduser('~/fontconfig/*')):
|
||||
os.link(f, os.path.join(frameworks_dir, os.path.basename(f)))
|
||||
for src, dest in plugin_files:
|
||||
if 'dylib' in dest:
|
||||
os.link(src, os.path.join(frameworks_dir, dest))
|
||||
|
@ -15,15 +15,14 @@ from optparse import OptionParser as _OptionParser
|
||||
from optparse import IndentedHelpFormatter
|
||||
from logging import Formatter
|
||||
|
||||
from ttfquery import findsystem, describe
|
||||
from PyQt4.QtCore import QSettings, QVariant, QUrl
|
||||
from PyQt4.QtGui import QDesktopServices
|
||||
|
||||
from calibre.translations.msgfmt import make
|
||||
from calibre.ebooks.chardet import detect
|
||||
from calibre.terminfo import TerminalController
|
||||
terminal_controller = TerminalController(sys.stdout)
|
||||
|
||||
terminal_controller = TerminalController(sys.stdout)
|
||||
iswindows = 'win32' in sys.platform.lower() or 'win64' in sys.platform.lower()
|
||||
isosx = 'darwin' in sys.platform.lower()
|
||||
islinux = not(iswindows or isosx)
|
||||
@ -306,44 +305,6 @@ def set_translator():
|
||||
|
||||
set_translator()
|
||||
|
||||
font_families = {}
|
||||
def get_font_families(cached=None):
|
||||
global font_families
|
||||
if cached is not None:
|
||||
font_families = cached
|
||||
if not font_families:
|
||||
try:
|
||||
ffiles = findsystem.findFonts()
|
||||
except Exception, err:
|
||||
print 'WARNING: Could not find fonts on your system.'
|
||||
print err
|
||||
else:
|
||||
zlist = []
|
||||
for ff in ffiles:
|
||||
try:
|
||||
if 'Optane' in str(ff):
|
||||
font = describe.openFont(ff)
|
||||
wt, italic = describe.modifiers(font)
|
||||
except:
|
||||
pass
|
||||
try:
|
||||
font = describe.openFont(ff)
|
||||
except: # Some font files cause ttfquery to raise an exception, in which case they are ignored
|
||||
continue
|
||||
try:
|
||||
wt, italic = describe.modifiers(font)
|
||||
except:
|
||||
wt, italic = 0, 0
|
||||
if wt == 400 and italic == 0:
|
||||
try:
|
||||
family = describe.shortName(font)[1].strip()
|
||||
except: # Windows strikes again!
|
||||
continue
|
||||
zlist.append((family, ff))
|
||||
font_families = dict(zlist)
|
||||
|
||||
return font_families
|
||||
|
||||
def sanitize_file_name(name):
|
||||
'''
|
||||
Remove characters that are illegal in filenames from name.
|
||||
@ -596,3 +557,12 @@ def entity_to_unicode(match, exceptions=[], encoding='cp1252'):
|
||||
except KeyError:
|
||||
return '&'+ent+';'
|
||||
|
||||
if isosx:
|
||||
fdir = os.path.expanduser('~/.fonts')
|
||||
if not os.path.exists(fdir):
|
||||
os.makedirs(fdir)
|
||||
if not os.path.exists(os.path.join(fdir, 'LiberationSans_Regular.ttf')):
|
||||
from calibre.ebooks.lrf.fonts.liberation import __all__ as fonts
|
||||
for font in fonts:
|
||||
exec 'from calibre.ebooks.lrf.fonts.liberation.'+font+' import font_data'
|
||||
open(os.path.join(fdir, font+'.ttf'), 'wb').write(font_data)
|
@ -9,7 +9,6 @@ from optparse import OptionValueError
|
||||
from htmlentitydefs import name2codepoint
|
||||
from uuid import uuid4
|
||||
|
||||
from ttfquery import describe, findsystem
|
||||
from fontTools.ttLib import TTLibError
|
||||
|
||||
from calibre.ebooks.lrf.pylrs.pylrs import Book as _Book
|
||||
@ -67,20 +66,6 @@ def profile_from_string(option, opt_str, value, parser):
|
||||
except KeyError:
|
||||
raise OptionValueError('Profile: '+value+' is not implemented. Implemented profiles: %s'%(profile_map.keys()))
|
||||
|
||||
def font_family(option, opt_str, value, parser):
|
||||
if value:
|
||||
value = value.split(',')
|
||||
if len(value) != 2:
|
||||
raise OptionValueError('Font family specification must be of the form'+\
|
||||
' "path to font directory, font family"')
|
||||
path, family = tuple(value)
|
||||
if not os.path.isdir(path) or not os.access(path, os.R_OK|os.X_OK):
|
||||
raise OptionValueError('Cannot read from ' + path)
|
||||
setattr(parser.values, option.dest, (path, family))
|
||||
else:
|
||||
setattr(parser.values, option.dest, tuple())
|
||||
|
||||
|
||||
def option_parser(usage, gui_mode=False):
|
||||
parser = OptionParser(usage=usage, gui_mode=gui_mode)
|
||||
metadata = parser.add_option_group('METADATA OPTIONS')
|
||||
@ -203,18 +188,17 @@ def option_parser(usage, gui_mode=False):
|
||||
fonts = parser.add_option_group('FONT FAMILIES',
|
||||
_('''Specify trutype font families for serif, sans-serif and monospace fonts. '''
|
||||
'''These fonts will be embedded in the LRF file. Note that custom fonts lead to '''
|
||||
'''slower page turns. Each family specification is of the form: '''
|
||||
'''"path to fonts directory, family" '''
|
||||
'''slower page turns. '''
|
||||
'''For example: '''
|
||||
'''--serif-family "%s, Times New Roman"
|
||||
''') % ('C:\Windows\Fonts' if iswindows else '/usr/share/fonts/corefonts'))
|
||||
fonts.add_option('--serif-family', action='callback', callback=font_family,
|
||||
'''--serif-family "Times New Roman"
|
||||
'''))
|
||||
fonts.add_option('--serif-family',
|
||||
default=None, dest='serif_family', type='string',
|
||||
help=_('The serif family of fonts to embed'))
|
||||
fonts.add_option('--sans-family', action='callback', callback=font_family,
|
||||
fonts.add_option('--sans-family',
|
||||
default=None, dest='sans_family', type='string',
|
||||
help=_('The sans-serif family of fonts to embed'))
|
||||
fonts.add_option('--mono-family', action='callback', callback=font_family,
|
||||
fonts.add_option('--mono-family',
|
||||
default=None, dest='mono_family', type='string',
|
||||
help=_('The monospace family of fonts to embed'))
|
||||
|
||||
@ -231,45 +215,25 @@ def option_parser(usage, gui_mode=False):
|
||||
return parser
|
||||
|
||||
def find_custom_fonts(options, logger):
|
||||
from calibre.utils.fontconfig import files_for_family
|
||||
fonts = {'serif' : None, 'sans' : None, 'mono' : None}
|
||||
def find_family(option):
|
||||
path, family = option
|
||||
paths = findsystem.findFonts([path])
|
||||
results = {}
|
||||
for path in paths:
|
||||
if len(results.keys()) == 4:
|
||||
break
|
||||
f = describe.openFont(path)
|
||||
name, cfamily = describe.shortName(f)
|
||||
if cfamily.lower().strip() != family.lower().strip():
|
||||
continue
|
||||
try:
|
||||
wt, italic = describe.modifiers(f)
|
||||
except TTLibError:
|
||||
logger.exception('Could not process fonts in %s', path)
|
||||
wt, italic = 0, 0
|
||||
result = (path, name)
|
||||
if wt == 400 and italic == 0:
|
||||
results['normal'] = result
|
||||
elif wt == 400 and italic > 0:
|
||||
results['italic'] = result
|
||||
elif wt >= 700 and italic == 0:
|
||||
results['bold'] = result
|
||||
elif wt >= 700 and italic > 0:
|
||||
results['bi'] = result
|
||||
return results
|
||||
def family(cmd):
|
||||
return cmd.split(',')[-1].strip()
|
||||
if options.serif_family:
|
||||
fonts['serif'] = find_family(options.serif_family)
|
||||
f = family(options.serif_family)
|
||||
fonts['serif'] = files_for_family(f)
|
||||
if not fonts['serif']:
|
||||
logger.warn('Unable to find serif family %s in %s'%(options.serif_family[1].strip(), options.serif_family[0]))
|
||||
logger.warn('Unable to find serif family %s'%f)
|
||||
if options.sans_family:
|
||||
fonts['sans'] = find_family(options.sans_family)
|
||||
f = family(options.sans_family)
|
||||
fonts['sans'] = files_for_family(f)
|
||||
if not fonts['sans']:
|
||||
logger.warn('Unable to find sans family %s in %s'%(options.sans_family[1].strip(), options.sans_family[0]))
|
||||
logger.warn('Unable to find sans family %s'%f)
|
||||
if options.mono_family:
|
||||
fonts['mono'] = find_family(options.mono_family)
|
||||
f = family(options.mono_family)
|
||||
fonts['mono'] = files_for_family(f)
|
||||
if not fonts['mono']:
|
||||
logger.warn('Unable to find mono family %s in %s'%(options.mono_family[1].strip(), options.mono_family[0]))
|
||||
logger.warn('Unable to find mono family %s'%f)
|
||||
return fonts
|
||||
|
||||
|
||||
@ -324,4 +288,4 @@ def Book(options, logger, font_delta=0, header=None,
|
||||
raise ConversionError, 'Could not find the normal version of the ' + family + ' font'
|
||||
return book, fonts
|
||||
|
||||
from calibre import entity_to_unicode
|
||||
from calibre import entity_to_unicode
|
||||
|
@ -0,0 +1,5 @@
|
||||
__all__ = ['LiberationMono_Bold', 'LiberationMono_Regular', 'LiberationSans_Bold',
|
||||
'LiberationSans_Regular', 'LiberationSerif_Bold', 'LiberationSerif_Regular',
|
||||
'LiberationMono_BoldItalic', 'LiberationMono_Italic',
|
||||
'LiberationSans_BoldItalic', 'LiberationSans_Italic',
|
||||
'LiberationSerif_BoldItalic', 'LiberationSerif_Italic']
|
@ -143,7 +143,7 @@ class LRFSingleDialog(QDialog, Ui_LRFSingleDialog):
|
||||
for opt in ('--serif-family', '--sans-family', '--mono-family'):
|
||||
if opt in cmdline:
|
||||
print 'in'
|
||||
family = cmdline[cmdline.index(opt)+1].split(',')[1].strip()
|
||||
family = cmdline[cmdline.index(opt)+1].split(',')[-1].strip()
|
||||
obj = getattr(self, 'gui_'+opt[2:].replace('-', '_'))
|
||||
try:
|
||||
obj.setCurrentIndex(self.font_family_model.index_of(family))
|
||||
@ -332,12 +332,8 @@ class LRFSingleDialog(QDialog, Ui_LRFSingleDialog):
|
||||
for opt in ('--serif-family', '--sans-family', '--mono-family'):
|
||||
obj = getattr(self, 'gui_'+opt[2:].replace('-', '_'))
|
||||
family = qstring_to_unicode(obj.itemText(obj.currentIndex())).strip()
|
||||
try:
|
||||
path = self.font_family_model.path_of(family)
|
||||
except KeyError:
|
||||
continue
|
||||
if path:
|
||||
cmd.extend([opt, os.path.dirname(path)+', '+family])
|
||||
if family != 'None':
|
||||
cmd.extend([opt, family])
|
||||
|
||||
return cmd
|
||||
|
||||
|
@ -48,6 +48,7 @@ entry_points = {
|
||||
'lrf2html = calibre.ebooks.lrf.html.convert_to:main',
|
||||
'calibre-debug = calibre.debug:main',
|
||||
'calibredb = calibre.library.cli:main',
|
||||
'calibre-fontconfig = calibre.utils.fontconfig:main',
|
||||
],
|
||||
'gui_scripts' : [
|
||||
__appname__+' = calibre.gui2.main:main',
|
||||
|
@ -31,7 +31,6 @@ class Distribution(object):
|
||||
('libusb', '0.1.12', None, None, None),
|
||||
('Qt', '4.4.0', 'qt', 'libqt4-core libqt4-gui', 'qt4'),
|
||||
('PyQt', '4.4.2', 'PyQt4', 'python-qt4', 'PyQt4'),
|
||||
('fonttools', '2.0-beta1', 'fonttools', 'fonttools', 'fonttools'),
|
||||
('mechanize for python', '0.1.7b', 'dev-python/mechanize', 'python-mechanize', 'python-mechanize'),
|
||||
('ImageMagick', '6.3.5', 'imagemagick', 'imagemagick', 'ImageMagick'),
|
||||
('xdg-utils', '1.0.2', 'xdg-utils', 'xdg-utils', 'xdg-utils'),
|
||||
|
@ -34,7 +34,7 @@
|
||||
<div py:if="distro.is_generic">
|
||||
<ol>
|
||||
<li>Make sure that your system has <code>python >= 2.5</code></li>
|
||||
<li>Install the various dependencies listed below: Make sure that any python packages are installed into python2.5 (e.g. setuptools, python-imaging, PyQt4, fonttools, etc)</li>
|
||||
<li>Install the various dependencies listed below: Make sure that any python packages are installed into python2.5 (e.g. setuptools, python-imaging, PyQt4, etc)</li>
|
||||
<li>As root run the command <pre class="wiki">easy_install-2.5 -U TTFQuery calibre && calibre_postinstall</pre></li>
|
||||
</ol>
|
||||
<h2>Dependencies</h2>
|
||||
|
@ -85,7 +85,6 @@ def main(args=sys.argv):
|
||||
if __name__ == '__main__':
|
||||
cwd = os.getcwd()
|
||||
sys.path.insert(0, os.path.dirname(os.path.dirname(cwd)))
|
||||
print sys.path[0]
|
||||
|
||||
sys.exit(main())
|
||||
|
||||
|
320
src/calibre/utils/fontconfig.py
Normal file
320
src/calibre/utils/fontconfig.py
Normal file
@ -0,0 +1,320 @@
|
||||
#!/usr/bin/env python
|
||||
__license__ = 'GPL v3'
|
||||
__copyright__ = '2008, Kovid Goyal kovid@kovidgoyal.net'
|
||||
__docformat__ = 'restructuredtext en'
|
||||
|
||||
'''
|
||||
:mod:`fontconfig` -- Query system fonts
|
||||
=============================================
|
||||
.. module:: fontconfig
|
||||
:platform: Unix, Windows, OS X
|
||||
:synopsis: Query system fonts
|
||||
.. moduleauthor:: Kovid Goyal <kovid@kovidgoyal.net>
|
||||
|
||||
A ctypes based wrapper around the `fontconfig <http://fontconfig.org>`_ library.
|
||||
It can be used to find all fonts available on the system as well as the closest
|
||||
match to a given font specification. The main functions in this module are:
|
||||
|
||||
.. autofunction:: find_font_families
|
||||
|
||||
.. autofunction:: files_for_family
|
||||
|
||||
.. autofunction:: match
|
||||
'''
|
||||
|
||||
import sys, os, locale, codecs
|
||||
from ctypes import cdll, c_void_p, Structure, c_int, POINTER, c_ubyte, c_char, \
|
||||
pointer, byref, create_string_buffer, Union, c_char_p, c_double
|
||||
|
||||
try:
|
||||
preferred_encoding = locale.getpreferredencoding()
|
||||
codecs.lookup(preferred_encoding)
|
||||
except:
|
||||
preferred_encoding = 'utf-8'
|
||||
|
||||
iswindows = 'win32' in sys.platform or 'win64' in sys.platform
|
||||
isosx = 'darwin' in sys.platform
|
||||
|
||||
def load_library():
|
||||
if isosx:
|
||||
lib = 'libfontconfig.1.dylib'
|
||||
if hasattr(sys, 'frameworks_dir'):
|
||||
lib = os.path.join(getattr(sys, 'frameworks_dir'), lib)
|
||||
return cdll.LoadLibrary(lib)
|
||||
elif iswindows:
|
||||
return cdll.LoadLibrary('libfontconfig-1')
|
||||
else:
|
||||
return cdll.LoadLibrary('libfontconfig.so')
|
||||
|
||||
class FcPattern(Structure):
|
||||
_fields_ = [
|
||||
('num', c_int),
|
||||
('size', c_int),
|
||||
('elts_offset', c_void_p),
|
||||
('ref', c_int)
|
||||
]
|
||||
class FcFontSet(Structure):
|
||||
_fields_ = [
|
||||
('nfont', c_int),
|
||||
('sfont', c_int),
|
||||
('fonts', POINTER(POINTER(FcPattern)))
|
||||
]
|
||||
(
|
||||
FcTypeVoid,
|
||||
FcTypeInteger,
|
||||
FcTypeDouble,
|
||||
FcTypeString,
|
||||
FcTypeBool,
|
||||
FcTypeMatrix,
|
||||
FcTypeCharSet,
|
||||
FcTypeFTFace,
|
||||
FcTypeLangSet
|
||||
) = map(c_int, range(9))
|
||||
(FcMatchPattern, FcMatchFont, FcMatchScan) = map(c_int, range(3))
|
||||
(
|
||||
FcResultMatch, FcResultNoMatch, FcResultTypeMismatch, FcResultNoId,
|
||||
FcResultOutOfMemory
|
||||
) = map(c_int, range(5))
|
||||
FcFalse, FcTrue = c_int(0), c_int(1)
|
||||
|
||||
class _FcValue(Union):
|
||||
_fields_ = [
|
||||
('s', c_char_p),
|
||||
('i', c_int),
|
||||
('b', c_int),
|
||||
('d', c_double),
|
||||
]
|
||||
|
||||
class FcValue(Structure):
|
||||
_fields_ = [
|
||||
('type', c_int),
|
||||
('u', _FcValue)
|
||||
]
|
||||
|
||||
lib = load_library()
|
||||
lib.FcPatternCreate.restype = c_void_p
|
||||
lib.FcObjectSetCreate.restype = c_void_p
|
||||
lib.FcFontSetDestroy.argtypes = [POINTER(FcFontSet)]
|
||||
lib.FcFontList.restype = POINTER(FcFontSet)
|
||||
lib.FcNameUnparse.argtypes = [POINTER(FcPattern)]
|
||||
lib.FcNameUnparse.restype = POINTER(c_ubyte)
|
||||
lib.FcPatternGetString.argtypes = [POINTER(FcPattern), POINTER(c_char), c_int, c_void_p]
|
||||
lib.FcPatternGetString.restype = c_int
|
||||
lib.FcPatternAdd.argtypes = [c_void_p, POINTER(c_char), FcValue, c_int]
|
||||
lib.FcPatternGetInteger.argtypes = [POINTER(FcPattern), POINTER(c_char), c_int, POINTER(c_int)]
|
||||
lib.FcPatternGetInteger.restype = c_int
|
||||
lib.FcNameParse.argtypes = [c_char_p]
|
||||
lib.FcNameParse.restype = POINTER(FcPattern)
|
||||
lib.FcDefaultSubstitute.argtypes = [POINTER(FcPattern)]
|
||||
lib.FcConfigSubstitute.argtypes = [c_void_p, POINTER(FcPattern), c_int]
|
||||
lib.FcFontSetCreate.restype = POINTER(FcFontSet)
|
||||
lib.FcFontMatch.argtypes = [c_void_p, POINTER(FcPattern), POINTER(c_int)]
|
||||
lib.FcFontMatch.restype = POINTER(FcPattern)
|
||||
lib.FcFontSetAdd.argtypes = [POINTER(FcFontSet), POINTER(FcPattern)]
|
||||
lib.FcFontSort.argtypes = [c_void_p, POINTER(FcPattern), c_int, c_void_p, POINTER(c_int)]
|
||||
lib.FcFontSort.restype = POINTER(FcFontSet)
|
||||
lib.FcFontRenderPrepare.argtypes = [c_void_p, POINTER(FcPattern), POINTER(FcPattern)]
|
||||
lib.FcFontRenderPrepare.restype = POINTER(FcPattern)
|
||||
|
||||
|
||||
if not lib.FcInit():
|
||||
raise RuntimeError(_('Could not initialize the fontconfig library'))
|
||||
|
||||
|
||||
def find_font_families(allowed_extensions=['ttf']):
|
||||
'''
|
||||
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']`. If it is empty, it is ignored.
|
||||
'''
|
||||
allowed_extensions = [i.lower() for i in allowed_extensions]
|
||||
|
||||
empty_pattern = lib.FcPatternCreate()
|
||||
oset = lib.FcObjectSetCreate()
|
||||
if not lib.FcObjectSetAdd(oset, 'file'):
|
||||
raise RuntimeError('Allocation failure')
|
||||
if not lib.FcObjectSetAdd(oset, 'family'):
|
||||
raise RuntimeError('Allocation failure')
|
||||
fs = lib.FcFontList(0, empty_pattern, oset)
|
||||
font_set = fs.contents
|
||||
file = pointer(create_string_buffer(chr(0), 5000))
|
||||
family = pointer(create_string_buffer(chr(0), 200))
|
||||
font_families = []
|
||||
for i in range(font_set.nfont):
|
||||
pat = font_set.fonts[i]
|
||||
if lib.FcPatternGetString(pat, 'file', 0, byref(file)) != FcResultMatch.value:
|
||||
raise RuntimeError('Error processing pattern')
|
||||
path = str(file.contents.value)
|
||||
ext = os.path.splitext(path)[1]
|
||||
if ext:
|
||||
ext = ext[1:].lower()
|
||||
if allowed_extensions and ext in allowed_extensions:
|
||||
if lib.FcPatternGetString(pat, 'family', 0, byref(family)) != FcResultMatch.value:
|
||||
raise RuntimeError('Error processing pattern')
|
||||
font_families.append(str(family.contents.value))
|
||||
|
||||
|
||||
lib.FcObjectSetDestroy(oset)
|
||||
lib.FcPatternDestroy(empty_pattern)
|
||||
lib.FcFontSetDestroy(fs)
|
||||
font_families = list(set(font_families))
|
||||
font_families.sort()
|
||||
return font_families
|
||||
|
||||
def files_for_family(family, normalize=True):
|
||||
'''
|
||||
Find all the variants in the font family `family`.
|
||||
Returns a dictionary of tuples. Each tuple is of the form (Full font name, path to font file).
|
||||
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')`
|
||||
'''
|
||||
if isinstance(family, unicode):
|
||||
family = family.encode(preferred_encoding)
|
||||
family_pattern = lib.FcPatternBuild(0, 'family', FcTypeString, family, 0)
|
||||
if not family_pattern:
|
||||
raise RuntimeError('Allocation failure')
|
||||
#lib.FcPatternPrint(family_pattern)
|
||||
oset = lib.FcObjectSetCreate()
|
||||
if not lib.FcObjectSetAdd(oset, 'file'):
|
||||
raise RuntimeError('Allocation failure')
|
||||
if not lib.FcObjectSetAdd(oset, 'weight'):
|
||||
raise RuntimeError('Allocation failure')
|
||||
if not lib.FcObjectSetAdd(oset, 'fullname'):
|
||||
raise RuntimeError('Allocation failure')
|
||||
if not lib.FcObjectSetAdd(oset, 'slant'):
|
||||
raise RuntimeError('Allocation failure')
|
||||
if not lib.FcObjectSetAdd(oset, 'style'):
|
||||
raise RuntimeError('Allocation failure')
|
||||
fonts = {}
|
||||
fs = lib.FcFontList(0, family_pattern, oset)
|
||||
font_set = fs.contents
|
||||
file = pointer(create_string_buffer(chr(0), 5000))
|
||||
full_name = pointer(create_string_buffer(chr(0), 200))
|
||||
weight = c_int(0)
|
||||
slant = c_int(0)
|
||||
fname = ''
|
||||
for i in range(font_set.nfont):
|
||||
pat = font_set.fonts[i]
|
||||
#lib.FcPatternPrint(pat)
|
||||
pat = font_set.fonts[i]
|
||||
if lib.FcPatternGetString(pat, 'file', 0, byref(file)) != FcResultMatch.value:
|
||||
raise RuntimeError('Error processing pattern')
|
||||
if lib.FcPatternGetInteger(pat, 'weight', 0, byref(weight)) != FcResultMatch.value:
|
||||
raise RuntimeError('Error processing pattern')
|
||||
if lib.FcPatternGetString(pat, 'fullname', 0, byref(full_name)) != FcResultMatch.value:
|
||||
if lib.FcPatternGetString(pat, 'fullname', 0, byref(full_name)) == FcResultNoMatch.value:
|
||||
if lib.FcPatternGetString(pat, 'style', 0, byref(full_name)) != FcResultMatch.value:
|
||||
raise RuntimeError('Error processing pattern')
|
||||
fname = family + ' ' + full_name.contents.value
|
||||
else:
|
||||
raise RuntimeError('Error processing pattern')
|
||||
else:
|
||||
fname = full_name.contents.value
|
||||
if lib.FcPatternGetInteger(pat, 'slant', 0, byref(slant)) != FcResultMatch.value:
|
||||
raise RuntimeError('Error processing pattern')
|
||||
style = (slant.value, weight.value)
|
||||
if normalize:
|
||||
italic = slant.value > 0
|
||||
normal = weight.value == 80
|
||||
bold = weight.value > 80
|
||||
if italic:
|
||||
style = 'italic' if normal else 'bi' if bold else 'li'
|
||||
else:
|
||||
style = 'normal' if normal else 'bold' if bold else 'light'
|
||||
fonts[style] = (file.contents.value, fname)
|
||||
lib.FcObjectSetDestroy(oset)
|
||||
lib.FcPatternDestroy(family_pattern)
|
||||
if not iswindows:
|
||||
lib.FcFontSetDestroy(fs)
|
||||
|
||||
return fonts
|
||||
|
||||
def match(name, sort=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. Each dictionary has the keys: 'weight', 'slant', 'family', 'file'
|
||||
|
||||
`sort`: If `True` return a sorted list of matching fonts, where the sort id in order of
|
||||
decreasing closeness of matching.
|
||||
`verbose`: If `True` print debugging information to stdout
|
||||
'''
|
||||
if isinstance(name, unicode):
|
||||
name = name.encode(preferred_encoding)
|
||||
pat = lib.FcNameParse(name)
|
||||
if not pat:
|
||||
raise ValueError('Could not parse font name')
|
||||
if verbose:
|
||||
print 'Searching for pattern'
|
||||
lib.FcPatternPrint(pat)
|
||||
if not lib.FcConfigSubstitute(0, pat, FcMatchPattern):
|
||||
raise RuntimeError('Allocation failure')
|
||||
lib.FcDefaultSubstitute(pat)
|
||||
fs = lib.FcFontSetCreate()
|
||||
result = c_int(0)
|
||||
matches = []
|
||||
if sort:
|
||||
font_patterns = lib.FcFontSort(0, pat, FcFalse, 0, byref(result))
|
||||
if not font_patterns:
|
||||
raise RuntimeError('Allocation failed')
|
||||
fps = font_patterns.contents
|
||||
for j in range(fps.nfont):
|
||||
fpat = fps.fonts[j]
|
||||
fp = lib.FcFontRenderPrepare(0, pat, fpat)
|
||||
if fp:
|
||||
lib.FcFontSetAdd(fs, fp)
|
||||
lib.FcFontSetDestroy(font_patterns)
|
||||
else:
|
||||
match_pat = lib.FcFontMatch(0, pat, byref(result))
|
||||
if pat:
|
||||
lib.FcFontSetAdd(fs, match_pat)
|
||||
if result.value != FcResultMatch.value:
|
||||
lib.FcPatternDestroy(pat)
|
||||
return matches
|
||||
font_set = fs.contents
|
||||
|
||||
file = pointer(create_string_buffer(chr(0), 5000))
|
||||
family = pointer(create_string_buffer(chr(0), 200))
|
||||
weight = c_int(0)
|
||||
slant = c_int(0)
|
||||
for j in range(font_set.nfont):
|
||||
fpat = font_set.fonts[j]
|
||||
#lib.FcPatternPrint(fpat)
|
||||
if lib.FcPatternGetString(fpat, 'file', 0, byref(file)) != FcResultMatch.value:
|
||||
raise RuntimeError('Error processing pattern')
|
||||
if lib.FcPatternGetString(fpat, 'family', 0, byref(family)) != FcResultMatch.value:
|
||||
raise RuntimeError('Error processing pattern')
|
||||
if lib.FcPatternGetInteger(fpat, 'weight', 0, byref(weight)) != FcResultMatch.value:
|
||||
raise RuntimeError('Error processing pattern')
|
||||
if lib.FcPatternGetInteger(fpat, 'slant', 0, byref(slant)) != FcResultMatch.value:
|
||||
raise RuntimeError('Error processing pattern')
|
||||
|
||||
matches.append({
|
||||
'file' : file.contents.value,
|
||||
'family' : family.contents.value,
|
||||
'weight' : weight.value,
|
||||
'slant' : slant.value,
|
||||
}
|
||||
)
|
||||
|
||||
lib.FcPatternDestroy(pat)
|
||||
lib.FcFontSetDestroy(fs)
|
||||
return matches
|
||||
|
||||
def main(args=sys.argv):
|
||||
print find_font_families()
|
||||
if len(args) > 1:
|
||||
print
|
||||
print files_for_family(args[1])
|
||||
print
|
||||
print match(args[1], verbose=True)
|
||||
return 0
|
||||
|
||||
if __name__ == '__main__':
|
||||
sys.exit(main())
|
@ -46,6 +46,7 @@ BrandingText "${PRODUCT_NAME} created by Kovid Goyal"
|
||||
!define CLIT "C:\clit\clit.exe"
|
||||
!define PDFTOHTML "C:\pdftohtml\pdftohtml.exe"
|
||||
!define IMAGEMAGICK "C:\ImageMagick"
|
||||
!DEFINE FONTCONFIG "C:\fontconfig"
|
||||
|
||||
|
||||
; ---------------PATH manipulation -----------------------------------------------------------------
|
||||
@ -283,6 +284,7 @@ Section "Main" "secmain"
|
||||
File /r "${PY2EXE_DIR}\*"
|
||||
File "${CLIT}"
|
||||
File "${PDFTOHTML}"
|
||||
File /r "${FONTCONFIG}\*"
|
||||
|
||||
SetOutPath "$INSTDIR\ImageMagick"
|
||||
File /r "${IMAGEMAGICK}\*"
|
||||
|
Loading…
x
Reference in New Issue
Block a user