-
Notifications
You must be signed in to change notification settings - Fork 3
/
create_font.py
executable file
·110 lines (90 loc) · 3.28 KB
/
create_font.py
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
#!/usr/bin/env python3
from io import StringIO, BytesIO
from re import sub
from copy import deepcopy
from subprocess import call
from collections import defaultdict
from lxml import etree
def remove_elm(doc, xpath):
elm = doc.xpath(xpath)[0]
elm.getparent().remove(elm)
def create_ligature_set(glyph):
elm = etree.Element('LigatureSet')
elm.set('glyph', glyph)
return elm
glyphs = []
liga_map = defaultdict(list)
xpath_tmpl = "/ttFont/GSUB/LookupList/Lookup/LigatureSubst/LigatureSet[@glyph='{}']//Ligature[@components='{}']"
call([
'ttx',
'material-icons.woff2'
])
md_icons = etree.parse('material-icons.ttx')
call(['rm', 'material-icons.ttx'])
with open('icon-names.txt') as f:
ic_names = [i.strip() for i in f.readlines()]
ic_names.sort()
for i in ic_names:
liga_map[i[0]].append(i)
for letter, names in liga_map.items():
for name in names:
compo = sub(r'(\w)', r'\1,', name)[2:-1].replace('_', 'underscore')
try:
ligature = md_icons.xpath(xpath_tmpl.format(letter, compo))[0]
glyphs.append(ligature.get('glyph'))
except IndexError:
print("Error: no such icon name={}".format(name))
with open('glyph_names.txt', 'w') as the_file:
the_file.write(','.join(glyphs))
call([
'pyftsubset',
'material-icons.woff2',
'--gids=13-39',
'--glyphs={}'.format(','.join(glyphs)),
'--layout-features-=liga',
'--output-file=needed-glyph.ttf'
])
call([
'ttx',
'needed-glyph.ttf'
])
call(['rm', 'needed-glyph.ttf'])
needed = etree.parse('needed-glyph.ttx')
gsub = needed.xpath('/ttFont/GSUB')[0]
remove_elm(gsub, '/ttFont/GSUB/ScriptList')
remove_elm(gsub, '/ttFont/GSUB/FeatureList')
gsub.append(deepcopy(md_icons.xpath('/ttFont/GSUB/ScriptList')[0]))
gsub.append(deepcopy(md_icons.xpath('/ttFont/GSUB/FeatureList')[0]))
lookup_list = gsub.xpath('/ttFont/GSUB/LookupList')[0]
lookup = etree.Element('Lookup')
lookup.set('index', '0')
lookup_list.append(lookup)
lookup.append(deepcopy(md_icons.xpath('/ttFont/GSUB/LookupList/Lookup/LookupType')[0]))
lookup.append(deepcopy(md_icons.xpath('/ttFont/GSUB/LookupList/Lookup/LookupFlag')[0]))
ligature_subst = etree.Element('LigatureSubst')
ligature_subst.set('index', '0')
ligature_subst.set('Format', '1')
lookup.append(ligature_subst)
for letter, names in liga_map.items():
ligature_set = create_ligature_set(letter)
ligature_subst.append(ligature_set)
# sort the liga items by length in reverse order. if not,
# `<Ligature components="e,p,e,a,t" glyph="uniE040"/>`
# would override
# `<Ligature components="e,p,e,a,t,underscore,o,n,e" glyph="uniE041"/>`
# as `uniE040,underscore,o,n,e` , ruins the icon
names.sort(key=len, reverse=True)
for name in names:
compo = sub(r'(\w)', r'\1,', name)[2:-1].replace('_', 'underscore')
try:
ligature = md_icons.xpath(xpath_tmpl.format(letter, compo))[0]
ligature_set.append(deepcopy(ligature))
except IndexError:
print("Error: no such Ligature glyph={}, components={}".format(letter, compo))
needed.write('needed-glyph-liga.ttx', pretty_print=True, xml_declaration=True, encoding="utf-8")
call([
'ttx',
'--flavor', 'woff2',
'-o', 'ic.min.woff2',
'needed-glyph-liga.ttx'
])