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

2614 lines
40 KiB
C

/**
** $Header: /roq/libim/imcur.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/imcur.c 1 11/02/99 4:38p Zaphod $"
/**
** FILE
** imcur.c - Microsoft Windows CUR file I/O
**
** PROJECT
** libim - SDSC image manipulation library
**
** DESCRIPTION
** imcur.c contains routines to read and write Microsoft Windows CUR
** files for the image manipulation library. Raster data read
** in is stored in a VFB. Raster data written out is taken from a
** tag table.
**
** PUBLIC CONTENTS
** d =defined constant
** f =function
** m =defined macro
** t =typedef/struct/union
** v =variable
** ? =other
**
** ImFileCurFormat v file format information
**
** PRIVATE CONTENTS
** imCurHeader t file header information
** imCurHeaderFields v imCurHeader description for Bin pkg.
**
** imCurDirEntry t cursor directory entry
** imCurDirEntryFields v imCurDirEntry description for Bin pkg.
**
** imCurInfo t cursor information
** imCurInfoFields v imCurInfo description for Bin pkg.
**
** imCurRead f read CUR file
** imCurImageRead f read the ith cursor image
** imCurImageReadVfb m read the ith cursor image
**
** imCurWriteRaw1 f write 1-bit uncompressed CUR file
**
** HISTORY
** $Log: /roq/libim/imcur.c $
*
* 1 11/02/99 4:38p Zaphod
** Revision 1.12 1995/06/29 00:28:04 bduggan
** updated copyright year
**
** Revision 1.11 1995/06/15 20:16:03 bduggan
** took out unused variables. Took out commands at unreachable code.
** Removed magic number since it conflicted with tga's.
**
** Revision 1.10 1995/05/16 22:11:11 bduggan
** Took \n out of iminfo's
** made HotSpot a static variable (since its address is used
** in the tag table)
**
** Revision 1.9 1995/04/03 21:21:49 bduggan
** took out #ifdef NEWMAGIC
**
** Revision 1.8 94/10/03 11:30:02 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.7 92/12/03 01:46:29 nadeau
** Corrected info messages.
**
** Revision 1.6 92/11/24 11:47:02 groening
** Removed use of IMINFOMSG.
**
** Revision 1.5 92/11/18 12:28:53 groening
** fixed error in offset of image
**
** Revision 1.4 92/11/04 11:46:19 groening
** added multiple read and write.
** put ImFIleFormat info and magic number info
** from imfmt.c into this file.
**
** Revision 1.3 92/10/12 15:54:17 vle
** Made changes to make Cray happy.
**
** Revision 1.2 92/09/29 17:59:03 vle
** Added ImInfo messages.
**
** Revision 1.1 92/09/17 14:31:40 vle
** Initial revision
**
**
**/
#include "iminternal.h"
/**
** FORMAT
** cur - Microsoft Windows cursor image
**
** AKA
**
** FORMAT REFERENCES
** Microsoft Windows 3.1 Programmer's Reference, volume 3, Microsoft
** Press, 1992.
**
** Microsoft Windows 3.1 Programmer's Reference, volume 3, Microsoft
** Press, 1992.
**
** CODE CREDITS
** Custom development, Vinh Le, San Diego Supercomputer Center, 1992.
** Extensions, Dave Nadeau, San Diego Supercomputer Center, 1993.
**
** DESCRIPTION
** Microsoft's CUR (CURsor) format is used in Microsoft's Windows
** versions 3.0 and up for storage of one or more cursors.
**
** The first item encountered in an CUR file is a Cursor Directory
** Header. This tells that the file is indeed a file containing
** cursors and that there are n number of them.
**
** Following the Cursor Directory Header is an Cursor Directory
** Entry for each cursor. A Cursor Directory Entry contains
** information on the cursor's location within the file,
** its width, height, etc. There are n Cursor Directory Entries.
**
** Following all this is the actual Cursor Images themselves, which
** consist of an info header, a colortable, and XOR and AND masks.
** The XOR mask could be considered the "real" cursor. The AND
** mask determines the XOR image's "transparency". XOR masks
** are 1-bit/pixel. 1-bit/pixel images are packed 8 pixels/byte.
** AND masks are always monochrome images, thus they are
** packed as 1-bit/pixel images, or 8-bits/byte.
**
**
** Stucture Overview
** -----------------
**
** CURSOR DIRECTORY
** ---------------------------------------------------------
** |CURSOR |CURSOR |CURSOR | ... | | | |
** |ENTRY 1|ENTRY 2|ENTRY 3| | | | |
** ---------------------------------------------------------
** |
** | ---------
** +---------> |CURSOR |
** |IMAGE |
** |-------|
** |Header |
** |-------|
** |Color |
** |Table |
** |-------|
** |XOR |
** |Mask |
** |-------|
** |AND |
** |Mask |
** ---------
**
**
** Cursor Directory Header (6 bytes+ 16 bytes/cursor entry)
** -----------------------
**
** The Cursor Directory Header contains the resource type and
** number of cursors in the Cursor Directory.
**
** Name Type Size Comments
** ---- ---- ---- --------
** cdReserved word 2 bytes reserved, must be 0
** cdType word 2 bytes resource type,
** must be 2
** cdCount word 2 bytes number of cursors
** cdEntries[] CurosrDirEntry 16 bytes array of info for
** per entry individual cursors
**
** typedef struct CURSORDIR
** {
** word cdReserved;
** word cdType;
** word cdCount;
** CURSORDIRENTRY cdEntries[cdCount];
** } CURSORDIR;
**
**
** Cursor Directory Entry (16 bytes/cursor entry)
** ----------------------
**
** An Cursor Directory Entry stores information about the an cursor's
** dimensions and color attributes.
**
** Name Type Size Comments
** ---- ---- ---- --------
** Width byte 1 byte width in pixels
** Height byte 1 byte height in pixels
** ColorCount byte 1 byte reserved, must be 0
** Reserved byte 1 byte reserved, must be 0
** XHotspot word 2 byte x coordinate of hotspot
** YHotspot word 2 byte y coordinate of hotspot
** BytesInRes dword 4 byte size of cursor in bytes
** ImageOffset dword 4 byte offset from beginning of file to
** Cursor Image
**
** typedef struct CURSORDIRENTRY
** {
** byte Width;
** byte Height;
** byte ColorCount;
** byte Reserved;
** word XHotspot;
** word YHotspot;
** dword BytesInRes;
** dword ImageOffset;
** } CURSORDIRENTRY;
**
**
** Cursor Image (40 bytes + 4 bytes/color entry + sizeof XOR mask +
** ------------ sizeof AND mask)
**
** Each Cursor Image stores 1 cursor.
**
** Name Type Size Comments
** ---- ---- ---- --------
** crHeader BITMAPFILEHEADER 40 bytes only biSize
** through
** biBitCount
** and
** biSizeImage
** are used
** biHeight =
** 2*XOR Mask
** height
** biPlanes = 1
** biBitCount = 1
** all other
** fields = 0
** crColors[] RGBQUAD 4 bytes per colortable used
** color in XOR mask
** crXOR[] byte 1 byte per XOR image mask
** element
** crAND[] byte 1 byte per AND image mask
** element
**
**
** Cur-Info Header (40 bytes)
** ------------------
**
** The Cur-Info Header contains information about the cursor's
** size and dimensions.
**
** Name Type Size Comments
** ---- ---- ---- --------
** biSize dword 4 bytes number of bytes in
** Cur-Info Header
** biWidth long 4 bytes width, in pixels
** biHeight long 4 bytes height, in pixels
** biPlanes word 2 bytes number of planes for the
** display device, must be 1
** biBitCount word 2 bytes bits per pixel, must be 1
** biCompression dword 4 bytes unused, must be 0
** biSizeImage dword 4 bytes image size in bytes
** biXPelsPerMeter long 4 bytes unused, must be 0
** biYPelsPerMeter long 4 bytes unused, must be 0
** biClrUsed dword 4 bytes unused, must be 0
** biClrImportant dword 4 bytes unused, must be 0
**
** typedef struct tagBITMAPINFOHEADER
** {
** dword biSize;
** long biWidth;
** long biHeight;
** word biPlanes;
** word biBitCount;
** dword biCompression;
** dword biSizeImage;
** long biXPelsPerMeter;
** long biYPelsPerMeter;
** dword biClrUsed;
** dword biClrImportant;
** } BITMAPINFOHEADER;
**
**
** ColorTable (4 bytes per color)
** ----------
**
** ColorTable is an array of RGBQuad's. Each RGBQuad contains color
** intensity values for Red, Green, and Blue.
**
** RGBQuad
** -------
**
** Name Type Size Comment
** ---- ---- ---- -------
** rgbBlue byte 1 byte intensity of blue
** rgbGreen byte 1 byte intensity of green
** rgbRed byte 1 byte intensity of red
** rgbReserved byte 1 byte unused
**
** typedef struct tagRGBQUAD
** {
** byte rgbBlue;
** byte rgbGreen;
** byte rgbRed;
** byte rgbReserved;
** } RGBQUAD;
**
**/
/*
* FUNCTION DECLARATIONS
*/
#ifdef __STDC__
static int imCurRead( int, int, FILE *, TagTable *, TagTable * );
static int imCurWriteRaw1( ImFileFormatWriteMap *, int, int, FILE *,
TagTable *, TagTable * );
#else
static int imCurRead( );
static int imCurWriteRaw1( );
#endif
/*
* FORMAT INFORMATION
* imCurNames - format's name and aliases
* imCurReadMap - read attributes
* imCurWriteMap - write attributes
* imCurMagicNumber - magic number
* imCurMagic - list of magic numbers
* ImFileCurFormat - master format description
*/
static char *imCurNames[ ] = { "cur", NULL };
static ImFileFormatReadMap imCurReadMap[ ] =
{
/* in out */
/* type,ch,dep, attr. VFB type attr. */
{ IN,1,1, C, IMVFBINDEX8, C|A },
{ -1, 0, -1, 0 },
};
static ImFileFormatWriteMap imCurWriteMap[ ] =
{
/* in out */
/* VFB type, attr., type,ch,dep, attr., func */
{ IMVFBMONO, C|A, IN,1,1, C, imCurWriteRaw1 },
{ -1, 0, -1, 0, NULL },
};
/*
* Magic number:
* The CUR magic number conflicts with
* TGA (targa) rgb files. So, I've left
* out the magic number so tga's can be
* read safely.
*
* The effect of this is not drastic:
* It just means that cur's can only be
* identified by their filename extension.
*
*/
/* static unsigned char imCurMagicNumber[ ] = { 0x00, 0x00, 0x02, 0x00 }; */
static ImFileMagic imCurMagic[ ] =
{
/* { 0, 4, imCurMagicNumber }, */
{ 0, 0, NULL },
};
ImFileFormat ImFileCurFormat =
{
imCurNames, /* Names */
"Windows cursor image file", /* Description */
"Microsoft", /* Creator */
"1-bit color index images with alpha channels.",/* Read support */
"1-bit color index images with alpha channels.",/* Write support*/
imCurMagic, /* Magic #'s */
IMMULTI, IMPIPE, /* Read? */
IMMULTI, IMPIPE, /* Write? */
imCurRead, imCurReadMap, imCurWriteMap /* Maps */
};
/*
* TYPEDEF & STRUCTURE
* imCurHeader - CUR file header
* imCurHeaderFields - CUR file header fields for binary pkg.
* imCurDirEntry - CUR cursor directory entry
* imCurDirEntryFields - CUR cursor directory entry for bin pkg.
* imCurInfo - CUR file info
* imCurInfoFields - CUR file info fields for bin pkg.
* imCurRGBQuad - CUR color information
* imCurRGBQuadFields - CUR color information fields for bin pkg.
*
* DESCRIPTION
* The imCurRGBQuad is one entry in the colortable.
*/
typedef struct imCurHeader
{
sdsc_uint16 cur_idReserved; /* reserved, must be zero */
sdsc_uint16 cur_idType; /* resource type, must be 2 */
sdsc_uint16 cur_idCount; /* number of entries in directory*/
} imCurHeader;
static BinField imCurHeaderFields[ ] =
{
{ UINT16, 2, 1 }, /* cur_idReserved */
{ UINT16, 2, 1 }, /* cur_idType */
{ UINT16, 2, 1 }, /* cur_idCount */
{ 0, 0, 0 }
};
typedef struct imCurDirEntry
{
unsigned char cur_Width; /* width in pixels */
unsigned char cur_Height; /* height in pixels */
unsigned char cur_ColorCount; /* reserved, must be 0 */
unsigned char cur_Reserved; /* reserved, must be 0 */
sdsc_uint16 cur_XHotspot; /* x coordinate of hotspot */
sdsc_uint16 cur_YHotspot; /* y coordinate of hotspot */
sdsc_uint32 cur_BytesInRes; /* size of cursor in bytes */
sdsc_uint32 cur_ImageOffset;/* offset of file to cursor */
} imCurDirEntry;
static BinField imCurDirEntryFields[ ] =
{
{ UCHAR, 1, 1 }, /* cur_Width */
{ UCHAR, 1, 1 }, /* cur_Height */
{ UCHAR, 1, 1 }, /* cur_ColorCount */
{ UCHAR, 1, 1 }, /* cur_Reserved */
{ UINT16, 2, 1 }, /* cur_XHotspot */
{ UINT16, 2, 1 }, /* cur_YHotspot */
{ UINT32, 4, 1 }, /* cur_ByteInRes */
{ UINT32, 4, 1 }, /* cur_ImageOffset */
{ 0, 0, 0 }
};
typedef struct imCurInfo
{
sdsc_uint32 cur_bisize; /* # bytes in cursor info header*/
sdsc_uint32 cur_biwidth; /* image width in pixels */
sdsc_uint32 cur_biheight; /* image height in pixels */
sdsc_uint16 cur_biplanes; /* # planes for device, always 1*/
sdsc_uint16 cur_bibitcount; /* bits/pixel, must be 1 */
sdsc_uint32 cur_bicompress; /* unused, must be 0 */
sdsc_uint32 cur_bisizeimage;/* image size in bytes */
sdsc_uint32 cur_bixpm; /* unused, must be 0 */
sdsc_uint32 cur_biypm; /* unused, must be 0 */
sdsc_uint32 cur_biclrused; /* unused, must be 0 */
sdsc_uint32 cur_biclrim; /* unused, must be 0 */
} imCurInfo;
static BinField imCurInfoFields[ ] =
{
{ UINT32, 4, 1 }, /* cur_bisize */
{ UINT32, 4, 1 }, /* cur_biwidth */
{ UINT32, 4, 1 }, /* cur_biheight */
{ UINT16, 2, 1 }, /* cur_biplanes */
{ UINT16, 2, 1 }, /* cur_bibitcount */
{ UINT32, 4, 1 }, /* cur_bicompress */
{ UINT32, 4, 1 }, /* cur_bisizeimage */
{ UINT32, 4, 1 }, /* cur_bixpm */
{ UINT32, 4, 1 }, /* cur_biypm */
{ UINT32, 4, 1 }, /* cur_biclrused */
{ UINT32, 4, 1 }, /* cur_biclrim */
{ 0, 0, 0 }
};
typedef struct imCurRGBQuad
{
unsigned char blue; /* blue intensity */
unsigned char green; /* green intensity */
unsigned char red; /* red intensity */
unsigned char reserved; /* unused */
} imCurRGBQuad;
static BinField imCurRGBQuadFields[ ] =
{
{ UCHAR, 1, 1 }, /* blue */
{ UCHAR, 1, 1 }, /* green */
{ UCHAR, 1, 1 }, /* red */
{ UCHAR, 1, 1 }, /* reserved */
{ 0, 0, 0 }
};
/*
* CONSTANTS
* CUR* - assorted useful CUR constants
*/
#define IMCURMAGIC 2
/* magic resource number for cursors */
#define IMCURHEADERSIZE 6
/* 6 bytes */
#define IMCURDIRENTRYSIZE 16
/* 16 bytes */
#define IMCURINFOSIZE 40
/* 40 bytes */
#define IMCURRGBQUADSIZE 4
/* 4 bytes */
#define IMCURXOR 0
/* XOR vfb flag, IMVFBMONO */
#define IMCURAND 1
/* AND vfb flag, IMVFBMONO */
#ifdef __STDC__
static int imCurImageRead( int, int, FILE *, TagTable *, TagTable *,
imCurDirEntry * );
#else
static int imCurImageRead( );
#endif
/*
* FUNCTION
* imCurRead - read a Microsoft Windows Cur file
*
* DESCRIPTION
* The file header is read and the size of the image determined.
* Space is allocated for the VFB and the file is read into the
* VFB.
*/
static int /* Returns # tags read in */
#ifdef __STDC__
imCurRead( int ioType, int fd, FILE *fp, TagTable *flagsTable, TagTable *tagTable )
#else
imCurRead( 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
{
imCurHeader header; /* CUR file header */
imCurDirEntry *curdirentries; /* CUR dir entries */
imCurDirEntry *curdirentryptr; /* CUR dir entry pointer */
unsigned int i; /* Counter */
char message[100]; /* ImInfo message */
/*
* Set Binary Package byte order and read in part of header
*/
BinByteOrder( BINLBF );
if( ImBinReadStruct( ioType, fd, fp, &header,
imCurHeaderFields ) == -1 )
{
ImReturnBinError( );
}
/*
* Use idType to determine byte ordering
*/
if( header.cur_idType != IMCURMAGIC )
{
/*
* Swap bytes
*/
header.cur_idType = (header.cur_idType&0xFF00)>>8 |
(header.cur_idType&0x00FF)<<8;
if( header.cur_idType != IMCURMAGIC )
{
ImErrorFatal( ImQError( ), -1, IMEMAGIC );
}
else
{
header.cur_idCount = (header.cur_idCount&0xFF00)>>8 |
(header.cur_idCount&0x00FF)<<8;
BinByteOrder( BINMBF );
ImInfo( "Byte Order", "Most Significant Byte First" );
}
}
else
{
ImInfo( "Byte Order", "Least Significant Byte First" );
}
/*
* Allocate space for cursor dir entries
*/
ImMalloc( curdirentries, imCurDirEntry*,
header.cur_idCount * sizeof(imCurDirEntry) );
/*
* Read in cursor dir entries
*/
curdirentryptr = curdirentries;
for( i = 0; i < header.cur_idCount; ++i )
{
if( ImBinReadStruct( ioType, fd, fp, curdirentryptr,
imCurDirEntryFields ) == -1 )
{
ImReturnBinError( );
}
++curdirentryptr;
}
/*
* Read in cursor images
*/
curdirentryptr = curdirentries;
for( i = 0; i < header.cur_idCount; ++i )
{
/*
* Read in ith cursor
*/
sprintf( message, "%d of %d", (i+1), header.cur_idCount );
ImInfo( "Image", message );
imCurImageRead( ioType, fd, fp, flagsTable, tagTable,
curdirentryptr );
++curdirentryptr;
}
free( curdirentries );
return header.cur_idCount;
}
#define imCurImageReadVfb( tmpvfb, vfbtype ) \
/* \
* The image is stored from the bottom up; that is, \
* the first scanline in the file is the last \
* scanline in the image. \
*/ \
\
/* \
* Go to the last scanline in the tmpvfb \
*/ \
vfbptr = ImVfbQPtr( tmpvfb, 0, y-1 ); \
\
switch( info.cur_bibitcount ) \
{ \
case 1: \
/* \
* Read 1-bit non-compressed image \
* \
* 1 bytes contains info for 8 pixels \
* \
* -------- <- 1 byte \
* 12345678 \
* \
* Set = first color in colortable \
* Not Set = second color in colortable \
* \
*/ \
\
/* \
* Find scanline size to nearest 32-bit \
* boundary and allocate read buffer \
* \
* Note: bit shifting is used to speed up \
* calculations \
*/ \
scanlinesize = x>>5; \
if( x%32 ) scanlinesize++; \
scanlinesize <<= 2; \
\
ImMalloc( rbuf, unsigned char*, scanlinesize ); \
\
for( i = 0; i < y ; ++i ) \
{ \
if( ImBinRead( ioType, fd, fp, \
rbuf, UCHAR, 1, scanlinesize ) == -1) \
{ \
ImReturnBinError( ); \
} \
rbufptr = rbuf; \
\
for( j = 0; j < (x/8); ++j ) \
{ \
mask = 128; \
for( k = 0; k < 8; ++k ) \
{ \
if( ( *(rbufptr) & mask ) == mask ) \
{ \
if( vfbtype == IMCURXOR ) \
{ \
ImVfbSIndex8( tmpvfb, vfbptr, 1 );\
} \
else \
{ \
ImVfbSAlpha( tmpvfb, vfbptr, 0 );\
} \
} \
else \
{ \
if( vfbtype == IMCURXOR ) \
{ \
ImVfbSIndex8( tmpvfb, vfbptr, 0 );\
} \
else \
{ \
ImVfbSAlpha( tmpvfb, vfbptr, 255 );\
} \
} \
vfbptr = ImVfbQRight( tmpvfb, vfbptr ); \
mask = mask >> 1; \
} \
++rbufptr; \
} \
if( x%8 ) \
{ \
mask = 128; \
for( k = 0; k < x%8; ++k ) \
{ \
if( ( *(rbufptr) & mask ) == mask ) \
{ \
if( vfbtype == IMCURXOR ) \
{ \
ImVfbSIndex8( tmpvfb, vfbptr, 1 );\
} \
else \
{ \
ImVfbSAlpha( tmpvfb, vfbptr, 0 );\
} \
} \
else \
{ \
if( vfbtype == IMCURXOR ) \
{ \
ImVfbSIndex8( tmpvfb, vfbptr, 0 );\
} \
else \
{ \
ImVfbSAlpha( tmpvfb, vfbptr, 255 );\
} \
} \
vfbptr = ImVfbQRight( tmpvfb, vfbptr ); \
mask = mask >> 1; \
} \
} \
\
/* \
* Go up two scanline since we \
* wrapped-around with ImVfbQRight( ) \
*/ \
vfbptr = ImVfbQUp( tmpvfb, vfbptr ); \
vfbptr = ImVfbQUp( tmpvfb, vfbptr ); \
} \
\
break; \
\
default: \
ImErrorFatal( ImQError( ), -1, IMEPLANES ); \
\
} /* end switch */ \
\
free( (unsigned char*) rbuf ); \
\
static int
#ifdef __STDC__
imCurImageRead ( int ioType, int fd, FILE *fp, TagTable *flagsTable,
TagTable *tagTable, imCurDirEntry *curdirentryptr )
#else
imCurImageRead ( ioType, fd, fp, flagsTable, tagTable, curdirentryptr )
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 */
imCurDirEntry *curdirentryptr; /* Cursor dir entry pointer */
#endif
{
imCurInfo info; /* Cursor image info */
ImVfb *vfb; /* Virtual Frame Buffers */
ImVfbPtr vfbptr; /* Pixel pointer */
ImClt *clt = IMCLTNULL; /* Colortable */
ImCltPtr cltptr; /* Colortable entry pointer */
static ImHotSpot hotspot; /* Cursor hotspot */
ImHotSpotPtr hotspotptr; /* Cursor hotspot pointer */
unsigned char mask; /* Mask for extracting pixels */
unsigned char *rbuf = NULL; /* Read buffer */
unsigned char *rbufptr; /* Read buffer data pointer */
unsigned int scanlinesize; /* Length of scanline in bytes */
unsigned int ncolors = 0; /* Number of colors used */
unsigned int x, y; /* Width and Height */
unsigned int i, j, k; /* Counters */
char message[100]; /* ImInfo message */
/*
* Read in cursor image info.
*/
if( ImBinReadStruct( ioType, fd, fp, &info, imCurInfoFields ) == -1 )
{
ImReturnBinError( );
}
/*
* Store hotspot in TagTable
*/
hotspotptr = &hotspot;
ImHotSpotSX( hotspotptr, curdirentryptr->cur_XHotspot );
ImHotSpotSY( hotspotptr, curdirentryptr->cur_YHotspot );
TagTableAppend( tagTable, TagEntryAlloc( "image hot spot",
POINTER, &hotspotptr) );
x = info.cur_biwidth;
y = info.cur_biheight / 2;
/*
* Allocate a VFBs of the required size and type.
*/
switch( info.cur_bibitcount )
{
case 1: /* 1-bit index image */
break;
default: /* unsupported image depth */
ImErrorFatal( ImQError( ), -1, IMEDEPTH );
}
vfb = ImVfbAlloc( x, y, IMVFBINDEX8 | IMVFBALPHA);
if ( vfb == IMVFBNULL )
{
ImErrorFatal( ImQError( ), -1, ImErrNo );
}
/*
* Allocate and read in colortable
*/
ncolors = (1 << info.cur_bibitcount);
switch( ncolors )
{
case 2: /* 1-bit, monochrome */
break;
default:
ImErrorFatal( ImQError( ), -1, IMECLTLENGTH );
/* output warning */
}
clt = ImCltAlloc( ncolors );
/*
* Read in colortable and set RGB values
*/
cltptr = ImCltQFirst( clt );
ImMalloc( rbuf, unsigned char*, ncolors*IMCURRGBQUADSIZE );
rbufptr = rbuf;
if( ImBinRead( ioType, fd, fp, rbuf, UCHAR, 1,
ncolors*IMCURRGBQUADSIZE ) == -1 )
{
ImReturnBinError( );
}
for( i = 0; i < ncolors; ++i )
{
ImCltSBlue( cltptr, *rbufptr );
++rbufptr;
ImCltSGreen( cltptr, *rbufptr );
++rbufptr;
ImCltSRed( cltptr, *rbufptr );
++rbufptr;
/* skip reserved field */
++rbufptr;
cltptr = ImCltQNext( clt, cltptr );
}
free( rbuf );
/*
* Attach colortable to vfb and append to tagTable
*/
ImVfbSClt( vfb, clt );
TagTableAppend( tagTable, TagEntryAlloc( "image clt",
POINTER, &clt) );
/*
* Read in XOR mask image
*/
imCurImageReadVfb( vfb, IMCURXOR );
/*
* Read in AND mask image
*/
info.cur_bibitcount = 1; /* AND masks are mono images */
imCurImageReadVfb( vfb, IMCURAND );
/*
* Add the VFB to the tagTable.
*/
TagTableAppend( tagTable,
TagEntryAlloc( "image vfb", POINTER, &vfb ) );
/*
* Output -verbose message
*/
sprintf( message, "%d x %d", x, y );
ImInfo( "Resolution", message );
ImInfo( "Type", "1-bit Color Indexed (XOR mask)" );
sprintf( message, "%d Entries", ncolors );
ImInfo( "Color Table", message );
ImInfo( "Alpha Channel", "1-bit Monochrome (AND mask)" );
sprintf( message, "%d, %d", hotspot.hot_x, hotspot.hot_y );
ImInfo( "Hot Spot", message );
return ( 2 );
}
/*
* FUNCTION
* imCurWriteRaw1 - write an 1-bit non-compressed CUR file
*
* DESCRIPTION
* That VFB is queried, and the CUR file header set up and written out.
* The VFB data is then converted and written out.
* Multiple image writes are supported.
*/
static int /* Returns # of tags used */
#ifdef __STDC__
imCurWriteRaw1( ImFileFormatWriteMap *pMap, int ioType, int fd, FILE *fp,
TagTable *flagsTable, TagTable *tagTable )
#else
imCurWriteRaw1( 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
{
imCurHeader header; /* CUR file header */
imCurDirEntry direntry; /* CUR dir entry */
imCurInfo info; /* CUR info */
ImVfb *vfb; /* Read in image */
ImVfbPtr vfbptr; /* Vfb pixel pointer */
imCurRGBQuad cltentry; /* Colortable RGBQuad entry */
ImClt *clt; /* Colortable */
ImCltPtr cltptr; /* Colortable entry pointer */
ImHotSpotPtr hotspotptr; /* Cursor hotspot pointer */
unsigned char pvalue; /* Pixel value */
unsigned char *wbuf; /* Pointer to write buffer */
unsigned char *wbufptr; /* Pointer to write buffer data */
unsigned int scanlinesize; /* Length of scanline */
unsigned char bitfield; /* Bitfield of 8 pixels */
unsigned int x, y; /* Width, Height */
int i, j, k, loop; /* Counters */
unsigned int count; /* Counter */
int fields; /* Vfb fields */
char message[100]; /* ImInfo message */
int imageNum; /* number of images in a file */
TagEntry *tagEntry; /* Tag table entry holder */
unsigned long offsetTotal; /* where you are in image */
/*
* Set byte ordering
*/
BinByteOrder( BINLBF );
ImInfo( "Byte Order", "Least Significant Byte First" );
/*
* Get number of images
*/
imageNum = TagTableQNEntry( tagTable, "image vfb" );
/*
* Setup header and write it out
*/
header.cur_idReserved = 0;
header.cur_idType = (sdsc_uint16) IMCURMAGIC;
header.cur_idCount = (sdsc_uint16) imageNum;
if ( ImBinWriteStruct( ioType, fd, fp, &header, imCurHeaderFields )==-1)
{
ImReturnBinError( );
}
#ifdef old
offsetTotal = (sdsc_uint32)( sizeof(imCurHeader)
+ (imageNum * (sizeof(imCurDirEntry))));
#else
/*
* Compute the file offset to right after the header and individual
* cursor directory entries.
*/
offsetTotal = (unsigned long) IMCURHEADERSIZE +
(imageNum * (unsigned long) IMCURDIRENTRYSIZE);
#endif
/*
* Start by doing a dummy pass through all the images in the
* tag table. For each image, write out a directory entry and
* compute where the image's bytes will eventually be in the file.
*/
for ( loop = 0; loop < imageNum; loop++ )
{
/*
* Get vfb and clt
*/
tagEntry = TagTableQDirect( tagTable, "image vfb", loop );
TagEntryQValue( tagEntry, &vfb );
clt = ImVfbQClt( vfb );
x = ImVfbQWidth( vfb );
y = ImVfbQHeight( vfb );
/*
* Find scanline size to nearest 32-bit boundary.
*/
scanlinesize = x>>5;
if ( x%32 ) scanlinesize++;
scanlinesize <<= 2;
/*
* Setup cursor directory and write it out
*/
direntry.cur_Width = (unsigned char) x;
direntry.cur_Height = (unsigned char) y;
direntry.cur_ColorCount = (unsigned char) 2; /* Always 2 */
direntry.cur_Reserved = 0;
if( TagEntryQValue( TagTableQDirect( tagTable,
"image hot spot", loop ), &hotspotptr ) == -1 )
{
direntry.cur_XHotspot = 0;
direntry.cur_YHotspot = 0;
}
else
{
direntry.cur_XHotspot =ImHotSpotQX( hotspotptr);
direntry.cur_YHotspot =ImHotSpotQY( hotspotptr);
}
/*
* # of bytes = cursor info + colortable +
* XOR mask + AND mask
*/
#ifdef old
direntry.cur_BytesInRes = (sdsc_uint32) ( IMCURINFOSIZE +
( 2 * IMCURRGBQUADSIZE ) + (scanlinesize * y) +
(x*y/8) );
#else
direntry.cur_BytesInRes = (sdsc_uint32) ( IMCURINFOSIZE +
( 2 * IMCURRGBQUADSIZE ) + (scanlinesize * y*2));
#endif
direntry.cur_ImageOffset= (sdsc_uint32) (offsetTotal);
if ( ImBinWriteStruct( ioType, fd, fp, &direntry,
imCurDirEntryFields )==-1)
{
ImReturnBinError( );
}
#ifdef old
offsetTotal += sizeof(imCurInfo)
+ (2 * sizeof(imCurRGBQuad))
+ ( 2 * ((x/8) *y) );
#else
offsetTotal += IMCURINFOSIZE + (2 * IMCURRGBQUADSIZE) +
2 * scanlinesize * y;
#endif
}
/*
* Now do it for real. Loop through all the images and write them
* out.
*/
for ( loop = 0; loop < imageNum; loop++ )
{
/*
* Get vfb and clt
*/
tagEntry = TagTableQDirect( tagTable, "image vfb", loop );
TagEntryQValue( tagEntry, &vfb );
clt = ImVfbQClt( vfb );
x = ImVfbQWidth( vfb );
y = ImVfbQHeight( vfb );
/*
* Find scanline size to nearest 32-bit boundary.
*/
scanlinesize = x>>5;
if( x%32 ) scanlinesize++;
scanlinesize <<= 2;
/*
* Setup cursor info and write it out
*/
info.cur_bisize = (sdsc_uint32) IMCURINFOSIZE;
info.cur_biwidth = (sdsc_uint32) x;
info.cur_biheight = (sdsc_uint32) (2*y);
info.cur_biplanes = (sdsc_uint16) 1;
info.cur_bibitcount = (sdsc_uint16) 1;
info.cur_bicompress = 0;
info.cur_bisizeimage = (sdsc_uint32) (scanlinesize * y);
info.cur_bixpm = 0;
info.cur_biypm = 0;
info.cur_biclrused = 0;
info.cur_biclrim = 0;
if ( ImBinWriteStruct( ioType, fd, fp, &info,
imCurInfoFields )==-1)
{
ImReturnBinError( );
}
/*
* Output -verbose message
*/
sprintf( message, "%d of %d", loop, imageNum );
ImInfo( "Image", message );
sprintf( message, "%d x %d", x, y );
ImInfo( "Resolution", message );
ImInfo( "Type", "1-bit Color Indexed (XOR mask)" );
ImInfo( "Color Table", "2 Entries" );
ImInfo( "Alpha Channel", "1-bit Monochrome (AND mask)" );
sprintf( message, "%d, %d", direntry.cur_XHotspot,
direntry.cur_YHotspot );
ImInfo( "Hot Spot", message );
/*
* Write colortable
*/
cltentry.reserved = 0;
cltentry.blue = 0;
cltentry.green = 0;
cltentry.red = 0;
if( clt != IMCLTNULL )
{
clt = ImVfbQClt( vfb );
cltptr = ImCltQFirst( clt );
cltentry.blue = (unsigned char) ImCltQBlue( cltptr );
cltentry.green = (unsigned char) ImCltQGreen( cltptr );
cltentry.red = (unsigned char) ImCltQRed( cltptr );
}
if ( ImBinWriteStruct( ioType, fd, fp, &cltentry,
imCurRGBQuadFields ) == -1 )
{
ImReturnBinError( );
}
cltentry.blue = 255;
cltentry.green = 255;
cltentry.red = 255;
if( ( clt != IMCLTNULL ) && (ImCltQNColors( clt ) > 1) )
{
cltptr = ImCltQNext( clt, cltptr );
cltentry.blue = (unsigned char) ImCltQBlue( cltptr );
cltentry.green = (unsigned char) ImCltQGreen( cltptr );
cltentry.red = (unsigned char) ImCltQRed( cltptr );
}
if ( ImBinWriteStruct(ioType,fd,fp,&cltentry,imCurRGBQuadFields )==-1)
{
ImReturnBinError( );
}
/*
* Allocate write buffer space
*/
ImCalloc( wbuf, unsigned char*, scanlinesize,
sizeof( unsigned char ) );
/*
* Write XOR mask image
*/
for( i = 0; i < y; ++i )
{
vfbptr = ImVfbQPtr( vfb, 0, y-i-1 );
wbufptr = wbuf;
for( j = 0; j < (x/8); ++j )
{
/*
* Pack 8 pixels into a 1 byte bitfield
*
* -------- <-- 1 byte
* 12345678
*
*/
bitfield = 0;
for( k = 0; k < 8; ++k )
{
pvalue = (unsigned char) ImVfbQMono( vfb, vfbptr );
if( pvalue ) {
bitfield = ( bitfield | (1 << (7-k) ) );
}
vfbptr = ImVfbQRight( vfb, vfbptr );
}
*( wbufptr ) = bitfield;
++wbufptr;
}
if( x%8 )
{
/*
* Pack 8 pixels into a 1 byte bitfield
*
* -------- <-- 1 byte
* 12345678
*
*/
bitfield = 0;
for( k = 0; k < x%8; ++k )
{
pvalue = (unsigned char) ImVfbQMono( vfb, vfbptr );
if( pvalue ) {
bitfield = ( bitfield | (1 << (7-k) ) );
}
vfbptr = ImVfbQRight( vfb, vfbptr );
}
*( wbufptr ) = bitfield;
}
if( ImBinWrite( ioType,fd,fp,wbuf,UCHAR,1,scanlinesize ) == -1 )
{
ImReturnBinError( );
}
/*
* Go up two scanline since we
* wrapped-around with ImVfbQRight( )
*/
vfbptr = ImVfbQUp( vfb, vfbptr );
vfbptr = ImVfbQUp( vfb, vfbptr );
}
/*
* Check for an existing alpha channel
*/
fields = ImVfbQFields( vfb );
/*
* If there's an alpha channel, use it as the AND mask
*/
if( fields & IMVFBALPHA )
{
/*
* Initialize
*/
count = 0;
/*
* Traverse through alpha plane and write out AND mask
*/
for( i = y-1; i > -1; --i )
{
wbufptr = wbuf;
for( j = 0; j < x; ++j )
{
vfbptr = ImVfbQPtr( vfb, j, i );
pvalue = ImVfbQAlpha( vfb, vfbptr );
if( pvalue < 128 )
{
bitfield = bitfield | 1;
}
++count;
if( count == 8 )
{
*(wbufptr++) = bitfield;
count = 0;
bitfield = 0;
}
bitfield = bitfield << 1;
}
if( ImBinWrite( ioType,fd,fp,wbuf,UCHAR,1,
scanlinesize )== -1 )
{
ImReturnBinError( );
}
}
}
else
{
/*
* Clear wbuf
*/
wbufptr = wbuf;
for( i = 0; i < scanlinesize; ++i )
{
*(wbufptr++) = 0;
}
/*
* Write AND mask scanlines
*/
for( i = 0; i < y; ++i )
{
if( ImBinWrite( ioType,fd,fp,wbuf,UCHAR,1,
scanlinesize )== -1 )
{
ImReturnBinError( );
}
}
}
free( (unsigned char*) wbuf );
}
return ( 1 );
}