Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Remove redundant name table records #3185

Merged
merged 7 commits into from
Jul 12, 2023
Merged
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
94 changes: 94 additions & 0 deletions Snippets/clean-nametable.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
#!/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):
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe remove this from the visitor object, move it somewhere else.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for looking. I've moved and converted the function so it's a static method of the name table. Imo it feels like belongs here. Happy to drop the static method and just have it as a plain func instead. I've moved it away from the Snippets dir so it can be imported into other libs and tools.

Happy to add tests if you're ok with the above. Still not too sure if I've found all the places in a font which can have a nameID though.

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():
if len(sys.argv) != 3:
print("Usage: python nameClean.py font.ttf out.ttf")
sys.exit()
font = TTFont(sys.argv[1])
removeUnusedNameRecords(font)
font.save(sys.argv[2])


if __name__ == "__main__":
main()