Answered step by step
Verified Expert Solution
Link Copied!

Question

1 Approved Answer

implement one of the following two features: Make getPPM and showPPMread and write comments, by storing the comments as a linked list of strings in

implement one of the following two features:

Make getPPM and showPPMread and write comments, by storing the comments as a linked list of strings in struct PPM. You can assume that any comment lines will always be immediately before width (although the PPM specification says they're allowed to occur anywhere in the file). You will need to rework how you read width if the first character you read is a #, then you have a comment, else it must be a digit and should be counted as part of width .

Make getPPM handle normal PPM files as well as Plain PPM. Normal PPM files start with P6 instead of P3, and have the image data stored directly as bytes (one or two bytes per colour, depending on max) rather than as decimal numbers see the PPM specification for more details. You can read data like this using the fread function.

================SOURCE COED BELOW================

#include

#include

#include

#include

/* The RGB values of a pixel. */

struct Pixel {

int red;

int green;

int blue;

};

/* An image loaded from a PPM file. */

struct PPM {

int width;

int height;

int max;

struct Pixel *pixels;

};

/* Reads an image from an open PPM file.

* Returns a new struct PPM, or NULL if the image cannot be read. */

struct PPM *getPPM(FILE * f)

{

int width, height, max;

if (fscanf(f, "P3 %d %d %d ", &width, &height, &max) != 3) {

fprintf(stderr, "Error reading PPM header ");

return NULL;

}

}

/* Write img to stdout in PPM format. */

void showPPM(const struct PPM *img)

{

printf("P3 %d %d %d ", img->width, img->height, img->max);

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

printf("%d %d %d ", img->pixels[i].red, img->pixels[i].green, img->pixels[i].blue);

}

}

/* Opens and reads a PPM file, returning a pointer to a new struct PPM.

* On error, prints an error message and returns NULL. */

struct PPM *readPPM(const char *filename)

{

/* Open the file for reading */

FILE *f = fopen(filename, "r");

if (f == NULL) {

fprintf(stderr, "File %s could not be opened. ", filename);

return NULL;

}

/* Load the image using getPPM */

struct PPM *img = getPPM(f);

/* Close the file */

fclose(f);

if (img == NULL) {

fprintf(stderr, "File %s could not be read. ", filename);

return NULL;

}

return img;

}

/* Encode the string text into the red channel of image img.

* Returns a new struct PPM, or NULL on error. */

struct PPM *encode(const char *text, const struct PPM *img)

{

int text_len = strlen(text);

int pixels_per_char = (img->width * img->height) / (text_len + 1);

if (pixels_per_char < 3) { // at least 3 pixels per character to encode

fprintf(stderr, "Image too small to encode message ");

return NULL;

}

if (pixels_per_char * (text_len + 1) > img->width * img->height) { // message too long to encode

fprintf(stderr, "Message too long to encode in image ");

return NULL;

}

struct PPM *newimg = malloc(sizeof(struct PPM));

newimg->width = img->width;

newimg->height = img->height;

newimg->max = img->max;

newimg->pixels = malloc(newimg->width * newimg->height * sizeof(struct Pixel));

memcpy(newimg->pixels, img->pixels, newimg->width * newimg->height * sizeof(struct Pixel));

srand(time(NULL));

for (int i = 0; i < text_len; i++) {

int j = i * pixels_per_char + rand() % pixels_per_char;

newimg->pixels[j].red = (unsigned char)

text[i];

}

return newimg;

}

/* Extract the string encoded in the red channel of newimg, by comparing it

* with oldimg. The two images must have the same size.

* Returns a new C string, or NULL on error. */

char *decode(const struct PPM *oldimg, const struct PPM *newimg)

{

int pixels_per_char = (oldimg->width * oldimg->height) / (strlen(MESSAGE) + 1);

int max_msg_len = pixels_per_char - 1; // maximum length of message that can be encoded in one group of pixels

char *msg = malloc(max_msg_len * (strlen(MESSAGE) + 1) + 1); // allocate space for the decoded message

int msg_idx = 0;

for (int i = 0; i < strlen(MESSAGE); i++) {

int j = i * pixels_per_char + rand() % pixels_per_char;

char c = newimg->pixels[j].red ^ oldimg->pixels[j].red; // decode the character by XORing the red values

if (c == '\0') { // end of message reached

break;

}

if (msg_idx >= max_msg_len * (strlen(MESSAGE) + 1)) { // message too long to decode

fprintf(stderr, "Message too long to decode ");

free(msg);

return NULL;

}

msg[msg_idx++] = c;

}

msg[msg_idx] = '\0'; // null-terminate the message

return msg;

}

/* TODO: Question 3 */

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

{

/* Initialise the random number generator, using the time as the seed */

srand(time(NULL));

/* Parse command-line arguments */

if (argc == 3 && strcmp(argv[1], "t") == 0) {

/* Mode "t" - test PPM reading and writing */

struct PPM *img = readPPM(argv[2]);

showPPM(img);

} else if (argc == 3 && strcmp(argv[1], "e") == 0) {

/* Mode "e" - encode PPM */

struct PPM *oldimg = readPPM(argv[2]);

/* TODO: prompt for a message from the user, and read it into a string */

char message[256];

printf("Enter a message to encode: ");

scanf("%255[^ ]", message); // read up to 255 characters until a newline is encountered

/* Check that the message length is not too long */

int pixels_per_char = (oldimg->width * oldimg->height) / (strlen(message) + 1);

if (pixels_per_char < 3) {

fprintf(stderr, "Image too small to encode message ");

return 1;

}

if (pixels_per_char * (strlen(message) + 1) > oldimg->width * oldimg->height) {

fprintf(stderr, "Message too long to encode in image ");

return 1;

}

struct PPM *newimg = encode(message, oldimg);

if (newimg == NULL) {

fprintf(stderr, "Encoding failed ");

return 1;

}

/* TODO: write the encoded image to a new file */

free(newimg->pixels);

free(newimg);

free(oldimg->pixels);

free(oldimg);

} else if (argc == 4 && strcmp(argv[1], "d") == 0) {

/* Mode "d" - decode PPM */

struct PPM *oldimg = readPPM(argv[2]);

struct PPM *newimg = readPPM(argv[3]);

char *message = decode(oldimg, newimg);

if (message == NULL) {

fprintf(stderr, "Decoding failed ");

return 1;

}

printf("Decoded message: %s ", message);

free(message);

free(newimg->pixels);

free(newimg);

free(oldimg->pixels);

free(oldimg);

} else {

fprintf(stderr, "Usage: %s t|e|d [filename2] ", argv[0]);

return 1;

}

return 0;

}

Step by Step Solution

There are 3 Steps involved in it

Step: 1

blur-text-image

Get Instant Access to Expert-Tailored Solutions

See step-by-step solutions with expert insights and AI powered tools for academic success

Step: 2

blur-text-image

Step: 3

blur-text-image

Ace Your Homework with AI

Get the answers you need in no time with our AI-driven, step-by-step assistance

Get Started

Recommended Textbook for

DB2 11 The Database For Big Data And Analytics

Authors: Cristian Molaro, Surekha Parekh, Terry Purcell, Julian Stuhler

1st Edition

1583473858, 978-1583473856

More Books

Students also viewed these Databases questions