aboutsummaryrefslogtreecommitdiff
path: root/fonts/Input_Fonts/Scripts/inputCustomize.py
diff options
context:
space:
mode:
authorRyan Kavanagh <rak@rak.ac>2021-12-13 17:17:25 -0500
committerRyan Kavanagh <rak@rak.ac>2021-12-13 17:17:25 -0500
commit4d34ea76dd72cc811cb1e40bc5f91dc74b3e3dc3 (patch)
tree38ced096661c94646ab7c49a02011dec10f3a54c /fonts/Input_Fonts/Scripts/inputCustomize.py
parentdzen scripts are executable (diff)
update font handling
Diffstat (limited to 'fonts/Input_Fonts/Scripts/inputCustomize.py')
-rw-r--r--fonts/Input_Fonts/Scripts/inputCustomize.py274
1 files changed, 274 insertions, 0 deletions
diff --git a/fonts/Input_Fonts/Scripts/inputCustomize.py b/fonts/Input_Fonts/Scripts/inputCustomize.py
new file mode 100644
index 0000000..703c4f2
--- /dev/null
+++ b/fonts/Input_Fonts/Scripts/inputCustomize.py
@@ -0,0 +1,274 @@
+#!/usr/bin/env python2.6
+# -*- coding: utf-8 -*-
+
+# Thanks to Jonas Kjellström and Cody Boisclair for their help in finding bugs in this script!
+
+import re
+import os
+import sys
+import tempfile
+from fontTools.ttLib import TTFont, newTable
+
+doc = """USAGE: python /path/to/inputCustomize.py [INPUT] [--dest=OUTPUT] [OPTIONS]
+Use this script to customize one or more Input font files.
+Requires TTX/FontTools: <http://sourceforge.net/projects/fonttools/>
+
+If INPUT is missing, it will customize all fonts in the Current Working Directory.
+If OUTPUT is missing, it will overwrite the INPUT files.
+
+Options:
+ -h, --help Print this help text, and exit.
+ --lineHeight=<float> A multiplier for the font's built-in line-height.
+ --fourStyleFamily Only works when four INPUT files are provided.
+ Assigns Regular, Italic, Bold, and Bold Italic names to the
+ INPUT fonts in the order provided.
+ --suffix=<string> Append a suffix to the font names. Takes a string with no spaces.
+ --a=ss Swaps alternate single-story 'a' for the default double-story 'a'
+ --g=ss Swaps alternate single-story 'g' for the default double-story 'a'
+ --i=serif Swaps one of the alternate 'i' for the default in Sans/Mono
+ serifs
+ serifs_round
+ topserif
+ --l=serif Swaps one of the alternate 'l' for the default in Sans/Mono
+ serifs
+ serifs_round
+ topserif
+ --zero=slash Swaps the slashed zero for the default dotted zero
+ nodot Swaps a dotless zero for the default dotted zero
+ --asterisk=height Swaps the mid-height asterisk for the default superscripted asterisk
+ --braces=straight Swaps tamer straight-sided braces for the default super-curly braces
+
+ Example 1:
+ $ cd /path/to/the/top/level/of/the/fonts/you/want/to/edit
+ $ python /path/to/InputCustomize.py --dest=/path/to/output --lineHeight=1.5 --suffix=Hack --fourStyleFamily --a=ss --g=ss --i=topserif --l=serifs_round --zero=slash --asterisk=height
+
+ Example 2:
+ $ cd /path/to/the/top/level/of/the/fonts/you/want/to/edit
+ $ python /path/to/InputCustomize.py InputSans-Regular.ttf InputSans-Italic.ttf InputSans-Bold.ttf InputSerif-Regular.ttf --suffix=Hack --fourStyleFamily
+"""
+
+class InputModifier(object):
+ """
+ An object for manipulating Input, takes a TTFont. Sorry this is a little hacky.
+ """
+
+ def __init__(self, f):
+ self.f = f
+
+ def changeLineHeight(self, lineHeight):
+ """
+ Takes a line height multiplier and changes the line height.
+ """
+ f = self.f
+ baseAsc = f['OS/2'].sTypoAscender
+ baseDesc = f['OS/2'].sTypoDescender
+ multiplier = float(lineHeight)
+ f['hhea'].ascent = round(baseAsc * multiplier)
+ f['hhea'].descent = round(baseDesc * multiplier)
+ f['OS/2'].usWinAscent = round(baseAsc * multiplier)
+ f['OS/2'].usWinDescent = round(baseDesc * multiplier)*-1
+
+ def swap(self, swap):
+ """
+ Takes a dictionary of glyphs to swap and swaps 'em.
+ """
+ f = self.f
+ glyphNames = f.getGlyphNames()
+ maps = {
+ 'a': {'a': 97, 'aring': 229, 'adieresis': 228, 'acyrillic': 1072, 'aacute': 225, 'amacron': 257, 'agrave': 224, 'atilde': 227, 'acircumflex': 226, 'aogonek': 261, 'abreve': 259},
+ 'g': {'gdotaccent': 289, 'gbreve': 287, 'gcircumflex': 285, 'gcommaaccent': 291, 'g': 103},
+ 'i': {'i': 105, 'iacute': 237, 'iogonek': 303, 'igrave': 236, 'itilde': 297, 'icircumflex': 238, 'imacron': 299, 'ij': 307, 'ibreve': 301, 'yicyrillic': 1111, 'idieresis': 239, 'icyrillic': 1110, 'dotlessi': 305,},
+ 'l': {'l': 108, 'lcaron': 318, 'lcommaaccent': 316, 'lacute': 314, 'lslash': 322, 'ldot': 320},
+ 'zero': {'zero': 48},
+ 'asterisk': {'asterisk': 42},
+ 'braces': {'braceleft': 123, 'braceright': 125}
+ }
+ swapMap = {}
+ for k, v in swap.items():
+ for gname, u in maps[k].items():
+ newGname = gname + '.salt_' + v
+ if newGname in glyphNames:
+ swapMap[gname] = newGname
+ for table in f['cmap'].tables:
+ cmap = table.cmap
+ for u, gname in cmap.items():
+ if swapMap.has_key(gname):
+ cmap[u] = swapMap[gname]
+
+ def fourStyleFamily(self, position, suffix=None):
+ """
+ Replaces the name table and certain OS/2 values with those that will make a four-style family.
+ """
+ f = self.f
+ source = TTFont(fourStyleFamilySources[position])
+
+ tf = tempfile.mkstemp()
+ pathToXML = tf[1]
+ source.saveXML(pathToXML, tables=['name'])
+ os.close(tf[0])
+
+ with open(pathToXML, "r") as temp:
+ xml = temp.read()
+
+ # make the changes
+ if suffix:
+ xml = xml.replace("Input", "Input" + suffix)
+
+ # save the table
+ with open(pathToXML, 'w') as temp:
+ temp.write(xml)
+ temp.write('\r')
+
+ f['OS/2'].usWeightClass = source['OS/2'].usWeightClass
+ f['OS/2'].fsType = source['OS/2'].fsType
+
+ # write the table
+ f['name'] = newTable('name')
+ f.importXML(pathToXML)
+
+ def changeNames(self, suffix=None):
+ # this is a similar process to fourStyleFamily()
+
+ tf = tempfile.mkstemp()
+ pathToXML = tf[1]
+ f.saveXML(pathToXML, tables=['name'])
+ os.close(tf[0])
+
+ with open(pathToXML, "r") as temp:
+ xml = temp.read()
+
+ # make the changes
+ if suffix:
+ xml = xml.replace("Input", "Input" + suffix)
+
+ # save the table
+ with open(pathToXML, 'w') as temp:
+ temp.write(xml)
+ temp.write('\r')
+
+ # write the table
+ f['name'] = newTable('name')
+ f.importXML(pathToXML)
+
+
+
+
+
+baseTemplatePath = os.path.split(__file__)[0]
+fourStyleFamilySources = [
+ os.path.join(baseTemplatePath, '_template_Regular.txt'),
+ os.path.join(baseTemplatePath, '_template_Italic.txt'),
+ os.path.join(baseTemplatePath, '_template_Bold.txt'),
+ os.path.join(baseTemplatePath, '_template_BoldItalic.txt'),
+]
+
+fourStyleFileNameAppend = [ 'Regular', 'Italic', 'Bold', 'BoldItalic' ]
+
+if __name__ == "__main__":
+
+ # Get command-line arguments
+ go = True
+ arguments = sys.argv[1:]
+ paths = []
+ swap = {}
+ lineHeight = None
+ fourStyleFamily = None
+ suffix = None
+ destBase = None
+
+
+ # parse arguments
+ for argument in arguments:
+ key = None
+ value = None
+ if len(argument.split('=')) == 2:
+ key, value = argument.split('=')
+ key = key[2:]
+ elif argument[0:2] == '--':
+ key = argument[2:]
+ value = True
+ elif argument == '-h':
+ print doc
+ go = False
+ else:
+ key = argument
+ value = None
+ # assign preference variables
+ if value is None:
+ paths.append(key)
+ elif key == 'lineHeight':
+ lineHeight = value
+ elif key == 'fourStyleFamily':
+ fourStyleFamily = True
+ elif key == 'suffix':
+ suffix = value
+ elif key == 'dest':
+ destBase = value
+ elif key == 'help':
+ print doc
+ go = False
+ else:
+ swap[key] = value
+
+ # account for arguments where no value is given (for example, '--a' instead of '--a=ss')
+ if swap.get('a') is True:
+ swap['a'] = 'ss'
+ if swap.get('g') is True:
+ swap['g'] = 'ss'
+ if swap.get('i') is True:
+ swap['i'] = 'serifs'
+ if swap.get('l') is True:
+ swap['l'] = 'serifs'
+ if swap.get('zero') is True:
+ swap['zero'] = 'slash'
+ if swap.get('asterisk') is True:
+ swap['asterisk'] = 'height'
+ if swap.get('braces') is True:
+ swap['braces'] = 'straight'
+
+
+ # if specific paths were not supplied, collect them from the current directory
+ if not paths:
+ for root, dirs, files in os.walk(os.getcwd()):
+ for filename in files:
+ basePath, ext = os.path.splitext(filename)
+ if ext in ['.otf', '.ttf']:
+ paths.append(os.path.join(root, filename))
+
+ # if four paths were not supplied, do not process as a four-style family
+ if len(paths) != 4:
+ fourStyleFamily = None
+
+ if go:
+ for i, path in enumerate(paths):
+ print os.path.split(path)[1]
+ f = TTFont(path)
+ c = InputModifier(f)
+ if lineHeight:
+ c.changeLineHeight(lineHeight)
+ if swap:
+ c.swap(swap)
+ if fourStyleFamily:
+ c.fourStyleFamily(i, suffix)
+ base, ext = os.path.splitext(path)
+ path = base + '_as_' + fourStyleFileNameAppend[i] + ext
+ elif suffix:
+ c.changeNames(suffix)
+ if destBase:
+ baseScrap, fileAndExt = os.path.split(path)
+ destPath = os.path.join(destBase, fileAndExt)
+ else:
+ destPath = path
+ try:
+ os.remove(destPath)
+ except:
+ pass
+
+ # Take care of that weird "post" table issue, just in case. Delta#1
+ try:
+ del f['post'].mapping['Delta#1']
+ except:
+ pass
+
+ f.save(destPath)
+ print 'done'