/** ** $Header: /roq/libim/imbmp.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/imbmp.c 1 11/02/99 4:38p Zaphod $" /** ** FILE ** imbmp.c - Microsoft Windows BMP file I/O ** ** PROJECT ** libim - SDSC image manipulation library ** ** DESCRIPTION ** imbmp.c contains routines to read and write Microsoft Windows BMP ** (DIB) 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 ** ** ImFileBmpFormat v file format information ** ** PRIVATE CONTENTS ** imBmpFileHeader t file header information for read ** imBmpHeaderFields v imBmpHeaderInfoRead description for Bin pkg ** ** imBmpFileHeaderWrite t file header information for write ** imBmpHeaderFieldsWrite v imBmpHeaderInfoWrite description for Bin pkg ** ** imBmpRGBQuad t BMP colortable entry ** imBmpRGBQuadFields v imBmpRGBQuad description for Bin pkg ** ** IMBMPCHECKBUFIN m test for full read buffer and do read ** imBmpWrite2Bytes m write two RLE bytes ** ** imBmpRead f read BMP file ** imBmpReadRLE4 f read 4-bit RLE BMP file ** imBmpReadRLE8 f read 8-bit RLE BMP file ** ** imBmpWriteRLE4 f write 4-bit RLE BMP file ** imBmpWriteRLE8 f write 8-bit RLE BMP file ** imBmpWriteRaw1 f write 1-bit uncompressed BMP file ** imBmpWriteRaw4 f write 4-bit uncompressed BMP file ** imBmpWriteRaw8 f write 8-bit uncompressed BMP file ** imBmpWriteRaw24 f write 24-bit uncompressed BMP file ** ** HISTORY ** $Log: /roq/libim/imbmp.c $ ** ** 1 11/02/99 4:38p Zaphod ** Revision 1.14 1995/06/29 00:28:04 bduggan ** updated copyright year ** ** Revision 1.13 1995/06/15 20:14:44 bduggan ** Took out 'break's at unreachable points. Took out some ** unused variables. ** ** Revision 1.12 1995/04/03 21:19:36 bduggan ** took out -DNEWMAGIC ** ** Revision 1.11 1994/10/04 20:18:37 bduggan ** added IM to all defines ** ** Revision 1.10 1994/07/20 11:42:23 nadeau ** Changed SDSC custom types to match v3.0 sdsc.h, added ANSI ** C function prototypes, updated read and write maps, updated ** to the new magic number scheme. ** ** Revision 1.9 92/12/03 01:46:13 nadeau ** Corrected info messages. ** ** Revision 1.8 92/11/23 17:49:31 nadeau ** Removed use of IMINFOMSGWIDTH2 ** ** Revision 1.7 92/11/04 11:48:24 groening ** put ImFIleFormat info and magic number info ** from imfmt.c into this file. ** ** Revision 1.6 92/10/12 15:53:40 vle ** Made changes to make Cray happy. ** ** Revision 1.5 92/09/29 17:59:17 vle ** Added ImInfo messages. ** ** Revision 1.4 92/09/17 14:06:48 vle ** Fixed "scanlinesize" math bug that caused images to be cropped. ** ** Revision 1.3 92/09/03 18:19:05 vle ** Removed one function parameter from imBmpReadRLE4() and ** imBmpReadRLE8(). ** ** Revision 1.2 92/08/31 17:20:57 vle ** Updated copyright notice. ** ** Revision 1.1 92/08/12 16:46:02 vle ** Initial revision ** ** **/ //#include #include "iminternal.h" /** ** FORMAT ** bmp - Microsoft Windows bitmap image ** ** AKA ** dib (Device Independent Bitmap) ** ** 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. ** ** Graphics File Formats, David C. Kay, John R. Levine, McGraw-Hill, ** 1992. ** ** Supercharged Bitmapped Graphics, Steve Rimmer, McGraw-Hill, 1992. ** ** CODE CREDITS ** Custom development, Vinh Le, San Diego Supercomputer Center, 1992. ** ** DESCRIPTION ** Microsoft's BMP (BitMaP) format, also known as DIB (Device ** Independent Bitmap) format, is used in Microsoft's Windows ** versions 3.0 and up for bitmap image storage. ** ** The BMP format consists of four segments: ** ** Bitmap-File Header ** Bitmap-Info Header ** ColorTable ** BitmapBits ** ** ** Bitmap-File Header (14 bytes) ** ------------------ ** ** The Bitmap-File Header contains information about the type, ** size, and layout of a device-independent bitmap file. ** ** Name Type Size Comments ** ---- ---- ---- -------- ** bfType uint 2 bytes type of file, must be BM ** bfSize dword 4 bytes size of the file in bytes ** bfReserved1 uint 2 bytes reserved, must be zero ** bfReserved2 uint 2 bytes reserved, must be zero ** bfOffBits dword 4 bytes offset in bytes from the ** beginning of the file to ** the actual bitmap data in ** the file ** ** ( Note: types above and below are as reported in the Microsoft ** specification and refer to IBM PC-sized values. Usage of the ** SDSC Binary I/O library by this code insures that an appropriate ** portable mapping is made from PC types and sizes to this host's. ) ** ** typedef struct tagBITMAPFILEHEADER ** { ** uint bfType; ** dword bfSize; ** uint bfReserved1; ** uint bfReserved2; ** dword bfOffBits; ** } BITMAPFILEHEADER; ** ** ** Bitmap-Info Header (40 bytes) ** ------------------ ** ** The Bitmap-Info Header contains information about the bitmap's ** dimensions, compression type, and color format. ** ** Name Type Size Comments ** ---- ---- ---- -------- ** biSize dword 4 bytes number of bytes in ** Bitmap-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, ** 4, 8 or 24 ** biCompression dword 4 bytes BI_RGB(0), no compression ** BI_RLE8(1), RLE compression of ** 8-bits/pixel image ** BI_RLE4(2), RLE compression of ** 4-bits/pixel image ** biSizeImage dword 4 bytes image size in bytes ** biXPelsPerMeter long 4 bytes horizontal resolution in ** pixels per meter, used for ** aspect scaling ** biYPelsPerMeter long 4 bytes vertical resolution in ** pixels per meter, used for ** aspect scaling ** biClrUsed dword 4 bytes number of color indexes ** actually used by bitmap ** biClrImportant dword 4 bytes number of color absolutely ** necessary to display the ** image; if 0, all colors are ** needed ** ** 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; ** ** ** BitmapBits ** ---------- ** ** BitmapBits is the actual bitmap image data. It is an array ** of bytes representing consecutive scanlines. The number of ** bytes varies with the resolution and number of colors. Each ** scanline must be zero-padded to a 32-bit boundary. Scanlines ** are stored from the bottom up; that is, the first-byte is in ** the lower-left corner of the image. ** ** The biBitCount field of BITMAPINFOHEADER gives the bits per ** pixel information for the bitmap. Valid values are 1 ** (monochrome image, 2 color image), 4 (16 color image), ** 8 (256 color image), or 24 (true color). ** ** Monochrome images have 2 color colortables. They are non- ** compressed, but are pixel packed. 8 pixels are packed into ** each stored byte. A clear bit means use the first color. ** A set bit means use the second color. ** ** 4-bits/pixel images can be non-compressed or compressed. ** Non-compressed images are pixel packed. Each byte stores ** two 4-bit pixels. Compressed images are compressed with ** a 4-bit RLE (RLE4) variant described below. ** ** 8-bits/pixel images can be non-compressed or compressed. ** For non-compressed images, each byte stores one 8-bit pixel. ** Compressed images are compressed with an 8-bit RLE (RLE8) ** variant described below. ** ** 24-bits/pixel images are stored non-compressed. Each pixel ** is represented by 3 bytes. Each byte represents Blue, ** Green, and Red, in this order. ** ** RLE4 - 4-bit RLE Encoding Scheme ** -------------------------------- ** ** The 4-bit RLE encoding scheme consists of two modes, Encoded ** and Absolute. ** ** The Encoded Mode consists of two byte pairs. ** 1st byte length of run ** 2nd byte This byte contains 2 color indicies, one in ** the high 4 bits and one in the low 4 bits. ** The run is filled with alternating sequences ** of these indicies. ** ** if the 1st byte is zero (0x00), then the 2nd byte is interpreted ** as follows: ** 0x00 End of scanline ** 0x01 End of bitmap ** 0x02 "Delta". The next two bytes indicate right ** and down movements. ** 0x03- Copy the next 3 to 255 4-bit byte halves ** 0xFF literally. This is the Absolute Mode. ** ** The Absolute Mode is described as above. It always has zero ** (0x00) as the 1st byte. The 2nd byte can range between 0x03 ** to 0xFF as described. ** ** ex. Compressed Expanded ** ---------- -------- ** 03 04 0 4 0 ** 05 06 0 6 0 6 0 ** 00 06 45 56 67 00 4 5 5 6 6 7 ** 00 02 05 01 Move 5 right and 1 down ** 04 78 7 8 7 8 ** 00 00 End of scanline ** 09 1E 1 E 1 E 1 E 1 E 1 ** 00 01 End of RLE bitmap ** ** Note: Runs must be word aligned! ** ** RLE8 - 8-bit RLE Encoding Scheme ** -------------------------------- ** ** The 8-bit RLE encoding scheme consists of two modes, Encoded ** and Absolute. ** ** The Encoded Mode consists of two byte pairs. ** 1st byte length of run ** 2nd byte byte to repeat in run (color index for pixel) ** ** if the 1st byte is zero (0x00), then the 2nd byte is interpreted ** as follows: ** 0x00 End of scanline ** 0x01 End of bitmap ** 0x02 "Delta". The next two bytes indicate right ** and down movements. ** 0x03- Copy the next 3 - 255 bytes literally. ** 0xFF This is the Absolute Mode. ** ** The Absolute Mode is described as above. It always has zero ** (0x00) as the 1st byte. The 2nd byte can range between 0x03 ** to 0xFF as described. ** ** ex. Compressed Expanded ** ---------- -------- ** 03 04 04 04 04 ** 05 06 06 06 06 06 06 ** 00 03 45 56 67 00 45 56 67 ** 00 02 05 01 Move 5 right and 1 down ** 02 78 78 78 ** 00 00 End of scanline ** 09 1E 1E 1E 1E 1E 1E 1E 1E 1E 1E ** 00 01 End of RLE bitmap ** ** Note: Runs must be word aligned! ** **/ /* * FUNCTION DECLARATIONS */ #ifdef __STDC__ static int imBmpRead( int, int, FILE *, TagTable *, TagTable * ); static int imBmpReadRLE4( int, int, FILE *, ImVfb *, unsigned int ); static int imBmpReadRLE8( int, int, FILE *, ImVfb *, unsigned int ); static int imBmpWriteRaw1( ImFileFormatWriteMap *, int, int, FILE *, TagTable *, TagTable * ); static int imBmpWriteRaw4( ImFileFormatWriteMap *, int, int, FILE *, TagTable *, TagTable * ); static int imBmpWriteRaw8( ImFileFormatWriteMap *, int, int, FILE *, TagTable *, TagTable * ); static int imBmpWriteRaw24( ImFileFormatWriteMap *, int, int, FILE *, TagTable *, TagTable * ); static int imBmpWriteRLE4( ImFileFormatWriteMap *, int, int, FILE *, TagTable *, TagTable * ); static int imBmpWriteRLE8( ImFileFormatWriteMap *, int, int, FILE *, TagTable *, TagTable * ); #else static int imBmpRead( ), imBmpReadRLE4( ), imBmpReadRLE8( ); static int imBmpWriteRaw1( ), imBmpWriteRaw4( ), imBmpWriteRaw8( ) ; static int imBmpWriteRaw24( ), imBmpWriteRLE4( ), imBmpWriteRLE8( ) ; #endif /* * FORMAT INFORMATION * imBmpNames - format's name and aliases * imBmpReadMap - read attributes * imBmpWriteMap - write attributes * imBmpMagicNumber - magic number * imBmpMagic - list of magic numbers * ImFileBmpFormat - master format description */ static char *imBmpNames[ ] = { "bmp", "dib", NULL }; static ImFileFormatReadMap imBmpReadMap[ ] = { /* in out */ /* type,ch,dep, attr. VFB type attr. */ { RGB,3,8, 0, IMVFBRGB, 0 }, { IN,1,8, C, IMVFBINDEX8, C }, { IN,1,4, C, IMVFBINDEX8, C }, { IN,1,8, RLE|C, IMVFBINDEX8, C }, { IN,1,4, RLE|C, IMVFBINDEX8, C }, { IN,1,1, C, IMVFBINDEX8, C }, { -1, 0, -1, 0 }, }; static ImFileFormatWriteMap imBmpWriteMap[ ] = { /* in out */ /* VFB type, attr., type,ch,dep, attr., func */ { IMVFBMONO, 0, IN,1,1, C, imBmpWriteRaw1 }, { IMVFBINDEX8, C, IN,1,8, C, imBmpWriteRaw8 }, { IMVFBINDEX8, C, IN,1,4, C, imBmpWriteRaw4 }, { IMVFBINDEX8, C, IN,1,8, RLE|C, imBmpWriteRLE8 }, { IMVFBINDEX8, C, IN,1,4, RLE|C, imBmpWriteRLE4 }, { IMVFBRGB, 0, RGB,3,8, 0, imBmpWriteRaw24 }, { -1, 0, -1, 0, NULL } }; static unsigned char imBmpMagicNumber[ ] = { 'B', 'M' }; static ImFileMagic imBmpMagic[ ] = { { 0, 2, imBmpMagicNumber }, { 0, 0, NULL }, }; ImFileFormat ImFileBmpFormat = { imBmpNames, /* Names */ "Windows bitmap image file", /* Description */ "Microsoft", /* Creator */ "1-, 4-, and 8-bit color index, and 24-bit RGB color, and\n\ - and 8-bit RLE compressed images.", /* Read support */ "1-, 4-, and 8-bit color index, and 24-bit RGB color, and\n\ - and 8-bit RLE compressed images.", /* Write support*/ imBmpMagic, /* Magic #'s */ IMNOMULTI, IMPIPE, /* Read? */ IMNOMULTI, IMNOPIPE, /* Write? */ imBmpRead, imBmpReadMap, imBmpWriteMap /* Maps */ }; /* * TYPEDEF & STRUCTURE * imBmpHeaderInfoRead - BMP file header information for read * imBmpHeaderFieldsRead - BMP file header fields for binary pkg. * imBmpHeaderInfoWrite - BMP file header information for write * imBmpHeaderFieldsWrite - BMP file header fields for binary pkg. * imBmpRGBQuad - BMP color information * imBmpRGBQuadFields - BMP color information fields for binary * pkg. * * DESCRIPTION * imBmpHeaderInfo contains both the Bitmap-File Header and * Bitmap-Info Header as described in the format specifications. * * The imBmpRGBQuad is one entry in the colortable. */ typedef struct imBmpHeaderInfoRead { sdsc_uint32 bmp_size; /* size of file in bytes */ sdsc_uint16 bmp_reserved1; /* reserved1, must be zero */ sdsc_uint16 bmp_reserved2; /* reserved2, must be zero */ sdsc_uint32 bmp_offsetbits; /* offset to actual bitmap data */ sdsc_uint32 bmp_bisize; /* # bytes in bitmap info header*/ sdsc_uint32 bmp_biwidth; /* image width in pixels */ sdsc_uint32 bmp_biheight; /* image height in pixels */ sdsc_uint16 bmp_biplanes; /* # planes for device, always 1*/ sdsc_uint16 bmp_bibitcount; /* bits/pixel (1, 4, 8, or 24) */ sdsc_uint32 bmp_bicompress; /* compression method */ sdsc_uint32 bmp_bisizeimage; /* image size in bytes */ sdsc_uint32 bmp_bixpm; /* x pixels per meter */ sdsc_uint32 bmp_biypm; /* y pixels per meter */ sdsc_uint32 bmp_biclrused; /* # colors actually used in CLT*/ sdsc_uint32 bmp_biclrim; /* # required colors to display */ } imBmpHeaderInfoRead; static BinField imBmpHeaderFieldsRead[ ] = { { UINT32, 4, 1 }, /* bmp_size */ { UINT16, 2, 1 }, /* bmp_reserved1 */ { UINT16, 2, 1 }, /* bmp_reserved2 */ { UINT32, 4, 1 }, /* bmp_offsetbits */ { UINT32, 4, 1 }, /* bmp_bisize */ { UINT32, 4, 1 }, /* bmp_biwidth */ { UINT32, 4, 1 }, /* bmp_biheight */ { UINT16, 2, 1 }, /* bmp_biplanes */ { UINT16, 2, 1 }, /* bmp_bibitcount */ { UINT32, 4, 1 }, /* bmp_bicompress */ { UINT32, 4, 1 }, /* bmp_bisizeimage */ { UINT32, 4, 1 }, /* bmp_bixpm */ { UINT32, 4, 1 }, /* bmp_biypm */ { UINT32, 4, 1 }, /* bmp_biclrused */ { UINT32, 4, 1 }, /* bmp_biclrim */ { 0, 0, 0 } }; typedef struct imBmpHeaderInfoWrite { sdsc_uint16 bmp_type; /* type of image, must be 'BM' */ sdsc_uint32 bmp_size; /* size of file in bytes */ sdsc_uint16 bmp_reserved1; /* reserved1, must be zero */ sdsc_uint16 bmp_reserved2; /* reserved2, must be zero */ sdsc_uint32 bmp_offsetbits; /* offset to actual bitmap data */ sdsc_uint32 bmp_bisize; /* # bytes in bitmap info header*/ sdsc_uint32 bmp_biwidth; /* image width in pixels */ sdsc_uint32 bmp_biheight; /* image height in pixels */ sdsc_uint16 bmp_biplanes; /* # planes for device, always 1*/ sdsc_uint16 bmp_bibitcount; /* bits/pixel (1, 4, 8, or 24) */ sdsc_uint32 bmp_bicompress; /* compression method */ sdsc_uint32 bmp_bisizeimage; /* image size in bytes */ sdsc_uint32 bmp_bixpm; /* x pixels per meter */ sdsc_uint32 bmp_biypm; /* y pixels per meter */ sdsc_uint32 bmp_biclrused; /* # colors actually used from CLT*/ sdsc_uint32 bmp_biclrim; /* # required colors to display */ } imBmpHeaderInfoWrite; static BinField imBmpHeaderFieldsWrite[ ] = { { UINT16, 2, 1 }, /* bmp_type */ { UINT32, 4, 1 }, /* bmp_size */ { UINT16, 2, 1 }, /* bmp_reserved1 */ { UINT16, 2, 1 }, /* bmp_reserved2 */ { UINT32, 4, 1 }, /* bmp_offsetbits */ { UINT32, 4, 1 }, /* bmp_bisize */ { UINT32, 4, 1 }, /* bmp_biwidth */ { UINT32, 4, 1 }, /* bmp_biheight */ { UINT16, 2, 1 }, /* bmp_biplanes */ { UINT16, 2, 1 }, /* bmp_bibitcount */ { UINT32, 4, 1 }, /* bmp_bicompress */ { UINT32, 4, 1 }, /* bmp_bisizeimage */ { UINT32, 4, 1 }, /* bmp_bixpm */ { UINT32, 4, 1 }, /* bmp_biypm */ { UINT32, 4, 1 }, /* bmp_biclrused */ { UINT32, 4, 1 }, /* bmp_biclrim */ { 0, 0, 0 } }; typedef struct imBmpRGBQuad { unsigned char blue; /* blue intensity */ unsigned char green; /* green intensity */ unsigned char red; /* red intensity */ unsigned char reserved; /* unused */ } imBmpRGBQuad; static BinField imBmpRGBQuadFields[ ] = { { UCHAR, 1, 1 }, /* blue */ { UCHAR, 1, 1 }, /* green */ { UCHAR, 1, 1 }, /* red */ { UCHAR, 1, 1 }, /* reserved */ { 0, 0, 0 } }; /* * CONSTANTS * BMP* - assorted useful BMP constants */ #define IMBMPMAGIC_MBF 0x424d /* magic value, 'BM' */ #define IMBMPMAGIC_LBF 0x4d42 /* magic value, 'BM' in reverse byte order */ #define IMBMPFILEHEADERSIZE 14 /* 14 bytes */ #define IMBMPINFOHEADERSIZE 40 /* 40 bytes */ #define IMBMPHEADERSIZE (IMBMPFILEHEADERSIZE + IMBMPINFOHEADERSIZE) /* size of complete header */ #define IMBMPRGBQUADSIZE 4 /* 4 bytes */ #define IMBMPRGB 0 /* no compression */ #define IMBMPRLE8 1 /* 8-bit RLE compression */ #define IMBMPRLE4 2 /* 4-bit RLE compression */ #define IMBLKSIZE (BUFSIZ) /* number of bytes to read */ #define IMBMPCHECKBUFIN \ if( bufin > (IMBLKSIZE-1) ) \ { \ if( ImBinRead( ioType,fd,fp,buf,UCHAR,1,IMBLKSIZE )==-1) \ { \ ImReturnBinError( ); \ } \ bufin = 0; \ } \ /* * FUNCTION * imBmpReadRLE8 - Read a BMP 8-bit RLE compressed image * * DESCRIPTION * This function reads in and decompresses a BMP 8-bit RLE image * into a vfb. See encoding scheme in FORMAT section. */ static int /* Returns status */ #ifdef __STDC__ imBmpReadRLE8( int ioType, int fd, FILE *fp, ImVfb *vfb, unsigned int y ) #else imBmpReadRLE8( ioType, fd, fp, vfb, y ) int ioType; /* I/O flags */ int fd; /* Input file descriptor */ FILE *fp; /* Input file pointer */ ImVfb *vfb; /* Pointer to image */ unsigned int y; /* height of image */ #endif { ImVfbPtr vfbptr; /* Pointer into vfb image */ unsigned char pair[ 2 ];/* RLE code pair */ unsigned char ampair[ 2 ];/* RLE Absolute Mode pair */ int ycount; /* Current scanline */ unsigned char buf[ IMBLKSIZE ]; /* File input buffer */ int bufin; /* File input buffer index */ int i; /* Counters */ /* * 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 vfb */ vfbptr = ImVfbQPtr( vfb, 0, y-1 ); /* * Initializations */ ycount = 0; bufin = IMBLKSIZE; /* * Read in and decompress image bitmap */ while( ycount < y) { /* * Read in file data into buf */ IMBMPCHECKBUFIN; pair[0] = buf[ bufin++ ]; IMBMPCHECKBUFIN; pair[1] = buf[ bufin++ ]; if ( pair[0] != 0x00 ) { /* Encoded Mode */ for( i = 0; i < pair[0]; ++i ) { ImVfbSIndex8( vfb, vfbptr, pair[1] ); vfbptr = ImVfbQRight( vfb, vfbptr ); } continue; } switch( pair[1] ) { case 0x00: /* end of scanline */ vfbptr = ImVfbQUp( vfb, vfbptr ); vfbptr = ImVfbQUp( vfb, vfbptr ); ++ycount; break; case 0x01: /* end of bitmap */ if( ycount != y-1 ) { /* issue warning to user */ ImErrorWarning( "Unexpected end of bitmap. Input file may be corrupted!", -1, IMEDECODING ); } return( 1 ); case 0x02: /* "delta", right and down movement */ /* * Read in file data into buf */ IMBMPCHECKBUFIN; pair[0] = buf[ bufin++ ]; IMBMPCHECKBUFIN; pair[1] = buf[ bufin++ ]; for( i = 0; i < pair[0]; ++i ) { vfbptr = ImVfbQRight( vfb, vfbptr ); } for( i = 0; i < pair[1]; ++i ) { vfbptr = ImVfbQDown( vfb, vfbptr ); } break; default: /* Absolute Mode */ for( i = 0; i < pair[1]/2; ++i ) { /* * Read in file data into buf */ IMBMPCHECKBUFIN; ampair[0] = buf[ bufin++ ]; IMBMPCHECKBUFIN; ampair[1] = buf[ bufin++ ]; ImVfbSIndex8( vfb, vfbptr, ampair[0] ); vfbptr = ImVfbQRight( vfb, vfbptr ); ImVfbSIndex8( vfb, vfbptr, ampair[1] ); vfbptr = ImVfbQRight( vfb, vfbptr ); } if( (pair[1]%2) != 0 ) { /* * Read in file data into buf */ IMBMPCHECKBUFIN; ampair[0] = buf[ bufin++ ]; IMBMPCHECKBUFIN; ampair[1] = buf[ bufin++ ]; ImVfbSIndex8( vfb, vfbptr, ampair[0] ); vfbptr = ImVfbQRight( vfb, vfbptr ); } break; } /* end switch */ } return( 1 ); } /* * FUNCTION * imBmpReadRLE4 - Read a BMP 4-bit RLE compressed image * * DESCRIPTION * This function reads in and decompresses a BMP 4-bit RLE image * into a vfb. See encoding scheme in FORMAT section. */ static int /* Returns status */ #ifdef __STDC__ imBmpReadRLE4( int ioType, int fd, FILE *fp, ImVfb *vfb, unsigned int y ) #else imBmpReadRLE4( ioType, fd, fp, vfb, y ) int ioType; /* I/O flags */ int fd; /* Input file descriptor */ FILE *fp; /* Input file pointer */ ImVfb *vfb; /* Pointer to image */ unsigned int y; /* height of image */ #endif { ImVfbPtr vfbptr; /* Pointer into vfb image */ unsigned char pair[ 2 ];/* RLE code pair */ unsigned char ampair[ 2 ];/* RLE Absolute Mode pair */ int ycount; /* Current scanline */ unsigned char buf[ IMBLKSIZE ]; /* File input buffer */ int bufin; /* File input buffer pointer */ int i; /* Counters */ /* * 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 vfb */ vfbptr = ImVfbQPtr( vfb, 0, y-1 ); /* * Initializations */ ycount = 0; bufin = IMBLKSIZE; /* * Read in and decompress image bitmap */ while( ycount < y ) { /* * Read in file data into buf */ IMBMPCHECKBUFIN; pair[0] = buf[ bufin++ ]; IMBMPCHECKBUFIN; pair[1] = buf[ bufin++ ]; if ( pair[0] != 0x00 ) { /* Encoded Mode */ for( i = 0; i < pair[0]/2; ++i ) { ImVfbSIndex8( vfb, vfbptr, (pair[1] >> 4) ); vfbptr = ImVfbQRight( vfb, vfbptr ); ImVfbSIndex8( vfb, vfbptr, pair[1] & 0x0F ); vfbptr = ImVfbQRight( vfb, vfbptr ); } if( pair[0]%2 != 0 ) { ImVfbSIndex8( vfb, vfbptr, (pair[1] >> 4) ); vfbptr = ImVfbQRight( vfb, vfbptr ); } continue; } switch( pair[1] ) { case 0x00: /* end of scanline */ vfbptr = ImVfbQUp( vfb, vfbptr ); vfbptr = ImVfbQUp( vfb, vfbptr ); ++ycount; break; case 0x01: /* end of bitmap */ if( ycount != y-1 ) { /* issue warning to user */ ImErrorWarning( "Unexpected end of bitmap. Input file may be corrupted!", -1, IMEDECODING ); } return( 1 ); case 0x02: /* "delta", right and down movement */ /* * Read in file data into buf */ IMBMPCHECKBUFIN; pair[0] = buf[ bufin++ ]; IMBMPCHECKBUFIN; pair[1] = buf[ bufin++ ]; for( i = 0; i < pair[0]; ++i ) { vfbptr = ImVfbQRight( vfb, vfbptr ); } for( i = 0; i < pair[1]; ++i ) { vfbptr = ImVfbQDown( vfb, vfbptr ); } break; default: /* Absolute Mode */ for( i = 0; i < pair[1]/4; ++i ) { /* * Read in file data into buf */ IMBMPCHECKBUFIN; ampair[0] = buf[ bufin++ ]; IMBMPCHECKBUFIN; ampair[1] = buf[ bufin++ ]; ImVfbSIndex8( vfb, vfbptr, (ampair[0] >> 4) ); vfbptr = ImVfbQRight( vfb, vfbptr ); ImVfbSIndex8( vfb, vfbptr, ampair[0] & 0x0F ); vfbptr = ImVfbQRight( vfb, vfbptr ); ImVfbSIndex8( vfb, vfbptr, (ampair[1] >> 4) ); vfbptr = ImVfbQRight( vfb, vfbptr ); ImVfbSIndex8( vfb, vfbptr, ampair[1] & 0x0F ); vfbptr = ImVfbQRight( vfb, vfbptr ); } if( (pair[1]%4) != 0 ) { /* * Read in file data into buf */ IMBMPCHECKBUFIN; ampair[0] = buf[ bufin++ ]; IMBMPCHECKBUFIN; ampair[1] = buf[ bufin++ ]; ImVfbSIndex8( vfb, vfbptr, (ampair[0] >> 4) ); vfbptr = ImVfbQRight( vfb, vfbptr ); if( pair[1]%4 > 1 ) { ImVfbSIndex8( vfb, vfbptr, ampair[0] & 0x0F ); vfbptr = ImVfbQRight( vfb, vfbptr ); } if( pair[1]%4 > 2 ) { ImVfbSIndex8( vfb, vfbptr, ampair[1] >> 4 ); vfbptr = ImVfbQRight( vfb, vfbptr ); } } break; } /* end switch */ } return( 1 ); } /* * FUNCTION * imBmpRead - read a Microsoft Windows Bmp 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__ imBmpRead( int ioType, int fd, FILE *fp, TagTable *flagsTable, TagTable *tagTable ) #else imBmpRead( 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 { imBmpHeaderInfoRead header; /* BMP file header */ ImVfb *vfb; /* Virtual Frame Buffer */ ImVfbPtr vfbptr; /* Pixel pointer */ ImClt *clt = IMCLTNULL; /* Colortable */ ImCltPtr cltptr; /* Colortable entry pointer */ int x,y; /* Convenient short names */ unsigned char mask; /* Mask for extracting pixels */ sdsc_uint16 bmp_type; /* BMP type (magic number) */ unsigned char *rbuf = NULL; /* read buffer */ unsigned char *rbufptr; /* read buffer data pointer */ unsigned char *sbuf = NULL; /* skip buffer */ unsigned int skipsize = 0; /* number of bytes to skip */ unsigned int scanlinesize; /* length of scanline in bytes */ unsigned int ncolors = 0; /* number of colors used */ unsigned int i, j, k; /* Counters */ char message[100]; /* ImInfo message */ /* * Set Binary Package byte order and read in BMP type */ BinByteOrder( BINLBF ); if( ImBinRead( ioType, fd, fp, &bmp_type, UINT16, 2, 1) == -1 ) { ImReturnBinError( ); } /* * Use BMP type (magic number) to determine byte ordering of rest * of file */ switch( bmp_type ) { case IMBMPMAGIC_LBF: /* no need to change byte ordering */ ImInfo( "Byte Order", "Least Significant Byte First" ); break; case IMBMPMAGIC_MBF: ImInfo( "Byte Order", "Most Significant Byte First" ); BinByteOrder( BINMBF ); break; default: /* * Bad BMP type (magic number) */ ImErrorFatal( ImQError( ), -1, IMEMAGIC ); } /* * Read in rest of Bmp file header */ if( ImBinReadStruct( ioType, fd, fp, &header, imBmpHeaderFieldsRead )== -1) { ImReturnBinError( ); } x = header.bmp_biwidth; y = header.bmp_biheight; sprintf( message, "%d x %d", x, y ); ImInfo( "Resolution", message ); /* * Allocate a VFB of the required size and type. */ switch( header.bmp_bibitcount ) { case 1: /* 1-bit index image */ case 4: /* 4-bit index image */ case 8: /* 8-bit index image */ if( (vfb = ImVfbAlloc( x, y, IMVFBINDEX8 )) == IMVFBNULL ) { ImErrorFatal( ImQError( ), -1, ImErrNo ); } ImVfbClear( IMVFBINDEX8, 0, vfb ); sprintf( message, "%d-bit Color Indexed", header.bmp_bibitcount ); ImInfo( "Type", message ); break; case 24: /* 24-bit RGB image */ if( (vfb = ImVfbAlloc( x, y, IMVFBRGB )) == IMVFBNULL ) { ImErrorFatal( ImQError( ), -1, ImErrNo ); } ImVfbClear( IMVFBRGB, 0, vfb ); sprintf( message, "24-bit RGB" ); ImInfo( "Type", message ); break; default: /* unsupported image depth */ ImErrorFatal( ImQError( ), -1, IMEDEPTH ); } /* * Allocate and read in colortable, if necessary */ if( header.bmp_bibitcount != 24) { /* * Find number of colors used and allocate space * for colortable */ ncolors = header.bmp_biclrused; if( ncolors == 0 ) { ncolors = 1 << header.bmp_bibitcount; } clt = ImCltAlloc( ncolors ); /* * Output -verbose messages */ sprintf( message, "%d Entries", ncolors ); ImInfo( "Color Table", message ); /* * Read in colortable and set RGB values */ cltptr = ImCltQFirst( clt ); ImMalloc( rbuf, unsigned char*, ncolors*IMBMPRGBQUADSIZE ); rbufptr = rbuf; if( ImBinRead( ioType, fd, fp, rbuf, UCHAR, 1, ncolors*IMBMPRGBQUADSIZE ) == -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)); } /* * Skip to beginning of bitmap data */ skipsize = ( (header.bmp_offsetbits - IMBMPHEADERSIZE) - (ncolors * IMBMPRGBQUADSIZE ) ); if( skipsize > 0 ) { if( ioType & IMFILEIOFD ) { ImSeek( ioType, fd, fp, header.bmp_offsetbits, L_SET ); } else { ImMalloc( sbuf, unsigned char*, skipsize ); if( ImBinRead( ioType, fd, fp, sbuf, UCHAR, 1, skipsize ) == -1 ) { free( (char*) sbuf ); ImReturnBinError( ); } free( (unsigned char*) sbuf ); } } /* * Use image compression type info to determine whether to do * verbatim copy into the vfb or RLE expansion into the vfb */ if( header.bmp_bicompress == IMBMPRGB ) /* no compression */ { /* * 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 vfb */ vfbptr = ImVfbQPtr( vfb, 0, y-1 ); /* * Read in non-compressed image */ switch( header.bmp_bibitcount ) { case 1: ImInfo( "Compression Type", "none" ); /* * 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 ) { ImVfbSIndex8( vfb, vfbptr, 1 ); } else { ImVfbSIndex8( vfb, vfbptr, 0 ); } vfbptr = ImVfbQRight( vfb, vfbptr ); mask = mask >> 1; } ++rbufptr; } if( x%8 ) { mask = 128; for( k = 0; k < x%8; ++k ) { if( ( *(rbufptr) & mask ) == mask ) { ImVfbSIndex8( vfb, vfbptr, 1 ); } else { ImVfbSIndex8( vfb, vfbptr, 0 ); } vfbptr = ImVfbQRight( vfb, vfbptr ); mask = mask >> 1; } } /* * Go up two scanline since we * wrapped-around with ImVfbQRight( ) */ vfbptr = ImVfbQUp( vfb, vfbptr ); vfbptr = ImVfbQUp( vfb, vfbptr ); } break; case 4: ImInfo( "Compression Type", "none" ); /* * Read 4-bit non-compressed image * * 1 byte contains info for 2 pixels * * ---- ---- <-- 1 byte * 1111 2222 * */ /* * Find scanline size to nearest 32-bit * boundary and allocate read buffer * * Note: bit shifting is used to speed up * calculations */ scanlinesize = x>>3; if( x%8 ) scanlinesize++; scanlinesize <<= 2; ImMalloc( rbuf, unsigned char*, scanlinesize ); /* * Read in image and store in vfb */ for( i = 0; i < y; ++i ) { if( ImBinRead( ioType, fd, fp, rbuf, UCHAR, 1, scanlinesize ) == -1) { ImReturnBinError( ); } rbufptr = rbuf; for( j = 0; j < (x/2); ++j ) { mask = 0xF0; ImVfbSIndex8( vfb, vfbptr, ((*(rbufptr) & mask) >> 4) ); vfbptr = ImVfbQRight( vfb, vfbptr ); mask = 0x0F; ImVfbSIndex8( vfb, vfbptr, *(rbufptr) & mask ); vfbptr = ImVfbQRight( vfb, vfbptr ); ++rbufptr; } if( x%2 ) { mask = 0xF0; ImVfbSIndex8( vfb, vfbptr, ((*(rbufptr) & mask) >> 4) ); vfbptr = ImVfbQRight( vfb, vfbptr ); } /* * Go up two scanline since we * wrapped-around with ImVfbQRight( ) */ vfbptr = ImVfbQUp( vfb, vfbptr ); vfbptr = ImVfbQUp( vfb, vfbptr ); } break; case 8: ImInfo( "Compression Type", "none" ); /* * Read 8-bit non-compressed image * * 1 byte contains info for 1 pixel * * -------- <-- 1 byte * 11111111 * */ /* * Find scanline size to nearest 32-bit * boundary and allocate read buffer * * Note: bit shifting is used to speed up * calculations */ scanlinesize = x>>2; if( x%4 ) scanlinesize++; scanlinesize <<= 2; ImMalloc( rbuf, unsigned char*, scanlinesize ); /* * Read in image and store in vfb */ for( i = 0; i < y; ++i ) { if( ImBinRead( ioType, fd, fp, rbuf, UCHAR, 1, scanlinesize ) == -1) { ImReturnBinError( ); } rbufptr = rbuf; for( j = 0; j < x; ++j ) { ImVfbSIndex8( vfb, vfbptr, *(rbufptr) ); vfbptr = ImVfbQRight( vfb, vfbptr ); ++rbufptr; } /* * Go up two scanline since we * wrapped-around with ImVfbQRight( ) */ vfbptr = ImVfbQUp( vfb, vfbptr ); vfbptr = ImVfbQUp( vfb, vfbptr ); } break; case 24: ImInfo( "Compression Type", "none" ); /* * Read 24-bit non-compressed image * * 3 bytes contain info for 1 pixel * * -------- -------- -------- <-- 3 bytes * BBBBBBBB GGGGGGGG RRRRRRRR * */ /* * Find scanline size to nearest 32-bit * boundary and allocate read buffer * * Note: bit shifting is used to speed up * calculations */ scanlinesize = (x*3)>>2; if( x%4 ) scanlinesize++; scanlinesize <<= 2; ImMalloc( rbuf, unsigned char*, scanlinesize ); /* * Read in image and store in vfb */ for( i = 0; i < y; ++i ) { if( ImBinRead( ioType, fd, fp, rbuf, UCHAR, 1, scanlinesize ) == -1) { ImReturnBinError( ); } rbufptr = rbuf; for( j = 0; j < x; ++j ) { ImVfbSBlue( vfb, vfbptr, *(rbufptr) ); ++rbufptr; ImVfbSGreen( vfb, vfbptr, *(rbufptr) ); ++rbufptr; ImVfbSRed( vfb, vfbptr, *(rbufptr) ); ++rbufptr; vfbptr = ImVfbQRight( vfb, vfbptr ); } /* * Go up two scanline since we * wrapped-around with ImVfbQRight( ) */ vfbptr = ImVfbQUp( vfb, vfbptr ); vfbptr = ImVfbQUp( vfb, vfbptr ); } break; } /* end switch */ free( (unsigned char*) rbuf ); } else /* RLE decompression for 4-bit or 8-bit images */ { switch( header.bmp_bicompress ) { case IMBMPRLE4: if( imBmpReadRLE4( ioType, fd, fp, vfb, y ) == -1 ) { return( -1 ); } ImInfo( "Compression Type", "Run Length Encoded (RLE4)" ); break; case IMBMPRLE8: if( imBmpReadRLE8( ioType, fd, fp, vfb, y ) == -1 ) { return( -1 ); } ImInfo( "Compression Type", "Run Length Encoded (RLE8)" ); break; default: /* unknown decompression type */ ImErrorFatal( ImQError( ), -1, IMEIMAGETYPE ); } /* end switch */ } /* * Add the VFB to the tagTable. */ TagTableAppend( tagTable, TagEntryAlloc( "image vfb", POINTER, &vfb ) ); return ( 2 ); } /* * FUNCTION * imBmpWriteRaw1 - write an 1-bit non-compressed BMP file * * DESCRIPTION * That VFB is queried, and the BMP file header set up and written out. * The VFB data is then converted and written out. */ static int /* Returns # of tags used */ #ifdef __STDC__ imBmpWriteRaw1( ImFileFormatWriteMap *pMap, int ioType, int fd, FILE *fp, TagTable *flagsTable, TagTable *tagTable ) #else imBmpWriteRaw1( 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 { imBmpHeaderInfoWrite header; /* BMP file header */ ImVfb *vfb; /* Read in image */ ImVfbPtr vfbptr; /* Vfb pixel pointer */ imBmpRGBQuad cltentry; /* Colortable RGBQuad entry */ ImClt *clt; /* Colortable */ ImCltPtr cltptr; /* Colortable entry 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 int ncolors = 0; /* Number of colors used */ unsigned char bitfield; /* Bitfield of 8 pixels */ unsigned int x, y; /* Width, Height */ int i, j, k; /* Counters */ char message[100]; /* ImInfo message */ /* * Set byte ordering */ BinByteOrder( BINLBF ); /* * Get vfb and clt */ TagEntryQValue( TagTableQDirect( tagTable, "image vfb", 0 ), &vfb ); clt = ImVfbQClt( vfb ); x = ImVfbQWidth( vfb ); y = ImVfbQHeight( vfb ); /* * Find scanline size to nearest 32-bit * boundary and allocate write buffer * * Note: bit shifting is used to speed up * calculations */ scanlinesize = x>>5; if( x%32 ) scanlinesize++; scanlinesize <<= 2; if( clt != IMCLTNULL ) { ncolors = ImCltQNColors( clt ); if( ncolors > 2 ) { ncolors = 2; } } /* * Setup header and write it out */ header.bmp_type = IMBMPMAGIC_LBF; header.bmp_size = (unsigned int) ( IMBMPHEADERSIZE + ( 2 * IMBMPRGBQUADSIZE ) + ( scanlinesize * y ) ); /* * file size = complete header size + * colortable size + image data size */ header.bmp_reserved1 = 0; header.bmp_reserved2 = 0; header.bmp_offsetbits = (unsigned int) IMBMPHEADERSIZE + ( 2 * IMBMPRGBQUADSIZE ); /* * offset to image data = * BMP header + * colortable size */ header.bmp_bisize = IMBMPINFOHEADERSIZE; header.bmp_biwidth = x; header.bmp_biheight = y; header.bmp_biplanes = 1; header.bmp_bibitcount = 1; header.bmp_bicompress = IMBMPRGB; header.bmp_bisizeimage = scanlinesize * y; header.bmp_bixpm = 0; header.bmp_biypm = 0; header.bmp_biclrused = 0; header.bmp_biclrim = 0; if ( ImBinWriteStruct( ioType, fd, fp, &header, imBmpHeaderFieldsWrite )==-1) { ImReturnBinError( ); } /* * Output -verbose messages */ ImInfo( "Byte Order", "Least Significant Byte First" ); sprintf( message, "%d x %d", x, y ); ImInfo( "Resolution", message ); ImInfo( "Type", "1-bit Color Indexed" ); ImInfo( "Color Table", "2 Entries" ); ImInfo( "Compression Type", "none" ); /* * Output Color Table */ 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,imBmpRGBQuadFields )==-1) { ImReturnBinError( ); } cltentry.blue = 255; cltentry.green = 255; cltentry.red = 255; if( clt != IMCLTNULL ) { 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,imBmpRGBQuadFields )==-1) { ImReturnBinError( ); } /* * Allocate write buffer space */ ImCalloc( wbuf, unsigned char*, scanlinesize, sizeof( unsigned char) ); /* * Output image bitmap */ /* * Go to last vfb scanline */ vfbptr = ImVfbQPtr( vfb, 0, y-1 ); for( i = 0; i < y; ++i ) { 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 ); } free( (unsigned char*) wbuf ); return ( 1 ); } /* * FUNCTION * imBmpWriteRaw4 - write a 4-bit non-compressed BMP file * * DESCRIPTION * That VFB is queried, and the BMP file header set up and written out. * The VFB data is then converted and written out. */ static int /* Returns # of tags used */ #ifdef __STDC__ imBmpWriteRaw4( ImFileFormatWriteMap *pMap, int ioType, int fd, FILE *fp, TagTable *flagsTable, TagTable *tagTable ) #else imBmpWriteRaw4( 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 { imBmpHeaderInfoWrite header; /* BMP file header */ ImVfb *vfb; /* Read in image */ ImVfbPtr vfbptr; /* Vfb pixel pointer */ imBmpRGBQuad cltentry; /* Colortable RGBQuad entry */ ImClt *clt; /* Colortable */ ImCltPtr cltptr; /* Colortable entry pointer */ unsigned char pvalue1; /* Pixel value */ unsigned char pvalue2; /* Pixel value */ unsigned char *wbuf; /* Pointer to write buffer */ unsigned char *wbufptr; /* Pointer to write buffer data */ unsigned int scanlinesize; /* Length of scanline */ unsigned int ncolors = 0; /* Number of colors used */ unsigned int x, y; /* Width, Height */ int i, j; /* Counters */ char message[100]; /* ImInfo message */ /* * Set byte ordering */ BinByteOrder( BINLBF ); /* * Get vfb and clt */ TagEntryQValue( TagTableQDirect( tagTable, "image vfb", 0 ), &vfb ); ImVfbToIndex( vfb, 16, vfb ); clt = ImVfbQClt( vfb ); x = ImVfbQWidth( vfb ); y = ImVfbQHeight( vfb ); /* * Find scanline size to nearest 32-bit * boundary and allocate write buffer * * Note: bit shifting is used to speed up * calculations */ scanlinesize = x>>3; if( x%8 ) scanlinesize++; scanlinesize <<= 2; ncolors = ImCltQNColors( clt ); if( ncolors > 16 ) { ncolors = 16; } /* * Setup header and write it out */ header.bmp_type = IMBMPMAGIC_LBF; header.bmp_size = (unsigned int) ( IMBMPHEADERSIZE + ( ncolors * IMBMPRGBQUADSIZE ) + ( scanlinesize * y ) ); /* * file size = complete header size + * colortable size + image data size */ header.bmp_reserved1 = 0; header.bmp_reserved2 = 0; header.bmp_offsetbits = (unsigned int) IMBMPHEADERSIZE + ( ncolors * IMBMPRGBQUADSIZE ); /* * offset to image data = * BMP header + * colortable size */ header.bmp_bisize = IMBMPINFOHEADERSIZE; header.bmp_biwidth = x; header.bmp_biheight = y; header.bmp_biplanes = 1; header.bmp_bibitcount = 4; header.bmp_bicompress = IMBMPRGB; header.bmp_bisizeimage = scanlinesize * y; header.bmp_bixpm = 0; header.bmp_biypm = 0; header.bmp_biclrused = (unsigned int) ncolors; if( ncolors == 16 ) { header.bmp_biclrused = 0; } header.bmp_biclrim = (unsigned int) ncolors; if ( ImBinWriteStruct( ioType, fd, fp, &header, imBmpHeaderFieldsWrite )==-1) { ImReturnBinError( ); } /* * Output -verbose messages */ ImInfo( "Byte Order", "Least Significant Byte First" ); sprintf( message, "%d x %d", x, y ); ImInfo( "Resolution", message ); ImInfo( "Type", "4-bit Color Indexed" ); sprintf( message, "%d Entries", ncolors ); ImInfo( "Color Table", message ); ImInfo( "Compression Type", "none" ); /* * Write colortable */ cltptr = ImCltQFirst( clt ); ImMalloc( wbuf, unsigned char*, ncolors*IMBMPRGBQUADSIZE ); wbufptr = wbuf; for( i = 0; i < ncolors; ++i ) { *wbufptr = (unsigned char) ImCltQBlue( cltptr ); ++wbufptr; *wbufptr = (unsigned char) ImCltQGreen( cltptr ); ++wbufptr; *wbufptr = (unsigned char) ImCltQRed( cltptr ); ++wbufptr; *wbufptr = 0; ++wbufptr; cltptr = ImCltQNext( clt, cltptr ); } if ( ImBinWrite( ioType, fd, fp, wbuf, UCHAR, 1, ncolors*IMBMPRGBQUADSIZE ) == -1 ) { ImReturnBinError( ); } free( wbuf ); /* * Allocate write buffer space */ ImCalloc( wbuf, unsigned char*, scanlinesize, sizeof( unsigned char) ); /* * Output image bitmap */ /* * Go to last vfb scanline */ vfbptr = ImVfbQPtr( vfb, 0, y-1 ); for( i = 0; i < y; ++i ) { wbufptr = wbuf; for( j = 0; j < (x/2); ++j ) { /* * Pack 2 pixels into 1 byte * * ---- ---- <-- 1 byte * 1111 2222 * */ pvalue1 = (unsigned char) ImVfbQIndex8( vfb, vfbptr ); /* check for out of range pvalue */ if( pvalue1 > 15 ) pvalue1 = 15; vfbptr = ImVfbQRight( vfb, vfbptr ); pvalue2 = (unsigned char) ImVfbQIndex8( vfb, vfbptr ); /* check for out of range pvalue */ if( pvalue2 > 15 ) pvalue2 = 15; vfbptr = ImVfbQRight( vfb, vfbptr ); *( wbufptr ) = ( ( pvalue1 << 4 ) | pvalue2 ); ++wbufptr; } if( x%2 ) { pvalue1 = (unsigned char) ImVfbQIndex8( vfb, vfbptr ); /* check for out of range pvalue */ if( pvalue1 > 15 ) pvalue1 = 15; vfbptr = ImVfbQRight( vfb, vfbptr ); *( wbufptr ) = ( pvalue1 << 4 ); } 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 ); } free( (unsigned char*) wbuf ); return ( 1 ); } /* * FUNCTION * imBmpWriteRaw8 - write an 8-bit non-compressed BMP file * * DESCRIPTION * That VFB is queried, and the BMP file header set up and written out. * The VFB data is then converted and written out. */ static int /* Returns # of tags used */ #ifdef __STDC__ imBmpWriteRaw8( ImFileFormatWriteMap *pMap, int ioType, int fd, FILE *fp, TagTable *flagsTable, TagTable *tagTable ) #else imBmpWriteRaw8( 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 { imBmpHeaderInfoWrite header; /* BMP file header */ ImVfb *vfb; /* Read in image */ ImVfbPtr vfbptr; /* Vfb pixel pointer */ ImClt *clt; /* Colortable */ ImCltPtr cltptr; /* Colortable entry pointer */ unsigned char *wbuf; /* Pointer to write buffer */ unsigned char *wbufptr; /* Pointer to write buffer data */ unsigned int scanlinesize; /* Length of scanline */ unsigned int ncolors = 0; /* Number of colors used */ unsigned int x, y; /* Width, Height */ int i, j; /* Counters */ char message[100]; /* ImInfo message */ /* * Set byte ordering */ BinByteOrder( BINLBF ); /* * Get vfb and clt */ TagEntryQValue( TagTableQDirect( tagTable, "image vfb", 0 ), &vfb ); clt = ImVfbQClt( vfb ); x = ImVfbQWidth( vfb ); y = ImVfbQHeight( vfb ); /* * Find scanline size to nearest 32-bit * boundary and allocate write buffer * * Note: bit shifting is used to speed up * calculations */ scanlinesize = x>>2; if( x%4 ) scanlinesize++; scanlinesize <<= 2; ncolors = ImCltQNColors( clt ); if( ncolors > 256 ) { ncolors = 256; } /* * Setup header and write it out */ header.bmp_type = IMBMPMAGIC_LBF; header.bmp_size = (unsigned int) ( IMBMPHEADERSIZE + ( ncolors * IMBMPRGBQUADSIZE ) + ( scanlinesize * y ) ); /* * file size = complete header size + * colortable size + image data size */ header.bmp_reserved1 = 0; header.bmp_reserved2 = 0; header.bmp_offsetbits = (unsigned int) IMBMPHEADERSIZE + ( ncolors * IMBMPRGBQUADSIZE ); /* * offset to image data = * BMP header + * colortable size */ header.bmp_bisize = IMBMPINFOHEADERSIZE; header.bmp_biwidth = x; header.bmp_biheight = y; header.bmp_biplanes = 1; header.bmp_bibitcount = 8; header.bmp_bicompress = IMBMPRGB; header.bmp_bisizeimage = scanlinesize * y; header.bmp_bixpm = 0; header.bmp_biypm = 0; header.bmp_biclrused = (unsigned int) ncolors; if( ncolors == 256 ) { header.bmp_biclrused = 0; } header.bmp_biclrim = (unsigned int) ncolors; if( ImBinWriteStruct( ioType, fd, fp, &header, imBmpHeaderFieldsWrite ) == -1) { ImReturnBinError( ); } /* * Output -verbose messages */ ImInfo( "Byte Order", "Least Significant Byte First" ); sprintf( message, "%d x %d", x, y ); ImInfo( "Resolution", message ); ImInfo( "Type", "8-bit Color Indexed" ); sprintf( message, "%d Entries", ncolors ); ImInfo( "Color Table", message ); ImInfo( "Compression Type", "none" ); /* * Write colortable */ cltptr = ImCltQFirst( clt ); ImMalloc( wbuf, unsigned char*, ncolors*IMBMPRGBQUADSIZE ); wbufptr = wbuf; for( i = 0; i < ncolors; ++i ) { *wbufptr = (unsigned char) ImCltQBlue( cltptr ); ++wbufptr; *wbufptr = (unsigned char) ImCltQGreen( cltptr ); ++wbufptr; *wbufptr = (unsigned char) ImCltQRed( cltptr ); ++wbufptr; *wbufptr = 0; ++wbufptr; cltptr = ImCltQNext( clt, cltptr ); } if ( ImBinWrite( ioType, fd, fp, wbuf, UCHAR, 1, ncolors*IMBMPRGBQUADSIZE ) == -1 ) { ImReturnBinError( ); } free( wbuf ); /* * Allocate write buffer space */ ImCalloc( wbuf, unsigned char*, scanlinesize, sizeof( unsigned char) ); /* * Output image bitmap */ /* * Go to last vfb scanline */ vfbptr = ImVfbQPtr( vfb, 0, y-1 ); for( i = 0; i < y; ++i ) { wbufptr = wbuf; for( j = 0; j < x; ++j ) { *( wbufptr ) = (unsigned char) ImVfbQIndex8( vfb, vfbptr ); vfbptr = ImVfbQRight( vfb, vfbptr ); ++wbufptr; } 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 ); } free( (unsigned char*) wbuf ); return( 1 ); } /* * FUNCTION * imBmpWriteRaw24 - write a 24-bit non-compressed BMP file * * DESCRIPTION * That VFB is queried, and the BMP file header set up and written out. * The VFB data is then converted and written out. */ static int /* Returns # of tags used */ #ifdef __STDC__ imBmpWriteRaw24( ImFileFormatWriteMap *pMap, int ioType, int fd, FILE *fp, TagTable *flagsTable, TagTable *tagTable ) #else imBmpWriteRaw24( 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 { imBmpHeaderInfoWrite header; /* BMP file header */ ImVfb *vfb; /* Read in image */ ImVfbPtr vfbptr; /* Vfb pixel pointer */ unsigned char *wbuf; /* Pointer to write buffer */ unsigned char *wbufptr; /* Pointer to write buffer data */ unsigned int scanlinesize; /* Length of scanline */ unsigned int x, y; /* Width, height */ int i, j; /* Counters */ char message[100]; /* ImInfo message */ /* * Set byte ordering */ BinByteOrder( BINLBF ); /* * Get vfb */ TagEntryQValue( TagTableQDirect( tagTable, "image vfb", 0 ), &vfb ); x = ImVfbQWidth( vfb ); y = ImVfbQHeight( vfb ); /* * Find scanline size to nearest 32-bit * boundary and allocate write buffer * * Note: bit shifting is used to speed up * calculations */ scanlinesize = (x*3)>>2; if( x%4 ) scanlinesize++; scanlinesize <<= 2; /* * Setup header and write it out */ header.bmp_type = IMBMPMAGIC_LBF; header.bmp_size = (unsigned int) ( IMBMPHEADERSIZE + ( scanlinesize * y ) ); /* * file size = complete header size + * image data size */ header.bmp_reserved1 = 0; header.bmp_reserved2 = 0; header.bmp_offsetbits = IMBMPHEADERSIZE; /* * offset to image data = BMP header */ header.bmp_bisize = IMBMPINFOHEADERSIZE; header.bmp_biwidth = x; header.bmp_biheight = y; header.bmp_biplanes = 1; header.bmp_bibitcount = 24; header.bmp_bicompress = IMBMPRGB; header.bmp_bisizeimage = scanlinesize * y; header.bmp_bixpm = 0; header.bmp_biypm = 0; header.bmp_biclrused = 0; header.bmp_biclrim = 0; if( ImBinWriteStruct( ioType, fd, fp, &header, imBmpHeaderFieldsWrite )==-1) { ImReturnBinError( ); } /* * Output -verbose messages */ ImInfo( "Byte Order", "Least Significant Byte First" ); sprintf( message, "%d x %d", x, y ); ImInfo( "Resolution", message ); ImInfo( "Type", "24-bit RGB" ); ImInfo( "Compression Type", "none" ); /* * Allocate write buffer space */ ImCalloc( wbuf, unsigned char*, scanlinesize, sizeof( unsigned char) ); /* * Output image bitmap */ /* * Go to last vfb scanline */ vfbptr = ImVfbQPtr( vfb, 0, y-1 ); /* * Output pixels */ for( i = 0; i < y; ++i ) { wbufptr = wbuf; for( j = 0; j < x; ++j ) { *( wbufptr ) = (unsigned char) ImVfbQBlue( vfb, vfbptr ); ++wbufptr; *( wbufptr ) = (unsigned char) ImVfbQGreen( vfb, vfbptr ); ++wbufptr; *( wbufptr ) = (unsigned char) ImVfbQRed( vfb, vfbptr ); ++wbufptr; vfbptr = ImVfbQRight( vfb, vfbptr ); } 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 ); } free( (unsigned char*) wbuf ); return( 1 ); } #define imBmpWrite2Bytes( arg1, arg2 ) \ \ buf[ bufin ] = arg1; \ ++bufin; \ buf[ bufin ] = arg2; \ ++bufin; \ if( bufin > (IMBLKSIZE-1) ) \ { \ if( ImBinWrite( ioType,fd,fp,buf,UCHAR,1,IMBLKSIZE )==-1) \ { \ ImReturnBinError( ); \ } \ bufin = 0; \ } \ /* * FUNCTION * imBmpWriteRLE4 - write a 4-bit RLE compressed BMP file * * DESCRIPTION * That VFB is queried, and the BMP file header set up and written out. * The VFB data is then converted and written out. See encoding * scheme in format section. */ static int /* Returns # of tags used */ #ifdef __STDC__ imBmpWriteRLE4( ImFileFormatWriteMap *pMap, int ioType, int fd, FILE *fp, TagTable *flagsTable, TagTable *tagTable ) #else imBmpWriteRLE4( 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 { imBmpHeaderInfoWrite header; /* BMP file header */ ImVfb *vfb; /* Read in image */ ImVfbPtr vfbptr; /* Vfb pixel pointer */ ImClt *clt; /* Colortable */ ImCltPtr cltptr; /* Colortable entry pointer */ unsigned int ncolors = 0; /* Number of colors used */ unsigned int x, y; /* Width, Height */ unsigned int run; /* Number of consecutive bytes */ unsigned char pixel; /* Temp pixel value */ unsigned int bytecount = 0; /* Bytes in compressed image */ unsigned int nowrite; /* Write status */ unsigned char pixbuf[ 256 ]; /* Pixel buffer */ unsigned char *cbuf; /* Buffer for colortable write */ unsigned char *cbufptr; /* Buffer pointer */ unsigned char buf[ IMBLKSIZE ];/* File write output buffer */ int bufin; /* Output buffer index */ int xcount, ycount; /* Counters */ int i; /* Counters */ int count; /* Counter */ char message[100]; /* ImInfo message */ /* * Set byte ordering */ BinByteOrder( BINLBF ); /* * Get vfb and clt */ TagEntryQValue( TagTableQDirect( tagTable, "image vfb", 0 ), &vfb ); ImVfbToIndex( vfb, 16, vfb ); clt = ImVfbQClt( vfb ); x = ImVfbQWidth( vfb ); y = ImVfbQHeight( vfb ); ncolors = ImCltQNColors( clt ); if( ncolors > 16 ) { ncolors = 16; } /* * Setup header and write it out */ header.bmp_type = IMBMPMAGIC_LBF; header.bmp_reserved1 = 0; header.bmp_reserved2 = 0; header.bmp_offsetbits = (unsigned int) IMBMPHEADERSIZE + ( ncolors * IMBMPRGBQUADSIZE ); /* * offset to image data = * BMP header + * colortable size */ header.bmp_bisize = IMBMPINFOHEADERSIZE; header.bmp_biwidth = x; header.bmp_biheight = y; header.bmp_biplanes = 1; header.bmp_bibitcount = 4; header.bmp_bicompress = IMBMPRLE4; header.bmp_bixpm = 0; header.bmp_biypm = 0; header.bmp_biclrused = (unsigned int) ncolors; if( ncolors == 16 ) { header.bmp_biclrused = 0; } header.bmp_biclrim = (unsigned int) ncolors; if( ImBinWriteStruct( ioType, fd, fp, &header, imBmpHeaderFieldsWrite ) == -1 ) { ImReturnBinError( ); } /* * Output -verbose messages */ ImInfo( "Byte Order", "Least Significant Byte First" ); sprintf( message, "%d x %d", x, y ); ImInfo( "Resolution", message ); ImInfo( "Type", "4-bit Color Indexed" ); sprintf( message, "%d Entries", ncolors ); ImInfo( "Color Table", message ); ImInfo( "Compression Type", "Run Length Encoded (RLE4)" ); /* * Write colortable */ cltptr = ImCltQFirst( clt ); ImMalloc( cbuf, unsigned char*, ncolors*IMBMPRGBQUADSIZE ); cbufptr = cbuf; for( i = 0; i < ncolors; ++i ) { *cbufptr = (unsigned char) ImCltQBlue( cltptr ); ++cbufptr; *cbufptr = (unsigned char) ImCltQGreen( cltptr ); ++cbufptr; *cbufptr = (unsigned char) ImCltQRed( cltptr ); ++cbufptr; *cbufptr = 0; ++cbufptr; cltptr = ImCltQNext( clt, cltptr ); } if ( ImBinWrite( ioType, fd, fp, cbuf, UCHAR, 1, ncolors*IMBMPRGBQUADSIZE ) == -1 ) { ImReturnBinError( ); } free( cbuf ); /* * Output image bitmap */ /* * Go to last vfb scanline */ vfbptr = ImVfbQPtr( vfb, 0, y-1 ); /* * RLE encode the image */ bytecount = 0; xcount = 0; ycount = 0; bufin = 0; pixel = ImVfbQIndex8( vfb, vfbptr ); /* check for out of range pixel */ if( pixel > 15 ) pixel = 15; vfbptr = ImVfbQRight( vfb, vfbptr ); while( ycount < y ) { /* * Boundary condition: 1 pixel at the end * of a scanline. */ if( xcount == (x-1) ) { /* * Encoded pixel as run of 1 */ imBmpWrite2Bytes( 1, pixel << 4 ); /* * Write end of scanline code */ imBmpWrite2Bytes( 0, 0 ); /* * Adjust counters and vfb pointers */ bytecount += 4; xcount = 0; ++ycount; vfbptr = ImVfbQUp( vfb, vfbptr ); vfbptr = ImVfbQUp( vfb, vfbptr ); pixel = ImVfbQIndex8( vfb, vfbptr ); /* check for out of range pixel */ if( pixel > 15 ) pixel = 15; vfbptr = ImVfbQRight( vfb, vfbptr ); } /* * Boundary condition: 2 pixels at the end * of a scanline. */ if( xcount == (x-2) ) { /* * Write the last two pixels as a run of two */ imBmpWrite2Bytes( 2, ( pixel << 4 ) | ImVfbQIndex8(vfb,vfbptr) ); /* * Write end of scanline code */ imBmpWrite2Bytes( 0, 0 ); /* * Adjust counters and vfb pointers */ bytecount += 4; xcount = 0; ++ycount; vfbptr = ImVfbQRight( vfb, vfbptr ); vfbptr = ImVfbQUp( vfb, vfbptr ); vfbptr = ImVfbQUp( vfb, vfbptr ); pixel = ImVfbQIndex8( vfb, vfbptr ); /* check for out of range pixel */ if( pixel > 15 ) pixel = 15; vfbptr = ImVfbQRight( vfb, vfbptr ); } /* * Encoded Mode - encoding of multiple consecutive * pixels of the same value into a run and * pixel value */ if( pixel == ImVfbQIndex8( vfb, vfbptr ) ) { run = 0; nowrite = TRUE; /* * While two adjacent pixels are the same, * count them up. If we reach the * end of a scanline, write out the * current run and pixel. If we * have a run of 255 pixels, write * out the run and pixel. */ while( pixel == ImVfbQIndex8( vfb, vfbptr ) ) { ++run; ++xcount; pixel = ImVfbQIndex8( vfb, vfbptr ); /* check for out of range pixel */ if( pixel > 15 ) pixel = 15; vfbptr = ImVfbQRight( vfb, vfbptr ); /* * End of a scanline */ if( xcount == x-1 ) { /* * Write run and pixel value */ imBmpWrite2Bytes( run+1, (pixel<<4) | pixel ); /* * Write end of scanline code */ imBmpWrite2Bytes( 0, 0 ); /* * Adjust counters and vfb pointers */ bytecount += 4; xcount = 0; ++ycount; vfbptr = ImVfbQUp( vfb, vfbptr ); vfbptr = ImVfbQUp( vfb, vfbptr ); pixel = ImVfbQIndex8( vfb, vfbptr ); /* check for out of range pixel */ if( pixel > 15 ) pixel = 15; vfbptr = ImVfbQRight( vfb, vfbptr ); nowrite = FALSE; break; } /* * End of 255 pixels */ if( run == 254 ) { /* * Write run and pixel value */ imBmpWrite2Bytes( 255, (pixel<<4) | pixel ); /* * Adjust counters and vfb pointers */ bytecount += 2; run = 0; ++xcount; pixel = ImVfbQIndex8( vfb, vfbptr ); /* check for out of range pixel */ if( pixel > 15 ) pixel = 15; vfbptr = ImVfbQRight( vfb, vfbptr ); nowrite = FALSE; break; } } /* * If we haven't written out the run and pixel, * do it now. */ if( nowrite == TRUE ) { /* * Write run and pixel */ imBmpWrite2Bytes( run+1, (pixel<<4) | pixel ); /* * Adjust counters and vfb pointers */ bytecount += 2; ++xcount; pixel = ImVfbQIndex8( vfb, vfbptr ); /* check for out of range pixel */ if( pixel > 15 ) pixel = 15; vfbptr = ImVfbQRight( vfb, vfbptr ); } } /* * Absolute Mode - copying of consecutive different pixels * literally */ if( (pixel != ImVfbQIndex8( vfb, vfbptr )) && (xcount < (x-2) ) && (ycount < y) ) { run = 0; nowrite = TRUE; pixbuf[ 0 ] = pixel; pixel = ImVfbQIndex8( vfb, vfbptr ); /* check for out of range pixel */ if( pixel > 15 ) pixel = 15; vfbptr = ImVfbQRight( vfb, vfbptr ); ++xcount; /* * Since Absolute Mode requires that there * be at least 3 different adjacent * pixels, we check for this condition * first. If there are only 1 or 2 * different adjacent bytes, then * we write them out as runs of 1 * and pixel. */ if( pixel == ImVfbQIndex8( vfb, vfbptr ) ) { /* * There is only 1 different pixel */ /* * Write out run and pixel */ imBmpWrite2Bytes( 1, pixbuf[ 0 ] << 4 ); bytecount += 2; nowrite = FALSE; } else { pixbuf[ 1 ] = pixel; pixel = ImVfbQIndex8( vfb, vfbptr ); /* check for out of range pixel */ if( pixel > 15 ) pixel = 15; vfbptr = ImVfbQRight( vfb, vfbptr ); ++xcount; if( pixel == ImVfbQIndex8( vfb, vfbptr ) ) { /* * There are only 2 different * adjacent pixels */ /* * Write run and pixel */ imBmpWrite2Bytes( 2, (pixbuf[ 0 ]<<4) | pixbuf[ 1 ]); bytecount += 2; nowrite = FALSE; } else { /* * There are at least 3 different * adjacent pixels, so we reset * the vfb pointers */ xcount -= 2; vfbptr = ImVfbQLeft( vfb, vfbptr ); vfbptr = ImVfbQLeft( vfb, vfbptr ); vfbptr = ImVfbQLeft( vfb, vfbptr ); pixel = ImVfbQIndex8( vfb, vfbptr ); /* check for out of range pixel */ if( pixel > 15 ) pixel = 15; vfbptr = ImVfbQRight( vfb, vfbptr ); } } /* * While adjacent pixels are different, count them * up and store them in pixbuf. */ while( pixel != ImVfbQIndex8( vfb, vfbptr ) ) { pixbuf[ run ] = pixel; pixel = ImVfbQIndex8( vfb, vfbptr ); /* check for out of range pixel */ if( pixel > 15 ) pixel = 15; vfbptr = ImVfbQRight( vfb, vfbptr ); ++run; ++xcount; /* * End of scanline */ if( xcount == x-1 ) { pixbuf[ run ] = pixel; pixbuf[ run+1 ] = 0; /* * Write escape(0) and run */ imBmpWrite2Bytes( 0, run+1 ); /* * Write pixels in pixbuf */ count = 0; for( i = 0; i < run+1; i += 2) { buf[ bufin ] = (pixbuf[ i ]<<4) | pixbuf[ i+1 ]; ++bufin; if( bufin > (IMBLKSIZE-1) ) { if( ImBinWrite( ioType, fd,fp,buf, UCHAR,1, IMBLKSIZE )==-1) { ImReturnBinError( ); } bufin = 0; } ++count; } bytecount += count; /* * Pad to word boundary if necessary */ if( (count%2) != 0 ) { buf[ bufin ] = 0; ++bufin; if( bufin > (IMBLKSIZE-1) ) { if( ImBinWrite( ioType, fd,fp,buf, UCHAR,1, IMBLKSIZE )==-1) { ImReturnBinError( ); } bufin = 0; } ++bytecount; } /* * Write end of scanline code */ imBmpWrite2Bytes( 0, 0 ); /* * Adjust counters and vfb pointers */ bytecount += 4; xcount = 0; ++ycount; vfbptr = ImVfbQUp( vfb, vfbptr ); vfbptr = ImVfbQUp( vfb, vfbptr ); pixel = ImVfbQIndex8( vfb, vfbptr ); /* check for out of range pixel */ if( pixel > 15 ) pixel = 15; vfbptr = ImVfbQRight( vfb, vfbptr ); nowrite = FALSE; break; } /* * End of 255 consecutive different pixels */ if( run == 254 ) { pixbuf[ run ] = pixel; pixbuf[ run+1 ] = 0; /* * Write escape code(0) and run */ imBmpWrite2Bytes( 0, 255 ); /* * Write pixel literals */ for( i = 0; i < 255; i += 2 ) { buf[ bufin ] = (pixbuf[ i ]<<4) | pixbuf[ i+1 ]; ++bufin; if( bufin > (IMBLKSIZE-1) ) { if( ImBinWrite( ioType, fd,fp,buf, UCHAR,1, IMBLKSIZE )==-1) { ImReturnBinError( ); } bufin = 0; } } /* * Adjust counters and vfb pointers */ bytecount += 130; run = 0; ++xcount; pixel = ImVfbQIndex8( vfb, vfbptr ); /* check for out of range pixel */ if( pixel > 15 ) pixel = 15; vfbptr = ImVfbQRight( vfb, vfbptr ); nowrite = FALSE; break; } } /* * If we haven't written out the pixels, then * write it now */ if( nowrite == TRUE ) { pixbuf[ run ] = 0; /* * Write escape code(0) and run */ imBmpWrite2Bytes( 0, run ); /* * Write pixel literals */ count = 0; for( i = 0; i < run; i += 2 ) { buf[ bufin ] = (pixbuf[ i ]<<4) | pixbuf[ i+1 ]; ++bufin; if( bufin > (IMBLKSIZE-1) ) { if( ImBinWrite( ioType,fd,fp ,buf,UCHAR,1 ,IMBLKSIZE )==-1) { ImReturnBinError( ); } bufin = 0; } ++count; } bytecount += count; /* * Pad to word boundary if necessary */ if( count%2 != 0 ) { buf[ bufin ] = 0; ++bufin; if( bufin > (IMBLKSIZE-1) ) { if( ImBinWrite( ioType, fd,fp,buf, UCHAR,1, IMBLKSIZE )==-1) { ImReturnBinError( ); } bufin = 0; } ++bytecount; } /* * Adjust bytecount */ bytecount += 2; } } } /* * Write end of bitmap code */ buf[ bufin ] = 0; ++bufin; buf[ bufin ] = 1; ++bufin; if( ImBinWrite( ioType,fd,fp,buf,UCHAR,1,bufin )==-1) { ImReturnBinError( ); } /* * Adjust bytecount */ bytecount += 2; /* * Seek to header and write file size */ if( ImSeek( ioType, fd, fp, 2, L_SET ) == -1 ) { ImReturnBinError( ); } header.bmp_size = IMBMPHEADERSIZE + ( ncolors * IMBMPRGBQUADSIZE ) + bytecount; if( ImBinWrite( ioType, fd, fp, &header.bmp_size, UINT32, 4, 1) == -1 ) { ImReturnBinError( ); } /* * Seek to header and write bitmap size */ if( ImSeek( ioType, fd, fp, 34, L_SET ) == -1 ) { ImReturnBinError( ); } header.bmp_bisizeimage = bytecount; if( ImBinWrite( ioType, fd, fp, &header.bmp_bisizeimage, UINT32, 4, 1) == -1 ) { ImReturnBinError( ); } return( 1 ); } /* * FUNCTION * imBmpWriteRLE8 - write an 8-bit RLE compressed BMP file * * DESCRIPTION * That VFB is queried, and the BMP file header set up and written out. * The VFB data is then converted and written out. See encoding * scheme in FORMAT section. */ static int /* Returns # of tags used */ #ifdef __STDC__ imBmpWriteRLE8( ImFileFormatWriteMap *pMap, int ioType, int fd, FILE *fp, TagTable *flagsTable, TagTable *tagTable ) #else imBmpWriteRLE8( 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 { imBmpHeaderInfoWrite header; /* BMP file header */ ImVfb *vfb; /* Read in image */ ImVfbPtr vfbptr; /* Vfb pixel pointer */ ImClt *clt; /* Colortable */ ImCltPtr cltptr; /* Colortable entry pointer */ unsigned int ncolors = 0; /* Number of colors used */ unsigned int x, y; /* Width, Height */ unsigned int run; /* Number of consecutive bytes */ unsigned char pixel; /* Temp pixel value */ unsigned int bytecount = 0; /* Bytes in compressed image */ unsigned int nowrite; /* Write status */ unsigned char pixbuf[ 255 ]; /* Pixel buffer */ unsigned char *cbuf; /* Buffer for colortable write */ unsigned char *cbufptr; /* Buffer pointer */ unsigned char buf[ IMBLKSIZE ];/* File write output buffer */ int bufin; /* Output buffer index */ int xcount, ycount; /* Counters */ int i; /* Counters */ char message[100]; /* ImInfo message */ /* * Set byte ordering */ BinByteOrder( BINLBF ); /* * Get vfb and clt */ TagEntryQValue( TagTableQDirect( tagTable, "image vfb", 0 ), &vfb ); clt = ImVfbQClt( vfb ); x = ImVfbQWidth( vfb ); y = ImVfbQHeight( vfb ); ncolors = ImCltQNColors( clt ); if( ncolors > 256 ) { ncolors = 256; } /* * Setup header and write it out */ header.bmp_type = IMBMPMAGIC_LBF; header.bmp_reserved1 = 0; header.bmp_reserved2 = 0; header.bmp_offsetbits = (unsigned int) IMBMPHEADERSIZE + ( ncolors * IMBMPRGBQUADSIZE ); /* * offset to image data = * BMP header + * colortable size */ header.bmp_bisize = IMBMPINFOHEADERSIZE; header.bmp_biwidth = x; header.bmp_biheight = y; header.bmp_biplanes = 1; header.bmp_bibitcount = 8; header.bmp_bicompress = IMBMPRLE8; header.bmp_bixpm = 0; header.bmp_biypm = 0; header.bmp_biclrused = (unsigned int) ncolors; if( ncolors == 256 ) { header.bmp_biclrused = 0; } header.bmp_biclrim = (unsigned int) ncolors;; if( ImBinWriteStruct( ioType, fd, fp, &header, imBmpHeaderFieldsWrite ) == -1 ) { ImReturnBinError( ); } /* * Output -verbose messages */ ImInfo( "Byte Order", "Least Significant Byte First" ); sprintf( message, "%d x %d", x, y ); ImInfo( "Resolution", message ); ImInfo( "Type", "8-bit Color Indexed" ); sprintf( message, "%d Entries", ncolors ); ImInfo( "Color Table", message ); ImInfo( "Compression Type", "Run Length Encoded (RLE8)" ); /* * Write colortable */ cltptr = ImCltQFirst( clt ); ImMalloc( cbuf, unsigned char*, ncolors*IMBMPRGBQUADSIZE ); cbufptr = cbuf; for( i = 0; i < ncolors; ++i ) { *cbufptr = (unsigned char) ImCltQBlue( cltptr ); ++cbufptr; *cbufptr = (unsigned char) ImCltQGreen( cltptr ); ++cbufptr; *cbufptr = (unsigned char) ImCltQRed( cltptr ); ++cbufptr; *cbufptr = 0; ++cbufptr; cltptr = ImCltQNext( clt, cltptr ); } if ( ImBinWrite( ioType, fd, fp, cbuf, UCHAR, 1, ncolors*IMBMPRGBQUADSIZE ) == -1 ) { ImReturnBinError( ); } free( cbuf ); /* * Output image bitmap */ /* * Go to last vfb scanline */ vfbptr = ImVfbQPtr( vfb, 0, y-1 ); /* * RLE encode the image */ bytecount = 0; xcount = 0; ycount = 0; bufin = 0; pixel = ImVfbQIndex8( vfb, vfbptr ); vfbptr = ImVfbQRight( vfb, vfbptr ); while( ycount < y ) { /* * Boundary condition: 1 pixel at the end * of a scanline. */ if( xcount == (x-1) ) { /* * Encoded pixel as run of 1 */ imBmpWrite2Bytes( 1, pixel ); /* * Write end of scanline code */ imBmpWrite2Bytes( 0, 0 ); /* * Adjust counters and vfb pointers */ bytecount += 4; xcount = 0; ++ycount; vfbptr = ImVfbQUp( vfb, vfbptr ); vfbptr = ImVfbQUp( vfb, vfbptr ); pixel = ImVfbQIndex8( vfb, vfbptr ); vfbptr = ImVfbQRight( vfb, vfbptr ); } /* * Boundary condition: 2 pixels at the end * of a scanline. */ if( xcount == (x-2) ) { /* * If the last two pixels are the same * then write them as a run of 2 with * pixel value. Else, write each * pixel value as runs of 1. */ if( pixel == ImVfbQIndex8( vfb, vfbptr ) ) { imBmpWrite2Bytes( 2, pixel ); bytecount += 4; } else { imBmpWrite2Bytes( 1, pixel ); imBmpWrite2Bytes( 1, ImVfbQIndex8(vfb,vfbptr)); bytecount += 6; } /* * Write end of scanline code */ imBmpWrite2Bytes( 0, 0 ); /* * Adjust counters and vfb pointers */ xcount = 0; ++ycount; vfbptr = ImVfbQRight( vfb, vfbptr ); vfbptr = ImVfbQUp( vfb, vfbptr ); vfbptr = ImVfbQUp( vfb, vfbptr ); pixel = ImVfbQIndex8( vfb, vfbptr ); vfbptr = ImVfbQRight( vfb, vfbptr ); } /* * Encoded Mode - encoding of multiple consecutive * pixels of the same value into a run and * pixel value */ if( pixel == ImVfbQIndex8( vfb, vfbptr ) ) { run = 0; nowrite = TRUE; /* * While two adjacent pixels are the same, * count them up. If we reach the * end of a scanline, write out the * current run and pixel. If we * have a run of 255 pixels, write * out the run and pixel. */ while( pixel == ImVfbQIndex8( vfb, vfbptr ) ) { ++run; ++xcount; pixel = ImVfbQIndex8( vfb, vfbptr ); vfbptr = ImVfbQRight( vfb, vfbptr ); /* * End of a scanline */ if( xcount == x-1 ) { /* * Write run and pixel value */ imBmpWrite2Bytes( run+1, pixel ); /* * Write end of scanline code */ imBmpWrite2Bytes( 0, 0 ); /* * Adjust counters and vfb pointers */ bytecount += 4; xcount = 0; ++ycount; vfbptr = ImVfbQUp( vfb, vfbptr ); vfbptr = ImVfbQUp( vfb, vfbptr ); pixel = ImVfbQIndex8( vfb, vfbptr ); vfbptr = ImVfbQRight( vfb, vfbptr ); nowrite = FALSE; break; } /* * End of 255 pixels */ if( run == 254 ) { /* * Write run and pixel value */ imBmpWrite2Bytes( 255, pixel ); /* * Adjust counters and vfb pointers */ bytecount += 2; run = 0; ++xcount; pixel = ImVfbQIndex8( vfb, vfbptr ); vfbptr = ImVfbQRight( vfb, vfbptr ); nowrite = FALSE; break; } } /* * If we haven't written out the run and pixel, * do it now. */ if( nowrite == TRUE ) { /* * Write run and pixel */ imBmpWrite2Bytes( run+1, pixel ); /* * Adjust counters and vfb pointers */ bytecount += 2; ++xcount; pixel = ImVfbQIndex8( vfb, vfbptr ); vfbptr = ImVfbQRight( vfb, vfbptr ); } } /* * Absolute Mode - copying of consecutive different pixels * literally */ if( (pixel != ImVfbQIndex8( vfb, vfbptr )) && (xcount < (x-2) ) && (ycount < y) ) { run = 0; nowrite = TRUE; pixbuf[ 0 ] = pixel; pixel = ImVfbQIndex8( vfb, vfbptr ); vfbptr = ImVfbQRight( vfb, vfbptr ); ++xcount; /* * Since Absolute Mode requires that there * be at least 3 different adjacent * pixels, we check for this condition * first. If there are only 1 or 2 * different adjacent bytes, then * we write them out as runs of 1 * and pixel. */ if( pixel == ImVfbQIndex8( vfb, vfbptr ) ) { /* * There is only 1 different pixel */ /* * Write out run and pixel */ imBmpWrite2Bytes( 1, pixbuf[ 0 ] ); bytecount += 2; nowrite = FALSE; } else { pixbuf[ 1 ] = pixel; pixel = ImVfbQIndex8( vfb, vfbptr ); vfbptr = ImVfbQRight( vfb, vfbptr ); ++xcount; if( pixel == ImVfbQIndex8( vfb, vfbptr ) ) { /* * There are only 2 different * adjacent pixels */ /* * Write run and pixel */ imBmpWrite2Bytes( 1, pixbuf[ 0 ] ); /* * Write run and pixel */ imBmpWrite2Bytes( 1, pixbuf[ 1 ] ); bytecount += 4; nowrite = FALSE; } else { /* * There are at least 3 different * adjacent pixels, so we reset * the vfb pointers */ xcount -= 2; vfbptr = ImVfbQLeft( vfb, vfbptr ); vfbptr = ImVfbQLeft( vfb, vfbptr ); vfbptr = ImVfbQLeft( vfb, vfbptr ); pixel = ImVfbQIndex8( vfb, vfbptr ); vfbptr = ImVfbQRight( vfb, vfbptr ); } } /* * While adjacent pixels are different, count them * up and store them in pixbuf. */ while( pixel != ImVfbQIndex8( vfb, vfbptr ) ) { pixbuf[ run ] = pixel; pixel = ImVfbQIndex8( vfb, vfbptr ); vfbptr = ImVfbQRight( vfb, vfbptr ); ++run; ++xcount; /* * End of scanline */ if( xcount == x-1 ) { pixbuf[ run ] = pixel; /* * Write escape(0) and run */ imBmpWrite2Bytes( 0, run+1 ); /* * Write pixels in pixbuf */ for( i = 0; i < run+1; ++i ) { buf[ bufin ] = pixbuf[ i ]; ++bufin; if( bufin > (IMBLKSIZE-1) ) { if( ImBinWrite( ioType, fd,fp,buf, UCHAR,1, IMBLKSIZE )==-1) { ImReturnBinError( ); } bufin = 0; } } /* * Pad to word boundary if necessary */ if( ((run+1)%2) != 0 ) { buf[ bufin ] = 0; ++bufin; if( bufin > (IMBLKSIZE-1) ) { if( ImBinWrite( ioType, fd,fp,buf, UCHAR,1, IMBLKSIZE )==-1) { ImReturnBinError( ); } bufin = 0; } ++bytecount; } /* * Write end of scanline code */ imBmpWrite2Bytes( 0, 0 ); /* * Adjust counters and vfb pointers */ bytecount += (5+run); xcount = 0; ++ycount; vfbptr = ImVfbQUp( vfb, vfbptr ); vfbptr = ImVfbQUp( vfb, vfbptr ); pixel = ImVfbQIndex8( vfb, vfbptr ); vfbptr = ImVfbQRight( vfb, vfbptr ); nowrite = FALSE; break; } /* * End of 255 consecutive different pixels */ if( run == 254 ) { pixbuf[ run ] = pixel; /* * Write escape code(0) and run */ imBmpWrite2Bytes( 0, 255 ); /* * Write pixel literals */ for( i = 0; i < 255; ++i ) { buf[ bufin ] = pixbuf[ i ]; ++bufin; if( bufin > (IMBLKSIZE-1) ) { if( ImBinWrite( ioType, fd,fp,buf, UCHAR,1, IMBLKSIZE )==-1) { ImReturnBinError( ); } bufin = 0; } } /* * Write word boundary padding */ buf[ bufin ] = 0; ++bufin; if( bufin > (IMBLKSIZE-1) ) { if( ImBinWrite( ioType, fd,fp,buf, UCHAR,1, IMBLKSIZE )==-1) { ImReturnBinError( ); } bufin = 0; } /* * Adjust counters and vfb pointers */ bytecount += 258; run = 0; ++xcount; pixel = ImVfbQIndex8( vfb, vfbptr ); vfbptr = ImVfbQRight( vfb, vfbptr ); nowrite = FALSE; break; } } /* * If we haven't written out the pixels, then * write it now */ if( nowrite == TRUE ) { /* * Write escape code(0) and run */ imBmpWrite2Bytes( 0, run ); /* * Write pixel literals */ for( i = 0; i < run; ++i ) { buf[ bufin ] = pixbuf[ i ]; ++bufin; if( bufin > (IMBLKSIZE-1) ) { if( ImBinWrite( ioType,fd,fp ,buf,UCHAR,1 ,IMBLKSIZE )==-1) { ImReturnBinError( ); } bufin = 0; } } /* * Write padding to word boundary if * necessary */ if( run%2 != 0 ) { buf[ bufin ] = 0; ++bufin; if( bufin > (IMBLKSIZE-1) ) { if( ImBinWrite( ioType,fd,fp ,buf,UCHAR,1 ,IMBLKSIZE )==-1) { ImReturnBinError( ); } bufin = 0; } ++bytecount; } /* * Adjust bytecount */ bytecount += (2+run); } } } /* * Write end of bitmap code */ buf[ bufin ] = 0; ++bufin; buf[ bufin ] = 1; ++bufin; if( ImBinWrite( ioType,fd,fp,buf,UCHAR,1,bufin )==-1) { ImReturnBinError( ); } /* * Adjust bytecount */ bytecount += 2; /* * Seek to header and write file size */ if( ImSeek( ioType, fd, fp, 2, L_SET ) == -1 ) { ImReturnBinError( ); } header.bmp_size = IMBMPHEADERSIZE + ( ncolors * IMBMPRGBQUADSIZE ) + bytecount; if( ImBinWrite( ioType, fd, fp, &header.bmp_size, UINT32, 4, 1) == -1 ) { ImReturnBinError( ); } /* * Seek to header and write bitmap size */ if( ImSeek( ioType, fd, fp, 34, L_SET ) == -1 ) { ImReturnBinError( ); } header.bmp_bisizeimage = bytecount; if( ImBinWrite( ioType, fd, fp, &header.bmp_bisizeimage, UINT32, 4, 1) == -1 ) { ImReturnBinError( ); } return( 1 ); }