[comp.sources.x] v06i001: Xloadimage, Patch 3, Part 01/02

argv%turnpike@Sun.COM (Dan Heller) (02/28/90)

Posting-number: Volume 6, Issue 1
Submitted-by: Jim Frost <jimf@saber.com>
Archive-name: xldimage/patch3.1-2
Patch-To: xldimage: Volume 5, Issue 27-28,30

This is part 1 of a 2 part patch to xloadimage to bring it from
patchlevel 02 to patchlevel 03.

There are many bug fixes and improvements in patchlevel 03, including
a new loader for GIF images.  This version should work on most X
servers, including those with depths of odd values such as 2 or 4 (eg
386/ix servers).  See the README file for more information.

Part 1, which follows, contains a patch file which should be applied
to a virgin patchlevel 02 source directory.  Save it in the file
"patch.03" and apply via "patch < patch.03".

Part 2 contains a shar file with the new GIF loader and associated
header files.  Save it in the file "patch.03.shar" and unpack it via
"sh patch.03.shar".

If you do not have xloadimage or do not have it updated to patchlevel
02, you can get the original source (distributed at patchlevel 01) and
the 02 patch from the comp.sources.x archives, or you can get the full
distribution from expo.lcs.mit.edu in /contrib/xloadimage.1.03.tar.Z
via anonymous ftp.  The original source and 02 patch are also on expo
but have been moved to /oldcontrib.

Feel free to email any questions or comments.

Enjoy,

jim frost
saber software
jimf@saber.com

-- patch.03: cut here --
diff -c xloadimage.02/Imakefile xloadimage.03/Imakefile
*** xloadimage.02/Imakefile	Sun Dec 31 16:03:09 1989
--- xloadimage.03/Imakefile	Wed Dec 13 15:18:47 1989
***************
*** 3,14 ****
          DEPLIBS = $(DEPLIBS)
  LOCAL_LIBRARIES = $(XLIB)
             SRCS = bright.c clip.c compress.c dither.c faces.c fill.c \
! 		  halftone.c imagetypes.c merge.c misc.c new.c \
  		  options.c path.c pbm.c reduce.c root.c send.c \
  		  sunraster.c value.c window.c xbitmap.c xloadimage.c \
  		  xpixmap.c zio.c zoom.c
             OBJS = bright.o clip.o compress.o dither.o faces.o fill.o \
! 		  halftone.o imagetypes.o merge.o misc.o new.o \
  		  options.o path.o pbm.o reduce.o root.o send.o \
  		  sunraster.o value.o window.o xbitmap.o xloadimage.o \
  		  xpixmap.o zio.o zoom.o
--- 3,14 ----
          DEPLIBS = $(DEPLIBS)
  LOCAL_LIBRARIES = $(XLIB)
             SRCS = bright.c clip.c compress.c dither.c faces.c fill.c \
! 		  gif.c halftone.c imagetypes.c merge.c misc.c new.c \
  		  options.c path.c pbm.c reduce.c root.c send.c \
  		  sunraster.c value.c window.c xbitmap.c xloadimage.c \
  		  xpixmap.c zio.c zoom.c
             OBJS = bright.o clip.o compress.o dither.o faces.o fill.o \
! 		  gif.o halftone.o imagetypes.o merge.o misc.o new.o \
  		  options.o path.o pbm.o reduce.o root.o send.o \
  		  sunraster.o value.o window.o xbitmap.o xloadimage.o \
  		  xpixmap.o zio.o zoom.o
diff -c xloadimage.02/Makefile.gcc xloadimage.03/Makefile.gcc
*** xloadimage.02/Makefile.gcc	Sun Dec 31 16:03:09 1989
--- xloadimage.03/Makefile.gcc	Wed Jan  3 15:30:20 1990
***************
*** 1,6 ****
  # Makefile for xloadimage using GNU C compiler
  #
! # Copyright 1989 Jim Frost
  #
  # See file "copyright.h" for complete copyright information.
  
--- 1,6 ----
  # Makefile for xloadimage using GNU C compiler
  #
! # Copyright 1989, 1990 Jim Frost
  #
  # See file "copyright.h" for complete copyright information.
  
***************
*** 8,14 ****
  CFLAGS= -O -fstrength-reduce -finline-functions -DSYSPATHFILE=\"/usr/lib/xloadimagerc\"
  
  LIBS= -lX11
! OBJS= bright.o clip.o compress.o dither.o faces.o fill.o \
        halftone.o imagetypes.o merge.o misc.o new.o options.o path.o \
        pbm.o reduce.o root.o send.o sunraster.o value.o window.o \
        xbitmap.o xloadimage.o xpixmap.o zio.o zoom.o
--- 8,14 ----
  CFLAGS= -O -fstrength-reduce -finline-functions -DSYSPATHFILE=\"/usr/lib/xloadimagerc\"
  
  LIBS= -lX11
! OBJS= bright.o clip.o compress.o dither.o faces.o fill.o gif.o \
        halftone.o imagetypes.o merge.o misc.o new.o options.o path.o \
        pbm.o reduce.o root.o send.o sunraster.o value.o window.o \
        xbitmap.o xloadimage.o xpixmap.o zio.o zoom.o
diff -c xloadimage.02/Makefile.std xloadimage.03/Makefile.std
*** xloadimage.02/Makefile.std	Sun Dec 31 16:03:10 1989
--- xloadimage.03/Makefile.std	Wed Jan  3 15:30:10 1990
***************
*** 1,6 ****
  # Makefile for xloadimage using standard C compiler
  #
! # Copyright 1989 Jim Frost
  #
  # See file "copyright.h" for complete copyright information.
  
--- 1,6 ----
  # Makefile for xloadimage using standard C compiler
  #
! # Copyright 1989, 1990 Jim Frost
  #
  # See file "copyright.h" for complete copyright information.
  
***************
*** 8,14 ****
  CFLAGS= -O -DSYSPATHFILE=\"/usr/lib/xloadimagerc\"
  
  LIBS= -lX11
! OBJS= bright.o clip.o compress.o dither.o faces.o fill.o \
        halftone.o imagetypes.o merge.o misc.o new.o options.o path.o \
        pbm.o reduce.o root.o send.o sunraster.o value.o window.o \
        xbitmap.o xloadimage.o xpixmap.o zio.o zoom.o
--- 8,14 ----
  CFLAGS= -O -DSYSPATHFILE=\"/usr/lib/xloadimagerc\"
  
  LIBS= -lX11
! OBJS= bright.o clip.o compress.o dither.o faces.o fill.o gif.o \
        halftone.o imagetypes.o merge.o misc.o new.o options.o path.o \
        pbm.o reduce.o root.o send.o sunraster.o value.o window.o \
        xbitmap.o xloadimage.o xpixmap.o zio.o zoom.o
diff -c xloadimage.02/README xloadimage.03/README
*** xloadimage.02/README	Sun Dec 31 16:03:16 1989
--- xloadimage.03/README	Wed Jan  3 12:41:10 1990
***************
*** 3,41 ****
  WHAT IS IT?
  
  This utility will view several types of images under X11, or load
! images onto the root window.  The current version supports X11 Bitmap,
! Portable Bitmap, Faces Project, and Sun Rasterfile images.  More are
! planned.
  
  A variety of options are available to modify images prior to viewing.
  These options include clipping, dithering, depth reduction, zoom
! (either X or Y axis independently or both at once),
! brightening/darkening, and image merging.  When applicable, these
! options are done automatically (eg a color image to be displayed on a
! monochrome screen will be dithered automatically).
  
- IMPLEMENTATION
- 
- Most functions are not particularly fast, and some functions use
- simple-minded algorithms deliberately over more advanced ones.  I
- stressed portability over all and simplicity over performance.  I
- believe the result is a usable, portable tool which should serve the
- needs of most users.
- 
- The source code is basically in two parts: image manipulation routines
- and everything else.  The image manipulation routines should be
- completely independent of X, thus allowing people to use them under
- other graphical systems.  No guarantees here, but I tried.
- 
- Performance-oriented people will notice that when loading a color
- image, the colormap of the image is minimized (and all pixel values in
- the image changed), then the colormap is redone (and all pixel values
- in the image changed again) before sending to X.  This could be
- reduced to only one remapping of the image but I wanted to keep the
- image from X's grubby (greedy?) hands as long as possible, and the
- image merging function really wants the image to have a minimized
- colormap.
- 
  COMPILING
  
  There are three ways to compile xloadimage, depending on what
--- 3,24 ----
  WHAT IS IT?
  
  This utility will view several types of images under X11, or load
! images onto the root window.  The current version supports:
  
+ 	Faces Project
+ 	GIF
+ 	Portable Bitmap (PBM)
+ 	Sun Rasterfile
+ 	X11 Bitmap
+ 	X Pixmap
+ 
  A variety of options are available to modify images prior to viewing.
  These options include clipping, dithering, depth reduction, zoom
! (either X or Y axis independently or both at once), brightening or
! darkening, and image merging.  When applicable, these options are done
! automatically (eg a color image to be displayed on a monochrome screen
! will be dithered automatically).
  
  COMPILING
  
  There are three ways to compile xloadimage, depending on what
***************
*** 59,71 ****
  After compiling and installing xloadimage, I recommend linking or
  symlinking to the executable with the names "xview" and "xsetbg".  The
  default behavior is slightly different when invoked with these
! commands (they're also easier to type).
  
  OWNERSHIP
  
! I used the MIT X Consortium copyright with all of these functions,
! thereby allowing full freedom with the code so long as the copyright
! notices remain intact.  Free code can be good code.
  
  SUGGESTIONS AND BUG REPORTS
  
--- 42,80 ----
  After compiling and installing xloadimage, I recommend linking or
  symlinking to the executable with the names "xview" and "xsetbg".  The
  default behavior is slightly different when invoked with these
! commands (they're also easier to type).  If you have a public image
! area you should consider setting the SYSPATHFILE option in the
! makefile and setting up a system-wide configuration file.  See the man
! page for information on the format of this file.
  
+ IMPLEMENTATION
+ 
+ Most functions are not particularly fast, and some functions use
+ simple-minded algorithms deliberately over more advanced ones.  I
+ stressed portability over all and simplicity over performance.  I
+ believe the result is a usable, portable tool which should serve the
+ needs of most users.
+ 
+ The source code is basically in two parts: image manipulation routines
+ and everything else.  The image manipulation routines should be
+ completely independent of X, thus allowing people to use them under
+ other graphical systems.  No guarantees here, but I tried.
+ 
+ Performance-oriented people will notice that when loading a color
+ image, the colormap of the image is minimized (and all pixel values in
+ the image changed), then the colormap is redone (and all pixel values
+ in the image changed again) before sending to X.  This could be
+ reduced to only one remapping of the image but I wanted to keep the
+ image from X's grubby (greedy?) hands as long as possible, and the
+ image merging function really wants the image to have a minimized
+ colormap.
+ 
  OWNERSHIP
  
! I used a modified version of the MIT X Consortium copyright with all
! of these functions, thereby allowing full freedom with the code so
! long as the copyright notices remain intact.  Free code can be good
! code.  All contributions have similar notices.
  
  SUGGESTIONS AND BUG REPORTS
  
***************
*** 72,91 ****
  Suggestions and bug reports should go to:
  
  	Jim Frost
! 	madd@std.com
! 	..uunet!world!madd
  
  Please include the version number and sample image data if you are
  reporting a bug.
  
  Functions implementing new image types are welcomed; mail them to the
! same address and I'll do my best to distribute them.
  
  THANKS
  
  Special thanks to the crew at the Boston University Graphics Lab for
  their assistance and sample images, and to bzs@std.com for his simple
! dithering algorithm (or what's left of it).
  
  HISTORY
  
--- 81,108 ----
  Suggestions and bug reports should go to:
  
  	Jim Frost
! 	jimf@saber.com
! 	..harvard!saber!jimf
  
  Please include the version number and sample image data if you are
  reporting a bug.
  
  Functions implementing new image types are welcomed; mail them to the
! same address and I'll do my best to distribute them.  Try do send them
! as public domain so I can keep the number of differing copyright
! messages to a minimum -- I'll use my standard message and leave the
! implementor's name and information in the file for credit.  I wouldn't
! copyright this stuff at all except that it's a requirement for X11
! distribution.
  
  THANKS
  
  Special thanks to the crew at the Boston University Graphics Lab for
  their assistance and sample images, and to bzs@std.com for his simple
! dithering algorithm (or what's left of it).  Real special thanks to
! Kirk L. Johnson (tuna@athena.mit.edu) for a very nice GIF loader, and
! to Mark Snitily (zok!mark@apple.com) for 386/ix compatibility work and
! miscellaneous bug-tracking.
  
  HISTORY
  
***************
*** 103,105 ****
--- 120,132 ----
  the image up (with the old one moved to halftone.c), and a bug fix to
  zoom.c to correct problems when zooming bitmaps.
  
+ Patch 03 contained a new loader for GIF files.  The dither bits array
+ in dither.c was changed so it worked properly, and both dither.c and
+ halftone.c had minor bugs fixed.  Merge.c was modified to correct bugs
+ when merging RGB images.  Pbm.c was modified to handle raw format
+ images.  Root.c was modified to deny image loads which would change
+ the root window's colormap.  Send.c was modified to use shared colors
+ whenever possible and to handle color displays which have depths which
+ are not a multiple of 8.  Window.c was modified to avoid deleting the
+ default colormap, allowing proper operation on some servers prior to
+ X11R3 patchlevel 08.  There were many miscellaneous bug fixes.
diff -c xloadimage.02/bright.c xloadimage.03/bright.c
*** xloadimage.02/bright.c	Mon Nov  6 10:51:07 1989
--- xloadimage.03/bright.c	Wed Dec  6 14:54:17 1989
***************
*** 13,19 ****
  
  void brighten(image, percent, verbose)
       Image        *image;
!      int           percent;
       unsigned int  verbose;
  { int          a;
    unsigned int newrgb;
--- 13,19 ----
  
  void brighten(image, percent, verbose)
       Image        *image;
!      unsigned int  percent;
       unsigned int  verbose;
  { int          a;
    unsigned int newrgb;
diff -c xloadimage.02/compress.c xloadimage.03/compress.c
*** xloadimage.02/compress.c	Mon Nov  6 10:51:09 1989
--- xloadimage.03/compress.c	Wed Jan  3 15:31:07 1990
***************
*** 4,11 ****
   *
   * jim frost 10.05.89
   *
!  * Copyright 1989 Jim Frost.  See included file "copyright.h" for complete
!  * copyright information.
   */
  
  #include "copyright.h"
--- 4,11 ----
   *
   * jim frost 10.05.89
   *
!  * Copyright 1989, 1990 Jim Frost.  See included file "copyright.h" for
!  * complete copyright information.
   */
  
  #include "copyright.h"
diff -c xloadimage.02/copyright.h xloadimage.03/copyright.h
*** xloadimage.02/copyright.h	Mon Nov  6 10:51:10 1989
--- xloadimage.03/copyright.h	Wed Jan  3 15:36:59 1990
***************
*** 1,6 ****
  #ifndef _JIM_COPYRIGHT_
  /*
!  * Copyright 1989 Jim Frost
   *
   * Permission to use, copy, modify, distribute, and sell this software
   * and its documentation for any purpose is hereby granted without fee,
--- 1,6 ----
  #ifndef _JIM_COPYRIGHT_
  /*
!  * Copyright 1989, 1990 Jim Frost
   *
   * Permission to use, copy, modify, distribute, and sell this software
   * and its documentation for any purpose is hereby granted without fee,
diff -c xloadimage.02/dither.c xloadimage.03/dither.c
*** xloadimage.02/dither.c	Sun Dec 31 16:03:11 1989
--- xloadimage.03/dither.c	Wed Jan  3 15:31:22 1990
***************
*** 7,13 ****
   * jim frost 07.10.89
   * Steve Losen 11.17.89
   *
!  * Copyright 1989 Jim Frost and Steve Losen.  See included file
   * "copyright.h" for complete copyright information.
   */
  
--- 7,13 ----
   * jim frost 07.10.89
   * Steve Losen 11.17.89
   *
!  * Copyright 1989, 1990 Jim Frost and Steve Losen.  See included file
   * "copyright.h" for complete copyright information.
   */
  
***************
*** 22,42 ****
  
  static byte DitherBits[GRAYS][4] = {
    0xf, 0xf, 0xf, 0xf,
!   0xf, 0xf, 0xf, 0x7,
!   0xf, 0xf, 0xf, 0x3,
!   0xf, 0xf, 0x7, 0x3,
!   0xf, 0xf, 0x3, 0x3,
!   0xf, 0xf, 0x3, 0x1,
!   0xf, 0x7, 0x3, 0x1,
!   0xf, 0x7, 0x1, 0x1,
!   0x7, 0x7, 0x3, 0x0,
!   0x7, 0x7, 0x1, 0x0,
!   0x7, 0x3, 0x1, 0x0,
!   0x7, 0x3, 0x0, 0x0,
!   0x3, 0x3, 0x0, 0x0,
!   0x3, 0x1, 0x0, 0x0,
!   0x3, 0x0, 0x0, 0x0,
!   0x1, 0x0, 0x0, 0x0,
    0x0, 0x0, 0x0, 0x0
  };
  
--- 22,42 ----
  
  static byte DitherBits[GRAYS][4] = {
    0xf, 0xf, 0xf, 0xf,
!   0xe, 0xf, 0xf, 0xf,
!   0xe, 0xf, 0xb, 0xf,
!   0xa, 0xf, 0xb, 0xf,
!   0xa, 0xf, 0xa, 0xf,
!   0xa, 0xd, 0xa, 0xf,
!   0xa, 0xd, 0xa, 0x7,
!   0xa, 0x5, 0xa, 0x7,
!   0xa, 0x5, 0xa, 0x5,
!   0x8, 0x5, 0xa, 0x5,
!   0x8, 0x5, 0x2, 0x5,
!   0x0, 0x5, 0x2, 0x5,
!   0x0, 0x5, 0x0, 0x5,
!   0x0, 0x4, 0x0, 0x5,
!   0x0, 0x4, 0x0, 0x1,
!   0x0, 0x0, 0x0, 0x1,
    0x0, 0x0, 0x0, 0x0
  };
  
***************
*** 47,59 ****
       Image        *cimage;
       unsigned int  verbose;
  { Image         *image;
!   unsigned char *sp, *dp, *dp2; /* data pointers */
!   unsigned int   dindex;        /* index into dither array */
!   unsigned int   spl;           /* source pixel length in bytes */
!   unsigned int   dll;           /* destination line length in bytes */
!   Pixel          color;         /* pixel color */
!   unsigned int  *index;         /* index into dither array for a given pixel */
!   unsigned int   a, x, y;       /* random counters */
  
    goodImage(cimage, "dither");
    if (! RGBP(cimage))
--- 47,59 ----
       Image        *cimage;
       unsigned int  verbose;
  { Image         *image;
!   unsigned char *sp, *dp; /* data pointers */
!   unsigned int   dindex;  /* index into dither array */
!   unsigned int   spl;     /* source pixel length in bytes */
!   unsigned int   dll;     /* destination line length in bytes */
!   Pixel          color;   /* pixel color */
!   unsigned int  *index;   /* index into dither array for a given pixel */
!   unsigned int   x, y;    /* random counters */
  
    goodImage(cimage, "dither");
    if (! RGBP(cimage))
***************
*** 84,94 ****
  
    if (cimage->depth <= 16) {
      index= (unsigned int *)malloc(sizeof(unsigned int) * cimage->rgb.used);
!     for (x= 0; x < cimage->rgb.used; x++)
        *(index + x)=
  	((unsigned long)(*(cimage->rgb.red + x)) +
  	 *(cimage->rgb.green + x) +
  	 *(cimage->rgb.blue + x)) / GRAYSTEP;
    }
    else
      index= NULL;
--- 84,97 ----
  
    if (cimage->depth <= 16) {
      index= (unsigned int *)malloc(sizeof(unsigned int) * cimage->rgb.used);
!     for (x= 0; x < cimage->rgb.used; x++) {
        *(index + x)=
  	((unsigned long)(*(cimage->rgb.red + x)) +
  	 *(cimage->rgb.green + x) +
  	 *(cimage->rgb.blue + x)) / GRAYSTEP;
+       if (*(index + x) >= GRAYS)
+ 	*(index + x)= GRAYS - 1;
+     }
    }
    else
      index= NULL;
***************
*** 103,112 ****
        color= memToVal(sp, spl);
        if (index)
  	dindex= *(index + color);
!       else
  	dindex= ((unsigned long)(*(cimage->rgb.red + color)) +
  		 *(cimage->rgb.green + color) +
  		 *(cimage->rgb.blue + color)) / GRAYSTEP;
        if (DitherBits[dindex][y & 3] & (1 << (x & 3)))
  	 dp[x / 8] |= 1 << (7 - (x & 7));
        sp += spl;
--- 106,118 ----
        color= memToVal(sp, spl);
        if (index)
  	dindex= *(index + color);
!       else {
  	dindex= ((unsigned long)(*(cimage->rgb.red + color)) +
  		 *(cimage->rgb.green + color) +
  		 *(cimage->rgb.blue + color)) / GRAYSTEP;
+ 	if (dindex >= GRAYS)
+ 	  dindex= GRAYS - 1;
+       }
        if (DitherBits[dindex][y & 3] & (1 << (x & 3)))
  	 dp[x / 8] |= 1 << (7 - (x & 7));
        sp += spl;
Only in xloadimage.03: gif.c
Only in xloadimage.03: gif.h
diff -c xloadimage.02/halftone.c xloadimage.03/halftone.c
*** xloadimage.02/halftone.c	Sun Dec 31 16:01:50 1989
--- xloadimage.03/halftone.c	Wed Jan  3 15:36:35 1990
***************
*** 6,13 ****
   *
   * jim frost 07.10.89
   *
!  * Copyright 1989 Jim Frost.  See included file "copyright.h" for complete
!  * copyright information.
   */
  
  #include "copyright.h"
--- 6,13 ----
   *
   * jim frost 07.10.89
   *
!  * Copyright 1989, 1990 Jim Frost.  See included file "copyright.h" for
!  * complete copyright information.
   */
  
  #include "copyright.h"
***************
*** 62,68 ****
     */
  
    if (verbose) {
!     printf("  Dithering image...");
      fflush(stdout);
    }
    image= newBitImage(cimage->width * 4, cimage->height * 4);
--- 62,68 ----
     */
  
    if (verbose) {
!     printf("  Halftoning image...");
      fflush(stdout);
    }
    image= newBitImage(cimage->width * 4, cimage->height * 4);
***************
*** 83,93 ****
  
    if (cimage->depth <= 16) {
      index= (unsigned int *)malloc(sizeof(unsigned int) * cimage->rgb.used);
!     for (x= 0; x < cimage->rgb.used; x++)
        *(index + x)=
  	((unsigned long)(*(cimage->rgb.red + x)) +
  	 *(cimage->rgb.green + x) +
  	 *(cimage->rgb.blue + x)) / GRAYSTEP;
    }
    else
      index= NULL;
--- 83,96 ----
  
    if (cimage->depth <= 16) {
      index= (unsigned int *)malloc(sizeof(unsigned int) * cimage->rgb.used);
!     for (x= 0; x < cimage->rgb.used; x++) {
        *(index + x)=
  	((unsigned long)(*(cimage->rgb.red + x)) +
  	 *(cimage->rgb.green + x) +
  	 *(cimage->rgb.blue + x)) / GRAYSTEP;
+       if (*(index + x) >= GRAYS) /* rounding errors can do this */
+ 	*(index + x)= GRAYS - 1;
+     }
    }
    else
      index= NULL;
***************
*** 103,112 ****
        color= memToVal(sp, spl);
        if (index)
  	dindex= *(index + color);
!       else
  	dindex= ((unsigned long)(*(cimage->rgb.red + color)) +
  		 *(cimage->rgb.green + color) +
  		 *(cimage->rgb.blue + color)) / GRAYSTEP;
  
        /* loop for the four Y bits in the dither pattern, putting all
         * four X bits in at once.  if you think this would be hard to
--- 106,118 ----
        color= memToVal(sp, spl);
        if (index)
  	dindex= *(index + color);
!       else {
  	dindex= ((unsigned long)(*(cimage->rgb.red + color)) +
  		 *(cimage->rgb.green + color) +
  		 *(cimage->rgb.blue + color)) / GRAYSTEP;
+ 	if (dindex >= GRAYS) /* rounding errors can do this */
+ 	  dindex= GRAYS - 1;
+       }
  
        /* loop for the four Y bits in the dither pattern, putting all
         * four X bits in at once.  if you think this would be hard to
diff -c xloadimage.02/image.h xloadimage.03/image.h
*** xloadimage.02/image.h	Sun Dec 31 16:03:11 1989
--- xloadimage.03/image.h	Wed Dec  6 15:12:34 1989
***************
*** 56,63 ****
--- 56,69 ----
  
  Image *clip(); /* clip.c */
  
+ void brighten(); /* bright.c */
+ 
+ void compress(); /* compress.c */
+ 
  Image *dither(); /* dither.c */
  
+ void fill(); /* fill.c */
+ 
  void fold(); /* fold.c */
  
  Image *halftone(); /* halftone.c */
***************
*** 66,72 ****
  void   identifyImage();
  void   goodImage();
  
! Image *mergeImages(); /* merge.c */
  
  char  *dupString(); /* new.c */
  Image *newBitImage();
--- 72,78 ----
  void   identifyImage();
  void   goodImage();
  
! void merge(); /* merge.c */
  
  char  *dupString(); /* new.c */
  Image *newBitImage();
***************
*** 82,90 ****
--- 88,100 ----
  void reduceRGBMap(); /* reduce.c */
  void reduce();
  
+ void imageOnRoot(); /* root.c */
+ 
  unsigned long memToVal(); /* value.c */
  void          valToMem();
  unsigned long memToValLSB();
  void          valToMemLSB();
+ 
+ void imageInWindow(); /* window.c */
  
  Image *zoom(); /* zoom.c */
diff -c xloadimage.02/imagetypes.h xloadimage.03/imagetypes.h
*** xloadimage.02/imagetypes.h	Sun Dec 31 16:03:12 1989
--- xloadimage.03/imagetypes.h	Wed Dec 13 15:21:36 1989
***************
*** 10,15 ****
--- 10,16 ----
  Image *facesLoad();
  Image *pbmLoad();
  Image *sunRasterLoad();
+ Image *gifLoad();
  Image *xbitmapLoad();
  Image *xpixmapLoad();
  
***************
*** 16,21 ****
--- 17,23 ----
  int facesIdent();
  int pbmIdent();
  int sunRasterIdent();
+ int gifIdent();
  int xbitmapIdent();
  int xpixmapIdent();
  
***************
*** 30,35 ****
--- 32,38 ----
    sunRasterIdent, sunRasterLoad, "Sun Rasterfile",
    pbmIdent,       pbmLoad,       "Portable Bit Map (PBM)",
    facesIdent,     facesLoad,     "Faces Project",
+   gifIdent,       gifLoad,       "GIF Image",
    xpixmapIdent,   xpixmapLoad,   "X Pixmap",
    xbitmapIdent,   xbitmapLoad,   "X Bitmap",
    NULL,           NULL,          NULL
Only in xloadimage.03: kljcpyrght.h
diff -c xloadimage.02/merge.c xloadimage.03/merge.c
*** xloadimage.02/merge.c	Mon Nov  6 10:51:20 1989
--- xloadimage.03/merge.c	Wed Jan  3 15:32:16 1990
***************
*** 4,11 ****
   *
   * jim frost 09.27.89
   *
!  * Copyright 1989 Jim Frost.  See included file "copyright.h" for complete
!  * copyright information.
   */
  
  #include "copyright.h"
--- 4,11 ----
   *
   * jim frost 09.27.89
   *
!  * Copyright 1989, 1990 Jim Frost.  See included file "copyright.h" for
!  * complete copyright information.
   */
  
  #include "copyright.h"
***************
*** 20,38 ****
    if (dest->rgb.used + src->rgb.used > dest->rgb.size) {
      newRGBMapData(&newcolors, dest->rgb.used + src->rgb.used);
      newcolors.used= newcolors.size;
!     for (a= 0, b= 0; a < dest->rgb.used; a++, b++) {
!       *(newcolors.red + b)= *(dest->rgb.red + a);
!       *(newcolors.green + b)= *(dest->rgb.green + a);
!       *(newcolors.blue + b)= *(dest->rgb.blue + a);
      }
!     for (b= 0; a < src->rgb.used; a++, b++) {
!       *(newcolors.red + b)= *(src->rgb.red + a);
!       *(newcolors.green + b)= *(src->rgb.green + a);
!       *(newcolors.blue + b)= *(src->rgb.blue + a);
      }
  
      reduceRGBMap(&newcolors, dest->rgb.size, verbose);
-     dest->rgb.used= dest->rgb.size;
      
      for (a= 0; a < dest->rgb.used; a++) {             /* put new colors into */
        *(dest->rgb.red + a)= *(newcolors.red + a);     /* old colormaps */
--- 20,37 ----
    if (dest->rgb.used + src->rgb.used > dest->rgb.size) {
      newRGBMapData(&newcolors, dest->rgb.used + src->rgb.used);
      newcolors.used= newcolors.size;
!     for (a= 0; a < dest->rgb.used; a++) {
!       *(newcolors.red + a)= *(dest->rgb.red + a);
!       *(newcolors.green + a)= *(dest->rgb.green + a);
!       *(newcolors.blue + a)= *(dest->rgb.blue + a);
      }
!     for (b= 0; b < src->rgb.used; a++, b++) {
!       *(newcolors.red + a)= *(src->rgb.red + b);
!       *(newcolors.green + a)= *(src->rgb.green + b);
!       *(newcolors.blue + a)= *(src->rgb.blue + b);
      }
  
      reduceRGBMap(&newcolors, dest->rgb.size, verbose);
      
      for (a= 0; a < dest->rgb.used; a++) {             /* put new colors into */
        *(dest->rgb.red + a)= *(newcolors.red + a);     /* old colormaps */
***************
*** 44,50 ****
        *(src->rgb.green + a)= *(newcolors.green + a + dest->rgb.used);
        *(src->rgb.blue + a)= *(newcolors.blue + a + dest->rgb.used);
      }
-     freeRGBMapData(&newcolors);
    }
    else
      for (a= 0; a < src->rgb.used; a++, (dest->rgb.used)++) {
--- 43,48 ----
***************
*** 136,142 ****
    unsigned int  x, y;
    byte         *destline, *srcline;
    byte         *destpixel, *srcpixel;
!   byte          srcstartmask, srcmask;
  
    if (verbose) {
      printf("  Merging bitmap image onto RGB image...");
--- 134,140 ----
    unsigned int  x, y;
    byte         *destline, *srcline;
    byte         *destpixel, *srcpixel;
!   byte          srcmask;
  
    if (verbose) {
      printf("  Merging bitmap image onto RGB image...");
***************
*** 219,232 ****
    for (x= 0; x < src->rgb.used; x++) {
      for (y= 0; y < dest->rgb.used; y++)
        if ((*(dest->rgb.red + y) == *(src->rgb.red + x)) &&
! 	  (*(dest->rgb.red + y) == *(src->rgb.red + x)) &&
! 	  (*(dest->rgb.red + y) == *(src->rgb.red + x))) {
  	*(index + x)= y;
  	break;
        }
      if (y == dest->rgb.used)
!       printf("merge: warning: Can't map source pixel %d to destination\n",
! 	     x);
    }
  
    destlinelen= dest->width * dest->pixlen;
--- 217,239 ----
    for (x= 0; x < src->rgb.used; x++) {
      for (y= 0; y < dest->rgb.used; y++)
        if ((*(dest->rgb.red + y) == *(src->rgb.red + x)) &&
! 	  (*(dest->rgb.green + y) == *(src->rgb.green + x)) &&
! 	  (*(dest->rgb.blue + y) == *(src->rgb.blue + x))) {
  	*(index + x)= y;
  	break;
        }
      if (y == dest->rgb.used)
!       if (y < dest->rgb.size) {
! 	*(dest->rgb.red + y)= *(src->rgb.red + x);
! 	*(dest->rgb.green + y)= *(src->rgb.green + x);
! 	*(dest->rgb.blue + y)= *(src->rgb.blue + x);
! 	*(index + x)= y;
! 	dest->rgb.used++;
!       }
!       else {
! 	printf("merge: warning: To few colors in destination colormap?!?\n");
! 	*(index + x)= 0;
!       }
    }
  
    destlinelen= dest->width * dest->pixlen;
***************
*** 290,302 ****
      cliph -= (dest->width - (aty + cliph));
  
    if (BITMAPP(dest) && (BITMAPP(src) || RGBP(src)))
!     bitmapToBitmap(src, dest, atx, aty, clipw, cliph, verbose);
    else {
      mergeColors(dest, src, verbose);
      if (RGBP(dest) && BITMAPP(src))
!       bitmapToRGB(src, dest, atx, aty, clipw, cliph, verbose);
      else if (RGBP(dest) && RGBP(src))
!       RGBToRGB(src, dest, atx, aty, clipw, cliph, verbose);
      else {
        printf("merge: Can't merge these two types of images (sorry)\n");
        exit(1);
--- 297,312 ----
      cliph -= (dest->width - (aty + cliph));
  
    if (BITMAPP(dest) && (BITMAPP(src) || RGBP(src)))
!     bitmapToBitmap(src, dest, (unsigned int)atx, (unsigned int)aty,
! 		   clipw, cliph, verbose);
    else {
      mergeColors(dest, src, verbose);
      if (RGBP(dest) && BITMAPP(src))
!       bitmapToRGB(src, dest, (unsigned int)atx, (unsigned int)aty,
! 		  clipw, cliph, verbose);
      else if (RGBP(dest) && RGBP(src))
!       RGBToRGB(src, dest, (unsigned int)atx, (unsigned int)aty,
! 	       clipw, cliph, verbose);
      else {
        printf("merge: Can't merge these two types of images (sorry)\n");
        exit(1);
diff -c xloadimage.02/misc.c xloadimage.03/misc.c
*** xloadimage.02/misc.c	Sun Dec 31 16:03:12 1989
--- xloadimage.03/misc.c	Wed Jan  3 15:32:37 1990
***************
*** 4,11 ****
   *
   * jim frost 10.05.89
   *
!  * Copyright 1989 Jim Frost.  See included file "copyright.h" for complete
!  * copyright information.
   */
  
  #include "copyright.h"
--- 4,11 ----
   *
   * jim frost 10.05.89
   *
!  * Copyright 1989, 1990 Jim Frost.  See included file "copyright.h" for
!  * complete copyright information.
   */
  
  #include "copyright.h"
***************
*** 29,34 ****
--- 29,35 ----
    printf("  -quiet                - silence is golden\n");
    printf("  -supported            - show supported image types\n");
    printf("  -verbose              - whistle while you work\n");
+   printf("  -version              - show version and patchlevel\n");
    printf("  -view                 - view image in a window\n");
    printf("Image_options:\n");
    printf("  -at X,Y               - load image at location\n");
***************
*** 69,75 ****
    XColor        xcolor;
    unsigned int  compressed= 0;
  
!   goodImage(image);
  
    /* clip the image if requested
     */
--- 70,76 ----
    XColor        xcolor;
    unsigned int  compressed= 0;
  
!   goodImage(image, "processImage");
  
    /* clip the image if requested
     */
***************
*** 149,154 ****
--- 150,156 ----
   * was issued.
   */
  
+ /* ARGSUSED */
  int ioErrorHandler(disp)
       Display *disp;
  {
diff -c xloadimage.02/new.c xloadimage.03/new.c
*** xloadimage.02/new.c	Mon Nov  6 10:51:35 1989
--- xloadimage.03/new.c	Wed Dec  6 14:56:08 1989
***************
*** 49,55 ****
    image= (Image *)lmalloc(sizeof(Image));
    image->type= IBITMAP;
    image->title= NULL;
!   newRGBMapData(&(image->rgb), 2);
    *(image->rgb.red)= *(image->rgb.green)= *(image->rgb.blue)= 65535;
    *(image->rgb.red + 1)= *(image->rgb.green + 1)= *(image->rgb.blue + 1)= 0;
    image->rgb.used= 2;
--- 49,55 ----
    image= (Image *)lmalloc(sizeof(Image));
    image->type= IBITMAP;
    image->title= NULL;
!   newRGBMapData(&(image->rgb), (unsigned int)2);
    *(image->rgb.red)= *(image->rgb.green)= *(image->rgb.blue)= 65535;
    *(image->rgb.red + 1)= *(image->rgb.green + 1)= *(image->rgb.blue + 1)= 0;
    image->rgb.used= 2;
diff -c xloadimage.02/patchlevel xloadimage.03/patchlevel
*** xloadimage.02/patchlevel	Sun Dec 31 16:03:17 1989
--- xloadimage.03/patchlevel	Wed Jan  3 14:37:02 1990
***************
*** 1 ****
! PATCHLEVEL 02
--- 1,5 ----
! /* this defines the version and patchlevel of this version of xloadimage
!  */
! 
! #define VERSION    "1"
! #define PATCHLEVEL "03"
diff -c xloadimage.02/path.c xloadimage.03/path.c
*** xloadimage.02/path.c	Mon Nov  6 10:51:38 1989
--- xloadimage.03/path.c	Wed Jan  3 15:33:01 1990
***************
*** 4,11 ****
   *
   * jim frost 10.03.89
   *
!  * Copyright 1989 Jim Frost.  See included file "copyright.h" for complete
!  * copyright information.
   */
  
  #include "copyright.h"
--- 4,11 ----
   *
   * jim frost 10.03.89
   *
!  * Copyright 1989, 1990 Jim Frost.  See included file "copyright.h" for
!  * complete copyright information.
   */
  
  #include "copyright.h"
***************
*** 13,18 ****
--- 13,19 ----
  #include <sys/file.h>
  #include <sys/types.h>
  #include <sys/stat.h>
+ #include <unistd.h>
  #include <pwd.h>
  #include <errno.h>
  
***************
*** 62,73 ****
  
      if (!strncmp(tokenbuf, PathToken, strlen(PathToken))) {
        secnum= PATHSECTION;
!       if (sscanf(tokenbuf + strlen(PathToken), "%s", buf) == 0)
  	continue;
      }
      else if (!strncmp(tokenbuf, ExtToken, strlen(ExtToken))) {
        secnum= EXTSECTION;
!       if (sscanf(tokenbuf + strlen(ExtToken), "%s", buf) == 0)
  	continue;
      }
      else
--- 63,74 ----
  
      if (!strncmp(tokenbuf, PathToken, strlen(PathToken))) {
        secnum= PATHSECTION;
!       if (sscanf(tokenbuf + strlen(PathToken), "%s", buf) != 1)
  	continue;
      }
      else if (!strncmp(tokenbuf, ExtToken, strlen(ExtToken))) {
        secnum= EXTSECTION;
!       if (sscanf(tokenbuf + strlen(ExtToken), "%s", buf) != 1)
  	continue;
      }
      else
***************
*** 110,124 ****
      return;
    havepaths= 1;
  
- #ifdef SYSPATHFILE
-   readPathsAndExts(SYSPATHFILE);
- #endif
    if (pw= getpwuid(getuid())) {
      sprintf(buf, "%s/.xloadimagerc", pw->pw_dir);
!     readPathsAndExts(buf);
    }
    else
      printf("Can't find your password file entry?!?\n");
  }
  
  /* find an image with paths and extensions from defaults files.  returns
--- 111,128 ----
      return;
    havepaths= 1;
  
    if (pw= getpwuid(getuid())) {
      sprintf(buf, "%s/.xloadimagerc", pw->pw_dir);
!     if (! access(buf, R_OK)) {
!       readPathsAndExts(buf);
!       return; /* don't read system file if user has one */
!     }
    }
    else
      printf("Can't find your password file entry?!?\n");
+ #ifdef SYSPATHFILE
+   readPathsAndExts(SYSPATHFILE);
+ #endif
  }
  
  /* find an image with paths and extensions from defaults files.  returns
diff -c xloadimage.02/pbm.c xloadimage.03/pbm.c
*** xloadimage.02/pbm.c	Mon Nov  6 10:51:39 1989
--- xloadimage.03/pbm.c	Wed Jan  3 15:34:04 1990
***************
*** 3,8 ****
--- 3,11 ----
   * portable bit map (pbm) format images
   *
   * jim frost 09.27.89
+  *
+  * patched by W. David Higgins (wdh@mkt.csd.harris.com) to support
+  * raw-format PBM files.
   */
  
  #include "xloadimage.h"
***************
*** 19,24 ****
--- 22,28 ----
  #define NOTPBM     1 /* not a pbm file */
  #define PBMNORMAL  2 /* pbm normal type file */
  #define PBMCOMPACT 3 /* pbm compacty type file */
+ #define PBMRAWBITS 4 /* pbm raw bits type file */
  
  static void initializeTable()
  { unsigned int a;
***************
*** 83,89 ****
  static int isPBM(zf, name, width, height, verbose)
       ZFILE        *zf;
       char         *name;
!      int          *width, *height;
       unsigned int  verbose;
  { unsigned char buf[4];
  
--- 87,93 ----
  static int isPBM(zf, name, width, height, verbose)
       ZFILE        *zf;
       char         *name;
!      unsigned int *width, *height;
       unsigned int  verbose;
  { unsigned char buf[4];
  
***************
*** 99,104 ****
--- 103,115 ----
        printf("%s is a %dx%d PBM image\n", name, *width, *height);
      return(PBMNORMAL);
    }
+   if (memToVal(buf, 2) == memToVal("P4", 2)) {
+     if (((*width= pbmReadInt(zf)) < 0) || ((*height= pbmReadInt(zf)) < 0))
+       return(NOTPBM);
+     if (verbose)
+       printf("%s is a %dx%d RawBits PBM image\n", name, *width, *height);
+     return(PBMRAWBITS);
+   }
    if (memToVal(buf, 2) == 0x2a17) {
      if (zread(zf, buf, 4) != 4)
        return(NOTPBM);
***************
*** 113,125 ****
  
  int pbmIdent(fullname, name)
       char *fullname, *name;
! { ZFILE *zf;
!   int    width, height, ret;
  
    if (! (zf= zopen(fullname, name)))
      return(0);
  
!   ret= isPBM(zf, name, &width, &height, 1);
    zclose(zf);
    return(ret != NOTPBM);
  }
--- 124,136 ----
  
  int pbmIdent(fullname, name)
       char *fullname, *name;
! { ZFILE        *zf;
!   unsigned int  width, height, ret;
  
    if (! (zf= zopen(fullname, name)))
      return(0);
  
!   ret= isPBM(zf, name, &width, &height, (unsigned int)1);
    zclose(zf);
    return(ret != NOTPBM);
  }
***************
*** 130,136 ****
  { ZFILE        *zf;
    Image        *image;
    unsigned int  x, y;
!   int           width, height;
    unsigned int  linelen;
    byte          srcmask, destmask;
    byte         *destptr, *destline;
--- 141,147 ----
  { ZFILE        *zf;
    Image        *image;
    unsigned int  x, y;
!   unsigned int  width, height;
    unsigned int  linelen;
    byte          srcmask, destmask;
    byte         *destptr, *destline;
***************
*** 185,190 ****
--- 196,241 ----
      }
      break;
  
+   case PBMRAWBITS:
+     image= newBitImage(width, height);
+     destline= image->data;
+     linelen= (width + 7) / 8;
+     numbytes= linelen * height;
+     srcmask= 0;		/* force initial read */
+     numread= 0;
+     for (y= 0; y < height; y++) {
+       destptr= destline;
+       destmask= 0x80;
+       if (srcmask != 0x80) {
+         srcmask= 0x80;
+ 	if ((numread < numbytes) && ((src= zgetc(zf)) == EOF)) {
+ 	   printf("%s: Short image\n", fullname);
+ 	   zclose(zf);
+ 	   exit(1);
+ 	}
+ 	numread++;
+       }
+       for (x= 0; x < width; x++) {
+ 	if (src & srcmask)
+ 	  *destptr |= destmask;
+ 	if (! (destmask >>= 1)) {
+ 	  destmask= 0x80;
+ 	  destptr++;
+ 	}
+ 	if (! (srcmask >>= 1)) {
+ 	  srcmask= 0x80;
+ 	  if ((numread < numbytes) && ((src= zgetc(zf)) == EOF)) {
+ 	    printf("%s: Short image\n", fullname);
+ 	    zclose(zf);
+ 	    exit(1);
+ 	  }
+ 	  numread++;
+ 	}
+       }
+       destline += linelen;
+     }
+     break;
+  
    case PBMCOMPACT:
      image= newBitImage(width, height);
      destline= image->data;
diff -c xloadimage.02/reduce.c xloadimage.03/reduce.c
*** xloadimage.02/reduce.c	Mon Nov  6 10:51:40 1989
--- xloadimage.03/reduce.c	Wed Jan  3 15:34:29 1990
***************
*** 4,11 ****
   *
   * jim frost 07.06.89
   *
!  * Copyright 1989 Jim Frost.  See included file "copyright.h" for complete
!  * copyright information.
   */
  
  #include "copyright.h"
--- 4,11 ----
   *
   * jim frost 07.06.89
   *
!  * Copyright 1989, 1990 Jim Frost.  See included file "copyright.h" for
!  * complete copyright information.
   */
  
  #include "copyright.h"
***************
*** 46,51 ****
--- 46,52 ----
    unsigned long qdist, bdist;
  
    bdist= 0xffffffff;
+   bcolor= 0;
    for (qcolor= color + 1; qcolor < rgb->used; qcolor++)
      if ((qdist= colorDistance(rgb, color, qcolor)) && (qdist < bdist)) {
        bdist= qdist;
***************
*** 56,63 ****
  }
  
  void reduceRGBMap(rgb, n, verbose)
!      RGBMap *rgb;
!      int     verbose;
  { unsigned int   numcolors;
    Pixel          a, b;
    Pixel          lowextreme, highextreme; /* intensity extremes */
--- 57,65 ----
  }
  
  void reduceRGBMap(rgb, n, verbose)
!      RGBMap       *rgb;
!      unsigned int  n;
!      unsigned int  verbose;
  { unsigned int   numcolors;
    Pixel          a, b;
    Pixel          lowextreme, highextreme; /* intensity extremes */
***************
*** 169,177 ****
  	*(best + a)= bestColor(rgb, a, dists + a);
    }
  
!   lfree(best);
!   lfree(dists);
!   lfree(same);
  
    if (verbose)
      printf("done\n");
--- 171,179 ----
  	*(best + a)= bestColor(rgb, a, dists + a);
    }
  
!   lfree((byte *)best);
!   lfree((byte *)dists);
!   lfree((byte *)same);
  
    if (verbose)
      printf("done\n");
***************
*** 182,188 ****
       unsigned int  n, verbose;
  { char buf[BUFSIZ];
  
!   goodImage(image);
    if (! RGBP(image)) /* we're AT&T */
      return;
    compress(image, verbose);
--- 184,190 ----
       unsigned int  n, verbose;
  { char buf[BUFSIZ];
  
!   goodImage(image, "reduce");
    if (! RGBP(image)) /* we're AT&T */
      return;
    compress(image, verbose);
***************
*** 189,194 ****
    reduceRGBMap(&(image->rgb), n, verbose);
    compress(image, verbose);
    sprintf(buf, "%s (%d colors)", image->title, image->rgb.used);
!   lfree(image->title);
    image->title= dupString(buf);
  }
--- 191,197 ----
    reduceRGBMap(&(image->rgb), n, verbose);
    compress(image, verbose);
    sprintf(buf, "%s (%d colors)", image->title, image->rgb.used);
!   if (image->title)
!     lfree((byte *)image->title);
    image->title= dupString(buf);
  }
diff -c xloadimage.02/root.c xloadimage.03/root.c
*** xloadimage.02/root.c	Mon Nov  6 10:51:42 1989
--- xloadimage.03/root.c	Wed Jan  3 15:34:57 1990
***************
*** 4,11 ****
   *
   * jim frost 10.03.89
   *
!  * Copyright 1989 Jim Frost.  See included file "copyright.h" for complete
!  * copyright information.
   */
  
  #include "copyright.h"
--- 4,11 ----
   *
   * jim frost 10.03.89
   *
!  * Copyright 1989, 1990 Jim Frost.  See included file "copyright.h" for
!  * complete copyright information.
   */
  
  #include "copyright.h"
***************
*** 23,34 ****
    if (! sendImageToX(disp, scrn, DefaultVisual(disp, scrn), image,
  		     &pixmap, &xcmap, verbose))
      exit(1);
    XSetWindowBackgroundPixmap(disp, RootWindow(disp, scrn), pixmap);
-   XSetWindowColormap(disp, RootWindow(disp, scrn), xcmap);
-   if (install)
-     XInstallColormap(disp, scrn, xcmap);
    XClearWindow(disp, RootWindow(disp, scrn));
-   XFreeColormap(disp, xcmap);
    XFreePixmap(disp, pixmap);
    XSetCloseDownMode(disp, RetainPermanent);
  }
--- 23,40 ----
    if (! sendImageToX(disp, scrn, DefaultVisual(disp, scrn), image,
  		     &pixmap, &xcmap, verbose))
      exit(1);
+ 
+   /* changing the root colormap is A Bad Thing, so deny it.
+    */
+ 
+   if (xcmap != DefaultColormap(disp, scrn)) {
+     printf("Loading image onto root would change default colormap (sorry)\n");
+     XFreePixmap(disp, pixmap);
+     exit(1);
+   }
+ 
    XSetWindowBackgroundPixmap(disp, RootWindow(disp, scrn), pixmap);
    XClearWindow(disp, RootWindow(disp, scrn));
    XFreePixmap(disp, pixmap);
    XSetCloseDownMode(disp, RetainPermanent);
  }
diff -c xloadimage.02/send.c xloadimage.03/send.c
*** xloadimage.02/send.c	Mon Nov  6 11:00:04 1989
--- xloadimage.03/send.c	Wed Jan  3 15:35:19 1990
***************
*** 4,11 ****
   *
   * jim frost 10.02.89
   *
!  * Copyright 1989 Jim Frost.  See included file "copyright.h" for complete
!  * copyright information.
   */
  
  #include "copyright.h"
--- 4,11 ----
   *
   * jim frost 10.02.89
   *
!  * Copyright 1989, 1990 Jim Frost.  See included file "copyright.h" for
!  * complete copyright information.
   */
  
  #include "copyright.h"
***************
*** 20,27 ****
       Colormap     *cmap;
       unsigned int  verbose;
  { Pixel        *index;
!   unsigned int  a, newmap, x, y;
!   byte         *pixptr;
    XColor        xcolor;
    XGCValues     gcv;
    GC            gc;
--- 20,28 ----
       Colormap     *cmap;
       unsigned int  verbose;
  { Pixel        *index;
!   unsigned int  a, b, newmap, x, y, linelen, ddepth;
!   unsigned long plane;
!   byte         *pixptr, *destline, *destptr, *bitplane, destmask;
    XColor        xcolor;
    XGCValues     gcv;
    GC            gc;
***************
*** 49,103 ****
    if (visual == DefaultVisual(disp, scrn)) {
      *cmap= DefaultColormap(disp, scrn);
      newmap= 0;
-   }
-   else {
-     if ((visual->class == PseudoColor) || (visual->class == GrayScale))
-       *cmap= XCreateColormap(disp, scrn, AllocNone);
-     else
-       *cmap= XCreateColormap(disp, scrn, AllocAll);
-     newmap= 1;
-   }
  
!   /* here's where we have fun; we try to build a reasonable colormap from
!    * whatever X will give us.  ugh.  blech.  gag.  puke.  barf.
!    */
  
-   if ((visual->class == PseudoColor) || (visual->class == GrayScale)) {
      for (a= 0; a < image->rgb.used; a++) {
!       if (! XAllocColorCells(disp, *cmap, False, NULL, 0, index + a, 1))
! 	if (newmap)
! 	  break;
  	else {
! 	  *cmap= XCopyColormapAndFree(disp, *cmap);
  	  newmap= 1;
! 	  a--;
  	}
      }
      if (a < image->rgb.used)     /* can't get enough colors, so reduce */
        reduce(image, a, verbose); /* the colormap to fit what we have */
!     for (a= 0; a < image->rgb.used; a++) {
!       xcolor.pixel= *(index + a);
!       xcolor.red= *(image->rgb.red + a);
!       xcolor.green= *(image->rgb.green + a);
!       xcolor.blue= *(image->rgb.blue + a);
        XStoreColor(disp, *cmap, &xcolor);
      }
    }
-   else if ((visual->class == StaticColor) || (visual->class == StaticGray)) {
-     for (a= 0; a < image->rgb.used; a++) {
-       xcolor.red= *(image->rgb.red + a);
-       xcolor.green= *(image->rgb.green + a);
-       xcolor.blue= *(image->rgb.blue + a);
-       if (! XAllocColor(disp, *cmap, &xcolor)) {
- 	printf("sendImageToX: XAllocColor failed on StaticGrey visual\n");
- 	return(0);
-       }
-       *(index + a)= xcolor.pixel;
-     }
-   }
  
    *pixmap= XCreatePixmap(disp, RootWindow(disp, scrn), image->width,
! 			 image->height, DefaultDepth(disp, scrn));
  
    /* blast the image across
     */
--- 50,113 ----
    if (visual == DefaultVisual(disp, scrn)) {
      *cmap= DefaultColormap(disp, scrn);
      newmap= 0;
  
!     /* allocate colors shareable (if we can)
!      */
  
      for (a= 0; a < image->rgb.used; a++) {
!       xcolor.red= *(image->rgb.red + a);
!       xcolor.green= *(image->rgb.green + a);
!       xcolor.blue= *(image->rgb.blue + a);
!       if (! XAllocColor(disp, *cmap, &xcolor))
! 	if ((visual->class == StaticColor) || (visual->class == StaticGray)) {
! 	  printf("sendImageToX: XAllocColor failed on a static visual\n");
! 	  return(0);
! 	}
  	else {
! 
! 	  /* we can't allocate the colors shareable so free all the colors
! 	   * we had allocated and create a private colormap
! 	   */
! 
! 	  for (b= 0; b < a; b++)
! 	    XFreeColors(disp, *cmap, index + b, 1, 0);
! 	  *cmap= XCreateColormap(disp, RootWindow(disp, scrn), visual,
! 				 AllocNone);
  	  newmap= 1;
! 	  break;
  	}
+       *(index + a)= xcolor.pixel;
      }
+   }
+   else {
+     if ((visual->class == PseudoColor) || (visual->class == GrayScale)) {
+       *cmap= XCreateColormap(disp, RootWindow(disp, scrn), AllocNone);
+     }
+     else
+       *cmap= XCreateColormap(disp, RootWindow(disp, scrn), AllocAll);
+     newmap= 1;
+   }
+ 
+   if (newmap) {
+     for (a= 0; a < image->rgb.used; a++) /* count entries we got */
+       if (! XAllocColorCells(disp, *cmap, False, NULL, 0, index + a, 1))
+ 	break;
+ 
      if (a < image->rgb.used)     /* can't get enough colors, so reduce */
        reduce(image, a, verbose); /* the colormap to fit what we have */
! 
!     for (b= 0; b < a; b++) {
!       xcolor.pixel= *(index + b);
!       xcolor.red= *(image->rgb.red + b);
!       xcolor.green= *(image->rgb.green + b);
!       xcolor.blue= *(image->rgb.blue + b);
        XStoreColor(disp, *cmap, &xcolor);
      }
    }
  
+   ddepth= DefaultDepth(disp, scrn);
    *pixmap= XCreatePixmap(disp, RootWindow(disp, scrn), image->width,
! 			 image->height, ddepth);
  
    /* blast the image across
     */
***************
*** 120,130 ****
  
    case IRGB:
  
!     /* modify pixel values to fit the colormap
       */
  
      if (verbose) {
!       printf("  Modifying image to conform to X colormap...");
        fflush(stdout);
      }
      pixptr= image->data;
--- 130,140 ----
  
    case IRGB:
  
!     /* modify image data to match colormap and pack pixels if necessary
       */
  
      if (verbose) {
!       printf("  Building XImage...");
        fflush(stdout);
      }
      pixptr= image->data;
***************
*** 134,145 ****
  		 pixptr, image->pixlen);
  	pixptr += image->pixlen;
        }
      if (verbose)
        printf("done\n");
  
      gcv.function= GXcopy;
      gc= XCreateGC(disp, *pixmap, GCFunction, &gcv);
!     ximage= XCreateImage(disp, visual, image->depth, ZPixmap, 0, image->data,
  			 image->width, image->height, 8, 0);
      ximage->byte_order= MSBFirst; /* trust me, i know what i'm talking about */
  
--- 144,208 ----
  		 pixptr, image->pixlen);
  	pixptr += image->pixlen;
        }
+ 
      if (verbose)
        printf("done\n");
  
+     /* if the destination depth is not a multiple of 8, then we send each
+      * plane as a bitmap because otherwise we would have to pack the pixel
+      * data and the XImage format is pretty vague about how that should
+      * be done.  this is not as fast as it would be if it were packed but
+      * it should be a lot more portable and only slightly slower.
+      */
+ 
+     if (ddepth % 8) {
+       gcv.function= GXcopy;
+       gcv.background= 0;
+       gc= XCreateGC(disp, *pixmap, GCFunction | GCBackground, &gcv);
+       linelen= (image->width / 8) + (image->width % 8 ? 1 : 0);
+       bitplane= lmalloc(image->height * linelen);
+       ximage= XCreateImage(disp, visual, 1, XYBitmap, 0, bitplane,
+ 			   image->width, image->height, 8, 0);
+       ximage->bitmap_bit_order= MSBFirst;
+       ximage->byte_order= MSBFirst;
+ 
+       for (plane= 1 << (ddepth - 1); plane; plane >>= 1) {
+ 	pixptr= image->data;
+ 	destline= bitplane;
+ 	for (y= 0; y < image->height; y++) {
+ 	  destmask= 0x80;
+ 	  destptr= destline;
+ 	  for (x= 0; x < image->width; x++) {
+ 	    if (*pixptr & plane)
+ 	      *destptr |= destmask;
+ 	    else
+ 	      *destptr &= ~destmask;
+ 	    if (!(destmask >>= 1)) {
+ 	      destmask= 0x80;
+ 	      destptr++;
+ 	    }
+ 	    pixptr += image->pixlen;
+ 	  }
+ 	  destline += linelen;
+ 	}
+ 	XSetForeground(disp, gc, plane);
+ 	XSetPlaneMask(disp, gc, plane);
+ 	XPutImage(disp, *pixmap, gc, ximage, 0, 0, 0, 0,
+ 		  image->width, image->height);
+       }
+ 
+       ximage->data= NULL;
+       XDestroyImage(ximage);
+       lfree(bitplane);
+       break;
+     }
+ 
+     /* send image across in one whack
+      */
+ 
      gcv.function= GXcopy;
      gc= XCreateGC(disp, *pixmap, GCFunction, &gcv);
!     ximage= XCreateImage(disp, visual, ddepth, ZPixmap, 0, image->data,
  			 image->width, image->height, 8, 0);
      ximage->byte_order= MSBFirst; /* trust me, i know what i'm talking about */
  
***************
*** 154,159 ****
      printf("sendImageToX: bad image type\n");
      return(0);
    }
!   lfree(index);
    return(1);
  }
--- 217,222 ----
      printf("sendImageToX: bad image type\n");
      return(0);
    }
!   lfree((byte *)index);
    return(1);
  }
diff -c xloadimage.02/value.c xloadimage.03/value.c
*** xloadimage.02/value.c	Sun Dec 31 16:03:13 1989
--- xloadimage.03/value.c	Wed Dec  6 15:20:32 1989
***************
*** 14,21 ****
  #include "image.h"
  
  unsigned long memToVal(p, len)
!      byte *p;
!      int   len;
  { unsigned int  a;
    unsigned long i;
  
--- 14,21 ----
  #include "image.h"
  
  unsigned long memToVal(p, len)
!      byte         *p;
!      unsigned int  len;
  { unsigned int  a;
    unsigned long i;
  
***************
*** 55,62 ****
       byte          *p;
       unsigned long  val;
       unsigned int   len;
! { int a;
! 
    while (len--) {
      *(p++)= val & 0xff;
      val >>= 8;
--- 55,61 ----
       byte          *p;
       unsigned long  val;
       unsigned int   len;
! {
    while (len--) {
      *(p++)= val & 0xff;
      val >>= 8;
diff -c xloadimage.02/window.c xloadimage.03/window.c
*** xloadimage.02/window.c	Mon Nov  6 11:00:11 1989
--- xloadimage.03/window.c	Wed Jan  3 15:35:42 1990
***************
*** 4,11 ****
   *
   * jim frost 10.03.89
   *
!  * Copyright 1989 Jim Frost.  See included file "copyright.h" for complete
!  * copyright information.
   */
  
  #include "copyright.h"
--- 4,11 ----
   *
   * jim frost 10.03.89
   *
!  * Copyright 1989, 1990 Jim Frost.  See included file "copyright.h" for
!  * complete copyright information.
   */
  
  #include "copyright.h"
***************
*** 20,30 ****
       Cursor       *cursor;
  { XSetWindowAttributes swa;
  
!   if ((ww == iw) && (wh == ih))
      swa.cursor= XCreateFontCursor(disp, XC_icon);
!   else if ((ww < iw) && (wh == ih))
      swa.cursor= XCreateFontCursor(disp, XC_sb_h_double_arrow);
!   else if ((ww == iw) && (wh < ih))
      swa.cursor= XCreateFontCursor(disp, XC_sb_v_double_arrow);
    else
      swa.cursor= XCreateFontCursor(disp, XC_fleur);
--- 20,30 ----
       Cursor       *cursor;
  { XSetWindowAttributes swa;
  
!   if ((ww >= iw) && (wh >= ih))
      swa.cursor= XCreateFontCursor(disp, XC_icon);
!   else if ((ww < iw) && (wh >= ih))
      swa.cursor= XCreateFontCursor(disp, XC_sb_h_double_arrow);
!   else if ((ww >= iw) && (wh < ih))
      swa.cursor= XCreateFontCursor(disp, XC_sb_v_double_arrow);
    else
      swa.cursor= XCreateFontCursor(disp, XC_fleur);
***************
*** 117,123 ****
    XSetNormalHints(disp, window, &sh);
  
    gcv.function= GXcopy;
!   gc= XCreateGC(disp, window, GCFunction, &gcv);
    XMapWindow(disp, window);
    pixx= pixy= 0;
    lastx= lasty= -1;
--- 117,124 ----
    XSetNormalHints(disp, window, &sh);
  
    gcv.function= GXcopy;
!   gcv.foreground= 0;
!   gc= XCreateGC(disp, window, GCFunction | GCForeground, &gcv);
    XMapWindow(disp, window);
    pixx= pixy= 0;
    lastx= lasty= -1;
***************
*** 133,147 ****
  	lasty= event.button.y;
  	break;
        }
- #ifdef NUKE_ME
-       XDestroyWindow(disp, window);
-       XFreeCursor(disp, swa.cursor);
-       XFreePixmap(disp, pixmap);
-       XFreeColormap(disp, xcmap);
-       return;
- #else
        break;
- #endif
  
      case KeyPress: {
        char buf[128];
--- 134,140 ----
***************
*** 153,159 ****
          XDestroyWindow(disp, window);
          XFreeCursor(disp, swa.cursor);
          XFreePixmap(disp, pixmap);
!         XFreeColormap(disp, xcmap);
          return;
        }
      }
--- 146,153 ----
          XDestroyWindow(disp, window);
          XFreeCursor(disp, swa.cursor);
          XFreePixmap(disp, pixmap);
! 	if (xcmap != DefaultColormap(disp, scrn))
!           XFreeColormap(disp, xcmap);
          return;
        }
      }
***************
*** 160,165 ****
--- 154,161 ----
        break;
  
      case MotionNotify:
+       if ((image->width <= winwidth) && (image->height <= winheight))
+ 	break; /* we're AT&T */
        mousex= event.button.x;
        mousey= event.button.y;
        while (XCheckTypedEvent(disp, MotionNotify, &event) == True) {
***************
*** 170,209 ****
        pixy += lasty - mousey;
        lastx= mousex;
        lasty= mousey;
!       if (pixx < 0)
! 	pixx= 0;
!       if (pixy < 0)
! 	pixy= 0;
!       if (pixx + winwidth > image->width)
! 	pixx= image->width - winwidth;
!       if (pixy + winheight > image->height)
! 	pixy= image->height - winheight;
        XCopyArea(disp, pixmap, window, gc,
  		pixx, pixy, winwidth, winheight, 0, 0);
        break;
  
      case ConfigureNotify:
  
-       /* if we got resized too big, fix it.  it's a stupid window manager.
-        */
- 
-       if ((event.configure.width > image->width) ||
- 	  (event.configure.height > image->height)) {
- 	if (event.configure.width > image->width)
- 	  winwidth= image->width;
- 	else
- 	  winwidth= event.configure.width;
- 	if (event.configure.height > image->height)
- 	  winheight= image->height;
- 	else
- 	  winheight= event.configure.height;
- 	XResizeWindow(disp, window, winwidth, winheight);
-       }
-       else {
- 	winwidth= event.configure.width;
- 	winheight= event.configure.height;
-       }
- 
        /* configure the cursor to indicate which directions we can drag
         */
  
--- 166,191 ----
        pixy += lasty - mousey;
        lastx= mousex;
        lasty= mousey;
!       if (image->width > winwidth) {
! 	if (pixx < 0)
! 	  pixx= 0;
! 	if (pixx + winwidth > image->width)
! 	  pixx= image->width - winwidth;
!       }
!       if (image->height > winheight) {
! 	if (pixy < 0)
! 	  pixy= 0;
! 	if (pixy + winheight > image->height)
! 	  pixy= image->height - winheight;
!       }
        XCopyArea(disp, pixmap, window, gc,
  		pixx, pixy, winwidth, winheight, 0, 0);
        break;
  
      case ConfigureNotify:
+       winwidth= event.configure.width;
+       winheight= event.configure.height;
  
        /* configure the cursor to indicate which directions we can drag
         */
  
***************
*** 211,216 ****
--- 193,202 ----
  	pixx= image->width - winwidth;
        if (pixy + winheight > image->height)
  	pixy= image->height - winheight;
+       if (winwidth > image->width)
+ 	pixx= 0;
+       if (winheight > image->height)
+ 	pixy= 0;
        setCursor(disp, window, image->width, image->height,
  		winwidth, winheight, &(swa.cursor));
  
***************
*** 224,230 ****
      case DestroyNotify:
        XFreeCursor(disp, swa.cursor);
        XFreePixmap(disp, pixmap);
!       XFreeColormap(disp, xcmap);
        return;
  
      case Expose:
--- 210,217 ----
      case DestroyNotify:
        XFreeCursor(disp, swa.cursor);
        XFreePixmap(disp, pixmap);
!       if (xcmap != DefaultColormap(disp, scrn))
! 	XFreeColormap(disp, xcmap);
        return;
  
      case Expose:
diff -c xloadimage.02/xbitmap.c xloadimage.03/xbitmap.c
*** xloadimage.02/xbitmap.c	Mon Nov  6 11:00:08 1989
--- xloadimage.03/xbitmap.c	Wed Dec  6 15:07:38 1989
***************
*** 241,247 ****
       char         *fullname, *name;
  { Image *image;
  
!   if (image= xbitmapLoad(fullname, name, 1)) {
      freeImage(image);
      return(1);
    }
--- 241,247 ----
       char         *fullname, *name;
  { Image *image;
  
!   if (image= xbitmapLoad(fullname, name, (unsigned int)1)) {
      freeImage(image);
      return(1);
    }
diff -c xloadimage.02/xloadimage.c xloadimage.03/xloadimage.c
*** xloadimage.02/xloadimage.c	Sun Dec 31 16:03:14 1989
--- xloadimage.03/xloadimage.c	Wed Jan  3 15:36:19 1990
***************
*** 4,15 ****
   *
   * jim frost 09.27.89
   *
!  * Copyright 1989 Jim Frost.  See included file "copyright.h" for complete
!  * copyright information.
   */
  
  #include "copyright.h"
  #include "xloadimage.h"
  
  /* options array and definitions
   */
--- 4,16 ----
   *
   * jim frost 09.27.89
   *
!  * Copyright 1989, 1990 Jim Frost.  See included file "copyright.h" for
!  * complete copyright information.
   */
  
  #include "copyright.h"
  #include "xloadimage.h"
+ #include "patchlevel"
  
  /* options array and definitions
   */
***************
*** 27,32 ****
--- 28,34 ----
    "quiet",
    "supported",
    "verbose",
+   "version",
    "view",
  
    "at", /* image options */
***************
*** 57,77 ****
  #define QUIET     9
  #define SUPPORTED 10
  #define VERBOSE   11
! #define VIEW      12
  
! #define AT         13
! #define BACKGROUND 14
! #define BRIGHT     15
! #define CENTER     16
! #define CLIP       17
! #define COLORS     18
! #define DITHER     19
! #define FOREGROUND 20
! #define HALFTONE   21
! #define NAME       22
! #define XZOOM      23
! #define YZOOM      24
! #define ZOOM       25
  
  /* if an image loader needs to have our display and screen, it will get
   * them from here.  this is done to keep most of the image routines
--- 59,80 ----
  #define QUIET     9
  #define SUPPORTED 10
  #define VERBOSE   11
! #define VER_NUM   12
! #define VIEW      13
  
! #define AT         14
! #define BACKGROUND 15
! #define BRIGHT     16
! #define CENTER     17
! #define CLIP       18
! #define COLORS     19
! #define DITHER     20
! #define FOREGROUND 21
! #define HALFTONE   22
! #define NAME       23
! #define XZOOM      24
! #define YZOOM      25
! #define ZOOM       26
  
  /* if an image loader needs to have our display and screen, it will get
   * them from here.  this is done to keep most of the image routines
***************
*** 129,134 ****
--- 132,149 ----
    winx= winy= winwidth= winheight= 0;
  
    imagecount= 0;
+   for (a= 0; a < MAXIMAGES; a++) {
+     images[a].name= NULL;
+     images[a].atx= images[a].aty= 0;
+     images[a].bright= 0;
+     images[a].center= 0;
+     images[a].clipx= images[a].clipy= 0;
+     images[a].clipw= images[a].cliph= 0;
+     images[a].dither= 0;
+     images[a].colors= 0;
+     images[a].fg= images[a].bg= NULL;
+     images[a].xzoom= images[a].yzoom= 0;
+   }
    for (a= 1; a < argc; a++) {
      switch (optionNumber(argv[a], Options)) {
      case OPT_BADOPT:
***************
*** 199,206 ****
--- 214,227 ----
        verbose= 1;
        break;
  
+     case VER_NUM:
+       printf("Xloadimage version %s patchlevel %s by Jim Frost\n",
+ 	     VERSION, PATCHLEVEL);
+       break;
+ 
      case VIEW:
        onroot= 0;
+       break;
  
      /* process options local to an image
       */
***************
*** 330,336 ****
        *dispimage->rgb.green= xcolor.green;
        *dispimage->rgb.blue= xcolor.blue;
      }
!     fill(dispimage, 0, 0, winwidth, winheight, 0, verbose);
    }
  
    /* load in each named image
--- 351,357 ----
        *dispimage->rgb.green= xcolor.green;
        *dispimage->rgb.blue= xcolor.blue;
      }
!     fill(dispimage, 0, 0, winwidth, winheight, 0);
    }
  
    /* load in each named image
diff -c xloadimage.02/xloadimage.h xloadimage.03/xloadimage.h
*** xloadimage.02/xloadimage.h	Mon Nov  6 10:51:58 1989
--- xloadimage.03/xloadimage.h	Wed Dec  6 15:08:47 1989
***************
*** 38,43 ****
--- 38,45 ----
  /* function declarations
   */
  
+ void supportedImageTypes(); /* imagetypes.c */
+ 
  ZFILE *zopen(); /* io.c */
  int    zread();
  int    zgetc();
diff -c xloadimage.02/xloadimage.man xloadimage.03/xloadimage.man
*** xloadimage.02/xloadimage.man	Sun Dec 31 16:03:15 1989
--- xloadimage.03/xloadimage.man	Wed Jan  3 15:51:00 1990
***************
*** 1,4 ****
! .TH XLOADIMAGE 1 "7 October 1989"
  .SH NAME
  xloadimage, xsetbg, xview \- load images into an X11 window or onto
  the root window
--- 1,4 ----
! .TH XLOADIMAGE 1 "13 December 1989"
  .SH NAME
  xloadimage, xsetbg, xview \- load images into an X11 window or onto
  the root window
***************
*** 7,14 ****
  .SH DESCRIPTION
  \fIXloadimage\fR displays images in an X11 window or loads them onto
  the root window.  See the \fIIMAGE TYPES\fR section below for
! supported image types.  Compressed images will automatically be
! uncompressed.
  .PP
  If the destination display cannot support the number of colors in the
  image, the image will be dithered (monochrome destination) or have its
--- 7,13 ----
  .SH DESCRIPTION
  \fIXloadimage\fR displays images in an X11 window or loads them onto
  the root window.  See the \fIIMAGE TYPES\fR section below for
! supported image types.
  .PP
  If the destination display cannot support the number of colors in the
  image, the image will be dithered (monochrome destination) or have its
***************
*** 19,25 ****
  single image.  The \fI-at\fR and \fI-center\fR options control where
  subsequent images will be loaded onto the initial image.  Any
  combination of color image depths and/or monochrome images may be
! loaded at one time.
  .PP
  A variety of image manipulations can be specified, including
  brightening, clipping, dithering, depth-reduction, and zooming.  Most
--- 18,26 ----
  single image.  The \fI-at\fR and \fI-center\fR options control where
  subsequent images will be loaded onto the initial image.  Any
  combination of color image depths and/or monochrome images may be
! loaded at one time.  If merging two color images would overload the
! number of available colormap entries, the number of colors shared
! between the images will be automatically reduced to fit.
  .PP
  A variety of image manipulations can be specified, including
  brightening, clipping, dithering, depth-reduction, and zooming.  Most
***************
*** 27,38 ****
  for above accuracy.
  .PP
  If you are viewing a large image in a window, the initial window will
! be at most 90% of the size of the display.  You may move the image
! around in the window by dragging with the first mouse button.  The
! cursor will indicate which directions you may drag, if any.  You may
! exit the window by typing 'q' or 'Q' when the keyboard focus is on the
! window.
  .PP
  \fIXsetbg\fR is equivalent to \fIxloadimage -onroot -quiet\fR and
  \fIxview\fR is equivalent to \fIxloadimage -view -verbose\fR.
  .SH GLOBAL OPTIONS
--- 28,44 ----
  for above accuracy.
  .PP
  If you are viewing a large image in a window, the initial window will
! be at most 90% of the size of the display (unless the window manager
! does not correctly handle window size requests).  You may move the
! image around in the window by dragging with the first mouse button.
! The cursor will indicate which directions you may drag, if any.  You
! may exit the window by typing 'q' or 'Q' when the keyboard focus is on
! the window.
  .PP
+ A wide variety of common image manipulations can be done by mixing and
+ matching the available options.  See the section entitled \fIHINTS FOR
+ GOOD IMAGE DISPLAYS\fR for some ideas.
+ .PP
  \fIXsetbg\fR is equivalent to \fIxloadimage -onroot -quiet\fR and
  \fIxview\fR is equivalent to \fIxloadimage -view -verbose\fR.
  .SH GLOBAL OPTIONS
***************
*** 43,52 ****
  This sets the background portion of the window which is not covered by
  any images to be \fIcolor\fR.
  .TP
- -colors \fIn\fR
- Specify the maximum number of colors to use in the image.  This is a
- way to forcibly reduce the depth of an image.
- .TP
  -display \fIdisplay_name\fR
  X11 display name to send the image(s) to.
  .TP
--- 49,54 ----
***************
*** 74,80 ****
  -onroot
  Load image(s) onto the root window instead of viewing in a window.
  This is the opposite of \fI-view\fR.  \fIXSetbg\fR has this option set
! by default.
  .TP
  -path
  Displays the image path and image suffixes which will be used when
--- 76,83 ----
  -onroot
  Load image(s) onto the root window instead of viewing in a window.
  This is the opposite of \fI-view\fR.  \fIXSetbg\fR has this option set
! by default.  Loading with the -onroot option will fail if enough
! sharable colors cannot be allocated from the default colormap.
  .TP
  -path
  Displays the image path and image suffixes which will be used when
***************
*** 93,98 ****
--- 96,106 ----
  image it's playing with and any special processing that it has to do. 
  This is the default for \fIxview\fR and \fIxloadimage\fR. 
  .TP
+ -version
+ Print the version number and patchlevel of this version of
+ \fIxloadimage\fR.  Versions prior to version 1, patchlevel 03 do not
+ have this option and should be updated.
+ .TP
  -view
  View image(s) in a window.  This is the opposite of \fI-onroot\fR and
  the default for \fIxsetbg\fR. 
***************
*** 100,105 ****
--- 108,119 ----
  The following options may preceed each image.  These options are
  local to the image they preceed. 
  .TP
+ -at \fIX\fR,\fIY\fR
+ Indicates coordinates to load the image at on the first image.  If
+ this is an option to the first image, and the \fI-onroot\fR option is
+ specified, the image will be loaded at the given location on the
+ display background. 
+ .TP
  -background \fIcolor\fR
  Use \fIcolor\fR as the background color instead of the default
  (usually white but this depends on the image type) if you are
***************
*** 115,125 ****
  the first image, and the \fI-onroot\fR option is specified, the image
  will be centered on the display background. 
  .TP
! -at \fIX\fR,\fIY\fR
! Indicates coordinates to load the image at on the first image.  If
! this is an option to the first image, and the \fI-onroot\fR option is
! specified, the image will be loaded at the given location on the
! display background. 
  .TP
  -clip \fIX\fR,\fIY\fR,\fIW\fR,\fIH\fR
  Clip the image before loading it.  \fIX\fR and \fIY\fR define the
--- 129,137 ----
  the first image, and the \fI-onroot\fR option is specified, the image
  will be centered on the display background. 
  .TP
! -colors \fIn\fR
! Specify the maximum number of colors to use in the image.  This is a
! way to forcibly reduce the depth of an image.
  .TP
  -clip \fIX\fR,\fIY\fR,\fIW\fR,\fIH\fR
  Clip the image before loading it.  \fIX\fR and \fIY\fR define the
***************
*** 161,173 ****
  .TP
  -zoom \fIpercentage\fR
  Zoom both the X and Y axes by \fIpercentage\fR.  See \fI-xzoom\fR for
! more information. 
  .SH EXAMPLES
  To load the rasterfile "my.image" onto the background and replicate
  it to fill the entire background:
  .sp
  .ti +5
! xloadimage my.image
  .PP
  To load a monochrome image "my.image" onto the background, using red
  as the foreground color, replicate the image, and overlay
--- 173,187 ----
  .TP
  -zoom \fIpercentage\fR
  Zoom both the X and Y axes by \fIpercentage\fR.  See \fI-xzoom\fR for
! more information.  Technically the percentage actually zoomed is the
! square of the number supplied since the zoom is to both axes, but I
! opted for consistency instead of accuracy.
  .SH EXAMPLES
  To load the rasterfile "my.image" onto the background and replicate
  it to fill the entire background:
  .sp
  .ti +5
! xloadimage -onroot my.image
  .PP
  To load a monochrome image "my.image" onto the background, using red
  as the foreground color, replicate the image, and overlay
***************
*** 181,202 ****
  .sp
  .ti +5
  xloadimage -center -clip 10,10,100,0 my.image
  .SH PATHS AND EXTENSIONS
! The file ~/.xloadimagerc (and optionally a system-wide file which is
! system-specific) defines the path and default extensions that
! .I xloadimage
! will use when looking for images.  The file can have two statements:
! "path=" and "extension=" (the equals signs must follow the word with
! no spaces between).  Everything following the "path=" keyword
! will be prepended to the supplied image name if the supplied name does
! not specify an existing file.  The paths will be searched in the order
! they are specified.  Everything following the "extension=" keyword
! will be appended to the supplied image name if the supplied name does
! not specify and existing file.  As with paths, these extensions will
! be searched in the order they are given.  Comments are any portion of
! a line following a hash-mark (#).  The following is a sample
! ~/.xloadimagerc file:
  .PP
  .nf
    # paths to look for images in
    path= /usr/local/images
--- 195,287 ----
  .sp
  .ti +5
  xloadimage -center -clip 10,10,100,0 my.image
+ .PP
+ To double the size of an image:
+ .sp
+ .ti +5
+ xloadimage -zoom 200 my.image
+ .PP
+ To halve the size of an image:
+ .sp
+ .ti +5
+ xloadimage -zoom 50 my.image
+ .PP
+ To brighten a dark image:
+ .sp
+ .ti +5
+ xloadimage -brighten 150 my.image
+ .PP
+ To darken a bright image:
+ .sp
+ .ti +5
+ xloadimage -brighten 50 my.image
+ .SH HINTS FOR GOOD IMAGE DISPLAYS
+ Since images are likely to come from a variety of sources, they may be
+ in a variety of aspect ratios which may not be supported by your
+ display.  The \fI-xzoom\fR and \fI-yzoom\fR options can be used to
+ change the aspect ratio of an image before display.  If you use these
+ options, it is recommended that you increase the size of one of the
+ dimensions instead of shrinking the other, since shrinking looses
+ detail.  For instance, many GIF images have an X:Y ratio of about 2:1.
+ You can correct this for viewing on a 1:1 display with either
+ \fI-xzoom 50\fR or \fI-yzoom 200\fR (reduce X axis to 50% of its size
+ and expand Y axis to 200% of its size, respectively) but the latter
+ should be used so no detail is lost in the conversion.
+ .PP
+ When merging images, the first image loaded is used to determine the
+ depth of the merged image.  This becomes a problem if the first image
+ is monochrome and other images are color, since the other images will
+ be dithered to monochrome before merging.  You can get around this
+ behavior by using the \fI-geometry\fR option to specify the size of
+ the destination image -- this will force \fIxloadimage\fR to use the
+ default depth of the display instead of 1.  The standard behavior
+ might be modified in the future if it becomes a problem.
+ .PP
+ You can perform image processing on a small portion of an image by
+ loading the image more than once and using the \fI-at\fR and
+ \fI-clip\fR options.  Load the image, then load it again and clip,
+ position, and process the second.  To brighten a 100x100 rectangular
+ portion of an image located at (50,50), for instance, you could type:
+ .sp
+ .ti +5
+ xloadimage my.image -at 50,50 -clip 50,50,100,100 -brighten 150 my.image
+ .PP
+ One common use of \fIxloadimage\fR is to load images onto the root
+ window.  Unfortunately there is no agreed-upon method of freeing some
+ root window resources, such as colormap entries, nor is there a way to
+ modify the root window colormap without confusing most window
+ managers.  For this reason, \fIxloadimage\fR will not allow the
+ loading of images onto the root window if it cannot allocate shared
+ colors from the root window's colormap.  I suggest the avoidance of
+ multiple color image loads onto the root window, as these eat up root
+ window shareable colormap entries.  If you wish to have a slideshow,
+ display the images in a window.  A future implementation of
+ \fIxloadimage\fR will have a \fI-fullscreen\fR (or maybe
+ \fI-slideshow\fR) option, but this is as yet unavailable.
+ .PP
+ One common complaint is that \fIxloadimage\fR does not have a
+ \fI-reverse\fR function for inverting monochrome images.  In fact,
+ this function is a special-case of the foreground and background
+ coloring options.  To invert an image with a black foreground and
+ white background (which is standard), use \fI-foreground white
+ -background black\fR.  This will work on both color and monochrome
+ displays.
  .SH PATHS AND EXTENSIONS
! The file ~/.xloadimagerc (and optionally a system-wide file) defines
! the path and default extensions that \fIxloadimage\fR will use when
! looking for images.  This file can have two statements: "path=" and
! "extension=" (the equals signs must follow the word with no spaces
! between).  Everything following the "path=" keyword will be prepended
! to the supplied image name if the supplied name does not specify an
! existing file.  The paths will be searched in the order they are
! specified.  Everything following the "extension=" keyword will be
! appended to the supplied image name if the supplied name does not
! specify an existing file.  As with paths, these extensions will be
! searched in the order they are given.  Comments are any portion of a
! line following a hash-mark (#).
  .PP
+ The following is a sample ~/.xloadimagerc file:
+ .PP
  .nf
    # paths to look for images in
    path= /usr/local/images
***************
*** 206,216 ****
--- 291,309 ----
    # default extensions for images; .Z is automatic; scanned in order
    extension= .csun .msun .sun .face .xbm .bm
  .fi
+ .PP
+ Versions of \fIxloadimage\fR prior to version 01, patchlevel 03 would
+ load the system-wide file (if any), followed by the user's file.  This
+ behavior made it difficult for the user to configure her environment
+ if she didn't want the default.  Newer versions will ignore the
+ system-wide file if a personal configuration file exists.
  .SH IMAGE TYPES
  .PP
  \fIXloadimage\fR currently supports the following image types:
+ .sp
  .nf
    Faces Project images
+   GIF images
    Portable Bitmap (PBM) images
    Sun monochrome rasterfiles
    Sun color RGB rasterfiles
***************
*** 219,247 ****
    X pixmap files
  .fi
  .PP
! Both normal and compact PBM images are supported.  Both standard and
! run-length encoded Sun rasterfiles are supported.
  .SH AUTHOR
  .nf
  Jim Frost
! Software Tool & Die
! madd@std.com
  .fi
  .SH BUGS
! Zooming dithered images is UGLY.
  .PP
! Loading images onto the root with PseudoColor or GrayScale displays
! can cause colormap problems (and may interfere with window manager
! operation) if there are not enough colors in the default colormap to
! allocate all of the colors read/write.  This can happen on images
! which have too many unique colors or if images are loaded onto the
! root in succession.  Since there is currently no X standard for
! changing the root colormap, this problem may or may not be corrected
! in the future.
  .PP
! Since \fIxloadimage\fR does not want a window larger than the image to
! be displayed, it resizes the window to fit the image if the window
! manager resizes the window to a size which is too large.  This could
! cause a conflict if the window manager responds to the resize request
! by resizing the window to the larger size.  This should be rare given
! the state of current window managers and has never been observed.
--- 312,401 ----
    X pixmap files
  .fi
  .PP
! Normal, compact, and raw PBM images are supported.  Both standard and
! run-length encoded Sun rasterfiles are supported.  Any image whose
! name ends in .Z is assumed to be a compressed image and will be
! filtered through "uncompress".
  .SH AUTHOR
  .nf
  Jim Frost
! Saber Software
! jimf@saber.com
  .fi
+ .PP
+ Other contributing people include Barry Shein (bzs@std.com), Kirk L.
+ Johnson (tuna@athena.mit.edu), Mark Snitilly (zok!mark@apple.com), and
+ W. David Higgins (wdh@mkt.csd.harris.com).
+ .SH FILES
+ .nf
+ .in +5
+ xloadimage            - the image loader and viewer
+ xsetbg                - pseudonym which quietly sets the background
+ xview                 - pseudonym which views in a window
+ /usr/lib/xloadimagerc - default system-wide configuration file
+ ~/.xloadimagerc       - user's personal configuration file
+ .in -5
+ .fi
+ .SH COPYRIGHT
+ Copyright (c) 1989, 1990 Jim Frost and others.
+ .PP
+ \fIXloadimage\fR is copywritten material with a very loose copyright
+ allowing unlimited modification and distribution if the copyright
+ notices are left intact.  Various portions are copywritten by various
+ people, but all use a modification of the MIT copyright notice.
+ Please check the source for complete copyright information.  The
+ intent is to keep the source free, not to stifle its distribution, so
+ please write to me if you have any questions.
  .SH BUGS
! Zooming dithered images, especially downwards, is UGLY.
  .PP
! The dithering algorithm used by \fI-dither\fR could be better, and
! both \fI-dither\fR and \fI-halftone\fR assume that a color's
! brightness is the sum of its RGB values, which is not correct but has
! the advantage of being simple and fast.
  .PP
! Images can come in a variety of aspect ratios.  \fIXloadimage\fR cannot
! detect what aspect ratio the particular image being loaded has, nor
! the aspect ratio of the destination display, so images with differing
! aspect ratios from the destination display will appear distorted.  See
! \fIHINTS FOR GOOD IMAGE DISPLAYS\fR for more information.
! .PP
! The GIF format allows more than one image to be stored in a single GIF
! file, but \fIxloadimage\fR will only display the first.
! .PP
! Only PseudoColor, GrayScale, StaticColor, and StaticGray visuals are
! supported.  These are the most common visuals so this isn't usually a
! problem.
! .PP
! You cannot load an image onto the root window if the default visual is
! not supported by \fIxloadimage\fR.
! .PP
! If color images with substantially differing colormaps are loaded onto
! the root window, eventually there will be no more sharable colors in
! the default colormap and subsequent image loads onto the root window
! will fail.  This is the result of limitations within X and a lack of
! any protocol for handling root window and/or default colormap changes.
! .PP
! One of the pseudonyms for \fIxloadimage\fR, \fIxview\fR, is the same
! name as Sun uses for their SunView-under-X package.  This will be
! confusing if you're one of those poor souls who has to use Sun's
! XView.
! .PP
! Some window managers do not correctly handle window size requests.  In
! particular, versions of the twm window manager prior to X11R4 will use
! the MaxSize hint instead of the PSize hint, causing images which
! are larger than the screen to display in a window larger than the
! screen, something which is normally avoided.  These versions of twm
! also ignore the MaxSize argument's real function, to limit the maximum
! size of the window, and allow the window to be resized larger than the
! image.  If this happens, \fIxloadimage\fR merely places the image in
! the upper-left corner of the window and uses the zero-value'ed pixel
! for any space which is not covered by the image.  This behavior is
! less-than-graceful but so are window managers which are cruel enough
! to ignore such details.
! .PP
! The order in which operations are performed on an image is independent
! of the order in which they were specified on the command line.
! Wherever possible I tried to order operations in such a way as to look
! the best possible (zooming before dithering, for instance) or to
! increase speed (zooming downward before compressing, for instance).
diff -c xloadimage.02/xpixmap.c xloadimage.03/xpixmap.c
*** xloadimage.02/xpixmap.c	Sun Dec 31 16:01:52 1989
--- xloadimage.03/xpixmap.c	Wed Dec  6 15:17:31 1989
***************
*** 39,44 ****
--- 39,45 ----
    char           buf[BUFSIZ];
    char           what[BUFSIZ];
    char          *p;
+   char          *imagetitle;
    unsigned int   value;
    unsigned int   format;  /* image format */
    unsigned int   w, h;    /* image dimensions */
***************
*** 112,132 ****
  
    if (p= rindex(what, '_')) {     /* get the name in the image if there is */
      *p= '\0';                     /* one */
!     image->title= dupString(what);
    }
    else {
      p= what;
!     image->title= dupString(name);
    }
  
    if (verbose)
      printf("%s is a %dx%d X Pixmap image with %d colors titled '%s'\n",
! 	   name, w, h, ncolors, image->title);
  
    for (depth= 1, value= 2; value < ncolors; value <<= 1, depth++)
      ;
    image= newRGBImage(w, h, depth);
    image->rgb.used= ncolors;
  
    /* read the colors array and build the image colormap
     */
--- 113,134 ----
  
    if (p= rindex(what, '_')) {     /* get the name in the image if there is */
      *p= '\0';                     /* one */
!     imagetitle= dupString(what);
    }
    else {
      p= what;
!     imagetitle= dupString(name);
    }
  
    if (verbose)
      printf("%s is a %dx%d X Pixmap image with %d colors titled '%s'\n",
! 	   name, w, h, ncolors, imagetitle);
  
    for (depth= 1, value= 2; value < ncolors; value <<= 1, depth++)
      ;
    image= newRGBImage(w, h, depth);
    image->rgb.used= ncolors;
+   image->title= dupString(imagetitle);
  
    /* read the colors array and build the image colormap
     */
***************
*** 227,235 ****
  }
  
  int xpixmapIdent(fullname, name)
  { Image *image;
  
!   if (image= xpixmapLoad(fullname, name, 1)) {
      freeImage(image);
      return(1);
    }
--- 229,238 ----
  }
  
  int xpixmapIdent(fullname, name)
+      char *fullname, *name;
  { Image *image;
  
!   if (image= xpixmapLoad(fullname, name, (unsigned int)1)) {
      freeImage(image);
      return(1);
    }
diff -c xloadimage.02/zio.c xloadimage.03/zio.c
*** xloadimage.02/zio.c	Mon Nov  6 10:52:00 1989
--- xloadimage.03/zio.c	Wed Dec  6 15:19:19 1989
***************
*** 16,27 ****
  { ZFILE *zf;
    char   buf[BUFSIZ];
  
!   zf= (ZFILE *)lmalloc(sizeof(ZFILE));
    if ((strlen(name) > 2) && !strcmp(".Z", name + (strlen(name) - 2))) {
      zf->type= ZPIPE;
      sprintf(buf, "uncompress -c %s", name);
      if (! (zf->stream= popen(buf, "r"))) {
!       lfree(zf);
        return(NULL);
      }
      return(zf);
--- 16,27 ----
  { ZFILE *zf;
    char   buf[BUFSIZ];
  
!   zf= (ZFILE *)lmalloc((unsigned int)sizeof(ZFILE));
    if ((strlen(name) > 2) && !strcmp(".Z", name + (strlen(name) - 2))) {
      zf->type= ZPIPE;
      sprintf(buf, "uncompress -c %s", name);
      if (! (zf->stream= popen(buf, "r"))) {
!       lfree((byte *)zf);
        return(NULL);
      }
      return(zf);
***************
*** 28,34 ****
    }
    zf->type= ZSTANDARD;
    if (! (zf->stream= fopen(name, "r"))) {
!     lfree(zf);
      return(NULL);
    }
    return(zf);
--- 28,34 ----
    }
    zf->type= ZSTANDARD;
    if (! (zf->stream= fopen(name, "r"))) {
!     lfree((byte *)zf);
      return(NULL);
    }
    return(zf);
***************
*** 73,77 ****
      printf("zclose: bad ZFILE structure\n");
      exit(1);
    }
!   lfree(zf);
  }
--- 73,77 ----
      printf("zclose: bad ZFILE structure\n");
      exit(1);
    }
!   lfree((byte *)zf);
  }
diff -c xloadimage.02/zoom.c xloadimage.03/zoom.c
*** xloadimage.02/zoom.c	Sun Dec 31 16:03:16 1989
--- xloadimage.03/zoom.c	Wed Dec  6 15:21:20 1989
***************
*** 162,169 ****
    }
  
    image->title= dupString(buf);
!   lfree(xindex);
!   lfree(yindex);
    if (verbose)
      printf("done\n");
    return(image);
--- 162,169 ----
    }
  
    image->title= dupString(buf);
!   lfree((byte *)xindex);
!   lfree((byte *)yindex);
    if (verbose)
      printf("done\n");
    return(image);

dan
-----------------------------------------------------------
		    O'Reilly && Associates
		argv@sun.com / argv@ora.com
	   632 Petaluma Ave, Sebastopol, CA 95472 
     800-338-NUTS, in CA: 800-533-NUTS, FAX 707-829-0104
    Opinions expressed reflect those of the author only.