automatos.c 4.68 KB
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdint.h>
#include "../inc/stegano.h"
#include "../inc/automatos.h"


/* Inverse le LSB d'un unsigne char *x passé en paramètre
   ex : 01001011 -> 01001010 */
void Change_LSB(unsigned char *x) {

	unsigned char mask = 0x01;		   //0b00000001
    unsigned char tmp;

    tmp = *x & mask;
    tmp = ~tmp & 0x01;
    *x = (*x & 0xFE) | tmp;
}


/* Copie le LSB de x pour le stocker à la ie position de a */
void GetOneChar(unsigned char x, unsigned char *a, int i) {

	unsigned char mask = 0x01;			//0b00000001
    *a += (x & mask) << (7-i);
}


/* Determine la parité du voisinage d'un pixel (de coordonnées int i, int j)
   La règle à utiliser est passée en paramètre via int algo_tab[] */
int Parity_check(Image **I, int algo_tab[], int i, int j) {

	/* Pixels à considérer pour la parité */
	int vois[9][2] = { { i   , j   } , { i   , j+1 } , { i+1 , j+1 },
					   { i+1 , j   } , { i+1 , j-1 } , { i   , j-1 },
					   { i-1 , j-1 } , { i-1 , j   } , { i-1 , j+1 } };
	int parity = 0;
	int h = (*I)->height;
	int w = (*I)->width;

	/* Evaluation et stockage de la parité de chaque pixel voisin */
	for (int k=0; k < 8; k++) {

		/* Considère ou non le voisin en fonction de l'algorithme de parité à appliquer */
		if (algo_tab[k] == 1) {
			/* Verifie les dépassements de tableau */
			if (vois[k+1][0] >= 0 && vois[k+1][0] < h && vois[k+1][1] >= 0 && vois[k+1][1] < w) {
				// Recupère le LSB du voisin (soit 1 si impair, soit 0 si pair)
				parity += ((*I)->Mat_data[vois[k+1][0]][vois[k+1][1]].blue) % 2; }
		}
	}
	// Ajoute la parité du pixel central lui même
	parity += (*I)->Mat_data[i][j].blue % 2;
	// Determine la parité globale du voisinage (0 si pair, 1 si impair)
	return (parity % 2);
}


/* Stocke les valeurs des 8 bits d'un octets 'byte' dans un int[8] passé en paramètre*/
void bit_in_tab(unsigned char *byte, int tab[]) {
	for(int k=7; k>=0; k--) {    
		tab[k] = *byte % 2;    
		*byte = *byte / 2;    
	}	  
}


/* Cache un message de N bit, bit à bit, dans N pixel, en modifiant ou non la parité du voisinage de chaque pixel
   Au terme de la fonction, le voisinage d'un pixel est impair lorsqu'un 1 est caché
						    le voisinage d'un pixel est pair lorsqu'un 0 est caché   */
void Parity_encode(Image **I, unsigned char *msg) {

	/* Determination de l'algorithme de parité */
	int algo_tab[8];
	unsigned char algo_byte = (*I)->Mat_data[4][4].red;
	bit_in_tab(&algo_byte, algo_tab);

	/* variables concernant le message à cacher */
	uint8_t current_byte = 0;
	int hide_byte[8];
	int bit = 0;
	bit_in_tab(&msg[current_byte], hide_byte);

	/* Parcours de la matrice */
	int h = (*I)->height;
	int w = (*I)->width;
	int parity = 0;
	int breaking = 0;

	for (int i = 0; i < h; i+=2) {
		for (int j = 0; j < w; j+=2) {

			/* Calcul de la parité des voisins*/
			parity = Parity_check(I, algo_tab, i, j);

			/* Dissimulation du message en fonction de la parité */
			if ((parity == 1) && (hide_byte[bit] == 0)) {
				Change_LSB(&((*I)->Mat_data[i][j].blue));
			}
			else if ((parity == 0) && (hide_byte[bit] == 1)) {
				Change_LSB(&((*I)->Mat_data[i][j].blue));
			}
			bit += 1;

			// Fin de message
			if (bit == 8 && breaking == 1) return;

			// Fin de caractère
			if (bit == 8) {
				current_byte ++;
				if (msg[current_byte] == '\0') breaking = 1; //Dernier caractère
				bit_in_tab(&msg[current_byte], hide_byte);   //Chargement des 8 bits d'un caractère (msg[current_byte]) au sein d'un int[8] (hide_byte)
				bit = 0;
			}
		}
	}
	return;
}


/*
Table de verité pour l'encodage :
H = bit à cacher
R = bit de poids faible du pixel central
Paire et impaire = parités des voisins du pixel central(dépend de l'algo)

|        |   H =  0   |   H = 1    |
|----------------------------------|
| Impaire|  change R  |  Nochange R|
|----------------------------------|
| Paire  | Nochange R |  change R  |

*/


/* Extrait un potentiel message caché au sein d'une image ppm (stockée préalablement dans une matrice 2D) */
void Parity_decode(Image **I, unsigned char *msg) {

	/* Determination de l'algorithme de parité */
	int algo_tab[8];
	unsigned char algo_byte = (*I)->Mat_data[4][4].red;
	bit_in_tab(&algo_byte, algo_tab);

	uint8_t l = 0;
	int bit = 0;

	/* Parcours de la matrice */
	int h = (*I)->height;
	int w = (*I)->width;
	int parity = 0;
	for (int i = 0; i < h; i+=2) {
		for (int j = 0; j < w; j+=2) {

			// parity == 0 (pair) -> le caractère caché est un 0
			// parity == 1 (impair) -> le caractère caché est un 1
			parity = Parity_check(I, algo_tab, i, j);
			GetOneChar(parity, &msg[l], bit);
			bit ++;

			//fin de caractère ou de message
			if (bit == 8) { 
				if (msg[l] == '\0') return;
				l ++;
				bit = 0;
			}
		}
	}
}