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
// 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.