Exemple #1
0
def _add_stat(font, axes):
    # for now we just get the axis tags and nameIDs from the fvar,
    # so we can reuse the same nameIDs which were defined in there.
    # TODO make use of 'axes' once it adds style attributes info:
    # https://github.com/LettError/designSpaceDocument/issues/8

    if "STAT" in font:
        return

    fvarTable = font['fvar']

    STAT = font["STAT"] = newTable('STAT')
    stat = STAT.table = ot.STAT()
    stat.Version = 0x00010001

    axisRecords = []
    for i, a in enumerate(fvarTable.axes):
        axis = ot.AxisRecord()
        axis.AxisTag = Tag(a.axisTag)
        axis.AxisNameID = a.axisNameID
        axis.AxisOrdering = i
        axisRecords.append(axis)

    axisRecordArray = ot.AxisRecordArray()
    axisRecordArray.Axis = axisRecords
    # XXX these should not be hard-coded but computed automatically
    stat.DesignAxisRecordSize = 8
    stat.DesignAxisCount = len(axisRecords)
    stat.DesignAxisRecord = axisRecordArray

    # for the elided fallback name, we default to the base style name.
    # TODO make this user-configurable via designspace document
    stat.ElidedFallbackNameID = 2
Exemple #2
0
def create_stat_table(ttfont):
    """Atm, Fontmake is only able to produce a basic stat table. Because of
  this, we'll create a STAT using the font's fvar table."""
    stat = newTable('STAT')
    stat.table = otTables.STAT()
    stat.table.Version = 0x00010001

    # # Build DesignAxisRecords from fvar
    stat.table.DesignAxisRecord = otTables.AxisRecordArray()
    stat.table.DesignAxisRecord.Axis = []

    stat_axises = stat.table.DesignAxisRecord.Axis

    # TODO (M Foley) add support for fonts which have multiple
    # axises e.g Barlow
    if len(ttfont['fvar'].axes) > 1:
        raise Exception('VFs with more than one axis are currently '
                        'not supported.')

    for idx, axis in enumerate(ttfont['fvar'].axes):
        append_stat_axis(stat, axis.axisTag, axis.axisNameID)

    # Build AxisValueArrays for each namedInstance from fvar namedInstances
    stat.table.AxisValueArray = otTables.AxisValueArray()
    stat.table.AxisValueArray.AxisValue = []

    for idx, instance in enumerate(ttfont['fvar'].instances):
        append_stat_record(stat, 0,
                           list(instance.coordinates.values())[0],
                           instance.subfamilyNameID)

    # Set ElidedFallbackNameID
    stat.table.ElidedFallbackNameID = 2
    ttfont['STAT'] = stat
Exemple #3
0
def _add_stat(font, axes):

    if "STAT" in font:
        return

    nameTable = font['name']

    STAT = font["STAT"] = newTable('STAT')
    stat = STAT.table = ot.STAT()
    stat.Version = 0x00010000

    axisRecords = []
    for i, a in enumerate(axes.values()):
        axis = ot.AxisRecord()
        axis.AxisTag = Tag(a.tag)
        # Meh. Reuse fvar nameID!
        axis.AxisNameID = nameTable.addName(tounicode(a.labelname['en']))
        axis.AxisOrdering = i
        axisRecords.append(axis)

    axisRecordArray = ot.AxisRecordArray()
    axisRecordArray.Axis = axisRecords
    # XXX these should not be hard-coded but computed automatically
    stat.DesignAxisRecordSize = 8
    stat.DesignAxisCount = len(axisRecords)
    stat.DesignAxisRecord = axisRecordArray
Exemple #4
0
def _new_empty_STAT_table():
    stat_table = fontTools.ttLib.newTable("STAT")
    stat_table.table = otTables.STAT()
    stat_table.table.Version = 0x00010001
    stat_table.table.DesignAxisRecord = otTables.AxisRecordArray()
    stat_table.table.DesignAxisRecord.Axis = []
    stat_table.table.AxisValueArray = otTables.AxisValueArray()
    stat_table.table.AxisValueArray.AxisValue = []
    return stat_table
Exemple #5
0
def makeSTAT(fvar):
	newSTAT = newTable("STAT")
	newSTAT.table = otTables.STAT()
	xmlData = ["<?xml version=\"1.0\" encoding=\"UTF-8\"?>",
				"<ttFont sfntVersion=\"OTTO\" ttLibVersion=\"3.11\">",
				"<STAT>",
				"\t<Version value=\"0x00010001\"/>",
				"\t<DesignAxisRecordSize value=\"8\"/>","\t<DesignAxisRecord>"]
	i = 0
	for a in fvar.axes:
		xmlData.append("\t\t<Axis index=\"%s\">" % (i))
		xmlData.append("\t\t\t<AxisTag value=\"%s\"/>" % (a.axisTag))
		xmlData.append("\t\t\t<AxisNameID value=\"%s\"/>" % (a.axisNameID))
		xmlData.append("\t\t\t<AxisOrdering value=\"%s\"/>" % (i))
		xmlData.append("\t\t</Axis>")
		i += 1

	xmlData.append("\t</DesignAxisRecord>")
	xmlData.append("\t<AxisValueArray>")
	# For each axis in turn, cycle through the named instances and
	# make a AxisValue entry for the instance of each new named instance when
	# the other axes are at 0.
	numAxes = len(fvar.axes)
	numInstances = len(fvar.instances)
	fallBackNameID = None
	for axisIndex in range(numAxes):
		axisTag = fvar.axes[axisIndex].axisTag
		seenCoordinate = {}
		axisList = []
		valueIndex = 0
		for j in range(numInstances):
			flagValue = 0
			instance = fvar.instances[j]
			entry = getNewAxisValue(seenCoordinate, instance, axisTag)
			if entry == None:
				continue
			axisValue, nameID = entry
# 			if (axisValue == 0) and (axisTag == 'wght'):
# 				# the style name from any other axis will probably
# 				# already be elided from the style name.
# 				fallBackNameID = nameID
# 				flagValue = 2
			axisEntry = AxisValueRecord(nameID, axisValue, flagValue, valueIndex, axisIndex)
			axisList.append(axisEntry)
			valueIndex += 1

		numEntries =len(axisList)
		linkDelta = None
		if numEntries == 0:
			continue
		if numEntries == 1:
			addAxisValueData(xmlData, None, axisList[0], None, linkDelta)
			continue
		if numEntries == 2:
			addAxisValueData(xmlData, None, axisList[0], axisList[1], linkDelta)
			addAxisValueData(xmlData, axisList[0], axisList[1], None, linkDelta)
			continue

		prevEntry = nextEntry = None
		for j in range(numEntries-1):
			axisEntry = axisList[j]
			nextEntry = axisList[j+1]
			addAxisValueData(xmlData, prevEntry, axisEntry, nextEntry, linkDelta)
			prevEntry = axisEntry
		addAxisValueData(xmlData, axisEntry, nextEntry, None, linkDelta)

	xmlData.append("\t</AxisValueArray>")

	if fallBackNameID == None:
		fallBackNameID = 2
	xmlData.append("\t<ElidedFallbackNameID value=\"%s\" />" % (fallBackNameID))
	xmlData.append("</STAT>")
	xmlData.append("</ttFont>")
	xmlData.append("")
	xmlData = os.linesep.join(xmlData)
	return xmlData
Exemple #6
0
def buildStatTable(ttFont, axes, locations=None, elidedFallbackName=2):
    """Add a 'STAT' table to 'ttFont'.

    'axes' is a list of dictionaries describing axes and their
    values.

    Example:

    axes = [
        dict(
            tag="wght",
            name="Weight",
            ordering=0,  # optional
            values=[
                dict(value=100, name='Thin'),
                dict(value=300, name='Light'),
                dict(value=400, name='Regular', flags=0x2),
                dict(value=900, name='Black'),
            ],
        )
    ]

    Each axis dict must have 'tag' and 'name' items. 'tag' maps
    to the 'AxisTag' field. 'name' can be a name ID (int), a string,
    or a dictionary containing multilingual names (see the
    addMultilingualName() name table method), and will translate to
    the AxisNameID field.

    An axis dict may contain an 'ordering' item that maps to the
    AxisOrdering field. If omitted, the order of the axes list is
    used to calculate AxisOrdering fields.

    The axis dict may contain a 'values' item, which is a list of
    dictionaries describing AxisValue records belonging to this axis.

    Each value dict must have a 'name' item, which can be a name ID
    (int), a string, or a dictionary containing multilingual names,
    like the axis name. It translates to the ValueNameID field.

    Optionally the value dict can contain a 'flags' item. It maps to
    the AxisValue Flags field, and will be 0 when omitted.

    The format of the AxisValue is determined by the remaining contents
    of the value dictionary:

    If the value dict contains a 'value' item, an AxisValue record
    Format 1 is created. If in addition to the 'value' item it contains
    a 'linkedValue' item, an AxisValue record Format 3 is built.

    If the value dict contains a 'nominalValue' item, an AxisValue
    record Format 2 is built. Optionally it may contain 'rangeMinValue'
    and 'rangeMaxValue' items. These map to -Infinity and +Infinity
    respectively if omitted.

    You cannot specify Format 4 AxisValue tables this way, as they are
    not tied to a single axis, and specify a name for a location that
    is defined by multiple axes values. Instead, you need to supply the
    'locations' argument.

    The optional 'locations' argument specifies AxisValue Format 4
    tables. It should be a list of dicts, where each dict has a 'name'
    item, which works just like the value dicts above, an optional
    'flags' item (defaulting to 0x0), and a 'location' dict. A
    location dict key is an axis tag, and the associated value is the
    location on the specified axis. They map to the AxisIndex and Value
    fields of the AxisValueRecord.

    Example:

    locations = [
        dict(name='Regular ABCD', location=dict(wght=300, ABCD=100)),
        dict(name='Bold ABCD XYZ', location=dict(wght=600, ABCD=200)),
    ]

    The optional 'elidedFallbackName' argument can be a name ID (int),
    a string, or a dictionary containing multilingual names. It
    translates to the ElidedFallbackNameID field.

    The 'ttFont' argument must be a TTFont instance that already has a
    'name' table. If a 'STAT' table already exists, it will be
    overwritten by the newly created one.
    """
    ttFont["STAT"] = ttLib.newTable("STAT")
    statTable = ttFont["STAT"].table = ot.STAT()
    nameTable = ttFont["name"]
    statTable.ElidedFallbackNameID = _addName(nameTable, elidedFallbackName)

    # 'locations' contains data for AxisValue Format 4
    axisRecords, axisValues = _buildAxisRecords(axes, nameTable)
    if not locations:
        statTable.Version = 0x00010001
    else:
        # We'll be adding Format 4 AxisValue records, which
        # requires a higher table version
        statTable.Version = 0x00010002
        multiAxisValues = _buildAxisValuesFormat4(locations, axes, nameTable)
        axisValues = multiAxisValues + axisValues

    # Store AxisRecords
    axisRecordArray = ot.AxisRecordArray()
    axisRecordArray.Axis = axisRecords
    # XXX these should not be hard-coded but computed automatically
    statTable.DesignAxisRecordSize = 8
    statTable.DesignAxisRecord = axisRecordArray
    statTable.DesignAxisCount = len(axisRecords)

    if axisValues:
        # Store AxisValueRecords
        axisValueArray = ot.AxisValueArray()
        axisValueArray.AxisValue = axisValues
        statTable.AxisValueArray = axisValueArray
        statTable.AxisValueCount = len(axisValues)