#!/usr/bin/env python3

# python3 -m pip install -U tifffile[all]
from tifffile import (imread, imwrite, TiffFile)

filename_input = "rgb-16bits.tif"
filename_output = "xyz-16bits-without-gamma.tif"


def extract_and_convert(filename_input):

	with TiffFile(filename_input) as tif:
		for page_index, page in enumerate(tif.pages):
			for line_index, line in enumerate(page.asarray()):
				for pixel_index, pixel in enumerate(line):

					print("======= Pixel (%d,%d,%d) ======" % (page_index, line_index, pixel_index))
					print("R = 0x%04x" % pixel[0], "G = 0x%04x" % pixel[1], "B = 0x%04x" % pixel[2])

					"""
					to divide by the maximum value of 16 bits, you put your value inside [0...1] range
					where   0x0000 = 0.0000
							0xFF00 = 0.5000
							0xFFFF = 1.0000
					with this value, you can now move this value inside any space !
					if you want to put this value inside :
					8 bits space  =   <value> * 0xFF
					12 bits space =   <value> * 0xFFF
					16 bits space =   <value> * 0xFFFF
					32 bits space =   <value> * 0xFFFFFFFF
					"""

					print("map 16 bits to [0...1] range")
					r_p = (pixel[0] / 0xFFFF)
					g_p = (pixel[1] / 0xFFFF)
					b_p = (pixel[2] / 0xFFFF)
					print("Rp = %f" % r_p, "Gp = %f" % g_p, "Bp = %f" % b_p)

					# RGB -> XYZ
					print("---- RGB -> XYZ ----")
					x = (r_p * 0.4451698156) + (g_p * 0.2771344092) + (b_p * 0.1722826698)
					y = (r_p * 0.2094916779) + (g_p * 0.7215952542) + (b_p * 0.0689130679)
					z = (r_p * 0.0000000000) + (g_p * 0.0470605601) + (b_p * 0.9073553944)
					print("x = %f" % x, "y = %f" % y, "z = %f" % z)

					print("unmap 16 bits from [0...1] range")
					r_p = (x * 0xFFFF)
					g_p = (y * 0xFFFF)
					b_p = (z * 0xFFFF)
					print("Rp = %f" % r_p, "Gp = %f" % g_p, "Bp = %f" % b_p)
					r_p_r = int(round(r_p))
					g_p_r = int(round(g_p))
					b_p_r = int(round(b_p))
					print("Rp' = %f" % r_p_r, "Gp' = %f" % g_p_r, "Bp' = %f" % b_p_r)
					print("Rp' = 0x%04x" % r_p_r, "Gp' = 0x%04x" % g_p_r, "Bp' = 0x%04x" % b_p_r)

					# push 6 octets (2 octets for each components r,g,b) to bytes format
					# needed for yield
					yield r_p_r.to_bytes(2, byteorder='little') \
						+ g_p_r.to_bytes(2, byteorder='little') \
						+ b_p_r.to_bytes(2, byteorder='little')



# get informations about input file
image = imread(filename_input)

# shape = (width, height, number_of_components)
print("shape =", image.shape)
# dtype = size_of_component (ex: uint16)
print("dtype =", image.dtype)

print(f"\nwrite to {filename_output}... {image.shape} => {image.dtype}")
imwrite(
	filename_output,
	data=extract_and_convert(filename_input),    # iterate is better for memory
	photometric='rgb',	   # don't care because XYZ have 3 components too
	shape=image.shape,
	dtype=image.dtype,
	metadata=None
)
