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 import _GetCoordinates, _SetCoordinates
|
||||||
from fontTools.varLib.models import (
|
from fontTools.varLib.models import (
|
||||||
supportScalar,
|
supportScalar,
|
||||||
normalizeLocation,
|
normalizeValue,
|
||||||
piecewiseLinearMap,
|
piecewiseLinearMap,
|
||||||
)
|
)
|
||||||
from fontTools.varLib.iup import iup_delta
|
from fontTools.varLib.iup import iup_delta
|
||||||
from fontTools.ttLib import TTFont
|
from fontTools.ttLib import TTFont
|
||||||
from fontTools.ttLib.tables._g_l_y_f import GlyphCoordinates
|
from fontTools.ttLib.tables._g_l_y_f import GlyphCoordinates
|
||||||
import os
|
|
||||||
import logging
|
import logging
|
||||||
|
import os
|
||||||
|
import re
|
||||||
|
|
||||||
|
|
||||||
log = logging.getLogger("fontTools.varlib.partialInstancer")
|
log = logging.getLogger("fontTools.varlib.partialInstancer")
|
||||||
@ -101,33 +102,42 @@ def instantiateGvar(varfont, location):
|
|||||||
instantiateGvarGlyph(varfont, location, glyphname)
|
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:
|
if not inplace:
|
||||||
varfont = deepcopy(varfont)
|
varfont = deepcopy(varfont)
|
||||||
|
normalizeAxisLimits(varfont, axis_limits)
|
||||||
|
|
||||||
fvar = varfont['fvar']
|
log.info("Normalized limits: %s", axis_limits)
|
||||||
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)
|
|
||||||
|
|
||||||
if "gvar" in varfont:
|
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
|
# TODO: actually process HVAR instead of dropping it
|
||||||
del varfont["HVAR"]
|
del varfont["HVAR"]
|
||||||
@ -135,7 +145,28 @@ def instantiateVariableFont(varfont, location, inplace=False):
|
|||||||
return varfont
|
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
|
from fontTools import configLogger
|
||||||
import argparse
|
import argparse
|
||||||
|
|
||||||
@ -148,8 +179,8 @@ def main(args=None):
|
|||||||
parser.add_argument(
|
parser.add_argument(
|
||||||
"locargs", metavar="AXIS=LOC", nargs="*",
|
"locargs", metavar="AXIS=LOC", nargs="*",
|
||||||
help="List of space separated locations. A location consist in "
|
help="List of space separated locations. A location consist in "
|
||||||
"the name of a variation axis, followed by '=' and a number. E.g.: "
|
"the name of a variation axis, followed by '=' and a number or"
|
||||||
" wdth=100")
|
"number:number. E.g.: wdth=100 or wght=75.0:125.0")
|
||||||
parser.add_argument(
|
parser.add_argument(
|
||||||
"-o", "--output", metavar="OUTPUT.ttf", default=None,
|
"-o", "--output", metavar="OUTPUT.ttf", default=None,
|
||||||
help="Output instance TTF file (default: INPUT-instance.ttf).")
|
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.")
|
"-q", "--quiet", action="store_true", help="Turn verbosity off.")
|
||||||
options = parser.parse_args(args)
|
options = parser.parse_args(args)
|
||||||
|
|
||||||
varfilename = options.input
|
infile = options.input
|
||||||
outfile = (
|
outfile = (
|
||||||
os.path.splitext(varfilename)[0] + '-partial.ttf'
|
os.path.splitext(infile)[0] + '-partial.ttf'
|
||||||
if not options.output else options.output)
|
if not options.output else options.output)
|
||||||
configLogger(
|
configLogger(
|
||||||
level=(
|
level=(
|
||||||
@ -172,20 +203,20 @@ def main(args=None):
|
|||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
loc = {}
|
axis_limits = parseLimits(options.locargs)
|
||||||
for arg in options.locargs:
|
if len(axis_limits) != len(options.locargs):
|
||||||
try:
|
raise ValueError('Specified multiple limits for the same axis')
|
||||||
tag, val = arg.split('=')
|
return (infile, outfile, axis_limits)
|
||||||
assert len(tag) <= 4
|
|
||||||
loc[tag.ljust(4)] = float(val)
|
|
||||||
except (ValueError, AssertionError):
|
def main(args=None):
|
||||||
parser.error("invalid location argument format: %r" % arg)
|
infile, outfile, axis_limits = parseArgs(args)
|
||||||
log.info("Location: %s", loc)
|
log.info("Restricting axes: %s", axis_limits)
|
||||||
|
|
||||||
log.info("Loading variable font")
|
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)
|
log.info("Saving partial variable font %s", outfile)
|
||||||
varfont.save(outfile)
|
varfont.save(outfile)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user