blob: 8c8b880b1f99caaec34b6d8477c78bc3629935bd [file] [log] [blame]
Behdad Esfahbod54660612013-07-21 18:16:55 -04001#!/usr/bin/python
2
3# Python OpenType Layout Subsetter
4# Writte by: Behdad Esfahbod
5
6import fontTools.ttx
7import sys
8import types
9
10if len (sys.argv) < 3:
11 print >>sys.stderr, "usage: pyotlss.py font-file glyph..."
12 sys.exit (1)
13
14fontfile = sys.argv[1]
15glyphs = sys.argv[2:]
16
17font = fontTools.ttx.TTFont (fontfile)
18
19names = font.getGlyphNames()
20# Convert to glyph names
21glyphs = [g if g in names else font.getGlyphName(int(g)) for g in glyphs]
22
23def add_method (clazz):
24 def wrapper(method):
25 setattr (clazz, method.func_name, method)
26 return wrapper
27
28#
29# Subset
30#
31
32@add_method(fontTools.ttLib.tables.otTables.Coverage)
33def subset (self, glyphs):
34 indices = [i for (i,g) in enumerate (self.glyphs) if g in glyphs]
35 self.glyphs = [g for g in self.glyphs if g in glyphs]
36 return indices
37
38@add_method(fontTools.ttLib.tables.otTables.ClassDef)
39def subset (self, glyphs):
40 self.classDefs = {g:v for g,v in self.classDefs.items() if g in glyphs}
41
42@add_method(fontTools.ttLib.tables.otTables.SingleSubst)
43def subset (self, glyphs):
44 if self.Format in [1, 2]:
45 self.mapping = {g:v for g,v in self.mapping.items() if g in glyphs}
46 else:
47 assert 0, "unknown format: %s" % self.Format
48
49@add_method(fontTools.ttLib.tables.otTables.MultipleSubst)
50def subset (self, glyphs):
51 if self.Format == 1:
52 indices = self.Coverage.subset (glyphs)
53 self.Sequence = [self.Sequence[i] for i in indices]
54 else:
55 assert 0, "unknown format: %s" % self.Format
56
57@add_method(fontTools.ttLib.tables.otTables.AlternateSubst)
58def subset (self, glyphs):
59 if self.Format == 1:
60 self.alternates = {g:v for g,v in self.alternates.items() if g in glyphs}
61 else:
62 assert 0, "unknown format: %s" % self.Format
63
64@add_method(fontTools.ttLib.tables.otTables.LigatureSubst)
65def subset (self, glyphs):
66 self.ligatures = {g:v for g,v in self.ligatures.items() if g in glyphs}
67 self.ligatures = {g:[seq for seq in seqs if all(c in glyphs for c in seq.Component)]
68 for g,seqs in self.ligatures.items()}
69 self.ligatures = {g:v for g,v in self.ligatures.items() if v}
70
71@add_method(fontTools.ttLib.tables.otTables.ContextSubst)
72def subset (self, glyphs):
73 pass # XXX
74
75@add_method(fontTools.ttLib.tables.otTables.ChainContextSubst)
76def subset (self, glyphs):
77 pass # XXX
78
79@add_method(fontTools.ttLib.tables.otTables.ExtensionSubst)
80def subset (self, glyphs):
81 if self.Format == 1:
82 self.ExtSubTable.subset (glyphs)
83 else:
84 assert 0, "unknown format: %s" % self.Format
85
86@add_method(fontTools.ttLib.tables.otTables.ReverseChainSingleSubst)
87def subset (self, glyphs):
88 if self.Format == 1:
89 indices = self.Coverage.subset (glyphs)
90 self.Substitute = [self.Substitute[i] for i in indices]
91 self.GlyphCount = len (self.Substitute)
92 for c in self.LookAheadCoverage:
93 c.subset (glyphs)
94 for c in self.BacktrackCoverage:
95 c.subset (glyphs)
96 else:
97 assert 0, "unknown format: %s" % self.Format
98
99@add_method(fontTools.ttLib.tables.otTables.SinglePos)
100def subset (self, glyphs):
101 if self.Format == 1:
102 self.Coverage.subset (glyphs)
103 elif self.Format == 2:
104 indices = self.Coverage.subset (glyphs)
105 self.Value = [self.Value[i] for i in indices]
106 self.ValueCount = len (self.Value)
107 else:
108 assert 0, "unknown format: %s" % self.Format
109
110@add_method(fontTools.ttLib.tables.otTables.PairPos)
111def subset (self, glyphs):
112 if self.Format == 1:
113 indices = self.Coverage.subset (glyphs)
114 self.PairSet = [self.PairSet[i] for i in indices]
115 for p in self.PairSet:
116 p.PairValueRecord = [r for r in p.PairValueRecord if r.SecondGlyph in glyphs]
117 p.PairValueCount = len (p.PairValueRecord)
118 # TODO Prune empty rules
119 self.PairSetCount = len (self.PairSet)
120 elif self.Format == 2:
121 self.Coverage.subset (glyphs)
122 self.ClassDef1.subset (glyphs)
123 self.ClassDef2.subset (glyphs)
124 # TODO Prune empty classes
125 else:
126 assert 0, "unknown format: %s" % self.Format
127
128@add_method(fontTools.ttLib.tables.otTables.CursivePos)
129def subset (self, glyphs):
130 if self.Format == 1:
131 indices = self.Coverage.subset (glyphs)
132 self.EntryExitRecord = [self.EntryExitRecord[i] for i in indices]
133 else:
134 assert 0, "unknown format: %s" % self.Format
135
136@add_method(fontTools.ttLib.tables.otTables.MarkBasePos)
137def subset (self, glyphs):
138 if self.Format == 1:
139 mark_indices = self.MarkCoverage.subset (glyphs)
140 self.MarkArray.MarkRecord = [self.MarkArray.MarkRecord[i] for i in mark_indices]
141 self.MarkArray.MarkCount = len (self.MarkArray.MarkRecord)
142 base_indices = self.BaseCoverage.subset (glyphs)
143 self.BaseArray.BaseRecord = [self.BaseArray.BaseRecord[i] for i in base_indices]
144 self.BaseArray.BaseCount = len (self.BaseArray.BaseRecord)
145 # TODO Prune empty classes
146 else:
147 assert 0, "unknown format: %s" % self.Format
148
149@add_method(fontTools.ttLib.tables.otTables.MarkLigPos)
150def subset (self, glyphs):
151 if self.Format == 1:
152 mark_indices = self.MarkCoverage.subset (glyphs)
153 self.MarkArray.MarkRecord = [self.MarkArray.MarkRecord[i] for i in mark_indices]
154 self.MarkArray.MarkCount = len (self.MarkArray.MarkRecord)
155 ligature_indices = self.LigatureCoverage.subset (glyphs)
156 self.LigatureArray.LigatureAttach = [self.LigatureArray.LigatureAttach[i] for i in ligature_indices]
157 self.LigatureArray.LigatureCount = len (self.LigatureArray.LigatureAttach)
158 # TODO Prune empty classes
159 else:
160 assert 0, "unknown format: %s" % self.Format
161
162@add_method(fontTools.ttLib.tables.otTables.MarkMarkPos)
163def subset (self, glyphs):
164 if self.Format == 1:
165 mark1_indices = self.Mark1Coverage.subset (glyphs)
166 self.Mark1Array.MarkRecord = [self.Mark1Array.MarkRecord[i] for i in mark1_indices]
167 self.Mark1Array.MarkCount = len (self.Mark1Array.MarkRecord)
168 mark2_indices = self.Mark2Coverage.subset (glyphs)
169 self.Mark2Array.Mark2Record = [self.Mark2Array.Mark2Record[i] for i in mark2_indices]
170 self.Mark2Array.MarkCount = len (self.Mark2Array.Mark2Record)
171 # TODO Prune empty classes
172 else:
173 assert 0, "unknown format: %s" % self.Format
174
175@add_method(fontTools.ttLib.tables.otTables.ContextPos)
176def subset (self, glyphs):
177 pass # XXX
178
179@add_method(fontTools.ttLib.tables.otTables.ChainContextPos)
180def subset (self, glyphs):
181 pass # XXX
182
183@add_method(fontTools.ttLib.tables.otTables.ExtensionPos)
184def subset (self, glyphs):
185 if self.Format == 1:
186 self.ExtSubTable.subset (glyphs)
187 else:
188 assert 0, "unknown format: %s" % self.Format
189
190for Gtag in ['GSUB', 'GPOS']:
191 if Gtag not in font:
192 continue
193 G = font[Gtag]
194 for lookup in G.table.LookupList.Lookup:
195 for subtable in lookup.SubTable:
196 print subtable
197 subtable.subset (glyphs)
198
199#font['GSUB'].toXML(sys.stdout, font)