#ifdef HAVE_TIFF

/*
 * xvtiffwr.c - write routine for TIFF pictures
 *
 * WriteTIFF(fp,pic,w,h,r,g,b,numcols,style,raw,fname,comment)
 */

#define NEEDSARGS
#include "xv.h"

#include "tiffio.h"    /* has to be after xv.h, as it needs varargs/stdarg */


#define ALLOW_JPEG 0  /* set to '1' to allow 'JPEG' choice in dialog box */


/*********************************************/
static void setupColormap(tif, rmap, gmap, bmap)
  TIFF *tif;
  byte *rmap, *gmap, *bmap;
{
  short red[256], green[256], blue[256];
  int i;

  /* convert 8-bit colormap to 16-bit */
  for (i=0; i<256; i++) {
#define	SCALE(x)	(((x)*((1L<<16)-1))/255)
      red[i] = SCALE(rmap[i]);
      green[i] = SCALE(gmap[i]);
      blue[i] = SCALE(bmap[i]);
  }
  TIFFSetField(tif, TIFFTAG_COLORMAP, red, green, blue);
}



/*******************************************/
static int WriteTIFF(fp,pic,ptype,w,h,rmap,gmap,bmap,numcols,colorstyle,
		     fname,comp,comment)
     FILE *fp;
     byte *pic;
     int   ptype,w,h,comp;
     byte *rmap, *gmap, *bmap;
     int   numcols, colorstyle;
     char *fname, *comment;
{
  TIFF *tif;
  byte *pix;
  int   i,j;

#ifndef VMS
  tif = TIFFOpen(fname, "w");
#else
  tif = TIFFFdOpen(dup(fileno(fp)), fname, "w");
#endif

  if (!tif) return 0;

  WaitCursor();

  TIFFSetField(tif, TIFFTAG_IMAGEWIDTH, w);
  TIFFSetField(tif, TIFFTAG_IMAGELENGTH, h);
  TIFFSetField(tif, TIFFTAG_COMPRESSION, comp);

  if (comment && strlen(comment)>0) {
    TIFFSetField(tif, TIFFTAG_IMAGEDESCRIPTION, comment);
  }

  if (comp == COMPRESSION_CCITTFAX3)
      TIFFSetField(tif, TIFFTAG_GROUP3OPTIONS,
	  GROUP3OPT_2DENCODING+GROUP3OPT_FILLBITS);

  TIFFSetField(tif, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG);
  TIFFSetField(tif, TIFFTAG_SAMPLESPERPIXEL, 1);
  TIFFSetField(tif, TIFFTAG_ORIENTATION, ORIENTATION_TOPLEFT);
  TIFFSetField(tif, TIFFTAG_ROWSPERSTRIP, h);

  /* write the image data */

  if (ptype == PIC24) {  /* only have to deal with FULLCOLOR or GREYSCALE */
    if (colorstyle == F_FULLCOLOR) {
      TIFFSetField(tif, TIFFTAG_SAMPLESPERPIXEL, 3);
      TIFFSetField(tif, TIFFTAG_BITSPERSAMPLE,   8);
      TIFFSetField(tif, TIFFTAG_PHOTOMETRIC,     PHOTOMETRIC_RGB);
      
      TIFFWriteEncodedStrip(tif, 0, pic, w*h*3);
    }

    else {  /* colorstyle == F_GREYSCALE */
      byte *tpic, *tp, *sp;

      TIFFSetField(tif, TIFFTAG_SAMPLESPERPIXEL, 1);
      TIFFSetField(tif, TIFFTAG_BITSPERSAMPLE,   8);
      TIFFSetField(tif, TIFFTAG_PHOTOMETRIC,     PHOTOMETRIC_MINISBLACK);

      tpic = (byte *) malloc(w*h);
      if (!tpic) FatalError("unable to malloc in WriteTIFF()");

      for (i=0, tp=tpic, sp=pic; i<w*h; i++, sp+=3) 
	*tp++ = MONO(sp[0],sp[1],sp[2]);
      
      TIFFWriteEncodedStrip(tif, 0, tpic, w*h);

      free(tpic);
    }
  }

  else {  /* PIC8 */
    if (colorstyle == F_FULLCOLOR) {                  /* 8bit Palette RGB */
      TIFFSetField(tif, TIFFTAG_BITSPERSAMPLE, 8);
      TIFFSetField(tif, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_PALETTE);
      setupColormap(tif, rmap, gmap, bmap);
      TIFFWriteEncodedStrip(tif, 0, pic, w*h);
    }

    else if (colorstyle == F_GREYSCALE) {             /* 8-bit greyscale */
      byte rgb[256];
      byte *tpic = (byte *)malloc(w*h);
      byte *tp = tpic;
      TIFFSetField(tif, TIFFTAG_BITSPERSAMPLE, 8);
      TIFFSetField(tif, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_MINISBLACK);
      for (i=0; i<numcols; i++) rgb[i] = MONO(rmap[i],gmap[i],bmap[i]);
      for (i=0, pix=pic; i<w*h; i++,pix++) {
	if ((i&0x7fff)==0) WaitCursor();
	*tp++ = rgb[*pix];
      }
      TIFFWriteEncodedStrip(tif, 0, tpic, w*h);
      free(tpic);
    }

    else if (colorstyle == F_BWDITHER) {             /* 1-bit B/W stipple */
      int bit,k,flipbw;
      byte *tpic, *tp;

      flipbw = (MONO(rmap[0],gmap[0],bmap[0]) > MONO(rmap[1],gmap[1],bmap[1]));
      TIFFSetField(tif, TIFFTAG_BITSPERSAMPLE, 1);
      TIFFSetField(tif, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_MINISBLACK);
      tpic = (byte *)malloc(TIFFStripSize(tif));
      tp = tpic;
      for (i=0, pix=pic; i<h; i++) {
	if ((i&15)==0) WaitCursor();
	for (j=0, bit=0, k=0; j<w; j++, pix++) {
	  k = (k << 1) | *pix;
	  bit++;
	  if (bit==8) {
	    if (flipbw) k = ~k;
	    *tp++ = (byte) (k&0xff);
	    bit = k = 0;
	  }
	} /* j */
	if (bit) {
	  k = k << (8-bit);
	  if (flipbw) k = ~k;
	  *tp++ = (byte) (k & 0xff);
	}
      }
      TIFFWriteEncodedStrip(tif, 0, tpic, TIFFStripSize(tif));
      free(tpic);
    }
  }


  TIFFClose(tif);

  return 0;
}




/**** Stuff for TIFFDialog box ****/

#define TWIDE 280
#define THIGH 160
#define T_NBUTTS 2
#define T_BOK    0
#define T_BCANC  1
#define BUTTH    24

#ifdef __STDC__
static void drawTD(int, int, int, int);
static void clickTD(int, int);
static void doCmd(int);
static void writeTIFF(void);
#else
static void drawTD(), doCmd(), clickTD(), writeTIFF();
#endif


/* local variables */
static char *filename;
static int   colorType;
static BUTT  tbut[T_NBUTTS];
static RBUTT *compRB;



/***************************************************/
void CreateTIFFW()
{
  int	     y;

  tiffW = CreateWindow("xv tiff", "XVtiff", NULL, 
		       TWIDE, THIGH, infofg, infobg, 0);
  if (!tiffW) FatalError("can't create tiff window!");

  XSelectInput(theDisp, tiffW, ExposureMask | ButtonPressMask | KeyPressMask);

  BTCreate(&tbut[T_BOK], tiffW, TWIDE-140-1, THIGH-10-BUTTH-1, 60, BUTTH, 
	   "Ok", infofg, infobg, hicol, locol);

  BTCreate(&tbut[T_BCANC], tiffW, TWIDE-70-1, THIGH-10-BUTTH-1, 60, BUTTH, 
	   "Cancel", infofg, infobg, hicol, locol);

  y = 55;
  compRB = RBCreate(NULL, tiffW, 36, y,   "None", infofg, infobg,hicol,locol);
  RBCreate(compRB, tiffW, 36, y+18,       "LZW", infofg, infobg,hicol,locol);
  RBCreate(compRB, tiffW, 36, y+36,       "PackBits", infofg, infobg,
	   hicol, locol);
  RBCreate(compRB, tiffW, TWIDE/2, y,     "CCITT Group3", infofg, infobg,
	   hicol, locol);
  RBCreate(compRB, tiffW, TWIDE/2, y+18,  "CCITT Group4", infofg, infobg,
	   hicol, locol);
  if (ALLOW_JPEG) {
    RBCreate(compRB, tiffW, TWIDE/2, y+36,  "JPEG", infofg, infobg,
	     hicol, locol);
  }

  XMapSubwindows(theDisp, tiffW);
}
  

/***************************************************/
void TIFFDialog(vis)
int vis;
{
  if (vis) {
    CenterMapWindow(tiffW, tbut[T_BOK].x + tbut[T_BOK].w/2,
		    tbut[T_BOK].y + tbut[T_BOK].h/2, TWIDE, THIGH);
  }
  else     XUnmapWindow(theDisp, tiffW);
  tiffUp = vis;
}


/***************************************************/
int TIFFCheckEvent(xev)
XEvent *xev;
{
  /* check event to see if it's for one of our subwindows.  If it is,
     deal accordingly, and return '1'.  Otherwise, return '0' */

  int rv;
  rv = 1;

  if (!tiffUp) return 0;

  if (xev->type == Expose) {
    int x,y,w,h;
    XExposeEvent *e = (XExposeEvent *) xev;
    x = e->x;  y = e->y;  w = e->width;  h = e->height;

    if (e->window == tiffW)       drawTD(x, y, w, h);
    else rv = 0;
  }

  else if (xev->type == ButtonPress) {
    XButtonEvent *e = (XButtonEvent *) xev;
    int x,y;
    x = e->x;  y = e->y;

    if (e->button == Button1) {
      if      (e->window == tiffW)     clickTD(x,y);
      else rv = 0;
    }  /* button1 */
    else rv = 0;
  }  /* button press */


  else if (xev->type == KeyPress) {
    XKeyEvent *e = (XKeyEvent *) xev;
    char buf[128];  KeySym ks;  XComposeStatus status;  
    int stlen;
	
    stlen = XLookupString(e,buf,128,&ks,&status);
    buf[stlen] = '\0';

    if (e->window == tiffW) {
      if (stlen) {
	if (buf[0] == '\r' || buf[0] == '\n') { /* enter */
	  FakeButtonPress(&tbut[T_BOK]);
	}
	else if (buf[0] == '\033') {            /* ESC */
	  FakeButtonPress(&tbut[T_BCANC]);
	}
      }
    }
    else rv = 0;
  }
  else rv = 0;

  if (rv==0 && (xev->type == ButtonPress || xev->type == KeyPress)) {
    XBell(theDisp, 50);
    rv = 1;   /* eat it */
  }

  return rv;
}


/***************************************************/
void TIFFSaveParams(fname, col)
char *fname;
int col;
{
  int cur;
  cur = RBWhich(compRB);

  filename = fname;
  colorType = col;
  if (colorType == F_BWDITHER) {
    RBSetActive(compRB,3,1);
    RBSetActive(compRB,4,1);
    if (ALLOW_JPEG) {
      RBSetActive(compRB,5,0);
      if (cur == 5) RBSelect(compRB,3);
    }
  }
  else {
    RBSetActive(compRB,3,0);
    RBSetActive(compRB,4,0);
    if (ALLOW_JPEG) RBSetActive(compRB,5,1);
    if (cur == 3 || cur == 4) RBSelect(compRB,0);
  }
}


/***************************************************/
static void drawTD(x,y,w,h)
int x,y,w,h;
{
  char *title  = "Save TIFF file...";
  int  i;
  XRectangle xr;

  xr.x = x;  xr.y = y;  xr.width = w;  xr.height = h;
  XSetClipRectangles(theDisp, theGC, 0,0, &xr, 1, Unsorted);

  XSetForeground(theDisp, theGC, infofg);
  XSetBackground(theDisp, theGC, infobg);

  for (i=0; i<T_NBUTTS; i++) BTRedraw(&tbut[i]);

  ULineString(tiffW, "Compression", compRB->x-16, compRB->y-3-DESCENT);
  RBRedraw(compRB, -1);

  XDrawString(theDisp, tiffW, theGC, 20, 29, title, strlen(title));

  XSetClipMask(theDisp, theGC, None);
}


/***************************************************/
static void clickTD(x,y)
int x,y;
{
  int i;
  BUTT *bp;

  /* check BUTTs */

  /* check the RBUTTS first, since they don't DO anything */
  if ( (i=RBClick(compRB, x,y)) >= 0) { 
    (void) RBTrack(compRB, i);
    return;
  }


  for (i=0; i<T_NBUTTS; i++) {
    bp = &tbut[i];
    if (PTINRECT(x, y, bp->x, bp->y, bp->w, bp->h)) break;
  }

  if (i<T_NBUTTS) {  /* found one */
    if (BTTrack(bp)) doCmd(i);
  }
}



/***************************************************/
static void doCmd(cmd)
int cmd;
{
  switch (cmd) {
  case T_BOK:  	writeTIFF();
  case T_BCANC:	TIFFDialog(0);
                break;

  default:	break;
  }
}


/*******************************************/
static void writeTIFF()
{
  FILE *fp;
  int   w, h, nc, rv, comp, ptype;
  byte *rmap, *gmap, *bmap;
  byte *bwpic, *thepic, *gampic24;

  nc = numcols;

  if (savenormCB.val) { thepic = cpic;  w = cWIDE;  h = cHIGH; }
                 else { thepic = epic;  w = eWIDE;  h = eHIGH; }

  /* see if we can open the output file before proceeding */
  fp = OpenOutFile(filename);
  if (!fp) return;

  WaitCursor();

  ptype = picType;

  bwpic = HandleBWandReduced(colorType, &nc, &rmap, &gmap, &bmap);
  if (bwpic) { thepic = bwpic;  ptype = PIC8; }


  /* deal with possiblity of Gamma-fication in 24-bit mode... */
  gampic24 = NULL;
  if (ptype == PIC24) {
    gampic24 = GammifyPic24(thepic, w, h);
    if (gampic24) thepic = gampic24;
  }


  if (colorType == F_REDUCED) colorType = F_FULLCOLOR;

  switch (RBWhich(compRB)) {
  case 0: comp = COMPRESSION_NONE;      break;
  case 1: comp = COMPRESSION_LZW;       break;
  case 2: comp = COMPRESSION_PACKBITS;  break;
  case 3: comp = COMPRESSION_CCITTFAX3; break;
  case 4: comp = COMPRESSION_CCITTFAX4; break;
  case 5: comp = COMPRESSION_JPEG;      break;
  default: comp = COMPRESSION_NONE;     break;
  }

  rv = WriteTIFF(fp, thepic, ptype, w, h,
      rmap, gmap, bmap, nc, colorType, filename, comp, picComments);

  SetCursors(-1);

  if (CloseOutFile(fp, filename, rv) == 0) {
    /* everything's cool! */
    DirBox(0);
  }

  if (bwpic) free(bwpic);
  if (gampic24) free(gampic24);
}


#endif /* HAVE_TIFF */
