Logo Search packages:      
Sourcecode: gandalf version File versions

tiff_io.c

/**
 * File:          $RCSfile: tiff_io.c,v $
 * Module:        TIFF format image file I/O functions
 * Part of:       Gandalf Library
 *
 * Revision:      $Revision: 1.8 $
 * Last edited:   $Date: 2002/06/05 14:07:46 $
 * Author:        $Author: pm $
 * Copyright:     (c) 2000 Imagineer Software Limited
 *
 * Notes:         Works with the libtiff library
 */

/* This library is free software; you can redistribute it and/or
   modify it under the terms of the GNU Lesser General Public
   License as published by the Free Software Foundation; either
   version 2.1 of the License, or (at your option) any later version.

   This library is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
   Lesser General Public License for more details.

   You should have received a copy of the GNU Lesser General Public
   License along with this library; if not, write to the Free Software
   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
*/

#include <gandalf/image/io/tiff_io.h>
#include <gandalf/image/image_bit.h>
#include <gandalf/image/image_gl_uchar.h>
#include <gandalf/image/image_gl_ushort.h>
#include <gandalf/image/image_rgb_uchar.h>
#include <gandalf/image/image_rgb_ushort.h>
#include <gandalf/image/image_rgba_uchar.h>
#include <gandalf/image/image_rgba_ushort.h>
#include <gandalf/common/array.h>
#include <gandalf/common/misc_error.h>
#include <string.h>

/* only compile if you have TIFF */
#ifdef HAVE_TIFF

#include <tiffio.h>

/**
 * \addtogroup ImagePackage
 * \{
 */

/**
 * \addtogroup ImageIO
 * \{
 */

static void *
 get_rowstart ( Gan_Image *pImage, unsigned uiRow )
{
   gan_err_test_ptr ( uiRow < pImage->height, "get_rowstart",
                      GAN_ERROR_INCOMPATIBLE, "" );

   switch ( pImage->format )
   {
      case GAN_GREY_LEVEL_IMAGE:
        switch ( pImage->type )
        {
           case GAN_UCHAR:
             return gan_image_get_pixptr_gl_uc ( pImage, uiRow, 0 );
             break;
             
           case GAN_USHORT:
             return gan_image_get_pixptr_gl_us ( pImage, uiRow, 0 );
             break;

           default:
             gan_err_flush_trace();
             gan_err_register ( "get_rowstart", GAN_ERROR_ILLEGAL_TYPE, "" );
             return NULL;
        }
        break;
        
      case GAN_RGB_COLOUR_IMAGE:
        switch ( pImage->type )
        {
           case GAN_UCHAR:
             return gan_image_get_pixptr_rgb_uc ( pImage, uiRow, 0 );
             break;
             
           case GAN_USHORT:
             return gan_image_get_pixptr_rgb_us ( pImage, uiRow, 0 );
             break;

           default:
             gan_err_flush_trace();
             gan_err_register ( "get_rowstart", GAN_ERROR_ILLEGAL_TYPE, "" );
             return NULL;
        }
        break;
        
      case GAN_RGB_COLOUR_ALPHA_IMAGE:
        switch ( pImage->type )
        {
           case GAN_UCHAR:
             return gan_image_get_pixptr_rgba_uc ( pImage, uiRow, 0 );
             break;
             
           case GAN_USHORT:
             return gan_image_get_pixptr_rgba_us ( pImage, uiRow, 0 );
             break;

           default:
             gan_err_flush_trace();
             gan_err_register ( "get_rowstart", GAN_ERROR_ILLEGAL_TYPE, "" );
             return NULL;
        }
        break;
        
      default:
        gan_err_flush_trace();
        gan_err_register ( "get_rowstart", GAN_ERROR_ILLEGAL_TYPE, "" );
        return NULL;
   }

   /* shouldn't get here */
   return NULL;
}

/* fill given sample in each pixel on row */
static Gan_Bool
 fill_row_samples ( Gan_Image *pImage, unsigned uiRow, uint16 s, tdata_t buf )
{
   int iCol;

   gan_err_test_bool ( uiRow < pImage->height, "fill_row_samples",
                       GAN_ERROR_INCOMPATIBLE, "" );

   switch ( pImage->format )
   {
      case GAN_RGB_COLOUR_IMAGE:
        switch ( pImage->type )
        {
           case GAN_UCHAR:
           {
              Gan_RGBPixel_uc *pixptr = gan_image_get_pixptr_rgb_uc(pImage,
                                                                    uiRow, 0);
              uint8 *bufptr = (uint8 *)buf;

              switch ( s )
              {
                 case 0:
                   for ( iCol = (int)pImage->width-1; iCol >= 0;
                         iCol--, pixptr++ )
                      pixptr->R = *bufptr++;

                   break;

                 case 1:
                   for ( iCol = (int)pImage->width-1; iCol >= 0;
                         iCol--, pixptr++ )
                      pixptr->G = *bufptr++;

                   break;

                 case 2:
                   for ( iCol = (int)pImage->width-1; iCol >= 0;
                         iCol--, pixptr++ )
                      pixptr->B = *bufptr++;

                   break;
                   
                 default:
                   gan_err_flush_trace();
                   gan_err_register ( "fill_row_samples",
                                      GAN_ERROR_ILLEGAL_TYPE, "" );
                   return GAN_FALSE;
              }
           }
           break;
             
           case GAN_USHORT:
           {
              Gan_RGBPixel_us *pixptr = gan_image_get_pixptr_rgb_us(pImage,
                                                                    uiRow, 0);
              uint16 *bufptr = (uint16 *)buf;

              switch ( s )
              {
                 case 0:
                   for ( iCol = (int)pImage->width-1; iCol >= 0;
                         iCol--, pixptr++ )
                      pixptr->R = *bufptr++;

                   break;

                 case 1:
                   for ( iCol = (int)pImage->width-1; iCol >= 0;
                         iCol--, pixptr++ )
                      pixptr->G = *bufptr++;

                   break;

                 case 2:
                   for ( iCol = (int)pImage->width-1; iCol >= 0;
                         iCol--, pixptr++ )
                      pixptr->B = *bufptr++;

                   break;
                   
                 default:
                   gan_err_flush_trace();
                   gan_err_register ( "fill_row_samples",
                                      GAN_ERROR_ILLEGAL_TYPE, "" );
                   return GAN_FALSE;
              }
           }
           break;
             
           default:
             gan_err_flush_trace();
             gan_err_register ( "fill_row_samples", GAN_ERROR_ILLEGAL_TYPE,
                                "" );
             return GAN_FALSE;
        }
        break;
        
      case GAN_RGB_COLOUR_ALPHA_IMAGE:
        switch ( pImage->type )
        {
           case GAN_UCHAR:
           {
              Gan_RGBAPixel_uc *pixptr = gan_image_get_pixptr_rgba_uc(pImage,
                                                                      uiRow,0);
              uint8 *bufptr = (uint8 *)buf;

              switch ( s )
              {
                 case 0:
                   for ( iCol = (int)pImage->width-1; iCol >= 0;
                         iCol--, pixptr++ )
                      pixptr->R = *bufptr++;

                   break;

                 case 1:
                   for ( iCol = (int)pImage->width-1; iCol >= 0;
                         iCol--, pixptr++ )
                      pixptr->G = *bufptr++;

                   break;

                 case 2:
                   for ( iCol = (int)pImage->width-1; iCol >= 0;
                         iCol--, pixptr++ )
                      pixptr->B = *bufptr++;

                   break;
                   
                 case 3:
                   for ( iCol = (int)pImage->width-1; iCol >= 0;
                         iCol--, pixptr++ )
                      pixptr->A = *bufptr++;

                   break;
                   
                 default:
                   gan_err_flush_trace();
                   gan_err_register ( "fill_row_samples",
                                      GAN_ERROR_ILLEGAL_TYPE, "" );
                   return GAN_FALSE;
              }
           }
           break;
             
           case GAN_USHORT:
           {
              Gan_RGBAPixel_us *pixptr = gan_image_get_pixptr_rgba_us(pImage,
                                                                      uiRow,0);
              uint16 *bufptr = (uint16 *)buf;

              switch ( s )
              {
                 case 0:
                   for ( iCol = (int)pImage->width-1; iCol >= 0;
                         iCol--, pixptr++ )
                      pixptr->R = *bufptr++;

                   break;

                 case 1:
                   for ( iCol = (int)pImage->width-1; iCol >= 0;
                         iCol--, pixptr++ )
                      pixptr->G = *bufptr++;

                   break;

                 case 2:
                   for ( iCol = (int)pImage->width-1; iCol >= 0;
                         iCol--, pixptr++ )
                      pixptr->B = *bufptr++;

                   break;
                   
                 case 3:
                   for ( iCol = (int)pImage->width-1; iCol >= 0;
                         iCol--, pixptr++ )
                      pixptr->A = *bufptr++;

                   break;
                   
                 default:
                   gan_err_flush_trace();
                   gan_err_register ( "fill_row_samples",
                                      GAN_ERROR_ILLEGAL_TYPE, "" );
                   return GAN_FALSE;
              }
           }
           break;
             
           default:
             gan_err_flush_trace();
             gan_err_register ( "fill_row_samples", GAN_ERROR_ILLEGAL_TYPE,
                                "" );
             return GAN_FALSE;
        }
        break;
        
      default:
        gan_err_flush_trace();
        gan_err_register ( "fill_row_samples", GAN_ERROR_ILLEGAL_TYPE, "" );
        return GAN_FALSE;
   }

   
   /* success */
   return GAN_TRUE;
}

/**
 * \brief Reads an image file in TIFF format.
 * \param filename The name of the image file
 * \param image The image structure to read the image data into or NULL
 * \return Pointer to image structure, or \c NULL on ailure.
 *
 * Reads the TIFF image stored in the file \a filename into an \a image.
 * If image is \c NULL a new image is dynamically allocated, otherwise the
 * already allocated \a image structure is reused.
 *
 * \sa gan_write_tiff_image().
 */
Gan_Image *
00351  gan_read_tiff_image ( const char *filename, Gan_Image *image )
{
   TIFF *tif;
      uint32 width, height;
   unsigned uiRow;
   tsize_t scanlinesize;
   uint16 bitspersample, config;
   tsample_t nsamples;
      tdata_t buf;
   Gan_ImageFormat format;
   Gan_Type type;

   /* attempt to open file */
   tif = TIFFOpen(filename, "r");
   if ( tif == NULL )
   {
      gan_err_flush_trace();
      gan_err_register ( "gan_read_tiff_image", GAN_ERROR_OPENING_FILE,
                         filename );
      return NULL;
   }

   /* read image details */
      TIFFGetField ( tif, TIFFTAG_IMAGEWIDTH,  &width );
      TIFFGetField ( tif, TIFFTAG_IMAGELENGTH, &height );
      TIFFGetField ( tif, TIFFTAG_BITSPERSAMPLE, &bitspersample );
      TIFFGetField ( tif, TIFFTAG_SAMPLESPERPIXEL, &nsamples );
   TIFFGetField ( tif, TIFFTAG_PLANARCONFIG, &config );

   /* make sure that we will have origin at top-left */
   TIFFSetField ( tif, TIFFTAG_ORIENTATION, ORIENTATION_BOTLEFT );

   /* compute total number of bytes */
   scanlinesize = TIFFScanlineSize(tif);

   /* allocate image data */
   buf = _TIFFmalloc(scanlinesize);
   if ( buf == NULL )
   {
      gan_err_flush_trace();
      gan_err_register ( "gan_read_tiff_image", GAN_ERROR_MALLOC_FAILED, "" );
      return NULL;
   }

   switch ( nsamples )
   {
      case 1:
        format = GAN_GREY_LEVEL_IMAGE;
        switch ( bitspersample )
        {
           case 8:
             type = GAN_UINT8;
             break;

           case 16:
             type = GAN_UINT16;
             break;

           default:
             gan_err_flush_trace();
             gan_err_register ( "gan_read_tiff_image",
                                GAN_ERROR_ILLEGAL_TYPE, "" );
             return NULL;
        }
        break;

      case 3:
        format = GAN_RGB_COLOUR_IMAGE;
        switch ( bitspersample )
        {
           case 8:
             type = GAN_UINT8;
             break;

           case 16:
             type = GAN_UINT16;
             break;

           default:
             gan_err_flush_trace();
             gan_err_register ( "gan_read_tiff_image",
                                GAN_ERROR_ILLEGAL_TYPE, "" );
             return NULL;
        }
        break;
        
      case 4:
        format = GAN_RGB_COLOUR_ALPHA_IMAGE;
        switch ( bitspersample )
        {
           case 8:
             type = GAN_UINT8;
             break;

           case 16:
             type = GAN_UINT16;
             break;

           default:
             gan_err_flush_trace();
             gan_err_register ( "gan_read_tiff_image",
                                GAN_ERROR_ILLEGAL_TYPE, "" );
             return NULL;
        }
        break;
        
      default:
        gan_err_flush_trace();
        gan_err_register ( "gan_read_tiff_image",
                           GAN_ERROR_ILLEGAL_TYPE, "" );
        return NULL;
   }

   if ( image == NULL )
      /* allocate memory for the new image */
      image = gan_image_alloc ( format, type,
                                (unsigned long) height,
                                (unsigned long) width );
   else
      /* use an already allocated image */
      image = gan_image_set_format_type_dims ( image, format, type,
                                               (unsigned long) height,
                                               (unsigned long) width );
   
   if ( image == NULL )
   {
      gan_err_register ( "gan_read_tiff_image", GAN_ERROR_FAILURE, "" );
      return NULL;
   }

   /* read image data */
   switch ( config )
   {
      case PLANARCONFIG_CONTIG:
        for ( uiRow = 0; uiRow < image->height; uiRow++ )
        {
           /* read a line of data and copy in into the image */
           TIFFReadScanline ( tif, buf, uiRow, 0 );
           memcpy ( get_rowstart ( image, uiRow ), (const void *)buf,
                    scanlinesize );
        }
        break;

      case PLANARCONFIG_SEPARATE:
      {
         uint16 s;

         for (s = 0; s < nsamples; s++)
            for ( uiRow = 0; uiRow < image->height; uiRow++ )
            {
               TIFFReadScanline ( tif, buf, uiRow, s );

               /* fill given sample in each pixel on row */
               fill_row_samples ( image, uiRow, s, buf );
            }
      }
      break;

      default:
        gan_err_flush_trace();
        gan_err_register ( "gan_read_tiff_image", GAN_ERROR_ILLEGAL_TYPE, "" );
        return NULL;
   }

   /* free buffer, close TIFF instance and return image */
   _TIFFfree ( buf );
   TIFFClose(tif);
   return image;
}

/**
 * \brief Writes an image file to a stream in TIFF format.
 * \param outfile The file stream
 * \param image The image structure to write to the file
 * \return #GAN_TRUE on successful write operation, or #GAN_FALSE on failure.
 *
 * Writes the \a image into a TIFF file using a file stream \a outfile.
 * Uses the basic function TIFFReadRGBAImage(), so currently assumes an
 * unsigned character RGBA image.
 *
 * \sa gan_read_tiff_image_stream().
 */
Gan_Bool
00534  gan_write_tiff_image_stream ( FILE *outfile, Gan_Image *image )
{
   gan_assert ( 0, "file streaming not compatible with TIFF library design" );
   return GAN_FALSE;
}

/**
 * \brief Writes an image file in TIFF format.
 * \param filename The name of the image file
 * \param image The image structure to write to the file
 * \return #GAN_TRUE on successful write operation, #GAN_FALSE on failure.
 *
 * Writes the \a image into a TIFF file \a filename.
 *
 * \sa gan_read_tiff_image().
 */
Gan_Bool
00551  gan_write_tiff_image ( const char *filename, Gan_Image *image )
{
   TIFF *tif;
   unsigned uiRow;

   /* attempt to open file */
   tif = TIFFOpen(filename, "w");
   if ( tif == NULL )
   {
      gan_err_flush_trace();
      gan_err_register ( "gan_write_tiff_image", GAN_ERROR_OPENING_FILE,
                         filename );
      return GAN_FALSE;
   }

   /* set image details */
      TIFFSetField ( tif, TIFFTAG_IMAGEWIDTH,  image->width );
      TIFFSetField ( tif, TIFFTAG_IMAGELENGTH, image->height );
   TIFFSetField ( tif, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG );
      TIFFSetField ( tif, TIFFTAG_ORIENTATION, ORIENTATION_TOPLEFT);

   switch ( image->format )
   {
      case GAN_GREY_LEVEL_IMAGE:
        TIFFSetField ( tif, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_MINISBLACK );
        TIFFSetField ( tif, TIFFTAG_SAMPLESPERPIXEL, 1 );
        switch ( image->type )
        {
           case GAN_UCHAR:
             TIFFSetField ( tif, TIFFTAG_BITSPERSAMPLE, 8 );
             for ( uiRow = 0; uiRow < image->height; uiRow++ )
                TIFFWriteScanline ( tif, (tdata_t)
                                    gan_image_get_pixptr_gl_uc ( image,
                                                                 uiRow, 0 ),
                                    uiRow, 0 );
             break;
           
#if (SIZEOF_SHORT == 2)
           case GAN_USHORT:
             TIFFSetField ( tif, TIFFTAG_BITSPERSAMPLE, 16 );
             for ( uiRow = 0; uiRow < image->height; uiRow++ )
                TIFFWriteScanline ( tif, (tdata_t)
                                    gan_image_get_pixptr_gl_us ( image,
                                                                 uiRow, 0 ),
                                    uiRow, 0 );
             break;
#endif
           default:
             gan_err_flush_trace();
             gan_err_register ( "gan_write_tiff_image", GAN_ERROR_ILLEGAL_TYPE,
                                "" );
             return GAN_FALSE;
        }
        break;

      case GAN_RGB_COLOUR_IMAGE:
        TIFFSetField ( tif, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_RGB );
        TIFFSetField ( tif, TIFFTAG_SAMPLESPERPIXEL, 3 );
        switch ( image->type )
        {
           case GAN_UCHAR:
             TIFFSetField ( tif, TIFFTAG_BITSPERSAMPLE, 8 );
             for ( uiRow = 0; uiRow < image->height; uiRow++ )
                TIFFWriteScanline ( tif, (tdata_t)
                                    gan_image_get_pixptr_rgb_uc ( image,
                                                                  uiRow, 0 ),
                                    uiRow, 0 );
             break;
           
#if (SIZEOF_SHORT == 2)
           case GAN_USHORT:
             TIFFSetField ( tif, TIFFTAG_BITSPERSAMPLE, 16 );
             for ( uiRow = 0; uiRow < image->height; uiRow++ )
                TIFFWriteScanline ( tif, (tdata_t)
                                    gan_image_get_pixptr_rgb_us ( image,
                                                                  uiRow, 0 ),
                                    uiRow, 0 );
             break;
#endif
           default:
             gan_err_flush_trace();
             gan_err_register ( "gan_write_tiff_image", GAN_ERROR_ILLEGAL_TYPE,
                                "" );
             return GAN_FALSE;
        }
        break;

      case GAN_RGB_COLOUR_ALPHA_IMAGE:
        TIFFSetField ( tif, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_RGB );
        TIFFSetField ( tif, TIFFTAG_SAMPLESPERPIXEL, 4 );
        switch ( image->type )
        {
           case GAN_UCHAR:
             TIFFSetField ( tif, TIFFTAG_BITSPERSAMPLE, 8 );
             for ( uiRow = 0; uiRow < image->height; uiRow++ )
                TIFFWriteScanline ( tif, (tdata_t)
                                    gan_image_get_pixptr_rgba_uc ( image,
                                                                   uiRow, 0 ),
                                    uiRow, 0 );
             break;

#if (SIZEOF_SHORT == 2)
           case GAN_USHORT:
             TIFFSetField ( tif, TIFFTAG_BITSPERSAMPLE, 16 );
             for ( uiRow = 0; uiRow < image->height; uiRow++ )
                TIFFWriteScanline ( tif, (tdata_t)
                                    gan_image_get_pixptr_rgba_us ( image,
                                                                   uiRow, 0 ),
                                    uiRow, 0 );
             break;
#endif
           default:
             gan_err_flush_trace();
             gan_err_register ( "gan_write_tiff_image", GAN_ERROR_ILLEGAL_TYPE,
                                "" );
             return GAN_FALSE;
        }
        break;

      default:
        gan_err_flush_trace();
        gan_err_register ( "gan_write_tiff_image", GAN_ERROR_ILLEGAL_TYPE,
                           "" );
        return GAN_FALSE;
   }

   /* that's it */
   TIFFClose(tif);
   return GAN_TRUE;
}

/**
 * \}
 */

/**
 * \}
 */

#endif /* #ifdef HAVE_TIFF */

Generated by  Doxygen 1.6.0   Back to index