1
1
mirror of https://github.com/rsms/inter.git synced 2024-11-27 09:49:07 +03:00
inter/misc/ufocompile

245 lines
7.1 KiB
Plaintext
Raw Normal View History

2017-08-22 10:05:20 +03:00
#!/usr/bin/env python
2017-10-24 07:59:39 +03:00
from __future__ import print_function
2017-08-22 10:05:20 +03:00
import os
import sys
import argparse
import logging
import subprocess
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
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 ''
def main():
2018-01-10 07:38:30 +03:00
# 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')
2018-01-10 07:38:30 +03:00
argparser = argparse.ArgumentParser(
description='Build TTF and OTF font files from UFO sources.')
2017-08-22 10:05:20 +03:00
2018-01-10 07:38:30 +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
2018-01-10 07:38:30 +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
2018-01-10 07:38:30 +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
2018-01-10 07:38:30 +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
args = argparser.parse_args()
styles = [s.lower() for s in args.styles]
2017-10-24 07:59:39 +03:00
handledStyles = []
ALL = len(styles) == 0
2017-08-22 10:05:20 +03:00
# version control tag, if any
buildTag = readVersionControlTag(BASEDIR)
2017-08-22 10:05:20 +03:00
2018-01-10 07:38:30 +03:00
# Since we reference a shared feature file, copy it to build dir so includes
# works
ufoTmpDir = os.path.join(args.out, 'InterUIUFO')
try:
os.makedirs(ufoTmpDir)
except:
pass
copyfile(
os.path.join(srcDir, 'features.fea'),
os.path.join(ufoTmpDir, 'features.fea'))
2017-08-22 10:05:20 +03:00
# Load masters
print('loading master: Regular')
rg = Master("%s/src/Inter-UI-Regular.ufo" % BASEDIR)
2017-08-22 10:05:20 +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')
bl = Master("%s/src/Inter-UI-Black.ufo" % BASEDIR)
2017-08-22 10:05:20 +03:00
glyphSpecializations = extractSpecializedGlyphs(rg)
2017-08-22 10:05:20 +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
def mixGlyphs(self, gname):
if self.glyphSpecializations is not None:
specializedGlyph = self.glyphSpecializations.get(gname)
if specializedGlyph is not None:
2017-10-24 07:59:39 +03:00
print('mixglyph using specialized', gname)
return specializedGlyph
return Mix.mixGlyphs(self, gname)
2017-08-22 10:05:20 +03:00
2018-01-10 07:38:30 +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
# panose for entire family
panose = {
'bFamilyType': 2, # Latin Text
'bSerifStyle': 11, # Normal Sans
'bProportion': 2, # Old Style
2018-01-10 07:38:30 +03:00
'bContrast': 3, # Very Low (thickest vs thinnest stem of "O")
'bXHeight': 4, # Constant/Large
# bWeight: see http://monotype.de/services/pan2#_Toc380547249
}
def mkpanose(weight):
return dict(panose.items() + {
'bWeight': weight
}.items())
2017-08-22 10:05:20 +03:00
if args.otf:
proj.buildOTF = True
2017-08-22 10:05:20 +03:00
# name syntax: family/styleName/styleCode/subfamilyAbbrev
#
# styleCode should be one of:
# Regular, Italic, Bold, Bold Italic
#
# italicNarrowAmount controls scale on the x axis. 1.0 means no scaling.
# italicMeanYCenter controls how far on the x axis the glyph should slide
# to compensate for the slant.
if ALL or 'regular' in styles:
2017-10-24 07:59:39 +03:00
handledStyles.append('regular')
proj.generateFont(rg.font, "%s/Regular/Regular/Rg" % FAMILYNAME,
panose=mkpanose(5))
2017-08-22 10:05:20 +03:00
2017-10-24 07:59:39 +03:00
if ALL or 'italic' in styles:
handledStyles.append('italic')
proj.generateFont(
rg.font, "%s/Italic/Italic/Rg" % FAMILYNAME,
italic=True, stemWidth=232, italicMeanYCenter=-825, italicNarrowAmount=1,
panose=mkpanose(5))
2017-08-22 10:05:20 +03:00
if ALL or 'medium' in styles:
2017-10-24 07:59:39 +03:00
handledStyles.append('medium')
proj.generateFont(
Mix2([rg, bl], 0.35, glyphSpecializations.get('medium', {})),
"%s/Medium/Regular/Me" % FAMILYNAME,
panose=mkpanose(6))
2017-08-22 10:05:20 +03:00
if ALL or 'mediumitalic' in styles:
2017-10-24 07:59:39 +03:00
handledStyles.append('mediumitalic')
proj.generateFont(
Mix2([rg, bl], 0.35, glyphSpecializations.get('medium', {})),
"%s/Medium Italic/Italic/Me" % FAMILYNAME,
italic=True, stemWidth=300, italicMeanYCenter=-825, italicNarrowAmount=1,
panose=mkpanose(6))
2017-08-22 10:05:20 +03:00
if ALL or 'bold' in styles:
2017-10-24 07:59:39 +03:00
handledStyles.append('bold')
proj.generateFont(
Mix2([rg, bl], 0.65, glyphSpecializations.get('bold', {})),
"%s/Bold/Bold/Rg" % FAMILYNAME,
panose=mkpanose(8))
2017-08-22 10:05:20 +03:00
if ALL or 'bolditalic' in styles:
2017-10-24 07:59:39 +03:00
handledStyles.append('bolditalic')
proj.generateFont(
Mix2([rg, bl], 0.65, glyphSpecializations.get('bold', {})),
"%s/Bold Italic/Bold Italic/Rg" % FAMILYNAME,
italic=True, stemWidth=350, italicMeanYCenter=-825, italicNarrowAmount=1,
panose=mkpanose(8))
if ALL or 'black' in styles:
2017-10-24 07:59:39 +03:00
handledStyles.append('black')
proj.generateFont(bl.font, "%s/Black/Regular/Bl" % FAMILYNAME,
panose=mkpanose(9))
if ALL or 'blackitalic' in styles:
2017-10-24 07:59:39 +03:00
handledStyles.append('blackitalic')
proj.generateFont(
bl.font, "%s/Black Italic/Italic/Bl" % FAMILYNAME,
italic=True, stemWidth=400, italicMeanYCenter=-825, italicNarrowAmount=1,
panose=mkpanose(9))
2017-08-22 10:05:20 +03:00
# generate TTFs
if args.no_ttf == False:
proj.generateTTFs()
2017-08-22 10:05:20 +03:00
2017-10-24 07:59:39 +03:00
if not ALL:
diff = set(styles).difference(set(handledStyles))
if len(diff) != 0:
print('Unknown styles %r' % diff, file=sys.stderr)
sys.exit(1)
main()
2017-08-22 10:05:20 +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)