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/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)
@@ -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,5 @@
1
+ Wheel-Version: 1.0
2
+ Generator: setuptools (82.0.1)
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any
5
+
@@ -0,0 +1,5 @@
1
+ [console_scripts]
2
+ ttffamily = ttfquery.ttffamily:main
3
+ ttffiles = ttfquery.ttffiles:main
4
+ ttfgroups = ttfquery.ttfgroups:main
5
+ ttfmetadata = ttfquery.ttfmetadata:main
@@ -0,0 +1 @@
1
+ ttfquery