I26 Answer ― Image Header


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

int main ( int argc, char* argv[] )
{
  FILE *file;
  char  buffer[1024];
  int   nrows, ncols, ngray ;
  int   ch, count ;
  int   moreComments=1;
  
  if ( argc != 2 )
  {
    printf("imageInfo filename\n");
    exit( EXIT_FAILURE );
  }
  
  /* open the image file for reading binary */
  if ( (file = fopen( argv[1], "rb") ) == NULL )
  {
    printf("image file %s could not be opened\n", argv[1] );
    exit( EXIT_FAILURE );
  }

  /* read signature on first line -- read in nonwhitespace characters */
  if ( fscanf( file, "%s", buffer ) != 1 )
  {
    printf("error in image header: no signature\n" );
    exit( EXIT_FAILURE );
  }

  if ( strncmp( buffer, "P5", 2 ) == 0 )
  printf("type: PGM\n" );

  else if ( strncmp( buffer, "P6", 2 ) == 0 )
    printf("type: PPM\n" );
  
  else
  {
    printf("type: %s\n", buffer );
    exit( EXIT_FAILURE );
  }

  /* echo comment lines */
  /* comment lines start with # and end with a linefeed */
  while ( moreComments )
  {
    /* advance to first nonwhitespace characgter */
    while ( (ch=fgetc(file)) && isspace(ch) );
    
    /* if there is a comment */
    if ( ch=='#' )
    {
      fgets( buffer, 1024, file ); /* read up to the required linefeed */
      printf("#%s", buffer );
    }
 
    /* this is not the start of a comment */
    else
    {
      moreComments = 0;
      ungetc( ch, file );
    }
  }

  /* Read in nrows, ncols, ngray. */
  /* The three values are in ascii, separated by white space */
  /* which might include a line terminator. */
  count = fscanf( file, " %d %d %d", &ncols, &nrows, &ngray );
  
  if ( count != 3 )
  {
    printf("error in image header\n" );
    exit( EXIT_FAILURE );
  }

  /* echo ncols, nrows, ngray */
  printf("ncols: %d\n", ncols );
  printf("nrows: %d\n", nrows );
  printf("ngray: %d\n", ngray );
}



Comments: The section that echos comment lines is slightly tricky. There might not be any comment lines, and the only way to know is to check if the whitespace that follows P5 or P6 is followed by a #. If it is, all characters up to the next linefeed character are a comment.

fgets() reads up to the newline character that is required at the end of a comment.

If the next nonwhitespace character is not a # the next character is part of the number of columns. The call to ungetc(ch,file) "puts back" the character just read in. The character must be scanned by the fscanf() in the next section of code.