
// PPM: declarations and routines
// Version 2.15, 08.Feb.98
// (c) 1997/98 by Stefan Diener

#ifndef STIMP_PPM_INC
#define STIMP_PPM_INC

#include <STIMP/misc.c>

#ifndef NO_PSEUDO_PPM_MODE
#ifndef NO_PSEUDO_PGM_MODE
#define NO_PSEUDO_PGM_MODE
#endif
#include <STIMP/pbm.c>
#include <STIMP/pgm.c>
#endif

const PPM_PUFFER_SIZE=5001;

struct PPM_Info
{
  unsigned int height;
  unsigned int width;
  unsigned int maxval;
  unsigned char *redData;
  unsigned char *greenData;
  unsigned char *blueData;
};

#ifndef NO_PSEUDO_PPM_MODE
int Copy_Picture(struct PPM_Info *info)
{
  int i, gesamt;
  unsigned char *srcR, *srcG, *srcB;

  gesamt=info->width*info->height;

  // allocate memory for green picture data
  info->greenData=NULL;
  info->greenData=(unsigned char *) malloc(gesamt*sizeof(unsigned char));
  if (info->greenData==NULL)
  {
    PrintMessage("No memory for green picture data left !");
    free((void *) info->redData);
    return 1;
  }

  // allocate memory for blue picture data
  info->blueData=NULL;
  info->blueData=(unsigned char *) malloc(gesamt*sizeof(unsigned char));
  if (info->blueData==NULL)
  {
    PrintMessage("No memory for blue picture data left !");
    free((void *) info->redData);
    free((void *) info->blueData);
    return 1;
  }

  // copy the red channel
  srcR=info->redData;
  srcG=info->greenData;
  srcB=info->blueData;
  for (i=0; i<gesamt; i++)
  {
     *srcG++=*srcR;
     *srcB++=*srcR++;
  }

  return 0;
}
#endif

int ReadPPMFile(char *name, struct PPM_Info *info)
// read a PPM-file
{
  FILE *datei;
  char tempo[5];
  long int i, j, elemente, gesamt, anzahl;
  unsigned char *srcR, *srcG, *srcB;
  unsigned char *Puffer, *zeiger;

  if (strcmp("-",name)==0) datei=stdin;   // use stdin
  else
  {
    // really open a file
    datei=fopen(name,"rb");
    if (datei==0)
    {
      PrintMessage("File %s not found !", name);
      return 1;
    }
  }

  // set buffer size
  setvbuf(datei,0,_IOFBF,1000);

  // check type
  fgets(tempo, 4, datei);
  correct(tempo);
  if (strcmp(tempo,"P6")!=0)
  {
    if (strcmp("-",name)==0)
    {
      PrintMessage("Unknown file type: %s !",name);
      return 1;
    }
    else
    {
#ifndef NO_PSEUDO_PPM_MODE
      int error=0;
      struct PBM_Info infoB;
      struct PGM_Info infoG;

      fclose(datei);
      switch (GetType(name))
      {
        case TYPE_PBM: error=ReadPBMFile(name, &infoB);
                                  if (!error)
                                  {
                                    info->width=infoB.width;
                                    info->height=infoB.height;
                                    info->maxval=255;
                                    info->redData=infoB.Data;
                                    error=Copy_Picture(info);
                                  }
                                  return error;
                                  break;

        case TYPE_PGM: error=ReadPGMFile(name, &infoG);
                                  if (!error)
                                  {
                                    info->width=infoG.width;
                                    info->height=infoG.height;
                                    info->maxval=infoG.maxval;
                                    info->redData=infoG.Data;
                                    error=Copy_Picture(info);
                                  }
                                  return error;
                                  break;

        default: return 1;
                     break;
      }
#else
      fclose(datei);
      PrintMessage("Unknown file type %s !",name);
      return 1;
#endif
    }
  }

  // read dimensions and maxval
  // skip comments !!!
  ReadComment(datei);
  fscanf(datei,"%i %i\n",&info->width,&info->height);
  ReadComment(datei);
  fscanf(datei,"%i\n",&info->maxval);

  // print it on the screen
  PrintMessage("Reading %s (PPM, %ix%i)", name, info->width, info->height);
  gesamt=info->width*info->height;

  // allocate memory for the read buffer
  Puffer=NULL;
  Puffer=(unsigned char *) malloc(PPM_PUFFER_SIZE*sizeof(unsigned char));
  if (Puffer==NULL)
  {
    PrintMessage("No memory for the read buffer left !");
    if (strcmp("-",name)!=0) fclose(datei);
    return 1;
  }

  // allocate memory for red picture data
  info->redData=NULL;
  info->redData=(unsigned char *) malloc(gesamt*sizeof(unsigned char));
  if (info->redData==NULL)
  {
    PrintMessage("No memory for red picture data left !");
    free((void *) Puffer);
    if (strcmp("-",name)!=0) fclose(datei);
    return 1;
  }

  // allocate memory for green picture data
  info->greenData=NULL;
  info->greenData=(unsigned char *) malloc(gesamt*sizeof(unsigned char));
  if (info->greenData==NULL)
  {
    PrintMessage("No memory for green picture data left !");
    free((void *) Puffer);
    free((void *) info->redData);
    if (strcmp("-",name)!=0) fclose(datei);
    return 1;
  }

  // allocate memory for blue picture data
  info->blueData=NULL;
  info->blueData=(unsigned char *) malloc(gesamt*sizeof(unsigned char));
  if (info->blueData==NULL)
  {
    PrintMessage("No memory for blue picture data left !");
    if (strcmp("-",name)!=0) fclose(datei);
    free((void *) Puffer);
    free((void *) info->redData);
    free((void *) info->greenData);
    return 1;
  }

  // need an empty picture
  srcR=info->redData;
  srcG=info->greenData;
  srcB=info->blueData;
  for (i=0; i<gesamt; i++)
  {
     *srcR++=0;
     *srcG++=0;
     *srcB++=0;
  }

  // get pointers
  srcR=info->redData;
  srcG=info->greenData;
  srcB=info->blueData;

  // read picture data
  i=0;
  elemente=PPM_PUFFER_SIZE/3;
  while (i<gesamt)
  {
    anzahl=gesamt-i;
    if (anzahl>elemente) anzahl=elemente;
    j=fread((void *) Puffer, sizeof(unsigned char), anzahl*3, datei);
    if (j!=anzahl*3)
    {
      i=gesamt;
      PrintMessage("Error while reading the file !");
    }
    else
    {
      i+=anzahl;
      zeiger=Puffer;
      for (j=0; j<anzahl; j++)
      {
        *srcR++=*zeiger++;
        *srcG++=*zeiger++;
        *srcB++=*zeiger++;
      }
    }
  }

  // free buffer memory
  free((void *) Puffer);

  // close file
  if (strcmp("-",name)!=0) fclose(datei);

  // ok
  return 0;
}

int WritePPMFile(char *name, struct PPM_Info *info)
// write a PPM-file
{
  FILE *datei;
  int i, j, anzahl, gesamt, elemente;
  unsigned char *dstR, *dstG, *dstB;
  unsigned char *Puffer, *zeiger;

  if (strcmp("-",name)==0) datei=stdout;   // use stdout
  else
  {
    // really open a file
    datei=fopen(name,"wb");
    if (datei==0)
    {
      PrintMessage("Could not open destination file %s !", name);
      return 1;
    }
  }

  PrintMessage("Writing %s (PPM, %ix%i)", name, info->width, info->height);

  // set buffer size
  setvbuf(datei,0,_IOFBF,1000);

  // write file header
  fprintf(datei,"P6\n");
  fprintf(datei,"# written by: "OP_NAME" "VERSION" ("DATE"), author: "AUTHOR"\n");
  fprintf(datei,"%i %i\n",info->width,info->height);
  fprintf(datei,"%i\n",info->maxval);

  // allocate memory for write buffer
  Puffer=NULL;
  Puffer=(unsigned char *) malloc(PPM_PUFFER_SIZE*sizeof(unsigned char));
  if (Puffer==NULL)
  {
    PrintMessage("No memory for write buffer left !");
    if (strcmp("-",name)!=0) fclose(datei);
    return 1;
  }

  // write picture data
  i=0;
  elemente=PPM_PUFFER_SIZE/3;
  gesamt=info->width*info->height;
  dstR=info->redData;
  dstG=info->greenData;
  dstB=info->blueData;

  while (i<gesamt)
  {
    anzahl=gesamt-i;
    if (anzahl>elemente) anzahl=elemente;
    zeiger=Puffer;
    for (j=0; j<anzahl; j++)
    {
      *zeiger++=*dstR++;
      *zeiger++=*dstG++;
      *zeiger++=*dstB++;
    }

    j=fwrite((void *) Puffer, sizeof(unsigned char), anzahl*3, datei);
    if (j!=anzahl*3)
    {
      i=gesamt;
      PrintMessage("Error while writing the file !");
    }
    else i+=anzahl;
  }

  // flush buffer and close file
  fflush(datei);
  if (strcmp("-",name)!=0) fclose(datei);

  // free buffer memory
  free((void *) Puffer);

  // ok
  return 0;
}

int CreatePPMArray(int y, int x, struct PPM_Info *info)
// allocate memory for a PPM-picture
{
  int i;
  unsigned char *dstR, *dstG, *dstB;

  // save dimensions and maxval
  info->width=x;
  info->height=y;
  info->maxval=255;

  // allocate memory for red picture data
  info->redData=NULL;
  info->redData=(unsigned char *) malloc(x*y*sizeof(unsigned char));
  if (info->redData==NULL)
  {
    PrintMessage("No memory for red picture data left !");
    return 1;
  }

  // allocate memory for green picture data
  info->greenData=NULL;
  info->greenData=(unsigned char *) malloc(x*y*sizeof(unsigned char));
  if (info->greenData==NULL)
  {
    PrintMessage("No memory for green picture data left !");
    free((void *) info->redData);
    return 1;
  }

  // allocate memory for blue picture data
  info->blueData=NULL;
  info->blueData=(unsigned char *) malloc(x*y*sizeof(unsigned char));
  if (info->blueData==NULL)
  {
    PrintMessage("No memory for blue picture data left !");
    free((void *) info->redData);
    free((void *) info->greenData);
    return 1;
  }

  // need an empty picture
  dstR=info->redData;
  dstG=info->greenData;
  dstB=info->blueData;
  for (i=0;i<info->width*info->height;i++)
  {
     *dstR++=0;
     *dstG++=0;
     *dstB++=0;
  }

  // ok
  return 0;
}

void FreePPMArray(struct PPM_Info *info)
// free the memory of a PPM-picture
{
  free((void *) info->redData);
  free((void *) info->greenData);
  free((void *) info->blueData);
}

#endif
