/* =============================================================================
 * =============================================================================
 * CPSC 514 Advanced Computer Graphics / Assignment 1
 *
 * file: png.c
 *
 * png file read/write
 *
 * Author: Andrew Nealen, Dept. of Computer Science, UBC Vancouver
 * Date: 01/24/02
 * =============================================================================
 * =============================================================================
 */

#include <stdio.h>
#include <errno.h>
#include <iostream.h>
#include <fstream.h>

unsigned char *
loadPNG( const char *filename,
	 unsigned int& width, unsigned int &height,
	 unsigned int &numComponents )
{
  FILE          *imgFile;
  char          buf[1024];
  char          type;
  int           i, j, k, l;
  double        distance, x, y;
  unsigned char*	imageData;
 
  imgFile= fopen( filename, "rb" );
  if( errno!= 0 ) {
    cout << "file doesn't exist. aborting." << endl;
    return NULL;
  }
  // read PNM magic number (P1 to P6)

  if( fscanf( imgFile, "P%c \n", &type )!= 1 || type < '1' || type > '8')
  {
    cout << "not am image file" << endl;
    fclose( imgFile );
    return NULL;
  }

  // skip comments
  while( fscanf( imgFile, "#%[^\n]\n", buf ) );

  // read width
  fscanf( imgFile, "%d", &width );

  /* skip comments */
  while( fscanf( imgFile, "#%[^\n]\n", buf ) );

  /* read height */
  fscanf( imgFile, "%d", &height );
  
  /* skip comments */
  while( fscanf( imgFile, "#%[^\n]\n", buf ) );

  /* skip max. component and exactly one whitespace */
  fscanf( imgFile, "%*d%*c" );
  
  switch( type )
  {
  case '1': // ASCII bitmap
  case '4': // binary bitmap
    cerr << "Bitmaps not implemented\n";
    fclose( imgFile );
    return NULL;
  case '2': // ASCII greymap
    imageData= new unsigned char[width*height*3];
    for( i= 0 ; i< height ; i++ )
      for( j= 0 ; j< width ; j++ )
      {
	fscanf( imgFile, "%d", &l );
	imageData[i*width+j]= l;
      }
    numComponents= 1;
    break;
  case '3': // ASCII RGB
    imageData= new unsigned char[width*height*3];
    for( i= 0 ; i< height ; i++ )
      for( j= 0 ; j< width ; j++ )
	for( k= 0 ; k< 3 ; k++ )
	{
	  fscanf( imgFile, "%d", &l );
	  imageData[(i*width+j)*3+k]= l;
	}
    numComponents= 3;
    break;
  case '5': // binary greymap
    imageData= new unsigned char[width*height];
    fread( imageData, 1, width*height, imgFile );
    numComponents= 1;
    break;
  case '6': // binary RGB
    imageData= new unsigned char[width*height*3];
    fread( imageData, 1, width*height*3, imgFile );
    numComponents= 3;
    break;
  }
  fclose( imgFile );
  
  return imageData;
}

void outputRGBImageData(const char* filename, 
			unsigned char* imageData, 
			int width, 
			int height) {

  ofstream outfile(filename, ios::out);

  outfile << "P6" << endl;
  outfile << "# CREATOR: pgm output" << endl;
  outfile << "# AUTHOR : Andrew Nealen. University of British " 
       << "Columbia, Vancouver" << endl;
  outfile << "# FORMAT : Binary RGB ppm (P6)" << endl;
  outfile << width << " " << height << endl;
  outfile << "255" << endl;
  
  outfile.setf(ios::binary);

  int zero = 0;

  for (int i = 0; i < height; i++) {
    for (int j = 0; j < width; j++) {
      outfile << imageData[(width*i+j)*3]; 
      outfile << imageData[(width*i+j)*3+1]; 
      outfile << imageData[(width*i+j)*3+2];
    }
  }

  outfile.close();
}

void outputGreyscaleImageData(const char* filename,
			      unsigned char* imageData, 
			      int width, 
			      int height) {

  ofstream outfile(filename, ios::out);

  outfile << "P5" << endl;
  outfile << "# CREATOR: pgm output" << endl;
  outfile << "# AUTHOR : Andrew Nealen. University of British " 
       << "Columbia, Vancouver" << endl;
  outfile << "# FORMAT : Binary greyscale pgm (P5)" << endl;
  outfile << width << " " << height << endl;
  outfile << "255" << endl;

  outfile.setf(ios::binary);

  for (int i = 0; i < height; i++) {
    for (int j = 0; j < width; j++) {
	unsigned char value = imageData[i*width+j];
	outfile << value; 
    }
  }

  outfile.close();
}

void outputGreyscaleImageDataAsPPM(const char* filename,
				   unsigned char* imageData, 
				   int width, 
				   int height) {

  ofstream outfile(filename, ios::out);

  outfile << "P6" << endl;
  outfile << "# CREATOR: pgm output" << endl;
  outfile << "# AUTHOR : Andrew Nealen. University of British " 
       << "Columbia, Vancouver" << endl;
  outfile << "# FORMAT : Binary RGB ppm (P6)" << endl;
  outfile << width << " " << height << endl;
  outfile << "255" << endl;
  
  outfile.setf(ios::binary);

  for (int i = 0; i < height; i++) {
    for (int j = 0; j < width; j++) {
	unsigned char value = imageData[i*width+j];
	outfile << value; 
	outfile << value; 
	outfile << value;
    }
  }

  outfile.close();
}
