[comp.sources.x] v09i055: xloadimage, Part08/09

jimf@saber.com (09/28/90)

Submitted-by: saber.com!jimf@saber.com
Posting-number: Volume 9, Issue 55
Archive-name: xloadimage/part08

#! /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 8 (of 9)."
# Contents:  window.c xloadimage.c xpixmap.c zoom.c
# Wrapped by jimf@armory on Tue Sep 25 19:37:42 1990
PATH=/bin:/usr/bin:/usr/ucb ; export PATH
if test -f 'window.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'window.c'\"
else
echo shar: Extracting \"'window.c'\" \(11558 characters\)
sed "s/^X//" >'window.c' <<'END_OF_FILE'
X/* window.c:
X *
X * display an image in a window
X *
X * jim frost 10.03.89
X *
X * Copyright 1989, 1990 Jim Frost.  See included file "copyright.h" for
X * complete copyright information.
X */
X
X#include "copyright.h"
X#include "xloadimage.h"
X#include <ctype.h>
X#include <X11/cursorfont.h>
X
X#ifdef SYSV
X#include <strings.h>
X#define index strchr
Xy#define rindex strrchr
X#else
Xchar *index();
Xchar *rindex();
X#endif
X
Xstatic Window ImageWindow= 0;
X
Xstatic void setCursor(disp, window, iw, ih, ww, wh, cursor)
X     Display      *disp;
X     Window        window;
X     unsigned int  iw, ih;
X     unsigned int  ww, wh;
X     Cursor       *cursor;
X{ XSetWindowAttributes swa;
X
X  if ((ww >= iw) && (wh >= ih))
X    swa.cursor= XCreateFontCursor(disp, XC_icon);
X  else if ((ww < iw) && (wh >= ih))
X    swa.cursor= XCreateFontCursor(disp, XC_sb_h_double_arrow);
X  else if ((ww >= iw) && (wh < ih))
X    swa.cursor= XCreateFontCursor(disp, XC_sb_v_double_arrow);
X  else
X    swa.cursor= XCreateFontCursor(disp, XC_fleur);
X  XChangeWindowAttributes(disp, window, CWCursor, &swa);
X  XFreeCursor(disp, *cursor);
X  *cursor= swa.cursor;
X}
X
X/* place an image
X */
X
Xstatic void placeImage(width, height, winwidth, winheight, rx, ry)
X     int width, height, winwidth, winheight;
X     int *rx, *ry; /* supplied and returned */
X{ int pixx, pixy;
X
X  pixx= *rx;
X  pixy= *ry;
X
X  if (winwidth > width)
X    pixx= (winwidth - width) / 2;
X  else {
X    if ((pixx < 0) && (pixx + width < winwidth))
X      pixx= winwidth - width;
X    if (pixx > 0)
X      pixx= 0;
X  }
X  if (winheight > height)
X    pixy= (winheight - height) / 2;
X  else {
X    if ((pixy < 0) && (pixy + height < winheight))
X      pixy= winheight - height;
X    if (pixy > 0)
X      pixy= 0;
X  }
X  *rx= pixx;
X  *ry= pixy;
X}
X
X/* blit an image
X */
X
Xstatic void blitImage(disp, pixmap, window, gc, pixx, pixy, width, height,
X		      winwidth, winheight, x, y, w, h)
X     Display *disp;
X     Pixmap   pixmap;
X     Window   window;
X     GC       gc;
X     int      pixx, pixy, width, height, winwidth, winheight, x, y, w, h;
X{
X  if (x + w > winwidth)
X    w= winwidth - x;
X  if (y + h > winheight)
X    h= winheight - y;
X  if (x < pixx) {
X    XClearArea(disp, window, x, y, pixx - x, y + h, False);
X    w -= (pixx - x);
X    x= pixx;
X  }
X  if (y < pixy) {
X    XClearArea(disp, window, x, y, w, pixy - y, False);
X    h -= (pixy - y);
X    y= pixy;
X  }
X  if (x + w > pixx + width) {
X    XClearArea(disp, window, pixx + width, y, w - width, h, False);
X    w= width;
X  }
X  if (y + h > pixy + height) {
X    XClearArea(disp, window, x, pixy + height, w, h - height, False);
X    h= height;
X  }
X  XCopyArea(disp, pixmap, ImageWindow, gc, x - pixx, y - pixy, w, h,
X	    x, y);
X}
X
X/* clean up static window if we're through with it
X */
X
Xvoid cleanUpWindow(disp)
X     Display *disp;
X{
X  if (ImageWindow)
X    XDestroyWindow(disp, ImageWindow);
X  ImageWindow= 0;
X}
X
X/* this attempts to convert an image title into a reasonable icon name
X */
X
Xstatic char *iconName(s)
X     char *s;
X{ static char buf[BUFSIZ];
X  char *t;
X
X  buf[BUFSIZ - 1]= '\0';
X  strncpy(buf, s, BUFSIZ - 1);
X  t= index(buf, ' '); /* strip off stuff following 1st word.  this strips */
X  if (t)              /* info added by processing functions too. */
X    *t= '\0';
X
X  /* strip off leading path.  if you don't use unix-style paths, you might
X   * want to change this.
X   */
X
X  if (t= rindex(buf, '/')) {
X    for (s= buf, t++; *t; s++, t++)
X      *s= *t;
X    *s= '\0';
X  }
X  t= index(buf, '.'); /* look for an extension and strip it off */
X  if (t)
X    *t= '\0';
X  return(buf);
X}
X
Xchar imageInWindow(disp, scrn, image, user_geometry,
X		   fullscreen, install, slideshow, argc, argv, verbose)
X     Display      *disp;
X     int           scrn;
X     Image        *image;
X     char         *user_geometry;
X     unsigned int  fullscreen;
X     unsigned int  install;
X     unsigned int  slideshow;
X     int           argc;
X     char         *argv[];
X     unsigned int  verbose;
X{ Pixmap               pixmap;
X  Colormap             xcmap;
X  static Colormap      tmpxcmap= 0; /* used when in slideshow mode */
X  XSetWindowAttributes swa;
X  XSizeHints           sh;
X  XWMHints             wmh;
X  XGCValues            gcv;
X  GC                   gc;
X  int                  pixx, pixy;
X  int                  lastx, lasty, mousex, mousey;
X  int                  paint;
X  union {
X    XEvent              event;
X    XAnyEvent           any;
X    XButtonEvent        button;
X    XKeyEvent           key;
X    XConfigureEvent     configure;
X    XExposeEvent        expose;
X    XMotionEvent        motion;
X    XResizeRequestEvent resize;
X  } event;
X  unsigned int          winx, winy, winwidth, winheight;
X  char                  def_geom[30];
X
X  /* figure out the window size.  unless specifically requested to do so,
X   * we will not exceed 90% of display real estate.
X   */
X
X  sprintf(def_geom, "%ux%u+0+0", image->width, image->height);
X  XGeometry(disp, scrn, user_geometry, def_geom, 0, 1, 1, 0, 0,
X	    &winx, &winy, &winwidth, &winheight);
X
X  if (fullscreen) {
X    winwidth= DisplayWidth(disp, scrn);
X    winheight= DisplayHeight(disp, scrn);
X  }
X  else {
X    lastx= (winwidth || winheight); /* user set size flag */
X    if (!winwidth) {
X      winwidth= image->width;
X      if (winwidth > DisplayWidth(disp, scrn) * 0.9)
X	winwidth= DisplayWidth(disp, scrn) * 0.9;
X    }
X    if (!winheight) {
X      winheight= image->height;
X      if (winheight > DisplayHeight(disp, scrn) * 0.9)
X	winheight= DisplayHeight(disp, scrn) * 0.9;
X    }
X  }
X
X  if (! sendImageToX(disp, scrn, DefaultVisual(disp, scrn),
X		     image, &pixmap, &xcmap, verbose))
X    exit(1);
X
X  swa.background_pixel= BlackPixel(disp,scrn);
X  swa.backing_store= NotUseful;
X  swa.bit_gravity= NorthWestGravity;
X  swa.cursor= XCreateFontCursor(disp, XC_watch);
X  swa.colormap= xcmap;
X  swa.event_mask= ButtonPressMask | Button1MotionMask | KeyPressMask |
X    ExposureMask | StructureNotifyMask | EnterWindowMask | LeaveWindowMask;
X  swa.save_under= False;
X  swa.override_redirect= (fullscreen ? True : False);
X  if (!ImageWindow) {
X    static XClassHint classHint;
X    ImageWindow= XCreateWindow(disp, RootWindow(disp, scrn), winx, winy,
X			       winwidth, winheight, 0,
X			       DefaultDepth(disp, scrn),
X			       InputOutput, CopyFromParent,
X			       CWBackPixel | CWBackingStore |
X			       CWBitGravity | CWCursor | CWColormap |
X			       CWEventMask | CWSaveUnder, &swa);
X    XSetCommand(disp, ImageWindow, argv, argc);
X    classHint.res_class = "xloadimage";
X    classHint.res_name=NULL;
X    (void) XSetClassHint(disp,ImageWindow,&classHint);
X    paint= 0;
X  }
X  else {
X    XResizeWindow(disp, ImageWindow, winwidth, winheight);
X    XChangeWindowAttributes(disp, ImageWindow, CWColormap, &swa);
X    paint= 1;
X  }
X  XStoreName(disp, ImageWindow, image->title);
X  XSetIconName(disp, ImageWindow, iconName(image->title));
X
X  sh.width= winwidth;
X  sh.height= winheight;
X  if (fullscreen) {
X    sh.min_width= sh.max_width= winwidth;
X    sh.min_height= sh.max_height= winheight;
X  }
X  else {
X    sh.min_width= 1;
X    sh.min_height= 1;
X    sh.max_width= image->width;
X    sh.max_height= image->height;
X  }
X  sh.width_inc= 1;
X  sh.height_inc= 1;
X  if (slideshow) {
X      sh.flags= PMinSize | PResizeInc;
X  } else {
X      sh.flags= PMinSize | PMaxSize | PResizeInc;
X  }
X  if (lastx || fullscreen)
X    sh.flags |= USSize;
X  else
X    sh.flags |= PSize;
X  if (fullscreen) {
X    sh.x= sh.y= 0;
X    sh.flags |= USPosition;
X  }
X  else if (winx || winy) {
X    sh.x= winx;
X    sh.y= winy;
X    sh.flags |= USPosition;
X  }
X  XSetNormalHints(disp, ImageWindow, &sh);
X
X  wmh.input= True;
X  wmh.flags= InputHint;
X  XSetWMHints(disp, ImageWindow, &wmh);
X
X  gcv.function= GXcopy;
X  gcv.foreground= 0;
X  gc= XCreateGC(disp, ImageWindow, GCFunction | GCForeground, &gcv);
X  XMapWindow(disp, ImageWindow);
X  placeImage(image->width, image->height, winwidth, winheight, &pixx, &pixy);
X  if (paint)
X    blitImage(disp, pixmap, ImageWindow, gc,
X	      pixx, pixy, image->width, image->height, winwidth, winheight,
X	      0, 0, winwidth, winheight);
X  setCursor(disp, ImageWindow, image->width, image->height,
X	    winwidth, winheight, &(swa.cursor));
X
X /* free old image's colormap if necessary.  this is done here to minimize
X  * technicolor when swapping images.
X  */
X
X  if (slideshow && tmpxcmap) {
X    XFreeColormap(disp, tmpxcmap);
X    tmpxcmap= 0;
X  }
X
X  lastx= lasty= -1;
X  for (;;) {
X    XNextEvent(disp, &event);
X    switch (event.any.type) {
X    case ButtonPress:
X      if (event.button.button == 1) {
X	lastx= event.button.x;
X	lasty= event.button.y;
X	break;
X      }
X      break;
X
X    case KeyPress: {
X      char buf[128];
X      KeySym ks;
X      XComposeStatus status;
X      char ret;
X      Cursor cursor;
X
X      XLookupString(&event.key,buf,128,&ks,&status);
X      ret= buf[0];
X      if (isupper(ret))
X	ret= tolower(ret);
X      switch (ret) {
X      case 'n':
X      case 'p':
X	cursor= swa.cursor;
X	swa.cursor= XCreateFontCursor(disp, XC_watch);
X	XChangeWindowAttributes(disp, ImageWindow, CWCursor, &swa);
X	XFreeCursor(disp, cursor);
X	XFlush(disp);
X	/* FALLTHRU */
X      case '\003': /* ^C */
X      case 'q':
X	XFreeCursor(disp, swa.cursor);
X	XFreePixmap(disp, pixmap);
X
X	/* XCopyColormapAndFree accomplishes two things.  First, it frees up
X	 * all our colors in the default colormap.  second, on some displays
X	 * it will help cut down on technicolor.  i tried to duplicate the
X	 * current colormap exactly but some servers return BadValue when
X	 * trying XQueryColor on an unallocated colormap entry so I gave up.
X	 */
X
X	if (slideshow && xcmap == DefaultColormap(disp, scrn) && (ret != 'q'))
X	  tmpxcmap= XCopyColormapAndFree(disp, xcmap);
X	if (xcmap != DefaultColormap(disp, scrn))
X          XFreeColormap(disp, xcmap);
X	return(ret);
X      }
X      break;
X    }
X
X    case MotionNotify:
X      if ((image->width <= winwidth) && (image->height <= winheight))
X	break; /* we're AT&T */
X      mousex= event.button.x;
X      mousey= event.button.y;
X      while (XCheckTypedEvent(disp, MotionNotify, &event) == True) {
X	mousex= event.button.x;
X	mousey= event.button.y;
X      }
X      pixx -= (lastx - mousex);
X      pixy -= (lasty - mousey);
X      lastx= mousex;
X      lasty= mousey;
X      placeImage(image->width, image->height, winwidth, winheight,
X		 &pixx, &pixy);
X      blitImage(disp, pixmap, ImageWindow, gc,
X		pixx, pixy, image->width, image->height, winwidth, winheight,
X		0, 0, winwidth, winheight);
X      break;
X
X    case ConfigureNotify:
X      winwidth= event.configure.width;
X      winheight= event.configure.height;
X
X      placeImage(image->width, image->height, winwidth, winheight,
X		 &pixx, &pixy);
X
X      /* configure the cursor to indicate which directions we can drag
X       */
X
X      setCursor(disp, ImageWindow, image->width, image->height,
X		winwidth, winheight, &(swa.cursor));
X
X      /* repaint 
X       */
X
X      blitImage(disp, pixmap, ImageWindow, gc,
X		pixx, pixy, image->width, image->height, winwidth, winheight,
X		0, 0, winwidth, winheight);
X      break;
X
X    case DestroyNotify:
X      XFreeCursor(disp, swa.cursor);
X      XFreePixmap(disp, pixmap);
X      if (xcmap != DefaultColormap(disp, scrn))
X	XFreeColormap(disp, xcmap);
X      return('\0');
X
X    case Expose:
X      blitImage(disp, pixmap, ImageWindow, gc,
X		pixx, pixy, image->width, image->height, winwidth, winheight,
X		event.expose.x, event.expose.y,
X		event.expose.width, event.expose.height);
X      break;
X
X    case EnterNotify:
X      if (install)
X	XInstallColormap(disp, xcmap);
X      break;
X
X    case LeaveNotify:
X      if (install)
X	XUninstallColormap(disp, xcmap);
X    }
X  }
X}
END_OF_FILE
if test 11558 -ne `wc -c <'window.c'`; then
    echo shar: \"'window.c'\" unpacked with wrong size!
fi
# end of 'window.c'
fi
if test -f 'xloadimage.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'xloadimage.c'\"
else
echo shar: Extracting \"'xloadimage.c'\" \(12257 characters\)
sed "s/^X//" >'xloadimage.c' <<'END_OF_FILE'
X/* loadimage.c:
X *
X * generic image loader for X11
X *
X * jim frost 09.27.89
X *
X * Copyright 1989, 1990 Jim Frost.  See included file "copyright.h" for
X * complete copyright information.
X */
X
X#include "copyright.h"
X#include "xloadimage.h"
X#include "patchlevel"
X
Xextern double atof();
X
X/* options array and definitions.  note that the enum values must be in the
X * same order as the options strings.
X */
X
Xchar *Options[] = {
X  "onroot", /* global options */
X  "border",
X  "display",
X  "fullscreen",
X  "geometry",
X  "help",
X  "identify",
X  "list",
X  "install",
X  "path",
X  "quiet",
X  "slideshow",
X  "supported",
X  "verbose",
X  "version",
X  "view",
X
X  "at", /* image options */
X  "background",
X  "brighten",
X  "gamma",
X  "center",
X  "clip",
X  "colors",
X  "dither",
X  "foreground",
X  "halftone",
X  "name",
X  "rotate",
X  "smooth",
X  "xzoom",
X  "yzoom",
X  "zoom",
X  NULL
X};
X
Xenum {
X
X  /* global options
X   */
X
X  ONROOT= 0, BORDER, DISPLAY, FULLSCREEN, GEOMETRY, HELP, IDENTIFY, LIST,
X  INSTALL, PATH, QUIET, SLIDESHOW, SUPPORTED, VERBOSE, VER_NUM, VIEW,
X
X  /* local options
X   */
X
X  AT, BACKGROUND, BRIGHT, GAMMA, CENTER, CLIP, COLORS, DITHER, FOREGROUND,
X  HALFTONE, NAME, ROTATE, SMOOTH, XZOOM, YZOOM, ZOOM
X};
X
X/* if an image loader needs to have our display and screen, it will get
X * them from here.  this is done to keep most of the image routines
X * clean
X */
X
XDisplay *Disp= NULL;
Xint      Scrn= 0;
X
X/* the real thing
X */
X
Xmain(argc, argv)
X     int argc;
X     char *argv[];
X{ char         *border;
X  char         *dname;
X  unsigned int  identify;
X  unsigned int  install;
X  unsigned int  slideshow;
X  unsigned int  verbose;
X  Image        *dispimage;      /* image that will be sent to the display */
X  Image        *newimage;       /* new image we're loading */
X  Display      *disp;           /* display we're sending to */
X  int           scrn;           /* screen we're sending to */
X  XColor        xcolor;         /* color for border option */
X  ImageOptions  images[MAXIMAGES]; /* list of image w/ options to load */
X  int           a;
X  unsigned int  imagecount;     /* number of images in ImageName array */
X  char         *user_geometry;	/* -geometry passed by user */
X  unsigned int  winwidth, winheight; /* geometry of image */
X  unsigned int  slide_bright= 0; /* options which are propagated to all */
X  unsigned int  slide_colors= 0; /* images when in -slideshow mode */
X  unsigned int  slide_dither= 0;
X  float         slide_gamma= 1.0;
X  unsigned int  slide_smooth= 0;
X  unsigned int  slide_xzoom= 0;
X  unsigned int  slide_yzoom= 0;
X
X  if (argc < 2)
X    usage(argv[0]);
X
X  /* defaults and other initial settings.  some of these depend on what
X   * our name was when invoked.
X   */
X
X  loadPathsAndExts();
X  onroot= 0;
X  verbose= 1;
X  if (!strcmp(tail(argv[0]), "xview")) {
X    onroot= 0;
X    verbose= 1;
X  }
X  else if (!strcmp(tail(argv[0]), "xsetbg")) {
X    onroot= 1;
X    verbose= 0;
X  }
X  border= NULL;
X  dname= NULL;
X  fullscreen= 0;
X  identify= 0;
X  install= 0;
X  slideshow= 0;
X  user_geometry = NULL;
X  winwidth= winheight= 0;
X
X  imagecount= 0;
X  for (a= 0; a < MAXIMAGES; a++) {
X    images[a].name= NULL;
X    images[a].atx= images[a].aty= 0;
X    images[a].bright= 0;
X    images[a].gamma= 1.0;
X    images[a].center= 0;
X    images[a].clipx= images[a].clipy= 0;
X    images[a].clipw= images[a].cliph= 0;
X    images[a].dither= 0;
X    images[a].colors= 0;
X    images[a].rotate= 0;
X    images[a].fg= images[a].bg= NULL;
X    images[a].xzoom= images[a].yzoom= 0;
X    images[a].smooth= 0;
X  }
X  for (a= 1; a < argc; a++) {
X    switch (optionNumber(argv[a], Options)) {
X    case OPT_BADOPT:
X      printf("%s: Bad option\n", argv[a]);
X      usage(argv[0]);
X      /* NOTREACHED */
X
X    case OPT_NOTOPT:
X      if (imagecount == MAXIMAGES)
X	printf("%s: Too many images (ignoring)\n", argv[++a]);
X      else {
X	images[imagecount++].name= argv[a];
X	if (slideshow && (imagecount < MAXIMAGES)) {
X	  images[imagecount].bright= slide_bright;
X	  images[imagecount].gamma= slide_gamma;
X	  images[imagecount].dither= slide_dither;
X	  images[imagecount].colors= slide_colors;
X	  images[imagecount].smooth= slide_smooth;
X	  images[imagecount].xzoom= slide_xzoom;
X	  images[imagecount].yzoom= slide_yzoom;
X	}
X      }
X      break;
X
X    case OPT_SHORTOPT:
X      printf("%s: Not enough characters to identify option\n", argv[a]);
X      usage(argv[0]);
X      /* NOTREACHED */
X
X    /* process options global to everything
X     */
X
X    case ONROOT:
X      onroot= 1;
X      break;
X
X    case BORDER:
X      if (argv[++a])
X	border= argv[a];
X      break;
X
X    case DISPLAY:
X      if (argv[++a])
X	dname= argv[a];
X      break;
X
X    case FULLSCREEN:
X      fullscreen= 1;
X      break;
X
X    case GEOMETRY:
X      if (argv[++a])
X	user_geometry = argv[a];
X      break;
X
X    case HELP:
X      usage(argv[0]);
X      exit(0);
X
X    case IDENTIFY:
X      identify= 1;
X      break;
X
X    case LIST:
X      listImages();
X      exit(0);
X
X    case INSTALL:
X      install= 1;
X      break;
X
X    case PATH:
X      showPath();
X      break;
X
X    case QUIET:
X      verbose= 0;
X      break;
X
X    case SLIDESHOW:
X      slideshow= 1;
X      break;
X
X    case SUPPORTED:
X      supportedImageTypes();
X      break;
X
X    case VERBOSE:
X      verbose= 1;
X      break;
X
X    case VER_NUM:
X      printf("Xloadimage version %s patchlevel %s by Jim Frost\n",
X	     VERSION, PATCHLEVEL);
X      break;
X
X    case VIEW:
X      onroot= 0;
X      break;
X
X    /* process options local to an image
X     */
X
X    case AT:
X      if (!argv[++a])
X	break;
X      if (sscanf(argv[a], "%d,%d",
X		 &images[imagecount].atx, &images[imagecount].aty) != 2) {
X	printf("Bad argument to -at\n");
X	usage(argv[0]);
X	/* NOTREACHED */
X      }
X      break;
X
X    case BACKGROUND:
X      if (argv[++a])
X	images[imagecount].bg= argv[a];
X      break;
X
X    case BRIGHT:
X      if (argv[++a]) {
X	images[imagecount].bright= atoi(argv[a]);
X	if (slideshow)
X	  slide_bright= images[imagecount].bright;
X      }
X      break;
X
X    case GAMMA:
X      if (argv[++a]) {
X	images[imagecount].gamma= atof(argv[a]);
X	if (slideshow)
X	  slide_gamma= images[imagecount].gamma;
X      }
X      break;
X
X    case CENTER:
X      images[imagecount].center= 1;
X      break;
X
X    case CLIP:
X      if (!argv[++a])
X	break;
X      if (sscanf(argv[a], "%d,%d,%d,%d",
X		 &images[imagecount].clipx, &images[imagecount].clipy,
X		 &images[imagecount].clipw, &images[imagecount].cliph) != 4) {
X	printf("Bad argument to -clip\n");
X	usage(argv[0]);
X	/* NOTREACHED */
X      }
X      break;
X
X    case COLORS:
X      if (!argv[++a])
X	break;
X      images[imagecount].colors= atoi(argv[a]);
X      if (images[imagecount].colors < 2) {
X	printf("Argument to -colors is too low (ignored)\n");
X	images[imagecount].colors= 0;
X      }
X      else if (images[imagecount].colors > 65536) {
X	printf("Argument to -colors is too high (ignored)\n");
X	images[imagecount].colors= 0;
X      }
X      if (slideshow)
X	slide_colors= images[imagecount].colors;
X      break;
X
X    case DITHER:
X      images[imagecount].dither= 1;
X      if (slideshow)
X	slide_dither= 1;
X      break;
X
X    case FOREGROUND:
X      if (argv[++a])
X	images[imagecount].fg= argv[a];
X      break;
X
X    case HALFTONE:
X      images[imagecount].dither= 2;
X      if (slideshow)
X	slide_dither= 2;
X      break;
X
X    case NAME:
X      if (imagecount == MAXIMAGES)
X	printf("%s: Too many images (ignoring)\n", argv[++a]);
X      else
X	images[imagecount++].name= argv[++a];
X      break;
X
X    case ROTATE:
X      if (!argv[++a])
X	break;
X      images[imagecount].rotate = atoi(argv[a]);
X      if ((images[imagecount].rotate % 90) != 0)
X	{ printf("Argument to -rotate must be a multiple of 90 (ignored)\n");
X	  images[imagecount].rotate = 0;
X	}
X      else 
X	while (images[imagecount].rotate < 0)
X	  images[imagecount].rotate += 360;
X      break;
X
X    case SMOOTH:
X      if (slideshow) {
X	slide_smooth++;
X	images[imagecount].smooth= slide_smooth;
X      }
X      else
X	images[imagecount].smooth++; /* add a smoothing iteration */
X      break;
X
X    case XZOOM:
X      if (argv[++a]) {
X	images[imagecount].xzoom= atoi(argv[a]);
X	if (slideshow)
X	  slide_xzoom= images[imagecount].xzoom;
X      }
X      break;
X
X    case YZOOM:
X      if (argv[++a]) {
X	images[imagecount].yzoom= atoi(argv[a]);
X	if (slideshow)
X	  slide_yzoom= images[imagecount].yzoom;
X      }
X      break;
X
X    case ZOOM:
X      if (argv[++a]) {
X	images[imagecount].xzoom= images[imagecount].yzoom= atoi(argv[a]);
X	if (slideshow)
X	  slide_xzoom= slide_yzoom= images[imagecount].xzoom;
X      }
X      break;
X
X    default:
X
X      /* this should not happen!
X       */
X
X      printf("%s: Internal error parsing arguments\n", argv[0]);
X      exit(1);
X    }
X  }
X
X  if (!imagecount) /* NO-OP from here on */
X    exit(0);
X
X  if (identify) {                    /* identify the named image(s) */
X    for (a= 0; a < imagecount; a++)
X      identifyImage(images[a].name);
X    exit(0);
X  }
X
X  /* filter out mutually exclusive flags
X   */
X
X  if (onroot && slideshow) {
X    printf("\
X%s: -onroot and -slideshow are mutually exclusive (-onroot ignored)\n",
X	   argv[0]);
X    onroot= 0;
X  }
X
X  /* start talking to the display
X   */
X
X  if (! (Disp= disp= XOpenDisplay(dname))) {
X    printf("%s: Cannot open display\n", XDisplayName(dname));
X    exit(1);
X  }
X  Scrn= scrn= DefaultScreen(disp);
X#if defined(mips) || defined(_IBMR2)
X  XSetIOErrorHandler(ioErrorHandler);
X#else
X  XSetIOErrorHandler((XIOErrorHandler)ioErrorHandler);
X#endif
X
X  dispimage= NULL;
X
X  if (onroot && (winwidth || winheight || images[0].center ||
X      images[0].atx || images[0].aty)) {
X    if (!winwidth)
X	winwidth= DisplayWidth(disp, scrn);
X    if (!winheight)
X      winheight= DisplayHeight(disp, scrn);
X    if (DefaultDepth(disp, scrn) == 1)
X      dispimage= newBitImage(winwidth, winheight);
X    else {
X      dispimage= newRGBImage(winwidth, winheight, DefaultDepth(disp, scrn));
X      dispimage->rgb.used= 1;
X    }
X    *(dispimage->rgb.red)= 65535;   /* default border value is white */
X    *(dispimage->rgb.green)= 65535;
X    *(dispimage->rgb.blue)= 65535;
X    if (border) {
X      XParseColor(disp, DefaultColormap(disp, scrn), border, &xcolor);
X      *dispimage->rgb.red= xcolor.red;
X      *dispimage->rgb.green= xcolor.green;
X      *dispimage->rgb.blue= xcolor.blue;
X    }
X
X    /* bitmap needs both black and white
X     */
X
X    if (DefaultDepth(disp, scrn) == 1) {
X	if (*(dispimage->rgb.red)) {
X	    *(dispimage->rgb.red + 1)= 0;
X	    *(dispimage->rgb.green + 1)= 0;
X	    *(dispimage->rgb.blue + 1)= 0;
X	}
X	else {
X	    *(dispimage->rgb.red + 1)= 65535;
X	    *(dispimage->rgb.green + 1)= 65535;
X	    *(dispimage->rgb.blue + 1)= 65535;
X	}
X    }
X    fill(dispimage, 0, 0, winwidth, winheight, 0);
X  }
X
X  /* load in each named image
X   */
X
X  for (a= 0; a < imagecount; a++) {
X    if (! (newimage= loadImage(images[a].name, verbose)))
X      continue;
X    if (!images[a].dither &&
X	((dispimage && BITMAPP(dispimage)) || (DefaultDepth(disp, scrn) == 1)))
X      images[a].dither= 1;
X    newimage= processImage(disp, scrn, newimage, &images[a], verbose);
X    if (images[a].center && dispimage) {
X      images[a].atx= (int)(dispimage->width - newimage->width) / 2;
X      images[a].aty= (int)(dispimage->height - newimage->height) / 2;
X    }
X    if (dispimage) {
X      if (! dispimage->title)
X	dispimage->title= dupString(newimage->title);
X      merge(dispimage, newimage, images[a].atx, images[a].aty, verbose);
X      freeImage(newimage);
X    }
X    else
X      dispimage= newimage;
X    if (slideshow) {
X      switch(imageInWindow(disp, scrn, dispimage, user_geometry,
X			   fullscreen, install, slideshow, argc, argv,
X			   verbose)) {
X      case '\0': /* window got nuked by someone */
X	XCloseDisplay(disp);
X	exit(1);
X      case '\003':
X      case 'q':  /* user quit */
X	XCloseDisplay(disp);
X	exit(0);
X	
X      case 'n':  /* next image */
X	break;
X      case 'p':  /* previous image */
X	if (a > 0)
X	  a -= 2;
X	else
X	  a--;
X	break;
X      }
X      freeImage(dispimage);
X      dispimage= NULL;
X    }
X  }
X
X  if (!slideshow && !dispimage) {
X    printf("No images to display\n");
X    exit(1);
X  }
X
X  if (onroot)
X    imageOnRoot(disp, scrn, dispimage, verbose);
X  else {
X    if (!slideshow)
X      imageInWindow(disp, scrn, dispimage, user_geometry,
X		    fullscreen, install, slideshow, argc, argv, verbose);
X    cleanUpWindow(disp);
X  }
X  XCloseDisplay(disp);
X  exit(0);
X}
END_OF_FILE
if test 12257 -ne `wc -c <'xloadimage.c'`; then
    echo shar: \"'xloadimage.c'\" unpacked with wrong size!
fi
# end of 'xloadimage.c'
fi
if test -f 'xpixmap.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'xpixmap.c'\"
else
echo shar: Extracting \"'xpixmap.c'\" \(5893 characters\)
sed "s/^X//" >'xpixmap.c' <<'END_OF_FILE'
X/* xpixmap.c:
X *
X * XPixMap format file read and identify routines.  these can handle any
X * "format 1" XPixmap file with up to BUFSIZ - 1 chars per pixel.  it's
X * not nearly as picky as it might be.
X *
X * unlike most image loading routines, this is X specific since it
X * requires X color name parsing.  to handle this we have global X
X * variables for display and screen.  it's ugly but it keeps the rest
X * of the image routines clean.
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
X#ifdef SYSV
X#include <string.h>
X#define rindex strrchr
X#else
Xchar *rindex();
X#endif
X
Xextern Display *Disp; /* X display, null if in "identify" mode */
Xextern int      Scrn; /* X screen number */
X
X#define XPM_FORMAT 1
X
Xstatic void corrupted(fullname, zf)
X     char  *fullname;
X     ZFILE *zf;
X{
X  zclose(zf);
X  printf("%s: X Pixmap file is corrupted\n", fullname);
X  exit(1);
X}
X
XImage *xpixmapLoad(fullname, name, verbose)
X     char         *fullname, *name;
X     unsigned int  verbose;
X{ ZFILE         *zf;
X  char           buf[BUFSIZ];
X  char           what[BUFSIZ];
X  char          *p;
X  char          *imagetitle;
X  unsigned int   value;
X  unsigned int   format;  /* image format */
X  unsigned int   w, h;    /* image dimensions */
X  unsigned int   cpp;     /* chars per pixel */
X  unsigned int   ncolors; /* number of colors */
X  unsigned int   depth;   /* depth of image */
X  char         **ctable;  /* color table */
X  Image         *image;
X  XColor         xcolor;
X  unsigned int   a, b, x, y;
X  int            c;
X  byte          *dptr;
X
X  if (! (zf= zopen(fullname)))
X    return(NULL);
X
X  /* read #defines until we have all that are necessary or until we
X   * get an error
X   */
X
X  format= w= h= ncolors= 0;
X  for (;;) {
X    if (! zgets(buf, BUFSIZ - 1, zf)) {
X      zclose(zf);
X      return(NULL);
X    }
X    if (!strncmp(buf, "#define", 7)) {
X      if (sscanf(buf, "#define %s %d", what, &value) != 2) {
X	zclose(zf);
X	return(NULL);
X      }
X      if (! (p= rindex(what, '_')))
X	p= what;
X      else
X	p++;
X      if (!strcmp(p, "format"))
X	format= value;
X      else if (!strcmp(p, "width"))
X	w= value;
X      else if (!strcmp(p, "height"))
X	h= value;
X      else if (!strcmp(p, "ncolors"))
X	ncolors= value;
X
X      /* this one is ugly
X       */
X
X      else if (!strcmp(p, "pixel")) { /* this isn't pretty but it works */
X	if (p == what)
X	  continue;
X	*(--p)= '\0';
X	if (!(p= rindex(what, '_')) || (p == what) || strcmp(++p, "per"))
X	  continue;
X	*(--p)= '\0';
X	if (!(p= rindex(what, '_')))
X	  p= what;
X	if (strcmp(++p, "chars"))
X	  continue;
X	cpp= value;
X      }
X    }
X    else if ((sscanf(buf, "static char * %s", what) == 1) &&
X	     (p= rindex(what, '_')) && !strcmp(++p, "colors[]"))
X      break;
X  }
X
X  if ((format != XPM_FORMAT) || !w || !h || !ncolors || !cpp) {
X    zclose(zf);
X    return(NULL);
X  }
X
X  if (p= rindex(what, '_')) {     /* get the name in the image if there is */
X    *p= '\0';                     /* one */
X    imagetitle= dupString(what);
X  }
X  else {
X    p= what;
X    imagetitle= dupString(name);
X  }
X
X  if (verbose)
X    printf("%s is a %dx%d X Pixmap image with %d colors titled '%s'\n",
X	   name, w, h, ncolors, imagetitle);
X
X  for (depth= 1, value= 2; value < ncolors; value <<= 1, depth++)
X    ;
X  image= newRGBImage(w, h, depth);
X  image->rgb.used= ncolors;
X  image->title= dupString(imagetitle);
X
X  /* read the colors array and build the image colormap
X   */
X
X  ctable= (char **)lmalloc(sizeof(char *) * ncolors);
X  xcolor.flags= DoRed | DoGreen | DoBlue;
X  for (a= 0; a < ncolors; a++) {
X 
X    /* read pixel value
X     */
X
X    *(ctable + a)= (char *)lmalloc(cpp);
X    while (((c= zgetc(zf)) != EOF) && (c != '"'))
X      ;
X    if (c == EOF)
X      corrupted(fullname, zf);
X    for (b= 0; b < cpp; b++) {
X      if ((c= zgetc(zf)) == '\\')
X	c= zgetc(zf);
X     if (c == EOF)
X	corrupted(fullname, zf);
X      *(*(ctable + a) + b)= (char)c;
X    }
X    if (((c= zgetc(zf)) == EOF) || (c != '"'))
X      corrupted(fullname, zf);
X
X    /* read color definition and parse it
X     */
X
X    while (((c= zgetc(zf)) != EOF) && (c != '"'))
X      ;
X    if (c == EOF)
X      corrupted(fullname, zf);
X    for (b= 0; ((c= zgetc(zf)) != EOF) && (c != '"'); b++) {
X      if (c == '\\')
X	c= zgetc(zf);
X      if (c == EOF)
X	corrupted(fullname, zf);
X      buf[b]= (char)c;
X    }
X    buf[b]= '\0';
X
X    if (Disp) {
X      if (! XParseColor(Disp, DefaultColormap(Disp, Scrn), buf, &xcolor)) {
X	printf("%s: %s: Bad color name\n", fullname, buf);
X	exit(1);
X      }
X      *(image->rgb.red + a)= xcolor.red;
X      *(image->rgb.green + a)= xcolor.green;
X      *(image->rgb.blue + a)= xcolor.blue;
X    }
X  }
X
X  for (;;) {
X    if (! zgets(buf, BUFSIZ - 1, zf))
X      corrupted(fullname, zf);
X    if (sscanf(buf, "static char * %s", what) == 1)
X      break;
X  }
X
X  if (p= rindex(what, '_'))
X    p++;
X  else
X    p= what;
X  if (strcmp(p, "pixels[]"))
X    corrupted(fullname, zf);
X
X  /* read in image data
X   */
X
X  dptr= image->data;
X  for (y= 0; y < h; y++) {
X    while (((c= zgetc(zf)) != EOF) && (c != '"'))
X      ;
X    for (x= 0; x < w; x++) {
X      for (a= 0; a < cpp; a++) {
X	if ((c= zgetc(zf)) == '\\')
X	  c= zgetc(zf);
X	if (c == EOF)
X	  corrupted(fullname, zf);
X	buf[a]= (char)c;
X      }
X      for (a= 0; a < ncolors; a++)
X	if (!strncmp(*(ctable + a), buf, cpp))
X	  break;
X      if (a == ncolors) { /* major uncool */
X	zclose(zf);
X	printf("%s: Pixel data doesn't match color data\n", fullname);
X	exit(1);
X      }
X      valToMem((unsigned long)a, dptr, image->pixlen);
X      dptr += image->pixlen;
X    }
X    if ((c= zgetc(zf)) != '"')
X      corrupted(fullname, zf);
X  }
X  zclose(zf);
X  return(image);
X}
X
Xint xpixmapIdent(fullname, name)
X     char *fullname, *name;
X{ Image *image;
X
X  if (image= xpixmapLoad(fullname, name, (unsigned int)1)) {
X    freeImage(image);
X    return(1);
X  }
X  return(0);
X}
END_OF_FILE
if test 5893 -ne `wc -c <'xpixmap.c'`; then
    echo shar: \"'xpixmap.c'\" unpacked with wrong size!
fi
# end of 'xpixmap.c'
fi
if test -f 'zoom.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'zoom.c'\"
else
echo shar: Extracting \"'zoom.c'\" \(4347 characters\)
sed "s/^X//" >'zoom.c' <<'END_OF_FILE'
X/* zoom.c:
X *
X * zoom an image
X *
X * jim frost 10.11.89
X *
X * Copyright 1989 Jim Frost.  See included file "copyright.h" for complete
X * copyright information.
X */
X
X#include "copyright.h"
X#include "image.h"
X
Xstatic unsigned int *buildIndex(width, zoom, rwidth)
X     unsigned int  width;
X     unsigned int  zoom;
X     unsigned int *rwidth;
X{ float         fzoom;
X  unsigned int *index;
X  unsigned int  a;
X
X  if (!zoom) {
X    fzoom= 100.0;
X    *rwidth= width;
X  }
X  else {
X    fzoom= (float)zoom / 100.0;
X    *rwidth= fzoom * width;
X  }
X  index= (unsigned int *)lmalloc(sizeof(unsigned int) * *rwidth);
X  for (a= 0; a < *rwidth; a++)
X    if (zoom)
X      *(index + a)= (float)a / fzoom;
X    else
X      *(index + a)= a;
X  return(index);
X}
X
XImage *zoom(oimage, xzoom, yzoom, verbose)
X     Image        *oimage;
X     unsigned int  xzoom, yzoom;
X{ char          buf[BUFSIZ];
X  Image        *image;
X  unsigned int *xindex, *yindex;
X  unsigned int  xwidth, ywidth;
X  unsigned int  x, y, xsrc, ysrc;
X  unsigned int  pixlen;
X  unsigned int  srclinelen;
X  unsigned int  destlinelen;
X  byte         *srcline, *srcptr;
X  byte         *destline, *destptr;
X  byte          srcmask, destmask, bit;
X  Pixel         value;
X
X  goodImage(oimage, "zoom");
X
X  if (!xzoom && !yzoom) /* stupid user */
X    return(NULL);
X
X  if (!xzoom) {
X    if (verbose)
X      printf("  Zooming image Y axis by %d%%...", yzoom);
X      sprintf(buf, "%s (Y zoom %d%%)", oimage->title, yzoom);
X  }
X  else if (!yzoom) {
X    if (verbose)
X      printf("  Zooming image X axis by %d%%...", xzoom);
X    sprintf(buf, "%s (X zoom %d%%)", oimage->title, xzoom);
X  }
X  else if (xzoom == yzoom) {
X    if (verbose)
X      printf("  Zooming image by %d%%...", xzoom);
X    sprintf(buf, "%s (%d%% zoom)", oimage->title, xzoom);
X  }
X  else {
X    if (verbose)
X      printf("  Zooming image X axis by %d%% and Y axis by %d%%...",
X	     xzoom, yzoom);
X    sprintf(buf, "%s (X zoom %d%% Y zoom %d%%)", oimage->title,
X	    xzoom, yzoom);
X  }
X  if (verbose)
X    fflush(stdout);
X
X  xindex= buildIndex(oimage->width, xzoom, &xwidth);
X  yindex= buildIndex(oimage->height, yzoom, &ywidth);
X
X  switch (oimage->type) {
X  case IBITMAP:
X    image= newBitImage(xwidth, ywidth);
X    for (x= 0; x < oimage->rgb.used; x++) {
X      *(image->rgb.red + x)= *(oimage->rgb.red + x);
X      *(image->rgb.green + x)= *(oimage->rgb.green + x);
X      *(image->rgb.blue + x)= *(oimage->rgb.blue + x);
X    }
X    image->rgb.used= oimage->rgb.used;
X    destline= image->data;
X    destlinelen= (xwidth / 8) + (xwidth % 8 ? 1 : 0);
X    srcline= oimage->data;
X    srclinelen= (oimage->width / 8) + (oimage->width % 8 ? 1 : 0);
X    for (y= 0, ysrc= *(yindex + y); y < ywidth; y++) {
X      while (ysrc != *(yindex + y)) {
X	ysrc++;
X	srcline += srclinelen;
X      }
X      srcptr= srcline;
X      destptr= destline;
X      srcmask= 0x80;
X      destmask= 0x80;
X      bit= srcmask & *srcptr;
X      for (x= 0, xsrc= *(xindex + x); x < xwidth; x++) {
X	if (xsrc != *(xindex + x)) {
X	  do {
X	    xsrc++;
X	    if (!(srcmask >>= 1)) {
X	      srcmask= 0x80;
X	      srcptr++;
X	    }
X	  } while (xsrc != *(xindex + x));
X	  bit= srcmask & *srcptr;
X	}
X	if (bit)
X	  *destptr |= destmask;
X	if (!(destmask >>= 1)) {
X	  destmask= 0x80;
X	  destptr++;
X	}
X      }
X      destline += destlinelen;
X    }
X    break;
X
X  case IRGB:
X    image= newRGBImage(xwidth, ywidth, oimage->depth);
X    for (x= 0; x < oimage->rgb.used; x++) {
X      *(image->rgb.red + x)= *(oimage->rgb.red + x);
X      *(image->rgb.green + x)= *(oimage->rgb.green + x);
X      *(image->rgb.blue + x)= *(oimage->rgb.blue + x);
X    }
X    image->rgb.used= oimage->rgb.used;
X    pixlen= oimage->pixlen;
X    destptr= image->data;
X    srcline= oimage->data;
X    srclinelen= oimage->width * pixlen;
X    for (y= 0, ysrc= *(yindex + y); y < ywidth; y++) {
X      while (ysrc != *(yindex + y)) {
X	ysrc++;
X	srcline += srclinelen;
X      }
X
X      srcptr= srcline;
X      value= memToVal(srcptr, pixlen);
X      for (x= 0, xsrc= *(xindex + x); x < xwidth; x++) {
X	if (xsrc != *(xindex + x)) {
X	  do {
X	    xsrc++;
X	    srcptr += image->pixlen;
X	  } while (xsrc != *(xindex + x));
X	  value= memToVal(srcptr, pixlen);
X	}
X	valToMem(value, destptr++, pixlen);
X      }
X    }
X    break;
X  }
X
X  image->title= dupString(buf);
X  lfree((byte *)xindex);
X  lfree((byte *)yindex);
X  if (verbose)
X    printf("done\n");
X  return(image);
X}
END_OF_FILE
if test 4347 -ne `wc -c <'zoom.c'`; then
    echo shar: \"'zoom.c'\" unpacked with wrong size!
fi
# end of 'zoom.c'
fi
echo shar: End of archive 8 \(of 9\).
cp /dev/null ark8isdone
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.