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


/* Génère une matrice 2D dynamique */
void NouvelleImage(int width, int height, Image** I)
{
	*I = malloc(sizeof(Image));
	(*I)->width = width;
	(*I)->height = height;

	/* Tableau de pointeur de tableau */
	(*I)->Mat_data = (Pix_rgb **)malloc(height * sizeof(Pix_rgb *));
	/* Allocation de mémoire pour chaque tableau */
	for (int i = 0; i < height; ++i) {
      (*I)->Mat_data[i] = (Pix_rgb *)malloc(width * sizeof(Pix_rgb));
	}

	return;
}


/* Libere l'espace mémoire alloué à la structure Image */
void free_image(Image** I) {

	for (int i = 0; i < (*I)->height; ++i)
	    free((*I)->Mat_data[i]);

    free((*I)->Mat_data);
    free(*I);
}


/* Lit l'entete d'un fichier ppm pour extraire la taille */
void read_header(FILE * im_file, int *width, int *height) {

	char * buff = malloc(10*sizeof(char));
	char * line = NULL;
    size_t len = 0;
    int nb_line = 0;

    /* Ignore les commentaire jusqu'à la ligne contenant la taille */
    while (nb_line != 2) {
		getline(&line, &len, im_file);
        if (strncmp(line, "#", 1) != 0) {
 			nb_line ++;
 		}
 	}

 	/* Recupere la taille */
 	strcpy(buff, strtok(line, " "));
	*width = atoi(buff);
	strcpy(buff, strtok(NULL, " "));
	*height = atoi(buff);

    getline(&line, &len, im_file);
    free(buff);
}


/* Charge l'image au sein d'une matrice */ 
int chargement_ppm(char *image_name, Image** I) {

	/* Ouverture du fichier image .ppm */
	FILE* im_file = NULL;
	if((im_file = fopen(image_name,"r")) == NULL) return -1;

	int width, height;

	read_header(im_file, &width, &height);
	printf("SIZE : %d %d\n", width, height);

	/* RECUPERATION ET STOCKAGE DES PIXELS */
	NouvelleImage(width,height, I);
	for (int i=0; i < (*I)->height; i++) {
		for (int j=0; j < (*I)->width ; j++) {

			fscanf(im_file, "%c", &((*I)->Mat_data[i][j].red));
			fscanf(im_file, "%c", &((*I)->Mat_data[i][j].green));
			fscanf(im_file, "%c", &((*I)->Mat_data[i][j].blue));
		}
	}
	fclose(im_file);
	return 0;
}


/* Crée une nouvelle image .ppm à partir d'une structure Image */
int sauvegarde_ppm(char* image_name, Image** I) {

  FILE* out = fopen(image_name, "w");
  if(!out) return -1;

  fprintf(out, "P6\n%d %d\n255\n", (*I)->width, (*I)->height);

	for (int i=0; i < (*I)->height; i++) {
		for (int j=0; j < (*I)->width ; j++) {

			fprintf(out, "%c", (*I)->Mat_data[i][j].red);
			fprintf(out, "%c", (*I)->Mat_data[i][j].green);
			fprintf(out, "%c", (*I)->Mat_data[i][j].blue);
		}
	}
	fclose(out);
	printf("saveOK\n");
	return 0;
}


/* Copie les 2 bits de poids faible de x pour les stocker dans le 1eme quart de a */
void GetPartChar(unsigned char x, unsigned char *a, int i) {

	unsigned char mask = 0x03;			//0b00000011
    *a += (x & mask) << (i-1)*2;
}


/* Copie le ieme quart de a pour les stocker dans les 2 bits de poids faible de x */
void SetPartChar(unsigned char *x, unsigned char a, int i) {
    
    unsigned char mask = 0x03;			//0b00000011
    unsigned char tmp;

    tmp = a & (mask << (i-1)*2);		//Decale mask pour obtenir un masque sur le ieme quart 
    *x = (*x & 0xFC) | (tmp >> (i-1)*2);//Place les 2 bits au niveau du poids faible de x
}


/* Determine dans quel pixels l'information est/sera dissimulée
   L'utilisation d'un chiffrement vigenere (int vigenere == 1) et donc d'une clé (unsigned char *cle)
   influe sur la détermination des pixels */
void Next_pixel(Image **I, int *current_pos, int *i, int *j, int vigenere, unsigned char *cle) {

	int h = (*I)->height;
	int w = (*I)->width;
	int im_size = h * w;

	*current_pos += ((*I)->Mat_data[(*i)][(*j)].red & (*I)->Mat_data[(*i)][(*j)].green) / 5;
	*current_pos += 1;

	if (vigenere) {
		int icle = *current_pos % strlen((const char *)cle);
		*current_pos += (*current_pos & cle[icle]) / 5;
	}
	int tmp_pos = *current_pos;

	if (tmp_pos % 2 == 0) tmp_pos = im_size - tmp_pos;
	//tmp_pos = tmp_pos % (w*h);
	//printf("pos %d\n", tmp_pos);
	*i = tmp_pos / w;
	*j = tmp_pos % w;
}


/* Cache ou extrait un unsigned char *msg au sein de la matrice Image **I 
   int encode = 1 -> cache le message
   			  = 0 -> extrait le message
   int vigenere   -> permet de savoir si un chiffrement vigenere a été ou doit être effectué (utile pour Next_pixel)
   unsigned char *clef -> utilisé en cas de chiffrement avec vigenere */
void LSB_hide(Image **I, unsigned char *msg, int encode, int vigenere, unsigned char *cle) {

	uint8_t k = 0;
	int quart = 1;

	int h = (*I)->height;
	int w = (*I)->width;
	int i = 0;
	int j = 0;
	int current_pos = i*h + j;
	
	/* dissimulation ou extraction message */
	while(1) {
		Next_pixel(I, &current_pos, &i, &j, vigenere, cle);
		if (encode == 1) SetPartChar(&((*I)->Mat_data[i][j].blue), msg[k], quart);
		else GetPartChar((*I)->Mat_data[i][j].blue, &msg[k], quart);
		quart += 1;
		if (quart == 5) {
			quart = 1;
			if ( msg[k] == '\0') return;
			k ++;
		}
		if (current_pos >= h*w) return;
	}
}



/* TODO 
1- vidage du buffer
*/