PGM or Portable Gray Map file is a grayscale image where each pixel is encoded with 1 or 2 bytes. It contains header information and pixel grayscale values in a matrix form.
Approach: The idea is followed to read PGMB format image is as follows:
- Open a PGMB (binary format PGM image).
- Extract the pixel information, which can be then used for further processing.
- The header information is stored in ASCII format can be read using any text editor but the pixel information is stored in a binary formation and the text editor will show that as some gibberish text.
Below is the sample pgm image.

Header Information:
- magic number for identifying the file type:
- Binary PGM File (PGMB): "P5"
- ASCII PGM File (PGMA): "P2"
- Width in ASCII decimal format
- Height in ASCII decimal format
- Maximum Gray Value, ASCII decimal format, between 0-255
- Can contain comments, denoted by beginning the line with a '#'
- All separated with white spaces (blanks space, tabs, CRs, LFs)
Header information in gfg_logo.pgm:
P5 # sample PGMB image # gfg_logo.pgm 200 200 255
After the header information, there is a grid of dimensions height * weight containing the grayscale pixel values of the image in binary format.
Reading PGMB Image:
- Open the image in the read binary, rb mode.
- Check if any comments are present and ignore them.
- Read the Magic Number.
- Read any comments/blank line/white space.
- Read width and height separated by white space.
- Read the max gray value, before and after any white space/comment.
- Read the grid (width * height) of pixel values, separated by white spaces.
Below is the program for the above approach:
// C Program to read a PGMB image
// and print its parameters
#include <ctype.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
// Structure for storing the
// image data
typedef struct PGMImage {
char pgmType[3];
unsigned char** data;
unsigned int width;
unsigned int height;
unsigned int maxValue;
} PGMImage;
// Function to ignore any comments
// in file
void ignoreComments(FILE* fp)
{
int ch;
char line[100];
// Ignore any blank lines
while ((ch = fgetc(fp)) != EOF
&& isspace(ch))
;
// Recursively ignore comments
// in a PGM image commented lines
// start with a '#'
if (ch == '#') {
fgets(line, sizeof(line), fp);
ignoreComments(fp);
}
else
fseek(fp, -1, SEEK_CUR);
}
// Function to open the input a PGM
// file and process it
bool openPGM(PGMImage* pgm,
const char* filename)
{
// Open the image file in the
// 'read binary' mode
FILE* pgmfile
= fopen(filename, "rb");
// If file does not exist,
// then return
if (pgmfile == NULL) {
printf("File does not exist\n");
return false;
}
ignoreComments(pgmfile);
fscanf(pgmfile, "%s",
pgm->pgmType);
// Check for correct PGM Binary
// file type
if (strcmp(pgm->pgmType, "P5")) {
fprintf(stderr,
"Wrong file type!\n");
exit(EXIT_FAILURE);
}
ignoreComments(pgmfile);
// Read the image dimensions
fscanf(pgmfile, "%d %d",
&(pgm->width),
&(pgm->height));
ignoreComments(pgmfile);
// Read maximum gray value
fscanf(pgmfile, "%d", &(pgm->maxValue));
ignoreComments(pgmfile);
// Allocating memory to store
// img info in defined struct
pgm->data
= malloc(pgm->height
* sizeof(unsigned char*));
// Storing the pixel info in
// the struct
if (pgm->pgmType[1] == '5') {
fgetc(pgmfile);
for (int i = 0;
i < pgm->height; i++) {
pgm->data[i]
= malloc(pgm->width
* sizeof(unsigned char));
// If memory allocation
// is failed
if (pgm->data[i] == NULL) {
fprintf(stderr,
"malloc failed\n");
exit(1);
}
// Read the gray values and
// write on allocated memory
fread(pgm->data[i],
sizeof(unsigned char),
pgm->width, pgmfile);
}
}
// Close the file
fclose(pgmfile);
return true;
}
// Function to print the file details
void printImageDetails(PGMImage* pgm,
const char* filename)
{
FILE* pgmfile = fopen(filename, "rb");
// Retrieving the file extension
char* ext = strrchr(filename, '.');
if (!ext)
printf("No extension found"
"in file %s",
filename);
else
printf("File format"
" : %s\n",
ext + 1);
printf("PGM File type : %s\n",
pgm->pgmType);
// Print type of PGM file, in ascii
// and binary format
if (!strcmp(pgm->pgmType, "P2"))
printf("PGM File Format:"
"ASCII\n");
else if (!strcmp(pgm->pgmType,
"P5"))
printf("PGM File Format:"
" Binary\n");
printf("Width of img : %d px\n",
pgm->width);
printf("Height of img : %d px\n",
pgm->height);
printf("Max Gray value : %d\n",
pgm->maxValue);
// close file
fclose(pgmfile);
}
// Driver Code
int main(int argc, char const* argv[])
{
PGMImage* pgm = malloc(sizeof(PGMImage));
const char* ipfile;
if (argc == 2)
ipfile = argv[1];
else
ipfile = "gfg_logo.pgm";
printf("\tip file : %s\n", ipfile);
// Process the image and print
// its details
if (openPGM(pgm, ipfile))
printImageDetails(pgm, ipfile);
return 0;
}
Output:
Explanation:
- Create a structure for storing the PGMB image details and allocate memory for the same.
- Take the file name input either as a command-line argument or by hard coding it in the program.
- The openPGM() function processes the input image files and takes the memory pointer and filename are input.
- The ignoreComments() function is used to skip any comments in the file. Comments are usually present in the header portion and thus, we check for them after reading every property.
- In openPGM() function, read the file header information, ie. file type, height, weight, etc as given above.
- Then allocate memory as per the height of the image and for each row, allocate memory for the width of the image.
- The fread() method reads the gray values and stores them in the allocated memory for the 2d character matrix of the pgm structure.
- printImageDetails() is used to print the values retrieved from the PGMB image file.