#-*-coding:utf8-*-
###############################################################################
# Réalise l'insertion et l'extraction, par substitution, d'une image
# dans une autre, dans le domaine DWT. On précise l'ondelette, la matrice DWT.
###############################################################################

import Image as im
import ImageStat
from ImageChops import difference
from BitVector import BitVector
from numpy import *

from dwt_marquage import Marquage_DWT
from outilsBase import setBit, getBit, conversion
from suite import Doublement
from chiffrement_image import Chiffrement
from coefficients import Coefficients


class Marquage_DWT_Doublement_IC:

    _nb_bits_coef = 16

    def __init__(self, hote = None, marque = None,
                       matrice_dwt = None, famille = None,
                       position = None, authentification = None,
                       LSB = None):
        '''
        Constructeur.
        '''

        # L'hote
        self._hote = hote
        if not self._hote:
            self._hote = raw_input("Quel fichier hôte ? ")

        # La marque
        self._marque = marque
        if not self._marque:
            self._marque = raw_input("Quel marque ? ")

        # Chiffrement
        print "\n================== Chiffrement =================="
        unChiffrement = Chiffrement(fichier_image = self._marque)
        unChiffrement.chiffrement()
        self._strategie = unChiffrement.get_strategie()
        self._image = unChiffrement.get_image()


        # Récupération des bits de l'image chiffrée
        self._code = [k/255 for k in list(self._image.getdata())]

        # La famille d'ondelettes
        self._famille = famille
        if not self._famille:
            self._famille = raw_input("Quelle famille d'ondelettes ? ")

        # La matrice DWT à modifier
        self._matrice_dwt = matrice_dwt
        if not self._matrice_dwt:
            self._matrice_dwt = raw_input("Quelle matrice DWT affecter ? ")
        assert self._matrice_dwt in ['A1','A2','A3','H1','H2','H3',
                                     'D1','D2','D3','V1','V2','V3']

        # Position de l'insertion dans la matrice DWT
        self._position = position
        if not self._position:
            self._position =eval(raw_input("Début de l'insertion ? "))

        self._authentification = authentification
        if self._authentification == None:
            self._authentification=eval(raw_input("Authentification ? "))
        if self._authentification:
            self._MSB = eval(raw_input("Quels MSB ? "))

        # Force de l'insertion
        self._LSB = LSB
        if not self._LSB:
            self._LSB = eval(raw_input("Liste des LSB ? "))




    def get_strategie(self,N):
        '''
        Récupère la stratégie des itérations chaotiques.
        '''
        if self._authentification:
            msc = Coefficients().getAllCoefs(self._hote, self._MSB)
            bits = BitVector(bitstring = self._code) ^ msc

        else:
             bits = BitVector(bitstring = self._code)
        doublement = Doublement(1, N,
                                generateur = Coefficients()\
                                                 .bit2coef(bits, N))
        suite = doublement.iterateur()
        while True:
            yield suite.next()





    def marquage(self):
        self._unMarquage = Marquage_DWT(hote = self._hote,
                       famille = self._famille)
        matrice = self._unMarquage.get_matrice_DWT(self._matrice_dwt)

        self._x0, self._y0 = self._position
        self._x1, self._y1 = matrice.shape
        assert self._x0 < matrice.shape[0]
        assert self._y0 < matrice.shape[1]


        taille = self._nb_bits_coef
        image = []
        for k in range(matrice.shape[0]):
            for l in range(matrice.shape[1]):
                texte = conversion(int(matrice[k,l]),2).zfill(taille)
                image += [int(texte[taille-x]) for x in self._LSB]

        compteur = 0

        # L'insertion
        strat = self.get_strategie(len(image))

        for x in range(len(self._code)):
            suivant = strat.next()
            image[suivant] = int(not image[suivant])


        # Reconstruction de l'image
        compteur = 0
        for k in range(matrice.shape[0]):
            for l in range(matrice.shape[1]):
                x = [int(d) for d in conversion\
                                 (int(matrice[k,l]),2).zfill(taille)]
                for m in self._LSB:
                    x[taille-m] = image[compteur]
                    compteur += 1
                x = ''.join([str(t) for t in x])
                matrice[k,l] -= int(matrice[k,l])
                matrice[k,l] += int(x,2)

        self._unMarquage.set_matrice_DWT(self._matrice_dwt, matrice)
        self._unMarquage.get_hote_marque().save('lena_marque.png')





    def get_hote_marque(self):
        return self._unMarquage.get_hote_marque()





    def extraction(self, hote = 'lena_marque.png'):
        unTatouage = Marquage_DWT_Doublement_IC(hote = hote,
                                          marque = self._marque,
                                          famille = self._famille)
        unTatouage.marquage()
        unTatouage.get_hote_marque().save('lena_demarque.png')
        image1 = im.open("lena512.jpg")
        image2 = im.open("lena_demarque.png")

        compteur = 0
        diffs = difference(image1, image2)
        for k in range(image1.size[0]):
            for l in range(image1.size[0]):
                if diffs.getpixel((k,l)) >0 :
                    compteur += 1
        print "\nNombre de différences :",compteur, "sur",
        print str(image1.size[0]*image1.size[1])+'.\n'
        maximum = max(list(diffs.getdata()))
        diffs.point(lambda x : x*255/maximum).show()
        raw_input("Différences (facteur de "+str(maximum)+")")
        stats = ImageStat.Stat(diffs)
        print "Valeur moyenne des différences : ", stats.mean[0]
        print "Médiane des différences : ", stats.median[0]
        print "Valeurs extrémales : ", stats.extrema[0]
        print "Somme des différences : ", stats.sum[0]
        print "Valeur efficace : ", stats.rms[0]
        print "Ecart-type : ", stats.stddev[0]



if __name__ == '__main__':
    unTatouage = Marquage_DWT_Doublement_IC(hote = 'lena512.jpg',
                                          marque = 'filigrane32.png',
                                          famille = 'db1')
    unTatouage.marquage()

    unTatouage.get_hote_marque().save('lena512marque.jpg')
    unTatouage.get_hote_marque().show()
    raw_input("Affichage de l'hôte marqué")

    diffs = difference(im.open('lena512.jpg'),unTatouage.get_hote_marque())
    maximum = max(list(diffs.getdata()))
    diffs.point(lambda x : int(x*255/maximum)).show()
    raw_input("Différences (facteur de "+str(maximum)+")")
    stats = ImageStat.Stat(diffs)
    print "Valeur moyenne des différences : ", stats.mean[0]
    print "Médiane des différences : ", stats.median[0]
    print "Valeurs extrémales : ", stats.extrema[0]
    print "Somme des différences : ", stats.sum[0]
    print "Valeur efficace : ", stats.rms[0]
    print "Ecart-type : ", stats.stddev[0]

    unTatouage.extraction('lena512marque.jpg')
