summaryrefslogtreecommitdiffstats
path: root/lib/silfont/scripts/psfsetglyphorder.py
blob: e2448e7a3428d8bc5e0ce74b88c9675072c544bb (plain)
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 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()