add removeUnusedNames staticmethod to name table

This commit is contained in:
Marc Foley 2023-06-27 12:02:00 +01:00
parent 552525dc84
commit a792851131
2 changed files with 73 additions and 78 deletions

View File

@ -11,6 +11,10 @@ from fontTools.misc.textTools import (
)
from fontTools.misc.encodingTools import getEncoding
from fontTools.ttLib import newTable
from fontTools.ttLib.ttVisitor import TTVisitor
from fontTools import ttLib
import fontTools.ttLib.tables.otTables as otTables
from fontTools.ttLib.tables import C_P_A_L_
from . import DefaultTable
import struct
import logging
@ -223,6 +227,28 @@ class table__n_a_m_e(DefaultTable.DefaultTable):
)
]
@staticmethod
def removeUnusedNames(ttFont):
"""Remove any name records which are not in NameID range 0-255 and not utilized
within the font itself."""
visitor = NameRecordVisitor()
visitor.visit(ttFont)
toDelete = set()
for record in ttFont["name"].names:
# Name IDs 26 to 255, inclusive, are reserved for future standard names.
# https://learn.microsoft.com/en-us/typography/opentype/spec/name#name-ids
if record.nameID < 256:
continue
if record.nameID not in visitor.seen:
toDelete.add(record.nameID)
if not toDelete:
log.info("Name table has no redundant records, skipping")
return
log.info(f"Deleting name records with NameIDs {toDelete}")
for nameID in toDelete:
ttFont["name"].removeNames(nameID)
def _findUnusedNameID(self, minNameID=256):
"""Finds an unused name id.
@ -1138,3 +1164,49 @@ _MAC_LANGUAGE_TO_SCRIPT = {
150: 0, # langAzerbaijanRoman → smRoman
151: 0, # langNynorsk → smRoman
}
class NameRecordVisitor(TTVisitor):
def __init__(self):
self.seen = set()
@NameRecordVisitor.register_attrs(
(
(otTables.FeatureParamsSize, ("SubfamilyID", "SubfamilyNameID")),
(otTables.FeatureParamsStylisticSet, ("UINameID",)),
(
otTables.FeatureParamsCharacterVariants,
(
"FeatUILabelNameID",
"FeatUITooltipTextNameID",
"SampleTextNameID",
"FirstParamUILabelNameID",
),
),
(otTables.STAT, ("ElidedFallbackNameID",)),
(otTables.AxisRecord, ("AxisNameID",)),
(otTables.AxisValue, ("ValueNameID",)),
(otTables.FeatureName, ("FeatureNameID",)),
(otTables.Setting, ("SettingNameID",)),
)
)
def visit(visitor, obj, attr, value):
visitor.seen.add(value)
@NameRecordVisitor.register(ttLib.getTableClass("fvar"))
def visit(visitor, obj):
for inst in obj.instances:
visitor.seen.add(inst.postscriptNameID)
visitor.seen.add(inst.subfamilyNameID)
for axis in obj.axes:
visitor.seen.add(axis.axisNameID)
@NameRecordVisitor.register(ttLib.getTableClass("CPAL"))
def visit(visitor, obj):
for nameID in obj.paletteLabels:
if nameID != C_P_A_L_.table_C_P_A_L_.NO_NAME_ID:
visitor.seen.add(nameID)

View File

@ -1,84 +1,7 @@
#!/usr/bin/env python3
"""Script to remove redundant font name table records."""
from fontTools.ttLib.ttVisitor import TTVisitor
from fontTools import ttLib
from fontTools.ttLib import TTFont
import fontTools.ttLib.tables.otTables as otTables
from fontTools.ttLib.tables import C_P_A_L_
import sys
import logging
logger = logging.getLogger()
class NameRecordVisitor(TTVisitor):
def __init__(self):
self.seen = set()
def removeUnusedNameRecords(self, font):
self.visit(font)
toDelete = set()
for record in font["name"].names:
# Name IDs 26 to 255, inclusive, are reserved for future standard names.
# https://learn.microsoft.com/en-us/typography/opentype/spec/name#name-ids
if record.nameID < 256:
continue
if record.nameID not in self.seen:
toDelete.add(record.nameID)
if not toDelete:
logger.info("Name table has no redundant records, skipping")
return
logger.info(f"Deleting name records with NameIDs {toDelete}")
for nameID in toDelete:
font["name"].removeNames(nameID)
@NameRecordVisitor.register_attrs(
(
(otTables.FeatureParamsSize, ("SubfamilyID", "SubfamilyNameID")),
(otTables.FeatureParamsStylisticSet, ("UINameID",)),
(
otTables.FeatureParamsCharacterVariants,
(
"FeatUILabelNameID",
"FeatUITooltipTextNameID",
"SampleTextNameID",
"FirstParamUILabelNameID",
),
),
(otTables.STAT, ("ElidedFallbackNameID",)),
(otTables.AxisRecord, ("AxisNameID",)),
(otTables.AxisValue, ("ValueNameID",)),
(otTables.FeatureName, ("FeatureNameID",)),
(otTables.Setting, ("SettingNameID",)),
)
)
def visit(visitor, obj, attr, value):
visitor.seen.add(value)
@NameRecordVisitor.register(ttLib.getTableClass("fvar"))
def visit(visitor, obj):
for inst in obj.instances:
visitor.seen.add(inst.postscriptNameID)
visitor.seen.add(inst.subfamilyNameID)
for axis in obj.axes:
visitor.seen.add(axis.axisNameID)
@NameRecordVisitor.register(ttLib.getTableClass("CPAL"))
def visit(visitor, obj):
for nameID in obj.paletteLabels:
if nameID != C_P_A_L_.table_C_P_A_L_.NO_NAME_ID:
visitor.seen.add(nameID)
def removeUnusedNameRecords(ttFont):
visitor = NameRecordVisitor()
visitor.removeUnusedNameRecords(ttFont)
def main():
@ -86,7 +9,7 @@ def main():
print("Usage: python nameClean.py font.ttf out.ttf")
sys.exit()
font = TTFont(sys.argv[1])
removeUnusedNameRecords(font)
font["name"].removeUnusedNames(font)
font.save(sys.argv[2])