38
38
from __future__ import absolute_import , division , unicode_literals , print_function
39
39
40
40
41
+ # The general approach here is to not change any glyph ids, merely to
42
+ # remove content for unused glyphs. This means the character map
43
+ # tables don't have to be rewritten. Additionally, this doesn't break
44
+ # random third-party table formats that use glyph ids. This does mean
45
+ # that some space savings are left on the table, but for large Unicode
46
+ # fonts, the glyph data itself is comprises the majority of the file
47
+ # size, and this approach tackles that handily.
48
+
49
+
41
50
__all__ = ['subset_font' ]
42
51
43
52
@@ -211,7 +220,7 @@ def _get_formats(self, fontfile):
211
220
def get_offsets (self , fontfile ):
212
221
entry_format , entry_size , scale = self ._get_formats (fontfile )
213
222
214
- content = self ._content
223
+ content = self .content
215
224
offsets = [
216
225
struct .unpack (
217
226
entry_format , content [i :i + entry_size ])[0 ] * scale
@@ -232,10 +241,9 @@ def subset(self, fontfile, glyphs, offsets):
232
241
new_offsets .append (offset )
233
242
234
243
entry_format , entry_size , scale = self ._get_formats (fontfile )
235
- new_content = []
236
- for value in new_offsets :
237
- new_content .append (struct .pack (entry_format , value // scale ))
238
- self .content = b'' .join (new_content )
244
+ self .content = b'' .join (
245
+ struct .pack (entry_format , value // scale )
246
+ for value in new_offsets )
239
247
240
248
241
249
class _GlyfTable (_Table ):
@@ -250,8 +258,29 @@ def find_all_glyphs(self, glyphs, offsets):
250
258
WE_HAVE_AN_X_AND_Y_SCALE = 1 << 6
251
259
WE_HAVE_A_TWO_BY_TWO = 1 << 7
252
260
253
- content = self .content
261
+ def calculate_skip (flags ):
262
+ """
263
+ Calculates the number of bytes to skip to get to the next
264
+ component entry.
265
+ """
266
+ # Numbers can be in bytes or shorts, depending on
267
+ # flag bit
268
+ if flags & ARG_1_AND_2_ARE_WORDS :
269
+ base_size = 2
270
+ else :
271
+ base_size = 1
272
+
273
+ nbytes = 4 + base_size * 2
274
+ if flags & WE_HAVE_A_SCALE :
275
+ nbytes += base_size
276
+ elif flags & WE_HAVE_AN_X_AND_Y_SCALE :
277
+ nbytes += base_size * 2
278
+ elif flags & WE_HAVE_A_TWO_BY_TWO :
279
+ nbytes += base_size * 4
280
+
281
+ return nbytes
254
282
283
+ content = self .content
255
284
all_glyphs = set ()
256
285
glyph_queue = glyphs [:]
257
286
@@ -276,22 +305,7 @@ def find_all_glyphs(self, glyphs, offsets):
276
305
if not flags & MORE_COMPONENTS :
277
306
break
278
307
279
- # Numbers can be in bytes or shorts, depending on
280
- # flag bit
281
- if flags & ARG_1_AND_2_ARE_WORDS :
282
- base_size = 2
283
- else :
284
- base_size = 1
285
-
286
- # This is just to calculate how many bytes to skip
287
- # over to find next component entry
288
- i += 4 + base_size * 2
289
- if flags & WE_HAVE_A_SCALE :
290
- i += base_size
291
- elif flags & WE_HAVE_AN_X_AND_Y_SCALE :
292
- i += base_size * 2
293
- elif flags & WE_HAVE_A_TWO_BY_TWO :
294
- i += base_size * 4
308
+ i += calculate_skip (flags )
295
309
296
310
all_glyphs = list (all_glyphs )
297
311
all_glyphs .sort ()
@@ -307,19 +321,15 @@ def subset(self, glyphs, offsets):
307
321
308
322
class _PostTable (_Table ):
309
323
post_table_struct = _BinaryStruct ([
310
- ('format' , 'I' ),
311
- ('unused' , '28s' )])
324
+ ('format' , 'I' )])
312
325
313
326
def __init__ (self , header , content ):
314
327
super (_PostTable , self ).__init__ (header , content )
315
328
316
- with open ('content.bin' , 'wb' ) as fd :
317
- fd .write (content )
318
-
319
- self .__dict__ .update (self .post_table_struct .unpack (content [:32 ]))
329
+ self .__dict__ .update (self .post_table_struct .unpack (content [:4 ]))
320
330
321
331
def _subset_format2 (self , glyphs ):
322
- n_basic_names = 258
332
+ N_BASIC_NAMES = 258
323
333
324
334
content = self ._content
325
335
i = 32
@@ -357,15 +367,16 @@ def _subset_format2(self, glyphs):
357
367
for i in range (numglyphs ):
358
368
val = new_glyph_index .get (i , 0 )
359
369
new_content .append (struct .pack ('>H' , val ))
370
+
360
371
for name in names :
361
372
new_content .append (struct .pack ('>B' , len (name )))
362
373
new_content .append (name )
363
374
364
- self . _content = b'' .join (new_content )
375
+ return b'' .join (new_content )
365
376
366
377
def subset (self , glyphs ):
367
- if self .format == 0x20000 :
368
- self ._subset_format2 (glyphs )
378
+ if self .format == 0x20000 and False :
379
+ self .content = self . _subset_format2 (glyphs )
369
380
370
381
371
382
SPECIAL_TABLES = {
@@ -447,6 +458,8 @@ def subset(self, ccodes):
447
458
self [b'post' ].subset (glyphs )
448
459
449
460
def write (self , fd ):
461
+ self ._header ['numTables' ] = len (self ._tables )
462
+
450
463
self .header_struct .write (fd , self ._header )
451
464
452
465
offset = (self .header_struct .size +
0 commit comments