#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <limits.h>

#include "labImage.h"
#include "labScale.h"

#define    MAGICSIZE    3

/**********************************************************************/

Picture *allocImage()
{
  return (Picture *)malloc(sizeof(Picture));
}

/**********************************************************************/

Picture *initImage(Picture *image)
{
  if (image)
  {
    image->width  = 0;
    image->height = 0;
    image->xoffset= 0;
    image->datasize=0;
    image->format = pix_unknown;
    image->data   = NULL;
    image->bytes_per_line=0;
    image->bytes_per_pixel=0;
    image->obformat=0;
    image->obdata=NULL;
    image->flags=0;
  }
  return image;
}

/**********************************************************************/

Picture *newImage()
{
  return initImage(allocImage());
}

/**********************************************************************/

void freeImage(Picture *image)
{
  if (image)
  {
    resizeImage(image, 0, 0);
    free(image);
  }
}

/**********************************************************************/

void clearImage(Picture *image)
{
  if (image)
    {
      switch (image->format)
	{
	case pix_grey  : 
	  memset( image->data, '\0',   image->width*image->height);
	  break;
	
	case pix_rgb24   :
	  memset( image->data, '\0',   3*image->width*image->height);
	  break;
	
	default   : 
	  break;
	}
    }
}

void clearImage_white(Picture *image)
{
  if (image)
    {
      memset( image->data, (unsigned char) 250 ,   image->datasize);
    }
}

/**********************************************************************/

void setImageType(Picture *image, pixel_format type)
{
  image->format=type;
}

/**********************************************************************/

int resizeImage(Picture *image, unsigned int width, unsigned int height)
{
  int     mydepth=0;   /*Number of Bytes per Pixel                    */
  unsigned char *pad;
  
  if (image && image->format!=pix_unknown)
  {
    switch (image->format)
    {
    case pix_grey   : mydepth = 1; break;
    case pix_rgb24  : mydepth = 3; break;
      
    default          :   mydepth = 0; break;
    }
    if ((width>0) && (height>0) && (mydepth>0))
      {
      image->width  = width;
      image->height = height;
      image->datasize=width*height*mydepth;
      image->bytes_per_line=width*mydepth;
      image->bytes_per_pixel=mydepth;
      
      if (image->data)
	{
	  //free(image->data);
	  //pad = (unsigned char *)malloc(image->datasize+31);
	  //image->data=(unsigned char *) ((((unsigned int) pad)+31) & (~31));
	  image->data=(unsigned char *)realloc(image->data, image->datasize);
	}      
      else
	{//Padding the data
	  //pad = (unsigned char *)malloc(image->datasize+31);
	  //image->data=(unsigned char *) ((((unsigned int) pad)+31) & (~31));
	  image->data=(unsigned char *)malloc(image->datasize);
	}
      
      if (!(image->data))
	{
	  image->width  = 0;
	  image->height = 0;
	  return(0);
	}
      return(1);
      }
    else
      {
	image->width           = 0;
	image->height          = 0;
	image->format          = pix_unknown;
	image->datasize        = 0;
	image->bytes_per_line  = 0;
	image->bytes_per_pixel = 0;
	
	if (image->data)
	  { 
	    free(image->data);
	  }
	image->data = NULL;
      }      
  }
  return(0);
}

/**********************************************************************/
int loadImage(char *fileN, Picture *image)
{
  int            status = 0;      /*Returnvalue, Number of Pixels read*/
  FILE          *file;            /*Inputfile                         */
  char           magicBuf[MAGICSIZE+1];/*Buffer for the P2,P3,P5,P6   */
  unsigned int   w, h;            /*widht and height of the Image     */
  char           ch;              /*Dummy for finding the \n in a Line*/
  unsigned int   ii;              /*Countervariable                   */
  int            zwint;           /*dummy-integer for loading P2 Files*/
  int            maxsize;         /*Maximum Grayvalue (for P2-Files)  */
  unsigned char *p_uchardata;     /*Datapointer for the Image         */
  short         *p_shortdata;     /*Datapointer for the Image         */
  
  file = fopen(fileN, "rb");
  if (!file) return(status);
  
  /*Fetch Magic Number*/
  ii = fread(magicBuf, sizeof(char), MAGICSIZE, file);
  rewind(file);
  if (ii != MAGICSIZE) ii = 0; 
  *(magicBuf+ii) = '\0'; /*null-terminating character*/
  
  if (strncmp(magicBuf, "P5", 2)==0)
    {
      do /*Read Comment Lines*/
	{ 
	  do 
	    fread(&ch, sizeof(char), 1, file); 
	  while (ch!='\n');
	  fread(&ch, sizeof(char), 1, file);
	} while (ch=='#');
      
      fseek(file, -1L, 1); /*reset last read Non-Hash*/
      
      fscanf(file, "%d %d\n", &w, &h);
      fscanf(file, "%d", &maxsize);
      do 
	fread(&ch, sizeof(char), 1, file); 
      while (ch!='\n');
      setImageType(image, pix_grey);
      resizeImage(image, w, h);
      
      status+=fread(image->data, image->width*image->height, 1, file);
    }
  
  else if (strncmp(magicBuf, "P2", 2)==0)
    {
      do/*Read Comment Lines*/
	{ 
	  do 
	    fread(&ch, sizeof(char), 1, file); 
	  while (ch!='\n');
	  fread(&ch, sizeof(char), 1, file);
	} while (ch=='#');
      
      fseek(file, -1L, 1); /*reset last read Non-Hash*/
      
      fscanf(file, "%d %d\n", &w, &h);
      fscanf(file, "%d", &maxsize);
      do fread(&ch, sizeof(char), 1, file); while (ch!='\n');
      if(maxsize < 256)
	{
	  setImageType(image, pix_grey);
	  resizeImage(image, w, h);
	  p_uchardata = (unsigned char *)image->data;
	  for(ii = 0; ii < image->width*image->height; ii++)
	    {
	      status += fscanf(file, "%d", &zwint);
	      *p_uchardata++ = (unsigned char)zwint;
	    }
	}
      else
	{
	  status=0;
	}
      
    }
  
  else if (strncmp(magicBuf, "P3", 2)==0)
    {
      do/*Read Comment Lines*/
	{ 
	  do 
	    fread(&ch, sizeof(char), 1, file); 
	  while (ch!='\n');
	  fread(&ch, sizeof(char), 1, file);
	} while (ch=='#');
      
      fseek(file, -1L, 1); /*reset last read Non-Hash*/
      
      fscanf(file, "%d %d\n", &w, &h);
      fscanf(file, "%d", &maxsize);
      do fread(&ch, sizeof(char), 1, file); while (ch!='\n');
      if(maxsize < 256)
	{
	  setImageType(image, pix_rgb24);
	  resizeImage(image, w, h);
	  p_uchardata = (unsigned char *)image->data;
	  for(ii = 0; ii < 3*image->width*image->height; ii++)
	    {
	      status += fscanf(file, "%d", &zwint);
	      *p_uchardata++ = (unsigned char)zwint;
	    }
	}
      else
	{
	  setImageType(image, pix_rgb24);
	  resizeImage(image, w, h);
	  p_uchardata = (unsigned char *)image->data;
	  for(ii = 0; ii < 3*image->width*image->height; ii++)
	    {
	      status += fscanf(file, "%d", &zwint);
	      if(zwint < 0)        *p_uchardata++ = 0;
	      else if(zwint > 255) *p_uchardata++ = 255;
	      else                 *p_uchardata++ = (unsigned char)zwint;
	    }
	}
    }
  
  else if (strncmp(magicBuf, "P6", 2)==0)
    {
      unsigned int    w, h;
      char        ch;
      
      do/*Read Comment Lines*/
	{ 
	  do 
	    fread(&ch, sizeof(char), 1, file); 
	  while (ch!='\n');
	  fread(&ch, sizeof(char), 1, file);
	} while (ch=='#');
      
      fseek(file, -1L, 1);/*reset last read Non-Hash*/
      
      fscanf(file, "%d %d\n", &w, &h);
      fscanf(file, "%d", &maxsize);
      do 
	fread(&ch, sizeof(char), 1, file); 
      while (ch!='\n');
      setImageType(image, pix_rgb24);
      resizeImage(image, w, h);
      
      status+=fread(image->data, 3*image->width*image->height, 1, file);
    }
  else /* unknown format */
    {
      status=0;
    }
  
  fclose(file);
  return(status);
}

/**************************************************************/
int loadImage_Info(char *fileN, Picture *image)
{
  int            status = 0;      /*Returnvalue, Number of Pixels read*/
  FILE          *file;            /*Inputfile                         */
  char           magicBuf[MAGICSIZE+1];/*Buffer for the P2,P3,P5,P6   */
  unsigned int   w, h;            /*widht and height of the Image     */
  char           ch;              /*Dummy for finding the \n in a Line*/
  unsigned int   ii;              /*Countervariable                   */
  int            zwint;           /*dummy-integer for loading P2 Files*/
  int            maxsize;         /*Maximum Grayvalue (for P2-Files)  */
  unsigned char *p_uchardata;     /*Datapointer for the Image         */
  short         *p_shortdata;     /*Datapointer for the Image         */
  
  file = fopen(fileN, "rb");
  if (!file) return(status);
  
  /*Fetch Magic Number*/
  ii = fread(magicBuf, sizeof(char), MAGICSIZE, file);
  rewind(file);
  if (ii != MAGICSIZE) ii = 0; 
  *(magicBuf+ii) = '\0'; /*null-terminating character*/
  
  if (strncmp(magicBuf, "P5", 2)==0)
    {
      do /*Read Comment Lines*/
	{ 
	  do 
	    fread(&ch, sizeof(char), 1, file); 
	  while (ch!='\n');
	  fread(&ch, sizeof(char), 1, file);
	} while (ch=='#');
      
      fseek(file, -1L, 1); /*reset last read Non-Hash*/
      
      fscanf(file, "%d %d\n", &w, &h);
      fscanf(file, "%d", &maxsize);
      do 
	fread(&ch, sizeof(char), 1, file); 
      while (ch!='\n');
      setImageType(image, pix_grey);
      resizeImage(image, w, h);
      
      //status+=fread(image->data, image->width*image->height, 1, file);
    }
  else if (strncmp(magicBuf, "P2", 2)==0)
    {
      do/*Read Comment Lines*/
      { 
	do 
	  fread(&ch, sizeof(char), 1, file); 
	while (ch!='\n');
	fread(&ch, sizeof(char), 1, file);
      } while (ch=='#');
      
      fseek(file, -1L, 1); /*reset last read Non-Hash*/
      
      fscanf(file, "%d %d\n", &w, &h);
      fscanf(file, "%d", &maxsize);
      do fread(&ch, sizeof(char), 1, file); while (ch!='\n');
      if(maxsize < 256)
      {
	setImageType(image, pix_grey);
	resizeImage(image, w, h);
	
      }
      else
	{
	  status=0;             
	}
    }
  
  else if (strncmp(magicBuf, "P3", 2)==0)
    {
      do/*Read Comment Lines*/
	{ 
	  do 
	    fread(&ch, sizeof(char), 1, file); 
	  while (ch!='\n');
	  fread(&ch, sizeof(char), 1, file);
	} while (ch=='#');
      
      fseek(file, -1L, 1); /*reset last read Non-Hash*/
      
      fscanf(file, "%d %d\n", &w, &h);
      fscanf(file, "%d", &maxsize);
      do fread(&ch, sizeof(char), 1, file); while (ch!='\n');
      if(maxsize < 256)
	{
	  setImageType(image, pix_rgb24);
	resizeImage(image, w, h);
	}
      else
	{
	  setImageType(image, pix_rgb24);
	  resizeImage(image, w, h);
	  p_uchardata = (unsigned char *)image->data;
	}
    }
  else if (strncmp(magicBuf, "P6", 2)==0)
    {
      unsigned int    w, h;
      char        ch;
      
      do/*Read Comment Lines*/
	{ 
	  do 
	    fread(&ch, sizeof(char), 1, file); 
	  while (ch!='\n');
	  fread(&ch, sizeof(char), 1, file);
	} while (ch=='#');
      
      fseek(file, -1L, 1);/*reset last read Non-Hash*/
      
      fscanf(file, "%d %d\n", &w, &h);
      fscanf(file, "%d", &maxsize);
      do 
	fread(&ch, sizeof(char), 1, file); 
      while (ch!='\n');
      
      setImageType(image, pix_rgb24);
      resizeImage(image, w, h);
    }
  else /* unknown format */
    {
      status=0;
    }
  
  fclose(file);
  
  return 1;
}
/******************/

void saveImage2(char *p_outname, Picture *image, char *p_comment)
{
  unsigned char *p_d;    /*Datapointer                                */
  unsigned char  nn;     /*Auxiliary for printing 0 to File           */
  unsigned int   ii;     /*Countervariable                            */
  short         *p_s;    /*Datapointer for Shortimage                 */
  char        *p_fileN;/*Filename for saving 4 Filesin Long-Image   */
  FILE        *file;   /*Outputfile                                 */
  
  file = NULL;
  if ((image)&&(p_outname))
  {
    switch (image->format)
      {
      case pix_grey :
	{
	  if(!(file=fopen(p_outname, "wb")))
	    {
	      fprintf(stderr, "Unable to open %s\n", p_outname);
	      fflush(stderr);
	    }
	  else
	    {
	      if(p_comment[strlen(p_comment)-1] == '\n')
		{
		  fprintf(file, "P5\n#%s%d %d\n%d\n",
			  p_comment, image->width, image->height, 255);
		}
	      else
		{
		  fprintf(file, "P5\n#%s\n%d %d\n%d\n",
			  p_comment, image->width, image->height, 255);
		}
	      fwrite(image->data, image->width*image->height, 1, file);
	      fclose(file);
	    }
	} break;
      
      case pix_rgb24    :
	{
	  if(!(file=fopen(p_outname, "wb")))
	    {
	      fprintf(stderr, "Unable to open %s\n", p_outname);
	      fflush(stderr);
	    }
        else
	  {
	    if(p_comment[strlen(p_comment)-1] == '\n')
	      {
		fprintf(file, "P6\n#%s%d %d\n%d\n",
			p_comment, image->width, image->height, 255);
	      }
	    else
	      {
		fprintf(file, "P6\n#%s\n%d %d\n%d\n",
			p_comment, image->width, image->height, 255);
	      }
	    fwrite(image->data,image->width*image->height, 3, file);
	    fclose(file);
	  }
	} break;
	
      default    : break;
    }
  }
}

/**********************************************************************/

void saveImage(char *p_outname, Picture *image)
{
  saveImage2(p_outname, image, "No Comment");
}

/**********************************************************************/

void saveImage2_Ascii(char *p_outname, Picture *image, char *p_comment)
{
  unsigned char *p_d;       /*Image-Data-Pointer                      */
  unsigned int   ii, jj;    /*Countervariables                        */
  short         *p_s;       /*Image-Data-Pointer                      */
  char          *p_fileN;   /*Filename for different P5-Files produced*/
                            /* by Long-Image                          */
  FILE          *file;      /*Outputfile                              */

  file = NULL;
  if ((image)&&(p_outname))
  {
    switch (image->format)
    {
      case pix_grey :
      {
        unsigned char *p_data;
        if(!(file=fopen(p_outname, "wb")))
        {
          fprintf(stderr, "Unable to open %s\n", p_outname);
          fflush(stderr);
        }
        else
        {
          if(p_comment[strlen(p_comment)-1] == '\n')
          {
            fprintf(file, "P2\n#%s%d %d\n%d\n",
                 p_comment, image->width, image->height, 255);
          }
          else
          {
            fprintf(file, "P2\n#%s\n%d %d\n%d\n",
              p_comment, image->width, image->height, 255);
          }
          p_data = (unsigned char *)(image->data);
          for(ii = 0; ii < image->height; ii++)
          {
            for(jj = 0; jj < image->width; jj++)
            {
              fprintf(file, "%d ", *p_data++);
            }
            fprintf(file, "\n");
          }
          fclose(file);
        }
      }
      break;
      
    case pix_rgb24    :
      {
        unsigned char *p_data;
        if(!(file=fopen(p_outname, "wb")))
        {
          fprintf(stderr, "Unable to open %s\n", p_outname);
          fflush(stderr);
        }
        else
        {
          if(p_comment[strlen(p_comment)-1] == '\n')
          {
            fprintf(file, "P3\n#%s%d %d\n%d\n",
                p_comment, image->width, image->height, 255);
          }
          else
          {
            fprintf(file, "P3\n#%s\n%d %d\n%d\n",
                  p_comment, image->width, image->height, 255);
          }
          p_data = (unsigned char *)(image->data);
          for(ii = 0; ii < image->height; ii++)
          {
            for(jj = 0; jj < 3*image->width; jj++)
            {
              fprintf(file, "%d ", *p_data++);
            }
            fprintf(file, "\n");
          }
          fclose(file);
        }
      }
      break;
     
      default    : 
      break;
    }
  }
}

/**********************************************************************/

void saveImage_Ascii(char *LbaseN, Picture *image)
{
  saveImage2_Ascii(LbaseN, image, "No Comment");
}

/**********************************************************************/
/**********************************************************************/
/**********************************************************************/

Picture *copyImage(Picture *image)
{
  Picture    *p_copy=NULL;   /*Copy of the Inputimage, Returnvalue      */
  
  if (image)
  {
    if(!(p_copy=newImage()))
      {
	//fprintf(stderr,"Could not initialise new image!\n"); 
	return(NULL);
      }
    p_copy->format=image->format;
    
    if(!resizeImage(p_copy, image->width, image->height)) 
      {
	free(p_copy);
	//fprintf(stderr,"Could not allocated memory for new image!\n");
	return(NULL);
      }
    switch (image->format)
    {
    case pix_grey : 
	memcpy(p_copy->data,image->data,  image->width*image->height);
	break;
	
    case pix_rgb24  :  
      memcpy(p_copy->data, image->data,3*image->width*image->height);
      break;
      
    default   : 
      break;
    }
  }
  return p_copy;
}

Picture *copyImage_cover(Picture *image)
{
  Picture    *p_copy=NULL;   /*Copy of the Inputimage, Returnvalue      */
  
  if (image)
  {
    if(!(p_copy=newImage())) 
      return(NULL);
    
    p_copy->format=image->format;
    
    if(!resizeImage(p_copy, image->width, image->height)) 
      {
	free(p_copy);
	return(NULL);
    }
   
  }
  return p_copy;
}

/**********************************************************************/

Picture *cropImage(Picture *image, int sx, int sy, unsigned int width, 
                                                   unsigned int height)
{ 
  Picture          *p_crop=NULL;      /*Image to be returned            */
  unsigned int   x, y;             /*countervariables                 */
  unsigned char  *p_l, *p_p, *p_q; /*Auxiliary-Datapointer            */
  int            len = 0;          /*Size of one Pixel                */
  
  if (image)
  {    
    switch (image->format)
      {
      case pix_grey : len = 1; break;
      case pix_rgb24  : len = 3; break;
      default     : return(NULL); 
      }  
    if(!(p_crop = newImage())) return(NULL);
    p_crop->format = image->format;
    if(!(resizeImage( p_crop, width, height )))
    {
      free(p_crop);
      return(NULL);
    }
    p_q = (unsigned char *)p_crop->data;
    p_l = ((unsigned char *)(image->data)+  len*(sy*image->width+sx));
    for (y = 0; y < height; y++)
    {
      p_p = p_l;
      for (x = 0; x < len * width; x++)
      {
        *p_q++ = *p_p++;
      }
      p_l += len * image->width;
    }
  }  
    
  return p_crop;
}

/**********************************************************************/
 
Picture *MONO2RGB(Picture *p_image)
{
  unsigned char  *p_u, *p_c;  /*Pointer to Mono and RGB-Data          */
  unsigned int    ii;         /*countervariable                       */
    
  if (p_image->format == pix_grey)
  {
    if((p_c = (unsigned char *)malloc(3 * p_image->width * 
               p_image->height * sizeof(unsigned char))))
    {
      p_u = (unsigned char *)(p_image->data);
 
      for (ii = 0; ii < p_image->height * p_image->width; ii++)
      {
        *p_c++ = *p_u;   /*R*/
        *p_c++ = *p_u;   /*G*/
        *p_c++ = *p_u++; /*B*/     
      }
 
      free(p_image->data);
      p_image->data = (unsigned char *)(p_c - (3*p_image->width*p_image->height));
      p_image->datasize*=3; 
      p_image->bytes_per_line*=3;
      
      p_image->bytes_per_pixel=3;
      p_image->format= pix_rgb24;
    }    
  }
  return p_image;
}

/**********************************************************************/
/*Multiplikatortables containing 256 * 0.299 * red                    */
/*                               256 * 0.587 * green                  */
/*                               256 * 0.114 * blue                   */
/**********************************************************************/

  static int red_mult[256] = {
        0,    77,   154,   231,   308,   385,   462,   539,
      616,   693,   770,   847,   924,  1001,  1078,  1155,
     1232,  1309,  1386,  1463,  1540,  1617,  1694,  1771,
     1848,  1925,  2002,  2079,  2156,  2233,  2310,  2387,
     2464,  2541,  2618,  2695,  2772,  2849,  2926,  3003,
     3080,  3157,  3234,  3311,  3388,  3465,  3542,  3619,
     3696,  3773,  3850,  3927,  4004,  4081,  4158,  4235,
     4312,  4389,  4466,  4543,  4620,  4697,  4774,  4851,
     4928,  5005,  5082,  5159,  5236,  5313,  5390,  5467,
     5544,  5621,  5698,  5775,  5852,  5929,  6006,  6083,
     6160,  6237,  6314,  6391,  6468,  6545,  6622,  6699,
     6776,  6853,  6930,  7007,  7084,  7161,  7238,  7315,
     7392,  7469,  7546,  7623,  7700,  7777,  7854,  7931,
     8008,  8085,  8162,  8239,  8316,  8393,  8470,  8547,
     8624,  8701,  8778,  8855,  8932,  9009,  9086,  9163,
     9240,  9317,  9394,  9471,  9548,  9625,  9702,  9779,
     9856,  9933, 10010, 10087, 10164, 10241, 10318, 10395,
    10472, 10549, 10626, 10703, 10780, 10857, 10934, 11011,
    11088, 11165, 11242, 11319, 11396, 11473, 11550, 11627,
    11704, 11781, 11858, 11935, 12012, 12089, 12166, 12243,
    12320, 12397, 12474, 12551, 12628, 12705, 12782, 12859,
    12936, 13013, 13090, 13167, 13244, 13321, 13398, 13475,
    13552, 13629, 13706, 13783, 13860, 13937, 14014, 14091,
    14168, 14245, 14322, 14399, 14476, 14553, 14630, 14707,
    14784, 14861, 14938, 15015, 15092, 15169, 15246, 15323,
    15400, 15477, 15554, 15631, 15708, 15785, 15862, 15939,
    16016, 16093, 16170, 16247, 16324, 16401, 16478, 16555,
    16632, 16709, 16786, 16863, 16940, 17017, 17094, 17171,
    17248, 17325, 17402, 17479, 17556, 17633, 17710, 17787,
    17864, 17941, 18018, 18095, 18172, 18249, 18326, 18403,
    18480, 18557, 18634, 18711, 18788, 18865, 18942, 19019,
    19096, 19173, 19250, 19327, 19404, 19481, 19558, 19635 };
 
  static int green_mult[256] = {
        0,   150,   300,   450,   600,   750,   900,  1050,
     1200,  1350,  1500,  1650,  1800,  1950,  2100,  2250,
     2400,  2550,  2700,  2850,  3000,  3150,  3300,  3450,
     3600,  3750,  3900,  4050,  4200,  4350,  4500,  4650,
     4800,  4950,  5100,  5250,  5400,  5550,  5700,  5850,
     6000,  6150,  6300,  6450,  6600,  6750,  6900,  7050,
     7200,  7350,  7500,  7650,  7800,  7950,  8100,  8250,
     8400,  8550,  8700,  8850,  9000,  9150,  9300,  9450,
     9600,  9750,  9900, 10050, 10200, 10350, 10500, 10650,
    10800, 10950, 11100, 11250, 11400, 11550, 11700, 11850,
    12000, 12150, 12300, 12450, 12600, 12750, 12900, 13050,
    13200, 13350, 13500, 13650, 13800, 13950, 14100, 14250,
    14400, 14550, 14700, 14850, 15000, 15150, 15300, 15450,
    15600, 15750, 15900, 16050, 16200, 16350, 16500, 16650,
    16800, 16950, 17100, 17250, 17400, 17550, 17700, 17850,
    18000, 18150, 18300, 18450, 18600, 18750, 18900, 19050,
    19200, 19350, 19500, 19650, 19800, 19950, 20100, 20250,
    20400, 20550, 20700, 20850, 21000, 21150, 21300, 21450,
    21600, 21750, 21900, 22050, 22200, 22350, 22500, 22650,
    22800, 22950, 23100, 23250, 23400, 23550, 23700, 23850,
    24000, 24150, 24300, 24450, 24600, 24750, 24900, 25050,
    25200, 25350, 25500, 25650, 25800, 25950, 26100, 26250,
    26400, 26550, 26700, 26850, 27000, 27150, 27300, 27450,
    27600, 27750, 27900, 28050, 28200, 28350, 28500, 28650,
    28800, 28950, 29100, 29250, 29400, 29550, 29700, 29850,
    30000, 30150, 30300, 30450, 30600, 30750, 30900, 31050,
    31200, 31350, 31500, 31650, 31800, 31950, 32100, 32250,
    32400, 32550, 32700, 32850, 33000, 33150, 33300, 33450,
    33600, 33750, 33900, 34050, 34200, 34350, 34500, 34650,
    34800, 34950, 35100, 35250, 35400, 35550, 35700, 35850,
    36000, 36150, 36300, 36450, 36600, 36750, 36900, 37050,
    37200, 37350, 37500, 37650, 37800, 37950, 38100, 38250 };
    
  static int blue_mult[256] = {
        0,    29,    58,    87,   116,   145,   174,   203,
      232,   261,   290,   319,   348,   377,   406,   435,
      464,   493,   522,   551,   580,   609,   638,   667,
      696,   725,   754,   783,   812,   841,   870,   899,
      928,   957,   986,  1015,  1044,  1073,  1102,  1131,
     1160,  1189,  1218,  1247,  1276,  1305,  1334,  1363,
     1392,  1421,  1450,  1479,  1508,  1537,  1566,  1595,
     1624,  1653,  1682,  1711,  1740,  1769,  1798,  1827,
     1856,  1885,  1914,  1943,  1972,  2001,  2030,  2059,
     2088,  2117,  2146,  2175,  2204,  2233,  2262,  2291,
     2320,  2349,  2378,  2407,  2436,  2465,  2494,  2523,
     2552,  2581,  2610,  2639,  2668,  2697,  2726,  2755,
     2784,  2813,  2842,  2871,  2900,  2929,  2958,  2987,
     3016,  3045,  3074,  3103,  3132,  3161,  3190,  3219,
     3248,  3277,  3306,  3335,  3364,  3393,  3422,  3451,
     3480,  3509,  3538,  3567,  3596,  3625,  3654,  3683,
     3712,  3741,  3770,  3799,  3828,  3857,  3886,  3915,
     3944,  3973,  4002,  4031,  4060,  4089,  4118,  4147,
     4176,  4205,  4234,  4263,  4292,  4321,  4350,  4379,
     4408,  4437,  4466,  4495,  4524,  4553,  4582,  4611,
     4640,  4669,  4698,  4727,  4756,  4785,  4814,  4843,
     4872,  4901,  4930,  4959,  4988,  5017,  5046,  5075,
     5104,  5133,  5162,  5191,  5220,  5249,  5278,  5307,
     5336,  5365,  5394,  5423,  5452,  5481,  5510,  5539,
     5568,  5597,  5626,  5655,  5684,  5713,  5742,  5771,
     5800,  5829,  5858,  5887,  5916,  5945,  5974,  6003,
     6032,  6061,  6090,  6119,  6148,  6177,  6206,  6235,
     6264,  6293,  6322,  6351,  6380,  6409,  6438,  6467,
     6496,  6525,  6554,  6583,  6612,  6641,  6670,  6699,
     6728,  6757,  6786,  6815,  6844,  6873,  6902,  6931,
     6960,  6989,  7018,  7047,  7076,  7105,  7134,  7163,
     7192,  7221,  7250,  7279,  7308,  7337,  7366,  7395 };

/**********************************************************************/

Picture *RGB2MONO(Picture *p_rgbimage, Picture *p_grayimage, int mode)
{
  int           ii;              /*countervariable                    */
  int           imagesize;       /*imagewidth*imageheight             */
  unsigned char *p_rgb, *p_gray; /*RGB and Grayvalue Data of the Image*/
 
  /*---mode1-gray = 0.299 * red + 0.587 * green + 0.114 * blue--------*/
  /*---mode0-gray = 0.333 * red + 0.333 * green + 0.333 * blue--------*/
 
  if(!p_rgbimage || !p_grayimage) 
  {
    if(p_grayimage) freeImage(p_grayimage);
    return(NULL);
  }
  if((p_rgbimage->format != pix_rgb24) ||(p_grayimage->format != pix_grey) ) 
    {
      freeImage(p_grayimage);
      return(NULL);
    }
  
  /*Resize MONO Image*/
  if((p_grayimage->width != p_rgbimage->width) || 
                       (p_grayimage->height != p_rgbimage->height))
  {
    if(!(resizeImage(p_grayimage,p_rgbimage->width,p_rgbimage->height)))
    {
      freeImage(p_grayimage); 
      return(NULL);
    }
  }
  
  p_rgb  = (unsigned char *)p_rgbimage->data;
  p_gray = (unsigned char *)p_grayimage->data;
  imagesize = p_rgbimage->width * p_rgbimage->height;
      
  if(mode)
  {
    /*Tablevalues are Multiplikators times 256, thus >>8*/
    for(ii = 0; ii < imagesize; ii++)
      *p_gray++ = (unsigned char)(((*(red_mult + *p_rgb++) + 
	                                  *(green_mult + *p_rgb++) + 
                                          *(blue_mult + *p_rgb++))>>8));
  }
  else
  {
    for(ii = 0; ii < imagesize; ii++)
      *p_gray++ = (unsigned char)((*p_rgb++ + *p_rgb++ + *p_rgb++)/3);
  }
  
  p_rgbimage->format=pix_grey;
  p_rgbimage->datasize=p_grayimage->datasize;
  p_rgbimage->bytes_per_line= p_grayimage->bytes_per_line;
  p_rgbimage->bytes_per_pixel= p_grayimage->bytes_per_pixel;
  
  p_rgbimage->data=(unsigned char *)realloc(p_rgbimage->data, p_rgbimage->datasize);
  memcpy(p_rgbimage->data, p_grayimage->data,p_grayimage->datasize);

  return(p_rgbimage);
}

/**********************************************************************/

int scaleImage(Picture *image, unsigned int width, unsigned int height)
{
  unsigned char *data;  /*Imagedata                                   */
  
  if (!width || !height || !image)                     return(0);
  if (!image->width || !image->height || !image->data) return(0);
  
  switch (image->format)
  {
    case pix_grey :
    {
      if(!(data=(unsigned char *)malloc(width*height))) return(0);

      scaleMONO_int((unsigned char *)(image->data), 
                    image->width, image->height, 0, 0, 
                    image->width, image->height, data, width, height);

      free(image->data);
      image->data   = (unsigned char *)data;
      image->width  = width;
      image->height = height;
      image->bytes_per_line=width; 
      image->datasize=width*height;

      return(1);
    }
    case pix_rgb24  :
    {
      if(!(data=(unsigned char *)malloc(3*width*height))) return(0);
      
      scaleRGB_int((unsigned char *)(image->data), 
                    image->width, image->height, 0, 0, 
            image->width, image->height, data, width, height);

      free(image->data);
      image->data   = (unsigned char*)data;
      image->width  = width;
      image->height = height;
      image->bytes_per_line=width*3; 
      image->datasize=width*height*3;
      return(1);
    }
    
    default   : 
      fprintf(stderr,"Scale Image: Not implemented for Type %d!\n", 
                                                        image->format);
      break;
  }
  return(0);
}

/**********************************************************************/

int subscaleImagexycrop(Picture *p_image, int startx, int starty, 
            int width, int height, int samplefactorx, int samplefactory)
{
  int            newx, newy; /*new widht and height                   */
  unsigned char *p_newdata;  /*new Datapointer replacing p_image->data*/
  
  if(!p_image) return(0);
  if(!samplefactorx || !samplefactory)   return(0);
  if((width < 1)  || (height < 1))       return(0);
  if((startx < 0) || (starty < 0))       return(0);
  if((startx+width)  > (int)p_image->width )  return(0);
  if((starty+height) > (int)p_image->height)  return(0);
  
  if(samplefactorx > 0) 
  {
    newx = width  / samplefactorx;
   if(width  % samplefactorx)  newx += 1;
  }
  else newx = -1 * width * samplefactorx;
  if(samplefactory > 0)
  {
    newy = height / samplefactory;
    if(height % samplefactory)  newy += 1;
  }
  else newy = -1 * height * samplefactory;
  
  
  
  if(p_image->format == pix_grey)
  {
    if(!(p_newdata = (unsigned char *)
           malloc(newx * newy * sizeof(unsigned char)))) 
    return(0);
    if(!subsample_mono((unsigned char *)p_image->data, p_image->width, 
              p_image->height, startx, starty, width, height,
              p_newdata, samplefactorx, samplefactory))
    {
      return(0);
    }
  }
  else if(p_image->format == pix_rgb24)
  {
    if(!(p_newdata = (unsigned char *)
           malloc(3*newx * newy * sizeof(unsigned char)))) 
    return(0);
    if(!subsample_rgb((unsigned char *)p_image->data, p_image->width, 
              p_image->height, startx, starty, width, height,
              p_newdata, samplefactorx, samplefactory))
    {
      return(0);
    }
   
  }
  else 
  {
    fprintf(stderr, "subscaleImagexycrop not implemented for Type ");
    fprintf(stderr, "%d yet\n", p_image->format);
    return(0);
  }
  free(p_image->data);
  p_image->data   = p_newdata;
  p_image->width  = newx;
  p_image->height = newy;
  return(1);
}

/**********************************************************************/

int subscaleImage(Picture *p_image, int samplefactor)
{
  int            newx, newy; /*new widht and height                   */
  unsigned char *p_newdata;  /*new Datapointer replacing p_image->data*/
  
  if(!p_image)        return(0);
  if(!samplefactor)   return(0);
  
  if(samplefactor > 0) 
  {
    newx = p_image->width  / samplefactor;
    if(p_image->width  % samplefactor)  newx += 1;
    newy = p_image->height / samplefactor;
    if(p_image->height % samplefactor)  newy += 1;
  }
  else
  {
    newx = -1 * p_image->width  * samplefactor;
    newy = -1 * p_image->height * samplefactor;
  }
  
  
  if(p_image->format == pix_grey)
  {
    if(!(p_newdata = (unsigned char *)
           malloc(newx * newy * sizeof(unsigned char)))) 
    return(0);
    if(!subsample_mono((unsigned char *)p_image->data, p_image->width, 
		       p_image->height, 0, 0, p_image->width, p_image->height,
		       p_newdata, samplefactor, samplefactor))
      {
      return(0);
    }
    p_image->bytes_per_line=newx;
  }
  else if(p_image->format == pix_rgb24)
  {
    if(!(p_newdata = (unsigned char *)
           malloc(3*newx * newy * sizeof(unsigned char)))) 
    return(0);
    if(!subsample_rgb((unsigned char *)p_image->data, p_image->width, 
		      p_image->height, 0, 0, p_image->width, p_image->height,
		      p_newdata, samplefactor, samplefactor))
      {
	return(0);
      }
   
    p_image->bytes_per_line=newx*3;
  }
  else 
  {
    fprintf(stderr, "subscaleImagexy not implemented for Type ");
    fprintf(stderr, "%d yet\n", p_image->format);
    return(0);
  }
  free(p_image->data);
  p_image->data   = p_newdata;
  p_image->width  = newx;
  p_image->height = newy;
  return(1);
}


/**********************************************************************/

int subsampleImage(Picture *p_image, int samplefactor)
{
  int            ii, jj;     /*Countervariables                       */
  int            newx, newy; /*new widht and height                   */
  unsigned char *p_newdata;  /*new Datapointer replacing p_image->data*/
  unsigned char *p_data;     /*Datapointer p_image->data              */
  unsigned char *p_data2;    /*dereferenced Datapointer p_image->data */
  int kacheloffset;
  
  if(!p_image)           return(0);
  if(samplefactor < 1)   return(0);
  
  newx = p_image->width  / samplefactor;
  if(p_image->width  % samplefactor)  newx += 1;
  newy = p_image->height / samplefactor;
  if(p_image->height % samplefactor)  newy += 1;
  
  if(p_image->format == pix_grey)
  {
    if(!(p_newdata = (unsigned char *)
           malloc(newx * newy * sizeof(unsigned char)))) 
    return(0);
    p_data = (unsigned char *)p_image->data;
    kacheloffset = samplefactor/2 * p_image->width + samplefactor/2;
    for(ii = 0; ii < newy-1; ii++)
    {
      for(jj = 0; jj < newx-1; jj++)
      {
        *p_newdata++ = p_data[(ii * p_image->width + jj) * 
                              samplefactor +  kacheloffset]; 
      }
      *p_newdata++ = p_data[((ii * samplefactor + samplefactor/2) *
           p_image->width+ p_image->width/2 + (newx-1)*samplefactor/2)];
    }
    kacheloffset = ((p_image->height/2 + (newy-1) * 
                   samplefactor/2) * p_image->width +samplefactor/2);
    for(jj = 0; jj < newx-1; jj++)
    {
      *p_newdata++ = p_data[kacheloffset +  jj * samplefactor];
    }
    *p_newdata++ = p_data[(p_image->height/2 + (newy-1) * 
                                 samplefactor/2) * p_image->width + 
                          p_image->width/2 + (newx-1) * samplefactor/2];
    p_newdata -= newx * newy;
  }
  else if(p_image->format == pix_rgb24)
  {
    if(!(p_newdata = (unsigned char *)
	 malloc(3*newx * newy * sizeof(unsigned char)))) 
      return(0);
    p_data = (unsigned char *)p_image->data;
    for(ii = 0; ii < newy-1; ii++)
      {
	for(jj = 0; jj < newx-1; jj++)
	  {
	    p_data2 = p_data + 3*(int)((ii+.5) * samplefactor * 
				       p_image->width + jj * samplefactor + samplefactor/2);
	    *p_newdata++ = *p_data2++;
	    *p_newdata++ = *p_data2++;
	    *p_newdata++ = *p_data2++;
	  }
	p_data2 = p_data + 3*(int)((ii+.5) *samplefactor*p_image->width+ 
				   p_image->width/2 + (newx-1) * samplefactor/2);
	*p_newdata++ = *p_data2++;
	*p_newdata++ = *p_data2++;
	*p_newdata++ = *p_data2++;      
      }
    for(jj = 0; jj < newx-1; jj++)
      {
	p_data2 = p_data + 3*(int)((p_image->height/2 + (newy-1) * 
				    samplefactor/2) * p_image->width + 
				   jj * samplefactor + samplefactor/2);
	*p_newdata++ = *p_data2++;
	*p_newdata++ = *p_data2++;
	*p_newdata++ = *p_data2++;
      }
    p_data2 = p_data + 3*(int)((p_image->height/2 + (newy-1) * 
				samplefactor/2) * p_image->width + 
			       p_image->width/2 + (newx-1) * samplefactor/2);
    *p_newdata++ = *p_data2++;
    *p_newdata++ = *p_data2++;
    *p_newdata++ = *p_data2++;
    
    p_newdata -= 3 * newx * newy;
  }
  else 
    {
      fprintf(stderr, "subsampleImage not implemented for Type ");
      fprintf(stderr, "%d yet\n", p_image->format);
    return(0);
  }
  
  free(p_image->data);
  
  p_image->data   = p_newdata;
  p_image->width  = newx;
  p_image->height = newy;
  p_image->bytes_per_line = newx * 3; 
  if(p_image->format==pix_rgb24)
    p_image->datasize=p_image->width*p_image->height*3;
  else
    p_image->datasize=p_image->width*p_image->height; 
  
  return(1);

}















