-
Notifications
You must be signed in to change notification settings - Fork 0
/
fontname.py
134 lines (113 loc) · 4.71 KB
/
fontname.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
#!/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:])