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

5208 lines
83 KiB
C

/** $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:
** <escape> <count> <index>
**
** 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:
** <escape> <0>
**
** To avoid expanding the storage size of images without any runs (like
** the ubiquitous Mandrill), just give the index by itself:
** <index>
**
** The worst case scenario is an image filled with "escape" bytes.
** Each "escape" byte will be expanded into an <escape> <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 );
}