basicImage.c

To create a program that consists of one big file: Copy and paste all of the following code into a file called basicImage.c which will be #included at the top of the source file. The suggested answers to the puzzles show this style.

If you want to create a project (rather than one big source file), copy and paste sections of this file into two individual files of the project as indicated by the dotted lines. Add the two files to your project along with your source files. Include the header file image.h at the top of source files where appropriate.


/* - - - - - - - - - - image.h - - - - - - - - - - - - - - */

typedef struct
{
  int nrows;
  int ncols;
  unsigned char *pixels;
} image;

unsigned char *newImage( image *img, int nrows, int ncols );
void freeImage( image *img );
void setPixel( image img, int row, int col, unsigned char val );
unsigned char getPixel( image img, int row, int col );
void writePGMimage( image img, char *filename );
void readPGMimage( image *img, char *filename );

/* - - - - - - - - - - imageFunctions.c - - - - - - - - - - */

/* #include "image.h" */

unsigned char *newImage( image *img, int nrows, int ncols )
{
  img->nrows = nrows;
  img->ncols = ncols;
  img->pixels = (unsigned char *)malloc( nrows * ncols );

  return img->pixels;
}

void freeImage( image *img )
{
  img->nrows = 0;
  img->ncols = 0;
  free( img->pixels );
}

void setPixel( image img, int row, int col, unsigned char val )
{
  img.pixels[ img.ncols*row + col ] = val;
}

unsigned char getPixel( image img, int row, int col )
{
  return img.pixels[ img.ncols*row + col ] ;
}

void writePGMimage( image img, char *filename )
{
  FILE *file;

  /* open the image file for writing */
  if ( (file = fopen( filename, "wb") ) == NULL )
  {
    printf("file %s could not be created\n", filename );
    system( "pause" );
    exit( EXIT_FAILURE );
  }

  /* write out the PGM Header information */
  fprintf( file, "P5\n");
  fprintf( file, "# Created by writeImage\n");
  fprintf( file,  "%d %d %d\n", img.ncols, img.nrows, 255 );

  /* write the pixel data */
  fwrite(img.pixels, 1, img.nrows*img.ncols, file );

  /* close the file */
  fclose( file );
}
 
void readPGMimage( image *img, char *filename )
{
  FILE *file;
  char  buffer[1024];
  int   nrows, ncols, ngray ;
  
  /* open the image file for reading binary */
  if ( (file = fopen( filename, "rb") ) == NULL )
  {
    printf("readImage(): file %s could not be opened\n", filename );
    exit( EXIT_FAILURE );
  }

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

  if ( strncmp( buffer, "P5", 2 ) != 0 )
  {
    printf("readPGMimage(): file %s is not a PGM file\n", filename );
    printf("Signature: %s\n", buffer );
    exit( EXIT_FAILURE );
  }

  /* skip over comment lines */
  int moreComments = 1, ch;
  while ( moreComments )
  {
    /* skip over possible white space */
    while ( (ch=fgetc(file)) && isspace(ch) );
    if ( ch=='#' )
    {
      /* comments are required to end with line-feed, so fgets will work */
      fgets( buffer, 1024, file );
    }
    else
    {
      moreComments = 0;
      ungetc( ch, file );
    }
  }

  /* get ncols, nrows, ngray and eat the required single white space that follows */
  int count = fscanf( file, "%d %d %d", &ncols, &nrows, &ngray );
  if ( count != 3 )
  {
    printf("error in image header\n" );
    exit( EXIT_FAILURE );
  }
  fgetc(file);

  if ( ngray != 255 )
  {
    printf("readPGMimage(): file %s is %d, not 8 bits per pixel\n",
      filename, ngray );
    exit( EXIT_FAILURE );
  }

  /* construct an image structure of the appropriate size */
  if ( !newImage( img, nrows, ncols ) )
  {
    printf("readPGMimage(): newImage failed\n" );
    exit( EXIT_FAILURE );
  }

  /* read the pixel data */
  fread( img->pixels, 1, img->nrows*img->ncols, file );

  /* close the file */
  fclose( file );
}