[comp.sources.x] v09i056: xloadimage, Part09/09

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.