jedioutcast/utils/roq2/libim/imrla.c
2013-04-04 13:07:40 -05:00

2435 lines
40 KiB
C

/**
** $Header: /roq/libim/imrla.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/imrla.c 1 11/02/99 4:38p Zaphod $"
/**
** FILE
** imrla.c - Wavefront RLA/RLB file I/O
**
** PROJECT
** libim - SDSC image manipulation library
**
** DESCRIPTION
** imrla.c contains routines to read and write Wavefront RLA/RLB files for
** the image manipulation library.
**
** NOTE: rla files have their origin in the lower left corner. VFBs
** have their origin in the upper left corner so we have to read and
** write our VFB scanlines in reverse order.
**
** PUBLIC CONTENTS
** d =defined constant
** f =function
** m =defined macro
** t =typedef/struct/union
** v =variable
** ? =other
**
** PRIVATE CONTENTS
**
** imRlaRead f read a Wavefront RLA/RLB file
** imRlaWrite f write a Wavefront RLA/RLB file
**
** NULL d an empty pointer
**
** imRlaHeaderInfo t RLA header
** imRlaHeaderFields t RLA header description for Bin pkg
** imRlaPrHeader f Debug routine for printing header
** imRlaPrWindow f Debug routine for printing header
** imRlaDecode f decode one scanline of pixel values
** imRlaEncode f encode one scanline of pixel values
**
** HISTORY
** $Log: /roq/libim/imrla.c $
*
* 1 11/02/99 4:38p Zaphod
** Revision 1.23 1995/06/30 22:09:41 bduggan
** fixed very weird bug with c++ on decalpha.
** (prob'ly a compiler bug.)
**
** Revision 1.22 1995/06/29 00:28:04 bduggan
** updated copyright year
**
** Revision 1.21 1995/06/15 21:12:27 bduggan
** changed bzero to memset. added include
**
** Revision 1.20 1995/04/03 21:36:19 bduggan
** took out #ifdef NEWMAGIC
**
** Revision 1.19 1995/01/10 23:42:38 bduggan
** put in IMMULTI, IMPIPE instead of TRUE/FALSE
** made read/write routines static
**
** Revision 1.18 94/10/03 11:30:53 nadeau
** Updated to ANSI C and C++ compatibility.
** Removed all use of register keyword.
** Minimized use of custom SDSC types (e.g., uchar vs. unsigned char)
** Changed all float arguments to double.
** Added forward declarations.
** Added misc. casts to passify SGI and DEC compilers.
** Changed all macros and defined constants to have names
** starting with IM.
** Rearranged magic number structures for format handlers.
** Made format handler routines static (i.e., local to file).
** Updated comments, adding format descriptions and references.
** Updated indenting on some code.
** Updated copyright message.
**
** Revision 1.17 93/09/22 11:41:33 nadeau
** Corrected resolution calculation for info message.
**
** Revision 1.16 92/12/03 01:52:08 nadeau
** Corrected info messages.
**
** Revision 1.15 92/11/04 12:07:00 groening
** put ImFIleFormat info and magic number info
** from imfmt.c into this file.
**
** Revision 1.14 92/10/19 14:11:06 groening
** added ImInfo statements
**
** Revision 1.13 92/08/31 17:34:37 vle
** Updated copyright notice.
**
** Revision 1.12 91/10/04 08:40:11 nadeau
** Fixed bad strcpy.
**
** Revision 1.11 91/10/03 09:18:08 nadeau
** Removed bogus PVFILE header field and merged with
** GAMMA field. Rearranged RGB read and write loops.
** Expanded window structure into header structure to
** avoid struct padding quirks of some C compilers.
**
** Revision 1.10 91/03/18 15:45:37 todd
** added a call to bzero to fix a bug on the cray
**
** Revision 1.9 91/02/12 11:37:21 nadeau
** Removed the tag table checking and VFB conversion now
** handled by ImFileRead and ImFileWrite. Removed pipe
** handling.
**
** Revision 1.8 91/01/29 11:09:44 todd
** make alpha channel optional
**
** Revision 1.7 90/11/30 14:39:48 mercurio
** Unchanged wrt 1.6
**
** Revision 1.6 90/09/07 16:02:38 mercurio
** Read function now clears VFB to all zeros before filling (important--
** since only the active area is filled explicitly).
**
** Revision 1.5 90/07/25 14:23:24 mercurio
** Fixed read routine to read entire window, not just active window
**
** Revision 1.4 90/07/02 13:21:56 nadeau
** Updated to the new error handling mechanism.
**
** Revision 1.3 90/06/25 14:47:39 nadeau
** Changed ImTag* to Tag* (new names).
**
** Revision 1.2 90/06/25 13:19:49 todd
** Lots of changes and functionality added. Works with pipes.
** Both RLA and RLB formats accepted. Fixed bugs. Tested.
**
** Revision 1.1 90/04/11 08:37:46 todd
** Initial revision
**
**
**/
/**
** FORMAT
** RLA - Wavefront run length encoded format
**
** AKA
** .rlb, .rle
**
** FORMAT REFERENCES
** Run Length Encoded File Format, ".rla", Techinal Memo 860605,
** Wavefront Technologies
**
** CODE CREDITS
** Custom development, Dave Nadeau, San Diego Supercomputer Center, 1990.
** Custom development, Todd Elvins, San Diego Supercomputer Center, 1990.
**
** DESCRIPTION
**
** All data in these files are stored Most Significant Byte first.
** The files are sequential scan-line write, and random scan-line read. A
** scanline offset table is used to locate the beginning of each encoded
** scanline within the file.
**
** The file is organized into three sections:
** - header 740 bytes
** - offset table 4*(y resolution;( # of scanlines) bytes
** - encoded channel data variable length
**
** ======
** Header
** ======
**
** short window_left; Boundaries of complete image
** short window_right;
** short window_bottom;
** short window_top;
** short active_window_left; Boundaries of non-zero image
** short active_window_right;
** short active_window_bottom;
** short active_window_top;
**
** The active_window values specify the dimensions for what is encoded.
** The window values specify the dimensions for the complete image.
**
** short frame; Frame number
**
** The frame number in a sequence of frames.
**
** short storage_type; Byte or word data
**
** Specifies whether it is byte or word data.
**
** short num_chan; Number of image channels
**
** Typically 3 for R,G,B.
**
** short num_matte; Number of matte channels
**
** 0 = no alpha channel. 1 = alpha channel.
** Could be more if the transparency information includes spectral
** information.
**
** short num_aux; Number of aux channels
** short aux_mask; Aux channel type mask
**
** num_aux is the number of auxillary channels. Auxillary channel
** information could include distance from the eye, direction of normal,
** etc. There are typically 0 auxillary channels.
** aux_mask is a bitmask that describes what is in the auxiallry channels.
** The interpretation of this bitmask is governed by the fmt__aux_chan
** table in the system configuration file.
**
** char gamma[IMRLANGAMMA]; Image storage gamma
**
** Floating point number: gamma that was applied to the file for storage.
**
** char red_pri[IMRLANPRI]; Image red primary chromaticity
** char green_pri[IMRLANPRI]; Image grn primary chromaticity
** char blue_pri[IMRLANPRI]; Image blu primary chromaticity
** char white_pt[IMRLANPRI]; White point
**
** Chromaticities of the red, green, and blue primaries, and the white
** point that were used to store the image, if it was an rgb image.
** Each field contains the x,y chromaticity as two floating point
** numbers seperated by a space.
**
** int job_num; Job Number
** char name[IMRLANNAME]; Original file name
** char desc[IMRLANNAME]; File description number
** char program[IMRLANPROG]; Creating program name
** char machine[IMRLANSTR]; Creating machine name
** char user[IMRLANSTR]; Creating user
** char date[IMRLANDATE]; Creation date
**
** Various informative pieces of data.
**
** char aspect[IMRLANASPECT]; Image aspect type
** char aspect_ratio[IMRLANAR]; Image aspect ratio
**
** Aspect ratio for the image.
**
** char chan[IMRLANSTR]; Image color space type
**
** Must be 'rgb'
**
** short field; Rendered on fields flag
** short filter_type; Post filtered interleaved flag
** int magic_number; unused
** int lut_size; unused
** int user_space_size; unused
** int wf_space_size; unused
** short lut_type; unused
** short mix_type; unused
** short encode_type; unused
** short padding; unused
** char space[IMRLANSPACE]; Unused expansion space
**
** Unused fields.
**
** ============
** Offset Table
** ============
**
** The length of each encoded scanline varies, depending on how well the
** encoding algorithm compresses the scanline. The offset table contains
** the starting positions of each scanline.
**
** ====================
** Encoded Channel Data
** ====================
**
** All of the data for one particular scanline appears sequentially in
** a file. If an image has an r,g,b, and alpha channel, then there will
** be a record for the red channel, followed by a record for the green
** channel, followed by a record for the blue channel, followed by a
** record for the alpha channel.
** The offset (from the offset table) points to the beginning of the record
** for the red channel. A record is of the form:
**
** - length 2 bytes
** - encoded string data length bytes
**
** The encoding scheme is fairly simple. It consists of a series of 'run's.
** There are two types of runs: verbatim and compressed. A run looks
** like this:
**
** - count 2 byte signed integer
** - data MAX(1,-count) bytes of data
**
** If the count is positive then this is a compressed run. In this case,
** the data is simply a value, which is to be repeated count+1 times.
**
** If the count is negative, then the next -count bytes of data are to be
** copied verbatim into the image.
**
** Data is not compressed if the repeat count is two or less.
**/
#include <time.h>
//#include <pwd.h>
#include "iminternal.h"
/*
* RLA/RLB - Wavefront image file
* For information on these structures, how to use them, etc. please
* see imfmt.c.
*/
#ifdef __STDC__
static int imRlaRead( int ioType, int fd, FILE *fp, TagTable *flagsTable, TagTable *tagTable );
static int imRlaWrite( ImFileFormatWriteMap *pMap, int ioType, int fd, FILE *fp, TagTable *flagsTable, TagTable *tagTable );
#else
static int imRlaRead( ), imRlaWrite( );
#endif
static char *imRlaNames[ ] = { "rla", "rlb", NULL };
static ImFileFormatReadMap imRlaReadMap[ ] =
{
/* in out */
/* type,ch,dep, attr. VFB type attr. */
{ RGB,3,8, RLE, IMVFBRGB, 0 },
{ RGB,3,8, RLE|A, IMVFBRGB, A },
{ -1, 0, -1, 0 },
};
static ImFileFormatWriteMap imRlaWriteMap[ ] =
{
/* in out */
/* VFB type, attr., type,ch,dep, attr., func */
{ IMVFBRGB, 0, RGB,3,8, RLE|A, imRlaWrite },
{ IMVFBRGB, A, RGB,3,8, RLE|A, imRlaWrite },
{ -1, 0, -1, 0, NULL },
};
static ImFileMagic imFileRlaMagic []=
{
{ 0, 0, NULL },
};
ImFileFormat ImFileRlaFormat =
{
imRlaNames, "Wavefront raster image file",
"Wavefront",
"24-bit RGB and 32-bit RGB+alpha RLE-compressed image files in both\n\
RLB and the older RLA format.",
"24-bit RGB and 32-bit RGB+alpha RLE-compressed image files in RLB\n\
format.",
imFileRlaMagic,
IMNOMULTI, IMNOPIPE,
IMNOMULTI, IMNOPIPE,
imRlaRead, imRlaReadMap, imRlaWriteMap
};
/*
* TYPEDEF & STRUCTURE
* imRlaHeaderInfo - RLA file header information
* imRlaHeaderFields - Description for Binio package
*
* DESCRIPTION
* A RLA file's header contains the image's width, height, and depth,
* and many other fields.
*/
#define IMRLANGAMMA (16)
#define IMRLANPRI (24)
#define IMRLANNAME (128)
#define IMRLANPROG (64)
#define IMRLANSTR (32)
#define IMRLANDATE (20)
#define IMRLANASPECT (24)
#define IMRLANAR (8)
#define IMRLANSPACE (100)
#define IMRLAHEADERSIZE (740)
typedef struct imRlaHeaderInfo
{
short window_left; /* Boundaries of complete image */
short window_right;
short window_bottom;
short window_top;
short active_window_left; /* Boundaries of non-zero image */
short active_window_right;
short active_window_bottom;
short active_window_top;
short frame; /* Frame number */
short storage_type; /* Byte or word data */
short num_chan; /* Number of image channels */
short num_matte; /* Number of matte channels */
short num_aux; /* Number of aux channels */
short aux_mask; /* Aux channel type mask */
char gamma[IMRLANGAMMA]; /* Image storage gamma */
char red_pri[IMRLANPRI]; /* Image red primary chromaticity */
char green_pri[IMRLANPRI]; /* Image grn primary chromaticity */
char blue_pri[IMRLANPRI]; /* Image blu primary chromaticity */
char white_pt[IMRLANPRI]; /* White point */
int job_num; /* Job Number */
char name[IMRLANNAME]; /* Original file name */
char desc[IMRLANNAME]; /* File description number */
char program[IMRLANPROG]; /* Creating program name */
char machine[IMRLANSTR]; /* Creating machine name */
char user[IMRLANSTR]; /* Creating user */
char date[IMRLANDATE]; /* Creation date */
char aspect[IMRLANASPECT]; /* Image aspect type */
char aspect_ratio[IMRLANAR]; /* Image aspect ratio */
char chan[IMRLANSTR]; /* Image color space type */
short field; /* Rendered on fields flag */
short filter_type; /* Post filtered interleaved flag*/
int magic_number; /* unused */
int lut_size; /* unused */
int user_space_size; /* unused */
int wf_space_size; /* unused */
short lut_type; /* unused */
short mix_type; /* unused */
short encode_type; /* unused */
short padding; /* unused */
char space[IMRLANSPACE]; /* Unused expansion space */
} imRlaHeaderInfo;
BinField imRlaHeaderFields[ ] =
{
{ SHORT, 2, 1 }, /* Window boundaries */
{ SHORT, 2, 1 },
{ SHORT, 2, 1 },
{ SHORT, 2, 1 },
{ SHORT, 2, 1 }, /* Active window boundaries */
{ SHORT, 2, 1 },
{ SHORT, 2, 1 },
{ SHORT, 2, 1 },
{ SHORT, 2, 1 }, /* Frame */
{ SHORT, 2, 1 }, /* Storage type */
{ SHORT, 2, 1 }, /* Number of image channels */
{ SHORT, 2, 1 }, /* Number of matte channels */
{ SHORT, 2, 1 }, /* Number of aux channels */
{ SHORT, 2, 1 }, /* Aux channel type mask */
{ CHAR, 1, IMRLANGAMMA }, /* Image storage gamma */
{ CHAR, 1, IMRLANPRI }, /* Image red primary chromaticity */
{ CHAR, 1, IMRLANPRI }, /* Image grn primary chromaticity */
{ CHAR, 1, IMRLANPRI }, /* Image blu primary chromaticity */
{ CHAR, 1, IMRLANPRI }, /* Image whi primary chromaticity */
{ INT, 4, 1 }, /* Job number */
{ CHAR, 1, IMRLANNAME }, /* Original file name */
{ CHAR, 1, IMRLANNAME }, /* File description */
{ CHAR, 1, IMRLANPROG }, /* Creating program name */
{ CHAR, 1, IMRLANSTR }, /* Creating machine name */
{ CHAR, 1, IMRLANSTR }, /* Creating user name */
{ CHAR, 1, IMRLANDATE }, /* Creation date */
{ CHAR, 1, IMRLANASPECT }, /* Image aspect type */
{ CHAR, 1, IMRLANAR }, /* Image aspect ratio */
{ CHAR, 1, IMRLANSTR }, /* Image color space type */
{ SHORT, 2, 1 }, /* Rendered on fields flag */
{ SHORT, 2, 1 }, /* Post filtered interleaved flag*/
{ INT, 4, 1 }, /* unused */
{ INT, 4, 1 }, /* unused */
{ INT, 4, 1 }, /* unused */
{ INT, 4, 1 }, /* unused */
{ SHORT, 2, 1 }, /* unused */
{ SHORT, 2, 1 }, /* unused */
{ SHORT, 2, 1 }, /* unused */
{ SHORT, 2, 1 }, /* unused */
{ CHAR, 1, IMRLANSPACE }, /* Unused expansion space */
{ 0, 0, 0 }
};
/*
* MACRO
* imRlaFrBuf - Free six chunks of memory
*
* DESCRIPTION
* Call free six times to free the six chunks of memory pointed to by
* a-f.
*/
#define imRlaFrBuf(a,b,c,d,e,f) free((a));free((b));free((c));free((d));free((e));free((f))
/*
* FUNCTION
* imPrRlaHeader - print out the header of a rla file
*
* DESCRIPTION
* The contents of the ImRlaHeader structure is printed on the
* standard error.
*/
static void
#ifdef __STDC__
imRlaPrHeader(imRlaHeaderInfo *p)
#else
imRlaPrHeader(p)
imRlaHeaderInfo *p;
#endif
{
char message[200]; /* contains information for ImInfo */
ImInfo ("Image Name", p->name);
ImInfo ("Byte Order", "Most Significant Byte First");
sprintf (message, "%d x %d",
( (p->active_window_right) - (p->active_window_left) + 1),
( (p->active_window_top) - (p->active_window_bottom) + 1));
ImInfo ("Resolution", message);
if (p->storage_type==0)
sprintf ( message , "24 bit RGB");
else sprintf ( message , "3 word RGB");
ImInfo ("Type",message);
if (p->num_matte>0)
{
if (p->storage_type==0)
sprintf ( message , "8 bit");
else sprintf ( message , "1 word");
}
else sprintf (message, "None");
ImInfo ("Alpha Channel", message);
#ifdef DEBUG
fprintf(stderr,"Channels: Image %d Matte %d Aux %d Aux Mask %02x\n",
p->num_chan, p->num_matte, p->num_aux, p->aux_mask);
fprintf(stderr,"Job Number %ld Name \"%s\"\n",p->job_num,p->name);
fprintf(stderr,"Desc \"%s\"\n",p->desc);
fprintf(stderr,"Program \"%s\" Machine \"%s\"\n",p->program,p->machine);
fprintf(stderr,"User %s Date %s Aspect %s Aspect ratio %s\n",
p->user,p->date,p->aspect,p->aspect_ratio);
fprintf(stderr,"Chan %s Field %d Filter_type %d Magic %d\n",
p->chan, p->field, p->filter_type, p->magic_number );
#endif
sprintf (message, "%d", p->frame);
ImInfo ("Frame Number", message);
ImInfo ( "Gamma", p->gamma);
ImInfo ( "Red Primary", p->red_pri);
ImInfo ( "Green Primary", p->green_pri);
ImInfo ( "Blue Primary", p->blue_pri);
ImInfo ( "White Point", p->white_pt);
}
/*
* FUNCTION
* imRlaDecode - decode one channel of one scanline
*
* DESCRIPTION
* One channel of one scanline (cIn) in Wavefront RLA format is decoded
* and returned in cOut. len is the number of bytes in cIn.
*/
static void
#ifdef __STDC__
imRlaDecode( unsigned char *cIn, unsigned char *cOut, int len )
#else
imRlaDecode( cIn, cOut, len )
unsigned char *cIn;
unsigned char *cOut;
int len;
#endif
{
int cnt;
/*
* Loop through the bytes to be decoded
*/
while( len > 0 )
{
cnt = *cIn++;
len--;
if ( cnt < 128 )
{
/*
* Repeat pixel value cnt+1 times
*/
while ( cnt-- >= 0 )
*cOut++ = *cIn;
cIn++;
len--;
}
else
/*
* Just copy the unencoded bytes directly
*/
for ( cnt=256-cnt; cnt-- > 0; len-- )
*cOut++ = *cIn++;
}
}
/*
* FUNCTION
* imRlaRead - read an Wavefront RLA file
*
* DESCRIPTION
* The file header is read and the size of the image determined.
* Space is allocated for the VFB and the run codes read in to
* a run buffer. The run buffer is then expanded into straight
* RGB values in the VFB and the completed VFB added to the tag table.
*/
static int /* Returns # tags read in */
#ifdef __STDC__
imRlaRead( int ioType, int fd, FILE *fp, TagTable *flagsTable, TagTable *tagTable )
#else
imRlaRead( 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 list to add to */
#endif
{
ImVfb *vfb; /* Read in image */
ImVfbPtr pptr; /* Pixel pointer */
ImVfbPtr leftpptr; /* Points to start of scanlines */
imRlaHeaderInfo header; /* RLA file header */
unsigned char *redBuf; /* Run buffer */
unsigned char *grnBuf; /* Run buffer */
unsigned char *bluBuf; /* Run buffer */
unsigned char *alpBuf; /* Run buffer */
unsigned char *buf; /* Run buffer */
short len; /* Number of bytes unencoded */
int *offsetTable; /* Array of scanline offsets */
int status; /* Status returned from seek */
int x,y,dep; /* Convenient short names */
int i,j; /* Loop counters */
int width; /* true width of image */
int height; /* true height of image */
int bPad; /* bottom padding amount */
int lPad; /* left padding amount */
unsigned char* freak; /* See the paragraph below */
/* The variable 'freak' is to have a totally gratuitous
* cast from an int into an unsigned char*. The purpose
* of this is to stop the decalpha c++ compiler from making
* some sort of weird crazy screwed up optimization that
* results in an endless loop.
*
* I don't understand why this works. But take out the
* cast, and this routine won't work on decalpha's with c++.
*
* You don't believe me? Try it!
*
* I haven't had enough free time to investigate this compiler
* bug, or pinpoint it very well.
*/
/*
* RLA files are usually generated on Irises, which have an MBF
* byte order. There is no floating point in the file so we
* won't bother setting the float format for BIN.
*/
BinByteOrder( BINMBF );
/*
* Read in the header.
*/
if (ImBinReadStruct(ioType, fd, fp, &header, imRlaHeaderFields ) == -1)
{
ImReturnBinError( );
}
imRlaPrHeader( &header );
width = 1 + header.window_right - header.window_left;
height = 1 + header.window_top - header.window_bottom;
x = 1 + header.active_window_right - header.active_window_left;
y = 1 + header.active_window_top - header.active_window_bottom;
bPad = (int) (header.active_window_bottom - header.window_bottom);
lPad = (int) (header.active_window_left - header.window_left);
/*
* Here's the moronic hack of all hacks to defeat
* the evil decalpha c++ compiler:
*/
freak = (unsigned char*)&lPad;
dep = header.num_chan + header.num_matte;
/*
* Check the important header parameters for legal bounds.
* header.chan must be 'rgb'
* x and y must have positive active window size
* image depth must be 3 (RGB) or 4 (RGBA)
* header.num_aux must be 0
*
* We'd like to check these as well, however while RLB files have
* them, RLA files don't, so we just skip checking their values.
* header.field must be 0
* header.magic_number must be 0
* header.filter_type must be 0
*/
if ((strcmp( header.chan, "rgb" ) != 0) || x < 1 || y < 1 ||
(dep != 4 && dep != 3) || header.num_aux != 0 )
{
ImErrNo = IMESYNTAX;
ImErrorFatal( ImQError( ), -1, ImErrNo );
}
/*
* Allocate space for the offset table and read it in
*/
ImMalloc( offsetTable, int *, sizeof(int) * y );
if ( ImBinRead( ioType, fd, fp, offsetTable, INT, 4, y ) == -1 )
{
free( (char *)offsetTable );
ImReturnBinError( );
}
/*
* Allocate a VFB of the required size and clear it.
*/
if ( header.num_matte == 1 )
vfb = ImVfbAlloc( width, height, IMVFBRGB | IMVFBALPHA );
else
vfb = ImVfbAlloc( width, height, IMVFBRGB );
if ( vfb == IMVFBNULL )
{
free( (char *)offsetTable );
ImErrorFatal( ImQError( ), -1, ImErrNo );
}
ImVfbClear( ImVfbQFields( vfb ), 0, vfb );
/*
* Allocate run buffers large enough for one scanline per channel.
*/
ImCalloc( redBuf, unsigned char *, x, 1 );
ImCalloc( grnBuf, unsigned char *, x, 1 );
ImCalloc( bluBuf, unsigned char *, x, 1 );
ImCalloc( alpBuf, unsigned char *, x, 1 );
ImCalloc( buf, unsigned char *, x*2, 1 );
/*
* Loop through the scan lines. Read in a scanline and decode it.
* Once all of the channels are decoded, copy them into the vfb,
* going from bottom to top.
*/
pptr = leftpptr = ImVfbQPtr( vfb, 0, height-bPad-1 );
for( i=0; i<y; i++ )
{
ImSeek( ioType, fd, fp, offsetTable[i], 0 );
for ( j = 0; j < dep; j++ )
{
if (ImBinRead(ioType, fd, fp, &len, SHORT, 2, 1 ) == -1)
{
imRlaFrBuf( redBuf, grnBuf, bluBuf, alpBuf,
buf, offsetTable );
ImReturnBinError( );
}
if ( len == 0 )
{
imRlaFrBuf( redBuf, grnBuf, bluBuf, alpBuf,
buf, offsetTable );
ImErrNo = IMESYNTAX;
ImErrorFatal( "Bad scanline encoding", -1,
ImErrNo );
}
if (ImBinRead(ioType, fd, fp, buf, UCHAR, 1, len )== -1)
{
imRlaFrBuf( redBuf, grnBuf, bluBuf, alpBuf,
buf, offsetTable );
ImReturnBinError( );
}
switch ( j )
{
case 0: imRlaDecode( buf, redBuf, len ); break;
case 1: imRlaDecode( buf, grnBuf, len ); break;
case 2: imRlaDecode( buf, bluBuf, len ); break;
case 3: imRlaDecode( buf, alpBuf, len ); break;
}
}
/*
* Skip over left padding area
*/
for ( j = 0; j < lPad; j++ )
{
ImVfbSInc( vfb, pptr );
}
/*
* Copy the buffers into the vfb
*/
if ( header.num_matte == 1 )
{
for ( j = 0; j < x; j++ )
{
ImVfbSRed( vfb, pptr, redBuf[j] );
ImVfbSGreen( vfb, pptr, grnBuf[j] );
ImVfbSBlue( vfb, pptr, bluBuf[j] );
ImVfbSAlpha( vfb, pptr, alpBuf[j] );
ImVfbSInc( vfb, pptr );
}
}
else
{
for ( j = 0; j < x; j++ )
{
ImVfbSRed( vfb, pptr, redBuf[j] );
ImVfbSGreen( vfb, pptr, grnBuf[j] );
ImVfbSBlue( vfb, pptr, bluBuf[j] );
ImVfbSInc( vfb, pptr );
}
}
/*
* Position leftpptr at the beginning of the scanline above
*/
ImVfbSUp( vfb, leftpptr );
pptr = leftpptr;
}
/*
* Add the VFB to the tagTable.
*/
TagTableAppend( tagTable, TagEntryAlloc( "image vfb", POINTER, &vfb ) );
/*
* Free the pixel storage arrays
*/
imRlaFrBuf(redBuf,grnBuf,bluBuf,alpBuf,buf,offsetTable);
return ( 1 );
}
/*
* FUNCTION
* imRlaEncode - encode one channel of one scanline
*
* DESCRIPTION
* One unencoded channel of one scanline (cIn) is encoded into
* Wavefront RLA format and returned in cOut.
*/
static int /* Returns # of encoded bytes */
#ifdef __STDC__
imRlaEncode( unsigned char *cOut, unsigned char *cIn, int width )
#else
imRlaEncode( cOut, cIn, width )
unsigned char *cOut; /* Returned encoded bytes */
unsigned char *cIn; /* Incomming unencoded data */
int width; /* # of unencoded bytes */
#endif
{
int cnt; /* Run length counter */
int len = 0; /* Encoded byte counter */
/*
* Loop thru the unencoded bytes
*/
while ( width > 0 )
{
if (( width > 1 ) && ( cIn[0] == cIn[1] ))
{
/* Encode case */
for( cnt=2; cnt < width; cnt++ )
{
if ( cIn[cnt] != cIn[cnt-1] )
break;
if ( cnt >= 127 )
break;
}
/* Write out count */
*cOut++ = cnt-1;
len++;
/* Write out value */
*cOut++ = *cIn;
len++;
width -= cnt;
cIn += cnt;
}
else /* Don't encode */
{
for( cnt=1; cnt < width; cnt++ )
{
if ((width-cnt > 1) && (cIn[cnt]==cIn[cnt+1]))
break;
if ( cnt >= 127 )
break;
}
/* Write out count */
*cOut++ = 256 - cnt;
len++;
/* Copy string of pixels */
for ( ; cnt-- > 0; len++, width-- )
*cOut++ = *cIn++;
}
}
return( len );
}
/*
* FUNCTION
* imRlaWrite - write an Wavefront RLA file
*
* DESCRIPTION
* The VFB is queried, and the RLA file header set up and written out.
* The VFB data is then read out and converted to run-codes, and those
* codes written out.
*/
static int /* Returns # of tags used */
#ifdef __STDC__
imRlaWrite( ImFileFormatWriteMap *pMap, int ioType, int fd, FILE *fp, TagTable *flagsTable, TagTable *tagTable )
#else
imRlaWrite( pMap, ioType, fd, fp, flagsTable, tagTable )
ImFileFormatWriteMap *pMap; /* Write map entry to adhear to */
int ioType; /* I/O flags */
int fd; /* Input file descriptor */
FILE *fp; /* Input file pointer */
TagTable *flagsTable; /* Flags */
TagTable *tagTable; /* Tag list to read from */
#endif
{
int x,y,dep; /* Convenient short names */
ImVfb *vfb; /* Read in image */
imRlaHeaderInfo header; /* RLA file header */
time_t seconds; /* Return value from time() */
ImVfbPtr pptr; /* Pixel pointer */
ImVfbPtr leftpptr; /* Points to start of scanlines */
unsigned char *redBuf; /* Run buffer */
unsigned char *grnBuf; /* Run buffer */
unsigned char *bluBuf; /* Run buffer */
unsigned char *alpBuf; /* Run buffer */
unsigned char *buf; /* Run buffer */
int *offsetTable; /* Array of scanline offsets */
int writeCount; /* Keep count of file offset */
short len; /* Number of bytes unencoded */
int i,j; /* Loop counters */
char *name; /* Login name */
char tmp[100]; /* Temp buffer */
struct passwd *pass; /* Password file entry */
/*
* RLA files are usually generated on Irises, which have an MBF
* byte order. There is no floating point in the file so we
* won't bother setting the float format for BIN.
*/
BinByteOrder( BINMBF );
/*
* Set up the header and write it out.
*/
TagEntryQValue( TagTableQDirect( tagTable, "image vfb", 0 ), &vfb );
x = ImVfbQWidth( vfb );
y = ImVfbQHeight( vfb );
header.window_right = x-1; /* Right side */
header.window_top = y-1; /* Top side */
header.window_left = 0; /* Left side */
header.window_bottom = 0; /* Bottom side */
header.active_window_right = x-1; /* Right side */
header.active_window_top = y-1; /* Top side */
header.active_window_left = 0; /* Left side */
header.active_window_bottom= 0; /* Bottom side */
header.frame = 1; /* First frame (anything) */
header.storage_type = 0; /* Image data (must be 0) */
header.num_chan = 3; /* RGB (must be 3) */
header.num_matte = 1; /* Alpha included (0 or 1) */
header.num_aux = 0; /* no aux channels (must be 0) */
header.aux_mask = 0; /* no aux channels (must be 0) */
header.job_num = 0; /* job 0 (anything) */
header.field = 0; /* not on fields (0 or 1) */
header.filter_type = 0; /* non-interleaved (0 or 1) */
header.magic_number = 0; /* no magic (must be 0) */
header.lut_size = 0; /* no CLT (must be 0) */
header.user_space_size = 0; /* no user space (must be 0) */
header.wf_space_size = 0; /* no wf space (must be 0) */
header.lut_type = 0; /* no CLT (must be 0) */
header.mix_type = 0; /* no mix (must be 0) */
header.encode_type = 0; /* no encoding (must be 0) */
header.padding = 0; /* no padding (must be 0) */
strcpy( header.gamma, "2.200" );
strcpy( header.red_pri, "00.6700 00.3300" );
strcpy( header.green_pri, "00.2100 00.7100" );
strcpy( header.blue_pri, "00.1400 00.0800" );
strcpy( header.white_pt, "00.3100 00.3160" );
strncpy( header.name, ImErrorFileName, IMRLANNAME );
strcpy( header.desc, "image file" );
strncpy( header.program, ImErrorProgramName, IMRLANPROG );
strcpy( header.chan, "rgb" );
/*
if ( (name = getlogin( )) == NULL )
{
pass = getpwuid( getuid( ) );
name = pass->pw_name;
}
*/
name = "Creator";
strncpy( header.user, name, IMRLANSTR );
strcpy( header.aspect, "user defined");
sprintf( tmp, "%3.2f", (float)x/y );
strncpy( header.aspect_ratio, tmp, IMRLANAR );
seconds = time( (time_t *)NULL );
strncpy( header.date, ctime( &seconds ), 19 );
#ifndef WIN32
gethostname( header.machine, IMRLANSTR );
#else
strcpy(header.machine, "jaws");
#endif
/*
* Write out the RLA image file header
*/
if (( writeCount = ImBinWriteStruct( ioType, fd, fp, &header, imRlaHeaderFields )) == -1 )
{
ImReturnBinError( );
}
if ( writeCount != IMRLAHEADERSIZE )
{
ImErrNo = IMESYS;
ImErrorFatal( ImQError( ), -1, ImErrNo );
}
imRlaPrHeader( &header );
/*
* Allocate an offset table and initialize it to zeroes. We'll
* write it out as zeroes now, fill it while we encode the data,
* then seek back and write the real table out when we're done.
*/
ImMalloc( offsetTable, int *, sizeof(int) * y );
memset( offsetTable, 0x00, sizeof(int) * y );
if ( ImBinWrite( ioType, fd, fp, offsetTable, INT, 4, y ) == -1 )
{
free( (char *)offsetTable );
ImReturnBinError( );
}
writeCount += 4 * y;
/*
* Allocate run buffers large enough for one scanline per color
*/
ImCalloc( redBuf, unsigned char *, x, 1 );
ImCalloc( grnBuf, unsigned char *, x, 1 );
ImCalloc( bluBuf, unsigned char *, x, 1 );
ImCalloc( alpBuf, unsigned char *, x, 1 );
ImCalloc( buf, unsigned char *, x*2, 1 );
/*
* Loop through the scan lines, from the bottom up. Fill the
* buffers with channel values, encode them, and then write them out.
*/
pptr = leftpptr = ImVfbQPtr( vfb, 0, y-1 );
for( i=0; i<y; i++ )
{
offsetTable[i] = writeCount;
/*
* Copy the vfb pixel values into scanline buffers.
* If an alpha channel is present, use it. If not, set to
* 0xFF.
*/
if ((ImVfbQFields(vfb) & IMVFBALPHA) == IMVFBALPHA)
{
for ( j = 0; j < x; j++ )
{
redBuf[j] = ImVfbQRed( vfb, pptr );
grnBuf[j] = ImVfbQGreen( vfb, pptr );
bluBuf[j] = ImVfbQBlue( vfb, pptr );
alpBuf[j] = ImVfbQAlpha( vfb, pptr );
ImVfbSInc( vfb, pptr );
}
}
else
{
for ( j = 0; j < x; j++ )
{
redBuf[j] = ImVfbQRed( vfb, pptr );
grnBuf[j] = ImVfbQGreen( vfb, pptr );
bluBuf[j] = ImVfbQBlue( vfb, pptr );
alpBuf[j] = 0xFF;
ImVfbSInc( vfb, pptr );
}
}
for ( j = 0; j < 4; j++ )
{
switch( j )
{
case 0: len = imRlaEncode( buf, redBuf, x ); break;
case 1: len = imRlaEncode( buf, grnBuf, x ); break;
case 2: len = imRlaEncode( buf, bluBuf, x ); break;
case 3: len = imRlaEncode( buf, alpBuf, x ); break;
}
writeCount += (2 + len);
#ifdef DEBUG
{int k;
fprintf(stderr," unenc %2d,%2d: ",i,j);
switch(j){
case 0: for(k=0;k<x;k++)fprintf(stderr,"%3d ",redBuf[k]); break;
case 1: for(k=0;k<x;k++)fprintf(stderr,"%3d ",grnBuf[k]); break;
case 2: for(k=0;k<x;k++)fprintf(stderr,"%3d ",bluBuf[k]); break;
case 3: for(k=0;k<x;k++)fprintf(stderr,"%3d ",alpBuf[k]); break;
}fprintf(stderr,"\n enc (%3d): ",len);
for(k=0;k<len;k++)if(buf[k]&0x80)fprintf(stderr,"-%2d ",256-buf[k]);else fprintf(stderr,"%3d ",buf[k]);
fprintf(stderr,"\n");
}
#endif
if (ImBinWrite(ioType, fd, fp, &len, SHORT, 2, 1 )== -1)
{
imRlaFrBuf( redBuf, grnBuf, bluBuf, alpBuf, buf,
offsetTable );
ImReturnBinError( );
}
if (ImBinWrite(ioType, fd, fp, buf, UCHAR, 1, len)== -1)
{
imRlaFrBuf( redBuf, grnBuf, bluBuf, alpBuf, buf,
offsetTable );
ImReturnBinError( );
}
}
/*
* Position leftpptr at the beginning of the scanline above
*/
ImVfbSUp( vfb, leftpptr );
pptr = leftpptr;
}
/*
* Seek backwards and write out the correct offsetTable.
*/
ImSeek( ioType, fd, fp, IMRLAHEADERSIZE, 0 );
#ifdef DEBUG
if(ioType&IMFILEIOFD)
fprintf(stderr,"seeked to %d bytes. tell reports 0x%08x (%d)\n",IMRLAHEADERSIZE,tell(fd),tell(fd));
else
fprintf(stderr,"seeked to %d bytes. tell reports 0x%08x (%d)\n",IMRLAHEADERSIZE,ftell(fp),ftell(fp));
for(i=0;i<y;i++)fprintf(stderr,"offsetTable[i] = 0x%08x (%d)\n",offsetTable[i],offsetTable[i]);
#endif
if ( ImBinWrite( ioType, fd, fp, offsetTable, INT, 4, y ) == -1 )
{
imRlaFrBuf(redBuf,grnBuf,bluBuf,alpBuf,buf,offsetTable);
ImReturnBinError( );
}
imRlaFrBuf(redBuf,grnBuf,bluBuf,alpBuf,buf,offsetTable);
return ( 1 );
}