 /*
  * Khoros: $Id: lviff2tiff.c,v 1.2 1991/07/15 06:05:39 khoros Exp $
  */

#if !defined(lint) && !defined(SABER)
static char rcsid[] = "Khoros: $Id: lviff2tiff.c,v 1.2 1991/07/15 06:05:39 khoros Exp $";
#endif

 /*
  * $Log: lviff2tiff.c,v $
 * Revision 1.2  1991/07/15  06:05:39  khoros
 * HellPatch1
 *
  */ 

/*
 *----------------------------------------------------------------------
 *
 * Copyright 1991, University of New Mexico.  All rights reserved.
 * Permission to copy and modify this software and its documen-
 * tation only for internal use in your organization is hereby
 * granted, provided that this notice is retained thereon and
 * on all copies.  UNM makes no representations as too the sui-
 * tability and operability of this software for any purpose.
 * It is provided "as is" without express or implied warranty.
 * 
 * UNM DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FIT-
 * NESS.  IN NO EVENT SHALL UNM BE LIABLE FOR ANY SPECIAL,
 * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY OTHER DAMAGES WHAT-
 * SOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
 * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
 * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PER-
 * FORMANCE OF THIS SOFTWARE.
 * 
 * No other rights, including for example, the right to redis-
 * tribute this software and its documentation or the right to
 * prepare derivative works, are granted unless specifically
 * provided in a separate license agreement.
 *---------------------------------------------------------------------
 */

#include "unmcopyright.h"        /* Copyright 1991 by UNM */

/*>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>  <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
 >>>>
 >>>>         File Name: lviff2tiff.c
 >>>>
 >>>>      Program Name: viff2tiff
 >>>>
 >>>> Date Last Updated: Mon Mar 11 17:22:12 1991 
 >>>>
 >>>>          Routines: lviff2tiff - the library call for viff2tiff
 >>>>
 >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>   <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<*/


#include "vinclude.h"


/* -library_includes */
#include "file_formats/tiffio.h"
#include "vrev.h"
#define SCALE(x)        (((x)*((1L<<16)-1))/255)
/* -library_includes_end */


/****************************************************************
*
* Routine Name: lviff2tiff - library call for viff2tiff
*
* Purpose:
*    
*    Convert a VIFF image to a TIFF image
*    
*    
* Input:
*    
*         TIFF *tif - pointer  to  the  tif  image  structure  (header
*         returned by TIFFOpen opened for reading)
*    
*         struct xvimage *viff - pointer to a pointer of a VIFF  image
*         file.
*    
*         int verbose - if set prints image header information
*    
*         int compression - defines the compression type, valid inputs
*         are            COMPRESSION_NONE,            COMPRESSION_LZW,
*         COMPRESSION_CCITTFAX3,                COMPRESSION_CCITTRLEW,
*         COMPRESSION_PACKBITS
*    
*         char *filename - the name of the input file
*    
*    
* Output:
*    
*         TIFF *tif - pointer to the tif  image  structure  containing
*         the converted image
*    
*         lviff2tiff returns a 1 upon sucess and a 0 upon failure.
*    
*    
*
* Written By: Tom Sauer
*    
*    
****************************************************************/


/* -library_def */
int lviff2tiff(tif, viff_image, verbose, compression, filename)

struct xvimage *viff_image;
TIFF *tif;
int verbose, compression;
char *filename;
/* -library_def_end */

/* -library_code */
{

    unsigned short  width, height, maplen;
    unsigned short  maprow, mapcol, stripsperimage, samplesperpixel;
    unsigned short  stripbytecounts, bitspersample, photometric;
    unsigned long   bytesperrow, rowsperstrip;
    time_t          clock;
    int             i, s, row, band;
    unsigned char  *rptr, *gptr, *bptr, *buf, *ptr;
    unsigned short red[256], green[256], blue[256];

    char   *program = "lviff2tiff";
    char   *version = "Khoros viff2tiff";
    char   desc[512];
 
    sprintf(desc, "converted Khoros VIFF image, Release %d, Version %d",
                viff_image->release, viff_image->version);

    /* make sure the VIFF image is convertable */
    if ((!propertype (program, viff_image, VFF_TYP_BIT, FALSE)) &&
            (!propertype (program, viff_image, VFF_TYP_1_BYTE, FALSE))) {
        fprintf (stderr, 
                "%s: VIFF image stored in an unconvertable data type.\n",
                program);
        fprintf (stderr, "Should be either bit or byte.\n");
        return (0);
    }

    if ((!proper_map_type (program, viff_image, VFF_MAPTYP_NONE, FALSE)) &&
            (!proper_map_type (program, viff_image, VFF_MAPTYP_1_BYTE, FALSE))) 
    {
        fprintf (stderr, "%s: Map stored in unconvertable format.\n", program);
        fprintf (stderr, 
                 "Should be either VFF_MAPTYP_NONE or VFF_MAPTYP_1_BYTE.\n");
        return (0);
    }

    if ((!proper_num_bands (program, viff_image, 1, FALSE)) &&
            (!proper_num_bands (program, viff_image, 3, FALSE))) 
    {
        fprintf (stderr, "%s: Image must have either 1 or 3 bands.\n", program);
        return (0);
    }

    if ((!proper_map_scheme (program, viff_image, VFF_MS_NONE, FALSE)) &&
            (!proper_map_scheme (program, viff_image, VFF_MS_ONEPERBAND, FALSE))
            && (!proper_map_scheme (program, viff_image, VFF_MS_SHARED, FALSE)))
    {
        fprintf (stderr, "%s: Unconvertable mapping scheme used.\n", program);
        fprintf (stderr, 
         "Should be either VFF_MS_NONE, VFF_MS_ONEPERBAND or VFF_MS_SHARED.\n");
        return (0);
    }

    if (!proper_num_images (program, viff_image, 1, FALSE)) {
        fprintf (stderr, "%s: Can only convert files containing 1 image.\n",
                program);
        return (0);
    }
    if ((!proper_color_model (program, viff_image, VFF_CM_NONE, FALSE)) 
          &&(!proper_color_model(program, viff_image, VFF_CM_genericRGB, FALSE))
          &&(!proper_color_model(program, viff_image, VFF_CM_ntscRGB, FALSE)) 
          &&(!proper_color_model (program, viff_image, VFF_CM_cieRGB, FALSE))) 
    {
        fprintf (stderr, "%s: WARNING: Image uses non-RGB color space model.\n",
                program);
        fprintf (stderr, "Image will be interpreted as an RGB image.\n");
    }

    if ((!proper_map_type (program, viff_image, VFF_MAPTYP_NONE, FALSE))
           && (proper_num_bands (program, viff_image, 3, FALSE))) {
        fprintf (stderr, 
                "%s: Can not convert an image with 3 bands and a map.\n",
                program);
        return (0);
    }

    if ((proper_map_type (program, viff_image, VFF_MAPTYP_1_BYTE)) 
           && (viff_image->map_row_size != 1) && (viff_image->map_row_size != 3))
    {
        fprintf (stderr,
                "%s: The VIFF image map must only contain 1 or 3 columns.\n",
                program);
        fprintf (stderr,"\tThis image contains a map with %d columns\n",
                viff_image->map_row_size);
        return (0);
    }

        /* if verbose mode give image info */

    if (verbose)
    {
        fprintf(stderr,"Input VIFF Image Information\n");
        fprintf(stderr,
            "-----------------------------------------------------\n\n");

        if (! lvfileinfo(viff_image, filename, stderr))
          fprintf(stderr, "%s: Unable to obtain VIFF file information\n",
                program);
    }

        
    /* set up variables to be used to construct the Raster file header */

    width   = (unsigned short) viff_image->row_size;
    height  = (unsigned short) viff_image->col_size;
    mapcol  = (unsigned short) viff_image->map_row_size;
    maprow  = (unsigned short) viff_image->map_col_size;
    maplen  = maprow * mapcol;


        /* set some of the TIFF image parameters based on the VIFF info */

    switch (viff_image->data_storage_type) {
        case VFF_TYP_BIT: 
            bitspersample = 1;
            samplesperpixel = 1;
            photometric = PHOTOMETRIC_MINISBLACK;
            bytesperrow = (width + 7) / 8;
            break;
        case VFF_TYP_1_BYTE: 
            bytesperrow = width;
            bitspersample = 8;

            if (viff_image->num_data_bands == 1)
            {
                if (mapcol == 0)
                {
                   photometric = PHOTOMETRIC_MINISBLACK;
                   samplesperpixel = 1;
                }
                else if (mapcol == 1 || mapcol == 3)
                {
                   photometric = PHOTOMETRIC_PALETTE;
                   samplesperpixel = 1;
                }
            }
            else /* must have 3 data bands */
            {
                photometric = PHOTOMETRIC_RGB;
                samplesperpixel = 3;
            }
            break;
        default:
            fprintf (stderr,
                    "%s: VIFF image stored in an unconvertable data type.\n",
                    program);
            fprintf (stderr, "Should be either bit or byte.\n");
            return(0);
            break; 
    }
    /* The TIFF spec 5.0 recommends that we use 8k bytes per strip
     * in the TIFF file. So calculate the number of images rows 
     * per 8k byte strips
     */

    rowsperstrip = (8 * 1024) / bytesperrow;
    stripsperimage = (height + (unsigned short) rowsperstrip -1) / 
                     (unsigned short) rowsperstrip;
    stripbytecounts = samplesperpixel * stripsperimage;
    clock = time(NULL);

    /* set up the TIFF header */

    TIFFSetField(tif, TIFFTAG_IMAGEWIDTH, width);
    TIFFSetField(tif, TIFFTAG_IMAGELENGTH, height);
    TIFFSetField(tif, TIFFTAG_BITSPERSAMPLE, bitspersample);
    TIFFSetField(tif, TIFFTAG_ORIENTATION, ORIENTATION_TOPLEFT);
    TIFFSetField(tif, TIFFTAG_COMPRESSION, compression);
    TIFFSetField(tif, TIFFTAG_PHOTOMETRIC, photometric);
    TIFFSetField(tif, TIFFTAG_DOCUMENTNAME, filename);
    TIFFSetField(tif, TIFFTAG_IMAGEDESCRIPTION, desc);
    TIFFSetField(tif, TIFFTAG_SAMPLESPERPIXEL, samplesperpixel);
    TIFFSetField(tif, TIFFTAG_ROWSPERSTRIP, rowsperstrip);
    TIFFSetField(tif, TIFFTAG_STRIPBYTECOUNTS, stripbytecounts);
    TIFFSetField(tif, TIFFTAG_STRIPOFFSETS, (stripsperimage * samplesperpixel));
    TIFFSetField(tif, TIFFTAG_PLANARCONFIG, PLANARCONFIG_SEPARATE);
    TIFFSetField(tif, TIFFTAG_SOFTWARE, version);
    TIFFSetField(tif, TIFFTAG_DATETIME, ctime(&clock));

        /* set the pixel resolution to centimeters, and calculate
         * the number of pixels per cenitmeter
         */
    TIFFSetField(tif, TIFFTAG_RESOLUTIONUNIT, RESUNIT_CENTIMETER);
    if (viff_image->pixsizx > 0)
        TIFFSetField(tif, TIFFTAG_XRESOLUTION, 
                        (1 / (100.0 * viff_image->pixsizx)));
    if (viff_image->pixsizy > 0)
        TIFFSetField(tif, TIFFTAG_YRESOLUTION, 
                        (1 / (100.0 * viff_image->pixsizy)));
    
        /* If we had color maps in the VIFF image, transfer them to
         * to the TIFF image
         */

    if (mapcol != 0)
    {
        bzero(red, sizeof(unsigned short) * 256);
        bzero(green, sizeof(unsigned short) * 256);
        bzero(blue, sizeof(unsigned short) * 256);

        if (mapcol == 1)
        {
           for (i = 0; i < maprow; i++)
              red[i] = green[i] = blue[i] =
                   SCALE((int) viff_image->maps[i]);
        }
        else /* mapcol = 3 */
        {
           rptr = (unsigned char *) &viff_image->maps[0]; 
           gptr = (unsigned char *) &viff_image->maps[maprow]; 
           bptr = (unsigned char *) &viff_image->maps[maprow * 2]; 

           for (i = 0; i < maprow; i++)
           {
                red[i]   = SCALE((int) *rptr++);
                green[i] = SCALE((int) *gptr++);
                blue[i]  = SCALE((int) *bptr++);
           } 
        }
        TIFFSetField(tif, TIFFTAG_COLORMAP, red, green, blue);
    }

        /* assign the image data from the VIFF image to the TIFF image
         * Note, TIFFWriteScanline takes care of data compression
         * automatically
         */

    if (viff_image->data_storage_type == VFF_TYP_BIT)
    {
        ptr = (unsigned char *) viff_image->imagedata;
        buf = (unsigned char *) calloc(1, bytesperrow*sizeof(unsigned char));
        for (row = 0; row < height; row++)
        {
           for (i = 0; i < bytesperrow; i++)
             buf[i] = rev[ptr[row * bytesperrow + i]];
           if (TIFFWriteScanline(tif, buf, row, 0) < 0)
           {
              fprintf(stderr,
                   "%s: Cannot write TIFF image, failed when writing ",
                    program);
              fprintf(stderr,"scanline (%d), band 0\n", row);
              free(buf);
              return(0);
           }
        }
        free(buf);
    }
    else  /* must be a BYTE image */
    {
        for (s = 0; s < viff_image->num_data_bands; s++)
        {
            band = s * height * width;
            for (row = 0; row < height; row++)
            {
               buf = (unsigned char *) &viff_image->imagedata[row*width+band];
               if (TIFFWriteScanline(tif, buf, row, s) < 0)
               {
                   fprintf(stderr, 
                     "%s: Cannot write TIFF image, failed when writing ", 
                        program);
                   fprintf(stderr,"scanline (%d), band (%d)\n", row, s);
                   return(0);
               }
           }
        }
    }

        /* flush the buffer */

    TIFFFlushData(tif);

    if (verbose)
    {
        fprintf(stderr,"\n\n\nOutput TIFF Image Information\n");
        fprintf(stderr,
            "-----------------------------------------------------\n\n");
        TIFFPrintDirectory(tif,stderr,TRUE, FALSE, FALSE);

    }

    return(TRUE);
}
/* -library_code_end */
