read PPM file and store it in an array; coded with C
Asked Answered
C

2

11

I need to read a PPM file and store it in an array written in C. Can anybody help me out doing this?

Thanks a lot.

Cressida answered 22/4, 2010 at 19:1 Comment(3)
What part are you having trouble with? If you post your attempt at it that's not working right, it'll be easy enough to find the bug(s).Churchless
This post seems to have the answer you are looking for. #8127315Cancellate
@Cancellate that question if for PGMs not PPMs. PPMs have binary pixel data.Loritalorn
H
28

The following code shows how to read, change the pixel colour and write an image in PPM format. I hope it helps.

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

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

typedef struct {
     int x, y;
     PPMPixel *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 = (PPMPixel*)malloc(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, 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(){
    PPMImage *image;
    image = readPPM("can_bottom.ppm");
    changeColorPPM(image);
    writePPM("can_bottom2.ppm",image);
    printf("Press any key...");
    getchar();
}
Harrington answered 23/4, 2010 at 15:40 Comment(2)
This code will fail on many PNM files because PNM uses whitespace between header entries and is not fixed to using only LF. A comment line can also be located almost anywhere in the header and is technically the only line that has to be terminated with a CR or LF. The PNM binary file format design is a broken mess. The sourceforge netpbm even states that the inclusion of a comment, even though it is a valid header object, essentially breaks the file format.Foraminifer
you have mallocs, why there are no frees?Cascio
O
3

Here is the PPM specification.

The PPM file is built in 9 sections separated by white-spaces.

  • Open the file
  • read until the first white space and check you got P6. Then skip other white-spaces.
  • read until the next white space, convert your buffer to an integer width. Then skip other white-spaces
  • read until the next white space, convert your buffer to an integer height. Then skip other white-spaces
  • Allocate a 2D array of integers in the size of height*width
  • read the max-val
  • read line by line and fill the array
Oxime answered 22/4, 2010 at 19:22 Comment(2)
I think you need to clarify what is going on in this answer, it's not very clear.Double
This will fail on many PNM files since it does not account for comment lines.Foraminifer

© 2022 - 2024 — McMap. All rights reserved.