def _buildAxisRecords(axes, nameTable): axisRecords = [] axisValues = [] for axisRecordIndex, axisDict in enumerate(axes): axis = ot.AxisRecord() axis.AxisTag = axisDict["tag"] axis.AxisNameID = _addName(nameTable, axisDict["name"]) axis.AxisOrdering = axisDict.get("ordering", axisRecordIndex) axisRecords.append(axis) for axisVal in axisDict.get("values", ()): axisValRec = ot.AxisValue() axisValRec.AxisIndex = axisRecordIndex axisValRec.Flags = axisVal.get("flags", 0) axisValRec.ValueNameID = _addName(nameTable, axisVal['name']) if "value" in axisVal: axisValRec.Value = axisVal["value"] if "linkedValue" in axisVal: axisValRec.Format = 3 axisValRec.LinkedValue = axisVal["linkedValue"] else: axisValRec.Format = 1 elif "nominalValue" in axisVal: axisValRec.Format = 2 axisValRec.NominalValue = axisVal["nominalValue"] axisValRec.RangeMinValue = axisVal.get("rangeMinValue", AXIS_VALUE_NEGATIVE_INFINITY) axisValRec.RangeMaxValue = axisVal.get("rangeMaxValue", AXIS_VALUE_POSITIVE_INFINITY) else: raise ValueError("Can't determine format for AxisValue") axisValues.append(axisValRec) return axisRecords, axisValues
def test_updateNameTable_format4_axisValues(varfont): # format 4 axisValues should dominate the other axisValues stat = varfont["STAT"].table axisValue = otTables.AxisValue() axisValue.Format = 4 axisValue.Flags = 0 varfont["name"].setName("Dominant Value", 297, 3, 1, 0x409) axisValue.ValueNameID = 297 axisValue.AxisValueRecord = [] for tag, value in (("wght", 900), ("wdth", 79)): rec = otTables.AxisValueRecord() rec.AxisIndex = next( i for i, a in enumerate(stat.DesignAxisRecord.Axis) if a.AxisTag == tag ) rec.Value = value axisValue.AxisValueRecord.append(rec) stat.AxisValueArray.AxisValue.append(axisValue) instancer.names.updateNameTable(varfont, {"wdth": 79, "wght": 900}) expected = { (1, 3, 1, 0x409): "Test Variable Font Dominant Value", (2, 3, 1, 0x409): "Regular", (16, 3, 1, 0x409): "Test Variable Font", (17, 3, 1, 0x409): "Dominant Value", } _test_name_records(varfont, expected, isNonRIBBI=True)
def _update_italic_stat(ttfont): stat = ttfont['STAT'].table record = ot.AxisValue() record.AxisIndex = 2 record.Flags = 0 record.ValueNameID = 258 # Italic record.Value = 1.0 record.Format = 1 stat.AxisValueArray.AxisValue[-1] = record
def _update_roman_stat(ttfont): stat = ttfont['STAT'].table record = ot.AxisValue() record.AxisIndex = 2 record.Flags = 2 record.ValueNameID = 296 # Roman record.LinkedValue = 1 record.Value = 0 record.Format = 3 stat.AxisValueArray.AxisValue[-1] = record
def append_stat_record(stat, axis_index, value, namerecord_id, linked_value=None): records = stat.table.AxisValueArray.AxisValue axis_record = otTables.AxisValue() axis_record.Format = 1 axis_record.ValueNameID = namerecord_id axis_record.Value = value axis_record.AxisIndex = axis_index axis_record.Flags = 0 if linked_value: axis_record.Format = 3 axis_record.LinkedValue = linked_value records.append(axis_record)
def _buildAxisValuesFormat4(locations, axes, nameTable): axisTagToIndex = {} for axisRecordIndex, axisDict in enumerate(axes): axisTagToIndex[axisDict["tag"]] = axisRecordIndex axisValues = [] for axisLocationDict in locations: axisValRec = ot.AxisValue() axisValRec.Format = 4 axisValRec.ValueNameID = _addName(nameTable, axisLocationDict['name']) axisValRec.Flags = axisLocationDict.get("flags", 0) axisValueRecords = [] for tag, value in axisLocationDict["location"].items(): avr = ot.AxisValueRecord() avr.AxisIndex = axisTagToIndex[tag] avr.Value = value axisValueRecords.append(avr) axisValueRecords.sort(key=lambda avr: avr.AxisIndex) axisValRec.AxisCount = len(axisValueRecords) axisValRec.AxisValueRecord = axisValueRecords axisValues.append(axisValRec) return axisValues
def generate_name_and_STAT_variable( stylespace: statmake.classes.Stylespace, varfont: fontTools.ttLib.TTFont, additional_locations: Mapping[str, float], ): """Generate a new name and STAT table ready for insertion.""" if "fvar" not in varfont: raise ValueError( "Need a variable font with the fvar table to determine which instances " "are present.") stylespace_name_to_axis = {a.name.default: a for a in stylespace.axes} fvar_name_to_axis = {} name_to_tag: Dict[str, str] = {} name_to_index: Dict[str, int] = {} index = 0 for index, fvar_axis in enumerate(varfont["fvar"].axes): fvar_axis_name = _default_name_string(varfont, fvar_axis.axisNameID) try: stylespace_axis = stylespace_name_to_axis[fvar_axis_name] except KeyError: raise ValueError( f"No stylespace entry found for axis name '{fvar_axis_name}'.") if fvar_axis.axisTag != stylespace_axis.tag: raise ValueError( f"fvar axis '{fvar_axis_name}' tag is '{fvar_axis.axisTag}', but " f"Stylespace tag is '{stylespace_axis.tag}'.") fvar_name_to_axis[fvar_axis_name] = fvar_axis name_to_tag[fvar_axis_name] = fvar_axis.axisTag name_to_index[fvar_axis_name] = index for axis_name in additional_locations: try: stylespace_axis = stylespace_name_to_axis[axis_name] except KeyError: raise ValueError( f"No stylespace entry found for axis name '{axis_name}'.") name_to_tag[stylespace_axis.name.default] = stylespace_axis.tag index += 1 name_to_index[stylespace_axis.name.default] = index # First, determine which stops are used on which axes. The STAT table must contain # a name for each stop that is used on each axis, so each stop must have an entry # in the Stylespace. Also include locations in additional_locations that can refer # to axes not present in the current varfont. stylespace_stops: Dict[str, Set[float]] = {} for axis in stylespace.axes: stylespace_stops[axis.tag] = {l.value for l in axis.locations} for named_location in stylespace.locations: for name, value in named_location.axis_values.items(): stylespace_stops[name_to_tag[name]].add(value) axis_stops: Mapping[str, Set[float]] = collections.defaultdict( set) # tag to stops for instance in varfont["fvar"].instances: for k, v in instance.coordinates.items(): if v not in stylespace_stops[k]: raise ValueError( f"There is no Stylespace entry for stop {v} on axis {k}.") axis_stops[k].add(v) for k, v in additional_locations.items(): axis_tag = name_to_tag[k] if v not in stylespace_stops[axis_tag]: raise ValueError( f"There is no Stylespace entry for stop {v} on axis {k} (from " "additional locations).") axis_stops[axis_tag].add(v) # Construct temporary name and STAT tables for returning at the end. name_table = copy.deepcopy(varfont["name"]) stat_table = _new_empty_STAT_table() # Generate axis records. Reuse an axis' name ID if it exists, else make a new one. for axis_name, axis_tag in name_to_tag.items(): stylespace_axis = stylespace_name_to_axis[axis_name] if axis_name in fvar_name_to_axis: axis_name_id = fvar_name_to_axis[axis_name].axisNameID else: axis_name_id = name_table.addMultilingualName( stylespace_axis.name.mapping, mac=False) axis_record = _new_axis_record(tag=axis_tag, name_id=axis_name_id, ordering=stylespace_axis.ordering) stat_table.table.DesignAxisRecord.Axis.append(axis_record) # Generate formats 1, 2 and 3. for axis in stylespace.axes: for location in axis.locations: if location.value not in axis_stops[axis.tag]: continue axis_value = otTables.AxisValue() name_id = name_table.addMultilingualName(location.name.mapping, mac=False) location.fill_in_AxisValue( axis_value, axis_index=name_to_index[axis.name.default], name_id=name_id) stat_table.table.AxisValueArray.AxisValue.append(axis_value) # Generate format 4. for named_location in stylespace.locations: if all(name_to_tag[k] in axis_stops and v in axis_stops[name_to_tag[k]] for k, v in named_location.axis_values.items()): stat_table.table.Version = 0x00010002 axis_value = otTables.AxisValue() name_id = name_table.addMultilingualName( named_location.name.mapping, mac=False) named_location.fill_in_AxisValue( axis_value, axis_name_to_index=name_to_index, name_id=name_id, axis_value_record_type=otTables.AxisValueRecord, ) stat_table.table.AxisValueArray.AxisValue.append(axis_value) stat_table.table.ElidedFallbackNameID = stylespace.elided_fallback_name_id return name_table, stat_table