 /*
  * Khoros: $Id: ltiff2viff.c,v 1.2 1992/03/20 23:35:49 dkhoros Exp $
  */

#if !defined(lint) && !defined(SABER)
static char rcsid[] = "Khoros: $Id: ltiff2viff.c,v 1.2 1992/03/20 23:35:49 dkhoros Exp $";
#endif

 /*
  * $Log: ltiff2viff.c,v $
 * Revision 1.2  1992/03/20  23:35:49  dkhoros
 * VirtualPatch5
 *
  */ 

/*
 *----------------------------------------------------------------------
 *
 * 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: ltiff2viff.c
 >>>>
 >>>>      Program Name: tiff2viff
 >>>>
 >>>> Date Last Updated: Sun Mar 10 21:09:24 1991 
 >>>>
 >>>>          Routines: ltiff2viff - the library call for tiff2viff
 >>>>
 >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>   <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<*/


#include "vinclude.h"


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


/****************************************************************
*
* Routine Name: ltiff2viff - library call for tiff2viff
*
* Purpose:
*    
*    Convert a TIFF image to a VIFF image
*    
*    
* Input:
*    
*         TIFF *tif - pointer  to  the  tif  image  structure  (header
*         returned by TIFFOpen)
*    
*         struct  xvimage **viff - pointer to  a  pointer  of  a  VIFF
*         image file (malloced in this routine)
*    
*         int verbose - if set prints Tiff image header information
*    
*         char *filename - the name of the input file
*    
*    
* Output:
*    
*         struct  xvimage **viff_image - malloced and copied imagedata
*         for VIFF image
*    
*    
*
* Written By: Tom Sauer
*    
*    
****************************************************************/


/* -library_def */
int ltiff2viff(tif, viff, verbose, filename)

TIFF *tif;
struct xvimage **viff;
int verbose;
char *filename;

/* -library_def_end */

/* -library_code */
{
        char *program = "ltiff2viff";
        struct xvimage *createimage(), *new_viff;
        TIFFDirectory *td;
        int i, s, row, col, numcolors;
        int width, height, bands, map_cols, map_rows, map_scheme;
        int bytesperrow, bitspersample, map_type, cmodel;
        unsigned char *red, *green, *blue, *ptr, *buf, *inp;
        unsigned short res, orien, config;
        float xres, yres, resolution;

        td = &tif->tif_dir;

        /*
         * Print info about the TIFF image
         */

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

        /* 
         * We can only handle image that have either 1 bit or 8 bits per sample
         */

        if (td->td_bitspersample > 8)
        {
           fprintf(stderr, 
               "%s: Can only work with image that have 1 or 8 bits per pixel\n",
                program);
           return(0);
        }

        width = (int) td->td_imagewidth;
        height = (int) td->td_imagelength;

        /*
         * determine whether or not the resulting VIFF image should be
         * a BIT or BYTE image, and whether or not it should have
         * one or three data bands.
         */

        switch (td->td_samplesperpixel) {
           case 1:
              if (td->td_bitspersample == 1)
              {
                 bitspersample = VFF_TYP_BIT;
                 bytesperrow = (width + 7) / 8;
                 bands = 1;
              }
              else
              {
                 bitspersample = VFF_TYP_1_BYTE;
                 bytesperrow = width;
                 bands = 1;
              }
              break;
           case 3:
           case 4:
              bitspersample = VFF_TYP_1_BYTE;
              bytesperrow = width;
              bands = 3;
              break;
           default:
              fprintf(stderr, 
                "%s: only handle 1-channel gray scale or 3-channel color\n", 
                  program);
              break;
        }


        /* 
         * determine the number of colors. If the number of colors is
         * equal to 2, then it is black and white, either bit or byte.
         * Otherwise, it is a BYTE image and we must determine if
         * it is a true RGB image (24 bits, 3 band) or a single band
         * image with a colormap 
         */

        numcolors = (1 << td->td_bitspersample);

        if ( numcolors == 2)
        {
           map_cols =0;
           map_rows =0;
           map_scheme = VFF_MS_NONE;
           map_type = VFF_MAPTYP_NONE;
           cmodel = VFF_CM_NONE;
        }
        else
        {
          switch (td->td_photometric)
          {
            case PHOTOMETRIC_MINISBLACK:
            case PHOTOMETRIC_MINISWHITE:
               map_cols = 1;
               map_rows = numcolors;
               map_scheme = VFF_MS_ONEPERBAND;  
               map_type = VFF_MAPTYP_1_BYTE;
               cmodel = VFF_CM_NONE;
               break;
            case PHOTOMETRIC_RGB:
               map_cols = 0;
               map_rows = 0;
               map_scheme = VFF_MS_NONE;        
               map_type = VFF_MAPTYP_NONE;
               cmodel = VFF_CM_genericRGB;
               break;
            case PHOTOMETRIC_PALETTE:
               map_cols = 3;
               map_rows = numcolors;
               map_scheme = VFF_MS_ONEPERBAND;  
               map_type = VFF_MAPTYP_1_BYTE;
               cmodel = VFF_CM_genericRGB;
               break;
            case PHOTOMETRIC_MASK:
               fprintf(stderr, "%s: Can not work on TIFF images with a photometric type of MASK\n",
                  program);
               return(0);
               break;
            case PHOTOMETRIC_DEPTH:
               fprintf(stderr, "%s: Can not work on TIFF images with a photometric type of DEPTH\n",
                  program);
               return(0);
               break;
            default:
               fprintf(stderr,"%s: unknown TIFF photometric type encountered\n",
                       program);
               return(0);
               break;
          }
        }

        /*
         * Now we know what the resulting VIFF image will look like,
         * so create it.
         */ 

        new_viff = createimage(height, width, bitspersample, 1, bands, 
                                NULL, map_cols, map_rows, map_scheme, 
                                map_type, VFF_LOC_IMPLICIT, 0);
                   
        new_viff->color_space_model = cmodel;

        /*
         * load the maps according to the td_photometric type.
         * the map is linear if its PHOTOMETRIC_MINISBLACK or
         * PHOTOMETRIC_MINISWHITE. If the td_photometric type
         * is PHOTOMETRIC_PALETTE, then the map is a 3 column map.
         */

        if (map_type != VFF_MAPTYP_NONE)
        {
           switch (td->td_photometric) 
           {
              case PHOTOMETRIC_MINISBLACK:
                  for (i = 0; i < numcolors; i++)
                      new_viff->maps[i] = (255 * i) / numcolors;
                  break;
              case PHOTOMETRIC_MINISWHITE:
                  for (i = 0; i < numcolors; i++)
                      new_viff->maps[i] = 255 - ((255 * i) / numcolors);
                  break;
              case PHOTOMETRIC_RGB:
                  break;
              case PHOTOMETRIC_PALETTE:
                  red = (unsigned char *) new_viff->maps; 
                  green = (unsigned char *) &(new_viff->maps[numcolors]); 
                  blue = (unsigned char *) &(new_viff->maps[2*numcolors]); 
                  for (i = 0; i < numcolors; i++) {
                      red[i]   =  CONVERT_COLOR(td->td_redcolormap[i]);
                      green[i] =  CONVERT_COLOR(td->td_greencolormap[i]);
                      blue[i]  =  CONVERT_COLOR(td->td_bluecolormap[i]);
                  }
                  break;
              default:
                  fprintf(stderr,
                             "%s: unknown TIFF photometric type encountered\n",
                             program);
                  return(0);
                  break;
           }
        }

        /*
         * load the image data. Grab one row of TIFF image data at a time
         * and load it into the VIFF file. First malloc space for the
         * row buffer. Then scan the TIFF image transfering each image
         * data row to the VIFF image.
         */

        buf = (unsigned char *) malloc(TIFFScanlineSize(tif));
        if (buf == NULL)
        {
            fprintf(stderr, "%s: can't allocate memory for scanline buffer\n", 
                program);
            return(0);
        }

        /*
         * Determine if the TIFF image data is stored in a Planer or
         * Contiguous form. Planer data is stored by planes or bands,
         * while Contiguous data is stored as RGBRGBRGB...
         */

        TIFFGetField(tif, TIFFTAG_PLANARCONFIG, &config);
        for (row = 0; row < height; row++) 
        {
           ptr = (unsigned char *) &(new_viff->imagedata[row * bytesperrow]);
           switch (td->td_photometric) 
           {

               /* 24 bit RGB data -- results in 3 data bands.
                * Load the VIFF according to the TIFF configuration
                */

              case PHOTOMETRIC_RGB:
                  if (config == PLANARCONFIG_CONTIG)
                  {
                     if (TIFFReadScanline(tif, buf, row, 0) < 0)
                     {
                        fprintf(stderr,
                                "%s: bad data read on line: %d of TIFF image\n",
                                 program, row);
                        return(0);
                     }

                     inp = buf;
                     red   = ptr;
                     green = ptr + (height * bytesperrow);
                     blue  = ptr + (2*height * bytesperrow);
                  
                     if (td->td_samplesperpixel == 4)
                         for (col = 0; col < bytesperrow; col++) 
                         {
                             *red = *inp;        red++;   inp++;
                             *green = *inp;      green++; inp++;
                             *blue = *inp;       blue++;  inp++;
                             inp++;     /* skip alpha channel */
                         }
                     else
                         for (col = 0; col < bytesperrow; col++) 
                         {
                             *red = *inp;       red++;   inp++;
                             *green = *inp;     green++; inp++;
                             *blue = *inp;      blue++;  inp++;
                         }
                  }
                  else /* must be PLANARCONFIG_SEPARATE */
                  {
                     for (s = 0; s < 3; s++)
                     {
                         if (TIFFReadScanline(tif, buf, row, s) < 0)
                         {
                            fprintf(stderr,
                               "%s: bad data read on line: %d of TIFF image\n",
                                 program, row);
                            return(0);
                         }
                         ptr = (unsigned char *) 
                               &(new_viff->imagedata[(height * bytesperrow * s)
                                                       + (row * bytesperrow)]);
                         bcopy(buf, ptr, bytesperrow);
                     }
                  }
                  break;

                /* 
                 * The image is a simple grey scale image. So,
                 * simply deal the different number of possible 
                 * bits per sample (1, 2, 4 or 8)
                 */

              case PHOTOMETRIC_MINISWHITE:
              case PHOTOMETRIC_MINISBLACK:
                  if (TIFFReadScanline(tif, buf, row, 0) < 0)
                  {
                     fprintf(stderr, 
                                "%s: bad data read on line: %d of TIFF image\n",
                                 program, row);
                     return(0);
                  }
                  inp = buf;

                  switch (td->td_bitspersample) 
                  {
                     case 1:
                         for (col = 0; col < ((width + 7) / 8); col++)
                         {
                             *ptr = rev[*inp];  
                             ptr++;  
                             inp++;
                         }
                         break;
                     case 2:
                         for (col = 0; col < ((width + 3) / 4); col++) 
                         {
                             *ptr++ = (*inp >> 6) & 3;
                             *ptr++ = (*inp >> 4) & 3;
                             *ptr++ = (*inp >> 2) & 3;
                             *ptr++ = *inp++ & 3;
                         }
                         break;
                     case 4:
                         for (col = 0; col < width / 2; col++) 
                         {
                             *ptr++ = *inp >> 4;
                             *ptr++ = *inp++ & 0xf;
                         }
                         break;
                     case 8:
                         bcopy(inp, ptr, bytesperrow);
                         break;
                     default:
                         fprintf(stderr, "%s: bad bits/sample: %d\n", 
                                 program, td->td_bitspersample);
                         break;
                  }
                  break;

                /*
                 * must be 8 bit, so just copy the image data.
                 */

              case PHOTOMETRIC_PALETTE:
                  if (TIFFReadScanline(tif, buf, row, 0) < 0)
                  {
                     fprintf(stderr, 
                           "%s: bad data read on line: %d of TIFF image\n",
                           program, row);
                     return(0);
                  }
                  bcopy(buf, ptr, bytesperrow);
                  break;
              default:
                  fprintf(stderr, "%s: unknown photometric (write): %d\n", 
                          program, td->td_photometric);
                  break;
           }
    }

        /* free up the buffer and assign the new image */

    free((char *) buf);


    /* get the pixel size information */
    
    TIFFGetField(tif, TIFFTAG_XRESOLUTION, &xres);
    TIFFGetField(tif, TIFFTAG_YRESOLUTION, &yres);
    TIFFGetField(tif, TIFFTAG_RESOLUTIONUNIT, &res);

        /*
         * convert the TIFF resolution units from inch or
         * centimeters to meters. Assign the pixel
         * size to the viff image
         */

    if (res != RESUNIT_NONE)
    {
       if (res == RESUNIT_INCH)
          resolution = 0.0254;             /* convert inch to meters */
       else if (res == RESUNIT_CENTIMETER)
          resolution = 0.01;              /* covert cm to meters */
        
       new_viff->pixsizx = resolution/xres;
       new_viff->pixsizy = resolution/yres;
    }

/*
 * The Orientation field is not recommended for use. This
 * field should be used for local use only as stated in the
 * TIFF 5.0 specification.
 *
 *  This code does work and can be un-commented if 
 *  its use is required.
 *
 * START of COMMENTED CODE

    TIFFGetField(tif, TIFFTAG_ORIENTATION, &orien);
    switch(orien)
    {
        case ORIENTATION_TOPLEFT:
           break;
        case ORIENTATION_TOPRIGHT:
           if (! lvflip(new_viff,TRUE, FALSE))
           {
                fprintf(stderr,
                 "%s: Warining... lvflip failed. Unable to flip TIFF image \n", 
                        program);
                fprintf(stderr, "so that the image orientation is top left");
           }
           break;
        case ORIENTATION_BOTRIGHT:
           if (! lvflip(new_viff,TRUE, TRUE))
           {
                fprintf(stderr,
                 "%s: Warning... lvflip failed. Unable to flip TIFF image \n", 
                        program);
                fprintf(stderr, "so that the image orientation is top left");
           }
           break;
        case ORIENTATION_BOTLEFT:
           if (! lvflip(new_viff,FALSE, TRUE))
           {
                fprintf(stderr,
                 "%s: lvflip failed. Unable to flip TIFF image \n", 
                        program);
                fprintf(stderr, "so that the image orientation is top left");
           }
           break;
        case ORIENTATION_LEFTTOP:
           if (! lvtranspos(new_viff))
           {
                fprintf(stderr,
                 "%s: lvtranspos failed. Unable to transpose the TIFF image \n",
                        program);
                fprintf(stderr, "so that the image orientation is top left");
                break;
           }
           break;

        case ORIENTATION_RIGHTTOP:
           if (! lvtranspos(new_viff))
           {
                fprintf(stderr,
                 "%s: lvtranspos failed. Unable to transpose the TIFF image \n",
                        program);
                fprintf(stderr, "so that the image orientation is top left");
                break;
           }

           if (! lvflip(new_viff,TRUE, FALSE))
           {
                fprintf(stderr,
                 "%s: Warining... lvflip failed. Unable to flip TIFF image \n",
                        program);
                fprintf(stderr, "so that the image orientation is top left");
           }
           break;

        case ORIENTATION_RIGHTBOT:
           if (! lvtranspos(new_viff))
           {
                fprintf(stderr,
                 "%s: lvtranspos failed. Unable to transpose the TIFF image \n",
                        program);
                fprintf(stderr, "so that the image orientation is top left");
                break;
           }

           if (! lvflip(new_viff,TRUE, TRUE))
           {
                fprintf(stderr,
                 "%s: Warining... lvflip failed. Unable to flip TIFF image \n",
                        program);
                fprintf(stderr, "so that the image orientation is top left");
           }
           break;

        case ORIENTATION_LEFTBOT:
           if (! lvtranspos(new_viff))
           {
                fprintf(stderr,
                 "%s: lvtranspos failed. Unable to transpose the TIFF image \n",
                        program);
                fprintf(stderr, "so that the image orientation is top left");
                break;
           }

           if (! lvflip(new_viff,FALSE, TRUE))
           {
                fprintf(stderr,
                 "%s: Warining... lvflip failed. Unable to flip TIFF image \n",
                        program);
                fprintf(stderr, "so that the image orientation is top left");
           }
           break;
    }

  END of COMMENTED CODE */


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

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

    *viff = new_viff;

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