2121#
2222# A script for subsetting a font, using FontForge. See README for details.
2323
24- # TODO 2013-04-08 ensure the menu files are as compact as possible by default, similar to subset.pl
25- # TODO 2013-05-22 in Arimo, the latin subset doesn't include ; but the greek does. why on earth is this happening?
24+ # TODO 2013-04-08 ensure the menu files are as compact as possible by default,
25+ # similar to subset.pl
26+ # TODO 2013-05-22 in Arimo, the latin subset doesn't include ; but the greek
27+ # does. why on earth is this happening?
2628
2729import getopt
2830import os
3537
3638def log_namelist (nam , unicode ):
3739 if nam and isinstance (unicode , int ):
38- print ("0x%0.4X" % unicode , fontforge .nameFromUnicode (unicode ), file = nam )
40+ print (f "0x{ unicode :04X } " , fontforge .nameFromUnicode (unicode ), file = nam )
3941
40- def select_with_refs (font , unicode , newfont , pe = None , nam = None ):
42+
43+ def select_with_refs (font , unicode , newfont , pe = None , nam = None ):
4144 newfont .selection .select (('more' , 'unicode' ), unicode )
4245 log_namelist (nam , unicode )
4346 if pe :
44- print ("SelectMore(%d)" % unicode , file = pe )
47+ print (f "SelectMore({ unicode } )" , file = pe )
4548 try :
4649 for ref in font [unicode ].references :
4750 newfont .selection .select (('more' ,), ref [0 ])
4851 log_namelist (nam , ref [0 ])
4952 if pe :
50- print ('SelectMore("%s")' % ref [0 ], file = pe )
53+ print (f 'SelectMore("{ ref [0 ]} ")' , file = pe )
5154 except Exception :
52- print ('Resolving references on u+%04x failed' % unicode )
55+ print (f'Resolving references on u+{ unicode :04x} failed' )
56+
5357
5458def subset_font_raw (font_in , font_out , unicodes , opts ):
5559 if '--namelist' in opts :
5660 # 2010-12-06 DC To allow setting namelist filenames,
5761 # change getopt.gnu_getopt from namelist to namelist=
5862 # and invert comments on following 2 lines
5963 # nam_fn = opts['--namelist']
60- nam_fn = font_out + ' .nam'
64+ nam_fn = f' { font_out } .nam'
6165 nam = open (nam_fn , 'w' )
6266 else :
6367 nam = None
@@ -68,7 +72,7 @@ def subset_font_raw(font_in, font_out, unicodes, opts):
6872 pe = None
6973 font = fontforge .open (font_in )
7074 if pe :
71- print ('Open("' + font_in + ' ")' , file = pe )
75+ print (f 'Open("{ font_in } ")' , file = pe )
7276 extract_vert_to_script (font_in , pe )
7377 for i in unicodes :
7478 select_with_refs (font , i , font , pe , nam )
@@ -83,9 +87,10 @@ def subset_font_raw(font_in, font_out, unicodes, opts):
8387 for glyph in addl_glyphs :
8488 font .selection .select (('more' ,), glyph )
8589 if nam :
86- print ("0x%0.4X" % fontforge .unicodeFromName (glyph ), glyph , file = nam )
90+ print (f"0x{ fontforge .unicodeFromName (glyph ):0.4X} " , glyph ,
91+ file = nam )
8792 if pe :
88- print ('SelectMore("%s ")' % glyph , file = pe )
93+ print (f 'SelectMore("{ glyph } ")' , file = pe )
8994
9095 flags = ()
9196
@@ -149,19 +154,20 @@ def subset_font_raw(font_in, font_out, unicodes, opts):
149154 nam .close ()
150155
151156 if pe :
152- print ('Generate("' + font_out + ' ")' , file = pe )
157+ print (f 'Generate("{ font_out } ")' , file = pe )
153158 pe .close ()
154159 subprocess .call (["fontforge" , "-script" , pe_fn ])
155160 else :
156- font .generate (font_out , flags = flags )
161+ font .generate (font_out , flags = flags )
157162 font .close ()
158163
159164 if '--roundtrip' in opts :
160165 # FontForge apparently contains a bug where it incorrectly calculates
161166 # the advanceWidthMax in the hhea table, and a workaround is to open
162167 # and re-generate
163168 font2 = fontforge .open (font_out )
164- font2 .generate (font_out , flags = flags )
169+ font2 .generate (font_out , flags = flags )
170+
165171
166172def subset_font (font_in , font_out , unicodes , opts ):
167173 font_out_raw = font_out
@@ -173,81 +179,97 @@ def subset_font(font_in, font_out, unicodes, opts):
173179# 2011-02-14 DC this needs to only happen with --namelist is used
174180# os.rename(font_out_raw + '.nam', font_out + '.nam')
175181
182+
176183def getsubset (subset , font_in ):
177184 subsets = subset .split ('+' )
178185
179- quotes = [0x2013 ] # endash
180- quotes += [0x2014 ] # emdash
181- quotes += [0x2018 ] # quoteleft
182- quotes += [0x2019 ] # quoteright
183- quotes += [0x201A ] # quotesinglbase
184- quotes += [0x201C ] # quotedblleft
185- quotes += [0x201D ] # quotedblright
186- quotes += [0x201E ] # quotedblbase
187- quotes += [0x2022 ] # bullet
188- quotes += [0x2039 ] # guilsinglleft
189- quotes += [0x203A ] # guilsinglright
190-
191- latin = range (0x20 , 0x7f ) # Basic Latin (A-Z, a-z, numbers)
192- latin += range (0xa0 , 0x100 ) # Western European symbols and diacritics
193- latin += [0x20ac ] # Euro
194- latin += [0x0152 ] # OE
195- latin += [0x0153 ] # oe
196- latin += [0x003b ] # semicolon
197- latin += [0x00b7 ] # periodcentered
198- latin += [0x0131 ] # dotlessi
199- latin += [0x02c6 ] # circumflex
200- latin += [0x02da ] # ring
201- latin += [0x02dc ] # tilde
202- latin += [0x2074 ] # foursuperior
203- latin += [0x2215 ] # division slash
204- latin += [0x2044 ] # fraction slash
205- latin += [0xe0ff ] # PUA: Font logo
206- latin += [0xeffd ] # PUA: Font version number
207- latin += [0xf000 ] # PUA: font ppem size indicator: run `ftview -f 1255 10 Ubuntu-Regular.ttf` to see it in action!
186+ quotes = [
187+ 0x2013 , # endash
188+ 0x2014 , # emdash
189+ 0x2018 , # quoteleft
190+ 0x2019 , # quoteright
191+ 0x201A , # quotesinglbase
192+ 0x201C , # quotedblleft
193+ 0x201D , # quotedblright
194+ 0x201E , # quotedblbase
195+ 0x2022 , # bullet
196+ 0x2039 , # guilsinglleft
197+ 0x203A , # guilsinglright
198+ ]
199+
200+ latin = [
201+ * range (0x20 , 0x7f ), # Basic Latin (A-Z, a-z, numbers)
202+ * range (0xa0 , 0x100 ), # Western European symbols and diacritics
203+ 0x20ac , # Euro
204+ 0x0152 , # OE
205+ 0x0153 , # oe
206+ 0x003b , # semicolon
207+ 0x00b7 , # periodcentered
208+ 0x0131 , # dotlessi
209+ 0x02c6 , # circumflex
210+ 0x02da , # ring
211+ 0x02dc , # tilde
212+ 0x2074 , # foursuperior
213+ 0x2215 , # division slash
214+ 0x2044 , # fraction slash
215+ 0xe0ff , # PUA: Font logo
216+ 0xeffd , # PUA: Font version number
217+ 0xf000 , # PUA: font ppem size indicator: run
218+ # `ftview -f 1255 10 Ubuntu-Regular.ttf` to see it in action!
219+ ]
208220
209221 result = quotes
210222
211223 if 'menu' in subset :
212224 font = fontforge .open (font_in )
213- result = map (ord , font .familyname )
214- result += [0x0020 ]
225+ result = [
226+ * map (ord , font .familyname ),
227+ 0x0020 ,
228+ ]
215229
216230 if 'latin' in subset :
217231 result += latin
218232 if 'latin-ext' in subset :
219233 # These ranges include Extended A, B, C, D, and Additional with the
220234 # exception of Vietnamese, which is a separate range
221- result += (range (0x100 , 0x370 ) +
222- range (0x1d00 , 0x1ea0 ) +
223- range (0x1ef2 , 0x1f00 ) +
224- range (0x2070 , 0x20d0 ) +
225- range (0x2c60 , 0x2c80 ) +
226- range (0xa700 , 0xa800 ))
235+ result += [
236+ * range (0x100 , 0x370 ),
237+ * range (0x1d00 , 0x1ea0 ),
238+ * range (0x1ef2 , 0x1f00 ),
239+ * range (0x2070 , 0x20d0 ),
240+ * range (0x2c60 , 0x2c80 ),
241+ * range (0xa700 , 0xa800 ),
242+ ]
227243 if 'vietnamese' in subset :
228- # 2011-07-16 DC: Charset from http://vietunicode.sourceforge.net/charset/ + U+1ef9 from Fontaine
244+ # 2011-07-16 DC: Charset from
245+ # http://vietunicode.sourceforge.net/charset/ + U+1ef9 from Fontaine
229246 result += [0x00c0 , 0x00c1 , 0x00c2 , 0x00c3 , 0x00C8 , 0x00C9 ,
230247 0x00CA , 0x00CC , 0x00CD , 0x00D2 , 0x00D3 , 0x00D4 ,
231248 0x00D5 , 0x00D9 , 0x00DA , 0x00DD , 0x00E0 , 0x00E1 ,
232249 0x00E2 , 0x00E3 , 0x00E8 , 0x00E9 , 0x00EA , 0x00EC ,
233250 0x00ED , 0x00F2 , 0x00F3 , 0x00F4 , 0x00F5 , 0x00F9 ,
234251 0x00FA , 0x00FD , 0x0102 , 0x0103 , 0x0110 , 0x0111 ,
235252 0x0128 , 0x0129 , 0x0168 , 0x0169 , 0x01A0 , 0x01A1 ,
236- 0x01AF , 0x01B0 , 0x20AB ] + range (0x1EA0 , 0x1EFA )
253+ 0x01AF , 0x01B0 , 0x20AB , * range (0x1EA0 , 0x1EFA )]
237254 if 'greek' in subset :
238- # Could probably be more aggressive here and exclude archaic characters,
239- # but lack data
240- result += range (0x370 , 0x400 )
255+ # Could probably be more aggressive here and exclude archaic
256+ # characters, but lack data
257+ result += [ * range (0x370 , 0x400 )]
241258 if 'greek-ext' in subset :
242- result += range (0x370 , 0x400 ) + range (0x1f00 , 0x2000 )
259+ result += [ * range (0x370 , 0x400 ), * range (0x1f00 , 0x2000 )]
243260 if 'cyrillic' in subset :
244261 # Based on character frequency analysis
245- result += range (0x400 , 0x460 ) + [ 0x490 , 0x491 , 0x4b0 , 0x4b1 , 0x2116 ]
262+ result += [ * range (0x400 , 0x460 ), 0x490 , 0x491 , 0x4b0 , 0x4b1 , 0x2116 ]
246263 if 'cyrillic-ext' in subset :
247- result += (range (0x400 , 0x530 ) +
248- [0x20b4 , 0x2116 ] + # 0x2116 is the russian No, a number abbreviation similar to the latin #, suggested by Alexei Vanyashin
249- range (0x2de0 , 0x2e00 ) +
250- range (0xa640 , 0xa6a0 ))
264+ result += [
265+ * range (0x400 , 0x530 ),
266+ 0x20b4 ,
267+ # 0x2116 is the russian No, a number abbreviation similar to the
268+ # latin #, suggested by Alexei Vanyashin
269+ 0x2116 ,
270+ * range (0x2de0 , 0x2e00 ),
271+ * range (0xa640 , 0xa6a0 ),
272+ ]
251273 if 'arabic' in subset :
252274 # Based on Droid Arabic Kufi 1.0
253275 result += [0x000D , 0x0020 , 0x0621 , 0x0627 , 0x062D ,
@@ -295,7 +317,8 @@ def getsubset(subset, font_in):
295317 0x06C8 , 0x06C9 , 0x06CA , 0x06CB , 0x06CF , 0x06CE ,
296318 0x06D0 , 0x06D1 , 0x06D4 , 0x06FA , 0x06DD , 0x06DE ,
297319 0x06E0 , 0x06E9 , 0x060D , 0xFD3E , 0xFD3F , 0x25CC ,
298- # Added from https://groups.google.com/d/topic/googlefontdirectory-discuss/MwlMWMPNCXs/discussion
320+ # Added from
321+ # https://groups.google.com/d/topic/googlefontdirectory-discuss/MwlMWMPNCXs/discussion
299322 0x063b , 0x063c , 0x063d , 0x063e , 0x063f , 0x0620 ,
300323 0x0674 , 0x0674 , 0x06EC ]
301324
@@ -308,42 +331,48 @@ def getsubset(subset, font_in):
308331
309332 return result
310333
311- # code for extracting vertical metrics from a TrueType font
312334
335+ # code for extracting vertical metrics from a TrueType font
313336class Sfnt :
314337 def __init__ (self , data ):
315338 version , numTables , _ , _ , _ = struct .unpack ('>IHHHH' , data [:12 ])
316339 self .tables = {}
317340 for i in range (numTables ):
318- tag , checkSum , offset , length = struct .unpack ('>4sIII' , data [12 + 16 * i : 28 + 16 * i ])
341+ tag , checkSum , offset , length = struct .unpack (
342+ '>4sIII' , data [12 + 16 * i : 28 + 16 * i ])
319343 self .tables [tag ] = data [offset : offset + length ]
320344
321345 def hhea (self ):
322346 r = {}
323347 d = self .tables ['hhea' ]
324- r ['Ascender' ], r ['Descender' ], r ['LineGap' ] = struct .unpack ('>hhh' , d [4 :10 ])
348+ r ['Ascender' ], r ['Descender' ], r ['LineGap' ] = struct .unpack (
349+ '>hhh' , d [4 :10 ])
325350 return r
326351
327352 def os2 (self ):
328353 r = {}
329354 d = self .tables ['OS/2' ]
330355 r ['fsSelection' ], = struct .unpack ('>H' , d [62 :64 ])
331- r ['sTypoAscender' ], r ['sTypoDescender' ], r ['sTypoLineGap' ] = struct .unpack ('>hhh' , d [68 :74 ])
332- r ['usWinAscender' ], r ['usWinDescender' ] = struct .unpack ('>HH' , d [74 :78 ])
356+ r ['sTypoAscender' ], r ['sTypoDescender' ], r ['sTypoLineGap' ] = \
357+ struct .unpack ('>hhh' , d [68 :74 ])
358+ r ['usWinAscender' ], r ['usWinDescender' ] = struct .unpack (
359+ '>HH' , d [74 :78 ])
333360 return r
334361
362+
335363def set_os2 (pe , name , val ):
336- print ('SetOS2Value("' + name + '", %d)' % val , file = pe )
364+ print (f'SetOS2Value("{ name } ", { val :d} )' , file = pe )
365+
337366
338367def set_os2_vert (pe , name , val ):
339368 set_os2 (pe , name + 'IsOffset' , 0 )
340369 set_os2 (pe , name , val )
341370
371+
342372# Extract vertical metrics data directly out of font file, and emit
343373# script code to set the values in the generated font. This is a (rather
344374# ugly) workaround for the issue described in:
345- # http://sourceforge.net/mailarchive/forum.php?thread_name=20100906085718.GB1907%40khaled-laptop&forum_name=fontforge-users
346-
375+ # https://sourceforge.net/p/fontforge/mailman/fontforge-users/thread/20100906085718.GB1907@khaled-laptop/
347376def extract_vert_to_script (font_in , pe ):
348377 with open (font_in , 'rb' ) as in_file :
349378 data = in_file .read ()
@@ -357,11 +386,12 @@ def extract_vert_to_script(font_in, pe):
357386 set_os2_vert (pe , "HHeadAscent" , hhea ['Ascender' ])
358387 set_os2_vert (pe , "HHeadDescent" , hhea ['Descender' ])
359388
389+
360390def main (argv ):
361- optlist , args = getopt .gnu_getopt (argv , '' , ['string=' , 'strip_names' , 'opentype-features' ,
362- 'simplify ' , 'new ' , 'script ' ,
363- 'nmr' , 'roundtrip' , 'subset=' ,
364- 'namelist' , 'null' , 'nd' , 'move-display' ])
391+ optlist , args = getopt .gnu_getopt (argv , '' , [
392+ 'string=' , 'strip_names' , 'opentype-features ' , 'simplify ' , 'new ' ,
393+ 'script' , 'nmr' , 'roundtrip' , 'subset=' , 'namelist' , 'null' , 'nd ' ,
394+ 'move-display' ])
365395
366396 font_in , font_out = args
367397 opts = dict (optlist )
@@ -371,5 +401,6 @@ def main(argv):
371401 subset = getsubset (opts .get ('--subset' , 'latin' ), font_in )
372402 subset_font (font_in , font_out , subset , opts )
373403
404+
374405if __name__ == '__main__' :
375406 main (sys .argv [1 :])
0 commit comments