/** ** $Header: /roq/libim/imxbm.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/imxbm.c 1 11/02/99 4:38p Zaphod $" /** ** FILE ** imxbm.c - X11 bitmap file I/O ** ** PROJECT ** libim - SDSC image manipulation library ** ** DESCRIPTION ** imxbm.c contains routines to read and write Sun Icon files for ** the image manipulation library. Raster data read in is stored ** in a VFB and optional CLT in a tag list. Raster data written ** out is taken from a tag list. ** ** PUBLIC CONTENTS ** d =defined constant ** f =function ** m =defined macro ** t =typedef/struct/union ** v =variable ** ? =other ** none ** ** PRIVATE CONTENTS ** ** imXbmRead f read a X11 Bitmap file ** imXbmWrite f write a X11 Bitmap file ** ** ** HISTORY ** $Log: /roq/libim/imxbm.c $ * * 1 11/02/99 4:38p Zaphod ** Revision 1.15 1995/06/29 00:28:04 bduggan ** updated copyright year ** ** Revision 1.14 1995/05/16 22:12:25 bduggan ** made HotSpot static (since its address is used in the tagtable) ** ** Revision 1.13 1995/04/03 21:41:29 bduggan ** took out #ifdef NEWMAGIC ** ** Revision 1.12 1995/01/10 23:50:58 bduggan ** made read/write routines static ** put in IMMULTI, IMPIPE instead of TRUE/FALSE ** ** Revision 1.11 94/10/03 11:31:13 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.10 92/11/23 18:43:20 nadeau ** Removed use of IMINFOMSG. ** ** Revision 1.9 92/11/04 12:10:54 groening ** put ImFIleFormat info and magic number info ** from imfmt.c into this file. ** ** Revision 1.8 92/09/29 17:56:55 vle ** Added ImInfo messages. ** ** Revision 1.7 92/09/17 13:58:22 vle ** Moved a misplaced line of code. ** ** Revision 1.6 92/09/01 20:16:05 vle ** Updated copyright notice. Added code to read/write hotspots, instead ** of just skipping them. ** ** Revision 1.5 91/10/04 08:52:26 nadeau ** Fixed strcpy typo. ** ** Revision 1.4 91/10/03 09:25:08 nadeau ** Minor comment updating. ** ** Revision 1.3 91/02/20 12:44:37 nadeau ** Added hotspot read handling. ** ** Revision 1.2 91/02/12 10:48:15 nadeau ** Removed the tag table checking and VFB conversion now ** handled by ImFileRead and ImFileWrite. Changed grayscale ** to mono support. ** ** Revision 1.1 91/01/30 18:18:31 nadeau ** Initial revision **/ #include #include "iminternal.h" /** ** FORMAT ** xbm - X11 Bitmap ** ** AKA ** bm ** ** FORMAT REFERENCES ** Graphics File Formats, David C. Kay, John R. Levine ** ** ** CODE CREDITS ** Custom development, Dave Nadeau, San Diego Supercomputer Center, 1991. ** ** DESCRIPTION ** X11 bitmaps are simple C code to declare and initialize a character ** array with bits for an X11 cursor, icon, or glyph of some other sort. ** Preceding the array declaration are a few #define-ed constants to ** give the image width and height, and optionally a cursor's hot spot ** location. ** ** #define name_width xxx ** #define name_height yyy ** #define name_x_hot xhot ** #define name_y_hot yhot ** static char name_bits[] = { ** ... ASCII hex bytes ... ** }; ** ** xxx is the image width, in pixels. ** ** yyy is the image height, in pixels. ** ** xhot and yhot are the hot spot location. These two lines are ** optional. imxbm.c ignores the hot spot. ** ** name is the name of the glyph. imxbm.c write code generates the ** name based upon the outgoing file name given in the flags table. **/ /* * XBM - MIT X11 Window System BitMap * For information on these structures, how to use them, etc. please * see imfmt.c. */ #ifdef __STDC__ static int imXbmRead( int ioType, int fd, FILE *fp, TagTable *flagsTable, TagTable *tagTable ); static int imXbmWrite( ImFileFormatWriteMap *pMap, int ioType, int fd, FILE *fp, TagTable *flagsTable, TagTable *tagTable ); #else static int imXbmRead( ); static int imXbmWrite( ); #endif static char *imXbmNames[ ] = { "xbm", "bm", NULL }; static ImFileFormatReadMap imXbmReadMap[ ] = { /* in out */ /* type,ch,dep, attr. VFB type attr. */ { IN,1,1, 0, IMVFBMONO, 0 }, { -1, 0, -1, 0 }, }; static ImFileFormatWriteMap imXbmWriteMap[ ] = { /* in out */ /* VFB type, attr., type,ch,dep, attr., func */ { IMVFBMONO, 0, IN,1,1, 0, imXbmWrite }, { -1, 0, -1, 0, NULL }, }; static ImFileMagic imFileXbmMagic []= { { 0, 0, NULL}, }; ImFileFormat ImFileXbmFormat = { imXbmNames, "X11 bitmap file", "X Consortium / MIT", "1-bit ASCII bitmap files.", "1-bit ASCII bitmap files.", imFileXbmMagic, IMNOMULTI, IMPIPE, IMNOMULTI, IMPIPE, imXbmRead, imXbmReadMap, imXbmWriteMap }; /* * FUNCTION * imXbmRead - read an X11 bitmap file * * DESCRIPTION * The file is read and it's mono image written to a new mono VFB. */ static int /* Returns # tags read in */ #ifdef __STDC__ imXbmRead( int ioType, int fd, FILE *fp, TagTable *flagsTable, TagTable *tagTable ) #else imXbmRead( 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 { int xdim; /* # columns */ int ydim; /* # rows */ int xdim2; /* # columns (nearest 8bit bndry)*/ int xdimExtra; /* # columns mod 8 */ int xhot = 0; /* hotspot x coordinate */ int yhot = 0; /* hotspot y coordinate */ int hotspotflag = FALSE; /* TRUE if there's a hotspot */ static ImHotSpot hotspot; /* Cursor hotspot */ ImHotSpotPtr hotspotptr; /* Cursor hotspot pointer */ ImVfb *vfb; /* Read in image */ ImVfbPtr pPixel; /* Pixel pointer */ int c; /* Character holder */ int pixel; /* 8-bits of pixels */ int i, j, k; /* Counters */ char message[1024]; /* Error message holder */ /* * Read in the header. */ if ( ioType & IMFILEIOFD ) { /* * Given file descriptor. More convenient to deal with * a file pointer for this format. */ if ( (fp = fdopen( fd, "r" )) == NULL ) { ImErrNo = IMESYS; return ( -1 ); } } /* Read in width: #define name_width xdim */ if ( fscanf( fp, "%*s %*s %d", &xdim ) != 1 ) { ImErrorFatal( "Syntax error in giving image width", -1, IMESYNTAX ); } for ( c = fgetc( fp ); c != EOF && c != '\n'; c = fgetc( fp ) ) ; if ( c == EOF ) { ImErrorFatal( "Syntax error in giving image width", -1, IMESYNTAX ); } /* Read in height: #define name_height ydim */ if ( fscanf( fp, "%*s %*s %d", &ydim ) != 1 ) { ImErrorFatal( "Syntax error in giving image height", -1, IMESYNTAX ); } for ( c = fgetc( fp ); c != EOF && c != '\n'; c = fgetc( fp ) ) ; if ( c == EOF ) { ImErrorFatal( "Syntax error in giving image height", -1, IMESYNTAX ); } sprintf( message, "%d x %d", xdim, ydim ); ImInfo( "Resolution", message ); ImInfo( "Type", "1-bit Monochrome" ); /* Read in x_hot (optional): #define name_x_hot xhot */ if ( (c = fgetc( fp )) == '#' ) { if ( fscanf( fp, "%*s %*s %d", &xhot ) != 1 ) { ImErrorFatal( "Syntax error in giving image hotspot x", -1, IMESYNTAX ); } for ( c = fgetc( fp ); c != EOF && c != '\n'; c = fgetc( fp ) ) ; if ( c == EOF ) { ImErrorFatal( "Syntax error in giving image hotspot x", -1, IMESYNTAX ); } hotspotflag = TRUE; } /* Read in y_hot (optional): #define name_y_hot xhot */ if ( (c = fgetc( fp )) == '#' ) { if ( fscanf( fp, "%*s %*s %d", &yhot ) != 1 ) { ImErrorFatal( "Syntax error in giving image hotspot y", -1, IMESYNTAX ); } for ( c = fgetc( fp ); c != EOF && c != '\n'; c = fgetc( fp ) ) ; if ( c == EOF ) { ImErrorFatal( "Syntax error in giving image hotspot y", -1, IMESYNTAX ); } hotspotflag = TRUE; } /* * Store hotspot in TagTable, if there's at least one coordinate in the file */ if( hotspotflag == TRUE ) { hotspotptr = &hotspot; ImHotSpotSX( hotspotptr, xhot ); ImHotSpotSY( hotspotptr, yhot ); TagTableAppend( tagTable, TagEntryAlloc( "image hot spot", POINTER, &hotspotptr ) ); sprintf( message, "%d, %d", xhot, yhot ); ImInfo( "Hot Spot", message ); } else { ImInfo( "Hot Spot", "none" ); } /* * Skip: * static char name_bits[] = { */ i = 1; while ( i-- ) { for ( c = fgetc( fp ); c != EOF && c != '\n'; c = fgetc( fp ) ) ; if ( c == EOF ) { if ( i == 0 ) ImErrorFatal( "Syntax error in bits array declaration", -1, IMESYNTAX ); ImErrorFatal( "Syntax error in giving hot spot location", -1, IMESYNTAX ); } } /* * Allocate a VFB of the required size. */ if ( (vfb = ImVfbAlloc( xdim, ydim, IMVFBMONO )) == IMVFBNULL ) ImErrorFatal( ImQError( ), -1, ImErrNo ); /* * Scan the file, reading in each hex character value holding * 8 bits. Unpack the bits into gray-scale values (0 = black, * 255 = white). */ xdimExtra = xdim & 0x7; xdim2 = xdim - xdimExtra; pPixel = ImVfbQFirst( vfb ); for ( i = 0; i < ydim; i++ ) { for ( j = 0; j < xdim2; j += 8 ) { /* Skip up to the 'x' in hex number. */ for ( c = fgetc( fp ); c != EOF && c != 'x'; ) c = fgetc( fp ); if ( c == EOF ) { sprintf( message, "Unexpected EOF in bits array element %d", i * (xdim2/8 + (xdimExtra+7)/8) + j/8 ); ImErrorFatal( message, -1, IMESYNTAX ); } /* Read in the pixel value. */ if ( fscanf( fp, "%x", &pixel ) != 1 ) { sprintf( message, "Syntax error in bits array element %d", i * (xdim2/8 + (xdimExtra+7)/8) + j/8 ); ImErrorFatal( message, -1, IMESYNTAX ); } for( k = 0; k < 8; k++ ) { ImVfbSMono( vfb, pPixel, (pixel&1) ); ImVfbSInc( vfb, pPixel ); pixel >>= 1; } } if ( xdimExtra == 0 ) continue; /* Skip up to the 'x' in hex number. */ for ( c = fgetc( fp ); c != EOF && c != 'x'; ) c = fgetc( fp ); if ( c == EOF ) { sprintf( message, "Unexpected EOF in bits array element %d", i * (xdim2/8 + (xdimExtra+7)/8) + j/8 ); ImErrorFatal( message, -1, IMESYNTAX ); } if ( fscanf( fp, "%x", &pixel ) != 1 ) { sprintf( message, "Syntax error in bits array element %d", i * (xdim2/8 + (xdimExtra+7)/8) + xdim2 ); ImErrorFatal( message, -1, IMESYNTAX ); } for( k = 0; k < xdimExtra; k++ ) { ImVfbSMono( vfb, pPixel, (pixel&1) ); ImVfbSInc( vfb, pPixel ); pixel >>= 1; } } /* * Add the VFB to the tagTable. */ TagTableAppend( tagTable, TagEntryAlloc( "image vfb", POINTER, &vfb ) ); return ( 1 ); } /* * FUNCTION * imXbmWrite - write a X11 bitmap file * * DESCRIPTION * The X11 bitmap header and image content are written out. */ static int /* Returns # of entries used */ #ifdef __STDC__ imXbmWrite( ImFileFormatWriteMap *pMap, int ioType, int fd, FILE *fp, TagTable *flagsTable, TagTable *tagTable ) #else imXbmWrite( pMap, ioType, fd, fp, flagsTable, tagTable ) ImFileFormatWriteMap *pMap; /* Write map entry to adhear to */ int ioType; /* Type of I/O to perform */ int fd; /* Output file descriptor */ FILE *fp; /* Output file pointer */ TagTable *flagsTable; /* Flags */ TagTable *tagTable; /* Table of info to write */ #endif { int xdim; /* # columns */ int xdim2; /* # columns (nearest 8bit bndry)*/ int xdimExtra; /* # columns mod 8 */ int ydim; /* # rows */ ImHotSpotPtr hotspotptr; /* hotspot pointer */ int hotspotflag = FALSE; /* TRUE, if there's a hotspot */ int xhot; /* hotspot x coordinate */ int yhot; /* hotspot y coordinate */ ImVfb *srcVfb; /* VFB to convert */ ImVfbPtr pPixel; /* gray pixel pointer */ char buf[1024]; /* Output buffer */ int pixel; /* Gray pixel color */ int i, j, k; /* Counters */ int n; /* # of tag table entries */ char name[1024]; /* Bitmap name */ char *s; /* String pointer */ char message[100]; /* ImInfo message */ /* * Use the output file's name, sans leading path and dot * extensions, to make up the root name of the #define's * and bits array declaration. */ s = &ImErrorFileName[strlen(ImErrorFileName)-1]; while ( s != (ImErrorFileName-1) && *s != '/' ) s--; ++s; if ( !isalpha( *s ) ) { /* Make it a legal variable name by adding an 'x'.*/ name[0] = 'x'; name[1] = '\0'; strcat( name, s ); } else strcpy( name, s ); s = name; while ( isalpha( *s ) || isdigit( *s ) || *s == '_' ) s++; *s = '\0'; /* * Get hotspot info if available */ if( TagEntryQValue( TagTableQDirect( tagTable, "image hot spot", 0 ), &hotspotptr ) != -1 ) { xhot = ImHotSpotQX( hotspotptr ); yhot = ImHotSpotQY( hotspotptr ); hotspotflag = TRUE; } /* * Write out the header. */ TagEntryQValue( TagTableQDirect( tagTable, "image vfb", 0 ), &srcVfb ); xdim = ImVfbQWidth( srcVfb ); ydim = ImVfbQHeight( srcVfb ); if ( ioType & IMFILEIOFD ) { sprintf( buf, "#define %s_width %d\n", name, xdim ); write( fd, buf, strlen( buf ) ); sprintf( buf, "#define %s_height %d\n", name, ydim ); write( fd, buf, strlen( buf ) ); if( hotspotflag == TRUE ) { sprintf( buf, "#define %s_x_hot %d\n", name, xhot ); write( fd, buf, strlen( buf ) ); sprintf( buf, "#define %s_y_hot %d\n", name, yhot ); write( fd, buf, strlen( buf ) ); } sprintf( buf, "static char %s_bits[] = {\n", name ); write( fd, buf, strlen( buf ) ); } else { fprintf( fp, "#define %s_width %d\n", name, xdim ); fprintf( fp, "#define %s_height %d\n", name, ydim ); if( hotspotflag == TRUE ) { fprintf( fp, "#define %s_x_hot %d\n", name, xhot ); fprintf( fp, "#define %s_y_hot %d\n", name, yhot ); } fprintf( fp, "static char %s_bits[] = {\n", name ); } xdimExtra = xdim & 0x7; xdim2 = xdim - xdimExtra; /* * Output -verbose message */ sprintf( message, "%d x %d", xdim, ydim ); ImInfo( "Resolution", message ); ImInfo( "Type", "1-bit Monochrome" ); if( hotspotflag == TRUE ) { sprintf( message, "%d, %d", xhot, yhot ); ImInfo( "Hot Spot", message ); } else { ImInfo( "Hot Spot", "none" ); } /* * Write out the image. */ pPixel = ImVfbQFirst( srcVfb ); for ( i = 0; i < ydim; i++ ) { for ( j = 0; j < xdim2; j += 8 ) { pixel = 0; for ( k = 0; k < 8; k++ ) { if ( ImVfbQMono( srcVfb, pPixel ) > 0 ) pixel |= (1< 0 ) pixel |= (1<