2614 lines
40 KiB
C
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 );
|
|
|
|
}
|
|
|