2017-02-08 5 views
3

Le programme crée un programme de stéganographie qui cache un message secret dans une image .ppm en changeant les valeurs de pixels rouges aléatoires en caractères ascii. Le programme est basé sur le code qui est sur stackoverflow pour lire et écrire des images en ppm (read PPM file and store it in an array; coded with C), tout autre code est mon propre travail. J'ai accompli toutes les fonctions nécessaires pour écrire, lire, encoder et décoder les fichiers, mais j'ai du mal à saisir la fonction fwrite.C: Écrire des structures de valeurs RVB dans un fichier pour créer une image ppm - fin prématurée du fichier

Actuellement, lorsque le programme code une image qu'il prend en .ppm le convertit en valeurs rgb dans une structure. Puis il cache le message secret en éditant les valeurs rouges en caractères ASCII. Le problème se pose lorsqu'il s'agit «d'imprimer» l'image dans un fichier. Lorsque le programme a terminé l'image produite est d'environ 90% de ce qu'il devrait être imprimé. Exemple d'affichage ci-dessous: Example of the unfinished image

J'ai vérifié qu'il stocke toutes les valeurs sont stockées correctement en imprimant toutes les valeurs RGB et il est. (utilisé la méthode showPPM). N'y a-t-il pas assez de mémoire pour écrire l'image? l'image est-elle trop grande pour la fonction d'écriture? Ce sont mes suppositions.

Toute information sur la façon dont je devrais changer la fonction writePPM afin que j'imprime correctement 100% de l'image dans le fichier serait géniale.

Voici le code ci-dessous:

#include<stdio.h> 
#include<stdlib.h> 
#include<math.h> 
#include<string.h> 
#include<time.h> 

typedef struct { 
    unsigned char red,green,blue; 
} PPMPixel; 

typedef struct { 
int x, y; 
PPMPixel *data; 
} PPMImage; 

void writePPM(PPMImage *img); 

static PPMImage *getPPM(const char *filename) 
{ 

    char buff[16]; 
    PPMImage *img; 
    FILE *fp; 
    int c, rgb_comp_color; 
    //open PPM file for reading 
    fp = fopen(filename, "rb"); 
    if (!fp) { 
      fprintf(stderr, "Unable to open file '%s'\n", filename); 
      exit(1); 
    } 

    //read image format 
    if (!fgets(buff, sizeof(buff), fp)) { 
      perror(filename); 
      exit(1); 
    } 

//check the image format 
if (buff[0] != 'P' || buff[1] != '3') { 
    fprintf(stderr, "Invalid image format (must be 'P3')\n"); 
    exit(1); 
}else{ 
    printf("P3\n"); 
} 

//alloc memory form image 
img = (PPMImage *)malloc(sizeof(PPMImage)); 
if (!img) { 
    fprintf(stderr, "Unable to allocate memory\n"); 
    exit(1); 
} 


    c = getc(fp); 
    while (c == '#') { 
    while (getc(fp) != '\n') ; 
    c = getc(fp); 

} 
ungetc(c, fp); 
//read image size information 
if (fscanf(fp, "%d %d", &img->x, &img->y) != 2) { 
    fprintf(stderr, "Invalid image size (error loading '%s')\n", filename); 
    exit(1); 
}else{ 
    printf("Height: %d\n",img->x); 
    printf("Width: %d\n",img->y); 

} 

//read rgb component 
if (fscanf(fp, "%d", &rgb_comp_color) != 1) { 
    fprintf(stderr, "Invalid rgb component (error loading '%s')\n", filename); 
    exit(1); 
}else{ 
    printf("%d\n",rgb_comp_color); 
} 

//check rgb component depth 
if (rgb_comp_color!= 255) { 
    fprintf(stderr, "'%s' does not have 8-bits components\n", filename); 
    exit(1); 
} 

while (fgetc(fp) != '\n') ; 
//memory allocation for pixel data 
img->data = (PPMPixel*)malloc(24*img->x * img->y * sizeof(PPMPixel)); 

if (!img) { 
    fprintf(stderr, "Unable to allocate memory\n"); 
    exit(1); 
} 

//read pixel data from file 
if (fread(img->data, 10*img->x, img->y, fp) != img->y) { 
    fprintf(stderr, "Error loading image '%s'\n", filename); 
    exit(1); 
} 

fclose(fp); 
return img; 
} 



struct PPMImage * encode(char * text, PPMImage * img) 
{ 
    //convert secret message to ascii code 

    int i,ascii,height,width; 
    int total = 0; 
    int rolling = 0; 
    int original = 0; 
    time_t t; 
    srand((unsigned) time(&t)); 
    height=img->y; 
    width=img->x; 

    for(i = 0; text[i]; i++){ 

     ascii = text[i]; 

     //create random number between 0 and max the width 
     total = total + rand() % width; 
     original = total; 
     //printf("Random Number: %d\n",total); 

     if(total >= width){ 
      rolling = rolling + 1; 
      total = total - width; 
     } 

     //printf("Before R: %d \n",img->data[0].red); 
     img->x=rolling; 
     img->y=total; 

     printf("X: %d ",rolling); 
     printf("Y: %d ",total); 

     //set img position 
     //at position random we set the red bit equal to ascii number 
     printf("Old R: %d ",img->data[i].red);      
     img->data[i].red=ascii; 
     printf("New R: %d\n ",img->data[i].red); 
    } 

    //take img then print it out 
    //setting the img values again for printing 
    img->x=width; 
    img->y=height; 
    writePPM(img); 

} 

void writePPM(PPMImage *img) 
{ 
FILE *fp; 
//open file to be written 
fp = fopen("encoded.ppm", "wb"); 
if (!fp) { 
    fprintf(stderr, "Unable to open file \n"); 
    exit(1); 
} 

//image format 
fprintf(fp, "P3\n"); 

//comments 
//need to store comments to be outputted 
fprintf(fp, "# Created by Sean \n"); 

//image size 
fprintf(fp,"%d %d\n",img->x,img->y); 

// rgb component depth 
fprintf(fp, "%d\n",255); 

//write pixels currently not fully working 
fwrite(img->data, sizeof(img->data), 3*img->y*img->x, fp); 

//close file stream 
fclose(fp); 
} 

void showPPM(PPMImage *img) 
{ 
    int i; 
    if(img){ 

    for(i=-1;i<img->x*img->y;i++){ 
     printf("Number: %d\n",i); 
     printf("R: %d ",img->data[i].red); 
     printf("G: %d ",img->data[i].green); 
     printf("B: %d\n ",img->data[i].blue); 

    } 
} 
} 


char * decode(PPMImage * i1,PPMImage * i2){ 

//compare difference in number of bits in red pixels 
//if there is a different then take the red pixel value from the encrypted image 
//then translate it from ascii to chars then print. 
printf("Decoding......\n"); 

int i; 
    for(i=-1;i<i1->x*i1->y;i++){ 
      if(i1->data[i].red != i2->data[i].red){ 
       printf("%c",i1->data[i].red); 
      } 
    } 

//to be able to test and finish this need to write code for encoding 

} 

int main(int argc, char *argv[]){ 

//input statements 
if(argc == 3){ 
    PPMImage *image; 
    image = getPPM(argv[2]); 
    //uncomment the showPPM to display all rgb values in the encoded files 
    //showPPM(image); 
    if(argv[1] = "e"){ 
    printf("Please enter your secret message to be encoded estimated max characters: %d\n",image->y); 

     //need to add user input 
    encode("test output!",image); 
    } 
}else if(argc == 4){ 
    PPMImage *i1; 
    PPMImage *i2; 
    i1 = getPPM(argv[2]); 
    i2 = getPPM(argv[3]); 

    if(argv[1] = "d"){ 
     decode(i1,i2); 
    } 
}else{ 
    printf("Wrong arguments"); 
} 
} 
+1

'sizeof (img-> données)' est pas ce que vous voulez. Cela vous donne la taille du * pointeur * et non la taille de la mémoire allouée. Vous avez des nombres magiques dans votre code tels que '24' et' 3' qui rendent non évident ce que les différentes tailles représentent. Donc je ne sais pas exactement de quelle taille vous avez besoin dans 'fwrite'. Mais ce n'est définitivement pas 'sizeof (img-> data)'. – kaylum

+0

Vous devriez éditer ceci pour enlever la conversation de marin d'anti-calum, nous essayons d'exécuter un joint respectable ici. – samgak

+0

Merci pour le conseil oublié que c'était là :) –

Répondre

0

Le problème est en fait dans le code de lecture dans le PPM, que vous avez modifié d'une manière qui semble fonctionner, mais ne fait pas parce que le fichier le format est différent de ce que vous pensez qu'il est.

Le code auquel vous vous êtes connecté permet de lire les fichiers PPM au format "brut". Ces fichiers commencent par le code "P6". Dans ces fichiers, chaque valeur RVB est stockée en tant que 1 ou 2 octets (selon que la profondeur du composant RVB est inférieure à 256). Donc, si la valeur maximale est 255, c'est 1 octet par valeur, donc la taille du fichier est width * height * 3.

Cependant, vous avez modifié le code pour lire les fichiers PPM "simples", qui commencent par le " P3 ", en vérifiant P3 et en lisant plus de données. Ces fichiers ne stockent pas les valeurs RVB en tant que données binaires brutes, mais en tant que texte ASCII spécifiant la valeur au format décimal, séparés par des espaces. Ainsi, par exemple, si vous avez la valeur 93 au format brut, ce sera simplement 1 octet avec une valeur de 93, mais dans le format "plain", 3 octets (ou plus): un ou plusieurs octets avec la valeur ASCII pour un espace (ou une tabulation), alors la valeur ASCII pour "9" (qui est 57) puis la valeur ASCII pour "3" (qui est 51). Il est impossible de calculer la taille du fichier en fonction de la largeur et de la hauteur car les espaces peuvent être variables et chaque valeur peut être représentée entre 1 et 3 chiffres.

Malgré le fait que vous n'êtes pas l'analyse des données sous forme de texte codé en ASCII, votre code PPM lecture semble travailler parce que vous lisez juste un morceau de données, (le cas échéant) modifier quelques octets aléatoires et puis l'écrire à nouveau totalement ou presque inchangé.

Ainsi, vos solutions possibles sont:

  • Modifiez le code getPPM à ce qu'elle était et utiliser un fichier P6 réel.
  • Ecrivez un lecteur PPM qui analyse correctement les données en tant que texte ASCII contenant des nombres décimaux séparés par des espaces (vous pouvez écrire en tant que P3 ou P6).

Plus d'infos: PPM Format Specification

+0

Merci pour l'aide, je voudrais changer le programme pour lire/écrire des images P3 de sorte que cela nécessiterait de changer le lecteur, comment pourrais-je passer à la bonne condition. Ajouter des espaces pour chaque valeur rgb? –

+0

Lorsque vous le lisez, appelez 'fscanf (fp,"% d% d% d ", & rouge, & vert, &blue);' dans une boucle, jusqu'à ce que vous ayez lu les valeurs width * height ou atteint la fin du fichier (test en utilisant feof (fp) '). Lire dans ints et ensuite définir les valeurs de 8 bits dans vos structures.Pour l'écrire, vous pouvez simplement utiliser fprintf.Notez que vous ne pouvez avoir que 70 valeurs sur chaque ligne.Lisez soigneusement les spécifications de format – samgak

+1

Ce code gère la lecture des fichiers ppm mais peut être un peu trop compliqué: https://sourceforge.net/p/netpbm/code/HEAD/tree/stable/lib/libppm1.c – samgak