/*****************************************************************
 * flclr.c: FBM Release 1.0 25-Feb-90 Michael Mauldin
 *
 * Copyright (C) 1989,1990 by Michael Mauldin.  Permission is granted
 * to use this file in whole or in part for any purpose, educational,
 * recreational or commercial, provided that this copyright notice
 * is retained unchanged.  This software is available to all free of
 * charge by anonymous FTP and in the UUNET archives.
 *
 * flclr.c: Color <--> BW, (Mapped Color | BW) --> unmapped color
 *
 * CONTENTS
 *	clr2gray (input, output, rw, gw, bw)
 *	gray2clr (input, output, sun)
 *
 * EDITLOG
 *	LastEditDate = Mon Jun 25 00:05:04 1990 - Michael Mauldin
 *	LastFileName = /usr2/mlm/src/misc/fbm/flclr.c
 *
 * HISTORY
 * 25-Jun-90  Michael Mauldin (mlm@cs.cmu.edu) Carnegie Mellon
 *	Package for Release 1.0
 *
 * 07-Mar-89  Michael Mauldin (mlm) at Carnegie Mellon University
 *	Beta release (version 0.9) mlm@cs.cmu.edu
 *
 * 28-Nov-88  Michael Mauldin (mlm) at Carnegie-Mellon University
 *	Created.
 *****************************************************************/

# include <stdio.h>
# include "fbm.h"

/****************************************************************
 * clr2gray: Apply a triplet of weights to each color in and RGB
 *	     or mapped image and produce an 8bit grayscale image
 ****************************************************************/

#ifndef lint
static char *fbmid =
"$FBM flclr.c <1.0> 25-Jun-90  (C) 1989,1990 by Michael Mauldin, source \
code available free from MLM@CS.CMU.EDU and from UUNET archives$";
#endif

clr2gray (input, output, rw, gw, bw)
FBM *input, *output;
int rw, gw, bw;
{ int rw1, gw1, bw1, width, height, clrlen, rowlen, colors;
  register int i, j;
  register unsigned char *bmp, *obm;

  /* Already monochrome? */
  if (input->hdr.planes == 1 && input->hdr.clrlen == 0)
  { *output = *input; return (1); }
  
  /* Invalid raster type */
  if (input->hdr.planes != 3 && input->hdr.clrlen == 0)
  { fprintf (stderr,
	 "clr2gray was passed invalid raster type, clrlen %d, planes %d\n",
	 input->hdr.clrlen, input->hdr.planes);
    return (0);
  }
  
  /* Adjust weights for fast division via shift */
  rw1 = rw * 256 / (rw + gw + bw);
  gw1 = gw * 256 / (rw + gw + bw);
  bw1 = 256 - (rw1+gw1);
  
  fprintf (stderr, "Using weights [%2d %2d %2d] ==> <%3d, %3d, %3d>\n",
	   rw, gw, bw, rw1, gw1, bw1);

  /* Allocate output bitmap */
  output->hdr = input->hdr;
  output->hdr.clrlen = 0;
  output->hdr.planes = 1;
  output->hdr.bits = output->hdr.physbits = 8;
  alloc_fbm (output);
  
  /* Set commonly used vars */
  width = input->hdr.cols;
  height = input->hdr.rows;
  rowlen = input->hdr.rowlen;
  clrlen = input->hdr.clrlen;
  colors = clrlen / 3;

  /* Mapped color to gray scale */
  if (input->hdr.clrlen > 0)
  { register int *gray;
  
    gray = (int *) malloc ((unsigned) input->hdr.clrlen * sizeof (int));
    
    for (i=0; i<colors; i++)
    { gray[i] = (rw1 * input->cm[i] + 
		 gw1 * input->cm[i+colors] + 
		 bw1 * input->cm[i+(colors<<1)]) >> 8;

# ifdef DEBUG
      fprintf (stderr, "color %3d:  [%3d %3d %3d] => %3d\n",
		i,
		input->cm[i],
		input->cm[i+colors],
		input->cm[i+colors*2],
		gray[i]);
# endif

    }
    
    for (j=0; j<height; j++)
    { bmp = &(input->bm[j*rowlen]);
      obm = &(output->bm[j*rowlen]);
      
      for (i=0; i<width; i++)
      { *obm++ = gray[*bmp++]; }
    }
  }
		 

  /* RGB color to gray scale */
  else if (input->hdr.planes == 3 && input->hdr.physbits == 8)
  { register unsigned char *rp, *gp, *bp;

    for (j=0; j<height; j++)
    { rp = &(input->bm[j*rowlen]);
      gp = rp + input->hdr.plnlen;
      bp = gp + input->hdr.plnlen;
      obm = (&output->bm[j*rowlen]);

      for (i=0; i<width; i++)
      { *obm++ = (rw1 * *rp++ + 
		  gw1 * *gp++ + 
		  bw1 * *bp++) >> 8;
      }
    }
  }
  
  return (1);
}

/****************************************************************
 * gray2clr: Add a colormap (shades of gray) to a grayscale file
 ****************************************************************/

gray2clr (input, output, sun_map)
FBM *input, *output;
int sun_map;
{ register unsigned char *rmap, *gmap, *bmap, *bmp, *obm;
  register int i, maplen, plnlen;

  /* Invalid raster type */
  if (input->hdr.planes == 3)
  { fprintf (stderr, "Input already is in RGB format\n");
    *output = *input; return (1);
  }
    
  /* Invalid raster type */
  if (input->hdr.clrlen > 0 )
  { fprintf (stderr, "Input already has color map with %d colors\n",
	     input->hdr.clrlen / 3);
    *output = *input; return (1);
  }

  /* Invalid raster type */
  if (input->hdr.planes != 1 || input->hdr.clrlen != 0)
  { fprintf (stderr,
	 "gray2clr was passed invalid raster type, clrlen %d, planes %d\n",
	 input->hdr.clrlen, input->hdr.planes);
    return (0);
  }
  
  plnlen = input->hdr.plnlen;
  
  /* Make colormap length power of two */
  maplen = 1 << input->hdr.bits;

  /* Allocate output bitmap */
  output->hdr = input->hdr;
  output->hdr.clrlen = maplen * 3;
  alloc_fbm (output);
  
  rmap = &(output->cm[0]);
  gmap = &(output->cm[maplen]);
  bmap = &(output->cm[2*maplen]);

  for (i=0; i<maplen; i++)
  { *rmap++ = *gmap++ = *bmap++ = i; }

  /* For sun_map, swap colors 0 and 255 */
  if (sun_map && (maplen == 256))
  { rmap = &(output->cm[0]);
    gmap = &(output->cm[maplen]);
    bmap = &(output->cm[2*maplen]);

    rmap[0] = gmap[0] = bmap[0] = 255;
    rmap[255] = gmap[255] = bmap[255] = 0;

    /* Copy bits */
    for (bmp = input->bm, obm = output-> bm, i=0; i<plnlen; i++, bmp++)
    { if (*bmp == 0)		*obm++ = 255;
      else if (*bmp == 255)	*obm++ = 0;
      else			*obm++ = *bmp;
    }
  }

  else  
  {
    /* Copy bits */
    for (bmp = input->bm, obm = output-> bm, i=0; i<plnlen; i++)
    { *obm++ = *bmp++; }
  }

  return (1);
}

/****************************************************************
 * clr_unmap: Convert a mapped color image into RGB
 ****************************************************************/

clr_unmap (input, output)
FBM *input, *output;
{ register unsigned char *red, *grn, *blu, *bmp, *obm, *tail;
  register int plnlen, k;

  if (input->hdr.planes == 3)
  { *output = *input; return (1); }

  if (input->hdr.planes != 1)
  { fprintf (stderr, "clr_unmap cannot handle images with %d planes\n", 
	     input->hdr.planes);
    return (0);
  }

  if (input->hdr.physbits != 8)
  { fprintf (stderr, "clr_unmap cannot handle images with %d physbits\n", 
	     input->hdr.physbits);
    return (0);
  }

  output->hdr = input->hdr;
  output->hdr.planes = 3;
  output->hdr.clrlen = 0;
  output->hdr.bits = output->hdr.physbits;
  
  alloc_fbm (output);

  /* Real mapped color image */
  if (input->hdr.clrlen > 0)
  { red = &(input->cm[0]);
    grn = red + input->hdr.clrlen / 3;
    blu = grn + input->hdr.clrlen / 3;
    plnlen = input->hdr.plnlen;
    
    bmp = input->bm;
    obm = output->bm;
    tail = bmp + plnlen;
    
    while (bmp < tail)
    { k = *bmp++;
    
      obm[0]			= red[k];
      obm[plnlen]		= grn[k];
      obm[plnlen+plnlen]	= blu[k];
      obm++;
    }
    
  }
  
  /* Grayscale image (just duplicate planes) */
  else
  { plnlen = input->hdr.plnlen;
  
    bmp = input->bm;
    tail = bmp + plnlen;
    
    red = output->bm;
    grn = red + plnlen;
    blu = grn + plnlen;
    
    while (bmp < tail)
    { *red++ = *grn++ = *blu++ = *bmp++; }
  }
  
  return (1);
}

/****************************************************************
 * copy_clr: Copy colormap from input to output
 ****************************************************************/

copy_clr (input, output)
FBM *input, *output;
{ register int i, clrlen;
  register unsigned char *ic, *oc;

  if (output->hdr.clrlen != input->hdr.clrlen)
  { if (output->hdr.clrlen > 0) free (output->cm);
    output->cm = (unsigned char *) malloc (input->hdr.clrlen);
  }

  output->hdr.clrlen = clrlen = input->hdr.clrlen;

  ic = input->cm;
  oc = output->cm;
  
  for (i=0; i < clrlen; i++)
  { *oc++ = *ic++; }

  return (1);
}
