/*****************************************************************
 * flcmps.c: FBM Release 1.2 06-May-93 Michael Mauldin
 *
 * Copyright (C) 1993 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.
 *
 * flcmps.c: 
 *
 * CONTENTS
 *	write_simple_ps (image, wfile)
 *
 * EDITLOG
 *	LastEditDate = Wed May 26 14:04:52 1993 - Mike Mauldin
 *	LastFileName = /usr/mlm/fbm/flcmps.c
 *
 * HISTORY
 * 26-May-93  Michael Mauldin (mlm) at Carnegie-Mellon University
 *	Created.
 *****************************************************************/

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

#ifndef lint
static char *fbmid =
"$FBM flcmps.c <1.2> 26-May-93  (C) 1993 by Michael Mauldin, source \
code available free from MLM@CS.CMU.EDU and from UUNET archives$";
#endif

/* map 3, 4, 17, 19, and 20 to nearest valid grayscale */
int ps_gray_char[256] = {
  0,  1,  2,  2,  5,  5,  6,  7,  8,  9, 10, 11, 12, 13, 14, 15,
 16, 16, 18, 18, 21, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47,
 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63,
 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79,
 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95,
 96, 97, 98, 99,100,101,102,103,104,105,106,107,108,109,110,111,
112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,
128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143,
144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,159,
160,161,162,163,164,165,166,167,168,169,170,171,172,173,174,175,
176,177,178,179,180,181,182,183,184,185,186,187,188,189,190,191,
192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207,
208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223,
224,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,
240,241,242,243,244,245,246,247,248,249,250,251,252,253,254,255 };

/* map 3, 4, 17, 19, and 20 to nearest valid grayscale */
int ps_1bit_char[256] = {
  0,  1,  2,  5,  2,  5,  6,  7,  8,  9, 10, 11, 12, 13, 14, 15,
 16,  9, 18, 35, 36, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47,
 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63,
 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79,
 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95,
 96, 97, 98, 99,100,101,102,103,104,105,106,107,108,109,110,111,
112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,
128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143,
144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,159,
160,161,162,163,164,165,166,167,168,169,170,171,172,173,174,175,
176,177,178,179,180,181,182,183,184,185,186,187,188,189,190,191,
192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207,
208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223,
224,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,
240,241,242,243,244,245,246,247,248,249,250,251,252,253,254,255 };

/****************************************************************
 * analyze_image: Determine color/grayscale and bits
 ****************************************************************/

analyze_image (image, iscolor, bits, padlen)
FBM *image;
int *iscolor, *bits, *padlen;
{ register int i, j, w, h, rowlen, plnlen, pad;
  register unsigned char *ibm, *s, *tail, *rd, *gr, *bl;
  int nclrs, onebit, fourbit, mapped;

  mapped = (image->hdr.clrlen > 0);

  w = image->hdr.cols;
  h = image->hdr.rows;
  rowlen = image->hdr.rowlen;
  plnlen = image->hdr.plnlen;

  /*================ Detect color vs grayscale ================*/
  if (image->hdr.planes > 1)
  { *iscolor = 1; }
  else if (!mapped)
  { *iscolor = 0; }
  else
  {
    /* Check for color or grayscale image */
    nclrs = image->hdr.clrlen / 3;
    rd = image->cm;
    gr = rd + nclrs;
    bl = gr + nclrs;

    for (*iscolor=0, i=0; i<nclrs; i++)

    { if (rd[i] != gr[i] || rd[i] != bl[i])
      { *iscolor=1; break; }
    }
  }

  /*================ Detect 1, 4 or 8 bits ================*/  
  if (mapped)
  { onebit = fourbit = 1;
  
    ibm = image->bm;
    rd = image->cm;

    for (s=ibm, tail = s + image->hdr.plnlen; s<tail; s++)
    { if (rd[*s] != 0 && rd[*s] != 255 ||
	  gr[*s] != 0 && gr[*s] != 255 ||
	  bl[*s] != 0 && bl[*s] != 255)
      { onebit = 0; break; }
    }
    
    for (s=ibm, tail = s + image->hdr.plnlen; s<tail; s++)
    { if ((rd[*s] & 0x0f) && rd[*s] != 255 ||
	  (gr[*s] & 0x0f) && gr[*s] != 255 ||
	  (bl[*s] & 0x0f) && bl[*s] != 255 )
      { fourbit = 0; break; }
    }
    
    *bits = onebit ? 1 : fourbit ? 4 : 8;
  }
  else
  { onebit = fourbit = 1;

    for (s=image->bm, tail = s + image->hdr.plnlen * image->hdr.planes;
	 s<tail;
	 s++)
    { if (*s != 0 && *s != 255)
      { onebit = 0; break; }
    }
    

    for (s=image->bm, tail = s + image->hdr.plnlen * image->hdr.planes;
	 s<tail;
	 s++)
    { if (*s & 0x0f)
      { fourbit = 0; break; }
    }
    
    if (*iscolor && onebit)
    { onebit = 0; fourbit = 1; }

    *bits = onebit ? 1 : fourbit ? 4 : 8;
  }
  
  /*=======================================================*/
  
  fprintf (stderr, "flcmps: type of file: %d bit %s %s\n", *bits,
	   mapped ? "mapped" : "unmapped", *iscolor ? "color" : "grayscale");
  
  pad = (*bits == 1) ? 8 : (*bits == 4) ? 2 : 1;
  *padlen = pad * ((w + pad - 1) / pad);
  if (*padlen < rowlen)
  { fprintf (stderr, "Error: rowlen %d, padlen smaller at %d\n",
	     rowlen, *padlen);
    abort ();
  }
  
}



/****************************************************************
 * write a simple postscript data stream without ^C, ^D, ^Q, ^S or ^T
 ****************************************************************/

write_simple_ps (image, wfile, iscolor, bits, padlen)
FBM *image;
FILE *wfile;
int iscolor, bits, padlen;
{ register int i, j, w, h, rowlen, plnlen;
  register unsigned char *ibm, *s, *tail, *rd, *gr, *bl;
  int nclrs, onebit, fourbit, mapped;

  mapped = (image->hdr.clrlen > 0);
  
  w = image->hdr.cols;
  h = image->hdr.rows;
  rowlen = image->hdr.rowlen;
  plnlen = image->hdr.plnlen;

  if (mapped)
  { /* Check for color or grayscale image */
    nclrs = image->hdr.clrlen / 3;
    rd = image->cm;
    gr = rd + nclrs;
    bl = gr + nclrs;
  }

  write_simple_decoder (padlen, h, bits, iscolor);

  if (iscolor && mapped)
  { for (j=0; j<h; j++)
    { write_simple_scanline (rowlen, padlen, bits, &image->bm[j * rowlen], rd);
      write_simple_scanline (rowlen, padlen, bits, &image->bm[j * rowlen], gr);
      write_simple_scanline (rowlen, padlen, bits, &image->bm[j * rowlen], bl);
    }
  }
  else if (iscolor)
  { for (j=0; j<h; j++)
    { write_simple_scanline (rowlen, padlen, bits,
			     &image->bm[j * rowlen], NULL);
      write_simple_scanline (rowlen, padlen, bits,
			     &image->bm[j * rowlen + plnlen], NULL);
      write_simple_scanline (rowlen, padlen, bits,
			     &image->bm[j * rowlen + 2 * plnlen], NULL);
      
    }
  }
  else
  { for (j=0; j<h; j++)
    { write_simple_scanline (rowlen, padlen, bits,
			     &image->bm[j * rowlen], image->cm);
    }
  }

  printf ("\n");

  return (1);
}

/****************************************************************
 * write_simple_scanline
 ****************************************************************/

# define PIXEL(C) (cmap ? cmap[ibm[C]] : ibm[C])

write_simple_scanline (rowlen, padlen, bits, ibm, cmap)
register int rowlen, padlen;
int bits;
register unsigned char *ibm, *cmap;
{ register int i, ch;

  switch (bits)
  { case 1:	for (i=0; i<padlen; i++)
		{ ch = (i<rowlen && PIXEL(i)) ? 1 : 0; ch <<= 1;
		  ch |= (++i<rowlen && PIXEL(i)) ? 1 : 0; ch <<= 1;
		  ch |= (++i<rowlen && PIXEL(i)) ? 1 : 0; ch <<= 1;
		  ch |= (++i<rowlen && PIXEL(i)) ? 1 : 0; ch <<= 1;
		  ch |= (++i<rowlen && PIXEL(i)) ? 1 : 0; ch <<= 1;
		  ch |= (++i<rowlen && PIXEL(i)) ? 1 : 0; ch <<= 1;
		  ch |= (++i<rowlen && PIXEL(i)) ? 1 : 0; ch <<= 1;
		  ch |= (++i<rowlen && PIXEL(i)) ? 1 : 0;
		  putchar (ps_1bit_char[ch]);
		}
		break;


    case 4:	for (i=0; i<padlen; i++)
		{ ch = (i<rowlen) ? (PIXEL(i) >> 4) : 0; ch <<= 4;
		  ch |= (++i<rowlen) ? (PIXEL(i) >> 4) : 0;
		  putchar (ps_gray_char[ch]);
		}
		break;

    default:	for (i=0; i<padlen; i++)
		{ ch = (i<rowlen) ? PIXEL(i) : 0;
		  putchar (ps_gray_char[ch]);
		}
  }
}


/****************************************************************
 * write_simple_decoder: Write a postscript header for the image
 ****************************************************************/

write_simple_decoder (w, h, bits, iscolor)
int w, h, bits, iscolor;
{

  if (iscolor)
  { printf ("/redScanLine %d string def\n", w);
    printf ("/greenScanLine %d string def\n", w);
    printf ("/blueScanLine %d string def\n", w);
    printf ("%d %d %d [%d 0 0 -%d 0 %d]\n", w, h, bits, w, h, h);
    printf ("{currentfile redScanLine readstring pop}\n");
    printf ("{currentfile greenScanLine readstring pop}\n");
    printf ("{currentfile blueScanLine readstring pop}\n");
    printf ("true 3 colorimage\n");
  }
  else
  { 
    printf ("/scanline %d string def\n", w);
    printf ("%d %d %d\n", w, h, bits);
    printf ("[ %d 0 0 -%d 0 %d ]\n", w, h, h);
    printf ("{ currentfile scanline readstring pop } bind\n");
    printf ("image\n");
  }
}
