Thread: Help With Reading The Image Size Of A PPM File?

  1. #1
    Registered User
    Join Date
    Dec 2021
    Posts
    34

    Help With Reading The Image Size Of A PPM File?

    I've used this code before to test it and it did work. Unfortunately it now reads two random numbers for a pgm file and the code ends before it even gets to read the image dimensions when I try to read a ppm file in. I know I'm missing something but I'm not quite sure where yet. Any help is much appreciated. Thanks. (the code is also unfinished)
    Code:
    #include<stdio.h>
    #include <stdlib.h>
    #include <string.h>
    
    #define RGB_COMPONENT_COLOUR 255
    #define height 1080
    #define width 1920
    
    typedef struct
    {
        unsigned char red, green, blue;
    } PPMPixel;
    
    typedef struct
    {
        int x, y;
        PPMPixel *data;
    } PPMImage;
    
    void clear_to_end(FILE *fp)
    {
        int c;
        while ((c = fgetc(fp)) != -1 && c != '\n');
    }
    
    PPMImage* load_file()
    {
        FILE *fp;
        PPMImage *img;
        int d;
        char buff[16];
        char fname[100];
        printf("Enter file name: ");
        scanf("%s", fname);
        fseek(stdin,0,SEEK_END);
        fp = fopen(fname, "rb");
        if (fp == NULL || !fp || ferror(fp))
        {   
            printf("\tError while opening the file\n");
        }                        
        else    
        {
            printf("\tReading in %s\n", fname);
        }
    
        //Checking for comments
        //Skip whitespace and comments
        d = getc(fp);
        while (d=='#')
        {
            while(getc(fp)!='\n')
            d=getc(fp);
        }
        ungetc(d,fp);
    
        //Checking header
        if (!fgets(buff,sizeof(buff),fp))
        {
            perror(fname);
            exit(1);
        }
    
        if (buff[0] =='P' || buff[1] == 2 || buff[1] == 3)
        {
            printf("\tReading PGM/PPM image in...\n");
        }
        else
        {
            printf("\tIncorrect image format\n");
        }
    
        //Read image size information
        if (fscanf(fp, "%u%u", &img->y, &img->x))
        {
            printf("\tInvalid image size\n");
            printf("\tImage size is: %u x %u\n", img->y, img->x);
        }
        else
        {
            printf("\tImage size is valid\n");
            printf("\tImage size is: %u x %u\n", img->y, img->x);
        }
    
    
    }
    void save_file(PPMImage *img)
    {
        
        
    }
    
    
    int main()
    {
        char key = 0;
        PPMImage* img = NULL;
        do {
            puts("\tPress r to read in an image in ppm format");
            puts("\tPress s to save image in ppm format");
            puts("\tPress q to quit");
            
            scanf(" %c", &key);
            clear_to_end(stdin);
            switch (key) {
                case 'r':
                    // TODO: if img != NULL, free it
                    img = load_file();
                    break;
                case 's':
                    save_file(img);
                    break;
                case 'q':
                    puts("\tTerminating program...");
                    break;
                default:
                    puts("\tInvalid Input");
                    break;
            }
        } while (key != 'q');
    
    return0;

  2. #2
    and the hat of int overfl Salem's Avatar
    Join Date
    Aug 2001
    Location
    The edge of the known universe
    Posts
    39,659
    Reposted without the horrid colour scheme.
    Code:
    #include<stdio.h>
    #include <stdlib.h>
    #include <string.h>
    
    #define RGB_COMPONENT_COLOUR 255
    #define height 1080
    #define width 1920
    
    typedef struct
    {
        unsigned char red, green, blue;
    } PPMPixel;
    
    typedef struct
    {
        int x, y;
        PPMPixel *data;
    } PPMImage;
    
    void clear_to_end(FILE *fp)
    {
        int c;
        while ((c = fgetc(fp)) != -1 && c != '\n');
    }
    
    PPMImage* load_file()
    {
        FILE *fp;
        PPMImage *img;
        int d;
        char buff[16];
        char fname[100];
        printf("Enter file name: ");
        scanf("%s", fname);
        fseek(stdin,0,SEEK_END);
        fp = fopen(fname, "rb");
        if (fp == NULL || !fp || ferror(fp))
        {   
            printf("\tError while opening the file\n");
        }                        
        else    
        {
            printf("\tReading in %s\n", fname);
        }
    
        //Checking for comments
        //Skip whitespace and comments
        d = getc(fp);
        while (d=='#')
        {
            while(getc(fp)!='\n')
            d=getc(fp);
        }
        ungetc(d,fp);
    
        //Checking header
        if (!fgets(buff,sizeof(buff),fp))
        {
            perror(fname);
            exit(1);
        }
    
        if (buff[0] =='P' || buff[1] == 2 || buff[1] == 3)
        {
            printf("\tReading PGM/PPM image in...\n");
        }
        else
        {
            printf("\tIncorrect image format\n");
        }
    
        //Read image size information
        if (fscanf(fp, "%u%u", &img->y, &img->x))
        {
            printf("\tInvalid image size\n");
            printf("\tImage size is: %u x %u\n", img->y, img->x);
        }
        else
        {
            printf("\tImage size is valid\n");
            printf("\tImage size is: %u x %u\n", img->y, img->x);
        }
    
    
    }
    void save_file(PPMImage *img)
    {
        
        
    }
    
    
    int main()
    {
        char key = 0;
        PPMImage* img = NULL;
        do {
            puts("\tPress r to read in an image in ppm format");
            puts("\tPress s to save image in ppm format");
            puts("\tPress q to quit");
            
            scanf(" %c", &key);
            clear_to_end(stdin);
            switch (key) {
                case 'r':
                    // TODO: if img != NULL, free it
                    img = load_file();
                    break;
                case 's':
                    save_file(img);
                    break;
                case 'q':
                    puts("\tTerminating program...");
                    break;
                default:
                    puts("\tInvalid Input");
                    break;
            }
        } while (key != 'q');
    
    return0;
    If you dance barefoot on the broken glass of undefined behaviour, you've got to expect the occasional cut.
    If at first you don't succeed, try writing your phone number on the exam paper.

  3. #3
    and the hat of int overfl Salem's Avatar
    Join Date
    Aug 2001
    Location
    The edge of the known universe
    Posts
    39,659
    > while ((c = fgetc(fp)) != -1 && c != '\n');
    Use EOF, don't assume EOF is -1

    > if (fp == NULL || !fp || ferror(fp))
    fp == NULL and !fp are the same test, there's nothing gained by writing both.
    Also, ferror is only set after performing some read/write operation on the file.

    > if (!fgets(buff,sizeof(buff),fp))
    How long is the first line?

    Netpbm - Wikipedia
    You're assuming a very specific layout of spaces and newlines, which isn't at all guaranteed.

    > if (buff[0] =='P' || buff[1] == 2 || buff[1] == 3)
    The file contains characters, not numbers.
    So you should be comparing '2' or '3'.

    Also, it should be say
    if (buff[0] =='P' && ( buff[1] == '2' || buff[1] == '3') )
    First char is 'P'
    Second char is either '2' or '3'.
    If you dance barefoot on the broken glass of undefined behaviour, you've got to expect the occasional cut.
    If at first you don't succeed, try writing your phone number on the exam paper.

  4. #4
    Registered User
    Join Date
    Dec 2021
    Posts
    34
    Quote Originally Posted by Salem View Post
    >
    > if (!fgets(buff,sizeof(buff),fp))
    How long is the first line?

    Netpbm - Wikipedia
    You're assuming a very specific layout of spaces and newlines, which isn't at all guaranteed.

    > if (buff[0] =='P' || buff[1] == 2 || buff[1] == 3)
    The file contains characters, not numbers.
    So you should be comparing '2' or '3'.

    Also, it should be say
    if (buff[0] =='P' && ( buff[1] == '2' || buff[1] == '3') )
    First char is 'P'
    Second char is either '2' or '3'.
    Thanks for the tips! I don't know how long the first line is because any pgm or ppm file could be read in but I'm not sure how to exactly work around that yet. Also I tried using if (buff[0] =='P' && ( buff[1] == '2' || buff[1] == '3') ) before but all it seems to do is print my error message "incorrect image format".

  5. #5
    and the hat of int overfl Salem's Avatar
    Join Date
    Aug 2001
    Location
    The edge of the known universe
    Posts
    39,659
    Maybe you could attach your PBM file (or post it at say Pastebin.com - #1 paste tool since 2002! ) so we can see how your code differs from the file you're trying to parse.
    If you dance barefoot on the broken glass of undefined behaviour, you've got to expect the occasional cut.
    If at first you don't succeed, try writing your phone number on the exam paper.

  6. #6
    Registered User
    Join Date
    Dec 2021
    Posts
    34
    Quote Originally Posted by Salem View Post
    Maybe you could attach your PBM file (or post it at say Pastebin.com - #1 paste tool since 2002! ) so we can see how your code differs from the file you're trying to parse.
    Well this is one of the ppm files I was having trouble with: PPM File - Pastebin.com

    Thanks again.

  7. #7
    Registered User
    Join Date
    Dec 2017
    Posts
    1,632
    If you actually made the changes you said you made then you wouldn't get the error you say you're getting.
    At any rate, you should open the file in text mode, not binary mode.
    And you need to malloc some memory for the image.
    Also, you're not handling comments properly at all. Comments can go anywhere but at the very beginning (which seems to be where you think they can go) or in the image data. So this is valid:
    Code:
    P2   # Magic number
    5    # Width
    2    # Height
    255  # Max color value
    # Image data
    10 20 30 40 50
    5 15 25 35 45
    A little inaccuracy saves tons of explanation. - H.H. Munro

  8. #8
    and the hat of int overfl Salem's Avatar
    Join Date
    Aug 2001
    Location
    The edge of the known universe
    Posts
    39,659
    A few tweaks.
    Code:
    #include<stdio.h>
    #include <stdlib.h>
    #include <string.h>
    
    #define RGB_COMPONENT_COLOUR 255
    #define height 1080
    #define width 1920
    
    typedef struct
    {
        unsigned char red, green, blue;
    } PPMPixel;
    
    typedef struct
    {
        int x, y;
        PPMPixel *data;
    } PPMImage;
    
    void clear_to_end(FILE *fp)
    {
        int c;
        while ((c = fgetc(fp)) != -1 && c != '\n');
    }
    
    PPMImage* load_file(const char *fname)
    {
        FILE *fp;
        PPMImage *img = malloc(sizeof(*img));	//!! allocate space!
        int d;
        // https://en.wikipedia.org/wiki/Netpbm#PPM_example
        // according to this, max length of any line is 70 chars
        char buff[80];
        fp = fopen(fname, "r");  //!! not rb for text files!!
        if (fp == NULL)
        {   
            printf("\tError while opening the file\n");
            return NULL;
        }                        
        else    
        {
            printf("\tReading in %s\n", fname);
        }
    
        //Checking for comments
        //Skip whitespace and comments
        d = getc(fp);
        while (d=='#')
        {
            while(getc(fp)!='\n')
            d=getc(fp);
        }
        ungetc(d,fp);
    
        //Checking header
        if (!fgets(buff,sizeof(buff),fp))
        {
            perror(fname);
            exit(1);
        }
    
        if (buff[0] =='P' && (buff[1] == '2' || buff[1] == '3'))
        {
            printf("\tReading PGM/PPM image in...\n");
        }
        else
        {
            printf("\tIncorrect image format\n");
            return NULL;
        }
    
        //Read image size information
        if (fscanf(fp, "%u%u", &img->y, &img->x))
        {
            printf("\tInvalid image size\n");
            printf("\tImage size is: %u x %u\n", img->y, img->x);
        }
        else
        {
            printf("\tImage size is valid\n");
            printf("\tImage size is: %u x %u\n", img->y, img->x);
        }
    
        return img;
    }
    
    int main()
    {
        PPMImage* img = load_file("foo.pbm");
        free(img);
    }
    Results
    Code:
    $ gcc foo.c
    $ head foo.pbm 
    P3
    107 48
    255
    255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 
    255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 
    255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 
    255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 
    255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 
    255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 
    255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 
    $ ./a.out 
    	Reading in foo.pbm
    	Reading PGM/PPM image in...
    	Invalid image size
    	Image size is: 107 x 48
    If you dance barefoot on the broken glass of undefined behaviour, you've got to expect the occasional cut.
    If at first you don't succeed, try writing your phone number on the exam paper.

  9. #9
    Registered User
    Join Date
    Dec 2021
    Posts
    34
    Quote Originally Posted by john.c View Post
    If you actually made the changes you said you made then you wouldn't get the error you say you're getting.
    At any rate, you should open the file in text mode, not binary mode.
    And you need to malloc some memory for the image.
    Also, you're not handling comments properly at all. Comments can go anywhere but at the very beginning (which seems to be where you think they can go) or in the image data. So this is valid:
    Code:
    P2   # Magic number
    5    # Width
    2    # Height
    255  # Max color value
    # Image data
    10 20 30 40 50
    5 15 25 35 45
    I forgot to add the ' ' around 2 and 3 that's why it wasn't working in the end.

  10. #10
    Registered User
    Join Date
    Dec 2021
    Posts
    34
    Quote Originally Posted by Salem View Post
    A few tweaks.
    Code:
    #include<stdio.h>
    #include <stdlib.h>
    #include <string.h>
    
    #define RGB_COMPONENT_COLOUR 255
    #define height 1080
    #define width 1920
    
    typedef struct
    {
        unsigned char red, green, blue;
    } PPMPixel;
    
    typedef struct
    {
        int x, y;
        PPMPixel *data;
    } PPMImage;
    
    void clear_to_end(FILE *fp)
    {
        int c;
        while ((c = fgetc(fp)) != -1 && c != '\n');
    }
    
    PPMImage* load_file(const char *fname)
    {
        FILE *fp;
        PPMImage *img = malloc(sizeof(*img));    //!! allocate space!
        int d;
        // https://en.wikipedia.org/wiki/Netpbm#PPM_example
        // according to this, max length of any line is 70 chars
        char buff[80];
        fp = fopen(fname, "r");  //!! not rb for text files!!
        if (fp == NULL)
        {   
            printf("\tError while opening the file\n");
            return NULL;
        }                        
        else    
        {
            printf("\tReading in %s\n", fname);
        }
    
        //Checking for comments
        //Skip whitespace and comments
        d = getc(fp);
        while (d=='#')
        {
            while(getc(fp)!='\n')
            d=getc(fp);
        }
        ungetc(d,fp);
    
        //Checking header
        if (!fgets(buff,sizeof(buff),fp))
        {
            perror(fname);
            exit(1);
        }
    
        if (buff[0] =='P' && (buff[1] == '2' || buff[1] == '3'))
        {
            printf("\tReading PGM/PPM image in...\n");
        }
        else
        {
            printf("\tIncorrect image format\n");
            return NULL;
        }
    
        //Read image size information
        if (fscanf(fp, "%u%u", &img->y, &img->x))
        {
            printf("\tInvalid image size\n");
            printf("\tImage size is: %u x %u\n", img->y, img->x);
        }
        else
        {
            printf("\tImage size is valid\n");
            printf("\tImage size is: %u x %u\n", img->y, img->x);
        }
    
        return img;
    }
    
    int main()
    {
        PPMImage* img = load_file("foo.pbm");
        free(img);
    }
    Results
    Code:
    $ gcc foo.c
    $ head foo.pbm 
    P3
    107 48
    255
    255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 
    255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 
    255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 
    255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 
    255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 
    255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 
    255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 
    $ ./a.out 
        Reading in foo.pbm
        Reading PGM/PPM image in...
        Invalid image size
        Image size is: 107 x 48
    Thanks a lot that's really helped to smooth out some problems in my code. Yet I'm still getting ridiculously high numbers for pgm image dimensions and my switch case doesn't loop after r (though the latter is kind of an unrelated issue).

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Image(bitmap) larger size than the initial
    By nutzu2010 in forum Windows Programming
    Replies: 2
    Last Post: 08-02-2011, 06:01 AM
  2. reading from file of unspecified size into array
    By AJOHNZ in forum C++ Programming
    Replies: 15
    Last Post: 08-22-2009, 01:21 PM
  3. Replies: 3
    Last Post: 08-13-2006, 05:58 AM
  4. how to convert a bitmap image to a jpg image file using C++?
    By nomer in forum Windows Programming
    Replies: 4
    Last Post: 06-04-2006, 07:40 PM
  5. Image Size
    By NightWalker in forum C++ Programming
    Replies: 2
    Last Post: 05-11-2004, 12:17 PM

Tags for this Thread