Makes life easier if ranged limits are wired from start
This commit is contained in:
parent
b6501a9406
commit
ced09ff3fd
@ -16,14 +16,15 @@ from fontTools.misc.fixedTools import floatToFixedToFloat
|
||||
from fontTools.varLib import _GetCoordinates, _SetCoordinates
|
||||
from fontTools.varLib.models import (
|
||||
supportScalar,
|
||||
normalizeLocation,
|
||||
normalizeValue,
|
||||
piecewiseLinearMap,
|
||||
)
|
||||
from fontTools.varLib.iup import iup_delta
|
||||
from fontTools.ttLib import TTFont
|
||||
from fontTools.ttLib.tables._g_l_y_f import GlyphCoordinates
|
||||
import os
|
||||
import logging
|
||||
import os
|
||||
import re
|
||||
|
||||
|
||||
log = logging.getLogger("fontTools.varlib.partialInstancer")
|
||||
@ -101,33 +102,42 @@ def instantiateGvar(varfont, location):
|
||||
instantiateGvarGlyph(varfont, location, glyphname)
|
||||
|
||||
|
||||
def instantiateVariableFont(varfont, location, inplace=False):
|
||||
def normalize(value, triple, avar_mapping):
|
||||
value = normalizeValue(value, triple)
|
||||
if avar_mapping:
|
||||
value = piecewiseLinearMap(value, avar_mapping)
|
||||
# Quantize to F2Dot14, to avoid surprise interpolations.
|
||||
return floatToFixedToFloat(value, 14)
|
||||
|
||||
def normalizeAxisLimits(varfont, axis_limits):
|
||||
fvar = varfont['fvar']
|
||||
bad_limits = axis_limits.keys() - {a.axisTag for a in fvar.axes}
|
||||
if bad_limits:
|
||||
raise ValueError('Cannot limit: {} not present in fvar'.format(bad_limits))
|
||||
|
||||
axes = {a.axisTag: (a.minValue, a.defaultValue, a.maxValue)
|
||||
for a in fvar.axes if a.axisTag in axis_limits}
|
||||
|
||||
avar_segments = {}
|
||||
if 'avar' in varfont:
|
||||
avar_segments = varfont['avar'].segments
|
||||
for axis_tag, triple in axes.items():
|
||||
avar_mapping = avar_segments.get(axis_tag, None)
|
||||
axis_limits[axis_tag] = tuple(normalize(v, triple, avar_mapping)
|
||||
for v in axis_limits[axis_tag])
|
||||
|
||||
def instantiateVariableFont(varfont, axis_limits, inplace=False):
|
||||
if not inplace:
|
||||
varfont = deepcopy(varfont)
|
||||
normalizeAxisLimits(varfont, axis_limits)
|
||||
|
||||
fvar = varfont['fvar']
|
||||
pinnedAxes = {
|
||||
a.axisTag: (a.minValue, a.defaultValue, a.maxValue)
|
||||
for a in fvar.axes
|
||||
if a.axisTag in location
|
||||
}
|
||||
if not pinnedAxes:
|
||||
return varfont # nothing to do
|
||||
|
||||
location = normalizeLocation(location, pinnedAxes)
|
||||
if 'avar' in varfont:
|
||||
# 'warp' the default normalization using avar
|
||||
maps = varfont['avar'].segments
|
||||
location = {
|
||||
axis: piecewiseLinearMap(v, maps[axis]) for axis, v in location.items()
|
||||
}
|
||||
# Quantize to F2Dot14, to avoid surprise interpolations.
|
||||
location = {axis: floatToFixedToFloat(v, 14) for axis, v in location.items()}
|
||||
# Location is normalized now
|
||||
log.info("Normalized location: %s", location)
|
||||
log.info("Normalized limits: %s", axis_limits)
|
||||
|
||||
if "gvar" in varfont:
|
||||
instantiateGvar(varfont, location)
|
||||
# TODO: support range, stop dropping max value
|
||||
axis_limits = {tag: minv for tag, (minv, maxv) in axis_limits.items()}
|
||||
print(axis_limits)
|
||||
instantiateGvar(varfont, axis_limits)
|
||||
|
||||
# TODO: actually process HVAR instead of dropping it
|
||||
del varfont["HVAR"]
|
||||
@ -135,7 +145,28 @@ def instantiateVariableFont(varfont, location, inplace=False):
|
||||
return varfont
|
||||
|
||||
|
||||
def main(args=None):
|
||||
def parseLimits(limits):
|
||||
result = {}
|
||||
for limit_string in limits:
|
||||
match = re.match(r'^(\w{1,4})=([^:]+)(?:[:](.+))?$', limit_string)
|
||||
if not match:
|
||||
parser.error("invalid location format: %r" % limit_string)
|
||||
tag = match.group(1).ljust(4)
|
||||
lbound = float(match.group(2))
|
||||
ubound = lbound
|
||||
if match.group(3):
|
||||
ubound = float(match.group(3))
|
||||
result[tag] = (lbound, ubound)
|
||||
return result
|
||||
|
||||
|
||||
def parseArgs(args):
|
||||
"""Parse argv.
|
||||
|
||||
Returns:
|
||||
3-tuple (infile, outfile, axis_limits)
|
||||
axis_limits is a map axis_tag:(min,max), meaning limit this axis to
|
||||
range."""
|
||||
from fontTools import configLogger
|
||||
import argparse
|
||||
|
||||
@ -148,8 +179,8 @@ def main(args=None):
|
||||
parser.add_argument(
|
||||
"locargs", metavar="AXIS=LOC", nargs="*",
|
||||
help="List of space separated locations. A location consist in "
|
||||
"the name of a variation axis, followed by '=' and a number. E.g.: "
|
||||
" wdth=100")
|
||||
"the name of a variation axis, followed by '=' and a number or"
|
||||
"number:number. E.g.: wdth=100 or wght=75.0:125.0")
|
||||
parser.add_argument(
|
||||
"-o", "--output", metavar="OUTPUT.ttf", default=None,
|
||||
help="Output instance TTF file (default: INPUT-instance.ttf).")
|
||||
@ -160,9 +191,9 @@ def main(args=None):
|
||||
"-q", "--quiet", action="store_true", help="Turn verbosity off.")
|
||||
options = parser.parse_args(args)
|
||||
|
||||
varfilename = options.input
|
||||
infile = options.input
|
||||
outfile = (
|
||||
os.path.splitext(varfilename)[0] + '-partial.ttf'
|
||||
os.path.splitext(infile)[0] + '-partial.ttf'
|
||||
if not options.output else options.output)
|
||||
configLogger(
|
||||
level=(
|
||||
@ -172,20 +203,20 @@ def main(args=None):
|
||||
)
|
||||
)
|
||||
|
||||
loc = {}
|
||||
for arg in options.locargs:
|
||||
try:
|
||||
tag, val = arg.split('=')
|
||||
assert len(tag) <= 4
|
||||
loc[tag.ljust(4)] = float(val)
|
||||
except (ValueError, AssertionError):
|
||||
parser.error("invalid location argument format: %r" % arg)
|
||||
log.info("Location: %s", loc)
|
||||
axis_limits = parseLimits(options.locargs)
|
||||
if len(axis_limits) != len(options.locargs):
|
||||
raise ValueError('Specified multiple limits for the same axis')
|
||||
return (infile, outfile, axis_limits)
|
||||
|
||||
|
||||
def main(args=None):
|
||||
infile, outfile, axis_limits = parseArgs(args)
|
||||
log.info("Restricting axes: %s", axis_limits)
|
||||
|
||||
log.info("Loading variable font")
|
||||
varfont = TTFont(varfilename)
|
||||
varfont = TTFont(infile)
|
||||
|
||||
instantiateVariableFont(varfont, loc, inplace=True)
|
||||
instantiateVariableFont(varfont, axis_limits, inplace=True)
|
||||
|
||||
log.info("Saving partial variable font %s", outfile)
|
||||
varfont.save(outfile)
|
||||
|
Loading…
x
Reference in New Issue
Block a user