2017-08-22 10:05:20 +03:00
|
|
|
#!/usr/bin/env python
|
|
|
|
import os
|
|
|
|
import sys
|
|
|
|
import argparse
|
|
|
|
import logging
|
|
|
|
import subprocess
|
|
|
|
|
2017-08-25 04:27:00 +03:00
|
|
|
from shutil import copyfile
|
2017-08-22 10:05:20 +03:00
|
|
|
from robofab.objects.objectsRF import RPoint
|
|
|
|
from robofab.world import OpenFont
|
|
|
|
from fontbuild.Build import FontProject
|
|
|
|
from fontbuild.mix import Master
|
|
|
|
from fontbuild.mix import Mix
|
|
|
|
|
2017-09-04 06:03:17 +03:00
|
|
|
|
2017-09-19 01:58:34 +03:00
|
|
|
FAMILYNAME = "Inter UI"
|
2017-08-22 10:05:20 +03:00
|
|
|
BASEDIR = os.path.abspath(os.path.join(os.path.dirname(__file__), os.pardir))
|
|
|
|
|
|
|
|
def extractSpecializedGlyphs(masterFont):
|
|
|
|
glyphSpecializations = {}
|
|
|
|
specializationSuffix = '.specz.'
|
|
|
|
|
|
|
|
specializedGlyphNames = []
|
|
|
|
font = masterFont.font
|
|
|
|
for g in font:
|
|
|
|
p = g.name.find(specializationSuffix)
|
|
|
|
if p == -1:
|
|
|
|
continue
|
|
|
|
name = g.name[:p]
|
|
|
|
category = g.name[p + len(specializationSuffix):]
|
|
|
|
g2 = g.copy()
|
|
|
|
g2.name = name
|
|
|
|
if name in font:
|
|
|
|
# copy unicodes
|
|
|
|
masterGlyph = font[name]
|
|
|
|
g2.unicodes = masterGlyph.unicodes
|
|
|
|
if not category in glyphSpecializations:
|
|
|
|
glyphSpecializations[category] = { name: g2 }
|
|
|
|
else:
|
|
|
|
glyphSpecializations[category][name] = g2
|
|
|
|
specializedGlyphNames.append(g.name)
|
|
|
|
|
|
|
|
ffont = masterFont.ffont
|
|
|
|
for name in specializedGlyphNames:
|
|
|
|
del ffont.glyphs[name]
|
|
|
|
font.removeGlyph(name)
|
|
|
|
|
|
|
|
return glyphSpecializations
|
|
|
|
|
|
|
|
|
|
|
|
def readVersionControlTag(dir):
|
|
|
|
try:
|
|
|
|
return subprocess.check_output(
|
|
|
|
['git', '-C', dir, 'rev-parse', '--short', 'HEAD'],
|
|
|
|
shell=False).strip()
|
|
|
|
except:
|
|
|
|
return ''
|
|
|
|
|
|
|
|
|
2017-09-04 06:03:17 +03:00
|
|
|
def main():
|
|
|
|
# silence warnings from fontTools.misc.fixedTools that is harmless and caused by
|
|
|
|
# the ufo2ft module.
|
|
|
|
logging.getLogger('fontTools.misc.fixedTools').setLevel(logging.ERROR)
|
|
|
|
|
|
|
|
default_out_dir = os.path.join(BASEDIR,'build','tmp')
|
|
|
|
srcDir = os.path.join(BASEDIR, 'src')
|
|
|
|
|
|
|
|
argparser = argparse.ArgumentParser(description='Build TTF and OTF font files from UFO sources.')
|
2017-08-22 10:05:20 +03:00
|
|
|
|
2017-09-04 06:03:17 +03:00
|
|
|
argparser.add_argument('styles', metavar='<style>', type=str, nargs='*',
|
|
|
|
help='Build specific styles. Omit to build all.')
|
2017-08-22 10:05:20 +03:00
|
|
|
|
2017-09-04 06:03:17 +03:00
|
|
|
argparser.add_argument('--otf', dest='otf', action='store_const',
|
|
|
|
const=True, default=False,
|
|
|
|
help='Build OTF files')
|
2017-08-22 10:05:20 +03:00
|
|
|
|
2017-09-04 06:03:17 +03:00
|
|
|
argparser.add_argument('--no-ttf', dest='no_ttf', action='store_const',
|
|
|
|
const=True, default=False,
|
|
|
|
help='Do not build TTF files')
|
2017-08-22 10:05:20 +03:00
|
|
|
|
2017-09-04 06:03:17 +03:00
|
|
|
argparser.add_argument('--out', dest='out', metavar='<dir>', type=str,
|
|
|
|
default=default_out_dir,
|
|
|
|
help='Write output to <dir> instead of the default (%r)' % default_out_dir)
|
2017-08-22 10:05:20 +03:00
|
|
|
|
2017-09-04 06:03:17 +03:00
|
|
|
args = argparser.parse_args()
|
|
|
|
styles = [s.lower() for s in args.styles]
|
|
|
|
ALL = len(styles) == 0
|
2017-08-22 10:05:20 +03:00
|
|
|
|
2017-09-04 06:03:17 +03:00
|
|
|
# version control tag, if any
|
|
|
|
buildTag = readVersionControlTag(BASEDIR)
|
2017-08-22 10:05:20 +03:00
|
|
|
|
2017-09-04 06:03:17 +03:00
|
|
|
# Since we reference a shared feature file, copy it to build dir so includes works
|
2017-09-19 01:58:34 +03:00
|
|
|
ufoTmpDir = os.path.join(args.out, 'InterUIUFO')
|
2017-09-05 18:06:04 +03:00
|
|
|
try:
|
|
|
|
os.makedirs(ufoTmpDir)
|
|
|
|
except:
|
|
|
|
pass
|
2017-09-04 06:03:17 +03:00
|
|
|
copyfile(
|
|
|
|
os.path.join(srcDir, 'features.fea'),
|
|
|
|
os.path.join(ufoTmpDir, 'features.fea'))
|
2017-08-22 10:05:20 +03:00
|
|
|
|
2017-09-04 06:03:17 +03:00
|
|
|
# Load masters
|
|
|
|
print('loading master: Regular')
|
2017-09-19 01:58:34 +03:00
|
|
|
rg = Master("%s/src/Inter-UI-Regular.ufo" % BASEDIR)
|
2017-08-22 10:05:20 +03:00
|
|
|
|
2017-09-05 18:06:04 +03:00
|
|
|
bl = None
|
|
|
|
if ALL \
|
|
|
|
or 'black' in styles or 'blackitalic' in styles \
|
|
|
|
or 'bold' in styles or 'bolditalic' in styles \
|
|
|
|
or 'medium' in styles or 'mediumitalic' in styles:
|
|
|
|
print('loading master: Black')
|
2017-09-19 01:58:34 +03:00
|
|
|
bl = Master("%s/src/Inter-UI-Black.ufo" % BASEDIR)
|
2017-08-25 04:27:00 +03:00
|
|
|
|
2017-08-22 10:05:20 +03:00
|
|
|
|
2017-09-04 06:03:17 +03:00
|
|
|
glyphSpecializations = extractSpecializedGlyphs(rg)
|
2017-08-22 10:05:20 +03:00
|
|
|
|
|
|
|
|
2017-09-04 06:03:17 +03:00
|
|
|
class Mix2(Mix):
|
|
|
|
def __init__(self, masters, v, glyphSpecializations=None):
|
|
|
|
Mix.__init__(self, masters, v)
|
|
|
|
self.glyphSpecializations = glyphSpecializations
|
2017-08-22 10:05:20 +03:00
|
|
|
|
2017-09-04 06:03:17 +03:00
|
|
|
def mixGlyphs(self, gname):
|
|
|
|
if self.glyphSpecializations is not None:
|
|
|
|
specializedGlyph = self.glyphSpecializations.get(gname)
|
|
|
|
if specializedGlyph is not None:
|
|
|
|
print 'mixglyph using specialized', gname
|
|
|
|
return specializedGlyph
|
|
|
|
return Mix.mixGlyphs(self, gname)
|
2017-08-22 10:05:20 +03:00
|
|
|
|
2017-09-04 06:03:17 +03:00
|
|
|
proj = FontProject(rg.font, BASEDIR, os.path.join(srcDir,'fontbuild.cfg'), buildTag=buildTag)
|
|
|
|
proj.builddir = args.out
|
2017-08-22 10:05:20 +03:00
|
|
|
|
|
|
|
|
2017-09-04 06:03:17 +03:00
|
|
|
if args.otf:
|
|
|
|
proj.buildOTF = True
|
2017-08-22 10:05:20 +03:00
|
|
|
|
2017-09-04 06:03:17 +03:00
|
|
|
# name syntax: family/longstyle/shortstyle/subfamilyAbbrev
|
2017-08-25 04:27:00 +03:00
|
|
|
|
2017-09-04 06:03:17 +03:00
|
|
|
if ALL or 'regular' in styles:
|
|
|
|
proj.generateFont(rg.font, "%s/Regular/Regular/Rg" % FAMILYNAME)
|
2017-08-22 10:05:20 +03:00
|
|
|
|
2017-09-04 06:03:17 +03:00
|
|
|
if ALL or 'regularitalic' in styles:
|
|
|
|
proj.generateFont(rg.font, "%s/Regular Italic/Italic/Rg" % FAMILYNAME,
|
|
|
|
italic=True, stemWidth=232, italicMeanYCenter=-825, italicNarrowAmount=1)
|
2017-08-22 10:05:20 +03:00
|
|
|
|
2017-09-05 18:06:04 +03:00
|
|
|
|
2017-09-04 06:03:17 +03:00
|
|
|
if ALL or 'medium' in styles:
|
|
|
|
proj.generateFont(
|
2017-09-05 18:06:04 +03:00
|
|
|
Mix2([rg, bl], 0.35, glyphSpecializations.get('medium', {})),
|
|
|
|
"%s/Medium/Regular/Me" % FAMILYNAME)
|
2017-08-22 10:05:20 +03:00
|
|
|
|
2017-09-04 06:03:17 +03:00
|
|
|
if ALL or 'mediumitalic' in styles:
|
|
|
|
proj.generateFont(
|
2017-09-05 18:06:04 +03:00
|
|
|
Mix2([rg, bl], 0.35, glyphSpecializations.get('medium', {})),
|
|
|
|
"%s/Medium Italic/Italic/Me" % FAMILYNAME,
|
|
|
|
italic=True, stemWidth=320, italicMeanYCenter=-825, italicNarrowAmount=1)
|
|
|
|
|
2017-08-22 10:05:20 +03:00
|
|
|
|
2017-09-04 06:03:17 +03:00
|
|
|
if ALL or 'bold' in styles:
|
2017-09-05 18:06:04 +03:00
|
|
|
proj.generateFont(
|
|
|
|
Mix2([rg, bl], 0.65, glyphSpecializations.get('bold', {})),
|
|
|
|
"%s/Bold/Bold/Rg" % FAMILYNAME)
|
2017-08-22 10:05:20 +03:00
|
|
|
|
2017-09-04 06:03:17 +03:00
|
|
|
if ALL or 'bolditalic' in styles:
|
2017-09-05 18:06:04 +03:00
|
|
|
proj.generateFont(
|
|
|
|
Mix2([rg, bl], 0.65, glyphSpecializations.get('bold', {})),
|
|
|
|
"%s/Bold Italic/Italic/Rg" % FAMILYNAME,
|
|
|
|
italic=True, stemWidth=384, italicMeanYCenter=-825, italicNarrowAmount=1)
|
|
|
|
|
|
|
|
|
|
|
|
if ALL or 'black' in styles:
|
|
|
|
proj.generateFont(bl.font, "%s/Black/Regular/Bl" % FAMILYNAME)
|
|
|
|
|
|
|
|
if ALL or 'blackitalic' in styles:
|
|
|
|
proj.generateFont(bl.font, "%s/Black Italic/Italic/Bl" % FAMILYNAME,
|
2017-09-04 06:03:17 +03:00
|
|
|
italic=True, stemWidth=290, italicMeanYCenter=-825, italicNarrowAmount=1)
|
2017-08-22 10:05:20 +03:00
|
|
|
|
2017-09-04 06:03:17 +03:00
|
|
|
# generate TTFs
|
|
|
|
if args.no_ttf == False:
|
|
|
|
proj.generateTTFs()
|
2017-08-22 10:05:20 +03:00
|
|
|
|
2017-09-04 06:03:17 +03:00
|
|
|
main()
|
2017-08-22 10:05:20 +03:00
|
|
|
|
2017-09-04 06:03:17 +03:00
|
|
|
# import hotshot, hotshot.stats, test.pystone
|
|
|
|
# prof = hotshot.Profile("ufocompile.prof")
|
|
|
|
# benchtime = prof.runcall(main)
|
|
|
|
# prof.close()
|
|
|
|
# stats = hotshot.stats.load("ufocompile.prof")
|
|
|
|
# # stats.strip_dirs()
|
|
|
|
# stats.sort_stats('time', 'calls')
|
|
|
|
# stats.print_stats(40)
|