summaryrefslogtreecommitdiffstats
path: root/lib/silfont/scripts/psfsetglyphorder.py
diff options
context:
space:
mode:
Diffstat (limited to 'lib/silfont/scripts/psfsetglyphorder.py')
-rwxr-xr-xlib/silfont/scripts/psfsetglyphorder.py91
1 files changed, 91 insertions, 0 deletions
diff --git a/lib/silfont/scripts/psfsetglyphorder.py b/lib/silfont/scripts/psfsetglyphorder.py
new file mode 100755
index 0000000..e2448e7
--- /dev/null
+++ b/lib/silfont/scripts/psfsetglyphorder.py
@@ -0,0 +1,91 @@
+#!/usr/bin/env python
+__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__ = 'http://github.com/silnrsi/pysilfont'
+__copyright__ = 'Copyright (c) 2015 SIL International (http://www.sil.org)'
+__license__ = 'Released under the MIT License (http://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()