/** $Header: /roq/libim/imras.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/imras.c 1 11/02/99 4:38p Zaphod $" /** ** FILE ** imras.c - Sun Rasterfile I/O ** ** PROJECT ** libim - SDSC image manipulation library ** ** DESCRIPTION ** imras.c contains routines to read and write Sun Rasterfiles 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. ** ** PUBLIC CONTENTS ** d =defined constant ** f =function ** m =defined macro ** t =typedef/struct/union ** v =variable ** ? =other ** ** none ** ** PRIVATE CONTENTS ** ** imRasRead f read a Sun Rasterfile ** imRasWrite1 f write 1-bit standard RAS format ** imRasWrite8 f write 8-bit standard RAS format ** imRasWriteRGB f write 24-bit RGB standard RAS format ** imRasWriteRGBA f write 32-bit RGBA standard RAS format ** imRasWriteRLE1 f write 1-bit encoded RAS format ** imRasWriteRLE8 f write 8-bit encoded RAS format ** imRasWriteRLERGB f write 24-bit RGB encoded RAS format ** imRasWriteRLERGBA f write 32-bit RGBA encoded RAS format ** ** imRasHeaderInfo t Rasterfile header information ** imRasHeaderFields v imRasHeaderInfo description for Bin pkg ** imRasHeader v Rasterfile header holder ** ** IMRASMAGIC d file magic number ** IMRASESC d escape code for run-length encoding ** IMRT* d raster encoding types ** IMRMT* d raster colormap encoding types ** ** IMRAS_RED,IMRAS_GREEN, ** IMRAS_BLUE,IMRAS_ALPHA d RGBA color cycle counter values ** ** imRasRead1 f read 1-bit RAS format ** imRasRead8 f read 8-bit standard RAS format ** imRasRead24RGB f read 24-bit RGB standard RAS format ** imRasRead32RGBA f read 32-bit RGBA standard RAS format ** imRasReadRLE1 f read 1-bit encoded RAS format ** imRasReadRLE8 f read 8-bit encoded RAS format ** imRasReadRLE24RGB f read 24-bit RGB encoded RAS format ** imRasReadRLE32RGBA f read 32-bit RGBA encoded RAS format ** ** imRasWriteHeaderClt f write header and CLT ** imRasCltToBuffer f convert CLT to file format buffer ** ** IMAddRun m add another pixel to RLE buffer ** IMDumpRun m dump an RLE run into the run buffer ** ** HISTORY ** $Log: /roq/libim/imras.c $ * * 1 11/02/99 4:38p Zaphod ** Revision 1.22 1995/06/29 00:28:04 bduggan ** updated copyright year ** ** Revision 1.21 1995/04/03 21:35:15 bduggan ** took out #ifdef NEWMAGIC ** ** Revision 1.20 1995/01/10 23:41:09 bduggan ** put in IMMULTI, IMPIPE instead of TRUE/FALSE ** made read/write routines static ** ** Revision 1.19 94/10/03 11:30:45 nadeau ** Fixed bug in RGB+Alpha handling that did incorrect scanling padding, ** causing corrupted images for some image widths. ** 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.18 92/12/03 01:51:39 nadeau ** Corrected info messages. ** ** Revision 1.17 92/11/23 18:43:05 nadeau ** Removed use of IMINFOMSG. ** ** Revision 1.16 92/11/04 12:06:10 groening ** put ImFIleFormat info and magic number info ** from imfmt.c into this file. ** ** Revision 1.15 92/09/29 17:57:38 vle ** Added ImInfo messages. ** ** Revision 1.14 92/08/31 17:33:39 vle ** Updated copyright notice. ** ** Revision 1.13 92/04/09 09:35:21 groening ** To make the compiler happy added extern statements. ** ** Revision 1.12 91/10/03 09:16:52 nadeau ** Reversed order from R-G-B to B-G-R on 24-bit image files. ** Added 32-bit image file read and write support. ** ** Revision 1.11 91/03/13 17:37:10 nadeau ** Fixed RGB ordering bug for RGB uncompressed read. ** ** Revision 1.10 91/02/12 10:44:47 nadeau ** Changed read and write routine names. Removed the top level ** write call and updated the VFB-specific write calls to be ** entry points from the generic ImFileWrite code. Encapsulated ** the run-length encoding into a few macros to reduce the ** apparent complexity of the RLE write routines. Removed the ** tag table error checking now handled by ImFileWrite. Removed ** temp file creation, now handled by ImFileWrite. ** ** Revision 1.9 91/01/30 18:10:04 nadeau ** Added monochrome support for read and write. ** ** Revision 1.8 90/12/03 12:51:14 nadeau ** Added checks to skip the extra pad byte on odd-length scanlines ** when reading RLE images. ** ** Revision 1.7 90/07/25 16:20:28 nadeau ** Documented the RAS format more fully. Changed image write to use ** a scratch file when writing to pipes. Fixed a byte padding problem ** on encoded images (and added description of problem to RAS comments). ** Removed stubs for 1-bit deep image read/write. ** ** Revision 1.6 90/07/23 13:49:04 nadeau ** Reversed order of channels on reading RGB images from BGR to RGB. ** ** Revision 1.5 90/07/02 13:21:43 nadeau ** Updated to the new error handling mechanism. ** ** Revision 1.4 90/06/25 14:39:01 nadeau ** Changed ImTag* to Tag* (new names). ** ** Revision 1.3 90/05/16 07:47:46 todd ** Add #include "ininternal.h" to top of file ** ** Revision 1.2 90/05/11 09:56:11 nadeau ** Totally restructured everything. Broke format variants into separate ** routines. For write, broke pipe vs file I/O into separate routines. ** Updated call interface and code to handle I/O on file descriptors nad ** file pointers. Finished 24-bit code. ** ** Revision 1.1 90/03/06 17:29:09 nadeau ** Initial revision ** **/ #include "iminternal.h" /** ** FORMAT ** RAS - Sun Rasterfile ** ** AKA ** sun, sr, scr ** ** FORMAT REFERENCES ** Graphics File Formats, David C. Kay, John R. Levine ** ** CODE CREDITS ** Custom development, Dave Nadeau, San Diego Supercomputer Center, 1990. ** ** DESCRIPTION ** Sun rasterfiles start with a fixed size header: ** ** magic The file's magic number. ** ** width The width of the image, in pixels. ** ** height The height of the image, in pixels. ** ** depth The depth of the image, in bits. ** ** length The total image storage size, in bytes. ** ** type The type of image encoding used. One of: ** ** Standard Unencoded (see below). ** ByteEncoded Run-length encoded (see below). ** ** mapType The type of CLT (if any). One of: ** ** None No CLT included. ** EqualRGB All red, then green, then blue ** Raw Unkown!!! ** ** mapLength The length of the CLT (if any), in bytes. ** ** Following the header is the CLT, stored as a string of red values, ** then green, then blue, for consecutive entries in the CLT. ** ** STANDARD FORMAT (unencoded) ** For standard (unencoded) images, consecutive bytes in the file ** correspond to consecutive pixels (or components of the pixel for ** RGB images). ** ** BYTE-ENCODING FORMAT (run-length encoded) ** The Sun rasterfile encodes the image byte stream by counting up ** adjacent identical bytes and flagging a count-index pair with an ** "escape" byte: ** ** ** The count is always biased by -1 (ie, count=1 means do a 2-byte run, ** count=2 means do a 3-byte run, and so on). The maximum run length ** is therefore 256. Runs always end on scanline boundaries. ** ** To include the "escape" byte in the image, give a count of 0, ** followed by no index: ** <0> ** ** To avoid expanding the storage size of images without any runs (like ** the ubiquitous Mandrill), just give the index by itself: ** ** ** The worst case scenario is an image filled with "escape" bytes. ** Each "escape" byte will be expanded into an <0> pair, ** thus doubling the size of the image file. ** ** The "escape" byte is an 0x80 (0200) (128). ** ** EXAMPLE #1 ** Unencoded 8-bit Index Stream: ** 0xAA 0xBB 0xBB 0xCC 0x80 0xDD 0xDD 0xDD ** ** Encoded Stream: ** 0xAA 0x80 0x01 0xBB 0xCC 0x80 0x00 0x80 0x02 0xDD ** ** There are two runs (2 * 0xBB, and 3 * 0xDD) and one occurrence of ** the escape byte. The encoded stream turns out to be 2 bytes larger ** than the unencoded one. ** ** ** EXAMPLE #2 ** Unencoded RGB Stream: ** 0x00 0x00 0x00 0x45 0x52 0x12 0x12 0x12 0x43 ** (blue) (green) (red) ... ** ** Encoded Stream: ** 0x80 0x02 0x00 0x45 0x52 0x80 0x02 0x12 0x43 ** ** There are two runs (3 * 0x0, and 3 * 0x12). The encoded stream comes ** out the same size as the unencoded one. Note that the 0x12 of the ** second RGB triplet, and the 0x12's of the third RGB triplet form a ** run of three 0x12's. ** ** ODDITIES ** Scanlines with an odd number of pixels must be padded with one dummy ** pixel. Note that the addition of a pad byte is based upon the scanline ** length... ** ** For 8-bit and 24-bit "standard" images, the pad byte makes ** each scanline's stream of bytes end on a 16-bit boundary. ** This is clearly the original intent of the padding. ** ** For 8-bit and 24-bit "encoded" images, the length of the ** scanline's encoded stream could be odd or even, depending upon ** the way runs are created from the data, not dependent upon the ** evenness or oddness of the original scanline length. ** Nevertheless, if the original scanline had an odd number of ** pixels in it, then a pad byte must be added, even if this ** makes the encoded stream have an odd number of bytes. ** ** For 32-bit images (with an alpha channel), there is no padding. **/ #ifdef __STDC__ static int imRasRead1(int ioType, int fd, FILE *fp, TagTable *flagsTable, TagTable *tagTable, ImVfb **pVfb ); static int imRasRead8( int ioType, int fd, FILE *fp, TagTable *flagsTable, TagTable *tagTable, ImVfb **pVfb); static int imRasRead24RGB( int ioType, int fd, FILE *fp, TagTable *flagsTable, TagTable *tagTable, ImVfb **pVfb); static int imRasRead32RGBA( int ioType, int fd, FILE *fp, TagTable *flagsTable, TagTable *tagTable, ImVfb **pVfb); static int imRasReadRLE1( int ioType, int fd, FILE *fp, TagTable *flagsTable, TagTable *tagTable, ImVfb **pVfb); static int imRasReadRLE8( int ioType, int fd, FILE *fp, TagTable *flagsTable, TagTable *tagTable, ImVfb **pVfb); static int imRasReadRLE24RGB( int ioType, int fd, FILE *fp, TagTable *flagsTable, TagTable *tagTable, ImVfb **pVfb); static int imRasReadRLE32RGBA( int ioType, int fd, FILE *fp, TagTable *flagsTable, TagTable *tagTable, ImVfb **pVfb); static int imRasCltToBuffer( ImVfb *vfb, unsigned char **cltBuffer, int *nClt ); #else static int imRasRead1( ); static int imRasRead8( ); static int imRasRead24RGB( ); static int imRasRead32RGBA( ); static int imRasReadRLE1( ); static int imRasReadRLE8( ); static int imRasReadRLE24RGB( ); static int imRasReadRLE32RGBA( ); static int imRasCltToBuffer( ); #endif /* * RAS - Sun Rasterfile * For information on these structures, how to use them, etc. please * see imfmt.c. */ #ifdef __STDC__ static int imRasRead( int ioType, int fd, FILE *fp, TagTable *flagsTable, TagTable *tagTable ); static int imRasWrite1( ImFileFormatWriteMap *pMap, int ioType, int fd, FILE *fp, TagTable *flagsTable, TagTable *tagTable ); static int imRasWrite8(ImFileFormatWriteMap *pMap, int ioType, int fd, FILE *fp, TagTable *flagsTable, TagTable *tagTable ); static int imRasWriteRGB( ImFileFormatWriteMap *pMap, int ioType, int fd, FILE *fp, TagTable *flagsTable, TagTable *tagTable ); static int imRasWriteRGBA( ImFileFormatWriteMap *pMap, int ioType, int fd, FILE *fp, TagTable *flagsTable, TagTable *tagTable ); static int imRasWriteRLE1( ImFileFormatWriteMap *pMap, int ioType, int fd, FILE *fp, TagTable *flagsTable, TagTable *tagTable ); static int imRasWriteRLE8( ImFileFormatWriteMap *pMap, int ioType, int fd, FILE *fp, TagTable *flagsTable, TagTable *tagTable ); static int imRasWriteRLERGB( ImFileFormatWriteMap *pMap, int ioType, int fd, FILE *fp, TagTable *flagsTable, TagTable *tagTable ); static int imRasWriteRLERGBA( ImFileFormatWriteMap *pMap, int ioType, int fd, FILE *fp, TagTable *flagsTable, TagTable *tagTable ); #else static int imRasRead( ); static int imRasWrite1( ), imRasWrite8( ); static int imRasWriteRGB( ), imRasWriteRGBA( ); static int imRasWriteRLE1( ), imRasWriteRLE8( ); static int imRasWriteRLERGB( ), imRasWriteRLERGBA( ); #endif static char *imRasNames[ ] = { "ras", "sun", "sr", "scr", NULL }; static unsigned char imRasMagicNumber[ ] = { 0x59, 0xA6, 0x6A, 0x95 }; static ImFileFormatReadMap imRasReadMap[ ] = { /* in out */ /* type,ch,dep, attr. VFB type attr. */ { IN,1,1, 0, IMVFBMONO, 0 }, { IN,1,1, C, IMVFBMONO, C }, { IN,1,8, 0, IMVFBINDEX8, 0 }, { IN,1,8, C, IMVFBINDEX8, C }, { RGB,3,8, 0, IMVFBRGB, 0 }, { RGB,3,8, C, IMVFBRGB, C }, { RGB,3,8, A, IMVFBRGB, A }, { RGB,3,8, A | C, IMVFBRGB, A | C }, { IN,1,1, RLE, IMVFBMONO, 0 }, { IN,1,1, RLE | C,IMVFBMONO, C }, { IN,1,8, RLE, IMVFBINDEX8, 0 }, { IN,1,8, RLE | C,IMVFBINDEX8, C }, { RGB,3,8, RLE, IMVFBRGB, 0 }, { RGB,3,8, RLE | C,IMVFBRGB, C }, { RGB,3,8, RLE|A, IMVFBRGB, A }, { RGB,3,8, RLE|A|C,IMVFBRGB, A | C }, { -1, 0, -1, 0 }, }; static ImFileFormatWriteMap imRasWriteMap[ ] = { /* in out */ /* VFB type, attr., type,ch,dep, attr., func */ { IMVFBMONO, 0, IN,1,1, RLE, imRasWriteRLE1 }, { IMVFBMONO, C, IN,1,1, RLE | C,imRasWriteRLE1 }, { IMVFBMONO, 0, IN,1,1, 0, imRasWrite1 }, { IMVFBMONO, C, IN,1,1, C, imRasWrite1 }, { IMVFBINDEX8, 0, IN,1,8, RLE, imRasWriteRLE8 }, { IMVFBINDEX8, C, IN,1,8, RLE | C,imRasWriteRLE8 }, { IMVFBINDEX8, 0, IN,1,8, 0, imRasWrite8 }, { IMVFBINDEX8, C, IN,1,8, C, imRasWrite8 }, { IMVFBRGB, 0, RGB,3,8, RLE, imRasWriteRLERGB}, { IMVFBRGB, C, RGB,3,8, RLE|C, imRasWriteRLERGB}, { IMVFBRGB, 0, RGB,3,8, 0, imRasWriteRGB}, { IMVFBRGB, C, RGB,3,8, C, imRasWriteRGB}, { IMVFBRGB, A, RGB,3,8, RLE|A, imRasWriteRLERGBA}, { IMVFBRGB, A | C, RGB,3,8, RLE|A|C,imRasWriteRLERGBA}, { IMVFBRGB, A, RGB,3,8, A, imRasWriteRGBA}, { IMVFBRGB, A | C, RGB,3,8, A|C, imRasWriteRGBA}, { -1, 0, -1, 0, NULL }, }; static ImFileMagic imFileRasMagic []= { { 0, 4, imRasMagicNumber}, { 0, 0, NULL }, }; ImFileFormat ImFileRasFormat = { imRasNames, "Sun Rasterfile", "Sun Microsystems, Inc.", "1- and 8-bit color index image files, with or without CLT's.\n\ 24-bit RGB and 32-bit RGB+alpha image files, with or without CLT's.\n\ Standard (uncompressed) and byte-encoded (RLE compressed).", "1- and 8-bit color index image files, with or without CLT's.\n\ 24-bit RGB and 32-bit RGB+alpha image files, with or without CLT's.\n\ Standard (uncompressed) and byte-encoded (RLE compressed).", imFileRasMagic, IMNOMULTI, IMNOPIPE, IMNOMULTI, IMNOPIPE, imRasRead, imRasReadMap, imRasWriteMap }; /* * TYPEDEF & STRUCTURE * imRasHeaderInfo - Rasterfile header information * imRasHeaderFields - imRasHeaderInfo description for Bin pkg * imRasHeader - Rasterfile header holder * * DESCRIPTION * A rasterfile's header contains a magic number, the image's width, * height, and depth, the length of the file, the type of run length * encoding in use, and the CLT, if any. */ typedef struct imRasHeaderInfo { unsigned int ras_magic; /* Magic number */ unsigned int ras_width; /* Image width */ unsigned int ras_height; /* Image height */ unsigned int ras_depth; /* Image depth */ unsigned int ras_length; /* Image length (in bytes) */ unsigned int ras_type; /* Type of encoding */ unsigned int ras_maptype; /* Type of CLT (color map) */ unsigned int ras_maplength; /* Length of CLT */ } imRasHeaderInfo; static BinField imRasHeaderFields[ ] = { { UINT, 4, 1 }, /* ras_magic */ { UINT, 4, 1 }, /* ras_width */ { UINT, 4, 1 }, /* ras_height */ { UINT, 4, 1 }, /* ras_depth */ { UINT, 4, 1 }, /* ras_length */ { UINT, 4, 1 }, /* ras_type */ { UINT, 4, 1 }, /* ras_maptype */ { UINT, 4, 1 }, /* ras_maplength */ { 0, 0, 0 }, }; static imRasHeaderInfo imRasHeader; /* RAS file header */ /* * CONSTANTS * IMRASMAGIC - file magic number * IMRASESC - escape code for run-length encoding * IMRT* - raster encoding types * IMRMT* - raster colormap encoding types * * DESCRIPTION * IMRASMAGIC (Sun's RAS_MAGIC) is the 32-bit magic number at the * top of all rasterfiles. * * IMRASESC indicates the beginning of a run in a run length * encoded raster file. * * IMRT* (Sun's RT_*) select the type of run-length encoding * used to encode the image data in the rasterfile. * * IMRMT* (Sun's RMT_*) select the type of colormap (CLT) * encoding used to encode the CLT data in the rasterfile, if any. */ #define IMRASMAGIC 0x59A66A95 #define IMRASESC 0x80 #define IMRTOLD 0 /* Raw pixrect image in 68K order*/ #define IMRTSTANDARD 1 /* Raw pixrect image in 68K order*/ #define IMRTBYTEENCODED 2 /* Run-length encoded */ #define IMRTEXPERIMENTAL 0xFFFF /* Reserved by Sun for testing */ #define IMRMTNONE 0 /* No CLT. ras_maplength == 0 */ #define IMRMTEQUALRGB 1 /* All red, then green, then blue*/ #define IMRMTRAW 2 /* Raw CLT (?) */ /* * CONSTANTS * IMRAS_RED, IMRAS_GREEN, IMRAS_BLUE, IMRAS_ALPHA - RGBA color cycle counter values * * DESCRIPTION * IMRAS_RED, IMRAS_GREEN, IMRAS_BLUE, and IMRAS_ALPHA are used as cycle values for a counter * when encoding and decoding run-length stuff. */ #define IMRAS_BLUE 0 #define IMRAS_GREEN 1 #define IMRAS_RED 2 #define IMRAS_ALPHA 3 #ifndef L_SET #define L_SET 0 /* Absolute offset */ #define L_INCR 1 /* Relative to current offset */ #define L_XTND 2 /* Relative to end of file */ #endif #ifndef F_SET #define F_SET 0 /* Absolute offset */ #define F_INCR 1 /* Relative to current offset */ #define F_XTND 2 /* Relative to end of file */ #endif /* * FUNCTION * imRasRead - read a Sun Rasterfile * * 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. * * Read supports no format flags. */ static int /* Returns status */ #ifdef __STDC__ imRasRead( int ioType, int fd, FILE *fp, TagTable *flagsTable, TagTable *tagTable ) #else imRasRead( ioType, fd, fp, flagsTable, tagTable ) int ioType; /* I/O flags */ int fd; /* Input file descriptor */ FILE *fp; /* Input file pointer */ TagTable *flagsTable; /* Flags */ TagTable *tagTable; /* Tag table to add to */ #endif { ImVfb *vfb; /* Read in image */ int nClt; /* Number of CLT entries */ ImClt *clt; /* Read in colormap */ ImCltPtr cptr; /* Color pointer */ unsigned char *cltBuffer; /* Color lookup table buffer */ unsigned char *redp; /* Red CLT range pointer */ unsigned char *greenp; /* Green CLT range pointer */ unsigned char *bluep; /* Blue CLT range pointer */ int i; /* Counter */ int status; /* Return status holder */ char message[100]; /* ImInfo message */ /* * Set the Binary I/O package's byte order, read in the file's * header, and check the magic number. */ BinByteOrder( BINMBF ); if ( ImBinReadStruct( ioType, fd, fp, &imRasHeader, imRasHeaderFields )== -1) { ImReturnBinError( ); } if ( imRasHeader.ras_magic != IMRASMAGIC ) { ImErrNo = IMEMAGIC; ImErrorFatal( ImQError( ), -1, ImErrNo ); } ImInfo( "Byte Order", "Most Significant Byte First" ); sprintf( message, "%d x %d", imRasHeader.ras_width, imRasHeader.ras_height ); ImInfo( "Resolution", message ); if( imRasHeader.ras_depth >= 24 ) sprintf( message, "%d-bit RGB", imRasHeader.ras_depth ); else sprintf( message, "%d-bit Color Indexed", imRasHeader.ras_depth ); ImInfo( "Type", message ); /* * Read in the CLT, if any. */ switch ( imRasHeader.ras_maptype ) { case IMRMTNONE: /* No CLT. */ if ( imRasHeader.ras_maplength != 0 ) { /* No CLT, yet the length says there is one!? */ ImErrNo = IMECLTLENGTH; ImErrorFatal( ImQError( ), -1, ImErrNo ); } clt = IMCLTNULL; ImInfo( "Color Table", "none" ); break; case IMRMTEQUALRGB: /* RGB CLT. */ if ( imRasHeader.ras_maplength == 0 ) { /* Is a CLT, yet the length says not!? */ ImErrNo = IMECLTLENGTH; ImErrorFatal( ImQError( ), -1, ImErrNo ); } nClt = imRasHeader.ras_maplength / 3; if ( (clt = ImCltAlloc( nClt )) ==IMCLTNULL) { ImErrorFatal( ImQError( ), -1, ImErrNo ); } ImMalloc( cltBuffer, unsigned char *, imRasHeader.ras_maplength ); /* Read in Red, Green, and Blue. */ if ( ImBinRead( ioType, fd, fp, cltBuffer, UCHAR, 1, imRasHeader.ras_maplength ) == -1 ) { free( (char *)cltBuffer ); ImReturnBinError( ); } cptr = ImCltQFirst( clt ); redp = cltBuffer; greenp = cltBuffer + nClt; bluep = cltBuffer + nClt + nClt; for ( i = 0; i < nClt; i++ ) { ImCltSRed( cptr, *redp++ ); ImCltSGreen( cptr, *greenp++ ); ImCltSBlue( cptr, *bluep++ ); ImCltSInc( clt, cptr ); } free( (char *)cltBuffer ); sprintf( message, "%d Entries", nClt ); ImInfo( "Color Table", message ); break; case IMRMTRAW: /* Raw CLT ? */ /* Fall through to error. */ default: ImErrNo = IMESYNTAX; ImErrorFatal( "Unkown CLT type in file header.", -1, ImErrNo ); } /* * Based on the image depth and encoding scheme, call a function * to do the rest of the work. These functions are never called * again anywhere else. It just breaks up this routine into * smaller bite-sized chunks for easier debugging. */ switch ( imRasHeader.ras_type ) { case IMRTOLD: /* * Old format rasterfiles have a 0 in the ras_length field. * Fortunately, old format rasterfiles don't do run-length * encoding, so the size of the image data is just the height * times the width times the depth, in bytes. */ imRasHeader.ras_length = imRasHeader.ras_width * imRasHeader.ras_height * imRasHeader.ras_depth; /* Fall through to standard. */ case IMRTSTANDARD: /* Un-encoded raster image. */ ImInfo( "Compression Type", "none (Standard)" ); switch ( imRasHeader.ras_depth ) { case 1: /* Monochrome image. */ status = imRasRead1( ioType, fd, fp, flagsTable, tagTable, &vfb ); ImInfo( "Alpha Channel", "none" ); break; case 8: /* CLT image. */ status = imRasRead8( ioType, fd, fp, flagsTable, tagTable, &vfb ); ImInfo( "Alpha Channel", "none" ); break; case 24:/* RGB image. */ status = imRasRead24RGB( ioType, fd, fp, flagsTable, tagTable, &vfb ); ImInfo( "Alpha Channel", "none" ); break; case 32:/* RGBA image. */ status = imRasRead32RGBA( ioType, fd, fp, flagsTable, tagTable, &vfb ); ImInfo( "Alpha Channel", "8-bit" ); break; default: ImErrNo = IMEDEPTH; ImErrorFatal( "Unknown standard-format image depth", -1, ImErrNo ); } break; case IMRTBYTEENCODED: /* Run-length encoded raster image. */ ImInfo("Compression Type","Run Length Encoded (Byte Encoded)"); switch ( imRasHeader.ras_depth ) { case 1: /* Monochrome image. */ status = imRasReadRLE1( ioType, fd, fp, flagsTable, tagTable, &vfb ); ImInfo( "Alpha Channel", "none" ); break; case 8: /* CLT image. */ status = imRasReadRLE8( ioType, fd, fp, flagsTable, tagTable, &vfb ); ImInfo( "Alpha Channel", "none" ); break; case 24:/* RGB image. */ status = imRasReadRLE24RGB( ioType, fd, fp, flagsTable, tagTable, &vfb ); ImInfo( "Alpha Channel", "none" ); break; case 32:/* RGBA image. */ status = imRasReadRLE32RGBA( ioType, fd, fp, flagsTable, tagTable, &vfb ); ImInfo( "Alpha Channel", "8-bit" ); break; default: ImErrNo = IMEDEPTH; ImErrorFatal( "Unkown byte-encoded-format image depth", -1, ImErrNo ); } break; case IMRTEXPERIMENTAL: /* Sun private experimental format. Unsupported by us.*/ /* Fall through to error. */ default: ImErrNo = IMEIMAGETYPE; ImErrorFatal( "Unknown image type in file header", -1, ImErrNo ); } if ( status == -1 ) return ( -1 ); if ( clt != IMCLTNULL ) { ImVfbSClt( vfb, clt ); TagTableAppend( tagTable, TagEntryAlloc( "image clt", POINTER, &clt )); } TagTableAppend( tagTable, TagEntryAlloc( "image vfb", POINTER, &vfb )); return ( 0 ); } /* * FUNCTION * imRasRead1 - read 1-bit RAS format * imRasRead8 - read 8-bit RAS format * imRasRead24RGB - read 24-bit RGB RAS format * imRasRead32RGBA - read 32-bit RGBA RAS format * * DESCRIPTION * Each of these routines deal with "standard" format RAS files. * The input stream is a file or a pipe. We don't care. * * A new VFB is allocated. The image is read in, one scanline at * a time, and converted into the VFB. */ static int /* Returns status */ #ifdef __STDC__ imRasRead1( int ioType, int fd, FILE *fp, TagTable *flagsTable, TagTable *tagTable, ImVfb **pVfb ) #else imRasRead1( ioType, fd, fp, flagsTable, tagTable, pVfb ) int ioType; /* I/O flags */ int fd; /* Input file descriptor */ FILE *fp; /* Input file pointer */ TagTable *flagsTable; /* Flags */ TagTable *tagTable; /* Tag table to add to */ ImVfb **pVfb; /* VFB to fill and return */ #endif { unsigned char *rbp; /* Run buffer pointer */ int i, j; /* Counters */ ImVfb *vfb; /* New vfb */ ImVfbPtr pptr; /* Pixel pointer */ int n; /* # of bytes in a scanline */ int byte; /* Byte of 8 mono pixels */ unsigned char *runBuffer; /* Run buffer */ /* * Allocate a VFB of the required size. */ if ( (*pVfb = ImVfbAlloc( imRasHeader.ras_width, imRasHeader.ras_height, IMVFBMONO )) == IMVFBNULL ) { ImErrorFatal( ImQError( ), -1, ImErrNo ); } vfb = *pVfb; /* * Allocate a buffer that is big enough for one scanline * (rounded to 2-bytes). Read in and process the image one * scanline at a time. */ pptr = ImVfbQFirst( vfb ); n = (imRasHeader.ras_width + 7) / 8; if ( (n&1) != 0 ) n++; /* Round out to multiple of 2 */ ImMalloc( runBuffer, unsigned char *, sizeof( unsigned char ) * n ); for ( i = 0; i < imRasHeader.ras_height; i++ ) { if ( ImBinRead( ioType, fd, fp, runBuffer, UCHAR, 1, n ) == -1 ) { free( (char *)runBuffer ); ImVfbFree( vfb ); ImReturnBinError( ); } rbp = runBuffer; for ( j = 0; j < imRasHeader.ras_width; j++ ) { if ( (j&7) == 0 ) byte = *rbp++; ImVfbSMono( vfb, pptr, (byte & 0x80) ? 0 : 1 ); ImVfbSInc( vfb, pptr ); byte <<= 1; } } free( (char *)runBuffer ); return ( 0 ); } static int /* Returns status */ #ifdef __STDC__ imRasRead8( int ioType, int fd, FILE *fp, TagTable *flagsTable, TagTable *tagTable, ImVfb **pVfb ) #else imRasRead8( ioType, fd, fp, flagsTable, tagTable, pVfb ) int ioType; /* I/O flags */ int fd; /* Input file descriptor */ FILE *fp; /* Input file pointer */ TagTable *flagsTable; /* Flags */ TagTable *tagTable; /* Tag table to add to */ ImVfb **pVfb; /* VFB to fill and return */ #endif { unsigned char *rbp; /* Run buffer pointer */ int i, j; /* Counters */ ImVfb *vfb; /* New vfb */ ImVfbPtr pptr; /* Pixel pointer */ int n; /* # of bytes in a scanline */ unsigned char *runBuffer; /* Run buffer */ /* * Allocate a VFB of the required size. */ if ( (*pVfb = ImVfbAlloc( imRasHeader.ras_width, imRasHeader.ras_height, IMVFBINDEX8 )) == IMVFBNULL ) { ImErrorFatal( ImQError( ), -1, ImErrNo ); } vfb = *pVfb; /* * Allocate a buffer that is big enough for one scanline * (rounded to 2-bytes). Read in and process the image one * scanline at a time. */ pptr = ImVfbQFirst( vfb ); n = imRasHeader.ras_width; if ( (n&1) != 0 ) n++; /* Round out to multiple of 2 */ ImMalloc( runBuffer, unsigned char *, sizeof( unsigned char ) * n ); for ( i = 0; i < imRasHeader.ras_height; i++ ) { if ( ImBinRead( ioType, fd, fp, runBuffer, UCHAR, 1, n ) == -1 ) { free( (char *)runBuffer ); ImVfbFree( vfb ); ImReturnBinError( ); } rbp = runBuffer; for ( j = 0; j < imRasHeader.ras_width; j++ ) { ImVfbSIndex8( vfb, pptr, *rbp++ ); ImVfbSInc( vfb, pptr ); } } free( (char *)runBuffer ); return ( 0 ); } static int /* Returns status */ #ifdef __STDC__ imRasRead24RGB( int ioType, int fd, FILE *fp, TagTable *flagsTable, TagTable *tagTable, ImVfb **pVfb ) #else imRasRead24RGB( ioType, fd, fp, flagsTable, tagTable, pVfb ) int ioType; /* I/O flags */ int fd; /* Input file descriptor */ FILE *fp; /* Input file pointer */ TagTable *flagsTable; /* Flags */ TagTable *tagTable; /* Tag table to add to */ ImVfb **pVfb; /* VFB to fill and return */ #endif { unsigned char *rbp; /* Run buffer pointer */ int i, j; /* Counters */ ImVfb *vfb; /* New vfb */ ImVfbPtr pptr; /* Pixel pointer */ int n; /* # of bytes in a scanline */ unsigned char *runBuffer; /* Run buffer */ /* * Allocate a VFB of the required size. */ if ( (*pVfb = ImVfbAlloc( imRasHeader.ras_width, imRasHeader.ras_height, IMVFBRGB )) == IMVFBNULL ) { ImErrorFatal( ImQError( ), -1, ImErrNo ); } vfb = *pVfb; /* * Allocate a buffer that is big enough for one scanline * (rounded to 2-bytes). Read in and process the image one * scanline at a time. */ pptr = ImVfbQFirst( vfb ); n = imRasHeader.ras_width * 3; /* # of bytes */ if ( (n&1) != 0 ) n++; /* Round out to multiple of 2 */ ImMalloc( runBuffer, unsigned char *, sizeof( unsigned char ) * n ); for ( i = 0; i < imRasHeader.ras_height; i++ ) { if ( ImBinRead( ioType, fd, fp, runBuffer, UCHAR, 1, n ) == -1 ) { free( (char *)runBuffer ); ImVfbFree( vfb ); ImReturnBinError( ); } rbp = runBuffer; for ( j = 0; j < imRasHeader.ras_width; j++ ) { ImVfbSBlue( vfb, pptr, *rbp++ ); ImVfbSGreen( vfb, pptr, *rbp++ ); ImVfbSRed( vfb, pptr, *rbp++ ); ImVfbSInc( vfb, pptr ); } } free( (char *)runBuffer ); return ( 0 ); } static int /* Returns status */ #ifdef __STDC__ imRasRead32RGBA( int ioType, int fd, FILE *fp, TagTable *flagsTable, TagTable *tagTable, ImVfb **pVfb ) #else imRasRead32RGBA( ioType, fd, fp, flagsTable, tagTable, pVfb ) int ioType; /* I/O flags */ int fd; /* Input file descriptor */ FILE *fp; /* Input file pointer */ TagTable *flagsTable; /* Flags */ TagTable *tagTable; /* Tag table to add to */ ImVfb **pVfb; /* VFB to fill and return */ #endif { unsigned char *rbp; /* Run buffer pointer */ int i, j; /* Counters */ ImVfb *vfb; /* New vfb */ ImVfbPtr pptr; /* Pixel pointer */ int n; /* # of bytes in a scanline */ unsigned char *runBuffer; /* Run buffer */ /* * Allocate a VFB of the required size. */ if ( (*pVfb = ImVfbAlloc( imRasHeader.ras_width, imRasHeader.ras_height, IMVFBRGB | IMVFBALPHA )) == IMVFBNULL ) { ImErrorFatal( ImQError( ), -1, ImErrNo ); } vfb = *pVfb; /* * Allocate a buffer that is big enough for one scanline * (rounded to 2-bytes). Read in and process the image one * scanline at a time. */ pptr = ImVfbQFirst( vfb ); n = imRasHeader.ras_width * 4; /* # of bytes */ if ( (n&1) != 0 ) n++; /* Round out to multiple of 2 */ ImMalloc( runBuffer, unsigned char *, sizeof( unsigned char ) * n ); for ( i = 0; i < imRasHeader.ras_height; i++ ) { if ( ImBinRead( ioType, fd, fp, runBuffer, UCHAR, 1, n ) == -1 ) { free( (char *)runBuffer ); ImVfbFree( vfb ); ImReturnBinError( ); } rbp = runBuffer; for ( j = 0; j < imRasHeader.ras_width; j++ ) { ImVfbSAlpha( vfb, pptr, *rbp++ ); ImVfbSBlue( vfb, pptr, *rbp++ ); ImVfbSGreen( vfb, pptr, *rbp++ ); ImVfbSRed( vfb, pptr, *rbp++ ); ImVfbSInc( vfb, pptr ); } } free( (char *)runBuffer ); return ( 0 ); } /* * FUNCTION * imRasReadRLE1 - read 1-bit encoded RAS format * imRasReadRLE8 - read 8-bit encoded RAS format * imRasReadRLE24RGB - read 24-bit RGB encoded RAS format * imRasReadRLE32RGBA - read 32-bit RGBA encoded RAS format * * DESCRIPTION * Each of these routines deal with "encoded" format RAS files. * The output stream is a file or a pipe. We don't care. * * A new VFB is allocated. The image is read into an image-sized * buffer, then converted into the VFB. * * We allocate a buffer the size of the file's run's because it is * awkward to decode runs in chunks. This should be done in the future * in order to reduce the memory use of these routines. */ static int /* Returns status */ #ifdef __STDC__ imRasReadRLE1( int ioType, int fd, FILE *fp, TagTable *flagsTable, TagTable *tagTable, ImVfb **pVfb ) #else imRasReadRLE1( ioType, fd, fp, flagsTable, tagTable, pVfb ) int ioType; /* I/O flags */ int fd; /* Input file descriptor */ FILE *fp; /* Input file pointer */ TagTable *flagsTable; /* Flags */ TagTable *tagTable; /* Tag table to add to */ ImVfb **pVfb; /* VFB to fill and return */ #endif { unsigned char *rbp; /* Run buffer pointer */ ImVfb *vfb; /* New vfb */ ImVfbPtr pptr; /* Pixel pointer */ unsigned char color; /* Color */ int count; /* Run-length encodeing count */ int n; /* # of bytes in image */ unsigned char *runBuffer; /* Run buffer */ unsigned char *endrbp; /* Ending rbp pointer value */ int nPixels; /* # of pixels so far in scanline*/ int byte; /* Byte of pixels */ int pad; /* Pad scanline? */ long fileOffset; /* Location in file */ /* * Allocate a VFB of the required size. */ if ( (*pVfb = ImVfbAlloc( imRasHeader.ras_width, imRasHeader.ras_height, IMVFBMONO )) == IMVFBNULL ) { ImErrorFatal( ImQError( ), -1, ImErrNo ); } vfb = *pVfb; /* * The imRasHeader.ras_length field of the file header is supposed * to be set to the number of bytes of image data in the file. * Unfortunately, this has been interpreted to mean several different * things by different people: * * - height * width, even when compressed. * - the actual number of compressed bytes. * - zero. * - a number of variants on these. * * This makes the ras_length field an undependable value. * * So, we'll ignore it. We seek to the end of the file and see * how many bytes there are from here to there, then read them all in. * This is a potential big waste of memory, but there's little we * can safely do about it. */ fileOffset = ImTell( ioType, fd, fp ); ImSeek( ioType, fd, fp, 0, L_XTND ); n = ImTell( ioType, fd, fp ) - fileOffset; ImSeek( ioType, fd, fp, fileOffset, L_SET ); /* * Allocate a buffer big enough for all those bytes. */ pptr = ImVfbQFirst( vfb ); ImMalloc( runBuffer, unsigned char *, sizeof( unsigned char ) * n ); rbp = runBuffer; /* * And read them in. */ if ( (n = ImBinRead( ioType, fd, fp, runBuffer, UCHAR, 1, n )) == -1 ) { free( (char *)runBuffer ); ImVfbFree( vfb ); ImReturnBinError( ); } endrbp = &runBuffer[n-1]; nPixels = 0; pad = ((int)((imRasHeader.ras_width + 7)/ 8) & 0x01) ? TRUE : FALSE; while ( rbp <= endrbp ) { color = *rbp++; count = 1; if ( color == IMRASESC && (count += *rbp++) != 1 ) color = *rbp++; while ( count-- != 0 ) { if ( nPixels >= imRasHeader.ras_width ) { /* End of scan line. */ nPixels = 0; if ( pad ) continue; /* Skip pixel */ } /* * Expand byte into up to 8 pixels. */ if ( (nPixels + 8) <= imRasHeader.ras_width ) { /* Expand full byte. Unwrap loop for speed.*/ ImVfbSMono( vfb, pptr, (color&0x80) ? 0 : 1 ); ImVfbSInc( vfb, pptr ); ImVfbSMono( vfb, pptr, (color&0x40) ? 0 : 1 ); ImVfbSInc( vfb, pptr ); ImVfbSMono( vfb, pptr, (color&0x20) ? 0 : 1 ); ImVfbSInc( vfb, pptr ); ImVfbSMono( vfb, pptr, (color&0x10) ? 0 : 1 ); ImVfbSInc( vfb, pptr ); ImVfbSMono( vfb, pptr, (color&0x08) ? 0 : 1 ); ImVfbSInc( vfb, pptr ); ImVfbSMono( vfb, pptr, (color&0x04) ? 0 : 1 ); ImVfbSInc( vfb, pptr ); ImVfbSMono( vfb, pptr, (color&0x02) ? 0 : 1 ); ImVfbSInc( vfb, pptr ); ImVfbSMono( vfb, pptr, (color&0x01) ? 0 : 1 ); ImVfbSInc( vfb, pptr ); nPixels += 8; continue; } /* Expand part of byte. Unwrap loop for speed. */ byte = color; switch ( imRasHeader.ras_width - nPixels ) { case 7: ImVfbSMono( vfb, pptr, (byte&0x80) ? 0 : 1 ); ImVfbSInc( vfb, pptr ); byte <<= 1; case 6: ImVfbSMono( vfb, pptr, (byte&0x80) ? 0 : 1 ); ImVfbSInc( vfb, pptr ); byte <<= 1; case 5: ImVfbSMono( vfb, pptr, (byte&0x80) ? 0 : 1 ); ImVfbSInc( vfb, pptr ); byte <<= 1; case 4: ImVfbSMono( vfb, pptr, (byte&0x80) ? 0 : 1 ); ImVfbSInc( vfb, pptr ); byte <<= 1; case 3: ImVfbSMono( vfb, pptr, (byte&0x80) ? 0 : 1 ); ImVfbSInc( vfb, pptr ); byte <<= 1; case 2: ImVfbSMono( vfb, pptr, (byte&0x80) ? 0 : 1 ); ImVfbSInc( vfb, pptr ); byte <<= 1; case 1: ImVfbSMono( vfb, pptr, (byte&0x80) ? 0 : 1 ); ImVfbSInc( vfb, pptr ); byte <<= 1; } nPixels = imRasHeader.ras_width; } } free( (char *)runBuffer ); return ( 0 ); } static int /* Returns status */ #ifdef __STDC__ imRasReadRLE8( int ioType, int fd, FILE *fp, TagTable *flagsTable, TagTable *tagTable, ImVfb **pVfb ) #else imRasReadRLE8( ioType, fd, fp, flagsTable, tagTable, pVfb ) int ioType; /* I/O flags */ int fd; /* Input file descriptor */ FILE *fp; /* Input file pointer */ TagTable *flagsTable; /* Flags */ TagTable *tagTable; /* Tag table to add to */ ImVfb **pVfb; /* VFB to fill and return */ #endif { unsigned char *rbp; /* Run buffer pointer */ ImVfb *vfb; /* New vfb */ ImVfbPtr pptr; /* Pixel pointer */ int n; /* # of bytes in image */ unsigned char *runBuffer; /* Run buffer */ unsigned char color; /* Color */ int count; /* Run-length encodeing count */ unsigned char *endrbp; /* Ending rbp pointer value */ int nPixels; /* # of pixels in scanline */ long fileOffset; /* Location in file */ /* * Allocate a VFB of the required size. */ if ( (*pVfb = ImVfbAlloc( imRasHeader.ras_width, imRasHeader.ras_height, IMVFBINDEX8 )) == IMVFBNULL ) { ImErrorFatal( ImQError( ), -1, ImErrNo ); } vfb = *pVfb; /* * The imRasHeader.ras_length field of the file header is supposed * to be set to the number of bytes of image data in the file. * Unfortunately, this has been interpreted to mean several different * things by different people: * * - height * width, even when compressed. * - the actual number of compressed bytes. * - zero. * - a number of variants on these. * * This makes the ras_length field an undependable value. * * So, we'll ignore it. We seek to the end of the file and see * how many bytes there are from here to there, then read them all in. * This is a potential big waste of memory, but there's little we * can safely do about it. */ fileOffset = ImTell( ioType, fd, fp ); ImSeek( ioType, fd, fp, 0, L_XTND ); n = ImTell( ioType, fd, fp ) - fileOffset; ImSeek( ioType, fd, fp, fileOffset, L_SET ); /* * Allocate a buffer big enough for all those bytes. */ pptr = ImVfbQFirst( vfb ); ImMalloc( runBuffer, unsigned char *, sizeof( unsigned char ) * n ); rbp = runBuffer; /* * And read them in. */ if ( (n = ImBinRead( ioType, fd, fp, runBuffer, UCHAR, 1, n )) == -1 ) { free( (char *)runBuffer ); ImVfbFree( vfb ); ImReturnBinError( ); } nPixels = 0; endrbp = &runBuffer[n-1]; while ( rbp <= endrbp ) { color = *rbp++; count = 1; if ( color == IMRASESC && (count += *rbp++) != 1 ) color = *rbp++; if ( (imRasHeader.ras_width & 0x01) == 0 ) { /* Even width. No pad bytes. */ while ( count-- != 0 ) { ImVfbSIndex8( vfb, pptr, color ); ImVfbSInc( vfb, pptr ); } continue; } /* Odd width. Skip pad byte after every 'width' pixels.*/ while ( count-- != 0 ) { if ( nPixels >= imRasHeader.ras_width ) { nPixels = 0; continue; /* Skip this pixel. */ } ImVfbSIndex8( vfb, pptr, color ); ImVfbSInc( vfb, pptr ); nPixels++; } } free( (char *)runBuffer ); return ( 0 ); } static int /* Returns status */ #ifdef __STDC__ imRasReadRLE24RGB( int ioType, int fd, FILE *fp, TagTable *flagsTable, TagTable *tagTable, ImVfb **pVfb ) #else imRasReadRLE24RGB( ioType, fd, fp, flagsTable, tagTable, pVfb ) int ioType; /* I/O flags */ int fd; /* Input file descriptor */ FILE *fp; /* Input file pointer */ TagTable *flagsTable; /* Flags */ TagTable *tagTable; /* Tag table to add to */ ImVfb **pVfb; /* VFB to fill and return */ #endif { unsigned char *rbp; /* Run buffer pointer */ ImVfb *vfb; /* New vfb */ ImVfbPtr pptr; /* Pixel pointer */ int n; /* # of bytes in image */ unsigned char *runBuffer; /* Run buffer */ unsigned char color; /* Color */ int count; /* Run-length encodeing count */ unsigned char *endrbp; /* Ending rbp pointer value */ int onRGB; /* RGB color cycle counter */ int nPixels; /* # of pixels in scanline */ long fileOffset; /* Location in file */ /* * Allocate a VFB of the required size. */ if ( (*pVfb = ImVfbAlloc( imRasHeader.ras_width, imRasHeader.ras_height, IMVFBRGB )) == IMVFBNULL ) { ImErrorFatal( ImQError( ), -1, ImErrNo ); } vfb = *pVfb; /* * The imRasHeader.ras_length field of the file header is supposed * to be set to the number of bytes of image data in the file. * Unfortunately, this has been interpreted to mean several different * things by different people: * * - height * width, even when compressed. * - the actual number of compressed bytes. * - zero. * - a number of variants on these. * * This makes the ras_length field an undependable value. * * So, we'll ignore it. We seek to the end of the file and see * how many bytes there are from here to there, then read them all in. * This is a potential big waste of memory, but there's little we * can safely do about it. */ fileOffset = ImTell( ioType, fd, fp ); ImSeek( ioType, fd, fp, 0, L_XTND ); n = ImTell( ioType, fd, fp ) - fileOffset; ImSeek( ioType, fd, fp, fileOffset, L_SET ); /* * Allocate a buffer big enough for all those bytes. */ pptr = ImVfbQFirst( vfb ); ImMalloc( runBuffer, unsigned char *, sizeof( unsigned char ) * n ); rbp = runBuffer; /* * And read them in. */ if ( (n = ImBinRead( ioType, fd, fp, runBuffer, UCHAR, 1, n )) == -1 ) { free( (char *)runBuffer ); ImVfbFree( vfb ); ImReturnBinError( ); } nPixels = 0; endrbp = &runBuffer[n-1]; onRGB = IMRAS_BLUE; while ( rbp <= endrbp ) { color = *rbp++; count = 1; if ( color == IMRASESC && (count += *rbp++) != 1 ) color = *rbp++; if ( (imRasHeader.ras_width & 0x01) == 0 ) { /* Even image width. No padding needed. */ while ( count-- != 0 ) { switch ( onRGB ) { case IMRAS_BLUE: ImVfbSBlue( vfb, pptr, color ); onRGB = IMRAS_GREEN; continue; case IMRAS_GREEN: ImVfbSGreen( vfb, pptr, color ); onRGB = IMRAS_RED; continue; case IMRAS_RED: ImVfbSRed( vfb, pptr, color ); ImVfbSInc( vfb, pptr ); nPixels++; onRGB = IMRAS_BLUE; continue; } } continue; } /* Odd image width. Pad 1 byte per scanline. */ while ( count-- != 0 ) { if ( nPixels >= imRasHeader.ras_width ) { nPixels = 0; continue; /* Skip this byte. */ } switch ( onRGB ) { case IMRAS_BLUE: ImVfbSBlue( vfb, pptr, color ); onRGB = IMRAS_GREEN; continue; case IMRAS_GREEN: ImVfbSGreen( vfb, pptr, color ); onRGB = IMRAS_RED; continue; case IMRAS_RED: ImVfbSRed( vfb, pptr, color ); ImVfbSInc( vfb, pptr ); nPixels++; onRGB = IMRAS_BLUE; continue; } } } free( (char *)runBuffer ); return ( 0 ); } static int /* Returns status */ #ifdef __STDC__ imRasReadRLE32RGBA( int ioType, int fd, FILE *fp, TagTable *flagsTable, TagTable *tagTable, ImVfb **pVfb ) #else imRasReadRLE32RGBA( ioType, fd, fp, flagsTable, tagTable, pVfb ) int ioType; /* I/O flags */ int fd; /* Input file descriptor */ FILE *fp; /* Input file pointer */ TagTable *flagsTable; /* Flags */ TagTable *tagTable; /* Tag table to add to */ ImVfb **pVfb; /* VFB to fill and return */ #endif { unsigned char *rbp; /* Run buffer pointer */ ImVfb *vfb; /* New vfb */ ImVfbPtr pptr; /* Pixel pointer */ int n; /* # of bytes in image */ unsigned char *runBuffer; /* Run buffer */ unsigned char color; /* Color */ int count; /* Run-length encodeing count */ unsigned char *endrbp; /* Ending rbp pointer value */ int onRGB; /* RGB color cycle counter */ int nPixels; /* # of pixels in scanline */ long fileOffset; /* Location in file */ /* * Allocate a VFB of the required size. */ if ( (*pVfb = ImVfbAlloc( imRasHeader.ras_width, imRasHeader.ras_height, IMVFBRGB | IMVFBALPHA )) == IMVFBNULL ) { ImErrorFatal( ImQError( ), -1, ImErrNo ); } vfb = *pVfb; /* * The imRasHeader.ras_length field of the file header is supposed * to be set to the number of bytes of image data in the file. * Unfortunately, this has been interpreted to mean several different * things by different people: * * - height * width, even when compressed. * - the actual number of compressed bytes. * - zero. * - a number of variants on these. * * This makes the ras_length field an undependable value. * * So, we'll ignore it. We seek to the end of the file and see * how many bytes there are from here to there, then read them all in. * This is a potential big waste of memory, but there's little we * can safely do about it. */ fileOffset = ImTell( ioType, fd, fp ); ImSeek( ioType, fd, fp, 0, L_XTND ); n = ImTell( ioType, fd, fp ) - fileOffset; ImSeek( ioType, fd, fp, fileOffset, L_SET ); /* * Allocate a buffer big enough for all those bytes. */ pptr = ImVfbQFirst( vfb ); ImMalloc( runBuffer, unsigned char *, sizeof( unsigned char ) * n ); rbp = runBuffer; /* * And read them in. */ if ( (n = ImBinRead( ioType, fd, fp, runBuffer, UCHAR, 1, n )) == -1 ) { free( (char *)runBuffer ); ImVfbFree( vfb ); ImReturnBinError( ); } nPixels = 0; endrbp = &runBuffer[n-1]; onRGB = IMRAS_ALPHA; while ( rbp <= endrbp ) { color = *rbp++; count = 1; if ( color == IMRASESC && (count += *rbp++) != 1 ) color = *rbp++; while ( count-- != 0 ) { switch ( onRGB ) { case IMRAS_ALPHA: ImVfbSAlpha( vfb, pptr, color ); onRGB = IMRAS_BLUE; continue; case IMRAS_BLUE: ImVfbSBlue( vfb, pptr, color ); onRGB = IMRAS_GREEN; continue; case IMRAS_GREEN: ImVfbSGreen( vfb, pptr, color ); onRGB = IMRAS_RED; continue; case IMRAS_RED: ImVfbSRed( vfb, pptr, color ); ImVfbSInc( vfb, pptr ); nPixels++; onRGB = IMRAS_ALPHA; continue; } } } free( (char *)runBuffer ); return ( 0 ); } /* * FUNCTION * imRasWriteHeaderClt - write header and CLT * * DESCRIPTION * A RAS file header is intialized and written out. If a CLT is to * be written out, it is converted to a CLT buffer, then written * following the header. */ static int /* Returns status */ #ifdef __STDC__ imRasWriteHeaderClt( ImFileFormatWriteMap *pMap, int ioType, int fd, FILE *fp, ImVfb *vfb, int depth, int type ) #else imRasWriteHeaderClt( pMap, ioType, fd, fp, vfb, depth, type ) ImFileFormatWriteMap *pMap; /* Write map entry to adhear to */ int ioType; /* I/O flags */ int fd; /* Output file descriptor */ FILE *fp; /* Output file pointer */ ImVfb *vfb; /* VFB to write out */ int depth; /* Image depth */ int type; /* Image type */ #endif { unsigned char *cltBuffer; /* Converted CLT */ int nClt; /* # of CLT entries */ char message[100]; /* ImInfo message */ /* * Set up the basic header. */ imRasHeader.ras_magic = IMRASMAGIC; imRasHeader.ras_width = ImVfbQWidth( vfb ); imRasHeader.ras_height = ImVfbQHeight( vfb ); imRasHeader.ras_depth = depth; imRasHeader.ras_type = type; imRasHeader.ras_length = imRasHeader.ras_width * imRasHeader.ras_height * depth / 8; if ( (imRasHeader.ras_width * depth / 8) % 2 != 0 ) { /* Pad each scanline to 2-byte boundary. */ imRasHeader.ras_length += imRasHeader.ras_height * depth / 8; } /* * If we've been requested to write the CLT, convert it to a tmp * buffer first. */ nClt = 0; if ( (pMap->map_outAttributes & IMCLTYES) && imRasCltToBuffer( vfb, &cltBuffer, &nClt ) == -1) { ImErrorFatal( ImQError( ), -1, ImErrNo ); } /* * Output -verbose message */ ImInfo( "Byte Order", "Most Significant Byte First" ); sprintf( message, "%d x %d", ImVfbQWidth( vfb ), ImVfbQHeight( vfb ) ); ImInfo( "Resolution", message ); if( depth >= 24 ) sprintf( message, "%d-bit RGB", depth ); else sprintf( message, "%d-bit Color Indexed", depth ); ImInfo( "Type", message ); if( nClt == 0 ) sprintf( message, "none" ); else sprintf( message, "%d Entries", nClt ); ImInfo( "Color Table", message ); if( type == IMRTBYTEENCODED ) { ImInfo("Compression Type","Run Length Encoded (Byte Encoded)"); } else ImInfo( "Compression Type", "none (Standard)" ); if( depth > 24 ) { ImInfo( "Alpha Channel", "8-bit" ); } else ImInfo( "Alpha Channel", "none" ); /* * If there's no CLT to write out, just write the header. Otherwise * write the header followed by the CLT tmp buffer. */ if ( nClt == 0 ) { imRasHeader.ras_maplength = 0; imRasHeader.ras_maptype = IMRMTNONE; if ( ImBinWriteStruct( ioType, fd, fp, &imRasHeader, imRasHeaderFields ) == -1 ) { ImReturnBinError( ); } return ( 0 ); } imRasHeader.ras_maplength = nClt * 3; imRasHeader.ras_maptype = IMRMTEQUALRGB; if ( ImBinWriteStruct( ioType, fd, fp, &imRasHeader, imRasHeaderFields ) == -1 ) { ImReturnBinError( ); } if ( ImBinWrite( ioType, fd, fp, cltBuffer, UCHAR, 1, imRasHeader.ras_maplength ) == -1 ) { free( (char *)cltBuffer ); ImReturnBinError( ); } free( (char *)cltBuffer ); return ( 0 ); } /* * FUNCTION * imRasCltToBuffer - convert CLT to file format buffer * * DESCRIPTION * The CLT for the given VFB is converted into a CLT buffer for later * writing out to a RAS image file. * * Since RAS CLT's are not a fixed size, we just have to convert * the actual entries in our CLT and not worry about padding the * convert buffer with dummy CLT entries. */ static int /* Returns status */ #ifdef __STDC__ imRasCltToBuffer( ImVfb *vfb, unsigned char **cltBuffer, int *nClt ) #else imRasCltToBuffer( vfb, cltBuffer, nClt ) ImVfb *vfb; /* VFB to check */ unsigned char **cltBuffer; /* Returned buffer */ int *nClt; /* Returned # of CLT entries */ #endif { ImCltPtr cptr; /* CLT pointer */ unsigned char *redp; /* Red CLT range pointer */ unsigned char *greenp; /* Green CLT range pointer */ unsigned char *bluep; /* Blue CLT range pointer */ ImClt *clt; /* Colormap */ int i; /* Counter */ int n; /* Number of CLT entries */ /* Get the VFB's CLT (if any). */ clt = ImVfbQClt( vfb ); if ( clt == IMCLTNULL ) { /* Isn't one. Never mind. */ *nClt = 0; *cltBuffer = NULL; return ( 0 ); /* No CLT, but that's OK. */ } *nClt = n = ImCltQNColors( clt ); ImMalloc( *cltBuffer, unsigned char *, sizeof( unsigned char ) * n * 3 ); redp = *cltBuffer; greenp = *cltBuffer + n; bluep = *cltBuffer + n + n; cptr = ImCltQFirst( clt ); for ( i = 0; i < n; i++ ) { *redp++ = ImCltQRed( cptr ); *greenp++ = ImCltQGreen( cptr ); *bluep++ = ImCltQBlue( cptr ); ImCltSInc( clt, cptr ); } return ( 0 ); /* CLT came from VFB */ } /* * FUNCTION * imRasWrite1 - write 1-bit standard RAS format * imRasWrite8 - write 8-bit standard RAS format * imRasWriteRGB - write 24-bit RGB standard RAS format * imRasWriteRGBA - write 32-bit RGBA standard RAS format * * DESCRIPTION * Each of these routines deal with "standard" format RAS files * (ie., no run-length encoding). The output stream may be a pipe * or a file. We don't care. * * The header and CLT (if any) are written out. The VFB is then * converted and written out one scanline at a time. Scanlines * are always padded to 2-byte boundaries. */ static int /* Returns status */ #ifdef __STDC__ imRasWrite1( ImFileFormatWriteMap *pMap, int ioType, int fd, FILE *fp, TagTable *flagsTable, TagTable *tagTable ) #else imRasWrite1( 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; /* Flags */ TagTable *tagTable; /* Tag table to read from */ #endif { int i, j; /* Counters */ ImVfbPtr pptr; /* Pixel pointer */ unsigned char *rbp; /* Run buffer pointer */ ImVfb *vfb; /* VFB to write out */ unsigned char *runBuffer; /* Run buffer */ int n; /* # of bytes to write */ unsigned char byte; /* New byte of pixels */ /* * Write out the header and possible CLT. */ TagEntryQValue( TagTableQDirect( tagTable, "image vfb", 0 ), &vfb ); BinByteOrder( BINMBF ); if ( imRasWriteHeaderClt( pMap, ioType, fd, fp, vfb, 1, IMRTSTANDARD ) == -1 ) return ( -1 ); /* Error already handled */ /* * Convert and write out the image. */ n = (imRasHeader.ras_width + 7) / 8; /* # bytes */ if ( (n&1) != 0 ) n++; /* Pad to 2-byte boundary*/ ImMalloc( runBuffer, unsigned char *, sizeof( unsigned char ) * n ); runBuffer[n-1] = 0; /* Set the pad byte */ pptr = ImVfbQFirst( vfb ); for ( i = 0; i < imRasHeader.ras_height; i++ ) { rbp = runBuffer; byte = 0; for ( j = 0; j < imRasHeader.ras_width; j++ ) { byte <<= 1; if ( ImVfbQMono( vfb, pptr ) == 0 ) byte |= 1; ImVfbSInc( vfb, pptr ); if ( (j&0x7) == 0x7 ) { *rbp++ = byte; byte = 0; } } if ( (j&0x7) != 0 ) *rbp++ = byte; if ( ImBinWrite( ioType, fd, fp, runBuffer, UCHAR, 1, n ) == -1) { free( (unsigned char *)runBuffer ); ImReturnBinError( ); } } free( (unsigned char *)runBuffer ); return ( 1 ); } static int /* Returns status */ #ifdef __STDC__ imRasWrite8( ImFileFormatWriteMap *pMap, int ioType, int fd, FILE *fp, TagTable *flagsTable, TagTable *tagTable ) #else imRasWrite8( 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; /* Flags */ TagTable *tagTable; /* Tag table to read from */ #endif { int i, j; /* Counters */ ImVfbPtr pptr; /* Pixel pointer */ unsigned char *rbp; /* Run buffer pointer */ ImVfb *vfb; /* VFB to write out */ unsigned char *runBuffer; /* Run buffer */ int n; /* # of bytes to write */ /* * Write out the header and possible CLT. */ TagEntryQValue( TagTableQDirect( tagTable, "image vfb", 0 ), &vfb ); BinByteOrder( BINMBF ); if ( imRasWriteHeaderClt( pMap, ioType, fd, fp, vfb, 8, IMRTSTANDARD ) == -1 ) return ( -1 ); /* Error already handled */ /* * Convert and write out the image. */ n = imRasHeader.ras_width * imRasHeader.ras_depth / 8;/* # bytes*/ if ( (n&1) != 0 ) n++; /* Pad to 2-byte boundary*/ ImMalloc( runBuffer, unsigned char *, sizeof( unsigned char ) * n ); runBuffer[n-1] = 0; /* Set the pad byte */ pptr = ImVfbQFirst( vfb ); for ( i = 0; i < imRasHeader.ras_height; i++ ) { rbp = runBuffer; for ( j = 0; j < imRasHeader.ras_width; j++ ) { *rbp++ = ImVfbQIndex8( vfb, pptr ); ImVfbSInc( vfb, pptr ); } if ( ImBinWrite( ioType, fd, fp, runBuffer, UCHAR, 1, n ) == -1) { free( (unsigned char *)runBuffer ); ImReturnBinError( ); } } free( (unsigned char *)runBuffer ); return ( 1 ); } static int /* Returns status */ #ifdef __STDC__ imRasWriteRGB( ImFileFormatWriteMap *pMap, int ioType, int fd, FILE *fp, TagTable *flagsTable, TagTable *tagTable ) #else imRasWriteRGB( 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; /* Flags */ TagTable *tagTable; /* Tag table to read from */ #endif { int i, j; /* Counters */ ImVfbPtr pptr; /* Pixel pointer */ unsigned char *rbp; /* Run buffer pointer */ ImVfb *vfb; /* VFB to write out */ unsigned char *runBuffer; /* Run buffer */ int n; /* # of bytes to write */ /* * Write out the header and possible CLT. */ TagEntryQValue( TagTableQDirect( tagTable, "image vfb", 0 ), &vfb ); BinByteOrder( BINMBF ); if ( imRasWriteHeaderClt( pMap, ioType, fd, fp, vfb, 24, IMRTSTANDARD ) == -1 ) return ( -1 ); /* Error already handled */ /* * Convert and write out the image. */ n = imRasHeader.ras_width * imRasHeader.ras_depth / 8; if ( (n&1) != 0 ) n++; /* Pad to 2-byte boundary*/ ImMalloc( runBuffer, unsigned char *, sizeof( unsigned char ) * n ); runBuffer[n-1] = 0; /* Set the pad byte */ pptr = ImVfbQFirst( vfb ); for ( i = 0; i < imRasHeader.ras_height; i++ ) { rbp = runBuffer; for ( j = 0; j < imRasHeader.ras_width; j++ ) { *rbp++ = ImVfbQBlue( vfb, pptr ); *rbp++ = ImVfbQGreen( vfb, pptr ); *rbp++ = ImVfbQRed( vfb, pptr ); ImVfbSInc( vfb, pptr ); } if ( ImBinWrite( ioType, fd, fp, runBuffer, UCHAR, 1, n ) == -1) { free( (unsigned char *)runBuffer ); ImReturnBinError( ); } } free( (unsigned char *)runBuffer ); return ( 1 ); } static int /* Returns status */ #ifdef __STDC__ imRasWriteRGBA( ImFileFormatWriteMap *pMap, int ioType, int fd, FILE *fp, TagTable *flagsTable, TagTable *tagTable ) #else imRasWriteRGBA( 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; /* Flags */ TagTable *tagTable; /* Tag table to read from */ #endif { int i, j; /* Counters */ ImVfbPtr pptr; /* Pixel pointer */ unsigned char *rbp; /* Run buffer pointer */ ImVfb *vfb; /* VFB to write out */ unsigned char *runBuffer; /* Run buffer */ int n; /* # of bytes to write */ /* * Write out the header and possible CLT. */ TagEntryQValue( TagTableQDirect( tagTable, "image vfb", 0 ), &vfb ); BinByteOrder( BINMBF ); if ( imRasWriteHeaderClt( pMap, ioType, fd, fp, vfb, 32, IMRTSTANDARD ) == -1 ) return ( -1 ); /* Error already handled */ /* * Convert and write out the image. */ n = imRasHeader.ras_width * imRasHeader.ras_depth / 8; if ( (n&1) != 0 ) n++; /* Pad to 2-byte boundary*/ ImMalloc( runBuffer, unsigned char *, sizeof( unsigned char ) * n ); runBuffer[n-1] = 0; /* Set the pad byte */ pptr = ImVfbQFirst( vfb ); for ( i = 0; i < imRasHeader.ras_height; i++ ) { rbp = runBuffer; for ( j = 0; j < imRasHeader.ras_width; j++ ) { *rbp++ = ImVfbQAlpha( vfb, pptr ); *rbp++ = ImVfbQBlue( vfb, pptr ); *rbp++ = ImVfbQGreen( vfb, pptr ); *rbp++ = ImVfbQRed( vfb, pptr ); ImVfbSInc( vfb, pptr ); } if ( ImBinWrite( ioType, fd, fp, runBuffer, UCHAR, 1, n ) == -1) { free( (unsigned char *)runBuffer ); ImReturnBinError( ); } } free( (unsigned char *)runBuffer ); return ( 1 ); } /* * MACROS * IMAddRun - add another pixel to RLE buffer * IMDumpRun - dump an RLE run into the run buffer * * DESCRIPTION * The 'index' pixel is added to the caller's run-length encoding * buffer. This involves checking if it differs from 'oldindex' * (the previous index value). * * If not, the run count is incremented. However, if it reaches 256, * we have to stop the run, copy it into the outgoing buffer, and * start a new run. * * If 'index' isn't the same as the current run index, then the run * is over. If it was a run of ESC values, the run is dumped as a * list of ESC,0 pairs. If the run was a count of 1, then the pixel * is dumped into the run buffer raw. Otherwise a run is dumped to * the run buffer. */ #define IMAddRun(count,oldindex,index,rbp,nBytes) \ { \ if ( (index) == (oldindex) ) \ { \ if ( ++(count) != 256 ) \ continue; \ /* Overflow. Dump run. */\ IMDumpRun( count, oldindex, index, rbp, nBytes ); \ (count) = 0; \ } \ else \ { \ /* End of run. Dump run. */\ IMDumpRun( count, oldindex, index, rbp, nBytes ); \ (oldindex) = (index); \ (count) = 1; \ } \ } #define IMDumpRun( count, oldindex, index, rbp, nBytes ) \ if ( (count) != 0 ) \ { \ if ( (oldindex) == IMRASESC ) \ { \ while ( (count)-- ) \ { \ *(rbp)++ = IMRASESC; \ *(rbp)++ = 0; \ (nBytes) += 2; \ } \ } \ else if ( count == 1 ) \ { \ /* Use the raw format. */\ *(rbp)++ = (oldindex); \ (nBytes)++; \ } \ else \ { \ /* Use count format. */\ *(rbp)++ = IMRASESC; \ *(rbp)++ = (count) - 1; \ *(rbp)++ = (oldindex); \ (nBytes)+= 3; \ } \ } /* * FUNCTION * imRasWriteRLE1 - write 1-bit encoded RAS format * imRasWriteRLE8 - write 8-bit encoded RAS format * imRasWriteRLERGB - write 24-bit RGB encoded RAS format * imRasWriteRLERGBA - write 32-bit RGBA encoded RAS format * * DESCRIPTION * Each of these routines deal with "encoded" format RAS files. * The output stream is a file. * * The header and CLT (if any) are written out. The VFB is then * converted and written out in chunks. When we are all done and * know how big the encoded image was, we seek back and fill in * the length field of the header. */ static int /* Returns status */ #ifdef __STDC__ imRasWriteRLE1( ImFileFormatWriteMap *pMap, int ioType, int fd, FILE *fp, TagTable *flagsTable, TagTable *tagTable ) #else imRasWriteRLE1( 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; /* Flags */ TagTable *tagTable; /* Tag table to read from */ #endif { int i, j, k; /* Counters */ ImVfbPtr pptr; /* Pixel pointer */ unsigned char *rbp; /* Run buffer pointer */ ImVfb *vfb; /* VFB to write out */ unsigned char *runBuffer; /* Run buffer */ int n; /* # of bytes to write */ int nBytes; /* # of bytes to write */ int count; /* Run length count */ int index; /* Run index */ int oldindex; /* Prevous run index */ int width; /* Width in bytes */ /* * Write out the header and possible CLT. */ TagEntryQValue( TagTableQDirect( tagTable, "image vfb", 0 ), &vfb ); BinByteOrder( BINMBF ); if ( imRasWriteHeaderClt( pMap, ioType, fd, fp, vfb, 1, IMRTBYTEENCODED ) == -1 ) return ( -1 ); /* Error already handled */ /* * Convert and write out the image. Maximum run buffer is twice * size of one scanline. */ width = (imRasHeader.ras_width + 7) / 8; n = 2 * width; ImMalloc( runBuffer, unsigned char *, sizeof( unsigned char ) * n ); pptr = ImVfbQFirst( vfb ); imRasHeader.ras_length = 0; for ( i = 0; i < imRasHeader.ras_height; i++ ) { rbp = runBuffer; nBytes = 0; count = 1; if ( imRasHeader.ras_width < 8 ) { for ( oldindex = 0, k = 0; k < imRasHeader.ras_width; k++ ) { oldindex <<= 1; if ( ImVfbQMono( vfb, pptr ) == 0 ) oldindex |= 1; ImVfbSInc( vfb, pptr ); } oldindex <<= (8-k); } else { for ( oldindex = 0, k = 0; k < 8; k++ ) { oldindex <<= 1; if ( ImVfbQMono( vfb, pptr ) == 0 ) oldindex |= 1; ImVfbSInc( vfb, pptr ); } } for ( j = k; j < imRasHeader.ras_width; ) { if ( imRasHeader.ras_width < (j+8) ) { for ( index = 0, k = 0; j < imRasHeader.ras_width; j++, k++ ) { index <<= 1; if ( ImVfbQMono( vfb, pptr ) == 0 ) index |= 1; ImVfbSInc( vfb, pptr ); } index <<= (8-k); } else { for ( index = 0, k = 0; k < 8; k++ ) { index <<= 1; if ( ImVfbQMono( vfb, pptr ) == 0 ) index |= 1; ImVfbSInc( vfb, pptr ); } j += 8; } IMAddRun( count, oldindex, index, rbp, nBytes ); } /* Dump last run. */ IMDumpRun( count, oldindex, index, rbp, nBytes ); if ( width & 0x1 ) { nBytes++; /* Strange 2-byte padding*/ *rbp++ = 0; } if ( ImBinWrite( ioType, fd, fp, runBuffer, UCHAR, 1, nBytes ) == -1 ) { free( (unsigned char *)runBuffer ); ImReturnBinError( ); } imRasHeader.ras_length += nBytes; } free( (unsigned char *)runBuffer ); /* * Seek back to the head of the file and rewrite the header. */ ImSeek( ioType, fd, fp, 0, 0 ); if ( ImBinWriteStruct( ioType, fd, fp, &imRasHeader, imRasHeaderFields ) == -1 ) { ImReturnBinError( ); } return ( 1 ); } static int /* Returns status */ #ifdef __STDC__ imRasWriteRLE8( ImFileFormatWriteMap *pMap, int ioType, int fd, FILE *fp, TagTable *flagsTable, TagTable *tagTable ) #else imRasWriteRLE8( 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; /* Flags */ TagTable *tagTable; /* Tag table to read from */ #endif { int i, j; /* Counters */ ImVfbPtr pptr; /* Pixel pointer */ unsigned char *rbp; /* Run buffer pointer */ ImVfb *vfb; /* VFB to write out */ unsigned char *runBuffer; /* Run buffer */ int n; /* # of bytes to write */ int nBytes; /* # of bytes to write */ int count; /* Run length count */ int index; /* Run index */ int oldindex; /* Prevous run index */ /* * Write out the header and possible CLT. */ TagEntryQValue( TagTableQDirect( tagTable, "image vfb", 0 ), &vfb ); BinByteOrder( BINMBF ); if ( imRasWriteHeaderClt( pMap, ioType, fd, fp, vfb, 8, IMRTBYTEENCODED ) == -1 ) return ( -1 ); /* Error already handled */ /* * Convert and write out the image. Maximum run buffer is twice * size of one scanline. */ n = 2 * imRasHeader.ras_width * imRasHeader.ras_depth / 8; ImMalloc( runBuffer, unsigned char *, sizeof( unsigned char ) * n ); pptr = ImVfbQFirst( vfb ); imRasHeader.ras_length = 0; for ( i = 0; i < imRasHeader.ras_height; i++ ) { rbp = runBuffer; nBytes = 0; count = 1; oldindex = ImVfbQIndex8( vfb, pptr ); ImVfbSInc( vfb, pptr ); for ( j = 1; j < imRasHeader.ras_width; j++ ) { index = ImVfbQIndex8( vfb, pptr ); ImVfbSInc( vfb, pptr ); IMAddRun( count, oldindex, index, rbp, nBytes ); } /* Dump last run. */ IMDumpRun( count, oldindex, index, rbp, nBytes ); if ( imRasHeader.ras_width & 0x1 ) { nBytes++; /* Strange 2-byte padding*/ *rbp++ = 0; } if ( ImBinWrite( ioType, fd, fp, runBuffer, UCHAR, 1, nBytes ) == -1 ) { free( (unsigned char *)runBuffer ); ImReturnBinError( ); } imRasHeader.ras_length += nBytes; } free( (unsigned char *)runBuffer ); /* * Seek back to the head of the file and rewrite the header. */ ImSeek( ioType, fd, fp, 0, 0 ); if ( ImBinWriteStruct( ioType, fd, fp, &imRasHeader, imRasHeaderFields ) == -1 ) { ImReturnBinError( ); } return ( 1 ); } static int /* Returns status */ #ifdef __STDC__ imRasWriteRLERGB( ImFileFormatWriteMap *pMap, int ioType, int fd, FILE *fp, TagTable *flagsTable, TagTable *tagTable ) #else imRasWriteRLERGB( 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; /* Flags */ TagTable *tagTable; /* Tag table to read from */ #endif { int i, j; /* Counters */ ImVfbPtr pptr; /* Pixel pointer */ unsigned char *rbp; /* Run buffer pointer */ ImVfb *vfb; /* VFB to write out */ unsigned char *runBuffer; /* Run buffer */ int nBytes; /* # of bytes to write */ int count; /* Run length count */ int index; /* Run index */ int oldindex; /* Prevous run index */ int onRGB; /* Which channel from VFB next? */ int n; /* # of bytes to write */ /* * Write out the header and possible CLT. */ TagEntryQValue( TagTableQDirect( tagTable, "image vfb", 0 ), &vfb ); BinByteOrder( BINMBF ); if ( imRasWriteHeaderClt( pMap, ioType, fd, fp, vfb, 24, IMRTBYTEENCODED ) == -1 ) return ( -1 ); /* Error already handled */ /* * Convert and write out the image. Maximum run buffer is twice * size of one scanline. */ n = 2 * imRasHeader.ras_width * imRasHeader.ras_depth / 8; ImMalloc( runBuffer, unsigned char *, sizeof( unsigned char ) * n ); pptr = ImVfbQFirst( vfb ); imRasHeader.ras_length = 0; for ( i = 0; i < imRasHeader.ras_height; i++ ) { rbp = runBuffer; nBytes = 0; count = 1; oldindex = ImVfbQBlue( vfb, pptr ); onRGB = IMRAS_GREEN; for ( j = 1; j < imRasHeader.ras_width*3; j++ ) { switch ( onRGB ) { case IMRAS_BLUE: /* Get IMRAS_BLUE next. */ index = ImVfbQBlue( vfb, pptr ); onRGB = IMRAS_GREEN; break; case IMRAS_GREEN: /* Get IMRAS_GREEN next. */ index = ImVfbQGreen( vfb, pptr ); onRGB = IMRAS_RED; break; case IMRAS_RED: /* Get IMRAS_RED next. */ index = ImVfbQRed( vfb, pptr ); ImVfbSInc( vfb, pptr ); onRGB = IMRAS_BLUE; break; } IMAddRun( count, oldindex, index, rbp, nBytes ); } /* Dump last run. */ IMDumpRun( count, oldindex, index, rbp, nBytes ); if ( imRasHeader.ras_width & 0x1 ) { nBytes++; /* Strange 2-byte padding*/ *rbp++ = 0; } if ( ImBinWrite( ioType, fd, fp, runBuffer, UCHAR, 1, nBytes ) == -1 ) { free( (unsigned char *)runBuffer ); ImReturnBinError( ); } imRasHeader.ras_length += nBytes; } free( (unsigned char *)runBuffer ); /* * Seek back to the head of the file and rewrite the header. */ ImSeek( ioType, fd, fp, 0, 0 ); if ( ImBinWriteStruct( ioType, fd, fp, &imRasHeader, imRasHeaderFields ) == -1 ) { ImReturnBinError( ); } return ( 1 ); } static int /* Returns status */ #ifdef __STDC__ imRasWriteRLERGBA( ImFileFormatWriteMap *pMap, int ioType, int fd, FILE *fp, TagTable *flagsTable, TagTable *tagTable ) #else imRasWriteRLERGBA( 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; /* Flags */ TagTable *tagTable; /* Tag table to read from */ #endif { int i, j; /* Counters */ ImVfbPtr pptr; /* Pixel pointer */ unsigned char *rbp; /* Run buffer pointer */ ImVfb *vfb; /* VFB to write out */ unsigned char *runBuffer; /* Run buffer */ int nBytes; /* # of bytes to write */ int count; /* Run length count */ int index; /* Run index */ int oldindex; /* Prevous run index */ int onRGB; /* Which channel from VFB next? */ int n; /* # of bytes to write */ /* * Write out the header and possible CLT. */ TagEntryQValue( TagTableQDirect( tagTable, "image vfb", 0 ), &vfb ); BinByteOrder( BINMBF ); if ( imRasWriteHeaderClt( pMap, ioType, fd, fp, vfb, 32, IMRTBYTEENCODED ) == -1 ) return ( -1 ); /* Error already handled */ /* * Convert and write out the image. Maximum run buffer is twice * size of one scanline. */ n = 2 * imRasHeader.ras_width * imRasHeader.ras_depth / 8; ImMalloc( runBuffer, unsigned char *, sizeof( unsigned char ) * n ); pptr = ImVfbQFirst( vfb ); imRasHeader.ras_length = 0; for ( i = 0; i < imRasHeader.ras_height; i++ ) { rbp = runBuffer; nBytes = 0; count = 1; oldindex = ImVfbQAlpha( vfb, pptr ); onRGB = IMRAS_BLUE; for ( j = 1; j < imRasHeader.ras_width*4; j++ ) { switch ( onRGB ) { case IMRAS_ALPHA: /* Get IMRAS_ALPHA next. */ index = ImVfbQAlpha( vfb, pptr ); onRGB = IMRAS_BLUE; break; case IMRAS_BLUE: /* Get IMRAS_BLUE next. */ index = ImVfbQBlue( vfb, pptr ); onRGB = IMRAS_GREEN; break; case IMRAS_GREEN: /* Get IMRAS_GREEN next. */ index = ImVfbQGreen( vfb, pptr ); onRGB = IMRAS_RED; break; case IMRAS_RED: /* Get IMRAS_RED next. */ index = ImVfbQRed( vfb, pptr ); ImVfbSInc( vfb, pptr ); onRGB = IMRAS_ALPHA; break; } IMAddRun( count, oldindex, index, rbp, nBytes ); } /* Dump last run. */ IMDumpRun( count, oldindex, index, rbp, nBytes ); if ( ImBinWrite( ioType, fd, fp, runBuffer, UCHAR, 1, nBytes ) == -1 ) { free( (unsigned char *)runBuffer ); ImReturnBinError( ); } imRasHeader.ras_length += nBytes; } free( (unsigned char *)runBuffer ); /* * Seek back to the head of the file and rewrite the header. */ ImSeek( ioType, fd, fp, 0, 0 ); if ( ImBinWriteStruct( ioType, fd, fp, &imRasHeader, imRasHeaderFields ) == -1 ) { ImReturnBinError( ); } return ( 1 ); }