Beispiel #1
0
def normalizeLocation(location, axes):
    """This behaves different from varLib.models.normalizeLocation in that
    it won't add missing axes values and doesn't filter values that aren't
    in the axes dict.
    """
    return {
        axisName: normalizeValue(v, axes.get(axisName, (-1, 0, 1)))
        for axisName, v in location.items()
    }
    def _normalized_location(self, location):
        location = self.fix_location(location)
        normalized_location = {}
        for axtag in location.keys():
            if axtag not in self.axes_dict:
                raise ValueError("Unknown axis %s in %s" % (axtag, location))
            axis = self.axes_dict[axtag]
            normalized_location[axtag] = normalizeValue(
                location[axtag], (axis.minValue, axis.defaultValue, axis.maxValue)
            )

        return Location(normalized_location)
Beispiel #3
0
    def _normalized_location(self, location):
        normalized_location = {}
        for axtag in location.keys():
            if axtag not in self.axes_dict:
                raise ValueError("Unknown axis %s in %s" % axtag, location)
            axis = self.axes_dict[axtag]
            normalized_location[axtag] = normalizeValue(
                location[axtag], (axis.minimum, axis.default, axis.maximum))

        for ax in self.axes:
            if ax.tag not in normalized_location:
                normalized_location[ax.tag] = 0

        return NormalizedLocation(normalized_location)
Beispiel #4
0
def normalizeLocation(doc, location):
    # Adapted from DesignSpaceDocument.normalizeLocation(), which takes axis
    # names, yet we need to work with tags here.
    # Also, the original takes design space coordinates, whereas I have user
    # space coordinates here.
    new = {}
    for axis in doc.axes:
        if axis.tag not in location:
            # skipping this dimension it seems
            continue
        value = axis.map_forward(location[axis.tag])
        triple = [
            axis.map_forward(v) for v in (axis.minimum, axis.default, axis.maximum)
        ]
        new[axis.tag] = normalizeValue(value, triple)
    return new
Beispiel #5
0
def _add_avar(font, axes):
	"""
	Add 'avar' table to font.

	axes is an ordered dictionary of DesignspaceAxis objects.
	"""

	assert axes
	assert isinstance(axes, OrderedDict)

	log.info("Generating avar")

	avar = newTable('avar')

	interesting = False
	for axis in axes.values():
		# Currently, some rasterizers require that the default value maps
		# (-1 to -1, 0 to 0, and 1 to 1) be present for all the segment
		# maps, even when the default normalization mapping for the axis
		# was not modified.
		# https://github.com/googlei18n/fontmake/issues/295
		# https://github.com/fonttools/fonttools/issues/1011
		# TODO(anthrotype) revert this (and 19c4b37) when issue is fixed
		curve = avar.segments[axis.tag] = {-1.0: -1.0, 0.0: 0.0, 1.0: 1.0}
		if not axis.map:
			continue

		items = sorted(axis.map.items())
		keys = [item[0] for item in items]
		vals = [item[1] for item in items]

		# Current avar requirements.  We don't have to enforce
		# these on the designer and can deduce some ourselves,
		# but for now just enforce them.
		assert axis.minimum == min(keys)
		assert axis.maximum == max(keys)
		assert axis.default in keys
		# No duplicates
		assert len(set(keys)) == len(keys)
		assert len(set(vals)) == len(vals)
		# Ascending values
		assert sorted(vals) == vals

		keys_triple = (axis.minimum, axis.default, axis.maximum)
		vals_triple = tuple(axis.map_forward(v) for v in keys_triple)

		keys = [models.normalizeValue(v, keys_triple) for v in keys]
		vals = [models.normalizeValue(v, vals_triple) for v in vals]

		if all(k == v for k, v in zip(keys, vals)):
			continue
		interesting = True

		curve.update(zip(keys, vals))

		assert 0.0 in curve and curve[0.0] == 0.0
		assert -1.0 not in curve or curve[-1.0] == -1.0
		assert +1.0 not in curve or curve[+1.0] == +1.0
		# curve.update({-1.0: -1.0, 0.0: 0.0, 1.0: 1.0})

	assert "avar" not in font
	if not interesting:
		log.info("No need for avar")
		avar = None
	else:
		font['avar'] = avar

	return avar
Beispiel #6
0
def _add_avar(font, axes):
    """
	Add 'avar' table to font.

	axes is an ordered dictionary of AxisDescriptor objects.
	"""

    assert axes
    assert isinstance(axes, OrderedDict)

    log.info("Generating avar")

    avar = newTable('avar')

    interesting = False
    for axis in axes.values():
        # Currently, some rasterizers require that the default value maps
        # (-1 to -1, 0 to 0, and 1 to 1) be present for all the segment
        # maps, even when the default normalization mapping for the axis
        # was not modified.
        # https://github.com/googlei18n/fontmake/issues/295
        # https://github.com/fonttools/fonttools/issues/1011
        # TODO(anthrotype) revert this (and 19c4b37) when issue is fixed
        curve = avar.segments[axis.tag] = {-1.0: -1.0, 0.0: 0.0, 1.0: 1.0}
        if not axis.map:
            continue

        items = sorted(axis.map)
        keys = [item[0] for item in items]
        vals = [item[1] for item in items]

        # Current avar requirements.  We don't have to enforce
        # these on the designer and can deduce some ourselves,
        # but for now just enforce them.
        if axis.minimum != min(keys):
            raise VarLibValidationError(
                f"Axis '{axis.name}': there must be a mapping for the axis minimum "
                f"value {axis.minimum} and it must be the lowest input mapping value."
            )
        if axis.maximum != max(keys):
            raise VarLibValidationError(
                f"Axis '{axis.name}': there must be a mapping for the axis maximum "
                f"value {axis.maximum} and it must be the highest input mapping value."
            )
        if axis.default not in keys:
            raise VarLibValidationError(
                f"Axis '{axis.name}': there must be a mapping for the axis default "
                f"value {axis.default}.")
        # No duplicate input values (output values can be >= their preceeding value).
        if len(set(keys)) != len(keys):
            raise VarLibValidationError(
                f"Axis '{axis.name}': All axis mapping input='...' values must be "
                "unique, but we found duplicates.")
        # Ascending values
        if sorted(vals) != vals:
            raise VarLibValidationError(
                f"Axis '{axis.name}': mapping output values must be in ascending order."
            )

        keys_triple = (axis.minimum, axis.default, axis.maximum)
        vals_triple = tuple(axis.map_forward(v) for v in keys_triple)

        keys = [models.normalizeValue(v, keys_triple) for v in keys]
        vals = [models.normalizeValue(v, vals_triple) for v in vals]

        if all(k == v for k, v in zip(keys, vals)):
            continue
        interesting = True

        curve.update(zip(keys, vals))

        assert 0.0 in curve and curve[0.0] == 0.0
        assert -1.0 not in curve or curve[-1.0] == -1.0
        assert +1.0 not in curve or curve[+1.0] == +1.0
        # curve.update({-1.0: -1.0, 0.0: 0.0, 1.0: 1.0})

    assert "avar" not in font
    if not interesting:
        log.info("No need for avar")
        avar = None
    else:
        font['avar'] = avar

    return avar
Beispiel #7
0
def normalize(value, triple, avarMapping):
    value = normalizeValue(value, triple)
    if avarMapping:
        value = piecewiseLinearMap(value, avarMapping)
    # Quantize to F2Dot14, to avoid surprise interpolations.
    return floatToFixedToFloat(value, 14)
Beispiel #8
0
def _add_avar(font, axes):
	"""
	Add 'avar' table to font.

	axes is an ordered dictionary of AxisDescriptor objects.
	"""

	assert axes
	assert isinstance(axes, OrderedDict)

	log.info("Generating avar")

	avar = newTable('avar')

	interesting = False
	for axis in axes.values():
		# Currently, some rasterizers require that the default value maps
		# (-1 to -1, 0 to 0, and 1 to 1) be present for all the segment
		# maps, even when the default normalization mapping for the axis
		# was not modified.
		# https://github.com/googlei18n/fontmake/issues/295
		# https://github.com/fonttools/fonttools/issues/1011
		# TODO(anthrotype) revert this (and 19c4b37) when issue is fixed
		curve = avar.segments[axis.tag] = {-1.0: -1.0, 0.0: 0.0, 1.0: 1.0}
		if not axis.map:
			continue

		items = sorted(axis.map)
		keys = [item[0] for item in items]
		vals = [item[1] for item in items]

		# Current avar requirements.  We don't have to enforce
		# these on the designer and can deduce some ourselves,
		# but for now just enforce them.
		assert axis.minimum == min(keys)
		assert axis.maximum == max(keys)
		assert axis.default in keys
		# No duplicates
		assert len(set(keys)) == len(keys)
		assert len(set(vals)) == len(vals)
		# Ascending values
		assert sorted(vals) == vals

		keys_triple = (axis.minimum, axis.default, axis.maximum)
		vals_triple = tuple(axis.map_forward(v) for v in keys_triple)

		keys = [models.normalizeValue(v, keys_triple) for v in keys]
		vals = [models.normalizeValue(v, vals_triple) for v in vals]

		if all(k == v for k, v in zip(keys, vals)):
			continue
		interesting = True

		curve.update(zip(keys, vals))

		assert 0.0 in curve and curve[0.0] == 0.0
		assert -1.0 not in curve or curve[-1.0] == -1.0
		assert +1.0 not in curve or curve[+1.0] == +1.0
		# curve.update({-1.0: -1.0, 0.0: 0.0, 1.0: 1.0})

	assert "avar" not in font
	if not interesting:
		log.info("No need for avar")
		avar = None
	else:
		font['avar'] = avar

	return avar
Beispiel #9
0
def _add_fvar_avar(font, axes, instances):
    """
	Add 'fvar' table to font.

	axes is an ordered dictionary of DesignspaceAxis objects.

	instances is list of dictionary objects with 'location', 'stylename',
	and possibly 'postscriptfontname' entries.
	"""

    assert axes
    assert isinstance(axes, OrderedDict)

    log.info("Generating fvar / avar")

    fvar = newTable('fvar')
    nameTable = font['name']

    for a in axes.values():
        axis = Axis()
        axis.axisTag = Tag(a.tag)
        axis.minValue, axis.defaultValue, axis.maxValue = a.minimum, a.default, a.maximum
        axis.axisNameID = nameTable.addName(tounicode(a.labelname['en']))
        # TODO:
        # Replace previous line with the following when the following issues are resolved:
        # https://github.com/fonttools/fonttools/issues/930
        # https://github.com/fonttools/fonttools/issues/931
        # axis.axisNameID = nameTable.addMultilingualName(a.labelname, font)
        fvar.axes.append(axis)

    for instance in instances:
        coordinates = instance['location']
        name = tounicode(instance['stylename'])
        psname = instance.get('postscriptfontname')

        inst = NamedInstance()
        inst.subfamilyNameID = nameTable.addName(name)
        if psname is not None:
            psname = tounicode(psname)
            inst.postscriptNameID = nameTable.addName(psname)
        inst.coordinates = {
            axes[k].tag: axes[k].map_backward(v)
            for k, v in coordinates.items()
        }
        fvar.instances.append(inst)

    avar = newTable('avar')
    interesting = False
    for axis in axes.values():
        curve = avar.segments[axis.tag] = {}
        if not axis.map or all(k == v for k, v in axis.map.items()):
            continue
        interesting = True

        items = sorted(axis.map.items())
        keys = [item[0] for item in items]
        vals = [item[1] for item in items]

        # Current avar requirements.  We don't have to enforce
        # these on the designer and can deduce some ourselves,
        # but for now just enforce them.
        assert axis.minimum == min(keys)
        assert axis.maximum == max(keys)
        assert axis.default in keys
        # No duplicates
        assert len(set(keys)) == len(keys)
        assert len(set(vals)) == len(vals)
        # Ascending values
        assert sorted(vals) == vals

        keys_triple = (axis.minimum, axis.default, axis.maximum)
        vals_triple = tuple(axis.map_forward(v) for v in keys_triple)

        keys = [models.normalizeValue(v, keys_triple) for v in keys]
        vals = [models.normalizeValue(v, vals_triple) for v in vals]
        curve.update(zip(keys, vals))

    if not interesting:
        log.info("No need for avar")
        avar = None

    assert "fvar" not in font
    font['fvar'] = fvar
    assert "avar" not in font
    if avar:
        font['avar'] = avar

    return fvar, avar
Beispiel #10
0
def _add_fvar_avar(font, axes, instances):
	"""
	Add 'fvar' table to font.

	axes is an ordered dictionary of DesignspaceAxis objects.

	instances is list of dictionary objects with 'location', 'stylename',
	and possibly 'postscriptfontname' entries.
	"""

	assert axes
	assert isinstance(axes, OrderedDict)

	log.info("Generating fvar / avar")

	fvar = newTable('fvar')
	nameTable = font['name']

	for a in axes.values():
		axis = Axis()
		axis.axisTag = Tag(a.tag)
		axis.minValue, axis.defaultValue, axis.maxValue = a.minimum, a.default, a.maximum
		axis.axisNameID = nameTable.addName(tounicode(a.labelname['en']))
		# TODO:
		# Replace previous line with the following when the following issues are resolved:
		# https://github.com/fonttools/fonttools/issues/930
		# https://github.com/fonttools/fonttools/issues/931
		# axis.axisNameID = nameTable.addMultilingualName(a.labelname, font)
		fvar.axes.append(axis)

	for instance in instances:
		coordinates = instance['location']
		name = tounicode(instance['stylename'])
		psname = instance.get('postscriptfontname')

		inst = NamedInstance()
		inst.subfamilyNameID = nameTable.addName(name)
		if psname is not None:
			psname = tounicode(psname)
			inst.postscriptNameID = nameTable.addName(psname)
		inst.coordinates = {axes[k].tag:axes[k].map_backward(v) for k,v in coordinates.items()}
		fvar.instances.append(inst)

	avar = newTable('avar')
	interesting = False
	for axis in axes.values():
		curve = avar.segments[axis.tag] = {}
		if not axis.map or all(k==v for k,v in axis.map.items()):
			continue
		interesting = True

		items = sorted(axis.map.items())
		keys   = [item[0] for item in items]
		vals = [item[1] for item in items]

		# Current avar requirements.  We don't have to enforce
		# these on the designer and can deduce some ourselves,
		# but for now just enforce them.
		assert axis.minimum == min(keys)
		assert axis.maximum == max(keys)
		assert axis.default in keys
		# No duplicates
		assert len(set(keys)) == len(keys)
		assert len(set(vals)) == len(vals)
		# Ascending values
		assert sorted(vals) == vals

		keys_triple = (axis.minimum, axis.default, axis.maximum)
		vals_triple = tuple(axis.map_forward(v) for v in keys_triple)

		keys = [models.normalizeValue(v, keys_triple) for v in keys]
		vals = [models.normalizeValue(v, vals_triple) for v in vals]
		curve.update(zip(keys, vals))

	if not interesting:
		log.info("No need for avar")
		avar = None

	assert "fvar" not in font
	font['fvar'] = fvar
	assert "avar" not in font
	if avar:
		font['avar'] = avar

	return fvar,avar