mirror of
https://github.com/adobe-fonts/source-sans.git
synced 2024-12-26 14:16:03 +01:00
183 lines
4.9 KiB
Python
Executable file
183 lines
4.9 KiB
Python
Executable file
#!/usr/bin/env python3
|
||
|
||
'''
|
||
Build script for Variable Fonts (VF)
|
||
'''
|
||
|
||
from pathlib import Path
|
||
import argparse
|
||
import subprocess
|
||
import shutil
|
||
|
||
FAMILY_NAME = 'SourceSans3VF'
|
||
ROOT_DIR = Path(__file__).parent
|
||
|
||
|
||
def get_args():
|
||
parser = argparse.ArgumentParser(
|
||
description=(__doc__))
|
||
|
||
parser.add_argument(
|
||
'-v', '--verbose',
|
||
action='store_true',
|
||
default=False,
|
||
help='verbose output')
|
||
|
||
parser.add_argument(
|
||
'--hinted',
|
||
action='store_true',
|
||
default=False,
|
||
help='hint VFs')
|
||
|
||
parser.add_argument(
|
||
'-d', '--debug',
|
||
action='store_true',
|
||
default=False,
|
||
help='do not delete temporary files')
|
||
|
||
return parser.parse_args()
|
||
|
||
|
||
def remove_source_otfs(slope):
|
||
# deletes source otf files
|
||
for i in range(4):
|
||
source_directory = ROOT_DIR.joinpath(
|
||
f'{slope}', 'Poles', f'pole_{i}')
|
||
for otf_to_delete in source_directory.glob("*.otf"):
|
||
subprocess.call(['rm', otf_to_delete])
|
||
|
||
|
||
def build_vf(args, slope):
|
||
# default mode is being quiet
|
||
STDOUT = subprocess.DEVNULL
|
||
STDERR = subprocess.DEVNULL
|
||
|
||
if any([args.verbose, args.debug]):
|
||
# verbose output
|
||
STDOUT = None
|
||
STDERR = None
|
||
|
||
target_dir = ROOT_DIR.joinpath(f'{slope}')
|
||
|
||
if slope == 'Italic':
|
||
vf_output_name = ROOT_DIR.joinpath(
|
||
target_dir, f'{FAMILY_NAME}-{slope}')
|
||
else:
|
||
slope == 'Upright'
|
||
vf_output_name = ROOT_DIR.joinpath(
|
||
target_dir, f'{FAMILY_NAME}-{slope}')
|
||
|
||
output_otf = vf_output_name.with_suffix('.otf')
|
||
output_ttf = vf_output_name.with_suffix('.ttf')
|
||
designspace_file = vf_output_name.with_suffix('.designspace')
|
||
|
||
# build pole OTFs
|
||
subprocess.call(
|
||
# --mkot to set makeotf options:
|
||
# gs to omit glyphs not in the GOADB
|
||
# osv 4 to write os/2 table v4
|
||
['buildmasterotfs', '--mkot', '-gs,-osv,4', '-d', designspace_file],
|
||
stdout=STDOUT,
|
||
stderr=STDERR
|
||
)
|
||
|
||
if args.hinted:
|
||
# split combined private dicts into FDArrays
|
||
subprocess.call(
|
||
['splitpsdicts', '-m', f'{slope}/vf_hinting_metadata.plist', '-d', designspace_file],
|
||
stdout=STDOUT,
|
||
stderr=STDERR
|
||
)
|
||
|
||
# merge OTFs into CFF2
|
||
subprocess.call(
|
||
# -k is for using 'post' table format 2
|
||
['buildcff2vf', '-k', '--omit-mac-names', '-d', designspace_file],
|
||
stdout=STDOUT,
|
||
stderr=STDERR
|
||
)
|
||
|
||
if args.hinted:
|
||
# hint the file
|
||
subprocess.call(
|
||
['psautohint', '--no-flex', output_otf],
|
||
stdout=STDOUT,
|
||
stderr=STDERR
|
||
)
|
||
|
||
if not args.hinted:
|
||
# at the moment, we don’t subroutinize the hinted fonts.
|
||
# extract and subroutinize the CFF2 table
|
||
subprocess.call(
|
||
['tx', '-cff2', '+S', '+b', '-std', output_otf, '/tmp/.tb_cff2'],
|
||
stdout=STDOUT,
|
||
stderr=STDERR
|
||
)
|
||
|
||
# replace CFF2 table with subroutinized version
|
||
subprocess.call(
|
||
['sfntedit', '-a', 'CFF2=/tmp/.tb_cff2', output_otf],
|
||
stdout=STDOUT,
|
||
stderr=STDERR
|
||
)
|
||
|
||
# build VF TTF with fontmake.
|
||
subprocess.call([
|
||
'fontmake', '-m', designspace_file, '-o', 'variable',
|
||
'--production-names', '--output-path', output_ttf,
|
||
'--feature-writer', 'None', '--no-check-compatibility'],
|
||
stdout=STDOUT,
|
||
stderr=STDERR
|
||
)
|
||
|
||
# use DSIG, name, OS/2, hhea, post, and STAT tables from OTFs
|
||
tables_from_otf = (
|
||
'DSIG=/tmp/.tb_DSIG,name=/tmp/.tb_name,OS/2=/tmp/.tb_os2,'
|
||
'hhea=/tmp/.tb_hhea,post=/tmp/.tb_post,STAT=/tmp/.tb_STAT,'
|
||
'fvar=/tmp/.tb_fvar')
|
||
|
||
subprocess.call([
|
||
'sfntedit', '-x', tables_from_otf, output_otf])
|
||
subprocess.call([
|
||
'sfntedit', '-a', tables_from_otf, output_ttf])
|
||
|
||
# use cmap, GDEF, GPOS, and GSUB tables from TTFs
|
||
tables_from_ttf = (
|
||
'cmap=/tmp/.tb_cmap,GDEF=/tmp/.tb_GDEF,'
|
||
'GPOS=/tmp/.tb_GPOS,GSUB=/tmp/.tb_GSUB')
|
||
|
||
subprocess.call([
|
||
'sfntedit', '-x', tables_from_ttf, output_ttf])
|
||
subprocess.call([
|
||
'sfntedit', '-a', tables_from_ttf, output_otf])
|
||
|
||
# move font files to target directory
|
||
if output_otf.exists():
|
||
shutil.move(output_otf, vf_dir)
|
||
if output_ttf.exists():
|
||
shutil.move(output_ttf, vf_dir)
|
||
|
||
# delete build artifacts
|
||
if not args.debug:
|
||
remove_source_otfs(slope)
|
||
|
||
|
||
if __name__ == '__main__':
|
||
args = get_args()
|
||
slopes = ['Upright', 'Italic']
|
||
|
||
if args.hinted:
|
||
output_dir_name = 'VF_hinted'
|
||
else:
|
||
output_dir_name = 'VF'
|
||
|
||
vf_dir = ROOT_DIR.joinpath('target', output_dir_name)
|
||
|
||
# clean existing target directory
|
||
if vf_dir.exists():
|
||
subprocess.call(['rm', '-rf', vf_dir])
|
||
# build target directory
|
||
vf_dir.mkdir(parents=True)
|
||
|
||
for slope in slopes:
|
||
build_vf(args, slope)
|