/*
 * $Id: readtiff.cxx,v 4.2 2004/05/25 06:40:20 hut66au Exp $
 *
 * Imview, the portable image analysis application
 * http://www.cmis.csiro.au/Hugues.Talbot/imview
 * ----------------------------------------------------------
 *
 *  Imview is an attempt to provide an image display application
 *  suitable for professional image analysis. It was started in
 *  1997 and is mostly the result of the efforts of Hugues Talbot,
 *  Image Analysis Project, CSIRO Mathematical and Information
 *  Sciences, with help from others (see the CREDITS files for
 *  more information)
 *
 *  Imview is Copyrighted (C) 1997-2001 by Hugues Talbot and was
 *  supported in parts by the Australian Commonwealth Science and 
 *  Industry Research Organisation. Please see the COPYRIGHT file 
 *  for full details. Imview also includes the contributions of 
 *  many others. Please see the CREDITS file for full details.
 *
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation; either version 2 of the License, or
 *  (at your option) any later version.
 *  
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *  
 *  You should have received a copy of the GNU General Public License
 *  along with this program; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
 * */

/*------------------------------------------------------------------------
 *
 * Decodes the TIFF format.
 * Should be able to read any data format. Will deal with non-char
 * data
 *
 * Based on `loadtiff.c' by the same author
 *
 * Hugues Talbot	10 Jan 1998
 *      
 *-----------------------------------------------------------------------*/

#include "imview.hxx"

#ifdef HAVE_TIFF

#include <stdio.h>
#include <stdlib.h>
#include <tiffio.h>
#include <stdarg.h>
#include "imageIO.hxx"
#include "readtiff.hxx"


extern imageIO *IOBlackBox;
// we need to retain this information from one call to the next

static bool     handlersInPlace = false;

//
// these are the handlers for TIFF Warnings
void imviewTiffWarningHandler(const char *module, const char *fmt, va_list ap);
void imviewTiffErrorHandler(const char *module, const char *fmt, va_list ap);

int readTiffImage(const char *name,
		     int imageindex)
{
    void   *p;
    int     res, start[3], end[3];
    int     impi, imsf, imspp, imbps;
    imgtype theimgtype;
    pixtype thepixtype;
    unsigned short *cmap[3];
    long            nbcolours;

    if (!handlersInPlace) {
	TIFFSetErrorHandler(imviewTiffErrorHandler);
	TIFFSetWarningHandler(imviewTiffWarningHandler);
	handlersInPlace = true;
    }
    
    // call the low-level TIFF reader
    res = load_tiff(name, imageindex, start, end,
		    &impi, &imsf, &imspp, &imbps,
		    cmap, &nbcolours,
		    &p);

    if (res == 0) { // all went well
	// now reprocess that according to content
	if ((res = getTiffType(impi, imsf, imspp, imbps,
			       &thepixtype, &theimgtype)) == 0) {
	    // the new buffer needs to be set first before
	    // the dimensions are changed because the previous buffer
	    // might be freed, and we will need its dimensions.
	    IOBlackBox->setCurrBuffp((void **)p);
	    IOBlackBox->setCurrImgWidth(end[0]-start[0]+1);
	    IOBlackBox->setCurrImgHeight(end[1]-start[1]+1);
	    IOBlackBox->setCurrImgThickness(end[2]-start[2]+1);
	    IOBlackBox->setXOffset(start[0]);
	    IOBlackBox->setYOffset(start[1]);
	    IOBlackBox->setZOffset(start[2]);
	    IOBlackBox->setCurrImgType((imgtype)theimgtype);
	    IOBlackBox->setCurrPixType((pixtype)thepixtype);
	    IOBlackBox->setCurrImgNbComps(1); // TIFF supports multiple image in a single file, but we read them here as a time series
	    IOBlackBox->setCurrImgNbSamples(imspp);
	    IOBlackBox->setCurrImgColourMap(cmap);
	    IOBlackBox->setCurrImgNbColours(nbcolours);
	    IOBlackBox->setImgDesc("TIFF");
	}
    }	
	
    return res;
}

//
// read and render in an 8-bit buffer
//
int readTiffOverlay(const char *name)
{
    void   *p;
    int     res, start[3], end[3];
    int     impi, imsf, imspp, imbps;
    unsigned short *cmap[3];
    long            nbcolours;
    imgtype theimgtype;
    pixtype thepixtype;
    
    // call the low-level TIFF reader
    res = load_tiff(name, 0, start, end,
		    &impi, &imsf, &imspp, &imbps,
		    cmap, &nbcolours,
		    &p);

    if (res == 0) {
	if ((res = getTiffType(impi, imsf, imspp, imbps,
			       &thepixtype, &theimgtype)) == 0) {
	    // image that has just been read should have the same dimensions
	    // as the image currently displayed.
	    res = IOBlackBox->renderOverlay(name, p, imspp, start, end, thepixtype);
	    IOBlackBox->freeRawBuffers(p, imspp);
	}
    }
    
    return res;
}


#define LIARerror errprintf
#define LIARdebug dbgprintf


// this functions walks the TIFF files and counts
// the number of subfiles.
// returns a positive number if file is OK and has
// at least one subfile,
// and a negative number in case of error
int tiffnbsubfiles(const char *fname)
{
    TIFF *tif;
    int   imageindex = 0;
    
    if ((tif = TIFFOpen(fname, "r")) == NULL) {
	LIARerror("Cannot open file %s", fname);
	return(-1);
    }

    while (TIFFSetDirectory(tif, imageindex))
	imageindex++;

    TIFFClose(tif);

    return imageindex;
}


void imviewTiffWarningHandler(const char *module, const char *fmt, va_list ap)
{
    char buff[1024], newfmt[200];

    if (module) {
	sprintf(newfmt, "%s: %s", module, fmt);
	vsprintf(buff, newfmt, ap);
	warnprintf(buff);
    } else {
	vsprintf(buff, fmt, ap);
	warnprintf(buff);
    }
    
    return;
}


void imviewTiffErrorHandler(const char *module, const char *fmt, va_list ap)
{
    char buff[1024], newfmt[200];

    if (module) {
	sprintf(newfmt, "%s: %s", module, fmt);
	vsprintf(buff, newfmt, ap);
	errprintf(buff);
    } else {
	vsprintf(buff, fmt, ap);
	errprintf(buff);
    }
    
    return;
}


#include "loadtiff-code.h"


#else // HAVE_TIFF

// stubs
int readTiffImage(const char *,
		     int)
{
    errprintf("This version of Imview cannot read TIFF images\n");
    return 1;
}

int  tiffnbsubfiles(const char *)
{
    return 0;
}


//
// read and render in an 8-bit buffer
//
int readTiffOverlay(const char *)
{
    return 0;
}


#endif
