Add a script to rename fonts for SDK. [DO NOT MERGE]

Create a script that will rename the PS name encoded in the font that is
to be shipped with the SDK.

This commit is a combination of 5 commits:
e0660d31c256e02e5f5e2967508a7205d1f62f86
7e149f02c4e4403101e7e0e88af36cd4ab6f3554
66d3314301a8983c7070a15ea68daacc7300b7f2
c6364fd90de1600526d3431ce0740b6b856e48f0
2d8c52dc4502b8407705d5b6efe628cb657b20b4

Change-Id: I675a98db39fea4525e3673656af1764eb7e5bb96
This commit is contained in:
Deepanshu Gupta
2014-05-15 18:39:30 -07:00
parent 80e84e2db9
commit c57b410c8e
4 changed files with 207 additions and 0 deletions

View File

@ -0,0 +1,9 @@
This tool is used to rename the PS name encoded inside the ttf font that we ship
with the SDK. There is bug in Java that returns incorrect results for
java.awt.Font#layoutGlyphVector() if two fonts with same name but differnt
versions are loaded. As a workaround, we rename all the fonts that we ship with
the SDK by appending the font version to its name.
The build_font.py copies all files from input_dir to output_dir while renaming
the font files (*.ttf) in the process.

Binary file not shown.

View File

@ -0,0 +1,154 @@
#!/usr/bin/env python
# Copyright (C) 2014 The Android Open Source Project
#
# Licensed under the Apache License, Version 2.0 (the 'License');
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an 'AS IS' BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
"""
Rename the PS name of all fonts in the input directories and copy them to the
output directory.
Usage: build_font.py /path/to/input_fonts1/ /path/to/input_fonts2/ /path/to/output_fonts/
"""
import sys
# fontTools is available at platform/external/fonttools
from fontTools import ttx
import re
import os
import xml.etree.ElementTree as etree
import shutil
import glob
from multiprocessing import Pool
# global variable
dest_dir = '/tmp'
def main(argv):
if len(argv) < 2:
sys.exit('Usage: build_font.py /path/to/input_fonts/ /path/to/out/dir/')
for directory in argv:
if not os.path.isdir(directory):
sys.exit(directory + ' is not a valid directory')
global dest_dir
dest_dir = argv[-1]
src_dirs = argv[:-1]
cwd = os.getcwd()
os.chdir(dest_dir)
files = glob.glob('*')
for filename in files:
os.remove(filename)
os.chdir(cwd)
input_fonts = list()
for src_dir in src_dirs:
for dirname, dirnames, filenames in os.walk(src_dir):
for filename in filenames:
input_path = os.path.join(dirname, filename)
extension = os.path.splitext(filename)[1].lower()
if (extension == '.ttf'):
input_fonts.append(input_path)
elif (extension == '.xml'):
shutil.copy(input_path, dest_dir)
if '.git' in dirnames:
# don't go into any .git directories.
dirnames.remove('.git')
# Create as many threads as the number of CPUs
pool = Pool(processes=None)
pool.map(convert_font, input_fonts)
class InvalidFontException(Exception):
pass
def convert_font(input_path):
filename = os.path.basename(input_path)
print 'Converting font: ' + filename
# the path to the output file. The file name is the fontfilename.ttx
ttx_path = os.path.join(dest_dir, filename)
ttx_path = ttx_path[:-1] + 'x'
try:
# run ttx to generate an xml file in the output folder which represents all
# its info
ttx_args = ['-q', '-d', dest_dir, input_path]
ttx.main(ttx_args)
# now parse the xml file to change its PS name.
tree = etree.parse(ttx_path)
root = tree.getroot()
for name in root.iter('name'):
[old_ps_name, version] = get_font_info(name)
if old_ps_name is not None and version is not None:
new_ps_name = old_ps_name + version
update_name(name, new_ps_name)
tree.write(ttx_path, xml_declaration=True, encoding='utf-8' )
# generate the udpated font now.
ttx_args = ['-q', '-d', dest_dir, ttx_path]
ttx.main(ttx_args)
except InvalidFontException:
# In case of invalid fonts, we exit.
print filename + ' is not a valid font'
raise
except Exception as e:
print 'Error converting font: ' + filename
print e
# Some fonts are too big to be handled by the ttx library.
# Just copy paste them.
shutil.copy(input_path, dest_dir)
try:
# delete the temp ttx file is it exists.
os.remove(ttx_path)
except OSError:
pass
def get_font_info(tag):
ps_name = None
ps_version = None
for namerecord in tag.iter('namerecord'):
if 'nameID' in namerecord.attrib:
# if the tag has nameID=6, it is the postscript name of the font.
# see: http://scripts.sil.org/cms/scripts/page.php?item_id=IWS-Chapter08#3054f18b
if namerecord.attrib['nameID'] == '6':
if ps_name is not None:
if not sanitize(namerecord.text) == ps_name:
raise InvalidFontException('found multiple possibilities of the font name')
else:
ps_name = sanitize(namerecord.text)
# nameID=5 means the font version
if namerecord.attrib['nameID'] == '5':
if ps_version is not None:
if not ps_version == get_version(namerecord.text):
raise InvalidFontException('found multiple possibilities of the font version')
else:
ps_version = get_version(namerecord.text)
return [ps_name, ps_version]
def update_name(tag, name):
for namerecord in tag.iter('namerecord'):
if 'nameID' in namerecord.attrib:
if namerecord.attrib['nameID'] == '6':
namerecord.text = name
def sanitize(string):
return re.sub(r'[^\w-]+', '', string)
def get_version(string):
# The string must begin with 'Version n.nn '
# to extract n.nn, we return the second entry in the split strings.
string = string.strip()
if not string.startswith('Version '):
raise InvalidFontException('mal-formed font version')
return sanitize(string.split()[1])
if __name__ == '__main__':
main(sys.argv[1:])

View File

@ -0,0 +1,44 @@
#!/usr/bin/env python
"""Tests build_font.py by renaming a font.
The test copies Roboto-Regular.ttf to a tmp directory and ask build_font.py to rename it and put in another dir.
We then use ttx to dump the new font to its xml and check if rename was successful
To test locally, use:
PYTHONPATH="$PYTHONPATH:/path/to/android/checkout/external/fonttools/Lib" ./test.py
"""
import unittest
import build_font
from fontTools import ttx
import os
import xml.etree.ElementTree as etree
import shutil
import tempfile
class MyTest(unittest.TestCase):
def test(self):
font_name = "Roboto-Regular.ttf"
srcdir = tempfile.mkdtemp()
print "srcdir: " + srcdir
shutil.copy(font_name, srcdir)
destdir = tempfile.mkdtemp()
print "destdir: " + destdir
self.assertTrue(build_font.main([srcdir, destdir]) is None)
out_path = os.path.join(destdir, font_name)
ttx.main([out_path])
ttx_path = out_path[:-1] + "x"
tree = etree.parse(ttx_path)
root = tree.getroot()
name_tag = root.find('name')
[f_name, f_version] = build_font.get_font_info(name_tag)
shutil.rmtree(srcdir)
shutil.rmtree(destdir)
self.assertEqual(f_name, "Roboto-Regular1200310")
if __name__ == '__main__':
unittest.main()