diff options
author | shumkovnd <shumkovnd@yandex-team.com> | 2023-11-10 14:39:34 +0300 |
---|---|---|
committer | shumkovnd <shumkovnd@yandex-team.com> | 2023-11-10 16:42:24 +0300 |
commit | 77eb2d3fdcec5c978c64e025ced2764c57c00285 (patch) | |
tree | c51edb0748ca8d4a08d7c7323312c27ba1a8b79a /contrib/python/fonttools/fontTools/misc/fixedTools.py | |
parent | dd6d20cadb65582270ac23f4b3b14ae189704b9d (diff) | |
download | ydb-77eb2d3fdcec5c978c64e025ced2764c57c00285.tar.gz |
KIKIMR-19287: add task_stats_drawing script
Diffstat (limited to 'contrib/python/fonttools/fontTools/misc/fixedTools.py')
-rw-r--r-- | contrib/python/fonttools/fontTools/misc/fixedTools.py | 253 |
1 files changed, 253 insertions, 0 deletions
diff --git a/contrib/python/fonttools/fontTools/misc/fixedTools.py b/contrib/python/fonttools/fontTools/misc/fixedTools.py new file mode 100644 index 00000000000..330042871c5 --- /dev/null +++ b/contrib/python/fonttools/fontTools/misc/fixedTools.py @@ -0,0 +1,253 @@ +""" +The `OpenType specification <https://docs.microsoft.com/en-us/typography/opentype/spec/otff#data-types>`_ +defines two fixed-point data types: + +``Fixed`` + A 32-bit signed fixed-point number with a 16 bit twos-complement + magnitude component and 16 fractional bits. +``F2DOT14`` + A 16-bit signed fixed-point number with a 2 bit twos-complement + magnitude component and 14 fractional bits. + +To support reading and writing data with these data types, this module provides +functions for converting between fixed-point, float and string representations. + +.. data:: MAX_F2DOT14 + + The maximum value that can still fit in an F2Dot14. (1.99993896484375) +""" + +from .roundTools import otRound, nearestMultipleShortestRepr +import logging + +log = logging.getLogger(__name__) + +__all__ = [ + "MAX_F2DOT14", + "fixedToFloat", + "floatToFixed", + "floatToFixedToFloat", + "floatToFixedToStr", + "fixedToStr", + "strToFixed", + "strToFixedToFloat", + "ensureVersionIsLong", + "versionToFixed", +] + + +MAX_F2DOT14 = 0x7FFF / (1 << 14) + + +def fixedToFloat(value, precisionBits): + """Converts a fixed-point number to a float given the number of + precision bits. + + Args: + value (int): Number in fixed-point format. + precisionBits (int): Number of precision bits. + + Returns: + Floating point value. + + Examples:: + + >>> import math + >>> f = fixedToFloat(-10139, precisionBits=14) + >>> math.isclose(f, -0.61883544921875) + True + """ + return value / (1 << precisionBits) + + +def floatToFixed(value, precisionBits): + """Converts a float to a fixed-point number given the number of + precision bits. + + Args: + value (float): Floating point value. + precisionBits (int): Number of precision bits. + + Returns: + int: Fixed-point representation. + + Examples:: + + >>> floatToFixed(-0.61883544921875, precisionBits=14) + -10139 + >>> floatToFixed(-0.61884, precisionBits=14) + -10139 + """ + return otRound(value * (1 << precisionBits)) + + +def floatToFixedToFloat(value, precisionBits): + """Converts a float to a fixed-point number and back again. + + By converting the float to fixed, rounding it, and converting it back + to float again, this returns a floating point values which is exactly + representable in fixed-point format. + + Note: this **is** equivalent to ``fixedToFloat(floatToFixed(value))``. + + Args: + value (float): The input floating point value. + precisionBits (int): Number of precision bits. + + Returns: + float: The transformed and rounded value. + + Examples:: + >>> import math + >>> f1 = -0.61884 + >>> f2 = floatToFixedToFloat(-0.61884, precisionBits=14) + >>> f1 != f2 + True + >>> math.isclose(f2, -0.61883544921875) + True + """ + scale = 1 << precisionBits + return otRound(value * scale) / scale + + +def fixedToStr(value, precisionBits): + """Converts a fixed-point number to a string representing a decimal float. + + This chooses the float that has the shortest decimal representation (the least + number of fractional decimal digits). + + For example, to convert a fixed-point number in a 2.14 format, use + ``precisionBits=14``:: + + >>> fixedToStr(-10139, precisionBits=14) + '-0.61884' + + This is pretty slow compared to the simple division used in ``fixedToFloat``. + Use sporadically when you need to serialize or print the fixed-point number in + a human-readable form. + It uses nearestMultipleShortestRepr under the hood. + + Args: + value (int): The fixed-point value to convert. + precisionBits (int): Number of precision bits, *up to a maximum of 16*. + + Returns: + str: A string representation of the value. + """ + scale = 1 << precisionBits + return nearestMultipleShortestRepr(value / scale, factor=1.0 / scale) + + +def strToFixed(string, precisionBits): + """Converts a string representing a decimal float to a fixed-point number. + + Args: + string (str): A string representing a decimal float. + precisionBits (int): Number of precision bits, *up to a maximum of 16*. + + Returns: + int: Fixed-point representation. + + Examples:: + + >>> ## to convert a float string to a 2.14 fixed-point number: + >>> strToFixed('-0.61884', precisionBits=14) + -10139 + """ + value = float(string) + return otRound(value * (1 << precisionBits)) + + +def strToFixedToFloat(string, precisionBits): + """Convert a string to a decimal float with fixed-point rounding. + + This first converts string to a float, then turns it into a fixed-point + number with ``precisionBits`` fractional binary digits, then back to a + float again. + + This is simply a shorthand for fixedToFloat(floatToFixed(float(s))). + + Args: + string (str): A string representing a decimal float. + precisionBits (int): Number of precision bits. + + Returns: + float: The transformed and rounded value. + + Examples:: + + >>> import math + >>> s = '-0.61884' + >>> bits = 14 + >>> f = strToFixedToFloat(s, precisionBits=bits) + >>> math.isclose(f, -0.61883544921875) + True + >>> f == fixedToFloat(floatToFixed(float(s), precisionBits=bits), precisionBits=bits) + True + """ + value = float(string) + scale = 1 << precisionBits + return otRound(value * scale) / scale + + +def floatToFixedToStr(value, precisionBits): + """Convert float to string with fixed-point rounding. + + This uses the shortest decimal representation (ie. the least + number of fractional decimal digits) to represent the equivalent + fixed-point number with ``precisionBits`` fractional binary digits. + It uses nearestMultipleShortestRepr under the hood. + + >>> floatToFixedToStr(-0.61883544921875, precisionBits=14) + '-0.61884' + + Args: + value (float): The float value to convert. + precisionBits (int): Number of precision bits, *up to a maximum of 16*. + + Returns: + str: A string representation of the value. + + """ + scale = 1 << precisionBits + return nearestMultipleShortestRepr(value, factor=1.0 / scale) + + +def ensureVersionIsLong(value): + """Ensure a table version is an unsigned long. + + OpenType table version numbers are expressed as a single unsigned long + comprising of an unsigned short major version and unsigned short minor + version. This function detects if the value to be used as a version number + looks too small (i.e. is less than ``0x10000``), and converts it to + fixed-point using :func:`floatToFixed` if so. + + Args: + value (Number): a candidate table version number. + + Returns: + int: A table version number, possibly corrected to fixed-point. + """ + if value < 0x10000: + newValue = floatToFixed(value, 16) + log.warning( + "Table version value is a float: %.4f; " "fix to use hex instead: 0x%08x", + value, + newValue, + ) + value = newValue + return value + + +def versionToFixed(value): + """Ensure a table version number is fixed-point. + + Args: + value (str): a candidate table version number. + + Returns: + int: A table version number, possibly corrected to fixed-point. + """ + value = int(value, 0) if value.startswith("0") else float(value) + value = ensureVersionIsLong(value) + return value |