Apparently Python 2 and Python 3 have different default print precisions for floats. Or at least with my build it is the case. As such, for example with amiri-regular.ttf I see these annoying differences in the ttx output of the two versions: 77203c77203 < <component ... scale="0.5999755859375" flags="0x1004"/> --- > <component ... scale="0.599975585938" flags="0x1004"/> That's just gross. Specially when these numbers are show to humans, while we know that's just 0.6. The fixedToFloat() routine in this module is smart enough to do that. Not used yet.
66 lines
1.4 KiB
Python
66 lines
1.4 KiB
Python
"""fontTools.misc.fixedTools.py -- tools for working with fixed numbers.
|
|
"""
|
|
|
|
from __future__ import print_function, division
|
|
from fontTools.misc.py23 import *
|
|
|
|
__all__ = [
|
|
"fixedToFloat",
|
|
"floatToFixed",
|
|
]
|
|
|
|
def fixedToFloat(value, precisionBits):
|
|
"""Converts a fixed-point number to a float, choosing the float
|
|
that has the shortest decimal reprentation. Eg. to convert a
|
|
fixed number in a 2.14 format, use precisionBits=14. This is
|
|
pretty slow compared to a simple division. Use sporadically.
|
|
|
|
>>> fixedToFloat(13107, 14)
|
|
0.8
|
|
>>> fixedToFloat(0, 14)
|
|
0.0
|
|
>>> fixedToFloat(0x4000, 14)
|
|
1.0
|
|
"""
|
|
|
|
if not value: return 0.0
|
|
|
|
scale = 1 << precisionBits
|
|
value /= scale
|
|
eps = .5 / scale
|
|
digits = (precisionBits + 2) // 3
|
|
fmt = "%%.%df" % digits
|
|
lo = fmt % (value - eps)
|
|
hi = fmt % (value + eps)
|
|
out = []
|
|
length = min(len(lo), len(hi))
|
|
for i in range(length):
|
|
if lo[i] != hi[i]:
|
|
break;
|
|
out.append(lo[i])
|
|
outlen = len(out)
|
|
if outlen < length:
|
|
out.append(max(lo[outlen], hi[outlen]))
|
|
return float(strjoin(out))
|
|
|
|
def floatToFixed(value, precisionBits):
|
|
"""Converts a float to a fixed-point number given the number of
|
|
precisionBits. Ie. int(round(value * (1<<precisionBits))).
|
|
|
|
>>> floatToFixed(0.8, 14)
|
|
13107
|
|
>>> floatToFixed(1.0, 14)
|
|
16384
|
|
>>> floatToFixed(1, 14)
|
|
16384
|
|
>>> floatToFixed(0, 14)
|
|
0
|
|
"""
|
|
|
|
return int(round(value * (1<<precisionBits)))
|
|
|
|
|
|
if __name__ == "__main__":
|
|
import doctest
|
|
doctest.testmod()
|