TTFQuery 2.0.1a1__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- ttfquery/__init__.py +2 -0
- ttfquery/_scriptregistry.py +16 -0
- ttfquery/describe.py +332 -0
- ttfquery/findsystem.py +142 -0
- ttfquery/glyph.py +194 -0
- ttfquery/glyphquery.py +90 -0
- ttfquery/guessdescription.py +135 -0
- ttfquery/scriptregistry.py +37 -0
- ttfquery/ttffamily.py +37 -0
- ttfquery/ttffiles.py +417 -0
- ttfquery/ttfgroups.py +50 -0
- ttfquery/ttfmetadata.py +41 -0
- ttfquery-2.0.1a1.dist-info/METADATA +83 -0
- ttfquery-2.0.1a1.dist-info/RECORD +17 -0
- ttfquery-2.0.1a1.dist-info/WHEEL +5 -0
- ttfquery-2.0.1a1.dist-info/entry_points.txt +5 -0
- ttfquery-2.0.1a1.dist-info/top_level.txt +1 -0
ttfquery/ttffiles.py
ADDED
|
@@ -0,0 +1,417 @@
|
|
|
1
|
+
"""Registry of available TrueType font files"""
|
|
2
|
+
from ttfquery import describe, findsystem
|
|
3
|
+
import traceback, os
|
|
4
|
+
try:
|
|
5
|
+
import cPickle as pickle
|
|
6
|
+
except ImportError:
|
|
7
|
+
import pickle
|
|
8
|
+
try:
|
|
9
|
+
unicode
|
|
10
|
+
except NameError:
|
|
11
|
+
unicode = str
|
|
12
|
+
import logging
|
|
13
|
+
log =logging.getLogger( __name__ )
|
|
14
|
+
from collections import namedtuple
|
|
15
|
+
|
|
16
|
+
class FontMetadata(namedtuple(
|
|
17
|
+
'FontMetadata',
|
|
18
|
+
(
|
|
19
|
+
'file_name',
|
|
20
|
+
'modifiers',
|
|
21
|
+
'specific_name',
|
|
22
|
+
'font_name',
|
|
23
|
+
'family',
|
|
24
|
+
),
|
|
25
|
+
)):
|
|
26
|
+
"""Stores specific font metadata
|
|
27
|
+
|
|
28
|
+
A specific font is basically an actual font-file,
|
|
29
|
+
that is, it is one of a family of fonts which make
|
|
30
|
+
up the various "modified" versions of a font face.
|
|
31
|
+
|
|
32
|
+
So `Ubuntu Light Italic` would be a specific font
|
|
33
|
+
that is a part of the font-face `Ubuntu` with the modifers
|
|
34
|
+
for `Light` and `Italic` applied.
|
|
35
|
+
|
|
36
|
+
* file_name -- fully specified absolute path
|
|
37
|
+
* modifiers -- (weightInteger, italicsFlag)
|
|
38
|
+
* specific_name -- specific name of the particular
|
|
39
|
+
font stored in the given file, the name of
|
|
40
|
+
the "modified" font
|
|
41
|
+
* font_name -- name of the general font which
|
|
42
|
+
the modifiers are specialising
|
|
43
|
+
* family -- family specifier, two-tuple of
|
|
44
|
+
high-level and sub-level font classifications
|
|
45
|
+
based on font characteristics as encoded
|
|
46
|
+
in the font file.
|
|
47
|
+
"""
|
|
48
|
+
__slots__ = ()
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
FILENAME, MODIFIERS, SPECIFICNAME, FONTNAME, FAMILY = range(5)
|
|
52
|
+
|
|
53
|
+
class Registry(object):
|
|
54
|
+
"""Object providing centralized registration of TTF files
|
|
55
|
+
|
|
56
|
+
Attributes:
|
|
57
|
+
|
|
58
|
+
families -- mapping from TrueType font families
|
|
59
|
+
to sub-families and then to general fonts
|
|
60
|
+
(as a set of font-names).
|
|
61
|
+
fonts -- mapping from general fonts to modifiers to
|
|
62
|
+
specific font instances
|
|
63
|
+
specificFonts -- mapping from specific font names
|
|
64
|
+
to the entire "metrics" set for the particular
|
|
65
|
+
font (a :class:`FontMetadata` namedtuple)
|
|
66
|
+
files -- mapping from (absolute) filenames to
|
|
67
|
+
specific font names
|
|
68
|
+
shortFiles -- mapping from font filename basenames
|
|
69
|
+
to font-file-lists
|
|
70
|
+
|
|
71
|
+
DIRTY -- flag indicating whether the registry has
|
|
72
|
+
had a new font registered (i.e. whether it should
|
|
73
|
+
be saved out to disk).
|
|
74
|
+
"""
|
|
75
|
+
DIRTY = 0
|
|
76
|
+
filename = ""
|
|
77
|
+
def __init__(self):
|
|
78
|
+
"""Initialize the Registry"""
|
|
79
|
+
self.families = {}
|
|
80
|
+
self.fonts = {}
|
|
81
|
+
self.specificFonts = {}
|
|
82
|
+
self.files = {}
|
|
83
|
+
self.shortFiles = {}
|
|
84
|
+
def clear( self ):
|
|
85
|
+
"""Clear out the all tables and mark unchanged"""
|
|
86
|
+
self.families.clear()
|
|
87
|
+
self.fonts.clear()
|
|
88
|
+
self.specificFonts.clear()
|
|
89
|
+
self.files.clear()
|
|
90
|
+
self.shortFiles.clear()
|
|
91
|
+
self.dirty(0)
|
|
92
|
+
def dirty(self, dirty = 1):
|
|
93
|
+
"""Mark the registry as changed/unchanged"""
|
|
94
|
+
self.DIRTY = dirty
|
|
95
|
+
|
|
96
|
+
def metadata(
|
|
97
|
+
self,
|
|
98
|
+
filename,
|
|
99
|
+
force = 0
|
|
100
|
+
):
|
|
101
|
+
"""Retrieve metadata from font file
|
|
102
|
+
|
|
103
|
+
:param filename: fully specified path to the font file
|
|
104
|
+
:param force: if false, and the metadata is already
|
|
105
|
+
available for this file, do not access the
|
|
106
|
+
font file to retrieve, just return the existing
|
|
107
|
+
metadata.
|
|
108
|
+
|
|
109
|
+
:rtype: :class:`FontMetadata`
|
|
110
|
+
"""
|
|
111
|
+
filename = os.path.abspath( filename )
|
|
112
|
+
if filename in self.files and not force:
|
|
113
|
+
return self.specificFonts.get( self.files[filename] )
|
|
114
|
+
font = describe.openFont(filename)
|
|
115
|
+
if 'glyf' not in font:
|
|
116
|
+
# CFF / OpenType-CFF fonts have no 'glyf' table; ttfquery's glyph
|
|
117
|
+
# outline extraction is TrueType-only, so exclude them rather than
|
|
118
|
+
# crash later when their outlines are requested.
|
|
119
|
+
raise ValueError(
|
|
120
|
+
"Unsupported font (no 'glyf' table, likely CFF/OpenType): %s" % (
|
|
121
|
+
filename,
|
|
122
|
+
)
|
|
123
|
+
)
|
|
124
|
+
try:
|
|
125
|
+
modifiers = describe.modifiers( font )
|
|
126
|
+
except (KeyError,AttributeError):
|
|
127
|
+
modifiers = (None,None)
|
|
128
|
+
specificName, fontName = describe.shortName( font )
|
|
129
|
+
specifier = describe.family(font)
|
|
130
|
+
result = (
|
|
131
|
+
filename,
|
|
132
|
+
modifiers,
|
|
133
|
+
specificName,
|
|
134
|
+
fontName,
|
|
135
|
+
specifier,
|
|
136
|
+
)
|
|
137
|
+
return FontMetadata(*[
|
|
138
|
+
(x.decode('utf-8') if isinstance(x,bytes) else x)
|
|
139
|
+
for x in result
|
|
140
|
+
])
|
|
141
|
+
def register(
|
|
142
|
+
self,
|
|
143
|
+
filename,
|
|
144
|
+
modifiers = None,
|
|
145
|
+
specificName = None,
|
|
146
|
+
fontName = None,
|
|
147
|
+
familySpecifier = None,
|
|
148
|
+
force = 0,
|
|
149
|
+
):
|
|
150
|
+
"""Do the actual registration of a filename & metadata
|
|
151
|
+
|
|
152
|
+
See metadata function for description of the various
|
|
153
|
+
arguments. If modifiers == None then the metadata function
|
|
154
|
+
will be used to scan for the metadata.
|
|
155
|
+
|
|
156
|
+
force -- if true, force re-reading font-file even if we already
|
|
157
|
+
have the meta-data for the file loaded.
|
|
158
|
+
"""
|
|
159
|
+
filename = os.path.abspath( filename )
|
|
160
|
+
if filename in self.files and not force:
|
|
161
|
+
return self.specificFonts.get( self.files[filename] )
|
|
162
|
+
self.dirty(1)
|
|
163
|
+
if modifiers == None:
|
|
164
|
+
(filename, modifiers, specificName, fontName, familySpecifier) = self.metadata(filename, force = force)
|
|
165
|
+
description = FontMetadata(filename, modifiers, specificName, fontName, familySpecifier)
|
|
166
|
+
try:
|
|
167
|
+
self.files[filename] = specificName
|
|
168
|
+
major,minor = familySpecifier
|
|
169
|
+
self.families.setdefault(major,{}).setdefault(minor,{})[fontName] = 1
|
|
170
|
+
self.fonts.setdefault(fontName, {}).setdefault(modifiers,[]).append(specificName)
|
|
171
|
+
self.specificFonts[ specificName ] = description
|
|
172
|
+
self.shortFiles.setdefault(os.path.basename(filename), []).append( filename )
|
|
173
|
+
except Exception:
|
|
174
|
+
if filename in self.files:
|
|
175
|
+
del self.files[filename]
|
|
176
|
+
raise
|
|
177
|
+
return description
|
|
178
|
+
|
|
179
|
+
def familyMembers( self, major, minor=None ):
|
|
180
|
+
"""Get all (general) fonts for a given family
|
|
181
|
+
|
|
182
|
+
:param major: string description of major family
|
|
183
|
+
:param minor: optional string description of minor family
|
|
184
|
+
|
|
185
|
+
:rtype: list of font faces in the family
|
|
186
|
+
"""
|
|
187
|
+
major = major.upper()
|
|
188
|
+
if not minor:
|
|
189
|
+
result = []
|
|
190
|
+
for key,set in self.families.get(major,{}).items():
|
|
191
|
+
result.extend( set.keys())
|
|
192
|
+
return result
|
|
193
|
+
minor = minor.upper()
|
|
194
|
+
return list(self.families.get( major, {}).get(minor,{}).keys())
|
|
195
|
+
def fontMembers( self, fontName, weight=None, italics=None ):
|
|
196
|
+
"""Get specific font names for given generic font name
|
|
197
|
+
|
|
198
|
+
:param fontName: general font name to search
|
|
199
|
+
:param weight: if given, only return specific fonts with that weight
|
|
200
|
+
:param italics: if given, only return fonts with italics value equal
|
|
201
|
+
|
|
202
|
+
:rtype: list of specific font names
|
|
203
|
+
"""
|
|
204
|
+
table = self.fonts.get( fontName, {})
|
|
205
|
+
items = list(table.items())
|
|
206
|
+
items.sort()
|
|
207
|
+
if weight is not None:
|
|
208
|
+
weight = describe.weightNumber( weight )
|
|
209
|
+
items = [item for item in items if item[0][0]==weight]
|
|
210
|
+
if italics is not None:
|
|
211
|
+
items = [item for item in items if item[0][1]==italics]
|
|
212
|
+
result = []
|
|
213
|
+
for item in items:
|
|
214
|
+
result.extend( item[1])
|
|
215
|
+
return result
|
|
216
|
+
def fontForms( self, fontName ):
|
|
217
|
+
"""Retrieve the set of font-forms (weight,italics) available in a font
|
|
218
|
+
|
|
219
|
+
:param fontName: general font name to search
|
|
220
|
+
:rtype: list of two-tuples of (weight,italics) available in the font
|
|
221
|
+
"""
|
|
222
|
+
return list(self.fonts.get( fontName, {}).keys())
|
|
223
|
+
|
|
224
|
+
def fontFile( self, specificName ):
|
|
225
|
+
"""Return the absolute path-name for a given specific font
|
|
226
|
+
|
|
227
|
+
:param specificName: specific font name to search
|
|
228
|
+
:rtype: str(file_name) of the FontMetadata instance
|
|
229
|
+
"""
|
|
230
|
+
description = self.specificFonts.get( specificName )
|
|
231
|
+
if description:
|
|
232
|
+
return description[0]
|
|
233
|
+
else:
|
|
234
|
+
raise KeyError( """Couldn't find font with specificName %r, can't retrieve filename for it"""%( specificName,))
|
|
235
|
+
|
|
236
|
+
def matchName( self, name, single=0 ):
|
|
237
|
+
"""Try to find a general font based on a name
|
|
238
|
+
|
|
239
|
+
:param name: name to use to try to find the font, can match on any of
|
|
240
|
+
specific name, major family, or minor family
|
|
241
|
+
:param single: return the first match only (not a dictionary of results)
|
|
242
|
+
|
|
243
|
+
:rtype: if single str(fontName) else {fontName:1,...}
|
|
244
|
+
"""
|
|
245
|
+
if isinstance(name,bytes):
|
|
246
|
+
try:
|
|
247
|
+
name = name.decode('utf-8')
|
|
248
|
+
except Exception:
|
|
249
|
+
# suppose we should use something else here...
|
|
250
|
+
name = name.decode('latin-1')
|
|
251
|
+
result = {}
|
|
252
|
+
if name in self.fonts:
|
|
253
|
+
v = name
|
|
254
|
+
if single:
|
|
255
|
+
return v
|
|
256
|
+
else:
|
|
257
|
+
result[v] = 1
|
|
258
|
+
if name in self.specificFonts:
|
|
259
|
+
v = self.specificFonts[name][FONTNAME]
|
|
260
|
+
if single:
|
|
261
|
+
return v
|
|
262
|
+
else:
|
|
263
|
+
result[v] = 1
|
|
264
|
+
if name.upper() in self.families:
|
|
265
|
+
for general in self.familyMembers( name ):
|
|
266
|
+
if single:
|
|
267
|
+
return general
|
|
268
|
+
result[general] = 1
|
|
269
|
+
testname = name.lower()
|
|
270
|
+
for specific in self.specificFonts.keys():
|
|
271
|
+
if specific.lower().find( testname ) > -1:
|
|
272
|
+
if single:
|
|
273
|
+
return specific
|
|
274
|
+
result[ self.specificFonts[specific][FONTNAME]]=1
|
|
275
|
+
for majorFamily in self.families.keys():
|
|
276
|
+
if majorFamily.lower().find( testname ) > -1:
|
|
277
|
+
for item in self.familyMembers( majorFamily ):
|
|
278
|
+
if single:
|
|
279
|
+
return item
|
|
280
|
+
result[item] = 1
|
|
281
|
+
else:
|
|
282
|
+
# if previous was true, we already included everything
|
|
283
|
+
# that could be included here...
|
|
284
|
+
for minorFamily in self.families[majorFamily].keys():
|
|
285
|
+
if minorFamily.lower().find( testname ) > -1:
|
|
286
|
+
for item in self.familyMembers( majorFamily, minorFamily ):
|
|
287
|
+
if single:
|
|
288
|
+
return item
|
|
289
|
+
result[item] = 1
|
|
290
|
+
if not result:
|
|
291
|
+
raise KeyError( """Couldn't find a font with name %r"""%(name,))
|
|
292
|
+
return list(result.keys())
|
|
293
|
+
|
|
294
|
+
def save( self, file=None, force=0 ):
|
|
295
|
+
"""Attempt to save the font metadata to a pickled file
|
|
296
|
+
|
|
297
|
+
file -- a file open in binary write mode or a filename
|
|
298
|
+
force -- if not true and DIRTY false, then don't actually
|
|
299
|
+
save anything
|
|
300
|
+
|
|
301
|
+
returns number of records saved
|
|
302
|
+
"""
|
|
303
|
+
if not force and not self.DIRTY:
|
|
304
|
+
return 0
|
|
305
|
+
file = file or self.filename
|
|
306
|
+
if not file:
|
|
307
|
+
raise TypeError( """Attempted to save %r to default file, no default file specified"""% (self,))
|
|
308
|
+
if not hasattr( file, 'write'):
|
|
309
|
+
file = open( file, 'wb' )
|
|
310
|
+
pickle.dump( list(self.specificFonts.values()), file, 1 )
|
|
311
|
+
self.dirty(0)
|
|
312
|
+
return len(self.specificFonts)
|
|
313
|
+
def load( self, file, clearFirst=1 ):
|
|
314
|
+
"""Attempt to load the font metadata from a pickled file
|
|
315
|
+
|
|
316
|
+
file -- a file open in binary read mode or a filename
|
|
317
|
+
clearFirst -- if true, clear tables first, and reset DIRTY
|
|
318
|
+
to 0 after finished
|
|
319
|
+
"""
|
|
320
|
+
if clearFirst:
|
|
321
|
+
self.clear()
|
|
322
|
+
if not hasattr( file, 'read'):
|
|
323
|
+
self.filename = file
|
|
324
|
+
file = open( file, 'rb' )
|
|
325
|
+
table = pickle.load( file )
|
|
326
|
+
for filename, modifiers, specificName, fontName, familySpecifier in table:
|
|
327
|
+
## Minimal sanity check...
|
|
328
|
+
if os.path.isfile( filename ):
|
|
329
|
+
self.register(filename, modifiers, specificName, fontName, familySpecifier)
|
|
330
|
+
if clearFirst:
|
|
331
|
+
self.dirty(0)
|
|
332
|
+
return len(table)
|
|
333
|
+
|
|
334
|
+
def scan( self, paths=None, printErrors=0, force = 0 ):
|
|
335
|
+
"""Scan the given paths registering each found font"""
|
|
336
|
+
new, failed = [],[]
|
|
337
|
+
for filename in findsystem.findFonts(paths):
|
|
338
|
+
try:
|
|
339
|
+
self.register( filename, force = force )
|
|
340
|
+
except Exception:
|
|
341
|
+
log.info( 'Failure scanning %s', filename )
|
|
342
|
+
if printErrors:
|
|
343
|
+
log.warn( "%s", traceback.format_exc())
|
|
344
|
+
failed.append( filename )
|
|
345
|
+
else:
|
|
346
|
+
new.append( filename )
|
|
347
|
+
return new, failed
|
|
348
|
+
|
|
349
|
+
def load( *arguments, **named ):
|
|
350
|
+
"""Construct registry from saved file
|
|
351
|
+
|
|
352
|
+
Assembly creates a Registry object and calls the
|
|
353
|
+
load method with the file as argument.
|
|
354
|
+
"""
|
|
355
|
+
registry = Registry()
|
|
356
|
+
registry.load( *arguments, **named )
|
|
357
|
+
return registry
|
|
358
|
+
|
|
359
|
+
def get_options():
|
|
360
|
+
"""Creation base options for creating a ttfquery registry"""
|
|
361
|
+
import argparse
|
|
362
|
+
from ttfquery import scriptregistry
|
|
363
|
+
parser = argparse.ArgumentParser(description="Create or update font metadata cache")
|
|
364
|
+
parser.add_argument(
|
|
365
|
+
'-r','--registry',
|
|
366
|
+
help="The registry file to update, defaults to %s"%(scriptregistry.registryFile),
|
|
367
|
+
default=scriptregistry.registryFile,
|
|
368
|
+
)
|
|
369
|
+
parser.add_argument(
|
|
370
|
+
'-s','--scan',
|
|
371
|
+
help='If specified, then force a scan even if the registry already exists (otherwise only scan if new)',
|
|
372
|
+
default=False,
|
|
373
|
+
action='store_true',
|
|
374
|
+
)
|
|
375
|
+
parser.add_argument(
|
|
376
|
+
'--directories',
|
|
377
|
+
nargs='*',
|
|
378
|
+
help='Directory (directories) to scan for font metadata, default is system font directories',
|
|
379
|
+
)
|
|
380
|
+
return parser
|
|
381
|
+
|
|
382
|
+
|
|
383
|
+
def main():
|
|
384
|
+
import logging
|
|
385
|
+
logging.basicConfig(level=logging.INFO)
|
|
386
|
+
options = get_options().parse_args()
|
|
387
|
+
registry = registry_for_options(options)
|
|
388
|
+
return 0
|
|
389
|
+
|
|
390
|
+
def registry_for_options(options):
|
|
391
|
+
"""Given options as in :func:`get_options` initialize registry"""
|
|
392
|
+
if options.registry and os.path.exists(options.registry):
|
|
393
|
+
registry = load(options.registry)
|
|
394
|
+
new = False
|
|
395
|
+
else:
|
|
396
|
+
registry = Registry()
|
|
397
|
+
new = True
|
|
398
|
+
scan = new
|
|
399
|
+
if getattr(options,'scan',False):
|
|
400
|
+
log.info("Forcing rescan of directories")
|
|
401
|
+
scan = True
|
|
402
|
+
if scan:
|
|
403
|
+
new,failed = registry.scan(
|
|
404
|
+
options.directories or None,
|
|
405
|
+
printErrors = False,
|
|
406
|
+
force = 1
|
|
407
|
+
)
|
|
408
|
+
if options.registry and registry.DIRTY:
|
|
409
|
+
registry.save(options.registry)
|
|
410
|
+
else:
|
|
411
|
+
log.info("Registry already populated")
|
|
412
|
+
log.info( '%s fonts available', len(registry.fonts) )
|
|
413
|
+
return registry
|
|
414
|
+
|
|
415
|
+
|
|
416
|
+
if __name__ == "__main__":
|
|
417
|
+
main()
|
ttfquery/ttfgroups.py
ADDED
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
"""Demo script to print ordered set of system fonts"""
|
|
2
|
+
from __future__ import print_function
|
|
3
|
+
from ttfquery import describe, ttffiles
|
|
4
|
+
import sys, logging
|
|
5
|
+
log = logging.getLogger( __name__ )
|
|
6
|
+
|
|
7
|
+
def buildTable( registry ):
|
|
8
|
+
"""Build table mapping {family:(font:{modifiers:(name,file)})}
|
|
9
|
+
|
|
10
|
+
filenames -- if provided, list of filenames to scan,
|
|
11
|
+
otherwise the full set of system fonts provided
|
|
12
|
+
by findsystem will be used.
|
|
13
|
+
"""
|
|
14
|
+
table = {}
|
|
15
|
+
for major, minors in registry.families.items():
|
|
16
|
+
for minor, fonts in minors.items():
|
|
17
|
+
for fontname in fonts.keys():
|
|
18
|
+
table.setdefault(major,{}).setdefault(fontname, {})
|
|
19
|
+
font = registry.fonts.get(fontname)
|
|
20
|
+
if font:
|
|
21
|
+
for modifier,specifics in sorted(font.items()):
|
|
22
|
+
for specific in specifics:
|
|
23
|
+
specificfont = registry.specificFonts[specific]
|
|
24
|
+
table[major][fontname][modifier] = (
|
|
25
|
+
specificfont.font_name,
|
|
26
|
+
specificfont.file_name
|
|
27
|
+
)
|
|
28
|
+
break
|
|
29
|
+
return table
|
|
30
|
+
|
|
31
|
+
def get_options():
|
|
32
|
+
base = ttffiles.get_options()
|
|
33
|
+
base.description = '''Display all of the major font-groups on the system'''
|
|
34
|
+
return base
|
|
35
|
+
|
|
36
|
+
def main():
|
|
37
|
+
options = get_options().parse_args()
|
|
38
|
+
table = buildTable(registry=ttffiles.registry_for_options(options))
|
|
39
|
+
run_report(table)
|
|
40
|
+
|
|
41
|
+
def run_report(table):
|
|
42
|
+
keys = sorted(table.keys())
|
|
43
|
+
for fam in keys:
|
|
44
|
+
print('_________________________')
|
|
45
|
+
print(fam)
|
|
46
|
+
fnts = sorted( table[fam].items() )
|
|
47
|
+
for fnt,modset in fnts:
|
|
48
|
+
mods = sorted(modset.keys())
|
|
49
|
+
mods = ",".join([ '%s%s'%( w, ['','(I)'][i&1]) for (w,i) in mods])
|
|
50
|
+
print(' ',fnt.ljust(32), '--', mods)
|
ttfquery/ttfmetadata.py
ADDED
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
#!/usr/bin/env python
|
|
2
|
+
"""Query for meta-data for a given font"""
|
|
3
|
+
from __future__ import print_function
|
|
4
|
+
#from ttfquery import describe
|
|
5
|
+
from ttfquery import ttffiles
|
|
6
|
+
import sys, logging
|
|
7
|
+
|
|
8
|
+
def printMetaData( metadata ):
|
|
9
|
+
print(' Specific Name:', metadata.specific_name)
|
|
10
|
+
print(' File:', metadata.file_name)
|
|
11
|
+
print(' Modifiers:', metadata.modifiers)
|
|
12
|
+
print(' Family Name:', ", ".join(metadata.family))
|
|
13
|
+
|
|
14
|
+
def get_options():
|
|
15
|
+
base = ttffiles.get_options()
|
|
16
|
+
base.description = 'Query/search for metadata for the given name'
|
|
17
|
+
base.add_argument(
|
|
18
|
+
'name',
|
|
19
|
+
help="The font name, family or fragment for which to search",
|
|
20
|
+
)
|
|
21
|
+
return base
|
|
22
|
+
|
|
23
|
+
def main():
|
|
24
|
+
logging.basicConfig(level=logging.INFO)
|
|
25
|
+
options = get_options().parse_args()
|
|
26
|
+
registry = ttffiles.registry_for_options( options )
|
|
27
|
+
find_match(options.name,registry)
|
|
28
|
+
|
|
29
|
+
def find_match(name, registry):
|
|
30
|
+
fontNames = registry.matchName( name )
|
|
31
|
+
fontNames.sort()
|
|
32
|
+
for general in fontNames:
|
|
33
|
+
print('Font:', general)
|
|
34
|
+
specifics = registry.fontMembers( general )
|
|
35
|
+
specifics.sort()
|
|
36
|
+
for specific in specifics:
|
|
37
|
+
printMetaData( registry.metadata( registry.fontFile(specific) ))
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
if __name__ == "__main__":
|
|
41
|
+
main()
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: TTFQuery
|
|
3
|
+
Version: 2.0.1a1
|
|
4
|
+
Summary: FontTools-based package for querying system fonts
|
|
5
|
+
Home-page: http://ttfquery.sourceforge.net/
|
|
6
|
+
Author: Mike C. Fletcher
|
|
7
|
+
Author-email: "Mike C. Fletcher" <mcfletch@users.sourceforge.net>
|
|
8
|
+
License: THIS SOFTWARE IS NOT FAULT TOLERANT AND SHOULD NOT BE USED IN ANY
|
|
9
|
+
SITUATION ENDANGERING HUMAN LIFE OR PROPERTY.
|
|
10
|
+
|
|
11
|
+
TTFQuery License
|
|
12
|
+
|
|
13
|
+
Copyright (c) 2003-2018, Michael C. Fletcher and Contributors
|
|
14
|
+
All rights reserved.
|
|
15
|
+
|
|
16
|
+
Redistribution and use in source and binary forms, with or without
|
|
17
|
+
modification, are permitted provided that the following conditions
|
|
18
|
+
are met:
|
|
19
|
+
|
|
20
|
+
Redistributions of source code must retain the above copyright
|
|
21
|
+
notice, this list of conditions and the following disclaimer.
|
|
22
|
+
|
|
23
|
+
Redistributions in binary form must reproduce the above
|
|
24
|
+
copyright notice, this list of conditions and the following
|
|
25
|
+
disclaimer in the documentation and/or other materials
|
|
26
|
+
provided with the distribution.
|
|
27
|
+
|
|
28
|
+
The name of Michael C. Fletcher, or the name of any Contributor,
|
|
29
|
+
may not be used to endorse or promote products derived from this
|
|
30
|
+
software without specific prior written permission.
|
|
31
|
+
|
|
32
|
+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
|
33
|
+
``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
|
34
|
+
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
|
35
|
+
FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
|
36
|
+
COPYRIGHT HOLDERS AND CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
|
|
37
|
+
INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
|
38
|
+
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
|
39
|
+
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
|
40
|
+
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
|
41
|
+
STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
|
42
|
+
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
|
|
43
|
+
OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
Project-URL: Homepage, http://ttfquery.sourceforge.net/
|
|
47
|
+
Keywords: fonttools,ttf,truetype,outline,font,curve,system fonts
|
|
48
|
+
Platform: Any
|
|
49
|
+
Classifier: Programming Language :: Python
|
|
50
|
+
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
51
|
+
Classifier: Intended Audience :: Developers
|
|
52
|
+
Classifier: Operating System :: OS Independent
|
|
53
|
+
Classifier: Topic :: Multimedia :: Graphics
|
|
54
|
+
Requires-Python: >=3.7
|
|
55
|
+
Description-Content-Type: text/markdown
|
|
56
|
+
Requires-Dist: fonttools
|
|
57
|
+
Requires-Dist: numpy
|
|
58
|
+
Provides-Extra: test
|
|
59
|
+
Requires-Dist: pytest; extra == "test"
|
|
60
|
+
Requires-Dist: pytest-cov; extra == "test"
|
|
61
|
+
Dynamic: author
|
|
62
|
+
Dynamic: home-page
|
|
63
|
+
Dynamic: platform
|
|
64
|
+
|
|
65
|
+
# TTFQuery
|
|
66
|
+
|
|
67
|
+
FontTools-based package for querying system fonts
|
|
68
|
+
|
|
69
|
+
TTFQuery builds on the FontTools package to allow the Python programmer to accomplish a number of tasks:
|
|
70
|
+
|
|
71
|
+
* query the system to find installed fonts
|
|
72
|
+
* retrieve metadata about any TTF font file (even those not yet installed)
|
|
73
|
+
* abstract family type
|
|
74
|
+
* proper font name
|
|
75
|
+
* glyph outlines
|
|
76
|
+
* build simple metadata registries for run-time font matching
|
|
77
|
+
|
|
78
|
+
With these functionalities, it is possible to readily create OpenGL solid-text
|
|
79
|
+
rendering libraries which can accept abstract font-family names as font
|
|
80
|
+
specifiers and deliver platform-specific TTF files to match those libraries.
|
|
81
|
+
|
|
82
|
+
TTFQuery doesn't provide rendering services, but a sample implementation can be
|
|
83
|
+
found in the OpenGLContext project, from which TTFQuery was refactored.
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
ttfquery/__init__.py,sha256=Ot6vTc2lfNk26JCZKXRhVvP-8d4kKqCDODXB3uCYbvY,86
|
|
2
|
+
ttfquery/_scriptregistry.py,sha256=7pgYLg2IqWwbQWFlt-TpgV0w8_pBtuiGQgXsiuoqdJY,657
|
|
3
|
+
ttfquery/describe.py,sha256=vnT0SYf1w4FIkN5OR_3LTgedWGWjgCJcFMGgPfj19MY,9285
|
|
4
|
+
ttfquery/findsystem.py,sha256=ypv-N8A60bvrstwxFmVrigE4mVYVj47-SYAatNoRdu8,4818
|
|
5
|
+
ttfquery/glyph.py,sha256=mDZ65UjTIdbDdoo4s6tGXuoBZOthHn_qiQ4wKh2E-kw,7783
|
|
6
|
+
ttfquery/glyphquery.py,sha256=Q5j_Ag3LMXuUUHwhX1Z34Dwg27rUEvuWw7BbpcRwdHA,3146
|
|
7
|
+
ttfquery/guessdescription.py,sha256=CJSr35za89Brv5_VQkPVozaWDd3tWVHX7ToGz8ML39I,3824
|
|
8
|
+
ttfquery/scriptregistry.py,sha256=EgMfzynQK4JhMuEml94w4UXp9BfQPSQYU9hBLL8eS-o,1456
|
|
9
|
+
ttfquery/ttffamily.py,sha256=6N8LCkU5LrBdkmVyAMXGHjte2IAHH6IKvTzgRMfgvtw,1173
|
|
10
|
+
ttfquery/ttffiles.py,sha256=KewT2Aboi9QfdWuCb2WacyCVvXUDG7deoFDu72JWNTc,14962
|
|
11
|
+
ttfquery/ttfgroups.py,sha256=giPGXyMUQV28x-qDwwWnlzqEqGyZLU37Sb2ExrnATuE,1870
|
|
12
|
+
ttfquery/ttfmetadata.py,sha256=_l9D6LRZO7VtKg7Kif3t8i_3G-rUASuqevXvolhqiNw,1264
|
|
13
|
+
ttfquery-2.0.1a1.dist-info/METADATA,sha256=sQWLXeRPSf1gSww-zKulAYGUvSQmYsgTKhrpchQSTX8,3683
|
|
14
|
+
ttfquery-2.0.1a1.dist-info/WHEEL,sha256=aeYiig01lYGDzBgS8HxWXOg3uV61G9ijOsup-k9o1sk,91
|
|
15
|
+
ttfquery-2.0.1a1.dist-info/entry_points.txt,sha256=y_N3c0kBxCTgisPoLgHRNuxyY020TjINqYBfzqm4LMQ,164
|
|
16
|
+
ttfquery-2.0.1a1.dist-info/top_level.txt,sha256=iw10UTGA4lWDMqmu_ZscW0fD1Hqlqmt_a3dy8F07KOA,9
|
|
17
|
+
ttfquery-2.0.1a1.dist-info/RECORD,,
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
ttfquery
|