/*
 * This software is copyrighted as noted below.  It may be freely copied,
 * modified, and redistributed, provided that the copyright notice is
 * preserved on all copies.
 *
 * There is no warranty or other guarantee of fitness for this software,
 * it is provided solely "as is".  Bug reports or fixes may be sent
 * to the author, who may or may not act on them as he desires.
 *
 * You may not include this software in a program or other software product
 * without supplying the source, or without informing the end-user that the
 * source is available for no extra charge.
 *
 * If you modify this software, you should include a notice giving the
 * name of the person performing the modification, the date of modification,
 * and the reason for such modification.
 */
/*
 * tiff.c - interface with Aldus-Microsoft TIFF format.
 *
 * Author:      Raul Rivero
 *              Mathematics Dept.
 *              University of Oviedo
 * Date:        Sat Jan 18 1992
 * Copyright (c) 1992, Raul Rivero
 *
 */
/*
 * Raul Rivero  -  04/14/94
 *      Added support for images with any # of colors.
 *
 */

#include <lug.h>
#include <lugfnts.h>


/*
 * Look here !!!
 * =============
 *
 * This code is valid only if we have defined the iTIFF
 * macro ( read the root Makefile for more information ).
 *
 */

#ifdef iTIFF

#include <tiffio.h>

#define GetField(a,b,c)         if ( TIFFGetField(a,b,c) == 0 ) error( 21 );

extern int LUGverbose;

read_tiff_file( name, image )
char *name;
bitmap_hdr *image;
{
  register int i, j;
  TIFF *handle;
  long xsize, ysize;
  ushort samplesperpixel;
  ushort bitspersample;
  ushort photometric;
  ushort planarconfig;
  ushort iscmyk = 0;
  ushort c, m, y, k;
  ushort *rTIFFcmap, *gTIFFcmap, *bTIFFcmap;
  byte *r, *g, *b;
  int totalsize;
  byte *ptr;
  byte *TIFFline;
  double val, inc;

  /*
   * Open the file.
   */
  if ( name )
    handle = TIFFOpen( name, "rb" );
  else handle = TIFFFdOpen( 0, "stdin", "rb" );
  if ( handle == NULL )
    error( 1 );

  /*
   * Get TIFF configuration.
   */
  GetField( handle, TIFFTAG_IMAGEWIDTH,  &xsize );
  GetField( handle, TIFFTAG_IMAGELENGTH, &ysize );
  GetField( handle, TIFFTAG_SAMPLESPERPIXEL, &samplesperpixel );
  GetField( handle, TIFFTAG_BITSPERSAMPLE, &bitspersample );
  GetField( handle, TIFFTAG_PHOTOMETRIC, &photometric );
  GetField( handle, TIFFTAG_PLANARCONFIG, &planarconfig );

  /*
   * ... ok. Fill our header.
   */
  image->magic = LUGUSED;
  image->xsize = (int) xsize;
  image->ysize = (int) ysize;
  image->depth = ( samplesperpixel < 4 ? samplesperpixel : 3 ) * bitspersample;
  image->colors = 1 << image->depth;

  /*
   * New LIBTIFF library has changed the calling parameters 
   * of the TIFFPrintDirectory functions, so ... what version 
   * are you using ?.
   */
  if ( LUGverbose )
#if TIFF_VERSION >= 42
    TIFFPrintDirectory( handle, stderr,  0L );
#else
    TIFFPrintDirectory( handle, stderr, 1, 0, 0 );
#endif
  
  switch ( photometric ) {
    case PHOTOMETRIC_MINISBLACK :
                /* Get the increments while building the cmap table */
                inc = 255. / (((double)image->colors)-1.);
                /* Allocate memory for our cmap and build it */
                ptr = image->cmap = (byte *) Malloc( 3 * image->colors );
                for ( i = 0, val = 0.; i < image->colors; i++, val += inc ) {
                  *ptr++ = (byte) val;
                  *ptr++ = *(ptr-1);
                  *ptr++ = *(ptr-1);
                }
                break;
    case PHOTOMETRIC_MINISWHITE :
                /* Get the increments while building the cmap table */
                inc = 255. / (((double)image->colors)-1.);
                /* Allocate memory for our cmap and build it */
                ptr = image->cmap = (byte *) Malloc( 3 * image->colors );
                for ( i = 0, val = 255.; i < image->colors; i++, val -=inc ) {
                  *ptr++ = (byte) val;
                  *ptr++ = *(ptr-1);
                  *ptr++ = *(ptr-1);
                }
                break;
    case PHOTOMETRIC_PALETTE :
                /* Read the TIFF cmap */
                if ( !TIFFGetField( handle, TIFFTAG_COLORMAP,
                                    &rTIFFcmap, &gTIFFcmap, &bTIFFcmap ) )
                  error( 9 );
                /* Allocate memory for our cmap and get it */
                ptr = image->cmap = (byte *) Malloc( 3 * image->colors );
                for ( i = 0; i < image->colors; i++ ) {
                  *ptr++ = ( rTIFFcmap[i] >> 8 );
                  *ptr++ = ( gTIFFcmap[i] >> 8 );
                  *ptr++ = ( bTIFFcmap[i] >> 8 );
                }
                break;
    case PHOTOMETRIC_RGB :
                break;
    case PHOTOMETRIC_SEPARATED:
                if ( TIFFGetField( handle, TIFFTAG_INKSET, &iscmyk ) == 0 ) {
                  if ( samplesperpixel == 4 ) {
                    /* 
                     * Photoshop doesn't save the INKSET tag. So ... we hope
                     * in a good CMYK's file if we have 4 samples per pixel.
                     */
                    VPRINTF( stderr, "Warning, cannot get the INKSET tag (possible further errors)\n" );
                    iscmyk = 4;
                  }else {
                    VPRINTF( stderr, "A possible CMYK image without INKSET tag neither 4 samples per pixel\n" );
                    error( 99 );
                  }
                }else {
                  if ( iscmyk != INKSET_CMYK ) {
                    fprintf( stderr, "Separated Photometric image but not CMYK\n" );
                    error( 99 );
                   }
                }
                break;
    default:
                fprintf( stderr, "Not supported photometric configuration\n");
                error( 99 );
  }
  if (  image->depth > 8 ) {
    switch ( planarconfig ) {
      case PLANARCONFIG_CONTIG   :
                break;
      case PLANARCONFIG_SEPARATE :
                fprintf( stderr, "Separate planar configuration is not supported, yet.\n");
                error( 99 );
                break;
      default:
                fprintf( stderr, "Unknown planar configuration\n");
                error( 99 );
    }
  }


  /*
   * Allocate memory for bitmap.
   */
  totalsize = (int) (xsize * ysize);
  r = image->r = (byte *) Malloc( totalsize );
  if ( image->depth > 8 ) {
    /* A real RGB image */
    g = image->g = (byte *) Malloc( totalsize );
    b = image->b = (byte *) Malloc( totalsize );
  }

  /*
   * Get TIFF raster lines.
   */
  TIFFline = (byte *) Malloc( TIFFScanlineSize(handle) );
  /*
   * This ...if... could be done inside the loop but what we
   * wanna is efficacy :-), so ...
   */
  if ( image->depth >= 8 ) {
    /* We have a 'beatiful' raw image */
    for ( i = 0; i < ysize; i++ ) {
      TIFFReadScanline( handle, TIFFline, i, 0 );
      if ( !iscmyk ) {
        /* Great!, a RGB image :) */
        for ( j = 0, ptr = TIFFline; j < xsize; j++ ) {
          *r++ = *ptr++;
          if ( image->depth > 8 ) {
            *g++ = *ptr++;
            *b++ = *ptr++;
            if ( samplesperpixel == 4 ) {
              /* Skip alpha channel */
              ptr++;
            }
          }
        }
      }else {
        /* Oooopss!, a CMYK image */
        for ( j = 0, ptr = TIFFline; j < xsize; j++ ) {
          c = 255 - *ptr++;
          m = 255 - *ptr++;
          y = 255 - *ptr++;
          k = 255 - *ptr++;
          *r++ = ((int)k*c/255);
          *g++ = ((int)k*m/255);
          *b++ = ((int)k*y/255);
        }
      }
    }
  }else {
    /* Ooopss, we have packed bits */
    int mask = ( 1 << bitspersample ) - 1;
    int offset;

    for ( i = 0; i < ysize; i++ ) {
      TIFFReadScanline( handle, TIFFline, i, 0 );
      for ( j = 0, ptr = TIFFline, offset = 8 - bitspersample; 
            j < xsize; 
            j++, offset -= bitspersample) {
        *r++ = (*ptr >> offset ) & mask;
        if ( !offset ) {
          offset = 8;
          ptr++;
        }
      }
    }
  }

  /*
   * Free our raster line and close the TIFF file.
   */
  free( TIFFline );
  TIFFClose( handle );
}

write_tiff_file( name, image )
char *name;
bitmap_hdr *image;
{
  register int i, j;
  TIFF *handle;
  byte *r, *g, *b;
  byte *buffer, *ptr;
  long rows_per_strip;
  int banks = (image->depth > 8 ? 3 : 1);
  long xsize, ysize;
  ushort *rTIFFcmap, *gTIFFcmap, *bTIFFcmap;

  if ( image->magic != LUGUSED )
    error( 19 );

  VPRINTF( stderr, "Writting TIFF file\n" );
  /*
   * Open the TIFF file.
   */
  if ( name )
    handle = TIFFOpen( name, "wb" );
  else handle = TIFFFdOpen( 1, "stdout", "wb" );
  if ( handle == NULL)
    error( 1 );

  /*
   * Configure the TIFF image.
   */
  xsize = image->xsize;
  ysize = image->ysize;
  TIFFSetField( handle,TIFFTAG_IMAGEWIDTH, xsize );
  TIFFSetField( handle,TIFFTAG_IMAGELENGTH, ysize );
  TIFFSetField( handle, TIFFTAG_COMPRESSION, COMPRESSION_LZW);
  TIFFSetField( handle, TIFFTAG_PREDICTOR, 2);
  rows_per_strip = 16*1024 / (image->xsize);
  if ( rows_per_strip < 1 )
    rows_per_strip = 1;
  TIFFSetField( handle, TIFFTAG_ROWSPERSTRIP, rows_per_strip);
  TIFFSetField( handle, TIFFTAG_XRESOLUTION, 72.0 );
  TIFFSetField( handle, TIFFTAG_YRESOLUTION, 72.0 );
  TIFFSetField( handle, TIFFTAG_RESOLUTIONUNIT, 1 );
  TIFFSetField( handle, TIFFTAG_BITSPERSAMPLE, 8 );
  TIFFSetField( handle, TIFFTAG_SAMPLESPERPIXEL, banks );
  TIFFSetField( handle, TIFFTAG_PLANARCONFIG, 1 );
  if ( banks > 1 ) {
    /*
     * A true color image.
     */
    TIFFSetField( handle, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_RGB );
  }else {
    /*
     * If a mapped image, the we need build the cmap.
     */
    TIFFSetField( handle, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_PALETTE );
    rTIFFcmap = (ushort *) Malloc( sizeof(short) * 256 );
    gTIFFcmap = (ushort *) Malloc( sizeof(short) * 256 );
    bTIFFcmap = (ushort *) Malloc( sizeof(short) * 256 );
    for ( i = 0, ptr = image->cmap; i < image->colors; i++ ) {
      rTIFFcmap[i] = ( *ptr++ << 8 );
      gTIFFcmap[i] = ( *ptr++ << 8 );
      bTIFFcmap[i] = ( *ptr++ << 8 );
    }
    TIFFSetField( handle, TIFFTAG_COLORMAP, rTIFFcmap, gTIFFcmap, bTIFFcmap );
  }

  /*
   * Set pointers.
   */
  r = image->r;
  if ( image->depth > 8 ) {
    g = image->g;
    b = image->b;
  }
  buffer = (byte *) Malloc( banks * image->xsize );

  /*
   * Dump each line.
   */
  for ( i = 0; i < image->ysize; i++ ) {
    /* TIFF library needs a RGBRGB...RGB raster line so ... */
    for ( j = 0, ptr = buffer; j < image->xsize; j++ ) {
      *ptr++ = *r++;
      if ( banks > 1 ) {
        *ptr++ = *g++;
        *ptr++ = *b++;
      }
    }
    TIFFWriteScanline( handle, buffer, i, 1);
  }

  /*
   * Close the TIFF file.
   */
  TIFFClose( handle );

  /*
   * Free memory.
   */
  free( buffer );
  if ( banks < 3 ) {
    free( rTIFFcmap );
    free( gTIFFcmap );
    free( bTIFFcmap );
  }
  TIFFClose( handle );
}


#endif  /* iTIFF */
