File: build.py

package info (click to toggle)
fonts-smc-rachana 7.0.1-1
  • links: PTS, VCS
  • area: main
  • in suites: buster
  • size: 6,220 kB
  • sloc: python: 132; makefile: 50; sh: 16; xml: 6
file content (187 lines) | stat: -rw-r--r-- 6,226 bytes parent folder | download | duplicates (2)
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
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
#!/usr/bin/python
# coding=utf-8
#
# Font build utility
#

import sys
import time
import os
import fontforge
import psMat
from tempfile import mkstemp
from fontTools.ttLib import TTFont
from fontTools.ttx import makeOutputFileName
import argparse


def flattenNestedReferences(font, ref, new_transform=(1, 0, 0, 1, 0, 0)):
    """Flattens nested references by replacing them with the ultimate reference
    and applying any transformation matrices involved, so that the final font
    has only simple composite glyphs. This to work around what seems to be an
    Apple bug that results in ignoring transformation matrix of nested
    references."""

    name = ref[0]
    transform = ref[1]
    glyph = font[name]
    new_ref = []
    if glyph.references and glyph.foreground.isEmpty():
        for nested_ref in glyph.references:
            for i in flattenNestedReferences(font, nested_ref, transform):
                matrix = psMat.compose(i[1], new_transform)
                new_ref.append((i[0], matrix))
    else:
        matrix = psMat.compose(transform, new_transform)
        new_ref.append((name, matrix))

    return new_ref


def validateGlyphs(font):
    """Fixes some common FontForge validation warnings, currently handles:
        * wrong direction
        * flipped references
    In addition to flattening nested references."""

    wrong_dir = 0x8
    flipped_ref = 0x10
    for glyph in font.glyphs():
        state = glyph.validate(True)
        refs = []

        if state & flipped_ref:
            glyph.unlinkRef()
            glyph.correctDirection()
        if state & wrong_dir:
            glyph.correctDirection()

        for ref in glyph.references:
            for i in flattenNestedReferences(font, ref):
                refs.append(i)
        if refs:
            glyph.references = refs


def fixGasp(font, value=15):
     try:
        table = font.get('gasp')
        table.gaspRange[65535] = value
     except:
        print('ER: {}: no table gasp')

def fixXAvgCharWidth(font):
    """xAvgCharWidth should be the average of all glyph widths in the font"""
    width_sum = 0
    count = 0
    for glyph_id in font['glyf'].glyphs:
      width = font['hmtx'].metrics[glyph_id][0]
      if width > 0:
           count += 1
           width_sum += width
    if count == 0:
        fb.error("CRITICAL: Found no glyph width data!")
    else:
        expected_value = int(round(width_sum) / count)
    font['OS/2'].xAvgCharWidth = int(round(width_sum) / count)
def opentype(infont, outdir, type, feature, version):
    font = fontforge.open(infont)
    if args.type == 'otf':
        outfont = infont.replace(".sfd", ".otf")
        flags = ("opentype",  "round", "omit-instructions", "dummy-dsig")
    else:
        outfont = infont.replace(".sfd", ".ttf")
        flags = ("opentype", "round", "omit-instructions", "dummy-dsig")
    outfont = os.path.join(outdir, outfont)
    print("Generating %s => %s" % (infont, outfont))
    tmpfont = mkstemp(suffix=os.path.basename(outfont))[1]

    # Remove all GSUB lookups
    for lookup in font.gsub_lookups:
        font.removeLookup(lookup)

    # Remove all GPOS lookups
    for lookup in font.gpos_lookups:
        font.removeLookup(lookup)

    # Merge the new featurefile
    font.mergeFeature(feature)
    font.version = version
    font.appendSFNTName('English (US)', 'Version',
                        'Version ' + version + '.0+' + time.strftime('%Y%m%d'))
    font.selection.all()
    font.correctReferences()
    font.simplify()
    font.selection.none()
    # fix some common font issues
    validateGlyphs(font)
    font.generate(tmpfont, flags=flags)
    font.close()
    # now open in fontTools
    font = TTFont(tmpfont, recalcBBoxes=0)

    # our 'name' table is a bit bulky, and of almost no use in for web fonts,
    # so we strip all unnecessary entries.
    name = font['name']
    names = []
    for record in name.names:
        platID = record.platformID
        langID = record.langID
        nameID = record.nameID

        # we keep only en_US entries in Windows and Mac platform id, every
        # thing else is dropped
        if (platID == 1 and langID == 0) or (platID == 3 and langID == 1033):
            if nameID == 13:
                # the full OFL text is too much, replace it with a simple
                # string
                if platID == 3:
                    # MS strings are UTF-16 encoded
                    text = 'OFL v1.1'.encode('utf_16_be')
                else:
                    text = 'OFL v1.1'
                record.string = text
                names.append(record)
                # keep every thing else except Descriptor, Sample Text
            elif nameID not in (10, 19):
                names.append(record)

    name.names = names
    font['OS/2'].version = 4
    fixGasp(font)
    fixXAvgCharWidth(font)
    # FFTM is FontForge specific, remove it
    del(font['FFTM'])
    # force compiling GPOS/GSUB tables by fontTools, saves few tens of KBs
    for tag in ('GPOS', 'GSUB'):
        font[tag].compile(font)

    font.save(outfont)
    font.close()
    os.remove(tmpfont)

def webfonts(infont, type):
    font = TTFont(infont, recalcBBoxes=0)
    # Generate WOFF2
    woffFileName = makeOutputFileName(infont, outputDir=None, extension='.' + type)
    print("Processing %s => %s" % (infont, woffFileName))
    font.flavor = type
    font.save(woffFileName, reorderTables=False)

    font.close()


if __name__ == "__main__":
    parser = argparse.ArgumentParser(description='Build fonts')
    parser.add_argument('-i', '--input', help='Input font', required=True)
    parser.add_argument('-v', '--version', help='Version')
    parser.add_argument('-f', '--feature', help='Feature file')
    parser.add_argument('-t', '--type', help='Output type', default='otf')
    parser.add_argument('-o', '--outdir', help='Output directory', default='build')
    args = parser.parse_args()
    if not os.path.exists(args.outdir):
        os.mkdir(args.outdir)
    if args.type == 'otf' or args.type == 'ttf':
        opentype(args.input, args.outdir, args.type, args.feature, args.version)
    if args.type == 'woff' or args.type == 'woff2':
        webfonts(args.input, args.type)