/*--------------------------------------------------------------------------*
 * 
 * This file contains the basic conversion utilities.
 *
 *  hdf_to_pixrect: Reads an hdf file and returns a pixrect.
 *  pixrect_to_hdf: Takes a pixrect and writes to an hdf file.
 *  hdf_to_rasterfile: Reads an hdf file and writes to a raster file stream.
 *  rasterfile_to_hdf: Reads a raster file stream and writes to an hdf file.
 *
 *
 *  To compile :
 *     cc -c rasutils.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 9/26/89
 * Please keep this notice with the file.
 *
 * RCS: $Id: rasutils.c,v 2.0 90/08/01 11:04:10 salem Exp $
 *  $Log:	rasutils.c,v $
 * Revision 2.0  90/08/01  11:04:10  salem
 * Bump to next release, no changes
 * 
 * Revision 1.1  90/07/30  18:36:17  salem
 * Initial revision
 * 
 *
 *--------------------------------------------------------------------------*/

#include "utils.h"
#include <pixrect/pixrect_hs.h>

void
  free_colormap_arrays (colormap)
colormap_t *colormap;
{
  if (colormap->type != RMT_NONE) {
    free (colormap->map[0]);
    free (colormap->map[1]);
    free (colormap->map[2]);
    colormap->type = RMT_NONE;
  }
}

void
  compress_pixrect_array (dest, source, dest_width, source_width, height)
char *source,*dest;
int source_width, dest_width, height;
/* Takes out the leftover bytes on the end of each row of a pixrect array */
{
  int i;
  for (i = 0; i< height; ++i, dest += dest_width, source += source_width)
    memcpy (dest, source, dest_width);
}  

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

struct pixrect *
  hdf_to_pixrect(hdf_file, index, colormap)
char *hdf_file;
int index;
colormap_t *colormap;
/* This reads in an hdf image, allocates a pixrect to hold it, and writes it 
   into the pix rect.
   If the HDF image has a palette, colormap arrays are allocated for it and 
   the colormap structure is updated.
   [Use free_colormap_arrays to free up the space.]

   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 the pixrect on success or 0 on error; check the values of DFerror 
     or errno.
  */
{
  struct pixrect  *pixrect;
  int xdim, ydim, ispalette, i;
  unsigned char palette[HDF_COLORMAP_SIZE][3];

  /* Invalidate colormap (to avoid inadvertent frees in the case of an error) */
  colormap->type = RMT_NONE;
  colormap->length = 0;

  /* 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 pixrect */
  pixrect = mem_create (xdim, ydim, 8);

  /* Get the data */
  if (DFR8getimage (hdf_file, (char *) mpr_d(pixrect)->md_image,
		    mpr_linebytes (xdim, 8), ydim, (unsigned char *) palette))
    {/* Error occurred, deallocate and return */
      pr_destroy(pixrect);
      ERROR_RETURN;
    }

  /* Fill the colormap structure (if necessary) */
  if (colormap && ispalette) {
    unsigned char *map[3];
    int map_num;

    /* Allocate the map arrays */
    map[0] = (unsigned char *) malloc(HDF_COLORMAP_SIZE);
    if (!map[0]) {pr_destroy(pixrect); ERROR_RETURN;}
    map[1] = (unsigned char *) malloc(HDF_COLORMAP_SIZE);
    if (!map[1]) {free(map[0]); pr_destroy(pixrect); ERROR_RETURN;}
    map[2] = (unsigned char *) malloc(HDF_COLORMAP_SIZE);
    if (!map[2])
      {free(map[1]); free(map[0]); pr_destroy(pixrect); ERROR_RETURN;}
	
    /* reorder the data and add pointers to color map struct */
    for (map_num = 0; map_num < 3; ++map_num) {
      colormap->map[map_num] = map[map_num];
      for (i = 0; i < HDF_COLORMAP_SIZE; ++i)
	(map[map_num])[i] = palette[i][map_num];
    }
    /* Change colormap type */
    colormap->type = RMT_EQUAL_RGB;
    colormap->length = HDF_COLORMAP_SIZE;
  }
  /* Done ! */
  return pixrect;
}

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

int
  pixrect_to_hdf(pixrect, colormap, hdf_file, appendp, compression_type)
struct pixrect *pixrect;
colormap_t *colormap;
char *hdf_file;
int appendp, compression_type;
/* This writes a pixrect to an hdf file.
   If the pixrect has a colormap, an HDF palette is written.

   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 xdim, ydim, ret;
  char *array, *temp_array;
  unsigned char palette[HDF_COLORMAP_SIZE][3];

  /* Check depth */
  if (pixrect->pr_depth != 8) {
    DFerror = LDFE_BADDEPTH;
    ERROR_RETURN;
  }

  /* initialize */
  xdim = pixrect->pr_width;
  ydim = pixrect->pr_height;
  array = ((char *) mpr_d(pixrect)->md_image)
      + mpr_d(pixrect)->md_linebytes * mpr_d(pixrect)->md_offset.y
      + mpr_d(pixrect)->md_offset.x;
  temp_array = NULL;
    
  /* Handle colormap */
  if (colormap && colormap->type == RMT_EQUAL_RGB)
    {int i, c, len;

     len = colormap->length;
     if (len > HDF_COLORMAP_SIZE) len = HDF_COLORMAP_SIZE;

     for (i = 0; i < len; ++i)
       for (c = 0; c < 3; ++c)
	 palette[i][c] = (colormap->map[c])[i];

     /* Fill in empty slots with white. */
     for (i = len; i < HDF_COLORMAP_SIZE; ++i)
       for (c = 0; c < 3; ++c)
	 palette[i][c] = 255;

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

  /* If the image width differs from the array width, squish it down */
  if (xdim != mpr_d(pixrect)->md_linebytes) {
    temp_array = malloc(xdim * ydim);
    if (!temp_array) ERROR_RETURN;
    compress_pixrect_array (temp_array, array,
			    xdim, mpr_d(pixrect)->md_linebytes, ydim);
    array = temp_array;
  }

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

  /* Delete the temp_array if necessary */
  if (temp_array) free (temp_array);

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

int
  hdf_to_rasterfile (hdf_file, index, ras_file)
char *hdf_file;
int index;
FILE *ras_file;
/* This reads in an hdf image and writes it to a rasterfile.
   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.
  */
{
  struct pixrect *pixrect;
  colormap_t colormap;
  int ret;

  pixrect = hdf_to_pixrect(hdf_file, index, &colormap);
  if (!pixrect) ERROR_RETURN;

  ret = pr_dump(pixrect, ras_file, &colormap, RT_STANDARD, 0);
  pr_destroy(pixrect);
  free_colormap_arrays(&colormap);
  if (ret)
    return False;
  else
    return True;
}

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

int
  rasterfile_to_hdf (ras_file, hdf_file, appendp)
FILE *ras_file;
char *hdf_file;
int appendp;
/* This reads in a rasterfile and writes it a hdf file.
   If appendp is non-zero, the image is appended to the file.
   Returns non-zero on success or 0 on error; check the values of DFerror 
     or errno.
  */
{
  struct pixrect *pixrect;
  colormap_t colormap;
  int ret;

  DFerror = DFE_NOERROR;	/* reset error code (in case the pr_load
				   fails we don't want it looking like an
				   HDF problem) */

  pixrect = pr_load(ras_file, &colormap);
  if (!pixrect) ERROR_RETURN;

  ret = pixrect_to_hdf(pixrect, &colormap, hdf_file, appendp, NULL);
  pr_destroy (pixrect);
  free_colormap_arrays(&colormap);
  return ret;
}

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