jimf@saber.com (09/28/90)
Submitted-by: saber.com!jimf@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@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@sun.com / argv@ora.com Opinions expressed reflect those of the author only.