
// PBM: declarations and routines
// Version 2.10, 11.Feb.98
// (c) 1997/98 by Stefan Diener

#ifndef STIMP_PBM_INC
#define STIMP_PBM_INC

#include <STIMP/misc.c>

struct PBM_Info
{
  unsigned int height;
  unsigned int width;
  unsigned char *Data;
};

int ReadPBMFile(char *name, struct PBM_Info *info)
// read a PBM-file
{
  FILE *datei;
  char tempo[5];
  int i, j, k, zeile;
  unsigned char *src, zwisch=0;

  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,500);

  // check type
  fgets(tempo, 4, datei);
  correct(tempo);
  if (strcmp(tempo,"P4")!=0)
  {
    PrintMessage("Unknown file type: %s !",name);
    if (strcmp("-",name)!=0) fclose(datei);
    return 1;
  }

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

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

  // allocate memory for the picture
  info->Data=NULL;
  info->Data=(unsigned char *) malloc(info->height*info->width*sizeof(unsigned char));
  if (info->Data==NULL)
  {
    PrintMessage("No memory for the picture data left !");
    if (strcmp("-",name)!=0) fclose(datei);
    return 1;
  }

  // need an empty picture
  src=info->Data;
  for (i=0;i<info->width*info->height;i++) *src++=0;

  // initialize help variables
  src=info->Data;
  zeile=info->width;
  if (zeile%8) zeile=zeile-(zeile%8)+8;
  zeile=zeile/8;

  // read picture data
  for (i=0; i<info->height; i++)
  {
    for (k=0; k<zeile; k++)
    {
      j=fgetc(datei);
      if (j==EOF)
      {
        PrintMessage("Unexpected end of file !");
        i=info->height;
        k=zeile;
      }
      else
      {
        zwisch=(unsigned char) j;
        for (j=7; j>=0; j--)
        {
          // Bit==0 => white, Bit==1 => black
          if (k*8+j<info->width) src[i*info->width+k*8+j]=((zwisch%2)?0:255);
          zwisch=zwisch>>1;
        }
      }
    }
  }

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

  // ok
  return 0;
}

int WritePBMFile(char *name, struct PBM_Info *info)
// write a PBM-file
{
  FILE *datei;
  int i, j, zeile;
  unsigned char *dst, zwisch=0;

  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 (PBM, %ix%i)", name, info->width, info->height);

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

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

  // write picture data
  dst=info->Data;
  zeile=info->width;
  if (zeile%8) zeile=zeile-(zeile%8)+8;

  for (i=0; i<info->height;i++)
  {
    for (j=0; j<zeile; j++)
    {
      zwisch=(zwisch<<1);

      // white => Bit=0, black => Bit=1
      if (j<info->width) zwisch=zwisch+(dst[i*info->width+j]?0:1);

      if (j%8==7)
      {
        fputc(zwisch,datei);
        zwisch=0;
      }
    }
  }

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

  // ok
  return 0;
}

int CreatePBMArray(int y, int x, struct PBM_Info *info)
// allocate memory for a PBM-picture
{
  int i;
  unsigned char *dst;

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

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

  // need an empty picture
  dst=info->Data;
  for (i=0;i<info->width*info->height;i++) *dst++=0;

  // ok
  return 0;
}

void FreePBMArray(struct PBM_Info *info)
// free the memory of a PBM-picture
{
  free((void *) info->Data);
}

#endif
