[subset] Add --retain-gids to retain glyph indices

This commit is contained in:
Behdad Esfahbod 2019-01-14 16:44:32 -05:00
parent 7cbb2da4df
commit dd081d64dc

View File

@ -123,6 +123,8 @@ Output options:
Glyph set expansion: Glyph set expansion:
These options control how additional glyphs are added to the subset. These options control how additional glyphs are added to the subset.
--retain-gids
Retain glyph indices; just empty glyphs not needed in-place.
--notdef-glyph --notdef-glyph
Add the '.notdef' glyph to the subset (ie, keep it). [default] Add the '.notdef' glyph to the subset (ie, keep it). [default]
--no-notdef-glyph --no-notdef-glyph
@ -1714,11 +1716,15 @@ def subset_glyphs(self, s):
@_add_method(ttLib.getTableClass('vmtx')) @_add_method(ttLib.getTableClass('vmtx'))
def subset_glyphs(self, s): def subset_glyphs(self, s):
self.metrics = _dict_subset(self.metrics, s.glyphs) self.metrics = _dict_subset(self.metrics, s.glyphs)
for g in s.glyphs_emptied:
self.metrics[g] = (0,0)
return bool(self.metrics) return bool(self.metrics)
@_add_method(ttLib.getTableClass('hmtx')) @_add_method(ttLib.getTableClass('hmtx'))
def subset_glyphs(self, s): def subset_glyphs(self, s):
self.metrics = _dict_subset(self.metrics, s.glyphs) self.metrics = _dict_subset(self.metrics, s.glyphs)
for g in s.glyphs_emptied:
self.metrics[g] = (0,0)
return True # Required table return True # Required table
@_add_method(ttLib.getTableClass('hdmx')) @_add_method(ttLib.getTableClass('hdmx'))
@ -1784,6 +1790,8 @@ def subset_glyphs(self, s):
def subset_glyphs(self, s): def subset_glyphs(self, s):
table = self.table table = self.table
# TODO Update for retain_gids
used = set() used = set()
if table.AdvWidthMap: if table.AdvWidthMap:
@ -2010,7 +2018,7 @@ def subset_glyphs(self, s):
return True return True
@_add_method(ttLib.getTableModule('glyf').Glyph) @_add_method(ttLib.getTableModule('glyf').Glyph)
def remapComponentsFast(self, indices): def remapComponentsFast(self, glyphidmap):
if not self.data or struct.unpack(">h", self.data[:2])[0] >= 0: if not self.data or struct.unpack(">h", self.data[:2])[0] >= 0:
return # Not composite return # Not composite
data = array.array("B", self.data) data = array.array("B", self.data)
@ -2020,7 +2028,7 @@ def remapComponentsFast(self, indices):
flags =(data[i] << 8) | data[i+1] flags =(data[i] << 8) | data[i+1]
glyphID =(data[i+2] << 8) | data[i+3] glyphID =(data[i+2] << 8) | data[i+3]
# Remap # Remap
glyphID = indices.index(glyphID) glyphID = glyphidmap[glyphID]
data[i+2] = glyphID >> 8 data[i+2] = glyphID >> 8
data[i+3] = glyphID & 0xFF data[i+3] = glyphID & 0xFF
i += 4 i += 4
@ -2063,13 +2071,17 @@ def prune_pre_subset(self, font, options):
@_add_method(ttLib.getTableClass('glyf')) @_add_method(ttLib.getTableClass('glyf'))
def subset_glyphs(self, s): def subset_glyphs(self, s):
self.glyphs = _dict_subset(self.glyphs, s.glyphs) self.glyphs = _dict_subset(self.glyphs, s.glyphs)
indices = [i for i,g in enumerate(self.glyphOrder) if g in s.glyphs] if not s.options.retain_gids:
for v in self.glyphs.values(): indices = [i for i,g in enumerate(self.glyphOrder) if g in s.glyphs]
if hasattr(v, "data"): glyphmap = {o:n for n,o in enumerate(indices)}
v.remapComponentsFast(indices) for v in self.glyphs.values():
else: if hasattr(v, "data"):
pass # No need v.remapComponentsFast(glyphmap)
self.glyphOrder = [g for g in self.glyphOrder if g in s.glyphs] Glyph = ttLib.getTableModule('glyf').Glyph
for g in s.glyphs_emptied:
self.glyphs[g] = Glyph()
self.glyphs[g].data = ''
self.glyphOrder = [g for g in self.glyphOrder if g in s.glyphs or g in s.glyphs_emptied]
# Don't drop empty 'glyf' tables, otherwise 'loca' doesn't get subset. # Don't drop empty 'glyf' tables, otherwise 'loca' doesn't get subset.
return True return True
@ -2275,6 +2287,7 @@ class Options(object):
self.name_legacy = False self.name_legacy = False
self.name_languages = [0x0409] # English self.name_languages = [0x0409] # English
self.obfuscate_names = False # to make webfont unusable as a system font self.obfuscate_names = False # to make webfont unusable as a system font
self.retain_gids = False
self.notdef_glyph = True # gid0 for TrueType / .notdef for CFF self.notdef_glyph = True # gid0 for TrueType / .notdef for CFF
self.notdef_outline = False # No need for notdef to have an outline really self.notdef_outline = False # No need for notdef to have an outline really
self.recommended_glyphs = False # gid1, gid2, gid3 for TrueType self.recommended_glyphs = False # gid1, gid2, gid3 for TrueType
@ -2533,12 +2546,17 @@ class Subsetter(object):
log.glyphs(self.glyphs, font=font) log.glyphs(self.glyphs, font=font)
self.glyphs_cffed = frozenset(self.glyphs) self.glyphs_cffed = frozenset(self.glyphs)
self.glyphs_all = frozenset(self.glyphs) self.glyphs_retained = frozenset(self.glyphs)
self.glyphs_emptied = frozenset()
if self.options.retain_gids:
self.glyphs_emptied = realGlyphs - self.glyphs_retained
# TODO Drop empty glyphs at the end of GlyphOrder vector.
order = font.getReverseGlyphMap() order = font.getReverseGlyphMap()
self.reverseOrigGlyphMap = {g:order[g] for g in self.glyphs_all} self.reverseOrigGlyphMap = {g:order[g] for g in self.glyphs_retained}
log.info("Retaining %d glyphs", len(self.glyphs_all)) log.info("Retaining %d glyphs", len(self.glyphs_retained))
del self.glyphs del self.glyphs
@ -2551,7 +2569,7 @@ class Subsetter(object):
elif hasattr(clazz, 'subset_glyphs'): elif hasattr(clazz, 'subset_glyphs'):
with timer("subset '%s'" % tag): with timer("subset '%s'" % tag):
table = font[tag] table = font[tag]
self.glyphs = self.glyphs_all self.glyphs = self.glyphs_retained
retain = table.subset_glyphs(self) retain = table.subset_glyphs(self)
del self.glyphs del self.glyphs
if not retain: if not retain:
@ -2565,11 +2583,12 @@ class Subsetter(object):
log.warning("%s NOT subset; don't know how to subset; dropped", tag) log.warning("%s NOT subset; don't know how to subset; dropped", tag)
del font[tag] del font[tag]
with timer("subset GlyphOrder"): if not self.options.retain_gids:
glyphOrder = font.getGlyphOrder() with timer("subset GlyphOrder"):
glyphOrder = [g for g in glyphOrder if g in self.glyphs_all] glyphOrder = font.getGlyphOrder()
font.setGlyphOrder(glyphOrder) glyphOrder = [g for g in glyphOrder if g in self.glyphs_retained]
font._buildReverseGlyphOrderDict() font.setGlyphOrder(glyphOrder)
font._buildReverseGlyphOrderDict()
def _prune_post_subset(self, font): def _prune_post_subset(self, font):
for tag in font.keys(): for tag in font.keys():