/*****************************************************************
 * tiff2fbm.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.
 *
 * tiff2fbm.c: 
 *	Convert a TIFF format image to FBM format.  Uses Sam Leffler's
 *	libtiff.a TIFF image library to read TIFF format.  See also,
 *	fbm2tiff for the opposite conversion.
 *
 * USAGE
 *	% tiff2fbm [ -<num> ] foo.tif > foo.fbm
 *
 * EDITLOG
 *	LastEditDate = Mon Jun 25 00:18:45 1990 - Michael Mauldin
 *	LastFileName = /usr2/mlm/src/misc/fbm/tiff2fbm.c
 *
 * HISTORY
 * 25-Jun-90  Michael Mauldin (mlm@cs.cmu.edu) Carnegie Mellon
 *	Package for Release 1.0
 *
 * 20-Jun-90  Paul Milazzo (milazzo) at BBN
 *	Patched for STDC.
 *
 * 14-Jun-89  Michael Mauldin (mlm) at Carnegie-Mellon University
 *	Created.  Based on tiff2ps by Sam Leffler.
 *****************************************************************/

# include <stdio.h>
# include <ctype.h>
# ifdef BYTE
# undef BYTE
# endif
# include <tiff.h>
# include <tiffio.h>
# include "fbm.h"

# ifdef __STDC__
#   define FIELD(tif,f)	TIFFFieldSet(tif, FIELD_ ## f)
# else
    /* The following macro is taken from tiff_print.c */
#   define FIELD(tif,f)	TIFFFieldSet(tif, FIELD_/**/f)
# endif

# define USAGE "Usage: tiff2fbm [ -<num> ] foo.tif > foo.fbm"

/****************************************************************
 * main
 ****************************************************************/

#ifndef lint
static char *fbmid =
"$FBM tiff2fbm.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

#define	howmany(x, y)	(((x)+((y)-1))/(y))

main (argc, argv)
char *argv[];
{ FBM image;
  int userdir = 1, fw, fh, rowlen, plnlen, clrlen=0, colors=0;
  double aspect = 0.0;
  char *fname = NULL, *title = NULL, *credits = NULL;

  TIFF *tif;
  TIFFDirectory *td;
  u_char *scanbuf, *tail;
  register u_char *pp, *obm, *tmp;
  int bitspersample, scanline, samplesperbyte;
  register unsigned int mask;
  register int shift, nib;
  register int poff, k, planes;
  int i, j, w, h, dirnum = 0;

  /* Get the options */
  while (--argc > 0 && (*++argv)[0] == '-')
  { while (*++(*argv))
    { switch (**argv)
      {
	case 'a':	aspect = atof (*argv+1); SKIPARG; break;
	case 't':	title = *argv+1; SKIPARG; break;
	case 'c':	credits = *argv+1; SKIPARG; break;
	default:        if (!isdigit (argv[0][1]))
			{ fprintf (stderr, "%s\n", USAGE);
                          exit (1);
			}
			else
			{ userdir = atoi (*argv+1);
			  SKIPARG;
			}
      }
    }
  }

  /* Get name of input file */
  if (argc != 1)
  { fprintf (stderr, "%s\n", USAGE);
    exit (1);
  }
  
  fname = *argv;

  /* Clear the memory pointers so alloc_fbm won't be confused */
  image.cm  = image.bm  = (unsigned char *) NULL;

  /* Now read in the TIFF format image */
  /*------------------------------*/

  if ((tif = TIFFOpen(fname, "r")) == NULL)
  { exit (1); }

  do
  { ++dirnum;

    if (userdir != dirnum) continue;

    td = &tif->tif_dir;
    bitspersample = td->td_bitspersample;
    planes = td->td_samplesperpixel;

    if (td->td_planarconfig == PLANARCONFIG_CONTIG)
    { bitspersample *= planes; }

    scanline = howmany (bitspersample * td->td_imagewidth, 8);
    scanbuf = (u_char *) malloc (scanline);
    if (scanbuf == NULL)
    { printf ("No space for scanline buffer\n");
      continue;
    }

    w = td->td_imagewidth;
    h = td->td_imagelength;

    switch (bitspersample)
    { case 1:	samplesperbyte = 8; break;
      case 2:	samplesperbyte = 4; break;
      case 4:	samplesperbyte = 2; break;
      case 8:	samplesperbyte = 1; break;
      case 24:	samplesperbyte = 1; break;
      default:	fprintf (stderr, "I can't handle %d bits per sample\n",
			bitspersample);
		exit (1);
    }

    /* Now build FBM image header */
    
    if (bitspersample == 1)
    { rowlen = 16 * ((w+15)/16); }
    else
    { rowlen = 2 * ((w+1)/2); }

    plnlen = rowlen * h;

    /* Build header */
    image.hdr.title[0] = image.hdr.credits[0] = '\0';
    
    image.hdr.rows = h;
    image.hdr.cols = w;
    image.hdr.planes = planes;
    image.hdr.bits = bitspersample / planes;
    image.hdr.physbits = 8;
    image.hdr.rowlen = rowlen;
    image.hdr.plnlen = plnlen;
    colors = FIELD (tif,COLORMAP) ? (1 << td->td_bitspersample) : 0;
    image.hdr.clrlen = colors * 3;


    /* Determine aspect from X and Y resolution */
    if (FIELD (tif,RESOLUTION) && td->td_yresolution != 0)
    { image.hdr.aspect = td->td_xresolution / td->td_yresolution; }
    else
    { image.hdr.aspect = 1.0; }

    /* Extract Title and Credit information */
    if (FIELD (tif,DOCUMENTNAME))
    { strcpy (image.hdr.title, td->td_documentname); }
    else if (FIELD (tif,IMAGEDESCRIPTION))
    { strcpy (image.hdr.title, td->td_imagedescription); }
    else
    { strcpy (image.hdr.title, fname); }
    
    if (FIELD (tif,ARTIST))
    { strcpy (image.hdr.credits, td->td_artist); }
    else if (FIELD (tif,SOFTWARE))
    { strcpy (image.hdr.credits, td->td_software); }
    else if (FIELD (tif,MAKE))
    { strcpy (image.hdr.credits, td->td_make);
      if (FIELD (tif,MODEL))
      { strcat (image.hdr.credits, ", ");
        strcat (image.hdr.credits, td->td_model);
      }
    }

    fprintf (stderr, "Reading \"%s\" [%dx%d], %d bits, directory %d\n",
	     image.hdr.title, w, h, bitspersample, userdir);

    /*----------------------------------------------------------------*/

    alloc_fbm (&image);

    /* Read colormap: Note TIFF colors are 16 bit, FBM colors 8 bit */
    if (FIELD (tif,COLORMAP))
    { for (i=0; i<colors; i++)
      { image.cm[i]			= td->td_redcolormap[i] >> 8;
        image.cm[i + colors]		= td->td_greencolormap[i] >> 8;
        image.cm[i + colors + colors]	= td->td_bluecolormap[i] >> 8;
      }
    }


    /* Check for multiplane images */
    if (td->td_planarconfig == PLANARCONFIG_SEPARATE &&
        planes > 1)
    { fprintf (stderr, "Multiplane images (%d) not yet implemented\n",
	       planes);
      exit (1);
    }

    else
    {

      /*
       * Read single plane images (for RGB color, values are stored in 
       * successive bytes)
       */
  
      /* Precompute mask and shift parameters */
      switch (samplesperbyte)
      { case 8:	mask = 0x01; shift = 1; break;
	case 4:	mask = 0x03; shift = 2; break;
	case 2:	mask = 0x0f; shift = 4; break;
	case 1:	mask = 0xff; shift = 8; break;
      }
      nib = 8 - shift;
  
      fprintf (stderr, "Samples per byte %d, mask %02x, shift %d, planes %d, scanline %d\n", 
		samplesperbyte, mask, shift, planes, scanline);

      /* Each loop does one scan line */
      for (j=0; j<h; j++)
      { if (TIFFReadScanline (tif, scanbuf, j, 0) < 0)
	{ fprintf (stderr, "Error: only read %d lines\n", j); break; }
    
	/* If 0 is WHITE, then flip all bits in the scanline */
	if (td->td_photometric == PHOTOMETRIC_MINISWHITE)
	{ for (pp = scanbuf, i=scanline; --i >= 0; pp++)
	  { *pp = ~ *pp; }
	}
    
	pp = scanbuf;
	obm = &image.bm[j * rowlen];
	tmp = obm;
	tail = obm + w;
    
	if (samplesperbyte > 1)
	{ for (; obm < tail; obm++)
	  { for (k=0, poff=0; k<planes; k++, poff += plnlen)
	    { obm[poff] = (*pp >> nib) & mask;
# ifdef DEBUG
	      if (j< 10 && (obm-tmp)< 18)
	      { fprintf (stderr, "<%2d,%2d>  obm[%d] = %d, nib %d, mask %d, pp %08x\n",
			(obm-tmp), j, poff, obm[poff], nib, mask, pp);
	      }
# endif
	      if ((nib -= shift) < 0) { pp++; nib = 8 - shift; }
	    }
	  }
	}
    
	else
	{ for (; obm < tail; obm++)
	  { for (k=0, poff=0; k<planes; k++, poff += plnlen)
	    { obm[poff] = *pp++; }
	  }
	}
      }
    }
  } while (TIFFReadDirectory (tif));

  /*----------------------------------------------------------------*/

  if (tif)
  { TIFFClose (tif); }

  /* Check whether an image was read */
  if (userdir > dirnum)
  { if (dirnum > 0)
    { fprintf (stderr, "File %s has only %d directories, %d out of range\n",
		fname, dirnum, userdir);
    }
    else
    { fprintf (stderr, "File %s has no directories\n", fname); }
    
    exit (1);
  }

  /*------------------------------*/

  if (aspect != 0.0)
  { fprintf (stderr,
	     "Overiding aspect ratio read (%1.3lf) with (%1.3lf)\n",
	     image.hdr.aspect, aspect);
    image.hdr.aspect = aspect;
  }

  if (title)
  { strncpy (image.hdr.title, title, FBM_MAX_TITLE); }

  if (credits)
  { strncpy (image.hdr.credits, credits, FBM_MAX_TITLE); }

  if (write_bitmap (&image, stdout, FMT_FBM))
  { exit (0); }

  exit (1);
}
