/** ** $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 #include //#include #include #include #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; icnt; 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 \n"); y = imTiffWriteDir[IMTIFF_IMAGELENGTH_INDEX].tdir_offset >> 16; for( i=0; i ", *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 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; it_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 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>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 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<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)<map_outChannelDepth); clt = ImVfbQClt(vfb); if (clt==NULL) { ImErrorFatal("No color table for image",0,IMENOCLT); } imTiffWriteClt (tif, clt , (1L)<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) { 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)> 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= 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