cimagebinarypgm

Exception thrown: write access violation. Variable was nullptr


I have to read a .pgm file for an assignment and decode the least significant bit in every byte to get some hidden text. I have the reading and writing code from the professor but when I try to read the file color has an issue being written to. I think I know how to actually get the hidden text out but the I/O always gives me trouble.

Thanks in advance for your help.

It wouldnt let me add the .pgm so i ranamed it as .png, so if you download it make sure to rename it to .pgm this is the .pgm image uploaded as a .png

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

typedef unsigned char uchar;

/****************************************/
/* Clear PGM (XV) comments.             */
/****************************************/
void pgmCommentClear(FILE* disk) {
    uchar  ch;
    fread(&ch, 1, 1, disk);
    if (ch != '#') {
        fseek(disk, -1, SEEK_CUR);
        return;
    }
    do {
        while (ch != '\n') fread(&ch, 1, 1, disk);
    } while (ch == '#');
    pgmCommentClear(disk);
}

/****************************************/
/* Read PGM formatted image (1D array). */
/****************************************/
uchar* PGM_FILE_READ_1D(char* FileName, int* Width, int* Height, int* color) {
    int   pmax;
    char  ch;
    char  type[3];
    uchar* Image;
    FILE* disk;
    if ((disk = fopen(FileName, "rb")) == NULL) {
        return NULL;
    }
    fscanf(disk, "%s", type);
    if (!strcmp(type, "P6")) *color = 1;
    else *color = 0;
    fread(&ch, 1, 1, disk);
    pgmCommentClear(disk);
    fscanf(disk, "%d", Width);
    fscanf(disk, "%d", Height);
    fscanf(disk, "%d", &pmax);
    fread(&ch, 1, 1, disk);
    if (*color == 1) {
        Image = (uchar*)calloc(*Height * *Width * 3, sizeof(uchar));
        fread(Image, 1, (*Height * *Width * 3), disk);
    }
    else {
        Image = (uchar*)calloc(*Height * *Width, sizeof(uchar));
        fread(Image, 1, (*Height * *Width), disk);
    }
    fclose(disk);
    return Image;
}

/****************************************/
/* Write PGM formatted image (1D array).*/
/****************************************/
void PGM_FILE_WRITE_1D(char* FileName, uchar* Image, int Width, int Height, int color) {
    FILE* disk;
    disk = fopen(FileName, "wb");
    if (color == 1) fprintf(disk, "P6\n");
    else fprintf(disk, "P5\n");
    fprintf(disk, "%d %d\n", Width, Height);
    fprintf(disk, "255\n");
    if (color == 1) {
        fwrite(Image, 1, (Height * Width * 3), disk);
    }
    else {
        fwrite(Image, 1, (Height * Width), disk);
    }
    fclose(disk);
}

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


    // do command line args stuff for extra credit
    //if (argv == 2) { }

    // read the file
    //int width = 876
    //int height = 594
    
    uchar* image = PGM_FILE_READ_1D("./hw10.pgm", 876, 594, 0);

    printf("%c", *image);

}

Solution

  • Pretty cool assignment, Ron Marsh ;-)

    #include <stdlib.h>
    #include <stdio.h>
    #include <string.h>
    
    typedef unsigned char uchar;
    
    /****************************************/
    /* Clear PGM (XV) comments.             */
    /****************************************/
    void pgmCommentClear(FILE* disk) {
        uchar  ch;
        fread(&ch, 1, 1, disk);
        if (ch != '#') {
            fseek(disk, -1, SEEK_CUR);
            return;
        }
        do {
            while (ch != '\n') fread(&ch, 1, 1, disk);
        } while (ch == '#');
        pgmCommentClear(disk);
    }
    
    /****************************************/
    /* Read PGM formatted image (1D array). */
    /****************************************/
    uchar* PGM_FILE_READ_1D(char* FileName, int* Width, int* Height, int* color) {
        int   pmax;
        char  ch;
        char  type[3];
        uchar* Image;
        FILE* disk;
        if ((disk = fopen(FileName, "rb")) == NULL) {
            return NULL;
        }
        fscanf(disk, "%s", type);
        if (!strcmp(type, "P6")) *color = 1;
        else *color = 0;
        fread(&ch, 1, 1, disk);
        pgmCommentClear(disk);
        fscanf(disk, "%d", Width);
        fscanf(disk, "%d", Height);
        fscanf(disk, "%d", &pmax);
        fread(&ch, 1, 1, disk);
        if (*color == 1) {
            Image = (uchar*)calloc(*Height * *Width * 3, sizeof(uchar));
            fread(Image, 1, (*Height * *Width * 3), disk);
        }
        else {
            Image = (uchar*)calloc(*Height * *Width, sizeof(uchar));
            fread(Image, 1, (*Height * *Width), disk);
        }
        fclose(disk);
        return Image;
    }
    
    /****************************************/
    /* Write PGM formatted image (1D array).*/
    /****************************************/
    void PGM_FILE_WRITE_1D(char* FileName, uchar* Image, int Width, int Height, int color) {
        FILE* disk;
        disk = fopen(FileName, "wb");
        if (color == 1) fprintf(disk, "P6\n");
        else fprintf(disk, "P5\n");
        fprintf(disk, "%d %d\n", Width, Height);
        fprintf(disk, "255\n");
        if (color == 1) {
            fwrite(Image, 1, (Height * Width * 3), disk);
        }
        else {
            fwrite(Image, 1, (Height * Width), disk);
        }
        fclose(disk);
    }
    
    int main(int argc, char const* argv[]) {
    
        // do command line args stuff for extra credit
        char newMsg[100] = "";
        if (argc >= 2) 
            for (int i = 1; i < argc; i++) {
                strcat(newMsg, argv[i]);
                strcat(newMsg, " ");
            }
            else
                strcat(newMsg, "Greetings from the other side");
        strcat(newMsg, "\0");
    
        int width, height, color;
        
        // read the file
        uchar* image = PGM_FILE_READ_1D("./hw10.pgm", &width, &height, &color);
        printf("width = %d, height = %d, color = %d\n", width, height, color);
    
        // Read encoded message
        int size = width * height, bitCount = 8;
        uchar hiddenChar = 0;
        for (int i = 0; i < size; i++) {
            //shift least-significant bit left `bitCount` times and overlay onto `hidden`
            hiddenChar |= ((image[i] & 0x01) << --bitCount); 
            // After 8 bits we have the hidden byte
            if (bitCount == 0) {
                // If character is null terminator then we're done
                if (hiddenChar == 0) 
                    break;
                // Print hidden character and reset
                printf("%c", hiddenChar);
                bitCount = 8;
                hiddenChar = 0;
            }
        }
    
        // Encode new message
        int len = strlen(newMsg) + 1;
        for (int i = 0; i < len; i++) 
            for (int j = 0; j < 8; j++) 
                if ( newMsg[i] & (0x01 << (7-j) ) )                 
                    image[i * 8 + j] |= 0x01;
                else
                    image[i * 8 + j] &= 0xfe;
        PGM_FILE_WRITE_1D("./hw10-out.pgm", image, width, height, color);
    
        return 0;
    }