/** pgm.c - implements a little library to handle raw pgm images
 *
 * Originally designed by Anton Nokolaev, implemented by Efstathios
 * Hadjidemetriou for Shree Nayar's computer vision.  
 *
 * Modified into its current format by Paul Blaer <psb15@cs.columbia.edu>
 * Updated by Lenny Volchok <lv71@columbia.edu>
 *
 * Last Modified: 3/24/2001
 *
 **/


/* includes */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "pgm.h"


/*  sets the size of the image to the given 
    height (# of rows) and width (# of columns);
    returns 0 if OK or -1 if fails;*/
int setSize(struct image *im, int rows, int columns) {
  im->rows=rows;
  im->columns=columns;
  im->data = (uchar *) malloc(rows * columns * sizeof(char));
  if(im->data == NULL) {
    fprintf(stderr, "Insufficient memory for new image\n");
    exit(1); 
  } 
  
  return 0;
}


/* returns the number of columns in the image;*/
int getNCols(struct image *im) {
  return im->columns;
}


/* returns the number of rows in the image;*/
int getNRows(struct image *im) {
  return im->rows;
}


/* sets the number of gray-level colors in the image
   (not counting 0);
   returns 0 if OK or -1 if fails;*/
int setColors(struct image *im, int colors) {
  im->colors=colors;
  return 0;
}


/* returns the number of gray-level colors in the image; */
int getColors(struct image *im) {
  return im->colors;
}


/* sets the pixel in the image at row i and column j 
   to a particular color; */
int setPixel(struct image *im, int i, int j, int color) {
  i=CLAMP(i, 0, im->rows-1);
  j=CLAMP(j, 0, im->columns-1);
  im->data[i*(im->columns)+j]=color;

  return 0;
}


 /* returns the color of the pixel in the image at row i and column j;*/
int getPixel(struct image *im, int i, int j) {
  i=CLAMP(i, 0, im->rows-1);
  j=CLAMP(j, 0, im->columns-1);
  return (int) im->data[i*(im->columns)+j];
}


/* reads image from fname;
   returns 0 if OK or -1 if something goes wrong. */
int readImage(struct image *im, const char *fname)
{  
  FILE *input;
  char line[1024];     
  int nCols,nRows;  
  int levels;
  int i, j;

  /* open it */
  if (!fname || (input=fopen(fname,"r"))==0)
    return-1;

  /* check for the right "magic number" */
  if (
        fread(line,1,3,input)!=3
      ||strncmp(line,"P5\n",3)
     )
  {
    fclose(input);
    return -1;
  }
  
  /* skip the comments */
  do
    fgets(line,sizeof line,input);
  while(*line=='#');

  /* read the width and height */
  sscanf(line,"%d %d\n",&nCols,&nRows);
  setSize(im, nRows, nCols);

  /* read # of gray levels */
  fgets(line,sizeof line,input);
  sscanf(line,"%d\n",&levels);
  setColors(im, levels);
  
  /* read pixel row by row */
  for(i=0;i<nRows;i++)
  {
    for(j=0;j<nCols;j++)
    {
      int byte=fgetc(input);

      if (byte==EOF) /* short file */
      {
        fclose(input);
        return -1;
      }
      else
        setPixel(im,i,j,byte);	
    }
  }

  /* close the file */
  fclose(input);
  return 0; /* OK */
}


/* writes the image into fname;
   returns 0 if OK or -1 if something goes wrong.
*/
int writeImage(struct image *im, const char *fname)
{
  FILE *output; 
  int nRows;
  int nCols;
  int colors;
  int i, j;
    
  /* open the file */
  if (!fname || (output=fopen(fname,"w"))==0)
    return(-1);

  nRows=getNRows(im);
  nCols=getNCols(im);
  colors=getColors(im);

  /* write the header */
  fprintf(output,"P5\n"); /* magic number */
  fprintf(output,"#\n");  /* empty comment */
  fprintf(output,"%d %d\n%03d\n",nCols,nRows,colors); /* image info */

  /* write pixels row by row */
  for(i=0;i<nRows;i++)
  {
    for(j=0;j<nCols;j++)
    {
      int byte=getPixel(im,i,j);

      if (fputc(byte,output)==EOF) /* couldn't write */
      {
	    fclose(output);
	    return -1;
      }      
    }
  }
  
  /* close the file */
  fclose(output);
  return 0; /* OK */
}
