summaryrefslogtreecommitdiffstats
path: root/lib/silfont/scripts/psfufo2ttf.py
blob: 832ef882f46a9a1895fefe812db8db18e0003fba (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
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
#!/usr/bin/env python
__doc__ = 'Generate a ttf file without OpenType tables from a UFO'
__url__ = 'http://github.com/silnrsi/pysilfont'
__copyright__ = 'Copyright (c) 2017 SIL International  (http://www.sil.org)'
__license__ = 'Released under the MIT License (http://opensource.org/licenses/MIT)'
__author__ = 'Alan Ward'

# Compared to fontmake it does not decompose glyphs or remove overlaps 
# and curve conversion seems to happen in a different way.

from silfont.core import execute
import defcon, ufo2ft.outlineCompiler, ufo2ft.preProcessor, ufo2ft.filters

argspec = [
    ('iufo', {'help': 'Input UFO folder'}, {}),
    ('ottf', {'help': 'Output ttf file name'}, {}),
    ('--removeOverlaps', {'help': 'Merge overlapping contours', 'action': 'store_true'}, {}),
    ('--decomposeComponents', {'help': 'Decompose componenets', 'action': 'store_true'}, {}),
    ('-l', '--log', {'help': 'Optional log file'}, {'type': 'outfile', 'def': '_ufo2ttf.log', 'optlog': True})]

PUBLIC_PREFIX = 'public.'

def doit(args):
    ufo = defcon.Font(args.iufo)

    # if style is Regular and there are no openTypeNameRecords defining the full name (ID=4), then
    # add one so that "Regular" is omitted from the fullname
    if ufo.info.styleName == 'Regular':
        if ufo.info.openTypeNameRecords is None:
            ufo.info.openTypeNameRecords = []
        fullNameRecords = [ nr for nr in ufo.info.openTypeNameRecords if nr['nameID'] == 4]
        if not len(fullNameRecords):
            ufo.info.openTypeNameRecords.append( { 'nameID': 4, 'platformID': 3, 'encodingID': 1, 'languageID': 1033, 'string': ufo.info.familyName } )

#    args.logger.log('Converting UFO to ttf and compiling fea')
#    font = ufo2ft.compileTTF(ufo,
#        glyphOrder = ufo.lib.get(PUBLIC_PREFIX + 'glyphOrder'),
#        useProductionNames = False)

    args.logger.log('Converting UFO to ttf without OT', 'P')

    # default arg value for TTFPreProcessor class: removeOverlaps = False, convertCubics = True
    preProcessor = ufo2ft.preProcessor.TTFPreProcessor(ufo, removeOverlaps = args.removeOverlaps, convertCubics=True,
                                                       flattenComponents = True,
                                                       skipExportGlyphs = ufo.lib.get("public.skipExportGlyphs", []))

    # Need to handle cases if filters that are used are set in com.github.googlei18n.ufo2ft.filters with lib.plist
    dc = dtc = ftpos = None
    for (i,filter) in enumerate(preProcessor.preFilters):
        if isinstance(filter, ufo2ft.filters.decomposeComponents.DecomposeComponentsFilter):
            dc = True
        if isinstance(filter, ufo2ft.filters.decomposeTransformedComponents.DecomposeTransformedComponentsFilter):
            dtc = True
        if isinstance(filter, ufo2ft.filters.flattenComponents.FlattenComponentsFilter):
            ftpos = i
    # Add decomposeComponents if --decomposeComponents is used
    if args.decomposeComponents and not dc: preProcessor.preFilters.append(
        ufo2ft.filters.decomposeComponents.DecomposeComponentsFilter())
    # Add decomposeTransformedComponents if not already set via lib.plist
    if not dtc: preProcessor.preFilters.append(ufo2ft.filters.decomposeTransformedComponents.DecomposeTransformedComponentsFilter())
    # Remove flattenComponents if set via lib.plist since we set it via flattenComponents = True when setting up the preprocessor
    if ftpos: preProcessor.preFilters.pop(ftpos)

    glyphSet = preProcessor.process()
    outlineCompiler = ufo2ft.outlineCompiler.OutlineTTFCompiler(ufo,
        glyphSet=glyphSet,
        glyphOrder=ufo.lib.get(PUBLIC_PREFIX + 'glyphOrder'))
    font = outlineCompiler.compile()

    # handle uvs glyphs until ufo2ft does it for us.
    uvsdict = getuvss(ufo)
    if len(uvsdict):
        from fontTools.ttLib.tables._c_m_a_p import cmap_format_14
        cmap_uvs = cmap_format_14(14)
        cmap_uvs.platformID = 0
        cmap_uvs.platEncID = 5
        cmap_uvs.cmap = {}
        cmap_uvs.uvsDict = uvsdict
        font['cmap'].tables.append(cmap_uvs)

    args.logger.log('Saving ttf file', 'P')
    font.save(args.ottf)

    args.logger.log('Done', 'P')

def getuvss(ufo):
    uvsdict = {}
    uvs = ufo.lib.get('org.sil.variationSequences', None)
    if uvs is not None:
        for usv, dat in uvs.items():
            usvc = int(usv, 16)
            pairs = []
            uvsdict[usvc] = pairs
            for k, v in dat.items():
                pairs.append((int(k, 16), v))
        return uvsdict
    for g in ufo:
        uvs = getattr(g, 'lib', {}).get("org.sil.uvs", None)
        if uvs is None:
            continue
        codes = [int(x, 16) for x in uvs.split()]
        if codes[1] not in uvsdict:
            uvsdict[codes[1]] = []
        uvsdict[codes[1]].append((codes[0], (g.name if codes[0] not in g.unicodes else None)))
    return uvsdict

def cmd(): execute(None, doit, argspec)
if __name__ == '__main__': cmd()