1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
|
#!/usr/bin/env python3
__doc__ = '''Load glyph order data into public.glyphOrder in lib.plist based on based on a text file in one of two formats:
- simple text file with one glyph name per line
- csv file with headers, using headers "glyph_name" and "sort_final" where the latter contains
numeric values used to sort the glyph names by'''
__url__ = 'https://github.com/silnrsi/pysilfont'
__copyright__ = 'Copyright (c) 2015 SIL International (https://www.sil.org)'
__license__ = 'Released under the MIT License (https://opensource.org/licenses/MIT)'
__author__ = 'David Raymond'
from silfont.core import execute
from xml.etree import ElementTree as ET
argspec = [
('ifont', {'help': 'Input font file'}, {'type': 'infont'}),
('ofont', {'help': 'Output font file', 'nargs': '?'}, {'type': 'outfont'}),
('--gname', {'help': 'Column header for glyph name', 'default': 'glyph_name'}, {}),
('--header', {'help': 'Column header(s) for sort order', 'default': 'sort_final'}, {}),
('--field', {'help': 'Field(s) in lib.plist to update', 'default': 'public.glyphOrder'}, {}),
('-i', '--input', {'help': 'Input text file, one glyphname per line'}, {'type': 'incsv', 'def': 'glyph_data.csv'}),
('-x', '--removemissing', {'help': 'Remove from list if glyph not in font', 'action': 'store_true', 'default': False}, {}),
('-l', '--log', {'help': 'Log file'}, {'type': 'outfile', 'def': '_gorder.log'})]
def doit(args):
font = args.ifont
incsv = args.input
logger = args.logger
removemissing = args.removemissing
fields = args.field.split(",")
fieldcount = len(fields)
headers = args.header.split(",")
if fieldcount != len(headers): logger.log("Must specify same number of values in --field and --header", "S")
gname = args.gname
# Identify file format from first line then create glyphdata[] with glyph name then one column per header
glyphdata = {}
fl = incsv.firstline
if fl is None: logger.log("Empty input file", "S")
numfields = len(fl)
incsv.numfields = numfields
fieldpos = []
if numfields > 1: # More than 1 column, so must have headers
if gname in fl:
glyphnpos = fl.index(gname)
else:
logger.log("No" + gname + "field in csv headers", "S")
for header in headers:
if header in fl:
pos = fl.index(header)
fieldpos.append(pos)
else:
logger.log('No "' + header + '" heading in csv headers"', "S")
next(incsv.reader, None) # Skip first line with headers in
for line in incsv:
glyphn = line[glyphnpos]
if len(glyphn) == 0:
continue # No need to include cases where name is blank
glyphdata[glyphn]=[]
for pos in fieldpos: glyphdata[glyphn].append(float(line[pos]))
elif numfields == 1: # Simple text file. Create glyphdata in same format as for csv files
for i, line in enumerate(incsv): glyphdata[line[0]]=(i,)
else:
logger.log("Invalid csv file", "S")
# Now process the data
if "lib" not in font.__dict__: font.addfile("lib")
glyphlist = list(font.deflayer.keys())
for i in range(0,fieldcount):
array = ET.Element("array")
for glyphn, vals in sorted(glyphdata.items(), key=lambda item: item[1][i]):
if glyphn in glyphlist:
sub = ET.SubElement(array, "string")
sub.text = glyphn
else:
font.logger.log("No glyph in font for " + glyphn, "I")
if not removemissing:
sub = ET.SubElement(array, "string")
sub.text = glyphn
font.lib.setelem(fields[i-1],array)
for glyphn in sorted(glyphlist): # Remaining glyphs were not in the input file
if glyphn not in glyphdata: font.logger.log("No entry in input file for font glyph " + glyphn, "I")
return font
def cmd(): execute("UFO", doit, argspec)
if __name__ == "__main__": cmd()
|