Question

This code (which I edited from code I found on a previous Stack Overflow question) is able to take the input of a ppm image and output the same image, but with all of the colors complementary. In my assignment, I am asked to do this, but then to swap the red and green components (basically make img->data[i].red into img->data[i].green and vice versa). However, I am unsure of how to go about doing this. I can't just make two equal statements, as the first would essentially nullify the second. The only thing that I can think of is to create a temporary array of the PPMImage type (a struct created earlier). However, I am a bit unsure of how the code and logic for this would work.

Here is the code. The 'for' loop in the changecolorPPM function is where the colors are complemented, and where I am pretty sure the swapping needs to occur.

#include<stdio.h>
#include<stdlib.h>

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

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

#define CREATOR "RPFELGUEIRAS"
#define RGB_COMPONENT_COLOR 255

static PPMImage *readPPM(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] != '6') {
     fprintf(stderr, "Invalid image format (must be 'P6')\n");
     exit(1);
}

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

//check for comments
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);
}

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

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

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

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

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

fclose(fp);
return img;
}
 void writePPM(const char *filename, PPMImage *img)
{
FILE *fp;
//open file for output
fp = fopen(filename, "wb");
if (!fp) {
     fprintf(stderr, "Unable to open file '%s'\n", filename);
     exit(1);
}

//write the header file
//image format
fprintf(fp, "P6\n");

//comments
fprintf(fp, "# Created by %s\n",CREATOR);

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

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

// pixel data
fwrite(img->data, 3 * img->x, img->y, fp);
fclose(fp);
}

void changeColorPPM(PPMImage *img)
{
int i;

if(img){

     for(i=0;i<img->x*img->y;i++){
          img->data[i].red=RGB_COMPONENT_COLOR-img->data[i].red;
          img->data[i].green=RGB_COMPONENT_COLOR-img->data[i].green;
          img->data[i].blue=RGB_COMPONENT_COLOR-img->data[i].blue;
     }
}
}

int main(int argc, char* argv[]){
PPMImage *image;
char* filename = argv[1];
image = readPPM(filename);
changeColorPPM(image);
writePPM("OutputFile.ppm",image);
printf("Press Enter");
getchar();
}
Was it helpful?

Solution

From your question, I believe you are looking for a swap function which could easily be implemented as

img->data[i].red = img->data[i].red + img->data[i].green;
img->data[i].green = img->data[i].red - img->data[i].green;
img->data[i].red = img->data[i].red - img->data[i].green;

Update:

This section is fine if there is no overflow from the addition operation. However, if the precision of the destination is not sufficient enough to hold the bits, then there could be potential loss of data. Hence, in these cases, as Mats and other experts suggested, the traditional temporary variable method would be the best way forward

temp = img->data[i].red;
img->data[i].red = img->data[i].green;
img->data[i].green = temp;

Note:

If you are into image processing, then this swap may not be pleasing from a visual perspective. Usually, Green contains the maximum intensity i.e. amount of brightness information as compared to Red and Blue and human eye can catch the variations in intensity very easily. It will interesting to check, how the final picture looks like after the swap.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top