-
Notifications
You must be signed in to change notification settings - Fork 154
/
Copy pathaddSVGtable.py
executable file
·200 lines (159 loc) · 5.63 KB
/
addSVGtable.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
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
#!/usr/bin/env python3
"""
Adds an SVG table to a TTF or OTF font.
The file names of the SVG glyphs need to match their corresponding glyph final names.
"""
import os
import sys
import re
try:
from fontTools import ttLib
except ImportError:
print("ERROR: FontTools Python module is not installed.", file=sys.stderr)
sys.exit(1)
TABLE_TAG = 'SVG '
# Regexp patterns
reSVGelement = re.compile(r"<svg.+?>.+?</svg>", re.DOTALL)
reIDvalue = re.compile(r"<svg[^>]+?(id=\".*?\").+?>", re.DOTALL)
reViewBox = re.compile(r"<svg.+?(viewBox=[\"|\'][\d, ]+[\"|\']).+?>", re.DOTALL)
reWhiteSpace = re.compile(r">\s+<", re.DOTALL)
def readFile(filePath):
with open(filePath, "rt") as f:
return f.read()
def setIDvalue(data, gid):
id = reIDvalue.search(data)
if id:
newData = re.sub(id.group(1), 'id="glyph{}"'.format(gid), data)
else:
newData = re.sub('<svg', '<svg id="glyph{}"'.format(gid), data)
return newData
def fixViewBox(data):
viewBox = reViewBox.search(data)
if not viewBox:
return data
fixedViewBox = 'viewBox=\"0 1000 1000 1000\"'
fixedData = re.sub(viewBox.group(1), fixedViewBox, data)
return fixedData
def getGlyphNameFromFileName(filePath):
folderPath, fontFileName = os.path.split(filePath)
fileNameNoExtension, fileExtension = os.path.splitext(fontFileName)
return fileNameNoExtension
def processFontFile(fontFilePath, svgFilePathsList):
font = ttLib.TTFont(fontFilePath)
# first create a dictionary because the SVG glyphs need to be sorted in the table
svgDocsDict = {}
for svgFilePath in svgFilePathsList:
gName = getGlyphNameFromFileName(svgFilePath)
try:
gid = font.getGlyphID(gName)
except KeyError:
print(
"ERROR: Could not find a glyph named {} in the font {}.".format(
gName, os.path.split(fontFilePath)[1]
),
file=sys.stderr
)
continue
svgItemsList = []
svgItemData = readFile(svgFilePath)
svgItemData = setIDvalue(svgItemData, gid)
svgItemData = fixViewBox(svgItemData)
# Remove all white space between elements
for whiteSpace in set(reWhiteSpace.findall(svgItemData)):
svgItemData = svgItemData.replace(whiteSpace, '><')
svgItemsList.append(svgItemData.strip())
svgItemsList.extend([gid, gid])
svgDocsDict[gid] = svgItemsList
# don't do any changes to the source OTF/TTF font if there's no SVG data
if not svgDocsDict:
print(
"ERROR: Could not find any artwork files "
"that can be added to the font.",
file=sys.stderr
)
return
svgDocsList = [svgDocsDict[index] for index in sorted(svgDocsDict.keys())]
svgTable = ttLib.newTable(TABLE_TAG)
svgTable.compressed = False # GZIP the SVG docs
svgTable.docList = svgDocsList
font[TABLE_TAG] = svgTable
font.save(fontFilePath)
font.close()
print(
"SVG table successfully added to {}".format(fontFilePath),
file=sys.stderr
)
def validateSVGfiles(svgFilePathsList):
"""
Light validation of SVG files.
Checks that there is an <svg> element.
"""
validatedPaths = []
for filePath in svgFilePathsList:
# skip hidden files (filenames that start with period)
fileName = os.path.basename(filePath)
if fileName[0] == '.':
continue
# read file
data = readFile(filePath)
# find <svg> blob
svg = reSVGelement.search(data)
if not svg:
print(
"WARNING: Could not find <svg> element in the file. "
"Skiping {}".format(filePath)
)
continue
validatedPaths.append(filePath)
return validatedPaths
def getFontFormat(fontFilePath):
# these lines were scavenged from fontTools
with open(fontFilePath, "rb") as f:
header = f.read(256)
head = header[:4]
if head == b"OTTO":
return "OTF"
elif head in (b"\0\1\0\0", b"true"):
return "TTF"
return None
def run():
fontFilePath = os.path.realpath(sys.argv[1])
svgFolderPath = os.path.realpath(sys.argv[2])
# Font file path
if os.path.isfile(fontFilePath):
if getFontFormat(fontFilePath) not in ["OTF", "TTF"]:
print("ERROR: The path is not a valid OTF or TTF font.",
file=sys.stderr)
return
else:
print("ERROR: The path to the font is invalid.",
file=sys.stderr)
return
# SVG folder path
if os.path.isdir(svgFolderPath):
svgFilePathsList = []
for dirName, subdirList, fileList in os.walk(
svgFolderPath): # Support nested folders
for file in fileList:
svgFilePathsList.append(os.path.join(dirName,
file)) # Assemble the full paths, not just file names
else:
print(
"ERROR: The path to the folder "
"containing the SVG files is invalid.",
file=sys.stderr
)
return
# validate the SVGs
svgFilePathsList = validateSVGfiles(svgFilePathsList)
if not svgFilePathsList:
print("WARNING: No SVG files were found.", file=sys.stderr)
return
processFontFile(fontFilePath, svgFilePathsList)
if __name__ == "__main__":
if len(sys.argv) != 3:
print("To run this script type:\n "
"python {} <path to input OTF/TTF file> "
"<path to folder tree containing SVG files>".format(sys.argv[0]))
else:
run()