diff -rud --new-file xv-3.10a-orig/Makefile xv-3.10a/Makefile
--- xv-3.10a-orig/Makefile	Mon Jan 23 18:20:54 1995
+++ xv-3.10a/Makefile	Sat Apr 15 11:21:44 2000
@@ -56,6 +56,25 @@
 
 
 ###
+### if, for whatever reason, you're unable to get the PNG library to compile
+### on your machine, *COMMENT OUT* the following lines
+###
+PNG    = -DDOPNG
+PNGDIR = /usr/local/src/libpng
+PNGINC = -I$(PNGDIR)
+PNGLIB = -L$(PNGDIR) -lpng
+
+
+###
+### if, for whatever reason, you're unable to get the PNG library to compile
+### on your machine, *COMMENT OUT* the following lines
+###
+ZLIBDIR = /usr/local/src/zlib
+ZLIBINC = -I$(ZLIBDIR)
+ZLIBLIB = -L$(ZLIBDIR) -lz
+
+
+###
 ### if, for whatever reason, you're unable to get the TIFF library to compile
 ### on your machine, *COMMENT OUT* the following lines
 ###
@@ -186,9 +205,9 @@
 
 CFLAGS = $(CCOPTS) $(JPEG) $(JPEGINC) $(TIFF) $(TIFFINC) $(PDS) \
 	$(NODIRENT) $(VPRINTF) $(TIMERS) $(UNIX) $(BSDTYPES) $(RAND) \
-	$(DXWM) $(MCHN)
+	$(DXWM) $(MCHN) $(PNG) $(PNGINC) $(ZLIBINC)
 
-LIBS = -lX11 $(JPEGLIB) $(TIFFLIB) -lm
+LIBS = -lX11 $(JPEGLIB) $(TIFFLIB) $(PNGLIB) $(ZLIBLIB) -lm
 
 OBJS = 	xv.o xvevent.o xvroot.o xvmisc.o xvimage.o xvcolor.o xvsmooth.o \
 	xv24to8.o xvgif.o xvpm.o xvinfo.o xvctrl.o xvscrl.o xvalg.o \
@@ -196,7 +215,7 @@
 	xvdial.o xvgraf.o xvsunras.o xvjpeg.o xvps.o xvpopup.o xvdflt.o \
 	xvtiff.o xvtiffwr.o xvpds.o xvrle.o xviris.o xvgrab.o vprintf.o \
 	xvbrowse.o xvtext.o xvpcx.o xviff.o xvtarga.o xvxpm.o xvcut.o \
-	xvxwd.o xvfits.o
+	xvxwd.o xvfits.o xvpng.o
 
 MISC = README INSTALL CHANGELOG IDEAS
 
@@ -267,7 +286,7 @@
 xvbrowse.o:	bits/br_pcx bits/br_jfif bits/br_tiff bits/br_pds 
 xvbrowse.o:	bits/br_ps bits/br_iff bits/br_targa bits/br_xpm
 xvbrowse.o:	bits/br_trash bits/fcurs bits/fccurs bits/fdcurs bits/fcursm
-xvbrowse.o:     bits/br_xwd
+xvbrowse.o:     bits/br_xwd bits/br_png
 
 xvbutt.o:	bits/cboard50 bits/rb_frame bits/rb_frame1 bits/rb_top
 xvbutt.o:	bits/rb_bot bits/rb_dtop bits/rb_dbot bits/rb_body
diff -rud --new-file xv-3.10a-orig/Makefile.std xv-3.10a/Makefile.std
--- xv-3.10a-orig/Makefile.std	Mon Jan 23 23:06:26 1995
+++ xv-3.10a/Makefile.std	Sat Apr 15 11:21:44 2000
@@ -56,6 +56,25 @@
 
 
 ###
+### if, for whatever reason, you're unable to get the PNG library to compile
+### on your machine, *COMMENT OUT* the following lines
+###
+PNG    = -DDOPNG
+PNGDIR = /usr/local/src/libpng
+PNGINC = -I$(PNGDIR)
+PNGLIB = -L$(PNGDIR) -lpng
+
+
+###
+### if, for whatever reason, you're unable to get the PNG library to compile
+### on your machine, *COMMENT OUT* the following lines
+###
+ZLIBDIR = /usr/local/src/zlib
+ZLIBINC = -I$(ZLIBDIR)
+ZLIBLIB = -L$(ZLIBDIR) -lz
+
+
+###
 ### if, for whatever reason, you're unable to get the TIFF library to compile
 ### on your machine, *COMMENT OUT* the following lines
 ###
@@ -186,9 +205,9 @@
 
 CFLAGS = $(CCOPTS) $(JPEG) $(JPEGINC) $(TIFF) $(TIFFINC) $(PDS) \
 	$(NODIRENT) $(VPRINTF) $(TIMERS) $(UNIX) $(BSDTYPES) $(RAND) \
-	$(DXWM) $(MCHN)
+	$(DXWM) $(MCHN) $(PNG) $(PNGINC) $(ZLIBINC)
 
-LIBS = -lX11 $(JPEGLIB) $(TIFFLIB) -lm
+LIBS = -lX11 $(JPEGLIB) $(TIFFLIB) $(PNGLIB) $(ZLIBLIB) -lm
 
 OBJS = 	xv.o xvevent.o xvroot.o xvmisc.o xvimage.o xvcolor.o xvsmooth.o \
 	xv24to8.o xvgif.o xvpm.o xvinfo.o xvctrl.o xvscrl.o xvalg.o \
@@ -196,7 +215,7 @@
 	xvdial.o xvgraf.o xvsunras.o xvjpeg.o xvps.o xvpopup.o xvdflt.o \
 	xvtiff.o xvtiffwr.o xvpds.o xvrle.o xviris.o xvgrab.o vprintf.o \
 	xvbrowse.o xvtext.o xvpcx.o xviff.o xvtarga.o xvxpm.o xvcut.o \
-	xvxwd.o xvfits.o
+	xvxwd.o xvfits.o xvpng.o
 
 MISC = README INSTALL CHANGELOG IDEAS
 
@@ -267,7 +286,7 @@
 xvbrowse.o:	bits/br_pcx bits/br_jfif bits/br_tiff bits/br_pds 
 xvbrowse.o:	bits/br_ps bits/br_iff bits/br_targa bits/br_xpm
 xvbrowse.o:	bits/br_trash bits/fcurs bits/fccurs bits/fdcurs bits/fcursm
-xvbrowse.o:     bits/br_xwd
+xvbrowse.o:     bits/br_xwd bits/br_png
 
 xvbutt.o:	bits/cboard50 bits/rb_frame bits/rb_frame1 bits/rb_top
 xvbutt.o:	bits/rb_bot bits/rb_dtop bits/rb_dbot bits/rb_body
diff -rud --new-file xv-3.10a-orig/README.PNG xv-3.10a/README.PNG
--- xv-3.10a-orig/README.PNG	Wed Dec 31 21:00:00 1969
+++ xv-3.10a/README.PNG	Sat Apr 15 11:21:22 2000
@@ -0,0 +1,33 @@
+This archive contains context diffs suitable for use with the GNU
+patch utility.  It adds the ability to read and write PNG format
+files with XV 3.10a.  This patch was written by Andreas Dilger
+<adilger@enel.ucalgary.ca> based on a patch written by Alexander
+Lehmann <lehmann@mathematik.th-darmstadt.de>.  No warranty, expressed
+or implied, of merchant-ability or fitness for a particular purpose
+is given with this patch.  It is also an unofficial patch, in the
+sense that the XV author had nothing to do with it.  Despite all that,
+it is reasonably reliable.
+
+The following files are required for adding PNG to XV 3.10a.
+xvpng.c
+xvpng.diff
+bits/br_png
+
+Move them into the same directory as the XV source code, and apply
+the patch via "patch -p1 < xvpng.diff".  You may need to edit your
+makefile to indicate the location of libpng and zlib, which are not
+included here.  Both are available at ftp.uu.net and various other
+locations on the internet.  This patch was created with libpng-0.89
+and zlib-1.0.2, but later versions should also work.
+
+The xvjpeg.diff and xvtiff.diff are not required for the PNG
+functionality, but were modifications I needed to make to get XV
+to compile with the latest versions of the respective libraries
+(libjpeg 6.0 and libtiff 3.4.beta027 respectively).  You do not
+need to apply them if you are using the libraries included with XV.
+
+The xcmap.diff file allows this program to work properly with a 1-bit
+X display.  It is not required for PNG functionality.  Why use xcmap
+for a 1-bit display?  Because I have an xcmap icon for fvwm, and it
+always starts regardless of the display, so it was easier to fix xcmap
+than to stop xcmap from starting based on the display depth.
diff -rud --new-file xv-3.10a-orig/bits/br_png xv-3.10a/bits/br_png
--- xv-3.10a-orig/bits/br_png	Wed Dec 31 21:00:00 1969
+++ xv-3.10a/bits/br_png	Sat Apr 15 11:21:06 2000
@@ -0,0 +1,28 @@
+#define br_png_width 48
+#define br_png_height 48
+static unsigned char br_png_bits[] = {
+  0xe0, 0xff, 0xff, 0xff, 0x01, 0x00, 0x20, 0x00, 0x00, 0x00, 0x03, 0x00,
+  0x20, 0x00, 0x00, 0x00, 0x05, 0x00, 0x20, 0x00, 0x00, 0x00, 0x09, 0x00,
+  0x20, 0x00, 0x00, 0x00, 0x11, 0x00, 0x20, 0x00, 0x00, 0x00, 0x21, 0x00,
+  0x20, 0x00, 0x00, 0x00, 0x41, 0x00, 0x20, 0x00, 0x00, 0x00, 0x81, 0x00,
+  0x20, 0x00, 0x00, 0x00, 0x01, 0x01, 0x20, 0x00, 0x00, 0x00, 0xff, 0x03,
+  0x20, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0x00, 0x00, 0x00, 0x00, 0x02,
+  0x20, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0xff, 0xff, 0xff, 0x3f, 0x02,
+  0x20, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0xff, 0xff, 0xff, 0x3f, 0x02,
+  0x20, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0x00, 0x00, 0x00, 0x00, 0x02,
+  0x20, 0xf8, 0x19, 0xc3, 0x07, 0x02, 0x20, 0x18, 0x3b, 0x63, 0x0c, 0x02,
+  0x20, 0x18, 0x3b, 0x33, 0x00, 0x02, 0x20, 0x18, 0x5b, 0x33, 0x00, 0x02,
+  0x20, 0xf8, 0x59, 0x33, 0x0f, 0x02, 0x20, 0x18, 0x98, 0x33, 0x0c, 0x02,
+  0x20, 0x18, 0x98, 0x33, 0x0c, 0x02, 0x20, 0x18, 0x18, 0x63, 0x0c, 0x02,
+  0x20, 0x18, 0x18, 0xc3, 0x0b, 0x02, 0x20, 0x00, 0x00, 0x00, 0x00, 0x02,
+  0x20, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0x00, 0x00, 0x00, 0x00, 0x02,
+  0x20, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0xff, 0xff, 0xff, 0x3f, 0x02,
+  0x20, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0xff, 0xff, 0xff, 0x3f, 0x02,
+  0x20, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0x00, 0x00, 0x00, 0x00, 0x02,
+  0x20, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0x00, 0x00, 0x00, 0x00, 0x02,
+  0x20, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0x00, 0x00, 0x00, 0x00, 0x02,
+  0x20, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0x00, 0x00, 0x00, 0x00, 0x02,
+  0x20, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0x00, 0x00, 0x00, 0x00, 0x02,
+  0x20, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0x00, 0x00, 0x00, 0x00, 0x02,
+  0x20, 0x00, 0x00, 0x00, 0x00, 0x02, 0xe0, 0xff, 0xff, 0xff, 0xff, 0x03,
+  };
diff -rud --new-file xv-3.10a-orig/xv.c xv-3.10a/xv.c
--- xv-3.10a-orig/xv.c	Thu Jan 19 16:08:43 1995
+++ xv-3.10a/xv.c	Sat Apr 15 11:21:44 2000
@@ -277,6 +277,10 @@
   tiffW = (Window) NULL;  tiffUp = 0;
 #endif
 
+#ifdef HAVE_PNG
+  pngW = (Window) NULL;  pngUp = 0;
+#endif
+
   imap = ctrlmap = gmap = browmap = cmtmap = 0;
 
   ch_offx = ch_offy = p_offx = p_offy = 0;
@@ -782,6 +786,10 @@
   XSetTransientForHint(theDisp, tiffW, dirW);
 #endif
   
+#ifdef HAVE_PNG
+  CreatePNGW();
+  XSetTransientForHint(theDisp, pngW, dirW);
+#endif
   
   LoadFishCursors();
   SetCursors(-1);
@@ -2611,6 +2619,11 @@
 	   (magicno[0]=='I' && magicno[1]=='I'))        rv = RFT_TIFF;
 #endif
 
+#ifdef HAVE_PNG
+  else if (magicno[0]==0x89 && magicno[1]=='P' &&
+           magicno[2]=='N'  && magicno[3]=='G')                  rv = RFT_PNG;
+#endif
+
 #ifdef HAVE_PDS
   else if (strncmp((char *) magicno,  "NJPL1I00", (size_t) 8)==0 ||
 	   strncmp((char *) magicno+2,"NJPL1I",   (size_t) 6)==0 ||
@@ -2669,6 +2682,10 @@
 
 #ifdef HAVE_TIFF
   case RFT_TIFF:    rv = LoadTIFF  (fname, pinfo);           break;
+#endif
+
+#ifdef HAVE_PNG
+  case RFT_PNG:     rv = LoadPNG   (fname, pinfo);         break;
 #endif
 
 #ifdef HAVE_PDS
diff -rud --new-file xv-3.10a-orig/xv.h xv-3.10a/xv.h
--- xv-3.10a-orig/xv.h	Mon Jan 23 18:22:23 1995
+++ xv-3.10a/xv.h	Sat Apr 15 11:21:44 2000
@@ -8,8 +8,8 @@
 #include "config.h"
 
 
-#define REVDATE   "Version 3.10a  Rev: 12/29/94"
-#define VERSTR    "3.10a"
+#define REVDATE   "Version 3.10a  Rev: 12/29/94 (PNG patch 1.2)"
+#define VERSTR    "3.10a(PNG)"
 
 /*
  * uncomment the following, and modify for your site, but only if you've
@@ -327,6 +327,10 @@
 #define HAVE_TIFF
 #endif
 
+#ifdef DOPNG
+#define HAVE_PNG
+#endif
+
 #ifdef DOPDS
 #define HAVE_PDS
 #endif
@@ -458,24 +462,31 @@
 #define F_TIFINC  0
 #endif
 
+#ifdef HAVE_PNG
+#define F_PNGINC  1
+#else
+#define F_PNGINC  0
+#endif
+
 
 #define F_GIF         0
 #define F_JPEG      ( 0 + F_JPGINC)
 #define F_TIFF      ( 0 + F_JPGINC + F_TIFINC)
-#define F_PS        ( 1 + F_JPGINC + F_TIFINC)
-#define F_PBMRAW    ( 2 + F_JPGINC + F_TIFINC)
-#define F_PBMASCII  ( 3 + F_JPGINC + F_TIFINC)
-#define F_XBM       ( 4 + F_JPGINC + F_TIFINC)
-#define F_XPM       ( 5 + F_JPGINC + F_TIFINC)
-#define F_BMP       ( 6 + F_JPGINC + F_TIFINC)
-#define F_SUNRAS    ( 7 + F_JPGINC + F_TIFINC)
-#define F_IRIS      ( 8 + F_JPGINC + F_TIFINC)
-#define F_TARGA     ( 9 + F_JPGINC + F_TIFINC)
-#define F_FITS      (10 + F_JPGINC + F_TIFINC)
-#define F_PM        (11 + F_JPGINC + F_TIFINC)
-#define F_DELIM1    (12 + F_JPGINC + F_TIFINC)     /* ----- */
-#define F_FILELIST  (13 + F_JPGINC + F_TIFINC)
-#define F_MAXFMTS   (14 + F_JPGINC + F_TIFINC)     /* 15, normally */
+#define F_PNG       ( 0 + F_JPGINC + F_TIFINC + F_PNGINC)
+#define F_PS        ( 1 + F_JPGINC + F_TIFINC + F_PNGINC)
+#define F_PBMRAW    ( 2 + F_JPGINC + F_TIFINC + F_PNGINC)
+#define F_PBMASCII  ( 3 + F_JPGINC + F_TIFINC + F_PNGINC)
+#define F_XBM       ( 4 + F_JPGINC + F_TIFINC + F_PNGINC)
+#define F_XPM       ( 5 + F_JPGINC + F_TIFINC + F_PNGINC)
+#define F_BMP       ( 6 + F_JPGINC + F_TIFINC + F_PNGINC)
+#define F_SUNRAS    ( 7 + F_JPGINC + F_TIFINC + F_PNGINC)
+#define F_IRIS      ( 8 + F_JPGINC + F_TIFINC + F_PNGINC)
+#define F_TARGA     ( 9 + F_JPGINC + F_TIFINC + F_PNGINC)
+#define F_FITS      (10 + F_JPGINC + F_TIFINC + F_PNGINC)
+#define F_PM        (11 + F_JPGINC + F_TIFINC + F_PNGINC)
+#define F_DELIM1    (12 + F_JPGINC + F_TIFINC + F_PNGINC)   /* ----- */
+#define F_FILELIST  (13 + F_JPGINC + F_TIFINC + F_PNGINC)
+#define F_MAXFMTS   (14 + F_JPGINC + F_TIFINC + F_PNGINC)   /* 17, normally */
 
 
 
@@ -505,6 +516,7 @@
 #define RFT_XPM      17
 #define RFT_XWD      18
 #define RFT_FITS     19
+#define RFT_PNG      20
 
 /* definitions for page up/down, arrow up/down list control */
 #define LS_PAGEUP   0
@@ -765,9 +777,10 @@
 typedef struct { Window win;            /* window ID */
 		 int x,y,w,h;           /* window coords in parent */
 		 int active;            /* true if can do anything*/
-		 int min,max;           /* min/max values 'pos' can take */
-		 int val;               /* 'value' of dial */
-		 int page;              /* amt val change on pageup/pagedown */
+		 double min,max;        /* min/max values 'pos' can take */
+		 double val;            /* 'value' of dial */
+		 double inc;            /* amt val change on up/down */
+		 double page;           /* amt val change on pageup/pagedown */
 		 char *title;           /* title for this guage */
 		 char *units;           /* string appended to value */
 		 u_long fg,bg,hi,lo;    /* colors */
@@ -1154,6 +1167,13 @@
 #endif
 
 
+#ifdef HAVE_PNG
+/* stuff used for 'png' box */
+WHERE Window        pngW;
+WHERE int           pngUp;        /* is pngW mapped, or what? */
+#endif
+
+
 #undef WHERE
 
 
@@ -1465,12 +1485,12 @@
 
 
 /*************************** XVDIAL.C ***************************/
-void DCreate               PARM((DIAL *, Window, int, int, int, int, int, 
-				 int, int, int, u_long, u_long, u_long, 
-				 u_long, char *, char *));
+void DCreate               PARM((DIAL *, Window, int, int, int, int, double,
+                                 double, double, double, double, u_long,
+                                 u_long, u_long, u_long, char *, char *));
 
-void DSetRange             PARM((DIAL *, int, int, int, int));
-void DSetVal               PARM((DIAL *, int));
+void DSetRange             PARM((DIAL *, double,double,double,double,double));
+void DSetVal               PARM((DIAL *, double));
 void DSetActive            PARM((DIAL *, int));
 void DRedraw               PARM((DIAL *));
 int  DTrack                PARM((DIAL *, int, int));
@@ -1612,6 +1632,13 @@
 void  TIFFDialog           PARM((int));
 int   TIFFCheckEvent       PARM((XEvent *));
 void  TIFFSaveParams       PARM((char *, int));
+
+/**************************** XVPNG.C ***************************/
+int  LoadPNG               PARM((char *, PICINFO *));
+void CreatePNGW            PARM((void));
+void PNGDialog             PARM((int));
+int  PNGCheckEvent         PARM((XEvent *));
+void PNGSaveParams         PARM((char *, int));
 
 /**************************** XVPDS.C ***************************/
 int LoadPDS                PARM((char *, PICINFO *));
diff -rud --new-file xv-3.10a-orig/xvbrowse.c xv-3.10a/xvbrowse.c
--- xv-3.10a-orig/xvbrowse.c	Thu Jan 19 15:49:17 1995
+++ xv-3.10a/xvbrowse.c	Sat Apr 15 11:21:44 2000
@@ -55,6 +55,7 @@
 #include "bits/br_xpm"
 #include "bits/br_xwd"
 #include "bits/br_fits"
+#include "bits/br_png"
 
 #include "bits/br_trash"
 #include "bits/fcurs"
@@ -94,7 +95,8 @@
 #define BF_XPM      25
 #define BF_XWD      26
 #define BF_FITS     27
-#define BF_MAX      28    /* # of built-in icons */
+#define BF_PNG      28
+#define BF_MAX      29    /* # of built-in icons */
 
 #define ISLOADABLE(ftyp) (ftyp!=BF_DIR  && ftyp!=BF_CHR && ftyp!=BF_BLK && \
 			  ftyp!=BF_SOCK && ftyp!=BF_FIFO) 
@@ -524,6 +526,7 @@
   bfIcons[BF_XPM] =MakePix1(br->win,br_xpm_bits, br_xpm_width, br_xpm_height);
   bfIcons[BF_XWD] =MakePix1(br->win,br_xwd_bits, br_xwd_width, br_xwd_height);
   bfIcons[BF_FITS]=MakePix1(br->win,br_fits_bits,br_fits_width,br_fits_height);
+  bfIcons[BF_PNG]=MakePix1(br->win,br_png_bits,br_png_width,br_png_height);
 
 
   /* check that they all got built */
@@ -3020,6 +3023,7 @@
     case RFT_XPM:      bf->ftype = BF_XPM;      break;
     case RFT_XWD:      bf->ftype = BF_XWD;      break;
     case RFT_FITS:     bf->ftype = BF_FITS;     break;
+    case RFT_PNG:      bf->ftype = BF_PNG;      break;
     }
   }
 }
@@ -3567,6 +3571,7 @@
   case RFT_XPM:      strcat(str,"XPM file");              break;
   case RFT_XWD:      strcat(str,"XWD file");              break;
   case RFT_FITS:     strcat(str,"FITS file");             break;
+  case RFT_PNG:      strcat(str,"PNG file");              break;
   default:           strcat(str,"file of unknown type");  break;
   }
   
diff -rud --new-file xv-3.10a-orig/xvdial.c xv-3.10a/xvdial.c
--- xv-3.10a-orig/xvdial.c	Tue Jan  3 19:20:31 1995
+++ xv-3.10a/xvdial.c	Sat Apr 15 11:21:44 2000
@@ -41,20 +41,21 @@
 
 
 /* local functions */
-static int  whereInDial     PARM((DIAL *, int, int));
-static void drawArrow       PARM((DIAL *));
-static void drawValStr      PARM((DIAL *));
-static void drawButt        PARM((DIAL *, int, int));
-static int  computeDialVal  PARM((DIAL *, int, int));
-static void dimDial         PARM((DIAL *));
+static int    whereInDial     PARM((DIAL *, int, int));
+static void   drawArrow       PARM((DIAL *));
+static void   drawValStr      PARM((DIAL *));
+static void   drawButt        PARM((DIAL *, int, int));
+static double computeDialVal  PARM((DIAL *, int, int));
+static void   dimDial         PARM((DIAL *));
 
 
 /***************************************************/
-void DCreate(dp, parent, x, y, w, h, minv, maxv, curv, page, 
+void DCreate(dp, parent, x, y, w, h, minv, maxv, curv, inc, page, 
 	          fg, bg, hi, lo, title, units)
 DIAL         *dp;
 Window        parent;
-int           x,y,w,h,minv,maxv,curv,page;
+int           x,y,w,h;
+double        minv,maxv,curv,inc,page;
 unsigned long fg,bg,hi,lo;
 char         *title, *units;
 {
@@ -98,18 +99,18 @@
 				1,fg,bg);
   if (!dp->win) FatalError("can't create dial window");
 
-  DSetRange(dp, minv, maxv, curv, page);
+  DSetRange(dp, minv, maxv, curv, inc, page);
   XSelectInput(theDisp, dp->win, ExposureMask | ButtonPressMask);
 }
 
 
 /***************************************************/
-void DSetRange(dp, minv, maxv, curv, page)
-DIAL *dp;
-int   minv, maxv, curv, page;
+void DSetRange(dp, minv, maxv, curv, inc, page)
+DIAL   *dp;
+double  minv, maxv, curv, inc, page;
 {
   if (maxv<minv) maxv=minv;
-  dp->min = minv;    dp->max = maxv;    dp->page = page;
+  dp->min = minv; dp->max = maxv; dp->inc = inc; dp->page = page;
   dp->active =  (minv < maxv);
 
   DSetVal(dp, curv);
@@ -118,8 +119,8 @@
 
 /***************************************************/
 void DSetVal(dp, curv)
-DIAL *dp;
-int   curv;
+DIAL  *dp;
+double curv;
 {
   RANGE(curv, dp->min, dp->max);   /* make sure curv is in-range */
 
@@ -129,7 +130,7 @@
   XSetForeground(theDisp, theGC, dp->bg); 
   drawArrow(dp);
 
-  dp->val = curv;
+  dp->val = (double)((int)(curv / dp->inc + (curv > 0 ? 0.5 : -0.5))) * dp->inc;
 
   /* draw new arrow and string */
   XSetForeground(theDisp, theGC, dp->fg);
@@ -202,7 +203,8 @@
 int mx,my;
 {
   Window       rW,cW;
-  int          rx,ry, x,y, ipos, pos, lit, i, origval;
+  int          rx, ry, x, y, ipos, pos, lit;
+  double       origval;
   unsigned int mask;
 
   lit = 0;
@@ -224,9 +226,9 @@
   if (ipos != INDIAL) {
     drawButt(dp, ipos, 1);
     switch (ipos) {
-    case INCW1:  if (dp->val < dp->max) DSetVal(dp, dp->val+1); break;
+    case INCW1:  if (dp->val < dp->max) DSetVal(dp, dp->val+dp->inc);  break;
     case INCW2:  if (dp->val < dp->max) DSetVal(dp, dp->val+dp->page); break;
-    case INCCW1: if (dp->val > dp->min) DSetVal(dp, dp->val-1); break;
+    case INCCW1: if (dp->val > dp->min) DSetVal(dp, dp->val-dp->inc);  break;
     case INCCW2: if (dp->val > dp->min) DSetVal(dp, dp->val-dp->page); break;
     }
     if (dp->drawobj != NULL) (dp->drawobj)();  
@@ -235,8 +237,9 @@
   }
 
   else { 
-    i = computeDialVal(dp, mx, my);
-    DSetVal(dp, i);
+    double v;
+    v = computeDialVal(dp, mx, my);
+    DSetVal(dp, v);
     if (dp->drawobj != NULL) (dp->drawobj)();  
   }
 
@@ -246,11 +249,11 @@
     if (!(mask & Button1Mask)) break;    /* button released */
 
     if (ipos == INDIAL) {
-      int j;
-      i = computeDialVal(dp, x, y);
-      j = dp->val;
-      DSetVal(dp, i);
-      if (j != dp->val) {
+      double v, w;
+      v = computeDialVal(dp, x, y);
+      w = dp->val;
+      DSetVal(dp, v);
+      if (w != dp->val) {
 	/* track whatever dial controls */
 	if (dp->drawobj != NULL) (dp->drawobj)();  
       }
@@ -266,11 +269,11 @@
 
       if (lit) {
 	switch (ipos) {
-	case INCW1:  if (dp->val < dp->max) DSetVal(dp, dp->val+1); 
+	case INCW1:  if (dp->val < dp->max) DSetVal(dp, dp->val+dp->inc); 
 	             break;
 	case INCW2:  if (dp->val < dp->max) DSetVal(dp, dp->val+dp->page);
                      break;
-	case INCCW1: if (dp->val > dp->min) DSetVal(dp, dp->val-1);
+	case INCCW1: if (dp->val > dp->min) DSetVal(dp, dp->val-dp->inc);
                      break;
 	case INCCW2: if (dp->val > dp->min) DSetVal(dp, dp->val-dp->page);
                      break;
@@ -320,19 +323,20 @@
 static void drawArrow(dp)
 DIAL *dp;
 {
-  int i, rad, cx, cy;
+  int rad, cx, cy;
+  double v;
   XPoint arrow[4];
 
   rad = dp->rad;  cx = dp->cx;  cy = dp->cy;
 
   /* map pos (range minv..maxv) into degrees (range 240..-60) */
-  i = 240 + (-300 * (dp->val - dp->min)) / (dp->max - dp->min);
-  arrow[0].x = cx + (int) ((double) rad * .80 * cos(i * DEG2RAD));
-  arrow[0].y = cy - (int) ((double) rad * .80 * sin(i * DEG2RAD));
-  arrow[1].x = cx + (int) ((double) rad * .33 * cos((i+160) * DEG2RAD));
-  arrow[1].y = cy - (int) ((double) rad * .33 * sin((i+160) * DEG2RAD));
-  arrow[2].x = cx + (int) ((double) rad * .33 * cos((i-160) * DEG2RAD));
-  arrow[2].y = cy - (int) ((double) rad * .33 * sin((i-160) * DEG2RAD));
+  v = 240 + (-300 * (dp->val - dp->min)) / (dp->max - dp->min);
+  arrow[0].x = cx + (int) ((double) rad * .80 * cos(v * DEG2RAD));
+  arrow[0].y = cy - (int) ((double) rad * .80 * sin(v * DEG2RAD));
+  arrow[1].x = cx + (int) ((double) rad * .33 * cos((v+160) * DEG2RAD));
+  arrow[1].y = cy - (int) ((double) rad * .33 * sin((v+160) * DEG2RAD));
+  arrow[2].x = cx + (int) ((double) rad * .33 * cos((v-160) * DEG2RAD));
+  arrow[2].y = cy - (int) ((double) rad * .33 * sin((v-160) * DEG2RAD));
   arrow[3].x = arrow[0].x;
   arrow[3].y = arrow[0].y;
   XDrawLines(theDisp, dp->win, theGC, arrow, 4, CoordModeOrigin);
@@ -343,23 +347,37 @@
 static void drawValStr(dp)
 DIAL *dp;
 {
-  int  i, x1, x2;
+  int  tot, i, x1, x2;
   char foo[60], foo1[60];
 
   /* compute longest string necessary so we can right-align this thing */
-  sprintf(foo,"%d",dp->min);    x1 = strlen(foo);
-  sprintf(foo,"%d",dp->max);    x2 = strlen(foo);
+  sprintf(foo,"%d",(int)dp->min);    x1 = strlen(foo);
+  sprintf(foo,"%d",(int)dp->max);    x2 = strlen(foo);
   if (dp->min < 0 && dp->max > 0) x2++;   /* put '+' at beginning */
   i = x1;  if (x2>x1) i = x2;
   if (dp->units) i += strlen(dp->units);
 
-  if (dp->min < 0 && dp->max > 0) sprintf(foo,"%+d", dp->val);
-  else sprintf(foo,"%d", dp->val);
+  sprintf(foo,"%g",dp->inc);   /* space for decimal values */
+  tot = i + strlen(foo) - 1;   /* Take away the 0 from the beginning */
+
+  if (dp->min < 0.0 && dp->max > 0.0) sprintf(foo,"%+g", dp->val);
+  else sprintf(foo,"%g", dp->val);
+
+  if (dp->inc < 1.0)
+  {
+    int j;
+
+    if (dp->val == (double)((int)dp->val))
+      strcat(foo,".");
+
+    for (j = strlen(foo); j < tot; j++)
+      strcat(foo,"0");
+  }
 
   if (dp->units) strcat(foo,dp->units);
   foo1[0] = '\0';
   if (strlen(foo) < (size_t) i) {
-    for (i = i - strlen(foo); i>0; i--) strcat(foo1," ");
+    for (i-=strlen(foo);i>0;i--) strcat(foo1," ");
   }
   strcat(foo1, foo);
 
@@ -411,12 +429,13 @@
 
 
 /***************************************************/
-static int computeDialVal(dp, x, y)
+static double computeDialVal(dp, x, y)
 DIAL *dp;
 int x, y;
 {
-  int dx, dy, val;
-  double angle;
+  int dx, dy;
+ 
+  double angle, val;
 
   /* compute dx, dy (distance from cx, cy).  Note: +dy is *up* */
   dx = x - dp->cx;  dy = dp->cy - y;
@@ -436,8 +455,10 @@
   if (angle > 270.0) angle -= 360.0;
   if (angle < -90.0) angle += 360.0;
 
-  val = (int) ((dp->max - dp->min) * (240.0 - angle) / 300.0) + dp->min;
+  val = ((dp->max - dp->min) * (240.0 - angle) / 300.0) + dp->min;
 
+  /* round value to be an even multiple of dp->inc */
+  val = (double)((int)(val / dp->inc + 0.5)) * dp->inc;
   return val;
 }
 
diff -rud --new-file xv-3.10a-orig/xvdir.c xv-3.10a/xvdir.c
--- xv-3.10a-orig/xvdir.c	Tue Jan  3 19:21:39 1995
+++ xv-3.10a/xvdir.c	Sat Apr 15 11:21:44 2000
@@ -62,6 +62,9 @@
 #ifdef HAVE_TIFF
 			       "TIFF",
 #endif
+#ifdef HAVE_PNG
+			       "PNG",
+#endif
 			       "PostScript",
 			       "PBM/PGM/PPM (raw)",
 			       "PBM/PGM/PPM (ascii)",
@@ -1115,6 +1118,15 @@
   }
 #endif
 
+#ifdef HAVE_PNG
+  else if (fmt == F_PNG) {   /* PNG */
+    PNGSaveParams(fullname, col);
+    PNGDialog(1);                   /* open PNG Dialog box */
+    dbut[S_BOK].lit = 0;  BTRedraw(&dbut[S_BOK]);
+    return 0;                      /* always 'succeeds' */
+  }
+#endif
+
 
 
 
@@ -1168,7 +1180,8 @@
     
   case F_XPM:
     rv = WriteXPM   (fp, thepic, ptype, w, h, rp, gp, bp, nc, col, 
-		     fullname, picComments);    
+		     fullname, picComments);
+    break;
   case F_FITS:
     rv = WriteFITS  (fp, thepic, ptype, w, h, rp, gp, bp, nc, col, 
 		     picComments);    
@@ -1380,14 +1393,21 @@
       (strcmp(lowsuf,"eps" )==0) ||
       (strcmp(lowsuf,"rgb" )==0) ||
       (strcmp(lowsuf,"tga" )==0) ||
-      (strcmp(lowsuf,"xpm" )==0) ||
       (strcmp(lowsuf,"fits")==0) ||
       (strcmp(lowsuf,"fts" )==0) ||
+#ifdef HAVE_JPEG
       (strcmp(lowsuf,"jpg" )==0) ||
       (strcmp(lowsuf,"jpeg")==0) ||
       (strcmp(lowsuf,"jfif")==0) ||
+#endif
+#ifdef HAVE_TIFF
       (strcmp(lowsuf,"tif" )==0) ||
-      (strcmp(lowsuf,"tiff")==0)) {
+      (strcmp(lowsuf,"tiff")==0) ||
+#endif
+#ifdef HAVE_PNG
+      (strcmp(lowsuf,"png" )==0) ||
+#endif
+      (strcmp(lowsuf,"xpm" )==0)) {
 
     /* found one.  set lowsuf = to the new suffix, and tack on to filename */
 
@@ -1422,6 +1442,10 @@
 
 #ifdef HAVE_TIFF
     case F_TIFF:     strcpy(lowsuf,"tif");  break;
+#endif
+
+#ifdef HAVE_PNG
+    case F_PNG:      strcpy(lowsuf,"png");  break;
 #endif
     }
 
diff -rud --new-file xv-3.10a-orig/xvevent.c xv-3.10a/xvevent.c
--- xv-3.10a-orig/xvevent.c	Mon Jan 23 21:20:24 1995
+++ xv-3.10a/xvevent.c	Sat Apr 15 11:21:44 2000
@@ -154,7 +154,7 @@
      int    *donep;
 {
   static int wasInfoUp=0, wasCtrlUp=0, wasDirUp=0, wasGamUp=0, wasPsUp=0;
-  static int wasJpegUp=0, wasTiffUp=0;
+  static int wasJpegUp=0, wasTiffUp=0, wasPngUp=0;
 
   static int mainWKludge=0;  /* force first mainW expose after a mainW config
 				to redraw all of mainW */
@@ -233,6 +233,10 @@
     if (TIFFCheckEvent(event)) break;   /* event has been processed */
 #endif
 
+#ifdef HAVE_PNG
+    if (PNGCheckEvent (event)) break;   /* event has been processed */
+#endif
+
     if (GamCheckEvent (event)) break;   /* event has been processed */
     if (BrowseCheckEvent (event, &retval, &done)) break;   /* event eaten */
     if (TextCheckEvent   (event, &retval, &done)) break;   /* event eaten */
@@ -359,6 +363,10 @@
       else if (client_event->window == tiffW) TIFFDialog(0);
 #endif
 
+#ifdef HAVE_PNG
+      else if (client_event->window == pngW)  PNGDialog(0);
+#endif
+
       else if (client_event->window == mainW) Quit(0);
     }
   }
@@ -538,6 +546,10 @@
 #ifdef HAVE_TIFF
 	if (wasTiffUp) { TIFFDialog(wasTiffUp);  wasTiffUp=0; }
 #endif
+
+#ifdef HAVE_PNG
+	if (wasPngUp)  { PNGDialog(wasJpegUp);   wasPngUp=0; }
+#endif
       }
     }
   }
@@ -576,6 +588,10 @@
 #ifdef HAVE_TIFF
 	  if (tiffUp) { wasTiffUp = tiffUp;  TIFFDialog(0); }
 #endif
+
+#ifdef HAVE_PNG
+	  if (pngUp)  { wasPngUp  = pngUp;   PNGDialog(0); }
+#endif
 	}
       }
     }
@@ -1147,6 +1163,10 @@
     if (TIFFCheckEvent(event)) break;
 #endif
     
+#ifdef HAVE_PNG
+    if (PNGCheckEvent (event)) break;
+#endif
+    
     if (GamCheckEvent (event)) break;
     if (BrowseCheckEvent (event, &retval, &done)) break;
     if (TextCheckEvent   (event, &retval, &done)) break;
@@ -1366,6 +1386,10 @@
     if (TIFFCheckEvent(event)) break;
 #endif
 
+#ifdef HAVE_PNG
+    if (PNGCheckEvent (event)) break;
+#endif
+
     if (GamCheckEvent (event)) break;
     if (BrowseCheckEvent (event, &retval, &done)) break;
     if (TextCheckEvent   (event, &retval, &done)) break;
@@ -2370,6 +2394,10 @@
 
 #ifdef HAVE_TIFF
   if (tiffUp) TIFFDialog(0);  /* close tiff window */
+#endif
+
+#ifdef HAVE_PNG
+  if (pngUp) PNGDialog(0);    /* close png window */
 #endif
 
   ClosePopUp();
diff -rud --new-file xv-3.10a-orig/xvgam.c xv-3.10a/xvgam.c
--- xv-3.10a-orig/xvgam.c	Fri Jan 13 17:51:14 1995
+++ xv-3.10a/xvgam.c	Sat Apr 15 11:21:44 2000
@@ -265,11 +265,11 @@
   BTCreate(&gbut[G_BRNDCOL], cmapF,  5 + 66 + 67 + 2, 189, 66, BUTTH, 
 	   "Random", infofg, infobg, hicol, locol);
 
-  DCreate(&rhDial, cmapF, 5, 215, 66, 100,   0,360,180, 5, 
+  DCreate(&rhDial, cmapF, 5, 215, 66, 100,   0.0, 360.0, 180.0, 1.0, 5.0, 
 	  infofg, infobg, hicol, locol, "Hue", NULL);
-  DCreate(&gsDial, cmapF, 72, 215, 66, 100,  0,360,180, 5, 
+  DCreate(&gsDial, cmapF, 72, 215, 66, 100,  0.0, 360.0, 180.0, 1.0, 5.0, 
 	  infofg, infobg, hicol, locol, "Sat.", NULL);
-  DCreate(&bvDial, cmapF, 139, 215, 66, 100,   0,360,180, 5, 
+  DCreate(&bvDial, cmapF, 139, 215, 66, 100, 0.0, 360.0, 180.0, 1.0, 5.0, 
 	  infofg, infobg, hicol, locol, "Value", NULL);
 
   rhDial.drawobj = gsDial.drawobj = bvDial.drawobj = dragEditColor;
@@ -359,7 +359,7 @@
 
   srcHD.drawobj = dstHD.drawobj = whtHD.drawobj = dragHueDial;
 
-  DCreate(&satDial, hsvF, 100, 199, 100, 121, -100, 100, 0, 5, 
+  DCreate(&satDial, hsvF, 100, 199, 100, 121, -100.0, 100.0, 0.0, 1.0, 5.0, 
 	   infofg, infobg,hicol,locol, "Saturation", "%");
 
   hueRB = RBCreate(NULL, hsvF,  7, 153, "1", 
@@ -722,7 +722,7 @@
 
   if (whtHD.enabCB.val && whtHD.satval) hsvnonlinear++;
 
-  if (satDial.val != 0) hsvnonlinear++;
+  if (satDial.val != 0.0) hsvnonlinear++;
 
   /* check intensity graf */
   for (i=0; i<256 && intGraf.func[i]==i; i++);
@@ -1291,14 +1291,14 @@
     rgb2hsv(rcmap[editColor], gcmap[editColor], bcmap[editColor], &h, &s, &v);
     if (h<0) h = 0;
 
-    DSetVal(&rhDial, (int) h);
-    DSetVal(&gsDial, (int) (s*100));
-    DSetVal(&bvDial, (int) (v*100));
+    DSetVal(&rhDial, h);
+    DSetVal(&gsDial, s*100);
+    DSetVal(&bvDial, v*100);
   }
   else {
-    DSetVal(&rhDial, rcmap[editColor]);
-    DSetVal(&gsDial, gcmap[editColor]);
-    DSetVal(&bvDial, bcmap[editColor]);
+    DSetVal(&rhDial, (double)rcmap[editColor]);
+    DSetVal(&gsDial, (double)gcmap[editColor]);
+    DSetVal(&bvDial, (double)bcmap[editColor]);
   }
 }
   
@@ -1310,16 +1310,15 @@
 
   if (hsvmode) {
     int rv, gv, bv;
-    hsv2rgb((double) rhDial.val, ((double) gsDial.val) / 100.0, 
-	    ((double) bvDial.val) / 100.0, &rv, &gv, &bv);
+    hsv2rgb(rhDial.val, gsDial.val / 100.0, bvDial.val / 100.0, &rv, &gv, &bv);
     rcmap[editColor] = rv;
     gcmap[editColor] = gv;
     bcmap[editColor] = bv;
   }
   else {
-    rcmap[editColor] = rhDial.val;
-    gcmap[editColor] = gsDial.val;
-    bcmap[editColor] = bvDial.val;
+    rcmap[editColor] = (int)rhDial.val;
+    gcmap[editColor] = (int)gsDial.val;
+    bcmap[editColor] = (int)bvDial.val;
   }
 }
 
@@ -1561,9 +1560,9 @@
     gsDial.title = "Green";
     bvDial.title = "Blue";
 		   
-    DSetRange(&rhDial, 0, 255, rcmap[editColor], 16);
-    DSetRange(&gsDial, 0, 255, gcmap[editColor], 16);
-    DSetRange(&bvDial, 0, 255, bcmap[editColor], 16);
+    DSetRange(&rhDial, 0.0, 255.0, (double)rcmap[editColor], 1.0, 16.0);
+    DSetRange(&gsDial, 0.0, 255.0, (double)gcmap[editColor], 1.0, 16.0);
+    DSetRange(&bvDial, 0.0, 255.0, (double)bcmap[editColor], 1.0, 16.0);
 
     XClearWindow(theDisp, rhDial.win);    DRedraw(&rhDial);
     XClearWindow(theDisp, gsDial.win);    DRedraw(&gsDial);
@@ -1581,9 +1580,9 @@
 	    &h, &s, &v);
 
     if (h<0.0) h = 0.0;
-    DSetRange(&rhDial, 0, 360, (int) h, 5);
-    DSetRange(&gsDial, 0, 100, (int) (s*100), 5);
-    DSetRange(&bvDial, 0, 100, (int) (v*100), 5);
+    DSetRange(&rhDial, 0.0, 360.0,     h, 1.0, 5.0);
+    DSetRange(&gsDial, 0.0, 100.0, s*100, 1.0, 5.0);
+    DSetRange(&bvDial, 0.0, 100.0, v*100, 1.0, 5.0);
 
     XClearWindow(theDisp, rhDial.win);    DRedraw(&rhDial);
     XClearWindow(theDisp, gsDial.win);    DRedraw(&gsDial);
@@ -1891,7 +1890,7 @@
     }
 
     /* apply satDial value to s */
-    s = s + ((double) satDial.val) / 100.0;
+    s = s + satDial.val / 100.0;
     if (s<0.0) s = 0.0;
     if (s>1.0) s = 1.0;
 
@@ -2007,7 +2006,7 @@
 
   gs->hueRBnum = RBWhich(hueRB);
 
-  gs->satval = satDial.val;
+  gs->satval = (int)satDial.val;
   GetGrafState(&intGraf,&gs->istate);
   GetGrafState(&rGraf,  &gs->rstate);
   GetGrafState(&gGraf,  &gs->gstate);
@@ -2064,8 +2063,8 @@
     changed++;
   }
     
-  if (gs->satval != satDial.val) {
-    DSetVal(&satDial,gs->satval);
+  if (gs->satval != (int)satDial.val) {
+    DSetVal(&satDial,(double)gs->satval);
     changed++;
   }
 
@@ -3200,7 +3199,7 @@
 
   if (whtHD.enabCB.val && whtHD.satval) hsvmod++;
 
-  if (satDial.val != 0) hsvmod++;
+  if (satDial.val != 0.0) hsvmod++;
 
   /* check intensity graf */
   for (i=0; i<256; i++) {
@@ -3284,7 +3283,7 @@
       }
 
       /* apply satDial value to s */
-      s = s + satDial.val;
+      s = s + (int)satDial.val;
       if (s<  0) s =   0;
       if (s>100) s = 100;
 
diff -rud --new-file xv-3.10a-orig/xvjpeg.c xv-3.10a/xvjpeg.c
--- xv-3.10a-orig/xvjpeg.c	Thu Jan  5 06:17:13 1995
+++ xv-3.10a/xvjpeg.c	Sat Apr 15 11:21:44 2000
@@ -87,10 +87,10 @@
   
   XSelectInput(theDisp, jpegW, ExposureMask | ButtonPressMask | KeyPressMask);
   
-  DCreate(&qDial, jpegW, 10, 10, 80, 100, 1, 100, 75, 5, 
+  DCreate(&qDial, jpegW, 10, 10, 80, 100, 1.0, 100.0, 75.0, 1.0, 5.0, 
 	  infofg, infobg, hicol, locol, "Quality", "%");
   
-  DCreate(&smDial, jpegW, 120, 10, 80, 100, 0, 100, 0, 5, 
+  DCreate(&smDial, jpegW, 120, 10, 80, 100, 0.0, 100.0, 0.0, 1.0, 5.0, 
 	  infofg, infobg, hicol, locol, "Smoothing", "%");
   
   BTCreate(&jbut[J_BOK], jpegW, JWIDE-180-1, JHIGH-10-BUTTH-1, 80, BUTTH, 
@@ -759,8 +759,8 @@
 
 
   jpeg_set_defaults(&cinfo);
-  jpeg_set_quality(&cinfo, qDial.val, TRUE);
-  cinfo.smoothing_factor = smDial.val;
+  jpeg_set_quality(&cinfo, (int)qDial.val, TRUE);
+  cinfo.smoothing_factor = (int)smDial.val;
 
 
   jpeg_start_compress(&cinfo, TRUE);
@@ -769,7 +769,7 @@
   /*** COMMENT HANDLING ***/
 
   sprintf(xvcmt, "%sXV %s  Quality = %d, Smoothing = %d\n",
-	  CREATOR_STR, REVDATE, qDial.val, smDial.val);
+	  CREATOR_STR, REVDATE, (int)qDial.val, (int)smDial.val);
   
   if (picComments) {   /* append XV comment */
     char *sp, *sp1;  int done;
diff -rud --new-file xv-3.10a-orig/xvmisc.c xv-3.10a/xvmisc.c
--- xv-3.10a-orig/xvmisc.c	Fri Jan 13 21:41:34 1995
+++ xv-3.10a/xvmisc.c	Sat Apr 15 11:21:44 2000
@@ -520,6 +520,10 @@
     if (tiffW) XDestroyWindow(theDisp, tiffW);
 #endif
 
+#ifdef HAVE_PNG
+    if (pngW)  XDestroyWindow(theDisp, pngW);
+#endif
+
     /* if NOT using stdcmap for images, free stdcmap */
     if (colorMapMode != CM_STDCMAP) { 
       int j;
@@ -715,6 +719,10 @@
   
 #ifdef HAVE_TIFF
   if (tiffW) XDefineCursor(theDisp, tiffW, otherc);
+#endif
+
+#ifdef HAVE_PNG
+  if (pngW)  XDefineCursor(theDisp, pngW, otherc);
 #endif
 }
 
diff -rud --new-file xv-3.10a-orig/xvpng.c xv-3.10a/xvpng.c
--- xv-3.10a-orig/xvpng.c	Wed Dec 31 21:00:00 1969
+++ xv-3.10a/xvpng.c	Sat Apr 15 11:21:22 2000
@@ -0,0 +1,965 @@
+/*
+ * xvpng.c - load and write routines for 'PNG' format pictures
+ *
+ * callable functions
+ *
+ *    CreatePNGW()
+ *    PNGDialog(vis)
+ *    PNGCheckEvent(xev)
+ *    PNGSaveParams(fname, col)
+ *    LoadPNG(fname, pinfo)
+ */
+
+/*#include "copyright.h"*/
+/* (c) 1995 by Alexander Lehmann <lehmann@mathematik.th-darmstadt.de>
+ *   this file is a suplement to xv and is supplied under the same copying
+ *   conditions (except the shareware part)
+ * Modified by Andreas Dilger <adilger@enel.ucalgary.ca> to fix
+ *   error handling for bad PNGs, add dialogs for interlacing and
+ *   compression selection, and upgrade to libpng-0.89
+ * The copyright will be passed on to JB at some future point if he
+ * so desires.
+ */
+
+#include "xv.h"
+
+#ifdef HAVE_PNG
+
+#include "png.h"
+
+/*** Stuff for PNG Dialog box ***/
+#define PWIDE 318
+#define PHIGH 215
+
+#define DISPLAY_GAMMA 2.20  /* Default display gamma */
+/* Default zlib compression level
+#define COMPRESSION   Z_BEST_COMPRESSION
+*/
+#define COMPRESSION   6
+
+#define DWIDE     86
+#define DHIGH    104
+#define PFX PWIDE-93
+#define PFY       44
+#define PFH       20
+
+#define P_BOK    0
+#define P_BCANC  1
+#define P_NBUTTS 2
+
+#define BUTTH    24
+
+/*** local functions ***/
+static    void drawPD         PARM((int, int, int, int));
+static    void clickPD        PARM((int, int));
+static    void doCmd          PARM((int));
+static    void writePNG       PARM((void));
+static    int  WritePNG       PARM((FILE *, byte *, int, int, int,
+                                    byte *, byte *, byte *, int));
+
+static    void png_xv_error   PARM((png_struct *png_ptr, char *message));
+static    void png_xv_warning PARM((png_struct *png_ptr, char *message));
+
+/*** local variables ***/
+static char *filename;
+static char *fbasename;
+static int   colorType;
+static int   read_anything;
+static double Display_Gamma = DISPLAY_GAMMA;
+
+static DIAL  cDial, gDial;
+static BUTT  pbut[P_NBUTTS];
+static CBUTT interCB;
+static CBUTT FdefCB, FnoneCB, FsubCB, FupCB, FavgCB, FPaethCB;
+
+/**************************************************************************/
+/* PNG SAVE DIALOG ROUTINES ***********************************************/
+/**************************************************************************/
+
+
+/*******************************************/
+void CreatePNGW()
+{
+  pngW = CreateWindow("xv png", "XVPNG", NULL,
+                      PWIDE, PHIGH, infofg, infobg, 0);
+  if (!pngW) FatalError("can't create PNG window!");
+
+  XSelectInput(theDisp, pngW, ExposureMask | ButtonPressMask | KeyPressMask);
+
+  DCreate(&cDial, pngW,  12, 25, DWIDE, DHIGH, (double)Z_NO_COMPRESSION,
+          (double)Z_BEST_COMPRESSION, COMPRESSION, 1.0, 2.0,
+          infofg, infobg, hicol, locol, "Compression", NULL);
+
+  DCreate(&gDial, pngW, DWIDE+27, 25, DWIDE, DHIGH, 1.0, 3.5,DISPLAY_GAMMA,0.01,0.2,
+          infofg, infobg, hicol, locol, "Disp. Gamma", NULL);
+
+  CBCreate(&interCB, pngW,  DWIDE+30, DHIGH+3*LINEHIGH+2, "interlace",
+           infofg, infobg, hicol, locol);
+
+  CBCreate(&FdefCB,   pngW, PFX, PFY, "Default",
+           infofg, infobg, hicol, locol);
+  FdefCB.val = 1;
+
+  CBCreate(&FnoneCB,  pngW, PFX, FdefCB.y + PFH + 4, "none",
+           infofg, infobg, hicol, locol);
+  CBCreate(&FsubCB,   pngW, PFX, FnoneCB.y + PFH, "sub",
+           infofg, infobg, hicol, locol);
+  CBCreate(&FupCB,    pngW, PFX, FsubCB.y  + PFH, "up",
+           infofg, infobg, hicol, locol);
+  CBCreate(&FavgCB,   pngW, PFX, FupCB.y   + PFH, "average",
+           infofg, infobg, hicol, locol);
+  CBCreate(&FPaethCB, pngW, PFX, FavgCB.y  + PFH, "Paeth",
+           infofg, infobg, hicol, locol);
+
+  FnoneCB.val = FsubCB.val = FupCB.val = FavgCB.val = FPaethCB.val = 1;
+  CBSetActive(&FnoneCB, !FdefCB.val);
+  CBSetActive(&FsubCB, !FdefCB.val);
+  CBSetActive(&FupCB, !FdefCB.val);
+  CBSetActive(&FavgCB, !FdefCB.val);
+  CBSetActive(&FPaethCB, !FdefCB.val);
+
+  BTCreate(&pbut[P_BOK], pngW, PWIDE-180-1, PHIGH-10-BUTTH-1, 80, BUTTH,
+          "Ok", infofg, infobg, hicol, locol);
+  BTCreate(&pbut[P_BCANC], pngW, PWIDE-90-1, PHIGH-10-BUTTH-1, 80, BUTTH,
+          "Cancel", infofg, infobg, hicol, locol);
+
+  XMapSubwindows(theDisp, pngW);          
+}
+
+
+/*******************************************/
+void PNGDialog(vis)
+     int vis;
+{
+  if (vis) {
+    CenterMapWindow(pngW, pbut[P_BOK].x + (int) pbut[P_BOK].w/2,
+                          pbut[P_BOK].y + (int) pbut[P_BOK].h/2,
+                    PWIDE, PHIGH);
+  }
+  else XUnmapWindow(theDisp, pngW);
+  pngUp = vis;
+}
+
+
+/*******************************************/
+int PNGCheckEvent(xev)
+     XEvent *xev;
+{
+  /* check event to see if it's for one of our subwindows.  If it is,
+     deal accordingly, and return '1'.  Otherwise, return '0' */
+
+  int rv;
+  rv = 1;
+
+  if (!pngUp) return 0;
+
+  if (xev->type == Expose) {
+    int x,y,w,h;
+    XExposeEvent *e = (XExposeEvent *) xev;
+    x = e->x; y = e->y; w = e->width; h = e->height;
+
+    /* throw away excess expose events for 'dumb' windows */
+    if (e->count > 0 && (e->window == cDial.win)) {}
+
+    else if (e->window == pngW)        drawPD(x, y, w, h);
+    else if (e->window == cDial.win)   DRedraw(&cDial);
+    else if (e->window == gDial.win)   DRedraw(&gDial);
+    else rv = 0;
+  }
+
+  else if (xev->type == ButtonPress) {
+    XButtonEvent *e = (XButtonEvent *) xev;
+    int x,y;
+    x = e->x;  y = e->y;
+    
+    if (e->button == Button1) {
+      if      (e->window == pngW)       clickPD(x,y);
+      else if (e->window == cDial.win)  DTrack(&cDial,x,y);
+      else if (e->window == gDial.win)  DTrack(&gDial,x,y);
+      else rv = 0;
+    }  /* button1 */
+    else rv = 0;
+  }  /* button press */
+
+  else if (xev->type == KeyPress) {
+    XKeyEvent *e = (XKeyEvent *) xev;
+    char buf[128];  KeySym ks;
+    int stlen;
+    
+    stlen = XLookupString(e,buf,128,&ks,(XComposeStatus *) NULL);
+    buf[stlen] = '\0';
+    
+    RemapKeyCheck(ks, buf, &stlen);
+    
+    if (e->window == pngW) {
+      if (stlen) {
+        if (buf[0] == '\r' || buf[0] == '\n') { /* enter */
+          FakeButtonPress(&pbut[P_BOK]);
+        }
+        else if (buf[0] == '\033') {            /* ESC */
+          FakeButtonPress(&pbut[P_BCANC]);
+        }
+      }
+    }
+    else rv = 0;
+  }
+  else rv = 0;
+
+  if (rv==0 && (xev->type == ButtonPress || xev->type == KeyPress)) {
+    XBell(theDisp, 50);
+    rv = 1;   /* eat it */
+  }
+
+  return rv;
+}
+
+
+/*******************************************/
+void PNGSaveParams(fname, col)
+     char *fname;
+     int col;
+{
+  filename = fname;
+  colorType = col;
+}
+
+
+/*******************************************/
+static void drawPD(x, y, w, h)
+     int x, y, w, h;
+{
+  char *title   = "Save PNG file...";
+
+  char ctitle1[20];
+  char *ctitle2 = "Useful range";
+  char *ctitle3 = "is 2 - 7.";
+  char *ctitle4 = "Uncompressed = 0";
+
+  char *ftitle  = "Row Filters:";
+
+  char gtitle[20];
+
+  int i;
+  XRectangle xr;
+  
+  xr.x = x;  xr.y = y;  xr.width = w;  xr.height = h;
+  XSetClipRectangles(theDisp, theGC, 0,0, &xr, 1, Unsorted);
+
+  XSetForeground(theDisp, theGC, infofg);
+  XSetBackground(theDisp, theGC, infobg);
+
+  for (i=0; i<P_NBUTTS; i++) BTRedraw(&pbut[i]);
+
+  DrawString(pngW,       15,  6+ASCENT,                          title);
+
+  sprintf(ctitle1, "Default = %d", COMPRESSION);
+  DrawString(pngW,       18,  6+DHIGH+cDial.y+ASCENT,            ctitle1);
+  DrawString(pngW,       17,  6+DHIGH+cDial.y+ASCENT+LINEHIGH,   ctitle2);
+  DrawString(pngW,       17,  6+DHIGH+cDial.y+ASCENT+2*LINEHIGH, ctitle3);
+  DrawString(pngW,       17,  6+DHIGH+cDial.y+ASCENT+3*LINEHIGH, ctitle4);
+
+  sprintf(gtitle, "Default = %g", DISPLAY_GAMMA);
+  DrawString(pngW, DWIDE+30,  6+DHIGH+gDial.y+ASCENT,            gtitle);
+
+  ULineString(pngW, FdefCB.x, FdefCB.y-3-DESCENT, ftitle);
+  XDrawRectangle(theDisp, pngW, theGC, FdefCB.x-11, FdefCB.y-LINEHIGH-3,
+                                       93, 8*LINEHIGH+15);
+  CBRedraw(&FdefCB);
+  XDrawLine(theDisp, pngW, theGC, FdefCB.x-11, FdefCB.y+LINEHIGH+4,
+                                  FdefCB.x+82, FdefCB.y+LINEHIGH+4);
+
+  CBRedraw(&FnoneCB);
+  CBRedraw(&FupCB);
+  CBRedraw(&FsubCB);
+  CBRedraw(&FavgCB);
+  CBRedraw(&FPaethCB);
+
+  CBRedraw(&interCB);
+
+  XSetClipMask(theDisp, theGC, None);
+}
+
+
+/*******************************************/
+static void clickPD(x,y)
+     int x,y;
+{
+  int i;
+  BUTT *bp;
+
+  /* check BUTTs */
+  
+  for (i=0; i<P_NBUTTS; i++) {
+    bp = &pbut[i];
+    if (PTINRECT(x, y, bp->x, bp->y, bp->w, bp->h)) break;
+  }
+  
+  if (i<P_NBUTTS) {  /* found one */
+    if (BTTrack(bp)) doCmd(i);
+  }
+
+  /* check CBUTTs */
+
+  else if (CBClick(&FdefCB,x,y)) {
+    int oldval = FdefCB.val;
+
+    CBTrack(&FdefCB);
+
+    if (oldval != FdefCB.val)
+    {
+      CBSetActive(&FnoneCB, !FdefCB.val);
+      CBSetActive(&FsubCB, !FdefCB.val);
+      CBSetActive(&FupCB, !FdefCB.val);
+      CBSetActive(&FavgCB, !FdefCB.val);
+      CBSetActive(&FPaethCB, !FdefCB.val);
+
+      CBRedraw(&FnoneCB);
+      CBRedraw(&FupCB);
+      CBRedraw(&FsubCB);
+      CBRedraw(&FavgCB);
+      CBRedraw(&FPaethCB);
+    }
+  }
+  else if (CBClick(&FnoneCB,x,y))  CBTrack(&FnoneCB);
+  else if (CBClick(&FsubCB,x,y))   CBTrack(&FsubCB);
+  else if (CBClick(&FupCB,x,y))    CBTrack(&FupCB);
+  else if (CBClick(&FavgCB,x,y))   CBTrack(&FavgCB);
+  else if (CBClick(&FPaethCB,x,y)) CBTrack(&FPaethCB);
+  else if (CBClick(&interCB,x,y))  CBTrack(&interCB);
+}
+
+
+/*******************************************/
+static void doCmd(cmd)
+     int cmd;
+{
+  switch (cmd) {
+  case P_BOK: {
+    char *fullname;
+
+    writePNG();
+    PNGDialog(0);
+    
+    fullname = GetDirFullName();
+    if (!ISPIPE(fullname[0])) {
+      XVCreatedFile(fullname);
+      StickInCtrlList(0);
+    }
+  }
+    break;
+
+  case P_BCANC:  PNGDialog(0);  break;
+
+  default:        break;
+  }
+}
+
+
+/*******************************************/
+static void writePNG()
+{
+  FILE       *fp;
+  int         w, h, nc, rv, ptype, pfree;
+  byte       *inpix, *rmap, *gmap, *bmap;
+
+  fp = OpenOutFile(filename);
+  if (!fp) return;
+
+  fbasename = BaseName(filename);
+
+  WaitCursor();
+  inpix = GenSavePic(&ptype, &w, &h, &pfree, &nc, &rmap, &gmap, &bmap);
+
+  rv = WritePNG(fp, inpix, ptype, w, h, rmap, gmap, bmap, nc);
+
+  SetCursors(-1);
+
+  if (CloseOutFile(fp, filename, rv) == 0) DirBox(0);
+
+  if (pfree) free(inpix);
+}
+
+
+/*******************************************/
+int WritePNG(fp, pic, ptype, w, h, rmap, gmap, bmap, numcols)
+     FILE *fp;
+     byte *pic;
+     int   ptype, w, h;
+     byte *rmap, *gmap, *bmap;
+     int   numcols;
+{
+  png_struct *png_ptr;
+  png_info   *info_ptr;
+  png_color   palette[256];
+  png_textp   text;
+  byte        remap[256];
+  int         i, filter, linesize = 0, pass;
+  byte       *p, *png_line;
+  char        software[256];
+  char       *savecmnt = NULL;
+
+  if ((png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL,
+       png_xv_error, png_xv_warning)) == NULL) {
+    FatalError("malloc failure in WritePNG");
+  }
+
+  if ((info_ptr = png_create_info_struct(png_ptr)) == NULL)
+  {
+    png_destroy_write_struct(&png_ptr, &info_ptr);
+    FatalError("malloc failure in WritePNG");
+  }
+
+  if (setjmp(png_ptr->jmpbuf)) {
+    png_destroy_write_struct(&png_ptr, &info_ptr);
+    return -1;
+  }
+
+  png_init_io(png_ptr, fp);
+
+  png_set_compression_level(png_ptr, (int)cDial.val);
+
+  /* Don't bother filtering if we aren't compressing the image */
+  if (FdefCB.val)
+  {
+    if ((int)cDial.val == 0)
+      png_set_filter(png_ptr, 0, PNG_FILTER_NONE);
+  }
+  else
+  {
+    filter  = FnoneCB.val  ? PNG_FILTER_NONE  : 0;
+    filter |= FsubCB.val   ? PNG_FILTER_SUB   : 0;
+    filter |= FupCB.val    ? PNG_FILTER_UP    : 0;
+    filter |= FavgCB.val   ? PNG_FILTER_AVG   : 0;
+    filter |= FPaethCB.val ? PNG_FILTER_PAETH : 0;
+
+    png_set_filter(png_ptr, 0, filter);
+  }
+
+  info_ptr->width = w;
+  info_ptr->height = h;
+
+  info_ptr->interlace_type = interCB.val ? 1 : 0;
+
+  if (colorType == F_FULLCOLOR || colorType == F_REDUCED) {
+    if(ptype == PIC24) {
+      linesize = 3*w;
+      info_ptr->color_type = PNG_COLOR_TYPE_RGB;
+      info_ptr->bit_depth = 8;
+    } else {
+      linesize = w;
+      info_ptr->color_type = PNG_COLOR_TYPE_PALETTE;
+      if(numcols <= 2)
+        info_ptr->bit_depth = 1;
+      else
+      if(numcols <= 4)
+        info_ptr->bit_depth = 2;
+      else
+      if(numcols <= 16)
+        info_ptr->bit_depth = 4;
+      else
+        info_ptr->bit_depth = 8;
+
+      for(i = 0; i < numcols; i++) {
+        palette[i].red   = rmap[i];
+        palette[i].green = gmap[i];
+        palette[i].blue  = bmap[i];
+      }
+      info_ptr->num_palette = numcols;
+      info_ptr->palette = palette;
+      info_ptr->valid |= PNG_INFO_PLTE;
+    }
+  }
+
+  else if(colorType == F_GREYSCALE || colorType == F_BWDITHER) {
+    info_ptr->color_type = PNG_COLOR_TYPE_GRAY;
+    if(colorType == F_BWDITHER) {
+      /* shouldn't happen */
+      if (ptype == PIC24) FatalError("PIC24 and B/W Stipple in WritePNG()");
+
+      info_ptr->bit_depth = 1;
+      if(MONO(rmap[0], gmap[0], bmap[0]) > MONO(rmap[1], gmap[1], bmap[1])) {
+        remap[0] = 1;
+        remap[1] = 0;
+      }
+      else {
+        remap[0] = 0;
+        remap[1] = 1;
+      }
+      linesize = w;
+    }
+    else {
+      if(ptype == PIC24) {
+        linesize = w*3;
+        info_ptr->bit_depth = 8;
+      }
+      else {
+        int low_presc;
+
+        linesize = w;
+
+        for(i = 0; i < numcols; i++)
+          remap[i] = MONO(rmap[i], gmap[i], bmap[i]);
+
+        for(; i < 256; i++)
+          remap[i]=0;
+
+        info_ptr->bit_depth = 8;
+
+        /* Note that this fails most of the time because of gamma */
+        /* try to adjust to 4 bit prescision grayscale */
+
+        low_presc=1;
+
+        for(i = 0; i < numcols; i++) {
+          if((remap[i] & 0x0f) * 0x11 != remap[i]) {
+            low_presc = 0;
+            break;
+          }
+        }
+
+        if(low_presc) {
+          for(i = 0; i < numcols; i++) {
+            remap[i] &= 0xf;
+          }
+          info_ptr->bit_depth = 4;
+
+          /* try to adjust to 2 bit prescision grayscale */
+
+          for(i = 0; i < numcols; i++) {
+            if((remap[i] & 0x03) * 0x05 != remap[i]) {
+              low_presc = 0;
+              break;
+            }
+          }
+        }
+
+        if(low_presc) {
+          for(i = 0; i < numcols; i++) {
+            remap[i] &= 3;
+          }
+          info_ptr->bit_depth = 2;
+
+          /* try to adjust to 1 bit prescision grayscale */
+
+          for(i = 0; i < numcols; i++) {
+            if((remap[i] & 0x01) * 0x03 != remap[i]) {
+              low_presc = 0;
+              break;
+            }
+          }
+        }
+
+        if(low_presc) {
+          for(i = 0; i < numcols; i++) {
+            remap[i] &= 1;
+          }
+          info_ptr->bit_depth = 1;
+        }
+      }
+    }
+  }
+
+  else
+    png_error(png_ptr, "Unknown colorstyle in WritePNG");
+
+  if ((text = (png_textp)malloc(sizeof(png_text)))) {
+    sprintf(software, "XV %s", REVDATE);
+
+    text->compression = -1;
+    text->key = "Software";
+    text->text = software;
+    text->text_length = strlen(text->text);
+
+    info_ptr->max_text = 1;
+    info_ptr->num_text = 1;
+    info_ptr->text = text;
+  }
+
+  Display_Gamma = gDial.val;  /* Save the current gamma for loading */
+
+  info_ptr->gamma = 1.0/gDial.val;
+  info_ptr->valid |= PNG_INFO_gAMA;
+
+  png_write_info(png_ptr, info_ptr);
+
+  if(info_ptr->bit_depth < 8)
+    png_set_packing(png_ptr);
+
+  pass=png_set_interlace_handling(png_ptr);
+
+  if((png_line = malloc(linesize)) == NULL)
+    png_error(png_ptr, "cannot allocate temp image line");
+
+  for(i = 0; i < pass; i++) {
+    int j;
+    p = pic;
+    for(j = 0; j < h; j++) {
+  fflush(stdout);
+      if(info_ptr->color_type == PNG_COLOR_TYPE_GRAY) {
+        int k;
+        for(k = 0; k < w; k++)
+          png_line[k] = ptype==PIC24 ? MONO(p[k*3], p[k*3+1], p[k*3+2]) :
+                                       remap[p[k]];
+        png_write_row(png_ptr, png_line);
+      } else  /* rbg or palette */
+        png_write_row(png_ptr, p);
+      if((j & 0x1f) == 0) WaitCursor();
+      p += linesize;
+    }
+  }
+
+  free(png_line);
+
+  if (text)
+  {
+    if (picComments && strlen(picComments) &&
+        (savecmnt = (char *)malloc((strlen(picComments) + 1)*sizeof(char)))) {
+      png_textp tp;
+      char *comment, *key;
+
+      strcpy(savecmnt, picComments);
+      key = savecmnt;
+      tp = text;
+      info_ptr->num_text = 0;
+
+      comment = strchr(key, ':');
+
+      do  {
+        /* Allocate a larger structure for comments if necessary */
+        if (info_ptr->num_text >= info_ptr->max_text)
+        {
+          if ((tp =
+              realloc(text, (info_ptr->num_text + 2)*sizeof(png_text))) == NULL)
+          {
+            break;
+          }
+          else
+          {
+            text = tp;
+            tp = &text[info_ptr->num_text];
+            info_ptr->max_text += 2;
+          }
+        }
+
+        /* See if it looks like a PNG keyword from LoadPNG */
+        if(comment && comment[1] == ':' && comment - key <= 80) {
+          *(comment++) = '\0';
+          *(comment++) = '\0';
+
+          /* If the comment is the 'Software' chunk XV writes, we remove it,
+             since we have already stored one */
+          if (strcmp(key, "Software") == 0 && strncmp(comment, "XV", 2) == 0) {
+            key = strchr(comment, '\n');
+            if(key)
+              key++; /* skip \n */
+            comment = strchr(key, ':');
+          }
+          /* We have another keyword and/or comment to write out */
+          else {
+            tp->key = key;
+            tp->text = comment;
+
+            /* We have to find the end of this comment, and the next keyword
+               if there is one */
+            do {
+              key = comment = strchr(comment, ':');
+            } while (key && key[1] != ':');
+
+            /* It looks like another keyword, go backward to the beginning */
+            if (key) {
+              while(key > tp->text && *key != '\n')
+                key--;
+
+              if (key > tp->text && comment - key <= 80) {
+                *key = '\0';
+                key++;
+              }
+            }
+
+            tp->text_length = strlen(tp->text);
+
+            /* We don't have another keyword, so remove the last newline */
+            if (!key && tp->text[tp->text_length - 1] == '\n')
+            {
+              tp->text[tp->text_length] = '\0';
+              tp->text_length--;
+            }
+
+            tp->compression = tp->text_length > 640 ? 0 : -1;
+            info_ptr->num_text++;
+            tp++;
+          }
+        }
+        /* It is just a generic comment */
+        else {
+          tp->key = "Comment";
+          tp->text = key;
+          tp->text_length = strlen(tp->text);
+          tp->compression = tp->text_length > 750 ? 0 : -1;
+          info_ptr->num_text++;
+          key = NULL;
+        }
+      } while (key && *key);
+    }
+    else
+    {
+      info_ptr->num_text = 0;
+    }
+  }
+  info_ptr->text = text;
+
+  png_convert_from_time_t(&(info_ptr->mod_time), time(NULL));
+  info_ptr->valid |= PNG_INFO_tIME;
+
+  png_write_end(png_ptr, info_ptr);
+  png_destroy_write_struct(&png_ptr, &info_ptr);
+
+  if (text)
+  {
+    free(text);
+    if (savecmnt)
+      free(savecmnt);
+  }
+
+  return 0;
+}
+
+
+/*******************************************/
+int LoadPNG(fname, pinfo)
+     char    *fname;
+     PICINFO *pinfo;
+/*******************************************/
+{
+  /* returns '1' on success */
+
+  FILE  *fp;
+  png_struct *png_ptr;
+  png_info *info_ptr;
+  png_color_16 my_background;
+  int i,j;
+  int linesize;
+  int filesize;
+  int pass;
+  size_t commentsize;
+
+  fbasename = BaseName(fname);
+
+  pinfo->pic     = (byte *) NULL;
+  pinfo->comment = (char *) NULL;
+
+  read_anything=0;
+
+  /* open the file */
+  fp = xv_fopen(fname,"r");
+  if (!fp)
+  {
+    SetISTR(ISTR_WARNING,"%s:  can't open file", fname);
+    return 0;
+  }
+
+  /* find the size of the file */
+  fseek(fp, 0L, 2);
+  filesize = ftell(fp);
+  fseek(fp, 0L, 0);
+  
+  png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL,
+                                   png_xv_error, png_xv_warning);
+  if(!png_ptr) {
+    fclose(fp);
+    FatalError("malloc failure in LoadPNG");
+  }
+
+  info_ptr = png_create_info_struct(png_ptr);
+
+  if(!info_ptr) {
+    fclose(fp);
+    png_destroy_read_struct(&png_ptr, (png_infopp)NULL, (png_infopp)NULL);
+    FatalError("malloc failure in LoadPNG");
+  }
+
+  if(setjmp(png_ptr->jmpbuf)) {
+    fclose(fp);
+    png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL);
+    if(!read_anything) {
+      if(pinfo->pic) {
+        free(pinfo->pic);
+        pinfo->pic = NULL;
+      }
+      if(pinfo->comment) {
+        free(pinfo->comment);
+        pinfo->comment = NULL;
+      }
+    }
+    return read_anything;
+  }
+
+  png_init_io(png_ptr, fp);
+  png_read_info(png_ptr, info_ptr);
+
+  pinfo->w = pinfo->normw = info_ptr->width;
+  pinfo->h = pinfo->normh = info_ptr->height;
+
+  pinfo->frmType = F_PNG;
+
+  sprintf(pinfo->fullInfo, "PNG, %d bit ",
+          info_ptr->bit_depth * info_ptr->channels);
+
+  switch(info_ptr->color_type) {
+    case PNG_COLOR_TYPE_PALETTE:
+      strcat(pinfo->fullInfo, "palette color");
+      break;
+
+    case PNG_COLOR_TYPE_GRAY:
+      strcat(pinfo->fullInfo, "grayscale");
+      break;
+
+    case PNG_COLOR_TYPE_GRAY_ALPHA:
+      strcat(pinfo->fullInfo, "grayscale+alpha");
+      break;
+
+    case PNG_COLOR_TYPE_RGB:
+      strcat(pinfo->fullInfo, "truecolor");
+      break;
+
+    case PNG_COLOR_TYPE_RGB_ALPHA:
+      strcat(pinfo->fullInfo, "truecolor+alpha");
+      break;
+  }
+
+  sprintf(pinfo->fullInfo + strlen(pinfo->fullInfo),
+	  ", %sinterlaced. (%d bytes)",
+	  info_ptr->interlace_type ? "" : "non-", filesize);
+
+  sprintf(pinfo->shrtInfo, "%dx%d PNG", info_ptr->width, info_ptr->height);
+
+  if (info_ptr->bit_depth < 8)
+      png_set_packing(png_ptr);
+
+  if (info_ptr->valid & PNG_INFO_gAMA)
+    png_set_gamma(png_ptr, Display_Gamma, info_ptr->gamma);
+  else
+    png_set_gamma(png_ptr, Display_Gamma, 0.45);
+
+  if (info_ptr->valid & PNG_INFO_bKGD)
+    png_set_background(png_ptr, &info_ptr->background,
+                       PNG_BACKGROUND_GAMMA_FILE, 1, 1.0);
+  else {
+    my_background.red = my_background.green = my_background.blue =
+      my_background.gray = 0;
+    png_set_background(png_ptr, &my_background, PNG_BACKGROUND_GAMMA_SCREEN,
+                       0, Display_Gamma);
+  }
+
+  if (info_ptr->bit_depth == 16)
+    png_set_strip_16(png_ptr);
+
+  if (info_ptr->color_type == PNG_COLOR_TYPE_GRAY ||
+      info_ptr->color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
+  {
+    if (info_ptr->bit_depth == 1)
+      pinfo->colType = F_BWDITHER;
+    else
+      pinfo->colType = F_GREYSCALE;
+    png_set_expand(png_ptr);
+  }
+
+  pass=png_set_interlace_handling(png_ptr);
+
+  png_read_update_info(png_ptr, info_ptr);
+
+  if(info_ptr->color_type == PNG_COLOR_TYPE_RGB ||
+     info_ptr->color_type == PNG_COLOR_TYPE_RGB_ALPHA) {
+    linesize = pinfo->w * 3;
+    pinfo->colType = F_FULLCOLOR;
+    pinfo->type = PIC24;
+  } else {
+    linesize = pinfo->w;
+    pinfo->type = PIC8;
+    if(info_ptr->color_type == PNG_COLOR_TYPE_GRAY ||
+       info_ptr->color_type == PNG_COLOR_TYPE_GRAY_ALPHA) {
+      for(i = 0; i < 256; i++)
+        pinfo->r[i] = pinfo->g[i] = pinfo->b[i] = i;
+    } else {
+      pinfo->colType = F_FULLCOLOR;
+      for(i = 0; i < info_ptr->num_palette; i++) {
+        pinfo->r[i] = info_ptr->palette[i].red;
+        pinfo->g[i] = info_ptr->palette[i].green;
+        pinfo->b[i] = info_ptr->palette[i].blue;
+      }
+    }
+  }
+  pinfo->pic = calloc((size_t)(linesize*pinfo->h), (size_t)1);
+
+  if(!pinfo->pic) {
+    png_error(png_ptr, "can't allocate space for PNG image");
+  }
+
+  png_start_read_image(png_ptr);
+
+  for(i = 0; i < pass; i++) {
+    byte *p = pinfo->pic;
+    for(j = 0; j < pinfo->h; j++) {
+      png_read_row(png_ptr, p, NULL);
+      read_anything = 1;
+      if((j & 0x1f) == 0) WaitCursor();
+      p += linesize;
+    }
+  }
+
+  png_read_end(png_ptr, info_ptr);
+
+  if(info_ptr->num_text > 0) {
+    commentsize = 1;
+
+    for(i = 0; i < info_ptr->num_text; i++)
+      commentsize += strlen(info_ptr->text[i].key) + 1 +
+                     info_ptr->text[i].text_length + 2;
+
+    if((pinfo->comment = malloc(commentsize)) == NULL) {
+      png_warning(png_ptr,"can't allocate comment string");
+    }
+    else {
+      pinfo->comment[0] = '\0';
+      for(i = 0; i < info_ptr->num_text; i++) {
+        strcat(pinfo->comment, info_ptr->text[i].key);
+        strcat(pinfo->comment, "::");
+        strcat(pinfo->comment, info_ptr->text[i].text);
+        strcat(pinfo->comment, "\n");
+      }
+    }
+  }
+
+  png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL);
+
+  fclose(fp);
+
+  return 1;
+}
+
+
+/*******************************************/
+static void
+png_xv_error(png_ptr, message)
+     png_struct *png_ptr;
+     char *message;
+{
+  SetISTR(ISTR_WARNING,"%s:  libpng error: %s", fbasename, message);
+
+  longjmp(png_ptr->jmpbuf, 1);
+}
+
+
+/*******************************************/
+static void
+png_xv_warning(png_ptr, message)
+     png_struct *png_ptr;
+     char *message;
+{
+  if (!png_ptr)
+    return;
+
+  SetISTR(ISTR_WARNING,"%s:  libpng warning: %s", fbasename, message);
+}
+
+#endif
diff -rud --new-file xv-3.10a-orig/xvpopup.c xv-3.10a/xvpopup.c
--- xv-3.10a-orig/xvpopup.c	Thu Jan 19 16:09:31 1995
+++ xv-3.10a/xvpopup.c	Sat Apr 15 11:21:44 2000
@@ -200,14 +200,14 @@
     
     if (!padHaveDooDads) {
       DCreate(&padWDial, popW, 16,      puhigh-16-100-1,75,100,
-	      1, 2048, pWIDE, 10,
+	      1.0, 2048.0, (double)pWIDE, 1.0, 10.0,
 	      infofg, infobg, hicol, locol, "Width", NULL);
       DCreate(&padHDial, popW, 16+1+75, puhigh-16-100-1,75,100,
-	      1, 2048, pHIGH, 10,
+	      1.0, 2048.0, (double)pHIGH, 1.0, 10.0,
 	      infofg, infobg, hicol, locol, "Height", NULL);
 
       DCreate(&padODial, popW, 16+1+75+75+9, puhigh-16-100-1,75,100,
-	      0, 100, 100, 10,
+	      0.0, 100.0, 100.0, 1.0, 10.0,
 	      infofg, infobg, hicol, locol, "Opaque", NULL);
 
       MBCreate(&padMthdMB, popW, 100-2+44, 10, 140, 19, NULL,
@@ -258,9 +258,9 @@
   else if (poptyp == ISPAD) {
     BTSetActive(&bts[0], (int) strlen(gsBuf));
     i = pWIDE * 3;  RANGE(i,2048,9999);  
-    DSetRange(&padWDial, 1, i, padWDial.val, 10);
+    DSetRange(&padWDial, 1.0, (double)i, padWDial.val, 1.0, 10.0);
     i = pHIGH * 3;  RANGE(i,2048,9999);  
-    DSetRange(&padHDial, 1, i, padHDial.val, 10);
+    DSetRange(&padHDial, 1.0, (double)i, padHDial.val, 1.0, 10.0);
 
     DSetActive(&padWDial, (padMode!=PAD_LOAD));  /* DSetRange activates dial */
     DSetActive(&padHDial, (padMode!=PAD_LOAD));
@@ -465,9 +465,9 @@
   changedGSBuf();      /* careful!  popW doesn't exist yet! */
 
   if (padHaveDooDads) { 
-    oldW = padWDial.val;  
-    oldH = padHDial.val;
-    oldO = padODial.val;
+    oldW = (int)padWDial.val;  
+    oldH = (int)padHDial.val;
+    oldO = (int)padODial.val;
   }
   else { oldW = pWIDE;  oldH = pHIGH;  oldO = 100; }
 
@@ -486,9 +486,9 @@
   }
 
   if (rv == 1) {   /* cancelled:  restore normal values */
-    DSetVal(&padWDial, oldW);
-    DSetVal(&padHDial, oldH);
-    DSetVal(&padODial, oldO);
+    DSetVal(&padWDial, (double)oldW);
+    DSetVal(&padHDial, (double)oldH);
+    DSetVal(&padODial, (double)oldO);
   }
 
   XUnmapWindow(theDisp, padWDial.win);
@@ -498,9 +498,9 @@
   /* load up return values */
   *pMode   = padMode;  
   *pStr    = padBuf;  
-  *pWide   = padWDial.val;
-  *pHigh   = padHDial.val;
-  *pOpaque = padODial.val;
+  *pWide   = (int)padWDial.val;
+  *pHigh   = (int)padHDial.val;
+  *pOpaque = (int)padODial.val;
   *pOmode  = padOMode;
 
   return rv;
@@ -972,8 +972,8 @@
   else if (popUp == ISPAD) {
     if (PTINRECT(x, y, padDButt.x, padDButt.y, padDButt.w, padDButt.h)) {
       if (BTTrack(&padDButt)) {
-	DSetVal(&padWDial, pWIDE);
-	DSetVal(&padHDial, pHIGH);
+	DSetVal(&padWDial, (double)pWIDE);
+	DSetVal(&padHDial, (double)pHIGH);
       }
     }
 
diff -rud --new-file xv-3.10a-orig/xvps.c xv-3.10a/xvps.c
--- xv-3.10a-orig/xvps.c	Thu Dec 22 20:34:42 1994
+++ xv-3.10a/xvps.c	Sat Apr 15 11:21:44 2000
@@ -139,9 +139,9 @@
   CBCreate(&encapsCB, psW, 240, 7, "preview", infofg, infobg, hicol, locol);
   CBCreate(&pscompCB, psW, 331, 7, "compress", infofg, infobg, hicol, locol);
 
-  DCreate(&xsDial, psW, 240, 30, 80, 100, 10, 800, 100, 5, 
+  DCreate(&xsDial, psW, 240, 30, 80, 100, 10.0, 800.0, 100.0, 0.5, 5.0, 
 	  infofg, infobg, hicol, locol, "Width", "%");
-  DCreate(&ysDial, psW, 331, 30, 80, 100, 10, 800, 100, 5, 
+  DCreate(&ysDial, psW, 331, 30, 80, 100, 10.0, 800.0, 100.0, 0.5, 5.0, 
 	  infofg, infobg, hicol, locol, "Height", "%");
   xsDial.drawobj = changedScale;
   ysDial.drawobj = changedScale;
@@ -236,10 +236,10 @@
 
   if (rd_int("psres")) {             /* xv.psres:  default paper resolution */
     if (def_int >= 10 && def_int <= 720) {
-      int i = (int) ((PIX2INCH * 100) / def_int);
+      double v = (PIX2INCH * 100) / def_int;
 
-      DSetVal(&xsDial, i);
-      DSetVal(&ysDial, i);
+      DSetVal(&xsDial, v);
+      DSetVal(&ysDial, v);
     }
   }
 
@@ -836,7 +836,7 @@
   if (scx < scy) { sz_iny = h * scx; }
             else { sz_inx = w * scy; }
 
-  DSetVal(&xsDial, (int) ((100 * (sz_inx * PIX2INCH) / w) + .5));
+  DSetVal(&xsDial, 100 * (sz_inx * PIX2INCH) / w);
   DSetVal(&ysDial, xsDial.val);
 
   sz_inx = (double) w / PIX2INCH * (xsDial.val / 100.0);  
