[varLib.avar] Sketch of code to reconstruct mappings from binary
https://github.com/Lorp/fencer/issues/25
This commit is contained in:
parent
770917d89e
commit
150d4fc195
@ -1,10 +1,104 @@
|
|||||||
from fontTools.varLib import _add_avar, load_designspace
|
from fontTools.varLib import _add_avar, load_designspace
|
||||||
|
from fontTools.varLib.varStore import VarStoreInstancer
|
||||||
|
from fontTools.misc.fixedTools import fixedToFloat as fi2fl
|
||||||
from fontTools.misc.cliTools import makeOutputFileName
|
from fontTools.misc.cliTools import makeOutputFileName
|
||||||
|
from itertools import product
|
||||||
import logging
|
import logging
|
||||||
|
|
||||||
log = logging.getLogger("fontTools.varLib.avar")
|
log = logging.getLogger("fontTools.varLib.avar")
|
||||||
|
|
||||||
|
|
||||||
|
def _denormalize(v, axis):
|
||||||
|
return axis.defaultValue + v * (
|
||||||
|
(axis.maxValue if v >= 0 else axis.minValue) - axis.defaultValue
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def mappings_from_avar(font, denormalize=True):
|
||||||
|
fvarAxes = font["fvar"].axes
|
||||||
|
axisMap = {a.axisTag: a for a in fvarAxes}
|
||||||
|
axisTags = [a.axisTag for a in fvarAxes]
|
||||||
|
axisIndexes = {a.axisTag: i for i, a in enumerate(fvarAxes)}
|
||||||
|
if "avar" not in font:
|
||||||
|
return {}, {}
|
||||||
|
avar = font["avar"]
|
||||||
|
axisMaps = {
|
||||||
|
tag: seg
|
||||||
|
for tag, seg in avar.segments.items()
|
||||||
|
if seg and seg != {-1: -1, 0: 0, 1: 1}
|
||||||
|
}
|
||||||
|
mappings = []
|
||||||
|
|
||||||
|
if getattr(avar, "majorVersion", 1) == 2:
|
||||||
|
varStore = avar.table.VarStore
|
||||||
|
regions = varStore.VarRegionList.Region
|
||||||
|
inputLocations = set()
|
||||||
|
for varData in varStore.VarData:
|
||||||
|
regionIndices = varData.VarRegionIndex
|
||||||
|
for regionIndex in regionIndices:
|
||||||
|
peakLocation = {}
|
||||||
|
corners = []
|
||||||
|
region = regions[regionIndex]
|
||||||
|
for axisIndex, axis in enumerate(region.VarRegionAxis):
|
||||||
|
if axis.PeakCoord == 0:
|
||||||
|
continue
|
||||||
|
axisTag = axisTags[axisIndex]
|
||||||
|
peakLocation[axisTag] = axis.PeakCoord
|
||||||
|
corner = []
|
||||||
|
if axis.StartCoord != 0:
|
||||||
|
corner.append((axisTag, axis.StartCoord))
|
||||||
|
if axis.EndCoord != 0:
|
||||||
|
corner.append((axisTag, axis.EndCoord))
|
||||||
|
corners.append(corner)
|
||||||
|
corners = set(product(*corners))
|
||||||
|
inputLocations.update(corners)
|
||||||
|
|
||||||
|
inputLocations = [
|
||||||
|
dict(t)
|
||||||
|
for t in sorted(
|
||||||
|
inputLocations,
|
||||||
|
key=lambda t: (len(t), tuple(axisIndexes[tag] for tag, _ in t)),
|
||||||
|
)
|
||||||
|
]
|
||||||
|
|
||||||
|
varIdxMap = avar.table.VarIdxMap
|
||||||
|
instancer = VarStoreInstancer(varStore, fvarAxes)
|
||||||
|
for location in inputLocations:
|
||||||
|
instancer.setLocation(location)
|
||||||
|
outputLocation = {}
|
||||||
|
for axisIndex, axisTag in enumerate(axisTags):
|
||||||
|
varIdx = axisIndex
|
||||||
|
if varIdxMap is not None:
|
||||||
|
varIdx = varIdxMap[varIdx]
|
||||||
|
delta = instancer[varIdx]
|
||||||
|
if delta != 0:
|
||||||
|
v = location.get(axisTag, 0)
|
||||||
|
v = v + fi2fl(delta, 14)
|
||||||
|
v = max(-1, min(1, v))
|
||||||
|
outputLocation[axisTag] = v
|
||||||
|
mappings.append((location, outputLocation))
|
||||||
|
# Filter out empty mappings
|
||||||
|
mappings = [io for io in mappings if io[1]]
|
||||||
|
|
||||||
|
if denormalize:
|
||||||
|
for tag, seg in axisMaps.items():
|
||||||
|
if tag not in axisMap:
|
||||||
|
raise ValueError(f"Unknown axis tag {tag}")
|
||||||
|
denorm = lambda v: _denormalize(v, axisMap[tag])
|
||||||
|
axisMaps[tag] = {denorm(k): denorm(v) for k, v in seg.items()}
|
||||||
|
|
||||||
|
for i, (inputLoc, outputLoc) in enumerate(mappings):
|
||||||
|
inputLoc = {
|
||||||
|
tag: _denormalize(val, axisMap[tag]) for tag, val in inputLoc.items()
|
||||||
|
}
|
||||||
|
outputLoc = {
|
||||||
|
tag: _denormalize(val, axisMap[tag]) for tag, val in outputLoc.items()
|
||||||
|
}
|
||||||
|
mappings[i] = (inputLoc, outputLoc)
|
||||||
|
|
||||||
|
return axisMaps, mappings
|
||||||
|
|
||||||
|
|
||||||
def main(args=None):
|
def main(args=None):
|
||||||
"""Add `avar` table from designspace file to variable font."""
|
"""Add `avar` table from designspace file to variable font."""
|
||||||
|
|
||||||
@ -24,7 +118,11 @@ def main(args=None):
|
|||||||
)
|
)
|
||||||
parser.add_argument("font", metavar="varfont.ttf", help="Variable-font file.")
|
parser.add_argument("font", metavar="varfont.ttf", help="Variable-font file.")
|
||||||
parser.add_argument(
|
parser.add_argument(
|
||||||
"designspace", metavar="family.designspace", help="Designspace file."
|
"designspace",
|
||||||
|
metavar="family.designspace",
|
||||||
|
help="Designspace file.",
|
||||||
|
nargs="?",
|
||||||
|
default=None,
|
||||||
)
|
)
|
||||||
parser.add_argument(
|
parser.add_argument(
|
||||||
"-o",
|
"-o",
|
||||||
@ -45,6 +143,12 @@ def main(args=None):
|
|||||||
log.error("Not a variable font.")
|
log.error("Not a variable font.")
|
||||||
return 1
|
return 1
|
||||||
|
|
||||||
|
if options.designspace is None:
|
||||||
|
from pprint import pprint
|
||||||
|
|
||||||
|
pprint(mappings_from_avar(font))
|
||||||
|
return
|
||||||
|
|
||||||
axisTags = [a.axisTag for a in font["fvar"].axes]
|
axisTags = [a.axisTag for a in font["fvar"].axes]
|
||||||
|
|
||||||
ds = load_designspace(options.designspace)
|
ds = load_designspace(options.designspace)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user