about summary refs log tree commit diff
diff options
context:
space:
mode:
authorgiraffedata <giraffedata@9d0c8265-081b-0410-96cb-a4ca84ce46f8>2020-09-26 23:52:08 +0000
committergiraffedata <giraffedata@9d0c8265-081b-0410-96cb-a4ca84ce46f8>2020-09-26 23:52:08 +0000
commit4c361c0a7638b4f068e8b524e4ff43374a286018 (patch)
tree0aef192966a1ae996a9f2a0364f3ccbb15d512c7
parentcd7f17a619a0421a1dfb2ceb09f4af60ead8ad5f (diff)
downloadnetpbm-mirror-4c361c0a7638b4f068e8b524e4ff43374a286018.tar.gz
netpbm-mirror-4c361c0a7638b4f068e8b524e4ff43374a286018.tar.xz
netpbm-mirror-4c361c0a7638b4f068e8b524e4ff43374a286018.zip
Promote Development to Advanced
git-svn-id: http://svn.code.sf.net/p/netpbm/code/advanced@3972 9d0c8265-081b-0410-96cb-a4ca84ce46f8
-rw-r--r--GNUmakefile13
-rwxr-xr-xbuildtools/configure.pl25
-rw-r--r--config.mk.in10
-rw-r--r--converter/other/jpeg2000/Makefile6
-rw-r--r--converter/other/jpeg2000/jpeg2ktopam.c34
-rw-r--r--converter/other/jpeg2000/libjasper/base/jas_image.c41
-rw-r--r--converter/other/jpeg2000/libjasper/include/jasper/jas_image.h27
-rw-r--r--converter/other/jpeg2000/libjasper/jp2/jp2_dec.c93
-rw-r--r--converter/other/jpeg2000/libjasper/jpc/jpc_dec.c1085
-rw-r--r--converter/other/jpeg2000/libjasper/jpc/jpc_t1dec.c1566
-rw-r--r--converter/other/jpeg2000/libjasper/jpc/jpc_t1dec.h14
-rw-r--r--converter/other/jpeg2000/libjasper_compat.c26
-rw-r--r--converter/other/jpeg2000/libjasper_compat.h35
-rw-r--r--converter/other/pamtowinicon.c44
-rw-r--r--converter/other/pgmtopbm.c114
-rw-r--r--converter/other/winicon.h3
-rw-r--r--converter/other/winicontopam.c65
-rw-r--r--converter/ppm/ppmtopcx.c476
-rw-r--r--doc/HISTORY63
-rw-r--r--editor/Makefile4
-rw-r--r--editor/pamfunc.c28
-rw-r--r--editor/pnmcrop.c163
-rw-r--r--editor/pnmnorm.c152
-rwxr-xr-xeditor/ppmbrighten60
-rw-r--r--editor/ppmbrighten.c218
-rw-r--r--other/pamarith.c46
-rw-r--r--other/pamdepth.c23
-rwxr-xr-xtest/Available-Testprog8
-rw-r--r--test/Test-Order8
-rw-r--r--test/all-in-place.ok4
-rwxr-xr-xtest/all-in-place.test6
-rw-r--r--test/channel-stack-roundtrip.ok11
-rwxr-xr-xtest/channel-stack-roundtrip.test34
-rw-r--r--test/legacy-names.ok4
-rwxr-xr-xtest/legacy-names.test8
-rw-r--r--test/pamarith.ok182
-rwxr-xr-xtest/pamarith.test165
-rw-r--r--test/pambrighten.ok96
-rwxr-xr-xtest/pambrighten.test99
-rw-r--r--test/pamdice.ok2
-rwxr-xr-xtest/pamdice.test2
-rw-r--r--test/pamexec.ok4
-rwxr-xr-xtest/pamexec.test4
-rw-r--r--test/pamfunc.ok70
-rwxr-xr-xtest/pamfunc.test166
-rwxr-xr-xtest/pamtopdbimg.test2
-rwxr-xr-xtest/pamvalidate.test11
-rwxr-xr-xtest/pbmtext-utf8.test4
-rw-r--r--test/pj-roundtrip.ok4
-rwxr-xr-xtest/pj-roundtrip.test12
-rw-r--r--test/ppmbrighten.ok10
-rwxr-xr-xtest/ppmbrighten.test30
-rw-r--r--test/winicon-roundtrip.ok14
-rwxr-xr-xtest/winicon-roundtrip.test42
-rw-r--r--test/winicon-roundtrip2.ok80
-rwxr-xr-xtest/winicon-roundtrip2.test150
-rw-r--r--version.mk4
57 files changed, 3601 insertions, 2069 deletions
diff --git a/GNUmakefile b/GNUmakefile
index f07eed01..7389c16a 100644
--- a/GNUmakefile
+++ b/GNUmakefile
@@ -322,8 +322,8 @@ ifneq ($(LINUXSVGALIB),NONE)
   MERGELIBS += $(LINUXSVGALIB)
 endif
 
-ifneq ($(shell pkg-config --modversion libpng$(PNGVER)),)
-  PNGLD = $(shell pkg-config --libs libpng$(PNGVER))
+ifneq ($(shell $(PKG_CONFIG) --modversion libpng$(PNGVER)),)
+  PNGLD = $(shell $(PKG_CONFIG) --libs libpng$(PNGVER))
 else
   ifneq ($(shell libpng$(PNGVER)-config --version),)
     PNGLD = $(shell libpng$(PNGVER)-config --ldflags)
@@ -332,8 +332,8 @@ else
   endif
 endif
 
-ifneq ($(shell pkg-config --modversion libxml-2.0),)
-  XML2LD=$(shell pkg-config --libs libxml-2.0)
+ifneq ($(shell $(PKG_CONFIG) --modversion libxml-2.0),)
+  XML2LD=$(shell $(PKG_CONFIG) --libs libxml-2.0)
 else
   ifneq ($(shell xml2-config --version),)
     XML2LD=$(shell xml2-config --libs)
@@ -342,8 +342,8 @@ else
   endif
 endif
 
-ifneq ($(shell pkg-config x11 --libs),)
-  X11LD = $(shell pkg-config x11 --libs)
+ifneq ($(shell $(PKG_CONFIG) x11 --libs),)
+  X11LD = $(shell $(PKG_CONFIG) x11 --libs)
 else
   X11LD = $(shell $(LIBOPT) $(LIBOPTR) $(X11LIB))
 endif
@@ -461,6 +461,7 @@ CHECK_VARS = \
 	JASPERLIB="$(JASPERLIB)" \
 	JBIGLIB="$(JBIGLIB)" \
 	JPEGLIB="$(JPEGLIB)" \
+	LINUXSVGALIB="$(LINUXSVGALIB)" \
 	PNGLIB="$(PNGLIB)" \
 	TIFFLIB="$(TIFFLIB)" \
 	URTLIB="$(URTLIB)" \
diff --git a/buildtools/configure.pl b/buildtools/configure.pl
index 4eeb97de..6a152a10 100755
--- a/buildtools/configure.pl
+++ b/buildtools/configure.pl
@@ -2241,27 +2241,6 @@ print("\n");
 
 #******************************************************************************
 #
-#  CONFIGURE DOCUMENTATION
-#
-#*****************************************************************************
-
-print("What URL will you use for the main Netpbm documentation page?\n");
-print("This information does not get built into any programs or libraries.\n");
-print("It does not make anything actually install that web page.\n");
-print("It is just for including in legacy man pages.\n");
-print("\n");
-
-my $default = "http://netpbm.sourceforge.net/doc/";
-
-my $netpbm_docurl = prompt("Documentation URL", $default);
-
-print("\n");
-
-
-
-
-#******************************************************************************
-#
 #  VALIDATE THE CONFIGURATION USER HAS SELECTED
 #
 #*****************************************************************************
@@ -2605,10 +2584,6 @@ if (defined($linuxsvgalib)) {
     push(@config_mk, "LINUXSVGALIB = $linuxsvgalib\n");
 }
 
-if (defined($netpbm_docurl)) {
-    push(@config_mk, "NETPBM_DOCURL = $netpbm_docurl\n");
-}
-
 if ($inttypesHeaderFile ne '<inttypes.h>') {
     push(@config_mk, "INTTYPES_H = $inttypesHeaderFile\n");
 }
diff --git a/config.mk.in b/config.mk.in
index 05cb45d4..b79472b0 100644
--- a/config.mk.in
+++ b/config.mk.in
@@ -657,16 +657,6 @@ DLLVER =
 #Cygwin
 #DLLVER = $(NETPBM_MAJOR_RELEASE)
 
-#NETPBM_DOCURL is the URL of the main documentation page for Netpbm.
-#This is a directory which contains a file for each Netpbm program,
-#library, and file type.  E.g. The documentation for jpegtopnm might be in
-#http://netpbm.sourceforge.net/doc/jpegtopnm.html .  This value gets
-#installed in the man pages (which say no more than to read the webpage)
-#and in the Manweb netpbm.url file.
-NETPBM_DOCURL = http://netpbm.sourceforge.net/doc/
-#For a system with no web access, but a local copy of the doc:
-#NETPBM_DOCURL = file:/usr/doc/netpbm/
-
 # RGB_DB_PATH is where Netpbm looks for the color database when the RGBDEF
 # environment variable is not set.  See pm_config.in.h for details.
 RGB_DB_PATH = /usr/local/netpbm/rgb.txt:/usr/share/netpbm/rgb.txt:/etc/X11/rgb.txt:/usr/lib/X11/rgb.txt:/usr/share/X11/rgb.txt:/usr/X11R6/lib/X11/rgb.txt
diff --git a/converter/other/jpeg2000/Makefile b/converter/other/jpeg2000/Makefile
index 6e5af8e7..9c8729ac 100644
--- a/converter/other/jpeg2000/Makefile
+++ b/converter/other/jpeg2000/Makefile
@@ -46,8 +46,8 @@ endif
 
 BINARIES = $(PORTBINARIES)
 
-OBJECTS = $(BINARIES:%=%.o)
-MERGE_OBJECTS = $(BINARIES:%=%.o2) 
+OBJECTS = $(BINARIES:%=%.o) libjasper_compat.o
+MERGE_OBJECTS = $(BINARIES:%=%.o2) libjasper_compat.o2
 ifeq ($(JASPERLIB),$(INTERNAL_JASPERLIB))
   # MERGE_OBJECTS contains relative paths, so $(INTERNAL_JASPERLIB) had better
   # be relative to the current directory.
@@ -63,7 +63,7 @@ include $(SRCDIR)/common.mk
 
 LIBOPTS = $(shell $(LIBOPT) $(JASPERLIB_USE))
 
-$(BINARIES): %: %.o $(JASPERLIB_DEP) $(LIBOPT)
+$(BINARIES): %: %.o libjasper_compat.o $(JASPERLIB_DEP) $(LIBOPT)
 $(BINARIES): LDFLAGS_TARGET = $(LIBOPTS) $(JASPERDEPLIBS)
 
 $(INTERNAL_JASPERLIB): $(BUILDDIR)/$(SUBDIR)/libjasper FORCE
diff --git a/converter/other/jpeg2000/jpeg2ktopam.c b/converter/other/jpeg2000/jpeg2ktopam.c
index b507f56e..bda0de2e 100644
--- a/converter/other/jpeg2000/jpeg2ktopam.c
+++ b/converter/other/jpeg2000/jpeg2ktopam.c
@@ -29,11 +29,9 @@
 
 #include "libjasper_compat.h"
 
-enum compmode {COMPMODE_INTEGER, COMPMODE_REAL};
 
-enum progression {PROG_LRCP, PROG_RLCP, PROG_RPCL, PROG_PCRL, PROG_CPRL};
 
-struct cmdlineInfo {
+struct CmdlineInfo {
     /* All the information the user supplied in the command line,
        in a form easy for the program to use.
     */
@@ -44,15 +42,15 @@ struct cmdlineInfo {
 
 
 static void
-parseCommandLine(int argc, char ** argv,
-                 struct cmdlineInfo * const cmdlineP) {
+parseCommandLine(int argc, const char ** argv,
+                 struct CmdlineInfo * const cmdlineP) {
 /*----------------------------------------------------------------------------
    Note that many of the strings that this function returns in the
    *cmdlineP structure are actually in the supplied argv array.  And
    sometimes, one of these strings is actually just a suffix of an entry
    in argv!
 -----------------------------------------------------------------------------*/
-    optEntry *option_def;
+    optEntry * option_def;
     optStruct3 opt;
 
     unsigned int debuglevelSpec;
@@ -71,7 +69,7 @@ parseCommandLine(int argc, char ** argv,
     opt.short_allowed = FALSE;  /* We have no short (old-fashioned) options */
     opt.allowNegNum = FALSE;  /* We have no parms that are negative numbers */
 
-    pm_optParseOptions3(&argc, argv, opt, sizeof(opt), 0);
+    pm_optParseOptions3(&argc, (char**)argv, opt, sizeof(opt), 0);
 
     if (!debuglevelSpec)
         cmdlineP->debuglevel = 0;
@@ -84,6 +82,7 @@ parseCommandLine(int argc, char ** argv,
         pm_error("Too many arguments.  The only argument accepted\n"
                  "is the input file specification");
 
+    free(option_def);
 }
 
 
@@ -114,9 +113,11 @@ static void
 readJ2k(const char *   const inputFilename,
         jas_image_t ** const jasperPP) {
 
+    const char * const options = "";
+
     jas_image_t * jasperP;
     jas_stream_t * instreamP;
-    const char * options;
+    const char * error;
 
     if (streq(inputFilename, "-")) {
         /* The input image is to be read from standard input. */
@@ -131,13 +132,10 @@ readJ2k(const char *   const inputFilename,
 
     validateJ2k(instreamP);
 
-    options = "";
-
-    jasperP = jas_image_decode(instreamP, jas_image_getfmt(instreamP),
-                               (char*)options);
-    if (jasperP == NULL)
-        pm_error("Unable to interpret JPEG-2000 input.  "
-                 "The Jasper library jas_image_decode() subroutine failed.");
+    pmjas_image_decode(instreamP, jas_image_getfmt(instreamP), options,
+                       &jasperP, &error);
+    if (error)
+        pm_error("Unable to interpret JPEG-2000 input.  %s", error);
 
     jas_stream_close(instreamP);
 
@@ -483,9 +481,9 @@ convertToPamPnm(struct pam *  const outpamP,
 
 
 int
-main(int argc, char **argv)
+main(int argc, const char **argv)
 {
-    struct cmdlineInfo cmdline;
+    struct CmdlineInfo cmdline;
     struct pam outpam;
     int * jasperCmpt;  /* malloc'ed */
        /* jaspercmpt[P] is the component number for use with the
@@ -493,7 +491,7 @@ main(int argc, char **argv)
        */
     jas_image_t * jasperP;
 
-    pnm_init(&argc, argv);
+    pm_proginit(&argc, argv);
 
     parseCommandLine(argc, argv, &cmdline);
 
diff --git a/converter/other/jpeg2000/libjasper/base/jas_image.c b/converter/other/jpeg2000/libjasper/base/jas_image.c
index 5c2822be..5ee13a0d 100644
--- a/converter/other/jpeg2000/libjasper/base/jas_image.c
+++ b/converter/other/jpeg2000/libjasper/base/jas_image.c
@@ -126,6 +126,8 @@
 #include <assert.h>
 #include <ctype.h>
 
+#include "netpbm/nstring.h"
+
 #include "jasper/jas_math.h"
 #include "jasper/jas_image.h"
 #include "jasper/jas_malloc.h"
@@ -379,22 +381,47 @@ static void jas_image_cmpt_destroy(jas_image_cmpt_t *cmpt)
 * Load and save operations.
 \*****************************************************************************/
 
-jas_image_t *jas_image_decode(jas_stream_t *in, int fmt, char *optstr)
-{
+void
+pmjas_image_decode(jas_stream_t * const in,
+				   int            const fmtArg,
+				   const char *   const optstr,
+				   jas_image_t ** const imagePP,
+				   const char **  const errorP) {
+/*----------------------------------------------------------------------------
+  Create an image from a stream in some specified format
+-----------------------------------------------------------------------------*/
 	jas_image_fmtinfo_t *fmtinfo;
+	int fmt;
 
 	/* If possible, try to determine the format of the input data. */
-	if (fmt < 0) {
+	if (fmtArg < 0) {
 		if ((fmt = jas_image_getfmt(in)) < 0) {
-			return 0;
+			pm_asprintf(errorP, "jas_image_getfmt failed");
+			return;
 		}
-	}
+	} else
+		fmt = fmtArg;
+
 	if (!(fmtinfo = jas_image_lookupfmtbyid(fmt))) {
-		return 0;
+		pm_asprintf(errorP, "jas_image_lookupfmtbyid of format %d failed",
+					fmt);
+		return;
+	}
+	{
+		const char * error;
+
+		(*fmtinfo->ops.decode)(in, optstr, imagePP, &error);
+		if (error) {
+			pm_asprintf(errorP, "decoder failed.  %s", error);
+			pm_strfree(error);
+		} else {
+			*errorP = NULL;
+		}
 	}
-	return (fmtinfo->ops.decode) ? (*fmtinfo->ops.decode)(in, optstr) : 0;
 }
 
+
+
 int jas_image_encode(jas_image_t *image, jas_stream_t *out, int fmt, char *optstr)
 {
 	jas_image_fmtinfo_t *fmtinfo;
diff --git a/converter/other/jpeg2000/libjasper/include/jasper/jas_image.h b/converter/other/jpeg2000/libjasper/include/jasper/jas_image.h
index 6e914efd..20170986 100644
--- a/converter/other/jpeg2000/libjasper/include/jasper/jas_image.h
+++ b/converter/other/jpeg2000/libjasper/include/jasper/jas_image.h
@@ -300,7 +300,10 @@ typedef struct {
 
 typedef struct {
 
-	jas_image_t *(*decode)(jas_stream_t *in, char *opts);
+	void (*decode)(jas_stream_t * const in,
+				   const char *   const opts,
+				   jas_image_t ** const imagePP,
+				   const char **  const errorP);
 	/* Decode image data from a stream. */
 
 	int (*encode)(jas_image_t *image, jas_stream_t *out, char *opts);
@@ -442,8 +445,14 @@ void jas_image_destroy(jas_image_t *image);
   any compression. */
 uint_fast32_t jas_image_rawsize(jas_image_t *image);
 
-/* Create an image from a stream in some specified format. */
-jas_image_t *jas_image_decode(jas_stream_t *in, int fmt, char *optstr);
+#define JAS_HAVE_PMJAS_IMAGE_DECODE
+
+void
+pmjas_image_decode(jas_stream_t * const in,
+				   int            const fmt,
+				   const char *   const optstr,
+				   jas_image_t ** const imagePP,
+				   const char **  const errorP);
 
 /* Write an image to a stream in a specified format. */
 int jas_image_encode(jas_image_t *image, jas_stream_t *out, int fmt,
@@ -567,14 +576,22 @@ int bmp_validate(jas_stream_t *in);
 
 #if !defined(EXCLUDE_JP2_CAPABILITY)
 /* Format-dependent operations for JP2 capability. */
-jas_image_t *jp2_decode(jas_stream_t *in, char *optstr);
+void
+jp2_decode(jas_stream_t * const in,
+		   const char *   const optstr,
+		   jas_image_t ** const imagePP,
+		   const char **  const errorP);
 int jp2_encode(jas_image_t *image, jas_stream_t *out, char *optstr);
 int jp2_validate(jas_stream_t *in);
 #endif
 
 #if !defined(EXCLUDE_JPC_CAPABILITY)
 /* Format-dependent operations for JPEG-2000 code stream capability. */
-jas_image_t *jpc_decode(jas_stream_t *in, char *optstr);
+void
+jpc_decode(jas_stream_t * const in,
+           const char *   const optstr,
+           jas_image_t ** const imagePP,
+           const char **  const errorP);
 int jpc_encode(jas_image_t *image, jas_stream_t *out, char *optstr);
 int jpc_validate(jas_stream_t *in);
 #endif
diff --git a/converter/other/jpeg2000/libjasper/jp2/jp2_dec.c b/converter/other/jpeg2000/libjasper/jp2/jp2_dec.c
index 4036f0f2..e8d71b0a 100644
--- a/converter/other/jpeg2000/libjasper/jp2/jp2_dec.c
+++ b/converter/other/jpeg2000/libjasper/jp2/jp2_dec.c
@@ -117,6 +117,8 @@
 #include "jasper/jas_malloc.h"
 #include "jasper/jas_version.h"
 
+#include "netpbm/nstring.h"
+
 #include "jp2_cod.h"
 #include "jp2_dec.h"
 
@@ -271,8 +273,11 @@ fromiccpcs(int cs) {
 
 
 
-jas_image_t *
-jp2_decode(jas_stream_t *in, char *optstr) {
+void
+jp2_decode(jas_stream_t * const in,
+           const char *   const optstr,
+           jas_image_t ** const imagePP,
+           const char **  const errorP) {
 
     jp2_box_t *box;
     int found;
@@ -295,32 +300,34 @@ jp2_decode(jas_stream_t *in, char *optstr) {
     image = 0;
 
     if (!(dec = jp2_dec_create())) {
-        goto error;
+        pm_asprintf(errorP, "jp2_dec_create failed");
+        goto cleanup;
     }
 
     /* Get the first box.  This should be a JP box. */
     if (!(box = jp2_box_get(in))) {
-        jas_eprintf("error: cannot get box\n");
-        goto error;
+        pm_asprintf(errorP, "cannot get box");
+        goto cleanup;
     }
     if (box->type != JP2_BOX_JP) {
-        jas_eprintf("error: expecting signature box\n");
-        goto error;
+        pm_asprintf(errorP, "expecting signature box");
+        goto cleanup;
     }
     if (box->data.jp.magic != JP2_JP_MAGIC) {
-        jas_eprintf("incorrect magic number\n");
-        goto error;
+        pm_asprintf(errorP, "incorrect magic number");
+        goto cleanup;
     }
     jp2_box_destroy(box);
     box = 0;
 
     /* Get the second box.  This should be a FTYP box. */
     if (!(box = jp2_box_get(in))) {
-        goto error;
+        pm_asprintf(errorP, "cannot get second box");
+        goto cleanup;
     }
     if (box->type != JP2_BOX_FTYP) {
-        jas_eprintf("expecting file type box\n");
-        goto error;
+        pm_asprintf(errorP, "expecting file type box");
+        goto cleanup;
     }
     jp2_box_destroy(box);
     box = 0;
@@ -329,7 +336,7 @@ jp2_decode(jas_stream_t *in, char *optstr) {
     found = 0;
     while ((box = jp2_box_get(in))) {
         if (jas_getdbglevel() >= 1) {
-            fprintf(stderr, "box type %s\n", box->info->name);
+            jas_eprintf("box type '%s'\n", box->info->name);
         }
         switch (box->type) {
         case JP2_BOX_JP2C:
@@ -382,19 +389,24 @@ jp2_decode(jas_stream_t *in, char *optstr) {
     }
 
     if (!found) {
-        jas_eprintf("error: no code stream found\n");
-        goto error;
+        pm_asprintf(errorP, "no code stream found");
+        goto cleanup;
     }
 
-    if (!(dec->image = jpc_decode(in, optstr))) {
-        jas_eprintf("error: cannot decode code stream\n");
-        goto error;
+    {
+        const char * decodeError;
+        jpc_decode(in, optstr, &dec->image, &decodeError);
+        if (decodeError) {
+            pm_asprintf(errorP, "cannot decode code stream.  %s", decodeError);
+            pm_strfree(decodeError);
+            goto cleanup;
+        }
     }
 
     /* An IHDR box must be present. */
     if (!dec->ihdr) {
-        jas_eprintf("error: missing IHDR box\n");
-        goto error;
+        pm_asprintf(errorP, "missing IHDR box");
+        goto cleanup;
     }
 
     /* Does the number of components indicated in the IHDR box match
@@ -405,8 +417,8 @@ jp2_decode(jas_stream_t *in, char *optstr) {
 
     /* At least one component must be present. */
     if (!jas_image_numcmpts(dec->image)) {
-        jas_eprintf("error: no components\n");
-        goto error;
+        pm_asprintf(errorP, "no components");
+        goto cleanup;
     }
 
     /* Determine if all components have the same data type. */
@@ -428,15 +440,15 @@ jp2_decode(jas_stream_t *in, char *optstr) {
 
     /* Can we handle the compression type? */
     if (dec->ihdr->data.ihdr.comptype != JP2_IHDR_COMPTYPE) {
-        jas_eprintf("error: not capable of this compression type\n");
-        goto error;
+        pm_asprintf(errorP, "not capable of this compression type");
+        goto cleanup;
     }
 
     if (dec->bpcc) {
         /* Is the number of components indicated in the BPCC box
           consistent with the code stream data? */
         if (dec->bpcc->data.bpcc.numcmpts != jas_image_numcmpts(
-          dec->image)) {
+                dec->image)) {
             jas_eprintf("warning: number of components mismatch\n");
         }
         /* Is the component data type information indicated in the BPCC
@@ -455,8 +467,8 @@ jp2_decode(jas_stream_t *in, char *optstr) {
 
     /* A COLR box must be present. */
     if (!dec->colr) {
-        jas_eprintf("error: no COLR box\n");
-        goto error;
+        pm_asprintf(errorP, "no COLR box");
+        goto cleanup;
     }
 
     switch (dec->colr->data.colr.method) {
@@ -502,14 +514,14 @@ jp2_decode(jas_stream_t *in, char *optstr) {
             /* Is the component number reasonable? */
             if (dec->cmap->data.cmap.ents[i].cmptno >=
                 jas_image_numcmpts(dec->image)) {
-                jas_eprintf("error: invalid component number in CMAP box\n");
-                goto error;
+                pm_asprintf(errorP, "invalid component number in CMAP box");
+                goto cleanup;
             }
             /* Is the LUT index reasonable? */
             if (dec->cmap->data.cmap.ents[i].pcol >=
                 dec->pclr->data.pclr.numchans) {
-                jas_eprintf("error: invalid CMAP LUT index\n");
-                goto error;
+                pm_asprintf(errorP, "invalid CMAP LUT index");
+                goto cleanup;
             }
         }
     }
@@ -517,8 +529,8 @@ jp2_decode(jas_stream_t *in, char *optstr) {
     /* Allocate space for the channel-number to component-number LUT. */
     dec->chantocmptlut = jas_malloc(dec->numchans * sizeof(uint_fast16_t));
     if (!dec->chantocmptlut) {
-        jas_eprintf("error: no memory\n");
-        goto error;
+        pm_asprintf(errorP, "no memory");
+        goto cleanup;
     }
 
     if (!dec->cmap) {
@@ -564,8 +576,8 @@ jp2_decode(jas_stream_t *in, char *optstr) {
                 }
 #endif
             } else {
-                jas_eprintf("error: invalid MTYP in CMAP box\n");
-                goto error;
+                pm_asprintf(errorP, "invalid MTYP in CMAP box");
+                goto cleanup;
             }
         }
     }
@@ -604,8 +616,8 @@ jp2_decode(jas_stream_t *in, char *optstr) {
 
     /* Ensure that some components survived. */
     if (!jas_image_numcmpts(dec->image)) {
-        jas_eprintf("error: no components\n");
-        goto error;
+        pm_asprintf(errorP, "no components");
+        goto cleanup;
     }
 
     /* Prevent the image from being destroyed later. */
@@ -614,16 +626,17 @@ jp2_decode(jas_stream_t *in, char *optstr) {
 
     jp2_dec_destroy(dec);
 
-    return image;
+    *imagePP = image;
+    *errorP = NULL;
+    return;
 
-error:
+cleanup:
     if (box) {
         jp2_box_destroy(box);
     }
     if (dec) {
         jp2_dec_destroy(dec);
     }
-    return 0;
 }
 
 
diff --git a/converter/other/jpeg2000/libjasper/jpc/jpc_dec.c b/converter/other/jpeg2000/libjasper/jpc/jpc_dec.c
index 4d4dfc50..140169ec 100644
--- a/converter/other/jpeg2000/libjasper/jpc/jpc_dec.c
+++ b/converter/other/jpeg2000/libjasper/jpc/jpc_dec.c
@@ -114,15 +114,13 @@
  * $Id$
  */
 
-/*****************************************************************************\
-* Includes.
-\*****************************************************************************/
-
 #include <stdio.h>
 #include <stdlib.h>
+#include <stdbool.h>
 #include <assert.h>
 
 #include "pm.h"
+#include "netpbm/nstring.h"
 
 #include "jasper/jas_types.h"
 #include "jasper/jas_math.h"
@@ -164,7 +162,10 @@ typedef struct {
     /* The states in which this type of marker segment can be
       validly encountered. */
 
-    int (*action)(jpc_dec_t *dec, jpc_ms_t *ms);
+    void (*action)(jpc_dec_t *   const dec,
+                   jpc_ms_t *    const ms,
+                   bool *        const doneP,
+                   const char ** const errorP);
     /* The action to take upon encountering this type of marker segment. */
 
 } jpc_dec_mstabent_t;
@@ -223,119 +224,263 @@ static void jpc_dec_cp_destroy(jpc_dec_cp_t *cp);
 static int jpc_dec_cp_setfrompoc(jpc_dec_cp_t *cp, jpc_poc_t *poc, int reset);
 static int jpc_pi_addpchgfrompoc(jpc_pi_t *pi, jpc_poc_t *poc);
 
-static int jpc_dec_decode(jpc_dec_t *dec);
 static jpc_dec_t *jpc_dec_create(jpc_dec_importopts_t *impopts, jas_stream_t *in);
 static void jpc_dec_destroy(jpc_dec_t *dec);
 static void jpc_dequantize(jas_matrix_t *x, jpc_fix_t absstepsize);
 static void jpc_undo_roi(jas_matrix_t *x, int roishift, int bgshift, int numbps);
 static jpc_fix_t jpc_calcabsstepsize(int stepsize, int numbits);
-static int jpc_dec_tiledecode(jpc_dec_t *dec, jpc_dec_tile_t *tile);
 static int jpc_dec_tileinit(jpc_dec_t *dec, jpc_dec_tile_t *tile);
 static int jpc_dec_tilefini(jpc_dec_t *dec, jpc_dec_tile_t *tile);
-static int jpc_dec_process_soc(jpc_dec_t *dec, jpc_ms_t *ms);
-static int jpc_dec_process_sot(jpc_dec_t *dec, jpc_ms_t *ms);
-static int jpc_dec_process_sod(jpc_dec_t *dec, jpc_ms_t *ms);
-static int jpc_dec_process_eoc(jpc_dec_t *dec, jpc_ms_t *ms);
-static int jpc_dec_process_siz(jpc_dec_t *dec, jpc_ms_t *ms);
-static int jpc_dec_process_cod(jpc_dec_t *dec, jpc_ms_t *ms);
-static int jpc_dec_process_coc(jpc_dec_t *dec, jpc_ms_t *ms);
-static int jpc_dec_process_rgn(jpc_dec_t *dec, jpc_ms_t *ms);
-static int jpc_dec_process_qcd(jpc_dec_t *dec, jpc_ms_t *ms);
-static int jpc_dec_process_qcc(jpc_dec_t *dec, jpc_ms_t *ms);
-static int jpc_dec_process_poc(jpc_dec_t *dec, jpc_ms_t *ms);
-static int jpc_dec_process_ppm(jpc_dec_t *dec, jpc_ms_t *ms);
-static int jpc_dec_process_ppt(jpc_dec_t *dec, jpc_ms_t *ms);
-static int jpc_dec_process_com(jpc_dec_t *dec, jpc_ms_t *ms);
-static int jpc_dec_process_unk(jpc_dec_t *dec, jpc_ms_t *ms);
-static int jpc_dec_process_crg(jpc_dec_t *dec, jpc_ms_t *ms);
-static int jpc_dec_parseopts(char *optstr, jpc_dec_importopts_t *opts);
 
-/******************************************************************************\
-* Global data.
-\******************************************************************************/
 
-jpc_dec_mstabent_t jpc_dec_mstab[] = {
-    {JPC_MS_SOC, JPC_MHSOC, jpc_dec_process_soc},
-    {JPC_MS_SOT, JPC_MH | JPC_TPHSOT, jpc_dec_process_sot},
-    {JPC_MS_SOD, JPC_TPH, jpc_dec_process_sod},
-    {JPC_MS_EOC, JPC_TPHSOT, jpc_dec_process_eoc},
-    {JPC_MS_SIZ, JPC_MHSIZ, jpc_dec_process_siz},
-    {JPC_MS_COD, JPC_MH | JPC_TPH, jpc_dec_process_cod},
-    {JPC_MS_COC, JPC_MH | JPC_TPH, jpc_dec_process_coc},
-    {JPC_MS_RGN, JPC_MH | JPC_TPH, jpc_dec_process_rgn},
-    {JPC_MS_QCD, JPC_MH | JPC_TPH, jpc_dec_process_qcd},
-    {JPC_MS_QCC, JPC_MH | JPC_TPH, jpc_dec_process_qcc},
-    {JPC_MS_POC, JPC_MH | JPC_TPH, jpc_dec_process_poc},
-    {JPC_MS_TLM, JPC_MH, 0},
-    {JPC_MS_PLM, JPC_MH, 0},
-    {JPC_MS_PLT, JPC_TPH, 0},
-    {JPC_MS_PPM, JPC_MH, jpc_dec_process_ppm},
-    {JPC_MS_PPT, JPC_TPH, jpc_dec_process_ppt},
-    {JPC_MS_SOP, 0, 0},
-    {JPC_MS_CRG, JPC_MH, jpc_dec_process_crg},
-    {JPC_MS_COM, JPC_MH | JPC_TPH, jpc_dec_process_com},
-    {0, JPC_MH | JPC_TPH, jpc_dec_process_unk}
-};
 
-/*****************************************************************************\
-* The main entry point for the JPEG-2000 decoder.
-\*****************************************************************************/
+static void
+jpc_dec_tiledecode(jpc_dec_t *      const dec,
+                   jpc_dec_tile_t * const tile,
+                   const char **    const errorP) {
 
-jas_image_t *jpc_decode(jas_stream_t *in, char *optstr)
-{
-    jpc_dec_importopts_t opts;
-    jpc_dec_t *dec;
-    jas_image_t *image;
+    int i;
+    int j;
+    jpc_dec_tcomp_t *tcomp;
+    jpc_dec_rlvl_t *rlvl;
+    jpc_dec_band_t *band;
+    int compno;
+    int rlvlno;
+    int bandno;
+    int adjust;
+    int v;
+    jpc_dec_ccp_t *ccp;
+    jpc_dec_cmpt_t *cmpt;
+    const char * error;
 
-    dec = 0;
+    jpc_dec_decodecblks(dec, tile, &error);
 
-    if (jpc_dec_parseopts(optstr, &opts)) {
-        goto error;
+    if (error) {
+        pm_asprintf(errorP, "jpc_dec_decodecblks failed.  %s", error);
+        return;
     }
 
-    jpc_initluts();
+    /* Perform dequantization. */
+    for (compno = 0, tcomp = tile->tcomps; compno < dec->numcomps;
+         ++compno, ++tcomp) {
+        ccp = &tile->cp->ccps[compno];
+        for (rlvlno = 0, rlvl = tcomp->rlvls; rlvlno < tcomp->numrlvls;
+             ++rlvlno, ++rlvl) {
+            if (!rlvl->bands) {
+                continue;
+            }
+            for (bandno = 0, band = rlvl->bands;
+                 bandno < rlvl->numbands; ++bandno, ++band) {
+                if (!band->data) {
+                    continue;
+                }
+                jpc_undo_roi(band->data, band->roishift, ccp->roishift -
+                             band->roishift, band->numbps);
+                if (tile->realmode) {
+                    jas_matrix_asl(band->data, JPC_FIX_FRACBITS);
+                    jpc_dequantize(band->data, band->absstepsize);
+                }
 
-    if (!(dec = jpc_dec_create(&opts, in))) {
-        goto error;
+            }
+        }
     }
 
-    /* Do most of the work. */
-    if (jpc_dec_decode(dec)) {
-        goto error;
+    /* Apply an inverse wavelet transform if necessary. */
+    for (compno = 0, tcomp = tile->tcomps; compno < dec->numcomps;
+         ++compno, ++tcomp) {
+        ccp = &tile->cp->ccps[compno];
+        jpc_tsfb_synthesize(tcomp->tsfb,
+                            ((ccp->qmfbid ==
+                              JPC_COX_RFT) ? JPC_TSFB_RITIMODE : 0),
+                            tcomp->data);
     }
 
-    if (jas_image_numcmpts(dec->image) >= 3) {
-        jas_image_setcolorspace(dec->image, JAS_IMAGE_CS_RGB);
-        jas_image_setcmpttype(dec->image, 0,
-          JAS_IMAGE_CT_COLOR(JAS_IMAGE_CT_RGB_R));
-        jas_image_setcmpttype(dec->image, 1,
-          JAS_IMAGE_CT_COLOR(JAS_IMAGE_CT_RGB_G));
-        jas_image_setcmpttype(dec->image, 2,
-          JAS_IMAGE_CT_COLOR(JAS_IMAGE_CT_RGB_B));
-    } else {
-        jas_image_setcolorspace(dec->image, JAS_IMAGE_CS_GRAY);
-        jas_image_setcmpttype(dec->image, 0,
-          JAS_IMAGE_CT_COLOR(JAS_IMAGE_CT_GRAY_Y));
+
+    /* Apply an inverse intercomponent transform if necessary. */
+    switch (tile->cp->mctid) {
+    case JPC_MCT_RCT:
+        assert(dec->numcomps == 3);
+        jpc_irct(tile->tcomps[0].data, tile->tcomps[1].data,
+                 tile->tcomps[2].data);
+        break;
+    case JPC_MCT_ICT:
+        assert(dec->numcomps == 3);
+        jpc_iict(tile->tcomps[0].data, tile->tcomps[1].data,
+                 tile->tcomps[2].data);
+        break;
     }
 
-    /* Save the return value. */
-    image = dec->image;
+    /* Perform rounding and convert to integer values. */
+    if (tile->realmode) {
+        for (compno = 0, tcomp = tile->tcomps; compno < dec->numcomps;
+             ++compno, ++tcomp) {
+            for (i = 0; i < jas_matrix_numrows(tcomp->data); ++i) {
+                for (j = 0; j < jas_matrix_numcols(tcomp->data); ++j) {
+                    v = jas_matrix_get(tcomp->data, i, j);
+                    v = jpc_fix_round(v);
+                    jas_matrix_set(tcomp->data, i, j, jpc_fixtoint(v));
+                }
+            }
+        }
+    }
 
-    /* Stop the image from being discarded. */
-    dec->image = 0;
+    /* Perform level shift. */
+    for (compno = 0, tcomp = tile->tcomps, cmpt = dec->cmpts; compno <
+             dec->numcomps; ++compno, ++tcomp, ++cmpt) {
+        adjust = cmpt->sgnd ? 0 : (1 << (cmpt->prec - 1));
+        for (i = 0; i < jas_matrix_numrows(tcomp->data); ++i) {
+            for (j = 0; j < jas_matrix_numcols(tcomp->data); ++j) {
+                *jas_matrix_getref(tcomp->data, i, j) += adjust;
+            }
+        }
+    }
 
-    /* Destroy decoder. */
-    jpc_dec_destroy(dec);
+    /* Perform clipping. */
+    for (compno = 0, tcomp = tile->tcomps, cmpt = dec->cmpts; compno <
+             dec->numcomps; ++compno, ++tcomp, ++cmpt) {
+        jpc_fix_t mn;
+        jpc_fix_t mx;
+        mn = cmpt->sgnd ? (-(1 << (cmpt->prec - 1))) : (0);
+        mx = cmpt->sgnd ? ((1 << (cmpt->prec - 1)) - 1) : ((1 <<
+                                                            cmpt->prec) - 1);
+        jas_matrix_clip(tcomp->data, mn, mx);
+    }
 
-    return image;
+    /* XXX need to free tsfb struct */
 
-error:
-    if (dec) {
-        jpc_dec_destroy(dec);
+    /* Write the data for each component of the image. */
+    for (compno = 0, tcomp = tile->tcomps, cmpt = dec->cmpts; compno <
+             dec->numcomps; ++compno, ++tcomp, ++cmpt) {
+        if (jas_image_writecmpt(dec->image, compno, tcomp->xstart -
+                                JPC_CEILDIV(dec->xstart, cmpt->hstep),
+                                tcomp->ystart -
+                                JPC_CEILDIV(dec->ystart, cmpt->vstep),
+                                jas_matrix_numcols(
+                                    tcomp->data),
+                                jas_matrix_numrows(tcomp->data),
+                                tcomp->data)) {
+            pm_asprintf(errorP, "write component failed");
+            return;
+        }
     }
-    return 0;
+    *errorP = NULL;
 }
 
+
+
+static void
+jpc_dec_process_sod(jpc_dec_t *   const dec,
+                    jpc_ms_t *    const ms,
+                    bool *        const doneP,
+                    const char ** const errorP) {
+
+    jpc_dec_tile_t *tile;
+    int pos;
+
+    if (!(tile = dec->curtile)) {
+        pm_asprintf(errorP, "No current tile");
+        return;
+    }
+
+    if (!tile->partno) {
+        if (!jpc_dec_cp_isvalid(tile->cp)) {
+            pm_asprintf(errorP, "CP is not valid");
+            return;
+        }
+        if (jpc_dec_cp_prepare(tile->cp)) {
+            pm_asprintf(errorP, "fpc_dec_cp_prepare failed");
+            return;
+        }
+        if (jpc_dec_tileinit(dec, tile)) {
+            pm_asprintf(errorP, "jpc_dec_tileinit failed");
+            return;
+        }
+    }
+
+    /* Are packet headers stored in the main header or tile-part header? */
+    if (dec->pkthdrstreams) {
+        /* Get the stream containing the packet header data for this
+          tile-part. */
+        if (!(tile->pkthdrstream = jpc_streamlist_remove(dec->pkthdrstreams, 0))) {
+            pm_asprintf(errorP, "jpc_streamlist_remove failed");
+            return;
+        }
+    }
+
+    if (tile->pptstab) {
+        if (!tile->pkthdrstream) {
+            if (!(tile->pkthdrstream = jas_stream_memopen(0, 0))) {
+                pm_asprintf(errorP, "jas_stream_memopen failed");
+                return;
+            }
+        }
+        pos = jas_stream_tell(tile->pkthdrstream);
+        jas_stream_seek(tile->pkthdrstream, 0, SEEK_END);
+        if (jpc_pptstabwrite(tile->pkthdrstream, tile->pptstab)) {
+            pm_asprintf(errorP, "jpc_pptstabwrite failed");
+            return;
+        }
+        jas_stream_seek(tile->pkthdrstream, pos, SEEK_SET);
+        jpc_ppxstab_destroy(tile->pptstab);
+        tile->pptstab = 0;
+    }
+
+    if (jas_getdbglevel() >= 10) {
+        jpc_dec_dump(dec, stderr);
+    }
+
+    if (jpc_dec_decodepkts(dec, (tile->pkthdrstream) ? tile->pkthdrstream :
+      dec->in, dec->in)) {
+        pm_asprintf(errorP, "jpc_dec_decodepkts failed");
+        return;
+    }
+
+    /* Gobble any unconsumed tile data. */
+    if (dec->curtileendoff > 0) {
+        uint_fast32_t curoff;
+        uint_fast32_t n;
+        curoff = jas_stream_getrwcount(dec->in);
+        if (curoff < dec->curtileendoff) {
+            n = dec->curtileendoff - curoff;
+            pm_message("warning: ignoring trailing garbage (%lu bytes)",
+                       (unsigned long) n);
+
+            while (n-- > 0) {
+                if (jas_stream_getc(dec->in) == EOF) {
+                    pm_asprintf(errorP, "read error");
+                    return;
+                }
+            }
+        } else if (curoff > dec->curtileendoff) {
+            pm_message("warning: not enough tile data (%lu bytes)",
+                       (unsigned long) curoff - dec->curtileendoff);
+        }
+    }
+
+    if (tile->numparts > 0 && tile->partno == tile->numparts - 1) {
+        const char * error;
+        jpc_dec_tiledecode(dec, tile, &error);
+        if (error) {
+            pm_asprintf(errorP, "jpc_dec_tiledecode failed.  %s", error);
+            pm_strfree(error);
+            return;
+        }
+        jpc_dec_tilefini(dec, tile);
+    }
+
+    dec->curtile = 0;
+
+    /* Increment the expected tile-part number. */
+    ++tile->partno;
+
+    /* We should expect to encounter a SOT marker segment next. */
+    dec->state = JPC_TPHSOT;
+
+    *errorP = NULL;
+}
+
+
+
 typedef enum {
     OPT_MAXLYRS,
     OPT_MAXPKTS,
@@ -349,7 +494,8 @@ jas_taginfo_t decopts[] = {
     {-1, 0}
 };
 
-static int jpc_dec_parseopts(char *optstr, jpc_dec_importopts_t *opts)
+static int
+jpc_dec_parseopts(const char *optstr, jpc_dec_importopts_t *opts)
 {
     jas_tvparser_t *tvp;
 
@@ -374,8 +520,8 @@ static int jpc_dec_parseopts(char *optstr, jpc_dec_importopts_t *opts)
             opts->maxpkts = atoi(jas_tvparser_getval(tvp));
             break;
         default:
-            fprintf(stderr, "warning: ignoring invalid option %s\n",
-              jas_tvparser_gettag(tvp));
+            pm_message("warning: ignoring invalid option %s",
+                       jas_tvparser_gettag(tvp));
             break;
         }
     }
@@ -385,79 +531,14 @@ static int jpc_dec_parseopts(char *optstr, jpc_dec_importopts_t *opts)
     return 0;
 }
 
-/******************************************************************************\
-* Code for table-driven code stream decoder.
-\******************************************************************************/
-
-static jpc_dec_mstabent_t *jpc_dec_mstab_lookup(uint_fast16_t id)
-{
-    jpc_dec_mstabent_t *mstabent;
-    for (mstabent = jpc_dec_mstab; mstabent->id != 0; ++mstabent) {
-        if (mstabent->id == id) {
-            break;
-        }
-    }
-    return mstabent;
-}
-
-static int jpc_dec_decode(jpc_dec_t *dec)
-{
-    jpc_ms_t *ms;
-    jpc_dec_mstabent_t *mstabent;
-    int ret;
-    jpc_cstate_t *cstate;
-
-    if (!(cstate = jpc_cstate_create())) {
-        return -1;
-    }
-    dec->cstate = cstate;
-
-    /* Initially, we should expect to encounter a SOC marker segment. */
-    dec->state = JPC_MHSOC;
-
-    for (;;) {
-
-        /* Get the next marker segment in the code stream. */
-        if (!(ms = jpc_getms(dec->in, cstate))) {
-            fprintf(stderr, "cannot get marker segment\n");
-            return -1;
-        }
-
-        mstabent = jpc_dec_mstab_lookup(ms->id);
-        assert(mstabent);
-
-        /* Ensure that this type of marker segment is permitted
-          at this point in the code stream. */
-        if (!(dec->state & mstabent->validstates)) {
-            fprintf(stderr, "unexpected marker segment type\n");
-            jpc_ms_destroy(ms);
-            return -1;
-        }
-
-        /* Process the marker segment. */
-        if (mstabent->action) {
-            ret = (*mstabent->action)(dec, ms);
-        } else {
-            /* No explicit action is required. */
-            ret = 0;
-        }
-
-        /* Destroy the marker segment. */
-        jpc_ms_destroy(ms);
-
-        if (ret < 0) {
-            return -1;
-        } else if (ret > 0) {
-            break;
-        }
 
-    }
 
-    return 0;
-}
+static void
+jpc_dec_process_crg(jpc_dec_t *   const dec,
+                    jpc_ms_t *    const ms,
+                    bool *        const doneP,
+                    const char ** const errorP) {
 
-static int jpc_dec_process_crg(jpc_dec_t *dec, jpc_ms_t *ms)
-{
     /* Ignore the information in the CRG marker segment for now.
        This information serves no useful purpose for decoding anyhow.
        Some other parts of the code need to be changed if these lines
@@ -475,19 +556,33 @@ static int jpc_dec_process_crg(jpc_dec_t *dec, jpc_ms_t *ms)
         cmpt->vsubstep = crg->comps[cmptno].voff;
     }
 #endif
-    return 0;
+    *doneP = false;
+    *errorP = NULL;
 }
 
-static int jpc_dec_process_soc(jpc_dec_t *dec, jpc_ms_t *ms)
-{
+
+
+static void
+jpc_dec_process_soc(jpc_dec_t *   const dec,
+                    jpc_ms_t *    const ms,
+                    bool *        const doneP,
+                    const char ** const errorP) {
+
     /* We should expect to encounter a SIZ marker segment next. */
     dec->state = JPC_MHSIZ;
 
-    return 0;
+    *doneP = false;
+    *errorP = NULL;
 }
 
-static int jpc_dec_process_sot(jpc_dec_t *dec, jpc_ms_t *ms)
-{
+
+
+static void
+jpc_dec_process_sot(jpc_dec_t *   const dec,
+                    jpc_ms_t *    const ms,
+                    bool *        const doneP,
+                    const char ** const errorP) {
+
     jpc_dec_tile_t *tile;
     jpc_sot_t *sot = &ms->parms.sot;
     jas_image_cmptparm_t *compinfos;
@@ -512,8 +607,9 @@ static int jpc_dec_process_sot(jpc_dec_t *dec, jpc_ms_t *ms)
         }
 
         if (!(dec->image = jas_image_create(dec->numcomps, compinfos,
-          JAS_IMAGE_CS_UNKNOWN))) {
-            return -1;
+                                            JAS_IMAGE_CS_UNKNOWN))) {
+            pm_asprintf(errorP, "jas_image_create failed");
+            return;
         }
         jas_free(compinfos);
 
@@ -538,18 +634,20 @@ static int jpc_dec_process_sot(jpc_dec_t *dec, jpc_ms_t *ms)
     }
 
     if (sot->tileno > dec->numtiles) {
-        fprintf(stderr, "invalid tile number in SOT marker segment\n");
-        return -1;
+        pm_asprintf(errorP, "invalid tile number in SOT marker segment");
+        return;
     }
     /* Set the current tile. */
     dec->curtile = &dec->tiles[sot->tileno];
     tile = dec->curtile;
     /* Ensure that this is the expected part number. */
     if (sot->partno != tile->partno) {
-        return -1;
+        pm_asprintf(errorP, "Unexpected part number");
+        return;
     }
     if (tile->numparts > 0 && sot->partno >= tile->numparts) {
-        return -1;
+        pm_asprintf(errorP, "part number greater than number of parts");
+        return;
     }
     if (!tile->numparts && sot->numparts > 0) {
         tile->numparts = sot->numparts;
@@ -563,7 +661,8 @@ static int jpc_dec_process_sot(jpc_dec_t *dec, jpc_ms_t *ms)
         tile->state = JPC_TILE_ACTIVE;
         assert(!tile->cp);
         if (!(tile->cp = jpc_dec_cp_copy(dec->cp))) {
-            return -1;
+            pm_asprintf(errorP, "jpc_dec_cp_copy failed");
+            return;
         }
         jpc_dec_cp_resetflags(dec->cp);
         break;
@@ -581,107 +680,11 @@ static int jpc_dec_process_sot(jpc_dec_t *dec, jpc_ms_t *ms)
       segments next. */
     dec->state = JPC_TPH;
 
-    return 0;
+    *doneP = false;
+    *errorP = NULL;
 }
 
-static int jpc_dec_process_sod(jpc_dec_t *dec, jpc_ms_t *ms)
-{
-    jpc_dec_tile_t *tile;
-    int pos;
-
-    if (!(tile = dec->curtile)) {
-        return -1;
-    }
-
-    if (!tile->partno) {
-        if (!jpc_dec_cp_isvalid(tile->cp)) {
-            return -1;
-        }
-        if (jpc_dec_cp_prepare(tile->cp)) {
-            return -1;
-        }
-        if (jpc_dec_tileinit(dec, tile)) {
-            return -1;
-        }
-    }
-
-    /* Are packet headers stored in the main header or tile-part header? */
-    if (dec->pkthdrstreams) {
-        /* Get the stream containing the packet header data for this
-          tile-part. */
-        if (!(tile->pkthdrstream = jpc_streamlist_remove(dec->pkthdrstreams, 0))) {
-            return -1;
-        }
-    }
-
-    if (tile->pptstab) {
-        if (!tile->pkthdrstream) {
-            if (!(tile->pkthdrstream = jas_stream_memopen(0, 0))) {
-                return -1;
-            }
-        }
-        pos = jas_stream_tell(tile->pkthdrstream);
-        jas_stream_seek(tile->pkthdrstream, 0, SEEK_END);
-        if (jpc_pptstabwrite(tile->pkthdrstream, tile->pptstab)) {
-            return -1;
-        }
-        jas_stream_seek(tile->pkthdrstream, pos, SEEK_SET);
-        jpc_ppxstab_destroy(tile->pptstab);
-        tile->pptstab = 0;
-    }
-
-    if (jas_getdbglevel() >= 10) {
-        jpc_dec_dump(dec, stderr);
-    }
-
-    if (jpc_dec_decodepkts(dec, (tile->pkthdrstream) ? tile->pkthdrstream :
-      dec->in, dec->in)) {
-        fprintf(stderr, "jpc_dec_decodepkts failed\n");
-        return -1;
-    }
-
-    /* Gobble any unconsumed tile data. */
-    if (dec->curtileendoff > 0) {
-        uint_fast32_t curoff;
-        uint_fast32_t n;
-        curoff = jas_stream_getrwcount(dec->in);
-        if (curoff < dec->curtileendoff) {
-            n = dec->curtileendoff - curoff;
-            fprintf(stderr,
-              "warning: ignoring trailing garbage (%lu bytes)\n",
-              (unsigned long) n);
-
-            while (n-- > 0) {
-                if (jas_stream_getc(dec->in) == EOF) {
-                    fprintf(stderr, "read error\n");
-                    return -1;
-                }
-            }
-        } else if (curoff > dec->curtileendoff) {
-            fprintf(stderr,
-              "warning: not enough tile data (%lu bytes)\n",
-              (unsigned long) curoff - dec->curtileendoff);
-        }
-
-    }
-
-    if (tile->numparts > 0 && tile->partno == tile->numparts - 1) {
-        if (jpc_dec_tiledecode(dec, tile)) {
-            return -1;
-        }
-        jpc_dec_tilefini(dec, tile);
-    }
-
-    dec->curtile = 0;
-
-    /* Increment the expected tile-part number. */
-    ++tile->partno;
-
-    /* We should expect to encounter a SOT marker segment next. */
-    dec->state = JPC_TPHSOT;
 
-    return 0;
-}
 
 static int jpc_dec_tileinit(jpc_dec_t *dec, jpc_dec_tile_t *tile)
 {
@@ -1059,136 +1062,25 @@ if (!prc->cblks) {
     return 0;
 }
 
-static int jpc_dec_tiledecode(jpc_dec_t *dec, jpc_dec_tile_t *tile)
-{
-    int i;
-    int j;
-    jpc_dec_tcomp_t *tcomp;
-    jpc_dec_rlvl_t *rlvl;
-    jpc_dec_band_t *band;
-    int compno;
-    int rlvlno;
-    int bandno;
-    int adjust;
-    int v;
-    jpc_dec_ccp_t *ccp;
-    jpc_dec_cmpt_t *cmpt;
 
-    if (jpc_dec_decodecblks(dec, tile)) {
-        fprintf(stderr, "jpc_dec_decodecblks failed\n");
-        return -1;
-    }
 
-    /* Perform dequantization. */
-    for (compno = 0, tcomp = tile->tcomps; compno < dec->numcomps;
-      ++compno, ++tcomp) {
-        ccp = &tile->cp->ccps[compno];
-        for (rlvlno = 0, rlvl = tcomp->rlvls; rlvlno < tcomp->numrlvls;
-          ++rlvlno, ++rlvl) {
-            if (!rlvl->bands) {
-                continue;
-            }
-            for (bandno = 0, band = rlvl->bands;
-              bandno < rlvl->numbands; ++bandno, ++band) {
-                if (!band->data) {
-                    continue;
-                }
-                jpc_undo_roi(band->data, band->roishift, ccp->roishift -
-                  band->roishift, band->numbps);
-                if (tile->realmode) {
-                    jas_matrix_asl(band->data, JPC_FIX_FRACBITS);
-                    jpc_dequantize(band->data, band->absstepsize);
-                }
+static void
+jpc_dec_process_eoc(jpc_dec_t *   const dec,
+                    jpc_ms_t *    const ms,
+                    bool *        const doneP,
+                    const char ** const errorP) {
 
-            }
-        }
-    }
-
-    /* Apply an inverse wavelet transform if necessary. */
-    for (compno = 0, tcomp = tile->tcomps; compno < dec->numcomps;
-      ++compno, ++tcomp) {
-        ccp = &tile->cp->ccps[compno];
-        jpc_tsfb_synthesize(tcomp->tsfb, ((ccp->qmfbid ==
-          JPC_COX_RFT) ? JPC_TSFB_RITIMODE : 0), tcomp->data);
-    }
-
-
-    /* Apply an inverse intercomponent transform if necessary. */
-    switch (tile->cp->mctid) {
-    case JPC_MCT_RCT:
-        assert(dec->numcomps == 3);
-        jpc_irct(tile->tcomps[0].data, tile->tcomps[1].data,
-          tile->tcomps[2].data);
-        break;
-    case JPC_MCT_ICT:
-        assert(dec->numcomps == 3);
-        jpc_iict(tile->tcomps[0].data, tile->tcomps[1].data,
-          tile->tcomps[2].data);
-        break;
-    }
-
-    /* Perform rounding and convert to integer values. */
-    if (tile->realmode) {
-        for (compno = 0, tcomp = tile->tcomps; compno < dec->numcomps;
-          ++compno, ++tcomp) {
-            for (i = 0; i < jas_matrix_numrows(tcomp->data); ++i) {
-                for (j = 0; j < jas_matrix_numcols(tcomp->data); ++j) {
-                    v = jas_matrix_get(tcomp->data, i, j);
-                    v = jpc_fix_round(v);
-                    jas_matrix_set(tcomp->data, i, j, jpc_fixtoint(v));
-                }
-            }
-        }
-    }
-
-    /* Perform level shift. */
-    for (compno = 0, tcomp = tile->tcomps, cmpt = dec->cmpts; compno <
-      dec->numcomps; ++compno, ++tcomp, ++cmpt) {
-        adjust = cmpt->sgnd ? 0 : (1 << (cmpt->prec - 1));
-        for (i = 0; i < jas_matrix_numrows(tcomp->data); ++i) {
-            for (j = 0; j < jas_matrix_numcols(tcomp->data); ++j) {
-                *jas_matrix_getref(tcomp->data, i, j) += adjust;
-            }
-        }
-    }
-
-    /* Perform clipping. */
-    for (compno = 0, tcomp = tile->tcomps, cmpt = dec->cmpts; compno <
-      dec->numcomps; ++compno, ++tcomp, ++cmpt) {
-        jpc_fix_t mn;
-        jpc_fix_t mx;
-        mn = cmpt->sgnd ? (-(1 << (cmpt->prec - 1))) : (0);
-        mx = cmpt->sgnd ? ((1 << (cmpt->prec - 1)) - 1) : ((1 <<
-          cmpt->prec) - 1);
-        jas_matrix_clip(tcomp->data, mn, mx);
-    }
-
-    /* XXX need to free tsfb struct */
-
-    /* Write the data for each component of the image. */
-    for (compno = 0, tcomp = tile->tcomps, cmpt = dec->cmpts; compno <
-      dec->numcomps; ++compno, ++tcomp, ++cmpt) {
-        if (jas_image_writecmpt(dec->image, compno, tcomp->xstart -
-          JPC_CEILDIV(dec->xstart, cmpt->hstep), tcomp->ystart -
-          JPC_CEILDIV(dec->ystart, cmpt->vstep), jas_matrix_numcols(
-          tcomp->data), jas_matrix_numrows(tcomp->data), tcomp->data)) {
-            fprintf(stderr, "write component failed\n");
-            return -4;
-        }
-    }
-
-    return 0;
-}
-
-static int jpc_dec_process_eoc(jpc_dec_t *dec, jpc_ms_t *ms)
-{
     int tileno;
     jpc_dec_tile_t *tile;
     for (tileno = 0, tile = dec->tiles; tileno < dec->numtiles; ++tileno,
       ++tile) {
         if (tile->state == JPC_TILE_ACTIVE) {
-            if (jpc_dec_tiledecode(dec, tile)) {
-                return -1;
+            const char * error;
+            jpc_dec_tiledecode(dec, tile, &error);
+            if (error) {
+                pm_asprintf(errorP, "jpc_dec_tiledecode failed.  %s", error);
+                pm_strfree(error);
+                return;
             }
         }
         jpc_dec_tilefini(dec, tile);
@@ -1197,11 +1089,17 @@ static int jpc_dec_process_eoc(jpc_dec_t *dec, jpc_ms_t *ms)
     /* We are done processing the code stream. */
     dec->state = JPC_MT;
 
-    return 1;
+    *doneP = true;
 }
 
-static int jpc_dec_process_siz(jpc_dec_t *dec, jpc_ms_t *ms)
-{
+
+
+static void
+jpc_dec_process_siz(jpc_dec_t *   const dec,
+                    jpc_ms_t *    const ms,
+                    bool *        const doneP,
+                    const char ** const errorP) {
+
     jpc_siz_t *siz = &ms->parms.siz;
     uint_fast16_t compno;
     uint_fast32_t tileno;
@@ -1221,11 +1119,13 @@ static int jpc_dec_process_siz(jpc_dec_t *dec, jpc_ms_t *ms)
     dec->tileyoff = siz->tileyoff;
     dec->numcomps = siz->numcomps;
     if (!(dec->cp = jpc_dec_cp_create(dec->numcomps))) {
-        return -1;
+        pm_asprintf(errorP, "jpc_dec_cp_create failed");
+        return;
     }
 
     if (!(dec->cmpts = jas_malloc(dec->numcomps * sizeof(jpc_dec_cmpt_t)))) {
-        return -1;
+        pm_asprintf(errorP, "jas_malloc failed");
+        return;
     }
 
     for (compno = 0, cmpt = dec->cmpts; compno < dec->numcomps; ++compno,
@@ -1248,7 +1148,8 @@ static int jpc_dec_process_siz(jpc_dec_t *dec, jpc_ms_t *ms)
     dec->numvtiles = JPC_CEILDIV(dec->yend - dec->tileyoff, dec->tileheight);
     dec->numtiles = dec->numhtiles * dec->numvtiles;
     if (!(dec->tiles = jas_malloc(dec->numtiles * sizeof(jpc_dec_tile_t)))) {
-        return -1;
+        pm_asprintf(errorP, "jas_malloc failed");
+        return;
     }
 
     for (tileno = 0, tile = dec->tiles;
@@ -1280,9 +1181,10 @@ static int jpc_dec_process_siz(jpc_dec_t *dec, jpc_ms_t *ms)
         tile->pkthdrstreampos = 0;
         tile->pptstab = 0;
         tile->cp = 0;
-        if (!(tile->tcomps = jas_malloc(dec->numcomps *
-          sizeof(jpc_dec_tcomp_t)))) {
-            return -1;
+        tile->tcomps = jas_malloc(dec->numcomps * sizeof(jpc_dec_tcomp_t));
+        if (!tile->tcomps) {
+            pm_asprintf(errorP, "jas_malloc failed");
+            return;
         }
         for (compno = 0, cmpt = dec->cmpts, tcomp = tile->tcomps;
           compno < dec->numcomps; ++compno, ++cmpt, ++tcomp) {
@@ -1302,11 +1204,18 @@ static int jpc_dec_process_siz(jpc_dec_t *dec, jpc_ms_t *ms)
       or an SOT marker segment next. */
     dec->state = JPC_MH;
 
-    return 0;
+    *doneP = false;
+    *errorP = NULL;
 }
 
-static int jpc_dec_process_cod(jpc_dec_t *dec, jpc_ms_t *ms)
-{
+
+
+static void
+jpc_dec_process_cod(jpc_dec_t *   const dec,
+                    jpc_ms_t *    const ms,
+                    bool *        const doneP,
+                    const char ** const errorP) {
+
     jpc_cod_t *cod = &ms->parms.cod;
     jpc_dec_tile_t *tile;
 
@@ -1316,26 +1225,34 @@ static int jpc_dec_process_cod(jpc_dec_t *dec, jpc_ms_t *ms)
         break;
     case JPC_TPH:
         if (!(tile = dec->curtile)) {
-            return -1;
+            pm_asprintf(errorP, "No current tile");
+            return;
         }
         if (tile->partno != 0) {
-            return -1;
+            pm_asprintf(errorP, "part number is not zero");
+            return;
         }
         jpc_dec_cp_setfromcod(tile->cp, cod);
         break;
     }
-    return 0;
+    *doneP = false;
+    *errorP = NULL;
 }
 
-static int jpc_dec_process_coc(jpc_dec_t *dec, jpc_ms_t *ms)
-{
+
+
+static void
+jpc_dec_process_coc(jpc_dec_t *   const dec,
+                    jpc_ms_t *    const ms,
+                    bool *        const doneP,
+                    const char ** const errorP) {
+
     jpc_coc_t *coc = &ms->parms.coc;
     jpc_dec_tile_t *tile;
 
     if (coc->compno > dec->numcomps) {
-        fprintf(stderr,
-          "invalid component number in COC marker segment\n");
-        return -1;
+        pm_asprintf(errorP, "invalid component number in COC marker segment");
+        return;
     }
     switch (dec->state) {
     case JPC_MH:
@@ -1343,26 +1260,34 @@ static int jpc_dec_process_coc(jpc_dec_t *dec, jpc_ms_t *ms)
         break;
     case JPC_TPH:
         if (!(tile = dec->curtile)) {
-            return -1;
+            pm_asprintf(errorP, "No current tile");
+            return;
         }
         if (tile->partno > 0) {
-            return -1;
+            pm_asprintf(errorP, "Part number is not zero");
+            return;
         }
         jpc_dec_cp_setfromcoc(tile->cp, coc);
         break;
     }
-    return 0;
+    *doneP = false;
+    *errorP = NULL;
 }
 
-static int jpc_dec_process_rgn(jpc_dec_t *dec, jpc_ms_t *ms)
-{
+
+
+static void
+jpc_dec_process_rgn(jpc_dec_t *   const dec,
+                    jpc_ms_t *    const ms,
+                    bool *        const doneP,
+                    const char ** const errorP) {
+
     jpc_rgn_t *rgn = &ms->parms.rgn;
     jpc_dec_tile_t *tile;
 
     if (rgn->compno > dec->numcomps) {
-        fprintf(stderr,
-          "invalid component number in RGN marker segment\n");
-        return -1;
+        pm_asprintf(errorP, "invalid component number in RGN marker segment");
+        return;
     }
     switch (dec->state) {
     case JPC_MH:
@@ -1370,20 +1295,29 @@ static int jpc_dec_process_rgn(jpc_dec_t *dec, jpc_ms_t *ms)
         break;
     case JPC_TPH:
         if (!(tile = dec->curtile)) {
-            return -1;
+            pm_asprintf(errorP, "No current tile");
+            return;
         }
         if (tile->partno > 0) {
-            return -1;
+            pm_asprintf(errorP, "Part number is not zero");
+            return;
         }
         jpc_dec_cp_setfromrgn(tile->cp, rgn);
         break;
     }
 
-    return 0;
+    *doneP = false;
+    *errorP = NULL;
 }
 
-static int jpc_dec_process_qcd(jpc_dec_t *dec, jpc_ms_t *ms)
-{
+
+
+static void
+jpc_dec_process_qcd(jpc_dec_t *   const dec,
+                    jpc_ms_t *    const ms,
+                    bool *        const doneP,
+                    const char ** const errorP) {
+
     jpc_qcd_t *qcd = &ms->parms.qcd;
     jpc_dec_tile_t *tile;
 
@@ -1393,26 +1327,34 @@ static int jpc_dec_process_qcd(jpc_dec_t *dec, jpc_ms_t *ms)
         break;
     case JPC_TPH:
         if (!(tile = dec->curtile)) {
-            return -1;
+            pm_asprintf(errorP, "No current tile");
+            return;
         }
         if (tile->partno > 0) {
-            return -1;
+            pm_asprintf(errorP, "Part number is not zero");
+            return;
         }
         jpc_dec_cp_setfromqcd(tile->cp, qcd);
         break;
     }
-    return 0;
+    *doneP = false;
+    *errorP = NULL;
 }
 
-static int jpc_dec_process_qcc(jpc_dec_t *dec, jpc_ms_t *ms)
-{
+
+
+static void
+jpc_dec_process_qcc(jpc_dec_t *   const dec,
+                    jpc_ms_t *    const ms,
+                    bool *        const doneP,
+                    const char ** const errorP) {
+
     jpc_qcc_t *qcc = &ms->parms.qcc;
     jpc_dec_tile_t *tile;
 
     if (qcc->compno > dec->numcomps) {
-        fprintf(stderr,
-          "invalid component number in QCC marker segment\n");
-        return -1;
+        pm_asprintf(errorP, "invalid component number in QCC marker segment");
+        return;
     }
     switch (dec->state) {
     case JPC_MH:
@@ -1420,69 +1362,98 @@ static int jpc_dec_process_qcc(jpc_dec_t *dec, jpc_ms_t *ms)
         break;
     case JPC_TPH:
         if (!(tile = dec->curtile)) {
-            return -1;
+            pm_asprintf(errorP, "No current tile");
+            return;
         }
         if (tile->partno > 0) {
-            return -1;
+            pm_asprintf(errorP, "Part number is not zero");
+            return;
         }
         jpc_dec_cp_setfromqcc(tile->cp, qcc);
         break;
     }
-    return 0;
+    *doneP = false;
+    *errorP = NULL;
 }
 
-static int jpc_dec_process_poc(jpc_dec_t *dec, jpc_ms_t *ms)
-{
+
+
+static void
+jpc_dec_process_poc(jpc_dec_t *   const dec,
+                    jpc_ms_t *    const ms,
+                    bool *        const doneP,
+                    const char ** const errorP) {
+
     jpc_poc_t *poc = &ms->parms.poc;
     jpc_dec_tile_t *tile;
     switch (dec->state) {
     case JPC_MH:
         if (jpc_dec_cp_setfrompoc(dec->cp, poc, 1)) {
-            return -1;
+            pm_asprintf(errorP, "jpc_dec_cp_setfrompoc failed");
+            return;
         }
         break;
     case JPC_TPH:
         if (!(tile = dec->curtile)) {
-            return -1;
+            pm_asprintf(errorP, "No current tile");
+            return;
         }
         if (!tile->partno) {
             if (jpc_dec_cp_setfrompoc(tile->cp, poc, (!tile->partno))) {
-                return -1;
+                pm_asprintf(errorP, "jpc_dec_cp_setfrompoc failed");
+                return;
             }
         } else {
             jpc_pi_addpchgfrompoc(tile->pi, poc);
         }
         break;
     }
-    return 0;
+    *doneP = false;
+    *errorP = NULL;
 }
 
-static int jpc_dec_process_ppm(jpc_dec_t *dec, jpc_ms_t *ms)
-{
+
+
+static void
+jpc_dec_process_ppm(jpc_dec_t *   const dec,
+                    jpc_ms_t *    const ms,
+                    bool *        const doneP,
+                    const char ** const errorP) {
+
     jpc_ppm_t *ppm = &ms->parms.ppm;
     jpc_ppxstabent_t *ppmstabent;
 
     if (!dec->ppmstab) {
         if (!(dec->ppmstab = jpc_ppxstab_create())) {
-            return -1;
+            pm_asprintf(errorP, "jpc_ppxstab_create failed");
+            return;
         }
     }
 
     if (!(ppmstabent = jpc_ppxstabent_create())) {
-        return -1;
+        pm_asprintf(errorP, "jpc_ppxstabent_create failed");
+        return;
     }
     ppmstabent->ind = ppm->ind;
     ppmstabent->data = ppm->data;
     ppm->data = 0;
     ppmstabent->len = ppm->len;
     if (jpc_ppxstab_insert(dec->ppmstab, ppmstabent)) {
-        return -1;
+        pm_asprintf(errorP, "jpc_ppxstab_insert failed");
+        return;
     }
-    return 0;
+    *doneP = false;
+    *errorP = NULL;
 }
 
-static int jpc_dec_process_ppt(jpc_dec_t *dec, jpc_ms_t *ms)
-{
+
+
+static void
+jpc_dec_process_ppt(jpc_dec_t *   const dec,
+                    jpc_ms_t *    const ms,
+                    bool *        const doneP,
+                    const char ** const errorP) {
+
     jpc_ppt_t *ppt = &ms->parms.ppt;
     jpc_dec_tile_t *tile;
     jpc_ppxstabent_t *pptstabent;
@@ -1490,34 +1461,55 @@ static int jpc_dec_process_ppt(jpc_dec_t *dec, jpc_ms_t *ms)
     tile = dec->curtile;
     if (!tile->pptstab) {
         if (!(tile->pptstab = jpc_ppxstab_create())) {
-            return -1;
+            pm_asprintf(errorP, "jpc_ppxstab_create failed");
+            return;
         }
     }
     if (!(pptstabent = jpc_ppxstabent_create())) {
-        return -1;
+        pm_asprintf(errorP, "jpc_ppxstabent_create failed");
+        return;
     }
     pptstabent->ind = ppt->ind;
     pptstabent->data = ppt->data;
     ppt->data = 0;
     pptstabent->len = ppt->len;
     if (jpc_ppxstab_insert(tile->pptstab, pptstabent)) {
-        return -1;
+        pm_asprintf(errorP, "jpc_ppxstab_insert failed.");
+        return;
     }
-    return 0;
+    *doneP = false;
+    *errorP = NULL;
 }
 
-static int jpc_dec_process_com(jpc_dec_t *dec, jpc_ms_t *ms)
-{
-    return 0;
+
+
+static void
+jpc_dec_process_com(jpc_dec_t *   const dec,
+                    jpc_ms_t *    const ms,
+                    bool *        const doneP,
+                    const char ** const errorP) {
+
+    *doneP = false;
+    *errorP = NULL;
 }
 
-static int jpc_dec_process_unk(jpc_dec_t *dec, jpc_ms_t *ms)
-{
-    fprintf(stderr, "warning: ignoring unknown marker segment\n");
+
+
+static void
+jpc_dec_process_unk(jpc_dec_t *   const dec,
+                    jpc_ms_t *    const ms,
+                    bool *        const doneP,
+                    const char ** const errorP) {
+
+    pm_message("warning: ignoring unknown marker segment");
     jpc_ms_dump(ms, stderr);
-    return 0;
+
+    *doneP = false;
+    *errorP = NULL;
 }
 
+
+
 /******************************************************************************\
 *
 \******************************************************************************/
@@ -2370,3 +2362,168 @@ void jpc_ppxstabent_destroy(jpc_ppxstabent_t *ent)
     }
     jas_free(ent);
 }
+
+
+
+jpc_dec_mstabent_t jpc_dec_mstab[] = {
+    {JPC_MS_SOC, JPC_MHSOC, jpc_dec_process_soc},
+    {JPC_MS_SOT, JPC_MH | JPC_TPHSOT, jpc_dec_process_sot},
+    {JPC_MS_SOD, JPC_TPH, jpc_dec_process_sod},
+    {JPC_MS_EOC, JPC_TPHSOT, jpc_dec_process_eoc},
+    {JPC_MS_SIZ, JPC_MHSIZ, jpc_dec_process_siz},
+    {JPC_MS_COD, JPC_MH | JPC_TPH, jpc_dec_process_cod},
+    {JPC_MS_COC, JPC_MH | JPC_TPH, jpc_dec_process_coc},
+    {JPC_MS_RGN, JPC_MH | JPC_TPH, jpc_dec_process_rgn},
+    {JPC_MS_QCD, JPC_MH | JPC_TPH, jpc_dec_process_qcd},
+    {JPC_MS_QCC, JPC_MH | JPC_TPH, jpc_dec_process_qcc},
+    {JPC_MS_POC, JPC_MH | JPC_TPH, jpc_dec_process_poc},
+    {JPC_MS_TLM, JPC_MH, 0},
+    {JPC_MS_PLM, JPC_MH, 0},
+    {JPC_MS_PLT, JPC_TPH, 0},
+    {JPC_MS_PPM, JPC_MH, jpc_dec_process_ppm},
+    {JPC_MS_PPT, JPC_TPH, jpc_dec_process_ppt},
+    {JPC_MS_SOP, 0, 0},
+    {JPC_MS_CRG, JPC_MH, jpc_dec_process_crg},
+    {JPC_MS_COM, JPC_MH | JPC_TPH, jpc_dec_process_com},
+    {0, JPC_MH | JPC_TPH, jpc_dec_process_unk}
+};
+
+
+
+static jpc_dec_mstabent_t *jpc_dec_mstab_lookup(uint_fast16_t id)
+{
+    jpc_dec_mstabent_t *mstabent;
+    for (mstabent = jpc_dec_mstab; mstabent->id != 0; ++mstabent) {
+        if (mstabent->id == id) {
+            break;
+        }
+    }
+    return mstabent;
+}
+
+
+
+static void
+jpc_dec_decode(jpc_dec_t *   const dec,
+               const char ** const errorP) {
+
+    jpc_ms_t *ms;
+    jpc_dec_mstabent_t *mstabent;
+    bool done;
+    jpc_cstate_t *cstate;
+
+    if (!(cstate = jpc_cstate_create())) {
+        pm_asprintf(errorP, "jpc_cstate_create failed");
+        return;
+    }
+    dec->cstate = cstate;
+
+    /* Initially, we should expect to encounter a SOC marker segment. */
+    dec->state = JPC_MHSOC;
+
+    *errorP = NULL;   /* initial value */
+
+    for (;;) {
+
+        /* Get the next marker segment in the code stream. */
+        if (!(ms = jpc_getms(dec->in, cstate))) {
+            pm_asprintf(errorP, "cannot get marker segment");
+            return;
+        }
+
+        mstabent = jpc_dec_mstab_lookup(ms->id);
+        assert(mstabent);
+
+        /* Ensure that this type of marker segment is permitted
+          at this point in the code stream. */
+        if (!(dec->state & mstabent->validstates)) {
+            pm_asprintf(errorP, "unexpected marker segment type");
+            jpc_ms_destroy(ms);
+            return;
+        }
+
+        /* Process the marker segment. */
+        if (mstabent->action) {
+            (*mstabent->action)(dec, ms, &done, errorP);
+        } else {
+            /* No explicit action is required. */
+            *errorP = NULL;
+            done = false;
+        }
+
+        /* Destroy the marker segment. */
+        jpc_ms_destroy(ms);
+
+        if (*errorP) {
+            return;
+        } else if (done) {
+            break;
+        }
+    }
+}
+
+
+
+/*****************************************************************************\
+* The main entry point for the JPEG-2000 decoder.
+\*****************************************************************************/
+
+void
+jpc_decode(jas_stream_t * const in,
+           const char *   const optstr,
+           jas_image_t ** const imagePP,
+           const char **  const errorP) {
+
+    jpc_dec_importopts_t opts;
+    jpc_dec_t *dec;
+    jas_image_t *image;
+    const char * error;
+
+    if (jpc_dec_parseopts(optstr, &opts)) {
+        pm_asprintf(errorP, "jpc_dec_parseopts failed");
+        return;
+    }
+
+    jpc_initluts();
+
+    dec = jpc_dec_create(&opts, in);
+
+    if (!dec) {
+        pm_asprintf(errorP, "jpc_dec_create failed");
+    } else {
+        /* Do most of the work. */
+        jpc_dec_decode(dec, &error);
+        if (error) {
+            pm_asprintf(errorP, "jpc_dec_decode failed.  %s", error);
+            pm_strfree(error);
+        } else {
+            if (jas_image_numcmpts(dec->image) >= 3) {
+                jas_image_setcolorspace(dec->image, JAS_IMAGE_CS_RGB);
+                jas_image_setcmpttype(dec->image, 0,
+                                      JAS_IMAGE_CT_COLOR(JAS_IMAGE_CT_RGB_R));
+                jas_image_setcmpttype(dec->image, 1,
+                                      JAS_IMAGE_CT_COLOR(JAS_IMAGE_CT_RGB_G));
+                jas_image_setcmpttype(dec->image, 2,
+                                      JAS_IMAGE_CT_COLOR(JAS_IMAGE_CT_RGB_B));
+            } else {
+                jas_image_setcolorspace(dec->image, JAS_IMAGE_CS_GRAY);
+                jas_image_setcmpttype(dec->image, 0,
+                                      JAS_IMAGE_CT_COLOR(JAS_IMAGE_CT_GRAY_Y));
+            }
+
+            /* Save the return value. */
+            image = dec->image;
+
+            /* Stop the image from being discarded. */
+            dec->image = 0;
+
+            *imagePP = image;
+
+            *errorP = NULL;
+        }
+        jpc_dec_destroy(dec);
+    }
+}
+
+
+
diff --git a/converter/other/jpeg2000/libjasper/jpc/jpc_t1dec.c b/converter/other/jpeg2000/libjasper/jpc/jpc_t1dec.c
index 01a54ea8..b6c5e14f 100644
--- a/converter/other/jpeg2000/libjasper/jpc/jpc_t1dec.c
+++ b/converter/other/jpeg2000/libjasper/jpc/jpc_t1dec.c
@@ -124,6 +124,8 @@
 #include <stdlib.h>
 #include <assert.h>
 
+#include "netpbm/nstring.h"
+
 #include "jasper/jas_fix.h"
 #include "jasper/jas_stream.h"
 #include "jasper/jas_math.h"
@@ -138,817 +140,871 @@
 *
 \******************************************************************************/
 
-static int jpc_dec_decodecblk(jpc_dec_t *dec, jpc_dec_tile_t *tile, jpc_dec_tcomp_t *tcomp, jpc_dec_band_t *band,
-  jpc_dec_cblk_t *cblk, int dopartial, int maxlyrs);
-static int dec_sigpass(jpc_dec_t *dec, jpc_mqdec_t *mqdec, int bitpos, int orient,
-  int vcausalflag, jas_matrix_t *flags, jas_matrix_t *data);
-static int dec_rawsigpass(jpc_dec_t *dec, jpc_bitstream_t *in, int bitpos,
-  int vcausalflag, jas_matrix_t *flags, jas_matrix_t *data);
-static int dec_refpass(jpc_dec_t *dec, jpc_mqdec_t *mqdec, int bitpos, int vcausalflag,
-  jas_matrix_t *flags, jas_matrix_t *data);
-static int dec_rawrefpass(jpc_dec_t *dec, jpc_bitstream_t *in, int bitpos,
-  int vcausalflag, jas_matrix_t *flags, jas_matrix_t *data);
-static int dec_clnpass(jpc_dec_t *dec, jpc_mqdec_t *mqdec, int bitpos, int orient,
-  int vcausalflag, int segsymflag, jas_matrix_t *flags, jas_matrix_t *data);
-
 #if defined(DEBUG)
 static long t1dec_cnt = 0;
 #endif
 
 #if !defined(DEBUG)
-#define	JPC_T1D_GETBIT(mqdec, v, passtypename, symtypename) \
-	((v) = jpc_mqdec_getbit(mqdec))
+#define JPC_T1D_GETBIT(mqdec, v, passtypename, symtypename) \
+    ((v) = jpc_mqdec_getbit(mqdec))
 #else
-#define	JPC_T1D_GETBIT(mqdec, v, passtypename, symtypename) \
+#define JPC_T1D_GETBIT(mqdec, v, passtypename, symtypename) \
 { \
-	(v) = jpc_mqdec_getbit(mqdec); \
-	if (jas_getdbglevel() >= 100) { \
-		fprintf(stderr, "index = %ld; passtype = %s; symtype = %s; sym = %d\n", t1dec_cnt, passtypename, symtypename, v); \
-		++t1dec_cnt; \
-	} \
+    (v) = jpc_mqdec_getbit(mqdec); \
+    if (jas_getdbglevel() >= 100) { \
+        fprintf(stderr, "index = %ld; passtype = %s; symtype = %s; sym = %d\n", t1dec_cnt, passtypename, symtypename, v); \
+        ++t1dec_cnt; \
+    } \
 }
 #endif
-#define	JPC_T1D_GETBITNOSKEW(mqdec, v, passtypename, symtypename) \
-	JPC_T1D_GETBIT(mqdec, v, passtypename, symtypename)
+#define JPC_T1D_GETBITNOSKEW(mqdec, v, passtypename, symtypename) \
+    JPC_T1D_GETBIT(mqdec, v, passtypename, symtypename)
 
 #if !defined(DEBUG)
-#define	JPC_T1D_RAWGETBIT(bitstream, v, passtypename, symtypename) \
-	((v) = jpc_bitstream_getbit(bitstream))
+#define JPC_T1D_RAWGETBIT(bitstream, v, passtypename, symtypename) \
+    ((v) = jpc_bitstream_getbit(bitstream))
 #else
-#define	JPC_T1D_RAWGETBIT(bitstream, v, passtypename, symtypename) \
+#define JPC_T1D_RAWGETBIT(bitstream, v, passtypename, symtypename) \
 { \
-	(v) = jpc_bitstream_getbit(bitstream); \
-	if (jas_getdbglevel() >= 100) { \
-		fprintf(stderr, "index = %ld; passtype = %s; symtype = %s; sym = %d\n", t1dec_cnt, passtypename, symtypename, v); \
-		++t1dec_cnt; \
-	} \
+    (v) = jpc_bitstream_getbit(bitstream); \
+    if (jas_getdbglevel() >= 100) { \
+        fprintf(stderr, "index = %ld; passtype = %s; symtype = %s; sym = %d\n", t1dec_cnt, passtypename, symtypename, v); \
+        ++t1dec_cnt; \
+    } \
 }
 #endif
 
-/******************************************************************************\
-* Code.
-\******************************************************************************/
 
-int jpc_dec_decodecblks(jpc_dec_t *dec, jpc_dec_tile_t *tile)
-{
-	jpc_dec_tcomp_t *tcomp;
-	int compcnt;
-	jpc_dec_rlvl_t *rlvl;
-	int rlvlcnt;
-	jpc_dec_band_t *band;
-	int bandcnt;
-	jpc_dec_prc_t *prc;
-	int prccnt;
-	jpc_dec_cblk_t *cblk;
-	int cblkcnt;
-
-	for (compcnt = dec->numcomps, tcomp = tile->tcomps; compcnt > 0;
-	  --compcnt, ++tcomp) {
-		for (rlvlcnt = tcomp->numrlvls, rlvl = tcomp->rlvls;
-		  rlvlcnt > 0; --rlvlcnt, ++rlvl) {
-			if (!rlvl->bands) {
-				continue;
-			}
-			for (bandcnt = rlvl->numbands, band = rlvl->bands;
-			  bandcnt > 0; --bandcnt, ++band) {
-				if (!band->data) {
-					continue;
-				}
-				for (prccnt = rlvl->numprcs, prc = band->prcs;
-				  prccnt > 0; --prccnt, ++prc) {
-					if (!prc->cblks) {
-						continue;
-					}
-					for (cblkcnt = prc->numcblks,
-					  cblk = prc->cblks; cblkcnt > 0;
-					  --cblkcnt, ++cblk) {
-						if (jpc_dec_decodecblk(dec, tile, tcomp,
-						  band, cblk, 1, JPC_MAXLYRS)) {
-							return -1;
-						}
-					}
-				}
-
-			}
-		}
-	}
-
-	return 0;
-}
-
-static int jpc_dec_decodecblk(jpc_dec_t *dec, jpc_dec_tile_t *tile, jpc_dec_tcomp_t *tcomp, jpc_dec_band_t *band,
-  jpc_dec_cblk_t *cblk, int dopartial, int maxlyrs)
-{
-	jpc_dec_seg_t *seg;
-	int i;
-	int bpno;
-	int passtype;
-	int ret;
-	int compno;
-	int filldata;
-	int fillmask;
-	jpc_dec_ccp_t *ccp;
-
-	compno = tcomp - tile->tcomps;
-
-	if (!cblk->flags) {
-		/* Note: matrix is assumed to be zeroed */
-		if (!(cblk->flags = jas_matrix_create(jas_matrix_numrows(cblk->data) +
-		  2, jas_matrix_numcols(cblk->data) + 2))) {
-			return -1;
-		}
-	}
-
-	seg = cblk->segs.head;
-	while (seg && (seg != cblk->curseg || dopartial) && (maxlyrs < 0 ||
-	  seg->lyrno < maxlyrs)) {
-		assert(seg->numpasses >= seg->maxpasses || dopartial);
-		assert(seg->stream);
-		jas_stream_rewind(seg->stream);
-		jas_stream_setrwcount(seg->stream, 0);
-		if (seg->type == JPC_SEG_MQ) {
-			if (!cblk->mqdec) {
-				if (!(cblk->mqdec = jpc_mqdec_create(JPC_NUMCTXS, 0))) {
-					return -1;
-				}
-				jpc_mqdec_setctxs(cblk->mqdec, JPC_NUMCTXS, jpc_mqctxs);
-			}
-			jpc_mqdec_setinput(cblk->mqdec, seg->stream);
-			jpc_mqdec_init(cblk->mqdec);
-		} else {
-			assert(seg->type == JPC_SEG_RAW);
-			if (!cblk->nulldec) {
-				if (!(cblk->nulldec = jpc_bitstream_sopen(seg->stream, "r"))) {
-					assert(0);
-				}
-			}
-		}
-
-
-		for (i = 0; i < seg->numpasses; ++i) {
-			if (cblk->numimsbs > band->numbps) {
-				ccp = &tile->cp->ccps[compno];
-				if (ccp->roishift <= 0) {
-					fprintf(stderr, "warning: corrupt code stream\n");
-				} else {
-					if (cblk->numimsbs < ccp->roishift - band->numbps) {
-						fprintf(stderr, "warning: corrupt code stream\n");
-					}
-				}
-			}
-			bpno = band->roishift + band->numbps - 1 - (cblk->numimsbs +
-			  (seg->passno + i - cblk->firstpassno + 2) / 3);
-if (bpno < 0) {
-	goto premature_exit;
-}
-#if 1
-			passtype = (seg->passno + i + 2) % 3;
-#else
-			passtype = JPC_PASSTYPE(seg->passno + i + 2);
-#endif
-			assert(bpno >= 0 && bpno < 31);
-			switch (passtype) {
-			case JPC_SIGPASS:
-				ret = (seg->type == JPC_SEG_MQ) ? dec_sigpass(dec,
-				  cblk->mqdec, bpno, band->orient,
-				  (tile->cp->ccps[compno].cblkctx & JPC_COX_VSC) != 0,
-				  cblk->flags, cblk->data) :
-				  dec_rawsigpass(dec, cblk->nulldec, bpno,
-				  (tile->cp->ccps[compno].cblkctx & JPC_COX_VSC) != 0,
-				  cblk->flags, cblk->data);
-				break;
-			case JPC_REFPASS:
-				ret = (seg->type == JPC_SEG_MQ) ?
-				  dec_refpass(dec, cblk->mqdec, bpno,
-				  (tile->cp->ccps[compno].cblkctx & JPC_COX_VSC) != 0,
-				  cblk->flags, cblk->data) :
-				  dec_rawrefpass(dec, cblk->nulldec, bpno,
-				  (tile->cp->ccps[compno].cblkctx & JPC_COX_VSC) != 0,
-				  cblk->flags, cblk->data);
-				break;
-			case JPC_CLNPASS:
-				assert(seg->type == JPC_SEG_MQ);
-				ret = dec_clnpass(dec, cblk->mqdec, bpno,
-				  band->orient, (tile->cp->ccps[compno].cblkctx &
-				  JPC_COX_VSC) != 0, (tile->cp->ccps[compno].cblkctx &
-				  JPC_COX_SEGSYM) != 0, cblk->flags,
-				  cblk->data);
-				break;
-			default:
-				ret = -1;
-				break;
-			}
-			/* Do we need to reset after each coding pass? */
-			if (tile->cp->ccps[compno].cblkctx & JPC_COX_RESET) {
-				jpc_mqdec_setctxs(cblk->mqdec, JPC_NUMCTXS, jpc_mqctxs);
-			}
-
-			if (ret) {
-				fprintf(stderr, "coding pass failed passtype=%d segtype=%d\n", passtype, seg->type);
-				return -1;
-			}
-
-		}
-
-		if (seg->type == JPC_SEG_MQ) {
-/* Note: dont destroy mq decoder because context info will be lost */
-		} else {
-			assert(seg->type == JPC_SEG_RAW);
-			if (tile->cp->ccps[compno].cblkctx & JPC_COX_PTERM) {
-				fillmask = 0x7f;
-				filldata = 0x2a;
-			} else {
-				fillmask = 0;
-				filldata = 0;
-			}
-			if ((ret = jpc_bitstream_inalign(cblk->nulldec, fillmask,
-			  filldata)) < 0) {
-				return -1;
-			} else if (ret > 0) {
-				fprintf(stderr, "warning: bad termination pattern detected\n");
-			}
-			jpc_bitstream_close(cblk->nulldec);
-			cblk->nulldec = 0;
-		}
-
-		cblk->curseg = seg->next;
-		jpc_seglist_remove(&cblk->segs, seg);
-		jpc_seg_destroy(seg);
-		seg = cblk->curseg;
-	}
-
-	assert(dopartial ? (!cblk->curseg) : 1);
-
-premature_exit:
-	return 0;
-}
 
 /******************************************************************************\
 * Code for significance pass.
 \******************************************************************************/
 
-#define	jpc_sigpass_step(fp, frowstep, dp, bitpos, oneplushalf, orient, mqdec, vcausalflag) \
+#define jpc_sigpass_step(fp, frowstep, dp, bitpos, oneplushalf, orient, mqdec, vcausalflag) \
 { \
-	int f; \
-	int v; \
-	f = *(fp); \
-	if ((f & JPC_OTHSIGMSK) && !(f & (JPC_SIG | JPC_VISIT))) { \
-		jpc_mqdec_setcurctx((mqdec), JPC_GETZCCTXNO(f, (orient))); \
-		JPC_T1D_GETBIT((mqdec), v, "SIG", "ZC"); \
-		if (v) { \
-			jpc_mqdec_setcurctx((mqdec), JPC_GETSCCTXNO(f)); \
-			JPC_T1D_GETBIT((mqdec), v, "SIG", "SC"); \
-			v ^= JPC_GETSPB(f); \
-			JPC_UPDATEFLAGS4((fp), (frowstep), v, (vcausalflag)); \
-			*(fp) |= JPC_SIG; \
-			*(dp) = (v) ? (-(oneplushalf)) : (oneplushalf); \
-		} \
-		*(fp) |= JPC_VISIT; \
-	} \
+    int f; \
+    int v; \
+    f = *(fp); \
+    if ((f & JPC_OTHSIGMSK) && !(f & (JPC_SIG | JPC_VISIT))) { \
+        jpc_mqdec_setcurctx((mqdec), JPC_GETZCCTXNO(f, (orient))); \
+        JPC_T1D_GETBIT((mqdec), v, "SIG", "ZC"); \
+        if (v) { \
+            jpc_mqdec_setcurctx((mqdec), JPC_GETSCCTXNO(f)); \
+            JPC_T1D_GETBIT((mqdec), v, "SIG", "SC"); \
+            v ^= JPC_GETSPB(f); \
+            JPC_UPDATEFLAGS4((fp), (frowstep), v, (vcausalflag)); \
+            *(fp) |= JPC_SIG; \
+            *(dp) = (v) ? (-(oneplushalf)) : (oneplushalf); \
+        } \
+        *(fp) |= JPC_VISIT; \
+    } \
 }
 
-static int dec_sigpass(jpc_dec_t *dec, register jpc_mqdec_t *mqdec, int bitpos, int orient,
-  int vcausalflag, jas_matrix_t *flags, jas_matrix_t *data)
-{
-	int i;
-	int j;
-	int one;
-	int half;
-	int oneplushalf;
-	int vscanlen;
-	int width;
-	int height;
-	jpc_fix_t *fp;
-	int frowstep;
-	int fstripestep;
-	jpc_fix_t *fstripestart;
-	jpc_fix_t *fvscanstart;
-	jpc_fix_t *dp;
-	int drowstep;
-	int dstripestep;
-	jpc_fix_t *dstripestart;
-	jpc_fix_t *dvscanstart;
-	int k;
-
-	width = jas_matrix_numcols(data);
-	height = jas_matrix_numrows(data);
-	frowstep = jas_matrix_rowstep(flags);
-	drowstep = jas_matrix_rowstep(data);
-	fstripestep = frowstep << 2;
-	dstripestep = drowstep << 2;
-
-	one = 1 << bitpos;
-	half = one >> 1;
-	oneplushalf = one | half;
-
-	fstripestart = jas_matrix_getref(flags, 1, 1);
-	dstripestart = jas_matrix_getref(data, 0, 0);
-	for (i = height; i > 0; i -= 4, fstripestart += fstripestep,
-	  dstripestart += dstripestep) {
-		fvscanstart = fstripestart;
-		dvscanstart = dstripestart;
-		vscanlen = JAS_MIN(i, 4);
-		for (j = width; j > 0; --j, ++fvscanstart, ++dvscanstart) {
-			fp = fvscanstart;
-			dp = dvscanstart;
-			k = vscanlen;
-
-			/* Process first sample in vertical scan. */
-			jpc_sigpass_step(fp, frowstep, dp, bitpos, oneplushalf,
-			  orient, mqdec, vcausalflag);
-			if (--k <= 0) {
-				continue;
-			}
-			fp += frowstep;
-			dp += drowstep;
-
-			/* Process second sample in vertical scan. */
-			jpc_sigpass_step(fp, frowstep, dp, bitpos, oneplushalf,
-			  orient, mqdec, 0);
-			if (--k <= 0) {
-				continue;
-			}
-			fp += frowstep;
-			dp += drowstep;
-
-			/* Process third sample in vertical scan. */
-			jpc_sigpass_step(fp, frowstep, dp, bitpos, oneplushalf,
-			  orient, mqdec, 0);
-			if (--k <= 0) {
-				continue;
-			}
-			fp += frowstep;
-			dp += drowstep;
-
-			/* Process fourth sample in vertical scan. */
-			jpc_sigpass_step(fp, frowstep, dp, bitpos, oneplushalf,
-			  orient, mqdec, 0);
-		}
-	}
-	return 0;
+#define jpc_rawsigpass_step(fp, frowstep, dp, oneplushalf, in, vcausalflag) \
+{ \
+    jpc_fix_t f = *(fp); \
+    jpc_fix_t v; \
+    if ((f & JPC_OTHSIGMSK) && !(f & (JPC_SIG | JPC_VISIT))) { \
+        JPC_T1D_RAWGETBIT(in, v, "SIG", "ZC"); \
+        if (v < 0) { \
+            return -1; \
+        } \
+        if (v) { \
+            JPC_T1D_RAWGETBIT(in, v, "SIG", "SC"); \
+            if (v < 0) { \
+                return -1; \
+            } \
+            JPC_UPDATEFLAGS4((fp), (frowstep), v, (vcausalflag)); \
+            *(fp) |= JPC_SIG; \
+            *(dp) = v ? (-oneplushalf) : (oneplushalf); \
+        } \
+        *(fp) |= JPC_VISIT; \
+    } \
 }
 
-#define	jpc_rawsigpass_step(fp, frowstep, dp, oneplushalf, in, vcausalflag) \
-{ \
-	jpc_fix_t f = *(fp); \
-	jpc_fix_t v; \
-	if ((f & JPC_OTHSIGMSK) && !(f & (JPC_SIG | JPC_VISIT))) { \
-		JPC_T1D_RAWGETBIT(in, v, "SIG", "ZC"); \
-		if (v < 0) { \
-			return -1; \
-		} \
-		if (v) { \
-			JPC_T1D_RAWGETBIT(in, v, "SIG", "SC"); \
-			if (v < 0) { \
-				return -1; \
-			} \
-			JPC_UPDATEFLAGS4((fp), (frowstep), v, (vcausalflag)); \
-			*(fp) |= JPC_SIG; \
-			*(dp) = v ? (-oneplushalf) : (oneplushalf); \
-		} \
-		*(fp) |= JPC_VISIT; \
-	} \
+
+
+static int
+dec_sigpass(jpc_dec_t *dec, register jpc_mqdec_t *mqdec, int bitpos,
+            int orient,
+            int vcausalflag, jas_matrix_t *flags, jas_matrix_t *data)
+{
+    int i;
+    int j;
+    int one;
+    int half;
+    int oneplushalf;
+    int vscanlen;
+    int width;
+    int height;
+    jpc_fix_t *fp;
+    int frowstep;
+    int fstripestep;
+    jpc_fix_t *fstripestart;
+    jpc_fix_t *fvscanstart;
+    jpc_fix_t *dp;
+    int drowstep;
+    int dstripestep;
+    jpc_fix_t *dstripestart;
+    jpc_fix_t *dvscanstart;
+    int k;
+
+    width = jas_matrix_numcols(data);
+    height = jas_matrix_numrows(data);
+    frowstep = jas_matrix_rowstep(flags);
+    drowstep = jas_matrix_rowstep(data);
+    fstripestep = frowstep << 2;
+    dstripestep = drowstep << 2;
+
+    one = 1 << bitpos;
+    half = one >> 1;
+    oneplushalf = one | half;
+
+    fstripestart = jas_matrix_getref(flags, 1, 1);
+    dstripestart = jas_matrix_getref(data, 0, 0);
+    for (i = height; i > 0; i -= 4, fstripestart += fstripestep,
+      dstripestart += dstripestep) {
+        fvscanstart = fstripestart;
+        dvscanstart = dstripestart;
+        vscanlen = JAS_MIN(i, 4);
+        for (j = width; j > 0; --j, ++fvscanstart, ++dvscanstart) {
+            fp = fvscanstart;
+            dp = dvscanstart;
+            k = vscanlen;
+
+            /* Process first sample in vertical scan. */
+            jpc_sigpass_step(fp, frowstep, dp, bitpos, oneplushalf,
+              orient, mqdec, vcausalflag);
+            if (--k <= 0) {
+                continue;
+            }
+            fp += frowstep;
+            dp += drowstep;
+
+            /* Process second sample in vertical scan. */
+            jpc_sigpass_step(fp, frowstep, dp, bitpos, oneplushalf,
+              orient, mqdec, 0);
+            if (--k <= 0) {
+                continue;
+            }
+            fp += frowstep;
+            dp += drowstep;
+
+            /* Process third sample in vertical scan. */
+            jpc_sigpass_step(fp, frowstep, dp, bitpos, oneplushalf,
+              orient, mqdec, 0);
+            if (--k <= 0) {
+                continue;
+            }
+            fp += frowstep;
+            dp += drowstep;
+
+            /* Process fourth sample in vertical scan. */
+            jpc_sigpass_step(fp, frowstep, dp, bitpos, oneplushalf,
+              orient, mqdec, 0);
+        }
+    }
+    return 0;
 }
 
-static int dec_rawsigpass(jpc_dec_t *dec, jpc_bitstream_t *in, int bitpos, int vcausalflag,
-  jas_matrix_t *flags, jas_matrix_t *data)
+
+
+static int
+dec_rawsigpass(jpc_dec_t *dec, jpc_bitstream_t *in, int bitpos,
+               int vcausalflag,
+               jas_matrix_t *flags, jas_matrix_t *data)
 {
-	int i;
-	int j;
-	int k;
-	int one;
-	int half;
-	int oneplushalf;
-	int vscanlen;
-	int width;
-	int height;
-	jpc_fix_t *fp;
-	int frowstep;
-	int fstripestep;
-	jpc_fix_t *fstripestart;
-	jpc_fix_t *fvscanstart;
-	jpc_fix_t *dp;
-	int drowstep;
-	int dstripestep;
-	jpc_fix_t *dstripestart;
-	jpc_fix_t *dvscanstart;
-
-	width = jas_matrix_numcols(data);
-	height = jas_matrix_numrows(data);
-	frowstep = jas_matrix_rowstep(flags);
-	drowstep = jas_matrix_rowstep(data);
-	fstripestep = frowstep << 2;
-	dstripestep = drowstep << 2;
-
-	one = 1 << bitpos;
-	half = one >> 1;
-	oneplushalf = one | half;
-
-	fstripestart = jas_matrix_getref(flags, 1, 1);
-	dstripestart = jas_matrix_getref(data, 0, 0);
-	for (i = height; i > 0; i -= 4, fstripestart += fstripestep,
-	  dstripestart += dstripestep) {
-		fvscanstart = fstripestart;
-		dvscanstart = dstripestart;
-		vscanlen = JAS_MIN(i, 4);
-		for (j = width; j > 0; --j, ++fvscanstart, ++dvscanstart) {
-			fp = fvscanstart;
-			dp = dvscanstart;
-			k = vscanlen;
-
-			/* Process first sample in vertical scan. */
-			jpc_rawsigpass_step(fp, frowstep, dp, oneplushalf,
-			  in, vcausalflag);
-			if (--k <= 0) {
-				continue;
-			}
-			fp += frowstep;
-			dp += drowstep;
-
-			/* Process second sample in vertical scan. */
-			jpc_rawsigpass_step(fp, frowstep, dp, oneplushalf,
-			  in, 0);
-			if (--k <= 0) {
-				continue;
-			}
-			fp += frowstep;
-			dp += drowstep;
-
-			/* Process third sample in vertical scan. */
-			jpc_rawsigpass_step(fp, frowstep, dp, oneplushalf,
-			  in, 0);
-			if (--k <= 0) {
-				continue;
-			}
-			fp += frowstep;
-			dp += drowstep;
-
-			/* Process fourth sample in vertical scan. */
-			jpc_rawsigpass_step(fp, frowstep, dp, oneplushalf,
-			  in, 0);
-
-		}
-	}
-	return 0;
+    int i;
+    int j;
+    int k;
+    int one;
+    int half;
+    int oneplushalf;
+    int vscanlen;
+    int width;
+    int height;
+    jpc_fix_t *fp;
+    int frowstep;
+    int fstripestep;
+    jpc_fix_t *fstripestart;
+    jpc_fix_t *fvscanstart;
+    jpc_fix_t *dp;
+    int drowstep;
+    int dstripestep;
+    jpc_fix_t *dstripestart;
+    jpc_fix_t *dvscanstart;
+
+    width = jas_matrix_numcols(data);
+    height = jas_matrix_numrows(data);
+    frowstep = jas_matrix_rowstep(flags);
+    drowstep = jas_matrix_rowstep(data);
+    fstripestep = frowstep << 2;
+    dstripestep = drowstep << 2;
+
+    one = 1 << bitpos;
+    half = one >> 1;
+    oneplushalf = one | half;
+
+    fstripestart = jas_matrix_getref(flags, 1, 1);
+    dstripestart = jas_matrix_getref(data, 0, 0);
+    for (i = height; i > 0; i -= 4, fstripestart += fstripestep,
+      dstripestart += dstripestep) {
+        fvscanstart = fstripestart;
+        dvscanstart = dstripestart;
+        vscanlen = JAS_MIN(i, 4);
+        for (j = width; j > 0; --j, ++fvscanstart, ++dvscanstart) {
+            fp = fvscanstart;
+            dp = dvscanstart;
+            k = vscanlen;
+
+            /* Process first sample in vertical scan. */
+            jpc_rawsigpass_step(fp, frowstep, dp, oneplushalf,
+              in, vcausalflag);
+            if (--k <= 0) {
+                continue;
+            }
+            fp += frowstep;
+            dp += drowstep;
+
+            /* Process second sample in vertical scan. */
+            jpc_rawsigpass_step(fp, frowstep, dp, oneplushalf,
+              in, 0);
+            if (--k <= 0) {
+                continue;
+            }
+            fp += frowstep;
+            dp += drowstep;
+
+            /* Process third sample in vertical scan. */
+            jpc_rawsigpass_step(fp, frowstep, dp, oneplushalf,
+              in, 0);
+            if (--k <= 0) {
+                continue;
+            }
+            fp += frowstep;
+            dp += drowstep;
+
+            /* Process fourth sample in vertical scan. */
+            jpc_rawsigpass_step(fp, frowstep, dp, oneplushalf,
+              in, 0);
+
+        }
+    }
+    return 0;
 }
 
+
+
 /******************************************************************************\
 * Code for refinement pass.
 \******************************************************************************/
 
-#define	jpc_refpass_step(fp, dp, poshalf, neghalf, mqdec, vcausalflag) \
+#define jpc_refpass_step(fp, dp, poshalf, neghalf, mqdec, vcausalflag) \
 { \
-	int v; \
-	int t; \
-	if (((*(fp)) & (JPC_SIG | JPC_VISIT)) == JPC_SIG) { \
-		jpc_mqdec_setcurctx((mqdec), JPC_GETMAGCTXNO(*(fp))); \
-		JPC_T1D_GETBITNOSKEW((mqdec), v, "REF", "MR"); \
-		t = (v ? (poshalf) : (neghalf)); \
-		*(dp) += (*(dp) < 0) ? (-t) : t; \
-		*(fp) |= JPC_REFINE; \
-	} \
+    int v; \
+    int t; \
+    if (((*(fp)) & (JPC_SIG | JPC_VISIT)) == JPC_SIG) { \
+        jpc_mqdec_setcurctx((mqdec), JPC_GETMAGCTXNO(*(fp))); \
+        JPC_T1D_GETBITNOSKEW((mqdec), v, "REF", "MR"); \
+        t = (v ? (poshalf) : (neghalf)); \
+        *(dp) += (*(dp) < 0) ? (-t) : t; \
+        *(fp) |= JPC_REFINE; \
+    } \
 }
 
-static int dec_refpass(jpc_dec_t *dec, register jpc_mqdec_t *mqdec, int bitpos,
-  int vcausalflag, jas_matrix_t *flags, jas_matrix_t *data)
+
+
+static int
+dec_refpass(jpc_dec_t *dec, register jpc_mqdec_t *mqdec, int bitpos,
+            int vcausalflag, jas_matrix_t *flags, jas_matrix_t *data)
 {
-	int i;
-	int j;
-	int vscanlen;
-	int width;
-	int height;
-	int one;
-	int poshalf;
-	int neghalf;
-	jpc_fix_t *fp;
-	int frowstep;
-	int fstripestep;
-	jpc_fix_t *fstripestart;
-	jpc_fix_t *fvscanstart;
-	jpc_fix_t *dp;
-	int drowstep;
-	int dstripestep;
-	jpc_fix_t *dstripestart;
-	jpc_fix_t *dvscanstart;
-	int k;
-
-	width = jas_matrix_numcols(data);
-	height = jas_matrix_numrows(data);
-	frowstep = jas_matrix_rowstep(flags);
-	drowstep = jas_matrix_rowstep(data);
-	fstripestep = frowstep << 2;
-	dstripestep = drowstep << 2;
-
-	one = 1 << bitpos;
-	poshalf = one >> 1;
-	neghalf = (bitpos > 0) ? (-poshalf) : (-1);
-
-	fstripestart = jas_matrix_getref(flags, 1, 1);
-	dstripestart = jas_matrix_getref(data, 0, 0);
-	for (i = height; i > 0; i -= 4, fstripestart += fstripestep,
-	  dstripestart += dstripestep) {
-		fvscanstart = fstripestart;
-		dvscanstart = dstripestart;
-		vscanlen = JAS_MIN(i, 4);
-		for (j = width; j > 0; --j, ++fvscanstart, ++dvscanstart) {
-			fp = fvscanstart;
-			dp = dvscanstart;
-			k = vscanlen;
-
-			/* Process first sample in vertical scan. */
-			jpc_refpass_step(fp, dp, poshalf, neghalf, mqdec,
-			  vcausalflag);
-			if (--k <= 0) {
-				continue;
-			}
-			fp += frowstep;
-			dp += drowstep;
-
-			/* Process second sample in vertical scan. */
-			jpc_refpass_step(fp, dp, poshalf, neghalf, mqdec, 0);
-			if (--k <= 0) {
-				continue;
-			}
-			fp += frowstep;
-			dp += drowstep;
-
-			/* Process third sample in vertical scan. */
-			jpc_refpass_step(fp, dp, poshalf, neghalf, mqdec, 0);
-			if (--k <= 0) {
-				continue;
-			}
-			fp += frowstep;
-			dp += drowstep;
-
-			/* Process fourth sample in vertical scan. */
-			jpc_refpass_step(fp, dp, poshalf, neghalf, mqdec, 0);
-		}
-	}
-
-	return 0;
+    int i;
+    int j;
+    int vscanlen;
+    int width;
+    int height;
+    int one;
+    int poshalf;
+    int neghalf;
+    jpc_fix_t *fp;
+    int frowstep;
+    int fstripestep;
+    jpc_fix_t *fstripestart;
+    jpc_fix_t *fvscanstart;
+    jpc_fix_t *dp;
+    int drowstep;
+    int dstripestep;
+    jpc_fix_t *dstripestart;
+    jpc_fix_t *dvscanstart;
+    int k;
+
+    width = jas_matrix_numcols(data);
+    height = jas_matrix_numrows(data);
+    frowstep = jas_matrix_rowstep(flags);
+    drowstep = jas_matrix_rowstep(data);
+    fstripestep = frowstep << 2;
+    dstripestep = drowstep << 2;
+
+    one = 1 << bitpos;
+    poshalf = one >> 1;
+    neghalf = (bitpos > 0) ? (-poshalf) : (-1);
+
+    fstripestart = jas_matrix_getref(flags, 1, 1);
+    dstripestart = jas_matrix_getref(data, 0, 0);
+    for (i = height; i > 0; i -= 4, fstripestart += fstripestep,
+      dstripestart += dstripestep) {
+        fvscanstart = fstripestart;
+        dvscanstart = dstripestart;
+        vscanlen = JAS_MIN(i, 4);
+        for (j = width; j > 0; --j, ++fvscanstart, ++dvscanstart) {
+            fp = fvscanstart;
+            dp = dvscanstart;
+            k = vscanlen;
+
+            /* Process first sample in vertical scan. */
+            jpc_refpass_step(fp, dp, poshalf, neghalf, mqdec,
+              vcausalflag);
+            if (--k <= 0) {
+                continue;
+            }
+            fp += frowstep;
+            dp += drowstep;
+
+            /* Process second sample in vertical scan. */
+            jpc_refpass_step(fp, dp, poshalf, neghalf, mqdec, 0);
+            if (--k <= 0) {
+                continue;
+            }
+            fp += frowstep;
+            dp += drowstep;
+
+            /* Process third sample in vertical scan. */
+            jpc_refpass_step(fp, dp, poshalf, neghalf, mqdec, 0);
+            if (--k <= 0) {
+                continue;
+            }
+            fp += frowstep;
+            dp += drowstep;
+
+            /* Process fourth sample in vertical scan. */
+            jpc_refpass_step(fp, dp, poshalf, neghalf, mqdec, 0);
+        }
+    }
+
+    return 0;
 }
 
-#define	jpc_rawrefpass_step(fp, dp, poshalf, neghalf, in, vcausalflag) \
+#define jpc_rawrefpass_step(fp, dp, poshalf, neghalf, in, vcausalflag) \
 { \
-	jpc_fix_t v; \
-	jpc_fix_t t; \
-	if (((*(fp)) & (JPC_SIG | JPC_VISIT)) == JPC_SIG) { \
-		JPC_T1D_RAWGETBIT(in, v, "REF", "MAGREF"); \
-		if (v < 0) { \
-			return -1; \
-		} \
-		t = (v ? poshalf : neghalf); \
-		*(dp) += (*(dp) < 0) ? (-t) : t; \
-		*(fp) |= JPC_REFINE; \
-	} \
+    jpc_fix_t v; \
+    jpc_fix_t t; \
+    if (((*(fp)) & (JPC_SIG | JPC_VISIT)) == JPC_SIG) { \
+        JPC_T1D_RAWGETBIT(in, v, "REF", "MAGREF"); \
+        if (v < 0) { \
+            return -1; \
+        } \
+        t = (v ? poshalf : neghalf); \
+        *(dp) += (*(dp) < 0) ? (-t) : t; \
+        *(fp) |= JPC_REFINE; \
+    } \
 }
 
-static int dec_rawrefpass(jpc_dec_t *dec, jpc_bitstream_t *in, int bitpos, int vcausalflag,
-  jas_matrix_t *flags, jas_matrix_t *data)
+
+
+static int
+dec_rawrefpass(jpc_dec_t *dec, jpc_bitstream_t *in, int bitpos,
+               int vcausalflag,
+               jas_matrix_t *flags, jas_matrix_t *data)
 {
-	int i;
-	int j;
-	int k;
-	int vscanlen;
-	int width;
-	int height;
-	int one;
-	int poshalf;
-	int neghalf;
-	jpc_fix_t *fp;
-	int frowstep;
-	int fstripestep;
-	jpc_fix_t *fstripestart;
-	jpc_fix_t *fvscanstart;
-	jpc_fix_t *dp;
-	int drowstep;
-	int dstripestep;
-	jpc_fix_t *dstripestart;
-	jpc_fix_t *dvscanstart;
-
-	width = jas_matrix_numcols(data);
-	height = jas_matrix_numrows(data);
-	frowstep = jas_matrix_rowstep(flags);
-	drowstep = jas_matrix_rowstep(data);
-	fstripestep = frowstep << 2;
-	dstripestep = drowstep << 2;
-
-	one = 1 << bitpos;
-	poshalf = one >> 1;
-	neghalf = (bitpos > 0) ? (-poshalf) : (-1);
-
-	fstripestart = jas_matrix_getref(flags, 1, 1);
-	dstripestart = jas_matrix_getref(data, 0, 0);
-	for (i = height; i > 0; i -= 4, fstripestart += fstripestep,
-	  dstripestart += dstripestep) {
-		fvscanstart = fstripestart;
-		dvscanstart = dstripestart;
-		vscanlen = JAS_MIN(i, 4);
-		for (j = width; j > 0; --j, ++fvscanstart, ++dvscanstart) {
-			fp = fvscanstart;
-			dp = dvscanstart;
-			k = vscanlen;
-
-			/* Process first sample in vertical scan. */
-			jpc_rawrefpass_step(fp, dp, poshalf, neghalf, in,
-			  vcausalflag);
-			if (--k <= 0) {
-				continue;
-			}
-			fp += frowstep;
-			dp += drowstep;
-
-			/* Process second sample in vertical scan. */
-			jpc_rawrefpass_step(fp, dp, poshalf, neghalf, in, 0);
-			if (--k <= 0) {
-				continue;
-			}
-			fp += frowstep;
-			dp += drowstep;
-
-			/* Process third sample in vertical scan. */
-			jpc_rawrefpass_step(fp, dp, poshalf, neghalf, in, 0);
-			if (--k <= 0) {
-				continue;
-			}
-			fp += frowstep;
-			dp += drowstep;
-
-			/* Process fourth sample in vertical scan. */
-			jpc_rawrefpass_step(fp, dp, poshalf, neghalf, in, 0);
-		}
-	}
-	return 0;
+    int i;
+    int j;
+    int k;
+    int vscanlen;
+    int width;
+    int height;
+    int one;
+    int poshalf;
+    int neghalf;
+    jpc_fix_t *fp;
+    int frowstep;
+    int fstripestep;
+    jpc_fix_t *fstripestart;
+    jpc_fix_t *fvscanstart;
+    jpc_fix_t *dp;
+    int drowstep;
+    int dstripestep;
+    jpc_fix_t *dstripestart;
+    jpc_fix_t *dvscanstart;
+
+    width = jas_matrix_numcols(data);
+    height = jas_matrix_numrows(data);
+    frowstep = jas_matrix_rowstep(flags);
+    drowstep = jas_matrix_rowstep(data);
+    fstripestep = frowstep << 2;
+    dstripestep = drowstep << 2;
+
+    one = 1 << bitpos;
+    poshalf = one >> 1;
+    neghalf = (bitpos > 0) ? (-poshalf) : (-1);
+
+    fstripestart = jas_matrix_getref(flags, 1, 1);
+    dstripestart = jas_matrix_getref(data, 0, 0);
+    for (i = height; i > 0; i -= 4, fstripestart += fstripestep,
+      dstripestart += dstripestep) {
+        fvscanstart = fstripestart;
+        dvscanstart = dstripestart;
+        vscanlen = JAS_MIN(i, 4);
+        for (j = width; j > 0; --j, ++fvscanstart, ++dvscanstart) {
+            fp = fvscanstart;
+            dp = dvscanstart;
+            k = vscanlen;
+
+            /* Process first sample in vertical scan. */
+            jpc_rawrefpass_step(fp, dp, poshalf, neghalf, in,
+              vcausalflag);
+            if (--k <= 0) {
+                continue;
+            }
+            fp += frowstep;
+            dp += drowstep;
+
+            /* Process second sample in vertical scan. */
+            jpc_rawrefpass_step(fp, dp, poshalf, neghalf, in, 0);
+            if (--k <= 0) {
+                continue;
+            }
+            fp += frowstep;
+            dp += drowstep;
+
+            /* Process third sample in vertical scan. */
+            jpc_rawrefpass_step(fp, dp, poshalf, neghalf, in, 0);
+            if (--k <= 0) {
+                continue;
+            }
+            fp += frowstep;
+            dp += drowstep;
+
+            /* Process fourth sample in vertical scan. */
+            jpc_rawrefpass_step(fp, dp, poshalf, neghalf, in, 0);
+        }
+    }
+    return 0;
 }
 
+
+
 /******************************************************************************\
 * Code for cleanup pass.
 \******************************************************************************/
 
-#define	jpc_clnpass_step(f, fp, frowstep, dp, oneplushalf, orient, mqdec, flabel, plabel, vcausalflag) \
+#define jpc_clnpass_step(f, fp, frowstep, dp, oneplushalf, orient, mqdec, flabel, plabel, vcausalflag) \
 { \
-	int v; \
+    int v; \
 flabel \
-	if (!((f) & (JPC_SIG | JPC_VISIT))) { \
-		jpc_mqdec_setcurctx((mqdec), JPC_GETZCCTXNO((f), (orient))); \
-		JPC_T1D_GETBIT((mqdec), v, "CLN", "ZC"); \
-		if (v) { \
+    if (!((f) & (JPC_SIG | JPC_VISIT))) { \
+        jpc_mqdec_setcurctx((mqdec), JPC_GETZCCTXNO((f), (orient))); \
+        JPC_T1D_GETBIT((mqdec), v, "CLN", "ZC"); \
+        if (v) { \
 plabel \
-			/* Coefficient is significant. */ \
-			jpc_mqdec_setcurctx((mqdec), JPC_GETSCCTXNO(f)); \
-			JPC_T1D_GETBIT((mqdec), v, "CLN", "SC"); \
-			v ^= JPC_GETSPB(f); \
-			*(dp) = (v) ? (-(oneplushalf)) : (oneplushalf); \
-			JPC_UPDATEFLAGS4((fp), (frowstep), v, (vcausalflag)); \
-			*(fp) |= JPC_SIG; \
-		} \
-	} \
-	/* XXX - Is this correct?  Can aggregation cause some VISIT bits not to be reset?  Check. */ \
-	*(fp) &= ~JPC_VISIT; \
+            /* Coefficient is significant. */ \
+            jpc_mqdec_setcurctx((mqdec), JPC_GETSCCTXNO(f)); \
+            JPC_T1D_GETBIT((mqdec), v, "CLN", "SC"); \
+            v ^= JPC_GETSPB(f); \
+            *(dp) = (v) ? (-(oneplushalf)) : (oneplushalf); \
+            JPC_UPDATEFLAGS4((fp), (frowstep), v, (vcausalflag)); \
+            *(fp) |= JPC_SIG; \
+        } \
+    } \
+    /* XXX - Is this correct?  Can aggregation cause some VISIT bits not to be reset?  Check. */ \
+    *(fp) &= ~JPC_VISIT; \
 }
 
-static int dec_clnpass(jpc_dec_t *dec, register jpc_mqdec_t *mqdec, int bitpos, int orient,
-  int vcausalflag, int segsymflag, jas_matrix_t *flags, jas_matrix_t *data)
+static int
+dec_clnpass(jpc_dec_t *dec, register jpc_mqdec_t *mqdec, int bitpos,
+            int orient, int vcausalflag, int segsymflag, jas_matrix_t *flags,
+            jas_matrix_t *data)
 {
-	int i;
-	int j;
-	int k;
-	int vscanlen;
-	int v;
-	int half;
-	int runlen;
-	int f;
-	int width;
-	int height;
-	int one;
-	int oneplushalf;
-
-	jpc_fix_t *fp;
-	int frowstep;
-	int fstripestep;
-	jpc_fix_t *fstripestart;
-	jpc_fix_t *fvscanstart;
-
-	jpc_fix_t *dp;
-	int drowstep;
-	int dstripestep;
-	jpc_fix_t *dstripestart;
-	jpc_fix_t *dvscanstart;
-
-	one = 1 << bitpos;
-	half = one >> 1;
-	oneplushalf = one | half;
-
-	width = jas_matrix_numcols(data);
-	height = jas_matrix_numrows(data);
-
-	frowstep = jas_matrix_rowstep(flags);
-	drowstep = jas_matrix_rowstep(data);
-	fstripestep = frowstep << 2;
-	dstripestep = drowstep << 2;
-
-	fstripestart = jas_matrix_getref(flags, 1, 1);
-	dstripestart = jas_matrix_getref(data, 0, 0);
-	for (i = 0; i < height; i += 4, fstripestart += fstripestep,
-	  dstripestart += dstripestep) {
-		fvscanstart = fstripestart;
-		dvscanstart = dstripestart;
-		vscanlen = JAS_MIN(4, height - i);
-		for (j = width; j > 0; --j, ++fvscanstart, ++dvscanstart) {
-			fp = fvscanstart;
-			if (vscanlen >= 4 && (!((*fp) & (JPC_SIG | JPC_VISIT |
-			  JPC_OTHSIGMSK))) && (fp += frowstep, !((*fp) & (JPC_SIG |
-			  JPC_VISIT | JPC_OTHSIGMSK))) && (fp += frowstep, !((*fp) &
-			  (JPC_SIG | JPC_VISIT | JPC_OTHSIGMSK))) && (fp += frowstep,
-			  !((*fp) & (JPC_SIG | JPC_VISIT | JPC_OTHSIGMSK)))) {
-
-				jpc_mqdec_setcurctx(mqdec, JPC_AGGCTXNO);
-				JPC_T1D_GETBIT(mqdec, v, "CLN", "AGG");
-				if (!v) {
-					continue;
-				}
-				jpc_mqdec_setcurctx(mqdec, JPC_UCTXNO);
-				JPC_T1D_GETBITNOSKEW(mqdec, v, "CLN", "RL");
-				runlen = v;
-				JPC_T1D_GETBITNOSKEW(mqdec, v, "CLN", "RL");
-				runlen = (runlen << 1) | v;
-				f = *(fp = fvscanstart + frowstep * runlen);
-				dp = dvscanstart + drowstep * runlen;
-				k = vscanlen - runlen;
-				switch (runlen) {
-				case 0:
-					goto clnpass_partial0;
-					break;
-				case 1:
-					goto clnpass_partial1;
-					break;
-				case 2:
-					goto clnpass_partial2;
-					break;
-				case 3:
-					goto clnpass_partial3;
-					break;
-				}
-			} else {
-				f = *(fp = fvscanstart);
-				dp = dvscanstart;
-				k = vscanlen;
-				goto clnpass_full0;
-			}
-
-			/* Process first sample in vertical scan. */
-			jpc_clnpass_step(f, fp, frowstep, dp, oneplushalf, orient,
-			  mqdec, clnpass_full0:, clnpass_partial0:,
-			  vcausalflag);
-			if (--k <= 0) {
-				continue;
-			}
-			fp += frowstep;
-			dp += drowstep;
-
-			/* Process second sample in vertical scan. */
-			f = *fp;
-			jpc_clnpass_step(f, fp, frowstep, dp, oneplushalf, orient,
-				mqdec, ;, clnpass_partial1:, 0);
-			if (--k <= 0) {
-				continue;
-			}
-			fp += frowstep;
-			dp += drowstep;
-
-			/* Process third sample in vertical scan. */
-			f = *fp;
-			jpc_clnpass_step(f, fp, frowstep, dp, oneplushalf, orient,
-				mqdec, ;, clnpass_partial2:, 0);
-			if (--k <= 0) {
-				continue;
-			}
-			fp += frowstep;
-			dp += drowstep;
-
-			/* Process fourth sample in vertical scan. */
-			f = *fp;
-			jpc_clnpass_step(f, fp, frowstep, dp, oneplushalf, orient,
-				mqdec, ;, clnpass_partial3:, 0);
-		}
-	}
-
-	if (segsymflag) {
-		int segsymval;
-		segsymval = 0;
-		jpc_mqdec_setcurctx(mqdec, JPC_UCTXNO);
-		JPC_T1D_GETBITNOSKEW(mqdec, v, "CLN", "SEGSYM");
-		segsymval = (segsymval << 1) | (v & 1);
-		JPC_T1D_GETBITNOSKEW(mqdec, v, "CLN", "SEGSYM");
-		segsymval = (segsymval << 1) | (v & 1);
-		JPC_T1D_GETBITNOSKEW(mqdec, v, "CLN", "SEGSYM");
-		segsymval = (segsymval << 1) | (v & 1);
-		JPC_T1D_GETBITNOSKEW(mqdec, v, "CLN", "SEGSYM");
-		segsymval = (segsymval << 1) | (v & 1);
-		if (segsymval != 0xa) {
-			fprintf(stderr, "warning: bad segmentation symbol\n");
-		}
-	}
-
-	return 0;
+    int i;
+    int j;
+    int k;
+    int vscanlen;
+    int v;
+    int half;
+    int runlen;
+    int f;
+    int width;
+    int height;
+    int one;
+    int oneplushalf;
+
+    jpc_fix_t *fp;
+    int frowstep;
+    int fstripestep;
+    jpc_fix_t *fstripestart;
+    jpc_fix_t *fvscanstart;
+
+    jpc_fix_t *dp;
+    int drowstep;
+    int dstripestep;
+    jpc_fix_t *dstripestart;
+    jpc_fix_t *dvscanstart;
+
+    one = 1 << bitpos;
+    half = one >> 1;
+    oneplushalf = one | half;
+
+    width = jas_matrix_numcols(data);
+    height = jas_matrix_numrows(data);
+
+    frowstep = jas_matrix_rowstep(flags);
+    drowstep = jas_matrix_rowstep(data);
+    fstripestep = frowstep << 2;
+    dstripestep = drowstep << 2;
+
+    fstripestart = jas_matrix_getref(flags, 1, 1);
+    dstripestart = jas_matrix_getref(data, 0, 0);
+    for (i = 0; i < height; i += 4, fstripestart += fstripestep,
+      dstripestart += dstripestep) {
+        fvscanstart = fstripestart;
+        dvscanstart = dstripestart;
+        vscanlen = JAS_MIN(4, height - i);
+        for (j = width; j > 0; --j, ++fvscanstart, ++dvscanstart) {
+            fp = fvscanstart;
+            if (vscanlen >= 4 && (!((*fp) & (JPC_SIG | JPC_VISIT |
+              JPC_OTHSIGMSK))) && (fp += frowstep, !((*fp) & (JPC_SIG |
+              JPC_VISIT | JPC_OTHSIGMSK))) && (fp += frowstep, !((*fp) &
+              (JPC_SIG | JPC_VISIT | JPC_OTHSIGMSK))) && (fp += frowstep,
+              !((*fp) & (JPC_SIG | JPC_VISIT | JPC_OTHSIGMSK)))) {
+
+                jpc_mqdec_setcurctx(mqdec, JPC_AGGCTXNO);
+                JPC_T1D_GETBIT(mqdec, v, "CLN", "AGG");
+                if (!v) {
+                    continue;
+                }
+                jpc_mqdec_setcurctx(mqdec, JPC_UCTXNO);
+                JPC_T1D_GETBITNOSKEW(mqdec, v, "CLN", "RL");
+                runlen = v;
+                JPC_T1D_GETBITNOSKEW(mqdec, v, "CLN", "RL");
+                runlen = (runlen << 1) | v;
+                f = *(fp = fvscanstart + frowstep * runlen);
+                dp = dvscanstart + drowstep * runlen;
+                k = vscanlen - runlen;
+                switch (runlen) {
+                case 0:
+                    goto clnpass_partial0;
+                    break;
+                case 1:
+                    goto clnpass_partial1;
+                    break;
+                case 2:
+                    goto clnpass_partial2;
+                    break;
+                case 3:
+                    goto clnpass_partial3;
+                    break;
+                }
+            } else {
+                f = *(fp = fvscanstart);
+                dp = dvscanstart;
+                k = vscanlen;
+                goto clnpass_full0;
+            }
+
+            /* Process first sample in vertical scan. */
+            jpc_clnpass_step(f, fp, frowstep, dp, oneplushalf, orient,
+              mqdec, clnpass_full0:, clnpass_partial0:,
+              vcausalflag);
+            if (--k <= 0) {
+                continue;
+            }
+            fp += frowstep;
+            dp += drowstep;
+
+            /* Process second sample in vertical scan. */
+            f = *fp;
+            jpc_clnpass_step(f, fp, frowstep, dp, oneplushalf, orient,
+                mqdec, ;, clnpass_partial1:, 0);
+            if (--k <= 0) {
+                continue;
+            }
+            fp += frowstep;
+            dp += drowstep;
+
+            /* Process third sample in vertical scan. */
+            f = *fp;
+            jpc_clnpass_step(f, fp, frowstep, dp, oneplushalf, orient,
+                mqdec, ;, clnpass_partial2:, 0);
+            if (--k <= 0) {
+                continue;
+            }
+            fp += frowstep;
+            dp += drowstep;
+
+            /* Process fourth sample in vertical scan. */
+            f = *fp;
+            jpc_clnpass_step(f, fp, frowstep, dp, oneplushalf, orient,
+                mqdec, ;, clnpass_partial3:, 0);
+        }
+    }
+
+    if (segsymflag) {
+        int segsymval;
+        segsymval = 0;
+        jpc_mqdec_setcurctx(mqdec, JPC_UCTXNO);
+        JPC_T1D_GETBITNOSKEW(mqdec, v, "CLN", "SEGSYM");
+        segsymval = (segsymval << 1) | (v & 1);
+        JPC_T1D_GETBITNOSKEW(mqdec, v, "CLN", "SEGSYM");
+        segsymval = (segsymval << 1) | (v & 1);
+        JPC_T1D_GETBITNOSKEW(mqdec, v, "CLN", "SEGSYM");
+        segsymval = (segsymval << 1) | (v & 1);
+        JPC_T1D_GETBITNOSKEW(mqdec, v, "CLN", "SEGSYM");
+        segsymval = (segsymval << 1) | (v & 1);
+        if (segsymval != 0xa) {
+            fprintf(stderr, "warning: bad segmentation symbol\n");
+        }
+    }
+
+    return 0;
+}
+
+
+
+static void
+jpc_dec_decodecblk(jpc_dec_t *       const dec,
+                   jpc_dec_tile_t *  const tile,
+                   jpc_dec_tcomp_t * const tcomp,
+                   jpc_dec_band_t *  const band,
+                   jpc_dec_cblk_t *  const cblk,
+                   int               const dopartial,
+                   int               const maxlyrs,
+                   const char **     const errorP) {
+
+    jpc_dec_seg_t *seg;
+    int i;
+    int bpno;
+    int passtype;
+    int ret;
+    int compno;
+    int filldata;
+    int fillmask;
+    jpc_dec_ccp_t *ccp;
+
+    compno = tcomp - tile->tcomps;
+
+    if (!cblk->flags) {
+        /* Note: matrix is assumed to be zeroed */
+        unsigned int const nrow = jas_matrix_numrows(cblk->data) + 2;
+        unsigned int const ncol = jas_matrix_numcols(cblk->data) + 2;
+        cblk->flags = jas_matrix_create(nrow, ncol);
+        if (!cblk->flags) {
+            pm_asprintf(errorP, "Out of memory allocating a flags matrix of "
+                        "%u rows by %u columns", nrow, ncol);
+            return;
+        }
+    }
+
+    seg = cblk->segs.head;
+    while (seg && (seg != cblk->curseg || dopartial) && (maxlyrs < 0 ||
+      seg->lyrno < maxlyrs)) {
+        assert(seg->numpasses >= seg->maxpasses || dopartial);
+        assert(seg->stream);
+        jas_stream_rewind(seg->stream);
+        jas_stream_setrwcount(seg->stream, 0);
+        if (seg->type == JPC_SEG_MQ) {
+            if (!cblk->mqdec) {
+                if (!(cblk->mqdec = jpc_mqdec_create(JPC_NUMCTXS, 0))) {
+                    pm_asprintf(errorP, "jpc_mqdec_create failed");
+                    return;
+                }
+                jpc_mqdec_setctxs(cblk->mqdec, JPC_NUMCTXS, jpc_mqctxs);
+            }
+            jpc_mqdec_setinput(cblk->mqdec, seg->stream);
+            jpc_mqdec_init(cblk->mqdec);
+        } else {
+            assert(seg->type == JPC_SEG_RAW);
+            if (!cblk->nulldec) {
+                if (!(cblk->nulldec = jpc_bitstream_sopen(seg->stream, "r"))) {
+                    assert(0);
+                }
+            }
+        }
+
+
+        for (i = 0; i < seg->numpasses; ++i) {
+            if (cblk->numimsbs > band->numbps) {
+                ccp = &tile->cp->ccps[compno];
+                if (ccp->roishift <= 0) {
+                    fprintf(stderr, "warning: corrupt code stream\n");
+                } else {
+                    if (cblk->numimsbs < ccp->roishift - band->numbps) {
+                        fprintf(stderr, "warning: corrupt code stream\n");
+                    }
+                }
+            }
+            bpno = band->roishift + band->numbps - 1 - (cblk->numimsbs +
+              (seg->passno + i - cblk->firstpassno + 2) / 3);
+            if (bpno < 0) {
+                goto exit;
+            }
+#if 1
+            passtype = (seg->passno + i + 2) % 3;
+#else
+            passtype = JPC_PASSTYPE(seg->passno + i + 2);
+#endif
+            assert(bpno >= 0 && bpno < 31);
+            switch (passtype) {
+            case JPC_SIGPASS:
+                ret = (seg->type == JPC_SEG_MQ) ? dec_sigpass(dec,
+                  cblk->mqdec, bpno, band->orient,
+                  (tile->cp->ccps[compno].cblkctx & JPC_COX_VSC) != 0,
+                  cblk->flags, cblk->data) :
+                  dec_rawsigpass(dec, cblk->nulldec, bpno,
+                  (tile->cp->ccps[compno].cblkctx & JPC_COX_VSC) != 0,
+                  cblk->flags, cblk->data);
+                break;
+            case JPC_REFPASS:
+                ret = (seg->type == JPC_SEG_MQ) ?
+                  dec_refpass(dec, cblk->mqdec, bpno,
+                  (tile->cp->ccps[compno].cblkctx & JPC_COX_VSC) != 0,
+                  cblk->flags, cblk->data) :
+                  dec_rawrefpass(dec, cblk->nulldec, bpno,
+                  (tile->cp->ccps[compno].cblkctx & JPC_COX_VSC) != 0,
+                  cblk->flags, cblk->data);
+                break;
+            case JPC_CLNPASS:
+                assert(seg->type == JPC_SEG_MQ);
+                ret = dec_clnpass(dec, cblk->mqdec, bpno,
+                  band->orient, (tile->cp->ccps[compno].cblkctx &
+                  JPC_COX_VSC) != 0, (tile->cp->ccps[compno].cblkctx &
+                  JPC_COX_SEGSYM) != 0, cblk->flags,
+                  cblk->data);
+                break;
+            default:
+                ret = -1;
+                break;
+            }
+            /* Do we need to reset after each coding pass? */
+            if (tile->cp->ccps[compno].cblkctx & JPC_COX_RESET) {
+                jpc_mqdec_setctxs(cblk->mqdec, JPC_NUMCTXS, jpc_mqctxs);
+            }
+
+            if (ret) {
+                pm_asprintf(errorP,
+                            "coding pass failed passtype=%d segtype=%d",
+                            passtype, seg->type);
+                return;
+            }
+
+        }
+
+        if (seg->type == JPC_SEG_MQ) {
+            /* Note: dont destroy mq decoder because context info will be
+               lost
+            */
+        } else {
+            assert(seg->type == JPC_SEG_RAW);
+            if (tile->cp->ccps[compno].cblkctx & JPC_COX_PTERM) {
+                fillmask = 0x7f;
+                filldata = 0x2a;
+            } else {
+                fillmask = 0;
+                filldata = 0;
+            }
+            if ((ret = jpc_bitstream_inalign(cblk->nulldec, fillmask,
+              filldata)) < 0) {
+                pm_asprintf(errorP, "jpc_bitstream_inalign failed");
+                return;
+            } else if (ret > 0) {
+                pm_message("warning: bad termination pattern detected");
+            }
+            jpc_bitstream_close(cblk->nulldec);
+            cblk->nulldec = 0;
+        }
+
+        cblk->curseg = seg->next;
+        jpc_seglist_remove(&cblk->segs, seg);
+        jpc_seg_destroy(seg);
+        seg = cblk->curseg;
+    }
+
+    assert(dopartial ? (!cblk->curseg) : 1);
+
+exit:
+    *errorP = NULL;
 }
+
+
+
+void
+jpc_dec_decodecblks(jpc_dec_t *      const decP,
+                    jpc_dec_tile_t * const tileP,
+                    const char **    const errorP) {
+/*----------------------------------------------------------------------------
+  Decode all of the code blocks for a particular tile
+-----------------------------------------------------------------------------*/
+    unsigned int compcnt;
+    jpc_dec_tcomp_t * tcompP;
+
+    for (compcnt = 0, tcompP = tileP->tcomps;
+         compcnt < decP->numcomps;
+         ++compcnt, ++tcompP) {
+
+        unsigned int rlvlcnt;
+        jpc_dec_rlvl_t * rlvlP;
+
+        for (rlvlcnt = 0, rlvlP = tcompP->rlvls;
+             rlvlcnt < tcompP->numrlvls;
+             ++rlvlcnt, ++rlvlP) {
+
+            if (rlvlP->bands) {
+                unsigned int bandcnt;
+                jpc_dec_band_t * bandP;
+
+                for (bandcnt = 0, bandP = rlvlP->bands;
+                     bandcnt < rlvlP->numbands;
+                     ++bandcnt, ++bandP) {
+
+                    if (bandP->data) {
+                        unsigned int prccnt;
+                        jpc_dec_prc_t * prcP;
+
+                        for (prccnt = 0, prcP = bandP->prcs;
+                             prccnt < rlvlP->numprcs;
+                             ++prccnt, ++prcP) {
+
+                            if (prcP->cblks) {
+                                unsigned int cblkcnt;
+                                jpc_dec_cblk_t * cblkP;
+
+                                for (cblkcnt = 0, cblkP = prcP->cblks;
+                                     cblkcnt < prcP->numcblks;
+                                     ++cblkcnt, ++cblkP) {
+
+                                    const char * error;
+
+                                    jpc_dec_decodecblk(decP, tileP, tcompP,
+                                                       bandP, cblkP, 1,
+                                                       JPC_MAXLYRS, &error);
+                                    if (error) {
+                                        pm_asprintf(errorP,
+                                                    "jpc_dec_decodecblk "
+                                                    "failed on component %u, "
+                                                    "resolution level %u, "
+                                                    "band %u, prc %u, "
+                                                    "code block %u.  %s",
+                                                    compcnt, rlvlcnt, bandcnt,
+                                                    prccnt, cblkcnt, error);
+                                        pm_strfree(error);
+                                        return;
+                                    }
+                                }
+                            }
+                        }
+                    }
+                }
+            }
+        }
+    }
+    *errorP = NULL;
+}
+
diff --git a/converter/other/jpeg2000/libjasper/jpc/jpc_t1dec.h b/converter/other/jpeg2000/libjasper/jpc/jpc_t1dec.h
index e28a1f57..f8b3b342 100644
--- a/converter/other/jpeg2000/libjasper/jpc/jpc_t1dec.h
+++ b/converter/other/jpeg2000/libjasper/jpc/jpc_t1dec.h
@@ -119,19 +119,13 @@
 #ifndef JPC_T1DEC_H
 #define JPC_T1DEC_H
 
-/******************************************************************************\
-* Includes.
-\******************************************************************************/
-
 #include "jpc_dec.h"
 #include "jpc_mqdec.h"
 #include "jpc_t1cod.h"
 
-/******************************************************************************\
-* Functions.
-\******************************************************************************/
-
-/* Decode all of the code blocks for a particular tile. */
-int jpc_dec_decodecblks(jpc_dec_t *dec, jpc_dec_tile_t *tile);
+void
+jpc_dec_decodecblks(jpc_dec_t *      const decP,
+                    jpc_dec_tile_t * const tileP,
+                    const char **    const errorP);
 
 #endif
diff --git a/converter/other/jpeg2000/libjasper_compat.c b/converter/other/jpeg2000/libjasper_compat.c
new file mode 100644
index 00000000..101820a3
--- /dev/null
+++ b/converter/other/jpeg2000/libjasper_compat.c
@@ -0,0 +1,26 @@
+#include "netpbm/nstring.h"
+
+#include "jasper/jasper.h"
+#include "jasper/jas_image.h"
+
+#ifndef JAS_HAVE_PMJAS_IMAGE_DECODE
+
+void
+pmjas_image_decode(jas_stream_t * const in,
+                   int            const fmtArg,
+                   const char *   const optstr,
+                   jas_image_t ** const imagePP,
+                   const char **  const errorP) {
+
+    jas_image_t * const jasperP = jas_image_decode(in, fmtArg, optstr);
+
+    if (jasperP) {
+        *imagePP = jasperP;
+        *errorP  = errorP;
+    } else {
+        pm_asprintf(errorP, "Failed.  Details may have been written to "
+                    "Standard Error");
+    }
+}
+
+#endif
diff --git a/converter/other/jpeg2000/libjasper_compat.h b/converter/other/jpeg2000/libjasper_compat.h
index 401144a3..45dd904b 100644
--- a/converter/other/jpeg2000/libjasper_compat.h
+++ b/converter/other/jpeg2000/libjasper_compat.h
@@ -1,12 +1,18 @@
 /* Here's some stuff to create backward compatibility with older Jasper
    libraries.  Unfortunately, new versions of the Jasper library are not
    backward compatible with old applications.
+
+   This also makes the programs compatible with both distributed Jasper
+   libraries and the Netpbm fork of Jasper distributed with Netpbm.
 */
 /* The color space thing got more complex between Version 1.600 and
    1.701.  For example, it now allows for multiple kinds of RGB, whereas
    in 1.600 RGB meant SRGB.  As part of that change, names changed
    from "colorspace" to "clrspc".
 */
+#include "jasper/jasper.h"
+#include "jasper/jas_image.h"
+
 #if defined(jas_image_setcolorspace)
 /* Old style color space */
 #define jas_image_setclrspc jas_image_setcolorspace
@@ -22,3 +28,32 @@
 #define JAS_CLRSPC_FAM_UNKNOWN JAS_IMAGE_CS_UNKNOWN
 
 #endif
+
+
+#ifndef JAS_HAVE_PMJAS_IMAGE_DECODE
+
+/* The Netpbm version of jas_image_decode (pmjas_image_decode) returns a
+   description of the problem when it fails and does not molest Standard
+   Error.  Real libjasper just indicates that it failed, after writing some
+   explanation (but not as much as the Netpbm version returns) to Standard
+   Error.
+*/
+void
+pmjas_image_decode(jas_stream_t * const in,
+                   int            const fmtArg,
+                   const char *   const optstr,
+                   jas_image_t ** const imagePP,
+                   const char **  const errorP) {
+
+    jas_image_t * const jasperP = jas_image_decode(in, fmtArg, optstr);
+
+    if (jasperP) {
+        *imagePP = jasperP;
+        *errorP  = errorP;
+    } else {
+        pm_asprintf(errorP, "Failed.  Details may have been written to "
+                    "Standard Error");
+    }
+}
+
+#endif
diff --git a/converter/other/pamtowinicon.c b/converter/other/pamtowinicon.c
index e8a9cc23..7df8f60d 100644
--- a/converter/other/pamtowinicon.c
+++ b/converter/other/pamtowinicon.c
@@ -283,10 +283,10 @@ writeBmpImageHeader(unsigned int const width,
 /*----------------------------------------------------------------------------
 
   Write BMP image header
-    
+
   Note: bm_height is sum of rows in XOR mask and AND mask, while
   image_size is the size of the AND mask only.
-    
+
   image_size does not include the sizes of the (optional) palette
   and the (mandatory) AND mask.
 -----------------------------------------------------------------------------*/
@@ -317,8 +317,8 @@ write32BitBmp(const struct pam *   const pamP,
   Write a 32-bit BMP encoded image to file *ofP.
 -----------------------------------------------------------------------------*/
     int row;
-    
-    writeBmpImageHeader(pamP->width, pamP->height, 32, 
+
+    writeBmpImageHeader(pamP->width, pamP->height, 32,
                         pamP->width * 4 * pamP->height, ofP);
 
     /*  write "XOR mask" */
@@ -334,7 +334,7 @@ write32BitBmp(const struct pam *   const pamP,
                 + ((uint32_t) pixel[PAM_GRN_PLANE] <<  8)
                 + ((uint32_t) pixel[PAM_BLU_PLANE] <<  0)
                 ;
-            
+
             if (haveAlpha)
                 val += (uint32_t) tuples[row][col][alphaPlane] << 24;
 
@@ -360,7 +360,7 @@ writeBmpPalette(const struct Palette * const paletteP,
                             +(paletteP->color[i][PAM_RED_PLANE] << 16)
                             +(paletteP->color[i][PAM_GRN_PLANE] <<  8)
                             +(paletteP->color[i][PAM_BLU_PLANE] <<  0));
-    
+
     for (; i < maxColors; ++i)
         pm_writelittlelongu(ofP, 0);
 }
@@ -382,7 +382,7 @@ writeXorMask(const struct pam *     const pamP,
     unsigned int const maxCol = ((pamP->width * bpp + 31) & ~31) / bpp;
 
     int row;
-                 
+
     for (row = pamP->height - 1; row >= 0; --row) {
         uint8_t  val;
         uint16_t mask;
@@ -500,7 +500,7 @@ writeAndMask(const struct pam * const pamP,
             mask <<= 1;
             val  <<= 1;
 
-            if (!andMakesOpaque(pamP, tuples, row, col, 
+            if (!andMakesOpaque(pamP, tuples, row, col,
                                 haveAlpha, alphaPlane, haveAnd, andPlane))
                 val |= 0x1;
 
@@ -537,7 +537,7 @@ makeAlphaFile(const struct pam * const imagePamP,
     struct pam alphaPam;
     tuple ** alphaTuples;
     unsigned int row;
-    
+
     pm_make_tmpfile(&alphaFileP, alphaFileNameP);
 
     alphaPam.size   = sizeof(alphaPam);
@@ -638,7 +638,7 @@ writePng(const struct pam * const pamP,
 
     acceptParm.ofP = ofP;
     acceptParm.writeCtP = &pngSize;
-    
+
     if (haveAlpha || haveAnd) {
         const char * alphaFileName;
         const char * alphaOpt;
@@ -650,15 +650,15 @@ writePng(const struct pam * const pamP,
 
         strcpy (pam.tuple_type,
                 pam.depth == 3 ? PAM_PPM_TUPLETYPE: PAM_PGM_TUPLETYPE);
-        
+
         pm_asprintf(&alphaOpt, "-alpha=%s", alphaFileName);
 
         pm_system_lp("pnmtopng", pm_feed_from_pamtuples, &pamTuples,
                      acceptToFile, &acceptParm,
                      "pnmtopng", alphaOpt, NULL);
-    
+
         pm_strfree(alphaOpt);
-    
+
         unlink(alphaFileName);
     } else {
         pm_system_lp("pnmtopng", pm_feed_from_pamtuples, &pamTuples,
@@ -906,19 +906,19 @@ writeIconAndCreateDirEntry(const struct pam *     const pamP,
             if (paletteP->colorCt <= 2) {
                 dirEntryP->color_count    = paletteP->colorCt;
                 dirEntryP->bits_per_pixel = 1;
-                    
+
                 writePaletteBmp(1, pamP, tuples, getPixel, paletteP,
                                 ofP, &bmpSize);
             } else if (paletteP->colorCt <= 16) {
                 dirEntryP->color_count    = paletteP->colorCt;
                 dirEntryP->bits_per_pixel = 4;
-                    
+
                 writePaletteBmp(4, pamP, tuples, getPixel,paletteP,
                                 ofP, &bmpSize);
             } else {
                 dirEntryP->color_count    = 0;
                 dirEntryP->bits_per_pixel = 8;
-                    
+
                 writePaletteBmp(8, pamP, tuples, getPixel, paletteP,
                                 ofP, &bmpSize);
             }
@@ -950,7 +950,7 @@ convertOneImage(unsigned int     const imageNum,
     GetPixelFn *        getPixel;
     struct Palette      palette;
     bool                doingPng;
-        
+
     /*  Output:
      *
      *  threshold^2 pixels or more:
@@ -1016,7 +1016,7 @@ convert(FILE *           const ifP,
 -----------------------------------------------------------------------------*/
     unsigned int imageNum;
     int eof;
-    
+
     for (imageNum = 0, eof = false; !eof; ++imageNum) {
         convertOneImage(imageNum, ifP, pngThreshold, mustBlackenXor,
                         ofP, dirP);
@@ -1030,14 +1030,14 @@ convert(FILE *           const ifP,
 static void
 writeIconDirEntry(const struct IconDirEntry * const dirEntryP,
                   FILE *                      const ofP) {
-        
+
     pm_writecharu        (ofP, dirEntryP->width);
     pm_writecharu        (ofP, dirEntryP->height);
     pm_writecharu        (ofP, dirEntryP->color_count);
     pm_writecharu        (ofP, dirEntryP->zero);
     pm_writelittleshortu (ofP, dirEntryP->color_planes);
     pm_writelittleshortu (ofP, dirEntryP->bits_per_pixel);
-    pm_writelittlelongu  (ofP, dirEntryP->size); 
+    pm_writelittlelongu  (ofP, dirEntryP->size);
     pm_writelittlelongu  (ofP, dirEntryP->offset);
 }
 
@@ -1065,7 +1065,7 @@ writeIconDirectory(const struct IconDir * const dirP,
          ++imageNum) {
 
         struct IconDirEntry * const dirEntryP = &dirP->entries[imageNum];
-        
+
         pm_message("image %2u: %3u x %3u x %2u",
                    imageNum,
                    dirEntryP->width,
@@ -1087,7 +1087,7 @@ copyFile(FILE * const ifP,
          FILE * const ofP) {
 
     bool eof;
-    
+
     for (eof = false; !eof; ) {
         unsigned char buffer[1024];
         size_t bytesRead;
diff --git a/converter/other/pgmtopbm.c b/converter/other/pgmtopbm.c
index 67cac468..64dc814b 100644
--- a/converter/other/pgmtopbm.c
+++ b/converter/other/pgmtopbm.c
@@ -21,15 +21,18 @@
 enum halftone {QT_FS, QT_THRESH, QT_DITHER8, QT_CLUSTER, QT_HILBERT};
 
 
-struct cmdlineInfo {
+struct CmdlineInfo {
     /* All the information the user supplied in the command line,
        in a form easy for the program to use.
     */
     const char *  inputFilespec;
     enum halftone halftone;
     unsigned int  clumpSize;
-    unsigned int  clusterRadius;  
+    unsigned int  clusterRadius;
         /* Defined only for halftone == QT_CLUSTER */
+    unsigned int  randomSeed;
+    unsigned int  randomSeedSpec;
+        /* Defined only for halftone == QT_FS */
     float         threshval;
 };
 
@@ -37,8 +40,8 @@ struct cmdlineInfo {
 
 
 static void
-parseCommandLine(int argc, char ** argv,
-                 struct cmdlineInfo *cmdlineP) {
+parseCommandLine(int argc, const char ** argv,
+                 struct CmdlineInfo *cmdlineP) {
 /*----------------------------------------------------------------------------
    Note that the file spec array we return is stored in the storage that
    was passed to us as the argv array.
@@ -68,22 +71,24 @@ parseCommandLine(int argc, char ** argv,
     OPTENT3(0, "c4",        OPT_FLAG,  NULL, &cluster4Opt,  0);
     OPTENT3(0, "cluster8",  OPT_FLAG,  NULL, &cluster8Opt,  0);
     OPTENT3(0, "c8",        OPT_FLAG,  NULL, &cluster8Opt,  0);
-    OPTENT3(0, "value",     OPT_FLOAT, &cmdlineP->threshval, 
+    OPTENT3(0, "value",     OPT_FLOAT, &cmdlineP->threshval,
             &valueSpec, 0);
-    OPTENT3(0, "clump",     OPT_UINT,  &cmdlineP->clumpSize, 
+    OPTENT3(0, "clump",     OPT_UINT,  &cmdlineP->clumpSize,
             &clumpSpec, 0);
+    OPTENT3(0, "randomseed", OPT_UINT,  &cmdlineP->randomSeed,
+            &cmdlineP->randomSeedSpec, 0);
 
     opt.opt_table = option_def;
     opt.short_allowed = FALSE;  /* We have no short (old-fashioned) options */
     opt.allowNegNum = FALSE;  /* We may have parms that are negative numbers */
 
-    pm_optParseOptions3(&argc, argv, opt, sizeof(opt), 0);
+    pm_optParseOptions3(&argc, (char **)argv, opt, sizeof(opt), 0);
         /* Uses and sets argc, argv, and some of *cmdlineP and others. */
 
-    if (floydOpt + thresholdOpt + hilbertOpt + dither8Opt + 
+    if (floydOpt + thresholdOpt + hilbertOpt + dither8Opt +
         cluster3Opt + cluster4Opt + cluster8Opt == 0)
         cmdlineP->halftone = QT_FS;
-    else if (floydOpt + thresholdOpt + dither8Opt + 
+    else if (floydOpt + thresholdOpt + dither8Opt +
         cluster3Opt + cluster4Opt + cluster8Opt > 1)
         pm_error("No cannot specify more than one halftoning type");
     else {
@@ -104,7 +109,7 @@ parseCommandLine(int argc, char ** argv,
         } else if (cluster8Opt) {
             cmdlineP->halftone = QT_CLUSTER;
             cmdlineP->clusterRadius = 8;
-        } else 
+        } else
             pm_error("INTERNAL ERROR.  No halftone option");
     }
 
@@ -118,7 +123,7 @@ parseCommandLine(int argc, char ** argv,
             pm_error("-value cannot be greater than one.  You specified %f",
                      cmdlineP->threshval);
     }
-            
+
     if (!clumpSpec)
         cmdlineP->clumpSize = 5;
     else {
@@ -127,6 +132,10 @@ parseCommandLine(int argc, char ** argv,
                      cmdlineP->clumpSize);
     }
 
+    if (cmdlineP->halftone != QT_FS && cmdlineP->randomSeedSpec)
+        pm_message ("Ignoring -randomseed value "
+                    "(meaningful only with Floyd-Steinberg)");
+
     if (argc-1 > 1)
         pm_error("Too many arguments (%d).  There is at most one "
                  "non-option argument:  the file name",
@@ -150,11 +159,11 @@ static int hil_x,hil_y;
 static int hil_stage[MAXORD];
 static int hil_width,hil_height;
 
-static void 
-init_hilbert(int const w, 
+static void
+init_hilbert(int const w,
              int const h) {
 /*----------------------------------------------------------------------------
-  Initialize the Hilbert curve tracer 
+  Initialize the Hilbert curve tracer
 -----------------------------------------------------------------------------*/
     int big,ber;
     hil_width = w;
@@ -169,7 +178,7 @@ init_hilbert(int const w,
 
 
 
-static int 
+static int
 hilbert(int * const px, int * const py) {
 /*----------------------------------------------------------------------------
   Return non-zero if got another point
@@ -215,7 +224,7 @@ hilbert(int * const px, int * const py) {
             temp = hil_dy;
             hil_dy = -hil_turn * hil_dx;
             hil_dx = hil_turn * temp;
-            if (hil_ord > 0) { 
+            if (hil_ord > 0) {
                 /* recurse */
 
                 hil_stage[hil_ord] = 3;
@@ -338,7 +347,7 @@ static void doHilbert(FILE *       const ifP,
 struct converter {
     void (*convertRow)(struct converter * const converterP,
                        unsigned int       const row,
-                       gray                     grayrow[], 
+                       gray                     grayrow[],
                        bit                      bitrow[]);
     void (*destroy)(struct converter * const converterP);
     unsigned int cols;
@@ -379,7 +388,7 @@ fsConvertRow(struct converter * const converterP,
 
     unsigned int limitcol;
     unsigned int col;
-    
+
     for (col = 0; col < converterP->cols + 2; ++col)
         nexterr[col] = 0;
     if (stateP->fs_forward) {
@@ -395,20 +404,20 @@ fsConvertRow(struct converter * const converterP,
     }
     do {
         long sum;
-        sum = ((long) *gP * fs_scale) / converterP->maxval + 
+        sum = ((long) *gP * fs_scale) / converterP->maxval +
             thiserr[col + 1];
         if (sum >= stateP->threshval) {
             *bP = PBM_WHITE;
             sum = sum - stateP->threshval - half_fs_scale;
         } else
             *bP = PBM_BLACK;
-        
+
         if (stateP->fs_forward) {
             thiserr[col + 2] += (sum * 7) / 16;
             nexterr[col    ] += (sum * 3) / 16;
             nexterr[col + 1] += (sum * 5) / 16;
             nexterr[col + 2] += (sum    ) / 16;
-            
+
             ++col;
             ++gP;
             ++bP;
@@ -417,13 +426,13 @@ fsConvertRow(struct converter * const converterP,
             nexterr[col + 2] += (sum * 3) / 16;
             nexterr[col + 1] += (sum * 5) / 16;
             nexterr[col    ] += (sum    ) / 16;
-            
+
             --col;
             --gP;
             --bP;
         }
     } while (col != limitcol);
-    
+
     stateP->thiserr = nexterr;
     stateP->nexterr = thiserr;
     stateP->fs_forward = ! stateP->fs_forward;
@@ -439,9 +448,11 @@ fsDestroy(struct converter * const converterP) {
 
 
 static struct converter
-createFsConverter(unsigned int const cols, 
+createFsConverter(unsigned int const cols,
                   gray         const maxval,
-                  float        const threshFraction) {
+                  float        const threshFraction,
+                  unsigned int const randomSeedSpec,
+                  unsigned int const randomSeed) {
 
     struct fsState * stateP;
     struct converter converter;
@@ -451,13 +462,13 @@ createFsConverter(unsigned int const cols,
     /* Initialize Floyd-Steinberg error vectors. */
     MALLOCARRAY_NOFAIL(stateP->thiserr, cols + 2);
     MALLOCARRAY_NOFAIL(stateP->nexterr, cols + 2);
-    srand(pm_randseed());
+    srand(randomSeedSpec ? randomSeed : pm_randseed());
 
     {
         /* (random errors in [-fs_scale/8 .. fs_scale/8]) */
         unsigned int col;
         for (col = 0; col < cols + 2; ++col)
-            stateP->thiserr[col] = 
+            stateP->thiserr[col] =
                 (long)(rand() % fs_scale - half_fs_scale) / 4;
     }
 
@@ -488,7 +499,7 @@ threshConvertRow(struct converter * const converterP,
                  unsigned int       const row,
                  gray                     grayrow[],
                  bit                      bitrow[]) {
-    
+
     struct threshState * const stateP = converterP->stateP;
 
     unsigned int col;
@@ -509,7 +520,7 @@ threshDestroy(struct converter * const converterP) {
 
 
 static struct converter
-createThreshConverter(unsigned int const cols, 
+createThreshConverter(unsigned int const cols,
                       gray         const maxval,
                       float        const threshFraction) {
 
@@ -571,7 +582,7 @@ dither8Destroy(struct converter * const converterP) {
 
 
 static struct converter
-createDither8Converter(unsigned int const cols, 
+createDither8Converter(unsigned int const cols,
                        gray         const maxval) {
 
     struct converter converter;
@@ -642,7 +653,7 @@ clusterDestroy(struct converter * const converterP) {
         free(stateP->clusterMatrix[row]);
 
     free(stateP->clusterMatrix);
-    
+
     free(stateP);
 }
 
@@ -650,9 +661,9 @@ clusterDestroy(struct converter * const converterP) {
 
 static struct converter
 createClusterConverter(unsigned int const radius,
-                       unsigned int const cols, 
+                       unsigned int const cols,
                        gray         const maxval) {
-    
+
     int const clusterNormalizer = radius * radius * 2;
     unsigned int const diameter = 2 * radius;
 
@@ -674,7 +685,7 @@ createClusterConverter(unsigned int const radius,
         unsigned int col;
 
         MALLOCARRAY_NOFAIL(stateP->clusterMatrix[row], diameter);
-        
+
         for (col = 0; col < diameter; ++col) {
             int val;
             switch (radius) {
@@ -686,7 +697,7 @@ createClusterConverter(unsigned int const radius,
             }
             stateP->clusterMatrix[row][col] = val * maxval / clusterNormalizer;
         }
-    }            
+    }
 
     converter.stateP = stateP;
 
@@ -696,14 +707,14 @@ createClusterConverter(unsigned int const radius,
 
 
 int
-main(int argc, char *argv[]) {
+main(int argc, const char *argv[]) {
 
-    struct cmdlineInfo cmdline;
-    FILE* ifP;
-    gray* grayrow;
-    bit* bitrow;
+    struct CmdlineInfo cmdline;
+    FILE * ifP;
+    gray * grayrow;
+    bit *  bitrow;
 
-    pgm_init(&argc, argv);
+    pm_proginit(&argc, argv);
 
     parseCommandLine(argc, argv, &cmdline);
 
@@ -719,24 +730,26 @@ main(int argc, char *argv[]) {
         int row;
 
         pgm_readpgminit(ifP, &cols, &rows, &maxval, &format);
-        
+
         pbm_writepbminit(stdout, cols, rows, 0);
 
         switch (cmdline.halftone) {
         case QT_FS:
-            converter = createFsConverter(cols, maxval, cmdline.threshval);
+            converter = createFsConverter(cols, maxval, cmdline.threshval,
+                                          cmdline.randomSeedSpec,
+                                          cmdline.randomSeed);
             break;
         case QT_THRESH:
             converter = createThreshConverter(cols, maxval, cmdline.threshval);
             break;
-        case QT_DITHER8: 
-            converter = createDither8Converter(cols, maxval); 
+        case QT_DITHER8:
+            converter = createDither8Converter(cols, maxval);
             break;
-        case QT_CLUSTER: 
-            converter = 
+        case QT_CLUSTER:
+            converter =
                 createClusterConverter(cmdline.clusterRadius, cols, maxval);
             break;
-        case QT_HILBERT: 
+        case QT_HILBERT:
                 pm_error("INTERNAL ERROR: halftone is QT_HILBERT where it "
                          "shouldn't be.");
                 break;
@@ -749,7 +762,7 @@ main(int argc, char *argv[]) {
             pgm_readpgmrow(ifP, grayrow, cols, maxval, format);
 
             converter.convertRow(&converter, row, grayrow, bitrow);
-            
+
             pbm_writepbmrow(stdout, bitrow, cols, 0);
         }
         pbm_freerow(bitrow);
@@ -763,3 +776,6 @@ main(int argc, char *argv[]) {
 
     return 0;
 }
+
+
+
diff --git a/converter/other/winicon.h b/converter/other/winicon.h
index 9ede01f5..e5c4aa89 100644
--- a/converter/other/winicon.h
+++ b/converter/other/winicon.h
@@ -65,8 +65,7 @@ typedef enum {
 
 } BiCompression;
 
-/*  PNG image structures  */
-#define PNG_HEADER { 0x89, 'P', 'N', 'G', '\r', '\n', 0x1A /* ^Z */, '\n' }
+#define PNG_SIGNATURE { 0x89, 'P', 'N', 'G', '\r', '\n', 0x1A /* ^Z */, '\n' }
 
 struct PngIhdr {
     uint32_t length;              /* 13 */
diff --git a/converter/other/winicontopam.c b/converter/other/winicontopam.c
index 70729cce..f6f89e11 100644
--- a/converter/other/winicontopam.c
+++ b/converter/other/winicontopam.c
@@ -106,7 +106,7 @@ parseCommandLine(int argc, const char **argv,
 
 
 
-static unsigned char const pngHeader[] = PNG_HEADER;
+static unsigned char const pngSignature[] = PNG_SIGNATURE;
 
 
 
@@ -613,7 +613,10 @@ readXorBitfields(struct BitmapInfoHeader * const hdrP,
                  uint16_t                  const index,
                  bool *                    const haveAlphaP,
                  uint32_t *                const bytesConsumedP) {
-
+/*----------------------------------------------------------------------------
+   Return as *haveAlphaP whether the Xor mask indicates the pixels are
+   anything but fully opaque.
+-----------------------------------------------------------------------------*/
     uint32_t   bitfields[4];
     uint8_t    shift    [4];
     sample     maxval   [4];
@@ -780,12 +783,21 @@ readXorBitfields(struct BitmapInfoHeader * const hdrP,
     bytesConsumed += truncatedXorSize;
 
     /*  A fully transparent alpha channel (all zero) in XOR mask is
-        defined to be void by Microsoft, and a fully opaque alpha
-        channel (all maxval) is trivial and will be dropped.
+        defined to be void by Microsoft.
     */
+    if (verbose) {
+        if (allTransparent)
+            pm_message("image %2u: All pixels are nominally coded in the "
+                       "transparency map as fully transparent, "
+                       "which is defined by the format to mean they "
+                       "are all opaque", index);
+        if (allOpaque)
+            pm_message("image %2u: All pixels are fully opaque "
+                       "in the transparency map", index);
+    }
     *haveAlphaP = !allTransparent && !allOpaque;
 
-    if (!allTransparent && verbose) {
+    if (!allTransparent && ! allOpaque && verbose) {
         unsigned int i;
         unsigned int c;
 
@@ -809,7 +821,16 @@ readAnd(struct BitmapInfoHeader * const hdrP,
         uint16_t                  const index,
         unsigned int              const plane,
         sample                    const maxval) {
+/*----------------------------------------------------------------------------
+  Fill in plane 'plane' of the tuple array 'tuples' according to the and
+  mask of a Windows icon.  Where the and mask for a pixel is 1, set the
+  plane to 'maxval'; where it is zero, set it to zero.
+
+  'bitmap' is the and mask, in a format describe dby *hdrP.
 
+  'index' is the position of the icon in question in the Windows icon file --
+  the first image in the file is 0, second is 1, etc.
+-----------------------------------------------------------------------------*/
     int16_t  row;
     uint32_t bytesConsumed;
     uint32_t bytesPerRow;
@@ -938,7 +959,13 @@ readXorMask(struct BitmapInfoHeader * const hdrP,
             uint32_t *                const bytesConsumedP) {
 /*----------------------------------------------------------------------------
    Read the so-called XOR mask (for non-monochrome images, this is the
-   color pixmap)
+   color pixmap, which may include transparency).
+
+   Return the pixels as 'tuples', an array whose width and height are
+   given by *hdrP and depth is 4.
+
+   Return as *haveAlphaP whether the Xor mask indicates the pixels are
+   anything but fully opaque.
 -----------------------------------------------------------------------------*/
     /*  preset the PAM with fully opaque black (just in case the image
         is truncated and not all pixels are filled in below).
@@ -1054,9 +1081,9 @@ convertBmp(const unsigned char * const image,
     offset += xorByteCt;
 
     {
-        /* If there is no alpha channel in XOR mask, store the AND mask to
-           the transparency plane.  Else, here are two transparency
-           maps. If requested, store the AND mask to a fifth PAM plane
+        /* If there is no alpha channel in the XOR mask, use the AND mask as
+           the transparency plane.  Else, there are two transparency
+           maps. If requested, return the AND mask as a fifth PAM plane.
         */
         bool haveAnd;
         unsigned int andPlane;
@@ -1095,15 +1122,15 @@ reportPngInfo(const unsigned char * const image,
 
     struct PngIhdr ihdr;
 
-    ihdr.length      = u32_be (image, sizeof(pngHeader)  +0);
-    ihdr.signature   = u32_xx (image, sizeof(pngHeader)  +4);
-    ihdr.width       = u32_be (image, sizeof(pngHeader)  +8);
-    ihdr.height      = u32_be (image, sizeof(pngHeader) +12);
-    ihdr.bit_depth   = u8_be  (image, sizeof(pngHeader) +16);
-    ihdr.color_type  = u8_be  (image, sizeof(pngHeader) +17);
-    ihdr.compression = u8_be  (image, sizeof(pngHeader) +18);
-    ihdr.filter      = u8_be  (image, sizeof(pngHeader) +19);
-    ihdr.interlace   = u8_be  (image, sizeof(pngHeader) +20);
+    ihdr.length      = u32_be (image, sizeof(pngSignature)  +0);
+    ihdr.signature   = u32_xx (image, sizeof(pngSignature)  +4);
+    ihdr.width       = u32_be (image, sizeof(pngSignature)  +8);
+    ihdr.height      = u32_be (image, sizeof(pngSignature) +12);
+    ihdr.bit_depth   = u8_be  (image, sizeof(pngSignature) +16);
+    ihdr.color_type  = u8_be  (image, sizeof(pngSignature) +17);
+    ihdr.compression = u8_be  (image, sizeof(pngSignature) +18);
+    ihdr.filter      = u8_be  (image, sizeof(pngSignature) +19);
+    ihdr.interlace   = u8_be  (image, sizeof(pngSignature) +20);
 
     if ((ihdr.length != 13)
         || ihdr.signature != *(uint32_t*)"IHDR") {
@@ -1246,7 +1273,7 @@ convertImage(struct File *         const icoP,
 
     image = readImage(icoP, dirEntryP);
 
-    if (MEMEQ(image, pngHeader, sizeof (pngHeader)))
+    if (MEMEQ(image, pngSignature, sizeof (pngSignature)))
         convertPng(image, ofP, dirEntryP);
     else
         convertBmp(image, ofP, dirEntryP, needHeaderDump, wantAndMaskPlane);
diff --git a/converter/ppm/ppmtopcx.c b/converter/ppm/ppmtopcx.c
index 76f06290..5b7e1003 100644
--- a/converter/ppm/ppmtopcx.c
+++ b/converter/ppm/ppmtopcx.c
@@ -31,13 +31,13 @@
 #define PCX_MAXVAL      (pixval)255
 
 
-struct cmdlineInfo {
+struct CmdlineInfo {
     /* All the information the user supplied in the command line,
        in a form easy for the program to use.
     */
-    const char *inputFilespec;  /* '-' if stdin */
+    const char * inputFilespec;  /* '-' if stdin */
     unsigned int truecolor;   /* -24bit option */
-    unsigned int use_8_bit; /* -8bit option */
+    unsigned int use8Bit; /* -8bit option */
     unsigned int planes;    /* zero means minimum */
     unsigned int packed;
     unsigned int verbose;
@@ -49,16 +49,16 @@ struct cmdlineInfo {
 
 
 
-struct pcxCmapEntry {
+struct PcxCmapEntry {
     unsigned char r;
     unsigned char g;
     unsigned char b;
 };
 
-static struct pcxCmapEntry
+static struct PcxCmapEntry
 pcxCmapEntryFromPixel(pixel const colorPixel) {
 
-    struct pcxCmapEntry retval;
+    struct PcxCmapEntry retval;
 
     retval.r = PPM_GETR(colorPixel);
     retval.g = PPM_GETG(colorPixel);
@@ -70,8 +70,8 @@ pcxCmapEntryFromPixel(pixel const colorPixel) {
 
 
 static void
-parseCommandLine(int argc, char ** argv,
-                 struct cmdlineInfo * const cmdlineP) {
+parseCommandLine(int argc, const char ** argv,
+                 struct CmdlineInfo * const cmdlineP) {
 /*----------------------------------------------------------------------------
    parse program command line described in Unix standard form by argc
    and argv.  Return the information in the options as *cmdlineP.
@@ -82,7 +82,7 @@ parseCommandLine(int argc, char ** argv,
    Note that the strings we return are stored in the storage that
    was passed to us as the argv array.  We also trash *argv.
 -----------------------------------------------------------------------------*/
-    optEntry *option_def;
+    optEntry * option_def;
         /* Instructions to pm_optParseOptions3 on how to parse our options.
          */
     optStruct3 opt;
@@ -97,7 +97,7 @@ parseCommandLine(int argc, char ** argv,
     OPTENT3(0, "24bit",     OPT_FLAG,   NULL,
             &cmdlineP->truecolor,    0);
     OPTENT3(0, "8bit",      OPT_FLAG,   NULL,
-            &cmdlineP->use_8_bit,    0);
+            &cmdlineP->use8Bit,    0);
     OPTENT3(0, "planes",    OPT_UINT,   &cmdlineP->planes,
             &planesSpec,             0);
     OPTENT3(0, "packed",    OPT_FLAG,   NULL,
@@ -115,7 +115,7 @@ parseCommandLine(int argc, char ** argv,
     opt.short_allowed = FALSE;  /* We have no short (old-fashioned) options */
     opt.allowNegNum = FALSE;  /* We have no parms that are negative numbers */
 
-    pm_optParseOptions3( &argc, argv, opt, sizeof(opt), 0 );
+    pm_optParseOptions3( &argc, (char **)argv, opt, sizeof(opt), 0 );
         /* Uses and sets argc, argv, and some of *cmdline_p and others. */
 
     if (!xposSpec)
@@ -141,7 +141,7 @@ parseCommandLine(int argc, char ** argv,
             pm_error("-planes is meaningless with -packed.");
         if (cmdlineP->truecolor)
             pm_error("-planes is meaningless with -24bit");
-        if (cmdlineP->use_8_bit)
+        if (cmdlineP->use8Bit)
             pm_error("-planes is meaningless with -8bit");
     }
 
@@ -151,7 +151,7 @@ parseCommandLine(int argc, char ** argv,
     if (!paletteSpec)
         cmdlineP->palette = NULL;
 
-    if (cmdlineP->use_8_bit && cmdlineP->truecolor)
+    if (cmdlineP->use8Bit && cmdlineP->truecolor)
         pm_error("You cannot specify both -8bit and -truecolor");
 
     if (argc-1 < 1)
@@ -172,8 +172,8 @@ parseCommandLine(int argc, char ** argv,
  * Write out a two-byte little-endian word to the PCX file
  */
 static void
-Putword(int    const w,
-        FILE * const fp) {
+putword(unsigned int const w,
+        FILE *       const fp) {
 
     int rc;
 
@@ -189,12 +189,13 @@ Putword(int    const w,
  * Write out a byte to the PCX file
  */
 static void
-Putbyte(int    const b,
-        FILE * const fp) {
+putbyte(unsigned int const b,
+        FILE *       const ofP) {
 
     int rc;
 
-    rc = fputc(b & 0xff, fp);
+    rc = fputc(b & 0xff, ofP);
+
     if (rc == EOF)
         pm_error("Error writing byte to output file.");
 }
@@ -203,9 +204,9 @@ Putbyte(int    const b,
 
 static void
 extractPlane(unsigned char * const rawrow,
-             int             const cols,
+             unsigned int    const cols,
              unsigned char * const buf,
-             int             const plane) {
+             unsigned int    const plane) {
 /*----------------------------------------------------------------------------
    From the image row 'rawrow', which is an array of 'cols' palette indices
    (as unsigned 8 bit integers), extract plane number 'plane' and return
@@ -223,9 +224,7 @@ extractPlane(unsigned char * const rawrow,
 
     cp = buf;  /* initial value */
 
-    cbit = 7;
-    byteUnderConstruction = 0x00;
-    for (col = 0; col < cols; ++col) {
+    for (col = 0, cbit = 7, byteUnderConstruction = 0x00; col < cols; ++col) {
         if (rawrow[col] & planeMask)
             byteUnderConstruction |= (1 << cbit);
 
@@ -247,14 +246,17 @@ extractPlane(unsigned char * const rawrow,
 
 
 static void
-PackBits(unsigned char * const rawrow,
-         int             const width,
+packBits(unsigned char * const rawrow,
+         unsigned int    const width,
          unsigned char * const buf,
-         int             const bits) {
+         unsigned int    const bits) {
 
-    int x, i, shift;
+    unsigned int x;
+    int i;
+    int shift;
 
-    shift = i = -1;
+    shift = -1;
+    i = -1;
 
     for (x = 0; x < width; ++x) {
         if (shift < 0) {
@@ -270,71 +272,73 @@ PackBits(unsigned char * const rawrow,
 
 
 static void
-write_header(FILE *              const fp,
-             int                 const cols,
-             int                 const rows,
-             int                 const BitsPerPixel,
-             int                 const Planes,
-             struct pcxCmapEntry const cmap16[],
-             unsigned int        const xPos,
-             unsigned int        const yPos) {
-
-    int i, BytesPerLine;
-
-    Putbyte(PCX_MAGIC, fp);        /* .PCX magic number            */
-    Putbyte(0x05, fp);             /* PC Paintbrush version        */
-    Putbyte(0x01, fp);             /* .PCX run length encoding     */
-    Putbyte(BitsPerPixel, fp);     /* bits per pixel               */
-
-    Putword(xPos, fp);             /* x1   - image left            */
-    Putword(yPos, fp);             /* y1   - image top             */
-    Putword(xPos+cols-1, fp);      /* x2   - image right           */
-    Putword(yPos+rows-1, fp);      /* y2   - image bottom          */
-
-    Putword(cols, fp);             /* horizontal resolution        */
-    Putword(rows, fp);             /* vertical resolution          */
+writeHeader(FILE *              const ofP,
+            unsigned int        const cols,
+            unsigned int        const rows,
+            unsigned int        const bitsPerPixel,
+            unsigned int        const planes,
+            struct PcxCmapEntry const cmap16[],
+            unsigned int        const xPos,
+            unsigned int        const yPos) {
+
+    unsigned int bytesPerLine;
+
+    putbyte(PCX_MAGIC, ofP);        /* .PCX magic number            */
+    putbyte(0x05, ofP);             /* PC Paintbrush version        */
+    putbyte(0x01, ofP);             /* .PCX run length encoding     */
+    putbyte(bitsPerPixel, ofP);     /* bits per pixel               */
+
+    putword(xPos, ofP);             /* x1   - image left            */
+    putword(yPos, ofP);             /* y1   - image top             */
+    putword(xPos+cols-1, ofP);      /* x2   - image right           */
+    putword(yPos+rows-1, ofP);      /* y2   - image bottom          */
+
+    putword(cols, ofP);             /* horizontal resolution        */
+    putword(rows, ofP);             /* vertical resolution          */
 
     /* Write out the Color Map for images with 16 colors or less */
-    if (cmap16)
+    if (cmap16) {
+        unsigned int i;
         for (i = 0; i < 16; ++i) {
-            Putbyte(cmap16[i].r, fp);
-            Putbyte(cmap16[i].g, fp);
-            Putbyte(cmap16[i].b, fp);
+            putbyte(cmap16[i].r, ofP);
+            putbyte(cmap16[i].g, ofP);
+            putbyte(cmap16[i].b, ofP);
         }
-    else {
+    } else {
         unsigned int i;
         for (i = 0; i < 16; ++i) {
-            Putbyte(0, fp);
-            Putbyte(0, fp);
-            Putbyte(0, fp);
+            putbyte(0, ofP);
+            putbyte(0, ofP);
+            putbyte(0, ofP);
         }
     }
-    Putbyte(0, fp);                /* reserved byte                */
-    Putbyte(Planes, fp);           /* number of color planes       */
+    putbyte(0, ofP);                /* reserved byte                */
+    putbyte(planes, ofP);           /* number of color planes       */
 
-    BytesPerLine = ((cols * BitsPerPixel) + 7) / 8;
-    Putword(BytesPerLine, fp);    /* number of bytes per scanline */
+    bytesPerLine = ((cols * bitsPerPixel) + 7) / 8;
+    putword(bytesPerLine, ofP);    /* number of bytes per scanline */
 
-    Putword(1, fp);                /* palette info                 */
+    putword(1, ofP);                /* palette info                 */
 
     {
         unsigned int i;
         for (i = 0; i < 58; ++i)        /* fill to end of header        */
-            Putbyte(0, fp);
+            putbyte(0, ofP);
     }
 }
 
 
 
 static void
-PCXEncode(FILE *                const fp,
+pcxEncode(FILE *                const ofP,
           const unsigned char * const buf,
-          int                   const Size) {
+          unsigned int          const size) {
 
-    const unsigned char * const end = buf + Size;
+    const unsigned char * const end = buf + size;
 
     const unsigned char * currentP;
-    int previous, count;
+    unsigned int          previous;
+    unsigned int          count;
 
     currentP = buf;
     previous = *currentP++;
@@ -347,19 +351,19 @@ PCXEncode(FILE *                const fp,
         else {
             if (count > 1 || (previous & 0xc0) == 0xc0) {
                 count |= 0xc0;
-                Putbyte ( count , fp );
+                putbyte ( count , ofP );
             }
-            Putbyte(previous, fp);
+            putbyte(previous, ofP);
             previous = c;
-            count   = 1;
+            count = 1;
         }
     }
 
     if (count > 1 || (previous & 0xc0) == 0xc0) {
         count |= 0xc0;
-        Putbyte ( count , fp );
+        putbyte(count, ofP);
     }
-    Putbyte(previous, fp);
+    putbyte(previous, ofP);
 }
 
 
@@ -386,61 +390,46 @@ indexOfColor(colorhash_table const cht,
 
 
 static void
-ppmTo16ColorPcx(pixel **            const pixels,
-                int                 const cols,
-                int                 const rows,
-                struct pcxCmapEntry const pcxcmap[],
-                int                 const colors,
-                colorhash_table     const cht,
-                bool                const packbits,
-                unsigned int        const planesRequested,
-                unsigned int        const xPos,
-                unsigned int        const yPos) {
+writeRaster16Color(FILE * const ofP,
+                   pixel **            const pixels,
+                   unsigned int        const cols,
+                   unsigned int        const rows,
+                   unsigned int        const planes,
+                   colorhash_table     const cht,
+                   bool                const packbits,
+                   unsigned int        const bitsPerPixel) {
+
+    unsigned int const bytesPerLine = ((cols * bitsPerPixel) + 7) / 8;
+
+    unsigned char * indexRow;  /* malloc'ed */
+    /* indexRow[x] is the palette index of the pixel at column x of
+       the row currently being processed
+    */
+    unsigned char * planesrow; /* malloc'ed */
+    /* This is the input for a single row to the compressor */
 
-    int Planes, BytesPerLine, BitsPerPixel;
-    unsigned char *indexRow;  /* malloc'ed */
-        /* indexRow[x] is the palette index of the pixel at column x of
-           the row currently being processed
-        */
-    unsigned char *planesrow; /* malloc'ed */
-        /* This is the input for a single row to the compressor */
-    int row;
+    unsigned int row;
 
-    if (packbits) {
-        Planes = 1;
-        if (colors > 4)        BitsPerPixel = 4;
-        else if (colors > 2)   BitsPerPixel = 2;
-        else                   BitsPerPixel = 1;
-    } else {
-        BitsPerPixel = 1;
-        if (planesRequested)
-            Planes = planesRequested;
-        else {
-            if (colors > 8)        Planes = 4;
-            else if (colors > 4)   Planes = 3;
-            else if (colors > 2)   Planes = 2;
-            else                   Planes = 1;
-        }
-    }
-    BytesPerLine = ((cols * BitsPerPixel) + 7) / 8;
     MALLOCARRAY_NOFAIL(indexRow, cols);
-    MALLOCARRAY_NOFAIL(planesrow, BytesPerLine);
+    MALLOCARRAY(planesrow, bytesPerLine);
+
+    if (!planesrow)
+        pm_error("Failed to allocate buffer for a line of %u bytes",
+                 bytesPerLine);
 
-    write_header(stdout, cols, rows, BitsPerPixel, Planes, pcxcmap,
-                 xPos, yPos);
     for (row = 0; row < rows; ++row) {
-        int col;
+        unsigned int col;
         for (col = 0; col < cols; ++col)
             indexRow[col] = indexOfColor(cht, pixels[row][col]);
 
         if (packbits) {
-            PackBits(indexRow, cols, planesrow, BitsPerPixel);
-            PCXEncode(stdout, planesrow, BytesPerLine);
+            packBits(indexRow, cols, planesrow, bitsPerPixel);
+            pcxEncode(ofP, planesrow, bytesPerLine);
         } else {
             unsigned int plane;
-            for (plane = 0; plane < Planes; ++plane) {
+            for (plane = 0; plane < planes; ++plane) {
                 extractPlane(indexRow, cols, planesrow, plane);
-                PCXEncode(stdout, planesrow, BytesPerLine);
+                pcxEncode(stdout, planesrow, bytesPerLine);
             }
         }
     }
@@ -451,83 +440,142 @@ ppmTo16ColorPcx(pixel **            const pixels,
 
 
 static void
+ppmTo16ColorPcx(pixel **            const pixels,
+                unsigned int        const cols,
+                unsigned int        const rows,
+                struct PcxCmapEntry const pcxcmap[],
+                unsigned int        const colorCt,
+                colorhash_table     const cht,
+                bool                const packbits,
+                unsigned int        const planesRequested,
+                unsigned int        const xPos,
+                unsigned int        const yPos) {
+
+    unsigned int planes;
+    unsigned int bitsPerPixel;
+
+    if (packbits) {
+        planes = 1;
+        if (colorCt > 4)        bitsPerPixel = 4;
+        else if (colorCt > 2)   bitsPerPixel = 2;
+        else                    bitsPerPixel = 1;
+    } else {
+        bitsPerPixel = 1;
+        if (planesRequested)
+            planes = planesRequested;
+        else {
+            if (colorCt > 8)        planes = 4;
+            else if (colorCt > 4)   planes = 3;
+            else if (colorCt > 2)   planes = 2;
+            else                   planes = 1;
+        }
+    }
+
+    writeHeader(stdout, cols, rows, bitsPerPixel, planes, pcxcmap,
+                xPos, yPos);
+
+    writeRaster16Color(stdout, pixels, cols, rows, planes, cht, packbits,
+                       bitsPerPixel);
+}
+
+
+
+static void
 ppmTo256ColorPcx(pixel **            const pixels,
-                 int                 const cols,
-                 int                 const rows,
-                 struct pcxCmapEntry const pcxcmap[],
-                 int                 const colors,
+                 unsigned int        const cols,
+                 unsigned int        const rows,
+                 struct PcxCmapEntry const pcxcmap[],
+                 unsigned int        const colorCt,
                  colorhash_table     const cht,
                  unsigned int        const xPos,
                  unsigned int        const yPos) {
 
-    int row;
-    unsigned int i;
-    unsigned char *rawrow;
+    unsigned char * rawrow;
+    unsigned int    row;
+
+    MALLOCARRAY(rawrow, cols);
 
-    rawrow = (unsigned char *)pm_allocrow(cols, sizeof(unsigned char));
+    if (!rawrow)
+        pm_error("Failed to allocate a buffer for %u columns", cols);
 
     /* 8 bits per pixel, 1 plane */
-    write_header(stdout, cols, rows, 8, 1, NULL, xPos, yPos);
+    writeHeader(stdout, cols, rows, 8, 1, NULL, xPos, yPos);
     for (row = 0; row < rows; ++row) {
-        int col;
+        unsigned int col;
         for (col = 0; col < cols; ++col)
             rawrow[col] = indexOfColor(cht, pixels[row][col]);
-        PCXEncode(stdout, rawrow, cols);
+        pcxEncode(stdout, rawrow, cols);
+
     }
-    Putbyte(PCX_256_COLORS, stdout);
-    for (i = 0; i < MAXCOLORS; ++i) {
-        Putbyte(pcxcmap[i].r, stdout);
-        Putbyte(pcxcmap[i].g, stdout);
-        Putbyte(pcxcmap[i].b, stdout);
+    putbyte(PCX_256_COLORS, stdout);
+
+    {
+        unsigned int i;
+
+        for (i = 0; i < MAXCOLORS; ++i) {
+            putbyte(pcxcmap[i].r, stdout);
+            putbyte(pcxcmap[i].g, stdout);
+            putbyte(pcxcmap[i].b, stdout);
+        }
     }
-    pm_freerow((void*)rawrow);
+    free(rawrow);
 }
 
 
 
 static void
 ppmToTruecolorPcx(pixel **     const pixels,
-                  int          const cols,
-                  int          const rows,
+                  unsigned int const cols,
+                  unsigned int const rows,
                   pixval       const maxval,
                   unsigned int const xPos,
                   unsigned int const yPos) {
 
-    unsigned char *redrow, *greenrow, *bluerow;
-    int col, row;
+    unsigned char * redrow;
+    unsigned char * grnrow;
+    unsigned char * blurow;
+    unsigned int    row;
 
-    redrow   = (unsigned char *)pm_allocrow(cols, sizeof(unsigned char));
-    greenrow = (unsigned char *)pm_allocrow(cols, sizeof(unsigned char));
-    bluerow  = (unsigned char *)pm_allocrow(cols, sizeof(unsigned char));
+    MALLOCARRAY(redrow, cols);
+    MALLOCARRAY(grnrow, cols);
+    MALLOCARRAY(blurow, cols);
+
+    if (!redrow || !grnrow || !blurow)
+        pm_error("Unable to allocate buffer for a row of %u pixels", cols);
 
     /* 8 bits per pixel, 3 planes */
-    write_header(stdout, cols, rows, 8, 3, NULL, xPos, yPos);
-    for( row = 0; row < rows; row++ ) {
-        register pixel *pP = pixels[row];
-        for( col = 0; col < cols; col++, pP++ ) {
-            if( maxval != PCX_MAXVAL ) {
-                redrow[col]   = (long)PPM_GETR(*pP) * PCX_MAXVAL / maxval;
-                greenrow[col] = (long)PPM_GETG(*pP) * PCX_MAXVAL / maxval;
-                bluerow[col]  = (long)PPM_GETB(*pP) * PCX_MAXVAL / maxval;
-            }
-            else {
-                redrow[col]   = PPM_GETR(*pP);
-                greenrow[col] = PPM_GETG(*pP);
-                bluerow[col]  = PPM_GETB(*pP);
+    writeHeader(stdout, cols, rows, 8, 3, NULL, xPos, yPos);
+
+    for (row = 0; row < rows; ++row) {
+        pixel * const pixrow = pixels[row];
+
+        unsigned int col;
+
+        for (col = 0; col < cols; ++col) {
+            pixel const pix = pixrow[col];
+
+            if (maxval != PCX_MAXVAL) {
+                redrow[col] = (long)PPM_GETR(pix) * PCX_MAXVAL / maxval;
+                grnrow[col] = (long)PPM_GETG(pix) * PCX_MAXVAL / maxval;
+                blurow[col] = (long)PPM_GETB(pix) * PCX_MAXVAL / maxval;
+            } else {
+                redrow[col] = PPM_GETR(pix);
+                grnrow[col] = PPM_GETG(pix);
+                blurow[col] = PPM_GETB(pix);
             }
         }
-        PCXEncode(stdout, redrow, cols);
-        PCXEncode(stdout, greenrow, cols);
-        PCXEncode(stdout, bluerow, cols);
+        pcxEncode(stdout, redrow, cols);
+        pcxEncode(stdout, grnrow, cols);
+        pcxEncode(stdout, blurow, cols);
     }
-    pm_freerow((void*)bluerow);
-    pm_freerow((void*)greenrow);
-    pm_freerow((void*)redrow);
+    free(blurow);
+    free(grnrow);
+    free(redrow);
 }
 
 
 
-static const struct pcxCmapEntry
+static const struct PcxCmapEntry
 stdPalette[] = {
     {   0,   0,   0 },
     {   0,   0, 170 },
@@ -605,19 +653,18 @@ putPcxColorInHash(colorhash_table const cht,
 
 
 static void
-generateStandardPalette(struct pcxCmapEntry ** const pcxcmapP,
+generateStandardPalette(struct PcxCmapEntry ** const pcxcmapP,
                         pixval                 const maxval,
                         colorhash_table *      const chtP,
-                        int *                  const colorsP) {
+                        unsigned int *         const colorsP) {
 
     unsigned int const stdPaletteSize = 16;
-    unsigned int colorIndex;
-    struct pcxCmapEntry * pcxcmap;
-    colorhash_table cht;
 
-    MALLOCARRAY_NOFAIL(pcxcmap, MAXCOLORS);
+    unsigned int          colorIndex;
+    struct PcxCmapEntry * pcxcmap;
+    colorhash_table       cht;
 
-    *pcxcmapP = pcxcmap;
+    MALLOCARRAY_NOFAIL(pcxcmap, MAXCOLORS);
 
     cht = ppm_alloccolorhash();
 
@@ -645,6 +692,7 @@ generateStandardPalette(struct pcxCmapEntry ** const pcxcmapP,
         pcxcmap[colorIndex].b = 0;
     }
 
+    *pcxcmapP = pcxcmap;
     *chtP = cht;
     *colorsP = stdPaletteSize;
 }
@@ -673,11 +721,10 @@ readPpmPalette(const char *   const paletteFileName,
                  *paletteSizeP, MAXCOLORS);
 
     {
-        int j;
-        int row;
-        j = 0;  /* initial value */
-        for (row = 0; row < rows; ++row) {
-            int col;
+        unsigned int j;
+        unsigned int row;
+        for (row = 0, j = 0; row < rows; ++row) {
+            unsigned int col;
             for (col = 0; col < cols; ++col)
                 (*ppmPaletteP)[j++] = pixels[row][col];
         }
@@ -688,16 +735,16 @@ readPpmPalette(const char *   const paletteFileName,
 
 
 static void
-readPaletteFromFile(struct pcxCmapEntry ** const pcxcmapP,
+readPaletteFromFile(struct PcxCmapEntry ** const pcxcmapP,
                     const char *           const paletteFileName,
                     pixval                 const maxval,
                     colorhash_table *      const chtP,
-                    int *                  const colorsP) {
+                    unsigned int *         const colorsP) {
 
     unsigned int colorIndex;
     pixel ppmPalette[MAXCOLORS];
     unsigned int paletteSize;
-    struct pcxCmapEntry * pcxcmap;
+    struct PcxCmapEntry * pcxcmap;
     colorhash_table cht;
 
     readPpmPalette(paletteFileName, &ppmPalette, &paletteSize);
@@ -730,7 +777,7 @@ readPaletteFromFile(struct pcxCmapEntry ** const pcxcmapP,
 
 static void
 moveBlackToIndex0(colorhist_vector const chv,
-                  int              const colors) {
+                  unsigned int     const colorCt) {
 /*----------------------------------------------------------------------------
    If black is in the palette, make it at Index 0.
 -----------------------------------------------------------------------------*/
@@ -742,7 +789,7 @@ moveBlackToIndex0(colorhist_vector const chv,
 
     blackPresent = FALSE;  /* initial assumption */
 
-    for (i = 0; i < colors; ++i)
+    for (i = 0; i < colorCt; ++i)
         if (PPM_EQUAL(chv[i].color, blackPixel))
             blackPresent = TRUE;
 
@@ -751,10 +798,11 @@ moveBlackToIndex0(colorhist_vector const chv,
            beginning of the table and if the color is already elsewhere in
            the table, removes it.
         */
-        int colors2;
-        colors2 = colors;
-        ppm_addtocolorhist(chv, &colors2, MAXCOLORS, &blackPixel, 0, 0);
-        assert(colors2 == colors);
+        int colorCt2;
+
+        colorCt2 = colorCt;
+        ppm_addtocolorhist(chv, &colorCt2, MAXCOLORS, &blackPixel, 0, 0);
+        assert(colorCt2 == colorCt);
     }
 }
 
@@ -762,12 +810,12 @@ moveBlackToIndex0(colorhist_vector const chv,
 
 static void
 makePcxColormapFromImage(pixel **               const pixels,
-                         int                    const cols,
-                         int                    const rows,
+                         unsigned int           const cols,
+                         unsigned int           const rows,
                          pixval                 const maxval,
-                         struct pcxCmapEntry ** const pcxcmapP,
+                         struct PcxCmapEntry ** const pcxcmapP,
                          colorhash_table *      const chtP,
-                         int *                  const colorsP,
+                         unsigned int *         const colorCtP,
                          bool *                 const tooManyColorsP) {
 /*----------------------------------------------------------------------------
    Make a colormap (palette) for the PCX header that can be used
@@ -783,29 +831,29 @@ makePcxColormapFromImage(pixel **               const pixels,
    Iff there are too many colors to do that (i.e. more than 256),
    return *tooManyColorsP == TRUE.
 -----------------------------------------------------------------------------*/
-    int colors;
+    int colorCt;
     colorhist_vector chv;
 
     pm_message("computing colormap...");
 
-    chv = ppm_computecolorhist(pixels, cols, rows, MAXCOLORS, &colors);
+    chv = ppm_computecolorhist(pixels, cols, rows, MAXCOLORS, &colorCt);
     if (chv == NULL)
         *tooManyColorsP = TRUE;
     else {
-        int i;
-        struct pcxCmapEntry * pcxcmap;
+        unsigned int i;
+        struct PcxCmapEntry * pcxcmap;
 
         *tooManyColorsP = FALSE;
 
-        pm_message("%d colors found", colors);
+        pm_message("%d colors found", colorCt);
 
-        moveBlackToIndex0(chv, colors);
+        moveBlackToIndex0(chv, colorCt);
 
         MALLOCARRAY_NOFAIL(pcxcmap, MAXCOLORS);
 
         *pcxcmapP = pcxcmap;
 
-        for (i = 0; i < colors; ++i) {
+        for (i = 0; i < colorCt; ++i) {
             pixel p;
 
             PPM_DEPTH(p, chv[i].color, maxval, PCX_MAXVAL);
@@ -822,9 +870,9 @@ makePcxColormapFromImage(pixel **               const pixels,
             pcxcmap[i].b = 0;
         }
 
-        *chtP = ppm_colorhisttocolorhash(chv, colors);
+        *chtP = ppm_colorhisttocolorhash(chv, colorCt);
 
-        *colorsP = colors;
+        *colorCtP = colorCt;
 
         ppm_freecolorhist(chv);
     }
@@ -834,43 +882,43 @@ makePcxColormapFromImage(pixel **               const pixels,
 
 static void
 ppmToPalettePcx(pixel **            const pixels,
-                int                 const cols,
-                int                 const rows,
+                unsigned int        const cols,
+                unsigned int        const rows,
                 pixval              const maxval,
                 unsigned int        const xPos,
                 unsigned int        const yPos,
-                struct pcxCmapEntry const pcxcmap[],
+                struct PcxCmapEntry const pcxcmap[],
                 colorhash_table     const cht,
-                int                 const colors,
+                unsigned int        const colorCt,
                 bool                const packbits,
                 unsigned int        const planes,
-                bool                const use_8_bit) {
+                bool                const use8Bit) {
 
     /* convert image */
-    if( colors <= 16 && !use_8_bit )
-        ppmTo16ColorPcx(pixels, cols, rows, pcxcmap, colors, cht,
+    if (colorCt <= 16 && !use8Bit )
+        ppmTo16ColorPcx(pixels, cols, rows, pcxcmap, colorCt, cht,
                         packbits, planes, xPos, yPos);
     else
-        ppmTo256ColorPcx(pixels, cols, rows, pcxcmap, colors, cht,
+        ppmTo256ColorPcx(pixels, cols, rows, pcxcmap, colorCt, cht,
                          xPos, yPos);
 }
 
 
 
 int
-main(int argc, char *argv[]) {
+main(int argc, const char *argv[]) {
 
-    struct cmdlineInfo cmdline;
-    FILE* ifP;
+    struct CmdlineInfo cmdline;
+    FILE * ifP;
     int rows, cols;
     pixval maxval;
     pixel **pixels;
-    struct pcxCmapEntry * pcxcmap;
+    struct PcxCmapEntry * pcxcmap;
     colorhash_table cht;
     bool truecolor;
-    int colors;
+    unsigned int colorCt;
 
-    ppm_init(&argc, argv);
+    pm_proginit(&argc, argv);
 
     parseCommandLine(argc, argv, &cmdline);
 
@@ -883,15 +931,15 @@ main(int argc, char *argv[]) {
     else {
         if (cmdline.stdpalette) {
             truecolor = FALSE;
-            generateStandardPalette(&pcxcmap, maxval, &cht, &colors);
+            generateStandardPalette(&pcxcmap, maxval, &cht, &colorCt);
         } else if (cmdline.palette) {
             truecolor = FALSE;
             readPaletteFromFile(&pcxcmap, cmdline.palette, maxval,
-                                &cht, &colors);
+                                &cht, &colorCt);
         } else {
             bool tooManyColors;
             makePcxColormapFromImage(pixels, cols, rows, maxval,
-                                     &pcxcmap, &cht, &colors,
+                                     &pcxcmap, &cht, &colorCt,
                                      &tooManyColors);
 
             if (tooManyColors) {
@@ -910,8 +958,8 @@ main(int argc, char *argv[]) {
     else {
         ppmToPalettePcx(pixels, cols, rows, maxval,
                         cmdline.xpos, cmdline.ypos,
-                        pcxcmap, cht, colors, cmdline.packed,
-                        cmdline.planes, cmdline.use_8_bit);
+                        pcxcmap, cht, colorCt, cmdline.packed,
+                        cmdline.planes, cmdline.use8Bit);
 
         ppm_freecolorhash(cht);
         free(pcxcmap);
diff --git a/doc/HISTORY b/doc/HISTORY
index 4c987946..8779bd44 100644
--- a/doc/HISTORY
+++ b/doc/HISTORY
@@ -4,37 +4,20 @@ Netpbm.
 CHANGE HISTORY 
 --------------
 
-20.09.16 BJH  Release 10.91.04
+20.09.26 BJH  Release 10.92.00
 
-              pamtojpeg2k: Fix failure with most -progression values.  Always
-              broken (pamtojpeg2k was new in Netpbm 10.12 (November 2002)).
-
-              pamtojpeg2k: Fix wrong result with -tilegrdtly.  Always
-              broken (pamtojpeg2k was new in Netpbm 10.12 (November 2002)).
+              pnmcrop: Make -margin effective with -blank-image=minimize.
 
-              jpeg2ktopam: Fix crash whenever the program fails.  Broken in
-              Netpbm 10.42 (March 2008).
-
-              pamarith: Fix crash with -compare where inputs are PBM.  Broken
-              in Netpbm 10.14 (February 2003).
+              pnmnorm: With bounds specified as -bpercent or -bsingle and
+              -wpercent or -wsingle, and the image has only one brightness,
+              don't attempt any normalization - leave image as is.  (Previous
+              version produces all black with -keephues).
 
-              pamfunc: Fix crash with -changemaxval and PBM input.  Always
-              broken.  -changemaxval was new in Netpbm 10.65 (December 2013).
-
-              pammixmulti: Fix bug: -randomseed ignored on some systems.
-              Always broken.  (pammixmulti was new in Netpbm 10.85 (December
-              2018).
-
-20.09.05 BJH  Release 10.91.03
+              pgmtopbm: Add -randomseed.
 
               pamfunc: Fix always wrong output with -not.  Always broken.
               (-not was new in Netpbm 10.40 (September 2007)).
 
-              ximtoppm: Fix bug: invalid memory references with pathological
-              image input.  Broken in Netpbm 10.91.00 (June 2020).
-
-20.08.29 BJH  Release 10.91.02
-
               pamdepth: fix bug: doesn't work on PAM with black and white
               tuple type.
 
@@ -42,16 +25,44 @@ CHANGE HISTORY
               indicate overlapping values.  Broken since Netpbm 10.43 (June
               2008).
 
-20.07.21 BJH  Release 10.91.01
-
               pbmtext: Fix double-free crash with -font .  Introduced in
               Netpbm 10.91 (June 2020).
 
+              jpeg2ktopam: Fix crash whenever the program fails.  Broken in
+              Netpbm 10.42 (March 2008).
+
+              pamtojpeg2k: Fix failure with most -progression values.  Always
+              broken (pamtojpeg2k was new in Netpbm 10.12 (November 2002)).
+
+              pamtojpeg2k: Fix wrong result with -tilegrdtly.  Always
+              broken (pamtojpeg2k was new in Netpbm 10.12 (November 2002)).
+
+              pamarith: Fix crash with -compare where inputs are PBM or
+              BLACKANDWHITE PAM.  Broken in Netpbm 10.14 (February 2003).
+
+              pamfunc: Fix crash with -changemaxval and PBM or BLACKANDWHITE
+              PAM input.  Always broken.  -changemaxval was new in Netpbm
+              10.65 (December 2013).
+
+              pammixmulti: Fix bug: -randomseed ignored on some systems.
+              Always broken.  (pammixmulti was new in Netpbm 10.85 (December
+              2018).
+
               pcdovtoppm: Fix some garbage from the conversion from csh to sh
               in Netpbm 9.12 (March 2001) in conversion from csh arrays that
               should have stopped it from working at all, despite reports from
               users that they were using it.
 
+              ximtoppm: Fix bug: invalid memory references with pathological
+              image input.  Broken in Netpbm 10.91 (June 2020).
+
+              Configure: remove obsolete question about URL to put in pointer
+              man pages of yesteryear.
+
+              Build: fix bug: PKG_CONFIG make variable not used for merge
+              build.  Always broken (PKG_CONFIG was new in Netpbm 10.76
+              (September 2016).
+
 20.06.28 BJH  Release 10.91.00
 
               pamstretch-gen: Add -quiet (supposedly added in 10.86, but never
diff --git a/editor/Makefile b/editor/Makefile
index 5b12e4ca..88409dad 100644
--- a/editor/Makefile
+++ b/editor/Makefile
@@ -32,7 +32,7 @@ PORTBINARIES = pamaddnoise pamaltsat pambackground pambrighten pamcomp pamcut \
 	       pnmnlfilt pnmnorm pnmpad pnmpaste \
 	       pnmremap pnmrotate \
 	       pnmscalefixed pnmshear pnmsmooth pnmstitch pnmtile \
-	       ppmbrighten ppmchange ppmcolormask \
+	       ppmchange ppmcolormask \
 	       ppmdim ppmdist ppmdither ppmdraw \
 	       ppmflash ppmlabel ppmmix \
 
@@ -44,7 +44,7 @@ NOMERGEBINARIES =
 MERGEBINARIES = $(PORTBINARIES)
 
 BINARIES = $(MERGEBINARIES) $(NOMERGEBINARIES)
-SCRIPTS = pnmflip ppmfade ppmquant ppmshadow \
+SCRIPTS = ppmbrighten pnmflip ppmfade ppmquant ppmshadow \
 	  pamstretch-gen pnmmargin pnmquant pnmquantall 
 
 OBJECTS = $(BINARIES:%=%.o)
diff --git a/editor/pamfunc.c b/editor/pamfunc.c
index 454e6d63..b85cfe9b 100644
--- a/editor/pamfunc.c
+++ b/editor/pamfunc.c
@@ -10,7 +10,7 @@
   ENHANCEMENT IDEAS:
 
   1) speed up by doing integer arithmetic instead of floating point for
-  multiply/divide where possible.  Especially when multiplying by an 
+  multiply/divide where possible.  Especially when multiplying by an
   integer.
 
   2) speed up by not transforming the raster in the idempotent cases
@@ -20,6 +20,7 @@
 
 #include "pm_c_util.h"
 #include "mallocvar.h"
+#include "nstring.h"
 #include "shhopt.h"
 #include "pam.h"
 
@@ -78,7 +79,7 @@ parseHex(const char * const hexString) {
     return retval;
 }
 
-         
+
 
 static void
 parseCommandLine(int argc, const char ** const argv,
@@ -103,7 +104,7 @@ parseCommandLine(int argc, const char ** const argv,
     MALLOCARRAY(option_def, 100);
 
     option_def_index = 0;   /* incremented by OPTENT3 */
-    OPTENT3(0,   "multiplier", OPT_FLOAT,  &cmdlineP->u.multiplier, 
+    OPTENT3(0,   "multiplier", OPT_FLOAT,  &cmdlineP->u.multiplier,
             &multiplierSpec, 0);
     OPTENT3(0,   "divisor",    OPT_FLOAT,  &cmdlineP->u.divisor,
             &divisorSpec,    0);
@@ -150,12 +151,12 @@ parseCommandLine(int argc, const char ** const argv,
     if (multiplierSpec) {
         cmdlineP->function = FN_MULTIPLY;
         if (cmdlineP->u.multiplier < 0)
-            pm_error("Multiplier must be nonnegative.  You specified %f", 
+            pm_error("Multiplier must be nonnegative.  You specified %f",
                      cmdlineP->u.multiplier);
     } else if (divisorSpec) {
         cmdlineP->function = FN_DIVIDE;
         if (cmdlineP->u.divisor < 0)
-            pm_error("Divisor must be nonnegative.  You specified %f", 
+            pm_error("Divisor must be nonnegative.  You specified %f",
                      cmdlineP->u.divisor);
     } else if (adderSpec) {
         cmdlineP->function = FN_ADD;
@@ -180,20 +181,20 @@ parseCommandLine(int argc, const char ** const argv,
         cmdlineP->function = FN_SHIFTLEFT;
     } else if (shiftrightSpec) {
         cmdlineP->function = FN_SHIFTRIGHT;
-    } else 
+    } else
         pm_error("You must specify one of -multiplier, -divisor, "
                  "-adder, -subtractor, -min, -max, "
                  "-and, -or, -xor, -not, -shiftleft, or -shiftright");
-        
+
     if (argc-1 > 1)
         pm_error("Too many arguments (%d).  File spec is the only argument.",
                  argc-1);
 
     if (argc-1 < 1)
         cmdlineP->inputFileName = "-";
-    else 
+    else
         cmdlineP->inputFileName = argv[1];
-    
+
     free(option_def);
 }
 
@@ -336,7 +337,7 @@ applyFunction(struct CmdlineInfo const cmdline,
            1/cmdline.u.divisor instead of divide by cmdline.u.divisor,
            so we compute that here.  Note that if the function isn't
            divide, both cmdline.u.divisor and oneOverDivisor are
-           meaningless.  
+           meaningless.
         */
     unsigned int col;
 
@@ -388,7 +389,7 @@ applyFunction(struct CmdlineInfo const cmdline,
             outputRow[col][plane] = MIN(outpam.maxval, outSample);
         }
     }
-}                
+}
 
 
 
@@ -422,6 +423,9 @@ main(int argc, const char *argv[]) {
     planTransform(cmdline, inpam.maxval, outpam.format,
                   &outpam.maxval, &mustChangeRaster);
 
+    if (outpam.maxval > 1 && strneq(outpam.tuple_type, "BLACKANDWHITE", 13))
+        strcpy(outpam.tuple_type, "");
+
     pnm_writepaminit(&outpam);
 
     outputRow = pnm_allocpamrow(&outpam);
@@ -440,7 +444,7 @@ main(int argc, const char *argv[]) {
     pnm_freepamrow(inputRow);
     pm_close(inpam.file);
     pm_close(outpam.file);
-    
+
     return 0;
 }
 
diff --git a/editor/pnmcrop.c b/editor/pnmcrop.c
index f07340eb..43027da0 100644
--- a/editor/pnmcrop.c
+++ b/editor/pnmcrop.c
@@ -1123,63 +1123,135 @@ noCrops(struct CmdlineInfo const cmdline) {
 
 
 
+static void
+divideAllBackgroundIntoBorders(unsigned int   const totalSz,
+                               bool           const wantCropSideA,
+                               bool           const wantCropSideB,
+                               unsigned int   const wantMargin,
+                               unsigned int * const sideASzP,
+                               unsigned int * const sideBSzP) {
+/*----------------------------------------------------------------------------
+   Divide up an all-background space into fictional borders (that can be
+   trimmed or padded).
+
+   If there is to be a margin, those borders touch - the entire image is
+   borders.  But if there is not to be a margin, there has to be one pixel,
+   row, or column between the borders so that there is something left after we
+   crop off those borders (because there's no such thing as a zero-pixel
+   image).
+
+   This function does the borders in one direction - top and bottom or left
+   and right.  Top or left is called "Side A"; bottom or right is called "Side
+   B".  'totalSz' is the width of the image in the top/bottom case and the
+   height of the image in the left/right case.
+-----------------------------------------------------------------------------*/
+    unsigned int sideASz, sideBSz;
+
+    if (wantCropSideA && wantCropSideB) {
+        sideASz = totalSz/2;
+        if (wantMargin)
+            sideBSz = totalSz - sideASz;
+        else
+            sideBSz = totalSz - sideASz - 1;
+    } else if (wantCropSideA) {
+        if (wantMargin)
+            sideASz = totalSz;
+        else
+            sideASz = totalSz - 1;
+        sideBSz = 0;
+    } else if (wantCropSideB) {
+        sideASz = 0;
+        if (wantMargin)
+            sideBSz = totalSz;
+        else
+            sideBSz = totalSz - 1;
+    } else {
+        sideASz = 0;
+        sideBSz = 0;
+    }
+    *sideASzP = sideASz;
+    *sideBSzP = sideBSz;
+}
+
+
+
+static CropOp
+oneSideCrop(bool         const wantCrop,
+            unsigned int const borderSz,
+            unsigned int const margin) {
+
+    CropOp retval;
+
+    if (wantCrop) {
+        if (borderSz >= margin) {
+            retval.removeSize = borderSz - margin;
+            retval.padSize    = 0;
+        } else {
+            retval.removeSize = 0;
+            retval.padSize    = margin - borderSz;
+        }
+    } else {
+        retval.removeSize = 0;
+        retval.padSize    = 0;
+    }
+
+    return retval;
+}
+
+
+
 static CropSet
 extremeCrops(struct CmdlineInfo const cmdline,
              unsigned int       const cols,
              unsigned int       const rows) {
 /*----------------------------------------------------------------------------
-   Crops that crop as much as possible, reducing output to a single pixel.
+   Crops that crop as much as possible, reducing output to a single
+   row, column, or pixel, plus margins.
 -----------------------------------------------------------------------------*/
     CropSet retval;
 
+    unsigned int leftBorderSz, rghtBorderSz;
+    unsigned int topBorderSz, botBorderSz;
+
     if (cmdline.verbose)
         pm_message("Input image has no distinction between "
                    "border and content");
 
-    /* We can't just pick a representative pixel, say top-left corner.
-       If -top and/or -bottom was specified but not -left and -right,
-       the output should be one row, not a single pixel.
+    /* Note that the "entirely background" image may have several colors: this
+       happens when -closeness was specified.  That means we can't just build
+       up an image from background color - we actually have to preserve some
+       of the original image.
 
-       The "entirely background" image may have several colors: this
-       happens when -closeness was specified.
+       We divide the background into individual borders, with a foreground of
+       either nothing at all or a single row, column, or pixel, then crop
+       those fictional borders the same as if they were real.  The "nothing
+       at all" case is feasible only when there is to be a margin, because
+       otherwise cropping the borders would leave nothing.
     */
 
-    if (cmdline.wantCrop[LEFT] && cmdline.wantCrop[RIGHT]) {
-        retval.op[LEFT ].removeSize = cols / 2;
-        retval.op[RIGHT].removeSize = cols - retval.op[LEFT].removeSize -1;
-    } else if (cmdline.wantCrop[LEFT]) {
-        retval.op[LEFT ].removeSize = cols - 1;
-        retval.op[RIGHT].removeSize = 0;
-    } else if (cmdline.wantCrop[RIGHT]) {
-        retval.op[LEFT ].removeSize = 0;
-        retval.op[RIGHT].removeSize = cols - 1;
-    } else {
-        retval.op[LEFT ].removeSize = 0;
-        retval.op[RIGHT].removeSize = 0;
-    }
-
-    if (cmdline.wantCrop[TOP] && cmdline.wantCrop[BOTTOM]) {
-        retval.op[ TOP  ].removeSize = rows / 2;
-        retval.op[BOTTOM].removeSize = rows - retval.op[TOP].removeSize -1;
-    } else if (cmdline.wantCrop[TOP]) {
-        retval.op[ TOP  ].removeSize = rows - 1;
-        retval.op[BOTTOM].removeSize = 0;
-    } else if (cmdline.wantCrop[BOTTOM]) {
-        retval.op[ TOP  ].removeSize = 0;
-        retval.op[BOTTOM].removeSize = rows - 1;
-    } else {
-        retval.op[ TOP  ].removeSize = 0;
-        retval.op[BOTTOM].removeSize = 0;
-    }
+    divideAllBackgroundIntoBorders(cols,
+                                   cmdline.wantCrop[LEFT],
+                                   cmdline.wantCrop[RIGHT],
+                                   cmdline.margin > 0,
+                                   &leftBorderSz,
+                                   &rghtBorderSz);
+
+    divideAllBackgroundIntoBorders(rows,
+                                   cmdline.wantCrop[TOP],
+                                   cmdline.wantCrop[BOTTOM],
+                                   cmdline.margin > 0,
+                                   &topBorderSz,
+                                   &botBorderSz);
+
+    retval.op[LEFT  ] =
+        oneSideCrop(cmdline.wantCrop[LEFT  ], leftBorderSz, cmdline.margin);
+    retval.op[RIGHT ] =
+        oneSideCrop(cmdline.wantCrop[RIGHT ], rghtBorderSz, cmdline.margin);
+    retval.op[TOP   ] =
+        oneSideCrop(cmdline.wantCrop[TOP   ], topBorderSz,  cmdline.margin);
+    retval.op[BOTTOM] =
+        oneSideCrop(cmdline.wantCrop[BOTTOM], botBorderSz,  cmdline.margin);
 
-    if (cmdline.margin > 0)
-        pm_message ("-margin value %u ignored", cmdline.margin);
-
-    {
-        EdgeLocation i;
-        for (i = 0; i < ARRAY_SIZE(retval.op); ++i)
-            retval.op[i].padSize = 0;
-    }
     return retval;
 }
 
@@ -1329,12 +1401,9 @@ cropOneImage(struct CmdlineInfo const cmdline,
             pm_error("The image is entirely background; "
                      "there is nothing to crop.");
             break;
-        case BLANK_PASS:
-            crop = noCrops(cmdline);                   break;
-        case BLANK_MINIMIZE:
-            crop = extremeCrops(cmdline, cols, rows);  break;
-        case BLANK_MAXCROP:
-            crop = maxcropReport(cmdline, cols, rows); break;
+        case BLANK_PASS:     crop = noCrops(cmdline);                   break;
+        case BLANK_MINIMIZE: crop = extremeCrops(cmdline, cols, rows);  break;
+        case BLANK_MAXCROP:  crop = maxcropReport(cmdline, cols, rows); break;
         }
     } else {
         crop = crops(cmdline, oldBorder);
diff --git a/editor/pnmnorm.c b/editor/pnmnorm.c
index 20d7eb04..8c25df80 100644
--- a/editor/pnmnorm.c
+++ b/editor/pnmnorm.c
@@ -38,7 +38,7 @@
 
 enum brightMethod {BRIGHT_LUMINOSITY, BRIGHT_COLORVALUE, BRIGHT_SATURATION};
 
-struct cmdlineInfo {
+struct CmdlineInfo {
     /* All the information the user supplied in the command line,
        in a form easy for the program to use.
     */
@@ -70,7 +70,7 @@ struct cmdlineInfo {
 
 static void
 parseCommandLine(int argc, const char ** argv,
-                 struct cmdlineInfo * const cmdlineP) {
+                 struct CmdlineInfo * const cmdlineP) {
 /*----------------------------------------------------------------------------
    parse program command line described in Unix standard form by argc
    and argv.  Return the information in the options as *cmdlineP.
@@ -265,7 +265,12 @@ buildHistogram(FILE *   const ifp,
 static xelval
 minimumValue(const unsigned int * const hist,
              unsigned int         const highest) {
+/*----------------------------------------------------------------------------
+   The minimum brightness in the image, according to histogram 'hist',
+   which goes up to 'highest'.
 
+   Abort the program if there are no pixels of any brightness.
+-----------------------------------------------------------------------------*/
     xelval i;
     bool foundOne;
 
@@ -288,7 +293,12 @@ minimumValue(const unsigned int * const hist,
 static xelval
 maximumValue(const unsigned int * const hist,
              unsigned int         const highest) {
+/*----------------------------------------------------------------------------
+   The maximum brightness in the image, according to histogram 'hist',
+   which goes up to 'highest'.
 
+   Abort the program if there are no pixels of any brightness.
+-----------------------------------------------------------------------------*/
     xelval i;
     bool foundOne;
 
@@ -308,12 +318,32 @@ maximumValue(const unsigned int * const hist,
 
 
 
+static unsigned int
+brightnessCount(const unsigned int * const hist,
+                unsigned int         const highest) {
+/*----------------------------------------------------------------------------
+   The number of distinct brightnesses in the image according to
+   histogram 'hist', which goes up to brightness 'highest'.
+-----------------------------------------------------------------------------*/
+    xelval i;
+    unsigned int nonzeroCount;
+
+    for (i = 0, nonzeroCount = 0; i <= highest; ++i) {
+        if (hist[i] > 0)
+            ++nonzeroCount;
+    }
+
+    return nonzeroCount;
+}
+
+
+
 static void
-computeBottomPercentile(unsigned int         hist[],
-                        unsigned int   const highest,
-                        unsigned int   const total,
-                        float          const percent,
-                        unsigned int * const percentileP) {
+computeBottomPercentile(const unsigned int * const hist,
+                        unsigned int         const highest,
+                        unsigned int         const total,
+                        float                const percent,
+                        unsigned int *       const percentileP) {
 /*----------------------------------------------------------------------------
    Compute the lowest index of hist[] such that the sum of the hist[]
    values with that index and lower represent at least 'percent' per cent of
@@ -341,11 +371,11 @@ computeBottomPercentile(unsigned int         hist[],
 
 
 static void
-computeTopPercentile(unsigned int         hist[],
-                     unsigned int   const highest,
-                     unsigned int   const total,
-                     float          const percent,
-                     unsigned int * const percentileP) {
+computeTopPercentile(const unsigned int * const hist,
+                     unsigned int         const highest,
+                     unsigned int         const total,
+                     float                const percent,
+                     unsigned int *       const percentileP) {
 /*----------------------------------------------------------------------------
    Compute the highest index of hist[] such that the sum of the hist[]
    values with that index and higher represent 'percent' per cent of
@@ -496,13 +526,68 @@ disOverlap(xelval   const reqBvalue,
 
 
 
+static xelval
+resolvedPctBvalue(const unsigned int * const hist,
+                  unsigned int         const totalPixelCt,
+                  xelval               const maxval,
+                  struct CmdlineInfo   const cmdline) {
+
+    xelval retval;
+
+    if (cmdline.bsingle)
+        retval = minimumValue(hist, maxval);
+    else if (cmdline.bvalueSpec && !cmdline.bpercentSpec) {
+        retval = cmdline.bvalue;
+    } else {
+        xelval percentBvalue;
+
+        computeBottomPercentile(hist, maxval, totalPixelCt, cmdline.bpercent,
+                                &percentBvalue);
+        if (cmdline.bvalueSpec)
+            retval = MIN(percentBvalue, cmdline.bvalue);
+        else
+            retval = percentBvalue;
+    }
+    return retval;
+}
+
+
+
+static xelval
+resolvedPctWvalue(const unsigned int * const hist,
+                  unsigned int         const totalPixelCt,
+                  xelval               const maxval,
+                  struct CmdlineInfo   const cmdline) {
+
+    xelval retval;
+
+    if (cmdline.wsingle)
+        retval = maximumValue(hist, maxval);
+    else if (cmdline.wvalueSpec && !cmdline.wpercentSpec) {
+        retval = cmdline.wvalue;
+    } else {
+        xelval percentWvalue;
+
+        computeTopPercentile(hist, maxval, totalPixelCt, cmdline.wpercent,
+                             &percentWvalue);
+        if (cmdline.wvalueSpec)
+            retval = MAX(percentWvalue, cmdline.wvalue);
+        else
+            retval = percentWvalue;
+    }
+
+    return retval;
+}
+
+
+
 static void
 resolvePercentParams(FILE *             const ifP,
                      unsigned int       const cols,
                      unsigned int       const rows,
                      xelval             const maxval,
                      int                const format,
-                     struct cmdlineInfo const cmdline,
+                     struct CmdlineInfo const cmdline,
                      xelval *           const bvalueP,
                      xelval *           const wvalueP) {
 /*----------------------------------------------------------------------------
@@ -523,32 +608,17 @@ resolvePercentParams(FILE *             const ifP,
         buildHistogram(ifP, cols, rows, maxval, format, hist,
                        cmdline.brightMethod);
 
-        if (cmdline.bsingle)
-            *bvalueP = minimumValue(hist, maxval);
-        else if (cmdline.bvalueSpec && !cmdline.bpercentSpec) {
-            *bvalueP = cmdline.bvalue;
+        if (!cmdline.bvalueSpec && !cmdline.wvalueSpec &&
+            brightnessCount(hist, maxval) < 2) {
+            /* Special case - you can't stretch a single brightness to both
+               ends.  So just don't stretch at all.
+            */
+            *bvalueP = 0;
+            *wvalueP = maxval;
         } else {
-            xelval percentBvalue;
-            computeBottomPercentile(hist, maxval, cols*rows, cmdline.bpercent,
-                                    &percentBvalue);
-            if (cmdline.bvalueSpec)
-                *bvalueP = MIN(percentBvalue, cmdline.bvalue);
-            else
-                *bvalueP = percentBvalue;
-        }
+            *bvalueP = resolvedPctBvalue(hist, cols * rows, maxval, cmdline);
 
-        if (cmdline.wsingle)
-            *wvalueP = maximumValue(hist, maxval);
-        else if (cmdline.wvalueSpec && !cmdline.wpercentSpec) {
-            *wvalueP = cmdline.wvalue;
-        } else {
-            xelval percentWvalue;
-            computeTopPercentile(hist, maxval, cols*rows, cmdline.wpercent,
-                                 &percentWvalue);
-            if (cmdline.wvalueSpec)
-                *wvalueP = MAX(percentWvalue, cmdline.wvalue);
-            else
-                *wvalueP = percentWvalue;
+            *wvalueP = resolvedPctWvalue(hist, cols * rows, maxval, cmdline);
         }
         free(hist);
     }
@@ -562,7 +632,7 @@ computeEndValues(FILE *             const ifP,
                  int                const rows,
                  xelval             const maxval,
                  int                const format,
-                 struct cmdlineInfo const cmdline,
+                 struct CmdlineInfo const cmdline,
                  xelval *           const bvalueP,
                  xelval *           const wvalueP,
                  bool *             const quadraticP,
@@ -629,7 +699,7 @@ computeLinearTransfer(xelval   const bvalue,
     unsigned int val;
     /* The following for structure is a hand optimization of this one:
        for (i = bvalue; i <= wvalue; ++i)
-       newBrightness[i] = (i-bvalue)*maxval/range);
+           newBrightness[i] = (i-bvalue)*maxval/range);
        (with proper rounding)
     */
     for (i = bvalue, val = range/2;
@@ -937,8 +1007,8 @@ reportTransferParm(bool   const quadratic,
 int
 main(int argc, const char *argv[]) {
 
-    struct cmdlineInfo cmdline;
-    FILE *ifP;
+    struct CmdlineInfo cmdline;
+    FILE * ifP;
     pm_filepos imagePos;
     xelval maxval;
     int rows, cols, format;
diff --git a/editor/ppmbrighten b/editor/ppmbrighten
new file mode 100755
index 00000000..f5de436f
--- /dev/null
+++ b/editor/ppmbrighten
@@ -0,0 +1,60 @@
+#! /bin/sh
+
+# This is just for backward compatibility.  New applications should use
+# 'pambrighten'.
+
+# We don't try very hard to respond well to invalid syntax, because backward
+# compatibility is mostly like existing, working applications.
+
+pambrightenOpts=''
+normalize='no'
+expectValue='no'
+
+for word in "$@"; do
+
+    if test "$expectValue" = 'yes'; then
+        # This is the value of an option, like "40" in "-saturation 40"
+        pambrightenOpts="$pambrightenOpts $word"
+        expectValue='no'
+    else
+        # 'word_one_hyphen' is 'word' except if 'word' is a double-hyphen
+        # option, 'word_one_hyphen' is the single-hyphen version of it.
+        # E.g. word=--saturation word_one_hyphen=-saturation .
+        word_one_hyphen=$(echo "$word" | sed s/^--/-/ )
+    
+        case $word_one_hyphen in
+            -version )
+                pambrighten -version; exit $?
+                ;;
+            -normalize|-normaliz|-normali|-normal|-norma|-norm|-nor|-no|-n)
+                normalize='yes'
+                ;;
+            -*=*)
+                pambrightenOpts="$pambrightenOpts $word"
+                # This is an option with value such as "-saturation=40"
+                ;;
+            -*)
+                pambrightenOpts="$pambrightenOpts $word"
+                # Starts with hyphen, no equals sign, so the next word is the
+                # option's value (note that the only valid ppmbrighten flag
+                # option is -normalized, handled above).
+                #
+                # E.g. "-saturation 40"
+                expectValue='yes'
+                ;;
+            *)
+                # Not an option or option value - only non-option argument
+                # ppmbrighten has is optional input file name
+                infile="$word"
+                ;;
+                
+        esac
+    fi
+done
+
+if test "$normalize" = 'yes'; then
+    pnmnorm -bsingle -wsingle -colorvalue -keephues $infile | \
+        pambrighten $pambrightenOpts | ppmtoppm
+else
+    pambrighten $pambrightenOpts $infile | ppmtoppm
+fi
diff --git a/editor/ppmbrighten.c b/editor/ppmbrighten.c
deleted file mode 100644
index 0446bb75..00000000
--- a/editor/ppmbrighten.c
+++ /dev/null
@@ -1,218 +0,0 @@
-/*=============================================================================
-                              ppmbrighten
-===============================================================================
-  Change Value and Saturation of PPM image.
-=============================================================================*/
-
-#include "pm_c_util.h"
-#include "ppm.h"
-#include "shhopt.h"
-#include "mallocvar.h"
-
-struct CmdlineInfo {
-    /* All the information the user supplied in the command line,
-       in a form easy for the program to use.
-    */
-    const char * inputFileName;  /* '-' if stdin */
-    float saturation;
-    float value;
-    unsigned int normalize;
-};
-
-
-
-static void
-parseCommandLine(int argc, const char ** argv,
-                 struct CmdlineInfo * const cmdlineP) {
-/*----------------------------------------------------------------------------
-   parse program command line described in Unix standard form by argc
-   and argv.  Return the information in the options as *cmdlineP.
-
-   If command line is internally inconsistent (invalid options, etc.),
-   issue error message to stderr and abort program.
-
-   Note that the strings we return are stored in the storage that
-   was passed to us as the argv array.  We also trash *argv.
------------------------------------------------------------------------------*/
-    optEntry *option_def;
-        /* Instructions to pm_optParseOptions3 on how to parse our options.
-         */
-    optStruct3 opt;
-
-    unsigned int option_def_index;
-
-    unsigned int saturationSpec, valueSpec;
-    int saturationOpt, valueOpt;
-
-    MALLOCARRAY_NOFAIL(option_def, 100);
-
-    option_def_index = 0;   /* incremented by OPTENT3 */
-    OPTENT3(0, "saturation",  OPT_INT,    &saturationOpt,
-            &saturationSpec,      0 );
-    OPTENT3(0, "value",       OPT_INT,    &valueOpt,
-            &valueSpec,           0 );
-    OPTENT3(0, "normalize",   OPT_FLAG,   NULL,
-            &cmdlineP->normalize, 0 );
-
-    opt.opt_table = option_def;
-    opt.short_allowed = FALSE;  /* We have no short (old-fashioned) options */
-    opt.allowNegNum = FALSE;  /* We have no parms that are negative numbers */
-
-    pm_optParseOptions3(&argc, (char **)argv, opt, sizeof(opt), 0);
-        /* Uses and sets argc, argv, and some of *cmdlineP and others. */
-
-    if (saturationSpec) {
-        if (saturationOpt < -100)
-            pm_error("Saturation reduction cannot be more than 100%%.  "
-                     "You specified %d", saturationOpt);
-        else
-            cmdlineP->saturation = 1.0 + (float)saturationOpt / 100;
-    } else
-        cmdlineP->saturation = 1.0;
-
-    if (valueSpec) {
-        if (valueOpt < -100)
-            pm_error("Value reduction cannot be more than 100%%.  "
-                     "You specified %d", valueOpt);
-        else
-            cmdlineP->value = 1.0 + (float)valueOpt / 100;
-    } else
-        cmdlineP->value = 1.0;
-
-    if (argc-1 < 1)
-        cmdlineP->inputFileName = "-";
-    else if (argc-1 == 1)
-        cmdlineP->inputFileName = argv[1];
-    else
-        pm_error("Program takes at most one argument:  file specification");
-}
-
-
-
-static void
-getMinMax(FILE *       const ifP,
-          unsigned int const cols,
-          unsigned int const rows,
-          pixval       const maxval,
-          int          const format,
-          double *     const minValueP,
-          double *     const maxValueP) {
-
-    pixel * pixelrow;
-    double minValue, maxValue;
-    unsigned int row;
-
-    pixelrow = ppm_allocrow(cols);
-
-    for (row = 0, minValue = 65536.0, maxValue = 0.0; row < rows; ++row) {
-        unsigned int col;
-
-        ppm_readppmrow(ifP, pixelrow, cols, maxval, format);
-
-        for (col = 0; col < cols; ++col) {
-            struct hsv const pixhsv =
-                ppm_hsv_from_color(pixelrow[col], maxval);
-
-            maxValue = MAX(maxValue, pixhsv.v);
-            minValue = MIN(minValue, pixhsv.v);
-        }
-    }
-    ppm_freerow(pixelrow);
-
-    *minValueP = minValue;
-    *maxValueP = maxValue;
-}
-
-
-
-int
-main(int argc, const char ** argv) {
-
-    double const EPSILON = 1.0e-5;
-    struct CmdlineInfo cmdline;
-    FILE * ifP;
-    pixel * pixelrow;
-    pixval maxval;
-    int rows, cols, format, row;
-    double minValue, maxValue;
-
-    pm_proginit(&argc, argv);
-
-    parseCommandLine(argc, argv, &cmdline);
-
-    if (cmdline.normalize)
-        ifP = pm_openr_seekable(cmdline.inputFileName);
-    else
-        ifP = pm_openr(cmdline.inputFileName);
-
-    ppm_readppminit(ifP, &cols, &rows, &maxval, &format);
-
-    if (cmdline.normalize) {
-        pm_filepos rasterPos;
-        pm_tell2(ifP, &rasterPos, sizeof(rasterPos));
-        getMinMax(ifP, cols, rows, maxval, format, &minValue, &maxValue);
-        pm_seek2(ifP, &rasterPos, sizeof(rasterPos));
-        if (maxValue - minValue > EPSILON) {
-            pm_message("Minimum value %.0f%% of full intensity "
-                       "being remapped to zero.",
-                       (minValue * 100.0));
-            pm_message("Maximum value %.0f%% of full intensity "
-                       "being remapped to full.",
-                       (maxValue * 100.0));
-        } else
-            pm_message("Sole value of %.0f%% of full intensity "
-                       "not being remapped",
-                       (maxValue * 100.0));
-    }
-
-    pixelrow = ppm_allocrow(cols);
-
-    ppm_writeppminit(stdout, cols, rows, maxval, 0);
-
-    for (row = 0; row < rows; ++row) {
-        unsigned int col;
-
-        ppm_readppmrow(ifP, pixelrow, cols, maxval, format);
-
-        for (col = 0; col < cols; ++col) {
-            struct hsv pixhsv;
-
-            pixhsv = ppm_hsv_from_color(pixelrow[col], maxval);
-                /* initial value */
-
-            if (cmdline.normalize) {
-                if (maxValue - minValue > EPSILON)
-                    pixhsv.v = (pixhsv.v - minValue) / (maxValue - minValue);
-            }
-            pixhsv.s = pixhsv.s * cmdline.saturation;
-            pixhsv.s = MAX(0.0, MIN(1.0, pixhsv.s));
-            pixhsv.v = pixhsv.v * cmdline.value;
-            pixhsv.v = MAX(0.0, MIN(1.0, pixhsv.v));
-            pixelrow[col] = ppm_color_from_hsv(pixhsv, maxval);
-        }
-        ppm_writeppmrow(stdout, pixelrow, cols, maxval, 0);
-    }
-    ppm_freerow(pixelrow);
-
-    pm_close(ifP);
-
-    /* If the program failed, it previously aborted with nonzero exit status
-       via various function calls.
-    */
-    return 0;
-}
-
-
-
-/**
-** Copyright (C) 1989 by Jef Poskanzer.
-** Copyright (C) 1990 by Brian Moffet.
-**
-** Permission to use, copy, modify, and distribute this software and its
-** documentation for any purpose and without fee is hereby granted, provided
-** that the above copyright notice appear in all copies and that both that
-** copyright notice and this permission notice appear in supporting
-** documentation.  This software is provided "as is" without express or
-** implied warranty.
-*/
-
diff --git a/other/pamarith.c b/other/pamarith.c
index 3fde1953..c67c7326 100644
--- a/other/pamarith.c
+++ b/other/pamarith.c
@@ -4,6 +4,7 @@
 
 #include "pm_c_util.h"
 #include "mallocvar.h"
+#include "nstring.h"
 #include "shhopt.h"
 #include "pam.h"
 
@@ -19,7 +20,7 @@ static bool
 isDyadic(enum function const function) {
 
     bool retval;
-    
+
     switch (function) {
     case FN_ADD:
     case FN_MEAN:
@@ -71,7 +72,7 @@ parseCommandLine(int argc, const char ** const argv,
     optStruct3 opt;
 
     unsigned int option_def_index;
-    
+
     unsigned int addSpec, subtractSpec, multiplySpec, divideSpec,
         differenceSpec,
         minimumSpec, maximumSpec, meanSpec, compareSpec,
@@ -160,7 +161,7 @@ parseCommandLine(int argc, const char ** const argv,
             cmdlineP->operandFileNames = &argv[1];
         }
     }
-}        
+}
 
 
 
@@ -183,7 +184,7 @@ static enum category
 functionCategory(enum function const function) {
 
     enum category retval;
-    
+
     switch (function) {
     case FN_ADD:
     case FN_SUBTRACT:
@@ -251,6 +252,7 @@ computeOutputType(struct pam *  const outpamP,
     outpamP->width       = inpam1.width;
     outpamP->depth       = MAX(inpam1.depth, inpam2.depth);
 
+
     if (function == FN_COMPARE)
         outpamP->format = outFmtForCompare(inpam1.format, inpam2.format);
     else
@@ -267,7 +269,7 @@ computeOutputType(struct pam *  const outpamP,
         if (inpam2.maxval != inpam1.maxval)
             pm_error("For a bit string operation, the maxvals of the "
                      "left and right image must be the same.  You have "
-                     "left=%u and right=%u", 
+                     "left=%u and right=%u",
                      (unsigned)inpam1.maxval, (unsigned)inpam2.maxval);
 
         if (pm_bitstomaxval(pm_maxvaltobits(inpam1.maxval)) != inpam1.maxval)
@@ -288,7 +290,11 @@ computeOutputType(struct pam *  const outpamP,
         outpamP->maxval = inpam1.maxval;
     }
     outpamP->bytes_per_sample = (pm_maxvaltobits(outpamP->maxval)+7)/8;
-    strcpy(outpamP->tuple_type, inpam1.tuple_type);
+
+    if (outpamP->maxval > 1 && strneq(inpam1.tuple_type, "BLACKANDWHITE", 13))
+        strcpy(outpamP->tuple_type, "");
+    else
+        strcpy(outpamP->tuple_type, inpam1.tuple_type);
 }
 
 
@@ -394,7 +400,7 @@ applyNormalizedFunction(enum function const function,
         operands[0] / operands[1] : 1.;
         break;
     case FN_DIFFERENCE:
-        result = operands[0] > operands[1] ? 
+        result = operands[0] > operands[1] ?
             operands[0] - operands[1] : operands[1] - operands[0];
         break;
     case FN_MINIMUM:
@@ -407,7 +413,7 @@ applyNormalizedFunction(enum function const function,
         result = samplenMean(operands, operandCt);
         break;
     case FN_COMPARE:
-        result = 
+        result =
             operands[0] > operands[1] ?
             1. : operands[0] < operands[1] ?
             0. : .5;
@@ -444,7 +450,7 @@ doNormalizedArith(struct pam *  const inpam1P,
            computation
         */
     unsigned int * plane;
-        /* plane[0] is the plane number in the first operand image for 
+        /* plane[0] is the plane number in the first operand image for
            the current one-sample computation.  plane[1] is the plane number
            in the second operand image, etc.
          */
@@ -461,10 +467,10 @@ doNormalizedArith(struct pam *  const inpam1P,
         unsigned int col;
         pnm_readpamrown(inpam1P, tuplerown[0]);
         pnm_readpamrown(inpam2P, tuplerown[1]);
-        
+
         for (col = 0; col < outpamP->width; ++col) {
             unsigned int outplane;
-            
+
             for (outplane = 0; outplane < outpamP->depth; ++outplane) {
                 unsigned int op;
 
@@ -474,8 +480,8 @@ doNormalizedArith(struct pam *  const inpam1P,
                 for (op = 0; op < operandCt; ++op)
                     operands[op] = tuplerown[op][col][plane[op]];
 
-                tuplerownOut[col][outplane] = 
-                    applyNormalizedFunction(function, operands, operandCt); 
+                tuplerownOut[col][outplane] =
+                    applyNormalizedFunction(function, operands, operandCt);
                 assert(tuplerownOut[col][outplane] >= 0.);
                 assert(tuplerownOut[col][outplane] <= 1.);
             }
@@ -765,7 +771,7 @@ doUnNormalizedArith(struct pam *  const inpam1P,
            computation
         */
     unsigned int * plane;
-        /* plane[0] is the plane number in the first operand image for 
+        /* plane[0] is the plane number in the first operand image for
            the current one-sample computation.  plane[1] is the plane number
            in the second operand image, etc.
          */
@@ -787,10 +793,10 @@ doUnNormalizedArith(struct pam *  const inpam1P,
         unsigned int col;
         pnm_readpamrow(inpam1P, tuplerow[0]);
         pnm_readpamrow(inpam2P, tuplerow[1]);
-        
+
         for (col = 0; col < outpamP->width; ++col) {
             unsigned int outplane;
-            
+
             for (outplane = 0; outplane < outpamP->depth; ++outplane) {
                 unsigned int op;
 
@@ -800,7 +806,7 @@ doUnNormalizedArith(struct pam *  const inpam1P,
                 for (op = 0; op < operandCt; ++op)
                     operands[op] = tuplerow[op][col][plane[op]];
 
-                tuplerowOut[col][outplane] = 
+                tuplerowOut[col][outplane] =
                     applyUnNormalizedFunction(function, operands, operandCt,
                                               maxval);
 
@@ -830,7 +836,7 @@ main(int argc, const char *argv[]) {
     struct pam outpam;
     FILE * if1P;
     FILE * if2P;
-    
+
     pm_proginit(&argc, argv);
 
     parseCommandLine(argc, argv, &cmdline);
@@ -861,7 +867,7 @@ main(int argc, const char *argv[]) {
 
     pnm_writepaminit(&outpam);
 
-    switch (functionCategory(cmdline.function)) {    
+    switch (functionCategory(cmdline.function)) {
     case CATEGORY_FRACTIONAL_ARITH:
         if (inpam1.maxval == inpam2.maxval && inpam2.maxval == outpam.maxval)
             doUnNormalizedArith(&inpam1, &inpam2, &outpam, cmdline.function);
@@ -876,6 +882,6 @@ main(int argc, const char *argv[]) {
 
     pm_close(if1P);
     pm_close(if2P);
-    
+
     return 0;
 }
diff --git a/other/pamdepth.c b/other/pamdepth.c
index 96613d07..46601864 100644
--- a/other/pamdepth.c
+++ b/other/pamdepth.c
@@ -17,7 +17,7 @@
 #include "shhopt.h"
 #include "pam.h"
 
-struct cmdlineInfo {
+struct CmdlineInfo {
     /* All the information the user supplied in the command line,
        in a form easy for the program to use.
     */
@@ -30,7 +30,7 @@ struct cmdlineInfo {
 
 static void
 parseCommandLine(int argc, const char ** argv,
-                 struct cmdlineInfo *cmdlineP) {
+                 struct CmdlineInfo * const cmdlineP) {
 /*----------------------------------------------------------------------------
    Note that the file spec strings we return are stored in the storage that
    was passed to us as the argv array.
@@ -45,7 +45,7 @@ parseCommandLine(int argc, const char ** argv,
     MALLOCARRAY_NOFAIL(option_def, 100);
 
     option_def_index = 0;   /* incremented by OPTENTRY */
-    OPTENT3(0, "verbose",  OPT_STRING, NULL, 
+    OPTENT3(0, "verbose",  OPT_STRING, NULL,
             &cmdlineP->verbose, 0);
 
     opt.opt_table = option_def;
@@ -64,8 +64,8 @@ parseCommandLine(int argc, const char ** argv,
             pm_error("New maxval must be at least 1.  You specified %d",
                      intval);
         else if (intval > PNM_OVERALLMAXVAL)
-            pm_error("newmaxval (%d) is too large.\n"
-                     "The maximum allowed by the PNM formats is %d.",
+            pm_error("newmaxval (%d) is too large.  "
+                     "The maximum allowed by the PNM formats is %u.",
                      intval, PNM_OVERALLMAXVAL);
         else
             cmdlineP->newMaxval = intval;
@@ -101,7 +101,7 @@ createSampleMap(sample   const oldMaxval,
 static void
 transformRaster(struct pam * const inpamP,
                 struct pam * const outpamP) {
-                
+
     tuple * tuplerow;
     unsigned int row;
     sample * sampleMap;  /* malloc'ed */
@@ -136,7 +136,7 @@ transformRaster(struct pam * const inpamP,
 int
 main(int argc, const char * argv[]) {
 
-    struct cmdlineInfo cmdline;
+    struct CmdlineInfo cmdline;
     FILE * ifP;
     struct pam inpam;
     struct pam outpam;
@@ -153,15 +153,15 @@ main(int argc, const char * argv[]) {
         pnm_readpaminit(ifP, &inpam, PAM_STRUCT_SIZE(tuple_type));
 
         outpam = inpam;  /* initial value */
-        
+
         outpam.file = stdout;
         outpam.maxval = cmdline.newMaxval;
-        
+
         if (PNM_FORMAT_TYPE(inpam.format) == PBM_TYPE) {
             outpam.format = PGM_TYPE;
         } else
             outpam.format = inpam.format;
-        
+
         if (streq(inpam.tuple_type, PAM_PBM_TUPLETYPE)) {
             pm_message("promoting from black and white to grayscale");
             strcpy(outpam.tuple_type, PAM_PGM_TUPLETYPE);
@@ -182,3 +182,6 @@ main(int argc, const char * argv[]) {
 
     return 0;
 }
+
+
+
diff --git a/test/Available-Testprog b/test/Available-Testprog
index 8176b57a..033c7eec 100755
--- a/test/Available-Testprog
+++ b/test/Available-Testprog
@@ -6,7 +6,6 @@ if [ "${CHECK_TYPE}" = "install" ]; then
 fi
 
 # Special case: no arguments were passed to this program
-# For all-in-place.test and legacy-names.test
 
 if [ $# = 0 ]; then
   exit 0
@@ -19,6 +18,10 @@ fi
 # each directory (for example converter/other/Makefile) for library
 # requirements and relevant variables.
 
+# Note that any variable used to determine whether a program exists
+# (BUILD_FIASCO, JASPERLIB, JBIGLIB, JPEGLIB, etc.)
+# must be in CHECK_VARS in GNUMakefile to be detected here. 
+
 for i in $@
     do
     case $i in
@@ -57,6 +60,9 @@ for i in $@
       svgtopam)
         [ "${XML2_LIBS}" = "NONE" ] && exit 1 ;;
 
+      ppmsvgalib)
+        [ "${LINUXSVGALIB}" = "NONE" ] && exit 1 ;;
+
       thinkjettopbm)
         [ -z "${LEX}" ] && exit 1 ;;
 
diff --git a/test/Test-Order b/test/Test-Order
index f907c29b..6c553be1 100644
--- a/test/Test-Order
+++ b/test/Test-Order
@@ -83,6 +83,7 @@ pnmremap2.test
 pnmquant.test
 pnmquantall.test
 pnmtile.test
+pambrighten.test
 ppmbrighten.test
 ppmdither.test
 ppmrelief.test
@@ -91,6 +92,9 @@ ppmdim.test
 pnmshear.test
 pgmbentley.test
 
+pamfunc.test
+pamarith.test
+
 pamenlarge.test
 pamenlarge-pbm.test
 
@@ -149,9 +153,10 @@ enlarge-reduce-roundtrip.test
 cut-cat-roundtrip.test
 pamhue-roundtrip.test
 
-# Round-trip tests: miscellaneous utility
+# Round-trip tests: miscellaneous utilities
 
 pamexec-roundtrip.test
+channel-stack-roundtrip.test
 
 # Round-trip tests : lossless converters
 
@@ -202,6 +207,7 @@ tiff-flate-lzw-roundtrip.test
 utahrle-roundtrip.test
 wbmp-roundtrip.test
 winicon-roundtrip.test
+winicon-roundtrip2.test
 xbm-roundtrip.test
 xpm-roundtrip.test
 xv-roundtrip.test
diff --git a/test/all-in-place.ok b/test/all-in-place.ok
index 2df9f392..4d840102 100644
--- a/test/all-in-place.ok
+++ b/test/all-in-place.ok
@@ -238,11 +238,9 @@ pnmtosir: ok
 pnmtotiffcmyk: ok
 pnmtoxwd: ok
 ppm3d: ok
-ppmbrighten: ok
 ppmchange: ok
 ppmcie: ok
 ppmcolormask: ok
-ppmcolors: ok
 ppmdcfont: ok
 ppmddumpfont: ok
 ppmdim: ok
@@ -266,6 +264,7 @@ ppmrough: ok
 ppmshadow: ok
 ppmshift: ok
 ppmspread: ok
+ppmsvgalib: ok
 ppmtoacad: ok
 ppmtoapplevol: ok
 ppmtoarbtxt: ok
@@ -276,6 +275,7 @@ ppmtoicr: ok
 ppmtoilbm: ok
 ppmtoleaf: ok
 ppmtolj: ok
+ppmtompeg: ok
 ppmtomitsu: ok
 ppmtoneo: ok
 ppmtopcx: ok
diff --git a/test/all-in-place.test b/test/all-in-place.test
index 6cf677ef..78a9346a 100755
--- a/test/all-in-place.test
+++ b/test/all-in-place.test
@@ -280,11 +280,9 @@ ordinary_testprogs="\
   pnmtotiffcmyk \
   pnmtoxwd \
   ppm3d \
-  ppmbrighten \
   ppmchange \
   ppmcie \
   ppmcolormask \
-  ppmcolors \
   ppmdcfont \
   ppmddumpfont \
   ppmdim \
@@ -308,6 +306,7 @@ ordinary_testprogs="\
   ppmshadow \
   ppmshift \
   ppmspread \
+  ppmsvgalib \
   ppmtoacad \
   ppmtoapplevol \
   ppmtoarbtxt \
@@ -318,6 +317,7 @@ ordinary_testprogs="\
   ppmtoilbm \
   ppmtoleaf \
   ppmtolj \
+  ppmtompeg \
   ppmtomitsu \
   ppmtoneo \
   ppmtopcx \
@@ -431,3 +431,5 @@ testExitStatus anytopnm 0 $?
 
 manweb --help > /dev/null
     testExitStatus manweb 0 $?
+
+# We do not test vidtoppm.
\ No newline at end of file
diff --git a/test/channel-stack-roundtrip.ok b/test/channel-stack-roundtrip.ok
new file mode 100644
index 00000000..708305f1
--- /dev/null
+++ b/test/channel-stack-roundtrip.ok
@@ -0,0 +1,11 @@
+Test 1: should print 1873848880 101532 twice, then 0
+1873848880 101532
+1873848880 101532
+1873848880 101532
+1873848880 101532
+1873848880 101532
+0
+Test 2: Should print 447072062 33892 three times
+447072062 33892
+447072062 33892
+447072062 33892
diff --git a/test/channel-stack-roundtrip.test b/test/channel-stack-roundtrip.test
new file mode 100755
index 00000000..dae64605
--- /dev/null
+++ b/test/channel-stack-roundtrip.test
@@ -0,0 +1,34 @@
+#! /bin/bash
+# This script tests: pamchanel pamstack
+# Also requires: pamtopam pamstack pamtopnm
+
+tmpdir=${tmpdir:-/tmp}
+r_pam=${tmpdir}/testimg_r.pam
+g_pam=${tmpdir}/testimg_g.pam
+b_pam=${tmpdir}/testimg_b.pam
+rgb_pam=${tmpdir}/testimg_rgb.pam
+
+echo "Test 1: should print 1873848880 101532 twice, then 0"
+
+pamchannel -tupletype="GRAYSCALE" -infile testimg.ppm 0 > ${r_pam}
+pamchannel -tupletype="GRAYSCALE" -infile testimg.ppm 1 > ${g_pam}
+pamchannel -tupletype="GRAYSCALE" -infile testimg.ppm 2 > ${b_pam}
+
+pamtopam < testimg.ppm | pamstack -tupletype="RGB" - | cksum
+pamstack ${r_pam} ${g_pam} | \
+pamstack -tupletype="RGB" - ${b_pam} | cksum
+pamstack ${r_pam} | \
+pamstack -tupletype="RGB" - ${g_pam} ${b_pam} | cksum
+pamstack ${r_pam} ${b_pam} ${g_pam} ${b_pam} ${b_pam} ${b_pam} | \
+  pamchannel -tupletype="RGB" 0 2 4 | cksum 
+pamstack -tupletype="RGB" ${r_pam} ${g_pam} ${b_pam} | tee ${rgb_pam} | cksum
+pamtopnm ${rgb_pam} | cmp - testimg.ppm
+echo $?
+
+echo "Test 2: Should print 447072062 33892 three times"
+
+cat ${r_pam} | cksum
+pamstack -tupletype="GRAYSCALE" ${r_pam} | cksum
+pamstack ${r_pam} | pamchannel -tupletype="GRAYSCALE" 0 | cksum
+
+rm ${r_pam} ${g_pam} ${b_pam} ${rgb_pam}
diff --git a/test/legacy-names.ok b/test/legacy-names.ok
index 94ef875f..27baf672 100644
--- a/test/legacy-names.ok
+++ b/test/legacy-names.ok
@@ -26,14 +26,16 @@ pnmtofits: ok
 pnmtoplainpnm: ok
 pnmtopnm: ok
 pnmtotiff: ok
+ppmbrighten: ok
+ppmcolors: ok
 ppmnorm: ok
 ppmquant: ok
 ppmquantall: ok
 ppmtogif: ok
 ppmtojpeg: ok
 ppmtomap: ok
-ppmtompeg: ok
 ppmtotga: ok
 ppmtouil: ok
 hpcdtoppm: ok
 pcdovtoppm: ok
+pcdindex: ok
diff --git a/test/legacy-names.test b/test/legacy-names.test
index 5a65615f..e20dde76 100755
--- a/test/legacy-names.test
+++ b/test/legacy-names.test
@@ -83,13 +83,14 @@ ordinary_testprogs="\
   pnmtoplainpnm \
   pnmtopnm \
   pnmtotiff \
+  ppmbrighten \
+  ppmcolors \
   ppmnorm \
   ppmquant \
   ppmquantall \
   ppmtogif \
   ppmtojpeg \
   ppmtomap \
-  ppmtompeg \
   ppmtotga \
   ppmtouil \
 "
@@ -125,10 +126,13 @@ for i in $ordinary_testprogs
 
 
 
-# Test hpcdtoppm and pcdovtoppm.  Simply confirm their existence.
+# Test hpcdtoppm, pcdovtoppm and pcdindex.  Simply confirm their existence.
 
 type -p hpcdtoppm > /dev/null
 testExitStatus hpcdtoppm 0 $?
 
 type -p pcdovtoppm > /dev/null
 testExitStatus pcdovtoppm 0 $?
+
+type -p pcdindex > /dev/null
+testExitStatus pcdindex 0 $?
diff --git a/test/pamarith.ok b/test/pamarith.ok
new file mode 100644
index 00000000..782637d3
--- /dev/null
+++ b/test/pamarith.ok
@@ -0,0 +1,182 @@
+Test 1
+P2
+16 2
+15
+0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
+2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2
+-add
+P2 16 1 15 2 3 4 5 6 7 8 9 10 11 12 13 14 15 15 15  
+1927712885 59
+1927712885 59
+1927712885 59
+-subtract
+P2 16 1 15 0 0 0 1 2 3 4 5 6 7 8 9 10 11 12 13  
+622443613 59
+622443613 59
+622443613 59
+-multiply
+P2 16 1 15 0 0 0 0 1 1 1 1 1 1 1 1 2 2 2 2  
+1589721418 59
+1589721418 59
+1589721418 59
+-divide
+P2 16 1 15 0 8 15 15 15 15 15 15 15 15 15 15 15 15 15 15  
+321546811 59
+321546811 59
+321546811 59
+-difference
+P2 16 1 15 2 1 0 1 2 3 4 5 6 7 8 9 10 11 12 13  
+590140907 59
+590140907 59
+590140907 59
+-minimum
+P2 16 1 15 0 1 2 2 2 2 2 2 2 2 2 2 2 2 2 2  
+3746423180 59
+3746423180 59
+3746423180 59
+-maximum
+P2 16 1 15 2 2 2 3 4 5 6 7 8 9 10 11 12 13 14 15  
+201376294 59
+201376294 59
+201376294 59
+-mean
+P2 16 1 15 1 2 2 3 3 4 4 5 5 6 6 7 7 8 8 9  
+1456675831 59
+1456675831 59
+1456675831 59
+-compare
+P2 16 1 2 0 0 1 2 2 2 2 2 2 2 2 2 2 2 2 2  
+196115582 58
+196115582 58
+196115582 58
+-and
+P2 16 1 15 0 0 2 2 0 0 2 2 0 0 2 2 0 0 2 2  
+3660405045 59
+3660405045 59
+3660405045 59
+-or
+P2 16 1 15 2 3 2 3 6 7 6 7 10 11 10 11 14 15 14 15  
+157317791 59
+157317791 59
+157317791 59
+-nand
+P2 16 1 15 15 15 13 13 15 15 13 13 15 15 13 13 15 15 13 13  
+1625584307 59
+1625584307 59
+1625584307 59
+-nor
+P2 16 1 15 13 12 13 12 9 8 9 8 5 4 5 4 1 0 1 0  
+3014218009 59
+3014218009 59
+3014218009 59
+-xor
+P2 16 1 15 2 3 0 1 6 7 4 5 10 11 8 9 14 15 12 13  
+3227090877 59
+3227090877 59
+3227090877 59
+-shiftleft
+P2 16 1 15 0 4 8 12 0 4 8 12 0 4 8 12 0 4 8 12  
+952940636 59
+952940636 59
+952940636 59
+-shiftright
+P2 16 1 15 0 0 0 0 1 1 1 1 2 2 2 2 3 3 3 3  
+2898922266 59
+2898922266 59
+2898922266 59
+Test 2 PBM
+P1
+8 2
+01010101
+00001111
+-add
+P1 8 1 00000101 
+-subtract
+P1 8 1 11110101 
+-multiply
+P1 8 1 01011111 
+-divide
+P1 8 1 01010000 
+-difference
+P1 8 1 10100101 
+-minimum
+P1 8 1 01011111 
+-maximum
+P1 8 1 00000101 
+-mean
+P1 8 1 00000101 
+-compare
+P2 8 1 2 1 0 1 0 2 1 2 1  
+-and
+P1 8 1 01011111 
+-or
+P1 8 1 00000101 
+-nand
+P1 8 1 10100000 
+-nor
+P1 8 1 11111010 
+-xor
+P1 8 1 10100101 
+-shiftleft
+P1 8 1 11110101 
+-shiftright
+P1 8 1 11110101 
+Test 3 (input = output)
+cksum is 2425386270 41 or 2921940274 59
+input image
+2425386270 41
+-minimum
+2425386270 41
+-maximum
+2425386270 41
+-mean
+2425386270 41
+-and
+2425386270 41
+-or
+2425386270 41
+input image
+2921940274 59
+-minimum
+2921940274 59
+-maximum
+2921940274 59
+-mean
+2921940274 59
+-and
+2921940274 59
+-or
+2921940274 59
+Test 4 (blank output)
+cksum is 2817549367 41 or 320101399 59
+-subtract
+2817549367 41
+-difference
+2817549367 41
+-xor
+2817549367 41
+-subtract
+320101399 59
+-difference
+320101399 59
+-xor
+320101399 59
+Test Invalid
+Expected failure 1 1
+Expected failure 2 1
+Expected failure 3 1
+Expected failure 4 1
+Expected failure 5 1
+Expected failure 6 1
+Expected failure 7 1
+Expected failure 8 1
+Expected failure 9 1
+Expected failure 10 1
+Expected failure 11 1
+Expected failure 12 1
+Expected failure 13 1
+Expected failure 14 1
+Expected failure 15 1
+Expected failure 16 1
+Expected failure 17 1
+Expected failure 18 1
diff --git a/test/pamarith.test b/test/pamarith.test
new file mode 100755
index 00000000..d8055385
--- /dev/null
+++ b/test/pamarith.test
@@ -0,0 +1,165 @@
+
+#! /bin/bash
+# This script tests: pamarith
+# Also requires: pamchannel pamseq pamtopnm pgmmake pnmcat rgb3toppm
+# Also requires: pbmmake pamenlarge
+
+tmpdir=${tmpdir:-/tmp}
+input1_pgm=${tmpdir}/input1.pgm
+input2_pgm=${tmpdir}/input2.pgm
+output_pgm=${tmpdir}/output.pgm
+input1_ppm=${tmpdir}/input1.ppm
+input2_ppm=${tmpdir}/input2.ppm
+
+echo "Test 1"
+
+pamseq 1 15 | pamtopnm -assume > ${input1_pgm}
+pgmmake -maxval 15 0.15 16 1 > ${input2_pgm}
+
+rgb3toppm ${input1_pgm} ${input1_pgm} ${input1_pgm} > ${input1_ppm} 
+rgb3toppm ${input2_pgm} ${input2_pgm} ${input2_pgm} > ${input2_ppm} 
+
+pnmcat -tb -plain ${input1_pgm} ${input2_pgm}
+
+for fn in "-add" "-subtract" "-multiply" "-divide" "-difference" \
+    "-minimum" "-maximum" "-mean" "-compare" \
+    "-and" "-or" "-nand" "-nor"  "-xor" \
+    "-shiftleft" "-shiftright"
+  do
+  echo ${fn}
+  pamarith ${fn} -plain ${input1_pgm} ${input2_pgm} | tr '\n' ' '; echo
+  pamarith ${fn} ${input1_pgm} ${input2_pgm} > ${output_pgm}
+  rgb3toppm  ${output_pgm} ${output_pgm} ${output_pgm} | cksum
+  pamarith ${fn} ${input1_ppm} ${input2_pgm} | cksum
+  pamarith ${fn} ${input1_ppm} ${input2_ppm} | cksum
+  done
+
+rm ${input1_pgm} ${input2_pgm} ${output_pgm} ${input2_ppm}
+
+
+input1_pbm=${tmpdir}/input1.pbm
+input2_pbm=${tmpdir}/input2.pbm
+
+echo "Test 2 PBM"
+
+pbmmake -g 8 1 > ${input1_pbm}
+pbmmake -g 2 1 | pamenlarge -xscale=4 > ${input2_pbm}
+
+pnmcat -tb -plain ${input1_pbm} ${input2_pbm}
+
+for fn in "-add" "-subtract" "-multiply" "-divide" "-difference" \
+    "-minimum" "-maximum" "-mean" "-compare" \
+    "-and" "-or" "-nand" "-nor"  "-xor" \
+    "-shiftleft" "-shiftright"
+  do
+  echo ${fn}
+  pamarith ${fn} -plain ${input1_pbm} ${input2_pbm} | tr '\n' ' '; echo
+  done
+
+rm ${input1_pbm} ${input2_pbm}
+
+
+echo "Test 3 (input = output)"
+echo "cksum is 2425386270 41 or 2921940274 59"
+
+for image in testgrid.pbm ${input1_ppm}
+  do
+  echo "input image"
+  cat ${image} | cksum 
+  for fn in "-minimum" "-maximum" "-mean" "-and" "-or"
+    do
+    echo ${fn}
+    pamarith ${fn} ${image} ${image} | cksum
+    done
+  done
+
+
+echo "Test 4 (blank output)"
+echo "cksum is 2817549367 41 or 320101399 59"
+
+for image in testgrid.pbm ${input1_ppm}
+  do
+  for fn in "-subtract" "-difference" "-xor"
+    do
+    echo ${fn}
+    pamarith ${fn} ${image} ${image} | cksum
+    done
+  done
+
+rm ${input1_ppm}
+
+
+echo "Invalid command-line argument combinations." 1>&2
+echo "Error messages should appear below the line." 1>&2
+echo "-----------------------------------------------------------" 1>&2
+
+echo "Test Invalid"
+
+output_ppm=${tmpdir}/output.ppm
+
+pamarith -add -subtract testimg.ppm testimg.ppm > ${output_ppm} || \
+  echo -n "Expected failure 1"
+  test -s ${output_ppm}; echo " "$?
+pamarith -multiply -divide testimg.ppm testimg.ppm > ${output_ppm} || \
+  echo -n "Expected failure 2"
+  test -s ${output_ppm}; echo " "$?
+pamarith -difference -minimum testimg.ppm testimg.ppm > ${output_ppm} || \
+  echo -n "Expected failure 3"
+  test -s ${output_ppm}; echo " "$?
+pamarith -maximum -mean testimg.ppm testimg.ppm > ${output_ppm} || \
+  echo -n "Expected failure 4"
+  test -s ${output_ppm}; echo " "$?
+pamarith -compare -and testimg.ppm testimg.ppm > ${output_ppm} || \
+  echo -n "Expected failure 5"
+  test -s ${output_ppm}; echo " "$?
+pamarith -or -nand testimg.ppm testimg.ppm > ${output_ppm} || \
+  echo -n "Expected failure 6"
+  test -s ${output_ppm}; echo " "$?
+pamarith -nor -xor testimg.ppm testimg.ppm > ${output_ppm} || \
+  echo -n "Expected failure 7"
+  test -s ${output_ppm}; echo " "$?
+pamarith -shiftleft -shiftright testimg.ppm testimg.ppm > ${output_ppm} || \
+  echo -n "Expected failure 8"
+  test -s ${output_ppm}; echo " "$?
+pamarith -add=1 testimg.ppm testimg.ppm > ${output_ppm} || \
+  echo -n "Expected failure 9"
+  test -s ${output_ppm}; echo " "$?
+
+pamarith -plain testimg.ppm testimg.ppm > ${output_ppm} || \
+  echo -n "Expected failure 10"
+  test -s ${output_ppm}; echo " "$?
+
+pamarith testimg.ppm testimg.ppm > ${output_ppm} || \
+  echo -n "Expected failure 11"
+  test -s ${output_ppm}; echo " "$?
+
+pamarith -add testimg.ppm testimg.ppm testimg.ppm > ${output_ppm}
+  echo -n "Expected failure 12"
+  test -s ${output_ppm}; echo " "$?
+pamarith -add testimg.ppm > ${output_ppm}
+  echo -n "Expected failure 13"
+  test -s ${output_ppm}; echo " "$?
+pamarith -add > ${output_ppm}
+  echo -n "Expected failure 14"
+  test -s ${output_ppm}; echo " "$?
+
+pamarith -add testimg.ppm testgrid.pbm > ${output_ppm}
+  echo -n "Expected failure 15"
+  test -s ${output_ppm}; echo " "$?
+
+pamchannel -infile testimg.ppm 0 1 | \
+  pamarith -add testimg.ppm - > ${output_ppm}
+  echo -n "Expected failure 16"
+  test -s ${output_ppm}; echo " "$?
+
+pamenlarge -xscale=2 testgrid.pbm | \
+  pamarith -add testgrid.pbm - > ${output_ppm}
+  echo -n "Expected failure 17"
+  test -s ${output_ppm}; echo " "$?
+
+pamenlarge -yscale=3 testgrid.pbm | \
+  pamarith -add testgrid.pbm - > ${output_ppm}
+  echo -n "Expected failure 18"
+  test -s ${output_ppm}; echo " "$?
+
+rm ${output_ppm}
\ No newline at end of file
diff --git a/test/pambrighten.ok b/test/pambrighten.ok
new file mode 100644
index 00000000..6c58b4c9
--- /dev/null
+++ b/test/pambrighten.ok
@@ -0,0 +1,96 @@
+Test 1
+P3
+8 1
+255
+0 0 0 0 0 100 0 100 0 0 100 100 100 0 0 100 0 100 100 100 0 100 100 100 
+
+P3
+8 1
+255
+0 0 0 0 0 110 0 110 0 0 110 110 110 0 0 110 0 110 110 110 0 110 110 110 
+
+P3
+8 1
+255
+0 0 0 0 0 90 0 90 0 0 90 90 90 0 0 90 0 90 90 90 0 90 90 90 
+
+P3
+8 1
+255
+0 0 0 0 0 200 0 200 0 0 200 200 200 0 0 200 0 200 200 200 0 200 200 200 
+
+P3
+8 1
+255
+0 0 0 0 0 255 0 255 0 0 255 255 255 0 0 255 0 255 255 255 0 255 255 255 
+
+P3
+8 1
+255
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
+
+Test 2
+P3
+8 1
+255
+0 0 0 10 10 100 10 100 10 10 100 100 100 10 10 100 10 100 100 100 10 100 100 100 
+
+P3
+8 1
+255
+0 0 0 100 100 100 100 100 100 100 100 100 100 100 100 100 100 100 100 100 100 100 100 100 
+
+Test 3: Output invariant
+P3
+8 1
+255
+0 0 0 0 0 100 0 100 0 0 100 100 100 0 0 100 0 100 100 100 0 100 100 100 
+
+P3
+8 1
+255
+0 0 0 0 0 100 0 100 0 0 100 100 100 0 0 100 0 100 100 100 0 100 100 100 
+
+P3
+8 1
+255
+0 0 0 0 0 100 0 100 0 0 100 100 100 0 0 100 0 100 100 100 0 100 100 100 
+
+P3
+8 1
+255
+0 0 0 0 0 100 0 100 0 0 100 100 100 0 0 100 0 100 100 100 0 100 100 100 
+
+P3
+8 1
+255
+0 0 0 0 0 100 0 100 0 0 100 100 100 0 0 100 0 100 100 100 0 100 100 100 
+
+P3
+8 1
+255
+0 0 0 0 0 100 0 100 0 0 100 100 100 0 0 100 0 100 100 100 0 100 100 100 
+
+Test 4: Should print 3990234518 268 six times
+3990234518 268
+3990234518 268
+3990234518 268
+3990234518 268
+3990234518 268
+3990234518 268
+Test Error: Should print 1 six times
+1
+1
+1
+1
+1
+1
+Test Error: Should print 99 followed by 1, four times
+99
+1
+99
+1
+99
+1
+99
+1
diff --git a/test/pambrighten.test b/test/pambrighten.test
new file mode 100755
index 00000000..3e1a3eb1
--- /dev/null
+++ b/test/pambrighten.test
@@ -0,0 +1,99 @@
+#! /bin/bash
+# This script tests: pambrighten
+# Also requires: pgmramp
+
+tmpdir=${tmpdir:-/tmp}
+
+input_ppm=${tmpdir}/input.ppm
+
+cat > ${input_ppm} << EOF
+P3
+8 1
+255
+0 0 0 0 0 100 0 100 0 0 100 100 100 0 0 100 0 100 100 100 0 100 100 100 
+EOF
+
+# Test 1
+
+echo "Test 1"
+pambrighten -v   0 -plain ${input_ppm}
+pambrighten -v +10 -plain ${input_ppm}
+pambrighten -v -10 -plain ${input_ppm}
+pambrighten -v +100 -plain ${input_ppm}
+pambrighten -v +200 -plain ${input_ppm}
+pambrighten -v -100 -plain ${input_ppm}
+
+echo "Test 2"
+pambrighten -s -10 -plain ${input_ppm}
+pambrighten -s -100 -plain ${input_ppm}
+
+echo "Test 3: Output invariant"
+pambrighten         -plain ${input_ppm}
+pambrighten -v   0  -plain ${input_ppm}
+pambrighten -s   0  -plain ${input_ppm}
+pambrighten -s +10  -plain ${input_ppm}
+pambrighten -s +100 -plain ${input_ppm}
+pambrighten -s +200 -plain ${input_ppm}
+
+rm ${input_ppm}
+
+echo "Test 4: Should print 3990234518 268 six times"
+
+input_pgm=${tmpdir}/input.pgm
+
+pgmramp -lr 255 1 | tee ${input_pgm} | cksum
+pambrighten -s -100 ${input_pgm} | cksum
+pambrighten -s -10  ${input_pgm} | cksum
+pambrighten -s +10  ${input_pgm} | cksum
+pambrighten -s +100 ${input_pgm} | cksum
+pambrighten -s +200 ${input_pgm} | cksum
+
+rm ${input_pgm}
+
+
+# Test 2
+# These should all fail.
+
+echo "Invalid command-line argument combinations." 1>&2
+echo "Error messages should appear below the line." 1>&2
+echo "-----------------------------------------------------------" 1>&2
+
+echo "Test Error: Should print 1 six times"
+
+output_ppm=${tmpdir}/output.ppm
+
+pambrighten -v -120 testimg.ppm > ${output_ppm}
+echo $?
+test -s ${output_ppm}
+echo $?
+pambrighten -s -120 testimg.ppm > ${output_ppm}
+echo $?
+test -s ${output_ppm}
+echo $?
+pambrighten 10 testimg.ppm > ${output_ppm}
+echo $?
+test -s ${output_ppm}
+echo $?
+
+
+echo "Test Error: Should print 99 followed by 1, four times"
+
+pambrighten -s 1.20 testimg.ppm > ${output_ppm}
+echo $?
+test -s ${output_ppm}
+echo $?
+pambrighten -v 10.5 testimg.ppm > ${output_ppm}
+echo $?
+test -s ${output_ppm}
+echo $?
+pambrighten -v testimg.ppm > ${output_ppm}
+echo $?
+test -s ${output_ppm}
+echo $?
+pambrighten -s testimg.ppm > ${output_ppm}
+echo $?
+test -s ${output_ppm}
+echo $?
+
+
+rm -f ${output_ppm}
diff --git a/test/pamdice.ok b/test/pamdice.ok
index 83db2775..99504ec0 100644
--- a/test/pamdice.ok
+++ b/test/pamdice.ok
@@ -1,5 +1,5 @@
 Test 1.
-     10 P1@1 1@0@
+10 P1@1 1@0@
 Test 2.
 P1@1 1@0@
 P1@1 1@1@
diff --git a/test/pamdice.test b/test/pamdice.test
index 71a9d645..3199fd4a 100755
--- a/test/pamdice.test
+++ b/test/pamdice.test
@@ -12,7 +12,7 @@ pbmmake -w 2 5 | pamdice -height=1 -width=1 -outstem=${fname_stem} -plain
 ls ${fname_stem}*.pbm | while read file
   do
   cat ${file} | tr '\n'  '@' ; echo 
-  done | sort | uniq -c
+  done | sort | uniq -c | sed 's/^ *//'
 
 rm ${fname_stem}*.pbm
 
diff --git a/test/pamexec.ok b/test/pamexec.ok
index 4bfa5202..23e4268e 100644
--- a/test/pamexec.ok
+++ b/test/pamexec.ok
@@ -1,6 +1,6 @@
 Test 1 : Should print 10 stdin: PBM RAW 21 24 1 1 BLACKANDWHITE twice
-     10 stdin: PBM RAW 21 24 1 1 BLACKANDWHITE
-     10 stdin: PBM RAW 21 24 1 1 BLACKANDWHITE
+10 stdin: PBM RAW 21 24 1 1 BLACKANDWHITE
+10 stdin: PBM RAW 21 24 1 1 BLACKANDWHITE
 Test 2: Should print 1791121103 989 twice
 1791121103 989
 1791121103 989
diff --git a/test/pamexec.test b/test/pamexec.test
index acf162c3..44c11339 100755
--- a/test/pamexec.test
+++ b/test/pamexec.test
@@ -11,8 +11,8 @@ cat ${test_pbm}[0123456789] > ${combined_pbm}
 
 echo "Test 1 : Should print 10 stdin: PBM RAW 21 24 1 1 BLACKANDWHITE twice"
 
-cat ${combined_pbm} | pamfile -all -mach | uniq -c 
-pamexec "pamfile -mach" ${combined_pbm}  | uniq -c
+cat ${combined_pbm} | pamfile -all -mach | uniq -c | sed 's/^ *//' 
+pamexec "pamfile -mach" ${combined_pbm}  | uniq -c | sed 's/^ *//' 
 
 echo "Test 2: Should print 1791121103 989 twice"
 
diff --git a/test/pamfunc.ok b/test/pamfunc.ok
new file mode 100644
index 00000000..4a531577
--- /dev/null
+++ b/test/pamfunc.ok
@@ -0,0 +1,70 @@
+Test 1
+P2 16 1 15 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15  
+P2 16 1 15 3 4 5 6 7 8 9 10 11 12 13 14 15 15 15 15  
+P2 16 1 15 0 0 0 0 1 2 3 4 5 6 7 8 9 10 11 12  
+P2 16 1 15 0 3 6 9 12 15 15 15 15 15 15 15 15 15 15 15  
+P2 16 1 15 0 1 1 2 2 3 3 4 4 5 5 6 6 7 7 8  
+P2 16 1 15 0 1 2 3 4 5 6 6 6 6 6 6 6 6 6 6  
+P2 16 1 15 5 5 5 5 5 5 6 7 8 9 10 11 12 13 14 15  
+P2 16 1 15 0 2 4 6 8 10 12 14 0 2 4 6 8 10 12 14  
+P2 16 1 15 0 0 1 1 2 2 3 3 4 4 5 5 6 6 7 7  
+P2 16 1 15 0 1 2 3 4 5 6 7 0 1 2 3 4 5 6 7  
+P2 16 1 15 0 0 2 2 4 4 6 6 8 8 10 10 12 12 14 14  
+Test 2
+P1 8 1 01010101 
+P1 8 1 00000000 
+P1 8 1 11111111 
+P1 8 1 01010101 
+P1 8 1 01010101 
+P1 8 1 01010101 
+P1 8 1 00000000 
+P1 8 1 11111111 
+P1 8 1 11111111 
+P1 8 1 11111111 
+P1 8 1 11111111 
+Test 3 (-changemaxval)
+P2 16 1 30 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15  
+P2 16 1 60 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15  
+P1 8 1 01010101 
+P1 8 1 11111111 
+Test 4: Should print 1926073387 101484 eight times
+1926073387 101484
+1926073387 101484
+1926073387 101484
+1926073387 101484
+1926073387 101484
+1926073387 101484
+1926073387 101484
+1926073387 101484
+Test 5: Should print 2425386270 41 six times
+2425386270 41
+2425386270 41
+2425386270 41
+2425386270 41
+2425386270 41
+2425386270 41
+Test Invalid
+Expected failure 1 1
+Expected failure 2 1
+Expected failure 3 1
+Expected failure 4 1
+Expected failure 5 1
+Expected failure 6 1
+Expected failure 7 1
+Expected failure 8 1
+Expected failure 9 1
+Expected failure 10 1
+Expected failure 11 1
+Expected failure 12 1
+Expected failure 13 1
+Expected failure 14 1
+Expected failure 15 1
+Expected failure 16 1
+Expected failure 17 1
+Expected failure 18 1
+Expected failure 19 1
+Expected failure 20 1
+Expected failure 21 1
+Expected failure 22 1
+Expected failure 23 1
+Expected failure 24 1
diff --git a/test/pamfunc.test b/test/pamfunc.test
new file mode 100755
index 00000000..f9a8a33e
--- /dev/null
+++ b/test/pamfunc.test
@@ -0,0 +1,166 @@
+#! /bin/bash
+# This script tests: pamfunc
+# Also requires: pamseq pamtopnm pbmmake
+
+tmpdir=${tmpdir:-/tmp}
+input_pgm=${tmpdir}/input.pgm
+
+echo "Test 1"  
+
+pamseq 1 15 | pamtopnm -assume > ${input_pgm}
+pamtopnm -plain ${input_pgm} | tr '\n' ' '; echo
+
+pamfunc -adder=3 -plain ${input_pgm} | tr '\n' ' '; echo
+pamfunc -subtractor=3 -plain ${input_pgm} | tr '\n' ' '; echo
+pamfunc -multiplier=3 -plain ${input_pgm} | tr '\n' ' '; echo
+pamfunc -divisor=2 -plain ${input_pgm} | tr '\n' ' '; echo
+pamfunc -max=6 -plain ${input_pgm} | tr '\n' ' '; echo
+pamfunc -min=5 -plain ${input_pgm} | tr '\n' ' '; echo
+
+pamfunc -shiftleft  1  -plain ${input_pgm} | tr '\n' ' '; echo
+pamfunc -shiftright 1  -plain ${input_pgm} | tr '\n' ' '; echo
+pamfunc -shiftleft  1 ${input_pgm} | pamfunc -shiftright 1 -plain | \
+  tr '\n' ' '; echo
+pamfunc -shiftright 1 ${input_pgm} | pamfunc -shiftleft 1  -plain | \
+  tr '\n' ' '; echo
+
+
+input_pbm=${tmpdir}/input.pbm
+
+echo "Test 2"
+
+pbmmake -g 8 1 > ${input_pbm}
+pamtopnm -plain ${input_pbm} | tr '\n' ' '; echo
+
+pamfunc -adder=1 -plain ${input_pbm} | tr '\n' ' '; echo
+pamfunc -subtractor=1 -plain ${input_pbm} | tr '\n' ' '; echo
+pamfunc -multiplier=1 -plain ${input_pbm} | tr '\n' ' '; echo
+pamfunc -divisor=1 -plain ${input_pbm} | tr '\n' ' '; echo
+pamfunc -max=1 -plain ${input_pbm} | tr '\n' ' '; echo
+pamfunc -min=1 -plain ${input_pbm} | tr '\n' ' '; echo
+
+pamfunc -shiftleft  1  -plain ${input_pbm} | tr '\n' ' '; echo
+pamfunc -shiftright 1  -plain ${input_pbm} | tr '\n' ' '; echo
+pamfunc -shiftleft  1 ${input_pbm} | pamfunc -shiftright 1 -plain | \
+  tr '\n' ' '; echo
+pamfunc -shiftright 1 ${input_pbm} | pamfunc -shiftleft 1  -plain | \
+  tr '\n' ' '; echo
+
+
+echo "Test 3 (-changemaxval)"
+
+pamfunc -divisor 2 -changemaxval ${input_pgm} -plain | \
+  tr '\n' ' '; echo
+pamfunc -multiplier 0.25 -changemaxval ${input_pgm} -plain | \
+  tr '\n' ' '; echo
+pamfunc -divisor 2 -changemaxval ${input_pbm} -plain | \
+  tr '\n' ' '; echo
+pamfunc -multiplier 0.25 -changemaxval ${input_pbm} -plain | \
+  tr '\n' ' '; echo
+
+rm ${input_pgm} ${input_pbm}
+
+echo "Test 4: Should print 1926073387 101484 eight times"
+
+cat testimg.ppm | cksum
+
+pamfunc -not testimg.ppm | pamfunc -not | cksum
+pamfunc -andmask 0xff testimg.ppm | cksum
+pamfunc -ormask  0x00 testimg.ppm | cksum
+pamfunc -xormask 0x00 testimg.ppm | cksum
+pamfunc -xormask 0xff testimg.ppm | pamfunc -xormask 0xff | cksum
+pamfunc -shiftleft  0 testimg.ppm | cksum
+pamfunc -shiftright 0 testimg.ppm | cksum
+
+
+echo "Test 5: Should print 2425386270 41 six times"
+
+cat testgrid.pbm | cksum
+
+pamfunc -andmask  0x1 testgrid.pbm | cksum
+pamfunc -ormask   0x0 testgrid.pbm | cksum
+pamfunc -xormask  0x1 testgrid.pbm | pamfunc -xormask 0x1 | cksum
+
+pamfunc -shiftleft  0 testgrid.pbm | cksum
+pamfunc -shiftright 0 testgrid.pbm | cksum
+
+echo "Invalid command-line argument combinations." 1>&2
+echo "Error messages should appear below the line." 1>&2
+echo "-----------------------------------------------------------" 1>&2
+
+echo "Test Invalid"
+
+output_ppm=${tmpdir}/output.ppm
+
+pamfunc -multiplier testimg.ppm > ${output_ppm} || \
+  echo -n "Expected failure 1"
+  test -s ${output_ppm}; echo " "$?
+pamfunc -multiplier=-1 testimg.ppm > ${output_ppm} || \
+  echo -n "Expected failure 2"
+  test -s ${output_ppm}; echo " "$?
+pamfunc -divisor testimg.ppm > ${output_ppm} || \
+  echo -n "Expected failure 3"
+  test -s ${output_ppm}; echo " "$?
+pamfunc -divisor=-20 testimg.ppm > ${output_ppm} || \
+  echo -n "Expected failure 4"
+  test -s ${output_ppm}; echo " "$?
+pamfunc -adder testimg.ppm > ${output_ppm} || \
+  echo -n "Expected failure 5"
+  test -s ${output_ppm}; echo " "$?
+pamfunc -adder 0.5 testimg.ppm > ${output_ppm} || \
+  echo -n "Expected failure 6"
+  test -s ${output_ppm}; echo " "$?
+pamfunc -subtractor testimg.ppm > ${output_ppm} || \
+  echo -n "Expected failure 7"
+  test -s ${output_ppm}; echo " "$?
+pamfunc -subtractor 0.1 testimg.ppm > ${output_ppm} || \
+  echo -n "Expected failure 8"
+  test -s ${output_ppm}; echo " "$?
+pamfunc -multiplier=1 -divisor=2 testimg.ppm > ${output_ppm} || \
+  echo -n "Expected failure 9"
+  test -s ${output_ppm}; echo " "$?
+pamfunc -adder=2 -subtractor=3 testimg.ppm > ${output_ppm} || \
+  echo -n "Expected failure 10"
+  test -s ${output_ppm}; echo " "$?
+pamfunc -min testimg.ppm > ${output_ppm} || \
+  echo -n "Expected failure 11"
+  test -s ${output_ppm}; echo " "$?
+pamfunc -max testimg.ppm > ${output_ppm} || \
+  echo -n "Expected failure 12"
+  test -s ${output_ppm}; echo " "$?
+pamfunc -andmask testimg.ppm > ${output_ppm} || \
+  echo -n "Expected failure 13"
+  test -s ${output_ppm}; echo " "$?
+pamfunc -ormask testimg.ppm > ${output_ppm} || \
+  echo -n "Expected failure 14"
+  test -s ${output_ppm}; echo " "$?
+pamfunc -xormask testimg.ppm > ${output_ppm} || \
+  echo -n "Expected failure 15"
+  test -s ${output_ppm}; echo " "$?
+pamfunc -not 1 testimg.ppm > ${output_ppm} || \
+  echo -n "Expected failure 16"
+  test -s ${output_ppm}; echo " "$?
+pamfunc -min=1 -max=2 testimg.ppm > ${output_ppm} || \
+  echo -n "Expected failure 17"
+  test -s ${output_ppm}; echo " "$?
+pamfunc -andmask=1 -ormask=0 testimg.ppm > ${output_ppm} || \
+  echo -n "Expected failure 18"
+  test -s ${output_ppm}; echo " "$?
+pamfunc -andmask=0xffff testimg.ppm > ${output_ppm} || \
+  echo -n "Expected failure 19"
+  test -s ${output_ppm}; echo " "$?
+pamfunc -shiftleft testimg.ppm > ${output_ppm} || \
+  echo -n "Expected failure 20"
+  test -s ${output_ppm}; echo " "$?
+pamfunc -shiftright testimg.ppm > ${output_ppm} || \
+  echo -n "Expected failure 21"
+  test -s ${output_ppm}; echo " "$?
+pamfunc -changemaxval testimg.ppm > ${output_ppm} || \
+  echo -n "Expected failure 22"
+  test -s ${output_ppm}; echo " "$?
+pamfunc -shiftleft=1 -shiftright=1 testimg.ppm > ${output_ppm} || \
+  echo -n "Expected failure 23"
+  test -s ${output_ppm}; echo " "$?
+pamfunc -multiplier=0.5 -changemaxval=65535 testimg.ppm > ${output_ppm} || \
+  echo -n "Expected failure 24"
+  test -s ${output_ppm}; echo " "$?
diff --git a/test/pamtopdbimg.test b/test/pamtopdbimg.test
index 8de78a70..9afee8f1 100755
--- a/test/pamtopdbimg.test
+++ b/test/pamtopdbimg.test
@@ -21,7 +21,7 @@ echo high compression
 pgmmake 0.5 -maxval=15 160 160 > ${mono_pgm}
 for flag in "-compressed" "-maybecompressed" "-uncompressed"
    do
-   pamtopdbimg $flag ${mono_pgm} | wc -c
+   pamtopdbimg $flag ${mono_pgm} | wc -c | tr -d ' '
    done  | uniq -c | awk '{print $1}'
 rm ${mono_pgm}
 
diff --git a/test/pamvalidate.test b/test/pamvalidate.test
index 46dd1bfa..4cabc7df 100755
--- a/test/pamvalidate.test
+++ b/test/pamvalidate.test
@@ -6,12 +6,15 @@ echo "valid"
 echo -e "P1\n5 5\n01010\n10101\n01010\n00000\n11111\n" | pamvalidate -plain
 
 echo "not valid: Should print 0 four times"
-echo -e "P1\n5 5\n01010\n10101\n01010\n00000\n1111\n"  | pamvalidate | wc -c
+echo -e "P1\n5 5\n01010\n10101\n01010\n00000\n1111\n"  | pamvalidate | \
+  wc -c | tr -d ' '
 
-echo -e "P1\n5 5\n01010\n10102\n01010\n00001\n11111\n" | pamvalidate | wc -c
+echo -e "P1\n5 5\n01010\n10102\n01010\n00001\n11111\n" | pamvalidate | \
+  wc -c | tr -d ' '
 
-echo -e "P1\n5\n01010\n10101\n01010\n00000\n11111\n" | pamvalidate | wc -c
+echo -e "P1\n5\n01010\n10101\n01010\n00000\n11111\n" | pamvalidate | \
+  wc -c | tr -d ' '
 
-echo -e "P1\n5 5" | pamvalidate | wc -c
+echo -e "P1\n5 5" | pamvalidate | wc -c | tr -d ' '
 
 
diff --git a/test/pbmtext-utf8.test b/test/pbmtext-utf8.test
index 1db7d849..8ebb6e31 100755
--- a/test/pbmtext-utf8.test
+++ b/test/pbmtext-utf8.test
@@ -125,7 +125,7 @@ long_txt=${tmpdir}/long.txt
 test_out=${tmpdir}/test_out
 
 head -c 4999 /dev/zero | sed 's@\x00@\xc2\xbe@g' > ${long_txt}
-cat ${long_txt} | wc -c
+cat ${long_txt} | wc -c | tr -d ' '
 
 cat ${long_txt} | \
   LC_ALL=${locale_for_test} pbmtext -nomargins -builtin fixed -wchar | cksum
@@ -136,7 +136,7 @@ echo "Error messages should appear below the line." 1>&2
 echo "-----------------------------------------------------------" 1>&2
 
 echo -n "z" >> ${long_txt}
-cat ${long_txt} | wc -c
+cat ${long_txt} | wc -c | tr -d ' '
 
 cat ${long_txt} | \
   LC_ALL=${locale_for_test} \
diff --git a/test/pj-roundtrip.ok b/test/pj-roundtrip.ok
index a13b01a7..195443ba 100644
--- a/test/pj-roundtrip.ok
+++ b/test/pj-roundtrip.ok
@@ -1,4 +1,4 @@
 Test 1. Should print:  0 0 0 0 : 0
 0 0 0 0 : 0
-Test 2. Should print:  0 0 0 0 0 : 0
-0 0 0 0 0 : 0
+Test 2. Should print:  0 0 : 0
+0 0 : 0
diff --git a/test/pj-roundtrip.test b/test/pj-roundtrip.test
index 3394a4d2..2b0d61e5 100755
--- a/test/pj-roundtrip.test
+++ b/test/pj-roundtrip.test
@@ -1,6 +1,6 @@
 #! /bin/bash
 # This script tests: ppmtopj pjtoppm
-# Also requires: pamseq pnmremap pamtopnm pamdepth ppmtopgm pgmtopbm
+# Also requires: pamseq pnmremap pamtopnm pamdepth ppmtoppm
 
 echo "Test 1. Should print:  0 0 0 0 : 0"
 
@@ -15,8 +15,12 @@ ppmtopj ${test8_ppm} | pjtoppm | pamdepth 1 | \
 
 rm ${test8_ppm}
 
-echo "Test 2. Should print:  0 0 0 0 0 : 0"
+echo "Test 2. Should print:  0 0 : 0"
 
-ppmtopj testgrid.pbm | pjtoppm | ppmtopgm | pgmtopbm | \
-  cmp -s - testgrid.pbm > /dev/null
+testout_ppm=${tmpdir}/testout.ppm
+
+ppmtopj testgrid.pbm | pjtoppm > ${testout_ppm}
+  ppmtoppm < testgrid.pbm | cmp -s - ${testout_ppm} > /dev/null
   echo ${PIPESTATUS[@]} ":" $?
+
+rm ${testout_ppm}
diff --git a/test/ppmbrighten.ok b/test/ppmbrighten.ok
index 376e71d3..3895dbd0 100644
--- a/test/ppmbrighten.ok
+++ b/test/ppmbrighten.ok
@@ -1,3 +1,11 @@
+Test 1: Should print 1969633344 101484
 1969633344 101484
-3688219243 101484
+Test 2: Should print 295150171 101484
 295150171 101484
+Test 3: Should print 1
+1
+Test Error: Should print 1 four times
+1
+1
+1
+1
diff --git a/test/ppmbrighten.test b/test/ppmbrighten.test
index 46c5cab5..40fe08f6 100755
--- a/test/ppmbrighten.test
+++ b/test/ppmbrighten.test
@@ -1,12 +1,38 @@
 #! /bin/bash
 # This script tests: ppmbrighten
-# Also requires:
+# Also requires: pnmnorm pambrighten pamsumm 
 
 # Failure message
 ## Ppmbrighten is sensitive to subtle differences in floating point math.
 ## If this test fails, please run the program and visually examine
 ## the output.
 
+echo "Test 1: Should print 1969633344 101484"
+
 ppmbrighten -v 100 testimg.ppm | cksum
-ppmbrighten -v 100 -normalize testimg.ppm | cksum
+
+echo "Test 2: Should print 295150171 101484"
+
 ppmbrighten -s 100 -v -50 testimg.ppm | cksum
+
+echo "Test 3: Should print 1"
+
+ppmbrighten -v 100 -normalize testimg.ppm | pamsumm --mean | \
+ awk '{print ($NF > 132.0) && ($NF < 132.2)}'
+
+echo "Invalid command-line argument combinations." 1>&2
+echo "Error messages should appear below the line." 1>&2
+echo "-----------------------------------------------------------" 1>&2
+
+echo "Test Error: Should print 1 four times"
+
+output_ppm=${tmpdir}/output.ppm
+
+pambrighten -v -120 testimg.ppm > ${output_ppm}
+echo $?
+test -s ${output_ppm}
+echo $?
+pambrighten -s -120 testimg.ppm > ${output_ppm}
+echo $?
+test -s ${output_ppm}
+echo $?
diff --git a/test/winicon-roundtrip.ok b/test/winicon-roundtrip.ok
index 8334ff4e..4ba2606e 100644
--- a/test/winicon-roundtrip.ok
+++ b/test/winicon-roundtrip.ok
@@ -1,2 +1,12 @@
-71846281 6925
-326197919 137
+Test 1. Should print 4241318573 6973 four times
+4241318573 6973
+4241318573 6973
+4241318573 6973
+4241318573 6973
+Test 1. Should print 819454437 1093 six times
+819454437 1093
+819454437 1093
+819454437 1093
+819454437 1093
+819454437 1093
+819454437 1093
diff --git a/test/winicon-roundtrip.test b/test/winicon-roundtrip.test
index b37a33e1..00c78400 100755
--- a/test/winicon-roundtrip.test
+++ b/test/winicon-roundtrip.test
@@ -1,13 +1,37 @@
 #! /bin/bash
-# This script tests: pamtowinicon winicontopam
-# Also requires: pamcut pnmtile pamtopnm ppmtopgm pgmtopbm
+# This script tests: pamtowinicon ppmtowinicon winicontopam
+# Also requires: pamchannel pamcut pamdepth pamtopam pngtopam pnmtile pnmtopng
 
+tmpdir=${tmpdir:-/tmp}
+test_pam=${tmpdir}/testimg.pam
 
-pamcut --left=30 --width=48 --height=48 testimg.ppm | \
-pamtowinicon | winicontopam | \
-  pamtopnm | cksum
+echo "Test 1. Should print 4241318573 6973 four times"
 
-pnmtile 32 32 testgrid.pbm | \
-pamtowinicon | winicontopam | \
-  pamtopnm | ppmtopgm | \
-  pgmtopbm  -th -val=0.5 | cksum
+pamcut --left=30 --width=48 --height=48 testimg.ppm | pamtopam | \
+  tee ${test_pam} | cksum
+pamtowinicon ${test_pam} | winicontopam | \
+  pamchannel -tupletype="RGB" 0 1 2 | cksum
+pamtowinicon -pngthreshold=300 ${test_pam} | winicontopam | \
+  pamchannel -tupletype="RGB" 0 1 2 | cksum
+pamtowinicon -pngthreshold=1   ${test_pam} | winicontopam | \
+  pamchannel -tupletype="RGB" 0 1 2 | cksum
+
+rm ${test_pam}
+
+echo "Test 1. Should print 819454437 1093 six times"
+
+pnmtile 32 32 testgrid.pbm | pamtopam | \
+  tee ${test_pam} | cksum
+pamtowinicon ${test_pam} | winicontopam | \
+  pamdepth 1 | pamchannel -tupletype="BLACKANDWHITE" 0 | cksum
+pamtowinicon -pngthreshold=300 ${test_pam} | winicontopam | \
+  pamdepth 1 | pamchannel -tupletype="BLACKANDWHITE" 0 | cksum
+pamtowinicon -pngthreshold=1   ${test_pam} | winicontopam | 
+  pamdepth 1 | pamchannel -tupletype="BLACKANDWHITE" 0 | cksum
+pamtowinicon -pngthreshold=1   ${test_pam} | winicontopam | 
+  pamchannel -tupletype="BLACKANDWHITE" 0 | cksum
+
+rm ${test_pam}
+
+pnmtile 32 32 testgrid.pbm | ppmtowinicon | winicontopam | \
+  pamdepth 1 | pamchannel -tupletype="BLACKANDWHITE" 0 | cksum
diff --git a/test/winicon-roundtrip2.ok b/test/winicon-roundtrip2.ok
new file mode 100644
index 00000000..bb8c77d8
--- /dev/null
+++ b/test/winicon-roundtrip2.ok
@@ -0,0 +1,80 @@
+16 24 32 48 64 : 1 plane
+Should print 2588356089 8591 or 3783949470 69390 four times
+2588356089 8591
+2588356089 8591
+2588356089 8591
+2588356089 8591
+16 24 32 48 64 : 2 planes
+Should print 3357739334 16877 or 3331485515 138534 four times
+3357739334 16877
+3357739334 16877
+3357739334 16877
+3357739334 16877
+16 24 32 48 64 : 3 planes
+Should print 3734212737 25073 or 56221695 207606 four times
+3734212737 25073
+3734212737 25073
+3734212737 25073
+3734212737 25073
+16 24 32 48 64 : 4 planes
+Should print 1294260080 33359 or 732184466 276750 four times
+1294260080 33359
+1294260080 33359
+1294260080 33359
+1294260080 33359
+16 24 32 48 64 : 5 planes: output 3
+Should print 3734212737 25073 or 56221695 207606 four times
+3734212737 25073
+3734212737 25073
+3734212737 25073
+3734212737 25073
+16 24 32 48 64 : 5 planes : output 4
+Should print 2704877198 33359 or 1699833476 276750 four times
+2704877198 33359
+2704877198 33359
+2704877198 33359
+2704877198 33359
+16 24 32 48 64 : 5 planes : output 5
+Should print 2567279592 41655 or 4154838752 345902 twice
+2567279592 41655
+2567279592 41655
+16 32 48 256 : 1 plane
+Should print 2588356089 8591 or 3783949470 69390 four times
+3783949470 69390
+3783949470 69390
+3783949470 69390
+3783949470 69390
+16 32 48 256 : 2 planes
+Should print 3357739334 16877 or 3331485515 138534 four times
+3331485515 138534
+3331485515 138534
+3331485515 138534
+3331485515 138534
+16 32 48 256 : 3 planes
+Should print 3734212737 25073 or 56221695 207606 four times
+56221695 207606
+56221695 207606
+56221695 207606
+56221695 207606
+16 32 48 256 : 4 planes
+Should print 1294260080 33359 or 732184466 276750 four times
+732184466 276750
+732184466 276750
+732184466 276750
+732184466 276750
+16 32 48 256 : 5 planes: output 3
+Should print 3734212737 25073 or 56221695 207606 four times
+56221695 207606
+56221695 207606
+56221695 207606
+56221695 207606
+16 32 48 256 : 5 planes : output 4
+Should print 2704877198 33359 or 1699833476 276750 four times
+1699833476 276750
+1699833476 276750
+1699833476 276750
+1699833476 276750
+16 32 48 256 : 5 planes : output 5
+Should print 2567279592 41655 or 4154838752 345902 twice
+4154838752 345902
+4154838752 345902
diff --git a/test/winicon-roundtrip2.test b/test/winicon-roundtrip2.test
new file mode 100755
index 00000000..ec074055
--- /dev/null
+++ b/test/winicon-roundtrip2.test
@@ -0,0 +1,150 @@
+#! /bin/bash
+# This script tests: pamtowinicon winicontopam
+# Also requires: pamchannel pamdepth pamstack pamtopam pbmmake pngtopam
+# Also requires: pnmtopng ppmpat
+
+tmpdir=${tmpdir:-/tmp}
+test_pam=${tmpdir}/testimg.pam
+test1_pam=${tmpdir}/testimg1.pam
+test2_pam=${tmpdir}/testimg2.pam
+#test3_pam=${tmpdir}/testimg3.pam
+test4_pam=${tmpdir}/testimg4.pam
+test5_pam=${tmpdir}/testimg5.pam
+black_pam=${tmpdir}/black.pam
+white_pam=${tmpdir}/white.pam
+gray_pam=${tmpdir}/gray.pam
+
+# classic: 16 24 32 48 64
+# full: 16 32 48 256
+
+for sizes in "16 24 32 48 64" "16 32 48 256"
+  do
+
+  for size in ${sizes}
+    do
+    ppmpat -tartan -color=rgb:1f/1f/1f,rgb:7f/ff/00,rgb:00/ff/3f \
+      ${size} ${size}
+    done | pamtopam > ${test_pam}
+
+  for size in ${sizes}
+    do
+    pbmmake -black ${size} ${size} | pamdepth 255
+    done | pamtopam > ${black_pam}
+
+  for size in ${sizes}
+    do
+    pbmmake -white ${size} ${size} | pamdepth 255
+    done | pamtopam > ${white_pam}
+
+  for size in ${sizes}
+    do
+    pbmmake -gray ${size} ${size} | pamdepth 255
+    done | pamtopam > ${gray_pam}
+
+# 1 plane
+
+  echo ${sizes} ": 1 plane"
+  echo "Should print 2588356089 8591 or 3783949470 69390 four times"
+
+  pamchannel -tupletype="GRAYSCALE" 0 < ${test_pam} | \
+    tee ${test1_pam} | cksum
+  pamtowinicon ${test1_pam} | winicontopam -allimages | \
+    pamchannel -tupletype="GRAYSCALE" 0 | cksum
+  pamtowinicon -pngthreshold=300 ${test1_pam} | winicontopam -allimages | \
+    pamchannel -tupletype="GRAYSCALE" 0 | cksum
+  pamtowinicon -pngthreshold=1   ${test1_pam} | winicontopam -allimages | \
+    pamchannel -tupletype="GRAYSCALE" 0 | cksum
+
+  rm ${test1_pam}
+
+# 2 planes
+
+  echo ${sizes} ": 2 planes"
+  echo "Should print 3357739334 16877 or 3331485515 138534 four times"
+
+  pamstack ${gray_pam} ${gray_pam} | \
+  pamchannel -tupletype="GRAYSCALE_ALPHA" 0 1 | tee ${test2_pam} | cksum
+  pamtowinicon ${test2_pam} | winicontopam -allimages | \
+    pamchannel -tupletype="GRAYSCALE_ALPHA" 0 1 | cksum
+  pamtowinicon -pngthreshold=300 ${test2_pam} | winicontopam -allimages | \
+    pamchannel -tupletype="GRAYSCALE_ALPHA" 0 1 | cksum
+  pamtowinicon -pngthreshold=1   ${test2_pam} | winicontopam -allimages | \
+    pamchannel -tupletype="GRAYSCALE_ALPHA" 0 1 | cksum
+
+  rm ${test2_pam}
+
+# 3 planes
+
+  echo ${sizes} ": 3 planes"
+  echo "Should print 3734212737 25073 or 56221695 207606 four times"
+
+  pamchannel -tupletype="RGB" 0 1 2 < ${test_pam} | cksum
+  pamtowinicon ${test_pam} | winicontopam -allimages | \
+    pamchannel -tupletype="RGB" 0 1 2 | cksum
+  pamtowinicon -pngthreshold=300 ${test_pam} | winicontopam -allimages | \
+    pamchannel -tupletype="RGB" 0 1 2 | cksum
+  pamtowinicon -pngthreshold=1   ${test_pam} | winicontopam -allimages | \
+    pamchannel -tupletype="RGB" 0 1 2 | cksum
+  
+# 4 planes
+
+  echo ${sizes} ": 4 planes"
+  echo "Should print 1294260080 33359 or 732184466 276750 four times"
+
+  pamdepth 255 ${black_pam} | pamstack ${test_pam} - | \
+  pamchannel -tupletype="RGB_ALPHA" 0 1 2 3 | tee ${test4_pam} | cksum
+  pamtowinicon ${test4_pam} | winicontopam -allimages | \
+    pamchannel -tupletype="RGB_ALPHA" 0 1 2 3 | cksum
+  pamtowinicon -pngthreshold=300 ${test4_pam} | winicontopam -allimages | \
+    pamchannel -tupletype="RGB_ALPHA" 0 1 2 3 | cksum
+  pamtowinicon -pngthreshold=1   ${test4_pam} | winicontopam -allimages | \
+    pamchannel -tupletype="RGB_ALPHA" 0 1 2 3 | cksum
+
+  rm ${test4_pam}
+
+# 5 planes
+
+  echo ${sizes} ": 5 planes: output 3"
+  echo "Should print 3734212737 25073 or 56221695 207606 four times"
+
+  pamstack ${test_pam} ${gray_pam} ${white_pam} | \
+  pamchannel -tupletype="RGB" 0 1 2 | \
+    tee ${test5_pam} | cksum
+  pamtowinicon ${test5_pam} | winicontopam -allimages -andmasks | \
+    pamchannel -tupletype="RGB" 0 1 2 | cksum
+  pamtowinicon -pngthreshold=300 ${test5_pam} | \
+    winicontopam -allimages -andmasks | \
+    pamchannel -tupletype="RGB" 0 1 2 | cksum
+  pamtowinicon -pngthreshold=1   ${test5_pam} | \
+    winicontopam -allimages -andmasks | \
+    pamchannel -tupletype="RGB" 0 1 2 | cksum
+    
+  echo ${sizes} ": 5 planes : output 4"
+  echo "Should print 2704877198 33359 or 1699833476 276750 four times"
+
+  pamstack ${test_pam} ${gray_pam} ${white_pam} | \
+  pamchannel -tupletype="RGB_ALPHA" 0 1 2 3 | \
+    tee ${test5_pam} | cksum
+  pamtowinicon ${test5_pam} | winicontopam -allimages -andmasks | \
+    pamchannel -tupletype="RGB_ALPHA" 0 1 2 3 | cksum
+  pamtowinicon -pngthreshold=300 ${test5_pam} | \
+    winicontopam -allimages -andmasks  | \
+    pamchannel -tupletype="RGB_ALPHA" 0 1 2 3 | cksum
+  pamtowinicon -pngthreshold=1   ${test5_pam} | \
+    winicontopam -allimages -andmasks | \
+    pamchannel -tupletype="RGB_ALPHA" 0 1 2 3 | cksum
+    
+  echo ${sizes} ": 5 planes : output 5"
+  echo "Should print 2567279592 41655 or 4154838752 345902 twice"
+
+  pamstack ${test_pam} ${gray_pam} ${white_pam} | \
+  pamchannel -tupletype="RGB_ALPHA_ANDMASK" 0 1 2 3 4 | \
+    tee ${test5_pam} | cksum
+  pamtowinicon -pngthreshold=300 ${test5_pam} | \
+    winicontopam -allimages -andmasks  | \
+    pamchannel -tupletype="RGB_ALPHA_ANDMASK" 0 1 2 3 4 | cksum
+    
+  rm ${test5_pam}
+
+  rm ${test_pam} ${gray_pam} ${white_pam} ${black_pam}
+done
diff --git a/version.mk b/version.mk
index 83e0f9d1..afa232e7 100644
--- a/version.mk
+++ b/version.mk
@@ -1,3 +1,3 @@
 NETPBM_MAJOR_RELEASE = 10
-NETPBM_MINOR_RELEASE = 91
-NETPBM_POINT_RELEASE = 4
+NETPBM_MINOR_RELEASE = 92
+NETPBM_POINT_RELEASE = 0