1

so i wrote an I/O for a pgm-file. My program reads a pgm and writes the data of it to a new pgm-file. But somehow it just writes the half of the data and i spent hours of searching for the mistake but couldn't find it.

Here is the code:

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

typedef struct {
    int row;
    int col;
    int max_greyscale;
    int **pixel_matrix;
} PGMData;

int **mem_alloc(int row, int col) {
    int **ret;

    ret = malloc(sizeof(int *) * row);
    if (ret == NULL) {
        perror("Error while allocating memory (NULL)");
        exit(EXIT_FAILURE);
    }

    for (int i = 0; i < row; i++) {
        ret[i] = malloc(sizeof(int) * col);
        if (ret[i] == NULL) {
            perror("Error while allocating memory (NULL)");
            exit(EXIT_FAILURE);
        }
    }
    return ret;
}

void destroy(int **pixel_matrix, int row) {
    for (int i = 0; i < row; i++) {
        free(pixel_matrix[i]);
    }
    free(pixel_matrix);
}

void ignoreComments(FILE *fp) {
    int c;
    char line[100];

    while((c = fgetc(fp)) != EOF && isspace(c))
        ;
    if (c == '#') {
        fgets(line, sizeof(line), fp);
        ignoreComments(fp);
    } else {
        fseek(fp, -1, SEEK_CUR);
    }
}

PGMData* readFile(const char *filename, PGMData *data) {
    FILE *fp;
    char magic[3];

    fp = fopen(filename, "r");
    if (fp == NULL) {
        perror("Error while reading file (NULL)");
        exit(EXIT_FAILURE);
    }

    fgets(magic, sizeof(magic), fp);

    ignoreComments(fp);
    fscanf(fp, "%d", &data->col);

    ignoreComments(fp);
    fscanf(fp, "%d", &data->row);

    ignoreComments(fp);
    fscanf(fp, "%d", &data->max_greyscale);

    fgetc(fp);
    data->pixel_matrix = mem_alloc(data->row, data->col);

    // read
    for (int i = 0; i < data->row; i++) {
        for (int j = 0; j < data->col; j++) {
            data->pixel_matrix[i][j] = fgetc(fp);
        }
    }
    fclose(fp);
    return data;
}

void writeFile(const char *filename, const PGMData *data) {
    FILE *fp;

    fp = fopen(filename, "w");
    if (fp == NULL) {
        perror("Error while writing file (NULL)");
        exit(EXIT_FAILURE);
    }

    fprintf(fp, "P2\n");
    fprintf(fp, "%d %d\n", data->col, data->row);
    fprintf(fp, "%d\n", data->max_greyscale);

    for (int i = 0; i < data->row; i++) {
        for (int j = 0; j < data->col; j++) {
            fputc(data->pixel_matrix[i][j], fp);
        }
    }

    fclose(fp);
    destroy(data->pixel_matrix, data->row);
}


int main(int argc, char *argv[]) {
    printf("P1\n");

    const char * source_file = argv[1]; // source
    const char * destin_file = argv[2]; // destination

    PGMData pgm_pic;
    PGMData * data = &pgm_pic;

    data = readFile(source_file, data); // read source
    writeFile(destin_file, data);       // write to destination

    return 0;
}

It gives me for this PGM:

P2
# feep.ascii.pgm
24 7
15
0 0  0  0  0  0  0  0  0 0  0  0  0  0  0  0  0 0  0  0  0  0  0  0
0 3  3  3  3  0  0  7  7 7  7  0  0 11 11 11 11 0  0 15 15 15 15  0
0 3  0  0  0  0  0  7  0 0  0  0  0 11  0  0  0 0  0 15  0  0 15  0
0 3  3  3  0  0  0  7  7 7  0  0  0 11 11 11  0 0  0 15 15 15 15  0
0 3  0  0  0  0  0  7  0 0  0  0  0 11  0  0  0 0  0 15  0  0  0  0
0 3  0  0  0  0  0  7  7 7  7  0  0 11 11 11 11 0  0 15  0  0  0  0
0 0  0  0  0  0  0  0  0 0  0  0  0  0  0  0  0 0  0  0  0  0  0  0

this output:

P2
24 7
15
0 0  0  0  0  0  0  0  0 0  0  0  0  0  0  0  0 0  0  0  0  0  0  0
0 3  3  3  3  0  0  7  7 7  7  0  0 11 11 11 11 0  0 15 15 15 15  0
0 3  0  0  0  0  0  7  0 0  0  0
thedude
  • 51
  • 8
  • Could you check if the source is read correctly, i.e. inspect `data` in your debugger. That will narrow down the problem. – Bathsheba Dec 04 '15 at 12:55
  • 1
    The line `data->pixel_matrix[i][j] = fgetc(fp);` in `readFile` seems to be expecting a PGM in binary format with one byte per pixel (which would be correct for magic number `P5`). Do you check the magic number anywhere to make sure it's the correct type of PGM file? – Ian Abbott Dec 04 '15 at 12:57
  • Oh is it? I don't have to check it, because i will only have to work with magic number P2 – thedude Dec 04 '15 at 12:59
  • But P2 format stores the pixels as whitespace-separated ASCII decimal numbers from 0 to 255, as shown in your input and output, not as single byte binary values. You'll need to use `fscanf` to read each pixel value as a decimal number, and use `fprintf` to print each pixel value as a decimal number. – Ian Abbott Dec 04 '15 at 13:07
  • To get the rows and columns, use a single `fscanf` call to read both values, don't call `ignoreComment` between them. Because there *can't* be any comment there. Furthermore, you should try to actually *debug* the program yourself. Step through the code, line by line, in a debugger. – Some programmer dude Dec 04 '15 at 13:07
  • thank you for your replies! i fixed the problem :) – thedude Dec 04 '15 at 13:14
  • It's good to hear that you found the cause of your problem. You could make this observation more helpful for future readers by writing a self-answer explaining *how* you diagnosed it, and in particular, which evidence will identify this problem when it's seen elsewhere. – Toby Speight Aug 16 '17 at 10:04
  • @TobySpeight Hi, well this is long time ago, and I couldn't reply as soon as possible, because of Stackoverflow doesn't give me permission, because of low points etc. Since I can't remember of the fix, here is the link to the repository with working code. I hope this can help you guys. https://github.com/yduman/pgm-image-processing/ – thedude Aug 16 '17 at 18:53

1 Answers1

1

But P2 format stores the pixels as whitespace-separated ASCII decimal numbers from 0 to 255, as shown in your input and output, not as single byte binary values. You'll need to use fscanf to read each pixel value as a decimal number, and use fprintf to print each pixel value as a decimal number. – Ian Abbott

Armali
  • 18,255
  • 14
  • 57
  • 171