"""
Programme   : TP-images-partie2-correction-exo1.py
Langage     : Python 3.7.3
Modules     : Pillow 7.1.2 - matplotlib 3.2.2
Auteur      : Mathieu Pons
Description : gestion des exceptions, manipulation d'images et tracé de courbes
Pillow      : https://pillow.readthedocs.io/en/stable/
matplotlib  : https://matplotlib.org/index.html

Vous pouvez travailler sur l'image retaillée dans le TP précédent perroquet.png} ou tout autre
image de votre choix. Toutefois, veillez à disposer d'une image dont les dimensions sont
raisonnables car le parcours de l'image pixel par pixel est coûteux en terme de performance.

Exercice à réaliser :
	1) La fonction afficher_infos du TP précédent souffre de certaines lacunes. Elle lève notamment
	une exception de type AttributeError: 'Image' object has no attribute 'filename' si l'image
	passée en paramètre est une image créée par vos soins.
	Implémenter un mécanisme de gestion d'exceptions permettant de résoudre cette problématique.

	2) Ecrire une fonction afficher_histogramme(pimg) qui affiche l'histogramme des couleurs d'une
	image tel que représentées sur les figures 7 et 8 de l'énoncé du TP.
"""

# IMPORT =========================================================================================
from PIL import Image
from matplotlib import pyplot

# FONCTIONS =======================================================================================
def afficher_info(pimg):
	"""
	Description : 	affiche des informations sur l'image passée en paramètre
	Paramètres 	: 	type(pimg) => Image.PIL
	Retour 		: 	aucun
	"""
	try:
		_name = pimg.filename # on essaye de lire l'attribut filename de l'image (c'est le nom lors son ouverture avec open)
		_format = pimg.format # on essaye de lire l'attribut format de l'image (c'est son extension : JPEG, PNG, ...)
	except AttributeError: # si une des deux opérations échouent, c'est que l'image a été créée
		# on indique alors que c'est une image stockée en mémoire centrale et non lue à partir du disque
		_name = "<Image en mémoire>"
		_format = "<Image en mémoire>"
		
	_mode = pimg.mode
	_nbpixel = pimg.width * pimg.height # nombre de pixel de l'image
	if _mode == "1":
		_txtmode = "Noir et blanc"
		_poids = _nbpixel / 8 # pixel codé sur un bit (1/8ième d'octet) -> blanc ou noir
	elif _mode == "L":
		_txtmode = "Niveaux de gris"
		_poids = _nbpixel # pixel codé sur un octet (8 bits) -> 256 niveaux de gris
	elif _mode == "RGB":
		_txtmode = "Couleurs RGB"
		_poids = _nbpixel * 3 # pixel codé sur 3 octets (24 bits), un par couleur -> 16 millions de couleurs
	elif _mode == "RGBA":
		_txtmode = "Couleurs RGB + Alpha"
		_poids = _nbpixel * 3 # pixel codé sur 4 octets (32 bits), un par couleur + un canal de transparence
	else:
		_txtmode = _mode

	print("+ {:-^56} +".format(""))
	print("| {:<56} |".format(_name))
	print("+ {:-^56} +".format(""))
	print("| {:<30} : {:<23} |".format("FORMAT", _format))
	print("| {:<30} : {:<23} |".format("MODE", _txtmode))
	print("| {:<30} : {:<23} |".format("TAILLE", str(pimg.width) + " x " + str(pimg.height)))
	print("| {:<30} : {:<23} |".format("NB PIXELS", _nbpixel))
	print("| {:<30} : {:<23.2f} |".format("POIDS(non compressé) en Mo ", _poids / (1024 * 1024)))
	print("+ {:-^56} +".format(""))
	print("")

def afficher_histogramme(pimg):
	"""
	Description : 	affiche l'histogramme des couleurs sous forme de courbe dans le même repère
	Paramètres 	: 	type(pimg) => Image.PIL
	Retour 		: 	aucun
	"""
	# on crée trois listes indexées par le code RGB de chaque canal
	_red = [0] * 256
	_green = [0] * 256
	_blue = [0] * 256
	_width, _height = pimg.width, pimg.height  # on récupère la largeur et la hauteur de l'image dans des variables locales

	for y in range(_height): # parcours ligne par ligne
		for x in range(_width): # et colonne par colonne
			r, g, b = pimg.getpixel((x, y)) # on récupère les composantes RGB du pixel
			# on incrémente le nombre de pixels correspondant pour chaque canal
			_red[r] = _red[r] + 1
			_green[g] = _green[g] + 1
			_blue[b] = _blue[b] + 1

	# Tracé des courbes dans le même graphique
	pyplot.title("Histogramme des couleurs : " + pimg.filename)
	pyplot.plot(_red, color = "red")
	pyplot.plot(_green, color = "green")
	pyplot.plot(_blue, color = "blue")
	pyplot.xlabel("Intensités")
	pyplot.ylabel("Nombre de pixels")
	pyplot.show()

def afficher_histogramme_barres(pimg):
	"""
	Description : 	affiche les histogrammes de chaque canal dans trois repères différents et sous forme
					de diagramme en barres
	Paramètres 	: 	type(pimg) => Image.PIL
	Retour 		: 	aucun
	"""
	_red = [0] * 256
	_green = [0] * 256
	_blue = [0] * 256
	_width, _height = pimg.width, pimg.height

	for y in range(_height):
		for x in range(_width):
			r, g, b = pimg.getpixel((x, y))
			_red[r] = _red[r] + 1
			_green[g] = _green[g] + 1
			_blue[b] = _blue[b] + 1

	# Tracé des diagrammes en barres dans trois graphiques différents disposés selon une organisation 3 lignes/1 colonne
	pyplot.subplot(3, 1, 1) # subdivise la figure en 3 sous-figures sur 3lignes/1 colonne et sélectionne la première sous-figure
	pyplot.title("Histogramme des couleurs : " + pimg.filename)
	pyplot.bar(range(256), _red, color = "red") # range(256) renvoit la liste de valeurs à placer sur l'axe des abscisses

	pyplot.subplot(3, 1, 2) # subdivise la figure en 3 sous-figures sur 3lignes/1 colonne et sélectionne la deuxième
	pyplot.bar(range(256), _green, color = "green")

	pyplot.subplot(3, 1, 3) # subdivise la figure en 3 sous-figures sur 3lignes/1 colonne et sélectionne la troisième
	pyplot.bar(range(256), _blue, color = "blue")

	pyplot.xlabel("Intensités")
	pyplot.show()

# PROGRAMME PRINCIPAL =============================================================================
# Question 1
img_en_memoire = Image.new("RGB", (100, 100))
afficher_info(img_en_memoire)

# Question 2
img = Image.open("perroquet.png")
afficher_info(img)
print("Création du diagramme de distribution des couleurs en cours...")
afficher_histogramme_barres(img)
