[comp.windows.x] XRdBitF.c: faster bitmap reading code for libX11.a

jim@athsys.uucp (Jim Becker) (09/01/88)

Please excuse the following source posting to comp.windows.x, but 
my stuff isn't complex enough for comp.sources.x to accept it..

The following is new bitmap reading code that is considerably 
faster than the R2 release. It has been submitted for R3. It
replaces the XRdBitF.c file in the "core.src/lib/X" directory
on the distribution, for building the library libX11.a.

You only need it if you read a lot of bitmaps from disk.


-Jim Becker

--skip or snip--

/* Copyright, 1987, Massachusetts Institute of Technology */

#include "copyright.h"

/*
 *	Code to read bitmaps from disk files. Interprets 
 *	data from X10 and X11 bitmap files and creates
 *	Pixmap representations of files. Returns Pixmap
 *	ID and specifics about image.
 *
 *	Modified for speedup by Jim Becker, changed image
 *	data parsing logic (removed some fscanf()s). 
 *	Aug 5, 1988
 */


#include <ctype.h>
#include <stdio.h>
#include <sys/types.h>


#include <X11/Xos.h>
#include "Xlib.h"
#include "Xutil.h"
#include "Xlibint.h"

#define MAX_SIZE	255

/*	shared data for the image read/parse logic	*/

static	FILE		*fstream;		/* file read handle */
static	short		HexVal[255];		/* conversion value */
static	short		HexSet		= 0;	/* initialized flag */


/*
 *	Table index for the hex values. Initialized once, first time.
 *	Used for translation value or delimiter significance lookup.
 */
static	SetupHex()
{
	/* set the translation entry values that are meaningful */

	HexVal['0']	= 0;	HexVal['1']	= 1;
	HexVal['2']	= 2;	HexVal['3']	= 3;
	HexVal['4']	= 4;	HexVal['5']	= 5;
	HexVal['6']	= 6;	HexVal['7']	= 7;
	HexVal['8']	= 8;	HexVal['9']	= 9;
	HexVal['A']	= 10;	HexVal['B']	= 11;
	HexVal['C']	= 12;	HexVal['D']	= 13;
	HexVal['E']	= 14;	HexVal['F']	= 15;
	HexVal['a']	= 10;	HexVal['b']	= 11;
	HexVal['c']	= 12;	HexVal['d']	= 13;
	HexVal['e']	= 14;	HexVal['f']	= 15;

	/* delimiters of significance are flagged w/ negative value */

	HexVal[' ']	= -1;	HexVal[',']	= -1;
	HexVal['}']	= -1;	HexVal['\n']	= -1;
	HexVal['\t']	= -1;
	
	HexSet++;
}

/*
 *	read next hex value in the input stream, return -1 if EOF
 */
static	NextInt()
{
	int	ch;
	int	value	= 0;
	short	gotone	= 0;
	short	done	= 0;

	/* loop, accumulate hex value until find delimiter  */
	/* skip any initial delimiters found in read stream */

	while( !done ) {

		ch	= getc(fstream);

		if( ch == EOF ) {
			value	= -1;
			done++;
		}
		else {
			/* trim high bits, check type and accumulate */
			if( isxdigit( (ch &= 0xff) ) ) {
				value	= (value << 4) + HexVal[ch];
				gotone++;
			}
			else
			if( (HexVal[ch]) < 0 && gotone )
				done++;
		}
	}

	return value;
}


int	XReadBitmapFile( display, d, filename, width, height, pixmap, x_hot, y_hot )
Display		*display;
Drawable	d;
char 		*filename;
unsigned int	*width, *height;	/* RETURNED */
Pixmap		*pixmap;		/* RETURNED */
int		*x_hot, *y_hot;		/* RETURNED */
{
	char		*data		= NULL;
	char		*ptr;
	char		line[MAX_SIZE];
	int		size, bytes;
	char		name_and_type[MAX_SIZE];
	char		*type;
	int		value;
	int		version10p;
	int		padding;
	int		bytes_per_line;
	Pixmap		pix;
	unsigned int	ww = 0;
	unsigned int	hh = 0;
	int		hx = -1;
	int		hy = -1;

	/* error cleanup and return macro	*/

#define	RETURN(code)	{if(data) free(data); 	\
			 fclose(fstream);\
			 return(code);}

	/* first time initialization */
	if( !HexSet )
		SetupHex();

	if (!(fstream = fopen(filename, "r")))
		return(BitmapOpenFailed);

	while(fgets(line, MAX_SIZE, fstream)) {

		if (strlen(line) == MAX_SIZE-1) 
			RETURN(BitmapFileInvalid);

		if (sscanf(line, "#define %s %d", name_and_type, &value) == 2) {
			if (!(type = rindex(name_and_type, '_')))
				type = name_and_type;
			else
				type++;

			if (!strcmp("width", type))
				ww=(unsigned int) value;
			if (!strcmp("height", type))
				hh=(unsigned int) value;
			if (!strcmp("hot", type)) {
				if (type--==name_and_type || type--==name_and_type)
					continue;
				if (!strcmp("x_hot", type))
					hx = value;
				if (!strcmp("y_hot", type))
					hy = value;
			}
			continue;
		}
    
		if (sscanf(line, "static short %s = {", name_and_type) == 1)
			version10p = 1;
		else 
		if (sscanf(line, "static unsigned char %s = {", name_and_type) == 1)
			version10p = 0;
		else 
		if (sscanf(line, "static char %s = {", name_and_type) == 1)
			version10p = 0;
		else
			continue;

		if (!(type = rindex(name_and_type, '_')))
			type = name_and_type;
		else
			type++;

		if (strcmp("bits[]", type))
			continue;
    
		if (!ww || !hh)
			RETURN(BitmapFileInvalid);

		if ((ww % 16) && ((ww % 16) < 9) && version10p)
			padding = 1;
		else
			padding = 0;

		bytes_per_line = (ww+7)/8 + padding;
    
		size = bytes_per_line * hh;
		data = (char *)Xmalloc( size );

		if (!data) 
			RETURN(BitmapNoMemory);

		if (version10p)
			for (bytes=0, ptr=data; bytes<size; (bytes += 2)) {
				if ( (value = NextInt()) < 0 )
					RETURN(BitmapFileInvalid);

				*(ptr++) = value;
				if (!padding || ((bytes+2) % bytes_per_line))
					*(ptr++) = value >> 8;
			}
		else
			for (bytes=0, ptr=data; bytes<size; bytes++, ptr++) {
				if ( (value = NextInt()) < 0 ) 
					RETURN(BitmapFileInvalid);
				*ptr=value;
			}
	}

	if( data == NULL ) 
		RETURN(BitmapFileInvalid);

	/* take data and convert to a pixmap for the user */
	pix	= XCreateBitmapFromData(display, d, data, ww, hh);

	if( pix == NULL ) 
		RETURN(BitmapNoMemory);

	*pixmap		= pix;
	*width		= ww;
	*height		= hh;

	if( x_hot != NULL )
		*x_hot		= hx;

	if( y_hot != NULL )
		*y_hot 		= hy;

	RETURN(BitmapSuccess);
}

jkh@violet.berkeley.edu (Jordan K. Hubbard) (09/02/88)

In article <129@tityus.UUCP> jim@athsys.uucp (Jim Becker) writes:
>
>Please excuse the following source posting to comp.windows.x, but 
>my stuff isn't complex enough for comp.sources.x to accept it..
>
>The following is new bitmap reading code that is considerably 
>faster than the R2 release. It has been submitted for R3. It

Great. Do the plans for R3 also provide a routine for getting just the bits
from a bitmap image, so that one can then convert it into a pixmap
of arbitraty depth and color(s)?

				Jordan

jim@athsys.uucp (Jim Becker) (09/03/88)

From article <13842@agate.BERKELEY.EDU>, by jkh@violet.berkeley.edu (Jordan K. Hubbard):
> In article <129@tityus.UUCP> jim@athsys.uucp (Jim Becker) writes:
> 
> Great. Do the plans for R3 also provide a routine for getting just the bits
> from a bitmap image, so that one can then convert it into a pixmap
> of arbitraty depth and color(s)?
> 				Jordan


	This is the primary reason that I had to originally get into
this code, as it builds you a pixmap rather than letting you get to
the bits. (This was a change that was put in with the X10->X11
changes.)  By cloning this routine, renaming it and modifying the
logic not to create the pixmap from the data you can get what you
want. If you return the "data" pointer instead of a pixmap XID you can
then get at the bits.

	Also, there was a minor bug to this that causes it not to be
reentrant.  The "fstream" variable should be local to the
XReadBitmapFile routine, and passed to the routine NextInt. Otherwise
there could be problems. Otherwise, it seems fine.

	Email me if this is not clear, as I want to keep net clutter
down.


-Jim Becker