/*--------------------------------------------------------------------------*
 * 
 * This file contains the basic conversion utilities.
 *
 *  hdf_to_tiff: Reads an hdf file and writes to a tiff file.
 *  tiff_to_hdf: Reads a tiff file and writes to an hdf file.
 *  hdf_to_tiff_file:
 *  tiff_file_to_hdf:
 *
 *  To compile :
 *     cc -c tiffutils.c
 *
 * 				NO WARRANTY
 *  
 *  This software is distributed free of charge and is in the public domain.
 *  Anyone may use, duplicate or modify this program.  Thinking Machines
 *  Corporation does not restrict in any way the use of this software by
 *  anyone.
 *  
 *  Thinking Machines Corporation provides absolutely no warranty of any kind.
 *  The entire risk as to the quality and performance of this program is with
 *  you.  In no event will Thinking Machines Corporation be liable to you for
 *  damages, including any lost profits, lost monies, or other special,
 *  incidental or consequential damages arising out of the use of this program.
 * 
 * Jim Salem 4/24/90
 * Please keep this notice with the file.
 *
 * RCS: $Id: tiffutils.c,v 2.0 90/08/01 11:04:15 salem Exp $
 *  $Log:	tiffutils.c,v $
 * Revision 2.0  90/08/01  11:04:15  salem
 * Bump to next release, no changes
 * 
 * Revision 1.2  90/08/01  10:21:04  salem
 * Change color rounding slightly
 * 
 * Revision 1.1  90/07/30  18:37:21  salem
 * Initial revision
 * 
 *
 *--------------------------------------------------------------------------*/

#include "utils.h"
#include <tiff/tiffio.h>

extern char * get_date_time(), * get_host_computer(), * get_artist();

#define DESIRED_STRIP_SIZE 8192

int TIFFInternal_counter;
int TIFFInternal_result;
#define TIFFFieldSafe(error)                                     \
  for (TIFFInternal_counter = 0;;++TIFFInternal_counter)         \
    if (TIFFInternal_counter != 0) {                             \
      if (TIFFInternal_result <= 0) {                            \
	 DFerror = (error);                                      \
	 ERROR_RETURN;                                           \
	 }                                                       \
      break;                                                     \
      }                                                          \
    else                                                         \
      TIFFInternal_result =
  
#define TIFFSetFieldSafe      TIFFFieldSafe(LDFE_TIFFERR) TIFFSetField
#define TIFFGetFieldSafe      TIFFFieldSafe(LDFE_TIFFERR) TIFFGetField
#define TIFFFlushSafe         TIFFFieldSafe(LDFE_TIFFIO) TIFFFlush
#define TIFFWriteScanlineSafe TIFFFieldSafe(LDFE_TIFFIO) TIFFWriteScanline
#define TIFFReadScanlineSafe  TIFFFieldSafe(LDFE_TIFFIO) TIFFReadScanline
  
/*--------------------------------------------------------------------------*/

Boolean
  hdf_to_tiff(hdf_file, index, tiff_file, compression_type)
char *hdf_file;
int index, compression_type;
TIFF *tiff_file;
/* This reads in an hdf image, and writes a tiff file.

   If the HDF image has a palette, a colormap is also written.

   index identifies the particular image within the hdf file (normally 0)
   If index is -1, the hdf file is not reset and the next image is read.

   Returns non-zero on success or 0 on error; check the values of DFerror 
     or errno.
  */
{
  int xdim, ydim, ispalette, i, map_num;
  unsigned char  hdf_map[HDF_COLORMAP_SIZE][3];
  unsigned short tiff_map[3][HDF_COLORMAP_SIZE];
  unsigned char *buffer;

  /* Default compression type */
  if (!compression_type)
    compression_type = COMPRESSION_LZW;     

  /* First, point to the right place in the image file */
  if (index != -1) {
    if (DFR8restart()) ERROR_RETURN;
    for (i = 0; i < index; ++i)
      if (DFR8getdims (hdf_file,&xdim,&ydim,&ispalette)) ERROR_RETURN;
  }
  /* Read the size */
  if (DFR8getdims (hdf_file,&xdim,&ydim,&ispalette)) ERROR_RETURN;

  /* Allocate a buffer */
  buffer = (unsigned char *) malloc(xdim*ydim);

  /* Get the data */
  if (DFR8getimage (hdf_file, buffer, xdim, ydim, (unsigned char *) hdf_map))
    {/* Error occurred, deallocate and return */
      free(buffer);
      ERROR_RETURN;
    }

  /* Fill the colormap structure (if necessary) */
  if (ispalette) {
    /* reorder and scale the data */
    for (map_num = 0; map_num < 3; ++map_num)
      for (i = 0; i < HDF_COLORMAP_SIZE; ++i)
	tiff_map[map_num][i] = hdf_map[i][map_num]*256+127;
  }

  /* Write the tiff file */
  TIFFSetFieldSafe(tiff_file, TIFFTAG_ARTIST, get_artist());
  TIFFSetFieldSafe(tiff_file, TIFFTAG_DATETIME, get_date_time());
  TIFFSetFieldSafe(tiff_file, TIFFTAG_HOSTCOMPUTER, get_host_computer());
  TIFFSetFieldSafe(tiff_file, TIFFTAG_IMAGEDESCRIPTION,
		   "Image converted from hdf file.");
  TIFFSetFieldSafe(tiff_file, TIFFTAG_SOFTWARE, "hdf2tiff");
  TIFFSetFieldSafe(tiff_file, TIFFTAG_IMAGEWIDTH, xdim);
  TIFFSetFieldSafe(tiff_file, TIFFTAG_IMAGELENGTH, ydim);
  TIFFSetFieldSafe(tiff_file, TIFFTAG_BITSPERSAMPLE, 8);
  TIFFSetFieldSafe(tiff_file, TIFFTAG_SAMPLESPERPIXEL, 1);
  TIFFSetFieldSafe(tiff_file, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG);
  if (ispalette) {
    TIFFSetFieldSafe(tiff_file, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_PALETTE);
    TIFFSetFieldSafe(tiff_file, TIFFTAG_COLORMAP,
		     &tiff_map[0][0], &tiff_map[1][0], &tiff_map[2][0]);
  }
  else
    TIFFSetFieldSafe(tiff_file, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_MINISBLACK);
  TIFFSetFieldSafe(tiff_file, TIFFTAG_COMPRESSION, compression_type);
  TIFFSetFieldSafe(tiff_file, TIFFTAG_ROWSPERSTRIP, MAX(1, 8192 / xdim));

  for (i = 0; i < ydim; i++)
    TIFFWriteScanlineSafe(tiff_file, buffer+(i*xdim), i, 0);
  free(buffer);
  TIFFFlushSafe(tiff_file);
  return True;
}

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

Boolean
  tiff_to_hdf(tiff_file, hdf_file, appendp, compression_type)
TIFF *tiff_file;
char *hdf_file;
Boolean appendp;
int compression_type;
/* This copies a TIFF file to an hdf file.

   If appendp is 0 the file is overwritten with the image.  Otherwise, the image
   is appended to the file.

   Returns non-zero on success or 0 on error; check the values of DFerror 
     or errno.
  */
{
  int i, ret;
  unsigned short xdim, ydim, bitspersample, numsamples, photometric;
  char *buffer;
  unsigned char hdf_map[HDF_COLORMAP_SIZE][3];
  unsigned short *tiff_map[3];

  /* Check depth */
  TIFFGetFieldSafe(tiff_file, TIFFTAG_BITSPERSAMPLE, &bitspersample);
  TIFFGetFieldSafe(tiff_file, TIFFTAG_SAMPLESPERPIXEL, &numsamples);
  if (bitspersample != 8 || numsamples != 1) {
    DFerror = LDFE_BADDEPTH;
    ERROR_RETURN;
  }

  /* initialize array */
  TIFFGetFieldSafe(tiff_file, TIFFTAG_IMAGEWIDTH,  &xdim);
  TIFFGetFieldSafe(tiff_file, TIFFTAG_IMAGELENGTH, &ydim);
  buffer = (char *) malloc(xdim * ydim);
  
  /* Transfer the data */
  for (i=0;i<ydim;++i)
    TIFFReadScanlineSafe(tiff_file, buffer+(i*xdim), i, 0);
    
  /* Handle colormap */
  TIFFGetFieldSafe(tiff_file, TIFFTAG_PHOTOMETRIC, &photometric);
  if (photometric == PHOTOMETRIC_PALETTE)
    {int map;
     TIFFGetFieldSafe (tiff_file, TIFFTAG_COLORMAP,
		       &tiff_map[0], &tiff_map[1], &tiff_map[2]);

     for (i = 0; i < HDF_COLORMAP_SIZE; ++i)
       for (map = 0; map < 3; ++map)
	 hdf_map[i][map] = (tiff_map[map])[i]>>8;

     /*  set the palette */
     if (DFR8setpalette(hdf_map)) ERROR_RETURN;
   }
  else
    /* clear the palette */
    if (DFR8setpalette(NULL)) ERROR_RETURN;


  /* Now write the image */
  if (appendp)
    ret = DFR8addimage(hdf_file, buffer, xdim, ydim, compression_type);
  else
    ret = DFR8putimage(hdf_file, buffer, xdim, ydim, compression_type);

  /* Delete the temp_buffer if necessary */
  free (buffer);

  /* Done ! */
  return (! ret);
}

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

Boolean
  hdf_to_tiff_file(hdf_filename, index, tiff_filename, appendp, compression_type)
char *hdf_filename, *tiff_filename;
int compression_type;
int index;
Boolean appendp;
/* This reads in an hdf image and writes it to a TIFF format file.
   index identifies the particular image within the hdf file (normally 0)
   If index is -1, the hdf file is not reset and the next image is read.

   Returns non-zero on success or 0 on error; check the values of DFerror 
     or errno.
  */
{
  TIFF *tiff_file;

  if (appendp)
    tiff_file = TIFFOpen(tiff_filename, "a");
  else
    tiff_file = TIFFOpen(tiff_filename, "w");

  if (! tiff_file) {
    DFerror = LDFE_TIFFOPEN;
    ERROR_RETURN;
  }
    
  if (!hdf_to_tiff (hdf_filename, index, tiff_file, compression_type))
    ERROR_RETURN;

  TIFFClose(tiff_file);

  return True;
}
  
/*--------------------------------------------------------------------------*/

Boolean
  tiff_file_to_hdf(tiff_filename, index, hdf_filename, appendp, compression_type)
char *hdf_filename, *tiff_filename;
int compression_type, index;
Boolean appendp;
/* This reads in a tiff file and writes it to an HDF format file.

   Returns non-zero on success or 0 on error; check the values of DFerror 
     or errno.
  */
{
  TIFF *tiff_file;
  int i;

  tiff_file = TIFFOpen(tiff_filename, "r");

  if (! tiff_file) {
    DFerror = LDFE_TIFFOPEN;
    ERROR_RETURN;
  }

  for (i = 0; i < index; ++i)
    if (! TIFFReadDirectory (tiff_file)) {
      DFerror = LDFE_TIFFINDEX;
      ERROR_RETURN;
    }      
    
  if (!tiff_to_hdf (tiff_file, hdf_filename, appendp, compression_type))
    ERROR_RETURN;

  TIFFClose(tiff_file);

  return True;
}
  
  
