#!/usr/bin/env python3

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

filename_input = "rgb-16bits.tif"
filename_output = "rgb-16bits-DCDM.tif"

"""
DCDM 16 bits is a fake 16 bits
We put 12 bits inside 16 bits !

12 bits component   [ FFF ]
                       |
                       v v------ fill 4 bits (0x0)
16 bits container   [ FFF0 ]

"""

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(f"==== Pixel {page_index}{line_index}{pixel_index} =====")

					print(f"Read 16 bits data\t:\t", end="")
					print(f"Red = 0x{pixel[0]:04x}\tGreen = 0x{pixel[1]:04x}\tBlue = 0x{pixel[2]:04x}")

					"""
					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(f"Place into 1...0 Map\t:\t", end="")
					red1   = (pixel[0] / 0xFFFF)
					green1 = (pixel[1] / 0xFFFF)
					blue1  = (pixel[2] / 0xFFFF)
					print(f"Red = {red1:.04f}\tGreen = {green1:.04f}\tBlue = {blue1:.04f}")

					print(f"Conversion to 12 bits\t:\t", end="")
					red12   = (red1 * 0xFFF)      # FFF = 4095 (max value for 12 bits)
					green12 = (green1 * 0xFFF)    # FFF = 4095 (max value for 12 bits)
					blue12  = (blue1 * 0xFFF)     # FFF = 4095 (max value for 12 bits)
					print(f"Red = {red12:.02f}\tGreen = {green12:.02f}\tBlue = {blue12:.02f}")

					# Round
					red12_round   = int(round(red12))
					green12_round = int(round(green12))
					blue12_round  = int(round(blue12))
					print(f"Round+Int values (dec)\t:\tRed = {red12_round:d}\tGreen = {green12_round:d}\tBlue = {blue12_round:d}")
					print(f"Round+Int Values (hex)\t:\tRed = 0x{red12_round:04x}\tGreen = 0x{green12_round:04x}\tBlue = 0x{blue12_round:04x}")

					# push 6 octets (2 octets/16 bits for each components r,g,b) to bytes format
					# needed for yield
					yield red12_round.to_bytes(2, byteorder='little') \
						+ green12_round.to_bytes(2, byteorder='little') \
						+ blue12_round.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)

imwrite(
	filename_output,
	data=extract_and_convert(filename_input),  # iterate is better for memory
	photometric='rgb',
	shape=image.shape,
	dtype='uint16',  # force uint16 by component
	byteorder='>',  # force byteorder
	metadata=None
)
print(f"\nwrite to {filename_output} ... {image.shape} => uint12 inside an uint16")
