Skip to content

Commit

Permalink
[varLib] Add avarPlanner
Browse files Browse the repository at this point in the history
  • Loading branch information
behdad committed Jul 23, 2023
1 parent b1ac5aa commit 3a4c1ab
Showing 1 changed file with 128 additions and 0 deletions.
128 changes: 128 additions & 0 deletions Lib/fontTools/varLib/avarPlanner.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,128 @@
from fontTools.pens.areaPen import AreaPen
from fontTools.varLib.models import piecewiseLinearMap
from fontTools.misc.cliTools import makeOutputFileName
from math import exp, log

WEIGHTS = [100, 200, 300, 400, 500, 600, 700, 800, 900]

SAMPLES = 8


def getGlyphsetWeight(glyphset):
wght_sum = wdth_sum = 0

Check warning on line 12 in Lib/fontTools/varLib/avarPlanner.py

View check run for this annotation

Codecov / codecov/patch

Lib/fontTools/varLib/avarPlanner.py#L12

Added line #L12 was not covered by tests
for glyph_name in glyphset:
glyph = glyphset[glyph_name]

Check warning on line 14 in Lib/fontTools/varLib/avarPlanner.py

View check run for this annotation

Codecov / codecov/patch

Lib/fontTools/varLib/avarPlanner.py#L14

Added line #L14 was not covered by tests

pen = AreaPen(glyphset=glyphset)
glyph.draw(pen)

Check warning on line 17 in Lib/fontTools/varLib/avarPlanner.py

View check run for this annotation

Codecov / codecov/patch

Lib/fontTools/varLib/avarPlanner.py#L16-L17

Added lines #L16 - L17 were not covered by tests

wght_sum += abs(pen.value)
wdth_sum += glyph.width

Check warning on line 20 in Lib/fontTools/varLib/avarPlanner.py

View check run for this annotation

Codecov / codecov/patch

Lib/fontTools/varLib/avarPlanner.py#L19-L20

Added lines #L19 - L20 were not covered by tests

return wght_sum / wdth_sum

Check warning on line 22 in Lib/fontTools/varLib/avarPlanner.py

View check run for this annotation

Codecov / codecov/patch

Lib/fontTools/varLib/avarPlanner.py#L22

Added line #L22 was not covered by tests


def planWeightAxis(font, minValue, defaultValue, maxValue, weights=WEIGHTS):
print("Weight min/default/max:", minValue, defaultValue, maxValue)

Check warning on line 26 in Lib/fontTools/varLib/avarPlanner.py

View check run for this annotation

Codecov / codecov/patch

Lib/fontTools/varLib/avarPlanner.py#L26

Added line #L26 was not covered by tests

out = {}
outNormalized = {}

Check warning on line 29 in Lib/fontTools/varLib/avarPlanner.py

View check run for this annotation

Codecov / codecov/patch

Lib/fontTools/varLib/avarPlanner.py#L28-L29

Added lines #L28 - L29 were not covered by tests

upem = font["head"].unitsPerEm
axisWeightAverage = {}

Check warning on line 32 in Lib/fontTools/varLib/avarPlanner.py

View check run for this annotation

Codecov / codecov/patch

Lib/fontTools/varLib/avarPlanner.py#L31-L32

Added lines #L31 - L32 were not covered by tests
for weight in sorted({minValue, defaultValue, maxValue}):
glyphset = font.getGlyphSet(location={"wght": weight})
axisWeightAverage[weight] = getGlyphsetWeight(glyphset) / upem

Check warning on line 35 in Lib/fontTools/varLib/avarPlanner.py

View check run for this annotation

Codecov / codecov/patch

Lib/fontTools/varLib/avarPlanner.py#L34-L35

Added lines #L34 - L35 were not covered by tests

print("Calculated average glyph black ratio:", axisWeightAverage)

Check warning on line 37 in Lib/fontTools/varLib/avarPlanner.py

View check run for this annotation

Codecov / codecov/patch

Lib/fontTools/varLib/avarPlanner.py#L37

Added line #L37 was not covered by tests

outNormalized[-1] = -1

Check warning on line 39 in Lib/fontTools/varLib/avarPlanner.py

View check run for this annotation

Codecov / codecov/patch

Lib/fontTools/varLib/avarPlanner.py#L39

Added line #L39 was not covered by tests
for extremeValue in sorted({minValue, maxValue} - {defaultValue}):
rangeMin = min(defaultValue, extremeValue)
rangeMax = max(defaultValue, extremeValue)

Check warning on line 42 in Lib/fontTools/varLib/avarPlanner.py

View check run for this annotation

Codecov / codecov/patch

Lib/fontTools/varLib/avarPlanner.py#L41-L42

Added lines #L41 - L42 were not covered by tests
targetWeights = {w for w in weights if rangeMin < w < rangeMax}
if not targetWeights:
continue

Check warning on line 45 in Lib/fontTools/varLib/avarPlanner.py

View check run for this annotation

Codecov / codecov/patch

Lib/fontTools/varLib/avarPlanner.py#L45

Added line #L45 was not covered by tests

bias = -1 if extremeValue < defaultValue else 0

Check warning on line 47 in Lib/fontTools/varLib/avarPlanner.py

View check run for this annotation

Codecov / codecov/patch

Lib/fontTools/varLib/avarPlanner.py#L47

Added line #L47 was not covered by tests

print("Planning target weights", targetWeights)
print("Sampling", SAMPLES, "points in range", rangeMin, rangeMax)
weightBlackRatio = axisWeightAverage.copy()

Check warning on line 51 in Lib/fontTools/varLib/avarPlanner.py

View check run for this annotation

Codecov / codecov/patch

Lib/fontTools/varLib/avarPlanner.py#L49-L51

Added lines #L49 - L51 were not covered by tests
for sample in range(1, SAMPLES + 1):
weight = rangeMin + (rangeMax - rangeMin) * sample / (SAMPLES + 1)
print("Sampling weight", weight)
glyphset = font.getGlyphSet(location={"wght": weight})
weightBlackRatio[weight] = getGlyphsetWeight(glyphset) / upem
print("Sampled average glyph black ratio:", weightBlackRatio)

Check warning on line 57 in Lib/fontTools/varLib/avarPlanner.py

View check run for this annotation

Codecov / codecov/patch

Lib/fontTools/varLib/avarPlanner.py#L53-L57

Added lines #L53 - L57 were not covered by tests

blackRatioWeight = {}

Check warning on line 59 in Lib/fontTools/varLib/avarPlanner.py

View check run for this annotation

Codecov / codecov/patch

Lib/fontTools/varLib/avarPlanner.py#L59

Added line #L59 was not covered by tests
for weight in sorted(weightBlackRatio):
blackRatioWeight[weightBlackRatio[weight]] = weight

Check warning on line 61 in Lib/fontTools/varLib/avarPlanner.py

View check run for this annotation

Codecov / codecov/patch

Lib/fontTools/varLib/avarPlanner.py#L61

Added line #L61 was not covered by tests

logMin = log(weightBlackRatio[rangeMin])
logMax = log(weightBlackRatio[rangeMax])
out[rangeMin] = rangeMin
outNormalized[bias] = bias

Check warning on line 66 in Lib/fontTools/varLib/avarPlanner.py

View check run for this annotation

Codecov / codecov/patch

Lib/fontTools/varLib/avarPlanner.py#L63-L66

Added lines #L63 - L66 were not covered by tests
for weight in sorted(targetWeights):
t = (weight - rangeMin) / (rangeMax - rangeMin)
targetBlackRatio = exp(logMin + t * (logMax - logMin))
targetWeight = piecewiseLinearMap(targetBlackRatio, blackRatioWeight)
print("Planned mapping weight %g to %g" % (weight, targetWeight))
out[weight] = targetWeight
outNormalized[t + bias] = (targetWeight - rangeMin) / (

Check warning on line 73 in Lib/fontTools/varLib/avarPlanner.py

View check run for this annotation

Codecov / codecov/patch

Lib/fontTools/varLib/avarPlanner.py#L68-L73

Added lines #L68 - L73 were not covered by tests
rangeMax - rangeMin
) + bias
out[rangeMax] = rangeMax
outNormalized[bias + 1] = bias + 1
outNormalized[+1] = +1

Check warning on line 78 in Lib/fontTools/varLib/avarPlanner.py

View check run for this annotation

Codecov / codecov/patch

Lib/fontTools/varLib/avarPlanner.py#L76-L78

Added lines #L76 - L78 were not covered by tests

print("Planned mapping:", out)
print("Planned normalized mapping:", outNormalized)
return out, outNormalized

Check warning on line 82 in Lib/fontTools/varLib/avarPlanner.py

View check run for this annotation

Codecov / codecov/patch

Lib/fontTools/varLib/avarPlanner.py#L80-L82

Added lines #L80 - L82 were not covered by tests


def main(args=None):
if args is None:
import sys

Check warning on line 87 in Lib/fontTools/varLib/avarPlanner.py

View check run for this annotation

Codecov / codecov/patch

Lib/fontTools/varLib/avarPlanner.py#L87

Added line #L87 was not covered by tests

args = sys.argv[1:]

Check warning on line 89 in Lib/fontTools/varLib/avarPlanner.py

View check run for this annotation

Codecov / codecov/patch

Lib/fontTools/varLib/avarPlanner.py#L89

Added line #L89 was not covered by tests

from fontTools.ttLib import TTFont
import argparse

Check warning on line 92 in Lib/fontTools/varLib/avarPlanner.py

View check run for this annotation

Codecov / codecov/patch

Lib/fontTools/varLib/avarPlanner.py#L91-L92

Added lines #L91 - L92 were not covered by tests

parser = argparse.ArgumentParser(

Check warning on line 94 in Lib/fontTools/varLib/avarPlanner.py

View check run for this annotation

Codecov / codecov/patch

Lib/fontTools/varLib/avarPlanner.py#L94

Added line #L94 was not covered by tests
"fonttools varLib.avarPlanner",
description="Plan `avar` table for variable font",
)
parser.add_argument("font", metavar="font.ttf", help="Font file.")

Check warning on line 98 in Lib/fontTools/varLib/avarPlanner.py

View check run for this annotation

Codecov / codecov/patch

Lib/fontTools/varLib/avarPlanner.py#L98

Added line #L98 was not covered by tests

options = parser.parse_args(args)

Check warning on line 100 in Lib/fontTools/varLib/avarPlanner.py

View check run for this annotation

Codecov / codecov/patch

Lib/fontTools/varLib/avarPlanner.py#L100

Added line #L100 was not covered by tests

font = TTFont(options.font)
fvar = font["fvar"]
wghtAxis = slntAxis = None

Check warning on line 104 in Lib/fontTools/varLib/avarPlanner.py

View check run for this annotation

Codecov / codecov/patch

Lib/fontTools/varLib/avarPlanner.py#L102-L104

Added lines #L102 - L104 were not covered by tests
for axis in fvar.axes:
if axis.axisTag == "wght":
wghtAxis = axis

Check warning on line 107 in Lib/fontTools/varLib/avarPlanner.py

View check run for this annotation

Codecov / codecov/patch

Lib/fontTools/varLib/avarPlanner.py#L107

Added line #L107 was not covered by tests
elif axis.axisTag == "slnt":
slntAxis = axis

Check warning on line 109 in Lib/fontTools/varLib/avarPlanner.py

View check run for this annotation

Codecov / codecov/patch

Lib/fontTools/varLib/avarPlanner.py#L109

Added line #L109 was not covered by tests

_, mapping = planWeightAxis(

Check warning on line 111 in Lib/fontTools/varLib/avarPlanner.py

View check run for this annotation

Codecov / codecov/patch

Lib/fontTools/varLib/avarPlanner.py#L111

Added line #L111 was not covered by tests
font, wghtAxis.minValue, wghtAxis.defaultValue, wghtAxis.maxValue
)
if "avar" in font:
print("Existing weight mapping:", font["avar"].segments["wght"])

Check warning on line 115 in Lib/fontTools/varLib/avarPlanner.py

View check run for this annotation

Codecov / codecov/patch

Lib/fontTools/varLib/avarPlanner.py#L115

Added line #L115 was not covered by tests
else:
font["avar"] = newTable("avar")
avar = font["avar"]
avar.segments["wght"] = mapping

Check warning on line 119 in Lib/fontTools/varLib/avarPlanner.py

View check run for this annotation

Codecov / codecov/patch

Lib/fontTools/varLib/avarPlanner.py#L117-L119

Added lines #L117 - L119 were not covered by tests

outfile = makeOutputFileName(options.font, overWrite=True, suffix=".avar")
font.save(outfile)

Check warning on line 122 in Lib/fontTools/varLib/avarPlanner.py

View check run for this annotation

Codecov / codecov/patch

Lib/fontTools/varLib/avarPlanner.py#L121-L122

Added lines #L121 - L122 were not covered by tests


if __name__ == "__main__":
import sys

sys.exit(main())

0 comments on commit 3a4c1ab

Please sign in to comment.