def toXML(self, writer, ttFont): axisTags = [axis.axisTag for axis in ttFont["fvar"].axes] for axis in axisTags: writer.begintag("segment", axis=axis) writer.newline() for key, value in sorted(self.segments[axis].items()): # roundtrip float -> fixed -> float to normalize TTX output # as dumped after decompiling or straight from varLib key = fixedToFloat(floatToFixed(key, 14), 14) value = fixedToFloat(floatToFixed(value, 14), 14) writer.simpletag("mapping", **{"from": key, "to": value}) writer.newline() writer.endtag("segment") writer.newline()
def decompile(self, data, axisTags): sstruct.unpack2(FVAR_INSTANCE_FORMAT, data, self) pos = sstruct.calcsize(FVAR_INSTANCE_FORMAT) for axis in axisTags: value = struct.unpack(">l", data[pos : pos + 4])[0] self.coordinates[axis] = fixedToFloat(value, 16) pos += 4
def decompileCoord_(axisTags, data, offset): coord = {} pos = offset for axis in axisTags: coord[axis] = fixedToFloat(struct.unpack(">h", data[pos:pos+2])[0], 14) pos += 2 return coord, pos
def decompile(self, data, axisTags): sstruct.unpack2(FVAR_INSTANCE_FORMAT, data, self) pos = sstruct.calcsize(FVAR_INSTANCE_FORMAT) for axis in axisTags: value = struct.unpack(">l", data[pos:pos + 4])[0] self.coordinates[axis] = fixedToFloat(value, 16) pos += 4
def decompile(self, data, ttFont): axisTags = [axis.axisTag for axis in ttFont["fvar"].axes] header = {} headerSize = sstruct.calcsize(AVAR_HEADER_FORMAT) header = sstruct.unpack(AVAR_HEADER_FORMAT, data[0:headerSize]) majorVersion = header["majorVersion"] if majorVersion != 1: raise TTLibError("unsupported 'avar' version %d" % majorVersion) pos = headerSize for axis in axisTags: segments = self.segments[axis] = {} numPairs = struct.unpack(">H", data[pos:pos+2])[0] pos = pos + 2 for _ in range(numPairs): fromValue, toValue = struct.unpack(">hh", data[pos:pos+4]) segments[fixedToFloat(fromValue, 14)] = fixedToFloat(toValue, 14) pos = pos + 4
def decompile(self, data, ttFont): axisTags = [axis.axisTag for axis in ttFont["fvar"].axes] header = {} headerSize = sstruct.calcsize(AVAR_HEADER_FORMAT) header = sstruct.unpack(AVAR_HEADER_FORMAT, data[0:headerSize]) if header["version"] != 0x00010000: raise TTLibError("unsupported 'avar' version %04x" % header["version"]) pos = headerSize for axis in axisTags: segments = self.segments[axis] = {} numPairs = struct.unpack(">H", data[pos:pos+2])[0] pos = pos + 2 for _ in range(numPairs): fromValue, toValue = struct.unpack(">hh", data[pos:pos+4]) segments[fixedToFloat(fromValue, 14)] = fixedToFloat(toValue, 14) pos = pos + 4 self.fixupSegments_(warn=warnings.warn)
def decompile(self, data, ttFont): axisTags = [axis.axisTag for axis in ttFont["fvar"].axes] header = {} headerSize = sstruct.calcsize(AVAR_HEADER_FORMAT) header = sstruct.unpack(AVAR_HEADER_FORMAT, data[0:headerSize]) majorVersion = header["majorVersion"] if majorVersion != 1: raise TTLibError("unsupported 'avar' version %d" % majorVersion) pos = headerSize for axis in axisTags: segments = self.segments[axis] = {} numPairs = struct.unpack(">H", data[pos:pos + 2])[0] pos = pos + 2 for _ in range(numPairs): fromValue, toValue = struct.unpack(">hh", data[pos:pos + 4]) segments[fixedToFloat(fromValue, 14)] = fixedToFloat(toValue, 14) pos = pos + 4
def decompile(self, data, ttFont): axisTags = [axis.axisTag for axis in ttFont["fvar"].axes] header = {} headerSize = sstruct.calcsize(AVAR_HEADER_FORMAT) header = sstruct.unpack(AVAR_HEADER_FORMAT, data[0:headerSize]) if header["version"] != 0x00010000: raise TTLibError("unsupported 'avar' version %04x" % header["version"]) pos = headerSize for axis in axisTags: segments = self.segments[axis] = {} numPairs = struct.unpack(">H", data[pos:pos + 2])[0] pos = pos + 2 for _ in range(numPairs): fromValue, toValue = struct.unpack(">hh", data[pos:pos + 4]) segments[fixedToFloat(fromValue, 14)] = fixedToFloat(toValue, 14) pos = pos + 4 self.fixupSegments_(warn=warnings.warn)
def decompileComponent(reader, axisTags): flags = reader.readUShort() numIntBitsForScale = flags & NUM_INT_BITS_FOR_SCALE_MASK scaleConverter = getToFloatConverterForNumIntBitsForScale(numIntBitsForScale) if flags & AXIS_INDICES_ARE_WORDS: numAxes = reader.readUShort() axisIndices = reader.readArray("H", 2, numAxes) hasVarIdxFlag = 0x8000 axisIndexMask = 0xFFFF - hasVarIdxFlag else: numAxes = reader.readUInt8() axisIndices = reader.readArray("B", 1, numAxes) hasVarIdxFlag = 0x80 axisIndexMask = 0xFF - hasVarIdxFlag axisHasVarIdx = [bool(axisIndex & hasVarIdxFlag) for axisIndex in axisIndices] axisIndices = [axisIndex & axisIndexMask for axisIndex in axisIndices] coord = [ (axisTags[i], dict(value=fixedToFloat(reader.readShort(), COORD_PRECISIONBITS))) for i in axisIndices ] numVarIdxs = sum(axisHasVarIdx) transform = [] for fieldName, mask in transformFieldFlags.items(): if not (flags & mask): continue value = reader.readShort() convert = transformFromIntConverters[fieldName] if convert is None: assert fieldName in {"ScaleX", "ScaleY"} convert = scaleConverter transform.append((fieldName, dict(value=convert(value)))) if flags & HAS_TRANSFORM_VARIATIONS: numVarIdxs += len(transform) varIdxs = decompileVarIdxs(reader, numVarIdxs) assert len(axisHasVarIdx) == len(coord) for hasVarIdx, (axisTag, valueDict) in zip(axisHasVarIdx, coord): if hasVarIdx: valueDict[VARIDX_KEY] = varIdxs.pop(0) if flags & HAS_TRANSFORM_VARIATIONS: for fieldName, valueDict in transform: valueDict[VARIDX_KEY] = varIdxs.pop(0) assert not varIdxs return ComponentRecord(dict(coord), dict(transform), numIntBitsForScale)
def decompile(self, data, axisTags): sstruct.unpack2(FVAR_INSTANCE_FORMAT, data, self) pos = sstruct.calcsize(FVAR_INSTANCE_FORMAT) for axis in axisTags: value = struct.unpack(">l", data[pos:pos + 4])[0] self.coordinates[axis] = fixedToFloat(value, 16) pos += 4 if pos + 2 <= len(data): self.postscriptNameID = struct.unpack(">H", data[pos:pos + 2])[0] else: self.postscriptNameID = 0xFFFF
def decompile(self, data, axisTags): sstruct.unpack2(FVAR_INSTANCE_FORMAT, data, self) pos = sstruct.calcsize(FVAR_INSTANCE_FORMAT) for axis in axisTags: value = struct.unpack(">l", data[pos : pos + 4])[0] self.coordinates[axis] = fixedToFloat(value, 16) pos += 4 if pos + 2 <= len(data): self.postscriptNameID = struct.unpack(">H", data[pos : pos + 2])[0] else: self.postscriptNameID = 0xFFFF
def test_fixedToFloat_precision14(self): self.assertEqual(0.8, fixedToFloat(13107, 14)) self.assertEqual(0.0, fixedToFloat(0, 14)) self.assertEqual(1.0, fixedToFloat(16384, 14)) self.assertEqual(-1.0, fixedToFloat(-16384, 14)) self.assertEqual(0.99994, fixedToFloat(16383, 14)) self.assertEqual(-0.99994, fixedToFloat(-16383, 14))
def test_fixedToFloat_return_float(self): value = fixedToFloat(16384, 14) self.assertIsInstance(value, float)
def test_fixedToFloat_precision6(self): self.assertAlmostEqual(-9.98, fixedToFloat(-639, 6)) self.assertAlmostEqual(-10.0, fixedToFloat(-640, 6)) self.assertAlmostEqual(9.98, fixedToFloat(639, 6)) self.assertAlmostEqual(10.0, fixedToFloat(640, 6))
except TypeError: # not iterable value = cls(value) else: value = cls._make(it) if value.value < minValue: raise OverflowError(f"{cls.__name__}: {value.value} < {minValue}") if value.value > maxValue: raise OverflowError(f"{cls.__name__}: {value.value} < {maxValue}") return value _to_variable_f16dot16_float = partial( _to_variable_value, cls=VariableFloat, minValue=-(2**15), maxValue=fixedToFloat(2**31 - 1, 16), ) _to_variable_f2dot14_float = partial( _to_variable_value, cls=VariableFloat, minValue=-2.0, maxValue=fixedToFloat(2**15 - 1, 14), ) _to_variable_int16 = partial( _to_variable_value, cls=VariableInt, minValue=-(2**15), maxValue=2**15 - 1, ) _to_variable_uint16 = partial( _to_variable_value,
def test_roundtrip(self): for bits in range(0, 15): for value in range(-(2**(bits+1)), 2**(bits+1)): self.assertEqual(value, floatToFixed(fixedToFloat(value, bits), bits))
result.insert(0, frozenset()) return result def build(self): glyphClasses = {} for classID, glyphs in enumerate(self.classes()): if classID == 0: continue for glyph in glyphs: glyphClasses[glyph] = classID classDef = ot.ClassDef() classDef.classDefs = glyphClasses return classDef AXIS_VALUE_NEGATIVE_INFINITY = fixedToFloat(-0x80000000, 16) AXIS_VALUE_POSITIVE_INFINITY = fixedToFloat(0x7FFFFFFF, 16) 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",
def read_fixed1616(self, b0, data, index): value, = struct.unpack(">l", data[index:index+4]) return fixedToFloat(value, precisionBits=16), index+4
def test_roundtrip(self): for bits in range(0, 15): for value in range(-(2**(bits + 1)), 2**(bits + 1)): self.assertEqual(value, floatToFixed(fixedToFloat(value, bits), bits))