135 lines
4.7 KiB
Python
135 lines
4.7 KiB
Python
#!/usr/bin/env python3
|
|
|
|
# ==========================================================================
|
|
# fontname.py
|
|
# Copyright 2019 Christopher Simpkins
|
|
# MIT License
|
|
#
|
|
# Dependencies:
|
|
# 1) Python 3.6+ interpreter
|
|
# 2) fonttools Python library (https://github.com/fonttools/fonttools)
|
|
# - install with `pip3 install fonttools`
|
|
#
|
|
# Usage:
|
|
# python3 fontname.py [FONT FAMILY NAME] [FONT PATH 1] <FONT PATH ...>
|
|
#
|
|
# Notes:
|
|
# Use quotes around font family name arguments that include spaces
|
|
# ===========================================================================
|
|
|
|
import os
|
|
import sys
|
|
|
|
from fontTools import ttLib
|
|
|
|
|
|
def main(argv):
|
|
# command argument tests
|
|
print(" ")
|
|
if len(argv) < 2:
|
|
sys.stderr.write(
|
|
f"[fontname.py] ERROR: you did not include enough arguments to the script.{os.linesep}"
|
|
)
|
|
sys.stderr.write(
|
|
f"Usage: python3 fontname.py [FONT FAMILY NAME] [FONT PATH 1] <FONT PATH ...>{os.linesep}"
|
|
)
|
|
sys.exit(1)
|
|
|
|
# begin parsing command line arguments
|
|
try:
|
|
font_name = str(argv[0]) # the first argument is the new typeface name
|
|
except Exception as e:
|
|
sys.stderr.write(
|
|
f"[fontname.py] ERROR: Unable to convert argument to string. {e}{os.linesep}"
|
|
)
|
|
sys.exit(1)
|
|
|
|
# all remaining arguments on command line are file paths to fonts
|
|
font_path_list = argv[1:]
|
|
|
|
# iterate through all paths provided on command line and rename to `font_name` defined by user
|
|
for font_path in font_path_list:
|
|
# test for existence of font file on requested file path
|
|
if not file_exists(font_path):
|
|
sys.stderr.write(
|
|
f"[fontname.py] ERROR: the path '{font_path}' does not appear to be a valid file path.{os.linesep}"
|
|
)
|
|
sys.exit(1)
|
|
|
|
tt = ttLib.TTFont(font_path)
|
|
namerecord_list = tt["name"].names
|
|
|
|
style = ""
|
|
|
|
# determine font style for this file path from name record nameID 2
|
|
for record in namerecord_list:
|
|
if record.nameID == 2:
|
|
style = str(record)
|
|
break
|
|
|
|
# test that a style name was found in the OpenType tables of the font
|
|
if len(style) == 0:
|
|
sys.stderr.write(
|
|
f"[fontname.py] Unable to detect the font style from the OpenType name table in '{font_path}'. {os.linesep}"
|
|
)
|
|
sys.stderr.write("Unable to complete execution of the script.")
|
|
sys.exit(1)
|
|
else:
|
|
# used for the Postscript name in the name table (no spaces allowed)
|
|
postscript_font_name = font_name.replace(" ", "")
|
|
# font family name
|
|
nameID1_string = font_name
|
|
nameID16_string = font_name
|
|
# full font name
|
|
nameID4_string = f"{font_name} {style}"
|
|
# Postscript name
|
|
# - no spaces allowed in family name or the PostScript suffix. should be dash delimited
|
|
nameID6_string = f"{postscript_font_name}-{style.replace(' ', '')}"
|
|
# nameID6_string = postscript_font_name + "-" + style.replace(" ", "")
|
|
|
|
# modify the opentype table data in memory with updated values
|
|
for record in namerecord_list:
|
|
if record.nameID == 1:
|
|
record.string = nameID1_string
|
|
elif record.nameID == 4:
|
|
record.string = nameID4_string
|
|
elif record.nameID == 6:
|
|
record.string = nameID6_string
|
|
elif record.nameID == 16:
|
|
record.string = nameID16_string
|
|
|
|
# CFF table naming for CFF fonts (only)
|
|
if "CFF " in tt:
|
|
try:
|
|
cff = tt["CFF "]
|
|
cff.cff[0].FamilyName = nameID1_string
|
|
cff.cff[0].FullName = nameID4_string
|
|
cff.cff.fontNames = [nameID6_string]
|
|
except Exception as e:
|
|
sys.stderr.write(
|
|
f"[fontname.py] ERROR: unable to write new names to CFF table: {e}"
|
|
)
|
|
|
|
# write changes to the font file
|
|
try:
|
|
tt.save(font_path)
|
|
print(f"[OK] Updated '{font_path}' with the name '{nameID4_string}'")
|
|
except Exception as e:
|
|
sys.stderr.write(
|
|
f"[fontname.py] ERROR: unable to write new name to OpenType name table for '{font_path}'. {os.linesep}"
|
|
)
|
|
sys.stderr.write(f"{e}{os.linesep}")
|
|
sys.exit(1)
|
|
|
|
|
|
# Utilities
|
|
|
|
|
|
def file_exists(filepath):
|
|
"""Tests for existence of a file on the string filepath"""
|
|
return os.path.exists(filepath) and os.path.isfile(filepath)
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main(sys.argv[1:])
|