You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
170 lines
5.5 KiB
170 lines
5.5 KiB
#!/usr/bin/env python3
|
|
"""Script to add a suffix to all family names in the input font's `name` table,
|
|
and to optionally rename the output files with the given suffix.
|
|
|
|
The current family name substring is searched in the nameIDs 1, 3, 4, 6, 16,
|
|
and 21, and if found the suffix is inserted after it; or else the suffix is
|
|
appended at the end.
|
|
"""
|
|
import os
|
|
import argparse
|
|
import logging
|
|
from fontTools.ttLib import TTFont
|
|
from fontTools.misc.cliTools import makeOutputFileName
|
|
|
|
|
|
logger = logging.getLogger()
|
|
|
|
WINDOWS_ENGLISH_IDS = 3, 1, 0x409
|
|
MAC_ROMAN_IDS = 1, 0, 0
|
|
|
|
FAMILY_RELATED_IDS = dict(
|
|
LEGACY_FAMILY=1,
|
|
TRUETYPE_UNIQUE_ID=3,
|
|
FULL_NAME=4,
|
|
POSTSCRIPT_NAME=6,
|
|
PREFERRED_FAMILY=16,
|
|
WWS_FAMILY=21,
|
|
)
|
|
|
|
|
|
def get_current_family_name(table):
|
|
family_name_rec = None
|
|
for plat_id, enc_id, lang_id in (WINDOWS_ENGLISH_IDS, MAC_ROMAN_IDS):
|
|
for name_id in (
|
|
FAMILY_RELATED_IDS["PREFERRED_FAMILY"],
|
|
FAMILY_RELATED_IDS["LEGACY_FAMILY"],
|
|
):
|
|
family_name_rec = table.getName(
|
|
nameID=name_id,
|
|
platformID=plat_id,
|
|
platEncID=enc_id,
|
|
langID=lang_id,
|
|
)
|
|
if family_name_rec is not None:
|
|
break
|
|
if family_name_rec is not None:
|
|
break
|
|
if not family_name_rec:
|
|
raise ValueError("family name not found; can't add suffix")
|
|
return family_name_rec.toUnicode()
|
|
|
|
|
|
def insert_suffix(string, family_name, suffix):
|
|
# check whether family_name is a substring
|
|
start = string.find(family_name)
|
|
if start != -1:
|
|
# insert suffix after the family_name substring
|
|
end = start + len(family_name)
|
|
new_string = string[:end] + suffix + string[end:]
|
|
else:
|
|
# it's not, we just append the suffix at the end
|
|
new_string = string + suffix
|
|
return new_string
|
|
|
|
|
|
def rename_record(name_record, family_name, suffix):
|
|
string = name_record.toUnicode()
|
|
new_string = insert_suffix(string, family_name, suffix)
|
|
name_record.string = new_string
|
|
return string, new_string
|
|
|
|
|
|
def rename_file(filename, family_name, suffix):
|
|
filename, ext = os.path.splitext(filename)
|
|
ps_name = family_name.replace(" ", "")
|
|
if ps_name in filename:
|
|
ps_suffix = suffix.replace(" ", "")
|
|
return insert_suffix(filename, ps_name, ps_suffix) + ext
|
|
else:
|
|
return insert_suffix(filename, family_name, suffix) + ext
|
|
|
|
|
|
def add_family_suffix(font, suffix):
|
|
table = font["name"]
|
|
|
|
family_name = get_current_family_name(table)
|
|
logger.info(" Current family name: '%s'", family_name)
|
|
|
|
# postcript name can't contain spaces
|
|
ps_family_name = family_name.replace(" ", "")
|
|
ps_suffix = suffix.replace(" ", "")
|
|
for rec in table.names:
|
|
name_id = rec.nameID
|
|
if name_id not in FAMILY_RELATED_IDS.values():
|
|
continue
|
|
if name_id == FAMILY_RELATED_IDS["POSTSCRIPT_NAME"]:
|
|
old, new = rename_record(rec, ps_family_name, ps_suffix)
|
|
elif name_id == FAMILY_RELATED_IDS["TRUETYPE_UNIQUE_ID"]:
|
|
# The Truetype Unique ID rec may contain either the PostScript
|
|
# Name or the Full Name string, so we try both
|
|
if ps_family_name in rec.toUnicode():
|
|
old, new = rename_record(rec, ps_family_name, ps_suffix)
|
|
else:
|
|
old, new = rename_record(rec, family_name, suffix)
|
|
else:
|
|
old, new = rename_record(rec, family_name, suffix)
|
|
logger.info(" %r: '%s' -> '%s'", rec, old, new)
|
|
|
|
return family_name
|
|
|
|
|
|
def main(args=None):
|
|
parser = argparse.ArgumentParser(
|
|
description=__doc__,
|
|
formatter_class=argparse.RawDescriptionHelpFormatter,
|
|
)
|
|
parser.add_argument("-s", "--suffix", required=True)
|
|
parser.add_argument("input_fonts", metavar="FONTFILE", nargs="+")
|
|
output_group = parser.add_mutually_exclusive_group()
|
|
output_group.add_argument("-i", "--inplace", action="store_true")
|
|
output_group.add_argument("-d", "--output-dir")
|
|
output_group.add_argument("-o", "--output-file")
|
|
parser.add_argument("-R", "--rename-files", action="store_true")
|
|
parser.add_argument("-v", "--verbose", action="count", default=0)
|
|
options = parser.parse_args(args)
|
|
|
|
if not options.verbose:
|
|
level = "WARNING"
|
|
elif options.verbose == 1:
|
|
level = "INFO"
|
|
else:
|
|
level = "DEBUG"
|
|
logging.basicConfig(level=level, format="%(message)s")
|
|
|
|
if options.output_file and len(options.input_fonts) > 1:
|
|
parser.error(
|
|
"argument -o/--output-file can't be used with multiple inputs"
|
|
)
|
|
if options.rename_files and (options.inplace or options.output_file):
|
|
parser.error("argument -R not allowed with arguments -i or -o")
|
|
|
|
for input_name in options.input_fonts:
|
|
logger.info("Renaming font: '%s'", input_name)
|
|
|
|
font = TTFont(input_name)
|
|
family_name = add_family_suffix(font, options.suffix)
|
|
|
|
if options.inplace:
|
|
output_name = input_name
|
|
elif options.output_file:
|
|
output_name = options.output_file
|
|
else:
|
|
if options.rename_files:
|
|
input_name = rename_file(
|
|
input_name, family_name, options.suffix
|
|
)
|
|
output_name = makeOutputFileName(input_name, options.output_dir)
|
|
|
|
font.save(output_name)
|
|
logger.info("Saved font: '%s'", output_name)
|
|
|
|
font.close()
|
|
del font
|
|
|
|
logger.info("Done!")
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|