jedi-outcast/utils/roq2/libim/imtiff.c

13233 lines
203 KiB
C

/**
** $Header: /roq/libim/imtiff.c 1 11/02/99 4:38p Zaphod $
** Copyright (c) 1989-1995 San Diego Supercomputer Center (SDSC)
** a division of General Atomics, San Diego, California, USA
**
** Users and possessors of this source code are hereby granted a
** nonexclusive, royalty-free copyright and design patent license to
** use this code in individual software. License is not granted for
** commercial resale, in whole or in part, without prior written
** permission from SDSC. This source is provided "AS IS" without express
** or implied warranty of any kind.
**
** For further information contact:
** E-Mail: info@sds.sdsc.edu
**
** Surface Mail: Information Center
** San Diego Supercomputer Center
** P.O. Box 85608
** San Diego, CA 92138-5608
** (619) 534-5000
**/
#define HEADER " $Header: /roq/libim/imtiff.c 1 11/02/99 4:38p Zaphod $"
/**
** FILE
** imtiff.c - TIFF Raster I/O
**
** PROJECT
** libim - SDSC image manipulation library
**
** DESCRIPTION
** imtiff.c contains routines to read and write TIFF image files for
** the image manipulation library. Raster data read in is stored
** in a VFB and optional CLT in a tag list. Raster data written
** out is taken from a tag list.
**
** The compiler flag -DUSE_TIFF_LIB will use the tiff library written
** by Sam Leffler instead of using the routines in this module.
**
** PUBLIC CONTENTS
** d =defined constant
** f =function
** m =defined macro
** t =typedef/struct/union
** v =variable
** ? =other
** none
**
** PRIVATE CONTENTS
**
** imTiffRead f read a TIFF Rasterfile
** imTiffWrite f write a TIFF Rasterfile
**
** imTiffHeaderInfo t Rasterfile header information
** imTiffHeaderFields v imTiffHeaderInfo description for Bin pkg
** imTiffHeader v Rasterfile header holder
** imTiffDataWidth v How many bytes for a byte, short, long, etc
** imTiffMask v Bits to mask when shifting variable data
**
** imTiffDirEntry t An Image File Directory entry
** imTiffDirectoryFields t imTiffDirEntry description for Bin pkg
** imTiffDirData t Program internal representation of dir data
** imTiffDirInfo t Program internal representation of directory
**
** IMTIFFBIGENDIANMAGIC d file magic number
** IMTIFFLITTLEENDIANMAGIC d file magic number
** IMTIFF* d type enumeration
**
** IMTIFFBITSPERBYTE d how big is a byte (8-bits of course)
** IMTIFFBYTESPERWORD d how many bytes in a word (4)
** IMTIFFSHORTSPERWORD d how many shorts in a word (2)
** NULL d an empty pointer
**
** imTiffDecode f decode the data in the directory offset
** imTiffReadDirectory f read a tiff Image File Directory
** imTiffFetchData f get data pointed to be a directory entry
** imTiffDataItem f get data out of dirdata structure
** imPrintTiffDirInfo f print the contents of an internal tiffdir
** imPrintTiffDirLongEntry f print the contents of a data entry
**
** imTiffRead1 f read a 1 bit image
** imTiffRead4 f read a 4 bit image
** imTiffRead8 f read a 8 bit image
** imTiffRead24 f read a 24 bit image
**
** imTiffWrite1 f write a 1 bit image
** imTiffWrite8 f write a 8 bit image
** imTiffWrite24 f write a 24 bit image
**
**
**
** HISTORY
** $Log: /roq/libim/imtiff.c $
*
* 1 11/02/99 4:38p Zaphod
** Revision 1.41 1995/10/03 20:42:37 bduggan
** Put back non-tiff library reading capability,
** since it works on the cray.
**
** Revision 1.39 1995/06/29 00:28:04 bduggan
** updated copyright year
**
** Revision 1.38 1995/06/15 21:21:13 bduggan
** changed bcopy's to memcpy's.
**
** Revision 1.37 1995/04/03 21:38:35 bduggan
** took out #ifdef NEWMAGIC
** Made write routines work on decAlpha (LSBF)
**
** Revision 1.36 1995/02/16 21:42:19 bduggan
** Commented out index16 writing, since xv & amazon can't read 'em
**
** Revision 1.35 1995/02/01 00:50:40 bduggan
** Fixed bug with ReadNonInterleavedTIles
**
** Revision 1.34 1995/01/30 21:30:06 bduggan
** Took out some stderr's
**
** Revision 1.33 1995/01/16 22:06:54 bduggan
** Added tiff library support!
**
** Revision 1.32 1994/10/27 23:49:05 bduggan
** changed ImTiffRead and Write into static functions
**
** Revision 1.31 94/10/03 11:31:04 nadeau
** Updated to ANSI C and C++ compatibility.
** Removed all use of register keyword.
** Minimized use of custom SDSC types (e.g., uchar vs. unsigned char)
** Changed all float arguments to double.
** Added forward declarations.
** Added misc. casts to passify SGI and DEC compilers.
** Changed all macros and defined constants to have names
** starting with IM.
** Rearranged magic number structures for format handlers.
** Made format handler routines static (i.e., local to file).
** Updated comments, adding format descriptions and references.
** Updated indenting on some code.
** Updated copyright message.
**
** Revision 1.30 92/12/03 01:53:02 nadeau
** Corrected info messages.
**
** Revision 1.29 92/11/23 18:43:14 nadeau
** Removed use of IMINFOMSG.
**
** Revision 1.28 92/11/04 12:09:13 groening
** put ImFIleFormat info and magic number info
** from imfmt.c into this file.
** Also, added multiple magic numbers.
**
** Revision 1.27 92/10/19 14:08:28 groening
** removed some debuggin statements left by vle
**
** Revision 1.26 92/10/16 13:58:09 vle
** Tracked down color table error.
** .`
**
** Revision 1.25 92/08/31 17:36:46 vle
** Updated copyright notice.
**
** Revision 1.24 92/04/08 12:13:47 nadeau
** Added extern declarations for private functions.
**
** Revision 1.23 91/10/03 09:19:48 nadeau
** Changed 'interlace' to 'interleave'.
**
** Revision 1.22 91/09/13 14:10:14 nadeau
** Fixed minor typos caused by Alliant ethernet controller that
** munged random bytes in files as they were read or written.
**
** Revision 1.21 91/09/11 13:44:33 todd
** update to tiff specification 5.0
**
** Revision 1.20 91/03/20 16:04:12 todd
** Cleaned up code that deals with stripbytecounts and stripoffsets
** so it is machine independent.
** Fixed ImTiffWrite to write alpha channels.
**
** Revision 1.19 91/03/20 10:53:22 todd
** Fix another bug. Can't read an array of shorts into an int (4 bytes)
** on the cray, of course.
**
** Revision 1.18 91/03/18 15:45:13 todd
** *** empty log message ***
**
** Revision 1.17 91/03/18 15:44:16 todd
** Fixed a bug in writing array of shorts.
** Two shorts cannot fit in 4 bytes on the cray.
**
** Revision 1.16 91/03/15 14:10:16 todd
** Fixed two bugs.
** Changed INT to CHAR in ImBinWrite in ImTiffWrite
** packbits case.
** Changed code that reads and writes the offset field
** in the tagged directory entries to do correct
** type of binary I/O.
** Added ImBinFloat() initialization
**
** Revision 1.15 91/03/14 15:34:31 todd
** Added return(0) statemensts where needed.
** Fixed imTiffGetClt so it doesn't try to free
** a null pointer.
**
** Revision 1.14 91/03/12 16:17:20 todd
** no changes
**
** Revision 1.13 91/03/12 15:57:17 todd
** Fixed conflict between cltRequest and clt == NULL.
** An extra bogus header tag was being written out.
**
** Revision 1.12 91/03/12 11:02:42 nadeau
** Added BinFloatFormat select.
**
** Revision 1.11 91/02/13 14:11:53 nadeau
** Added error message handling for read and write return cases
** that just returned a -1 instead of doing a message.
**
** Revision 1.10 91/02/12 17:01:25 nadeau
** Removed tag table checking and temp file handling now
** handled by ImFileRead and ImFileWrite. Changed GRAY
** to MONO VFB's. Fixed minor byte order machine dependency
** in read and write code for 16-bit indexes.
**
** Revision 1.9 91/01/29 11:12:32 todd
** add monochrome to write routine
**
** Revision 1.8 91/01/09 15:52:51 todd
** Updated some types for better portability.
**
** Revision 1.7 90/12/13 13:43:50 rama
** Fixed problems with pointers
**
** Revision 1.6 90/12/13 12:52:52 rama
** fixed problems with bcopy and calloc
**
** Revision 1.5 90/12/12 18:52:17 todd
** no changes. Rama is going to fix Todd's non-portable bugs.
**
** Revision 1.4 90/09/10 09:57:07 todd
** Works for 8 bit images with and without CLTs. Works for 24 bit images.
** Reads 1 and 4 bit images. Lempel-Ziv Welch encoding works for read
** and write. 32 bit images with CLTs should work but its untested.
** Alpha channels are supported.
**
** Revision 1.3 90/09/06 14:24:22 todd
** Added lots of functionality. Everything works except
** writing out LZW compressed images. Writing 1 bit images
** is not supported either.
**
** Revision 1.2 90/07/25 15:17:59 todd
** Most read routines work. Write routines written but not debugged yet.
**
** Revision 1.1 90/06/25 13:25:07 todd
** Initial revision
**
**
**/
#include <stdio.h>
#include <sys/types.h>
//#include <sys/file.h>
#include <fcntl.h>
#include <errno.h>
#include "iminternal.h"
#ifdef USE_TIFF_LIB
#include "tiff.h"
#include "tiffio.h"
#endif
/*
**
** FORMAT
** TIFF - Aldus Tagged Image File Format
**
** AKA
** tif
**
** FORMAT REFERENCES
** - Bit-Mapped Graphics, Steve Rimmer
** - Supercharged Bitmapped Graphics, Steve Rimmer
** - Graphics File Formats, David C. Kay, John R. Levine
** - TIFF Revision 6.0, Aldus
**
**
** CODE CREDITS
** Custom development, Todd Elvins, San Diego Supercomputer Center, 1992.
**
** DESCRIPTION
** TIFF files are composed of a small file header, one or more
** image directories containing tagged information about an image
** in the file, and one or more images. Images of any depth
** can be stored in a Tiff file. We only deal with
** reading 1, 4, 8, and 24 bit images, and writing 8 and 24 bit
** images. The pixel data in Tiff files can be encoded in a number
** of different ways. Currently we are only handling unencoded
** pixel data, and Lempil-Ziv Welsh encoding. In the future
** we might want to add Thunderscan, Macintosh PackBits, or Pixar picio.
**
**
** The sections of a tiff file are as follows :
**
** - header 8 bytes Header info.
** - image file directory variable points to image data
** (IFD) There may be
** more than one IFD.
** - actual data
** The sections are not necessarily in that order; the header point
** to the first IFD, which points to subsequent IFDs and image data.
**
** Header
** ------
**
** Bytes Description
** 0-1 Byte Order (MSB or LSB)
** 2-3 Magic number (stored according to byte order)
** 4-7 Location of the first IFD in the file
**
** Image File Directories
** ----------------------
** An IFD consists of the following information:
** - the number of entries in the directory (2 bytes)
** - a series of entries (12 bytes each)
** - the location of the next IFD or 0 for the (4 bytes)
** last entry
** Each entry in the IFD contains:
** - a tag identifying the field (bytes 0-1)
** - the field type (bytes 2-3)
** - the size of the data: 'count'
** (the actual size of the data is
** sizeof(field_type) * count bytes) (bytes 4-7)
** - the location of the data in the file (must
** begin on a word boundary, so this is an even
** number) (bytes 8-11)
**
**/
/**
** The TIFF library
** ----------------
**
** This library claims to support many many many different
** possible image types. The specifications for TIFF allow for
** any number of channels in an image, and any depth for each channel.
** BUT, most software packages that use the tiff library do not
** support such a variety of formats.
**
** Here is what the routines that follow support :
**
** Read support:
**
** 1. RGB Images with
** 1,2,4,8 or 16 bits per channel
** alpha or no alpha channel
** non-interleaved
** grouped by scanlines
**
** 2. RGB Images with
** 8 bits per channel
** alpha or no alpha channel
** plane-interleaved
** grouped by scanlines or tiles
**
** 3. Color Indexed or Greyscale Images with
** 1,2,4,8, or 16 bits per channel
** plane-interleaved or non-interleaved
** (those are equivalent since there's one plane)
** grouped by scanlines or tiles
**
** Compression is handled by the tiff library. So, whatever
** compression schemes the tiff library handles are supported
** by the image tools.
**
** Write support:
**
** 1. RGB Images with
** 8 bits per channel
** alpha or no alpha channel
** non-interleaved or plane-interleaved
** grouped by scanlines or tiles
**
** 2. Color Indexed or Greyscale images with
** 1,2,4,8,16 bits per channel
** plane or non-interleaved (equivalent)
** grouped by scanlines
**
** 3. Color Indexed or Greyscale images with
** 8 bits per channel
** plane or non-interleaved (equivalent)
** grouped by tiles
**
** The compression schemes supported are:
**
** Macintosh PackBits encoding,
** Lempel-Ziv & Welch encoding,
** JPEG encoding (Discrete Cosine Transform),
** none
**
**
** The reason for not having write capability for rgb images
** with other than 8 bits per channel is because such files
** make Amazon and xv dump core. The capability IS in place
** to write such images, and this can be accomplished simply
** by adding these specifications to the write map below.
**
** i.e. adding
**
** { IMVFBRGB, 0, RGB,3,1, 0, imTiffWrite },
** { IMVFBRGB, 0, RGB,3,2, 0, imTiffWrite },
** { IMVFBRGB, 0, RGB,3,4, 0, imTiffWrite },
**
** would allow for writing RGB images with no compression and
** 1,2, or 4 bits per channel.
**
**/
/*
* TIFF - Tagged Image File Format
* For information on these structures, how to use them, etc. please
* see imfmt.c.
*/
#ifdef __STDC__
static int imTiffRead( int ioType, int fd, FILE *fp, TagTable *flags, TagTable *tagTable );
static int imTiffWrite( ImFileFormatWriteMap *pMap, int ioType, int fd, FILE *fp, TagTable *flagsTable, TagTable *tagTable );
#else
static int imTiffRead( );
static int imTiffWrite( );
#endif
static char *imTiffNames[ ] = { "tiff", "tif", NULL };
static unsigned char imTiffMagicNumberA[ ] = {0x4d, 0x4d };
static unsigned char imTiffMagicNumberB[ ] = {0x49, 0x49 };
static ImFileFormatReadMap imTiffReadMap[ ] =
{
/* in out */
/* type,ch,dep, attr. VFB type attr. */
#ifdef USE_TIFF_LIB
{ IN,1,1, 0, IMVFBMONO, 0 },
{ IN,1,4, C, IMVFBINDEX8, C },
{ IN,1,4, 0, IMVFBINDEX8, 0 },
{ IN,1,4, LZW|C, IMVFBINDEX8, C },
{ IN,1,4, LZW, IMVFBINDEX8, 0 },
{ IN,1,4, PB|C, IMVFBINDEX8, C },
{ IN,1,4, PB, IMVFBINDEX8, 0 },
{ IN,1,8, 0, IMVFBINDEX8, 0 },
{ IN,1,8, 0, IMVFBINDEX8, 0 },
{ IN,1,8, C, IMVFBINDEX8, C },
{ IN,1,32, 0, IMVFBINDEX16, 0 },
{ IN,1,32, C, IMVFBINDEX16, C },
{ RGB,3,8, 0, IMVFBRGB, 0 },
{ RGB,3,8, A, IMVFBRGB, A },
{ IN,1,1, PB, IMVFBMONO, 0 },
{ IN,1,4, PB, IMVFBINDEX8, 0 },
{ IN,1,8, PB, IMVFBINDEX8, 0 },
{ IN,1,8, PB, IMVFBINDEX8, 0 },
{ IN,1,8, PB|C, IMVFBINDEX8, C },
{ IN,1,32, PB, IMVFBINDEX16, 0 },
{ IN,1,32, PB|C, IMVFBINDEX16, C },
{ RGB,3,8, PB, IMVFBRGB, 0 },
{ RGB,3,8, PB|A, IMVFBRGB, A },
{ IN,1,1, LZW, IMVFBMONO, 0 },
{ IN,1,4, LZW, IMVFBINDEX8, 0 },
{ IN,1,8, LZW, IMVFBINDEX8, 0 },
{ IN,1,8, LZW, IMVFBINDEX8, 0 },
{ IN,1,8, LZW|C, IMVFBINDEX8, C },
{ IN,1,32, LZW, IMVFBINDEX16, 0 },
{ IN,1,32, LZW|C, IMVFBINDEX16, C },
{ RGB,3,8, LZW, IMVFBRGB, 0 },
{ RGB,3,8, LZW|A, IMVFBRGB, A },
#else
{ IN,1,1, 0, IMVFBMONO, 0 },
{ IN,1,4, 0, IMVFBINDEX8, 0 },
{ IN,1,8, 0, IMVFBINDEX8, 0 },
{ IN,1,8, 0, IMVFBINDEX8, 0 },
{ IN,1,8, C, IMVFBINDEX8, C },
{ IN,1,32, 0, IMVFBINDEX16, 0 },
{ IN,1,32, C, IMVFBINDEX16, C },
{ RGB,3,8, 0, IMVFBRGB, 0 },
{ RGB,3,8, A, IMVFBRGB, A },
{ IN,1,1, PB, IMVFBMONO, 0 },
{ IN,1,4, PB, IMVFBINDEX8, 0 },
{ IN,1,8, PB, IMVFBINDEX8, 0 },
{ IN,1,8, PB, IMVFBINDEX8, 0 },
{ IN,1,8, PB|C, IMVFBINDEX8, C },
{ IN,1,32, PB, IMVFBINDEX16, 0 },
{ IN,1,32, PB|C, IMVFBINDEX16, C },
{ RGB,3,8, PB, IMVFBRGB, 0 },
{ RGB,3,8, PB|A, IMVFBRGB, A },
{ IN,1,1, LZW, IMVFBMONO, 0 },
{ IN,1,4, LZW, IMVFBINDEX8, 0 },
{ IN,1,8, LZW, IMVFBINDEX8, 0 },
{ IN,1,8, LZW, IMVFBINDEX8, 0 },
{ IN,1,8, LZW|C, IMVFBINDEX8, C },
{ IN,1,32, LZW, IMVFBINDEX16, 0 },
{ IN,1,32, LZW|C, IMVFBINDEX16, C },
{ RGB,3,8, LZW, IMVFBRGB, 0 },
{ RGB,3,8, LZW|A, IMVFBRGB, A },
#endif
{ -1, 0, -1, 0 },
};
static ImFileFormatWriteMap imTiffWriteMap[ ] =
{
/* in out */
/* VFB type, attr., type,ch,dep, attr., func */
#ifdef USE_TIFF_LIB
{ IMVFBMONO, 0, IN,1,1, LZW, imTiffWrite },
{ IMVFBMONO, 0, IN,1,1, PB, imTiffWrite },
{ IMVFBMONO, 0, IN,1,1, 0, imTiffWrite },
{ IMVFBMONO, C, IN,1,1, C|LZW, imTiffWrite },
{ IMVFBMONO, C, IN,1,1, C|PB, imTiffWrite },
{ IMVFBMONO, C, IN,1,1, C, imTiffWrite },
{ IMVFBMONO, 0, IN,1,1, PI|LZW, imTiffWrite },
{ IMVFBMONO, 0, IN,1,1, PI|PB, imTiffWrite },
{ IMVFBMONO, 0, IN,1,1, PI, imTiffWrite },
{ IMVFBMONO, C, IN,1,1, PI|C|LZW,imTiffWrite },
{ IMVFBMONO, C, IN,1,1, PI|C|PB, imTiffWrite },
{ IMVFBMONO, C, IN,1,1, PI|C, imTiffWrite },
{ IMVFBINDEX8, 0, IN,1,8, LZW, imTiffWrite },
{ IMVFBINDEX8, 0, IN,1,8, PB, imTiffWrite },
{ IMVFBINDEX8, 0, IN,1,8, 0, imTiffWrite },
{ IMVFBINDEX8, C, IN,1,8, C|LZW, imTiffWrite },
{ IMVFBINDEX8, C, IN,1,8, C|PB, imTiffWrite },
{ IMVFBINDEX8, C, IN,1,8, C, imTiffWrite },
{ IMVFBINDEX8, 0, IN,1,8, PI|LZW, imTiffWrite },
{ IMVFBINDEX8, 0, IN,1,8, PI|PB, imTiffWrite },
{ IMVFBINDEX8, 0, IN,1,8, PI, imTiffWrite },
{ IMVFBINDEX8, C, IN,1,8, PI|C|LZW,imTiffWrite },
{ IMVFBINDEX8, C, IN,1,8, PI|C|PB, imTiffWrite },
{ IMVFBINDEX8, C, IN,1,8, PI|C, imTiffWrite },
{ IMVFBINDEX8, 0, IN,1,4, LZW, imTiffWrite },
{ IMVFBINDEX8, 0, IN,1,4, PB, imTiffWrite },
{ IMVFBINDEX8, 0, IN,1,4, 0, imTiffWrite },
{ IMVFBINDEX8, C, IN,1,4, C|LZW, imTiffWrite },
{ IMVFBINDEX8, C, IN,1,4, C|PB, imTiffWrite },
{ IMVFBINDEX8, C, IN,1,4, C, imTiffWrite },
{ IMVFBINDEX8, 0, IN,1,4, PI|LZW, imTiffWrite },
{ IMVFBINDEX8, 0, IN,1,4, PI|PB, imTiffWrite },
{ IMVFBINDEX8, 0, IN,1,4, PI, imTiffWrite },
{ IMVFBINDEX8, C, IN,1,4, PI|C|LZW,imTiffWrite },
{ IMVFBINDEX8, C, IN,1,4, PI|C|PB, imTiffWrite },
{ IMVFBINDEX8, C, IN,1,4, PI|C, imTiffWrite },
{ IMVFBINDEX8, 0, IN,1,2, LZW, imTiffWrite },
{ IMVFBINDEX8, 0, IN,1,2, PB, imTiffWrite },
{ IMVFBINDEX8, 0, IN,1,2, 0, imTiffWrite },
{ IMVFBINDEX8, C, IN,1,2, C|LZW, imTiffWrite },
{ IMVFBINDEX8, C, IN,1,2, C|PB, imTiffWrite },
{ IMVFBINDEX8, C, IN,1,2, C, imTiffWrite },
{ IMVFBINDEX8, 0, IN,1,2, PI|LZW, imTiffWrite },
{ IMVFBINDEX8, 0, IN,1,2, PI|PB, imTiffWrite },
{ IMVFBINDEX8, 0, IN,1,2, PI, imTiffWrite },
{ IMVFBINDEX8, C, IN,1,2, PI|C|LZW,imTiffWrite },
{ IMVFBINDEX8, C, IN,1,2, PI|C|PB, imTiffWrite },
{ IMVFBINDEX8, C, IN,1,2, PI|C, imTiffWrite },
#if 0 /* Nobody seems capable of reading index16 tiffs. */
{ IMVFBINDEX16, 0, IN,1,16, LZW, imTiffWrite },
{ IMVFBINDEX16, 0, IN,1,16, PB, imTiffWrite },
{ IMVFBINDEX16, 0, IN,1,16, 0, imTiffWrite },
{ IMVFBINDEX16, C, IN,1,16, C|LZW, imTiffWrite },
{ IMVFBINDEX16, C, IN,1,16, C|PB, imTiffWrite },
{ IMVFBINDEX16, C, IN,1,16, C, imTiffWrite },
{ IMVFBINDEX16, 0, IN,1,16, PI|LZW, imTiffWrite },
{ IMVFBINDEX16, 0, IN,1,16, PI|PB, imTiffWrite },
{ IMVFBINDEX16, 0, IN,1,16, PI, imTiffWrite },
{ IMVFBINDEX16, C, IN,1,16, PI|C|LZW,imTiffWrite },
{ IMVFBINDEX16, C, IN,1,16, PI|C|PB, imTiffWrite },
{ IMVFBINDEX16, C, IN,1,16, PI|C, imTiffWrite },
#endif
{ IMVFBRGB, 0, RGB,3,8, LZW, imTiffWrite },
{ IMVFBRGB, 0, RGB,3,8, PB, imTiffWrite },
{ IMVFBRGB, 0, RGB,3,8, 0, imTiffWrite },
{ IMVFBRGB, A, RGB,3,8, A|LZW, imTiffWrite },
{ IMVFBRGB, A, RGB,3,8, A|PB, imTiffWrite },
{ IMVFBRGB, A, RGB,3,8, A, imTiffWrite },
{ IMVFBRGB, 0, RGB,3,8, PI|LZW, imTiffWrite },
{ IMVFBRGB, 0, RGB,3,8, PI|PB, imTiffWrite },
{ IMVFBRGB, 0, RGB,3,8, PI, imTiffWrite },
{ IMVFBRGB, A, RGB,3,8, PI|A|LZW,imTiffWrite },
{ IMVFBRGB, A, RGB,3,8, PI|A|PB, imTiffWrite },
{ IMVFBRGB, A, RGB,3,8, PI|A, imTiffWrite },
/* tiles */
{ IMVFBINDEX8, 0, IN,1,8, T|LZW, imTiffWrite },
{ IMVFBINDEX8, 0, IN,1,8, T|PB, imTiffWrite },
{ IMVFBINDEX8, 0, IN,1,8, T|0, imTiffWrite },
{ IMVFBINDEX8, 0, IN,1,8, T|DCT, imTiffWrite },
{ IMVFBINDEX8, C, IN,1,8, T|C|LZW, imTiffWrite },
{ IMVFBINDEX8, C, IN,1,8, T|C|PB, imTiffWrite },
{ IMVFBINDEX8, C, IN,1,8, T|C, imTiffWrite },
{ IMVFBINDEX8, C, IN,1,8, T|C|DCT, imTiffWrite },
{ IMVFBINDEX8, 0, IN,1,8, T|PI|LZW, imTiffWrite },
{ IMVFBINDEX8, 0, IN,1,8, T|PI|PB, imTiffWrite },
{ IMVFBINDEX8, 0, IN,1,8, T|PI, imTiffWrite },
{ IMVFBINDEX8, 0, IN,1,8, T|PI|DCT, imTiffWrite },
{ IMVFBINDEX8, C, IN,1,8, T|PI|C|LZW,imTiffWrite },
{ IMVFBINDEX8, C, IN,1,8, T|PI|C|PB, imTiffWrite },
{ IMVFBINDEX8, C, IN,1,8, T|PI|C, imTiffWrite },
{ IMVFBINDEX8, C, IN,1,8, T|PI|C|DCT,imTiffWrite },
{ IMVFBRGB, 0, RGB,3,8, T|LZW, imTiffWrite },
{ IMVFBRGB, 0, RGB,3,8, T|PB, imTiffWrite },
{ IMVFBRGB, 0, RGB,3,8, T, imTiffWrite },
{ IMVFBRGB, 0, RGB,3,8, T|DCT, imTiffWrite },
{ IMVFBRGB, A, RGB,3,8, T|A|LZW, imTiffWrite },
{ IMVFBRGB, A, RGB,3,8, T|A|PB, imTiffWrite },
{ IMVFBRGB, A, RGB,3,8, T|A, imTiffWrite },
{ IMVFBRGB, A, RGB,3,8, T|A|DCT, imTiffWrite },
{ IMVFBRGB, 0, RGB,3,8, T|PI|LZW, imTiffWrite },
{ IMVFBRGB, 0, RGB,3,8, T|PI|PB, imTiffWrite },
{ IMVFBRGB, 0, RGB,3,8, T|PI, imTiffWrite },
{ IMVFBRGB, 0, RGB,3,8, T|PI|DCT, imTiffWrite },
{ IMVFBRGB, A, RGB,3,8, T|PI|A|LZW,imTiffWrite },
{ IMVFBRGB, A, RGB,3,8, T|PI|A|PB, imTiffWrite },
{ IMVFBRGB, A, RGB,3,8, T|PI|A, imTiffWrite },
{ IMVFBRGB, A, RGB,3,8, T|PI|A|DCT,imTiffWrite },
#else
{ IMVFBMONO, 0, IN,1,1, LZW, imTiffWrite },
{ IMVFBMONO, 0, IN,1,1, PB, imTiffWrite },
{ IMVFBMONO, 0, IN,1,1, 0, imTiffWrite },
{ IMVFBINDEX8, 0, IN,1,8, LZW, imTiffWrite },
{ IMVFBINDEX8, 0, IN,1,8, PB, imTiffWrite },
{ IMVFBINDEX8, 0, IN,1,8, 0, imTiffWrite },
{ IMVFBINDEX8, C, IN,1,8, LZW|C, imTiffWrite },
{ IMVFBINDEX8, C, IN,1,8, PB|C, imTiffWrite },
{ IMVFBINDEX8, C, IN,1,8, C, imTiffWrite },
{ IMVFBRGB, A, RGB,3,8, LZW|A, imTiffWrite },
{ IMVFBRGB, A, RGB,3,8, PB|A, imTiffWrite },
{ IMVFBRGB, A, RGB,3,8, A, imTiffWrite },
{ IMVFBRGB, 0, RGB,3,8, LZW, imTiffWrite },
{ IMVFBRGB, 0, RGB,3,8, PB, imTiffWrite },
{ IMVFBRGB, 0, RGB,3,8, 0, imTiffWrite },
#endif
{ -1, 0, -1, 0, NULL },
};
static ImFileMagic imFileTiffMagic []=
{
{ 0, 2, imTiffMagicNumberA},
{ 0, 2, imTiffMagicNumberB},
{ 0, 0, NULL},
};
ImFileFormat ImFileTiffFormat =
{
imTiffNames, "Tagged image file",
"Aldus, MicroSoft, and NeXT",
"1-, 4-, 8-, and 32-bit color index images. 24-bit RGB and 32-bit\n\
RGB+alpha images. Standard (uncompressed), Mac Packbits, and Lempel-\n\
Ziv & Welsh compression.",
"1-, 8-, and 32-bit color index images. 24-bit RGB and 32-bit\n\
RGB+alpha images. Standard (uncompressed), Mac Packbits, and Lempel-\n\
Ziv & Welsh compression.",
imFileTiffMagic,
#ifdef USE_TIFF_LIB
IMMULTI, IMNOPIPE, /* Read */
IMMULTI, IMNOPIPE, /* Write */
#else
IMNOMULTI, IMNOPIPE,
IMNOMULTI, IMNOPIPE,
#endif
imTiffRead, imTiffReadMap, imTiffWriteMap
};
#ifdef USE_TIFF_LIB
/*
* MACRO
* IM_QCHANNEL( value, channel)
*
* DESCRIPTION
* Set a value to be this attribute of this pixel
*
*/
#define IM_QCHANNEL(value, channel) \
switch (channel) \
{ \
case IMVFBGREY : /* same as INDEX8 */ \
value = (uint16) ImVfbQGrey (vfb, vfbptr); \
break; \
case IMVFBRED : \
value = (uint16) ImVfbQRed (vfb, vfbptr); \
break; \
case IMVFBGREEN : \
value = (uint16) ImVfbQGreen(vfb, vfbptr); \
break; \
case IMVFBBLUE : \
value = (uint16) ImVfbQBlue (vfb, vfbptr); \
break; \
case IMVFBALPHA : \
value = (uint16) ImVfbQAlpha (vfb, vfbptr); \
break; \
case IMVFBINDEX16 : \
value = (uint16) ImVfbQIndex16 (vfb, vfbptr); \
break; \
}
#define IMTIFFNULL NULL
#define IM_MIN(x,y) ( (x) < (y) ? (x) : (y) )
#ifdef __STDC__
static int imTiffReadNonInterleavedScanlines( TIFF* tiff, ImVfb* vfb);
static int imTiffReadPlaneInterleavedScanlines( TIFF *tif, ImVfb* vfb);
static int imTiffReadNonInterleavedTiles (TIFF *tif, ImVfb *vfb);
static int imTiffReadPlaneInterleavedTiles ( TIFF *tif, ImVfb *vfb);
static int imTiffReadClt(TIFF* tif, ImClt **cltBuf);
static int imTiffReadRedScanlinePlane(TIFF* tif, ImVfb* vfb);
static int imTiffReadGreenScanlinePlane(TIFF* tif, ImVfb* vfb);
static int imTiffReadBlueScanlinePlane(TIFF* tif, ImVfb* vfb);
static int imTiffReadAlphaScanlinePlane(TIFF* tif, ImVfb* vfb);
static int imTiffReadRedTiledPlane( TIFF* tif, ImVfb* vfb, uint32 tileWidth,
uint32 tileLength, uint32 imageWidth, uint32 imageLength, tsize_t tileSize);
static int imTiffReadGreenTiledPlane( TIFF* tif, ImVfb* vfb, uint32 tileWidth,
uint32 tileLength, uint32 imageWidth, uint32 imageLength, tsize_t tileSize);
static int imTiffReadBlueTiledPlane( TIFF* tif, ImVfb* vfb, uint32 tileWidth,
uint32 tileLength, uint32 imageWidth, uint32 imageLength, tsize_t tileSize);
static int imTiffReadAlphaTiledPlane( TIFF* tif, ImVfb* vfb, uint32 tileWidth,
uint32 tileLength, uint32 imageWidth, uint32 imageLength, tsize_t tileSize);
static int imTiffWriteNonInterleavedScanlines( TIFF* tiff, ImVfb* vfb, ImFileFormatWriteMap* pMap);
static int imTiffWritePlaneInterleavedScanlines( TIFF *tif, ImVfb* vfb, ImFileFormatWriteMap* pMap);
static int imTiffWriteNonInterleavedTiles (TIFF *tif, ImVfb *vfb, ImFileFormatWriteMap* pMap );
static int imTiffWritePlaneInterleavedTiles ( TIFF *tif, ImVfb *vfb, ImFileFormatWriteMap* pMap);
static int imTiffWriteClt(TIFF* tif, ImClt *cltBuf, long numEntries);
static int imTiffWriteRedScanlinePlane(ImVfb *vfb, TIFF *tif, uint16 chandepth);
static int imTiffWriteGreenScanlinePlane(ImVfb *vfb, TIFF *tif, uint16 chandepth);
static int imTiffWriteBlueScanlinePlane(ImVfb *vfb, TIFF *tif, uint16 chandepth);
static int imTiffWriteAlphaScanlinePlane(ImVfb *vfb, TIFF *tif, uint16 chandepth);
static int imTiffWriteIndex8ScanlinePlane(ImVfb *vfb, TIFF *tif, uint16 chandepth);
static int imTiffWriteIndex16ScanlinePlane(ImVfb *vfb, TIFF *tif, uint16 chandepth);
static int imTiffWriteRedTiledPlane(ImVfb* vfb, TIFF *tif, uint16 chandepth, uint32 tileWidth, uint32 tileHeight);
static int imTiffWriteGreenTiledPlane( ImVfb* vfb, TIFF* tif, uint16 chanDepth, uint32 tileWidth, uint32 tileHeight);
static int imTiffWriteBlueTiledPlane( ImVfb* vfb, TIFF* tif, uint16 chanDepth, uint32 tileWidth, uint32 tileHeight);
static int imTiffWriteAlphaTiledPlane( ImVfb* vfb, TIFF* tif, uint16 chanDepth, uint32 tileWidth, uint32 tileHeight);
static int imTiffWriteIndex8TiledPlane( ImVfb* vfb, TIFF* tif, uint16 chanDepth, uint32 tileWidth, uint32 tileHeight);
static void imTiffSwapBytes(unsigned char* linebuf, tsize_t linesize);
#else /* __STDC__ is not defined */
static int imTiffReadNonInterleavedScanlines( );
static int imTiffReadPlaneInterleavedScanlines();
static int imTiffReadNonInterleavedTiles ( );
static int imTiffReadPlaneInterleavedTiles ( );
static int imTiffReadClt();
static int imTiffReadRedScanlinePlane();
static int imTiffReadGreenScanlinePlane();
static int imTiffReadBlueScanlinePlane();
static int imTiffReadAlphaScanlinePlane();
static int imTiffReadRedTiledPlane( );
static int imTiffReadGreenTiledPlane( );
static int imTiffReadBlueTiledPlane( );
static int imTiffReadAlphaTiledPlane( );
static int imTiffWriteNonInterleavedScanlines();
static int imTiffWritePlaneInterleavedScanlines( );
static int imTiffWriteNonInterleavedTiles ();
static int imTiffWritePlaneInterleavedTiles ( );
static int imTiffWriteClt();
static int imTiffWriteRedScanlinePlane();
static int imTiffWriteGreenScanlinePlane();
static int imTiffWriteBlueScanlinePlane();
static int imTiffWriteAlphaScanlinePlane();
static int imTiffWriteIndex8ScanlinePlane();
static int imTiffWriteIndex16ScanlinePlane();
static int imTiffWriteRedTiledPlane();
static int imTiffWriteGreenTiledPlane();
static int imTiffWriteBluedTiledPlane();
static int imTiffWriteAlphadTiledPlane();
static int imTiffWriteIndex8TiledPlane();
static void imTiffSwapBytes();
#endif /* __STDC__ */
#endif /* USE_TIFF_LIB */
/*
*
* Code to read tiff files without using the tiff library starts here.
*
*/
#ifndef USE_TIFF_LIB
/*
* Prototypes
* These functions are in imlzw.c or macpack.c
*/
#ifdef __STDC__
int ImLzwPreDecode( unsigned char *buf, int size );
int ImLzwDecode(unsigned char *buf, char *op, int occ);
int ImLzwPostDecode();
int ImLzwPreEncode(int size);
int ImLzwEncode(int ioType, int fd, FILE *fp, unsigned char *bp, int cc);
int ImLzwPostEncode( int ioType, int fd, FILE *fp );
void ImLzwCleanup();
void UnpackBits( unsigned char *srcPtr, unsigned char *dstPtr, unsigned int *cnt );
void PackBits3( unsigned char *cIn, unsigned char *cOut, unsigned int * width );
void PackBits( unsigned char *cIn, unsigned char *cOut, unsigned int *width );
#else
int ImLzwPreDecode( );
int ImLzwDecode();
int ImLzwPostDecode();
int ImLzwPreEncode();
int ImLzwEncode();
int ImLzwPostEncode( );
void ImLzwCleanup();
void UnpackBits( );
void PackBits3( );
void PackBits( );
#endif
/*
* TYPEDEF & STRUCTURE
* imTiffHeaderInfo - Rasterfile header information
* imTiffHeaderFields - imTiffHeaderInfo description for Bin pkg
* imTiffDirEntry - An Image File Directory entry
* imTiffDirFields - imTiffDirEntry description for Bin pkg
* imTiffDataWidth - An array of values indicating data size
* imTiffMask - A bit mask corresponding to data size
* imTiffDirData - Program internal representation of dir data
* imTiffDirInfo - Program internal representation of directory
* imTmpFile - A filename format for a temporary file.
*
* DESCRIPTION
* A TIFF file header contains a magic number, the version number,
* and an offset to the first directory entry. Directories are
* variable length. The number of dir entries is in the short preceeding
* the first directory entry. The offset of the next directory in
* the file is in the 4 bytes after the last directory entry. Most
* directory entries contain a tag, type, size, and a single value.
* Other entries contain a tag, type, size, and offset to an array of
* values (or a single double that would not fit in the value field).
*
* NOTE:
* TIFF's tiff.h is **NOT** directly included here!
* Therefore we recreate the essentials ourselves.
*/
typedef struct imTiffHeaderInfo
{
unsigned short tiff_magic; /* Magic number (byte order) */
unsigned short tiff_version; /* TIFF version number */
unsigned int tiff_diroff; /* byte offset to first dir */
} imTiffHeaderInfo;
static BinField imTiffHeaderFields[ ] =
{
{ USHORT, 2, 1 }, /* tiff_magic */
{ USHORT, 2, 1 }, /* tiff_version */
{ UINT, 4, 1 }, /* tiff_diroff */
{ 0, 0, 0 },
};
typedef struct imTiffDirEntry
{
unsigned short tdir_tag; /* Tagged file format type */
unsigned short tdir_type; /* Data type */
unsigned int tdir_count; /* Number of items; length */
unsigned int tdir_offset; /* byte offset to field data */
/* Last field is read separately*/
} imTiffDirEntry;
/*
* Read the tdir_offset separately depending on whether the
* type indicates it contains, bytes, shorts, or a long.
*/
static BinField imTiffDirFields[ ] =
{
{ USHORT, 2, 1 }, /* tdir_tag */
{ USHORT, 2, 1 }, /* tdir_type */
{ UINT, 4, 1 }, /* tdir_count */
{ 0, 0, 0 },
};
/*
* These are the sizes of various datatypes as they exist in tiff files.
* Always. We have to remember that in memory they can be wildly different.
*/
static int imTiffDataWidth[] = {
1, /* Nothing */
1, /* Byte */
1, /* ASCII */
2, /* Short */
4, /* Long */
8, /* Rational */
};
static int imTiffMask[]=
{
0xff, /* Nothing */
0xff, /* Byte */
0xff, /* ASCII */
0xffff, /* Short */
0xffffffff, /* Long */
};
typedef struct imTiffDirData
{
int type; /* Byte, short, or long */
int cnt; /* How many of them */
unsigned char *data; /* The actual array of values */
} imTiffDirData;
typedef struct imTiffDirInfo
{
unsigned int t_width; /* Image width */
unsigned int t_height; /* Image height */
unsigned short t_depth; /* Image depth in bits */
unsigned int t_compression; /* Image compression scheme */
unsigned int t_photometric; /* Photometric interpretation */
unsigned int t_orientation; /* Image orientation */
unsigned int t_rowsperstrip; /* Image rows/strip of data */
unsigned int t_samplesperpixel; /* Image samples/pixel */
unsigned int t_planarconfig; /* Storage type */
imTiffDirData t_xposition; /* Image x position */
imTiffDirData t_yposition; /* Image y position */
imTiffDirData t_bitspersample;/* Image depth in bits */
imTiffDirData t_stripoffsets; /* Image bytes counts for strips*/
imTiffDirData t_stripbytecounts; /* Image bytes counts for strips*/
imTiffDirData t_colormap; /* RGB map for pallette image */
unsigned char *t_imagedescr; /* Image description */
unsigned char *t_software; /* Software used to create */
unsigned char *t_datetime; /* Date/time created */
unsigned char *t_artist; /* Creator */
unsigned char *t_host; /* Host computer used */
unsigned char *t_whitepoint; /* Image white point */
unsigned char *t_primarychrom; /* Primary chromaticities */
unsigned int t_predictor; /* Predict pixel differences */
unsigned int t_matteing; /* Alpha channel is present ? */
} imTiffDirInfo;
static imTiffHeaderInfo imTiffHeader; /* TIFF file header */
/*
* CONSTANTS
* IMTIFFBIGENDIANMAGIC - file magic number
* IMTIFFLITTLEENDIANMAGIC - escape code for run-length encoding
* IMTIFFVERSION - TIFF version number
* IMTIFFBYTESPERWORD - Number of bytes in a word
* IMTIFFSHORTSPERWORD - Number of shorts in a word
* IMTIFFBITSPERBYTE - Number of bits in a byte
* IMTIFFNIBBLESPERBYTE - Number of nibbles in a byte
* IMTIFFNIBBLESMULT - Multiply by 16 to fill out to 8 bits
* IMTIFFBITMULT - Multiply by 255 to fill out to 8 bits
* IMTIFF(type) - enumerated types
*
* DESCRIPTION
* IMTIFFBIGENDIANMAGIC and IMTIFFLITTLEENDIANMAGIC are
* the 32-bit magic numbers at the top of all tiff files.
* The former indicates MBF byte ordering and the latter indicates
* LBF byte ordering.
*
* IMTIFFVERSION is always 42.
*
* The enumerated types are found in the directory type field to
* describe what is to be found in the offset field or whereever the
* offset points to.
*
*/
#define IMTIFFBIGENDIANMAGIC 0x4d4d
#define IMTIFFLITTLEENDIANMAGIC 0x4949
#define IMTIFFVERSION (42)
#define IMTIFFBITSPERBYTE (8)
#define IMTIFFBITSPERLONG (32)
#define IMTIFFBYTESPERWORD (4)
#define IMTIFFSHORTSPERWORD (2)
#define IMTIFFNIBBLESPERBYTE (2)
#define IMTIFFNIBBLEMULT (16)
#define IMTIFFBYTE (1)
#define IMTIFFASCII (2)
#define IMTIFFSHORT (3)
#define IMTIFFLONG (4)
#define IMTIFFRATIONAL (5)
/*
#define DEBUG
*/
/*
* CONSTANTS
* NULL - an empty pointer
*
* DESCRIPTION
* NULL might not be defined by the include files, but we need it.
*/
#ifndef NULL
#define NULL (0)
#endif
/*
* CONSTANTS
* TIFF Tag Definitions.
*
* DESCRIPTIONS
* These are straight out of tiff.h (with an IM_added )
* Those marked with a + are obsoleted by revision 5.0
*/
#define IM_TIFFTAG_SUBFILETYPE 254 /* subfile data descriptor */
#define FILETYPE_REDUCEDIMAGE 0x1 /* reduced resolution version */
#define FILETYPE_PAGE 0x2 /* one page of many */
#define FILETYPE_MASK 0x4 /* transparency mask */
#define IM_TIFFTAG_OSUBFILETYPE 255 /* +kind of data in subfile */
#define OFILETYPE_IMAGE 1 /* full resolution image data */
#define OFILETYPE_REDUCEDIMAGE 2 /* reduced size image data */
#define OFILETYPE_PAGE 3 /* one page of many */
#define IM_TIFFTAG_IMAGEWIDTH 256 /* image width in pixels */
#define IM_TIFFTAG_IMAGELENGTH 257 /* image height in pixels */
#define IM_TIFFTAG_BITSPERSAMPLE 258 /* bits per channel (sample) */
#define IM_TIFFTAG_COMPRESSION 259 /* data compression technique */
#define IM_COMPRESSION_NONE 1 /* dump mode */
#define IM_COMPRESSION_CCITTRLE 2 /* CCITT modified Huffman RLE */
#define IM_COMPRESSION_CCITTFAX3 3 /* CCITT Group 3 fax encoding */
#define IM_COMPRESSION_CCITTFAX4 4 /* CCITT Group 4 fax encoding */
#define IM_COMPRESSION_LZW 5 /* Lempel-Ziv & Welch */
#define IM_COMPRESSION_NEXT 32766 /* NeXT 2-bit RLE */
#define IM_COMPRESSION_CCITTRLEW 32771 /* #1 w/ word alignment */
#define IM_COMPRESSION_PACKBITS 32773 /* Macintosh RLE */
#define IM_COMPRESSION_THUNDERSCAN 32809 /* ThunderScan RLE */
#define IM_COMPRESSION_PICIO 32900 /* old Pixar picio RLE */
#define IM_COMPRESSION_SGIRLE 32901 /* Silicon Graphics RLE */
#define IM_TIFFTAG_PHOTOMETRIC 262 /* photometric interpretation */
#define IM_PHOTOMETRIC_MINISWHITE 0 /* min value is white */
#define IM_PHOTOMETRIC_MINISBLACK 1 /* min value is black */
#define IM_PHOTOMETRIC_RGB 2 /* RGB color model */
#define IM_PHOTOMETRIC_PALETTE 3 /* color map indexed */
#define IM_PHOTOMETRIC_MASK 4 /* holdout mask */
#define IM_PHOTOMETRIC_DEPTH 32768 /* z-depth data */
#define IM_TIFFTAG_THRESHHOLDING 263 /* +thresholding used on data */
#define IM_THRESHHOLD_BILEVEL 1 /* b&w art scan */
#define IM_THRESHHOLD_HALFTONE 2 /* or dithered scan */
#define IM_THRESHHOLD_ERRORDIFFUSE 3 /* usually floyd-steinberg */
#define IM_TIFFTAG_CELLWIDTH 264 /* +dithering matrix width */
#define IM_TIFFTAG_CELLLENGTH 265 /* +dithering matrix height */
#define IM_TIFFTAG_FILLORDER 266 /* +data order within a byte */
#define IM_FILLORDER_MSB2LSB 1 /* most significant -> least */
#define IM_FILLORDER_LSB2MSB 2 /* least significant -> most */
#define IM_TIFFTAG_DOCUMENTNAME 269 /* name of doc. image is from */
#define IM_TIFFTAG_IMAGEDESCRIPTION 270 /* info about image */
#define IM_TIFFTAG_MAKE 271 /* scanner manufacturer name */
#define IM_TIFFTAG_MODEL 272 /* scanner model name/number */
#define IM_TIFFTAG_STRIPOFFSETS 273 /* offsets to data strips */
#define IM_TIFFTAG_ORIENTATION 274 /* +image orientation */
#define IM_ORIENTATION_TOPLEFT 1 /* row 0 top, col 0 lhs */
#define IM_ORIENTATION_TOPRIGHT 2 /* row 0 top, col 0 rhs */
#define IM_ORIENTATION_BOTRIGHT 3 /* row 0 bottom, col 0 rhs */
#define IM_ORIENTATION_BOTLEFT 4 /* row 0 bottom, col 0 lhs */
#define IM_ORIENTATION_LEFTTOP 5 /* row 0 lhs, col 0 top */
#define IM_ORIENTATION_RIGHTTOP 6 /* row 0 rhs, col 0 top */
#define IM_ORIENTATION_RIGHTBOT 7 /* row 0 rhs, col 0 bottom */
#define IM_ORIENTATION_LEFTBOT 8 /* row 0 lhs, col 0 bottom */
#define IM_TIFFTAG_SAMPLESPERPIXEL 277 /* samples per pixel */
#define IM_TIFFTAG_ROWSPERSTRIP 278 /* rows per strip of data */
#define IM_TIFFTAG_STRIPBYTECOUNTS 279 /* bytes counts for strips */
#define IM_TIFFTAG_MINSAMPLEVALUE 280 /* +minimum sample value */
#define IM_TIFFTAG_MAXSAMPLEVALUE 281 /* maximum sample value */
#define IM_TIFFTAG_XRESOLUTION 282 /* pixels/resolution in x */
#define IM_TIFFTAG_YRESOLUTION 283 /* pixels/resolution in y */
#define IM_TIFFTAG_PLANARCONFIG 284 /* storage organization */
#define IM_PLANARCONFIG_CONTIG 1 /* single image plane */
#define IM_PLANARCONFIG_SEPARATE 2 /* separate planes of data */
#define IM_TIFFTAG_PAGENAME 285 /* page name image is from */
#define IM_TIFFTAG_XPOSITION 286 /* x page offset of image lhs */
#define IM_TIFFTAG_YPOSITION 287 /* y page offset of image lhs */
#define IM_TIFFTAG_FREEOFFSETS 288 /* +byte offset to free block */
#define IM_TIFFTAG_FREEBYTECOUNTS 289 /* +sizes of free blocks */
#define IM_TIFFTAG_GRAYRESPONSEUNIT 290 /* gray scale curve accuracy */
#define IM_GRAYRESPONSEUNIT_10S 1 /* tenths of a unit */
#define IM_GRAYRESPONSEUNIT_100S 2 /* hundredths of a unit */
#define IM_GRAYRESPONSEUNIT_1000S 3 /* thousandths of a unit */
#define IM_GRAYRESPONSEUNIT_10000S 4 /* ten-thousandths of a unit */
#define IM_GRAYRESPONSEUNIT_100000S 5 /* hundred-thousandths */
#define IM_TIFFTAG_GRAYRESPONSECURVE 291 /* gray scale response curve */
#define IM_TIFFTAG_GROUP3OPTIONS 292 /* 32 flag bits */
#define IM_GROUP3OPT_2DENCODING 0x1 /* 2-dimensional coding */
#define IM_GROUP3OPT_UNCOMPRESSED 0x2 /* data not compressed */
#define IM_GROUP3OPT_FILLBITS 0x4 /* fill to byte boundary */
#define IM_TIFFTAG_GROUP4OPTIONS 293 /* 32 flag bits */
#define IM_GROUP4OPT_UNCOMPRESSED 0x2 /* data not compressed */
#define IM_TIFFTAG_RESOLUTIONUNIT 296 /* units of resolutions */
#define IM_RESUNIT_NONE 1 /* no meaningful units */
#define IM_RESUNIT_INCH 2 /* english */
#define IM_RESUNIT_CENTIMETER 3 /* metric */
#define IM_TIFFTAG_PAGENUMBER 297 /* page numbers of multi-page */
#define IM_TIFFTAG_COLORRESPONSEUNIT 300 /* color scale curve accuracy */
#define IM_COLORRESPONSEUNIT_10S 1 /* tenths of a unit */
#define IM_COLORRESPONSEUNIT_100S 2 /* hundredths of a unit */
#define IM_COLORRESPONSEUNIT_1000S 3 /* thousandths of a unit */
#define IM_COLORRESPONSEUNIT_10000S 4 /* ten-thousandths of a unit */
#define IM_COLORRESPONSEUNIT_100000S 5 /* hundred-thousandths */
#define IM_TIFFTAG_COLORRESPONSECURVE 301 /* RGB response curve */
#define IM_TIFFTAG_SOFTWARE 305 /* name & release */
#define IM_TIFFTAG_DATETIME 306 /* creation date and time */
#define IM_TIFFTAG_ARTIST 315 /* creator of image */
#define IM_TIFFTAG_HOSTCOMPUTER 316 /* machine where created */
#define IM_TIFFTAG_PREDICTOR 317 /* prediction scheme w/ LZW */
#define IM_TIFFTAG_WHITEPOINT 318 /* image white point */
#define IM_TIFFTAG_PRIMARYCHROMATICITIES 319 /* primary chromaticities */
#define IM_TIFFTAG_COLORMAP 320 /* RGB map for pallette image */
#define IM_TIFFTAG_BADFAXLINES 326 /* lines w/ wrong pixel count */
#define IM_TIFFTAG_CLEANFAXDATA 327 /* regenerated line info */
#define IM_CLEANFAXDATA_CLEAN 0 /* no errors detected */
#define IM_CLEANFAXDATA_REGENERATED 1 /* receiver regenerated lines */
#define IM_CLEANFAXDATA_UNCLEAN 2 /* uncorrected errors exist */
#define IM_TIFFTAG_CONSECUTIVEBADFAXLINES 328 /* max consecutive bad lines */
/* tags 32995-32999 are private tags registered to SGI */
#define IM_TIFFTAG_MATTEING 32995 /* alpha channel is present */
#define IM_TIFFTAG_SGICOLORMAP 32996 /* SGI colormap indicator */
/*
* STRUCTURE
* tagnames - an array of the names of the tages
*
* DESCRIPTION
* An array of tagnames so that we can print and debug easily.
*/
static
struct ImTiffTagNames {
int tag;
char *name;
} ImTiffTagNames[] = {
{ IM_TIFFTAG_SUBFILETYPE, "SubFileType" },
{ IM_TIFFTAG_OSUBFILETYPE, "OldSubFileType" },
{ IM_TIFFTAG_IMAGEWIDTH, "ImageWidth" },
{ IM_TIFFTAG_IMAGELENGTH, "ImageLength" },
{ IM_TIFFTAG_BITSPERSAMPLE, "BitsPerSample" },
{ IM_TIFFTAG_COMPRESSION, "Compression" },
{ IM_TIFFTAG_PHOTOMETRIC, "Photometric" },
{ IM_TIFFTAG_THRESHHOLDING, "Threshholding" },
{ IM_TIFFTAG_CELLWIDTH, "CellWidth" },
{ IM_TIFFTAG_CELLLENGTH, "CellLength" },
{ IM_TIFFTAG_FILLORDER, "FillOrder" },
{ IM_TIFFTAG_DOCUMENTNAME, "DocumentName" },
{ IM_TIFFTAG_IMAGEDESCRIPTION, "ImageDescription" },
{ IM_TIFFTAG_MAKE, "Make" },
{ IM_TIFFTAG_MODEL, "Model" },
{ IM_TIFFTAG_STRIPOFFSETS, "StripOffsets" },
{ IM_TIFFTAG_ORIENTATION, "Orientation" },
{ IM_TIFFTAG_SAMPLESPERPIXEL, "SamplesPerPixel" },
{ IM_TIFFTAG_ROWSPERSTRIP, "RowsPerStrip" },
{ IM_TIFFTAG_STRIPBYTECOUNTS, "StripByteCounts" },
{ IM_TIFFTAG_MINSAMPLEVALUE, "MinSampleValue" },
{ IM_TIFFTAG_MAXSAMPLEVALUE, "MaxSampleValue" },
{ IM_TIFFTAG_XRESOLUTION, "XResolution" },
{ IM_TIFFTAG_YRESOLUTION, "YResolution" },
{ IM_TIFFTAG_PLANARCONFIG, "PlanarConfig" },
{ IM_TIFFTAG_PAGENAME, "PageName" },
{ IM_TIFFTAG_XPOSITION, "XPosition" },
{ IM_TIFFTAG_YPOSITION, "YPosition" },
{ IM_TIFFTAG_FREEOFFSETS, "FreeOffsets" },
{ IM_TIFFTAG_FREEBYTECOUNTS, "FreeByteCounts" },
{ IM_TIFFTAG_GRAYRESPONSEUNIT, "GrayResponseUnit" },
{ IM_TIFFTAG_GRAYRESPONSECURVE,"GrayResponseCurve" },
{ IM_TIFFTAG_GROUP3OPTIONS, "Group3Options" },
{ IM_TIFFTAG_GROUP4OPTIONS, "Group4Options" },
{ IM_TIFFTAG_RESOLUTIONUNIT, "ResolutionUnit" },
{ IM_TIFFTAG_PAGENUMBER, "PageNumber" },
{ IM_TIFFTAG_COLORRESPONSEUNIT,"ColorResponseUnit" },
{ IM_TIFFTAG_COLORRESPONSECURVE,"ColorResponseCurve" },
{ IM_TIFFTAG_SOFTWARE, "Software" },
{ IM_TIFFTAG_DATETIME, "DateTime" },
{ IM_TIFFTAG_ARTIST, "Artist" },
{ IM_TIFFTAG_HOSTCOMPUTER, "HostComputer" },
{ IM_TIFFTAG_PREDICTOR, "Predictor" },
{ IM_TIFFTAG_WHITEPOINT, "Whitepoint" },
{ IM_TIFFTAG_PRIMARYCHROMATICITIES,"PrimaryChromaticities" },
{ IM_TIFFTAG_COLORMAP, "Colormap" },
{ IM_TIFFTAG_BADFAXLINES, "Bad FAX Lines" },
{ IM_TIFFTAG_CLEANFAXDATA, "Clean Fax Data" },
{ IM_TIFFTAG_CONSECUTIVEBADFAXLINES, "Consecutive bad fax lines" },
{ IM_TIFFTAG_SGICOLORMAP, "SGIColormap" },
{ 32768, "OLD BOGUS Matteing tag" },
{ IM_TIFFTAG_MATTEING, "Matteing" },
};
#define IM_NTAGS (sizeof (ImTiffTagNames) / sizeof (ImTiffTagNames[0]))
#define IMTIFF_IMAGEWIDTH_INDEX 0
#define IMTIFF_IMAGELENGTH_INDEX 1
#define IMTIFF_BITSPERSAMPLE_INDEX 2
#define IMTIFF_COMPRESSION_INDEX 3
#define IMTIFF_PHOTOMETRIC_INDEX 4
#define IMTIFF_STRIPOFFSETS_INDEX 5
#define IMTIFF_ORIENTATION_INDEX 6
#define IMTIFF_SAMPLESPERPIXEL_INDEX 7
#define IMTIFF_ROWSPERSTRIP_INDEX 8
#define IMTIFF_STRIPBYTECOUNTS_INDEX 9
#define IMTIFF_PLANARCONFIG_INDEX 10
#define IMTIFF_XPOSITION_INDEX 11
#define IMTIFF_YPOSITION_INDEX 12
#define IMTIFF_MATTEING_INDEX 13
#define IMTIFF_COLORMAP_INDEX 14 /* Alway last ! */
/*
* By default we write out a 1 bit deep file with 1 sample per pixel.
* No compression and origin in the topleft corner.
*
* Note: These must be ordered by tag.
*/
static imTiffDirEntry imTiffWriteDir[] =
{
{ IM_TIFFTAG_IMAGEWIDTH, IMTIFFSHORT, 1, 0 },
{ IM_TIFFTAG_IMAGELENGTH, IMTIFFSHORT, 1, 0 },
{ IM_TIFFTAG_BITSPERSAMPLE, IMTIFFSHORT, 1, (8 << 16) },
{ IM_TIFFTAG_COMPRESSION, IMTIFFSHORT, 1, (IM_COMPRESSION_NONE << 16) },
{ IM_TIFFTAG_PHOTOMETRIC, IMTIFFSHORT, 1, (IM_PHOTOMETRIC_PALETTE << 16) },
{ IM_TIFFTAG_STRIPOFFSETS, IMTIFFLONG, 1, 0 },
{ IM_TIFFTAG_ORIENTATION, IMTIFFSHORT, 1, (IM_ORIENTATION_TOPLEFT << 16) },
{ IM_TIFFTAG_SAMPLESPERPIXEL, IMTIFFSHORT, 1, 1 },
{ IM_TIFFTAG_ROWSPERSTRIP, IMTIFFLONG, 1, 1 },
{ IM_TIFFTAG_STRIPBYTECOUNTS, IMTIFFLONG, 1, 0 },
{ IM_TIFFTAG_PLANARCONFIG, IMTIFFSHORT,1, (IM_PLANARCONFIG_CONTIG << 16) },
{ IM_TIFFTAG_XPOSITION, IMTIFFRATIONAL, 1, 0 },
{ IM_TIFFTAG_YPOSITION, IMTIFFRATIONAL, 1, 0 },
{ IM_TIFFTAG_MATTEING, IMTIFFSHORT, 1, 0 },
{ IM_TIFFTAG_COLORMAP, IMTIFFSHORT, 768, 0 },
};
#define IMTIFFWRITEDIRENTRIES sizeof(imTiffWriteDir)/sizeof(imTiffDirEntry)
#ifdef __STDC__
static int imTiffReadDirectory( int ioType, int fd, FILE *fp, unsigned int *dirOffset, imTiffDirInfo *imTDI );
static int imTiffRead16( int ioType, int fd, FILE *fp, TagTable *flags, TagTable *tagTable, imTiffDirInfo *imTDI,
ImVfb **pVfb );
static int imTiffRead24Cont( int ioType, int fd, FILE *fp, TagTable *flags, TagTable *tagTable, imTiffDirInfo *imTDI,
ImVfb **pVfb );
static int imTiffRead24Sep( int ioType, int fd, FILE *fp, TagTable *flags, TagTable *tagTable, imTiffDirInfo *imTDI,
ImVfb **pVfb );
static int imTiffRead8( int ioType, int fd, FILE *fp, TagTable *flags, TagTable *tagTable, imTiffDirInfo *imTDI, ImVfb **pVfb );
static int imTiffRead4( int ioType, int fd, FILE *fp, TagTable *flags, TagTable *tagTable, imTiffDirInfo *imTDI, ImVfb **pVfb );
static int imTiffRead1( int ioType, int fd, FILE *fp, TagTable *flags, TagTable *tagTable, imTiffDirInfo *imTDI, ImVfb **pVfb );
static int imTiffGetClt( imTiffDirInfo *imTDI, ImClt **pClt );
static int imTiffVfbWrite( int ioType, int fd, FILE *fp, TagTable *flagsTable, ImVfb *vfb );
#else
static int imTiffReadDirectory( );
static int imTiffRead16( );
static int imTiffRead24Cont( );
static int imTiffRead24Sep( );
static int imTiffRead8( );
static int imTiffRead4( );
static int imTiffRead1( );
static int imTiffGetClt( );
static int imTiffVfbWrite( );
#endif
/*
* FUNCTION
* imPrintTiffTag - print the name of tag
*
* DESCRIPTION
* Given a tag value, seach through the table until the entry with
* the matching tag is found. Print the string in the second field.
*/
static void /* Doesn't return a value */
#ifdef __STDC__
imPrintTiffTag(unsigned short tag)
#else
imPrintTiffTag(tag)
unsigned short tag; /* The tag number */
#endif /* __STDC__ */
{
struct ImTiffTagNames *tp;
char message[1024];
for (tp = ImTiffTagNames; tp < &ImTiffTagNames[IM_NTAGS]; tp++)
{
if (tp->tag == tag)
{
sprintf(message, "%s (%d) \n", tp->name, tag);
ImErrorWarning(message,IM_NOTHING,IMEUNSUPPORTED);
return;
}
}
sprintf(message, "%d (0x%x) Tag Not Found \n", tag, tag);
ImErrorWarning(message,IM_NOTHING,IMEUNSUPPORTED);
}
#ifdef DEBUG
/*
* FUNCTION
* imPrintTiffDirLongEntry - Print the fields in a data entry
* imPrintTiffDirInfo - Print the fields in a Tiff directory
*
* DESCRIPTION
* Print the fields from the internal tiff directory structure in
* human readable form.
* This is strictly for debugging.
*
* WARNING: This routine assumes that a double is 8 bytes.
*/
static void
#ifdef __STDC__
imPrintTiffDirLongEntry( imTiffDirData *imTD, char *str )
#else
imPrintTiffDirLongEntry( imTD, str )
imTiffDirData *imTD; /* The internal directory info */
char *str;
#endif
{
int i;
int val;
fprintf(stderr,"%s: type %d count %d data %d \n <",
str, imTD->type, imTD->cnt, imTD->data );
if ( imTD->data == NULL )
{
fprintf(stderr," > \n");
return;
}
if ( imTD->type == IMTIFFASCII )
{
fprintf(stderr,"%s > \n",imTD->data );
return;
}
for( i=0; i<imTD->cnt; i++)
{
val = imTiffDataItem( imTD, i );
fprintf(stderr,"%d ",val);
}
fprintf(stderr,"> \n ");
}
static void
#ifdef __STDC__
imPrintTiffDirInfo( imTiffDirInfo * imTI )
#else
imPrintTiffDirInfo( imTI )
imTiffDirInfo* imTI; /* The internal directory info */
#endif
{
fprintf(stderr,"Tiff Directory Info \n");
fprintf(stderr,"------------------- \n");
fprintf(stderr,"width : %d \n", imTI->t_width);
fprintf(stderr,"heigt : %d \n", imTI->t_height);
fprintf(stderr,"depth : %d \n", imTI->t_depth);
fprintf(stderr,"compr : %d \n", imTI->t_compression);
fprintf(stderr,"photo : %d \n", imTI->t_photometric);
fprintf(stderr,"planr : %d \n", imTI->t_planarconfig);
fprintf(stderr,"orien : %d \n", imTI->t_orientation);
fprintf(stderr,"sampl : %d \n", imTI->t_samplesperpixel);
fprintf(stderr,"rowsp : %d \n", imTI->t_rowsperstrip);
fprintf(stderr,"descrip : %s \n", imTI->t_imagedescr);
fprintf(stderr,"software : %s \n", imTI->t_software);
fprintf(stderr,"datetime : %s \n", imTI->t_datetime);
fprintf(stderr,"user : %s \n", imTI->t_artist);
fprintf(stderr,"host : %s \n", imTI->t_host);
fprintf(stderr,"whitepoint : %s \n", imTI->t_whitepoint);
fprintf(stderr,"primarychr : %s \n", imTI->t_primarychrom);
fprintf(stderr,"predictor : %d \n", imTI->t_predictor);
fprintf(stderr,"matting : %d \n", imTI->t_matteing);
imPrintTiffDirLongEntry( &imTI->t_xposition, "xposition" );
imPrintTiffDirLongEntry( &imTI->t_yposition, "yposition" );
imPrintTiffDirLongEntry( &imTI->t_bitspersample, "bitspersample" );
imPrintTiffDirLongEntry( &imTI->t_colormap, "colormap" );
imPrintTiffDirLongEntry( &imTI->t_stripbytecounts, "stripbytecounts" );
imPrintTiffDirLongEntry( &imTI->t_stripoffsets, "stripoffsets" );
fprintf(stderr,"------------------- \n");
}
static void
#ifdef __STDC__
imPrintTiffWriteDir( char *s, unsigned int *sc, unsigned int *so )
#else
imPrintTiffWriteDir( s, sc, so )
char *s;
unsigned int *sc, *so;
#endif
{
int i, y;
fprintf(stderr,"%s \n",s);
for(i=0;i<IMTIFFWRITEDIRENTRIES;i++)
{
imPrintTiffTag( imTiffWriteDir[i].tdir_tag );
fprintf(stderr,"cnt %d type %d offset %d 0x%x \n",
imTiffWriteDir[i].tdir_count,
imTiffWriteDir[i].tdir_type,
imTiffWriteDir[i].tdir_offset,
imTiffWriteDir[i].tdir_offset );
}
fprintf(stderr,"\n <bytecount offset> \n");
y = imTiffWriteDir[IMTIFF_IMAGELENGTH_INDEX].tdir_offset >> 16;
for( i=0; i<y; i++ )
fprintf(stderr,"<%d %d> ", *sc++, *so++ );
}
#endif /* DEBUG */
/*
* FUNCTION
* imTiffRead - read a TIFF image file
*
* DESCRIPTION
* The file header is read and the magic number checked. If there is
* a CLT in the file, it is read in and converted into an ImClt.
* Separate routines are then called to handle different depth and
* storage format variations of the image data.
*/
static int /* Returns status */
#ifdef __STDC__
imTiffRead( int ioType, int fd, FILE *fp, TagTable *flags, TagTable *tagTable )
#else
imTiffRead( ioType, fd, fp, flags, tagTable )
int ioType; /* I/O flags */
int fd; /* Input file descriptor */
FILE *fp; /* Input file pointer */
TagTable *flags; /* Format flags */
TagTable *tagTable; /* Tag table to add to */
#endif
{
unsigned int nextDir; /* Offset to next directory */
unsigned int imageCount; /* Number of images in file */
ImVfb *vfb; /* vfb holder */
ImClt *clt; /* clt holder */
unsigned char fileBuf; /* Read in the whole file */
int status; /* Status returned from readdir */
imTiffDirInfo imTiffInfo; /* Structure with useful info */
int depth; /* The bit depth of the image */
char message[100]; /* ImInfo message */
imageCount = 0;
/*
* Initialize the byte ordering to something so that we can read the
* header
*/
BinByteOrder( BINMBF );
BinFloatFormat( BINIEEE );
/*
* Read the magic number, check it, initialize byte order, then
* read in the version number and directory offset to the first
* directory.
*/
if ( ImBinRead( ioType, fd, fp, &imTiffHeader.tiff_magic, USHORT, 2, 1 ) == -1)
{
ImReturnBinError( );
}
if ( imTiffHeader.tiff_magic == IMTIFFBIGENDIANMAGIC )
BinByteOrder( BINMBF );
else if ( imTiffHeader.tiff_magic == IMTIFFLITTLEENDIANMAGIC )
BinByteOrder( BINLBF );
else
{
ImErrNo = IMEMAGIC;
ImErrorFatal( ImQError( ), -1, ImErrNo );
}
if ( ImBinRead( ioType, fd, fp, &imTiffHeader.tiff_version,
USHORT, 2, 1 ) == -1)
{
ImReturnBinError( );
}
if ( imTiffHeader.tiff_version != IMTIFFVERSION )
{
ImErrNo = IMEVERSION;
ImErrorFatal( ImQError( ), -1, ImErrNo );
}
/*
* Output -verbose message
*/
sprintf( message, "%d", IMTIFFVERSION );
ImInfo( "Version", message );
if ( imTiffHeader.tiff_magic == IMTIFFBIGENDIANMAGIC )
{
ImInfo( "Byte Order", "Most Significant Byte First" );
}
else
ImInfo( "Byte Order", "Least Significant Byte First" );
if ( ImBinRead( ioType, fd, fp, &imTiffHeader.tiff_diroff,
UINT, 4, 1 ) == -1)
{
ImReturnBinError( );
}
/*
* Loop for every Image File Directory (IFD) in the file
*/
nextDir = imTiffHeader.tiff_diroff;
while ( nextDir )
{
/*
* Read in the directory info. It is variable length.
* Put the important info in the imTiffDirInfo struct.
*/
memset( &imTiffInfo, 0x00, sizeof(imTiffDirInfo) );
status = imTiffReadDirectory( ioType, fd, fp, &nextDir,
&imTiffInfo );
if ( status == -1 )
return( -1 ); /* ImErrNo already set */
#ifdef DEBUG
imPrintTiffDirInfo( &imTiffInfo );
#endif
/*
* Output -verbose message
*/
sprintf( message, "%d", (imageCount+1) );
ImInfo( "Image", message );
if( imTiffInfo.t_imagedescr != NULL )
{
ImInfo( "Description", imTiffInfo.t_imagedescr );
}
else
ImInfo( "Description", "none" );
sprintf( message, "%d x %d", imTiffInfo.t_width,
imTiffInfo.t_height );
ImInfo( "Resolution", message );
depth = imTiffInfo.t_depth * imTiffInfo.t_samplesperpixel;
if( depth < 24 )
sprintf( message, "%d-bit Color Indexed", depth );
else
sprintf( message, "%d-bit RGB", depth );
ImInfo( "Type", message );
if( imTiffInfo.t_planarconfig == IM_PLANARCONFIG_CONTIG )
sprintf( message, "Chunky (Contiguous)" );
else
sprintf( message, "Planar (Separate)" );
ImInfo( "Plane Configuration", message );
/*
* Call the appropriate routine for the depth of the image.
* These routines are not called anywhere else but at least
* it breaks up the code for debugging and modularity.
* The routines called here have to make their own decisions
* about what to do with encoded pixel data.
*/
depth = imTiffInfo.t_depth * imTiffInfo.t_samplesperpixel;
/*
* 32 images refer to index32. 24 includes the alpha channel
*/
if ( imTiffInfo.t_matteing )
depth = 24;
switch( depth )
{
case 16:
status = imTiffRead16( ioType, fd, fp, flags,
tagTable, &imTiffInfo, &vfb );
break;
case 24:
if ( imTiffInfo.t_planarconfig == IM_PLANARCONFIG_CONTIG )
status = imTiffRead24Cont(ioType,fd, fp, flags,
tagTable, &imTiffInfo, &vfb );
else
if ( imTiffInfo.t_planarconfig == IM_PLANARCONFIG_SEPARATE)
status = imTiffRead24Sep(ioType,fd, fp, flags,
tagTable, &imTiffInfo, &vfb );
else
{
ImErrNo = IMEPLANES;
status = -1;
}
break;
case 8:
status = imTiffRead8( ioType, fd, fp, flags,
tagTable, &imTiffInfo, &vfb );
break;
case 4:
status = imTiffRead4( ioType, fd, fp, flags,
tagTable, &imTiffInfo, &vfb );
break;
case 1:
status = imTiffRead1( ioType, fd, fp, flags,
tagTable, &imTiffInfo, &vfb );
break;
case 32:
default:
ImErrNo = IMEDEPTH; /* We only understand 24,8,1 */
ImErrorFatal( ImQError( ), -1, ImErrNo );
}
if ( status == -1 )
return( -1 ); /* ImErrNo already set */
/*
* Check the image orientation
*/
if ( imTiffInfo.t_orientation == IM_ORIENTATION_BOTLEFT ||
imTiffInfo.t_orientation == IM_ORIENTATION_LEFTBOT )
if ( ImVfbFlip( vfb, IMVFBYFLIP, vfb ) == IMVFBNULL )
{
ImErrorFatal( ImQError( ), -1, ImErrNo );
}
/*
* Get an associated CLT if there is one
*/
if ( imTiffGetClt( &imTiffInfo, &clt ) == -1 )
return( -1 ); /* ImErrNo already set */
if ( clt != IMCLTNULL )
{
ImVfbSClt( vfb, clt );
TagTableAppend( tagTable,
TagEntryAlloc( "image clt", POINTER, &clt ));
}
TagTableAppend(tagTable, TagEntryAlloc( "image vfb",
POINTER, &vfb ));
/*
* Output -verbose message
*/
switch( imTiffInfo.t_compression )
{
case IM_COMPRESSION_NONE:
sprintf( message, "none (Dump)" );
break;
case IM_COMPRESSION_CCITTRLE:
sprintf( message, "CCITT Run Length Encoded \
(Huffman RLE)" );
break;
case IM_COMPRESSION_CCITTFAX3:
sprintf( message, "CCITT Group 3 FAX" );
break;
case IM_COMPRESSION_CCITTFAX4:
sprintf( message, "CCITT Group 4 FAX" );
break;
case IM_COMPRESSION_LZW:
sprintf(message,"Lempel-Ziv and Welch (LZW)" );
break;
case IM_COMPRESSION_NEXT:
sprintf( message, "Run Length Encoded \
(NeXT 2-bit RLE)" );
break;
case IM_COMPRESSION_CCITTRLEW:
sprintf( message, "Run Length Encoded W \
(RLE with word alignment)" );
break;
case IM_COMPRESSION_PACKBITS:
sprintf( message, "Apple Macintosh Packbits");
break;
case IM_COMPRESSION_THUNDERSCAN:
sprintf( message, "Run Length Encoded \
(Thunderscan RLE)" );
break;
case IM_COMPRESSION_PICIO:
sprintf( message, "Run Length Encoded \
(Pixar RLE)" );
break;
case IM_COMPRESSION_SGIRLE:
sprintf( message, "Run Length Encoded \
(Silicon Graphics RLE)" );
break;
}
ImInfo( "Compression Type", message );
if( imTiffInfo.t_matteing )
{
ImInfo( "Alpha Channel", "8-bit\n" );
}
else
ImInfo( "Alpha Channel", "none\n" );
imageCount++;
}
if ( imTiffInfo.t_compression == IM_COMPRESSION_LZW )
ImLzwCleanup( );
/*
* Return the number of vfb's in the tag table
*/
return( imageCount );
}
/*
* FUNCTION
* imTiffDecode - Decode the type, length, and offset fields
*
* DESCRIPTION
* This is the case where the actual data item is stored in the offset
* field. The type indicates how many bytes we want (i think). The
* bytes are left justified so we have to shift to get them out.
*/
static int
#ifdef __STDC__
imTiffDecode( imTiffDirEntry *tifDir, unsigned char *p )
#else
imTiffDecode( tifDir, p )
imTiffDirEntry *tifDir;
unsigned char *p;
#endif
{
int shift;
int da;
switch( tifDir->tdir_type )
{
case IMTIFFBYTE:
case IMTIFFASCII:
shift = (IMTIFFBYTESPERWORD - tifDir->tdir_count) * IMTIFFBITSPERBYTE;
da = tifDir->tdir_offset >> shift;
memcpy( p, &da, sizeof(int) );
break;
case IMTIFFSHORT:
shift = (IMTIFFSHORTSPERWORD - tifDir->tdir_count) * IMTIFFBITSPERBYTE;
da = tifDir->tdir_offset >> (shift * IMTIFFSHORTSPERWORD);
memcpy( p, &da, sizeof(int) );
break;
case IMTIFFLONG:
memcpy( p, &tifDir->tdir_offset, sizeof(int) );
break;
case IMTIFFRATIONAL: /* It is an error to have 8 byte data here*/
default:
ImErrNo = IMEOUTOFRANGE;
ImErrorFatal( ImQError( ), -1, ImErrNo );
}
return( 0 );
}
/*
* FUNCTION
* imTiffDecOrFetch - Decode or fetch directory data
*
* DESCRIPTION
* Seek to the proper place in the file, allocate memory and then
* read in the pertinent data. This is used to read in arrays of
* data including strings, and colormaps.
* If the data is actually just stuffed in the offset field then
* copy that to the malloced space.
* Return a pointer to the dataspace.
*/
static int /* Returns pointer or -1 for error */
#ifdef __STDC__
imTiffDecOrFetch( int ioType, int fd, FILE *fp, imTiffDirEntry *d, unsigned char **p )
#else
imTiffDecOrFetch( ioType, fd, fp, d, p )
int ioType; /* I/O flags */
int fd; /* Input file descriptor */
FILE *fp; /* Input file pointer */
imTiffDirEntry *d; /* The directory entry to fill */
unsigned char **p; /* Return a pointer result */
#endif
{
int size; /* Size of the dir data */
int status; /* Returned from Bin Read */
int *ip=NULL;
unsigned short *sp=NULL;
double *dp=NULL;
/*
* Size of the data in the tiff file, NOT size in memory
*/
size = d->tdir_count * imTiffDataWidth[d->tdir_type];
if ( size <= 4 )
{
if (imTiffDecode( d, (unsigned char*)p ) == -1)
return( -1 ); /* ImErrNo already set */
}
else
{
ImSeek( ioType, fd, fp, d->tdir_offset, 0 );
switch( d->tdir_type )
{
case IMTIFFRATIONAL:
ImMalloc( dp, double *, d->tdir_count * sizeof(double));
status = ImBinRead( ioType, fd, fp, dp, DOUBLE, 8,
d->tdir_count );
*p = (unsigned char *)dp;
break;
case IMTIFFLONG:
ImMalloc( ip, int *, d->tdir_count * sizeof(int));
status = ImBinRead( ioType, fd, fp, ip, INT, 4,
d->tdir_count );
*p = (unsigned char *)ip;
break;
case IMTIFFSHORT:
ImMalloc( sp, unsigned short *, d->tdir_count * sizeof(ushort));
status = ImBinRead( ioType, fd, fp, sp, USHORT, 2,
d->tdir_count );
*p = (unsigned char *)sp;
break;
case IMTIFFBYTE:
case IMTIFFASCII:
ImMalloc( *p, unsigned char *, d->tdir_count * sizeof(unsigned char));
status = ImBinRead( ioType, fd, fp, *p, UCHAR, 1,
d->tdir_count );
break;
}
if ( status == -1 )
{
ImReturnBinError( );
}
}
return( 0 );
}
/*
* FUNCTION
* imTiffDataItem - Get a data value out of the data field
*
* DESCRIPTION
* Data may either be resident in the data field or else may be
* out in an data array. Given an index and a XXX structure, find
* and return the right size data element.
*/
static int /* Returns pointer or -1 for error */
#ifdef __STDC__
imTiffDataItem( imTiffDirData *iTD, int index )
#else
imTiffDataItem( iTD, index )
imTiffDirData *iTD; /* The data item structure */
int index; /* What number item */
#endif
{
int size; /* Size of one item of dir data */
int shift; /* Number of bits to shift */
unsigned char *cd; /* Array of chars */
short *sd; /* Array of shorts */
int *id; /* Array of ints */
double *dd; /* Array of doubles */
/*
* Size of the data in the tiff file, Not size in memory
*/
size = imTiffDataWidth[iTD->type];
if ( iTD->cnt * size <= 4 ) /* Data is resident in data field */
{
shift = index * size * IMTIFFBITSPERBYTE;
return(((int)iTD->data >> shift) & imTiffMask[iTD->type]);
}
else
{
/*
* Use the correct pointer type, and then indices work !
*/
switch (iTD->type)
{
case IMTIFFBYTE:
case IMTIFFASCII:
cd = (unsigned char *)iTD->data;
return ((int)cd[index]);
break;
case IMTIFFSHORT:
sd = (short *)iTD->data;
return ((int)sd[index]);
break;
case IMTIFFLONG:
id = (int *)iTD->data;
return ((int)id[index]);
break;
case IMTIFFRATIONAL:
dd = (double *)iTD->data;
return ((int)dd[index]);
break;
}
}
}
/*
* imTiffReadDirectory - read a TIFF Rasterfile Directory
*
* DESCRIPTION
* Read a Tiff directory. Parse the directory and associated pixel data.
* Store the resulting vfb and possibly clt in the tagtable.
* Return the offset to the next tiff directory in dirOffset.
*/
static int
#ifdef __STDC__
imTiffReadDirectory( int ioType, int fd, FILE *fp, unsigned int *dirOffset, imTiffDirInfo *imTDI )
#else
imTiffReadDirectory( ioType, fd, fp, dirOffset, imTDI )
int ioType; /* I/O flags */
int fd; /* Input file descriptor */
FILE *fp; /* Input file pointer */
unsigned int *dirOffset; /* The offset of the tiff dir */
imTiffDirInfo *imTDI; /* Unencoded directory info */
#endif
{
imTiffDirEntry *tifDir; /* Store an array of entries */
unsigned char *bits; /* Point to an array of data */
unsigned short numEntries; /* Number of directory entries */
unsigned short so[2]; /* Temp storage of two shorts */
int i; /* Loop counter */
int c,t; /* count and type of data data */
int depth; /* Bit depth of image */
int status=0; /* Hold returned status */
int size; /* Number of bytes of offset */
/*
* Seek to the directory at offset dirOffset in the file.
*/
ImSeek( ioType, fd, fp, *dirOffset, 0 );
/*
* Read in the number of entries in this directory, allocate space
* and then read in the directory entries one by one.
*/
if ( ImBinRead( ioType, fd, fp, &numEntries, USHORT, 2, 1) == -1 )
{
ImReturnBinError( );
}
ImCalloc( tifDir, imTiffDirEntry *, sizeof(imTiffDirEntry), numEntries);
/*
* Read all of the directory entries into an array of structs
*/
for( i=0; i<numEntries; i++ )
{
/*
* Read the type, count, and tag fields since they are
* of fixed type.
*/
if ( ImBinReadStruct( ioType, fd, fp, &(tifDir[i]),
imTiffDirFields) == -1 )
{
ImReturnBinError( );
}
/*
* Read the offset field separately since it can contain one
* of three different types of variables.
* Check to see if the offset field contains an offset.
* If it does, then read it as an int and continue
*/
size = tifDir[i].tdir_count *
imTiffDataWidth[tifDir[i].tdir_type];
if ( size > 4 )
{
if ( ImBinRead( ioType, fd, fp,
&(tifDir[i].tdir_offset), INT, 4, 1) == -1 )
ImReturnBinError( );
continue;
}
/*
* If it is not an offset, then there is data in the
* offset field. We have to read it as the correct type
*/
switch( tifDir[i].tdir_type )
{
case IMTIFFBYTE:
case IMTIFFASCII:
status = ImBinRead( ioType, fd, fp,
&(tifDir[i].tdir_offset), UCHAR, 1, 4);
break;
case IMTIFFSHORT:
status = ImBinRead( ioType, fd, fp, so, USHORT, 2, 2);
tifDir[i].tdir_offset = (so[0] << 16) | so[1];
break;
case IMTIFFLONG:
status = ImBinRead( ioType, fd, fp,
&(tifDir[i].tdir_offset), INT, 4, 1);
break;
}
if ( status == -1 )
ImReturnBinError( );
}
/*
* Read the offset of the next directory. It will probably be
* zero indicating that this file only has one directory.
*/
if ( ImBinRead( ioType, fd, fp, dirOffset, UINT, 4, 1) == -1 )
{
ImReturnBinError( );
}
/*
* Parse the directory entries and do something sensible with each
* value we are interested in.
*/
for( i=0; i<numEntries; i++ )
{
switch( tifDir[i].tdir_tag )
{
case IM_TIFFTAG_IMAGEWIDTH:
status = imTiffDecOrFetch( ioType, fd, fp, &(tifDir[i]),
(unsigned char**)&imTDI->t_width );
break;
case IM_TIFFTAG_IMAGELENGTH: /* This means height */
status = imTiffDecOrFetch( ioType, fd, fp, &(tifDir[i]),
(unsigned char**)&imTDI->t_height );
break;
case IM_TIFFTAG_COMPRESSION:
status = imTiffDecOrFetch( ioType, fd, fp, &(tifDir[i]),
(unsigned char**)&imTDI->t_compression );
break;
case IM_TIFFTAG_PHOTOMETRIC:
status = imTiffDecOrFetch( ioType, fd, fp, &(tifDir[i]),
(unsigned char**)&imTDI->t_photometric );
break;
case IM_TIFFTAG_IMAGEDESCRIPTION:
status = imTiffDecOrFetch( ioType, fd, fp, &(tifDir[i]),
&imTDI->t_imagedescr );
break;
case IM_TIFFTAG_ORIENTATION:
status = imTiffDecOrFetch( ioType, fd, fp, &(tifDir[i]),
(unsigned char**)&imTDI->t_orientation );
if ( imTDI->t_orientation != IM_ORIENTATION_TOPLEFT &&
imTDI->t_orientation != IM_ORIENTATION_BOTLEFT &&
imTDI->t_orientation != IM_ORIENTATION_LEFTTOP &&
imTDI->t_orientation != IM_ORIENTATION_LEFTBOT )
{
ImErrNo = IMEORIENTATION;
ImErrorFatal( ImQError( ), -1, ImErrNo );
}
break;
case IM_TIFFTAG_SAMPLESPERPIXEL:
status= imTiffDecOrFetch( ioType, fd, fp, &(tifDir[i]),
(unsigned char**)&imTDI->t_samplesperpixel );
break;
case IM_TIFFTAG_ROWSPERSTRIP:
status = imTiffDecOrFetch( ioType, fd, fp, &(tifDir[i]),
(unsigned char**)&imTDI->t_rowsperstrip );
break;
case IM_TIFFTAG_BITSPERSAMPLE:
imTDI->t_bitspersample.type = tifDir[i].tdir_type;
imTDI->t_bitspersample.cnt = tifDir[i].tdir_count;
status = imTiffDecOrFetch( ioType, fd, fp, &(tifDir[i]),
&imTDI->t_bitspersample.data );
/*
* The depth may be (8 8 8) for eight bits each
* channel. Just save one of the counts in the
* in the t_depth field for easier access.
*/
imTDI->t_depth=imTiffDataItem(&imTDI->t_bitspersample,0);
break;
case IM_TIFFTAG_STRIPBYTECOUNTS:
imTDI->t_stripbytecounts.type = tifDir[i].tdir_type;
imTDI->t_stripbytecounts.cnt = tifDir[i].tdir_count;
status = imTiffDecOrFetch( ioType, fd, fp, &(tifDir[i]),
&imTDI->t_stripbytecounts.data );
break;
case IM_TIFFTAG_STRIPOFFSETS:
imTDI->t_stripoffsets.type = tifDir[i].tdir_type;
imTDI->t_stripoffsets.cnt = tifDir[i].tdir_count;
status = imTiffDecOrFetch( ioType, fd, fp, &(tifDir[i]),
&imTDI->t_stripoffsets.data );
break;
case IM_TIFFTAG_COLORMAP:
imTDI->t_colormap.type = tifDir[i].tdir_type;
imTDI->t_colormap.cnt = tifDir[i].tdir_count;
status = imTiffDecOrFetch( ioType, fd, fp, &(tifDir[i]),
&imTDI->t_colormap.data );
break;
case IM_TIFFTAG_PLANARCONFIG:
status = imTiffDecOrFetch( ioType, fd, fp, &(tifDir[i]),
(unsigned char**)&imTDI->t_planarconfig );
break;
case IM_TIFFTAG_XPOSITION:
imTDI->t_xposition.type = tifDir[i].tdir_type;
imTDI->t_xposition.cnt = tifDir[i].tdir_count;
status = imTiffDecOrFetch( ioType, fd, fp, &(tifDir[i]),
&imTDI->t_xposition.data );
break;
case IM_TIFFTAG_YPOSITION:
imTDI->t_yposition.type = tifDir[i].tdir_type;
imTDI->t_yposition.cnt = tifDir[i].tdir_count;
status = imTiffDecOrFetch( ioType, fd, fp, &(tifDir[i]),
&imTDI->t_yposition.data );
break;
case IM_TIFFTAG_SOFTWARE:
status = imTiffDecOrFetch( ioType, fd, fp, &(tifDir[i]),
&imTDI->t_software );
break;
case IM_TIFFTAG_DATETIME:
status = imTiffDecOrFetch( ioType, fd, fp, &(tifDir[i]),
&imTDI->t_datetime );
break;
case IM_TIFFTAG_ARTIST:
status = imTiffDecOrFetch( ioType, fd, fp, &(tifDir[i]),
&imTDI->t_artist );
break;
case IM_TIFFTAG_HOSTCOMPUTER:
status = imTiffDecOrFetch( ioType, fd, fp, &(tifDir[i]),
&imTDI->t_host );
break;
case IM_TIFFTAG_WHITEPOINT:
status = imTiffDecOrFetch( ioType, fd, fp, &(tifDir[i]),
&imTDI->t_whitepoint );
break;
case IM_TIFFTAG_PRIMARYCHROMATICITIES:
status = imTiffDecOrFetch( ioType, fd, fp, &(tifDir[i]),
&imTDI->t_primarychrom );
break;
case IM_TIFFTAG_PREDICTOR:
status = imTiffDecOrFetch( ioType, fd, fp, &(tifDir[i]),
(unsigned char**)&imTDI->t_predictor );
break;
case IM_TIFFTAG_MATTEING:
status = imTiffDecOrFetch( ioType, fd, fp, &(tifDir[i]),
(unsigned char**)&imTDI->t_matteing );
break;
default:
ImErrNo = IMEFORMAT;
ImErrorWarning("Ignoring tiff dir tag", -1, ImErrNo );
imPrintTiffTag( tifDir[i].tdir_tag );
break;
}
if ( status == -1 )
return( -1 ); /* ImErrNo already set */
} /* End of parsing directory */
/*
* Check to be sure that values are reasonable
*/
if ( imTDI->t_predictor > 1 )
{
ImErrNo = IMEUNSUPPORTED;
ImErrorFatal( "LZW+Prediction not supported", -1, ImErrNo );
}
if ( imTDI->t_width < 1 )
{
ImErrNo = IMEWIDTH;
ImErrorFatal( ImQError( ), -1, ImErrNo );
}
if ( imTDI->t_height < 1 )
{
ImErrNo = IMEHEIGHT;
ImErrorFatal( ImQError( ), -1, ImErrNo );
}
if ( imTDI->t_rowsperstrip == 0 )
imTDI->t_rowsperstrip = imTDI->t_height;
if ( imTDI->t_depth == 0 )
imTDI->t_depth = 1;
if ( imTDI->t_samplesperpixel == 0 )
imTDI->t_samplesperpixel = 1;
if ( imTDI->t_compression == 0 )
imTDI->t_compression = IM_COMPRESSION_NONE;
if ( imTDI->t_orientation == 0 )
imTDI->t_orientation = IM_ORIENTATION_TOPLEFT;
if ( imTDI->t_compression != IM_COMPRESSION_NONE &&
imTDI->t_compression != IM_COMPRESSION_PACKBITS &&
imTDI->t_compression != IM_COMPRESSION_LZW )
{
ImErrNo = IMEUNSUPPORTED;
ImErrorFatal("TIFF compression scheme not supported", -1, ImErrNo );
}
/*
* If the bytecounts field is missing and there is more than one
* strip offset given, then give up, it is too hard to figure out.
* The bytecounts field is mandatory but someprograms don't write it
* anyway.
*/
if ( imTDI->t_stripbytecounts.data == NULL )
{
if ( imTDI->t_compression != IM_COMPRESSION_NONE )
{
ImErrNo = IMECONFLICT;
ImErrorFatal(
"TIFF required tag 'stripbytecounts' not present",
-1, ImErrNo );
}
if ( imTDI->t_stripoffsets.cnt > 1 )
{
ImErrNo = IMECONFLICT;
ImErrorFatal( ImQError( ), -1, ImErrNo );
}
ImErrorWarning(
"TIFF required tag 'stripbytecounts' tag not present, trying anyway",
-1, IMESYNTAX );
imTDI->t_stripbytecounts.cnt = 1;
imTDI->t_stripbytecounts.type = IMTIFFLONG;
imTDI->t_stripbytecounts.data = (unsigned char*) ((imTDI->t_width *
imTDI->t_height * imTDI->t_depth) / IMTIFFBITSPERBYTE);
}
free( tifDir );
return ( 0 );
}
#define imTiffFree() \
if(strip!=NULL) \
free(strip); \
if(ucstrip!=NULL) \
free(ucstrip);
/*
* FUNCTION
* imTiffRead1 - read 1-bit TIFF format
* imTiffRead4 - read 4-bit TIFF format
* imTiffRead8 - read 8-bit TIFF format
* imTiffRead16 - read 16-bit TIFF format (CLT longer than 256)
* imTiffRead24Sep - read 24-bit TIFF format separate planes
* imTiffRead24Cont - read 24-bit TIFF format contiguous planes
*
* DESCRIPTION
* Each of these routines deal with TIFF files.
* The input stream is a file or a pipe. We don't care.
*
* A new VFB is allocated. The image is read in
* and converted into the VFB.
*
* The 1 and 4 bit reads should be changed when we implement 1 and 4
* bit vfbs.
*/
static int /* Returns status */
#ifdef __STDC__
imTiffRead1( int ioType, int fd, FILE *fp, TagTable *flags, TagTable *tagTable, imTiffDirInfo *imTDI, ImVfb **pVfb )
#else
imTiffRead1( ioType, fd, fp, flags, tagTable, imTDI, pVfb )
int ioType; /* I/O flags */
int fd; /* Input file descriptor */
FILE *fp; /* Input file pointer */
TagTable *flags; /* Format flags */
TagTable *tagTable; /* Tag table to add to */
imTiffDirInfo *imTDI; /* Directory information */
ImVfb **pVfb; /* VFB to fill and return */
#endif
{
ImVfbPtr pptr; /* Pixel pointer */
ImVfb *vfb; /* A more convenient pointer */
unsigned char *strip; /* Storage for pixel indices */
unsigned char *ucstrip=NULL; /* If encoded, use this buffer */
unsigned char *stripptr; /* Walk thru the pixels */
int size; /* The number of bytes of index */
int i,j; /* Loop counters */
int where; /* Where to start reading */
int howMany; /* How many to read */
int decodedsize; /* How many bytes when decoded */
int k; /* Counter */
int rows; /* Number of scanlines this time*/
int rowsread=0; /* Number of scanlines readsofar*/
int shift; /* Number of bits to shift */
int val; /* Pixel value, either 0 or 255 */
/*
* Allocate a VFB of the required size.
*/
if ( (*pVfb = ImVfbAlloc( imTDI->t_width, imTDI->t_height,
IMVFBMONO )) == IMVFBNULL )
{
ImErrorFatal( ImQError( ), -1, ImErrNo );
}
vfb = *pVfb;
pptr = ImVfbQFirst( vfb );
/*
* Allocate space for the pixel values
* Sometimes things are bigger when compresses, so we make it 2x
*/
size = (imTDI->t_width * imTDI->t_rowsperstrip) / IMTIFFBITSPERBYTE;
ImMalloc( strip, unsigned char *, size*2 );
/*
* If compressed, we need a extra buffer
*/
if ( imTDI->t_compression != IM_COMPRESSION_NONE )
ImMalloc( ucstrip, unsigned char *, size );
rows = imTDI->t_rowsperstrip;
/*
* Read in the strips and put them in the vfb one at a time
*/
for( i=0; i < imTDI->t_stripoffsets.cnt; i++ )
{
/*
* We have to know how many pixels are left to read, so we
* keep track of the number of rows read so far. We keep
* these numbers in uncompressed bytes even if reading a
* compressed file.
*/
if ( rows > imTDI->t_height - rowsread )
rows = imTDI->t_height % imTDI->t_rowsperstrip;
decodedsize = rows * ((imTDI->t_samplesperpixel *
imTDI->t_width + (IMTIFFBITSPERBYTE - 1)) /
IMTIFFBITSPERBYTE);
where = imTiffDataItem( &imTDI->t_stripoffsets, i );
howMany = imTiffDataItem( &imTDI->t_stripbytecounts, i );
ImSeek( ioType, fd, fp, where, 0 );
if ( ImBinRead( ioType, fd, fp, strip, UCHAR, 1, howMany )== -1)
{
ImReturnBinError( );
}
rowsread += rows;
stripptr = strip;
/*
* If the rows are compressed, uncompress them
*/
if ( imTDI->t_compression == IM_COMPRESSION_LZW )
{
if (ImLzwPreDecode( strip, howMany ) == -1)
{
imTiffFree();
ImVfbFree(vfb);
return( -1 );
}
if (ImLzwDecode( strip, ucstrip, decodedsize ) == -1)
{
imTiffFree();
ImVfbFree(vfb);
return( -1 );
}
ImLzwPostDecode();
stripptr = ucstrip;
}
if ( imTDI->t_compression == IM_COMPRESSION_PACKBITS )
{
UnpackBits( strip, ucstrip, (unsigned int*)&howMany );
decodedsize = howMany;
stripptr = ucstrip;
}
for ( k = 0; k < rows; k++ )
{
/*
* Added to VFB. Watch for the last byte of each
* row. If the image width is not a multiple of 8,
* the last byte will not be filled and we'll need
* to skip the extra bits.
*/
for ( j = 0; j < imTDI->t_width; j++ )
{
shift=IMTIFFBITSPERBYTE-(j % IMTIFFBITSPERBYTE)-1;
val= (*stripptr >> shift) & 0x01;
if (shift == 0)
stripptr++;
ImVfbSMono( vfb, pptr, val );
ImVfbSInc( vfb, pptr );
}
if ( shift != 0 )
stripptr++;
}
}
imTiffFree();
return(1);
}
static int /* Returns status */
#ifdef __STDC__
imTiffRead4( int ioType, int fd, FILE *fp, TagTable *flags, TagTable *tagTable, imTiffDirInfo *imTDI, ImVfb **pVfb )
#else
imTiffRead4( ioType, fd, fp, flags, tagTable, imTDI, pVfb )
int ioType; /* I/O flags */
int fd; /* Input file descriptor */
FILE *fp; /* Input file pointer */
TagTable *flags; /* Format flags */
TagTable *tagTable; /* Tag table to add to */
imTiffDirInfo *imTDI; /* Directory information */
ImVfb **pVfb; /* VFB to fill and return */
#endif
{
ImVfbPtr pptr; /* Pixel pointer */
ImVfb *vfb; /* A more convenient pointer */
unsigned char *strip; /* Storage for pixel indices */
unsigned char *ucstrip=NULL; /* If encoded, use this buffer */
unsigned char *stripptr; /* Walk thru the pixels */
int size; /* The number of bytes of index */
int i,j; /* Loop counters */
int where; /* Where to start reading */
int howMany; /* How many to read */
int decodedsize; /* How many bytes when decoded */
int rows; /* Number of scanlines this time*/
int rowsread=0; /* Number of scanlines readsofar*/
int shift; /* Number of bits to shift */
int val; /* Pixel value, either 0 or 255 */
/*
* Allocate a VFB of the required size.
*/
if ( (*pVfb = ImVfbAlloc( imTDI->t_width, imTDI->t_height,
IMVFBINDEX8 )) == IMVFBNULL )
{
ImErrorFatal( ImQError( ), -1, ImErrNo );
}
vfb = *pVfb;
pptr = ImVfbQFirst( vfb );
/*
* Allocate space for the pixel values
* Sometimes things are bigger when compresses, so we make it 2x
*/
size = (imTDI->t_width * imTDI->t_rowsperstrip) / IMTIFFNIBBLESPERBYTE;
ImMalloc( strip, unsigned char *, size*2 );
/*
* If compressed, we need a extra buffer
*/
if ( imTDI->t_compression != IM_COMPRESSION_NONE )
ImMalloc( ucstrip, unsigned char *, size );
rows = imTDI->t_rowsperstrip;
/*
* Read in the strips and put them in the vfb one at a time
*/
for( i=0; i < imTDI->t_stripoffsets.cnt; i++ )
{
/*
* We have to know how many pixels are left to read, so we
* keep track of the number of rows read so far. We keep
* these numbers in uncompressed bytes even if reading a
* compressed file.
*/
if ( rows > imTDI->t_height - rowsread )
rows = imTDI->t_height % imTDI->t_rowsperstrip;
decodedsize = (rows * imTDI->t_samplesperpixel * imTDI->t_width
* imTDI->t_depth) / IMTIFFBITSPERBYTE;
where = imTiffDataItem( &imTDI->t_stripoffsets, i );
howMany = imTiffDataItem( &imTDI->t_stripbytecounts, i );
ImSeek( ioType, fd, fp, where, 0 );
if ( ImBinRead( ioType, fd, fp, strip, UCHAR, 1, howMany )== -1)
{
ImReturnBinError( );
}
rowsread += rows;
stripptr = strip;
/*
* If the rows are compressed, uncompress them
*/
if ( imTDI->t_compression == IM_COMPRESSION_LZW )
{
if (ImLzwPreDecode( strip, howMany ) == -1)
{
imTiffFree();
ImVfbFree(vfb);
return( -1 );
}
if (ImLzwDecode( strip, ucstrip, decodedsize ) == -1)
{
imTiffFree();
ImVfbFree(vfb);
return( -1 );
}
ImLzwPostDecode();
stripptr = ucstrip;
}
if ( imTDI->t_compression == IM_COMPRESSION_PACKBITS )
{
UnpackBits( strip, ucstrip, (unsigned int*)&howMany );
decodedsize = howMany;
stripptr = ucstrip;
}
/*
* If there is no colormap, then put them in a gray vfb
*/
for( j=0; j < decodedsize*IMTIFFNIBBLESPERBYTE; j++ )
{
if ( j % IMTIFFNIBBLESPERBYTE == 0 )
val=((*stripptr >> 4) & 0x0f);
else
{
val=(*stripptr & 0x0f);
stripptr++;
}
ImVfbSIndex8( vfb, pptr, val * IMTIFFNIBBLEMULT );
ImVfbSInc( vfb, pptr );
}
}
imTiffFree();
return(1);
}
static int /* Returns status */
#ifdef __STDC__
imTiffRead8( int ioType, int fd, FILE *fp, TagTable *flags, TagTable *tagTable, imTiffDirInfo *imTDI, ImVfb **pVfb )
#else
imTiffRead8( ioType, fd, fp, flags, tagTable, imTDI, pVfb )
int ioType; /* I/O flags */
int fd; /* Input file descriptor */
FILE *fp; /* Input file pointer */
TagTable *flags; /* Format flags */
TagTable *tagTable; /* Tag table to add to */
imTiffDirInfo *imTDI; /* Directory information */
ImVfb **pVfb; /* VFB to fill and return */
#endif
{
ImVfbPtr pptr; /* Pixel pointer */
ImVfb *vfb; /* A more convenient pointer */
unsigned char *strip; /* Storage for pixel indices */
unsigned char *ucstrip=NULL; /* If encoded, use this buffer */
unsigned char *stripptr; /* Walk thru the pixels */
int size; /* The number of bytes of index */
int i,j; /* Loop counters */
int where; /* Where to start reading */
int howMany; /* How many to read */
int decodedsize; /* How many bytes when decoded */
int rows; /* Number of scanlines this time*/
int rowsread=0; /* Number of scanlines readsofar*/
/*
* Allocate a VFB of the required size.
*/
if ( (*pVfb = ImVfbAlloc( imTDI->t_width, imTDI->t_height,
IMVFBINDEX8 )) == IMVFBNULL )
{
ImErrorFatal( ImQError( ), -1, ImErrNo );
}
vfb = *pVfb;
pptr = ImVfbQFirst( vfb );
/*
* Allocate space for the pixel indices
* Sometimes things are bigger when compresses, so we make it 2x
*/
size = imTDI->t_width * imTDI->t_rowsperstrip;
ImMalloc( strip, unsigned char *, size*2 );
/*
* If compressed, we need a extra buffer
*/
if ( imTDI->t_compression != IM_COMPRESSION_NONE )
ImMalloc( ucstrip, unsigned char *, size );
rows = imTDI->t_rowsperstrip;
/*
* Read in the strips and put them in the vfb one at a time
*/
for( i=0; i < imTDI->t_stripoffsets.cnt; i++ )
{
/*
* We have to know how many pixels are left to read, so we
* keep track of the number of rows read so far. We keep
* these numbers in uncompressed bytes even if reading a
* compressed file.
*/
if ( rows > imTDI->t_height - rowsread )
rows = imTDI->t_height % imTDI->t_rowsperstrip;
decodedsize = (rows * imTDI->t_samplesperpixel * imTDI->t_width
* imTDI->t_depth) / IMTIFFBITSPERBYTE;
where = imTiffDataItem( &imTDI->t_stripoffsets, i );
howMany = imTiffDataItem( &imTDI->t_stripbytecounts, i );
ImSeek( ioType, fd, fp, where, 0 );
if ( ImBinRead( ioType, fd, fp, strip, UCHAR, 1, howMany )== -1)
{
ImReturnBinError( );
}
rowsread += rows;
stripptr = strip;
/*
* If the rows are compressed, uncompress them
*/
if ( imTDI->t_compression == IM_COMPRESSION_LZW )
{
if (ImLzwPreDecode( strip, howMany ) == -1)
{
imTiffFree();
ImVfbFree(vfb);
return( -1 );
}
if (ImLzwDecode( strip, ucstrip, decodedsize ) == -1)
{
imTiffFree();
ImVfbFree(vfb);
return( -1 );
}
ImLzwPostDecode();
stripptr = ucstrip;
}
if ( imTDI->t_compression == IM_COMPRESSION_PACKBITS )
{
UnpackBits( strip, ucstrip, (unsigned int*)&howMany );
decodedsize = howMany;
stripptr = ucstrip;
}
for( j=0; j < decodedsize; j++ )
{
ImVfbSIndex8( vfb, pptr, *stripptr++ );
ImVfbSInc( vfb, pptr );
}
}
imTiffFree();
return(1);
}
static int /* Returns status */
#ifdef __STDC__
imTiffRead16( int ioType, int fd, FILE *fp, TagTable *flags, TagTable *tagTable, imTiffDirInfo *imTDI, ImVfb **pVfb )
#else
imTiffRead16( ioType, fd, fp, flags, tagTable, imTDI, pVfb )
int ioType; /* I/O flags */
int fd; /* Input file descriptor */
FILE *fp; /* Input file pointer */
TagTable *flags; /* Format flags */
TagTable *tagTable; /* Tag table to add to */
imTiffDirInfo *imTDI; /* Directory information */
ImVfb **pVfb; /* VFB to fill and return */
#endif
{
ImVfbPtr pptr; /* Pixel pointer */
ImVfb *vfb; /* A more convenient pointer */
unsigned char *strip; /* Storage for pixel indices */
unsigned char *ucstrip=NULL; /* If encoded, use this buffer */
unsigned char *stripptr; /* Walk thru the pixels */
unsigned char *rbp; /* Walk thru an array of uchars */
int size; /* The number of bytes of index */
int i,j; /* Loop counters */
unsigned int tmp; /* Temp integer holder */
int where; /* Where to start reading */
int howMany; /* How many to read */
int decodedsize; /* How many bytes when decoded */
int rows; /* Number of scanlines this time*/
int rowsread=0; /* Number of scanlines readsofar*/
/*
* Allocate a VFB of the required size.
*/
if ( (*pVfb = ImVfbAlloc( imTDI->t_width, imTDI->t_height,
IMVFBINDEX16 )) == IMVFBNULL )
{
ImErrorFatal( ImQError( ), -1, ImErrNo );
}
vfb = *pVfb;
pptr = ImVfbQFirst( vfb );
/*
* Allocate space for the pixel indices
* Sometimes things are bigger when compresses, so we make it 2x
*/
size = imTDI->t_width * imTDI->t_rowsperstrip * imTDI->t_depth/8;
ImMalloc( strip, unsigned char *, size*2 );
/*
* If compressed, we need a extra buffer
*/
if ( imTDI->t_compression != IM_COMPRESSION_NONE )
ImMalloc( ucstrip, unsigned char *, size );
rows = imTDI->t_rowsperstrip;
/*
* Read in the strips and put them in the vfb one at a time
*/
for( i=0; i < imTDI->t_stripoffsets.cnt; i++ )
{
/*
* We have to know how many pixels are left to read, so we
* keep track of the number of rows read so far. We keep
* these numbers in uncompressed bytes even if reading a
* compressed file.
*/
if ( rows > imTDI->t_height - rowsread )
rows = imTDI->t_height % imTDI->t_rowsperstrip;
decodedsize = (rows * imTDI->t_samplesperpixel * imTDI->t_width
* imTDI->t_depth) / IMTIFFBITSPERBYTE;
where = imTiffDataItem( &imTDI->t_stripoffsets, i );
howMany = imTiffDataItem( &imTDI->t_stripbytecounts, i );
ImSeek( ioType, fd, fp, where, 0 );
if ( ImBinRead( ioType, fd, fp, strip, UCHAR, 1, howMany )== -1)
{
ImReturnBinError( );
}
rowsread += rows;
stripptr = strip;
/*
* If the rows are compressed, uncompress them
*/
if ( imTDI->t_compression == IM_COMPRESSION_LZW )
{
if (ImLzwPreDecode( strip, howMany ) == -1)
{
imTiffFree();
ImVfbFree(vfb);
return( -1 );
}
if (ImLzwDecode( strip, ucstrip, decodedsize ) == -1)
{
imTiffFree();
ImVfbFree(vfb);
return( -1 );
}
ImLzwPostDecode();
stripptr = ucstrip;
}
if ( imTDI->t_compression == IM_COMPRESSION_PACKBITS )
{
UnpackBits( strip, ucstrip, (unsigned int*)&howMany );
decodedsize = howMany;
stripptr = ucstrip;
}
/*
* Put the values into a vfb.
*/
if ( imTiffHeader.tiff_magic == IMTIFFBIGENDIANMAGIC )
{
/* MBF byte order. */
rbp = stripptr;
for( j=0; j < decodedsize / 2; j++ )
{
tmp = ((*rbp) << 8) | (*(rbp+1));
rbp += 2;
ImVfbSIndex16( vfb, pptr, tmp );
ImVfbSInc( vfb, pptr );
}
}
else
{
/* LBF byte order. */
rbp = stripptr;
for( j=0; j < decodedsize / 2; j++ )
{
tmp = ((*(rbp+1)) << 8) | (*rbp);
rbp += 2;
ImVfbSIndex16( vfb, pptr, tmp );
ImVfbSInc( vfb, pptr );
}
}
}
imTiffFree();
return(1);
}
static int /* Returns status */
#ifdef __STDC__
imTiffRead24Cont( int ioType, int fd, FILE *fp, TagTable *flags, TagTable *tagTable, imTiffDirInfo *imTDI, ImVfb **pVfb )
#else
imTiffRead24Cont( ioType, fd, fp, flags, tagTable, imTDI, pVfb )
int ioType; /* I/O flags */
int fd; /* Input file descriptor */
FILE *fp; /* Input file pointer */
TagTable *flags; /* Format flags */
TagTable *tagTable; /* Tag table to add to */
imTiffDirInfo *imTDI; /* Directory information */
ImVfb **pVfb; /* VFB to fill and return */
#endif
{
ImVfbPtr pptr; /* Pixel pointer */
ImVfb *vfb; /* A more convenient pointer */
unsigned char *strip; /* Storage for pixel indices */
unsigned char *ucstrip=NULL; /* If encoded, use this buffer */
unsigned char *stripptr; /* Walk thru the pixels */
int size; /* The number of bytes of index */
int i,j; /* Loop counters */
int where; /* Where to start reading */
int howMany; /* How many to read */
int decodedsize; /* How many bytes when decoded */
int rows; /* Number of scanlines this time*/
int alpha; /* Is there an alpha channel */
int rowsread=0; /* Number of scanlines readsofar*/
/*
* Allocate a VFB of the required size.
* If there is an alpha channel make room for it.
* The location of the alpha channel is undocumented so we are assuming
* that it is mixed in with the color channels.
*/
alpha = imTDI->t_matteing;
if ( alpha )
{
if ( (*pVfb = ImVfbAlloc( imTDI->t_width, imTDI->t_height,
IMVFBRGB|IMVFBALPHA )) == IMVFBNULL )
{
ImErrorFatal( ImQError( ), -1, ImErrNo );
}
size = imTDI->t_width * imTDI->t_rowsperstrip * 4;
}
else
{
if ( (*pVfb = ImVfbAlloc( imTDI->t_width, imTDI->t_height,
IMVFBRGB )) == IMVFBNULL )
{
ImErrorFatal( ImQError( ), -1, ImErrNo );
}
size = imTDI->t_width * imTDI->t_rowsperstrip * 3;
}
vfb = *pVfb;
pptr = ImVfbQFirst( vfb );
/*
* Allocate space for the pixel values
* Sometimes things are bigger when compresses, so we make it 2x
*/
ImMalloc( strip, unsigned char *, size*2 );
/*
* If compressed, we need a extra buffer
*/
if ( imTDI->t_compression != IM_COMPRESSION_NONE )
ImMalloc( ucstrip, unsigned char *, size );
rows = imTDI->t_rowsperstrip;
/*
* Read in the strips and put them in the vfb one at a time
*/
for( i=0; i < imTDI->t_stripoffsets.cnt; i++ )
{
/*
* We have to know how many pixels are left to read, so we
* keep track of the number of rows read so far. We keep
* these numbers in uncompressed bytes even if reading a
* compressed file.
*/
if ( rows > imTDI->t_height - rowsread )
rows = imTDI->t_height % imTDI->t_rowsperstrip;
decodedsize = (rows * imTDI->t_samplesperpixel * imTDI->t_width
* imTDI->t_depth) / IMTIFFBITSPERBYTE;
where = imTiffDataItem( &imTDI->t_stripoffsets, i );
howMany = imTiffDataItem( &imTDI->t_stripbytecounts, i );
ImSeek( ioType, fd, fp, where, 0 );
if ( ImBinRead( ioType, fd, fp, strip, UCHAR, 1, howMany )== -1)
{
ImReturnBinError( );
}
rowsread += rows;
stripptr = strip;
/*
* If the rows are compressed, uncompress them
*/
if ( imTDI->t_compression == IM_COMPRESSION_LZW )
{
if (ImLzwPreDecode( strip, howMany ) == -1)
{
imTiffFree();
ImVfbFree(vfb);
return( -1 );
}
if (ImLzwDecode( strip, ucstrip, decodedsize ) == -1)
{
imTiffFree();
ImVfbFree(vfb);
return( -1 );
}
ImLzwPostDecode();
stripptr = ucstrip;
}
if ( imTDI->t_compression == IM_COMPRESSION_PACKBITS )
{
UnpackBits( strip, ucstrip, (unsigned int*)&howMany );
decodedsize = howMany;
stripptr = ucstrip;
}
/*
* If there is no colormap, then put them in a gray vfb
*/
if ( alpha )
for( j=0; j < decodedsize/4; j++ )
{
ImVfbSRed( vfb, pptr, *stripptr++ );
ImVfbSGreen( vfb, pptr, *stripptr++ );
ImVfbSBlue( vfb, pptr, *stripptr++ );
ImVfbSAlpha( vfb, pptr, *stripptr++ );
ImVfbSInc( vfb, pptr );
}
else
for( j=0; j < decodedsize/3; j++ )
{
ImVfbSRed( vfb, pptr, *stripptr++ );
ImVfbSGreen( vfb, pptr, *stripptr++ );
ImVfbSBlue( vfb, pptr, *stripptr++ );
ImVfbSInc( vfb, pptr );
}
}
imTiffFree();
return(1);
}
static int /* Returns status */
#ifdef __STDC__
imTiffRead24Sep( int ioType, int fd, FILE *fp, TagTable *flags, TagTable *tagTable, imTiffDirInfo *imTDI, ImVfb **pVfb )
#else
imTiffRead24Sep( ioType, fd, fp, flags, tagTable, imTDI, pVfb )
int ioType; /* I/O flags */
int fd; /* Input file descriptor */
FILE *fp; /* Input file pointer */
TagTable *flags; /* Format flags */
TagTable *tagTable; /* Tag table to add to */
imTiffDirInfo *imTDI; /* Directory information */
ImVfb **pVfb; /* VFB to fill and return */
#endif
{
ImVfbPtr pptr; /* Pixel pointer */
ImVfb *vfb; /* A more convenient pointer */
unsigned char *strip; /* Storage for pixels */
unsigned char *ucstrip=NULL; /* If encoded, use this buffer */
unsigned char *stripptr; /* Walk thru the pixels red */
int where; /* Where to start reading */
int howMany; /* How many reds to read */
int i,j; /* Loop counters */
int decodedsize; /* How many bytes when decoded */
int alpha=0; /* Is there an alpha channel */
int samples; /* Samples per pixel */
int rows; /* Number of scanlines this time*/
int size; /* The number of bytes of index */
int rowsread; /* Number of scanlines readsofar*/
int color; /* Loop counter for colors */
int stripspercolor;/* Number of strips/component */
/*
* Tiff files with separate image planes store all of the red rows
* followed by all of the green rows and then all of the blue and
* alpha rows (I think).
*/
alpha = imTDI->t_matteing;
samples = imTDI->t_samplesperpixel;
rows = imTDI->t_rowsperstrip;
size = imTDI->t_width * rows;
stripspercolor = imTDI->t_stripoffsets.cnt/samples;
/*
* Allocate a VFB of the required size.
* If there is an alpha channel make room for it.
* The location of the alpha channel is undocumented so we are assume
* that it follows the blue plane
*/
if ( alpha )
{
if ( (*pVfb = ImVfbAlloc( imTDI->t_width, imTDI->t_height,
IMVFBRGB|IMVFBALPHA )) == IMVFBNULL )
{
ImErrorFatal( ImQError( ), -1, ImErrNo );
}
}
else
{
if ( (*pVfb = ImVfbAlloc( imTDI->t_width, imTDI->t_height,
IMVFBRGB )) == IMVFBNULL )
{
ImErrorFatal( ImQError( ), -1, ImErrNo );
}
}
vfb = *pVfb;
/*
* Allocate space for one component of one row of pixels
* Sometimes things are bigger when compresses, so we make it 2x
*/
ImMalloc( strip, unsigned char *, size*2 );
/*
* If compressed, we need a extra buffer
*/
if ( imTDI->t_compression != IM_COMPRESSION_NONE )
ImMalloc( ucstrip, unsigned char *, size );
/*
* Cycle through red, green, blue, alpha(?) and for each one
* read in all of the scanlines (rows), decode them (?), and
* put them into a vfb.
*/
for( color=0; color<samples; color++ )
{
pptr = ImVfbQFirst( vfb );
rowsread = 0;
for( i=0; i < stripspercolor; i++ )
{
/*
* We have to know how many pixels are left to read,
* so we keep track of the number of rows read so far.
* We keep these numbers in uncompressed bytes even
* if reading a compressed file.
*/
if ( rows > imTDI->t_height - rowsread )
decodedsize = imTDI->t_width *
(imTDI->t_height % imTDI->t_rowsperstrip);
else
decodedsize = imTDI->t_width * rows;
/*
* Get the stripoffset and stripbytecount from the file
*/
where = imTiffDataItem( &imTDI->t_stripoffsets,
(stripspercolor * color) + i );
howMany = imTiffDataItem( &imTDI->t_stripbytecounts,
(stripspercolor * color) + i );
ImSeek( ioType, fd, fp, where, 0 );
if ( ImBinRead(ioType, fd, fp, strip, UCHAR, 1,
howMany) == -1)
{
ImReturnBinError( );
}
/*
* Keep track of the number of rows because the last
* row may not contain as many scanlines as the others
*/
rowsread += (decodedsize/imTDI->t_width);
stripptr = strip;
/*
* If the rows are compressed, uncompress them
*/
if ( imTDI->t_compression == IM_COMPRESSION_LZW )
{
if (ImLzwPreDecode( strip, howMany ) == -1)
{
imTiffFree();
return( -1 );
}
if (ImLzwDecode(strip,ucstrip,decodedsize)== -1)
{
imTiffFree();
return( -1 );
}
ImLzwPostDecode();
stripptr = ucstrip;
}
if ( imTDI->t_compression == IM_COMPRESSION_PACKBITS )
{
UnpackBits( strip, ucstrip, (unsigned int*)&howMany );
decodedsize = howMany;
stripptr = ucstrip;
}
/*
* Put one component of one row in a vfb
*/
switch ( color )
{
case 0:
for( j=0; j < decodedsize; j++ )
{
ImVfbSRed( vfb, pptr, *stripptr++ );
ImVfbSInc( vfb, pptr );
}
break;
case 1:
for( j=0; j < decodedsize; j++ )
{
ImVfbSGreen( vfb, pptr, *stripptr++ );
ImVfbSInc( vfb, pptr );
}
break;
case 2:
for( j=0; j < decodedsize; j++ )
{
ImVfbSBlue( vfb, pptr, *stripptr++ );
ImVfbSInc( vfb, pptr );
}
break;
case 3:
for( j=0; j < decodedsize; j++ )
{
ImVfbSAlpha( vfb, pptr, *stripptr++ );
ImVfbSInc( vfb, pptr );
}
break;
}
} /* End foreach row */
} /* End foreach color */
imTiffFree();
return(1);
}
/*
* FUNCTION
* imTiffGetClt - Transfer a colormap into a CLT
*
* DESCRIPTION
* Elements in a TIFF colormap may be bytes or shorts or whatever.
* So we use memcpys to get them out of the colormap and into the CLT.
*/
static int
#ifdef __STDC__
imTiffGetClt( imTiffDirInfo *imTDI, ImClt **pClt )
#else
imTiffGetClt( imTDI, pClt )
imTiffDirInfo *imTDI; /* Directory information */
ImClt **pClt; /* VFB to fill and return */
#endif
{
ImClt *clt; /* Color pointer */
ImCltPtr cptr; /* Color pointer */
int i; /* Loop counter */
unsigned int redp; /* Red CLT range pointer */
unsigned int grnp; /* Green CLT range pointer */
unsigned int blup; /* Blue CLT range pointer */
unsigned int n; /* Number of colors */
unsigned char red; /* Temporary storage of red val */
unsigned char grn; /* Temporary storage of grn val */
unsigned char blu; /* Temporary storage of blu val */
unsigned char *cd; /* Treat array as chars */
unsigned short *sd; /* Treat array as shorts */
char message[100]; /* ImInfo message */
/*
* If there is a colormap in the file, put it in a CLT
*/
*pClt = IMCLTNULL;
if ( imTDI->t_colormap.data != NULL )
{
clt = *pClt = ImCltAlloc( imTDI->t_colormap.cnt/3 );
cptr = ImCltQFirst( clt );
n = imTDI->t_colormap.cnt / 3;
redp = 0;
grnp = n;
blup = n+n;
/*
* Output -verbose message
*/
sprintf( message, "%d Entries", n );
ImInfo( "Color Table", message );
switch ( imTDI->t_colormap.type )
{
case IMTIFFBYTE:
case IMTIFFASCII:
cd = (unsigned char *)imTDI->t_colormap.data;
for ( i = 0; i < n; i++ )
{
red = cd[redp++];
grn = cd[grnp++];
blu = cd[blup++];
ImCltSRed (cptr, red);
ImCltSGreen (cptr, grn);
ImCltSBlue (cptr, blu);
ImCltSInc( clt, cptr );
}
break;
case IMTIFFSHORT:
sd = (unsigned short *)imTDI->t_colormap.data;
for ( i = 0; i < n; i++ )
{
/*
* Since we can only store 8-bit R, G and
* B values, we have to use some method
* of removing 8-bits of data from the 16-bit
* short. This usually involves a
* scaling function to reduce the
* range of colors. For TIFF colortable
* entries, all we need to do is use
* the upper 8-bits and ignore the lower
* 8-bits.
*/
red = (unsigned char) (sd[redp++] );
grn = (unsigned char) (sd[grnp++] );
blu = (unsigned char) (sd[blup++] );
ImCltSRed (cptr, red);
ImCltSGreen (cptr, grn);
ImCltSBlue (cptr, blu);
ImCltSInc( clt, cptr );
}
break;
}
}
else
ImInfo( "Color Table", "none" );
if ( imTDI->t_colormap.data != NULL )
free( imTDI->t_colormap.data );
return( 0 );
}
/*
* FUNCTION
* imTiffWrite - Write a TIFF format file or stream
*
* DESCRIPTION
* Each of these routines deal with TIFF files.
*/
static int /* Returns # of tags written */
#ifdef __STDC__
imTiffWrite( ImFileFormatWriteMap *pMap, int ioType, int fd, FILE *fp, TagTable *flagsTable, TagTable *tagTable )
#else
imTiffWrite( pMap, ioType, fd, fp, flagsTable, tagTable )
ImFileFormatWriteMap *pMap; /* Write map entry to adhear to */
int ioType; /* I/O flags */
int fd; /* Output file descriptor */
FILE *fp; /* Output file pointer */
TagTable *flagsTable; /* Format flags */
TagTable *tagTable; /* Tag list to add to */
#endif
{
ImClt *clt; /* CLT pointer */
ImVfb *vfb; /* VFB pointer */
char *s; /* Tag name string */
int nTag = 0; /* # of tags written */
int n; /* # of tag table entries */
int i; /* Counter */
int flags; /* Write flags */
TagEntry *tagEntry; /* Tag table entry holder */
char message[100]; /* ImInfo message */
/*
* All administrative stuff (tags, reference counts, file offsets)
* are in MBF byte order.
*/
BinByteOrder( BINMBF );
BinFloatFormat( BINIEEE );
ImInfo( "Version", "42" );
ImInfo( "Byte Order", "Most Significant Byte First" );
/*
* Write out the file header, initialize the byte order and check
* the magic number, check the version number.
*/
memset( (void *)&imTiffHeader, 0x00, sizeof( imTiffHeader ) );
imTiffHeader.tiff_magic = IMTIFFBIGENDIANMAGIC;
imTiffHeader.tiff_version = IMTIFFVERSION;
imTiffHeader.tiff_diroff = 0; /* Fill this in later */
if ( ImBinWriteStruct( ioType, fd, fp, &imTiffHeader,
imTiffHeaderFields ) == -1 )
{
ImReturnBinError( );
}
n = TagTableQNEntry( tagTable, "image vfb" );
for ( i = 0; i < n; i++ )
{
sprintf( message, "%d of %d\n", (i+1), n );
ImInfo( "Image", message );
ImInfo( "Description", "none" );
tagEntry = TagTableQDirect( tagTable, "image vfb", i );
s = TagEntryQTag( tagEntry );
TagEntryQValue( tagEntry, &vfb );
if ( imTiffVfbWrite( ioType, fd, fp, flagsTable, vfb )== -1)
return ( -1 ); /* Error already posted */
nTag++;
}
/*
* Write out a zero into the next-dir-offset location indicating
* that there are no more directories
*/
n = 0;
if (ImBinWrite( ioType, fd, fp, &n, UINT, 4, 1 ) == -1)
{
ImReturnBinError( );
}
return( 0 );
}
/*
* FUNCTION
* imTiffVfbWrite - write VFB to file
*
* DESCRIPTION
* Write out Clt, Vfb, and then stripbyte counts, and
* stripoffsets. Then write out the directory afterwards.
* Seek back and fill in the directory offset.
* This routine may be called multiple times for
* multiple vfb/clt sets.
*/
static int /* Returns # of tags written */
#ifdef __STDC__
imTiffVfbWrite( int ioType, int fd, FILE *fp, TagTable *flagsTable, ImVfb *vfb )
#else
imTiffVfbWrite( ioType, fd, fp, flagsTable, vfb )
int ioType; /* I/O flags */
int fd; /* Output file descriptor */
FILE *fp; /* Output file pointer */
TagTable *flagsTable; /* Format flags */
ImVfb *vfb; /* VFB to write out */
#endif
{
ImClt *clt; /* VFB's CLT */
ImCltPtr pColor; /* VFB's CLT */
ImVfbPtr pptr; /* VFB's pixel ptr */
unsigned short sh; /* For writing out a temp const */
unsigned short so[2]; /* Temp storage for writing */
int i,j; /* Loop counters */
int n; /* Number of colors in colormap */
int junk; /* A dummy value to write out */
int fields; /* VFB header fields */
int sx,x,y,d; /* Convenient dimension access */
int pixcnt; /* The number of bytes written */
int compress; /* Do lzw compression ? */
int cnt; /* Byte count after compression */
int diroffsetposition; /* Offset in file */
unsigned int *stripbytecountsptr; /* Walk thru byte counts */
unsigned int *stripbytecounts; /* Byte count array */
unsigned int *stripoffsetsptr; /* Byte count after compression */
unsigned int *stripoffsets; /* Byte offsets to pixel info */
int newdiroffset; /* The offset to the new direc */
int offset; /* Used to calc word boundaries */
int shift; /* Number of bits to shift */
int size; /* Number of bytes in offset fld*/
int status; /* Returned from binwrite */
unsigned char *buffer=NULL; /* Pixel buffer */
unsigned char *pbuffer=NULL; /* Pack bits pixel buffer */
unsigned short *cbuffer=NULL; /* Colormap buffer */
unsigned char *rbp; /* Walk thru the buffer as bytes*/
unsigned char bw; /* A value, either 255 or 0 */
unsigned int *rip; /* Walk thru the buffer as ints */
char errstr[256]; /* For printing out error stings*/
/*
int xoffset;
int yoffset;
*/
double xoffset;
double yoffset;
unsigned int tmp; /* Integer holder */
int interRequest; /* Interleave request */
int compRequest; /* Compression request */
int cltRequest; /* CLT request */
int alphaRequest; /* Alpha plane request */
TagEntry *tagEntry; /* Flags table entry holder */
char message[100]; /* ImInfo message */
/*
* Get the requests from the flags table.
*/
interRequest = IMINTERPLANE;
compRequest = IMCOMPRLE;
cltRequest = IMCLTYES;
alphaRequest = IMALPHAYES;
if ( flagsTable != TAGTABLENULL )
{
tagEntry = TagTableQDirect( flagsTable, "image interleave request", 0 );
if ( tagEntry != TAGENTRYNULL )
TagEntryQValue( tagEntry, &interRequest );
/* interRequest is guaranteed to be one we can support. */
tagEntry = TagTableQDirect( flagsTable, "image compression request", 0 );
if ( tagEntry != TAGENTRYNULL )
TagEntryQValue( tagEntry, &compRequest );
/* compRequest is guaranteed to be one we can support. */
tagEntry = TagTableQDirect( flagsTable, "image clt request", 0 );
if ( tagEntry != TAGENTRYNULL )
TagEntryQValue( tagEntry, &cltRequest );
/* cltRequest is guaranteed to be one we can support. */
tagEntry = TagTableQDirect( flagsTable, "image alpha request", 0 );
if ( tagEntry != TAGENTRYNULL )
TagEntryQValue( tagEntry, &alphaRequest );
/* alphaRequest is guaranteed to be one we can support. */
}
/*
* Eventually we need to get the x & y image offsets out of the
* the tag table
*/
xoffset = 0;
yoffset = 0;
/*
* The current write position is 4 bytes past
* where the "next-dir-offset" is going
* to go, when we know what that is.
*/
diroffsetposition = ImTell( ioType, fd, fp ) - 4;
if ( compRequest == IMCOMPLZW )
{
imTiffWriteDir[IMTIFF_COMPRESSION_INDEX].tdir_offset =
IM_COMPRESSION_LZW << 16;
compress = IM_COMPRESSION_LZW;
}
else if ( compRequest == IMCOMPPB )
{
imTiffWriteDir[IMTIFF_COMPRESSION_INDEX].tdir_offset =
IM_COMPRESSION_PACKBITS << 16;
compress = IM_COMPRESSION_PACKBITS;
}
else
{
imTiffWriteDir[IMTIFF_COMPRESSION_INDEX].tdir_offset =
IM_COMPRESSION_NONE << 16;
compress = IM_COMPRESSION_NONE;
}
/*
* Write out the clt if there is one and we are supposed to write it
* out. Remember where it is and such.
*/
clt = ImVfbQClt( vfb );
if ( clt != IMCLTNULL && cltRequest == IMCLTYES )
{
imTiffWriteDir[IMTIFF_COLORMAP_INDEX].tdir_count = n
= 3 * ImCltQNColors(clt);
imTiffWriteDir[IMTIFF_COLORMAP_INDEX].tdir_offset = ImTell( ioType, fd, fp );
ImMalloc( cbuffer, unsigned short*, sizeof(ushort) * n );
pColor = ImCltQFirst( clt );
for ( i = 0; i < n/3; i++ )
{
cbuffer[i] = (unsigned short) ImCltQRed( pColor );
cbuffer[i+n/3] = (unsigned short) ImCltQGreen( pColor );
cbuffer[i+n/3+n/3] = (unsigned short) ImCltQBlue( pColor );
ImCltSInc( clt, pColor );
}
if (ImBinWrite( ioType, fd, fp, cbuffer, USHORT, 2, n ) == -1)
{
ImReturnBinError( );
}
free( cbuffer );
}
else
{
imTiffWriteDir[IMTIFF_COLORMAP_INDEX].tdir_count= 0;
imTiffWriteDir[IMTIFF_COLORMAP_INDEX].tdir_offset = 0;
}
/*
* Set width and height in the tiff directory
*/
pptr = ImVfbQFirst( vfb );
x = ImVfbQWidth( vfb );
y = ImVfbQHeight( vfb );
imTiffWriteDir[IMTIFF_IMAGEWIDTH_INDEX].tdir_offset = x << 16;
imTiffWriteDir[IMTIFF_IMAGELENGTH_INDEX].tdir_offset = y << 16;
sprintf( message, "%d x %d", x, y );
ImInfo( "Resolution", message );
/*
* Set depth and bitspersample in the tiff directory
*/
fields = ImVfbQFields( vfb );
if ( fields & IMVFBMONO )
{
d = 1;
imTiffWriteDir[IMTIFF_BITSPERSAMPLE_INDEX].tdir_offset = 1<<16;
imTiffWriteDir[IMTIFF_SAMPLESPERPIXEL_INDEX].tdir_offset= 1<<16;
imTiffWriteDir[IMTIFF_PHOTOMETRIC_INDEX].tdir_offset =
IM_PHOTOMETRIC_MINISBLACK << 16;
}
else if ( fields & IMVFBINDEX8 )
{
d = 8;
imTiffWriteDir[IMTIFF_BITSPERSAMPLE_INDEX].tdir_offset = 8<<16;
imTiffWriteDir[IMTIFF_SAMPLESPERPIXEL_INDEX].tdir_offset= 1<<16;
imTiffWriteDir[IMTIFF_PHOTOMETRIC_INDEX].tdir_offset =
IM_PHOTOMETRIC_PALETTE << 16;
}
else if ( fields & IMVFBINDEX16 )
{
d = 16;
imTiffWriteDir[IMTIFF_BITSPERSAMPLE_INDEX].tdir_offset = 8<<16;
imTiffWriteDir[IMTIFF_SAMPLESPERPIXEL_INDEX].tdir_offset= 4<<16;
imTiffWriteDir[IMTIFF_PHOTOMETRIC_INDEX].tdir_offset =
IM_PHOTOMETRIC_PALETTE << 16;
}
else if ( (fields & IMVFBRGB) && (fields & IMVFBALPHA) && alphaRequest == IMALPHAYES )
{
d = 32;
imTiffWriteDir[IMTIFF_BITSPERSAMPLE_INDEX].tdir_offset = 8<<16;
imTiffWriteDir[IMTIFF_SAMPLESPERPIXEL_INDEX].tdir_offset= 4<<16;
imTiffWriteDir[IMTIFF_MATTEING_INDEX].tdir_offset = 1<<16;
imTiffWriteDir[IMTIFF_PHOTOMETRIC_INDEX].tdir_offset =
IM_PHOTOMETRIC_RGB << 16;
}
else if ( fields & IMVFBRGB )
{
d = 24;
imTiffWriteDir[IMTIFF_BITSPERSAMPLE_INDEX].tdir_offset = 8<<16;
imTiffWriteDir[IMTIFF_SAMPLESPERPIXEL_INDEX].tdir_offset= 3<<16;
imTiffWriteDir[IMTIFF_PHOTOMETRIC_INDEX].tdir_offset =
IM_PHOTOMETRIC_RGB << 16;
}
else
{
ImErrNo = IMEDEPTH;
ImErrorFatal( ImQError( ), -1, ImErrNo );
}
if( d < 24 )
sprintf( message, "%d-bit Color Indexed", d );
else
sprintf( message, "%d-bit RGB", d );
ImInfo( "Type", message );
ImInfo( "Plane Configuration", "Chunky (Contiguous)" );
if( clt != NULL )
sprintf( message, "%d Entries", ImCltQNColors( clt ) );
else
sprintf( message, "none" );
ImInfo( "Color Table", message );
/*
* Write out place holders for the stripbyte counts and
* the stripbyteoffsets. Remember where they are and such.
*/
ImCalloc( stripbytecounts, unsigned int *, sizeof(uint), y );
stripbytecountsptr = stripbytecounts;
imTiffWriteDir[IMTIFF_STRIPBYTECOUNTS_INDEX].tdir_count = y;
imTiffWriteDir[IMTIFF_STRIPBYTECOUNTS_INDEX].tdir_offset = ImTell( ioType, fd, fp );
if (ImBinWrite( ioType, fd, fp, stripbytecounts, UINT, 4, y ) == -1)
{
ImReturnBinError( );
}
ImCalloc( stripoffsets, unsigned int *, sizeof(uint), y );
stripoffsetsptr = stripoffsets;
imTiffWriteDir[IMTIFF_STRIPOFFSETS_INDEX].tdir_count = y;
imTiffWriteDir[IMTIFF_STRIPOFFSETS_INDEX].tdir_offset = ImTell( ioType, fd, fp );
if (ImBinWrite( ioType, fd, fp, stripoffsets, UINT, 4, y ) == -1)
{
ImReturnBinError( );
}
/*
* Write out x and y image offset. Always zero for now
*/
imTiffWriteDir[IMTIFF_XPOSITION_INDEX].tdir_offset =
ImTell( ioType, fd, fp );
/*
* We need to fix the binary IO package to do doubles
* In the mean time just write out two ints. x &y offset are
* both zero until we figure out how to put them in the tab table
*
*/
if (ImBinWrite( ioType, fd, fp, &xoffset, DOUBLE, 8, 1 ) == -1)
{
ImReturnBinError( );
}
/*
if (ImBinWrite( ioType, fd, fp, &xoffset, INT, 4, 1 ) == -1)
{
ImReturnBinError( );
}
if (ImBinWrite( ioType, fd, fp, &xoffset, INT, 4, 1 ) == -1)
{
ImReturnBinError( );
}
*/
imTiffWriteDir[IMTIFF_YPOSITION_INDEX].tdir_offset =
ImTell( ioType, fd, fp );
/*
if (ImBinWrite( ioType, fd, fp, &yoffset, INT, 4, 1 ) == -1)
{
ImReturnBinError( );
}
if (ImBinWrite( ioType, fd, fp, &yoffset, INT, 4, 1 ) == -1)
{
ImReturnBinError( );
}
*/
if (ImBinWrite( ioType, fd, fp, &yoffset, DOUBLE, 8, 1 ) == -1)
{
ImReturnBinError( );
}
/*
* Get ready to write out some pixel values
*/
if ( d == 1 )
cnt = sx = (x + (IMTIFFBITSPERBYTE-1)) / IMTIFFBITSPERBYTE;
else
cnt = sx = x * d / IMTIFFBITSPERBYTE;
ImMalloc( buffer, unsigned char *, sx );
if ( compress != IM_COMPRESSION_NONE )
ImMalloc( pbuffer, unsigned char *, sx+1 );
switch( compress )
{
case IM_COMPRESSION_LZW:
ImInfo("Compression Type","Lempel-Ziv and Welch (LZW)");
break;
case IM_COMPRESSION_PACKBITS:
ImInfo("Compression Type","Apple Macintosh Packbits" );
break;
case IM_COMPRESSION_NONE:
ImInfo( "Compression Type", "none" );
break;
}
if ( (fields & IMVFBRGB) && (fields & IMVFBALPHA) && alphaRequest == IMALPHAYES )
{
ImInfo( "Alpha Channel", "8-bit\n" );
}
else
ImInfo( "Alpha Channel", "none\n" );
/*
* For every scanline
*/
for( j=0; j<y; j++ )
{
/*
* Walk through each of the scanlines
* Get pixels out of vfb and into buffer
*/
switch (d)
{
case 1:
memset( buffer,0x00, sx );
rbp = buffer;
for( i=0; i<x; i++ )
{
bw = ImVfbQMono( vfb, pptr );
shift=IMTIFFBITSPERBYTE-(i%IMTIFFBITSPERBYTE)-1;
*rbp = *rbp | ((bw&0x1) << shift);
if ( shift == 0 )
rbp++;
ImVfbSInc( vfb, pptr );
}
break;
case 8:
rbp = buffer;
for( i=0; i<x; i++ )
{
*rbp++ = ImVfbQIndex8( vfb, pptr );
ImVfbSInc( vfb, pptr );
}
break;
case 24:
rbp = buffer;
for( i=0; i<x; i++ )
{
*rbp++ = ImVfbQRed( vfb, pptr );
*rbp++ = ImVfbQGreen( vfb, pptr );
*rbp++ = ImVfbQBlue( vfb, pptr );
ImVfbSInc( vfb, pptr );
}
break;
case 32:
rbp = buffer;
for( i=0; i<x; i++ )
{
*rbp++ = ImVfbQRed( vfb, pptr );
*rbp++ = ImVfbQGreen( vfb, pptr );
*rbp++ = ImVfbQBlue( vfb, pptr );
*rbp++ = ImVfbQAlpha( vfb, pptr );
ImVfbSInc( vfb, pptr );
}
break;
case 16:
rbp = buffer;
for( i=0; i<x; i++ )
{
tmp = ImVfbQIndex16( vfb, pptr );
ImVfbSInc( vfb, pptr );
/* Guarantee MBF byte order. */
*rbp++ = (tmp>>8) & 0xFF;
*rbp++ = tmp & 0xFF;
}
break;
default:
ImErrNo = IMEDEPTH;
sprintf( errstr,"Can't write %d bit image files",d);
ImErrorFatal( errstr, -1, ImErrNo );
}
/*
* Only write scanlines starting on word boundaries
*/
offset = ImTell( ioType, fd, fp );
offset += 4 - (offset % 4);
ImSeek( ioType, fd, fp, offset, 0 );
if ( compress == IM_COMPRESSION_LZW )
{
ImLzwPreEncode( sx );
if ( ImLzwEncode( ioType, fd, fp, buffer, sx ) == -1 )
return( -1 ); /* ImErrNo already set */
if ( ( cnt = ImLzwPostEncode( ioType, fd, fp )) == -1 )
return( -1 ); /* ImErrNo already set */
}
else if ( compress == IM_COMPRESSION_PACKBITS )
{
cnt = sx;
PackBits( buffer, pbuffer, (unsigned int*)&cnt );
if (ImBinWrite( ioType, fd, fp, pbuffer,
UCHAR, 1, cnt ) == -1)
{
ImReturnBinError( );
}
}
else
{
if (ImBinWrite(ioType,fd,fp,buffer, UCHAR, 1, cnt)== -1)
{
ImReturnBinError( );
}
}
*stripbytecountsptr++ = cnt;
*stripoffsetsptr++ = offset;
}
#ifdef DEBUG
imPrintTiffWriteDir( "After", stripbytecounts, stripoffsets );
#endif
if ( compress == IM_COMPRESSION_LZW )
ImLzwCleanup( );
/*
* Seek back and write out the offset of the new direntry
*/
newdiroffset = ImTell( ioType, fd, fp );
newdiroffset += 4 - (newdiroffset % 4);
ImSeek( ioType, fd, fp, diroffsetposition, 0 );
if (ImBinWrite( ioType, fd, fp, &newdiroffset, UINT, 4, 1 ) == -1)
{
ImReturnBinError( );
}
/*
* Seek to the stripoffset location and write out some real values
*/
ImSeek( ioType, fd, fp,
imTiffWriteDir[IMTIFF_STRIPOFFSETS_INDEX].tdir_offset, 0 );
if (ImBinWrite( ioType, fd, fp, stripoffsets, UINT, 4, y ) == -1)
{
ImReturnBinError( );
}
/*
* Seek to the stripbytecounts location and write out some real values
*/
ImSeek( ioType, fd, fp,
imTiffWriteDir[IMTIFF_STRIPBYTECOUNTS_INDEX].tdir_offset, 0 );
if (ImBinWrite( ioType, fd, fp, stripbytecounts, UINT, 4, y ) == -1)
{
ImReturnBinError( );
}
/*
* Seek to the new dir location and write out the dir entries
*/
ImSeek( ioType, fd, fp, newdiroffset, 0 );
if ( cltRequest == IMCLTNO || clt == IMCLTNULL )
sh = IMTIFFWRITEDIRENTRIES - 1;
else
sh = IMTIFFWRITEDIRENTRIES;
if (ImBinWrite( ioType, fd, fp, &sh, USHORT, 2, 1 ) == -1)
{
ImReturnBinError( );
}
/*
* Write out all of the directory entries
*/
for( i=0; i<sh; i++ )
{
if ( ImBinWriteStruct( ioType, fd, fp, &(imTiffWriteDir[i]),
imTiffDirFields) == -1 )
{
ImReturnBinError( );
}
/*
* Write the offset field separately since it can contain one
* of three different types of variables.
* Check to see if the offset field contains an offset.
* If it does, then write it as an int and continue
*/
size = imTiffWriteDir[i].tdir_count *
imTiffDataWidth[imTiffWriteDir[i].tdir_type];
if ( size > 4 )
{
if ( ImBinWrite( ioType, fd, fp,
&(imTiffWriteDir[i].tdir_offset), INT, 4, 1) == -1 )
ImReturnBinError();
continue;
}
/*
* If it is not an offset, then there is data in the
* offset field. We have to read it as the correct type
*/
switch( imTiffWriteDir[i].tdir_type )
{
case IMTIFFBYTE:
case IMTIFFASCII:
status = ImBinWrite( ioType, fd, fp,
&(imTiffWriteDir[i].tdir_offset), UCHAR, 1, 4);
break;
case IMTIFFSHORT:
so[0]=(imTiffWriteDir[i].tdir_offset & 0xffff0000) >>16;
so[1]=imTiffWriteDir[i].tdir_offset & 0xffff;
status = ImBinWrite( ioType, fd, fp, so, SHORT, 2, 2);
break;
case IMTIFFLONG:
status = ImBinWrite( ioType, fd, fp,
&(imTiffWriteDir[i].tdir_offset), INT, 4, 1);
break;
}
if ( status == -1 )
ImReturnBinError( );
}
/*
* The file pointer is currently positioned at the place where the
* "offset-to-next-directory" value goes. The next call to this
* routine (imTiffVfbWrite()) calls ImTell() to get this offset.
*/
free( buffer );
if ( pbuffer )
free( pbuffer );
return( 0 );
}
#else /* from #ifndef USE_TIFF_LIB */
/*
*
* Code to use the tiff library routines starts here.
*
*/
/*
* FUNCTION
* imTiffRead
*
* DESCRIPTION
* Read in a tiff file using the routines in the tiff library.
*
*/
static int /* Returns status */
#ifdef __STDC__
imTiffRead( int ioType, int fd, FILE *fp, TagTable *flags, TagTable *tagTable )
#else
imTiffRead( ioType, fd, fp, flags, tagTable )
int ioType; /* I/O flags */
int fd; /* Input file descriptor */
FILE *fp; /* Input file pointer */
TagTable *flags; /* Format flags */
TagTable *tagTable; /* Tag table to add to */
#endif
{
TIFF* tif; /* Structure for manipulating TIFF image. */
ImVfb* vfb; /* Vfb we will be creating. */
uint32 xSize, ySize; /* Image Size (in bytes) for allocating vfb */
int fieldMask; /* Fields in the Vfb. */
uint16 numchans; /* number of channels */
uint16 chandepth; /* number of bits per channel */
uint16 interleave_method; /* method of interleaving. */
uint16 photometric; /* indicates color index / rgb / b&w */
ImClt* cltBuf; /* Color lookup table */
uint16 byteOrder; /* byte order in file (just for ImInfo) */
uint16 compression; /* compression method (just for ImInfo) */
char* filename; /* filename */
char message[500]; /* message buffer */
int curImage; /* Index of current image in the file */
int moreImages; /* Flag for the while loop */
TagEntry* entry; /* Entry to get file name */
/*
* We need a file descriptor. So, if we have a
* file pointer, get a file descriptor
* for it.
*/
if (ioType & IMFILEIOFP)
{
fd = fileno(fp);
fflush(fp);
rewind(fp);
}
/*
* If we can't discern the filename, use 'libtiff'. This way, error messages
* will say things like 'libtiff: Can't open file'.
*/
if (!flags || TagTableQNEntry (flags, "file name") == 0)
{
filename = NULL;
}
else
{
entry = TagTableQDirect ( flags, "file name", 0 );
if (TagEntryQValue( entry, &filename) == -1)
filename = NULL;
}
tif = TIFFFdOpen( fd, filename ? filename : "libtiff", "rb");
if (tif == IMTIFFNULL)
{
ImErrorFatal( "Error opening file.", -1, IMENOFILE);
}
moreImages = 1;
curImage = 0;
/* Loop through the images in the file */
while (moreImages)
{
curImage++;
sprintf( message, "%d", curImage );
ImInfo( "Image", message );
/*
* Figure out how big the image is and what fields it contains.
* Then allocate our vfb accordingly.
*/
/* Get the image size */
TIFFGetField( tif, TIFFTAG_IMAGEWIDTH, &xSize);
TIFFGetField( tif, TIFFTAG_IMAGELENGTH, &ySize);
sprintf(message,"%d x %d",xSize,ySize);
ImInfo( "Resolution", message);
/* Get the image type */
TIFFGetField( tif, TIFFTAG_PHOTOMETRIC, &photometric);
TIFFGetFieldDefaulted(tif, TIFFTAG_BITSPERSAMPLE, &chandepth);
TIFFGetFieldDefaulted(tif, TIFFTAG_SAMPLESPERPIXEL, &numchans);
/*
* Translate tiff's idea of an image type into the image tools'
* idea of an image type
*/
fieldMask = 0;
switch (numchans)
{
case 1: /* Greyscale or color-indexed */
if (chandepth<=8)
{
sprintf(message,"%d-bit %s", chandepth,
photometric==PHOTOMETRIC_PALETTE ? "Color Indexed" : "Greyscale" );
fieldMask = IMVFBINDEX8;
ImInfo ( "Type", message);
if (photometric==PHOTOMETRIC_MINISWHITE)
ImInfo("Greyscale Mode", "Minimum is white");
if (photometric==PHOTOMETRIC_MINISBLACK)
ImInfo("Greyscale Mode", "Minimum is black");
}
else
if (chandepth==16)
{
fieldMask = IMVFBINDEX16;
ImInfo ("Type", "16-bit Color indexed");
}
break;
case 3: /* RGB with no alpha */
fieldMask = IMVFBRGB;
sprintf(message,"%d-bit RGB", chandepth * numchans);
ImInfo ("Type", message);
break;
case 4: /* RGB with alpha */
fieldMask = IMVFBRGB | IMVFBALPHA;
break;
default: break;
} /* End of switch */
if (fieldMask==0)
{
sprintf(message,"Cannot handle images with %d channels, and depth %d",
numchans, chandepth);
ImErrorFatal( message, -1, IMEUNSUPPORTED);
}
/*
* No support for the following.
*/
if (photometric==PHOTOMETRIC_YCBCR)
{
ImErrorFatal( "No support for YCBCR photometric interepretation",-1,
IMEUNSUPPORTED);
}
/* Allocate our vfb */
vfb = ImVfbAlloc( xSize, ySize, fieldMask );
if ( (vfb = ImVfbAlloc( xSize, ySize, fieldMask )) == IMVFBNULL)
{
ImErrorFatal( ImQError( ), -1, ImErrNo );
}
/* Discern the byte order for ImInfo message */
TIFFGetFieldDefaulted(tif, TIFFTAG_FILLORDER, &byteOrder);
if (byteOrder==FILLORDER_MSB2LSB)
ImInfo( "Byte Order", "Most Significant Byte First")
else
ImInfo( "Byte Order", "Least Significant Byte First")
/* Discern the compression scheme */
TIFFGetFieldDefaulted(tif, TIFFTAG_COMPRESSION, &compression);
switch (compression)
{
case COMPRESSION_NONE:
ImInfo ("Compression Type", "none");
break;
case COMPRESSION_CCITTRLE:
ImInfo ("Compression Type", "CCITT modified Huffman encoding");
break;
case COMPRESSION_CCITTFAX3:
ImInfo ("Compression Type", "CCITT Group 3 facsimile encoding");
break;
case COMPRESSION_CCITTFAX4:
ImInfo ("Compression Type", "CCITT Group 4 facsimile encoding");
break;
case COMPRESSION_CCITTRLEW:
ImInfo ("Compression Type", "CCITT modified Huffman encoding w/ word alignment");
break;
case COMPRESSION_PACKBITS:
ImInfo ("Compression Type", "Macintosh PackBits encoding");
break;
case COMPRESSION_THUNDERSCAN:
ImInfo ("Compression Type", "ThunderScan 4-bit encoding");
break;
case COMPRESSION_LZW:
ImInfo ("Compression Type", "Lempel-Ziv & Welch encoding");
break;
case COMPRESSION_NEXT:
ImInfo ("Compression Type", "NeXT 2-bit encoding");
break;
case COMPRESSION_JPEG:
ImInfo ("Compression Type", "JPEG encoding");
break;
default:
ImInfo ("Compression Type", "Unknown");
break;
}
/*
*
* Determine the method of interleaving, and grouping.
* Then call the appropriate subroutine to decode the pixel
* data.
*
*/
if (TIFFIsTiled(tif))
ImInfo( "Grouping Method", "Tiles" )
else
ImInfo( "Grouping Method", "Scanlines" )
TIFFGetFieldDefaulted(tif, TIFFTAG_PLANARCONFIG, &interleave_method);
switch (interleave_method)
{
case PLANARCONFIG_CONTIG : /* contiguous (noninterleaved) */
ImInfo( "Interleave Method", "Non-interleaved" );
if (TIFFIsTiled(tif))
imTiffReadNonInterleavedTiles (tif, vfb);
else
imTiffReadNonInterleavedScanlines( tif, vfb);
break;
case PLANARCONFIG_SEPARATE : /* plane interleaved */
ImInfo( "Interleave Method", "Plane Interleaved" );
if (TIFFIsTiled (tif))
imTiffReadPlaneInterleavedTiles ( tif, vfb);
else
imTiffReadPlaneInterleavedScanlines ( tif, vfb);
break;
default :
ImErrorFatal( "Unknown interleave method.",-1, IMEUNSUPPORTED);
}
/*
* If there is a clt, read it in.
*/
if (photometric == PHOTOMETRIC_PALETTE)
{
sprintf(message,"%d-bit", chandepth);
ImInfo ("Color Table", message );
if (imTiffReadClt(tif, &cltBuf) != 0)
{
ImVfbSClt (vfb, cltBuf);
TagTableAppend( tagTable,
TagEntryAlloc( "image clt", POINTER, &cltBuf ) );
}
/* else error is reported by imTiffReadClt */
}
else
ImInfo ("Color Table", "none");
/*
* Append the vfb to the tagtable
*/
TagTableAppend( tagTable,
TagEntryAlloc( "image vfb", POINTER, &vfb ) );
moreImages = TIFFReadDirectory(tif);
} /* End of while moreimages */
TIFFClose( tif );
return curImage;
}
/*
* Macro to scale value to be between 0 and 255
*/
#define IM_SCALE_0_255(currentValue,chandepth) ( ((currentValue) * 255) / ( (1L << (chandepth)) - 1))
/*
*
* FUNCTION
* imTiffReadNonInterleavedScanlines
*
* DESCRIPTION
* Read data into a vfb, from a TIFF structure.
* The data is stored in the form RGBRGBRGB....
* The tiff library calls this "contiguous". We
* call it "non-interleaved".
*
* RETURN VALUE
* 1 if everything went smoothly.
* 0 otherwise.
*
*/
static int
#ifdef __STDC__
imTiffReadNonInterleavedScanlines( TIFF* tif, ImVfb* vfb)
#else
imTiffReadNonInterleavedScanlines( tif, vfb)
TIFF* tif; /* incoming data */
ImVfb* vfb; /* outgoing vfb */
#endif
{
unsigned char* linebuf; /* buffer for one scanline */
uint16* linebuf16; /* the line as an array of 16-bit values */
tsize_t scanlineSize; /* size of scanlines */
ImVfbPtr vfbptr; /* ptr into a vfb */
uint32 row, col; /* Loop indices */
uint32 ySize; /* Image size (y) */
uint16 numchans; /* number of channels */
uint16 chandepth; /* number of bits per channel */
uint16 mask; /* mask to read pixels from the array */
uint16 startmask; /* start with this mask */
uint16 currentValue; /* value of current channel of current pixel */
int sampleNum; /* Index of the current value in the scanline */
int samplesPerScanline; /* number of samples per scanline. */
int chanIndex; /* which channel is being set */
/* (index in the chanList array) */
int index16; /* index within 16-bit array */
int chanList[5]; /* List of channels to cycle through */
uint16 photometric; /* Tells us the type of image this is. */
int currentShift; /* How many bits to shift this sample */
char message[200]; /* Buffer for error messages */
int isGreyscale; /* flag indicating greyscale image (vs clt) */
uint16 compression; /* Compression type */
int byteOrder; /* indicates byte order */
/* Get some important fields from the tiff structure. */
TIFFGetFieldDefaulted(tif, TIFFTAG_BITSPERSAMPLE, &chandepth);
TIFFGetFieldDefaulted(tif, TIFFTAG_SAMPLESPERPIXEL, &numchans);
TIFFGetField( tif, TIFFTAG_IMAGELENGTH, &ySize);
TIFFGetField( tif, TIFFTAG_PHOTOMETRIC, &photometric);
TIFFGetFieldDefaulted(tif, TIFFTAG_COMPRESSION, &compression);
scanlineSize = TIFFScanlineSize(tif);
samplesPerScanline = scanlineSize * 8 / chandepth;
byteOrder = BinQMachine()->bin_byteOrder;
/*
* According to page 17 of the TIFF 6.0 specification, grayscale images that
* are compressed with certain compression schemes should be reversed.
*/
if ( (compression==COMPRESSION_CCITTRLE) ||
(compression==COMPRESSION_CCITTFAX3) ||
(compression==COMPRESSION_CCITTRLEW) ||
(compression==COMPRESSION_CCITTFAX4) )
{
/* Switch the photometric if it is a greyscale image */
if (photometric==PHOTOMETRIC_MINISBLACK)
photometric = PHOTOMETRIC_MINISWHITE;
else if (photometric==PHOTOMETRIC_MINISWHITE)
photometric = PHOTOMETRIC_MINISBLACK;
}
/*
* Here is what's going on here:
*
* The scanlines are read one at a time.
*
* For each scanline...
*
* We need to extract values from the scanline that are not necessarily
* 8-bits (in particular, that are 1,2,4,8 or 16 bits).
*
* To do this, we cast the array of values into an array of 16-bit values,
* and then use a bit-mask, in conjunction with an array index, to traverse
* the array.
*
* i.e.
* array: +----+----+----+----+ ...
* | | | | |
* +----+----+----+----+ ...
* mask: 1100
* index16: 0
*
* when index16 is 0, and the mask masks the upper 4 bits of a uint16, then
* we are looking at the value in the first 4 bits of the first array element.
*
* When index16 is 1, we are looking at the first 4 bits of the second array element.
* et cetera
*
* This allows us to extract values from the scanline. Then, for each value, we
* determine which channel we are on by using an array containing the channels through
* which we are looping.
*
* This will allow us to read a scanline of the form
* RGBRGBRGBRGB
*
* where each R is only 2 bits long.
* (and each G is only 2 bits long and each B is only 2 bits long)
*/
/* Set up the original mask (Mask the leftmost chandepth bits) */
mask = (uint16) 0;
switch (chandepth)
{
case 16 : mask = mask | (1<<0);
mask = mask | (1<<1);
mask = mask | (1<<2);
mask = mask | (1<<3);
mask = mask | (1<<4);
mask = mask | (1<<5);
mask = mask | (1<<6);
mask = mask | (1<<7); /* fall through */
case 8 : mask = mask | (1<<8);
mask = mask | (1<<9);
mask = mask | (1<<10);
mask = mask | (1<<11); /* fall through */
case 4 : mask = mask | (1<<12);
mask = mask | (1<<13); /* fall through */
case 2 : mask = mask | (1<<14); /* fall through */
case 1 : mask = mask | (1<<15);
break;
default :
sprintf(message,"Unsupported channel depth. No support for %d bits per sample",chandepth);
ImErrorWarning(message,0,IMEUNSUPPORTED);
return 0;
}
startmask = mask;
/*
* Set up the list of channels through which we are going to cycle.
*/
switch (numchans)
{
case 1 :
/*
* Determine whether this is a greyscale image or a color
* indexed image. (So that we know whether or not to scale
* the incoming value to be between 0 and 255.
*/
if (photometric!=PHOTOMETRIC_PALETTE)
isGreyscale = 1;
else
isGreyscale = 0;
if (chandepth==16)
chanList[0] = IMVFBINDEX16;
else
chanList[0] = IMVFBINDEX8;
break;
case 3 :
chanList[0] = IMVFBRED;
chanList[1] = IMVFBGREEN;
chanList[2] = IMVFBBLUE;
break;
case 4 :
chanList[0] = IMVFBRED;
chanList[1] = IMVFBGREEN;
chanList[2] = IMVFBBLUE;
chanList[3] = IMVFBALPHA;
break;
default :
sprintf(message,"Unsupported channel depth (bits per sample) : %d",chandepth);
ImErrorWarning(message,0,IMEUNSUPPORTED);
}
/*
* currentShift tells us how many bits to shift the value
* to the right, after we get it from the array.
* i.e. after using mask to collect the upper 2 bits of
* a uint16, we need to shift the value 14 bits to the right
* to get our final value.
*/
currentShift = 16 - chandepth;
/* Allocate space and cast our array into a 16-bit one. */
ImMalloc(linebuf,unsigned char *,scanlineSize);
linebuf16 = (uint16 *) linebuf;
for (row=0; row< ySize ; row++)
{
/* Read a scanline */
if (TIFFReadScanline(tif, linebuf, row, 0) < 0)
break;
if (byteOrder==BINLBF)
imTiffSwapBytes(linebuf, samplesPerScanline);
/*
* mask and index16 start at the upper chandepth
* bits of the first array element
*/
index16 = 0;
mask = startmask;
/*
* start with the first channel (i.e. red for RGB,
* INDEX8 for indexed images ...
*/
chanIndex = 0;
/* Keep track of how many samples we've traversed (so far 0) */
sampleNum = 0;
/* currentShift's function is explained above */
currentShift = 16 - chandepth;
/* move to the beginning of the row */
vfbptr = ImVfbQPtr(vfb, 0, row);
while (sampleNum < samplesPerScanline)
{
/*
* index16 is the index relative to the 16-bit array.
* mask is the mask within the current array element
* (i.e. the index relative to the current 16-bit value)
* sampleNum is the index of the sample in the scanline.
*
*/
currentValue = (mask & *(linebuf16 + index16));
currentValue = currentValue >> currentShift;
currentShift -= chandepth;
if (currentShift < 0)
currentShift = 16 - chandepth;
/* Is 0 black or white? */
if (photometric == PHOTOMETRIC_MINISWHITE)
{
currentValue = ~currentValue;
/* Knock off upper (16 - chandepth) bits */
currentValue = currentValue << (16 - chandepth);
currentValue = currentValue >> (16 - chandepth);
}
switch (chanList[chanIndex])
{
case IMVFBINDEX8 : /* same as IMVFBGREY */
if (isGreyscale)
ImVfbSGrey(vfb, vfbptr, IM_SCALE_0_255(currentValue,chandepth));
else
ImVfbSIndex8 (vfb, vfbptr, currentValue);
break;
case IMVFBRED :
ImVfbSRed (vfb, vfbptr, IM_SCALE_0_255(currentValue,chandepth) );
break;
case IMVFBGREEN :
ImVfbSGreen(vfb, vfbptr, IM_SCALE_0_255(currentValue,chandepth) );
break;
case IMVFBBLUE :
ImVfbSBlue (vfb, vfbptr, IM_SCALE_0_255(currentValue,chandepth) );
break;
case IMVFBALPHA :
ImVfbSAlpha (vfb, vfbptr, IM_SCALE_0_255(currentValue,chandepth) );
break;
case IMVFBINDEX16 :
ImVfbSIndex16 (vfb, vfbptr, currentValue );
break;
}
/*
* Increment: the channel index, the sample number,
* the mask, possibly the vfb pointer, and possibly
* the index in the scanline array.
*/
chanIndex++;
if (chanIndex > (numchans - 1))
{
ImVfbSNext (vfb, vfbptr);
chanIndex = 0;
}
sampleNum++;
/* Shift mask and possibly index16 */
mask = mask>>chandepth;
if (mask == 0)
{
mask = startmask;
index16++;
}
}
}
free ((unsigned char *) linebuf);
return 1;
}
/*
*
* FUNCTION
* imTiffReadPlaneInterleavedScanlines
*
* DESCRIPTION
* Read data into a vfb, from a TIFF structure.
* The data is stored in the form RRR...GGG...BBB....B
* The tiff library calls this "seperate". We
* call it "plane-interleaved".
*
*/
static int /* returns 1 for success, 0 for failure */
#ifdef __STDC__
imTiffReadPlaneInterleavedScanlines( TIFF* tif, ImVfb* vfb)
#else
imTiffReadPlaneInterleavedScanlines( tif, vfb)
TIFF* tif; /* incoming data */
ImVfb* vfb; /* outgoing vfb */
#endif
{
uint16 numchans; /* number of channels */
uint16 chandepth; /* Depth of each channel */
char message[200]; /* Buffer for messages */
/*
* Get the number of channels and channel depth from tiff
*/
TIFFGetFieldDefaulted(tif, TIFFTAG_SAMPLESPERPIXEL, &numchans);
TIFFGetFieldDefaulted(tif, TIFFTAG_BITSPERSAMPLE, &chandepth);
/*
* Go through the vfb once for each channel, and
* read the appropriate plane from the TIFF structure.
*/
switch (numchans)
{
case 1:
/*
* Being plane interleaved and having only one
* plane is silly. It's the same as being non-interleaved.
* Nevertheless, tiff's flags can indicate such a thing
* occurring.
* So, let's just call the non-interleaved function.
* (which handles varying channel depths.)
*/
imTiffReadNonInterleavedScanlines(tif, vfb);
break;
case 3:
if (chandepth!=8)
{
sprintf(message,"Can't read %d bits per channel plane-interleaved images\n",chandepth);
ImErrorFatal(message,0,IMEUNSUPPORTED);
}
imTiffReadRedScanlinePlane(tif, vfb);
imTiffReadGreenScanlinePlane(tif, vfb);
imTiffReadBlueScanlinePlane(tif, vfb);
break;
case 4:
if (chandepth!=8)
{
sprintf(message,"Can't read %d bits per channel plane-interleaved images\n",chandepth);
ImErrorFatal(message,0,IMEUNSUPPORTED);
}
imTiffReadRedScanlinePlane(tif, vfb);
imTiffReadGreenScanlinePlane(tif, vfb);
imTiffReadBlueScanlinePlane(tif, vfb);
imTiffReadAlphaScanlinePlane(tif, vfb);
break;
default :
sprintf(message,"Can't read %d channels plane-interleaved\n",numchans);
ImErrorFatal(message,0,IMEUNSUPPORTED);
}
return 1;
}
/*
*
* FUNCTION
* imTiffReadClt
*
* DESCRIPTION
* Allocate space for, and then read a clt from a tiff file.
*
*/
static int /* returns 1 for success, 0 for failure */
#ifdef __STDC__
imTiffReadClt(TIFF* tif, ImClt **cltBuf)
#else
imTiffReadClt(tif, cltBuf)
TIFF* tif; /* TIFF structure */
ImClt **cltBuf; /* buffer for new clt */
#endif
{
int nClt; /* Number of entries in the clt */
uint16 *redmap, /* Red color table entry components */
*greenmap, /* Green color table entry components */
*bluemap; /* Blue color table entry components */
uint16 chandepth; /* Depth of each channel */
ImCltPtr cltptr; /* Pointer into a clt */
int i; /* loop index */
/*
* Read in the table
*/
if (!TIFFGetField(tif, TIFFTAG_COLORMAP, &redmap, &greenmap, &bluemap))
{
ImErrorFatal("No color table for image",0,IMENOCLT);
}
/* Compute number of entries in the clt. */
TIFFGetFieldDefaulted(tif, TIFFTAG_BITSPERSAMPLE, &chandepth);
nClt = 1<<chandepth;
/* Allocate a new clt */
if ( (*cltBuf = ImCltAlloc(nClt)) == IMCLTNULL)
{
ImErrorFatal ( ImQError(), 0, ImErrNo );
}
cltptr = ImCltQFirst (*cltBuf);
/* Copy stuff into the clt */
for (i=0;i < nClt; i++)
{
ImCltSRed (cltptr, (redmap[i]) );
ImCltSGreen (cltptr, (greenmap[i]) );
ImCltSBlue (cltptr, (bluemap[i]) );
ImCltSInc (*clrBuf, cltptr);
}
return 1;
}
/*
* FUNCTION
*
* imTiffReadNonInterleavedTiles
*
* DESCRIPTION
*
* Read the data in a tif file into a vfb, where the storage
* method is non-interleaved tiles. (i.e. RGBRGBRGB.... organized into
* tiles.)
*
*/
static int /* returns 1 for success, 0 for failure */
#ifdef __STDC__
imTiffReadNonInterleavedTiles (TIFF *tif, ImVfb *vfb)
#else
imTiffReadNonInterleavedTiles(tif, vfb)
TIFF* tif;
ImVfb* vfb;
#endif
{
unsigned char* tilebuf; /* buffer for one scanline */
uint16* tilebuf16; /* the line as an array of 16-bit values */
tsize_t tileSize; /* size of tiles */
ImVfbPtr vfbptr; /* ptr into a vfb */
int x, y, index16; /* Loop indices */
uint32 imageWidth,
imageLength; /* Image size (y) */
uint16 numchans; /* number of channels */
uint16 chandepth; /* number of bits per channel */
uint16 mask; /* mask to read pixels from the array */
uint16 startmask; /* start with this mask */
uint16 currentValue; /* value of current channel of current pixel */
int sampleNum; /* Index of the current value in the tile */
int samplesPerTile; /* number of samples per scanline. */
int chanIndex; /* which channel is being set */
/* (index in the chanList array) */
int chanList[5]; /* List of channels to cycle through */
uint16 photometric; /* Tells us the type of image this is. */
int currentShift; /* How many bits to shift this sample */
uint32 tileWidth, /* Width of each tile (must be multiple of 16)*/
tileLength; /* Length of each tile ( " " ) */
int pixelNum; /* x-coordinate of pixel within this tile */
int pixelsInThisTile; /* Number of pixels in this tile */
char message[200]; /* Buffer for error messages */
int isGreyscale; /* flag indicating greyscale image (vs clt) */
uint16 compression; /* Compression type */
int vfbX, vfbY; /* index relative to the entire vfb */
int byteOrder; /* machine's byte order */
/* Get some important fields from the tiff structure. */
TIFFGetFieldDefaulted(tif, TIFFTAG_BITSPERSAMPLE, &chandepth);
TIFFGetFieldDefaulted(tif, TIFFTAG_SAMPLESPERPIXEL, &numchans);
TIFFGetFieldDefaulted(tif, TIFFTAG_COMPRESSION, &compression);
TIFFGetField(tif, TIFFTAG_IMAGEWIDTH, &imageWidth);
TIFFGetField(tif, TIFFTAG_IMAGELENGTH, &imageLength);
TIFFGetField( tif, TIFFTAG_PHOTOMETRIC, &photometric);
TIFFGetField(tif, TIFFTAG_TILEWIDTH, &tileWidth);
TIFFGetField(tif, TIFFTAG_TILELENGTH, &tileLength);
tileSize = TIFFTileSize(tif);
samplesPerTile = tileSize * 8 / chandepth;
byteOrder = BinQMachine()->bin_byteOrder;
/*
* According to page 17 of the TIFF 6.0 specification, grayscale images that
* are compressed with certain compression schemes should be reversed.
*
*/
if ( (compression==COMPRESSION_CCITTRLE) ||
(compression==COMPRESSION_CCITTFAX3) ||
(compression==COMPRESSION_CCITTRLEW) ||
(compression==COMPRESSION_CCITTFAX4) )
{
/* Switch the photometric if it is a greyscale image */
if (photometric==PHOTOMETRIC_MINISBLACK)
photometric = PHOTOMETRIC_MINISWHITE;
else if (photometric==PHOTOMETRIC_MINISWHITE)
photometric = PHOTOMETRIC_MINISBLACK;
}
/*
* Here is what's going on here:
*
* The tiles are read one at a time.
*
* For each tile...
*
* We need to extract values from the tile that are not necessarily
* 8-bits (in particular, that are 1,2,4,8 or 16 bits).
*
* To do this, we cast the array of values into an array of 16-bit values,
* and then use a bit-mask, in conjunction with an array index, to traverse
* the array.
*
* i.e.
* array: +----+----+----+----+ ...
* | | | | |
* +----+----+----+----+ ...
* mask: 1100
* index16: 0
*
* when index16 is 0, and the mask masks the upper 4 bits of a uint16, then
* we are looking at the value in the first 4 bits of the first array element.
*
* When index16 is 1, we are looking at the first 4 bits of the second array element.
* et cetera
*
* This allows us to extract values from the tile. Then, for each value, we
* determine which channel we are on by using an array containing the channels through
* which we are looping.
*
* This will allow us to read a tile of the form
* RGBRGBRGBRGB
*
* where each R is only 2 bits long.
* (and each G is only 2 bits long and each B is only 2 bits long)
*
* After reading a value, the correct channel for the vfbptr is set, the vfbptr
* from from left to right, and top to bottom along each tile.
*/
/*
* Note also that if we read a tile that is x by y, then there
* will always be x*y*number-of-channes pixels in the buffer.
* This means that if a tile goes beyond the boundaries of a
* vfb, then it will be padded with junk.
*/
/* Set up the original mask (Mask the leftmost chandepth bits) */
mask = (uint16) 0;
switch (chandepth)
{
case 16 : mask = mask | (1<<0);
mask = mask | (1<<1);
mask = mask | (1<<2);
mask = mask | (1<<3);
mask = mask | (1<<4);
mask = mask | (1<<5);
mask = mask | (1<<6);
mask = mask | (1<<7); /* fall through */
case 8 : mask = mask | (1<<8);
mask = mask | (1<<9);
mask = mask | (1<<10);
mask = mask | (1<<11); /* fall through */
case 4 : mask = mask | (1<<12);
mask = mask | (1<<13); /* fall through */
case 2 : mask = mask | (1<<14); /* fall through */
case 1 : mask = mask | (1<<15);
break;
default :
sprintf(message,"Unsupported channel depth (bits per sample) : %d",chandepth);
ImErrorWarning(message,0,IMEUNSUPPORTED);
}
startmask = mask;
/*
* Set up the list of channels through which we are going to cycle.
*/
switch (numchans)
{
case 1 :
/*
* Determine whether this is a greyscale image or a color
* indexed image. (So that we know whether or not to scale
* the incoming value to be between 0 and 255.
*/
if (photometric!=PHOTOMETRIC_PALETTE)
isGreyscale = 1;
else
isGreyscale = 0;
if (chandepth==16)
chanList[0] = IMVFBINDEX16;
else
chanList[0] = IMVFBINDEX8;
break;
case 3 :
chanList[0] = IMVFBRED;
chanList[1] = IMVFBGREEN;
chanList[2] = IMVFBBLUE;
break;
case 4 :
chanList[0] = IMVFBRED;
chanList[1] = IMVFBGREEN;
chanList[2] = IMVFBBLUE;
chanList[3] = IMVFBALPHA;
break;
default :
sprintf(message,"No support for %d channels in an image. Skipping image",numchans);
ImErrorWarning(message,0,IMEUNSUPPORTED);
}
chanIndex = 0;
/*
* currentShift tells us how many bits to shift the value
* to the right, after we get it from the array.
* i.e. after using mask to collect the upper 2 bits of
* a uint16, we need to shift the value 14 bits to the right
* to get our final value.
*/
currentShift = 16 - chandepth;
/*
* Allocate space for our tile buffer, and cast
* it into an array of 16-bit values
*/
ImMalloc(tilebuf,unsigned char *,tileSize+1);
tilebuf16 = (uint16 *) tilebuf;
for (y = 0; y < imageLength ; y+=tileLength)
{
for (x = 0; x < imageWidth; x += tileWidth)
{
/* Keep track of where we are precisely with vfbX and vfbY */
vfbY = y;
vfbX = x;
/* Read the tile! */
if (TIFFReadTile(tif, tilebuf, x, y, 0, 0) < 0)
break;
if (byteOrder==BINLBF)
imTiffSwapBytes(tilebuf, tileSize);
/*
* Set vfbptr to the upper left hand corner of where this
* tile goes in the image.
*/
vfbptr = ImVfbQPtr(vfb, x , y);
/* Start with the first sample of the first pixel in the first array element*/
pixelNum = 0;
index16 = 0;
sampleNum = 0;
while (vfbY < y + tileLength )
{
/*
* index16 is the index relative to the 16-bit array.
* mask is the mask within the current array element
* (i.e. the index relative to the current 16-bit value)
* sampleNum is the index of the sample in the tile.
*/
currentValue = (mask & tilebuf16[index16]);
currentValue = currentValue >> currentShift;
currentShift -= chandepth;
if (currentShift < 0)
currentShift = 16 - chandepth;
/* Is 0 black or white? */
if (photometric == PHOTOMETRIC_MINISWHITE)
{
currentValue = ~currentValue;
/* Knock off upper (16 - chandepth) bits */
currentValue = currentValue << (16 - chandepth);
currentValue = currentValue >> (16 - chandepth);
}
/*
* Only set the value if we are within the vfb
*/
if (vfbX < imageWidth && vfbY < imageLength)
{
switch (chanList[chanIndex])
{
case IMVFBGREY : /* same as INDEX8 */
if (isGreyscale)
ImVfbSGrey(vfb, vfbptr, IM_SCALE_0_255(currentValue,chandepth));
else
ImVfbSIndex8 (vfb, vfbptr, currentValue);
break;
case IMVFBRED :
ImVfbSRed (vfb, vfbptr, IM_SCALE_0_255(currentValue,chandepth) );
break;
case IMVFBGREEN :
ImVfbSGreen(vfb, vfbptr, IM_SCALE_0_255(currentValue,chandepth) );
break;
case IMVFBBLUE :
ImVfbSBlue (vfb, vfbptr, IM_SCALE_0_255(currentValue,chandepth) );
break;
case IMVFBALPHA :
ImVfbSAlpha (vfb, vfbptr, IM_SCALE_0_255(currentValue,chandepth) );
break;
case IMVFBINDEX16 :
ImVfbSIndex16 (vfb, vfbptr, currentValue );
break;
}
}
/*
* Increment: the channel index, the sample number,
* the mask, possibly the vfb pointer, and possibly
* the index in the scanline array.
*/
chanIndex++;
if (chanIndex > (numchans - 1))
{
/*
* Move right one pixel in the vfb.
* If we are at a boundary of the tile, then
* move down one line and left to y
*/
vfbX++;
pixelNum++;
if (pixelNum == tileWidth)
{ /* Reached the right edge of the tile */
pixelNum = 0;
vfbY += 1;
vfbX = x;
if (vfbX < imageWidth && vfbY < imageLength)
vfbptr = ImVfbQPtr(vfb, x, vfbY);
}
else
{
/* If we're still in the vfb */
if (vfbX < imageWidth && vfbY < imageLength)
ImVfbSRight (vfb, vfbptr);
}
chanIndex = 0;
}
sampleNum++;
/* Shift mask and possibly index16 */
mask = mask>>chandepth;
if (mask == 0)
{
mask = startmask;
index16++;
}
}
}
}
free ((unsigned char *) tilebuf);
return 1;
}
/*
* FUNCTION
*
* imTiffReadPlaneInterleavedTiles
*
* DESCRIPTION
*
* Read the data in a tif file into a vfb, where the storage
* method is non-interleaved tiles.
*
*/
static int /* returns 1 for success, 0 for failure */
#ifdef __STDC__
imTiffReadPlaneInterleavedTiles ( TIFF *tif, ImVfb *vfb)
#else
imTiffReadPlaneInterleavedTiles ( tif, vfb)
TIFF* tif;
ImVfb* vfb;
#endif
{
uint16 numchans; /* number of channels */
uint16 chandepth; /* Depth of each channel */
char message[200]; /* Buffer for messages */
uint32 tileWidth, tileLength; /* size of tiles */
uint32 imageWidth, imageLength;/* size of image */
tsize_t tileSize; /* # of bytes per tile */
/*
* Go through the vfb once for each channel.
* Call the appropriate read function for each channel.
*/
/*
* Get the number of channels and channel depth from tiff
*/
TIFFGetFieldDefaulted(tif, TIFFTAG_SAMPLESPERPIXEL, &numchans);
TIFFGetFieldDefaulted(tif, TIFFTAG_BITSPERSAMPLE, &chandepth);
tileSize = TIFFTileSize(tif);
TIFFGetField(tif, TIFFTAG_IMAGEWIDTH, &imageWidth );
TIFFGetField(tif, TIFFTAG_IMAGELENGTH, &imageLength);
TIFFGetField(tif, TIFFTAG_TILEWIDTH, &tileWidth );
TIFFGetField(tif, TIFFTAG_TILELENGTH, &tileLength );
switch (numchans)
{
case 1:
/*
* It is silly to have one plane, and call it plane
* interleaved. This is non-interleaved. Hence, just
* call the read-non-intereleaved-tiles function.
* (which allows for varying channel depths)
*/
imTiffReadNonInterleavedTiles(tif, vfb);
break;
case 3:
if (chandepth!=8)
{
sprintf(message,"Can't read %d bits per channel plane-interleaved, tiled images\n",chandepth);
ImErrorFatal(message,0,IMEUNSUPPORTED);
}
imTiffReadRedTiledPlane (tif, vfb, tileWidth, tileLength, imageWidth, imageLength, tileSize);
imTiffReadGreenTiledPlane(tif, vfb, tileWidth, tileLength, imageWidth, imageLength, tileSize);
imTiffReadBlueTiledPlane (tif, vfb, tileWidth, tileLength, imageWidth, imageLength, tileSize);
break;
case 4:
if (chandepth!=8)
{
sprintf(message,"Can't read %d bits per channel plane-interleaved, tiled images\n",chandepth);
ImErrorFatal(message,0,IMEUNSUPPORTED);
}
imTiffReadRedTiledPlane (tif, vfb, tileWidth, tileLength, imageWidth, imageLength, tileSize);
imTiffReadGreenTiledPlane(tif, vfb, tileWidth, tileLength, imageWidth, imageLength, tileSize);
imTiffReadBlueTiledPlane (tif, vfb, tileWidth, tileLength, imageWidth, imageLength, tileSize);
imTiffReadAlphaTiledPlane(tif, vfb, tileWidth, tileLength, imageWidth, imageLength, tileSize);
break;
default :
sprintf(message,"Can't read %d channels plane-interleaved\n",numchans);
ImErrorFatal(message,0,IMEUNSUPPORTED);
}
return 1;
}
static int /* Returns # of tags written */
#ifdef __STDC__
imTiffWrite( ImFileFormatWriteMap *pMap, int ioType, int fd, FILE *fp, TagTable *flagsTable, TagTable *tagTable )
#else
imTiffWrite( pMap, ioType, fd, fp, flagsTable, tagTable )
ImFileFormatWriteMap *pMap; /* Write map entry to adhear to */
int ioType; /* I/O flags */
int fd; /* Output file descriptor */
FILE *fp; /* Output file pointer */
TagTable *flagsTable; /* Format flags */
TagTable *tagTable; /* Tag list to add to */
#endif
{
TIFF* tif; /* TIFF structure */
char message[200]; /* buffer for messages. */
ImVfb* vfb; /* Holds a vfb */
ImClt* clt; /* Holds a clt */
char *filename; /* Holds file name */
int curImage; /* index for the current image */
int numImages; /* number of images in the vfb */
TagEntry* entry; /* entry in table with file name */
/*
* Open our tif structure for writing.
*/
if (ioType & IMFILEIOFP)
{
fd = fileno(fp);
}
/* Search flags table for filename */
if (!flagsTable || TagTableQNEntry (flagsTable, "file name") == 0)
{
filename = NULL;
}
else
{
entry = TagTableQDirect ( flagsTable, "file name", 0 );
if (TagEntryQValue( entry, &filename) == -1)
filename = NULL;
}
tif = TIFFFdOpen(fd, filename ? filename : "libtiff", "wb");
if (!tif)
{
ImErrorFatal("Could not write to output file", -1, IMENOTPOSSIBLE);
}
/*
* Loop through images in vfb
*/
numImages = TagTableQNEntry( tagTable, "image vfb");
for (curImage = 0; curImage < numImages; curImage++)
{
/* Retreieve this vfb from the table */
TagEntryQValue (TagTableQDirect (tagTable, "image vfb", curImage), &vfb);
if (numImages > 1)
{
sprintf (message,"%d of %d", curImage + 1, numImages);
ImInfo ( "Image", message );
}
/*
* Set resolution
*/
sprintf(message,"%d x %d",ImVfbQWidth(vfb),ImVfbQHeight(vfb));
ImInfo( "Resolution", message );
TIFFSetField(tif, TIFFTAG_IMAGEWIDTH, ImVfbQWidth(vfb) );
TIFFSetField(tif, TIFFTAG_IMAGELENGTH, ImVfbQHeight(vfb) );
/*
* Set orientation
*/
TIFFSetField (tif,TIFFTAG_ORIENTATION, ORIENTATION_TOPLEFT);
/*
* Set min, max values.
*/
TIFFSetField (tif, TIFFTAG_MINSAMPLEVALUE, 0 );
TIFFSetField (tif, TIFFTAG_MAXSAMPLEVALUE, ((1L)<<(pMap->map_outChannelDepth)) - 1L);
/*
* Set byte order
*/
if ( BinQMachine()->bin_byteOrder == BINLBF)
{
TIFFSetField(tif, TIFFTAG_FILLORDER,FILLORDER_LSB2MSB);
ImInfo ("Byte Order", "Least Significant Byte First");
}
else
{
TIFFSetField(tif, TIFFTAG_FILLORDER,FILLORDER_MSB2LSB);
ImInfo ("Byte Order", "Most Significant Byte First");
}
/*
* Set image type
*/
if (pMap->map_outAttributes & IMALPHAYES || (ImVfbQFields(vfb) & IMVFBALPHA))
sprintf(message,"%d-bit ",pMap->map_outChannelDepth * ( pMap->map_outNChannels + 1)) ;
else
sprintf(message,"%d-bit ",pMap->map_outChannelDepth * pMap->map_outNChannels) ;
if (pMap->map_outType == IMTYPERGB || (ImVfbQFields(vfb) & IMVFBRGB) )
{
strcat(message,"RGB");
TIFFSetField(tif,TIFFTAG_PHOTOMETRIC,PHOTOMETRIC_RGB);
}
else
{
strcat(message,"Color Indexed");
/*
* Is this a color-indexed image or a mono image or a greyscale image?
*/
if (ImVfbQClt(vfb) != IMCLTNULL)
TIFFSetField(tif,TIFFTAG_PHOTOMETRIC,PHOTOMETRIC_PALETTE);
else /* mono or grayscale. Treat them the same. */
TIFFSetField(tif,TIFFTAG_PHOTOMETRIC,PHOTOMETRIC_MINISBLACK);
}
ImInfo ("Type",message);
TIFFSetField (tif, TIFFTAG_BITSPERSAMPLE ,pMap->map_outChannelDepth);
/*
* Set alpha channel if one exists
*/
if (pMap->map_outAttributes & IMALPHAYES || (ImVfbQFields(vfb) & IMVFBALPHA))
{
uint16 fields[2];
fields[0] = EXTRASAMPLE_ASSOCALPHA;
sprintf(message,"%d-bit",pMap->map_outChannelDepth);
ImInfo ("Alpha Channel", message);
TIFFSetField (tif, TIFFTAG_SAMPLESPERPIXEL ,pMap->map_outNChannels + 1);
TIFFSetField (tif, TIFFTAG_EXTRASAMPLES, 1, fields );
}
else
{
ImInfo ("Alpha Channel", "none");
TIFFSetField (tif, TIFFTAG_SAMPLESPERPIXEL ,pMap->map_outNChannels);
}
/*
* Set Interleave method
*/
if (pMap->map_outAttributes & IMINTERPLANE)
{
ImInfo ("Interleave method","Plane Interleaved");
TIFFSetField (tif,TIFFTAG_PLANARCONFIG, PLANARCONFIG_SEPARATE );
}
else
{
ImInfo ("Interleave Method","Non-interleaved");
TIFFSetField (tif,TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG );
}
/*
* Set Color Table
*/
if (pMap->map_outAttributes & IMCLTYES || (ImVfbQClt(vfb) != IMCLTNULL) )
{
sprintf(message,"%d entries",(1L)<<pMap->map_outChannelDepth);
clt = ImVfbQClt(vfb);
if (clt==NULL)
{
ImErrorFatal("No color table for image",0,IMENOCLT);
}
imTiffWriteClt (tif, clt , (1L)<<pMap->map_outChannelDepth);
}
else
{
sprintf(message,"none");
}
ImInfo ("Color Table", message);
/*
* Set Compression scheme
*/
switch (pMap->map_outAttributes & IMCOMPMASK)
{
case IMCOMPPACKBITS :
ImInfo ("Compression Type","Macintosh PackBits encoding");
TIFFSetField(tif, TIFFTAG_COMPRESSION, COMPRESSION_PACKBITS);
break;
case IMCOMPLZW :
ImInfo ("Compression Type", "Lempel-Ziv & Welch encoding");
TIFFSetField(tif, TIFFTAG_COMPRESSION, COMPRESSION_LZW);
break;
case IMCOMPDCT :
ImInfo ("Compression Type", "JPEG encoding (DCT)");
TIFFSetField(tif, TIFFTAG_COMPRESSION, COMPRESSION_JPEG);
break;
case IMCOMPNO :
ImInfo ("Compression Type", "none");
TIFFSetField(tif, TIFFTAG_COMPRESSION, COMPRESSION_NONE);
break;
}
/*
* Set Grouping method
*/
if ( (pMap->map_outAttributes & IMGROUPMASK) == IMGROUPTILES)
{
ImInfo ("Grouping Method", "Tiles");
/* Determine interleaving method and call the correct routine. */
if ( pMap->map_outAttributes & IMINTERPLANE )
{
imTiffWritePlaneInterleavedTiles(tif,vfb, pMap);
}
else
{
imTiffWriteNonInterleavedTiles(tif, vfb, pMap);
}
}
else /* store as scanlines */
{
ImInfo ("Grouping Method", "Scanlines");
/* Determine interleaving method and call the correct routine. */
if ( pMap->map_outAttributes & IMINTERPLANE )
{
imTiffWritePlaneInterleavedScanlines(tif,vfb, pMap);
}
else
{
imTiffWriteNonInterleavedScanlines(tif, vfb, pMap);
}
}
/*
* Write the directory to prepare for the next vfb
*/
TIFFWriteDirectory(tif);
} /* End of for loop */
TIFFClose (tif);
return numImages;
}
/*
*
* FUNCTION
*
* imTiffWriteNonInterleavedScanlines
*
* DESCRIPTION
*
* Write a tiff file with the pixels noninterleaved,
* and grouping by scanlines.
*
*/
static int /* Returns 1 for okay, 0 for failure */
#ifdef __STDC__
imTiffWriteNonInterleavedScanlines( TIFF* tif, ImVfb* vfb, ImFileFormatWriteMap* pMap)
#else
imTiffWriteNonInterleavedScanlines( tif, vfb, pMap)
TIFF* tif;
ImVfb* vfb;
ImFileFormatWriteMap *pMap;
#endif
{
unsigned char* linebuf; /* buffer for one scanline */
uint16* ptr16; /* pointer to the scanline as a 16-bit array */
tsize_t scanlineSize; /* size of scanlines */
ImVfbPtr vfbptr; /* ptr into a vfb */
uint32 x,y; /* Loop indices */
uint32 ySize; /* Image size (y) */
uint32 xSize; /* Image size (x) */
uint16 numchans; /* number of channels */
uint16 chandepth; /* number of bits per channel */
uint16 currentValue; /* value of current channel of current pixel */
int chanIndex; /* which channel is being set */
int chanList[5]; /* List of channels to cycle through */
uint16 photometric; /* Tells us the type of image this is. */
int currentShift; /* How many bits to shift this sample */
char message[200]; /* Buffer for error messages */
uint16 lastBits; /* Contains the chandepth bits of data */
/*
* Determine some important things about the vfb
*/
chandepth = pMap->map_outChannelDepth;
numchans = pMap->map_outNChannels;
xSize = ImVfbQWidth (vfb);
ySize = ImVfbQHeight(vfb);
if (ImVfbQFields(vfb) & IMVFBALPHA)
numchans++;
/*
* Set Rows per strip to "infinite"
*/
TIFFSetField (tif, TIFFTAG_ROWSPERSTRIP, (uint32) -1);
/* Allocate space for the scanline buffer */
scanlineSize = xSize * numchans * chandepth / 8 + 2;
ImMalloc(linebuf, unsigned char *, scanlineSize );
/*
* Set up the list of channels through which we are going to cycle.
*/
switch (numchans)
{
case 1 :
if (chandepth==16)
chanList[0] = IMVFBINDEX16;
else
chanList[0] = IMVFBINDEX8;
break;
case 3 :
chanList[0] = IMVFBRED;
chanList[1] = IMVFBGREEN;
chanList[2] = IMVFBBLUE;
break;
case 4 :
chanList[0] = IMVFBRED;
chanList[1] = IMVFBGREEN;
chanList[2] = IMVFBBLUE;
chanList[3] = IMVFBALPHA;
break;
default :
sprintf(message,"No support for %d channels in an image. Skipping image",numchans);
ImErrorWarning(message,0,IMEUNSUPPORTED);
break;
} /* end of switch */
/*
* Algorithm for writing non-interleaved scanlines:
*
* Loop through the pixels in the file, and for
* each channel of each pixel, query the value, and
* store it in a scanline buffer.
*
* Note that if we are writing less than 8-bits per channel,
* then we need to do some bit shifting and |'ing to place
* the data from the vfb in the correct place.
*
* Admittedly, having a switch statement within the loop that
* writes pixels will slow down processing time, but this enables
* us to handle a wider variety of formats.
*
*/
for (y=0; y< ySize ; y++)
{
/* Write Scanline #y */
ptr16 = (uint16 *) linebuf;
x = 0;
vfbptr = ImVfbQPtr( vfb, 0, y);
chanIndex = 0;
currentShift = 0;
/* Clear the first entry in the array */
*ptr16 = (uint16) 0;
/* Fill up linebuf with information from the vfb */
while (x < xSize)
{
/*
* Get current data from VFB
*/
IM_QCHANNEL (currentValue, chanList[chanIndex])
/*
* Store the last chandepth bits of currentValue
* in the first chandepth bits of lastBits.
*/
lastBits = (currentValue << (16 - chandepth)) ;
/*
* Shift the value by currentShift (to the right) and bit-or it
* with *ptr16 (ptr16 is traversing the scanline in 16-bit increments)
*/
*ptr16 = (*ptr16) | (lastBits >> currentShift);
/*
* Increment the channel index. This signifies which aspect
* of the pixel we will query next.
*/
chanIndex++;
if (chanIndex == numchans)
{ /* We're done with this pixel */
ImVfbSNext(vfb, vfbptr);
chanIndex = 0;
x++;
}
/* Increment currentShift. If we get a number bigger than 16,
* increment ptr16.
*/
currentShift += chandepth;
if (currentShift >= 16)
{
ptr16++;
currentShift = 0;
/* Clear the next entry in the array */
*ptr16 = (uint16) 0;
}
} /* end of while x < xSize */
if ( BinQMachine()->bin_byteOrder == BINLBF)
imTiffSwapBytes(linebuf, scanlineSize);
/* Okay, now write the scanline to the tiff file. */
if (TIFFWriteScanline( tif, linebuf, y, 0)==-1)
{
ImErrorFatal("Error writing scanline",0,IMESYS);
}
} /* end of for y = 0 to ySize */
return 1;
}
/*
*
* FUNCTION
*
* imTiffWritePlaneInterleavedScanlines
*
* DESCRIPTION
*
* Write a tiff file, plane-interleaving the pixels,
* and using scanlines.
*
*/
static int /* Returns 1 for okay, 0 for failure */
#ifdef __STDC__
imTiffWritePlaneInterleavedScanlines( TIFF *tif, ImVfb* vfb, ImFileFormatWriteMap* pMap)
#else
imTiffWritePlaneInterleavedScanlines( tif, vfb, pMap)
TIFF* tif;
ImVfb* vfb;
ImFileFormatWriteMap* pMap;
#endif
{
char message[300]; /* Buffer for error message */
uint16 numchans; /* number of channels */
uint16 chandepth; /* number of bits per channel */
/*
* Algorithm :
*
* This is basically just like writing non-interleaved scanlines,
* once for each channel. So this routine does just that.
* It calls the functions :
* imTiffWriteRedScanlinePlane, imTiffWriteGreenScanlinePlane
* imTiffWriteBlueScanlinePlane, imTiffWriteAlphaScanlinePlane
*
* Each of those functions simply acts like
* imTiffWriteNonInterleavedScanlines
* except that it only writes one channel.
*
*/
/*
* Determine depth and number of channels
*/
chandepth = pMap->map_outChannelDepth;
numchans = pMap->map_outNChannels;
if (ImVfbQFields(vfb) & IMVFBALPHA)
numchans++;
/*
* Set Rows per strip to "infinite"
*/
TIFFSetField (tif, TIFFTAG_ROWSPERSTRIP, (uint32) -1);
switch (numchans)
{
case 1:
if (ImVfbQFields(vfb) & IMVFBINDEX16)
imTiffWriteIndex16ScanlinePlane(vfb, tif, chandepth);
else
imTiffWriteIndex8ScanlinePlane(vfb, tif, chandepth);
break;
case 3:
imTiffWriteRedScanlinePlane (vfb, tif, chandepth);
imTiffWriteGreenScanlinePlane(vfb, tif, chandepth);
imTiffWriteBlueScanlinePlane (vfb, tif, chandepth);
break;
case 4:
imTiffWriteRedScanlinePlane (vfb, tif, chandepth);
imTiffWriteGreenScanlinePlane(vfb, tif, chandepth);
imTiffWriteBlueScanlinePlane (vfb, tif, chandepth);
imTiffWriteAlphaScanlinePlane(vfb, tif, chandepth);
break;
default:
sprintf(message,"Can't handle %d channels plane-interleaved scanlines\n", numchans);
ImErrorFatal(message,0,IMEUNSUPPORTED);
}
return 1;
}
/*
*
* FUNCTION
*
* imTiffWriteNonInterleavedTiles
*
* DESCRIPTION
*
* Write a tiff file, using tiles, and not interleaving
* the pixels.
*
*/
static int /* Returns 1 for okay, 0 for failure */
#ifdef __STDC__
imTiffWriteNonInterleavedTiles (TIFF *tif, ImVfb *vfb, ImFileFormatWriteMap* pMap)
#else
imTiffWriteNonInterleavedTiles (tif, vfb, pMap)
TIFF* tif;
ImVfb* vfb;
ImFileFormatWriteMap* pMap;
#endif
{
uint32 vfbX, vfbY; /* loop indexes */
unsigned char* tilebuf; /* buffer for tiles */
ImVfbPtr vfbptr; /* pointer into a vfb */
int vfbwidth, vfbheight; /* dimensions of the vfb */
int tileindex; /* index into tilebuf */
int x,y; /* indexes within a tile */
uint16 numchans; /* number of channels */
uint16 chandepth; /* channel depth */
uint32 tileWidth, tileHeight; /* size of tiles */
char message[120]; /* buffer for error messages */
/*
* Discern the number of channels and channel depth
*/
numchans = pMap->map_outNChannels;
if (ImVfbQFields(vfb) & IMVFBALPHA)
numchans++;
chandepth = pMap->map_outChannelDepth;
if (chandepth!=8)
{
sprintf(message,"No support non-interleaved tiles with depth %d",chandepth);
ImErrorWarning(message,0,IMEUNSUPPORTED);
}
/* Let's just make the tiles 16 by 16 (the dimensions must be multiples of 16) */
tileWidth = (uint32) 16;
tileHeight = (uint32) 16;
TIFFSetField (tif, TIFFTAG_TILEWIDTH, tileWidth);
TIFFSetField (tif, TIFFTAG_TILELENGTH, tileHeight);
/*
* if only one plane then this is equivalent to writing plane
* interleaved tiles
*/
if (numchans==1)
{
return imTiffWriteIndex8TiledPlane(vfb, tif, chandepth, tileWidth, tileHeight);
}
/* Determine vfb dimensions */
vfbwidth = ImVfbQWidth(vfb);
vfbheight = ImVfbQHeight(vfb);
/*
* Allocate space for tilebuf
*/
ImMalloc(tilebuf, unsigned char *, (int) (tileWidth * tileHeight * numchans) + 1 );
/*
* Loop through tile positions and create either an RGB or an RGBA image
*/
for (vfbX=0; vfbX<vfbwidth; vfbX+=tileWidth)
{
for (vfbY=0; vfbY<vfbheight; vfbY+=tileHeight)
{
/*
* Create a tile at vfbX, vfbY
*/
vfbptr = ImVfbQPtr(vfb, vfbX, vfbY);
tileindex = 0;
/*
* start x,y at the upper left hand corner
* of the tile
*/
x = 0;
y = 0;
while ( y < (int) tileHeight && vfbY + y < vfbheight )
{
/*
* If we're past the right edge of the image,
* put in a dummy value (i.e. pad the image)
*/
if (vfbX + x >= vfbwidth)
{
tilebuf[tileindex++] = (unsigned char) 0;
tilebuf[tileindex++] = (unsigned char) 0;
tilebuf[tileindex++] = (unsigned char) 0;
if (numchans==4)
tilebuf[tileindex++] = (unsigned char) 0;
}
else /* put in the real values */
{
tilebuf[tileindex++] = ImVfbQRed(vfb,vfbptr);
tilebuf[tileindex++] = ImVfbQGreen(vfb,vfbptr);
tilebuf[tileindex++] = ImVfbQBlue(vfb,vfbptr);
if (numchans==4)
tilebuf[tileindex++] = ImVfbQAlpha(vfb,vfbptr);
}
/* Increment index within tile */
x++;
/*
* if we're at the end of the tile
* move down one line
* and back to the start of the
* tile.
*/
if ( x >= (int) tileWidth )
{
y++;
if (vfbY + y < vfbheight)
vfbptr = ImVfbQPtr(vfb, vfbX, vfbY + y);
x = 0;
}
else /* just move to the right */
{
if (vfbY + y < vfbheight)
vfbptr = ImVfbQRight(vfb,vfbptr);
}
}
/* Send out tile to tiff */
if ( BinQMachine()->bin_byteOrder == BINLBF)
imTiffSwapBytes(tilebuf, tileWidth * tileHeight * numchans);
TIFFWriteTile(tif, tilebuf, (uint32) vfbX, (uint32) vfbY, 0, 0);
}
}
return 1;
}
/*
*
* FUNCTION
*
* imTiffWritePlaneInterleavedTiles
*
* DESCRIPTION
*
* Write a tiff file, using plane-interleaving and
* tiles.
*
*/
static int /* Returns 1 for okay, 0 for failure */
#ifdef __STDC__
imTiffWritePlaneInterleavedTiles ( TIFF *tif, ImVfb *vfb, ImFileFormatWriteMap* pMap)
#else
imTiffWritePlaneInterleavedTiles ( tif, vfb, pMap)
TIFF* tif;
ImVfb* vfb;
ImFileFormatWriteMap* pMap;
#endif
{
uint16 numchans; /* number of channels */
uint16 chandepth; /* number of bits per channel */
uint32 tileWidth; /* width of tiles */
uint32 tileHeight; /* height of tiles */
char message[100]; /* buffer for messages */
int numTiles; /* Number of tiles in the image*/
/*
* For each plane in the image, call a function to write
* the plane to the tiff structure
*/
chandepth = pMap->map_outChannelDepth;
numchans = pMap->map_outNChannels;
if (ImVfbQFields(vfb) & IMVFBALPHA)
numchans++;
/*
* No support for depths other than 8 at this point in time
*/
if (chandepth!=8)
{
sprintf(message,"Can't write %d depth tiled images",chandepth);
ImErrorFatal(message,0,IMEUNSUPPORTED);
}
/*
* Let's make the tiles 16 x 16.
* If anyone ever wants to change this, just be sure
* that the dimensions are multiples of 16 (as per
* tiff's standards). Or maybe multiples of 8. TIFF
* has some contradictions in their standards. The man
* pages for TIFFSetField say 8. The README file says 16.
*
*/
tileWidth = (uint32) 16;
tileHeight = (uint32) 16;
TIFFSetField (tif, TIFFTAG_TILEWIDTH, tileWidth);
TIFFSetField (tif, TIFFTAG_TILELENGTH, tileHeight);
switch (numchans)
{
case 1:
imTiffWriteIndex8TiledPlane(vfb, tif, chandepth, tileWidth, tileHeight);
break;
case 3:
imTiffWriteRedTiledPlane (vfb, tif, chandepth, tileWidth, tileHeight);
imTiffWriteGreenTiledPlane(vfb, tif, chandepth, tileWidth, tileHeight);
imTiffWriteBlueTiledPlane (vfb, tif, chandepth, tileWidth, tileHeight);
break;
case 4:
imTiffWriteRedTiledPlane (vfb, tif, chandepth, tileWidth, tileHeight);
imTiffWriteGreenTiledPlane(vfb, tif, chandepth, tileWidth, tileHeight);
imTiffWriteBlueTiledPlane (vfb, tif, chandepth, tileWidth, tileHeight);
imTiffWriteAlphaTiledPlane(vfb, tif, chandepth, tileWidth, tileHeight);
break;
default:
sprintf(message,"Can't handle %d channels plane-interleaved tiles\n", numchans);
ImErrorFatal(message,0,IMEUNSUPPORTED);
}
return 1;
}
/*
*
* FUNCTION
*
* imTiffWriteClt
*
* DESCRIPTION
*
* Write the clt for an image to a file.
*
*/
static
int /* Returns 1 for okay, 0 for failure */
#ifdef __STDC__
imTiffWriteClt(TIFF* tif, ImClt *clt, long numEntries)
#else
imTiffWriteClt(tif, clt, numEntries)
TIFF* tif;
ImClt* clt;
long numEntries;
#endif
{
uint16* redmap; /* Stores red components for color map entries */
uint16* bluemap; /* Stores blue components for color map entries */
uint16* greenmap; /* Stores green components for color map entries */
ImCltPtr cltptr; /* pointer into the clt */
long i; /* loop index */
long realNumEntries; /* minimum of desired and actual no. of entries */
/* Allocate space for arrays which are passed to tif structure */
ImMalloc(redmap , uint16* , numEntries * sizeof(uint16) );
ImMalloc(bluemap , uint16* , numEntries * sizeof(uint16));
ImMalloc(greenmap, uint16* , numEntries * sizeof(uint16));
/* Do we really have numEntries entries in the clt? Or are there fewer? */
realNumEntries = numEntries;
if (ImCltQNColors(clt)<realNumEntries)
realNumEntries = ImCltQNColors(clt);
/* Read entries from clt and put them into tif. */
cltptr = ImCltQFirst(clt);
i = (long) 0;
while (i < realNumEntries)
{
redmap[i] = (uint16) ImCltQRed(cltptr);
bluemap[i] = (uint16) ImCltQBlue(cltptr);
greenmap[i] = (uint16) ImCltQGreen(cltptr);
i++;
cltptr = ImCltQNext(clt, cltptr);
}
/*
* Scale colormap to TIFF-required 16-bit values.
*/
#define IM_CLTSCALE(x) (((x)*((1L<<16)-1))/255)
for (i = (long) 0; i < realNumEntries; i++)
{
redmap[i] = IM_CLTSCALE(redmap[i]);
greenmap[i] = IM_CLTSCALE(greenmap[i]);
bluemap[i] = IM_CLTSCALE(bluemap[i]);
}
/* Write the map to the tiff structure */
TIFFSetField(tif, TIFFTAG_COLORMAP, redmap, greenmap, bluemap);
free(redmap);
free(greenmap);
free(bluemap);
return 1;
}
/*
* FUNCTIONS
* imTiffWriteRedScanlinePlane
* imTiffWriteBlueScanlinePlane
* imTiffWriteGreenScanlinePlane
* imTiffWriteIndex8ScanlinePlane
* imTiffWriteAlphaScanlinePlane
* imTiffWriteIndex16ScanlinePlane
*
* DESCRIPTION
* Go through the entire vfb, and write a series of
* scanlines to the tiff structure.
*
*/
#ifdef __STDC__
#define FunctionHeaderSPW(functionName) \
static int functionName(ImVfb *vfb, TIFF *tif, uint16 chandepth)
#else
#define FunctionHeaderSPW(functionName) \
static int functionName(vfb, tif, chandepth) \
ImVfb* vfb; \
TIFF* tif; \
uint16 chandepth;
#endif
#define IM_MAKE_SCANLINE_PLANE_WRITE_FUNCTION(functionName, ImVfbQSomething, imagePlane) \
\
FunctionHeaderSPW(functionName) \
{ \
unsigned char* linebuf; /* buffer for one scanline */ \
tsize_t scanlineSize; /* size of a scanline */ \
uint16* ptr16; /* pointer to a 16-bit value */ \
ImVfbPtr vfbptr; /* ptr into a vfb */ \
uint32 x,y; /* Loop indices */ \
uint32 ySize; /* Image size (y) */ \
uint32 xSize; /* Image size (x) */ \
uint16 currentValue; /* value of current channel of current pixel */ \
int currentShift; /* How many bits to shift this sample */ \
uint16 lastBits; /* Contains chandepth bits of data */ \
\
/* \
* Determine some important things about the vfb \
*/ \
\
xSize = ImVfbQWidth (vfb); \
ySize = ImVfbQHeight(vfb); \
\
/* Allocate space for the scanline buffer */ \
\
scanlineSize = xSize * chandepth / 8 + 2; \
ImMalloc(linebuf,unsigned char *, scanlineSize); \
\
/* \
* Note that if we are writing less than 8-bits per channel, \
* then we need to do some bit shifting and |'ing to place \
* the data from the vfb in the correct place. \
* \
* I won't explain it all here. \
* See imTiffWriteNonInterleavedScanlines for more comments. \
* \
*/ \
\
for (y=0; y< ySize ; y++) \
{ \
\
/* Write Scanline #y */ \
\
ptr16 = (uint16 *) linebuf; \
vfbptr = ImVfbQPtr( vfb, 0, y); \
currentShift = 0; \
\
/* Clear the first entry in the array */ \
\
*ptr16 = (uint16) 0; \
\
/* Fill up linebuf with information from the vfb */ \
\
for (x=0;x < xSize; x++) \
{ \
currentValue = (uint16) ImVfbQSomething(vfb,vfbptr); \
lastBits = (currentValue << (16 - chandepth)) ; \
*ptr16 = (*ptr16) | (lastBits >> currentShift); \
currentShift += chandepth; \
if (currentShift >= 16) \
{ \
ptr16++; \
currentShift = 0; \
/* Clear the next entry in the array */ \
*ptr16 = (uint16) 0; \
} \
\
ImVfbSNext(vfb, vfbptr); \
} \
\
if ( BinQMachine()->bin_byteOrder == BINLBF) \
imTiffSwapBytes(linebuf, scanlineSize); \
\
/* Okay, now write the scanline to the tiff file. */ \
if (TIFFWriteScanline( tif, linebuf, y, imagePlane)==-1) \
{ \
ImErrorFatal("Error writing scanline",0,IMESYS); \
} \
\
} /* end of for y = 0 to ySize */ \
\
return 1; \
\
}
IM_MAKE_SCANLINE_PLANE_WRITE_FUNCTION(imTiffWriteRedScanlinePlane,ImVfbQRed, 0)
IM_MAKE_SCANLINE_PLANE_WRITE_FUNCTION(imTiffWriteGreenScanlinePlane,ImVfbQGreen, 1)
IM_MAKE_SCANLINE_PLANE_WRITE_FUNCTION(imTiffWriteBlueScanlinePlane,ImVfbQBlue, 2)
IM_MAKE_SCANLINE_PLANE_WRITE_FUNCTION(imTiffWriteAlphaScanlinePlane,ImVfbQAlpha, 3)
IM_MAKE_SCANLINE_PLANE_WRITE_FUNCTION(imTiffWriteIndex8ScanlinePlane,ImVfbQIndex8, 0)
IM_MAKE_SCANLINE_PLANE_WRITE_FUNCTION(imTiffWriteIndex16ScanlinePlane,ImVfbQIndex16, 0)
/*
* FUNCTION
* imTiffReadRedScanlinePlane
* imTiffReadGreenScanlinePlane
* imTiffReadBlueScanlinePlane
*
* DESCRIPTION
* Read the plane into the vfb.
* This routine only works for 8-bit images.
*
*/
#ifdef __STDC__
#define FunctionHeaderSPR(functionName) \
static int \
functionName(TIFF* tif, ImVfb* vfb)
#else
#define FunctionHeaderSPR(functionName) \
static int \
functionName(tif,vfb) \
TIFF* tif; \
ImVfb* vfb;
#endif
#define IM_MAKE_SCANLINE_PLANE_READ_FUNCTION(functionName,ImVfbSSomething,imagePlane) \
FunctionHeaderSPR(functionName) \
{ \
unsigned char* linebuf; /* buffer for one scanline */ \
tsize_t scanlineSize; /* size of scanlines */ \
ImVfbPtr vfbptr; /* ptr into a vfb */ \
uint32 row, col; /* Loop indices */ \
uint32 ySize; /* Image size (y) */ \
\
TIFFGetField( tif, TIFFTAG_IMAGELENGTH, &ySize); \
scanlineSize = TIFFScanlineSize(tif); \
ImMalloc(linebuf,unsigned char *,scanlineSize); \
vfbptr = ImVfbQPtr(vfb, 0, 0); \
for (row=0; row<ySize; row++) \
{ \
if (TIFFReadScanline(tif, linebuf, row, imagePlane) < 0) \
break; \
for (col=0;col<scanlineSize;col++) \
{ \
ImVfbSSomething(vfb, vfbptr, linebuf[col]); \
ImVfbSNext(vfb, vfbptr); \
} \
} \
free(linebuf); \
return 1; \
}
IM_MAKE_SCANLINE_PLANE_READ_FUNCTION(imTiffReadRedScanlinePlane, ImVfbSRed, 0)
IM_MAKE_SCANLINE_PLANE_READ_FUNCTION(imTiffReadGreenScanlinePlane, ImVfbSGreen, 1)
IM_MAKE_SCANLINE_PLANE_READ_FUNCTION(imTiffReadBlueScanlinePlane, ImVfbSBlue, 2)
IM_MAKE_SCANLINE_PLANE_READ_FUNCTION(imTiffReadAlphaScanlinePlane, ImVfbSAlpha, 3)
/*
*
* FUNCTION
* imTiffWriteRedTiledPlane
* imTiffWriteGreenTiledPlane
* imTiffWriteBlueTiledPlane
* imTiffWriteAlphaTiledPlane
* imTiffWriteIndex8TiledPlane
*
* DESCRIPTION
* Write the red,green, blue or alpha planes to the tiff
* structure, storing them in tiles.
* These functions only support 8 bits per channel.
*/
#ifdef __STDC__
#define functionHeaderTPWF(functionName) \
static int /* Returns 1 for success, 0 for failure */ \
functionName( ImVfb* vfb, TIFF* tif, uint16 chanDepth, uint32 tileWidth, uint32 tileHeight)
#else
#define functionHeaderTPWF(functionName) \
static int /* Returns 1 for success, 0 for failure */ \
functionName( vfb, tif, chanDepth, tileWidth, tileHeight) \
ImVfb* vfb; \
TIFF* tif; \
uint16 chanDepth; \
uint32 tileWidth; \
uint32 tileHeight;
#endif
#define IM_MAKE_TIFF_TILE_PLANE_WRITE_FUNCTION(functionName,ImVfbQSomething,imagePlane) \
functionHeaderTPWF(functionName) \
{ \
uint32 vfbX, vfbY; /* loop indexes */ \
unsigned char* tilebuf; /* buffer for tiles */ \
ImVfbPtr vfbptr; /* pointer into a vfb */ \
int vfbwidth, vfbheight; /* dimensions of the vfb */ \
int tileindex; /* index into tilebuf */ \
int x,y; /* indexes within a tile */ \
\
vfbwidth = ImVfbQWidth(vfb); \
vfbheight = ImVfbQHeight(vfb); \
\
/* \
* Allocate space for tilebuf \
*/ \
ImMalloc(tilebuf, unsigned char *, (int) (tileWidth * tileHeight) + 1); \
\
/* \
* Loop through tile positions \
*/ \
\
for (vfbX=0; vfbX<vfbwidth; vfbX+=tileWidth) \
{ \
for (vfbY=0; vfbY<vfbheight; vfbY+=tileHeight) \
{ \
/* \
* Create a tile! \
*/ \
vfbptr = ImVfbQPtr(vfb, vfbX, vfbY); \
tileindex = 0; \
x = 0; \
y = 0; \
while ( y < (int) tileHeight && vfbY + y < vfbheight ) \
{ \
/* \
* If we're past the edge of the image, \
* put in a dummy value (i.e. pad the image) \
*/ \
\
if (vfbX + x >= vfbwidth) \
{ \
tilebuf[tileindex] = (unsigned char) 0; \
} \
else /* put in the real value */ \
{ \
tilebuf[tileindex] = ImVfbQSomething(vfb,vfbptr); \
} \
\
/* Increment index within tile */ \
x++; \
\
/* \
* if we're at the end of the tile \
* move down one line \
* and back to the start of the \
* tile. \
*/ \
if ( x >= (int) tileWidth ) \
{ \
y++; \
if (vfbY + y < vfbheight) \
vfbptr = ImVfbQPtr(vfb, vfbX, vfbY + y); \
x = 0; \
} \
else /* just move to the right */ \
{ \
if (vfbY + y < vfbheight) \
vfbptr = ImVfbQRight(vfb,vfbptr); \
} \
tileindex++; \
} \
/* Send out tile to tiff */ \
if ( BinQMachine()->bin_byteOrder == BINLBF) \
imTiffSwapBytes(tilebuf, tileWidth * tileHeight); \
TIFFWriteTile(tif, tilebuf, (uint32) vfbX, (uint32) vfbY, 0, imagePlane); \
} \
} \
return 1; \
}
IM_MAKE_TIFF_TILE_PLANE_WRITE_FUNCTION(imTiffWriteIndex8TiledPlane,ImVfbQIndex8,0)
IM_MAKE_TIFF_TILE_PLANE_WRITE_FUNCTION(imTiffWriteRedTiledPlane,ImVfbQRed,0)
IM_MAKE_TIFF_TILE_PLANE_WRITE_FUNCTION(imTiffWriteGreenTiledPlane,ImVfbQGreen,1)
IM_MAKE_TIFF_TILE_PLANE_WRITE_FUNCTION(imTiffWriteBlueTiledPlane,ImVfbQBlue,2)
IM_MAKE_TIFF_TILE_PLANE_WRITE_FUNCTION(imTiffWriteAlphaTiledPlane,ImVfbQAlpha,3)
/*
* FUNCTIONS
*
* imTiffReadIndex8TiledPlane
* imTiffReadRedTiledPlane
* imTiffReadGreenTiledPlane
* imTiffReadBlueTiledPlane
* imTiffReadAlphaTiledPlane
*
* DESCRIPTION
* Read this channel into the entire vfb, when the
* data is grouped in tiles.
*
*/
#ifdef __STDC__
#define functionHeaderRTPF(functionName) \
static int /* returns 1 for success, 0 for failure */ \
functionName( TIFF* tif, ImVfb* vfb, uint32 tileWidth, \
uint32 tileLength, uint32 imageWidth, uint32 imageLength, tsize_t tileSize)
#else
#define functionHeaderRTPF(functionName) \
static int /* returns 1 for success, 0 for failure */ \
functionName( tif, vfb, tileWidth,tileLength, imageWidth, imageLength, tileSize) \
TIFF* tif; \
ImVfb* vfb; \
uint32 tileWidth; \
uint32 tileLength; \
uint32 imageWidth; \
uint32 imageLength; \
tsize_t tileSize;
#endif
#define IM_TIFF_MAKE_READ_TILED_PLANE_FUNCTION(functionName, ImVfbSSomething, imagePlane) \
functionHeaderRTPF(functionName) \
{ \
ImVfbPtr vfbptr; /* Pointer into the vfb */ \
uint32 tileX, tileY; /* relative to the tile */ \
uint32 vfbX, vfbY; /* start of tile relative to vfb */ \
unsigned char* tilebuf;/* buffer for tile data */ \
int tileIndex; /* index within tilebuf */ \
\
/* Allocate space for tilebuf */ \
\
ImMalloc( tilebuf, unsigned char *, tileSize); \
\
for (vfbY = 0; vfbY < imageLength; vfbY += tileLength) \
{ \
for (vfbX = 0; vfbX < imageWidth; vfbX += tileWidth) \
{ \
TIFFReadTile( tif, tilebuf, vfbX, vfbY, 0, imagePlane); \
tileX = 0; \
tileY = 0; \
\
/* Move to upper left hand corner of this tile */ \
\
vfbptr = ImVfbQPtr( vfb, vfbX, vfbY); \
tileIndex = 0; \
\
/* Read this tile! */ \
\
while (tileIndex < tileSize) \
{ \
/* Only write to the vfb if we're within our boundaries */ \
\
if (vfbX + tileX < imageWidth && vfbY + tileY < imageLength) \
{ \
ImVfbSSomething (vfb, vfbptr, tilebuf[tileIndex]); \
ImVfbSRight (vfb, vfbptr); \
} \
tileX++; \
if (tileX >= tileWidth) \
{ \
/* move down a line and back to the left edge of the tile */ \
tileX = 0; \
tileY++; \
if (vfbY + tileY < imageLength) \
{ \
vfbptr = ImVfbQPtr (vfb, vfbX + 0, vfbY + tileY); \
} \
} \
tileIndex++; \
} \
} \
} \
return 1; \
}
IM_TIFF_MAKE_READ_TILED_PLANE_FUNCTION(imTiffReadRedTiledPlane, ImVfbSRed, 0)
IM_TIFF_MAKE_READ_TILED_PLANE_FUNCTION(imTiffReadGreenTiledPlane, ImVfbSGreen, 1)
IM_TIFF_MAKE_READ_TILED_PLANE_FUNCTION(imTiffReadBlueTiledPlane, ImVfbSBlue, 2)
IM_TIFF_MAKE_READ_TILED_PLANE_FUNCTION(imTiffReadAlphaTiledPlane, ImVfbSAlpha, 0)
/*
* FUNCTION
* imTiffSwapBytes
*
* DESCRIPTION
* Traverse a line and switch every pair of bytes
* An extra byte should be allocated when passing a buffer with
* an odd size to this routine.
*
*/
static void /* Returns nothing */
#ifdef __STDC__
imTiffSwapBytes(unsigned char* linebuf, tsize_t linesize)
#else
imTiffSwapBytes(linebuf, linesize)
unsigned char* linebuf;
tsize_t linesize;
#endif
{
int i; /* loop index */
unsigned char temp; /* temporary variable */
for (i=0;i<linesize;i+=2)
{
/* Swap linebuf[i] and linebuf[i+1] */
temp = linebuf[i];
linebuf[i] = linebuf[i+1];
linebuf[i+1] = temp;
}
}
#endif /* USE_TIFF_LIB */