v09i056: xloadimage, Part09/09
saber.com!jimf at saber.com
saber.com!jimf at saber.com
Fri Sep 28 11:56:07 AEST 1990
Submitted-by: saber.com!jimf at saber.com
Posting-number: Volume 9, Issue 56
Archive-name: xloadimage/part09
#! /bin/sh
# This is a shell archive. Remove anything before this line, then unpack
# it by saving it into a file and typing "sh file". To overwrite existing
# files, type "sh file -c". You can also feed this as standard input via
# unshar, or by typing "sh <file", e.g.. If this archive is complete, you
# will see the following message at the end:
# "End of archive 9 (of 9)."
# Contents: xwd.c
# Wrapped by jimf at armory on Tue Sep 25 19:37:42 1990
PATH=/bin:/usr/bin:/usr/ucb ; export PATH
if test -f 'xwd.c' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'xwd.c'\"
else
echo shar: Extracting \"'xwd.c'\" \(14563 characters\)
sed "s/^X//" >'xwd.c' <<'END_OF_FILE'
X/* xwd.c:
X *
X * XWD file reader. unfortunately the bozo who thought up this format didn't
X * define anything at all that we can use as an identifier or even to tell
X * what kind of machine dumped the format. what this does is read the
X * header and look at several fields to decide if this *might* be an XWD
X * file and if it is what byte order machine wrote it.
X *
X * jim frost 07.24.90
X *
X * Copyright 1989 Jim Frost. See included file "copyright.h" for complete
X * copyright information.
X */
X
X#include "copyright.h"
X#include "xloadimage.h"
X#include "xwd.h"
X
X/* this reads the header and does the magic to determine if it is indeed
X * an XWD file.
X */
X
Xstatic int isXWD(name, zf, header, verbose)
X char *name;
X ZFILE *zf;
X XWDHeader *header;
X int verbose;
X{ GenericXWDHeader gh;
X int a;
X
X if (zread(zf, &gh, sizeof(GenericXWDHeader)) != sizeof(GenericXWDHeader))
X return(0);
X
X /* first try -- see if XWD version number matches in either MSB or LSB order
X */
X
X if (memToVal(gh.file_version, 4) != XWD_VERSION)
X return(0);
X
X /* convert fields to fill out header. things we don't care about
X * are commented out.
X */
X
X header->header_size= memToVal(gh.header_size, 4);
X header->file_version= memToVal(gh.file_version, 4);
X header->pixmap_format= memToVal(gh.pixmap_format, 4);
X header->pixmap_depth= memToVal(gh.pixmap_depth, 4);
X header->pixmap_width= memToVal(gh.pixmap_width, 4);
X header->pixmap_height= memToVal(gh.pixmap_height, 4);
X header->xoffset= memToVal(gh.xoffset, 4);
X header->byte_order= memToVal(gh.byte_order, 4);
X header->bitmap_unit= memToVal(gh.bitmap_unit, 4);
X header->bitmap_bit_order= memToVal(gh.bitmap_bit_order, 4);
X header->bitmap_pad= memToVal(gh.bitmap_pad, 4);
X header->bits_per_pixel= memToVal(gh.bits_per_pixel, 4);
X header->bytes_per_line= memToVal(gh.bytes_per_line, 4);
X header->visual_class= memToVal(gh.visual_class, 4);
X/*header->red_mask= memToVal(gh.red_mask, 4);*/
X/*header->green_mask= memToVal(gh.green_mask, 4);*/
X/*header->blue_mask= memToVal(gh.blue_mask, 4);*/
X/*header->bits_per_rgb= memToVal(gh.bits_per_rgb, 4);*/
X header->colormap_entries= memToVal(gh.colormap_entries, 4);
X header->ncolors= memToVal(gh.ncolors, 4);
X/*header->window_width= memToVal(gh.window_width, 4);*/
X/*header->window_height= memToVal(gh.window_height, 4);*/
X/*header->window_x= memToVal(gh.window_x, 4);*/
X/*header->window_y= memToVal(gh.window_y, 4);*/
X/*header->window_bdrwidth= memToVal(gh.window_bdrwidth, 4);*/
X
X /* if header size isn't either 100 or 104 bytes, this isn't an XWD file
X */
X
X if (header->header_size < sizeof(GenericXWDHeader))
X return(0);
X
X for (a= header->header_size - sizeof(GenericXWDHeader); a; a--)
X zgetc(zf);
X
X /* look at a variety of the XImage fields to see if they are sane. if
X * they are, this passes our tests.
X */
X
X switch (header->pixmap_format) {
X case XYBitmap:
X case XYPixmap:
X case ZPixmap:
X break;
X default:
X return(0);
X }
X
X switch (header->visual_class) {
X case StaticGray:
X case GrayScale:
X case StaticColor:
X case PseudoColor:
X
X /* the following are unsupported but recognized
X */
X
X case TrueColor:
X case DirectColor:
X break;
X default:
X return(0);
X }
X
X if (verbose) {
X printf("%s is a %dx%d XWD image in ",
X name, header->pixmap_width, header->pixmap_height);
X switch (header->pixmap_format) {
X case XYBitmap:
X printf("XYBitmap");
X break;
X case XYPixmap:
X printf("%d bit XYPixmap", header->pixmap_depth);
X break;
X case ZPixmap:
X printf("%d bit ZPixmap", header->pixmap_depth);
X break;
X }
X printf(" format\n");
X }
X
X /* if it got this far, we're pretty damned certain we've got the right
X * file type and know what order it's in.
X */
X
X return(1);
X}
X
Xint xwdIdent(fullname, name)
X char *fullname, *name;
X{ ZFILE *zf;
X XWDHeader header;
X int ret;
X
X if (! (zf= zopen(fullname)))
X return(0);
X ret= isXWD(name, zf, &header, 1);
X zclose(zf);
X return(ret);
X}
X
Xstatic Image *loadXYBitmap(fullname, zf, header)
X char *fullname;
X ZFILE *zf;
X XWDHeader header;
X{ Image *image;
X int dlinelen; /* length of scan line in data file */
X int ilinelen; /* length of line within image structure */
X int unit; /* # of bytes in a bitmap unit */
X int xoffset; /* xoffset within line */
X int xunits; /* # of units across the whole scan line */
X int trailer; /* # of bytes in last bitmap unit on a line */
X int shift; /* # of bits to shift last byte set */
X int x, y; /* horizontal and vertical counters */
X byte *line; /* input scan line */
X byte *dptr, *iptr; /* image data pointers */
X unsigned long (*loader)(); /* unit loading function */
X
X image= newBitImage(header.pixmap_width, header.pixmap_height);
X ilinelen= (header.pixmap_width / 8) + (header.pixmap_width % 8 ? 1 : 0);
X if (header.bitmap_unit > 7) /* supposed to be 8, 16, or 32 but appears */
X unit= header.bitmap_unit / 8; /* to often be the byte count. this will */
X else /* accept either. */
X unit= header.bitmap_unit;
X xoffset= (header.xoffset / (unit * 8)) * unit;
X if (header.bytes_per_line)
X dlinelen= header.bytes_per_line;
X else
X dlinelen= unit * header.pixmap_width;
X xunits= (header.pixmap_width / (unit * 8)) +
X (header.pixmap_width % (unit * 8) ? 1 : 0);
X trailer= unit - ((xunits * unit) - ilinelen);
X xunits--; /* we want to use one less than the actual # of units */
X shift= (unit - trailer) * 8;
X if (header.byte_order == MSBFirst)
X loader= memToVal;
X else
X loader= memToValLSB;
X line= (byte *)lmalloc(dlinelen);
X
X for (y= 0; y < header.pixmap_height; y++) {
X if (zread(zf, line, dlinelen) != dlinelen) {
X fprintf(stderr,
X "%s: Short read while reading data! (returning partial image)\n",
X fullname);
X lfree(line);
X return(image);
X }
X dptr= line + xoffset;
X iptr= image->data + (y * ilinelen);
X
X if (header.bitmap_bit_order == LSBFirst)
X flipBits(line, dlinelen);
X
X for (x= 0; x < xunits; x++) {
X valToMem(loader(dptr, unit), iptr, unit);
X dptr += unit;
X iptr += unit;
X }
X
X /* take care of last unit on this line
X */
X
X valToMem(loader(dptr, unit) >> shift, iptr, trailer);
X }
X
X lfree(line);
X return(image);
X}
X
X/* this is a lot like the above function but OR's planes together to
X * build the destination. 1-bit images are handled by XYBitmap.
X */
X
Xstatic Image *loadXYPixmap(fullname, zf, header)
X char *fullname;
X ZFILE *zf;
X XWDHeader header;
X{ Image *image;
X int plane;
X int dlinelen; /* length of scan line in data file */
X int ilinelen; /* length of line within image structure */
X int unit; /* # of bytes in a bitmap unit */
X int unitbits; /* # of bits in a bitmap unit */
X int unitmask; /* mask for current bit within current unit */
X int xoffset; /* xoffset within data */
X int xunits; /* # of units across the whole scan line */
X int x, x2, y; /* horizontal and vertical counters */
X int index; /* index within image scan line */
X byte *line; /* input scan line */
X byte *dptr, *iptr; /* image data pointers */
X unsigned long pixvals; /* bits for pixels in this unit */
X unsigned long mask;
X unsigned long (*loader)(); /* unit loading function */
X
X image= newRGBImage(header.pixmap_width, header.pixmap_height,
X header.pixmap_depth);
X ilinelen= image->width * image->pixlen;
X if (header.bitmap_unit > 7) /* supposed to be 8, 16, or 32 but appears */
X unit= header.bitmap_unit / 8; /* to often be the byte count. this will */
X else /* accept either. */
X unit= header.bitmap_unit;
X unitbits= unit * 8;
X unitmask= 1 << (unitbits - 1);
X xoffset= (header.xoffset / unitbits) * unit;
X if (header.bytes_per_line)
X dlinelen= header.bytes_per_line;
X else
X dlinelen= unit * header.pixmap_width;
X xunits= (header.pixmap_width / (unit * 8)) +
X (header.pixmap_width % (unit * 8) ? 1 : 0);
X if (header.byte_order == MSBFirst)
X loader= memToVal;
X else
X loader= memToValLSB;
X line= (byte *)lmalloc(dlinelen);
X
X /* for each plane, load in the bitmap and or it into the image
X */
X
X for (plane= header.pixmap_depth; plane > 0; plane--) {
X for (y= 0; y < header.pixmap_height; y++) {
X if (zread(zf, line, dlinelen) != dlinelen) {
X fprintf(stderr,
X "%s: Short read while reading data! (returning partial image)\n",
X fullname);
X lfree(line);
X return(image);
X }
X dptr= line + xoffset;
X iptr= image->data + (y * ilinelen);
X index= 0;
X
X if (header.bitmap_bit_order == LSBFirst)
X flipBits(line, dlinelen);
X
X for (x= 0; x < xunits; x++) {
X pixvals= loader(dptr, unit);
X mask= unitmask;
X for (x2= 0; x2 < unitbits; x2++) {
X if (pixvals & mask)
X valToMem(memToVal(iptr + index, image->pixlen) | (1 << plane),
X iptr + index, image->pixlen);
X index += image->pixlen;
X if (index > ilinelen) {
X x= xunits;
X break;
X }
X if (! (mask >>= 1))
X mask= unitmask;
X }
X dptr += unit;
X }
X }
X }
X
X lfree(line);
X return(image);
X}
X
X/* this loads a ZPixmap format image. note that this only supports depths
X * of 4, 8, 16, 24, or 32 bits as does Xlib. You gotta 6-bit image,
X * you gotta problem. 1-bit images are handled by XYBitmap.
X */
X
Xstatic Image *loadZPixmap(fullname, zf, header)
X char *fullname;
X ZFILE *zf;
X XWDHeader header;
X{ Image *image;
X int dlinelen; /* length of scan line in data file */
X int ilinelen; /* length of scan line in image file */
X int depth; /* depth rounded up to 8-bit value */
X int pixlen; /* length of pixel in bytes */
X int x, y; /* horizontal and vertical counters */
X byte *line; /* input scan line */
X byte *dptr, *iptr; /* image data pointers */
X unsigned long pixmask; /* bit mask within pixel */
X unsigned long pixel; /* pixel we're working on */
X unsigned long (*loader)(); /* unit loading function */
X
X image= newRGBImage(header.pixmap_width, header.pixmap_height,
X header.pixmap_depth);
X
X /* for pixmaps that aren't simple depths, we round to a depth of 8. this
X * is what Xlib does, be it right nor not.
X */
X
X if ((header.pixmap_depth != 4) && (header.pixmap_depth % 8))
X depth= header.pixmap_depth + 8 - (header.pixmap_depth % 8);
X else
X depth= header.pixmap_depth;
X
X pixmask= 0xffffffff >> (32 - header.pixmap_depth);
X if (header.bytes_per_line)
X dlinelen= header.bytes_per_line;
X else
X dlinelen= depth * header.pixmap_width;
X ilinelen= image->width * image->pixlen;
X if (header.byte_order == MSBFirst)
X loader= memToVal;
X else
X loader= memToValLSB;
X
X line= (byte *)lmalloc(dlinelen);
X
X for (y= 0; y < header.pixmap_height; y++) {
X if (zread(zf, line, dlinelen) != dlinelen) {
X fprintf(stderr,
X "%s: Short read while reading data! (returning partial image)\n",
X fullname);
X lfree(line);
X return(image);
X }
X dptr= line;
X iptr= image->data + (y * ilinelen);
X
X if (header.bitmap_bit_order == LSBFirst)
X flipBits(line, dlinelen);
X
X for (x= 0; x < header.pixmap_width; x++) {
X switch (depth) {
X case 4:
X pixel= memToVal(dptr, 1);
X if (header.bitmap_bit_order == LSBFirst) { /* nybbles are reversed */
X valToMem(pixel & 0xf, iptr++, 1); /* by flipBits */
X if (++x < header.pixmap_width)
X valToMem(pixel >> 4, iptr++, 1);
X }
X else {
X valToMem(pixel >> 4, iptr++, 1);
X if (++x < header.pixmap_width)
X valToMem(pixel & 0xf, iptr++, 1);
X }
X break;
X case 8:
X pixel= ((unsigned long)*(dptr++)) & pixmask; /* loader isn't needed */
X valToMem(pixel, iptr++, 1);
X break;
X case 16:
X case 24:
X case 32:
X valToMem(loader(dptr, pixlen) & pixmask, iptr, pixlen);
X dptr += pixlen;
X iptr += pixlen;
X break;
X default:
X fprintf(stderr,
X "%s: ZPixmaps of depth %d are not supported (sorry).\n",
X fullname, header.pixmap_depth);
X exit(1);
X }
X }
X }
X
X lfree(line);
X return(image);
X}
X
XImage *xwdLoad(fullname, name, verbose)
X char *fullname, *name;
X int verbose;
X{ ZFILE *zf;
X XWDHeader header;
X int cmaplen;
X XWDColor *cmap;
X Image *image;
X int a;
X
X if (! (zf= zopen(fullname)))
X return(NULL);
X if (! isXWD(name, zf, &header, verbose)) {
X zclose(zf);
X return(NULL);
X }
X
X /* complain if we don't understand the visual
X */
X
X switch (header.visual_class) {
X case StaticGray:
X case GrayScale:
X case StaticColor:
X case PseudoColor:
X break;
X case TrueColor:
X case DirectColor:
X fprintf(stderr, "Unsupported visual type, sorry\n");
X exit(1);
X }
X
X if ((header.pixmap_width == 0) || (header.pixmap_height == 0)) {
X fprintf(stderr, "Zero-size image -- header might be corrupted.\n");
X exit(1);
X }
X
X /* read in colormap
X */
X
X cmaplen= header.ncolors * sizeof(XWDColor);
X cmap= (XWDColor *)lmalloc(cmaplen);
X if (zread(zf, cmap, cmaplen) != cmaplen) {
X fprintf(stderr, "Short read in colormap!\n");
X exit(1);
X }
X
X /* any depth 1 image is basically a XYBitmap so we fake it here
X */
X
X if (header.pixmap_depth == 1)
X header.pixmap_format= XYBitmap;
X
X /* we can't realistically support images of more than depth 16 with the
X * RGB image format so this nukes them for the time being.
X */
X
X if (header.pixmap_depth > 16) {
X fprintf(stderr,
X "%s: Sorry, cannot load images deeper than 16 bits (yet)\n",
X fullname);
X exit(1);
X }
X
X switch (header.pixmap_format) {
X case XYBitmap:
X image= loadXYBitmap(fullname, zf, header);
X zclose(zf);
X image->title= dupString(name);
X return(image); /* we used to goof w/ the cmap but we gave up */
X case XYPixmap:
X image= loadXYPixmap(fullname, zf, header);
X break;
X case ZPixmap:
X image= loadZPixmap(fullname, zf, header);
X break;
X }
X zclose(zf);
X image->title= dupString(name);
X
X /* load the colormap. we should probably use pixval instead of the color
X * number but the value seems pretty system-dependent and most colormaps
X * seem to be just dumped in order.
X */
X
X image->rgb.used= header.ncolors;
X for (a= 0; a < header.ncolors; a++) {
X image->rgb.red[a]= memToVal(cmap[a].red, 2);
X image->rgb.green[a]= memToVal(cmap[a].green, 2);
X image->rgb.blue[a]= memToVal(cmap[a].blue, 2);
X }
X
X lfree(cmap);
X return(image);
X}
END_OF_FILE
if test 14563 -ne `wc -c <'xwd.c'`; then
echo shar: \"'xwd.c'\" unpacked with wrong size!
fi
# end of 'xwd.c'
fi
echo shar: End of archive 9 \(of 9\).
cp /dev/null ark9isdone
MISSING=""
for I in 1 2 3 4 5 6 7 8 9 ; do
if test ! -f ark${I}isdone ; then
MISSING="${MISSING} ${I}"
fi
done
if test "${MISSING}" = "" ; then
echo You have unpacked all 9 archives.
rm -f ark[1-9]isdone ark[1-9][0-9]isdone
else
echo You still need to unpack the following archives:
echo " " ${MISSING}
fi
## End of shell archive.
exit 0
dan
----------------------------------------------------
O'Reilly && Associates argv at sun.com / argv at ora.com
Opinions expressed reflect those of the author only.
More information about the Comp.sources.x
mailing list