/*
 * tkImgTIFF.c --
 *
 * A photo image file handler for XPM files. 
 *
 * This needs libtiff 3.4beta 036 (any other version _may_ work)
 *
 * Copyright (c) 1997 by Oliver Graf <ograf@fga.de>
 *
 * Copyright (c) 1994 The Regents of the University of California.
 * Copyright (c) 1994-1996 Sun Microsystems, Inc.
 *
 * See the file "license.terms" for information on usage and redistribution
 * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
 * 
 * Adapted from tkImgXPM.c and tkImgGIF.c
 * 
 * Reed Wade (wade@cs.utk.edu), University of Tennessee
 *
 * Copyright (c) 1995-1996 Sun Microsystems, Inc.
 *
 */

#ifdef ENABLE_TIFF

#include "tkInt.h"
#include "tkPort.h"
#include <tiffio.h>

/*
 * The type record for TIFF images:
 */
static int      ImgTIFFFileMatch _ANSI_ARGS_((Tcl_Channel chan, char *fileName,
					      char *formatString,
					      int *widthPtr, int *heightPtr));

static int      ImgTIFFFileRead  _ANSI_ARGS_((Tcl_Interp *interp,
					      Tcl_Channel chan, char *fileName,
					      char *formatString,
					      Tk_PhotoHandle imageHandle,
					      int destX, int destY,
					      int width, int height,
					      int srcX, int srcY));


Tk_PhotoImageFormat tkImgFmtTIFF = {
	"TIFF",			/* name */
	ImgTIFFFileMatch,  	/* fileMatchProc */
	NULL,     	        /* stringMatchProc */
	ImgTIFFFileRead,    	/* fileReadProc */
	NULL,           	/* stringReadProc */
	NULL,           	/* fileWriteProc */
	NULL,	           	/* stringWriteProc */
};


/*
 *----------------------------------------------------------------------
 *
 * ImgTIFFFileMatch --
 *
 *  This procedure is invoked by the photo image type to see if
 *  a file contains image data in TIFF format.
 *
 * Results:
 *  The return value is 1 if the first characters in file f look
 *  like TIFF data, and 0 otherwise. 
 *
 * Side effects:
 *  None
 *
 *----------------------------------------------------------------------
 */

static int
ImgTIFFFileMatch(chan, fileName, formatString, widthPtr, heightPtr)
     Tcl_Channel chan;		/* The image file, open for reading. */
     char *fileName;		/* The name of the image file. */
     char *formatString;		/* User-specified format string, or NULL. */
     int *widthPtr, *heightPtr;	/* The dimensions of the image are
				 * returned here if the file is a valid
				 * TIFF file. */
{
  FILE *mf;
  uint16 magic;
  TIFF *tif;

  mf=fopen(fileName,"r");
  if (mf==NULL) return 0;
  if (fread(&magic,sizeof(uint16),1,mf)!=1)
    {
      fclose(mf);
      return 0;
    }
  fclose(mf);
  if (magic!=0x4d4d && magic!=0x4949) return 0;
  
  tif=TIFFOpen(fileName,"r");
  if (tif==NULL)
    {
      return 0;
    }

  TIFFGetField(tif,TIFFTAG_IMAGEWIDTH,widthPtr);
  TIFFGetField(tif,TIFFTAG_IMAGELENGTH,heightPtr);

  TIFFClose(tif);

  return 1;
}


/*
 *----------------------------------------------------------------------
 *
 * ImgTIFFFileRead --
 *
 *	This procedure is called by the photo image type to read
 *	TIFF format data from a file and write it into a given
 *	photo image.
 *
 * Results:
 *	A standard TCL completion code.  If TCL_ERROR is returned
 *	then an error message is left in interp->result.
 *
 * Side effects:
 *	New data is added to the image given by imageHandle.
 *
 *----------------------------------------------------------------------
 */

static int
ImgTIFFFileRead(interp, chan, fileName, formatString, imageHandle, destX, destY,
		width, height, srcX, srcY)
     Tcl_Interp *interp;		/* Interpreter to use for reporting errors. */
     Tcl_Channel chan;			/* The image file, open for reading. */
     char *fileName;		/* The name of the image file. */
     char *formatString;		/* User-specified format string, or NULL. */
     Tk_PhotoHandle imageHandle;	/* The photo image to write into. */
     int destX, destY;		/* Coordinates of top-left pixel in
				 * photo image to be written to. */
     int width, height;		/* Dimensions of block of photo image to
				 * be written to. */
     int srcX, srcY;		/* Coordinates of top-left pixel to be used
				 * in image being read. */
{
  int fileWidth, fileHeight;
  int nBytes, x, y;
  Tk_PhotoImageBlock block, run;
  int transparent = -1;
  TIFF *tif;
  unsigned char mapper[4]={0,1,2,3};
    
  tif=TIFFOpen(fileName,"r");
  if (tif==NULL)
    {
      return TCL_ERROR;
    }

  TIFFGetField(tif,TIFFTAG_IMAGEWIDTH,&fileWidth);
  TIFFGetField(tif,TIFFTAG_IMAGELENGTH,&fileHeight);

  if ((fileWidth <= 0) || (fileHeight <= 0))
    {
      Tcl_AppendResult(interp, "TIFF image file \"", fileName,
		       "\" has dimension(s) <= 0", (char *) NULL);
      TIFFClose(tif);
      return TCL_ERROR;
    }
    
  if ((srcX + width) > fileWidth)
    {
      width = fileWidth - srcX;
    }
  if ((srcY + height) > fileHeight)
    {
      height = fileHeight - srcY;
    }
  if ((width <= 0) || (height <= 0)
      || (srcX >= fileWidth) || (srcY >= fileHeight))
    {
      TIFFClose(tif);
      return TCL_OK;
    }
    
  Tk_PhotoExpand(imageHandle, destX + width, destY + height);

  block.width = fileWidth;
  block.height = fileHeight;
  block.pixelSize = sizeof(uint32);
  block.pitch = sizeof(uint32) * fileWidth;
  block.offset[0] = TIFFGetR(*((uint32 *)mapper));
  block.offset[1] = TIFFGetG(*((uint32 *)mapper));
  block.offset[2] = TIFFGetB(*((uint32 *)mapper));
  nBytes = fileHeight * block.pitch;
  block.pixelPtr = (unsigned char *) ckalloc((unsigned) nBytes);

  if (TIFFReadRGBAImage(tif,fileWidth,fileHeight,(uint32 *)block.pixelPtr,0)==0)
    {
      goto error;
    }

  /* Clear current contents */
  Tk_PhotoBlank(imageHandle);

  /* Setup run descriptor */
  run.height = 1;
  run.pitch = block.pitch;
  run.pixelSize = block.pixelSize;
  run.offset[0] = TIFFGetR(*((uint32 *)mapper));
  run.offset[1] = TIFFGetG(*((uint32 *)mapper));
  run.offset[2] = TIFFGetB(*((uint32 *)mapper));

  /* Copy opaque runs to photo image */
  for (y = 0; y < block.height; y++) {
    char* p = block.pixelPtr + y*block.pitch;
    char* s = p;
    int   w = 0;
    for (x = 0; x < block.width; x++) {
      if (p[TIFFGetA(*((uint32 *)mapper))]) {
	/* opaque: add pixel to current run */
	if (w == 0)
	  s = p;
	w = w + 1;
      } else if (s) {
	/* copy run to photo image */
	if (w > 0) {
	  run.width = w;
	  run.pixelPtr = s;
	  Tk_PhotoPutBlock(imageHandle, &run, x-w, block.height-y-1, run.width, 1);
	}
	w = 0;
      }
      p += block.pixelSize;
    }
    if (w > 0) {
      /* copy final run, if any */
      run.width = w;
      run.pixelPtr = s;
      Tk_PhotoPutBlock(imageHandle, &run, x-w, block.height-y-1, run.width, 1);
    }
  }
  
  ckfree((char *) block.pixelPtr);
  TIFFClose(tif);
  return TCL_OK;
  
 error:
  ckfree((char *) block.pixelPtr);
  TIFFClose(tif);
  return TCL_ERROR;

}

#endif
