


/* These weights are magic numbers which apparently are appropriate
 * for converting RGB values into a single gray-level value.   */
  
#define	RED_WEIGHT	(0.299)
#define GREEN_WEIGHT	(0.587)
#define BLUE_WEIGHT	(0.114)



#define IDENTITY(x)      (x)
#define IDENT3(x, a, b)  (x)
#define ROUNDER(x)   ({ typeof (x) _x = (x);  ((_x < 0) ? (_x - 0.5) : (_x + 0.5));})



#define THRESHOLD(ITYPE)                                                               \
  {                                                                                    \
    ITYPE i = (ITYPE) img;                                                             \
    BinaryImage o = (BinaryImage) out;                                                 \
    typeof (*(i->data)) iscan, iend;                                                   \
    char *oscan;                                                                       \
                                                                                       \
    iscan = imGetStore(i);                                                             \
    iend  = iscan + imGetStoreLen(i);                                                  \
    oscan = imGetStore(o);                                                             \
    while (iscan < iend) {                                                             \
      *oscan++ = (((double) *iscan++) >= thresh) ? 1 : 0;                              \
    }                                                                                  \
                                                                                       \
    break;                                                                             \
  }



#define DOBINARY(OTYPE, OFF, ON)                                                       \
  {                                                                                    \
    BinaryImage i = (BinaryImage) img;                                                 \
    OTYPE o = (OTYPE) out;                                                             \
    char *iscan, *iend;                                                                \
    typeof (*(o->data)) oscan;                                                         \
                                                                                       \
    iscan = imGetStore(i);                                                             \
    iend  = iscan + imGetStoreLen(i);                                                  \
    oscan = imGetStore(o);                                                             \
    while (iscan < iend) {                                                             \
      *oscan++ = (*iscan++) ? ON : OFF;                                                \
    }                                                                                  \
                                                                                       \
    break;                                                                             \
  }



#define SCLRASS(x) { *oscan = (typeof (**(o->data))) (x); }
#define RGBASS(x)  { oscan->r = oscan->g = oscan->b = (typeof ((**(o->data)).r)) (x); }
#define HSVASS(x)  { oscan->h = -1.0;                                                  \
                     oscan->s = 0.0;                                                   \
                     oscan->v = (float) (x); }
  


#define CONVERT(ITYPE, OTYPE, POSONLY, RND, ASSIGN, BND, MINV, MAXV)			 \
  {											 \
    ITYPE i = (ITYPE) img;								 \
    OTYPE o = (OTYPE) out;								 \
    typeof (*(i->data)) iscan, iend;							 \
    typeof (*(o->data)) oscan;								 \
											 \
    iscan = imGetStore(i);								 \
    iend  = iscan + imGetStoreLen(i);							 \
    oscan = imGetStore(o);								 \
											 \
    if (direct)  {									 \
      for ( ; iscan < iend; iscan++, oscan++) {						 \
        ASSIGN(BND(RND((double) *iscan), MINV, MAXV));					 \
      }											 \
    }											 \
    else if ((mode == ImConvZero)  &&  imin >= 0.0) {					 \
      for ( ; iscan < iend; iscan++, oscan++) {						 \
        ASSIGN(RND(((double) *iscan) * mxval / imax));					 \
      }											 \
    }											 \
    else if (POSONLY  ||  imin >= 0.0) {						 \
      for ( ; iscan < iend; iscan++, oscan++) {						 \
        ASSIGN(RND((((double) *iscan) - imin) * mxval / idif));				 \
      }											 \
    }											 \
    else {										 \
      for ( ; iscan < iend; iscan++, oscan++) {						 \
        ASSIGN(RND(((double) *iscan) * mxval / iabs));					 \
      }											 \
    }											 \
											 \
    break;										 \
  }



#define RGBSCLR(x)  (RED_WEIGHT   * ((double) x->r) +                                  \
                     GREEN_WEIGHT * ((double) x->g) +                                  \
                     BLUE_WEIGHT  * ((double) x->b))



 
#define RGBTOSCLR(ITYPE, OTYPE, POSONLY, RND, BND, MINV, MAXV)				 \
  {											 \
    ITYPE i = (ITYPE) img;								 \
    OTYPE o = (OTYPE) out;								 \
    typeof (*(i->data)) iscan, iend;							 \
    typeof (*(o->data)) oscan;								 \
											 \
    iscan = imGetStore(i);								 \
    iend  = iscan + imGetStoreLen(i);							 \
    oscan = imGetStore(o);								 \
											 \
    if (direct) {									 \
      for ( ; iscan < iend; iscan++, oscan++) {						 \
        SCLRASS(BND(RND(RGBSCLR(iscan)), MINV, MAXV));					 \
      }											 \
    }											 \
    if ((mode == ImConvZero)  &&  imin >= 0.0) {					 \
      for ( ; iscan < iend; iscan++, oscan++) {						 \
        SCLRASS(RND((RGBSCLR(iscan)) * mxval / imax));					 \
      }											 \
    }											 \
    else if (POSONLY  ||  imin >= 0.0) {						 \
      for ( ; iscan < iend; iscan++, oscan++) {						 \
        SCLRASS(RND(((RGBSCLR(iscan)) - imin) * mxval / idif));				 \
      }											 \
    }											 \
    else {										 \
      for ( ; iscan < iend; iscan++, oscan++) {						 \
        SCLRASS(RND((RGBSCLR(iscan)) * mxval / iabs));					 \
      }											 \
    }											 \
											 \
    break;										 \
  }




#define RGBTHRESH(ITYPE)                                                               \
  {                                                                                    \
    ITYPE i = (ITYPE) img;                                                             \
    BinaryImage o = (BinaryImage) out;                                                 \
    typeof (*(i->data)) iscan, iend;                                                   \
    char *oscan;                                                                       \
                                                                                       \
    iscan = imGetStore(i);                                                             \
    iend  = iscan + imGetStoreLen(i);                                                  \
    oscan = imGetStore(o);                                                             \
    for ( ; iscan < iend; iscan++, oscan++) {                                          \
      *oscan = ((RGBSCLR(iscan)) >= thresh) ? 1 : 0;                                   \
    }                                                                                  \
                                                                                       \
    break;                                                                             \
  }



 
#define RGBTORGB(ITYPE, OTYPE, POSONLY, RND, BND, MINV, MAXV)				 \
  {											 \
    ITYPE i = (ITYPE) img;								 \
    OTYPE o = (OTYPE) out;								 \
    typeof (*(i->data)) iscan, iend;							 \
    typeof (*(o->data)) oscan;								 \
    double rgbimin = (double) MIN(RGBmin.r, MIN(RGBmin.g, RGBmin.b));			 \
    double rgbimax = (double) MAX(RGBmax.r, MAX(RGBmax.g, RGBmax.b));			 \
    double rgbiabs = MAX(ABS(rgbimax), ABS(rgbimin));					 \
    double rgbidif = rgbimax - rgbimin;							 \
											 \
    iscan = imGetStore(i);								 \
    iend  = iscan + imGetStoreLen(i);							 \
    oscan = imGetStore(o);								 \
											 \
    if (direct) {									 \
      for ( ; iscan < iend; iscan++, oscan++) {						 \
        oscan->r = ((typeof (oscan->r)) BND(RND((double) (iscan->r)), MINV, MAXV));	 \
        oscan->g = ((typeof (oscan->g)) BND(RND((double) (iscan->g)), MINV, MAXV));	 \
        oscan->b = ((typeof (oscan->b)) BND(RND((double) (iscan->b)), MINV, MAXV));	 \
      }											 \
    }											 \
    if ((mode == ImConvZero)  &&  rgbimin >= 0.0) {					 \
      for ( ; iscan < iend; iscan++, oscan++) {						 \
        oscan->r = ((typeof (oscan->r))							 \
                    RND(((double) (iscan->r)) * mxval / rgbimax));			 \
        oscan->g = ((typeof (oscan->g))							 \
                    RND(((double) (iscan->g)) * mxval / rgbimax));			 \
        oscan->b = ((typeof (oscan->b))							 \
                    RND(((double) (iscan->b)) * mxval / rgbimax));			 \
      }											 \
    }											 \
    else if (POSONLY  ||  rgbimin >= 0.0) {						 \
      for ( ; iscan < iend; iscan++, oscan++) {						 \
        oscan->r = ((typeof (oscan->r))							 \
                    RND((((double) (iscan->r)) - rgbimin) * mxval / rgbidif));		 \
        oscan->g = ((typeof (oscan->g))							 \
                    RND((((double) (iscan->g)) - rgbimin) * mxval / rgbidif));		 \
        oscan->b = ((typeof (oscan->b))							 \
                    RND((((double) (iscan->b)) - rgbimin) * mxval / rgbidif));		 \
      }											 \
    }											 \
    else {										 \
      for ( ; iscan < iend; iscan++, oscan++) {						 \
        oscan->r = ((typeof (oscan->r))							 \
                    RND(((double) (iscan->r)) * mxval / rgbiabs));			 \
        oscan->g = ((typeof (oscan->g))							 \
                    RND(((double) (iscan->g)) * mxval / rgbiabs));			 \
        oscan->b = ((typeof (oscan->b))							 \
                    RND(((double) (iscan->b)) * mxval / rgbiabs));			 \
      }											 \
    }											 \
											 \
    break;										 \
  }




#define MAPFUNC(ITYPE, OTYPE, FUNC)                                                    \
  {                                                                                    \
    ITYPE i = (ITYPE) img;                                                             \
    OTYPE o = (OTYPE) out;                                                             \
    typeof (*(i->data)) iscan, iend;                                                   \
    typeof (*(o->data)) oscan;                                                         \
                                                                                       \
    iscan = imGetStore(i);                                                             \
    iend  = iscan + imGetStoreLen(i);                                                  \
    oscan = imGetStore(o);                                                             \
                                                                                       \
    for ( ; iscan < iend; iscan++, oscan++) {                                          \
      *oscan = FUNC(*iscan);                                                           \
    }                                                                                  \
                                                                                       \
    break;                                                                             \
  }

