Reading PPM format images

Thread Starter

asilvester635

Joined Jan 26, 2017
73
I’m trying to read this PPM format image, which contains an ASCII header followed by binary pixel data. The header consists of something like this:

P6

650 652

255

P6 indicates that it is a PPM image. The next two fields are the width and height of the image. The last field gives the maximum pixel value. At the end of the header is a \n and then the binary pixel data. The image is in color so there are three bytes (red, green, blue). The goal of my readPPM function is to return the pixel data in a one-dimensional array of unsigned chars, plus the width and height of the image. The goal of my writePPM function (I haven't done anything for that function yet) is to write the PPM format image to an empty file from the given information returned from my readPPM function.

I've successfully stored the header (P6, 650, 652, and 255)) in their right variables (I know because I tried printing their values and they came out right). My output is shown below. I was wondering what those nonsense characters below the maximum were. Are those the binary pixel data? If so, then I just need to write my writePPM function.


Output:
PSix: P6
Width: 650
Height: 652
maximum: 255
?ɡ?Ƞ?ɢ?ˤ?ɢ?Ş?ĝ?Ǡ?ʤ?ɣ?ɡ?ɡ?ǟ?Ĝ?ŝ?Ƞ?ȡ?ʣ?ʣ?ȡ?Ŝ?Ŝ?Ȟ?ʠ?̤?ƞ?Ơ?ʤ?ʦ?ʦ?ɧ?Ƥ?ǥ?Ȧ?ɩ?ʪ?ʫ?ʫ?ʪ?ʨ?ɤ?Ǡ?ʢ?̤?ȡ?ȡ?ʥ?ɥ?ʧ?Ģ?ǥ?Ƥ?Ģ? ????Ƥ????ǥ?ʨ?ɧ?ʨ?ɧ?ɧ?ͨ?ϧ?ʟ?ˠ?Х?Φ?ͥ?ˣ?ǟ?œ?Ơ?ʦ?ɥ?Ġ????????????? ?????ħ?Ũ???????©?Ǯ?????????????Ǩ?˭?ū?????????????????????????鴢紣㴢ⳡ޴?ܴᷟ?⺡㻢Ḥ⹥޴?ݳ?۱?ܲ?۱?خ?׭?ٯ?֮?ѫ?Ъ?̨?մ?յ?Ǫ?̲?ٿ?һ????ư?ɳ?ɳ?ɱ?ɱ?˰?ˮ?ɪ?Ȧ?ͫ?ֵ?ұ?Ť?¡?ʩ?Ӳ?Ϯ?ͫ?ϭ?ѯ?ѯ?Ϭ?̭?˰?Ͷ?͵?˳?ʱ?Ǯ?ȯ?ε?ӷ?ϳ?̯?ɬ?̫?ͬ?ͭ?˪?ΰ?ͮ?ί?Ӵ?Ӷ?ϲ?ˮ?ɬ?ʭ?Ѵ?ҵ?г?ϲ?ˮ?ȫ?ɬ?ǩ?ϱ?в?˭?ʬ?˭?̭?ί?ͮ?ͮ?ͮ?ί?ˬ?ȩ?ʫ?ͮ?ղ?ү?Ӳ?ֵ?Ҵ?ѳ?ϲ?ˮ?ȭ?˰?ˮ?ˮ?ͯ?̮?̬?ͯ?ˮ?̱?˲?ȯ?ƭ?Ư?Ů?®?¯?????????????????????????????????????¨?é?é?ū?¨???????????????????????????????ī?ī?ī?Ŭ?Ŭ?ī?ū?ū?é???????ĭ?Ů?®???????????©??????????ȫ?ȫ?Ȫ?ɫ?̭?̭?˭?ʬ?ɫ?ʬ?ʮ?˯?˯?˯?˯?Ȭ?Ȫ?ɫ?̮?ͯ?ϱ?ѳ?ӵ?Ѵ?б?ϰ?ϭ?ά?Ѯ?Ա?Ӱ?Э?Ϭ?ү?ү?Э?ά?ѯ?ױ?ӭ?ϩ?ͧ?ϧ?ѩ?Ԭ?ذ?խ?ѩ?Ϧ?Ϧ?Ч?ҩ?ҩ?ҩ?ת?ث?׭?خ?ׯ?֮?կ?կ?Ԭ?խ?ج?ج?ܬ?߰?㳩䴨峨ݫ?٧?ެ?䲧峨䲧䲧Ⱗ䲩붮?ﺲ국굯???????걦뱥ﶥ???????????????????????????????????????±????ð?????????????????????????????????????????????????æ?ũ?ç?é?Ī?ë???????£?Ʀ?Ʀ?ƥ?Ť?Ť?ƥ?ɧ?ʨ?ͫ?ά?ʩ?Ť?â?ţ?Ǩ?ť?Ƨ?ˬ?ɭ?¦???????????????????????????????ç???????????????????????????????????????????????????????????????????????????????????????????????????????????????????ñ?°?ñ??????????î????????????????????????鲯豮汭尬䯫汭곮췱洫ᱧద嵫緭䴪᯦᯦䲩洫鴬鴬鴬국국贩춬??????뵩괪???????????겱⪭????겳???뵫贩贩趫긭긭긭跩綨깫컭궩糦뵩뷩켨컪鸧綨浧絬鷮鷰峬洫???긭跩긭캱캳깲綯㳩ᱧ㳧嵩㵨᳦᳤ⴥ乩缬轭轭缬ߴ?۰?ߴ?幬


Here is my code just in case you are curious...


main.cc
Code:
    char fileName[50] = "test.ppm";
    char pSix[10];        // indicates this is a PPM image
    int width = 0;        // width of the image
    int height = 0;        // heigt of the image
    int maximum = 0;    // maximum pixel value
    int size = 128;        // size of the array

    // read the PPM file and store its contents inside an array and return the pointer to that array to pixelArray
    unsigned char* pixelArray = readPPM(fileName, pSix, &width, &height, &maximum);

readPPM.cc
Code:
unsigned char* readPPM(const char* fileName, char* pSix, int* width, int* height, int* maximum) {

    // open the file to read just the header reading
    FILE* fr = fopen(fileName, "r");

    // formatted read of header
    fscanf(fr, "%s", pSix);

    // check to see if it's a PPM image file
    if (strncmp(pSix, "p6" , 10) != 0) {
        printf("They are not the same\n");
    } else {
        printf("They are the same\n");
    }

    // read the rest of header
    fscanf(fr, "%d\n %d\n", width, height);

    fscanf(fr, "%d\n", maximum);

    // check to see if they were stored properly
    printf("PSix: %s\n", pSix);
    printf("Width: %d\n", *width);
    printf("Height: %d\n", *height);
    printf("maximum: %d\n", *maximum);

    //int size = width * height;
    int size = 423800;

    // allocate array for pixels
    unsigned char* pixels = new unsigned char[size];

    // unformatted read of binary pixel data
    while (fread(pixels, sizeof(pixels), 128, fr)) {
        printf("%s", pixels);
    } // end of for loop

    // close file
    fclose(fr);

    // return the array
    return pixels;
   
} // end of readPPM
 

MrSoftware

Joined Oct 29, 2013
2,273
Open your source file in a hex editor so that you can see the raw data. Use the memory watch in your debugger to view the raw bytes in memory as you read the file into memory. Do the values match? That will tell you if you're reading the data that you think you're reading.

Also double check your while loop, off the cuff I believe your sizeof(pixels) is giving you something other than what you're expecting. i.e. I believe you're going to get the size of a char* pointer, most likely 4-bytes if compiled as 32-bit binary.

Also fread doesn't return a bool, it returns the number of elements read. Using it as a bool is a bad practice that can lead to bugs. For example, if something goes wrong part way through reading the file, you'll never know that you didn't read the entire file. Instead you should check to see if it read the number of elements that you expected it to read. You should use your favorite version of fstat to get the file size, then keep track of the actual number of bytes read to be sure that you read the entire file. When fread fails, use feof and ferror to determine if you had a real error, or if you just reached the end of the file.
 
Top