/*******************************************************************************
 *                                                                             *
 *  Filename : medcut.c                                                        *
 *  Authors  : Andrey Collison (fist implementation at IAM)                    *
 *  Authors  : Bruno Grossniklaus (to complete the transform algorithms)       *
 *  Created  :  5.5.91                                                         *
 *  Modified :                                                                 *
 *             20.6.91 Gro: bug fixed if no filename is given                  *
 *                                                                             *
 ******************************************************************************/


/*
 * medcut.c
 *
 * Transforms 32 or 24 Bit pixrect or rayshade files to 8 Bit colormap files
 * with the mediancut algorithm
 *
 */


/******************************************************************** INCLUDE */
/* global defaults are set in defaults.h */
#include <stdio.h>
/* This version is for use with XView only! */
#include <pixrect/pixrect_hs.h>
#include "defaults.h"


/******************************************************************** DEFINE  */
/* defaults for medcut */
/* more defaults are included in defaults.h */

#define  VERSION  "1.02 (20.6.91)"        /* Versions Nr.                     */

#define  DEFAULT_SHIFT_R     2            /* Default shift for red            */
#define  DEFAULT_SHIFT_G     2            /* Default shift for green          */
#define  DEFAULT_SHIFT_B     2            /* Default shift for blue           */

#define  CUT_RED             1            /* next color to cut                */
#define  CUT_GREEN           2            /* next color to cut                */
#define  CUT_BLUE            3            /* next color to cut                */


/********************************************************************* TYPES  */
/* types for median */
typedef struct {                          /* Type of histogram                */
  long int           n;                   /* number to count colors           */
} HIST_T;                                 /* and keeps colormap_index         */

struct LIST_ELEMENT_T {                   /* type of element in list          */
  struct LIST_ELEMENT_T *next;            /* pointer to next element in list  */
  struct COLOR_BOX_T    *info;            /* pointer to info (could be void)  */
};

struct LIST_T {                           /* type of list                     */
  struct LIST_ELEMENT_T first;            /* an element in list               */
  struct LIST_ELEMENT_T *last;            /* pointer to last element in list  */
};

struct COLOR_BOX_T {                      /* type of a color box              */
  long int size;                          /* size of color box                */
  long int num_pixels;                    /* number of pixels in box          */
  int      edge_lenght;                   /* longest edge in box              */
  int      cut_edge;                      /* next edge to cut                 */
  int      min_r, max_r;                  /* color values                     */
  int      min_g, max_g;                  /* color values                     */
  int      min_b, max_b;                  /* color values                     */
};


/******************************************************************** GLOBALS */
static long int       global_num_pixels;         /* number of pixels (x*y)    */

static HIST_T         *global_histogram;         /* pointer into histogram    */

static int            global_hist_size_r;        /* size of histogram         */
static int            global_hist_size_g;        /* size of histogram         */
static int            global_hist_size_b;        /* size of histogram         */

static unsigned char  global_shift_r;            /* shift for red             */
static unsigned char  global_shift_g;            /* shift for green           */
static unsigned char  global_shift_b;            /* shift for blue            */


/****************************************************************** FUNCTIONS */
/* functions in pic_io.c */
extern void set_file_names();
extern void close_success();
extern void close_error();
extern int  open_in_file();
extern int  open_out_file();
extern int  get_image();
extern int  get_mem();
extern int  put_image();
extern void print_euclidean_dist();
extern void write_map();

/* functions to deklare */
struct COLOR_BOX_T    *extract_first_element_from_list();
struct COLOR_BOX_T    *get_first_info_in_list();
struct COLOR_BOX_T    *init_color_box();
struct COLOR_BOX_T    *calc_median_and_cut();
int                   compare();


/*******************************************************************************
 *   main                                                                      *
 *                                                                             *
 *   Input  :                                                                  *
 *            - argv      arguments (options and filename)                     *
 *            - argc      number of arguments                                  *
 *                                                                             *
 *   Return : - NULL if ok, 1 on error                                         *
 *                                                                             *
 ******************************************************************************/

int main (argc,argv)
int argc;
char *argv [];

{
/******************************************************************** DEKLAR  */
  FILE                *fp_in;             /* file pointer                     */
  FILE                *fp_out;            /* file pointer                     */
  char                fn_in[FNS];         /* file name input                  */
  char                fn_out[FNS];        /* file name output                 */
  char                tmp_str[16];        /* temorary string                  */
  char                tmp_str_fs[3*FNS];  /* for system call (fs)             */

  Pixrect             *mem_8_out;         /* pixrect in memory 8 Bit          */
  Pixrect             *mem_in;            /* pixrect in memory 24 or 32 Bit   */

  colormap_t          colormap;           /* colormap of output file          */
  unsigned char       red[256];           /* used for colormap                */
  unsigned char       green[256];         /* used for colormap                */
  unsigned char       blue[256];          /* used for colormap                */
  int                 num_colors;         /* number of different colors       */
  int                 col_map_max;

  unsigned char       *im_ptr_8_out;      /* pointer into 8 Bit image         */
  int                 *im_ptr_in;         /* pointer into 24 or 32 Bit image  */

  int                 x,y,depth;          /* size and depth of image          */
  int                 out_format;         /* outfileformat (standard,encoded) */
  int                 i;                  /* used for loops                   */
  long int            r,g,b;              /* value of red,green,blue          */

  unsigned char       flag_prompt;        /* flag if prompt                   */
  unsigned char       flag_euclid;        /* flag if calculate euclid         */
  unsigned char       flag_expand_name;   /* flag if expand name              */
  unsigned char       flag_option_ok;     /* flag if option ok                */
  unsigned char       flag_write_map;     /* flag if write colormap           */
  unsigned char       flag_stdout;        /* flag if write to stdout          */
  unsigned char       flag_sunview;       /* flag if sunview                  */

  unsigned long int   hist_size;          /* size of histogram                */
  register unsigned long int
                      hist_index;         /* index for histogram              */

  register unsigned char
     red_r,green_r,green_l,blue_r,blue_l; /* for fast access in loops         */

  struct COLOR_BOX_T  *main_color_box;          /* pointer to color box       */
  struct COLOR_BOX_T  *main_current_color_box;  /* pointer to color box       */
  struct COLOR_BOX_T  *main_new_color_box;      /* pointer to color box       */
  struct LIST_T       main_color_box_list;      /* pointer list of color boxes*/

  unsigned char       flag_floyd_steinb;  /* flag if floyd steinberg dither   */
  register int                            /* spreading of errors              */
                      spread_hori,        /* spreading horizontal             */
                      spread_diag,        /* spreading diagonal               */
                      spread_vert;        /* spreading vertical               */
  register int        spread_percent;     /* spread error in %                */


/******************************************************************** INIT    */
  /* set variables with defaults (defined in defaults.h) */

  /* file names with EOS (end of string) */
  for (i = 0; i < FNS; i++) fn_in[i] = fn_out[i] = '\0';

  /* pointers with NULL */
  fp_in = fp_out = NULL;
  mem_8_out = mem_in = NULL;

  /* set default shift */
  global_shift_r = DEFAULT_SHIFT_R;
  global_shift_g = DEFAULT_SHIFT_G;
  global_shift_b = DEFAULT_SHIFT_B;

  /* other default values */
  out_format = DEFAULT_OUT_FORM;
  flag_prompt = DEFAULT_PROMPT;
  flag_euclid = DEFAULT_EUCLID;
  flag_expand_name = DEFAULT_EXP_NAM;
  flag_write_map = DEFAULT_WRITE_MAP;
  flag_stdout = FALSE;
  flag_sunview = DEFAULT_SUNVIEW;

  /* set default for floyd steinberg dither */
  flag_floyd_steinb = DEFAULT_FLOYD;
  spread_hori = DEFAULT_SPREAD_HORI;
  spread_diag = DEFAULT_SPREAD_DIAG;
  spread_vert = 100 - spread_hori - spread_diag;
  spread_percent = DEFAULT_SPREAD_PERCENT;

  fprintf (stderr,"\n");


/******************************************************************** OPTIONS */
  /* argv[0] is name of program */
  /* if there are no parameters specified show usage */
  if (argc <= 1) {
    fprintf (stderr,"Called without parameters \n");
    usage_exit (argv[0]);
  }

  /* the last parameter is the input file name or the -h option */
  else if (argv[argc - 1] [0] != '-')
      strcpy (fn_in,argv[argc - 1]);
    else
      if (strcmp (argv[argc - 1], "-h") == 0) help_exit (argv[0]);
      else if (strcmp (argv[argc -1],"-c") == 0) {
        fprintf (stderr,"%s was written by Bruno Grossniklaus in 1991\n",
                         argv[0]);
        exit (1);
      }
      else {
        fprintf (stderr,"Last parameter %s is not filename (but option) \n",
                                                                  argv[argc-1]);
        usage_exit (argv[0]);
      }


  /* scan the options */
  i=1;
  flag_option_ok = TRUE;

  while ( (i < argc - 1) && (flag_option_ok) ) {
    flag_option_ok = FALSE;

    if (strcmp (argv[i],"-p+") == 0) {
      i++;
      flag_option_ok = TRUE;
      flag_prompt = TRUE;
    }

    if (strcmp (argv[i],"-p-") == 0) {
      i++;
      flag_option_ok = TRUE;
      flag_prompt = FALSE;
    }

    if (strcmp (argv[i],"-p") == 0) {
      i++;
      flag_option_ok = TRUE;
      flag_prompt = !flag_prompt;
    }


    if (strcmp (argv[i],"-o") == 0) {
      flag_option_ok = TRUE;
      i++;
      if (i >= argc - 1) {
        fprintf (stderr,"Missing parameter after %s. \n",argv[i-1]);
        fprintf (stderr,"%s is the input filename! \n",argv[i]);
        usage_exit (argv[0]);
      }
      strcpy (fn_out,argv[i]);
      if ( (fn_out[0] == '-') || (fn_out == NULL) ) {
        fprintf (stderr,"Parameter %s after -o is not filename \n",fn_out);
        usage_exit (argv[0]);
      }
      i++;
    }


    if (strcmp (argv[i],"-en+") == 0) {
      i++;
      flag_option_ok = TRUE;
      flag_expand_name = TRUE;
    }

    if (strcmp (argv[i],"-en-") == 0) {
      i++;
      flag_option_ok = TRUE;
      flag_expand_name = FALSE;
    }

    if (strcmp (argv[i],"-en") == 0) {
      i++;
      flag_option_ok = TRUE;
      flag_expand_name = !flag_expand_name;
    }


    if ( (strcmp (argv[i],"-ws+") == 0) || (strcmp (argv[i],"-ws") == 0) ) {
      flag_option_ok = TRUE;
      out_format = RT_STANDARD;
      if (flag_prompt) fprintf (stderr,"Output file format is STANDARD \n");
      i++;
    }

    if (strcmp (argv[i],"-ws-") == 0) {
      flag_option_ok = TRUE;
      out_format = RT_BYTE_ENCODED;
      if (flag_prompt)
            fprintf (stderr,"Output file format is RUN LENGTH ENCODED \n");
      i++;
    }


    if (strcmp (argv[i],"-sv+") == 0) {
      i++;
      flag_option_ok = TRUE;
      flag_sunview = TRUE;
    }

    if (strcmp (argv[i],"-sv-") == 0) {
      i++;
      flag_option_ok = TRUE;
      flag_sunview = FALSE;
    }

    if (strcmp (argv[i],"-sv") == 0) {
      i++;
      flag_option_ok = TRUE;
      flag_sunview = !flag_sunview;
    }


    if (strcmp (argv[i],"-sa") == 0) {
      i++;
      flag_option_ok = TRUE;
      if (i >= argc - 1) {
        fprintf (stderr,"Missing parameter after %s. \n",argv[i-1]);
        fprintf (stderr,"%s is the input filename! \n",argv[i]);
        usage_exit (argv[0]);
      }
      if ( (atoi(argv[i]) < 1) || (atoi(argv[i]) > 8) ) {
        fprintf (stderr," %d is not allowed for %s \n",atoi(argv[i]),argv[i-1]);
        usage_exit (argv[0]);
      }
      else {
        global_shift_r = atoi(argv[i]);
        global_shift_g = atoi(argv[i]);
        global_shift_b = atoi(argv[i]);
      }
      i++;
    }

    if (strcmp (argv[i],"-sr") == 0) {
      i++;
      flag_option_ok = TRUE;
      if (i >= argc - 1) {
        fprintf (stderr,"Missing parameter after %s. \n",argv[i-1]);
        fprintf (stderr,"%s is the input filename! \n",argv[i]);
        usage_exit (argv[0]);
      }
      if ( (atoi(argv[i]) < 1) || (atoi(argv[i]) > 8) ) {
        fprintf (stderr," %d is not allowed for %s \n",atoi(argv[i]),argv[i-1]);
        usage_exit (argv[0]);
      }
      else global_shift_r = atoi(argv[i]);
      i++;
    }

    if (strcmp (argv[i],"-sg") == 0) {
      i++;
      flag_option_ok = TRUE;
      if (i >= argc - 1) {
        fprintf (stderr,"Missing parameter after %s. \n",argv[i-1]);
        fprintf (stderr,"%s is the input filename! \n",argv[i]);
        usage_exit (argv[0]);
      }
      if ( (atoi(argv[i]) < 1) || (atoi(argv[i]) > 8) ) {
        fprintf (stderr," %d is not allowed for %s \n",atoi(argv[i]),argv[i-1]);
        usage_exit (argv[0]);
      }
      else global_shift_g = atoi(argv[i]);
      i++;
    }

    if (strcmp (argv[i],"-sb") == 0) {
      i++;
      flag_option_ok = TRUE;
      if (i >= argc - 1) {
        fprintf (stderr,"Missing parameter after %s. \n",argv[i-1]);
        fprintf (stderr,"%s is the input filename! \n",argv[i]);
        usage_exit (argv[0]);
      }
      if ( (atoi(argv[i]) < 1) || (atoi(argv[i]) > 8) ) {
        fprintf (stderr," %d is not allowed for %s \n",atoi(argv[i]),argv[i-1]);
        usage_exit (argv[0]);
      }
      else global_shift_b = atoi(argv[i]);
      i++;
    }

    if (strcmp (argv[i],"-fs%") == 0) {
      i++;
      flag_option_ok = TRUE;
      if ( (argv[i][0] == '-') || (i >= argc - 1) ) {
        fprintf (stderr,"Missing parameter after %s. \n",argv[i-1]);
        usage_exit (argv[0]);
      }
      else {
        spread_percent = atoi (argv[i]);
        if ( (spread_percent < 0) || (spread_percent > 100) ) {
          fprintf (stderr,"After -fs%% must be a number in percent. ");
          fprintf (stderr,"%d not allowed\n",spread_percent);
          usage_exit (argv[0]);
        }
      }
      i++;
    }

    if (strcmp (argv[i],"-fs+") == 0) {
      i++;
      flag_option_ok = TRUE;
      flag_floyd_steinb = TRUE;
      if ( (argv[i][0] != '-')  && (i < argc - 1) ) {
        spread_hori = atoi (argv[i]);
        i++;
        if ( (argv[i][0] == '-') || (i >= argc - 1) ) {
          fprintf (stderr,"Missing parameter after %s. \n",argv[i-2]);
          fprintf (stderr,"%s must be diagonal spreading! \n",argv[i]);
          usage_exit (argv[0]);
        }
        spread_diag = atoi (argv[i]);
        i++;
      }
      if ( (spread_hori < 0) || (spread_hori > 100) ) {
        fprintf (stderr,"Horizontal spreading is ");
        fprintf (stderr,"%d, but must be >= 0 and <= 100!\n",spread_hori);
        usage_exit (argv[0]);
      }
      if ( (spread_diag < 0) || (spread_diag > 100) ) {
        fprintf (stderr,"Diagonal spreading is ");
        fprintf (stderr,"%d, but must be >= 0 and <= 100!\n",spread_diag);
        usage_exit (argv[0]);
      }
      spread_vert = 100 - spread_hori - spread_diag;
      if (spread_vert < 0) {
        fprintf (stderr,"Vertical spreading is %d, but must be >= 0!\n",
                 spread_vert);
        usage_exit (argv[0]);
      }
    }


    if (strcmp (argv[i],"-fs-") == 0) {
      i++;
      flag_option_ok = TRUE;
      flag_floyd_steinb = FALSE;
    }

    if (strcmp (argv[i],"-fs") == 0) {
      i++;
      flag_option_ok = TRUE;
      flag_floyd_steinb = !flag_floyd_steinb;
      if (flag_floyd_steinb) {
        if ( (argv[i][0] != '-') && (i < argc - 1) ) {
          spread_hori = atoi (argv[i]);
          i++;
          if ( (argv[i][0] == '-') || (i >= argc - 1) ) {
            fprintf (stderr,"Missing parameter after %s. \n",argv[i-2]);
            fprintf (stderr,"%s must be diagonal spreading! \n",argv[i]);
            usage_exit (argv[0]);
          }
          spread_diag = atoi (argv[i]);
          i++;
        }
        if ( (spread_hori < 0) || (spread_hori > 100) ) {
          fprintf (stderr,"Horizontal spreading is ");
          fprintf (stderr,"%d, but must be >= 0 and <= 100!\n",spread_hori);
          usage_exit (argv[0]);
        }
        if ( (spread_diag < 0) || (spread_diag > 100) ) {
          fprintf (stderr,"Diagonal spreading is ");
          fprintf (stderr,"%d, but must be >= 0 and <= 100!\n",spread_diag);
          usage_exit (argv[0]);
        }
        spread_vert = 100 - spread_hori - spread_diag;
        if (spread_vert < 0) {
          fprintf (stderr,"Vertical spreading is %d, but must be >= 0!\n",
                   spread_vert);
          usage_exit (argv[0]);
        }
      }
    }

    if (strcmp (argv[i],"-ce+") == 0) {
      i++;
      flag_option_ok = TRUE;
      flag_euclid = TRUE;
    }

    if (strcmp (argv[i],"-ce-") == 0) {
      i++;
      flag_option_ok = TRUE;
      flag_euclid = FALSE;
    }

    if (strcmp (argv[i],"-ce") == 0) {
      i++;
      flag_option_ok = TRUE;
      flag_euclid = !flag_euclid;
    }


    if (strcmp (argv[i],"-m+") == 0) {
      i++;
      flag_option_ok = TRUE;
      flag_write_map = TRUE;
    }

    if (strcmp (argv[i],"-m-") == 0) {
      i++;
      flag_option_ok = TRUE;
      flag_write_map = FALSE;
    }

    if (strcmp (argv[i],"-m") == 0) {
      i++;
      flag_option_ok = TRUE;
      flag_write_map = !flag_write_map;
    }


    if (strcmp (argv[i],"-h") == 0)
      help_exit (argv[0]);

  }


  /* if current parameter was no good option */
  if (!flag_option_ok) {
    fprintf (stderr,"%s is not an allowed option \n",argv[i]);
    usage_exit (argv[0]);
  }


/******************************************************************** INIT    */
  if (strcmp (fn_out,DEFAULT_STDOUT) == 0) flag_stdout = TRUE;

  /* function in pic_io.c */
  set_file_names (fn_in,fn_out);

  /* if expand name is set then add current settings to the output file name  */
  if ( (flag_expand_name) && (!flag_stdout) ){

    /* m means mediancut algorithm */
    strcat (fn_out,"_m_");

    /* add shift */
    sprintf (tmp_str,"%d", global_shift_r);
    strcat (fn_out,tmp_str);
    sprintf (tmp_str,"%d", global_shift_g);
    strcat (fn_out,tmp_str);
    sprintf (tmp_str,"%d", global_shift_b);
    strcat (fn_out,tmp_str);

    /* print the output file name to console */
    fprintf (stderr,"Expand name is set. So output file is %s \n",fn_out);
  }

  if ( (flag_stdout) && (flag_floyd_steinb)) strcpy (fn_out,TMP_FILE_NAME);

/***************************************************************** OPEN & GET */
  /* now open the files and load image */
  /* functions in pic_io.c */
  if (open_in_file (fn_in,&fp_in,fp_out,mem_in,mem_8_out) != NULL) exit (1);
  if (open_out_file (fn_out,fp_in,&fp_out,mem_in,mem_8_out) != NULL) exit (1);
  if (    get_image (fn_in,fp_in,fp_out,&mem_in,mem_8_out,
                     flag_prompt,&x,&y,&depth) != NULL) exit (1);

  /* allocate memory for output image */
  if (get_mem(fp_in,fp_out,mem_in,&mem_8_out,flag_prompt,x,y) != NULL) exit (1);


/*********************************************************** COLOR STATISTICS */
  /* set globals */
  global_num_pixels = x*y;

  /* set histogram size */
  global_hist_size_r = 256 >> global_shift_r;
  global_hist_size_g = 256 >> global_shift_g;
  global_hist_size_b = 256 >> global_shift_b;

  /* init histogram */
  hist_size = (256 >> global_shift_r) *
              (256 >> global_shift_g) * (256 >> global_shift_b);
  if (flag_prompt) fprintf (stderr,"Histogram size : %d \n",hist_size);

  if ( (global_histogram = (HIST_T *)
                    malloc ( (unsigned) hist_size  * sizeof (HIST_T))) == NULL) {
    fprintf (stderr,"\nError in malloc for histogram. \n");
    fprintf (stderr," Not enough memory!\n");
    free ( (char *) global_histogram);
    close_error (fp_in,fp_out,mem_in,mem_8_out);
    exit (1);
  }

  /* init histogram */
  for (hist_index = 0; hist_index < hist_size ; hist_index++)
    global_histogram[hist_index].n = 0;

  if (flag_prompt) fprintf (stderr,"Sampling for color statistics ... ");

  num_colors = 0;

  /* set registers for faster access */
  red_r   =      global_shift_r;
  green_r =  8 + global_shift_g;
  blue_r  = 16 + global_shift_b;
  green_l =  8 - global_shift_r;
  blue_l  = 16 - global_shift_r - global_shift_g;

  /* set pointer to first pixel */
  im_ptr_in = (int *) mpr_d(mem_in)->md_image;

  /* scan image and count the different colors */
  for (i = 0; i < x*y; i++, im_ptr_in++) {
    /* look for the coding to get histogram index */

    r =  ((*im_ptr_in) & 0x000000ff) >> red_r;
    g = (((*im_ptr_in) & 0x0000ff00) >> green_r) << green_l;
    b = (((*im_ptr_in) & 0x00ff0000) >> blue_r ) << blue_l;

    if (global_histogram[r + g + b].n++ == 0) {
      num_colors ++;
    }

  }
  if (flag_prompt) fprintf (stderr,"done. \n");
  if (flag_prompt) fprintf (stderr,"  Number of different colors : %d \n",
                            num_colors);


/*************************************************************** GET COLORMAP */
  if (flag_prompt)
    fprintf (stderr,"Getting colormap ... ");

  /* if sunview option reserve 2 colors for sunview */
  if (num_colors > 256) num_colors = 256;
  if (flag_sunview) col_map_max = num_colors - 2; else col_map_max = num_colors;

  /* init color box */
  num_colors = 1;
  init_list (&main_color_box_list);
  main_new_color_box = init_color_box ();
  append_to_list (&main_color_box_list, main_new_color_box);

  /* loop over all colors to put in colormap */
  while (num_colors < col_map_max) {

    /* get the first box in list */
    main_current_color_box =
                     extract_first_element_from_list (&main_color_box_list);

    /* end if lenght of greatest box is 0 */
    if (main_current_color_box->edge_lenght <= 0) break;

    /* get new color box and fist both */
    main_new_color_box = calc_median_and_cut (main_current_color_box);

    /* put them in list */
    insert_in_list (&main_color_box_list, main_current_color_box, compare );
    insert_in_list (&main_color_box_list, main_new_color_box, compare );

    num_colors++;

  }

  if (flag_prompt) fprintf (stderr,"done.\n");

  if (flag_prompt) fprintf (stderr,"Preprocessing for mapping ... ");

  i = 0;
  main_color_box = extract_first_element_from_list (&main_color_box_list);

  /* set registers for faster access */
  green_l =  8 - global_shift_r;
  blue_l  = 16 - global_shift_r - global_shift_g;

  /* get the colormap and put indexes in histogram */

  while (main_color_box != NULL) {

    red[i]   = (unsigned char) ((main_color_box->max_r + main_color_box->min_r)
                                 << (global_shift_r - 1));
    green[i] = (unsigned char) ((main_color_box->max_g + main_color_box->min_g)
                                 << (global_shift_g - 1));
    blue[i]  = (unsigned char) ((main_color_box->max_b + main_color_box->min_b)
                                 << (global_shift_b - 1));

    /* put indexes in histogram now */
    for ( r = main_color_box->min_r; r <= main_color_box->max_r; r++)
     for ( g = main_color_box->min_g; g <= main_color_box->max_g; g++)
      for ( b = main_color_box->min_b; b <= main_color_box->max_b; b++)
       global_histogram [ r + (g << green_l) + (b << blue_l) ].n = i;

    /* free memory used for color box */
    free ( (char *) main_color_box);

    /* get new color box */
    main_color_box = extract_first_element_from_list (&main_color_box_list);
    i++;
  }


  /* reserve colors for sunview */
  if (flag_sunview) {
    red[254] = green[254] = blue[254] = 255;
    red[255] = green[255] = blue[255] = 0;
  }

  colormap.type   = RMT_EQUAL_RGB;
  colormap.length = 256;
  colormap.map[0] = red; colormap.map[1] = green; colormap.map[2] = blue;

  /* fix bug or undocumented function of pixrect functions */
  if ( (red[0] == 0) && (green[0] == 0) && (blue[0] == 0) ) blue[0] = 1;

  if (flag_prompt) fprintf (stderr,"done.\n");

  if (flag_prompt) fprintf (stderr,"  There are %d colors in the colormap\n",
                                    num_colors);


/************************************************************* MAPPING COLORS */
  /* map colors to colormap */
  if (flag_prompt) fprintf (stderr,"Mapping colors ... ");

  /* set registers for faster access */
  red_r   =      global_shift_r;
  green_r =  8 + global_shift_g;
  blue_r  = 16 + global_shift_b;
  green_l =  8 - global_shift_r;
  blue_l  = 16 - global_shift_r - global_shift_g;

  /* set image pointers to first pixel */
  im_ptr_in = (int *) mpr_d(mem_in)->md_image;
  im_ptr_8_out = (unsigned char *) mpr_d(mem_8_out)->md_image;

  /* loop over all pixels in x direction */
  for (i = 0; i < x*y; i++, im_ptr_in++, im_ptr_8_out++) {

    r =  ((*im_ptr_in) & 0x000000ff) >> red_r;
    g = (((*im_ptr_in) & 0x0000ff00) >> green_r) << green_l;
    b = (((*im_ptr_in) & 0x00ff0000) >> blue_r ) << blue_l;

    *im_ptr_8_out = global_histogram[ r + g + b ].n;

  }
  if (flag_prompt) fprintf (stderr,"done. \n");

  /* free memory used for histogram /*
  free ( (char *) global_histogram);


/**************************************************************** WRITE IMAGE */
  /* write output image */
  if (put_image (fn_out,fp_in,fp_out,mem_in,mem_8_out,
      flag_prompt,colormap,out_format) != NULL) exit (1);


/************************************************************ WRITE TO STDOUT */
  /* write colormap to stdout if option is set */
  if (flag_write_map)
    if (flag_stdout) {
      fprintf (stderr,"I write the image to stdout. ");
      fprintf (stderr,"So no other writing to stdout allowed! \n");
    }
    else write_map (fn_out,red,green,blue);

  /* calculate euclidean distance if option is set */
  if (flag_euclid)
    if (flag_stdout) {
      fprintf (stderr,"I write the image to stdout. ");
      fprintf (stderr,"So no other writing to stdout allowed! \n");
    }
    else print_euclidean_dist
                      (fn_out,mem_in,mem_8_out,flag_prompt,red,green,blue,x,y);


/**************************************************************** ENDING MAIN */
  /* close files and free memory */
  close_success (fp_in,fp_out,mem_in,mem_8_out);

  /* call fs from shell if fs option is set */
  if (flag_floyd_steinb) {
    strcpy  (tmp_str_fs,"fs -fs ");
    sprintf (tmp_str,"%d",spread_hori);
    strcat  (tmp_str_fs,tmp_str);
    strcat  (tmp_str_fs," ");
    sprintf (tmp_str,"%d",spread_diag);
    strcat  (tmp_str_fs,tmp_str);
    strcat  (tmp_str_fs," -fs% ");
    sprintf (tmp_str,"%d",spread_percent);
    strcat  (tmp_str_fs,tmp_str);
    sprintf (tmp_str," -sr %d",global_shift_r);
    strcat  (tmp_str_fs,tmp_str);
    sprintf (tmp_str," -sg %d",global_shift_g);
    strcat  (tmp_str_fs,tmp_str);
    sprintf (tmp_str," -sb %d ",global_shift_b);
    strcat  (tmp_str_fs,tmp_str);
    if (flag_prompt)
      strcat (tmp_str_fs," -p+");
    else
      strcat (tmp_str_fs," -p-");
    if (flag_expand_name)
      strcat (tmp_str_fs," -en+");
    else
      strcat (tmp_str_fs," -en-");
    if (flag_euclid)
      strcat (tmp_str_fs," -ce+");
    else
      strcat (tmp_str_fs," -ce-");
    if (out_format == RT_STANDARD)
      strcat (tmp_str_fs," -ws+");
     else
      strcat (tmp_str_fs," -ws-");
    if (flag_stdout) {
      strcat  (tmp_str_fs," -o ");
      strcat  (tmp_str_fs,DEFAULT_STDOUT);
      strcat  (tmp_str_fs," ");
      strcat  (tmp_str_fs,fn_in);
      strcat  (tmp_str_fs," ");
      strcat  (tmp_str_fs,TMP_FILE_NAME);
    }
    else {
      strcat  (tmp_str_fs," ");
      strcat  (tmp_str_fs,fn_in);
      strcat  (tmp_str_fs," ");
      strcat  (tmp_str_fs,fn_out);
    }

    if (system (tmp_str_fs) != NULL) {
      fprintf (stderr,"Error in systemcall for fs!\n");
      fprintf (stderr," - maybe there was an error in fs.\n");
      fprintf (stderr," - maybe fs not in current dir or path.\n");
      fprintf (stderr," - maybe out of memory.\n");
      fprintf (stderr," - maybe system problem.\n");
      exit (1);
    }
  }


  /* null problemo */
  return (0);
}


/*******************************************************************************
 *   usage_exit                                                                *
 *                                                                             *
 *   Input  :                                                                  *
 *            - name      name of program as string                            *
 *                                                                             *
 *   Output :                                                                  *
 *            - writes the usage and the default values to stderr              *
 *                                                                             *
 *   Return : - exits with 1                                                   *
 *                                                                             *
 ******************************************************************************/
usage_exit (name)
char *name;
{
  fprintf (stderr,"\n%s V%s\n",name,VERSION);
  fprintf (stderr,"Usage: %s {options} <input filename> \n",name);
  fprintf (stderr,"               -o <output filename|%s> \n",
                                                               DEFAULT_STDOUT);
  fprintf (stderr,"               -en[+|-]        expand name with mode \n");
  fprintf (stderr,"               -ws[+|-]        write standard format \n");
  fprintf (stderr,"               -sv[+|-]        colors for sunview \n");
  fprintf (stderr,"               -sa <1..8>      shift all values in Bit \n");
  fprintf (stderr,"               -sr <1..8>      shift red values in Bit \n");
  fprintf (stderr,"               -sg <1..8>      shift green values in Bit\n");
  fprintf (stderr,"               -sb <1..8>      shift blue values in Bit \n");
  fprintf (stderr,"               -fs[+|-] [h d]  use Floyd Steinberg ");
  fprintf (stderr,"dither\n");
  fprintf (stderr,"                                 following parameters ");
  fprintf (stderr,"in %% :\n");
  fprintf (stderr,"                                 h = horizontal error ");
  fprintf (stderr,"spreading\n");
  fprintf (stderr,"                                 d = diagonal error ");
  fprintf (stderr,"spreading\n");
  fprintf (stderr,"                                 h, d are integers ");
  fprintf (stderr,"(h+d<=100) \n");
  fprintf (stderr,"               -fs%% <0..100>   percent for Floyd ");
  fprintf (stderr,"Steinberg\n");
  fprintf (stderr,"                               dithering \n");
  fprintf (stderr,"               -ce[+|-]        calculate euclid. ");
  fprintf (stderr,"distance\n");
  fprintf (stderr,"                               and write to stdout \n");
  fprintf (stderr,"               -m[+|-]         write colormap to stdout \n");
  fprintf (stderr,"               -p[+|-]         prompt info to stderr \n");
  fprintf (stderr,"               -h              help (to stderr) \n");

  /* print the defaults */
  fprintf (stderr,"\nDefaults:                                       \n");
/*fprintf (stderr,"  - Extension of input file   : %s \n",DEFAULT_IN_EXT); */
  fprintf (stderr,"  - Extension of output file  : %s \n",DEFAULT_OUT_EXT);

  if (DEFAULT_EXP_NAM)
    fprintf (stderr,"  - Expand name               : + \n");
  else
    fprintf (stderr,"  - Expand name               : - \n");

  if (DEFAULT_OUT_FORM == RT_STANDARD)
    fprintf (stderr,"  - Write format              : standard \n");
  else
    fprintf (stderr,"  - Write format              : run length encoded \n");

  if (DEFAULT_SUNVIEW)
    fprintf (stderr,"  - Colors for sunview        : + \n");
  else
    fprintf (stderr,"  - Colors for sunview        : - \n");

  fprintf (stderr,"  - shift red values in Bit   : %d \n",DEFAULT_SHIFT_R);
  fprintf (stderr,"  - shift green values in Bit : %d \n",DEFAULT_SHIFT_G);
  fprintf (stderr,"  - shift blue values in Bit  : %d \n",DEFAULT_SHIFT_B);

  if (DEFAULT_FLOYD)
    fprintf (stderr,"  - Floyd Steinberg dither    : +  %d %d\n",
                        DEFAULT_SPREAD_HORI,DEFAULT_SPREAD_DIAG);
  else
    fprintf (stderr,"  - Floyd Steinberg dither    : - %d %d\n",
                       DEFAULT_SPREAD_HORI,DEFAULT_SPREAD_DIAG);

  fprintf (stderr,"  - Percent for Floyd Steinb. : %d \n",
           DEFAULT_SPREAD_PERCENT);

  if (DEFAULT_EUCLID)
    fprintf (stderr,"  - Calculate euclidean dist. : + \n");
  else
    fprintf (stderr,"  - Calculate euclidean dist. : - \n");

  if (DEFAULT_WRITE_MAP)
    fprintf (stderr,"  - Write colormap to stdout  : + \n");
  else
    fprintf (stderr,"  - Write colormap to stdout  : - \n");

  if (DEFAULT_PROMPT)
    fprintf (stderr,"  - Prompt info to stderr     : + \n");
  else
    fprintf (stderr,"  - Prompt info to stderr     : - \n");

  fprintf (stderr,"\n->try %s |& more\n",name);

  exit(1);
}


/*******************************************************************************
 *   help_exit                                                                 *
 *                                                                             *
 *   Input  :                                                                  *
 *            - name      name of program as string                            *
 *                                                                             *
 *   Output : - writes the help to stderr                                      *
 *                                                                             *
 *   Return : - exits with 1                                                   *
 *                                                                             *
 ******************************************************************************/
help_exit (name)
char *name;
{
  fprintf (stderr,"Help for %s V%s\n",name,VERSION);
  fprintf (stderr," I convert 24 or 32 Bit pixrect or rayshade images\n");
  fprintf (stderr," to 8 Bit colormapped images for suns using the mediancut\n");
  fprintf (stderr," algorithm. Here are some valid examples for calling:\n"); 
  fprintf (stderr,"   %s -ws- -en -p hsv.pixrect\n",name);
  fprintf (stderr,"   %s -sv -o %s tree.pic | rastool \n",name,DEFAULT_STDOUT);
  fprintf (stderr,"   %s -fs -o test.pic_8 test.pic_32 \n",name);
  fprintf (stderr,"   %s -fs -fs%% 75 -sv hsv\n",name);
  exit (1);
}


/*******************************************************************************
 *   init_list                                                                 *
 *                                                                             *
 *   Input  :                                                                  *
 *            - listp     pointer to list                                      *
 *                                                                             *
 *   initializes a list                                                        *
 *                                                                             *
 ******************************************************************************/
init_list (listp)
struct LIST_T *listp;

{
  listp->first.next = NULL;
  listp->first.info = NULL;
  listp->last       = &listp->first;
}


/*******************************************************************************
 *   insert_in_list                                                            *
 *                                                                             *
 *   Input  :                                                                  *
 *            - listp     pointer to list                                      *
 *            - infop     pointer to info to insert                            *
 *            - compfctp  pointer to compare function                          *
 *                                                                             *
 *   inserts an element in list                                                *
 *                                                                             *
 *   compare the element step by step to the elements in the list and insert it*
 *   before the first element with compfct (insert_element, list_element)      *
 *   returning non zero                                                        *
 *                                                                             *
 ******************************************************************************/
insert_in_list (listp, infop, compfctp)
struct LIST_T *listp;
struct COLOR_BOX_T *infop;
int    ( *compfctp) ();

{
  struct LIST_ELEMENT_T  *element;
  struct LIST_ELEMENT_T  *current_element;

  /* get memory for element */
  if ( (element = (struct LIST_ELEMENT_T *)
       malloc ( (unsigned)sizeof (struct LIST_ELEMENT_T))) == NULL ) {
    fprintf (stderr,"Error in malloc (list_element) \n");
    fprintf (stderr,"Not enough memory!\n");
    exit (1);
  }

  /* set info */
  element->info = infop;
  current_element = &listp->first;

  /* find place to insert */
  while (current_element->next != NULL) {
    if (compfctp (infop, current_element->next->info) ) break;
    current_element = current_element->next;
  }

  /* now insert */
  element->next = current_element->next;
  current_element->next = element;

  /* set last element if necessary */
  while (listp->last->next != NULL) listp->last = listp->last->next;

}


/*******************************************************************************
 *   append_to_list                                                            *
 *                                                                             *
 *   Input  :                                                                  *
 *            - listp     pointer to list                                      *
 *            - infop     pointer to info to append                            *
 *                                                                             *
 ******************************************************************************/
append_to_list (listp, infop)
struct LIST_T  *listp;
struct COLOR_BOX_T *infop;

{
  struct LIST_ELEMENT_T *element;

  /* get memory for element */
  if ( (element = (struct LIST_ELEMENT_T *)
         malloc ( (unsigned)sizeof (struct LIST_ELEMENT_T))) == NULL ) {
    fprintf (stderr,"Error in malloc (append_to_list) \n");
    fprintf (stderr,"Not enough memory!\n");
    exit (1);
  }

  /* set info */
  element->info = infop;
  element->next = NULL;

  /* appent element */
  listp->last->next = element;
  listp->last       = element;
}


/*******************************************************************************
 *   extract_first_element_from_list                                           *
 *                                                                             *
 *   Input  :                                                                  *
 *            - listp     pointer to list                                      *
 *                                                                             *
 *   Return : info of first element or NULL if listp points to NULL            *
 *                                                                             *
 ******************************************************************************/
struct COLOR_BOX_T *extract_first_element_from_list (listp)
struct LIST_T *listp;

{
  struct LIST_ELEMENT_T *element;
  struct COLOR_BOX_T                  *infop;

  element = listp->first.next;
  if (element != NULL) {
    /* get the first element */
    listp->first.next = element->next;
    /* get the pointer to info */
    infop = element->info;
    free ( (char *) element);
    if (listp->first.next == NULL) listp->last = &listp->first;
    return (infop);
  }
  else return (NULL);
}


/*******************************************************************************
 *   get_first_info_in_list                                                    *
 *                                                                             *
 *   Input  :                                                                  *
 *            - listp     pointer to list                                      *
 *                                                                             *
 *   Return : info of first element or NULL if listp points to NULL            *
 *                                                                             *
 ******************************************************************************/
struct COLOR_BOX_T *get_first_info_in_list (listp)
struct LIST_T *listp;

{
  if (listp->first.next != NULL)
    return (listp->first.next->info);
  else return NULL;
}


/*******************************************************************************
 *   init_color_box                                                            *
 *                                                                             *
 *   Input  :                                                                  *
 *                                                                             *
 *   Return : pointer to initialized color_box                                 *
 *                                                                             *
 ******************************************************************************/
struct COLOR_BOX_T *init_color_box ()

{
  struct COLOR_BOX_T *loc_color_box;

  /* get memory for color box */
  if ( (loc_color_box = (struct COLOR_BOX_T *)
       malloc ( (unsigned)sizeof (struct COLOR_BOX_T))) == NULL ) {
    fprintf (stderr,"Error in malloc (color_box) \n");
    fprintf (stderr,"Not enough memory!\n");
    exit (1);
  }

  loc_color_box->max_r = (global_hist_size_r) - 1;
  loc_color_box->max_g = (global_hist_size_g) - 1;
  loc_color_box->max_b = (global_hist_size_b) - 1;

  loc_color_box->min_r = 0;
  loc_color_box->min_g = 0;
  loc_color_box->min_b = 0;

  loc_color_box->num_pixels = global_num_pixels;

  calc_box (loc_color_box);

  return loc_color_box;

}


/*******************************************************************************
 *   calc_median_and_cut                                                       *
 *                                                                             *
 *   Input  :                                                                  *
 *            - loc_color_box    pointer to color_box                          *
 *                                                                             *
 *   Return : pointer to calculated color_box                                  *
 *                                                                             *
 ******************************************************************************/
struct COLOR_BOX_T *calc_median_and_cut (loc_color_box)
struct COLOR_BOX_T *loc_color_box;

{
  register int            r,g,b;
  long int                half_pixels;
  register long int       count_pixels;
  long int                old_count;
  struct COLOR_BOX_T      *new_color_box;
  register unsigned char  green_l, blue_l;

  /* calculate median of box along the longes edge */
  half_pixels = loc_color_box->num_pixels / 2;
  old_count = 0;
  count_pixels = 0;

  /* set registers for faster access */
  green_l =  8 - global_shift_r;
  blue_l  = 16 - global_shift_r - global_shift_g;

  switch (loc_color_box->cut_edge) {

  /* cut red */
  case CUT_RED:
    r = loc_color_box->min_r;
    while (count_pixels < half_pixels) {
    old_count = count_pixels;
      for (g = loc_color_box->min_g; g <= loc_color_box->max_g; g++)
       for (b = loc_color_box->min_b; b <= loc_color_box->max_b; b++)
        count_pixels += global_histogram[ r +
                                   (g << green_l) +
                                   (b << blue_l)].n;
      r++;
    }
    /* adjust median */
    if ( (half_pixels - old_count) < (count_pixels - half_pixels) ) {
      r--;
      count_pixels = old_count;
    }
    break;

  /* cut green */
  case CUT_GREEN:
    g = loc_color_box->min_g;
    while (count_pixels < half_pixels) {
      old_count = count_pixels;
      for (r = loc_color_box->min_r; r <= loc_color_box->max_r; r++)
       for (b = loc_color_box->min_b; b <= loc_color_box->max_b; b++)
        count_pixels += global_histogram[ r +
                                   (g << green_l) +
                                   (b << blue_l)].n;
      g++;
    }
    /* adjust median */
    if ( (half_pixels - old_count) < (count_pixels - half_pixels) ) {
      g--;
      count_pixels = old_count;
    }
    break;

  /* cut blue */
  case CUT_BLUE:
    b = loc_color_box->min_b;
    while (count_pixels < half_pixels) {
      old_count = count_pixels;
      for (r = loc_color_box->min_r; r <= loc_color_box->max_r; r++)
       for (g = loc_color_box->min_g; g <= loc_color_box->max_g; g++)
        count_pixels += global_histogram[ r +
                                   (g << green_l) +
                                   (b << blue_l)].n;
      b++;
    }
    /* adjust median */
    if ( (half_pixels - old_count) < (count_pixels - half_pixels) ) {
      b--;
      count_pixels = old_count;
    }
    break;

  default :
    fprintf (stderr,"Coding error in calc_median_and_cut\n");
    exit (1);
  }

  /* get memory for new color box */
  if ( (new_color_box = (struct COLOR_BOX_T *)
       malloc ( (unsigned)sizeof (struct COLOR_BOX_T))) == NULL ) {
    fprintf (stderr,"Error in malloc (new_color_box) \n");
    fprintf (stderr,"Not enough memory!\n");
    exit (1);
  }

  /* now cut the box */
  new_color_box->min_r = loc_color_box->min_r;
  new_color_box->min_g = loc_color_box->min_g;
  new_color_box->min_b = loc_color_box->min_b;

  new_color_box->max_r = loc_color_box->max_r;
  new_color_box->max_g = loc_color_box->max_g;
  new_color_box->max_b = loc_color_box->max_b;

  new_color_box->num_pixels = loc_color_box->num_pixels - count_pixels;
  loc_color_box->num_pixels = count_pixels;

  switch (loc_color_box->cut_edge) {
  case CUT_RED:
    loc_color_box->max_r = r - 1;
    new_color_box->min_r = r;
    break;

  case CUT_GREEN:
    loc_color_box->max_g = g - 1;
    new_color_box->min_g = g;
    break;

  case CUT_BLUE:
    loc_color_box->max_b = b - 1;
    new_color_box->min_b = b;
    break;

  default :
    fprintf (stderr,"Coding error in calc_median_and_cut\n");
    exit (1);
  }

  /* adjust the parameters of the boxes */
  calc_box (loc_color_box);
  calc_box (new_color_box);

  return new_color_box;
}


/*******************************************************************************
 *   calc_box                                                                  *
 *                                                                             *
 *   Input  :                                                                  *
 *            - loc_color_box  pointer to colorbox                             *
 *                                                                             *
 *   Output : -                                                                *
 *                                                                             *
 *                                                                             *
 *   Return : -                                                                *
 *                                                                             *
 ******************************************************************************/
calc_box (loc_color_box)
struct COLOR_BOX_T *loc_color_box;

{
  register int            r,g,b;
  unsigned char           flag_found;
  register unsigned char  green_l, blue_l;

  /* set default values */
  loc_color_box->edge_lenght = -1;
  loc_color_box->size = -1;
  loc_color_box->cut_edge = 0;

  /* set registers for faster access */
  green_l =  8 - global_shift_r;
  blue_l  = 16 - global_shift_r - global_shift_g;

  if (loc_color_box->num_pixels <= 0) return;

  /* sweep red min plane */
  flag_found = FALSE;
  while ( (flag_found == FALSE) &&
          (loc_color_box->min_r <= loc_color_box->max_r) ) {
    for (g = loc_color_box->min_g; g <= loc_color_box->max_g; g++)
     for (b = loc_color_box->min_b; b <= loc_color_box->max_b; b++)
      if (global_histogram[ loc_color_box->min_r +
                          (g << green_l) + (b << blue_l)].n
          != 0) flag_found = TRUE;
    loc_color_box->min_r++;
  }
  loc_color_box->min_r--;

  /* sweep green min plane */
  flag_found = FALSE;
  while ( (flag_found == FALSE) &&
          (loc_color_box->min_g <= loc_color_box->max_g) ) {
    for (r = loc_color_box->min_r; r <= loc_color_box->max_r; r++)
     for (b = loc_color_box->min_b; b <= loc_color_box->max_b; b++)
      if (global_histogram[ r + (loc_color_box->min_g << green_l) +
                           (b << blue_l)].n
          != 0) flag_found = TRUE;
    loc_color_box->min_g++;
  }
  loc_color_box->min_g--;

  /* sweep blue min plane */
  flag_found = FALSE;
  while ( (flag_found == FALSE) &&
          (loc_color_box->min_b <= loc_color_box->max_b) ) {
    for (r = loc_color_box->min_r; r <= loc_color_box->max_r; r++)
     for (g = loc_color_box->min_g; g <= loc_color_box->max_g; g++)
      if (global_histogram[ r + (g << green_l) +
                           (loc_color_box->min_b << blue_l)].n
          != 0) flag_found = TRUE;
    loc_color_box->min_b++;
  }
  loc_color_box->min_b--;

  /* sweep red max plane */
  flag_found = FALSE;
  while ( (flag_found == FALSE) &&
          (loc_color_box->min_r <= loc_color_box->max_r) ) {
    for (g = loc_color_box->min_g; g <= loc_color_box->max_g; g++)
     for (b = loc_color_box->min_b; b <= loc_color_box->max_b; b++)
      if (global_histogram[ loc_color_box->max_r +
                            (g << green_l) + (b << blue_l)].n
          != 0) flag_found = TRUE;
    loc_color_box->max_r--;
  }
  loc_color_box->max_r++;

  /* sweep green max plane */
  flag_found = FALSE;
  while ( (flag_found == FALSE) &&
          (loc_color_box->min_g <= loc_color_box->max_g) ) {
    for (r = loc_color_box->min_r; r <= loc_color_box->max_r; r++)
     for (b = loc_color_box->min_b; b <= loc_color_box->max_b; b++)
      if (global_histogram[ r +
                           (loc_color_box->max_g << green_l) + (b << blue_l)].n
          != 0) flag_found = TRUE;
    loc_color_box->max_g--;
  }
  loc_color_box->max_g++;

  /* sweep blue max plane */
  flag_found = FALSE;
  while ( (flag_found == FALSE) &&
          (loc_color_box->min_b <= loc_color_box->max_b) ) {
    for (r = loc_color_box->min_r; r <= loc_color_box->max_r; r++)
     for (g = loc_color_box->min_g; g <= loc_color_box->max_g; g++)
      if (global_histogram[ r + (g << green_l) +
                           (loc_color_box->max_b << blue_l)].n
          != 0) flag_found = TRUE;
    loc_color_box->max_b--;
  }
  loc_color_box->max_b++;

  /* caluculate size of cube */
  loc_color_box->size  = (loc_color_box->max_r - loc_color_box->min_r) *
                     (loc_color_box->max_r - loc_color_box->min_r);
  loc_color_box->size += (loc_color_box->max_g - loc_color_box->min_g) *
                     (loc_color_box->max_g - loc_color_box->min_g);
  loc_color_box->size += (loc_color_box->max_b - loc_color_box->min_b) *
                     (loc_color_box->max_b - loc_color_box->min_b);

  /* find the longest edge of box */
  /* (next to cut)                */
  if ( (loc_color_box->max_r - loc_color_box->min_r) >
       loc_color_box->edge_lenght) {
    loc_color_box->edge_lenght = loc_color_box->max_r - loc_color_box->min_r;
    loc_color_box->cut_edge = CUT_RED;
  }
  if ( (loc_color_box->max_g - loc_color_box->min_g) >
       loc_color_box->edge_lenght) {
    loc_color_box->edge_lenght = loc_color_box->max_g - loc_color_box->min_g;
    loc_color_box->cut_edge = CUT_GREEN;
  }
  if ( (loc_color_box->max_b - loc_color_box->min_b) >
        loc_color_box->edge_lenght) {
    loc_color_box->edge_lenght = loc_color_box->max_b - loc_color_box->min_b;
    loc_color_box->cut_edge = CUT_BLUE;
  }
}


/*******************************************************************************
 *   compare                                                                   *
 *                                                                             *
 *   Input  :                                                                  *
 *            - loc_color_box_1  pointer to colorbox                           *
 *            - loc_color_box_2  pointer to colorbox                           *
 *                                                                             *
 *   Return : - 1 if size of loc_color_box_1 > loc_color_box_2                 *
 *            - 0 if size of loc_color_box_1 < loc_color_box_2                 *
 *                                                                             *
 ******************************************************************************/
int compare (loc_color_box_1,loc_color_box_2)
struct COLOR_BOX_T *loc_color_box_1;
struct COLOR_BOX_T *loc_color_box_2;

{
  if (loc_color_box_1->size == loc_color_box_2->size)
   return (loc_color_box_1->num_pixels > loc_color_box_2->num_pixels);
  else if (loc_color_box_1->size > loc_color_box_2->size) return (1);
  return (0);
}


/*******************************************************************************
 *   print_color_box  (for testing only)                                       *
 *                                                                             *
 *   Input  :                                                                  *
 *            - cb               pointer to colorbox                           *
 *            - i                integer to print                              *
 *                                                                             *
 ******************************************************************************/
print_color_box (cb,i)
struct COLOR_BOX_T *cb;
int                  i;

{
  fprintf (stderr,"\n Colorbox : %d\n",i);
  fprintf (stderr,"    num pixels   : %d \n",cb->num_pixels);
  fprintf (stderr,"    size         : %d \n",cb->size);
  fprintf (stderr,"    cut edge     : %d \n",cb->cut_edge);
  fprintf (stderr,"    edge len     : %d \n",cb->edge_lenght);
  fprintf (stderr,"    min r, max r : %3d %3d  (%3d %3d)\n",cb->min_r,cb->max_r,
                  cb->min_r << global_shift_r,cb->max_r << global_shift_r);
  fprintf (stderr,"    min g, max g : %3d %3d  (%3d %3d)\n",cb->min_g,cb->max_g,
                  cb->min_g << global_shift_g,cb->max_g << global_shift_g);
  fprintf (stderr,"    min b, max b : %3d %3d  (%3d %3d)\n",cb->min_b,cb->max_b,
                  cb->min_b << global_shift_b,cb->max_b << global_shift_b);
}




