Skip to content

Commit 3fab36e

Browse files
committed
Minor improvements to subsetting
1 parent 07f7f4d commit 3fab36e

File tree

1 file changed

+45
-32
lines changed

1 file changed

+45
-32
lines changed

lib/freetypy/subset.py

Lines changed: 45 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,15 @@
3838
from __future__ import absolute_import, division, unicode_literals, print_function
3939

4040

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+
4150
__all__ = ['subset_font']
4251

4352

@@ -211,7 +220,7 @@ def _get_formats(self, fontfile):
211220
def get_offsets(self, fontfile):
212221
entry_format, entry_size, scale = self._get_formats(fontfile)
213222

214-
content = self._content
223+
content = self.content
215224
offsets = [
216225
struct.unpack(
217226
entry_format, content[i:i+entry_size])[0] * scale
@@ -232,10 +241,9 @@ def subset(self, fontfile, glyphs, offsets):
232241
new_offsets.append(offset)
233242

234243
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)
239247

240248

241249
class _GlyfTable(_Table):
@@ -250,8 +258,29 @@ def find_all_glyphs(self, glyphs, offsets):
250258
WE_HAVE_AN_X_AND_Y_SCALE = 1 << 6
251259
WE_HAVE_A_TWO_BY_TWO = 1 << 7
252260

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
254282

283+
content = self.content
255284
all_glyphs = set()
256285
glyph_queue = glyphs[:]
257286

@@ -276,22 +305,7 @@ def find_all_glyphs(self, glyphs, offsets):
276305
if not flags & MORE_COMPONENTS:
277306
break
278307

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)
295309

296310
all_glyphs = list(all_glyphs)
297311
all_glyphs.sort()
@@ -307,19 +321,15 @@ def subset(self, glyphs, offsets):
307321

308322
class _PostTable(_Table):
309323
post_table_struct = _BinaryStruct([
310-
('format', 'I'),
311-
('unused', '28s')])
324+
('format', 'I')])
312325

313326
def __init__(self, header, content):
314327
super(_PostTable, self).__init__(header, content)
315328

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]))
320330

321331
def _subset_format2(self, glyphs):
322-
n_basic_names = 258
332+
N_BASIC_NAMES = 258
323333

324334
content = self._content
325335
i = 32
@@ -357,15 +367,16 @@ def _subset_format2(self, glyphs):
357367
for i in range(numglyphs):
358368
val = new_glyph_index.get(i, 0)
359369
new_content.append(struct.pack('>H', val))
370+
360371
for name in names:
361372
new_content.append(struct.pack('>B', len(name)))
362373
new_content.append(name)
363374

364-
self._content = b''.join(new_content)
375+
return b''.join(new_content)
365376

366377
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)
369380

370381

371382
SPECIAL_TABLES = {
@@ -447,6 +458,8 @@ def subset(self, ccodes):
447458
self[b'post'].subset(glyphs)
448459

449460
def write(self, fd):
461+
self._header['numTables'] = len(self._tables)
462+
450463
self.header_struct.write(fd, self._header)
451464

452465
offset = (self.header_struct.size +

0 commit comments

Comments
 (0)