The program i am creating a steganography program that hides a secret message inside a .ppm image by changing random red pixel values to ascii characters. The program is based on code that is on stackoverflow for reading and writing ppm images (read PPM file and store it in an array; coded with C), all other code is my own work. I have completed all the necessary functions to do this such as writing,reading,encoding and decoding the files but i am struggling to grasp the fwrite function.
Currently when the program encodes an image it takes in the .ppm converts it to its rgb values in a struct. Then it hides the secret message by editing the red values to ascii characters. The issue arises when it comes to "printing" the image to a file. When the program has completed the image produced is around 90% of what it should be printing. Example show below: Example of the unfinished image
I have checked it is storing all the values are being stored correctly by printing all the rgb values and it is. (used the showPPM method). Is there not enough memory to write the image? is the image to large for the write function? these are my guesses.
Any information on how i should go about changing the writePPM function so that i correctly print 100% of the image to the file would be great.
Here is the code below:
#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");
}
}