#!/usr/bin/env python # Store 32-bit floating point number within three 8bit channels of a 32-bit RGBA pixel. # Only suitable for normalised input values in the range [0.0, 1.0). # # Refer: https://aras-p.info/blog/2009/07/30/encoding-floats-to-rgba-the-final/ import numpy as np def frac(x): return x - np.floor(x) def encode(v): enc = np.float32((1.0, 256.0, 256.0**2, 256.0**3)) * v enc = frac(enc) enc -= (enc[0], enc[1], enc[2], enc[2]) * np.float32((1/256.0, 1/256.0, 1/256.0, 0.0)) return enc def decode(rgba): return np.dot(rgba, np.float32((1.0, 1/256.0, 1/(256.0**2), 1/(256.0**3)))) if __name__ == "__main__": max_diff = 0.0 for x in np.linspace(0.0, 1.0, 1000, endpoint=False): enc = encode(x) enc8 = np.uint8(enc * 256.0) dec8 = enc8 / 256.0 dec = decode(dec8) max_diff = np.maximum(max_diff, x - dec) print(f"{x}: {x - dec}") print(f"Max diff {max_diff}")