about summary refs log tree commit diff
path: root/converter/other
diff options
context:
space:
mode:
Diffstat (limited to 'converter/other')
-rw-r--r--converter/other/Makefile204
-rwxr-xr-xconverter/other/anytopnm7
-rw-r--r--converter/other/avstopam.c103
-rw-r--r--converter/other/bmepsoe.c560
-rw-r--r--converter/other/bmepsoe.h79
-rw-r--r--converter/other/bmptopnm.c363
-rw-r--r--converter/other/cameratopam/Makefile22
-rw-r--r--converter/other/cameratopam/camera.c375
-rw-r--r--converter/other/cameratopam/camera.h95
-rw-r--r--converter/other/cameratopam/cameratopam.c1237
-rw-r--r--converter/other/cameratopam/cameratopam.h6
-rw-r--r--converter/other/cameratopam/canon.c6
-rw-r--r--converter/other/cameratopam/canon.h11
-rw-r--r--converter/other/cameratopam/dng.c151
-rw-r--r--converter/other/cameratopam/dng.h4
-rw-r--r--converter/other/cameratopam/foveon.c37
-rw-r--r--converter/other/cameratopam/foveon.h13
-rw-r--r--converter/other/cameratopam/global_variables.h1
-rw-r--r--converter/other/cameratopam/identify.c2256
-rw-r--r--converter/other/cameratopam/identify.h4
-rw-r--r--converter/other/cameratopam/ljpeg.c238
-rw-r--r--converter/other/cameratopam/ljpeg.h14
-rw-r--r--converter/other/exif.c1216
-rw-r--r--converter/other/exif.h24
-rw-r--r--converter/other/fiasco/Makefile16
-rw-r--r--converter/other/fiasco/binerror.c8
-rw-r--r--converter/other/fiasco/codec/approx.c4
-rw-r--r--converter/other/fiasco/codec/coder.c161
-rw-r--r--converter/other/fiasco/codec/control.c6
-rw-r--r--converter/other/fiasco/codec/decoder.c1809
-rw-r--r--converter/other/fiasco/codec/dfiasco.c8
-rw-r--r--converter/other/fiasco/codec/domain-pool.c16
-rw-r--r--converter/other/fiasco/codec/ip.c4
-rw-r--r--converter/other/fiasco/codec/motion.c12
-rw-r--r--converter/other/fiasco/codec/mwfa.c17
-rw-r--r--converter/other/fiasco/codec/options.c7
-rw-r--r--converter/other/fiasco/codec/prediction.c6
-rw-r--r--converter/other/fiasco/codec/subdivide.c56
-rw-r--r--converter/other/fiasco/codec/tiling.c80
-rw-r--r--converter/other/fiasco/codec/wfa.h4
-rw-r--r--converter/other/fiasco/codec/wfalib.c11
-rw-r--r--converter/other/fiasco/config.h3
-rw-r--r--converter/other/fiasco/display.c15
-rw-r--r--converter/other/fiasco/fiascotopnm.c10
-rw-r--r--converter/other/fiasco/getopt.c10
-rw-r--r--converter/other/fiasco/input/basis.c2
-rw-r--r--converter/other/fiasco/input/read.c8
-rw-r--r--converter/other/fiasco/input/weights.c204
-rw-r--r--converter/other/fiasco/lib/arith.c4
-rw-r--r--converter/other/fiasco/lib/bit-io.c6
-rw-r--r--converter/other/fiasco/lib/dither.c32
-rw-r--r--converter/other/fiasco/lib/error.c39
-rw-r--r--converter/other/fiasco/lib/image.c6
-rw-r--r--converter/other/fiasco/lib/list.c6
-rw-r--r--converter/other/fiasco/lib/macros.h11
-rw-r--r--converter/other/fiasco/lib/misc.c33
-rw-r--r--converter/other/fiasco/lib/misc.h4
-rw-r--r--converter/other/fiasco/output/matrices.c8
-rw-r--r--converter/other/fiasco/output/weights.c293
-rw-r--r--converter/other/fiasco/params.c151
-rw-r--r--converter/other/fiasco/pnmtofiasco.c418
-rw-r--r--converter/other/fitstopnm.c203
-rw-r--r--converter/other/giftopnm.c1639
-rw-r--r--converter/other/hdifftopam.c4
-rw-r--r--converter/other/infotopam.c70
-rw-r--r--converter/other/ipdb.c384
-rw-r--r--converter/other/ipdb.h243
-rw-r--r--converter/other/jbig/ANNOUNCE243
-rw-r--r--converter/other/jbig/Makefile39
-rw-r--r--converter/other/jbig/README20
-rw-r--r--converter/other/jbig/README.Netpbm12
-rw-r--r--converter/other/jbig/jbig_tab.c428
-rw-r--r--converter/other/jbig/jbigtopnm.c2
-rw-r--r--converter/other/jbig/libjbig/ANNOUNCE172
-rw-r--r--converter/other/jbig/libjbig/COPYING339
-rw-r--r--converter/other/jbig/libjbig/Makefile24
-rw-r--r--converter/other/jbig/libjbig/include/jbig.h (renamed from converter/other/jbig/jbig.h)126
-rw-r--r--converter/other/jbig/libjbig/include/jbig_ar.h53
-rw-r--r--converter/other/jbig/libjbig/jbig.c (renamed from converter/other/jbig/jbig.c)1842
-rw-r--r--converter/other/jbig/libjbig/jbig.txt (renamed from converter/other/jbig/jbig.doc)409
-rw-r--r--converter/other/jbig/libjbig/jbig_ar.c417
-rw-r--r--converter/other/jbig/pnmtojbig.c2
-rw-r--r--converter/other/jpeg2000/Makefile26
-rw-r--r--converter/other/jpeg2000/jpeg2ktopam.c68
-rw-r--r--converter/other/jpeg2000/libjasper/README4
-rw-r--r--converter/other/jpeg2000/libjasper/base/jas_image.c8
-rw-r--r--converter/other/jpeg2000/libjasper/base/jas_seq.c3
-rw-r--r--converter/other/jpeg2000/libjasper/base/jas_stream.c9
-rw-r--r--converter/other/jpeg2000/libjasper/common.mk8
-rw-r--r--converter/other/jpeg2000/libjasper/include/jasper/jas_image.h40
-rw-r--r--converter/other/jpeg2000/libjasper/include/jasper/jas_types.h2
-rw-r--r--converter/other/jpeg2000/libjasper/include/jasper/jas_types.h.orig228
-rw-r--r--converter/other/jpeg2000/libjasper/jp2/jp2_cod.c1055
-rw-r--r--converter/other/jpeg2000/libjasper/jp2/jp2_dec.c8
-rw-r--r--converter/other/jpeg2000/libjasper/jpc/jpc_bs.c4
-rw-r--r--converter/other/jpeg2000/libjasper/jpc/jpc_bs.h2
-rw-r--r--converter/other/jpeg2000/libjasper/jpc/jpc_cs.c2010
-rw-r--r--converter/other/jpeg2000/libjasper/jpc/jpc_cs.h2
-rw-r--r--converter/other/jpeg2000/libjasper/jpc/jpc_dec.c3524
-rw-r--r--converter/other/jpeg2000/libjasper/jpc/jpc_dec.h2
-rw-r--r--converter/other/jpeg2000/libjasper/jpc/jpc_enc.c4810
-rw-r--r--converter/other/jpeg2000/libjasper/jpc/jpc_math.h2
-rw-r--r--converter/other/jpeg2000/libjasper/jpc/jpc_mqcod.h2
-rw-r--r--converter/other/jpeg2000/libjasper/jpc/jpc_mqenc.c392
-rw-r--r--converter/other/jpeg2000/libjasper/jpc/jpc_qmfb.c8
-rw-r--r--converter/other/jpeg2000/libjasper/jpc/jpc_t2cod.h4
-rw-r--r--converter/other/jpeg2000/pamtojpeg2k.c143
-rw-r--r--converter/other/jpegtopnm.c24
-rw-r--r--converter/other/pamrgbatopng.c150
-rw-r--r--converter/other/pamtoavs.c150
-rw-r--r--converter/other/pamtodjvurle.c4
-rw-r--r--converter/other/pamtofits.c8
-rw-r--r--converter/other/pamtogif.c14
-rw-r--r--converter/other/pamtohdiff.c4
-rw-r--r--converter/other/pamtohtmltbl.c4
-rw-r--r--converter/other/pamtompfont.c6
-rw-r--r--converter/other/pamtooctaveimg.c4
-rw-r--r--converter/other/pamtopam.c2
-rw-r--r--converter/other/pamtopdbimg.c810
-rw-r--r--converter/other/pamtopfm.c8
-rw-r--r--converter/other/pamtopng.c825
-rw-r--r--converter/other/pamtopnm.c36
-rw-r--r--converter/other/pamtosrf.c217
-rw-r--r--converter/other/pamtosvg/Makefile32
-rw-r--r--converter/other/pamtosvg/bitmap.c4
-rw-r--r--converter/other/pamtosvg/bitmap.h2
-rw-r--r--converter/other/pamtosvg/image-proc.c4
-rw-r--r--converter/other/pamtosvg/message.h16
-rw-r--r--converter/other/pamtosvg/pamtosvg.c14
-rw-r--r--converter/other/pamtosvg/pxl-outline.c1
-rw-r--r--converter/other/pamtosvg/thin-image.c6
-rw-r--r--converter/other/pamtosvg/vector.c1
-rw-r--r--converter/other/pamtotga.c6
-rw-r--r--converter/other/pamtotiff.c593
-rw-r--r--converter/other/pamtouil.c8
-rw-r--r--converter/other/pamtowinicon.c1177
-rw-r--r--converter/other/pamtoxvmini.c4
-rw-r--r--converter/other/pdbimgtopam.c774
-rw-r--r--converter/other/pfmtopam.c4
-rw-r--r--converter/other/pgmtopbm.c6
-rw-r--r--converter/other/pgmtoppm.c5
-rw-r--r--converter/other/pngtopam.c1237
-rw-r--r--converter/other/pngtopnm.c1255
-rw-r--r--converter/other/pngtxt.c468
-rw-r--r--converter/other/pngtxt.h14
-rw-r--r--converter/other/pngx.c757
-rw-r--r--converter/other/pngx.h274
-rw-r--r--converter/other/pnmtojpeg.c13
-rw-r--r--converter/other/pnmtopalm/Makefile16
-rw-r--r--converter/other/pnmtopalm/gen_palm_colormap.c4
-rw-r--r--converter/other/pnmtopalm/palm.h8
-rw-r--r--converter/other/pnmtopalm/palmcolormap.c8
-rw-r--r--converter/other/pnmtopalm/palmtopnm.c4
-rw-r--r--converter/other/pnmtopalm/pnmtopalm.c125
-rw-r--r--converter/other/pnmtopclxl.c1069
-rw-r--r--converter/other/pnmtopng.README101
-rw-r--r--converter/other/pnmtopng.c1439
-rw-r--r--converter/other/pnmtops.c1711
-rw-r--r--converter/other/pnmtorast.c501
-rw-r--r--converter/other/pnmtosgi.c513
-rw-r--r--converter/other/pnmtoxwd.c24
-rw-r--r--converter/other/ppmtopgm.c4
-rw-r--r--converter/other/pstopnm.c888
-rw-r--r--converter/other/rast.c83
-rw-r--r--converter/other/rast.h15
-rw-r--r--converter/other/rasttopnm.c703
-rw-r--r--converter/other/rletopnm.c154
-rw-r--r--converter/other/sgi.h8
-rw-r--r--converter/other/sgitopnm.c747
-rw-r--r--converter/other/srf.c653
-rw-r--r--converter/other/srf.h170
-rw-r--r--converter/other/srftopam.c226
-rw-r--r--converter/other/sunicontopnm.c172
-rw-r--r--converter/other/svgtopam.c18
-rw-r--r--converter/other/tiff.c6
-rw-r--r--converter/other/tifftopnm.c273
-rw-r--r--converter/other/winicon.h82
-rw-r--r--converter/other/winicontopam.c1286
-rw-r--r--converter/other/xwdtopnm.c6
-rw-r--r--converter/other/yuy2topam.c266
180 files changed, 29781 insertions, 19992 deletions
diff --git a/converter/other/Makefile b/converter/other/Makefile
index 077db195..6a3d14ed 100644
--- a/converter/other/Makefile
+++ b/converter/other/Makefile
@@ -7,12 +7,20 @@ VPATH=.:$(SRCDIR)/$(SUBDIR)
 
 include $(BUILDDIR)/config.mk
 
-ifeq ($(shell xml2-config --version),)
-  XML2_LIBS=NONE
-  XML2_CFLAGS=NONE
+TEST_PKGCONFIG_LIBXML2 = if pkg-config libxml-2.0; then echo exists; fi
+
+ifneq ($(shell $(TEST_PKGCONFIG_LIBXML2)),)
+  # pkg-config libxml2 works on this system
+  XML2_LIBS = $(shell pkg-config libxml-2.0 --libs)
+  XML2_CFLAGS = $(shell pkg-config libxml-2.0 --cflags)
 else
-  XML2_LIBS=$(shell xml2-config --libs)
-  XML2_CFLAGS=$(shell xml2-config --cflags)
+  ifeq ($(shell xml2-config --version),)
+    XML2_LIBS=NONE
+    XML2_CFLAGS=NONE
+  else
+    XML2_LIBS=$(shell xml2-config --libs)
+    XML2_CFLAGS=$(shell xml2-config --cflags)
+  endif
 endif
 
 SUBDIRS = jbig pnmtopalm jpeg2000 cameratopam pamtosvg
@@ -26,19 +34,29 @@ ifneq ($(TIFFLIB),NONE)
   endif
 endif
 
-ifeq ($(shell libpng$(PNGVER)-config --version),)
-  ifneq ($(PNGLIB),NONE)
+TEST_PKGCONFIG_LIBPNG = if pkg-config libpng$(PNGVER); then echo exists; fi
+
+ifneq ($(shell $(TEST_PKGCONFIG_LIBPNG)),)
+  # pkg-config libpng works on this system
+  HAVE_PNGLIB = Y
+  EXTERN_INCLUDES += $(shell pkg-config libpng$(PNGVER) --cflags)
+else
+  ifneq ($(shell libpng$(PNGVER)-config --version),)
+    # No pkg-config, but we have libpng-config on this system
     HAVE_PNGLIB = Y
-    ifneq ($(PNGHDR_DIR)x,x)
-      EXTERN_INCLUDES += -I$(PNGHDR_DIR)
-    endif
-    ifneq ($(ZHDR_DIR)x,x)
-      EXTERN_INCLUDES += -I$(ZHDR_DIR)
+    EXTERN_INCLUDES += $(shell libpng$(PNGVER)-config --cflags)
+  else
+    # System can't tell us where libpng is; use stuff from config.mk
+    ifneq ($(PNGLIB),NONE)
+      HAVE_PNGLIB = Y
+      ifneq ($(PNGHDR_DIR)x,x)
+        EXTERN_INCLUDES += -I$(PNGHDR_DIR)
+      endif
+      ifneq ($(ZHDR_DIR)x,x)
+        EXTERN_INCLUDES += -I$(ZHDR_DIR)
+      endif
     endif
   endif
-else
-  HAVE_PNGLIB = Y
-  EXTERN_INCLUDES += $(shell libpng$(PNGVER)-config --cflags)
 endif
 
 ifneq ($(JPEGLIB),NONE)
@@ -77,49 +95,66 @@ ifeq ($(TIFFLIB_NEEDS_Z),Y)
   endif
 endif
 
-PORTBINARIES =  bmptopnm fitstopnm \
+# TIFFLIB_USERLIBS is for the user to set manually, on the make command line
+# or manually added to config.mk.  There are arcane situations where the TIFF
+# library refers to additional libraries not handled above.
+
+TIFFLIB_EXTRALIBS += $(TIFFLIB_USERLIBS)
+
+# Pnmtops's "flate" compression function requires libz.  But if we don't
+# have libz, we still build Pnmtops; we just omit the flate compression
+# capability.
+ifeq ($(ZLIB),NONE)
+  PNMTOPS_ZLIB_OPT =
+  PNMTOPS_NOFLATE_OPT = -DNOFLATE
+else
+  PNMTOPS_ZLIB_OPT = $(ZLIB)
+  PNMTOPS_NOFLATE_OPT =
+endif
+
+
+PORTBINARIES =  avstopam bmptopnm fitstopnm \
 		gemtopnm giftopnm hdifftopam infotopam \
-		pamtodjvurle pamtofits pamtogif \
+		pamtoavs pamtodjvurle pamtofits pamtogif \
 		pamtohdiff pamtohtmltbl pamtompfont pamtooctaveimg \
-		pamtopam pamtopfm pamtopnm pamtouil \
-		pamtoxvmini \
-		pbmtopgm pfmtopam \
+		pamtopam pamtopdbimg pamtopfm pamtopnm pamtosrf pamtouil \
+		pamtowinicon pamtoxvmini \
+		pbmtopgm pdbimgtopam pfmtopam \
 	        pgmtopbm pgmtoppm ppmtopgm pnmtoddif \
-		pnmtopclxl \
+		pnmtopclxl pnmtorast \
 		pnmtosgi pnmtosir pamtotga pnmtoxwd \
-		rlatopam sgitopnm sirtopnm xwdtopnm zeisstopnm
+		rasttopnm rlatopam sgitopnm sirtopnm srftopam sunicontopnm \
+		winicontopam xwdtopnm yuy2topam zeisstopnm
 
 ifneq ($(DONT_HAVE_PROCESS_MGMT),Y)
-  PORTBINARIES += pstopnm
+  PORTBINARIES += pstopnm pnmtops
 endif
 
-BINARIES = $(PORTBINARIES) pnmtorast rasttopnm
-
 ifeq ($(HAVE_PNGLIB),Y)
-  BINARIES += pnmtopng pngtopnm pngtopam pamrgbatopng
+  PORTBINARIES += pamtopng pnmtopng pngtopam
 endif
 ifneq ($(JPEGLIB),NONE)
-  BINARIES += jpegtopnm pnmtojpeg
+  PORTBINARIES += jpegtopnm pnmtojpeg
 endif
 ifneq ($(TIFF_PREREQ_MISSING),Y)
-  BINARIES += tifftopnm pamtotiff pnmtotiffcmyk
+  PORTBINARIES += tifftopnm pamtotiff pnmtotiffcmyk
 endif
 ifneq ($(URTLIB),NONE)
-  BINARIES += rletopnm pnmtorle
-endif
-ifneq ($(ZLIB),NONE)
-  BINARIES += pnmtops
+  PORTBINARIES += rletopnm pnmtorle
 endif
 
 ifneq ($(XML2_LIBS),NONE)
-  BINARIES += svgtopam
+  PORTBINARIES += svgtopam
 endif 
 
+BINARIES = $(PORTBINARIES)
+
 MERGEBINARIES = $(BINARIES)
 
-EXTRA_OBJECTS = exif.o rast.o bmepsoe.o
+EXTRA_OBJECTS = exif.o rast.o ipdb.o srf.o
 ifeq ($(HAVE_PNGLIB),Y)
   EXTRA_OBJECTS += pngtxt.o
+  EXTRA_OBJECTS += pngx.o
 endif
 ifneq ($(JPEGLIB),NONE)
   EXTRA_OBJECTS += jpegdatasource.o
@@ -131,6 +166,7 @@ endif
 OBJECTS = $(BINARIES:%=%.o) $(EXTRA_OBJECTS)
 MERGE_OBJECTS = $(MERGEBINARIES:%=%.o2) $(EXTRA_OBJECTS)
 
+pnmtops.o pnmtops.o2: CFLAGS_TARGET=$(PNMTOPS_NOFLATE_OPT)
 
 SCRIPTS = anytopnm pnmtoplainpnm
 
@@ -145,69 +181,68 @@ else
   LIBOPTR =
 endif
 
-LIBOPTS_TIFF = $(shell $(LIBOPT) $(NETPBMLIB) \
+LIBOPTS_TIFF = $(shell $(LIBOPT) \
   $(LIBOPTR) $(TIFFLIB) $(TIFFLIB_EXTRALIBS))
 
-tifftopnm pamtotiff pnmtotiffcmyk: %: %.o tiff.o $(NETPBMLIB) $(LIBOPT)
-	$(LD) -o $@ $@.o tiff.o \
-	  $(LIBOPTS_TIFF) $(MATHLIB) $(LDFLAGS) $(LDLIBS) $(RPATH) $(LADD)
+tifftopnm pamtotiff pnmtotiffcmyk: tiff.o
+tifftopnm pamtotiff pnmtotiffcmyk: ADDL_OBJECTS = tiff.o
+tifftopnm pamtotiff pnmtotiffcmyk: \
+  LDFLAGS_TARGET = \
+ $(shell $(LIBOPT)  $(LIBOPTR) $(TIFFLIB) $(TIFFLIB_EXTRALIBS))
 
-ifeq ($(shell libpng$(PNGVER)-config --version),)
-  PNGLIB_LIBOPTS = $(shell $(LIBOPT) $(LIBOPTR) $(PNGLIB) $(ZLIB))
+ifneq ($(shell $(TEST_PKGCONFIG_LIBPNG)),)
+  # pkg-config libpng works on this system
+  PNGLIB_LIBOPTS = $(shell pkg-config libpng$(PNGVER) --libs)
 else
-  PNGLIB_LIBOPTS = $(shell libpng$(PNGVER)-config --ldflags)
+  ifneq ($(shell libpng$(PNGVER)-config --version),)
+    # No pkg-config, but we have libpng-config on this system
+    PNGLIB_LIBOPTS = $(shell libpng$(PNGVER)-config --ldflags)
+  else
+    # System can't tell us where libpng is; use stuff from config.mk
+    PNGLIB_LIBOPTS = $(shell $(LIBOPT) $(LIBOPTR) $(PNGLIB) $(ZLIB))
+  endif
 endif
 
-pngtopnm pngtopam: %: %.o $(NETPBMLIB) $(LIBOPT)
-	$(LD) -o $@ $@.o \
-	  $(shell $(LIBOPT) $(NETPBMLIB)) \
-	  $(PNGLIB_LIBOPTS) $(MATHLIB) $(LDFLAGS) $(LDLIBS) $(RPATH) $(LADD)
+pngtopam: pngx.o
+pngtopam: ADDL_OBJECTS = pngx.o
+pngtopam: LDFLAGS_TARGET = $(PNGLIB_LIBOPTS)
+
+pamtopng: pngx.o pngtxt.o
+pamtopng: ADDL_OBJECTS = pngx.o pngtxt.o
+pamtopng: LDFLAGS_TARGET = $(PNGLIB_LIBOPTS)
 
-pnmtopng: %: %.o pngtxt.o $(NETPBMLIB) $(LIBOPT)
-	$(LD) -o $@ $@.o pngtxt.o \
-	  $(shell $(LIBOPT) $(NETPBMLIB)) \
-	  $(PNGLIB_LIBOPTS) $(MATHLIB) $(LDFLAGS) $(LDLIBS) $(RPATH) $(LADD)
+pnmtopng: pngx.o pngtxt.o
+pnmtopng: ADDL_OBJECTS = pngx.o pngtxt.o
+pnmtopng: LDFLAGS_TARGET = $(PNGLIB_LIBOPTS)
 
-pamrgbatopng: %: %.o $(NETPBMLIB) $(LIBOPT)
-	$(LD) -o $@ $@.o \
-	  $(shell $(LIBOPT) $(NETPBMLIB)) $(PNGLIB_LIBOPTS) \
-	  $(MATHLIB) $(LDFLAGS) $(LDLIBS) $(RPATH) $(LADD)
+jpegtopnm: jpegdatasource.o exif.o
+jpegtopnm: ADDL_OBJECTS = jpegdatasource.o exif.o
+jpegtopnm: LDFLAGS_TARGET = $(shell $(LIBOPT) $(LIBOPTR) $(JPEGLIB))
 
-jpegtopnm: %: %.o jpegdatasource.o exif.o $(NETPBMLIB) $(LIBOPT)
-	$(LD) -o $@ $< jpegdatasource.o exif.o \
-	  $(shell $(LIBOPT) $(NETPBMLIB) $(LIBOPTR) $(JPEGLIB)) \
-	  $(MATHLIB) $(LDFLAGS) $(LDLIBS) $(RPATH) $(LADD) 
+srftopam pamtosrf: srf.o
+srftopam pamtosrf: ADDL_OBJECTS = srf.o
 
-pnmtojpeg: %: %.o $(NETPBMLIB) $(LIBOPT)
-	$(LD) -o $@ $@.o \
-	  $(shell $(LIBOPT) $(NETPBMLIB) $(LIBOPTR) $(JPEGLIB)) \
-	  $(MATHLIB) $(LDFLAGS) $(LDLIBS) $(RPATH) $(LADD)
+pnmtojpeg: LDFLAGS_TARGET = $(shell $(LIBOPT) $(LIBOPTR) $(JPEGLIB))
 
-svgtopam: %: %.o $(NETPBMLIB) $(LIBOPT)
-	$(LD) -o $@ $@.o \
-	  $(shell $(LIBOPT) $(NETPBMLIB) $(LIBOPTR)) \
-	  $(XML2_LIBS) $(MATHLIB) $(LDFLAGS) $(LDLIBS) $(RPATH) $(LADD)
+svgtopam: LDFLAGS_TARGET = $(XML2_LIBS)
 
 # If URTLIB is BUNDLED_URTLIB, then we're responsible for building it, which
 # means it needs to be a dependency:
 ifeq ($(URTLIB), $(BUNDLED_URTLIB))
-  URTLIBDEP = $(URTLIB)
+rletopnm pnmtorle: $(URTLIB)
 endif
 
-rletopnm pnmtorle: %: %.o $(NETPBMLIB) $(URTLIBDEP) $(LIBOPT)
-	$(LD) -o $@ $@.o \
-	  $(shell $(LIBOPT) $(URTLIB) $(NETPBMLIB)) \
-	  $(MATHLIB) $(LDFLAGS) $(LDLIBS) $(RPATH) $(LADD)
+rletopnm pnmtorle: LDFLAGS_TARGET = $(shell $(LIBOPT) $(URTLIB))
+
+pnmtops: LDFLAGS_TARGET = $(shell $(LIBOPT) $(PNMTOPS_ZLIB_OPT))
+
+pnmtorast rasttopnm: rast.o
+pnmtorast rasttopnm: ADDL_OBJECTS = rast.o
 
-pnmtops: %: %.o bmepsoe.o $(NETPBMLIB) $(LIBOPT)
-	$(LD) -o $@ $@.o bmepsoe.o \
-	  $(shell $(LIBOPT) $(NETPBMLIB) $(ZLIB)) \
-	  $(MATHLIB) $(LDFLAGS) $(LDLIBS) $(RPATH) $(LADD)
+pdbimgtopam pamtopdbimg: ipdb.o
+pdbimgtopam pamtopdbimg: ADDL_OBJECTS = ipdb.o
 
-pnmtorast rasttopnm: %: %.o rast.o $(NETPBMLIB) $(LIBOPT)
-	$(LD) -o $@ $@.o rast.o \
-	  $(shell $(LIBOPT) $(NETPBMLIB)) \
-	  $(MATHLIB) $(LDFLAGS) $(LDLIBS) $(RPATH) $(LADD)
+# Declare dependencies on created header files (symbolic links, actually).
 
 bmptopnm.o bmptopnm.o2: bmp.h
 
@@ -248,3 +283,16 @@ ifneq ($(TIFF_PREREQ_MISSING),Y)
 	cd $(PKGDIR)/bin ; \
 	$(SYMLINK) pamtotiff$(EXE) pnmtotiff$(EXE)
 endif
+ifeq ($(HAVE_PNGLIB),Y)
+# In September 2009, pngtopam replaced pngtopnm
+	cd $(PKGDIR)/bin ; \
+	$(SYMLINK) pngtopam$(EXE) pngtopnm$(EXE)
+endif
+# In December 2010, sunicontopnm replaced icontopbm
+	cd $(PKGDIR)/bin ; \
+	$(SYMLINK) sunicontopnm$(EXE) icontopbm$(EXE)
+ifeq ($(HAVE_PNGLIB),Y)
+# In June 2015, pamtopng replaced pamrgbapng
+	cd $(PKGDIR)/bin ; \
+	$(SYMLINK) pamtopng$(EXE) pamrgbatopng$(EXE)
+endif
diff --git a/converter/other/anytopnm b/converter/other/anytopnm
index 06f48b4f..397faae5 100755
--- a/converter/other/anytopnm
+++ b/converter/other/anytopnm
@@ -150,7 +150,8 @@ computeTypeFromTypeDescription () {
             filetype=tiff
             ;;
     
-        *PC*bitmap*data* )
+        # We have seen "PC bitmap" and "PC bitmap data"
+        *PC*bitmap* )
             filetype=bmp
             ;;
         
@@ -399,7 +400,7 @@ case "$2" in
         ;;
 
     gif )
-        giftopnm "$file"
+        giftopnm -image=all "$file"
         ;;
 
     tiff )
@@ -437,7 +438,7 @@ case "$2" in
         ;;
 
     png )
-        pngtopnm "$file"
+        pngtopam "$file"
         ;;
 
     mda )
diff --git a/converter/other/avstopam.c b/converter/other/avstopam.c
new file mode 100644
index 00000000..322f387d
--- /dev/null
+++ b/converter/other/avstopam.c
@@ -0,0 +1,103 @@
+/* ----------------------------------------------------------------------
+ *
+ * Convert an AVS X image to a PAM image
+ *
+ * By Scott Pakin <scott+pbm@pakin.org>
+ *
+ * ----------------------------------------------------------------------
+ *
+ * Copyright (C) 2010 Scott Pakin <scott+pbm@pakin.org>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or (at
+ * your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see http://www.gnu.org/licenses/.
+ *
+ * ----------------------------------------------------------------------
+ */
+
+#include <stdio.h>
+
+#include "pm.h"
+#include "pam.h"
+
+
+
+static void
+producePam(FILE *       const avsFileP,
+           struct pam * const pamP) {
+
+    tuple *      tuplerow;
+    unsigned int row;
+
+    tuplerow = pnm_allocpamrow(pamP);
+    for (row = 0; row < pamP->height; ++row) {
+        unsigned int col;
+        for (col = 0; col < pamP->width; ++col) {
+            tuple const thisTuple = tuplerow[col];
+            unsigned char c;
+            pm_readcharu(avsFileP, &c); thisTuple[3] = c;
+            pm_readcharu(avsFileP, &c); thisTuple[0] = c;
+            pm_readcharu(avsFileP, &c); thisTuple[1] = c;
+            pm_readcharu(avsFileP, &c); thisTuple[2] = c;
+        }
+        pnm_writepamrow(pamP, tuplerow);
+    }
+    pnm_freepamrow(tuplerow);
+}
+
+
+
+int
+main(int argc, const char *argv[]) {
+
+    const char * comment = "Produced by avstopam";  /* constant */
+
+    struct pam   outPam;
+    const char * inputFilename;
+    FILE       * inFileP;
+    long         width;
+    long         height;
+
+    pm_proginit(&argc, argv);
+
+    inputFilename = (argc > 1) ? argv[1] : "-";
+
+    inFileP = pm_openr(inputFilename);
+
+    pm_readbiglong(inFileP, &width);
+    pm_readbiglong(inFileP, &height);
+
+    outPam.size             = sizeof(struct pam);
+    outPam.len              = PAM_STRUCT_SIZE(comment_p);
+    outPam.file             = stdout;
+    outPam.format           = PAM_FORMAT;
+    outPam.plainformat      = 0;
+    outPam.width            = width;
+    outPam.height           = height;
+    outPam.depth            = 4;
+    outPam.maxval           = 255;
+    outPam.bytes_per_sample = 1;
+    sprintf(outPam.tuple_type, "RGB_ALPHA");
+    outPam.allocation_depth = 4;
+    outPam.comment_p        = &comment;
+
+    /* Produce a PAM output header.  Note that AVS files *always*
+       contain four channels with one byte per channel.
+    */
+    pnm_writepaminit(&outPam);
+
+    producePam(inFileP, &outPam);
+
+    pm_closer(inFileP);
+
+    return 0;
+}
diff --git a/converter/other/bmepsoe.c b/converter/other/bmepsoe.c
deleted file mode 100644
index 02bf39aa..00000000
--- a/converter/other/bmepsoe.c
+++ /dev/null
@@ -1,560 +0,0 @@
-/* 
- * This was adapted for Netpbm from bmpesoe.c in Dirk Krause's Bmeps package
- * by Bryan Henderson on 2005.01.05.
- *
- * Differences:
- *   - doesn't require Bmeps configuration stuff (bmepsco.h)
- *   - doesn't include pngeps.h
- *   - doesn't have test scaffold code
- *   - a few compiler warnings fixed
- *
- * Copyright (C) 2000 - Dirk Krause
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License along with this library; if not, write to the
- * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- * Boston, MA 02111-1307, USA.
- * In this package the copy of the GNU Library General Public License
- * is placed in file COPYING.
- */
-
-#include "bmepsoe.h"
-
-#define RL_RUNLENGTH(i) (257 - (i))
-#define RL_STRINGLENGTH(i) ((i) - 1)
-#define RL_MAXLENGTH (127)
-
-#define FINALOUTPUT(c) fputc((c),o->out)
-
-void oe_init(Output_Encoder *o, FILE *out, int mode, int rate, int *buf,
-  Bytef *flib, size_t flis, Bytef *flob, size_t flos
-)
-{
-  
-  o->out = out;
-  o->mode = mode;
-  o->textpos = 0;
-  o->a85_value = 0UL; o->a85_consumed = 0;
-  o->a85_0 = 1UL;
-  o->a85_1 = 85UL;
-  o->a85_2 = 85UL * 85UL;
-  o->a85_3 = 85UL * o->a85_2;
-  o->a85_4 = 85UL * o->a85_3;
-  o->rl_lastbyte = 0;
-  o->rl_buffer = buf;
-  o->rl_bufused = 0;
-  o->rl_state = 0;
-  o->bit_value = 0;
-  o->bit_consumed = 0;
-  o->flate_rate = rate;
-  if(o->flate_rate < 0) {
-    o->mode &= (~OE_FLATE);
-  }
-  if(o->flate_rate > 9) {
-    o->flate_rate = 9;
-  }
-  if((o->mode & OE_FLATE) && flib && flis && flob && flos) {
-    (o->flate_stream).zfree = (free_func)0;
-    (o->flate_stream).zalloc = (alloc_func)0;
-    (o->flate_stream).opaque = (voidpf)0;
-    if(deflateInit((&(o->flate_stream)),o->flate_rate) != Z_OK) {
-      o->mode &= (~OE_FLATE);
-    }
-  }
-  o->fl_i_buffer = flib;
-  o->fl_o_buffer = flob;
-  o->fl_i_size   = flis;
-  o->fl_o_size   = flos;
-  o->fl_i_used   = 0;
-  
-}
-
-static char hexdigits[] = {
-  "0123456789ABCDEF"
-};
-
-static void asciihex_add(Output_Encoder *o, int b)
-{
-  
-  FINALOUTPUT(hexdigits[(b/16)]) ;
-  FINALOUTPUT(hexdigits[(b%16)]) ;
-  o->textpos = o->textpos + 2;
-  if(o->textpos >= 64) {
-    FINALOUTPUT('\n') ;
-    o->textpos = 0;
-  }
-  
-}
-
-static void asciihex_flush(Output_Encoder *o)
-{
-  
-  if(o->textpos > 0) {
-    FINALOUTPUT('\n') ;
-    o->textpos = 0;
-  }
-  
-}
-
-static char   ascii85_char(unsigned long x)
-{
-  unsigned u;
-  int      i;
-  char back;
-  back = (char)0;
-  u = (unsigned)x;
-  i = (int)u;
-  i += 33;
-  back = (char)i;
-  return back;
-}
-
-
-
-static void
-ascii85_output(Output_Encoder * const o) {
-    unsigned long value;
-
-    value = o->a85_value;  /* initial value */
-
-    if (value == 0 && o->a85_consumed == 4) {
-        FINALOUTPUT('z');
-        ++o->textpos;
-    } else {
-        unsigned int i;
-        unsigned int j;
-        char buffer[6];
-
-        buffer[0] = ascii85_char(value / (o->a85_4));
-        value = value % (o->a85_4);
-        buffer[1] = ascii85_char(value / (o->a85_3));
-        value = value % (o->a85_3);
-        buffer[2] = ascii85_char(value / (o->a85_2));
-        value = value % (o->a85_2);
-        buffer[3] = ascii85_char(value / (o->a85_1));
-        value = value % (o->a85_1);
-        buffer[4] = ascii85_char(value);
-        buffer[5] = '\0';
-
-        i = o->a85_consumed + 1;
-        o->textpos += i;
-
-        for (j = 0; j < i; ++j)
-            FINALOUTPUT(buffer[j]);
-    }
-    if (o->textpos >= 64) {
-        FINALOUTPUT('\n');
-        o->textpos = 0;
-    }
-}
-
-
-
-static void ascii85_add(Output_Encoder *o, int b)
-{
-  unsigned u;
-  unsigned long ul;
-  
-  u = (unsigned)b;
-  ul = (unsigned long)u;
-  o->a85_value = 256UL * (o->a85_value) + ul;
-  o->a85_consumed = o->a85_consumed + 1;
-  if(o->a85_consumed >= 4) {
-    ascii85_output(o);
-    o->a85_value = 0UL;
-    o->a85_consumed = 0;
-  }
-  
-}
-
-static void ascii85_flush(Output_Encoder *o)
-{
-  int i;
-  
-  if(o->a85_consumed > 0) {
-    i = o->a85_consumed;
-    while(i < 4) {
-      o->a85_value = 256UL * o->a85_value;
-      i++;
-    }
-    ascii85_output(o);
-    o->a85_value = 0UL;
-    o->a85_consumed = 0;
-  }
-  if(o->textpos > 0) {
-    FINALOUTPUT('\n') ;
-    o->textpos = 0;
-  }
-  
-}
-
-static void after_flate_add(Output_Encoder *o, int b)
-{
-  
-  if(o->mode & OE_ASC85) {
-    ascii85_add(o,b);
-  } else {
-    asciihex_add(o,b);
-  }
-  
-}
-
-
-
-static void
-do_flate_flush(Output_Encoder * const oP,
-               int              const final) {
-
-    Bytef *iptr, *optr, *xptr;
-    unsigned long is;
-    unsigned long os;
-    unsigned long xs;
-    int err;
-    int mustContinue;
-  
-    iptr = oP->fl_i_buffer; optr = oP->fl_o_buffer;
-    is = oP->fl_i_size; os = oP->fl_o_size;
-  
-    if (iptr && optr && is && os) {
-        is = oP->fl_i_used;
-        if (is || final) {
-            oP->flate_stream.next_in = iptr;
-            oP->flate_stream.avail_in = is;
-            if (final) { 
-                mustContinue = 1;
-                while (mustContinue) {
-                    oP->flate_stream.next_out = optr;
-                    oP->flate_stream.avail_out = os;
-                    mustContinue = 0;
-                    err = deflate(&oP->flate_stream, Z_FINISH);
-                    switch (err) {
-                    case Z_STREAM_END: { 
-                        xptr = optr;
-          
-                        xs = os - (oP->flate_stream.avail_out);
-                        while (xs--) {
-                            after_flate_add(oP, *(xptr++));
-                        }
-                    } break;
-                    case Z_OK : {
-                        mustContinue = 1;
-                        xptr = optr;
-          
-                        xs = os - (oP->flate_stream.avail_out);
-                        while (xs--) {
-                            after_flate_add(oP, *(xptr++));
-                        }
-                    } break;
-                    default : { 
-                    } break;
-                    }
-                }
-            } else { 
-                mustContinue = 1;
-                while (mustContinue) {
-                    mustContinue = 0;
-                    oP->flate_stream.avail_out = os;
-                    oP->flate_stream.next_out = optr;
-                    err = deflate(&oP->flate_stream, 0);
-                    switch (err) {
-                    case Z_OK: {
-                        if (oP->flate_stream.avail_in) {
-                            mustContinue = 1;
-                        }
-          
-                        xptr = optr; xs = os - (oP->flate_stream.avail_out);
-                        while (xs--) {
-                            after_flate_add(oP, *(xptr++));
-                        }
-                    } break;
-                    default : { 
-                    } break;
-                    }
-                }
-            }
-        }
-    }
-}
-
-
-
-static void flate_add(Output_Encoder *o, int b)
-{
-  Byte bt;
-  Bytef *btptr;
-  
-  btptr = o->fl_i_buffer;
-  if(btptr) { 
-    bt = (Byte)b; 
-    btptr[(o->fl_i_used)] = bt;
-    o->fl_i_used += 1UL;
-    if(o->fl_i_used >= o->fl_i_size) {
-      do_flate_flush(o, 0);
-      o->fl_i_used = 0UL;
-    }
-  }
-  
-}
-
-static void after_flate_flush(Output_Encoder *o)
-{
-  
-  if(o->mode & OE_ASC85) {
-    ascii85_flush(o);
-  } else {
-    asciihex_flush(o);
-  }
-  
-}
-
-static void flate_flush(Output_Encoder *o)
-{
-  do_flate_flush(o,1);
-  deflateEnd(&(o->flate_stream));
-  after_flate_flush(o);
-}
-
-
-static void after_rl_add(Output_Encoder *o, int b)
-{
-  
-  if(o->mode & OE_FLATE) {
-    flate_add(o,b);
-  } else {
-    after_flate_add(o,b);
-  }
-  
-}
-
-static void rl_add(Output_Encoder *o, int b)
-{
-  int lgt, i;
-  int *buffer;
-  /* ##### */
-  
-  buffer = o->rl_buffer;
-  lgt = o->rl_bufused;
-  if(buffer) {
-    
-    if(lgt > 0) {
-      if(o->rl_lastbyte == b) {
-    switch(o->rl_state) {
-      case 2: {
-        buffer[lgt++] = b;
-        o->rl_bufused = lgt;
-        o->rl_state = 2;
-        o->rl_lastbyte = b;
-        if(lgt >= RL_MAXLENGTH) {
-          after_rl_add(o, RL_RUNLENGTH(lgt));
-          after_rl_add(o, b);
-          o->rl_bufused = 0;
-          o->rl_state = 0;
-          o->rl_lastbyte = b;
-        }
-      } break;
-      case 1: {
-        buffer[lgt++] = b;
-        o->rl_bufused = lgt;
-        o->rl_state = 2;
-        o->rl_lastbyte = b;
-        lgt = lgt - 3;
-        if(lgt > 0) {
-          after_rl_add(o, RL_STRINGLENGTH(lgt));
-          for(i = 0; i < lgt; i++) {
-        after_rl_add(o, buffer[i]);
-          }
-          buffer[0] = buffer[1] = buffer[2] = b;
-          o->rl_bufused = 3;
-          o->rl_state = 2;
-          o->rl_lastbyte = b;
-        }
-      } break;
-      default: {
-        buffer[lgt++] = b;
-        o->rl_bufused = lgt;
-        o->rl_state = 1;
-        o->rl_lastbyte = b;
-        if(lgt >= RL_MAXLENGTH) {
-          lgt = lgt - 2;
-          after_rl_add(o, RL_STRINGLENGTH(lgt));
-          for(i = 0; i < lgt; i++) {
-        after_rl_add(o, buffer[i]);
-          }
-          buffer[0] = buffer[1] = b;
-          o->rl_bufused = 2;
-          o->rl_state = 1;
-          o->rl_lastbyte = b;
-        }
-      } break;
-    }
-      } else {
-    if(o->rl_state == 2) {
-      after_rl_add(o, RL_RUNLENGTH(lgt));
-      after_rl_add(o, (o->rl_lastbyte));
-      buffer[0] = b; o->rl_bufused = 1; o->rl_lastbyte = b;
-      o->rl_state = 0;
-    } else {
-      buffer[lgt++] = b;
-      o->rl_bufused = lgt;
-      o->rl_lastbyte = b;
-      if(lgt >= RL_MAXLENGTH) {
-        after_rl_add(o, RL_STRINGLENGTH(lgt));
-        for(i = 0; i < lgt; i++) {
-          after_rl_add(o, buffer[i]);
-        }
-        o->rl_bufused = 0;
-      }
-      o->rl_state = 0;
-    }
-      }
-    } else {
-      buffer[0] = b;
-      o->rl_bufused = 1;
-      o->rl_lastbyte = b;
-    }
-    o->rl_lastbyte = b;
-    
-  } else { 
-    after_rl_add(o,0);
-    after_rl_add(o,b);
-  }
-  
-}
-
-static void after_rl_flush(Output_Encoder *o)
-{
-  
-  if(o->mode & OE_FLATE) {
-    flate_flush(o);
-  } else {
-    after_flate_flush(o);
-  }
-  
-}
-
-static void rl_flush(Output_Encoder *o)
-{
-  int lgt;
-  int *buffer;
-  int i;
-  
-  buffer = o->rl_buffer;
-  lgt = o->rl_bufused;
-  if(lgt > 0) {
-    if(o->rl_state == 2) {
-      i = o->rl_lastbyte;
-      after_rl_add(o,RL_RUNLENGTH(lgt));
-      after_rl_add(o,i);
-    } else {
-      after_rl_add(o,RL_STRINGLENGTH(lgt));
-      for(i = 0; i < lgt; i++) {
-    after_rl_add(o,buffer[i]);
-      }
-    }
-  }
-  after_rl_flush(o);
-  
-}
-
-
-
-static void
-internal_byte_add(Output_Encoder * const oP,
-                  int              const b) {
-  
-    if (oP->mode & OE_RL)
-        rl_add(oP, b);
-    else
-        after_rl_add(oP, b);
-}
-
-
-
-static void internal_byte_flush(Output_Encoder *o)
-{
-  
-  if((o->mode) & OE_RL) {
-    rl_flush(o);
-  } else {
-    after_rl_flush(o);
-  }
-  
-}
-
-
-
-void
-oe_bit_add(Output_Encoder * const oP,
-           int              const b) {
-  
-    oP->bit_value = 2 * oP->bit_value + (b ? 1 : 0);
-    oP->bit_consumed = oP->bit_consumed + 1;
-    if (oP->bit_consumed >= 8) {
-        oP->bit_consumed = 0;
-        internal_byte_add(oP, oP->bit_value);
-        oP->bit_value = 0;
-    }
-}
-
-
-
-void oe_bit_flush(Output_Encoder *o)
-{
-  
-  if(o->bit_consumed) {
-    int v, i;
-    v = o->bit_value;
-    i = o->bit_consumed;
-    while(i < 8) {
-      i++;
-      v = v * 2;
-    }
-    internal_byte_add(o,v);
-    o->bit_value = 0;
-    o->bit_consumed = 0;
-  }
-  internal_byte_flush(o);
-  
-}
-
-
-
-void
-oe_byte_add(Output_Encoder * const oP,
-            int              const b) {
-  
-    if (oP->bit_consumed) {
-        int testval;
-        int i;
-        testval = 128;
-        for (i = 0; i < 8; ++i) {
-            if (b & testval) {
-                oe_bit_add(oP, 1);
-            } else {
-                oe_bit_add(oP, 0);
-            }
-            testval = testval / 2;
-        }
-    } else {
-        internal_byte_add(oP, b);
-    }
-}
-
-
-
-void oe_byte_flush(Output_Encoder *o)
-{
-  
-  oe_bit_flush(o);
-  
-}
diff --git a/converter/other/bmepsoe.h b/converter/other/bmepsoe.h
deleted file mode 100644
index 99c59f77..00000000
--- a/converter/other/bmepsoe.h
+++ /dev/null
@@ -1,79 +0,0 @@
-/* 
- * libbmeps - Bitmap to EPS conversion library
- * Copyright (C) 2000 - Dirk Krause
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License along with this library; if not, write to the
- * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- * Boston, MA 02111-1307, USA.
- * In this package the copy of the GNU Library General Public License
- * is placed in file COPYING.
- */
-
-#ifndef BMPESOE_H_INCLUDED
-#define BMPESOE_H_INCLUDED
-
-#include <stdio.h>
-
-#include <zlib.h>
-
-typedef struct {
-  int mode;
-  FILE *out;
-  int textpos;
-  unsigned long a85_value;
-  int      a85_consumed;
-  unsigned long a85_4;
-  unsigned long a85_3;
-  unsigned long a85_2;
-  unsigned long a85_1;
-  unsigned long a85_0;
-  int rl_lastbyte;
-  int *rl_buffer;
-  int rl_bufused;
-  int rl_state;
-  int bit_value;
-  int bit_consumed;
-  z_stream flate_stream;
-  Bytef *fl_i_buffer;
-  Bytef *fl_o_buffer;
-  uLong  fl_i_size;
-  uLong  fl_o_size;
-  uLong  fl_i_used;
-  int    flate_rate;
-} Output_Encoder;
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-void oe_init(Output_Encoder *o, FILE *out, int mode, int rate, int *buf,
-  Bytef *flib, size_t flis, Bytef *flob, size_t flos
-);
-void oe_byte_add(Output_Encoder *o, int b);
-void oe_byte_flush(Output_Encoder *o);
-void oe_bit_add(Output_Encoder *o, int b);
-void oe_bit_flush(Output_Encoder *o);
-
-#ifdef __cplusplus
-}
-#endif
-
-
-
-#define OE_ASC85 1
-#define OE_FLATE 2
-#define OE_RL    4
-
-#endif
-
diff --git a/converter/other/bmptopnm.c b/converter/other/bmptopnm.c
index fb89433c..bf4d10f8 100644
--- a/converter/other/bmptopnm.c
+++ b/converter/other/bmptopnm.c
@@ -28,14 +28,12 @@
 #include <assert.h>
 
 #include "pm_c_util.h"
-#include "pnm.h"
+#include "mallocvar.h"
 #include "shhopt.h"
 #include "nstring.h"
+#include "pnm.h"
 #include "bmp.h"
 
-/* MAXCOLORS is the maximum size of a color map in a BMP image */
-#define MAXCOLORS       256
-
 static xelval const bmpMaxval = 255;
     /* The maxval for intensity values in a BMP image -- either in a
        truecolor raster or in a colormap
@@ -103,59 +101,57 @@ struct bmpInfoHeader {
         /* Size in bytes of the image data.  We only reference this 
            when the image is compressed. */    
     unsigned short cPlanes;
-    unsigned long int compression;
+    BMPCompType compression;
     struct pixelformat pixelformat;
 };
 
 
 
-struct cmdline_info {
+struct cmdlineInfo {
     /* All the information the user supplied in the command line,
        in a form easy for the program to use.
     */
-    const char *input_filespec;  /* Filespecs of input files */
-    int verbose;    /* -verbose option */
+    const char * inputFileName;
+    unsigned int verbose;
 };
 
-static const char *ifname;
+static const char * ifname;
 
 
 
 static void
-parse_command_line(int argc, char ** argv,
-                   struct cmdline_info *cmdline_p) {
+parseCommandLine(int argc, const char ** argv,
+                 struct cmdlineInfo * const cmdlineP) {
 /*----------------------------------------------------------------------------
    Note that the file spec array we return is stored in the storage that
    was passed to us as the argv array.
 -----------------------------------------------------------------------------*/
-    optStruct *option_def = malloc(100*sizeof(optStruct));
+    optEntry * option_def;
         /* Instructions to OptParseOptions2 on how to parse our options.
          */
-    optStruct2 opt;
+    optStruct3 opt;
 
     unsigned int option_def_index;
 
-    option_def_index = 0;   /* incremented by OPTENTRY */
-    OPTENTRY(0,   "verbose",     OPT_FLAG,   &cmdline_p->verbose,         0);
- 
-    /* Set the defaults */
-    cmdline_p->verbose = FALSE;
+    MALLOCARRAY_NOFAIL(option_def, 100);
 
+    option_def_index = 0;   /* incremented by OPTENT3 */
+    OPTENT3(0,   "verbose",     OPT_FLAG,   NULL, &cmdlineP->verbose,   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 */
 
-    optParseOptions2(&argc, argv, opt, 0);
-        /* Uses and sets argc, argv, and some of *cmdline_p and others. */
+    pm_optParseOptions3(&argc, (char **)argv, opt, sizeof(opt), 0);
+        /* Uses and sets argc, argv, and some of *cmdlineP and others. */
 
     if (argc-1 == 0) 
-        cmdline_p->input_filespec = "-";
+        cmdlineP->inputFileName = "-";
     else if (argc-1 != 1)
         pm_error("Program takes zero or one argument (filename).  You "
                  "specified %d", argc-1);
     else
-        cmdline_p->input_filespec = argv[1];
-
+        cmdlineP->inputFileName = argv[1];
 }
 
 
@@ -254,13 +250,13 @@ readOffBytes(FILE * const fp, unsigned int const nbytes) {
 
 
 static void
-BMPreadfileheader(FILE *         const ifP, 
+bmpReadfileheader(FILE *         const ifP, 
                   unsigned int * const bytesReadP, 
                   unsigned int * const offBitsP) {
 
-    unsigned short  xHotSpot;
-    unsigned short  yHotSpot;
-    unsigned long   offBits;
+    unsigned short    xHotSpot;
+    unsigned short    yHotSpot;
+    unsigned long     offBits;
     unsigned long int fileSize;
 
 
@@ -273,9 +269,9 @@ BMPreadfileheader(FILE *         const ifP,
 
 
     fileSize = GetLong(ifP);  /* This is not always reliable. */
-    xHotSpot  = GetShort(ifP);
-    yHotSpot  = GetShort(ifP);
-    offBits   = GetLong(ifP);
+    xHotSpot = GetShort(ifP);
+    yHotSpot = GetShort(ifP);
+    offBits  = GetLong(ifP);
 
     *offBitsP = offBits;
 
@@ -329,7 +325,7 @@ readOs2InfoHeader(FILE *                 const ifP,
                  
     headerP->pixelformat = defaultPixelformat(headerP->cBitCount);
 
-    headerP->compression = COMP_RGB;
+    headerP->compression = BMPCOMP_RGB;
     
     pm_message("OS/2 BMP, %dx%dx%d",
                headerP->cols, headerP->rows, headerP->cBitCount);
@@ -342,26 +338,26 @@ validateCompression(unsigned long const compression,
                     enum rowOrder const rowOrder,
                     unsigned int  const cBitCount) {
     
-    if (compression != COMP_RGB && compression != COMP_BITFIELDS &&
-        compression != COMP_RLE4 && compression != COMP_RLE8 ) 
+    if (compression != BMPCOMP_RGB && compression != BMPCOMP_BITFIELDS &&
+        compression != BMPCOMP_RLE4 && compression != BMPCOMP_RLE8) 
         pm_error("Input has unknown encoding.  "
                  "Compression type code = %ld.  The only ones we know "
                  "are RGB (%u), BITFIELDS (%u), "
                  "RLE4 (%u), and RLE8 (%u)",
-                 compression, COMP_RGB, COMP_BITFIELDS,
-                 COMP_RLE4, COMP_RLE8);
+                 compression, BMPCOMP_RGB, BMPCOMP_BITFIELDS,
+                 BMPCOMP_RLE4, BMPCOMP_RLE8);
                      
-    if ((compression == COMP_RLE4 || compression == COMP_RLE8) &&
+    if ((compression == BMPCOMP_RLE4 || compression == BMPCOMP_RLE8) &&
         rowOrder == TOPDOWN )                        
         pm_error("Invalid BMP header.  Claims image is top-down and also "
                  "compressed, which is an impossible combination.");
 
-    if ( (compression == COMP_RLE4 && cBitCount !=4) ||
-         (compression == COMP_RLE8 && cBitCount !=8) ) 
+    if ((compression == BMPCOMP_RLE4 && cBitCount !=4 ) ||
+        (compression == BMPCOMP_RLE8 && cBitCount !=8 )) 
         pm_error("Invalid BMP header.  " 
                  "Compression type (%s) disagrees with "
                  "number of bits per pixel (%u).",
-                 compression == COMP_RLE4 ? "RLE4" : "RLE8",
+                 compression == BMPCOMP_RLE4 ? "RLE4" : "RLE8",
                  cBitCount);
 }
 
@@ -379,18 +375,22 @@ readWindowsBasic40ByteInfoHeader(FILE *                 const ifP,
 -----------------------------------------------------------------------------*/
     int colorsimportant;   /* ColorsImportant value from header */
     int colorsused;        /* ColorsUsed value from header */
-    long colsField;
+    unsigned short planesField, bitCountField;
+    int32_t colsField;
 
     headerP->class = C_WIN;
 
-    colsField = GetLong(ifP);
-
-    if (colsField <= 0)
-        pm_error("Invalid BMP file: says width is %ld", colsField);
+    pm_readlittlelong2(ifP, &colsField);
 
-    headerP->cols = (unsigned long)colsField;
+    if (colsField == 0)
+        pm_error("Invalid BMP file: says width is zero");
+    else if (colsField < 0)
+        pm_error("Invalid BMP file: says width is negative (%d)", colsField);
+    else
+        headerP->cols = (unsigned int)colsField;
     {
         long const cy = GetLong(ifP);
+
         if (cy == 0)
             pm_error("Invalid BMP file: says height is zero");
         if (cy < 0) {
@@ -401,17 +401,18 @@ readWindowsBasic40ByteInfoHeader(FILE *                 const ifP,
             headerP->rows = cy;
         }
     }
-    headerP->cPlanes = GetShort(ifP);
-    headerP->cBitCount = GetShort(ifP);
- 
+    pm_readlittleshortu(ifP, &planesField);
+    headerP->cPlanes = planesField;
+    pm_readlittleshortu(ifP, &bitCountField);
+    headerP->cBitCount = bitCountField;
     {
         unsigned long int const compression = GetLong(ifP);
 
-        headerP->bitFields = (compression == COMP_BITFIELDS);
-
         validateCompression(compression, headerP->rowOrder,
                             headerP->cBitCount);
 
+        headerP->bitFields = (compression == BMPCOMP_BITFIELDS);
+
         headerP->compression = compression;             
     }
     /* And read the rest of the junk in the 40 byte header */
@@ -624,7 +625,7 @@ readWindowsInfoHeader(FILE *                 const ifP,
 
 
 static void
-BMPreadinfoheader(FILE *                 const ifP, 
+bmpReadinfoheader(FILE *                 const ifP, 
                   unsigned int *         const bytesReadP,
                   struct bmpInfoHeader * const headerP) {
 
@@ -656,7 +657,7 @@ BMPreadinfoheader(FILE *                 const ifP,
 
 
 static void
-BMPreadcolormap(FILE *         const ifP, 
+bmpReadColormap(FILE *         const ifP, 
                 int            const class, 
                 xel **         const colormapP, 
                 unsigned int   const cmapsize,
@@ -883,8 +884,8 @@ convertRow(unsigned char      const bmprow[],
             unsigned int const index = bmprow[col];
             validateIndex(index, cmapsize);
             xelrow[col] = colormap[index];
-        }
-    } else if (cBitCount < 8) {
+	}
+    } else if (cBitCount == 1 || cBitCount == 2 || cBitCount == 4) {
         /* It's a bit field color index */
         unsigned char const mask = ( 1 << cBitCount ) - 1;
 
@@ -898,18 +899,21 @@ convertRow(unsigned char      const bmprow[],
             validateIndex(index, cmapsize);
             xelrow[col] = colormap[index];
         }
-    } else
-        pm_error("Internal error: invalid cBitCount in convertRow()");
+    } else {
+        /* Every possible BMP bits per pixel is handled above */
+        assert(false);
+    }
 }
 
 
 
 static unsigned char **
-allocBMPraster(unsigned int const rows, unsigned int const bytesPerRow) {
+allocBmpRaster(unsigned int const rows,
+               unsigned int const bytesPerRow) {
 
     unsigned int const storageSize = 
         rows * sizeof(unsigned char *) + rows * bytesPerRow;        
-    unsigned char ** BMPraster;
+    unsigned char ** bmpRaster;
     unsigned int row;
     unsigned char * startOfRows;
 
@@ -920,18 +924,18 @@ allocBMPraster(unsigned int const rows, unsigned int const bytesPerRow) {
     if (UINT_MAX / (bytesPerRow + sizeof(unsigned char *)) < rows)
         pm_error("raster is ridiculously large.");
 
-    BMPraster = (unsigned char **) malloc(storageSize);
+    bmpRaster = (unsigned char **) malloc(storageSize);
 
-    if (BMPraster == NULL)
+    if (bmpRaster == NULL)
         pm_error("Unable to allocate %u bytes for the BMP raster\n",
                  storageSize);
 
-    startOfRows = (unsigned char *)(BMPraster + rows);
+    startOfRows = (unsigned char *)(bmpRaster + rows);
 
     for (row = 0; row < rows; ++row) 
-        BMPraster[row] = startOfRows + row * bytesPerRow;
+        bmpRaster[row] = startOfRows + row * bytesPerRow;
 
-    return BMPraster;
+    return bmpRaster;
 }
 
 
@@ -940,14 +944,14 @@ static void
 readrow(FILE *           const ifP,
         unsigned int     const row,
         unsigned int     const bytesPerRow,
-        unsigned char ** const BMPraster,
+        unsigned char ** const bmpRaster,
         unsigned int *   const bytesReadP) {
 
     size_t bytesRead;
 
     assert(bytesPerRow > 0);
     
-    bytesRead = fread(BMPraster[row], 1, bytesPerRow, ifP);
+    bytesRead = fread(bmpRaster[row], 1, bytesPerRow, ifP);
 
     if (bytesRead < bytesPerRow) {
         if (feof(ifP))
@@ -1023,12 +1027,12 @@ readrowRLE(FILE *           const ifP,
            unsigned int     const row,
            unsigned int     const cols,
            bool             const lastrow,
-           unsigned long    const compression,
-           unsigned char ** const BMPraster,
+           BMPCompType      const compression,
+           unsigned char ** const bmpRaster,
            unsigned int  *  const bytesReadP) {
 
-    bool const RLE4 = (compression == COMP_RLE4);
-    int  const pixelsPerRowMargin = RLE4 ? cols % 2 : 0;
+    bool const rle4 = (compression == BMPCOMP_RLE4);
+    int  const pixelsPerRowMargin = rle4 ? cols % 2 : 0;
 
     char const err_decode[] = 
         "Error while decoding compressed BMP image.  "
@@ -1046,17 +1050,17 @@ readrowRLE(FILE *           const ifP,
     totalBytesRead = 0;  /* Initial value */
     pixelsRead = 0;      /* Initial value */
 
-    while (TRUE) {
+    while (true) {
         unsigned int n;
             /* decompressed bytes already read; current write point */ 
         unsigned int cnt;
         unsigned char code;
 
-        n = RLE4 ? (pixelsRead + 1) / 2 : pixelsRead;
+        n = rle4 ? (pixelsRead + 1) / 2 : pixelsRead;
 
         switch (readRLEcode(ifP, &cnt, &code)) {
         case ENC_MODE: {
-            unsigned int const byteCnt = RLE4 ? (cnt + 1) /2 : cnt;
+            unsigned int const byteCnt = rle4 ? (cnt + 1) /2 : cnt;
             unsigned int i; 
 
             if (pixelsRead + cnt > cols + pixelsPerRowMargin)
@@ -1064,11 +1068,11 @@ readrowRLE(FILE *           const ifP,
                          row, pixelsRead ); 
                  
             for (i = 0; i < byteCnt; ++i)
-                BMPraster[row][n+i] = code;
+                bmpRaster[row][n+i] = code;
                  
-            if (RLE4 && pixelsRead % 2 == 1)
+            if (rle4 && pixelsRead % 2 == 1)
                 /* previous read ended odd */
-                nibbleAlign(&BMPraster[row][n-1], cnt); 
+                nibbleAlign(&bmpRaster[row][n-1], cnt); 
             
             pixelsRead += cnt;
             totalBytesRead += 2;
@@ -1078,13 +1082,13 @@ readrowRLE(FILE *           const ifP,
             unsigned int cmpBytesRead; /* compressed bytes read */
             /* align read-end to 16 bit boundary */
             unsigned int const bytesToRead =
-                RLE4 ? (cnt + 3) / 4 * 2 : (cnt + 1) / 2 * 2;
+                rle4 ? (cnt + 3) / 4 * 2 : (cnt + 1) / 2 * 2;
 
             if (pixelsRead + cnt > cols + pixelsPerRowMargin)
                 pm_error(err_decode,  "Too many pixels in absolute mode",
                          row, pixelsRead); 
 
-            cmpBytesRead = fread(&BMPraster[row][n], 
+            cmpBytesRead = fread(&bmpRaster[row][n], 
                                  sizeof(char), bytesToRead, ifP);
 
             if (cmpBytesRead < bytesToRead) {
@@ -1095,8 +1099,8 @@ readrowRLE(FILE *           const ifP,
                     pm_error("Error reading BMP raster.  Errno=%d (%s)",
                              errno, strerror(errno));
             }
-            if (RLE4 && pixelsRead % 2 == 1) /* previous read ended odd */
-                nibbleAlign(&BMPraster[row][n-1], cnt); 
+            if (rle4 && pixelsRead % 2 == 1) /* previous read ended odd */
+                nibbleAlign(&bmpRaster[row][n-1], cnt); 
     
             pixelsRead += cnt;
             totalBytesRead += cmpBytesRead + 2;
@@ -1146,25 +1150,36 @@ readrowRLE(FILE *           const ifP,
 
 
 static void
-BMPreadraster(FILE *            const ifP, 
+bmpReadraster(FILE *            const ifP, 
               unsigned int      const cols, 
               unsigned int      const rows, 
               enum rowOrder     const rowOrder,
               unsigned int      const cBitCount, 
-              unsigned long int const compression,
-              unsigned char *** const BMPrasterP, 
+              BMPCompType       const compression,
+              unsigned char *** const bmpRasterP, 
               unsigned int *    const bytesReadP) {
+/*----------------------------------------------------------------------------
+   Read the raster from the BMP file on *ifP (which is positioned to the
+   raster).  The raster is 'rows' rows of 'cols' columns, 'cBitCount' bits per
+   pixel, with rows in order 'rowOrder'.
+
+   Return the raster in a newly malloced 2-dimensional array and return
+   a pointer to that array as *bmpRasterP.
 
+   Leave the input file positioned immediately after the raster and return
+   as *bytesReadP the number of bytes we read from the file (i.e. the number
+   of bytes in the raster portion of the file).
+-----------------------------------------------------------------------------*/
     unsigned int const bytesPerRow =
-        (compression == COMP_RLE4) ? cols / 2 + 2 :
-        (compression == COMP_RLE8) ? cols + 1 :
+        (compression == BMPCOMP_RLE4) ? cols / 2 + 2 :
+        (compression == BMPCOMP_RLE8) ? cols + 1 :
         ((cols * cBitCount + 31) / 32) * 4;
         /* A BMP raster row is a multiple of 4 bytes, padded on the right
            with don't cares.
         */
-    unsigned char ** BMPraster;
+    unsigned char ** bmpRaster;
 
-    BMPraster = allocBMPraster(rows, bytesPerRow);
+    bmpRaster = allocBmpRaster(rows, bytesPerRow);
 
     *bytesReadP = 0;
 
@@ -1175,31 +1190,36 @@ BMPreadraster(FILE *            const ifP,
     */
     
     switch(compression){
-    case COMP_RGB:
-    case COMP_BITFIELDS: {
+    case BMPCOMP_RGB:
+    case BMPCOMP_BITFIELDS: {
         unsigned int i;
         for (i = 0; i < rows; ++i)
             readrow(ifP, rowOrder == TOPDOWN ? i : rows - i - 1, 
-                    bytesPerRow, BMPraster, bytesReadP);
+                    bytesPerRow, bmpRaster, bytesReadP);
     } break;
-    case COMP_RLE4: 
-    case COMP_RLE8: {
+    case BMPCOMP_RLE4: 
+    case BMPCOMP_RLE8: {
         unsigned int i;
         /* Read all rows except last */
+        assert(rows >= 1);
         for (i = 0; i < rows - 1; ++i){
             readrowRLE(ifP, rowOrder == TOPDOWN ? i : rows - i - 1, 
-                       cols, FALSE, compression, BMPraster, bytesReadP);
+                       cols, FALSE, compression, bmpRaster, bytesReadP);
         }
         /* Read last row */
         readrowRLE(ifP, rowOrder == TOPDOWN ? i : rows - i - 1, 
-                   cols, TRUE,  compression, BMPraster, bytesReadP);
+                   cols, TRUE,  compression, bmpRaster, bytesReadP);
     } break;             
-    default:       
-        pm_error("The BMP specifies a compression scheme we don't "
-                 "recognize.  Code= %lu", compression);
+    case BMPCOMP_JPEG:
+        pm_error("BMP file uses JPEG compression.  We don't know how to "
+                 "interpret that.");
+        break;
+    case BMPCOMP_PNG:
+        pm_error("BMP file uses PNG compression.  We don't know how to "
+                 "interpret that.");
+        break;
     }
-
-    *BMPrasterP = BMPraster;
+    *bmpRasterP = bmpRaster;
 }
 
 
@@ -1220,14 +1240,7 @@ reportHeader(struct bmpInfoHeader const header,
                header.rowOrder == BOTTOMUP ? "bottom up" : "top down");
     pm_message("  Byte offset of raster within file: %u", offBits);
     pm_message("  Bits per pixel in raster: %u", header.cBitCount);
-    pm_message("  Compression: %s", 
-               header.compression == COMP_RGB ? "none" :
-               header.compression == COMP_RLE4 ? "4 bit run-length coding" :
-               header.compression == COMP_RLE8 ? "8 bit run-length coding" :
-               header.compression == COMP_BITFIELDS ? "none" :
-               header.compression == COMP_JPEG ? "JPEG (not supported)" :
-               header.compression == COMP_PNG ? "PNG (not supported)" :
-               "???");                
+    pm_message("  Compression: %s", BMPCompTypeName(header.compression));
     pm_message("  Colors in color map: %u", header.cmapsize);
 }        
 
@@ -1265,11 +1278,11 @@ analyzeColors(xel          const colormap[],
 
 
 static void
-warnIfOffBitsWrong(struct bmpInfoHeader const BMPheader,
+warnIfOffBitsWrong(struct bmpInfoHeader const bmpHeader,
                    unsigned int         const offBits) {
 
-    if (offBits != BMPoffbits(BMPheader.class, BMPheader.cBitCount, 
-                              BMPheader.cmapsize)) {
+    if (offBits != BMPoffbits(bmpHeader.class, bmpHeader.cBitCount, 
+                              bmpHeader.cmapsize)) {
 
         pm_message("warning: the BMP header says the raster starts "
                    "at offset %u bytes into the file (offbits), "
@@ -1277,8 +1290,8 @@ warnIfOffBitsWrong(struct bmpInfoHeader const BMPheader,
                    "the raster.  This inconsistency probably means the "
                    "input file is not a legal BMP file and is unusable.",
                    offBits,
-                   BMPoffbits(BMPheader.class, BMPheader.cBitCount, 
-                              BMPheader.cmapsize));
+                   BMPoffbits(bmpHeader.class, bmpHeader.cBitCount, 
+                              bmpHeader.cmapsize));
     }
 }
 
@@ -1286,63 +1299,37 @@ warnIfOffBitsWrong(struct bmpInfoHeader const BMPheader,
 
 static void
 readColorMap(FILE *               const ifP,
-             struct bmpInfoHeader const BMPheader,
+             struct bmpInfoHeader const bmpHeader,
              xel **               const colorMapP,
              unsigned int *       const posP) {
 
     unsigned int bytesRead;
 
-    BMPreadcolormap(ifP, BMPheader.class, 
-                    colorMapP, BMPheader.cmapsize, &bytesRead);
+    bmpReadColormap(ifP, bmpHeader.class, 
+                    colorMapP, bmpHeader.cmapsize, &bytesRead);
 
     *posP += bytesRead;
-
-    if (bytesRead != BMPlencolormap(BMPheader.class, BMPheader.cBitCount, 
-                                    BMPheader.cmapsize)) {
-
-        pm_message("warning: %u-byte RGB table, expected %u bytes",
-                   bytesRead,
-                   BMPlencolormap(BMPheader.class, BMPheader.cBitCount, 
-                                  BMPheader.cmapsize));
-    }
 }
 
 
 
 static void
 readRaster(FILE *               const ifP,
-           struct bmpInfoHeader const BMPheader,
-           unsigned char ***    const BMPrasterP, 
+           struct bmpInfoHeader const bmpHeader,
+           unsigned char ***    const bmpRasterP, 
            unsigned int *       const posP) {
 
     unsigned int bytesRead;
 
-    BMPreadraster(ifP, BMPheader.cols, BMPheader.rows, BMPheader.rowOrder,
-                  BMPheader.cBitCount, BMPheader.compression,
-                  BMPrasterP, &bytesRead);
+    bmpReadraster(ifP, bmpHeader.cols, bmpHeader.rows, bmpHeader.rowOrder,
+                  bmpHeader.cBitCount, bmpHeader.compression,
+                  bmpRasterP, &bytesRead);
 
     *posP += bytesRead;
 }
 
 
 
-static void
-warnIfBadFileSize(struct bmpInfoHeader const BMPheader,
-                  unsigned int         const pos) {
-
-    unsigned int const expectedSize =
-        BMPlenfileGen(BMPheader.class, BMPheader.cBitCount, 
-                      BMPheader.cmapsize, BMPheader.cols,
-                      BMPheader.rows, BMPheader.imageSize,
-                      BMPheader.compression);
-
-    if (pos != expectedSize)
-        pm_message("warning: read %u bytes, expected to read %u bytes",
-                   pos, expectedSize);
-}
-
-
-
 static bool
 isValidBmpBpp(unsigned int const cBitCount) {
 
@@ -1364,7 +1351,7 @@ isValidBmpBpp(unsigned int const cBitCount) {
 
 static void
 readBmp(FILE *               const ifP, 
-        unsigned char ***    const BMPrasterP, 
+        unsigned char ***    const bmpRasterP, 
         int *                const colsP, 
         int *                const rowsP,
         bool *               const grayPresentP, 
@@ -1383,60 +1370,59 @@ readBmp(FILE *               const ifP,
     
     unsigned int offBits;
         /* Byte offset into file of raster */
-    struct bmpInfoHeader BMPheader;
+    struct bmpInfoHeader bmpHeader;
 
     pos = 0;  /* Starting at the beginning ... */
     { 
         unsigned int bytesRead;
-        BMPreadfileheader(ifP, &bytesRead, &offBits);
+        bmpReadfileheader(ifP, &bytesRead, &offBits);
         pos += bytesRead;
     }
     {
         unsigned int bytesRead;
-        BMPreadinfoheader(ifP, &bytesRead, &BMPheader);
+        bmpReadinfoheader(ifP, &bytesRead, &bmpHeader);
         if (verbose)
             pm_message("Read %u bytes of header", bytesRead);
         pos += bytesRead;
     }
 
     if (verbose) 
-        reportHeader(BMPheader, offBits);
+        reportHeader(bmpHeader, offBits);
 
-    warnIfOffBitsWrong(BMPheader, offBits);
+    warnIfOffBitsWrong(bmpHeader, offBits);
 
-    readColorMap(ifP, BMPheader, &colormap, &pos);
+    readColorMap(ifP, bmpHeader, &colormap, &pos);
 
-    analyzeColors(colormap, BMPheader.cmapsize, bmpMaxval, 
+    analyzeColors(colormap, bmpHeader.cmapsize, bmpMaxval, 
                   grayPresentP, colorPresentP);
 
     readOffBytes(ifP, offBits - pos);
 
     pos = offBits;
 
-    readRaster(ifP, BMPheader, BMPrasterP, &pos);
+    readRaster(ifP, bmpHeader, bmpRasterP, &pos);
 
-    warnIfBadFileSize(BMPheader, pos);
-    
     if (fgetc(ifP) != EOF)
         pm_message("warning: some image data remains unread.");
     
-    if (!isValidBmpBpp(BMPheader.cBitCount))
+    if (!isValidBmpBpp(bmpHeader.cBitCount))
         pm_error("Invalid BMP image: 'cBitCount' field of header "
                  "(number of bits for each pixel in raster) is %u",
-                 BMPheader.cBitCount);
+                 bmpHeader.cBitCount);
 
-    *colsP        = BMPheader.cols;
-    *rowsP        = BMPheader.rows;
-    *cBitCountP   = BMPheader.cBitCount;
-    *pixelformatP = BMPheader.pixelformat;
+    *cBitCountP   = bmpHeader.cBitCount;
+
+    *colsP        = bmpHeader.cols;
+    *rowsP        = bmpHeader.rows;
+    *pixelformatP = bmpHeader.pixelformat;
     *colormapP    = colormap;
-    *cmapsizeP    = BMPheader.cmapsize;
+    *cmapsizeP    = bmpHeader.cmapsize;
 }
 
 
 
 static void
-writeRasterGen(unsigned char **   const BMPraster,
+writeRasterGen(unsigned char **   const bmpRaster,
                int                const cols, 
                int                const rows, 
                int                const format,
@@ -1446,7 +1432,7 @@ writeRasterGen(unsigned char **   const BMPraster,
                unsigned int       const cmapsize) {
 /*----------------------------------------------------------------------------
   Write the PNM raster to Standard Output, corresponding to the raw BMP
-  raster BMPraster.  Write the raster assuming the PNM image has 
+  raster bmpRaster.  Write the raster assuming the PNM image has 
   dimensions 'cols' by 'rows' and format 'format', with maxval 255.
 
   The BMP image has 'cBitCount' bits per pixel, arranged in format
@@ -1463,7 +1449,7 @@ writeRasterGen(unsigned char **   const BMPraster,
     xelrow = pnm_allocrow(cols);
 
     for (row = 0; row < rows; ++row) {
-        convertRow(BMPraster[row], xelrow, cols, cBitCount, pixelformat,
+        convertRow(bmpRaster[row], xelrow, cols, cBitCount, pixelformat,
                    colormap, cmapsize);
         pnm_writepnmrow(stdout, xelrow, cols, bmpMaxval, format, FALSE);
     }
@@ -1473,13 +1459,13 @@ writeRasterGen(unsigned char **   const BMPraster,
 
 
 static void
-writeRasterPbm(unsigned char ** const BMPraster,
+writeRasterPbm(unsigned char ** const bmpRaster,
                int              const cols, 
                int              const rows, 
                xel              const colormap[]) {
 /*----------------------------------------------------------------------------
   Write the PBM raster to Standard Output corresponding to the raw BMP
-  raster BMPraster.  Write the raster assuming the PBM image has 
+  raster bmpRaster.  Write the raster assuming the PBM image has 
   dimensions 'cols' by 'rows'.
 
   The BMP image has 'cBitCount' bits per pixel, arranged in format
@@ -1490,10 +1476,8 @@ writeRasterPbm(unsigned char ** const BMPraster,
   abnormal case in which colormap[0] and colormap[1] have the same
   value (i.e. both white or both black.)
   
-  We destroy *BMPraster as a side effect.
+  We destroy *bmpRaster as a side effect.
 -----------------------------------------------------------------------------*/
-    unsigned int const charBits = (sizeof(unsigned char) * 8);
-        /* Number of bits in a character */
     unsigned int const colChars = pbm_packed_bytes(cols);
     
     int row;
@@ -1506,20 +1490,15 @@ writeRasterPbm(unsigned char ** const BMPraster,
         colorformat = BlackWhite;
         
     for (row=0; row < rows; ++row){
-        unsigned char * const bitrow = BMPraster[row]; 
+        unsigned char * const bitrow = bmpRaster[row]; 
 
         if (colorformat == BlackWhite) {
             unsigned int i;
             for (i = 0; i < colChars; ++i) 
                 bitrow[i] = ~bitrow[i]; /* flip all pixels */ 
         }   
-            
-        if (cols % 8 > 0) {
-            /* adjust final partial byte */
-            bitrow[colChars-1] >>= charBits - cols % charBits;
-            bitrow[colChars-1] <<= charBits - cols % charBits;
-        }
-        
+
+        pbm_cleanrowend_packed(bitrow, cols);
         pbm_writepbmrow_packed(stdout, bitrow, cols, FALSE);
     }
 }
@@ -1527,9 +1506,9 @@ writeRasterPbm(unsigned char ** const BMPraster,
 
 
 int
-main(int argc, char ** argv) {
+main(int argc, const char ** argv) {
 
-    struct cmdline_info cmdline;
+    struct cmdlineInfo cmdline;
     FILE * ifP;
     int outputType;
 
@@ -1539,10 +1518,10 @@ main(int argc, char ** argv) {
            and gray.
         */
     int cols, rows;
-    unsigned char **BMPraster;
+    unsigned char **bmpRaster;
         /* The raster part of the BMP image, as a row x column array, with
            each element being a raw byte from the BMP raster.  Note that
-           BMPraster[0] is really Row 0 -- the top row of the image, even
+           bmpRaster[0] is really Row 0 -- the top row of the image, even
            though the bottom row comes first in the BMP format.
         */
     unsigned int cBitCount;
@@ -1561,17 +1540,17 @@ main(int argc, char ** argv) {
            allow files with just 1.
 	 */
 
-    pnm_init(&argc, argv);
+    pm_proginit(&argc, argv);
 
-    parse_command_line(argc, argv, &cmdline);
+    parseCommandLine(argc, argv, &cmdline);
 
-    ifP = pm_openr(cmdline.input_filespec);
-    if (streq(cmdline.input_filespec, "-"))
+    ifP = pm_openr(cmdline.inputFileName);
+    if (streq(cmdline.inputFileName, "-"))
         ifname = "Standard Input";
     else 
-        ifname = cmdline.input_filespec;
+        ifname = cmdline.inputFileName;
 
-    readBmp(ifP, &BMPraster, &cols, &rows, &grayPresent, &colorPresent, 
+    readBmp(ifP, &bmpRaster, &cols, &rows, &grayPresent, &colorPresent, 
             &cBitCount, &pixelformat, &colormap, &cmapsize,
             cmdline.verbose);
     pm_close(ifP);
@@ -1589,14 +1568,14 @@ main(int argc, char ** argv) {
     
     if (outputType == PBM_TYPE  && cBitCount == 1){
         pbm_writepbminit(stdout, cols, rows, FALSE);
-        writeRasterPbm(BMPraster, cols, rows, colormap);
+        writeRasterPbm(bmpRaster, cols, rows, colormap);
     } else {
         pnm_writepnminit(stdout, cols, rows, bmpMaxval, outputType, FALSE);
-        writeRasterGen(BMPraster, cols, rows, outputType, cBitCount,
+        writeRasterGen(bmpRaster, cols, rows, outputType, cBitCount,
                        pixelformat, colormap, cmapsize); 
     }
     free(colormap);
-    free(BMPraster);
+    free(bmpRaster);
 
     return 0;
 }
diff --git a/converter/other/cameratopam/Makefile b/converter/other/cameratopam/Makefile
index 20a95aa2..d6207aea 100644
--- a/converter/other/cameratopam/Makefile
+++ b/converter/other/cameratopam/Makefile
@@ -9,7 +9,7 @@ EXTERN_INCLUDES =
 ifneq ($(JPEGLIB),NONE)
   ifneq ($(JPEGHDR_DIR)x,x)
     EXTERN_INCLUDES += -I$(JPEGHDR_DIR)
-    CFLAGS += -DHAVE_JPEG
+    HAVE_JPEG_DEFINE = -DHAVE_JPEG
   endif
 endif
 
@@ -19,20 +19,20 @@ include $(BUILDDIR)/config.mk
 .PHONY: all
 all: cameratopam
 
-OBJECTS = util.o identify.o cameratopam.o camera.o foveon.o decode.o \
+ADDL_OBJECTS = util.o identify.o camera.o foveon.o decode.o \
 	canon.o ljpeg.o dng.o
 
-MERGE_OBJECTS =
+OBJECTS = cameratopam.o $(ADDL_OBJECTS)
 
-BINARIES = cameratopam
-MERGEBINARIES = 
+camera.o camera.o2: CFLAGS_TARGET = $(HAVE_JPEG_DEFINE)
+
+MERGE_OBJECTS = cameratopam.o2 $(ADDL_OBJECTS)
+
+PORTBINARIES = cameratopam
+BINARIES = $(PORTBINARIES)
+MERGEBINARIES = cameratopam
 SCRIPTS = 
 
 include $(SRCDIR)/common.mk
 
-cameratopam: $(OBJECTS) $(NETPBMLIB) $(LIBOPT)
-	$(LD) -o $@ \
-          $(OBJECTS) $(shell $(LIBOPT) $(NETPBMLIB) $(LIBOPTR)) \
-	  $(MATHLIB) $(LDFLAGS) $(LDLIBS) \
-	  $(RPATH) $(LADD)
-
+cameratopam: $(ADDL_OBJECTS)
diff --git a/converter/other/cameratopam/camera.c b/converter/other/cameratopam/camera.c
index 98d6d37a..a1adba95 100644
--- a/converter/other/cameratopam/camera.c
+++ b/converter/other/cameratopam/camera.c
@@ -12,10 +12,13 @@
 #include <jpeglib.h>
 #endif
 
+#include "pm_config.h"
 #include "pm.h"
 #include "mallocvar.h"
+#include "pm_c_util.h"
 
 #include "global_variables.h"
+#include "cameratopam.h"
 #include "util.h"
 #include "decode.h"
 #include "bayer.h"
@@ -54,67 +57,76 @@ merror (const void *ptr, const char *where)
 
 
 static void  
-adobe_copy_pixel (int row, int col, unsigned short **rp, bool use_secondary)
-{
-  unsigned r=row, c=col;
-
-  if (fuji_secondary && use_secondary) (*rp)++;
-  if (filters) {
-    if (fuji_width) {
-      r = row + fuji_width - 1 - (col >> 1);
-      c = row + ((col+1) >> 1);
-    }
-    if (r < height && c < width)
-      BAYER(r,c) = **rp < 0x1000 ? curve[**rp] : **rp;
-    *rp += 1 + fuji_secondary;
-  } else
-    for (c=0; c < tiff_samples; c++) {
-      image[row*width+col][c] = **rp < 0x1000 ? curve[**rp] : **rp;
-      (*rp)++;
+adobeCopyPixel(Image             const image,
+               unsigned int      const row,
+               unsigned int      const col,
+               unsigned short ** const rp,
+               bool              const useSecondary) {
+
+    unsigned r=row, c=col;
+
+    if (fuji_secondary && useSecondary)
+        ++(*rp);
+    if (filters) {
+        if (fuji_width) {
+            r = row + fuji_width - 1 - (col >> 1);
+            c = row + ((col+1) >> 1);
+        }
+        if (r < height && c < width)
+            BAYER(r,c) = **rp < 0x1000 ? curve[**rp] : **rp;
+        *rp += 1 + fuji_secondary;
+    } else {
+        unsigned int c;
+        for (c = 0; c < tiff_samples; ++c) {
+            image[row*width+col][c] = **rp < 0x1000 ? curve[**rp] : **rp;
+            ++(*rp);
+        }
     }
-  if (fuji_secondary && use_secondary) (*rp)--;
+    if (fuji_secondary && useSecondary)
+        --(*rp);
 }
 
 void
-adobe_dng_load_raw_lj()
-{
-  int save, twide, trow=0, tcol=0, jrow, jcol;
-  struct jhead jh;
-  unsigned short *rp;
+adobe_dng_load_raw_lj(Image const image) {
 
-  while (1) {
-    save = ftell(ifp);
-    fseek (ifp, get4(ifp), SEEK_SET);
-    if (!ljpeg_start (ifp, &jh)) break;
-    if (trow >= raw_height) break;
-    if (jh.high > raw_height-trow)
-    jh.high = raw_height-trow;
-    twide = jh.wide;
-    if (filters) twide *= jh.clrs;
-    else         colors = jh.clrs;
-    if (fuji_secondary) twide /= 2;
-    if (twide > raw_width-tcol)
-    twide = raw_width-tcol;
-
-    for (jrow=0; jrow < jh.high; jrow++) {
-      ljpeg_row (&jh);
-      for (rp=jh.row, jcol=0; jcol < twide; jcol++)
-    adobe_copy_pixel (trow+jrow, tcol+jcol, &rp, use_secondary);
-    }
-    fseek (ifp, save+4, SEEK_SET);
-    if ((tcol += twide) >= raw_width) {
-      tcol = 0;
-      trow += jh.high;
+    int save, twide, trow=0, tcol=0, jrow, jcol;
+    struct jhead jh;
+    unsigned short *rp;
+
+    while (1) {
+        save = ftell(ifp);
+        fseek (ifp, get4(ifp), SEEK_SET);
+        if (!ljpeg_start (ifp, &jh)) break;
+        if (trow >= raw_height) break;
+        if (jh.high > raw_height-trow)
+            jh.high = raw_height-trow;
+        twide = jh.wide;
+        if (filters) twide *= jh.clrs;
+        else         colors = jh.clrs;
+        if (fuji_secondary) twide /= 2;
+        if (twide > raw_width-tcol)
+            twide = raw_width-tcol;
+
+        for (jrow=0; jrow < jh.high; jrow++) {
+            ljpeg_row(ifp, &jh);
+            for (rp=jh.row, jcol=0; jcol < twide; jcol++)
+                adobeCopyPixel(image,
+                               trow+jrow, tcol+jcol, &rp, use_secondary);
+        }
+        fseek (ifp, save+4, SEEK_SET);
+        if ((tcol += twide) >= raw_width) {
+            tcol = 0;
+            trow += jh.high;
+        }
+        free (jh.row);
     }
-    free (jh.row);
-  }
 }
 
 
 
 void
-adobe_dng_load_raw_nc()
-{
+adobe_dng_load_raw_nc(Image const image) {
+
     unsigned short *pixel, *rp;
     int row, col;
 
@@ -123,7 +135,7 @@ adobe_dng_load_raw_nc()
     for (row=0; row < raw_height; row++) {
         read_shorts (ifp, pixel, raw_width * tiff_samples);
         for (rp=pixel, col=0; col < raw_width; col++)
-            adobe_copy_pixel (row, col, &rp, use_secondary);
+            adobeCopyPixel(image, row, col, &rp, use_secondary);
     }
     free (pixel);
 }
@@ -133,8 +145,8 @@ adobe_dng_load_raw_nc()
 static int nikon_curve_offset;
 
 void
-nikon_compressed_load_raw(void)
-{
+nikon_compressed_load_raw(Image const image) {
+
     static const unsigned char nikon_tree[] = {
         0,1,5,1,1,1,1,1,1,2,0,0,0,0,0,0,
         5,4,3,6,2,7,1,0,8,9,11,10,12
@@ -158,7 +170,7 @@ nikon_compressed_load_raw(void)
     for (row=0; row < height; row++)
         for (col=0; col < raw_width; col++)
         {
-            diff = ljpeg_diff (first_decode);
+            diff = ljpeg_diff (ifp, first_decode);
             if (col < 2) {
                 i = 2*(row & 1) + (col & 1);
                 vpred[i] += diff;
@@ -175,8 +187,8 @@ nikon_compressed_load_raw(void)
 }
 
 void
-nikon_load_raw()
-{
+nikon_load_raw(Image const image) {
+
   int irow, row, col, i;
 
   getbits(ifp, -1);
@@ -293,8 +305,8 @@ minolta_z2()
 }
 
 void
-nikon_e2100_load_raw()
-{
+nikon_e2100_load_raw(Image const image) {
+        
   unsigned char   data[3432], *dp;
   unsigned short pixel[2288], *pix;
   int row, col;
@@ -321,8 +333,8 @@ nikon_e2100_load_raw()
 }
 
 void
-nikon_e950_load_raw()
-{
+nikon_e950_load_raw(Image const image) {
+
   int irow, row, col;
 
   getbits(ifp, -1);
@@ -340,8 +352,7 @@ nikon_e950_load_raw()
    The Fuji Super CCD is just a Bayer grid rotated 45 degrees.
  */
 void
-fuji_s2_load_raw()
-{
+fuji_s2_load_raw(Image const image) {
   unsigned short pixel[2944];
   int row, col, r, c;
 
@@ -357,8 +368,7 @@ fuji_s2_load_raw()
 }
 
 void
-fuji_s3_load_raw()
-{
+fuji_s3_load_raw(Image const image) {
   unsigned short pixel[4352];
   int row, col, r, c;
 
@@ -373,42 +383,52 @@ fuji_s3_load_raw()
   }
 }
 
-static void  fuji_common_load_raw (int ncol, int icol, int nrow)
-{
-  unsigned short pixel[2048];
-  int row, col, r, c;
-
-  for (row=0; row < nrow; row++) {
-    read_shorts(ifp, pixel, ncol);
-    for (col=0; col <= icol; col++) {
-      r = icol - col + (row >> 1);
-      c = col + ((row+1) >> 1);
-      BAYER(r,c) = pixel[col];
+static void 
+fuji_common_load_raw(Image        const image,
+                     unsigned int const ncol,
+                     unsigned int const icol,
+                     unsigned int const nrow) {
+
+    unsigned short pixel[2048];
+    unsigned int row;
+
+    for (row = 0; row < nrow; ++row) {
+        unsigned int col;
+        read_shorts(ifp, pixel, ncol);
+        for (col = 0; col <= icol; ++col) {
+            int const r = icol - col + (row >> 1);
+            int const c = col + ((row+1) >> 1);
+            BAYER(r,c) = pixel[col];
+        }
     }
-  }
 }
 
+
+
 void
-fuji_s5000_load_raw()
-{
+fuji_s5000_load_raw(Image const image) {
+
   fseek (ifp, (1472*4+24)*2, SEEK_CUR);
-  fuji_common_load_raw (1472, 1423, 2152);
+  fuji_common_load_raw(image, 1472, 1423, 2152);
 }
 
+
+
 void
-fuji_s7000_load_raw()
-{
-  fuji_common_load_raw (2048, 2047, 3080);
+fuji_s7000_load_raw(Image const image) {
+
+    fuji_common_load_raw(image, 2048, 2047, 3080);
 }
 
+
+
 /*
    The Fuji Super CCD SR has two photodiodes for each pixel.
    The secondary has about 1/16 the sensitivity of the primary,
    but this ratio may vary.
  */
 void
-fuji_f700_load_raw()
-{
+fuji_f700_load_raw(Image const image) {
   unsigned short pixel[2944];
   int row, col, r, c, val;
 
@@ -424,8 +444,7 @@ fuji_f700_load_raw()
 }
 
 void
-rollei_load_raw()
-{
+rollei_load_raw(Image const image) {
   unsigned char pixel[10];
   unsigned iten=0, isix, i, buffer=0, row, col, todo[16];
 
@@ -451,8 +470,7 @@ rollei_load_raw()
 }
 
 void
-phase_one_load_raw()
-{
+phase_one_load_raw(Image const image) {
   int row, col, a, b;
   unsigned short *pixel, akey, bkey;
 
@@ -478,8 +496,7 @@ phase_one_load_raw()
 }
 
 void
-ixpress_load_raw()
-{
+ixpress_load_raw(Image const image) {
   unsigned short pixel[4090];
   int row, col;
 
@@ -493,8 +510,7 @@ ixpress_load_raw()
 }
 
 void
-leaf_load_raw()
-{
+leaf_load_raw(Image const image) {
   unsigned short *pixel;
   int r, c, row, col;
 
@@ -513,8 +529,7 @@ leaf_load_raw()
    For this function only, raw_width is in bytes, not pixels!
  */
 void
-packed_12_load_raw()
-{
+packed_12_load_raw(Image const image) {
   int row, col;
 
   getbits(ifp, -1);
@@ -527,8 +542,7 @@ packed_12_load_raw()
 }
 
 void
-unpacked_load_raw()
-{
+unpacked_load_raw(Image const image) {
   unsigned short *pixel;
   int row, col;
 
@@ -543,8 +557,7 @@ unpacked_load_raw()
 }
 
 void
-olympus_e300_load_raw()
-{
+olympus_e300_load_raw(Image const image) {
   unsigned char  *data,  *dp;
   unsigned short *pixel, *pix;
   int dwide, row, col;
@@ -567,8 +580,7 @@ olympus_e300_load_raw()
 }
 
 void
-olympus_cseries_load_raw()
-{
+olympus_cseries_load_raw(Image const image) {
   int irow, row, col;
 
   for (irow=0; irow < height; irow++) {
@@ -583,8 +595,7 @@ olympus_cseries_load_raw()
 }
 
 void
-eight_bit_load_raw()
-{
+eight_bit_load_raw(Image const image) {
   unsigned char *pixel;
   int row, col;
 
@@ -600,8 +611,7 @@ eight_bit_load_raw()
 }
 
 void
-casio_qv5700_load_raw()
-{
+casio_qv5700_load_raw(Image const image) {
   unsigned char  data[3232],  *dp;
   unsigned short pixel[2576], *pix;
   int row, col;
@@ -621,8 +631,7 @@ casio_qv5700_load_raw()
 }
 
 void
-nucore_load_raw()
-{
+nucore_load_raw(Image const image) {
   unsigned short *pixel;
   int irow, row, col;
 
@@ -684,79 +693,91 @@ static int  radc_token (int tree)
 : (buf[c][y-1][x+1] + 2*buf[c][y-1][x] + buf[c][y][x+1]) / 4)
 
 void
-kodak_radc_load_raw()
-{
-  int row, col, tree, nreps, rep, step, i, c, s, r, x, y, val;
-  short last[3] = { 16,16,16 }, mul[3], buf[3][3][386];
+kodak_radc_load_raw(Image const image) {
+    int row, col, tree, nreps, rep, step, c, s, r, x, y, val;
+    unsigned int i;
+    short last[3] = { 16,16,16 }, mul[3], buf[3][3][386];
 
-  init_decoder();
-  getbits(ifp, -1);
-  for (i=0; i < sizeof(buf)/sizeof(short); i++)
-    buf[0][0][i] = 2048;
-  for (row=0; row < height; row+=4) {
-    for (i=0; i < 3; i++)
-      mul[i] = getbits(ifp, 6);
-    FORC3 {
-      val = ((0x1000000/last[c] + 0x7ff) >> 12) * mul[c];
-      s = val > 65564 ? 10:12;
-      x = ~(-1 << (s-1));
-      val <<= 12-s;
-      for (i=0; i < sizeof(buf[0])/sizeof(short); i++)
-    buf[c][0][i] = (buf[c][0][i] * val + x) >> s;
-      last[c] = mul[c];
-      for (r=0; r <= !c; r++) {
-    buf[c][1][width/2] = buf[c][2][width/2] = mul[c] << 7;
-    for (tree=1, col=width/2; col > 0; ) {
-      if ((tree = radc_token(tree))) {
-        col -= 2;
-        if (tree == 8)
-          FORYX buf[c][y][x] = radc_token(tree+10) * mul[c];
-        else
-          FORYX buf[c][y][x] = radc_token(tree+10) * 16 + PREDICTOR;
-      } else
-        do {
-          nreps = (col > 2) ? radc_token(9) + 1 : 1;
-          for (rep=0; rep < 8 && rep < nreps && col > 0; rep++) {
-        col -= 2;
-        FORYX buf[c][y][x] = PREDICTOR;
-        if (rep & 1) {
-          step = radc_token(10) << 4;
-          FORYX buf[c][y][x] += step;
+    init_decoder();
+    getbits(ifp, -1);
+    for (i = 0; i < ARRAY_SIZE(buf); ++i) {
+        unsigned int j;
+        for (j = 0; j < ARRAY_SIZE(buf[0]); ++j) {
+            unsigned int k;
+            for (k = 0; k < ARRAY_SIZE(buf[0][0]); ++k)
+                buf[i][j][k] = 2048;
         }
-          }
-        } while (nreps == 9);
-    }
-    for (y=0; y < 2; y++)
-      for (x=0; x < width/2; x++) {
-        val = (buf[c][y+1][x] << 4) / mul[c];
-        if (val < 0) val = 0;
-        if (c)
-          BAYER(row+y*2+c-1,x*2+2-c) = val;
-        else
-          BAYER(row+r*2+y,x*2+y) = val;
-      }
-    memcpy (buf[c][0]+!c, buf[c][2], sizeof buf[c][0]-2*!c);
-      }
-    }
-    for (y=row; y < row+4; y++)
-      for (x=0; x < width; x++)
-    if ((x+y) & 1) {
-      val = (BAYER(y,x)-2048)*2 + (BAYER(y,x-1)+BAYER(y,x+1))/2;
-      if (val < 0) val = 0;
-      BAYER(y,x) = val;
     }
-  }
-  maximum = 0x1fff;     /* wild guess */
+    for (row=0; row < height; row+=4) {
+        unsigned int i;
+        for (i = 0; i < 3; ++i)
+            mul[i] = getbits(ifp, 6);
+        FORC3 {
+            val = ((0x1000000/last[c] + 0x7ff) >> 12) * mul[c];
+            s = val > 65564 ? 10:12;
+            x = ~(-1 << (s-1));
+            val <<= 12-s;
+            for (i=0; i < ARRAY_SIZE(buf[c][0]); i++)
+                buf[c][0][i] = (buf[c][0][i] * val + x) >> s;
+            last[c] = mul[c];
+            for (r=0; r <= !c; r++) {
+                buf[c][1][width/2] = buf[c][2][width/2] = mul[c] << 7;
+                for (tree=1, col=width/2; col > 0; ) {
+                    if ((tree = radc_token(tree))) {
+                        col -= 2;
+                        if (tree == 8)
+                            FORYX buf[c][y][x] =
+                                radc_token(tree+10) * mul[c];
+                        else
+                            FORYX buf[c][y][x] =
+                                radc_token(tree+10) * 16 + PREDICTOR;
+                    } else
+                        do {
+                            nreps = (col > 2) ? radc_token(9) + 1 : 1;
+                            for (rep=0;
+                                 rep < 8 && rep < nreps && col > 0;
+                                 rep++) {
+                                col -= 2;
+                                FORYX buf[c][y][x] = PREDICTOR;
+                                if (rep & 1) {
+                                    step = radc_token(10) << 4;
+                                    FORYX buf[c][y][x] += step;
+                                }
+                            }
+                        } while (nreps == 9);
+                }
+                for (y=0; y < 2; y++)
+                    for (x=0; x < width/2; x++) {
+                        val = (buf[c][y+1][x] << 4) / mul[c];
+                        if (val < 0) val = 0;
+                        if (c)
+                            BAYER(row+y*2+c-1,x*2+2-c) = val;
+                        else
+                            BAYER(row+r*2+y,x*2+y) = val;
+                    }
+                memcpy (buf[c][0]+!c, buf[c][2], sizeof buf[c][0]-2*!c);
+            }
+        }
+        for (y=row; y < row+4; y++)
+            for (x=0; x < width; x++)
+                if ((x+y) & 1) {
+                    val = (BAYER(y,x)-2048)*2 + (BAYER(y,x-1)+BAYER(y,x+1))/2;
+                    if (val < 0) val = 0;
+                    BAYER(y,x) = val;
+                }
+    }
+    maximum = 0x1fff;     /* wild guess */
 }
 
 #undef FORYX
 #undef PREDICTOR
 
 #ifndef HAVE_JPEG
-void kodak_jpeg_load_raw() {}
+void
+kodak_jpeg_load_raw(Image const Image) {}
 #else
 
-static boolean
+static bool
 fill_input_buffer (j_decompress_ptr cinfo)
 {
   static char jpeg_buffer[4096];
@@ -770,7 +791,7 @@ fill_input_buffer (j_decompress_ptr cinfo)
 }
 
 void
-kodak_jpeg_load_raw()
+kodak_jpeg_load_raw(Image const image)
 {
   struct jpeg_decompress_struct cinfo;
   struct jpeg_error_mgr jerr;
@@ -811,7 +832,7 @@ kodak_jpeg_load_raw()
 #endif
 
 void
-kodak_dc120_load_raw()
+kodak_dc120_load_raw(Image const image)
 {
   static const int mul[4] = { 162, 192, 187,  92 };
   static const int add[4] = {   0, 636, 424, 212 };
@@ -847,7 +868,7 @@ kodak_dc20_coeff (float const juice)
 }
 
 void
-kodak_easy_load_raw()
+kodak_easy_load_raw(Image const image)
 {
   unsigned char *pixel;
   unsigned row, col, icol;
@@ -875,7 +896,7 @@ kodak_easy_load_raw()
 }
 
 void
-kodak_compressed_load_raw()
+kodak_compressed_load_raw(Image const image)
 {
   unsigned char c, blen[256];
   unsigned short raw[6];
@@ -939,7 +960,7 @@ kodak_compressed_load_raw()
 }
 
 void
-kodak_yuv_load_raw()
+kodak_yuv_load_raw(Image const image)
 {
   unsigned char c, blen[384];
   unsigned row, col, len, bits=0;
@@ -1030,7 +1051,7 @@ static void  sony_decrypt (unsigned *data, int len, int start, int key)
 }
 
 void
-sony_load_raw()
+sony_load_raw(Image const image)
 {
   unsigned char head[40];
   struct pixel {
@@ -1298,12 +1319,6 @@ parse_mos(FILE * const ifp,
         fread (data, 1, 40, ifp);
         skip = get4(ifp);
         from = ftell(ifp);
-#ifdef USE_LCMS
-        if (!strcmp(data,"icc_camera_profile")) {
-            profile_length = skip;
-            profile_offset = from;
-        }
-#endif
         if (!strcmp(data,"NeutObj_neutrals")) {
             for (i=0; i < 4; i++)
                 fscanf (ifp, "%d", neut+i);
diff --git a/converter/other/cameratopam/camera.h b/converter/other/cameratopam/camera.h
index a1e884cf..02c3f2af 100644
--- a/converter/other/cameratopam/camera.h
+++ b/converter/other/cameratopam/camera.h
@@ -1,5 +1,10 @@
+#ifndef CAMERA_H_INCLUDED
+#define CAMERA_H_INCLUDED
+
 #include <stdio.h>
 
+#include "cameratopam.h"
+
 void 
 parse_ciff(FILE * const ifp,
            int    const offset,
@@ -21,20 +26,18 @@ void
 parse_mos(FILE * const ifp,
           int    const offset);
 
-void
-adobe_dng_load_raw_lj(void);
+typedef void LoadRawFn(Image const image);
 
-void
-adobe_dng_load_raw_nc(void);
+LoadRawFn adobe_dng_load_raw_lj;
+
+LoadRawFn adobe_dng_load_raw_nc;
 
 int
 nikon_is_compressed(void);
 
-void
-nikon_compressed_load_raw(void);
+LoadRawFn nikon_compressed_load_raw;
 
-void
-nikon_e950_load_raw(void);
+LoadRawFn nikon_e950_load_raw;
 
 void
 nikon_e950_coeff(void);
@@ -45,87 +48,63 @@ nikon_e990(void);
 int
 nikon_e2100(void);
 
-void
-nikon_e2100_load_raw(void);
+LoadRawFn nikon_e2100_load_raw;
 
 int
 minolta_z2(void);
 
-void
-fuji_s2_load_raw(void);
+LoadRawFn fuji_s2_load_raw;
 
-void
-fuji_s3_load_raw(void);
+LoadRawFn fuji_s3_load_raw;
 
-void
-fuji_s5000_load_raw(void);
+LoadRawFn fuji_s5000_load_raw;
 
-void
-unpacked_load_raw(void);
+LoadRawFn unpacked_load_raw;
 
-void
-fuji_s7000_load_raw(void);
+LoadRawFn fuji_s7000_load_raw;
 
-void
-fuji_f700_load_raw(void);
+LoadRawFn fuji_f700_load_raw;
 
-void
-packed_12_load_raw(void);
+LoadRawFn packed_12_load_raw;
 
-void
-eight_bit_load_raw(void);
+LoadRawFn eight_bit_load_raw;
 
-void
-phase_one_load_raw(void);
+LoadRawFn phase_one_load_raw;
 
-void
-ixpress_load_raw(void);
+LoadRawFn ixpress_load_raw;
 
-void
-leaf_load_raw(void);
+LoadRawFn leaf_load_raw;
 
-void
-olympus_e300_load_raw(void);
+LoadRawFn olympus_e300_load_raw;
 
-void
-olympus_cseries_load_raw(void);
+LoadRawFn olympus_cseries_load_raw;
 
-void
-sony_load_raw(void);
+LoadRawFn sony_load_raw;
 
-void
-kodak_easy_load_raw(void);
+LoadRawFn kodak_easy_load_raw;
 
-void
-kodak_compressed_load_raw(void);
+LoadRawFn kodak_compressed_load_raw;
 
-void
-kodak_yuv_load_raw(void);
+LoadRawFn kodak_yuv_load_raw;
 
 void
 kodak_dc20_coeff (float const juice);
 
-void
-kodak_radc_load_raw(void);
+LoadRawFn kodak_radc_load_raw;
 
-void
-kodak_jpeg_load_raw(void);
+LoadRawFn kodak_jpeg_load_raw;
 
-void
-kodak_dc120_load_raw(void);
+LoadRawFn kodak_dc120_load_raw;
 
-void
-rollei_load_raw(void);
+LoadRawFn rollei_load_raw;
 
-void
-casio_qv5700_load_raw(void);
+LoadRawFn casio_qv5700_load_raw;
 
-void
-nucore_load_raw(void);
+LoadRawFn nucore_load_raw;
 
-void
-nikon_load_raw(void);
+LoadRawFn nikon_load_raw;
 
 int
 pentax_optio33(void);
 
+#endif
diff --git a/converter/other/cameratopam/cameratopam.c b/converter/other/cameratopam/cameratopam.c
index b2d6da9b..ec33dd31 100644
--- a/converter/other/cameratopam/cameratopam.c
+++ b/converter/other/cameratopam/cameratopam.c
@@ -7,8 +7,11 @@
  */
 
 
-#define _BSD_SOURCE 1   /* Make sure string.h contains strcasecmp() */
-#define _XOPEN_SOURCE  /* Make sure unistd.h contains swab() */
+#define _BSD_SOURCE 1   /* Make sure string.h contains strdup() */
+#define _XOPEN_SOURCE 500
+   /* Make sure unistd.h contains swab(), string.h constains strdup() */
+
+#include "pm_config.h"
 
 #include <ctype.h>
 #include <unistd.h>
@@ -23,10 +26,10 @@
 #include <stdlib.h>
 #include <string.h>
 
-#ifdef __CYGWIN__
+#ifdef HAVE_IO_H
   #include <io.h>
 #endif
-#if !defined(WIN32) || defined(__CYGWIN__)
+#if !MSVCRT
   #include <unistd.h>
 #endif
 
@@ -36,6 +39,7 @@
 #include "pam.h"
 
 #include "global_variables.h"
+#include "cameratopam.h"
 #include "util.h"
 #include "decode.h"
 #include "identify.h"
@@ -59,22 +63,19 @@ int height, width, fuji_width, colors, tiff_samples;
 int black, maximum, clip_max;
 int iheight, iwidth, shrink;
 int is_dng, is_canon, is_foveon, use_coeff, use_gamma;
-int trim, flip, xmag, ymag;
+int flip, xmag, ymag;
 int zero_after_ff;
 unsigned filters;
-unsigned short (*image)[4], white[8][8], curve[0x1000];
+unsigned short  white[8][8];
+unsigned short  curve[0x1000];
 int fuji_secondary;
-float cam_mul[4], pre_mul[4], coeff[3][4];
+float cam_mul[4], coeff[3][4];
+float pre_mul[4];
 int histogram[3][0x2000];
 jmp_buf failure;
-bool use_secondary;
+int use_secondary;
 bool verbose;
 
-#ifdef USE_LCMS
-#include <lcms.h>
-int profile_offset, profile_length;
-#endif
-
 #define CLASS
 
 #define FORC3 for (c=0; c < 3; c++)
@@ -86,7 +87,7 @@ static void CLASS merror (const void *ptr, const char *where)
         pm_error ("Out of memory in %s", where);
 }
 
-struct cmdlineInfo {
+struct CmdlineInfo {
     /* All the information the user supplied in the command line,
        in a form easy for the program to use.
     */
@@ -110,11 +111,11 @@ struct cmdlineInfo {
 };
 
 
-static struct cmdlineInfo cmdline;
+static struct CmdlineInfo cmdline;
 
 static void
 parseCommandLine(int argc, char ** argv,
-                 struct cmdlineInfo *cmdlineP) {
+                 struct CmdlineInfo *cmdlineP) {
 /*----------------------------------------------------------------------------
    Note that many of the strings that this function returns in the
    *cmdlineP structure are actually in the supplied argv array.  And
@@ -167,7 +168,7 @@ parseCommandLine(int argc, char ** argv,
     OPTENT3(0,   "linear",   
             OPT_FLAG,    NULL, &cmdlineP->linear, 0);
 
-    optParseOptions3(&argc, argv, opt, sizeof(opt), 0);
+    pm_optParseOptions3(&argc, argv, opt, sizeof(opt), 0);
 
     if (!brightSpec)
         cmdlineP->bright = 1.0;
@@ -189,615 +190,694 @@ parseCommandLine(int argc, char ** argv,
 }
 
   
-/*
-   Seach from the current directory up to the root looking for
-   a ".badpixels" file, and fix those pixels now.
- */
-static void CLASS bad_pixels()
-{
-  FILE *fp=NULL;
-  char *fname, *cp, line[128];
-  int len, time, row, col, r, c, rad, tot, n, fixed=0;
-
-  if (!filters) return;
-  for (len=16 ; ; len *= 2) {
-    fname = malloc (len);
-    if (!fname) return;
-    if (getcwd (fname, len-12)) break;
-    free (fname);
-    if (errno != ERANGE) return;
-  }
-#ifdef WIN32
-  if (fname[1] == ':')
-    memmove (fname, fname+2, len-2);
-  for (cp=fname; *cp; cp++)
-    if (*cp == '\\') *cp = '/';
+
+static void CLASS
+fixBadPixels(Image const image) {
+/*----------------------------------------------------------------------------
+  Search from the current directory up to the root looking for
+  a ".badpixels" file, and fix those pixels now.
+-----------------------------------------------------------------------------*/
+    if (filters) {
+        FILE *fp;
+        char *fname, *cp, line[128];
+        int len, time, row, col, rad, tot, n, fixed=0;
+
+        for (len=16 ; ; len *= 2) {
+            fname = malloc (len);
+            if (!fname) return;
+            if (getcwd (fname, len-12))
+                break;
+            free (fname);
+            if (errno != ERANGE)
+                return;
+        }
+#if MSVCRT
+        if (fname[1] == ':')
+            memmove (fname, fname+2, len-2);
+        for (cp=fname; *cp; cp++)
+            if (*cp == '\\') *cp = '/';
 #endif
-  cp = fname + strlen(fname);
-  if (cp[-1] == '/') cp--;
-  while (*fname == '/') {
-    strcpy (cp, "/.badpixels");
-    if ((fp = fopen (fname, "r"))) break;
-    if (cp == fname) break;
-    while (*--cp != '/');
-  }
-  free (fname);
-  if (!fp) return;
-  while (fgets (line, 128, fp)) {
-    cp = strchr (line, '#');
-    if (cp) *cp = 0;
-    if (sscanf (line, "%d %d %d", &col, &row, &time) != 3) continue;
-    if ((unsigned) col >= width || (unsigned) row >= height) continue;
-    if (time > timestamp) continue;
-    for (tot=n=0, rad=1; rad < 3 && n==0; rad++)
-      for (r = row-rad; r <= row+rad; r++)
-    for (c = col-rad; c <= col+rad; c++)
-      if ((unsigned) r < height && (unsigned) c < width &&
-        (r != row || c != col) && FC(r,c) == FC(row,col)) {
-        tot += BAYER(r,c);
-        n++;
-      }
-    BAYER(row,col) = tot/n;
-    if (cmdline.verbose) {
-      if (!fixed++)
-          pm_message ("Fixed bad pixels at: %d,%d", col, row);
+        cp = fname + strlen(fname);
+        if (cp[-1] == '/')
+            --cp;
+        fp = NULL; /* initial value */
+        while (*fname == '/') {
+            strcpy (cp, "/.badpixels");
+            fp = fopen (fname, "r");
+            if (fp)
+                break;
+            if (cp == fname)
+                break;
+            while (*--cp != '/');
+        }
+        free (fname);
+        if (fp) {
+            while (fgets (line, 128, fp)) {
+                char * cp;
+                cp = strchr (line, '#');
+                if (cp) *cp = 0;
+                if (sscanf (line, "%d %d %d", &col, &row, &time) != 3)
+                    continue;
+                if ((unsigned) col >= width || (unsigned) row >= height)
+                    continue;
+                if (time > timestamp) continue;
+                for (tot=n=0, rad=1; rad < 3 && n==0; rad++) {
+                    unsigned int r;
+                    for (r = row-rad; r <= row+rad; ++r) {
+                        unsigned int c;
+                        for (c = col-rad; c <= col+rad; ++c) {
+                            if ((unsigned) r < height &&
+                                (unsigned) c < width  &&
+                                (r != row || c != col) &&
+                                FC(r,c) == FC(row,col)) {
+                                tot += BAYER(r,c);
+                                ++n;
+                            }
+                        }
+                    }
+                }
+                BAYER(row,col) = tot/n;
+                if (cmdline.verbose) {
+                    if (!fixed++)
+                        pm_message ("Fixed bad pixels at: %d,%d", col, row);
+                }
+            }
+            fclose (fp);
+        }
     }
-  }
-  fclose (fp);
 }
 
-static void CLASS scale_colors()
-{
-  int row, col, c, val, shift=0;
-  int min[4], max[4], count[4];
-  double sum[4], dmin;
-
-  maximum -= black;
-  if (cmdline.use_auto_wb || (cmdline.use_camera_wb && camera_red == -1)) {
-    FORC4 min[c] = INT_MAX;
-    FORC4 max[c] = count[c] = sum[c] = 0;
-    for (row=0; row < height; row++)
-      for (col=0; col < width; col++)
-    FORC4 {
-      val = image[row*width+col][c];
-      if (!val) continue;
-      if (min[c] > val) min[c] = val;
-      if (max[c] < val) max[c] = val;
-      val -= black;
-      if (val > maximum-25) continue;
-      if (val < 0) val = 0;
-      sum[c] += val;
-      count[c]++;
+
+
+static void CLASS
+scaleColors(Image const image) {
+
+    int row;
+    int c;
+    int val;
+    int shift;
+    int min[4], max[4], count[4];
+    double sum[4], dmin;
+    int scaleMax;
+
+    scaleMax = maximum - black;  /* initial value */
+    if (cmdline.use_auto_wb || (cmdline.use_camera_wb && camera_red == -1)) {
+        unsigned int row;
+        FORC4 min  [c] = INT_MAX;
+        FORC4 max  [c] = 0;
+        FORC4 count[c] = 0;
+        FORC4 sum  [c] = 0;
+        for (row = 0; row < height; ++row) {
+            unsigned int col;
+            for (col = 0; col < width; ++col) {
+                FORC4 {
+                    int val;
+                    val = image[row*width+col][c];
+                    if (val != 0) {
+                        if (min[c] > val)
+                            min[c] = val;
+                        if (max[c] < val)
+                            max[c] = val;
+                        val -= black;
+                        if (val <= scaleMax-25) {
+                            sum  [c] += MAX(0, val);
+                            count[c] += 1;
+                        }
+                    }
+                }
+            }
+        }
+        FORC4 pre_mul[c] = count[c] / sum[c];
     }
-    FORC4 pre_mul[c] = count[c] / sum[c];
-  }
-  if (cmdline.use_camera_wb && camera_red != -1) {
-    FORC4 count[c] = sum[c] = 0;
-    for (row=0; row < 8; row++)
-      for (col=0; col < 8; col++) {
-    c = FC(row,col);
-    if ((val = white[row][col] - black) > 0)
-      sum[c] += val;
-    count[c]++;
-      }
-    val = 1;
-    FORC4 if (sum[c] == 0) val = 0;
-    if (val)
-      FORC4 pre_mul[c] = count[c] / sum[c];
-    else if (camera_red && camera_blue)
-      memcpy (pre_mul, cam_mul, sizeof pre_mul);
-    else
-      pm_message ("Cannot use camera white balance.");
-  }
-  if (!use_coeff) {
-    pre_mul[0] *= cmdline.red_scale;
-    pre_mul[2] *= cmdline.blue_scale;
-  }
-  dmin = DBL_MAX;
-  FORC4 if (dmin > pre_mul[c])
+    if (cmdline.use_camera_wb && camera_red != -1) {
+        unsigned int row;
+        FORC4 count[c] = sum[c] = 0;
+        for (row = 0; row < 8; ++row) {
+            unsigned int col;
+            for (col = 0; col < 8; ++col) {
+                c = FC(row,col);
+                if ((val = white[row][col] - black) > 0)
+                    sum[c] += val;
+                ++count[c];
+            }
+        }
+        val = 1;
+        FORC4 if (sum[c] == 0) val = 0;
+        if (val)
+            FORC4 pre_mul[c] = count[c] / sum[c];
+        else if (camera_red && camera_blue)
+            memcpy(pre_mul, cam_mul, sizeof pre_mul);
+        else
+            pm_message ("Cannot use camera white balance.");
+    }
+    if (!use_coeff) {
+        pre_mul[0] *= cmdline.red_scale;
+        pre_mul[2] *= cmdline.blue_scale;
+    }
+    dmin = DBL_MAX;
+    FORC4 if (dmin > pre_mul[c])
         dmin = pre_mul[c];
-  FORC4 pre_mul[c] /= dmin;
-
-  while (maximum << shift < 0x8000) shift++;
-  FORC4 pre_mul[c] *= 1 << shift;
-  maximum <<= shift;
-
-  if (cmdline.linear || cmdline.bright < 1) {
-      maximum *= cmdline.bright;
-      if (maximum > 0xffff)
-          maximum = 0xffff;
-      FORC4 pre_mul[c] *= cmdline.bright;
-  }
-  if (cmdline.verbose) {
-    fprintf (stderr, "Scaling with black=%d, pre_mul[] =", black);
-    FORC4 fprintf (stderr, " %f", pre_mul[c]);
-    fputc ('\n', stderr);
-  }
-  clip_max = cmdline.no_clip_color ? 0xffff : maximum;
-  for (row=0; row < height; row++)
-    for (col=0; col < width; col++)
-      FORC4 {
-    val = image[row*width+col][c];
-    if (!val) continue;
-    val -= black;
-    val *= pre_mul[c];
-    if (val < 0) val = 0;
-    if (val > clip_max) val = clip_max;
-    image[row*width+col][c] = val;
-      }
-}
-
-/*
-   This algorithm is officially called:
+    FORC4 pre_mul[c] /= dmin;
 
-   "Interpolation using a Threshold-based variable number of gradients"
+    for (shift = 0; scaleMax << shift < 0x8000; ++shift);
 
-   described in http://www-ise.stanford.edu/~tingchen/algodep/vargra.html
+    FORC4 pre_mul[c] *= 1 << shift;
+    scaleMax <<= shift;
 
-   I've extended the basic idea to work with non-Bayer filter arrays.
-   Gradients are numbered clockwise from NW=0 to W=7.
- */
-static void CLASS vng_interpolate()
-{
-  static const signed char *cp, terms[] = {
-    -2,-2,+0,-1,0,(char)0x01, -2,-2,+0,+0,1,(char)0x01, -2,-1,-1,+0,0,(char)0x01,
-    -2,-1,+0,-1,0,(char)0x02, -2,-1,+0,+0,0,(char)0x03, -2,-1,+0,+1,1,(char)0x01,
-    -2,+0,+0,-1,0,(char)0x06, -2,+0,+0,+0,1,(char)0x02, -2,+0,+0,+1,0,(char)0x03,
-    -2,+1,-1,+0,0,(char)0x04, -2,+1,+0,-1,1,(char)0x04, -2,+1,+0,+0,0,(char)0x06,
-    -2,+1,+0,+1,0,(char)0x02, -2,+2,+0,+0,1,(char)0x04, -2,+2,+0,+1,0,(char)0x04,
-    -1,-2,-1,+0,0,(char)0x80, -1,-2,+0,-1,0,(char)0x01, -1,-2,+1,-1,0,(char)0x01,
-    -1,-2,+1,+0,1,(char)0x01, -1,-1,-1,+1,0,(char)0x88, -1,-1,+1,-2,0,(char)0x40,
-    -1,-1,+1,-1,0,(char)0x22, -1,-1,+1,+0,0,(char)0x33, -1,-1,+1,+1,1,(char)0x11,
-    -1,+0,-1,+2,0,(char)0x08, -1,+0,+0,-1,0,(char)0x44, -1,+0,+0,+1,0,(char)0x11,
-    -1,+0,+1,-2,1,(char)0x40, -1,+0,+1,-1,0,(char)0x66, -1,+0,+1,+0,1,(char)0x22,
-    -1,+0,+1,+1,0,(char)0x33, -1,+0,+1,+2,1,(char)0x10, -1,+1,+1,-1,1,(char)0x44,
-    -1,+1,+1,+0,0,(char)0x66, -1,+1,+1,+1,0,(char)0x22, -1,+1,+1,+2,0,(char)0x10,
-    -1,+2,+0,+1,0,(char)0x04, -1,+2,+1,+0,1,(char)0x04, -1,+2,+1,+1,0,(char)0x04,
-    +0,-2,+0,+0,1,(char)0x80, +0,-1,+0,+1,1,(char)0x88, +0,-1,+1,-2,0,(char)0x40,
-    +0,-1,+1,+0,0,(char)0x11, +0,-1,+2,-2,0,(char)0x40, +0,-1,+2,-1,0,(char)0x20,
-    +0,-1,+2,+0,0,(char)0x30, +0,-1,+2,+1,1,(char)0x10, +0,+0,+0,+2,1,(char)0x08,
-    +0,+0,+2,-2,1,(char)0x40, +0,+0,+2,-1,0,(char)0x60, +0,+0,+2,+0,1,(char)0x20,
-    +0,+0,+2,+1,0,(char)0x30, +0,+0,+2,+2,1,(char)0x10, +0,+1,+1,+0,0,(char)0x44,
-    +0,+1,+1,+2,0,(char)0x10, +0,+1,+2,-1,1,(char)0x40, +0,+1,+2,+0,0,(char)0x60,
-    +0,+1,+2,+1,0,(char)0x20, +0,+1,+2,+2,0,(char)0x10, +1,-2,+1,+0,0,(char)0x80,
-    +1,-1,+1,+1,0,(char)0x88, +1,+0,+1,+2,0,(char)0x08, +1,+0,+2,-1,0,(char)0x40,
-    +1,+0,+2,+1,0,(char)0x10
-  }, chood[] = { -1,-1, -1,0, -1,+1, 0,+1, +1,+1, +1,0, +1,-1, 0,-1 };
-  unsigned short (*brow[5])[4], *pix;
-  int code[8][2][320], *ip, gval[8], gmin, gmax, sum[4];
-  int row, col, shift, x, y, x1, x2, y1, y2, t, weight, grads, color, diag;
-  int g, diff, thold, num, c;
-
-  for (row=0; row < 8; row++) {     /* Precalculate for bilinear */
-    for (col=1; col < 3; col++) {
-      ip = code[row][col & 1];
-      memset (sum, 0, sizeof sum);
-      for (y=-1; y <= 1; y++)
-    for (x=-1; x <= 1; x++) {
-      shift = (y==0) + (x==0);
-      if (shift == 2) continue;
-      color = FC(row+y,col+x);
-      *ip++ = (width*y + x)*4 + color;
-      *ip++ = shift;
-      *ip++ = color;
-      sum[color] += 1 << shift;
-    }
-      FORC4
-    if (c != FC(row,col)) {
-      *ip++ = c;
-      *ip++ = sum[c];
+    if (cmdline.linear || cmdline.bright < 1) {
+        scaleMax = MIN(0xffff, scaleMax * cmdline.bright);
+        FORC4 pre_mul[c] *= cmdline.bright;
     }
+    if (cmdline.verbose) {
+        fprintf(stderr, "Scaling with black=%d, ", black);
+        fprintf(stderr, "pre_mul[] = ");
+        FORC4 fprintf (stderr, " %f", pre_mul[c]);
+        fprintf(stderr, "\n");
     }
-  }
-  for (row=1; row < height-1; row++) {  /* Do bilinear interpolation */
-    for (col=1; col < width-1; col++) {
-      pix = image[row*width+col];
-      ip = code[row & 7][col & 1];
-      memset (sum, 0, sizeof sum);
-      for (g=8; g--; ) {
-    diff = pix[*ip++];
-    diff <<= *ip++;
-    sum[*ip++] += diff;
-      }
-      for (g=colors; --g; ) {
-    c = *ip++;
-    pix[c] = sum[c] / *ip++;
-      }
+    clip_max = cmdline.no_clip_color ? 0xffff : scaleMax;
+    for (row = 0; row < height; ++row) {
+        unsigned int col;
+        for (col = 0; col < width; ++col) {
+            unsigned int c;
+            for (c = 0; c < colors; ++c) {
+                int val;
+                val = image[row*width+col][c];
+                if (val != 0) {
+                    val -= black;
+                    val *= pre_mul[c];
+                    image[row*width+col][c] = MAX(0, MIN(clip_max, val));
+                }
+            }
+        }
     }
-  }
-  if (cmdline.quick_interpolate)
-    return;
-
-  for (row=0; row < 8; row++) {     /* Precalculate for VNG */
-    for (col=0; col < 2; col++) {
-      ip = code[row][col];
-      for (cp=terms, t=0; t < 64; t++) {
-    y1 = *cp++;  x1 = *cp++;
-    y2 = *cp++;  x2 = *cp++;
-    weight = *cp++;
-    grads = *cp++;
-    color = FC(row+y1,col+x1);
-    if (FC(row+y2,col+x2) != color) continue;
-    diag = (FC(row,col+1) == color && FC(row+1,col) == color) ? 2:1;
-    if (abs(y1-y2) == diag && abs(x1-x2) == diag) continue;
-    *ip++ = (y1*width + x1)*4 + color;
-    *ip++ = (y2*width + x2)*4 + color;
-    *ip++ = weight;
-    for (g=0; g < 8; g++)
-      if (grads & 1<<g) *ip++ = g;
-    *ip++ = -1;
-      }
-      *ip++ = INT_MAX;
-      for (cp=chood, g=0; g < 8; g++) {
-    y = *cp++;  x = *cp++;
-    *ip++ = (y*width + x) * 4;
-    color = FC(row,col);
-    if (FC(row+y,col+x) != color && FC(row+y*2,col+x*2) == color)
-      *ip++ = (y*width + x) * 8 + color;
-    else
-      *ip++ = 0;
-      }
+}
+
+
+
+static void CLASS
+vngInterpolate(Image const image) {
+
+    /*
+      This algorithm is officially called "Interpolation using a
+      Threshold-based variable number of gradients," described in
+      http://www-ise.stanford.edu/~tingchen/algodep/vargra.html
+
+      I've extended the basic idea to work with non-Bayer filter arrays.
+      Gradients are numbered clockwise from NW=0 to W=7.
+    */
+
+    static const signed char *cp, terms[] = {
+  -2,-2,+0,-1,0,(char)0x01, -2,-2,+0,+0,1,(char)0x01, -2,-1,-1,+0,0,(char)0x01,
+  -2,-1,+0,-1,0,(char)0x02, -2,-1,+0,+0,0,(char)0x03, -2,-1,+0,+1,1,(char)0x01,
+  -2,+0,+0,-1,0,(char)0x06, -2,+0,+0,+0,1,(char)0x02, -2,+0,+0,+1,0,(char)0x03,
+  -2,+1,-1,+0,0,(char)0x04, -2,+1,+0,-1,1,(char)0x04, -2,+1,+0,+0,0,(char)0x06,
+  -2,+1,+0,+1,0,(char)0x02, -2,+2,+0,+0,1,(char)0x04, -2,+2,+0,+1,0,(char)0x04,
+  -1,-2,-1,+0,0,(char)0x80, -1,-2,+0,-1,0,(char)0x01, -1,-2,+1,-1,0,(char)0x01,
+  -1,-2,+1,+0,1,(char)0x01, -1,-1,-1,+1,0,(char)0x88, -1,-1,+1,-2,0,(char)0x40,
+  -1,-1,+1,-1,0,(char)0x22, -1,-1,+1,+0,0,(char)0x33, -1,-1,+1,+1,1,(char)0x11,
+  -1,+0,-1,+2,0,(char)0x08, -1,+0,+0,-1,0,(char)0x44, -1,+0,+0,+1,0,(char)0x11,
+  -1,+0,+1,-2,1,(char)0x40, -1,+0,+1,-1,0,(char)0x66, -1,+0,+1,+0,1,(char)0x22,
+  -1,+0,+1,+1,0,(char)0x33, -1,+0,+1,+2,1,(char)0x10, -1,+1,+1,-1,1,(char)0x44,
+  -1,+1,+1,+0,0,(char)0x66, -1,+1,+1,+1,0,(char)0x22, -1,+1,+1,+2,0,(char)0x10,
+  -1,+2,+0,+1,0,(char)0x04, -1,+2,+1,+0,1,(char)0x04, -1,+2,+1,+1,0,(char)0x04,
+  +0,-2,+0,+0,1,(char)0x80, +0,-1,+0,+1,1,(char)0x88, +0,-1,+1,-2,0,(char)0x40,
+  +0,-1,+1,+0,0,(char)0x11, +0,-1,+2,-2,0,(char)0x40, +0,-1,+2,-1,0,(char)0x20,
+  +0,-1,+2,+0,0,(char)0x30, +0,-1,+2,+1,1,(char)0x10, +0,+0,+0,+2,1,(char)0x08,
+  +0,+0,+2,-2,1,(char)0x40, +0,+0,+2,-1,0,(char)0x60, +0,+0,+2,+0,1,(char)0x20,
+  +0,+0,+2,+1,0,(char)0x30, +0,+0,+2,+2,1,(char)0x10, +0,+1,+1,+0,0,(char)0x44,
+  +0,+1,+1,+2,0,(char)0x10, +0,+1,+2,-1,1,(char)0x40, +0,+1,+2,+0,0,(char)0x60,
+  +0,+1,+2,+1,0,(char)0x20, +0,+1,+2,+2,0,(char)0x10, +1,-2,+1,+0,0,(char)0x80,
+  +1,-1,+1,+1,0,(char)0x88, +1,+0,+1,+2,0,(char)0x08, +1,+0,+2,-1,0,(char)0x40,
+  +1,+0,+2,+1,0,(char)0x10
+    }, chood[] = { -1,-1, -1,0, -1,+1, 0,+1, +1,+1, +1,0, +1,-1, 0,-1 };
+    unsigned short (*brow[5])[4], *pix;
+    int code[8][2][320], *ip, gval[8], gmin, gmax, sum[4];
+    int row, col, shift, x, y, x1, x2, y1, y2, t, weight, grads, color, diag;
+    int g, diff, thold, num, c;
+
+    for (row=0; row < 8; row++) {     /* Precalculate for bilinear */
+        for (col=1; col < 3; col++) {
+            ip = code[row][col & 1];
+            memset (sum, 0, sizeof sum);
+            for (y=-1; y <= 1; y++)
+                for (x=-1; x <= 1; x++) {
+                    shift = (y==0) + (x==0);
+                    if (shift == 2) continue;
+                    color = FC(row+y,col+x);
+                    *ip++ = (width*y + x)*4 + color;
+                    *ip++ = shift;
+                    *ip++ = color;
+                    sum[color] += 1 << shift;
+                }
+            FORC4
+                if (c != FC(row,col)) {
+                    *ip++ = c;
+                    *ip++ = sum[c];
+                }
+        }
     }
-  }
-  brow[4] = calloc (width*3, sizeof **brow);
-  merror (brow[4], "vng_interpolate()");
-  for (row=0; row < 3; row++)
-    brow[row] = brow[4] + row*width;
-  for (row=2; row < height-2; row++) {      /* Do VNG interpolation */
-    for (col=2; col < width-2; col++) {
-      pix = image[row*width+col];
-      ip = code[row & 7][col & 1];
-      memset (gval, 0, sizeof gval);
-      while ((g = ip[0]) != INT_MAX) {      /* Calculate gradients */
-    num = (diff = pix[g] - pix[ip[1]]) >> 31;
-    gval[ip[3]] += (diff = ((diff ^ num) - num) << ip[2]);
-    ip += 5;
-    if ((g = ip[-1]) == -1) continue;
-    gval[g] += diff;
-    while ((g = *ip++) != -1)
-      gval[g] += diff;
-      }
-      ip++;
-      gmin = gmax = gval[0];            /* Choose a threshold */
-      for (g=1; g < 8; g++) {
-    if (gmin > gval[g]) gmin = gval[g];
-    if (gmax < gval[g]) gmax = gval[g];
-      }
-      if (gmax == 0) {
-    memcpy (brow[2][col], pix, sizeof *image);
-    continue;
-      }
-      thold = gmin + (gmax >> 1);
-      memset (sum, 0, sizeof sum);
-      color = FC(row,col);
-      for (num=g=0; g < 8; g++,ip+=2) {     /* Average the neighbors */
-    if (gval[g] <= thold) {
-      FORC4
-        if (c == color && ip[1])
-          sum[c] += (pix[c] + pix[ip[1]]) >> 1;
-        else
-          sum[c] += pix[ip[0] + c];
-      num++;
+    for (row=1; row < height-1; row++) {  /* Do bilinear interpolation */
+        for (col=1; col < width-1; col++) {
+            pix = image[row*width+col];
+            ip = code[row & 7][col & 1];
+            memset (sum, 0, sizeof sum);
+            for (g=8; g--; ) {
+                diff = pix[*ip++];
+                diff <<= *ip++;
+                sum[*ip++] += diff;
+            }
+            for (g=colors; --g; ) {
+                c = *ip++;
+                pix[c] = sum[c] / *ip++;
+            }
+        }
     }
-      }
-      FORC4 {                   /* Save to buffer */
-    t = pix[color];
-    if (c != color) {
-      t += (sum[c] - sum[color])/num;
-      if (t < 0) t = 0;
-      if (t > clip_max) t = clip_max;
+    if (cmdline.quick_interpolate)
+        return;
+
+    for (row=0; row < 8; row++) {     /* Precalculate for VNG */
+        for (col=0; col < 2; col++) {
+            ip = code[row][col];
+            for (cp=terms, t=0; t < 64; t++) {
+                y1 = *cp++;  x1 = *cp++;
+                y2 = *cp++;  x2 = *cp++;
+                weight = *cp++;
+                grads = *cp++;
+                color = FC(row+y1,col+x1);
+                if (FC(row+y2,col+x2) != color) continue;
+                diag =
+                    (FC(row,col+1) == color && FC(row+1,col) == color) ? 2:1;
+                if (abs(y1-y2) == diag && abs(x1-x2) == diag) continue;
+                *ip++ = (y1*width + x1)*4 + color;
+                *ip++ = (y2*width + x2)*4 + color;
+                *ip++ = weight;
+                for (g=0; g < 8; g++)
+                    if (grads & 1<<g) *ip++ = g;
+                *ip++ = -1;
+            }
+            *ip++ = INT_MAX;
+            for (cp=chood, g=0; g < 8; g++) {
+                y = *cp++;  x = *cp++;
+                *ip++ = (y*width + x) * 4;
+                color = FC(row,col);
+                if (FC(row+y,col+x) != color && FC(row+y*2,col+x*2) == color)
+                    *ip++ = (y*width + x) * 8 + color;
+                else
+                    *ip++ = 0;
+            }
+        }
     }
-    brow[2][col][c] = t;
-      }
+    brow[4] = calloc (width*3, sizeof **brow);
+    merror (brow[4], "vngInterpolate()");
+    for (row=0; row < 3; row++)
+        brow[row] = brow[4] + row*width;
+    for (row=2; row < height-2; row++) {      /* Do VNG interpolation */
+        for (col=2; col < width-2; col++) {
+            pix = image[row*width+col];
+            ip = code[row & 7][col & 1];
+            memset (gval, 0, sizeof gval);
+            while ((g = ip[0]) != INT_MAX) {      /* Calculate gradients */
+                num = (diff = pix[g] - pix[ip[1]]) >> 31;
+                gval[ip[3]] += (diff = ((diff ^ num) - num) << ip[2]);
+                ip += 5;
+                if ((g = ip[-1]) == -1) continue;
+                gval[g] += diff;
+                while ((g = *ip++) != -1)
+                    gval[g] += diff;
+            }
+            ip++;
+            gmin = gmax = gval[0];            /* Choose a threshold */
+            for (g=1; g < 8; g++) {
+                if (gmin > gval[g]) gmin = gval[g];
+                if (gmax < gval[g]) gmax = gval[g];
+            }
+            if (gmax == 0) {
+                memcpy (brow[2][col], pix, sizeof *image);
+                continue;
+            }
+            thold = gmin + (gmax >> 1);
+            memset (sum, 0, sizeof sum);
+            color = FC(row,col);
+            for (num=g=0; g < 8; g++,ip+=2) {     /* Average the neighbors */
+                if (gval[g] <= thold) {
+                    FORC4
+                        if (c == color && ip[1])
+                            sum[c] += (pix[c] + pix[ip[1]]) >> 1;
+                        else
+                            sum[c] += pix[ip[0] + c];
+                    num++;
+                }
+            }
+            FORC4 {                   /* Save to buffer */
+                t = pix[color];
+                if (c != color) {
+                    t += (sum[c] - sum[color])/num;
+                    if (t < 0) t = 0;
+                    if (t > clip_max) t = clip_max;
+                }
+                brow[2][col][c] = t;
+            }
+        }
+        if (row > 3)                /* Write buffer to image */
+            memcpy(image[(row-2)*width+2], brow[0]+2, (width-4)*sizeof *image);
+        for (g=0; g < 4; g++)
+            brow[(g-1) & 3] = brow[g];
     }
-    if (row > 3)                /* Write buffer to image */
-      memcpy (image[(row-2)*width+2], brow[0]+2, (width-4)*sizeof *image);
-    for (g=0; g < 4; g++)
-      brow[(g-1) & 3] = brow[g];
-  }
-  memcpy (image[(row-2)*width+2], brow[0]+2, (width-4)*sizeof *image);
-  memcpy (image[(row-1)*width+2], brow[1]+2, (width-4)*sizeof *image);
-  free (brow[4]);
+    memcpy (image[(row-2)*width+2], brow[0]+2, (width-4)*sizeof *image);
+    memcpy (image[(row-1)*width+2], brow[1]+2, (width-4)*sizeof *image);
+    free (brow[4]);
 }
 
-#ifdef USE_LCMS
-static void 
-apply_profile(FILE *       const ifP,
-              const char * const pfname)
-{
-  char *prof;
-  cmsHPROFILE hInProfile=NULL, hOutProfile;
-  cmsHTRANSFORM hTransform;
-
-  if (pfname)
-    hInProfile = cmsOpenProfileFromFile (pfname, "r");
-  else if (profile_length) {
-    prof = malloc (profile_length);
-    merror (prof, "apply_profile()");
-    fseek (ifP, profile_offset, SEEK_SET);
-    fread (prof, 1, profile_length, ifP);
-    hInProfile = cmsOpenProfileFromMem (prof, profile_length);
-    free (prof);
-  }
-  if (!hInProfile) return;
-  if (cmdline.verbose)
-      pm_message( "Applying color profile...");
-  maximum = 0xffff;
-  use_gamma = use_coeff = 0;
-
-  hOutProfile = cmsCreate_sRGBProfile();
-  hTransform = cmsCreateTransform (hInProfile, TYPE_RGBA_16,
-    hOutProfile, TYPE_RGBA_16, INTENT_PERCEPTUAL, 0);
-  cmsDoTransform (hTransform, image, image, width*height);
-
-  cmsDeleteTransform (hTransform);
-  cmsCloseProfile (hInProfile);
-  cmsCloseProfile (hOutProfile);
-}
-#else
-static void 
-apply_profile(FILE *       const ifP,
-              const char * const pfname)
-{
-}
-#endif
 
-/*
+
+static void CLASS
+convertToRgb(Image        const image,
+             unsigned int const trim) {
+/*----------------------------------------------------------------------------
    Convert the entire image to RGB colorspace and build a histogram.
- */
-static void CLASS convert_to_rgb()
-{
-  int row, col, r, g, c=0;
-  unsigned short *img;
-  float rgb[3];
-
-  if (cmdline.document_mode)
-    colors = 1;
-  memset (histogram, 0, sizeof histogram);
-  for (row = trim; row < height-trim; row++)
-    for (col = trim; col < width-trim; col++) {
-      img = image[row*width+col];
-      if (cmdline.document_mode)
-    c = FC(row,col);
-      if (colors == 4 && !use_coeff)    /* Recombine the greens */
-    img[1] = (img[1] + img[3]) >> 1;
-      if (colors == 1)          /* RGB from grayscale */
-    for (r=0; r < 3; r++)
-      rgb[r] = img[c];
-      else if (use_coeff) {     /* RGB via coeff[][] */
-    for (r=0; r < 3; r++)
-      for (rgb[r]=g=0; g < colors; g++)
-        rgb[r] += img[g] * coeff[r][g];
-      } else                /* RGB from RGB (easy) */
-    goto norgb;
-      for (r=0; r < 3; r++) {
-    if (rgb[r] < 0)        rgb[r] = 0;
-    if (rgb[r] > clip_max) rgb[r] = clip_max;
-    img[r] = rgb[r];
-      }
-norgb:
-      for (r=0; r < 3; r++)
-    histogram[r][img[r] >> 3]++;
+
+   We modify 'image' to change it from whatever it is now to RGB.
+-----------------------------------------------------------------------------*/
+    unsigned int row;
+    unsigned int c;
+    float rgb[3];  /* { red, green, blue } */
+
+    c = 0;  /* initial value */
+
+    if (cmdline.document_mode)
+        colors = 1;
+
+    memset(histogram, 0, sizeof histogram);
+
+    for (row = 0 + trim; row < height - trim; ++row) {
+        unsigned int col;
+        for (col = 0 + trim; col < width - trim; ++col) {
+            unsigned short * const img = image[row*width+col];
+
+            if (cmdline.document_mode)
+                c = FC(row,col);
+
+            if (colors == 4 && !use_coeff)
+                /* Recombine the greens */
+                img[1] = (img[1] + img[3]) / 2;
+
+            if (colors == 1) {
+                /* RGB from grayscale */
+                unsigned int i;
+                for (i = 0; i < 3; ++i)
+                    rgb[i] = img[c];
+            } else if (use_coeff) {
+                /* RGB via coeff[][] */
+                unsigned int i;
+                for (i = 0; i < 3; ++i) {
+                    unsigned int j;
+                    for (j = 0, rgb[i]= 0; j < colors; ++j)
+                        rgb[i] += img[j] * coeff[i][j];
+                }
+            } else {
+                /* RGB from RGB (easy) */
+                unsigned int i;
+                for (i = 0; i < 3; ++i)
+                    rgb[i] = img[i];
+            }
+            {
+                unsigned int i;
+                for (i = 0; i < 3; ++i)
+                    img[i] = MIN(clip_max, MAX(0, rgb[i]));
+            }
+            {
+                unsigned int i;
+                for (i = 0; i < 3; ++i)
+                    ++histogram[i][img[i] >> 3];
+            }
+        }
     }
 }
 
-static void CLASS fuji_rotate()
-{
-  int i, wide, high, row, col;
-  double step;
-  float r, c, fr, fc;
-  unsigned ur, uc;
-  unsigned short (*img)[4], (*pix)[4];
-
-  if (!fuji_width) return;
-  if (cmdline.verbose)
-    pm_message ("Rotating image 45 degrees...");
-  fuji_width = (fuji_width + shrink) >> shrink;
-  step = sqrt(0.5);
-  wide = fuji_width / step;
-  high = (height - fuji_width) / step;
-  img = calloc (wide*high, sizeof *img);
-  merror (img, "fuji_rotate()");
-
-  for (row=0; row < high; row++)
-    for (col=0; col < wide; col++) {
-      ur = r = fuji_width + (row-col)*step;
-      uc = c = (row+col)*step;
-      if (ur > height-2 || uc > width-2) continue;
-      fr = r - ur;
-      fc = c - uc;
-      pix = image + ur*width + uc;
-      for (i=0; i < colors; i++)
-    img[row*wide+col][i] =
-      (pix[    0][i]*(1-fc) + pix[      1][i]*fc) * (1-fr) +
-      (pix[width][i]*(1-fc) + pix[width+1][i]*fc) * fr;
+
+
+static void CLASS
+fujiRotate(Image * const imageP) {
+
+    int wide;
+    int high;
+    unsigned int row;
+    double step;
+    float r, c, fr, fc;
+    unsigned short (*newImage)[4];
+    unsigned short (*pix)[4];
+
+    if (fuji_width > 0) {
+        if (cmdline.verbose)
+            pm_message ("Rotating image 45 degrees...");
+
+        fuji_width = (fuji_width + shrink) >> shrink;
+        step = sqrt(0.5);
+        wide = fuji_width / step;
+        high = (height - fuji_width) / step;
+        newImage = calloc (wide*high, sizeof *newImage);
+        merror (newImage, "fujiRotate()");
+
+        for (row = 0; row < high; ++row) {
+            unsigned int col;
+            for (col = 0; col < wide; ++col) {
+                unsigned int ur = r = fuji_width + (row-col)*step;
+                unsigned int uc = c = (row+col)*step;
+
+                unsigned int i;
+
+                if (ur > height-2 || uc > width-2)
+                    continue;
+
+                fr = r - ur;
+                fc = c - uc;
+                pix = (*imageP) + ur * width + uc;
+
+                for (i = 0; i < colors; ++i) {
+                    newImage[row*wide+col][i] =
+                        (pix[    0][i]*(1-fc) + pix[      1][i]*fc) * (1-fr) +
+                        (pix[width][i]*(1-fc) + pix[width+1][i]*fc) * fr;
+                } 
+            }
+        }        
+        free(*imageP);
+        width  = wide;
+        height = high;
+        *imageP  = newImage;
+        fuji_width = 0;
     }
-  free (image);
-  width  = wide;
-  height = high;
-  image  = img;
-  fuji_width = 0;
 }
 
-static void CLASS flip_image()
-{
+
+
+static void CLASS
+flipImage(Image const image) {
+
     unsigned *flag;
-    int size, base, dest, next, row, col, temp;
+    int size, base, dest;
 
     struct imageCell {
         unsigned char contents[8];
     };
     struct imageCell * img;
-    struct imageCell hold;
 
     switch ((flip+3600) % 360) {
-    case 270:  flip = 5;  break;
-    case 180:  flip = 3;  break;
-    case  90:  flip = 6;
+    case 270:  flip = 0x5;  break;
+    case 180:  flip = 0x3;  break;
+    case  90:  flip = 0x6;
     }
     img = (struct imageCell *) image;
     size = height * width;
     flag = calloc ((size+31) >> 5, sizeof *flag);
-    merror (flag, "flip_image()");
-    for (base = 0; base < size; base++) {
-        if (flag[base >> 5] & (1 << (base & 31)))
-            continue;
-        dest = base;
-        hold = img[base];
-        while (1) {
-            if (flip & 4) {
-                row = dest % height;
-                col = dest / height;
-            } else {
-                row = dest / width;
-                col = dest % width;
+    merror (flag, "flipImage()");
+    for (base = 0; base < size; ++base) {
+        if (flag[base >> 5] & (1 << (base & 31))) {
+            /* nothing */
+        } else {
+            struct imageCell const hold = img[base];
+            dest = base;
+            while (true) {
+                unsigned int col;
+                unsigned int row;
+                int next;
+                if (flip & 0x4) {
+                    row = dest % height;
+                    col = dest / height;
+                } else {
+                    row = dest / width;
+                    col = dest % width;
+                }
+                if (flip & 0x2)
+                    row = height - 1 - row;
+                if (flip & 1)
+                    col = width - 1 - col;
+                next = row * width + col;
+                if (next == base)
+                    break;
+                flag[next >> 5] |= 1 << (next & 31);
+                img[dest] = img[next];
+                dest = next;
             }
-            if (flip & 2)
-                row = height - 1 - row;
-            if (flip & 1)
-                col = width - 1 - col;
-            next = row * width + col;
-            if (next == base) break;
-            flag[next >> 5] |= 1 << (next & 31);
-            img[dest] = img[next];
-            dest = next;
+            img[dest] = hold;
         }
-        img[dest] = hold;
     }
     free (flag);
-    if (flip & 4) {
-        temp = height;
+    if (flip & 0x4) {
+        int const oldHeight = height;
+        int const oldYmag = ymag;
+
         height = width;
-        width = temp;
-        temp = ymag;
+        width = oldHeight;
         ymag = xmag;
-        xmag = temp;
+        xmag = oldYmag;
     }
 }
 
-/*
-   Write the image as an RGB PAM image
- */
-static void CLASS write_pam_nonlinear (FILE *ofp)
-{
-  unsigned char lut[0x10000];
-  int perc, c, val, total, i, row, col;
-  float white=0, r;
-  struct pam pam;
-  tuple * tuplerow;
-
-  pam.size   = sizeof(pam);
-  pam.len    = PAM_STRUCT_SIZE(tuple_type);
-  pam.file   = ofp;
-  pam.width  = xmag*(width-trim*2);
-  pam.height = ymag*(height-trim*2);
-  pam.depth  = 3;
-  pam.format = PAM_FORMAT;
-  pam.maxval = 255;
-  strcpy(pam.tuple_type, "RGB");
-
-  pnm_writepaminit(&pam);
-
-  tuplerow = pnm_allocpamrow(&pam);
-
-  perc = width * height * 0.01;     /* 99th percentile white point */
-  if (fuji_width) perc /= 2;
-  FORC3 {
-    for (val=0x2000, total=0; --val > 32; )
-      if ((total += histogram[c][val]) > perc) break;
-    if (white < val) white = val;
-  }
-  white *= 8 / cmdline.bright;
-  for (i=0; i < 0x10000; i++) {
-    r = i / white;
-    val = 256 * ( !use_gamma ? r :
-    r <= 0.018 ? r*4.5 : pow(r,0.45)*1.099-0.099 );
-    if (val > 255) val = 255;
-    lut[i] = val;
-  }
-  for (row=trim; row < height-trim; row++) {
-      for (col=trim; col < width-trim; col++) {
-          unsigned int plane;
-          for (plane=0; plane < pam.depth; ++plane) {
-              unsigned int copy;
-              for (copy=0; copy < xmag; ++copy) {
-                  unsigned int const pamcol = xmag*(col-trim)+copy;
-                  tuplerow[pamcol][plane] = lut[image[row*width+col][plane]];
-              }
-          }
-      }
-      {
-          unsigned int copy;
-          for (copy=0; copy < ymag; ++copy)
-              pnm_writepamrow(&pam, tuplerow);
-      }
-  }
-  pnm_freepamrow(tuplerow);
+
+
+static void CLASS
+writePamLinear(FILE *       const ofP,
+               Image        const image,
+               unsigned int const trim) {
+/*----------------------------------------------------------------------------
+   Write the image 'image' to a 16-bit PAM file with linear color space
+-----------------------------------------------------------------------------*/
+    unsigned int row;
+
+    struct pam pam;
+    tuple * tuplerow;
+
+    pam.size   = sizeof(pam);
+    pam.len    = PAM_STRUCT_SIZE(tuple_type);
+    pam.file   = ofP;
+    pam.width  = width - trim - trim;
+    pam.height = height - trim - trim;
+    pam.depth  = 3;
+    pam.format = PAM_FORMAT;
+    pam.maxval = MAX(maximum, 256);
+    strcpy(pam.tuple_type, "RGB");
+
+    pnm_writepaminit(&pam);
+
+    tuplerow = pnm_allocpamrow(&pam);
+
+    for (row = 0 + trim; row < height - trim; ++row) {
+        unsigned int col;
+        for (col = 0 + trim; col < width - trim; ++col) {
+            unsigned int const pamCol = col - trim;
+            unsigned int plane;
+            for (plane = 0; plane < 3; ++plane)
+                tuplerow[pamCol][plane] = image[row*width+col][plane];
+        }
+        pnm_writepamrow(&pam, tuplerow);
+    }
+    pnm_freepamrow(tuplerow);
 }
 
-/*
-   Write the image to a 16-bit PAM file with linear color space
- */
-static void CLASS write_pam_linear (FILE *ofp)
-{
-  int row;
-
-  struct pam pam;
-  tuple * tuplerow;
-
-  if (maximum < 256) maximum = 256;
-
-  pam.size   = sizeof(pam);
-  pam.len    = PAM_STRUCT_SIZE(tuple_type);
-  pam.file   = ofp;
-  pam.width  = width-trim*2;
-  pam.height = height-trim*2;
-  pam.depth  = 3;
-  pam.format = PAM_FORMAT;
-  pam.maxval = MAX(maximum, 256);
-  strcpy(pam.tuple_type, "RGB");
-
-  pnm_writepaminit(&pam);
-
-  tuplerow = pnm_allocpamrow(&pam);
-
-  for (row = trim; row < height-trim; row++) {
-      unsigned int col;
-      for (col = trim; col < width-trim; col++) {
-          unsigned int const pamCol = col - trim;
-          unsigned int plane;
-          for (plane = 0; plane < 3; ++plane)
-              tuplerow[pamCol][plane] = image[row*width+col][plane];
-      }
-      pnm_writepamrow(&pam, tuplerow);
-  }
-  pnm_freepamrow(tuplerow);
+
+
+static void CLASS
+writePamNonlinear(FILE *       const ofP,
+                  Image        const image,
+                  unsigned int const trim) {
+/*----------------------------------------------------------------------------
+  Write the image 'image' as an RGB PAM image
+-----------------------------------------------------------------------------*/
+    unsigned char lut[0x10000];
+    int perc;
+    int c;
+    int total;
+    int i;
+    unsigned int row;
+    float white;
+    float r;
+    struct pam pam;
+    tuple * tuplerow;
+
+    white = 0;  /* initial value */
+
+    pam.size   = sizeof(pam);
+    pam.len    = PAM_STRUCT_SIZE(tuple_type);
+    pam.file   = ofP;
+    pam.width  = xmag*(width-trim*2);
+    pam.height = ymag*(height-trim*2);
+    pam.depth  = 3;
+    pam.format = PAM_FORMAT;
+    pam.maxval = 255;
+    strcpy(pam.tuple_type, "RGB");
+
+    pnm_writepaminit(&pam);
+
+    tuplerow = pnm_allocpamrow(&pam);
+
+    perc = width * height * 0.01;     /* 99th percentile white point */
+    if (fuji_width) perc /= 2;
+    FORC3 {
+        int val;
+        for (val=0x2000, total=0; --val > 32; )
+            if ((total += histogram[c][val]) > perc) break;
+        if (white < val)
+            white = val;
+    }
+    white *= 8 / cmdline.bright;
+    for (i=0; i < 0x10000; ++i) {
+        int val;
+        r = i / white;
+        val = 256 * ( !use_gamma ? r :
+                      r <= 0.018 ? r*4.5 : pow(r,0.45)*1.099-0.099 );
+        lut[i] = MIN(255, val);
+    }
+
+    for (row = 0 + trim; row < height - trim; ++row) {
+        unsigned int col;
+        for (col = 0 + trim; col < width - trim; ++col) {
+            unsigned int plane;
+            for (plane = 0; plane < pam.depth; ++plane) {
+                sample const value = lut[image[row*width+col][plane]];
+                unsigned int copy;
+                for (copy = 0; copy < xmag; ++copy) {
+                    unsigned int const pamcol = xmag*(col-trim)+copy;
+                    tuplerow[pamcol][plane] = value;
+                }
+            }
+        }
+        {
+            unsigned int copy;
+            for (copy = 0; copy < ymag; ++copy)
+                pnm_writepamrow(&pam, tuplerow);
+        }
+    }
+    pnm_freepamrow(tuplerow);
 }
 
 
 
 static void CLASS
-writePam(FILE * const ofP,
-         bool   const linear) {
+writePam(FILE *       const ofP,
+         Image        const image,
+         bool         const linear,
+         unsigned int const trim) {
 
     if (linear)
-        write_pam_linear(ofP);
+        writePamLinear(ofP, image, trim);
     else
-        write_pam_nonlinear(ofP);
+        writePamNonlinear(ofP, image, trim);
 }
 
 
 
-
 static void CLASS
-convertIt(FILE *    const ifP,
-          FILE *    const ofP,
-          loadRawFn const load_raw) {
+convertIt(FILE *       const ifP,
+          FILE *       const ofP,
+          LoadRawFn *  const load_raw) {
+
+    Image image;
+    unsigned int trim;
 
     shrink = cmdline.half_size && filters;
     iheight = (height + shrink) >> shrink;
     iwidth  = (width  + shrink) >> shrink;
-    image = calloc (iheight*iwidth*sizeof *image + meta_length, 1);
+    image = calloc (iheight*iwidth*sizeof(*image) + meta_length, 1);
     merror (image, "main()");
     meta_data = (char *) (image + iheight*iwidth);
     if (cmdline.verbose)
@@ -807,43 +887,49 @@ convertIt(FILE *    const ifP,
 
     ifp = ifP;  /* Set global variable for (*load_raw)() */
 
-    load_raw();
-    bad_pixels();
+    load_raw(image);
+    fixBadPixels(image);
     height = iheight;
     width  = iwidth;
     if (is_foveon) {
         if (cmdline.verbose)
             pm_message ("Foveon interpolation...");
-        foveon_interpolate(coeff);
+        foveon_interpolate(image, coeff);
     } else {
-        scale_colors();
+        scaleColors(image);
     }
-    if (shrink) filters = 0;
-    trim = 0;
+    if (shrink)
+        filters = 0;
+
     if (filters && !cmdline.document_mode) {
         trim = 1;
         if (cmdline.verbose)
             pm_message ("%s interpolation...",
                         cmdline.quick_interpolate ? "Bilinear":"VNG");
-        vng_interpolate();
-    }
-    fuji_rotate();
-    apply_profile(ifP, cmdline.profile);
+        vngInterpolate(image);
+    } else
+        trim = 0;
+
+    fujiRotate(&image);
+
     if (cmdline.verbose)
         pm_message ("Converting to RGB colorspace...");
-    convert_to_rgb();
+    convertToRgb(image, trim);
 
     if (flip) {
         if (cmdline.verbose)
             pm_message ("Flipping image %c:%c:%c...",
                         flip & 1 ? 'H':'0', flip & 2 ? 'V':'0', 
                         flip & 4 ? 'T':'0');
-        flip_image();
+        flipImage(image);
     }
-    writePam(ofP, cmdline.linear);
+    writePam(ofP, image, cmdline.linear, trim);
+
+    free(image);
 }
 
 
+
 int 
 main (int argc, char **argv) {
 
@@ -851,7 +937,7 @@ main (int argc, char **argv) {
 
     FILE * ifP;
     int rc;
-    loadRawFn load_raw;
+    LoadRawFn * load_raw;
 
     pnm_init(&argc, argv);
 
@@ -861,8 +947,6 @@ main (int argc, char **argv) {
 
     ifP = pm_openr(cmdline.inputFileName);
 
-    image = NULL;
-    
     rc = identify(ifP,
                   cmdline.use_secondary, cmdline.use_camera_rgb,
                   cmdline.red_scale, cmdline.blue_scale,
@@ -881,7 +965,6 @@ main (int argc, char **argv) {
     }
     pm_close(ifP);
     pm_close(ofP);
-    free(image);
 
     return 0;
 }
diff --git a/converter/other/cameratopam/cameratopam.h b/converter/other/cameratopam/cameratopam.h
new file mode 100644
index 00000000..9ff33cb3
--- /dev/null
+++ b/converter/other/cameratopam/cameratopam.h
@@ -0,0 +1,6 @@
+#ifndef CAMERATOPAM_H_INCLUDED
+#define CAMERATOPAM_H_INCLUDED
+
+typedef unsigned short (*Image)[4];
+
+#endif
diff --git a/converter/other/cameratopam/canon.c b/converter/other/cameratopam/canon.c
index a34771d0..96a6210b 100644
--- a/converter/other/cameratopam/canon.c
+++ b/converter/other/cameratopam/canon.c
@@ -9,7 +9,7 @@
 
 
 void 
-canon_600_load_raw(void) {
+canon_600_load_raw(Image const image) {
     unsigned char  data[1120], *dp;
     unsigned short pixel[896], *pix;
     int irow, orow, col;
@@ -42,7 +42,7 @@ canon_600_load_raw(void) {
 
 
 void
-canon_a5_load_raw(void) {
+canon_a5_load_raw(Image const image) {
     unsigned char  data[1940], *dp;
     unsigned short pixel[1552], *pix;
     int row, col;
@@ -97,7 +97,7 @@ canon_has_lowbits()
 
 
 void 
-canon_compressed_load_raw(void) {
+canon_compressed_load_raw(Image const image) {
     unsigned short *pixel, *prow;
     int lowbits, i, row, r, col, save, val;
     unsigned irow, icol;
diff --git a/converter/other/cameratopam/canon.h b/converter/other/cameratopam/canon.h
index 041cdc4d..fe6a5a08 100644
--- a/converter/other/cameratopam/canon.h
+++ b/converter/other/cameratopam/canon.h
@@ -1,13 +1,12 @@
 #ifndef CANON_H_INCLUDED
 #define CANON_H_INCLUDED
 
-void 
-canon_600_load_raw(void);
+#include "camera.h"
 
-void
-canon_a5_load_raw(void);
+LoadRawFn canon_600_load_raw;
 
-void 
-canon_compressed_load_raw(void);
+LoadRawFn canon_a5_load_raw;
+
+LoadRawFn canon_compressed_load_raw;
 
 #endif
diff --git a/converter/other/cameratopam/dng.c b/converter/other/cameratopam/dng.c
index 44d45b02..bddfd9f4 100644
--- a/converter/other/cameratopam/dng.c
+++ b/converter/other/cameratopam/dng.c
@@ -4,70 +4,105 @@
 #include "dng.h"
 
 void 
-dng_coeff (double cc[4][4], double cm[4][3], double xyz[3])
-{
-  static const double rgb_xyz[3][3] = {     /* RGB from XYZ */
-    {  3.240479, -1.537150, -0.498535 },
-    { -0.969256,  1.875992,  0.041556 },
-    {  0.055648, -0.204043,  1.057311 } };
+dng_coeff (double cc[4][4],
+           double cm[4][3],
+           double xyz[3]) {
+    static const double rgb_xyz[3][3] = {     /* RGB from XYZ */
+        {  3.240479, -1.537150, -0.498535 },
+        { -0.969256,  1.875992,  0.041556 },
+        {  0.055648, -0.204043,  1.057311 } };
 #if 0
-  static const double xyz_rgb[3][3] = {     /* XYZ from RGB */
-    { 0.412453, 0.357580, 0.180423 },
-    { 0.212671, 0.715160, 0.072169 },
-    { 0.019334, 0.119193, 0.950227 } };
+    static const double xyz_rgb[3][3] = {     /* XYZ from RGB */
+        { 0.412453, 0.357580, 0.180423 },
+        { 0.212671, 0.715160, 0.072169 },
+        { 0.019334, 0.119193, 0.950227 } };
 #endif
-  double cam_xyz[4][3], xyz_cam[3][4], invert[3][6], num;
-  int i, j, k;
+    double cam_xyz[4][3], xyz_cam[3][4], invert[3][6];
+    unsigned int i;
 
-  memset (cam_xyz, 0, sizeof cam_xyz);
-  for (i=0; i < colors; i++)
-    for (j=0; j < 3; j++)
-      for (k=0; k < colors; k++)
-    cam_xyz[i][j] += cc[i][k] * cm[k][j] * xyz[j];
+    for (i = 0; i < colors; ++i) {
+        unsigned int j;
+        for (j = 0; j < 3; ++j) {
+            unsigned int k;
+            for (k = 0, cam_xyz[i][j] = 0.0; k < colors; ++k) {
+                cam_xyz[i][j] += cc[i][k] * cm[k][j] * xyz[j];
+            }
+        }
+    }
+    for (i = 0; i < colors; ++i) {
+        unsigned int j;
+        double camXyzSum;
+
+        for (j = 0, camXyzSum = 0.0; j < 3; ++j)
+            camXyzSum += cam_xyz[i][j];
 
-  for (i=0; i < colors; i++) {
-    for (num=j=0; j < 3; j++)
-      num += cam_xyz[i][j];
-    for (j=0; j < 3; j++)
-      cam_xyz[i][j] /= num;
-    pre_mul[i] = 1 / num;
-  }
-  for (i=0; i < 3; i++) {
-    for (j=0; j < 6; j++)
-      invert[i][j] = j == i+3;
-    for (j=0; j < 3; j++)
-      for (k=0; k < colors; k++)
-    invert[i][j] += cam_xyz[k][i] * cam_xyz[k][j];
-  }
-  for (i=0; i < 3; i++) {
-    num = invert[i][i];
-    for (j=0; j < 6; j++)       /* Normalize row i */
-      invert[i][j] /= num;
-    for (k=0; k < 3; k++) {     /* Subtract it from other rows */
-      if (k==i) continue;
-      num = invert[k][i];
-      for (j=0; j < 6; j++)
-    invert[k][j] -= invert[i][j] * num;
+        for (j = 0; j < 3; ++j)
+            cam_xyz[i][j] /= camXyzSum;
+
+        pre_mul[i] = 1 / camXyzSum;
+    }
+    for (i = 0; i < 3; ++i) {
+        unsigned int j;
+        for (j = 0; j < 6; ++j)
+            invert[i][j] = j == i+3;
+        for (j = 0; j < 3; ++j) {
+            unsigned int k;
+            for (k = 0; k < colors; ++k)
+                invert[i][j] += cam_xyz[k][i] * cam_xyz[k][j];
+        }
     }
-  }
-  memset (xyz_cam, 0, sizeof xyz_cam);
-  for (i=0; i < 3; i++)
-    for (j=0; j < colors; j++)
-      for (k=0; k < 3; k++)
-    xyz_cam[i][j] += invert[i][k+3] * cam_xyz[j][k];
+    for (i = 0; i < 3; ++i) {
+        double const num = invert[i][i];
+        unsigned int j;
+        unsigned int k;
+        for (j = 0; j < 6; ++j)       /* Normalize row i */
+            invert[i][j] /= num;
+        for (k = 0; k < 3; ++k) {     /* Subtract it from other rows */
+            if (k != i) {
+                double const num = invert[k][i];
+                unsigned int j;
+                for (j = 0; j < 6; ++j)
+                    invert[k][j] -= invert[i][j] * num;
+            }
+        }
+    }
+
+    memset(xyz_cam, 0, sizeof xyz_cam);
 
-  memset (coeff, 0, sizeof coeff);
-  for (i=0; i < 3; i++)
-    for (j=0; j < colors; j++)
-      for (k=0; k < 3; k++)
-    coeff[i][j] += rgb_xyz[i][k] * xyz_cam[k][j];
+    for (i = 0; i < 3; ++i) {
+        unsigned int j;
+        for (j = 0; j < colors; ++j) {
+            unsigned int k;
+            for (k = 0; k < 3; ++k)
+                xyz_cam[i][j] += invert[i][k+3] * cam_xyz[j][k];
+        }
+    }
+    memset (coeff, 0, sizeof coeff);
 
-  for (num=j=0; j < colors; j++)
-    num += coeff[1][j];
-  for (i=0; i < 3; i++) {
-    for (j=0; j < colors; j++)
-      coeff[i][j] /= num;
-  }
-  use_coeff = 1;
+    for (i = 0; i < 3; ++i) {
+        unsigned int j;
+        for (j = 0; j < colors; ++j) {
+            unsigned int k;
+            for (k = 0; k < 3; ++k)
+                coeff[i][j] += rgb_xyz[i][k] * xyz_cam[k][j];
+        }
+    }
+    {
+        double greenSum;
+        unsigned int j;
+        unsigned int i;
+
+        for (j = 0, greenSum = 0.0; j < colors; ++j)
+            greenSum += coeff[1][j];
+
+        for (i = 0; i < 3; ++i) {
+            unsigned int j;
+            for (j = 0; j < colors; ++j)
+                coeff[i][j] /= greenSum;
+        }
+    }
+    use_coeff = 1;
 }
 
+
+
diff --git a/converter/other/cameratopam/dng.h b/converter/other/cameratopam/dng.h
index 01e7e0a5..56293563 100644
--- a/converter/other/cameratopam/dng.h
+++ b/converter/other/cameratopam/dng.h
@@ -1,2 +1,4 @@
 void 
-dng_coeff (double cc[4][4], double cm[4][3], double xyz[3]);
+dng_coeff(double cc[4][4],
+          double cm[4][3],
+          double xyz[3]);
diff --git a/converter/other/cameratopam/foveon.c b/converter/other/cameratopam/foveon.c
index a8d62bee..a3e5449a 100644
--- a/converter/other/cameratopam/foveon.c
+++ b/converter/other/cameratopam/foveon.c
@@ -141,8 +141,8 @@ parse_foveon(FILE * const ifp) {
 
 
 void  
-foveon_coeff(bool * const useCoeffP,
-             float        coeff[3][4]) {
+foveon_coeff(int * const useCoeffP,
+             float       coeff[3][4]) {
 
     static const float foveon[3][3] =
     { {  1.4032, -0.2231, -0.1016 },
@@ -211,7 +211,7 @@ foveon_load_camf() {
 
 
 void  
-foveon_load_raw() {
+foveon_load_raw(Image const image) {
 
     struct decode *dindex;
     short diff[1024], pred[3];
@@ -391,7 +391,8 @@ static int  foveon_apply_curve (short *curve, int i)
 }
 
 void  
-foveon_interpolate(float coeff[3][4]) {
+foveon_interpolate(Image const image,
+                   float coeff[3][4]) {
 
     static const short hood[] = { 
         -1,-1, -1,0, -1,1, 0,-1, 0,1, 1,-1, 1,0, 1,1 };
@@ -472,18 +473,22 @@ foveon_interpolate(float coeff[3][4]) {
     sgrow = calloc (dim[1], sizeof *sgrow);
     sgx = (width + dim[1]-2) / (dim[1]-1);
 
-    black = calloc (height, sizeof *black);
-    for (row=0; row < height; row++) {
-        for (i=0; i < 6; i++)
-            ddft[0][0][i] = ddft[1][0][i] +
-                row / (height-1.0) * (ddft[2][0][i] - ddft[1][0][i]);
+    black = calloc (height, sizeof(black[0]));
+    for (row=0; row < height; ++row) {
+        unsigned int i;
+        for (i=0; i < 3; ++i) {
+            unsigned int j;
+            for (j = 0; j < 2; ++j)
+                ddft[0][i][j] = ddft[1][i][j] +
+                    row / (height-1.0) * (ddft[2][i][j] - ddft[1][i][j]);
+        }
         FORC3 black[row][c] =
             ( foveon_avg (image[row*width]+c, dscr[0], cfilt) +
               foveon_avg (image[row*width]+c, dscr[1], cfilt) * 3
               - ddft[0][c][0] ) / 4 - ddft[0][c][1];
     }
-    memcpy (black, black+8, sizeof (*black)*8);
-    memcpy (black+height-11, black+height-22, 11*sizeof *black);
+    memcpy (black, black+8, 8 * sizeof(black[0]));
+    memcpy (black+height-11, black+height-22, 11*(sizeof black[0]));
     memcpy (last, black, sizeof last);
 
     for (row=1; row < height-1; row++) {
@@ -522,9 +527,13 @@ foveon_interpolate(float coeff[3][4]) {
         FORC3 black[row][c] += fsum[c]/2 + total[c]/(total[3]*100.0);
 
     for (row=0; row < height; row++) {
-        for (i=0; i < 6; i++)
-            ddft[0][0][i] = ddft[1][0][i] +
-                row / (height-1.0) * (ddft[2][0][i] - ddft[1][0][i]);
+        unsigned int i;
+        for (i = 0; i < 3; ++i) {
+            unsigned int j;
+            for (j = 0; j < 2; ++j)
+                ddft[0][i][j] = ddft[1][i][j] +
+                    row / (height-1.0) * (ddft[2][i][j] - ddft[1][i][j]);
+        }
         pix = (short*)image[row*width];
         memcpy (prev, pix, sizeof prev);
         frow = row / (height-1.0) * (dim[2]-1);
diff --git a/converter/other/cameratopam/foveon.h b/converter/other/cameratopam/foveon.h
index 57be2244..c9bf48a8 100644
--- a/converter/other/cameratopam/foveon.h
+++ b/converter/other/cameratopam/foveon.h
@@ -1,14 +1,17 @@
 #include "pm.h"
 
+#include "cameratopam.h"
+#include "camera.h"
+
 void 
 parse_foveon(FILE * const ifp);
 
 void  
-foveon_interpolate(float coeff[3][4]);
+foveon_interpolate(Image const image,
+                   float coeff[3][4]);
 
-void 
-foveon_load_raw(void);
+LoadRawFn foveon_load_raw;
 
 void  
-foveon_coeff(bool * const useCoeffP,
-             float        coeff[3][4]);
+foveon_coeff(int * const useCoeffP,
+             float       coeff[3][4]);
diff --git a/converter/other/cameratopam/global_variables.h b/converter/other/cameratopam/global_variables.h
index c8732d5a..2bfc08c9 100644
--- a/converter/other/cameratopam/global_variables.h
+++ b/converter/other/cameratopam/global_variables.h
@@ -23,7 +23,6 @@ extern time_t timestamp;
 extern int is_foveon;
 extern int is_dng;
 extern int is_canon;
-extern unsigned short (*image)[4];
 extern int maximum;
 extern int clip_max;
 extern short order;
diff --git a/converter/other/cameratopam/identify.c b/converter/other/cameratopam/identify.c
index a101c8ad..02208be6 100644
--- a/converter/other/cameratopam/identify.c
+++ b/converter/other/cameratopam/identify.c
@@ -2,6 +2,8 @@
 #include <string.h>
 
 #include "pm.h"
+#include "pm_c_util.h"
+#include "nstring.h"
 
 #include "global_variables.h"
 #include "util.h"
@@ -15,235 +17,250 @@
 
 
 #if HAVE_INT64
-   static bool const have64BitArithmetic = true;
+static bool const have64BitArithmetic = true;
 #else
-   static bool const have64BitArithmetic = false;
+static bool const have64BitArithmetic = false;
 #endif
 
 
-static loadRawFn load_raw;
 
 /* This does the same as the function of the same name in the GNU C library */
 static const char *memmem_internal (const char *haystack, size_t haystacklen,
-                     const char *needle, size_t needlelen)
+                                    const char *needle, size_t needlelen)
 {
-  const char *c;
-  for (c = haystack; c <= haystack + haystacklen - needlelen; c++)
-    if (!memcmp (c, needle, needlelen))
-      return c;
-  return NULL;
+    const char *c;
+    for (c = haystack; c <= haystack + haystacklen - needlelen; c++)
+        if (!memcmp (c, needle, needlelen))
+            return c;
+    return NULL;
 }
 
-/*
-   Thanks to Adobe for providing these excellent CAM -> XYZ matrices!
- */
+
+
 static void 
-adobe_coeff()
-{
-  static const struct {
-    const char *prefix;
-    short trans[12];
-  } table[] = {
-    { "Canon EOS D2000C",
-    { 24542,-10860,-3401,-1490,11370,-297,2858,-605,3225 } },
-    { "Canon EOS D30",
-    { 9805,-2689,-1312,-5803,13064,3068,-2438,3075,8775 } },
-    { "Canon EOS D60",
-    { 6188,-1341,-890,-7168,14489,2937,-2640,3228,8483 } },
-    { "Canon EOS 10D",
-    { 8197,-2000,-1118,-6714,14335,2592,-2536,3178,8266 } },
-    { "Canon EOS 20D",
-    { 6599,-537,-891,-8071,15783,2424,-1983,2234,7462 } },
-    { "Canon EOS-1Ds Mark II",
-    { 6517,-602,-867,-8180,15926,2378,-1618,1771,7633 } },
-    { "Canon EOS-1D Mark II",
-    { 6264,-582,-724,-8312,15948,2504,-1744,1919,8664 } },
-    { "Canon EOS-1DS",
-    { 4374,3631,-1743,-7520,15212,2472,-2892,3632,8161 } },
-    { "Canon EOS-1D",
-    { 6906,-278,-1017,-6649,15074,1621,-2848,3897,7611 } },
-    { "Canon EOS",
-    { 8197,-2000,-1118,-6714,14335,2592,-2536,3178,8266 } },
-    { "Canon PowerShot 600",
-    { -3822,10019,1311,4085,-157,3386,-5341,10829,4812,-1969,10969,1126 } },
-    { "Canon PowerShot A50",
-    { -5300,9846,1776,3436,684,3939,-5540,9879,6200,-1404,11175,217 } },
-    { "Canon PowerShot A5",
-    { -4801,9475,1952,2926,1611,4094,-5259,10164,5947,-1554,10883,547 } },
-    { "Canon PowerShot G1",
-    { -4778,9467,2172,4743,-1141,4344,-5146,9908,6077,-1566,11051,557 } },
-    { "Canon PowerShot G2",
-    { 9087,-2693,-1049,-6715,14382,2537,-2291,2819,7790 } },
-    { "Canon PowerShot G3",
-    { 9212,-2781,-1073,-6573,14189,2605,-2300,2844,7664 } },
-    { "Canon PowerShot G5",
-    { 9757,-2872,-933,-5972,13861,2301,-1622,2328,7212 } },
-    { "Canon PowerShot G6",
-    { 9877,-3775,-871,-7613,14807,3072,-1448,1305,7485 } },
-    { "Canon PowerShot Pro1",
-    { 10062,-3522,-999,-7643,15117,2730,-765,817,7323 } },
-    { "Canon PowerShot Pro70",
-    { -4155,9818,1529,3939,-25,4522,-5521,9870,6610,-2238,10873,1342 } },
-    { "Canon PowerShot Pro90",
-    { -4963,9896,2235,4642,-987,4294,-5162,10011,5859,-1770,11230,577 } },
-    { "Canon PowerShot S30",
-    { 10566,-3652,-1129,-6552,14662,2006,-2197,2581,7670 } },
-    { "Canon PowerShot S40",
-    { 8510,-2487,-940,-6869,14231,2900,-2318,2829,9013 } },
-    { "Canon PowerShot S45",
-    { 8163,-2333,-955,-6682,14174,2751,-2077,2597,8041 } },
-    { "Canon PowerShot S50",
-    { 8882,-2571,-863,-6348,14234,2288,-1516,2172,6569 } },
-    { "Canon PowerShot S70",
-    { 9976,-3810,-832,-7115,14463,2906,-901,989,7889 } },
-    { "Contax N Digital",
-    { 7777,1285,-1053,-9280,16543,2916,-3677,5679,7060 } },
-    { "EPSON R-D1",
-    { 6827,-1878,-732,-8429,16012,2564,-704,592,7145 } },
-    { "FUJIFILM FinePix E550",
-    { 11044,-3888,-1120,-7248,15168,2208,-1531,2277,8069 } },
-    { "FUJIFILM FinePix F700",
-    { 10004,-3219,-1201,-7036,15047,2107,-1863,2565,7736 } },
-    { "FUJIFILM FinePix S20Pro",
-    { 10004,-3219,-1201,-7036,15047,2107,-1863,2565,7736 } },
-    { "FUJIFILM FinePix S2Pro",
-    { 12492,-4690,-1402,-7033,15423,1647,-1507,2111,7697 } },
-    { "FUJIFILM FinePix S3Pro",
-    { 11807,-4612,-1294,-8927,16968,1988,-2120,2741,8006 } },
-    { "FUJIFILM FinePix S5000",
-    { 8754,-2732,-1019,-7204,15069,2276,-1702,2334,6982 } },
-    { "FUJIFILM FinePix S5100",
-    { 11940,-4431,-1255,-6766,14428,2542,-993,1165,7421 } },
-    { "FUJIFILM FinePix S7000",
-    { 10190,-3506,-1312,-7153,15051,2238,-2003,2399,7505 } },
-    { "Kodak DCS315C",
-    { 17523,-4827,-2510,756,8546,-137,6113,1649,2250 } },
-    { "Kodak DCS330C",
-    { 20620,-7572,-2801,-103,10073,-396,3551,-233,2220 } },
-    { "KODAK DCS420",
-    { 10868,-1852,-644,-1537,11083,484,2343,628,2216 } },
-    { "KODAK DCS460",
-    { 10592,-2206,-967,-1944,11685,230,2206,670,1273 } },
-    { "KODAK EOSDCS1",
-    { 10592,-2206,-967,-1944,11685,230,2206,670,1273 } },
-    { "KODAK EOSDCS3B",
-    { 9898,-2700,-940,-2478,12219,206,1985,634,1031 } },
-    { "Kodak DCS520C",
-    { 24542,-10860,-3401,-1490,11370,-297,2858,-605,3225 } },
-    { "Kodak DCS560C",
-    { 20482,-7172,-3125,-1033,10410,-285,2542,226,3136 } },
-    { "Kodak DCS620C",
-    { 23617,-10175,-3149,-2054,11749,-272,2586,-489,3453 } },
-    { "Kodak DCS620X",
-    { 13095,-6231,154,12221,-21,-2137,895,4602,2258 } },
-    { "Kodak DCS660C",
-    { 18244,-6351,-2739,-791,11193,-521,3711,-129,2802 } },
-    { "Kodak DCS720X",
-    { 11775,-5884,950,9556,1846,-1286,-1019,6221,2728 } },
-    { "Kodak DCS760C",
-    { 16623,-6309,-1411,-4344,13923,323,2285,274,2926 } },
-    { "Kodak DCS Pro SLR",
-    { 5494,2393,-232,-6427,13850,2846,-1876,3997,5445 } },
-    { "Kodak DCS Pro 14nx",
-    { 5494,2393,-232,-6427,13850,2846,-1876,3997,5445 } },
-    { "Kodak DCS Pro 14",
-    { 7791,3128,-776,-8588,16458,2039,-2455,4006,6198 } },
-    { "Kodak ProBack645",
-    { 16414,-6060,-1470,-3555,13037,473,2545,122,4948 } },
-    { "Kodak ProBack",
-    { 21179,-8316,-2918,-915,11019,-165,3477,-180,4210 } },
-    { "LEICA DIGILUX 2",
-    { 11340,-4069,-1275,-7555,15266,2448,-2960,3426,7685 } },
-    { "Leaf Valeo",
-    { 8236,1746,-1314,-8251,15953,2428,-3673,5786,5771 } },
-    { "Minolta DiMAGE 5",
-    { 8983,-2942,-963,-6556,14476,2237,-2426,2887,8014 } },
-    { "Minolta DiMAGE 7",
-    { 9144,-2777,-998,-6676,14556,2281,-2470,3019,7744 } },
-    { "Minolta DiMAGE A1",
-    { 9274,-2547,-1167,-8220,16323,1943,-2273,2720,8340 } },
-    { "MINOLTA DiMAGE A200",
-    { 8560,-2487,-986,-8112,15535,2771,-1209,1324,7743 } },
-    { "Minolta DiMAGE A2",
-    { 9097,-2726,-1053,-8073,15506,2762,-966,981,7763 } },
-    { "MINOLTA DYNAX 7D",
-    { 10239,-3104,-1099,-8037,15727,2451,-927,925,6871 } },
-    { "NIKON D100",
-    { 5915,-949,-778,-7516,15364,2282,-1228,1337,6404 } },
-    { "NIKON D1H",
-    { 7577,-2166,-926,-7454,15592,1934,-2377,2808,8606 } },
-    { "NIKON D1X",
-    { 7620,-2173,-966,-7604,15843,1805,-2356,2811,8439 } },
-    { "NIKON D1",
-    { 7559,-2130,-965,-7611,15713,1972,-2478,3042,8290 } },
-    { "NIKON D2H",
-    { 5710,-901,-615,-8594,16617,2024,-2975,4120,6830 } },
-    { "NIKON D70",
-    { 7732,-2422,-789,-8238,15884,2498,-859,783,7330 } },
-    { "NIKON E995", /* copied from E5000 */
-    { -5547,11762,2189,5814,-558,3342,-4924,9840,5949,688,9083,96 } },
-    { "NIKON E2500",
-    { -5547,11762,2189,5814,-558,3342,-4924,9840,5949,688,9083,96 } },
-    { "NIKON E4500",
-    { -5547,11762,2189,5814,-558,3342,-4924,9840,5949,688,9083,96 } },
-    { "NIKON E5000",
-    { -5547,11762,2189,5814,-558,3342,-4924,9840,5949,688,9083,96 } },
-    { "NIKON E5400",
-    { 9349,-2987,-1001,-7919,15766,2266,-2098,2680,6839 } },
-    { "NIKON E5700",
-    { -5368,11478,2368,5537,-113,3148,-4969,10021,5782,778,9028,211 } },
-    { "NIKON E8400",
-    { 7842,-2320,-992,-8154,15718,2599,-1098,1342,7560 } },
-    { "NIKON E8700",
-    { 8489,-2583,-1036,-8051,15583,2643,-1307,1407,7354 } },
-    { "NIKON E8800",
-    { 7971,-2314,-913,-8451,15762,2894,-1442,1520,7610 } },
-    { "OLYMPUS C5050",
-    { 10508,-3124,-1273,-6079,14294,1901,-1653,2306,6237 } },
-    { "OLYMPUS C5060",
-    { 10445,-3362,-1307,-7662,15690,2058,-1135,1176,7602 } },
-    { "OLYMPUS C70",
-    { 10793,-3791,-1146,-7498,15177,2488,-1390,1577,7321 } },
-    { "OLYMPUS C80",
-    { 8606,-2509,-1014,-8238,15714,2703,-942,979,7760 } },
-    { "OLYMPUS E-10",
-    { 12745,-4500,-1416,-6062,14542,1580,-1934,2256,6603 } },
-    { "OLYMPUS E-1",
-    { 11846,-4767,-945,-7027,15878,1089,-2699,4122,8311 } },
-    { "OLYMPUS E-20",
-    { 13173,-4732,-1499,-5807,14036,1895,-2045,2452,7142 } },
-    { "OLYMPUS E-300",
-    { 7828,-1761,-348,-5788,14071,1830,-2853,4518,6557 } },
-    { "PENTAX *ist D",
-    { 9651,-2059,-1189,-8881,16512,2487,-1460,1345,10687 } },
-    { "Panasonic DMC-LC1",
-    { 11340,-4069,-1275,-7555,15266,2448,-2960,3426,7685 } },
-    { "SONY DSC-F828",
-    { 7924,-1910,-777,-8226,15459,2998,-1517,2199,6818,-7242,11401,3481 } },
-    { "SONY DSC-V3",
-    { 9877,-3775,-871,-7613,14807,3072,-1448,1305,7485 } }
-  };
-  double cc[4][4], cm[4][3], xyz[] = { 1,1,1 };
-  char name[130];
-  int i, j;
+adobeCoeff(const char * const make,
+           const char * const model) {
+    /*
+      Thanks to Adobe for providing these excellent CAM -> XYZ matrices!
+    */
+    struct CoeffTableEntry {
+        const char * prefix;
+        short trans[12];
+    }; 
+
+    static struct CoeffTableEntry const table[] = {
+        { "Canon EOS D2000C",
+          { 24542,-10860,-3401,-1490,11370,-297,2858,-605,3225 } },
+        { "Canon EOS D30",
+          { 9805,-2689,-1312,-5803,13064,3068,-2438,3075,8775 } },
+        { "Canon EOS D60",
+          { 6188,-1341,-890,-7168,14489,2937,-2640,3228,8483 } },
+        { "Canon EOS 10D",
+          { 8197,-2000,-1118,-6714,14335,2592,-2536,3178,8266 } },
+        { "Canon EOS 20D",
+          { 6599,-537,-891,-8071,15783,2424,-1983,2234,7462 } },
+        { "Canon EOS-1Ds Mark II",
+          { 6517,-602,-867,-8180,15926,2378,-1618,1771,7633 } },
+        { "Canon EOS-1D Mark II",
+          { 6264,-582,-724,-8312,15948,2504,-1744,1919,8664 } },
+        { "Canon EOS-1DS",
+          { 4374,3631,-1743,-7520,15212,2472,-2892,3632,8161 } },
+        { "Canon EOS-1D",
+          { 6906,-278,-1017,-6649,15074,1621,-2848,3897,7611 } },
+        { "Canon EOS",
+          { 8197,-2000,-1118,-6714,14335,2592,-2536,3178,8266 } },
+        { "Canon PowerShot 600",
+          { -3822,10019,1311,4085,-157,3386,-5341,10829,4812,-1969,10969,
+            1126} },
+        { "Canon PowerShot A50",
+          { -5300,9846,1776,3436,684,3939,-5540,9879,6200,-1404,11175,217 } },
+        { "Canon PowerShot A5",
+          { -4801,9475,1952,2926,1611,4094,-5259,10164,5947,-1554,10883,547} },
+        { "Canon PowerShot G1",
+          { -4778,9467,2172,4743,-1141,4344,-5146,9908,6077,-1566,11051,557} },
+        { "Canon PowerShot G2",
+          { 9087,-2693,-1049,-6715,14382,2537,-2291,2819,7790 } },
+        { "Canon PowerShot G3",
+          { 9212,-2781,-1073,-6573,14189,2605,-2300,2844,7664 } },
+        { "Canon PowerShot G5",
+          { 9757,-2872,-933,-5972,13861,2301,-1622,2328,7212 } },
+        { "Canon PowerShot G6",
+          { 9877,-3775,-871,-7613,14807,3072,-1448,1305,7485 } },
+        { "Canon PowerShot Pro1",
+          { 10062,-3522,-999,-7643,15117,2730,-765,817,7323 } },
+        { "Canon PowerShot Pro70",
+          { -4155,9818,1529,3939,-25,4522,-5521,9870,6610,-2238,10873,1342 } },
+        { "Canon PowerShot Pro90",
+          { -4963,9896,2235,4642,-987,4294,-5162,10011,5859,-1770,11230,577} },
+        { "Canon PowerShot S30",
+          { 10566,-3652,-1129,-6552,14662,2006,-2197,2581,7670 } },
+        { "Canon PowerShot S40",
+          { 8510,-2487,-940,-6869,14231,2900,-2318,2829,9013 } },
+        { "Canon PowerShot S45",
+          { 8163,-2333,-955,-6682,14174,2751,-2077,2597,8041 } },
+        { "Canon PowerShot S50",
+          { 8882,-2571,-863,-6348,14234,2288,-1516,2172,6569 } },
+        { "Canon PowerShot S70",
+          { 9976,-3810,-832,-7115,14463,2906,-901,989,7889 } },
+        { "Contax N Digital",
+          { 7777,1285,-1053,-9280,16543,2916,-3677,5679,7060 } },
+        { "EPSON R-D1",
+          { 6827,-1878,-732,-8429,16012,2564,-704,592,7145 } },
+        { "FUJIFILM FinePix E550",
+          { 11044,-3888,-1120,-7248,15168,2208,-1531,2277,8069 } },
+        { "FUJIFILM FinePix F700",
+          { 10004,-3219,-1201,-7036,15047,2107,-1863,2565,7736 } },
+        { "FUJIFILM FinePix S20Pro",
+          { 10004,-3219,-1201,-7036,15047,2107,-1863,2565,7736 } },
+        { "FUJIFILM FinePix S2Pro",
+          { 12492,-4690,-1402,-7033,15423,1647,-1507,2111,7697 } },
+        { "FUJIFILM FinePix S3Pro",
+          { 11807,-4612,-1294,-8927,16968,1988,-2120,2741,8006 } },
+        { "FUJIFILM FinePix S5000",
+          { 8754,-2732,-1019,-7204,15069,2276,-1702,2334,6982 } },
+        { "FUJIFILM FinePix S5100",
+          { 11940,-4431,-1255,-6766,14428,2542,-993,1165,7421 } },
+        { "FUJIFILM FinePix S7000",
+          { 10190,-3506,-1312,-7153,15051,2238,-2003,2399,7505 } },
+        { "Kodak DCS315C",
+          { 17523,-4827,-2510,756,8546,-137,6113,1649,2250 } },
+        { "Kodak DCS330C",
+          { 20620,-7572,-2801,-103,10073,-396,3551,-233,2220 } },
+        { "KODAK DCS420",
+          { 10868,-1852,-644,-1537,11083,484,2343,628,2216 } },
+        { "KODAK DCS460",
+          { 10592,-2206,-967,-1944,11685,230,2206,670,1273 } },
+        { "KODAK EOSDCS1",
+          { 10592,-2206,-967,-1944,11685,230,2206,670,1273 } },
+        { "KODAK EOSDCS3B",
+          { 9898,-2700,-940,-2478,12219,206,1985,634,1031 } },
+        { "Kodak DCS520C",
+          { 24542,-10860,-3401,-1490,11370,-297,2858,-605,3225 } },
+        { "Kodak DCS560C",
+          { 20482,-7172,-3125,-1033,10410,-285,2542,226,3136 } },
+        { "Kodak DCS620C",
+          { 23617,-10175,-3149,-2054,11749,-272,2586,-489,3453 } },
+        { "Kodak DCS620X",
+          { 13095,-6231,154,12221,-21,-2137,895,4602,2258 } },
+        { "Kodak DCS660C",
+          { 18244,-6351,-2739,-791,11193,-521,3711,-129,2802 } },
+        { "Kodak DCS720X",
+          { 11775,-5884,950,9556,1846,-1286,-1019,6221,2728 } },
+        { "Kodak DCS760C",
+          { 16623,-6309,-1411,-4344,13923,323,2285,274,2926 } },
+        { "Kodak DCS Pro SLR",
+          { 5494,2393,-232,-6427,13850,2846,-1876,3997,5445 } },
+        { "Kodak DCS Pro 14nx",
+          { 5494,2393,-232,-6427,13850,2846,-1876,3997,5445 } },
+        { "Kodak DCS Pro 14",
+          { 7791,3128,-776,-8588,16458,2039,-2455,4006,6198 } },
+        { "Kodak ProBack645",
+          { 16414,-6060,-1470,-3555,13037,473,2545,122,4948 } },
+        { "Kodak ProBack",
+          { 21179,-8316,-2918,-915,11019,-165,3477,-180,4210 } },
+        { "LEICA DIGILUX 2",
+          { 11340,-4069,-1275,-7555,15266,2448,-2960,3426,7685 } },
+        { "Leaf Valeo",
+          { 8236,1746,-1314,-8251,15953,2428,-3673,5786,5771 } },
+        { "Minolta DiMAGE 5",
+          { 8983,-2942,-963,-6556,14476,2237,-2426,2887,8014 } },
+        { "Minolta DiMAGE 7",
+          { 9144,-2777,-998,-6676,14556,2281,-2470,3019,7744 } },
+        { "Minolta DiMAGE A1",
+          { 9274,-2547,-1167,-8220,16323,1943,-2273,2720,8340 } },
+        { "MINOLTA DiMAGE A200",
+          { 8560,-2487,-986,-8112,15535,2771,-1209,1324,7743 } },
+        { "Minolta DiMAGE A2",
+          { 9097,-2726,-1053,-8073,15506,2762,-966,981,7763 } },
+        { "MINOLTA DYNAX 7D",
+          { 10239,-3104,-1099,-8037,15727,2451,-927,925,6871 } },
+        { "NIKON D100",
+          { 5915,-949,-778,-7516,15364,2282,-1228,1337,6404 } },
+        { "NIKON D1H",
+          { 7577,-2166,-926,-7454,15592,1934,-2377,2808,8606 } },
+        { "NIKON D1X",
+          { 7620,-2173,-966,-7604,15843,1805,-2356,2811,8439 } },
+        { "NIKON D1",
+          { 7559,-2130,-965,-7611,15713,1972,-2478,3042,8290 } },
+        { "NIKON D2H",
+          { 5710,-901,-615,-8594,16617,2024,-2975,4120,6830 } },
+        { "NIKON D70",
+          { 7732,-2422,-789,-8238,15884,2498,-859,783,7330 } },
+        { "NIKON E995", /* copied from E5000 */
+          { -5547,11762,2189,5814,-558,3342,-4924,9840,5949,688,9083,96 } },
+        { "NIKON E2500",
+          { -5547,11762,2189,5814,-558,3342,-4924,9840,5949,688,9083,96 } },
+        { "NIKON E4500",
+          { -5547,11762,2189,5814,-558,3342,-4924,9840,5949,688,9083,96 } },
+        { "NIKON E5000",
+          { -5547,11762,2189,5814,-558,3342,-4924,9840,5949,688,9083,96 } },
+        { "NIKON E5400",
+          { 9349,-2987,-1001,-7919,15766,2266,-2098,2680,6839 } },
+        { "NIKON E5700",
+          { -5368,11478,2368,5537,-113,3148,-4969,10021,5782,778,9028,211 } },
+        { "NIKON E8400",
+          { 7842,-2320,-992,-8154,15718,2599,-1098,1342,7560 } },
+        { "NIKON E8700",
+          { 8489,-2583,-1036,-8051,15583,2643,-1307,1407,7354 } },
+        { "NIKON E8800",
+          { 7971,-2314,-913,-8451,15762,2894,-1442,1520,7610 } },
+        { "OLYMPUS C5050",
+          { 10508,-3124,-1273,-6079,14294,1901,-1653,2306,6237 } },
+        { "OLYMPUS C5060",
+          { 10445,-3362,-1307,-7662,15690,2058,-1135,1176,7602 } },
+        { "OLYMPUS C70",
+          { 10793,-3791,-1146,-7498,15177,2488,-1390,1577,7321 } },
+        { "OLYMPUS C80",
+          { 8606,-2509,-1014,-8238,15714,2703,-942,979,7760 } },
+        { "OLYMPUS E-10",
+          { 12745,-4500,-1416,-6062,14542,1580,-1934,2256,6603 } },
+        { "OLYMPUS E-1",
+          { 11846,-4767,-945,-7027,15878,1089,-2699,4122,8311 } },
+        { "OLYMPUS E-20",
+          { 13173,-4732,-1499,-5807,14036,1895,-2045,2452,7142 } },
+        { "OLYMPUS E-300",
+          { 7828,-1761,-348,-5788,14071,1830,-2853,4518,6557 } },
+        { "PENTAX *ist D",
+          { 9651,-2059,-1189,-8881,16512,2487,-1460,1345,10687 } },
+        { "Panasonic DMC-LC1",
+          { 11340,-4069,-1275,-7555,15266,2448,-2960,3426,7685 } },
+        { "SONY DSC-F828",
+          { 7924,-1910,-777,-8226,15459,2998,-1517,2199,6818,-7242,11401,
+            3481} },
+        { "SONY DSC-V3",
+          { 9877,-3775,-871,-7613,14807,3072,-1448,1305,7485 } }
+    };
+    double cc[4][4];
+    double cm[4][3];
+    double xyz[] = { 1,1,1 };
+    char name[130];
+    unsigned int i;
 
-  for (i=0; i < 4; i++)
-    for (j=0; j < 4; j++)
-      cc[i][j] = i == j;
-  sprintf (name, "%s %s", make, model);
-  for (i=0; i < sizeof table / sizeof *table; i++)
-    if (!strncmp (name, table[i].prefix, strlen(table[i].prefix))) {
-      for (j=0; j < 12; j++)
-    cm[0][j] = table[i].trans[j];
-      dng_coeff (cc, cm, xyz);
-      break;
+    /* Make an identity matrix (1's on the diagonal) */
+    for (i = 0; i < 4; ++i) {
+        unsigned int j;
+        for (j = 0; j < 4; ++j)
+            cc[i][j] = (i == j);
+    }
+    sprintf (name, "%s %s", make, model);
+
+    for (i = 0; i < ARRAY_SIZE(table); ++i) {
+        const struct CoeffTableEntry * const entryP = &table[i];
+
+        if (strneq(name, entryP->prefix, strlen(entryP->prefix))) {
+            unsigned int j;
+            for (j = 0; j < 12; ++j)
+                cm[j/3][j%3] = entryP->trans[j];
+            dng_coeff(cc, cm, xyz);
+
+            break;
+        }
     }
 }
 
-/*
-   Identify which camera created this file, and set global variables
-   accordingly.  Return nonzero if the file cannot be decoded.
- */
+
+
+
 int
 identify(FILE *       const ifp,
          bool         const use_secondary,
@@ -252,932 +269,937 @@ identify(FILE *       const ifp,
          float        const blue_scale,
          unsigned int const four_color_rgb,
          const char * const inputFileName,
-         loadRawFn *  const loadRawFnP)
-{
-  char head[32];
-  char * c;
-  unsigned hlen, fsize, i;
-  static const struct {
-    int fsize;
-    char make[12], model[15], withjpeg;
-  } table[] = {
-    {    62464, "Kodak",    "DC20"       ,0 },
-    {   124928, "Kodak",    "DC20"       ,0 },
-    {   311696, "ST Micro", "STV680 VGA" ,0 },  /* SPYz */
-    {   787456, "Creative", "PC-CAM 600" ,0 },
-    {  2465792, "NIKON",    "E950"       ,1 },  /* or E800,E700 */
-    {  2940928, "NIKON",    "E2100"      ,1 },  /* or E2500 */
-    {  4771840, "NIKON",    "E990"       ,1 },  /* or E995 */
-    {  4775936, "NIKON",    "E3700"      ,1 },  /* or Optio 33WR */
-    {  5869568, "NIKON",    "E4300"      ,1 },  /* or DiMAGE Z2 */
-    {  5865472, "NIKON",    "E4500"      ,0 },
-    {  1976352, "CASIO",    "QV-2000UX"  ,0 },
-    {  3217760, "CASIO",    "QV-3*00EX"  ,0 },
-    {  6218368, "CASIO",    "QV-5700"    ,0 },
-    {  7530816, "CASIO",    "QV-R51"     ,1 },
-    {  7684000, "CASIO",    "QV-4000"    ,0 },
-    {  7753344, "CASIO",    "EX-Z55"     ,1 },
-    {  9313536, "CASIO",    "EX-P600"    ,1 },
-    { 10979200, "CASIO",    "EX-P700"    ,1 },
-    {  3178560, "PENTAX",   "Optio S"    ,1 },  /*  8-bit */
-    {  4841984, "PENTAX",   "Optio S"    ,1 },  /* 12-bit */
-    {  6114240, "PENTAX",   "Optio S4"   ,1 },  /* or S4i */
-    { 12582980, "Sinar",    ""           ,0 } };
-  static const char *corp[] =
-    { "Canon", "NIKON", "EPSON", "Kodak", "OLYMPUS", "PENTAX",
-      "MINOLTA", "Minolta", "Konica", "CASIO" };
-  float tmp;
-
-  /*  What format is this file?  Set make[] if we recognize it. */
+         LoadRawFn ** const loadRawFnP) {
+/*----------------------------------------------------------------------------
+  Identify which camera created this file, and set global variables
+  accordingly.  Return nonzero if the file cannot be decoded.
+-----------------------------------------------------------------------------*/
+    char head[32];
+    char * c;
+    unsigned hlen, fsize, i;
+    static const struct {
+        int fsize;
+        char make[12], model[15], withjpeg;
+    } table[] = {
+        {    62464, "Kodak",    "DC20"       ,0 },
+        {   124928, "Kodak",    "DC20"       ,0 },
+        {   311696, "ST Micro", "STV680 VGA" ,0 },  /* SPYz */
+        {   787456, "Creative", "PC-CAM 600" ,0 },
+        {  2465792, "NIKON",    "E950"       ,1 },  /* or E800,E700 */
+        {  2940928, "NIKON",    "E2100"      ,1 },  /* or E2500 */
+        {  4771840, "NIKON",    "E990"       ,1 },  /* or E995 */
+        {  4775936, "NIKON",    "E3700"      ,1 },  /* or Optio 33WR */
+        {  5869568, "NIKON",    "E4300"      ,1 },  /* or DiMAGE Z2 */
+        {  5865472, "NIKON",    "E4500"      ,0 },
+        {  1976352, "CASIO",    "QV-2000UX"  ,0 },
+        {  3217760, "CASIO",    "QV-3*00EX"  ,0 },
+        {  6218368, "CASIO",    "QV-5700"    ,0 },
+        {  7530816, "CASIO",    "QV-R51"     ,1 },
+        {  7684000, "CASIO",    "QV-4000"    ,0 },
+        {  7753344, "CASIO",    "EX-Z55"     ,1 },
+        {  9313536, "CASIO",    "EX-P600"    ,1 },
+        { 10979200, "CASIO",    "EX-P700"    ,1 },
+        {  3178560, "PENTAX",   "Optio S"    ,1 },  /*  8-bit */
+        {  4841984, "PENTAX",   "Optio S"    ,1 },  /* 12-bit */
+        {  6114240, "PENTAX",   "Optio S4"   ,1 },  /* or S4i */
+        { 12582980, "Sinar",    ""           ,0 } };
+    static const char *corp[] =
+        { "Canon", "NIKON", "EPSON", "Kodak", "OLYMPUS", "PENTAX",
+          "MINOLTA", "Minolta", "Konica", "CASIO" };
+    float tmp;
+    LoadRawFn * load_raw;
 
-  raw_height = raw_width = fuji_width = flip = 0;
-  make[0] = model[0] = model2[0] = 0;
-  memset (white, 0, sizeof white);
-  timestamp = tiff_samples = 0;
-  data_offset = meta_length = tiff_data_compression = 0;
-  zero_after_ff = is_dng = fuji_secondary = filters = 0;
-  black = is_foveon = use_coeff = 0;
-  use_gamma = xmag = ymag = 1;
-  for (i=0; i < 4; i++) {
-    cam_mul[i] = 1 & i;
-    pre_mul[i] = 1;
-  }
-  colors = 3;
-  for (i=0; i < 0x1000; i++) curve[i] = i;
-  maximum = 0xfff;
-#ifdef USE_LCMS
-  profile_length = 0;
-#endif
+    /*  What format is this file?  Set make[] if we recognize it. */
 
-  order = get2(ifp);
-  hlen = get4(ifp);
-  fseek (ifp, 0, SEEK_SET);
-  fread (head, 1, 32, ifp);
-  fseek (ifp, 0, SEEK_END);
-  fsize = ftell(ifp);
-  if ((c = (char*)memmem_internal(head, 32, "MMMMRawT", 8))) {
-    strcpy (make, "Phase One");
-    data_offset = c - head;
-    fseek (ifp, data_offset + 8, SEEK_SET);
-    fseek (ifp, get4(ifp) + 136, SEEK_CUR);
-    raw_width = get4(ifp);
-    fseek (ifp, 12, SEEK_CUR);
-    raw_height = get4(ifp);
-  } else if (order == 0x4949 || order == 0x4d4d) {
-    if (!memcmp (head+6, "HEAPCCDR", 8)) {
-      data_offset = hlen;
-      parse_ciff(ifp, hlen, fsize - hlen);
-    } else {
-      parse_tiff(ifp, 0);
-      if (!strncmp(make,"NIKON",5) && filters == 0)
-    make[0] = 0;
+    raw_height = raw_width = fuji_width = flip = 0;
+    make[0] = model[0] = model2[0] = 0;
+    memset (white, 0, sizeof white);
+    timestamp = tiff_samples = 0;
+    data_offset = meta_length = tiff_data_compression = 0;
+    zero_after_ff = is_dng = fuji_secondary = filters = 0;
+    black = is_foveon = use_coeff = 0;
+    use_gamma = xmag = ymag = 1;
+    for (i=0; i < 4; i++) {
+        cam_mul[i] = 1 & i;
+        pre_mul[i] = 1;
     }
-  } else if (!memcmp (head, "\0MRM", 4))
-    parse_minolta(ifp);
+    colors = 3;
+    for (i=0; i < 0x1000; i++) curve[i] = i;
+    maximum = 0xfff;
+
+    order = get2(ifp);
+    hlen = get4(ifp);
+    fseek (ifp, 0, SEEK_SET);
+    fread (head, 1, 32, ifp);
+    fseek (ifp, 0, SEEK_END);
+    fsize = ftell(ifp);
+    if ((c = (char*)memmem_internal(head, 32, "MMMMRawT", 8))) {
+        strcpy (make, "Phase One");
+        data_offset = c - head;
+        fseek (ifp, data_offset + 8, SEEK_SET);
+        fseek (ifp, get4(ifp) + 136, SEEK_CUR);
+        raw_width = get4(ifp);
+        fseek (ifp, 12, SEEK_CUR);
+        raw_height = get4(ifp);
+    } else if (order == 0x4949 || order == 0x4d4d) {
+        if (!memcmp (head+6, "HEAPCCDR", 8)) {
+            data_offset = hlen;
+            parse_ciff(ifp, hlen, fsize - hlen);
+        } else {
+            parse_tiff(ifp, 0);
+            if (!strncmp(make,"NIKON",5) && filters == 0)
+                make[0] = 0;
+        }
+    } else if (!memcmp (head, "\0MRM", 4))
+        parse_minolta(ifp);
     else if (!memcmp (head, "\xff\xd8\xff\xe1", 4) &&
-         !memcmp (head+6, "Exif", 4)) {
-    fseek (ifp, 4, SEEK_SET);
-    fseek (ifp, 4 + get2(ifp), SEEK_SET);
-    if (fgetc(ifp) != 0xff)
-      parse_tiff(ifp, 12);
-  } else if (!memcmp (head, "BM", 2)) {
-    data_offset = 0x1000;
-    order = 0x4949;
-    fseek (ifp, 38, SEEK_SET);
-    if (get4(ifp) == 2834 && get4(ifp) == 2834) {
-      strcpy (model, "BMQ");
-      flip = 3;
-      goto nucore;
-    }
-  } else if (!memcmp (head, "BR", 2)) {
-    strcpy (model, "RAW");
-nucore:
-    strcpy (make, "Nucore");
-    order = 0x4949;
-    fseek (ifp, 10, SEEK_SET);
-    data_offset += get4(ifp);
-    get4(ifp);
-    raw_width  = get4(ifp);
-    raw_height = get4(ifp);
-    if (model[0] == 'B' && raw_width == 2597) {
-      raw_width++;
-      data_offset -= 0x1000;
-    }
-  } else if (!memcmp (head+25, "ARECOYK", 7)) {
-    strcpy (make, "Contax");
-    strcpy (model,"N Digital");
-    fseek (ifp, 60, SEEK_SET);
-    camera_red  = get4(ifp);
-    camera_red /= get4(ifp);
-    camera_blue = get4(ifp);
-    camera_blue = get4(ifp) / camera_blue;
-  } else if (!memcmp (head, "FUJIFILM", 8)) {
-    long data_offset_long;
-    fseek (ifp, 84, SEEK_SET);
-    parse_tiff(ifp, get4(ifp)+12);
-    fseek (ifp, 100, SEEK_SET);
-    pm_readbiglong(ifp, &data_offset_long);
-    data_offset = data_offset_long;
-  } else if (!memcmp (head, "DSC-Image", 9))
-    parse_rollei(ifp);
-  else if (!memcmp (head, "FOVb", 4))
-    parse_foveon(ifp);
-  else
-      for (i=0; i < sizeof table / sizeof *table; i++)
-          if (fsize == table[i].fsize) {
-              strcpy (make,  table[i].make );
-              strcpy (model, table[i].model);
-              if (table[i].withjpeg)
-                  parse_external_jpeg(inputFileName);
-          }
-  parse_mos(ifp, 8);
-  parse_mos(ifp, 3472);
+             !memcmp (head+6, "Exif", 4)) {
+        fseek (ifp, 4, SEEK_SET);
+        fseek (ifp, 4 + get2(ifp), SEEK_SET);
+        if (fgetc(ifp) != 0xff)
+            parse_tiff(ifp, 12);
+    } else if (!memcmp (head, "BM", 2)) {
+        data_offset = 0x1000;
+        order = 0x4949;
+        fseek (ifp, 38, SEEK_SET);
+        if (get4(ifp) == 2834 && get4(ifp) == 2834) {
+            strcpy (model, "BMQ");
+            flip = 3;
+            goto nucore;
+        }
+    } else if (!memcmp (head, "BR", 2)) {
+        strcpy (model, "RAW");
+    nucore:
+        strcpy (make, "Nucore");
+        order = 0x4949;
+        fseek (ifp, 10, SEEK_SET);
+        data_offset += get4(ifp);
+        get4(ifp);
+        raw_width  = get4(ifp);
+        raw_height = get4(ifp);
+        if (model[0] == 'B' && raw_width == 2597) {
+            raw_width++;
+            data_offset -= 0x1000;
+        }
+    } else if (!memcmp (head+25, "ARECOYK", 7)) {
+        strcpy (make, "Contax");
+        strcpy (model,"N Digital");
+        fseek (ifp, 60, SEEK_SET);
+        camera_red  = get4(ifp);
+        camera_red /= get4(ifp);
+        camera_blue = get4(ifp);
+        camera_blue = get4(ifp) / camera_blue;
+    } else if (!memcmp (head, "FUJIFILM", 8)) {
+        long data_offset_long;
+        fseek (ifp, 84, SEEK_SET);
+        parse_tiff(ifp, get4(ifp)+12);
+        fseek (ifp, 100, SEEK_SET);
+        pm_readbiglong(ifp, &data_offset_long);
+        data_offset = data_offset_long;
+    } else if (!memcmp (head, "DSC-Image", 9))
+        parse_rollei(ifp);
+    else if (!memcmp (head, "FOVb", 4))
+        parse_foveon(ifp);
+    else
+        for (i=0; i < sizeof table / sizeof *table; i++)
+            if (fsize == table[i].fsize) {
+                strcpy (make,  table[i].make );
+                strcpy (model, table[i].model);
+                if (table[i].withjpeg)
+                    parse_external_jpeg(inputFileName);
+            }
+    parse_mos(ifp, 8);
+    parse_mos(ifp, 3472);
+
+    for (i=0; i < sizeof corp / sizeof *corp; i++)
+        if (strstr (make, corp[i]))     /* Simplify company names */
+            strcpy (make, corp[i]);
+    if (!strncmp (make, "KODAK", 5))
+        make[16] = model[16] = 0;
+    c = make + strlen(make);      /* Remove trailing spaces */
+    while (*--c == ' ') *c = 0;
+    c = model + strlen(model);
+    while (*--c == ' ') *c = 0;
+    i = strlen(make);         /* Remove make from model */
+    if (!strncmp (model, make, i++))
+        memmove (model, model+i, 64-i);
+    make[63] = model[63] = model2[63] = 0;
 
-  for (i=0; i < sizeof corp / sizeof *corp; i++)
-    if (strstr (make, corp[i]))     /* Simplify company names */
-    strcpy (make, corp[i]);
-  if (!strncmp (make, "KODAK", 5))
-    make[16] = model[16] = 0;
-  c = make + strlen(make);      /* Remove trailing spaces */
-  while (*--c == ' ') *c = 0;
-  c = model + strlen(model);
-  while (*--c == ' ') *c = 0;
-  i = strlen(make);         /* Remove make from model */
-  if (!strncmp (model, make, i++))
-    memmove (model, model+i, 64-i);
-  make[63] = model[63] = model2[63] = 0;
+    if (verbose)
+        fprintf(stderr, "Make = '%s', Model = '%s'\n", make, model);
 
-  if (make[0] == 0) {
-    pm_message ("unrecognized file format.");
-    return 1;
-  }
+    if (make[0] == 0) {
+        pm_message ("unrecognized file format.");
+        return 1;
+    }
 
 /*  File format is OK.  Do we know this camera? */
 /*  Start with some useful defaults:           */
 
-  top_margin = left_margin = 0;
-  if ((raw_height | raw_width) < 0)
-       raw_height = raw_width  = 0;
-  height = raw_height;
-  width  = raw_width;
-  if (fuji_width) {
-    width = height + fuji_width;
-    height = width - 1;
-    ymag = 1;
-  }
-  load_raw = NULL;
-  if (is_dng) {
-    strcat (model, " DNG");
-    if (!filters)
-      colors = tiff_samples;
-    if (tiff_data_compression == 1)
-      load_raw = adobe_dng_load_raw_nc;
-    if (tiff_data_compression == 7)
-      load_raw = adobe_dng_load_raw_lj;
-    goto dng_skip;
-  }
+    top_margin = left_margin = 0;
+    if ((raw_height | raw_width) < 0)
+        raw_height = raw_width  = 0;
+    height = raw_height;
+    width  = raw_width;
+    if (fuji_width) {
+        width = height + fuji_width;
+        height = width - 1;
+        ymag = 1;
+    }
+    load_raw = NULL;
+    if (is_dng) {
+        strcat (model, " DNG");
+        if (!filters)
+            colors = tiff_samples;
+        if (tiff_data_compression == 1)
+            load_raw = adobe_dng_load_raw_nc;
+        if (tiff_data_compression == 7)
+            load_raw = adobe_dng_load_raw_lj;
+        goto dng_skip;
+    }
 
-/*  We'll try to decode anything from Canon or Nikon. */
+    /*  We'll try to decode anything from Canon or Nikon. */
 
-  if (!filters) filters = 0x94949494;
-  if ((is_canon = !strcmp(make,"Canon")))
-    load_raw = memcmp (head+6,"HEAPCCDR",8) ?
-        lossless_jpeg_load_raw : canon_compressed_load_raw;
-  if (!strcmp(make,"NIKON"))
-    load_raw = nikon_is_compressed() ?
-    nikon_compressed_load_raw : nikon_load_raw;
+    if (!filters) filters = 0x94949494;
+    if ((is_canon = !strcmp(make,"Canon")))
+        load_raw = memcmp (head+6,"HEAPCCDR",8) ?
+            lossless_jpeg_load_raw : canon_compressed_load_raw;
+    if (!strcmp(make,"NIKON"))
+        load_raw = nikon_is_compressed() ?
+            nikon_compressed_load_raw : nikon_load_raw;
 
-/* Set parameters based on camera name (for non-DNG files). */
+    /* Set parameters based on camera name (for non-DNG files). */
 
-  if (is_foveon) {
-    if (!have64BitArithmetic)
-      pm_error("This program was built without 64 bit arithmetic "
-               "capability and the Foveon format requires it.");
-    if (height*2 < width) ymag = 2;
-    if (width < height) xmag = 2;
-    filters = 0;
-    load_raw = foveon_load_raw;
-    foveon_coeff(&use_coeff, coeff);
-  } else if (!strcmp(model,"PowerShot 600")) {
-    height = 613;
-    width  = 854;
-    colors = 4;
-    filters = 0xe1e4e1e4;
-    load_raw = canon_600_load_raw;
-  } else if (!strcmp(model,"PowerShot A5") ||
-         !strcmp(model,"PowerShot A5 Zoom")) {
-    height = 773;
-    width  = 960;
-    raw_width = 992;
-    colors = 4;
-    filters = 0x1e4e1e4e;
-    load_raw = canon_a5_load_raw;
-  } else if (!strcmp(model,"PowerShot A50")) {
-    height =  968;
-    width  = 1290;
-    raw_width = 1320;
-    colors = 4;
-    filters = 0x1b4e4b1e;
-    load_raw = canon_a5_load_raw;
-  } else if (!strcmp(model,"PowerShot Pro70")) {
-    height = 1024;
-    width  = 1552;
-    colors = 4;
-    filters = 0x1e4b4e1b;
-    load_raw = canon_a5_load_raw;
-    black = 34;
-  } else if (!strcmp(model,"PowerShot Pro90 IS")) {
-    width  = 1896;
-    colors = 4;
-    filters = 0xb4b4b4b4;
-  } else if (is_canon && raw_width == 2144) {
-    height = 1550;
-    width  = 2088;
-    top_margin  = 8;
-    left_margin = 4;
-    if (!strcmp(model,"PowerShot G1")) {
-      colors = 4;
-      filters = 0xb4b4b4b4;
-    }
-  } else if (is_canon && raw_width == 2224) {
-    height = 1448;
-    width  = 2176;
-    top_margin  = 6;
-    left_margin = 48;
-  } else if (is_canon && raw_width == 2376) {
-    height = 1720;
-    width  = 2312;
-    top_margin  = 6;
-    left_margin = 12;
-  } else if (is_canon && raw_width == 2672) {
-    height = 1960;
-    width  = 2616;
-    top_margin  = 6;
-    left_margin = 12;
-  } else if (is_canon && raw_width == 3152) {
-    height = 2056;
-    width  = 3088;
-    top_margin  = 12;
-    left_margin = 64;
-    maximum = 0xfa0;
-  } else if (is_canon && raw_width == 3160) {
-    height = 2328;
-    width  = 3112;
-    top_margin  = 12;
-    left_margin = 44;
-  } else if (is_canon && raw_width == 3344) {
-    height = 2472;
-    width  = 3288;
-    top_margin  = 6;
-    left_margin = 4;
-  } else if (!strcmp(model,"EOS D2000C")) {
-    filters = 0x61616161;
-    black = curve[200];
-  } else if (!strcmp(model,"EOS-1D")) {
-    raw_height = height = 1662;
-    raw_width  = width  = 2496;
-    data_offset = 288912;
-    filters = 0x61616161;
-  } else if (!strcmp(model,"EOS-1DS")) {
-    raw_height = height = 2718;
-    raw_width  = width  = 4082;
-    data_offset = 289168;
-    filters = 0x61616161;
-  } else if (is_canon && raw_width == 3516) {
-    top_margin  = 14;
-    left_margin = 42;
-    goto canon_cr2;
-  } else if (is_canon && raw_width == 3596) {
-    top_margin  = 12;
-    left_margin = 74;
-    goto canon_cr2;
-  } else if (is_canon && raw_width == 5108) {
-    top_margin  = 13;
-    left_margin = 98;
-    maximum = 0xe80;
-canon_cr2:
-    height = raw_height - top_margin;
-    width  = raw_width - left_margin;
-  } else if (!strcmp(model,"D1")) {
-    camera_red  *= 256/527.0;
-    camera_blue *= 256/317.0;
-  } else if (!strcmp(model,"D1X")) {
-    width  = 4024;
-    ymag = 2;
-  } else if (!strcmp(model,"D100")) {
-    if (tiff_data_compression == 34713 && load_raw == nikon_load_raw)
-      raw_width = (width += 3) + 3;
-  } else if (!strcmp(model,"D2H")) {
-    width  = 2482;
-    left_margin = 6;
-  } else if (!strcmp(model,"D2X")) {
-    width  = 4312;
-    pre_mul[0] = 1.514;
-    pre_mul[2] = 1.727;
-  } else if (fsize == 2465792) {
-    height = 1203;
-    width  = 1616;
-    filters = 0x4b4b4b4b;
-    colors = 4;
-    load_raw = nikon_e950_load_raw;
-    nikon_e950_coeff();
-    pre_mul[0] = 1.18193;
-    pre_mul[2] = 1.16452;
-    pre_mul[3] = 1.17250;
-  } else if (!strcmp(model,"E990")) {
-    if (!timestamp && !nikon_e990()) goto cp_e995;
-    height = 1540;
-    width  = 2064;
-    colors = 4;
-    filters = 0xb4b4b4b4;
-    nikon_e950_coeff();
-    pre_mul[0] = 1.196;
-    pre_mul[1] = 1.246;
-    pre_mul[2] = 1.018;
-  } else if (!strcmp(model,"E995")) {
-cp_e995:
-    strcpy (model, "E995");
-    height = 1540;
-    width  = 2064;
-    colors = 4;
-    filters = 0xe1e1e1e1;
-  } else if (!strcmp(model,"E2100")) {
-    if (!timestamp && !nikon_e2100()) goto cp_e2500;
-    width = 1616;
-    height = 1206;
-    load_raw = nikon_e2100_load_raw;
-    pre_mul[0] = 1.945;
-    pre_mul[2] = 1.040;
-  } else if (!strcmp(model,"E2500")) {
-cp_e2500:
-    strcpy (model, "E2500");
-    width = 1616;
-    height = 1204;
-    colors = 4;
-    filters = 0x4b4b4b4b;
-  } else if (!strcmp(model,"E3700")) {
-    if (!timestamp && pentax_optio33()) goto optio_33wr;
-    height = 1542;
-    width  = 2064;
-    load_raw = nikon_e2100_load_raw;
-    pre_mul[0] = 1.818;
-    pre_mul[2] = 1.618;
-  } else if (!strcmp(model,"Optio 33WR")) {
-optio_33wr:
-    strcpy (make, "PENTAX");
-    strcpy (model,"Optio 33WR");
-    height = 1542;
-    width  = 2064;
-    load_raw = nikon_e2100_load_raw;
-    flip = 1;
-    filters = 0x16161616;
-    pre_mul[0] = 1.331;
-    pre_mul[2] = 1.820;
-  } else if (!strcmp(model,"E4300")) {
-    if (!timestamp && minolta_z2()) goto dimage_z2;
-    height = 1710;
-    width  = 2288;
-    filters = 0x16161616;
-    pre_mul[0] = 508;
-    pre_mul[1] = 256;
-    pre_mul[2] = 322;
-  } else if (!strcmp(model,"DiMAGE Z2")) {
-dimage_z2:
-    strcpy (make, "MINOLTA");
-    strcpy (model,"DiMAGE Z2");
-    height = 1710;
-    width  = 2288;
-    filters = 0x16161616;
-    load_raw = nikon_e2100_load_raw;
-    pre_mul[0] = 508;
-    pre_mul[1] = 256;
-    pre_mul[2] = 450;
-  } else if (!strcmp(model,"E4500")) {
-    height = 1708;
-    width  = 2288;
-    colors = 4;
-    filters = 0xb4b4b4b4;
-  } else if (!strcmp(model,"R-D1")) {
-    tiff_data_compression = 34713;
-    load_raw = nikon_load_raw;
-  } else if (!strcmp(model,"FinePixS2Pro")) {
-    height = 3584;
-    width  = 3583;
-    fuji_width = 2144;
-    filters = 0x61616161;
-    load_raw = fuji_s2_load_raw;
-    black = 128;
-    strcpy (model+7, " S2Pro");
-  } else if (!strcmp(model,"FinePix S3Pro")) {
-    height = 3583;
-    width  = 3584;
-    fuji_width = 2144;
-    if (fsize > 18000000 && use_secondary)
-      data_offset += 4352*2*1444;
-    filters = 0x49494949;
-    load_raw = fuji_s3_load_raw;
-    maximum = 0xffff;
-  } else if (!strcmp(model,"FinePix S5000")) {
-    height = 2499;
-    width  = 2500;
-    fuji_width = 1423;
-    filters = 0x49494949;
-    load_raw = fuji_s5000_load_raw;
-    maximum = 0x3e00;
-  } else if (!strcmp(model,"FinePix S5100") ||
-         !strcmp(model,"FinePix S5500")) {
-    height = 1735;
-    width  = 2304;
-    data_offset += width*10;
-    filters = 0x49494949;
-    load_raw = unpacked_load_raw;
-    maximum = 0xffff;
-  } else if (!strcmp(model,"FinePix E550") ||
-         !strcmp(model,"FinePix F810") ||
-         !strcmp(model,"FinePix S7000")) {
-    height = 3587;
-    width  = 3588;
-    fuji_width = 2047;
-    filters = 0x49494949;
-    load_raw = fuji_s7000_load_raw;
-    maximum = 0x3e00;
-  } else if (!strcmp(model,"FinePix F700") ||
-         !strcmp(model,"FinePix S20Pro")) {
-    height = 2523;
-    width  = 2524;
-    fuji_width = 1440;
-    filters = 0x49494949;
-    load_raw = fuji_f700_load_raw;
-    maximum = 0x3e00;
-  } else if (!strcmp(model,"Digital Camera KD-400Z")) {
-    height = 1712;
-    width  = 2312;
-    raw_width = 2336;
-    data_offset = 4034;
-    fseek (ifp, 2032, SEEK_SET);
-    goto konica_400z;
-  } else if (!strcmp(model,"Digital Camera KD-510Z")) {
-    data_offset = 4032;
-    pre_mul[0] = 1.297;
-    pre_mul[2] = 1.438;
-    fseek (ifp, 2032, SEEK_SET);
-    goto konica_510z;
-  } else if (!strcasecmp(make,"MINOLTA")) {
-    load_raw = unpacked_load_raw;
-    maximum = 0xf7d;
-    if (!strncmp(model,"DiMAGE A",8)) {
-      if (!strcmp(model,"DiMAGE A200")) {
-    filters = 0x49494949;
-    tmp = camera_red;
-    camera_red  = 1 / camera_blue;
-    camera_blue = 1 / tmp;
-      }
-      load_raw = packed_12_load_raw;
-      maximum = model[8] == '1' ? 0xf8b : 0xfff;
-    } else if (!strncmp(model,"ALPHA",5) ||
-           !strncmp(model,"DYNAX",5) ||
-           !strncmp(model,"MAXXUM",6)) {
-      load_raw = packed_12_load_raw;
-      maximum = 0xffb;
-    } else if (!strncmp(model,"DiMAGE G",8)) {
-      if (model[8] == '4') {
-    data_offset = 5056;
-    pre_mul[0] = 1.602;
-    pre_mul[2] = 1.441;
-    fseek (ifp, 2078, SEEK_SET);
-    height = 1716;
-    width  = 2304;
-      } else if (model[8] == '5') {
-    data_offset = 4016;
-    fseek (ifp, 1936, SEEK_SET);
-konica_510z:
-    height = 1956;
-    width  = 2607;
-    raw_width = 2624;
-      } else if (model[8] == '6') {
-    data_offset = 4032;
-    fseek (ifp, 2030, SEEK_SET);
-    height = 2136;
-    width  = 2848;
-      }
-      filters = 0x61616161;
-konica_400z:
-      load_raw = unpacked_load_raw;
-      maximum = 0x3df;
-      order = 0x4d4d;
-      camera_red   = get2(ifp);
-      camera_blue  = get2(ifp);
-      camera_red  /= get2(ifp);
-      camera_blue /= get2(ifp);
-    }
-    if (pre_mul[0] == 1 && pre_mul[2] == 1) {
-      pre_mul[0] = 1.42;
-      pre_mul[2] = 1.25;
-    }
-  } else if (!strcmp(model,"*ist D")) {
-    load_raw = unpacked_load_raw;
-  } else if (!strcmp(model,"*ist DS")) {
-    height--;
-    load_raw = packed_12_load_raw;
-  } else if (!strcmp(model,"Optio S")) {
-    if (fsize == 3178560) {
-      height = 1540;
-      width  = 2064;
-      load_raw = eight_bit_load_raw;
-      camera_red  *= 4;
-      camera_blue *= 4;
-      pre_mul[0] = 1.391;
-      pre_mul[2] = 1.188;
-    } else {
-      height = 1544;
-      width  = 2068;
-      raw_width = 3136;
-      load_raw = packed_12_load_raw;
-      maximum = 0xf7c;
-      pre_mul[0] = 1.137;
-      pre_mul[2] = 1.453;
-    }
-  } else if (!strncmp(model,"Optio S4",8)) {
-    height = 1737;
-    width  = 2324;
-    raw_width = 3520;
-    load_raw = packed_12_load_raw;
-    maximum = 0xf7a;
-    pre_mul[0] = 1.980;
-    pre_mul[2] = 1.570;
-  } else if (!strcmp(model,"STV680 VGA")) {
-    height = 484;
-    width  = 644;
-    load_raw = eight_bit_load_raw;
-    flip = 2;
-    filters = 0x16161616;
-    black = 16;
-    pre_mul[0] = 1.097;
-    pre_mul[2] = 1.128;
-  } else if (!strcmp(make,"Phase One")) {
-    switch (raw_height) {
-      case 2060:
-    strcpy (model, "LightPhase");
-    height = 2048;
-    width  = 3080;
-    top_margin  = 5;
-    left_margin = 22;
-    pre_mul[0] = 1.331;
-    pre_mul[2] = 1.154;
-    break;
-      case 2682:
-    strcpy (model, "H10");
-    height = 2672;
-    width  = 4012;
-    top_margin  = 5;
-    left_margin = 26;
-    break;
-      case 4128:
-    strcpy (model, "H20");
-    height = 4098;
-    width  = 4098;
-    top_margin  = 20;
-    left_margin = 26;
-    pre_mul[0] = 1.963;
-    pre_mul[2] = 1.430;
-    break;
-      case 5488:
-    strcpy (model, "H25");
-    height = 5458;
-    width  = 4098;
-    top_margin  = 20;
-    left_margin = 26;
-    pre_mul[0] = 2.80;
-    pre_mul[2] = 1.20;
-    }
-    filters = top_margin & 1 ? 0x94949494 : 0x49494949;
-    load_raw = phase_one_load_raw;
-    maximum = 0xffff;
-  } else if (!strcmp(model,"Ixpress")) {
-    height = 4084;
-    width  = 4080;
-    filters = 0x49494949;
-    load_raw = ixpress_load_raw;
-    maximum = 0xffff;
-    pre_mul[0] = 1.963;
-    pre_mul[2] = 1.430;
-  } else if (!strcmp(make,"Sinar") && !memcmp(head,"8BPS",4)) {
-    fseek (ifp, 14, SEEK_SET);
-    height = get4(ifp);
-    width  = get4(ifp);
-    filters = 0x61616161;
-    data_offset = 68;
-    load_raw = unpacked_load_raw;
-    maximum = 0xffff;
-  } else if (!strcmp(make,"Leaf")) {
-    if (height > width)
-      filters = 0x16161616;
-    load_raw = unpacked_load_raw;
-    maximum = 0x3fff;
-    strcpy (model, "Valeo");
-    if (raw_width == 2060) {
-      filters = 0;
-      load_raw = leaf_load_raw;
-      maximum = 0xffff;
-      strcpy (model, "Volare");
-    }
-  } else if (!strcmp(model,"DIGILUX 2") || !strcmp(model,"DMC-LC1")) {
-    height = 1928;
-    width  = 2568;
-    data_offset = 1024;
-    load_raw = unpacked_load_raw;
-    maximum = 0xfff0;
-  } else if (!strcmp(model,"E-1")) {
-    filters = 0x61616161;
-    load_raw = unpacked_load_raw;
-    maximum = 0xfff0;
-    black = 1024;
-  } else if (!strcmp(model,"E-10")) {
-    load_raw = unpacked_load_raw;
-    maximum = 0xfff0;
-    black = 2048;
-  } else if (!strncmp(model,"E-20",4)) {
-    load_raw = unpacked_load_raw;
-    maximum = 0xffc0;
-    black = 2560;
-  } else if (!strcmp(model,"E-300")) {
-    width -= 21;
-    load_raw = olympus_e300_load_raw;
-    if (fsize > 15728640) {
-      load_raw = unpacked_load_raw;
-      maximum = 0xfc30;
-    } else
-      black = 62;
-  } else if (!strcmp(make,"OLYMPUS")) {
-    load_raw = olympus_cseries_load_raw;
-    if (!strcmp(model,"C5050Z") ||
-    !strcmp(model,"C8080WZ"))
-      filters = 0x16161616;
-  } else if (!strcmp(model,"N Digital")) {
-    height = 2047;
-    width  = 3072;
-    filters = 0x61616161;
-    data_offset = 0x1a00;
-    load_raw = packed_12_load_raw;
-    maximum = 0xf1e;
-  } else if (!strcmp(model,"DSC-F828")) {
-    width = 3288;
-    left_margin = 5;
-    load_raw = sony_load_raw;
-    filters = 0x9c9c9c9c;
-    colors = 4;
-    black = 491;
-  } else if (!strcmp(model,"DSC-V3")) {
-    width = 3109;
-    left_margin = 59;
-    load_raw = sony_load_raw;
-  } else if (!strcasecmp(make,"KODAK")) {
-    filters = 0x61616161;
-    if (!strcmp(model,"NC2000F")) {
-      width -= 4;
-      left_margin = 1;
-      for (i=176; i < 0x1000; i++)
-    curve[i] = curve[i-1];
-      pre_mul[0] = 1.509;
-      pre_mul[2] = 2.686;
-    } else if (!strcmp(model,"EOSDCS3B")) {
-      width -= 4;
-      left_margin = 2;
-    } else if (!strcmp(model,"EOSDCS1")) {
-      width -= 4;
-      left_margin = 2;
-    } else if (!strcmp(model,"DCS315C")) {
-      black = 8;
-    } else if (!strcmp(model,"DCS330C")) {
-      black = 8;
-    } else if (!strcmp(model,"DCS420")) {
-      width -= 4;
-      left_margin = 2;
-    } else if (!strcmp(model,"DCS460")) {
-      width -= 4;
-      left_margin = 2;
-    } else if (!strcmp(model,"DCS460A")) {
-      width -= 4;
-      left_margin = 2;
-      colors = 1;
-      filters = 0;
-    } else if (!strcmp(model,"DCS520C")) {
-      black = 180;
-    } else if (!strcmp(model,"DCS560C")) {
-      black = 188;
-    } else if (!strcmp(model,"DCS620C")) {
-      black = 180;
-    } else if (!strcmp(model,"DCS620X")) {
-      black = 185;
-    } else if (!strcmp(model,"DCS660C")) {
-      black = 214;
-    } else if (!strcmp(model,"DCS660M")) {
-      black = 214;
-      colors = 1;
-      filters = 0;
-    } else if (!strcmp(model,"DCS760M")) {
-      colors = 1;
-      filters = 0;
-    }
-    switch (tiff_data_compression) {
-    case 0:               /* No compression */
-    case 1:
-        load_raw = kodak_easy_load_raw;
-        break;
-    case 7:               /* Lossless JPEG */
-        load_raw = lossless_jpeg_load_raw;
-    case 32867:
-        break;
-    case 65000:           /* Kodak DCR compression */
+    if (is_foveon) {
         if (!have64BitArithmetic)
             pm_error("This program was built without 64 bit arithmetic "
-                     "capability, and Kodak DCR compression requires it.");
-        if (kodak_data_compression == 32803)
-            load_raw = kodak_compressed_load_raw;
-        else {
-            load_raw = kodak_yuv_load_raw;
-            height = (height+1) & -2;
-            width  = (width +1) & -2;
+                     "capability and the Foveon format requires it.");
+        if (height*2 < width) ymag = 2;
+        if (width < height) xmag = 2;
+        filters = 0;
+        load_raw = foveon_load_raw;
+        foveon_coeff(&use_coeff, coeff);
+    } else if (!strcmp(model,"PowerShot 600")) {
+        height = 613;
+        width  = 854;
+        colors = 4;
+        filters = 0xe1e4e1e4;
+        load_raw = canon_600_load_raw;
+    } else if (!strcmp(model,"PowerShot A5") ||
+               !strcmp(model,"PowerShot A5 Zoom")) {
+        height = 773;
+        width  = 960;
+        raw_width = 992;
+        colors = 4;
+        filters = 0x1e4e1e4e;
+        load_raw = canon_a5_load_raw;
+    } else if (!strcmp(model,"PowerShot A50")) {
+        height =  968;
+        width  = 1290;
+        raw_width = 1320;
+        colors = 4;
+        filters = 0x1b4e4b1e;
+        load_raw = canon_a5_load_raw;
+    } else if (!strcmp(model,"PowerShot Pro70")) {
+        height = 1024;
+        width  = 1552;
+        colors = 4;
+        filters = 0x1e4b4e1b;
+        load_raw = canon_a5_load_raw;
+        black = 34;
+    } else if (!strcmp(model,"PowerShot Pro90 IS")) {
+        width  = 1896;
+        colors = 4;
+        filters = 0xb4b4b4b4;
+    } else if (is_canon && raw_width == 2144) {
+        height = 1550;
+        width  = 2088;
+        top_margin  = 8;
+        left_margin = 4;
+        if (!strcmp(model,"PowerShot G1")) {
+            colors = 4;
+            filters = 0xb4b4b4b4;
+        }
+    } else if (is_canon && raw_width == 2224) {
+        height = 1448;
+        width  = 2176;
+        top_margin  = 6;
+        left_margin = 48;
+    } else if (is_canon && raw_width == 2376) {
+        height = 1720;
+        width  = 2312;
+        top_margin  = 6;
+        left_margin = 12;
+    } else if (is_canon && raw_width == 2672) {
+        height = 1960;
+        width  = 2616;
+        top_margin  = 6;
+        left_margin = 12;
+    } else if (is_canon && raw_width == 3152) {
+        height = 2056;
+        width  = 3088;
+        top_margin  = 12;
+        left_margin = 64;
+        maximum = 0xfa0;
+    } else if (is_canon && raw_width == 3160) {
+        height = 2328;
+        width  = 3112;
+        top_margin  = 12;
+        left_margin = 44;
+    } else if (is_canon && raw_width == 3344) {
+        height = 2472;
+        width  = 3288;
+        top_margin  = 6;
+        left_margin = 4;
+    } else if (!strcmp(model,"EOS D2000C")) {
+        filters = 0x61616161;
+        black = curve[200];
+    } else if (!strcmp(model,"EOS-1D")) {
+        raw_height = height = 1662;
+        raw_width  = width  = 2496;
+        data_offset = 288912;
+        filters = 0x61616161;
+    } else if (!strcmp(model,"EOS-1DS")) {
+        raw_height = height = 2718;
+        raw_width  = width  = 4082;
+        data_offset = 289168;
+        filters = 0x61616161;
+    } else if (is_canon && raw_width == 3516) {
+        top_margin  = 14;
+        left_margin = 42;
+        goto canon_cr2;
+    } else if (is_canon && raw_width == 3596) {
+        top_margin  = 12;
+        left_margin = 74;
+        goto canon_cr2;
+    } else if (is_canon && raw_width == 5108) {
+        top_margin  = 13;
+        left_margin = 98;
+        maximum = 0xe80;
+    canon_cr2:
+        height = raw_height - top_margin;
+        width  = raw_width - left_margin;
+    } else if (!strcmp(model,"D1")) {
+        camera_red  *= 256/527.0;
+        camera_blue *= 256/317.0;
+    } else if (!strcmp(model,"D1X")) {
+        width  = 4024;
+        ymag = 2;
+    } else if (!strcmp(model,"D100")) {
+        if (tiff_data_compression == 34713 && load_raw == nikon_load_raw)
+            raw_width = (width += 3) + 3;
+    } else if (!strcmp(model,"D2H")) {
+        width  = 2482;
+        left_margin = 6;
+    } else if (!strcmp(model,"D2X")) {
+        width  = 4312;
+        pre_mul[0] = 1.514;
+        pre_mul[2] = 1.727;
+    } else if (fsize == 2465792) {
+        height = 1203;
+        width  = 1616;
+        filters = 0x4b4b4b4b;
+        colors = 4;
+        load_raw = nikon_e950_load_raw;
+        nikon_e950_coeff();
+        pre_mul[0] = 1.18193;
+        pre_mul[2] = 1.16452;
+        pre_mul[3] = 1.17250;
+    } else if (!strcmp(model,"E990")) {
+        if (!timestamp && !nikon_e990()) goto cp_e995;
+        height = 1540;
+        width  = 2064;
+        colors = 4;
+        filters = 0xb4b4b4b4;
+        nikon_e950_coeff();
+        pre_mul[0] = 1.196;
+        pre_mul[1] = 1.246;
+        pre_mul[2] = 1.018;
+    } else if (!strcmp(model,"E995")) {
+    cp_e995:
+        strcpy (model, "E995");
+        height = 1540;
+        width  = 2064;
+        colors = 4;
+        filters = 0xe1e1e1e1;
+    } else if (!strcmp(model,"E2100")) {
+        if (!timestamp && !nikon_e2100()) goto cp_e2500;
+        width = 1616;
+        height = 1206;
+        load_raw = nikon_e2100_load_raw;
+        pre_mul[0] = 1.945;
+        pre_mul[2] = 1.040;
+    } else if (!strcmp(model,"E2500")) {
+    cp_e2500:
+        strcpy (model, "E2500");
+        width = 1616;
+        height = 1204;
+        colors = 4;
+        filters = 0x4b4b4b4b;
+    } else if (!strcmp(model,"E3700")) {
+        if (!timestamp && pentax_optio33()) goto optio_33wr;
+        height = 1542;
+        width  = 2064;
+        load_raw = nikon_e2100_load_raw;
+        pre_mul[0] = 1.818;
+        pre_mul[2] = 1.618;
+    } else if (!strcmp(model,"Optio 33WR")) {
+    optio_33wr:
+        strcpy (make, "PENTAX");
+        strcpy (model,"Optio 33WR");
+        height = 1542;
+        width  = 2064;
+        load_raw = nikon_e2100_load_raw;
+        flip = 1;
+        filters = 0x16161616;
+        pre_mul[0] = 1.331;
+        pre_mul[2] = 1.820;
+    } else if (!strcmp(model,"E4300")) {
+        if (!timestamp && minolta_z2()) goto dimage_z2;
+        height = 1710;
+        width  = 2288;
+        filters = 0x16161616;
+        pre_mul[0] = 508;
+        pre_mul[1] = 256;
+        pre_mul[2] = 322;
+    } else if (!strcmp(model,"DiMAGE Z2")) {
+    dimage_z2:
+        strcpy (make, "MINOLTA");
+        strcpy (model,"DiMAGE Z2");
+        height = 1710;
+        width  = 2288;
+        filters = 0x16161616;
+        load_raw = nikon_e2100_load_raw;
+        pre_mul[0] = 508;
+        pre_mul[1] = 256;
+        pre_mul[2] = 450;
+    } else if (!strcmp(model,"E4500")) {
+        height = 1708;
+        width  = 2288;
+        colors = 4;
+        filters = 0xb4b4b4b4;
+    } else if (!strcmp(model,"R-D1")) {
+        tiff_data_compression = 34713;
+        load_raw = nikon_load_raw;
+    } else if (!strcmp(model,"FinePixS2Pro")) {
+        height = 3584;
+        width  = 3583;
+        fuji_width = 2144;
+        filters = 0x61616161;
+        load_raw = fuji_s2_load_raw;
+        black = 128;
+        strcpy (model+7, " S2Pro");
+    } else if (!strcmp(model,"FinePix S3Pro")) {
+        height = 3583;
+        width  = 3584;
+        fuji_width = 2144;
+        if (fsize > 18000000 && use_secondary)
+            data_offset += 4352*2*1444;
+        filters = 0x49494949;
+        load_raw = fuji_s3_load_raw;
+        maximum = 0xffff;
+    } else if (!strcmp(model,"FinePix S5000")) {
+        height = 2499;
+        width  = 2500;
+        fuji_width = 1423;
+        filters = 0x49494949;
+        load_raw = fuji_s5000_load_raw;
+        maximum = 0x3e00;
+    } else if (!strcmp(model,"FinePix S5100") ||
+               !strcmp(model,"FinePix S5500")) {
+        height = 1735;
+        width  = 2304;
+        data_offset += width*10;
+        filters = 0x49494949;
+        load_raw = unpacked_load_raw;
+        maximum = 0xffff;
+    } else if (!strcmp(model,"FinePix E550") ||
+               !strcmp(model,"FinePix F810") ||
+               !strcmp(model,"FinePix S7000")) {
+        height = 3587;
+        width  = 3588;
+        fuji_width = 2047;
+        filters = 0x49494949;
+        load_raw = fuji_s7000_load_raw;
+        maximum = 0x3e00;
+    } else if (!strcmp(model,"FinePix F700") ||
+               !strcmp(model,"FinePix S20Pro")) {
+        height = 2523;
+        width  = 2524;
+        fuji_width = 1440;
+        filters = 0x49494949;
+        load_raw = fuji_f700_load_raw;
+        maximum = 0x3e00;
+    } else if (!strcmp(model,"Digital Camera KD-400Z")) {
+        height = 1712;
+        width  = 2312;
+        raw_width = 2336;
+        data_offset = 4034;
+        fseek (ifp, 2032, SEEK_SET);
+        goto konica_400z;
+    } else if (!strcmp(model,"Digital Camera KD-510Z")) {
+        data_offset = 4032;
+        pre_mul[0] = 1.297;
+        pre_mul[2] = 1.438;
+        fseek (ifp, 2032, SEEK_SET);
+        goto konica_510z;
+    } else if (!strcasecmp(make,"MINOLTA")) {
+        load_raw = unpacked_load_raw;
+        maximum = 0xf7d;
+        if (!strncmp(model,"DiMAGE A",8)) {
+            if (!strcmp(model,"DiMAGE A200")) {
+                filters = 0x49494949;
+                tmp = camera_red;
+                camera_red  = 1 / camera_blue;
+                camera_blue = 1 / tmp;
+            }
+            load_raw = packed_12_load_raw;
+            maximum = model[8] == '1' ? 0xf8b : 0xfff;
+        } else if (!strncmp(model,"ALPHA",5) ||
+                   !strncmp(model,"DYNAX",5) ||
+                   !strncmp(model,"MAXXUM",6)) {
+            load_raw = packed_12_load_raw;
+            maximum = 0xffb;
+        } else if (!strncmp(model,"DiMAGE G",8)) {
+            if (model[8] == '4') {
+                data_offset = 5056;
+                pre_mul[0] = 1.602;
+                pre_mul[2] = 1.441;
+                fseek (ifp, 2078, SEEK_SET);
+                height = 1716;
+                width  = 2304;
+            } else if (model[8] == '5') {
+                data_offset = 4016;
+                fseek (ifp, 1936, SEEK_SET);
+            konica_510z:
+                height = 1956;
+                width  = 2607;
+                raw_width = 2624;
+            } else if (model[8] == '6') {
+                data_offset = 4032;
+                fseek (ifp, 2030, SEEK_SET);
+                height = 2136;
+                width  = 2848;
+            }
+            filters = 0x61616161;
+        konica_400z:
+            load_raw = unpacked_load_raw;
+            maximum = 0x3df;
+            order = 0x4d4d;
+            camera_red   = get2(ifp);
+            camera_blue  = get2(ifp);
+            camera_red  /= get2(ifp);
+            camera_blue /= get2(ifp);
+        }
+        if (pre_mul[0] == 1 && pre_mul[2] == 1) {
+            pre_mul[0] = 1.42;
+            pre_mul[2] = 1.25;
+        }
+    } else if (!strcmp(model,"*ist D")) {
+        load_raw = unpacked_load_raw;
+    } else if (!strcmp(model,"*ist DS")) {
+        height--;
+        load_raw = packed_12_load_raw;
+    } else if (!strcmp(model,"Optio S")) {
+        if (fsize == 3178560) {
+            height = 1540;
+            width  = 2064;
+            load_raw = eight_bit_load_raw;
+            camera_red  *= 4;
+            camera_blue *= 4;
+            pre_mul[0] = 1.391;
+            pre_mul[2] = 1.188;
+        } else {
+            height = 1544;
+            width  = 2068;
+            raw_width = 3136;
+            load_raw = packed_12_load_raw;
+            maximum = 0xf7c;
+            pre_mul[0] = 1.137;
+            pre_mul[2] = 1.453;
+        }
+    } else if (!strncmp(model,"Optio S4",8)) {
+        height = 1737;
+        width  = 2324;
+        raw_width = 3520;
+        load_raw = packed_12_load_raw;
+        maximum = 0xf7a;
+        pre_mul[0] = 1.980;
+        pre_mul[2] = 1.570;
+    } else if (!strcmp(model,"STV680 VGA")) {
+        height = 484;
+        width  = 644;
+        load_raw = eight_bit_load_raw;
+        flip = 2;
+        filters = 0x16161616;
+        black = 16;
+        pre_mul[0] = 1.097;
+        pre_mul[2] = 1.128;
+    } else if (!strcmp(make,"Phase One")) {
+        switch (raw_height) {
+        case 2060:
+            strcpy (model, "LightPhase");
+            height = 2048;
+            width  = 3080;
+            top_margin  = 5;
+            left_margin = 22;
+            pre_mul[0] = 1.331;
+            pre_mul[2] = 1.154;
+            break;
+        case 2682:
+            strcpy (model, "H10");
+            height = 2672;
+            width  = 4012;
+            top_margin  = 5;
+            left_margin = 26;
+            break;
+        case 4128:
+            strcpy (model, "H20");
+            height = 4098;
+            width  = 4098;
+            top_margin  = 20;
+            left_margin = 26;
+            pre_mul[0] = 1.963;
+            pre_mul[2] = 1.430;
+            break;
+        case 5488:
+            strcpy (model, "H25");
+            height = 5458;
+            width  = 4098;
+            top_margin  = 20;
+            left_margin = 26;
+            pre_mul[0] = 2.80;
+            pre_mul[2] = 1.20;
+        }
+        filters = top_margin & 1 ? 0x94949494 : 0x49494949;
+        load_raw = phase_one_load_raw;
+        maximum = 0xffff;
+    } else if (!strcmp(model,"Ixpress")) {
+        height = 4084;
+        width  = 4080;
+        filters = 0x49494949;
+        load_raw = ixpress_load_raw;
+        maximum = 0xffff;
+        pre_mul[0] = 1.963;
+        pre_mul[2] = 1.430;
+    } else if (!strcmp(make,"Sinar") && !memcmp(head,"8BPS",4)) {
+        fseek (ifp, 14, SEEK_SET);
+        height = get4(ifp);
+        width  = get4(ifp);
+        filters = 0x61616161;
+        data_offset = 68;
+        load_raw = unpacked_load_raw;
+        maximum = 0xffff;
+    } else if (!strcmp(make,"Leaf")) {
+        if (height > width)
+            filters = 0x16161616;
+        load_raw = unpacked_load_raw;
+        maximum = 0x3fff;
+        strcpy (model, "Valeo");
+        if (raw_width == 2060) {
             filters = 0;
+            load_raw = leaf_load_raw;
+            maximum = 0xffff;
+            strcpy (model, "Volare");
+        }
+    } else if (!strcmp(model,"DIGILUX 2") || !strcmp(model,"DMC-LC1")) {
+        height = 1928;
+        width  = 2568;
+        data_offset = 1024;
+        load_raw = unpacked_load_raw;
+        maximum = 0xfff0;
+    } else if (!strcmp(model,"E-1")) {
+        filters = 0x61616161;
+        load_raw = unpacked_load_raw;
+        maximum = 0xfff0;
+        black = 1024;
+    } else if (!strcmp(model,"E-10")) {
+        load_raw = unpacked_load_raw;
+        maximum = 0xfff0;
+        black = 2048;
+    } else if (!strncmp(model,"E-20",4)) {
+        load_raw = unpacked_load_raw;
+        maximum = 0xffc0;
+        black = 2560;
+    } else if (!strcmp(model,"E-300")) {
+        width -= 21;
+        load_raw = olympus_e300_load_raw;
+        if (fsize > 15728640) {
+            load_raw = unpacked_load_raw;
+            maximum = 0xfc30;
+        } else
+            black = 62;
+    } else if (!strcmp(make,"OLYMPUS")) {
+        load_raw = olympus_cseries_load_raw;
+        if (!strcmp(model,"C5050Z") ||
+            !strcmp(model,"C8080WZ"))
+            filters = 0x16161616;
+    } else if (!strcmp(model,"N Digital")) {
+        height = 2047;
+        width  = 3072;
+        filters = 0x61616161;
+        data_offset = 0x1a00;
+        load_raw = packed_12_load_raw;
+        maximum = 0xf1e;
+    } else if (!strcmp(model,"DSC-F828")) {
+        width = 3288;
+        left_margin = 5;
+        load_raw = sony_load_raw;
+        filters = 0x9c9c9c9c;
+        colors = 4;
+        black = 491;
+    } else if (!strcmp(model,"DSC-V3")) {
+        width = 3109;
+        left_margin = 59;
+        load_raw = sony_load_raw;
+    } else if (!strcasecmp(make,"KODAK")) {
+        filters = 0x61616161;
+        if (!strcmp(model,"NC2000F")) {
+            width -= 4;
+            left_margin = 1;
+            for (i=176; i < 0x1000; i++)
+                curve[i] = curve[i-1];
+            pre_mul[0] = 1.509;
+            pre_mul[2] = 2.686;
+        } else if (!strcmp(model,"EOSDCS3B")) {
+            width -= 4;
+            left_margin = 2;
+        } else if (!strcmp(model,"EOSDCS1")) {
+            width -= 4;
+            left_margin = 2;
+        } else if (!strcmp(model,"DCS315C")) {
+            black = 8;
+        } else if (!strcmp(model,"DCS330C")) {
+            black = 8;
+        } else if (!strcmp(model,"DCS420")) {
+            width -= 4;
+            left_margin = 2;
+        } else if (!strcmp(model,"DCS460")) {
+            width -= 4;
+            left_margin = 2;
+        } else if (!strcmp(model,"DCS460A")) {
+            width -= 4;
+            left_margin = 2;
+            colors = 1;
+            filters = 0;
+        } else if (!strcmp(model,"DCS520C")) {
+            black = 180;
+        } else if (!strcmp(model,"DCS560C")) {
+            black = 188;
+        } else if (!strcmp(model,"DCS620C")) {
+            black = 180;
+        } else if (!strcmp(model,"DCS620X")) {
+            black = 185;
+        } else if (!strcmp(model,"DCS660C")) {
+            black = 214;
+        } else if (!strcmp(model,"DCS660M")) {
+            black = 214;
+            colors = 1;
+            filters = 0;
+        } else if (!strcmp(model,"DCS760M")) {
+            colors = 1;
+            filters = 0;
+        }
+        switch (tiff_data_compression) {
+        case 0:               /* No compression */
+        case 1:
+            load_raw = kodak_easy_load_raw;
+            break;
+        case 7:               /* Lossless JPEG */
+            load_raw = lossless_jpeg_load_raw;
+        case 32867:
+            break;
+        case 65000:           /* Kodak DCR compression */
+            if (!have64BitArithmetic)
+                pm_error("This program was built without 64 bit arithmetic "
+                         "capability, and Kodak DCR compression requires it.");
+            if (kodak_data_compression == 32803)
+                load_raw = kodak_compressed_load_raw;
+            else {
+                load_raw = kodak_yuv_load_raw;
+                height = (height+1) & -2;
+                width  = (width +1) & -2;
+                filters = 0;
+            }
+            break;
+        default:
+            pm_message ("%s %s uses unrecognized compression method %d.",
+                        make, model, tiff_data_compression);
+            return 1;
+        }
+        if (!strcmp(model,"DC20")) {
+            height = 242;
+            if (fsize < 100000) {
+                width = 249;
+                raw_width = 256;
+            } else {
+                width = 501;
+                raw_width = 512;
+            }
+            data_offset = raw_width + 1;
+            colors = 4;
+            filters = 0x8d8d8d8d;
+            kodak_dc20_coeff (1.0);
+            pre_mul[1] = 1.179;
+            pre_mul[2] = 1.209;
+            pre_mul[3] = 1.036;
+            load_raw = kodak_easy_load_raw;
+        } else if (strstr(model,"DC25")) {
+            strcpy (model, "DC25");
+            height = 242;
+            if (fsize < 100000) {
+                width = 249;
+                raw_width = 256;
+                data_offset = 15681;
+            } else {
+                width = 501;
+                raw_width = 512;
+                data_offset = 15937;
+            }
+            colors = 4;
+            filters = 0xb4b4b4b4;
+            load_raw = kodak_easy_load_raw;
+        } else if (!strcmp(model,"Digital Camera 40")) {
+            strcpy (model, "DC40");
+            height = 512;
+            width = 768;
+            data_offset = 1152;
+            load_raw = kodak_radc_load_raw;
+        } else if (strstr(model,"DC50")) {
+            strcpy (model, "DC50");
+            height = 512;
+            width = 768;
+            data_offset = 19712;
+            load_raw = kodak_radc_load_raw;
+        } else if (strstr(model,"DC120")) {
+            strcpy (model, "DC120");
+            height = 976;
+            width = 848;
+            if (tiff_data_compression == 7)
+                load_raw = kodak_jpeg_load_raw;
+            else
+                load_raw = kodak_dc120_load_raw;
+        }
+    } else if (!strcmp(make,"Rollei")) {
+        switch (raw_width) {
+        case 1316:
+            height = 1030;
+            width  = 1300;
+            top_margin  = 1;
+            left_margin = 6;
+            break;
+        case 2568:
+            height = 1960;
+            width  = 2560;
+            top_margin  = 2;
+            left_margin = 8;
+        }
+        filters = 0x16161616;
+        load_raw = rollei_load_raw;
+        pre_mul[0] = 1.8;
+        pre_mul[2] = 1.3;
+    } else if (!strcmp(model,"PC-CAM 600")) {
+        height = 768;
+        data_offset = width = 1024;
+        filters = 0x49494949;
+        load_raw = eight_bit_load_raw;
+        pre_mul[0] = 1.14;
+        pre_mul[2] = 2.73;
+    } else if (!strcmp(model,"QV-2000UX")) {
+        height = 1208;
+        width  = 1632;
+        data_offset = width * 2;
+        load_raw = eight_bit_load_raw;
+    } else if (!strcmp(model,"QV-3*00EX")) {
+        height = 1546;
+        width  = 2070;
+        raw_width = 2080;
+        load_raw = eight_bit_load_raw;
+    } else if (!strcmp(model,"QV-4000")) {
+        height = 1700;
+        width  = 2260;
+        load_raw = unpacked_load_raw;
+        maximum = 0xffff;
+    } else if (!strcmp(model,"QV-5700")) {
+        height = 1924;
+        width  = 2576;
+        load_raw = casio_qv5700_load_raw;
+    } else if (!strcmp(model,"QV-R51")) {
+        height = 1926;
+        width  = 2576;
+        raw_width = 3904;
+        load_raw = packed_12_load_raw;
+        pre_mul[0] = 1.340;
+        pre_mul[2] = 1.672;
+    } else if (!strcmp(model,"EX-Z55")) {
+        height = 1960;
+        width  = 2570;
+        raw_width = 3904;
+        load_raw = packed_12_load_raw;
+        pre_mul[0] = 1.520;
+        pre_mul[2] = 1.316;
+    } else if (!strcmp(model,"EX-P600")) {
+        height = 2142;
+        width  = 2844;
+        raw_width = 4288;
+        load_raw = packed_12_load_raw;
+        pre_mul[0] = 1.797;
+        pre_mul[2] = 1.219;
+    } else if (!strcmp(model,"EX-P700")) {
+        height = 2318;
+        width  = 3082;
+        raw_width = 4672;
+        load_raw = packed_12_load_raw;
+        pre_mul[0] = 1.758;
+        pre_mul[2] = 1.504;
+    } else if (!strcmp(make,"Nucore")) {
+        filters = 0x61616161;
+        load_raw = unpacked_load_raw;
+        if (width == 2598) {
+            filters = 0x16161616;
+            load_raw = nucore_load_raw;
+            flip = 2;
         }
-        break;
-    default:
-        pm_message ("%s %s uses unrecognized compression method %d.",
-                    make, model, tiff_data_compression);
-        return 1;
-    }
-    if (!strcmp(model,"DC20")) {
-      height = 242;
-      if (fsize < 100000) {
-    width = 249;
-    raw_width = 256;
-      } else {
-    width = 501;
-    raw_width = 512;
-      }
-      data_offset = raw_width + 1;
-      colors = 4;
-      filters = 0x8d8d8d8d;
-      kodak_dc20_coeff (1.0);
-      pre_mul[1] = 1.179;
-      pre_mul[2] = 1.209;
-      pre_mul[3] = 1.036;
-      load_raw = kodak_easy_load_raw;
-    } else if (strstr(model,"DC25")) {
-      strcpy (model, "DC25");
-      height = 242;
-      if (fsize < 100000) {
-    width = 249;
-    raw_width = 256;
-    data_offset = 15681;
-      } else {
-    width = 501;
-    raw_width = 512;
-    data_offset = 15937;
-      }
-      colors = 4;
-      filters = 0xb4b4b4b4;
-      load_raw = kodak_easy_load_raw;
-    } else if (!strcmp(model,"Digital Camera 40")) {
-      strcpy (model, "DC40");
-      height = 512;
-      width = 768;
-      data_offset = 1152;
-      load_raw = kodak_radc_load_raw;
-    } else if (strstr(model,"DC50")) {
-      strcpy (model, "DC50");
-      height = 512;
-      width = 768;
-      data_offset = 19712;
-      load_raw = kodak_radc_load_raw;
-    } else if (strstr(model,"DC120")) {
-      strcpy (model, "DC120");
-      height = 976;
-      width = 848;
-      if (tiff_data_compression == 7)
-    load_raw = kodak_jpeg_load_raw;
-      else
-    load_raw = kodak_dc120_load_raw;
-    }
-  } else if (!strcmp(make,"Rollei")) {
-    switch (raw_width) {
-      case 1316:
-    height = 1030;
-    width  = 1300;
-    top_margin  = 1;
-    left_margin = 6;
-    break;
-      case 2568:
-    height = 1960;
-    width  = 2560;
-    top_margin  = 2;
-    left_margin = 8;
-    }
-    filters = 0x16161616;
-    load_raw = rollei_load_raw;
-    pre_mul[0] = 1.8;
-    pre_mul[2] = 1.3;
-  } else if (!strcmp(model,"PC-CAM 600")) {
-    height = 768;
-    data_offset = width = 1024;
-    filters = 0x49494949;
-    load_raw = eight_bit_load_raw;
-    pre_mul[0] = 1.14;
-    pre_mul[2] = 2.73;
-  } else if (!strcmp(model,"QV-2000UX")) {
-    height = 1208;
-    width  = 1632;
-    data_offset = width * 2;
-    load_raw = eight_bit_load_raw;
-  } else if (!strcmp(model,"QV-3*00EX")) {
-    height = 1546;
-    width  = 2070;
-    raw_width = 2080;
-    load_raw = eight_bit_load_raw;
-  } else if (!strcmp(model,"QV-4000")) {
-    height = 1700;
-    width  = 2260;
-    load_raw = unpacked_load_raw;
-    maximum = 0xffff;
-  } else if (!strcmp(model,"QV-5700")) {
-    height = 1924;
-    width  = 2576;
-    load_raw = casio_qv5700_load_raw;
-  } else if (!strcmp(model,"QV-R51")) {
-    height = 1926;
-    width  = 2576;
-    raw_width = 3904;
-    load_raw = packed_12_load_raw;
-    pre_mul[0] = 1.340;
-    pre_mul[2] = 1.672;
-  } else if (!strcmp(model,"EX-Z55")) {
-    height = 1960;
-    width  = 2570;
-    raw_width = 3904;
-    load_raw = packed_12_load_raw;
-    pre_mul[0] = 1.520;
-    pre_mul[2] = 1.316;
-  } else if (!strcmp(model,"EX-P600")) {
-    height = 2142;
-    width  = 2844;
-    raw_width = 4288;
-    load_raw = packed_12_load_raw;
-    pre_mul[0] = 1.797;
-    pre_mul[2] = 1.219;
-  } else if (!strcmp(model,"EX-P700")) {
-    height = 2318;
-    width  = 3082;
-    raw_width = 4672;
-    load_raw = packed_12_load_raw;
-    pre_mul[0] = 1.758;
-    pre_mul[2] = 1.504;
-  } else if (!strcmp(make,"Nucore")) {
-    filters = 0x61616161;
-    load_raw = unpacked_load_raw;
-    if (width == 2598) {
-      filters = 0x16161616;
-      load_raw = nucore_load_raw;
-      flip = 2;
     }
-  }
-  if (!use_coeff) adobe_coeff();
+    if (!use_coeff)
+        adobeCoeff(make, model);
 dng_skip:
-  if (!load_raw || !height) {
-    pm_message ("This program cannot handle data from %s %s.",
-                make, model);
-    return 1;
-  }
+    if (!load_raw || !height) {
+        pm_message ("This program cannot handle data from %s %s.",
+                    make, model);
+        return 1;
+    }
 #ifdef NO_JPEG
-  if (load_raw == kodak_jpeg_load_raw) {
-    pm_message ("decoder was not linked with libjpeg.");
-    return 1;
-  }
-#endif
-  if (!raw_height) raw_height = height;
-  if (!raw_width ) raw_width  = width;
-  if (use_camera_rgb && colors == 3)
-      use_coeff = 0;
-  if (use_coeff)         /* Apply user-selected color balance */
-    for (i=0; i < colors; i++) {
-      coeff[0][i] *= red_scale;
-      coeff[2][i] *= blue_scale;
+    if (load_raw == kodak_jpeg_load_raw) {
+        pm_message ("decoder was not linked with libjpeg.");
+        return 1;
     }
-  if (four_color_rgb && filters && colors == 3) {
-    for (i=0; i < 32; i+=4) {
-      if ((filters >> i & 15) == 9)
-    filters |= 2 << i;
-      if ((filters >> i & 15) == 6)
-    filters |= 8 << i;
+#endif
+    if (!raw_height) raw_height = height;
+    if (!raw_width ) raw_width  = width;
+    if (use_camera_rgb && colors == 3)
+        use_coeff = 0;
+    if (use_coeff)         /* Apply user-selected color balance */
+        for (i=0; i < colors; i++) {
+            coeff[0][i] *= red_scale;
+            coeff[2][i] *= blue_scale;
+        }
+    if (four_color_rgb && filters && colors == 3) {
+        for (i=0; i < 32; i+=4) {
+            if ((filters >> i & 15) == 9)
+                filters |= 2 << i;
+            if ((filters >> i & 15) == 6)
+                filters |= 8 << i;
+        }
+        colors++;
+        pre_mul[3] = pre_mul[1];
+        if (use_coeff)
+            for (i=0; i < 3; i++)
+                coeff[i][3] = coeff[i][1] /= 2;
     }
-    colors++;
-    pre_mul[3] = pre_mul[1];
-    if (use_coeff)
-      for (i=0; i < 3; i++)
-    coeff[i][3] = coeff[i][1] /= 2;
-  }
-  fseek (ifp, data_offset, SEEK_SET);
+    fseek (ifp, data_offset, SEEK_SET);
 
-  *loadRawFnP = load_raw;
+    *loadRawFnP = load_raw;
 
-  return 0;
+    return 0;
 }
diff --git a/converter/other/cameratopam/identify.h b/converter/other/cameratopam/identify.h
index 012b807c..62c9aae5 100644
--- a/converter/other/cameratopam/identify.h
+++ b/converter/other/cameratopam/identify.h
@@ -1,4 +1,4 @@
-typedef void (*loadRawFn)();
+#include "camera.h"
 
 int
 identify(FILE *       const ifp,
@@ -8,4 +8,4 @@ identify(FILE *       const ifp,
          float        const blue_scale,
          unsigned int const four_color_rgb,
          const char * const inputFileName,
-         loadRawFn *  const loadRawFnP);
+         LoadRawFn ** const loadRawFnP);
diff --git a/converter/other/cameratopam/ljpeg.c b/converter/other/cameratopam/ljpeg.c
index 4b092933..07791e25 100644
--- a/converter/other/cameratopam/ljpeg.c
+++ b/converter/other/cameratopam/ljpeg.c
@@ -20,127 +20,145 @@
  */
 
 int  
-ljpeg_start (FILE * ifp, struct jhead *jh)
-{
-  int i, tag, len;
-  unsigned char data[256], *dp;
-
-  init_decoder();
-  for (i=0; i < 4; i++)
-    jh->huff[i] = free_decode;
-  fread (data, 2, 1, ifp);
-  if (data[0] != 0xff || data[1] != 0xd8) return 0;
-  do {
-    fread (data, 2, 2, ifp);
-    tag =  data[0] << 8 | data[1];
-    len = (data[2] << 8 | data[3]);
-    if (len < 2)
-      pm_error("Length field is %u; must be at least 2", len);
-    else {
-      unsigned int const dataLen = len - 2;
-      if (tag <= 0xff00 || dataLen > 255) return 0;
-      fread (data, 1, dataLen, ifp);
-      switch (tag) {
-      case 0xffc3:
-        jh->bits = data[0];
-        jh->high = data[1] << 8 | data[2];
-        jh->wide = data[3] << 8 | data[4];
-        jh->clrs = data[5];
-        break;
-      case 0xffc4:
-        for (dp = data; dp < data+dataLen && *dp < 4; ) {
-          jh->huff[*dp] = free_decode;
-          dp = make_decoder (++dp, 0);
+ljpeg_start(FILE *         const ifP,
+            struct jhead * const jhP) {
+
+    int i, tag;
+    unsigned char data[256], *dp;
+
+    init_decoder();
+    for (i=0; i < 4; i++)
+        jhP->huff[i] = free_decode;
+    fread (data, 2, 1, ifP);
+    if (data[0] != 0xff || data[1] != 0xd8) return 0;
+    do {
+        unsigned int len;
+
+        fread (data, 2, 2, ifP);
+        tag =  data[0] << 8 | data[1];
+        len = data[2] << 8 | data[3];
+
+        if (len < 2)
+            pm_error("Length field is %u; must be at least 2", len);
+        else {
+            unsigned int const dataLen = len - 2;
+
+            if (tag <= 0xff00 || dataLen > 255) return 0;
+            fread (data, 1, dataLen, ifP);
+            switch (tag) {
+            case 0xffc3:
+                jhP->bits = data[0];
+                jhP->high = data[1] << 8 | data[2];
+                jhP->wide = data[3] << 8 | data[4];
+                jhP->clrs = data[5];
+                break;
+            case 0xffc4:
+                for (dp = data; dp < data + dataLen && *dp < 4; ) {
+                    jhP->huff[*dp] = free_decode;
+                    dp = make_decoder (++dp, 0);
+                }
+            }
         }
-      }
-    }
-  } while (tag != 0xffda);
-  jh->row = calloc (jh->wide*jh->clrs, 2);
-  if (jh->row == NULL)
-      pm_error("Out of memory in ljpeg_start()");
-  for (i=0; i < 4; i++)
-    jh->vpred[i] = 1 << (jh->bits-1);
-  zero_after_ff = 1;
-  getbits(ifp, -1);
-  return 1;
+    } while (tag != 0xffda);
+    jhP->row = calloc (jhP->wide*jhP->clrs, 2);
+    if (jhP->row == NULL)
+        pm_error("Out of memory in ljpeg_start()");
+    for (i=0; i < 4; i++)
+        jhP->vpred[i] = 1 << (jhP->bits-1);
+    zero_after_ff = 1;
+    getbits(ifP, -1);
+    return 1;
 }
 
+
+
 int 
-ljpeg_diff (struct decode *dindex)
-{
-  int len, diff;
-
-  while (dindex->branch[0])
-    dindex = dindex->branch[getbits(ifp, 1)];
-  diff = getbits(ifp, len = dindex->leaf);
-  if ((diff & (1 << (len-1))) == 0)
-    diff -= (1 << len) - 1;
-  return diff;
+ljpeg_diff(FILE *          const ifP,
+           struct decode * const dindexHeadP) {
+
+    int len;
+    int diff;
+    struct decode * dindexP;
+
+    for (dindexP = dindexHeadP; dindexP->branch[0]; )
+        dindexP = dindexP->branch[getbits(ifP, 1)];
+
+    diff = getbits(ifP, len = dindexP->leaf);
+
+    if ((diff & (1 << (len-1))) == 0)
+        diff -= (1 << len) - 1;
+
+    return diff;
 }
 
+
+
 void
-ljpeg_row (struct jhead *jh)
-{
-  int col, c, diff;
-  unsigned short *outp=jh->row;
-
-  for (col=0; col < jh->wide; col++)
-    for (c=0; c < jh->clrs; c++) {
-      diff = ljpeg_diff (jh->huff[c]);
-      *outp = col ? outp[-jh->clrs]+diff : (jh->vpred[c] += diff);
-      outp++;
-    }
+ljpeg_row(FILE *         const ifP,
+          struct jhead * const jhP) {
+
+    int col, c, diff;
+    unsigned short *outp=jhP->row;
+
+    for (col=0; col < jhP->wide; col++)
+        for (c=0; c < jhP->clrs; c++) {
+            diff = ljpeg_diff(ifP, jhP->huff[c]);
+            *outp = col ? outp[-jhP->clrs]+diff : (jhP->vpred[c] += diff);
+            outp++;
+        }
 }
 
+
+
 void  
-lossless_jpeg_load_raw(void)
-{
-  int jwide, jrow, jcol, val, jidx, i, row, col;
-  struct jhead jh;
-  int min=INT_MAX;
-
-  if (!ljpeg_start (ifp, &jh)) return;
-  jwide = jh.wide * jh.clrs;
-
-  for (jrow=0; jrow < jh.high; jrow++) {
-    ljpeg_row (&jh);
-    for (jcol=0; jcol < jwide; jcol++) {
-      val = curve[jh.row[jcol]];
-      jidx = jrow*jwide + jcol;
-      if (raw_width == 5108) {
-    i = jidx / (1680*jh.high);
-    if (i < 2) {
-      row = jidx / 1680 % jh.high;
-      col = jidx % 1680 + i*1680;
-    } else {
-      jidx -= 2*1680*jh.high;
-      row = jidx / 1748;
-      col = jidx % 1748 + 2*1680;
-    }
-      } else if (raw_width == 3516) {
-    row = jidx / 1758;
-    col = jidx % 1758;
-    if (row >= raw_height) {
-      row -= raw_height;
-      col += 1758;
-    }
-      } else {
-    row = jidx / raw_width;
-    col = jidx % raw_width;
-      }
-      if ((unsigned) (row-top_margin) >= height) continue;
-      if ((unsigned) (col-left_margin) < width) {
-    BAYER(row-top_margin,col-left_margin) = val;
-    if (min > val) min = val;
-      } else
-    black += val;
+lossless_jpeg_load_raw(Image  const image) {
+
+    int jwide, jrow, jcol, val, jidx, i, row, col;
+    struct jhead jh;
+    int min=INT_MAX;
+
+    if (!ljpeg_start (ifp, &jh)) return;
+    jwide = jh.wide * jh.clrs;
+
+    for (jrow=0; jrow < jh.high; jrow++) {
+        ljpeg_row (ifp, &jh);
+        for (jcol=0; jcol < jwide; jcol++) {
+            val = curve[jh.row[jcol]];
+            jidx = jrow*jwide + jcol;
+            if (raw_width == 5108) {
+                i = jidx / (1680*jh.high);
+                if (i < 2) {
+                    row = jidx / 1680 % jh.high;
+                    col = jidx % 1680 + i*1680;
+                } else {
+                    jidx -= 2*1680*jh.high;
+                    row = jidx / 1748;
+                    col = jidx % 1748 + 2*1680;
+                }
+            } else if (raw_width == 3516) {
+                row = jidx / 1758;
+                col = jidx % 1758;
+                if (row >= raw_height) {
+                    row -= raw_height;
+                    col += 1758;
+                }
+            } else {
+                row = jidx / raw_width;
+                col = jidx % raw_width;
+            }
+            if ((unsigned) (row-top_margin) >= height) continue;
+            if ((unsigned) (col-left_margin) < width) {
+                BAYER(row-top_margin,col-left_margin) = val;
+                if (min > val) min = val;
+            } else
+                black += val;
+        }
     }
-  }
-  free (jh.row);
-  if (raw_width > width)
-    black /= (raw_width - width) * height;
-  if (!strcasecmp(make,"KODAK"))
-    black = min;
+    free (jh.row);
+    if (raw_width > width)
+        black /= (raw_width - width) * height;
+    if (!strcasecmp(make,"KODAK"))
+        black = min;
 }
 
 
diff --git a/converter/other/cameratopam/ljpeg.h b/converter/other/cameratopam/ljpeg.h
index 60832a3d..9d9d8ee9 100644
--- a/converter/other/cameratopam/ljpeg.h
+++ b/converter/other/cameratopam/ljpeg.h
@@ -1,17 +1,21 @@
+#include "camera.h"
+
 struct jhead {
   int bits, high, wide, clrs, vpred[4];
   struct decode *huff[4];
   unsigned short *row;
 };
 
-void  
-lossless_jpeg_load_raw(void);
+LoadRawFn lossless_jpeg_load_raw;
 
 int  
-ljpeg_start (FILE * ifp, struct jhead *jh);
+ljpeg_start (FILE *         const ifP,
+             struct jhead * const jhP);
 
 int 
-ljpeg_diff (struct decode *dindex);
+ljpeg_diff (FILE *          const ifP,
+            struct decode * const dindexP);
 
 void
-ljpeg_row (struct jhead *jh);
+ljpeg_row(FILE *         const ifP,
+          struct jhead * const jhP);
diff --git a/converter/other/exif.c b/converter/other/exif.c
index f9592d6c..1bfe4b2b 100644
--- a/converter/other/exif.c
+++ b/converter/other/exif.c
@@ -21,6 +21,7 @@
   See the EXIF specs at http://exif.org (2001.09.01).
 
 --------------------------------------------------------------------------*/
+#include "pm_config.h"
 #include <stdio.h>
 #include <stdlib.h>
 #include <math.h>
@@ -30,7 +31,7 @@
 #include <limits.h>
 #include <ctype.h>
 
-#ifdef _WIN32
+#if MSVCRT
     #include <sys/utime.h>
 #else
     #include <utime.h>
@@ -45,22 +46,21 @@
 
 #include "exif.h"
 
-static unsigned char * LastExifRefd;
-static unsigned char * DirWithThumbnailPtrs;
+static const unsigned char * DirWithThumbnailPtrs;
 static double FocalplaneXRes;
 bool HaveXRes;
 static double FocalplaneUnits;
 static int ExifImageWidth;
-static int MotorolaOrder = 0;
 
 typedef struct {
     unsigned short Tag;
     const char * Desc;
-}TagTable_t;
+} TagTable;
+
 
 
 /* Describes format descriptor */
-static int BytesPerFormat[] = {0,1,1,2,4,8,1,1,2,4,8,4,8};
+static int const bytesPerFormat[] = {0,1,1,2,4,8,1,1,2,4,8,4,8};
 #define NUM_FORMATS 12
 
 #define FMT_BYTE       1 
@@ -119,7 +119,7 @@ static int BytesPerFormat[] = {0,1,1,2,4,8,1,1,2,4,8,4,8};
 #define TAG_THUMBNAIL_OFFSET  0x0201
 #define TAG_THUMBNAIL_LENGTH  0x0202
 
-static TagTable_t const TagTable[] = {
+static TagTable const tagTable[] = {
   {   0x100,   "ImageWidth"},
   {   0x101,   "ImageLength"},
   {   0x102,   "BitsPerSample"},
@@ -207,498 +207,583 @@ static TagTable_t const TagTable[] = {
 
 
 
+typedef enum { NORMAL, MOTOROLA } ByteOrder;
+
+
+
+static uint16_t
+get16u(const void * const data,
+       ByteOrder    const byteOrder) {
 /*--------------------------------------------------------------------------
    Convert a 16 bit unsigned value from file's native byte order
 --------------------------------------------------------------------------*/
-static int Get16u(void * Short)
-{
-    if (MotorolaOrder){
-        return (((unsigned char *)Short)[0] << 8) | 
-            ((unsigned char *)Short)[1];
+    if (byteOrder == MOTOROLA){
+        return (((const unsigned char *)data)[0] << 8) | 
+            ((const unsigned char *)data)[1];
     }else{
-        return (((unsigned char *)Short)[1] << 8) | 
-            ((unsigned char *)Short)[0];
+        return (((const unsigned char *)data)[1] << 8) | 
+            ((const unsigned char *)data)[0];
     }
 }
 
+
+
+static int32_t
+get32s(const void * const data,
+       ByteOrder    const byteOrder) {
 /*--------------------------------------------------------------------------
    Convert a 32 bit signed value from file's native byte order
 --------------------------------------------------------------------------*/
-static int Get32s(void * Long)
-{
-    if (MotorolaOrder){
+    if (byteOrder == MOTOROLA){
         return  
-            ((( char *)Long)[0] << 24) | (((unsigned char *)Long)[1] << 16) |
-            (((unsigned char *)Long)[2] << 8 ) | 
-            (((unsigned char *)Long)[3] << 0 );
-    }else{
+            (((const char *)data)[0] << 24) |
+            (((const unsigned char *)data)[1] << 16) |
+            (((const unsigned char *)data)[2] << 8 ) | 
+            (((const unsigned char *)data)[3] << 0 );
+    } else {
         return  
-            ((( char *)Long)[3] << 24) | (((unsigned char *)Long)[2] << 16) |
-            (((unsigned char *)Long)[1] << 8 ) | 
-            (((unsigned char *)Long)[0] << 0 );
+            (((const char *)data)[3] << 24) |
+            (((const unsigned char *)data)[2] << 16) |
+            (((const unsigned char *)data)[1] << 8 ) | 
+            (((const unsigned char *)data)[0] << 0 );
     }
 }
 
+
+
+static uint32_t
+get32u(const void * const data,
+       ByteOrder    const byteOrder) {
 /*--------------------------------------------------------------------------
    Convert a 32 bit unsigned value from file's native byte order
 --------------------------------------------------------------------------*/
-static unsigned Get32u(void * Long)
-{
-    return (unsigned)Get32s(Long) & 0xffffffff;
+    return (uint32_t)get32s(data, byteOrder) & 0xffffffff;
 }
 
+
+
+static void
+printFormatNumber(FILE *       const fileP, 
+                  const void * const ValuePtr, 
+                  int          const Format,
+                  int          const ByteCount,
+                  ByteOrder    const byteOrder) {
 /*--------------------------------------------------------------------------
    Display a number as one of its many formats
 --------------------------------------------------------------------------*/
-static void PrintFormatNumber(FILE * const file, 
-                              void * const ValuePtr, 
-                              int const Format, int const ByteCount)
-{
     switch(Format){
     case FMT_SBYTE:
-    case FMT_BYTE:      printf("%02x\n",*(unsigned char *)ValuePtr); break;
-    case FMT_USHORT:    fprintf(file, "%d\n",Get16u(ValuePtr));    break;
+    case FMT_BYTE:
+        fprintf(fileP, "%02x\n", *(unsigned char *)ValuePtr);
+        break;
+    case FMT_USHORT:
+        fprintf(fileP, "%d\n",get16u(ValuePtr, byteOrder));
+        break;
     case FMT_ULONG:     
-    case FMT_SLONG:     fprintf(file, "%d\n",Get32s(ValuePtr));    break;
+    case FMT_SLONG:
+        fprintf(fileP, "%d\n",get32s(ValuePtr, byteOrder));
+        break;
     case FMT_SSHORT:    
-        fprintf(file, "%hd\n",(signed short)Get16u(ValuePtr));     break;
+        fprintf(fileP, "%hd\n",(signed short)get16u(ValuePtr, byteOrder));
+        break;
     case FMT_URATIONAL:
     case FMT_SRATIONAL: 
-        fprintf(file, "%d/%d\n",Get32s(ValuePtr), Get32s(4+(char *)ValuePtr));
+        fprintf(fileP, "%d/%d\n",get32s(ValuePtr, byteOrder),
+                get32s(4+(char *)ValuePtr, byteOrder));
         break;
     case FMT_SINGLE:    
-        fprintf(file, "%f\n",(double)*(float *)ValuePtr);          break;
-    case FMT_DOUBLE:    fprintf(file, "%f\n",*(double *)ValuePtr); break;
+        fprintf(fileP, "%f\n",(double)*(float *)ValuePtr);
+        break;
+    case FMT_DOUBLE:
+        fprintf(fileP, "%f\n",*(double *)ValuePtr);
+        break;
     default: 
-        fprintf(file, "Unknown format %d:", Format);
+        fprintf(fileP, "Unknown format %d:", Format);
         {
-            int a;
-            for (a=0; a < ByteCount && a < 16; ++a)
+            unsigned int a;
+            for (a = 0; a < ByteCount && a < 16; ++a)
                 printf("%02x", ((unsigned char *)ValuePtr)[a]);
         }
-        fprintf(file, "\n");
+        fprintf(fileP, "\n");
     }
 }
 
 
+
+static double
+convertAnyFormat(const void * const ValuePtr,
+                 int          const Format,
+                 ByteOrder    const byteOrder) {
 /*--------------------------------------------------------------------------
    Evaluate number, be it int, rational, or float from directory.
 --------------------------------------------------------------------------*/
-static double ConvertAnyFormat(void * ValuePtr, int Format)
-{
     double Value;
     Value = 0;
 
     switch(Format){
-        case FMT_SBYTE:     Value = *(signed char *)ValuePtr;  break;
-        case FMT_BYTE:      Value = *(unsigned char *)ValuePtr;        break;
-
-        case FMT_USHORT:    Value = Get16u(ValuePtr);          break;
-        case FMT_ULONG:     Value = Get32u(ValuePtr);          break;
-
-        case FMT_URATIONAL:
-        case FMT_SRATIONAL: 
-            {
-                int Num,Den;
-                Num = Get32s(ValuePtr);
-                Den = Get32s(4+(char *)ValuePtr);
-                if (Den == 0){
-                    Value = 0;
-                }else{
-                    Value = (double)Num/Den;
-                }
-                break;
-            }
-
-        case FMT_SSHORT:    Value = (signed short)Get16u(ValuePtr);  break;
-        case FMT_SLONG:     Value = Get32s(ValuePtr);                break;
+    case FMT_SBYTE:
+        Value = *(signed char *)ValuePtr;
+        break;
+    case FMT_BYTE:
+        Value = *(unsigned char *)ValuePtr;
+        break;
+    case FMT_USHORT:
+        Value = get16u(ValuePtr, byteOrder);
+        break;
+    case FMT_ULONG:
+        Value = get32u(ValuePtr, byteOrder);
+        break;
+    case FMT_URATIONAL:
+    case FMT_SRATIONAL: {
+        int num, den;
+        num = get32s(ValuePtr, byteOrder);
+        den = get32s(4+(char *)ValuePtr, byteOrder);
+        Value = den == 0 ? 0 : (double)(num/den);
+    } break;
+    case FMT_SSHORT:
+        Value = (signed short)get16u(ValuePtr, byteOrder);
+        break;
+    case FMT_SLONG:
+        Value = get32s(ValuePtr, byteOrder);
+        break;
 
-        /* Not sure if this is correct (never seen float used in Exif format)
-         */
-        case FMT_SINGLE:    Value = (double)*(float *)ValuePtr;      break;
-        case FMT_DOUBLE:    Value = *(double *)ValuePtr;             break;
+    /* Not sure if this is correct (never seen float used in Exif format) */
+    case FMT_SINGLE:
+        Value = (double)*(float *)ValuePtr;
+        break;
+    case FMT_DOUBLE:
+        Value = *(double *)ValuePtr;
+        break;
     }
     return Value;
 }
 
-/*--------------------------------------------------------------------------
-   Process one of the nested EXIF directories.
---------------------------------------------------------------------------*/
-static void 
-ProcessExifDir(unsigned char *  const ExifData, 
-               unsigned int     const ExifLength,
-               unsigned int     const DirOffset,
-               ImageInfo_t *    const ImageInfoP, 
-               int              const ShowTags,
-               unsigned char ** const LastExifRefdP) {
-
-    unsigned char * const DirStart = ExifData + DirOffset;
-    int de;
-    int a;
-    int NumDirEntries;
-    unsigned ThumbnailOffset = 0;
-    unsigned ThumbnailSize = 0;
-
-    NumDirEntries = Get16u(DirStart);
-    #define DIR_ENTRY_ADDR(Start, Entry) (Start+2+12*(Entry))
 
-    {
-        unsigned char * DirEnd;
-        DirEnd = DIR_ENTRY_ADDR(DirStart, NumDirEntries);
-        if (DirEnd+4 > (ExifData+ExifLength)){
-            if (DirEnd+2 == ExifData+ExifLength || 
-                DirEnd == ExifData+ExifLength){
-                /* Version 1.3 of jhead would truncate a bit too much.
-                   This also caught later on as well.
-                */
-            }else{
-                /* Note: Files that had thumbnails trimmed with jhead
-                   1.3 or earlier might trigger this.
+
+static void
+traceTag(int                   const tag,
+         int                   const format,
+         const unsigned char * const valuePtr,
+         unsigned int          const byteCount,
+         ByteOrder             const byteOrder) {
+             
+    /* Show tag name */
+    unsigned int a;
+    bool found;
+    for (a = 0, found = false; !found; ++a){
+        if (tagTable[a].Tag == 0){
+            fprintf(stderr, "  Unknown Tag %04x Value = ", tag);
+            found = true;
+        }
+        if (tagTable[a].Tag == tag){
+            fprintf(stderr, "    %s = ",tagTable[a].Desc);
+            found = true;
+        }
+    }
+
+    /* Show tag value. */
+    switch(format){
+
+    case FMT_UNDEFINED:
+        /* Undefined is typically an ascii string. */
+
+    case FMT_STRING: {
+        /* String arrays printed without function call
+           (different from int arrays)
+        */
+        bool noPrint;
+        printf("\"");
+        for (a = 0, noPrint = false; a < byteCount; ++a){
+            if (ISPRINT((valuePtr)[a])){
+                fprintf(stderr, "%c", valuePtr[a]);
+                noPrint = false;
+            } else {
+                /* Avoiding indicating too many unprintable characters of
+                   proprietary bits of binary information this program may not
+                   know how to parse.
                 */
-                pm_message("Illegal directory entry size");
-                return;
+                if (!noPrint){
+                    fprintf(stderr, "?");
+                    noPrint = true;
+                }
             }
         }
-        if (DirEnd > LastExifRefd) LastExifRefd = DirEnd;
+        fprintf(stderr, "\"\n");
+    } break;
+
+    default:
+        /* Handle arrays of numbers later (will there ever be?)*/
+        printFormatNumber(stderr, valuePtr, format, byteCount, byteOrder);
     }
+}
+
+
+
+/* Forward declaration for recursion */
+
+static void 
+processExifDir(const unsigned char *  const ExifData, 
+               unsigned int           const ExifLength,
+               unsigned int           const DirOffset,
+               exif_ImageInfo *       const imageInfoP, 
+               ByteOrder              const byteOrder,
+               bool                   const wantTagTrace,
+               const unsigned char ** const LastExifRefdP);
+
+
+static void
+processDirEntry(const unsigned char *  const dirEntry,
+                const unsigned char *  const exifData,
+                unsigned int           const exifLength,
+                ByteOrder              const byteOrder,
+                bool                   const wantTagTrace,
+                exif_ImageInfo *       const imageInfoP, 
+                unsigned int *         const thumbnailOffsetP,
+                unsigned int *         const thumbnailSizeP,
+                bool *                 const haveThumbnailP,
+                const unsigned char ** const lastExifRefdP) {
+
+    int const tag        = get16u(&dirEntry[0], byteOrder);
+    int const format     = get16u(&dirEntry[2], byteOrder);
+    int const components = get32u(&dirEntry[4], byteOrder);
+
+    const unsigned char * valuePtr;
+        /* This actually can point to a variety of things; it must be cast to
+           other types when used.  But we use it as a byte-by-byte cursor, so
+           we declare it as a pointer to a generic byte here.
+        */
+    unsigned int byteCount;
 
-    if (ShowTags){
-        pm_message("Directory with %d entries",NumDirEntries);
+    if ((format-1) >= NUM_FORMATS) {
+        /* (-1) catches illegal zero case as unsigned underflows
+           to positive large.  
+        */
+        pm_message("Illegal number format %d for tag %04x", format, tag);
+        return;
+    }
+        
+    byteCount = components * bytesPerFormat[format];
+
+    if (byteCount > 4){
+        unsigned const offsetVal = get32u(&dirEntry[8], byteOrder);
+        /* If its bigger than 4 bytes, the dir entry contains an offset.*/
+        if (offsetVal + byteCount > exifLength){
+            /* Bogus pointer offset and / or bytecount value */
+            pm_message("Illegal pointer offset value in EXIF "
+                       "for tag %04x.  "
+                       "Offset %d bytes %d ExifLen %d\n",
+                       tag, offsetVal, byteCount, exifLength);
+            return;
+        }
+        valuePtr = &exifData[offsetVal];
+    } else {
+        /* 4 bytes or less and value is in the dir entry itself */
+        valuePtr = &dirEntry[8];
     }
 
-    for (de=0;de<NumDirEntries;de++){
-        int Tag, Format, Components;
-        unsigned char * ValuePtr;
-            /* This actually can point to a variety of things; it must
-               be cast to other types when used.  But we use it as a
-               byte-by-byte cursor, so we declare it as a pointer to a
-               generic byte here.  
-            */
-        int ByteCount;
-        unsigned char * DirEntry;
-        DirEntry = DIR_ENTRY_ADDR(DirStart, de);
+    if (*lastExifRefdP < valuePtr + byteCount){
+        /* Keep track of last byte in the exif header that was actually
+           referenced.  That way, we know where the discardable thumbnail data
+           begins.
+        */
+        *lastExifRefdP = valuePtr + byteCount;
+    }
 
-        Tag = Get16u(DirEntry);
-        Format = Get16u(DirEntry+2);
-        Components = Get32u(DirEntry+4);
+    if (wantTagTrace)
+        traceTag(tag, format, valuePtr, byteCount, byteOrder);
 
-        if ((Format-1) >= NUM_FORMATS) {
-            /* (-1) catches illegal zero case as unsigned underflows
-               to positive large.  
-            */
-            pm_message("Illegal number format %d for tag %04x", Format, Tag);
-            continue;
+    *haveThumbnailP = (tag == TAG_THUMBNAIL_OFFSET);
+
+    /* Extract useful components of tag */
+    switch (tag){
+
+    case TAG_MAKE:
+        STRSCPY(imageInfoP->CameraMake, (const char*)valuePtr);
+        break;
+
+    case TAG_MODEL:
+        STRSCPY(imageInfoP->CameraModel, (const char*)valuePtr);
+        break;
+
+    case TAG_XRESOLUTION:
+        imageInfoP->XResolution = 
+            convertAnyFormat(valuePtr, format, byteOrder);
+        break;
+
+    case TAG_YRESOLUTION:
+        imageInfoP->YResolution = 
+            convertAnyFormat(valuePtr, format, byteOrder);
+        break;
+
+    case TAG_DATETIME_ORIGINAL:
+        STRSCPY(imageInfoP->DateTime, (const char*)valuePtr);
+        imageInfoP->DatePointer = (const char*)valuePtr;
+        break;
+
+    case TAG_USERCOMMENT: {
+        /* Olympus has this padded with trailing spaces.  We stop the copy
+           where those start.
+        */
+        const char * const value = (const char *)valuePtr;
+
+        unsigned int cursor;
+        unsigned int outCursor;
+        unsigned int end;
+
+        for (end = byteCount; end > 0 && value[end] == ' '; --end);
+
+        /* Skip "ASCII" if it is there */
+        if (end >= 5 && MEMEQ(value, "ASCII", 5))
+            cursor = 5;
+        else
+            cursor = 0;
+
+        /* Skip consecutive blanks and NULs */
+
+        for (;
+             cursor < byteCount && 
+                 (value[cursor] == '\0' || value[cursor] == ' ');
+             ++cursor);
+
+        /* Copy the rest as the comment */
+
+        for (outCursor = 0;
+             cursor < end && outCursor < MAX_COMMENT-1;
+             ++cursor)
+            imageInfoP->Comments[outCursor++] = value[cursor];
+
+        imageInfoP->Comments[outCursor++] = '\0';
+    } break;
+
+    case TAG_FNUMBER:
+        /* Simplest way of expressing aperture, so I trust it the most.
+           (overwrite previously computd value if there is one)
+        */
+        imageInfoP->ApertureFNumber = 
+            (float)convertAnyFormat(valuePtr, format, byteOrder);
+        break;
+
+    case TAG_APERTURE:
+    case TAG_MAXAPERTURE:
+        /* More relevant info always comes earlier, so only use this field if
+           we don't have appropriate aperture information yet.
+        */
+        if (imageInfoP->ApertureFNumber == 0){
+            imageInfoP->ApertureFNumber = (float)
+                exp(convertAnyFormat(valuePtr, format, byteOrder)
+                    * log(2) * 0.5);
         }
-        
-        ByteCount = Components * BytesPerFormat[Format];
-
-        if (ByteCount > 4){
-            unsigned OffsetVal;
-            OffsetVal = Get32u(DirEntry+8);
-            /* If its bigger than 4 bytes, the dir entry contains an offset.*/
-            if (OffsetVal+ByteCount > ExifLength){
-                /* Bogus pointer offset and / or bytecount value */
-                pm_message("Illegal pointer offset value in EXIF "
-                           "for tag %04x.  "
-                           "Offset %d bytes %d ExifLen %d\n",
-                           Tag, OffsetVal, ByteCount, ExifLength);
-                continue;
-            }
-            ValuePtr = ExifData+OffsetVal;
+        break;
+
+    case TAG_FOCALLENGTH:
+        /* Nice digital cameras actually save the focal length
+           as a function of how farthey are zoomed in. 
+        */
+
+        imageInfoP->FocalLength = 
+            (float)convertAnyFormat(valuePtr, format, byteOrder);
+        break;
+
+    case TAG_SUBJECT_DISTANCE:
+        /* Inidcates the distacne the autofocus camera is focused to.
+           Tends to be less accurate as distance increases.
+        */
+        imageInfoP->Distance = 
+            (float)convertAnyFormat(valuePtr, format, byteOrder);
+        break;
+
+    case TAG_EXPOSURETIME:
+        /* Simplest way of expressing exposure time, so I
+           trust it most.  (overwrite previously computd value
+           if there is one) 
+        */
+        imageInfoP->ExposureTime = 
+            (float)convertAnyFormat(valuePtr, format, byteOrder);
+        break;
+
+    case TAG_SHUTTERSPEED:
+        /* More complicated way of expressing exposure time,
+           so only use this value if we don't already have it
+           from somewhere else.  
+        */
+        if (imageInfoP->ExposureTime == 0){
+            imageInfoP->ExposureTime = (float)
+                (1/exp(convertAnyFormat(valuePtr, format, byteOrder)
+                       * log(2)));
+        }
+        break;
+
+    case TAG_FLASH:
+        if ((int)convertAnyFormat(valuePtr, format, byteOrder) & 0x7){
+            imageInfoP->FlashUsed = TRUE;
         }else{
-            /* 4 bytes or less and value is in the dir entry itself */
-            ValuePtr = DirEntry+8;
+            imageInfoP->FlashUsed = FALSE;
         }
+        break;
 
-        if (*LastExifRefdP < ValuePtr+ByteCount){
-            /* Keep track of last byte in the exif header that was
-               actually referenced.  That way, we know where the
-               discardable thumbnail data begins.
-            */
-            *LastExifRefdP = ValuePtr+ByteCount;
+    case TAG_ORIENTATION:
+        imageInfoP->Orientation = 
+            (int)convertAnyFormat(valuePtr, format, byteOrder);
+        if (imageInfoP->Orientation < 1 || 
+            imageInfoP->Orientation > 8){
+            pm_message("Undefined rotation value %d",
+                       imageInfoP->Orientation);
+            imageInfoP->Orientation = 0;
         }
+        break;
 
-        if (ShowTags){
-            /* Show tag name */
-            for (a=0;;a++){
-                if (TagTable[a].Tag == 0){
-                    fprintf(stderr, "  Unknown Tag %04x Value = ", Tag);
-                    break;
-                }
-                if (TagTable[a].Tag == Tag){
-                    fprintf(stderr, "    %s = ",TagTable[a].Desc);
-                    break;
-                }
-            }
+    case TAG_EXIF_IMAGELENGTH:
+    case TAG_EXIF_IMAGEWIDTH:
+        /* Use largest of height and width to deal with images
+           that have been rotated to portrait format.  
+        */
+        ExifImageWidth =
+            MIN(ExifImageWidth,
+                (int)convertAnyFormat(valuePtr, format, byteOrder));
+        break;
 
-            /* Show tag value. */
-            switch(Format){
-
-                case FMT_UNDEFINED:
-                    /* Undefined is typically an ascii string. */
-
-                case FMT_STRING:
-                    /* String arrays printed without function call
-                       (different from int arrays)
-                    */
-                    {
-                        int NoPrint = 0;
-                        printf("\"");
-                        for (a=0;a<ByteCount;a++){
-                            if (ISPRINT((ValuePtr)[a])){
-                                fprintf(stderr, "%c", (ValuePtr)[a]);
-                                NoPrint = 0;
-                            }else{
-
-                                /* Avoiding indicating too many
-                                   unprintable characters of proprietary
-                                   bits of binary information this
-                                   program may not know how to parse.  
-                                */
-                                if (!NoPrint){
-                                    fprintf(stderr, "?");
-                                    NoPrint = 1;
-                                }
-                            }
-                        }
-                        fprintf(stderr, "\"\n");
-                    }
-                    break;
+    case TAG_FOCALPLANEXRES:
+        HaveXRes = TRUE;
+        FocalplaneXRes = convertAnyFormat(valuePtr, format, byteOrder);
+        break;
 
-                default:
-                    /* Handle arrays of numbers later (will there ever be?)*/
-                    PrintFormatNumber(stderr, ValuePtr, Format, ByteCount);
-            }
+    case TAG_FOCALPLANEUNITS:
+        switch((int)convertAnyFormat(valuePtr, format, byteOrder)){
+        case 1: FocalplaneUnits = 25.4; break; /* 1 inch */
+        case 2: 
+            /* According to the information I was using, 2
+               means meters.  But looking at the Cannon
+               powershot's files, inches is the only
+               sensible value.  
+            */
+            FocalplaneUnits = 25.4;
+            break;
+
+        case 3: FocalplaneUnits = 10;   break;  /* 1 centimeter*/
+        case 4: FocalplaneUnits = 1;    break;  /* 1 millimeter*/
+        case 5: FocalplaneUnits = .001; break;  /* 1 micrometer*/
         }
+        break;
 
-        /* Extract useful components of tag */
-        switch(Tag){
-
-            case TAG_MAKE:
-                STRSCPY(ImageInfoP->CameraMake, (char*)ValuePtr);
-                break;
-
-            case TAG_MODEL:
-                STRSCPY(ImageInfoP->CameraModel, (char*)ValuePtr);
-                break;
-
-            case TAG_XRESOLUTION:
-                ImageInfoP->XResolution = 
-                    ConvertAnyFormat(ValuePtr, Format);
-                break;
-    
-            case TAG_YRESOLUTION:
-                ImageInfoP->YResolution = 
-                    ConvertAnyFormat(ValuePtr, Format);
-                break;
-    
-            case TAG_DATETIME_ORIGINAL:
-                STRSCPY(ImageInfoP->DateTime, (char*)ValuePtr);
-                ImageInfoP->DatePointer = (char*)ValuePtr;
-                break;
-
-            case TAG_USERCOMMENT:
-                /* Olympus has this padded with trailing spaces.
-                   Remove these first. 
-                */
-                for (a=ByteCount;;){
-                    a--;
-                    if (((char*)ValuePtr)[a] == ' '){
-                        ((char*)ValuePtr)[a] = '\0';
-                    }else{
-                        break;
-                    }
-                    if (a == 0) break;
-                }
+        /* Remaining cases contributed by: Volker C. Schoech
+           (schoech@gmx.de)
+        */
 
-                /* Copy the comment */
-                if (memcmp(ValuePtr, "ASCII",5) == 0){
-                    for (a=5;a<10;a++){
-                        char c;
-                        c = ((char*)ValuePtr)[a];
-                        if (c != '\0' && c != ' '){
-                            strncpy(ImageInfoP->Comments, (char*)ValuePtr+a, 
-                                    199);
-                            break;
-                        }
-                    }
-                    
-                }else{
-                    strncpy(ImageInfoP->Comments, (char*)ValuePtr, 199);
-                }
-                break;
-
-            case TAG_FNUMBER:
-                /* Simplest way of expressing aperture, so I trust it the most.
-                   (overwrite previously computd value if there is one)
-                   */
-                ImageInfoP->ApertureFNumber = 
-                    (float)ConvertAnyFormat(ValuePtr, Format);
-                break;
-
-            case TAG_APERTURE:
-            case TAG_MAXAPERTURE:
-                /* More relevant info always comes earlier, so only
-                 use this field if we don't have appropriate aperture
-                 information yet. 
-                */
-                if (ImageInfoP->ApertureFNumber == 0){
-                    ImageInfoP->ApertureFNumber = (float)
-                        exp(ConvertAnyFormat(ValuePtr, Format)*log(2)*0.5);
-                }
-                break;
+    case TAG_EXPOSURE_BIAS:
+        imageInfoP->ExposureBias = 
+            (float) convertAnyFormat(valuePtr, format, byteOrder);
+        break;
 
-            case TAG_FOCALLENGTH:
-                /* Nice digital cameras actually save the focal length
-                   as a function of how farthey are zoomed in. 
-                */
+    case TAG_WHITEBALANCE:
+        imageInfoP->Whitebalance = 
+            (int)convertAnyFormat(valuePtr, format, byteOrder);
+        break;
 
-                ImageInfoP->FocalLength = 
-                    (float)ConvertAnyFormat(ValuePtr, Format);
-                break;
+    case TAG_METERING_MODE:
+        imageInfoP->MeteringMode = 
+            (int)convertAnyFormat(valuePtr, format, byteOrder);
+        break;
 
-            case TAG_SUBJECT_DISTANCE:
-                /* Inidcates the distacne the autofocus camera is focused to.
-                   Tends to be less accurate as distance increases.
-                */
-                ImageInfoP->Distance = 
-                    (float)ConvertAnyFormat(ValuePtr, Format);
-                break;
-
-            case TAG_EXPOSURETIME:
-                /* Simplest way of expressing exposure time, so I
-                   trust it most.  (overwrite previously computd value
-                   if there is one) 
-                */
-                ImageInfoP->ExposureTime = 
-                    (float)ConvertAnyFormat(ValuePtr, Format);
-                break;
-
-            case TAG_SHUTTERSPEED:
-                /* More complicated way of expressing exposure time,
-                   so only use this value if we don't already have it
-                   from somewhere else.  
-                */
-                if (ImageInfoP->ExposureTime == 0){
-                    ImageInfoP->ExposureTime = (float)
-                        (1/exp(ConvertAnyFormat(ValuePtr, Format)*log(2)));
-                }
-                break;
+    case TAG_EXPOSURE_PROGRAM:
+        imageInfoP->ExposureProgram = 
+            (int)convertAnyFormat(valuePtr, format, byteOrder);
+        break;
 
-            case TAG_FLASH:
-                if ((int)ConvertAnyFormat(ValuePtr, Format) & 7){
-                    ImageInfoP->FlashUsed = TRUE;
-                }else{
-                    ImageInfoP->FlashUsed = FALSE;
-                }
-                break;
-
-            case TAG_ORIENTATION:
-                ImageInfoP->Orientation = 
-                    (int)ConvertAnyFormat(ValuePtr, Format);
-                if (ImageInfoP->Orientation < 1 || 
-                    ImageInfoP->Orientation > 8){
-                    pm_message("Undefined rotation value %d", 
-                               ImageInfoP->Orientation);
-                    ImageInfoP->Orientation = 0;
-                }
-                break;
+    case TAG_ISO_EQUIVALENT:
+        imageInfoP->ISOequivalent = 
+            (int)convertAnyFormat(valuePtr, format, byteOrder);
+        if ( imageInfoP->ISOequivalent < 50 ) 
+            imageInfoP->ISOequivalent *= 200;
+        break;
 
-            case TAG_EXIF_IMAGELENGTH:
-            case TAG_EXIF_IMAGEWIDTH:
-                /* Use largest of height and width to deal with images
-                   that have been rotated to portrait format.  
-                */
-                a = (int)ConvertAnyFormat(ValuePtr, Format);
-                if (ExifImageWidth < a) ExifImageWidth = a;
-                break;
-
-            case TAG_FOCALPLANEXRES:
-                HaveXRes = TRUE;
-                FocalplaneXRes = ConvertAnyFormat(ValuePtr, Format);
-                break;
-
-            case TAG_FOCALPLANEUNITS:
-                switch((int)ConvertAnyFormat(ValuePtr, Format)){
-                    case 1: FocalplaneUnits = 25.4; break; /* 1 inch */
-                    case 2: 
-                        /* According to the information I was using, 2
-                           means meters.  But looking at the Cannon
-                           powershot's files, inches is the only
-                           sensible value.  
-                        */
-                        FocalplaneUnits = 25.4;
-                        break;
+    case TAG_COMPRESSION_LEVEL:
+        imageInfoP->CompressionLevel = 
+            (int)convertAnyFormat(valuePtr, format, byteOrder);
+        break;
 
-                    case 3: FocalplaneUnits = 10;   break;  /* 1 centimeter*/
-                    case 4: FocalplaneUnits = 1;    break;  /* 1 millimeter*/
-                    case 5: FocalplaneUnits = .001; break;  /* 1 micrometer*/
-                }
-                break;
+    case TAG_THUMBNAIL_OFFSET:
+        *thumbnailOffsetP = (unsigned int)
+            convertAnyFormat(valuePtr, format, byteOrder);
+        break;
 
-                /* Remaining cases contributed by: Volker C. Schoech
-                   (schoech@gmx.de)
-                */
+    case TAG_THUMBNAIL_LENGTH:
+        *thumbnailSizeP = (unsigned int)
+            convertAnyFormat(valuePtr, format, byteOrder);
+        break;
 
-            case TAG_EXPOSURE_BIAS:
-                ImageInfoP->ExposureBias = 
-                    (float) ConvertAnyFormat(ValuePtr, Format);
-                break;
-
-            case TAG_WHITEBALANCE:
-                ImageInfoP->Whitebalance = 
-                    (int)ConvertAnyFormat(ValuePtr, Format);
-                break;
-
-            case TAG_METERING_MODE:
-                ImageInfoP->MeteringMode = 
-                    (int)ConvertAnyFormat(ValuePtr, Format);
-                break;
-
-            case TAG_EXPOSURE_PROGRAM:
-                ImageInfoP->ExposureProgram = 
-                    (int)ConvertAnyFormat(ValuePtr, Format);
-                break;
-
-            case TAG_ISO_EQUIVALENT:
-                ImageInfoP->ISOequivalent = 
-                    (int)ConvertAnyFormat(ValuePtr, Format);
-                if ( ImageInfoP->ISOequivalent < 50 ) 
-                    ImageInfoP->ISOequivalent *= 200;
-                break;
-
-            case TAG_COMPRESSION_LEVEL:
-                ImageInfoP->CompressionLevel = 
-                    (int)ConvertAnyFormat(ValuePtr, Format);
-                break;
-
-            case TAG_THUMBNAIL_OFFSET:
-                ThumbnailOffset = (unsigned)ConvertAnyFormat(ValuePtr, Format);
-                DirWithThumbnailPtrs = DirStart;
-                break;
-
-            case TAG_THUMBNAIL_LENGTH:
-                ThumbnailSize = (unsigned)ConvertAnyFormat(ValuePtr, Format);
-                break;
-
-            case TAG_EXIF_OFFSET:
-            case TAG_INTEROP_OFFSET:
-                {
-                    unsigned int const SubdirOffset  = Get32u(ValuePtr);
-                    if (SubdirOffset >= ExifLength)
-                        pm_message("Illegal exif or interop offset "
-                                   "directory link.  Offset is %u, "
-                                   "but Exif data is only %u bytes.",
-                                   SubdirOffset, ExifLength);
-                    else
-                        ProcessExifDir(ExifData, ExifLength, SubdirOffset, 
-                                       ImageInfoP, ShowTags, LastExifRefdP);
-                    continue;
-                }
-        }
+    case TAG_EXIF_OFFSET:
+    case TAG_INTEROP_OFFSET: {
+        unsigned int const subdirOffset = get32u(valuePtr, byteOrder);
+        if (subdirOffset >= exifLength)
+            pm_message("Illegal exif or interop offset "
+                       "directory link.  Offset is %u, "
+                       "but Exif data is only %u bytes.",
+                       subdirOffset, exifLength);
+        else
+            processExifDir(exifData, exifLength, subdirOffset, 
+                           imageInfoP, byteOrder, wantTagTrace,
+                           lastExifRefdP);
+    } break;
+    }
+}
+
+
+
+static void 
+processExifDir(const unsigned char *  const exifData, 
+               unsigned int           const exifLength,
+               unsigned int           const dirOffset,
+               exif_ImageInfo *       const imageInfoP, 
+               ByteOrder              const byteOrder,
+               bool                   const wantTagTrace,
+               const unsigned char ** const lastExifRefdP) {
+/*--------------------------------------------------------------------------
+   Process one of the nested EXIF directories.
+--------------------------------------------------------------------------*/
+    const unsigned char * const dirStart = exifData + dirOffset;
+    unsigned int const numDirEntries = get16u(&dirStart[0], byteOrder);
+    unsigned int de;
+    bool haveThumbnail;
+    unsigned int thumbnailOffset;
+    unsigned int thumbnailSize;
+
+    #define DIR_ENTRY_ADDR(Start, Entry) (Start+2+12*(Entry))
 
+    {
+        const unsigned char * const dirEnd =
+            DIR_ENTRY_ADDR(dirStart, numDirEntries);
+        if (dirEnd + 4 > (exifData + exifLength)){
+            if (dirEnd + 2 == exifData + exifLength || 
+                dirEnd == exifData + exifLength){
+                /* Version 1.3 of jhead would truncate a bit too much.
+                   This also caught later on as well.
+                */
+            }else{
+                /* Note: Files that had thumbnails trimmed with jhead
+                   1.3 or earlier might trigger this.
+                */
+                pm_message("Illegal directory entry size");
+                return;
+            }
+        }
+        *lastExifRefdP = MAX(*lastExifRefdP, dirEnd);
     }
 
+    if (wantTagTrace)
+        pm_message("Directory with %d entries", numDirEntries);
+
+    haveThumbnail   = false;  /* initial value */
+    thumbnailOffset = 0;      /* initial value */
+    thumbnailSize   = 0;      /* initial value */
+
+    for (de = 0; de < numDirEntries; ++de)
+        processDirEntry(DIR_ENTRY_ADDR(dirStart, de), exifData, exifLength,
+                        byteOrder, wantTagTrace, imageInfoP,
+                        &thumbnailOffset, &thumbnailSize, &haveThumbnail,
+                        lastExifRefdP);
+
+    if (haveThumbnail)
+        DirWithThumbnailPtrs = dirStart;
 
     {
         /* In addition to linking to subdirectories via exif tags,
@@ -706,28 +791,30 @@ ProcessExifDir(unsigned char *  const ExifData,
            of each directory.  This has got to be the result of a
            committee!  
         */
-        if (DIR_ENTRY_ADDR(DirStart, NumDirEntries) + 4 <= 
-            ExifData+ExifLength){
-            unsigned int const SubdirOffset =
-                Get32u(DirStart+2+12*NumDirEntries);
-            if (SubdirOffset){
-                unsigned char * const SubdirStart = ExifData + SubdirOffset;
-                if (SubdirStart > ExifData+ExifLength){
-                    if (SubdirStart < ExifData+ExifLength+20){
+        if (DIR_ENTRY_ADDR(dirStart, numDirEntries) + 4 <= 
+            exifData + exifLength){
+            unsigned int const subdirOffset =
+                get32u(dirStart + 2 + 12*numDirEntries, byteOrder);
+            if (subdirOffset){
+                const unsigned char * const subdirStart =
+                    exifData + subdirOffset;
+                if (subdirStart > exifData + exifLength){
+                    if (subdirStart < exifData + exifLength + 20){
                         /* Jhead 1.3 or earlier would crop the whole directory!
                            As Jhead produces this form of format incorrectness,
                            I'll just let it pass silently.
                         */
-                        if (ShowTags) 
+                        if (wantTagTrace) 
                             printf("Thumbnail removed with "
                                    "Jhead 1.3 or earlier\n");
                     }else{
                         pm_message("Illegal subdirectory link");
                     }
                 }else{
-                    if (SubdirOffset <= ExifLength)
-                        ProcessExifDir(ExifData, ExifLength, SubdirOffset,
-                                       ImageInfoP, ShowTags, LastExifRefdP);
+                    if (subdirOffset <= exifLength)
+                        processExifDir(exifData, exifLength, subdirOffset,
+                                       imageInfoP, byteOrder, wantTagTrace,
+                                       lastExifRefdP);
                 }
             }
         }else{
@@ -735,14 +822,14 @@ ProcessExifDir(unsigned char *  const ExifData,
         }
     }
 
-    if (ThumbnailSize && ThumbnailOffset){
-        if (ThumbnailSize + ThumbnailOffset <= ExifLength){
+    if (thumbnailSize && thumbnailOffset){
+        if (thumbnailSize + thumbnailOffset <= exifLength){
             /* The thumbnail pointer appears to be valid.  Store it. */
-            ImageInfoP->ThumbnailPointer = ExifData + ThumbnailOffset;
-            ImageInfoP->ThumbnailSize = ThumbnailSize;
+            imageInfoP->ThumbnailPointer = exifData + thumbnailOffset;
+            imageInfoP->ThumbnailSize = thumbnailSize;
 
-            if (ShowTags){
-                fprintf(stderr, "Thumbnail size: %d bytes\n",ThumbnailSize);
+            if (wantTagTrace){
+                fprintf(stderr, "Thumbnail size: %u bytes\n", thumbnailSize);
             }
         }
     }
@@ -751,56 +838,56 @@ ProcessExifDir(unsigned char *  const ExifData,
 
 
 void 
-process_EXIF(unsigned char * const ExifData,
-             unsigned int    const length,
-             ImageInfo_t *   const ImageInfoP, 
-             int             const ShowTags,
-             const char **   const errorP) {
+exif_parse(const unsigned char * const exifData,
+           unsigned int          const length,
+           exif_ImageInfo *      const imageInfoP, 
+           bool                  const wantTagTrace,
+           const char **         const errorP) {
 /*--------------------------------------------------------------------------
   Interpret an EXIF APP1 marker
 
-  'ExifData' is the actual Exif data; it does not include the
+  'exifData' is the actual Exif data; it does not include the
   "Exif" identifier and length field that often prefix Exif data.
 
   'length' is the length of the Exif section.
 --------------------------------------------------------------------------*/
+    ByteOrder byteOrder;
     int FirstOffset;
-    unsigned char * LastExifRefd;
+    const unsigned char * lastExifRefd;
 
     *errorP = NULL;  /* initial assumption */
 
-    if (ShowTags){
+    if (wantTagTrace)
         fprintf(stderr, "Exif header %d bytes long\n",length);
-    }
 
-    if (memcmp(ExifData+0,"II",2) == 0) {
-        if (ShowTags) 
+    if (MEMEQ(exifData + 0, "II" , 2)) {
+        if (wantTagTrace) 
             fprintf(stderr, "Exif header in Intel order\n");
-        MotorolaOrder = 0;
+        byteOrder = NORMAL;
     } else {
-        if (memcmp(ExifData+0, "MM", 2) == 0) {
-            if (ShowTags) 
+        if (MEMEQ(exifData + 0, "MM", 2)) {
+            if (wantTagTrace) 
                 fprintf(stderr, "Exif header in Motorola order\n");
-            MotorolaOrder = 1;
+            byteOrder = MOTOROLA;
         } else {
-            asprintfN(errorP, "Invalid alignment marker in Exif "
-                      "data.  First two bytes are '%c%c' (0x%02x%02x) "
-                      "instead of 'II' or 'MM'.", 
-                      ExifData[0], ExifData[1], ExifData[0], ExifData[1]);
+            pm_asprintf(errorP, "Invalid alignment marker in Exif "
+                        "data.  First two bytes are '%c%c' (0x%02x%02x) "
+                        "instead of 'II' or 'MM'.", 
+                        exifData[0], exifData[1], exifData[0], exifData[1]);
         }
     }
     if (!*errorP) {
-        unsigned short const start = Get16u(ExifData + 2);
+        unsigned short const start = get16u(exifData + 2, byteOrder);
         /* Check the next value for correctness. */
         if (start != 0x002a){
-            asprintfN(errorP, "Invalid Exif header start.  "
-                      "two bytes after the alignment marker "
-                      "should be 0x002a, but is 0x%04x",
-                      start);
+            pm_asprintf(errorP, "Invalid Exif header start.  "
+                        "two bytes after the alignment marker "
+                        "should be 0x002a, but is 0x%04x",
+                        start);
         }
     }
     if (!*errorP) {
-        FirstOffset = Get32u(ExifData + 4);
+        FirstOffset = get32u(exifData + 4, byteOrder);
         if (FirstOffset < 8 || FirstOffset > 16){
             /* I used to ensure this was set to 8 (website I used
                indicated its 8) but PENTAX Optio 230 has it set
@@ -809,51 +896,54 @@ process_EXIF(unsigned char * const ExifData,
             pm_message("Suspicious offset of first IFD value in Exif header");
         }
         
-        ImageInfoP->Comments[0] = '\0';  /* Initial value - null string */
+        imageInfoP->Comments[0] = '\0';  /* Initial value - null string */
         
         HaveXRes = FALSE;  /* Initial assumption */
         FocalplaneUnits = 0;
         ExifImageWidth = 0;
         
-        LastExifRefd = ExifData;
+        lastExifRefd = exifData;
         DirWithThumbnailPtrs = NULL;
         
-        ProcessExifDir(ExifData, length, FirstOffset, 
-                       ImageInfoP, ShowTags, &LastExifRefd);
+        processExifDir(exifData, length, FirstOffset, 
+                       imageInfoP, byteOrder, wantTagTrace, &lastExifRefd);
         
         /* Compute the CCD width, in millimeters. */
         if (HaveXRes){
-            ImageInfoP->HaveCCDWidth = 1;
-            ImageInfoP->CCDWidth = 
+            imageInfoP->HaveCCDWidth = 1;
+            imageInfoP->CCDWidth = 
                     (float)(ExifImageWidth * FocalplaneUnits / FocalplaneXRes);
         } else
-            ImageInfoP->HaveCCDWidth = 0;
+            imageInfoP->HaveCCDWidth = 0;
             
-        if (ShowTags){
+        if (wantTagTrace){
             fprintf(stderr, 
-                    "Non-settings part of Exif header: %d bytes\n",
-                    ExifData+length-LastExifRefd);
+                    "Non-settings part of Exif header: %lu bytes\n",
+                    (unsigned long)(exifData + length - lastExifRefd));
         }
     }
 }
 
+
+
+void 
+exif_showImageInfo(const exif_ImageInfo * const imageInfoP,
+                   FILE *                 const fileP) {
 /*--------------------------------------------------------------------------
    Show the collected image info, displaying camera F-stop and shutter
    speed in a consistent and legible fashion.
 --------------------------------------------------------------------------*/
-void 
-ShowImageInfo(ImageInfo_t * const ImageInfoP)
-{
-    if (ImageInfoP->CameraMake[0]){
-        fprintf(stderr, "Camera make  : %s\n",ImageInfoP->CameraMake);
-        fprintf(stderr, "Camera model : %s\n",ImageInfoP->CameraModel);
+    if (imageInfoP->CameraMake[0]) {
+        fprintf(fileP, "Camera make  : %s\n", imageInfoP->CameraMake);
+        fprintf(fileP, "Camera model : %s\n", imageInfoP->CameraModel);
     }
-    if (ImageInfoP->DateTime[0]){
-        fprintf(stderr, "Date/Time    : %s\n",ImageInfoP->DateTime);
-    }
-    fprintf(stderr, "Resolution   : %f x %f\n",
-            ImageInfoP->XResolution, ImageInfoP->YResolution);
-    if (ImageInfoP->Orientation > 1){
+    if (imageInfoP->DateTime[0])
+        fprintf(fileP, "Date/Time    : %s\n", imageInfoP->DateTime);
+
+    fprintf(fileP, "Resolution   : %f x %f\n",
+            imageInfoP->XResolution, imageInfoP->YResolution);
+
+    if (imageInfoP->Orientation > 1) {
 
         /* Only print orientation if one was supplied, and if its not
            1 (normal orientation)
@@ -890,154 +980,144 @@ ShowImageInfo(ImageInfo_t * const ImageInfoP)
             "rotate 270",       /* rotate 270 to right it. */
         };
 
-        fprintf(stderr, "Orientation  : %s\n", 
-                OrientTab[ImageInfoP->Orientation]);
+        fprintf(fileP, "Orientation  : %s\n", 
+                OrientTab[imageInfoP->Orientation]);
     }
 
-    if (ImageInfoP->IsColor == 0){
-        fprintf(stderr, "Color/bw     : Black and white\n");
-    }
-    if (ImageInfoP->FlashUsed >= 0){
-        fprintf(stderr, "Flash used   : %s\n",
-                ImageInfoP->FlashUsed ? "Yes" :"No");
-    }
-    if (ImageInfoP->FocalLength){
-        fprintf(stderr, "Focal length : %4.1fmm",
-                (double)ImageInfoP->FocalLength);
-        if (ImageInfoP->HaveCCDWidth){
-            fprintf(stderr, "  (35mm equivalent: %dmm)",
+    if (imageInfoP->IsColor == 0)
+        fprintf(fileP, "Color/bw     : Black and white\n");
+
+    if (imageInfoP->FlashUsed >= 0)
+        fprintf(fileP, "Flash used   : %s\n",
+                imageInfoP->FlashUsed ? "Yes" :"No");
+
+    if (imageInfoP->FocalLength) {
+        fprintf(fileP, "Focal length : %4.1fmm",
+                (double)imageInfoP->FocalLength);
+        if (imageInfoP->HaveCCDWidth){
+            fprintf(fileP, "  (35mm equivalent: %dmm)",
                     (int)
-                    (ImageInfoP->FocalLength/ImageInfoP->CCDWidth*36 + 0.5));
+                    (imageInfoP->FocalLength/imageInfoP->CCDWidth*36 + 0.5));
         }
-        fprintf(stderr, "\n");
+        fprintf(fileP, "\n");
     }
 
-    if (ImageInfoP->HaveCCDWidth){
-        fprintf(stderr, "CCD width    : %2.4fmm\n",
-                (double)ImageInfoP->CCDWidth);
-    }
+    if (imageInfoP->HaveCCDWidth)
+        fprintf(fileP, "CCD width    : %2.4fmm\n",
+                (double)imageInfoP->CCDWidth);
 
-    if (ImageInfoP->ExposureTime){ 
-        if (ImageInfoP->ExposureTime < 0.010){
-            fprintf(stderr, 
+    if (imageInfoP->ExposureTime) {
+        if (imageInfoP->ExposureTime < 0.010){
+            fprintf(fileP, 
                     "Exposure time: %6.4f s ",
-                    (double)ImageInfoP->ExposureTime);
+                    (double)imageInfoP->ExposureTime);
         }else{
-            fprintf(stderr, 
+            fprintf(fileP, 
                     "Exposure time: %5.3f s ",
-                    (double)ImageInfoP->ExposureTime);
+                    (double)imageInfoP->ExposureTime);
         }
-        if (ImageInfoP->ExposureTime <= 0.5){
-            fprintf(stderr, " (1/%d)",(int)(0.5 + 1/ImageInfoP->ExposureTime));
+        if (imageInfoP->ExposureTime <= 0.5){
+            fprintf(fileP, " (1/%d)",(int)(0.5 + 1/imageInfoP->ExposureTime));
         }
-        fprintf(stderr, "\n");
+        fprintf(fileP, "\n");
     }
-    if (ImageInfoP->ApertureFNumber){
-        fprintf(stderr, "Aperture     : f/%3.1f\n",
-                (double)ImageInfoP->ApertureFNumber);
+    if (imageInfoP->ApertureFNumber){
+        fprintf(fileP, "Aperture     : f/%3.1f\n",
+                (double)imageInfoP->ApertureFNumber);
     }
-    if (ImageInfoP->Distance){
-        if (ImageInfoP->Distance < 0){
-            fprintf(stderr, "Focus dist.  : Infinite\n");
+    if (imageInfoP->Distance){
+        if (imageInfoP->Distance < 0){
+            fprintf(fileP, "Focus dist.  : Infinite\n");
         }else{
-            fprintf(stderr, "Focus dist.  :%5.2fm\n",
-                    (double)ImageInfoP->Distance);
+            fprintf(fileP, "Focus dist.  :%5.2fm\n",
+                    (double)imageInfoP->Distance);
         }
     }
 
-
-
-
-
-    if (ImageInfoP->ISOequivalent){ /* 05-jan-2001 vcs */
-        fprintf(stderr, "ISO equiv.   : %2d\n",(int)ImageInfoP->ISOequivalent);
+    if (imageInfoP->ISOequivalent){ /* 05-jan-2001 vcs */
+        fprintf(fileP, "ISO equiv.   : %2d\n",(int)imageInfoP->ISOequivalent);
     }
-    if (ImageInfoP->ExposureBias){ /* 05-jan-2001 vcs */
-        fprintf(stderr, "Exposure bias:%4.2f\n",
-                (double)ImageInfoP->ExposureBias);
+    if (imageInfoP->ExposureBias){ /* 05-jan-2001 vcs */
+        fprintf(fileP, "Exposure bias:%4.2f\n",
+                (double)imageInfoP->ExposureBias);
     }
         
-    if (ImageInfoP->Whitebalance){ /* 05-jan-2001 vcs */
-        switch(ImageInfoP->Whitebalance) {
+    if (imageInfoP->Whitebalance){ /* 05-jan-2001 vcs */
+        switch(imageInfoP->Whitebalance) {
         case 1:
-            fprintf(stderr, "Whitebalance : sunny\n");
+            fprintf(fileP, "Whitebalance : sunny\n");
             break;
         case 2:
-            fprintf(stderr, "Whitebalance : fluorescent\n");
+            fprintf(fileP, "Whitebalance : fluorescent\n");
             break;
         case 3:
-            fprintf(stderr, "Whitebalance : incandescent\n");
+            fprintf(fileP, "Whitebalance : incandescent\n");
             break;
         default:
-            fprintf(stderr, "Whitebalance : cloudy\n");
+            fprintf(fileP, "Whitebalance : cloudy\n");
         }
     }
-    if (ImageInfoP->MeteringMode){ /* 05-jan-2001 vcs */
-        switch(ImageInfoP->MeteringMode) {
+    if (imageInfoP->MeteringMode){ /* 05-jan-2001 vcs */
+        switch(imageInfoP->MeteringMode) {
         case 2:
-            fprintf(stderr, "Metering Mode: center weight\n");
+            fprintf(fileP, "Metering Mode: center weight\n");
             break;
         case 3:
-            fprintf(stderr, "Metering Mode: spot\n");
+            fprintf(fileP, "Metering Mode: spot\n");
             break;
         case 5:
-            fprintf(stderr, "Metering Mode: matrix\n");
+            fprintf(fileP, "Metering Mode: matrix\n");
             break;
         }
     }
-    if (ImageInfoP->ExposureProgram){ /* 05-jan-2001 vcs */
-        switch(ImageInfoP->ExposureProgram) {
+    if (imageInfoP->ExposureProgram){ /* 05-jan-2001 vcs */
+        switch(imageInfoP->ExposureProgram) {
         case 2:
-            fprintf(stderr, "Exposure     : program (auto)\n");
+            fprintf(fileP, "Exposure     : program (auto)\n");
             break;
         case 3:
-            fprintf(stderr, "Exposure     : aperture priority (semi-auto)\n");
+            fprintf(fileP, "Exposure     : aperture priority (semi-auto)\n");
             break;
         case 4:
-            fprintf(stderr, "Exposure     : shutter priority (semi-auto)\n");
+            fprintf(fileP, "Exposure     : shutter priority (semi-auto)\n");
             break;
         }
     }
-    if (ImageInfoP->CompressionLevel){ /* 05-jan-2001 vcs */
-        switch(ImageInfoP->CompressionLevel) {
+    if (imageInfoP->CompressionLevel){ /* 05-jan-2001 vcs */
+        switch(imageInfoP->CompressionLevel) {
         case 1:
-            fprintf(stderr, "Jpeg Quality  : basic\n");
+            fprintf(fileP, "Jpeg Quality  : basic\n");
             break;
         case 2:
-            fprintf(stderr, "Jpeg Quality  : normal\n");
+            fprintf(fileP, "Jpeg Quality  : normal\n");
             break;
         case 4:
-            fprintf(stderr, "Jpeg Quality  : fine\n");
+            fprintf(fileP, "Jpeg Quality  : fine\n");
             break;
        }
     }
 
-         
-
     /* Print the comment. Print 'Comment:' for each new line of comment. */
-    if (ImageInfoP->Comments[0]){
-        int a,c;
-        fprintf(stderr, "Comment      : ");
-        for (a=0;a<MAX_COMMENT;a++){
-            c = ImageInfoP->Comments[a];
-            if (c == '\0') break;
+    if (imageInfoP->Comments[0]) {
+        unsigned int a;
+
+        fprintf(fileP, "Comment      : ");
+
+        for (a = 0; a < MAX_COMMENT && imageInfoP->Comments[a]; ++a) {
+            char const c = imageInfoP->Comments[a];
             if (c == '\n'){
                 /* Do not start a new line if the string ends with a cr */
-                if (ImageInfoP->Comments[a+1] != '\0'){
-                    fprintf(stderr, "\nComment      : ");
-                }else{
-                    fprintf(stderr, "\n");
-                }
-            }else{
-                putc(c, stderr);
-            }
+                if (imageInfoP->Comments[a+1] != '\0')
+                    fprintf(fileP, "\nComment      : ");
+                else
+                    fprintf(fileP, "\n");
+            } else
+                putc(c, fileP);
         }
-        fprintf(stderr, "\n");
+        fprintf(fileP, "\n");
     }
 
-    fprintf(stderr, "\n");
+    fprintf(fileP, "\n");
 }
 
 
-
-
diff --git a/converter/other/exif.h b/converter/other/exif.h
index 4630988f..57eb745b 100644
--- a/converter/other/exif.h
+++ b/converter/other/exif.h
@@ -1,9 +1,12 @@
 #ifndef EXIF_H_INCLUDED
 #define EXIF_H_INCLUDED
 
+#include <stdio.h>
+#include "netpbm/pm_c_util.h"
+
 #define MAX_COMMENT 2000
 
-#ifdef _WIN32
+#if MSVCRT
     #define PATH_MAX _MAX_PATH
 #endif
 
@@ -35,23 +38,24 @@ typedef struct {
     int   CompressionLevel;
     char  Comments[MAX_COMMENT];
 
-    unsigned char * ThumbnailPointer;  /* Pointer at the thumbnail */
+    const unsigned char * ThumbnailPointer;  /* Pointer at the thumbnail */
     unsigned ThumbnailSize;     /* Size of thumbnail. */
 
-    char * DatePointer;
-}ImageInfo_t;
+    const char * DatePointer;
+} exif_ImageInfo;
 
 
 /* Prototypes for exif.c functions. */
 
 void 
-process_EXIF(unsigned char * const ExifSection, 
-             unsigned int    const length,
-             ImageInfo_t *   const ImageInfoP, 
-             int             const ShowTags,
-             const char **   const errorP);
+exif_parse(const unsigned char * const exifSection, 
+           unsigned int          const length,
+           exif_ImageInfo *      const imageInfoP, 
+           bool                  const wantTagTrace,
+           const char **         const errorP);
 
 void 
-ShowImageInfo(ImageInfo_t * const ImageInfoP);
+exif_showImageInfo(const exif_ImageInfo * const imageInfoP,
+                   FILE *                 const fileP);
 
 #endif
diff --git a/converter/other/fiasco/Makefile b/converter/other/fiasco/Makefile
index 16221d77..392e843c 100644
--- a/converter/other/fiasco/Makefile
+++ b/converter/other/fiasco/Makefile
@@ -11,8 +11,9 @@ COMP_INCLUDES = \
 	-I$(SRCDIR)/$(SUBDIR)/codec -I$(SRCDIR)/$(SUBDIR)/input \
 	-I$(SRCDIR)/$(SUBDIR)/output -I$(SRCDIR)/$(SUBDIR)/lib \
 
-BINARIES = pnmtofiasco fiascotopnm
+PORTBINARIES = pnmtofiasco fiascotopnm
 
+BINARIES = $(PORTBINARIES)
 MERGEBINARIES = $(BINARIES)
 
 SCRIPTS =
@@ -24,21 +25,18 @@ FIASCOLIBS = codec/libfiasco_codec.a \
 	     output/libfiasco_output.a \
 	     lib/libfiasco_lib.a 
 
-COMMON_OBJECTS = binerror.o getopt.o getopt1.o params.o
+ADDL_OBJECTS = binerror.o getopt.o getopt1.o params.o
 
-OBJECTS = $(BINARIES:%=%.o) $(COMMON_OBJECTS)
+OBJECTS = $(BINARIES:%=%.o) $(ADDL_OBJECTS)
 
-MERGE_OBJECTS = $(BINARIES:%=%.o2) $(COMMON_OBJECTS)  $(FIASCOLIBS)
+MERGE_OBJECTS = $(BINARIES:%=%.o2) $(ADDL_OBJECTS) $(FIASCOLIBS)
 
 SUBDIRS = codec input output lib
 
 include $(SRCDIR)/common.mk
 
-$(BINARIES):%:%.o $(COMMON_OBJECTS) $(FIASCOLIBS) $(NETPBMLIB) \
-   $(LIBOPT)
-	$(LD) -o $@ $< $(COMMON_OBJECTS) \
-	$(shell $(LIBOPT) $(FIASCOLIBS) $(NETPBMLIB)) $(MATHLIB) \
-	$(LDFLAGS) $(LDLIBS) $(RPATH) $(LADD)
+$(BINARIES):%:%.o $(ADDL_OBJECTS) $(FIASCOLIBS)
+$(BINARIES): LDFLAGS_TARGET = $(shell $(LIBOPT) $(FIASCOLIBS))
 
 codec/libfiasco_codec.a: $(BUILDDIR)/$(SUBDIR)/codec FORCE
 	$(MAKE) -C codec -f $(SRCDIR)/$(SUBDIR)/codec/Makefile \
diff --git a/converter/other/fiasco/binerror.c b/converter/other/fiasco/binerror.c
index 8a41a214..77243c64 100644
--- a/converter/other/fiasco/binerror.c
+++ b/converter/other/fiasco/binerror.c
@@ -92,11 +92,7 @@ _error (const char *format, ...)
 
    fprintf (stderr, "%s: %s: line %d:\nError: ",
 	    executable, error_file, error_line);
-#if HAVE_VPRINTF
    vfprintf (stderr, format, args);
-#elif HAVE_DOPRNT
-   _doprnt (format, args, stderr);
-#endif /* HAVE_DOPRNT */
    fputc ('\n', stderr);
    va_end(args);
 
@@ -132,11 +128,7 @@ _warning (const char *format, ...)
 
    fprintf (stderr, "%s: %s: line %d:\nWarning: ",
 	    executable, error_file, error_line);
-#if HAVE_VPRINTF
    vfprintf (stderr, format, args);
-#elif HAVE_DOPRNT
-   _doprnt (format, args, stderr);
-#endif /* HAVE_DOPRNT */
    fputc ('\n', stderr);
 
    va_end (args);
diff --git a/converter/other/fiasco/codec/approx.c b/converter/other/fiasco/codec/approx.c
index 72e38cbf..5072fae3 100644
--- a/converter/other/fiasco/codec/approx.c
+++ b/converter/other/fiasco/codec/approx.c
@@ -294,7 +294,7 @@ static real_t ip_domain_ortho_vector [MAXSTATES][MAXEDGES];
 static real_t rem_denominator [MAXSTATES];     
 static real_t rem_numerator [MAXSTATES];
 /*
- *  At step n of the orthogonalization the comparitive value
+ *  At step n of the orthogonalization the comparative value
  *  (numerator_i / denominator_i):= <b, o_n>^2 / ||o_n|| ,
  *  is computed for every domain i,
  *  where o_n := s_i - \sum(k = 0, ... , n-1) {(<s_i, o_k> / ||o_k||^2) o_k}
@@ -670,7 +670,7 @@ orthogonalize (unsigned index, unsigned n, unsigned level, real_t min_norm,
     *  for (i = 0, ... , wfa->states)  
     *  <s_i, o_n> := <s_i, v_n> -
     *      \sum (k = 0, ... , n - 1){ <v_n, o_k> <s_i, o_k> / ||o_k||^2}
-    *  Moreover the denominator and numerator parts of the comparitive
+    *  Moreover the denominator and numerator parts of the comparative
     *  value are updated.
     */
    for (domain = 0; domain_blocks [domain] >= 0; domain++) 
diff --git a/converter/other/fiasco/codec/coder.c b/converter/other/fiasco/codec/coder.c
index 927ebbda..94e367dd 100644
--- a/converter/other/fiasco/codec/coder.c
+++ b/converter/other/fiasco/codec/coder.c
@@ -252,14 +252,14 @@ alloc_coder (char const * const * const inputname,
         lx = (unsigned) (log2 (wi->width - 1) + 1);
         ly = (unsigned) (log2 (wi->height - 1) + 1);
       
-        wi->level = max (lx, ly) * 2 - ((ly == lx + 1) ? 1 : 0);
+        wi->level = MAX(lx, ly) * 2 - ((ly == lx + 1) ? 1 : 0);
     }
    
     c = Calloc (1, sizeof (coding_t));
 
     c->options             = *options;
-    c->options.lc_min_level = max (options->lc_min_level, 3);
-    c->options.lc_max_level = min (options->lc_max_level, wi->level - 1);
+    c->options.lc_min_level = MAX(options->lc_min_level, 3);
+    c->options.lc_max_level = MIN(options->lc_max_level, wi->level - 1);
 
     c->tiling = alloc_tiling (options->tiling_method,
                               options->tiling_exponent, wi->level);
@@ -273,7 +273,7 @@ alloc_coder (char const * const * const inputname,
     if (c->options.lc_max_level >= wi->level - c->tiling->exponent)
     {
         message ("'max_level' changed from %d to %d "
-                 "due to image tiling level.",
+                 "because of image tiling level.",
                  c->options.lc_max_level, wi->level - c->tiling->exponent - 1);
         c->options.lc_max_level = wi->level - c->tiling->exponent - 1;
     }
@@ -285,16 +285,16 @@ alloc_coder (char const * const * const inputname,
      *  p_min_level, p_max_level min and max level for ND/MC prediction
      *  [p_min_level, p_max_level] must be a subset of [min_level, max_level] !
      */
-    wi->p_min_level = max (options->p_min_level, c->options.lc_min_level);
-    wi->p_max_level = min (options->p_max_level, c->options.lc_max_level);
+    wi->p_min_level = MAX(options->p_min_level, c->options.lc_min_level);
+    wi->p_max_level = MIN(options->p_max_level, c->options.lc_max_level);
     if (wi->p_min_level > wi->p_max_level)
         wi->p_min_level = wi->p_max_level;
 
-    c->options.images_level = min (c->options.images_level,
-                                   c->options.lc_max_level - 1);
+    c->options.images_level = MIN(c->options.images_level,
+                                  c->options.lc_max_level - 1);
    
-    c->products_level  = max (0, ((signed int) c->options.lc_max_level
-                                  - (signed int) c->options.images_level - 1));
+    c->products_level  = MAX(0, ((signed int) c->options.lc_max_level
+                                 - (signed int) c->options.images_level - 1));
     c->pixels         = Calloc (size_of_level (c->options.lc_max_level),
                                 sizeof (real_t));
     c->images_of_state = Calloc (MAXSTATES, sizeof (real_t *));
@@ -324,8 +324,8 @@ alloc_coder (char const * const * const inputname,
     /*
      *  Max. number of states and edges
      */
-    wi->max_states         = max (min (options->max_states, MAXSTATES), 1);
-    c->options.max_elements = max (min (options->max_elements, MAXEDGES), 1);
+    wi->max_states          = MAX(MIN(options->max_states, MAXSTATES), 1);
+    c->options.max_elements = MAX(MIN(options->max_elements, MAXEDGES), 1);
 
     /*
      *  Title and comment strings
@@ -348,7 +348,7 @@ alloc_coder (char const * const * const inputname,
     /*
      *  Color image options ...
      */
-    wi->chroma_max_states = max (1, options->chroma_max_states);
+    wi->chroma_max_states = MAX(1, options->chroma_max_states);
 
     /*
     *  Set up motion compensation struct.
@@ -432,9 +432,9 @@ print_statistics (char c, real_t costs, const wfa_t *wfa, const image_t *image,
      
       if (lincomb)
       {
-     max_level = max (max_level,
+     max_level = MAX(max_level,
               (unsigned) (wfa->level_of_state [state] - 1));
-     min_level = min (min_level,
+     min_level = MIN(min_level,
               (unsigned) (wfa->level_of_state [state] - 1));
       }
    }
@@ -548,77 +548,78 @@ frame_coder (wfa_t *wfa, coding_t *c, bitfile_t *output)
    }
    else
    {
-      int     YCb_node = -1;
-      int     tree [3];         /* 3 root states of each color comp. */
-      color_e band;
+       int     YCb_node = -1;
+       int     tree [3];         /* 3 root states of each color comp. */
+       color_e band;
       
-      /*
-       *  When compressing color images, the three color components (YCbCr) 
-       *  are copied into a large image:
-       *  [  Y  Cr ]
-       *  [  Cb 0  ]
-       *  I.e. the color components of an image are processed in a row.
-       *  After all components are compressed, virtual states are generated
-       *  to describe the large image.
-       */
-      for (band = first_band (YES); band <= last_band (YES) ; band++)
-      {
-     debug_message ("Encoding color component %d", band);
-     tree [band] = RANGE;
-     if (band == Cb)
-     {
-        unsigned min_level;
-
-        c->domain_pool->chroma (wfa->wfainfo->chroma_max_states, wfa,
-                    c->domain_pool->model);
-        /*
-         *  Don't use a finer partioning for the chrominancy bands than for
-         *  the luminancy band.
-         */
-        for (min_level = MAXLEVEL, state = wfa->basis_states;
-         state < wfa->states; state++)
-        {
-           unsigned lincomb, label;
+       /*
+        *  When compressing color images, the three color components (YCbCr) 
+        *  are copied into a large image:
+        *  [  Y  Cr ]
+        *  [  Cb 0  ]
+        *  I.e. the color components of an image are processed in a row.
+        *  After all components are compressed, virtual states are generated
+        *  to describe the large image.
+        */
+       for (band = first_band (YES); band <= last_band (YES) ; band++)
+       {
+           debug_message ("Encoding color component %d", band);
+           tree [band] = RANGE;
+           if (band == Cb)
+           {
+               unsigned min_level;
+
+               c->domain_pool->chroma (wfa->wfainfo->chroma_max_states, wfa,
+                                       c->domain_pool->model);
+               /*
+                *  Don't use a finer partioning for the chrominancy bands than
+                *  for the luminancy band.
+                */
+               for (min_level = MAXLEVEL, state = wfa->basis_states;
+                    state < wfa->states; state++)
+               {
+                   unsigned lincomb, label;
            
-           for (lincomb = 0, label = 0; label < MAXLABELS; label++)
-          lincomb += isrange (wfa->tree [state][label]) ? 1 : 0;
-           if (lincomb)
-          min_level = min (min_level,
-                   (unsigned) (wfa->level_of_state [state]
-                           - 1));
-        }
-        c->options.lc_min_level = min_level;
-        if (c->mt->frame_type != I_FRAME) /* subtract mc of luminance */
-           subtract_mc (c->mt->original, c->mt->past, c->mt->future, wfa);
-     }
-
-     memset (&range, 0, sizeof (range_t));
-     range.level = wfa->wfainfo->level;
+                   for (lincomb = 0, label = 0; label < MAXLABELS; label++)
+                       lincomb += isrange (wfa->tree [state][label]) ? 1 : 0;
+                   if (lincomb)
+                       min_level = MIN(min_level,
+                                       (unsigned) (wfa->level_of_state [state]
+                                                   - 1));
+               }
+               c->options.lc_min_level = min_level;
+               if (c->mt->frame_type != I_FRAME) /* subtract mc of luminance */
+                   subtract_mc (c->mt->original, c->mt->past, c->mt->future,
+                                wfa);
+           }
+
+           memset (&range, 0, sizeof (range_t));
+           range.level = wfa->wfainfo->level;
      
-     costs = subdivide (MAXCOSTS, band, tree [Y], &range, wfa, c,
-                c->mt->frame_type != I_FRAME && band == Y, NO);
-     if (c->options.progress_meter != FIASCO_PROGRESS_NONE)
-        message ("");
-     {
-        char colors [] = {'Y', 'B', 'R'};
+           costs = subdivide (MAXCOSTS, band, tree [Y], &range, wfa, c,
+                              c->mt->frame_type != I_FRAME && band == Y, NO);
+           if (c->options.progress_meter != FIASCO_PROGRESS_NONE)
+               message ("");
+           {
+               char colors [] = {'Y', 'B', 'R'};
         
-        print_statistics (colors [band], costs, wfa,
-                  c->mt->original, &range);
-     }
+               print_statistics (colors [band], costs, wfa,
+                                 c->mt->original, &range);
+           }
      
-     if (isrange (range.tree))  /* whole image is approx. by a l.c. */
-        error ("No root state generated for color component %d!", band);
-     else
-        tree[band] = range.tree;
+           if (isrange (range.tree))  /* whole image is approx. by a l.c. */
+               error ("No root state generated for color component %d!", band);
+           else
+               tree[band] = range.tree;
      
-     if (band == Cb)
-     {
-        wfa->tree [wfa->states][0] = tree[Y];
-        wfa->tree [wfa->states][1] = tree[Cb];
-        YCb_node = wfa->states;
-        append_state (YES, compute_final_distribution (wfa->states, wfa),
-              wfa->wfainfo->level + 1, wfa, c);
-     }
+           if (band == Cb)
+           {
+               wfa->tree [wfa->states][0] = tree[Y];
+               wfa->tree [wfa->states][1] = tree[Cb];
+               YCb_node = wfa->states;
+               append_state (YES, compute_final_distribution(wfa->states, wfa),
+                             wfa->wfainfo->level + 1, wfa, c);
+           }
       }
       /*
        *  generate two virtual states (*) 
diff --git a/converter/other/fiasco/codec/control.c b/converter/other/fiasco/codec/control.c
index 9af9928b..94c23c83 100644
--- a/converter/other/fiasco/codec/control.c
+++ b/converter/other/fiasco/codec/control.c
@@ -16,11 +16,7 @@
 
 #include "config.h"
 
-#if HAVE_STRING_H
-#	include <string.h>
-#else /* not HAVE_STRING_H */
-#	include <strings.h>
-#endif /* not HAVE_STRING_H */
+#include <string.h>
  
 #include "types.h"
 #include "macros.h"
diff --git a/converter/other/fiasco/codec/decoder.c b/converter/other/fiasco/codec/decoder.c
index 77d5340f..26284596 100644
--- a/converter/other/fiasco/codec/decoder.c
+++ b/converter/other/fiasco/codec/decoder.c
@@ -1,9 +1,9 @@
 /*
- *  decode.c:		Decoding of an image represented by a WFA
+ *  decode.c:       Decoding of an image represented by a WFA
  *
- *  Written by:		Ullrich Hafner
- *			Michael Unger
- *		
+ *  Written by:     Ullrich Hafner
+ *          Michael Unger
+ *      
  *  This file is part of FIASCO («F»ractal «I»mage «A»nd «S»equence «CO»dec)
  *  Copyright (C) 1994-2000 Ullrich Hafner <hafner@bigfoot.de>
  */
@@ -15,13 +15,12 @@
  *  $State: Exp $
  */
 
+#include "pm_config.h"
 #include "config.h"
 
-#if HAVE_STRING_H
-#	include <string.h>
-#else /* not HAVE_STRING_H */
-#	include <strings.h>
-#endif /* not HAVE_STRING_H */
+#include <string.h>
+
+#include "pm_c_util.h"
 
 #include "types.h"
 #include "macros.h"
@@ -37,33 +36,33 @@
 
 /*****************************************************************************
 
-				prototypes
+                prototypes
   
 *****************************************************************************/
 
 static void
 compute_state_images (unsigned frame_level, word_t **simg,
-		      const u_word_t *offset, const wfa_t *wfa);
+              const u_word_t *offset, const wfa_t *wfa);
 static void
 free_state_images (unsigned max_level, bool_t color, word_t **state_image,
-		   u_word_t *offset, const unsigned *root_state,
-		   unsigned range_state, format_e format, const wfa_t *wfa);
+           u_word_t *offset, const unsigned *root_state,
+           unsigned range_state, format_e format, const wfa_t *wfa);
 static void
 alloc_state_images (word_t ***images, u_word_t **offsets, const image_t *frame,
-		    const unsigned *root_state, unsigned range_state,
-		    unsigned max_level, format_e format, const wfa_t *wfa);
+            const unsigned *root_state, unsigned range_state,
+            unsigned max_level, format_e format, const wfa_t *wfa);
 static void
 compute_actual_size (unsigned luminance_root,
-		     unsigned *width, unsigned *height, const wfa_t *wfa);
+             unsigned *width, unsigned *height, const wfa_t *wfa);
 static void
 enlarge_image (int enlarge_factor, format_e format, unsigned y_root,
-	       wfa_t *wfa);
+           wfa_t *wfa);
 static word_t *
 duplicate_state_image (const word_t *domain, unsigned offset, unsigned level);
 
 /*****************************************************************************
 
-				public code
+                public code
   
 *****************************************************************************/
 
@@ -75,7 +74,7 @@ alloc_video (bool_t store_wfa)
  *  and future WFA if flag 'store_wfa' is TRUE.
  *
  *  Return value:
- *	pointer to the new video structure
+ *  pointer to the new video structure
  */
 {
    video_t *video = Calloc (1, sizeof (video_t));
@@ -84,7 +83,7 @@ alloc_video (bool_t store_wfa)
    video->display        = 0;
 
    video->future = video->sfuture = video->past
-		 = video->frame   = video->sframe = NULL;
+         = video->frame   = video->sframe = NULL;
 
    if (store_wfa)
    {
@@ -107,7 +106,7 @@ free_video (video_t *video)
  *  No return value.
  *
  *  Side effects:
- *	'video' struct is discarded.
+ *  'video' struct is discarded.
  */
 {
    if (video->past)
@@ -132,9 +131,9 @@ free_video (video_t *video)
 
 image_t *
 get_next_frame (bool_t store_wfa, int enlarge_factor,
-		int smoothing, const char *reference_frame,
-		format_e format, video_t *video, dectimer_t *timer,
-		wfa_t *orig_wfa, bitfile_t *input)
+        int smoothing, const char *reference_frame,
+        format_e format, video_t *video, dectimer_t *timer,
+        wfa_t *orig_wfa, bitfile_t *input)
 /*
  *  Get next frame of the WFA 'video' from stream 'input'.
  *  'orig_wfa' is the constant part of the WFA used by all frames.
@@ -148,265 +147,265 @@ get_next_frame (bool_t store_wfa, int enlarge_factor,
  *  If 'timer' is not NULL, then accumulate running time statistics. 
  *
  *  Return value:
- *	pointer to decoded frame
+ *  pointer to decoded frame
  *
  *  Side effects:
- *	'video' and 'timer' struct are modified.
+ *  'video' and 'timer' struct are modified.
  */
 {
-   image_t *frame 			  = NULL; /* current frame */
-   image_t *sframe 			  = NULL; /* current smoothed frame */
+   image_t *frame             = NULL; /* current frame */
+   image_t *sframe            = NULL; /* current smoothed frame */
    bool_t   current_frame_is_future_frame = NO;
 
-   if (video->future_display == video->display)	 
+   if (video->future_display == video->display)  
    {
       /*
        *  Future frame is already computed since it has been used
        *  as reference frame. So just return the stored frame.
        */
       if (video->frame) /* discard current frame */
-	 free_image (video->frame);
+     free_image (video->frame);
       video->frame  = video->future;
       video->future = NULL;
 
       if (video->sframe) /* discard current (smoothed) frame */
-	 free_image (video->sframe);
+     free_image (video->sframe);
       video->sframe  = video->sfuture;
       video->sfuture = NULL;
 
       if (store_wfa)
-	 copy_wfa (video->wfa, video->wfa_future);
+     copy_wfa (video->wfa, video->wfa_future);
 
       video->display++;
 
       if (!store_wfa)
-	 video->wfa = NULL;
+     video->wfa = NULL;
    }
    else
    {
-      do				/* compute next frame(s) */
+      do                /* compute next frame(s) */
       {
-	 unsigned      frame_number;	/* current frame number */
-	 clock_t       ptimer;
-	 unsigned int  stop_timer [3];
-	 wfa_t	      *tmp_wfa = NULL;
-	 
-	 if (!store_wfa)
-	    video->wfa = orig_wfa;
-	 else
-	 {
-	    tmp_wfa = alloc_wfa (NO);
-	    copy_wfa (tmp_wfa, video->wfa);
-	    copy_wfa (video->wfa, orig_wfa);
-	 }
+     unsigned      frame_number;    /* current frame number */
+     clock_t       ptimer;
+     unsigned int  stop_timer [3];
+     wfa_t        *tmp_wfa = NULL;
+     
+     if (!store_wfa)
+        video->wfa = orig_wfa;
+     else
+     {
+        tmp_wfa = alloc_wfa (NO);
+        copy_wfa (tmp_wfa, video->wfa);
+        copy_wfa (video->wfa, orig_wfa);
+     }
    
-	 /*
-	  *  First step: read WFA from disk
-	  */
-	 prg_timer (&ptimer, START);
-	 frame_number = read_next_wfa (video->wfa, input);
-	 stop_timer [0] = prg_timer (&ptimer, STOP);
-	 if (timer)
-	 {
-	    timer->input [video->wfa->frame_type] += stop_timer [0];
-	    timer->frames [video->wfa->frame_type]++;
-	 }
+     /*
+      *  First step: read WFA from disk
+      */
+     prg_timer (&ptimer, START);
+     frame_number = read_next_wfa (video->wfa, input);
+     stop_timer [0] = prg_timer (&ptimer, STOP);
+     if (timer)
+     {
+        timer->input [video->wfa->frame_type] += stop_timer [0];
+        timer->frames [video->wfa->frame_type]++;
+     }
       
-	 /*
-	  *  Read reference frame from disk if required
-	  *  (i.e., 1st frame is of type B or P)
-	  */
-	 if (video->display == 0 && video->wfa->frame_type != I_FRAME)
-	 {
-	    if (!reference_frame)
-	       error ("First frame is %c-frame but no "
-		      "reference frame is given.",
-		      video->wfa->frame_type == B_FRAME ? 'B' : 'P');
-
-	    video->frame  = read_image_file (reference_frame);
-	    video->sframe = NULL;
-	 }
+     /*
+      *  Read reference frame from disk if required
+      *  (i.e., 1st frame is of type B or P)
+      */
+     if (video->display == 0 && video->wfa->frame_type != I_FRAME)
+     {
+        if (!reference_frame)
+           error ("First frame is %c-frame but no "
+              "reference frame is given.",
+              video->wfa->frame_type == B_FRAME ? 'B' : 'P');
+
+        video->frame  = read_image_file (reference_frame);
+        video->sframe = NULL;
+     }
    
-	 /*
-	  *  Depending on current frame type update past and future frames
-	  */
-	 if (video->wfa->frame_type == I_FRAME)
-	 {
-	    if (video->past)		/* discard past frame */
-	       free_image (video->past);
-	    video->past = NULL;
-	    if (video->future)		/* discard future frame */
-	       free_image (video->future);
-	    video->future = NULL;
-	    if (video->sfuture)		/* discard (smoothed) future frame */
-	       free_image (video->sfuture);
-	    video->sfuture = NULL;
-	    if (video->frame)		/* discard current frame */
-	       free_image (video->frame);
-	    video->frame = NULL;
-	    if (video->sframe)		/* discard current (smoothed) frame */
-	       free_image (video->sframe);
-	    video->sframe = NULL;
-	 }
-	 else if (video->wfa->frame_type == P_FRAME)
-	 {
-	    if (video->past)		/* discard past frame */
-	       free_image (video->past);
-	    video->past = video->frame;	/* past <- current frame */
-	    video->frame = NULL;
-	    if (video->sframe)		/* discard current (smoothed) frame */
-	       free_image (video->sframe);
-	    video->sframe = NULL;
-	    if (store_wfa)
-	       copy_wfa (video->wfa_past, tmp_wfa);
-	    if (video->future)		/* discard future frame */
-	       free_image (video->future);
-	    video->future = NULL;
-	    if (video->sfuture)		/* discard (smoothed) future frame */
-	       free_image (video->sfuture);
-	    video->sfuture = NULL;
-	 }
-	 else				/* B_FRAME */
-	 {
-	    if (current_frame_is_future_frame)
-	    {
-	       if (video->future)	/* discard future frame */
-		  free_image (video->future);
-	       video->future = frame;	/* future <- current frame */
-	       if (video->sfuture)	/* discard (smoothed) future frame */
-		  free_image (video->sfuture);
-	       video->sfuture = sframe;	/* future <- current (smoothed) */
-	       if (store_wfa)
-		  copy_wfa (video->wfa_future, tmp_wfa);
-	       if (video->frame)	/* discard current frame */
-		  free_image (video->frame);
-	       video->frame = NULL;
-	       if (video->sframe)	/* discard current (smoothed) frame */
-		  free_image (video->sframe);
-	       video->sframe = NULL;
-	       frame  = NULL;
-	       sframe = NULL;
-	    }
-	    else
-	    {
-	       if (video->wfa->wfainfo->B_as_past_ref == YES)
-	       {
-		  if (video->past)	/* discard past frame */
-		     free_image (video->past);
-		  video->past  = video->frame; /* past <- current frame */
-		  video->frame = NULL;
-		  if (video->sframe)	/* discard current (smoothed) frame */
-		     free_image (video->sframe);
-		  video->sframe = NULL;
-		  if (store_wfa)
-		     copy_wfa (video->wfa_past, tmp_wfa);
-	       }
-	       else
-	       {
-		  if (video->frame)	/* discard current */
-		     free_image (video->frame);
-		  video->frame = NULL;
-		  if (video->sframe)	/* discard current (smoothed) frame */
-		     free_image (video->sframe);
-		  video->sframe = NULL;
-	       }
-	    }
-	 }
-	 if (tmp_wfa)
-	    free_wfa (tmp_wfa);
-	 
-	 current_frame_is_future_frame = NO;
-	 /*
-	  *  Second step: decode image
-	  *  Optionally enlarge image if specified by option 'enlarge_factor'.
-	  */
-	 {
-	    unsigned orig_width, orig_height;
-
-	    stop_timer [0] = stop_timer [1] = stop_timer [2] = 0;
-	 
-	    enlarge_image (enlarge_factor, format,
-			   (video->wfa->wfainfo->color
-			    && format == FORMAT_4_2_0)
-			   ? video->wfa->tree [video->wfa->tree [video->wfa->root_state][0]][0] : -1, video->wfa);
-
-	    if (enlarge_factor > 0)
-	    {
-	       orig_width  = video->wfa->wfainfo->width  << enlarge_factor;
-	       orig_height = video->wfa->wfainfo->height << enlarge_factor; 
-	    }
-	    else
-	    { 
-	       orig_width  = video->wfa->wfainfo->width  >> - enlarge_factor;
-	       orig_height = video->wfa->wfainfo->height >> - enlarge_factor;
-	       if (orig_width & 1)
-		  orig_width++;
-	       if (orig_height & 1)
-		  orig_height++;
-	    }
-	 
-	    frame = decode_image (orig_width, orig_height, format,
-				  timer != NULL ? stop_timer : NULL,
-				  video->wfa);
-	    if (timer)
-	    {
-	       timer->preprocessing [video->wfa->frame_type] += stop_timer [0];
-	       timer->decoder [video->wfa->frame_type]       += stop_timer [1];
-	       timer->cleanup [video->wfa->frame_type]       += stop_timer [2];
-	    }
-	 }
-
-	 /*
-	  *  Third step: restore motion compensation
-	  */
-	 if (video->wfa->frame_type != I_FRAME)
-	 {
-	    prg_timer (&ptimer, START);
-	    restore_mc (enlarge_factor, frame, video->past, video->future,
-			video->wfa);
-	    stop_timer [0] = prg_timer (&ptimer, STOP);
-	    if (timer)
-	       timer->motion [video->wfa->frame_type] += stop_timer [0];
-	 }
-
-	 /*
-	  *  Fourth step: smooth image along partitioning borders
-	  */
-	 prg_timer (&ptimer, START);
-	 if (smoothing < 0)	/* smoothing not changed by user */
-	    smoothing = video->wfa->wfainfo->smoothing;
-	 if (smoothing > 0 && smoothing <= 100)
-	 {
-	    sframe = clone_image (frame);
-	    smooth_image (smoothing, video->wfa, sframe);
-	 }
-	 else
-	    sframe = NULL;
-	 
-	 stop_timer [0] = prg_timer (&ptimer, STOP);
-	 if (timer)
-	    timer->smooth [video->wfa->frame_type] += stop_timer [0];
-
-	 if (frame_number == video->display)
-	 {
-	    video->display++;
-	    video->frame  = frame;
-	    video->sframe = sframe;
-	    frame         = NULL;
-	    sframe        = NULL;
-	 }
-	 else if (frame_number > video->display)
-	 {
-	    video->future_display 	  = frame_number;
-	    current_frame_is_future_frame = YES;
-	 }
+     /*
+      *  Depending on current frame type update past and future frames
+      */
+     if (video->wfa->frame_type == I_FRAME)
+     {
+        if (video->past)        /* discard past frame */
+           free_image (video->past);
+        video->past = NULL;
+        if (video->future)      /* discard future frame */
+           free_image (video->future);
+        video->future = NULL;
+        if (video->sfuture)     /* discard (smoothed) future frame */
+           free_image (video->sfuture);
+        video->sfuture = NULL;
+        if (video->frame)       /* discard current frame */
+           free_image (video->frame);
+        video->frame = NULL;
+        if (video->sframe)      /* discard current (smoothed) frame */
+           free_image (video->sframe);
+        video->sframe = NULL;
+     }
+     else if (video->wfa->frame_type == P_FRAME)
+     {
+        if (video->past)        /* discard past frame */
+           free_image (video->past);
+        video->past = video->frame; /* past <- current frame */
+        video->frame = NULL;
+        if (video->sframe)      /* discard current (smoothed) frame */
+           free_image (video->sframe);
+        video->sframe = NULL;
+        if (store_wfa)
+           copy_wfa (video->wfa_past, tmp_wfa);
+        if (video->future)      /* discard future frame */
+           free_image (video->future);
+        video->future = NULL;
+        if (video->sfuture)     /* discard (smoothed) future frame */
+           free_image (video->sfuture);
+        video->sfuture = NULL;
+     }
+     else               /* B_FRAME */
+     {
+        if (current_frame_is_future_frame)
+        {
+           if (video->future)   /* discard future frame */
+          free_image (video->future);
+           video->future = frame;   /* future <- current frame */
+           if (video->sfuture)  /* discard (smoothed) future frame */
+          free_image (video->sfuture);
+           video->sfuture = sframe; /* future <- current (smoothed) */
+           if (store_wfa)
+          copy_wfa (video->wfa_future, tmp_wfa);
+           if (video->frame)    /* discard current frame */
+          free_image (video->frame);
+           video->frame = NULL;
+           if (video->sframe)   /* discard current (smoothed) frame */
+          free_image (video->sframe);
+           video->sframe = NULL;
+           frame  = NULL;
+           sframe = NULL;
+        }
+        else
+        {
+           if (video->wfa->wfainfo->B_as_past_ref == YES)
+           {
+          if (video->past)  /* discard past frame */
+             free_image (video->past);
+          video->past  = video->frame; /* past <- current frame */
+          video->frame = NULL;
+          if (video->sframe)    /* discard current (smoothed) frame */
+             free_image (video->sframe);
+          video->sframe = NULL;
+          if (store_wfa)
+             copy_wfa (video->wfa_past, tmp_wfa);
+           }
+           else
+           {
+          if (video->frame) /* discard current */
+             free_image (video->frame);
+          video->frame = NULL;
+          if (video->sframe)    /* discard current (smoothed) frame */
+             free_image (video->sframe);
+          video->sframe = NULL;
+           }
+        }
+     }
+     if (tmp_wfa)
+        free_wfa (tmp_wfa);
+     
+     current_frame_is_future_frame = NO;
+     /*
+      *  Second step: decode image
+      *  Optionally enlarge image if specified by option 'enlarge_factor'.
+      */
+     {
+        unsigned orig_width, orig_height;
+
+        stop_timer [0] = stop_timer [1] = stop_timer [2] = 0;
+     
+        enlarge_image (enlarge_factor, format,
+               (video->wfa->wfainfo->color
+                && format == FORMAT_4_2_0)
+               ? video->wfa->tree [video->wfa->tree [video->wfa->root_state][0]][0] : -1, video->wfa);
+
+        if (enlarge_factor > 0)
+        {
+           orig_width  = video->wfa->wfainfo->width  << enlarge_factor;
+           orig_height = video->wfa->wfainfo->height << enlarge_factor; 
+        }
+        else
+        { 
+           orig_width  = video->wfa->wfainfo->width  >> - enlarge_factor;
+           orig_height = video->wfa->wfainfo->height >> - enlarge_factor;
+           if (orig_width & 1)
+          orig_width++;
+           if (orig_height & 1)
+          orig_height++;
+        }
+     
+        frame = decode_image (orig_width, orig_height, format,
+                  timer != NULL ? stop_timer : NULL,
+                  video->wfa);
+        if (timer)
+        {
+           timer->preprocessing [video->wfa->frame_type] += stop_timer [0];
+           timer->decoder [video->wfa->frame_type]       += stop_timer [1];
+           timer->cleanup [video->wfa->frame_type]       += stop_timer [2];
+        }
+     }
+
+     /*
+      *  Third step: restore motion compensation
+      */
+     if (video->wfa->frame_type != I_FRAME)
+     {
+        prg_timer (&ptimer, START);
+        restore_mc (enlarge_factor, frame, video->past, video->future,
+            video->wfa);
+        stop_timer [0] = prg_timer (&ptimer, STOP);
+        if (timer)
+           timer->motion [video->wfa->frame_type] += stop_timer [0];
+     }
+
+     /*
+      *  Fourth step: smooth image along partitioning borders
+      */
+     prg_timer (&ptimer, START);
+     if (smoothing < 0) /* smoothing not changed by user */
+        smoothing = video->wfa->wfainfo->smoothing;
+     if (smoothing > 0 && smoothing <= 100)
+     {
+        sframe = clone_image (frame);
+        smooth_image (smoothing, video->wfa, sframe);
+     }
+     else
+        sframe = NULL;
+     
+     stop_timer [0] = prg_timer (&ptimer, STOP);
+     if (timer)
+        timer->smooth [video->wfa->frame_type] += stop_timer [0];
+
+     if (frame_number == video->display)
+     {
+        video->display++;
+        video->frame  = frame;
+        video->sframe = sframe;
+        frame         = NULL;
+        sframe        = NULL;
+     }
+     else if (frame_number > video->display)
+     {
+        video->future_display     = frame_number;
+        current_frame_is_future_frame = YES;
+     }
       
-	 if (!store_wfa)
-	    remove_states (video->wfa->basis_states, video->wfa);
+     if (!store_wfa)
+        remove_states (video->wfa->basis_states, video->wfa);
       } while (!video->frame);
 
       if (!store_wfa)
-	 video->wfa = NULL;
+     video->wfa = NULL;
    }
    
    return video->sframe ? video->sframe : video->frame;
@@ -414,7 +413,7 @@ get_next_frame (bool_t store_wfa, int enlarge_factor,
 
 image_t *
 decode_image (unsigned orig_width, unsigned orig_height, format_e format,
-	      unsigned *dec_timer, const wfa_t *wfa)
+          unsigned *dec_timer, const wfa_t *wfa)
 /*
  *  Compute image which is represented by the given 'wfa'.
  *  'orig_width'x'orig_height' gives the resolution of the image at
@@ -422,20 +421,20 @@ decode_image (unsigned orig_width, unsigned orig_height, format_e format,
  *  If 'dec_timer' is given, accumulate running time statistics. 
  *  
  *  Return value:
- *	pointer to decoded image
+ *  pointer to decoded image
  *
  *  Side effects:
- *	'*dectimer' is changed if 'dectimer' != NULL.
+ *  '*dectimer' is changed if 'dectimer' != NULL.
  */
 {
-   unsigned   root_state [3];		/* root of bintree for each band */
-   unsigned   width, height;		/* computed image size */
-   image_t   *frame;			/* regenerated frame */
-   word_t   **images;			/* pointer to array of pointers
-					   to state images */
-   u_word_t  *offsets;			/* pointer to array of state image
-					   offsets */
-   unsigned   max_level;		/* max. level of state with approx. */
+   unsigned   root_state [3];       /* root of bintree for each band */
+   unsigned   width, height;        /* computed image size */
+   image_t   *frame;            /* regenerated frame */
+   word_t   **images;           /* pointer to array of pointers
+                       to state images */
+   u_word_t  *offsets;          /* pointer to array of state image
+                       offsets */
+   unsigned   max_level;        /* max. level of state with approx. */
    unsigned   state;
    clock_t    ptimer;
 
@@ -458,16 +457,16 @@ decode_image (unsigned orig_width, unsigned orig_height, format_e format,
     */
    for (max_level = 0, state = wfa->basis_states; state < wfa->states; state++)
       if (isedge (wfa->into [state][0][0]) || isedge (wfa->into [state][1][0]))
-	 max_level = max (max_level, wfa->level_of_state [state]);
+     max_level = MAX(max_level, wfa->level_of_state [state]);
    
 
    /*
     *  Allocate frame buffer for decoded image
     */
    compute_actual_size (format == FORMAT_4_2_0 ? root_state [Y] : MAXSTATES,
-			&width, &height, wfa);
-   width  = max (width, orig_width);
-   height = max (height, orig_height);
+            &width, &height, wfa);
+   width  = MAX(width, orig_width);
+   height = MAX(height, orig_height);
    frame = alloc_image (width, height, wfa->wfainfo->color, format);
    
    /*
@@ -480,7 +479,7 @@ decode_image (unsigned orig_width, unsigned orig_height, format_e format,
       wfa->level_of_state [wfa->tree[wfa->root_state][1]] = 128;
    }
    alloc_state_images (&images, &offsets, frame, root_state, 0, max_level, 
-		       format, wfa);
+               format, wfa);
 
    if (dec_timer)
       dec_timer [0] += prg_timer (&ptimer, STOP);
@@ -498,38 +497,38 @@ decode_image (unsigned orig_width, unsigned orig_height, format_e format,
     */
    prg_timer (&ptimer, START);
    free_state_images (max_level, frame->color, images, offsets, root_state, 0,
-		      format, wfa);
+              format, wfa);
    
    /*
     *  Crop decoded image if the image size differs.
     */
    if (orig_width != width || orig_height != height)
    {
-      frame->height = orig_height;	
-      frame->width  = orig_width;	
-      if (orig_width != width)		
+      frame->height = orig_height;  
+      frame->width  = orig_width;   
+      if (orig_width != width)      
       {
-	 color_e   band;		/* current color band */
-	 word_t	  *src, *dst;		/* source and destination pointers */
-	 unsigned  y;			/* current row */
-	 
-	 for (band  = first_band (frame->color);
-	      band <= last_band (frame->color); band++)
-	 {
-	    src = dst = frame->pixels [band];
-	    for (y = orig_height; y; y--)
-	    {
-	       memmove (dst, src, orig_width * sizeof (word_t));
-	       dst += orig_width;
-	       src += width;
-	    }
-	    if (format == FORMAT_4_2_0 && band == Y)
-	    {
-	       orig_width  >>= 1;
-	       orig_height >>= 1;
-	       width       >>= 1;
-	    }
-	 }
+     color_e   band;        /* current color band */
+     word_t   *src, *dst;       /* source and destination pointers */
+     unsigned  y;           /* current row */
+     
+     for (band  = first_band (frame->color);
+          band <= last_band (frame->color); band++)
+     {
+        src = dst = frame->pixels [band];
+        for (y = orig_height; y; y--)
+        {
+           memmove (dst, src, orig_width * sizeof (word_t));
+           dst += orig_width;
+           src += width;
+        }
+        if (format == FORMAT_4_2_0 && band == Y)
+        {
+           orig_width  >>= 1;
+           orig_height >>= 1;
+           width       >>= 1;
+        }
+     }
       }
    }
    if (dec_timer)
@@ -544,10 +543,10 @@ decode_state (unsigned state, unsigned level, wfa_t *wfa)
  *  Decode 'state' image of 'wfa' at given 'level'.
  *
  *  Return value.
- *	pointer to decoded state image
+ *  pointer to decoded state image
  *
  *  Side effects:
- *	'wfa' states > 'state' are removed.  
+ *  'wfa' states > 'state' are removed.  
  */
 {
    word_t  *domains [2];
@@ -571,15 +570,15 @@ decode_state (unsigned state, unsigned level, wfa_t *wfa)
     */
    {
       word_t   *src, *dst;
-      unsigned	y;
-	    
+      unsigned  y;
+        
       src = domains [0];
       dst = img->pixels [GRAY];
       for (y = img->height; y; y--)
       {
-	 memcpy (dst, src, width_of_level (level) * sizeof (word_t));
-	 src += width_of_level (level);
-	 dst += img->width;
+     memcpy (dst, src, width_of_level (level) * sizeof (word_t));
+     src += width_of_level (level);
+     dst += img->width;
       }
       Free (domains [0]);
    }
@@ -589,87 +588,87 @@ decode_state (unsigned state, unsigned level, wfa_t *wfa)
 
 word_t *
 decode_range (unsigned range_state, unsigned range_label, unsigned range_level,
-	      word_t **domain, wfa_t *wfa)
+          word_t **domain, wfa_t *wfa)
 /*
  *  Compute 'wfa' image of range (identified by 'state' and 'label')
  *  at 'range_level (works as function decode_image()).
  *
  *  Return value:
- *	pointer to the pixels in SHORT format
+ *  pointer to the pixels in SHORT format
  *
  *  Side effects:
- *	if 'domain' != NULL then also the domain blocks
- *	of the corresponding range blocks are generated
+ *  if 'domain' != NULL then also the domain blocks
+ *  of the corresponding range blocks are generated
  *      and returned in domain[]
- *	'wfa->level_of_state []' is changed
+ *  'wfa->level_of_state []' is changed
  */
 {
-   unsigned   root_state [3];		/* dummy (for alloc_state_images) */
-   image_t   *state_image;		/* regenerated state image */
-   word_t   **images;			/* pointer to array of pointers
-					   to state images */
-   u_word_t  *offsets;			/* pointer to array of state image
-					   offsets */
+   unsigned   root_state [3];       /* dummy (for alloc_state_images) */
+   image_t   *state_image;      /* regenerated state image */
+   word_t   **images;           /* pointer to array of pointers
+                       to state images */
+   u_word_t  *offsets;          /* pointer to array of state image
+                       offsets */
    word_t    *range;
 
    enlarge_image (range_level - (wfa->level_of_state [range_state] - 1),
-		  FORMAT_4_4_4, -1, wfa);
+          FORMAT_4_4_4, -1, wfa);
    root_state [0] = range_state;
    state_image    = alloc_image (width_of_level (range_level + 1),
-				 height_of_level (range_level + 1),
-				 NO, FORMAT_4_4_4);
+                 height_of_level (range_level + 1),
+                 NO, FORMAT_4_4_4);
    alloc_state_images (&images, &offsets, state_image, NULL, range_state,
-		       range_level + 1, NO, wfa);
+               range_level + 1, NO, wfa);
    compute_state_images (range_level + 1, images, offsets, wfa);
 
    range = Calloc (size_of_level (range_level), sizeof (word_t));
 
-   if ((range_level & 1) == 0)		/* square image */
+   if ((range_level & 1) == 0)      /* square image */
    {
       memcpy (range,
-	      images [range_state + (range_level + 1) * wfa->states]
-	      + range_label * size_of_level (range_level),
-	      size_of_level (range_level) * sizeof (word_t));
+          images [range_state + (range_level + 1) * wfa->states]
+          + range_label * size_of_level (range_level),
+          size_of_level (range_level) * sizeof (word_t));
    }
-   else					/* rectangle */
+   else                 /* rectangle */
    {
       word_t   *src, *dst;
       unsigned  y;
       
       src = images [range_state + (range_level + 1) * wfa->states]
-	    + range_label * width_of_level (range_level);
+        + range_label * width_of_level (range_level);
       dst = range;
       for (y = height_of_level (range_level); y; y--)
       {
-	 memcpy (dst, src, width_of_level (range_level) * sizeof (word_t));
-	 dst += width_of_level (range_level);
-	 src += width_of_level (range_level + 1);
+     memcpy (dst, src, width_of_level (range_level) * sizeof (word_t));
+     dst += width_of_level (range_level);
+     src += width_of_level (range_level + 1);
       }
    }
 
-   if (domain != NULL)			/* copy domain images */
+   if (domain != NULL)          /* copy domain images */
    {
-      int      s;			/* domain state */
-      unsigned edge;			/* counter */
-		
+      int      s;           /* domain state */
+      unsigned edge;            /* counter */
+        
       if (ischild (s = wfa->tree [range_state][range_label]))
-	 *domain++ = duplicate_state_image (images [s + (range_level)
-						   * wfa->states],
-					    offsets [s + (range_level)
-						    * wfa->states],
-					    range_level);
+     *domain++ = duplicate_state_image (images [s + (range_level)
+                           * wfa->states],
+                        offsets [s + (range_level)
+                            * wfa->states],
+                        range_level);
       for (edge = 0; isedge (s = wfa->into[range_state][range_label][edge]);
-	   edge++)
-	 *domain++ = duplicate_state_image (images [s + (range_level)
-						   * wfa->states],
-					    offsets [s + (range_level)
-						    * wfa->states],
-					    range_level);
+       edge++)
+     *domain++ = duplicate_state_image (images [s + (range_level)
+                           * wfa->states],
+                        offsets [s + (range_level)
+                            * wfa->states],
+                        range_level);
       *domain = NULL;
    }
    
    free_state_images (range_level + 1, NO, images, offsets, NULL, range_state,
-		      NO, wfa);
+              NO, wfa);
    free_image (state_image);
    
    return range;
@@ -684,102 +683,102 @@ smooth_image (unsigned sf, const wfa_t *wfa, image_t *image)
  *  No return value.
  *
  *  Side effects:
- *	pixel values of the 'image' are modified with respect to 's'
+ *  pixel values of the 'image' are modified with respect to 's'
  */
 {
-   int	    is, inegs;			/* integer factors of s and 1 - s*/
-   unsigned state;			
+   int      is, inegs;          /* integer factors of s and 1 - s*/
+   unsigned state;          
    unsigned img_width  = image->width;
    unsigned img_height = image->height;
-   real_t   s 	       = 1.0 - sf / 200.0;
+   real_t   s          = 1.0 - sf / 200.0;
 
-   if (s < 0.5 || s >= 1)		/* value out of range */
+   if (s < 0.5 || s >= 1)       /* value out of range */
       return;
 
-   is 	 = s * 512 + .5;		/* integer representation of s */
-   inegs = (1 - s) * 512 + .5;		/* integer representation of 1 - s */
+   is    = s * 512 + .5;        /* integer representation of s */
+   inegs = (1 - s) * 512 + .5;      /* integer representation of 1 - s */
    
    for (state = wfa->basis_states;
-	state < (wfa->wfainfo->color
-		 ? wfa->tree [wfa->root_state][0]
-		 : wfa->states); state++)
+    state < (wfa->wfainfo->color
+         ? wfa->tree [wfa->root_state][0]
+         : wfa->states); state++)
    {
       word_t   *bptr   = image->pixels [Y]; /* pointer to right or
-					       lower line */
+                           lower line */
       unsigned  level  = wfa->level_of_state[state]; /* level of state image */
       unsigned  width  = width_of_level (level); /* size of state image */
       unsigned  height = height_of_level (level); /* size of state image */
       
       if (wfa->y [state][1] >= img_height || wfa->x [state][1] >= img_width)
-	 continue;			/* outside visible area */
-	 
-      if (level % 2)			/* horizontal smoothing */
+     continue;          /* outside visible area */
+     
+      if (level % 2)            /* horizontal smoothing */
       {
-	 unsigned  i;			/* line counter */
-	 word_t   *img1;		/* pointer to left or upper line */
-	 word_t   *img2;		/* pointer to right or lower line */
-
-	 img1 = bptr + (wfa->y [state][1] - 1) * img_width
-		+ wfa->x [state][1];
-	 img2 = bptr + wfa->y [state][1] * img_width + wfa->x [state][1];
-	 
-	 for (i = min (width, img_width - wfa->x [state][1]); i;
-	      i--, img1++, img2++)
-	 {
-	    int tmp = *img1;
-	    
+     unsigned  i;           /* line counter */
+     word_t   *img1;        /* pointer to left or upper line */
+     word_t   *img2;        /* pointer to right or lower line */
+
+     img1 = bptr + (wfa->y [state][1] - 1) * img_width
+        + wfa->x [state][1];
+     img2 = bptr + wfa->y [state][1] * img_width + wfa->x [state][1];
+     
+     for (i = MIN(width, img_width - wfa->x [state][1]); i;
+          i--, img1++, img2++)
+     {
+        int tmp = *img1;
+        
 #ifdef HAVE_SIGNED_SHIFT
-	    *img1 = (((is * tmp) >> 10) << 1)
-		    + (((inegs * (int) *img2) >> 10) << 1);
-	    *img2 = (((is * (int) *img2) >> 10) << 1)
-		    + (((inegs * tmp) >> 10) << 1);
+        *img1 = (((is * tmp) >> 10) << 1)
+            + (((inegs * (int) *img2) >> 10) << 1);
+        *img2 = (((is * (int) *img2) >> 10) << 1)
+            + (((inegs * tmp) >> 10) << 1);
 #else /* not HAVE_SIGNED_SHIFT */
-	    *img1 = (((is * tmp) / 1024) * 2)
-		    + (((inegs * (int) *img2) / 1024) * 2);
-	    *img2 = (((is * (int) *img2) / 1024) * 2)
-		    + (((inegs * tmp) / 1024) *2);
+        *img1 = (((is * tmp) / 1024) * 2)
+            + (((inegs * (int) *img2) / 1024) * 2);
+        *img2 = (((is * (int) *img2) / 1024) * 2)
+            + (((inegs * tmp) / 1024) *2);
 #endif /* not HAVE_SIGNED_SHIFT */
-	 }
+     }
       }
-      else				/* vertical smoothing */
+      else              /* vertical smoothing */
       {
-	 unsigned  i;			/* line counter */
-	 word_t   *img1;		/* pointer to left or upper line */
-	 word_t   *img2;		/* pointer to right or lower line */
-
-	 img1 = bptr + wfa->y [state][1] * img_width + wfa->x [state][1] - 1;
-	 img2 = bptr + wfa->y [state][1] * img_width + wfa->x [state][1];
-	 
-	 for (i = min (height, img_height - wfa->y [state][1]); i;
-	      i--, img1 += img_width, img2 += img_width)
-	 {
-	    int tmp = *img1;
-	    
+     unsigned  i;           /* line counter */
+     word_t   *img1;        /* pointer to left or upper line */
+     word_t   *img2;        /* pointer to right or lower line */
+
+     img1 = bptr + wfa->y [state][1] * img_width + wfa->x [state][1] - 1;
+     img2 = bptr + wfa->y [state][1] * img_width + wfa->x [state][1];
+     
+     for (i = MIN(height, img_height - wfa->y [state][1]); i;
+          i--, img1 += img_width, img2 += img_width)
+     {
+        int tmp = *img1;
+        
 #ifdef HAVE_SIGNED_SHIFT
-	    *img1 = (((is * tmp) >> 10) << 1)
-		    + (((inegs * (int) *img2) >> 10) << 1);
-	    *img2 = (((is * (int) *img2) >> 10) << 1)
-		    + (((inegs * tmp) >> 10) << 1);
+        *img1 = (((is * tmp) >> 10) << 1)
+            + (((inegs * (int) *img2) >> 10) << 1);
+        *img2 = (((is * (int) *img2) >> 10) << 1)
+            + (((inegs * tmp) >> 10) << 1);
 #else /* not HAVE_SIGNED_SHIFT */
-	    *img1 = (((is * tmp) / 1024) * 2)
-		    + (((inegs * (int) *img2) / 1024) * 2);
-	    *img2 = (((is * (int) *img2) / 1024) * 2)
-		    + (((inegs * tmp) / 1024) *2);
+        *img1 = (((is * tmp) / 1024) * 2)
+            + (((inegs * (int) *img2) / 1024) * 2);
+        *img2 = (((is * (int) *img2) / 1024) * 2)
+            + (((inegs * tmp) / 1024) *2);
 #endif /* not HAVE_SIGNED_SHIFT */
-	 }
+     }
       }
    }
 }
 
 /*****************************************************************************
 
-				private code
+                private code
   
 *****************************************************************************/
 
 static void
 enlarge_image (int enlarge_factor, format_e format, unsigned y_root,
-	       wfa_t *wfa)
+           wfa_t *wfa)
 /*
  *  Enlarge or reduce size of state images by factor 2^'enlarge_factor'.
  *  Use 4:2:0 subsampling if specified by 'format', else use 4:4:4 format.
@@ -788,8 +787,8 @@ enlarge_image (int enlarge_factor, format_e format, unsigned y_root,
  *  No return value.
  *
  *  Side effects:
- *	coordinates of ranges and motion blocks in the WFA structure 'wfa'
- *	are modified.
+ *  coordinates of ranges and motion blocks in the WFA structure 'wfa'
+ *  are modified.
  */
 {
    
@@ -799,53 +798,53 @@ enlarge_image (int enlarge_factor, format_e format, unsigned y_root,
 
       if (enlarge_factor == 0)
       {
-	 state 		= y_root + 1;
-	 enlarge_factor = -1;
+     state      = y_root + 1;
+     enlarge_factor = -1;
       }
       else
-	 state = wfa->basis_states;
+     state = wfa->basis_states;
       
       for (; state < wfa->states; state++)
       {
-	 unsigned label, n;
-	 
-	 wfa->level_of_state [state]
-	    = max (wfa->level_of_state [state] + enlarge_factor * 2, 0);
-
-	 for (label = 0; label < MAXLABELS; label++)
-	    if (enlarge_factor > 0)
-	    {
-	       wfa->x [state][label] <<= enlarge_factor;
-	       wfa->y [state][label] <<= enlarge_factor;
-	       for (n = enlarge_factor; n; n--)
-	       {
-		  wfa->mv_tree [state][label].fx *= 2;
-		  wfa->mv_tree [state][label].fy *= 2;
-		  wfa->mv_tree [state][label].bx *= 2;
-		  wfa->mv_tree [state][label].by *= 2;
-	       }
-	    }
-	    else				/* enlarge_factor < 0 */
-	    {
-	       wfa->x [state][label] >>= - enlarge_factor;
-	       wfa->y [state][label] >>= - enlarge_factor;
-	       for (n = - enlarge_factor; n; n--)
-	       {
-		  wfa->mv_tree [state][label].fx /= 2;
-		  wfa->mv_tree [state][label].fy /= 2;
-		  wfa->mv_tree [state][label].bx /= 2;
-		  wfa->mv_tree [state][label].by /= 2;
-	       }
-	    }
-	 if (format == FORMAT_4_2_0 && state == y_root)
-	    enlarge_factor--;
+     unsigned label, n;
+     
+     wfa->level_of_state [state]
+        = MAX(wfa->level_of_state [state] + enlarge_factor * 2, 0);
+
+     for (label = 0; label < MAXLABELS; label++)
+        if (enlarge_factor > 0)
+        {
+           wfa->x [state][label] <<= enlarge_factor;
+           wfa->y [state][label] <<= enlarge_factor;
+           for (n = enlarge_factor; n; n--)
+           {
+          wfa->mv_tree [state][label].fx *= 2;
+          wfa->mv_tree [state][label].fy *= 2;
+          wfa->mv_tree [state][label].bx *= 2;
+          wfa->mv_tree [state][label].by *= 2;
+           }
+        }
+        else                /* enlarge_factor < 0 */
+        {
+           wfa->x [state][label] >>= - enlarge_factor;
+           wfa->y [state][label] >>= - enlarge_factor;
+           for (n = - enlarge_factor; n; n--)
+           {
+          wfa->mv_tree [state][label].fx /= 2;
+          wfa->mv_tree [state][label].fy /= 2;
+          wfa->mv_tree [state][label].bx /= 2;
+          wfa->mv_tree [state][label].by /= 2;
+           }
+        }
+     if (format == FORMAT_4_2_0 && state == y_root)
+        enlarge_factor--;
       }
    }
 }
 
 static void
 compute_actual_size (unsigned luminance_root,
-		     unsigned *width, unsigned *height, const wfa_t *wfa)
+             unsigned *width, unsigned *height, const wfa_t *wfa)
 /*
  *  Compute actual size of the frame represented by the given 'wfa'.
  *  (The reconstructed frame may get larger than the original due
@@ -853,24 +852,24 @@ compute_actual_size (unsigned luminance_root,
  *  If 'luminance_root' < MAXSTATES then the size of chroma ranges (4:2:0).
  *
  *  Return values:
- *	actual 'width' and 'height' of the decoded frame.
+ *  actual 'width' and 'height' of the decoded frame.
  */
 {
-   unsigned x = 0, y = 0;		/* maximum coordinates */
-   unsigned state;			/* counter */
+   unsigned x = 0, y = 0;       /* maximum coordinates */
+   unsigned state;          /* counter */
    
    for (state = wfa->basis_states; state < wfa->states; state++)
       if (isedge (wfa->into [state][0][0]) || isedge (wfa->into [state][1][0]))
       {
-	 unsigned mult = state > luminance_root ? 2 : 1;
-	 
-	 x = max ((wfa->x [state][0]
-		   + width_of_level (wfa->level_of_state [state])) * mult, x);
-	 y = max ((wfa->y [state][0]
-		   + height_of_level (wfa->level_of_state [state])) * mult, y);
+          unsigned mult = state > luminance_root ? 2 : 1;
+          
+          x = MAX((wfa->x [state][0]
+                   + width_of_level (wfa->level_of_state [state])) * mult, x);
+          y = MAX((wfa->y [state][0]
+                   + height_of_level (wfa->level_of_state [state])) * mult, y);
       }
 
-   if (x & 1)				/* ensure that image size is even */
+   if (x & 1)               /* ensure that image size is even */
       x++;
    if (y & 1)
       y++;
@@ -880,8 +879,8 @@ compute_actual_size (unsigned luminance_root,
 
 static void
 alloc_state_images (word_t ***images, u_word_t **offsets, const image_t *frame,
-		    const unsigned *root_state, unsigned range_state,
-		    unsigned max_level, format_e format, const wfa_t *wfa)
+            const unsigned *root_state, unsigned range_state,
+            unsigned max_level, format_e format, const wfa_t *wfa)
 /*
  *  Generate list of 'wfa' state images which have to be computed for
  *  each level to obtain the decoded 'frame'. 'root_state[]' denotes the
@@ -893,24 +892,24 @@ alloc_state_images (word_t ***images, u_word_t **offsets, const image_t *frame,
  *  image of 'wfa->root_state'.
  *
  *  Return values:
- *	'*images'	Pointer to array of state image pointers
- *	'*offsets'	Pointer to array of state image offsets.
+ *  '*images'   Pointer to array of state image pointers
+ *  '*offsets'  Pointer to array of state image offsets.
  *
  *  Side effects:
- *	The arrays given above are filled with useful values.
+ *  The arrays given above are filled with useful values.
  */
 {
-   word_t   **simg;			/* ptr to list of state image ptr's */
-   u_word_t  *offs;			/* ptr to list of offsets */
-   unsigned   level;			/* counter */
+   word_t   **simg;         /* ptr to list of state image ptr's */
+   u_word_t  *offs;         /* ptr to list of offsets */
+   unsigned   level;            /* counter */
    
-   simg	= Calloc (wfa->states * (max_level + 1), sizeof (word_t *));
-   offs	= Calloc (wfa->states * (max_level + 1), sizeof (u_word_t));
+   simg = Calloc (wfa->states * (max_level + 1), sizeof (word_t *));
+   offs = Calloc (wfa->states * (max_level + 1), sizeof (u_word_t));
 
    /*
     *  Initialize buffers for those state images which are at 'max_level'.
     */
-   if (range_state > 0)			/* a range is given */
+   if (range_state > 0)         /* a range is given */
    {
       simg [range_state + max_level * wfa->states] = frame->pixels [GRAY];
       offs [range_state + max_level * wfa->states] = frame->width;
@@ -920,25 +919,25 @@ alloc_state_images (word_t ***images, u_word_t **offsets, const image_t *frame,
       unsigned state;
 
       for (state = wfa->basis_states; state <= root_state [Y]; state++)
-	 if (wfa->level_of_state [state] == max_level)
-	 {
-	    simg [state + max_level * wfa->states]
-	       = (frame->pixels [Y] + wfa->y [state][0] * frame->width
-		  + wfa->x [state][0]);
-	    offs [state + max_level * wfa->states] = frame->width;
-	 }
+     if (wfa->level_of_state [state] == max_level)
+     {
+        simg [state + max_level * wfa->states]
+           = (frame->pixels [Y] + wfa->y [state][0] * frame->width
+          + wfa->x [state][0]);
+        offs [state + max_level * wfa->states] = frame->width;
+     }
       if (frame->color)
       {
-	 unsigned width = format == FORMAT_4_2_0 ?
-			  (frame->width >> 1) : frame->width;
-	 for (; state < wfa->states; state++)
-	    if (wfa->level_of_state [state] == max_level)
-	    {
-	       simg [state + max_level * wfa->states]
-		  = (frame->pixels [state > root_state [Cb] ? Cr : Cb]
-		     + wfa->y [state][0] * width + wfa->x [state][0]);
-	       offs [state + max_level * wfa->states] = width;
-	    }
+     unsigned width = format == FORMAT_4_2_0 ?
+              (frame->width >> 1) : frame->width;
+     for (; state < wfa->states; state++)
+        if (wfa->level_of_state [state] == max_level)
+        {
+           simg [state + max_level * wfa->states]
+          = (frame->pixels [state > root_state [Cb] ? Cr : Cb]
+             + wfa->y [state][0] * width + wfa->x [state][0]);
+           offs [state + max_level * wfa->states] = width;
+        }
       }
    }
    
@@ -954,63 +953,63 @@ alloc_state_images (word_t ***images, u_word_t **offsets, const image_t *frame,
        *  Range approximation with child. 
        */
       for (state = 1; state < (range_state > 0 ?
-			       range_state + 1 : wfa->states); state++)
-	 if (simg [state + level * wfa->states])
-	    for (label = 0; label < MAXLABELS; label++)
-	       if (ischild (child = wfa->tree[state][label]))
-	       {
-		  if (isedge (wfa->into[state][label][0]))
-		  {
-		     /*
-		      *  Allocate new image block.
-		      */
-		     simg [child + (level - 1) * wfa->states]
-			= Calloc (size_of_level (level - 1), sizeof (word_t));
-		     offs [child + (level - 1) * wfa->states]
-			= width_of_level (level - 1);
-		  }
-		  else
-		  {
-		     /*
-		      *  Use image block and offset of parent.
-		      */
-		     if (level & 1)	/* split vertically */
-		     {
-			simg [child + (level - 1) * wfa->states]
-			   = (simg [state + level * wfa->states]
-			      + label * (height_of_level (level - 1)
-					 * offs [state
-						+ level * wfa->states]));
-		     }
-		     else		/* split horizontally */
-		     {
-			simg [child + (level - 1) * wfa->states]
-			   = (simg [state + level * wfa->states]
-			      + label * width_of_level (level - 1));
-		     }
-		     offs [child + (level - 1) * wfa->states]
-			= offs [state + level * wfa->states];
-		  }
-	       }
+                   range_state + 1 : wfa->states); state++)
+     if (simg [state + level * wfa->states])
+        for (label = 0; label < MAXLABELS; label++)
+           if (ischild (child = wfa->tree[state][label]))
+           {
+          if (isedge (wfa->into[state][label][0]))
+          {
+             /*
+              *  Allocate new image block.
+              */
+             simg [child + (level - 1) * wfa->states]
+            = Calloc (size_of_level (level - 1), sizeof (word_t));
+             offs [child + (level - 1) * wfa->states]
+            = width_of_level (level - 1);
+          }
+          else
+          {
+             /*
+              *  Use image block and offset of parent.
+              */
+             if (level & 1) /* split vertically */
+             {
+            simg [child + (level - 1) * wfa->states]
+               = (simg [state + level * wfa->states]
+                  + label * (height_of_level (level - 1)
+                     * offs [state
+                        + level * wfa->states]));
+             }
+             else       /* split horizontally */
+             {
+            simg [child + (level - 1) * wfa->states]
+               = (simg [state + level * wfa->states]
+                  + label * width_of_level (level - 1));
+             }
+             offs [child + (level - 1) * wfa->states]
+            = offs [state + level * wfa->states];
+          }
+           }
       /*
        *  Range approximation with linear combination 
        */
       for (state = 1; state < (range_state > 0 ?
-			       range_state + 1 : wfa->states); state++)
-	 if (simg [state + level * wfa->states])
-	    for (label = 0; label < MAXLABELS; label++)
-	       for (edge = 0; isedge (domain = wfa->into[state][label][edge]);
-		    edge++)
-	       {
-		  if (domain > 0	/* don't allocate memory for state 0 */
-		      && !simg [domain + (level - 1) * wfa->states])
-		  {
-		     simg [domain + (level - 1) * wfa->states]
-			= Calloc (size_of_level (level - 1), sizeof (word_t));
-		     offs [domain + (level - 1) * wfa->states]
-			= width_of_level (level - 1);
-		  }
-	       }
+                   range_state + 1 : wfa->states); state++)
+     if (simg [state + level * wfa->states])
+        for (label = 0; label < MAXLABELS; label++)
+           for (edge = 0; isedge (domain = wfa->into[state][label][edge]);
+            edge++)
+           {
+          if (domain > 0    /* don't allocate memory for state 0 */
+              && !simg [domain + (level - 1) * wfa->states])
+          {
+             simg [domain + (level - 1) * wfa->states]
+            = Calloc (size_of_level (level - 1), sizeof (word_t));
+             offs [domain + (level - 1) * wfa->states]
+            = width_of_level (level - 1);
+          }
+           }
       
    }
 
@@ -1020,8 +1019,8 @@ alloc_state_images (word_t ***images, u_word_t **offsets, const image_t *frame,
 
 static void
 free_state_images (unsigned max_level, bool_t color, word_t **state_image,
-		   u_word_t *offset, const unsigned *root_state,
-		   unsigned range_state, format_e format, const wfa_t *wfa)
+           u_word_t *offset, const unsigned *root_state,
+           unsigned range_state, format_e format, const wfa_t *wfa)
 /*
  *  Free memory of state images.
  *  For more details refer to the inverse function 'alloc_state_images()'.
@@ -1029,10 +1028,10 @@ free_state_images (unsigned max_level, bool_t color, word_t **state_image,
  *  No return value.
  *
  *  Side effects:
- *	arrays 'state_image' and 'offset' are discarded.
+ *  arrays 'state_image' and 'offset' are discarded.
  */
 {
-   word_t   marker;			/* ptr is required as a marker */
+   word_t   marker;         /* ptr is required as a marker */
    unsigned level;
 
    if (range_state > 0)
@@ -1047,19 +1046,19 @@ free_state_images (unsigned max_level, bool_t color, word_t **state_image,
        *  Initialize state image array with states at 'max_level'
        */
       for (state = wfa->basis_states; state <= root_state [Y]; state++)
-	 if (wfa->level_of_state [state] == max_level)
-	    state_image [state + max_level * wfa->states] = &marker;
+     if (wfa->level_of_state [state] == max_level)
+        state_image [state + max_level * wfa->states] = &marker;
 
       if (color)
       {
-	 if (format == FORMAT_4_2_0)
-	    level = max_level - 2;
-	 else
-	    level = max_level;
+     if (format == FORMAT_4_2_0)
+        level = max_level - 2;
+     else
+        level = max_level;
       
-	 for (; state < wfa->states; state++)
-	    if (wfa->level_of_state [state] == level)
-	       state_image [state + level * wfa->states] = &marker;
+     for (; state < wfa->states; state++)
+        if (wfa->level_of_state [state] == level)
+           state_image [state + level * wfa->states] = &marker;
       }
    }
    
@@ -1071,37 +1070,37 @@ free_state_images (unsigned max_level, bool_t color, word_t **state_image,
        *  Range approximation with child. 
        */
       for (state = 1; state < (range_state > 0 ?
-			       range_state + 1 : wfa->states); state++)
-	 if (state_image [state + level * wfa->states])
-	    for (label = 0; label < MAXLABELS; label++)
-	       if (ischild (child = wfa->tree[state][label]))
-	       {
-		  if (isedge (wfa->into[state][label][0])
-		      && (state_image [child + (level - 1) * wfa->states]
-			  != &marker))
-		     Free (state_image [child + (level - 1) * wfa->states]);
-		  state_image [child + (level - 1) * wfa->states] = &marker;
-	       }
+                   range_state + 1 : wfa->states); state++)
+     if (state_image [state + level * wfa->states])
+        for (label = 0; label < MAXLABELS; label++)
+           if (ischild (child = wfa->tree[state][label]))
+           {
+          if (isedge (wfa->into[state][label][0])
+              && (state_image [child + (level - 1) * wfa->states]
+              != &marker))
+             Free (state_image [child + (level - 1) * wfa->states]);
+          state_image [child + (level - 1) * wfa->states] = &marker;
+           }
       /*
        *  Range approximation with linear combination 
        */
       for (state = 1; state < (range_state > 0 ?
-			       range_state + 1 : wfa->states);
-	   state++)
-	 if (state_image [state + level * wfa->states])
-	    for (label = 0; label < MAXLABELS; label++)
-	       for (edge = 0; isedge (domain = wfa->into[state][label][edge]);
-		    edge++)
-		  if (domain > 0	
-		      && (state_image [domain + (level - 1) * wfa->states]
-			  != NULL)
-		      && (state_image [domain + (level - 1) * wfa->states]
-			  != &marker))
-		  {
-		     Free (state_image [domain + (level - 1) * wfa->states]);
-		     state_image [domain + (level - 1) * wfa->states]
-			= &marker;
-		  }
+                   range_state + 1 : wfa->states);
+       state++)
+     if (state_image [state + level * wfa->states])
+        for (label = 0; label < MAXLABELS; label++)
+           for (edge = 0; isedge (domain = wfa->into[state][label][edge]);
+            edge++)
+          if (domain > 0    
+              && (state_image [domain + (level - 1) * wfa->states]
+              != NULL)
+              && (state_image [domain + (level - 1) * wfa->states]
+              != &marker))
+          {
+             Free (state_image [domain + (level - 1) * wfa->states]);
+             state_image [domain + (level - 1) * wfa->states]
+            = &marker;
+          }
    }
    Free (state_image);
    Free (offset);
@@ -1109,7 +1108,7 @@ free_state_images (unsigned max_level, bool_t color, word_t **state_image,
 
 static void
 compute_state_images (unsigned max_level, word_t **simg,
-		      const u_word_t *offset, const wfa_t *wfa)
+              const u_word_t *offset, const wfa_t *wfa)
 /*
  *  Compute all state images of the 'wfa' at level {1, ... , 'max_level'}
  *  which are marked in the array 'simg' (offsets of state images
@@ -1121,8 +1120,8 @@ compute_state_images (unsigned max_level, word_t **simg,
  *  No return value.
  *
  *  Side effects:
- *	state images (given by pointers in the array 'state_image')
- *	are computed.
+ *  state images (given by pointers in the array 'state_image')
+ *  are computed.
  */
 {
    unsigned level, state;
@@ -1132,8 +1131,8 @@ compute_state_images (unsigned max_level, word_t **simg,
     */
 
    for (state = 1; state < wfa->states; state++)
-      if (simg [state] != NULL)		/* compute image at level 0 */
-	 *simg [state] = (int) (wfa->final_distribution[state] * 8 + .5) * 2;
+      if (simg [state] != NULL)     /* compute image at level 0 */
+     *simg [state] = (int) (wfa->final_distribution[state] * 8 + .5) * 2;
 
    /*
     *  Compute images of states
@@ -1153,351 +1152,351 @@ compute_state_images (unsigned max_level, word_t **simg,
       unsigned height = height_of_level (level - 1);
       
       for (state = 1; state < wfa->states; state++)
-	 if (simg [state + level * wfa->states] != NULL)
-	    for (label = 0; label < MAXLABELS; label++)
-	       if (isedge (wfa->into [state][label][0]))
-	       {
-		  unsigned  edge;
-		  int       domain;
-		  word_t   *range;	/* address of current range */
-		  bool_t    prediction_used; /* ND prediction found ? */
-
-		  /*
-		   *  Compute address of range image
-		   */
-		  if (level & 1)	/* split vertically */
-		  {
-		     range = simg [state + level * wfa->states]
-			     + label * (height_of_level (level - 1)
-					* offset [state
-						 + level * wfa->states]);
-		  }
-		  else			/* split horizontally */
-		  {
-		     range = simg [state + level * wfa->states]
-			     + label * width_of_level (level - 1);
-		  }
-
-		  /*
-		   *  Generate the state images by adding the corresponding 
-		   *  weighted state images:
-		   *  subimage [label] =
-		   *       weight_1 * image_1 + ... + weight_n * image_n
-		   */
-		  if (!ischild (domain = wfa->tree[state][label]))
-		     prediction_used = NO;
-		  else
-		  {
-		     unsigned  y;
-		     word_t   *src;
-		     word_t   *dst;
-		     unsigned  src_offset;
-		     unsigned  dst_offset;
-
-		     prediction_used = YES;
-		     /*
-		      *  Copy child image
-		      */
-		     src        = simg [domain + (level - 1) * wfa->states];
-		     src_offset = offset [domain + (level - 1) * wfa->states] ;
-		     dst        = range;
-		     dst_offset	= offset [state + level * wfa->states];
-		     for (y = height; y; y--)
-		     {
-			memcpy (dst, src, width * sizeof (word_t));
-			src += src_offset;
-			dst += dst_offset;
-		     }
-		  }
-
-		  if (!prediction_used
-		      && isedge (domain = wfa->into[state][label][0]))
-		  {
-		     /*
-		      *  If prediction is not used then the range is
-		      *  filled with the first domain. No addition is needed.
-		      */
-		     edge = 0;
-		     if (domain != 0)
-		     {
-			int	  weight;
-			word_t 	 *src;
-			unsigned  src_offset;
-
-			src        = simg [domain + ((level - 1)
-						     * wfa->states)];
-			src_offset = offset [domain + ((level - 1)
-						       * wfa->states)] - width;
-			weight     = wfa->int_weight [state][label][edge];
-			
-			if (width == 1)	/* can't add two-pixels in a row */
-			{
-			   word_t   *dst;
-			   unsigned  dst_offset;
-			   
-			   dst        = range;
-			   dst_offset = offset [state + level * wfa->states]
-					- width;
+     if (simg [state + level * wfa->states] != NULL)
+        for (label = 0; label < MAXLABELS; label++)
+           if (isedge (wfa->into [state][label][0]))
+           {
+          unsigned  edge;
+          int       domain;
+          word_t   *range;  /* address of current range */
+          bool_t    prediction_used; /* ND prediction found ? */
+
+          /*
+           *  Compute address of range image
+           */
+          if (level & 1)    /* split vertically */
+          {
+             range = simg [state + level * wfa->states]
+                 + label * (height_of_level (level - 1)
+                    * offset [state
+                         + level * wfa->states]);
+          }
+          else          /* split horizontally */
+          {
+             range = simg [state + level * wfa->states]
+                 + label * width_of_level (level - 1);
+          }
+
+          /*
+           *  Generate the state images by adding the corresponding 
+           *  weighted state images:
+           *  subimage [label] =
+           *       weight_1 * image_1 + ... + weight_n * image_n
+           */
+          if (!ischild (domain = wfa->tree[state][label]))
+             prediction_used = NO;
+          else
+          {
+             unsigned  y;
+             word_t   *src;
+             word_t   *dst;
+             unsigned  src_offset;
+             unsigned  dst_offset;
+
+             prediction_used = YES;
+             /*
+              *  Copy child image
+              */
+             src        = simg [domain + (level - 1) * wfa->states];
+             src_offset = offset [domain + (level - 1) * wfa->states] ;
+             dst        = range;
+             dst_offset = offset [state + level * wfa->states];
+             for (y = height; y; y--)
+             {
+            memcpy (dst, src, width * sizeof (word_t));
+            src += src_offset;
+            dst += dst_offset;
+             }
+          }
+
+          if (!prediction_used
+              && isedge (domain = wfa->into[state][label][0]))
+          {
+             /*
+              *  If prediction is not used then the range is
+              *  filled with the first domain. No addition is needed.
+              */
+             edge = 0;
+             if (domain != 0)
+             {
+            int   weight;
+            word_t   *src;
+            unsigned  src_offset;
+
+            src        = simg [domain + ((level - 1)
+                             * wfa->states)];
+            src_offset = offset [domain + ((level - 1)
+                               * wfa->states)] - width;
+            weight     = wfa->int_weight [state][label][edge];
+            
+            if (width == 1) /* can't add two-pixels in a row */
+            {
+               word_t   *dst;
+               unsigned  dst_offset;
+               
+               dst        = range;
+               dst_offset = offset [state + level * wfa->states]
+                    - width;
 #ifdef HAVE_SIGNED_SHIFT
-			   *dst++ = ((weight * (int) *src++) >> 10) << 1;
-#else 					/* not HAVE_SIGNED_SHIFT */
-			   *dst++ = ((weight * (int) *src++) / 1024) * 2;
+               *dst++ = ((weight * (int) *src++) >> 10) << 1;
+#else                   /* not HAVE_SIGNED_SHIFT */
+               *dst++ = ((weight * (int) *src++) / 1024) * 2;
 #endif /* not HAVE_SIGNED_SHIFT */
-			   if (height == 2) 
-			   {
-			      src += src_offset;
-			      dst += dst_offset;
+               if (height == 2) 
+               {
+                  src += src_offset;
+                  dst += dst_offset;
 #ifdef HAVE_SIGNED_SHIFT
-			      *dst++ = ((weight * (int) *src++) >> 10) << 1;
+                  *dst++ = ((weight * (int) *src++) >> 10) << 1;
 #else /* not HAVE_SIGNED_SHIFT */
-			      *dst++ = ((weight * (int) *src++) / 1024) * 2;
+                  *dst++ = ((weight * (int) *src++) / 1024) * 2;
 #endif /* not HAVE_SIGNED_SHIFT */
-			   }
-			}
-			else
-			{
-			   unsigned  y;
-			   int 	    *idst;
-			   unsigned  idst_offset;
-			   
-			   idst        = (int *) range;
-			   idst_offset = (offset [state + level * wfa->states]
-					  - width) / 2;
-			   for (y = height; y; y--)
-			   {
-			      int *comp_dst = idst + (width >> 1);
-			      
-			      for (; idst != comp_dst; )
- 			      {
-				 int tmp; /* temp. value of adjacent pixels */
+               }
+            }
+            else
+            {
+               unsigned  y;
+               int      *idst;
+               unsigned  idst_offset;
+               
+               idst        = (int *) range;
+               idst_offset = (offset [state + level * wfa->states]
+                      - width) / 2;
+               for (y = height; y; y--)
+               {
+                  int *comp_dst = idst + (width >> 1);
+                  
+                  for (; idst != comp_dst; )
+                  {
+                 int tmp; /* temp. value of adjacent pixels */
 #ifdef HAVE_SIGNED_SHIFT
-#	if BYTE_ORDER == LITTLE_ENDIAN
-                                 tmp = (((weight * (int) src [1]) >> 10) << 17)
-				       | (((weight * (int) src [0]) >> 9)
-					  & 0xfffe);
-#	else
-                                 tmp = (((weight * (int) src [0]) >> 10) << 17)
-				       | (((weight * (int) src [1]) >> 9)
-					  & 0xfffe);
-#	endif
+#   if BYTE_ORDER == LITTLE_ENDIAN
+                 tmp = (((weight * (int) src [1]) >> 10) << 17)
+                     | (((weight * (int) src [0]) >> 9)
+                        & 0xfffe);
+#   else
+                 tmp = (((weight * (int) src [0]) >> 10) << 17)
+                     | (((weight * (int) src [1]) >> 9)
+                        & 0xfffe);
+#   endif
 #else /* not HAVE_SIGNED_SHIFT */
-#	if BYTE_ORDER == LITTLE_ENDIAN
-                                 tmp = (((weight * (int) src [1]) / 1024)
-					* 131072)
-				       | (((weight * (int) src [0])/ 512)
-					  & 0xfffe);
-#	else
-                                 tmp = (((weight * (int) src [0]) / 1024)
-					* 131072)
-				       | (((weight * (int) src [1]) / 512)
-					  & 0xfffe);
-#	endif /* not WORDS_BIGENDIAN */
-#endif
-				 src    +=  2;
-				 *idst++ = tmp & 0xfffefffe;
-			      }
-			      src  += src_offset;
-			      idst += idst_offset;
-			   }
-			}
-		     }
-		     else
-		     {
-			int weight = (int) (wfa->weight[state][label][edge]
-					    * wfa->final_distribution[0]
-					    * 8 + .5) * 2;
-			/*
-			 *  Range needs domain 0
-			 *  (the constant function f(x, y) = 1),
-			 *  hence a faster algorithm is used.
-			 */
-			if (width == 1)	/* can't add two-pixels in a row */
-			{
-			   word_t   *dst;
-			   unsigned  dst_offset;
-			   
-			   dst        = range;
-			   dst_offset = offset [state + level * wfa->states]
-					- width;
-			   
-			   *dst++ = weight;
-			   if (height == 2)
-			   {
-			      dst += dst_offset;
-			      *dst++ = weight;
-			   }
-			}
-			else
-			{
-			   unsigned  x, y;
-			   int 	    *idst;
-			   unsigned  idst_offset;
-			   
-			   weight      = (weight * 65536) | (weight & 0xffff);
-			   idst	       = (int *) range;
-			   idst_offset = offset [state + level * wfa->states]
-					 / 2;
-			   for (x = width >> 1; x; x--)
-			      *idst++ = weight & 0xfffefffe;
-			   idst += (offset [state + level * wfa->states]
-				    - width) / 2;
-
-			   for (y = height - 1; y; y--)
-			   {
-			      memcpy (idst, idst - idst_offset,
-				      width * sizeof (word_t));
-			      idst += idst_offset;
-			   }
-			}
-		     }
-		     edge = 1;
-		  }
-		  else
-		     edge = 0;
-		  
-		  /*
-		   *  Add remaining weighted domain images to current range
-		   */
-		  for (; isedge (domain = wfa->into[state][label][edge]);
-		       edge++)
-		  {
-		     if (domain != 0)
-		     {
-			word_t 	 *src;
-			unsigned  src_offset;
-			int	  weight;
-
-			src        = simg [domain + (level - 1) * wfa->states];
-			src_offset = offset [domain + ((level - 1)
-						       * wfa->states)] - width;
-			weight     = wfa->int_weight [state][label][edge];
-			
-			if (width == 1)	/* can't add two-pixels in a row */
-			{
-			   word_t   *dst;
-			   unsigned  dst_offset;
-			   
-			   dst        = range;
-			   dst_offset = offset [state + level * wfa->states]
-					- width;
+#   if BYTE_ORDER == LITTLE_ENDIAN
+                 tmp = (((weight * (int) src [1]) / 1024)
+                        * 131072)
+                     | (((weight * (int) src [0])/ 512)
+                        & 0xfffe);
+#   else
+                 tmp = (((weight * (int) src [0]) / 1024)
+                        * 131072)
+                     | (((weight * (int) src [1]) / 512)
+                        & 0xfffe);
+#   endif
+#endif /* not HAVE_SIGNED_SHIFT */
+                 src    +=  2;
+                 *idst++ = tmp & 0xfffefffe;
+                  }
+                  src  += src_offset;
+                  idst += idst_offset;
+               }
+            }
+             }
+             else
+             {
+            int weight = (int) (wfa->weight[state][label][edge]
+                        * wfa->final_distribution[0]
+                        * 8 + .5) * 2;
+            /*
+             *  Range needs domain 0
+             *  (the constant function f(x, y) = 1),
+             *  hence a faster algorithm is used.
+             */
+            if (width == 1) /* can't add two-pixels in a row */
+            {
+               word_t   *dst;
+               unsigned  dst_offset;
+               
+               dst        = range;
+               dst_offset = offset [state + level * wfa->states]
+                    - width;
+               
+               *dst++ = weight;
+               if (height == 2)
+               {
+                  dst += dst_offset;
+                  *dst++ = weight;
+               }
+            }
+            else
+            {
+               unsigned  x, y;
+               int      *idst;
+               unsigned  idst_offset;
+               
+               weight      = (weight * 65536) | (weight & 0xffff);
+               idst        = (int *) range;
+               idst_offset = offset [state + level * wfa->states]
+                     / 2;
+               for (x = width >> 1; x; x--)
+                  *idst++ = weight & 0xfffefffe;
+               idst += (offset [state + level * wfa->states]
+                    - width) / 2;
+
+               for (y = height - 1; y; y--)
+               {
+                  memcpy (idst, idst - idst_offset,
+                      width * sizeof (word_t));
+                  idst += idst_offset;
+               }
+            }
+             }
+             edge = 1;
+          }
+          else
+             edge = 0;
+          
+          /*
+           *  Add remaining weighted domain images to current range
+           */
+          for (; isedge (domain = wfa->into[state][label][edge]);
+               edge++)
+          {
+             if (domain != 0)
+             {
+            word_t   *src;
+            unsigned  src_offset;
+            int   weight;
+
+            src        = simg [domain + (level - 1) * wfa->states];
+            src_offset = offset [domain + ((level - 1)
+                               * wfa->states)] - width;
+            weight     = wfa->int_weight [state][label][edge];
+            
+            if (width == 1) /* can't add two-pixels in a row */
+            {
+               word_t   *dst;
+               unsigned  dst_offset;
+               
+               dst        = range;
+               dst_offset = offset [state + level * wfa->states]
+                    - width;
 
 #ifdef HAVE_SIGNED_SHIFT
-			   *dst++ += ((weight * (int) *src++) >> 10) << 1;
+               *dst++ += ((weight * (int) *src++) >> 10) << 1;
 #else /* not HAVE_SIGNED_SHIFT */
-			   *dst++ += ((weight * (int) *src++) / 1024) * 2;
+               *dst++ += ((weight * (int) *src++) / 1024) * 2;
 #endif /* not HAVE_SIGNED_SHIFT */
-			   if (height == 2) 
-			   {
-			      src += src_offset;
-			      dst += dst_offset;
+               if (height == 2) 
+               {
+                  src += src_offset;
+                  dst += dst_offset;
 #ifdef HAVE_SIGNED_SHIFT
-			      *dst++ += ((weight * (int) *src++) >> 10) << 1;
+                  *dst++ += ((weight * (int) *src++) >> 10) << 1;
 #else /* not HAVE_SIGNED_SHIFT */
-			      *dst++ += ((weight * (int) *src++) / 1024) * 2;
+                  *dst++ += ((weight * (int) *src++) / 1024) * 2;
 #endif /* not HAVE_SIGNED_SHIFT */
-			   }
-			}
-			else
-			{
-			   int 	    *idst;
-			   unsigned  idst_offset;
-			   unsigned  y;
-			   
-			   idst        = (int *) range;
-			   idst_offset = (offset [state + level * wfa->states]
-					  - width) / 2;
-			   
-			   for (y = height; y; y--)
-			   {
-			      int *comp_dst = idst + (width >> 1);
-			      
-			      for (; idst != comp_dst;)
- 			      {
-				 int tmp; /* temp. value of adjacent pixels */
+               }
+            }
+            else
+            {
+               int      *idst;
+               unsigned  idst_offset;
+               unsigned  y;
+               
+               idst        = (int *) range;
+               idst_offset = (offset [state + level * wfa->states]
+                      - width) / 2;
+               
+               for (y = height; y; y--)
+               {
+                  int *comp_dst = idst + (width >> 1);
+                  
+                  for (; idst != comp_dst;)
+                  {
+                 int tmp; /* temp. value of adjacent pixels */
 #ifdef HAVE_SIGNED_SHIFT
-#	if BYTE_ORDER == LITTLE_ENDIAN
-                                 tmp = (((weight * (int) src [1]) >> 10) << 17)
-				       | (((weight * (int) src [0]) >> 9)
-					  & 0xfffe);
-#	else
-                                 tmp = (((weight * (int)src [0]) >> 10) << 17)
-				       | (((weight * (int)src [1]) >> 9)
-					  & 0xfffe);
-#	endif
+#   if BYTE_ORDER == LITTLE_ENDIAN
+                 tmp = (((weight * (int) src [1]) >> 10) << 17)
+                     | (((weight * (int) src [0]) >> 9)
+                        & 0xfffe);
+#   else
+                 tmp = (((weight * (int)src [0]) >> 10) << 17)
+                     | (((weight * (int)src [1]) >> 9)
+                        & 0xfffe);
+#   endif
 #else /* not HAVE_SIGNED_SHIFT */
-#	if BYTE_ORDER == LITTLE_ENDIAN
-                                 tmp = (((weight * (int) src [1]) / 1024)
-					* 131072)
-				       | (((weight * (int) src [0])/ 512)
-					  & 0xfffe);
-#	else
-                                 tmp = (((weight * (int) src [0]) / 1024)
-					* 131072)
-				       | (((weight * (int) src [1])/ 512)
-					  & 0xfffe);
-#	endif /* not WORDS_BIGENDIAN */
-#endif
-				 src +=  2;
-				 *idst = (*idst + tmp) & 0xfffefffe;
-				 idst++;
-			      }
-			      src  += src_offset;
-			      idst += idst_offset;
-			   }
-			}
-		     }
-		     else
-		     {
-			int weight = (int) (wfa->weight[state][label][edge]
-					    * wfa->final_distribution[0]
-					    * 8 + .5) * 2;
-			/*
-			 *  Range needs domain 0
-			 *  (the constant function f(x, y) = 1),
-			 *  hence a faster algorithm is used.
-			 */
-			if (width == 1)	/* can't add two-pixels in a row */
-			{
-			   word_t   *dst;
-			   unsigned  dst_offset;
-			   
-			   dst        = range;
-			   dst_offset = offset [state + level * wfa->states]
-					- width;
-			   
-			   *dst++ += weight;
-			   if (height == 2)
-			   {
-			      dst    += dst_offset;
-			      *dst++ += weight;
-			   }
-			}
-			else
-			{
-			   int 	    *idst;
-			   unsigned  idst_offset;
-			   unsigned  y;
-			   
-			   weight      = (weight * 65536) | (weight & 0xffff);
-			   idst	       = (int *) range;
-			   idst_offset = (offset [state + level * wfa->states]
-					  - width) /2;
-			   
-			   for (y = height; y; y--)
-			   {
-			      int *comp_dst = idst + (width >> 1);
-			      
-			      for (; idst != comp_dst; )
-			      {
-				 *idst = (*idst + weight) & 0xfffefffe;
+#   if BYTE_ORDER == LITTLE_ENDIAN
+                 tmp = (((weight * (int) src [1]) / 1024)
+                        * 131072)
+                     | (((weight * (int) src [0])/ 512)
+                        & 0xfffe);
+#   else
+                 tmp = (((weight * (int) src [0]) / 1024)
+                        * 131072)
+                     | (((weight * (int) src [1])/ 512)
+                        & 0xfffe);
+#   endif
+#endif /* not HAVE_SIGNED_SHIFT */
+                 src +=  2;
+                 *idst = (*idst + tmp) & 0xfffefffe;
+                 idst++;
+                  }
+                  src  += src_offset;
+                  idst += idst_offset;
+               }
+            }
+             }
+             else
+             {
+            int weight = (int) (wfa->weight[state][label][edge]
+                        * wfa->final_distribution[0]
+                        * 8 + .5) * 2;
+            /*
+             *  Range needs domain 0
+             *  (the constant function f(x, y) = 1),
+             *  hence a faster algorithm is used.
+             */
+            if (width == 1) /* can't add two-pixels in a row */
+            {
+               word_t   *dst;
+               unsigned  dst_offset;
+               
+               dst        = range;
+               dst_offset = offset [state + level * wfa->states]
+                    - width;
+               
+               *dst++ += weight;
+               if (height == 2)
+               {
+                  dst    += dst_offset;
+                  *dst++ += weight;
+               }
+            }
+            else
+            {
+               int      *idst;
+               unsigned  idst_offset;
+               unsigned  y;
+               
+               weight      = (weight * 65536) | (weight & 0xffff);
+               idst        = (int *) range;
+               idst_offset = (offset [state + level * wfa->states]
+                      - width) /2;
+               
+               for (y = height; y; y--)
+               {
+                  int *comp_dst = idst + (width >> 1);
+                  
+                  for (; idst != comp_dst; )
+                  {
+                 *idst = (*idst + weight) & 0xfffefffe;
                                  idst++;
-			      }
-			      idst += idst_offset;
-			   }
-			}
-		     }
-		  }
-	       } 
+                  }
+                  idst += idst_offset;
+               }
+            }
+             }
+          }
+           } 
    }
 }
 
@@ -1509,24 +1508,24 @@ duplicate_state_image (const word_t *domain, unsigned offset, unsigned level)
  *  to the lock 'pixels'.
  *
  *  Return value:
- *	pointer to the new domain block
+ *  pointer to the new domain block
  */
 {
    word_t *dst, *pixels;
-   int	   y, n;
+   int     y, n;
 
    dst = pixels = Calloc (size_of_level (level), sizeof (word_t));
 
    if (domain)
       for (y = height_of_level (level); y; y--)
       {
-	 memcpy (dst, domain, width_of_level (level) * sizeof (word_t));
-	 dst    += width_of_level (level);
-	 domain += offset;
+     memcpy (dst, domain, width_of_level (level) * sizeof (word_t));
+     dst    += width_of_level (level);
+     domain += offset;
       }
-   else					/* state 0 */
+   else                 /* state 0 */
       for (n = size_of_level (level); n; n--)
-	 *dst++ = (int) (128 * 8 + .5) * 2;
+     *dst++ = (int) (128 * 8 + .5) * 2;
 
    return pixels;
 }
diff --git a/converter/other/fiasco/codec/dfiasco.c b/converter/other/fiasco/codec/dfiasco.c
index 1cdfc672..2fdec573 100644
--- a/converter/other/fiasco/codec/dfiasco.c
+++ b/converter/other/fiasco/codec/dfiasco.c
@@ -14,8 +14,12 @@
  *  $State: Exp $
  */
 
+#include <stdlib.h>
 #include <string.h>
 
+#include "pm_c_util.h"
+#include "nstring.h"
+
 #include "config.h"
 
 #include "types.h"
@@ -112,7 +116,7 @@ fiasco_decoder_new (const char *filename, const fiasco_d_options_t *options)
 	    {
 	       set_error (_("Magnifaction factor `%d' is too large. "
 			    "Maximium value is %d."),
-			  dfiasco->enlarge_factor, max (0, n - 1));
+			  dfiasco->enlarge_factor, MAX(0, n - 1));
 	       fiasco_decoder_delete (decoder);
 	       return NULL;
 	    }
@@ -129,7 +133,7 @@ fiasco_decoder_new (const char *filename, const fiasco_d_options_t *options)
 	    {
 	       set_error (_("Magnifaction factor `%d' is too small. "
 			    "Minimum value is %d."),
-			  dfiasco->enlarge_factor, - max (0, n - 1));
+			  dfiasco->enlarge_factor, - MAX(0, n - 1));
 	       fiasco_decoder_delete (decoder);
 	       return NULL;
 	    }
diff --git a/converter/other/fiasco/codec/domain-pool.c b/converter/other/fiasco/codec/domain-pool.c
index 09f854a6..7cc3900e 100644
--- a/converter/other/fiasco/codec/domain-pool.c
+++ b/converter/other/fiasco/codec/domain-pool.c
@@ -17,16 +17,10 @@
 #include "config.h"
 
 #include <math.h>
+#include <stdlib.h>
+#include <string.h>
 
-#if STDC_HEADERS
-#   include <stdlib.h>
-#endif /* not STDC_HEADERS */
-
-#if HAVE_STRING_H
-#   include <string.h>
-#else /* not HAVE_STRING_H */
-#   include <strings.h>
-#endif /* not HAVE_STRING_H */
+#include "pm_c_util.h"
 
 #include "types.h"
 #include "macros.h"
@@ -466,7 +460,7 @@ qac_chroma (unsigned max_domains, const wfa_t *wfa, void *model)
                                 max_domains, wfa);
         for (n = 0; n < max_domains && domains [n] >= 0; n++)
             states [n] = domains [n];
-        max_domains = min (max_domains, n);
+        max_domains = MIN(max_domains, n);
         Free (domains);
 
         for (old = 0, new = 0; new < max_domains && old < qac_model->n; old++)
@@ -854,7 +848,7 @@ rle_chroma (unsigned max_domains, const wfa_t *wfa, void *model)
             states [n] = domains [n];
 
         assert (states [0] == 0);
-        max_domains = min (max_domains, n);
+        max_domains = MIN(max_domains, n);
         Free (domains);
 
         Free (rle_model->states);
diff --git a/converter/other/fiasco/codec/ip.c b/converter/other/fiasco/codec/ip.c
index caa97baf..ade0d916 100644
--- a/converter/other/fiasco/codec/ip.c
+++ b/converter/other/fiasco/codec/ip.c
@@ -282,7 +282,7 @@ standard_ip_image_state (unsigned address, unsigned level, unsigned domain,
    real_t   ip = 0, *imageptr, *stateptr;
 
    if (level > c->options.images_level)
-      error ("Level %d not supported.", level);
+      error ("We cannot interpret a Level %d image.", level);
    
    imageptr = &c->pixels [address * size_of_level (level)];
 
@@ -311,7 +311,7 @@ standard_ip_state_state (unsigned domain1, unsigned domain2, unsigned level,
    real_t   ip = 0, *state1ptr, *state2ptr;
 
    if (level > c->options.images_level)
-      error ("Level %d not supported.", level);
+      error ("We cannot interpret and image with Level %d.", level);
 
    state1ptr = c->images_of_state [domain1] + address_of_level (level);
    state2ptr = c->images_of_state [domain2] + address_of_level (level);
diff --git a/converter/other/fiasco/codec/motion.c b/converter/other/fiasco/codec/motion.c
index 92951281..876a2998 100644
--- a/converter/other/fiasco/codec/motion.c
+++ b/converter/other/fiasco/codec/motion.c
@@ -17,11 +17,9 @@
 
 #include "config.h"
 
-#if HAVE_STRING_H
-#	include <string.h>
-#else /* not HAVE_STRING_H */
-#	include <strings.h>
-#endif /* not HAVE_STRING_H */
+#include <string.h>
+
+#include "pm_c_util.h"
 
 #include "types.h"
 #include "macros.h"
@@ -54,10 +52,10 @@ restore_mc (int enlarge_factor, image_t *image, const image_t *past,
 
 #define FX(v) ((image->format == FORMAT_4_2_0) && band != Y ? ((v) / 2) : v)
    
-   mcblock1 = Calloc (size_of_level (max ((int) wfa->wfainfo->p_max_level
+   mcblock1 = Calloc (size_of_level (MAX((int) wfa->wfainfo->p_max_level
 					  + 2 * enlarge_factor, 0)),
 		      sizeof (word_t));
-   mcblock2 = Calloc (size_of_level (max ((int) wfa->wfainfo->p_max_level
+   mcblock2 = Calloc (size_of_level (MAX((int) wfa->wfainfo->p_max_level
 					  + 2 * enlarge_factor, 0)),
 		      sizeof (word_t));
 
diff --git a/converter/other/fiasco/codec/mwfa.c b/converter/other/fiasco/codec/mwfa.c
index 6f0af8be..43a7dae2 100644
--- a/converter/other/fiasco/codec/mwfa.c
+++ b/converter/other/fiasco/codec/mwfa.c
@@ -18,12 +18,9 @@
 #include "config.h"
 
 #include <ctype.h>
+#include <string.h>
 
-#if HAVE_STRING_H
-#	include <string.h>
-#else /* not HAVE_STRING_H */
-#	include <strings.h>
-#endif /* not HAVE_STRING_H */
+#include "pm_c_util.h"
 
 #include "types.h"
 #include "macros.h"
@@ -441,7 +438,7 @@ find_B_frame_mc (word_t *mcpe, real_t price, range_t *range,
    else					/* local exhaustive search */
    {
       /*
-       *  Keep forward and backward mv due to time constraints
+       *  Keep forward and backward mv because of time constraints
        */
 
       ifx = fx;
@@ -813,10 +810,10 @@ find_second_mv (real_t price, const image_t *original,
 
    sr = wi->search_range;
 
-   y0 = max ((int) -sr, *my - (int) local_range);
-   y1 = min ((int) sr, *my + (int) local_range);
-   x0 = max ((int) -sr, *mx - (int) local_range);
-   x1 = min ((int) sr, *mx + (int) local_range);
+   y0 = MAX((int) -sr, *my - (int) local_range);
+   y1 = MIN((int) sr, *my + (int) local_range);
+   x0 = MAX((int) -sr, *mx - (int) local_range);
+   x1 = MIN((int) sr, *mx + (int) local_range);
 
    *mx = *my = 0;
 
diff --git a/converter/other/fiasco/codec/options.c b/converter/other/fiasco/codec/options.c
index 77dbaf00..c8e4d2e2 100644
--- a/converter/other/fiasco/codec/options.c
+++ b/converter/other/fiasco/codec/options.c
@@ -20,12 +20,11 @@
 #include "config.h"
 
 #include <string.h>
-#if STDC_HEADERS
-#	include <stdlib.h>
-#endif /* not STDC_HEADERS */
-
+#include <stdlib.h>
 #include <stdio.h>
 
+#include "nstring.h"
+
 #include "types.h"
 #include "macros.h"
 #include "error.h"
diff --git a/converter/other/fiasco/codec/prediction.c b/converter/other/fiasco/codec/prediction.c
index 351ba9df..e056d10f 100644
--- a/converter/other/fiasco/codec/prediction.c
+++ b/converter/other/fiasco/codec/prediction.c
@@ -17,11 +17,7 @@
 
 #include "config.h"
 
-#if HAVE_STRING_H
-#	include <string.h>
-#else /* not HAVE_STRING_H */
-#	include <strings.h>
-#endif /* not HAVE_STRING_H */
+#include <string.h>
 
 #include "types.h"
 #include "macros.h"
diff --git a/converter/other/fiasco/codec/subdivide.c b/converter/other/fiasco/codec/subdivide.c
index b7982716..2ace18e4 100644
--- a/converter/other/fiasco/codec/subdivide.c
+++ b/converter/other/fiasco/codec/subdivide.c
@@ -16,11 +16,9 @@
 
 #include "config.h"
 
-#if HAVE_STRING_H
-#	include <string.h>
-#else /* not HAVE_STRING_H */
-#	include <strings.h>
-#endif /* not HAVE_STRING_H */
+#include <string.h>
+
+#include "pm_c_util.h"
 
 #include "types.h"
 #include "macros.h"
@@ -293,7 +291,7 @@ subdivide (real_t max_costs, unsigned band, int y_state, range_t *range,
 			  : rrange.y;
 	 
 	 /* 
-	  *  If neccessary compute the inner products of the new states
+	  *  If necessary compute the inner products of the new states
 	  *  (generated during the recursive approximation of child [0])
 	  */
 	 if (label && rrange.level <= c->options.lc_max_level)
@@ -304,7 +302,7 @@ subdivide (real_t max_costs, unsigned band, int y_state, range_t *range,
 	  *  Abort the recursion if 'subdivide_costs' exceed 'lincomb_costs'
 	  *  or 'max_costs'.
 	  */
-	 remaining_costs = min (lincomb_costs, max_costs) - subdivide_costs;
+	 remaining_costs = MIN(lincomb_costs, max_costs) - subdivide_costs;
 
 	 if (remaining_costs > 0)	/* still a way for improvement */
 	 {
@@ -356,7 +354,7 @@ subdivide (real_t max_costs, unsigned band, int y_state, range_t *range,
 	  *  If costs of subdivision exceed costs of linear combination 
 	  *  then abort recursion.
 	  */
-	 if (subdivide_costs >= min (lincomb_costs, max_costs)) 
+	 if (subdivide_costs >= MIN(lincomb_costs, max_costs)) 
 	 {
 	    subdivide_costs = MAXCOSTS;
 	    break; 
@@ -386,28 +384,28 @@ subdivide (real_t max_costs, unsigned band, int y_state, range_t *range,
     */
    if (try_mc || try_nd)		/* try prediction */
    {
-      real_t prediction_costs;	/* Costs arising from approx. the current
-				   range with prediction */
-
-      prediction_costs
-	 = predict_range (min (min (lincomb_costs, subdivide_costs),
-			       max_costs),
-			  price, range, wfa, c, band, y_state, states,
-			  &tree_model, &p_tree_model, domain_model,
-			  d_domain_model, coeff_model, d_coeff_model);
-      if (prediction_costs < MAXCOSTS)	/* prediction has smallest costs */
-      {
-	 c->domain_pool->model_free (domain_model);
-	 c->d_domain_pool->model_free (d_domain_model);
-	 c->domain_pool->model_free (lc_domain_model);
-	 c->d_domain_pool->model_free (lc_d_domain_model);
-	 c->coeff->model_free (coeff_model);
-	 c->d_coeff->model_free (d_coeff_model);
-	 c->coeff->model_free (lc_coeff_model);
-	 c->d_coeff->model_free (lc_d_coeff_model);
+       real_t prediction_costs;	/* Costs arising from approx. the current
+                                   range with prediction */
+
+       prediction_costs
+           = predict_range (MIN(MIN(lincomb_costs, subdivide_costs),
+                                max_costs),
+                            price, range, wfa, c, band, y_state, states,
+                            &tree_model, &p_tree_model, domain_model,
+                            d_domain_model, coeff_model, d_coeff_model);
+       if (prediction_costs < MAXCOSTS)	/* prediction has smallest costs */
+       {
+           c->domain_pool->model_free (domain_model);
+           c->d_domain_pool->model_free (d_domain_model);
+           c->domain_pool->model_free (lc_domain_model);
+           c->d_domain_pool->model_free (lc_d_domain_model);
+           c->coeff->model_free (coeff_model);
+           c->d_coeff->model_free (d_coeff_model);
+           c->coeff->model_free (lc_coeff_model);
+           c->d_coeff->model_free (lc_d_coeff_model);
 	 
-	 return prediction_costs;
-      }
+           return prediction_costs;
+       }
    }
 
    if (lincomb_costs >= MAXCOSTS && subdivide_costs >= MAXCOSTS)
diff --git a/converter/other/fiasco/codec/tiling.c b/converter/other/fiasco/codec/tiling.c
index e820f7fb..21e4428a 100644
--- a/converter/other/fiasco/codec/tiling.c
+++ b/converter/other/fiasco/codec/tiling.c
@@ -16,9 +16,9 @@
 
 #include "config.h"
 
-#if STDC_HEADERS
-#	include <stdlib.h>
-#endif /* not STDC_HEADERS */
+#include <stdlib.h>
+
+#include "pm_c_util.h"
 
 #include "types.h"
 #include "macros.h"
@@ -29,22 +29,7 @@
 #include "wfalib.h"
 #include "tiling.h"
 
-/*****************************************************************************
-
-				prototypes
-  
-*****************************************************************************/
-
-static int
-cmpdecvar (const void *value1, const void *value2);
-static int
-cmpincvar (const void *value1, const void *value2);
-
-/*****************************************************************************
 
-				public code
-  
-*****************************************************************************/
 
 typedef struct var_list
 {
@@ -52,6 +37,38 @@ typedef struct var_list
    real_t variance;			/* variance of tile */
 } var_list_t;
 
+#ifndef LITERAL_FN_DEF_MATCH
+static qsort_comparison_fn cmpincvar;
+#endif
+
+static int
+cmpincvar(const void * const value1,
+          const void * const value2) {
+/*----------------------------------------------------------------------------
+  Sorts by increasing variances (quicksort sorting function)
+-----------------------------------------------------------------------------*/
+    return
+        ((var_list_t *) value1)->variance - ((var_list_t *) value2)->variance;
+}
+
+
+
+#ifndef LITERAL_FN_DEF_MATCH
+static qsort_comparison_fn cmpdecvar;
+#endif
+
+static int
+cmpdecvar(const void * const value1,
+          const void * const value2) {
+/*----------------------------------------------------------------------------
+  Sorts by decreasing variances (quicksort sorting function).
+-----------------------------------------------------------------------------*/
+    return
+        ((var_list_t *) value2)->variance - ((var_list_t *) value1)->variance;
+}
+
+
+
 tiling_t *
 alloc_tiling (fiasco_tiling_e method, unsigned tiling_exponent,
 	      unsigned image_level)
@@ -146,7 +163,7 @@ perform_tiling (const image_t *image, tiling_t *tiling)
 	 unsigned    number;		/* number of image tiles */
 	 unsigned    lx       = log2 (image->width - 1) + 1; /* x level */
 	 unsigned    ly       = log2 (image->height - 1) + 1; /* y level */
-	 unsigned    level    = max (lx, ly) * 2 - ((ly == lx + 1) ? 1 : 0);
+	 unsigned    level    = MAX(lx, ly) * 2 - ((ly == lx + 1) ? 1 : 0);
 	 var_list_t *var_list = Calloc (tiles, sizeof (var_list_t));
 	 
 	 /*
@@ -207,33 +224,10 @@ perform_tiling (const image_t *image, tiling_t *tiling)
       }
       else
       {
-	 warning ("Unsupported image tiling method.\n"
+	 warning ("We do not know the tiling method.\n"
 		  "Skipping image tiling step.");
 	 tiling->exponent = 0;
       }
    }
 }
 
-/*****************************************************************************
-
-				private code
-  
-*****************************************************************************/
-
-static int
-cmpincvar (const void *value1, const void *value2)
-/*
- *  Sorts by increasing variances (quicksort sorting function).
- */
-{
-  return ((var_list_t *) value1)->variance - ((var_list_t *) value2)->variance;
-}
-
-static int
-cmpdecvar (const void *value1, const void *value2)
-/*
- *  Sorts by decreasing variances (quicksort sorting function).
- */
-{
-  return ((var_list_t *) value2)->variance - ((var_list_t *) value1)->variance;
-}
diff --git a/converter/other/fiasco/codec/wfa.h b/converter/other/fiasco/codec/wfa.h
index 8b9793f2..9253affd 100644
--- a/converter/other/fiasco/codec/wfa.h
+++ b/converter/other/fiasco/codec/wfa.h
@@ -19,7 +19,7 @@
 
 #define MAXEDGES  5
 #define MAXSTATES 6000
-#define MAXLABELS 2			/* only bintree supported anymore */
+#define MAXLABELS 2			/* only bintree possible anymore */
 #define MAXLEVEL  22 
 
 #define FIASCO_BINFILE_RELEASE   2
@@ -122,7 +122,7 @@ typedef struct wfa
    real_t	*final_distribution;    /* one pixel images */
    byte_t	*level_of_state;	/* level of the image part which is
 					   represented by the current state */
-   byte_t	*domain_type;		/* Bit_0==1: auxilliary state
+   byte_t	*domain_type;		/* Bit_0==1: auxiliary state
 					   Bit_1==1: used for Y compr */
    mv_t		(*mv_tree)[MAXLABELS];	/* motion vectors */
    word_t	(*tree)[MAXLABELS];	/* bintree partitioning */
diff --git a/converter/other/fiasco/codec/wfalib.c b/converter/other/fiasco/codec/wfalib.c
index a3acb975..61d64d2f 100644
--- a/converter/other/fiasco/codec/wfalib.c
+++ b/converter/other/fiasco/codec/wfalib.c
@@ -19,12 +19,11 @@
 
 #include "config.h"
 
-#if STDC_HEADERS
-#	include <stdlib.h>
-#endif /* not STDC_HEADERS */
-
+#include <stdlib.h>
 #include <string.h>
 
+#include "pm_c_util.h"
+
 #include "types.h"
 #include "macros.h"
 #include "error.h"
@@ -218,7 +217,7 @@ compute_hits (unsigned from, unsigned to, unsigned n, const wfa_t *wfa)
 
    qsort (hits + 1, to - 1, sizeof (pair_t), sort_desc_pair);
 
-   n       = min (to, n);
+   n       = MIN(to, n);
    domains = Calloc (n + 1, sizeof (word_t));
 
    for (domain = 0; domain < (int) n && (!domain || hits [domain].key);
@@ -486,7 +485,7 @@ compute_spiral (int *vorder, unsigned image_width, unsigned image_height,
    
    lx     = log2 (image_width - 1) + 1;
    ly     = log2 (image_height - 1) + 1;
-   level  = max (lx, ly) * 2 - ((ly == lx + 1) ? 1 : 0);
+   level  = MAX(lx, ly) * 2 - ((ly == lx + 1) ? 1 : 0);
    tiles  = 1 << tiling_exp;		/* Number of image tiles */
    width  = width_of_level (level - tiling_exp);
    height = height_of_level (level - tiling_exp);
diff --git a/converter/other/fiasco/config.h b/converter/other/fiasco/config.h
index 64b905f8..57b3518d 100644
--- a/converter/other/fiasco/config.h
+++ b/converter/other/fiasco/config.h
@@ -56,9 +56,6 @@
 /* Define if you have the strcasecmp function.  */
 #define HAVE_STRCASECMP 1
 
-/* Define if you have the strdup function.  */
-#define HAVE_STRDUP 1
-
 /* Define if you have the <X11/extensions/XShm.h> header file.  */
 /* #undef HAVE_X11_EXTENSIONS_XSHM_H */
 
diff --git a/converter/other/fiasco/display.c b/converter/other/fiasco/display.c
index 9e531149..cf160329 100644
--- a/converter/other/fiasco/display.c
+++ b/converter/other/fiasco/display.c
@@ -27,16 +27,8 @@
 #include <X11/Xutil.h>
 #include <X11/keysym.h>
 
-#if STDC_HEADERS
-#	include <stdlib.h>
-#	include <string.h>
-#else /* not STDC_HEADERS */
-#	if HAVE_STRING_H
-#		include <string.h>
-#	else /* not HAVE_STRING_H */
-#		include <strings.h>
-#	endif /* not HAVE_STRING_H */
-#endif /* not STDC_HEADERS */
+#include <stdlib.h>
+#include <string.h>
 
 #include "types.h"
 #include "macros.h"
@@ -315,7 +307,8 @@ alloc_ximage (x11_info_t *xinfo, unsigned width, unsigned height)
       shmem_flag = 0;
       if (fiasco_get_verbosity ())
 	 fprintf (stderr,
-		  "Shared memory not supported\nReverting to normal Xlib.\n");
+              "Shared memory does not work on this system\n"
+              "Reverting to normal Xlib.\n");
    }
 
    if (shmem_flag)
diff --git a/converter/other/fiasco/fiascotopnm.c b/converter/other/fiasco/fiascotopnm.c
index 6d8b6f7f..dfba2256 100644
--- a/converter/other/fiasco/fiascotopnm.c
+++ b/converter/other/fiasco/fiascotopnm.c
@@ -25,6 +25,8 @@
 #include <string.h>
 #include <math.h>
 
+#include "nstring.h"
+
 #include "types.h"
 #include "macros.h"
 
@@ -176,21 +178,21 @@ checkargs (int argc, char **argv, bool_t *double_resolution, bool_t *panel,
     *options = fiasco_d_options_new ();
 
     {
-        int n = *((int *) parameter_value (params, "smoothing"));
+        int const n = *((int *) parameter_value (params, "smoothing"));
       
-        if (!fiasco_d_options_set_smoothing (*options, max (-1, n)))
+        if (!fiasco_d_options_set_smoothing (*options, MAX(-1, n)))
             error (fiasco_get_error_message ());
     }
 
     {
-        int n = *((int *) parameter_value (params, "magnify"));
+        int const n = *((int *) parameter_value (params, "magnify"));
       
         if (!fiasco_d_options_set_magnification (*options, n))
             error (fiasco_get_error_message ());
     }
    
     {
-        bool_t n = *((bool_t *) parameter_value (params, "fast"));
+        bool_t const n = *((bool_t *) parameter_value (params, "fast"));
       
         if (!fiasco_d_options_set_4_2_0_format (*options, n > 0 ? YES : NO))
             error (fiasco_get_error_message ());
diff --git a/converter/other/fiasco/getopt.c b/converter/other/fiasco/getopt.c
index 0b2d1b75..2f45c7cc 100644
--- a/converter/other/fiasco/getopt.c
+++ b/converter/other/fiasco/getopt.c
@@ -73,15 +73,7 @@
 #include <unistd.h>
 #endif	/* GNU C library.  */
 
-#ifdef VMS
-#include <unixlib.h>
-#if HAVE_STRING_H - 0
-#include <string.h>
-#endif
-#endif
-
-#if defined (WIN32) && !defined (__CYGWIN32__)
-/* It's not Unix, really.  See?  Capital letters.  */
+#if MSVCRT
 #include <windows.h>
 #define getpid() GetCurrentProcessId()
 #endif
diff --git a/converter/other/fiasco/input/basis.c b/converter/other/fiasco/input/basis.c
index cef075e6..4a748f61 100644
--- a/converter/other/fiasco/input/basis.c
+++ b/converter/other/fiasco/input/basis.c
@@ -16,6 +16,8 @@
 
 #include "config.h"
 
+#include "nstring.h"
+
 #include "types.h"
 #include "macros.h"
 #include "error.h"
diff --git a/converter/other/fiasco/input/read.c b/converter/other/fiasco/input/read.c
index 26bae7e4..e6e2d7e8 100644
--- a/converter/other/fiasco/input/read.c
+++ b/converter/other/fiasco/input/read.c
@@ -23,6 +23,8 @@
 
 #include <string.h>
 
+#include "nstring.h"
+
 #include "types.h"
 #include "macros.h"
 #include "error.h"
@@ -155,7 +157,7 @@ open_wfa (const char *filename, wfa_info_t *wi)
 	 unsigned lx = log2 (wi->width - 1) + 1;
 	 unsigned ly = log2 (wi->height - 1) + 1;
       
-	 wi->level = max (lx, ly) * 2 - ((ly == lx + 1) ? 1 : 0);
+	 wi->level = MAX(lx, ly) * 2 - ((ly == lx + 1) ? 1 : 0);
       }
       wi->chroma_max_states = wi->color ? read_rice_code (rice_k, input) : -1;
       wi->p_min_level       = read_rice_code (rice_k, input);
@@ -275,7 +277,7 @@ read_basis (const char *filename, wfa_t *wfa)
     *   string		|MAGIC Number "Wfa"
     *	int		|Number of basis states 'N'
     *	bool_t-array[N]	|use vector in linear combinations,
-    *			|0: don't use vector (auxilliary state)
+    *			|0: don't use vector (auxiliary state)
     *			|1: use vector in linear combinations
     *	float-array[N]	|final distribution of every state
     *
@@ -395,7 +397,7 @@ read_next_wfa (wfa_t *wfa, bitfile_t *input)
 
    /*
     *  Compute domain pool.
-    *  Large images have not been used due to image tiling.
+    *  Large images have not been used because of image tiling.
     */
    {
       unsigned state;
diff --git a/converter/other/fiasco/input/weights.c b/converter/other/fiasco/input/weights.c
index 55339980..15c35731 100644
--- a/converter/other/fiasco/input/weights.c
+++ b/converter/other/fiasco/input/weights.c
@@ -1,8 +1,8 @@
 /*
- *  weights.c:		Input of weights
+ *  weights.c:          Input of weights
  *
- *  Written by:		Ullrich Hafner
- *		
+ *  Written by:         Ullrich Hafner
+ *              
  *  This file is part of FIASCO («F»ractal «I»mage «A»nd «S»equence «CO»dec)
  *  Copyright (C) 1994-2000 Ullrich Hafner <hafner@bigfoot.de>
  */
@@ -16,6 +16,8 @@
 
 #include "config.h"
 
+#include "pm_c_util.h"
+
 #include "types.h"
 #include "macros.h"
 #include "error.h"
@@ -29,7 +31,7 @@
 
 /*****************************************************************************
 
-				public code
+                                public code
   
 *****************************************************************************/
 
@@ -42,17 +44,17 @@ read_weights (unsigned total, wfa_t *wfa, bitfile_t *input)
  *  No return value.
  *
  *  Side effects:
- *	'wfa->weights' are filled with the decoded values
+ *      'wfa->weights' are filled with the decoded values
  */
 {
-   unsigned	    state;
-   unsigned	    label;
-   unsigned	    edge;		/* current edge */
-   unsigned	   *weights_array;	/* array of weights to encode */
-   unsigned	   *level_array;	/* array of corresponding levels */
-   unsigned	    offset1, offset2;	/* prob. model offsets. */
-   unsigned	    offset3, offset4;	/* prob. model offsets. */
-   bool_t	    delta_approx = NO; 	/* true if delta has been used */
+   unsigned         state;
+   unsigned         label;
+   unsigned         edge;               /* current edge */
+   unsigned        *weights_array;      /* array of weights to encode */
+   unsigned        *level_array;        /* array of corresponding levels */
+   unsigned         offset1, offset2;   /* prob. model offsets. */
+   unsigned         offset3, offset4;   /* prob. model offsets. */
+   bool_t           delta_approx = NO;  /* true if delta has been used */
    
    /*
     *  Check whether delta approximation has been used
@@ -60,52 +62,54 @@ read_weights (unsigned total, wfa_t *wfa, bitfile_t *input)
    for (state = wfa->basis_states; state < wfa->states; state++)
       if (wfa->delta_state [state])
       {
-	 delta_approx = YES;
-	 break;
+         delta_approx = YES;
+         break;
       }
   
    /*
     *  Generate array of corresponding levels (context of probability model)
     */
    {
-      int 	min_level, max_level; 	/* min and max range level */
-      int 	d_min_level, d_max_level; /* min and max range level (delta) */
-      unsigned *lptr;			/* pointer to current corresp. level */
-      int	domain;			/* current domain */
-      bool_t	dc, d_dc;		/* indicates whether DC is used */
+      int       min_level, max_level;   /* min and max range level */
+      int       d_min_level, d_max_level; /* min and max range level (delta) */
+      unsigned *lptr;                   /* pointer to current corresp. level */
+      int       domain;                 /* current domain */
+      bool_t    dc, d_dc;               /* indicates whether DC is used */
 
       /*
        *  Compute minimum and maximum level of delta and normal approximations
        */
       min_level = d_min_level = MAXLEVEL;
       max_level = d_max_level = 0;
-      dc 	= d_dc	   = NO;
+      dc        = d_dc     = NO;
    
       for (state = wfa->basis_states; state < wfa->states; state++)
-	 for (label = 0; label < MAXLABELS; label++)
-	    if (isrange (wfa->tree [state][label]))
-	    {
-	       if (delta_approx && wfa->delta_state [state])
-	       {
-		  d_min_level = min (d_min_level,
-				     wfa->level_of_state [state] - 1);
-		  d_max_level = max (d_max_level,
-				     wfa->level_of_state [state] - 1);
-		  if (wfa->into [state][label][0] == 0)
-		     d_dc = YES;
-	       }
-	       else
-	       {
-		  min_level = min (min_level, wfa->level_of_state [state] - 1);
-		  max_level = max (max_level, wfa->level_of_state [state] - 1);
-		  if (wfa->into [state][label][0] == 0)
-		     dc = YES;
-	       }
-	    }
-      if (min_level > max_level)		/* no lc found */
-	 max_level = min_level - 1;
+          for (label = 0; label < MAXLABELS; label++)
+              if (isrange (wfa->tree [state][label]))
+              {
+                  if (delta_approx && wfa->delta_state [state])
+                  {
+                      d_min_level =
+                          MIN(d_min_level, wfa->level_of_state [state] - 1);
+                      d_max_level =
+                          MAX(d_max_level, wfa->level_of_state [state] - 1);
+                      if (wfa->into [state][label][0] == 0)
+                          d_dc = YES;
+                  }
+                  else
+                  {
+                      min_level =
+                          MIN(min_level, wfa->level_of_state [state] - 1);
+                      max_level =
+                          MAX(max_level, wfa->level_of_state [state] - 1);
+                      if (wfa->into [state][label][0] == 0)
+                          dc = YES;
+                  }
+              }
+      if (min_level > max_level)                /* no lc found */
+         max_level = min_level - 1;
       if (d_min_level > d_max_level)
-	 d_max_level = d_min_level - 1;
+         d_max_level = d_min_level - 1;
 
       offset1 = dc ? 1 : 0;
       offset2 = offset1 + (d_dc ? 1 : 0);
@@ -114,47 +118,47 @@ read_weights (unsigned total, wfa_t *wfa, bitfile_t *input)
 
       lptr = level_array = Calloc (total, sizeof (int));
       for (state = wfa->basis_states; state < wfa->states; state++)
-	 for (label = 0; label < MAXLABELS; label++)
-	    if (isrange (wfa->tree[state][label]))
-	       for (edge = 0; isedge (domain = wfa->into[state][label][edge]);
-		    edge++)
-	       {
-		  if ((unsigned) (lptr - level_array) >= total)
-		     error ("Can't read more than %d weights.", total);
-		  if (domain)
-		  {
-		     if (delta_approx && wfa->delta_state [state])
-			*lptr++ = offset3 + wfa->level_of_state [state]
-				  - 1 - d_min_level;
-		     else
-			*lptr++ = offset2 + wfa->level_of_state [state]
-				  - 1 - min_level;
-		  }
-		  else
-		     *lptr++ = delta_approx && wfa->delta_state [state]
-			       ? offset1 : 0;
-	       }
+         for (label = 0; label < MAXLABELS; label++)
+            if (isrange (wfa->tree[state][label]))
+               for (edge = 0; isedge (domain = wfa->into[state][label][edge]);
+                    edge++)
+               {
+                  if ((unsigned) (lptr - level_array) >= total)
+                     error ("Can't read more than %d weights.", total);
+                  if (domain)
+                  {
+                     if (delta_approx && wfa->delta_state [state])
+                        *lptr++ = offset3 + wfa->level_of_state [state]
+                                  - 1 - d_min_level;
+                     else
+                        *lptr++ = offset2 + wfa->level_of_state [state]
+                                  - 1 - min_level;
+                  }
+                  else
+                     *lptr++ = delta_approx && wfa->delta_state [state]
+                               ? offset1 : 0;
+               }
    }
 
    /*
     *  Decode the list of weights with an arithmetic decoder
     */
    {
-      unsigned	      i;
-      unsigned	     *c_symbols = Calloc (offset4, sizeof (unsigned));
-      const unsigned  scale 	= 500; 	/* scaling of probability model */
+      unsigned        i;
+      unsigned       *c_symbols = Calloc (offset4, sizeof (unsigned));
+      const unsigned  scale     = 500;  /* scaling of probability model */
 
       c_symbols [0] = 1 << (wfa->wfainfo->dc_rpf->mantissa_bits + 1);
       if (offset1 != offset2)
-	 c_symbols [offset1] = 1 << (wfa->wfainfo->d_dc_rpf->mantissa_bits
-				     + 1);
+         c_symbols [offset1] = 1 << (wfa->wfainfo->d_dc_rpf->mantissa_bits
+                                     + 1);
       for (i = offset2; i < offset3; i++)
-	 c_symbols [i] = 1 << (wfa->wfainfo->rpf->mantissa_bits + 1);
+         c_symbols [i] = 1 << (wfa->wfainfo->rpf->mantissa_bits + 1);
       for (; i < offset4; i++)
-	 c_symbols [i] = 1 << (wfa->wfainfo->d_rpf->mantissa_bits + 1);
+         c_symbols [i] = 1 << (wfa->wfainfo->d_rpf->mantissa_bits + 1);
       
       weights_array = decode_array (input, level_array, c_symbols,
-				    offset4, total, scale);
+                                    offset4, total, scale);
       Free (c_symbols);
    }
    Free (level_array);
@@ -163,36 +167,36 @@ read_weights (unsigned total, wfa_t *wfa, bitfile_t *input)
     *  Update transitions with decoded weights
     */
    {
-      unsigned *wptr = weights_array;	/* pointer to current weight */
-      int	domain;			/* current domain */
+      unsigned *wptr = weights_array;   /* pointer to current weight */
+      int       domain;                 /* current domain */
 
       for (state = wfa->basis_states; state < wfa->states; state++)
-	 for (label = 0; label < MAXLABELS; label++)
-	    if (isrange (wfa->tree[state][label]))
-	       for (edge = 0; isedge (domain = wfa->into[state][label][edge]);
-		    edge++)
-	       {
-		  if (domain)		/* not DC component */
-		  {
-		     if (delta_approx && wfa->delta_state [state])
-			wfa->weight [state][label][edge]
-			   = btor (*wptr++, wfa->wfainfo->d_rpf);
-		     else
-			wfa->weight [state][label][edge]
-			   = btor (*wptr++, wfa->wfainfo->rpf);
-		  }
-		  else
-		  {
-		     if (delta_approx && wfa->delta_state [state])
-			wfa->weight [state][label][edge]
-			   = btor (*wptr++, wfa->wfainfo->d_dc_rpf);
-		     else
-			wfa->weight [state][label][edge]
-			   = btor (*wptr++, wfa->wfainfo->dc_rpf);
-		  }
-		  wfa->int_weight [state][label][edge]
-		     = wfa->weight [state][label][edge] * 512 + 0.5;
-	       }
+         for (label = 0; label < MAXLABELS; label++)
+            if (isrange (wfa->tree[state][label]))
+               for (edge = 0; isedge (domain = wfa->into[state][label][edge]);
+                    edge++)
+               {
+                  if (domain)           /* not DC component */
+                  {
+                     if (delta_approx && wfa->delta_state [state])
+                        wfa->weight [state][label][edge]
+                           = btor (*wptr++, wfa->wfainfo->d_rpf);
+                     else
+                        wfa->weight [state][label][edge]
+                           = btor (*wptr++, wfa->wfainfo->rpf);
+                  }
+                  else
+                  {
+                     if (delta_approx && wfa->delta_state [state])
+                        wfa->weight [state][label][edge]
+                           = btor (*wptr++, wfa->wfainfo->d_dc_rpf);
+                     else
+                        wfa->weight [state][label][edge]
+                           = btor (*wptr++, wfa->wfainfo->dc_rpf);
+                  }
+                  wfa->int_weight [state][label][edge]
+                     = wfa->weight [state][label][edge] * 512 + 0.5;
+               }
    }
    
    Free (weights_array);
diff --git a/converter/other/fiasco/lib/arith.c b/converter/other/fiasco/lib/arith.c
index e3745bf7..dc35d1d1 100644
--- a/converter/other/fiasco/lib/arith.c
+++ b/converter/other/fiasco/lib/arith.c
@@ -90,7 +90,7 @@ encode_symbol (unsigned symbol, arith_t *arith, model_t *model)
  *  The current state of the arithmetic coder is given by 'arith'.
  *  Output bits are appended to the stream 'output'.
  *
- *  The model is updated after encoding the symbol (if neccessary the
+ *  The model is updated after encoding the symbol (if necessary the
  *  symbol counts are rescaled).
  *  
  *  Return value:
@@ -354,7 +354,7 @@ decode_symbol (arith_t *arith, model_t *model)
  *  Decode the next symbol - the state of the arithmetic decoder
  *  is given in 'arith'. Read refinement bits from the stream 'input'
  *  and use the given probability 'model'. Update the probability model after
- *  deconding the symbol (if neccessary also rescale the symbol counts).
+ *  deconding the symbol (if necessary also rescale the symbol counts).
  *  
  *  Return value:
  *	decoded symbol
diff --git a/converter/other/fiasco/lib/bit-io.c b/converter/other/fiasco/lib/bit-io.c
index 364a1c05..1bfef598 100644
--- a/converter/other/fiasco/lib/bit-io.c
+++ b/converter/other/fiasco/lib/bit-io.c
@@ -20,9 +20,9 @@
 #include "config.h"
 
 #include <string.h>
-#if STDC_HEADERS
-#   include <stdlib.h>
-#endif /* not STDC_HEADERS */
+#include <stdlib.h>
+
+#include "nstring.h"
 
 #include "macros.h"
 #include "types.h"
diff --git a/converter/other/fiasco/lib/dither.c b/converter/other/fiasco/lib/dither.c
index a39afa3c..accd9dd6 100644
--- a/converter/other/fiasco/lib/dither.c
+++ b/converter/other/fiasco/lib/dither.c
@@ -38,14 +38,8 @@
 #include "pm_config.h"
 #include "config.h"
 
-#if HAVE_STRING_H
-#	include <string.h>
-#else /* not HAVE_STRING_H */
-#	include <strings.h>
-#endif /* not HAVE_STRING_H */
-#if STDC_HEADERS
-#	include <stdlib.h>
-#endif /* not STDC_HEADERS */
+#include <string.h>
+#include <stdlib.h>
 
 #include "types.h"
 #include "macros.h"
@@ -65,19 +59,22 @@
 static int 
 display_16_bit (const struct fiasco_renderer *this, unsigned char *ximage,
 		const fiasco_image_t *fiasco_image);
+
 static int 
 display_24_bit_bgr (const struct fiasco_renderer *this, unsigned char *ximage,
 		    const fiasco_image_t *fiasco_image);
+
 static int 
 display_24_bit_rgb (const struct fiasco_renderer *this, unsigned char *ximage,
 		    const fiasco_image_t *fiasco_image);
+
 static int 
 display_32_bit (const struct fiasco_renderer *this, unsigned char *ximage,
 		const fiasco_image_t *fiasco_image);
+
 static int
 free_bits_at_bottom (unsigned long a);
-static int
-free_bits_at_top (unsigned long a);
+
 static int
 number_of_bits_set (unsigned long a);
 
@@ -345,21 +342,6 @@ number_of_bits_set (unsigned long a)
 }
 
 static int
-free_bits_at_top (unsigned long a)
-/*
- *  How many 0 bits are there at most significant end of longword.
- *  Low performance, do not call often.
- */
-{
-   if(!a)				/* assume char is 8 bits */
-      return sizeof (unsigned long) * 8;
-   else if (((long) a) < 0l)		/* assume twos complement */
-      return 0;
-   else
-      return 1 + free_bits_at_top ( a << 1);
-}
-
-static int
 free_bits_at_bottom (unsigned long a)
 /*
  *  How many 0 bits are there at least significant end of longword.
diff --git a/converter/other/fiasco/lib/error.c b/converter/other/fiasco/lib/error.c
index b858badf..ee3afe1f 100644
--- a/converter/other/fiasco/lib/error.c
+++ b/converter/other/fiasco/lib/error.c
@@ -29,18 +29,9 @@
 #include <stdio.h>
 #include <errno.h>
 
-#if STDC_HEADERS
-#	include <stdarg.h>
-#	define VA_START(args, lastarg) va_start(args, lastarg)
-#else  /* not STDC_HEADERS */
-#	include <varargs.h>
-#	define VA_START(args, lastarg) va_start(args)
-#endif /* not STDC_HEADERS */
-#if HAVE_STRING_H
-#	include <string.h>
-#else /* not HAVE_STRING_H */
-#	include <strings.h>
-#endif /* not HAVE_STRING_H */
+#include <stdarg.h>
+#define VA_START(args, lastarg) va_start(args, lastarg)
+#include <string.h>
 
 #if HAVE_SETJMP_H
 #	include <setjmp.h>
@@ -117,11 +108,7 @@ set_error (const char *format, ...)
       Free (error_message);
    error_message = Calloc (len, sizeof (char));
    
-#if HAVE_VPRINTF
    vsprintf (error_message, format, args);
-#elif HAVE_DOPRNT
-   _doprnt (format, args, stderr);
-#endif /* HAVE_DOPRNT */
 
    va_end (args);
 }
@@ -178,11 +165,7 @@ error (const char *format, ...)
       Free (error_message);
    error_message = Calloc (len, sizeof (char));
    
-#if HAVE_VPRINTF
    vsprintf (error_message, format, args);
-#elif HAVE_DOPRNT
-   _doprnt (format, args, stderr);
-#endif /* HAVE_DOPRNT */
 
    va_end (args);
    
@@ -236,11 +219,7 @@ warning (const char *format, ...)
       return;
 	
    fprintf (stderr, "Warning: ");
-#if HAVE_VPRINTF
    vfprintf (stderr, format, args);
-#elif HAVE_DOPRNT
-   _doprnt (format, args, stderr);
-#endif /* HAVE_DOPRNT */
    fputc ('\n', stderr);
 
    va_end (args);
@@ -259,11 +238,7 @@ message (const char *format, ...)
    if (verboselevel == FIASCO_NO_VERBOSITY)
       return;
 
-#if HAVE_VPRINTF
    vfprintf (stderr, format, args);
-#elif HAVE_DOPRNT
-   _doprnt (format, args, stderr);
-#endif /* HAVE_DOPRNT */
    fputc ('\n', stderr);
    va_end (args);
 }
@@ -282,11 +257,7 @@ debug_message (const char *format, ...)
       return;
 
    fprintf (stderr, "*** ");
-#if HAVE_VPRINTF
    vfprintf (stderr, format, args);
-#elif HAVE_DOPRNT
-   _doprnt (format, args, stderr);
-#endif /* HAVE_DOPRNT */
    fputc ('\n', stderr);
    va_end (args);
 }
@@ -304,11 +275,7 @@ info (const char *format, ...)
    if (verboselevel == FIASCO_NO_VERBOSITY)
       return;
 
-#if HAVE_VPRINTF
    vfprintf (stderr, format, args);
-#elif HAVE_DOPRNT
-   _doprnt (format, args, stderr);
-#endif /* HAVE_DOPRNT */
    fflush (stderr);
    va_end (args);
 }
diff --git a/converter/other/fiasco/lib/image.c b/converter/other/fiasco/lib/image.c
index 0168734c..fa3b2db5 100644
--- a/converter/other/fiasco/lib/image.c
+++ b/converter/other/fiasco/lib/image.c
@@ -18,6 +18,8 @@
 
 #include <string.h>
 
+#include "nstring.h"
+
 #include "types.h"
 #include "macros.h"
 #include "error.h"
@@ -239,7 +241,7 @@ alloc_image (unsigned width, unsigned height, bool_t color, format_e format)
    image->format      = format;
    image->reference_count = 1;
    
-   strcpy (image->id, "IFIASCO");
+   STRSCPY(image->id, "IFIASCO");
 
    for (band = first_band (color); band <= last_band (color); band++)
       if (format == FORMAT_4_2_0 && band != Y)
@@ -447,7 +449,7 @@ write_image (const char *image_name, const image_t *image)
    
    if (image->format == FORMAT_4_2_0)
    {
-      warning ("Writing of images in 4:2:0 format not supported.");
+      warning ("We cannot write images in 4:2:0 format.");
       return;
    }
    
diff --git a/converter/other/fiasco/lib/list.c b/converter/other/fiasco/lib/list.c
index 9f516c2e..bb4efae1 100644
--- a/converter/other/fiasco/lib/list.c
+++ b/converter/other/fiasco/lib/list.c
@@ -16,11 +16,7 @@
 
 #include "config.h"
 
-#if HAVE_STRING_H
-#	include <string.h>
-#else /* not HAVE_STRING_H */
-#	include <strings.h>
-#endif /* not HAVE_STRING_H */
+#include <string.h>
 
 #include "types.h"
 #include "macros.h"
diff --git a/converter/other/fiasco/lib/macros.h b/converter/other/fiasco/lib/macros.h
index 877abeea..9968110a 100644
--- a/converter/other/fiasco/lib/macros.h
+++ b/converter/other/fiasco/lib/macros.h
@@ -28,11 +28,6 @@
 #   define SEEK_CUR	1
 #endif /* not SEEK_CUR */
 
-#ifdef WIN32
-#undef max
-#undef min
-#endif /* not WIN32 */
-
 /*****************************************************************************
 
 				Various macros
@@ -50,12 +45,6 @@
 #define address_of_level(l)	((unsigned) (size_of_level (l) - 1))
 #define size_of_tree(l)		((unsigned) (address_of_level ((l) + 1)))
 #define is_odd(n)		(abs (n) % 2)
-#ifndef max
-#define max(a,b)		((a) < (b) ? (b) : (a))
-#endif
-#ifndef min
-#define min(a,b)	        ((a) > (b) ? (b) : (a))
-#endif
 #define _(x) (x) 
 
 
diff --git a/converter/other/fiasco/lib/misc.c b/converter/other/fiasco/lib/misc.c
index 12b94e7a..782ed1e9 100644
--- a/converter/other/fiasco/lib/misc.c
+++ b/converter/other/fiasco/lib/misc.c
@@ -1,5 +1,5 @@
 /*
- *  misc.c:		Some usefull functions, that don't fit in one of 
+ *  misc.c:		Some useful functions, that don't fit in one of 
  *			the other files and that are needed by at least
  *			two modules. 
  *
@@ -33,15 +33,10 @@
 #	endif /* not HAVE_SYS_TIME_H */
 #endif /* not TIME_WITH_SYS_TIME */
 
-#if STDC_HEADERS
-#	include <stdlib.h>
-#endif /* not STDC_HEADERS */
+#include <stdlib.h>
+#include <string.h>
 
-#if HAVE_STRING_H
-#	include <string.h>
-#else /* not HAVE_STRING_H */
-#	include <strings.h>
-#endif /* not HAVE_STRING_H */
+#include "pm_c_util.h"
 
 #include "types.h"
 #include "macros.h"
@@ -401,22 +396,6 @@ memmove (void *v_dst, const void *v_src, size_t n)
 }
 #endif /* not HAVE_MEMMOVE */
 
-#ifndef HAVE_STRDUP
-char *
-strdup (const char *s)
-/*
- *  Duplicate given string 's'.
- *
- *  Return value:
- *	pointer to new string value
- */
-{
-   assert (s);
-   
-   return strcpy (Calloc (strlen (s) + 1, sizeof (char)), s);
-}
-#endif /* not HAVE_STRDUP */
-
 /* Note that some systems have a "log2()" in the math library and some
    have a "log2" macro.  So we name ours Log2.  But to avoid lots of
    differences from the original fiasco source code, we define a
@@ -452,13 +431,13 @@ variance (const word_t *pixels, unsigned x0, unsigned y0,
    assert (pixels);
    
    for (average = 0, n = 0, y = y0; y < y0 + height; y++)
-      for (x = x0; x < min (x0 + width, cols); x++, n++)
+      for (x = x0; x < MIN(x0 + width, cols); x++, n++)
 	 average += pixels [y * cols + x] / 16;
 
    average /= n;
 
    for (variance = 0, y = y0; y < y0 + height; y++)
-      for (x = x0; x < min (x0 + width, cols); x++)
+      for (x = x0; x < MIN(x0 + width, cols); x++)
 	 variance += square ((pixels [y * cols + x] / 16) - average);
 
    return variance;
diff --git a/converter/other/fiasco/lib/misc.h b/converter/other/fiasco/lib/misc.h
index 29456590..28fd8b5a 100644
--- a/converter/other/fiasco/lib/misc.h
+++ b/converter/other/fiasco/lib/misc.h
@@ -72,10 +72,6 @@ memmove(void *dest, const void *src, size_t n);
 
 double
 Log2 (double x);
-#ifndef HAVE_STRDUP
-char *
-strdup (const char *s);
-#endif
 #ifndef HAVE_STRCASECMP
 bool_t
 strcaseeq (const char *s1, const char *s2);
diff --git a/converter/other/fiasco/output/matrices.c b/converter/other/fiasco/output/matrices.c
index fd8d31e2..01189669 100644
--- a/converter/other/fiasco/output/matrices.c
+++ b/converter/other/fiasco/output/matrices.c
@@ -20,9 +20,9 @@
 
 #include "config.h"
 
-#if STDC_HEADERS
-#	include <stdlib.h>
-#endif /* not STDC_HEADERS */
+#include <stdlib.h>
+
+#include "pm_c_util.h"
 
 #include "types.h"
 #include "macros.h"
@@ -144,7 +144,7 @@ delta_encoding (bool_t use_normal_domains, bool_t use_delta_domains,
 		  ;
 	       count [edge]++;
 	       edges++;
-	       M = max (edge, M);
+	       M = MAX(edge, M);
 	    }
       write_rice_code (M, 3, output);
       for (n = 0; n <= M; n++)
diff --git a/converter/other/fiasco/output/weights.c b/converter/other/fiasco/output/weights.c
index 085a1f00..5aa17674 100644
--- a/converter/other/fiasco/output/weights.c
+++ b/converter/other/fiasco/output/weights.c
@@ -16,6 +16,8 @@
 
 #include "config.h"
 
+#include "pm_c_util.h"
+
 #include "types.h"
 #include "macros.h"
 #include "error.h"
@@ -43,158 +45,159 @@ write_weights (unsigned total, const wfa_t *wfa, bitfile_t *output)
  *  No return value.
  */
 {
-   unsigned  state, label;		/* current label */
-   unsigned  offset1, offset2;		/* model offsets. */
-   unsigned  offset3, offset4;		/* model offsets. */
-   unsigned *weights_array;		/* array of weights to encode */
-   unsigned *wptr;			/* pointer to current weight */
-   unsigned *level_array;		/* array of corresponding levels */
-   unsigned *lptr;			/* pointer to current corr. level */
-   int	     min_level, max_level;	/* min and max range level */
-   int	     d_min_level, d_max_level; 	/* min and max delta range level */
-   bool_t    dc, d_dc;			/* true if dc or delta dc are used */
-   bool_t    delta_approx = NO;		/* true if delta has been used */
-   unsigned  delta_count  = 0;		/* number of delta ranges */
-   unsigned  bits 	  = bits_processed (output);
+    unsigned  state, label;		/* current label */
+    unsigned  offset1, offset2;		/* model offsets. */
+    unsigned  offset3, offset4;		/* model offsets. */
+    unsigned *weights_array;		/* array of weights to encode */
+    unsigned *wptr;			/* pointer to current weight */
+    unsigned *level_array;		/* array of corresponding levels */
+    unsigned *lptr;			/* pointer to current corr. level */
+    int	     min_level, max_level;	/* min and max range level */
+    int	     d_min_level, d_max_level; 	/* min and max delta range level */
+    bool_t    dc, d_dc;			/* true if dc or delta dc are used */
+    bool_t    delta_approx = NO;		/* true if delta has been used */
+    unsigned  delta_count  = 0;		/* number of delta ranges */
+    unsigned  bits 	  = bits_processed (output);
    
-   /*
-    *  Check whether delta approximation has been used
-    */
-   for (state = wfa->basis_states; state < wfa->states; state++)
-      if (wfa->delta_state [state])
-      {
-	 delta_approx = YES;
-	 break;
-      }
+    /*
+     *  Check whether delta approximation has been used
+     */
+    for (state = wfa->basis_states; state < wfa->states; state++)
+        if (wfa->delta_state [state])
+        {
+            delta_approx = YES;
+            break;
+        }
    
-   /*
-    *  Generate array of corresponding levels (context of probability model)
-    */
-   min_level = d_min_level = MAXLEVEL;
-   max_level = d_max_level = 0;
-   dc 	     = d_dc	   = NO;
+    /*
+     *  Generate array of corresponding levels (context of probability model)
+     */
+    min_level = d_min_level = MAXLEVEL;
+    max_level = d_max_level = 0;
+    dc 	     = d_dc	   = NO;
    
-   for (state = wfa->basis_states; state < wfa->states; state++)
-      for (label = 0; label < MAXLABELS; label++)
-         if (isrange (wfa->tree [state][label]))
-	 {
-	    if (delta_approx && wfa->delta_state [state]) /* delta approx. */
-	    {
-	       d_min_level = min (d_min_level,
-				  wfa->level_of_state [state] - 1);
-	       d_max_level = max (d_max_level,
-				  wfa->level_of_state [state] - 1);
-	       if (wfa->into [state][label][0] == 0)
-		  d_dc = YES;
-	    }
-	    else
-	    {
-	       min_level = min (min_level, wfa->level_of_state [state] - 1);
-	       max_level = max (max_level, wfa->level_of_state [state] - 1);
-	       if (wfa->into [state][label][0] == 0)
-		  dc = YES;
-	    }
-	 }
-   if (min_level > max_level)		/* no lc found */
-      max_level = min_level - 1;
-   if (d_min_level > d_max_level)
-      d_max_level = d_min_level - 1;
-
-   /*
-    *  Context model:
-    *		0		DC weight
-    *		1		Delta DC weight
-    *		2-k		normal weights per level
-    *		k+1 - m		Delta weights per level
-    */
-
-   offset1 = dc ? 1 : 0;
-   offset2 = offset1 + (d_dc ? 1 : 0);
-   offset3 = offset2 + (max_level - min_level + 1);
-   offset4 = offset3 + (d_max_level - d_min_level + 1);
+    for (state = wfa->basis_states; state < wfa->states; state++)
+        for (label = 0; label < MAXLABELS; label++)
+            if (isrange (wfa->tree [state][label]))
+            {
+                if (delta_approx && wfa->delta_state [state]) /* delta approx. */
+                {
+                    d_min_level = MIN(d_min_level, wfa->level_of_state [state] - 1);
+                    d_max_level = MAX(d_max_level, wfa->level_of_state [state] - 1);
+                    if (wfa->into [state][label][0] == 0)
+                        d_dc = YES;
+                }
+                else
+                {
+                    min_level = MIN(min_level, wfa->level_of_state [state] - 1);
+                    max_level = MAX(max_level, wfa->level_of_state [state] - 1);
+                    if (wfa->into [state][label][0] == 0)
+                        dc = YES;
+                }
+            }
+    if (min_level > max_level)		/* no lc found */
+        max_level = min_level - 1;
+    if (d_min_level > d_max_level)
+        d_max_level = d_min_level - 1;
+
+    /*
+     *  Context model:
+     *		0		DC weight
+     *		1		Delta DC weight
+     *		2-k		normal weights per level
+     *		k+1 - m		Delta weights per level
+     */
+
+    offset1 = dc ? 1 : 0;
+    offset2 = offset1 + (d_dc ? 1 : 0);
+    offset3 = offset2 + (max_level - min_level + 1);
+    offset4 = offset3 + (d_max_level - d_min_level + 1);
    
-   /*
-    *  Weights are encoded as follows:
-    *  all weights of state n
-    *     sorted by label
-    *        sorted by domain number
-    */
-
-   wptr = weights_array = Calloc (total, sizeof (unsigned));
-   lptr = level_array   = Calloc (total, sizeof (unsigned));
-
-   for (state = wfa->basis_states; state < wfa->states; state++)
-      for (label = 0; label < MAXLABELS; label++)
-         if (isrange (wfa->tree [state][label]))
-	 {
-	    int	edge;			/* current edge */
-	    int	domain;			/* current domain (context of model) */
-	    
-            for (edge = 0; isedge (domain = wfa->into [state][label][edge]);
-		 edge++)
+    /*
+     *  Weights are encoded as follows:
+     *  all weights of state n
+     *     sorted by label
+     *        sorted by domain number
+     */
+
+    wptr = weights_array = Calloc (total, sizeof (unsigned));
+    lptr = level_array   = Calloc (total, sizeof (unsigned));
+
+    for (state = wfa->basis_states; state < wfa->states; state++)
+        for (label = 0; label < MAXLABELS; label++)
+            if (isrange (wfa->tree [state][label]))
             {
-	       if (wptr - weights_array >= (int) total)
-		  error ("Can't write more than %d weights.", total);
-	       if (domain)		/* not DC component */
-	       {
-		  if (delta_approx && wfa->delta_state [state]) /* delta */
-		  {
-		     *wptr++ = rtob (wfa->weight [state][label][edge],
-				     wfa->wfainfo->d_rpf);
-		     *lptr++ = offset3
-			       + wfa->level_of_state [state] - 1 - d_min_level;
-		     delta_count++;
-		  }
-		  else
-		  {
-		     *wptr++ = rtob (wfa->weight [state][label][edge],
-				     wfa->wfainfo->rpf);
-		     *lptr++ = offset2
-			       + wfa->level_of_state [state] - 1 - min_level;
-		  }
-	       }
-	       else			/* DC component */
-	       {
-		  if (delta_approx && wfa->delta_state [state]) /* delta */
-		  {
-		     *wptr++ = rtob (wfa->weight [state][label][edge],
-				     wfa->wfainfo->d_dc_rpf);
-		     *lptr++ = offset1;
-		  }
-		  else
-		  {
-		     *wptr++ = rtob (wfa->weight [state][label][edge],
-				     wfa->wfainfo->dc_rpf);
-		     *lptr++ = 0;
-		  }
-	       }
+                int	edge;			/* current edge */
+                int	domain;			/* current domain (context of model) */
+	    
+                for (edge = 0; isedge (domain = wfa->into [state][label][edge]);
+                     edge++)
+                {
+                    if (wptr - weights_array >= (int) total)
+                        error ("Can't write more than %d weights.", total);
+                    if (domain)		/* not DC component */
+                    {
+                        if (delta_approx && wfa->delta_state [state]) /* delta */
+                        {
+                            *wptr++ = rtob (wfa->weight [state][label][edge],
+                                            wfa->wfainfo->d_rpf);
+                            *lptr++ = offset3
+                                + wfa->level_of_state [state] - 1 - d_min_level;
+                            delta_count++;
+                        }
+                        else
+                        {
+                            *wptr++ = rtob (wfa->weight [state][label][edge],
+                                            wfa->wfainfo->rpf);
+                            *lptr++ = offset2
+                                + wfa->level_of_state [state] - 1 - min_level;
+                        }
+                    }
+                    else			/* DC component */
+                    {
+                        if (delta_approx && wfa->delta_state [state]) /* delta */
+                        {
+                            *wptr++ = rtob (wfa->weight [state][label][edge],
+                                            wfa->wfainfo->d_dc_rpf);
+                            *lptr++ = offset1;
+                        }
+                        else
+                        {
+                            *wptr++ = rtob (wfa->weight [state][label][edge],
+                                            wfa->wfainfo->dc_rpf);
+                            *lptr++ = 0;
+                        }
+                    }
+                }
             }
-	 }
-
-   {
-      unsigned	 i;
-      unsigned	*c_symbols = Calloc (offset4, sizeof (int));
-      const int	 scale 	   = 500;	/* scaling of probability model */
-
-      c_symbols [0] = 1 << (wfa->wfainfo->dc_rpf->mantissa_bits + 1);
-      if (offset1 != offset2)
-	 c_symbols [offset1] = 1 << (wfa->wfainfo->d_dc_rpf->mantissa_bits
-				     + 1);
-      for (i = offset2; i < offset3; i++)
-	 c_symbols [i] = 1 << (wfa->wfainfo->rpf->mantissa_bits + 1);
-      for (; i < offset4; i++)
-	 c_symbols [i] = 1 << (wfa->wfainfo->d_rpf->mantissa_bits + 1);
+
+    {
+        unsigned	 i;
+        unsigned	*c_symbols = Calloc (offset4, sizeof (int));
+        const int	 scale 	   = 500;	/* scaling of probability model */
+
+        c_symbols [0] = 1 << (wfa->wfainfo->dc_rpf->mantissa_bits + 1);
+        if (offset1 != offset2)
+            c_symbols [offset1] = 1 << (wfa->wfainfo->d_dc_rpf->mantissa_bits
+                                        + 1);
+        for (i = offset2; i < offset3; i++)
+            c_symbols [i] = 1 << (wfa->wfainfo->rpf->mantissa_bits + 1);
+        for (; i < offset4; i++)
+            c_symbols [i] = 1 << (wfa->wfainfo->d_rpf->mantissa_bits + 1);
       
-      encode_array (output, weights_array, level_array, c_symbols, offset4,
-		    total, scale);
-      Free (c_symbols);
-   }
+        encode_array (output, weights_array, level_array, c_symbols, offset4,
+                      total, scale);
+        Free (c_symbols);
+    }
    
-   debug_message ("%d delta weights out of %d.", delta_count, total);
-   debug_message ("weights:      %5d bits. (%5d symbols => %5.2f bps)",
-		  bits_processed (output) - bits, total,
-		  (bits_processed (output) - bits) / (double) total);
+    debug_message ("%d delta weights out of %d.", delta_count, total);
+    debug_message ("weights:      %5d bits. (%5d symbols => %5.2f bps)",
+                   bits_processed (output) - bits, total,
+                   (bits_processed (output) - bits) / (double) total);
 
-   Free (weights_array);
-   Free (level_array);
+    Free (weights_array);
+    Free (level_array);
 }
+
+
+
diff --git a/converter/other/fiasco/params.c b/converter/other/fiasco/params.c
index 7a302b82..afacbada 100644
--- a/converter/other/fiasco/params.c
+++ b/converter/other/fiasco/params.c
@@ -30,6 +30,7 @@
  
 #include <getopt.h>			/* system or ../lib */
 
+#include "pm_c_util.h"
 #include "nstring.h"
 
 #include "types.h"
@@ -631,6 +632,8 @@ read_parameter_file (param_t *params, FILE *file)
    }
 }   
 
+
+
 static void 
 usage (const param_t *params, const char *progname, const char *synopsis,
        const char *comment, const char *non_opt_string,
@@ -647,82 +650,84 @@ usage (const param_t *params, const char *progname, const char *synopsis,
  *  No return value.
  */
 {
-   int	  i;
-   size_t width = 0;
+    int	  i;
+    size_t width = 0;
    
-   fprintf (stderr, "Usage: %s [OPTION]...%s\n", progname,
-	    non_opt_string ? non_opt_string : " ");
-   if (synopsis != NULL)
-      fprintf (stderr, synopsis);
-   fprintf (stderr, "\n\n");
-   fprintf (stderr, "Mandatory or optional arguments to long options "
-	    "are mandatory or optional\nfor short options too. "
-	    "Default values are surrounded by {}.\n");
-   for (i = 0; params [i].name != NULL; i++)
-      if (params [i].optchar != '\0' || show_all_options)
-      {
-	 if (params [i].type == POSTR)
-	    width = max (width, (strlen (params [i].name)
-				 + strlen (params [i].argument_name) + 2));
-	 else if (params [i].type != PFLAG)
-	    width = max (width, (strlen (params [i].name)
-				 + strlen (params [i].argument_name)));
-	 else
-	    width = max (width, (strlen (params [i].name)) - 1);
-      }
+    fprintf (stderr, "Usage: %s [OPTION]...%s\n", progname,
+             non_opt_string ? non_opt_string : " ");
+    if (synopsis != NULL)
+        fprintf (stderr, "%s", synopsis);
+    fprintf (stderr, "\n\n");
+    fprintf (stderr, "Mandatory or optional arguments to long options "
+             "are mandatory or optional\nfor short options too. "
+             "Default values are surrounded by {}.\n");
+    for (i = 0; params [i].name != NULL; i++)
+        if (params [i].optchar != '\0' || show_all_options)
+        {
+            if (params [i].type == POSTR)
+                width = MAX(width, (strlen (params [i].name)
+                                     + strlen (params [i].argument_name) + 2));
+            else if (params [i].type != PFLAG)
+                width = MAX(width, (strlen (params [i].name)
+                                     + strlen (params [i].argument_name)));
+            else
+                width = MAX(width, (strlen (params [i].name)) - 1);
+        }
    
-   for (i = 0; params [i].name != NULL; i++)
-      if (params [i].optchar != '\0' || show_all_options)
-      {
-	 if (params [i].optchar != '\0')
-	    fprintf (stderr, "  -%c, --", params [i].optchar);
-	 else
-	    fprintf (stderr, "      --");
+    for (i = 0; params [i].name != NULL; i++)
+        if (params [i].optchar != '\0' || show_all_options)
+        {
+            if (params [i].optchar != '\0')
+                fprintf (stderr, "  -%c, --", params [i].optchar);
+            else
+                fprintf (stderr, "      --");
 	 
-	 if (params [i].type == POSTR)
-	    fprintf (stderr, "%s=[%s]%-*s  ", params [i].name,
-		     params [i].argument_name,
-		     max (0, (width - 2 - strlen (params [i].name)
-			   - strlen (params [i].argument_name))), "");
-	 else if (params [i].type != PFLAG)
-	    fprintf (stderr, "%s=%-*s  ", params [i].name,
-		  width - strlen (params [i].name),
-		  params [i].argument_name);
-	 else
-	    fprintf (stderr, "%-*s  ", width + 1, params [i].name);
-
-	 fprintf (stderr, params [i].use, params [i].argument_name);
+            if (params [i].type == POSTR)
+                fprintf (stderr, "%s=[%s]%-*s  ", params [i].name,
+                         params [i].argument_name,
+                         (unsigned)
+                         MAX(0, (width - 2 - strlen (params [i].name)
+                                 - strlen (params [i].argument_name))), "");
+            else if (params [i].type != PFLAG)
+                fprintf (stderr, "%s=%-*s  ", params [i].name,
+                         (unsigned)(width - strlen (params [i].name)),
+                         params [i].argument_name);
+            else
+                fprintf (stderr, "%-*s  ",
+                         (unsigned)(width + 1), params [i].name);
+
+            fprintf (stderr, params [i].use, params [i].argument_name);
 	 
-	 switch (params [i].type)
-	 {
-	    case PFLAG:
-	       break;
-	    case PINT:
-	       fprintf (stderr, "{%d}", params [i].value.i);
-	       break;
-	    case PFLOAT:
-	       fprintf (stderr, "{%.2f}", (double) params [i].value.f);
-	       break;
-	    case PSTR:
-	    case POSTR:
-	       if (params [i].value.s)
-		  fprintf (stderr, "{%s}", params [i].value.s);
-	       break;
-	    default:
-	       error ("type %d for %s invalid",
-		      params [i].type, params [i].name);
-	 }
-	 fprintf (stderr, "\n");
-      }
-   fprintf (stderr, "\n");
-   fprintf (stderr, "Parameter initialization order:\n");
-   fprintf (stderr,
-	    "1.) %s\n2.) $HOME/%s\t 3.) command line\t 4.) --config=file",
-	    sys_file_name, usr_file_name);
-   fprintf (stderr, "\n\n");
-   if (comment != NULL)
-      fprintf (stderr, "%s\n", comment);
-
-   exit (1);
+            switch (params [i].type)
+            {
+            case PFLAG:
+                break;
+            case PINT:
+                fprintf (stderr, "{%d}", params [i].value.i);
+                break;
+            case PFLOAT:
+                fprintf (stderr, "{%.2f}", (double) params [i].value.f);
+                break;
+            case PSTR:
+            case POSTR:
+                if (params [i].value.s)
+                    fprintf (stderr, "{%s}", params [i].value.s);
+                break;
+            default:
+                error ("type %d for %s invalid",
+                       params [i].type, params [i].name);
+            }
+            fprintf (stderr, "\n");
+        }
+    fprintf (stderr, "\n");
+    fprintf (stderr, "Parameter initialization order:\n");
+    fprintf (stderr,
+             "1.) %s\n2.) $HOME/%s\t 3.) command line\t 4.) --config=file",
+             sys_file_name, usr_file_name);
+    fprintf (stderr, "\n\n");
+    if (comment != NULL)
+        fprintf (stderr, "%s\n", comment);
+
+    exit (1);
 }
 
diff --git a/converter/other/fiasco/pnmtofiasco.c b/converter/other/fiasco/pnmtofiasco.c
index 2218256d..eebd09a9 100644
--- a/converter/other/fiasco/pnmtofiasco.c
+++ b/converter/other/fiasco/pnmtofiasco.c
@@ -1,8 +1,8 @@
 /*
- *  cwfa.c:		FIASCO coder
+ *  cwfa.c:     FIASCO coder
  *
- *  Written by:		Ullrich Hafner
- *		
+ *  Written by:     Ullrich Hafner
+ *      
  *  This file is part of FIASCO («F»ractal «I»mage «A»nd «S»equence «CO»dec)
  *  Copyright (C) 1994-2000 Ullrich Hafner <hafner@bigfoot.de>
  */
@@ -15,18 +15,12 @@
  */
 
 #include "config.h"
+#include "pm_c_util.h"
 #include "pnm.h"
 
-#if STDC_HEADERS
-#	include <stdlib.h>
-#	include <string.h>
-#else /* not STDC_HEADERS */
-#	if HAVE_STRING_H
-#		include <string.h>
-#	else /* not HAVE_STRING_H */
-#		include <strings.h>
-#	endif /* not HAVE_STRING_H */
-#endif /* not STDC_HEADERS */
+#include <stdlib.h>
+#include <string.h>
+#include <string.h>
 
 #include "types.h"
 #include "macros.h"
@@ -38,7 +32,7 @@
 
 /*****************************************************************************
 
-			     local variables
+                 local variables
   
 *****************************************************************************/
 
@@ -144,27 +138,27 @@ static param_t params [] =
 
 /*****************************************************************************
 
-				prototypes
+                prototypes
   
 *****************************************************************************/
 
 static void 
 checkargs (int argc, char **argv, char const ***image_template,
-	   char **wfa_name, float *quality, fiasco_c_options_t **options);
+       char **wfa_name, float *quality, fiasco_c_options_t **options);
 
 /*****************************************************************************
 
-				public code
+                public code
   
 *****************************************************************************/
  
 int 
 main (int argc, char **argv)
 {
-   char const 	      **image_template;	/* template for input image files */
-   char	       	       *wfa_name;	/* filename of output WFA */
-   float	      	quality;	/* approximation quality */
-   fiasco_c_options_t  *options;	/* additional coder options */
+   char const         **image_template; /* template for input image files */
+   char                *wfa_name;   /* filename of output WFA */
+   float            quality;    /* approximation quality */
+   fiasco_c_options_t  *options;    /* additional coder options */
    
    pnm_init(&argc, argv);
    
@@ -176,7 +170,7 @@ main (int argc, char **argv)
       return 0;
    else
    {
-      fprintf (stderr, fiasco_get_error_message ());
+       fprintf (stderr, "%s", fiasco_get_error_message ());
       fprintf (stderr, "\n");
       return 1;
    }
@@ -184,228 +178,228 @@ main (int argc, char **argv)
 
 /*****************************************************************************
 
-				private code
+                private code
   
 *****************************************************************************/
 
 static void 
 checkargs (int argc, char **argv, char const ***image_template,
-	   char **wfa_name, float *quality, fiasco_c_options_t **options)
+           char **wfa_name, float *quality, fiasco_c_options_t **options)
 /*
  *  Check validness of command line parameters and of the parameter files.
  *
  *  Return value:
- *	1 on success
- *	0 otherwise
+ *  1 on success
+ *  0 otherwise
  *  
  *
  *  Side effects:
- *	'image_template', 'wfa_name', 'quality' and 'options' are set.
+ *  'image_template', 'wfa_name', 'quality' and 'options' are set.
  */
 {
-   int	 optind;			/* last processed commandline param */
-   char	*image_name;			/* filename given by option '-i' */
-   int	 i;				/* counter */
+    int   optind;            /* last processed commandline param */
+    char *image_name;            /* filename given by option '--input_name' */
+    int   i;             /* counter */
    
-   optind = parseargs (params, argc, argv,
-		       "Compress raw PPM/PGM image FILEs to a FIASCO file.",
-		       "With no image FILE, or if FILE is -, "
-		       "read standard input.\n"
-		       "FILE must be either a filename"
-		       " or an image template of the form:\n"
-		       "`prefix[start-end{+,-}step]suffix'\n"
-		       "e.g., img0[12-01-1].pgm is substituted by"
-		       " img012.pgm ... img001.pgm\n\n"
-		       "Environment:\n"
-		       "FIASCO_DATA   Search and save path for FIASCO files. "
-		       "Default: ./\n"
-		       "FIASCO_IMAGES Search path for image files. "
-		       "Default: ./", " [FILE]...",
-		       FIASCO_SHARE, "system.fiascorc", ".fiascorc");
+    optind = parseargs (params, argc, argv,
+                        "Compress raw PPM/PGM image FILEs to a FIASCO file.",
+                        "With no image FILE, or if FILE is -, "
+                        "read standard input.\n"
+                        "FILE must be either a filename"
+                        " or an image template of the form:\n"
+                        "`prefix[start-end{+,-}step]suffix'\n"
+                        "e.g., img0[12-01-1].pgm is substituted by"
+                        " img012.pgm ... img001.pgm\n\n"
+                        "Environment:\n"
+                        "FIASCO_DATA   Search and save path for FIASCO files. "
+                        "Default: ./\n"
+                        "FIASCO_IMAGES Search path for image files. "
+                        "Default: ./", " [FILE]...",
+                        FIASCO_SHARE, "system.fiascorc", ".fiascorc");
 
-   /*
-    *  Default options ...
-    */
-   image_name = (char *) parameter_value (params, "image-name"); 
-   *wfa_name  = (char *) parameter_value (params, "output-name");
-   for (;;)
-   {
-      *quality = * (float *) parameter_value (params, "quality");
-      if (*quality > 100)
-	 fprintf (stderr, "Typical range of quality: (0,100].\n"
-		  "Expect some trouble on slow machines.\n");
-      if (*quality > 0)
-	 break;
-      ask_and_set (params, "quality",
-		   "Please enter coding quality 'q' ('q' > 0): ");
-   }
+    /*
+     *  Default options ...
+     */
+    image_name = (char *) parameter_value (params, "image-name"); 
+    *wfa_name  = (char *) parameter_value (params, "output-name");
+    for (;;)
+    {
+        *quality = * (float *) parameter_value (params, "quality");
+        if (*quality > 100)
+            fprintf (stderr, "Typical range of quality: (0,100].\n"
+                     "Expect some trouble on slow machines.\n");
+        if (*quality > 0)
+            break;
+        ask_and_set (params, "quality",
+                     "Please enter coding quality 'q' ('q' > 0): ");
+    }
    
-   if (optind < argc)			/* Additional command line param */
-   {
-      if (image_name)
-	 error ("Multiple image_template arguments."
-		"\nOption -i %s already specified!", image_name);
+    if (optind < argc)           /* Additional command line param */
+    {
+        if (image_name)
+            error ("Multiple image_template arguments."
+                   "\nOption --input-name %s already specified!", image_name);
 
-      *image_template = calloc (argc - optind + 1, sizeof (char *));
-      if (!*image_template)
-	 error ("Out of memory.");
-      for (i = 0; optind < argc; i++, optind++)
-	 (*image_template) [i] = argv [optind];
-      (*image_template) [i] = NULL;
-   }
-   else					/* option -i image_name */
-   {
-      *image_template = calloc (2, sizeof (char *));
-      if (!*image_template)
-	 error ("Out of memory.");
-      (*image_template) [0] = image_name;
-      (*image_template) [1] = NULL;
-   }
-   /*
-    *  Additional options ... (have to be set with the fiasco_set_... methods)
-    */
-   {
-      *options = fiasco_c_options_new ();
+        *image_template = calloc (argc - optind + 1, sizeof (char *));
+        if (!*image_template)
+            error ("Out of memory.");
+        for (i = 0; optind < argc; i++, optind++)
+            (*image_template) [i] = argv [optind];
+        (*image_template) [i] = NULL;
+    }
+    else                 /* option -i image_name */
+    {
+        *image_template = calloc (2, sizeof (char *));
+        if (!*image_template)
+            error ("Out of memory.");
+        (*image_template) [0] = image_name;
+        (*image_template) [1] = NULL;
+    }
+    /*
+     *  Additional options ... (have to be set with the fiasco_set_... methods)
+     */
+    {
+        *options = fiasco_c_options_new ();
       
-      {
-	 char *pattern = (char *) parameter_value (params, "pattern");
+        {
+            char *pattern = (char *) parameter_value (params, "pattern");
 
-	 if (!fiasco_c_options_set_frame_pattern (*options, pattern))
-	    error (fiasco_get_error_message ());
-      }
+            if (!fiasco_c_options_set_frame_pattern (*options, pattern))
+                error (fiasco_get_error_message ());
+        }
 
-      {
-	 char *basis = (char *) parameter_value (params, "basis-name");
-	 
-	 if (!fiasco_c_options_set_basisfile (*options, basis))
-	    error (fiasco_get_error_message ());
-      }
+        {
+            char *basis = (char *) parameter_value (params, "basis-name");
+     
+            if (!fiasco_c_options_set_basisfile (*options, basis))
+                error (fiasco_get_error_message ());
+        }
 
-      {
-	 int   n = * (int *) parameter_value (params, "chroma-dictionary");
-	 float q = * (float *) parameter_value (params, "chroma-qfactor");
+        {
+            int   n = * (int *) parameter_value (params, "chroma-dictionary");
+            float q = * (float *) parameter_value (params, "chroma-qfactor");
       
-	 if (!fiasco_c_options_set_chroma_quality (*options, q, max (0, n)))
-	    error (fiasco_get_error_message ());
-      }
+            if (!fiasco_c_options_set_chroma_quality (*options, q, MAX(0, n)))
+                error (fiasco_get_error_message ());
+        }
       
-      {
-	 int n = *((int *) parameter_value (params, "smooth"));
-	 
-	 if (!fiasco_c_options_set_smoothing (*options, max (0, n)))
-	    error (fiasco_get_error_message ());
-      }
+        {
+            int n = *((int *) parameter_value (params, "smooth"));
+     
+            if (!fiasco_c_options_set_smoothing (*options, MAX(0, n)))
+                error (fiasco_get_error_message ());
+        }
       
-      {
-          int n = * (int *) parameter_value (params, "progress-meter");
-          fiasco_progress_e type = (n < 0) ? 
-              FIASCO_PROGRESS_NONE : (fiasco_progress_e) n;
+        {
+            int n = * (int *) parameter_value (params, "progress-meter");
+            fiasco_progress_e type = (n < 0) ? 
+                FIASCO_PROGRESS_NONE : (fiasco_progress_e) n;
       
-          if (!fiasco_c_options_set_progress_meter (*options, type))
-              error (fiasco_get_error_message ());
-      }
+            if (!fiasco_c_options_set_progress_meter (*options, type))
+                error (fiasco_get_error_message ());
+        }
       
-      {
-	 char *t = (char *) parameter_value (params, "title");
-	 
-	 if (strlen (t) > 0 && !fiasco_c_options_set_title (*options, t))
-	    error (fiasco_get_error_message ());
-      }
+        {
+            char *t = (char *) parameter_value (params, "title");
+     
+            if (strlen (t) > 0 && !fiasco_c_options_set_title (*options, t))
+                error (fiasco_get_error_message ());
+        }
       
-      {
-	 char *c = (char *) parameter_value (params, "comment");
+        {
+            char *c = (char *) parameter_value (params, "comment");
 
-	 if (strlen (c) > 0 && !fiasco_c_options_set_comment (*options, c))
-	    error (fiasco_get_error_message ());
-      }
+            if (strlen (c) > 0 && !fiasco_c_options_set_comment (*options, c))
+                error (fiasco_get_error_message ());
+        }
       
-      {
-	 fiasco_tiling_e method = FIASCO_TILING_VARIANCE_DSC;
-	 int   e  = * (int *) parameter_value (params, "tiling-exponent");
-	 char *m  = (char *) parameter_value (params, "tiling-method");
+        {
+            fiasco_tiling_e method = FIASCO_TILING_VARIANCE_DSC;
+            int   e  = * (int *) parameter_value (params, "tiling-exponent");
+            char *m  = (char *) parameter_value (params, "tiling-method");
 
-	 if (strcaseeq (m, "desc-variance"))
-	    method = FIASCO_TILING_VARIANCE_DSC;
-	 else if (strcaseeq (m, "asc-variance"))
-	    method = FIASCO_TILING_VARIANCE_ASC;
-	 else if (strcaseeq (m, "asc-spiral"))
-	    method = FIASCO_TILING_SPIRAL_ASC;
-	 else if (strcaseeq (m, "dsc-spiral"))
-	    method = FIASCO_TILING_SPIRAL_DSC;
-	 else
-	    error (_("Invalid tiling method `%s' specified."), m);
+            if (strcaseeq (m, "desc-variance"))
+                method = FIASCO_TILING_VARIANCE_DSC;
+            else if (strcaseeq (m, "asc-variance"))
+                method = FIASCO_TILING_VARIANCE_ASC;
+            else if (strcaseeq (m, "asc-spiral"))
+                method = FIASCO_TILING_SPIRAL_ASC;
+            else if (strcaseeq (m, "dsc-spiral"))
+                method = FIASCO_TILING_SPIRAL_DSC;
+            else
+                error (_("Invalid tiling method `%s' specified."), m);
 
-	 if (!fiasco_c_options_set_tiling (*options, method, max (0, e)))
-	    error (fiasco_get_error_message ());
-      }
+            if (!fiasco_c_options_set_tiling (*options, method, MAX(0, e)))
+                error (fiasco_get_error_message ());
+        }
       
-      {
-	 int M/*  = * (int *) parameter_value (params, "max-level") */;
-	 int m/*  = * (int *) parameter_value (params, "min-level") */;
-	 int N/*  = * (int *) parameter_value (params, "max-elements") */;
-	 int D = * (int *) parameter_value (params, "dictionary-size");
-	 int o = * (int *) parameter_value (params, "optimize");
+        {
+            int M/*  = * (int *) parameter_value (params, "max-level") */;
+            int m/*  = * (int *) parameter_value (params, "min-level") */;
+            int N/*  = * (int *) parameter_value (params, "max-elements") */;
+            int D = * (int *) parameter_value (params, "dictionary-size");
+            int o = * (int *) parameter_value (params, "optimize");
 
-	 if (o <= 0)
-	 {
-	    o = 0;
-	    M = 10;
-	    m = 6;
-	    N = 3;
-	 }
-	 else
-	 {
-	    o -= 1;
-	    M = 12;
-	    m = 4;
-	    N = 5;
-	 }
-	 
-	 if (!fiasco_c_options_set_optimizations (*options, m, M, N,
-						  max (0, D), o))
-	    error (fiasco_get_error_message ());
-      }
-      {
-	 int M = * (int *) parameter_value (params, "max-level");
-	 int m = * (int *) parameter_value (params, "min-level");
-	 int p = * (int *) parameter_value (params, "prediction");
-	 
-	 if (!fiasco_c_options_set_prediction (*options,
-					       p, max (0, m), max (0, M)))
-	    error (fiasco_get_error_message ());
-      }
-      {
-	 float r    = * (float *) parameter_value (params, "rpf-range");
-	 float dc_r = * (float *) parameter_value (params, "dc-rpf-range");
-	 int   m    = * (int *)   parameter_value (params, "rpf-mantissa");
-	 int   dc_m = * (int *)   parameter_value (params, "dc-rpf-mantissa");
-	 fiasco_rpf_range_e range, dc_range;
-	 
-	 if (r < 1)
-	    range = FIASCO_RPF_RANGE_0_75;
-	 else if (r < 1.5)
-	    range = FIASCO_RPF_RANGE_1_00;
-	 else if (r < 2.0)
-	    range = FIASCO_RPF_RANGE_1_50;
-	 else
-	    range = FIASCO_RPF_RANGE_2_00;
-	    
-	 if (dc_r < 1)
-	    dc_range = FIASCO_RPF_RANGE_0_75;
-	 else if (dc_r < 1.5)
-	    dc_range = FIASCO_RPF_RANGE_1_00;
-	 else if (dc_r < 2.0)
-	    dc_range = FIASCO_RPF_RANGE_1_50;
-	 else
-	    dc_range = FIASCO_RPF_RANGE_2_00;
-	    
-	 if (!fiasco_c_options_set_quantization (*options,
-						 max (0, m), range,
-						 max (0, dc_m), dc_range))
-	    error (fiasco_get_error_message ());
-      }
+            if (o <= 0)
+            {
+                o = 0;
+                M = 10;
+                m = 6;
+                N = 3;
+            }
+            else
+            {
+                o -= 1;
+                M = 12;
+                m = 4;
+                N = 5;
+            }
+     
+            if (!fiasco_c_options_set_optimizations (*options, m, M, N,
+                                                     MAX(0, D), o))
+                error (fiasco_get_error_message ());
+        }
+        {
+            int M = * (int *) parameter_value (params, "max-level");
+            int m = * (int *) parameter_value (params, "min-level");
+            int p = * (int *) parameter_value (params, "prediction");
+     
+            if (!fiasco_c_options_set_prediction (*options,
+                                                  p, MAX(0, m), MAX(0, M)))
+                error (fiasco_get_error_message ());
+        }
+        {
+            float r    = * (float *)parameter_value(params, "rpf-range");
+            float dc_r = * (float *)parameter_value(params, "dc-rpf-range");
+            int   m    = * (int *)  parameter_value(params, "rpf-mantissa");
+            int   dc_m = * (int *)  parameter_value(params, "dc-rpf-mantissa");
+            fiasco_rpf_range_e range, dc_range;
+     
+            if (r < 1)
+                range = FIASCO_RPF_RANGE_0_75;
+            else if (r < 1.5)
+                range = FIASCO_RPF_RANGE_1_00;
+            else if (r < 2.0)
+                range = FIASCO_RPF_RANGE_1_50;
+            else
+                range = FIASCO_RPF_RANGE_2_00;
+        
+            if (dc_r < 1)
+                dc_range = FIASCO_RPF_RANGE_0_75;
+            else if (dc_r < 1.5)
+                dc_range = FIASCO_RPF_RANGE_1_00;
+            else if (dc_r < 2.0)
+                dc_range = FIASCO_RPF_RANGE_1_50;
+            else
+                dc_range = FIASCO_RPF_RANGE_2_00;
+        
+            if (!fiasco_c_options_set_quantization (*options,
+                                                    MAX(0, m), range,
+                                                    MAX(0, dc_m), dc_range))
+                error (fiasco_get_error_message ());
+        }
 
-      if (fiasco_get_verbosity () == FIASCO_ULTIMATE_VERBOSITY)
-	 write_parameters (params, stderr);
-   }
-}	
+        if (fiasco_get_verbosity () == FIASCO_ULTIMATE_VERBOSITY)
+            write_parameters (params, stderr);
+    }
+}   
diff --git a/converter/other/fitstopnm.c b/converter/other/fitstopnm.c
index 73564c4b..bdf5c78a 100644
--- a/converter/other/fitstopnm.c
+++ b/converter/other/fitstopnm.c
@@ -34,10 +34,16 @@
   The official specification of FITS format (which is for more than
   just visual images) is at
   ftp://legacy.gsfc.nasa.gov/fits_info/fits_office/fits_standard.pdf
+
+  An example FITS file is at
+
+    http://fits.gsfc.nasa.gov/nrao_data/tests/incunabula/mndrll-8.fits
+
 */
 
 #include <string.h>
 #include <float.h>
+#include <assert.h>
 
 #include "pm_config.h"
 #include "pm_c_util.h"
@@ -48,7 +54,7 @@
 
 
 
-struct cmdlineInfo {
+struct CmdlineInfo {
     const char * inputFileName;
     unsigned int image;  /* zero if unspecified */
     float max;
@@ -69,8 +75,8 @@ struct cmdlineInfo {
 
 
 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 +88,7 @@ parseCommandLine(int argc, char ** argv,
    was passed to us as the argv array.  We also trash *argv.
 --------------------------------------------------------------------------*/
     optEntry * option_def;
-        /* Instructions to optParseOptions3 on how to parse our options. */
+        /* Instructions to pm_optParseOptions3 on how to parse our options. */
     optStruct3 opt;
 
     unsigned int imageSpec;
@@ -114,7 +120,7 @@ parseCommandLine(int argc, char ** argv,
 
     /* Set some defaults the lazy way (using multiple setting of variables) */
 
-    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 (imageSpec) {
@@ -139,13 +145,17 @@ parseCommandLine(int argc, char ** argv,
             pm_error("Too many arguments (%u).  The only non-option argument "
                      "is the input file name.", argc-1);
     }
+    free(option_def);
 }
 
 
 
 struct FITS_Header {
   int simple;       /* basic format or not */
-  int bitpix;       /* number of bits per pixel */
+  int bitpix;
+      /* number of bits per pixel, positive for integer, negative 
+         for floating point
+      */
   int naxis;        /* number of axes */
   int naxis1;       /* number of points on axis 1 */
   int naxis2;       /* number of points on axis 2 */
@@ -157,6 +167,16 @@ struct FITS_Header {
 };
 
 
+typedef enum {
+    VF_CHAR, VF_SHORT, VF_LONG, VF_FLOAT, VF_DOUBLE
+} valFmt;
+
+struct fitsRasterInfo {
+    valFmt valFmt;
+    double bzer;
+    double bscale;
+};
+
 /* This code deals properly with integers, no matter what the byte order
    or integer size of the host machine.  We handle sign extension manually to
    prevent problems with signed/unsigned characters.  We read floating point
@@ -276,34 +296,56 @@ readFitsDouble(FILE *   const ifP,
 
 
 
+static valFmt
+valFmtFromBitpix(int const bitpix) {
+/*----------------------------------------------------------------------------
+   Return the format of a "value" in the FITS file, given the value
+   of the BITPIX header in the FITS file.
+
+   BITPIX has a stupid format wherein it is fundamentally the number
+   of bits per value, but its sign indicates whether it is integer
+   or floating point.
+-----------------------------------------------------------------------------*/
+    switch (bitpix) {
+    case  +8: return VF_CHAR;
+    case +16: return VF_SHORT;
+    case +32: return VF_LONG;
+    case -32: return VF_FLOAT;
+    case -64: return VF_DOUBLE;
+    default:
+        /* Every possibility is covered above. */
+        assert(false);
+        return 0;  /* quiet compiler warning */
+    }
+}
+
+
+
 static void
 readVal(FILE *   const ifP,
-        int      const bitpix,
+        valFmt   const fmt,
         double * const vP) {
 
-    switch (bitpix) {
-    case 8:
+    switch (fmt) {
+    case VF_CHAR:
         readFitsChar(ifP, vP);
         break;
 
-    case 16:
+    case VF_SHORT:
         readFitsShort(ifP, vP);
         break;
       
-    case 32:
+    case VF_LONG:
         readFitsLong(ifP, vP);
         break;
       
-    case -32:
+    case VF_FLOAT:
         readFitsFloat(ifP, vP);
         break;
       
-    case -64:
+    case VF_DOUBLE:
         readFitsDouble(ifP, vP);
         break;
-      
-    default:
-        pm_error("Strange bitpix value %d in readVal()", bitpix);
     }
 }
 
@@ -419,7 +461,7 @@ scanImageForMinMax(FILE *       const ifP,
                    unsigned int const images,
                    int          const cols,
                    int          const rows,
-                   unsigned int const bitpix,
+                   valFmt       const valFmt,
                    double       const bscale,
                    double       const bzer,
                    unsigned int const imagenum,
@@ -427,6 +469,9 @@ scanImageForMinMax(FILE *       const ifP,
                    double *     const dataminP,
                    double *     const datamaxP) {
 
+    /* Note that a value in the file might be Not-A-Number.  We ignore
+       such entries in computing the minimum and maximum for the image.
+    */
     double dmax, dmin;
     unsigned int image;
     pm_filepos rasterPos;
@@ -436,14 +481,12 @@ scanImageForMinMax(FILE *       const ifP,
 
     pm_message("Scanning file for scaling parameters");
 
-    switch (bitpix) {
-    case   8: fmaxval = 255.0;        break;
-    case  16: fmaxval = 65535.0;      break;
-    case  32: fmaxval = 4294967295.0; break;
-    case -32: fmaxval = FLT_MAX;      break;
-    case -64: fmaxval = DBL_MAX;      break;
-    default:
-        pm_error("unusual bits per pixel (%u), can't read", bitpix);
+    switch (valFmt) {
+    case VF_CHAR:   fmaxval = 255.0;        break;
+    case VF_SHORT:  fmaxval = 65535.0;      break;
+    case VF_LONG:   fmaxval = 4294967295.0; break;
+    case VF_FLOAT:  fmaxval = FLT_MAX;      break;
+    case VF_DOUBLE: fmaxval = DBL_MAX;      break;
     }
 
     dmax = -fmaxval;
@@ -454,10 +497,11 @@ scanImageForMinMax(FILE *       const ifP,
             unsigned int col;
             for (col = 0; col < cols; ++col) {
                 double val;
-                readVal(ifP, bitpix, &val);
+                readVal(ifP, valFmt, &val);
                 if (image == imagenum || multiplane ) {
-                    dmax = MAX(dmax, val);
-                    dmin = MIN(dmin, val);
+                    /* Note: if 'val' is NaN, result is 2nd operand */
+                    dmax = MAX(val, dmax);
+                    dmin = MIN(val, dmin);
                 }
             }
         }
@@ -509,7 +553,8 @@ computeMinMax(FILE *             const ifP,
 
     if (datamin == -DBL_MAX || datamax == DBL_MAX) {
         double scannedDatamin, scannedDatamax;
-        scanImageForMinMax(ifP, images, cols, rows, h.bitpix, h.bscale, h.bzer,
+        scanImageForMinMax(ifP, images, cols, rows,
+                           valFmtFromBitpix(h.bitpix), h.bscale, h.bzer,
                            imagenum, multiplane,
                            &scannedDatamin, &scannedDatamax);
 
@@ -525,8 +570,8 @@ computeMinMax(FILE *             const ifP,
 
 
 static xelval
-determineMaxval(struct cmdlineInfo const cmdline,
-                struct FITS_Header const fitsHeader,
+determineMaxval(struct CmdlineInfo const cmdline,
+                valFmt             const valFmt,
                 double             const datamax,
                 double             const datamin) {
 
@@ -535,7 +580,7 @@ determineMaxval(struct cmdlineInfo const cmdline,
     if (cmdline.omaxvalSpec)
         retval = cmdline.omaxval;
     else {
-        if (fitsHeader.bitpix < 0) {
+        if (valFmt == VF_FLOAT || valFmt == VF_DOUBLE) {
             /* samples are floating point, which means the resolution
                could be anything.  So we just pick a convenient maxval
                of 255.  Before Netpbm 10.20 (January 2004), we did
@@ -561,16 +606,16 @@ determineMaxval(struct cmdlineInfo const cmdline,
 
 
 static void
-convertPgmRaster(FILE *             const ifP,
-                 unsigned int       const cols,
-                 unsigned int       const rows,
-                 xelval             const maxval,
-                 unsigned int       const desiredImage,
-                 unsigned int       const imageCount,
-                 struct FITS_Header const fitsHdr,
-                 double             const scale,
-                 double             const datamin,
-                 xel **             const xels) {
+convertPgmRaster(FILE *                const ifP,
+                 unsigned int          const cols,
+                 unsigned int          const rows,
+                 xelval                const maxval,
+                 unsigned int          const desiredImage,
+                 unsigned int          const imageCount,
+                 struct fitsRasterInfo const rasterInfo,
+                 double                const scale,
+                 double                const datamin,
+                 xel **                const xels) {
         
     /* Note: the FITS specification does not give the association between
        file position and image position (i.e. is the first pixel in the
@@ -581,8 +626,7 @@ convertPgmRaster(FILE *             const ifP,
     */
     unsigned int image;
 
-    pm_message("Writing PPM file "
-               "(Probably not what you want - consider an -image option)");
+    pm_message("writing PGM file");
 
     for (image = 1; image <= desiredImage; ++image) {
         unsigned int row;
@@ -594,10 +638,10 @@ convertPgmRaster(FILE *             const ifP,
             unsigned int col;
             for (col = 0; col < cols; ++col) {
                 double val;
-                readVal(ifP, fitsHdr.bitpix, &val);
+                readVal(ifP, rasterInfo.valFmt, &val);
                 {
                     double const t = scale *
-                        (val * fitsHdr.bscale + fitsHdr.bzer - datamin);
+                        (val * rasterInfo.bscale + rasterInfo.bzer - datamin);
                     xelval const tx = MAX(0, MIN(t, maxval));
                     if (image == desiredImage)
                         PNM_ASSIGN1(xels[row][col], tx);
@@ -610,14 +654,14 @@ convertPgmRaster(FILE *             const ifP,
 
 
 static void
-convertPpmRaster(FILE *             const ifP,
-                 unsigned int       const cols,
-                 unsigned int       const rows,
-                 xelval             const maxval,
-                 struct FITS_Header const fitsHdr,
-                 double             const scale,
-                 double             const datamin,
-                 xel **             const xels) {
+convertPpmRaster(FILE *                const ifP,
+                 unsigned int          const cols,
+                 unsigned int          const rows,
+                 xelval                const maxval,
+                 struct fitsRasterInfo const rasterInfo,
+                 double                const scale,
+                 double                const datamin,
+                 xel **                const xels) {
 /*----------------------------------------------------------------------------
    Read the FITS raster from file *ifP into xels[][].  Image dimensions
    are 'cols' by 'rows'.  The FITS raster is 3 planes composing one
@@ -625,7 +669,8 @@ convertPpmRaster(FILE *             const ifP,
 -----------------------------------------------------------------------------*/
     unsigned int plane;
 
-    pm_message("writing PPM file");
+    pm_message("Writing PPM file "
+               "(Probably not what you want - consider an -image option)");
 
     for (plane = 0; plane < 3; ++plane) {
         unsigned int row;
@@ -635,10 +680,10 @@ convertPpmRaster(FILE *             const ifP,
             unsigned int col;
             for (col = 0; col < cols; ++col) {
                 double val;
-                readVal(ifP, fitsHdr.bitpix, &val);
+                readVal(ifP, rasterInfo.valFmt, &val);
                 {
                     double const t = scale *
-                        (val * fitsHdr.bscale + fitsHdr.bzer - datamin);
+                        (val * rasterInfo.bscale + rasterInfo.bzer - datamin);
                     xelval const sample = MAX(0, MIN(t, maxval));
 
                     switch (plane) {
@@ -655,17 +700,17 @@ convertPpmRaster(FILE *             const ifP,
 
 
 static void
-convertRaster(FILE *             const ifP,
-              unsigned int       const cols,
-              unsigned int       const rows,
-              xelval             const maxval,
-              bool               const forceplain,
-              bool               const multiplane,
-              unsigned int       const desiredImage,
-              unsigned int       const imageCount,
-              struct FITS_Header const fitsHdr,
-              double             const scale,
-              double             const datamin) {
+convertRaster(FILE *                const ifP,
+              unsigned int          const cols,
+              unsigned int          const rows,
+              xelval                const maxval,
+              bool                  const forceplain,
+              bool                  const multiplane,
+              unsigned int          const desiredImage,
+              unsigned int          const imageCount,
+              struct fitsRasterInfo const rasterInfo,
+              double                const scale,
+              double                const datamin) {
 
     xel ** xels;
     int format;
@@ -674,12 +719,12 @@ convertRaster(FILE *             const ifP,
 
     if (multiplane) {
         format = PPM_FORMAT;
-        convertPpmRaster(ifP, cols, rows, maxval, fitsHdr, scale, datamin,
+        convertPpmRaster(ifP, cols, rows, maxval, rasterInfo, scale, datamin,
                          xels);
     } else {
         format = PGM_FORMAT;
         convertPgmRaster(ifP, cols, rows, maxval,
-                         desiredImage, imageCount, fitsHdr, scale, datamin,
+                         desiredImage, imageCount, rasterInfo, scale, datamin,
                          xels);
     }
     pnm_writepnm(stdout, xels, cols, rows, maxval, format, forceplain);
@@ -689,15 +734,16 @@ convertRaster(FILE *             const ifP,
 
 
 int
-main(int argc, char * argv[]) {
+main(int argc, const char * argv[]) {
 
-    struct cmdlineInfo cmdline;
+    struct CmdlineInfo cmdline;
     FILE * ifP;
     unsigned int cols, rows;
     xelval maxval;
     double scale;
     double datamin, datamax;
     struct FITS_Header fitsHeader;
+    struct fitsRasterInfo rasterInfo;
 
     unsigned int imageCount;
     unsigned int desiredImage;
@@ -709,7 +755,7 @@ main(int argc, char * argv[]) {
            is undefined
         */
   
-    pnm_init( &argc, argv );
+    pm_proginit(&argc, argv);
   
     parseCommandLine(argc, argv, &cmdline);
 
@@ -726,6 +772,10 @@ main(int argc, char * argv[]) {
     cols = fitsHeader.naxis1;
     rows = fitsHeader.naxis2;
 
+    rasterInfo.bscale = fitsHeader.bscale;
+    rasterInfo.bzer   = fitsHeader.bzer;
+    rasterInfo.valFmt = valFmtFromBitpix(fitsHeader.bitpix);
+
     interpretPlanes(fitsHeader, cmdline.image, cmdline.verbose,
                     &imageCount, &multiplane, &desiredImage);
 
@@ -735,7 +785,7 @@ main(int argc, char * argv[]) {
                   cmdline.min, cmdline.max,
                   &datamin, &datamax);
 
-    maxval = determineMaxval(cmdline, fitsHeader, datamax, datamin);
+    maxval = determineMaxval(cmdline, rasterInfo.valFmt, datamax, datamin);
 
     if (datamax - datamin == 0)
         scale = 1.0;
@@ -747,10 +797,13 @@ main(int argc, char * argv[]) {
     else
         convertRaster(ifP, cols, rows, maxval, cmdline.noraw,
                       multiplane, desiredImage, imageCount,
-                      fitsHeader, scale, datamin);
+                      rasterInfo, scale, datamin);
 
     pm_close(ifP);
     pm_close(stdout);
 
     return 0;
 }
+
+
+
diff --git a/converter/other/giftopnm.c b/converter/other/giftopnm.c
index 4cba5068..76cf4bff 100644
--- a/converter/other/giftopnm.c
+++ b/converter/other/giftopnm.c
@@ -8,8 +8,9 @@
 /* |   provided "as is" without express or implied warranty.           | */
 /* +-------------------------------------------------------------------+ */
 
-/* There is a copy of the GIF89 specification, as defined by its
-   inventor, Compuserve, in 1989, at http://members.aol.com/royalef/gif89a.txt
+/* There is a copy of the GIF89 specification, as defined by its inventor,
+   Compuserve, in 1990 at: 
+   http://www.w3.org/Graphics/GIF/spec-gif89a.txt
 
    This covers the high level format, but does not cover how the "data"
    contents of a GIF image represent the raster of color table indices.
@@ -18,11 +19,12 @@
    describe the Lempel-Ziv base.
 */
 
-#define _BSD_SOURCE   /* Make sure strcasecmp() is in string.h */
-
+#define _XOPEN_SOURCE 500  /* Make sure strdup() is in string.h */
+#define _BSD_SOURCE   /* for strcaseeq */
 #include <string.h>
 #include <assert.h>
 
+#include "pm_config.h"
 #include "pm_c_util.h"
 #include "mallocvar.h"
 #include "nstring.h"
@@ -38,35 +40,18 @@
 
 #define MAX_LZW_BITS  12
 
-#define INTERLACE      0x40
-#define LOCALCOLORMAP  0x80
-#define BitSet(byte, bit)      (((byte) & (bit)) == (bit))
-
-#if !defined(BYTE_ORDER) || !defined(LITTLE_ENDIAN)
-  /* make sure (BYTE_ORDER == LITTLE_ENDIAN) is FALSE */ 
-  #define BYTE_ORDER    0
-  #define LITTLE_ENDIAN 1
-#endif
-
-#if defined(__x86_64__) | defined(__i486__) | defined(__vax__)
-# define UNALIGNED_OK 1
-#else
-# define UNALIGNED_OK 0
+#ifndef   FASTPBMRENDER
+  #define FASTPBMRENDER TRUE
 #endif
 
+static const bool useFastPbmRender = FASTPBMRENDER;
 
+#ifndef   REPORTLZWCODES
+  #define REPORTLZWCODES FALSE
+#endif
 
-static __inline__ bool
-ReadOK(FILE *          const fileP,
-       unsigned char * const buffer,
-       size_t          const len) {
-
-    size_t bytesRead;
-
-    bytesRead = fread(buffer, len, 1, fileP);
-
-    return (bytesRead != 0);
-}
+static const bool wantLzwCodes = REPORTLZWCODES;
+    /* In verbose output, include all the LZW codes */
 
 
 
@@ -78,41 +63,37 @@ readFile(FILE *          const ifP,
 
     size_t bytesRead;
 
-    bytesRead = fread(buffer, len, 1, ifP);
+    bytesRead = fread(buffer, 1, len, ifP);
 
     if (bytesRead == len)
         *errorP = NULL;
     else {
         if (ferror(ifP))
-            asprintfN(errorP, "Error reading file.  errno=%d (%s)",
-                      errno, strerror(errno));
+            pm_asprintf(errorP, "Error reading file.  errno=%d (%s)",
+                        errno, strerror(errno));
         else if (feof(ifP))
-            asprintfN(errorP, "End of file encountered");
+            pm_asprintf(errorP, "End of file encountered");
         else
-            asprintfN(errorP, "Short read -- %u bytes of %u",
-                              (unsigned)bytesRead, (unsigned)len);
+            pm_asprintf(errorP, "Short read -- %u bytes of %u",
+                        (unsigned)bytesRead, (unsigned)len);
     }
 }
 
 
 
-#define LM_to_uint(a,b)                        (((b)<<8)|(a))
-
-static int const maxnum_lzwCode = (1<<MAX_LZW_BITS);
-
-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 * input_filespec;  /* Filespecs of input files */
+    const char * inputFilespec;  /* Filespecs of input files */
     unsigned int verbose;    /* -verbose option */
     unsigned int comments;   /* -comments option */
-    bool all_images;  /* He wants all the images */
-    unsigned int image_no;
+    bool allImages;  /* He wants all the images */
+    unsigned int imageNum;
         /* image number he wants from input, starting at 0.  Undefined
-           if all_images is TRUE
+           if allImages is TRUE
         */
-    const char * alpha_filename;
+    const char * alphaFileName;
     unsigned int quitearly;
     unsigned int repair;
 };
@@ -121,13 +102,13 @@ struct cmdlineInfo {
 
 static void
 parseCommandLine(int argc, char ** argv,
-                 struct cmdlineInfo * const cmdlineP) {
+                 struct CmdlineInfo * const cmdlineP) {
 /*----------------------------------------------------------------------------
    Note that the file spec array we return is stored in the storage that
    was passed to us as the argv array.
 -----------------------------------------------------------------------------*/
     optEntry * option_def;
-        /* Instructions to optParseOptions3 on how to parse our options.
+        /* Instructions to pm_optParseOptions3 on how to parse our options.
          */
     
     optStruct3 opt;
@@ -150,120 +131,198 @@ parseCommandLine(int argc, char ** argv,
             &cmdlineP->repair,          0);
     OPTENT3(0, "image",       OPT_STRING, &image,
             &imageSpec,                 0);
-    OPTENT3(0, "alphaout",    OPT_STRING, &cmdlineP->alpha_filename, 
+    OPTENT3(0, "alphaout",    OPT_STRING, &cmdlineP->alphaFileName, 
             &alphaSpec,                 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 */
 
-    optParseOptions3( &argc, argv, opt, sizeof(opt), 0);
+    pm_optParseOptions3( &argc, argv, opt, sizeof(opt), 0);
         /* Uses and sets argc, argv, and some of *cmdlineP and others. */
 
+    free(option_def);
+
     if (!imageSpec) {
-        cmdlineP->image_no = 0;
-        cmdlineP->all_images = FALSE;
+        cmdlineP->imageNum = 0;
+        cmdlineP->allImages = FALSE;
     } else {
-        if (strcasecmp(image, "all") == 0) 
-            cmdlineP->all_images = TRUE;
-        else {
+        if (strcaseeq(image, "all")) { 
+            cmdlineP->allImages = TRUE;
+        } else {
             char * tailptr;
 
-            long const imageNo = strtol(image, &tailptr, 10);
+            long const imageNum = strtol(image, &tailptr, 10);
 
             if (*tailptr != '\0')
                 pm_error("Invalid value for '-image' option.  Must be either "
                          "a number or 'all'.  You specified '%s'", image);
-            else if (imageNo < 0)
+            else if (imageNum < 0)
                 pm_error("Invalid value for '-image' option.  Must be "
-                         "positive.  You specified %ld", imageNo);
-            else if (imageNo == 0)
+                         "positive.  You specified %ld", imageNum);
+            else if (imageNum == 0)
                 pm_error("Invalid value for 'image' option.  You specified "
                          "zero.  The first image is 1.");
 
-            cmdlineP->all_images = FALSE;
-            cmdlineP->image_no = (unsigned int) imageNo - 1;
+            cmdlineP->allImages = FALSE;
+            cmdlineP->imageNum = (unsigned int) imageNum - 1;
         }
     }
     
     if (argc-1 == 0) 
-        cmdlineP->input_filespec = "-";
+        cmdlineP->inputFilespec = "-";
     else if (argc-1 != 1)
         pm_error("Program takes zero or one argument (filename).  You "
                  "specified %d", argc-1);
     else
-        cmdlineP->input_filespec = argv[1];
+        cmdlineP->inputFilespec = argv[1];
 
     if (!alphaSpec) 
-        cmdlineP->alpha_filename = NULL;
+        cmdlineP->alphaFileName = NULL;
 }
 
 
-typedef unsigned char gifColorMap[3][MAXCOLORMAPSIZE];
 
-struct gifScreen {
-    unsigned int    Width;
-    unsigned int    Height;
-    gifColorMap     ColorMap;
-    unsigned int    ColorMapSize;
-        /* Number of colors in the color map. */
-    unsigned int    ColorResolution;
-    unsigned int    Background;
-    unsigned int    AspectRatio;
+typedef struct {
+    unsigned char map[MAXCOLORMAPSIZE][3];
+    unsigned int size;
+} GifColorMap;
+
+/*----------------------------------------------------------------------
+  On GIF color maps:
+
+  The color map can have any number of colors up to 256.  If the color map
+  size is not a power of 2 the table is padded up.  The LZW "clear" control
+  code is always placed at a power of 2.
+
+  The color map and code table of an image with three colors (black, white
+  and red) will look like this:
+
+  0: black
+  1: white
+  2: red
+  3: (unused)
+  4: clear code
+  5: end code
+  6: first LZW string code
+  7: second LZW string code
+     ...
+  4095: last LZW string code
+
+  Some GIFs have odd color maps.
+
+  (1) Some encoders use fixed color maps.  A GIF image produced by this
+      kind of encoder may have colors in the table which never appear in
+      the image.
+
+      Note that we make the decision on whether the output should be PBM,
+      PGM or PPM by scanning through the color map, not the entire image.
+      Any unused colors will influence our decision.
+
+  (2) There are GIF editors which allow one to rewrite the color map.
+      These programs will produce color maps with multiple entries for the
+      same color.
+
+  (3) Some encoders put the transparent code outside the color map.
+      (In the above example, the unused value 3.)  Around 2000 there were
+      several encoders that did this, including "Animation Gif Maker
+      (GifAnim)".  As of 2012, such images are rare.  We reject them with
+      an error message unless -repair is specified.
+-----------------------------------------------------------------------*/
+
+
+struct GifScreen {
+    unsigned int    width;
+    unsigned int    height;
+    bool            hasGlobalColorMap;
+        /* The stream has a global color map, to wit 'colorMap'.
+           (If the stream doesn't have a global color map, the individual
+           images must each have a local color map)
+        */
+    GifColorMap     colorMap;
+        /* The global color map for the stream.  Meaningful only if
+           'hasGlobalColorMap' is true.
+        */
+    unsigned int    colorResolution;
+    unsigned int    background;
+    unsigned int    aspectRatio;
         /* Aspect ratio of each pixel, times 64, minus 15.  (i.e. 1 => 1:4).
            But Zero means 1:1.
         */
-    int      hasGray;  
+    bool     hasGray;  
         /* Boolean: global colormap has at least one gray color
            (not counting black and white) 
         */
-    int      hasColor;
+    bool     hasColor;
         /* Boolean: global colormap has at least one non-gray,
            non-black, non-white color 
         */
 };
 
-struct gif89 {
-       int     transparent;
-       int     delayTime;
-       int     inputFlag;
-       int     disposal;
+struct Gif89 {
+    bool         haveTransColor;
+        /* The GIF specifies a transparent background color */
+    unsigned int transparentIndex;
+        /* The color index of the color which is the transparent 
+           background color.
+
+           Meaningful only when 'haveTransColor' is true
+        */
+    bool          haveDelayTime;
+    unsigned int  delayTime;
+    bool          haveInputFlag;
+    unsigned char inputFlag;
+    bool          haveDisposal;
+    unsigned char disposal;
 };
 
 static void
-initGif89(struct gif89 * const gif89P) {
-    gif89P->transparent = -1;
-    gif89P->delayTime = -1;
-    gif89P->inputFlag = -1;
-    gif89P->disposal = -1;
+initGif89(struct Gif89 * const gif89P) {
+    gif89P->haveTransColor = false;
+    gif89P->haveDelayTime  = false;
+    gif89P->haveInputFlag  = false;
+    gif89P->haveDisposal   = false;
 }       
 
 
-static int verbose;
-int    showComment;
+static bool verbose;
+static bool showComment;
 
 
 
 static void
-readColorMap(FILE *ifP, const int colormapsize, 
-             unsigned char colormap[3][MAXCOLORMAPSIZE],
-             int *hasGrayP, int * const hasColorP) {
+readColorMap(FILE *        const ifP,
+             unsigned int  const cmapSize,
+             GifColorMap * const cmapP,
+             bool *        const hasGrayP,
+             bool *        const hasColorP) {
+/*----------------------------------------------------------------------------
+   Read a color map from a GIF stream, where the stream is on *ifP,
+   which is positioned to a color map, which is 'cmapSize' bytes long.
 
-    int             i;
-    unsigned char   rgb[3];
+   Return as *cmapP that color map.
 
-    assert(colormapsize <= MAXCOLORMAPSIZE);
+   Furthermore, analyze that color map and return *hasGrayP == true iff it
+   contains any gray (black and white don't count) and *hasColorP == true iff
+   it contains anything that is not gray or black or white.
+-----------------------------------------------------------------------------*/
+    unsigned int  i;
+    unsigned char rgb[3];
+
+    assert(cmapSize <= MAXCOLORMAPSIZE);
 
     *hasGrayP = FALSE;  /* initial assumption */
     *hasColorP = FALSE;  /* initial assumption */
 
-    for (i = 0; i < colormapsize; ++i) {
-        if (! ReadOK(ifP, rgb, sizeof(rgb)))
-            pm_error("Unable to read Color %d from colormap", i);
+    for (i = 0; i < cmapSize; ++i) {
+        const char * error;
+        readFile(ifP, rgb, sizeof(rgb), &error);
+        if (error)
+            pm_error("Unable to read Color %u from colormap.  %s", i, error);
 
-        colormap[CM_RED][i] = rgb[0] ;
-        colormap[CM_GRN][i] = rgb[1] ;
-        colormap[CM_BLU][i] = rgb[2] ;
+        cmapP->map[i][CM_RED] = rgb[0] ;
+        cmapP->map[i][CM_GRN] = rgb[1] ;
+        cmapP->map[i][CM_BLU] = rgb[2] ;
 
         if (rgb[0] == rgb[1] && rgb[1] == rgb[2]) {
             if (rgb[0] != 0 && rgb[0] != GIFMAXVAL)
@@ -271,6 +330,7 @@ readColorMap(FILE *ifP, const int colormapsize,
         } else
             *hasColorP = TRUE;
     }
+    cmapP->size = cmapSize;
 }
 
 
@@ -302,13 +362,17 @@ getDataBlock(FILE *          const ifP,
    If we hit EOF or have an I/O error reading the data portion of the
    DataBlock, we exit the program with pm_error().
 -----------------------------------------------------------------------------*/
+    long const pos = ftell(ifP);
+
     unsigned char count;
-    bool successfulRead;
+    const char * error;
     
-    long const pos = ftell(ifP);
-    successfulRead = ReadOK(ifP, &count, 1);
-    if (!successfulRead) {
-        pm_message("EOF or error in reading DataBlock size from file" );
+    readFile(ifP, &count, sizeof(count), &error);
+
+    if (error) {
+        pm_message("EOF or error in reading DataBlock size from file.  %s",
+                   error);
+        pm_strfree(error);
         *errorP = NULL;
         *eofP = TRUE;
         *lengthP = 0;
@@ -322,17 +386,18 @@ getDataBlock(FILE *          const ifP,
             *errorP = NULL;
             zeroDataBlock = TRUE;
         } else {
-            bool successfulRead;
+            const char * error;
 
             zeroDataBlock = FALSE;
-            successfulRead = ReadOK(ifP, buf, count); 
+            readFile(ifP, buf, count, &error); 
 
-            if (successfulRead) 
+            if (error) {
+                pm_asprintf(errorP,
+                            "Unable to read data portion of %u byte "
+                            "DataBlock from file.  %s", count, error);
+                pm_strfree(error);
+            } else
                 *errorP = NULL;
-            else
-                asprintfN(errorP,
-                          "EOF or error reading data portion of %u byte "
-                          "DataBlock from file", count);
         }
     }
 }
@@ -348,7 +413,7 @@ readThroughEod(FILE * const ifP) {
   If there is no EOD marker between the present file position and EOF,
   we read to EOF and issue warning message about a missing EOD marker.
 -----------------------------------------------------------------------------*/
-    unsigned char buf[260];
+    unsigned char buf[256];
     bool eod;
 
     eod = FALSE;  /* initial value */
@@ -371,6 +436,27 @@ readThroughEod(FILE * const ifP) {
 
 
 static void
+doPlainTextExtension(FILE * const ifP) {
+#if 0
+    /* incomplete code fragment, attempt to handle Plain Text Extension */
+    GetDataBlock(ifP, (unsigned char*) buf, &eof, &length);
+    
+    lpos   = LM_to_uint(buf[0], buf[1]);
+    tpos   = LM_to_uint(buf[2], buf[3]);
+    width  = LM_to_uint(buf[4], buf[5]);
+    height = LM_to_uint(buf[6], buf[7]);
+    cellw  = buf[8];
+    cellh  = buf[9];
+    foreground = buf[10];
+    background = buf[11];
+#else
+    readThroughEod(ifP);
+#endif
+}
+
+
+
+static void
 doCommentExtension(FILE * const ifP) {
 /*----------------------------------------------------------------------------
    Read the rest of a comment extension from the input file 'ifP' and handle
@@ -380,7 +466,7 @@ doCommentExtension(FILE * const ifP) {
    it could have nonprintable characters or embedded nulls.  I don't know if
    the GIF spec requires regular text or not.
 -----------------------------------------------------------------------------*/
-    char buf[255+1];
+    char buf[256];
     unsigned int blocklen;  
     bool done;
 
@@ -405,13 +491,22 @@ doCommentExtension(FILE * const ifP) {
 
 
 
+static unsigned int
+LM_to_uint(unsigned char const a,
+           unsigned char const b) {
+
+    return ((unsigned int)b << 8) | ((unsigned int) a << 0);
+}
+
+
+
 static void 
 doGraphicControlExtension(FILE *         const ifP,
-                          struct gif89 * const gif89P) {
+                          struct Gif89 * const gif89P) {
 
     bool eof;
     unsigned int length;
-    static unsigned char buf[256];
+    unsigned char buf[256];
     const char * error;
 
     getDataBlock(ifP, buf, &eof, &length, &error);
@@ -425,11 +520,16 @@ doGraphicControlExtension(FILE *         const ifP,
                  "It must be at least 4 bytes; it is %d bytes.",
                  length);
     else {
+        gif89P->haveDisposal = true;
         gif89P->disposal = (buf[0] >> 2) & 0x7;
+        gif89P->haveInputFlag = true;
         gif89P->inputFlag = (buf[0] >> 1) & 0x1;
-        gif89P->delayTime = LM_to_uint(buf[1],buf[2]);
-        if ((buf[0] & 0x1) != 0)
-            gif89P->transparent = buf[3];
+        gif89P->haveDelayTime = true;
+        gif89P->delayTime = LM_to_uint(buf[1], buf[2]);
+        if ((buf[0] & 0x1) != 0) {
+            gif89P->haveTransColor = true;
+            gif89P->transparentIndex = buf[3];
+        }
         readThroughEod(ifP);
     }
 }
@@ -437,34 +537,16 @@ doGraphicControlExtension(FILE *         const ifP,
 
 
 static void
-doExtension(FILE * const ifP, int const label, struct gif89 * const gif89P) {
+doExtension(FILE *         const ifP,
+            unsigned char  const label,
+            struct Gif89 * const gif89P) {
+
     const char * str;
     
     switch (label) {
     case 0x01:              /* Plain Text Extension */
         str = "Plain Text";
-#ifdef notdef
-        GetDataBlock(ifP, (unsigned char*) buf, &eof, &length);
-        
-        lpos   = LM_to_uint(buf[0], buf[1]);
-        tpos   = LM_to_uint(buf[2], buf[3]);
-        width  = LM_to_uint(buf[4], buf[5]);
-        height = LM_to_uint(buf[6], buf[7]);
-        cellw  = buf[8];
-        cellh  = buf[9];
-        foreground = buf[10];
-        background = buf[11];
-        
-        while (GetDataBlock(ifP, (unsigned char*) buf) != 0) {
-            PPM_ASSIGN(xels[ypos][xpos],
-                       cmap[CM_RED][v],
-                       cmap[CM_GRN][v],
-                       cmap[CM_BLU][v]);
-            ++index;
-        }
-#else
-        readThroughEod(ifP);
-#endif
+        doPlainTextExtension(ifP);
         break;
     case 0xff:              /* Application Extension */
         str = "Application";
@@ -479,21 +561,20 @@ doExtension(FILE * const ifP, int const label, struct gif89 * const gif89P) {
         doGraphicControlExtension(ifP, gif89P);
         break;
     default: {
-        static char buf[256];
-        str = buf;
+        char buf[256];
         sprintf(buf, "UNKNOWN (0x%02x)", label);
+        str = buf;
         pm_message("Ignoring unrecognized extension (type 0x%02x)", label);
         readThroughEod(ifP);
-        }
-        break;
+    } break;
     }
     if (verbose)
-        pm_message(" got a '%s' extension", str );
+        pm_message(" got a '%s' extension", str);
 }
 
 
 
-struct getCodeState {
+struct GetCodeState {
     unsigned char buf[280];
         /* This is the buffer through which we read the data from the 
            stream.  We must buffer it because we have to read whole data
@@ -519,11 +600,11 @@ struct getCodeState {
 
 static void
 getAnotherBlock(FILE *                const ifP, 
-                struct getCodeState * const gsP,
+                struct GetCodeState * const gsP,
                 const char **         const errorP) {
 
     unsigned int count;
-    unsigned int assumed_count;
+    unsigned int assumedCount;
     bool eof;
 
     /* Shift buffer down so last two bytes are now the
@@ -548,22 +629,22 @@ getAnotherBlock(FILE *                const ifP,
                        "file is malformed, but we are proceeding "
                        "anyway as if an EOD marker were at the end "
                        "of the file.");
-            assumed_count = 0;
+            assumedCount = 0;
         } else
-            assumed_count = count;
+            assumedCount = count;
 
-        gsP->streamExhausted = (assumed_count == 0);
+        gsP->streamExhausted = (assumedCount == 0);
         
-        gsP->bufCount += assumed_count;
+        gsP->bufCount += assumedCount;
     }
 }
 
 
 
-static struct getCodeState getCodeState;
+static struct GetCodeState getCodeState;
 
 static void
-getCode_init(struct getCodeState * const getCodeStateP) {
+getCode_init(struct GetCodeState * const getCodeStateP) {
     
     /* Fake a previous data block */
     getCodeStateP->buf[0] = 0;
@@ -615,7 +696,7 @@ bitsOfLeBuffer(const unsigned char * const buf,
 
 
 static void
-getCode_get(struct getCodeState * const gsP,
+getCode_get(struct GetCodeState * const gsP,
             FILE *                const ifP, 
             int                   const codeSize,
             bool *                const eofP,
@@ -668,6 +749,9 @@ getCode_get(struct getCodeState * const gsP,
         } else {
             *codeP = bitsOfLeBuffer(gsP->buf, gsP->curbit, codeSize);
 
+            if (verbose && wantLzwCodes)
+                pm_message("LZW code=0x%03x [%d]", *codeP, codeSize);
+
             gsP->curbit += codeSize;
             *eofP = FALSE;
         }
@@ -676,18 +760,17 @@ getCode_get(struct getCodeState * const gsP,
 
 
 
-
-struct stack {
+struct Stack {
     /* Stack grows from low addresses to high addresses */
-    int * stack;  /* malloc'ed array */
-    int * sp;     /* stack pointer */
-    int * top;    /* next word above top of stack */
+    unsigned char * stack;  /* malloc'ed array */
+    unsigned char * sp;     /* stack pointer */
+    unsigned char * top;    /* next word above top of stack */
 };
 
 
 
 static void 
-initStack(struct stack * const stackP, unsigned int const size) {
+initStack(struct Stack * const stackP, unsigned int const size) {
 
     MALLOCARRAY(stackP->stack, size);
     if (stackP->stack == NULL)
@@ -699,7 +782,7 @@ initStack(struct stack * const stackP, unsigned int const size) {
 
 
 static void
-pushStack(struct stack * const stackP, int const value) {
+pushStack(struct Stack * const stackP, unsigned char const value) {
 
     if (stackP->sp >= stackP->top)
         pm_error("stack overflow");
@@ -710,14 +793,14 @@ pushStack(struct stack * const stackP, int const value) {
 
 
 static bool
-stackIsEmpty(const struct stack * const stackP) {
+stackIsEmpty(const struct Stack * const stackP) {
     return stackP->sp == stackP->stack;
 }
 
 
 
-static int
-popStack(struct stack * const stackP) {
+static unsigned char
+popStack(struct Stack * const stackP) {
 
     if (stackP->sp <= stackP->stack)
         pm_error("stack underflow");
@@ -728,7 +811,7 @@ popStack(struct stack * const stackP) {
 
 
 static void
-termStack(struct stack * const stackP) {
+termStack(struct Stack * const stackP) {
     free(stackP->stack);
     stackP->stack = NULL;
 }
@@ -774,98 +857,164 @@ termStack(struct stack * const stackP) {
 
 -----------------------------------------------------------------------------*/
 
+static int const maxLzwCodeCt = (1<<MAX_LZW_BITS);
 
-struct decompressor {
-    struct stack stack;
-    int      fresh;
+struct Decompressor {
+    struct Stack stack;
+    bool fresh;
         /* The stream is right after a clear code or at the very beginning */
-    int      codeSize;
+    unsigned int codeSize;
         /* The current code size -- each LZW code in this part of the image
            is this many bits.  Ergo, we read this many bits at a time from
            the stream.
         */
-    int      maxnum_code;
+    unsigned int maxCodeCt;
         /* The maximum number of LZW codes that can be represented with the 
            current code size.  (1 << codeSize)
         */
-    int      next_tableSlot;
+    unsigned int nextTableSlot;
         /* Index in the code translation table of the next free entry */
     unsigned int firstcode;
         /* This is always a true data element code */
-    int      prevcode;
+    unsigned int prevcode;
         /* The code just before, in the image, the one we're processing now */
-    int      table[2][(1 << MAX_LZW_BITS)];
 
     /* The following are constant for the life of the decompressor */
     FILE * ifP;
-    int init_codeSize;
-    int max_dataVal;
-    int clear_code;
-    int end_code; 
+    unsigned int initCodeSize;
+    unsigned int cmapSize;
+    unsigned int maxDataVal;
+    unsigned int clearCode;
+    unsigned int endCode;
+    bool haveTransColor;
+    unsigned int transparentIndex;
+        /* meaningful only when 'haveTransColor' is true */
+    bool tolerateBadInput; 
+        /* We are to tolerate bad input data as best we can, rather than
+           just declaring an error and bailing out.
+        */
+    unsigned int table[(1 << MAX_LZW_BITS)][2];   /* LZW code table */  
 };
 
 
 
 static void
-resetDecompressor(struct decompressor * const decompP) {
+resetDecompressor(struct Decompressor * const decompP) {
+
+    decompP->codeSize      = decompP->initCodeSize+1;
+    decompP->maxCodeCt     = 1 << decompP->codeSize;
+    decompP->nextTableSlot = decompP->maxDataVal + 3;
+    decompP->fresh         = TRUE;
+}
 
-    decompP->codeSize = decompP->init_codeSize+1;
-    decompP->maxnum_code = 1 << decompP->codeSize;
-    decompP->next_tableSlot = decompP->max_dataVal + 3;
-    decompP->fresh = 1;
+
+
+static void
+validateTransparentIndex(unsigned int const transparentIndex,
+                         bool         const tolerateBadInput,
+                         unsigned int const cmapSize,
+                         unsigned int const maxDataVal) {
+
+    if (transparentIndex >= cmapSize) {
+        if (tolerateBadInput) {
+            if (transparentIndex > maxDataVal)
+                pm_error("Invalid transparent index value: %d",
+                         transparentIndex);
+        } else {
+            pm_error("Invalid transparent index value %d in image with "
+                     "only %u colors.  %s",
+                     transparentIndex, cmapSize,
+                     transparentIndex <= maxDataVal ?
+                     "" :
+                     "Use the -repair option to try to render the "
+                     "image overriding this error.");
+        }
+    }
 }
 
 
 
 static void
-lzwInit(struct decompressor * const decompP, 
+lzwInit(struct Decompressor * const decompP, 
         FILE *                const ifP,
-        int                   const init_codeSize) {
+        int                   const initCodeSize,
+        unsigned int          const cmapSize,
+        bool                  const haveTransColor,
+        unsigned int          const transparentIndex,
+        bool                  const tolerateBadInput) {
 
+    unsigned int const maxDataVal = (1 << initCodeSize) - 1;
+    
     if (verbose)
         pm_message("Image says the initial compression code size is "
                    "%d bits", 
-                   init_codeSize);
+                   initCodeSize);
     
-    decompP->ifP = ifP;
-    decompP->init_codeSize = init_codeSize;
-
-    assert(decompP->init_codeSize < sizeof(decompP->max_dataVal) * 8);
-
-    decompP->max_dataVal = (1 << init_codeSize) - 1;
-    decompP->clear_code = decompP->max_dataVal + 1;
-    decompP->end_code = decompP->max_dataVal + 2;
+    decompP->ifP              = ifP;
+    decompP->initCodeSize     = initCodeSize;
+    decompP->cmapSize         = cmapSize;
+    decompP->tolerateBadInput = tolerateBadInput;
+    decompP->maxDataVal       = maxDataVal;
+    decompP->clearCode        = maxDataVal + 1;
+    decompP->endCode          = maxDataVal + 2;
 
     if (verbose)
-        pm_message("Initial code size is %u bits; clear code = 0x%x, "
-                   "end code = 0x%x",
-                   decompP->init_codeSize, 
-                   decompP->clear_code, decompP->end_code);
+        pm_message("Initial code size is %u bits; clear code = 0x%03x, "
+                   "end code = 0x%03x",
+                   decompP->initCodeSize, 
+                   decompP->clearCode, decompP->endCode);
     
     /* The entries in the translation table for true data codes are
-       constant throughout the stream.  We set them now and they never
-       change.
+       constant throughout the image.  For PBM output we make an
+       adjustment later.  Once set entries never change.
     */
     {
         unsigned int i;
-        for (i = 0; i <= decompP->max_dataVal; ++i) {
-            decompP->table[0][i] = 0;
-            decompP->table[1][i] = i;
+        for (i = 0; i <= maxDataVal; ++i) {
+            decompP->table[i][0] = 0;
+            decompP->table[i][1] = i < cmapSize ? i : 0;
         }
     }
+    decompP->haveTransColor   = haveTransColor;
+    decompP->transparentIndex = transparentIndex;
+
+    if (haveTransColor)
+        validateTransparentIndex(transparentIndex, tolerateBadInput,
+                                 cmapSize, maxDataVal);
+
     resetDecompressor(decompP);
 
     getCode_init(&getCodeState);
     
     decompP->fresh = TRUE;
     
-    initStack(&decompP->stack, maxnum_lzwCode * 2);
+    initStack(&decompP->stack, maxLzwCodeCt);
+
+    assert(decompP->initCodeSize < sizeof(decompP->maxDataVal) * 8);
 }
 
 
 
 static void
-lzwTerm(struct decompressor * const decompP) {
+lzwAdjustForPBM(struct Decompressor * const decompP,
+                GifColorMap           const cmap) {
+/*----------------------------------------------------------------------------
+  In the PBM case we use the table index value directly instead of looking up
+  the color map for each pixel.
+
+  Note that cmap.size is not always 2.
+
+  Similar logic should work for PGM.
+----------------------------------------------------------------------------*/
+    unsigned int i;
+    for (i = 0; i < cmap.size; ++i)
+        decompP->table[i][1] = cmap.map[i][0] == 0 ? PBM_BLACK : PBM_WHITE;
+}
+
+
+
+static void
+lzwTerm(struct Decompressor * const decompP) {
 
     termStack(&decompP->stack);
 }
@@ -873,8 +1022,32 @@ lzwTerm(struct decompressor * const decompP) {
 
 
 static void
-expandCodeOntoStack(struct decompressor * const decompP,
-                    int                   const incode,
+pushWholeStringOnStack(struct Decompressor * const decompP,
+                       unsigned int          const code0) {
+/*----------------------------------------------------------------------------
+  Get the whole string that compression code 'code0' represents and push
+  it onto the code stack so the leftmost code is on top.  Set
+  decompP->firstcode to the first (leftmost) code in that string.
+-----------------------------------------------------------------------------*/
+    unsigned int code;
+    unsigned int stringCount;
+
+    for (stringCount = 0, code = code0;
+         code > decompP->maxDataVal;
+         ++stringCount, code = decompP->table[code][0]
+        ) {
+
+        pushStack(&decompP->stack, decompP->table[code][1]);
+    }
+    decompP->firstcode = decompP->table[code][1];
+    pushStack(&decompP->stack, decompP->firstcode);
+}
+
+
+
+static void
+expandCodeOntoStack(struct Decompressor * const decompP,
+                    unsigned int          const incode,
                     const char **         const errorP) {
 /*----------------------------------------------------------------------------
    'incode' is an LZW string code.  It represents a string of true data
@@ -889,119 +1062,125 @@ expandCodeOntoStack(struct decompressor * const decompP,
    from which it was built is invalid), fail (return text explanation
    as *errorP).
 -----------------------------------------------------------------------------*/
-    int code;
-    const char * error;
-
-    error = NULL; /* Initial value */
-
-    if (incode < decompP->next_tableSlot) 
-        code = incode;
-    else {
-        /* It's a code that isn't in our translation table yet
-        
-           The only thing it could legally be is one higher than the
-           highest one we've seen so far.
-        */
-        if (code > decompP->next_tableSlot) {
-            /* We just abort because we added this to stable code to fix
-               a bug and we don't want to disturb stable code more than we
-               have to.
-            */
-            pm_error("Error in GIF image: LZW string code %u "
-                     "is neither a previously defined one nor the "
-                     "next in sequence to define (%u)",
-                     code, decompP->next_tableSlot);
-        }
-        pushStack(&decompP->stack, decompP->firstcode);
-        code = decompP->prevcode;
+    unsigned int code;
+
+    *errorP = NULL; /* Initial value */
+
+    if (incode <= decompP->maxDataVal) {
+        if (incode < decompP->cmapSize)
+            code = incode;      /* Direct index */
+        else if (decompP->tolerateBadInput &&
+                 decompP->haveTransColor &&
+                 decompP->table[incode][1] == decompP->transparentIndex)
+            /* transparent code outside cmap   exceptional case */
+            code = incode;
+        else
+            pm_asprintf(errorP, "Error in GIF image: invalid color code %u. "
+                        "Valid color values are 0 - %u",
+                        incode, decompP->cmapSize - 1);
     }
-
-    {
-        /* Get the whole string that this compression code
-           represents and push it onto the code stack so the
-           leftmost code is on top.  Set decompP->firstcode to the
-           first (leftmost) code in that string.
+    else if (incode < decompP->nextTableSlot)  
+        /* LZW string, defined */
+        code = incode;
+    else if  (incode == decompP->nextTableSlot && !decompP->fresh) {
+        /* It's a code that isn't in our translation table yet.
+           This does not happen with the decoder in a fresh state.
         */
+        if (wantLzwCodes && verbose)
+            pm_message ("LZW code valid, but not in decoder table");
 
-        unsigned int stringCount;
-        stringCount = 0;
-
-        while (code > decompP->max_dataVal && !error) {
-            if (stringCount > maxnum_lzwCode) {
-                asprintfN(&error,
-                          "Error in GIF image: contains LZW string loop");
-            } else {
-                ++stringCount;
-                pushStack(&decompP->stack, decompP->table[1][code]);
-                code = decompP->table[0][code];
-            }
-        }
-        decompP->firstcode = decompP->table[1][code];
         pushStack(&decompP->stack, decompP->firstcode);
-    }
+        code = decompP->prevcode;
+    } else
+        pm_asprintf(errorP, "Error in GIF image: invalid LZW code");
 
-    if (decompP->next_tableSlot < maxnum_lzwCode) {
-        decompP->table[0][decompP->next_tableSlot] = decompP->prevcode;
-        decompP->table[1][decompP->next_tableSlot] = decompP->firstcode;
-        ++decompP->next_tableSlot;
-        if (decompP->next_tableSlot >= decompP->maxnum_code) {
-            /* We've used up all the codes of the current code size.
-               Future codes in the stream will have codes one bit longer.
-               But there's an exception if we're already at the LZW
-               maximum, in which case the codes will simply continue
-               the same size.
-            */
-            if (decompP->codeSize < MAX_LZW_BITS) {
-                ++decompP->codeSize;
-                decompP->maxnum_code = 1 << decompP->codeSize;
+    if (!*errorP) {
+        pushWholeStringOnStack(decompP, code);
+
+        if (decompP->nextTableSlot < maxLzwCodeCt) {
+            decompP->table[decompP->nextTableSlot][0] = decompP->prevcode;
+            decompP->table[decompP->nextTableSlot][1] = decompP->firstcode;
+            ++decompP->nextTableSlot;
+            if (decompP->nextTableSlot >= decompP->maxCodeCt) {
+                /* We've used up all the codes of the current code size.
+                   Future codes in the stream will have codes one bit longer.
+                   But there's an exception if we're already at the LZW
+                   maximum, in which case the codes will simply continue
+                   the same size.
+                */
+                if (decompP->codeSize < MAX_LZW_BITS) {
+                    ++decompP->codeSize;
+                    decompP->maxCodeCt = 1 << decompP->codeSize;
+                }
             }
         }
+        decompP->prevcode = incode;
     }
-
-    *errorP = error;
-
-    decompP->prevcode = incode;
 }
 
 
 
 static void
-lzwReadByteFresh(struct getCodeState * const getCodeStateP,
-                 struct decompressor * const decompP,
+lzwReadByteFresh(struct GetCodeState * const getCodeStateP,
+                 struct Decompressor * const decompP,
                  bool *                const endOfImageP,
-                 unsigned int *        const dataReadP,
+                 unsigned char *       const dataReadP,
                  const char **         const errorP) {
-                     
-    /* Read off all initial clear codes, read the first non-clear code,
-       and return it.  There are no strings in the table yet, so the next
-       code must be a direct true data code.
-    */
+/*----------------------------------------------------------------------------
+  Read off all initial clear codes, read the first non-clear code, and return
+  it as *dataReadP.
+
+  Iff we hit end of image in so doing, return *endOfImageP true and nothing as
+  *dataReadP.  One way we hit end of image is for that first non-clear code to
+  be an end code.
+
+  Assume the decompressor is fresh, i.e. there are no strings in the table
+  yet, so the next code must be a direct true data code.
+-----------------------------------------------------------------------------*/
+    unsigned int code;
     bool eof;
+
+    assert(decompP->fresh);  /* Entry requirement */
+
+    decompP->fresh = FALSE;
+
     do {
         getCode_get(getCodeStateP, decompP->ifP, decompP->codeSize,
-                    &eof, &decompP->firstcode, errorP);
-        decompP->prevcode = decompP->firstcode;
-    } while (decompP->firstcode == decompP->clear_code && !*errorP && !eof);
+                    &eof, &code, errorP);
+    } while (!*errorP && !eof && code == decompP->clearCode);
 
     if (!*errorP) {
         if (eof)
             *endOfImageP = TRUE;
-        else if (decompP->firstcode == decompP->end_code) {
+        else if (code == decompP->endCode) {
             if (!zeroDataBlock)
                 readThroughEod(decompP->ifP);
             *endOfImageP = TRUE;
-        } else {
+        } else if (code >= decompP->cmapSize) { 
+            pm_asprintf(errorP, "Error in GIF image: invalid color code %u. "
+                        "Valid color values are: 0 - %u",
+                        code, decompP->cmapSize-1);
+            /* Set these values in order to avoid errors in the -repair
+               case
+            */
+            decompP->prevcode = decompP->firstcode = 0;
+
             *endOfImageP = FALSE;
+        } else {    /* valid code */
+            decompP->prevcode  = code;
+            decompP->firstcode = decompP->table[code][1];
             *dataReadP = decompP->firstcode;
+            *endOfImageP = FALSE;
         }
     }
 }
 
 
 
+
 static void
-lzwReadByte(struct decompressor * const decompP,
-            unsigned int *        const dataReadP,
+lzwReadByte(struct Decompressor * const decompP,
+            unsigned char *       const dataReadP,
             bool *                const endOfImageP,
             const char **         const errorP) {
 /*----------------------------------------------------------------------------
@@ -1025,8 +1204,6 @@ lzwReadByte(struct decompressor * const decompP,
         *endOfImageP = FALSE;
         *dataReadP = popStack(&decompP->stack);
     } else if (decompP->fresh) {
-        decompP->fresh = FALSE;
-
         lzwReadByteFresh(&getCodeState, decompP, endOfImageP, dataReadP,
                          errorP);
     } else {
@@ -1036,14 +1213,15 @@ lzwReadByte(struct decompressor * const decompP,
                     &eof, &code, errorP);
         if (!*errorP) {
             if (eof)
-                asprintfN(errorP,
-                          "Premature end of file; no proper GIF closing");
+                pm_asprintf(errorP,
+                            "Premature end of file; no proper GIF closing");
             else {
-                if (code == decompP->clear_code) {
+                if (code == decompP->clearCode) {
                     resetDecompressor(decompP);
-                    lzwReadByte(decompP, dataReadP, endOfImageP, errorP);
+                    lzwReadByteFresh(&getCodeState, decompP, endOfImageP,
+                    dataReadP, errorP);
                 } else {
-                    if (code == decompP->end_code) {
+                    if (code == decompP->endCode) {
                         if (!zeroDataBlock)
                             readThroughEod(decompP->ifP);
                         *endOfImageP = TRUE;
@@ -1065,8 +1243,8 @@ lzwReadByte(struct decompressor * const decompP,
 enum pass {MULT8PLUS0, MULT8PLUS4, MULT4PLUS2, MULT2PLUS1};
 
 static void
-bumpRowInterlace(unsigned int * const rowP,
-                 unsigned int   const rows,
+bumpRowInterlace(unsigned int   const rows,
+                 unsigned int * const rowP,
                  enum pass *    const passP) {
 /*----------------------------------------------------------------------------
    Move *pixelCursorP to the next row in the interlace pattern.
@@ -1119,47 +1297,57 @@ bumpRowInterlace(unsigned int * const rowP,
 }
 
 
+static void
+renderRow(unsigned char *    const cmapIndexRow,
+          unsigned int       const cols,
+          GifColorMap        const cmap, 
+          bool               const haveTransColor,
+          unsigned int       const transparentIndex,
+          FILE *             const imageOutfile,
+          int                const format,
+          xel *              const xelrow,
+          FILE *             const alphaFileP,
+          bit *              const alphabits) {
+/*----------------------------------------------------------------------------
+  Convert one row of cmap indexes to PPM/PGM/PBM output.
+
+  Render the alpha row to *alphaFileP iff 'alphabits' is non-NULL.  If
+  'haveTransColor' is false, render all white (i.e. the row is
+  opaque).  'alphabits' is otherwise just a one-row buffer for us to use
+  in rendering the alpha row.
+  
+  imageOutfile is NULL if user wants only the alpha file.
+----------------------------------------------------------------------------*/
+    if (alphabits) {
+        unsigned int col;
+
+        for (col=0; col < cols; ++col) {
+            alphabits[col] =
+                (haveTransColor && cmapIndexRow[col] == transparentIndex) ?
+                PBM_BLACK : PBM_WHITE;
+        }
+        pbm_writepbmrow(alphaFileP, alphabits, cols, false);
+    }
 
-struct pnmBuffer {
-    xel ** xels;
-    unsigned int col;
-    unsigned int row;
-};
+    if (imageOutfile) {
+        if (useFastPbmRender && format == PBM_FORMAT && !haveTransColor) {
 
-static void
-addPixelToRaster(unsigned int       const cmapIndex,
-                 struct pnmBuffer * const pnmBufferP,
-                 unsigned int       const cols,
-                 unsigned int       const rows,
-                 gifColorMap              cmap, 
-                 unsigned int       const cmapSize,
-                 bool               const interlace,
-                 int                const transparentIndex,
-                 bit **             const alphabits,
-                 enum pass *        const passP) {
-
-    if (cmapIndex >= cmapSize)
-        pm_error("Invalid color index %u in an image that has only "
-                 "%u colors in the color map.", cmapIndex, cmapSize);
-    
-    assert(cmapIndex < MAXCOLORMAPSIZE);
-    
-    PPM_ASSIGN(pnmBufferP->xels[pnmBufferP->row][pnmBufferP->col], 
-               cmap[CM_RED][cmapIndex],
-               cmap[CM_GRN][cmapIndex],
-               cmap[CM_BLU][cmapIndex]);
-    
-    if (alphabits) 
-        alphabits[pnmBufferP->row][pnmBufferP->col] =
-            (cmapIndex == transparentIndex) ? PBM_BLACK : PBM_WHITE;
-    
-    ++pnmBufferP->col;
-    if (pnmBufferP->col == cols) {
-        pnmBufferP->col = 0;
-        if (interlace)
-            bumpRowInterlace(&pnmBufferP->row, rows, passP);
-        else
-            ++pnmBufferP->row;
+            bit * const bitrow = cmapIndexRow; 
+
+            pbm_writepbmrow(imageOutfile, bitrow, cols, false);
+        } else {
+            /* PPM, PGM and PBM with transparent */
+            unsigned int col;
+            for (col = 0; col < cols; ++col) {
+                unsigned char const cmapIndex = cmapIndexRow[col];
+                const unsigned char * const color = cmap.map[cmapIndex];
+                assert(cmapIndex < cmap.size);
+                PPM_ASSIGN(xelrow[col],
+                           color[CM_RED], color[CM_GRN],color[CM_BLU]);
+            }
+            pnm_writepnmrow(imageOutfile, xelrow, cols,
+                            GIFMAXVAL, format, false);
+        }
     }
 }
 
@@ -1170,19 +1358,18 @@ verifyPixelRead(bool          const endOfImage,
                 const char *  const readError,
                 unsigned int  const cols,
                 unsigned int  const rows,
-                unsigned int  const failedRowNum,
                 const char ** const errorP) {
 
     if (readError)
-        *errorP = strdup(readError);
+        *errorP = pm_strdup(readError);
     else {
         if (endOfImage)
-            asprintfN(errorP,
-                      "Error in GIF image: Not enough raster data to fill "
-                      "%u x %u dimensions.  Ran out of raster data in "
-                      "row %u.  The image has proper ending sequence, so "
-                      "this is not just a truncated file.",
-                      cols, rows, failedRowNum);
+            pm_asprintf(errorP,
+                        "Error in GIF image: Not enough raster data to fill "
+                        "%u x %u dimensions.  "
+                        "The image has proper ending sequence, so "
+                        "this is not just a truncated file.",
+                        cols, rows);
         else
             *errorP = NULL;
     }
@@ -1190,93 +1377,212 @@ verifyPixelRead(bool          const endOfImage,
 
 
 
+static int
+pnmFormat(bool const hasGray,
+          bool const hasColor) {
+/*----------------------------------------------------------------------------
+  The proper PNM format (PBM, PGM, or PPM) for an image described
+  by 'hasGray' and 'hasColor'.
+-----------------------------------------------------------------------------*/
+    int format;
+    const char * formatName;
+           
+    if (hasColor) {
+        format = PPM_FORMAT;
+        formatName = "PPM";
+    } else if (hasGray) {
+        format = PGM_FORMAT;
+        formatName = "PGM";
+    } else {
+        format = PBM_FORMAT;
+        formatName = "PBM";
+    }
+    if (verbose) 
+        pm_message("writing a %s file", formatName);
+ 
+    return format;
+}
+
+
+
 static void
-readRaster(struct decompressor * const decompP,
-           xel **                const xels, 
+makePnmRow(struct Decompressor * const decompP,
            unsigned int          const cols,
            unsigned int          const rows,
-           gifColorMap                 cmap, 
-           unsigned int          const cmapSize,
-           bool                  const interlace,
-           int                   const transparentIndex,
-           bit **                const alphabits,
-           bool                  const tolerateBadInput) {
-                   
-    struct pnmBuffer pnmBuffer;
-    enum pass pass;
-    bool fillingMissingPixels;
+           bool                  const fillWithZero,
+           unsigned char *       const cmapIndexRow,
+           const char **         const errorP) {
 
-    pass = MULT8PLUS0;
-    pnmBuffer.xels = xels;
-    pnmBuffer.col  = 0;
-    pnmBuffer.row  = 0;
-    fillingMissingPixels = false;  /* initial value */
+    bool fillingWithZero;
+    unsigned int col;
 
-    while (pnmBuffer.row < rows) {
-        unsigned int colorIndex;
+    *errorP = NULL;  /* initial value */
 
-        if (fillingMissingPixels)
-            colorIndex = 0;
-        else {
-            const char * error;
+    for (col = 0, fillingWithZero = fillWithZero;
+         col < cols;
+         ++col) {
 
-            const char * readError;
-            unsigned int readColorIndex;
-            bool endOfImage;
+        unsigned char colorIndex;
+
+        if (fillingWithZero)
+            colorIndex = 0;
+        else { 
+            const char *  readError;
+            unsigned char readColorIndex;
+            bool          endOfImage;
 
             lzwReadByte(decompP, &readColorIndex, &endOfImage, &readError);
 
-            verifyPixelRead(endOfImage, readError, cols, rows, pnmBuffer.row,
-                            &error);
+            verifyPixelRead(endOfImage, readError, cols, rows, errorP);
 
             if (readError)
-                strfree(readError);
-
-            if (error) {
-                if (tolerateBadInput) {
-                    pm_message("WARNING: %s.  "
-                               "Filling bottom %u rows with arbitrary color",
-                               error, rows - pnmBuffer.row);
-                    fillingMissingPixels = true;
-                } else
-                    pm_error("Unable to read input image.  %s.  Use the "
-                             "-repair option to try to salvage some of "
-                             "the image",
-                             error);
-
+                pm_strfree(readError);
+
+            if (*errorP) {
+                /* Caller may want to try to ignore this error, so we
+                   fill out the row with zeroes.  Note that we can't possibly
+                   have another error while doing that.
+                */
+                fillingWithZero = true;
                 colorIndex = 0;
             } else
                 colorIndex = readColorIndex;
         }
-        addPixelToRaster(colorIndex, &pnmBuffer, cols, rows, cmap, cmapSize,
-                         interlace, transparentIndex, alphabits, &pass);
+        cmapIndexRow[col] = colorIndex;
     }
 }
 
 
 
 static void
-skipExtraneousData(struct decompressor * const decompP) {
+convertRaster(struct Decompressor * const decompP,
+              unsigned int          const cols,
+              unsigned int          const rows,
+              GifColorMap           const cmap, 
+              bool                  const interlace,
+              FILE *                const imageOutFileP,
+              FILE *                const alphaFileP,
+              bool                  const hasGray,
+              bool                  const hasColor) {
+/*----------------------------------------------------------------------------
+   Read the raster from the GIF decompressor *decompP, and write it as a
+   complete PNM stream (starting with the header) on *imageOutFileP and
+   *alphaFileP.
+
+   Assume that raster is 'cols' x 'rows', refers to colormap 'cmap', and is
+   interlaced iff 'interlace' is true.
+
+   Assume the image has gray levels and/or color per 'hasGray' and 'hasColor'.
+-----------------------------------------------------------------------------*/
+    int const format = pnmFormat(hasGray, hasColor);
+
+    enum pass pass;
+    bool fillingMissingPixels;
+    unsigned int row;
+    unsigned char ** cmapIndexArray;
+    bit * alphabits;
+    xel * xelrow;
+    unsigned int outrow;
+        /* Non-interlace: outrow is always 0: cmapIndexRow keeps pointing
+           to the single row in array.
+
+           Interlace: outrow is modified with each call to bumpRowInterface().
+        */
+
+    MALLOCARRAY2(cmapIndexArray, interlace ? rows : 1 , cols);
+
+    if (imageOutFileP)
+        pnm_writepnminit(imageOutFileP, cols, rows, GIFMAXVAL, format, FALSE);
+    if (alphaFileP)
+        pbm_writepbminit(alphaFileP, cols, rows, FALSE);
+
+    xelrow = pnm_allocrow(cols);  
+    if (!xelrow)
+        pm_error("couldn't alloc space for image" );
 
-    unsigned int byteRead;
+    if (alphaFileP) {
+        alphabits = pbm_allocrow(cols);
+        if (!alphabits)
+            pm_error("couldn't alloc space for alpha image" );
+    } else
+        alphabits = NULL;
+
+    fillingMissingPixels = false;  /* initial value */
+    pass = MULT8PLUS0;
+    outrow = 0;
+
+    for (row = 0; row < rows; ++row) {
+        const char * problem;
+        makePnmRow(decompP, cols, rows, fillingMissingPixels,
+                   cmapIndexArray[outrow], &problem);
+
+        if (problem) {
+            /* makePnmRow() recovered from the problem and produced an output
+               row, stuffed with zeroes as necessary
+            */
+            if (decompP->tolerateBadInput) {
+                pm_message("WARNING: %s.  "
+                           "Filling bottom %u rows with arbitrary color",
+                           problem, rows - row);
+                fillingMissingPixels = true;
+            } else
+                pm_error("Unable to read input image.  %s "
+                         "(Output row: %u).  "
+                         "Use the -repair option to try to salvage "
+                         "some of the image",
+                         problem, interlace ? outrow : row);
+        }
+
+        if (interlace)
+            bumpRowInterlace(rows, &outrow, &pass);
+        else
+            renderRow(cmapIndexArray[outrow], cols, cmap,
+                      decompP->haveTransColor, decompP->transparentIndex,
+                      imageOutFileP, format, xelrow, alphaFileP, alphabits);
+    }
+    /* All rows decompressed (and rendered and output if non-interlaced) */  
+    if (interlace) {
+        unsigned int row;
+        for (row = 0; row < rows; ++row) 
+            renderRow(cmapIndexArray[row], cols, cmap,
+                      decompP->haveTransColor, decompP->transparentIndex,
+                      imageOutFileP, format, xelrow, alphaFileP, alphabits);
+    }
+
+    pnm_freerow(xelrow);
+    if (alphabits)
+        pbm_freerow(alphabits);
+    pm_freearray2((void **)cmapIndexArray);
+}
+
+
+
+static void
+skipExtraneousData(struct Decompressor * const decompP) {
+
+    unsigned char byteRead;
     bool endOfImage;
     const char * error;
 
+    endOfImage = FALSE;  /* initial value */
+
     lzwReadByte(decompP, &byteRead, &endOfImage, &error);
 
     if (error)
-        strfree(error);
-    else if (!endOfImage) {
-        pm_message("Extraneous data at end of image.  "
-                   "Skipped to end of image");
+        pm_strfree(error);
+    else {
+        if (!endOfImage) {
+            pm_message("Extraneous data at end of image.  "
+                       "Skipped to end of image");
 
-        while (!endOfImage && !error)
-            lzwReadByte(decompP, &byteRead, &endOfImage, &error);
+            while (!endOfImage && !error)
+                lzwReadByte(decompP, &byteRead, &endOfImage, &error);
 
-        if (error) {
-            pm_message("Error encountered skipping to end of image: %s",
-                       error);
-            strfree(error);
+            if (error) {
+                pm_message("Error encountered skipping to end of image: %s",
+                           error);
+                pm_strfree(error);
+            }
         }
     }
 }
@@ -1284,36 +1590,89 @@ skipExtraneousData(struct decompressor * const decompP) {
 
 
 static void
+issueTransparencyMessage(bool         const haveTransColor,
+                         unsigned int const transparentIndex, 
+                         GifColorMap  const cmap) {
+/*----------------------------------------------------------------------------
+   If user wants verbose output, tell him whether there is a transparent
+   background color ('haveTransColor') and if so what it is
+   ('transparentIndex').
+   
+   Some GIFs put transparentIndex outside the color map.  Allow this only
+   with "-repair", checked in lzwInit().  Here we issue a warning and report
+   the substitute color.
+-----------------------------------------------------------------------------*/
+    if (verbose) {
+        if (haveTransColor) {
+            if (transparentIndex >= cmap.size) {
+                const unsigned char * const color = cmap.map[0];
+                pm_message("WARNING: Transparent index %u "
+                           "is outside color map. "
+                           "substitute background color: rgb:%02x/%02x/%02x ",
+                           transparentIndex,
+                           color[CM_RED],
+                           color[CM_GRN],
+                           color[CM_BLU]
+                    );
+            } else {
+                const unsigned char * const color = cmap.map[transparentIndex];
+                pm_message("transparent background color: rgb:%02x/%02x/%02x "
+                           "Index %u",
+                           color[CM_RED],
+                           color[CM_GRN],
+                           color[CM_BLU],
+                           transparentIndex
+                    );
+            }
+        } else
+            pm_message("no transparency");
+    }
+}
+
+
+
+static void
 readImageData(FILE *       const ifP, 
-              xel **       const xels, 
               unsigned int const cols,
               unsigned int const rows,
-              gifColorMap        cmap, 
-              unsigned int const cmapSize,
+              GifColorMap  const cmap, 
               bool         const interlace,
-              int          const transparentIndex,
-              bit **       const alphabits,
+              bool         const haveTransColor,
+              unsigned int const transparentIndex,
+              FILE *       const imageOutFileP,
+              FILE *       const alphaFileP,
+              bool         const hasGray,
+              bool         const hasColor,
               bool         const tolerateBadInput) {
 
     unsigned char lzwMinCodeSize;      
-    struct decompressor decomp;
-    bool gotMinCodeSize;
+    struct Decompressor decomp;
+    const char * error;
 
-    gotMinCodeSize =  ReadOK(ifP, &lzwMinCodeSize, 1);
-    if (!gotMinCodeSize)
-        pm_error("GIF stream ends (or read error) "
+    readFile(ifP, &lzwMinCodeSize, sizeof(lzwMinCodeSize), &error);
+    if (error)
+        pm_error("Can't read GIF stream "
                  "right after an image separator; no "
-                 "image data follows.");
+                 "image data follows.  %s", error);
 
     if (lzwMinCodeSize > MAX_LZW_BITS)
         pm_error("Invalid minimum code size value in image data: %u.  "
                  "Maximum allowable code size in GIF is %u", 
                  lzwMinCodeSize, MAX_LZW_BITS);
 
-    lzwInit(&decomp, ifP, lzwMinCodeSize);
+    lzwInit(&decomp, ifP, lzwMinCodeSize, cmap.size,
+            haveTransColor, transparentIndex, tolerateBadInput);
+
+    issueTransparencyMessage(haveTransColor, transparentIndex, cmap);
 
-    readRaster(&decomp, xels, cols, rows, cmap, cmapSize, interlace,
-               transparentIndex, alphabits, tolerateBadInput);
+    if (useFastPbmRender && !hasGray && ! hasColor && !haveTransColor) {
+        if (verbose)
+            pm_message("Using fast PBM rendering");
+        lzwAdjustForPBM(&decomp, cmap);
+    }
+    convertRaster(&decomp, cols, rows, cmap, interlace,
+                  imageOutFileP, alphaFileP,
+                  hasGray, hasColor);
 
     skipExtraneousData(&decomp);
 
@@ -1323,80 +1682,47 @@ readImageData(FILE *       const ifP,
 
 
 static void
-writePnm(FILE * const outfileP,
-         xel ** const xels, 
-         int    const cols,
-         int    const rows,
-         int    const hasGray,
-         int    const hasColor) {
-/*----------------------------------------------------------------------------
-   Write a PNM image to the current position of file *outfileP with
-   dimensions 'cols' x 'rows' and raster 'xels'.
-   
-   Make it PBM, PGM, or PBM according to 'hasGray' and 'hasColor'.
------------------------------------------------------------------------------*/
-    int format;
-    const char * formatName;
-           
-    if (hasColor) {
-        format = PPM_FORMAT;
-        formatName = "PPM";
-    } else if (hasGray) {
-        format = PGM_FORMAT;
-        formatName = "PGM";
-    } else {
-        format = PBM_FORMAT;
-        formatName = "PBM";
-    }
-    if (verbose) 
-        pm_message("writing a %s file", formatName);
-    
-    if (outfileP) 
-        pnm_writepnm(outfileP, xels, cols, rows,
-                     (xelval) GIFMAXVAL, format, FALSE);
-}
+warnUserNotSquare(unsigned int const aspectRatio) {
 
+    const char * baseMsg =
+        "warning - input pixels are not square, "
+        "but we are rendering them as square pixels "
+        "in the output";
 
+    if (pm_have_float_format()) {
+        float const r = ((float)aspectRatio + 15.0 ) / 64.0;
 
-static void
-transparencyMessage(int const transparentIndex, 
-                    gifColorMap cmap) {
-/*----------------------------------------------------------------------------
-   If user wants verbose output, tell him that the color with index
-   'transparentIndex' is supposed to be a transparent background color.
-   
-   If transparentIndex == -1, tell him there is no transparent background
-   color.
------------------------------------------------------------------------------*/
-    if (verbose) {
-        if (transparentIndex == -1)
-            pm_message("no transparency");
-        else
-            pm_message("transparent background color: rgb:%02x/%02x/%02x "
-                       "Index %d",
-                       cmap[CM_RED][transparentIndex],
-                       cmap[CM_GRN][transparentIndex],
-                       cmap[CM_BLU][transparentIndex],
-                       transparentIndex
-                );
-    }
+        pm_message("%s.  To fix the output, run it through "
+                   "'pamscale -%cscale %g'",
+                   baseMsg,
+                   r < 1.0 ? 'x' : 'y',
+                   r < 1.0 ? 1.0 / r : r );
+    } else
+        pm_message("%s", baseMsg);
 }
 
+
+
 static void
-readGifHeader(FILE * const gifFile, struct gifScreen * const gifScreenP) {
+readGifHeader(FILE *             const gifFileP,
+              struct GifScreen * const gifScreenP) {
 /*----------------------------------------------------------------------------
-   Read the GIF stream header off the file gifFile, which is present
+   Read the GIF stream header off the file *gifFileP, which is present
    positioned to the beginning of a GIF stream.  Return the info from it
    as *gifScreenP.
 -----------------------------------------------------------------------------*/
-    unsigned char   buf[16];
-    char     version[4];
+#define GLOBALCOLORMAP  0x80
 
+    unsigned char buf[16];
+    char version[4];
+    unsigned int cmapSize;
+    const char * error;
 
-    if (! ReadOK(gifFile,buf,6))
-        pm_error("error reading magic number" );
+    readFile(gifFileP, buf, 6, &error);
+    if (error)
+        pm_error("Error reading magic number.  %s", error);
     
-    if (strncmp((char *)buf,"GIF",3) != 0)
+    if (!strneq((char *)buf, "GIF", 3))
         pm_error("File does not contain a GIF stream.  It does not start "
                  "with 'GIF'.");
     
@@ -1407,56 +1733,52 @@ readGifHeader(FILE * const gifFile, struct gifScreen * const gifScreenP) {
         pm_message("GIF format version is '%s'", version);
     
     if ((!streq(version, "87a")) && (!streq(version, "89a")))
-        pm_error("bad version number, not '87a' or '89a'" );
+        pm_error("Bad version number, not '87a' or '89a'" );
     
-    if (! ReadOK(gifFile,buf,7))
-        pm_error("failed to read screen descriptor" );
+    readFile(gifFileP, buf, 7, &error);
+    if (error)
+        pm_error("Failed to read screen descriptor.  %s", error);
     
-    gifScreenP->Width           = LM_to_uint(buf[0],buf[1]);
-    gifScreenP->Height          = LM_to_uint(buf[2],buf[3]);
-    gifScreenP->ColorMapSize    = 1 << ((buf[4] & 0x07) + 1);
-    gifScreenP->ColorResolution = (buf[4] & 0x70 >> 3) + 1;
-    gifScreenP->Background      = buf[5];
-    gifScreenP->AspectRatio     = buf[6];
+    gifScreenP->width           = LM_to_uint(buf[0],buf[1]);
+    gifScreenP->height          = LM_to_uint(buf[2],buf[3]);
+    cmapSize                    = 1 << ((buf[4] & 0x07) + 1);
+    gifScreenP->colorResolution = (buf[4] & 0x70 >> 3) + 1;
+    gifScreenP->background      = buf[5];
+    gifScreenP->aspectRatio     = buf[6];
 
     if (verbose) {
-        pm_message("GIF Width = %d GIF Height = %d "
-                   "Pixel aspect ratio = %d (%f:1)",
-                   gifScreenP->Width, gifScreenP->Height, 
-                   gifScreenP->AspectRatio, 
-                   gifScreenP->AspectRatio == 0 ? 
-                   1 : (gifScreenP->AspectRatio + 15) / 64.0);
-        pm_message("Colors = %d   Color Resolution = %d",
-                   gifScreenP->ColorMapSize, gifScreenP->ColorResolution);
+        pm_message("GIF Width = %u GIF Height = %u "
+                   "Pixel aspect ratio = %u (%f:1)",
+                   gifScreenP->width, gifScreenP->height, 
+                   gifScreenP->aspectRatio, 
+                   gifScreenP->aspectRatio == 0 ? 
+                   1 : (gifScreenP->aspectRatio + 15) / 64.0);
+        pm_message("Global color count = %u   Color Resolution = %u",
+                   cmapSize, gifScreenP->colorResolution);
     }           
-    if (BitSet(buf[4], LOCALCOLORMAP)) {    /* Global Colormap */
-        readColorMap(gifFile, gifScreenP->ColorMapSize, gifScreenP->ColorMap,
+    if (buf[4] & GLOBALCOLORMAP) {
+        gifScreenP->hasGlobalColorMap = true;
+        readColorMap(gifFileP, cmapSize, &gifScreenP->colorMap,
                      &gifScreenP->hasGray, &gifScreenP->hasColor);
         if (verbose) {
-            pm_message("Color map %s grays, %s colors", 
+            pm_message("Global color map %s grays, %s colors", 
                        gifScreenP->hasGray ? "contains" : "doesn't contain",
                        gifScreenP->hasColor ? "contains" : "doesn't contain");
         }
-    }
+    } else
+        gifScreenP->hasGlobalColorMap = false;
     
-    if (gifScreenP->AspectRatio != 0 && gifScreenP->AspectRatio != 49) {
-        float   r;
-        r = ( (float) gifScreenP->AspectRatio + 15.0 ) / 64.0;
-        pm_message("warning - input pixels are not square, "
-                   "but we are rendering them as square pixels "
-                   "in the output.  "
-                   "To fix the output, run it through "
-                   "'pnmscale -%cscale %g'",
-                   r < 1.0 ? 'x' : 'y',
-                   r < 1.0 ? 1.0 / r : r );
-    }
+    if (gifScreenP->aspectRatio != 0 && gifScreenP->aspectRatio != 49)
+        warnUserNotSquare(gifScreenP->aspectRatio);
+
+#undef GLOBALCOLORMAP
 }
 
 
 
 static void
 readExtensions(FILE*          const ifP, 
-               struct gif89 * const gif89P,
+               struct Gif89 * const gif89P,
                bool *         const eodP,
                const char **  const errorP) {
 /*----------------------------------------------------------------------------
@@ -1482,13 +1804,13 @@ readExtensions(FILE*          const ifP,
         unsigned char c;
         const char * error;
 
-        readFile(ifP, &c, 1, &error);
+        readFile(ifP, &c, sizeof(c), &error);
 
         if (error) {
-            asprintfN(errorP, "File read error where start of image "
-                      "descriptor or end of GIF expected.  %s",
-                      error);
-            strfree(error);
+            pm_asprintf(errorP, "File read error where start of image "
+                        "descriptor or end of GIF expected.  %s",
+                        error);
+            pm_strfree(error);
         } else {
             if (c == ';') {         /* GIF terminator */
                 eod = TRUE;
@@ -1499,17 +1821,18 @@ readExtensions(FILE*          const ifP,
                 readFile(ifP, &functionCode, 1, &error);
 
                 if (error) {
-                    asprintfN(errorP, "Failed to read function code "
-                              "of GIF extension (immediately after the '!' "
-                              "extension delimiter) from input.  %s", error);
-                    strfree(error);
+                    pm_asprintf(errorP, "Failed to read function code "
+                                "of GIF extension (immediately after the '!' "
+                                "extension delimiter) from input.  %s", error);
+                    pm_strfree(error);
                 } else {
                     doExtension(ifP, functionCode, gif89P);
                 }
             } else if (c == ',') 
                 imageStart = TRUE;
             else 
-                pm_message("bogus character 0x%02x, ignoring", (int)c);
+                pm_message("Encountered invalid character 0x%02x while "
+                           "seeking extension block, ignoring", (int)c);
         }
     }
     *eodP = eod;
@@ -1517,20 +1840,111 @@ readExtensions(FILE*          const ifP,
 
 
 
+struct GifImageHeader {
+/*----------------------------------------------------------------------------
+   Information in the header (first 9 bytes) of a GIF image.
+-----------------------------------------------------------------------------*/
+    bool hasLocalColormap;
+        /* The image has its own color map.  Its size is 'localColorMapSize' */
+        /* (If an image does not have its own color map, the image uses the 
+           global color map for the GIF stream)
+        */
+    unsigned int localColorMapSize;
+        /* Meaningful only if 'hasLocalColormap' is true. */
+
+    /* Position of the image (max 65535) */
+    unsigned int lpos;
+    unsigned int tpos;
+
+    /* Dimensions of the image (max 65535) */
+    unsigned int cols;
+    unsigned int rows;
+
+    bool interlaced;
+};
+
+
+
 static void
-reportImageInfo(unsigned int const cols,
-                unsigned int const rows,
-                bool         const useGlobalColormap,
-                unsigned int const localColorMapSize,
-                bool         const interlaced) {
+reportImageHeader(struct GifImageHeader const imageHeader) {
 
     pm_message("reading %u by %u%s GIF image",
-               cols, rows, interlaced ? " interlaced" : "" );
+               imageHeader.cols, imageHeader.rows,
+               imageHeader.interlaced ? " interlaced" : "" );
 
-    if (useGlobalColormap)
-        pm_message("  Uses global colormap");
+    if (imageHeader.lpos > 0 || imageHeader.tpos > 0)
+        pm_message("  Image left position: %u top position: %u",
+                   imageHeader.lpos, imageHeader.tpos);
+    
+    if (imageHeader.hasLocalColormap)
+        pm_message("  Uses local colormap of %u colors",
+                   imageHeader.localColorMapSize);
     else
-        pm_message("  Uses local colormap of %u colors", localColorMapSize);
+        pm_message("  Uses global colormap");
+}
+
+
+
+static void
+readImageHeader(FILE *                  const ifP,
+                struct GifImageHeader * const imageHeaderP) {
+
+#define LOCALCOLORMAP  0x80
+#define INTERLACE      0x40
+
+    unsigned char buf[16];
+    const char * error;
+
+    readFile(ifP, buf, 9, &error);
+    if (error)
+        pm_error("couldn't read left/top/width/height.  %s", error);
+
+    imageHeaderP->hasLocalColormap  = !!(buf[8] & LOCALCOLORMAP);
+    imageHeaderP->localColorMapSize = 1u << ((buf[8] & 0x07) + 1);
+    imageHeaderP->lpos              = LM_to_uint(buf[0], buf[1]);
+    imageHeaderP->tpos              = LM_to_uint(buf[2], buf[3]);
+    imageHeaderP->cols              = LM_to_uint(buf[4], buf[5]);
+    imageHeaderP->rows              = LM_to_uint(buf[6], buf[7]);
+    imageHeaderP->interlaced        = !!(buf[8] & INTERLACE);
+
+    if (verbose)
+        reportImageHeader(*imageHeaderP);
+
+#undef INTERLACE
+#undef LOCALCOLORMAP
+}
+
+
+
+static void
+validateWithinGlobalScreen(struct GifImageHeader const imageHeader,
+                           struct GifScreen      const gifScreen) {
+
+    unsigned long int const rpos = imageHeader.lpos + imageHeader.cols;
+    unsigned long int const bpos = imageHeader.tpos + imageHeader.rows; 
+
+    if (rpos > gifScreen.width)
+        pm_error("Image right end (%lu) is outside global screen: %u x %u",
+                 rpos, gifScreen.width, gifScreen.height);
+    if (bpos > gifScreen.height)
+        pm_error("Image bottom end (%lu) is outside global screen: "
+                 "%u x %u",
+                 bpos, gifScreen.width, gifScreen.height);
+}
+
+
+
+static void
+skipImageData(FILE * const ifP) {
+    unsigned char lzwMinCodeSize;
+    const char * error;
+
+    readFile(ifP, &lzwMinCodeSize, sizeof(lzwMinCodeSize), &error);
+    if (error) {
+        pm_message("Unable to read file to skip image DataBlock.  %s", error);
+        pm_strfree(error);
+    }
+    readThroughEod(ifP);
 }
 
 
@@ -1538,88 +1952,51 @@ reportImageInfo(unsigned int const cols,
 static void
 convertImage(FILE *           const ifP, 
              bool             const skipIt, 
-             FILE *           const imageout_file, 
-             FILE *           const alphafile, 
-             struct gifScreen       gifScreen,
-             struct gif89     const gif89,
+             FILE *           const imageoutFileP, 
+             FILE *           const alphafileP, 
+             struct GifScreen const gifScreen,
+             struct Gif89     const gif89,
              bool             const tolerateBadInput) {
 /*----------------------------------------------------------------------------
    Read a single GIF image from the current position of file 'ifP'.
 
    If 'skipIt' is TRUE, don't do anything else.  Otherwise, write the
-   image to the current position of files 'imageout_file' and 'alphafile'.
-   If 'alphafile' is NULL, though, don't write any alpha information.
+   image to the current position of files *imageoutFileP and *alphafileP.
+   If *alphafileP is NULL, though, don't write any alpha information.
 -----------------------------------------------------------------------------*/
-    unsigned char buf[16];
-    bool useGlobalColormap;
-    xel **xels;  /* The image raster, in libpnm format */
-    bit **alphabits;  
-        /* The image alpha mask, in libpbm format.  NULL if we aren't computing
-           an alpha mask.
-        */
-    unsigned int cols, rows;  /* Dimensions of the image */
-    gifColorMap localColorMap;
-    unsigned int localColorMapSize;
-    bool interlaced;
-
-    if (! ReadOK(ifP,buf,9))
-        pm_error("couldn't read left/top/width/height");
-
-    useGlobalColormap = ! BitSet(buf[8], LOCALCOLORMAP);
-    localColorMapSize = 1u << ((buf[8] & 0x07) + 1);
-    cols = LM_to_uint(buf[4], buf[5]);
-    rows = LM_to_uint(buf[6], buf[7]);
-    interlaced = !!BitSet(buf[8], INTERLACE);
+    struct GifImageHeader imageHeader;
+    GifColorMap localColorMap;
+    const GifColorMap * currentColorMapP;
+    bool hasGray, hasColor;
 
-    if (verbose)
-        reportImageInfo(cols, rows, useGlobalColormap, localColorMapSize,
-                        interlaced);
-
-    if (cols == 0)
-        pm_error("Invalid GIF - width is zero");
-        
-    xels = pnm_allocarray(cols, rows);
-    if (!xels)
-        pm_error("couldn't alloc space for image" );
+    readImageHeader(ifP, &imageHeader);
 
-    if (alphafile) {
-        alphabits = pbm_allocarray(cols, rows);
-        if (!alphabits)
-            pm_error("couldn't alloc space for alpha image" );
-    } else
-        alphabits = NULL;
-    
-    if (!useGlobalColormap) {
-        int hasGray, hasColor;
+    validateWithinGlobalScreen(imageHeader, gifScreen);
 
-        readColorMap(ifP, localColorMapSize, localColorMap, 
+    if (imageHeader.hasLocalColormap) {
+        readColorMap(ifP, imageHeader.localColorMapSize, &localColorMap, 
                      &hasGray, &hasColor);
-        transparencyMessage(gif89.transparent, localColorMap);
-        readImageData(ifP, xels, cols, rows, localColorMap, localColorMapSize,
-                      interlaced, gif89.transparent, alphabits,
-                      tolerateBadInput);
-        if (!skipIt) {
-            writePnm(imageout_file, xels, cols, rows,
-                     hasGray, hasColor);
-        }
+        currentColorMapP = &localColorMap;
+    } else if (gifScreen.hasGlobalColorMap) {
+        currentColorMapP = &gifScreen.colorMap;
+        hasGray  = gifScreen.hasGray;
+        hasColor = gifScreen.hasColor;
     } else {
-        transparencyMessage(gif89.transparent, gifScreen.ColorMap);
-        readImageData(ifP, xels, cols, rows, 
-                      gifScreen.ColorMap, gifScreen.ColorMapSize,
-                      interlaced, gif89.transparent, alphabits,
-                      tolerateBadInput);
-        if (!skipIt) {
-            writePnm(imageout_file, xels, cols, rows,
-                     gifScreen.hasGray, gifScreen.hasColor);
-        }
+        pm_error("Invalid GIF: "
+                 "Image has no local color map and stream has no global "
+                 "color map either.");
     }
 
-    if (!skipIt && alphafile && alphabits)
-        pbm_writepbm(alphafile, alphabits, cols, rows, FALSE);
-
-    pnm_freearray(xels, rows);
-    if (alphabits)
-        pbm_freearray(alphabits, rows);
+    if (!skipIt) {
+        readImageData(ifP, imageHeader.cols, imageHeader.rows,
+                      *currentColorMapP,
+                      imageHeader.interlaced,
+                      gif89.haveTransColor, gif89.transparentIndex,
+                      imageoutFileP, alphafileP,
+                      hasGray, hasColor,
+                      tolerateBadInput);
+    } else
+        skipImageData(ifP);
 }
 
 
@@ -1637,7 +2014,7 @@ disposeOfReadExtensionsError(const char * const error,
         else
             pm_error("Error accessing Image %u of stream.  %s",
                      imageSeq, error);
-        strfree(error);
+        pm_strfree(error);
         *eodP = TRUE;
     }
 }
@@ -1645,17 +2022,17 @@ disposeOfReadExtensionsError(const char * const error,
 
 
 static void
-convertImages(FILE * const ifP, 
-              bool   const allImages,
-              int    const requestedImageSeq, 
-              bool   const drainStream,
-              FILE * const imageout_file, 
-              FILE * const alphafile,
-              bool   const tolerateBadInput) {
+convertImages(FILE *       const ifP, 
+              bool         const allImages,
+              unsigned int const requestedImageSeq, 
+              bool         const drainStream,
+              FILE *       const imageOutFileP, 
+              FILE *       const alphaFileP,
+              bool         const tolerateBadInput) {
 /*----------------------------------------------------------------------------
    Read a GIF stream from file 'ifP' and write one or more images from
-   it as PNM images to file 'imageout_file'.  If the images have transparency
-   and 'alphafile' is non-NULL, write PGM alpha masks to file 'alphafile'.
+   it as PNM images to file 'imageOutFileP'.  If the images have transparency
+   and 'alphafile' is non-NULL, write PGM alpha masks to file 'alphaFileP'.
 
    'allImages' means Caller wants all the images in the stream.  
 
@@ -1669,21 +2046,24 @@ convertImages(FILE * const ifP,
    format in the tail of the stream and there may yet be more stuff in
    the file when we return.
 -----------------------------------------------------------------------------*/
-    int imageSeq;
+    unsigned int imageSeq;
         /* Sequence within GIF stream of image we are currently processing.
            First is 0.
         */
-    struct gifScreen gifScreen;
-    struct gif89 gif89;
+    struct GifScreen gifScreen;
+    struct Gif89 gif89;
     bool eod;
         /* We've read through the GIF terminator character */
 
+    /* Set 'gif89' to initial values, to be updated as we encounter the
+       relevant extensions in the GIF stream.
+    */
     initGif89(&gif89);
 
     readGifHeader(ifP, &gifScreen);
 
     for (imageSeq = 0, eod = FALSE;
-         !eod && (imageSeq <= requestedImageSeq || allImages || drainStream);
+         !eod && (allImages || imageSeq <= requestedImageSeq || drainStream);
          ++imageSeq) {
 
         const char * error;
@@ -1701,9 +2081,10 @@ convertImages(FILE * const ifP,
                          imageSeq, imageSeq > 1 ? "s" : "");
         } else {
             if (verbose)
-                pm_message("Reading Image Sequence %d", imageSeq);
+                pm_message("Reading Image Sequence %u", imageSeq);
+
             convertImage(ifP, !allImages && (imageSeq != requestedImageSeq), 
-                         imageout_file, alphafile, gifScreen, gif89,
+                         imageOutFileP, alphaFileP, gifScreen, gif89,
                          tolerateBadInput);
         }
     }
@@ -1714,9 +2095,10 @@ convertImages(FILE * const ifP,
 int
 main(int argc, char **argv) {
 
-    struct cmdlineInfo cmdline;
-    FILE *ifP;
-    FILE *alpha_file, *imageout_file;
+    struct CmdlineInfo cmdline;
+    FILE * ifP;
+    FILE * alphaFileP;
+    FILE * imageOutFileP;
 
     pnm_init(&argc, argv);
 
@@ -1724,27 +2106,30 @@ main(int argc, char **argv) {
     verbose = cmdline.verbose;
     showComment = cmdline.comments;
    
-    ifP = pm_openr(cmdline.input_filespec);
+    ifP = pm_openr(cmdline.inputFilespec);
 
-    if (cmdline.alpha_filename == NULL)
-        alpha_file = NULL;
+    if (cmdline.alphaFileName == NULL)
+        alphaFileP = NULL;
     else
-        alpha_file = pm_openw(cmdline.alpha_filename);
+        alphaFileP = pm_openw(cmdline.alphaFileName);
 
-    if (alpha_file && streq(cmdline.alpha_filename, "-"))
-        imageout_file = NULL;
+    if (alphaFileP && streq(cmdline.alphaFileName, "-"))
+        imageOutFileP = NULL;
     else
-        imageout_file = stdout;
+        imageOutFileP = stdout;
 
-    convertImages(ifP, cmdline.all_images, cmdline.image_no, 
-                  !cmdline.quitearly, imageout_file, alpha_file,
+    convertImages(ifP, cmdline.allImages, cmdline.imageNum, 
+                  !cmdline.quitearly, imageOutFileP, alphaFileP,
                   cmdline.repair);
 
     pm_close(ifP);
-    if (imageout_file != NULL) 
-        pm_close(imageout_file);
-    if (alpha_file != NULL)
-        pm_close(alpha_file);
+    if (imageOutFileP != NULL) 
+        pm_close(imageOutFileP);
+    if (alphaFileP != NULL)
+        pm_close(alphaFileP);
 
     return 0;
 }
+
+
+
diff --git a/converter/other/hdifftopam.c b/converter/other/hdifftopam.c
index 7bfeed9b..c9363040 100644
--- a/converter/other/hdifftopam.c
+++ b/converter/other/hdifftopam.c
@@ -33,7 +33,7 @@ parseCommandLine(int argc, char ** argv,
    was passed to us as the argv array.
 -----------------------------------------------------------------------------*/
     optEntry *option_def = malloc( 100*sizeof( optEntry ) );
-        /* Instructions to optParseOptions3 on how to parse our options.
+        /* Instructions to pm_optParseOptions3 on how to parse our options.
          */
     optStruct3 opt;
 
@@ -47,7 +47,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 */
 
-    optParseOptions3(&argc, argv, opt, sizeof(opt), 0);
+    pm_optParseOptions3(&argc, argv, opt, sizeof(opt), 0);
         /* Uses and sets argc, argv, and some of *cmdlineP and others. */
 
     if (argc-1 < 1)
diff --git a/converter/other/infotopam.c b/converter/other/infotopam.c
index 21fa8ee2..f2e35827 100644
--- a/converter/other/infotopam.c
+++ b/converter/other/infotopam.c
@@ -114,7 +114,7 @@ typedef struct DiskObject_ { /* 78 bytes (including Gadget struct) */
     unsigned char version[2];       /* Object version number */
     unsigned char gadget[44];       /* Copy of in memory gadget (44 by */
     unsigned char type;             /* ??? */
-    unsigned char pad;              /* Pad it out to the next word boundry */
+    unsigned char pad;              /* Pad it out to the next word boundary */
     unsigned char pDefaultTool[4];  /* Pointer  to default tool */
     unsigned char ppToolTypes[4];   /* Pointer pointer to tool types */
     unsigned char currentX[4];      /* Current X position (?) */
@@ -175,7 +175,7 @@ parseCommandLine( int              argc,
     opt.allowNegNum   = FALSE;  /* No negative number parameters */
 
     /* Parse the command line */
-    optParseOptions3( &argc, argv, opt, sizeof( opt ), 0 );
+    pm_optParseOptions3( &argc, argv, opt, sizeof( opt ), 0 );
 
     infoP->forceColor = forceColorSpec;
     infoP->selected = selectedSpec;
@@ -233,33 +233,33 @@ getDiskObject( IconInfo * const infoP ) {
     /* Read the disk object header */
     bytesRead = fread( &dobj, 1, sizeof(dobj), infoP->fp );
     if (ferror(infoP->fp))
-        pm_error( "Cannot read disk object header for file '%s'.  "
-                  "fread() errno = %d (%s)",
-                  infoP->name, errno, strerror( errno ) );
-    else if ( bytesRead != sizeof(dobj) )
-        pm_error( "Cannot read entire disk object header for file '%s'.  "
-                  "Only read 0x%X of 0x%X bytes",
-                  infoP->name, bytesRead, sizeof(dobj) );
+        pm_error("Cannot read disk object header for file '%s'.  "
+                 "fread() errno = %d (%s)",
+                 infoP->name, errno, strerror(errno));
+    else if (bytesRead != sizeof(dobj))
+        pm_error("Cannot read entire disk object header for file '%s'.  "
+                 "Only read 0x%X of 0x%X bytes",
+                 infoP->name, (unsigned)bytesRead, (unsigned)sizeof(dobj));
 
     /* Check magic number */
-    if ( ( dobj.magic[0] != 0xE3 ) && ( dobj.magic[1] != 0x10 ) )
-        pm_error( "Wrong magic number for file '%s'.  "
-                  "Expected 0xE310, but got 0x%X%X",
-                  infoP->name, dobj.magic[0], dobj.magic[1] );
+    if ((dobj.magic[0] != 0xE3) && (dobj.magic[1] != 0x10))
+        pm_error("Wrong magic number for file '%s'.  "
+                 "Expected 0xE310, but got 0x%X%X",
+                 infoP->name, dobj.magic[0], dobj.magic[1]);
 
     /* Set version info and have drawer data flag */
-    infoP->version     = ( dobj.version[0]     <<  8 ) +
-        ( dobj.version[1]           );
-    infoP->drawerData  = ( dobj.pDrawerData[0] << 24 ) +
-        ( dobj.pDrawerData[1] << 16 ) +
-        ( dobj.pDrawerData[2] <<  8 ) +
-        ( dobj.pDrawerData[3]       ) ? TRUE : FALSE;
+    infoP->version     = (dobj.version[0]     <<  8) +
+        (dobj.version[1]           );
+    infoP->drawerData  = (dobj.pDrawerData[0] << 24) +
+        (dobj.pDrawerData[1] << 16) +
+        (dobj.pDrawerData[2] <<  8) +
+        (dobj.pDrawerData[3]      ) ? TRUE : FALSE;
 }
 
 
 
 static void 
-getIconHeader( IconInfo * const infoP ) {
+getIconHeader(IconInfo * const infoP) {
 /*-------------------------------------------------------------------------
  * Get fields from icon header portion of info file
  *-------------------------------------------------------------------------*/
@@ -267,25 +267,25 @@ getIconHeader( IconInfo * const infoP ) {
     size_t      bytesRead;
 
     /* Read icon header */
-    bytesRead = fread( &ihead, 1, sizeof(ihead), infoP->fp );
-    if ( ferror(infoP->fp ) )
-         pm_error( "Cannot read icon header for file '%s'.  "
-                   "fread() errno = %d (%s)",
-                   infoP->name, errno, strerror( errno ) );
-    else if ( bytesRead != sizeof(ihead) )
-        pm_error( "Cannot read the entire icon header for file '%s'.  "
-                  "Only read 0x%X of 0x%X bytes",
-                  infoP->name, bytesRead, sizeof(ihead) );
+    bytesRead = fread(&ihead, 1, sizeof(ihead), infoP->fp);
+    if (ferror(infoP->fp))
+        pm_error("Cannot read icon header for file '%s'.  "
+                 "fread() errno = %d (%s)",
+                 infoP->name, errno, strerror(errno));
+    else if (bytesRead != sizeof(ihead))
+        pm_error("Cannot read the entire icon header for file '%s'.  "
+                 "Only read 0x%X of 0x%X bytes",
+                 infoP->name, (unsigned)bytesRead, (unsigned)sizeof(ihead));
 
     /* Get icon width, heigh, and bitplanes */
-    infoP->width  = ( ihead.iconWidth[0]  << 8 ) + ihead.iconWidth[1];
-    infoP->height = ( ihead.iconHeight[0] << 8 ) + ihead.iconHeight[1];
-    infoP->depth  = ( ihead.bpp[0]        << 8 ) + ihead.bpp[1];
+    infoP->width  = (ihead.iconWidth[0]  << 8) + ihead.iconWidth[1];
+    infoP->height = (ihead.iconHeight[0] << 8) + ihead.iconHeight[1];
+    infoP->depth  = (ihead.bpp[0]        << 8) + ihead.bpp[1];
 
     /* Check number of bit planes */
-    if ( ( infoP->depth > 2 ) || ( infoP->depth < 1 ) )
-        pm_error( "We don't know how to interpret %u bitplanes file '%s'.  ",
-                  infoP->depth, infoP->name );
+    if ((infoP->depth > 2) || (infoP->depth < 1))
+        pm_error("We don't know how to interpret %u bitplanes file '%s'.  ",
+                 infoP->depth, infoP->name);
 }
 
 
diff --git a/converter/other/ipdb.c b/converter/other/ipdb.c
new file mode 100644
index 00000000..7ee37872
--- /dev/null
+++ b/converter/other/ipdb.c
@@ -0,0 +1,384 @@
+/*
+ *
+ * Copyright (C) 1997 Eric A. Howe
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *   Authors:  Eric A. Howe (mu@trends.net)
+ *             Bryan Henderson, 2010
+ */
+#define _XOPEN_SOURCE 500  /* Make sure strdup() is in string.h */
+#define _BSD_SOURCE   /* Ensure strdup() is in <string.h> */
+#include <assert.h>
+#include <time.h>
+#include <string.h>
+
+#include "mallocvar.h"
+#include "nstring.h"
+#include "ipdb.h"
+
+typedef uint32_t pilot_time_t;
+
+
+
+
+static unsigned int
+imgPpb(IMAGE * const imgP) {
+/*----------------------------------------------------------------------------
+   Pixels per byte
+-----------------------------------------------------------------------------*/
+    return
+        imgP->type == IMG_GRAY   ? 4 :
+        imgP->type == IMG_GRAY16 ? 2 :
+        8;
+}
+
+
+
+unsigned int
+ipdb_img_ppb(IMAGE * const imgP) {
+/*----------------------------------------------------------------------------
+   Pixels per byte
+-----------------------------------------------------------------------------*/
+    return imgPpb(imgP);
+}
+
+
+
+size_t
+ipdb_img_size(IMAGE * const imgP) {
+/*----------------------------------------------------------------------------
+  Size (in bytes) of an image's data.
+-----------------------------------------------------------------------------*/
+    return (size_t)(imgP->width / imgPpb(imgP) * imgP->height);
+}
+
+
+
+/*
+ * Return the start of row `r'.
+ */
+ uint8_t *
+ ipdb_img_row(IMAGE *      const imgP,
+              unsigned int const row) {
+
+     return &imgP->data[(row) * imgP->width / imgPpb(imgP)];
+ }
+
+
+
+ #define img_row(i, r)   
+
+ static pilot_time_t const unixepoch = (66*365+17)*24*3600;
+     /* The unix epoch in Mac time (the Mac epoch is 00:00 UTC 1904.01.01).
+        The 17 is the number of leap years.
+     */
+
+ static const char * const errorDesc[] = {
+     /* E_BADCOLORS      */
+     "Invalid palette, only {0x00, 0x55, 0xAA, 0xFF} allowed.",
+
+     /* E_NOTIMAGE       */
+     "Not an image file.",
+
+     /* E_IMAGETHERE     */
+     "Image record already present, logic error.",
+
+     /* E_IMAGENOTTHERE  */
+     "Image record required before text record, logic error.",
+
+     /* E_TEXTTHERE      */
+     "Text record already present, logic error.",
+
+     /* E_NOTRECHDR      */
+     "Invalid record header encountered.",
+
+     /* E_UNKNOWNRECHDR  */
+     "Unknown record header.",
+
+     /* E_TOOBIGG        */
+     "Image too big, maximum size approx. 640*400 gray pixels.",
+
+     /* E_TOOBIGM        */
+     "Image too big, maximum size approx. 640*800 monochrome pixels.",
+ };
+
+
+
+ const char *
+ ipdb_err(int const e) {
+
+     if (e < 0)
+         return e >= E_LAST ? errorDesc[-e - 1] : "unknown error";
+     else
+         return strerror(e);
+ }
+
+
+
+ static void
+ rechdr_free(RECHDR * const recP) {
+
+     if (recP) {
+         free(recP->extra);
+         free(recP);
+     }
+ }
+
+
+
+ void
+ ipdb_image_free(IMAGE * const imgP) {
+
+     if (imgP) {
+         rechdr_free(imgP->r);
+         free(imgP->data);
+         free(imgP);
+     }
+ }
+
+
+
+ void
+ ipdb_text_free(TEXT * const textP) {
+
+     if (textP) {
+         rechdr_free(textP->r);
+         free(textP->data);
+         free(textP);
+     }
+ }
+
+
+
+ void
+ ipdb_pdbhead_free(PDBHEAD * const headP) {
+
+     free(headP);
+ }
+
+
+
+ void
+ ipdb_clear(IPDB * const pdbP) {
+     
+     if (pdbP) {
+         ipdb_image_free(pdbP->i);
+         ipdb_text_free(pdbP->t);
+         ipdb_pdbhead_free(pdbP->p);
+    }
+}
+
+
+
+void
+ipdb_free(IPDB * const pdbP) {
+
+    ipdb_clear(pdbP);
+    free(pdbP);
+}
+
+
+
+PDBHEAD *
+ipdb_pdbhead_alloc(const char * const name) {
+
+    PDBHEAD * pdbHeadP;
+
+    MALLOCVAR(pdbHeadP);
+
+    if (pdbHeadP) {
+        MEMSZERO(pdbHeadP);
+
+        STRSCPY(pdbHeadP->name, name == NULL ? "unnamed" : name);
+
+        /*
+         * All of the Image Viewer pdb files that I've come across have
+         * 3510939142U (1997.08.16 14:38:22 UTC) here.  I don't know where
+         * this bizarre date comes from but the real date works fine so
+         * I'm using it.
+         */
+        pdbHeadP->ctime =
+            pdbHeadP->mtime = (pilot_time_t)time(NULL) + unixepoch;
+        
+        MEMSCPY(&pdbHeadP->type, IPDB_vIMG);
+        MEMSCPY(&pdbHeadP->id,   IPDB_View);
+    }
+    return pdbHeadP;
+}
+
+
+
+static RECHDR *
+rechdr_alloc(int      const type,
+             uint32_t const offset) {
+
+    /*
+     * We never produce the `extra' bytes (we only read them from a file)
+     * so there is no point allocating them here.
+     */
+
+    RECHDR  * recHdrP;
+
+    MALLOCVAR(recHdrP);
+    
+    if (recHdrP) {
+        MEMSSET(recHdrP, 0);
+
+        recHdrP->offset   = offset;
+        recHdrP->rec_type = (uint8_t)(0xff & type);
+        MEMSCPY(&recHdrP->unknown, IPDB_MYST);
+    }
+    return recHdrP;
+}
+
+
+
+/*
+ * The offset will be patched up as needed elsewhere.
+ */
+#define IMGOFFSET   (PDBHEAD_SIZE + 8)
+
+
+
+IMAGE *
+ipdb_image_alloc(const char * const name,
+            int          const type,
+            int          const w,
+            int          const h) {
+
+    bool failed;
+    IMAGE * imgP;
+
+    failed = false;
+
+    MALLOCVAR(imgP);
+
+    if (imgP) {
+        MEMSZERO(imgP);
+
+        STRSCPY(imgP->name, name == NULL ? "unnamed" : name);
+        imgP->type     = type;
+        imgP->x_anchor = 0xffff;
+        imgP->y_anchor = 0xffff;
+        imgP->width    = w;
+        imgP->height   = h;
+
+        imgP->r = rechdr_alloc(IMG_REC, IMGOFFSET);
+
+        if (imgP->r) {
+            if (w != 0 && h != 0) {
+                MALLOCARRAY(imgP->data, w * h);
+
+                if (imgP->data) {
+                    memset(imgP->data, 0, sizeof(*(imgP->data)) * w * h);
+                } else
+                    failed = true;
+            }
+            if (failed)
+                rechdr_free(imgP->r);
+        } else
+            failed = true;
+        
+        if (failed)
+            ipdb_image_free(imgP);
+    } else 
+        failed = true;
+
+    return failed ? NULL : imgP;
+}
+
+
+
+TEXT *
+ipdb_text_alloc(const char * const content) {
+
+    TEXT * textP;
+    bool failed;
+
+    failed = false;
+    /*
+     * The offset will be patched up later on when we know what it
+     * should be.
+     */
+
+    MALLOCVAR(textP);
+
+    if (textP) {
+        MEMSZERO(textP);
+
+        textP->r = rechdr_alloc(TEXT_REC, 0);
+
+        if (textP->r) {
+            if (content) {
+                textP->data = strdup(content);
+
+                if (!textP->data)
+                    failed = true;
+            }
+            if (failed)
+                rechdr_free(textP->r);
+        } else
+            failed = true;
+
+        if (failed)
+            ipdb_text_free(textP);
+    } else
+        failed = true;
+
+    return failed ? NULL : textP;
+}
+
+
+
+IPDB *
+ipdb_alloc(const char * const name) {
+
+    IPDB * pdbP;
+    bool failed;
+
+    failed = false;
+
+    MALLOCVAR(pdbP);
+
+    if (pdbP) {
+        MEMSZERO(pdbP);
+
+        if (name) {
+            pdbP->p = ipdb_pdbhead_alloc(name);
+
+            if (!pdbP->p)
+                failed = true;
+        }
+        if (failed)
+            ipdb_free(pdbP);
+    } else
+        failed = true;
+
+    return failed ? NULL : pdbP;
+}
+
+
+
+const char *
+ipdb_typeName(uint8_t const type) {
+
+    switch (type) {
+    case IMG_GRAY16: return "16 Bit Grayscale"; break;
+    case IMG_GRAY: return "Grayscale"; break;
+    case IMG_MONO: return "Monochrome"; break;
+    default: return "???";
+    }
+}
diff --git a/converter/other/ipdb.h b/converter/other/ipdb.h
new file mode 100644
index 00000000..6af5fc44
--- /dev/null
+++ b/converter/other/ipdb.h
@@ -0,0 +1,243 @@
+/*
+ * ipdb.h
+ *  Image Viewer PDB file functions.
+ *
+ * Copyright (C) 1997 Eric A. Howe
+ *
+ * This library is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Library General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *   Authors: Eric A. Howe (mu@trends.net)
+ *            Bryan Henderson 2010
+ */
+#ifndef IPDB_H_INCLUDED
+#define IPDB_H_INCLUDED
+
+#include <stdio.h>
+#include <errno.h>
+
+/*
+ * Extra error numbers, feed these (or errno values) to ipdb_err()
+ * to get strings.
+ */
+#define E_BADCOLORS -1
+#define E_NOTIMAGE  -2
+#define E_IMAGETHERE    -3
+#define E_IMAGENOTTHERE -4
+#define E_TEXTTHERE -5
+#define E_NOTRECHDR -6
+#define E_UNKNOWNRECHDR -7
+#define E_TOOBIGG   -8
+#define E_TOOBIGM   -9
+#define E_LAST      -9
+
+/*
+ * The standard pdb header.
+ */
+typedef struct {
+    char      name[32];       /* nul terminated   */
+    uint16_t  flags;          /* 0            */
+    uint16_t  version;        /* 0            */
+    uint32_t  ctime;          /* mac time     */
+    uint32_t  mtime;          /* mac time     */
+    uint32_t  btime;          /* mac time     */
+    uint32_t  mod_num;        /* 0            */
+    uint32_t  app_info;       /* 0            */
+    uint32_t  sort_info;      /* 0            */
+    uint8_t   type[4];        /* vIMG         */
+    uint8_t   id[4];          /* View         */
+    uint32_t  uniq_seed;      /* 0            */
+    uint32_t  next_rec;       /* 0            */
+    uint16_t  num_recs;       /* 1            */
+} PDBHEAD;
+#define PDBHEAD_SIZE    (32 + 2*2 + 6*4 + 4 + 4 + 2*4 + 2)
+
+/*
+ * Between the pdb header and the image header we find some "mystery" bytes,
+ * these are supposed to be eight byte record headers but sometimes there
+ * are ten bytes.  Version zero files use eight bytes, version 1 files appear
+ * to use ten bytes, files with attached notes (version 2?) use two sets of
+ * eight bytes.  Note that this version isn't the same as the `version' field
+ * in IMAGE, that version only indicates if the file is compressed or not.
+ *
+ * The first four bytes of each piece are a four byte offset to the start
+ * of the corresponding image header or text record; the next three bytes
+ * (40 6f 80) are some kind of magic (they are always the same); the next
+ * byte is zero for image records and 1 for text records; any remaining
+ * mystery bytes (zero or two) are always zero.
+ */
+typedef struct {
+    uint32_t offset;     /* offset, from zero, to the image  */
+    uint8_t  unknown[3]; /* 40 6f 80             */
+    uint8_t  rec_type;   /* byte seven, TEXT_REC || IMG_REC  */
+    size_t   n_extra;    /* bytes in extra           */
+    uint8_t  *extra;     /* extra unknown end bytes      */
+} RECHDR;
+#define IMG_REC     (uint8_t)(0x00)
+#define TEXT_REC    (uint8_t)(0x01)
+
+/*
+ * The image headers.
+ */
+typedef struct {
+    RECHDR  * r;
+
+    /*
+     * Whether the image was originally compressed.  Since compressed
+     * data can cross row boundaries we have to uncompress the whole
+     * thing during reads so `data' is always in the uncompressed
+     * (but packed) format.  I think we can just use the `version'
+     * field for this but a little extra paranoia is worth a couple
+     * of bytes. This is also set after a write to indicate if
+     * compression was used.
+     */
+    int       compressed;
+
+    /*
+     * The actual image header, this starts at `m->offset'.
+     */
+    char      name[32];   /* nul terminated           */
+    uint8_t   version;    /* 0 => uncompressed, 1 => compressed   */
+    uint8_t   type;       /* GRAYSCALE || MONOCHROME      */
+    uint8_t   reserved1[4];   /* zero                 */
+    uint8_t   note[4];    /* zero                 */
+    uint16_t  x_last;     /* zero                 */
+    uint16_t  y_last;     /* zero                 */
+    uint8_t   reserved2[4];   /* zero                 */
+    uint16_t  x_anchor;   /* 0xffff               */
+    uint16_t  y_anchor;   /* 0xffff               */
+    uint16_t  width;      /* pixels (must be 0 mod 16)        */
+    uint16_t  height;     /* pixels               */
+
+    /*
+     * And finally, the actual image data.  We always store the
+     * image data as 4 pixels per byte uncompressed.  Any compression
+     * or decompression is done at I/O time.
+     */
+    uint8_t  * data;
+} IMAGE;
+
+#define IMAGESIZE   (32 + 1 + 1 + 4 + 4 + 2*2 + 4 + 2*2 + 2*2)
+
+/*
+ * Image types for IMAGE.type.
+ */
+#define IMG_GRAY16  ((uint8_t)2)
+#define IMG_GRAY    ((uint8_t)0)
+#define IMG_MONO    ((uint8_t)0xff)
+
+const char *
+ipdb_typeName(uint8_t const type);
+
+
+/*
+ * Compression constants for IMAGE.version.
+ */
+#define IMG_COMPRESSED      ((uint8_t)0x01)
+#define IMG_UNCOMPRESSED    ((uint8_t)0x00)
+
+/*
+ * The notes record.  If this exists, it will follow the image record.
+ */
+typedef struct {
+    RECHDR  *r;
+    char    *data;      /* the actual text as a normal string   */
+} TEXT;
+
+/*
+ * One PDB file.  The `t' field will be NULL if there is no note.
+ */
+typedef struct {
+    PDBHEAD * p;
+    IMAGE   * i;
+    TEXT    * t;
+} IPDB;
+
+/*
+ * Only use four bytes of these.
+ */
+#define IPDB_vIMG   "vIMG"
+#define IPDB_View   "View"
+/*
+ * Only use three bytes of this.
+ */
+#define IPDB_MYST   "\x40\x6f\x80"
+
+/*
+ * Flags for ipdb_write().
+ */
+#define IPDB_COMPMAYBE  0       /* compress if it does any good */
+#define IPDB_NOCOMPRESS (1 << 1)    /* don't compress       */
+#define IPDB_COMPRESS   (1 << 2)    /* compress         */
+
+#define ipdb_width(pdb)     ((pdb)->i->width)
+#define ipdb_height(pdb)    ((pdb)->i->height)
+#define ipdb_text(pdb)      ((pdb)->t == NULL ? NULL : (pdb)->t->data)
+#define ipdb_compressed(pdb)    ((pdb)->i->compressed)
+#define ipdb_ctime(pdb)     ((time_t)((pdb)->p->ctime - UNIXEPOCH))
+#define ipdb_mtime(pdb)     ((time_t)((pdb)->p->mtime - UNIXEPOCH))
+#define ipdb_btime(pdb)     ((time_t)((pdb)->p->btime - UNIXEPOCH))
+#define ipdb_iname(pdb)     ((pdb)->i->name)
+#define ipdb_pname(pdb)     ((pdb)->p->name)
+#define ipdb_version(pdb)   ((pdb)->i->version)
+#define ipdb_type(pdb)      ((pdb)->i->type)
+#define ipdb_xlast(pdb)     ((pdb)->i->x_last)
+#define ipdb_ylast(pdb)     ((pdb)->i->y_last)
+#define ipdb_xanchor(pdb)   ((pdb)->i->x_anchor)
+#define ipdb_yanchor(pdb)   ((pdb)->i->y_anchor)
+
+const char *
+ipdb_err(int error);
+
+size_t
+ipdb_img_size(IMAGE * const imgP);
+
+unsigned int
+ipdb_img_ppb(IMAGE * const imgP);
+
+uint8_t *
+ipdb_img_row(IMAGE *      const imgP,
+             unsigned int const row);
+
+void
+ipdb_free(IPDB *);
+
+IPDB *
+ipdb_alloc(const char *);
+
+void
+ipdb_clear(IPDB * const pdbP);
+
+PDBHEAD *
+ipdb_pdbhead_alloc(const char * const name);
+
+void
+ipdb_pdbhead_free(PDBHEAD * const headP);
+
+IMAGE *
+ipdb_image_alloc(const char * const name,
+                 int          const type,
+                 int          const w,
+                 int          const h);
+
+void
+ipdb_image_free(IMAGE * const imgP);
+
+void
+ipdb_text_free(TEXT * const textP);
+
+TEXT *
+ipdb_text_alloc(const char * const content);
+
+#endif
diff --git a/converter/other/jbig/ANNOUNCE b/converter/other/jbig/ANNOUNCE
deleted file mode 100644
index edbcc3f8..00000000
--- a/converter/other/jbig/ANNOUNCE
+++ /dev/null
@@ -1,243 +0,0 @@
-
-Version 1.2 of the JBIG-KIT lossless image compression library available
-------------------------------------------------------------------------
-
-Markus Kuhn -- 2000-04-08
-
-
-The latest release of JBIG-KIT can be downloaded over the Internet
-with anonymous ftp from
-
-  ftp://ftp.informatik.uni-erlangen.de/pub/doc/ISO/JBIG/jbigkit-1.2.tar.gz
-  http://www.cl.cam.ac.uk/~mgk25/download/jbigkit-1.2.tar.gz
-
-and from a number of other servers.
-
-JBIG-KIT implements a highly effective data compression algorithm for
-bi-level high-resolution images such as fax pages or scanned
-documents.
-
-JBIG-KIT provides a portable library of compression and decompression
-functions with a documented interface that you can very easily include
-into your image or document processing software. In addition, JBIG-KIT
-provides ready-to-use compression and decompression programs with a
-simple command line interface (similar to the converters found in Jef
-Poskanzer's PBM graphics file conversion package).
-
-JBIG-KIT implements the specification
-
-  International Standard ISO/IEC 11544:1993 and ITU-T Recommendation
-  T.82(1993), "Information technology - Coded representation of picture
-  and audio information - progressive bi-level image compression",
-  <http://www.itu.ch/itudoc/itu-t/rec/t/t82_23822.html>,
-
-which is commonly referred to as the "JBIG standard". JBIG (Joint
-Bi-level Image experts Group) is the committee which developed this
-international standard for the lossless compression of images using
-arithmetic coding. Like the well-known compression algorithms JPEG and
-MPEG, also JBIG has been developed and published by the International
-Organization for Standardization (ISO) and the International
-Telecommunication Union (ITU). See also
-
-  http://www.jpeg.org/public/jbighomepage.htm
-  http://www.iso.ch/
-  http://www.itu.ch/
-
-The JBIG compression algorithm offers the following features:
-
-  - Close to state-of-the-art lossless compression ratio for high
-    resolution bi-level images.
-
-  - Around 1.1 to 1.5 times better compression ratio on typical
-    scanned documents compared to G4 fax compression (ITU-T T.6),
-    which has been the best compression algorithm for scanned
-    documents available prior to JBIG.
-
-  - Up to 30 times better compression of scanned images with dithered
-    images compared to G4 fax compression.
-
-  - Around 2 times better compression on typical 300 dpi documents
-    compared to 'gzip -9' on raw bitmaps.
-    
-  - Around 3-4 times better compression than GIF on typical 300 dpi
-    documents.
-
-  - Even much better competitive compression results on computer
-    generated images which are free of scanning distortions.
-
-  - JBIG supports hierarchical "progressive" encoding, that means it is
-    possible to encode a low resolution image first, followed by
-    resolution enhancement data. This allows for instance a document
-    browser to display already a good 75 dpi low resolution version of
-    an image, while the data necessary to reconstruct the full 300 dpi
-    version for laser printer reproduction is still arriving (say
-    over a slow network link or mass storage medium).
-
-  - The various resolution layers of a JBIG image in progressive
-    encoding mode together require not much more space than a
-    normal non-progressive mode encoded image (which JBIG also
-    supports).
-
-  - The progressive encoding mode utilizes a very sophisticated
-    resolution reduction algorithm which offers highest quality
-    low resolution versions that preserve the shape of characters as
-    well as the integrity of thin lines and dithered images.
-
-  - JBIG supports multiple bit planes and can this way also be used
-    for greyscale and color images, although the main field of
-    application is compression of bi-level images, i.e. images with
-    only two different pixel values. For greyscale images with up to
-    6 bit per pixel, JBIG performs superior to JPEG's lossless
-    mode.
-
-JBIG-KIT is free software under the GNU General Public License. For
-other license arrangements contact the author. JBIG-KIT provides a
-portable library implemented in ANSI/ISO C for encoding and decoding
-JBIG data streams together with documentation. The library is not
-intended for 8-bit or 16-bit machine architectures (e.g., old MS-DOS C
-compilers) on which a number of very efficient optimization techniques
-used in this software are not possible. For maximum performance, a
-32-bit processor is required (64-bit systems work too, of course). On
-architectures with 16-bit pointer arithmetic, only very small images
-can be processed.
-
-Special features of the JBIG-KIT implementation are:
-
-  - Fully reentrant multithread-capable design (no global or static
-    variables, isolated malloc()/free() calls, etc.).
-
-  - Capable of handling incomplete and growing JBIG data streams in
-    order to allow earliest display of low resolution versions.
-
-  - Capable of handling several incoming data streams simultaneously
-    in one single process and task.
-
-  - Especially designed with applications in mind that want to display
-    incoming data as early as possible (e.g., similar to the way in
-    which Netscape Navigator handles incoming GIF images).
-
-  - Implements all JBIG features and options including progressive and
-    sequential encoding, multiple bit planes, user specified
-    resolution reduction and deterministic prediction tables, adaptive
-    template changes for optimal performance on half-tone images,
-    deterministic prediction, typical prediction in lowest and
-    differential layers, various stripe orderings, etc. Only the SEQ
-    and HITOLO options are currently not supported by the decoder
-    (they are normally never required, but could be added later in
-    case of user requirements).
-
-  - Efficient code, optimized utilization of 32-bit processor
-    registers.
-
-  - Very easy to use documented C library interface.
-
-  - Included Gray code conversion routines for efficient encoding
-    of greyscale images.
-
-  - Ready-to-use pbmtojbg and jbgtopbm converters.
-
-
-Changes in version 1.2 (2000-04-08):
-
-  - bug in the decoder fixed, which caused the rest of the input file
-    to be skipped whenever a comment marker was encountered (special
-    thanks to Ben Rudiak-Gould <benrg@math.berkeley.edu> for
-    reporting this one)
-
-Changes in version 1.1 (1999-11-16):
-
-  - serious bug in the encoder fixed, which for a very small
-    percentage of images has caused an unterminated linked list to be
-    created internally that could have been responsible for
-    segmentation violations or non-terminating encoders
-    (special thanks to Hisashi Saiga <saiga@itl.tnr.sharp.co.jp> for
-    tracking that one down)
-
-  - minor bug in the "jbgtopbm -d" diagnostic output fixed
-
-Changes in version 1.0 (1998-04-11):
-
-  - two bugs fixed that caused the encoder and decoder to fail
-    under certain modes of operation with several bit planes
-
-  - added new functions jbg_split_planes(), jbg_dec_merge_planes(),
-    and jbg_dec_getsize_merged() for easy handling of greyscale
-    images
-
-  - added support for compressing greyscale PGM files to pbmtojbg
-    and jbgtopbm
-
-  - more changes to avoid paranoid compiler warnings
-
-Changes in version 0.9 (1996-01-09):
-
-  - encoder won't break any more on input bitmap data with incorrect
-    zero padding
-
-  - pbmtojbg displays a warning if input file has incorrect zero
-    padding
-
-  - various minor improvements suggested by Stefan Willer
-    <Stefan.Willer@unnet.wupper.DE>
-
-  - many minor changes in order to avoid warnings from paranoid
-    compilers
-
-Changes in version 0.8 (1995-09-20):
-
-  - namespace cleared up, all names externally visible from the library
-    start now with jbg_ or JBG_
-
-  - minor non-critical bug fixed which caused library to fail compatibility
-    test and showed up especially on DEC Alpha systems
-
-  - jbg_dec_gethight() is now called jbg_dec_getheight()
-
-  - filenames conform now to MS-DOS limits
-
-  - Bug in pbmtojbg fixed (handling of ASCII PBM files)
-
-Changes in version 0.7 (1995-06-10):
-
-  - more problems on 16-bit int systems and on Macintosh systems fixed
-    (special thanks to Jean-Pierre Gachen <jpg11@calvanet.calvacom.fr>)
-
-  - global Makefile
-
-Changes in version 0.6 (1995-06-08):
-
-  - memory leak fixed
-
-  - should now also work on systems where int is only 16-bit large
-
-  - changes of the JBIG "Technical Corrigendum 1" included (special
-    thanks to Dr. Sebestyen from Siemens AG for sending me a copy
-    of the draft)
-
-First release: version 0.5 (1995-05-28)
-
-
-Please send all questions, problem reports, patches, suggestions,
-success stories, comments, etc. to
-
-  mkuhn at acm.org
-
-I will try to provide free support and maintenance for this software
-at least for the next few months depending on my available time.
-
-Y2K statement: JBIG-KIT does not handle any date and time related
-data, therefore if JBIG-KIT causes you any problems related to date
-and time overflows, this would indeed be most surprising.
-
-This library has been published in the hope that it will encourage the
-development of good freely available scanned document handling and
-transmission systems for the Internet so that large amounts of scanned
-text can be made available to the global village easily.
-
-Happy compressing ...
-
-Markus Kuhn
-
---
-Markus G. Kuhn, Security Group, Computer Lab, Cambridge University, UK
-email: mkuhn at acm.org,  home page: <http://www.cl.cam.ac.uk/~mgk25/>
diff --git a/converter/other/jbig/Makefile b/converter/other/jbig/Makefile
index b5f4e14a..c4d7e9d6 100644
--- a/converter/other/jbig/Makefile
+++ b/converter/other/jbig/Makefile
@@ -5,43 +5,54 @@ endif
 SUBDIR = converter/other/jbig
 VPATH=.:$(SRCDIR)/$(SUBDIR)
 
+SUBDIRS =
+
 include $(BUILDDIR)/config.mk
 
-LIBJBIG_OBJECTS = jbig.o jbig_tab.o
+# INTERNAL_JBIGLIB must be relative to the current directory, because it
+# may end up in MERGE_OBJECTS, which must be relative.
+INTERNAL_JBIGLIB = libjbig/libjbig.a
+INTERNAL_JBIGHDR_DIR = $(SRCDIR)/$(SUBDIR)/libjbig/include
 
 EXTERN_INCLUDES =
 ifneq ($(JBIGHDR_DIR),NONE)
-  EXTERN_INCLUDES += -I$(JBIGHDR_DIR)
+  ifneq ($(JBIGHDR_DIR)x,x)
+    EXTERN_INCLUDES += -I$(JBIGHDR_DIR)
+  endif
 endif
 
 ifneq ($(JBIGHDR_DIR),NONE)
   ifneq ($(JBIGLIB),NONE)
-    BINARIES = jbigtopnm pnmtojbig
+    PORTBINARIES = jbigtopnm pnmtojbig
   endif
 endif
 
+BINARIES = $(PORTBINARIES)
+
+MERGEBINARIES = $(BINARIES)
+
 SCRIPTS =
 
-ifeq ($(JBIGLIB),$(BUILDDIR)/$(SUBDIR)/libjbig.a)
+ifeq ($(JBIGLIB),$(INTERNAL_JBIGLIB))
   JBIGLIB_DEP = $(JBIGLIB)
+  SUBDIRS += libjbig
 else
   # It's not our internal version; user's on his own to make sure it's built
 endif
 
-OBJECTS = $(BINARIES:%=%.o) $(LIBJBIG_OBJECTS)
-MERGE_OBJECTS = $(BINARIES:%=%.o2) $(LIBJBIG_OBJECTS)
+OBJECTS = $(BINARIES:%=%.o)
+MERGE_OBJECTS = $(BINARIES:%=%.o2)
 
 all: $(BINARIES)
 
 include $(SRCDIR)/common.mk
 
-$(BINARIES): %: %.o $(JBIGLIB_DEP) $(NETPBMLIB) $(LIBOPT)
-	$(LD) -o $@ $< \
-	  $(shell $(LIBOPT) $(NETPBMLIB) $(JBIGLIB)) $(MATHLIB) \
-	  $(LDFLAGS) $(LDLIBS) $(RPATH) $(LADD)
-
+$(BINARIES): %: %.o $(JBIGLIB_DEP) $(LIBOPT)
+$(BINARIES): LDFLAGS_TARGET = $(shell $(LIBOPT) $(JBIGLIB))
 
-$(BUILDDIR)/$(SUBDIR)/libjbig.a: $(LIBJBIG_OBJECTS)
-	$(AR) -rc $@ $^
-	$(RANLIB) $@
+$(INTERNAL_JBIGLIB): $(BUILDDIR)/$(SUBDIR)/libjbig FORCE
+	$(MAKE) -f $(SRCDIR)/$(SUBDIR)/libjbig/Makefile \
+	  -C $(dir $@) $(notdir $@)
 
+.PHONY: FORCE
+FORCE:
diff --git a/converter/other/jbig/README b/converter/other/jbig/README
new file mode 100644
index 00000000..bd7a4745
--- /dev/null
+++ b/converter/other/jbig/README
@@ -0,0 +1,20 @@
+The jbig tools are derived from the JBIG-KIT package by Marcus Kuhn,
+by Bryan Henderson on 2000.05.11.
+
+The file ANNOUNCE in the 'libjbig' subdirectory is from that package and gives
+details.
+
+The Netpbm tools jbigtopbm and pbmtojbig were adapted from JBIG-KIT's
+jbgtopbm and pbmtojbg.  The main difference is that the Netpbm
+versions use the Netpbm libraries.
+
+The code in subdirectory 'libjbig' is straight from the JBIG_KIT package and
+generates essentially the same libjbig.a that one gets from that package.
+
+The code is based on JBIG-KIT version 2.1, adapted to Netpbm by Bryan
+Henderson in June 2014.
+
+The reason Netpbm contains a copy of the library is convenience of users.  For
+many people, the only reason to have a jbig library is to be able to convert
+images to and from the format, which they do with Netpbm.  Requiring a Netpbm
+user to find and install this esoteric library is impractical.
\ No newline at end of file
diff --git a/converter/other/jbig/README.Netpbm b/converter/other/jbig/README.Netpbm
deleted file mode 100644
index 3d593b92..00000000
--- a/converter/other/jbig/README.Netpbm
+++ /dev/null
@@ -1,12 +0,0 @@
-The jbig tools are derived from the JBIG-KIT package by Marcus Kuhn,
-by Bryan Henderson on 2000.05.11.
-
-The file ANNOUNCE in this directory is from that package and gives
-details.
-
-The Netpbm tools jbigtopbm and pbmtojbig were adapted from JBIG-KIT's
-jbgtopbm and pbmtojbg.  The main difference is that the Netpbm
-versions use the Netpbm libraries.
-
-The jbig.c and jbig_table.c modules are straight from the JBIG_KIT 
-package.  They are what normally are packaged as libjbig.a.
diff --git a/converter/other/jbig/jbig_tab.c b/converter/other/jbig/jbig_tab.c
deleted file mode 100644
index 55183503..00000000
--- a/converter/other/jbig/jbig_tab.c
+++ /dev/null
@@ -1,428 +0,0 @@
-/*
- *  Probability estimation tables for the arithmetic encoder/decoder
- *  given by ITU T.82 Table 24.
- *
- *  $Id: jbig_tab.c,v 1.6 1998-04-05 18:36:19+01 mgk25 Rel $
- */
-
-short jbg_lsz[113] = {
-  0x5a1d, 0x2586, 0x1114, 0x080b, 0x03d8, 0x01da, 0x00e5, 0x006f,
-  0x0036, 0x001a, 0x000d, 0x0006, 0x0003, 0x0001, 0x5a7f, 0x3f25,
-  0x2cf2, 0x207c, 0x17b9, 0x1182, 0x0cef, 0x09a1, 0x072f, 0x055c,
-  0x0406, 0x0303, 0x0240, 0x01b1, 0x0144, 0x00f5, 0x00b7, 0x008a,
-  0x0068, 0x004e, 0x003b, 0x002c, 0x5ae1, 0x484c, 0x3a0d, 0x2ef1,
-  0x261f, 0x1f33, 0x19a8, 0x1518, 0x1177, 0x0e74, 0x0bfb, 0x09f8,
-  0x0861, 0x0706, 0x05cd, 0x04de, 0x040f, 0x0363, 0x02d4, 0x025c,
-  0x01f8, 0x01a4, 0x0160, 0x0125, 0x00f6, 0x00cb, 0x00ab, 0x008f,
-  0x5b12, 0x4d04, 0x412c, 0x37d8, 0x2fe8, 0x293c, 0x2379, 0x1edf,
-  0x1aa9, 0x174e, 0x1424, 0x119c, 0x0f6b, 0x0d51, 0x0bb6, 0x0a40,
-  0x5832, 0x4d1c, 0x438e, 0x3bdd, 0x34ee, 0x2eae, 0x299a, 0x2516,
-  0x5570, 0x4ca9, 0x44d9, 0x3e22, 0x3824, 0x32b4, 0x2e17, 0x56a8,
-  0x4f46, 0x47e5, 0x41cf, 0x3c3d, 0x375e, 0x5231, 0x4c0f, 0x4639,
-  0x415e, 0x5627, 0x50e7, 0x4b85, 0x5597, 0x504f, 0x5a10, 0x5522,
-  0x59eb
-};
-
-unsigned char jbg_nmps[113] = {
-    1,   2,   3,   4,   5,   6,   7,   8,
-    9,  10,  11,  12,  13,  13,  15,  16,
-   17,  18,  19,  20,  21,  22,  23,  24,
-   25,  26,  27,  28,  29,  30,  31,  32,
-   33,  34,  35,   9,  37,  38,  39,  40,
-   41,  42,  43,  44,  45,  46,  47,  48,
-   49,  50,  51,  52,  53,  54,  55,  56,
-   57,  58,  59,  60,  61,  62,  63,  32,
-   65,  66,  67,  68,  69,  70,  71,  72,
-   73,  74,  75,  76,  77,  78,  79,  48,
-   81,  82,  83,  84,  85,  86,  87,  71,
-   89,  90,  91,  92,  93,  94,  86,  96,
-   97,  98,  99, 100,  93, 102, 103, 104,
-   99, 106, 107, 103, 109, 107, 111, 109,
-  111
-};
-
-/*
- * least significant 7 bits (mask 0x7f) of jbg_nlps[] contain NLPS value,
- * most significant bit (mask 0x80) contains SWTCH bit
- */
-unsigned char jbg_nlps[113] = {
-  129,  14,  16,  18,  20,  23,  25,  28,
-   30,  33,  35,   9,  10,  12, 143,  36,
-   38,  39,  40,  42,  43,  45,  46,  48,
-   49,  51,  52,  54,  56,  57,  59,  60,
-   62,  63,  32,  33, 165,  64,  65,  67,
-   68,  69,  70,  72,  73,  74,  75,  77,
-   78,  79,  48,  50,  50,  51,  52,  53,
-   54,  55,  56,  57,  58,  59,  61,  61,
-  193,  80,  81,  82,  83,  84,  86,  87,
-   87,  72,  72,  74,  74,  75,  77,  77,
-  208,  88,  89,  90,  91,  92,  93,  86,
-  216,  95,  96,  97,  99,  99,  93, 223,
-  101, 102, 103, 104,  99, 105, 106, 107,
-  103, 233, 108, 109, 110, 111, 238, 112,
-  240
-};
-
-/*
- * Resolution reduction table given by ITU-T T.82 Table 17
- */
-
-char jbg_resred[4096] = {
-  0,0,0,1,0,0,0,1,0,1,1,1,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
-  0,0,1,1,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
-  0,0,0,0,0,0,0,1,0,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
-  0,0,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
-  0,0,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
-  0,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
-  0,0,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
-  1,1,1,1,1,1,1,1,0,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
-  0,0,0,0,0,0,0,1,0,0,1,1,0,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,
-  0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
-  0,0,1,1,0,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,
-  0,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
-  0,0,1,1,0,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,
-  1,1,0,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
-  1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
-  1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
-  0,0,0,0,0,0,0,1,0,0,1,0,0,0,1,1,0,0,0,0,0,1,0,1,0,0,1,1,1,0,1,1,
-  0,0,0,1,0,0,0,1,0,0,1,0,0,0,1,1,0,1,1,1,0,0,0,1,1,1,1,1,1,1,1,1,
-  0,0,0,0,0,0,0,1,0,1,1,1,0,1,0,1,0,0,1,1,1,0,1,1,0,1,1,1,1,1,1,1,
-  0,0,0,0,0,0,0,0,0,1,0,1,0,0,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,
-  0,0,0,0,0,0,0,1,0,1,0,0,0,0,0,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
-  0,0,0,0,1,0,0,1,1,0,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
-  0,0,0,0,0,0,0,0,0,1,0,1,0,0,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,
-  1,0,0,1,0,0,1,1,0,1,1,1,1,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
-  0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,1,1,1,0,0,1,1,1,1,1,1,1,1,1,1,
-  0,0,1,1,0,0,0,1,0,0,0,1,0,0,1,1,0,1,1,1,0,1,0,1,1,1,1,1,1,1,1,1,
-  0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,1,1,0,1,1,0,1,1,1,1,1,1,0,1,1,1,0,
-  0,0,0,0,0,0,0,1,0,0,1,0,0,0,0,1,1,1,1,1,1,1,0,0,1,1,1,1,1,1,1,1,
-  0,0,0,0,0,0,0,0,1,0,0,1,0,0,1,1,0,1,1,1,0,1,0,1,1,1,1,1,1,1,1,1,
-  0,0,0,1,0,0,0,1,0,1,1,0,1,0,1,1,1,1,1,1,0,1,0,1,1,1,1,1,1,1,1,1,
-  1,1,1,0,1,0,0,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,
-  1,0,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,
-  0,0,0,0,0,0,0,1,0,0,1,0,0,0,1,1,0,0,0,0,0,0,0,1,0,0,1,1,1,1,1,1,
-  0,0,0,1,0,0,0,1,0,0,0,0,0,0,0,1,0,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,
-  0,0,0,0,0,0,0,1,0,1,1,1,0,1,0,1,0,1,1,0,1,0,1,1,0,1,1,1,1,1,1,1,
-  0,0,0,0,0,0,0,0,0,1,0,1,0,0,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,
-  0,0,0,0,0,0,0,1,0,1,1,0,0,0,0,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
-  0,0,1,0,1,0,0,1,0,0,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
-  0,0,0,0,0,0,0,0,0,1,1,1,0,0,1,1,0,0,1,1,1,1,1,1,0,1,1,1,1,0,1,1,
-  1,0,0,1,0,0,1,0,0,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
-  0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,1,1,1,1,0,1,1,1,1,1,1,1,1,1,0,
-  0,0,1,0,1,1,1,1,0,0,0,1,1,0,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
-  0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,1,0,0,1,1,0,1,1,1,1,1,1,1,1,1,1,0,
-  0,0,0,0,1,0,0,1,0,0,1,1,0,1,1,1,0,1,1,1,1,1,1,0,0,1,1,1,1,1,1,1,
-  0,0,0,0,0,0,0,0,1,1,0,1,0,0,1,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
-  0,0,0,1,1,0,1,1,0,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
-  0,0,0,0,0,0,0,0,0,1,1,1,0,1,0,1,0,1,1,1,1,1,1,1,0,1,1,1,0,1,1,1,
-  0,0,1,0,0,1,1,1,0,1,1,1,1,1,1,1,0,1,1,1,1,0,1,1,0,1,1,1,1,1,1,1,
-  0,0,0,0,0,0,0,1,0,0,0,0,0,0,1,1,0,0,0,0,0,0,0,1,0,0,0,0,1,0,0,1,
-  0,0,0,1,0,0,0,1,0,0,0,0,0,0,0,1,0,1,0,0,0,0,0,1,1,0,0,1,0,0,1,1,
-  0,0,0,0,0,0,0,1,0,1,1,1,0,1,0,1,0,0,1,0,0,0,0,1,0,1,0,1,0,1,0,1,
-  0,0,0,0,0,0,0,0,0,1,0,1,0,0,0,1,1,0,0,0,0,0,0,0,1,1,1,1,0,1,1,1,
-  0,0,0,0,0,0,0,1,0,1,0,0,0,0,0,1,0,1,1,0,1,0,1,1,0,0,0,1,0,0,1,1,
-  0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,
-  0,0,0,0,0,0,0,0,0,1,0,1,0,0,0,1,0,0,0,0,0,0,0,1,0,1,1,1,0,0,1,1,
-  0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,1,1,0,1,1,0,1,1,1,1,1,1,1,1,1,1,1,
-  0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,1,1,0,0,0,0,1,1,0,0,0,0,0,0,1,
-  0,0,1,0,0,1,1,1,0,0,0,0,1,0,0,1,0,0,0,1,1,1,1,0,1,0,1,1,1,1,1,1,
-  0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,1,0,1,0,1,1,0,
-  0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,1,1,1,1,1,1,1,
-  0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,1,0,0,0,0,1,0,1,1,1,0,1,1,1,
-  0,0,0,0,0,0,1,1,0,0,0,0,0,0,0,1,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
-  0,1,1,0,1,0,0,0,1,1,0,1,0,0,0,0,1,1,1,1,0,0,1,1,1,0,1,1,0,0,1,1,
-  0,0,0,0,0,0,0,0,1,1,0,1,0,0,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,
-  0,0,0,0,0,0,0,1,0,0,0,0,0,0,1,1,0,0,1,1,0,1,1,1,1,1,1,1,1,1,1,1,
-  0,0,1,1,0,0,1,1,0,0,1,1,0,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
-  0,0,0,0,0,0,0,1,0,1,1,1,0,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
-  0,0,0,1,0,0,0,1,0,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
-  0,0,0,0,0,0,0,1,1,1,1,1,0,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
-  0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,
-  0,0,0,1,0,0,1,0,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
-  1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,
-  0,0,0,0,0,0,0,1,0,0,0,1,0,0,1,0,0,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,
-  0,0,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
-  0,0,0,0,0,0,0,0,0,1,1,0,0,0,1,0,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,
-  0,0,1,1,1,1,1,1,0,0,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
-  0,0,0,1,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,
-  0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
-  1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
-  1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
-  0,0,0,0,0,0,0,1,0,0,1,0,0,0,1,1,0,0,0,0,0,0,0,1,0,0,0,1,1,0,1,1,
-  0,0,0,1,0,0,0,1,0,0,1,0,0,0,1,1,0,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,
-  0,0,0,0,0,0,0,1,0,1,1,1,0,1,0,1,0,0,1,0,1,0,1,1,0,1,1,1,0,1,1,1,
-  0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,1,1,0,1,1,1,1,1,0,1,1,1,1,1,1,1,1,
-  0,0,0,0,0,0,0,1,1,1,0,0,0,0,0,1,0,1,0,1,1,0,1,1,0,1,1,1,1,1,1,1,
-  0,0,0,0,1,0,0,1,0,0,1,1,0,0,1,1,0,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,
-  0,0,0,0,0,0,0,0,0,1,0,1,0,0,0,1,0,0,1,1,0,1,1,1,1,1,1,1,1,0,1,1,
-  1,0,1,0,1,0,0,1,1,0,1,1,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
-  0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,1,1,1,0,0,0,1,1,0,1,1,0,1,1,1,
-  0,0,1,0,0,0,0,1,0,0,0,0,0,0,1,1,0,1,1,1,0,1,0,1,1,1,1,1,1,1,1,1,
-  0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,1,0,1,1,1,0,1,1,0,1,1,1,1,
-  0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,
-  0,0,0,0,0,0,0,0,1,1,0,0,0,0,0,1,0,1,1,1,0,1,0,1,1,1,1,1,1,1,1,1,
-  0,0,0,0,0,0,0,1,1,0,1,0,1,0,1,1,0,1,0,1,0,0,0,1,1,1,1,1,1,1,1,1,
-  1,1,1,0,1,0,0,0,1,1,0,1,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,
-  1,0,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,
-  0,0,0,0,0,0,0,1,0,0,1,0,0,0,1,1,0,0,0,0,0,0,0,1,0,0,0,1,1,0,1,1,
-  0,0,1,1,0,0,0,1,0,0,0,0,0,0,0,1,0,1,0,1,0,0,1,1,0,1,1,1,1,1,1,1,
-  0,0,0,0,0,0,0,1,0,1,1,1,0,1,0,1,0,0,1,0,1,0,0,1,0,1,1,1,1,1,1,1,
-  0,0,0,0,0,0,0,0,0,1,0,1,0,0,0,1,1,0,1,1,0,1,1,0,1,1,1,1,1,1,1,1,
-  0,0,0,0,0,0,0,1,1,1,1,0,0,0,0,0,0,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,
-  0,0,0,0,1,0,1,0,0,0,1,1,1,0,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
-  0,0,0,0,0,0,0,0,0,1,1,1,0,0,0,1,0,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,
-  1,0,0,0,1,0,0,0,0,1,1,1,0,1,0,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,
-  0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,1,1,0,0,0,0,1,1,1,1,1,0,1,1,0,
-  0,0,1,1,1,1,1,1,0,0,0,0,1,0,0,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
-  0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,1,0,1,1,1,0,1,1,1,1,1,1,1,
-  0,0,0,0,1,0,0,0,0,0,0,1,0,0,1,1,0,1,1,1,1,1,1,0,0,1,1,1,1,1,1,1,
-  0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,
-  0,0,1,0,1,0,1,1,0,0,1,0,1,1,1,1,0,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,
-  0,0,0,0,0,0,0,0,0,1,1,1,0,0,0,1,0,1,1,1,1,1,1,1,0,1,1,1,0,1,1,1,
-  0,0,1,0,1,0,1,1,0,1,1,1,1,1,1,1,0,0,1,1,1,0,1,1,0,1,1,1,1,1,1,1,
-  0,0,0,0,0,0,0,1,0,0,0,0,0,0,1,1,0,0,0,0,0,0,0,1,0,0,0,0,1,0,0,1,
-  0,0,0,1,0,0,0,1,0,0,0,0,0,0,0,1,0,1,0,0,0,0,0,1,0,0,0,0,0,0,0,1,
-  0,0,0,0,0,0,0,1,0,1,1,1,0,1,0,1,0,0,1,0,0,0,0,1,0,1,0,1,0,1,0,1,
-  0,0,0,0,0,0,0,0,0,1,0,1,0,0,0,1,1,0,0,0,0,0,0,0,0,1,0,1,0,0,1,1,
-  0,0,0,0,0,0,0,1,0,1,0,0,0,0,0,1,0,1,0,0,1,0,0,1,0,0,0,0,0,0,0,1,
-  0,0,0,0,1,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,1,0,0,1,1,
-  0,0,0,0,0,0,0,0,0,1,0,1,0,0,0,1,0,0,0,0,0,0,0,0,0,1,0,1,0,0,1,1,
-  1,0,0,0,0,0,0,0,0,1,0,0,0,0,0,1,0,0,0,1,0,0,1,1,0,1,1,1,1,1,1,1,
-  0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,1,1,0,0,0,0,1,1,0,0,0,0,0,0,0,
-  0,0,1,0,0,0,0,1,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,1,0,0,0,1,0,0,1,1,
-  0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,
-  0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,1,1,
-  0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,1,1,
-  0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,1,0,1,0,1,0,0,0,1,0,1,1,1,1,1,1,1,
-  0,0,0,0,0,0,0,0,0,1,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,0,0,1,1,
-  0,0,0,0,0,0,0,1,0,1,0,1,0,1,0,0,0,0,1,1,0,0,0,1,0,1,1,1,0,1,1,1
-};
-
-/*
- * Deterministic prediction tables given by ITU-T T.82 tables
- * 19 to 22. The table below is organized differently, the
- * index bits are permutated for higher efficiency.
- */
-
-char jbg_dptable[256 + 512 + 2048 + 4096] = {
-  /* phase 0: offset=0 */
-  0,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,
-  0,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,2,0,2,2,2,2,2,2,2,2,2,2,2,2,2,
-  0,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,0,2,2,2,2,2,2,0,2,2,2,2,2,2,2,
-  0,2,0,2,2,2,2,2,2,2,2,2,2,2,2,2,0,0,2,2,2,2,2,2,0,2,0,2,2,2,2,2,
-  2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,2,0,2,2,2,2,2,2,2,2,2,2,2,2,2,
-  2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,1,
-  2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,0,2,2,2,2,2,2,2,2,2,2,2,2,2,2,
-  2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,
-  /* phase 1: offset=256 */
-  2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,2,2,2,2,2,2,2,2,2,2,2,2,2,
-  0,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,0,2,2,2,2,2,0,2,0,2,2,2,2,2,
-  2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,2,2,2,2,2,2,2,2,2,2,2,2,2,
-  0,2,2,2,2,1,2,1,2,2,2,2,1,1,1,1,2,0,2,0,2,2,2,2,0,2,0,2,2,2,2,2,
-  0,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,0,0,2,2,2,2,0,2,2,2,2,2,2,2,
-  0,2,0,2,2,2,2,2,2,2,2,2,2,0,2,0,2,2,0,0,2,2,2,2,2,0,0,2,2,2,2,2,
-  0,2,2,2,2,1,2,1,2,2,2,2,1,1,1,1,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,1,
-  1,2,1,2,2,2,2,2,2,2,2,2,2,1,2,2,2,2,1,1,2,2,2,2,2,0,2,2,2,2,2,2,
-  2,2,2,2,2,0,2,0,2,2,2,2,0,0,0,0,0,2,0,2,2,2,2,2,0,2,2,2,2,2,2,2,
-  0,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,2,0,2,2,2,2,0,2,0,2,2,2,2,2,
-  2,2,2,2,2,1,1,1,2,2,2,2,1,1,1,1,1,2,1,2,2,2,2,2,2,2,2,2,2,2,2,1,
-  2,2,2,2,2,2,2,2,2,2,2,2,2,0,1,2,0,2,0,2,2,2,2,2,0,2,0,2,2,2,2,1,
-  0,2,0,2,2,1,2,1,2,2,2,2,1,1,1,1,0,0,0,0,2,2,2,2,0,2,0,2,2,2,2,1,
-  2,2,0,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,2,2,2,2,2,0,0,0,2,2,2,2,2,
-  2,2,2,2,2,1,2,1,2,2,2,2,2,2,2,1,2,2,2,2,2,2,2,2,1,2,1,2,2,2,2,1,
-  2,2,2,2,2,2,2,2,0,2,0,2,2,1,2,2,2,2,2,2,2,2,2,2,0,0,0,2,2,2,2,2,
-  /* phase 2: offset=768 */
-  2,2,2,2,1,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,1,1,1,1,2,2,2,2,1,1,1,1,
-  0,2,2,2,2,1,2,1,2,2,2,2,1,2,1,2,0,0,0,0,1,1,1,1,0,0,0,0,1,1,1,1,
-  2,2,0,2,2,2,1,2,2,2,2,2,2,2,2,2,2,2,0,2,2,1,2,1,2,2,2,2,2,1,1,1,
-  2,0,2,2,2,1,2,1,0,2,2,2,1,2,1,2,2,2,2,0,2,2,2,2,0,2,0,2,2,2,2,2,
-  0,2,0,0,1,1,1,1,2,2,2,2,1,1,1,1,0,2,0,2,1,1,1,1,2,2,2,2,1,1,1,1,
-  2,2,0,2,2,2,1,2,2,2,2,2,1,2,1,2,2,2,0,2,2,1,2,1,0,2,0,2,1,1,1,1,
-  2,0,0,2,2,2,2,2,0,2,0,2,2,0,2,0,2,0,2,0,2,2,2,1,2,2,0,2,1,1,2,1,
-  2,2,2,0,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,2,2,2,1,2,1,
-  2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,1,1,1,1,2,2,2,2,1,1,1,1,
-  0,0,0,0,2,2,2,2,0,0,0,0,2,2,2,2,0,2,0,2,2,2,2,2,2,2,2,2,2,2,2,2,
-  2,2,0,2,2,2,2,1,0,2,2,2,1,1,1,1,2,0,2,2,2,2,2,2,0,2,0,2,2,1,2,1,
-  2,0,2,0,2,2,2,2,0,2,0,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,2,2,2,2,2,
-  0,2,2,2,1,2,1,2,2,2,2,2,2,2,2,2,0,2,2,2,2,2,1,2,2,2,2,2,2,2,2,2,
-  2,2,0,2,2,2,2,2,2,2,2,2,2,2,0,2,2,0,0,2,2,1,2,1,0,2,2,2,1,1,1,1,
-  2,2,2,0,2,2,2,2,2,2,0,2,2,0,2,0,2,1,2,2,2,2,2,2,1,2,1,2,2,2,2,2,
-  2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,2,0,2,2,2,1,
-  0,2,2,2,1,2,2,2,2,2,2,2,2,2,2,2,0,2,2,2,2,1,1,1,2,2,2,2,1,1,1,1,
-  2,2,2,1,2,2,2,2,2,2,1,2,0,0,0,0,2,2,0,2,2,1,2,2,2,2,2,2,1,1,1,1,
-  2,0,0,0,2,2,2,2,0,2,2,2,2,2,2,0,2,2,2,0,2,2,2,2,2,0,0,2,2,2,2,2,
-  2,2,2,2,2,2,2,2,2,2,0,2,2,1,2,2,2,2,2,2,2,2,2,2,2,0,2,2,2,1,2,1,
-  0,2,0,2,2,1,1,2,2,2,2,2,2,2,2,2,1,2,2,2,2,2,2,2,2,2,2,2,2,1,2,2,
-  2,0,2,0,2,1,2,1,0,2,0,2,2,2,1,2,2,0,2,0,2,2,2,2,0,2,0,2,2,2,1,2,
-  2,2,2,0,2,2,2,2,2,2,0,2,2,2,2,2,2,2,1,2,2,2,2,2,2,0,1,2,2,2,2,1,
-  2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,1,2,2,2,2,2,2,2,2,2,2,2,0,2,2,2,1,
-  0,2,2,2,1,2,1,2,2,2,2,2,2,2,2,2,0,2,2,2,2,2,1,2,2,2,2,2,2,2,2,2,
-  2,0,2,0,2,2,2,2,2,2,2,2,2,2,2,2,2,0,0,2,2,1,2,1,0,2,2,2,1,1,1,1,
-  2,0,2,0,2,1,2,2,0,2,0,2,2,2,1,2,2,2,2,2,2,2,2,2,2,2,0,2,2,1,2,2,
-  2,0,2,2,2,2,2,2,2,0,2,2,2,2,2,2,2,0,2,0,2,2,2,2,0,0,0,0,2,1,2,1,
-  2,2,2,2,2,2,2,0,2,2,2,2,2,2,2,0,2,2,2,2,2,1,2,0,0,2,2,2,1,2,2,2,
-  0,0,2,0,2,2,2,2,0,2,0,2,2,0,2,0,1,1,1,2,2,2,2,2,2,2,2,2,2,1,1,1,
-  2,2,2,2,2,2,2,2,2,0,2,2,2,2,2,1,2,2,2,2,2,2,2,2,2,0,2,0,2,2,2,1,
-  2,2,0,0,2,2,2,2,2,2,2,0,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,
-  2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,1,1,1,1,2,2,2,2,1,1,1,1,
-  0,2,2,2,1,2,1,2,2,2,2,2,2,2,2,2,0,2,2,2,2,2,1,2,2,2,2,2,2,2,2,2,
-  2,0,0,2,2,2,2,2,0,2,0,2,2,2,2,2,1,0,1,2,2,2,2,1,0,2,2,2,1,1,1,1,
-  2,2,2,2,2,2,2,2,2,2,0,2,2,0,2,0,2,1,2,2,2,2,2,2,2,2,0,2,2,1,2,2,
-  0,2,0,0,1,1,1,1,0,2,2,2,1,1,1,1,2,2,2,2,2,2,2,2,2,0,2,2,1,2,1,1,
-  2,2,0,2,2,1,2,2,2,2,2,2,1,2,2,2,2,0,2,2,2,2,2,2,0,2,0,2,1,2,1,1,
-  2,0,2,0,2,2,2,2,0,2,0,2,2,1,2,2,2,2,2,2,2,2,2,2,2,1,2,2,2,2,2,1,
-  2,2,2,2,2,2,2,2,2,0,2,2,2,2,2,1,2,2,2,2,2,2,2,2,2,2,2,0,2,2,2,1,
-  0,2,2,2,1,2,2,2,2,2,2,2,2,2,2,2,0,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,
-  0,2,2,2,2,0,2,0,2,2,2,2,0,0,0,0,2,2,2,2,2,1,1,2,2,2,2,2,1,2,2,2,
-  2,0,2,2,2,1,2,1,0,2,2,2,2,2,1,2,2,0,2,0,2,2,2,2,0,2,0,2,2,1,2,2,
-  0,2,0,0,2,2,2,2,1,2,2,2,2,2,2,0,2,1,2,2,2,2,2,2,1,2,2,2,2,2,2,2,
-  0,2,0,2,2,2,1,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,2,2,2,2,1,0,2,2,
-  0,0,0,2,2,1,1,1,2,2,2,2,1,2,2,2,2,0,2,0,2,2,2,1,2,2,2,2,1,2,1,2,
-  0,0,0,0,2,2,2,2,2,2,0,2,2,1,2,2,2,1,2,1,2,2,2,2,1,2,1,2,0,2,2,2,
-  2,0,2,0,2,2,2,2,2,0,2,2,2,2,2,1,2,2,2,2,2,2,2,2,2,2,2,0,2,2,2,1,
-  0,2,2,2,1,2,1,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,
-  2,1,2,2,2,2,2,0,2,2,1,2,2,0,0,0,2,2,2,2,2,1,2,2,0,2,2,2,1,2,1,2,
-  2,0,2,0,2,2,2,2,0,2,0,2,2,1,2,2,0,2,0,0,2,2,2,2,2,2,2,2,2,1,2,2,
-  2,2,2,2,2,2,2,2,2,0,2,2,2,2,2,1,2,2,2,2,2,2,2,2,2,0,2,0,2,2,2,1,
-  1,2,0,2,2,1,2,1,2,2,2,2,1,2,2,2,2,0,2,0,2,2,2,2,2,0,2,2,1,1,1,1,
-  0,2,2,2,2,2,2,1,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,2,0,2,2,1,2,1,
-  2,2,0,0,2,2,2,2,2,0,2,2,2,1,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,1,1,
-  2,2,2,0,2,2,2,2,2,2,2,0,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,
-  2,2,2,2,2,2,2,2,1,2,1,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,0,2,
-  2,0,2,0,2,2,2,2,2,1,1,2,2,2,2,2,2,2,2,2,2,2,2,1,0,2,0,2,2,2,1,2,
-  2,0,2,0,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,2,2,2,1,2,2,
-  2,0,2,0,2,2,2,2,2,0,2,0,2,2,2,2,2,0,2,0,2,2,2,2,0,0,0,0,2,1,2,1,
-  2,2,2,2,2,1,2,1,0,2,0,2,2,2,2,2,2,0,2,0,2,2,2,2,0,2,0,2,2,2,2,1,
-  2,0,2,0,2,2,2,2,2,1,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,2,2,2,1,2,0,
-  2,0,2,0,2,2,2,1,2,2,2,0,2,2,2,1,2,0,2,0,2,2,2,2,0,0,0,2,2,2,2,1,
-  2,0,2,0,2,2,2,2,2,2,2,0,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,2,2,2,2,
-  /* phase 3: offset=2816 */
-  2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,2,2,2,1,2,2,2,2,2,2,2,2,2,2,2,
-  2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,0,0,0,1,1,1,1,0,0,0,0,1,1,1,1,
-  0,2,2,2,1,2,2,2,2,2,2,2,2,2,2,2,2,1,2,1,2,0,2,0,1,2,1,2,0,2,0,2,
-  2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,
-  2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,
-  2,2,0,2,2,2,1,2,0,2,2,2,1,2,2,2,2,0,2,0,2,1,2,1,0,0,0,0,1,1,1,1,
-  2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,2,2,2,1,2,2,0,2,2,2,1,2,
-  2,2,2,1,2,2,2,0,1,1,1,1,0,0,0,0,2,2,2,2,2,2,2,2,2,0,2,0,2,1,2,1,
-  2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,2,2,2,1,2,2,0,0,0,0,1,1,1,1,
-  2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,2,0,2,1,2,1,0,0,0,0,1,1,1,1,
-  2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,1,2,1,2,0,2,0,2,
-  2,2,0,2,2,2,1,2,2,2,2,2,2,2,2,2,2,0,2,0,2,1,2,1,2,0,2,0,2,1,2,1,
-  2,0,0,0,2,1,1,1,0,0,0,0,1,1,1,1,2,2,2,0,2,2,2,1,2,2,2,2,2,2,2,2,
-  2,0,2,2,2,1,2,2,2,2,0,2,2,2,1,2,2,2,2,2,2,2,2,2,0,0,2,0,1,1,2,1,
-  2,2,2,0,2,2,2,1,2,1,2,2,2,0,2,2,2,2,2,2,2,2,2,2,2,0,2,2,2,1,2,2,
-  2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,2,2,2,1,
-  2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,
-  2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,0,0,0,1,1,1,1,0,0,0,0,1,1,1,1,
-  0,0,0,0,1,1,1,1,0,0,0,0,1,1,1,1,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,
-  0,0,0,0,1,1,1,1,0,0,0,0,1,1,1,1,2,0,2,0,2,1,2,1,0,0,0,0,1,1,1,1,
-  2,0,0,2,2,1,1,2,2,2,2,2,2,2,2,2,2,1,2,1,2,0,2,0,2,1,1,1,2,0,0,0,
-  2,1,2,1,2,0,2,0,1,2,1,2,0,2,0,2,2,2,2,0,2,2,2,1,2,0,2,0,2,1,2,1,
-  2,0,2,0,2,1,2,1,0,0,0,0,1,1,1,1,2,2,2,2,2,2,2,2,2,0,2,0,2,1,2,1,
-  2,2,2,2,2,2,2,2,2,0,0,0,2,1,1,1,2,2,2,2,2,2,2,2,2,0,2,0,2,1,2,1,
-  2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,2,2,2,1,2,2,2,2,2,2,2,2,2,
-  0,2,2,2,1,2,2,2,2,2,2,2,2,2,2,2,2,2,0,2,2,2,1,2,2,2,2,2,2,2,2,2,
-  2,0,0,0,2,1,1,1,0,0,0,0,1,1,1,1,2,0,2,0,2,1,2,1,0,0,2,0,1,1,2,1,
-  2,2,1,2,2,2,0,2,2,2,2,2,2,2,2,2,2,2,2,0,2,2,2,1,2,0,0,0,2,1,1,1,
-  2,2,2,1,2,2,2,0,2,1,1,1,2,0,0,0,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,
-  2,2,2,0,2,2,2,1,2,2,2,2,2,2,2,2,2,1,2,1,2,0,2,0,1,2,1,2,0,2,0,2,
-  2,2,2,2,2,2,2,2,2,2,2,0,2,2,2,1,2,2,2,2,2,2,2,2,2,2,2,0,2,2,2,1,
-  2,2,2,2,2,2,2,2,2,0,2,2,2,1,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,
-  2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,
-  0,2,2,2,1,2,2,2,2,2,2,2,2,2,2,2,2,0,0,0,2,1,1,1,0,0,0,0,1,1,1,1,
-  2,0,2,2,2,1,2,2,0,0,2,0,1,1,2,1,2,1,2,1,2,0,2,0,2,2,2,2,2,2,2,2,
-  2,2,0,2,2,2,1,2,2,2,2,2,2,2,2,2,2,0,2,2,2,1,2,2,0,0,0,0,1,1,1,1,
-  2,0,0,0,2,1,1,1,0,0,0,0,1,1,1,1,2,2,2,2,2,2,2,2,2,1,0,2,2,0,1,2,
-  2,2,2,1,2,2,2,0,2,1,1,1,2,0,0,0,2,2,2,2,2,2,2,2,2,2,2,0,2,2,2,1,
-  2,2,2,2,2,2,2,2,2,2,0,2,2,2,1,2,2,2,2,2,2,2,2,2,2,0,2,2,2,1,2,2,
-  2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,2,2,2,1,
-  0,2,2,2,1,2,2,2,2,2,2,2,2,2,2,2,2,1,2,2,2,0,2,2,2,2,2,2,2,2,2,2,
-  2,1,2,1,2,0,2,0,1,2,1,1,0,2,0,0,0,0,2,1,1,1,2,0,0,0,0,0,1,1,1,1,
-  2,2,2,2,2,2,2,2,1,2,2,2,0,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,
-  2,0,2,1,2,1,2,0,0,2,2,2,1,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,
-  2,2,2,0,2,2,2,1,2,2,0,2,2,2,1,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,
-  2,2,2,2,2,2,2,2,2,1,2,2,2,0,2,2,2,2,0,2,2,2,1,2,2,2,0,0,2,2,1,1,
-  2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,2,2,2,1,
-  2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,
-  2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,2,2,2,1,2,2,2,2,2,2,2,2,2,
-  0,2,2,2,1,2,2,2,2,2,2,2,2,2,2,2,2,2,1,2,2,2,0,2,2,2,2,2,2,2,2,2,
-  2,0,2,0,2,1,2,1,0,0,0,0,1,1,1,1,2,2,2,2,2,2,2,2,0,0,0,0,1,1,1,1,
-  2,2,0,2,2,2,1,2,2,2,2,2,2,2,2,2,2,2,2,0,2,2,2,1,2,0,0,0,2,1,1,1,
-  2,2,2,0,2,2,2,1,0,2,2,2,1,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,
-  2,2,2,2,2,2,2,2,2,2,0,2,2,2,1,2,2,2,2,2,2,2,2,2,2,0,2,2,2,1,2,2,
-  2,0,2,2,2,1,2,2,2,0,2,0,2,1,2,1,2,2,2,2,2,2,2,2,2,2,2,0,2,2,2,1,
-  2,1,2,1,2,0,2,0,1,2,1,2,0,2,0,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,
-  2,1,2,1,2,0,2,0,1,2,1,1,0,2,0,0,2,0,2,2,2,1,2,2,0,2,1,2,1,2,0,2,
-  2,2,2,1,2,2,2,0,2,2,1,2,2,2,0,2,2,1,2,2,2,0,2,2,2,2,0,2,2,2,1,2,
-  0,0,2,0,1,1,2,1,0,0,1,0,1,1,0,1,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,
-  2,2,2,0,2,2,2,1,1,2,2,2,0,2,2,2,0,0,0,0,1,1,1,1,0,0,0,0,1,1,1,1,
-  2,2,2,2,2,2,2,2,2,1,2,2,2,0,2,2,2,2,2,2,2,2,2,2,2,2,2,0,2,2,2,1,
-  2,2,2,2,2,2,2,2,2,0,2,2,2,1,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,
-  2,2,0,0,2,2,1,1,2,2,2,0,2,2,2,1,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,
-  2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,
-  2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,
-  2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,0,0,0,1,1,1,1,0,0,0,0,1,1,1,1,
-  2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,2,2,2,1,2,2,2,2,2,2,2,2,2,
-  0,2,2,2,1,2,2,2,2,2,2,2,2,2,2,2,2,2,1,2,2,2,0,2,2,2,2,2,2,2,2,2,
-  2,0,0,0,2,1,1,1,0,0,0,0,1,1,1,1,2,2,2,1,2,2,2,0,2,1,2,1,2,0,2,0,
-  2,1,2,2,2,0,2,2,2,2,2,2,2,2,2,2,0,2,0,0,1,2,1,1,2,0,0,0,2,1,1,1,
-  2,2,2,2,2,2,2,2,2,1,1,1,2,0,0,0,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,
-  2,2,2,0,2,2,2,1,2,2,0,2,2,2,1,2,2,1,2,1,2,0,2,0,2,0,2,2,2,1,2,2,
-  2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,1,2,2,2,0,2,2,2,1,1,1,2,0,0,0,
-  2,2,2,2,2,2,2,2,2,0,2,2,2,1,2,2,2,2,2,2,2,2,2,2,0,2,0,0,1,2,1,1,
-  2,2,0,2,2,2,1,2,2,2,2,2,2,2,2,2,2,0,2,2,2,1,2,2,0,2,2,2,1,2,2,2,
-  2,1,2,1,2,0,2,0,2,1,2,2,2,0,2,2,2,2,2,0,2,2,2,1,2,0,2,0,2,1,2,1,
-  2,0,2,0,2,1,2,1,0,2,0,2,1,2,1,2,2,2,2,2,2,2,2,2,2,0,2,2,2,1,2,2,
-  2,2,2,2,2,2,2,2,0,2,0,2,1,2,1,2,2,2,2,2,2,2,2,2,0,1,0,0,1,0,1,1,
-  2,2,2,2,2,2,2,2,2,1,2,2,2,0,2,2,2,2,2,2,2,2,2,2,2,2,2,0,2,2,2,1,
-  2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,
-  2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,
-  0,2,2,2,1,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,
-  0,0,0,0,1,1,1,1,0,0,0,0,1,1,1,1,2,2,1,2,2,2,0,2,2,2,2,2,2,2,2,2,
-  2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,1,2,2,1,0,2,0,2,2,2,1,2,2,2,
-  2,2,2,2,2,2,2,2,1,2,2,2,0,2,2,2,2,2,2,0,2,2,2,1,2,2,0,2,2,2,1,2,
-  2,0,2,0,2,1,2,1,0,2,0,2,1,2,1,2,2,2,2,2,2,2,2,2,2,0,2,2,2,1,2,2,
-  0,2,0,0,1,2,1,1,2,0,0,0,2,1,1,1,2,2,2,2,2,2,2,2,1,0,1,2,0,1,0,2,
-  2,2,2,2,2,2,2,2,2,0,2,2,2,1,2,2,2,1,2,2,2,0,2,2,1,1,2,2,0,0,2,2,
-  0,2,2,2,1,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,
-  2,1,2,1,2,0,2,0,2,1,2,2,2,0,2,2,2,0,2,2,2,1,2,2,0,2,2,2,1,2,2,2,
-  0,2,2,2,1,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,2,2,2,1,1,2,2,2,0,2,2,2,
-  2,0,2,2,2,1,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,2,0,2,1,2,1,2,
-  0,0,0,0,1,1,1,1,2,2,0,2,2,2,1,2,2,2,2,2,2,2,2,2,2,0,2,2,2,1,2,2,
-  2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,1,2,1,2,0,2,0,2,2,0,2,2,2,1,2,
-  2,0,2,0,2,1,2,1,2,0,2,2,2,1,2,2,2,2,2,2,2,2,2,2,2,2,2,0,2,2,2,1,
-  2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,
-  2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,2,2,2,1,2,2,2,2,2,2,2,2,2,
-  0,2,2,2,1,2,2,2,2,2,2,2,2,2,2,2,0,2,2,2,1,2,2,2,2,2,2,2,2,2,2,2,
-  2,2,2,1,2,2,2,0,1,1,2,1,0,0,2,0,2,0,2,2,2,1,2,2,0,2,2,2,1,2,2,2,
-  2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,1,2,2,2,0,2,2,2,2,0,2,2,2,1,2,
-  2,0,2,0,2,1,2,1,0,2,0,2,1,2,1,2,2,2,2,2,2,2,2,2,2,1,2,2,2,0,2,2,
-  0,2,0,0,1,2,1,1,0,2,0,2,1,2,1,2,2,2,2,2,2,2,2,2,0,0,0,2,1,1,1,2,
-  2,2,2,2,2,2,2,2,2,0,2,2,2,1,2,2,2,2,2,2,2,2,2,2,2,2,2,0,2,2,2,1,
-  2,2,2,2,2,2,2,2,2,0,2,2,2,1,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,
-  2,2,0,2,2,2,1,2,2,2,2,2,2,2,2,2,0,0,2,1,1,1,2,0,0,2,2,2,1,2,2,2,
-  2,1,2,1,2,0,2,0,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,2,0,0,1,2,1,1,
-  0,0,2,2,1,1,2,2,0,2,1,2,1,2,0,2,2,1,2,1,2,0,2,0,1,2,1,2,0,2,0,2,
-  2,2,2,2,2,2,2,2,1,2,1,2,0,2,0,2,2,2,2,2,2,2,2,2,2,0,2,0,2,1,2,1,
-  2,2,0,0,2,2,1,1,2,2,0,0,2,2,1,1,2,2,2,2,2,2,2,2,2,2,0,0,2,2,1,1,
-  2,2,2,2,2,2,2,2,0,2,2,2,1,2,2,2,2,2,2,2,2,2,2,2,0,2,0,0,1,2,1,1,
-  2,2,2,0,2,2,2,1,2,2,2,0,2,2,2,1,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,
-  2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,
-  2,2,2,2,2,2,2,2,2,0,2,2,2,1,2,2,2,2,2,2,2,2,2,2,1,1,1,2,0,0,0,2,
-  2,2,2,2,2,2,2,2,1,1,1,2,0,0,0,2,2,2,2,2,2,2,2,2,0,2,2,2,1,2,2,2,
-  2,0,2,0,2,1,2,1,2,2,2,0,2,2,2,1,2,2,2,2,2,2,2,2,2,0,0,0,2,1,1,1,
-  2,0,2,2,2,1,2,2,0,2,2,2,1,2,2,2,2,0,2,0,2,1,2,1,2,2,2,2,2,2,2,2,
-  2,0,2,0,2,1,2,1,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,
-  2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,
-  2,0,2,0,2,1,2,1,2,1,2,0,2,0,2,1,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,
-  2,0,2,0,2,1,2,1,1,2,1,2,0,2,0,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,
-  2,2,2,2,2,2,2,2,1,2,1,2,0,2,0,2,2,1,2,1,2,0,2,0,2,2,2,2,2,2,2,2,
-  2,0,2,1,2,1,2,0,0,2,1,2,1,2,0,2,2,2,2,2,2,2,2,2,2,2,2,0,2,2,2,1,
-  2,0,2,0,2,1,2,1,2,2,2,0,2,2,2,1,2,2,2,2,2,2,2,2,2,0,2,0,2,1,2,1,
-  2,2,2,2,2,2,2,2,2,2,2,0,2,2,2,1,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,
-  2,0,2,2,2,1,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,
-  2,1,2,1,2,0,2,0,1,1,1,2,0,0,0,2,2,2,2,2,2,2,2,2,2,2,2,0,2,2,2,1,
-  2,0,2,0,2,1,2,1,2,2,2,0,2,2,2,1,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,
-  2,2,2,2,2,2,2,2,2,2,2,0,2,2,2,1,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,
-};
diff --git a/converter/other/jbig/jbigtopnm.c b/converter/other/jbig/jbigtopnm.c
index 7a6e95c1..733ba227 100644
--- a/converter/other/jbig/jbigtopnm.c
+++ b/converter/other/jbig/jbigtopnm.c
@@ -231,7 +231,7 @@ int main (int argc, char **argv)
         pm_error("Problem while reading input file '%s", fnin);
     if (result != JBG_EOK && result != JBG_EOK_INTR) 
         pm_error("Problem with input file '%s': %s\n", 
-                 fnin, jbg_strerror(result, JBG_EN));
+                 fnin, jbg_strerror(result));
     if (plane >= 0 && jbg_dec_getplanes(&s) <= plane) 
         pm_error("Image has only %d planes!\n", jbg_dec_getplanes(&s));
 
diff --git a/converter/other/jbig/libjbig/ANNOUNCE b/converter/other/jbig/libjbig/ANNOUNCE
new file mode 100644
index 00000000..15ce550d
--- /dev/null
+++ b/converter/other/jbig/libjbig/ANNOUNCE
@@ -0,0 +1,172 @@
+
+JBIG-KIT lossless image compression library
+-------------------------------------------
+
+by Markus Kuhn
+
+
+The latest release of JBIG-KIT can be downloaded from
+
+  http://www.cl.cam.ac.uk/~mgk25/jbigkit/
+
+JBIG-KIT implements a highly effective data compression algorithm for
+bi-level high-resolution images such as fax pages or scanned
+documents.
+
+JBIG-KIT provides two variants of a portable library of compression
+and decompression functions with a documented interface. You can very
+easily include into your image or document processing software. In
+addition, JBIG-KIT provides ready-to-use compression and decompression
+programs with a simple command line interface (similar to the
+converters found in Jef Poskanzer's PBM graphics file conversion
+package).
+
+JBIG-KIT implements the specification
+
+  International Standard ISO/IEC 11544:1993 and ITU-T Recommendation
+  T.82(1993), "Information technology - Coded representation of picture
+  and audio information - progressive bi-level image compression",
+  <http://www.itu.int/rec/T-REC-T.82>,
+
+which is commonly referred to as the "JBIG1 standard". JBIG (Joint
+Bi-level Image experts Group) is the committee which developed this
+international standard for the lossless compression of images using
+arithmetic coding. Like the well-known compression algorithms JPEG and
+MPEG, JBIG has also been developed and published by the International
+Organization for Standardization (ISO) and the International
+Telecommunication Union (ITU). See also
+
+  http://www.jpeg.org/jbig/
+  http://www.iso.ch/
+  http://www.itu.int/
+
+The JBIG compression algorithm offers the following features:
+
+  - Close to state-of-the-art lossless compression ratio for high
+    resolution bi-level images.
+
+  - About 1.1 to 1.5 times better compression ratio on typical
+    scanned documents compared to G4 fax compression (ITU-T T.6),
+    which has been the best compression algorithm for scanned
+    documents available prior to JBIG.
+
+  - Up to 30 times better compression of scanned images with dithered
+    images compared to G4 fax compression.
+
+  - About 2 times better compression on typical 300 dpi documents
+    compared to 'gzip -9' on raw bitmaps.
+    
+  - About 3-4 times better compression than GIF on typical 300 dpi
+    documents.
+
+  - Even much better competitive compression results on computer
+    generated images which are free of scanning distortions.
+
+  - JBIG supports hierarchical "progressive" encoding, that means it is
+    possible to encode a low resolution image first, followed by
+    resolution enhancement data. This allows, for instance, a document
+    browser to display already a good 75 dpi low resolution version of
+    an image, while the data necessary to reconstruct the full 300 dpi
+    version for laser printer reproduction is still arriving (say
+    over a slow network link or mass storage medium).
+
+  - The various resolution layers of a JBIG image in progressive
+    encoding mode together require not much more space than a
+    normal non-progressive mode encoded image (which JBIG also
+    supports).
+
+  - The progressive encoding mode utilizes a quite sophisticated
+    resolution reduction algorithm which offers high quality low
+    resolution versions that preserve the shape of characters as well
+    as the integrity of thin lines and dithered images.
+
+  - JBIG supports multiple bit planes and can this way also be used
+    for grayscale and color images, although the main field of
+    application is compression of bi-level images, i.e. images with
+    only two different pixel values. For grayscale images with up to
+    6 bit per pixel, JBIG performs superior to JPEG's lossless
+    mode.
+
+JBIG-KIT can be used as free software under the GNU General Public
+License. Other license arrangements more suitable for commercial
+applications are available as well, please contact the author for
+details. JBIG-KIT provides two portable libraries implemented in
+ANSI/ISO C for encoding and decoding JBIG data streams, along with
+documentation. The first library, jbig.c, implements nearly all of the
+options that the JBIG standard provides, but keeps the entire
+uncompressed image in memory. The second library, jbig85.c, implements
+only the ITU-R T.85 subset of the standard that black/white fax
+machines use (single bit per pixel, no "progressive" encoding), and
+keeps only three lines of the uncompressed image in memory, making it
+particularly attractive for low-memory embedded applications.
+
+The libraries are not intended for 8-bit or 16-bit machine
+architectures (e.g., old MS-DOS C compilers). For maximum performance,
+a 32-bit processor is required (64-bit systems work too, of course).
+On architectures with 16-bit pointer arithmetic, the full-featured
+jbig.c library can process only very small images.
+
+Special features of the full-featured jbig.c variant:
+
+  - Fully reentrant multithread-capable design (no global or static
+    variables, isolated malloc()/free() calls, etc.)
+
+  - Capable of handling incomplete and growing JBIG data streams in
+    order to allow earliest display of low resolution versions
+
+  - Capable of handling several incoming data streams simultaneously
+    in one single process and thread
+
+  - Especially designed with applications in mind that want to display
+    incoming data as early as possible (e.g., similar to the way in
+    which Netscape Navigator handles incoming GIF images)
+
+  - Implements all JBIG features and options including progressive and
+    sequential encoding, multiple bit planes, user specified
+    resolution reduction and deterministic prediction tables, adaptive
+    template changes for optimal performance on half-tone images,
+    deterministic prediction, typical prediction in lowest and
+    differential layers, various stripe orderings, etc; only the SEQ
+    and HITOLO options are currently not supported by the decoder
+    (they are normally never required, but could be added later in
+    case of user requirements)
+
+  - Suitable for fax applications, satisfies ITU-T T.85 profile
+
+  - Efficient code, optimized utilization of 32-bit processor
+    registers
+
+  - Very easy to use documented C library interface
+
+  - Included Gray code conversion routines for efficient encoding
+    of grayscale images
+
+  - Ready-to-use pbmtojbg and jbgtopbm converters.
+
+Special features of the light-weight jbig85.c variant:
+
+  - Suitable for low-memory embedded applications
+
+  - Implements only the JBIG1 subset defined in the ITU-T T.85
+    profile (single bit plane, no differential layers)
+
+  - Requires only three pixel rows of the uncompressed image to be
+    kept in memory
+
+  - Handles all NEWLEN modes of operation required by ITU-T T.85 with
+    just a single pass over the data, automatically performing the
+    necessary lookahead after the last stripe
+
+  - Codec buffers only a few bytes of arithmetic-codec data and outputs
+    resulting bytes or lines as soon as they are available.
+
+I will try to provide free support and maintenance for this software
+for the foreseeable future, depending on my available time.
+
+Happy compressing ...
+
+Markus Kuhn
+
+--
+Markus Kuhn, Computer Laboratory, University of Cambridge
+http://www.cl.cam.ac.uk/~mgk25/ || CB3 0FD, Great Britain
diff --git a/converter/other/jbig/libjbig/COPYING b/converter/other/jbig/libjbig/COPYING
new file mode 100644
index 00000000..a43ea212
--- /dev/null
+++ b/converter/other/jbig/libjbig/COPYING
@@ -0,0 +1,339 @@
+		    GNU GENERAL PUBLIC LICENSE
+		       Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+                          675 Mass Ave, Cambridge, MA 02139, USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+			    Preamble
+
+  The licenses for most software are designed to take away your
+freedom to share and change it.  By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users.  This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it.  (Some other Free Software Foundation software is covered by
+the GNU Library General Public License instead.)  You can apply it to
+your programs, too.
+
+  When we speak of free software, we are referring to freedom, not
+price.  Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+  To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+  For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have.  You must make sure that they, too, receive or can get the
+source code.  And you must show them these terms so they know their
+rights.
+
+  We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+  Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software.  If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+  Finally, any free program is threatened constantly by software
+patents.  We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary.  To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.
+
+		    GNU GENERAL PUBLIC LICENSE
+   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+  0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License.  The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language.  (Hereinafter, translation is included without limitation in
+the term "modification".)  Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope.  The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+  1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+  2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+    a) You must cause the modified files to carry prominent notices
+    stating that you changed the files and the date of any change.
+
+    b) You must cause any work that you distribute or publish, that in
+    whole or in part contains or is derived from the Program or any
+    part thereof, to be licensed as a whole at no charge to all third
+    parties under the terms of this License.
+
+    c) If the modified program normally reads commands interactively
+    when run, you must cause it, when started running for such
+    interactive use in the most ordinary way, to print or display an
+    announcement including an appropriate copyright notice and a
+    notice that there is no warranty (or else, saying that you provide
+    a warranty) and that users may redistribute the program under
+    these conditions, and telling the user how to view a copy of this
+    License.  (Exception: if the Program itself is interactive but
+    does not normally print such an announcement, your work based on
+    the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole.  If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works.  But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+  3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+    a) Accompany it with the complete corresponding machine-readable
+    source code, which must be distributed under the terms of Sections
+    1 and 2 above on a medium customarily used for software interchange; or,
+
+    b) Accompany it with a written offer, valid for at least three
+    years, to give any third party, for a charge no more than your
+    cost of physically performing source distribution, a complete
+    machine-readable copy of the corresponding source code, to be
+    distributed under the terms of Sections 1 and 2 above on a medium
+    customarily used for software interchange; or,
+
+    c) Accompany it with the information you received as to the offer
+    to distribute corresponding source code.  (This alternative is
+    allowed only for noncommercial distribution and only if you
+    received the program in object code or executable form with such
+    an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it.  For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable.  However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+  4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License.  Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+  5. You are not required to accept this License, since you have not
+signed it.  However, nothing else grants you permission to modify or
+distribute the Program or its derivative works.  These actions are
+prohibited by law if you do not accept this License.  Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+  6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions.  You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+  7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License.  If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all.  For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices.  Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+  8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded.  In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+  9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time.  Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number.  If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation.  If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+  10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission.  For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this.  Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+			    NO WARRANTY
+
+  11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW.  EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.  THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU.  SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+  12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+		     END OF TERMS AND CONDITIONS
+
+	Appendix: How to Apply These Terms to Your New Programs
+
+  If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+  To do so, attach the following notices to the program.  It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+    <one line to give the program's name and a brief idea of what it does.>
+    Copyright (C) 19yy  <name of author>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+    Gnomovision version 69, Copyright (C) 19yy name of author
+    Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+    This is free software, and you are welcome to redistribute it
+    under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License.  Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary.  Here is a sample; alter the names:
+
+  Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+  `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+  <signature of Ty Coon>, 1 April 1989
+  Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs.  If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library.  If this is what you want to do, use the GNU Library General
+Public License instead of this License.
diff --git a/converter/other/jbig/libjbig/Makefile b/converter/other/jbig/libjbig/Makefile
new file mode 100644
index 00000000..2e574903
--- /dev/null
+++ b/converter/other/jbig/libjbig/Makefile
@@ -0,0 +1,24 @@
+ifeq ($(SRCDIR)x,x)
+  SRCDIR = $(CURDIR)/../../../..
+  BUILDDIR = $(SRCDIR)
+endif
+SUBDIR = converter/other/jbig/libjbig
+VPATH=.:$(SRCDIR)/$(SUBDIR)
+
+include $(BUILDDIR)/config.mk
+
+LIBJBIG_OBJECTS = jbig.o jbig_ar.o
+
+OBJECTS = $(LIBJBIG_OBJECTS)
+MERGE_OBJECTS = $(LIBJBIG_OBJECTS)
+
+COMP_INCLUDES = -I$(SRCDIR)/$(SUBDIR)/include
+
+all: libjbig.a
+
+include $(SRCDIR)/common.mk
+
+libjbig.a: $(LIBJBIG_OBJECTS)
+	$(AR) -rc $@ $^
+	$(RANLIB) $@
+
diff --git a/converter/other/jbig/jbig.h b/converter/other/jbig/libjbig/include/jbig.h
index dd9a76f3..67994107 100644
--- a/converter/other/jbig/jbig.h
+++ b/converter/other/jbig/libjbig/include/jbig.h
@@ -1,21 +1,32 @@
 /*
- *  Header file for the portable free JBIG compression library
+ *  Header file for the portable JBIG compression library
  *
- *  Markus Kuhn -- mkuhn@acm.org
- *
- *  $Id: jbig.h,v 1.9 1999-11-16 15:58:45+00 mgk25 Rel $
+ *  Copyright 1995-2014 -- Markus Kuhn -- http://www.cl.cam.ac.uk/~mgk25/
  */
 
 #ifndef JBG_H
 #define JBG_H
 
 #include <stddef.h>
+#include "jbig_ar.h"
 
 /*
  * JBIG-KIT version number
  */
 
-#define JBG_VERSION    "1.1"
+#define JBG_VERSION    "2.1"
+#define JBG_VERSION_MAJOR 2
+#define JBG_VERSION_MINOR 1
+
+/*
+ * JBIG-KIT licence agreement reference code:
+ * If you use JBIG-KIT under a commercial licence, please replace
+ * below the letters GPL with the reference code that you received
+ * with your licence agreement. (This code is typically a letter "A"
+ * followed by four decimal digits, e.g. "A1234".)
+ */
+
+#define JBG_LICENCE    "GPL"
 
 /*
  * Buffer block for SDEs which are temporarily stored by encoder
@@ -34,7 +45,7 @@ struct jbg_buf {
 };
 
 /*
- * Maximum number of allowed ATMOVEs per stripe
+ * Maximum number of ATMOVEs per stripe that decoder can handle
  */
 
 #define JBG_ATMOVES_MAX  64
@@ -56,82 +67,30 @@ struct jbg_buf {
 #define JBG_DPPRIV     0x02
 #define JBG_DPLAST     0x01
 
-#define JBG_DELAY_AT   0x100  /* delay ATMOVE until the first line of the next
+/* encoding options that will not be indicated in the header */
+
+#define JBG_DELAY_AT   0x100  /* Delay ATMOVE until the first line of the next
 			       * stripe. Option available for compatibility
-			       * with conformance test example in clause 7.2.*/
+			       * with conformance test example in clause 7.2. */
 
+#define JBG_SDRST      0x200  /* Use SDRST instead of SDNORM. This option is
+			       * there for anyone who needs to generate
+			       * test data that covers the SDRST cases. */
 
 /*
  * Possible error code return values
  */
 
-#define JBG_EOK        0
-#define JBG_EOK_INTR   1
-#define JBG_EAGAIN     2
-#define JBG_ENOMEM     3
-#define JBG_EABORT     4
-#define JBG_EMARKER    5
-#define JBG_ENOCONT    6
-#define JBG_EINVAL     7
-#define JBG_EIMPL      8
-
-/*
- * Language code for error message strings (based on ISO 639 2-letter
- * standard language name abbreviations).
- */ 
-
-#define JBG_EN         0        /* English */
-#define JBG_DE_8859_1  1        /* German in ISO Latin 1 character set */
-#define JBG_DE_UTF_8   2        /* German in Unicode UTF-8 encoding */
-
-/*
- * Status description of an arithmetic encoder
- */
-
-struct jbg_arenc_state {
-  unsigned char st[4096];    /* probability status for contexts, MSB = MPS */
-  unsigned long c;                /* C register, base of coding intervall, *
-                                   * layout as in Table 23                 */
-  unsigned long a;      /* A register, normalized size of coding intervall */
-  long sc;        /* counter for buffered 0xff values which might overflow */
-  int ct;  /* bit shift counter, determines when next byte will be written */
-  int buffer;                /* buffer for most recent output byte != 0xff */
-  void (*byte_out)(int, void *); /* function which receives all PSCD bytes */
-  void *file;                              /* parameter passed to byte_out */
-};
-
-
-/*
- * Status description of an arithmetic decoder
- */
-
-struct jbg_ardec_state {
-  unsigned char st[4096];    /* probability status for contexts, MSB = MPS */
-  unsigned long c;                /* C register, base of coding intervall, *
-                                   * layout as in Table 25                 */
-  unsigned long a;      /* A register, normalized size of coding intervall */
-  int ct;     /* bit shift counter, determines when next byte will be read */
-  unsigned char *pscd_ptr;               /* pointer to next PSCD data byte */
-  unsigned char *pscd_end;                   /* pointer to byte after PSCD */
-  enum {
-    JBG_OK,                        /* symbol has been successfully decoded */
-    JBG_READY,             /* no more bytes of this PSCD required, marker  *
-		            * encountered, probably more symbols available */
-    JBG_MORE,          /* more PSCD data bytes required to decode a symbol */
-    JBG_MARKER   /* more PSCD data bytes required, ignored final 0xff byte */
-  } result;                              /* result of previous decode call */
-  int startup;                            /* controls initial fill of s->c */
-};
-
-#ifdef TEST_CODEC
-void arith_encode_init(struct jbg_arenc_state *s, int reuse_st);
-void arith_encode_flush(struct jbg_arenc_state *s);
-void arith_encode(struct jbg_arenc_state *s, int cx, int pix);
-void arith_decode_init(struct jbg_ardec_state *s, int reuse_st);
-int arith_decode(struct jbg_ardec_state *s, int cx);
-#endif
+#define JBG_EOK        (0 << 4)
+#define JBG_EOK_INTR   (1 << 4)
+#define JBG_EAGAIN     (2 << 4)
+#define JBG_ENOMEM     (3 << 4)
+#define JBG_EABORT     (4 << 4)
+#define JBG_EMARKER    (5 << 4)
+#define JBG_EINVAL     (6 << 4)
+#define JBG_EIMPL      (7 << 4)
+#define JBG_ENOCONT    (8 << 4)
 
- 
 /*
  * Status of a JBIG encoder
  */
@@ -139,6 +98,8 @@ int arith_decode(struct jbg_ardec_state *s, int cx);
 struct jbg_enc_state {
   int d;                            /* resolution layer of the input image */
   unsigned long xd, yd;    /* size of the input image (resolution layer d) */
+  unsigned long yd1;    /* BIH announced height of image, use yd1 != yd to
+                        emulate T.85-style NEWLEN height updates for tests */
   int planes;                         /* number of different bitmap planes */
   int dl;                       /* lowest resolution layer in the next BIE */
   int dh;                      /* highest resolution layer in the next BIE */
@@ -161,6 +122,10 @@ struct jbg_enc_state {
                                                     /* data write callback */
   void *file;                            /* parameter passed to data_out() */
   char *tp;    /* buffer for temp. values used by diff. typical prediction */
+  unsigned char *comment; /* content of comment marker segment to be added
+                             at next opportunity (will be reset to NULL
+                             as soon as comment has been written)          */
+  unsigned long comment_len;       /* length of data pointed to by comment */
 };
 
 
@@ -236,7 +201,7 @@ int jbg_enc_lrlmax(struct jbg_enc_state *s, unsigned long mwidth,
 void jbg_enc_layers(struct jbg_enc_state *s, int d);
 int  jbg_enc_lrange(struct jbg_enc_state *s, int dl, int dh);
 void jbg_enc_options(struct jbg_enc_state *s, int order, int options,
-		     long l0, int mx, int my);
+		     unsigned long l0, int mx, int my);
 void jbg_enc_out(struct jbg_enc_state *s);
 void jbg_enc_free(struct jbg_enc_state *s);
 
@@ -245,17 +210,17 @@ void jbg_dec_maxsize(struct jbg_dec_state *s, unsigned long xmax,
 		     unsigned long ymax);
 int  jbg_dec_in(struct jbg_dec_state *s, unsigned char *data, size_t len,
 		size_t *cnt);
-long jbg_dec_getwidth(const struct jbg_dec_state *s);
-long jbg_dec_getheight(const struct jbg_dec_state *s);
+unsigned long jbg_dec_getwidth(const struct jbg_dec_state *s);
+unsigned long jbg_dec_getheight(const struct jbg_dec_state *s);
 unsigned char *jbg_dec_getimage(const struct jbg_dec_state *s, int plane);
-long jbg_dec_getsize(const struct jbg_dec_state *s);
+unsigned long jbg_dec_getsize(const struct jbg_dec_state *s);
 void jbg_dec_merge_planes(const struct jbg_dec_state *s, int use_graycode,
 			  void (*data_out)(unsigned char *start, size_t len,
 					   void *file), void *file);
-long jbg_dec_getsize_merged(const struct jbg_dec_state *s);
+unsigned long jbg_dec_getsize_merged(const struct jbg_dec_state *s);
 void jbg_dec_free(struct jbg_dec_state *s);
 
-const char *jbg_strerror(int errnum, int language);
+const char *jbg_strerror(int errnum);
 void jbg_int2dppriv(unsigned char *dptable, const char *internal);
 void jbg_dppriv2int(char *internal, const unsigned char *dptable);
 unsigned long jbg_ceil_half(unsigned long x, int n);
@@ -263,5 +228,6 @@ void jbg_split_planes(unsigned long x, unsigned long y, int has_planes,
 		      int encode_planes,
 		      const unsigned char *src, unsigned char **dest,
 		      int use_graycode);
+int jbg_newlen(unsigned char *bie, size_t len);
 
 #endif /* JBG_H */
diff --git a/converter/other/jbig/libjbig/include/jbig_ar.h b/converter/other/jbig/libjbig/include/jbig_ar.h
new file mode 100644
index 00000000..d58b1ae0
--- /dev/null
+++ b/converter/other/jbig/libjbig/include/jbig_ar.h
@@ -0,0 +1,53 @@
+/*
+ *  Header file for the arithmetic encoder and decoder of
+ *  the portable JBIG compression library
+ *
+ *  Markus Kuhn -- http://www.cl.cam.ac.uk/~mgk25/jbigkit/
+ */
+
+#ifndef JBG_AR_H
+#define JBG_AR_H
+
+/*
+ * Status of arithmetic encoder
+ */
+
+struct jbg_arenc_state {
+  unsigned char st[4096];    /* probability status for contexts, MSB = MPS */
+  unsigned long c;                /* register C: base of coding intervall, *
+                                   * layout as in Table 23                 */
+  unsigned long a;       /* register A: normalized size of coding interval */
+  long sc;     /* number of buffered 0xff values that might still overflow */
+  int ct;  /* bit shift counter, determines when next byte will be written */
+  int buffer;                /* buffer for most recent output byte != 0xff */
+  void (*byte_out)(int, void *);  /* function that receives all PSCD bytes */
+  void *file;                              /* parameter passed to byte_out */
+};
+
+/*
+ * Status of arithmetic decoder
+ */
+
+struct jbg_ardec_state {
+  unsigned char st[4096];    /* probability status for contexts, MSB = MPS */
+  unsigned long c;                /* register C: base of coding intervall, *
+                                   * layout as in Table 25                 */
+  unsigned long a;       /* register A: normalized size of coding interval */
+  unsigned char *pscd_ptr;               /* pointer to next PSCD data byte */
+  unsigned char *pscd_end;                   /* pointer to byte after PSCD */
+  int ct;    /* bit-shift counter, determines when next byte will be read;
+              * special value -1 signals that zero-padding has started     */
+  int startup;          /* boolean flag that controls initial fill of s->c */
+  int nopadding;        /* boolean flag that triggers return -2 between
+			 * reaching PSCD end and decoding the first symbol
+			 * that might never have been encoded in the first
+			 * place */
+};
+
+void arith_encode_init(struct jbg_arenc_state *s, int reuse_st);
+void arith_encode_flush(struct jbg_arenc_state *s);
+void arith_encode(struct jbg_arenc_state *s, int cx, int pix);
+void arith_decode_init(struct jbg_ardec_state *s, int reuse_st);
+int  arith_decode(struct jbg_ardec_state *s, int cx);
+
+#endif /* JBG_AR_H */
diff --git a/converter/other/jbig/jbig.c b/converter/other/jbig/libjbig/jbig.c
index f33f80be..d7141a75 100644
--- a/converter/other/jbig/jbig.c
+++ b/converter/other/jbig/libjbig/jbig.c
@@ -1,15 +1,13 @@
 /*
- *  Portable Free JBIG image compression library
+ *  Portable JBIG image compression library
  *
- *  Markus Kuhn -- mkuhn@acm.org
- *
- *  $Id: jbig.c,v 1.12 2000-04-08 11:42:18+01 mgk25 Rel $
+ *  Copyright 1995-2014 -- Markus Kuhn -- http://www.cl.cam.ac.uk/~mgk25/
  *
  *  This module implements a portable standard C encoder and decoder
- *  using the JBIG lossless bi-level image compression algorithm as
- *  specified in International Standard ISO 11544:1993 or equivalently
- *  as specified in ITU-T Recommendation T.82. See the file jbig.doc
- *  for usage instructions and application examples.
+ *  using the JBIG1 lossless bi-level image compression algorithm
+ *  specified in International Standard ISO 11544:1993 and
+ *  ITU-T Recommendation T.82. See the file jbig.txt for usage
+ *  instructions and application examples.
  *
  *  This program is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License as published by
@@ -27,42 +25,22 @@
  * 
  *  If you want to use this program under different license conditions,
  *  then contact the author for an arrangement.
- *
- *  It is possible that certain products which can be built using this
- *  software module might form inventions protected by patent rights in
- *  some countries (e.g., by patents about arithmetic coding algorithms
- *  owned by IBM and AT&T in the USA). Provision of this software by the
- *  author does NOT include any licences for any patents. In those
- *  countries where a patent licence is required for certain applications
- *  of this software module, you will have to obtain such a licence
- *  yourself.
  */
 
 #ifdef DEBUG
 #include <stdio.h>
+#else
+#define NDEBUG
 #endif
 
 #include <stdlib.h>
+#include <string.h>
 #include <assert.h>
 
 #include "jbig.h"
 
-
-/* optional export of arithmetic coder functions for test purposes */
-#ifdef TEST_CODEC
-#define ARITH
-#define ARITH_INL
-#else
-#define ARITH      static
-#ifdef __GNUC__
-#define ARITH_INL  static __inline__
-#else
-#define ARITH_INL  static
-#endif
-#endif
-
-#define MX_MAX  23     /* maximal supported mx offset for
-			* adaptive template in the encoder */
+#define MX_MAX  127
+   /* maximal mx offset for adaptive template in the encoder */
 
 #define TPB2CX  0x195  /* contexts for TP special pixels */
 #define TPB3CX  0x0e5
@@ -91,15 +69,15 @@
 /* object code version id */
 
 const char jbg_version[] = 
-" JBIG-KIT " JBG_VERSION " -- Markus Kuhn -- "
-"$Id: jbig.c,v 1.12 2000-04-08 11:42:18+01 mgk25 Rel $ ";
+  "JBIG-KIT " JBG_VERSION " -- (c) 1995-2014 Markus Kuhn -- "
+  "Licence: " JBG_LICENCE "\n";
 
 /*
- * the following array specifies for each combination of the 3
+ * The following array specifies for each combination of the 3
  * ordering bits, which ii[] variable represents which dimension
  * of s->sde.
  */
-static const int index[8][3] = {
+static const int iindex[8][3] = {
   { 2, 1, 0 },    /* no ordering bit set */
   { -1, -1, -1},  /* SMID -> illegal combination */
   { 2, 0, 1 },    /* ILEAVE */
@@ -110,96 +88,90 @@ static const int index[8][3] = {
   { -1, -1, -1 }  /* SEQ + SMID + ILEAVE -> illegal combination */
 };
 
+#define _(String) String  /* to mark translatable string for GNU gettext */
 
 /*
- * Array [language][message] with text string error messages that correspond
+ * Array with English ASCII error messages that correspond
  * to return values from public functions in this library.
  */
-#define NEMSG         9  /* number of error codes */
-#define NEMSG_LANG    3  /* number of supported languages */
-static const char *errmsg[NEMSG_LANG][NEMSG] = {
-  /* English (JBG_EN) */
-  {
-    "Everything is ok",                                     /* JBG_EOK */
-    "Reached specified maximum size",                       /* JBG_EOK_INTR */
-    "Unexpected end of data",                               /* JBG_EAGAIN */
-    "Not enough memory available",                          /* JBG_ENOMEM */
-    "ABORT marker found",                                   /* JBG_EABORT */
-    "Unknown marker segment encountered",                   /* JBG_EMARKER */
-    "Incremental BIE does not fit to previous one",         /* JBG_ENOCONT */
-    "Invalid data encountered",                             /* JBG_EINVAL */
-    "Unimplemented features used"                           /* JBG_EIMPL */
-  },
-  /* German (JBG_DE_8859_1) */
-  {
-    "Kein Problem aufgetreten",                             /* JBG_EOK */
-    "Angegebene maximale Bildgr\366\337e erreicht",         /* JBG_EOK_INTR */
-    "Unerwartetes Ende der Daten",                          /* JBG_EAGAIN */
-    "Nicht gen\374gend Speicher vorhanden",                 /* JBG_ENOMEM */
-    "Es wurde eine Abbruch-Sequenz gefunden",               /* JBG_EABORT */
-    "Eine unbekannte Markierungssequenz wurde gefunden",    /* JBG_EMARKER */
-    "Neue Daten passen nicht zu vorangegangenen Daten",     /* JBG_ENOCONT */
-    "Es wurden ung\374ltige Daten gefunden",                /* JBG_EINVAL */
-    "Noch nicht implementierte Optionen wurden benutzt"     /* JBG_EIMPL */
-  },
-  /* German (JBG_DE_UTF_8) */
-  {
-    "Kein Problem aufgetreten",                             /* JBG_EOK */
-    "Angegebene maximale Bildgr\303\266\303\237e erreicht", /* JBG_EOK_INTR */
-    "Unerwartetes Ende der Daten",                          /* JBG_EAGAIN */
-    "Nicht gen\303\274gend Speicher vorhanden",             /* JBG_ENOMEM */
-    "Es wurde eine Abbruch-Sequenz gefunden",               /* JBG_EABORT */
-    "Eine unbekannte Markierungssequenz wurde gefunden",    /* JBG_EMARKER */
-    "Neue Daten passen nicht zu vorangegangenen Daten",     /* JBG_ENOCONT */
-    "Es wurden ung\303\274ltige Daten gefunden",            /* JBG_EINVAL */
-    "Noch nicht implementierte Optionen wurden benutzt"     /* JBG_EIMPL */
-  }
+static const char *errmsg[] = {
+  _("All OK"),                                               /* JBG_EOK */
+  _("Reached specified image size"),                         /* JBG_EOK_INTR */
+  _("Unexpected end of input data stream"),                  /* JBG_EAGAIN */
+  _("Not enough memory available"),                          /* JBG_ENOMEM */
+  _("ABORT marker segment encountered"),                     /* JBG_EABORT */
+  _("Unknown marker segment encountered"),                   /* JBG_EMARKER */
+  _("Input data stream contains invalid data"),              /* JBG_EINVAL */
+  _("Input data stream uses unimplemented JBIG features"),   /* JBG_EIMPL */
+  _("Incremental BIE does not continue previous one")        /* JBG_ENOCONT */
 };
 
 
-
 /*
  * The following three functions are the only places in this code, were
  * C library memory management functions are called. The whole JBIG
  * library has been designed in order to allow multi-threaded
- * execution. no static or global variables are used, so all fuctions
+ * execution. No static or global variables are used, so all fuctions
  * are fully reentrant. However if you want to use this multi-thread
  * capability and your malloc, realloc and free are not reentrant,
  * then simply add the necessary semaphores or mutex primitives below.
+ * In contrast to C's malloc() and realloc(), but like C's calloc(),
+ * these functions take two parameters nmemb and size that are multiplied
+ * before being passed on to the corresponding C function. 
+ * This we can catch all overflows during a size_t multiplication a
+ * a single place.
  */
 
-static void *checked_malloc(size_t size)
+#ifndef SIZE_MAX
+#define SIZE_MAX ((size_t) -1)     /* largest value of size_t */
+#endif
+
+static void *checked_malloc(size_t nmemb, size_t size)
 {
   void *p;
-  
-  p = malloc(size);
+
   /* Full manual exception handling is ugly here for performance
    * reasons. If an adequate handling of lack of memory is required,
-   * then use C++ and throw a C++ exception here. */
+   * then use C++ and throw a C++ exception instead of abort(). */
+
+  /* assert that nmemb * size <= SIZE_MAX */
+  if (size > SIZE_MAX / nmemb)
+    abort();
+  
+  p = malloc(nmemb * size);
+
   if (!p)
     abort();
 
 #if 0
-  fprintf(stderr, "%p = malloc(%ld)\n", p, (long) size);
+  fprintf(stderr, "%p = malloc(%lu * %lu)\n", p,
+	  (unsigned long) nmemb, (unsigned long) size);
 #endif
 
   return p;
 }
 
 
-static void *checked_realloc(void *ptr, size_t size)
+static void *checked_realloc(void *ptr, size_t nmemb, size_t size)
 {
   void *p;
 
-  p = realloc(ptr, size);
   /* Full manual exception handling is ugly here for performance
    * reasons. If an adequate handling of lack of memory is required,
-   * then use C++ and throw a C++ exception here. */
+   * then use C++ and throw a C++ exception here instead of abort(). */
+
+  /* assert that nmemb * size <= SIZE_MAX */
+  if (size > SIZE_MAX / nmemb)
+    abort();
+  
+  p = realloc(ptr, nmemb * size);
+
   if (!p)
     abort();
 
 #if 0
-  fprintf(stderr, "%p = realloc(%p, %ld)\n", p, ptr, (long) size);
+  fprintf(stderr, "%p = realloc(%p, %lu * %lu)\n", p, ptr,
+	  (unsigned long) nmemb, (unsigned long) size);
 #endif
 
   return p;
@@ -218,291 +190,6 @@ static void checked_free(void *ptr)
 
 
 
-/*
- * The next functions implement the arithmedic encoder and decoder
- * required for JBIG. The same algorithm is also used in the arithmetic
- * variant of JPEG.
- */
-
-#ifdef DEBUG
-static long encoded_pixels = 0;
-#endif
-
-ARITH void arith_encode_init(struct jbg_arenc_state *s, int reuse_st)
-{
-  int i;
-  
-  if (!reuse_st)
-    for (i = 0; i < 4096; s->st[i++] = 0);
-  s->c = 0;
-  s->a = 0x10000L;
-  s->sc = 0;
-  s->ct = 11;
-  s->buffer = -1;    /* empty */
-  
-  return;
-}
-
-
-ARITH void arith_encode_flush(struct jbg_arenc_state *s)
-{
-  unsigned long temp;
-
-#ifdef DEBUG
-  fprintf(stderr, "  encoded pixels = %ld, a = %05lx, c = %08lx\n",
-	  encoded_pixels, s->a, s->c);
-#endif
-
-  /* find the s->c in the coding interval with the largest
-   * number of trailing zero bits */
-  if ((temp = (s->a - 1 + s->c) & 0xffff0000L) < s->c)
-    s->c = temp + 0x8000;
-  else
-    s->c = temp;
-  /* send remaining bytes to output */
-  s->c <<= s->ct;
-  if (s->c & 0xf8000000L) {
-    /* one final overflow has to be handled */
-    if (s->buffer >= 0) {
-      s->byte_out(s->buffer + 1, s->file);
-      if (s->buffer + 1 == MARKER_ESC)
-	s->byte_out(MARKER_STUFF, s->file);
-    }
-    /* output 0x00 bytes only when more non-0x00 will follow */
-    if (s->c & 0x7fff800L)
-      for (; s->sc; --s->sc)
-	s->byte_out(0x00, s->file);
-  } else {
-    if (s->buffer >= 0)
-      s->byte_out(s->buffer, s->file); 
-    /* T.82 figure 30 says buffer+1 for the above line! Typo? */
-    for (; s->sc; --s->sc) {
-      s->byte_out(0xff, s->file);
-      s->byte_out(MARKER_STUFF, s->file);
-    }
-  }
-  /* output final bytes only if they are not 0x00 */
-  if (s->c & 0x7fff800L) {
-    s->byte_out((s->c >> 19) & 0xff, s->file);
-    if (((s->c >> 19) & 0xff) == MARKER_ESC)
-      s->byte_out(MARKER_STUFF, s->file);
-    if (s->c & 0x7f800L) {
-      s->byte_out((s->c >> 11) & 0xff, s->file);
-      if (((s->c >> 11) & 0xff) == MARKER_ESC)
-	s->byte_out(MARKER_STUFF, s->file);
-    }
-  }
-
-  return;
-}
-
-
-ARITH_INL void arith_encode(struct jbg_arenc_state *s, int cx, int pix) 
-{
-  extern short jbg_lsz[];
-  extern unsigned char jbg_nmps[], jbg_nlps[];
-  register unsigned lsz, ss;
-  register unsigned char *st;
-  long temp;
-
-#ifdef DEBUG
-  ++encoded_pixels;
-#endif
-
-  assert(cx >= 0 && cx < 4096);
-  st = s->st + cx;
-  ss = *st & 0x7f;
-  assert(ss < 113);
-  lsz = jbg_lsz[ss];
-
-#if 0
-  fprintf(stderr, "pix = %d, cx = %d, mps = %d, st = %3d, lsz = 0x%04x, "
-	  "a = 0x%05lx, c = 0x%08lx, ct = %2d, buf = 0x%02x\n",
-	  pix, cx, !!(s->st[cx] & 0x80), ss, lsz, s->a, s->c, s->ct,
-	  s->buffer);
-#endif
-
-  if (((pix << 7) ^ s->st[cx]) & 0x80) {
-    /* encode the less probable symbol */
-    if ((s->a -= lsz) >= lsz) {
-      /* If the interval size (lsz) for the less probable symbol (LPS)
-       * is larger than the interval size for the MPS, then exchange
-       * the two symbols for coding efficiency, otherwise code the LPS
-       * as usual: */
-      s->c += s->a;
-      s->a = lsz;
-    }
-    /* Check whether MPS/LPS exchange is necessary
-     * and chose next probability estimator status */
-    *st &= 0x80;
-    *st ^= jbg_nlps[ss];
-  } else {
-    /* encode the more probable symbol */
-    if ((s->a -= lsz) & 0xffff8000L)
-      return;   /* A >= 0x8000 -> ready, no renormalization required */
-    if (s->a < lsz) {
-      /* If the interval size (lsz) for the less probable symbol (LPS)
-       * is larger than the interval size for the MPS, then exchange
-       * the two symbols for coding efficiency: */
-      s->c += s->a;
-      s->a = lsz;
-    }
-    /* chose next probability estimator status */
-    *st &= 0x80;
-    *st |= jbg_nmps[ss];
-  }
-
-  /* renormalization of coding interval */
-  do {
-    s->a <<= 1;
-    s->c <<= 1;
-    --s->ct;
-    if (s->ct == 0) {
-      /* another byte is ready for output */
-      temp = s->c >> 19;
-      if (temp & 0xffffff00L) {
-	/* handle overflow over all buffered 0xff bytes */
-	if (s->buffer >= 0) {
-	  ++s->buffer;
-	  s->byte_out(s->buffer, s->file);
-	  if (s->buffer == MARKER_ESC)
-	    s->byte_out(MARKER_STUFF, s->file);
-	}
-	for (; s->sc; --s->sc)
-	  s->byte_out(0x00, s->file);
-	s->buffer = temp & 0xff;  /* new output byte, might overflow later */
-	assert(s->buffer != 0xff);
-	/* can s->buffer really never become 0xff here? */
-      } else if (temp == 0xff) {
-	/* buffer 0xff byte (which might overflow later) */
-	++s->sc;
-      } else {
-	/* output all buffered 0xff bytes, they will not overflow any more */
-	if (s->buffer >= 0)
-	  s->byte_out(s->buffer, s->file);
-	for (; s->sc; --s->sc) {
-	  s->byte_out(0xff, s->file);
-	  s->byte_out(MARKER_STUFF, s->file);
-	}
-	s->buffer = temp;   /* buffer new output byte (can still overflow) */
-      }
-      s->c &= 0x7ffffL;
-      s->ct = 8;
-    }
-  } while (s->a < 0x8000);
- 
-  return;
-}
-
-
-ARITH void arith_decode_init(struct jbg_ardec_state *s, int reuse_st)
-{
-  int i;
-  
-  if (!reuse_st)
-    for (i = 0; i < 4096; s->st[i++] = 0);
-  s->c = 0;
-  s->a = 1;
-  s->ct = 0;
-  s->result = JBG_OK;
-  s->startup = 1;
-  return;
-}
-
-
-ARITH_INL int arith_decode(struct jbg_ardec_state *s, int cx)
-{
-  extern short jbg_lsz[];
-  extern unsigned char jbg_nmps[], jbg_nlps[];
-  register unsigned lsz, ss;
-  register unsigned char *st;
-  int pix;
-
-  /* renormalization */
-  while (s->a < 0x8000 || s->startup) {
-    if (s->ct < 1 && s->result != JBG_READY) {
-      /* first we have to move a new byte into s->c */
-      if (s->pscd_ptr >= s->pscd_end) {
-	s->result = JBG_MORE;
-	return -1;
-      }
-      if (*s->pscd_ptr == 0xff) 
-	if (s->pscd_ptr + 1 >= s->pscd_end) {
-	  s->result = JBG_MARKER;
-	  return -1;
-	} else {
-	  if (*(s->pscd_ptr + 1) == MARKER_STUFF) {
-	    s->c |= 0xffL << (8 - s->ct);
-	    s->ct += 8;
-	    s->pscd_ptr += 2;
-	    s->result = JBG_OK;
-	  } else
-	    s->result = JBG_READY;
-	}
-      else {
-	s->c |= (long)*(s->pscd_ptr++) << (8 - s->ct);
-	s->ct += 8;
-	s->result = JBG_OK;
-      }
-    }
-    s->c <<= 1;
-    s->a <<= 1;
-    --s->ct;
-    if (s->a == 0x10000L)
-      s->startup = 0;
-  }
-
-  st = s->st + cx;
-  ss = *st & 0x7f;
-  assert(ss < 113);
-  lsz = jbg_lsz[ss];
-
-#if 0
-  fprintf(stderr, "cx = %d, mps = %d, st = %3d, lsz = 0x%04x, a = 0x%05lx, "
-	  "c = 0x%08lx, ct = %2d\n",
-	  cx, !!(s->st[cx] & 0x80), ss, lsz, s->a, s->c, s->ct);
-#endif
-
-  if ((s->c >> 16) < (s->a -= lsz))
-    if (s->a & 0xffff8000L)
-      return *st >> 7;
-    else {
-      /* MPS_EXCHANGE */
-      if (s->a < lsz) {
-	pix = 1 - (*st >> 7);
-	/* Check whether MPS/LPS exchange is necessary
-	 * and chose next probability estimator status */
-	*st &= 0x80;
-	*st ^= jbg_nlps[ss];
-      } else {
-	pix = *st >> 7;
-	*st &= 0x80;
-	*st |= jbg_nmps[ss];
-      }
-    }
-  else {
-    /* LPS_EXCHANGE */
-    if (s->a < lsz) {
-      s->c -= s->a << 16;
-      s->a = lsz;
-      pix = *st >> 7;
-      *st &= 0x80;
-      *st |= jbg_nmps[ss];
-    } else {
-      s->c -= s->a << 16;
-      s->a = lsz;
-      pix = 1 - (*st >> 7);
-      /* Check whether MPS/LPS exchange is necessary
-       * and chose next probability estimator status */
-      *st &= 0x80;
-      *st ^= jbg_nlps[ss];
-    }
-  }
-
-  return pix;
-}
-
-
 
 /*
  * Memory management for buffers which are used for temporarily
@@ -532,7 +219,7 @@ static struct jbg_buf *jbg_buf_init(struct jbg_buf **free_list)
     *free_list = new_block->next;
   } else {
     /* request a new memory block */
-    new_block = (struct jbg_buf *) checked_malloc(sizeof(struct jbg_buf));
+    new_block = (struct jbg_buf *) checked_malloc(1, sizeof(struct jbg_buf));
   }
   new_block->len = 0;
   new_block->next = NULL;
@@ -668,7 +355,8 @@ static void jbg_buf_output(struct jbg_buf **head,
 
 
 /*
- * Calculate y = ceil(x/2) applied n times. This function is used to
+ * Calculate y = ceil(x/2) applied n times, which is equivalent to
+ * y = ceil(x/(2^n)). This function is used to
  * determine the number of pixels per row or column after n resolution
  * reductions. E.g. X[d-1] = jbg_ceil_half(X[d], 1) and X[0] =
  * jbg_ceil_half(X[d], d) as defined in clause 6.2.3 of T.82.
@@ -677,12 +365,405 @@ unsigned long jbg_ceil_half(unsigned long x, int n)
 {
   unsigned long mask;
   
+  assert(n >= 0 && n < 32);
   mask = (1UL << n) - 1;     /* the lowest n bits are 1 here */
   return (x >> n) + ((mask & x) != 0);
 }
 
 
 /*
+ * Set L0 (the number of lines in a stripe at lowest resolution)
+ * to a default value, such that there are about 35 stripes, as
+ * suggested in Annex C of ITU-T T.82, without exceeding the
+ * limit 128/2^D suggested in Annex A.
+ */
+static void jbg_set_default_l0(struct jbg_enc_state *s)
+{
+  s->l0 = jbg_ceil_half(s->yd, s->d) / 35;   /* 35 stripes/image */
+  while ((s->l0 << s->d) > 128)              /* but <= 128 lines/stripe */
+    --s->l0;
+  if (s->l0 < 2) s->l0 = 2;
+}
+
+
+/*
+ * Calculate the number of stripes, as defined in clause 6.2.3 of T.82.
+ */
+static unsigned long jbg_stripes(unsigned long l0, unsigned long yd,
+			  unsigned long d)
+{
+  unsigned long y0 = jbg_ceil_half(yd, d);
+
+  return y0 / l0 + (y0 % l0 != 0);
+}
+
+
+/*
+ * Resolution reduction table given by ITU-T T.82 Table 17
+ */
+
+static char jbg_resred[4096] = {
+  0,0,0,1,0,0,0,1,0,1,1,1,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
+  0,0,1,1,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
+  0,0,0,0,0,0,0,1,0,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
+  0,0,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
+  0,0,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
+  0,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
+  0,0,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
+  1,1,1,1,1,1,1,1,0,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
+  0,0,0,0,0,0,0,1,0,0,1,1,0,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,
+  0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
+  0,0,1,1,0,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,
+  0,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
+  0,0,1,1,0,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,
+  1,1,0,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
+  1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
+  1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
+  0,0,0,0,0,0,0,1,0,0,1,0,0,0,1,1,0,0,0,0,0,1,0,1,0,0,1,1,1,0,1,1,
+  0,0,0,1,0,0,0,1,0,0,1,0,0,0,1,1,0,1,1,1,0,0,0,1,1,1,1,1,1,1,1,1,
+  0,0,0,0,0,0,0,1,0,1,1,1,0,1,0,1,0,0,1,1,1,0,1,1,0,1,1,1,1,1,1,1,
+  0,0,0,0,0,0,0,0,0,1,0,1,0,0,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,
+  0,0,0,0,0,0,0,1,0,1,0,0,0,0,0,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
+  0,0,0,0,1,0,0,1,1,0,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
+  0,0,0,0,0,0,0,0,0,1,0,1,0,0,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,
+  1,0,0,1,0,0,1,1,0,1,1,1,1,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
+  0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,1,1,1,0,0,1,1,1,1,1,1,1,1,1,1,
+  0,0,1,1,0,0,0,1,0,0,0,1,0,0,1,1,0,1,1,1,0,1,0,1,1,1,1,1,1,1,1,1,
+  0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,1,1,0,1,1,0,1,1,1,1,1,1,0,1,1,1,0,
+  0,0,0,0,0,0,0,1,0,0,1,0,0,0,0,1,1,1,1,1,1,1,0,0,1,1,1,1,1,1,1,1,
+  0,0,0,0,0,0,0,0,1,0,0,1,0,0,1,1,0,1,1,1,0,1,0,1,1,1,1,1,1,1,1,1,
+  0,0,0,1,0,0,0,1,0,1,1,0,1,0,1,1,1,1,1,1,0,1,0,1,1,1,1,1,1,1,1,1,
+  1,1,1,0,1,0,0,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,
+  1,0,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,
+  0,0,0,0,0,0,0,1,0,0,1,0,0,0,1,1,0,0,0,0,0,0,0,1,0,0,1,1,1,1,1,1,
+  0,0,0,1,0,0,0,1,0,0,0,0,0,0,0,1,0,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,
+  0,0,0,0,0,0,0,1,0,1,1,1,0,1,0,1,0,1,1,0,1,0,1,1,0,1,1,1,1,1,1,1,
+  0,0,0,0,0,0,0,0,0,1,0,1,0,0,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,
+  0,0,0,0,0,0,0,1,0,1,1,0,0,0,0,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
+  0,0,1,0,1,0,0,1,0,0,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
+  0,0,0,0,0,0,0,0,0,1,1,1,0,0,1,1,0,0,1,1,1,1,1,1,0,1,1,1,1,0,1,1,
+  1,0,0,1,0,0,1,0,0,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
+  0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,1,1,1,1,0,1,1,1,1,1,1,1,1,1,0,
+  0,0,1,0,1,1,1,1,0,0,0,1,1,0,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
+  0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,1,0,0,1,1,0,1,1,1,1,1,1,1,1,1,1,0,
+  0,0,0,0,1,0,0,1,0,0,1,1,0,1,1,1,0,1,1,1,1,1,1,0,0,1,1,1,1,1,1,1,
+  0,0,0,0,0,0,0,0,1,1,0,1,0,0,1,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
+  0,0,0,1,1,0,1,1,0,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
+  0,0,0,0,0,0,0,0,0,1,1,1,0,1,0,1,0,1,1,1,1,1,1,1,0,1,1,1,0,1,1,1,
+  0,0,1,0,0,1,1,1,0,1,1,1,1,1,1,1,0,1,1,1,1,0,1,1,0,1,1,1,1,1,1,1,
+  0,0,0,0,0,0,0,1,0,0,0,0,0,0,1,1,0,0,0,0,0,0,0,1,0,0,0,0,1,0,0,1,
+  0,0,0,1,0,0,0,1,0,0,0,0,0,0,0,1,0,1,0,0,0,0,0,1,1,0,0,1,0,0,1,1,
+  0,0,0,0,0,0,0,1,0,1,1,1,0,1,0,1,0,0,1,0,0,0,0,1,0,1,0,1,0,1,0,1,
+  0,0,0,0,0,0,0,0,0,1,0,1,0,0,0,1,1,0,0,0,0,0,0,0,1,1,1,1,0,1,1,1,
+  0,0,0,0,0,0,0,1,0,1,0,0,0,0,0,1,0,1,1,0,1,0,1,1,0,0,0,1,0,0,1,1,
+  0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,
+  0,0,0,0,0,0,0,0,0,1,0,1,0,0,0,1,0,0,0,0,0,0,0,1,0,1,1,1,0,0,1,1,
+  0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,1,1,0,1,1,0,1,1,1,1,1,1,1,1,1,1,1,
+  0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,1,1,0,0,0,0,1,1,0,0,0,0,0,0,1,
+  0,0,1,0,0,1,1,1,0,0,0,0,1,0,0,1,0,0,0,1,1,1,1,0,1,0,1,1,1,1,1,1,
+  0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,1,0,1,0,1,1,0,
+  0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,1,1,1,1,1,1,1,
+  0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,1,0,0,0,0,1,0,1,1,1,0,1,1,1,
+  0,0,0,0,0,0,1,1,0,0,0,0,0,0,0,1,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
+  0,1,1,0,1,0,0,0,1,1,0,1,0,0,0,0,1,1,1,1,0,0,1,1,1,0,1,1,0,0,1,1,
+  0,0,0,0,0,0,0,0,1,1,0,1,0,0,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,
+  0,0,0,0,0,0,0,1,0,0,0,0,0,0,1,1,0,0,1,1,0,1,1,1,1,1,1,1,1,1,1,1,
+  0,0,1,1,0,0,1,1,0,0,1,1,0,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
+  0,0,0,0,0,0,0,1,0,1,1,1,0,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
+  0,0,0,1,0,0,0,1,0,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
+  0,0,0,0,0,0,0,1,1,1,1,1,0,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
+  0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,
+  0,0,0,1,0,0,1,0,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
+  1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,
+  0,0,0,0,0,0,0,1,0,0,0,1,0,0,1,0,0,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,
+  0,0,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
+  0,0,0,0,0,0,0,0,0,1,1,0,0,0,1,0,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,
+  0,0,1,1,1,1,1,1,0,0,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
+  0,0,0,1,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,
+  0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
+  1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
+  1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
+  0,0,0,0,0,0,0,1,0,0,1,0,0,0,1,1,0,0,0,0,0,0,0,1,0,0,0,1,1,0,1,1,
+  0,0,0,1,0,0,0,1,0,0,1,0,0,0,1,1,0,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,
+  0,0,0,0,0,0,0,1,0,1,1,1,0,1,0,1,0,0,1,0,1,0,1,1,0,1,1,1,0,1,1,1,
+  0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,1,1,0,1,1,1,1,1,0,1,1,1,1,1,1,1,1,
+  0,0,0,0,0,0,0,1,1,1,0,0,0,0,0,1,0,1,0,1,1,0,1,1,0,1,1,1,1,1,1,1,
+  0,0,0,0,1,0,0,1,0,0,1,1,0,0,1,1,0,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,
+  0,0,0,0,0,0,0,0,0,1,0,1,0,0,0,1,0,0,1,1,0,1,1,1,1,1,1,1,1,0,1,1,
+  1,0,1,0,1,0,0,1,1,0,1,1,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
+  0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,1,1,1,0,0,0,1,1,0,1,1,0,1,1,1,
+  0,0,1,0,0,0,0,1,0,0,0,0,0,0,1,1,0,1,1,1,0,1,0,1,1,1,1,1,1,1,1,1,
+  0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,1,0,1,1,1,0,1,1,0,1,1,1,1,
+  0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,
+  0,0,0,0,0,0,0,0,1,1,0,0,0,0,0,1,0,1,1,1,0,1,0,1,1,1,1,1,1,1,1,1,
+  0,0,0,0,0,0,0,1,1,0,1,0,1,0,1,1,0,1,0,1,0,0,0,1,1,1,1,1,1,1,1,1,
+  1,1,1,0,1,0,0,0,1,1,0,1,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,
+  1,0,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,
+  0,0,0,0,0,0,0,1,0,0,1,0,0,0,1,1,0,0,0,0,0,0,0,1,0,0,0,1,1,0,1,1,
+  0,0,1,1,0,0,0,1,0,0,0,0,0,0,0,1,0,1,0,1,0,0,1,1,0,1,1,1,1,1,1,1,
+  0,0,0,0,0,0,0,1,0,1,1,1,0,1,0,1,0,0,1,0,1,0,0,1,0,1,1,1,1,1,1,1,
+  0,0,0,0,0,0,0,0,0,1,0,1,0,0,0,1,1,0,1,1,0,1,1,0,1,1,1,1,1,1,1,1,
+  0,0,0,0,0,0,0,1,1,1,1,0,0,0,0,0,0,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,
+  0,0,0,0,1,0,1,0,0,0,1,1,1,0,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
+  0,0,0,0,0,0,0,0,0,1,1,1,0,0,0,1,0,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,
+  1,0,0,0,1,0,0,0,0,1,1,1,0,1,0,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,
+  0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,1,1,0,0,0,0,1,1,1,1,1,0,1,1,0,
+  0,0,1,1,1,1,1,1,0,0,0,0,1,0,0,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
+  0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,1,0,1,1,1,0,1,1,1,1,1,1,1,
+  0,0,0,0,1,0,0,0,0,0,0,1,0,0,1,1,0,1,1,1,1,1,1,0,0,1,1,1,1,1,1,1,
+  0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,
+  0,0,1,0,1,0,1,1,0,0,1,0,1,1,1,1,0,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,
+  0,0,0,0,0,0,0,0,0,1,1,1,0,0,0,1,0,1,1,1,1,1,1,1,0,1,1,1,0,1,1,1,
+  0,0,1,0,1,0,1,1,0,1,1,1,1,1,1,1,0,0,1,1,1,0,1,1,0,1,1,1,1,1,1,1,
+  0,0,0,0,0,0,0,1,0,0,0,0,0,0,1,1,0,0,0,0,0,0,0,1,0,0,0,0,1,0,0,1,
+  0,0,0,1,0,0,0,1,0,0,0,0,0,0,0,1,0,1,0,0,0,0,0,1,0,0,0,0,0,0,0,1,
+  0,0,0,0,0,0,0,1,0,1,1,1,0,1,0,1,0,0,1,0,0,0,0,1,0,1,0,1,0,1,0,1,
+  0,0,0,0,0,0,0,0,0,1,0,1,0,0,0,1,1,0,0,0,0,0,0,0,0,1,0,1,0,0,1,1,
+  0,0,0,0,0,0,0,1,0,1,0,0,0,0,0,1,0,1,0,0,1,0,0,1,0,0,0,0,0,0,0,1,
+  0,0,0,0,1,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,1,0,0,1,1,
+  0,0,0,0,0,0,0,0,0,1,0,1,0,0,0,1,0,0,0,0,0,0,0,0,0,1,0,1,0,0,1,1,
+  1,0,0,0,0,0,0,0,0,1,0,0,0,0,0,1,0,0,0,1,0,0,1,1,0,1,1,1,1,1,1,1,
+  0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,1,1,0,0,0,0,1,1,0,0,0,0,0,0,0,
+  0,0,1,0,0,0,0,1,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,1,0,0,0,1,0,0,1,1,
+  0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,
+  0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,1,1,
+  0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,1,1,
+  0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,1,0,1,0,1,0,0,0,1,0,1,1,1,1,1,1,1,
+  0,0,0,0,0,0,0,0,0,1,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,0,0,1,1,
+  0,0,0,0,0,0,0,1,0,1,0,1,0,1,0,0,0,0,1,1,0,0,0,1,0,1,1,1,0,1,1,1
+};
+
+/*
+ * Deterministic prediction tables given by ITU-T T.82 tables
+ * 19 to 22. The table below is organized differently, the
+ * index bits are permutated for higher efficiency.
+ */
+
+static char jbg_dptable[256 + 512 + 2048 + 4096] = {
+  /* phase 0: offset=0 */
+  0,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,
+  0,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,2,0,2,2,2,2,2,2,2,2,2,2,2,2,2,
+  0,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,0,2,2,2,2,2,2,0,2,2,2,2,2,2,2,
+  0,2,0,2,2,2,2,2,2,2,2,2,2,2,2,2,0,0,2,2,2,2,2,2,0,2,0,2,2,2,2,2,
+  2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,2,0,2,2,2,2,2,2,2,2,2,2,2,2,2,
+  2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,1,
+  2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,0,2,2,2,2,2,2,2,2,2,2,2,2,2,2,
+  2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,
+  /* phase 1: offset=256 */
+  2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,2,2,2,2,2,2,2,2,2,2,2,2,2,
+  0,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,0,2,2,2,2,2,0,2,0,2,2,2,2,2,
+  2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,2,2,2,2,2,2,2,2,2,2,2,2,2,
+  0,2,2,2,2,1,2,1,2,2,2,2,1,1,1,1,2,0,2,0,2,2,2,2,0,2,0,2,2,2,2,2,
+  0,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,0,0,2,2,2,2,0,2,2,2,2,2,2,2,
+  0,2,0,2,2,2,2,2,2,2,2,2,2,0,2,0,2,2,0,0,2,2,2,2,2,0,0,2,2,2,2,2,
+  0,2,2,2,2,1,2,1,2,2,2,2,1,1,1,1,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,1,
+  1,2,1,2,2,2,2,2,2,2,2,2,2,1,2,2,2,2,1,1,2,2,2,2,2,0,2,2,2,2,2,2,
+  2,2,2,2,2,0,2,0,2,2,2,2,0,0,0,0,0,2,0,2,2,2,2,2,0,2,2,2,2,2,2,2,
+  0,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,2,0,2,2,2,2,0,2,0,2,2,2,2,2,
+  2,2,2,2,2,1,1,1,2,2,2,2,1,1,1,1,1,2,1,2,2,2,2,2,2,2,2,2,2,2,2,1,
+  2,2,2,2,2,2,2,2,2,2,2,2,2,0,1,2,0,2,0,2,2,2,2,2,0,2,0,2,2,2,2,1,
+  0,2,0,2,2,1,2,1,2,2,2,2,1,1,1,1,0,0,0,0,2,2,2,2,0,2,0,2,2,2,2,1,
+  2,2,0,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,2,2,2,2,2,0,0,0,2,2,2,2,2,
+  2,2,2,2,2,1,2,1,2,2,2,2,2,2,2,1,2,2,2,2,2,2,2,2,1,2,1,2,2,2,2,1,
+  2,2,2,2,2,2,2,2,0,2,0,2,2,1,2,2,2,2,2,2,2,2,2,2,0,0,0,2,2,2,2,2,
+  /* phase 2: offset=768 */
+  2,2,2,2,1,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,1,1,1,1,2,2,2,2,1,1,1,1,
+  0,2,2,2,2,1,2,1,2,2,2,2,1,2,1,2,0,0,0,0,1,1,1,1,0,0,0,0,1,1,1,1,
+  2,2,0,2,2,2,1,2,2,2,2,2,2,2,2,2,2,2,0,2,2,1,2,1,2,2,2,2,2,1,1,1,
+  2,0,2,2,2,1,2,1,0,2,2,2,1,2,1,2,2,2,2,0,2,2,2,2,0,2,0,2,2,2,2,2,
+  0,2,0,0,1,1,1,1,2,2,2,2,1,1,1,1,0,2,0,2,1,1,1,1,2,2,2,2,1,1,1,1,
+  2,2,0,2,2,2,1,2,2,2,2,2,1,2,1,2,2,2,0,2,2,1,2,1,0,2,0,2,1,1,1,1,
+  2,0,0,2,2,2,2,2,0,2,0,2,2,0,2,0,2,0,2,0,2,2,2,1,2,2,0,2,1,1,2,1,
+  2,2,2,0,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,2,2,2,1,2,1,
+  2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,1,1,1,1,2,2,2,2,1,1,1,1,
+  0,0,0,0,2,2,2,2,0,0,0,0,2,2,2,2,0,2,0,2,2,2,2,2,2,2,2,2,2,2,2,2,
+  2,2,0,2,2,2,2,1,0,2,2,2,1,1,1,1,2,0,2,2,2,2,2,2,0,2,0,2,2,1,2,1,
+  2,0,2,0,2,2,2,2,0,2,0,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,2,2,2,2,2,
+  0,2,2,2,1,2,1,2,2,2,2,2,2,2,2,2,0,2,2,2,2,2,1,2,2,2,2,2,2,2,2,2,
+  2,2,0,2,2,2,2,2,2,2,2,2,2,2,0,2,2,0,0,2,2,1,2,1,0,2,2,2,1,1,1,1,
+  2,2,2,0,2,2,2,2,2,2,0,2,2,0,2,0,2,1,2,2,2,2,2,2,1,2,1,2,2,2,2,2,
+  2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,2,0,2,2,2,1,
+  0,2,2,2,1,2,2,2,2,2,2,2,2,2,2,2,0,2,2,2,2,1,1,1,2,2,2,2,1,1,1,1,
+  2,2,2,1,2,2,2,2,2,2,1,2,0,0,0,0,2,2,0,2,2,1,2,2,2,2,2,2,1,1,1,1,
+  2,0,0,0,2,2,2,2,0,2,2,2,2,2,2,0,2,2,2,0,2,2,2,2,2,0,0,2,2,2,2,2,
+  2,2,2,2,2,2,2,2,2,2,0,2,2,1,2,2,2,2,2,2,2,2,2,2,2,0,2,2,2,1,2,1,
+  0,2,0,2,2,1,1,2,2,2,2,2,2,2,2,2,1,2,2,2,2,2,2,2,2,2,2,2,2,1,2,2,
+  2,0,2,0,2,1,2,1,0,2,0,2,2,2,1,2,2,0,2,0,2,2,2,2,0,2,0,2,2,2,1,2,
+  2,2,2,0,2,2,2,2,2,2,0,2,2,2,2,2,2,2,1,2,2,2,2,2,2,0,1,2,2,2,2,1,
+  2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,1,2,2,2,2,2,2,2,2,2,2,2,0,2,2,2,1,
+  0,2,2,2,1,2,1,2,2,2,2,2,2,2,2,2,0,2,2,2,2,2,1,2,2,2,2,2,2,2,2,2,
+  2,0,2,0,2,2,2,2,2,2,2,2,2,2,2,2,2,0,0,2,2,1,2,1,0,2,2,2,1,1,1,1,
+  2,0,2,0,2,1,2,2,0,2,0,2,2,2,1,2,2,2,2,2,2,2,2,2,2,2,0,2,2,1,2,2,
+  2,0,2,2,2,2,2,2,2,0,2,2,2,2,2,2,2,0,2,0,2,2,2,2,0,0,0,0,2,1,2,1,
+  2,2,2,2,2,2,2,0,2,2,2,2,2,2,2,0,2,2,2,2,2,1,2,0,0,2,2,2,1,2,2,2,
+  0,0,2,0,2,2,2,2,0,2,0,2,2,0,2,0,1,1,1,2,2,2,2,2,2,2,2,2,2,1,1,1,
+  2,2,2,2,2,2,2,2,2,0,2,2,2,2,2,1,2,2,2,2,2,2,2,2,2,0,2,0,2,2,2,1,
+  2,2,0,0,2,2,2,2,2,2,2,0,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,
+  2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,1,1,1,1,2,2,2,2,1,1,1,1,
+  0,2,2,2,1,2,1,2,2,2,2,2,2,2,2,2,0,2,2,2,2,2,1,2,2,2,2,2,2,2,2,2,
+  2,0,0,2,2,2,2,2,0,2,0,2,2,2,2,2,1,0,1,2,2,2,2,1,0,2,2,2,1,1,1,1,
+  2,2,2,2,2,2,2,2,2,2,0,2,2,0,2,0,2,1,2,2,2,2,2,2,2,2,0,2,2,1,2,2,
+  0,2,0,0,1,1,1,1,0,2,2,2,1,1,1,1,2,2,2,2,2,2,2,2,2,0,2,2,1,2,1,1,
+  2,2,0,2,2,1,2,2,2,2,2,2,1,2,2,2,2,0,2,2,2,2,2,2,0,2,0,2,1,2,1,1,
+  2,0,2,0,2,2,2,2,0,2,0,2,2,1,2,2,2,2,2,2,2,2,2,2,2,1,2,2,2,2,2,1,
+  2,2,2,2,2,2,2,2,2,0,2,2,2,2,2,1,2,2,2,2,2,2,2,2,2,2,2,0,2,2,2,1,
+  0,2,2,2,1,2,2,2,2,2,2,2,2,2,2,2,0,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,
+  0,2,2,2,2,0,2,0,2,2,2,2,0,0,0,0,2,2,2,2,2,1,1,2,2,2,2,2,1,2,2,2,
+  2,0,2,2,2,1,2,1,0,2,2,2,2,2,1,2,2,0,2,0,2,2,2,2,0,2,0,2,2,1,2,2,
+  0,2,0,0,2,2,2,2,1,2,2,2,2,2,2,0,2,1,2,2,2,2,2,2,1,2,2,2,2,2,2,2,
+  0,2,0,2,2,2,1,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,2,2,2,2,1,0,2,2,
+  0,0,0,2,2,1,1,1,2,2,2,2,1,2,2,2,2,0,2,0,2,2,2,1,2,2,2,2,1,2,1,2,
+  0,0,0,0,2,2,2,2,2,2,0,2,2,1,2,2,2,1,2,1,2,2,2,2,1,2,1,2,0,2,2,2,
+  2,0,2,0,2,2,2,2,2,0,2,2,2,2,2,1,2,2,2,2,2,2,2,2,2,2,2,0,2,2,2,1,
+  0,2,2,2,1,2,1,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,
+  2,1,2,2,2,2,2,0,2,2,1,2,2,0,0,0,2,2,2,2,2,1,2,2,0,2,2,2,1,2,1,2,
+  2,0,2,0,2,2,2,2,0,2,0,2,2,1,2,2,0,2,0,0,2,2,2,2,2,2,2,2,2,1,2,2,
+  2,2,2,2,2,2,2,2,2,0,2,2,2,2,2,1,2,2,2,2,2,2,2,2,2,0,2,0,2,2,2,1,
+  1,2,0,2,2,1,2,1,2,2,2,2,1,2,2,2,2,0,2,0,2,2,2,2,2,0,2,2,1,1,1,1,
+  0,2,2,2,2,2,2,1,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,2,0,2,2,1,2,1,
+  2,2,0,0,2,2,2,2,2,0,2,2,2,1,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,1,1,
+  2,2,2,0,2,2,2,2,2,2,2,0,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,
+  2,2,2,2,2,2,2,2,1,2,1,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,0,2,
+  2,0,2,0,2,2,2,2,2,1,1,2,2,2,2,2,2,2,2,2,2,2,2,1,0,2,0,2,2,2,1,2,
+  2,0,2,0,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,2,2,2,1,2,2,
+  2,0,2,0,2,2,2,2,2,0,2,0,2,2,2,2,2,0,2,0,2,2,2,2,0,0,0,0,2,1,2,1,
+  2,2,2,2,2,1,2,1,0,2,0,2,2,2,2,2,2,0,2,0,2,2,2,2,0,2,0,2,2,2,2,1,
+  2,0,2,0,2,2,2,2,2,1,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,2,2,2,1,2,0,
+  2,0,2,0,2,2,2,1,2,2,2,0,2,2,2,1,2,0,2,0,2,2,2,2,0,0,0,2,2,2,2,1,
+  2,0,2,0,2,2,2,2,2,2,2,0,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,2,2,2,2,
+  /* phase 3: offset=2816 */
+  2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,2,2,2,1,2,2,2,2,2,2,2,2,2,2,2,
+  2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,0,0,0,1,1,1,1,0,0,0,0,1,1,1,1,
+  0,2,2,2,1,2,2,2,2,2,2,2,2,2,2,2,2,1,2,1,2,0,2,0,1,2,1,2,0,2,0,2,
+  2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,
+  2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,
+  2,2,0,2,2,2,1,2,0,2,2,2,1,2,2,2,2,0,2,0,2,1,2,1,0,0,0,0,1,1,1,1,
+  2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,2,2,2,1,2,2,0,2,2,2,1,2,
+  2,2,2,1,2,2,2,0,1,1,1,1,0,0,0,0,2,2,2,2,2,2,2,2,2,0,2,0,2,1,2,1,
+  2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,2,2,2,1,2,2,0,0,0,0,1,1,1,1,
+  2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,2,0,2,1,2,1,0,0,0,0,1,1,1,1,
+  2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,1,2,1,2,0,2,0,2,
+  2,2,0,2,2,2,1,2,2,2,2,2,2,2,2,2,2,0,2,0,2,1,2,1,2,0,2,0,2,1,2,1,
+  2,0,0,0,2,1,1,1,0,0,0,0,1,1,1,1,2,2,2,0,2,2,2,1,2,2,2,2,2,2,2,2,
+  2,0,2,2,2,1,2,2,2,2,0,2,2,2,1,2,2,2,2,2,2,2,2,2,0,0,2,0,1,1,2,1,
+  2,2,2,0,2,2,2,1,2,1,2,2,2,0,2,2,2,2,2,2,2,2,2,2,2,0,2,2,2,1,2,2,
+  2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,2,2,2,1,
+  2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,
+  2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,0,0,0,1,1,1,1,0,0,0,0,1,1,1,1,
+  0,0,0,0,1,1,1,1,0,0,0,0,1,1,1,1,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,
+  0,0,0,0,1,1,1,1,0,0,0,0,1,1,1,1,2,0,2,0,2,1,2,1,0,0,0,0,1,1,1,1,
+  2,0,0,2,2,1,1,2,2,2,2,2,2,2,2,2,2,1,2,1,2,0,2,0,2,1,1,1,2,0,0,0,
+  2,1,2,1,2,0,2,0,1,2,1,2,0,2,0,2,2,2,2,0,2,2,2,1,2,0,2,0,2,1,2,1,
+  2,0,2,0,2,1,2,1,0,0,0,0,1,1,1,1,2,2,2,2,2,2,2,2,2,0,2,0,2,1,2,1,
+  2,2,2,2,2,2,2,2,2,0,0,0,2,1,1,1,2,2,2,2,2,2,2,2,2,0,2,0,2,1,2,1,
+  2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,2,2,2,1,2,2,2,2,2,2,2,2,2,
+  0,2,2,2,1,2,2,2,2,2,2,2,2,2,2,2,2,2,0,2,2,2,1,2,2,2,2,2,2,2,2,2,
+  2,0,0,0,2,1,1,1,0,0,0,0,1,1,1,1,2,0,2,0,2,1,2,1,0,0,2,0,1,1,2,1,
+  2,2,1,2,2,2,0,2,2,2,2,2,2,2,2,2,2,2,2,0,2,2,2,1,2,0,0,0,2,1,1,1,
+  2,2,2,1,2,2,2,0,2,1,1,1,2,0,0,0,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,
+  2,2,2,0,2,2,2,1,2,2,2,2,2,2,2,2,2,1,2,1,2,0,2,0,1,2,1,2,0,2,0,2,
+  2,2,2,2,2,2,2,2,2,2,2,0,2,2,2,1,2,2,2,2,2,2,2,2,2,2,2,0,2,2,2,1,
+  2,2,2,2,2,2,2,2,2,0,2,2,2,1,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,
+  2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,
+  0,2,2,2,1,2,2,2,2,2,2,2,2,2,2,2,2,0,0,0,2,1,1,1,0,0,0,0,1,1,1,1,
+  2,0,2,2,2,1,2,2,0,0,2,0,1,1,2,1,2,1,2,1,2,0,2,0,2,2,2,2,2,2,2,2,
+  2,2,0,2,2,2,1,2,2,2,2,2,2,2,2,2,2,0,2,2,2,1,2,2,0,0,0,0,1,1,1,1,
+  2,0,0,0,2,1,1,1,0,0,0,0,1,1,1,1,2,2,2,2,2,2,2,2,2,1,0,2,2,0,1,2,
+  2,2,2,1,2,2,2,0,2,1,1,1,2,0,0,0,2,2,2,2,2,2,2,2,2,2,2,0,2,2,2,1,
+  2,2,2,2,2,2,2,2,2,2,0,2,2,2,1,2,2,2,2,2,2,2,2,2,2,0,2,2,2,1,2,2,
+  2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,2,2,2,1,
+  0,2,2,2,1,2,2,2,2,2,2,2,2,2,2,2,2,1,2,2,2,0,2,2,2,2,2,2,2,2,2,2,
+  2,1,2,1,2,0,2,0,1,2,1,1,0,2,0,0,0,0,2,1,1,1,2,0,0,0,0,0,1,1,1,1,
+  2,2,2,2,2,2,2,2,1,2,2,2,0,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,
+  2,0,2,1,2,1,2,0,0,2,2,2,1,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,
+  2,2,2,0,2,2,2,1,2,2,0,2,2,2,1,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,
+  2,2,2,2,2,2,2,2,2,1,2,2,2,0,2,2,2,2,0,2,2,2,1,2,2,2,0,0,2,2,1,1,
+  2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,2,2,2,1,
+  2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,
+  2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,2,2,2,1,2,2,2,2,2,2,2,2,2,
+  0,2,2,2,1,2,2,2,2,2,2,2,2,2,2,2,2,2,1,2,2,2,0,2,2,2,2,2,2,2,2,2,
+  2,0,2,0,2,1,2,1,0,0,0,0,1,1,1,1,2,2,2,2,2,2,2,2,0,0,0,0,1,1,1,1,
+  2,2,0,2,2,2,1,2,2,2,2,2,2,2,2,2,2,2,2,0,2,2,2,1,2,0,0,0,2,1,1,1,
+  2,2,2,0,2,2,2,1,0,2,2,2,1,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,
+  2,2,2,2,2,2,2,2,2,2,0,2,2,2,1,2,2,2,2,2,2,2,2,2,2,0,2,2,2,1,2,2,
+  2,0,2,2,2,1,2,2,2,0,2,0,2,1,2,1,2,2,2,2,2,2,2,2,2,2,2,0,2,2,2,1,
+  2,1,2,1,2,0,2,0,1,2,1,2,0,2,0,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,
+  2,1,2,1,2,0,2,0,1,2,1,1,0,2,0,0,2,0,2,2,2,1,2,2,0,2,1,2,1,2,0,2,
+  2,2,2,1,2,2,2,0,2,2,1,2,2,2,0,2,2,1,2,2,2,0,2,2,2,2,0,2,2,2,1,2,
+  0,0,2,0,1,1,2,1,0,0,1,0,1,1,0,1,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,
+  2,2,2,0,2,2,2,1,1,2,2,2,0,2,2,2,0,0,0,0,1,1,1,1,0,0,0,0,1,1,1,1,
+  2,2,2,2,2,2,2,2,2,1,2,2,2,0,2,2,2,2,2,2,2,2,2,2,2,2,2,0,2,2,2,1,
+  2,2,2,2,2,2,2,2,2,0,2,2,2,1,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,
+  2,2,0,0,2,2,1,1,2,2,2,0,2,2,2,1,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,
+  2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,
+  2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,
+  2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,0,0,0,1,1,1,1,0,0,0,0,1,1,1,1,
+  2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,2,2,2,1,2,2,2,2,2,2,2,2,2,
+  0,2,2,2,1,2,2,2,2,2,2,2,2,2,2,2,2,2,1,2,2,2,0,2,2,2,2,2,2,2,2,2,
+  2,0,0,0,2,1,1,1,0,0,0,0,1,1,1,1,2,2,2,1,2,2,2,0,2,1,2,1,2,0,2,0,
+  2,1,2,2,2,0,2,2,2,2,2,2,2,2,2,2,0,2,0,0,1,2,1,1,2,0,0,0,2,1,1,1,
+  2,2,2,2,2,2,2,2,2,1,1,1,2,0,0,0,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,
+  2,2,2,0,2,2,2,1,2,2,0,2,2,2,1,2,2,1,2,1,2,0,2,0,2,0,2,2,2,1,2,2,
+  2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,1,2,2,2,0,2,2,2,1,1,1,2,0,0,0,
+  2,2,2,2,2,2,2,2,2,0,2,2,2,1,2,2,2,2,2,2,2,2,2,2,0,2,0,0,1,2,1,1,
+  2,2,0,2,2,2,1,2,2,2,2,2,2,2,2,2,2,0,2,2,2,1,2,2,0,2,2,2,1,2,2,2,
+  2,1,2,1,2,0,2,0,2,1,2,2,2,0,2,2,2,2,2,0,2,2,2,1,2,0,2,0,2,1,2,1,
+  2,0,2,0,2,1,2,1,0,2,0,2,1,2,1,2,2,2,2,2,2,2,2,2,2,0,2,2,2,1,2,2,
+  2,2,2,2,2,2,2,2,0,2,0,2,1,2,1,2,2,2,2,2,2,2,2,2,0,1,0,0,1,0,1,1,
+  2,2,2,2,2,2,2,2,2,1,2,2,2,0,2,2,2,2,2,2,2,2,2,2,2,2,2,0,2,2,2,1,
+  2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,
+  2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,
+  0,2,2,2,1,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,
+  0,0,0,0,1,1,1,1,0,0,0,0,1,1,1,1,2,2,1,2,2,2,0,2,2,2,2,2,2,2,2,2,
+  2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,1,2,2,1,0,2,0,2,2,2,1,2,2,2,
+  2,2,2,2,2,2,2,2,1,2,2,2,0,2,2,2,2,2,2,0,2,2,2,1,2,2,0,2,2,2,1,2,
+  2,0,2,0,2,1,2,1,0,2,0,2,1,2,1,2,2,2,2,2,2,2,2,2,2,0,2,2,2,1,2,2,
+  0,2,0,0,1,2,1,1,2,0,0,0,2,1,1,1,2,2,2,2,2,2,2,2,1,0,1,2,0,1,0,2,
+  2,2,2,2,2,2,2,2,2,0,2,2,2,1,2,2,2,1,2,2,2,0,2,2,1,1,2,2,0,0,2,2,
+  0,2,2,2,1,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,
+  2,1,2,1,2,0,2,0,2,1,2,2,2,0,2,2,2,0,2,2,2,1,2,2,0,2,2,2,1,2,2,2,
+  0,2,2,2,1,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,2,2,2,1,1,2,2,2,0,2,2,2,
+  2,0,2,2,2,1,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,2,0,2,1,2,1,2,
+  0,0,0,0,1,1,1,1,2,2,0,2,2,2,1,2,2,2,2,2,2,2,2,2,2,0,2,2,2,1,2,2,
+  2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,1,2,1,2,0,2,0,2,2,0,2,2,2,1,2,
+  2,0,2,0,2,1,2,1,2,0,2,2,2,1,2,2,2,2,2,2,2,2,2,2,2,2,2,0,2,2,2,1,
+  2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,
+  2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,2,2,2,1,2,2,2,2,2,2,2,2,2,
+  0,2,2,2,1,2,2,2,2,2,2,2,2,2,2,2,0,2,2,2,1,2,2,2,2,2,2,2,2,2,2,2,
+  2,2,2,1,2,2,2,0,1,1,2,1,0,0,2,0,2,0,2,2,2,1,2,2,0,2,2,2,1,2,2,2,
+  2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,1,2,2,2,0,2,2,2,2,0,2,2,2,1,2,
+  2,0,2,0,2,1,2,1,0,2,0,2,1,2,1,2,2,2,2,2,2,2,2,2,2,1,2,2,2,0,2,2,
+  0,2,0,0,1,2,1,1,0,2,0,2,1,2,1,2,2,2,2,2,2,2,2,2,0,0,0,2,1,1,1,2,
+  2,2,2,2,2,2,2,2,2,0,2,2,2,1,2,2,2,2,2,2,2,2,2,2,2,2,2,0,2,2,2,1,
+  2,2,2,2,2,2,2,2,2,0,2,2,2,1,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,
+  2,2,0,2,2,2,1,2,2,2,2,2,2,2,2,2,0,0,2,1,1,1,2,0,0,2,2,2,1,2,2,2,
+  2,1,2,1,2,0,2,0,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,2,0,0,1,2,1,1,
+  0,0,2,2,1,1,2,2,0,2,1,2,1,2,0,2,2,1,2,1,2,0,2,0,1,2,1,2,0,2,0,2,
+  2,2,2,2,2,2,2,2,1,2,1,2,0,2,0,2,2,2,2,2,2,2,2,2,2,0,2,0,2,1,2,1,
+  2,2,0,0,2,2,1,1,2,2,0,0,2,2,1,1,2,2,2,2,2,2,2,2,2,2,0,0,2,2,1,1,
+  2,2,2,2,2,2,2,2,0,2,2,2,1,2,2,2,2,2,2,2,2,2,2,2,0,2,0,0,1,2,1,1,
+  2,2,2,0,2,2,2,1,2,2,2,0,2,2,2,1,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,
+  2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,
+  2,2,2,2,2,2,2,2,2,0,2,2,2,1,2,2,2,2,2,2,2,2,2,2,1,1,1,2,0,0,0,2,
+  2,2,2,2,2,2,2,2,1,1,1,2,0,0,0,2,2,2,2,2,2,2,2,2,0,2,2,2,1,2,2,2,
+  2,0,2,0,2,1,2,1,2,2,2,0,2,2,2,1,2,2,2,2,2,2,2,2,2,0,0,0,2,1,1,1,
+  2,0,2,2,2,1,2,2,0,2,2,2,1,2,2,2,2,0,2,0,2,1,2,1,2,2,2,2,2,2,2,2,
+  2,0,2,0,2,1,2,1,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,
+  2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,
+  2,0,2,0,2,1,2,1,2,1,2,0,2,0,2,1,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,
+  2,0,2,0,2,1,2,1,1,2,1,2,0,2,0,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,
+  2,2,2,2,2,2,2,2,1,2,1,2,0,2,0,2,2,1,2,1,2,0,2,0,2,2,2,2,2,2,2,2,
+  2,0,2,1,2,1,2,0,0,2,1,2,1,2,0,2,2,2,2,2,2,2,2,2,2,2,2,0,2,2,2,1,
+  2,0,2,0,2,1,2,1,2,2,2,0,2,2,2,1,2,2,2,2,2,2,2,2,2,0,2,0,2,1,2,1,
+  2,2,2,2,2,2,2,2,2,2,2,0,2,2,2,1,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,
+  2,0,2,2,2,1,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,
+  2,1,2,1,2,0,2,0,1,1,1,2,0,0,0,2,2,2,2,2,2,2,2,2,2,2,2,0,2,2,2,1,
+  2,0,2,0,2,1,2,1,2,2,2,0,2,2,2,1,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,
+  2,2,2,2,2,2,2,2,2,2,2,0,2,2,2,1,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,
+};
+
+
+/*
  * Initialize the status struct for the encoder.
  */
 void jbg_enc_init(struct jbg_enc_state *s, unsigned long x, unsigned long y,
@@ -693,12 +774,13 @@ void jbg_enc_init(struct jbg_enc_state *s, unsigned long x, unsigned long y,
 {
   unsigned long l, lx;
   int i;
-  size_t bufsize;
-
-  extern char jbg_resred[], jbg_dptable[];
 
+  assert(x > 0 && y > 0 && planes > 0 && planes < 256);
   s->xd = x;
   s->yd = y;
+  s->yd1 = y; /* This is the hight initially announced in BIH. To provoke
+                 generation of NEWLEN for T.85 compatibility tests,
+                 overwrite with new value s->yd1 > s->yd  */
   s->planes = planes;
   s->data_out = data_out;
   s->file = file;
@@ -706,33 +788,32 @@ void jbg_enc_init(struct jbg_enc_state *s, unsigned long x, unsigned long y,
   s->d = 0;
   s->dl = 0;
   s->dh = s->d;
-  s->l0 = jbg_ceil_half(s->yd, s->d) / 35;   /* 35 stripes/image */
-  while ((s->l0 << s->d) > 128)              /* but <= 128 lines/stripe */
-    --s->l0;
-  if (s->l0 < 2) s->l0 = 2;
+  jbg_set_default_l0(s);
   s->mx = 8;
   s->my = 0;
   s->order = JBG_ILEAVE | JBG_SMID;
   s->options = JBG_TPBON | JBG_TPDON | JBG_DPON;
+  s->comment = NULL;
   s->dppriv = jbg_dptable;
   s->res_tab = jbg_resred;
   
-  s->highres = checked_malloc(planes * sizeof(int));
+  s->highres = (int *) checked_malloc(planes, sizeof(int));
   s->lhp[0] = p;
-  s->lhp[1] = checked_malloc(planes * sizeof(unsigned char *));
-  bufsize = ((jbg_ceil_half(x, 1) + 7) / 8) * jbg_ceil_half(y, 1);
+  s->lhp[1] = (unsigned char **)
+    checked_malloc(planes, sizeof(unsigned char *));
   for (i = 0; i < planes; i++) {
     s->highres[i] = 0;
-    s->lhp[1][i] = checked_malloc(sizeof(unsigned char) * bufsize);
+    s->lhp[1][i] = (unsigned char *)
+      checked_malloc(jbg_ceil_half(y, 1), jbg_ceil_half(x, 1+3));
   }
   
   s->free_list = NULL;
   s->s = (struct jbg_arenc_state *) 
-    checked_malloc(s->planes * sizeof(struct jbg_arenc_state));
-  s->tx = (int *) checked_malloc(s->planes * sizeof(int));
+    checked_malloc(s->planes, sizeof(struct jbg_arenc_state));
+  s->tx = (int *) checked_malloc(s->planes, sizeof(int));
   lx = jbg_ceil_half(x, 1);
-  s->tp = (char *) checked_malloc(lx * sizeof(char));
-  for (l = 0; l < lx; s->tp[l++] = 2);
+  s->tp = (char *) checked_malloc(lx, sizeof(char));
+  for (l = 0; l < lx; s->tp[l++] = 2) ;
   s->sde = NULL;
 
   return;
@@ -759,12 +840,7 @@ int jbg_enc_lrlmax(struct jbg_enc_state *s, unsigned long x,
       break;
   s->dl = 0;
   s->dh = s->d;
-
-  s->l0 = jbg_ceil_half(s->yd, s->d) / 35;  /* 35 stripes/image */
-  while ((s->l0 << s->d) > 128)             /* but <= 128 lines/stripe */
-    --s->l0;
-  if (s->l0 < 2) s->l0 = 2;
-
+  jbg_set_default_l0(s);
   return s->d;
 }
 
@@ -776,17 +852,12 @@ int jbg_enc_lrlmax(struct jbg_enc_state *s, unsigned long x,
  */
 void jbg_enc_layers(struct jbg_enc_state *s, int d)
 {
-  if (d < 0 || d > 255)
+  if (d < 0 || d > 31)
     return;
   s->d  = d;
   s->dl = 0;
   s->dh = s->d;
-
-  s->l0 = jbg_ceil_half(s->yd, s->d) / 35;  /* 35 stripes/image */
-  while ((s->l0 << s->d) > 128)             /* but <= 128 lines/stripe */
-    --s->l0;
-  if (s->l0 < 2) s->l0 = 2;
-
+  jbg_set_default_l0(s);
   return;
 }
 
@@ -813,11 +884,11 @@ int jbg_enc_lrange(struct jbg_enc_state *s, int dl, int dh)
  * the number of layer 0 lines per stripes.
  */
 void jbg_enc_options(struct jbg_enc_state *s, int order, int options,
-		     long l0, int mx, int my)
+		     unsigned long l0, int mx, int my)
 {
   if (order >= 0 && order <= 0x0f) s->order = order;
   if (options >= 0) s->options = options;
-  if (l0 >= 0) s->l0 = l0;
+  if (l0 > 0) s->l0 = l0;
   if (mx >= 0 && mx < 128) s->mx = mx;
   if (my >= 0 && my < 256) s->my = my;
 
@@ -838,13 +909,17 @@ static void encode_sde(struct jbg_enc_state *s,
   unsigned long line_h0 = 0, line_h1 = 0;
   unsigned long line_h2, line_h3, line_l1, line_l2, line_l3;
   struct jbg_arenc_state *se;
-  unsigned long i, j, y;
-  unsigned t;
+  unsigned long y;  /* current line number in highres image */
+  unsigned long i;  /* current line number within highres stripe */
+  unsigned long j;  /* current column number in highres image */
+  long o;
+  unsigned a, p, t;
   int ltp, ltp_old, cx;
   unsigned long c_all, c[MX_MAX + 1], cmin, cmax, clmin, clmax;
   int tmax, at_determined;
   int new_tx;
   long new_tx_line = -1;
+  int reset;
   struct jbg_buf *new_jbg_buf;
 
 #ifdef DEBUG
@@ -876,16 +951,19 @@ static void encode_sde(struct jbg_enc_state *s,
   lx = jbg_ceil_half(hx, 1);
   ly = jbg_ceil_half(hy, 1);
   /* bytes per line in highres and lowres image */
-  hbpl = (hx + 7) / 8;
-  lbpl = (lx + 7) / 8;
+  hbpl = jbg_ceil_half(hx, 3);
+  lbpl = jbg_ceil_half(lx, 3);
   /* pointer to first image byte of highres stripe */
   hp = s->lhp[s->highres[plane]][plane] + stripe * hl * hbpl;
   lp2 = s->lhp[1 - s->highres[plane]][plane] + stripe * ll * lbpl;
   lp1 = lp2 + lbpl;
   
+  /* check whether we can refer to any state of a previous stripe */
+  reset = (stripe == 0) || (s->options & JBG_SDRST);
+
   /* initialize arithmetic encoder */
   se = s->s + plane;
-  arith_encode_init(se, stripe != 0);
+  arith_encode_init(se, !reset);
   s->sde[stripe][layer][plane] = jbg_buf_init(&s->free_list);
   se->byte_out = jbg_buf_write;
   se->file = s->sde[stripe][layer][plane];
@@ -894,7 +972,7 @@ static void encode_sde(struct jbg_enc_state *s,
   c_all = 0;
   for (t = 0; t <= s->mx; t++)
     c[t] = 0;
-  if (stripe == 0)
+  if (stripe == 0)    /* the SDRST case is handled at the end */
     s->tx[plane] = 0;
   new_tx = -1;
   at_determined = 0;  /* we haven't yet decided the template move */
@@ -903,16 +981,16 @@ static void encode_sde(struct jbg_enc_state *s,
 
   /* initialize typical prediction */
   ltp = 0;
-  if (stripe == 0)
+  if (reset)
     ltp_old = 0;
   else {
     ltp_old = 1;
     p1 = hp - hbpl;
     if (y > 1) {
       q1 = p1 - hbpl;
-      while (p1 < hp && (ltp_old = (*p1++ == *q1++)) != 0);
+      while (p1 < hp && (ltp_old = (*p1++ == *q1++)) != 0) ;
     } else
-      while (p1 < hp && (ltp_old = (*p1++ == 0)) != 0);
+      while (p1 < hp && (ltp_old = (*p1++ == 0)) != 0) ;
   }
 
   if (layer == 0) {
@@ -938,7 +1016,7 @@ static void encode_sde(struct jbg_enc_state *s,
 	if (c_all - cmax < (c_all >> 3) &&
 	    cmax - c[s->tx[plane]] > c_all - cmax &&
 	    cmax - c[s->tx[plane]] > (c_all >> 4) &&
-	    /*                     ^ T.82 says here < !!! Typo ? */
+	    /*                     ^ T.82 said < here, fixed in Cor.1/25 */
 	    cmax - (c_all - c[s->tx[plane]]) > c_all - cmax &&
 	    cmax - (c_all - c[s->tx[plane]]) > (c_all >> 4) &&
 	    cmax - cmin > (c_all >> 2) &&
@@ -949,19 +1027,24 @@ static void encode_sde(struct jbg_enc_state *s,
 	    new_tx_line = i;
 	    s->tx[plane] = new_tx;
 	  }
+#ifdef DEBUG
+	  fprintf(stderr, "ATMOVE: line=%ld, tx=%d, c_all=%ld\n",
+		  i, new_tx, c_all);
+#endif
 	}
 	at_determined = 1;
       }
+      assert(s->tx[plane] >= 0); /* i.e., tx can safely be cast to unsigned */
       
       /* typical prediction */
       if (s->options & JBG_TPBON) {
 	ltp = 1;
 	p1 = hp;
-	if (y > 0) {
+	if (i > 0 || !reset) {
 	  q1 = hp - hbpl;
-	  while (q1 < hp && (ltp = (*p1++ == *q1++)) != 0);
+	  while (q1 < hp && (ltp = (*p1++ == *q1++)) != 0) ;
 	} else
-	  while (p1 < hp + hbpl && (ltp = (*p1++ == 0)) != 0);
+	  while (p1 < hp + hbpl && (ltp = (*p1++ == 0)) != 0) ;
 	arith_encode(se, (s->options & JBG_LRLTWO) ? TPB2CX : TPB3CX,
 		     ltp == ltp_old);
 #ifdef DEBUG
@@ -985,26 +1068,35 @@ static void encode_sde(struct jbg_enc_state *s,
        */
       
       line_h1 = line_h2 = line_h3 = 0;
-      if (y > 0) line_h2 = (long)*(hp - hbpl) << 8;
-      if (y > 1) line_h3 = (long)*(hp - hbpl - hbpl) << 8;
+      if (i > 0 || !reset) line_h2 = (long)*(hp - hbpl) << 8;
+      if (i > 1 || !reset) line_h3 = (long)*(hp - hbpl - hbpl) << 8;
       
       /* encode line */
       for (j = 0; j < hx; hp++) {
 	line_h1 |= *hp;
-	if (j < hbpl * 8 - 8 && y > 0) {
+	if (j < hbpl * 8 - 8 && (i > 0 || !reset)) {
 	  line_h2 |= *(hp - hbpl + 1);
-	  if (y > 1)
+	  if (i > 1 || !reset)
 	    line_h3 |= *(hp - hbpl - hbpl + 1);
 	}
 	if (s->options & JBG_LRLTWO) {
 	  /* two line template */
 	  do {
 	    line_h1 <<= 1;  line_h2 <<= 1;  line_h3 <<= 1;
-	    if (s->tx[plane])
-	      arith_encode(se, (((line_h2 >> 10) & 0x3e0) |
-				((line_h1 >> (4 + s->tx[plane])) & 0x010) |
+	    if (s->tx[plane]) {
+	      if ((unsigned) s->tx[plane] > j)
+		a = 0;
+	      else {
+		o = (j - s->tx[plane]) - (j & ~7L);
+		a = (hp[o >> 3] >> (7 - (o & 7))) & 1;
+		a <<= 4;
+	      }
+	      assert(s->tx[plane] > 23 ||
+		     a == ((line_h1 >> (4 + s->tx[plane])) & 0x010));
+	      arith_encode(se, (((line_h2 >> 10) & 0x3e0) | a |
 				((line_h1 >>  9) & 0x00f)),
 			   (line_h1 >> 8) & 1);
+	    }
 	    else
 	      arith_encode(se, (((line_h2 >> 10) & 0x3f0) |
 				((line_h1 >>  9) & 0x00f)),
@@ -1014,9 +1106,20 @@ static void encode_sde(struct jbg_enc_state *s,
 #endif
 	    /* statistics for adaptive template changes */
 	    if (!at_determined && j >= s->mx && j < hx-2) {
-	      c[0] += !(((line_h2 >> 6) ^ line_h1) & 0x100);
-	      for (t = 5; t <= s->mx; t++)
-		c[t] += !(((line_h1 >> t) ^ line_h1) & 0x100);
+	      p = (line_h1 & 0x100) != 0; /* current pixel value */
+	      c[0] += ((line_h2 & 0x4000) != 0) == p; /* default position */
+	      assert(!(((line_h2 >> 6) ^ line_h1) & 0x100) ==
+		     (((line_h2 & 0x4000) != 0) == p));
+	      for (t = 5; t <= s->mx && t <= j; t++) {
+		o = (j - t) - (j & ~7L);
+		a = (hp[o >> 3] >> (7 - (o & 7))) & 1;
+		assert(t > 23 ||
+		       (a == p) == !(((line_h1 >> t) ^ line_h1) & 0x100));
+		c[t] += a == p;
+	      }
+	      for (; t <= s->mx; t++) {
+		c[t] += 0 == p;
+	      }
 	      ++c_all;
 	    }
 	  } while (++j & 7 && j < hx);
@@ -1024,13 +1127,21 @@ static void encode_sde(struct jbg_enc_state *s,
 	  /* three line template */
 	  do {
 	    line_h1 <<= 1;  line_h2 <<= 1;  line_h3 <<= 1;
-	    if (s->tx[plane]) 
+	    if (s->tx[plane]) {
+	      if ((unsigned) s->tx[plane] > j)
+		a = 0;
+	      else {
+		o = (j - s->tx[plane]) - (j & ~7L);
+		a = (hp[o >> 3] >> (7 - (o & 7))) & 1;
+		a <<= 2;
+	      }
+	      assert(s->tx[plane] > 23 ||
+		     a == ((line_h1 >> (6 + s->tx[plane])) & 0x004));
 	      arith_encode(se, (((line_h3 >>  8) & 0x380) |
-				((line_h2 >> 12) & 0x078) |
-				((line_h1 >> (6 + s->tx[plane])) & 0x004) |
+				((line_h2 >> 12) & 0x078) | a |
 				((line_h1 >>  9) & 0x003)),
 			   (line_h1 >> 8) & 1);
-	    else
+	    } else
 	      arith_encode(se, (((line_h3 >>  8) & 0x380) |
 				((line_h2 >> 12) & 0x07c) |
 				((line_h1 >>  9) & 0x003)),
@@ -1040,9 +1151,20 @@ static void encode_sde(struct jbg_enc_state *s,
 #endif
 	    /* statistics for adaptive template changes */
 	    if (!at_determined && j >= s->mx && j < hx-2) {
-	      c[0] += !(((line_h2 >> 6) ^ line_h1) & 0x100);
-	      for (t = 3; t <= s->mx; t++)
-		c[t] += !(((line_h1 >> t) ^ line_h1) & 0x100);
+	      p = (line_h1 & 0x100) != 0; /* current pixel value */
+	      c[0] += ((line_h2 & 0x4000) != 0) == p; /* default position */
+	      assert(!(((line_h2 >> 6) ^ line_h1) & 0x100) ==
+		     (((line_h2 & 0x4000) != 0) == p));
+	      for (t = 3; t <= s->mx && t <= j; t++) {
+		o = (j - t) - (j & ~7L);
+		a = (hp[o >> 3] >> (7 - (o & 7))) & 1;
+		assert(t > 23 ||
+		       (a == p) == !(((line_h1 >> t) ^ line_h1) & 0x100));
+		c[t] += a == p;
+	      }
+	      for (; t <= s->mx; t++) {
+		c[t] += 0 == p;
+	      }
 	      ++c_all;
 	    }
 	  } while (++j & 7 && j < hx);
@@ -1073,7 +1195,7 @@ static void encode_sde(struct jbg_enc_state *s,
 	if (c_all - cmax < (c_all >> 3) &&
 	    cmax - c[s->tx[plane]] > c_all - cmax &&
 	    cmax - c[s->tx[plane]] > (c_all >> 4) &&
-	    /*                     ^ T.82 says here < !!! Typo ? */
+	    /*                     ^ T.82 said < here, fixed in Cor.1/25 */
 	    cmax - (c_all - c[s->tx[plane]]) > c_all - cmax &&
 	    cmax - (c_all - c[s->tx[plane]]) > (c_all >> 4) &&
 	    cmax - cmin > (c_all >> 2) &&
@@ -1101,7 +1223,7 @@ static void encode_sde(struct jbg_enc_state *s,
 	p0 = p1 = hp;
 	if (i < hl - 1 && y < hy - 1)
 	  p0 = hp + hbpl;
-	if (y > 1)
+	if (i > 1 || !reset)
 	  line_l3 = (long)*(q2 - lbpl) << 8;
 	else
 	  line_l3 = 0;
@@ -1110,7 +1232,7 @@ static void encode_sde(struct jbg_enc_state *s,
 	ltp = 1;
 	for (j = 0; j < lx && ltp; q1++, q2++) {
 	  if (j < lbpl * 8 - 8) {
-	    if (y > 1)
+	    if (i > 1 || !reset)
 	      line_l3 |= *(q2 - lbpl + 1);
 	    line_l2 |= *(q2 + 1);
 	    line_l1 |= *(q1 + 1);
@@ -1180,8 +1302,8 @@ static void encode_sde(struct jbg_enc_state *s,
       
 
       line_h1 = line_h2 = line_h3 = line_l1 = line_l2 = line_l3 = 0;
-      if (y > 0) line_h2 = (long)*(hp - hbpl) << 8;
-      if (y > 1) {
+      if (i > 0 || !reset) line_h2 = (long)*(hp - hbpl) << 8;
+      if (i > 1 || !reset) {
 	line_h3 = (long)*(hp - hbpl - hbpl) << 8;
 	line_l3 = (long)*(lp2 - lbpl) << 8;
       }
@@ -1191,12 +1313,12 @@ static void encode_sde(struct jbg_enc_state *s,
       /* encode line */
       for (j = 0; j < hx; lp1++, lp2++) {
 	if ((j >> 1) < lbpl * 8 - 8) {
-	  if (y > 1)
+	  if (i > 1 || !reset)
 	    line_l3 |= *(lp2 - lbpl + 1);
 	  line_l2 |= *(lp2 + 1);
 	  line_l1 |= *(lp1 + 1);
 	}
-	do {
+	do { /* ... while (j & 15 && j < hx) */
 
 	  assert(hp - (s->lhp[s->highres[plane]][plane] +
 		       (stripe * hl + i) * hbpl)
@@ -1206,15 +1328,15 @@ static void encode_sde(struct jbg_enc_state *s,
 			(stripe * ll + (i>>1)) * lbpl)
 		 == (ptrdiff_t) j >> 4);
 
-	  line_h1 |= *(hp++);
+	  line_h1 |= *hp;
 	  if (j < hbpl * 8 - 8) {
-	    if (y > 0) {
-	      line_h2 |= *(hp - hbpl);
-	      if (y > 1)
-		line_h3 |= *(hp - hbpl - hbpl);
+	    if (i > 0 || !reset) {
+	      line_h2 |= *(hp - hbpl + 1);
+	      if (i > 1 || !reset)
+		line_h3 |= *(hp - hbpl - hbpl + 1);
 	    }
 	  }
-	  do {
+	  do { /* ... while (j & 7 && j < hx) */
 	    line_l1 <<= 1;  line_l2 <<= 1;  line_l3 <<= 1;
 	    if (ltp && s->tp[j >> 1] < 2) {
 	      /* pixel are typical and have not to be encoded */
@@ -1227,7 +1349,7 @@ static void encode_sde(struct jbg_enc_state *s,
 	      j += 2;
 #endif
 	    } else
-	      do {
+	      do { /* ... while (++j & 1 && j < hx) */
 		line_h1 <<= 1;  line_h2 <<= 1;  line_h3 <<= 1;
 
 		/* deterministic prediction */
@@ -1286,12 +1408,20 @@ static void encode_sde(struct jbg_enc_state *s,
 		}
 
 		/* determine context */
-		if (s->tx[plane])
-		  cx = (((line_h1 >> 9)  & 0x003) |
-			((line_h1 >> (4 + s->tx[plane])) & 0x010) |
+		if (s->tx[plane]) {
+		  if ((unsigned) s->tx[plane] > j)
+		    a = 0;
+		  else {
+		    o = (j - s->tx[plane]) - (j & ~7L);
+		    a = (hp[o >> 3] >> (7 - (o & 7))) & 1;
+		    a <<= 4;
+		  }
+		  assert(s->tx[plane] > 23 ||
+			 a == ((line_h1 >> (4 + s->tx[plane])) & 0x010));
+		  cx = (((line_h1 >> 9)  & 0x003) | a |
 			((line_h2 >> 13) & 0x00c) |
 			((line_h3 >> 11) & 0x020));
-		else
+		} else
 		  cx = (((line_h1 >> 9)  & 0x003) |
 			((line_h2 >> 13) & 0x01c) |
 			((line_h3 >> 11) & 0x020));
@@ -1318,6 +1448,7 @@ static void encode_sde(struct jbg_enc_state *s,
 		
 	      } while (++j & 1 && j < hx);
 	  } while (j & 7 && j < hx);
+	  hp++;
 	} while (j & 15 && j < hx);
       } /* for (j = ...) */
 
@@ -1333,7 +1464,10 @@ static void encode_sde(struct jbg_enc_state *s,
   arith_encode_flush(se);
   jbg_buf_remove_zeros(s->sde[stripe][layer][plane]);
   jbg_buf_write(MARKER_ESC, s->sde[stripe][layer][plane]);
-  jbg_buf_write(MARKER_SDNORM, s->sde[stripe][layer][plane]);
+  jbg_buf_write((s->options & JBG_SDRST) ? MARKER_SDRST : MARKER_SDNORM,
+		s->sde[stripe][layer][plane]);
+  if (s->options & JBG_SDRST)
+    s->tx[plane] = 0;
 
   /* add ATMOVE */
   if (new_tx != -1) {
@@ -1381,12 +1515,18 @@ static void encode_sde(struct jbg_enc_state *s,
 static void resolution_reduction(struct jbg_enc_state *s, int plane,
 				 int higher_layer)
 {
-  unsigned long hx, hy, lx, ly, hbpl, lbpl;
+  unsigned long hl, ll, hx, hy, lx, ly, hbpl, lbpl;
   unsigned char *hp1, *hp2, *hp3, *lp;
   unsigned long line_h1, line_h2, line_h3, line_l2;
-  unsigned long i, j;
+  unsigned long y;  /* current line number in lowres image */
+  unsigned long i;  /* current line number within lowres stripe */
+  unsigned long j;  /* current column number in lowres image */
   int pix, k, l;
 
+  /* number of lines per stripe in highres image */
+  hl = s->l0 << higher_layer;
+  /* number of lines per stripe in lowres image */
+  ll = hl >> 1;
   /* number of pixels in highres image */
   hx = jbg_ceil_half(s->xd, s->d - higher_layer);
   hy = jbg_ceil_half(s->yd, s->d - higher_layer);
@@ -1394,8 +1534,8 @@ static void resolution_reduction(struct jbg_enc_state *s, int plane,
   lx = jbg_ceil_half(hx, 1);
   ly = jbg_ceil_half(hy, 1);
   /* bytes per line in highres and lowres image */
-  hbpl = (hx + 7) / 8;
-  lbpl = (lx + 7) / 8;
+  hbpl = jbg_ceil_half(hx, 3);
+  lbpl = jbg_ceil_half(lx, 3);
   /* pointers to first image bytes */
   hp2 = s->lhp[s->highres[plane]][plane];
   hp1 = hp2 + hbpl;
@@ -1424,40 +1564,44 @@ static void resolution_reduction(struct jbg_enc_state *s, int plane,
    *   76543210 76543210 76543210 76543210     line_l2
    *                            X
    */
-      
-  for (i = 0; i < ly; i++) {
-    if (2*i + 1 >= hy)
-      hp1 = hp2;
-    pix = 0;
-    line_h1 = line_h2 = line_h3 = line_l2 = 0;
-    for (j = 0; j < lbpl * 8; j += 8) {
-      *lp = 0;
-      line_l2 |= i ? lp[-lbpl] : 0;
-      for (k = 0; k < 8 && j + k < lx; k += 4) {
-	if (((j + k) >> 2) < hbpl) {
-	  line_h3 |= i ? *hp3 : 0;
-	  ++hp3;
-	  line_h2 |= *(hp2++);
-	  line_h1 |= *(hp1++);
-	}
-	for (l = 0; l < 4 && j + k + l < lx; l++) {
-	  line_h3 <<= 2;
-	  line_h2 <<= 2;
-	  line_h1 <<= 2;
-	  line_l2 <<= 1;
-	  pix = s->res_tab[((line_h1 >> 8) & 0x007) |
-			   ((line_h2 >> 5) & 0x038) |
-			   ((line_h3 >> 2) & 0x1c0) |
-			   (pix << 9) | ((line_l2 << 2) & 0xc00)];
-	  *lp = (*lp << 1) | pix;
+
+  for (y = 0; y < ly;) {
+    for (i = 0; i < ll && y < ly; i++, y++) {
+      if (2*y + 1 >= hy)
+	hp1 = hp2;
+      pix = 0;
+      line_h1 = line_h2 = line_h3 = line_l2 = 0;
+      for (j = 0; j < lbpl * 8; j += 8) {
+	*lp = 0;
+	if (i > 0 || (y > 0 && !(s->options & JBG_SDRST)))
+	  line_l2 |= *(lp-lbpl);
+	for (k = 0; k < 8 && j + k < lx; k += 4) {
+	  if (((j + k) >> 2) < hbpl) {
+	    if (i > 0 || (y > 0 && !(s->options & JBG_SDRST)))
+	      line_h3 |= *hp3;
+	    ++hp3;
+	    line_h2 |= *(hp2++);
+	    line_h1 |= *(hp1++);
+	  }
+	  for (l = 0; l < 4 && j + k + l < lx; l++) {
+	    line_h3 <<= 2;
+	    line_h2 <<= 2;
+	    line_h1 <<= 2;
+	    line_l2 <<= 1;
+	    pix = s->res_tab[((line_h1 >> 8) & 0x007) |
+			     ((line_h2 >> 5) & 0x038) |
+			     ((line_h3 >> 2) & 0x1c0) |
+			     (pix << 9) | ((line_l2 << 2) & 0xc00)];
+	    *lp = (*lp << 1) | pix;
+	  }
 	}
+	++lp;
       }
-      ++lp;
+      *(lp - 1) <<= lbpl * 8 - lx;
+      hp1 += hbpl;
+      hp2 += hbpl;
+      hp3 += hbpl;
     }
-    *(lp - 1) <<= lbpl * 8 - lx;
-    hp1 += hbpl;
-    hp2 += hbpl;
-    hp3 += hbpl;
   }
 
 #ifdef DEBUG
@@ -1482,16 +1626,15 @@ static void resolution_reduction(struct jbg_enc_state *s, int plane,
  * order to write the next SDE. It has first to generate the required
  * SDE and all SDEs which have to be encoded before this SDE can be
  * created. The problem here is that if we want to output a lower
- * resolution layer, we have to allpy the resolution reduction
- * algorithm in order to get it. As we try to safe as much memory as
+ * resolution layer, we have to apply the resolution reduction
+ * algorithm first to get it. As we try to safe as much memory as
  * possible, the resolution reduction will overwrite previous higher
  * resolution bitmaps. Consequently, we have to encode and buffer SDEs
  * which depend on higher resolution layers before we can start the
- * resolution reduction. All this logic about which SDE has to be
- * encoded before resolution reduction is allowed is handled here.
- * This approach might be a little bit more complex than alternative
- * ways to do it, but it allows us to do the encoding with the minimal
- * possible amount of temporary memory.
+ * resolution reduction. All the logic about which SDE has to be
+ * encoded before resolution reduction is allowed is handled
+ * here. This approach may be a bit more complex than alternative ways
+ * of doing it, but it minimizes the amount of temporary memory used.
  */
 static void output_sde(struct jbg_enc_state *s,
 		       unsigned long stripe, int layer, int plane)
@@ -1587,12 +1730,12 @@ void jbg_int2dppriv(unsigned char *dptable, const char *internal)
   int trans2[11] = { 1, 0, 3, 2, 10, 9, 8, 7, 6, 5, 4 };
   int trans3[12] = { 1, 0, 3, 2, 11, 10, 9, 8, 7, 6, 5, 4 };
   
-  for (i = 0; i < 1728; dptable[i++] = 0);
+  for (i = 0; i < 1728; dptable[i++] = 0) ;
 
 #define FILL_TABLE1(offset, len, trans) \
   for (i = 0; i < len; i++) { \
     k = 0; \
-    for (j = 0; j < 8; j++) \
+    for (j = 0; i >> j; j++) \
       k |= ((i >> j) & 1) << trans[j]; \
     dptable[(i + offset) >> 2] |= \
       (internal[k + offset] & 3) << ((3 - (i&3)) << 1); \
@@ -1623,7 +1766,7 @@ void jbg_dppriv2int(char *internal, const unsigned char *dptable)
 #define FILL_TABLE2(offset, len, trans) \
   for (i = 0; i < len; i++) { \
     k = 0; \
-    for (j = 0; j < 8; j++) \
+    for (j = 0; i >> j; j++) \
       k |= ((i >> j) & 1) << trans[j]; \
     internal[k + offset] = \
       (dptable[(i + offset) >> 2] >> ((3 - (i & 3)) << 1)) & 3; \
@@ -1644,20 +1787,19 @@ void jbg_dppriv2int(char *internal, const unsigned char *dptable)
  */
 void jbg_enc_out(struct jbg_enc_state *s)
 {
-  long bpl;
-  unsigned char bih[20];
+  unsigned long bpl;
+  unsigned char buf[20];
   unsigned long xd, yd, y;
   long ii[3], is[3], ie[3];    /* generic variables for the 3 nested loops */ 
   unsigned long stripe;
   int layer, plane;
   int order;
   unsigned char dpbuf[1728];
-  extern char jbg_dptable[];
 
   /* some sanity checks */
   s->order &= JBG_HITOLO | JBG_SEQ | JBG_ILEAVE | JBG_SMID;
   order = s->order & (JBG_SEQ | JBG_ILEAVE | JBG_SMID);
-  if (index[order][0] < 0)
+  if (iindex[order][0] < 0)
     s->order = order = JBG_SMID | JBG_ILEAVE;
   if (s->options & JBG_DPON && s->dppriv != jbg_dptable)
     s->options |= JBG_DPPRIV;
@@ -1669,29 +1811,65 @@ void jbg_enc_out(struct jbg_enc_state *s)
   if (s->d > 255 || s->d < 0 || s->dh > s->d || s->dh < 0 ||
       s->dl < 0 || s->dl > s->dh || s->planes < 0 || s->planes > 255)
     return;
+  /* prevent uint32 overflow: s->l0 * 2 ^ s->d < 2 ^ 32 */
+  if (s->d > 31 || (s->d != 0 && s->l0 >= (1UL << (32 - s->d))))
+    return;
+  if (s->yd1 < s->yd)
+    s->yd1 = s->yd;
+  if (s->yd1 > s->yd)
+    s->options |= JBG_VLENGTH;
 
   /* ensure correct zero padding of bitmap at the final byte of each line */
   if (s->xd & 7) {
-    bpl = (s->xd + 7) / 8;     /* bytes per line */
+    bpl = jbg_ceil_half(s->xd, 3);     /* bytes per line */
     for (plane = 0; plane < s->planes; plane++)
       for (y = 0; y < s->yd; y++)
 	s->lhp[0][plane][y * bpl + bpl - 1] &= ~((1 << (8 - (s->xd & 7))) - 1);
   }
 
+  /* prepare BIH */
+  buf[0] = s->dl;
+  buf[1] = s->dh;
+  buf[2] = s->planes;
+  buf[3] = 0;
+  xd = jbg_ceil_half(s->xd, s->d - s->dh);
+  yd = jbg_ceil_half(s->yd1, s->d - s->dh);
+  buf[4] = xd >> 24;
+  buf[5] = (xd >> 16) & 0xff;
+  buf[6] = (xd >> 8) & 0xff;
+  buf[7] = xd & 0xff;
+  buf[8] = yd >> 24;
+  buf[9] = (yd >> 16) & 0xff;
+  buf[10] = (yd >> 8) & 0xff;
+  buf[11] = yd & 0xff;
+  buf[12] = s->l0 >> 24;
+  buf[13] = (s->l0 >> 16) & 0xff;
+  buf[14] = (s->l0 >> 8) & 0xff;
+  buf[15] = s->l0 & 0xff;
+  buf[16] = s->mx;
+  buf[17] = s->my;
+  buf[18] = s->order;
+  buf[19] = s->options & 0x7f;
+
+#if 0
+  /* sanitize L0 (if it was set to 0xffffffff for T.85-style NEWLEN tests) */
+  if (s->l0 > (s->yd >> s->d))
+    s->l0 = s->yd >> s->d;
+#endif
+
   /* calculate number of stripes that will be required */
-  s->stripes = ((s->yd >> s->d) + 
-		((((1UL << s->d) - 1) & s->xd) != 0) + s->l0 - 1) / s->l0;
+  s->stripes = jbg_stripes(s->l0, s->yd, s->d);
 
   /* allocate buffers for SDE pointers */
   if (s->sde == NULL) {
     s->sde = (struct jbg_buf ****)
-      checked_malloc(s->stripes * sizeof(struct jbg_buf ***));
+      checked_malloc(s->stripes, sizeof(struct jbg_buf ***));
     for (stripe = 0; stripe < s->stripes; stripe++) {
       s->sde[stripe] = (struct jbg_buf ***)
-	checked_malloc((s->d + 1) * sizeof(struct jbg_buf **));
+	checked_malloc(s->d + 1, sizeof(struct jbg_buf **));
       for (layer = 0; layer < s->d + 1; layer++) {
 	s->sde[stripe][layer] = (struct jbg_buf **)
-	  checked_malloc(s->planes * sizeof(struct jbg_buf *));
+	  checked_malloc(s->planes, sizeof(struct jbg_buf *));
 	for (plane = 0; plane < s->planes; plane++)
 	  s->sde[stripe][layer][plane] = SDE_TODO;
       }
@@ -1699,29 +1877,7 @@ void jbg_enc_out(struct jbg_enc_state *s)
   }
 
   /* output BIH */
-  bih[0] = s->dl;
-  bih[1] = s->dh;
-  bih[2] = s->planes;
-  bih[3] = 0;
-  xd = jbg_ceil_half(s->xd, s->d - s->dh);
-  yd = jbg_ceil_half(s->yd, s->d - s->dh);
-  bih[4] = xd >> 24;
-  bih[5] = (xd >> 16) & 0xff;
-  bih[6] = (xd >> 8) & 0xff;
-  bih[7] = xd & 0xff;
-  bih[8] = yd >> 24;
-  bih[9] = (yd >> 16) & 0xff;
-  bih[10] = (yd >> 8) & 0xff;
-  bih[11] = yd & 0xff;
-  bih[12] = s->l0 >> 24;
-  bih[13] = (s->l0 >> 16) & 0xff;
-  bih[14] = (s->l0 >> 8) & 0xff;
-  bih[15] = s->l0 & 0xff;
-  bih[16] = s->mx;
-  bih[17] = s->my;
-  bih[18] = s->order;
-  bih[19] = s->options & 0x7f;
-  s->data_out(bih, 20, s->file);
+  s->data_out(buf, 20, s->file);
   if ((s->options & (JBG_DPON | JBG_DPPRIV | JBG_DPLAST)) ==
       (JBG_DPON | JBG_DPPRIV)) {
     /* write private table */
@@ -1751,27 +1907,68 @@ void jbg_enc_out(struct jbg_enc_state *s)
    * stripe depends on the option flags.
    */
 
-  /* start and end value vor each loop */
-  is[index[order][STRIPE]] = 0;
-  ie[index[order][STRIPE]] = s->stripes - 1;
-  is[index[order][LAYER]] = s->dl;
-  ie[index[order][LAYER]] = s->dh;
-  is[index[order][PLANE]] = 0;
-  ie[index[order][PLANE]] = s->planes - 1;
+  /* start and end value for each loop */
+  is[iindex[order][STRIPE]] = 0;
+  ie[iindex[order][STRIPE]] = s->stripes - 1;
+  is[iindex[order][LAYER]] = s->dl;
+  ie[iindex[order][LAYER]] = s->dh;
+  is[iindex[order][PLANE]] = 0;
+  ie[iindex[order][PLANE]] = s->planes - 1;
 
   for (ii[0] = is[0]; ii[0] <= ie[0]; ii[0]++)
     for (ii[1] = is[1]; ii[1] <= ie[1]; ii[1]++)
       for (ii[2] = is[2]; ii[2] <= ie[2]; ii[2]++) {
 	
-	stripe = ii[index[order][STRIPE]];
+	stripe = ii[iindex[order][STRIPE]];
 	if (s->order & JBG_HITOLO)
-	  layer = s->dh - (ii[index[order][LAYER]] - s->dl);
+	  layer = s->dh - (ii[iindex[order][LAYER]] - s->dl);
 	else
-	  layer = ii[index[order][LAYER]];
-	plane = ii[index[order][PLANE]];
+	  layer = ii[iindex[order][LAYER]];
+	plane = ii[iindex[order][PLANE]];
+
+	/* output comment marker segment if there is any pending */
+	if (s->comment) {
+	  buf[0] = MARKER_ESC;
+	  buf[1] = MARKER_COMMENT;
+	  buf[2] = s->comment_len >> 24;
+	  buf[3] = (s->comment_len >> 16) & 0xff;
+	  buf[4] = (s->comment_len >> 8) & 0xff;
+	  buf[5] = s->comment_len & 0xff;
+	  s->data_out(buf, 6, s->file);
+	  s->data_out(s->comment, s->comment_len, s->file);
+	  s->comment = NULL;
+	}
 
 	output_sde(s, stripe, layer, plane);
 
+	/*
+	 * When we generate a NEWLEN test case (s->yd1 > s->yd), output
+	 * NEWLEN after last stripe if we have only a single
+	 * resolution layer or plane (see ITU-T T.85 profile), otherwise
+	 * output NEWLEN before last stripe.
+	 */
+	if (s->yd1 > s->yd &&
+	    (stripe == s->stripes - 1 ||
+	     (stripe == s->stripes - 2 && 
+	      (s->dl != s->dh || s->planes > 1)))) {
+	  s->yd1 = s->yd;
+	  yd = jbg_ceil_half(s->yd, s->d - s->dh);
+	  buf[0] = MARKER_ESC;
+	  buf[1] = MARKER_NEWLEN;
+	  buf[2] = yd >> 24;
+	  buf[3] = (yd >> 16) & 0xff;
+	  buf[4] = (yd >> 8) & 0xff;
+	  buf[5] = yd & 0xff;
+	  s->data_out(buf, 6, s->file);
+#ifdef DEBUG
+	  fprintf(stderr, "NEWLEN: yd=%lu\n", yd);
+#endif
+	  if (stripe == s->stripes - 1) {
+	    buf[1] = MARKER_SDNORM;
+	    s->data_out(buf, 2, s->file);
+	  }
+	}
+
       }
 
   return;
@@ -1784,7 +1981,7 @@ void jbg_enc_free(struct jbg_enc_state *s)
   int layer, plane;
 
 #ifdef DEBUG
-  fprintf(stderr, "jbg_enc_free(%p)\n", s);
+  fprintf(stderr, "jbg_enc_free(%p)\n", (void *) s);
 #endif
 
   /* clear buffers for SDEs */
@@ -1820,23 +2017,24 @@ void jbg_enc_free(struct jbg_enc_state *s)
       checked_free(s->lhp[1][plane]);
     checked_free(s->lhp[1]);
   }
-
+  
+  /* clear buffer for index of highres image in lhp */
+  checked_free(s->highres);
+  
   return;
 }
 
 
 /*
- * Convert the error codes used by jbg_dec_in() into a string
- * written in the selected language and character set.
+ * Convert the error codes used by jbg_dec_in() into an English ASCII string
  */
-const char *jbg_strerror(int errnum, int language)
+const char *jbg_strerror(int errnum)
 {
-  if (errnum < 0 || errnum >= NEMSG)
+  errnum >>= 4;
+  if (errnum < 0 || (unsigned) errnum >= sizeof(errmsg)/sizeof(errmsg[0]))
     return "Unknown error code passed to jbg_strerror()";
-  if (language < 0 || language >= NEMSG_LANG)
-    return "Unknown language code passed to jbg_strerror()";
 
-  return errmsg[language][errnum];
+  return errmsg[errnum];
 }
 
 
@@ -1880,8 +2078,8 @@ void jbg_dec_maxsize(struct jbg_dec_state *s, unsigned long xmax,
  * Decode the new len PSDC bytes to which data points and add them to
  * the current stripe. Return the number of bytes which have actually
  * been read (this will be less than len if a marker segment was 
- * part of the data or if the final byte was 0xff were this code
- * can not determine, whether we have a marker segment.
+ * part of the data or if the final byte was 0xff, in which case
+ * this code cannot determine whether we have a marker segment).
  */
 static size_t decode_pscd(struct jbg_dec_state *s, unsigned char *data,
 			  size_t len)
@@ -1894,13 +2092,15 @@ static size_t decode_pscd(struct jbg_dec_state *s, unsigned char *data,
   register unsigned long line_l1, line_l2, line_l3;
   struct jbg_ardec_state *se;
   unsigned long x;
+  long o;
+  unsigned a;
   int n;
-  int pix, cx = 0, slntp, shift, tx;
+  int pix, cx = 0, slntp, tx;
 
   /* SDE loop variables */
-  stripe = s->ii[index[s->order & 7][STRIPE]];
-  layer = s->ii[index[s->order & 7][LAYER]];
-  plane = s->ii[index[s->order & 7][PLANE]];
+  stripe = s->ii[iindex[s->order & 7][STRIPE]];
+  layer = s->ii[iindex[s->order & 7][LAYER]];
+  plane = s->ii[iindex[s->order & 7][PLANE]];
 
   /* forward data to arithmetic decoder */
   se = s->s[plane] + layer - s->dl;
@@ -1920,8 +2120,8 @@ static size_t decode_pscd(struct jbg_dec_state *s, unsigned char *data,
   lx = jbg_ceil_half(hx, 1);
   ly = jbg_ceil_half(hy, 1);
   /* bytes per line in highres and lowres image */
-  hbpl = (hx + 7) / 8;
-  lbpl = (lx + 7) / 8;
+  hbpl = jbg_ceil_half(hx, 3);
+  lbpl = jbg_ceil_half(lx, 3);
   /* pointer to highres and lowres image bytes */
   hp  = s->lhp[ layer    & 1][plane] + (stripe * hl + s->i) * hbpl +
     (s->x >> 3);
@@ -1938,19 +2138,18 @@ static size_t decode_pscd(struct jbg_dec_state *s, unsigned char *data,
   line_l3 = s->line_l3;
   x = s->x;
 
-  if (s->x == 0 && s->i == 0 &&
-      (stripe == 0 || s->reset[plane][layer - s->dl])) {
-    s->tx[plane][layer - s->dl] = s->ty[plane][layer - s->dl] = 0;
-    if (s->pseudo)
-      s->lntp[plane][layer - s->dl] = 1;
-  }
-
 #ifdef DEBUG
   if (s->x == 0 && s->i == 0 && s->pseudo)
     fprintf(stderr, "decode_pscd(%p, %p, %ld): s/d/p = %2lu/%2u/%2u\n",
-	    s, data, (long) len, stripe, layer, plane);
+	    (void *) s, (void *) data, (long) len, stripe, layer, plane);
 #endif
 
+  if (s->x == 0 && s->i == 0 &&
+      (stripe == 0 || s->reset[plane][layer - s->dl]) && s->pseudo) {
+    s->tx[plane][layer - s->dl] = s->ty[plane][layer - s->dl] = 0;
+    s->lntp[plane][layer - s->dl] = 1;
+  }
+
   if (layer == 0) {
 
     /*
@@ -1960,7 +2159,7 @@ static size_t decode_pscd(struct jbg_dec_state *s, unsigned char *data,
     for (; s->i < hl && y < hy; s->i++, y++) {
 
       /* adaptive template changes */
-      if (x == 0)
+      if (x == 0 && s->pseudo)
 	for (n = 0; n < s->at_moves; n++)
 	  if (s->at_line[n] == s->i) {
 	    s->tx[plane][layer - s->dl] = s->at_tx[n];
@@ -1971,19 +2170,16 @@ static size_t decode_pscd(struct jbg_dec_state *s, unsigned char *data,
 #endif
 	  }
       tx = s->tx[plane][layer - s->dl];
-      shift =  tx - ((s->options & JBG_LRLTWO) ? 5 : 3);
+      assert(tx >= 0); /* i.e., tx can safely be cast to unsigned */
 
       /* typical prediction */
       if (s->options & JBG_TPBON && s->pseudo) {
 	slntp = arith_decode(se, (s->options & JBG_LRLTWO) ? TPB2CX : TPB3CX);
-	if (se->result == JBG_MORE || se->result == JBG_MARKER)
+	if (slntp < 0)
 	  goto leave;
 	s->lntp[plane][layer - s->dl] =
 	  !(slntp ^ s->lntp[plane][layer - s->dl]);
-	if (s->lntp[plane][layer - s->dl]) {
-	  /* this line is 'not typical' and has to be coded completely */
-	  s->pseudo = 0;
-	} else {
+	if (!s->lntp[plane][layer - s->dl]) {
 	  /* this line is 'typical' (i.e. identical to the previous one) */
 	  p1 = hp;
 	  if (s->i == 0 && (stripe == 0 || s->reset[plane][layer - s->dl]))
@@ -1995,7 +2191,9 @@ static size_t decode_pscd(struct jbg_dec_state *s, unsigned char *data,
 	  hp += hbpl;
 	  continue;
 	}
+	/* this line is 'not typical' and has to be coded completely */
       }
+      s->pseudo = 0;
       
       /*
        * Layout of the variables line_h1, line_h2, line_h3, which contain
@@ -2071,14 +2269,24 @@ static size_t decode_pscd(struct jbg_dec_state *s, unsigned char *data,
 	if (s->options & JBG_LRLTWO) {
 	  /* two line template */
 	  do {
-	    if (tx)
-	      pix = arith_decode(se, (((line_h2 >> 9) & 0x3e0) |
-				      ((line_h1 >> shift) & 0x010) |
+	    if (tx) {
+	      if ((unsigned) tx > x)
+		a = 0;
+	      else if (tx < 8)
+		a = ((line_h1 >> (tx - 5)) & 0x010);
+	      else {
+		o = (x - tx) - (x & ~7L);
+		a = (hp[o >> 3] >> (7 - (o & 7))) & 1;
+		a <<= 4;
+	      }
+	      assert(tx > 31 ||
+		     a == ((line_h1 >> (tx - 5)) & 0x010));
+	      pix = arith_decode(se, (((line_h2 >> 9) & 0x3e0) | a |
 				      (line_h1 & 0x00f)));
-	    else
+	    } else
 	      pix = arith_decode(se, (((line_h2 >> 9) & 0x3f0) |
 				      (line_h1 & 0x00f)));
-	    if (se->result == JBG_MORE || se->result == JBG_MARKER)
+	    if (pix < 0)
 	      goto leave;
 	    line_h1 = (line_h1 << 1) | pix;
 	    line_h2 <<= 1;
@@ -2086,16 +2294,26 @@ static size_t decode_pscd(struct jbg_dec_state *s, unsigned char *data,
 	} else {
 	  /* three line template */
 	  do {
-	    if (tx) 
+	    if (tx) {
+	      if ((unsigned) tx > x)
+		a = 0;
+	      else if (tx < 8)
+		a = ((line_h1 >> (tx - 3)) & 0x004);
+	      else {
+		o = (x - tx) - (x & ~7L);
+		a = (hp[o >> 3] >> (7 - (o & 7))) & 1;
+		a <<= 2;
+	      }
+	      assert(tx > 31 ||
+		     a == ((line_h1 >> (tx - 3)) & 0x004));
 	      pix = arith_decode(se, (((line_h3 >>  7) & 0x380) |
-				      ((line_h2 >> 11) & 0x078) |
-				      ((line_h1 >> shift) & 0x004) |
+				      ((line_h2 >> 11) & 0x078) | a |
 				      (line_h1 & 0x003)));
-	    else
+	    } else
 	      pix = arith_decode(se, (((line_h3 >>  7) & 0x380) |
 				      ((line_h2 >> 11) & 0x07c) |
 				      (line_h1 & 0x003)));
-	    if (se->result == JBG_MORE || se->result == JBG_MARKER)
+	    if (pix < 0)
 	      goto leave;
 	    
 	    line_h1 = (line_h1 << 1) | pix;
@@ -2130,20 +2348,17 @@ static size_t decode_pscd(struct jbg_dec_state *s, unsigned char *data,
 #endif
 	  }
       tx = s->tx[plane][layer - s->dl];
-      shift = tx - 3;
 
       /* handle lower border of low-resolution image */
       if ((s->i >> 1) >= ll - 1 || (y >> 1) >= ly - 1)
 	lp1 = lp2;
 
       /* typical prediction */
-      if (s->options & JBG_TPDON && s->pseudo) {
-	s->lntp[plane][layer - s->dl] = arith_decode(se, TPDCX);
-	if (se->result == JBG_MORE || se->result == JBG_MARKER)
+      if ((s->options & JBG_TPDON) && s->pseudo) {
+	if ((s->lntp[plane][layer - s->dl] = arith_decode(se, TPDCX)) < 0)
 	  goto leave;
-	s->pseudo = 0;
       }
-
+      s->pseudo = 0;
 
       /*
        * Layout of the variables line_h1, line_h2, line_h3, which contain
@@ -2254,7 +2469,7 @@ static size_t decode_pscd(struct jbg_dec_state *s, unsigned char *data,
 		if (pix & 2) {
 		  if (tx)
 		    cx = ((line_h1         & 0x003) |
-			  (((line_h1 << 2) >> shift) & 0x010) |
+			  (((line_h1 << 2) >> (tx - 3)) & 0x010) |
 			  ((line_h2 >> 12) & 0x00c) |
 			  ((line_h3 >> 10) & 0x020));
 		  else
@@ -2270,7 +2485,7 @@ static size_t decode_pscd(struct jbg_dec_state *s, unsigned char *data,
 		  cx |= (y & 1) << 11;
 
 		  pix = arith_decode(se, cx);
-		  if (se->result == JBG_MORE || se->result == JBG_MARKER)
+		  if (pix < 0)
 		    goto leave;
 		}
 
@@ -2316,23 +2531,38 @@ static size_t decode_pscd(struct jbg_dec_state *s, unsigned char *data,
 
 
 /*
- * Provide a new BIE fragment to the decoder.
+ * Provide to the decoder a new BIE fragment of len bytes starting at data.
+ *
+ * Unless cnt is NULL, *cnt will contain the number of actually read bytes
+ * on return.
+ *
+ * Normal return values:
+ *
+ *   JBG_EAGAIN      All data bytes provided so far have been processed
+ *                   (*cnt == len) but the end of the data stream has
+ *                   not yet been recognized. Call the function again
+ *                   with additional BIE bytes.
+ *   JBG_EOK         The function has reached the end of a and
+ *                   a full image has been decoded. The function can
+ *                   be called again with data from the next BIE, if
+ *                   there exists one, in order to get to a higher
+ *                   resolution layer. The remaining len - *cnt bytes
+ *                   of the previous data block will then have to passed
+ *                   to this function again if len > *cnt.
+ *   JBG_EOK_INTR    Parsing the BIE has been interrupted as had been
+ *                   requested by a jbg_dec_maxsize() specification.
+ *                   This function can be called again with the
+ *                   rest of the BIE to continue the decoding process.
+ *                   The remaining len - *cnt bytes of the previous
+ *                   data block will then have to be passed to this
+ *                   function again if len > *cnt.
  *
- * If cnt is not NULL, then *cnt will contain after the call the
- * number of actually read bytes. If the data was not complete, then
- * the return value will be JBG_EAGAIN and *cnt == len. In case this
- * function has returned with JBG_EOK, then it has reached the end of
- * a BIE but it can be called again with data from the next BIE if
- * there exists one in order to get to a higher resolution layer. In
- * case the return value was JBG_EOK_INTR then this function can be
- * called again with the rest of the BIE, because parsing the BIE has
- * been interrupted by a jbg_dec_maxsize() specification. In both
- * cases the remaining len - *cnt bytes of the previous block will
- * have to passed to this function again (if len > *cnt). In case of
- * any other return value than JBG_EOK, JBG_EOK_INTR or JBG_EAGAIN, a
- * serious problem has occured and the only function you should call
- * is jbg_dec_free() in order to remove the mess (and probably
- * jbg_strerror() in order to find out what to tell the user).
+ * Any other return value indicates that the decoding process was
+ * aborted by a serious problem and the only function you can then
+ * still call is jbg_dec_free() in order to remove the mess, and
+ * jbg85_strerror() to find out what to tell the user. (Looking at the
+ * least significant bits of the return value will provide additional
+ * information by identifying which test exactly has failed.)
  */
 int jbg_dec_in(struct jbg_dec_state *s, unsigned char *data, size_t len,
 	       size_t *cnt)
@@ -2340,9 +2570,8 @@ int jbg_dec_in(struct jbg_dec_state *s, unsigned char *data, size_t len,
   int i, j, required_length;
   unsigned long x, y;
   unsigned long is[3], ie[3];
-  long hsize, lsize;
-  extern char jbg_dptable[];
   size_t dummy_cnt;
+  unsigned char *dppriv;
 
   if (!cnt) cnt = &dummy_cnt;
   *cnt = 0;
@@ -2354,92 +2583,112 @@ int jbg_dec_in(struct jbg_dec_state *s, unsigned char *data, size_t len,
       s->buffer[s->bie_len++] = data[(*cnt)++];
     if (s->bie_len < 20) 
       return JBG_EAGAIN;
-    if (s->buffer[1] < s->buffer[0])
-      return JBG_EINVAL;
     /* test whether this looks like a valid JBIG header at all */
-    if (s->buffer[3] != 0 || (s->buffer[18] & 0xf0) != 0 ||
-	(s->buffer[19] & 0x80) != 0)
-      return JBG_EINVAL;
+    if (s->buffer[1] < s->buffer[0])
+      return JBG_EINVAL | 1;
+    if (s->buffer[3] != 0)           return JBG_EINVAL | 2; /* padding != 0 */
+    if ((s->buffer[18] & 0xf0) != 0) return JBG_EINVAL | 3; /* padding != 0 */
+    if ((s->buffer[19] & 0x80) != 0) return JBG_EINVAL | 4; /* padding != 0 */
     if (s->buffer[0] != s->d + 1)
-      return JBG_ENOCONT;
+      return JBG_ENOCONT | 1;
     s->dl = s->buffer[0];
     s->d = s->buffer[1];
     if (s->dl == 0)
       s->planes = s->buffer[2];
     else
       if (s->planes != s->buffer[2])
-	return JBG_ENOCONT;
+	return JBG_ENOCONT | 2;
     x = (((long) s->buffer[ 4] << 24) | ((long) s->buffer[ 5] << 16) |
 	 ((long) s->buffer[ 6] <<  8) | (long) s->buffer[ 7]);
     y = (((long) s->buffer[ 8] << 24) | ((long) s->buffer[ 9] << 16) |
 	 ((long) s->buffer[10] <<  8) | (long) s->buffer[11]);
     if (s->dl != 0 && ((s->xd << (s->d - s->dl + 1)) != x &&
 		       (s->yd << (s->d - s->dl + 1)) != y))
-      return JBG_ENOCONT;
+      return JBG_ENOCONT | 3;
     s->xd = x;
     s->yd = y;
     s->l0 = (((long) s->buffer[12] << 24) | ((long) s->buffer[13] << 16) |
 	     ((long) s->buffer[14] <<  8) | (long) s->buffer[15]);
-    if (!s->planes || !s->xd || !s->yd || !s->l0)
-      return JBG_EINVAL;
+    /* ITU-T T.85 trick not directly implemented by decoder; for full
+     * T.85 compatibility with respect to all NEWLEN marker scenarios,
+     * preprocess BIE with jbg_newlen() before passing it to the decoder,
+     * or consider using the decoder found in jbig85.c instead. */
+    if (s->yd == 0xffffffff)
+      return JBG_EIMPL | 1;
+    if (!s->planes) return JBG_EINVAL | 5;
+    if (!s->xd)     return JBG_EINVAL | 6;
+    if (!s->yd)     return JBG_EINVAL | 7;
+    if (!s->l0)     return JBG_EINVAL | 8;
+    /* prevent uint32 overflow: s->l0 * 2 ^ s->d < 2 ^ 32 */
+    if (s->d > 31)
+      return JBG_EIMPL | 2;
+    if ((s->d != 0 && s->l0 >= (1UL << (32 - s->d))))
+      return JBG_EIMPL | 3;
     s->mx = s->buffer[16];
     if (s->mx > 127)
-      return JBG_EINVAL;
+      return JBG_EINVAL | 9;
     s->my = s->buffer[17];
-    if (s->mx > 32 || s->my > 0) 
-      return JBG_EIMPL;
+#if 0
+    if (s->my > 0)
+      return JBG_EIMPL | 4;
+#endif
     s->order = s->buffer[18];
-    if (index[s->order & 7][0] < 0)
-      return JBG_EINVAL;
+    if (iindex[s->order & 7][0] < 0)
+      return JBG_EINVAL | 10;
     /* HITOLO and SEQ currently not yet implemented */
     if (s->dl != s->d && (s->order & JBG_HITOLO || s->order & JBG_SEQ))
-      return JBG_EIMPL;
+      return JBG_EIMPL | 5;
     s->options = s->buffer[19];
 
     /* calculate number of stripes that will be required */
-    s->stripes = ((s->yd >> s->d) +
-		  ((((1UL << s->d) - 1) & s->xd) != 0) + s->l0 - 1) / s->l0;
-
+    s->stripes = jbg_stripes(s->l0, s->yd, s->d);
+    
     /* some initialization */
-    s->ii[index[s->order & 7][STRIPE]] = 0;
-    s->ii[index[s->order & 7][LAYER]] = s->dl;
-    s->ii[index[s->order & 7][PLANE]] = 0;
-    /* bytes required for resolution layer D and D-1 */
-    hsize = ((s->xd + 7) / 8) * s->yd;
-    lsize = ((jbg_ceil_half(s->xd, 1) + 7) / 8) *
-      jbg_ceil_half(s->yd, 1);
+    s->ii[iindex[s->order & 7][STRIPE]] = 0;
+    s->ii[iindex[s->order & 7][LAYER]] = s->dl;
+    s->ii[iindex[s->order & 7][PLANE]] = 0;
     if (s->dl == 0) {
-      s->s = checked_malloc(s->planes * sizeof(struct jbg_ardec_state *));
-      s->tx = checked_malloc(s->planes * sizeof(int *));
-      s->ty = checked_malloc(s->planes * sizeof(int *));
-      s->reset = checked_malloc(s->planes * sizeof(int *));
-      s->lntp = checked_malloc(s->planes * sizeof(int *));
-      s->lhp[0] = checked_malloc(s->planes * sizeof(unsigned char *));
-      s->lhp[1] = checked_malloc(s->planes * sizeof(unsigned char *));
+      s->s      = (struct jbg_ardec_state **)
+	checked_malloc(s->planes, sizeof(struct jbg_ardec_state *));
+      s->tx     = (int **) checked_malloc(s->planes, sizeof(int *));
+      s->ty     = (int **) checked_malloc(s->planes, sizeof(int *));
+      s->reset  = (int **) checked_malloc(s->planes, sizeof(int *));
+      s->lntp   = (int **) checked_malloc(s->planes, sizeof(int *));
+      s->lhp[0] = (unsigned char **)
+	checked_malloc(s->planes, sizeof(unsigned char *));
+      s->lhp[1] = (unsigned char **)
+	checked_malloc(s->planes, sizeof(unsigned char *));
       for (i = 0; i < s->planes; i++) {
-	s->s[i] = checked_malloc((s->d - s->dl + 1) *
-				 sizeof(struct jbg_ardec_state));
-	s->tx[i] = checked_malloc((s->d - s->dl + 1) * sizeof(int));
-	s->ty[i] = checked_malloc((s->d - s->dl + 1) * sizeof(int));
-	s->reset[i] = checked_malloc((s->d - s->dl + 1) * sizeof(int));
-	s->lntp[i] = checked_malloc((s->d - s->dl + 1) * sizeof(int));
-	s->lhp[s->d    &1][i] = checked_malloc(sizeof(unsigned char) * hsize);
-	s->lhp[(s->d-1)&1][i] = checked_malloc(sizeof(unsigned char) * lsize);
+	s->s[i]     = (struct jbg_ardec_state *)
+	  checked_malloc(s->d - s->dl + 1, sizeof(struct jbg_ardec_state));
+	s->tx[i]    = (int *) checked_malloc(s->d - s->dl + 1, sizeof(int));
+	s->ty[i]    = (int *) checked_malloc(s->d - s->dl + 1, sizeof(int));
+	s->reset[i] = (int *) checked_malloc(s->d - s->dl + 1, sizeof(int));
+	s->lntp[i]  = (int *) checked_malloc(s->d - s->dl + 1, sizeof(int));
+	s->lhp[ s->d    & 1][i] = (unsigned char *)
+	  checked_malloc(s->yd, jbg_ceil_half(s->xd, 3));
+	s->lhp[(s->d-1) & 1][i] = (unsigned char *)
+	  checked_malloc(jbg_ceil_half(s->yd, 1), jbg_ceil_half(s->xd, 1+3));
       }
     } else {
       for (i = 0; i < s->planes; i++) {
-	s->s[i] = checked_realloc(s->s[i], (s->d - s->dl + 1) *
-				  sizeof(struct jbg_ardec_state));
-	s->tx[i] = checked_realloc(s->tx[i], (s->d - s->dl + 1) * sizeof(int));
-	s->ty[i] = checked_realloc(s->ty[i], (s->d - s->dl + 1) * sizeof(int));
-	s->reset[i] = checked_realloc(s->reset[i],
-				      (s->d - s->dl +1) * sizeof(int));
-	s->lntp[i] = checked_realloc(s->lntp[i],
-				     (s->d - s->dl +1) * sizeof(int));
-	s->lhp[s->d    &1][i] = checked_realloc(s->lhp[s->d    & 1][i],
-						sizeof(unsigned char) * hsize);
-	s->lhp[(s->d-1)&1][i] = checked_realloc(s->lhp[(s->d-1)&1][i],
-						sizeof(unsigned char) * lsize);
+	s->s[i]     = (struct jbg_ardec_state *)
+	  checked_realloc(s->s[i], s->d - s->dl + 1,
+			  sizeof(struct jbg_ardec_state));
+	s->tx[i]    = (int *) checked_realloc(s->tx[i],
+					      s->d - s->dl + 1, sizeof(int));
+	s->ty[i]    = (int *) checked_realloc(s->ty[i],
+					      s->d - s->dl + 1, sizeof(int));
+	s->reset[i] = (int *) checked_realloc(s->reset[i],
+					      s->d - s->dl + 1, sizeof(int));
+	s->lntp[i]  = (int *) checked_realloc(s->lntp[i],
+					      s->d - s->dl + 1, sizeof(int));
+	s->lhp[ s->d    & 1][i] = (unsigned char *)
+	  checked_realloc(s->lhp[ s->d    & 1][i],
+			  s->yd, jbg_ceil_half(s->xd, 3));
+	s->lhp[(s->d-1) & 1][i] = (unsigned char *)
+	  checked_realloc(s->lhp[(s->d-1) & 1][i],
+			  jbg_ceil_half(s->yd, 1), jbg_ceil_half(s->xd, 1+3));
       }
     }
     for (i = 0; i < s->planes; i++)
@@ -2460,13 +2709,16 @@ int jbg_dec_in(struct jbg_dec_state *s, unsigned char *data, size_t len,
       (s->options & (JBG_DPON | JBG_DPPRIV | JBG_DPLAST)) ==
       (JBG_DPON | JBG_DPPRIV)) {
     assert(s->bie_len >= 20);
+    if (!s->dppriv || s->dppriv == jbg_dptable)
+      s->dppriv = (char *) checked_malloc(1728, sizeof(char));
     while (s->bie_len < 20 + 1728 && *cnt < len)
-      s->buffer[s->bie_len++ - 20] = data[(*cnt)++];
+      s->dppriv[s->bie_len++ - 20] = data[(*cnt)++];
     if (s->bie_len < 20 + 1728) 
       return JBG_EAGAIN;
-    if (!s->dppriv || s->dppriv == jbg_dptable)
-      s->dppriv = checked_malloc(sizeof(char) * 1728);
-    jbg_dppriv2int(s->dppriv, s->buffer);
+    dppriv = (unsigned char *) s->dppriv;
+    s->dppriv = (char *) checked_malloc(6912, sizeof(char));
+    jbg_dppriv2int(s->dppriv, dppriv);
+    checked_free(dppriv);
   }
 
   /*
@@ -2516,7 +2768,7 @@ int jbg_dec_in(struct jbg_dec_state *s, unsigned char *data, size_t len,
       /* now the buffer is filled with exactly one marker segment */
       switch (s->buffer[1]) {
       case MARKER_COMMENT:
-	s->comment_skip = 
+	s->comment_skip =
 	  (((long) s->buffer[2] << 24) | ((long) s->buffer[3] << 16) |
 	   ((long) s->buffer[4] <<  8) | (long) s->buffer[5]);
 	break;
@@ -2531,21 +2783,21 @@ int jbg_dec_in(struct jbg_dec_state *s, unsigned char *data, size_t len,
 	      s->at_tx[s->at_moves] >   (int) s->mx ||
 	      s->at_ty[s->at_moves] >   (int) s->my ||
 	      (s->at_ty[s->at_moves] == 0 && s->at_tx[s->at_moves] < 0))
-	    return JBG_EINVAL;
+	    return JBG_EINVAL | 11;
+	  if (s->at_ty[s->at_moves] != 0)
+	    return JBG_EIMPL | 6;
 	  s->at_moves++;
 	} else
-	  return JBG_EINVAL;
+	  return JBG_EIMPL | 7; /* more than JBG_ATMOVES_MAX ATMOVES */
 	break;
       case MARKER_NEWLEN:
 	y = (((long) s->buffer[2] << 24) | ((long) s->buffer[3] << 16) |
 	     ((long) s->buffer[4] <<  8) | (long) s->buffer[5]);
-	if (y > s->yd || !(s->options & JBG_VLENGTH))
-	  return JBG_EINVAL;
+	if (y > s->yd)                   return JBG_EINVAL | 12;
+	if (!(s->options & JBG_VLENGTH)) return JBG_EINVAL | 13;
 	s->yd = y;
 	/* calculate again number of stripes that will be required */
-	s->stripes = 
-	  ((s->yd >> s->d) +
-	   ((((1UL << s->d) - 1) & s->xd) != 0) + s->l0 - 1) / s->l0;
+	s->stripes = jbg_stripes(s->l0, s->yd, s->d);
 	break;
       case MARKER_ABORT:
 	return JBG_EABORT;
@@ -2555,13 +2807,13 @@ int jbg_dec_in(struct jbg_dec_state *s, unsigned char *data, size_t len,
 	/* decode final pixels based on trailing zero bytes */
 	decode_pscd(s, s->buffer, 2);
 
-	arith_decode_init(s->s[s->ii[index[s->order & 7][PLANE]]] + 
-			  s->ii[index[s->order & 7][LAYER]] - s->dl,
-			  s->ii[index[s->order & 7][STRIPE]] != s->stripes - 1
+	arith_decode_init(s->s[s->ii[iindex[s->order & 7][PLANE]]] + 
+			  s->ii[iindex[s->order & 7][LAYER]] - s->dl,
+			  s->ii[iindex[s->order & 7][STRIPE]] != s->stripes - 1
 			  && s->buffer[1] != MARKER_SDRST);
 	
-	s->reset[s->ii[index[s->order & 7][PLANE]]]
-	  [s->ii[index[s->order & 7][LAYER]] - s->dl] =
+	s->reset[s->ii[iindex[s->order & 7][PLANE]]]
+	  [s->ii[iindex[s->order & 7][LAYER]] - s->dl] =
 	    (s->buffer[1] == MARKER_SDRST);
 	
 	/* prepare for next SDE */
@@ -2572,12 +2824,12 @@ int jbg_dec_in(struct jbg_dec_state *s, unsigned char *data, size_t len,
 	
 	/* increment layer/stripe/plane loop variables */
 	/* start and end value for each loop: */
-	is[index[s->order & 7][STRIPE]] = 0;
-	ie[index[s->order & 7][STRIPE]] = s->stripes - 1;
-	is[index[s->order & 7][LAYER]] = s->dl;
-	ie[index[s->order & 7][LAYER]] = s->d;
-	is[index[s->order & 7][PLANE]] = 0;
-	ie[index[s->order & 7][PLANE]] = s->planes - 1;
+	is[iindex[s->order & 7][STRIPE]] = 0;
+	ie[iindex[s->order & 7][STRIPE]] = s->stripes - 1;
+	is[iindex[s->order & 7][LAYER]] = s->dl;
+	ie[iindex[s->order & 7][LAYER]] = s->d;
+	is[iindex[s->order & 7][PLANE]] = 0;
+	ie[iindex[s->order & 7][PLANE]] = s->planes - 1;
 	i = 2;  /* index to innermost loop */
 	do {
 	  j = 0;  /* carry flag */
@@ -2593,12 +2845,16 @@ int jbg_dec_in(struct jbg_dec_state *s, unsigned char *data, size_t len,
 	
 	/* check whether this have been all SDEs */
 	if (j) {
+#ifdef DEBUG
+	  fprintf(stderr, "This was the final SDE in this BIE, "
+		  "%ld bytes left.\n", (long) (len - *cnt));
+#endif
 	  s->bie_len = 0;
 	  return JBG_EOK;
 	}
 
 	/* check whether we have to abort because of xmax/ymax */
-	if (index[s->order & 7][LAYER] == 0 && i < 0) {
+	if (iindex[s->order & 7][LAYER] == 0 && i < 0) {
 	  /* LAYER is the outermost loop and we have just gone to next layer */
 	  if (jbg_ceil_half(s->xd, s->d - s->ii[0]) > s->xmax ||
 	      jbg_ceil_half(s->yd, s->d - s->ii[0]) > s->ymax) {
@@ -2629,7 +2885,7 @@ int jbg_dec_in(struct jbg_dec_state *s, unsigned char *data, size_t len,
 		"%02x %02x %02x %02x ...\n", data[*cnt], data[*cnt+1],
 		data[*cnt+2], data[*cnt+3]);
 #endif
-	return JBG_EINVAL;
+	return JBG_EINVAL | 14;
       }
       
     }
@@ -2641,15 +2897,16 @@ int jbg_dec_in(struct jbg_dec_state *s, unsigned char *data, size_t len,
 
 /*
  * After jbg_dec_in() returned JBG_EOK or JBG_EOK_INTR, you can call this
- * function in order to find out the width of the image.
+ * function in order to find out the width of the image. Returns 0 if
+ * there is no image available yet.
  */
-long jbg_dec_getwidth(const struct jbg_dec_state *s)
+unsigned long jbg_dec_getwidth(const struct jbg_dec_state *s)
 {
   if (s->d < 0)
-    return -1;
-  if (index[s->order & 7][LAYER] == 0) {
+    return 0;
+  if (iindex[s->order & 7][LAYER] == 0) {
     if (s->ii[0] < 1)
-      return -1;
+      return 0;
     else
       return jbg_ceil_half(s->xd, s->d - (s->ii[0] - 1));
   }
@@ -2660,15 +2917,16 @@ long jbg_dec_getwidth(const struct jbg_dec_state *s)
 
 /*
  * After jbg_dec_in() returned JBG_EOK or JBG_EOK_INTR, you can call this
- * function in order to find out the height of the image.
+ * function in order to find out the height of the image. Returns 0 if
+ * there is no image available yet.
  */
-long jbg_dec_getheight(const struct jbg_dec_state *s)
+unsigned long jbg_dec_getheight(const struct jbg_dec_state *s)
 {
   if (s->d < 0)
-    return -1;
-  if (index[s->order & 7][LAYER] == 0) {
+    return 0;
+  if (iindex[s->order & 7][LAYER] == 0) {
     if (s->ii[0] < 1)
-      return -1;
+      return 0;
     else
       return jbg_ceil_half(s->yd, s->d - (s->ii[0] - 1));
   }
@@ -2679,13 +2937,14 @@ long jbg_dec_getheight(const struct jbg_dec_state *s)
 
 /*
  * After jbg_dec_in() returned JBG_EOK or JBG_EOK_INTR, you can call this
- * function in order to get a pointer to the image.
+ * function in order to get a pointer to the image. Returns NULL if
+ * there is no image available yet.
  */
 unsigned char *jbg_dec_getimage(const struct jbg_dec_state *s, int plane)
 {
   if (s->d < 0)
     return NULL;
-  if (index[s->order & 7][LAYER] == 0) {
+  if (iindex[s->order & 7][LAYER] == 0) {
     if (s->ii[0] < 1)
       return NULL;
     else
@@ -2701,20 +2960,20 @@ unsigned char *jbg_dec_getimage(const struct jbg_dec_state *s, int plane)
  * this function in order to find out the size in bytes of one
  * bitplane of the image.
  */
-long jbg_dec_getsize(const struct jbg_dec_state *s)
+unsigned long jbg_dec_getsize(const struct jbg_dec_state *s)
 {
   if (s->d < 0)
-    return -1;
-  if (index[s->order & 7][LAYER] == 0) {
+    return 0;
+  if (iindex[s->order & 7][LAYER] == 0) {
     if (s->ii[0] < 1)
-      return -1;
+      return 0;
     else
       return 
-	((jbg_ceil_half(s->xd, s->d - (s->ii[0] - 1)) + 7) / 8) *
+	jbg_ceil_half(s->xd, s->d - (s->ii[0] - 1) + 3) * /* overflow risk? */
 	jbg_ceil_half(s->yd, s->d - (s->ii[0] - 1));
   }
   
-  return ((s->xd + 7) / 8) * s->yd;
+  return jbg_ceil_half(s->xd, 3) * s->yd;
 }
 
 
@@ -2723,16 +2982,16 @@ long jbg_dec_getsize(const struct jbg_dec_state *s)
  * this function in order to find out the size of the image that you
  * can retrieve with jbg_merge_planes().
  */
-long jbg_dec_getsize_merged(const struct jbg_dec_state *s)
+unsigned long jbg_dec_getsize_merged(const struct jbg_dec_state *s)
 {
   if (s->d < 0)
-    return -1;
-  if (index[s->order & 7][LAYER] == 0) {
+    return 0;
+  if (iindex[s->order & 7][LAYER] == 0) {
     if (s->ii[0] < 1)
-      return -1;
+      return 0;
     else
       return 
-	jbg_ceil_half(s->xd, s->d - (s->ii[0] - 1)) *
+	jbg_ceil_half(s->xd, s->d - (s->ii[0] - 1)) * /* overflow risk? */
 	jbg_ceil_half(s->yd, s->d - (s->ii[0] - 1)) *
 	((s->planes + 7) / 8);
   }
@@ -2770,6 +3029,8 @@ void jbg_dec_free(struct jbg_dec_state *s)
   checked_free(s->lntp);
   checked_free(s->lhp[0]);
   checked_free(s->lhp[1]);
+  if (s->dppriv && s->dppriv != jbg_dptable)
+    checked_free(s->dppriv);
 
   s->s = NULL;
 
@@ -2790,11 +3051,10 @@ void jbg_split_planes(unsigned long x, unsigned long y, int has_planes,
 		      const unsigned char *src, unsigned char **dest,
 		      int use_graycode)
 {
-  unsigned bpl = (x + 7) / 8;           /* bytes per line in dest plane */
-  unsigned i, k = 8;
+  unsigned long bpl = jbg_ceil_half(x, 3);  /* bytes per line in dest plane */
+  unsigned long line, i;
+  unsigned k = 8;
   int p;
-  unsigned long line;
-  extern void *memset(void *s, int c, size_t n);
   unsigned prev;     /* previous *src byte shifted by 8 bit to the left */
   register int bits, msb = has_planes - 1;
   int bitno;
@@ -2818,7 +3078,7 @@ void jbg_split_planes(unsigned long x, unsigned long y, int has_planes,
 	  bits = (prev | *src) >> bitno;
 	  /* go to next *src byte, but keep old */
 	  if (bitno == 0)
-	    prev = *src++;
+	    prev = *src++ << 8;
 	  /* make space for inserting new bit */
 	  dest[p][bpl * line + i] <<= 1;
 	  /* insert bit, if requested apply Gray encoding */
@@ -2831,7 +3091,7 @@ void jbg_split_planes(unsigned long x, unsigned long y, int has_planes,
 	}
 	/* skip unused *src bytes */
 	for (;p < has_planes; p++)
-	  if (((has_planes - 1 - p) & 7) == 0)
+	  if (((msb - p) & 7) == 0)
 	    src++;
       }
     }
@@ -2845,16 +3105,16 @@ void jbg_split_planes(unsigned long x, unsigned long y, int has_planes,
 /* 
  * Merge the separate bit planes decoded by the JBIG decoder into an
  * integer pixel field. This is essentially the counterpart to
- * jbg_split_planes(). */
+ * jbg_split_planes().
+ */
 void jbg_dec_merge_planes(const struct jbg_dec_state *s, int use_graycode,
 			  void (*data_out)(unsigned char *start, size_t len,
 					   void *file), void *file)
 {
 #define BUFLEN 4096
-  int bpp, bpl;
-  unsigned long line;
-  unsigned i, k = 8;
-  int p, q;
+  unsigned long bpl, line, i;
+  unsigned k = 8;
+  int p;
   unsigned char buf[BUFLEN];
   unsigned char *bp = buf;
   unsigned char **src;
@@ -2866,12 +3126,11 @@ void jbg_dec_merge_planes(const struct jbg_dec_state *s, int use_graycode,
   
   x = jbg_dec_getwidth(s);
   y = jbg_dec_getheight(s);
-  if (x <= 0 || y <= 0)
+  if (x == 0 || y == 0)
     return;
-  bpp = (s->planes + 7) / 8;   /* bytes per pixel in dest image */
-  bpl = (x + 7) / 8;           /* bytes per line in src plane */
+  bpl = jbg_ceil_half(x, 3);   /* bytes per line in src plane */
 
-  if (index[s->order & 7][LAYER] == 0)
+  if (iindex[s->order & 7][LAYER] == 0)
     if (s->ii[0] < 1)
       return;
     else
@@ -2882,12 +3141,13 @@ void jbg_dec_merge_planes(const struct jbg_dec_state *s, int use_graycode,
   for (line = 0; line < y; line++) {                    /* lines loop */
     for (i = 0; i * 8 < x; i++) {                       /* src bytes loop */
       for (k = 0; k < 8 && i * 8 + k < x; k++) {        /* pixel loop */
-	for (p = (s->planes-1) & ~7; p >= 0; p -= 8) {  /* dest bytes loop */
-	  v = 0;
-	  for (q = 0; q < 8 && p+q < s->planes; q++)    /* pixel bit loop */
+	v = 0;
+	for (p = 0; p < s->planes;) {                   /* dest bytes loop */
+	  do {
 	    v = (v << 1) |
-	      (((src[p+q][bpl * line + i] >> (7 - k)) & 1) ^
+	      (((src[p][bpl * line + i] >> (7 - k)) & 1) ^
 	       (use_graycode & v));
+	  } while ((s->planes - ++p) & 7);
 	  *bp++ = v;
 	  if (bp - buf == BUFLEN) {
 	    data_out(buf, BUFLEN, file);
@@ -2903,3 +3163,123 @@ void jbg_dec_merge_planes(const struct jbg_dec_state *s, int use_graycode,
   
   return;
 }
+
+
+/*
+ * Given a pointer p to the first byte of either a marker segment or a
+ * PSCD, as well as the length len of the remaining data, return
+ * either the pointer to the first byte of the next marker segment or
+ * PSCD, or p+len if this was the last one, or NULL if some error was
+ * encountered. Possible errors are:
+ *
+ *  - not enough bytes left for complete marker segment
+ *  - no marker segment terminates the PSCD
+ *  - unknown marker code encountered
+ *  
+ */
+static unsigned char *jbg_next_pscdms(unsigned char *p, size_t len)
+{
+  unsigned char *pp;
+  unsigned long l;
+
+  if (len < 2)
+    return NULL; /* not enough bytes left for complete marker segment */
+
+  if (p[0] != MARKER_ESC || p[1] == MARKER_STUFF) {
+    do {
+      while (p[0] == MARKER_ESC && p[1] == MARKER_STUFF) {
+	p += 2;
+	len -= 2;
+	if (len < 2)
+	  return NULL; /* not enough bytes left for complete marker segment */
+      }
+      assert(len >= 2);
+      pp = (unsigned char *) memchr(p, MARKER_ESC, len - 1);
+      if (!pp)
+	return NULL; /* no marker segment terminates the PSCD */
+      l = pp - p;
+      assert(l < len);
+      p += l;
+      len -= l;
+    } while (p[1] == MARKER_STUFF);
+  } else {
+    switch (p[1]) {
+    case MARKER_SDNORM:
+    case MARKER_SDRST:
+    case MARKER_ABORT:
+      return p + 2;
+    case MARKER_NEWLEN:
+      if (len < 6)
+	return NULL; /* not enough bytes left for complete marker segment */
+      return p + 6;
+    case MARKER_ATMOVE:
+      if (len < 8)
+	return NULL; /* not enough bytes left for complete marker segment */
+      return p + 8;
+    case MARKER_COMMENT:
+      if (len < 6)
+	return NULL; /* not enough bytes left for complete marker segment */
+      l = (((long) p[2] << 24) | ((long) p[3] << 16) |
+	   ((long) p[4] <<  8) |  (long) p[5]);
+      if (len - 6 < l)
+	return NULL; /* not enough bytes left for complete marker segment */
+      return p + 6 + l;
+    default:
+      /* unknown marker sequence encountered */
+      return NULL;
+    }
+  }
+
+  return p;
+}
+
+
+/*
+ * Scan a complete BIE for a NEWLEN marker segment, then read the new
+ * YD value found in it and use it to overwrite the one in the BIE
+ * header. Use this procedure if a BIE initially declares an
+ * unreasonably high provisional YD value (e.g., 0xffffffff) or
+ * depends on the fact that section 6.2.6.2 of ITU-T T.82 says that a
+ * NEWLEN marker segment "could refer to a line in the immediately
+ * preceding stripe due to an unexpected termination of the image or
+ * the use of only such stripe". ITU-T.85 explicitely suggests the
+ * use of this for fax machines that start transmission before having
+ * encountered the end of the page. None of this is necessary for
+ * BIEs produced by JBIG-KIT, which normally does not use NEWLEN.
+ */
+int jbg_newlen(unsigned char *bie, size_t len)
+{
+  unsigned char *p = bie + 20;
+  int i;
+  unsigned long y, yn;
+
+  if (len < 20)
+    return JBG_EAGAIN;
+  if ((bie[19] & (JBG_DPON | JBG_DPPRIV | JBG_DPLAST))
+      == (JBG_DPON | JBG_DPPRIV))
+    p += 1728; /* skip DPTABLE */
+  if (p >= bie + len)
+    return JBG_EAGAIN;
+
+  while ((p = jbg_next_pscdms(p, len - (p - bie)))) {
+    if (p == bie + len)
+      return JBG_EOK;
+    else if (p[0] == MARKER_ESC)
+      switch (p[1]) {
+      case MARKER_NEWLEN:
+	y = (((long) bie[ 8] << 24) | ((long) bie[ 9] << 16) |
+	     ((long) bie[10] <<  8) |  (long) bie[11]);
+	yn = (((long) p[2] << 24) | ((long) p[3] << 16) |
+	      ((long) p[4] <<  8) |  (long) p[5]);
+	if (yn > y) return JBG_EINVAL | 12;
+	/* overwrite YD in BIH with YD from NEWLEN */
+	for (i = 0; i < 4; i++) {
+	  bie[8+i] = p[2+i];
+	}
+	return JBG_EOK;
+      case MARKER_ABORT:
+	return JBG_EABORT;
+      }
+  }
+  return JBG_EINVAL | 0;
+}
diff --git a/converter/other/jbig/jbig.doc b/converter/other/jbig/libjbig/jbig.txt
index 10eeda80..bdc14b17 100644
--- a/converter/other/jbig/jbig.doc
+++ b/converter/other/jbig/libjbig/jbig.txt
@@ -2,47 +2,56 @@
 Using the JBIG-KIT library
 --------------------------
 
-Markus Kuhn -- 1998-04-10
+Markus Kuhn -- 2013-09-10
 
 
-This text explains how to include the functions provided by the
-JBIG-KIT portable image compression library into your application
-software.
+This text explains how to use the functions provided by the JBIG-KIT
+portable image compression library jbig.c in your application
+software. The jbig.c library is a full-featured implementation of the
+JBIG1 standard aimed at applications that can hold the entire
+uncompressed and compressed image in RAM.
+
+[For applications that require only the single-bit-per-pixel "fax
+subset" of the JBIG1 standard defined in ITU-T Recommendation T.85
+<http://www.itu.int/rec/T-REC-T.85/en>, the alternative implementation
+found in jbig85.c may be preferable. It keeps not more than three
+lines of the uncompressed image in RAM, which makes it particularly
+suitable for embedded applications. For information on how to use
+jbig85.c, please refer to the separate documentation file jbig85.txt.]
 
 
 1  Introduction to JBIG
 
-Below follows a short introduction into some technical aspects of the
-JBIG standard. More detailed information is provided in the
-"Introduction and overview" section of the JBIG standard. Information
-about how to obtain a copy of the standard is available on the
-Internet from <http://www.itu.ch/> or <http://www.iso.ch/>.
+We start with a short introduction to JBIG1. More detailed information
+is provided in the "Introduction and overview" section of the JBIG1
+standard. Information on how to obtain a copy of the standard is
+available from <http://www.itu.int/rec/T-REC-T.82/en> or
+<http://www.iso.ch/>.
 
 Image data encoded with the JBIG algorithm is separated into planes,
 layers, and stripes. Each plane contains one bit per pixel. The number
 of planes stored in a JBIG data stream is the number of bits per
 pixel. Resolution layers are numbered from 0 to D with 0 being the
-layer with the lowest resolution and D the layer with the highest one.
-Each next higher resolution layer has exactly twice the number of rows
-and columns than the previous one. Layer 0 is encoded independently of
-any other data, all other resolution layers are encoded as only the
-difference between the next lower and the current layer. For
-applications that require very quick access to parts of an image it is
-possible to divide an image into several horizontal stripes. All
-stripes of one resolution layer have equal size except perhaps the
-final one. The number of stripes of an image is equal in all
-resolution layers and in all bit planes.
+layer with the lowest resolution and D the one with the highest. Each
+next higher resolution layer has twice the number of rows and columns.
+Layer 0 is encoded independently of any other data, all other
+resolution layers are encoded as only the difference between the next
+lower and the current layer. For applications that require very quick
+access to parts of an image, it is possible to divide an image into
+several horizontal stripes. All stripes of one resolution layer have
+equal size, except perhaps the final one. The number of stripes of an
+image is equal in all resolution layers and in all bit planes.
 
 The compressed data stream specified by the JBIG standard is called a
 bi-level image entity (BIE). A BIE consists of a 20-byte header,
 followed by an optional 1728-byte table (usually not present, except
 in special applications) followed by a sequence of stripe data
-entities (SDE). SDEs are the data blocks of which each encodes the
-content of one single stripe in one plane and resolution layer.
-Between the SDEs, other information blocks (called floating marker
-segments) can also be present, which change certain parameters of the
-algorithm in the middle of an image or contain additional application
-specific information. A BIE looks like this:
+entities (SDE). Each SDE encodes the content of one single stripe in
+one plane of one resolution layer. Between the SDEs, other information
+blocks (called floating marker segments) can also be present. They are
+used to change certain parameters of the algorithm in the middle of an
+image or contain additional application specific information. A BIE
+looks like this:
 
 
           +------------------------------------------------+
@@ -57,6 +66,10 @@ specific information. A BIE looks like this:
           |                                                |
           +------------------------------------------------+
           |                                                |
+          |       optional floating marker segments        |
+          |                                                |
+          +------------------------------------------------+
+          |                                                |
           |              stripe data entity                |
           |                                                |
           +------------------------------------------------+
@@ -85,58 +98,58 @@ storing the image in one single resolution layer.
 
 Different applications might have different requirements for the order
 in which the SDEs for stripes of various planes and layers are stored
-in the BIE, so all possible sensible orderings are allowed and
-indicated by four bits in the header.
+in the BIE, so all possible sensible orderings are allowed by the
+standard and indicated by four bits in the header.
 
 It is possible to use the raw BIE data stream as specified by the JBIG
 standard directly as the format of a file used for storing images.
-This is what the JBIG<->PBM conversion tools that are provided in this
-package as demonstration applications do. However as the BIE format
-has been designed for a large number of very different applications
-and also in order to allow efficient direct processing by special JBIG
-hardware chip implementations, the BIE header contains only the
-minimum amount of information absolutely required by the decompression
-algorithm. A large number of features expected from a good file format
-are missing in the BIE data stream:
+This is what the pbmtojbg, jbgtopbm, pbmtojbg85, and jbgtopbm85
+conversion tools do that are provided in this package as demonstration
+applications. However, as the BIE format has been designed for a large
+number of very different applications, and to allow efficient direct
+processing by special JBIG hardware chip implementations, the BIE
+header contains only the minimum amount of information absolutely
+required by the decompression algorithm. Many features expected from a
+good file format are missing in the BIE data stream:
 
   - no "magic code" in the first few bytes to allow identification
-    of the file on a typeless file system as JBIG encoded and to allow
+    of the file format on a typeless file system and to allow
     automatic distinction from other compression algorithms
 
-  - no standardized way to encode additional information like a textual
-    description, information about the meaning of various bit planes,
-    the physical size and resolution of the document, etc.
+  - no standardized way to encode additional information such as a
+    textual description, information about the meaning of various bit
+    planes, the physical size and resolution of the document, etc.
 
-  - a checksum that ensures image integrity
+  - a checksum to ensure image integrity
 
   - encryption and signature mechanisms
 
   - many things more
 
-Raw BIE data streams alone are consequently no suitable format for
+Raw BIE data streams alone may therefore not be a suitable format for
 document archiving and exchange. A standard format for this purpose
-would typically combine a BIE representing the image data together
-with an additional header providing auxiliary information into one
-file. Existing established multi-purpose file formats with a rich set
-of auxiliary information attributes like TIFF could be extended easily
-so that they can also contain JBIG compressed data.
+would typically combine a BIE representing the image data with an
+additional header providing auxiliary information into one file.
+Existing established multi-purpose file formats with a rich set of
+auxiliary information attributes like TIFF could be extended easily to
+also hold JBIG compressed data.
 
-On the other hand, in database applications for instance, a BIE might
-be directly stored in a variable length field. Auxiliary information
-on which efficient search operations are required would then be stored
-in other fields of the same record.
+On the other hand, in e.g. database applications, a BIE might be
+stored directly in a binary variable-length field. Auxiliary
+information would then be stored in other fields of the same record,
+to simplify search operations.
 
 
 2  Compressing an image
 
 2.1  Format of the source image
 
-For processing by the library, the image has to be present in memory
-as separate bitmap planes. Each byte of a bitmap contains eight
-pixels, the most significant bit represents the leftmost of these
-pixels. Each line of a bitmap has to be stored in an integral number
-of bytes. If the image width is not an integral multiple of eight,
-then the final byte has to be padded with zero bits.
+To be processed by the jbig.c encoder, the image has to be present in
+memory as separate bitmap planes. Each byte of a bitmap contains eight
+pixels, where the most significant bit represents the leftmost of
+these. Each line of a bitmap has to be stored in an integral number of
+bytes. If the image width is not an integral multiple of eight, then
+the final byte has to be padded with zero bits.
 
 For example the 23x5 pixels large single plane image:
 
@@ -158,28 +171,29 @@ or in hexadecimal notation
 
    7c e2 38 04 92 40 04 e2 5c 44 92 44 38 e2 38
 
-This is the format used in binary PBM files and it can also be be
-handled directly by the Xlib library of the X Window System.
+This is the format used in binary PBM files and it can also be handled
+directly by the Xlib library of the X Window System.
 
-As JBIG can also handle images with several bit planes, the JBIG-KIT
+As JBIG can also handle images with multiple bit planes, the jbig.c
 library functions accept and return always arrays of pointers to
 bitmaps with one pointer per plane.
 
-For single plane images, the standard recommends that a 0 pixel
+For single-plane images, the standard recommends that a 0 pixel
 represents the background and a 1 pixel represents the foreground
-color of an image, i.e. 0 is white and 1 is black for scanned paper
-documents. For images with several bits per pixel, the JBIG standard
-makes no recommendations about how various colors should be encoded.
+colour of an image, in other words, 0 is white and 1 is black for
+scanned paper documents. For images with several bits per pixel, the
+JBIG standard makes no recommendations about how various colours should
+be encoded.
 
-For greyscale images, by using a Gray code instead of a simple binary
+For grey-scale images, by using a Gray code instead of a simple binary
 weighted representation of the pixel intensity, some increase in
 coding efficiency can be reached.
 
-A Gray code is also a binary representation of integer numbers, but
+A Gray code is also a binary representation of integer numbers, but it
 has the property that the representations of the integer numbers i and
-(i+1) differ always in exactly one single bit. For example, the
-numbers 0 to 7 can be represented in normal binary code and Gray code
-as in the following table:
+(i+1) always differ in exactly one bit. For example, the numbers 0 to
+7 can be represented in normal binary code and Gray code as in the
+following table:
 
                            normal
               number    binary code     Gray code
@@ -198,7 +212,7 @@ half of the code (numbers 4 - 7) is simply the mirrored first half
 (numbers 3 - 0) with the first bit set to one. This way, arbitrarily
 large Gray codes can be generated quickly by mirroring the above
 example and prefixing the first half with zeros and the second half
-with ones as often as required. In greyscale images, it is common
+with ones as often as required. In grey-scale images, it is common
 practise to use the all-0 code for black and the all-1 code for white.
 
 No matter whether a Gray code or a binary code is used for encoding a
@@ -212,7 +226,7 @@ during the transmission.
 
 2.2  A simple compression application
 
-In order to use JBIG-KIT in your application, just link libjbig.a to
+In order to use jbig.c in your application, just link libjbig.a to
 your executable (on Unix systems just add -ljbig and -L. to the
 command line options of your compiler, on other systems you will have
 to write a new Makefile anyway), copy the file jbig.h into your source
@@ -222,10 +236,10 @@ directory and put the line
 
 into your source code.
 
-The library interface follows the concepts of object-oriented
-programming. You have to declare a variable (object)
+The library interface follows object-oriented programming principles.
+You have to declare a variable (object)
 
-  struct jbg_enc_state se;
+  struct jbg_enc_state s;
 
 which contains the current status of an encoder. Then you initialize
 the encoder by calling the constructor function
@@ -238,12 +252,12 @@ the encoder by calling the constructor function
 
 The parameters have the following meaning:
 
-  s             A pointer to the jbg_enc_state structure which you want
+  s             A pointer to the jbg_enc_state structure that you want
                 to initialize.
 
-  x             The width of your image.
+  x             The width of your image in pixels.
 
-  y             The height of your image.
+  y             The height of your image in pixels (lines).
 
   pl            the number of bitmap planes you want to encode.
 
@@ -251,36 +265,37 @@ The parameters have the following meaning:
                 pointing to the first byte of a bitmap as described in
                 section 2.1.
 
-  data_out      This is a call-back function which will be called during
-                the compression process by libjbig in order to deliver
-                the BIE data to the application. The parameters of the
-                function data_out are a pointer start to the new block of
-                data to be delivered as well as the number len of delivered
-                bytes. The pointer file is transparently delivered to
-                data_out as specified in jbg_enc_init(). Usually, data_out
-                will write the BIE portion to a file, send it to a
-                network connection or append it to some memory buffer.
-
-  file          A pointer parameter which is transparently passed to
-                data_out() and allows data_out() to distinguish by which
-                compression task it has been called in multi-threaded
-                applications.
+  data_out      This is a call-back function that the encoder will
+                call during the compression process by in order to
+                deliver the BIE data to your application. The
+                parameters of the function data_out are a pointer
+                start to the new block of data being delivered, as
+                well as the number len of delivered bytes. The pointer
+                file is transparently delivered to data_out, as
+                specified in jbg_enc_init(). Typically, data_out will
+                write the BIE portion to a file, send it to a network
+                connection, or append it to some memory buffer.
+
+  file          A pointer parameter that is passed on to data_out()
+                and can be used, for instance, to allow data_out() to
+                distinguish by which compression task it has been
+                called in multi-threaded applications.
 
 In the simplest case, the compression is then started by calling the
 function
 
   void jbg_enc_out(struct jbg_enc_state *s);
 
-which will deliver the complete BIE to data_out(). After this, a call
-to the destructor function
+which will deliver the complete BIE to data_out() in several calls.
+After jbg_enc_out has returned, a call to the destructor function
 
   void jbg_enc_free(struct jbg_enc_state *s);
 
-will release any memory allocated by the previous functions.
+will release any heap memory allocated by the previous functions.
 
 
-A minimal example application which sends the BIE of the above example
-bitmap to stdout looks like this:
+A minimal example application, which sends the BIE of the above bitmap
+to stdout, looks like this:
 
 ---------------------------------------------------------------------------
 /* A sample JBIG encoding application */
@@ -332,7 +347,7 @@ following default values are used for various compression parameters:
   - The number of lines per stripe is selected so that approximately
     35 stripes per image are used (as recommended in annex C of the
     standard together with the suggested adaptive template change
-    algorithm). However not less than 2 and not more than 128 lines
+    algorithm). However, not less than 2 and not more than 128 lines
     are used in order to stay within the suggested minimum parameter
     support range specified in annex A of the standard).
 
@@ -340,7 +355,7 @@ following default values are used for various compression parameters:
     TPDON and DPON).
 
   - The default resolution reduction table and the default deterministic
-    prediction tables are used
+    prediction table are used
 
   - The maximal vertical offset of the adaptive template pixel is 0
     and the maximal horizontal offset is 8 (mx = 8, my = 0).
@@ -354,14 +369,16 @@ with
   void jbg_enc_layers(struct jbg_enc_state *s, int d);
 
 the number d of differential resolution layers which shall be encoded
-in addition to the lowest resolution layer 0. For example, if a 300
-dpi document has to be stored and the lowest resolution layer shall
-have 75 dpi so that a screen previewer can directly decompress only
-the required resolution, then a call
+in addition to the lowest resolution layer 0. For example, if a
+document with 60-micrometer pixels has to be stored, and the lowest
+resolution layer shall have 240-micrometer pixels, so that a screen
+previewer can directly decompress only the required resolution, then a
+call
 
   jbg_enc_layers(&se, 2);
 
-will cause three resolution layers with 75, 150 and 300 dots per inch.
+will cause three layers with 240, 120 and 60 micrometers resolution to
+be generated.
 
 If the application does not know what typical resolutions are used and
 simply wants to ensure that the lowest resolution layer will fit into
@@ -381,26 +398,26 @@ resolution directly, then call
 The return value is the number of differential layers selected.
 
 After the number of resolution layers has been specified by calls to
-jbg_enc_layers() or jbg_enc_lrlmax(), by default all these layers will
-be written into the BIE. This can be changed with a call to
+jbg_enc_layers() or jbg_enc_lrlmax(), by default, all these layers
+will be written into the BIE. This can be changed with a call to
 
   int  jbg_enc_lrange(struct jbg_enc_state *s, int dl, int dh);
 
 Parameter dl specifies the lowest resolution layer and dh the highest
-resolution layer that will appear in the BIE. If e.g. only layer 0
+resolution layer that will appear in the BIE. For instance, if layer 0
 shall be written to the first BIE and layer 1 and 2 shall be written
-to a second one, then before writing the first BIE, one calls
+to a second one, then before writing the first BIE, call
 
   jbg_enc_lrange(&se, 0, 0);
 
-and before writing the second BIE with jbg_enc_out(), one calls
+and before writing the second BIE with jbg_enc_out(), call
 
   jbg_enc_lrange(&se, 1, 2);
 
 If any of the parameters is negative, it will be ignored. The return
-value is the total number of differential layers which will represent
+value is the total number of differential layers that will represent
 the input image. This way, jbg_enc_lrange(&se, -1, -1) can be used to
-query the layer of the full image.
+query the layer of the full image resolution.
 
 A number of other more exotic options of the JBIG algorithm can be
 modified by calling
@@ -418,14 +435,14 @@ the SDEs are stored in the BIE. The bits have the following meaning:
                the higher resolution layers, so that a decoder can
                already start to display a low resolution version of
                the full image once a prefix of the BIE has been
-               received. When this bit is set however, the BIE will
+               received. When this bit is set, however, the BIE will
                contain the higher layers before the lower layers. This
                avoids additional buffer memory in the encoder and is
                intended for applications where the encoder is connected
                to a database which can easily reorder the SDEs before
                sending them to a decoder. Warning: JBIG decoders are
                not expected to support the HITOLO option (e.g. the
-               JBIG-KIT decoder does currently not) so you should
+               jbig.c decoder currently does not) so you should
                normally not use it.
 
   JBG_SEQ      Usually, at first all stripes of one resolution layer
@@ -434,10 +451,10 @@ the SDEs are stored in the BIE. The bits have the following meaning:
                all layers of the first stripe will be written,
                followed by all layers of the second stripe, etc. This
                option also should normally never be required and is
-               not supported by the current JBIG-KIT decoder.
+               not supported by the current jbig.c decoder.
 
   JBG_SMID     In case there exist several bit planes, then the order of
-               the stripes is determined by 3 loops over all stripes,
+               the stripes is determined by three loops over all stripes,
                all planes and all layers. When SMID is set, the loop
                over all stripes is the middle loop.
 
@@ -445,8 +462,8 @@ the SDEs are stored in the BIE. The bits have the following meaning:
                plane are written before the encoder starts with the next
                plane.
 
-The above description might be somewhat confusing, but the following
-table (see also Table 11 in ITU-T T.82) makes clear how the three bits
+The above description may be somewhat confusing, but the following
+table (see also Table 11 in ITU-T T.82) clarifies how the three bits
 JBG_SEQ, JBIG_ILEAVE and JBG_SMID influence the ordering of the loops
 over all stripes, planes and layers:
 
@@ -482,15 +499,15 @@ some of the optional algorithms defined by JBIG:
                  the slightly faster but 5% less well compressing two
                  line alternative is selected. God bless the committees.
                  Although probably nobody will ever need this option,
-                 it has been implemented in JBIG-KIT and is off by
+                 it has been implemented in jbig.c and is off by
                  default.
 
   JBG_TPDON      This activates the "typical prediction" algorithm
                  for differential layers which avoids that large
-                 areas of equal color have to be encoded at all.
+                 areas of equal colour have to be encoded at all.
                  This is on by default and there is no good reason to
                  switch it off except for debugging or preparing data
-                 for cheap JBIG hardware which does not support this
+                 for cheap JBIG hardware that might not support this
                  option.
 
   JBG_TPBON      Like JBG_TPDON this activates the "typical prediction"
@@ -501,12 +518,12 @@ some of the optional algorithms defined by JBIG:
                  layers the "deterministic prediction" algorithm,
                  which avoids that higher resolution layer pixels are
                  encoded when their value can already be determined
-                 with the knowledge of the neighbor pixels, the
+                 with the knowledge of the neighbour pixels, the
                  corresponding lower resolution pixels and the
                  resolution reduction algorithm. This is also
-                 activated by default and one only might perhaps want
-                 to deactivate it if the default resolution reduction
-                 algorithm is replaced by a new one.
+                 activated by default and one reason for deactivating
+                 it would be if the default resolution reduction
+                 algorithm were replaced by another one.
 
   JBG_DELAY_AT   Use a slightly less efficient algorithm to determine
                  when an adaptive template change is necessary. With
@@ -514,31 +531,32 @@ some of the optional algorithms defined by JBIG:
                  conformance test examples in cause 7.2 of ITU-T T.82.
                  Then all adaptive template changes are delayed until
                  the first line of the next stripe. This option is by
-                 default deactivated and only required for passing a
+                 default deactivated and is only required for passing a
                  special compatibility test suite.
 
 In addition, parameter l0 in jbg_enc_options() allows you to specify
 the number of lines per stripe in resolution layer 0. The parameters
 mx and my change the maximal offset allowed for the adaptive template
-pixel. The JBIG-KIT implementation allows currently a maximal mx value
-of 23 in the encoder and 32 in the decoder. Parameter my is at the
-moment ignored and always set to 0. As the standard requires of all
-decoder implementations only a maximum supported mx = 16 and my = 0,
+pixel. JBIG-KIT now supports the full range of possible mx values up
+to 127 in the encoder and decoder, but my is at the moment ignored and
+always set to 0. As the standard requires of all decoder
+implementations only to support maximum values mx = 16 and my = 0,
 higher values should normally be avoided in order to guarantee
-interoperability. Default is mx = 8 and my = 0. If any of the
-parameters order, options, l0, mx or my is negative, then this value
-is ignored and the current value stays unmodified.
+interoperability. The ITU-T T.85 profile for JBIG in fax machines
+requires support for mx = 127 and my = 0. Default is mx = 8 and my =
+0. If any of the parameters order, options, mx or my is negative, or
+l0 is zero, then the corresponding current value remains unmodified.
 
 The resolution reduction and deterministic prediction tables can also
 be replaced. However as these options are anyway only for experts,
 please have a look at the source code of jbg_enc_out() and the struct
 members dppriv and res_tab of struct jbg_enc_state for the details of
-how to do this in case you really need it. The functions
+how to do this, in case you really need it. The functions
 jbg_int2dppriv and jbg_dppriv2int are provided in order to convert the
 DPTABLE data from the format used in the standard into the more
 efficient format used internally by JBIG-KIT.
 
-If you want to encode a greyscale image, you can use the library
+If you want to encode a grey-scale image, you can use the library
 function
 
   void jbg_split_planes(unsigned long x, unsigned long y, int has_planes,
@@ -547,8 +565,8 @@ function
                         int use_graycode);
 
 It separates an image in which each pixel is represented by one or
-more bytes into separate bitplanes. The dest array of pointers to
-these bitplanes can then be handed over to jbg_enc_init(). The
+more bytes into separate bit planes. The dest array of pointers to
+these bit planes can then be handed over to jbg_enc_init(). The
 variables x and y specify the width and height of the image in pixels,
 and has_planes specifies how many bits per pixel are used. As each
 pixel is represented by an integral number of consecutive bytes, of
@@ -557,7 +575,7 @@ image array src[] will therefore be x * y * ((has_planes + 7) / 8)
 bytes. The pixels are stored as usually in English reading order, and
 for each pixel the integer value is stored with the most significant
 byte coming first (Bigendian). This is exactly the format used in raw
-PGM files. In encode_planes, the number of bitplanes that shall be
+PGM files. In encode_planes, the number of bit planes that shall be
 extracted can be specified. This allows for instance to extract only
 the most significant 8 bits of a 12-bit image, where each pixel is
 represented by two bytes, by specifying has_planes = 12 and
@@ -568,7 +586,7 @@ the pixel integer values will be used instead of the Gray code. Plane
 
 3  Decompressing an image
 
-Like with the compression functions, if you want to use the JBIG-KIT
+Like with the compression functions, if you want to use the jbig.c
 library, you have to put the line
 
   #include "jbig.h"
@@ -603,19 +621,19 @@ will return the error JBG_ENOCONT after the header of the new BIE has
 been received completely.
 
 If pointer cnt is not NULL, then the number of bytes actually read
-from the data block is stored there. In case the data block did not
-contain the end of the BIE, then the value JBG_EAGAIN will be returned
-and *cnt equals len.
+from the data block will be stored there. In case the data block did
+not contain the end of the BIE, then the value JBG_EAGAIN will be
+returned and *cnt equals len.
 
 Once the end of a BIE has been reached, the return value of
 jbg_dec_in() will be JBG_EOK. After this has happened, the functions
 and macros
 
-  long jbg_dec_getwidth(struct jbg_dec_state *s);
-  long jbg_dec_getheight(struct jbg_dec_state *s);
+  unsigned long jbg_dec_getwidth(struct jbg_dec_state *s);
+  unsigned long jbg_dec_getheight(struct jbg_dec_state *s);
   int jbg_dec_getplanes(struct jbg_dec_state *s);
   unsigned char *jbg_dec_getimage(struct jbg_dec_state *s, int plane);
-  long jbg_dec_getsize(struct jbg_dec_state *s);
+  unsigned long jbg_dec_getsize(struct jbg_dec_state *s);
 
 can be used to query the dimensions of the now completely decoded
 image and to get a pointer to all bitmap planes. The bitmaps are
@@ -628,14 +646,14 @@ The function
                             void (*data_out)(unsigned char *start, size_t len,
                                              void *file), void *file);
 
-allows you to merge the bitplanes that can be accessed individually
+allows you to merge the bit planes that can be accessed individually
 with jbg_dec_getimage() into an array with one or more bytes per pixel
 (i.e., the format provided to jbg_split_planes()). If use_graycode is
 zero, then a binary encoding will be used. The output array will be
 delivered via the callback function data_out, exactly in the same way
 in which the encoder provides the BIE. The function
 
-  long jbg_dec_getsize_merged(const struct jbg_dec_state *s);
+  unsigned long jbg_dec_getsize_merged(const struct jbg_dec_state *s);
 
 determines how long the data array delivered by jbg_dec_merge_planes()
 is going to be.
@@ -683,34 +701,105 @@ and the memory can be released.
 
 The function
 
-  const char *jbg_strerror(int errnum, int language);
+  const char *jbg_strerror(int errnum);
 
-returns a pointer to a short single line test message which explains
+returns a pointer to a short single line test message that explains
 the return value of jbg_dec_in(). This message can be used in order to
 provide the user a brief informative message about what when wrong
-while decompressing the JBIG image. The error messages are available
-in several languages and in several character sets. Currently
-supported are the following values for the language parameter:
-
-  JBG_EN              English messages in ASCII
-  JBG_DE_8859_1       German messages in ISO 8859-1 Latin 1 character set
-  JBG_DE_UTF_8        German messages in ISO 10646/Unicode UTF-8 encoding
-
-
-The current implementation of the JBIG-KIT decoder has the following
+while decompressing a JBIG image. The po/ subdirectory contains *.po
+files that translate the English ASCII strings returned by
+jbg_strerror() into other languages (e.g., for use with GNU gettext).
+The four least-significant bits of the return value of jbg_dec_in()
+may contain additional detailed technical information about the exact
+test that spotted the error condition (see source code for details),
+i.e. more than the text message returned by jbg_strerror() reveals.
+Therefore it may be useful to display the return value itself as a
+hexadecimal number, in addition to the string returned by
+jbg_strerror().
+
+The current implementation of the jbig.c decoder has the following
 limitations:
 
-  - The maximal horizontal offset mx of the adaptive template pixel
-    must not be larger than 32 and the maximal vertical offset must
-    be zero.
+  - The maximal vertical offset MY of the adaptive template pixel
+    must be zero.
 
   - HITOLO and SEQ bits must not be set in the order value.
 
+  - Not more than JBG_ATMOVES_MAX (currently set to 64) ATMOVE
+    marker segments can be handled per stripe.
+
+  - the number D of differential layers must be less than 32
+
+None of the above limitations can be exceeded by a JBIG data stream
+that conforms to the ITU-T T.85 application profile for the use of
+JBIG1 in fax machines.
+
+The current implementation of the jbig.c decoder does not impose any
+limits on the image size that it will process, as long as malloc() is
+able to allocate enough heap space for the resulting bitmaps. The only
+exception is that jbg_dec_in() will return "Input data stream uses
+unimplemented JBIG features" (JBG_EIMPL | 1) if Y_D equals 0xffffffff,
+which is an extreme value commonly used to encode images according to
+ITU-T T.85 where the height was unknown when the BIH was emitted.
+After jbg_dec_in() received the 20-byte long BIH at the start of the
+BIE, it will malloc() to allocate enough memory to hold the requested
+image planes and layers. If you want to defend your application
+against excessive image-size parameters in a received BIH, then do
+make sure that you check X_D, Y_D, and P against appropriate safety
+limits before handing over the BIH to jbg_dec_in().
+
+There are two more limitations of the current implementation of the
+jbig.c decoder that might cause problems with processing JBIG data
+stream that conform to ITU-T T.85:
+
+  - The jbig.c decoder was designed to operate incrementally.
+    Each received byte is processed immediately as soon as it arrives.
+    As a result, it does not look beyond the SDRST/SDNORM at the end
+    of all stripes for any immediately following NEWLEN marker that
+    might reduce the number of lines encoded by the current stripe.
+    However section 6.2.6.2 of ITU-T T.82 says that a NEWLEN marker
+    segment "could refer to a line in the immediately preceding stripe
+    due to an unexpected termination of the image or the use of only
+    such stripe", and ITU-T.85 explicitly suggests the use of this
+    for fax machines that start transmission before having encountered
+    the end of the page.
+
+  - The image size initially indicated in the BIE header is used to
+    allocate memory for a bitmap of this size. This means that BIEs
+    that set initially Y_D = 0xffffffff (as suggested in ITU-T T.85
+    for fax machines that do not know the height of the page at the
+    start of the transmission) cannot be decoded directly by this
+    version.
+
+For both issues, there is a workaround available:
+
+If you encounter a BIE that has in the header the VLENGTH=1 option bit
+set, then first wait until you have received the entire BIE and stored
+it in memory. Then call the function
+
+  int jbg_newlen(unsigned char *bie, size_t len);
+
+where bie is a pointer to the first byte of the BIE and len its length
+in bytes. This function will scan the entire BIE for the first NEWLEN
+marker segment. It will then take the updated image-height value YD
+from it and use it to overwrite the YD value in the BIE header. The
+jbg_newlen() can return some of the same error codes as jbg_dec_in(),
+namely JBG_EOK if everything went fine, JBG_EAGAIN is the data
+provided is too short to be a valid BIE, JBG_EINVAL if a format error
+was encountered, and JBG_EABORT if an ABORT marker segment was found.
+After having patched the image-height value in the BIE using
+jbg_newlen(), simply hand over the BIE as usual to jbg_dec_in().
+
+In general, for applications where NEWLEN markers can appear, in
+particular fax reception, you should consider using the jbig85.c
+decoder instead, as it can process BIEs with NEWLEN markers in a
+single pass.
+
 A more detailed description of the JBIG-KIT implementation is
 
   Markus Kuhn: Effiziente Kompression von bi-level Bilddaten durch
   kontextsensitive arithmetische Codierung. Studienarbeit, Lehrstuhl
-  für Betriebssysteme, IMMD IV, Universität Erlangen-Nürnberg,
+  für Betriebssysteme, IMMD IV, Universität Erlangen-Nürnberg,
   Erlangen, July 1995. (German, 62 pages)
   <http://www.cl.cam.ac.uk/~mgk25/kuhn-sta.pdf>
 
diff --git a/converter/other/jbig/libjbig/jbig_ar.c b/converter/other/jbig/libjbig/jbig_ar.c
new file mode 100644
index 00000000..d23a317d
--- /dev/null
+++ b/converter/other/jbig/libjbig/jbig_ar.c
@@ -0,0 +1,417 @@
+/*
+ *  Arithmetic encoder and decoder of the portable JBIG
+ *  compression library
+ *
+ *  Markus Kuhn -- http://www.cl.cam.ac.uk/~mgk25/jbigkit/
+ *
+ *  This module implements a portable standard C arithmetic encoder
+ *  and decoder used by the JBIG lossless bi-level image compression
+ *  algorithm as specified in International Standard ISO 11544:1993
+ *  and ITU-T Recommendation T.82.
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ * 
+ *  If you want to use this program under different license conditions,
+ *  then contact the author for an arrangement.
+ */
+
+#include <assert.h>
+#include "jbig_ar.h"
+
+/*
+ *  Probability estimation tables for the arithmetic encoder/decoder
+ *  given by ITU T.82 Table 24.
+ */
+
+static short lsztab[113] = {
+  0x5a1d, 0x2586, 0x1114, 0x080b, 0x03d8, 0x01da, 0x00e5, 0x006f,
+  0x0036, 0x001a, 0x000d, 0x0006, 0x0003, 0x0001, 0x5a7f, 0x3f25,
+  0x2cf2, 0x207c, 0x17b9, 0x1182, 0x0cef, 0x09a1, 0x072f, 0x055c,
+  0x0406, 0x0303, 0x0240, 0x01b1, 0x0144, 0x00f5, 0x00b7, 0x008a,
+  0x0068, 0x004e, 0x003b, 0x002c, 0x5ae1, 0x484c, 0x3a0d, 0x2ef1,
+  0x261f, 0x1f33, 0x19a8, 0x1518, 0x1177, 0x0e74, 0x0bfb, 0x09f8,
+  0x0861, 0x0706, 0x05cd, 0x04de, 0x040f, 0x0363, 0x02d4, 0x025c,
+  0x01f8, 0x01a4, 0x0160, 0x0125, 0x00f6, 0x00cb, 0x00ab, 0x008f,
+  0x5b12, 0x4d04, 0x412c, 0x37d8, 0x2fe8, 0x293c, 0x2379, 0x1edf,
+  0x1aa9, 0x174e, 0x1424, 0x119c, 0x0f6b, 0x0d51, 0x0bb6, 0x0a40,
+  0x5832, 0x4d1c, 0x438e, 0x3bdd, 0x34ee, 0x2eae, 0x299a, 0x2516,
+  0x5570, 0x4ca9, 0x44d9, 0x3e22, 0x3824, 0x32b4, 0x2e17, 0x56a8,
+  0x4f46, 0x47e5, 0x41cf, 0x3c3d, 0x375e, 0x5231, 0x4c0f, 0x4639,
+  0x415e, 0x5627, 0x50e7, 0x4b85, 0x5597, 0x504f, 0x5a10, 0x5522,
+  0x59eb
+};
+
+static unsigned char nmpstab[113] = {
+    1,   2,   3,   4,   5,   6,   7,   8,
+    9,  10,  11,  12,  13,  13,  15,  16,
+   17,  18,  19,  20,  21,  22,  23,  24,
+   25,  26,  27,  28,  29,  30,  31,  32,
+   33,  34,  35,   9,  37,  38,  39,  40,
+   41,  42,  43,  44,  45,  46,  47,  48,
+   49,  50,  51,  52,  53,  54,  55,  56,
+   57,  58,  59,  60,  61,  62,  63,  32,
+   65,  66,  67,  68,  69,  70,  71,  72,
+   73,  74,  75,  76,  77,  78,  79,  48,
+   81,  82,  83,  84,  85,  86,  87,  71,
+   89,  90,  91,  92,  93,  94,  86,  96,
+   97,  98,  99, 100,  93, 102, 103, 104,
+   99, 106, 107, 103, 109, 107, 111, 109,
+  111
+};
+
+/*
+ * least significant 7 bits (mask 0x7f) of nlpstab[] contain NLPS value,
+ * most significant bit (mask 0x80) contains SWTCH bit
+ */
+static unsigned char nlpstab[113] = {
+  129,  14,  16,  18,  20,  23,  25,  28,
+   30,  33,  35,   9,  10,  12, 143,  36,
+   38,  39,  40,  42,  43,  45,  46,  48,
+   49,  51,  52,  54,  56,  57,  59,  60,
+   62,  63,  32,  33, 165,  64,  65,  67,
+   68,  69,  70,  72,  73,  74,  75,  77,
+   78,  79,  48,  50,  50,  51,  52,  53,
+   54,  55,  56,  57,  58,  59,  61,  61,
+  193,  80,  81,  82,  83,  84,  86,  87,
+   87,  72,  72,  74,  74,  75,  77,  77,
+  208,  88,  89,  90,  91,  92,  93,  86,
+  216,  95,  96,  97,  99,  99,  93, 223,
+  101, 102, 103, 104,  99, 105, 106, 107,
+  103, 233, 108, 109, 110, 111, 238, 112,
+  240
+};
+
+/*
+ * The next functions implement the arithmedic encoder and decoder
+ * required for JBIG. The same algorithm is also used in the arithmetic
+ * variant of JPEG.
+ */
+
+/* marker codes */
+#define MARKER_STUFF    0x00
+#define MARKER_ESC      0xff
+
+void arith_encode_init(struct jbg_arenc_state *s, int reuse_st)
+{
+  int i;
+  
+  if (!reuse_st)
+    for (i = 0; i < 4096; s->st[i++] = 0) ;
+  s->c = 0;
+  s->a = 0x10000L;
+  s->sc = 0;
+  s->ct = 11;
+  s->buffer = -1;    /* empty */
+  
+  return;
+}
+
+
+void arith_encode_flush(struct jbg_arenc_state *s)
+{
+  unsigned long temp;
+
+  /* find the s->c in the coding interval with the largest
+   * number of trailing zero bits */
+  if ((temp = (s->a - 1 + s->c) & 0xffff0000L) < s->c)
+    s->c = temp + 0x8000;
+  else
+    s->c = temp;
+  /* send remaining bytes to output */
+  s->c <<= s->ct;
+  if (s->c & 0xf8000000L) {
+    /* one final overflow has to be handled */
+    if (s->buffer >= 0) {
+      s->byte_out(s->buffer + 1, s->file);
+      if (s->buffer + 1 == MARKER_ESC)
+	s->byte_out(MARKER_STUFF, s->file);
+    }
+    /* output 0x00 bytes only when more non-0x00 will follow */
+    if (s->c & 0x7fff800L)
+      for (; s->sc; --s->sc)
+	s->byte_out(0x00, s->file);
+  } else {
+    if (s->buffer >= 0)
+      s->byte_out(s->buffer, s->file); 
+    /* T.82 figure 30 says buffer+1 for the above line! Typo? */
+    for (; s->sc; --s->sc) {
+      s->byte_out(0xff, s->file);
+      s->byte_out(MARKER_STUFF, s->file);
+    }
+  }
+  /* output final bytes only if they are not 0x00 */
+  if (s->c & 0x7fff800L) {
+    s->byte_out((s->c >> 19) & 0xff, s->file);
+    if (((s->c >> 19) & 0xff) == MARKER_ESC)
+      s->byte_out(MARKER_STUFF, s->file);
+    if (s->c & 0x7f800L) {
+      s->byte_out((s->c >> 11) & 0xff, s->file);
+      if (((s->c >> 11) & 0xff) == MARKER_ESC)
+	s->byte_out(MARKER_STUFF, s->file);
+    }
+  }
+
+  return;
+}
+
+
+void arith_encode(struct jbg_arenc_state *s, int cx, int pix) 
+{
+  register unsigned lsz, ss;
+  register unsigned char *st;
+  long temp;
+
+  assert(cx >= 0 && cx < 4096);
+  st = s->st + cx;
+  ss = *st & 0x7f;
+  assert(ss < 113);
+  lsz = lsztab[ss];
+
+#if 0
+  fprintf(stderr, "pix = %d, cx = %d, mps = %d, st = %3d, lsz = 0x%04x, "
+	  "a = 0x%05lx, c = 0x%08lx, ct = %2d, buf = 0x%02x\n",
+	  pix, cx, !!(s->st[cx] & 0x80), ss, lsz, s->a, s->c, s->ct,
+	  s->buffer);
+#endif
+
+  if (((pix << 7) ^ s->st[cx]) & 0x80) {
+    /* encode the less probable symbol */
+    if ((s->a -= lsz) >= lsz) {
+      /* If the interval size (lsz) for the less probable symbol (LPS)
+       * is larger than the interval size for the MPS, then exchange
+       * the two symbols for coding efficiency, otherwise code the LPS
+       * as usual: */
+      s->c += s->a;
+      s->a = lsz;
+    }
+    /* Check whether MPS/LPS exchange is necessary
+     * and chose next probability estimator status */
+    *st &= 0x80;
+    *st ^= nlpstab[ss];
+  } else {
+    /* encode the more probable symbol */
+    if ((s->a -= lsz) & 0xffff8000L)
+      return;   /* A >= 0x8000 -> ready, no renormalization required */
+    if (s->a < lsz) {
+      /* If the interval size (lsz) for the less probable symbol (LPS)
+       * is larger than the interval size for the MPS, then exchange
+       * the two symbols for coding efficiency: */
+      s->c += s->a;
+      s->a = lsz;
+    }
+    /* chose next probability estimator status */
+    *st &= 0x80;
+    *st |= nmpstab[ss];
+  }
+
+  /* renormalization of coding interval */
+  do {
+    s->a <<= 1;
+    s->c <<= 1;
+    --s->ct;
+    if (s->ct == 0) {
+      /* another byte is ready for output */
+      temp = s->c >> 19;
+      if (temp & 0xffffff00L) {
+	/* handle overflow over all buffered 0xff bytes */
+	if (s->buffer >= 0) {
+	  ++s->buffer;
+	  s->byte_out(s->buffer, s->file);
+	  if (s->buffer == MARKER_ESC)
+	    s->byte_out(MARKER_STUFF, s->file);
+	}
+	for (; s->sc; --s->sc)
+	  s->byte_out(0x00, s->file);
+	s->buffer = temp & 0xff;  /* new output byte, might overflow later */
+	assert(s->buffer != 0xff);
+	/* can s->buffer really never become 0xff here? */
+      } else if (temp == 0xff) {
+	/* buffer 0xff byte (which might overflow later) */
+	++s->sc;
+      } else {
+	/* output all buffered 0xff bytes, they will not overflow any more */
+	if (s->buffer >= 0)
+	  s->byte_out(s->buffer, s->file);
+	for (; s->sc; --s->sc) {
+	  s->byte_out(0xff, s->file);
+	  s->byte_out(MARKER_STUFF, s->file);
+	}
+	s->buffer = temp;   /* buffer new output byte (can still overflow) */
+      }
+      s->c &= 0x7ffffL;
+      s->ct = 8;
+    }
+  } while (s->a < 0x8000);
+ 
+  return;
+}
+
+
+void arith_decode_init(struct jbg_ardec_state *s, int reuse_st)
+{
+  int i;
+  
+  if (!reuse_st)
+    for (i = 0; i < 4096; s->st[i++] = 0) ;
+  s->c = 0;
+  s->a = 1;
+  s->ct = 0;
+  s->startup = 1;
+  s->nopadding = 0;
+  return;
+}
+
+/*
+ * Decode and return one symbol from the provided PSCD byte stream
+ * that starts in s->pscd_ptr and ends in the byte before s->pscd_end.
+ * The context cx is a 12-bit integer in the range 0..4095. This
+ * function will advance s->pscd_ptr each time it has consumed all
+ * information from that PSCD byte.
+ *
+ * If a symbol has been decoded successfully, the return value will be
+ * 0 or 1 (depending on the symbol).
+ *
+ * If the decoder was not able to decode a symbol from the provided
+ * PSCD, then the return value will be -1, and two cases can be
+ * distinguished:
+ *
+ * s->pscd_ptr == s->pscd_end:
+ *
+ *   The decoder has used up all information in the provided PSCD
+ *   bytes. Further PSCD bytes have to be provided (via new values of
+ *   s->pscd_ptr and/or s->pscd_end) before another symbol can be
+ *   decoded.
+ *
+ * s->pscd_ptr == s->pscd_end - 1:
+ * 
+ *   The decoder has used up all provided PSCD bytes except for the
+ *   very last byte, because that has the value 0xff. The decoder can
+ *   at this point not yet tell whether this 0xff belongs to a
+ *   MARKER_STUFF sequence or marks the end of the PSCD. Further PSCD
+ *   bytes have to be provided (via new values of s->pscd_ptr and/or
+ *   s->pscd_end), including the not yet processed 0xff byte, before
+ *   another symbol can be decoded successfully.
+ *
+ * If s->nopadding != 0, the decoder will return -2 when it reaches
+ * the first two bytes of the marker segment that follows (and
+ * terminates) the PSCD, but before decoding the first symbol that
+ * depends on a bit in the input data that could have been the result
+ * of zero padding, and might, therefore, never have been encoded.
+ * This gives the caller the opportunity to lookahead early enough
+ * beyond a terminating SDNORM/SDRST for a trailing NEWLEN (as
+ * required by T.85) before decoding remaining symbols. Call the
+ * decoder again afterwards as often as necessary (leaving s->pscd_ptr
+ * pointing to the start of the marker segment) to retrieve any
+ * required remaining symbols that might depend on padding.
+ *
+ * [Note that each PSCD can be decoded into an infinitely long
+ * sequence of symbols, because the encoder might have truncated away
+ * an arbitrarily long sequence of trailing 0x00 bytes, which the
+ * decoder will append automatically as needed when it reaches the end
+ * of the PSCD. Therefore, the decoder cannot report any end of the
+ * symbol sequence and other means (external to the PSCD and
+ * arithmetic decoding process) are needed to determine that.]
+ */
+
+int arith_decode(struct jbg_ardec_state *s, int cx)
+{
+  register unsigned lsz, ss;
+  register unsigned char *st;
+  int pix;
+
+  /* renormalization */
+  while (s->a < 0x8000 || s->startup) {
+    while (s->ct <= 8 && s->ct >= 0) {
+      /* first we can move a new byte into s->c */
+      if (s->pscd_ptr >= s->pscd_end) {
+	return -1;  /* more bytes needed */
+      }
+      if (*s->pscd_ptr == 0xff) 
+	if (s->pscd_ptr + 1 >= s->pscd_end) {
+	  return -1; /* final 0xff byte not processed */
+	} else {
+	  if (*(s->pscd_ptr + 1) == MARKER_STUFF) {
+	    s->c |= 0xffL << (8 - s->ct);
+	    s->ct += 8;
+	    s->pscd_ptr += 2;
+	  } else {
+	    s->ct = -1; /* start padding with zero bytes */
+	    if (s->nopadding) {
+	      s->nopadding = 0;
+	      return -2; /* subsequent symbols might depend on zero padding */
+	    }
+	  }
+	}
+      else {
+	s->c |= (long)*(s->pscd_ptr++) << (8 - s->ct);
+	s->ct += 8;
+      }
+    }
+    s->c <<= 1;
+    s->a <<= 1;
+    if (s->ct >= 0) s->ct--;
+    if (s->a == 0x10000L)
+      s->startup = 0;
+  }
+
+  st = s->st + cx;
+  ss = *st & 0x7f;
+  assert(ss < 113);
+  lsz = lsztab[ss];
+
+#if 0
+  fprintf(stderr, "cx = %d, mps = %d, st = %3d, lsz = 0x%04x, a = 0x%05lx, "
+	  "c = 0x%08lx, ct = %2d\n",
+	  cx, !!(s->st[cx] & 0x80), ss, lsz, s->a, s->c, s->ct);
+#endif
+
+  if ((s->c >> 16) < (s->a -= lsz))
+    if (s->a & 0xffff8000L)
+      return *st >> 7;
+    else {
+      /* MPS_EXCHANGE */
+      if (s->a < lsz) {
+	pix = 1 - (*st >> 7);
+	/* Check whether MPS/LPS exchange is necessary
+	 * and chose next probability estimator status */
+	*st &= 0x80;
+	*st ^= nlpstab[ss];
+      } else {
+	pix = *st >> 7;
+	*st &= 0x80;
+	*st |= nmpstab[ss];
+      }
+    }
+  else {
+    /* LPS_EXCHANGE */
+    if (s->a < lsz) {
+      s->c -= s->a << 16;
+      s->a = lsz;
+      pix = *st >> 7;
+      *st &= 0x80;
+      *st |= nmpstab[ss];
+    } else {
+      s->c -= s->a << 16;
+      s->a = lsz;
+      pix = 1 - (*st >> 7);
+      /* Check whether MPS/LPS exchange is necessary
+       * and chose next probability estimator status */
+      *st &= 0x80;
+      *st ^= nlpstab[ss];
+    }
+  }
+
+  return pix;
+}
diff --git a/converter/other/jbig/pnmtojbig.c b/converter/other/jbig/pnmtojbig.c
index 9dbef3fa..f5188c7b 100644
--- a/converter/other/jbig/pnmtojbig.c
+++ b/converter/other/jbig/pnmtojbig.c
@@ -195,7 +195,7 @@ readPnm(FILE *            const fin,
     free(image);
     
     /* Invert the image if it is just one plane.  See top of this file
-       for an explanation why.  Due to the separate handling of PBM,
+       for an explanation why.  Because of the separate handling of PBM,
        this is for exceptional PGM files.  
     */
 
diff --git a/converter/other/jpeg2000/Makefile b/converter/other/jpeg2000/Makefile
index f2e3b4a1..6e5af8e7 100644
--- a/converter/other/jpeg2000/Makefile
+++ b/converter/other/jpeg2000/Makefile
@@ -5,21 +5,23 @@ endif
 SUBDIR = converter/other/jpeg2000
 VPATH=.:$(SRCDIR)/$(SUBDIR)
 
-SUBDIRS = libjasper
+SUBDIRS =
 
 include $(BUILDDIR)/config.mk
 
 EXTERN_INCLUDES =
-ifneq ($(JASPERHDR_DIR),NONE)
-  EXTERN_INCLUDES += -I$(JASPERHDR_DIR)
-endif
-
 
 # INTERNAL_JASPERLIB must be relative to the current directory, because it
 # may end up in MERGE_OBJECTS, which must be relative.
 INTERNAL_JASPERLIB = libjasper/libjasper.a
 INTERNAL_JASPERHDR_DIR = $(SRCDIR)/$(SUBDIR)/libjasper/include
 
+ifneq ($(JASPERHDR_DIR),NONE)
+  ifneq ($(JASPERHDR_DIR)x,x)
+    EXTERN_INCLUDES += -I$(JASPERHDR_DIR)
+  endif
+endif
+
 ifeq ($(JASPERLIB),$(INTERNAL_JASPERLIB))
   ifeq ($(HAVE_INT64),Y)
     JASPERLIB_DEP = $(JASPERLIB)
@@ -38,17 +40,19 @@ endif
 
 ifneq ($(JASPERHDR_DIR),NONE)
   ifneq ($(JASPERLIB_USE),NONE)
-    BINARIES = pamtojpeg2k jpeg2ktopam
+    PORTBINARIES = pamtojpeg2k jpeg2ktopam
   endif
 endif
 
+BINARIES = $(PORTBINARIES)
 
 OBJECTS = $(BINARIES:%=%.o)
 MERGE_OBJECTS = $(BINARIES:%=%.o2) 
 ifeq ($(JASPERLIB),$(INTERNAL_JASPERLIB))
   # MERGE_OBJECTS contains relative paths, so $(INTERNAL_JASPERLIB) had better
-  # be relative to the current relative to the current directory.
+  # be relative to the current directory.
   MERGE_OBJECTS += $(JASPERLIB)
+  SUBDIRS += libjasper
 endif
 MERGEBINARIES = $(BINARIES)
 
@@ -57,12 +61,10 @@ all: $(BINARIES)
 
 include $(SRCDIR)/common.mk
 
-LIBOPTS = $(shell $(LIBOPT) $(JASPERLIB_USE) $(NETPBMLIB))
+LIBOPTS = $(shell $(LIBOPT) $(JASPERLIB_USE))
 
-$(BINARIES): %: %.o $(JASPERLIB_DEP) $(NETPBMLIB) $(LIBOPT)
-	$(LD) -o $@ $< \
-	  $(LIBOPTS) $(JASPERDEPLIBS) $(MATHLIB) $(RPATH) \
-	  $(LDFLAGS) $(LDLIBS) $(LADD)
+$(BINARIES): %: %.o $(JASPERLIB_DEP) $(LIBOPT)
+$(BINARIES): LDFLAGS_TARGET = $(LIBOPTS) $(JASPERDEPLIBS)
 
 $(INTERNAL_JASPERLIB): $(BUILDDIR)/$(SUBDIR)/libjasper FORCE
 	$(MAKE) -f $(SRCDIR)/$(SUBDIR)/libjasper/Makefile \
diff --git a/converter/other/jpeg2000/jpeg2ktopam.c b/converter/other/jpeg2000/jpeg2ktopam.c
index e6db7658..405de9c9 100644
--- a/converter/other/jpeg2000/jpeg2ktopam.c
+++ b/converter/other/jpeg2000/jpeg2ktopam.c
@@ -9,17 +9,23 @@
 *****************************************************************************/
 
 #define _BSD_SOURCE 1      /* Make sure strdup() is in string.h */
-/* Make sure strdup() is in string.h and int_fast32_t is in inttypes.h */
-#define _XOPEN_SOURCE 600
+#define _XOPEN_SOURCE 500 /* Make sure strdup() is in string.h */
+    /* In 2014.09, this was _XOPEN_SOURCE 600, with a comment saying it was
+       necessary to make <inttypes.h> define int_fast32_t, etc. on AIX.
+       <jasper/jasper.h> does use int_fast32_t and does include <inttypes.h>,
+       but plenty of source files of libjasper do to0, and they did not have
+       _XOPEN_SOURCE 600, so it would seem to be superfluous here too.
+    */
 #include <string.h>
 
+#include <jasper/jasper.h>
+
 #include "pm_c_util.h"
 #include "pam.h"
 #include "shhopt.h"
 #include "nstring.h"
 #include "mallocvar.h"
 
-#include <jasper/jasper.h>
 #include "libjasper_compat.h"
 
 enum compmode {COMPMODE_INTEGER, COMPMODE_REAL};
@@ -41,7 +47,7 @@ parseCommandLine(int argc, char ** argv,
                  struct cmdlineInfo * const cmdlineP) {
 /*----------------------------------------------------------------------------
    Note that many of the strings that this function returns in the
-   *cmdline_p structure are actually in the supplied argv array.  And
+   *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!
 -----------------------------------------------------------------------------*/
@@ -64,7 +70,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 */
 
-    optParseOptions3(&argc, argv, opt, sizeof(opt), 0);
+    pm_optParseOptions3(&argc, argv, opt, sizeof(opt), 0);
 
     if (!debuglevelSpec)
         cmdlineP->debuglevel = 0;
@@ -82,36 +88,57 @@ parseCommandLine(int argc, char ** argv,
 
 
 static void
-readJpc(const char *   const inputFilename, 
+validateJ2k(jas_stream_t * const instreamP) {
+/*----------------------------------------------------------------------------
+   Abort program with error message if *instreamP is not a JPEG-2000 code
+   stream (JPC) or image file (JP2).
+-----------------------------------------------------------------------------*/
+    assert(jas_image_lookupfmtbyname("jpc"));
+    assert(jas_image_lookupfmtbyname("jp2"));
+
+    if (jas_image_lookupfmtbyname("jpc")->ops.validate(instreamP) != 0 &&
+        jas_image_lookupfmtbyname("jp2")->ops.validate(instreamP) != 0) {
+
+        pm_error("Input is not JPEG-2000 image file (JP2) "
+                 "or code stream (JPC).  "
+                 "(the first few bytes of the file are not the required "
+                 "signature)");
+    }
+}
+
+        
+
+
+static void
+readJ2k(const char *   const inputFilename, 
         jas_image_t ** const jasperPP) {
 
     jas_image_t * jasperP;
-    jas_stream_t *instream;
+    jas_stream_t * instreamP;
     const char * options;
 
-    if ( strcmp(inputFilename, "-") == 0) {
+    if (streq(inputFilename, "-")) {
         /* The input image is to be read from standard input. */
-        instream = jas_stream_fdopen(fileno(stdin), "rb");
-        if (instream == NULL)
+        instreamP = jas_stream_fdopen(fileno(stdin), "rb");
+        if (instreamP == NULL)
             pm_error("error: cannot reopen standard input");
     } else {
-        instream = jas_stream_fopen(inputFilename, "rb");
-        if (instream == NULL )
+        instreamP = jas_stream_fopen(inputFilename, "rb");
+        if (instreamP == NULL )
             pm_error("cannot open input image file '%s'", inputFilename);
     } 
 
-    if (jas_image_getfmt(instream) != jas_image_strtofmt((char*)"jpc"))
-        pm_error("Input is not JPEG-2000 code stream");
+    validateJ2k(instreamP);
 
     options = "";
 
-    jasperP = jas_image_decode(instream, jas_image_strtofmt((char*)"jpc"), 
+    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.");
 
-	jas_stream_close(instream);
+	jas_stream_close(instreamP);
 
     *jasperPP = jasperP;
 }
@@ -189,7 +216,7 @@ static void
 validateComponentsAlike(jas_image_t * const jasperP) {
 /*----------------------------------------------------------------------------
    JPC allows each component to have its own width and height.  But
-   PAM requires all planes to the same shape.  So we validate now that
+   PAM requires all planes to have the same shape.  So we validate now that
    all the channels are the same, and abort the program if not.
 -----------------------------------------------------------------------------*/
     int cmptNo;
@@ -406,8 +433,9 @@ convertToPamPnm(struct pam *  const outpamP,
     unsigned int row;
     tuple * tuplerow;
     jas_seqent_t ** jasperRow;   /* malloc'ed */
-       /* A row of a plane of the raster from the Jasper library 
-          This is an array of pointers into the 'matrix' data structures.
+       /* A row of the raster from the Jasper library This is an array of
+          pointers into the 'matrix' data structures, one for each plane in
+          the row.
        */
     bool singleMaxval;
 
@@ -479,7 +507,7 @@ main(int argc, char **argv)
     
     jas_setdbglevel(cmdline.debuglevel);
     
-    readJpc(cmdline.inputFilename, &jasperP);
+    readJ2k(cmdline.inputFilename, &jasperP);
 
     outpam.file = stdout;
     outpam.size = sizeof(outpam);
diff --git a/converter/other/jpeg2000/libjasper/README b/converter/other/jpeg2000/libjasper/README
index ad3e019b..b0512fe8 100644
--- a/converter/other/jpeg2000/libjasper/README
+++ b/converter/other/jpeg2000/libjasper/README
@@ -6,10 +6,12 @@ The adaptation was done by Bryan Henderson on 2002.10.26.
 
 The adaptation involved:
 
-  - remove stuff for formats other than PNM.
+  - Remove stuff for formats other than JPEG-2000.
 
   - Replace build stuff (Jasper uses GNU Autoconf/Automake/Libtool).
 
+  - Make JP2 decoder not dump the box to stderr unless debug is turned on.
+
 See <http://www.ece.uvic.ca/~mdadams/jasper/>.
 
 
diff --git a/converter/other/jpeg2000/libjasper/base/jas_image.c b/converter/other/jpeg2000/libjasper/base/jas_image.c
index e6439fcd..903b45c6 100644
--- a/converter/other/jpeg2000/libjasper/base/jas_image.c
+++ b/converter/other/jpeg2000/libjasper/base/jas_image.c
@@ -375,9 +375,9 @@ static void jas_image_cmpt_destroy(jas_image_cmpt_t *cmpt)
 	jas_free(cmpt);
 }
 
-/******************************************************************************\
+/*****************************************************************************\
 * Load and save operations.
-\******************************************************************************/
+\*****************************************************************************/
 
 jas_image_t *jas_image_decode(jas_stream_t *in, int fmt, char *optstr)
 {
@@ -623,7 +623,7 @@ int jas_image_getfmt(jas_stream_t *in)
 	int found;
 	int i;
 
-	/* Check for data in each of the supported formats. */
+	/* Check for data in each of the formats we know. */
 	found = 0;
 	for (i = 0, fmtinfo = jas_image_fmtinfos; i < jas_image_numfmts; ++i,
 	  ++fmtinfo) {
@@ -857,7 +857,7 @@ void jas_image_dump(jas_image_t *image, FILE *out)
 	}
 	for (cmptno = 0; cmptno < image->numcmpts_; ++cmptno) {
 		cmpt = image->cmpts_[cmptno];
-		fprintf(out, "prec=%d sgnd=%d\n", cmpt->prec_, cmpt->sgnd_);
+		fprintf(out, "prec=%d sgnd=%d\n", (int)cmpt->prec_, cmpt->sgnd_);
 		if (jas_image_readcmpt(image, cmptno, 0, 0, 1, 1, data)) {
 			abort();
 		}
diff --git a/converter/other/jpeg2000/libjasper/base/jas_seq.c b/converter/other/jpeg2000/libjasper/base/jas_seq.c
index b8e3c94b..12dc1595 100644
--- a/converter/other/jpeg2000/libjasper/base/jas_seq.c
+++ b/converter/other/jpeg2000/libjasper/base/jas_seq.c
@@ -414,7 +414,8 @@ int jas_matrix_output(jas_matrix_t *matrix, FILE *out)
 	int j;
 	jas_seqent_t x;
 
-	fprintf(out, "%d %d\n", jas_matrix_numrows(matrix), jas_matrix_numcols(matrix));
+	fprintf(out, "%d %d\n",
+            (int)jas_matrix_numrows(matrix), (int)jas_matrix_numcols(matrix));
 	for (i = 0; i < jas_matrix_numrows(matrix); ++i) {
 		for (j = 0; j < jas_matrix_numcols(matrix); ++j) {
 			x = jas_matrix_get(matrix, i, j);
diff --git a/converter/other/jpeg2000/libjasper/base/jas_stream.c b/converter/other/jpeg2000/libjasper/base/jas_stream.c
index 4c84e6c2..16c948eb 100644
--- a/converter/other/jpeg2000/libjasper/base/jas_stream.c
+++ b/converter/other/jpeg2000/libjasper/base/jas_stream.c
@@ -117,6 +117,7 @@
     */
 #define _XOPEN_SOURCE 500    /* Make sure P_tmpdir is defined */
 
+#include "pm_config.h"
 #include <assert.h>
 #include <fcntl.h>
 #include <stdlib.h>
@@ -126,11 +127,11 @@
 #if defined(HAVE_UNISTD_H)
 #include <unistd.h>
 #endif
-#if defined(WIN32) || defined(HAVE_IO_H)
+#if HAVE_IO_H
 #include <io.h>
 #endif
 
-#include "pm.h"
+#include "netpbm/pm.h"
 
 #include "jasper/jas_types.h"
 #include "jasper/jas_stream.h"
@@ -440,7 +441,7 @@ jas_stream_t *jas_stream_fdopen(int fd, const char *mode)
 	/* Parse the mode string. */
 	stream->openmode_ = jas_strtoopenmode(mode);
 
-#if defined(WIN32)
+#if defined(HAVE_SETMODE) && defined(O_BINARY)
 	/* Argh!!!  Someone ought to banish text mode (i.e., O_TEXT) to the
 	  greatest depths of purgatory! */
 	/* Ensure that the file descriptor is in binary mode, if the caller
@@ -902,7 +903,7 @@ int jas_stream_copy(jas_stream_t *out, jas_stream_t *in, int n)
 	while (all || m > 0) {
 		if ((c = jas_stream_getc_macro(in)) == EOF) {
 			/* The next character of input could not be read. */
-			/* Return with an error if an I/O error occured
+			/* Return with an error if an I/O error occurred
 			  (not including EOF) or if an explicit copy count
 			  was specified. */
 			return (!all || jas_stream_error(in)) ? (-1) : 0;
diff --git a/converter/other/jpeg2000/libjasper/common.mk b/converter/other/jpeg2000/libjasper/common.mk
index 687a9f3f..a333f5d6 100644
--- a/converter/other/jpeg2000/libjasper/common.mk
+++ b/converter/other/jpeg2000/libjasper/common.mk
@@ -13,19 +13,19 @@ partlist: $(SUBDIRS:%=%/partlist)
 	cat /dev/null $(SUBDIRS:%=%/partlist) >$@
 	echo $(LIB_OBJECTS:%=$(CURDIR)/%) >>$@
 
-.PHONY: $(SUBDIRS:%=%/partlist)
-$(SUBDIRS:%=%/partlist): %/partlist: $(CURDIR)/%
+$(SUBDIRS:%=%/partlist):
 	$(MAKE) -C $(dir $@) -f $(SRCDIR)/$(SUBDIR)/$(dir $@)Makefile \
 	    SRCDIR=$(SRCDIR) BUILDDIR=$(BUILDDIR) $(notdir $@) 
 
 include $(SRCDIR)/common.mk
 
-INCLUDES = -I$(JASPERSRCDIR)/include -Iimportinc
+INCLUDES := -I$(JASPERSRCDIR)/include $(INCLUDES)
 
 DEFS = -DHAVE_LIBM=1 -DSTDC_HEADERS=1 -DHAVE_FCNTL_H=1 -DHAVE_LIMITS_H=1 -DHAVE_UNISTD_H=1 -DHAVE_SYS_TYPES_H=1 -DHAVE_STDLIB_H=1 -DHAVE_STDDEF_H=1 -DEXCLUDE_BMP_SUPPORT -DEXCLUDE_RAS_SUPPORT -DEXCLUDE_MIF_SUPPORT -DEXCLUDE_JPG_SUPPORT -DEXCLUDE_PGX_SUPPORT -DEXCLUDE_PNM_SUPPORT
 
 $(LIB_OBJECTS):%.o:%.c
-	$(CC) -c $(INCLUDES) $(DEFS) $(CPPFLAGS) $(CFLAGS) $(CADD) $<
+	$(CC) -c $(INCLUDES) $(DEFS) $(CPPFLAGS) $(CFLAGS) \
+	  $(CFLAGS_PERSONAL) $(CADD) $<
 
 $(LIB_OBJECTS): importinc
 
diff --git a/converter/other/jpeg2000/libjasper/include/jasper/jas_image.h b/converter/other/jpeg2000/libjasper/include/jasper/jas_image.h
index d6456f7c..6e914efd 100644
--- a/converter/other/jpeg2000/libjasper/include/jasper/jas_image.h
+++ b/converter/other/jpeg2000/libjasper/include/jasper/jas_image.h
@@ -123,7 +123,7 @@
 * Includes.
 \******************************************************************************/
 
-#include "pm_c_util.h"
+#include "netpbm/pm_c_util.h"
 #include <jasper/jas_stream.h>
 #include <jasper/jas_seq.h>
 
@@ -171,9 +171,9 @@ extern "C" {
 
 #define	JAS_IMAGE_CT_GRAY_Y	0
 
-/******************************************************************************\
+/*****************************************************************************\
 * Image class and supporting classes.
-\******************************************************************************/
+\*****************************************************************************/
 
 /* Image component class. */
 
@@ -294,7 +294,7 @@ typedef struct {
 \******************************************************************************/
 
 #define	JAS_IMAGE_MAXFMTS	32
-/* The maximum number of image data formats supported. */
+/* The maximum number of image data formats we can handle. */
 
 /* Image format-dependent operations. */
 
@@ -530,57 +530,57 @@ int jas_image_getfmt(jas_stream_t *in);
 * Image format-dependent operations.
 \******************************************************************************/
 
-#if !defined(EXCLUDE_JPG_SUPPORT)
-/* Format-dependent operations for JPG support. */
+#if !defined(EXCLUDE_JPG_CAPABILITY)
+/* Format-dependent operations for JPG capability. */
 jas_image_t *jpg_decode(jas_stream_t *in, char *optstr);
 int jpg_encode(jas_image_t *image, jas_stream_t *out, char *optstr);
 int jpg_validate(jas_stream_t *in);
 #endif
 
-#if !defined(EXCLUDE_MIF_SUPPORT)
-/* Format-dependent operations for MIF support. */
+#if !defined(EXCLUDE_MIF_CAPABILITY)
+/* Format-dependent operations for MIF capability. */
 jas_image_t *mif_decode(jas_stream_t *in, char *optstr);
 int mif_encode(jas_image_t *image, jas_stream_t *out, char *optstr);
 int mif_validate(jas_stream_t *in);
 #endif
 
-#if !defined(EXCLUDE_PNM_SUPPORT)
-/* Format-dependent operations for PNM support. */
+#if !defined(EXCLUDE_PNM_CAPABILITY)
+/* Format-dependent operations for PNM capability. */
 jas_image_t *pnm_decode(jas_stream_t *in, char *optstr);
 int pnm_encode(jas_image_t *image, jas_stream_t *out, char *optstr);
 int pnm_validate(jas_stream_t *in);
 #endif
 
-#if !defined(EXCLUDE_RAS_SUPPORT)
-/* Format-dependent operations for Sun Rasterfile support. */
+#if !defined(EXCLUDE_RAS_CAPABILITY)
+/* Format-dependent operations for Sun Rasterfile capability. */
 jas_image_t *ras_decode(jas_stream_t *in, char *optstr);
 int ras_encode(jas_image_t *image, jas_stream_t *out, char *optstr);
 int ras_validate(jas_stream_t *in);
 #endif
 
-#if !defined(EXCLUDE_BMP_SUPPORT)
-/* Format-dependent operations for BMP support. */
+#if !defined(EXCLUDE_BMP_CAPABILITY)
+/* Format-dependent operations for BMP capability. */
 jas_image_t *bmp_decode(jas_stream_t *in, char *optstr);
 int bmp_encode(jas_image_t *image, jas_stream_t *out, char *optstr);
 int bmp_validate(jas_stream_t *in);
 #endif
 
-#if !defined(EXCLUDE_JP2_SUPPORT)
-/* Format-dependent operations for JP2 support. */
+#if !defined(EXCLUDE_JP2_CAPABILITY)
+/* Format-dependent operations for JP2 capability. */
 jas_image_t *jp2_decode(jas_stream_t *in, char *optstr);
 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_SUPPORT)
-/* Format-dependent operations for JPEG-2000 code stream support. */
+#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);
 int jpc_encode(jas_image_t *image, jas_stream_t *out, char *optstr);
 int jpc_validate(jas_stream_t *in);
 #endif
 
-#if !defined(EXCLUDE_PGX_SUPPORT)
-/* Format-dependent operations for PGX support. */
+#if !defined(EXCLUDE_PGX_CAPABILITY)
+/* Format-dependent operations for PGX capability. */
 jas_image_t *pgx_decode(jas_stream_t *in, char *optstr);
 int pgx_encode(jas_image_t *image, jas_stream_t *out, char *optstr);
 int pgx_validate(jas_stream_t *in);
diff --git a/converter/other/jpeg2000/libjasper/include/jasper/jas_types.h b/converter/other/jpeg2000/libjasper/include/jasper/jas_types.h
index 4d3a4988..fbcb2ffb 100644
--- a/converter/other/jpeg2000/libjasper/include/jasper/jas_types.h
+++ b/converter/other/jpeg2000/libjasper/include/jasper/jas_types.h
@@ -4,7 +4,7 @@
    In Netpbm, we do that with pm_config.h, and the original Jasper
    method doesn't work.
 */
-#include "pm_config.h"
+#include "netpbm/pm_config.h"
 
 
 /* The below macro is intended to be used for type casts.  By using this
diff --git a/converter/other/jpeg2000/libjasper/include/jasper/jas_types.h.orig b/converter/other/jpeg2000/libjasper/include/jasper/jas_types.h.orig
deleted file mode 100644
index 10c1152d..00000000
--- a/converter/other/jpeg2000/libjasper/include/jasper/jas_types.h.orig
+++ /dev/null
@@ -1,228 +0,0 @@
-/*
- * Copyright (c) 1999-2000 Image Power, Inc. and the University of
- *   British Columbia.
- * Copyright (c) 2001-2002 Michael David Adams.
- * All rights reserved.
- */
-
-/* __START_OF_JASPER_LICENSE__
- * 
- * JasPer Software License
- * 
- * IMAGE POWER JPEG-2000 PUBLIC LICENSE
- * ************************************
- * 
- * GRANT:
- * 
- * Permission is hereby granted, free of charge, to any person (the "User")
- * obtaining a copy of this software and associated documentation, to deal
- * in the JasPer Software without restriction, including without limitation
- * the right to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the JasPer Software (in source and binary forms),
- * and to permit persons to whom the JasPer Software is furnished to do so,
- * provided further that the License Conditions below are met.
- * 
- * License Conditions
- * ******************
- * 
- * A.  Redistributions of source code must retain the above copyright notice,
- * and this list of conditions, and the following disclaimer.
- * 
- * B.  Redistributions in binary form must reproduce the above copyright
- * notice, and this list of conditions, and the following disclaimer in
- * the documentation and/or other materials provided with the distribution.
- * 
- * C.  Neither the name of Image Power, Inc. nor any other contributor
- * (including, but not limited to, the University of British Columbia and
- * Michael David Adams) may be used to endorse or promote products derived
- * from this software without specific prior written permission.
- * 
- * D.  User agrees that it shall not commence any action against Image Power,
- * Inc., the University of British Columbia, Michael David Adams, or any
- * other contributors (collectively "Licensors") for infringement of any
- * intellectual property rights ("IPR") held by the User in respect of any
- * technology that User owns or has a right to license or sublicense and
- * which is an element required in order to claim compliance with ISO/IEC
- * 15444-1 (i.e., JPEG-2000 Part 1).  "IPR" means all intellectual property
- * rights worldwide arising under statutory or common law, and whether
- * or not perfected, including, without limitation, all (i) patents and
- * patent applications owned or licensable by User; (ii) rights associated
- * with works of authorship including copyrights, copyright applications,
- * copyright registrations, mask work rights, mask work applications,
- * mask work registrations; (iii) rights relating to the protection of
- * trade secrets and confidential information; (iv) any right analogous
- * to those set forth in subsections (i), (ii), or (iii) and any other
- * proprietary rights relating to intangible property (other than trademark,
- * trade dress, or service mark rights); and (v) divisions, continuations,
- * renewals, reissues and extensions of the foregoing (as and to the extent
- * applicable) now existing, hereafter filed, issued or acquired.
- * 
- * E.  If User commences an infringement action against any Licensor(s) then
- * such Licensor(s) shall have the right to terminate User's license and
- * all sublicenses that have been granted hereunder by User to other parties.
- * 
- * F.  This software is for use only in hardware or software products that
- * are compliant with ISO/IEC 15444-1 (i.e., JPEG-2000 Part 1).  No license
- * or right to this Software is granted for products that do not comply
- * with ISO/IEC 15444-1.  The JPEG-2000 Part 1 standard can be purchased
- * from the ISO.
- * 
- * THIS DISCLAIMER OF WARRANTY CONSTITUTES AN ESSENTIAL PART OF THIS LICENSE.
- * NO USE OF THE JASPER SOFTWARE IS AUTHORIZED HEREUNDER EXCEPT UNDER
- * THIS DISCLAIMER.  THE JASPER SOFTWARE IS PROVIDED BY THE LICENSORS AND
- * CONTRIBUTORS UNDER THIS LICENSE ON AN ``AS-IS'' BASIS, WITHOUT WARRANTY
- * OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, WITHOUT LIMITATION,
- * WARRANTIES THAT THE JASPER SOFTWARE IS FREE OF DEFECTS, IS MERCHANTABLE,
- * IS FIT FOR A PARTICULAR PURPOSE OR IS NON-INFRINGING.  THOSE INTENDING
- * TO USE THE JASPER SOFTWARE OR MODIFICATIONS THEREOF FOR USE IN HARDWARE
- * OR SOFTWARE PRODUCTS ARE ADVISED THAT THEIR USE MAY INFRINGE EXISTING
- * PATENTS, COPYRIGHTS, TRADEMARKS, OR OTHER INTELLECTUAL PROPERTY RIGHTS.
- * THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE JASPER SOFTWARE
- * IS WITH THE USER.  SHOULD ANY PART OF THE JASPER SOFTWARE PROVE DEFECTIVE
- * IN ANY RESPECT, THE USER (AND NOT THE INITIAL DEVELOPERS, THE UNIVERSITY
- * OF BRITISH COLUMBIA, IMAGE POWER, INC., MICHAEL DAVID ADAMS, OR ANY
- * OTHER CONTRIBUTOR) SHALL ASSUME THE COST OF ANY NECESSARY SERVICING,
- * REPAIR OR CORRECTION.  UNDER NO CIRCUMSTANCES AND UNDER NO LEGAL THEORY,
- * WHETHER TORT (INCLUDING NEGLIGENCE), CONTRACT, OR OTHERWISE, SHALL THE
- * INITIAL DEVELOPER, THE UNIVERSITY OF BRITISH COLUMBIA, IMAGE POWER, INC.,
- * MICHAEL DAVID ADAMS, ANY OTHER CONTRIBUTOR, OR ANY DISTRIBUTOR OF THE
- * JASPER SOFTWARE, OR ANY SUPPLIER OF ANY OF SUCH PARTIES, BE LIABLE TO
- * THE USER OR ANY OTHER PERSON FOR ANY INDIRECT, SPECIAL, INCIDENTAL, OR
- * CONSEQUENTIAL DAMAGES OF ANY CHARACTER INCLUDING, WITHOUT LIMITATION,
- * DAMAGES FOR LOSS OF GOODWILL, WORK STOPPAGE, COMPUTER FAILURE OR
- * MALFUNCTION, OR ANY AND ALL OTHER COMMERCIAL DAMAGES OR LOSSES, EVEN IF
- * SUCH PARTY HAD BEEN INFORMED, OR OUGHT TO HAVE KNOWN, OF THE POSSIBILITY
- * OF SUCH DAMAGES.  THE JASPER SOFTWARE AND UNDERLYING TECHNOLOGY ARE NOT
- * FAULT-TOLERANT AND ARE NOT DESIGNED, MANUFACTURED OR INTENDED FOR USE OR
- * RESALE AS ON-LINE CONTROL EQUIPMENT IN HAZARDOUS ENVIRONMENTS REQUIRING
- * FAIL-SAFE PERFORMANCE, SUCH AS IN THE OPERATION OF NUCLEAR FACILITIES,
- * AIRCRAFT NAVIGATION OR COMMUNICATION SYSTEMS, AIR TRAFFIC CONTROL, DIRECT
- * LIFE SUPPORT MACHINES, OR WEAPONS SYSTEMS, IN WHICH THE FAILURE OF THE
- * JASPER SOFTWARE OR UNDERLYING TECHNOLOGY OR PRODUCT COULD LEAD DIRECTLY
- * TO DEATH, PERSONAL INJURY, OR SEVERE PHYSICAL OR ENVIRONMENTAL DAMAGE
- * ("HIGH RISK ACTIVITIES").  LICENSOR SPECIFICALLY DISCLAIMS ANY EXPRESS
- * OR IMPLIED WARRANTY OF FITNESS FOR HIGH RISK ACTIVITIES.  USER WILL NOT
- * KNOWINGLY USE, DISTRIBUTE OR RESELL THE JASPER SOFTWARE OR UNDERLYING
- * TECHNOLOGY OR PRODUCTS FOR HIGH RISK ACTIVITIES AND WILL ENSURE THAT ITS
- * CUSTOMERS AND END-USERS OF ITS PRODUCTS ARE PROVIDED WITH A COPY OF THE
- * NOTICE SPECIFIED IN THIS SECTION.
- * 
- * __END_OF_JASPER_LICENSE__
- */
-
-/*
- * Primitive Types
- *
- * $Id$
- */
-
-#ifndef JAS_TYPES_H
-#define JAS_TYPES_H
-
-#if defined(HAVE_STDLIB_H)
-#include <stdlib.h>
-#endif
-#if defined(HAVE_STDDEF_H)
-#include <stddef.h>
-#endif
-#if defined(HAVE_SYS_TYPES_H)
-#include <sys/types.h>
-#endif
-
-#if defined(HAVE_STDBOOL_H)
-/*
- * The C language implementation does correctly provide the standard header
- * file "stdbool.h".
- */
-#include <stdbool.h>
-#else
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-/*
- * The C language implementation does not provide the standard header file
- * "stdbool.h" as required by ISO/IEC 9899:1999.  Try to compensate for this
- * braindamage below.
- */
-#if !defined(bool)
-#define	bool	int
-#endif
-#if !defined(true)
-#define true	1
-#endif
-#if !defined(false)
-#define	false	0
-#endif
-
-#ifdef __cplusplus
-}
-#endif
-
-/* pm_config.h defines the FAST integer types if possible (typically by
-   including <inttypes.h>.  If not, the following try to take care
-   of it.
-*/
-/**********/
-#if !defined(INT_FAST8_MAX)
-typedef signed char int_fast8_t;
-#define INT_FAST8_MIN	(-127)
-#define INT_FAST8_MAX	128
-#endif
-/**********/
-#if !defined(UINT_FAST8_MAX)
-typedef unsigned char uint_fast8_t;
-#define UINT_FAST8_MAX	255
-#endif
-/**********/
-#if !defined(INT_FAST16_MAX)
-typedef short int_fast16_t;
-#define INT_FAST16_MIN	SHRT_MIN
-#define INT_FAST16_MAX	SHRT_MAX
-#endif
-/**********/
-#if !defined(UINT_FAST16_MAX)
-typedef unsigned short uint_fast16_t;
-#define UINT_FAST16_MAX	USHRT_MAX
-#endif
-/**********/
-#if !defined(INT_FAST32_MAX)
-typedef int int_fast32_t;
-#define INT_FAST32_MIN	INT_MIN
-#define INT_FAST32_MAX	INT_MAX
-#endif
-/**********/
-#if !defined(UINT_FAST32_MAX)
-typedef unsigned int uint_fast32_t;
-#define UINT_FAST32_MAX	UINT_MAX
-#endif
-/**********/
-#if !defined(INT_FAST64_MAX)
-typedef int int_fast64_t;
-#define INT_FAST64_MIN	LLONG_MIN
-#define INT_FAST64_MAX	LLONG_MAX
-#endif
-/**********/
-#if !defined(UINT_FAST64_MAX)
-typedef unsigned int uint_fast64_t;
-#define UINT_FAST64_MAX	ULLONG_MAX
-#endif
-/**********/
-#endif
-
-/* The below macro is intended to be used for type casts.  By using this
-  macro, type casts can be easily located in the source code with
-  tools like "grep". */
-#define	JAS_CAST(t, e) \
-	((t) (e))
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif
diff --git a/converter/other/jpeg2000/libjasper/jp2/jp2_cod.c b/converter/other/jpeg2000/libjasper/jp2/jp2_cod.c
index 4769c408..c99c9608 100644
--- a/converter/other/jpeg2000/libjasper/jp2/jp2_cod.c
+++ b/converter/other/jpeg2000/libjasper/jp2/jp2_cod.c
@@ -123,7 +123,7 @@
 #include <assert.h>
 #include <stdlib.h>
 
-#include "pm_c_util.h"
+#include "netpbm/pm_c_util.h"
 
 #include "jasper/jas_stream.h"
 #include "jasper/jas_malloc.h"
@@ -135,7 +135,7 @@
 * Function prototypes.
 \******************************************************************************/
 
-#define	ONES(n)	((1 << (n)) - 1)
+#define ONES(n) ((1 << (n)) - 1)
 
 jp2_boxinfo_t *jp2_boxinfolookup(int type);
 
@@ -183,49 +183,49 @@ static void jp2_pclr_dumpdata(jp2_box_t *box, FILE *out);
 \******************************************************************************/
 
 jp2_boxinfo_t jp2_boxinfos[] = {
-	{JP2_BOX_JP, "JP", 0,
-	  {0, 0, jp2_jp_getdata, jp2_jp_putdata, 0}},
-	{JP2_BOX_FTYP, "FTYP", 0,
-	  {0, 0, jp2_ftyp_getdata, jp2_ftyp_putdata, 0}},
-	{JP2_BOX_JP2H, "JP2H", JP2_BOX_SUPER,
-	  {0, 0, 0, 0, 0}},
-	{JP2_BOX_IHDR, "IHDR", 0,
-	  {0, 0, jp2_ihdr_getdata, jp2_ihdr_putdata, 0}},
-	{JP2_BOX_BPCC, "BPCC", 0,
-	  {0, jp2_bpcc_destroy, jp2_bpcc_getdata, jp2_bpcc_putdata, 0}},
-	{JP2_BOX_COLR, "COLR", 0,
-	  {0, jp2_colr_destroy, jp2_colr_getdata, jp2_colr_putdata, jp2_colr_dumpdata}},
-	{JP2_BOX_PCLR, "PCLR", 0,
-	  {0, jp2_pclr_destroy, jp2_pclr_getdata, jp2_pclr_putdata, jp2_pclr_dumpdata}},
-	{JP2_BOX_CMAP, "CMAP", 0,
-	  {0, jp2_cmap_destroy, jp2_cmap_getdata, jp2_cmap_putdata, jp2_cmap_dumpdata}},
-	{JP2_BOX_CDEF, "CDEF", 0,
-	  {0, jp2_cdef_destroy, jp2_cdef_getdata, jp2_cdef_putdata, jp2_cdef_dumpdata}},
-	{JP2_BOX_RES, "RES", JP2_BOX_SUPER,
-	  {0, 0, 0, 0, 0}},
-	{JP2_BOX_RESC, "RESC", 0,
-	  {0, 0, 0, 0, 0}},
-	{JP2_BOX_RESD, "RESD", 0,
-	  {0, 0, 0, 0, 0}},
-	{JP2_BOX_JP2C, "JP2C", JP2_BOX_NODATA,
-	  {0, 0, 0, 0, 0}},
-	{JP2_BOX_JP2I, "JP2I", 0,
-	  {0, 0, 0, 0, 0}},
-	{JP2_BOX_XML, "XML", 0,
-	  {0, 0, 0, 0, 0}},
-	{JP2_BOX_UUID, "UUID", 0,
-	  {0, 0, 0, 0, 0}},
-	{JP2_BOX_UINF, "UINF", JP2_BOX_SUPER,
-	  {0, 0, 0, 0, 0}},
-	{JP2_BOX_ULST, "ULST", 0,
-	  {0, 0, 0, 0, 0}},
-	{JP2_BOX_URL, "URL", 0,
-	  {0, 0, 0, 0, 0}},
-	{0, 0, 0, {0, 0, 0, 0, 0}},
+    {JP2_BOX_JP, "JP", 0,
+      {0, 0, jp2_jp_getdata, jp2_jp_putdata, 0}},
+    {JP2_BOX_FTYP, "FTYP", 0,
+      {0, 0, jp2_ftyp_getdata, jp2_ftyp_putdata, 0}},
+    {JP2_BOX_JP2H, "JP2H", JP2_BOX_SUPER,
+      {0, 0, 0, 0, 0}},
+    {JP2_BOX_IHDR, "IHDR", 0,
+      {0, 0, jp2_ihdr_getdata, jp2_ihdr_putdata, 0}},
+    {JP2_BOX_BPCC, "BPCC", 0,
+      {0, jp2_bpcc_destroy, jp2_bpcc_getdata, jp2_bpcc_putdata, 0}},
+    {JP2_BOX_COLR, "COLR", 0,
+      {0, jp2_colr_destroy, jp2_colr_getdata, jp2_colr_putdata, jp2_colr_dumpdata}},
+    {JP2_BOX_PCLR, "PCLR", 0,
+      {0, jp2_pclr_destroy, jp2_pclr_getdata, jp2_pclr_putdata, jp2_pclr_dumpdata}},
+    {JP2_BOX_CMAP, "CMAP", 0,
+      {0, jp2_cmap_destroy, jp2_cmap_getdata, jp2_cmap_putdata, jp2_cmap_dumpdata}},
+    {JP2_BOX_CDEF, "CDEF", 0,
+      {0, jp2_cdef_destroy, jp2_cdef_getdata, jp2_cdef_putdata, jp2_cdef_dumpdata}},
+    {JP2_BOX_RES, "RES", JP2_BOX_SUPER,
+      {0, 0, 0, 0, 0}},
+    {JP2_BOX_RESC, "RESC", 0,
+      {0, 0, 0, 0, 0}},
+    {JP2_BOX_RESD, "RESD", 0,
+      {0, 0, 0, 0, 0}},
+    {JP2_BOX_JP2C, "JP2C", JP2_BOX_NODATA,
+      {0, 0, 0, 0, 0}},
+    {JP2_BOX_JP2I, "JP2I", 0,
+      {0, 0, 0, 0, 0}},
+    {JP2_BOX_XML, "XML", 0,
+      {0, 0, 0, 0, 0}},
+    {JP2_BOX_UUID, "UUID", 0,
+      {0, 0, 0, 0, 0}},
+    {JP2_BOX_UINF, "UINF", JP2_BOX_SUPER,
+      {0, 0, 0, 0, 0}},
+    {JP2_BOX_ULST, "ULST", 0,
+      {0, 0, 0, 0, 0}},
+    {JP2_BOX_URL, "URL", 0,
+      {0, 0, 0, 0, 0}},
+    {0, 0, 0, {0, 0, 0, 0, 0}},
 };
 
 jp2_boxinfo_t jp2_boxinfo_unk = {
-	0, "Unknown", 0, {0, 0, 0, 0}
+    0, "Unknown", 0, {0, 0, 0, 0}
 };
 
 /******************************************************************************\
@@ -234,21 +234,21 @@ jp2_boxinfo_t jp2_boxinfo_unk = {
 
 jp2_box_t *jp2_box_create(int type)
 {
-	jp2_box_t *box;
-	jp2_boxinfo_t *boxinfo;
+    jp2_box_t *box;
+    jp2_boxinfo_t *boxinfo;
 
-	if (!(box = jas_malloc(sizeof(jp2_box_t)))) {
-		return 0;
-	}
-	memset(box, 0, sizeof(jp2_box_t));
-	box->type = type;
-	box->len = 0;
-	if (!(boxinfo = jp2_boxinfolookup(type))) {
-		return 0;
-	}
-	box->info = boxinfo;
-	box->ops = &boxinfo->ops;
-	return box;
+    if (!(box = jas_malloc(sizeof(jp2_box_t)))) {
+        return 0;
+    }
+    memset(box, 0, sizeof(jp2_box_t));
+    box->type = type;
+    box->len = 0;
+    if (!(boxinfo = jp2_boxinfolookup(type))) {
+        return 0;
+    }
+    box->info = boxinfo;
+    box->ops = &boxinfo->ops;
+    return box;
 }
 
 /******************************************************************************\
@@ -257,28 +257,28 @@ jp2_box_t *jp2_box_create(int type)
 
 void jp2_box_destroy(jp2_box_t *box)
 {
-	if (box->ops->destroy) {
-		(*box->ops->destroy)(box);
-	}
-	jas_free(box);
+    if (box->ops->destroy) {
+        (*box->ops->destroy)(box);
+    }
+    jas_free(box);
 }
 
 static void jp2_bpcc_destroy(jp2_box_t *box)
 {
-	jp2_bpcc_t *bpcc = &box->data.bpcc;
-	if (bpcc->bpcs) {
-		jas_free(bpcc->bpcs);
-		bpcc->bpcs = 0;
-	}
+    jp2_bpcc_t *bpcc = &box->data.bpcc;
+    if (bpcc->bpcs) {
+        jas_free(bpcc->bpcs);
+        bpcc->bpcs = 0;
+    }
 }
 
 static void jp2_cdef_destroy(jp2_box_t *box)
 {
-	jp2_cdef_t *cdef = &box->data.cdef;
-	if (cdef->ents) {
-		jas_free(cdef->ents);
-		cdef->ents = 0;
-	}
+    jp2_cdef_t *cdef = &box->data.cdef;
+    if (cdef->ents) {
+        jas_free(cdef->ents);
+        cdef->ents = 0;
+    }
 }
 
 /******************************************************************************\
@@ -287,222 +287,224 @@ static void jp2_cdef_destroy(jp2_box_t *box)
 
 jp2_box_t *jp2_box_get(jas_stream_t *in)
 {
-	jp2_box_t *box;
-	jp2_boxinfo_t *boxinfo;
-	jas_stream_t *tmpstream;
-	uint_fast32_t len;
+    jp2_box_t *box;
+    jp2_boxinfo_t *boxinfo;
+    jas_stream_t *tmpstream;
+    uint_fast32_t len;
     uint_fast64_t extlen;
-	bool dataflag;
-
-	box = 0;
-	tmpstream = 0;
-
-	if (!(box = jas_malloc(sizeof(jp2_box_t)))) {
-		goto error;
-	}
-	box->ops = &jp2_boxinfo_unk.ops;
-	if (jp2_getuint32(in, &len) || jp2_getuint32(in, &box->type)) {
-		goto error;
-	}
-	boxinfo = jp2_boxinfolookup(box->type);
-	box->info = boxinfo;
-	box->ops = &boxinfo->ops;
-	box->len = len;
-	if (box->len == 1) {
-		if (jp2_getuint64(in, &extlen)) {
-			goto error;
-		}
-		box->len = extlen;
-	}
-	if (box->len != 0 && box->len < 8) {
-		goto error;
-	}
-
-	dataflag = !(box->info->flags & (JP2_BOX_SUPER | JP2_BOX_NODATA));
-
-	if (dataflag) {
-		if (!(tmpstream = jas_stream_memopen(0, 0))) {
-			goto error;
-		}
-		if (jas_stream_copy(tmpstream, in, box->len - JP2_BOX_HDRLEN)) {
-			goto error;
-		}
-		jas_stream_rewind(tmpstream);
-
-		if (box->ops->getdata) {
-			if ((*box->ops->getdata)(box, tmpstream)) {
-				goto error;
-			}
-		}
-		jas_stream_close(tmpstream);
-	}
-
-	jp2_box_dump(box, stderr);
-
-	return box;
-	abort();
+    bool dataflag;
+
+    box = 0;
+    tmpstream = 0;
+
+    if (!(box = jas_malloc(sizeof(jp2_box_t)))) {
+        goto error;
+    }
+    box->ops = &jp2_boxinfo_unk.ops;
+    if (jp2_getuint32(in, &len) || jp2_getuint32(in, &box->type)) {
+        goto error;
+    }
+    boxinfo = jp2_boxinfolookup(box->type);
+    box->info = boxinfo;
+    box->ops = &boxinfo->ops;
+    box->len = len;
+    if (box->len == 1) {
+        if (jp2_getuint64(in, &extlen)) {
+            goto error;
+        }
+        box->len = extlen;
+    }
+    if (box->len != 0 && box->len < 8) {
+        goto error;
+    }
+
+    dataflag = !(box->info->flags & (JP2_BOX_SUPER | JP2_BOX_NODATA));
+
+    if (dataflag) {
+        if (!(tmpstream = jas_stream_memopen(0, 0))) {
+            goto error;
+        }
+        if (jas_stream_copy(tmpstream, in, box->len - JP2_BOX_HDRLEN)) {
+            goto error;
+        }
+        jas_stream_rewind(tmpstream);
+
+        if (box->ops->getdata) {
+            if ((*box->ops->getdata)(box, tmpstream)) {
+                goto error;
+            }
+        }
+        jas_stream_close(tmpstream);
+    }
+
+    if (jas_getdbglevel() > 0) {
+        jp2_box_dump(box, stderr);
+    }
+    return box;
+    abort();
 
 error:
-	if (box) {
-		jp2_box_destroy(box);
-	}
-	if (tmpstream) {
-		jas_stream_close(tmpstream);
-	}
-	return 0;
+    if (box) {
+        jp2_box_destroy(box);
+    }
+    if (tmpstream) {
+        jas_stream_close(tmpstream);
+    }
+    return 0;
 }
 
 void jp2_box_dump(jp2_box_t *box, FILE *out)
 {
-	jp2_boxinfo_t *boxinfo;
-	boxinfo = jp2_boxinfolookup(box->type);
-	assert(boxinfo);
+    jp2_boxinfo_t *boxinfo;
+    boxinfo = jp2_boxinfolookup(box->type);
+    assert(boxinfo);
 
-	fprintf(out, "JP2 box: ");
-	fprintf(out, "type=%c%s%c (0x%08x); length=%d\n", '"', boxinfo->name,
-	  '"', box->type, box->len);
-	if (box->ops->dumpdata) {
-		(*box->ops->dumpdata)(box, out);
-	}
+    fprintf(out, "JP2 box: ");
+    fprintf(out, "type=%c%s%c (0x%08x); length=%d\n", '"', boxinfo->name,
+            '"', (unsigned int) box->type, (int)box->len);
+    if (box->ops->dumpdata) {
+        (*box->ops->dumpdata)(box, out);
+    }
 }
 
 static int jp2_jp_getdata(jp2_box_t *box, jas_stream_t *in)
 {
-	jp2_jp_t *jp = &box->data.jp;
-	if (jp2_getuint32(in, &jp->magic)) {
-		return -1;
-	}
-	return 0;
+    jp2_jp_t *jp = &box->data.jp;
+    if (jp2_getuint32(in, &jp->magic)) {
+        return -1;
+    }
+    return 0;
 }
 
 static int jp2_ftyp_getdata(jp2_box_t *box, jas_stream_t *in)
 {
-	jp2_ftyp_t *ftyp = &box->data.ftyp;
-	int i;
-	if (jp2_getuint32(in, &ftyp->majver) || jp2_getuint32(in, &ftyp->minver)) {
-		return -1;
-	}
-	ftyp->numcompatcodes = ((box->len - JP2_BOX_HDRLEN) - 8) / 4;
-	if (ftyp->numcompatcodes > JP2_FTYP_MAXCOMPATCODES) {
-		return -1;
-	}
-	for (i = 0; i < ftyp->numcompatcodes; ++i) {
-		if (jp2_getuint32(in, &ftyp->compatcodes[i])) {
-			return -1;
-		}
-	}
-	return 0;
+    jp2_ftyp_t *ftyp = &box->data.ftyp;
+    int i;
+    if (jp2_getuint32(in, &ftyp->majver) || jp2_getuint32(in, &ftyp->minver)) {
+        return -1;
+    }
+    ftyp->numcompatcodes = ((box->len - JP2_BOX_HDRLEN) - 8) / 4;
+    if (ftyp->numcompatcodes > JP2_FTYP_MAXCOMPATCODES) {
+        return -1;
+    }
+    for (i = 0; i < ftyp->numcompatcodes; ++i) {
+        if (jp2_getuint32(in, &ftyp->compatcodes[i])) {
+            return -1;
+        }
+    }
+    return 0;
 }
 
 static int jp2_ihdr_getdata(jp2_box_t *box, jas_stream_t *in)
 {
-	jp2_ihdr_t *ihdr = &box->data.ihdr;
-	if (jp2_getuint32(in, &ihdr->height) || jp2_getuint32(in, &ihdr->width) ||
-	  jp2_getuint16(in, &ihdr->numcmpts) || jp2_getuint8(in, &ihdr->bpc) ||
-	  jp2_getuint8(in, &ihdr->comptype) || jp2_getuint8(in, &ihdr->csunk) ||
-	  jp2_getuint8(in, &ihdr->ipr)) {
-		return -1;
-	}
-	return 0;
+    jp2_ihdr_t *ihdr = &box->data.ihdr;
+    if (jp2_getuint32(in, &ihdr->height) || jp2_getuint32(in, &ihdr->width) ||
+      jp2_getuint16(in, &ihdr->numcmpts) || jp2_getuint8(in, &ihdr->bpc) ||
+      jp2_getuint8(in, &ihdr->comptype) || jp2_getuint8(in, &ihdr->csunk) ||
+      jp2_getuint8(in, &ihdr->ipr)) {
+        return -1;
+    }
+    return 0;
 }
 
 static int jp2_bpcc_getdata(jp2_box_t *box, jas_stream_t *in)
 {
-	jp2_bpcc_t *bpcc = &box->data.bpcc;
-	int i;
-	bpcc->numcmpts = box->len - JP2_BOX_HDRLEN;
-	if (!(bpcc->bpcs = jas_malloc(bpcc->numcmpts * sizeof(uint_fast8_t)))) {
-		return -1;
-	}
-	for (i = 0; i < bpcc->numcmpts; ++i) {
-		if (jp2_getuint8(in, &bpcc->bpcs[i])) {
-			return -1;
-		}
-	}
-	return 0;
+    jp2_bpcc_t *bpcc = &box->data.bpcc;
+    int i;
+    bpcc->numcmpts = box->len - JP2_BOX_HDRLEN;
+    if (!(bpcc->bpcs = jas_malloc(bpcc->numcmpts * sizeof(uint_fast8_t)))) {
+        return -1;
+    }
+    for (i = 0; i < bpcc->numcmpts; ++i) {
+        if (jp2_getuint8(in, &bpcc->bpcs[i])) {
+            return -1;
+        }
+    }
+    return 0;
 }
 
 static void jp2_colr_dumpdata(jp2_box_t *box, FILE *out)
 {
-	jp2_colr_t *colr = &box->data.colr;
-	fprintf(out, "method=%d; pri=%d; approx=%d\n", (int)colr->method, (int)colr->pri, (int)colr->approx);
-	switch (colr->method) {
-	case JP2_COLR_ENUM:
-		fprintf(out, "csid=%d\n", (int)colr->csid);
-		break;
-	case JP2_COLR_ICC:
-		jas_memdump(out, colr->iccp, colr->iccplen);
-		break;
-	}
+    jp2_colr_t *colr = &box->data.colr;
+    fprintf(out, "method=%d; pri=%d; approx=%d\n", (int)colr->method, (int)colr->pri, (int)colr->approx);
+    switch (colr->method) {
+    case JP2_COLR_ENUM:
+        fprintf(out, "csid=%d\n", (int)colr->csid);
+        break;
+    case JP2_COLR_ICC:
+        jas_memdump(out, colr->iccp, colr->iccplen);
+        break;
+    }
 }
 
 static int jp2_colr_getdata(jp2_box_t *box, jas_stream_t *in)
 {
-	jp2_colr_t *colr = &box->data.colr;
-	colr->csid = 0;
-	colr->iccp = 0;
-	colr->iccplen = 0;
-
-	if (jp2_getuint8(in, &colr->method) || jp2_getuint8(in, &colr->pri) ||
-	  jp2_getuint8(in, &colr->approx)) {
-		return -1;
-	}
-	switch (colr->method) {
-	case JP2_COLR_ENUM:
-		if (jp2_getuint32(in, &colr->csid)) {
-			return -1;
-		}
-		break;
-	case JP2_COLR_ICC:
-		colr->iccplen = box->len - JP2_BOX_HDRLEN - 3;
-		if (!(colr->iccp = jas_malloc(colr->iccplen * sizeof(uint_fast8_t)))) {
-			return -1;
-		}
-		if (jas_stream_read(in, colr->iccp, colr->iccplen) != colr->iccplen) {
-			return -1;
-		}
-		break;
-	}
-	return 0;
+    jp2_colr_t *colr = &box->data.colr;
+    colr->csid = 0;
+    colr->iccp = 0;
+    colr->iccplen = 0;
+
+    if (jp2_getuint8(in, &colr->method) || jp2_getuint8(in, &colr->pri) ||
+      jp2_getuint8(in, &colr->approx)) {
+        return -1;
+    }
+    switch (colr->method) {
+    case JP2_COLR_ENUM:
+        if (jp2_getuint32(in, &colr->csid)) {
+            return -1;
+        }
+        break;
+    case JP2_COLR_ICC:
+        colr->iccplen = box->len - JP2_BOX_HDRLEN - 3;
+        if (!(colr->iccp = jas_malloc(colr->iccplen * sizeof(uint_fast8_t)))) {
+            return -1;
+        }
+        if (jas_stream_read(in, colr->iccp, colr->iccplen) != colr->iccplen) {
+            return -1;
+        }
+        break;
+    }
+    return 0;
 }
 
 static void jp2_cdef_dumpdata(jp2_box_t *box, FILE *out)
 {
-	jp2_cdef_t *cdef = &box->data.cdef;
-	int i;
-	for (i = 0; i < cdef->numchans; ++i) {
-		fprintf(out, "channo=%d; type=%d; assoc=%d\n",
-		  cdef->ents[i].channo, cdef->ents[i].type, cdef->ents[i].assoc);
-	}
+    jp2_cdef_t *cdef = &box->data.cdef;
+    int i;
+    for (i = 0; i < cdef->numchans; ++i) {
+        fprintf(out, "channo=%d; type=%d; assoc=%d\n",
+                (int)cdef->ents[i].channo, (int)cdef->ents[i].type,
+                (int)cdef->ents[i].assoc);
+    }
 }
 
 static void jp2_colr_destroy(jp2_box_t *box)
 {
-	jp2_colr_t *colr = &box->data.colr;
-	if (colr->iccp) {
-		free(colr->iccp);
-	}
+    jp2_colr_t *colr = &box->data.colr;
+    if (colr->iccp) {
+        free(colr->iccp);
+    }
 }
 
 static int jp2_cdef_getdata(jp2_box_t *box, jas_stream_t *in)
 {
-	jp2_cdef_t *cdef = &box->data.cdef;
-	jp2_cdefchan_t *chan;
-	int channo;
-	if (jp2_getuint16(in, &cdef->numchans)) {
-		return -1;
-	}
-	if (!(cdef->ents = jas_malloc(cdef->numchans * sizeof(jp2_cdefchan_t)))) {
-		return -1;
-	}
-	for (channo = 0; channo < cdef->numchans; ++channo) {
-		chan = &cdef->ents[channo];
-		if (jp2_getuint16(in, &chan->channo) || jp2_getuint16(in, &chan->type) ||
-		  jp2_getuint16(in, &chan->assoc)) {
-			return -1;
-		}
-	}
-	return 0;
+    jp2_cdef_t *cdef = &box->data.cdef;
+    jp2_cdefchan_t *chan;
+    int channo;
+    if (jp2_getuint16(in, &cdef->numchans)) {
+        return -1;
+    }
+    if (!(cdef->ents = jas_malloc(cdef->numchans * sizeof(jp2_cdefchan_t)))) {
+        return -1;
+    }
+    for (channo = 0; channo < cdef->numchans; ++channo) {
+        chan = &cdef->ents[channo];
+        if (jp2_getuint16(in, &chan->channo) || jp2_getuint16(in, &chan->type) ||
+          jp2_getuint16(in, &chan->assoc)) {
+            return -1;
+        }
+    }
+    return 0;
 }
 
 /******************************************************************************\
@@ -511,23 +513,23 @@ static int jp2_cdef_getdata(jp2_box_t *box, jas_stream_t *in)
 
 int jp2_box_put(jp2_box_t *box, jas_stream_t *out)
 {
-	jas_stream_t *tmpstream;
-	bool dataflag;
+    jas_stream_t *tmpstream;
+    bool dataflag;
 
-	tmpstream = 0;
+    tmpstream = 0;
 
-	dataflag = !(box->info->flags & (JP2_BOX_SUPER | JP2_BOX_NODATA));
+    dataflag = !(box->info->flags & (JP2_BOX_SUPER | JP2_BOX_NODATA));
 
-	if (dataflag) {
-		tmpstream = jas_stream_memopen(0, 0);
-		if (box->ops->putdata) {
-			if ((*box->ops->putdata)(box, tmpstream)) {
-				goto error;
-			}
-		}
-		box->len = jas_stream_tell(tmpstream) + JP2_BOX_HDRLEN;
-		jas_stream_rewind(tmpstream);
-	}
+    if (dataflag) {
+        tmpstream = jas_stream_memopen(0, 0);
+        if (box->ops->putdata) {
+            if ((*box->ops->putdata)(box, tmpstream)) {
+                goto error;
+            }
+        }
+        box->len = jas_stream_tell(tmpstream) + JP2_BOX_HDRLEN;
+        jas_stream_rewind(tmpstream);
+    }
     /* There was code here in official Jasper to handle 64 bit lengths,
        but it was based on determining whether box->len fits in 32 bits.
        But box->len is a 32 bit data type, so it fits in 32 bits by
@@ -535,119 +537,119 @@ int jp2_box_put(jp2_box_t *box, jas_stream_t *out)
        lengths that don't fit in 32 bits, or it passes invalid values of
        box->len to us.  We assume the former because it's easier.
     */
-	if (jp2_putuint32(out, box->len)) {
-		goto error;
-	}
-	if (jp2_putuint32(out, box->type)) {
-		goto error;
-	}
-
-	if (dataflag) {
-		if (jas_stream_copy(out, tmpstream, box->len - JP2_BOX_HDRLEN)) {
-			goto error;
-		}
-		jas_stream_close(tmpstream);
-	}
-
-	return 0;
-	abort();
+    if (jp2_putuint32(out, box->len)) {
+        goto error;
+    }
+    if (jp2_putuint32(out, box->type)) {
+        goto error;
+    }
+
+    if (dataflag) {
+        if (jas_stream_copy(out, tmpstream, box->len - JP2_BOX_HDRLEN)) {
+            goto error;
+        }
+        jas_stream_close(tmpstream);
+    }
+
+    return 0;
+    abort();
 
 error:
 
-	if (tmpstream) {
-		jas_stream_close(tmpstream);
-	}
-	return -1;
+    if (tmpstream) {
+        jas_stream_close(tmpstream);
+    }
+    return -1;
 }
 
 static int jp2_jp_putdata(jp2_box_t *box, jas_stream_t *out)
 {
-	jp2_jp_t *jp = &box->data.jp;
-	if (jp2_putuint32(out, jp->magic)) {
-		return -1;
-	}
-	return 0;
+    jp2_jp_t *jp = &box->data.jp;
+    if (jp2_putuint32(out, jp->magic)) {
+        return -1;
+    }
+    return 0;
 }
 
 static int jp2_ftyp_putdata(jp2_box_t *box, jas_stream_t *out)
 {
-	jp2_ftyp_t *ftyp = &box->data.ftyp;
-	int i;
-	if (jp2_putuint32(out, ftyp->majver) || jp2_putuint32(out, ftyp->minver)) {
-		return -1;
-	}
-	for (i = 0; i < ftyp->numcompatcodes; ++i) {
-		if (jp2_putuint32(out, ftyp->compatcodes[i])) {
-			return -1;
-		}
-	}
-	return 0;
+    jp2_ftyp_t *ftyp = &box->data.ftyp;
+    int i;
+    if (jp2_putuint32(out, ftyp->majver) || jp2_putuint32(out, ftyp->minver)) {
+        return -1;
+    }
+    for (i = 0; i < ftyp->numcompatcodes; ++i) {
+        if (jp2_putuint32(out, ftyp->compatcodes[i])) {
+            return -1;
+        }
+    }
+    return 0;
 }
 
 static int jp2_ihdr_putdata(jp2_box_t *box, jas_stream_t *out)
 {
-	jp2_ihdr_t *ihdr = &box->data.ihdr;
-	if (jp2_putuint32(out, ihdr->height) || jp2_putuint32(out, ihdr->width) ||
-	  jp2_putuint16(out, ihdr->numcmpts) || jp2_putuint8(out, ihdr->bpc) ||
-	  jp2_putuint8(out, ihdr->comptype) || jp2_putuint8(out, ihdr->csunk) ||
-	  jp2_putuint8(out, ihdr->ipr)) {
-		return -1;
-	}
-	return 0;
+    jp2_ihdr_t *ihdr = &box->data.ihdr;
+    if (jp2_putuint32(out, ihdr->height) || jp2_putuint32(out, ihdr->width) ||
+      jp2_putuint16(out, ihdr->numcmpts) || jp2_putuint8(out, ihdr->bpc) ||
+      jp2_putuint8(out, ihdr->comptype) || jp2_putuint8(out, ihdr->csunk) ||
+      jp2_putuint8(out, ihdr->ipr)) {
+        return -1;
+    }
+    return 0;
 }
 
 static int jp2_bpcc_putdata(jp2_box_t *box, jas_stream_t *out)
 {
-	jp2_bpcc_t *bpcc = &box->data.bpcc;
-	int i;
-	for (i = 0; i < bpcc->numcmpts; ++i) {
-		if (jp2_putuint8(out, bpcc->bpcs[i])) {
-			return -1;
-		}
-	}
-	return 0;
+    jp2_bpcc_t *bpcc = &box->data.bpcc;
+    int i;
+    for (i = 0; i < bpcc->numcmpts; ++i) {
+        if (jp2_putuint8(out, bpcc->bpcs[i])) {
+            return -1;
+        }
+    }
+    return 0;
 }
 
 static int jp2_colr_putdata(jp2_box_t *box, jas_stream_t *out)
 {
-	jp2_colr_t *colr = &box->data.colr;
-	if (jp2_putuint8(out, colr->method) || jp2_putuint8(out, colr->pri) ||
-	  jp2_putuint8(out, colr->approx)) {
-		return -1;
-	}
-	switch (colr->method) {
-	case JP2_COLR_ENUM:
-		if (jp2_putuint32(out, colr->csid)) {
-			return -1;
-		}
-		break;
-	case JP2_COLR_ICC:
-		/* XXX - not implemented */
-		abort();
-		break;
-	}
-	return 0;
+    jp2_colr_t *colr = &box->data.colr;
+    if (jp2_putuint8(out, colr->method) || jp2_putuint8(out, colr->pri) ||
+      jp2_putuint8(out, colr->approx)) {
+        return -1;
+    }
+    switch (colr->method) {
+    case JP2_COLR_ENUM:
+        if (jp2_putuint32(out, colr->csid)) {
+            return -1;
+        }
+        break;
+    case JP2_COLR_ICC:
+        /* XXX - not implemented */
+        abort();
+        break;
+    }
+    return 0;
 }
 
 static int jp2_cdef_putdata(jp2_box_t *box, jas_stream_t *out)
 {
-	jp2_cdef_t *cdef = &box->data.cdef;
-	int i;
-	jp2_cdefchan_t *ent;
+    jp2_cdef_t *cdef = &box->data.cdef;
+    int i;
+    jp2_cdefchan_t *ent;
 
-	if (jp2_putuint16(out, cdef->numchans)) {
-		return -1;
-	}
+    if (jp2_putuint16(out, cdef->numchans)) {
+        return -1;
+    }
 
-	for (i = 0; i < cdef->numchans; ++i) {
-		ent = &cdef->ents[i];
-		if (jp2_putuint16(out, ent->channo) ||
-		  jp2_putuint16(out, ent->type) ||
-		  jp2_putuint16(out, ent->assoc)) {
-			return -1;
-		}
-	}
-	return 0;
+    for (i = 0; i < cdef->numchans; ++i) {
+        ent = &cdef->ents[i];
+        if (jp2_putuint16(out, ent->channo) ||
+          jp2_putuint16(out, ent->type) ||
+          jp2_putuint16(out, ent->assoc)) {
+            return -1;
+        }
+    }
+    return 0;
 }
 
 /******************************************************************************\
@@ -656,63 +658,63 @@ static int jp2_cdef_putdata(jp2_box_t *box, jas_stream_t *out)
 
 static int jp2_getuint8(jas_stream_t *in, uint_fast8_t *val)
 {
-	int c;
-	if ((c = jas_stream_getc(in)) == EOF) {
-		return -1;
-	}
-	if (val) {
-		*val = c;
-	}
-	return 0;
+    int c;
+    if ((c = jas_stream_getc(in)) == EOF) {
+        return -1;
+    }
+    if (val) {
+        *val = c;
+    }
+    return 0;
 }
 
 static int jp2_getuint16(jas_stream_t *in, uint_fast16_t *val)
 {
-	uint_fast16_t v;
-	int c;
-	if ((c = jas_stream_getc(in)) == EOF) {
-		return -1;
-	}
-	v = c;
-	if ((c = jas_stream_getc(in)) == EOF) {
-		return -1;
-	}
-	v = (v << 8) | c;
-	if (val) {
-		*val = v;
-	}
-	return 0;
+    uint_fast16_t v;
+    int c;
+    if ((c = jas_stream_getc(in)) == EOF) {
+        return -1;
+    }
+    v = c;
+    if ((c = jas_stream_getc(in)) == EOF) {
+        return -1;
+    }
+    v = (v << 8) | c;
+    if (val) {
+        *val = v;
+    }
+    return 0;
 }
 
 static int jp2_getuint32(jas_stream_t *in, uint_fast32_t *val)
 {
-	uint_fast32_t v;
-	int c;
-	if ((c = jas_stream_getc(in)) == EOF) {
-		return -1;
-	}
-	v = c;
-	if ((c = jas_stream_getc(in)) == EOF) {
-		return -1;
-	}
-	v = (v << 8) | c;
-	if ((c = jas_stream_getc(in)) == EOF) {
-		return -1;
-	}
-	v = (v << 8) | c;
-	if ((c = jas_stream_getc(in)) == EOF) {
-		return -1;
-	}
-	v = (v << 8) | c;
-	if (val) {
-		*val = v;
-	}
-	return 0;
+    uint_fast32_t v;
+    int c;
+    if ((c = jas_stream_getc(in)) == EOF) {
+        return -1;
+    }
+    v = c;
+    if ((c = jas_stream_getc(in)) == EOF) {
+        return -1;
+    }
+    v = (v << 8) | c;
+    if ((c = jas_stream_getc(in)) == EOF) {
+        return -1;
+    }
+    v = (v << 8) | c;
+    if ((c = jas_stream_getc(in)) == EOF) {
+        return -1;
+    }
+    v = (v << 8) | c;
+    if (val) {
+        *val = v;
+    }
+    return 0;
 }
 
 static int jp2_getuint64(jas_stream_t *in, uint_fast64_t *val)
 {
-	abort();
+    abort();
 }
 
 /******************************************************************************\
@@ -721,30 +723,30 @@ static int jp2_getuint64(jas_stream_t *in, uint_fast64_t *val)
 
 static int jp2_putuint8(jas_stream_t *out, uint_fast8_t val)
 {
-	if (jas_stream_putc(out, val & 0xff) == EOF) {
-		return -1;
-	}
-	return 0;
+    if (jas_stream_putc(out, val & 0xff) == EOF) {
+        return -1;
+    }
+    return 0;
 }
 
 static int jp2_putuint16(jas_stream_t *out, uint_fast16_t val)
 {
-	if (jas_stream_putc(out, (val >> 8) & 0xff) == EOF ||
-	  jas_stream_putc(out, val & 0xff) == EOF) {
-		return -1;
-	}
-	return 0;
+    if (jas_stream_putc(out, (val >> 8) & 0xff) == EOF ||
+      jas_stream_putc(out, val & 0xff) == EOF) {
+        return -1;
+    }
+    return 0;
 }
 
 static int jp2_putuint32(jas_stream_t *out, uint_fast32_t val)
 {
-	if (jas_stream_putc(out, (val >> 24) & 0xff) == EOF ||
-	  jas_stream_putc(out, (val >> 16) & 0xff) == EOF ||
-	  jas_stream_putc(out, (val >> 8) & 0xff) == EOF ||
-	  jas_stream_putc(out, val & 0xff) == EOF) {
-		return -1;
-	}
-	return 0;
+    if (jas_stream_putc(out, (val >> 24) & 0xff) == EOF ||
+      jas_stream_putc(out, (val >> 16) & 0xff) == EOF ||
+      jas_stream_putc(out, (val >> 8) & 0xff) == EOF ||
+      jas_stream_putc(out, val & 0xff) == EOF) {
+        return -1;
+    }
+    return 0;
 }
 
 /******************************************************************************\
@@ -753,13 +755,13 @@ static int jp2_putuint32(jas_stream_t *out, uint_fast32_t val)
 
 jp2_boxinfo_t *jp2_boxinfolookup(int type)
 {
-	jp2_boxinfo_t *boxinfo;
-	for (boxinfo = jp2_boxinfos; boxinfo->name; ++boxinfo) {
-		if (boxinfo->type == type) {
-			return boxinfo;
-		}
-	}
-	return &jp2_boxinfo_unk;
+    jp2_boxinfo_t *boxinfo;
+    for (boxinfo = jp2_boxinfos; boxinfo->name; ++boxinfo) {
+        if (boxinfo->type == type) {
+            return boxinfo;
+        }
+    }
+    return &jp2_boxinfo_unk;
 }
 
 
@@ -768,161 +770,162 @@ jp2_boxinfo_t *jp2_boxinfolookup(int type)
 
 static void jp2_cmap_destroy(jp2_box_t *box)
 {
-	jp2_cmap_t *cmap = &box->data.cmap;
-	if (cmap->ents) {
-		jas_free(cmap->ents);
-	}
+    jp2_cmap_t *cmap = &box->data.cmap;
+    if (cmap->ents) {
+        jas_free(cmap->ents);
+    }
 }
 
 static int jp2_cmap_getdata(jp2_box_t *box, jas_stream_t *in)
 {
-	jp2_cmap_t *cmap = &box->data.cmap;
-	jp2_cmapent_t *ent;
-	int i;
-
-	cmap->numchans = (box->len - JP2_BOX_HDRLEN) / 4;
-	if (!(cmap->ents = jas_malloc(cmap->numchans * sizeof(jp2_cmapent_t)))) {
-		return -1;
-	}
-	for (i = 0; i < cmap->numchans; ++i) {
-		ent = &cmap->ents[i];
-		if (jp2_getuint16(in, &ent->cmptno) ||
-		  jp2_getuint8(in, &ent->map) ||
-		  jp2_getuint8(in, &ent->pcol)) {
-			return -1;
-		}
-	}
-	
-	return 0;
+    jp2_cmap_t *cmap = &box->data.cmap;
+    jp2_cmapent_t *ent;
+    int i;
+
+    cmap->numchans = (box->len - JP2_BOX_HDRLEN) / 4;
+    if (!(cmap->ents = jas_malloc(cmap->numchans * sizeof(jp2_cmapent_t)))) {
+        return -1;
+    }
+    for (i = 0; i < cmap->numchans; ++i) {
+        ent = &cmap->ents[i];
+        if (jp2_getuint16(in, &ent->cmptno) ||
+          jp2_getuint8(in, &ent->map) ||
+          jp2_getuint8(in, &ent->pcol)) {
+            return -1;
+        }
+    }
+    
+    return 0;
 }
 
 static int jp2_cmap_putdata(jp2_box_t *box, jas_stream_t *out)
 {
-	return -1;
+    return -1;
 }
 
 static void jp2_cmap_dumpdata(jp2_box_t *box, FILE *out)
 {
-	jp2_cmap_t *cmap = &box->data.cmap;
-	int i;
-	jp2_cmapent_t *ent;
-	fprintf(stderr, "numchans = %d\n", (int) cmap->numchans);
-	for (i = 0; i < cmap->numchans; ++i) {
-		ent = &cmap->ents[i];
-		fprintf(stderr, "cmptno=%d; map=%d; pcol=%d\n",
-		  (int) ent->cmptno, (int) ent->map, (int) ent->pcol);
-	}
+    jp2_cmap_t *cmap = &box->data.cmap;
+    int i;
+    jp2_cmapent_t *ent;
+    fprintf(stderr, "numchans = %d\n", (int) cmap->numchans);
+    for (i = 0; i < cmap->numchans; ++i) {
+        ent = &cmap->ents[i];
+        fprintf(stderr, "cmptno=%d; map=%d; pcol=%d\n",
+          (int) ent->cmptno, (int) ent->map, (int) ent->pcol);
+    }
 }
 
 static void jp2_pclr_destroy(jp2_box_t *box)
 {
-	jp2_pclr_t *pclr = &box->data.pclr;
-	if (pclr->lutdata) {
-		jas_free(pclr->lutdata);
-	}
+    jp2_pclr_t *pclr = &box->data.pclr;
+    if (pclr->lutdata) {
+        jas_free(pclr->lutdata);
+    }
 }
 
 static int jp2_pclr_getdata(jp2_box_t *box, jas_stream_t *in)
 {
-	jp2_pclr_t *pclr = &box->data.pclr;
-	int lutsize;
-	int i;
-	int j;
-	int_fast32_t x;
-
-	pclr->lutdata = 0;
-
-	if (jp2_getuint16(in, &pclr->numlutents) ||
-	  jp2_getuint8(in, &pclr->numchans)) {
-		return -1;
-	}
-	lutsize = pclr->numlutents * pclr->numchans;
-	if (!(pclr->lutdata = jas_malloc(lutsize * sizeof(int_fast32_t)))) {
-		return -1;
-	}
-	if (!(pclr->bpc = jas_malloc(pclr->numchans * sizeof(uint_fast8_t)))) {
-		return -1;
-	}
-	for (i = 0; i < pclr->numchans; ++i) {
-		if (jp2_getuint8(in, &pclr->bpc[i])) {
-			return -1;
-		}
-	}
-	for (i = 0; i < pclr->numlutents; ++i) {
-		for (j = 0; j < pclr->numchans; ++j) {
-			if (jp2_getint(in, (pclr->bpc[j] & 0x80) != 0,
-			  (pclr->bpc[j] & 0x7f) + 1, &x)) {
-				return -1;
-			}
-			pclr->lutdata[i * pclr->numchans + j] = x;
-		}
-	}
-	return 0;
+    jp2_pclr_t *pclr = &box->data.pclr;
+    int lutsize;
+    int i;
+    int j;
+    int_fast32_t x;
+
+    pclr->lutdata = 0;
+
+    if (jp2_getuint16(in, &pclr->numlutents) ||
+      jp2_getuint8(in, &pclr->numchans)) {
+        return -1;
+    }
+    lutsize = pclr->numlutents * pclr->numchans;
+    if (!(pclr->lutdata = jas_malloc(lutsize * sizeof(int_fast32_t)))) {
+        return -1;
+    }
+    if (!(pclr->bpc = jas_malloc(pclr->numchans * sizeof(uint_fast8_t)))) {
+        return -1;
+    }
+    for (i = 0; i < pclr->numchans; ++i) {
+        if (jp2_getuint8(in, &pclr->bpc[i])) {
+            return -1;
+        }
+    }
+    for (i = 0; i < pclr->numlutents; ++i) {
+        for (j = 0; j < pclr->numchans; ++j) {
+            if (jp2_getint(in, (pclr->bpc[j] & 0x80) != 0,
+              (pclr->bpc[j] & 0x7f) + 1, &x)) {
+                return -1;
+            }
+            pclr->lutdata[i * pclr->numchans + j] = x;
+        }
+    }
+    return 0;
 }
 
 static int jp2_pclr_putdata(jp2_box_t *box, jas_stream_t *out)
 {
     /* This code from official Jasper must be part of unfinished work.
        It generates an unused variable warning.
-	jp2_pclr_t *pclr = &box->data.pclr;
+    jp2_pclr_t *pclr = &box->data.pclr;
     */
-	return -1;
+    return -1;
 }
 
 static void jp2_pclr_dumpdata(jp2_box_t *box, FILE *out)
 {
-	jp2_pclr_t *pclr = &box->data.pclr;
-	int i;
-	int j;
-	fprintf(out, "numents=%d; numchans=%d\n", (int) pclr->numlutents,
-	  (int) pclr->numchans);
-	for (i = 0; i < pclr->numlutents; ++i) {
-		for (j = 0; j < pclr->numchans; ++j) {
-			fprintf(out, "LUT[%d][%d]=%d\n", i, j, pclr->lutdata[i * pclr->numchans + j]);
-		}
-	}
+    jp2_pclr_t *pclr = &box->data.pclr;
+    int i;
+    int j;
+    fprintf(out, "numents=%d; numchans=%d\n", (int) pclr->numlutents,
+      (int) pclr->numchans);
+    for (i = 0; i < pclr->numlutents; ++i) {
+        for (j = 0; j < pclr->numchans; ++j) {
+            fprintf(out, "LUT[%d][%d]=%d\n", i, j,
+                    (int)pclr->lutdata[i * pclr->numchans + j]);
+        }
+    }
 }
 
 static int jp2_getint(jas_stream_t *in, int s, int n, int_fast32_t *val)
 {
-	int c;
-	int i;
-	uint_fast32_t v;
-	int m;
-
-	m = (n + 7) / 8;
-
-	v = 0;
-	for (i = 0; i < m; ++i) {
-		if ((c = jas_stream_getc(in)) == EOF) {
-			return -1;
-		}
-		v = (v << 8) | c;
-	}
-	v &= ONES(n);
-	if (s) {
-		int sb;
-		sb = v & (1 << (8 * m - 1));
-		*val = ((~v) + 1) & ONES(8 * m);
-		if (sb) {
-			*val = -*val;
-		}
-	} else {
-		*val = v;
-	}
-
-	return 0;
+    int c;
+    int i;
+    uint_fast32_t v;
+    int m;
+
+    m = (n + 7) / 8;
+
+    v = 0;
+    for (i = 0; i < m; ++i) {
+        if ((c = jas_stream_getc(in)) == EOF) {
+            return -1;
+        }
+        v = (v << 8) | c;
+    }
+    v &= ONES(n);
+    if (s) {
+        int sb;
+        sb = v & (1 << (8 * m - 1));
+        *val = ((~v) + 1) & ONES(8 * m);
+        if (sb) {
+            *val = -*val;
+        }
+    } else {
+        *val = v;
+    }
+
+    return 0;
 }
 
 jp2_cdefchan_t *jp2_cdef_lookup(jp2_cdef_t *cdef, int channo)
 {
-	int i;
-	jp2_cdefchan_t *cdefent;
-	for (i = 0; i < cdef->numchans; ++i) {
-		cdefent = &cdef->ents[i];
-		if (cdefent->channo == channo) {
-			return cdefent;
-		}
-	}
-	return 0;
+    int i;
+    jp2_cdefchan_t *cdefent;
+    for (i = 0; i < cdef->numchans; ++i) {
+        cdefent = &cdef->ents[i];
+        if (cdefent->channo == channo) {
+            return cdefent;
+        }
+    }
+    return 0;
 }
diff --git a/converter/other/jpeg2000/libjasper/jp2/jp2_dec.c b/converter/other/jpeg2000/libjasper/jp2/jp2_dec.c
index 3cce9278..91ce6c51 100644
--- a/converter/other/jpeg2000/libjasper/jp2/jp2_dec.c
+++ b/converter/other/jpeg2000/libjasper/jp2/jp2_dec.c
@@ -297,9 +297,9 @@ jas_image_t *jp2_decode(jas_stream_t *in, char *optstr)
 		jas_eprintf("warning: component data type mismatch\n");
 	}
 
-	/* Is the compression type supported? */
+	/* Can we handle the compression type? */
 	if (dec->ihdr->data.ihdr.comptype != JP2_IHDR_COMPTYPE) {
-		jas_eprintf("error: unsupported compression type\n");
+		jas_eprintf("error: not capable of this compression type\n");
 		goto error;
 	}
 
@@ -340,7 +340,8 @@ jas_image_t *jp2_decode(jas_stream_t *in, char *optstr)
 		iccp = dec->colr->data.colr.iccp;
 		cs = (iccp[16] << 24) | (iccp[17] << 16) | (iccp[18] << 8) |
 		  iccp[19];
-		jas_eprintf("ICC Profile CS %08x\n", cs);
+        if (jas_getdbglevel() > 1)
+            jas_eprintf("ICC Profile CS %08x\n", cs);
 		jas_image_setcolorspace(dec->image, fromiccpcs(cs));
 		break;
 	}
@@ -454,7 +455,6 @@ jas_image_t *jp2_decode(jas_stream_t *in, char *optstr)
 		jas_eprintf("error: no components\n");
 		goto error;
 	}
-fprintf(stderr, "no of components is %d\n", jas_image_numcmpts(dec->image));
 
 	/* Prevent the image from being destroyed later. */
 	image = dec->image;
diff --git a/converter/other/jpeg2000/libjasper/jpc/jpc_bs.c b/converter/other/jpeg2000/libjasper/jpc/jpc_bs.c
index 54f0a819..c66fcd99 100644
--- a/converter/other/jpeg2000/libjasper/jpc/jpc_bs.c
+++ b/converter/other/jpeg2000/libjasper/jpc/jpc_bs.c
@@ -157,10 +157,6 @@ jpc_bitstream_t *jpc_bitstream_sopen(jas_stream_t *stream, const char *mode)
 {
 	jpc_bitstream_t *bitstream;
 
-	/* Ensure that the open mode is valid. */
-	assert(!strcmp(mode, "r") || !strcmp(mode, "w") || !strcmp(mode, "r+")
-	  || !strcmp(mode, "w+"));
-
 	if (!(bitstream = jpc_bitstream_alloc())) {
 		return 0;
 	}
diff --git a/converter/other/jpeg2000/libjasper/jpc/jpc_bs.h b/converter/other/jpeg2000/libjasper/jpc/jpc_bs.h
index f515972b..edb0a2df 100644
--- a/converter/other/jpeg2000/libjasper/jpc/jpc_bs.h
+++ b/converter/other/jpeg2000/libjasper/jpc/jpc_bs.h
@@ -149,7 +149,7 @@
 #define	JPC_BITSTREAM_NOCLOSE	0x01
 /* End of file has been reached while reading. */
 #define	JPC_BITSTREAM_EOF	0x02
-/* An I/O error has occured. */
+/* An I/O error has occurred. */
 #define	JPC_BITSTREAM_ERR	0x04
 
 /******************************************************************************\
diff --git a/converter/other/jpeg2000/libjasper/jpc/jpc_cs.c b/converter/other/jpeg2000/libjasper/jpc/jpc_cs.c
index 63cf8ba7..559f36cf 100644
--- a/converter/other/jpeg2000/libjasper/jpc/jpc_cs.c
+++ b/converter/other/jpeg2000/libjasper/jpc/jpc_cs.c
@@ -135,9 +135,9 @@
 
 /* Marker segment table entry. */
 typedef struct {
-	int id;
-	const char *name;
-	jpc_msops_t ops;
+    int id;
+    const char *name;
+    jpc_msops_t ops;
 } jpc_mstabent_t;
 
 /******************************************************************************\
@@ -220,40 +220,40 @@ static int jpc_cox_putcompparms(jpc_ms_t *ms, jpc_cstate_t *cstate,
 \******************************************************************************/
 
 static jpc_mstabent_t jpc_mstab[] = {
-	{JPC_MS_SOC, "SOC", {0, 0, 0, 0}},
-	{JPC_MS_SOT, "SOT", {0, jpc_sot_getparms, jpc_sot_putparms,
-	  jpc_sot_dumpparms}},
-	{JPC_MS_SOD, "SOD", {0, 0, 0, 0}},
-	{JPC_MS_EOC, "EOC", {0, 0, 0, 0}},
-	{JPC_MS_SIZ, "SIZ", {jpc_siz_destroyparms, jpc_siz_getparms,
-	  jpc_siz_putparms, jpc_siz_dumpparms}},
-	{JPC_MS_COD, "COD", {jpc_cod_destroyparms, jpc_cod_getparms,
-	  jpc_cod_putparms, jpc_cod_dumpparms}},
-	{JPC_MS_COC, "COC", {jpc_coc_destroyparms, jpc_coc_getparms,
-	  jpc_coc_putparms, jpc_coc_dumpparms}},
-	{JPC_MS_RGN, "RGN", {0, jpc_rgn_getparms, jpc_rgn_putparms,
-	  jpc_rgn_dumpparms}},
-	{JPC_MS_QCD, "QCD", {jpc_qcd_destroyparms, jpc_qcd_getparms,
-	  jpc_qcd_putparms, jpc_qcd_dumpparms}},
-	{JPC_MS_QCC, "QCC", {jpc_qcc_destroyparms, jpc_qcc_getparms,
-	  jpc_qcc_putparms, jpc_qcc_dumpparms}},
-	{JPC_MS_POC, "POC", {jpc_poc_destroyparms, jpc_poc_getparms,
-	  jpc_poc_putparms, jpc_poc_dumpparms}},
-	{JPC_MS_TLM, "TLM", {0, jpc_unk_getparms, jpc_unk_putparms, 0}},
-	{JPC_MS_PLM, "PLM", {0, jpc_unk_getparms, jpc_unk_putparms, 0}},
-	{JPC_MS_PPM, "PPM", {jpc_ppm_destroyparms, jpc_ppm_getparms,
-	  jpc_ppm_putparms, jpc_ppm_dumpparms}},
-	{JPC_MS_PPT, "PPT", {jpc_ppt_destroyparms, jpc_ppt_getparms,
-	  jpc_ppt_putparms, jpc_ppt_dumpparms}},
-	{JPC_MS_SOP, "SOP", {0, jpc_sop_getparms, jpc_sop_putparms,
-	  jpc_sop_dumpparms}},
-	{JPC_MS_EPH, "EPH", {0, 0, 0, 0}},
-	{JPC_MS_CRG, "CRG", {0, jpc_crg_getparms, jpc_crg_putparms,
-	  jpc_crg_dumpparms}},
-	{JPC_MS_COM, "COM", {jpc_com_destroyparms, jpc_com_getparms,
-	  jpc_com_putparms, jpc_com_dumpparms}},
-	{-1, "UNKNOWN",  {jpc_unk_destroyparms, jpc_unk_getparms,
-	  jpc_unk_putparms, jpc_unk_dumpparms}}
+    {JPC_MS_SOC, "SOC", {0, 0, 0, 0}},
+    {JPC_MS_SOT, "SOT", {0, jpc_sot_getparms, jpc_sot_putparms,
+      jpc_sot_dumpparms}},
+    {JPC_MS_SOD, "SOD", {0, 0, 0, 0}},
+    {JPC_MS_EOC, "EOC", {0, 0, 0, 0}},
+    {JPC_MS_SIZ, "SIZ", {jpc_siz_destroyparms, jpc_siz_getparms,
+      jpc_siz_putparms, jpc_siz_dumpparms}},
+    {JPC_MS_COD, "COD", {jpc_cod_destroyparms, jpc_cod_getparms,
+      jpc_cod_putparms, jpc_cod_dumpparms}},
+    {JPC_MS_COC, "COC", {jpc_coc_destroyparms, jpc_coc_getparms,
+      jpc_coc_putparms, jpc_coc_dumpparms}},
+    {JPC_MS_RGN, "RGN", {0, jpc_rgn_getparms, jpc_rgn_putparms,
+      jpc_rgn_dumpparms}},
+    {JPC_MS_QCD, "QCD", {jpc_qcd_destroyparms, jpc_qcd_getparms,
+      jpc_qcd_putparms, jpc_qcd_dumpparms}},
+    {JPC_MS_QCC, "QCC", {jpc_qcc_destroyparms, jpc_qcc_getparms,
+      jpc_qcc_putparms, jpc_qcc_dumpparms}},
+    {JPC_MS_POC, "POC", {jpc_poc_destroyparms, jpc_poc_getparms,
+      jpc_poc_putparms, jpc_poc_dumpparms}},
+    {JPC_MS_TLM, "TLM", {0, jpc_unk_getparms, jpc_unk_putparms, 0}},
+    {JPC_MS_PLM, "PLM", {0, jpc_unk_getparms, jpc_unk_putparms, 0}},
+    {JPC_MS_PPM, "PPM", {jpc_ppm_destroyparms, jpc_ppm_getparms,
+      jpc_ppm_putparms, jpc_ppm_dumpparms}},
+    {JPC_MS_PPT, "PPT", {jpc_ppt_destroyparms, jpc_ppt_getparms,
+      jpc_ppt_putparms, jpc_ppt_dumpparms}},
+    {JPC_MS_SOP, "SOP", {0, jpc_sop_getparms, jpc_sop_putparms,
+      jpc_sop_dumpparms}},
+    {JPC_MS_EPH, "EPH", {0, 0, 0, 0}},
+    {JPC_MS_CRG, "CRG", {0, jpc_crg_getparms, jpc_crg_putparms,
+      jpc_crg_dumpparms}},
+    {JPC_MS_COM, "COM", {jpc_com_destroyparms, jpc_com_getparms,
+      jpc_com_putparms, jpc_com_dumpparms}},
+    {-1, "UNKNOWN",  {jpc_unk_destroyparms, jpc_unk_getparms,
+      jpc_unk_putparms, jpc_unk_dumpparms}}
 };
 
 /******************************************************************************\
@@ -263,160 +263,160 @@ static jpc_mstabent_t jpc_mstab[] = {
 /* Create a code stream state object. */
 jpc_cstate_t *jpc_cstate_create()
 {
-	jpc_cstate_t *cstate;
-	if (!(cstate = jas_malloc(sizeof(jpc_cstate_t)))) {
-		return 0;
-	}
-	cstate->numcomps = 0;
-	return cstate;
+    jpc_cstate_t *cstate;
+    if (!(cstate = jas_malloc(sizeof(jpc_cstate_t)))) {
+        return 0;
+    }
+    cstate->numcomps = 0;
+    return cstate;
 }
 
 /* Destroy a code stream state object. */
 void jpc_cstate_destroy(jpc_cstate_t *cstate)
 {
-	jas_free(cstate);
+    jas_free(cstate);
 }
 
 /* Read a marker segment from a stream. */
 jpc_ms_t *jpc_getms(jas_stream_t *in, jpc_cstate_t *cstate)
 {
-	jpc_ms_t *ms;
-	jpc_mstabent_t *mstabent;
-	jas_stream_t *tmpstream;
-
-	if (!(ms = jpc_ms_create(0))) {
-		return 0;
-	}
-
-	/* Get the marker type. */
-	if (jpc_getuint16(in, &ms->id) || ms->id < JPC_MS_MIN ||
-	  ms->id > JPC_MS_MAX) {
-		jpc_ms_destroy(ms);
-		return 0;
-	}
-
-	mstabent = jpc_mstab_lookup(ms->id);
-	ms->ops = &mstabent->ops;
-
-	/* Get the marker segment length and parameters if present. */
-	/* Note: It is tacitly assumed that a marker segment cannot have
-	  parameters unless it has a length field.  That is, there cannot
-	  be a parameters field without a length field and vice versa. */
-	if (JPC_MS_HASPARMS(ms->id)) {
-		/* Get the length of the marker segment. */
-		if (jpc_getuint16(in, &ms->len) || ms->len < 3) {
-			jpc_ms_destroy(ms);
-			return 0;
-		}
-		/* Calculate the length of the marker segment parameters. */
-		ms->len -= 2;
-		/* Create and prepare a temporary memory stream from which to
-		  read the marker segment parameters. */
-		/* Note: This approach provides a simple way of ensuring that
-		  we never read beyond the end of the marker segment (even if
-		  the marker segment length is errantly set too small). */
-		if (!(tmpstream = jas_stream_memopen(0, 0))) {
-			jpc_ms_destroy(ms);
-			return 0;
-		}
-		if (jas_stream_copy(tmpstream, in, ms->len) ||
-		  jas_stream_seek(tmpstream, 0, SEEK_SET) < 0) {
-			jas_stream_close(tmpstream);
-			jpc_ms_destroy(ms);
-			return 0;
-		}
-		/* Get the marker segment parameters. */
-		if ((*ms->ops->getparms)(ms, cstate, tmpstream)) {
-			ms->ops = 0;
-			jpc_ms_destroy(ms);
-			jas_stream_close(tmpstream);
-			return 0;
-		}
-
-		if (jas_getdbglevel() > 0) {
-			jpc_ms_dump(ms, stderr);
-		}
-
-		if (jas_stream_tell(tmpstream) != ms->len) {
-			fprintf(stderr,
-			  "warning: trailing garbage in marker segment (%ld bytes)\n",
-			  ms->len - jas_stream_tell(tmpstream));
-		}
-
-		/* Close the temporary stream. */
-		jas_stream_close(tmpstream);
-
-	} else {
-		/* There are no marker segment parameters. */
-		ms->len = 0;
-
-		if (jas_getdbglevel() > 0) {
-			jpc_ms_dump(ms, stderr);
-		}
-	}
-
-	/* Update the code stream state information based on the type of
-	  marker segment read. */
-	/* Note: This is a bit of a hack, but I'm not going to define another
-	  type of virtual function for this one special case. */
-	if (ms->id == JPC_MS_SIZ) {
-		cstate->numcomps = ms->parms.siz.numcomps;
-	}
-
-	return ms;
+    jpc_ms_t *ms;
+    jpc_mstabent_t *mstabent;
+    jas_stream_t *tmpstream;
+
+    if (!(ms = jpc_ms_create(0))) {
+        return 0;
+    }
+
+    /* Get the marker type. */
+    if (jpc_getuint16(in, &ms->id) || ms->id < JPC_MS_MIN ||
+      ms->id > JPC_MS_MAX) {
+        jpc_ms_destroy(ms);
+        return 0;
+    }
+
+    mstabent = jpc_mstab_lookup(ms->id);
+    ms->ops = &mstabent->ops;
+
+    /* Get the marker segment length and parameters if present. */
+    /* Note: It is tacitly assumed that a marker segment cannot have
+      parameters unless it has a length field.  That is, there cannot
+      be a parameters field without a length field and vice versa. */
+    if (JPC_MS_HASPARMS(ms->id)) {
+        /* Get the length of the marker segment. */
+        if (jpc_getuint16(in, &ms->len) || ms->len < 3) {
+            jpc_ms_destroy(ms);
+            return 0;
+        }
+        /* Calculate the length of the marker segment parameters. */
+        ms->len -= 2;
+        /* Create and prepare a temporary memory stream from which to
+          read the marker segment parameters. */
+        /* Note: This approach provides a simple way of ensuring that
+          we never read beyond the end of the marker segment (even if
+          the marker segment length is errantly set too small). */
+        if (!(tmpstream = jas_stream_memopen(0, 0))) {
+            jpc_ms_destroy(ms);
+            return 0;
+        }
+        if (jas_stream_copy(tmpstream, in, ms->len) ||
+          jas_stream_seek(tmpstream, 0, SEEK_SET) < 0) {
+            jas_stream_close(tmpstream);
+            jpc_ms_destroy(ms);
+            return 0;
+        }
+        /* Get the marker segment parameters. */
+        if ((*ms->ops->getparms)(ms, cstate, tmpstream)) {
+            ms->ops = 0;
+            jpc_ms_destroy(ms);
+            jas_stream_close(tmpstream);
+            return 0;
+        }
+
+        if (jas_getdbglevel() > 0) {
+            jpc_ms_dump(ms, stderr);
+        }
+
+        if (jas_stream_tell(tmpstream) != ms->len) {
+            fprintf(stderr,
+              "warning: trailing garbage in marker segment (%ld bytes)\n",
+              ms->len - jas_stream_tell(tmpstream));
+        }
+
+        /* Close the temporary stream. */
+        jas_stream_close(tmpstream);
+
+    } else {
+        /* There are no marker segment parameters. */
+        ms->len = 0;
+
+        if (jas_getdbglevel() > 0) {
+            jpc_ms_dump(ms, stderr);
+        }
+    }
+
+    /* Update the code stream state information based on the type of
+      marker segment read. */
+    /* Note: This is a bit of a hack, but I'm not going to define another
+      type of virtual function for this one special case. */
+    if (ms->id == JPC_MS_SIZ) {
+        cstate->numcomps = ms->parms.siz.numcomps;
+    }
+
+    return ms;
 }
 
 /* Write a marker segment to a stream. */
 int jpc_putms(jas_stream_t *out, jpc_cstate_t *cstate, jpc_ms_t *ms)
 {
-	jas_stream_t *tmpstream;
-	int len;
-
-	/* Output the marker segment type. */
-	if (jpc_putuint16(out, ms->id)) {
-		return -1;
-	}
-
-	/* Output the marker segment length and parameters if necessary. */
-	if (ms->ops->putparms) {
-		/* Create a temporary stream in which to buffer the
-		  parameter data. */
-		if (!(tmpstream = jas_stream_memopen(0, 0))) {
-			return -1;
-		}
-		if ((*ms->ops->putparms)(ms, cstate, tmpstream)) {
-			jas_stream_close(tmpstream);
-			return -1;
-		}
-		/* Get the number of bytes of parameter data written. */
-		if ((len = jas_stream_tell(tmpstream)) < 0) {
-			jas_stream_close(tmpstream);
-			return -1;
-		}
-		ms->len = len;
-		/* Write the marker segment length and parameter data to
-		  the output stream. */
-		if (jas_stream_seek(tmpstream, 0, SEEK_SET) < 0 ||
-		  jpc_putuint16(out, ms->len + 2) ||
-		  jas_stream_copy(out, tmpstream, ms->len) < 0) {
-			jas_stream_close(tmpstream);
-			return -1;
-		}
-		/* Close the temporary stream. */
-		jas_stream_close(tmpstream);
-	}
-
-	/* This is a bit of a hack, but I'm not going to define another
-	  type of virtual function for this one special case. */
-	if (ms->id == JPC_MS_SIZ) {
-		cstate->numcomps = ms->parms.siz.numcomps;
-	}
-
-	if (jas_getdbglevel() > 0) {
-		jpc_ms_dump(ms, stderr);
-	}
-
-	return 0;
+    jas_stream_t *tmpstream;
+    int len;
+
+    /* Output the marker segment type. */
+    if (jpc_putuint16(out, ms->id)) {
+        return -1;
+    }
+
+    /* Output the marker segment length and parameters if necessary. */
+    if (ms->ops->putparms) {
+        /* Create a temporary stream in which to buffer the
+          parameter data. */
+        if (!(tmpstream = jas_stream_memopen(0, 0))) {
+            return -1;
+        }
+        if ((*ms->ops->putparms)(ms, cstate, tmpstream)) {
+            jas_stream_close(tmpstream);
+            return -1;
+        }
+        /* Get the number of bytes of parameter data written. */
+        if ((len = jas_stream_tell(tmpstream)) < 0) {
+            jas_stream_close(tmpstream);
+            return -1;
+        }
+        ms->len = len;
+        /* Write the marker segment length and parameter data to
+          the output stream. */
+        if (jas_stream_seek(tmpstream, 0, SEEK_SET) < 0 ||
+          jpc_putuint16(out, ms->len + 2) ||
+          jas_stream_copy(out, tmpstream, ms->len) < 0) {
+            jas_stream_close(tmpstream);
+            return -1;
+        }
+        /* Close the temporary stream. */
+        jas_stream_close(tmpstream);
+    }
+
+    /* This is a bit of a hack, but I'm not going to define another
+      type of virtual function for this one special case. */
+    if (ms->id == JPC_MS_SIZ) {
+        cstate->numcomps = ms->parms.siz.numcomps;
+    }
+
+    if (jas_getdbglevel() > 0) {
+        jpc_ms_dump(ms, stderr);
+    }
+
+    return 0;
 }
 
 /******************************************************************************\
@@ -426,45 +426,46 @@ int jpc_putms(jas_stream_t *out, jpc_cstate_t *cstate, jpc_ms_t *ms)
 /* Create a marker segment of the specified type. */
 jpc_ms_t *jpc_ms_create(int type)
 {
-	jpc_ms_t *ms;
-	jpc_mstabent_t *mstabent;
+    jpc_ms_t *ms;
+    jpc_mstabent_t *mstabent;
 
-	if (!(ms = jas_malloc(sizeof(jpc_ms_t)))) {
-		return 0;
-	}
-	ms->id = type;
-	ms->len = 0;
-	mstabent = jpc_mstab_lookup(ms->id);
-	ms->ops = &mstabent->ops;
-	memset(&ms->parms, 0, sizeof(jpc_msparms_t));
-	return ms;
+    if (!(ms = jas_malloc(sizeof(jpc_ms_t)))) {
+        return 0;
+    }
+    ms->id = type;
+    ms->len = 0;
+    mstabent = jpc_mstab_lookup(ms->id);
+    ms->ops = &mstabent->ops;
+    memset(&ms->parms, 0, sizeof(jpc_msparms_t));
+    return ms;
 }
 
 /* Destroy a marker segment. */
 void jpc_ms_destroy(jpc_ms_t *ms)
 {
-	if (ms->ops && ms->ops->destroyparms) {
-		(*ms->ops->destroyparms)(ms);
-	}
-	jas_free(ms);
+    if (ms->ops && ms->ops->destroyparms) {
+        (*ms->ops->destroyparms)(ms);
+    }
+    jas_free(ms);
 }
 
 /* Dump a marker segment to a stream for debugging. */
 void jpc_ms_dump(jpc_ms_t *ms, FILE *out)
 {
-	jpc_mstabent_t *mstabent;
-	mstabent = jpc_mstab_lookup(ms->id);
-	fprintf(out, "type = 0x%04x (%s);", ms->id, mstabent->name);
-	if (JPC_MS_HASPARMS(ms->id)) {
-		fprintf(out, " len = %d;", ms->len + 2);
-		if (ms->ops->dumpparms) {
-			(*ms->ops->dumpparms)(ms, out);
-		} else {
-			fprintf(out, "\n");
-		}
-	} else {
-		fprintf(out, "\n");
-	}
+    jpc_mstabent_t *mstabent;
+    mstabent = jpc_mstab_lookup(ms->id);
+    fprintf(out, "type = 0x%04x (%s);",
+            (unsigned int)ms->id, mstabent->name);
+    if (JPC_MS_HASPARMS(ms->id)) {
+        fprintf(out, " len = %d;", (int)ms->len + 2);
+        if (ms->ops->dumpparms) {
+            (*ms->ops->dumpparms)(ms, out);
+        } else {
+            fprintf(out, "\n");
+        }
+    } else {
+        fprintf(out, "\n");
+    }
 }
 
 /******************************************************************************\
@@ -473,37 +474,37 @@ void jpc_ms_dump(jpc_ms_t *ms, FILE *out)
 
 static int jpc_sot_getparms(jpc_ms_t *ms, jpc_cstate_t *cstate, jas_stream_t *in)
 {
-	jpc_sot_t *sot = &ms->parms.sot;
-	if (jpc_getuint16(in, &sot->tileno) ||
-	  jpc_getuint32(in, &sot->len) ||
-	  jpc_getuint8(in, &sot->partno) ||
-	  jpc_getuint8(in, &sot->numparts)) {
-		return -1;
-	}
-	if (jas_stream_eof(in)) {
-		return -1;
-	}
-	return 0;
+    jpc_sot_t *sot = &ms->parms.sot;
+    if (jpc_getuint16(in, &sot->tileno) ||
+      jpc_getuint32(in, &sot->len) ||
+      jpc_getuint8(in, &sot->partno) ||
+      jpc_getuint8(in, &sot->numparts)) {
+        return -1;
+    }
+    if (jas_stream_eof(in)) {
+        return -1;
+    }
+    return 0;
 }
 
 static int jpc_sot_putparms(jpc_ms_t *ms, jpc_cstate_t *cstate, jas_stream_t *out)
 {
-	jpc_sot_t *sot = &ms->parms.sot;
-	if (jpc_putuint16(out, sot->tileno) ||
-	  jpc_putuint32(out, sot->len) ||
-	  jpc_putuint8(out, sot->partno) ||
-	  jpc_putuint8(out, sot->numparts)) {
-		return -1;
-	}
-	return 0;
+    jpc_sot_t *sot = &ms->parms.sot;
+    if (jpc_putuint16(out, sot->tileno) ||
+      jpc_putuint32(out, sot->len) ||
+      jpc_putuint8(out, sot->partno) ||
+      jpc_putuint8(out, sot->numparts)) {
+        return -1;
+    }
+    return 0;
 }
 
 static int jpc_sot_dumpparms(jpc_ms_t *ms, FILE *out)
 {
-	jpc_sot_t *sot = &ms->parms.sot;
-	fprintf(out, "tileno = %d; len = %d; partno = %d; numparts = %d\n",
-	  sot->tileno, sot->len, sot->partno, sot->numparts);
-	return 0;
+    jpc_sot_t *sot = &ms->parms.sot;
+    fprintf(out, "tileno = %d; len = %d; partno = %d; numparts = %d\n",
+            (int)sot->tileno, (int)sot->len, sot->partno, sot->numparts);
+    return 0;
 }
 
 /******************************************************************************\
@@ -512,242 +513,244 @@ static int jpc_sot_dumpparms(jpc_ms_t *ms, FILE *out)
 
 static void jpc_siz_destroyparms(jpc_ms_t *ms)
 {
-	jpc_siz_t *siz = &ms->parms.siz;
-	if (siz->comps) {
-		jas_free(siz->comps);
-	}
+    jpc_siz_t *siz = &ms->parms.siz;
+    if (siz->comps) {
+        jas_free(siz->comps);
+    }
 }
 
 static int jpc_siz_getparms(jpc_ms_t *ms, jpc_cstate_t *cstate, jas_stream_t *in)
 {
-	jpc_siz_t *siz = &ms->parms.siz;
-	int i;
-	uint_fast8_t tmp;
-	if (jpc_getuint16(in, &siz->caps) ||
-	  jpc_getuint32(in, &siz->width) ||
-	  jpc_getuint32(in, &siz->height) ||
-	  jpc_getuint32(in, &siz->xoff) ||
-	  jpc_getuint32(in, &siz->yoff) ||
-	  jpc_getuint32(in, &siz->tilewidth) ||
-	  jpc_getuint32(in, &siz->tileheight) ||
-	  jpc_getuint32(in, &siz->tilexoff) ||
-	  jpc_getuint32(in, &siz->tileyoff) ||
-	  jpc_getuint16(in, &siz->numcomps)) {
-		return -1;
-	}
-	if (!siz->width || !siz->height || !siz->tilewidth ||
-	  !siz->tileheight || !siz->numcomps) {
-		return -1;
-	}
-	if (!(siz->comps = jas_malloc(siz->numcomps * sizeof(jpc_sizcomp_t)))) {
-		return -1;
-	}
-	for (i = 0; i < siz->numcomps; ++i) {
-		if (jpc_getuint8(in, &tmp) ||
-		  jpc_getuint8(in, &siz->comps[i].hsamp) ||
-		  jpc_getuint8(in, &siz->comps[i].vsamp)) {
-			jas_free(siz->comps);
-			return -1;
-		}
-		siz->comps[i].sgnd = (tmp >> 7) & 1;
-		siz->comps[i].prec = (tmp & 0x7f) + 1;
-	}
-	if (jas_stream_eof(in)) {
-		jas_free(siz->comps);
-		return -1;
-	}
-	return 0;
+    jpc_siz_t *siz = &ms->parms.siz;
+    int i;
+    uint_fast8_t tmp;
+    if (jpc_getuint16(in, &siz->caps) ||
+      jpc_getuint32(in, &siz->width) ||
+      jpc_getuint32(in, &siz->height) ||
+      jpc_getuint32(in, &siz->xoff) ||
+      jpc_getuint32(in, &siz->yoff) ||
+      jpc_getuint32(in, &siz->tilewidth) ||
+      jpc_getuint32(in, &siz->tileheight) ||
+      jpc_getuint32(in, &siz->tilexoff) ||
+      jpc_getuint32(in, &siz->tileyoff) ||
+      jpc_getuint16(in, &siz->numcomps)) {
+        return -1;
+    }
+    if (!siz->width || !siz->height || !siz->tilewidth ||
+      !siz->tileheight || !siz->numcomps) {
+        return -1;
+    }
+    if (!(siz->comps = jas_malloc(siz->numcomps * sizeof(jpc_sizcomp_t)))) {
+        return -1;
+    }
+    for (i = 0; i < siz->numcomps; ++i) {
+        if (jpc_getuint8(in, &tmp) ||
+          jpc_getuint8(in, &siz->comps[i].hsamp) ||
+          jpc_getuint8(in, &siz->comps[i].vsamp)) {
+            jas_free(siz->comps);
+            return -1;
+        }
+        siz->comps[i].sgnd = (tmp >> 7) & 1;
+        siz->comps[i].prec = (tmp & 0x7f) + 1;
+    }
+    if (jas_stream_eof(in)) {
+        jas_free(siz->comps);
+        return -1;
+    }
+    return 0;
 }
 
 static int jpc_siz_putparms(jpc_ms_t *ms, jpc_cstate_t *cstate, jas_stream_t *out)
 {
-	jpc_siz_t *siz = &ms->parms.siz;
-	int i;
-	assert(siz->width && siz->height && siz->tilewidth &&
-	  siz->tileheight && siz->numcomps);
-	if (jpc_putuint16(out, siz->caps) ||
-	  jpc_putuint32(out, siz->width) ||
-	  jpc_putuint32(out, siz->height) ||
-	  jpc_putuint32(out, siz->xoff) ||
-	  jpc_putuint32(out, siz->yoff) ||
-	  jpc_putuint32(out, siz->tilewidth) ||
-	  jpc_putuint32(out, siz->tileheight) ||
-	  jpc_putuint32(out, siz->tilexoff) ||
-	  jpc_putuint32(out, siz->tileyoff) ||
-	  jpc_putuint16(out, siz->numcomps)) {
-		return -1;
-	}
-	for (i = 0; i < siz->numcomps; ++i) {
-		if (jpc_putuint8(out, ((siz->comps[i].sgnd & 1) << 7) |
-		  ((siz->comps[i].prec - 1) & 0x7f)) ||
-		  jpc_putuint8(out, siz->comps[i].hsamp) ||
-		  jpc_putuint8(out, siz->comps[i].vsamp)) {
-			return -1;
-		}
-	}
-	return 0;
+    jpc_siz_t *siz = &ms->parms.siz;
+    int i;
+    assert(siz->width && siz->height && siz->tilewidth &&
+      siz->tileheight && siz->numcomps);
+    if (jpc_putuint16(out, siz->caps) ||
+      jpc_putuint32(out, siz->width) ||
+      jpc_putuint32(out, siz->height) ||
+      jpc_putuint32(out, siz->xoff) ||
+      jpc_putuint32(out, siz->yoff) ||
+      jpc_putuint32(out, siz->tilewidth) ||
+      jpc_putuint32(out, siz->tileheight) ||
+      jpc_putuint32(out, siz->tilexoff) ||
+      jpc_putuint32(out, siz->tileyoff) ||
+      jpc_putuint16(out, siz->numcomps)) {
+        return -1;
+    }
+    for (i = 0; i < siz->numcomps; ++i) {
+        if (jpc_putuint8(out, ((siz->comps[i].sgnd & 1) << 7) |
+          ((siz->comps[i].prec - 1) & 0x7f)) ||
+          jpc_putuint8(out, siz->comps[i].hsamp) ||
+          jpc_putuint8(out, siz->comps[i].vsamp)) {
+            return -1;
+        }
+    }
+    return 0;
 }
 
 static int jpc_siz_dumpparms(jpc_ms_t *ms, FILE *out)
 {
-	jpc_siz_t *siz = &ms->parms.siz;
-	int i;
-	fprintf(out, "caps = 0x%02x;\n", siz->caps);
-	fprintf(out, "width = %d; height = %d; xoff = %d; yoff = %d;\n",
-	  siz->width, siz->height, siz->xoff, siz->yoff);
-	fprintf(out, "tilewidth = %d; tileheight = %d; tilexoff = %d; "
-	  "tileyoff = %d;\n", siz->tilewidth, siz->tileheight, siz->tilexoff,
-	  siz->tileyoff);
-	for (i = 0; i < siz->numcomps; ++i) {
-		fprintf(out, "prec[%d] = %d; sgnd[%d] = %d; hsamp[%d] = %d; "
-		  "vsamp[%d] = %d\n", i, siz->comps[i].prec, i,
-		  siz->comps[i].sgnd, i, siz->comps[i].hsamp, i,
-		  siz->comps[i].vsamp);
-	}
-	return 0;
-}
-
-/******************************************************************************\
+    jpc_siz_t *siz = &ms->parms.siz;
+    int i;
+    fprintf(out, "caps = 0x%02x;\n", (unsigned int)siz->caps);
+    fprintf(out, "width = %d; height = %d; xoff = %d; yoff = %d;\n",
+            (int)siz->width, (int)siz->height, (int)siz->xoff, (int)siz->yoff);
+    fprintf(out, "tilewidth = %d; tileheight = %d; tilexoff = %d; "
+            "tileyoff = %d;\n",
+            (int)siz->tilewidth, (int)siz->tileheight,
+            (int)siz->tilexoff, (int)siz->tileyoff);
+    for (i = 0; i < siz->numcomps; ++i) {
+        fprintf(out, "prec[%d] = %d; sgnd[%d] = %d; hsamp[%d] = %d; "
+                "vsamp[%d] = %d\n", i, siz->comps[i].prec, i,
+                siz->comps[i].sgnd, i, siz->comps[i].hsamp, i,
+                siz->comps[i].vsamp);
+    }
+    return 0;
+}
+
+/*****************************************************************************\
 * COD marker segment operations.
-\******************************************************************************/
+\*****************************************************************************/
 
 static void jpc_cod_destroyparms(jpc_ms_t *ms)
 {
-	jpc_cod_t *cod = &ms->parms.cod;
-	jpc_cox_destroycompparms(&cod->compparms);
+    jpc_cod_t *cod = &ms->parms.cod;
+    jpc_cox_destroycompparms(&cod->compparms);
 }
 
 static int jpc_cod_getparms(jpc_ms_t *ms, jpc_cstate_t *cstate, jas_stream_t *in)
 {
-	jpc_cod_t *cod = &ms->parms.cod;
-	if (jpc_getuint8(in, &cod->csty)) {
-		return -1;
-	}
-	if (jpc_getuint8(in, &cod->prg) ||
-	  jpc_getuint16(in, &cod->numlyrs) ||
-	  jpc_getuint8(in, &cod->mctrans)) {
-		return -1;
-	}
-	if (jpc_cox_getcompparms(ms, cstate, in,
-	  (cod->csty & JPC_COX_PRT) != 0, &cod->compparms)) {
-		return -1;
-	}
-	if (jas_stream_eof(in)) {
-		jpc_cod_destroyparms(ms);
-		return -1;
-	}
-	return 0;
+    jpc_cod_t *cod = &ms->parms.cod;
+    if (jpc_getuint8(in, &cod->csty)) {
+        return -1;
+    }
+    if (jpc_getuint8(in, &cod->prg) ||
+      jpc_getuint16(in, &cod->numlyrs) ||
+      jpc_getuint8(in, &cod->mctrans)) {
+        return -1;
+    }
+    if (jpc_cox_getcompparms(ms, cstate, in,
+      (cod->csty & JPC_COX_PRT) != 0, &cod->compparms)) {
+        return -1;
+    }
+    if (jas_stream_eof(in)) {
+        jpc_cod_destroyparms(ms);
+        return -1;
+    }
+    return 0;
 }
 
 static int jpc_cod_putparms(jpc_ms_t *ms, jpc_cstate_t *cstate, jas_stream_t *out)
 {
-	jpc_cod_t *cod = &ms->parms.cod;
-	assert(cod->numlyrs > 0 && cod->compparms.numdlvls <= 32);
-	assert(cod->compparms.numdlvls == cod->compparms.numrlvls - 1);
-	if (jpc_putuint8(out, cod->compparms.csty) ||
-	  jpc_putuint8(out, cod->prg) ||
-	  jpc_putuint16(out, cod->numlyrs) ||
-	  jpc_putuint8(out, cod->mctrans)) {
-		return -1;
-	}
-	if (jpc_cox_putcompparms(ms, cstate, out,
-	  (cod->csty & JPC_COX_PRT) != 0, &cod->compparms)) {
-		return -1;
-	}
-	return 0;
+    jpc_cod_t *cod = &ms->parms.cod;
+    assert(cod->numlyrs > 0 && cod->compparms.numdlvls <= 32);
+    assert(cod->compparms.numdlvls == cod->compparms.numrlvls - 1);
+    if (jpc_putuint8(out, cod->compparms.csty) ||
+      jpc_putuint8(out, cod->prg) ||
+      jpc_putuint16(out, cod->numlyrs) ||
+      jpc_putuint8(out, cod->mctrans)) {
+        return -1;
+    }
+    if (jpc_cox_putcompparms(ms, cstate, out,
+      (cod->csty & JPC_COX_PRT) != 0, &cod->compparms)) {
+        return -1;
+    }
+    return 0;
 }
 
 static int jpc_cod_dumpparms(jpc_ms_t *ms, FILE *out)
 {
-	jpc_cod_t *cod = &ms->parms.cod;
-	int i;
-	fprintf(out, "csty = 0x%02x;\n", cod->compparms.csty);
-	fprintf(out, "numdlvls = %d; qmfbid = %d; mctrans = %d\n",
-	  cod->compparms.numdlvls, cod->compparms.qmfbid, cod->mctrans);
-	fprintf(out, "prg = %d; numlyrs = %d;\n",
-	  cod->prg, cod->numlyrs);
-	fprintf(out, "cblkwidthval = %d; cblkheightval = %d; "
-	  "cblksty = 0x%02x;\n", cod->compparms.cblkwidthval, cod->compparms.cblkheightval,
-	  cod->compparms.cblksty);
-	if (cod->csty & JPC_COX_PRT) {
-		for (i = 0; i < cod->compparms.numrlvls; ++i) {
-			fprintf(stderr, "prcwidth[%d] = %d, prcheight[%d] = %d\n",
-			  i, cod->compparms.rlvls[i].parwidthval,
-			  i, cod->compparms.rlvls[i].parheightval);
-		}
-	}
-	return 0;
-}
-
-/******************************************************************************\
+    jpc_cod_t *cod = &ms->parms.cod;
+    int i;
+    fprintf(out, "csty = 0x%02x;\n", cod->compparms.csty);
+    fprintf(out, "numdlvls = %d; qmfbid = %d; mctrans = %d\n",
+            cod->compparms.numdlvls, cod->compparms.qmfbid, cod->mctrans);
+    fprintf(out, "prg = %d; numlyrs = %d;\n",
+            cod->prg, (int)cod->numlyrs);
+    fprintf(out, "cblkwidthval = %d; cblkheightval = %d; "
+            "cblksty = 0x%02x;\n", cod->compparms.cblkwidthval, cod->compparms.cblkheightval,
+            cod->compparms.cblksty);
+    if (cod->csty & JPC_COX_PRT) {
+        for (i = 0; i < cod->compparms.numrlvls; ++i) {
+            fprintf(stderr, "prcwidth[%d] = %d, prcheight[%d] = %d\n",
+                    i, cod->compparms.rlvls[i].parwidthval,
+                    i, cod->compparms.rlvls[i].parheightval);
+        }
+    }
+    return 0;
+}
+
+/*****************************************************************************\
 * COC marker segment operations.
-\******************************************************************************/
+\*****************************************************************************/
 
 static void jpc_coc_destroyparms(jpc_ms_t *ms)
 {
-	jpc_coc_t *coc = &ms->parms.coc;
-	jpc_cox_destroycompparms(&coc->compparms);
+    jpc_coc_t *coc = &ms->parms.coc;
+    jpc_cox_destroycompparms(&coc->compparms);
 }
 
 static int jpc_coc_getparms(jpc_ms_t *ms, jpc_cstate_t *cstate, jas_stream_t *in)
 {
-	jpc_coc_t *coc = &ms->parms.coc;
-	uint_fast8_t tmp;
-	if (cstate->numcomps <= 256) {
-		if (jpc_getuint8(in, &tmp)) {
-			return -1;
-		}
-		coc->compno = tmp;
-	} else {
-		if (jpc_getuint16(in, &coc->compno)) {
-			return -1;
-		}
-	}
-	if (jpc_getuint8(in, &coc->compparms.csty)) {
-		return -1;
-	}
-	if (jpc_cox_getcompparms(ms, cstate, in,
-	  (coc->compparms.csty & JPC_COX_PRT) != 0, &coc->compparms)) {
-		return -1;
-	}
-	if (jas_stream_eof(in)) {
-		return -1;
-	}
-	return 0;
+    jpc_coc_t *coc = &ms->parms.coc;
+    uint_fast8_t tmp;
+    if (cstate->numcomps <= 256) {
+        if (jpc_getuint8(in, &tmp)) {
+            return -1;
+        }
+        coc->compno = tmp;
+    } else {
+        if (jpc_getuint16(in, &coc->compno)) {
+            return -1;
+        }
+    }
+    if (jpc_getuint8(in, &coc->compparms.csty)) {
+        return -1;
+    }
+    if (jpc_cox_getcompparms(ms, cstate, in,
+      (coc->compparms.csty & JPC_COX_PRT) != 0, &coc->compparms)) {
+        return -1;
+    }
+    if (jas_stream_eof(in)) {
+        return -1;
+    }
+    return 0;
 }
 
 static int jpc_coc_putparms(jpc_ms_t *ms, jpc_cstate_t *cstate, jas_stream_t *out)
 {
-	jpc_coc_t *coc = &ms->parms.coc;
-	assert(coc->compparms.numdlvls <= 32);
-	if (cstate->numcomps <= 256) {
-		if (jpc_putuint8(out, coc->compno)) {
-			return -1;
-		}
-	} else {
-		if (jpc_putuint16(out, coc->compno)) {
-			return -1;
-		}
-	}
-	if (jpc_putuint8(out, coc->compparms.csty)) {
-		return -1;
-	}
-	if (jpc_cox_putcompparms(ms, cstate, out,
-	  (coc->compparms.csty & JPC_COX_PRT) != 0, &coc->compparms)) {
-		return -1;
-	}
-	return 0;
+    jpc_coc_t *coc = &ms->parms.coc;
+    assert(coc->compparms.numdlvls <= 32);
+    if (cstate->numcomps <= 256) {
+        if (jpc_putuint8(out, coc->compno)) {
+            return -1;
+        }
+    } else {
+        if (jpc_putuint16(out, coc->compno)) {
+            return -1;
+        }
+    }
+    if (jpc_putuint8(out, coc->compparms.csty)) {
+        return -1;
+    }
+    if (jpc_cox_putcompparms(ms, cstate, out,
+      (coc->compparms.csty & JPC_COX_PRT) != 0, &coc->compparms)) {
+        return -1;
+    }
+    return 0;
 }
 
 static int jpc_coc_dumpparms(jpc_ms_t *ms, FILE *out)
 {
-	jpc_coc_t *coc = &ms->parms.coc;
-	fprintf(out, "compno = %d; csty = 0x%02x; numdlvls = %d;\n",
-	  coc->compno, coc->compparms.csty, coc->compparms.numdlvls);
-	fprintf(out, "cblkwidthval = %d; cblkheightval = %d; "
-	  "cblksty = 0x%02x; qmfbid = %d;\n", coc->compparms.cblkwidthval,
-	  coc->compparms.cblkheightval, coc->compparms.cblksty, coc->compparms.qmfbid);
-	return 0;
+    jpc_coc_t *coc = &ms->parms.coc;
+    fprintf(out, "compno = %d; csty = 0x%02x; numdlvls = %d;\n",
+            (int)coc->compno, coc->compparms.csty, coc->compparms.numdlvls);
+    fprintf(out, "cblkwidthval = %d; cblkheightval = %d; "
+            "cblksty = 0x%02x; qmfbid = %d;\n", coc->compparms.cblkwidthval,
+            coc->compparms.cblkheightval, coc->compparms.cblksty,
+            coc->compparms.qmfbid);
+    return 0;
 }
 /******************************************************************************\
 * COD/COC marker segment operation helper functions.
@@ -760,58 +763,58 @@ static void jpc_cox_destroycompparms(jpc_coxcp_t *compparms)
 static int jpc_cox_getcompparms(jpc_ms_t *ms, jpc_cstate_t *cstate,
   jas_stream_t *in, int prtflag, jpc_coxcp_t *compparms)
 {
-	uint_fast8_t tmp;
-	int i;
-	if (jpc_getuint8(in, &compparms->numdlvls) ||
-	  jpc_getuint8(in, &compparms->cblkwidthval) ||
-	  jpc_getuint8(in, &compparms->cblkheightval) ||
-	  jpc_getuint8(in, &compparms->cblksty) ||
-	  jpc_getuint8(in, &compparms->qmfbid)) {
-		return -1;
-	}
-	compparms->numrlvls = compparms->numdlvls + 1;
-	if (prtflag) {
-		for (i = 0; i < compparms->numrlvls; ++i) {
-			if (jpc_getuint8(in, &tmp)) {
-				jpc_cox_destroycompparms(compparms);
-				return -1;
-			}
-			compparms->rlvls[i].parwidthval = tmp & 0xf;
-			compparms->rlvls[i].parheightval = (tmp >> 4) & 0xf;
-		}
+    uint_fast8_t tmp;
+    int i;
+    if (jpc_getuint8(in, &compparms->numdlvls) ||
+      jpc_getuint8(in, &compparms->cblkwidthval) ||
+      jpc_getuint8(in, &compparms->cblkheightval) ||
+      jpc_getuint8(in, &compparms->cblksty) ||
+      jpc_getuint8(in, &compparms->qmfbid)) {
+        return -1;
+    }
+    compparms->numrlvls = compparms->numdlvls + 1;
+    if (prtflag) {
+        for (i = 0; i < compparms->numrlvls; ++i) {
+            if (jpc_getuint8(in, &tmp)) {
+                jpc_cox_destroycompparms(compparms);
+                return -1;
+            }
+            compparms->rlvls[i].parwidthval = tmp & 0xf;
+            compparms->rlvls[i].parheightval = (tmp >> 4) & 0xf;
+        }
 /* Sigh.  This bit should be in the same field in both COC and COD mrk segs. */
 compparms->csty |= JPC_COX_PRT;
-	} else {
-	}
-	if (jas_stream_eof(in)) {
-		jpc_cox_destroycompparms(compparms);
-		return -1;
-	}
-	return 0;
+    } else {
+    }
+    if (jas_stream_eof(in)) {
+        jpc_cox_destroycompparms(compparms);
+        return -1;
+    }
+    return 0;
 }
 
 static int jpc_cox_putcompparms(jpc_ms_t *ms, jpc_cstate_t *cstate,
   jas_stream_t *out, int prtflag, jpc_coxcp_t *compparms)
 {
-	int i;
-	assert(compparms->numdlvls <= 32);
-	if (jpc_putuint8(out, compparms->numdlvls) ||
-	  jpc_putuint8(out, compparms->cblkwidthval) ||
-	  jpc_putuint8(out, compparms->cblkheightval) ||
-	  jpc_putuint8(out, compparms->cblksty) ||
-	  jpc_putuint8(out, compparms->qmfbid)) {
-		return -1;
-	}
-	if (prtflag) {
-		for (i = 0; i < compparms->numrlvls; ++i) {
-			if (jpc_putuint8(out,
-			  ((compparms->rlvls[i].parheightval & 0xf) << 4) |
-			  (compparms->rlvls[i].parwidthval & 0xf))) {
-				return -1;
-			}
-		}
-	}
-	return 0;
+    int i;
+    assert(compparms->numdlvls <= 32);
+    if (jpc_putuint8(out, compparms->numdlvls) ||
+      jpc_putuint8(out, compparms->cblkwidthval) ||
+      jpc_putuint8(out, compparms->cblkheightval) ||
+      jpc_putuint8(out, compparms->cblksty) ||
+      jpc_putuint8(out, compparms->qmfbid)) {
+        return -1;
+    }
+    if (prtflag) {
+        for (i = 0; i < compparms->numrlvls; ++i) {
+            if (jpc_putuint8(out,
+              ((compparms->rlvls[i].parheightval & 0xf) << 4) |
+              (compparms->rlvls[i].parwidthval & 0xf))) {
+                return -1;
+            }
+        }
+    }
+    return 0;
 }
 
 /******************************************************************************\
@@ -820,50 +823,50 @@ static int jpc_cox_putcompparms(jpc_ms_t *ms, jpc_cstate_t *cstate,
 
 static int jpc_rgn_getparms(jpc_ms_t *ms, jpc_cstate_t *cstate, jas_stream_t *in)
 {
-	jpc_rgn_t *rgn = &ms->parms.rgn;
-	uint_fast8_t tmp;
-	if (cstate->numcomps <= 256) {
-		if (jpc_getuint8(in, &tmp)) {
-			return -1;
-		}
-		rgn->compno = tmp;
-	} else {
-		if (jpc_getuint16(in, &rgn->compno)) {
-			return -1;
-		}
-	}
-	if (jpc_getuint8(in, &rgn->roisty) ||
-	  jpc_getuint8(in, &rgn->roishift)) {
-		return -1;
-	}
-	return 0;
+    jpc_rgn_t *rgn = &ms->parms.rgn;
+    uint_fast8_t tmp;
+    if (cstate->numcomps <= 256) {
+        if (jpc_getuint8(in, &tmp)) {
+            return -1;
+        }
+        rgn->compno = tmp;
+    } else {
+        if (jpc_getuint16(in, &rgn->compno)) {
+            return -1;
+        }
+    }
+    if (jpc_getuint8(in, &rgn->roisty) ||
+      jpc_getuint8(in, &rgn->roishift)) {
+        return -1;
+    }
+    return 0;
 }
 
 static int jpc_rgn_putparms(jpc_ms_t *ms, jpc_cstate_t *cstate, jas_stream_t *out)
 {
-	jpc_rgn_t *rgn = &ms->parms.rgn;
-	if (cstate->numcomps <= 256) {
-		if (jpc_putuint8(out, rgn->compno)) {
-			return -1;
-		}
-	} else {
-		if (jpc_putuint16(out, rgn->compno)) {
-			return -1;
-		}
-	}
-	if (jpc_putuint8(out, rgn->roisty) ||
-	  jpc_putuint8(out, rgn->roishift)) {
-		return -1;
-	}
-	return 0;
+    jpc_rgn_t *rgn = &ms->parms.rgn;
+    if (cstate->numcomps <= 256) {
+        if (jpc_putuint8(out, rgn->compno)) {
+            return -1;
+        }
+    } else {
+        if (jpc_putuint16(out, rgn->compno)) {
+            return -1;
+        }
+    }
+    if (jpc_putuint8(out, rgn->roisty) ||
+      jpc_putuint8(out, rgn->roishift)) {
+        return -1;
+    }
+    return 0;
 }
 
 static int jpc_rgn_dumpparms(jpc_ms_t *ms, FILE *out)
 {
-	jpc_rgn_t *rgn = &ms->parms.rgn;
-	fprintf(out, "compno = %d; roisty = %d; roishift = %d\n",
-	  rgn->compno, rgn->roisty, rgn->roishift);
-	return 0;
+    jpc_rgn_t *rgn = &ms->parms.rgn;
+    fprintf(out, "compno = %d; roisty = %d; roishift = %d\n",
+            (int)rgn->compno, rgn->roisty, rgn->roishift);
+    return 0;
 }
 
 /******************************************************************************\
@@ -872,34 +875,34 @@ static int jpc_rgn_dumpparms(jpc_ms_t *ms, FILE *out)
 
 static void jpc_qcd_destroyparms(jpc_ms_t *ms)
 {
-	jpc_qcd_t *qcd = &ms->parms.qcd;
-	jpc_qcx_destroycompparms(&qcd->compparms);
+    jpc_qcd_t *qcd = &ms->parms.qcd;
+    jpc_qcx_destroycompparms(&qcd->compparms);
 }
 
 static int jpc_qcd_getparms(jpc_ms_t *ms, jpc_cstate_t *cstate, jas_stream_t *in)
 {
-	jpc_qcxcp_t *compparms = &ms->parms.qcd.compparms;
-	return jpc_qcx_getcompparms(compparms, cstate, in, ms->len);
+    jpc_qcxcp_t *compparms = &ms->parms.qcd.compparms;
+    return jpc_qcx_getcompparms(compparms, cstate, in, ms->len);
 }
 
 static int jpc_qcd_putparms(jpc_ms_t *ms, jpc_cstate_t *cstate, jas_stream_t *out)
 {
-	jpc_qcxcp_t *compparms = &ms->parms.qcd.compparms;
-	return jpc_qcx_putcompparms(compparms, cstate, out);
+    jpc_qcxcp_t *compparms = &ms->parms.qcd.compparms;
+    return jpc_qcx_putcompparms(compparms, cstate, out);
 }
 
 static int jpc_qcd_dumpparms(jpc_ms_t *ms, FILE *out)
 {
-	jpc_qcd_t *qcd = &ms->parms.qcd;
-	int i;
-	fprintf(out, "qntsty = %d; numguard = %d; numstepsizes = %d\n",
-	  (int) qcd->compparms.qntsty, qcd->compparms.numguard, qcd->compparms.numstepsizes);
-	for (i = 0; i < qcd->compparms.numstepsizes; ++i) {
-		fprintf(out, "expn[%d] = 0x%04x; mant[%d] = 0x%04x;\n",
-		  i, (unsigned) JPC_QCX_GETEXPN(qcd->compparms.stepsizes[i]),
-		  i, (unsigned) JPC_QCX_GETMANT(qcd->compparms.stepsizes[i]));
-	}
-	return 0;
+    jpc_qcd_t *qcd = &ms->parms.qcd;
+    int i;
+    fprintf(out, "qntsty = %d; numguard = %d; numstepsizes = %d\n",
+      (int) qcd->compparms.qntsty, qcd->compparms.numguard, qcd->compparms.numstepsizes);
+    for (i = 0; i < qcd->compparms.numstepsizes; ++i) {
+        fprintf(out, "expn[%d] = 0x%04x; mant[%d] = 0x%04x;\n",
+          i, (unsigned) JPC_QCX_GETEXPN(qcd->compparms.stepsizes[i]),
+          i, (unsigned) JPC_QCX_GETMANT(qcd->compparms.stepsizes[i]));
+    }
+    return 0;
 }
 
 /******************************************************************************\
@@ -908,133 +911,134 @@ static int jpc_qcd_dumpparms(jpc_ms_t *ms, FILE *out)
 
 static void jpc_qcc_destroyparms(jpc_ms_t *ms)
 {
-	jpc_qcc_t *qcc = &ms->parms.qcc;
-	jpc_qcx_destroycompparms(&qcc->compparms);
+    jpc_qcc_t *qcc = &ms->parms.qcc;
+    jpc_qcx_destroycompparms(&qcc->compparms);
 }
 
 static int jpc_qcc_getparms(jpc_ms_t *ms, jpc_cstate_t *cstate, jas_stream_t *in)
 {
-	jpc_qcc_t *qcc = &ms->parms.qcc;
-	uint_fast8_t tmp;
-	int len;
-	len = ms->len;
-	if (cstate->numcomps <= 256) {
-		jpc_getuint8(in, &tmp);
-		qcc->compno = tmp;
-		--len;
-	} else {
-		jpc_getuint16(in, &qcc->compno);
-		len -= 2;
-	}
-	if (jpc_qcx_getcompparms(&qcc->compparms, cstate, in, len)) {
-		return -1;
-	}
-	if (jas_stream_eof(in)) {
-		jpc_qcc_destroyparms(ms);
-		return -1;
-	}
-	return 0;
+    jpc_qcc_t *qcc = &ms->parms.qcc;
+    uint_fast8_t tmp;
+    int len;
+    len = ms->len;
+    if (cstate->numcomps <= 256) {
+        jpc_getuint8(in, &tmp);
+        qcc->compno = tmp;
+        --len;
+    } else {
+        jpc_getuint16(in, &qcc->compno);
+        len -= 2;
+    }
+    if (jpc_qcx_getcompparms(&qcc->compparms, cstate, in, len)) {
+        return -1;
+    }
+    if (jas_stream_eof(in)) {
+        jpc_qcc_destroyparms(ms);
+        return -1;
+    }
+    return 0;
 }
 
 static int jpc_qcc_putparms(jpc_ms_t *ms, jpc_cstate_t *cstate, jas_stream_t *out)
 {
-	jpc_qcc_t *qcc = &ms->parms.qcc;
-	if (cstate->numcomps <= 256) {
-		jpc_putuint8(out, qcc->compno);
-	} else {
-		jpc_putuint16(out, qcc->compno);
-	}
-	if (jpc_qcx_putcompparms(&qcc->compparms, cstate, out)) {
-		return -1;
-	}
-	return 0;
+    jpc_qcc_t *qcc = &ms->parms.qcc;
+    if (cstate->numcomps <= 256) {
+        jpc_putuint8(out, qcc->compno);
+    } else {
+        jpc_putuint16(out, qcc->compno);
+    }
+    if (jpc_qcx_putcompparms(&qcc->compparms, cstate, out)) {
+        return -1;
+    }
+    return 0;
 }
 
 static int jpc_qcc_dumpparms(jpc_ms_t *ms, FILE *out)
 {
-	jpc_qcc_t *qcc = &ms->parms.qcc;
-	int i;
-	fprintf(out, "compno = %d; qntsty = %d; numguard = %d; "
-	  "numstepsizes = %d\n", qcc->compno, qcc->compparms.qntsty, qcc->compparms.numguard,
-	  qcc->compparms.numstepsizes);
-	for (i = 0; i < qcc->compparms.numstepsizes; ++i) {
-		fprintf(out, "expn[%d] = 0x%04x; mant[%d] = 0x%04x;\n",
-		  i, (unsigned) JPC_QCX_GETEXPN(qcc->compparms.stepsizes[i]),
-		  i, (unsigned) JPC_QCX_GETMANT(qcc->compparms.stepsizes[i]));
-	}
-	return 0;
-}
-
-/******************************************************************************\
+    jpc_qcc_t *qcc = &ms->parms.qcc;
+    int i;
+    fprintf(out, "compno = %d; qntsty = %d; numguard = %d; "
+            "numstepsizes = %d\n",
+            (int)qcc->compno, qcc->compparms.qntsty, qcc->compparms.numguard,
+            qcc->compparms.numstepsizes);
+    for (i = 0; i < qcc->compparms.numstepsizes; ++i) {
+        fprintf(out, "expn[%d] = 0x%04x; mant[%d] = 0x%04x;\n",
+          i, (unsigned) JPC_QCX_GETEXPN(qcc->compparms.stepsizes[i]),
+          i, (unsigned) JPC_QCX_GETMANT(qcc->compparms.stepsizes[i]));
+    }
+    return 0;
+}
+
+/*****************************************************************************\
 * QCD/QCC marker segment helper functions.
-\******************************************************************************/
+\*****************************************************************************/
 
 static void jpc_qcx_destroycompparms(jpc_qcxcp_t *compparms)
 {
-	if (compparms->stepsizes) {
-		jas_free(compparms->stepsizes);
-	}
+    if (compparms->stepsizes) {
+        jas_free(compparms->stepsizes);
+    }
 }
 
 static int jpc_qcx_getcompparms(jpc_qcxcp_t *compparms, jpc_cstate_t *cstate,
   jas_stream_t *in, uint_fast16_t len)
 {
-	uint_fast8_t tmp;
-	int n;
-	int i;
-	n = 0;
-	jpc_getuint8(in, &tmp);
-	++n;
-	compparms->qntsty = tmp & 0x1f;
-	compparms->numguard = (tmp >> 5) & 7;
-	switch (compparms->qntsty) {
-	case JPC_QCX_SIQNT:
-		compparms->numstepsizes = 1;
-		break;
-	case JPC_QCX_NOQNT:
-		compparms->numstepsizes = (len - n);
-		break;
-	case JPC_QCX_SEQNT:
-		/* XXX - this is a hack */
-		compparms->numstepsizes = (len - n) / 2;
-		break;
-	}
+    uint_fast8_t tmp;
+    int n;
+    int i;
+    n = 0;
+    jpc_getuint8(in, &tmp);
+    ++n;
+    compparms->qntsty = tmp & 0x1f;
+    compparms->numguard = (tmp >> 5) & 7;
+    switch (compparms->qntsty) {
+    case JPC_QCX_SIQNT:
+        compparms->numstepsizes = 1;
+        break;
+    case JPC_QCX_NOQNT:
+        compparms->numstepsizes = (len - n);
+        break;
+    case JPC_QCX_SEQNT:
+        /* XXX - this is a hack */
+        compparms->numstepsizes = (len - n) / 2;
+        break;
+    }
 if (compparms->numstepsizes > 0) {
-	compparms->stepsizes = jas_malloc(compparms->numstepsizes *
-	  sizeof(uint_fast32_t));
-	assert(compparms->stepsizes);
-	for (i = 0; i < compparms->numstepsizes; ++i) {
-		if (compparms->qntsty == JPC_QCX_NOQNT) {
-			jpc_getuint8(in, &tmp);
-			compparms->stepsizes[i] = JPC_QCX_EXPN(tmp >> 3);
-		} else {
-			jpc_getuint16(in, &compparms->stepsizes[i]);
-		}
-	}
+    compparms->stepsizes = jas_malloc(compparms->numstepsizes *
+      sizeof(uint_fast32_t));
+    assert(compparms->stepsizes);
+    for (i = 0; i < compparms->numstepsizes; ++i) {
+        if (compparms->qntsty == JPC_QCX_NOQNT) {
+            jpc_getuint8(in, &tmp);
+            compparms->stepsizes[i] = JPC_QCX_EXPN(tmp >> 3);
+        } else {
+            jpc_getuint16(in, &compparms->stepsizes[i]);
+        }
+    }
 } else {
-	compparms->stepsizes = 0;
+    compparms->stepsizes = 0;
 }
-	if (jas_stream_error(in) || jas_stream_eof(in)) {
-		jpc_qcx_destroycompparms(compparms);
-		return -1;
-	}
-	return 0;
+    if (jas_stream_error(in) || jas_stream_eof(in)) {
+        jpc_qcx_destroycompparms(compparms);
+        return -1;
+    }
+    return 0;
 }
 
 static int jpc_qcx_putcompparms(jpc_qcxcp_t *compparms, jpc_cstate_t *cstate,
   jas_stream_t *out)
 {
-	int i;
-	jpc_putuint8(out, ((compparms->numguard & 7) << 5) | compparms->qntsty);
-	for (i = 0; i < compparms->numstepsizes; ++i) {
-		if (compparms->qntsty == JPC_QCX_NOQNT) {
-			jpc_putuint8(out, JPC_QCX_GETEXPN(
-			  compparms->stepsizes[i]) << 3);
-		} else {
-			jpc_putuint16(out, compparms->stepsizes[i]);
-		}
-	}
-	return 0;
+    int i;
+    jpc_putuint8(out, ((compparms->numguard & 7) << 5) | compparms->qntsty);
+    for (i = 0; i < compparms->numstepsizes; ++i) {
+        if (compparms->qntsty == JPC_QCX_NOQNT) {
+            jpc_putuint8(out, JPC_QCX_GETEXPN(
+              compparms->stepsizes[i]) << 3);
+        } else {
+            jpc_putuint16(out, compparms->stepsizes[i]);
+        }
+    }
+    return 0;
 }
 
 /******************************************************************************\
@@ -1043,27 +1047,27 @@ static int jpc_qcx_putcompparms(jpc_qcxcp_t *compparms, jpc_cstate_t *cstate,
 
 static int jpc_sop_getparms(jpc_ms_t *ms, jpc_cstate_t *cstate, jas_stream_t *in)
 {
-	jpc_sop_t *sop = &ms->parms.sop;
-	if (jpc_getuint16(in, &sop->seqno)) {
-		return -1;
-	}
-	return 0;
+    jpc_sop_t *sop = &ms->parms.sop;
+    if (jpc_getuint16(in, &sop->seqno)) {
+        return -1;
+    }
+    return 0;
 }
 
 static int jpc_sop_putparms(jpc_ms_t *ms, jpc_cstate_t *cstate, jas_stream_t *out)
 {
-	jpc_sop_t *sop = &ms->parms.sop;
-	if (jpc_putuint16(out, sop->seqno)) {
-		return -1;
-	}
-	return 0;
+    jpc_sop_t *sop = &ms->parms.sop;
+    if (jpc_putuint16(out, sop->seqno)) {
+        return -1;
+    }
+    return 0;
 }
 
 static int jpc_sop_dumpparms(jpc_ms_t *ms, FILE *out)
 {
-	jpc_sop_t *sop = &ms->parms.sop;
-	fprintf(out, "seqno = %d;\n", sop->seqno);
-	return 0;
+    jpc_sop_t *sop = &ms->parms.sop;
+    fprintf(out, "seqno = %d;\n", (int)sop->seqno);
+    return 0;
 }
 
 /******************************************************************************\
@@ -1072,61 +1076,61 @@ static int jpc_sop_dumpparms(jpc_ms_t *ms, FILE *out)
 
 static void jpc_ppm_destroyparms(jpc_ms_t *ms)
 {
-	jpc_ppm_t *ppm = &ms->parms.ppm;
-	if (ppm->data) {
-		jas_free(ppm->data);
-	}
+    jpc_ppm_t *ppm = &ms->parms.ppm;
+    if (ppm->data) {
+        jas_free(ppm->data);
+    }
 }
 
 static int jpc_ppm_getparms(jpc_ms_t *ms, jpc_cstate_t *cstate, jas_stream_t *in)
 {
-	jpc_ppm_t *ppm = &ms->parms.ppm;
-
-	ppm->data = 0;
-
-	if (ms->len < 1) {
-		goto error;
-	}
-	if (jpc_getuint8(in, &ppm->ind)) {
-		goto error;
-	}
-
-	ppm->len = ms->len - 1;
-	if (ppm->len > 0) {
-		if (!(ppm->data = jas_malloc(ppm->len * sizeof(unsigned char)))) {
-			goto error;
-		}
-		if (jas_stream_read(in, ppm->data, ppm->len) != ppm->len) {
-			goto error;
-		}
-	} else {
-		ppm->data = 0;
-	}
-	return 0;
+    jpc_ppm_t *ppm = &ms->parms.ppm;
+
+    ppm->data = 0;
+
+    if (ms->len < 1) {
+        goto error;
+    }
+    if (jpc_getuint8(in, &ppm->ind)) {
+        goto error;
+    }
+
+    ppm->len = ms->len - 1;
+    if (ppm->len > 0) {
+        if (!(ppm->data = jas_malloc(ppm->len * sizeof(unsigned char)))) {
+            goto error;
+        }
+        if (jas_stream_read(in, ppm->data, ppm->len) != ppm->len) {
+            goto error;
+        }
+    } else {
+        ppm->data = 0;
+    }
+    return 0;
 
 error:
-	jpc_ppm_destroyparms(ms);
-	return -1;
+    jpc_ppm_destroyparms(ms);
+    return -1;
 }
 
 static int jpc_ppm_putparms(jpc_ms_t *ms, jpc_cstate_t *cstate, jas_stream_t *out)
 {
-	jpc_ppm_t *ppm = &ms->parms.ppm;
-	if (jas_stream_write(out, (char *) ppm->data, ppm->len) != ppm->len) {
-		return -1;
-	}
-	return 0;
+    jpc_ppm_t *ppm = &ms->parms.ppm;
+    if (jas_stream_write(out, (char *) ppm->data, ppm->len) != ppm->len) {
+        return -1;
+    }
+    return 0;
 }
 
 static int jpc_ppm_dumpparms(jpc_ms_t *ms, FILE *out)
 {
-	jpc_ppm_t *ppm = &ms->parms.ppm;
-	fprintf(out, "ind=%d; len = %d;\n", ppm->ind, ppm->len);
-	if (ppm->len > 0) {
-		fprintf(out, "data =\n");
-		jas_memdump(out, ppm->data, ppm->len);
-	}
-	return 0;
+    jpc_ppm_t *ppm = &ms->parms.ppm;
+    fprintf(out, "ind=%d; len = %d;\n", ppm->ind, (int)ppm->len);
+    if (ppm->len > 0) {
+        fprintf(out, "data =\n");
+        jas_memdump(out, ppm->data, ppm->len);
+    }
+    return 0;
 }
 
 /******************************************************************************\
@@ -1135,169 +1139,169 @@ static int jpc_ppm_dumpparms(jpc_ms_t *ms, FILE *out)
 
 static void jpc_ppt_destroyparms(jpc_ms_t *ms)
 {
-	jpc_ppt_t *ppt = &ms->parms.ppt;
-	if (ppt->data) {
-		jas_free(ppt->data);
-	}
+    jpc_ppt_t *ppt = &ms->parms.ppt;
+    if (ppt->data) {
+        jas_free(ppt->data);
+    }
 }
 
 static int jpc_ppt_getparms(jpc_ms_t *ms, jpc_cstate_t *cstate, jas_stream_t *in)
 {
-	jpc_ppt_t *ppt = &ms->parms.ppt;
-	ppt->data = 0;
-
-	if (ms->len < 1) {
-		goto error;
-	}
-	if (jpc_getuint8(in, &ppt->ind)) {
-		goto error;
-	}
-	ppt->len = ms->len - 1;
-	if (ppt->len > 0) {
-		if (!(ppt->data = jas_malloc(ppt->len * sizeof(unsigned char)))) {
-			goto error;
-		}
-		if (jas_stream_read(in, (char *) ppt->data, ppt->len) != ppt->len) {
-			goto error;
-		}
-	} else {
-		ppt->data = 0;
-	}
-	return 0;
+    jpc_ppt_t *ppt = &ms->parms.ppt;
+    ppt->data = 0;
+
+    if (ms->len < 1) {
+        goto error;
+    }
+    if (jpc_getuint8(in, &ppt->ind)) {
+        goto error;
+    }
+    ppt->len = ms->len - 1;
+    if (ppt->len > 0) {
+        if (!(ppt->data = jas_malloc(ppt->len * sizeof(unsigned char)))) {
+            goto error;
+        }
+        if (jas_stream_read(in, (char *) ppt->data, ppt->len) != ppt->len) {
+            goto error;
+        }
+    } else {
+        ppt->data = 0;
+    }
+    return 0;
 
 error:
-	jpc_ppt_destroyparms(ms);
-	return -1;
+    jpc_ppt_destroyparms(ms);
+    return -1;
 }
 
 static int jpc_ppt_putparms(jpc_ms_t *ms, jpc_cstate_t *cstate, jas_stream_t *out)
 {
-	jpc_ppt_t *ppt = &ms->parms.ppt;
-	if (jpc_putuint8(out, ppt->ind)) {
-		return -1;
-	}
-	if (jas_stream_write(out, (char *) ppt->data, ppt->len) != ppt->len) {
-		return -1;
-	}
-	return 0;
+    jpc_ppt_t *ppt = &ms->parms.ppt;
+    if (jpc_putuint8(out, ppt->ind)) {
+        return -1;
+    }
+    if (jas_stream_write(out, (char *) ppt->data, ppt->len) != ppt->len) {
+        return -1;
+    }
+    return 0;
 }
 
 static int jpc_ppt_dumpparms(jpc_ms_t *ms, FILE *out)
 {
-	jpc_ppt_t *ppt = &ms->parms.ppt;
-	fprintf(out, "ind=%d; len = %d;\n", ppt->ind, ppt->len);
-	if (ppt->len > 0) {
-		fprintf(out, "data =\n");
-		jas_memdump(out, ppt->data, ppt->len);
-	}
-	return 0;
+    jpc_ppt_t *ppt = &ms->parms.ppt;
+    fprintf(out, "ind=%d; len = %d;\n", ppt->ind, (int)ppt->len);
+    if (ppt->len > 0) {
+        fprintf(out, "data =\n");
+        jas_memdump(out, ppt->data, ppt->len);
+    }
+    return 0;
 }
 
-/******************************************************************************\
+/*****************************************************************************\
 * POC marker segment operations.
-\******************************************************************************/
+\*****************************************************************************/
 
 static void jpc_poc_destroyparms(jpc_ms_t *ms)
 {
-	jpc_poc_t *poc = &ms->parms.poc;
-	if (poc->pchgs) {
-		jas_free(poc->pchgs);
-	}
+    jpc_poc_t *poc = &ms->parms.poc;
+    if (poc->pchgs) {
+        jas_free(poc->pchgs);
+    }
 }
 
 static int jpc_poc_getparms(jpc_ms_t *ms, jpc_cstate_t *cstate, jas_stream_t *in)
 {
-	jpc_poc_t *poc = &ms->parms.poc;
-	jpc_pocpchg_t *pchg;
-	int pchgno;
-	uint_fast8_t tmp;
-	poc->numpchgs = (cstate->numcomps > 256) ? (ms->len / 9) :
-	  (ms->len / 7);
-	if (!(poc->pchgs = jas_malloc(poc->numpchgs * sizeof(jpc_pocpchg_t)))) {
-		goto error;
-	}
-	for (pchgno = 0, pchg = poc->pchgs; pchgno < poc->numpchgs; ++pchgno,
-	  ++pchg) {
-		if (jpc_getuint8(in, &pchg->rlvlnostart)) {
-			goto error;
-		}
-		if (cstate->numcomps > 256) {
-			if (jpc_getuint16(in, &pchg->compnostart)) {
-				goto error;
-			}
-		} else {
-			if (jpc_getuint8(in, &tmp)) {
-				goto error;
-			};
-			pchg->compnostart = tmp;
-		}
-		if (jpc_getuint16(in, &pchg->lyrnoend) ||
-		  jpc_getuint8(in, &pchg->rlvlnoend)) {
-			goto error;
-		}
-		if (cstate->numcomps > 256) {
-			if (jpc_getuint16(in, &pchg->compnoend)) {
-				goto error;
-			}
-		} else {
-			if (jpc_getuint8(in, &tmp)) {
-				goto error;
-			}
-			pchg->compnoend = tmp;
-		}
-		if (jpc_getuint8(in, &pchg->prgord)) {
-			goto error;
-		}
-		if (pchg->rlvlnostart > pchg->rlvlnoend ||
-		  pchg->compnostart > pchg->compnoend) {
-			goto error;
-		}
-	}
-	return 0;
+    jpc_poc_t *poc = &ms->parms.poc;
+    jpc_pocpchg_t *pchg;
+    int pchgno;
+    uint_fast8_t tmp;
+    poc->numpchgs = (cstate->numcomps > 256) ? (ms->len / 9) :
+      (ms->len / 7);
+    if (!(poc->pchgs = jas_malloc(poc->numpchgs * sizeof(jpc_pocpchg_t)))) {
+        goto error;
+    }
+    for (pchgno = 0, pchg = poc->pchgs; pchgno < poc->numpchgs; ++pchgno,
+      ++pchg) {
+        if (jpc_getuint8(in, &pchg->rlvlnostart)) {
+            goto error;
+        }
+        if (cstate->numcomps > 256) {
+            if (jpc_getuint16(in, &pchg->compnostart)) {
+                goto error;
+            }
+        } else {
+            if (jpc_getuint8(in, &tmp)) {
+                goto error;
+            };
+            pchg->compnostart = tmp;
+        }
+        if (jpc_getuint16(in, &pchg->lyrnoend) ||
+          jpc_getuint8(in, &pchg->rlvlnoend)) {
+            goto error;
+        }
+        if (cstate->numcomps > 256) {
+            if (jpc_getuint16(in, &pchg->compnoend)) {
+                goto error;
+            }
+        } else {
+            if (jpc_getuint8(in, &tmp)) {
+                goto error;
+            }
+            pchg->compnoend = tmp;
+        }
+        if (jpc_getuint8(in, &pchg->prgord)) {
+            goto error;
+        }
+        if (pchg->rlvlnostart > pchg->rlvlnoend ||
+          pchg->compnostart > pchg->compnoend) {
+            goto error;
+        }
+    }
+    return 0;
 
 error:
-	jpc_poc_destroyparms(ms);
-	return -1;
+    jpc_poc_destroyparms(ms);
+    return -1;
 }
 
 static int jpc_poc_putparms(jpc_ms_t *ms, jpc_cstate_t *cstate, jas_stream_t *out)
 {
-	jpc_poc_t *poc = &ms->parms.poc;
-	jpc_pocpchg_t *pchg;
-	int pchgno;
-	for (pchgno = 0, pchg = poc->pchgs; pchgno < poc->numpchgs; ++pchgno,
-	  ++pchg) {
-		if (jpc_putuint8(out, pchg->rlvlnostart) ||
-		  ((cstate->numcomps > 256) ?
-		  jpc_putuint16(out, pchg->compnostart) :
-		  jpc_putuint8(out, pchg->compnostart)) ||
-		  jpc_putuint16(out, pchg->lyrnoend) ||
-		  jpc_putuint8(out, pchg->rlvlnoend) ||
-		  ((cstate->numcomps > 256) ?
-		  jpc_putuint16(out, pchg->compnoend) :
-		  jpc_putuint8(out, pchg->compnoend)) ||
-		  jpc_putuint8(out, pchg->prgord)) {
-			return -1;
-		}
-	}
-	return 0;
+    jpc_poc_t *poc = &ms->parms.poc;
+    jpc_pocpchg_t *pchg;
+    int pchgno;
+    for (pchgno = 0, pchg = poc->pchgs; pchgno < poc->numpchgs; ++pchgno,
+      ++pchg) {
+        if (jpc_putuint8(out, pchg->rlvlnostart) ||
+          ((cstate->numcomps > 256) ?
+          jpc_putuint16(out, pchg->compnostart) :
+          jpc_putuint8(out, pchg->compnostart)) ||
+          jpc_putuint16(out, pchg->lyrnoend) ||
+          jpc_putuint8(out, pchg->rlvlnoend) ||
+          ((cstate->numcomps > 256) ?
+          jpc_putuint16(out, pchg->compnoend) :
+          jpc_putuint8(out, pchg->compnoend)) ||
+          jpc_putuint8(out, pchg->prgord)) {
+            return -1;
+        }
+    }
+    return 0;
 }
 
 static int jpc_poc_dumpparms(jpc_ms_t *ms, FILE *out)
 {
-	jpc_poc_t *poc = &ms->parms.poc;
-	jpc_pocpchg_t *pchg;
-	int pchgno;
-	for (pchgno = 0, pchg = poc->pchgs; pchgno < poc->numpchgs;
-	  ++pchgno, ++pchg) {
-		fprintf(out, "po[%d] = %d; ", pchgno, pchg->prgord);
-		fprintf(out, "cs[%d] = %d; ce[%d] = %d; ",
-		  pchgno, pchg->compnostart, pchgno, pchg->compnoend);
-		fprintf(out, "rs[%d] = %d; re[%d] = %d; ",
-		  pchgno, pchg->rlvlnostart, pchgno, pchg->rlvlnoend);
-		fprintf(out, "le[%d] = %d\n", pchgno, pchg->lyrnoend);
-	}
-	return 0;
+    jpc_poc_t *poc = &ms->parms.poc;
+    jpc_pocpchg_t *pchg;
+    int pchgno;
+    for (pchgno = 0, pchg = poc->pchgs; pchgno < poc->numpchgs;
+      ++pchgno, ++pchg) {
+        fprintf(out, "po[%d] = %d; ", pchgno, pchg->prgord);
+        fprintf(out, "cs[%d] = %d; ce[%d] = %d; ",
+                pchgno, (int)pchg->compnostart, pchgno, (int)pchg->compnoend);
+        fprintf(out, "rs[%d] = %d; re[%d] = %d; ",
+                pchgno, pchg->rlvlnostart, pchgno, pchg->rlvlnoend);
+        fprintf(out, "le[%d] = %d\n", pchgno, (int)pchg->lyrnoend);
+    }
+    return 0;
 }
 
 /******************************************************************************\
@@ -1306,58 +1310,58 @@ static int jpc_poc_dumpparms(jpc_ms_t *ms, FILE *out)
 
 static void jpc_crg_destroyparms(jpc_ms_t *ms)
 {
-	jpc_crg_t *crg = &ms->parms.crg;
-	if (crg->comps) {
-		jas_free(crg->comps);
-	}
+    jpc_crg_t *crg = &ms->parms.crg;
+    if (crg->comps) {
+        jas_free(crg->comps);
+    }
 }
 
 static int jpc_crg_getparms(jpc_ms_t *ms, jpc_cstate_t *cstate, jas_stream_t *in)
 {
-	jpc_crg_t *crg = &ms->parms.crg;
-	jpc_crgcomp_t *comp;
-	uint_fast16_t compno;
-	crg->numcomps = cstate->numcomps;
-	if (!(crg->comps = jas_malloc(cstate->numcomps * sizeof(uint_fast16_t)))) {
-		return -1;
-	}
-	for (compno = 0, comp = crg->comps; compno < cstate->numcomps;
-	  ++compno, ++comp) {
-		if (jpc_getuint16(in, &comp->hoff) ||
-		  jpc_getuint16(in, &comp->voff)) {
-			jpc_crg_destroyparms(ms);
-			return -1;
-		}
-	}
-	return 0;
+    jpc_crg_t *crg = &ms->parms.crg;
+    jpc_crgcomp_t *comp;
+    uint_fast16_t compno;
+    crg->numcomps = cstate->numcomps;
+    if (!(crg->comps = jas_malloc(cstate->numcomps * sizeof(uint_fast16_t)))) {
+        return -1;
+    }
+    for (compno = 0, comp = crg->comps; compno < cstate->numcomps;
+      ++compno, ++comp) {
+        if (jpc_getuint16(in, &comp->hoff) ||
+          jpc_getuint16(in, &comp->voff)) {
+            jpc_crg_destroyparms(ms);
+            return -1;
+        }
+    }
+    return 0;
 }
 
 static int jpc_crg_putparms(jpc_ms_t *ms, jpc_cstate_t *cstate, jas_stream_t *out)
 {
-	jpc_crg_t *crg = &ms->parms.crg;
-	int compno;
-	jpc_crgcomp_t *comp;
-	for (compno = 0, comp = crg->comps; compno < crg->numcomps; ++compno,
-	  ++comp) {
-		if (jpc_putuint16(out, comp->hoff) ||
-		  jpc_putuint16(out, comp->voff)) {
-			return -1;
-		}
-	}
-	return 0;
+    jpc_crg_t *crg = &ms->parms.crg;
+    int compno;
+    jpc_crgcomp_t *comp;
+    for (compno = 0, comp = crg->comps; compno < crg->numcomps; ++compno,
+      ++comp) {
+        if (jpc_putuint16(out, comp->hoff) ||
+          jpc_putuint16(out, comp->voff)) {
+            return -1;
+        }
+    }
+    return 0;
 }
 
 static int jpc_crg_dumpparms(jpc_ms_t *ms, FILE *out)
 {
-	jpc_crg_t *crg = &ms->parms.crg;
-	int compno;
-	jpc_crgcomp_t *comp;
-	for (compno = 0, comp = crg->comps; compno < crg->numcomps; ++compno,
-	  ++comp) {
-		fprintf(out, "hoff[%d] = %d; voff[%d] = %d\n", compno,
-		  comp->hoff, compno, comp->voff);
-	}
-	return 0;
+    jpc_crg_t *crg = &ms->parms.crg;
+    int compno;
+    jpc_crgcomp_t *comp;
+    for (compno = 0, comp = crg->comps; compno < crg->numcomps; ++compno,
+      ++comp) {
+        fprintf(out, "hoff[%d] = %d; voff[%d] = %d\n",
+                compno, (int)comp->hoff, compno, (int)comp->voff);
+    }
+    return 0;
 }
 
 /******************************************************************************\
@@ -1366,112 +1370,108 @@ static int jpc_crg_dumpparms(jpc_ms_t *ms, FILE *out)
 
 static void jpc_com_destroyparms(jpc_ms_t *ms)
 {
-	jpc_com_t *com = &ms->parms.com;
-	if (com->data) {
-		jas_free(com->data);
-	}
+    jpc_com_t *com = &ms->parms.com;
+    if (com->data) {
+        jas_free(com->data);
+    }
 }
 
 static int jpc_com_getparms(jpc_ms_t *ms, jpc_cstate_t *cstate, jas_stream_t *in)
 {
-	jpc_com_t *com = &ms->parms.com;
-	if (jpc_getuint16(in, &com->regid)) {
-		return -1;
-	}
-	com->len = ms->len - 2;
-	if (com->len > 0) {
-		if (!(com->data = jas_malloc(com->len))) {
-			return -1;
-		}
-		if (jas_stream_read(in, com->data, com->len) != com->len) {
-			return -1;
-		}
-	} else {
-		com->data = 0;
-	}
-	return 0;
+    jpc_com_t *com = &ms->parms.com;
+    if (jpc_getuint16(in, &com->regid)) {
+        return -1;
+    }
+    com->len = ms->len - 2;
+    if (com->len > 0) {
+        if (!(com->data = jas_malloc(com->len))) {
+            return -1;
+        }
+        if (jas_stream_read(in, com->data, com->len) != com->len) {
+            return -1;
+        }
+    } else {
+        com->data = 0;
+    }
+    return 0;
 }
 
 static int jpc_com_putparms(jpc_ms_t *ms, jpc_cstate_t *cstate, jas_stream_t *out)
 {
-	jpc_com_t *com = &ms->parms.com;
-	if (jpc_putuint16(out, com->regid)) {
-		return -1;
-	}
-	if (jas_stream_write(out, com->data, com->len) != com->len) {
-		return -1;
-	}
-	return 0;
+    jpc_com_t *com = &ms->parms.com;
+    if (jpc_putuint16(out, com->regid)) {
+        return -1;
+    }
+    if (jas_stream_write(out, com->data, com->len) != com->len) {
+        return -1;
+    }
+    return 0;
 }
 
 static int jpc_com_dumpparms(jpc_ms_t *ms, FILE *out)
 {
-	jpc_com_t *com = &ms->parms.com;
-	int i;
-	int printable;
-	fprintf(out, "regid = %d;\n", com->regid);
-	printable = 1;
-	for (i = 0; i < com->len; ++i) {
-		if (!isprint(com->data[i])) {
-			printable = 0;
-			break;
-		}
-	}
-	if (printable) {
-		fprintf(out, "data = ");
-		fwrite(com->data, sizeof(char), com->len, out);
-		fprintf(out, "\n");
-	}
-	return 0;
-}
-
-/******************************************************************************\
+    jpc_com_t *com = &ms->parms.com;
+    int i;
+    int printable;
+    fprintf(out, "regid = %d;\n", (int)com->regid);
+    printable = 1;
+    for (i = 0, printable = 1; i < com->len && printable; ++i) {
+        if (!isprint(com->data[i]))
+            printable = 0;
+    }
+    if (printable) {
+        fprintf(out, "data = ");
+        fwrite(com->data, sizeof(char), com->len, out);
+        fprintf(out, "\n");
+    }
+    return 0;
+}
+
+/*****************************************************************************\
 * Operations for unknown types of marker segments.
-\******************************************************************************/
+\*****************************************************************************/
 
 static void jpc_unk_destroyparms(jpc_ms_t *ms)
 {
-	jpc_unk_t *unk = &ms->parms.unk;
-	if (unk->data) {
-		jas_free(unk->data);
-	}
+    jpc_unk_t *unk = &ms->parms.unk;
+    if (unk->data) {
+        jas_free(unk->data);
+    }
 }
 
 static int jpc_unk_getparms(jpc_ms_t *ms, jpc_cstate_t *cstate, jas_stream_t *in)
 {
-	jpc_unk_t *unk = &ms->parms.unk;
+    jpc_unk_t *unk = &ms->parms.unk;
 
-	if (ms->len > 0) {
-		if (!(unk->data = jas_malloc(ms->len * sizeof(unsigned char)))) {
-			return -1;
-		}
-		if (jas_stream_read(in, (char *) unk->data, ms->len) != ms->len) {
-			jas_free(unk->data);
-			return -1;
-		}
-		unk->len = ms->len;
-	} else {
-		unk->data = 0;
-		unk->len = 0;
-	}
-	return 0;
+    if (ms->len > 0) {
+        if (!(unk->data = jas_malloc(ms->len * sizeof(unsigned char)))) {
+            return -1;
+        }
+        if (jas_stream_read(in, (char *) unk->data, ms->len) != ms->len) {
+            jas_free(unk->data);
+            return -1;
+        }
+        unk->len = ms->len;
+    } else {
+        unk->data = 0;
+        unk->len = 0;
+    }
+    return 0;
 }
 
 static int jpc_unk_putparms(jpc_ms_t *ms, jpc_cstate_t *cstate, jas_stream_t *out)
 {
-	/* If this function is called, we are trying to write an unsupported
-	  type of marker segment.  Return with an error indication.  */
-	return -1;
+    return -1;
 }
 
 static int jpc_unk_dumpparms(jpc_ms_t *ms, FILE *out)
 {
-	int i;
-	jpc_unk_t *unk = &ms->parms.unk;
-	for (i = 0; i < unk->len; ++i) {
-		fprintf(out, "%02x ", unk->data[i]);
-	}
-	return 0;
+    int i;
+    jpc_unk_t *unk = &ms->parms.unk;
+    for (i = 0; i < unk->len; ++i) {
+        fprintf(out, "%02x ", unk->data[i]);
+    }
+    return 0;
 }
 
 /******************************************************************************\
@@ -1480,86 +1480,86 @@ static int jpc_unk_dumpparms(jpc_ms_t *ms, FILE *out)
 
 int jpc_getuint8(jas_stream_t *in, uint_fast8_t *val)
 {
-	int c;
-	if ((c = jas_stream_getc(in)) == EOF) {
-		return -1;
-	}
-	if (val) {
-		*val = c;
-	}
-	return 0;
+    int c;
+    if ((c = jas_stream_getc(in)) == EOF) {
+        return -1;
+    }
+    if (val) {
+        *val = c;
+    }
+    return 0;
 }
 
 int jpc_putuint8(jas_stream_t *out, uint_fast8_t val)
 {
-	if (jas_stream_putc(out, val & 0xff) == EOF) {
-		return -1;
-	}
-	return 0;
+    if (jas_stream_putc(out, val & 0xff) == EOF) {
+        return -1;
+    }
+    return 0;
 }
 
 int jpc_getuint16(jas_stream_t *in, uint_fast16_t *val)
 {
-	uint_fast16_t v;
-	int c;
-	if ((c = jas_stream_getc(in)) == EOF) {
-		return -1;
-	}
-	v = c;
-	if ((c = jas_stream_getc(in)) == EOF) {
-		return -1;
-	}
-	v = (v << 8) | c;
-	if (val) {
-		*val = v;
-	}
-	return 0;
+    uint_fast16_t v;
+    int c;
+    if ((c = jas_stream_getc(in)) == EOF) {
+        return -1;
+    }
+    v = c;
+    if ((c = jas_stream_getc(in)) == EOF) {
+        return -1;
+    }
+    v = (v << 8) | c;
+    if (val) {
+        *val = v;
+    }
+    return 0;
 }
 
 int jpc_putuint16(jas_stream_t *out, uint_fast16_t val)
 {
-	if (jas_stream_putc(out, (val >> 8) & 0xff) == EOF ||
-	  jas_stream_putc(out, val & 0xff) == EOF) {
-		return -1;
-	}
-	return 0;
+    if (jas_stream_putc(out, (val >> 8) & 0xff) == EOF ||
+      jas_stream_putc(out, val & 0xff) == EOF) {
+        return -1;
+    }
+    return 0;
 }
 
 int jpc_getuint32(jas_stream_t *in, uint_fast32_t *val)
 {
-	uint_fast32_t v;
-	int c;
-	if ((c = jas_stream_getc(in)) == EOF) {
-		return -1;
-	}
-	v = c;
-	if ((c = jas_stream_getc(in)) == EOF) {
-		return -1;
-	}
-	v = (v << 8) | c;
-	if ((c = jas_stream_getc(in)) == EOF) {
-		return -1;
-	}
-	v = (v << 8) | c;
-	if ((c = jas_stream_getc(in)) == EOF) {
-		return -1;
-	}
-	v = (v << 8) | c;
-	if (val) {
-		*val = v;
-	}
-	return 0;
+    uint_fast32_t v;
+    int c;
+    if ((c = jas_stream_getc(in)) == EOF) {
+        return -1;
+    }
+    v = c;
+    if ((c = jas_stream_getc(in)) == EOF) {
+        return -1;
+    }
+    v = (v << 8) | c;
+    if ((c = jas_stream_getc(in)) == EOF) {
+        return -1;
+    }
+    v = (v << 8) | c;
+    if ((c = jas_stream_getc(in)) == EOF) {
+        return -1;
+    }
+    v = (v << 8) | c;
+    if (val) {
+        *val = v;
+    }
+    return 0;
 }
 
 int jpc_putuint32(jas_stream_t *out, uint_fast32_t val)
 {
-	if (jas_stream_putc(out, (val >> 24) & 0xff) == EOF ||
-	  jas_stream_putc(out, (val >> 16) & 0xff) == EOF ||
-	  jas_stream_putc(out, (val >> 8) & 0xff) == EOF ||
-	  jas_stream_putc(out, val & 0xff) == EOF) {
-		return -1;
-	}
-	return 0;
+    if (jas_stream_putc(out, (val >> 24) & 0xff) == EOF ||
+      jas_stream_putc(out, (val >> 16) & 0xff) == EOF ||
+      jas_stream_putc(out, (val >> 8) & 0xff) == EOF ||
+      jas_stream_putc(out, val & 0xff) == EOF) {
+        return -1;
+    }
+    return 0;
 }
 
 /******************************************************************************\
@@ -1568,47 +1568,47 @@ int jpc_putuint32(jas_stream_t *out, uint_fast32_t val)
 
 static jpc_mstabent_t *jpc_mstab_lookup(int id)
 {
-	jpc_mstabent_t *mstabent;
-	for (mstabent = jpc_mstab;; ++mstabent) {
-		if (mstabent->id == id || mstabent->id < 0) {
-			return mstabent;
-		}
-	}
-	assert(0);
-	return 0;
+    jpc_mstabent_t *mstabent;
+    for (mstabent = jpc_mstab;; ++mstabent) {
+        if (mstabent->id == id || mstabent->id < 0) {
+            return mstabent;
+        }
+    }
+    assert(0);
+    return 0;
 }
 
 int jpc_validate(jas_stream_t *in)
 {
-	int n;
-	int i;
-	unsigned char buf[2];
-
-	assert(JAS_STREAM_MAXPUTBACK >= 2);
-
-	if ((n = jas_stream_read(in, (char *) buf, 2)) < 0) {
-		return -1;
-	}
-	for (i = n - 1; i >= 0; --i) {
-		if (jas_stream_ungetc(in, buf[i]) == EOF) {
-			return -1;
-		}
-	}
-	if (n < 2) {
-		return -1;
-	}
-	if (buf[0] == (JPC_MS_SOC >> 8) && buf[1] == (JPC_MS_SOC & 0xff)) {
-		return 0;
-	}
-	return -1;
+    int n;
+    int i;
+    unsigned char buf[2];
+
+    assert(JAS_STREAM_MAXPUTBACK >= 2);
+
+    if ((n = jas_stream_read(in, (char *) buf, 2)) < 0) {
+        return -1;
+    }
+    for (i = n - 1; i >= 0; --i) {
+        if (jas_stream_ungetc(in, buf[i]) == EOF) {
+            return -1;
+        }
+    }
+    if (n < 2) {
+        return -1;
+    }
+    if (buf[0] == (JPC_MS_SOC >> 8) && buf[1] == (JPC_MS_SOC & 0xff)) {
+        return 0;
+    }
+    return -1;
 }
 
 int jpc_getdata(jas_stream_t *in, jas_stream_t *out, long len)
 {
-	return jas_stream_copy(out, in, len);
+    return jas_stream_copy(out, in, len);
 }
 
 int jpc_putdata(jas_stream_t *out, jas_stream_t *in, long len)
 {
-	return jas_stream_copy(out, in, len);
+    return jas_stream_copy(out, in, len);
 }
diff --git a/converter/other/jpeg2000/libjasper/jpc/jpc_cs.h b/converter/other/jpeg2000/libjasper/jpc/jpc_cs.h
index 07a046d1..4bff677c 100644
--- a/converter/other/jpeg2000/libjasper/jpc/jpc_cs.h
+++ b/converter/other/jpeg2000/libjasper/jpc/jpc_cs.h
@@ -188,7 +188,7 @@ typedef struct {
 	/* The tile number. */
 	uint_fast16_t tileno;
 
-	/* The combined length of the marker segment and its auxilary data
+	/* The combined length of the marker segment and its auxiliary data
 	  (i.e., packet data). */
 	uint_fast32_t len;
 
diff --git a/converter/other/jpeg2000/libjasper/jpc/jpc_dec.c b/converter/other/jpeg2000/libjasper/jpc/jpc_dec.c
index 42980225..72bd0126 100644
--- a/converter/other/jpeg2000/libjasper/jpc/jpc_dec.c
+++ b/converter/other/jpeg2000/libjasper/jpc/jpc_dec.c
@@ -114,14 +114,16 @@
  * $Id$
  */
 
-/******************************************************************************\
+/*****************************************************************************\
 * Includes.
-\******************************************************************************/
+\*****************************************************************************/
 
 #include <stdio.h>
 #include <stdlib.h>
 #include <assert.h>
 
+#include "pm.h"
+
 #include "jasper/jas_types.h"
 #include "jasper/jas_math.h"
 #include "jasper/jas_tvp.h"
@@ -136,34 +138,34 @@
 #include "jpc_t1dec.h"
 #include "jpc_math.h"
 
-/******************************************************************************\
+/*****************************************************************************\
 *
-\******************************************************************************/
+\*****************************************************************************/
 
-#define	JPC_MHSOC	0x0001
+#define JPC_MHSOC   0x0001
   /* In the main header, expecting a SOC marker segment. */
-#define	JPC_MHSIZ	0x0002
+#define JPC_MHSIZ   0x0002
   /* In the main header, expecting a SIZ marker segment. */
-#define	JPC_MH		0x0004
+#define JPC_MH      0x0004
   /* In the main header, expecting "other" marker segments. */
-#define	JPC_TPHSOT	0x0008
+#define JPC_TPHSOT  0x0008
   /* In a tile-part header, expecting a SOT marker segment. */
-#define	JPC_TPH		0x0010
+#define JPC_TPH     0x0010
   /* In a tile-part header, expecting "other" marker segments. */
-#define	JPC_MT		0x0020
+#define JPC_MT      0x0020
   /* In the main trailer. */
 
 typedef struct {
 
-	uint_fast16_t id;
-	/* The marker segment type. */
+    uint_fast16_t id;
+    /* The marker segment type. */
 
-	int validstates;
-	/* The states in which this type of marker segment can be
-	  validly encountered. */
+    int validstates;
+    /* The states in which this type of marker segment can be
+      validly encountered. */
 
-	int (*action)(jpc_dec_t *dec, jpc_ms_t *ms);
-	/* The action to take upon encountering this type of marker segment. */
+    int (*action)(jpc_dec_t *dec, jpc_ms_t *ms);
+    /* The action to take upon encountering this type of marker segment. */
 
 } jpc_dec_mstabent_t;
 
@@ -172,13 +174,13 @@ typedef struct {
 \******************************************************************************/
 
 /* COD/COC parameters have been specified. */
-#define	JPC_CSET	0x0001
+#define JPC_CSET    0x0001
 /* QCD/QCC parameters have been specified. */
-#define	JPC_QSET	0x0002
+#define JPC_QSET    0x0002
 /* COD/COC parameters set from a COC marker segment. */
-#define	JPC_COC	0x0004
+#define JPC_COC 0x0004
 /* QCD/QCC parameters set from a QCC marker segment. */
-#define	JPC_QCC	0x0008
+#define JPC_QCC 0x0008
 
 /******************************************************************************\
 * Local function prototypes.
@@ -253,134 +255,134 @@ static int jpc_dec_parseopts(char *optstr, jpc_dec_importopts_t *opts);
 \******************************************************************************/
 
 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}
+    {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.
-\******************************************************************************/
+\*****************************************************************************/
 
 jas_image_t *jpc_decode(jas_stream_t *in, char *optstr)
 {
-	jpc_dec_importopts_t opts;
-	jpc_dec_t *dec;
-	jas_image_t *image;
+    jpc_dec_importopts_t opts;
+    jpc_dec_t *dec;
+    jas_image_t *image;
 
-	dec = 0;
+    dec = 0;
 
-	if (jpc_dec_parseopts(optstr, &opts)) {
-		goto error;
-	}
+    if (jpc_dec_parseopts(optstr, &opts)) {
+        goto error;
+    }
 
-	jpc_initluts();
+    jpc_initluts();
 
-	if (!(dec = jpc_dec_create(&opts, in))) {
-		goto error;
-	}
+    if (!(dec = jpc_dec_create(&opts, in))) {
+        goto error;
+    }
 
-	/* Do most of the work. */
-	if (jpc_dec_decode(dec)) {
-		goto error;
-	}
+    /* Do most of the work. */
+    if (jpc_dec_decode(dec)) {
+        goto error;
+    }
 
-	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));
-	}
+    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;
+    /* Save the return value. */
+    image = dec->image;
 
-	/* Stop the image from being discarded. */
-	dec->image = 0;
+    /* Stop the image from being discarded. */
+    dec->image = 0;
 
-	/* Destroy decoder. */
-	jpc_dec_destroy(dec);
+    /* Destroy decoder. */
+    jpc_dec_destroy(dec);
 
-	return image;
+    return image;
 
 error:
-	if (dec) {
-		jpc_dec_destroy(dec);
-	}
-	return 0;
+    if (dec) {
+        jpc_dec_destroy(dec);
+    }
+    return 0;
 }
 
 typedef enum {
-	OPT_MAXLYRS,
-	OPT_MAXPKTS,
-	OPT_DEBUG
+    OPT_MAXLYRS,
+    OPT_MAXPKTS,
+    OPT_DEBUG
 } optid_t;
 
 jas_taginfo_t decopts[] = {
-	{OPT_MAXLYRS, "maxlyrs"},
-	{OPT_MAXPKTS, "maxpkts"},
-	{OPT_DEBUG, "debug"},
-	{-1, 0}
+    {OPT_MAXLYRS, "maxlyrs"},
+    {OPT_MAXPKTS, "maxpkts"},
+    {OPT_DEBUG, "debug"},
+    {-1, 0}
 };
 
 static int jpc_dec_parseopts(char *optstr, jpc_dec_importopts_t *opts)
 {
-	jas_tvparser_t *tvp;
+    jas_tvparser_t *tvp;
 
-	opts->debug = 0;
-	opts->maxlyrs = JPC_MAXLYRS;
-	opts->maxpkts = -1;
+    opts->debug = 0;
+    opts->maxlyrs = JPC_MAXLYRS;
+    opts->maxpkts = -1;
 
-	if (!(tvp = jas_tvparser_create(optstr ? optstr : ""))) {
-		return -1;
-	}
+    if (!(tvp = jas_tvparser_create(optstr ? optstr : ""))) {
+        return -1;
+    }
 
-	while (!jas_tvparser_next(tvp)) {
-		switch (jas_taginfo_nonull(jas_taginfos_lookup(decopts,
-		  jas_tvparser_gettag(tvp)))->id) {
-		case OPT_MAXLYRS:
-			opts->maxlyrs = atoi(jas_tvparser_getval(tvp));
-			break;
-		case OPT_DEBUG:
-			opts->debug = atoi(jas_tvparser_getval(tvp));
-			break;
-		case OPT_MAXPKTS:
-			opts->maxpkts = atoi(jas_tvparser_getval(tvp));
-			break;
-		default:
-			fprintf(stderr, "warning: ignoring invalid option %s\n",
-			  jas_tvparser_gettag(tvp));
-			break;
-		}
-	}
+    while (!jas_tvparser_next(tvp)) {
+        switch (jas_taginfo_nonull(jas_taginfos_lookup(decopts,
+          jas_tvparser_gettag(tvp)))->id) {
+        case OPT_MAXLYRS:
+            opts->maxlyrs = atoi(jas_tvparser_getval(tvp));
+            break;
+        case OPT_DEBUG:
+            opts->debug = atoi(jas_tvparser_getval(tvp));
+            break;
+        case OPT_MAXPKTS:
+            opts->maxpkts = atoi(jas_tvparser_getval(tvp));
+            break;
+        default:
+            fprintf(stderr, "warning: ignoring invalid option %s\n",
+              jas_tvparser_gettag(tvp));
+            break;
+        }
+    }
 
-	jas_tvparser_destroy(tvp);
+    jas_tvparser_destroy(tvp);
 
-	return 0;
+    return 0;
 }
 
 /******************************************************************************\
@@ -389,1121 +391,1121 @@ static int jpc_dec_parseopts(char *optstr, jpc_dec_importopts_t *opts)
 
 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;
+    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;
+    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;
+    if (!(cstate = jpc_cstate_create())) {
+        return -1;
+    }
+    dec->cstate = cstate;
 
-	/* Initially, we should expect to encounter a SOC marker segment. */
-	dec->state = JPC_MHSOC;
+    /* Initially, we should expect to encounter a SOC marker segment. */
+    dec->state = JPC_MHSOC;
 
-	for (;;) {
+    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;
-		}
+        /* 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);
+        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;
-		}
+        /* 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;
-		}
+        /* 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);
+        /* Destroy the marker segment. */
+        jpc_ms_destroy(ms);
 
-		if (ret < 0) {
-			return -1;
-		} else if (ret > 0) {
-			break;
-		}
+        if (ret < 0) {
+            return -1;
+        } else if (ret > 0) {
+            break;
+        }
 
-	}
+    }
 
-	return 0;
+    return 0;
 }
 
 static int jpc_dec_process_crg(jpc_dec_t *dec, jpc_ms_t *ms)
 {
-	uint_fast16_t cmptno;
-	jpc_dec_cmpt_t *cmpt;
-	jpc_crg_t *crg;
+    uint_fast16_t cmptno;
+    jpc_dec_cmpt_t *cmpt;
+    jpc_crg_t *crg;
 
-	crg = &ms->parms.crg;
-	for (cmptno = 0, cmpt = dec->cmpts; cmptno < dec->numcomps; ++cmptno,
-	  ++cmpt) {
-		/* 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
-		  are uncommented.
-		cmpt->hsubstep = crg->comps[cmptno].hoff;
-		cmpt->vsubstep = crg->comps[cmptno].voff;
-		*/
-	}
-	return 0;
+    crg = &ms->parms.crg;
+    for (cmptno = 0, cmpt = dec->cmpts; cmptno < dec->numcomps; ++cmptno,
+      ++cmpt) {
+        /* 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
+          are uncommented.
+        cmpt->hsubstep = crg->comps[cmptno].hoff;
+        cmpt->vsubstep = crg->comps[cmptno].voff;
+        */
+    }
+    return 0;
 }
 
 static int jpc_dec_process_soc(jpc_dec_t *dec, jpc_ms_t *ms)
 {
-	/* We should expect to encounter a SIZ marker segment next. */
-	dec->state = JPC_MHSIZ;
+    /* We should expect to encounter a SIZ marker segment next. */
+    dec->state = JPC_MHSIZ;
 
-	return 0;
+    return 0;
 }
 
 static int jpc_dec_process_sot(jpc_dec_t *dec, jpc_ms_t *ms)
 {
-	jpc_dec_tile_t *tile;
-	jpc_sot_t *sot = &ms->parms.sot;
-	jas_image_cmptparm_t *compinfos;
-	jas_image_cmptparm_t *compinfo;
-	jpc_dec_cmpt_t *cmpt;
-	uint_fast16_t cmptno;
-
-	if (dec->state == JPC_MH) {
-
-		compinfos = jas_malloc(dec->numcomps * sizeof(jas_image_cmptparm_t));
-		assert(compinfos);
-		for (cmptno = 0, cmpt = dec->cmpts, compinfo = compinfos;
-		  cmptno < dec->numcomps; ++cmptno, ++cmpt, ++compinfo) {
-			compinfo->tlx = 0;
-			compinfo->tly = 0;
-			compinfo->prec = cmpt->prec;
-			compinfo->sgnd = cmpt->sgnd;
-			compinfo->width = cmpt->width;
-			compinfo->height = cmpt->height;
-			compinfo->hstep = cmpt->hstep;
-			compinfo->vstep = cmpt->vstep;
-		}
-
-		if (!(dec->image = jas_image_create(dec->numcomps, compinfos,
-		  JAS_IMAGE_CS_UNKNOWN))) {
-			return -1;
-		}
-		jas_free(compinfos);
-
-		/* Is the packet header information stored in PPM marker segments in
-		  the main header? */
-		if (dec->ppmstab) {
-			/* Convert the PPM marker segment data into a collection of streams
-			  (one stream per tile-part). */
-			if (!(dec->pkthdrstreams = jpc_ppmstabtostreams(dec->ppmstab))) {
-				abort();
-			}
-			jpc_ppxstab_destroy(dec->ppmstab);
-			dec->ppmstab = 0;
-		}
-	}
-
-	if (sot->len > 0) {
-		dec->curtileendoff = jas_stream_getrwcount(dec->in) - ms->len -
-		  4 + sot->len;
-	} else {
-		dec->curtileendoff = 0;
-	}
-
-	if (sot->tileno > dec->numtiles) {
-		fprintf(stderr, "invalid tile number in SOT marker segment\n");
-		return -1;
-	}
-	/* 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;
-	}
-	if (tile->numparts > 0 && sot->partno >= tile->numparts) {
-		return -1;
-	}
-	if (!tile->numparts && sot->numparts > 0) {
-		tile->numparts = sot->numparts;
-	}
-
-	tile->pptstab = 0;
-
-	switch (tile->state) {
-	case JPC_TILE_INIT:
-		/* This is the first tile-part for this tile. */
-		tile->state = JPC_TILE_ACTIVE;
-		assert(!tile->cp);
-		if (!(tile->cp = jpc_dec_cp_copy(dec->cp))) {
-			return -1;
-		}
-		jpc_dec_cp_resetflags(dec->cp);
-		break;
-	default:
-		if (sot->numparts == sot->partno - 1) {
-			tile->state = JPC_TILE_ACTIVELAST;
-		}
-		break;
-	}
-
-	/* Note: We do not increment the expected tile-part number until
-	  all processing for this tile-part is complete. */
-
-	/* We should expect to encounter other tile-part header marker
-	  segments next. */
-	dec->state = JPC_TPH;
-
-	return 0;
+    jpc_dec_tile_t *tile;
+    jpc_sot_t *sot = &ms->parms.sot;
+    jas_image_cmptparm_t *compinfos;
+    jas_image_cmptparm_t *compinfo;
+    jpc_dec_cmpt_t *cmpt;
+    uint_fast16_t cmptno;
+
+    if (dec->state == JPC_MH) {
+
+        compinfos = jas_malloc(dec->numcomps * sizeof(jas_image_cmptparm_t));
+        assert(compinfos);
+        for (cmptno = 0, cmpt = dec->cmpts, compinfo = compinfos;
+          cmptno < dec->numcomps; ++cmptno, ++cmpt, ++compinfo) {
+            compinfo->tlx = 0;
+            compinfo->tly = 0;
+            compinfo->prec = cmpt->prec;
+            compinfo->sgnd = cmpt->sgnd;
+            compinfo->width = cmpt->width;
+            compinfo->height = cmpt->height;
+            compinfo->hstep = cmpt->hstep;
+            compinfo->vstep = cmpt->vstep;
+        }
+
+        if (!(dec->image = jas_image_create(dec->numcomps, compinfos,
+          JAS_IMAGE_CS_UNKNOWN))) {
+            return -1;
+        }
+        jas_free(compinfos);
+
+        /* Is the packet header information stored in PPM marker segments in
+          the main header? */
+        if (dec->ppmstab) {
+            /* Convert the PPM marker segment data into a collection of streams
+              (one stream per tile-part). */
+            if (!(dec->pkthdrstreams = jpc_ppmstabtostreams(dec->ppmstab))) {
+                abort();
+            }
+            jpc_ppxstab_destroy(dec->ppmstab);
+            dec->ppmstab = 0;
+        }
+    }
+
+    if (sot->len > 0) {
+        dec->curtileendoff = jas_stream_getrwcount(dec->in) - ms->len -
+          4 + sot->len;
+    } else {
+        dec->curtileendoff = 0;
+    }
+
+    if (sot->tileno > dec->numtiles) {
+        fprintf(stderr, "invalid tile number in SOT marker segment\n");
+        return -1;
+    }
+    /* 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;
+    }
+    if (tile->numparts > 0 && sot->partno >= tile->numparts) {
+        return -1;
+    }
+    if (!tile->numparts && sot->numparts > 0) {
+        tile->numparts = sot->numparts;
+    }
+
+    tile->pptstab = 0;
+
+    switch (tile->state) {
+    case JPC_TILE_INIT:
+        /* This is the first tile-part for this tile. */
+        tile->state = JPC_TILE_ACTIVE;
+        assert(!tile->cp);
+        if (!(tile->cp = jpc_dec_cp_copy(dec->cp))) {
+            return -1;
+        }
+        jpc_dec_cp_resetflags(dec->cp);
+        break;
+    default:
+        if (sot->numparts == sot->partno - 1) {
+            tile->state = JPC_TILE_ACTIVELAST;
+        }
+        break;
+    }
+
+    /* Note: We do not increment the expected tile-part number until
+      all processing for this tile-part is complete. */
+
+    /* We should expect to encounter other tile-part header marker
+      segments next. */
+    dec->state = JPC_TPH;
+
+    return 0;
 }
 
 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;
-		}
-		jpc_dec_cp_prepare(tile->cp);
-		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;
+    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;
+        }
+        jpc_dec_cp_prepare(tile->cp);
+        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)
 {
-	jpc_dec_tcomp_t *tcomp;
-	uint_fast16_t compno;
-	int rlvlno;
-	jpc_dec_rlvl_t *rlvl;
-	jpc_dec_band_t *band;
-	jpc_dec_prc_t *prc;
-	int bndno;
-	jpc_tsfb_band_t *bnd;
-	int bandno;
-	jpc_dec_ccp_t *ccp;
-	int prccnt;
-	jpc_dec_cblk_t *cblk;
-	int cblkcnt;
-	uint_fast32_t tlprcxstart;
-	uint_fast32_t tlprcystart;
-	uint_fast32_t brprcxend;
-	uint_fast32_t brprcyend;
-	uint_fast32_t tlcbgxstart;
-	uint_fast32_t tlcbgystart;
-	uint_fast32_t brcbgxend;
-	uint_fast32_t brcbgyend;
-	uint_fast32_t cbgxstart;
-	uint_fast32_t cbgystart;
-	uint_fast32_t cbgxend;
-	uint_fast32_t cbgyend;
-	uint_fast32_t tlcblkxstart;
-	uint_fast32_t tlcblkystart;
-	uint_fast32_t brcblkxend;
-	uint_fast32_t brcblkyend;
-	uint_fast32_t cblkxstart;
-	uint_fast32_t cblkystart;
-	uint_fast32_t cblkxend;
-	uint_fast32_t cblkyend;
-	uint_fast32_t tmpxstart;
-	uint_fast32_t tmpystart;
-	uint_fast32_t tmpxend;
-	uint_fast32_t tmpyend;
-	jpc_dec_cp_t *cp;
-	jpc_tsfb_band_t bnds[64];
-	jpc_pchg_t *pchg;
-	int pchgno;
-	jpc_dec_cmpt_t *cmpt;
-
-	cp = tile->cp;
-	tile->realmode = 0;
-	if (cp->mctid == JPC_MCT_ICT) {
-		tile->realmode = 1;
-	}
-
-	for (compno = 0, tcomp = tile->tcomps, cmpt = dec->cmpts; compno <
-	  dec->numcomps; ++compno, ++tcomp, ++cmpt) {
-		ccp = &tile->cp->ccps[compno];
-		if (ccp->qmfbid == JPC_COX_INS) {
-			tile->realmode = 1;
-		}
-		tcomp->numrlvls = ccp->numrlvls;
-		if (!(tcomp->rlvls = jas_malloc(tcomp->numrlvls *
-		  sizeof(jpc_dec_rlvl_t)))) {
-			return -1;
-		}
-		if (!(tcomp->data = jas_seq2d_create(JPC_CEILDIV(tile->xstart,
-		  cmpt->hstep), JPC_CEILDIV(tile->ystart, cmpt->vstep),
-		  JPC_CEILDIV(tile->xend, cmpt->hstep), JPC_CEILDIV(tile->yend,
-		  cmpt->vstep)))) {
-			return -1;
-		}
-		if (!(tcomp->tsfb = jpc_cod_gettsfb(ccp->qmfbid,
-		  tcomp->numrlvls - 1))) {
-			return -1;
-		}
-{
-	jpc_tsfb_getbands(tcomp->tsfb, jas_seq2d_xstart(tcomp->data), jas_seq2d_ystart(tcomp->data), jas_seq2d_xend(tcomp->data), jas_seq2d_yend(tcomp->data), bnds);
-}
-		for (rlvlno = 0, rlvl = tcomp->rlvls; rlvlno < tcomp->numrlvls;
-		  ++rlvlno, ++rlvl) {
+    jpc_dec_tcomp_t *tcomp;
+    uint_fast16_t compno;
+    int rlvlno;
+    jpc_dec_rlvl_t *rlvl;
+    jpc_dec_band_t *band;
+    jpc_dec_prc_t *prc;
+    int bndno;
+    jpc_tsfb_band_t *bnd;
+    int bandno;
+    jpc_dec_ccp_t *ccp;
+    int prccnt;
+    jpc_dec_cblk_t *cblk;
+    int cblkcnt;
+    uint_fast32_t tlprcxstart;
+    uint_fast32_t tlprcystart;
+    uint_fast32_t brprcxend;
+    uint_fast32_t brprcyend;
+    uint_fast32_t tlcbgxstart;
+    uint_fast32_t tlcbgystart;
+    uint_fast32_t brcbgxend;
+    uint_fast32_t brcbgyend;
+    uint_fast32_t cbgxstart;
+    uint_fast32_t cbgystart;
+    uint_fast32_t cbgxend;
+    uint_fast32_t cbgyend;
+    uint_fast32_t tlcblkxstart;
+    uint_fast32_t tlcblkystart;
+    uint_fast32_t brcblkxend;
+    uint_fast32_t brcblkyend;
+    uint_fast32_t cblkxstart;
+    uint_fast32_t cblkystart;
+    uint_fast32_t cblkxend;
+    uint_fast32_t cblkyend;
+    uint_fast32_t tmpxstart;
+    uint_fast32_t tmpystart;
+    uint_fast32_t tmpxend;
+    uint_fast32_t tmpyend;
+    jpc_dec_cp_t *cp;
+    jpc_tsfb_band_t bnds[64];
+    jpc_pchg_t *pchg;
+    int pchgno;
+    jpc_dec_cmpt_t *cmpt;
+
+    cp = tile->cp;
+    tile->realmode = 0;
+    if (cp->mctid == JPC_MCT_ICT) {
+        tile->realmode = 1;
+    }
+
+    for (compno = 0, tcomp = tile->tcomps, cmpt = dec->cmpts; compno <
+      dec->numcomps; ++compno, ++tcomp, ++cmpt) {
+        ccp = &tile->cp->ccps[compno];
+        if (ccp->qmfbid == JPC_COX_INS) {
+            tile->realmode = 1;
+        }
+        tcomp->numrlvls = ccp->numrlvls;
+        if (!(tcomp->rlvls = jas_malloc(tcomp->numrlvls *
+          sizeof(jpc_dec_rlvl_t)))) {
+            return -1;
+        }
+        if (!(tcomp->data = jas_seq2d_create(JPC_CEILDIV(tile->xstart,
+          cmpt->hstep), JPC_CEILDIV(tile->ystart, cmpt->vstep),
+          JPC_CEILDIV(tile->xend, cmpt->hstep), JPC_CEILDIV(tile->yend,
+          cmpt->vstep)))) {
+            return -1;
+        }
+        if (!(tcomp->tsfb = jpc_cod_gettsfb(ccp->qmfbid,
+          tcomp->numrlvls - 1))) {
+            return -1;
+        }
+{
+    jpc_tsfb_getbands(tcomp->tsfb, jas_seq2d_xstart(tcomp->data), jas_seq2d_ystart(tcomp->data), jas_seq2d_xend(tcomp->data), jas_seq2d_yend(tcomp->data), bnds);
+}
+        for (rlvlno = 0, rlvl = tcomp->rlvls; rlvlno < tcomp->numrlvls;
+          ++rlvlno, ++rlvl) {
 rlvl->bands = 0;
-			rlvl->xstart = JPC_CEILDIVPOW2(tcomp->xstart,
-			  tcomp->numrlvls - 1 - rlvlno);
-			rlvl->ystart = JPC_CEILDIVPOW2(tcomp->ystart,
-			  tcomp->numrlvls - 1 - rlvlno);
-			rlvl->xend = JPC_CEILDIVPOW2(tcomp->xend,
-			  tcomp->numrlvls - 1 - rlvlno);
-			rlvl->yend = JPC_CEILDIVPOW2(tcomp->yend,
-			  tcomp->numrlvls - 1 - rlvlno);
-			rlvl->prcwidthexpn = ccp->prcwidthexpns[rlvlno];
-			rlvl->prcheightexpn = ccp->prcheightexpns[rlvlno];
-			tlprcxstart = JPC_FLOORDIVPOW2(rlvl->xstart,
-			  rlvl->prcwidthexpn) << rlvl->prcwidthexpn;
-			tlprcystart = JPC_FLOORDIVPOW2(rlvl->ystart,
-			  rlvl->prcheightexpn) << rlvl->prcheightexpn;
-			brprcxend = JPC_CEILDIVPOW2(rlvl->xend,
-			  rlvl->prcwidthexpn) << rlvl->prcwidthexpn;
-			brprcyend = JPC_CEILDIVPOW2(rlvl->yend,
-			  rlvl->prcheightexpn) << rlvl->prcheightexpn;
-			rlvl->numhprcs = (brprcxend - tlprcxstart) >>
-			  rlvl->prcwidthexpn;
-			rlvl->numvprcs = (brprcyend - tlprcystart) >>
-			  rlvl->prcheightexpn;
-			rlvl->numprcs = rlvl->numhprcs * rlvl->numvprcs;
-
-			if (rlvl->xstart >= rlvl->xend || rlvl->ystart >= rlvl->yend) {
-				rlvl->bands = 0;
-				rlvl->numprcs = 0;
-				rlvl->numhprcs = 0;
-				rlvl->numvprcs = 0;
-				continue;
-			}	
-			if (!rlvlno) {
-				tlcbgxstart = tlprcxstart;
-				tlcbgystart = tlprcystart;
-				brcbgxend = brprcxend;
-				brcbgyend = brprcyend;
-				rlvl->cbgwidthexpn = rlvl->prcwidthexpn;
-				rlvl->cbgheightexpn = rlvl->prcheightexpn;
-			} else {
-				tlcbgxstart = JPC_CEILDIVPOW2(tlprcxstart, 1);
-				tlcbgystart = JPC_CEILDIVPOW2(tlprcystart, 1);
-				brcbgxend = JPC_CEILDIVPOW2(brprcxend, 1);
-				brcbgyend = JPC_CEILDIVPOW2(brprcyend, 1);
-				rlvl->cbgwidthexpn = rlvl->prcwidthexpn - 1;
-				rlvl->cbgheightexpn = rlvl->prcheightexpn - 1;
-			}
-			rlvl->cblkwidthexpn = JAS_MIN(ccp->cblkwidthexpn,
-			  rlvl->cbgwidthexpn);
-			rlvl->cblkheightexpn = JAS_MIN(ccp->cblkheightexpn,
-			  rlvl->cbgheightexpn);
-
-			rlvl->numbands = (!rlvlno) ? 1 : 3;
-			if (!(rlvl->bands = jas_malloc(rlvl->numbands *
-			  sizeof(jpc_dec_band_t)))) {
-				return -1;
-			}
-			for (bandno = 0, band = rlvl->bands;
-			  bandno < rlvl->numbands; ++bandno, ++band) {
-				bndno = (!rlvlno) ? 0 : (3 * (rlvlno - 1) +
-				  bandno + 1);
-				bnd = &bnds[bndno];
-
-				band->orient = bnd->orient;
-				band->stepsize = ccp->stepsizes[bndno];
-				band->analgain = JPC_NOMINALGAIN(ccp->qmfbid,
-				  tcomp->numrlvls - 1, rlvlno, band->orient);
-				band->absstepsize = jpc_calcabsstepsize(band->stepsize,
-				  cmpt->prec + band->analgain);
-				band->numbps = ccp->numguardbits +
-				  JPC_QCX_GETEXPN(band->stepsize) - 1;
-				band->roishift = (ccp->roishift + band->numbps >= JPC_PREC) ?
-				  (JPC_PREC - 1 - band->numbps) : ccp->roishift;
-				band->data = 0;
-				band->prcs = 0;
-				if (bnd->xstart == bnd->xend || bnd->ystart == bnd->yend) {
-					continue;
-				}
-				if (!(band->data = jas_seq2d_create(0, 0, 0, 0))) {
-					return -1;
-				}
-				jas_seq2d_bindsub(band->data, tcomp->data, bnd->locxstart, bnd->locystart, bnd->locxend, bnd->locyend);
-				jas_seq2d_setshift(band->data, bnd->xstart, bnd->ystart);
-
-				assert(rlvl->numprcs);
-
-				if (!(band->prcs = jas_malloc(rlvl->numprcs * sizeof(jpc_dec_prc_t)))) {
-					return -1;
-				}
+            rlvl->xstart = JPC_CEILDIVPOW2(tcomp->xstart,
+              tcomp->numrlvls - 1 - rlvlno);
+            rlvl->ystart = JPC_CEILDIVPOW2(tcomp->ystart,
+              tcomp->numrlvls - 1 - rlvlno);
+            rlvl->xend = JPC_CEILDIVPOW2(tcomp->xend,
+              tcomp->numrlvls - 1 - rlvlno);
+            rlvl->yend = JPC_CEILDIVPOW2(tcomp->yend,
+              tcomp->numrlvls - 1 - rlvlno);
+            rlvl->prcwidthexpn = ccp->prcwidthexpns[rlvlno];
+            rlvl->prcheightexpn = ccp->prcheightexpns[rlvlno];
+            tlprcxstart = JPC_FLOORDIVPOW2(rlvl->xstart,
+              rlvl->prcwidthexpn) << rlvl->prcwidthexpn;
+            tlprcystart = JPC_FLOORDIVPOW2(rlvl->ystart,
+              rlvl->prcheightexpn) << rlvl->prcheightexpn;
+            brprcxend = JPC_CEILDIVPOW2(rlvl->xend,
+              rlvl->prcwidthexpn) << rlvl->prcwidthexpn;
+            brprcyend = JPC_CEILDIVPOW2(rlvl->yend,
+              rlvl->prcheightexpn) << rlvl->prcheightexpn;
+            rlvl->numhprcs = (brprcxend - tlprcxstart) >>
+              rlvl->prcwidthexpn;
+            rlvl->numvprcs = (brprcyend - tlprcystart) >>
+              rlvl->prcheightexpn;
+            rlvl->numprcs = rlvl->numhprcs * rlvl->numvprcs;
+
+            if (rlvl->xstart >= rlvl->xend || rlvl->ystart >= rlvl->yend) {
+                rlvl->bands = 0;
+                rlvl->numprcs = 0;
+                rlvl->numhprcs = 0;
+                rlvl->numvprcs = 0;
+                continue;
+            }   
+            if (!rlvlno) {
+                tlcbgxstart = tlprcxstart;
+                tlcbgystart = tlprcystart;
+                brcbgxend = brprcxend;
+                brcbgyend = brprcyend;
+                rlvl->cbgwidthexpn = rlvl->prcwidthexpn;
+                rlvl->cbgheightexpn = rlvl->prcheightexpn;
+            } else {
+                tlcbgxstart = JPC_CEILDIVPOW2(tlprcxstart, 1);
+                tlcbgystart = JPC_CEILDIVPOW2(tlprcystart, 1);
+                brcbgxend = JPC_CEILDIVPOW2(brprcxend, 1);
+                brcbgyend = JPC_CEILDIVPOW2(brprcyend, 1);
+                rlvl->cbgwidthexpn = rlvl->prcwidthexpn - 1;
+                rlvl->cbgheightexpn = rlvl->prcheightexpn - 1;
+            }
+            rlvl->cblkwidthexpn = JAS_MIN(ccp->cblkwidthexpn,
+              rlvl->cbgwidthexpn);
+            rlvl->cblkheightexpn = JAS_MIN(ccp->cblkheightexpn,
+              rlvl->cbgheightexpn);
+
+            rlvl->numbands = (!rlvlno) ? 1 : 3;
+            if (!(rlvl->bands = jas_malloc(rlvl->numbands *
+              sizeof(jpc_dec_band_t)))) {
+                return -1;
+            }
+            for (bandno = 0, band = rlvl->bands;
+              bandno < rlvl->numbands; ++bandno, ++band) {
+                bndno = (!rlvlno) ? 0 : (3 * (rlvlno - 1) +
+                  bandno + 1);
+                bnd = &bnds[bndno];
+
+                band->orient = bnd->orient;
+                band->stepsize = ccp->stepsizes[bndno];
+                band->analgain = JPC_NOMINALGAIN(ccp->qmfbid,
+                  tcomp->numrlvls - 1, rlvlno, band->orient);
+                band->absstepsize = jpc_calcabsstepsize(band->stepsize,
+                  cmpt->prec + band->analgain);
+                band->numbps = ccp->numguardbits +
+                  JPC_QCX_GETEXPN(band->stepsize) - 1;
+                band->roishift = (ccp->roishift + band->numbps >= JPC_PREC) ?
+                  (JPC_PREC - 1 - band->numbps) : ccp->roishift;
+                band->data = 0;
+                band->prcs = 0;
+                if (bnd->xstart == bnd->xend || bnd->ystart == bnd->yend) {
+                    continue;
+                }
+                if (!(band->data = jas_seq2d_create(0, 0, 0, 0))) {
+                    return -1;
+                }
+                jas_seq2d_bindsub(band->data, tcomp->data, bnd->locxstart, bnd->locystart, bnd->locxend, bnd->locyend);
+                jas_seq2d_setshift(band->data, bnd->xstart, bnd->ystart);
+
+                assert(rlvl->numprcs);
+
+                if (!(band->prcs = jas_malloc(rlvl->numprcs * sizeof(jpc_dec_prc_t)))) {
+                    return -1;
+                }
 
 /************************************************/
-	cbgxstart = tlcbgxstart;
-	cbgystart = tlcbgystart;
-	for (prccnt = rlvl->numprcs, prc = band->prcs;
-	  prccnt > 0; --prccnt, ++prc) {
-		cbgxend = cbgxstart + (1 << rlvl->cbgwidthexpn);
-		cbgyend = cbgystart + (1 << rlvl->cbgheightexpn);
-		prc->xstart = JAS_MAX(cbgxstart, jas_seq2d_xstart(band->data));
-		prc->ystart = JAS_MAX(cbgystart, jas_seq2d_ystart(band->data));
-		prc->xend = JAS_MIN(cbgxend, jas_seq2d_xend(band->data));
-		prc->yend = JAS_MIN(cbgyend, jas_seq2d_yend(band->data));
-		if (prc->xend > prc->xstart && prc->yend > prc->ystart) {
-			tlcblkxstart = JPC_FLOORDIVPOW2(prc->xstart,
-			  rlvl->cblkwidthexpn) << rlvl->cblkwidthexpn;
-			tlcblkystart = JPC_FLOORDIVPOW2(prc->ystart,
-			  rlvl->cblkheightexpn) << rlvl->cblkheightexpn;
-			brcblkxend = JPC_CEILDIVPOW2U(prc->xend,
-			  rlvl->cblkwidthexpn) << rlvl->cblkwidthexpn;
-			brcblkyend = JPC_CEILDIVPOW2U(prc->yend,
-			  rlvl->cblkheightexpn) << rlvl->cblkheightexpn;
-			prc->numhcblks = (brcblkxend - tlcblkxstart) >>
-			  rlvl->cblkwidthexpn;
-			prc->numvcblks = (brcblkyend - tlcblkystart) >>
-			  rlvl->cblkheightexpn;
-			prc->numcblks = prc->numhcblks * prc->numvcblks;
-			assert(prc->numcblks > 0);
-
-			if (!(prc->incltagtree = jpc_tagtree_create(prc->numhcblks, prc->numvcblks))) {
-				return -1;
-			}
-			if (!(prc->numimsbstagtree = jpc_tagtree_create(prc->numhcblks, prc->numvcblks))) {
-				return -1;
-			}
-			if (!(prc->cblks = jas_malloc(prc->numcblks * sizeof(jpc_dec_cblk_t)))) {
-				return -1;
-			}
-
-			cblkxstart = cbgxstart;
-			cblkystart = cbgystart;
-			for (cblkcnt = prc->numcblks, cblk = prc->cblks; cblkcnt > 0;) {
-				cblkxend = cblkxstart + (1 << rlvl->cblkwidthexpn);
-				cblkyend = cblkystart + (1 << rlvl->cblkheightexpn);
-				tmpxstart = JAS_MAX(cblkxstart, prc->xstart);
-				tmpystart = JAS_MAX(cblkystart, prc->ystart);
-				tmpxend = JAS_MIN(cblkxend, prc->xend);
-				tmpyend = JAS_MIN(cblkyend, prc->yend);
-				if (tmpxend > tmpxstart && tmpyend > tmpystart) {
-					cblk->firstpassno = -1;
-					cblk->mqdec = 0;
-					cblk->nulldec = 0;
-					cblk->flags = 0;
-					cblk->numpasses = 0;
-					cblk->segs.head = 0;
-					cblk->segs.tail = 0;
-					cblk->curseg = 0;
-					cblk->numimsbs = 0;
-					cblk->numlenbits = 3;
-					cblk->flags = 0;
-					if (!(cblk->data = jas_seq2d_create(0, 0, 0, 0))) {
-						return -1;
-					}
-					jas_seq2d_bindsub(cblk->data, band->data, tmpxstart, tmpystart, tmpxend, tmpyend);
-					++cblk;
-					--cblkcnt;
-				}
-				cblkxstart += 1 << rlvl->cblkwidthexpn;
-				if (cblkxstart >= cbgxend) {
-					cblkxstart = cbgxstart;
-					cblkystart += 1 << rlvl->cblkheightexpn;
-				}
-			}
-
-		} else {
-			prc->cblks = 0;
-			prc->incltagtree = 0;
-			prc->numimsbstagtree = 0;
-		}
-		cbgxstart += 1 << rlvl->cbgwidthexpn;
-		if (cbgxstart >= brcbgxend) {
-			cbgxstart = tlcbgxstart;
-			cbgystart += 1 << rlvl->cbgheightexpn;
-		}
-
-	}
+    cbgxstart = tlcbgxstart;
+    cbgystart = tlcbgystart;
+    for (prccnt = rlvl->numprcs, prc = band->prcs;
+      prccnt > 0; --prccnt, ++prc) {
+        cbgxend = cbgxstart + (1 << rlvl->cbgwidthexpn);
+        cbgyend = cbgystart + (1 << rlvl->cbgheightexpn);
+        prc->xstart = JAS_MAX(cbgxstart, jas_seq2d_xstart(band->data));
+        prc->ystart = JAS_MAX(cbgystart, jas_seq2d_ystart(band->data));
+        prc->xend = JAS_MIN(cbgxend, jas_seq2d_xend(band->data));
+        prc->yend = JAS_MIN(cbgyend, jas_seq2d_yend(band->data));
+        if (prc->xend > prc->xstart && prc->yend > prc->ystart) {
+            tlcblkxstart = JPC_FLOORDIVPOW2(prc->xstart,
+              rlvl->cblkwidthexpn) << rlvl->cblkwidthexpn;
+            tlcblkystart = JPC_FLOORDIVPOW2(prc->ystart,
+              rlvl->cblkheightexpn) << rlvl->cblkheightexpn;
+            brcblkxend = JPC_CEILDIVPOW2U(prc->xend,
+              rlvl->cblkwidthexpn) << rlvl->cblkwidthexpn;
+            brcblkyend = JPC_CEILDIVPOW2U(prc->yend,
+              rlvl->cblkheightexpn) << rlvl->cblkheightexpn;
+            prc->numhcblks = (brcblkxend - tlcblkxstart) >>
+              rlvl->cblkwidthexpn;
+            prc->numvcblks = (brcblkyend - tlcblkystart) >>
+              rlvl->cblkheightexpn;
+            prc->numcblks = prc->numhcblks * prc->numvcblks;
+            assert(prc->numcblks > 0);
+
+            if (!(prc->incltagtree = jpc_tagtree_create(prc->numhcblks, prc->numvcblks))) {
+                return -1;
+            }
+            if (!(prc->numimsbstagtree = jpc_tagtree_create(prc->numhcblks, prc->numvcblks))) {
+                return -1;
+            }
+            if (!(prc->cblks = jas_malloc(prc->numcblks * sizeof(jpc_dec_cblk_t)))) {
+                return -1;
+            }
+
+            cblkxstart = cbgxstart;
+            cblkystart = cbgystart;
+            for (cblkcnt = prc->numcblks, cblk = prc->cblks; cblkcnt > 0;) {
+                cblkxend = cblkxstart + (1 << rlvl->cblkwidthexpn);
+                cblkyend = cblkystart + (1 << rlvl->cblkheightexpn);
+                tmpxstart = JAS_MAX(cblkxstart, prc->xstart);
+                tmpystart = JAS_MAX(cblkystart, prc->ystart);
+                tmpxend = JAS_MIN(cblkxend, prc->xend);
+                tmpyend = JAS_MIN(cblkyend, prc->yend);
+                if (tmpxend > tmpxstart && tmpyend > tmpystart) {
+                    cblk->firstpassno = -1;
+                    cblk->mqdec = 0;
+                    cblk->nulldec = 0;
+                    cblk->flags = 0;
+                    cblk->numpasses = 0;
+                    cblk->segs.head = 0;
+                    cblk->segs.tail = 0;
+                    cblk->curseg = 0;
+                    cblk->numimsbs = 0;
+                    cblk->numlenbits = 3;
+                    cblk->flags = 0;
+                    if (!(cblk->data = jas_seq2d_create(0, 0, 0, 0))) {
+                        return -1;
+                    }
+                    jas_seq2d_bindsub(cblk->data, band->data, tmpxstart, tmpystart, tmpxend, tmpyend);
+                    ++cblk;
+                    --cblkcnt;
+                }
+                cblkxstart += 1 << rlvl->cblkwidthexpn;
+                if (cblkxstart >= cbgxend) {
+                    cblkxstart = cbgxstart;
+                    cblkystart += 1 << rlvl->cblkheightexpn;
+                }
+            }
+
+        } else {
+            prc->cblks = 0;
+            prc->incltagtree = 0;
+            prc->numimsbstagtree = 0;
+        }
+        cbgxstart += 1 << rlvl->cbgwidthexpn;
+        if (cbgxstart >= brcbgxend) {
+            cbgxstart = tlcbgxstart;
+            cbgystart += 1 << rlvl->cbgheightexpn;
+        }
+
+    }
 /********************************************/
-			}
-		}
-	}
+            }
+        }
+    }
 
 if (!(tile->pi = jpc_dec_pi_create(dec, tile)))
 {
-	return -1;
+    return -1;
 }
 
-	for (pchgno = 0; pchgno < jpc_pchglist_numpchgs(tile->cp->pchglist);
-	  ++pchgno) {
-		pchg = jpc_pchg_copy(jpc_pchglist_get(tile->cp->pchglist, pchgno));
-		assert(pchg);
-		jpc_pi_addpchg(tile->pi, pchg);
-	}
-	jpc_pi_init(tile->pi);
+    for (pchgno = 0; pchgno < jpc_pchglist_numpchgs(tile->cp->pchglist);
+      ++pchgno) {
+        pchg = jpc_pchg_copy(jpc_pchglist_get(tile->cp->pchglist, pchgno));
+        assert(pchg);
+        jpc_pi_addpchg(tile->pi, pchg);
+    }
+    jpc_pi_init(tile->pi);
 
-	return 0;
+    return 0;
 }
 
 static int jpc_dec_tilefini(jpc_dec_t *dec, jpc_dec_tile_t *tile)
 {
-	jpc_dec_tcomp_t *tcomp;
-	int compno;
-	int bandno;
-	int rlvlno;
-	jpc_dec_band_t *band;
-	jpc_dec_rlvl_t *rlvl;
-	int prcno;
-	jpc_dec_prc_t *prc;
-	jpc_dec_seg_t *seg;
-	jpc_dec_cblk_t *cblk;
-	int cblkno;
+    jpc_dec_tcomp_t *tcomp;
+    int compno;
+    int bandno;
+    int rlvlno;
+    jpc_dec_band_t *band;
+    jpc_dec_rlvl_t *rlvl;
+    int prcno;
+    jpc_dec_prc_t *prc;
+    jpc_dec_seg_t *seg;
+    jpc_dec_cblk_t *cblk;
+    int cblkno;
 
 if (tile->tcomps) {
 
-	for (compno = 0, tcomp = tile->tcomps; compno < dec->numcomps;
-	  ++compno, ++tcomp) {
-		for (rlvlno = 0, rlvl = tcomp->rlvls; rlvlno < tcomp->numrlvls;
-		  ++rlvlno, ++rlvl) {
+    for (compno = 0, tcomp = tile->tcomps; compno < dec->numcomps;
+      ++compno, ++tcomp) {
+        for (rlvlno = 0, rlvl = tcomp->rlvls; rlvlno < tcomp->numrlvls;
+          ++rlvlno, ++rlvl) {
 if (!rlvl->bands) {
-	continue;
+    continue;
 }
-			for (bandno = 0, band = rlvl->bands; bandno < rlvl->numbands; ++bandno, ++band) {
+            for (bandno = 0, band = rlvl->bands; bandno < rlvl->numbands; ++bandno, ++band) {
 if (band->prcs) {
-				for (prcno = 0, prc = band->prcs; prcno <
-				  rlvl->numprcs; ++prcno, ++prc) {
+                for (prcno = 0, prc = band->prcs; prcno <
+                  rlvl->numprcs; ++prcno, ++prc) {
 if (!prc->cblks) {
-	continue;
-}
-					for (cblkno = 0, cblk = prc->cblks; cblkno < prc->numcblks; ++cblkno, ++cblk) {
-
-	while (cblk->segs.head) {
-		seg = cblk->segs.head;
-		jpc_seglist_remove(&cblk->segs, seg);
-		jpc_seg_destroy(seg);
-	}
-	jas_matrix_destroy(cblk->data);
-	if (cblk->mqdec) {
-		jpc_mqdec_destroy(cblk->mqdec);
-	}
-	if (cblk->nulldec) {
-		jpc_bitstream_close(cblk->nulldec);
-	}
-	if (cblk->flags) {
-		jas_matrix_destroy(cblk->flags);
-	}
-					}
-					if (prc->incltagtree) {
-						jpc_tagtree_destroy(prc->incltagtree);
-					}
-					if (prc->numimsbstagtree) {
-						jpc_tagtree_destroy(prc->numimsbstagtree);
-					}
-					if (prc->cblks) {
-						jas_free(prc->cblks);
-					}
-				}
-}
-				if (band->data) {
-					jas_matrix_destroy(band->data);
-				}
-				if (band->prcs) {
-					jas_free(band->prcs);
-				}
-			}
-			if (rlvl->bands) {
-				jas_free(rlvl->bands);
-			}
-		}
-		if (tcomp->rlvls) {
-			jas_free(tcomp->rlvls);
-		}
-		if (tcomp->data) {
-			jas_matrix_destroy(tcomp->data);
-		}
-		if (tcomp->tsfb) {
-			jpc_tsfb_destroy(tcomp->tsfb);
-		}
-	}
-}
-	if (tile->cp) {
-		jpc_dec_cp_destroy(tile->cp);
-		tile->cp = 0;
-	}
-	if (tile->tcomps) {
-		jas_free(tile->tcomps);
-		tile->tcomps = 0;
-	}
-	if (tile->pi) {
-		jpc_pi_destroy(tile->pi);
-		tile->pi = 0;
-	}
-	if (tile->pkthdrstream) {
-		jas_stream_close(tile->pkthdrstream);
-		tile->pkthdrstream = 0;
-	}
-	if (tile->pptstab) {
-		jpc_ppxstab_destroy(tile->pptstab);
-		tile->pptstab = 0;
-	}
-
-	tile->state = JPC_TILE_DONE;
-
-	return 0;
+    continue;
+}
+                    for (cblkno = 0, cblk = prc->cblks; cblkno < prc->numcblks; ++cblkno, ++cblk) {
+
+    while (cblk->segs.head) {
+        seg = cblk->segs.head;
+        jpc_seglist_remove(&cblk->segs, seg);
+        jpc_seg_destroy(seg);
+    }
+    jas_matrix_destroy(cblk->data);
+    if (cblk->mqdec) {
+        jpc_mqdec_destroy(cblk->mqdec);
+    }
+    if (cblk->nulldec) {
+        jpc_bitstream_close(cblk->nulldec);
+    }
+    if (cblk->flags) {
+        jas_matrix_destroy(cblk->flags);
+    }
+                    }
+                    if (prc->incltagtree) {
+                        jpc_tagtree_destroy(prc->incltagtree);
+                    }
+                    if (prc->numimsbstagtree) {
+                        jpc_tagtree_destroy(prc->numimsbstagtree);
+                    }
+                    if (prc->cblks) {
+                        jas_free(prc->cblks);
+                    }
+                }
+}
+                if (band->data) {
+                    jas_matrix_destroy(band->data);
+                }
+                if (band->prcs) {
+                    jas_free(band->prcs);
+                }
+            }
+            if (rlvl->bands) {
+                jas_free(rlvl->bands);
+            }
+        }
+        if (tcomp->rlvls) {
+            jas_free(tcomp->rlvls);
+        }
+        if (tcomp->data) {
+            jas_matrix_destroy(tcomp->data);
+        }
+        if (tcomp->tsfb) {
+            jpc_tsfb_destroy(tcomp->tsfb);
+        }
+    }
+}
+    if (tile->cp) {
+        jpc_dec_cp_destroy(tile->cp);
+        tile->cp = 0;
+    }
+    if (tile->tcomps) {
+        jas_free(tile->tcomps);
+        tile->tcomps = 0;
+    }
+    if (tile->pi) {
+        jpc_pi_destroy(tile->pi);
+        tile->pi = 0;
+    }
+    if (tile->pkthdrstream) {
+        jas_stream_close(tile->pkthdrstream);
+        tile->pkthdrstream = 0;
+    }
+    if (tile->pptstab) {
+        jpc_ppxstab_destroy(tile->pptstab);
+        tile->pptstab = 0;
+    }
+
+    tile->state = JPC_TILE_DONE;
+
+    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);
-				}
-
-			}
-		}
-	}
-
-	/* 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;
+    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);
+                }
+
+            }
+        }
+    }
+
+    /* 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;
-			}
-		}
-		jpc_dec_tilefini(dec, tile);
-	}
+    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;
+            }
+        }
+        jpc_dec_tilefini(dec, tile);
+    }
 
-	/* We are done processing the code stream. */
-	dec->state = JPC_MT;
+    /* We are done processing the code stream. */
+    dec->state = JPC_MT;
 
-	return 1;
+    return 1;
 }
 
 static int jpc_dec_process_siz(jpc_dec_t *dec, jpc_ms_t *ms)
 {
-	jpc_siz_t *siz = &ms->parms.siz;
-	uint_fast16_t compno;
-	uint_fast32_t tileno;
-	jpc_dec_tile_t *tile;
-	jpc_dec_tcomp_t *tcomp;
-	uint_fast32_t htileno;
-	uint_fast32_t vtileno;
-	jpc_dec_cmpt_t *cmpt;
-
-	dec->xstart = siz->xoff;
-	dec->ystart = siz->yoff;
-	dec->xend = siz->width;
-	dec->yend = siz->height;
-	dec->tilewidth = siz->tilewidth;
-	dec->tileheight = siz->tileheight;
-	dec->tilexoff = siz->tilexoff;
-	dec->tileyoff = siz->tileyoff;
-	dec->numcomps = siz->numcomps;
-	if (!(dec->cp = jpc_dec_cp_create(dec->numcomps))) {
-		return -1;
-	}
-
-	if (!(dec->cmpts = jas_malloc(dec->numcomps * sizeof(jpc_dec_cmpt_t)))) {
-		return -1;
-	}
-
-	for (compno = 0, cmpt = dec->cmpts; compno < dec->numcomps; ++compno,
-	  ++cmpt) {
-		cmpt->prec = siz->comps[compno].prec;
-		cmpt->sgnd = siz->comps[compno].sgnd;
-		cmpt->hstep = siz->comps[compno].hsamp;
-		cmpt->vstep = siz->comps[compno].vsamp;
-		cmpt->width = JPC_CEILDIV(dec->xend, cmpt->hstep) -
-		  JPC_CEILDIV(dec->xstart, cmpt->hstep);
-		cmpt->height = JPC_CEILDIV(dec->yend, cmpt->vstep) -
-		  JPC_CEILDIV(dec->ystart, cmpt->vstep);
-		cmpt->hsubstep = 0;
-		cmpt->vsubstep = 0;
-	}
-
-	dec->image = 0;
-
-	dec->numhtiles = JPC_CEILDIV(dec->xend - dec->tilexoff, dec->tilewidth);
-	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;
-	}
-
-	for (tileno = 0, tile = dec->tiles; tileno < dec->numtiles; ++tileno,
-	  ++tile) {
-		htileno = tileno % dec->numhtiles;
-		vtileno = tileno / dec->numhtiles;
-		tile->realmode = 0;
-		tile->state = JPC_TILE_INIT;
-		tile->xstart = JAS_MAX(dec->tilexoff + htileno * dec->tilewidth,
-		  dec->xstart);
-		tile->ystart = JAS_MAX(dec->tileyoff + vtileno * dec->tileheight,
-		  dec->ystart);
-		tile->xend = JAS_MIN(dec->tilexoff + (htileno + 1) *
-		  dec->tilewidth, dec->xend);
-		tile->yend = JAS_MIN(dec->tileyoff + (vtileno + 1) *
-		  dec->tileheight, dec->yend);
-		tile->numparts = 0;
-		tile->partno = 0;
-		tile->pkthdrstream = 0;
-		tile->pkthdrstreampos = 0;
-		tile->pptstab = 0;
-		tile->cp = 0;
-		if (!(tile->tcomps = jas_malloc(dec->numcomps *
-		  sizeof(jpc_dec_tcomp_t)))) {
-			return -1;
-		}
-		for (compno = 0, cmpt = dec->cmpts, tcomp = tile->tcomps;
-		  compno < dec->numcomps; ++compno, ++cmpt, ++tcomp) {
-			tcomp->rlvls = 0;
-			tcomp->data = 0;
-			tcomp->xstart = JPC_CEILDIV(tile->xstart, cmpt->hstep);
-			tcomp->ystart = JPC_CEILDIV(tile->ystart, cmpt->vstep);
-			tcomp->xend = JPC_CEILDIV(tile->xend, cmpt->hstep);
-			tcomp->yend = JPC_CEILDIV(tile->yend, cmpt->vstep);
-			tcomp->tsfb = 0;
-		}
-	}
-
-	dec->pkthdrstreams = 0;
-
-	/* We should expect to encounter other main header marker segments
-	  or an SOT marker segment next. */
-	dec->state = JPC_MH;
-
-	return 0;
+    jpc_siz_t *siz = &ms->parms.siz;
+    uint_fast16_t compno;
+    uint_fast32_t tileno;
+    jpc_dec_tile_t *tile;
+    jpc_dec_tcomp_t *tcomp;
+    uint_fast32_t htileno;
+    uint_fast32_t vtileno;
+    jpc_dec_cmpt_t *cmpt;
+
+    dec->xstart = siz->xoff;
+    dec->ystart = siz->yoff;
+    dec->xend = siz->width;
+    dec->yend = siz->height;
+    dec->tilewidth = siz->tilewidth;
+    dec->tileheight = siz->tileheight;
+    dec->tilexoff = siz->tilexoff;
+    dec->tileyoff = siz->tileyoff;
+    dec->numcomps = siz->numcomps;
+    if (!(dec->cp = jpc_dec_cp_create(dec->numcomps))) {
+        return -1;
+    }
+
+    if (!(dec->cmpts = jas_malloc(dec->numcomps * sizeof(jpc_dec_cmpt_t)))) {
+        return -1;
+    }
+
+    for (compno = 0, cmpt = dec->cmpts; compno < dec->numcomps; ++compno,
+      ++cmpt) {
+        cmpt->prec = siz->comps[compno].prec;
+        cmpt->sgnd = siz->comps[compno].sgnd;
+        cmpt->hstep = siz->comps[compno].hsamp;
+        cmpt->vstep = siz->comps[compno].vsamp;
+        cmpt->width = JPC_CEILDIV(dec->xend, cmpt->hstep) -
+          JPC_CEILDIV(dec->xstart, cmpt->hstep);
+        cmpt->height = JPC_CEILDIV(dec->yend, cmpt->vstep) -
+          JPC_CEILDIV(dec->ystart, cmpt->vstep);
+        cmpt->hsubstep = 0;
+        cmpt->vsubstep = 0;
+    }
+
+    dec->image = 0;
+
+    dec->numhtiles = JPC_CEILDIV(dec->xend - dec->tilexoff, dec->tilewidth);
+    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;
+    }
+
+    for (tileno = 0, tile = dec->tiles; tileno < dec->numtiles; ++tileno,
+      ++tile) {
+        htileno = tileno % dec->numhtiles;
+        vtileno = tileno / dec->numhtiles;
+        tile->realmode = 0;
+        tile->state = JPC_TILE_INIT;
+        tile->xstart = JAS_MAX(dec->tilexoff + htileno * dec->tilewidth,
+          dec->xstart);
+        tile->ystart = JAS_MAX(dec->tileyoff + vtileno * dec->tileheight,
+          dec->ystart);
+        tile->xend = JAS_MIN(dec->tilexoff + (htileno + 1) *
+          dec->tilewidth, dec->xend);
+        tile->yend = JAS_MIN(dec->tileyoff + (vtileno + 1) *
+          dec->tileheight, dec->yend);
+        tile->numparts = 0;
+        tile->partno = 0;
+        tile->pkthdrstream = 0;
+        tile->pkthdrstreampos = 0;
+        tile->pptstab = 0;
+        tile->cp = 0;
+        if (!(tile->tcomps = jas_malloc(dec->numcomps *
+          sizeof(jpc_dec_tcomp_t)))) {
+            return -1;
+        }
+        for (compno = 0, cmpt = dec->cmpts, tcomp = tile->tcomps;
+          compno < dec->numcomps; ++compno, ++cmpt, ++tcomp) {
+            tcomp->rlvls = 0;
+            tcomp->data = 0;
+            tcomp->xstart = JPC_CEILDIV(tile->xstart, cmpt->hstep);
+            tcomp->ystart = JPC_CEILDIV(tile->ystart, cmpt->vstep);
+            tcomp->xend = JPC_CEILDIV(tile->xend, cmpt->hstep);
+            tcomp->yend = JPC_CEILDIV(tile->yend, cmpt->vstep);
+            tcomp->tsfb = 0;
+        }
+    }
+
+    dec->pkthdrstreams = 0;
+
+    /* We should expect to encounter other main header marker segments
+      or an SOT marker segment next. */
+    dec->state = JPC_MH;
+
+    return 0;
 }
 
 static int jpc_dec_process_cod(jpc_dec_t *dec, jpc_ms_t *ms)
 {
-	jpc_cod_t *cod = &ms->parms.cod;
-	jpc_dec_tile_t *tile;
-
-	switch (dec->state) {
-	case JPC_MH:
-		jpc_dec_cp_setfromcod(dec->cp, cod);
-		break;
-	case JPC_TPH:
-		if (!(tile = dec->curtile)) {
-			return -1;
-		}
-		if (tile->partno != 0) {
-			return -1;
-		}
-		jpc_dec_cp_setfromcod(tile->cp, cod);
-		break;
-	}
-	return 0;
+    jpc_cod_t *cod = &ms->parms.cod;
+    jpc_dec_tile_t *tile;
+
+    switch (dec->state) {
+    case JPC_MH:
+        jpc_dec_cp_setfromcod(dec->cp, cod);
+        break;
+    case JPC_TPH:
+        if (!(tile = dec->curtile)) {
+            return -1;
+        }
+        if (tile->partno != 0) {
+            return -1;
+        }
+        jpc_dec_cp_setfromcod(tile->cp, cod);
+        break;
+    }
+    return 0;
 }
 
 static int jpc_dec_process_coc(jpc_dec_t *dec, jpc_ms_t *ms)
 {
-	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;
-	}
-	switch (dec->state) {
-	case JPC_MH:
-		jpc_dec_cp_setfromcoc(dec->cp, coc);
-		break;
-	case JPC_TPH:
-		if (!(tile = dec->curtile)) {
-			return -1;
-		}
-		if (tile->partno > 0) {
-			return -1;
-		}
-		jpc_dec_cp_setfromcoc(tile->cp, coc);
-		break;
-	}
-	return 0;
+    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;
+    }
+    switch (dec->state) {
+    case JPC_MH:
+        jpc_dec_cp_setfromcoc(dec->cp, coc);
+        break;
+    case JPC_TPH:
+        if (!(tile = dec->curtile)) {
+            return -1;
+        }
+        if (tile->partno > 0) {
+            return -1;
+        }
+        jpc_dec_cp_setfromcoc(tile->cp, coc);
+        break;
+    }
+    return 0;
 }
 
 static int jpc_dec_process_rgn(jpc_dec_t *dec, jpc_ms_t *ms)
 {
-	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;
-	}
-	switch (dec->state) {
-	case JPC_MH:
-		jpc_dec_cp_setfromrgn(dec->cp, rgn);
-		break;
-	case JPC_TPH:
-		if (!(tile = dec->curtile)) {
-			return -1;
-		}
-		if (tile->partno > 0) {
-			return -1;
-		}
-		jpc_dec_cp_setfromrgn(tile->cp, rgn);
-		break;
-	}
-
-	return 0;
+    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;
+    }
+    switch (dec->state) {
+    case JPC_MH:
+        jpc_dec_cp_setfromrgn(dec->cp, rgn);
+        break;
+    case JPC_TPH:
+        if (!(tile = dec->curtile)) {
+            return -1;
+        }
+        if (tile->partno > 0) {
+            return -1;
+        }
+        jpc_dec_cp_setfromrgn(tile->cp, rgn);
+        break;
+    }
+
+    return 0;
 }
 
 static int jpc_dec_process_qcd(jpc_dec_t *dec, jpc_ms_t *ms)
 {
-	jpc_qcd_t *qcd = &ms->parms.qcd;
-	jpc_dec_tile_t *tile;
-
-	switch (dec->state) {
-	case JPC_MH:
-		jpc_dec_cp_setfromqcd(dec->cp, qcd);
-		break;
-	case JPC_TPH:
-		if (!(tile = dec->curtile)) {
-			return -1;
-		}
-		if (tile->partno > 0) {
-			return -1;
-		}
-		jpc_dec_cp_setfromqcd(tile->cp, qcd);
-		break;
-	}
-	return 0;
+    jpc_qcd_t *qcd = &ms->parms.qcd;
+    jpc_dec_tile_t *tile;
+
+    switch (dec->state) {
+    case JPC_MH:
+        jpc_dec_cp_setfromqcd(dec->cp, qcd);
+        break;
+    case JPC_TPH:
+        if (!(tile = dec->curtile)) {
+            return -1;
+        }
+        if (tile->partno > 0) {
+            return -1;
+        }
+        jpc_dec_cp_setfromqcd(tile->cp, qcd);
+        break;
+    }
+    return 0;
 }
 
 static int jpc_dec_process_qcc(jpc_dec_t *dec, jpc_ms_t *ms)
 {
-	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;
-	}
-	switch (dec->state) {
-	case JPC_MH:
-		jpc_dec_cp_setfromqcc(dec->cp, qcc);
-		break;
-	case JPC_TPH:
-		if (!(tile = dec->curtile)) {
-			return -1;
-		}
-		if (tile->partno > 0) {
-			return -1;
-		}
-		jpc_dec_cp_setfromqcc(tile->cp, qcc);
-		break;
-	}
-	return 0;
+    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;
+    }
+    switch (dec->state) {
+    case JPC_MH:
+        jpc_dec_cp_setfromqcc(dec->cp, qcc);
+        break;
+    case JPC_TPH:
+        if (!(tile = dec->curtile)) {
+            return -1;
+        }
+        if (tile->partno > 0) {
+            return -1;
+        }
+        jpc_dec_cp_setfromqcc(tile->cp, qcc);
+        break;
+    }
+    return 0;
 }
 
 static int jpc_dec_process_poc(jpc_dec_t *dec, jpc_ms_t *ms)
 {
-	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;
-		}
-		break;
-	case JPC_TPH:
-		if (!(tile = dec->curtile)) {
-			return -1;
-		}
-		if (!tile->partno) {
-			if (jpc_dec_cp_setfrompoc(tile->cp, poc, (!tile->partno))) {
-				return -1;
-			}
-		} else {
-			jpc_pi_addpchgfrompoc(tile->pi, poc);
-		}
-		break;
-	}
-	return 0;
+    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;
+        }
+        break;
+    case JPC_TPH:
+        if (!(tile = dec->curtile)) {
+            return -1;
+        }
+        if (!tile->partno) {
+            if (jpc_dec_cp_setfrompoc(tile->cp, poc, (!tile->partno))) {
+                return -1;
+            }
+        } else {
+            jpc_pi_addpchgfrompoc(tile->pi, poc);
+        }
+        break;
+    }
+    return 0;
 }
 
 static int jpc_dec_process_ppm(jpc_dec_t *dec, jpc_ms_t *ms)
 {
-	jpc_ppm_t *ppm = &ms->parms.ppm;
-	jpc_ppxstabent_t *ppmstabent;
+    jpc_ppm_t *ppm = &ms->parms.ppm;
+    jpc_ppxstabent_t *ppmstabent;
 
-	if (!dec->ppmstab) {
-		if (!(dec->ppmstab = jpc_ppxstab_create())) {
-			return -1;
-		}
-	}
+    if (!dec->ppmstab) {
+        if (!(dec->ppmstab = jpc_ppxstab_create())) {
+            return -1;
+        }
+    }
 
-	if (!(ppmstabent = jpc_ppxstabent_create())) {
-		return -1;
-	}
-	ppmstabent->ind = ppm->ind;
-	ppmstabent->data = ppm->data;
-	ppm->data = 0;
-	ppmstabent->len = ppm->len;
-	if (jpc_ppxstab_insert(dec->ppmstab, ppmstabent)) {
-		return -1;
-	}
-	return 0;
+    if (!(ppmstabent = jpc_ppxstabent_create())) {
+        return -1;
+    }
+    ppmstabent->ind = ppm->ind;
+    ppmstabent->data = ppm->data;
+    ppm->data = 0;
+    ppmstabent->len = ppm->len;
+    if (jpc_ppxstab_insert(dec->ppmstab, ppmstabent)) {
+        return -1;
+    }
+    return 0;
 }
 
 static int jpc_dec_process_ppt(jpc_dec_t *dec, jpc_ms_t *ms)
 {
-	jpc_ppt_t *ppt = &ms->parms.ppt;
-	jpc_dec_tile_t *tile;
-	jpc_ppxstabent_t *pptstabent;
-
-	tile = dec->curtile;
-	if (!tile->pptstab) {
-		if (!(tile->pptstab = jpc_ppxstab_create())) {
-			return -1;
-		}
-	}
-	if (!(pptstabent = jpc_ppxstabent_create())) {
-		return -1;
-	}
-	pptstabent->ind = ppt->ind;
-	pptstabent->data = ppt->data;
-	ppt->data = 0;
-	pptstabent->len = ppt->len;
-	if (jpc_ppxstab_insert(tile->pptstab, pptstabent)) {
-		return -1;
-	}
-	return 0;
+    jpc_ppt_t *ppt = &ms->parms.ppt;
+    jpc_dec_tile_t *tile;
+    jpc_ppxstabent_t *pptstabent;
+
+    tile = dec->curtile;
+    if (!tile->pptstab) {
+        if (!(tile->pptstab = jpc_ppxstab_create())) {
+            return -1;
+        }
+    }
+    if (!(pptstabent = jpc_ppxstabent_create())) {
+        return -1;
+    }
+    pptstabent->ind = ppt->ind;
+    pptstabent->data = ppt->data;
+    ppt->data = 0;
+    pptstabent->len = ppt->len;
+    if (jpc_ppxstab_insert(tile->pptstab, pptstabent)) {
+        return -1;
+    }
+    return 0;
 }
 
 static int jpc_dec_process_com(jpc_dec_t *dec, jpc_ms_t *ms)
 {
-	return 0;
+    return 0;
 }
 
 static int jpc_dec_process_unk(jpc_dec_t *dec, jpc_ms_t *ms)
 {
-	fprintf(stderr, "warning: ignoring unknown marker segment\n");
-	jpc_ms_dump(ms, stderr);
-	return 0;
+    fprintf(stderr, "warning: ignoring unknown marker segment\n");
+    jpc_ms_dump(ms, stderr);
+    return 0;
 }
 
 /******************************************************************************\
@@ -1512,426 +1514,426 @@ static int jpc_dec_process_unk(jpc_dec_t *dec, jpc_ms_t *ms)
 
 static jpc_dec_cp_t *jpc_dec_cp_create(uint_fast16_t numcomps)
 {
-	jpc_dec_cp_t *cp;
-	jpc_dec_ccp_t *ccp;
-	int compno;
-
-	if (!(cp = jas_malloc(sizeof(jpc_dec_cp_t)))) {
-		return 0;
-	}
-	cp->flags = 0;
-	cp->numcomps = numcomps;
-	cp->prgord = 0;
-	cp->numlyrs = 0;
-	cp->mctid = 0;
-	cp->csty = 0;
-	if (!(cp->ccps = jas_malloc(cp->numcomps * sizeof(jpc_dec_ccp_t)))) {
-		return 0;
-	}
-	if (!(cp->pchglist = jpc_pchglist_create())) {
-		jas_free(cp->ccps);
-		return 0;
-	}
-	for (compno = 0, ccp = cp->ccps; compno < cp->numcomps;
-	  ++compno, ++ccp) {
-		ccp->flags = 0;
-		ccp->numrlvls = 0;
-		ccp->cblkwidthexpn = 0;
-		ccp->cblkheightexpn = 0;
-		ccp->qmfbid = 0;
-		ccp->numstepsizes = 0;
-		ccp->numguardbits = 0;
-		ccp->roishift = 0;
-		ccp->cblkctx = 0;
-	}
-	return cp;
+    jpc_dec_cp_t *cp;
+    jpc_dec_ccp_t *ccp;
+    int compno;
+
+    if (!(cp = jas_malloc(sizeof(jpc_dec_cp_t)))) {
+        return 0;
+    }
+    cp->flags = 0;
+    cp->numcomps = numcomps;
+    cp->prgord = 0;
+    cp->numlyrs = 0;
+    cp->mctid = 0;
+    cp->csty = 0;
+    if (!(cp->ccps = jas_malloc(cp->numcomps * sizeof(jpc_dec_ccp_t)))) {
+        return 0;
+    }
+    if (!(cp->pchglist = jpc_pchglist_create())) {
+        jas_free(cp->ccps);
+        return 0;
+    }
+    for (compno = 0, ccp = cp->ccps; compno < cp->numcomps;
+      ++compno, ++ccp) {
+        ccp->flags = 0;
+        ccp->numrlvls = 0;
+        ccp->cblkwidthexpn = 0;
+        ccp->cblkheightexpn = 0;
+        ccp->qmfbid = 0;
+        ccp->numstepsizes = 0;
+        ccp->numguardbits = 0;
+        ccp->roishift = 0;
+        ccp->cblkctx = 0;
+    }
+    return cp;
 }
 
 static jpc_dec_cp_t *jpc_dec_cp_copy(jpc_dec_cp_t *cp)
 {
-	jpc_dec_cp_t *newcp;
-	jpc_dec_ccp_t *newccp;
-	jpc_dec_ccp_t *ccp;
-	int compno;
-
-	if (!(newcp = jpc_dec_cp_create(cp->numcomps))) {
-		return 0;
-	}
-	newcp->flags = cp->flags;
-	newcp->prgord = cp->prgord;
-	newcp->numlyrs = cp->numlyrs;
-	newcp->mctid = cp->mctid;
-	newcp->csty = cp->csty;
-	jpc_pchglist_destroy(newcp->pchglist);
-	newcp->pchglist = 0;
-	if (!(newcp->pchglist = jpc_pchglist_copy(cp->pchglist))) {
-		jas_free(newcp);
-		return 0;
-	}
-	for (compno = 0, newccp = newcp->ccps, ccp = cp->ccps;
-	  compno < cp->numcomps;
-	  ++compno, ++newccp, ++ccp) {
-		*newccp = *ccp;
-	}
-	return newcp;
+    jpc_dec_cp_t *newcp;
+    jpc_dec_ccp_t *newccp;
+    jpc_dec_ccp_t *ccp;
+    int compno;
+
+    if (!(newcp = jpc_dec_cp_create(cp->numcomps))) {
+        return 0;
+    }
+    newcp->flags = cp->flags;
+    newcp->prgord = cp->prgord;
+    newcp->numlyrs = cp->numlyrs;
+    newcp->mctid = cp->mctid;
+    newcp->csty = cp->csty;
+    jpc_pchglist_destroy(newcp->pchglist);
+    newcp->pchglist = 0;
+    if (!(newcp->pchglist = jpc_pchglist_copy(cp->pchglist))) {
+        jas_free(newcp);
+        return 0;
+    }
+    for (compno = 0, newccp = newcp->ccps, ccp = cp->ccps;
+      compno < cp->numcomps;
+      ++compno, ++newccp, ++ccp) {
+        *newccp = *ccp;
+    }
+    return newcp;
 }
 
 static void jpc_dec_cp_resetflags(jpc_dec_cp_t *cp)
 {
-	int compno;
-	jpc_dec_ccp_t *ccp;
-	cp->flags &= (JPC_CSET | JPC_QSET);
-	for (compno = 0, ccp = cp->ccps; compno < cp->numcomps;
-	  ++compno, ++ccp) {
-		ccp->flags = 0;
-	}
+    int compno;
+    jpc_dec_ccp_t *ccp;
+    cp->flags &= (JPC_CSET | JPC_QSET);
+    for (compno = 0, ccp = cp->ccps; compno < cp->numcomps;
+      ++compno, ++ccp) {
+        ccp->flags = 0;
+    }
 }
 
 static void jpc_dec_cp_destroy(jpc_dec_cp_t *cp)
 {
-	if (cp->ccps) {
-		jas_free(cp->ccps);
-	}
-	if (cp->pchglist) {
-		jpc_pchglist_destroy(cp->pchglist);
-	}
-	jas_free(cp);
+    if (cp->ccps) {
+        jas_free(cp->ccps);
+    }
+    if (cp->pchglist) {
+        jpc_pchglist_destroy(cp->pchglist);
+    }
+    jas_free(cp);
 }
 
 static int jpc_dec_cp_isvalid(jpc_dec_cp_t *cp)
 {
-	uint_fast16_t compcnt;
-	jpc_dec_ccp_t *ccp;
+    uint_fast16_t compcnt;
+    jpc_dec_ccp_t *ccp;
 
-	if (!(cp->flags & JPC_CSET) || !(cp->flags & JPC_QSET)) {
-		return 0;
-	}
-	for (compcnt = cp->numcomps, ccp = cp->ccps; compcnt > 0; --compcnt,
-	  ++ccp) {
-		/* Is there enough step sizes for the number of bands? */
-		if ((ccp->qsty != JPC_QCX_SIQNT && ccp->numstepsizes < 3 *
-		  ccp->numrlvls - 2) || (ccp->qsty == JPC_QCX_SIQNT &&
-		  ccp->numstepsizes != 1)) {
-			return 0;
-		}
-	}
-	return 1;
+    if (!(cp->flags & JPC_CSET) || !(cp->flags & JPC_QSET)) {
+        return 0;
+    }
+    for (compcnt = cp->numcomps, ccp = cp->ccps; compcnt > 0; --compcnt,
+      ++ccp) {
+        /* Is there enough step sizes for the number of bands? */
+        if ((ccp->qsty != JPC_QCX_SIQNT && ccp->numstepsizes < 3 *
+          ccp->numrlvls - 2) || (ccp->qsty == JPC_QCX_SIQNT &&
+          ccp->numstepsizes != 1)) {
+            return 0;
+        }
+    }
+    return 1;
 }
 
 static void calcstepsizes(uint_fast16_t refstepsize, int numrlvls,
   uint_fast16_t *stepsizes)
 {
-	int bandno;
-	int numbands;
-	uint_fast16_t expn;
-	uint_fast16_t mant;
-	expn = JPC_QCX_GETEXPN(refstepsize);
-	mant = JPC_QCX_GETMANT(refstepsize);
-	numbands = 3 * numrlvls - 2;
-	for (bandno = 0; bandno < numbands; ++bandno) {
-		stepsizes[bandno] = JPC_QCX_MANT(mant) | JPC_QCX_EXPN(expn +
-		  (numrlvls - 1) - (numrlvls - 1 - ((bandno > 0) ? ((bandno + 2) / 3) : (0))));
-	}
+    int bandno;
+    int numbands;
+    uint_fast16_t expn;
+    uint_fast16_t mant;
+    expn = JPC_QCX_GETEXPN(refstepsize);
+    mant = JPC_QCX_GETMANT(refstepsize);
+    numbands = 3 * numrlvls - 2;
+    for (bandno = 0; bandno < numbands; ++bandno) {
+        stepsizes[bandno] = JPC_QCX_MANT(mant) | JPC_QCX_EXPN(expn +
+          (numrlvls - 1) - (numrlvls - 1 - ((bandno > 0) ? ((bandno + 2) / 3) : (0))));
+    }
 }
 
 static int jpc_dec_cp_prepare(jpc_dec_cp_t *cp)
 {
-	jpc_dec_ccp_t *ccp;
-	int compno;
-	int i;
-	for (compno = 0, ccp = cp->ccps; compno < cp->numcomps;
-	  ++compno, ++ccp) {
-		if (!(ccp->csty & JPC_COX_PRT)) {
-			for (i = 0; i < JPC_MAXRLVLS; ++i) {
-				ccp->prcwidthexpns[i] = 15;
-				ccp->prcheightexpns[i] = 15;
-			}
-		}
-		if (ccp->qsty == JPC_QCX_SIQNT) {
-			calcstepsizes(ccp->stepsizes[0], ccp->numrlvls, ccp->stepsizes);
-		}
-	}
-	return 0;
+    jpc_dec_ccp_t *ccp;
+    int compno;
+    int i;
+    for (compno = 0, ccp = cp->ccps; compno < cp->numcomps;
+      ++compno, ++ccp) {
+        if (!(ccp->csty & JPC_COX_PRT)) {
+            for (i = 0; i < JPC_MAXRLVLS; ++i) {
+                ccp->prcwidthexpns[i] = 15;
+                ccp->prcheightexpns[i] = 15;
+            }
+        }
+        if (ccp->qsty == JPC_QCX_SIQNT) {
+            calcstepsizes(ccp->stepsizes[0], ccp->numrlvls, ccp->stepsizes);
+        }
+    }
+    return 0;
 }
 
 static int jpc_dec_cp_setfromcod(jpc_dec_cp_t *cp, jpc_cod_t *cod)
 {
-	jpc_dec_ccp_t *ccp;
-	int compno;
-	cp->flags |= JPC_CSET;
-	cp->prgord = cod->prg;
-	if (cod->mctrans) {
-		cp->mctid = (cod->compparms.qmfbid == JPC_COX_INS) ? (JPC_MCT_ICT) : (JPC_MCT_RCT);
-	} else {
-		cp->mctid = JPC_MCT_NONE;
-	}
-	cp->numlyrs = cod->numlyrs;
-	cp->csty = cod->csty & (JPC_COD_SOP | JPC_COD_EPH);
-	for (compno = 0, ccp = cp->ccps; compno < cp->numcomps;
-	  ++compno, ++ccp) {
-		jpc_dec_cp_setfromcox(cp, ccp, &cod->compparms, 0);
-	}
-	cp->flags |= JPC_CSET;
-	return 0;
+    jpc_dec_ccp_t *ccp;
+    int compno;
+    cp->flags |= JPC_CSET;
+    cp->prgord = cod->prg;
+    if (cod->mctrans) {
+        cp->mctid = (cod->compparms.qmfbid == JPC_COX_INS) ? (JPC_MCT_ICT) : (JPC_MCT_RCT);
+    } else {
+        cp->mctid = JPC_MCT_NONE;
+    }
+    cp->numlyrs = cod->numlyrs;
+    cp->csty = cod->csty & (JPC_COD_SOP | JPC_COD_EPH);
+    for (compno = 0, ccp = cp->ccps; compno < cp->numcomps;
+      ++compno, ++ccp) {
+        jpc_dec_cp_setfromcox(cp, ccp, &cod->compparms, 0);
+    }
+    cp->flags |= JPC_CSET;
+    return 0;
 }
 
 static int jpc_dec_cp_setfromcoc(jpc_dec_cp_t *cp, jpc_coc_t *coc)
 {
-	jpc_dec_cp_setfromcox(cp, &cp->ccps[coc->compno], &coc->compparms, JPC_COC);
-	return 0;
+    jpc_dec_cp_setfromcox(cp, &cp->ccps[coc->compno], &coc->compparms, JPC_COC);
+    return 0;
 }
 
 static int jpc_dec_cp_setfromcox(jpc_dec_cp_t *cp, jpc_dec_ccp_t *ccp,
   jpc_coxcp_t *compparms, int flags)
 {
-	int rlvlno;
-	if ((flags & JPC_COC) || !(ccp->flags & JPC_COC)) {
-		ccp->numrlvls = compparms->numdlvls + 1;
-		ccp->cblkwidthexpn = JPC_COX_GETCBLKSIZEEXPN(
-		  compparms->cblkwidthval);
-		ccp->cblkheightexpn = JPC_COX_GETCBLKSIZEEXPN(
-		  compparms->cblkheightval);
-		ccp->qmfbid = compparms->qmfbid;
-		ccp->cblkctx = compparms->cblksty;
-		ccp->csty = compparms->csty & JPC_COX_PRT;
-		for (rlvlno = 0; rlvlno < compparms->numrlvls; ++rlvlno) {
-			ccp->prcwidthexpns[rlvlno] =
-			  compparms->rlvls[rlvlno].parwidthval;
-			ccp->prcheightexpns[rlvlno] =
-			  compparms->rlvls[rlvlno].parheightval;
-		}
-		ccp->flags |= flags | JPC_CSET;
-	}
-	return 0;
+    int rlvlno;
+    if ((flags & JPC_COC) || !(ccp->flags & JPC_COC)) {
+        ccp->numrlvls = compparms->numdlvls + 1;
+        ccp->cblkwidthexpn = JPC_COX_GETCBLKSIZEEXPN(
+          compparms->cblkwidthval);
+        ccp->cblkheightexpn = JPC_COX_GETCBLKSIZEEXPN(
+          compparms->cblkheightval);
+        ccp->qmfbid = compparms->qmfbid;
+        ccp->cblkctx = compparms->cblksty;
+        ccp->csty = compparms->csty & JPC_COX_PRT;
+        for (rlvlno = 0; rlvlno < compparms->numrlvls; ++rlvlno) {
+            ccp->prcwidthexpns[rlvlno] =
+              compparms->rlvls[rlvlno].parwidthval;
+            ccp->prcheightexpns[rlvlno] =
+              compparms->rlvls[rlvlno].parheightval;
+        }
+        ccp->flags |= flags | JPC_CSET;
+    }
+    return 0;
 }
 
 static int jpc_dec_cp_setfromqcd(jpc_dec_cp_t *cp, jpc_qcd_t *qcd)
 {
-	int compno;
-	jpc_dec_ccp_t *ccp;
-	for (compno = 0, ccp = cp->ccps; compno < cp->numcomps;
-	  ++compno, ++ccp) {
-		jpc_dec_cp_setfromqcx(cp, ccp, &qcd->compparms, 0);
-	}
-	cp->flags |= JPC_QSET;
-	return 0;
+    int compno;
+    jpc_dec_ccp_t *ccp;
+    for (compno = 0, ccp = cp->ccps; compno < cp->numcomps;
+      ++compno, ++ccp) {
+        jpc_dec_cp_setfromqcx(cp, ccp, &qcd->compparms, 0);
+    }
+    cp->flags |= JPC_QSET;
+    return 0;
 }
 
 static int jpc_dec_cp_setfromqcc(jpc_dec_cp_t *cp, jpc_qcc_t *qcc)
 {
-	return jpc_dec_cp_setfromqcx(cp, &cp->ccps[qcc->compno], &qcc->compparms, JPC_QCC);
+    return jpc_dec_cp_setfromqcx(cp, &cp->ccps[qcc->compno], &qcc->compparms, JPC_QCC);
 }
 
 static int jpc_dec_cp_setfromqcx(jpc_dec_cp_t *cp, jpc_dec_ccp_t *ccp,
   jpc_qcxcp_t *compparms, int flags)
 {
-	int bandno;
-	if ((flags & JPC_QCC) || !(ccp->flags & JPC_QCC)) {
-		ccp->flags |= flags | JPC_QSET;
-		for (bandno = 0; bandno < compparms->numstepsizes; ++bandno) {
-			ccp->stepsizes[bandno] = compparms->stepsizes[bandno];
-		}
-		ccp->numstepsizes = compparms->numstepsizes;
-		ccp->numguardbits = compparms->numguard;
-		ccp->qsty = compparms->qntsty;
-	}
-	return 0;
+    int bandno;
+    if ((flags & JPC_QCC) || !(ccp->flags & JPC_QCC)) {
+        ccp->flags |= flags | JPC_QSET;
+        for (bandno = 0; bandno < compparms->numstepsizes; ++bandno) {
+            ccp->stepsizes[bandno] = compparms->stepsizes[bandno];
+        }
+        ccp->numstepsizes = compparms->numstepsizes;
+        ccp->numguardbits = compparms->numguard;
+        ccp->qsty = compparms->qntsty;
+    }
+    return 0;
 }
 
 static int jpc_dec_cp_setfromrgn(jpc_dec_cp_t *cp, jpc_rgn_t *rgn)
 {
-	jpc_dec_ccp_t *ccp;
-	ccp = &cp->ccps[rgn->compno];
-	ccp->roishift = rgn->roishift;
-	return 0;
+    jpc_dec_ccp_t *ccp;
+    ccp = &cp->ccps[rgn->compno];
+    ccp->roishift = rgn->roishift;
+    return 0;
 }
 
 static int jpc_pi_addpchgfrompoc(jpc_pi_t *pi, jpc_poc_t *poc)
 {
-	int pchgno;
-	jpc_pchg_t *pchg;
-	for (pchgno = 0; pchgno < poc->numpchgs; ++pchgno) {
-		if (!(pchg = jpc_pchg_copy(&poc->pchgs[pchgno]))) {
-			return -1;
-		}
-		if (jpc_pchglist_insert(pi->pchglist, -1, pchg)) {
-			return -1;
-		}
-	}
-	return 0;
+    int pchgno;
+    jpc_pchg_t *pchg;
+    for (pchgno = 0; pchgno < poc->numpchgs; ++pchgno) {
+        if (!(pchg = jpc_pchg_copy(&poc->pchgs[pchgno]))) {
+            return -1;
+        }
+        if (jpc_pchglist_insert(pi->pchglist, -1, pchg)) {
+            return -1;
+        }
+    }
+    return 0;
 }
 
 static int jpc_dec_cp_setfrompoc(jpc_dec_cp_t *cp, jpc_poc_t *poc, int reset)
 {
-	int pchgno;
-	jpc_pchg_t *pchg;
-	if (reset) {
-		while (jpc_pchglist_numpchgs(cp->pchglist) > 0) {
-			pchg = jpc_pchglist_remove(cp->pchglist, 0);
-			jpc_pchg_destroy(pchg);
-		}
-	}
-	for (pchgno = 0; pchgno < poc->numpchgs; ++pchgno) {
-		if (!(pchg = jpc_pchg_copy(&poc->pchgs[pchgno]))) {
-			return -1;
-		}
-		if (jpc_pchglist_insert(cp->pchglist, -1, pchg)) {
-			return -1;
-		}
-	}
-	return 0;
+    int pchgno;
+    jpc_pchg_t *pchg;
+    if (reset) {
+        while (jpc_pchglist_numpchgs(cp->pchglist) > 0) {
+            pchg = jpc_pchglist_remove(cp->pchglist, 0);
+            jpc_pchg_destroy(pchg);
+        }
+    }
+    for (pchgno = 0; pchgno < poc->numpchgs; ++pchgno) {
+        if (!(pchg = jpc_pchg_copy(&poc->pchgs[pchgno]))) {
+            return -1;
+        }
+        if (jpc_pchglist_insert(cp->pchglist, -1, pchg)) {
+            return -1;
+        }
+    }
+    return 0;
 }
 
 static jpc_fix_t jpc_calcabsstepsize(int stepsize, int numbits)
 {
-	jpc_fix_t absstepsize;
-	int n;
+    jpc_fix_t absstepsize;
+    int n;
 
-	absstepsize = jpc_inttofix(1);
-	n = JPC_FIX_FRACBITS - 11;
-	absstepsize |= (n >= 0) ? (JPC_QCX_GETMANT(stepsize) << n) :
-	  (JPC_QCX_GETMANT(stepsize) >> (-n));
-	n = numbits - JPC_QCX_GETEXPN(stepsize);
-	absstepsize = (n >= 0) ? (absstepsize << n) : (absstepsize >> (-n));
-	return absstepsize;
+    absstepsize = jpc_inttofix(1);
+    n = JPC_FIX_FRACBITS - 11;
+    absstepsize |= (n >= 0) ? (JPC_QCX_GETMANT(stepsize) << n) :
+      (JPC_QCX_GETMANT(stepsize) >> (-n));
+    n = numbits - JPC_QCX_GETEXPN(stepsize);
+    absstepsize = (n >= 0) ? (absstepsize << n) : (absstepsize >> (-n));
+    return absstepsize;
 }
 
 static void jpc_dequantize(jas_matrix_t *x, jpc_fix_t absstepsize)
 {
-	int i;
-	int j;
-	int t;
+    int i;
+    int j;
+    int t;
 
-	assert(absstepsize >= 0);
-	if (absstepsize == jpc_inttofix(1)) {
-		return;
-	}
+    assert(absstepsize >= 0);
+    if (absstepsize == jpc_inttofix(1)) {
+        return;
+    }
 
-	for (i = 0; i < jas_matrix_numrows(x); ++i) {
-		for (j = 0; j < jas_matrix_numcols(x); ++j) {
-			t = jas_matrix_get(x, i, j);
-			if (t) {
-				t = jpc_fix_mul(t, absstepsize);
-			} else {
-				t = 0;
-			}
-			jas_matrix_set(x, i, j, t);
-		}
-	}
+    for (i = 0; i < jas_matrix_numrows(x); ++i) {
+        for (j = 0; j < jas_matrix_numcols(x); ++j) {
+            t = jas_matrix_get(x, i, j);
+            if (t) {
+                t = jpc_fix_mul(t, absstepsize);
+            } else {
+                t = 0;
+            }
+            jas_matrix_set(x, i, j, t);
+        }
+    }
 
 }
 
 static void jpc_undo_roi(jas_matrix_t *x, int roishift, int bgshift, int numbps)
 {
-	int i;
-	int j;
-	int thresh;
-	jpc_fix_t val;
-	jpc_fix_t mag;
-	bool warn;
-	uint_fast32_t mask;
-
-	if (roishift == 0 && bgshift == 0) {
-		return;
-	}
-	thresh = 1 << roishift;
-
-	warn = false;
-	for (i = 0; i < jas_matrix_numrows(x); ++i) {
-		for (j = 0; j < jas_matrix_numcols(x); ++j) {
-			val = jas_matrix_get(x, i, j);
-			mag = JAS_ABS(val);
-			if (mag >= thresh) {
-				/* We are dealing with ROI data. */
-				mag >>= roishift;
-				val = (val < 0) ? (-mag) : mag;
-				jas_matrix_set(x, i, j, val);
-			} else {
-				/* We are dealing with non-ROI (i.e., background) data. */
-				mag <<= bgshift;
-				mask = (1 << numbps) - 1;
-				/* Perform a basic sanity check on the sample value. */
-				/* Some implementations write garbage in the unused
-				  most-significant bit planes introduced by ROI shifting.
-				  Here we ensure that any such bits are masked off. */
-				if (mag & (~mask)) {
-					if (!warn) {
-						fprintf(stderr,
-						  "warning: possibly corrupt code stream\n");
-						warn = true;
-					}
-					mag &= mask;
-				}
-				val = (val < 0) ? (-mag) : mag;
-				jas_matrix_set(x, i, j, val);
-			}
-		}
-	}
+    int i;
+    int j;
+    int thresh;
+    jpc_fix_t val;
+    jpc_fix_t mag;
+    bool warn;
+    uint_fast32_t mask;
+
+    if (roishift == 0 && bgshift == 0) {
+        return;
+    }
+    thresh = 1 << roishift;
+
+    warn = false;
+    for (i = 0; i < jas_matrix_numrows(x); ++i) {
+        for (j = 0; j < jas_matrix_numcols(x); ++j) {
+            val = jas_matrix_get(x, i, j);
+            mag = JAS_ABS(val);
+            if (mag >= thresh) {
+                /* We are dealing with ROI data. */
+                mag >>= roishift;
+                val = (val < 0) ? (-mag) : mag;
+                jas_matrix_set(x, i, j, val);
+            } else {
+                /* We are dealing with non-ROI (i.e., background) data. */
+                mag <<= bgshift;
+                mask = (1 << numbps) - 1;
+                /* Perform a basic sanity check on the sample value. */
+                /* Some implementations write garbage in the unused
+                  most-significant bit planes introduced by ROI shifting.
+                  Here we ensure that any such bits are masked off. */
+                if (mag & (~mask)) {
+                    if (!warn) {
+                        fprintf(stderr,
+                          "warning: possibly corrupt code stream\n");
+                        warn = true;
+                    }
+                    mag &= mask;
+                }
+                val = (val < 0) ? (-mag) : mag;
+                jas_matrix_set(x, i, j, val);
+            }
+        }
+    }
 }
 
 static jpc_dec_t *jpc_dec_create(jpc_dec_importopts_t *impopts, jas_stream_t *in)
 {
-	jpc_dec_t *dec;
-
-	if (!(dec = jas_malloc(sizeof(jpc_dec_t)))) {
-		return 0;
-	}
-
-	dec->image = 0;
-	dec->xstart = 0;
-	dec->ystart = 0;
-	dec->xend = 0;
-	dec->yend = 0;
-	dec->tilewidth = 0;
-	dec->tileheight = 0;
-	dec->tilexoff = 0;
-	dec->tileyoff = 0;
-	dec->numhtiles = 0;
-	dec->numvtiles = 0;
-	dec->numtiles = 0;
-	dec->tiles = 0;
-	dec->curtile = 0;
-	dec->numcomps = 0;
-	dec->in = in;
-	dec->cp = 0;
-	dec->maxlyrs = impopts->maxlyrs;
-	dec->maxpkts = impopts->maxpkts;
+    jpc_dec_t *dec;
+
+    if (!(dec = jas_malloc(sizeof(jpc_dec_t)))) {
+        return 0;
+    }
+
+    dec->image = 0;
+    dec->xstart = 0;
+    dec->ystart = 0;
+    dec->xend = 0;
+    dec->yend = 0;
+    dec->tilewidth = 0;
+    dec->tileheight = 0;
+    dec->tilexoff = 0;
+    dec->tileyoff = 0;
+    dec->numhtiles = 0;
+    dec->numvtiles = 0;
+    dec->numtiles = 0;
+    dec->tiles = 0;
+    dec->curtile = 0;
+    dec->numcomps = 0;
+    dec->in = in;
+    dec->cp = 0;
+    dec->maxlyrs = impopts->maxlyrs;
+    dec->maxpkts = impopts->maxpkts;
 dec->numpkts = 0;
-	dec->ppmseqno = 0;
-	dec->state = 0;
-	dec->cmpts = 0;
-	dec->pkthdrstreams = 0;
-	dec->ppmstab = 0;
-	dec->curtileendoff = 0;
+    dec->ppmseqno = 0;
+    dec->state = 0;
+    dec->cmpts = 0;
+    dec->pkthdrstreams = 0;
+    dec->ppmstab = 0;
+    dec->curtileendoff = 0;
 
-	return dec;
+    return dec;
 }
 
 static void jpc_dec_destroy(jpc_dec_t *dec)
 {
-	if (dec->cstate) {
-		jpc_cstate_destroy(dec->cstate);
-	}
-	if (dec->pkthdrstreams) {
-		jpc_streamlist_destroy(dec->pkthdrstreams);
-	}
-	if (dec->image) {
-		jas_image_destroy(dec->image);
-	}
+    if (dec->cstate) {
+        jpc_cstate_destroy(dec->cstate);
+    }
+    if (dec->pkthdrstreams) {
+        jpc_streamlist_destroy(dec->pkthdrstreams);
+    }
+    if (dec->image) {
+        jas_image_destroy(dec->image);
+    }
 
-	if (dec->cp) {
-		jpc_dec_cp_destroy(dec->cp);
-	}
+    if (dec->cp) {
+        jpc_dec_cp_destroy(dec->cp);
+    }
 
-	if (dec->cmpts) {
-		jas_free(dec->cmpts);
-	}
+    if (dec->cmpts) {
+        jas_free(dec->cmpts);
+    }
 
-	if (dec->tiles) {
-		jas_free(dec->tiles);
-	}
+    if (dec->tiles) {
+        jas_free(dec->tiles);
+    }
 
-	jas_free(dec);
+    jas_free(dec);
 }
 
 /******************************************************************************\
@@ -1940,395 +1942,411 @@ static void jpc_dec_destroy(jpc_dec_t *dec)
 
 void jpc_seglist_insert(jpc_dec_seglist_t *list, jpc_dec_seg_t *ins, jpc_dec_seg_t *node)
 {
-	jpc_dec_seg_t *prev;
-	jpc_dec_seg_t *next;
-
-	prev = ins;
-	node->prev = prev;
-	next = prev ? (prev->next) : 0;
-	node->prev = prev;
-	node->next = next;
-	if (prev) {
-		prev->next = node;
-	} else {
-		list->head = node;
-	}
-	if (next) {
-		next->prev = node;
-	} else {
-		list->tail = node;
-	}
+    jpc_dec_seg_t *prev;
+    jpc_dec_seg_t *next;
+
+    prev = ins;
+    node->prev = prev;
+    next = prev ? (prev->next) : 0;
+    node->prev = prev;
+    node->next = next;
+    if (prev) {
+        prev->next = node;
+    } else {
+        list->head = node;
+    }
+    if (next) {
+        next->prev = node;
+    } else {
+        list->tail = node;
+    }
 }
 
 void jpc_seglist_remove(jpc_dec_seglist_t *list, jpc_dec_seg_t *seg)
 {
-	jpc_dec_seg_t *prev;
-	jpc_dec_seg_t *next;
-
-	prev = seg->prev;
-	next = seg->next;
-	if (prev) {
-		prev->next = next;
-	} else {
-		list->head = next;
-	}
-	if (next) {
-		next->prev = prev;
-	} else {
-		list->tail = prev;
-	}
-	seg->prev = 0;
-	seg->next = 0;
+    jpc_dec_seg_t *prev;
+    jpc_dec_seg_t *next;
+
+    prev = seg->prev;
+    next = seg->next;
+    if (prev) {
+        prev->next = next;
+    } else {
+        list->head = next;
+    }
+    if (next) {
+        next->prev = prev;
+    } else {
+        list->tail = prev;
+    }
+    seg->prev = 0;
+    seg->next = 0;
 }
 
 jpc_dec_seg_t *jpc_seg_alloc(void)
 {
-	jpc_dec_seg_t *seg;
+    jpc_dec_seg_t *seg;
 
-	if (!(seg = jas_malloc(sizeof(jpc_dec_seg_t)))) {
-		return 0;
-	}
-	seg->prev = 0;
-	seg->next = 0;
-	seg->passno = -1;
-	seg->numpasses = 0;
-	seg->maxpasses = 0;
-	seg->type = JPC_SEG_INVALID;
-	seg->stream = 0;
-	seg->cnt = 0;
-	seg->complete = 0;
-	seg->lyrno = -1;
-	return seg;
+    if (!(seg = jas_malloc(sizeof(jpc_dec_seg_t)))) {
+        return 0;
+    }
+    seg->prev = 0;
+    seg->next = 0;
+    seg->passno = -1;
+    seg->numpasses = 0;
+    seg->maxpasses = 0;
+    seg->type = JPC_SEG_INVALID;
+    seg->stream = 0;
+    seg->cnt = 0;
+    seg->complete = 0;
+    seg->lyrno = -1;
+    return seg;
 }
 
 void jpc_seg_destroy(jpc_dec_seg_t *seg)
 {
-	if (seg->stream) {
-		jas_stream_close(seg->stream);
-	}
-	jas_free(seg);
+    if (seg->stream) {
+        jas_stream_close(seg->stream);
+    }
+    jas_free(seg);
 }
 
 static int jpc_dec_dump(jpc_dec_t *dec, FILE *out)
 {
-	jpc_dec_tile_t *tile;
-	int tileno;
-	jpc_dec_tcomp_t *tcomp;
-	uint_fast16_t compno;
-	jpc_dec_rlvl_t *rlvl;
-	int rlvlno;
-	jpc_dec_band_t *band;
-	int bandno;
-	jpc_dec_prc_t *prc;
-	int prcno;
-	jpc_dec_cblk_t *cblk;
-	int cblkno;
-
-	for (tileno = 0, tile = dec->tiles; tileno < dec->numtiles;
-	  ++tileno, ++tile) {
-		for (compno = 0, tcomp = tile->tcomps; compno < dec->numcomps;
-		  ++compno, ++tcomp) {
-			for (rlvlno = 0, rlvl = tcomp->rlvls; rlvlno <
-			  tcomp->numrlvls; ++rlvlno, ++rlvl) {
-fprintf(out, "RESOLUTION LEVEL %d\n", rlvlno);
-fprintf(out, "xs =%d, ys = %d, xe = %d, ye = %d, w = %d, h = %d\n",
-  rlvl->xstart, rlvl->ystart, rlvl->xend, rlvl->yend, rlvl->xend -
-  rlvl->xstart, rlvl->yend - rlvl->ystart);
-				for (bandno = 0, band = rlvl->bands;
-				  bandno < rlvl->numbands; ++bandno, ++band) {
-fprintf(out, "BAND %d\n", bandno);
-fprintf(out, "xs =%d, ys = %d, xe = %d, ye = %d, w = %d, h = %d\n",
-  jas_seq2d_xstart(band->data), jas_seq2d_ystart(band->data), jas_seq2d_xend(band->data),
-  jas_seq2d_yend(band->data), jas_seq2d_xend(band->data) - jas_seq2d_xstart(band->data),
-  jas_seq2d_yend(band->data) - jas_seq2d_ystart(band->data));
-					for (prcno = 0, prc = band->prcs;
-					  prcno < rlvl->numprcs; ++prcno,
-					  ++prc) {
-fprintf(out, "CODE BLOCK GROUP %d\n", prcno);
-fprintf(out, "xs =%d, ys = %d, xe = %d, ye = %d, w = %d, h = %d\n",
-  prc->xstart, prc->ystart, prc->xend, prc->yend, prc->xend -
-  prc->xstart, prc->yend - prc->ystart);
-						for (cblkno = 0, cblk =
-						  prc->cblks; cblkno <
-						  prc->numcblks; ++cblkno,
-						  ++cblk) {
-fprintf(out, "CODE BLOCK %d\n", cblkno);
-fprintf(out, "xs =%d, ys = %d, xe = %d, ye = %d, w = %d, h = %d\n",
-  jas_seq2d_xstart(cblk->data), jas_seq2d_ystart(cblk->data), jas_seq2d_xend(cblk->data),
-  jas_seq2d_yend(cblk->data), jas_seq2d_xend(cblk->data) - jas_seq2d_xstart(cblk->data),
-  jas_seq2d_yend(cblk->data) - jas_seq2d_ystart(cblk->data));
-						}
-					}
-				}
-			}
-		}
-	}
-
-	return 0;
+    jpc_dec_tile_t *tile;
+    int tileno;
+    jpc_dec_tcomp_t *tcomp;
+    uint_fast16_t compno;
+    jpc_dec_rlvl_t *rlvl;
+    int rlvlno;
+    jpc_dec_band_t *band;
+    int bandno;
+    jpc_dec_prc_t *prc;
+    int prcno;
+    jpc_dec_cblk_t *cblk;
+    int cblkno;
+
+    for (tileno = 0, tile = dec->tiles; tileno < dec->numtiles;
+      ++tileno, ++tile) {
+        for (compno = 0, tcomp = tile->tcomps; compno < dec->numcomps;
+          ++compno, ++tcomp) {
+            for (rlvlno = 0, rlvl = tcomp->rlvls; rlvlno <
+              tcomp->numrlvls; ++rlvlno, ++rlvl) {
+                fprintf(out, "RESOLUTION LEVEL %d\n", rlvlno);
+                fprintf(out, "xs =%d, ys = %d, xe = %d, ye = %d, "
+                        "w = %d, h = %d\n",
+                        (int)rlvl->xstart, (int)rlvl->ystart,
+                        (int)rlvl->xend, (int)rlvl->yend,
+                        (int)(rlvl->xend - rlvl->xstart),
+                        (int)(rlvl->yend - rlvl->ystart));
+                for (bandno = 0, band = rlvl->bands;
+                     bandno < rlvl->numbands; ++bandno, ++band) {
+                    fprintf(out, "BAND %d\n", bandno);
+                    fprintf(out, "xs =%d, ys = %d, xe = %d, ye = %d, "
+                            "w = %d, h = %d\n",
+                            (int)jas_seq2d_xstart(band->data),
+                            (int)jas_seq2d_ystart(band->data),
+                            (int)jas_seq2d_xend(band->data),
+                            (int)jas_seq2d_yend(band->data),
+                            (int)(jas_seq2d_xend(band->data) -
+                                  jas_seq2d_xstart(band->data)),
+                            (int)(jas_seq2d_yend(band->data) -
+                                  jas_seq2d_ystart(band->data)));
+                    for (prcno = 0, prc = band->prcs;
+                         prcno < rlvl->numprcs;
+                         ++prcno, ++prc) {
+                        fprintf(out, "CODE BLOCK GROUP %d\n", prcno);
+                        fprintf(out, "xs =%d, ys = %d, xe = %d, ye = %d, "
+                                "w = %d, h = %d\n",
+                                (int)prc->xstart, (int)prc->ystart,
+                                (int)prc->xend, (int)prc->yend,
+                                (int)(prc->xend - prc->xstart),
+                                (int)(prc->yend - prc->ystart));
+                        for (cblkno = 0, cblk = prc->cblks;
+                             cblkno < prc->numcblks;
+                             ++cblkno, ++cblk) {
+                            fprintf(out, "CODE BLOCK %d\n", cblkno);
+                            fprintf(out, "xs =%d, ys = %d, xe = %d, ye = %d, "
+                                    "w = %d, h = %d\n",
+                                    (int)jas_seq2d_xstart(cblk->data),
+                                    (int)jas_seq2d_ystart(cblk->data),
+                                    (int)jas_seq2d_xend(cblk->data),
+                                    (int)jas_seq2d_yend(cblk->data),
+                                    (int)(jas_seq2d_xend(cblk->data) -
+                                          jas_seq2d_xstart(cblk->data)),
+                                    (int)(jas_seq2d_yend(cblk->data) -
+                                          jas_seq2d_ystart(cblk->data)));
+                        }
+                    }
+                }
+            }
+        }
+    }
+    return 0;
 }
 
 jpc_streamlist_t *jpc_streamlist_create()
 {
-	jpc_streamlist_t *streamlist;
-	int i;
-
-	if (!(streamlist = jas_malloc(sizeof(jpc_streamlist_t)))) {
-		return 0;
-	}
-	streamlist->numstreams = 0;
-	streamlist->maxstreams = 100;
-	if (!(streamlist->streams = jas_malloc(streamlist->maxstreams *
-	  sizeof(jas_stream_t *)))) {
-		jas_free(streamlist);
-		return 0;
-	}
-	for (i = 0; i < streamlist->maxstreams; ++i) {
-		streamlist->streams[i] = 0;
-	}
-	return streamlist;
+    jpc_streamlist_t *streamlist;
+    int i;
+
+    if (!(streamlist = jas_malloc(sizeof(jpc_streamlist_t)))) {
+        return 0;
+    }
+    streamlist->numstreams = 0;
+    streamlist->maxstreams = 100;
+    if (!(streamlist->streams = jas_malloc(streamlist->maxstreams *
+      sizeof(jas_stream_t *)))) {
+        jas_free(streamlist);
+        return 0;
+    }
+    for (i = 0; i < streamlist->maxstreams; ++i) {
+        streamlist->streams[i] = 0;
+    }
+    return streamlist;
 }
 
 int jpc_streamlist_insert(jpc_streamlist_t *streamlist, int streamno,
   jas_stream_t *stream)
 {
-	jas_stream_t **newstreams;
-	int newmaxstreams;
-	int i;
-	/* Grow the array of streams if necessary. */
-	if (streamlist->numstreams >= streamlist->maxstreams) {
-		newmaxstreams = streamlist->maxstreams + 1024;
-		if (!(newstreams = jas_realloc(streamlist->streams,
-		  (newmaxstreams + 1024) * sizeof(jas_stream_t *)))) {
-			return -1;
-		}
-		for (i = streamlist->numstreams; i < streamlist->maxstreams; ++i) {
-			streamlist->streams[i] = 0;
-		}
-		streamlist->maxstreams = newmaxstreams;
-		streamlist->streams = newstreams;
-	}
-	if (streamno != streamlist->numstreams) {
-		/* Can only handle insertion at start of list. */
-		return -1;
-	}
-	streamlist->streams[streamno] = stream;
-	++streamlist->numstreams;
-	return 0;
+    jas_stream_t **newstreams;
+    int newmaxstreams;
+    int i;
+    /* Grow the array of streams if necessary. */
+    if (streamlist->numstreams >= streamlist->maxstreams) {
+        newmaxstreams = streamlist->maxstreams + 1024;
+        if (!(newstreams = jas_realloc(streamlist->streams,
+          (newmaxstreams + 1024) * sizeof(jas_stream_t *)))) {
+            return -1;
+        }
+        for (i = streamlist->numstreams; i < streamlist->maxstreams; ++i) {
+            streamlist->streams[i] = 0;
+        }
+        streamlist->maxstreams = newmaxstreams;
+        streamlist->streams = newstreams;
+    }
+    if (streamno != streamlist->numstreams) {
+        /* Can only handle insertion at start of list. */
+        return -1;
+    }
+    streamlist->streams[streamno] = stream;
+    ++streamlist->numstreams;
+    return 0;
 }
 
 jas_stream_t *jpc_streamlist_remove(jpc_streamlist_t *streamlist, int streamno)
 {
-	jas_stream_t *stream;
-	int i;
-	if (streamno >= streamlist->numstreams) {
-		abort();
-	}
-	stream = streamlist->streams[streamno];
-	for (i = streamno + 1; i < streamlist->numstreams; ++i) {
-		streamlist->streams[i - 1] = streamlist->streams[i];
-	}
-	--streamlist->numstreams;
-	return stream;
+    jas_stream_t *stream;
+    int i;
+    if (streamno >= streamlist->numstreams) {
+        abort();
+    }
+    stream = streamlist->streams[streamno];
+    for (i = streamno + 1; i < streamlist->numstreams; ++i) {
+        streamlist->streams[i - 1] = streamlist->streams[i];
+    }
+    --streamlist->numstreams;
+    return stream;
 }
 
 void jpc_streamlist_destroy(jpc_streamlist_t *streamlist)
 {
-	int streamno;
-	if (streamlist->streams) {
-		for (streamno = 0; streamno < streamlist->numstreams;
-		  ++streamno) {
-			jas_stream_close(streamlist->streams[streamno]);
-		}
-		jas_free(streamlist->streams);
-	}
-	jas_free(streamlist);
+    int streamno;
+    if (streamlist->streams) {
+        for (streamno = 0; streamno < streamlist->numstreams;
+          ++streamno) {
+            jas_stream_close(streamlist->streams[streamno]);
+        }
+        jas_free(streamlist->streams);
+    }
+    jas_free(streamlist);
 }
 
 jas_stream_t *jpc_streamlist_get(jpc_streamlist_t *streamlist, int streamno)
 {
-	assert(streamno < streamlist->numstreams);
-	return streamlist->streams[streamno];
+    assert(streamno < streamlist->numstreams);
+    return streamlist->streams[streamno];
 }
 
 int jpc_streamlist_numstreams(jpc_streamlist_t *streamlist)
 {
-	return streamlist->numstreams;
+    return streamlist->numstreams;
 }
 
 jpc_ppxstab_t *jpc_ppxstab_create()
 {
-	jpc_ppxstab_t *tab;
+    jpc_ppxstab_t *tab;
 
-	if (!(tab = jas_malloc(sizeof(jpc_ppxstab_t)))) {
-		return 0;
-	}
-	tab->numents = 0;
-	tab->maxents = 0;
-	tab->ents = 0;
-	return tab;
+    if (!(tab = jas_malloc(sizeof(jpc_ppxstab_t)))) {
+        return 0;
+    }
+    tab->numents = 0;
+    tab->maxents = 0;
+    tab->ents = 0;
+    return tab;
 }
 
 void jpc_ppxstab_destroy(jpc_ppxstab_t *tab)
 {
-	int i;
-	for (i = 0; i < tab->numents; ++i) {
-		jpc_ppxstabent_destroy(tab->ents[i]);
-	}
-	if (tab->ents) {
-		jas_free(tab->ents);
-	}
-	jas_free(tab);
+    int i;
+    for (i = 0; i < tab->numents; ++i) {
+        jpc_ppxstabent_destroy(tab->ents[i]);
+    }
+    if (tab->ents) {
+        jas_free(tab->ents);
+    }
+    jas_free(tab);
 }
 
 int jpc_ppxstab_grow(jpc_ppxstab_t *tab, int maxents)
 {
-	jpc_ppxstabent_t **newents;
-	if (tab->maxents < maxents) {
-		newents = (tab->ents) ? jas_realloc(tab->ents, maxents *
-		  sizeof(jpc_ppxstabent_t *)) : jas_malloc(maxents * sizeof(jpc_ppxstabent_t *));
-		if (!newents) {
-			return -1;
-		}
-		tab->ents = newents;
-		tab->maxents = maxents;
-	}
-	return 0;
+    jpc_ppxstabent_t **newents;
+    if (tab->maxents < maxents) {
+        newents = (tab->ents) ? jas_realloc(tab->ents, maxents *
+          sizeof(jpc_ppxstabent_t *)) : jas_malloc(maxents * sizeof(jpc_ppxstabent_t *));
+        if (!newents) {
+            return -1;
+        }
+        tab->ents = newents;
+        tab->maxents = maxents;
+    }
+    return 0;
 }
 
 int jpc_ppxstab_insert(jpc_ppxstab_t *tab, jpc_ppxstabent_t *ent)
 {
-	int inspt;
-	int i;
+    int inspt;
+    int i;
 
-	for (i = 0; i < tab->numents; ++i) {
-		if (tab->ents[i]->ind > ent->ind) {
-			break;
-		}
-	}
-	inspt = i;
+    for (i = 0; i < tab->numents; ++i) {
+        if (tab->ents[i]->ind > ent->ind) {
+            break;
+        }
+    }
+    inspt = i;
 
-	if (tab->numents >= tab->maxents) {
-		if (jpc_ppxstab_grow(tab, tab->maxents + 128)) {
-			return -1;
-		}
-	}
+    if (tab->numents >= tab->maxents) {
+        if (jpc_ppxstab_grow(tab, tab->maxents + 128)) {
+            return -1;
+        }
+    }
 
-	for (i = tab->numents; i > inspt; --i) {
-		tab->ents[i] = tab->ents[i - 1];
-	}
-	tab->ents[i] = ent;
-	++tab->numents;
+    for (i = tab->numents; i > inspt; --i) {
+        tab->ents[i] = tab->ents[i - 1];
+    }
+    tab->ents[i] = ent;
+    ++tab->numents;
 
-	return 0;
+    return 0;
 }
 
 jpc_streamlist_t *jpc_ppmstabtostreams(jpc_ppxstab_t *tab)
 {
-	jpc_streamlist_t *streams;
-	unsigned char *dataptr;
-	uint_fast32_t datacnt;
-	uint_fast32_t tpcnt;
-	jpc_ppxstabent_t *ent;
-	int entno;
-	jas_stream_t *stream;
-	int n;
-
-	if (!(streams = jpc_streamlist_create())) {
-		goto error;
-	}
-
-	if (!tab->numents) {
-		return streams;
-	}
-
-	entno = 0;
-	ent = tab->ents[entno];
-	dataptr = ent->data;
-	datacnt = ent->len;
-	for (;;) {
-
-		/* Get the length of the packet header data for the current
-		  tile-part. */
-		if (datacnt < 4) {
-			goto error;
-		}
-		if (!(stream = jas_stream_memopen(0, 0))) {
-			goto error;
-		}
-		if (jpc_streamlist_insert(streams, jpc_streamlist_numstreams(streams),
-		  stream)) {
-			goto error;
-		}
-		tpcnt = (dataptr[0] << 24) | (dataptr[1] << 16) | (dataptr[2] << 8)
-		  | dataptr[3];
-		datacnt -= 4;
-		dataptr += 4;
-
-		/* Get the packet header data for the current tile-part. */
-		while (tpcnt) {
-			if (!datacnt) {
-				if (++entno >= tab->numents) {
-					goto error;
-				}
-				ent = tab->ents[entno];
-				dataptr = ent->data;
-				datacnt = ent->len;
-			}
-			n = JAS_MIN(tpcnt, datacnt);
-			if (jas_stream_write(stream, dataptr, n) != n) {
-				goto error;
-			}
-			tpcnt -= n;
-			dataptr += n;
-			datacnt -= n;
-		}
-		jas_stream_rewind(stream);
-		if (!datacnt) {
-			if (++entno >= tab->numents) {
-				break;
-			}
-			ent = tab->ents[entno];
-			dataptr = ent->data;
-			datacnt = ent->len;
-		}
-	}
-
-	return streams;
+    jpc_streamlist_t *streams;
+    unsigned char *dataptr;
+    uint_fast32_t datacnt;
+    uint_fast32_t tpcnt;
+    jpc_ppxstabent_t *ent;
+    int entno;
+    jas_stream_t *stream;
+    int n;
+
+    if (!(streams = jpc_streamlist_create())) {
+        goto error;
+    }
+
+    if (!tab->numents) {
+        return streams;
+    }
+
+    entno = 0;
+    ent = tab->ents[entno];
+    dataptr = ent->data;
+    datacnt = ent->len;
+    for (;;) {
+
+        /* Get the length of the packet header data for the current
+          tile-part. */
+        if (datacnt < 4) {
+            goto error;
+        }
+        if (!(stream = jas_stream_memopen(0, 0))) {
+            goto error;
+        }
+        if (jpc_streamlist_insert(streams, jpc_streamlist_numstreams(streams),
+          stream)) {
+            goto error;
+        }
+        tpcnt = (dataptr[0] << 24) | (dataptr[1] << 16) | (dataptr[2] << 8)
+          | dataptr[3];
+        datacnt -= 4;
+        dataptr += 4;
+
+        /* Get the packet header data for the current tile-part. */
+        while (tpcnt) {
+            if (!datacnt) {
+                if (++entno >= tab->numents) {
+                    goto error;
+                }
+                ent = tab->ents[entno];
+                dataptr = ent->data;
+                datacnt = ent->len;
+            }
+            n = JAS_MIN(tpcnt, datacnt);
+            if (jas_stream_write(stream, dataptr, n) != n) {
+                goto error;
+            }
+            tpcnt -= n;
+            dataptr += n;
+            datacnt -= n;
+        }
+        jas_stream_rewind(stream);
+        if (!datacnt) {
+            if (++entno >= tab->numents) {
+                break;
+            }
+            ent = tab->ents[entno];
+            dataptr = ent->data;
+            datacnt = ent->len;
+        }
+    }
+
+    return streams;
 
 error:
-	jpc_streamlist_destroy(streams);
-	return 0;
+    jpc_streamlist_destroy(streams);
+    return 0;
 }
 
 int jpc_pptstabwrite(jas_stream_t *out, jpc_ppxstab_t *tab)
 {
-	int i;
-	jpc_ppxstabent_t *ent;
-	for (i = 0; i < tab->numents; ++i) {
-		ent = tab->ents[i];
-		if (jas_stream_write(out, ent->data, ent->len) != ent->len) {
-			return -1;
-		}
-	}
-	return 0;
+    int i;
+    jpc_ppxstabent_t *ent;
+    for (i = 0; i < tab->numents; ++i) {
+        ent = tab->ents[i];
+        if (jas_stream_write(out, ent->data, ent->len) != ent->len) {
+            return -1;
+        }
+    }
+    return 0;
 }
 
 jpc_ppxstabent_t *jpc_ppxstabent_create()
 {
-	jpc_ppxstabent_t *ent;
-	if (!(ent = jas_malloc(sizeof(jpc_ppxstabent_t)))) {
-		return 0;
-	}
-	ent->data = 0;
-	ent->len = 0;
-	ent->ind = 0;
-	return ent;
+    jpc_ppxstabent_t *ent;
+    if (!(ent = jas_malloc(sizeof(jpc_ppxstabent_t)))) {
+        return 0;
+    }
+    ent->data = 0;
+    ent->len = 0;
+    ent->ind = 0;
+    return ent;
 }
 
 void jpc_ppxstabent_destroy(jpc_ppxstabent_t *ent)
 {
-	if (ent->data) {
-		jas_free(ent->data);
-	}
-	jas_free(ent);
+    if (ent->data) {
+        jas_free(ent->data);
+    }
+    jas_free(ent);
 }
diff --git a/converter/other/jpeg2000/libjasper/jpc/jpc_dec.h b/converter/other/jpeg2000/libjasper/jpc/jpc_dec.h
index 5231048d..02c5553d 100644
--- a/converter/other/jpeg2000/libjasper/jpc/jpc_dec.h
+++ b/converter/other/jpeg2000/libjasper/jpc/jpc_dec.h
@@ -175,7 +175,7 @@ typedef struct {
 	/* The number of streams in this list. */
 	int numstreams;
 
-	/* The maximum number of streams that can be accomodated without
+	/* The maximum number of streams that can be accommodated without
 	  growing the streams array. */
 	int maxstreams;
 
diff --git a/converter/other/jpeg2000/libjasper/jpc/jpc_enc.c b/converter/other/jpeg2000/libjasper/jpc/jpc_enc.c
index 3284dfeb..d17e9aa3 100644
--- a/converter/other/jpeg2000/libjasper/jpc/jpc_enc.c
+++ b/converter/other/jpeg2000/libjasper/jpc/jpc_enc.c
@@ -1,129 +1,13 @@
-/*
- * Copyright (c) 1999-2000 Image Power, Inc. and the University of
- *   British Columbia.
- * Copyright (c) 2001-2002 Michael David Adams.
- * All rights reserved.
- */
-
-/* __START_OF_JASPER_LICENSE__
- * 
- * JasPer Software License
- * 
- * IMAGE POWER JPEG-2000 PUBLIC LICENSE
- * ************************************
- * 
- * GRANT:
- * 
- * Permission is hereby granted, free of charge, to any person (the "User")
- * obtaining a copy of this software and associated documentation, to deal
- * in the JasPer Software without restriction, including without limitation
- * the right to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the JasPer Software (in source and binary forms),
- * and to permit persons to whom the JasPer Software is furnished to do so,
- * provided further that the License Conditions below are met.
- * 
- * License Conditions
- * ******************
- * 
- * A.  Redistributions of source code must retain the above copyright notice,
- * and this list of conditions, and the following disclaimer.
- * 
- * B.  Redistributions in binary form must reproduce the above copyright
- * notice, and this list of conditions, and the following disclaimer in
- * the documentation and/or other materials provided with the distribution.
- * 
- * C.  Neither the name of Image Power, Inc. nor any other contributor
- * (including, but not limited to, the University of British Columbia and
- * Michael David Adams) may be used to endorse or promote products derived
- * from this software without specific prior written permission.
- * 
- * D.  User agrees that it shall not commence any action against Image Power,
- * Inc., the University of British Columbia, Michael David Adams, or any
- * other contributors (collectively "Licensors") for infringement of any
- * intellectual property rights ("IPR") held by the User in respect of any
- * technology that User owns or has a right to license or sublicense and
- * which is an element required in order to claim compliance with ISO/IEC
- * 15444-1 (i.e., JPEG-2000 Part 1).  "IPR" means all intellectual property
- * rights worldwide arising under statutory or common law, and whether
- * or not perfected, including, without limitation, all (i) patents and
- * patent applications owned or licensable by User; (ii) rights associated
- * with works of authorship including copyrights, copyright applications,
- * copyright registrations, mask work rights, mask work applications,
- * mask work registrations; (iii) rights relating to the protection of
- * trade secrets and confidential information; (iv) any right analogous
- * to those set forth in subsections (i), (ii), or (iii) and any other
- * proprietary rights relating to intangible property (other than trademark,
- * trade dress, or service mark rights); and (v) divisions, continuations,
- * renewals, reissues and extensions of the foregoing (as and to the extent
- * applicable) now existing, hereafter filed, issued or acquired.
- * 
- * E.  If User commences an infringement action against any Licensor(s) then
- * such Licensor(s) shall have the right to terminate User's license and
- * all sublicenses that have been granted hereunder by User to other parties.
- * 
- * F.  This software is for use only in hardware or software products that
- * are compliant with ISO/IEC 15444-1 (i.e., JPEG-2000 Part 1).  No license
- * or right to this Software is granted for products that do not comply
- * with ISO/IEC 15444-1.  The JPEG-2000 Part 1 standard can be purchased
- * from the ISO.
- * 
- * THIS DISCLAIMER OF WARRANTY CONSTITUTES AN ESSENTIAL PART OF THIS LICENSE.
- * NO USE OF THE JASPER SOFTWARE IS AUTHORIZED HEREUNDER EXCEPT UNDER
- * THIS DISCLAIMER.  THE JASPER SOFTWARE IS PROVIDED BY THE LICENSORS AND
- * CONTRIBUTORS UNDER THIS LICENSE ON AN ``AS-IS'' BASIS, WITHOUT WARRANTY
- * OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, WITHOUT LIMITATION,
- * WARRANTIES THAT THE JASPER SOFTWARE IS FREE OF DEFECTS, IS MERCHANTABLE,
- * IS FIT FOR A PARTICULAR PURPOSE OR IS NON-INFRINGING.  THOSE INTENDING
- * TO USE THE JASPER SOFTWARE OR MODIFICATIONS THEREOF FOR USE IN HARDWARE
- * OR SOFTWARE PRODUCTS ARE ADVISED THAT THEIR USE MAY INFRINGE EXISTING
- * PATENTS, COPYRIGHTS, TRADEMARKS, OR OTHER INTELLECTUAL PROPERTY RIGHTS.
- * THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE JASPER SOFTWARE
- * IS WITH THE USER.  SHOULD ANY PART OF THE JASPER SOFTWARE PROVE DEFECTIVE
- * IN ANY RESPECT, THE USER (AND NOT THE INITIAL DEVELOPERS, THE UNIVERSITY
- * OF BRITISH COLUMBIA, IMAGE POWER, INC., MICHAEL DAVID ADAMS, OR ANY
- * OTHER CONTRIBUTOR) SHALL ASSUME THE COST OF ANY NECESSARY SERVICING,
- * REPAIR OR CORRECTION.  UNDER NO CIRCUMSTANCES AND UNDER NO LEGAL THEORY,
- * WHETHER TORT (INCLUDING NEGLIGENCE), CONTRACT, OR OTHERWISE, SHALL THE
- * INITIAL DEVELOPER, THE UNIVERSITY OF BRITISH COLUMBIA, IMAGE POWER, INC.,
- * MICHAEL DAVID ADAMS, ANY OTHER CONTRIBUTOR, OR ANY DISTRIBUTOR OF THE
- * JASPER SOFTWARE, OR ANY SUPPLIER OF ANY OF SUCH PARTIES, BE LIABLE TO
- * THE USER OR ANY OTHER PERSON FOR ANY INDIRECT, SPECIAL, INCIDENTAL, OR
- * CONSEQUENTIAL DAMAGES OF ANY CHARACTER INCLUDING, WITHOUT LIMITATION,
- * DAMAGES FOR LOSS OF GOODWILL, WORK STOPPAGE, COMPUTER FAILURE OR
- * MALFUNCTION, OR ANY AND ALL OTHER COMMERCIAL DAMAGES OR LOSSES, EVEN IF
- * SUCH PARTY HAD BEEN INFORMED, OR OUGHT TO HAVE KNOWN, OF THE POSSIBILITY
- * OF SUCH DAMAGES.  THE JASPER SOFTWARE AND UNDERLYING TECHNOLOGY ARE NOT
- * FAULT-TOLERANT AND ARE NOT DESIGNED, MANUFACTURED OR INTENDED FOR USE OR
- * RESALE AS ON-LINE CONTROL EQUIPMENT IN HAZARDOUS ENVIRONMENTS REQUIRING
- * FAIL-SAFE PERFORMANCE, SUCH AS IN THE OPERATION OF NUCLEAR FACILITIES,
- * AIRCRAFT NAVIGATION OR COMMUNICATION SYSTEMS, AIR TRAFFIC CONTROL, DIRECT
- * LIFE SUPPORT MACHINES, OR WEAPONS SYSTEMS, IN WHICH THE FAILURE OF THE
- * JASPER SOFTWARE OR UNDERLYING TECHNOLOGY OR PRODUCT COULD LEAD DIRECTLY
- * TO DEATH, PERSONAL INJURY, OR SEVERE PHYSICAL OR ENVIRONMENTAL DAMAGE
- * ("HIGH RISK ACTIVITIES").  LICENSOR SPECIFICALLY DISCLAIMS ANY EXPRESS
- * OR IMPLIED WARRANTY OF FITNESS FOR HIGH RISK ACTIVITIES.  USER WILL NOT
- * KNOWINGLY USE, DISTRIBUTE OR RESELL THE JASPER SOFTWARE OR UNDERLYING
- * TECHNOLOGY OR PRODUCTS FOR HIGH RISK ACTIVITIES AND WILL ENSURE THAT ITS
- * CUSTOMERS AND END-USERS OF ITS PRODUCTS ARE PROVIDED WITH A COPY OF THE
- * NOTICE SPECIFIED IN THIS SECTION.
- * 
- * __END_OF_JASPER_LICENSE__
- */
-
-/*
- * $Id$
- */
-
-/******************************************************************************\
-* Includes.
-\******************************************************************************/
-
+#include <stdarg.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <assert.h>
 #include <math.h>
 #include <float.h>
 
+#include "netpbm/pm.h"
+#include "netpbm/nstring.h"
+
 #include "jasper/jas_string.h"
 #include "jasper/jas_malloc.h"
 #include "jasper/jas_image.h"
@@ -147,24 +31,24 @@
 #include "jpc_math.h"
 #include "jpc_util.h"
 
-/******************************************************************************\
+/*****************************************************************************\
 *
-\******************************************************************************/
+\*****************************************************************************/
 
 #define JPC_POW2(n) \
-	(1 << (n))
+    (1 << (n))
 
 #define JPC_FLOORTOMULTPOW2(x, n) \
   (((n) > 0) ? ((x) & (~((1 << n) - 1))) : (x))
 /* Round to the nearest multiple of the specified power of two in the
   direction of negative infinity. */
 
-#define	JPC_CEILTOMULTPOW2(x, n) \
+#define JPC_CEILTOMULTPOW2(x, n) \
   (((n) > 0) ? JPC_FLOORTOMULTPOW2(((x) + (1 << (n)) - 1), n) : (x))
 /* Round to the nearest multiple of the specified power of two in the
   direction of positive infinity. */
 
-#define	JPC_POW2(n)	\
+#define JPC_POW2(n) \
   (1 << (n))
 
 jpc_enc_tile_t *jpc_enc_tile_create(jpc_enc_cp_t *cp, jas_image_t *image, int tileno);
@@ -202,180 +86,205 @@ void jpc_enc_destroy(jpc_enc_t *enc);
 static int jpc_enc_encodemainhdr(jpc_enc_t *enc);
 static int jpc_enc_encodemainbody(jpc_enc_t *enc);
 int jpc_enc_encodetiledata(jpc_enc_t *enc);
-int rateallocate(jpc_enc_t *enc, int numlyrs, uint_fast32_t *cumlens);
 int setins(int numvalues, jpc_flt_t *values, jpc_flt_t value);
 static jpc_enc_cp_t *cp_create(char *optstr, jas_image_t *image);
 void jpc_enc_cp_destroy(jpc_enc_cp_t *cp);
 
 static uint_fast32_t jpc_abstorelstepsize(jpc_fix_t absdelta, int scaleexpn)
 {
-	int p;
-	uint_fast32_t mant;
-	uint_fast32_t expn;
-	int n;
-
-	if (absdelta < 0) {
-		abort();
-	}
-
-	p = jpc_firstone(absdelta) - JPC_FIX_FRACBITS;
-	n = 11 - jpc_firstone(absdelta);
-	mant = ((n < 0) ? (absdelta >> (-n)) : (absdelta << n)) & 0x7ff;
-	expn = scaleexpn - p;
-	if (scaleexpn < p) {
-		abort();
-	}
-	return JPC_QCX_EXPN(expn) | JPC_QCX_MANT(mant);
+    int p;
+    uint_fast32_t mant;
+    uint_fast32_t expn;
+    int n;
+
+    if (absdelta < 0) {
+        abort();
+    }
+
+    p = jpc_firstone(absdelta) - JPC_FIX_FRACBITS;
+    n = 11 - jpc_firstone(absdelta);
+    mant = ((n < 0) ? (absdelta >> (-n)) : (absdelta << n)) & 0x7ff;
+    expn = scaleexpn - p;
+    if (scaleexpn < p) {
+        abort();
+    }
+    return JPC_QCX_EXPN(expn) | JPC_QCX_MANT(mant);
 }
 
 typedef enum {
-	OPT_DEBUG,
-	OPT_IMGAREAOFFX,
-	OPT_IMGAREAOFFY,
-	OPT_TILEGRDOFFX,
-	OPT_TILEGRDOFFY,
-	OPT_TILEWIDTH,
-	OPT_TILEHEIGHT,
-	OPT_PRCWIDTH,
-	OPT_PRCHEIGHT,
-	OPT_CBLKWIDTH,
-	OPT_CBLKHEIGHT,
-	OPT_MODE,
-	OPT_PRG,
-	OPT_NOMCT,
-	OPT_MAXRLVLS,
-	OPT_SOP,
-	OPT_EPH,
-	OPT_LAZY,
-	OPT_TERMALL,
-	OPT_SEGSYM,
-	OPT_VCAUSAL,
-	OPT_RESET,
-	OPT_PTERM,
-	OPT_NUMGBITS,
-	OPT_RATE,
-	OPT_ILYRRATES,
-	OPT_JP2OVERHEAD
+    OPT_DEBUG,
+    OPT_IMGAREAOFFX,
+    OPT_IMGAREAOFFY,
+    OPT_TILEGRDOFFX,
+    OPT_TILEGRDOFFY,
+    OPT_TILEWIDTH,
+    OPT_TILEHEIGHT,
+    OPT_PRCWIDTH,
+    OPT_PRCHEIGHT,
+    OPT_CBLKWIDTH,
+    OPT_CBLKHEIGHT,
+    OPT_MODE,
+    OPT_PRG,
+    OPT_NOMCT,
+    OPT_MAXRLVLS,
+    OPT_SOP,
+    OPT_EPH,
+    OPT_LAZY,
+    OPT_TERMALL,
+    OPT_SEGSYM,
+    OPT_VCAUSAL,
+    OPT_RESET,
+    OPT_PTERM,
+    OPT_NUMGBITS,
+    OPT_RATE,
+    OPT_ILYRRATES,
+    OPT_JP2OVERHEAD
 } optid_t;
 
 jas_taginfo_t encopts[] = {
-	{OPT_DEBUG, "debug"},
-	{OPT_IMGAREAOFFX, "imgareatlx"},
-	{OPT_IMGAREAOFFY, "imgareatly"},
-	{OPT_TILEGRDOFFX, "tilegrdtlx"},
-	{OPT_TILEGRDOFFY, "tilegrdtly"},
-	{OPT_TILEWIDTH, "tilewidth"},
-	{OPT_TILEHEIGHT, "tileheight"},
-	{OPT_PRCWIDTH, "prcwidth"},
-	{OPT_PRCHEIGHT, "prcheight"},
-	{OPT_CBLKWIDTH, "cblkwidth"},
-	{OPT_CBLKHEIGHT, "cblkheight"},
-	{OPT_MODE, "mode"},
-	{OPT_PRG, "prg"},
-	{OPT_NOMCT, "nomct"},
-	{OPT_MAXRLVLS, "numrlvls"},
-	{OPT_SOP, "sop"},
-	{OPT_EPH, "eph"},
-	{OPT_LAZY, "lazy"},
-	{OPT_TERMALL, "termall"},
-	{OPT_SEGSYM, "segsym"},
-	{OPT_VCAUSAL, "vcausal"},
-	{OPT_PTERM, "pterm"},
-	{OPT_RESET, "resetprob"},
-	{OPT_NUMGBITS, "numgbits"},
-	{OPT_RATE, "rate"},
-	{OPT_ILYRRATES, "ilyrrates"},
-	{OPT_JP2OVERHEAD, "_jp2overhead"},
-	{-1, 0}
+    {OPT_DEBUG, "debug"},
+    {OPT_IMGAREAOFFX, "imgareatlx"},
+    {OPT_IMGAREAOFFY, "imgareatly"},
+    {OPT_TILEGRDOFFX, "tilegrdtlx"},
+    {OPT_TILEGRDOFFY, "tilegrdtly"},
+    {OPT_TILEWIDTH, "tilewidth"},
+    {OPT_TILEHEIGHT, "tileheight"},
+    {OPT_PRCWIDTH, "prcwidth"},
+    {OPT_PRCHEIGHT, "prcheight"},
+    {OPT_CBLKWIDTH, "cblkwidth"},
+    {OPT_CBLKHEIGHT, "cblkheight"},
+    {OPT_MODE, "mode"},
+    {OPT_PRG, "prg"},
+    {OPT_NOMCT, "nomct"},
+    {OPT_MAXRLVLS, "numrlvls"},
+    {OPT_SOP, "sop"},
+    {OPT_EPH, "eph"},
+    {OPT_LAZY, "lazy"},
+    {OPT_TERMALL, "termall"},
+    {OPT_SEGSYM, "segsym"},
+    {OPT_VCAUSAL, "vcausal"},
+    {OPT_PTERM, "pterm"},
+    {OPT_RESET, "resetprob"},
+    {OPT_NUMGBITS, "numgbits"},
+    {OPT_RATE, "rate"},
+    {OPT_ILYRRATES, "ilyrrates"},
+    {OPT_JP2OVERHEAD, "_jp2overhead"},
+    {-1, 0}
 };
 
 typedef enum {
-	PO_L = 0,
-	PO_R
+    PO_L = 0,
+    PO_R
 } poid_t;
 
 
 jas_taginfo_t prgordtab[] = {
-	{JPC_COD_LRCPPRG, "lrcp"},
-	{JPC_COD_RLCPPRG, "rlcp"},
-	{JPC_COD_RPCLPRG, "rpcl"},
-	{JPC_COD_PCRLPRG, "pcrl"},
-	{JPC_COD_CPRLPRG, "cprl"},
-	{-1, 0}
+    {JPC_COD_LRCPPRG, "lrcp"},
+    {JPC_COD_RLCPPRG, "rlcp"},
+    {JPC_COD_RPCLPRG, "rpcl"},
+    {JPC_COD_PCRLPRG, "pcrl"},
+    {JPC_COD_CPRLPRG, "cprl"},
+    {-1, 0}
 };
 
 typedef enum {
-	MODE_INT,
-	MODE_REAL
+    MODE_INT,
+    MODE_REAL
 } modeid_t;
 
 jas_taginfo_t modetab[] = {
-	{MODE_INT, "int"},
-	{MODE_REAL, "real"},
-	{-1, 0}
+    {MODE_INT, "int"},
+    {MODE_REAL, "real"},
+    {-1, 0}
 };
 
+
+static void
+tracev(const char * const fmt,
+       va_list            args) {
+
+    vfprintf(stderr, fmt, args);
+
+    fprintf(stderr, "\n");
+}
+
+
+
+static void
+trace(const char * const fmt, ...) {
+
+    if (jas_getdbglevel() > 0) {
+        va_list args;
+
+        va_start(args, fmt);
+        tracev(fmt, args);
+        va_end(args);
+    }
+}
+
+
+
 /******************************************************************************\
 * The main encoder entry point.
 \******************************************************************************/
 
 int jpc_encode(jas_image_t *image, jas_stream_t *out, char *optstr)
 {
-	jpc_enc_t *enc;
-	jpc_enc_cp_t *cp;
+    jpc_enc_t *enc;
+    jpc_enc_cp_t *cp;
 
-	enc = 0;
-	cp = 0;
+    enc = 0;
+    cp = 0;
 
-	jpc_initluts();
+    jpc_initluts();
 
-	if (!(cp = cp_create(optstr, image))) {
-		fprintf(stderr, "invalid JP encoder options\n");
-		goto error;
-	}
+    if (!(cp = cp_create(optstr, image))) {
+        fprintf(stderr, "invalid JP encoder options\n");
+        goto error;
+    }
 
-	if (!(enc = jpc_enc_create(cp, out, image))) {
-		goto error;
-	}
-	cp = 0;
+    if (!(enc = jpc_enc_create(cp, out, image))) {
+        goto error;
+    }
+    cp = 0;
 
-	/* Encode the main header. */
-	if (jpc_enc_encodemainhdr(enc)) {
-		goto error;
-	}
+    /* Encode the main header. */
+    if (jpc_enc_encodemainhdr(enc)) {
+        goto error;
+    }
 
-	/* Encode the main body.  This constitutes most of the encoding work. */
-	if (jpc_enc_encodemainbody(enc)) {
-		goto error;
-	}
+    /* Encode the main body.  This constitutes most of the encoding work. */
+    if (jpc_enc_encodemainbody(enc)) {
+        goto error;
+    }
 
-	/* Write EOC marker segment. */
-	if (!(enc->mrk = jpc_ms_create(JPC_MS_EOC))) {
-		goto error;
-	}
-	if (jpc_putms(enc->out, enc->cstate, enc->mrk)) {
-		fprintf(stderr, "cannot write EOI marker\n");
-		goto error;
-	}
-	jpc_ms_destroy(enc->mrk);
-	enc->mrk = 0;
+    /* Write EOC marker segment. */
+    if (!(enc->mrk = jpc_ms_create(JPC_MS_EOC))) {
+        goto error;
+    }
+    if (jpc_putms(enc->out, enc->cstate, enc->mrk)) {
+        fprintf(stderr, "cannot write EOI marker\n");
+        goto error;
+    }
+    jpc_ms_destroy(enc->mrk);
+    enc->mrk = 0;
 
-	if (jas_stream_flush(enc->out)) {
-		goto error;
-	}
+    if (jas_stream_flush(enc->out)) {
+        goto error;
+    }
 
-	jpc_enc_destroy(enc);
+    jpc_enc_destroy(enc);
 
-	return 0;
+    return 0;
 
 error:
-	if (cp) {
-		jpc_enc_cp_destroy(cp);
-	}
-	if (enc) {
-		jpc_enc_destroy(enc);
-	}
-	return -1;
+    if (cp) {
+        jpc_enc_cp_destroy(cp);
+    }
+    if (enc) {
+        jpc_enc_destroy(enc);
+    }
+    return -1;
 }
 
 /******************************************************************************\
@@ -384,466 +293,461 @@ error:
 
 static jpc_enc_cp_t *cp_create(char *optstr, jas_image_t *image)
 {
-	jpc_enc_cp_t *cp;
-	jas_tvparser_t *tvp;
-	int ret;
-	int numilyrrates;
-	double *ilyrrates;
-	int i;
-	int tagid;
-	jpc_enc_tcp_t *tcp;
-	jpc_enc_tccp_t *tccp;
-	jpc_enc_ccp_t *ccp;
-	uint_fast16_t cmptno;
-	uint_fast16_t rlvlno;
-	uint_fast16_t prcwidthexpn;
-	uint_fast16_t prcheightexpn;
-	bool enablemct;
-	uint_fast32_t jp2overhead;
-	uint_fast16_t lyrno;
-	uint_fast32_t hsteplcm;
-	uint_fast32_t vsteplcm;
-	bool mctvalid;
-
-	tvp = 0;
-	cp = 0;
-	ilyrrates = 0;
-	numilyrrates = 0;
-
-	if (!(cp = jas_malloc(sizeof(jpc_enc_cp_t)))) {
-		goto error;
-	}
-
-	prcwidthexpn = 15;
-	prcheightexpn = 15;
-	enablemct = true;
-	jp2overhead = 0;
-
-	cp->ccps = 0;
-	cp->debug = 0;
-	cp->imgareatlx = UINT_FAST32_MAX;
-	cp->imgareatly = UINT_FAST32_MAX;
-	cp->refgrdwidth = 0;
-	cp->refgrdheight = 0;
-	cp->tilegrdoffx = UINT_FAST32_MAX;
-	cp->tilegrdoffy = UINT_FAST32_MAX;
-	cp->tilewidth = 0;
-	cp->tileheight = 0;
-	cp->numcmpts = jas_image_numcmpts(image);
-
-	hsteplcm = 1;
-	vsteplcm = 1;
-	for (cmptno = 0; cmptno < jas_image_numcmpts(image); ++cmptno) {
-		if (jas_image_cmptbrx(image, cmptno) + jas_image_cmpthstep(image, cmptno) <=
-		  jas_image_brx(image) || jas_image_cmptbry(image, cmptno) +
-		  jas_image_cmptvstep(image, cmptno) <= jas_image_bry(image)) {
-			fprintf(stderr, "unsupported image type\n");
-			goto error;
-		}
-		/* Note: We ought to be calculating the LCMs here.  Fix some day. */
-		hsteplcm *= jas_image_cmpthstep(image, cmptno);
-		vsteplcm *= jas_image_cmptvstep(image, cmptno);
-	}
-
-	if (!(cp->ccps = jas_malloc(cp->numcmpts * sizeof(jpc_enc_ccp_t)))) {
-		goto error;
-	}
-	for (cmptno = 0, ccp = cp->ccps; cmptno < cp->numcmpts; ++cmptno,
-	  ++ccp) {
-		ccp->sampgrdstepx = jas_image_cmpthstep(image, cmptno);
-		ccp->sampgrdstepy = jas_image_cmptvstep(image, cmptno);
-		/* XXX - this isn't quite correct for more general image */
-		ccp->sampgrdsubstepx = 0;
-		ccp->sampgrdsubstepx = 0;
-		ccp->prec = jas_image_cmptprec(image, cmptno);
-		ccp->sgnd = jas_image_cmptsgnd(image, cmptno);
-		ccp->numstepsizes = 0;
-		memset(ccp->stepsizes, 0, sizeof(ccp->stepsizes));
-	}
-
-	cp->rawsize = jas_image_rawsize(image);
-	cp->totalsize = UINT_FAST32_MAX;
-
-	tcp = &cp->tcp;
-	tcp->csty = 0;
-	tcp->intmode = true;
-	tcp->prg = JPC_COD_LRCPPRG;
-	tcp->numlyrs = 1;
-	tcp->ilyrrates = 0;
-
-	tccp = &cp->tccp;
-	tccp->csty = 0;
-	tccp->maxrlvls = 6;
-	tccp->cblkwidthexpn = 6;
-	tccp->cblkheightexpn = 6;
-	tccp->cblksty = 0;
-	tccp->numgbits = 2;
-
-	if (!(tvp = jas_tvparser_create(optstr ? optstr : ""))) {
-		goto error;
-	}
-
-	while (!(ret = jas_tvparser_next(tvp))) {
-		switch (jas_taginfo_nonull(jas_taginfos_lookup(encopts,
-		  jas_tvparser_gettag(tvp)))->id) {
-		case OPT_DEBUG:
-			cp->debug = atoi(jas_tvparser_getval(tvp));
-			break;
-		case OPT_IMGAREAOFFX:
-			cp->imgareatlx = atoi(jas_tvparser_getval(tvp));
-			break;
-		case OPT_IMGAREAOFFY:
-			cp->imgareatly = atoi(jas_tvparser_getval(tvp));
-			break;
-		case OPT_TILEGRDOFFX:
-			cp->tilegrdoffx = atoi(jas_tvparser_getval(tvp));
-			break;
-		case OPT_TILEGRDOFFY:
-			cp->tilegrdoffy = atoi(jas_tvparser_getval(tvp));
-			break;
-		case OPT_TILEWIDTH:
-			cp->tilewidth = atoi(jas_tvparser_getval(tvp));
-			break;
-		case OPT_TILEHEIGHT:
-			cp->tileheight = atoi(jas_tvparser_getval(tvp));
-			break;
-		case OPT_PRCWIDTH:
-			prcwidthexpn = jpc_floorlog2(atoi(jas_tvparser_getval(tvp)));
-			break;
-		case OPT_PRCHEIGHT:
-			prcheightexpn = jpc_floorlog2(atoi(jas_tvparser_getval(tvp)));
-			break;
-		case OPT_CBLKWIDTH:
-			tccp->cblkwidthexpn =
-			  jpc_floorlog2(atoi(jas_tvparser_getval(tvp)));
-			break;
-		case OPT_CBLKHEIGHT:
-			tccp->cblkheightexpn =
-			  jpc_floorlog2(atoi(jas_tvparser_getval(tvp)));
-			break;
-		case OPT_MODE:
-			if ((tagid = jas_taginfo_nonull(jas_taginfos_lookup(modetab,
-			  jas_tvparser_getval(tvp)))->id) < 0) {
-				fprintf(stderr,
-				  "ignoring invalid mode %s\n",
-				  jas_tvparser_getval(tvp));
-			} else {
-				tcp->intmode = (tagid == MODE_INT);
-			}
-			break;
-		case OPT_PRG:
-			if ((tagid = jas_taginfo_nonull(jas_taginfos_lookup(prgordtab,
-			  jas_tvparser_getval(tvp)))->id) < 0) {
-				fprintf(stderr,
-				  "ignoring invalid progression order %s\n",
-				  jas_tvparser_getval(tvp));
-			} else {
-				tcp->prg = tagid;
-			}
-			break;
-		case OPT_NOMCT:
-			enablemct = false;
-			break;
-		case OPT_MAXRLVLS:
-			tccp->maxrlvls = atoi(jas_tvparser_getval(tvp));
-			break;
-		case OPT_SOP:
-			cp->tcp.csty |= JPC_COD_SOP;
-			break;
-		case OPT_EPH:
-			cp->tcp.csty |= JPC_COD_EPH;
-			break;
-		case OPT_LAZY:
-			tccp->cblksty |= JPC_COX_LAZY;
-			break;
-		case OPT_TERMALL:
-			tccp->cblksty |= JPC_COX_TERMALL;
-			break;
-		case OPT_SEGSYM:
-			tccp->cblksty |= JPC_COX_SEGSYM;
-			break;
-		case OPT_VCAUSAL:
-			tccp->cblksty |= JPC_COX_VSC;
-			break;
-		case OPT_RESET:
-			tccp->cblksty |= JPC_COX_RESET;
-			break;
-		case OPT_PTERM:
-			tccp->cblksty |= JPC_COX_PTERM;
-			break;
-		case OPT_NUMGBITS:
-			cp->tccp.numgbits = atoi(jas_tvparser_getval(tvp));
-			break;
-		case OPT_RATE:
-			if (ratestrtosize(jas_tvparser_getval(tvp), cp->rawsize,
-			  &cp->totalsize)) {
-				fprintf(stderr,
-				  "ignoring bad rate specifier %s\n",
-				  jas_tvparser_getval(tvp));
-			}
-			break;
-		case OPT_ILYRRATES:
-			if (jpc_atoaf(jas_tvparser_getval(tvp), &numilyrrates,
-			  &ilyrrates)) {
-				fprintf(stderr,
-				  "warning: invalid intermediate layer rates specifier ignored (%s)\n",
-				  jas_tvparser_getval(tvp));
-			}
-			break;
-
-		case OPT_JP2OVERHEAD:
-			jp2overhead = atoi(jas_tvparser_getval(tvp));
-			break;
-		default:
-			fprintf(stderr, "warning: ignoring invalid option %s\n",
-			 jas_tvparser_gettag(tvp));
-			break;
-		}
-	}
-
-	jas_tvparser_destroy(tvp);
-	tvp = 0;
-
-	if (cp->totalsize != UINT_FAST32_MAX) {
-		cp->totalsize = (cp->totalsize > jp2overhead) ?
-		  (cp->totalsize - jp2overhead) : 0;
-	}
-
-	if (cp->imgareatlx == UINT_FAST32_MAX) {
-		cp->imgareatlx = 0;
-	} else {
-		if (hsteplcm != 1) {
-			fprintf(stderr, "warning: overriding imgareatlx value\n");
-		}
-		cp->imgareatlx *= hsteplcm;
-	}
-	if (cp->imgareatly == UINT_FAST32_MAX) {
-		cp->imgareatly = 0;
-	} else {
-		if (vsteplcm != 1) {
-			fprintf(stderr, "warning: overriding imgareatly value\n");
-		}
-		cp->imgareatly *= vsteplcm;
-	}
-	cp->refgrdwidth = cp->imgareatlx + jas_image_width(image);
-	cp->refgrdheight = cp->imgareatly + jas_image_height(image);
-	if (cp->tilegrdoffx == UINT_FAST32_MAX) {
-		cp->tilegrdoffx = cp->imgareatlx;
-	}
-	if (cp->tilegrdoffy == UINT_FAST32_MAX) {
-		cp->tilegrdoffy = cp->imgareatly;
-	}
-	if (!cp->tilewidth) {
-		cp->tilewidth = cp->refgrdwidth - cp->tilegrdoffx;
-	}
-	if (!cp->tileheight) {
-		cp->tileheight = cp->refgrdheight - cp->tilegrdoffy;
-	}
-
-	if (cp->numcmpts == 3) {
-		mctvalid = true;
-		for (cmptno = 0; cmptno < jas_image_numcmpts(image); ++cmptno) {
-			if (jas_image_cmptprec(image, cmptno) != jas_image_cmptprec(image, 0) ||
-			  jas_image_cmptsgnd(image, cmptno) != jas_image_cmptsgnd(image, 0) ||
-			  jas_image_cmptwidth(image, cmptno) != jas_image_cmptwidth(image, 0) ||
-			  jas_image_cmptheight(image, cmptno) != jas_image_cmptheight(image, 0)) {
-				mctvalid = false;
-			}
-		}
-	} else {
-		mctvalid = false;
-	}
-	if (mctvalid && enablemct && jas_image_colorspace(image) != JAS_IMAGE_CS_RGB) {
-		fprintf(stderr, "warning: color model apparently not RGB\n");
-	}
-	if (mctvalid && enablemct && jas_image_colorspace(image) == JAS_IMAGE_CS_RGB) {
-		tcp->mctid = (tcp->intmode) ? (JPC_MCT_RCT) : (JPC_MCT_ICT);
-	} else {
-		tcp->mctid = JPC_MCT_NONE;
-	}
-	tccp->qmfbid = (tcp->intmode) ? (JPC_COX_RFT) : (JPC_COX_INS);
-
-	for (rlvlno = 0; rlvlno < tccp->maxrlvls; ++rlvlno) {
-		tccp->prcwidthexpns[rlvlno] = prcwidthexpn;
-		tccp->prcheightexpns[rlvlno] = prcheightexpn;
-	}
-	if (prcwidthexpn != 15 || prcheightexpn != 15) {
-		tccp->csty |= JPC_COX_PRT;
-	}
-
-	/* Ensure that the tile width and height is valid. */
-	if (!cp->tilewidth) {
-		fprintf(stderr, "invalid tile width %lu\n", (unsigned long)
-		  cp->tilewidth);
-		goto error;
-	}
-	if (!cp->tileheight) {
-		fprintf(stderr, "invalid tile height %lu\n", (unsigned long)
-		  cp->tileheight);
-		goto error;
-	}
-
-	/* Ensure that the tile grid offset is valid. */
-	if (cp->tilegrdoffx > cp->imgareatlx ||
-	  cp->tilegrdoffy > cp->imgareatly ||
-	  cp->tilegrdoffx + cp->tilewidth < cp->imgareatlx ||
-	  cp->tilegrdoffy + cp->tileheight < cp->imgareatly) {
-		fprintf(stderr, "invalid tile grid offset (%lu, %lu)\n",
-		  (unsigned long) cp->tilegrdoffx, (unsigned long)
-		  cp->tilegrdoffy);
-		goto error;
-	}
-
-	cp->numhtiles = JPC_CEILDIV(cp->refgrdwidth - cp->tilegrdoffx,
-	  cp->tilewidth);
-	cp->numvtiles = JPC_CEILDIV(cp->refgrdheight - cp->tilegrdoffy,
-	  cp->tileheight);
-	cp->numtiles = cp->numhtiles * cp->numvtiles;
-
-	if (ilyrrates && numilyrrates > 0) {
-		tcp->numlyrs = numilyrrates + 1;
-		if (!(tcp->ilyrrates = jas_malloc((tcp->numlyrs - 1) *
-		  sizeof(jpc_fix_t)))) {
-			goto error;
-		}
-		for (i = 0; i < tcp->numlyrs - 1; ++i) {
-			tcp->ilyrrates[i] = jpc_dbltofix(ilyrrates[i]);
-		}
-	}
-
-	/* Ensure that the integer mode is used in the case of lossless
-	  coding. */
-	if (cp->totalsize == UINT_FAST32_MAX && (!cp->tcp.intmode)) {
-		fprintf(stderr, "cannot use real mode for lossless coding\n");
-		goto error;
-	}
-
-	/* Ensure that the precinct width is valid. */
-	if (prcwidthexpn > 15) {
-		fprintf(stderr, "invalid precinct width\n");
-		goto error;
-	}
-
-	/* Ensure that the precinct height is valid. */
-	if (prcheightexpn > 15) {
-		fprintf(stderr, "invalid precinct height\n");
-		goto error;
-	}
-
-	/* Ensure that the code block width is valid. */
-	if (cp->tccp.cblkwidthexpn < 2 || cp->tccp.cblkwidthexpn > 12) {
-		fprintf(stderr, "invalid code block width %d\n",
-		  JPC_POW2(cp->tccp.cblkwidthexpn));
-		goto error;
-	}
-
-	/* Ensure that the code block height is valid. */
-	if (cp->tccp.cblkheightexpn < 2 || cp->tccp.cblkheightexpn > 12) {
-		fprintf(stderr, "invalid code block height %d\n",
-		  JPC_POW2(cp->tccp.cblkheightexpn));
-		goto error;
-	}
-
-	/* Ensure that the code block size is not too large. */
-	if (cp->tccp.cblkwidthexpn + cp->tccp.cblkheightexpn > 12) {
-		fprintf(stderr, "code block size too large\n");
-		goto error;
-	}
-
-	/* Ensure that the number of layers is valid. */
-	if (cp->tcp.numlyrs > 16384) {
-		fprintf(stderr, "too many layers\n");
-		goto error;
-	}
-
-	/* There must be at least one resolution level. */
-	if (cp->tccp.maxrlvls < 1) {
-		fprintf(stderr, "must be at least one resolution level\n");
-		goto error;
-	}
-
-	/* Ensure that the number of guard bits is valid. */
-	if (cp->tccp.numgbits > 8) {
-		fprintf(stderr, "invalid number of guard bits\n");
-		goto error;
-	}
-
-	/* Ensure that the rate is within the legal range. */
-	if (cp->totalsize != UINT_FAST32_MAX && cp->totalsize > cp->rawsize) {
-		fprintf(stderr, "warning: specified rate is unreasonably large (%lu > %lu)\n", (unsigned long) cp->totalsize, (unsigned long) cp->rawsize);
-	}
-
-	/* Ensure that the intermediate layer rates are valid. */
-	if (tcp->numlyrs > 1) {
-		/* The intermediate layers rates must increase monotonically. */
-		for (lyrno = 0; lyrno + 2 < tcp->numlyrs; ++lyrno) {
-			if (tcp->ilyrrates[lyrno] >= tcp->ilyrrates[lyrno + 1]) {
-				fprintf(stderr, "intermediate layer rates must increase monotonically\n");
-				goto error;
-			}
-		}
-		/* The intermediate layer rates must be less than the overall rate. */
-		if (cp->totalsize != UINT_FAST32_MAX) {
-			for (lyrno = 0; lyrno < tcp->numlyrs - 1; ++lyrno) {
-				if (jpc_fixtodbl(tcp->ilyrrates[lyrno]) > ((double) cp->totalsize)
-				  / cp->rawsize) {
-					fprintf(stderr, "warning: intermediate layer rates must be less than overall rate\n");
-					goto error;
-				}
-			}
-		}
-	}
-
-	if (ilyrrates) {
-		jas_free(ilyrrates);
-	}
-
-	return cp;
+    jpc_enc_cp_t *cp;
+    jas_tvparser_t *tvp;
+    int ret;
+    int numilyrrates;
+    double *ilyrrates;
+    int i;
+    int tagid;
+    jpc_enc_tcp_t *tcp;
+    jpc_enc_tccp_t *tccp;
+    jpc_enc_ccp_t *ccp;
+    uint_fast16_t cmptno;
+    uint_fast16_t rlvlno;
+    uint_fast16_t prcwidthexpn;
+    uint_fast16_t prcheightexpn;
+    bool enablemct;
+    uint_fast32_t jp2overhead;
+    uint_fast16_t lyrno;
+    uint_fast32_t hsteplcm;
+    uint_fast32_t vsteplcm;
+    bool mctvalid;
+
+    tvp = 0;
+    cp = 0;
+    ilyrrates = 0;
+    numilyrrates = 0;
+
+    if (!(cp = jas_malloc(sizeof(jpc_enc_cp_t)))) {
+        goto error;
+    }
+
+    prcwidthexpn = 15;
+    prcheightexpn = 15;
+    enablemct = true;
+    jp2overhead = 0;
+
+    cp->ccps = 0;
+    cp->debug = 0;
+    cp->imgareatlx = UINT_FAST32_MAX;
+    cp->imgareatly = UINT_FAST32_MAX;
+    cp->refgrdwidth = 0;
+    cp->refgrdheight = 0;
+    cp->tilegrdoffx = UINT_FAST32_MAX;
+    cp->tilegrdoffy = UINT_FAST32_MAX;
+    cp->tilewidth = 0;
+    cp->tileheight = 0;
+    cp->numcmpts = jas_image_numcmpts(image);
+
+    hsteplcm = 1;
+    vsteplcm = 1;
+    for (cmptno = 0; cmptno < jas_image_numcmpts(image); ++cmptno) {
+        if (jas_image_cmptbrx(image, cmptno) + jas_image_cmpthstep(image, cmptno) <=
+          jas_image_brx(image) || jas_image_cmptbry(image, cmptno) +
+          jas_image_cmptvstep(image, cmptno) <= jas_image_bry(image)) {
+            fprintf(stderr, "We don't know how to interpret this image type\n");
+            goto error;
+        }
+        /* Note: We ought to be calculating the LCMs here.  Fix some day. */
+        hsteplcm *= jas_image_cmpthstep(image, cmptno);
+        vsteplcm *= jas_image_cmptvstep(image, cmptno);
+    }
+
+    if (!(cp->ccps = jas_malloc(cp->numcmpts * sizeof(jpc_enc_ccp_t)))) {
+        goto error;
+    }
+    for (cmptno = 0, ccp = cp->ccps; cmptno < cp->numcmpts; ++cmptno,
+      ++ccp) {
+        ccp->sampgrdstepx = jas_image_cmpthstep(image, cmptno);
+        ccp->sampgrdstepy = jas_image_cmptvstep(image, cmptno);
+        /* XXX - this isn't quite correct for more general image */
+        ccp->sampgrdsubstepx = 0;
+        ccp->sampgrdsubstepx = 0;
+        ccp->prec = jas_image_cmptprec(image, cmptno);
+        ccp->sgnd = jas_image_cmptsgnd(image, cmptno);
+        ccp->numstepsizes = 0;
+        memset(ccp->stepsizes, 0, sizeof(ccp->stepsizes));
+    }
+
+    cp->rawsize = jas_image_rawsize(image);
+    cp->totalsize = UINT_FAST32_MAX;
+
+    tcp = &cp->tcp;
+    tcp->csty = 0;
+    tcp->intmode = true;
+    tcp->prg = JPC_COD_LRCPPRG;
+    tcp->numlyrs = 1;
+    tcp->ilyrrates = 0;
+
+    tccp = &cp->tccp;
+    tccp->csty = 0;
+    tccp->maxrlvls = 6;
+    tccp->cblkwidthexpn = 6;
+    tccp->cblkheightexpn = 6;
+    tccp->cblksty = 0;
+    tccp->numgbits = 2;
+
+    if (!(tvp = jas_tvparser_create(optstr ? optstr : ""))) {
+        goto error;
+    }
+
+    while (!(ret = jas_tvparser_next(tvp))) {
+        switch (jas_taginfo_nonull(jas_taginfos_lookup(encopts,
+          jas_tvparser_gettag(tvp)))->id) {
+        case OPT_DEBUG:
+            cp->debug = atoi(jas_tvparser_getval(tvp));
+            break;
+        case OPT_IMGAREAOFFX:
+            cp->imgareatlx = atoi(jas_tvparser_getval(tvp));
+            break;
+        case OPT_IMGAREAOFFY:
+            cp->imgareatly = atoi(jas_tvparser_getval(tvp));
+            break;
+        case OPT_TILEGRDOFFX:
+            cp->tilegrdoffx = atoi(jas_tvparser_getval(tvp));
+            break;
+        case OPT_TILEGRDOFFY:
+            cp->tilegrdoffy = atoi(jas_tvparser_getval(tvp));
+            break;
+        case OPT_TILEWIDTH:
+            cp->tilewidth = atoi(jas_tvparser_getval(tvp));
+            break;
+        case OPT_TILEHEIGHT:
+            cp->tileheight = atoi(jas_tvparser_getval(tvp));
+            break;
+        case OPT_PRCWIDTH:
+            prcwidthexpn = jpc_floorlog2(atoi(jas_tvparser_getval(tvp)));
+            break;
+        case OPT_PRCHEIGHT:
+            prcheightexpn = jpc_floorlog2(atoi(jas_tvparser_getval(tvp)));
+            break;
+        case OPT_CBLKWIDTH:
+            tccp->cblkwidthexpn =
+              jpc_floorlog2(atoi(jas_tvparser_getval(tvp)));
+            break;
+        case OPT_CBLKHEIGHT:
+            tccp->cblkheightexpn =
+              jpc_floorlog2(atoi(jas_tvparser_getval(tvp)));
+            break;
+        case OPT_MODE:
+            if ((tagid = jas_taginfo_nonull(jas_taginfos_lookup(modetab,
+              jas_tvparser_getval(tvp)))->id) < 0) {
+                fprintf(stderr,
+                  "ignoring invalid mode %s\n",
+                  jas_tvparser_getval(tvp));
+            } else {
+                tcp->intmode = (tagid == MODE_INT);
+            }
+            break;
+        case OPT_PRG:
+            if ((tagid = jas_taginfo_nonull(jas_taginfos_lookup(prgordtab,
+              jas_tvparser_getval(tvp)))->id) < 0) {
+                fprintf(stderr,
+                  "ignoring invalid progression order %s\n",
+                  jas_tvparser_getval(tvp));
+            } else {
+                tcp->prg = tagid;
+            }
+            break;
+        case OPT_NOMCT:
+            enablemct = false;
+            break;
+        case OPT_MAXRLVLS:
+            tccp->maxrlvls = atoi(jas_tvparser_getval(tvp));
+            break;
+        case OPT_SOP:
+            cp->tcp.csty |= JPC_COD_SOP;
+            break;
+        case OPT_EPH:
+            cp->tcp.csty |= JPC_COD_EPH;
+            break;
+        case OPT_LAZY:
+            tccp->cblksty |= JPC_COX_LAZY;
+            break;
+        case OPT_TERMALL:
+            tccp->cblksty |= JPC_COX_TERMALL;
+            break;
+        case OPT_SEGSYM:
+            tccp->cblksty |= JPC_COX_SEGSYM;
+            break;
+        case OPT_VCAUSAL:
+            tccp->cblksty |= JPC_COX_VSC;
+            break;
+        case OPT_RESET:
+            tccp->cblksty |= JPC_COX_RESET;
+            break;
+        case OPT_PTERM:
+            tccp->cblksty |= JPC_COX_PTERM;
+            break;
+        case OPT_NUMGBITS:
+            cp->tccp.numgbits = atoi(jas_tvparser_getval(tvp));
+            break;
+        case OPT_RATE:
+            if (ratestrtosize(jas_tvparser_getval(tvp), cp->rawsize,
+              &cp->totalsize)) {
+                fprintf(stderr,
+                  "ignoring bad rate specifier %s\n",
+                  jas_tvparser_getval(tvp));
+            }
+            break;
+        case OPT_ILYRRATES:
+            if (jpc_atoaf(jas_tvparser_getval(tvp), &numilyrrates,
+              &ilyrrates)) {
+                fprintf(stderr,
+                  "warning: invalid intermediate layer rates specifier ignored (%s)\n",
+                  jas_tvparser_getval(tvp));
+            }
+            break;
+
+        case OPT_JP2OVERHEAD:
+            jp2overhead = atoi(jas_tvparser_getval(tvp));
+            break;
+        default:
+            fprintf(stderr, "warning: ignoring invalid option %s\n",
+             jas_tvparser_gettag(tvp));
+            break;
+        }
+    }
+
+    jas_tvparser_destroy(tvp);
+    tvp = 0;
+
+    if (cp->totalsize != UINT_FAST32_MAX) {
+        cp->totalsize = (cp->totalsize > jp2overhead) ?
+          (cp->totalsize - jp2overhead) : 0;
+    }
+
+    if (cp->imgareatlx == UINT_FAST32_MAX) {
+        cp->imgareatlx = 0;
+    } else {
+        if (hsteplcm != 1) {
+            fprintf(stderr, "warning: overriding imgareatlx value\n");
+        }
+        cp->imgareatlx *= hsteplcm;
+    }
+    if (cp->imgareatly == UINT_FAST32_MAX) {
+        cp->imgareatly = 0;
+    } else {
+        if (vsteplcm != 1) {
+            fprintf(stderr, "warning: overriding imgareatly value\n");
+        }
+        cp->imgareatly *= vsteplcm;
+    }
+    cp->refgrdwidth = cp->imgareatlx + jas_image_width(image);
+    cp->refgrdheight = cp->imgareatly + jas_image_height(image);
+    if (cp->tilegrdoffx == UINT_FAST32_MAX) {
+        cp->tilegrdoffx = cp->imgareatlx;
+    }
+    if (cp->tilegrdoffy == UINT_FAST32_MAX) {
+        cp->tilegrdoffy = cp->imgareatly;
+    }
+    if (!cp->tilewidth) {
+        cp->tilewidth = cp->refgrdwidth - cp->tilegrdoffx;
+    }
+    if (!cp->tileheight) {
+        cp->tileheight = cp->refgrdheight - cp->tilegrdoffy;
+    }
+
+    if (cp->numcmpts == 3) {
+        mctvalid = true;
+        for (cmptno = 0; cmptno < jas_image_numcmpts(image); ++cmptno) {
+            if (jas_image_cmptprec(image, cmptno) != jas_image_cmptprec(image, 0) ||
+              jas_image_cmptsgnd(image, cmptno) != jas_image_cmptsgnd(image, 0) ||
+              jas_image_cmptwidth(image, cmptno) != jas_image_cmptwidth(image, 0) ||
+              jas_image_cmptheight(image, cmptno) != jas_image_cmptheight(image, 0)) {
+                mctvalid = false;
+            }
+        }
+    } else {
+        mctvalid = false;
+    }
+    if (mctvalid && enablemct && jas_image_colorspace(image) != JAS_IMAGE_CS_RGB) {
+        fprintf(stderr, "warning: color model apparently not RGB\n");
+    }
+    if (mctvalid && enablemct && jas_image_colorspace(image) == JAS_IMAGE_CS_RGB) {
+        tcp->mctid = (tcp->intmode) ? (JPC_MCT_RCT) : (JPC_MCT_ICT);
+    } else {
+        tcp->mctid = JPC_MCT_NONE;
+    }
+    tccp->qmfbid = (tcp->intmode) ? (JPC_COX_RFT) : (JPC_COX_INS);
+
+    for (rlvlno = 0; rlvlno < tccp->maxrlvls; ++rlvlno) {
+        tccp->prcwidthexpns[rlvlno] = prcwidthexpn;
+        tccp->prcheightexpns[rlvlno] = prcheightexpn;
+    }
+    if (prcwidthexpn != 15 || prcheightexpn != 15) {
+        tccp->csty |= JPC_COX_PRT;
+    }
+
+    /* Ensure that the tile width and height is valid. */
+    if (!cp->tilewidth) {
+        fprintf(stderr, "invalid tile width %lu\n", (unsigned long)
+          cp->tilewidth);
+        goto error;
+    }
+    if (!cp->tileheight) {
+        fprintf(stderr, "invalid tile height %lu\n", (unsigned long)
+          cp->tileheight);
+        goto error;
+    }
+
+    /* Ensure that the tile grid offset is valid. */
+    if (cp->tilegrdoffx > cp->imgareatlx ||
+      cp->tilegrdoffy > cp->imgareatly ||
+      cp->tilegrdoffx + cp->tilewidth < cp->imgareatlx ||
+      cp->tilegrdoffy + cp->tileheight < cp->imgareatly) {
+        fprintf(stderr, "invalid tile grid offset (%lu, %lu)\n",
+          (unsigned long) cp->tilegrdoffx, (unsigned long)
+          cp->tilegrdoffy);
+        goto error;
+    }
+
+    cp->numhtiles = JPC_CEILDIV(cp->refgrdwidth - cp->tilegrdoffx,
+      cp->tilewidth);
+    cp->numvtiles = JPC_CEILDIV(cp->refgrdheight - cp->tilegrdoffy,
+      cp->tileheight);
+    cp->numtiles = cp->numhtiles * cp->numvtiles;
+
+    if (ilyrrates && numilyrrates > 0) {
+        tcp->numlyrs = numilyrrates + 1;
+        if (!(tcp->ilyrrates = jas_malloc((tcp->numlyrs - 1) *
+          sizeof(jpc_fix_t)))) {
+            goto error;
+        }
+        for (i = 0; i < tcp->numlyrs - 1; ++i) {
+            tcp->ilyrrates[i] = jpc_dbltofix(ilyrrates[i]);
+        }
+    }
+
+    /* Ensure that the integer mode is used in the case of lossless
+      coding. */
+    if (cp->totalsize == UINT_FAST32_MAX && (!cp->tcp.intmode)) {
+        fprintf(stderr, "cannot use real mode for lossless coding\n");
+        goto error;
+    }
+
+    /* Ensure that the precinct width is valid. */
+    if (prcwidthexpn > 15) {
+        fprintf(stderr, "invalid precinct width\n");
+        goto error;
+    }
+
+    /* Ensure that the precinct height is valid. */
+    if (prcheightexpn > 15) {
+        fprintf(stderr, "invalid precinct height\n");
+        goto error;
+    }
+
+    /* Ensure that the code block width is valid. */
+    if (cp->tccp.cblkwidthexpn < 2 || cp->tccp.cblkwidthexpn > 12) {
+        fprintf(stderr, "invalid code block width %d\n",
+          JPC_POW2(cp->tccp.cblkwidthexpn));
+        goto error;
+    }
+
+    /* Ensure that the code block height is valid. */
+    if (cp->tccp.cblkheightexpn < 2 || cp->tccp.cblkheightexpn > 12) {
+        fprintf(stderr, "invalid code block height %d\n",
+          JPC_POW2(cp->tccp.cblkheightexpn));
+        goto error;
+    }
+
+    /* Ensure that the code block size is not too large. */
+    if (cp->tccp.cblkwidthexpn + cp->tccp.cblkheightexpn > 12) {
+        fprintf(stderr, "code block size too large\n");
+        goto error;
+    }
+
+    /* Ensure that the number of layers is valid. */
+    if (cp->tcp.numlyrs > 16384) {
+        fprintf(stderr, "too many layers\n");
+        goto error;
+    }
+
+    /* There must be at least one resolution level. */
+    if (cp->tccp.maxrlvls < 1) {
+        fprintf(stderr, "must be at least one resolution level\n");
+        goto error;
+    }
+
+    /* Ensure that the number of guard bits is valid. */
+    if (cp->tccp.numgbits > 8) {
+        fprintf(stderr, "invalid number of guard bits\n");
+        goto error;
+    }
+
+    /* Ensure that the intermediate layer rates are valid. */
+    if (tcp->numlyrs > 1) {
+        /* The intermediate layers rates must increase monotonically. */
+        for (lyrno = 0; lyrno + 2 < tcp->numlyrs; ++lyrno) {
+            if (tcp->ilyrrates[lyrno] >= tcp->ilyrrates[lyrno + 1]) {
+                fprintf(stderr, "intermediate layer rates must increase monotonically\n");
+                goto error;
+            }
+        }
+        /* The intermediate layer rates must be less than the overall rate. */
+        if (cp->totalsize != UINT_FAST32_MAX) {
+            for (lyrno = 0; lyrno < tcp->numlyrs - 1; ++lyrno) {
+                if (jpc_fixtodbl(tcp->ilyrrates[lyrno]) > ((double) cp->totalsize)
+                  / cp->rawsize) {
+                    fprintf(stderr, "warning: intermediate layer rates must be less than overall rate\n");
+                    goto error;
+                }
+            }
+        }
+    }
+
+    if (ilyrrates) {
+        jas_free(ilyrrates);
+    }
+
+    return cp;
 
 error:
 
-	if (ilyrrates) {
-		jas_free(ilyrrates);
-	}
-	if (tvp) {
-		jas_tvparser_destroy(tvp);
-	}
-	if (cp) {
-		jpc_enc_cp_destroy(cp);
-	}
-	return 0;
+    if (ilyrrates) {
+        jas_free(ilyrrates);
+    }
+    if (tvp) {
+        jas_tvparser_destroy(tvp);
+    }
+    if (cp) {
+        jpc_enc_cp_destroy(cp);
+    }
+    return 0;
 }
 
 void jpc_enc_cp_destroy(jpc_enc_cp_t *cp)
 {
-	if (cp->ccps) {
-		if (cp->tcp.ilyrrates) {
-			jas_free(cp->tcp.ilyrrates);
-		}
-		jas_free(cp->ccps);
-	}
-	jas_free(cp);
+    if (cp->ccps) {
+        if (cp->tcp.ilyrrates) {
+            jas_free(cp->tcp.ilyrrates);
+        }
+        jas_free(cp->ccps);
+    }
+    jas_free(cp);
 }
 
 int ratestrtosize(const char *s, uint_fast32_t rawsize, uint_fast32_t *size)
 {
-	char *cp;
-	jpc_flt_t f;
-
-	/* Note: This function must not modify output size on failure. */
-	if ((cp = strchr(s, 'B'))) {
-		*size = atoi(s);
-	} else {
-		f = atof(s);
-		if (f < 0) {
-			*size = 0;
-		} else if (f > 1.0) {
-			*size = rawsize + 1;
-		} else {
-			*size = f * rawsize;
-		}
-	}
-	return 0;
+    char *cp;
+    jpc_flt_t f;
+
+    /* Note: This function must not modify output size on failure. */
+    if ((cp = strchr(s, 'B'))) {
+        *size = atoi(s);
+    } else {
+        f = atof(s);
+        if (f < 0) {
+            *size = 0;
+        } else if (f > 1.0) {
+            *size = rawsize + 1;
+        } else {
+            *size = f * rawsize;
+        }
+    }
+    return 0;
 }
 
 /******************************************************************************\
@@ -852,58 +756,58 @@ int ratestrtosize(const char *s, uint_fast32_t rawsize, uint_fast32_t *size)
 
 jpc_enc_t *jpc_enc_create(jpc_enc_cp_t *cp, jas_stream_t *out, jas_image_t *image)
 {
-	jpc_enc_t *enc;
+    jpc_enc_t *enc;
 
-	enc = 0;
+    enc = 0;
 
-	if (!(enc = jas_malloc(sizeof(jpc_enc_t)))) {
-		goto error;
-	}
+    if (!(enc = jas_malloc(sizeof(jpc_enc_t)))) {
+        goto error;
+    }
 
-	enc->image = image;
-	enc->out = out;
-	enc->cp = cp;
-	enc->cstate = 0;
-	enc->tmpstream = 0;
-	enc->mrk = 0;
-	enc->curtile = 0;
+    enc->image = image;
+    enc->out = out;
+    enc->cp = cp;
+    enc->cstate = 0;
+    enc->tmpstream = 0;
+    enc->mrk = 0;
+    enc->curtile = 0;
 
-	if (!(enc->cstate = jpc_cstate_create())) {
-		goto error;
-	}
-	enc->len = 0;
-	enc->mainbodysize = 0;
+    if (!(enc->cstate = jpc_cstate_create())) {
+        goto error;
+    }
+    enc->len = 0;
+    enc->mainbodysize = 0;
 
-	return enc;
+    return enc;
 
 error:
 
-	if (enc) {
-		jpc_enc_destroy(enc);
-	}
-	return 0;
+    if (enc) {
+        jpc_enc_destroy(enc);
+    }
+    return 0;
 }
 
 void jpc_enc_destroy(jpc_enc_t *enc)
 {
-	/* The image object (i.e., enc->image) and output stream object
-	(i.e., enc->out) are created outside of the encoder.
-	Therefore, they must not be destroyed here. */
-
-	if (enc->curtile) {
-		jpc_enc_tile_destroy(enc->curtile);
-	}
-	if (enc->cp) {
-		jpc_enc_cp_destroy(enc->cp);
-	}
-	if (enc->cstate) {
-		jpc_cstate_destroy(enc->cstate);
-	}
-	if (enc->tmpstream) {
-		jas_stream_close(enc->tmpstream);
-	}
-
-	jas_free(enc);
+    /* The image object (i.e., enc->image) and output stream object
+    (i.e., enc->out) are created outside of the encoder.
+    Therefore, they must not be destroyed here. */
+
+    if (enc->curtile) {
+        jpc_enc_tile_destroy(enc->curtile);
+    }
+    if (enc->cp) {
+        jpc_enc_cp_destroy(enc->cp);
+    }
+    if (enc->cstate) {
+        jpc_cstate_destroy(enc->cstate);
+    }
+    if (enc->tmpstream) {
+        jas_stream_close(enc->tmpstream);
+    }
+
+    jas_free(enc);
 }
 
 /******************************************************************************\
@@ -912,1713 +816,2011 @@ void jpc_enc_destroy(jpc_enc_t *enc)
 
 static int jpc_enc_encodemainhdr(jpc_enc_t *enc)
 {
-	jpc_siz_t *siz;
-	jpc_cod_t *cod;
-	jpc_qcd_t *qcd;
-	int i;
+    jpc_siz_t *siz;
+    jpc_cod_t *cod;
+    jpc_qcd_t *qcd;
+    int i;
 long startoff;
 long mainhdrlen;
-	jpc_enc_cp_t *cp;
-	jpc_qcc_t *qcc;
-	jpc_enc_tccp_t *tccp;
-	uint_fast16_t cmptno;
-	jpc_tsfb_band_t bandinfos[JPC_MAXBANDS];
-	jpc_fix_t mctsynweight;
-	jpc_enc_tcp_t *tcp;
-	jpc_tsfb_t *tsfb;
-	jpc_tsfb_band_t *bandinfo;
-	uint_fast16_t numbands;
-	uint_fast16_t bandno;
-	uint_fast16_t rlvlno;
-	uint_fast16_t analgain;
-	jpc_fix_t absstepsize;
-	char buf[1024];
-	jpc_com_t *com;
-
-	cp = enc->cp;
+    jpc_enc_cp_t *cp;
+    jpc_qcc_t *qcc;
+    jpc_enc_tccp_t *tccp;
+    uint_fast16_t cmptno;
+    jpc_tsfb_band_t bandinfos[JPC_MAXBANDS];
+    jpc_fix_t mctsynweight;
+    jpc_enc_tcp_t *tcp;
+    jpc_tsfb_t *tsfb;
+    jpc_tsfb_band_t *bandinfo;
+    uint_fast16_t numbands;
+    uint_fast16_t bandno;
+    uint_fast16_t rlvlno;
+    uint_fast16_t analgain;
+    jpc_fix_t absstepsize;
+    char buf[1024];
+    jpc_com_t *com;
+
+    cp = enc->cp;
 
 startoff = jas_stream_getrwcount(enc->out);
 
-	/* Write SOC marker segment. */
-	if (!(enc->mrk = jpc_ms_create(JPC_MS_SOC))) {
-		return -1;
-	}
-	if (jpc_putms(enc->out, enc->cstate, enc->mrk)) {
-		fprintf(stderr, "cannot write SOC marker\n");
-		return -1;
-	}
-	jpc_ms_destroy(enc->mrk);
-	enc->mrk = 0;
-
-	/* Write SIZ marker segment. */
-	if (!(enc->mrk = jpc_ms_create(JPC_MS_SIZ))) {
-		return -1;
-	}
-	siz = &enc->mrk->parms.siz;
-	siz->caps = 0;
-	siz->xoff = cp->imgareatlx;
-	siz->yoff = cp->imgareatly;
-	siz->width = cp->refgrdwidth;
-	siz->height = cp->refgrdheight;
-	siz->tilexoff = cp->tilegrdoffx;
-	siz->tileyoff = cp->tilegrdoffy;
-	siz->tilewidth = cp->tilewidth;
-	siz->tileheight = cp->tileheight;
-	siz->numcomps = cp->numcmpts;
-	siz->comps = jas_malloc(siz->numcomps * sizeof(jpc_sizcomp_t));
-	assert(siz->comps);
-	for (i = 0; i < cp->numcmpts; ++i) {
-		siz->comps[i].prec = cp->ccps[i].prec;
-		siz->comps[i].sgnd = cp->ccps[i].sgnd;
-		siz->comps[i].hsamp = cp->ccps[i].sampgrdstepx;
-		siz->comps[i].vsamp = cp->ccps[i].sampgrdstepy;
-	}
-	if (jpc_putms(enc->out, enc->cstate, enc->mrk)) {
-		fprintf(stderr, "cannot write SIZ marker\n");
-		return -1;
-	}
-	jpc_ms_destroy(enc->mrk);
-	enc->mrk = 0;
-
-	if (!(enc->mrk = jpc_ms_create(JPC_MS_COM))) {
-		return -1;
-	}
-	sprintf(buf, "Creator: JasPer Version %s", jas_getversion());
-	com = &enc->mrk->parms.com;
-	com->len = strlen(buf);
-	com->regid = JPC_COM_LATIN;
-	if (!(com->data = JAS_CAST(unsigned char *, jas_strdup(buf)))) {
-		abort();
-	}
-	if (jpc_putms(enc->out, enc->cstate, enc->mrk)) {
-		fprintf(stderr, "cannot write COM marker\n");
-		return -1;
-	}
-	jpc_ms_destroy(enc->mrk);
-	enc->mrk = 0;
+    /* Write SOC marker segment. */
+    if (!(enc->mrk = jpc_ms_create(JPC_MS_SOC))) {
+        return -1;
+    }
+    if (jpc_putms(enc->out, enc->cstate, enc->mrk)) {
+        fprintf(stderr, "cannot write SOC marker\n");
+        return -1;
+    }
+    jpc_ms_destroy(enc->mrk);
+    enc->mrk = 0;
+
+    /* Write SIZ marker segment. */
+    if (!(enc->mrk = jpc_ms_create(JPC_MS_SIZ))) {
+        return -1;
+    }
+    siz = &enc->mrk->parms.siz;
+    siz->caps = 0;
+    siz->xoff = cp->imgareatlx;
+    siz->yoff = cp->imgareatly;
+    siz->width = cp->refgrdwidth;
+    siz->height = cp->refgrdheight;
+    siz->tilexoff = cp->tilegrdoffx;
+    siz->tileyoff = cp->tilegrdoffy;
+    siz->tilewidth = cp->tilewidth;
+    siz->tileheight = cp->tileheight;
+    siz->numcomps = cp->numcmpts;
+    siz->comps = jas_malloc(siz->numcomps * sizeof(jpc_sizcomp_t));
+    assert(siz->comps);
+    for (i = 0; i < cp->numcmpts; ++i) {
+        siz->comps[i].prec = cp->ccps[i].prec;
+        siz->comps[i].sgnd = cp->ccps[i].sgnd;
+        siz->comps[i].hsamp = cp->ccps[i].sampgrdstepx;
+        siz->comps[i].vsamp = cp->ccps[i].sampgrdstepy;
+    }
+    if (jpc_putms(enc->out, enc->cstate, enc->mrk)) {
+        fprintf(stderr, "cannot write SIZ marker\n");
+        return -1;
+    }
+    jpc_ms_destroy(enc->mrk);
+    enc->mrk = 0;
+
+    if (!(enc->mrk = jpc_ms_create(JPC_MS_COM))) {
+        return -1;
+    }
+    sprintf(buf, "Creator: JasPer Version %s", jas_getversion());
+    com = &enc->mrk->parms.com;
+    com->len = strlen(buf);
+    com->regid = JPC_COM_LATIN;
+    if (!(com->data = JAS_CAST(unsigned char *, jas_strdup(buf)))) {
+        abort();
+    }
+    if (jpc_putms(enc->out, enc->cstate, enc->mrk)) {
+        fprintf(stderr, "cannot write COM marker\n");
+        return -1;
+    }
+    jpc_ms_destroy(enc->mrk);
+    enc->mrk = 0;
 
 #if 0
-	if (!(enc->mrk = jpc_ms_create(JPC_MS_CRG))) {
-		return -1;
-	}
-	crg = &enc->mrk->parms.crg;
-	crg->comps = jas_malloc(crg->numcomps * sizeof(jpc_crgcomp_t));
-	if (jpc_putms(enc->out, enc->cstate, enc->mrk)) {
-		fprintf(stderr, "cannot write CRG marker\n");
-		return -1;
-	}
-	jpc_ms_destroy(enc->mrk);
-	enc->mrk = 0;
+    if (!(enc->mrk = jpc_ms_create(JPC_MS_CRG))) {
+        return -1;
+    }
+    crg = &enc->mrk->parms.crg;
+    crg->comps = jas_malloc(crg->numcomps * sizeof(jpc_crgcomp_t));
+    if (jpc_putms(enc->out, enc->cstate, enc->mrk)) {
+        fprintf(stderr, "cannot write CRG marker\n");
+        return -1;
+    }
+    jpc_ms_destroy(enc->mrk);
+    enc->mrk = 0;
 #endif
 
-	tcp = &cp->tcp;
-	tccp = &cp->tccp;
-	for (cmptno = 0; cmptno < cp->numcmpts; ++cmptno) {
-		tsfb = jpc_cod_gettsfb(tccp->qmfbid, tccp->maxrlvls - 1);
-		jpc_tsfb_getbands(tsfb, 0, 0, 1 << tccp->maxrlvls, 1 << tccp->maxrlvls,
-		  bandinfos);
-		jpc_tsfb_destroy(tsfb);
-		mctsynweight = jpc_mct_getsynweight(tcp->mctid, cmptno);
-		numbands = 3 * tccp->maxrlvls - 2;
-		for (bandno = 0, bandinfo = bandinfos; bandno < numbands;
-		  ++bandno, ++bandinfo) {
-			rlvlno = (bandno) ? ((bandno - 1) / 3 + 1) : 0;
-			analgain = JPC_NOMINALGAIN(tccp->qmfbid, tccp->maxrlvls,
-			  rlvlno, bandinfo->orient);
-			if (!tcp->intmode) {
-				absstepsize = jpc_fix_div(jpc_inttofix(1 <<
-				  (analgain + 1)), bandinfo->synenergywt);
-			} else {
-				absstepsize = jpc_inttofix(1);
-			}	
-			cp->ccps[cmptno].stepsizes[bandno] =
-			  jpc_abstorelstepsize(absstepsize,
-			  cp->ccps[cmptno].prec + analgain);
-		}
-		cp->ccps[cmptno].numstepsizes = numbands;
-	}
-
-	if (!(enc->mrk = jpc_ms_create(JPC_MS_COD))) {
-		return -1;
-	}
-	cod = &enc->mrk->parms.cod;
-	cod->csty = cp->tccp.csty | cp->tcp.csty;
-	cod->compparms.csty = cp->tccp.csty | cp->tcp.csty;
-	cod->compparms.numdlvls = cp->tccp.maxrlvls - 1;
-	cod->compparms.numrlvls = cp->tccp.maxrlvls;
-	cod->prg = cp->tcp.prg;
-	cod->numlyrs = cp->tcp.numlyrs;
-	cod->compparms.cblkwidthval = JPC_COX_CBLKSIZEEXPN(cp->tccp.cblkwidthexpn);
-	cod->compparms.cblkheightval = JPC_COX_CBLKSIZEEXPN(cp->tccp.cblkheightexpn);
-	cod->compparms.cblksty = cp->tccp.cblksty;
-	cod->compparms.qmfbid = cp->tccp.qmfbid;
-	cod->mctrans = (cp->tcp.mctid != JPC_MCT_NONE);
-	if (tccp->csty & JPC_COX_PRT) {
-		for (rlvlno = 0; rlvlno < tccp->maxrlvls; ++rlvlno) {
-			cod->compparms.rlvls[rlvlno].parwidthval = tccp->prcwidthexpns[rlvlno];
-			cod->compparms.rlvls[rlvlno].parheightval = tccp->prcheightexpns[rlvlno];
-		}
-	}
-	if (jpc_putms(enc->out, enc->cstate, enc->mrk)) {
-		fprintf(stderr, "cannot write COD marker\n");
-		return -1;
-	}
-	jpc_ms_destroy(enc->mrk);
-	enc->mrk = 0;
-
-	if (!(enc->mrk = jpc_ms_create(JPC_MS_QCD))) {
-		return -1;
-	}
-	qcd = &enc->mrk->parms.qcd;
-	qcd->compparms.qntsty = (tccp->qmfbid == JPC_COX_INS) ?
-	  JPC_QCX_SEQNT : JPC_QCX_NOQNT;
-	qcd->compparms.numstepsizes = cp->ccps[0].numstepsizes;
-	qcd->compparms.numguard = cp->tccp.numgbits;
-	qcd->compparms.stepsizes = cp->ccps[0].stepsizes;
-	if (jpc_putms(enc->out, enc->cstate, enc->mrk)) {
-		return -1;
-	}
-	/* We do not want the step size array to be freed! */
-	qcd->compparms.stepsizes = 0;
-	jpc_ms_destroy(enc->mrk);
-	enc->mrk = 0;
-
-	tccp = &cp->tccp;
-	for (cmptno = 1; cmptno < cp->numcmpts; ++cmptno) {
-		if (!(enc->mrk = jpc_ms_create(JPC_MS_QCC))) {
-			return -1;
-		}
-		qcc = &enc->mrk->parms.qcc;
-		qcc->compno = cmptno;
-		qcc->compparms.qntsty = (tccp->qmfbid == JPC_COX_INS) ?
-		  JPC_QCX_SEQNT : JPC_QCX_NOQNT;
-		qcc->compparms.numstepsizes = cp->ccps[cmptno].numstepsizes;
-		qcc->compparms.numguard = cp->tccp.numgbits;
-		qcc->compparms.stepsizes = cp->ccps[cmptno].stepsizes;
-		if (jpc_putms(enc->out, enc->cstate, enc->mrk)) {
-			return -1;
-		}
-		/* We do not want the step size array to be freed! */
-		qcc->compparms.stepsizes = 0;
-		jpc_ms_destroy(enc->mrk);
-		enc->mrk = 0;
-	}
-
-#define MAINTLRLEN	2
-	mainhdrlen = jas_stream_getrwcount(enc->out) - startoff;
-	enc->len += mainhdrlen;
-	if (enc->cp->totalsize != UINT_FAST32_MAX) {
-		uint_fast32_t overhead;
-		overhead = mainhdrlen + MAINTLRLEN;
-		enc->mainbodysize = (enc->cp->totalsize >= overhead) ?
-		  (enc->cp->totalsize - overhead) : 0;
-	} else {
-		enc->mainbodysize = UINT_FAST32_MAX;
-	}
-
-	return 0;
+    tcp = &cp->tcp;
+    tccp = &cp->tccp;
+    for (cmptno = 0; cmptno < cp->numcmpts; ++cmptno) {
+        tsfb = jpc_cod_gettsfb(tccp->qmfbid, tccp->maxrlvls - 1);
+        jpc_tsfb_getbands(tsfb, 0, 0, 1 << tccp->maxrlvls, 1 << tccp->maxrlvls,
+          bandinfos);
+        jpc_tsfb_destroy(tsfb);
+        mctsynweight = jpc_mct_getsynweight(tcp->mctid, cmptno);
+        numbands = 3 * tccp->maxrlvls - 2;
+        for (bandno = 0, bandinfo = bandinfos; bandno < numbands;
+          ++bandno, ++bandinfo) {
+            rlvlno = (bandno) ? ((bandno - 1) / 3 + 1) : 0;
+            analgain = JPC_NOMINALGAIN(tccp->qmfbid, tccp->maxrlvls,
+              rlvlno, bandinfo->orient);
+            if (!tcp->intmode) {
+                absstepsize = jpc_fix_div(jpc_inttofix(1 <<
+                  (analgain + 1)), bandinfo->synenergywt);
+            } else {
+                absstepsize = jpc_inttofix(1);
+            }   
+            cp->ccps[cmptno].stepsizes[bandno] =
+              jpc_abstorelstepsize(absstepsize,
+              cp->ccps[cmptno].prec + analgain);
+        }
+        cp->ccps[cmptno].numstepsizes = numbands;
+    }
+
+    if (!(enc->mrk = jpc_ms_create(JPC_MS_COD))) {
+        return -1;
+    }
+    cod = &enc->mrk->parms.cod;
+    cod->csty = cp->tccp.csty | cp->tcp.csty;
+    cod->compparms.csty = cp->tccp.csty | cp->tcp.csty;
+    cod->compparms.numdlvls = cp->tccp.maxrlvls - 1;
+    cod->compparms.numrlvls = cp->tccp.maxrlvls;
+    cod->prg = cp->tcp.prg;
+    cod->numlyrs = cp->tcp.numlyrs;
+    cod->compparms.cblkwidthval = JPC_COX_CBLKSIZEEXPN(cp->tccp.cblkwidthexpn);
+    cod->compparms.cblkheightval = JPC_COX_CBLKSIZEEXPN(cp->tccp.cblkheightexpn);
+    cod->compparms.cblksty = cp->tccp.cblksty;
+    cod->compparms.qmfbid = cp->tccp.qmfbid;
+    cod->mctrans = (cp->tcp.mctid != JPC_MCT_NONE);
+    if (tccp->csty & JPC_COX_PRT) {
+        for (rlvlno = 0; rlvlno < tccp->maxrlvls; ++rlvlno) {
+            cod->compparms.rlvls[rlvlno].parwidthval = tccp->prcwidthexpns[rlvlno];
+            cod->compparms.rlvls[rlvlno].parheightval = tccp->prcheightexpns[rlvlno];
+        }
+    }
+    if (jpc_putms(enc->out, enc->cstate, enc->mrk)) {
+        fprintf(stderr, "cannot write COD marker\n");
+        return -1;
+    }
+    jpc_ms_destroy(enc->mrk);
+    enc->mrk = 0;
+
+    if (!(enc->mrk = jpc_ms_create(JPC_MS_QCD))) {
+        return -1;
+    }
+    qcd = &enc->mrk->parms.qcd;
+    qcd->compparms.qntsty = (tccp->qmfbid == JPC_COX_INS) ?
+      JPC_QCX_SEQNT : JPC_QCX_NOQNT;
+    qcd->compparms.numstepsizes = cp->ccps[0].numstepsizes;
+    qcd->compparms.numguard = cp->tccp.numgbits;
+    qcd->compparms.stepsizes = cp->ccps[0].stepsizes;
+    if (jpc_putms(enc->out, enc->cstate, enc->mrk)) {
+        return -1;
+    }
+    /* We do not want the step size array to be freed! */
+    qcd->compparms.stepsizes = 0;
+    jpc_ms_destroy(enc->mrk);
+    enc->mrk = 0;
+
+    tccp = &cp->tccp;
+    for (cmptno = 1; cmptno < cp->numcmpts; ++cmptno) {
+        if (!(enc->mrk = jpc_ms_create(JPC_MS_QCC))) {
+            return -1;
+        }
+        qcc = &enc->mrk->parms.qcc;
+        qcc->compno = cmptno;
+        qcc->compparms.qntsty = (tccp->qmfbid == JPC_COX_INS) ?
+          JPC_QCX_SEQNT : JPC_QCX_NOQNT;
+        qcc->compparms.numstepsizes = cp->ccps[cmptno].numstepsizes;
+        qcc->compparms.numguard = cp->tccp.numgbits;
+        qcc->compparms.stepsizes = cp->ccps[cmptno].stepsizes;
+        if (jpc_putms(enc->out, enc->cstate, enc->mrk)) {
+            return -1;
+        }
+        /* We do not want the step size array to be freed! */
+        qcc->compparms.stepsizes = 0;
+        jpc_ms_destroy(enc->mrk);
+        enc->mrk = 0;
+    }
+
+#define MAINTLRLEN  2
+    mainhdrlen = jas_stream_getrwcount(enc->out) - startoff;
+    enc->len += mainhdrlen;
+    if (enc->cp->totalsize != UINT_FAST32_MAX) {
+        uint_fast32_t overhead;
+        overhead = mainhdrlen + MAINTLRLEN;
+        enc->mainbodysize = (enc->cp->totalsize >= overhead) ?
+          (enc->cp->totalsize - overhead) : 0;
+    } else {
+        enc->mainbodysize = UINT_FAST32_MAX;
+    }
+
+    return 0;
 }
 
-static int jpc_enc_encodemainbody(jpc_enc_t *enc)
+int jpc_enc_encodetiledata(jpc_enc_t *enc)
 {
-	int tileno;
-	int tilex;
-	int tiley;
-	int i;
-	jpc_sot_t *sot;
-	jpc_enc_tcmpt_t *comp;
-	jpc_enc_tcmpt_t *endcomps;
-	jpc_enc_band_t *band;
-	jpc_enc_band_t *endbands;
-	jpc_enc_rlvl_t *lvl;
-	int rlvlno;
-	jpc_qcc_t *qcc;
-	jpc_cod_t *cod;
-	int adjust;
-	int j;
-	int absbandno;
-	long numbytes;
-	long tilehdrlen;
-	long tilelen;
-	jpc_enc_tile_t *tile;
-	jpc_enc_cp_t *cp;
-	double rho;
-	uint_fast16_t lyrno;
-	uint_fast16_t cmptno;
-	int samestepsizes;
-	jpc_enc_ccp_t *ccps;
-	jpc_enc_tccp_t *tccp;
-int bandno;
-uint_fast32_t x;
-uint_fast32_t y;
-int mingbits;
-int actualnumbps;
-jpc_fix_t mxmag;
-jpc_fix_t mag;
-int numgbits;
-
-	cp = enc->cp;
-
-	/* Avoid compile warnings. */
-	numbytes = 0;
-
-	for (tileno = 0; tileno < cp->numtiles; ++tileno) {
-		tilex = tileno % cp->numhtiles;
-		tiley = tileno / cp->numhtiles;
-
-		if (!(enc->curtile = jpc_enc_tile_create(enc->cp, enc->image, tileno))) {
-			abort();
-		}
-
-		tile = enc->curtile;
-
-		if (jas_getdbglevel() >= 10) {
-			jpc_enc_dump(enc);
-		}
-
-		endcomps = &tile->tcmpts[tile->numtcmpts];
-		for (cmptno = 0, comp = tile->tcmpts; cmptno < tile->numtcmpts; ++cmptno, ++comp) {
-			if (!cp->ccps[cmptno].sgnd) {
-				adjust = 1 << (cp->ccps[cmptno].prec - 1);
-				for (i = 0; i < jas_matrix_numrows(comp->data); ++i) {
-					for (j = 0; j < jas_matrix_numcols(comp->data); ++j) {
-						*jas_matrix_getref(comp->data, i, j) -= adjust;
-					}
-				}
-			}
-		}
-
-		if (!tile->intmode) {
-				endcomps = &tile->tcmpts[tile->numtcmpts];
-				for (comp = tile->tcmpts; comp != endcomps; ++comp) {
-					jas_matrix_asl(comp->data, JPC_FIX_FRACBITS);
-				}
-		}
-
-		switch (tile->mctid) {
-		case JPC_MCT_RCT:
-assert(jas_image_numcmpts(enc->image) == 3);
-			jpc_rct(tile->tcmpts[0].data, tile->tcmpts[1].data,
-			  tile->tcmpts[2].data);
-			break;
-		case JPC_MCT_ICT:
-assert(jas_image_numcmpts(enc->image) == 3);
-			jpc_ict(tile->tcmpts[0].data, tile->tcmpts[1].data,
-			  tile->tcmpts[2].data);
-			break;
-		default:
-			break;
-		}
-
-		for (i = 0; i < jas_image_numcmpts(enc->image); ++i) {
-			comp = &tile->tcmpts[i];
-			jpc_tsfb_analyze(comp->tsfb, ((comp->qmfbid == JPC_COX_RFT) ? JPC_TSFB_RITIMODE : 0), comp->data);
-
-		}
-
-
-		endcomps = &tile->tcmpts[tile->numtcmpts];
-		for (cmptno = 0, comp = tile->tcmpts; comp != endcomps; ++cmptno, ++comp) {
-			mingbits = 0;
-			absbandno = 0;
-			/* All bands must have a corresponding quantizer step size,
-			  even if they contain no samples and are never coded. */
-			/* Some bands may not be hit by the loop below, so we must
-			  initialize all of the step sizes to a sane value. */
-			memset(comp->stepsizes, 0, sizeof(comp->stepsizes));
-			for (rlvlno = 0, lvl = comp->rlvls; rlvlno < comp->numrlvls; ++rlvlno, ++lvl) {
-				if (!lvl->bands) {
-					absbandno += rlvlno ? 3 : 1;
-					continue;
-				}
-				endbands = &lvl->bands[lvl->numbands];
-				for (band = lvl->bands; band != endbands; ++band) {
-					if (!band->data) {
-						++absbandno;
-						continue;
-					}
-					actualnumbps = 0;
-					mxmag = 0;
-					for (y = 0; y < jas_matrix_numrows(band->data); ++y) {
-						for (x = 0; x < jas_matrix_numcols(band->data); ++x) {
-							mag = abs(jas_matrix_get(band->data, y, x));
-							if (mag > mxmag) {
-								mxmag = mag;
-							}
-						}
-					}
-					if (tile->intmode) {
-						actualnumbps = jpc_firstone(mxmag) + 1;
-					} else {
-						actualnumbps = jpc_firstone(mxmag) + 1 - JPC_FIX_FRACBITS;
-					}
-					numgbits = actualnumbps - (cp->ccps[cmptno].prec - 1 +
-					  band->analgain);
-#if 0
-fprintf(stderr, "%d %d mag=%d actual=%d numgbits=%d\n", cp->ccps[cmptno].prec, band->analgain, mxmag, actualnumbps, numgbits);
-#endif
-					if (numgbits > mingbits) {
-						mingbits = numgbits;
-					}
-					if (!tile->intmode) {
-						band->absstepsize = jpc_fix_div(jpc_inttofix(1
-						  << (band->analgain + 1)),
-						  band->synweight);
-					} else {
-						band->absstepsize = jpc_inttofix(1);
-					}
-					band->stepsize = jpc_abstorelstepsize(
-					  band->absstepsize, cp->ccps[cmptno].prec +
-					  band->analgain);
-					band->numbps = cp->tccp.numgbits +
-					  JPC_QCX_GETEXPN(band->stepsize) - 1;
-
-					if ((!tile->intmode) && band->data) {
-						quantize(band->data, band->absstepsize);
-					}
-
-					comp->stepsizes[absbandno] = band->stepsize;
-					++absbandno;
-				}
-			}
-
-			assert(JPC_FIX_FRACBITS >= JPC_NUMEXTRABITS);
-			if (!tile->intmode) {
-				jas_matrix_divpow2(comp->data, JPC_FIX_FRACBITS - JPC_NUMEXTRABITS);
-			} else {
-				jas_matrix_asl(comp->data, JPC_NUMEXTRABITS);
-			}
-		}
-#if 0
-fprintf(stderr, "mingbits %d\n", mingbits);
-#endif
+assert(enc->tmpstream);
+    if (jpc_enc_encpkts(enc, enc->tmpstream)) {
+        return -1;
+    }
+    return 0;
+}
 
-		if (mingbits > cp->tccp.numgbits) {
-			fprintf(stderr, "error: too few guard bits (need at least %d)\n",
-			  mingbits);
-			return -1;
-		}
-
-		if (!(enc->tmpstream = jas_stream_memopen(0, 0))) {
-			fprintf(stderr, "cannot open tmp file\n");
-			return -1;
-		}
-
-		/* Write the tile header. */
-		if (!(enc->mrk = jpc_ms_create(JPC_MS_SOT))) {
-			return -1;
-		}
-		sot = &enc->mrk->parms.sot;
-		sot->len = 0;
-		sot->tileno = tileno;
-		sot->partno = 0;
-		sot->numparts = 1;
-		if (jpc_putms(enc->tmpstream, enc->cstate, enc->mrk)) {
-			fprintf(stderr, "cannot write SOT marker\n");
-			return -1;
-		}
-		jpc_ms_destroy(enc->mrk);
-		enc->mrk = 0;
+void quantize(jas_matrix_t *data, jpc_fix_t stepsize)
+{
+    int i;
+    int j;
+    jpc_fix_t t;
 
-/************************************************************************/
-/************************************************************************/
-/************************************************************************/
+    if (stepsize == jpc_inttofix(1)) {
+        return;
+    }
 
-		tccp = &cp->tccp;
-		for (cmptno = 0; cmptno < cp->numcmpts; ++cmptno) {
-			comp = &tile->tcmpts[cmptno];
-			if (comp->numrlvls != tccp->maxrlvls) {
-				if (!(enc->mrk = jpc_ms_create(JPC_MS_COD))) {
-					return -1;
-				}
-/* XXX = this is not really correct. we are using comp #0's precint sizes
-and other characteristics */
-				comp = &tile->tcmpts[0];
-				cod = &enc->mrk->parms.cod;
-				cod->compparms.csty = 0;
-				cod->compparms.numdlvls = comp->numrlvls - 1;
-				cod->prg = tile->prg;
-				cod->numlyrs = tile->numlyrs;
-				cod->compparms.cblkwidthval = JPC_COX_CBLKSIZEEXPN(comp->cblkwidthexpn);
-				cod->compparms.cblkheightval = JPC_COX_CBLKSIZEEXPN(comp->cblkheightexpn);
-				cod->compparms.cblksty = comp->cblksty;
-				cod->compparms.qmfbid = comp->qmfbid;
-				cod->mctrans = (tile->mctid != JPC_MCT_NONE);
-				for (i = 0; i < comp->numrlvls; ++i) {
-					cod->compparms.rlvls[i].parwidthval = comp->rlvls[i].prcwidthexpn;
-					cod->compparms.rlvls[i].parheightval = comp->rlvls[i].prcheightexpn;
-				}
-				if (jpc_putms(enc->tmpstream, enc->cstate, enc->mrk)) {
-					return -1;
-				}
-				jpc_ms_destroy(enc->mrk);
-				enc->mrk = 0;
-			}
-		}
-
-		for (cmptno = 0, comp = tile->tcmpts; cmptno < cp->numcmpts; ++cmptno, ++comp) {
-			ccps = &cp->ccps[cmptno];
-			if (ccps->numstepsizes == comp->numstepsizes) {
-				samestepsizes = 1;
-				for (bandno = 0; bandno < ccps->numstepsizes; ++bandno) {
-					if (ccps->stepsizes[bandno] != comp->stepsizes[bandno]) {
-						samestepsizes = 0;
-						break;
-					}
-				}
-			} else {
-				samestepsizes = 0;
-			}
-			if (!samestepsizes) {
-				if (!(enc->mrk = jpc_ms_create(JPC_MS_QCC))) {
-					return -1;
-				}
-				qcc = &enc->mrk->parms.qcc;
-				qcc->compno = cmptno;
-				qcc->compparms.numguard = cp->tccp.numgbits;
-				qcc->compparms.qntsty = (comp->qmfbid == JPC_COX_INS) ?
-				  JPC_QCX_SEQNT : JPC_QCX_NOQNT;
-				qcc->compparms.numstepsizes = comp->numstepsizes;
-				qcc->compparms.stepsizes = comp->stepsizes;
-				if (jpc_putms(enc->tmpstream, enc->cstate, enc->mrk)) {
-					return -1;
-				}
-				qcc->compparms.stepsizes = 0;
-				jpc_ms_destroy(enc->mrk);
-				enc->mrk = 0;
-			}
-		}
-
-		/* Write a SOD marker to indicate the end of the tile header. */
-		if (!(enc->mrk = jpc_ms_create(JPC_MS_SOD))) {
-			return -1;
-		}
-		if (jpc_putms(enc->tmpstream, enc->cstate, enc->mrk)) {
-			fprintf(stderr, "cannot write SOD marker\n");
-			return -1;
-		}
-		jpc_ms_destroy(enc->mrk);
-		enc->mrk = 0;
-tilehdrlen = jas_stream_getrwcount(enc->tmpstream);
+    for (i = 0; i < jas_matrix_numrows(data); ++i) {
+        for (j = 0; j < jas_matrix_numcols(data); ++j) {
+            t = jas_matrix_get(data, i, j);
 
-/************************************************************************/
-/************************************************************************/
-/************************************************************************/
+{
+    if (t < 0) {
+        t = jpc_fix_neg(jpc_fix_div(jpc_fix_neg(t), stepsize));
+    } else {
+        t = jpc_fix_div(t, stepsize);
+    }
+}
 
-if (jpc_enc_enccblks(enc)) {
-	abort();
-	return -1;
+            jas_matrix_set(data, i, j, t);
+        }
+    }
 }
 
-		cp = enc->cp;
-		rho = (double) (tile->brx - tile->tlx) * (tile->bry - tile->tly) /
-		  ((cp->refgrdwidth - cp->imgareatlx) * (cp->refgrdheight -
-		  cp->imgareatly));
-		tile->rawsize = cp->rawsize * rho;
-
-		for (lyrno = 0; lyrno < tile->numlyrs - 1; ++lyrno) {
-			tile->lyrsizes[lyrno] = tile->rawsize * jpc_fixtodbl(
-			  cp->tcp.ilyrrates[lyrno]);
-		}
-		tile->lyrsizes[tile->numlyrs - 1] = (cp->totalsize != UINT_FAST32_MAX) ?
-		  (rho * enc->mainbodysize) : UINT_FAST32_MAX;
-		for (lyrno = 0; lyrno < tile->numlyrs; ++lyrno) {
-			if (tile->lyrsizes[lyrno] != UINT_FAST32_MAX) {
-				if (tilehdrlen <= tile->lyrsizes[lyrno]) {
-					tile->lyrsizes[lyrno] -= tilehdrlen;
-				} else {
-					tile->lyrsizes[lyrno] = 0;
-				}
-			}
-		}
-
-		if (rateallocate(enc, tile->numlyrs, tile->lyrsizes)) {
-			return -1;
-		}
+static void calcrdslopes(jpc_enc_cblk_t *cblk)
+{
+    jpc_enc_pass_t *endpasses;
+    jpc_enc_pass_t *pass0;
+    jpc_enc_pass_t *pass1;
+    jpc_enc_pass_t *pass2;
+    jpc_flt_t slope0;
+    jpc_flt_t slope;
+    jpc_flt_t dd;
+    long dr;
+
+    endpasses = &cblk->passes[cblk->numpasses];
+    pass2 = cblk->passes;
+    slope0 = 0;
+    while (pass2 != endpasses) {
+        pass0 = 0;
+        for (pass1 = cblk->passes; pass1 != endpasses; ++pass1) {
+            dd = pass1->cumwmsedec;
+            dr = pass1->end;
+            if (pass0) {
+                dd -= pass0->cumwmsedec;
+                dr -= pass0->end;
+            }
+            if (dd <= 0) {
+                pass1->rdslope = JPC_BADRDSLOPE;
+                if (pass1 >= pass2) {
+                    pass2 = &pass1[1];
+                }
+                continue;
+            }
+            if (pass1 < pass2 && pass1->rdslope <= 0) {
+                continue;
+            }
+            if (!dr) {
+                assert(pass0);
+                pass0->rdslope = 0;
+                break;
+            }
+            slope = dd / dr;
+            if (pass0 && slope >= slope0) {
+                pass0->rdslope = 0;
+                break;
+            }
+            pass1->rdslope = slope;
+            if (pass1 >= pass2) {
+                pass2 = &pass1[1];
+            }
+            pass0 = pass1;
+            slope0 = slope;
+        }
+    }
 
 #if 0
-fprintf(stderr, "ENCODE TILE DATA\n");
+    for (pass0 = cblk->passes; pass0 != endpasses; ++pass0) {
+if (pass0->rdslope > 0.0) {
+        fprintf(stderr, "pass %02d nmsedec=%lf dec=%lf end=%d %lf\n", pass0 - cblk->passes,
+          fixtodbl(pass0->nmsedec), pass0->wmsedec, pass0->end, pass0->rdslope);
+}
+    }
 #endif
-		if (jpc_enc_encodetiledata(enc)) {
-			fprintf(stderr, "dotile failed\n");
-			return -1;
-		}
+}
 
-/************************************************************************/
-/************************************************************************/
-/************************************************************************/
 
-/************************************************************************/
-/************************************************************************/
-/************************************************************************/
 
-		tilelen = jas_stream_tell(enc->tmpstream);
+static void
+traceLayerSizes(const uint_fast32_t * const lyrSizes,
+                unsigned int          const layerCt) {
+
+    if (jas_getdbglevel() > 0) {
+        unsigned int i;
+        for (i = 0; i < layerCt; ++i) {
+            fprintf(stderr, "Layer %u size = ", i);
 
-		if (jas_stream_seek(enc->tmpstream, 6, SEEK_SET) < 0) {
-			return -1;
-		}
-		jpc_putuint32(enc->tmpstream, tilelen);
+            if (lyrSizes[i] == UINT_FAST32_MAX)
+                fprintf(stderr, "Unlimited");
+            else
+                fprintf(stderr, "%u", (unsigned)lyrSizes[i]);
+            fprintf(stderr, "\n");
+        }
+    }
+}
 
-		if (jas_stream_seek(enc->tmpstream, 0, SEEK_SET) < 0) {
-			return -1;
-		}
-		if (jpc_putdata(enc->out, enc->tmpstream, -1)) {
-			return -1;
-		}
-		enc->len += tilelen;
 
-		jas_stream_close(enc->tmpstream);
-		enc->tmpstream = 0;
 
-		jpc_enc_tile_destroy(enc->curtile);
-		enc->curtile = 0;
+static void
+computeLayerSizes(jpc_enc_t *      const encP,
+                  jpc_enc_tile_t * const tileP,
+                  jpc_enc_cp_t *   const cpP,
+                  double           const rho,
+                  long             const tilehdrlen,
+                  const char **    const errorP) {
 
-	}
+    /* Note that in allowed sizes, UINT_FAST32_MAX is a special value meaning
+       "unlimited".
+    */
 
-	return 0;
-}
+    unsigned int const lastLyrno = tileP->numlyrs - 1;
 
-int jpc_enc_encodetiledata(jpc_enc_t *enc)
-{
-assert(enc->tmpstream);
-	if (jpc_enc_encpkts(enc, enc->tmpstream)) {
-		return -1;
-	}
-	return 0;
-}
+    unsigned int lyrno;
 
-void quantize(jas_matrix_t *data, jpc_fix_t stepsize)
-{
-	int i;
-	int j;
-	jpc_fix_t t;
+    assert(tileP->numlyrs > 0);
 
-	if (stepsize == jpc_inttofix(1)) {
-		return;
-	}
+    for (lyrno = 0; lyrno < lastLyrno; ++lyrno) {
+        tileP->lyrsizes[lyrno] = tileP->rawsize * jpc_fixtodbl(
+            cpP->tcp.ilyrrates[lyrno]);
+    }
 
-	for (i = 0; i < jas_matrix_numrows(data); ++i) {
-		for (j = 0; j < jas_matrix_numcols(data); ++j) {
-			t = jas_matrix_get(data, i, j);
+    tileP->lyrsizes[lastLyrno] =
+        (cpP->totalsize != UINT_FAST32_MAX) ?
+        (rho * encP->mainbodysize) : UINT_FAST32_MAX;
 
-{
-	if (t < 0) {
-		t = jpc_fix_neg(jpc_fix_div(jpc_fix_neg(t), stepsize));
-	} else {
-		t = jpc_fix_div(t, stepsize);
-	}
-}
 
-			jas_matrix_set(data, i, j, t);
-		}
-	}
+    /* Subtract 'tilehdrlen' from every layer. */
+
+    for (lyrno = 0; lyrno < tileP->numlyrs; ++lyrno) {
+        if (tileP->lyrsizes[lyrno] != UINT_FAST32_MAX) {
+            if (tilehdrlen <= tileP->lyrsizes[lyrno]) {
+                tileP->lyrsizes[lyrno] -= tilehdrlen;
+            } else {
+                tileP->lyrsizes[lyrno] = 0;
+            }
+        }
+    }
+
+    if (tileP->lyrsizes[lastLyrno] < 1)
+        pm_asprintf(errorP, "Cannot make image that small (%u bytes).  "
+                    "Even with pixels compressed as far as possible, metadata "
+                    "would exceed the limit",
+                    (unsigned)cpP->totalsize);
+    else
+        *errorP = NULL;
+
+    traceLayerSizes(tileP->lyrsizes, tileP->numlyrs);
 }
 
-static void calcrdslopes(jpc_enc_cblk_t *cblk)
+
+
+static void dump_layeringinfo(jpc_enc_t *enc)
 {
-	jpc_enc_pass_t *endpasses;
-	jpc_enc_pass_t *pass0;
-	jpc_enc_pass_t *pass1;
-	jpc_enc_pass_t *pass2;
-	jpc_flt_t slope0;
-	jpc_flt_t slope;
-	jpc_flt_t dd;
-	long dr;
-
-	endpasses = &cblk->passes[cblk->numpasses];
-	pass2 = cblk->passes;
-	slope0 = 0;
-	while (pass2 != endpasses) {
-		pass0 = 0;
-		for (pass1 = cblk->passes; pass1 != endpasses; ++pass1) {
-			dd = pass1->cumwmsedec;
-			dr = pass1->end;
-			if (pass0) {
-				dd -= pass0->cumwmsedec;
-				dr -= pass0->end;
-			}
-			if (dd <= 0) {
-				pass1->rdslope = JPC_BADRDSLOPE;
-				if (pass1 >= pass2) {
-					pass2 = &pass1[1];
-				}
-				continue;
-			}
-			if (pass1 < pass2 && pass1->rdslope <= 0) {
-				continue;
-			}
-			if (!dr) {
-				assert(pass0);
-				pass0->rdslope = 0;
-				break;
-			}
-			slope = dd / dr;
-			if (pass0 && slope >= slope0) {
-				pass0->rdslope = 0;
-				break;
-			}
-			pass1->rdslope = slope;
-			if (pass1 >= pass2) {
-				pass2 = &pass1[1];
-			}
-			pass0 = pass1;
-			slope0 = slope;
-		}
-	}
 
-#if 0
-	for (pass0 = cblk->passes; pass0 != endpasses; ++pass0) {
-if (pass0->rdslope > 0.0) {
-		fprintf(stderr, "pass %02d nmsedec=%lf dec=%lf end=%d %lf\n", pass0 - cblk->passes,
-		  fixtodbl(pass0->nmsedec), pass0->wmsedec, pass0->end, pass0->rdslope);
+    jpc_enc_tcmpt_t *tcmpt;
+    uint_fast16_t tcmptno;
+    jpc_enc_rlvl_t *rlvl;
+    uint_fast16_t rlvlno;
+    jpc_enc_band_t *band;
+    uint_fast16_t bandno;
+    jpc_enc_prc_t *prc;
+    uint_fast32_t prcno;
+    jpc_enc_cblk_t *cblk;
+    uint_fast16_t cblkno;
+    jpc_enc_pass_t *pass;
+    uint_fast16_t passno;
+    int lyrno;
+    jpc_enc_tile_t *tile;
+
+    tile = enc->curtile;
+
+    for (lyrno = 0; lyrno < tile->numlyrs; ++lyrno) {
+        fprintf(stderr, "lyrno = %02d\n", lyrno);
+        for (tcmptno = 0, tcmpt = tile->tcmpts; tcmptno < tile->numtcmpts;
+          ++tcmptno, ++tcmpt) {
+            for (rlvlno = 0, rlvl = tcmpt->rlvls; rlvlno < tcmpt->numrlvls;
+              ++rlvlno, ++rlvl) {
+                if (!rlvl->bands) {
+                    continue;
+                }
+                for (bandno = 0, band = rlvl->bands; bandno < rlvl->numbands;
+                  ++bandno, ++band) {
+                    if (!band->data) {
+                        continue;
+                    }
+                    for (prcno = 0, prc = band->prcs; prcno < rlvl->numprcs;
+                      ++prcno, ++prc) {
+                        if (!prc->cblks) {
+                            continue;
+                        }
+                        for (cblkno = 0, cblk = prc->cblks; cblkno <
+                          prc->numcblks; ++cblkno, ++cblk) {
+                            for (passno = 0, pass = cblk->passes;
+                                 passno < cblk->numpasses &&
+                                     pass->lyrno == lyrno;
+                                 ++passno, ++pass) {
+                                fprintf(stderr,
+                                        "lyrno=%02d cmptno=%02d "
+                                        "rlvlno=%02d bandno=%02d "
+                                        "prcno=%02d cblkno=%03d "
+                                        "passno=%03d\n",
+                                        lyrno, (int)tcmptno, (int)rlvlno,
+                                        (int)bandno, (int)prcno, (int) cblkno,
+                                        (int)passno);
+                            }
+                        }
+                    }
+                }
+            }
+        }
+    }
 }
-	}
-#endif
+
+
+
+
+static void
+trace_layeringinfo(jpc_enc_t * const encP) {
+
+    if (jas_getdbglevel() >= 5)
+        dump_layeringinfo(encP);
 }
 
-static void dump_layeringinfo(jpc_enc_t *enc)
-{
 
-	jpc_enc_tcmpt_t *tcmpt;
-	uint_fast16_t tcmptno;
-	jpc_enc_rlvl_t *rlvl;
-	uint_fast16_t rlvlno;
-	jpc_enc_band_t *band;
-	uint_fast16_t bandno;
-	jpc_enc_prc_t *prc;
-	uint_fast32_t prcno;
-	jpc_enc_cblk_t *cblk;
-	uint_fast16_t cblkno;
-	jpc_enc_pass_t *pass;
-	uint_fast16_t passno;
-	int lyrno;
-	jpc_enc_tile_t *tile;
-
-	tile = enc->curtile;
-
-	for (lyrno = 0; lyrno < tile->numlyrs; ++lyrno) {
-		fprintf(stderr, "lyrno = %02d\n", lyrno);
-		for (tcmptno = 0, tcmpt = tile->tcmpts; tcmptno < tile->numtcmpts;
-		  ++tcmptno, ++tcmpt) {
-			for (rlvlno = 0, rlvl = tcmpt->rlvls; rlvlno < tcmpt->numrlvls;
-			  ++rlvlno, ++rlvl) {
-				if (!rlvl->bands) {
-					continue;
-				}
-				for (bandno = 0, band = rlvl->bands; bandno < rlvl->numbands;
-				  ++bandno, ++band) {
-					if (!band->data) {
-						continue;
-					}
-					for (prcno = 0, prc = band->prcs; prcno < rlvl->numprcs;
-					  ++prcno, ++prc) {
-						if (!prc->cblks) {
-							continue;
-						}
-						for (cblkno = 0, cblk = prc->cblks; cblkno <
-						  prc->numcblks; ++cblkno, ++cblk) {
-							for (passno = 0, pass = cblk->passes; passno <
-							  cblk->numpasses && pass->lyrno == lyrno;
-							  ++passno, ++pass) {
-								fprintf(stderr, "lyrno=%02d cmptno=%02d rlvlno=%02d bandno=%02d prcno=%02d cblkno=%03d passno=%03d\n", lyrno, tcmptno, rlvlno, bandno, prcno, cblkno, passno);
-							}
-						}
-					}
-				}
-			}
-		}
-	}
+
+static void
+validateCumlensIncreases(const uint_fast32_t * const cumlens,
+                         unsigned int          const numlyrs) {
+    unsigned int lyrno;
+
+    for (lyrno = 1; lyrno < numlyrs - 1; ++lyrno) {
+        if (cumlens[lyrno - 1] > cumlens[lyrno]) {
+            abort();
+        }
+    }
 }
 
-int rateallocate(jpc_enc_t *enc, int numlyrs, uint_fast32_t *cumlens)
-{
-	jpc_flt_t lo;
-	jpc_flt_t hi;
-	jas_stream_t *out;
-	long cumlen;
-	int lyrno;
-	jpc_flt_t thresh;
-	jpc_flt_t goodthresh;
-	int success;
-	long pos;
-	long oldpos;
-	int numiters;
-
-	jpc_enc_tcmpt_t *comp;
-	jpc_enc_tcmpt_t *endcomps;
-	jpc_enc_rlvl_t *lvl;
-	jpc_enc_rlvl_t *endlvls;
-	jpc_enc_band_t *band;
-	jpc_enc_band_t *endbands;
-	jpc_enc_cblk_t *cblk;
-	jpc_enc_cblk_t *endcblks;
-	jpc_enc_pass_t *pass;
-	jpc_enc_pass_t *endpasses;
-	jpc_enc_pass_t *pass1;
-	jpc_flt_t mxrdslope;
-	jpc_flt_t mnrdslope;
-	jpc_enc_tile_t *tile;
-	jpc_enc_prc_t *prc;
-	uint_fast32_t prcno;
-
-	tile = enc->curtile;
-
-	for (lyrno = 1; lyrno < numlyrs - 1; ++lyrno) {
-		if (cumlens[lyrno - 1] > cumlens[lyrno]) {
-			abort();
-		}
-	}
-
-	if (!(out = jas_stream_memopen(0, 0))) {
-		return -1;
-	}
-
-
-	/* Find minimum and maximum R-D slope values. */
-	mnrdslope = DBL_MAX;
-	mxrdslope = 0;
-	endcomps = &tile->tcmpts[tile->numtcmpts];
-	for (comp = tile->tcmpts; comp != endcomps; ++comp) {
-		endlvls = &comp->rlvls[comp->numrlvls];
-		for (lvl = comp->rlvls; lvl != endlvls; ++lvl) {
-			if (!lvl->bands) {
-				continue;
-			}
-			endbands = &lvl->bands[lvl->numbands];
-			for (band = lvl->bands; band != endbands; ++band) {
-				if (!band->data) {
-					continue;
-				}
-				for (prcno = 0, prc = band->prcs; prcno < lvl->numprcs; ++prcno, ++prc) {
-					if (!prc->cblks) {
-						continue;
-					}
-					endcblks = &prc->cblks[prc->numcblks];
-					for (cblk = prc->cblks; cblk != endcblks; ++cblk) {
-						calcrdslopes(cblk);
-						endpasses = &cblk->passes[cblk->numpasses];
-						for (pass = cblk->passes; pass != endpasses; ++pass) {
-							if (pass->rdslope > 0) {
-								if (pass->rdslope < mnrdslope) {
-									mnrdslope = pass->rdslope;
-								}
-								if (pass->rdslope > mxrdslope) {
-									mxrdslope = pass->rdslope;
-								}
-							}
-						}
-					}
-				}
-			}
-		}
-	}
-if (jas_getdbglevel()) {
-	fprintf(stderr, "min rdslope = %f max rdslope = %f\n", mnrdslope, mxrdslope);
+
+
+static void
+findMinMaxRDSlopeValues(jpc_enc_tile_t * const tileP,
+                        jpc_flt_t *      const mnrdslopeP,
+                        jpc_flt_t *      const mxrdslopeP) {
+/*----------------------------------------------------------------------------
+  Find minimum and maximum R-D slope values.
+-----------------------------------------------------------------------------*/
+    jpc_flt_t mxrdslope;
+    jpc_flt_t mnrdslope;
+    jpc_enc_tcmpt_t * endcomps;
+    jpc_enc_tcmpt_t * compP;
+
+    mnrdslope = DBL_MAX;
+    mxrdslope = 0;
+    endcomps = &tileP->tcmpts[tileP->numtcmpts];
+
+    for (compP = tileP->tcmpts; compP != endcomps; ++compP) {
+        jpc_enc_rlvl_t * const endlvlsP = &compP->rlvls[compP->numrlvls];
+
+        jpc_enc_rlvl_t * lvlP;
+
+        for (lvlP = compP->rlvls; lvlP != endlvlsP; ++lvlP) {
+            jpc_enc_band_t * endbandsP;
+            jpc_enc_band_t * bandP;
+
+            if (lvlP->bands) {
+                endbandsP = &lvlP->bands[lvlP->numbands];
+                for (bandP = lvlP->bands; bandP != endbandsP; ++bandP) {
+                    uint_fast32_t prcno;
+                    jpc_enc_prc_t * prcP;
+
+                    if (bandP->data) {
+                        for (prcno = 0, prcP = bandP->prcs;
+                             prcno < lvlP->numprcs;
+                             ++prcno, ++prcP) {
+
+                            jpc_enc_cblk_t * endcblksP;
+                            jpc_enc_cblk_t * cblkP;
+
+                            if (prcP->cblks) {
+                                endcblksP = &prcP->cblks[prcP->numcblks];
+                                for (cblkP = prcP->cblks;
+                                     cblkP != endcblksP;
+                                     ++cblkP) {
+                                    jpc_enc_pass_t * endpassesP;
+                                    jpc_enc_pass_t * passP;
+
+                                    calcrdslopes(cblkP);
+                                    endpassesP =
+                                        &cblkP->passes[cblkP->numpasses];
+                                    for (passP = cblkP->passes;
+                                         passP != endpassesP;
+                                         ++passP) {
+                                        if (passP->rdslope > 0) {
+                                            mnrdslope =
+                                                MIN(passP->rdslope, mnrdslope);
+                                            mxrdslope =
+                                                MAX(passP->rdslope, mxrdslope);
+                                        }
+                                    }
+                                }
+                            }
+                        }
+                    }
+                }
+            }
+        }
+    }
+    trace("min rdslope = %f max rdslope = %f", mnrdslope, mxrdslope);
+
+    *mnrdslopeP = mnrdslope;
+    *mxrdslopeP = mxrdslope;
 }
 
-	jpc_init_t2state(enc, 1);
-
-	for (lyrno = 0; lyrno < numlyrs; ++lyrno) {
-
-		lo = mnrdslope;
-		hi = mxrdslope;
-
-		success = 0;
-		goodthresh = 0;
-		numiters = 0;
-
-		do {
-
-			cumlen = cumlens[lyrno];
-			if (cumlen == UINT_FAST32_MAX) {
-				/* Only the last layer can be free of a rate
-				  constraint (e.g., for lossless coding). */
-				assert(lyrno == numlyrs - 1);
-				goodthresh = -1;
-				success = 1;
-				break;
-			}
-
-			thresh = (lo + hi) / 2;
-
-			/* Save the tier 2 coding state. */
-			jpc_save_t2state(enc);
-			oldpos = jas_stream_tell(out);
-			assert(oldpos >= 0);
-
-			/* Assign all passes with R-D slopes greater than or
-			  equal to the current threshold to this layer. */
-			endcomps = &tile->tcmpts[tile->numtcmpts];
-			for (comp = tile->tcmpts; comp != endcomps; ++comp) {
-				endlvls = &comp->rlvls[comp->numrlvls];
-				for (lvl = comp->rlvls; lvl != endlvls; ++lvl) {
-					if (!lvl->bands) {
-						continue;
-					}
-					endbands = &lvl->bands[lvl->numbands];
-					for (band = lvl->bands; band != endbands; ++band) {
-						if (!band->data) {
-							continue;
-						}
-						for (prcno = 0, prc = band->prcs; prcno < lvl->numprcs; ++prcno, ++prc) {
-							if (!prc->cblks) {
-								continue;
-							}
-							endcblks = &prc->cblks[prc->numcblks];
-							for (cblk = prc->cblks; cblk != endcblks; ++cblk) {
-								if (cblk->curpass) {
-									endpasses = &cblk->passes[cblk->numpasses];
-									pass1 = cblk->curpass;
-									for (pass = cblk->curpass; pass != endpasses; ++pass) {
-										if (pass->rdslope >= thresh) {
-											pass1 = &pass[1];
-										}
-									}
-									for (pass = cblk->curpass; pass != pass1; ++pass) {
-										pass->lyrno = lyrno;
-									}
-									for (; pass != endpasses; ++pass) {
-										pass->lyrno = -1;
-									}
-								}
-							}
-						}
-					}
-				}
-			}
-
-			/* Perform tier 2 coding. */
-			endcomps = &tile->tcmpts[tile->numtcmpts];
-			for (comp = tile->tcmpts; comp != endcomps; ++comp) {
-				endlvls = &comp->rlvls[comp->numrlvls];
-				for (lvl = comp->rlvls; lvl != endlvls; ++lvl) {
-					if (!lvl->bands) {
-						continue;
-					}
-					for (prcno = 0; prcno < lvl->numprcs; ++prcno) {
-						if (jpc_enc_encpkt(enc, out, comp - tile->tcmpts, lvl - comp->rlvls, prcno, lyrno)) {
-							return -1;
-						}
-					}
-				}
-			}
-
-			pos = jas_stream_tell(out);
-
-			/* Check the rate constraint. */
-			assert(pos >= 0);
-			if (pos > cumlen) {
-				/* The rate is too high. */
-				lo = thresh;
-			} else if (pos <= cumlen) {
-				/* The rate is low enough, so try higher. */
-				hi = thresh;
-				if (!success || thresh < goodthresh) {
-					goodthresh = thresh;
-					success = 1;
-				}
-			}
-
-			/* Save the tier 2 coding state. */
-			jpc_restore_t2state(enc);
-			if (jas_stream_seek(out, oldpos, SEEK_SET) < 0) {
-				abort();
-			}
-
-if (jas_getdbglevel()) {
-fprintf(stderr, "maxlen=%08ld actuallen=%08ld thresh=%f\n", cumlen, pos, thresh);
+
+
+static void
+performTier2CodingOneLayer(jpc_enc_t *      const encP,
+                           jpc_enc_tile_t * const tileP,
+                           unsigned int     const lyrno,
+                           jas_stream_t *   const outP,
+                           const char **    const errorP) {
+/*----------------------------------------------------------------------------
+  Encode Layer 'lyrno' of tile *tileP to stream *outP.
+
+  Use the pass assignment already in *tileP.
+-----------------------------------------------------------------------------*/
+    jpc_enc_tcmpt_t * const endcompsP = &tileP->tcmpts[tileP->numtcmpts];
+
+    jpc_enc_tcmpt_t * compP;
+
+    *errorP = NULL;  /* initial assumption */
+
+    for (compP = tileP->tcmpts; compP != endcompsP && !*errorP; ++compP) {
+        jpc_enc_rlvl_t * const endlvlsP = &compP->rlvls[compP->numrlvls];
+
+        jpc_enc_rlvl_t * lvlP;
+
+        for (lvlP = compP->rlvls; lvlP != endlvlsP && !*errorP; ++lvlP) {
+            if (lvlP->bands) {
+                uint_fast32_t prcno;
+                for (prcno = 0; prcno < lvlP->numprcs && !*errorP; ++prcno) {
+                    int rc;
+                    rc = jpc_enc_encpkt(encP, outP, compP - tileP->tcmpts,
+                                        lvlP - compP->rlvls, prcno, lyrno);
+                    if (rc != 0)
+                        pm_asprintf(errorP, "jpc_enc_encpkt() failed on "
+                                    "precinct %u", (unsigned)prcno);
+                }
+            }
+        }
+    }
 }
 
-			++numiters;
-		} while (lo < hi - 1e-3 && numiters < 32);
 
-		if (!success) {
-			fprintf(stderr, "warning: empty layer generated\n");
-		}
 
-if (jas_getdbglevel()) {
-fprintf(stderr, "success %d goodthresh %f\n", success, goodthresh);
+static void
+assignHighSlopePassesToLayer(jpc_enc_t *      const encP,
+                             jpc_enc_tile_t * const tileP,
+                             unsigned int     const lyrno,
+                             bool             const haveThresh,
+                             jpc_flt_t        const thresh) {
+/*----------------------------------------------------------------------------
+  Assign all passes with R-D slopes greater than or equal to 'thresh' to layer
+  'lyrno' and the rest to no layer.
+
+  If 'haveThresh' is false, assign all passes to no layer.
+-----------------------------------------------------------------------------*/
+    jpc_enc_tcmpt_t * endcompsP;
+    jpc_enc_tcmpt_t * compP;
+
+    endcompsP = &tileP->tcmpts[tileP->numtcmpts];
+    for (compP = tileP->tcmpts; compP != endcompsP; ++compP) {
+        jpc_enc_rlvl_t * const endlvlsP = &compP->rlvls[compP->numrlvls];
+
+        jpc_enc_rlvl_t * lvlP;
+
+        for (lvlP = compP->rlvls; lvlP != endlvlsP; ++lvlP) {
+            if (lvlP->bands) {
+                jpc_enc_band_t * const endbandsP =
+                    &lvlP->bands[lvlP->numbands];
+                jpc_enc_band_t * bandP;
+                for (bandP = lvlP->bands; bandP != endbandsP; ++bandP) {
+                    if (bandP->data) {
+                        jpc_enc_prc_t * prcP;
+                        uint_fast32_t prcno;
+                        for (prcno = 0, prcP = bandP->prcs;
+                             prcno < lvlP->numprcs;
+                             ++prcno, ++prcP) {
+                            if (prcP->cblks) {
+                                jpc_enc_cblk_t * const endcblksP =
+                                    &prcP->cblks[prcP->numcblks];
+                                jpc_enc_cblk_t * cblkP;
+                                for (cblkP = prcP->cblks;
+                                     cblkP != endcblksP;
+                                     ++cblkP) {
+                                    if (cblkP->curpass) {
+                                        jpc_enc_pass_t *  const endpassesP =
+                                            &cblkP->passes[cblkP->numpasses];
+                                        jpc_enc_pass_t * pass1P;
+                                        jpc_enc_pass_t * passP;
+
+                                        pass1P = cblkP->curpass;
+                                        if (haveThresh) {
+                                            jpc_enc_pass_t * passP;
+                                            for (passP = cblkP->curpass;
+                                                 passP != endpassesP;
+                                                 ++passP) {
+                                                if (passP->rdslope >= thresh)
+                                                    pass1P = passP + 1;
+                                            }
+                                        }
+                                        for (passP = cblkP->curpass;
+                                             passP != pass1P;
+                                             ++passP) {
+                                            passP->lyrno = lyrno;
+                                        }
+                                        for (; passP != endpassesP; ++passP) {
+                                            passP->lyrno = -1;
+                                        }
+                                    
+                                    }   
+                                }
+                            }
+                        }
+                    }
+                }
+            }
+        }
+    }
 }
 
-		/* Assign all passes with R-D slopes greater than or
-		  equal to the selected threshold to this layer. */
-		endcomps = &tile->tcmpts[tile->numtcmpts];
-		for (comp = tile->tcmpts; comp != endcomps; ++comp) {
-			endlvls = &comp->rlvls[comp->numrlvls];
-			for (lvl = comp->rlvls; lvl != endlvls; ++lvl) {
-if (!lvl->bands) {
-	continue;
+
+
+static void
+doLayer(jpc_enc_t *      const encP,
+        jpc_enc_tile_t * const tileP,
+        unsigned int     const lyrno,
+        uint_fast32_t    const allowedSize,
+        jpc_flt_t        const mnrdslope,
+        jpc_flt_t        const mxrdslope,
+        jas_stream_t *   const outP,
+        const char **    const errorP) {
+/*----------------------------------------------------------------------------
+   Assign passes to layer 'lyrno' such that the cumulative size through
+   this layer is as close as possible to, but not exceeding, 'allowedSize'.
+-----------------------------------------------------------------------------*/
+    bool      haveGoodThresh;
+    jpc_flt_t goodThresh;
+
+    if (allowedSize == UINT_FAST32_MAX) {
+        /* There's no rate constraint (This can be true of the last layer,
+           e.g. for lossless coding). */
+        goodThresh = -1;
+        haveGoodThresh = true;
+        *errorP = NULL;
+    } else {
+        /* Iterate through successive approximations of the threshold, finding
+           the threshold that gets us closest to 'allowedSize' without going
+           over.  In each iteration, we do the full encoding, note the size,
+           and then restore the previous state.
+        */
+        long pos;
+        jpc_flt_t lo;
+        jpc_flt_t hi;
+        unsigned int numiters;
+
+        lo = mnrdslope;  /* initial value */
+        hi = mxrdslope;  /* initial value */
+        numiters = 0;    /* initial value */
+        haveGoodThresh = false;  /* initial value */
+        goodThresh = 0;     /* initial value */
+
+        do {
+            if (allowedSize == UINT_FAST32_MAX) {
+                /* There's no rate constraint (This can be true of the last
+                   layer, e.g. for lossless coding). */
+                goodThresh = -1;
+                haveGoodThresh = true;
+            } else {
+                jpc_flt_t const thresh = (lo + hi) / 2;
+
+                int rc;
+                long oldpos;
+
+                /* Save the tier 2 coding state. */
+                jpc_save_t2state(encP);
+                oldpos = jas_stream_tell(outP);
+                assert(oldpos >= 0);
+
+                assignHighSlopePassesToLayer(encP, tileP, lyrno, true, thresh);
+
+                performTier2CodingOneLayer(encP, tileP, lyrno, outP, errorP);
+
+                if (!*errorP) {
+                    pos = jas_stream_tell(outP);
+
+                    /* Check the rate constraint. */
+                    assert(pos >= 0);
+                    if (pos > allowedSize) {
+                        /* The rate is too high. */
+                        lo = thresh;
+                    } else if (pos <= allowedSize) {
+                        /* The rate is low enough, so try higher. */
+                        hi = thresh;
+                        if (!haveGoodThresh || thresh < goodThresh) {
+                            goodThresh = thresh;
+                            haveGoodThresh = true;
+                        }
+                    }
+                }
+                /* Restore the tier 2 coding state. */
+                jpc_restore_t2state(encP);
+                rc = jas_stream_seek(outP, oldpos, SEEK_SET);
+                if (rc < 0)
+                    abort();
+
+                trace("iter %u: allowedlen=%08ld actuallen=%08ld thresh=%f",
+                      numiters, allowedSize, pos, thresh);
+            }
+            ++numiters;
+        } while (lo < hi - 1e-3 && numiters < 32 && !*errorP);
+    }
+
+    if (!*errorP) {
+        if (!haveGoodThresh)
+            fprintf(stderr, "warning: empty layer generated\n");
+
+        trace("haveGoodThresh %u goodthresh %f", haveGoodThresh, goodThresh);
+
+        assignHighSlopePassesToLayer(encP, tileP, lyrno,
+                                     haveGoodThresh, goodThresh);
+
+        performTier2CodingOneLayer(encP, tileP, lyrno, outP, errorP);
+    }
 }
-				endbands = &lvl->bands[lvl->numbands];
-				for (band = lvl->bands; band != endbands; ++band) {
-					if (!band->data) {
-						continue;
-					}
-					for (prcno = 0, prc = band->prcs; prcno < lvl->numprcs; ++prcno, ++prc) {
-						if (!prc->cblks) {
-							continue;
-						}
-						endcblks = &prc->cblks[prc->numcblks];
-						for (cblk = prc->cblks; cblk != endcblks; ++cblk) {
-							if (cblk->curpass) {
-								endpasses = &cblk->passes[cblk->numpasses];
-								pass1 = cblk->curpass;
-								if (success) {
-									for (pass = cblk->curpass; pass != endpasses; ++pass) {
-										if (pass->rdslope >= goodthresh) {
-											pass1 = &pass[1];
-										}
-									}
-								}
-								for (pass = cblk->curpass; pass != pass1; ++pass) {
-									pass->lyrno = lyrno;
-								}
-								for (; pass != endpasses; ++pass) {
-									pass->lyrno = -1;
-								}
-							}
-						}
-					}
-				}
-			}
-		}
-
-		/* Perform tier 2 coding. */
-		endcomps = &tile->tcmpts[tile->numtcmpts];
-		for (comp = tile->tcmpts; comp != endcomps; ++comp) {
-			endlvls = &comp->rlvls[comp->numrlvls];
-			for (lvl = comp->rlvls; lvl != endlvls; ++lvl) {
-				if (!lvl->bands) {
-					continue;
-				}
-				for (prcno = 0; prcno < lvl->numprcs; ++prcno) {
-					if (jpc_enc_encpkt(enc, out, comp - tile->tcmpts, lvl - comp->rlvls, prcno, lyrno)) {
-						return -1;
-					}
-				}
-			}
-		}
-	}
-
-	if (jas_getdbglevel() >= 5) {
-		dump_layeringinfo(enc);
-	}
-
-	jas_stream_close(out);
-
-	JAS_DBGLOG(10, ("done doing rateallocation\n"));
-#if 0
-fprintf(stderr, "DONE RATE ALLOCATE\n");
-#endif
 
-	return 0;
+
+
+static void
+performTier2Coding(jpc_enc_t *     const encP,
+                   unsigned int    const numlyrs,
+                   uint_fast32_t * const cumlens,
+                   const char **   const errorP) {
+/*----------------------------------------------------------------------------
+   Encode in 'numlyrs' layers, such that at each layer L, the size is
+   cumlens[L].
+-----------------------------------------------------------------------------*/
+    jpc_enc_tile_t * const tileP = encP->curtile;
+
+    jas_stream_t * outP;
+    unsigned int lyrno;
+    jpc_flt_t mnrdslope;
+    jpc_flt_t mxrdslope;
+
+    validateCumlensIncreases(cumlens, numlyrs);
+
+    outP = jas_stream_memopen(0, 0);
+
+    if (!outP)
+        pm_asprintf(errorP, "jas_stream_memopen() failed");
+    else {
+        findMinMaxRDSlopeValues(tileP, &mnrdslope, &mxrdslope);
+
+        jpc_init_t2state(encP, 1);
+
+        for (lyrno = 0, *errorP = NULL;
+             lyrno < numlyrs && !*errorP;
+             ++lyrno) {
+            doLayer(encP, tileP, lyrno, cumlens[lyrno],
+                    mnrdslope, mxrdslope, outP, errorP);
+        }
+
+        if (!*errorP) {
+            trace_layeringinfo(encP);
+
+            jas_stream_close(outP);
+        }
+    }
+    JAS_DBGLOG(10, ("done doing rateallocation\n"));
 }
 
-/******************************************************************************\
+/*****************************************************************************\
 * Tile constructors and destructors.
-\******************************************************************************/
+\*****************************************************************************/
 
 jpc_enc_tile_t *jpc_enc_tile_create(jpc_enc_cp_t *cp, jas_image_t *image, int tileno)
 {
-	jpc_enc_tile_t *tile;
-	uint_fast32_t htileno;
-	uint_fast32_t vtileno;
-	uint_fast16_t lyrno;
-	uint_fast16_t cmptno;
-	jpc_enc_tcmpt_t *tcmpt;
-
-	if (!(tile = jas_malloc(sizeof(jpc_enc_tile_t)))) {
-		goto error;
-	}
-
-	/* Initialize a few members used in error recovery. */
-	tile->tcmpts = 0;
-	tile->lyrsizes = 0;
-	tile->numtcmpts = cp->numcmpts;
-	tile->pi = 0;
-
-	tile->tileno = tileno;
-	htileno = tileno % cp->numhtiles;
-	vtileno = tileno / cp->numhtiles;
-
-	/* Calculate the coordinates of the top-left and bottom-right
-	  corners of the tile. */
-	tile->tlx = JAS_MAX(cp->tilegrdoffx + htileno * cp->tilewidth,
-	  cp->imgareatlx);
-	tile->tly = JAS_MAX(cp->tilegrdoffy + vtileno * cp->tileheight,
-	  cp->imgareatly);
-	tile->brx = JAS_MIN(cp->tilegrdoffx + (htileno + 1) * cp->tilewidth,
-	  cp->refgrdwidth);
-	tile->bry = JAS_MIN(cp->tilegrdoffy + (vtileno + 1) * cp->tileheight,
-	  cp->refgrdheight);
-
-	/* Initialize some tile coding parameters. */
-	tile->intmode = cp->tcp.intmode;
-	tile->csty = cp->tcp.csty;
-	tile->prg = cp->tcp.prg;
-	tile->mctid = cp->tcp.mctid;
-
-	tile->numlyrs = cp->tcp.numlyrs;
-	if (!(tile->lyrsizes = jas_malloc(tile->numlyrs *
-	  sizeof(uint_fast32_t)))) {
-		goto error;
-	}
-	for (lyrno = 0; lyrno < tile->numlyrs; ++lyrno) {
-		tile->lyrsizes[lyrno] = 0;
-	}
-
-	/* Allocate an array for the per-tile-component information. */
-	if (!(tile->tcmpts = jas_malloc(cp->numcmpts * sizeof(jpc_enc_tcmpt_t)))) {
-		goto error;
-	}
-	/* Initialize a few members critical for error recovery. */
-	for (cmptno = 0, tcmpt = tile->tcmpts; cmptno < cp->numcmpts;
-	  ++cmptno, ++tcmpt) {
-		tcmpt->rlvls = 0;
-		tcmpt->tsfb = 0;
-		tcmpt->data = 0;
-	}
-	/* Initialize the per-tile-component information. */
-	for (cmptno = 0, tcmpt = tile->tcmpts; cmptno < cp->numcmpts;
-	  ++cmptno, ++tcmpt) {
-		if (!tcmpt_create(tcmpt, cp, image, tile)) {
-			goto error;
-		}
-	}
-
-	/* Initialize the synthesis weights for the MCT. */
-	switch (tile->mctid) {
-	case JPC_MCT_RCT:
-		tile->tcmpts[0].synweight = jpc_dbltofix(sqrt(3.0));
-		tile->tcmpts[1].synweight = jpc_dbltofix(sqrt(0.6875));
-		tile->tcmpts[2].synweight = jpc_dbltofix(sqrt(0.6875));
-		break;
-	case JPC_MCT_ICT:
-		tile->tcmpts[0].synweight = jpc_dbltofix(sqrt(3.0000));
-		tile->tcmpts[1].synweight = jpc_dbltofix(sqrt(3.2584));
-		tile->tcmpts[2].synweight = jpc_dbltofix(sqrt(2.4755));
-		break;
-	default:
-	case JPC_MCT_NONE:
-		for (cmptno = 0, tcmpt = tile->tcmpts; cmptno < cp->numcmpts;
-		  ++cmptno, ++tcmpt) {
-			tcmpt->synweight = JPC_FIX_ONE;
-		}
-		break;
-	}
-
-	if (!(tile->pi = jpc_enc_pi_create(cp, tile))) {
-		goto error;
-	}
-
-	return tile;
+    jpc_enc_tile_t *tile;
+    uint_fast32_t htileno;
+    uint_fast32_t vtileno;
+    uint_fast16_t lyrno;
+    uint_fast16_t cmptno;
+    jpc_enc_tcmpt_t *tcmpt;
+
+    if (!(tile = jas_malloc(sizeof(jpc_enc_tile_t)))) {
+        goto error;
+    }
+
+    /* Initialize a few members used in error recovery. */
+    tile->tcmpts = 0;
+    tile->lyrsizes = 0;
+    tile->numtcmpts = cp->numcmpts;
+    tile->pi = 0;
+
+    tile->tileno = tileno;
+    htileno = tileno % cp->numhtiles;
+    vtileno = tileno / cp->numhtiles;
+
+    /* Calculate the coordinates of the top-left and bottom-right
+      corners of the tile. */
+    tile->tlx = JAS_MAX(cp->tilegrdoffx + htileno * cp->tilewidth,
+      cp->imgareatlx);
+    tile->tly = JAS_MAX(cp->tilegrdoffy + vtileno * cp->tileheight,
+      cp->imgareatly);
+    tile->brx = JAS_MIN(cp->tilegrdoffx + (htileno + 1) * cp->tilewidth,
+      cp->refgrdwidth);
+    tile->bry = JAS_MIN(cp->tilegrdoffy + (vtileno + 1) * cp->tileheight,
+      cp->refgrdheight);
+
+    /* Initialize some tile coding parameters. */
+    tile->intmode = cp->tcp.intmode;
+    tile->csty = cp->tcp.csty;
+    tile->prg = cp->tcp.prg;
+    tile->mctid = cp->tcp.mctid;
+
+    tile->numlyrs = cp->tcp.numlyrs;
+    if (!(tile->lyrsizes = jas_malloc(tile->numlyrs *
+      sizeof(uint_fast32_t)))) {
+        goto error;
+    }
+    for (lyrno = 0; lyrno < tile->numlyrs; ++lyrno) {
+        tile->lyrsizes[lyrno] = 0;
+    }
+
+    /* Allocate an array for the per-tile-component information. */
+    if (!(tile->tcmpts = jas_malloc(cp->numcmpts * sizeof(jpc_enc_tcmpt_t)))) {
+        goto error;
+    }
+    /* Initialize a few members critical for error recovery. */
+    for (cmptno = 0, tcmpt = tile->tcmpts; cmptno < cp->numcmpts;
+      ++cmptno, ++tcmpt) {
+        tcmpt->rlvls = 0;
+        tcmpt->tsfb = 0;
+        tcmpt->data = 0;
+    }
+    /* Initialize the per-tile-component information. */
+    for (cmptno = 0, tcmpt = tile->tcmpts; cmptno < cp->numcmpts;
+      ++cmptno, ++tcmpt) {
+        if (!tcmpt_create(tcmpt, cp, image, tile)) {
+            goto error;
+        }
+    }
+
+    /* Initialize the synthesis weights for the MCT. */
+    switch (tile->mctid) {
+    case JPC_MCT_RCT:
+        tile->tcmpts[0].synweight = jpc_dbltofix(sqrt(3.0));
+        tile->tcmpts[1].synweight = jpc_dbltofix(sqrt(0.6875));
+        tile->tcmpts[2].synweight = jpc_dbltofix(sqrt(0.6875));
+        break;
+    case JPC_MCT_ICT:
+        tile->tcmpts[0].synweight = jpc_dbltofix(sqrt(3.0000));
+        tile->tcmpts[1].synweight = jpc_dbltofix(sqrt(3.2584));
+        tile->tcmpts[2].synweight = jpc_dbltofix(sqrt(2.4755));
+        break;
+    default:
+    case JPC_MCT_NONE:
+        for (cmptno = 0, tcmpt = tile->tcmpts; cmptno < cp->numcmpts;
+          ++cmptno, ++tcmpt) {
+            tcmpt->synweight = JPC_FIX_ONE;
+        }
+        break;
+    }
+
+    if (!(tile->pi = jpc_enc_pi_create(cp, tile))) {
+        goto error;
+    }
+
+    return tile;
 
 error:
 
-	if (tile) {
-		jpc_enc_tile_destroy(tile);
-	}
-	return 0;
+    if (tile) {
+        jpc_enc_tile_destroy(tile);
+    }
+    return 0;
 }
 
 void jpc_enc_tile_destroy(jpc_enc_tile_t *tile)
 {
-	jpc_enc_tcmpt_t *tcmpt;
-	uint_fast16_t cmptno;
-
-	if (tile->tcmpts) {
-		for (cmptno = 0, tcmpt = tile->tcmpts; cmptno <
-		  tile->numtcmpts; ++cmptno, ++tcmpt) {
-			tcmpt_destroy(tcmpt);
-		}
-		jas_free(tile->tcmpts);
-	}
-	if (tile->lyrsizes) {
-		jas_free(tile->lyrsizes);
-	}
-	if (tile->pi) {
-		jpc_pi_destroy(tile->pi);
-	}
-	jas_free(tile);
+    jpc_enc_tcmpt_t *tcmpt;
+    uint_fast16_t cmptno;
+
+    if (tile->tcmpts) {
+        for (cmptno = 0, tcmpt = tile->tcmpts; cmptno <
+          tile->numtcmpts; ++cmptno, ++tcmpt) {
+            tcmpt_destroy(tcmpt);
+        }
+        jas_free(tile->tcmpts);
+    }
+    if (tile->lyrsizes) {
+        jas_free(tile->lyrsizes);
+    }
+    if (tile->pi) {
+        jpc_pi_destroy(tile->pi);
+    }
+    jas_free(tile);
 }
 
 static jpc_enc_tcmpt_t *tcmpt_create(jpc_enc_tcmpt_t *tcmpt, jpc_enc_cp_t *cp,
   jas_image_t *image, jpc_enc_tile_t *tile)
 {
-	uint_fast16_t cmptno;
-	uint_fast16_t rlvlno;
-	jpc_enc_rlvl_t *rlvl;
-	uint_fast32_t tlx;
-	uint_fast32_t tly;
-	uint_fast32_t brx;
-	uint_fast32_t bry;
-	uint_fast32_t cmpttlx;
-	uint_fast32_t cmpttly;
-	jpc_enc_ccp_t *ccp;
-	jpc_tsfb_band_t bandinfos[JPC_MAXBANDS];
-
-	tcmpt->tile = tile;
-	tcmpt->tsfb = 0;
-	tcmpt->data = 0;
-	tcmpt->rlvls = 0;
-
-	/* Deduce the component number. */
-	cmptno = tcmpt - tile->tcmpts;
-
-	ccp = &cp->ccps[cmptno];
-
-	/* Compute the coordinates of the top-left and bottom-right
-	  corners of this tile-component. */
-	tlx = JPC_CEILDIV(tile->tlx, ccp->sampgrdstepx);
-	tly = JPC_CEILDIV(tile->tly, ccp->sampgrdstepy);
-	brx = JPC_CEILDIV(tile->brx, ccp->sampgrdstepx);
-	bry = JPC_CEILDIV(tile->bry, ccp->sampgrdstepy);
-
-	/* Create a sequence to hold the tile-component sample data. */
-	if (!(tcmpt->data = jas_seq2d_create(tlx, tly, brx, bry))) {
-		goto error;
-	}
-
-	/* Get the image data associated with this tile-component. */
-	cmpttlx = JPC_CEILDIV(cp->imgareatlx, ccp->sampgrdstepx);
-	cmpttly = JPC_CEILDIV(cp->imgareatly, ccp->sampgrdstepy);
-	if (jas_image_readcmpt(image, cmptno, tlx - cmpttlx, tly - cmpttly,
-	  brx - tlx, bry - tly, tcmpt->data)) {
-		goto error;
-	}
-
-	tcmpt->synweight = 0;
-	tcmpt->qmfbid = cp->tccp.qmfbid;
-	tcmpt->numrlvls = cp->tccp.maxrlvls;
-	tcmpt->numbands = 3 * tcmpt->numrlvls - 2;
-	if (!(tcmpt->tsfb = jpc_cod_gettsfb(tcmpt->qmfbid, tcmpt->numrlvls - 1))) {
-		goto error;
-	}
-
-	for (rlvlno = 0; rlvlno < tcmpt->numrlvls; ++rlvlno) {
-		tcmpt->prcwidthexpns[rlvlno] = cp->tccp.prcwidthexpns[rlvlno];
-		tcmpt->prcheightexpns[rlvlno] = cp->tccp.prcheightexpns[rlvlno];
-	}
-	tcmpt->cblkwidthexpn = cp->tccp.cblkwidthexpn;
-	tcmpt->cblkheightexpn = cp->tccp.cblkheightexpn;
-	tcmpt->cblksty = cp->tccp.cblksty;
-	tcmpt->csty = cp->tccp.csty;
-
-	tcmpt->numstepsizes = tcmpt->numbands;
-	assert(tcmpt->numstepsizes <= JPC_MAXBANDS);
-	memset(tcmpt->stepsizes, 0, sizeof(tcmpt->numstepsizes *
-	  sizeof(uint_fast16_t)));
-
-	/* Retrieve information about the various bands. */
-	jpc_tsfb_getbands(tcmpt->tsfb, jas_seq2d_xstart(tcmpt->data),
-	  jas_seq2d_ystart(tcmpt->data), jas_seq2d_xend(tcmpt->data),
-	  jas_seq2d_yend(tcmpt->data), bandinfos);
-
-	if (!(tcmpt->rlvls = jas_malloc(tcmpt->numrlvls * sizeof(jpc_enc_rlvl_t)))) {
-		goto error;
-	}
-	for (rlvlno = 0, rlvl = tcmpt->rlvls; rlvlno < tcmpt->numrlvls;
-	  ++rlvlno, ++rlvl) {
-		rlvl->bands = 0;
-		rlvl->tcmpt = tcmpt;
-	}
-	for (rlvlno = 0, rlvl = tcmpt->rlvls; rlvlno < tcmpt->numrlvls;
-	  ++rlvlno, ++rlvl) {
-		if (!rlvl_create(rlvl, cp, tcmpt, bandinfos)) {
-			goto error;
-		}
-	}
-
-	return tcmpt;
+    uint_fast16_t cmptno;
+    uint_fast16_t rlvlno;
+    jpc_enc_rlvl_t *rlvl;
+    uint_fast32_t tlx;
+    uint_fast32_t tly;
+    uint_fast32_t brx;
+    uint_fast32_t bry;
+    uint_fast32_t cmpttlx;
+    uint_fast32_t cmpttly;
+    jpc_enc_ccp_t *ccp;
+    jpc_tsfb_band_t bandinfos[JPC_MAXBANDS];
+
+    tcmpt->tile = tile;
+    tcmpt->tsfb = 0;
+    tcmpt->data = 0;
+    tcmpt->rlvls = 0;
+
+    /* Deduce the component number. */
+    cmptno = tcmpt - tile->tcmpts;
+
+    ccp = &cp->ccps[cmptno];
+
+    /* Compute the coordinates of the top-left and bottom-right
+      corners of this tile-component. */
+    tlx = JPC_CEILDIV(tile->tlx, ccp->sampgrdstepx);
+    tly = JPC_CEILDIV(tile->tly, ccp->sampgrdstepy);
+    brx = JPC_CEILDIV(tile->brx, ccp->sampgrdstepx);
+    bry = JPC_CEILDIV(tile->bry, ccp->sampgrdstepy);
+
+    /* Create a sequence to hold the tile-component sample data. */
+    if (!(tcmpt->data = jas_seq2d_create(tlx, tly, brx, bry))) {
+        goto error;
+    }
+
+    /* Get the image data associated with this tile-component. */
+    cmpttlx = JPC_CEILDIV(cp->imgareatlx, ccp->sampgrdstepx);
+    cmpttly = JPC_CEILDIV(cp->imgareatly, ccp->sampgrdstepy);
+    if (jas_image_readcmpt(image, cmptno, tlx - cmpttlx, tly - cmpttly,
+      brx - tlx, bry - tly, tcmpt->data)) {
+        goto error;
+    }
+
+    tcmpt->synweight = 0;
+    tcmpt->qmfbid = cp->tccp.qmfbid;
+    tcmpt->numrlvls = cp->tccp.maxrlvls;
+    tcmpt->numbands = 3 * tcmpt->numrlvls - 2;
+    if (!(tcmpt->tsfb = jpc_cod_gettsfb(tcmpt->qmfbid, tcmpt->numrlvls - 1))) {
+        goto error;
+    }
+
+    for (rlvlno = 0; rlvlno < tcmpt->numrlvls; ++rlvlno) {
+        tcmpt->prcwidthexpns[rlvlno] = cp->tccp.prcwidthexpns[rlvlno];
+        tcmpt->prcheightexpns[rlvlno] = cp->tccp.prcheightexpns[rlvlno];
+    }
+    tcmpt->cblkwidthexpn = cp->tccp.cblkwidthexpn;
+    tcmpt->cblkheightexpn = cp->tccp.cblkheightexpn;
+    tcmpt->cblksty = cp->tccp.cblksty;
+    tcmpt->csty = cp->tccp.csty;
+
+    tcmpt->numstepsizes = tcmpt->numbands;
+    assert(tcmpt->numstepsizes <= JPC_MAXBANDS);
+    memset(tcmpt->stepsizes, 0, sizeof(tcmpt->numstepsizes *
+      sizeof(uint_fast16_t)));
+
+    /* Retrieve information about the various bands. */
+    jpc_tsfb_getbands(tcmpt->tsfb, jas_seq2d_xstart(tcmpt->data),
+      jas_seq2d_ystart(tcmpt->data), jas_seq2d_xend(tcmpt->data),
+      jas_seq2d_yend(tcmpt->data), bandinfos);
+
+    if (!(tcmpt->rlvls = jas_malloc(tcmpt->numrlvls * sizeof(jpc_enc_rlvl_t)))) {
+        goto error;
+    }
+    for (rlvlno = 0, rlvl = tcmpt->rlvls; rlvlno < tcmpt->numrlvls;
+      ++rlvlno, ++rlvl) {
+        rlvl->bands = 0;
+        rlvl->tcmpt = tcmpt;
+    }
+    for (rlvlno = 0, rlvl = tcmpt->rlvls; rlvlno < tcmpt->numrlvls;
+      ++rlvlno, ++rlvl) {
+        if (!rlvl_create(rlvl, cp, tcmpt, bandinfos)) {
+            goto error;
+        }
+    }
+
+    return tcmpt;
 
 error:
 
-	tcmpt_destroy(tcmpt);
-	return 0;
+    tcmpt_destroy(tcmpt);
+    return 0;
 
 }
 
 static void tcmpt_destroy(jpc_enc_tcmpt_t *tcmpt)
 {
-	jpc_enc_rlvl_t *rlvl;
-	uint_fast16_t rlvlno;
-
-	if (tcmpt->rlvls) {
-		for (rlvlno = 0, rlvl = tcmpt->rlvls; rlvlno < tcmpt->numrlvls;
-		  ++rlvlno, ++rlvl) {
-			rlvl_destroy(rlvl);
-		}
-		jas_free(tcmpt->rlvls);
-	}
-
-	if (tcmpt->data) {
-		jas_seq2d_destroy(tcmpt->data);
-	}
-	if (tcmpt->tsfb) {
-		jpc_tsfb_destroy(tcmpt->tsfb);
-	}
+    jpc_enc_rlvl_t *rlvl;
+    uint_fast16_t rlvlno;
+
+    if (tcmpt->rlvls) {
+        for (rlvlno = 0, rlvl = tcmpt->rlvls; rlvlno < tcmpt->numrlvls;
+          ++rlvlno, ++rlvl) {
+            rlvl_destroy(rlvl);
+        }
+        jas_free(tcmpt->rlvls);
+    }
+
+    if (tcmpt->data) {
+        jas_seq2d_destroy(tcmpt->data);
+    }
+    if (tcmpt->tsfb) {
+        jpc_tsfb_destroy(tcmpt->tsfb);
+    }
 }
 
 static jpc_enc_rlvl_t *rlvl_create(jpc_enc_rlvl_t *rlvl, jpc_enc_cp_t *cp,
   jpc_enc_tcmpt_t *tcmpt, jpc_tsfb_band_t *bandinfos)
 {
-	uint_fast16_t rlvlno;
-	uint_fast32_t tlprctlx;
-	uint_fast32_t tlprctly;
-	uint_fast32_t brprcbrx;
-	uint_fast32_t brprcbry;
-	uint_fast16_t bandno;
-	jpc_enc_band_t *band;
-
-	/* Deduce the resolution level. */
-	rlvlno = rlvl - tcmpt->rlvls;
-
-	/* Initialize members required for error recovery. */
-	rlvl->bands = 0;
-	rlvl->tcmpt = tcmpt;
-
-	/* Compute the coordinates of the top-left and bottom-right
-	  corners of the tile-component at this resolution. */
-	rlvl->tlx = JPC_CEILDIVPOW2(jas_seq2d_xstart(tcmpt->data), tcmpt->numrlvls -
-	  1 - rlvlno);
-	rlvl->tly = JPC_CEILDIVPOW2(jas_seq2d_ystart(tcmpt->data), tcmpt->numrlvls -
-	  1 - rlvlno);
-	rlvl->brx = JPC_CEILDIVPOW2(jas_seq2d_xend(tcmpt->data), tcmpt->numrlvls -
-	  1 - rlvlno);
-	rlvl->bry = JPC_CEILDIVPOW2(jas_seq2d_yend(tcmpt->data), tcmpt->numrlvls -
-	  1 - rlvlno);
-
-	if (rlvl->tlx >= rlvl->brx || rlvl->tly >= rlvl->bry) {
-		rlvl->numhprcs = 0;
-		rlvl->numvprcs = 0;
-		rlvl->numprcs = 0;
-		return rlvl;
-	}
-
-	rlvl->numbands = (!rlvlno) ? 1 : 3;
-	rlvl->prcwidthexpn = cp->tccp.prcwidthexpns[rlvlno];
-	rlvl->prcheightexpn = cp->tccp.prcheightexpns[rlvlno];
-	if (!rlvlno) {
-		rlvl->cbgwidthexpn = rlvl->prcwidthexpn;
-		rlvl->cbgheightexpn = rlvl->prcheightexpn;
-	} else {
-		rlvl->cbgwidthexpn = rlvl->prcwidthexpn - 1;
-		rlvl->cbgheightexpn = rlvl->prcheightexpn - 1;
-	}
-	rlvl->cblkwidthexpn = JAS_MIN(cp->tccp.cblkwidthexpn, rlvl->cbgwidthexpn);
-	rlvl->cblkheightexpn = JAS_MIN(cp->tccp.cblkheightexpn, rlvl->cbgheightexpn);
-
-	/* Compute the number of precincts. */
-	tlprctlx = JPC_FLOORTOMULTPOW2(rlvl->tlx, rlvl->prcwidthexpn);
-	tlprctly = JPC_FLOORTOMULTPOW2(rlvl->tly, rlvl->prcheightexpn);
-	brprcbrx = JPC_CEILTOMULTPOW2(rlvl->brx, rlvl->prcwidthexpn);
-	brprcbry = JPC_CEILTOMULTPOW2(rlvl->bry, rlvl->prcheightexpn);
-	rlvl->numhprcs = JPC_FLOORDIVPOW2(brprcbrx - tlprctlx, rlvl->prcwidthexpn);
-	rlvl->numvprcs = JPC_FLOORDIVPOW2(brprcbry - tlprctly, rlvl->prcheightexpn);
-	rlvl->numprcs = rlvl->numhprcs * rlvl->numvprcs;
-
-	if (!(rlvl->bands = jas_malloc(rlvl->numbands * sizeof(jpc_enc_band_t)))) {
-		goto error;
-	}
-	for (bandno = 0, band = rlvl->bands; bandno < rlvl->numbands;
-	  ++bandno, ++band) {
-		band->prcs = 0;
-		band->data = 0;
-		band->rlvl = rlvl;
-	}
-	for (bandno = 0, band = rlvl->bands; bandno < rlvl->numbands;
-	  ++bandno, ++band) {
-		if (!band_create(band, cp, rlvl, bandinfos)) {
-			goto error;
-		}
-	}
-
-	return rlvl;
+    uint_fast16_t rlvlno;
+    uint_fast32_t tlprctlx;
+    uint_fast32_t tlprctly;
+    uint_fast32_t brprcbrx;
+    uint_fast32_t brprcbry;
+    uint_fast16_t bandno;
+    jpc_enc_band_t *band;
+
+    /* Deduce the resolution level. */
+    rlvlno = rlvl - tcmpt->rlvls;
+
+    /* Initialize members required for error recovery. */
+    rlvl->bands = 0;
+    rlvl->tcmpt = tcmpt;
+
+    /* Compute the coordinates of the top-left and bottom-right
+      corners of the tile-component at this resolution. */
+    rlvl->tlx = JPC_CEILDIVPOW2(jas_seq2d_xstart(tcmpt->data), tcmpt->numrlvls -
+      1 - rlvlno);
+    rlvl->tly = JPC_CEILDIVPOW2(jas_seq2d_ystart(tcmpt->data), tcmpt->numrlvls -
+      1 - rlvlno);
+    rlvl->brx = JPC_CEILDIVPOW2(jas_seq2d_xend(tcmpt->data), tcmpt->numrlvls -
+      1 - rlvlno);
+    rlvl->bry = JPC_CEILDIVPOW2(jas_seq2d_yend(tcmpt->data), tcmpt->numrlvls -
+      1 - rlvlno);
+
+    if (rlvl->tlx >= rlvl->brx || rlvl->tly >= rlvl->bry) {
+        rlvl->numhprcs = 0;
+        rlvl->numvprcs = 0;
+        rlvl->numprcs = 0;
+        return rlvl;
+    }
+
+    rlvl->numbands = (!rlvlno) ? 1 : 3;
+    rlvl->prcwidthexpn = cp->tccp.prcwidthexpns[rlvlno];
+    rlvl->prcheightexpn = cp->tccp.prcheightexpns[rlvlno];
+    if (!rlvlno) {
+        rlvl->cbgwidthexpn = rlvl->prcwidthexpn;
+        rlvl->cbgheightexpn = rlvl->prcheightexpn;
+    } else {
+        rlvl->cbgwidthexpn = rlvl->prcwidthexpn - 1;
+        rlvl->cbgheightexpn = rlvl->prcheightexpn - 1;
+    }
+    rlvl->cblkwidthexpn = JAS_MIN(cp->tccp.cblkwidthexpn, rlvl->cbgwidthexpn);
+    rlvl->cblkheightexpn = JAS_MIN(cp->tccp.cblkheightexpn, rlvl->cbgheightexpn);
+
+    /* Compute the number of precincts. */
+    tlprctlx = JPC_FLOORTOMULTPOW2(rlvl->tlx, rlvl->prcwidthexpn);
+    tlprctly = JPC_FLOORTOMULTPOW2(rlvl->tly, rlvl->prcheightexpn);
+    brprcbrx = JPC_CEILTOMULTPOW2(rlvl->brx, rlvl->prcwidthexpn);
+    brprcbry = JPC_CEILTOMULTPOW2(rlvl->bry, rlvl->prcheightexpn);
+    rlvl->numhprcs = JPC_FLOORDIVPOW2(brprcbrx - tlprctlx, rlvl->prcwidthexpn);
+    rlvl->numvprcs = JPC_FLOORDIVPOW2(brprcbry - tlprctly, rlvl->prcheightexpn);
+    rlvl->numprcs = rlvl->numhprcs * rlvl->numvprcs;
+
+    if (!(rlvl->bands = jas_malloc(rlvl->numbands * sizeof(jpc_enc_band_t)))) {
+        goto error;
+    }
+    for (bandno = 0, band = rlvl->bands; bandno < rlvl->numbands;
+      ++bandno, ++band) {
+        band->prcs = 0;
+        band->data = 0;
+        band->rlvl = rlvl;
+    }
+    for (bandno = 0, band = rlvl->bands; bandno < rlvl->numbands;
+      ++bandno, ++band) {
+        if (!band_create(band, cp, rlvl, bandinfos)) {
+            goto error;
+        }
+    }
+
+    return rlvl;
 error:
 
-	rlvl_destroy(rlvl);
-	return 0;
+    rlvl_destroy(rlvl);
+    return 0;
 }
 
 static void rlvl_destroy(jpc_enc_rlvl_t *rlvl)
 {
-	jpc_enc_band_t *band;
-	uint_fast16_t bandno;
-
-	if (rlvl->bands) {
-		for (bandno = 0, band = rlvl->bands; bandno < rlvl->numbands;
-		  ++bandno, ++band) {
-			band_destroy(band);
-		}
-		jas_free(rlvl->bands);
-	}
+    jpc_enc_band_t *band;
+    uint_fast16_t bandno;
+
+    if (rlvl->bands) {
+        for (bandno = 0, band = rlvl->bands; bandno < rlvl->numbands;
+          ++bandno, ++band) {
+            band_destroy(band);
+        }
+        jas_free(rlvl->bands);
+    }
 }
 
 static jpc_enc_band_t *band_create(jpc_enc_band_t *band, jpc_enc_cp_t *cp,
   jpc_enc_rlvl_t *rlvl, jpc_tsfb_band_t *bandinfos)
 {
-	uint_fast16_t bandno;
-	uint_fast16_t gblbandno;
-	uint_fast16_t rlvlno;
-	jpc_tsfb_band_t *bandinfo;
-	jpc_enc_tcmpt_t *tcmpt;
-	uint_fast32_t prcno;
-	jpc_enc_prc_t *prc;
-
-	tcmpt = rlvl->tcmpt;
-	band->data = 0;
-	band->prcs = 0;
-	band->rlvl = rlvl;
-
-	/* Deduce the resolution level and band number. */
-	rlvlno = rlvl - rlvl->tcmpt->rlvls;
-	bandno = band - rlvl->bands;
-	gblbandno = (!rlvlno) ? 0 : (3 * (rlvlno - 1) + bandno + 1);
-
-	bandinfo = &bandinfos[gblbandno];
+    uint_fast16_t bandno;
+    uint_fast16_t gblbandno;
+    uint_fast16_t rlvlno;
+    jpc_tsfb_band_t *bandinfo;
+    jpc_enc_tcmpt_t *tcmpt;
+    uint_fast32_t prcno;
+    jpc_enc_prc_t *prc;
+
+    tcmpt = rlvl->tcmpt;
+    band->data = 0;
+    band->prcs = 0;
+    band->rlvl = rlvl;
+
+    /* Deduce the resolution level and band number. */
+    rlvlno = rlvl - rlvl->tcmpt->rlvls;
+    bandno = band - rlvl->bands;
+    gblbandno = (!rlvlno) ? 0 : (3 * (rlvlno - 1) + bandno + 1);
+
+    bandinfo = &bandinfos[gblbandno];
 
 if (bandinfo->xstart != bandinfo->xend && bandinfo->ystart != bandinfo->yend) {
-	if (!(band->data = jas_seq2d_create(0, 0, 0, 0))) {
-		goto error;
-	}
-	jas_seq2d_bindsub(band->data, tcmpt->data, bandinfo->locxstart,
-	  bandinfo->locystart, bandinfo->locxend, bandinfo->locyend);
-	jas_seq2d_setshift(band->data, bandinfo->xstart, bandinfo->ystart);
+    if (!(band->data = jas_seq2d_create(0, 0, 0, 0))) {
+        goto error;
+    }
+    jas_seq2d_bindsub(band->data, tcmpt->data, bandinfo->locxstart,
+      bandinfo->locystart, bandinfo->locxend, bandinfo->locyend);
+    jas_seq2d_setshift(band->data, bandinfo->xstart, bandinfo->ystart);
 }
-	band->orient = bandinfo->orient;
-	band->analgain = JPC_NOMINALGAIN(cp->tccp.qmfbid, tcmpt->numrlvls, rlvlno,
-	  band->orient);
-	band->numbps = 0;
-	band->absstepsize = 0;
-	band->stepsize = 0;
-	band->synweight = bandinfo->synenergywt;
+    band->orient = bandinfo->orient;
+    band->analgain = JPC_NOMINALGAIN(cp->tccp.qmfbid, tcmpt->numrlvls, rlvlno,
+      band->orient);
+    band->numbps = 0;
+    band->absstepsize = 0;
+    band->stepsize = 0;
+    band->synweight = bandinfo->synenergywt;
 
 if (band->data) {
-	if (!(band->prcs = jas_malloc(rlvl->numprcs * sizeof(jpc_enc_prc_t)))) {
-		goto error;
-	}
-	for (prcno = 0, prc = band->prcs; prcno < rlvl->numprcs; ++prcno,
-	  ++prc) {
-		prc->cblks = 0;
-		prc->incltree = 0;
-		prc->nlibtree = 0;
-		prc->savincltree = 0;
-		prc->savnlibtree = 0;
-		prc->band = band;
-	}
-	for (prcno = 0, prc = band->prcs; prcno < rlvl->numprcs; ++prcno,
-	  ++prc) {
-		if (!prc_create(prc, cp, band)) {
-			goto error;
-		}
-	}
+    if (!(band->prcs = jas_malloc(rlvl->numprcs * sizeof(jpc_enc_prc_t)))) {
+        goto error;
+    }
+    for (prcno = 0, prc = band->prcs; prcno < rlvl->numprcs; ++prcno,
+      ++prc) {
+        prc->cblks = 0;
+        prc->incltree = 0;
+        prc->nlibtree = 0;
+        prc->savincltree = 0;
+        prc->savnlibtree = 0;
+        prc->band = band;
+    }
+    for (prcno = 0, prc = band->prcs; prcno < rlvl->numprcs; ++prcno,
+      ++prc) {
+        if (!prc_create(prc, cp, band)) {
+            goto error;
+        }
+    }
 }
 
-	return band;
+    return band;
 
 error:
-	band_destroy(band);
-	return 0;
+    band_destroy(band);
+    return 0;
 }
 
 static void band_destroy(jpc_enc_band_t *band)
 {
-	jpc_enc_prc_t *prc;
-	jpc_enc_rlvl_t *rlvl;
-	uint_fast32_t prcno;
-
-	if (band->prcs) {
-		rlvl = band->rlvl;
-		for (prcno = 0, prc = band->prcs; prcno < rlvl->numprcs;
-		  ++prcno, ++prc) {
-			prc_destroy(prc);
-		}
-		jas_free(band->prcs);
-	}
-	if (band->data) {
-		jas_seq2d_destroy(band->data);
-	}
+    jpc_enc_prc_t *prc;
+    jpc_enc_rlvl_t *rlvl;
+    uint_fast32_t prcno;
+
+    if (band->prcs) {
+        rlvl = band->rlvl;
+        for (prcno = 0, prc = band->prcs; prcno < rlvl->numprcs;
+          ++prcno, ++prc) {
+            prc_destroy(prc);
+        }
+        jas_free(band->prcs);
+    }
+    if (band->data) {
+        jas_seq2d_destroy(band->data);
+    }
 }
 
 static jpc_enc_prc_t *prc_create(jpc_enc_prc_t *prc, jpc_enc_cp_t *cp, jpc_enc_band_t *band)
 {
-	uint_fast32_t prcno;
-	uint_fast32_t prcxind;
-	uint_fast32_t prcyind;
-	uint_fast32_t cbgtlx;
-	uint_fast32_t cbgtly;
-	uint_fast32_t tlprctlx;
-	uint_fast32_t tlprctly;
-	uint_fast32_t tlcbgtlx;
-	uint_fast32_t tlcbgtly;
-	uint_fast16_t rlvlno;
-	jpc_enc_rlvl_t *rlvl;
-	uint_fast32_t tlcblktlx;
-	uint_fast32_t tlcblktly;
-	uint_fast32_t brcblkbrx;
-	uint_fast32_t brcblkbry;
-	uint_fast32_t cblkno;
-	jpc_enc_cblk_t *cblk;
-	jpc_enc_tcmpt_t *tcmpt;
-
-	prc->cblks = 0;
-	prc->incltree = 0;
-	prc->savincltree = 0;
-	prc->nlibtree = 0;
-	prc->savnlibtree = 0;
-
-	rlvl = band->rlvl;
-	tcmpt = rlvl->tcmpt;
+    uint_fast32_t prcno;
+    uint_fast32_t prcxind;
+    uint_fast32_t prcyind;
+    uint_fast32_t cbgtlx;
+    uint_fast32_t cbgtly;
+    uint_fast32_t tlprctlx;
+    uint_fast32_t tlprctly;
+    uint_fast32_t tlcbgtlx;
+    uint_fast32_t tlcbgtly;
+    uint_fast16_t rlvlno;
+    jpc_enc_rlvl_t *rlvl;
+    uint_fast32_t tlcblktlx;
+    uint_fast32_t tlcblktly;
+    uint_fast32_t brcblkbrx;
+    uint_fast32_t brcblkbry;
+    uint_fast32_t cblkno;
+    jpc_enc_cblk_t *cblk;
+    jpc_enc_tcmpt_t *tcmpt;
+
+    prc->cblks = 0;
+    prc->incltree = 0;
+    prc->savincltree = 0;
+    prc->nlibtree = 0;
+    prc->savnlibtree = 0;
+
+    rlvl = band->rlvl;
+    tcmpt = rlvl->tcmpt;
 rlvlno = rlvl - tcmpt->rlvls;
-	prcno = prc - band->prcs;
-	prcxind = prcno % rlvl->numhprcs;
-	prcyind = prcno / rlvl->numhprcs;
-	prc->band = band;
+    prcno = prc - band->prcs;
+    prcxind = prcno % rlvl->numhprcs;
+    prcyind = prcno / rlvl->numhprcs;
+    prc->band = band;
 
 tlprctlx = JPC_FLOORTOMULTPOW2(rlvl->tlx, rlvl->prcwidthexpn);
 tlprctly = JPC_FLOORTOMULTPOW2(rlvl->tly, rlvl->prcheightexpn);
 if (!rlvlno) {
-	tlcbgtlx = tlprctlx;
-	tlcbgtly = tlprctly;
+    tlcbgtlx = tlprctlx;
+    tlcbgtly = tlprctly;
 } else {
-	tlcbgtlx = JPC_CEILDIVPOW2(tlprctlx, 1);
-	tlcbgtly = JPC_CEILDIVPOW2(tlprctly, 1);
+    tlcbgtlx = JPC_CEILDIVPOW2(tlprctlx, 1);
+    tlcbgtly = JPC_CEILDIVPOW2(tlprctly, 1);
 }
 
-	/* Compute the coordinates of the top-left and bottom-right
-	  corners of the precinct. */
-	cbgtlx = tlcbgtlx + (prcxind << rlvl->cbgwidthexpn);
-	cbgtly = tlcbgtly + (prcyind << rlvl->cbgheightexpn);
-	prc->tlx = JAS_MAX(jas_seq2d_xstart(band->data), cbgtlx);
-	prc->tly = JAS_MAX(jas_seq2d_ystart(band->data), cbgtly);
-	prc->brx = JAS_MIN(jas_seq2d_xend(band->data), cbgtlx +
-	  (1 << rlvl->cbgwidthexpn));
-	prc->bry = JAS_MIN(jas_seq2d_yend(band->data), cbgtly +
-	  (1 << rlvl->cbgheightexpn));
-
-	if (prc->tlx < prc->brx && prc->tly < prc->bry) {
-		/* The precinct contains at least one code block. */
-
-		tlcblktlx = JPC_FLOORTOMULTPOW2(prc->tlx, rlvl->cblkwidthexpn);
-		tlcblktly = JPC_FLOORTOMULTPOW2(prc->tly, rlvl->cblkheightexpn);
-		brcblkbrx = JPC_CEILTOMULTPOW2(prc->brx, rlvl->cblkwidthexpn);
-		brcblkbry = JPC_CEILTOMULTPOW2(prc->bry, rlvl->cblkheightexpn);
-		prc->numhcblks = JPC_FLOORDIVPOW2(brcblkbrx - tlcblktlx,
-		  rlvl->cblkwidthexpn);
-		prc->numvcblks = JPC_FLOORDIVPOW2(brcblkbry - tlcblktly,
-		  rlvl->cblkheightexpn);
-		prc->numcblks = prc->numhcblks * prc->numvcblks;
-
-		if (!(prc->incltree = jpc_tagtree_create(prc->numhcblks,
-		  prc->numvcblks))) {
-			goto error;
-		}
-		if (!(prc->nlibtree = jpc_tagtree_create(prc->numhcblks,
-		  prc->numvcblks))) {
-			goto error;
-		}
-		if (!(prc->savincltree = jpc_tagtree_create(prc->numhcblks,
-		  prc->numvcblks))) {
-			goto error;
-		}
-		if (!(prc->savnlibtree = jpc_tagtree_create(prc->numhcblks,
-		  prc->numvcblks))) {
-			goto error;
-		}
-
-		if (!(prc->cblks = jas_malloc(prc->numcblks * sizeof(jpc_enc_cblk_t)))) {
-			goto error;
-		}
-		for (cblkno = 0, cblk = prc->cblks; cblkno < prc->numcblks;
-		  ++cblkno, ++cblk) {
-			cblk->passes = 0;
-			cblk->stream = 0;
-			cblk->mqenc = 0;
-			cblk->data = 0;
-			cblk->flags = 0;
-			cblk->prc = prc;
-		}
-		for (cblkno = 0, cblk = prc->cblks; cblkno < prc->numcblks;
-		  ++cblkno, ++cblk) {
-			if (!cblk_create(cblk, cp, prc)) {
-				goto error;
-			}
-		}
-	} else {
-		/* The precinct does not contain any code blocks. */
-		prc->tlx = prc->brx;
-		prc->tly = prc->bry;
-		prc->numcblks = 0;
-		prc->numhcblks = 0;
-		prc->numvcblks = 0;
-		prc->cblks = 0;
-		prc->incltree = 0;
-		prc->nlibtree = 0;
-		prc->savincltree = 0;
-		prc->savnlibtree = 0;
-	}
-
-	return prc;
+    /* Compute the coordinates of the top-left and bottom-right
+      corners of the precinct. */
+    cbgtlx = tlcbgtlx + (prcxind << rlvl->cbgwidthexpn);
+    cbgtly = tlcbgtly + (prcyind << rlvl->cbgheightexpn);
+    prc->tlx = JAS_MAX(jas_seq2d_xstart(band->data), cbgtlx);
+    prc->tly = JAS_MAX(jas_seq2d_ystart(band->data), cbgtly);
+    prc->brx = JAS_MIN(jas_seq2d_xend(band->data), cbgtlx +
+      (1 << rlvl->cbgwidthexpn));
+    prc->bry = JAS_MIN(jas_seq2d_yend(band->data), cbgtly +
+      (1 << rlvl->cbgheightexpn));
+
+    if (prc->tlx < prc->brx && prc->tly < prc->bry) {
+        /* The precinct contains at least one code block. */
+
+        tlcblktlx = JPC_FLOORTOMULTPOW2(prc->tlx, rlvl->cblkwidthexpn);
+        tlcblktly = JPC_FLOORTOMULTPOW2(prc->tly, rlvl->cblkheightexpn);
+        brcblkbrx = JPC_CEILTOMULTPOW2(prc->brx, rlvl->cblkwidthexpn);
+        brcblkbry = JPC_CEILTOMULTPOW2(prc->bry, rlvl->cblkheightexpn);
+        prc->numhcblks = JPC_FLOORDIVPOW2(brcblkbrx - tlcblktlx,
+          rlvl->cblkwidthexpn);
+        prc->numvcblks = JPC_FLOORDIVPOW2(brcblkbry - tlcblktly,
+          rlvl->cblkheightexpn);
+        prc->numcblks = prc->numhcblks * prc->numvcblks;
+
+        if (!(prc->incltree = jpc_tagtree_create(prc->numhcblks,
+          prc->numvcblks))) {
+            goto error;
+        }
+        if (!(prc->nlibtree = jpc_tagtree_create(prc->numhcblks,
+          prc->numvcblks))) {
+            goto error;
+        }
+        if (!(prc->savincltree = jpc_tagtree_create(prc->numhcblks,
+          prc->numvcblks))) {
+            goto error;
+        }
+        if (!(prc->savnlibtree = jpc_tagtree_create(prc->numhcblks,
+          prc->numvcblks))) {
+            goto error;
+        }
+
+        if (!(prc->cblks = jas_malloc(prc->numcblks * sizeof(jpc_enc_cblk_t)))) {
+            goto error;
+        }
+        for (cblkno = 0, cblk = prc->cblks; cblkno < prc->numcblks;
+          ++cblkno, ++cblk) {
+            cblk->passes = 0;
+            cblk->stream = 0;
+            cblk->mqenc = 0;
+            cblk->data = 0;
+            cblk->flags = 0;
+            cblk->prc = prc;
+        }
+        for (cblkno = 0, cblk = prc->cblks; cblkno < prc->numcblks;
+          ++cblkno, ++cblk) {
+            if (!cblk_create(cblk, cp, prc)) {
+                goto error;
+            }
+        }
+    } else {
+        /* The precinct does not contain any code blocks. */
+        prc->tlx = prc->brx;
+        prc->tly = prc->bry;
+        prc->numcblks = 0;
+        prc->numhcblks = 0;
+        prc->numvcblks = 0;
+        prc->cblks = 0;
+        prc->incltree = 0;
+        prc->nlibtree = 0;
+        prc->savincltree = 0;
+        prc->savnlibtree = 0;
+    }
+
+    return prc;
 
 error:
-	prc_destroy(prc);
-	return 0;
+    prc_destroy(prc);
+    return 0;
 }
 
 static void prc_destroy(jpc_enc_prc_t *prc)
 {
-	jpc_enc_cblk_t *cblk;
-	uint_fast32_t cblkno;
-
-	if (prc->cblks) {
-		for (cblkno = 0, cblk = prc->cblks; cblkno < prc->numcblks;
-		  ++cblkno, ++cblk) {
-			cblk_destroy(cblk);
-		}
-		jas_free(prc->cblks);
-	}
-	if (prc->incltree) {
-		jpc_tagtree_destroy(prc->incltree);
-	}
-	if (prc->nlibtree) {
-		jpc_tagtree_destroy(prc->nlibtree);
-	}
-	if (prc->savincltree) {
-		jpc_tagtree_destroy(prc->savincltree);
-	}
-	if (prc->savnlibtree) {
-		jpc_tagtree_destroy(prc->savnlibtree);
-	}
+    jpc_enc_cblk_t *cblk;
+    uint_fast32_t cblkno;
+
+    if (prc->cblks) {
+        for (cblkno = 0, cblk = prc->cblks; cblkno < prc->numcblks;
+          ++cblkno, ++cblk) {
+            cblk_destroy(cblk);
+        }
+        jas_free(prc->cblks);
+    }
+    if (prc->incltree) {
+        jpc_tagtree_destroy(prc->incltree);
+    }
+    if (prc->nlibtree) {
+        jpc_tagtree_destroy(prc->nlibtree);
+    }
+    if (prc->savincltree) {
+        jpc_tagtree_destroy(prc->savincltree);
+    }
+    if (prc->savnlibtree) {
+        jpc_tagtree_destroy(prc->savnlibtree);
+    }
 }
 
 static jpc_enc_cblk_t *cblk_create(jpc_enc_cblk_t *cblk, jpc_enc_cp_t *cp, jpc_enc_prc_t *prc)
 {
-	jpc_enc_band_t *band;
-	uint_fast32_t cblktlx;
-	uint_fast32_t cblktly;
-	uint_fast32_t cblkbrx;
-	uint_fast32_t cblkbry;
-	jpc_enc_rlvl_t *rlvl;
-	uint_fast32_t cblkxind;
-	uint_fast32_t cblkyind;
-	uint_fast32_t cblkno;
-	uint_fast32_t tlcblktlx;
-	uint_fast32_t tlcblktly;
-
-	cblkno = cblk - prc->cblks;
-	cblkxind = cblkno % prc->numhcblks;
-	cblkyind = cblkno / prc->numhcblks;
-	rlvl = prc->band->rlvl;
-	cblk->prc = prc;
-
-	cblk->numpasses = 0;
-	cblk->passes = 0;
-	cblk->numencpasses = 0;
-	cblk->numimsbs = 0;
-	cblk->numlenbits = 0;
-	cblk->stream = 0;
-	cblk->mqenc = 0;
-	cblk->flags = 0;
-	cblk->numbps = 0;
-	cblk->curpass = 0;
-	cblk->data = 0;
-	cblk->savedcurpass = 0;
-	cblk->savednumlenbits = 0;
-	cblk->savednumencpasses = 0;
-
-	band = prc->band;
-	tlcblktlx = JPC_FLOORTOMULTPOW2(prc->tlx, rlvl->cblkwidthexpn);
-	tlcblktly = JPC_FLOORTOMULTPOW2(prc->tly, rlvl->cblkheightexpn);
-	cblktlx = JAS_MAX(tlcblktlx + (cblkxind << rlvl->cblkwidthexpn), prc->tlx);
-	cblktly = JAS_MAX(tlcblktly + (cblkyind << rlvl->cblkheightexpn), prc->tly);
-	cblkbrx = JAS_MIN(tlcblktlx + ((cblkxind + 1) << rlvl->cblkwidthexpn),
-	  prc->brx);
-	cblkbry = JAS_MIN(tlcblktly + ((cblkyind + 1) << rlvl->cblkheightexpn),
-	  prc->bry);
-
-	assert(cblktlx < cblkbrx && cblktly < cblkbry);
-	if (!(cblk->data = jas_seq2d_create(0, 0, 0, 0))) {
-		goto error;
-	}
-	jas_seq2d_bindsub(cblk->data, band->data, cblktlx, cblktly, cblkbrx, cblkbry);
-
-	return cblk;
+    jpc_enc_band_t *band;
+    uint_fast32_t cblktlx;
+    uint_fast32_t cblktly;
+    uint_fast32_t cblkbrx;
+    uint_fast32_t cblkbry;
+    jpc_enc_rlvl_t *rlvl;
+    uint_fast32_t cblkxind;
+    uint_fast32_t cblkyind;
+    uint_fast32_t cblkno;
+    uint_fast32_t tlcblktlx;
+    uint_fast32_t tlcblktly;
+
+    cblkno = cblk - prc->cblks;
+    cblkxind = cblkno % prc->numhcblks;
+    cblkyind = cblkno / prc->numhcblks;
+    rlvl = prc->band->rlvl;
+    cblk->prc = prc;
+
+    cblk->numpasses = 0;
+    cblk->passes = 0;
+    cblk->numencpasses = 0;
+    cblk->numimsbs = 0;
+    cblk->numlenbits = 0;
+    cblk->stream = 0;
+    cblk->mqenc = 0;
+    cblk->flags = 0;
+    cblk->numbps = 0;
+    cblk->curpass = 0;
+    cblk->data = 0;
+    cblk->savedcurpass = 0;
+    cblk->savednumlenbits = 0;
+    cblk->savednumencpasses = 0;
+
+    band = prc->band;
+    tlcblktlx = JPC_FLOORTOMULTPOW2(prc->tlx, rlvl->cblkwidthexpn);
+    tlcblktly = JPC_FLOORTOMULTPOW2(prc->tly, rlvl->cblkheightexpn);
+    cblktlx = JAS_MAX(tlcblktlx + (cblkxind << rlvl->cblkwidthexpn), prc->tlx);
+    cblktly = JAS_MAX(tlcblktly + (cblkyind << rlvl->cblkheightexpn), prc->tly);
+    cblkbrx = JAS_MIN(tlcblktlx + ((cblkxind + 1) << rlvl->cblkwidthexpn),
+      prc->brx);
+    cblkbry = JAS_MIN(tlcblktly + ((cblkyind + 1) << rlvl->cblkheightexpn),
+      prc->bry);
+
+    assert(cblktlx < cblkbrx && cblktly < cblkbry);
+    if (!(cblk->data = jas_seq2d_create(0, 0, 0, 0))) {
+        goto error;
+    }
+    jas_seq2d_bindsub(cblk->data, band->data, cblktlx, cblktly, cblkbrx, cblkbry);
+
+    return cblk;
 
 error:
-	cblk_destroy(cblk);
-	return 0;
+    cblk_destroy(cblk);
+    return 0;
 }
 
 static void cblk_destroy(jpc_enc_cblk_t *cblk)
 {
-	uint_fast16_t passno;
-	jpc_enc_pass_t *pass;
-	if (cblk->passes) {
-		for (passno = 0, pass = cblk->passes; passno < cblk->numpasses;
-		  ++passno, ++pass) {
-			pass_destroy(pass);
-		}
-		jas_free(cblk->passes);
-	}
-	if (cblk->stream) {
-		jas_stream_close(cblk->stream);
-	}
-	if (cblk->mqenc) {
-		jpc_mqenc_destroy(cblk->mqenc);
-	}
-	if (cblk->data) {
-		jas_seq2d_destroy(cblk->data);
-	}
-	if (cblk->flags) {
-		jas_seq2d_destroy(cblk->flags);
-	}
+    uint_fast16_t passno;
+    jpc_enc_pass_t *pass;
+    if (cblk->passes) {
+        for (passno = 0, pass = cblk->passes; passno < cblk->numpasses;
+          ++passno, ++pass) {
+            pass_destroy(pass);
+        }
+        jas_free(cblk->passes);
+    }
+    if (cblk->stream) {
+        jas_stream_close(cblk->stream);
+    }
+    if (cblk->mqenc) {
+        jpc_mqenc_destroy(cblk->mqenc);
+    }
+    if (cblk->data) {
+        jas_seq2d_destroy(cblk->data);
+    }
+    if (cblk->flags) {
+        jas_seq2d_destroy(cblk->flags);
+    }
 }
 
 static void pass_destroy(jpc_enc_pass_t *pass)
 {
-	/* XXX - need to free resources here */
+    /* XXX - need to free resources here */
 }
 
 void jpc_enc_dump(jpc_enc_t *enc)
 {
-	jpc_enc_tile_t *tile;
-	jpc_enc_tcmpt_t *tcmpt;
-	jpc_enc_rlvl_t *rlvl;
-	jpc_enc_band_t *band;
-	jpc_enc_prc_t *prc;
-	jpc_enc_cblk_t *cblk;
-	uint_fast16_t cmptno;
-	uint_fast16_t rlvlno;
-	uint_fast16_t bandno;
-	uint_fast32_t prcno;
-	uint_fast32_t cblkno;
-
-	tile = enc->curtile;
-
-	for (cmptno = 0, tcmpt = tile->tcmpts; cmptno < tile->numtcmpts; ++cmptno,
-	  ++tcmpt) {
-		fprintf(stderr, "  tcmpt %5d %5d %5d %5d\n", jas_seq2d_xstart(tcmpt->data), jas_seq2d_ystart(tcmpt->data), jas_seq2d_xend(tcmpt->data), jas_seq2d_yend(tcmpt->data));
-		for (rlvlno = 0, rlvl = tcmpt->rlvls; rlvlno < tcmpt->numrlvls;
-		  ++rlvlno, ++rlvl) {
-			fprintf(stderr, "    rlvl %5d %5d %5d %5d\n", rlvl->tlx, rlvl->tly, rlvl->brx, rlvl->bry);
-			for (bandno = 0, band = rlvl->bands; bandno < rlvl->numbands;
-			  ++bandno, ++band) {
-				if (!band->data) {
-					continue;
-				}
-				fprintf(stderr, "      band %5d %5d %5d %5d\n", jas_seq2d_xstart(band->data), jas_seq2d_ystart(band->data), jas_seq2d_xend(band->data), jas_seq2d_yend(band->data));
-				for (prcno = 0, prc = band->prcs; prcno < rlvl->numprcs;
-				  ++prcno, ++prc) {
-					fprintf(stderr, "        prc %5d %5d %5d %5d (%5d %5d)\n", prc->tlx, prc->tly, prc->brx, prc->bry, prc->brx - prc->tlx, prc->bry - prc->tly);
-					if (!prc->cblks) {
-						continue;
-					}
-					for (cblkno = 0, cblk = prc->cblks; cblkno < prc->numcblks;
-					  ++cblkno, ++cblk) {
-						fprintf(stderr, "         cblk %5d %5d %5d %5d\n", jas_seq2d_xstart(cblk->data), jas_seq2d_ystart(cblk->data), jas_seq2d_xend(cblk->data), jas_seq2d_yend(cblk->data));
-					}
-				}
-			}
-		}
-	}
+    jpc_enc_tile_t *tile;
+    jpc_enc_tcmpt_t *tcmpt;
+    jpc_enc_rlvl_t *rlvl;
+    jpc_enc_band_t *band;
+    jpc_enc_prc_t *prc;
+    jpc_enc_cblk_t *cblk;
+    uint_fast16_t cmptno;
+    uint_fast16_t rlvlno;
+    uint_fast16_t bandno;
+    uint_fast32_t prcno;
+    uint_fast32_t cblkno;
+
+    tile = enc->curtile;
+
+    for (cmptno = 0, tcmpt = tile->tcmpts;
+         cmptno < tile->numtcmpts;
+         ++cmptno, ++tcmpt) {
+        fprintf(stderr, "  tcmpt %5d %5d %5d %5d\n",
+                (int)jas_seq2d_xstart(tcmpt->data),
+                (int)jas_seq2d_ystart(tcmpt->data),
+                (int)jas_seq2d_xend(tcmpt->data),
+                (int)jas_seq2d_yend(tcmpt->data));
+        for (rlvlno = 0, rlvl = tcmpt->rlvls;
+             rlvlno < tcmpt->numrlvls;
+          ++rlvlno, ++rlvl) {
+            fprintf(stderr, "    rlvl %5d %5d %5d %5d\n",
+                    (int)rlvl->tlx, (int)rlvl->tly,
+                    (int)rlvl->brx, (int)rlvl->bry);
+            for (bandno = 0, band = rlvl->bands; bandno < rlvl->numbands;
+              ++bandno, ++band) {
+                if (!band->data) {
+                    continue;
+                }
+                fprintf(stderr, "      band %5d %5d %5d %5d\n",
+                        (int)jas_seq2d_xstart(band->data),
+                        (int)jas_seq2d_ystart(band->data),
+                        (int)jas_seq2d_xend(band->data),
+                        (int)jas_seq2d_yend(band->data));
+                for (prcno = 0, prc = band->prcs;
+                     prcno < rlvl->numprcs;
+                     ++prcno, ++prc) {
+                    fprintf(stderr, "        prc %5d %5d %5d %5d (%5d %5d)\n",
+                            (int)prc->tlx, (int)prc->tly, 
+                            (int)prc->brx, (int)prc->bry,
+                            (int)(prc->brx - prc->tlx), 
+                            (int)(prc->bry - prc->tly));
+                    if (!prc->cblks) {
+                        continue;
+                    }
+                    for (cblkno = 0, cblk = prc->cblks; cblkno < prc->numcblks;
+                      ++cblkno, ++cblk) {
+                        fprintf(stderr, "         cblk %5d %5d %5d %5d\n",
+                                (int)jas_seq2d_xstart(cblk->data),
+                                (int)jas_seq2d_ystart(cblk->data),
+                                (int)jas_seq2d_xend(cblk->data),
+                                (int)jas_seq2d_yend(cblk->data));
+                    }
+                }
+            }
+        }
+    }
+}
+
+
+
+static int jpc_enc_encodemainbody(jpc_enc_t *enc)
+{
+    int tileno;
+    int tilex;
+    int tiley;
+    int i;
+    jpc_sot_t *sot;
+    jpc_enc_tcmpt_t *comp;
+    jpc_enc_tcmpt_t *endcomps;
+    jpc_enc_band_t *band;
+    jpc_enc_band_t *endbands;
+    jpc_enc_rlvl_t *lvl;
+    int rlvlno;
+    jpc_qcc_t *qcc;
+    jpc_cod_t *cod;
+    int adjust;
+    int j;
+    int absbandno;
+    long numbytes;
+    long tilehdrlen;
+    long tilelen;
+    jpc_enc_tile_t *tile;
+    jpc_enc_cp_t *cp;
+    double rho;
+    uint_fast16_t cmptno;
+    int samestepsizes;
+    jpc_enc_ccp_t *ccps;
+    jpc_enc_tccp_t *tccp;
+    int bandno;
+    uint_fast32_t x;
+    uint_fast32_t y;
+    int mingbits;
+    int actualnumbps;
+    jpc_fix_t mxmag;
+    jpc_fix_t mag;
+    int numgbits;
+    const char * error;
+
+    cp = enc->cp;
+
+    /* Avoid compile warnings. */
+    numbytes = 0;
+
+    for (tileno = 0; tileno < cp->numtiles; ++tileno) {
+        tilex = tileno % cp->numhtiles;
+        tiley = tileno / cp->numhtiles;
+
+        enc->curtile = jpc_enc_tile_create(enc->cp, enc->image, tileno);
+        if (!enc->curtile)
+            abort();
+
+        tile = enc->curtile;
+
+        if (jas_getdbglevel() >= 10) {
+            jpc_enc_dump(enc);
+        }
+
+        endcomps = &tile->tcmpts[tile->numtcmpts];
+        for (cmptno = 0, comp = tile->tcmpts;
+             cmptno < tile->numtcmpts;
+             ++cmptno, ++comp) {
+            if (!cp->ccps[cmptno].sgnd) {
+                adjust = 1 << (cp->ccps[cmptno].prec - 1);
+                for (i = 0; i < jas_matrix_numrows(comp->data); ++i) {
+                    for (j = 0; j < jas_matrix_numcols(comp->data); ++j) {
+                        *jas_matrix_getref(comp->data, i, j) -= adjust;
+                    }
+                }
+            }
+        }
+
+        if (!tile->intmode) {
+            endcomps = &tile->tcmpts[tile->numtcmpts];
+            for (comp = tile->tcmpts; comp != endcomps; ++comp) {
+                jas_matrix_asl(comp->data, JPC_FIX_FRACBITS);
+            }
+        }
+
+        switch (tile->mctid) {
+        case JPC_MCT_RCT:
+            assert(jas_image_numcmpts(enc->image) == 3);
+            jpc_rct(tile->tcmpts[0].data, tile->tcmpts[1].data,
+                    tile->tcmpts[2].data);
+            break;
+        case JPC_MCT_ICT:
+            assert(jas_image_numcmpts(enc->image) == 3);
+            jpc_ict(tile->tcmpts[0].data, tile->tcmpts[1].data,
+                    tile->tcmpts[2].data);
+            break;
+        default:
+            break;
+        }
+
+        for (i = 0; i < jas_image_numcmpts(enc->image); ++i) {
+            comp = &tile->tcmpts[i];
+            jpc_tsfb_analyze(comp->tsfb,
+                             ((comp->qmfbid == JPC_COX_RFT) ?
+                              JPC_TSFB_RITIMODE : 0), comp->data);
+
+        }
+
+
+        endcomps = &tile->tcmpts[tile->numtcmpts];
+        for (cmptno = 0, comp = tile->tcmpts;
+             comp != endcomps;
+             ++cmptno, ++comp) {
+            mingbits = 0;
+            absbandno = 0;
+            /* All bands must have a corresponding quantizer step size,
+               even if they contain no samples and are never coded. */
+            /* Some bands may not be hit by the loop below, so we must
+               initialize all of the step sizes to a sane value. */
+            memset(comp->stepsizes, 0, sizeof(comp->stepsizes));
+            for (rlvlno = 0, lvl = comp->rlvls;
+                 rlvlno < comp->numrlvls;
+                 ++rlvlno, ++lvl) {
+                if (!lvl->bands) {
+                    absbandno += rlvlno ? 3 : 1;
+                    continue;
+                }
+                endbands = &lvl->bands[lvl->numbands];
+                for (band = lvl->bands; band != endbands; ++band) {
+                    if (!band->data) {
+                        ++absbandno;
+                        continue;
+                    }
+                    actualnumbps = 0;
+                    mxmag = 0;
+                    for (y = 0; y < jas_matrix_numrows(band->data); ++y) {
+                        for (x = 0; x < jas_matrix_numcols(band->data); ++x) {
+                            mag = abs(jas_matrix_get(band->data, y, x));
+                            if (mag > mxmag) {
+                                mxmag = mag;
+                            }
+                        }
+                    }
+                    if (tile->intmode) {
+                        actualnumbps =
+                            jpc_firstone(mxmag) + 1;
+                    } else {
+                        actualnumbps =
+                            jpc_firstone(mxmag) + 1 - JPC_FIX_FRACBITS;
+                    }
+                    numgbits = actualnumbps - (cp->ccps[cmptno].prec - 1 +
+                                               band->analgain);
+                    if (numgbits > mingbits) {
+                        mingbits = numgbits;
+                    }
+                    if (!tile->intmode) {
+                        band->absstepsize =
+                            jpc_fix_div(
+                                jpc_inttofix(1 << (band->analgain + 1)),
+                                band->synweight);
+                    } else {
+                        band->absstepsize = jpc_inttofix(1);
+                    }
+                    band->stepsize = jpc_abstorelstepsize(
+                        band->absstepsize, cp->ccps[cmptno].prec +
+                        band->analgain);
+                    band->numbps = cp->tccp.numgbits +
+                        JPC_QCX_GETEXPN(band->stepsize) - 1;
+
+                    if ((!tile->intmode) && band->data) {
+                        quantize(band->data, band->absstepsize);
+                    }
+
+                    comp->stepsizes[absbandno] = band->stepsize;
+                    ++absbandno;
+                }
+            }
+
+            assert(JPC_FIX_FRACBITS >= JPC_NUMEXTRABITS);
+            if (!tile->intmode) {
+                jas_matrix_divpow2(comp->data,
+                                   JPC_FIX_FRACBITS - JPC_NUMEXTRABITS);
+            } else {
+                jas_matrix_asl(comp->data, JPC_NUMEXTRABITS);
+            }
+        }
+
+        if (mingbits > cp->tccp.numgbits) {
+            fprintf(stderr, "error: too few guard bits (need at least %d)\n",
+                    mingbits);
+            return -1;
+        }
+
+        if (!(enc->tmpstream = jas_stream_memopen(0, 0))) {
+            fprintf(stderr, "cannot open tmp file\n");
+            return -1;
+        }
+
+        /* Write the tile header. */
+        if (!(enc->mrk = jpc_ms_create(JPC_MS_SOT))) {
+            return -1;
+        }
+        sot = &enc->mrk->parms.sot;
+        sot->len = 0;
+        sot->tileno = tileno;
+        sot->partno = 0;
+        sot->numparts = 1;
+        if (jpc_putms(enc->tmpstream, enc->cstate, enc->mrk)) {
+            fprintf(stderr, "cannot write SOT marker\n");
+            return -1;
+        }
+        jpc_ms_destroy(enc->mrk);
+        enc->mrk = 0;
+
+/************************************************************************/
+/************************************************************************/
+/************************************************************************/
+
+        tccp = &cp->tccp;
+        for (cmptno = 0; cmptno < cp->numcmpts; ++cmptno) {
+            comp = &tile->tcmpts[cmptno];
+            if (comp->numrlvls != tccp->maxrlvls) {
+                if (!(enc->mrk = jpc_ms_create(JPC_MS_COD))) {
+                    return -1;
+                }
+                /* XXX = this is not really correct. we are using comp #0's
+                   precint sizes and other characteristics */
+                comp = &tile->tcmpts[0];
+                cod = &enc->mrk->parms.cod;
+                cod->compparms.csty = 0;
+                cod->compparms.numdlvls = comp->numrlvls - 1;
+                cod->prg = tile->prg;
+                cod->numlyrs = tile->numlyrs;
+                cod->compparms.cblkwidthval =
+                    JPC_COX_CBLKSIZEEXPN(comp->cblkwidthexpn);
+                cod->compparms.cblkheightval =
+                    JPC_COX_CBLKSIZEEXPN(comp->cblkheightexpn);
+                cod->compparms.cblksty = comp->cblksty;
+                cod->compparms.qmfbid = comp->qmfbid;
+                cod->mctrans = (tile->mctid != JPC_MCT_NONE);
+                for (i = 0; i < comp->numrlvls; ++i) {
+                    cod->compparms.rlvls[i].parwidthval =
+                        comp->rlvls[i].prcwidthexpn;
+                    cod->compparms.rlvls[i].parheightval =
+                        comp->rlvls[i].prcheightexpn;
+                }
+                if (jpc_putms(enc->tmpstream, enc->cstate, enc->mrk)) {
+                    return -1;
+                }
+                jpc_ms_destroy(enc->mrk);
+                enc->mrk = 0;
+            }
+        }
+
+        for (cmptno = 0, comp = tile->tcmpts;
+             cmptno < cp->numcmpts;
+             ++cmptno, ++comp) {
+            ccps = &cp->ccps[cmptno];
+            if (ccps->numstepsizes == comp->numstepsizes) {
+                samestepsizes = 1;
+                for (bandno = 0; bandno < ccps->numstepsizes; ++bandno) {
+                    if (ccps->stepsizes[bandno] != comp->stepsizes[bandno]) {
+                        samestepsizes = 0;
+                        break;
+                    }
+                }
+            } else {
+                samestepsizes = 0;
+            }
+            if (!samestepsizes) {
+                if (!(enc->mrk = jpc_ms_create(JPC_MS_QCC))) {
+                    return -1;
+                }
+                qcc = &enc->mrk->parms.qcc;
+                qcc->compno = cmptno;
+                qcc->compparms.numguard = cp->tccp.numgbits;
+                qcc->compparms.qntsty = (comp->qmfbid == JPC_COX_INS) ?
+                    JPC_QCX_SEQNT : JPC_QCX_NOQNT;
+                qcc->compparms.numstepsizes = comp->numstepsizes;
+                qcc->compparms.stepsizes = comp->stepsizes;
+                if (jpc_putms(enc->tmpstream, enc->cstate, enc->mrk)) {
+                    return -1;
+                }
+                qcc->compparms.stepsizes = 0;
+                jpc_ms_destroy(enc->mrk);
+                enc->mrk = 0;
+            }
+        }
+
+        /* Write a SOD marker to indicate the end of the tile header. */
+        if (!(enc->mrk = jpc_ms_create(JPC_MS_SOD))) {
+            return -1;
+        }
+        if (jpc_putms(enc->tmpstream, enc->cstate, enc->mrk)) {
+            fprintf(stderr, "cannot write SOD marker\n");
+            return -1;
+        }
+        jpc_ms_destroy(enc->mrk);
+        enc->mrk = 0;
+        tilehdrlen = jas_stream_getrwcount(enc->tmpstream);
+
+/************************************************************************/
+/************************************************************************/
+/************************************************************************/
+
+        if (jpc_enc_enccblks(enc)) {
+            abort();
+            return -1;
+        }
+
+        cp = enc->cp;
+        rho = (double) (tile->brx - tile->tlx) * (tile->bry - tile->tly) /
+            ((cp->refgrdwidth - cp->imgareatlx) * (cp->refgrdheight -
+                                                   cp->imgareatly));
+        tile->rawsize = cp->rawsize * rho;
+
+        computeLayerSizes(enc, tile, cp, rho, tilehdrlen, &error);
+        
+        if (!error) {
+            int rc;
+            performTier2Coding(enc, tile->numlyrs, tile->lyrsizes, &error);
+
+            rc =  jpc_enc_encodetiledata(enc);
+            if (rc != 0)
+                pm_asprintf(&error, "jpc_enc_encodetiledata() failed\n");
+        }
+
+        if (error) {
+            fprintf(stderr, "%s\n", error);
+            pm_strfree(error);
+            return -1;
+        }
+
+        tilelen = jas_stream_tell(enc->tmpstream);
+
+        if (jas_stream_seek(enc->tmpstream, 6, SEEK_SET) < 0) {
+            return -1;
+        }
+        jpc_putuint32(enc->tmpstream, tilelen);
+
+        if (jas_stream_seek(enc->tmpstream, 0, SEEK_SET) < 0) {
+            return -1;
+        }
+        if (jpc_putdata(enc->out, enc->tmpstream, -1)) {
+            return -1;
+        }
+        enc->len += tilelen;
+
+        jas_stream_close(enc->tmpstream);
+        enc->tmpstream = 0;
+
+        jpc_enc_tile_destroy(enc->curtile);
+        enc->curtile = 0;
+
+    }
+
+    return 0;
 }
+
+
+
+/*
+ * Copyright (c) 1999-2000 Image Power, Inc. and the University of
+ *   British Columbia.
+ * Copyright (c) 2001-2002 Michael David Adams.
+ * All rights reserved.
+ */
+
+/* __START_OF_JASPER_LICENSE__
+ * 
+ * JasPer Software License
+ * 
+ * IMAGE POWER JPEG-2000 PUBLIC LICENSE
+ * ************************************
+ * 
+ * GRANT:
+ * 
+ * Permission is hereby granted, free of charge, to any person (the "User")
+ * obtaining a copy of this software and associated documentation, to deal
+ * in the JasPer Software without restriction, including without limitation
+ * the right to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the JasPer Software (in source and binary forms),
+ * and to permit persons to whom the JasPer Software is furnished to do so,
+ * provided further that the License Conditions below are met.
+ * 
+ * License Conditions
+ * ******************
+ * 
+ * A.  Redistributions of source code must retain the above copyright notice,
+ * and this list of conditions, and the following disclaimer.
+ * 
+ * B.  Redistributions in binary form must reproduce the above copyright
+ * notice, and this list of conditions, and the following disclaimer in
+ * the documentation and/or other materials provided with the distribution.
+ * 
+ * C.  Neither the name of Image Power, Inc. nor any other contributor
+ * (including, but not limited to, the University of British Columbia and
+ * Michael David Adams) may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ * 
+ * D.  User agrees that it shall not commence any action against Image Power,
+ * Inc., the University of British Columbia, Michael David Adams, or any
+ * other contributors (collectively "Licensors") for infringement of any
+ * intellectual property rights ("IPR") held by the User in respect of any
+ * technology that User owns or has a right to license or sublicense and
+ * which is an element required in order to claim compliance with ISO/IEC
+ * 15444-1 (i.e., JPEG-2000 Part 1).  "IPR" means all intellectual property
+ * rights worldwide arising under statutory or common law, and whether
+ * or not perfected, including, without limitation, all (i) patents and
+ * patent applications owned or licensable by User; (ii) rights associated
+ * with works of authorship including copyrights, copyright applications,
+ * copyright registrations, mask work rights, mask work applications,
+ * mask work registrations; (iii) rights relating to the protection of
+ * trade secrets and confidential information; (iv) any right analogous
+ * to those set forth in subsections (i), (ii), or (iii) and any other
+ * proprietary rights relating to intangible property (other than trademark,
+ * trade dress, or service mark rights); and (v) divisions, continuations,
+ * renewals, reissues and extensions of the foregoing (as and to the extent
+ * applicable) now existing, hereafter filed, issued or acquired.
+ * 
+ * E.  If User commences an infringement action against any Licensor(s) then
+ * such Licensor(s) shall have the right to terminate User's license and
+ * all sublicenses that have been granted hereunder by User to other parties.
+ * 
+ * F.  This software is for use only in hardware or software products that
+ * are compliant with ISO/IEC 15444-1 (i.e., JPEG-2000 Part 1).  No license
+ * or right to this Software is granted for products that do not comply
+ * with ISO/IEC 15444-1.  The JPEG-2000 Part 1 standard can be purchased
+ * from the ISO.
+ * 
+ * THIS DISCLAIMER OF WARRANTY CONSTITUTES AN ESSENTIAL PART OF THIS LICENSE.
+ * NO USE OF THE JASPER SOFTWARE IS AUTHORIZED HEREUNDER EXCEPT UNDER
+ * THIS DISCLAIMER.  THE JASPER SOFTWARE IS PROVIDED BY THE LICENSORS AND
+ * CONTRIBUTORS UNDER THIS LICENSE ON AN ``AS-IS'' BASIS, WITHOUT WARRANTY
+ * OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, WITHOUT LIMITATION,
+ * WARRANTIES THAT THE JASPER SOFTWARE IS FREE OF DEFECTS, IS MERCHANTABLE,
+ * IS FIT FOR A PARTICULAR PURPOSE OR IS NON-INFRINGING.  THOSE INTENDING
+ * TO USE THE JASPER SOFTWARE OR MODIFICATIONS THEREOF FOR USE IN HARDWARE
+ * OR SOFTWARE PRODUCTS ARE ADVISED THAT THEIR USE MAY INFRINGE EXISTING
+ * PATENTS, COPYRIGHTS, TRADEMARKS, OR OTHER INTELLECTUAL PROPERTY RIGHTS.
+ * THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE JASPER SOFTWARE
+ * IS WITH THE USER.  SHOULD ANY PART OF THE JASPER SOFTWARE PROVE DEFECTIVE
+ * IN ANY RESPECT, THE USER (AND NOT THE INITIAL DEVELOPERS, THE UNIVERSITY
+ * OF BRITISH COLUMBIA, IMAGE POWER, INC., MICHAEL DAVID ADAMS, OR ANY
+ * OTHER CONTRIBUTOR) SHALL ASSUME THE COST OF ANY NECESSARY SERVICING,
+ * REPAIR OR CORRECTION.  UNDER NO CIRCUMSTANCES AND UNDER NO LEGAL THEORY,
+ * WHETHER TORT (INCLUDING NEGLIGENCE), CONTRACT, OR OTHERWISE, SHALL THE
+ * INITIAL DEVELOPER, THE UNIVERSITY OF BRITISH COLUMBIA, IMAGE POWER, INC.,
+ * MICHAEL DAVID ADAMS, ANY OTHER CONTRIBUTOR, OR ANY DISTRIBUTOR OF THE
+ * JASPER SOFTWARE, OR ANY SUPPLIER OF ANY OF SUCH PARTIES, BE LIABLE TO
+ * THE USER OR ANY OTHER PERSON FOR ANY INDIRECT, SPECIAL, INCIDENTAL, OR
+ * CONSEQUENTIAL DAMAGES OF ANY CHARACTER INCLUDING, WITHOUT LIMITATION,
+ * DAMAGES FOR LOSS OF GOODWILL, WORK STOPPAGE, COMPUTER FAILURE OR
+ * MALFUNCTION, OR ANY AND ALL OTHER COMMERCIAL DAMAGES OR LOSSES, EVEN IF
+ * SUCH PARTY HAD BEEN INFORMED, OR OUGHT TO HAVE KNOWN, OF THE POSSIBILITY
+ * OF SUCH DAMAGES.  THE JASPER SOFTWARE AND UNDERLYING TECHNOLOGY ARE NOT
+ * FAULT-TOLERANT AND ARE NOT DESIGNED, MANUFACTURED OR INTENDED FOR USE OR
+ * RESALE AS ON-LINE CONTROL EQUIPMENT IN HAZARDOUS ENVIRONMENTS REQUIRING
+ * FAIL-SAFE PERFORMANCE, SUCH AS IN THE OPERATION OF NUCLEAR FACILITIES,
+ * AIRCRAFT NAVIGATION OR COMMUNICATION SYSTEMS, AIR TRAFFIC CONTROL, DIRECT
+ * LIFE SUPPORT MACHINES, OR WEAPONS SYSTEMS, IN WHICH THE FAILURE OF THE
+ * JASPER SOFTWARE OR UNDERLYING TECHNOLOGY OR PRODUCT COULD LEAD DIRECTLY
+ * TO DEATH, PERSONAL INJURY, OR SEVERE PHYSICAL OR ENVIRONMENTAL DAMAGE
+ * ("HIGH RISK ACTIVITIES").  LICENSOR SPECIFICALLY DISCLAIMS ANY EXPRESS
+ * OR IMPLIED WARRANTY OF FITNESS FOR HIGH RISK ACTIVITIES.  USER WILL NOT
+ * KNOWINGLY USE, DISTRIBUTE OR RESELL THE JASPER SOFTWARE OR UNDERLYING
+ * TECHNOLOGY OR PRODUCTS FOR HIGH RISK ACTIVITIES AND WILL ENSURE THAT ITS
+ * CUSTOMERS AND END-USERS OF ITS PRODUCTS ARE PROVIDED WITH A COPY OF THE
+ * NOTICE SPECIFIED IN THIS SECTION.
+ * 
+ * __END_OF_JASPER_LICENSE__
+ */
+
diff --git a/converter/other/jpeg2000/libjasper/jpc/jpc_math.h b/converter/other/jpeg2000/libjasper/jpc/jpc_math.h
index e343bab1..77df0c62 100644
--- a/converter/other/jpeg2000/libjasper/jpc/jpc_math.h
+++ b/converter/other/jpeg2000/libjasper/jpc/jpc_math.h
@@ -135,7 +135,7 @@
 #define	JPC_CEILDIVPOW2(x, y) \
 	(assert(x >= 0 && y >= 0), ((x) + (1 << (y)) - 1) >> (y))
 /* JPC_CEILDIVPOW2U is for unsigned arguments (JPC_CEILDIVPOW2 would generate
-   compiler warnings due to its superfluous >= 0 check)
+   compiler warnings because of its superfluous >= 0 check)
 */
 #define	JPC_CEILDIVPOW2U(x, y) \
 	(((x) + (1 << (y)) - 1) >> (y))
diff --git a/converter/other/jpeg2000/libjasper/jpc/jpc_mqcod.h b/converter/other/jpeg2000/libjasper/jpc/jpc_mqcod.h
index 914f8e8a..5f99e021 100644
--- a/converter/other/jpeg2000/libjasper/jpc/jpc_mqcod.h
+++ b/converter/other/jpeg2000/libjasper/jpc/jpc_mqcod.h
@@ -123,7 +123,7 @@
 * Includes.
 \*****************************************************************************/
 
-#include "pm_c_util.h"
+#include "netpbm/pm_c_util.h"
 #include "jasper/jas_types.h"
 
 /*****************************************************************************\
diff --git a/converter/other/jpeg2000/libjasper/jpc/jpc_mqenc.c b/converter/other/jpeg2000/libjasper/jpc/jpc_mqenc.c
index 0219a000..3f6122e3 100644
--- a/converter/other/jpeg2000/libjasper/jpc/jpc_mqenc.c
+++ b/converter/other/jpeg2000/libjasper/jpc/jpc_mqenc.c
@@ -135,91 +135,91 @@
 \******************************************************************************/
 
 #if defined(DEBUG)
-#define	JPC_MQENC_CALL(n, x) \
-	((jas_getdbglevel() >= (n)) ? ((void)(x)) : ((void)0))
+#define JPC_MQENC_CALL(n, x) \
+    ((jas_getdbglevel() >= (n)) ? ((void)(x)) : ((void)0))
 #else
-#define	JPC_MQENC_CALL(n, x)
+#define JPC_MQENC_CALL(n, x)
 #endif
 
-#define	jpc_mqenc_codemps9(areg, creg, ctreg, curctx, enc) \
+#define jpc_mqenc_codemps9(areg, creg, ctreg, curctx, enc) \
 { \
-	jpc_mqstate_t *state = *(curctx); \
-	(areg) -= state->qeval; \
-	if (!((areg) & 0x8000)) { \
-		if ((areg) < state->qeval) { \
-			(areg) = state->qeval; \
-		} else { \
-			(creg) += state->qeval; \
-		} \
-		*(curctx) = state->nmps; \
-		jpc_mqenc_renorme((areg), (creg), (ctreg), (enc)); \
-	} else { \
-		(creg) += state->qeval; \
-	} \
+    jpc_mqstate_t *state = *(curctx); \
+    (areg) -= state->qeval; \
+    if (!((areg) & 0x8000)) { \
+        if ((areg) < state->qeval) { \
+            (areg) = state->qeval; \
+        } else { \
+            (creg) += state->qeval; \
+        } \
+        *(curctx) = state->nmps; \
+        jpc_mqenc_renorme((areg), (creg), (ctreg), (enc)); \
+    } else { \
+        (creg) += state->qeval; \
+    } \
 }
 
-#define	jpc_mqenc_codelps2(areg, creg, ctreg, curctx, enc) \
+#define jpc_mqenc_codelps2(areg, creg, ctreg, curctx, enc) \
 { \
-	jpc_mqstate_t *state = *(curctx); \
-	(areg) -= state->qeval; \
-	if ((areg) < state->qeval) { \
-		(creg) += state->qeval; \
-	} else { \
-		(areg) = state->qeval; \
-	} \
-	*(curctx) = state->nlps; \
-	jpc_mqenc_renorme((areg), (creg), (ctreg), (enc)); \
+    jpc_mqstate_t *state = *(curctx); \
+    (areg) -= state->qeval; \
+    if ((areg) < state->qeval) { \
+        (creg) += state->qeval; \
+    } else { \
+        (areg) = state->qeval; \
+    } \
+    *(curctx) = state->nlps; \
+    jpc_mqenc_renorme((areg), (creg), (ctreg), (enc)); \
 }
 
-#define	jpc_mqenc_renorme(areg, creg, ctreg, enc) \
+#define jpc_mqenc_renorme(areg, creg, ctreg, enc) \
 { \
-	do { \
-		(areg) <<= 1; \
-		(creg) <<= 1; \
-		if (!--(ctreg)) { \
-			jpc_mqenc_byteout((areg), (creg), (ctreg), (enc)); \
-		} \
-	} while (!((areg) & 0x8000)); \
+    do { \
+        (areg) <<= 1; \
+        (creg) <<= 1; \
+        if (!--(ctreg)) { \
+            jpc_mqenc_byteout((areg), (creg), (ctreg), (enc)); \
+        } \
+    } while (!((areg) & 0x8000)); \
 }
 
-#define	jpc_mqenc_byteout(areg, creg, ctreg, enc) \
+#define jpc_mqenc_byteout(areg, creg, ctreg, enc) \
 { \
-	if ((enc)->outbuf != 0xff) { \
-		if ((creg) & 0x8000000) { \
-			if (++((enc)->outbuf) == 0xff) { \
-				(creg) &= 0x7ffffff; \
-				jpc_mqenc_byteout2(enc); \
-				enc->outbuf = ((creg) >> 20) & 0xff; \
-				(creg) &= 0xfffff; \
-				(ctreg) = 7; \
-			} else { \
-				jpc_mqenc_byteout2(enc); \
-				enc->outbuf = ((creg) >> 19) & 0xff; \
-				(creg) &= 0x7ffff; \
-				(ctreg) = 8; \
-			} \
-		} else { \
-			jpc_mqenc_byteout2(enc); \
-			(enc)->outbuf = ((creg) >> 19) & 0xff; \
-			(creg) &= 0x7ffff; \
-			(ctreg) = 8; \
-		} \
-	} else { \
-		jpc_mqenc_byteout2(enc); \
-		(enc)->outbuf = ((creg) >> 20) & 0xff; \
-		(creg) &= 0xfffff; \
-		(ctreg) = 7; \
-	} \
+    if ((enc)->outbuf != 0xff) { \
+        if ((creg) & 0x8000000) { \
+            if (++((enc)->outbuf) == 0xff) { \
+                (creg) &= 0x7ffffff; \
+                jpc_mqenc_byteout2(enc); \
+                enc->outbuf = ((creg) >> 20) & 0xff; \
+                (creg) &= 0xfffff; \
+                (ctreg) = 7; \
+            } else { \
+                jpc_mqenc_byteout2(enc); \
+                enc->outbuf = ((creg) >> 19) & 0xff; \
+                (creg) &= 0x7ffff; \
+                (ctreg) = 8; \
+            } \
+        } else { \
+            jpc_mqenc_byteout2(enc); \
+            (enc)->outbuf = ((creg) >> 19) & 0xff; \
+            (creg) &= 0x7ffff; \
+            (ctreg) = 8; \
+        } \
+    } else { \
+        jpc_mqenc_byteout2(enc); \
+        (enc)->outbuf = ((creg) >> 20) & 0xff; \
+        (creg) &= 0xfffff; \
+        (ctreg) = 7; \
+    } \
 }
 
-#define	jpc_mqenc_byteout2(enc) \
+#define jpc_mqenc_byteout2(enc) \
 { \
-	if (enc->outbuf >= 0) { \
-		if (jas_stream_putc(enc->out, (unsigned char)enc->outbuf) == EOF) { \
-			enc->err |= 1; \
-		} \
-	} \
-	enc->lastbyte = enc->outbuf; \
+    if (enc->outbuf >= 0) { \
+        if (jas_stream_putc(enc->out, (unsigned char)enc->outbuf) == EOF) { \
+            enc->err |= 1; \
+        } \
+    } \
+    enc->lastbyte = enc->outbuf; \
 }
 
 /******************************************************************************\
@@ -236,45 +236,45 @@ static void jpc_mqenc_setbits(jpc_mqenc_t *mqenc);
 
 jpc_mqenc_t *jpc_mqenc_create(int maxctxs, jas_stream_t *out)
 {
-	jpc_mqenc_t *mqenc;
+    jpc_mqenc_t *mqenc;
 
-	/* Allocate memory for the MQ encoder. */
-	if (!(mqenc = jas_malloc(sizeof(jpc_mqenc_t)))) {
-		goto error;
-	}
-	mqenc->out = out;
-	mqenc->maxctxs = maxctxs;
+    /* Allocate memory for the MQ encoder. */
+    if (!(mqenc = jas_malloc(sizeof(jpc_mqenc_t)))) {
+        goto error;
+    }
+    mqenc->out = out;
+    mqenc->maxctxs = maxctxs;
 
-	/* Allocate memory for the per-context state information. */
-	if (!(mqenc->ctxs = jas_malloc(mqenc->maxctxs * sizeof(jpc_mqstate_t *)))) {
-		goto error;
-	}
+    /* Allocate memory for the per-context state information. */
+    if (!(mqenc->ctxs = jas_malloc(mqenc->maxctxs * sizeof(jpc_mqstate_t *)))) {
+        goto error;
+    }
 
-	/* Set the current context to the first one. */
-	mqenc->curctx = mqenc->ctxs;
+    /* Set the current context to the first one. */
+    mqenc->curctx = mqenc->ctxs;
 
-	jpc_mqenc_init(mqenc);
+    jpc_mqenc_init(mqenc);
 
-	/* Initialize the per-context state information to something sane. */
-	jpc_mqenc_setctxs(mqenc, 0, 0);
+    /* Initialize the per-context state information to something sane. */
+    jpc_mqenc_setctxs(mqenc, 0, 0);
 
-	return mqenc;
+    return mqenc;
 
 error:
-	if (mqenc) {
-		jpc_mqenc_destroy(mqenc);
-	}
-	return 0;
+    if (mqenc) {
+        jpc_mqenc_destroy(mqenc);
+    }
+    return 0;
 }
 
 /* Destroy a MQ encoder. */
 
 void jpc_mqenc_destroy(jpc_mqenc_t *mqenc)
 {
-	if (mqenc->ctxs) {
-		jas_free(mqenc->ctxs);
-	}
-	jas_free(mqenc);
+    if (mqenc->ctxs) {
+        jas_free(mqenc->ctxs);
+    }
+    jas_free(mqenc);
 }
 
 /******************************************************************************\
@@ -285,33 +285,33 @@ void jpc_mqenc_destroy(jpc_mqenc_t *mqenc)
 
 void jpc_mqenc_init(jpc_mqenc_t *mqenc)
 {
-	mqenc->areg = 0x8000;
-	mqenc->outbuf = -1;
-	mqenc->creg = 0;
-	mqenc->ctreg = 12;
-	mqenc->lastbyte = -1;
-	mqenc->err = 0;
+    mqenc->areg = 0x8000;
+    mqenc->outbuf = -1;
+    mqenc->creg = 0;
+    mqenc->ctreg = 12;
+    mqenc->lastbyte = -1;
+    mqenc->err = 0;
 }
 
 /* Initialize one or more contexts. */
 
 void jpc_mqenc_setctxs(jpc_mqenc_t *mqenc, int numctxs, jpc_mqctx_t *ctxs)
 {
-	jpc_mqstate_t **ctx;
-	int n;
-
-	ctx = mqenc->ctxs;
-	n = JAS_MIN(mqenc->maxctxs, numctxs);
-	while (--n >= 0) {
-		*ctx = &jpc_mqstates[2 * ctxs->ind + ctxs->mps];
-		++ctx;
-		++ctxs;
-	}
-	n = mqenc->maxctxs - numctxs;
-	while (--n >= 0) {
-		*ctx = &jpc_mqstates[0];
-		++ctx;
-	}
+    jpc_mqstate_t **ctx;
+    int n;
+
+    ctx = mqenc->ctxs;
+    n = JAS_MIN(mqenc->maxctxs, numctxs);
+    while (--n >= 0) {
+        *ctx = &jpc_mqstates[2 * ctxs->ind + ctxs->mps];
+        ++ctx;
+        ++ctxs;
+    }
+    n = mqenc->maxctxs - numctxs;
+    while (--n >= 0) {
+        *ctx = &jpc_mqstates[0];
+        ++ctx;
+    }
 
 }
 
@@ -319,10 +319,10 @@ void jpc_mqenc_setctxs(jpc_mqenc_t *mqenc, int numctxs, jpc_mqctx_t *ctxs)
 
 void jpc_mqenc_getstate(jpc_mqenc_t *mqenc, jpc_mqencstate_t *state)
 {
-	state->areg = mqenc->areg;
-	state->creg = mqenc->creg;
-	state->ctreg = mqenc->ctreg;
-	state->lastbyte = mqenc->lastbyte;
+    state->areg = mqenc->areg;
+    state->creg = mqenc->creg;
+    state->ctreg = mqenc->ctreg;
+    state->lastbyte = mqenc->lastbyte;
 }
 
 /******************************************************************************\
@@ -333,49 +333,49 @@ void jpc_mqenc_getstate(jpc_mqenc_t *mqenc, jpc_mqencstate_t *state)
 
 int jpc_mqenc_putbit_func(jpc_mqenc_t *mqenc, int bit)
 {
-	const jpc_mqstate_t *state;
-	JAS_DBGLOG(100, ("jpc_mqenc_putbit(%p, %d)\n", mqenc, bit));
-	JPC_MQENC_CALL(100, jpc_mqenc_dump(mqenc, stderr));
-
-	state = *(mqenc->curctx);
-
-	if (state->mps == bit) {
-		/* Apply the CODEMPS algorithm as defined in the standard. */
-		mqenc->areg -= state->qeval;
-		if (!(mqenc->areg & 0x8000)) {
-			jpc_mqenc_codemps2(mqenc);
-		} else {
-			mqenc->creg += state->qeval;
-		}
-	} else {
-		/* Apply the CODELPS algorithm as defined in the standard. */
-		jpc_mqenc_codelps2(mqenc->areg, mqenc->creg, mqenc->ctreg, mqenc->curctx, mqenc);
-	}
-
-	return jpc_mqenc_error(mqenc) ? (-1) : 0;
+    const jpc_mqstate_t *state;
+    JAS_DBGLOG(100, ("jpc_mqenc_putbit(%p, %d)\n", mqenc, bit));
+    JPC_MQENC_CALL(100, jpc_mqenc_dump(mqenc, stderr));
+
+    state = *(mqenc->curctx);
+
+    if (state->mps == bit) {
+        /* Apply the CODEMPS algorithm as defined in the standard. */
+        mqenc->areg -= state->qeval;
+        if (!(mqenc->areg & 0x8000)) {
+            jpc_mqenc_codemps2(mqenc);
+        } else {
+            mqenc->creg += state->qeval;
+        }
+    } else {
+        /* Apply the CODELPS algorithm as defined in the standard. */
+        jpc_mqenc_codelps2(mqenc->areg, mqenc->creg, mqenc->ctreg, mqenc->curctx, mqenc);
+    }
+
+    return jpc_mqenc_error(mqenc) ? (-1) : 0;
 }
 
 int jpc_mqenc_codemps2(jpc_mqenc_t *mqenc)
 {
-	/* Note: This function only performs part of the work associated with
-	the CODEMPS algorithm from the standard.  Some of the work is also
-	performed by the caller. */
-
-	jpc_mqstate_t *state = *(mqenc->curctx);
-	if (mqenc->areg < state->qeval) {
-		mqenc->areg = state->qeval;
-	} else {
-		mqenc->creg += state->qeval;
-	}
-	*mqenc->curctx = state->nmps;
-	jpc_mqenc_renorme(mqenc->areg, mqenc->creg, mqenc->ctreg, mqenc);
-	return jpc_mqenc_error(mqenc) ? (-1) : 0;
+    /* Note: This function only performs part of the work associated with
+    the CODEMPS algorithm from the standard.  Some of the work is also
+    performed by the caller. */
+
+    jpc_mqstate_t *state = *(mqenc->curctx);
+    if (mqenc->areg < state->qeval) {
+        mqenc->areg = state->qeval;
+    } else {
+        mqenc->creg += state->qeval;
+    }
+    *mqenc->curctx = state->nmps;
+    jpc_mqenc_renorme(mqenc->areg, mqenc->creg, mqenc->ctreg, mqenc);
+    return jpc_mqenc_error(mqenc) ? (-1) : 0;
 }
 
 int jpc_mqenc_codelps(jpc_mqenc_t *mqenc)
 {
-	jpc_mqenc_codelps2(mqenc->areg, mqenc->creg, mqenc->ctreg, mqenc->curctx, mqenc);
-	return jpc_mqenc_error(mqenc) ? (-1) : 0;
+    jpc_mqenc_codelps2(mqenc->areg, mqenc->creg, mqenc->ctreg, mqenc->curctx, mqenc);
+    return jpc_mqenc_error(mqenc) ? (-1) : 0;
 }
 
 /******************************************************************************\
@@ -386,56 +386,56 @@ int jpc_mqenc_codelps(jpc_mqenc_t *mqenc)
 
 int jpc_mqenc_flush(jpc_mqenc_t *mqenc, int termmode)
 {
-	int_fast16_t k;
-
-	switch (termmode) {
-	case JPC_MQENC_PTERM:
-		k = 11 - mqenc->ctreg + 1;
-		while (k > 0) {
-			mqenc->creg <<= mqenc->ctreg;
-			mqenc->ctreg = 0;
-			jpc_mqenc_byteout(mqenc->areg, mqenc->creg, mqenc->ctreg,
-			  mqenc);
-			k -= mqenc->ctreg;
-		}
-		if (mqenc->outbuf != 0xff) {
-			jpc_mqenc_byteout(mqenc->areg, mqenc->creg, mqenc->ctreg, mqenc);
-		}
-		break;
-	case JPC_MQENC_DEFTERM:
-		jpc_mqenc_setbits(mqenc);
-		mqenc->creg <<= mqenc->ctreg;
-		jpc_mqenc_byteout(mqenc->areg, mqenc->creg, mqenc->ctreg, mqenc);
-		mqenc->creg <<= mqenc->ctreg;
-		jpc_mqenc_byteout(mqenc->areg, mqenc->creg, mqenc->ctreg, mqenc);
-		if (mqenc->outbuf != 0xff) {
-			jpc_mqenc_byteout(mqenc->areg, mqenc->creg, mqenc->ctreg, mqenc);
-		}
-		break;
-	default:
-		abort();
-		break;
-	}
-	return 0;
+    int_fast16_t k;
+
+    switch (termmode) {
+    case JPC_MQENC_PTERM:
+        k = 11 - mqenc->ctreg + 1;
+        while (k > 0) {
+            mqenc->creg <<= mqenc->ctreg;
+            mqenc->ctreg = 0;
+            jpc_mqenc_byteout(mqenc->areg, mqenc->creg, mqenc->ctreg,
+              mqenc);
+            k -= mqenc->ctreg;
+        }
+        if (mqenc->outbuf != 0xff) {
+            jpc_mqenc_byteout(mqenc->areg, mqenc->creg, mqenc->ctreg, mqenc);
+        }
+        break;
+    case JPC_MQENC_DEFTERM:
+        jpc_mqenc_setbits(mqenc);
+        mqenc->creg <<= mqenc->ctreg;
+        jpc_mqenc_byteout(mqenc->areg, mqenc->creg, mqenc->ctreg, mqenc);
+        mqenc->creg <<= mqenc->ctreg;
+        jpc_mqenc_byteout(mqenc->areg, mqenc->creg, mqenc->ctreg, mqenc);
+        if (mqenc->outbuf != 0xff) {
+            jpc_mqenc_byteout(mqenc->areg, mqenc->creg, mqenc->ctreg, mqenc);
+        }
+        break;
+    default:
+        abort();
+        break;
+    }
+    return 0;
 }
 
 static void jpc_mqenc_setbits(jpc_mqenc_t *mqenc)
 {
-	uint_fast32_t tmp = mqenc->creg + mqenc->areg;
-	mqenc->creg |= 0xffff;
-	if (mqenc->creg >= tmp) {
-		mqenc->creg -= 0x8000;
-	}
+    uint_fast32_t tmp = mqenc->creg + mqenc->areg;
+    mqenc->creg |= 0xffff;
+    if (mqenc->creg >= tmp) {
+        mqenc->creg -= 0x8000;
+    }
 }
 
 /* Dump a MQ encoder to a stream for debugging. */
 
 int jpc_mqenc_dump(jpc_mqenc_t *mqenc, FILE *out)
 {
-	fprintf(out, "AREG = %08x, CREG = %08x, CTREG = %d\n",
-	  mqenc->areg, mqenc->creg, mqenc->ctreg);
-	fprintf(out, "IND = %02d, MPS = %d, QEVAL = %04x\n",
-	  *mqenc->curctx - jpc_mqstates, (*mqenc->curctx)->mps,
-	  (*mqenc->curctx)->qeval);
-	return 0;
+    fprintf(out, "AREG = %08x, CREG = %08x, CTREG = %d\n",
+            (unsigned)mqenc->areg, (unsigned)mqenc->creg, (int)mqenc->ctreg);
+    fprintf(out, "IND = %02d, MPS = %d, QEVAL = %04x\n",
+            (int)(*mqenc->curctx - jpc_mqstates), (int)(*mqenc->curctx)->mps,
+            (unsigned)(*mqenc->curctx)->qeval);
+    return 0;
 }
diff --git a/converter/other/jpeg2000/libjasper/jpc/jpc_qmfb.c b/converter/other/jpeg2000/libjasper/jpc/jpc_qmfb.c
index 1d41d5c5..80bc5aa5 100644
--- a/converter/other/jpeg2000/libjasper/jpc/jpc_qmfb.c
+++ b/converter/other/jpeg2000/libjasper/jpc/jpc_qmfb.c
@@ -900,8 +900,8 @@ static void jpc_ns_analyze(jpc_qmfb1d_t *qmfb, int flags, jas_seq2d_t *x)
 			startptr += interstep;
 		}
 	} else {
-		/* The reversible integer-to-integer mode is not supported
-		  for this transform. */
+		/* The reversible integer-to-integer mode is not valid for this
+		  transform. */
 		abort();
 	}
 }
@@ -973,8 +973,8 @@ static void jpc_ns_synthesize(jpc_qmfb1d_t *qmfb, int flags, jas_seq2d_t *x)
 			startptr += interstep;
 		}
 	} else {
-		/* The reversible integer-to-integer mode is not supported
-		  for this transform. */
+		/* The reversible integer-to-integer mode is not valid
+           for this transform. */
 		abort();
 	}
 }
diff --git a/converter/other/jpeg2000/libjasper/jpc/jpc_t2cod.h b/converter/other/jpeg2000/libjasper/jpc/jpc_t2cod.h
index 05f41b9e..82dafcce 100644
--- a/converter/other/jpeg2000/libjasper/jpc/jpc_t2cod.h
+++ b/converter/other/jpeg2000/libjasper/jpc/jpc_t2cod.h
@@ -136,7 +136,7 @@ typedef struct {
 	/* The number of progression changes. */
 	int numpchgs;
 
-	/* The maximum number of progression changes that can be accomodated
+	/* The maximum number of progression changes that can be accommodated
 	  without growing the progression change array. */
 	int maxpchgs;
 
@@ -253,7 +253,7 @@ typedef struct {
 	/* The progression change list. */
 	jpc_pchglist_t *pchglist;
 
-	/* The progression to use in the absense of explicit specification. */
+	/* The progression to use in the absence of explicit specification. */
 	jpc_pchg_t defaultpchg;
 
 	/* The current progression change number. */
diff --git a/converter/other/jpeg2000/pamtojpeg2k.c b/converter/other/jpeg2000/pamtojpeg2k.c
index 69ceb22b..142e452f 100644
--- a/converter/other/jpeg2000/pamtojpeg2k.c
+++ b/converter/other/jpeg2000/pamtojpeg2k.c
@@ -9,17 +9,24 @@
 *****************************************************************************/
 
 #define _BSD_SOURCE 1    /* Make sure strdup() is in string.h */
-/* Make sure strdup() is in string.h and int_fast32_t is in inttypes.h */
-#define _XOPEN_SOURCE 600
+#define _XOPEN_SOURCE 500 /* Make sure strdup() is in string.h */
+    /* In 2014.09, this was _XOPEN_SOURCE 600, with a comment saying it was
+       necessary to make <inttypes.h> define int_fast32_t, etc. on AIX.
+       <jasper/jasper.h> does use int_fast32_t and does include <inttypes.h>,
+       but plenty of source files of libjasper do too, and they did not have
+       _XOPEN_SOURCE 600, so it would seem to be superfluous here too.
+    */
+
 #include <string.h>
 
+#include <jasper/jasper.h>
+
 #include "pm_c_util.h"
 #include "pam.h"
 #include "shhopt.h"
 #include "nstring.h"
 #include "mallocvar.h"
 
-#include <jasper/jasper.h>
 #include "libjasper_compat.h"
 
 
@@ -43,7 +50,8 @@ struct cmdlineInfo {
     unsigned int cblkwidth;
     unsigned int cblkheight;
     enum compmode compmode;
-    float        compressionRatio;
+    unsigned int compressionSpec;
+    float        compression;
     char *       ilyrrates;
     enum progression progression;
     unsigned int numrlvls;
@@ -81,7 +89,7 @@ parseCommandLine(int argc, char ** argv,
     unsigned int tilewidthSpec, tileheightSpec;
     unsigned int prcwidthSpec, prcheightSpec;
     unsigned int cblkwidthSpec, cblkheightSpec;
-    unsigned int modeSpec, compressionSpec, ilyrratesSpec;
+    unsigned int modeSpec, ilyrratesSpec;
     unsigned int progressionSpec, numrlvlsSpec, numgbitsSpec;
     unsigned int debuglevelSpec;
 
@@ -115,8 +123,8 @@ parseCommandLine(int argc, char ** argv,
             &cblkheightSpec,     0);
     OPTENT3(0, "mode",         OPT_STRING, &modeOpt,
             &modeSpec,           0);
-    OPTENT3(0, "compression",  OPT_FLOAT,  &cmdlineP->compressionRatio,
-            &compressionSpec,    0);
+    OPTENT3(0, "compression",  OPT_FLOAT,  &cmdlineP->compression,
+            &cmdlineP->compressionSpec,    0);
     OPTENT3(0, "ilyrrates",    OPT_STRING, &cmdlineP->ilyrrates,
             &ilyrratesSpec,      0);
     OPTENT3(0, "progression",  OPT_STRING, &progressionOpt,
@@ -152,7 +160,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 */
 
-    optParseOptions3(&argc, argv, opt, sizeof(opt), 0);
+    pm_optParseOptions3(&argc, argv, opt, sizeof(opt), 0);
 
     if (!imgareatlxSpec)
         cmdlineP->imgareatlx = 0;
@@ -184,11 +192,6 @@ parseCommandLine(int argc, char ** argv,
                      "valid values are 'INTEGER' and 'REAL'", modeOpt);
     } else
         cmdlineP->compmode = COMPMODE_INTEGER;
-    if (compressionSpec) {
-        if (cmdlineP->compressionRatio < 1.0)
-            pm_error("Compression ratio less than 1 does not make sense.");
-    } else
-        cmdlineP->compressionRatio = 1.0;
     if (!ilyrratesSpec)
         cmdlineP->ilyrrates = (char*) "";
     if (progressionSpec) {
@@ -230,7 +233,10 @@ parseCommandLine(int argc, char ** argv,
 static void
 createJasperRaster(struct pam *  const inpamP, 
                    jas_image_t * const jasperP) {
-
+/*----------------------------------------------------------------------------
+   Create the raster in the *jasperP object, reading the raster from the
+   input file described by *inpamP, which is positioned to the raster.
+-----------------------------------------------------------------------------*/
     jas_matrix_t ** matrix;  /* malloc'ed */
         /* matrix[X] is the data for Plane X of the current row */
     unsigned int plane;
@@ -380,7 +386,7 @@ writeJpc(jas_image_t *      const jasperP,
        specifying garbage for the -ilyrrates option 
     */
     if (strlen(cmdline.ilyrrates) > 0)
-        asprintfN(&ilyrratesOpt, "ilyrrates=%s", cmdline.ilyrrates);
+        pm_asprintf(&ilyrratesOpt, "ilyrrates=%s", cmdline.ilyrrates);
     else
         ilyrratesOpt = strdup("");
 
@@ -394,55 +400,62 @@ writeJpc(jas_image_t *      const jasperP,
 
     /* Note that asprintfN() doesn't understand %f, but sprintf() does */
 
-    sprintf(rateOpt, "%1.9f", 1.0/cmdline.compressionRatio);
-
-    asprintfN(&options, 
-              "imgareatlx=%u "
-              "imgareatly=%u "
-              "tilegrdtlx=%u "
-              "tilegrdtly=%u "
-              "tilewidth=%u "
-              "tileheight=%u "
-              "prcwidth=%u "
-              "prcheight=%u "
-              "cblkwidth=%u "
-              "cblkheight=%u "
-              "mode=%s "
-              "rate=%s "
-              "%s "
-              "prg=%s "
-              "numrlvls=%u "
-              "numgbits=%u "
-              "%s %s %s %s %s %s %s %s %s",
-
-              cmdline.imgareatlx,
-              cmdline.imgareatly,
-              cmdline.tilegrdtlx,
-              cmdline.tilegrdtlx,
-              cmdline.tilewidth,
-              cmdline.tileheight,
-              cmdline.prcwidth,
-              cmdline.prcheight,
-              cmdline.cblkwidth,
-              cmdline.cblkheight,
-              cmdline.compmode == COMPMODE_INTEGER ? "int" : "real",
-              rateOpt,
-              ilyrratesOpt,
-              prgValue,
-              cmdline.numrlvls,
-              cmdline.numgbits,
-              cmdline.nomct     ? "nomct"     : "",
-              cmdline.sop       ? "sop"       : "",
-              cmdline.eph       ? "eph"       : "",
-              cmdline.lazy      ? "lazy"      : "",
-              cmdline.termall   ? "termall"   : "",
-              cmdline.segsym    ? "segsym"    : "",
-              cmdline.vcausal   ? "vcausal"   : "",
-              cmdline.pterm     ? "pterm"     : "",
-              cmdline.resetprob ? "resetprob" : ""
+    if (cmdline.compressionSpec)
+        sprintf(rateOpt, "rate=%1.9f", 1.0/cmdline.compression);
+    else {
+        /* No 'rate' option.  This means there is no constraint on the image
+           size, so the encoder will compress losslessly.  Note that the
+           image may get larger, because of metadata.
+        */
+        rateOpt[0] = '\0';
+    }
+    pm_asprintf(&options, 
+                "imgareatlx=%u "
+                "imgareatly=%u "
+                "tilegrdtlx=%u "
+                "tilegrdtly=%u "
+                "tilewidth=%u "
+                "tileheight=%u "
+                "prcwidth=%u "
+                "prcheight=%u "
+                "cblkwidth=%u "
+                "cblkheight=%u "
+                "mode=%s "
+                "%s "    /* rate */
+                "%s "    /* ilyrrates */
+                "prg=%s "
+                "numrlvls=%u "
+                "numgbits=%u "
+                "%s %s %s %s %s %s %s %s %s",
+                
+                cmdline.imgareatlx,
+                cmdline.imgareatly,
+                cmdline.tilegrdtlx,
+                cmdline.tilegrdtlx,
+                cmdline.tilewidth,
+                cmdline.tileheight,
+                cmdline.prcwidth,
+                cmdline.prcheight,
+                cmdline.cblkwidth,
+                cmdline.cblkheight,
+                cmdline.compmode == COMPMODE_INTEGER ? "int" : "real",
+                rateOpt,
+                ilyrratesOpt,
+                prgValue,
+                cmdline.numrlvls,
+                cmdline.numgbits,
+                cmdline.nomct     ? "nomct"     : "",
+                cmdline.sop       ? "sop"       : "",
+                cmdline.eph       ? "eph"       : "",
+                cmdline.lazy      ? "lazy"      : "",
+                cmdline.termall   ? "termall"   : "",
+                cmdline.segsym    ? "segsym"    : "",
+                cmdline.vcausal   ? "vcausal"   : "",
+                cmdline.pterm     ? "pterm"     : "",
+                cmdline.resetprob ? "resetprob" : ""
         );
-    strfree(ilyrratesOpt);
 
+    pm_strfree(ilyrratesOpt);
 
     /* Open the output image file (Standard Output) */
     outStreamP = jas_stream_fdopen(fileno(ofP), "w+b");
@@ -459,7 +472,7 @@ writeJpc(jas_image_t *      const jasperP,
 
         rc = jas_image_encode(jasperP, outStreamP, 
                               jas_image_strtofmt((char*)"jpc"), 
-                              (char*)options);
+                              (char *)options);
         if (rc != 0)
             pm_error("jas_image_encode() failed to encode the JPEG 2000 "
                      "image.  Rc=%d", rc);
@@ -478,7 +491,7 @@ writeJpc(jas_image_t *      const jasperP,
 
 	jas_image_clearfmts();
 
-    strfree(options);
+    pm_strfree(options);
 }
 
 
@@ -487,7 +500,7 @@ int
 main(int argc, char **argv)
 {
     struct cmdlineInfo cmdline;
-    FILE *ifP;
+    FILE * ifP;
     struct pam inpam;
     jas_image_t * jasperP;
 
diff --git a/converter/other/jpegtopnm.c b/converter/other/jpegtopnm.c
index 07a7dfb0..ab3b18e5 100644
--- a/converter/other/jpegtopnm.c
+++ b/converter/other/jpegtopnm.c
@@ -22,7 +22,7 @@
     Extend pamtoppm to convert this to ppm using the standard
     transformation.
 
-    See if additional decompressor options effects signficant speedup.
+    See if additional decompressor options effects significant speedup.
     grayscale output of color image, downscaling, color quantization, and
     dithering are possibilities.  Djpeg's man page says they make it faster.
 
@@ -173,7 +173,7 @@ parseCommandLine(int                  const argc,
    not change argv at all.
 -----------------------------------------------------------------------------*/
     optEntry *option_def;
-        /* Instructions to optParseOptions3 on how to parse our options.
+        /* Instructions to pm_optParseOptions3 on how to parse our options.
          */
     optStruct3 opt;
 
@@ -216,12 +216,12 @@ parseCommandLine(int                  const argc,
     opt.short_allowed = FALSE;  /* We have no short (old-fashioned) options */
     opt.allowNegNum = FALSE;  /* We may have parms that are negative numbers */
 
-    /* Make private copy of arguments for optParseOptions to corrupt */
+    /* Make private copy of arguments for pm_optParseOptions to corrupt */
     argc_parse = argc;
     for (i=0; i < argc; ++i)
         argv_parse[i] = argv[i];
 
-    optParseOptions3( &argc_parse, argv_parse, opt, sizeof(opt), 0);
+    pm_optParseOptions3( &argc_parse, argv_parse, opt, sizeof(opt), 0);
         /* Uses and sets argc_parse, argv_parse, 
            and some of *cmdlineP and others. */
 
@@ -582,7 +582,7 @@ print_verbose_info_about_header(struct jpeg_decompress_struct const cinfo){
                colorspace_name(cinfo.jpeg_color_space));
 
     /* Note that raw information about marker, including marker type code,
-       was already printed by the jpeg library, due to the jpeg library
+       was already printed by the jpeg library, because of the jpeg library
        trace level >= 1.  Our job is to interpret it a little bit.
     */
     if (cinfo.marker_list)
@@ -652,19 +652,20 @@ print_exif_info(struct jpeg_marker_struct const marker) {
    Dump as informational messages the contents of the Jpeg miscellaneous
    marker 'marker', assuming it is an Exif header.
 -----------------------------------------------------------------------------*/
-    ImageInfo_t imageInfo;
+    bool const wantTagTrace = false;
+    exif_ImageInfo imageInfo;
     const char * error;
 
     assert(marker.data_length >= 6);
 
-    process_EXIF(marker.data+6, marker.data_length-6, 
-                 &imageInfo, FALSE, &error);
+    exif_parse(marker.data+6, marker.data_length-6, 
+               &imageInfo, wantTagTrace, &error);
 
     if (error) {
         pm_message("EXIF header is invalid.  %s", error);
-        strfree(error);
+        pm_strfree(error);
     } else
-        ShowImageInfo(&imageInfo);
+        exif_showImageInfo(&imageInfo, stderr);
 }
 
 
@@ -700,8 +701,7 @@ dump_exif(struct jpeg_decompress_struct const cinfo) {
 
     found_one = FALSE;  /* initial value */
 
-    for (markerP = cinfo.marker_list;
-         markerP; markerP = markerP->next) 
+    for (markerP = cinfo.marker_list; markerP; markerP = markerP->next) 
         if (is_exif(*markerP)) {
             pm_message("EXIF INFO:");
             print_exif_info(*markerP);
diff --git a/converter/other/pamrgbatopng.c b/converter/other/pamrgbatopng.c
deleted file mode 100644
index 7babf9f9..00000000
--- a/converter/other/pamrgbatopng.c
+++ /dev/null
@@ -1,150 +0,0 @@
-#include <png.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <setjmp.h>
-
-#include "pam.h"
-#include "mallocvar.h"
-
-struct cmdlineInfo {
-    const char * inputFileName;
-};
-
-
-
-static void
-processCommandLine(int                  const argc,
-                   char *               const argv[],
-                   struct cmdlineInfo * const cmdlineP) {
-        
-    if (argc-1 < 1)
-        cmdlineP->inputFileName = "-";
-    else {
-        cmdlineP->inputFileName = argv[1];
-
-        if (argc-1 > 1)
-            pm_error("Too many arguments.  "
-                     "The only argument is the input file name.");
-    }
-}
-
-
-
-static void
-convertPamToPng(const struct pam * const pamP,
-                const tuple *      const tuplerow,
-                png_byte *         const pngRow) {
-    
-    unsigned int col;
-    
-    for (col = 0; col < pamP->width; ++col) {
-        unsigned int plane;
-        
-        for (plane = 0; plane < 4; ++plane)
-            pngRow[4 * col + plane] = tuplerow[col][plane];
-    }
-}
-
-
-
-static void
-writeRaster(const struct pam * const pamP,
-            png_struct *       const pngP) {
-    
-    tuple * tupleRow;
-    png_byte * pngRow;
-    
-    tupleRow = pnm_allocpamrow(pamP);
-    MALLOCARRAY(pngRow, pamP->width * 4);
-
-    if (pngRow == NULL)
-        pm_error("Unable to allocate space for PNG pixel row.");
-    else {
-        unsigned int row;
-        for (row = 0; row < pamP->height; ++row) {
-            pnm_readpamrow(pamP, tupleRow);
-            
-            convertPamToPng(pamP, tupleRow, pngRow);
-            
-            png_write_row(pngP, pngRow);
-        }
-        free(pngRow);
-    }
-    pnm_freepamrow(tupleRow);
-}
-
-
-
-static void
-pngErrorHandler(png_struct * const pngP,
-                const char * const message) {
-
-    pm_error("Error generating PNG image.  libpng says: %s", message);
-}
-
-
-
-static void
-writePng(const struct pam * const pamP,
-         FILE *             const ofP) {
-
-    png_struct * pngP;
-    png_info * infoP;
-
-    pngP = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
-    if (!pngP)
-        pm_error("Could not allocate png struct.");
-
-    png_set_error_fn(pngP, NULL, &pngErrorHandler, NULL);
-
-    infoP = png_create_info_struct(pngP);
-    if (!infoP)
-        pm_error("Could not allocate PNG info structure");
-    else {
-        infoP->width      = pamP->width;
-        infoP->height     = pamP->height;
-        infoP->bit_depth  = 8;
-        infoP->color_type = PNG_COLOR_TYPE_RGB_ALPHA;
-        
-        png_init_io(pngP, ofP);
-
-        png_write_info(pngP, infoP);
-        
-        writeRaster(pamP, pngP);
-
-        png_write_end(pngP, infoP);
-        
-        png_destroy_write_struct(&pngP, &infoP);
-    }
-}
-    
-
-
-int
-main(int argc, char * argv[]) {
-
-    FILE * ifP;
-    struct cmdlineInfo cmdline;
-    struct pam pam;
-
-    pnm_init(&argc, argv);
-
-    processCommandLine(argc, argv, &cmdline);
-
-    ifP = pm_openr(cmdline.inputFileName);
-
-    pnm_readpaminit(ifP, &pam, PAM_STRUCT_SIZE(tuple_type));
-    
-    if (pam.depth < 4)
-        pm_error("PAM must have depth at least 4 (red, green, blue, alpha).  "
-                 "This one has depth %u", pam.depth);
-        
-    if (pam.maxval != 255)
-        pm_error("PAM must have maxval 255.  This one has %lu", pam.maxval);
-
-    writePng(&pam, stdout);
-
-    pm_close(ifP);
-
-    return 0;
-}
diff --git a/converter/other/pamtoavs.c b/converter/other/pamtoavs.c
new file mode 100644
index 00000000..4764c9e8
--- /dev/null
+++ b/converter/other/pamtoavs.c
@@ -0,0 +1,150 @@
+/* ----------------------------------------------------------------------
+ *
+ * Convert a PAM image to an AVS X image
+ *
+ * By Scott Pakin <scott+pbm@pakin.org>
+ *
+ * ----------------------------------------------------------------------
+ *
+ * Copyright (C) 2010 Scott Pakin <scott+pbm@pakin.org>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or (at
+ * your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see http://www.gnu.org/licenses/.
+ *
+ * ----------------------------------------------------------------------
+ */
+
+#include <stdio.h>
+#include "pm.h"
+#include "pam.h"
+
+
+
+static char
+sample2char(sample const s,
+            sample const maxval) {
+/* Scale down a sample to a single byte. */
+
+    return maxval==255 ? s : s * 255 / maxval;
+}
+
+
+#define THIS_SAMPLE_CHAR(PLANE) \
+  sample2char(tuplerow[col][PLANE], pamP->maxval)
+
+static void
+produceAvs(struct pam * const pamP,
+           FILE *       const avsFileP) {
+
+    tuple * tuplerow;
+
+    /* Write the AVS header (image width and height as 4-byte
+       big-endian integers).
+    */
+    pm_writebiglong(avsFileP, pamP->width);
+    pm_writebiglong(avsFileP, pamP->height);
+
+    /* Write the AVS data (alpha, red, green, blue -- one byte apiece. */
+    tuplerow = pnm_allocpamrow(pamP);
+    switch (pamP->depth) {
+    case 1: {
+        /* Black-and-white or grayscale, no alpha */
+        unsigned int row;
+        for (row = 0; row < pamP->height; ++row) {
+            unsigned int col;
+            pnm_readpamrow(pamP, tuplerow);
+            for (col = 0; col < pamP->width; ++col) {
+                pm_writechar(avsFileP, (char)255);
+                pm_writechar(avsFileP, THIS_SAMPLE_CHAR(0));
+                pm_writechar(avsFileP, THIS_SAMPLE_CHAR(0));
+                pm_writechar(avsFileP, THIS_SAMPLE_CHAR(0));
+            }
+        }
+    } break;
+
+    case 2: {
+        /* Black-and-white or grayscale plus alpha */
+        unsigned int row;
+        for (row = 0; row < pamP->height; ++row) {
+            unsigned int col;
+            pnm_readpamrow(pamP, tuplerow);
+            for (col = 0; col < pamP->width; ++col) {
+                pm_writechar(avsFileP, THIS_SAMPLE_CHAR(1));
+                pm_writechar(avsFileP, THIS_SAMPLE_CHAR(0));
+                pm_writechar(avsFileP, THIS_SAMPLE_CHAR(0));
+                pm_writechar(avsFileP, THIS_SAMPLE_CHAR(0));
+            }
+        }
+    } break;
+
+    case 3: {
+        /* RGB, no alpha */
+        unsigned int row;
+        for (row = 0; row < pamP->height; ++row) {
+            unsigned int col;
+            pnm_readpamrow(pamP, tuplerow);
+            for (col = 0; col < pamP->width; ++col) {
+                pm_writechar(avsFileP, (char)255);
+                pm_writechar(avsFileP, THIS_SAMPLE_CHAR(0));
+                pm_writechar(avsFileP, THIS_SAMPLE_CHAR(1));
+                pm_writechar(avsFileP, THIS_SAMPLE_CHAR(2));
+            }
+        }
+    } break;
+
+    case 4: {
+        /* RGB plus alpha */
+        unsigned int row;
+        for (row = 0; row < pamP->height; ++row) {
+            unsigned int col;
+            pnm_readpamrow( pamP, tuplerow );
+            for (col = 0; col < pamP->width; ++col) {
+                pm_writechar(avsFileP, THIS_SAMPLE_CHAR(3));
+                pm_writechar(avsFileP, THIS_SAMPLE_CHAR(0));
+                pm_writechar(avsFileP, THIS_SAMPLE_CHAR(1));
+                pm_writechar(avsFileP, THIS_SAMPLE_CHAR(2));
+            }
+        }
+    } break;
+
+    default:
+        pm_error("Unrecognized PAM depth %u.  We understand only "
+                 "1, 2, 3, and 4", pamP->depth);
+        break;
+    }
+    pnm_freepamrow(tuplerow);
+}
+
+
+
+int
+main(int argc, const char *argv[]) {
+    struct pam   inPam;
+    const char * inputFilename;
+    FILE       * inFileP;
+
+    pm_proginit(&argc, argv);
+
+    inputFilename = (argc > 1) ? argv[1] : "-";
+
+    inFileP = pm_openr(inputFilename);
+
+    pnm_readpaminit(inFileP, &inPam, PAM_STRUCT_SIZE(tuple_type));
+
+    produceAvs(&inPam, stdout);
+
+    pm_closer(inFileP);
+
+    return 0;
+}
+
diff --git a/converter/other/pamtodjvurle.c b/converter/other/pamtodjvurle.c
index 2d26eeb0..cae9e026 100644
--- a/converter/other/pamtodjvurle.c
+++ b/converter/other/pamtodjvurle.c
@@ -45,7 +45,7 @@ parseCommandLine(int argc,
    was passed to us as the argv array.  We also trash *argv.
 --------------------------------------------------------------------------*/
     optEntry *option_def = malloc( 100*sizeof( optEntry ) );
-    /* Instructions to optParseOptions3 on how to parse our options. */
+    /* Instructions to pm_optParseOptions3 on how to parse our options. */
     optStruct3 opt;
   
     unsigned int option_def_index;
@@ -61,7 +61,7 @@ parseCommandLine(int argc,
     opt.short_allowed = FALSE;  /* We have no short (old-fashioned) options */
     opt.allowNegNum = FALSE;   /* We have no parms that are negative numbers */
 
-    optParseOptions3( &argc, argv, opt, sizeof(opt), 0 );
+    pm_optParseOptions3( &argc, argv, opt, sizeof(opt), 0 );
     /* Uses and sets argc, argv, and some of *cmdline_p and others. */
 
     if (!transparentSpec)
diff --git a/converter/other/pamtofits.c b/converter/other/pamtofits.c
index 7a1c70de..92e29c7e 100644
--- a/converter/other/pamtofits.c
+++ b/converter/other/pamtofits.c
@@ -59,7 +59,7 @@ parseCommandLine(int argc, char ** argv,
    was passed to us as the argv array.  We also trash *argv.
 --------------------------------------------------------------------------*/
     optEntry * option_def;
-        /* Instructions to optParseOptions3 on how to parse our options. */
+        /* Instructions to pm_optParseOptions3 on how to parse our options. */
     optStruct3 opt;
 
     unsigned int minSpec;
@@ -79,7 +79,7 @@ parseCommandLine(int argc, char ** argv,
 
     /* Set some defaults the lazy way (using multiple setting of variables) */
 
-    optParseOptions3( &argc, argv, opt, sizeof(opt), 0 );
+    pm_optParseOptions3( &argc, argv, opt, sizeof(opt), 0 );
     /* Uses and sets argc, argv, and some of *cmdlineP and others. */
 
     if (!minSpec)
@@ -111,11 +111,11 @@ writeHeaderCard(const char * const s) {
 -----------------------------------------------------------------------------*/
     const char * card;
 
-    asprintfN(&card, "%-80.80s", s);
+    pm_asprintf(&card, "%-80.80s", s);
 
     fwrite(card, sizeof(card[0]), 80, stdout);
 
-    strfree(card);
+    pm_strfree(card);
 }
 
 
diff --git a/converter/other/pamtogif.c b/converter/other/pamtogif.c
index 0c8c0f9e..aabf7fc2 100644
--- a/converter/other/pamtogif.c
+++ b/converter/other/pamtogif.c
@@ -35,7 +35,7 @@ typedef int stringCode;
        changes throughout the image.
 
        A variable of this type sometimes has the value -1 instead of
-       a string code due to cheesy programming.
+       a string code because of cheesy programming.
 
        Ergo, this data structure must be signed and at least BITS bits
        wide plus sign bit.
@@ -163,7 +163,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 */
 
-    optParseOptions3(&argc, argv, opt, sizeof(opt), 0);
+    pm_optParseOptions3(&argc, argv, opt, sizeof(opt), 0);
         /* Uses and sets argc, argv, and some of *cmdlineP and others. */
 
     if (argc-1 == 0) 
@@ -220,7 +220,7 @@ closestColor(tuple         const color,
     
     unsigned int i;
     unsigned int imin, dmin;
-    bool fits;
+    int fits;
 
     dmin = UINT_MAX;
     imin = 0;
@@ -627,11 +627,11 @@ static void
 byteBuffer_out(byteBuffer *  const byteBufferP,
                unsigned char const c) {
 /*----------------------------------------------------------------------------
-  Add a byte to the end of the current data block, and if it is now 254
+  Add a byte to the end of the current data block, and if it is now 255
   characters, flush the data block to the output file.
 -----------------------------------------------------------------------------*/
     byteBufferP->buffer[byteBufferP->count++] = c;
-    if (byteBufferP->count >= 254)
+    if (byteBufferP->count >= 255)
         byteBuffer_flush(byteBufferP);
 }
 
@@ -893,7 +893,7 @@ lzw_create(FILE *       const ofP,
     
        Above that we use a table with 4096 slots plus 20% extra.
        When this is not enough the clear code is emitted.
-       Due to the extra 20% the table itself never fills up.
+       Because of the extra 20% the table itself never fills up.
        
        lzw.hsize and lzw.hshift stay constant through the image.
 
@@ -1544,7 +1544,7 @@ computeTransparent(char          const colorarg[],
         const char * colorspec;
         bool exact;
         tuple transcolor;
-        bool found;
+        int found;
         int colorindex;
         
         if (colorarg[0] == '=') {
diff --git a/converter/other/pamtohdiff.c b/converter/other/pamtohdiff.c
index 2d5f6a61..8d785f5b 100644
--- a/converter/other/pamtohdiff.c
+++ b/converter/other/pamtohdiff.c
@@ -38,7 +38,7 @@ parseCommandLine(int argc, char ** argv,
    was passed to us as the argv array.
 -----------------------------------------------------------------------------*/
     optEntry *option_def = malloc( 100*sizeof( optEntry ) );
-        /* Instructions to optParseOptions3 on how to parse our options.
+        /* Instructions to pm_optParseOptions3 on how to parse our options.
          */
     optStruct3 opt;
 
@@ -51,7 +51,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 */
 
-    optParseOptions3( &argc, argv, opt, sizeof(opt), 0 );
+    pm_optParseOptions3( &argc, argv, opt, sizeof(opt), 0 );
         /* Uses and sets argc, argv, and some of *cmdlineP and others. */
 
     if (argc-1 < 1)
diff --git a/converter/other/pamtohtmltbl.c b/converter/other/pamtohtmltbl.c
index 5335ff9f..d1482073 100644
--- a/converter/other/pamtohtmltbl.c
+++ b/converter/other/pamtohtmltbl.c
@@ -33,7 +33,7 @@ parseCommandLine(int argc, char ** argv,
    was passed to us as the argv array.  We also trash *argv.
 -----------------------------------------------------------------------------*/
     optEntry * option_def;
-        /* Instructions to optParseOptions3 on how to parse our options.
+        /* Instructions to pm_optParseOptions3 on how to parse our options.
          */
     optStruct3 opt;
 
@@ -53,7 +53,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 */
 
-    optParseOptions3( &argc, argv, opt, sizeof(opt), 0);
+    pm_optParseOptions3( &argc, argv, opt, sizeof(opt), 0);
         /* Uses and sets argc, argv, and some of *cmdlineP and others. */
 
 
diff --git a/converter/other/pamtompfont.c b/converter/other/pamtompfont.c
index ba170fef..92f8de29 100644
--- a/converter/other/pamtompfont.c
+++ b/converter/other/pamtompfont.c
@@ -42,7 +42,7 @@ parseCommandLine(int argc, char ** argv,
    Note that the file spec array we return is stored in the storage that
    was passed to us as the argv array.
 -----------------------------------------------------------------------------*/
-    optEntry *option_def;
+    optEntry * option_def;
         /* Instructions to OptParseOptions3 on how to parse our options.
          */
     optStruct3 opt;
@@ -59,7 +59,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 */
 
-    optParseOptions3(&argc, argv, opt, sizeof(opt), 0);
+    pm_optParseOptions3(&argc, argv, opt, sizeof(opt), 0);
         /* Uses and sets argc, argv, and some of *cmdlineP and others. */
 
     if (argc-1 == 0) 
@@ -69,6 +69,8 @@ parseCommandLine(int argc, char ** argv,
                  "specified %d", argc-1);
     else
         cmdlineP->inputFilename = argv[1];
+
+    free(option_def);
 }
 
 
diff --git a/converter/other/pamtooctaveimg.c b/converter/other/pamtooctaveimg.c
index b090281d..28bc4cd4 100644
--- a/converter/other/pamtooctaveimg.c
+++ b/converter/other/pamtooctaveimg.c
@@ -75,13 +75,13 @@ findOrAddColor(tuple          const color,
   colormap *cmapP.  If the color isn't in the map, give it a new
   colormap index, put it in the colormap, and return that.
 -----------------------------------------------------------------------------*/
-    bool found;
+    int found;
     int colorIndex;
 
     pnm_lookuptuple(&cmapP->pam, cmapP->hash, color, &found, &colorIndex);
 
     if (!found) {
-        bool fits;
+        int fits;
         unsigned int plane;
 
         colorIndex = cmapP->nColors++;
diff --git a/converter/other/pamtopam.c b/converter/other/pamtopam.c
index cae54060..9cb82f7a 100644
--- a/converter/other/pamtopam.c
+++ b/converter/other/pamtopam.c
@@ -17,7 +17,7 @@
 int
 main(int argc, const char * argv[]) {
 
-    bool       eof;     /* no more images in input stream */
+    int        eof;     /* no more images in input stream */
     struct pam inpam;   /* Input PAM image */
     struct pam outpam;  /* Output PAM image */
 
diff --git a/converter/other/pamtopdbimg.c b/converter/other/pamtopdbimg.c
new file mode 100644
index 00000000..6454292e
--- /dev/null
+++ b/converter/other/pamtopdbimg.c
@@ -0,0 +1,810 @@
+/*=============================================================================
+                               pamtopdbimg
+===============================================================================
+
+  Convert Netpbm image to Palm Pilot PDB Image format (for viewing by
+  Pilot Image Viewer).
+
+  Bryan Henderson derived this from Eric Howe's programs named
+  'pgmtoimgv' and 'pbmtoimgv' in September 2010.
+=============================================================================*/
+/*
+ * Copyright (C) 1997 Eric A. Howe
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *   Authors:  Eric A. Howe (mu@trends.net)
+ *             Bryan Henderson, September 2010.
+ */
+
+#include <stdlib.h>
+#include <assert.h>
+#include <string.h>
+#include <sys/stat.h>
+
+#include "pm_c_util.h"
+#include "mallocvar.h"
+#include "nstring.h"
+#include "shhopt.h"
+#include "pam.h"
+
+#include "ipdb.h"
+
+enum CompMode {COMPRESSED, MAYBE, UNCOMPRESSED};
+
+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 */
+    const char * title;
+    const char * notefile;  /* NULL if not specified */
+    enum CompMode compMode;
+    unsigned int depth4;
+};
+
+
+
+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 titleSpec, notefileSpec;
+    unsigned int compressed, maybeCompressed, uncompressed;
+
+    MALLOCARRAY_NOFAIL(option_def, 100);
+
+    option_def_index = 0;   /* incremented by OPTENT3 */
+    OPTENT3(0, "title",               OPT_STRING,    &cmdlineP->title,
+            &titleSpec,               0);
+    OPTENT3(0, "notefile",            OPT_STRING,    &cmdlineP->notefile,
+            &notefileSpec,            0);
+    OPTENT3(0, "compressed",          OPT_FLAG,      NULL,
+            &compressed,              0);
+    OPTENT3(0, "maybecompressed",     OPT_FLAG,      NULL,
+            &maybeCompressed,         0);
+    OPTENT3(0, "uncompressed",        OPT_FLAG,      NULL,
+            &uncompressed,            0);
+    OPTENT3(0, "4depth",              OPT_FLAG,      NULL,
+            &cmdlineP->depth4,        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 (!titleSpec)
+        cmdlineP->title = "unnamed";
+
+    if (!notefileSpec)
+        cmdlineP->notefile = NULL;
+    
+    if (compressed + uncompressed + maybeCompressed > 1)
+        pm_error("You may specify only one of -compressed, -uncompressed, "
+                 "-maybecompressed");
+    if (compressed)
+        cmdlineP->compMode = COMPRESSED;
+    else if (uncompressed)
+        cmdlineP->compMode = UNCOMPRESSED;
+    else if (maybeCompressed)
+        cmdlineP->compMode = MAYBE;
+    else
+        cmdlineP->compMode = MAYBE;
+
+    if (argc-1 < 1)
+        cmdlineP->inputFileName = "-";
+    else if (argc-1 == 1)
+        cmdlineP->inputFileName = argv[1];
+    else
+        pm_error("Program takes at most one argument:  input file name");
+}
+
+
+
+/*
+ * Pixel setting macros.
+ */
+#define setg16pixel(b,v,o)  ((b) |= ((v) << (4 - 4*(o))))
+#define setgpixel(b,v,o)    ((b) |= ((v) << (6 - 2*(o))))
+#define setmpixelblack(b,o)    ((b) |= (1 << (7 - (o))))
+
+
+
+static int
+pdbheadWrite(PDBHEAD * const pdbheadP,
+             FILE *    const fileP) {
+
+    fwrite(pdbheadP->name, 1, 32, fileP);
+    pm_writebigshort(fileP, pdbheadP->flags);
+    pm_writebigshort(fileP, pdbheadP->version);
+    pm_writebiglong(fileP, pdbheadP->ctime);
+    pm_writebiglong(fileP, pdbheadP->mtime);
+    pm_writebiglong(fileP, pdbheadP->btime);
+    pm_writebiglong(fileP, pdbheadP->mod_num);
+    pm_writebiglong(fileP, pdbheadP->app_info);
+    pm_writebiglong(fileP, pdbheadP->sort_info);
+    fwrite(pdbheadP->type, 1, 4,  fileP);
+    fwrite(pdbheadP->id,   1, 4,  fileP);
+    pm_writebiglong(fileP, pdbheadP->uniq_seed);
+    pm_writebiglong(fileP, pdbheadP->next_rec);
+    pm_writebigshort(fileP, pdbheadP->num_recs);
+
+    return 0;
+}
+
+
+
+static int
+rechdrWrite(RECHDR * const rechdrP,
+            FILE *   const fileP) {
+
+    if (rechdrP) {
+        pm_writebiglong(fileP, rechdrP->offset);
+        fwrite(rechdrP->unknown,   1, 3, fileP);
+        fwrite(&rechdrP->rec_type, 1, 1, fileP);
+
+        if (rechdrP->n_extra != 0)
+            fwrite(rechdrP->extra, 1, rechdrP->n_extra, fileP);
+    }
+    return 0;
+}
+
+
+
+static void
+imageWriteHeader(IMAGE * const imgP,
+                 FILE *  const fileP) {
+
+    fwrite(imgP->name,       1, 32, fileP);
+    fwrite(&imgP->version,   1,  1, fileP);
+    fwrite(&imgP->type,      1,  1, fileP);
+    fwrite(imgP->reserved1,  1,  4, fileP);
+    fwrite(imgP->note,       1,  4, fileP);
+    pm_writebigshort(fileP, imgP->x_last);
+    pm_writebigshort(fileP, imgP->y_last);
+    fwrite(imgP->reserved2,  1,  4, fileP);
+    pm_writebigshort(fileP, imgP->x_anchor);
+    pm_writebigshort(fileP, imgP->y_anchor);
+    pm_writebigshort(fileP, imgP->width);
+    pm_writebigshort(fileP, imgP->height);
+}
+
+
+
+static void
+imageWriteData(IMAGE *         const imgP,
+               const uint8_t * const data,
+               size_t          const dataSize,
+               FILE *          const fileP) {
+
+    fwrite(data, 1,  dataSize, fileP);
+}
+
+
+
+static void
+imageWrite(IMAGE *   const imgP,
+           uint8_t * const data,
+           size_t    const dataSize,
+           FILE *    const fileP) {
+
+    imageWriteHeader(imgP, fileP);
+
+    imageWriteData(imgP, data, dataSize, fileP);
+}
+
+
+
+static int
+textWrite(TEXT * const textP,
+          FILE * const fileP) {
+    
+    if (textP)
+        fwrite(textP->data, 1, strlen(textP->data), fileP);
+
+    return 0;
+}
+
+
+
+typedef struct {
+    unsigned int match;
+    uint8_t      buf[128];
+    int          mode;
+    size_t       len;
+    size_t       used;
+    uint8_t *    p;
+} RLE;
+#define MODE_MATCH  0
+#define MODE_LIT    1
+#define MODE_NONE   2
+
+#define reset(r) {                              \
+        (r)->match = 0xffff;                    \
+        (r)->mode  = MODE_NONE;                 \
+        (r)->len   = 0;                         \
+    }
+
+
+
+static void
+putMatch(RLE *  const rleP,
+          size_t const n) {
+
+    *rleP->p++ = 0x80 + n - 1;
+    *rleP->p++ = rleP->match;
+    rleP->used += 2;
+    reset(rleP);
+}
+
+
+
+static void
+putLit(RLE *  const rleP,
+       size_t const n) {
+
+    *rleP->p++ = n - 1;
+    rleP->p = (uint8_t *)memcpy(rleP->p, rleP->buf, n) + n;
+    rleP->used += n + 1;
+    reset(rleP);
+}
+
+
+
+static size_t
+compress(const uint8_t * const inData,
+         size_t          const n_in,
+         uint8_t *       const out) {
+
+    static void (*put[])(RLE *, size_t) = {putMatch, putLit};
+    RLE rle;
+    size_t  i;
+    const uint8_t * p;
+
+    MEMSZERO(&rle);
+    rle.p = out;
+    reset(&rle);
+
+    for (i = 0, p = &inData[0]; i < n_in; ++i, ++p) {
+        if (*p == rle.match) {
+            if (rle.mode == MODE_LIT && rle.len > 1) {
+                putLit(&rle, rle.len - 1);
+                ++rle.len;
+                rle.match = *p;
+            }
+            rle.mode = MODE_MATCH;
+            ++rle.len;
+        } else {
+            if (rle.mode == MODE_MATCH)
+                putMatch(&rle, rle.len);
+            rle.mode         = MODE_LIT;
+            rle.match        = *p;
+            rle.buf[rle.len++] = *p;
+        }
+        if (rle.len == 128)
+            put[rle.mode](&rle, rle.len);
+    }
+    if (rle.len != 0)
+        put[rle.mode](&rle, rle.len);
+
+    return rle.used;
+}
+
+
+
+static void
+compressIfRequired(IPDB *     const pdbP,
+                   int        const comp,
+                   uint8_t ** const compressedDataP,
+                   size_t *   const compressedSizeP) {
+
+    if (comp == IPDB_NOCOMPRESS) {
+        *compressedDataP = pdbP->i->data;
+        *compressedSizeP = ipdb_img_size(pdbP->i);
+    } else {
+        int const uncompressedSz = ipdb_img_size(pdbP->i);
+        
+        /* Allocate for the worst case. */
+        size_t const allocSz = (3 * uncompressedSz + 2)/2;
+
+        uint8_t * data;
+            
+        data = pdbP->i->data;
+
+        MALLOCARRAY(data, allocSz);
+            
+        if (data == NULL)
+            pm_error("Could not get %lu bytes of memory to decompress",
+                     (unsigned long)allocSz);
+        else {
+            size_t compressedSz;
+            compressedSz = compress(pdbP->i->data, uncompressedSz, data);
+            if (comp == IPDB_COMPMAYBE && compressedSz >= uncompressedSz) {
+                /* Return the uncompressed data */
+                free(data);
+                *compressedDataP = pdbP->i->data;
+                *compressedSizeP = uncompressedSz;
+            } else {
+                pdbP->i->compressed = TRUE;
+                if (pdbP->i->type == IMG_GRAY16)
+                    pdbP->i->version = 9;
+                else
+                    pdbP->i->version = 1;
+                if (pdbP->t != NULL)
+                    pdbP->t->r->offset -= uncompressedSz - compressedSz;
+                *compressedDataP = data;
+                *compressedSizeP = compressedSz;
+            }
+        }
+    }
+}
+
+
+
+static void
+ipdbWrite(IPDB * const pdbP,
+          int    const comp,
+          FILE * const fileP) {
+
+    RECHDR * const trP = pdbP->t == NULL ? NULL : pdbP->t->r;
+    RECHDR * const irP = pdbP->i->r;
+
+    int rc;
+    uint8_t * compressedData;
+        /* This is the image raster, compressed as required.
+           (I.e. if it doesn't have to be compressed, it isn't).
+        */
+    size_t compressedSize;
+
+    assert(pdbP->i);
+
+    compressIfRequired(pdbP, comp, &compressedData, &compressedSize);
+
+    rc = pdbheadWrite(pdbP->p, fileP);
+    if (rc != 0)
+        pm_error("Failed to write PDB header.  %s", ipdb_err(rc));
+            
+    rc = rechdrWrite(irP, fileP);
+    if (rc != 0)
+        pm_error("Failed to write image record header.  %s", ipdb_err(rc));
+
+    rc = rechdrWrite(trP, fileP);
+    if (rc != 0)
+        pm_error("Failed to write text record header.  %s", ipdb_err(rc));
+
+    imageWrite(pdbP->i, compressedData, compressedSize, fileP);
+
+    rc = textWrite(pdbP->t, fileP);
+    if (rc != 0)
+        pm_error("Failed to write text.  %s", ipdb_err(rc));
+
+    /* Oh, gross.  compressIfRequired() might have returned a pointer to
+       storage that was already allocated, or it might have returned a
+       pointer to newly malloc'ed storage.  In the latter case, we have
+       to free the storage.
+    */
+    if (compressedData != pdbP->i->data)
+        free(compressedData);
+}
+
+
+
+static void
+g16pack(tuple *         const tupleRow,
+        struct pam *    const pamP,
+        uint8_t *       const outData,
+        unsigned int    const paddedWidth) {
+/*----------------------------------------------------------------------------
+   Pack a row of 16-level graysacle pixels 'tupleRow', described by *pamP into
+   'outData', padding it to 'paddedWidth' with white.
+
+   We pack 2 input pixels into one output byte.
+-----------------------------------------------------------------------------*/
+    unsigned int col;
+    unsigned int off;
+    uint8_t * seg;
+
+    for (col = 0, off = 0, seg = &outData[0]; col < paddedWidth; ++col) {
+        if (col < pamP->width)
+            setg16pixel(*seg, 15 - tupleRow[col][0] * 15 / pamP->maxval, off);
+        else
+            /* Pad on the right with white */
+            setgpixel(*seg, 0, off);
+
+        if (++off == 2) {
+            ++seg;
+            off = 0;
+        }
+    }
+}
+
+
+
+static void
+gpack(tuple *         const tupleRow,
+      struct pam *    const pamP,
+      uint8_t *       const outData,
+      unsigned int    const paddedWidth) {
+/*----------------------------------------------------------------------------
+   Pack a row of 4-level graysacle pixels 'tupleRow', described by *pamP into
+   'outData', padding it to 'paddedWidth' with white.
+
+   We pack 4 input pixels into one output byte.
+-----------------------------------------------------------------------------*/
+    unsigned int col;
+    unsigned int off;
+    uint8_t * seg;
+
+    for (col = 0, off = 0, seg = &outData[0]; col < paddedWidth; ++col) {
+        if (col < pamP->width)
+            setgpixel(*seg, 3 - tupleRow[col][0] * 3 / pamP->maxval, off);
+        else
+            /* Pad on the right with white */
+            setgpixel(*seg, 0, off);
+
+        if (++off == 4) {
+            ++seg;
+            off = 0;
+        }
+    }
+}
+
+
+
+static void
+mpack(tuple *         const tupleRow,
+      struct pam *    const pamP,
+      uint8_t *       const outData,
+      unsigned int    const paddedWidth) {
+/*----------------------------------------------------------------------------
+   Pack a row of monochrome pixels 'tupleRow', described by *pamP into
+   'outData', padding it to 'paddedWidth' with white.
+
+   We pack 8 input pixels into one output byte.
+-----------------------------------------------------------------------------*/
+    unsigned int col;
+    unsigned int off;
+    uint8_t * seg;
+
+    assert(paddedWidth % 8 == 0);
+
+    /* Initialize row to white, then set necessary pixels black */
+    memset(outData, 0, paddedWidth/8);
+
+    for (col = 0, off = 0, seg = &outData[0]; col < paddedWidth; ++col) {
+        if (col < pamP->width && tupleRow[col][0] == PAM_BLACK)
+            setmpixelblack(*seg, off);
+        if (++off == 8) {
+            ++seg;
+            off = 0;
+        }
+    }
+}
+
+
+
+static int
+adjustDimensions(unsigned int   const w,
+                 unsigned int   const h,
+                 unsigned int * const awP,
+                 unsigned int * const ahP) {
+
+    unsigned int provW, provH;
+
+    provW = w;
+    provH = h;
+    if (provW % 16 != 0)
+        provW += 16 - (provW % 16);
+    if (provW < 160)
+        provW = 160;
+    if (provH < 160)
+        provH = 160;
+
+    *awP = provW;
+    *ahP = provH;
+
+    return w == provW && h == provH;
+}
+
+
+
+/*
+ * You can allocate only 64k chunks of memory on the pilot and that
+ * supplies an image size limit.
+ */
+#define MAX_SIZE(t) ((1 << 16)*((t) == IMG_GRAY ? 4 : 8))
+
+static void
+imageInsertInit(IPDB * const pdbP,
+                int    const uw,
+                int    const uh,
+                int    const type) {
+
+    char * const name = pdbP->p->name;
+    unsigned int adjustedWidth, adjustedHeight;
+
+    if (pdbP->p->num_recs != 0)
+        pm_error("Image record already present, logic error.");
+    else {
+        adjustDimensions(uw, uh, &adjustedWidth, &adjustedHeight);
+        pm_message("Output dimensions: %uw x %uh",
+                   adjustedWidth, adjustedHeight);
+        if (adjustedWidth * adjustedHeight > MAX_SIZE(type))
+            pm_error("Image too large.   Maximum number of pixels allowed "
+                     "for a %s image is %u",
+                     ipdb_typeName(type), MAX_SIZE(type));
+        else {
+            pdbP->i =
+                ipdb_image_alloc(name, type, adjustedWidth, adjustedHeight);
+            if (pdbP->i == NULL)
+                pm_message("Could not get memory for %u x %u image",
+                           adjustedWidth, adjustedHeight);
+            else
+                pdbP->p->num_recs = 1;
+        }
+    }
+}
+
+
+
+static void
+insertG16image(IPDB *          const pdbP,
+               struct pam *    const pamP,
+               tuple **        const tuples) {
+/*----------------------------------------------------------------------------
+   Insert into the PDB an image in 16-level grayscale format.
+
+   The pixels of the image to insert are 'tuples', described by *pamP.
+   Note that the image inserted may be padded up to larger dimensions.
+-----------------------------------------------------------------------------*/
+    imageInsertInit(pdbP, pamP->width, pamP->height, IMG_GRAY16);
+    {
+        int const rowSize = ipdb_width(pdbP)/2;
+            /* The size in bytes of a packed, padded row */
+
+        uint8_t * outP;
+        unsigned int row;
+
+        for (row = 0, outP = &pdbP->i->data[0];
+             row < pamP->height;
+             ++row, outP += rowSize)
+            g16pack(tuples[row], pamP, outP, ipdb_width(pdbP));
+
+        /* Pad with white on the bottom */
+        for (; row < ipdb_height(pdbP); ++row)
+            memset(outP, 0, rowSize);
+    } 
+}
+
+
+
+static void
+insertGimage(IPDB *          const pdbP,
+             struct pam *    const pamP,
+             tuple **        const tuples) {
+/*----------------------------------------------------------------------------
+   Insert into the PDB an image in 4-level grayscale format.
+
+   The pixels of the image to insert are 'tuples', described by *pamP.
+   Note that the image inserted may be padded up to larger dimensions.
+-----------------------------------------------------------------------------*/
+    imageInsertInit(pdbP, pamP->width, pamP->height, IMG_GRAY);
+    {
+        int const rowSize = ipdb_width(pdbP)/4;
+            /* The size in bytes of a packed, padded row */
+
+        uint8_t * outP;
+        unsigned int row;
+
+        for (row = 0, outP = &pdbP->i->data[0];
+             row < pamP->height;
+             ++row, outP += rowSize)
+            gpack(tuples[row], pamP, outP, ipdb_width(pdbP));
+
+        /* Pad with white on the bottom */
+        for (; row < ipdb_height(pdbP); ++row)
+            memset(outP, 0, rowSize);
+    } 
+}
+
+
+
+static void
+insertMimage(IPDB *          const pdbP,
+             struct pam *    const pamP,
+             tuple **        const tuples) {
+/*----------------------------------------------------------------------------
+   Insert into the PDB an image in monochrome format.
+
+   The pixels of the image to insert are 'tuples', described by *pamP.
+   Note that the image inserted may be padded up to larger dimensions.
+-----------------------------------------------------------------------------*/
+    imageInsertInit(pdbP, pamP->width, pamP->height, IMG_MONO);
+    {
+        int const rowSize = ipdb_width(pdbP)/8;
+            /* The size in bytes of a packed, padded row */
+
+        uint8_t * outP;
+        unsigned int row;
+
+        for (row = 0, outP = &pdbP->i->data[0];
+             row < pamP->height;
+             ++row, outP += rowSize)
+            mpack(tuples[row], pamP, outP, ipdb_width(pdbP));
+
+        /* Pad with white on the bottom */
+        for (; row < ipdb_height(pdbP); ++row)
+            memset(outP, 0, rowSize);
+    } 
+}
+
+
+
+static int
+insertText(IPDB *       const pdbP,
+           const char * const s) {
+
+    int retval;
+
+    if (pdbP->i == NULL)
+        retval = E_IMAGENOTTHERE;
+    else if (pdbP->p->num_recs == 2)
+        retval = E_TEXTTHERE;
+    else {
+        pdbP->t = ipdb_text_alloc(s);
+        if (pdbP->t == NULL)
+            retval = ENOMEM;
+        else {
+            pdbP->p->num_recs = 2;
+
+            pdbP->i->r->offset += 8;
+            pdbP->t->r->offset =
+                pdbP->i->r->offset + IMAGESIZE + ipdb_img_size(pdbP->i);
+
+            retval = 0;
+        }
+    }
+    return retval;
+}
+
+
+
+static void
+readimg(IPDB * const pdbP,
+        FILE * const ifP,
+        bool   const depth4) {
+
+     struct pam inpam;
+    tuple ** tuples;
+
+    tuples = pnm_readpam(ifP, &inpam, PAM_STRUCT_SIZE(tuple_type));
+
+    if (strneq(inpam.tuple_type, "RGB", 3))
+        pm_error("Input image is color.  Cannot make a Palm color image.");
+
+    if (inpam.maxval == 1)
+        insertMimage(pdbP, &inpam, tuples);
+    else if (depth4)
+        insertG16image(pdbP, &inpam, tuples);
+    else
+        insertGimage(pdbP, &inpam, tuples);
+
+    pnm_freepamarray(tuples, &inpam);
+}
+
+
+
+static void
+readtxt(IPDB *       const pdbP,
+        const char * const noteFileName) {
+
+    struct stat st;
+    char * fileContent;
+    FILE * fP;
+    int n;
+    int rc;
+    size_t bytesRead;
+
+    rc = stat(noteFileName, &st);
+
+    if (rc != 0)
+        pm_error("stat of '%s' failed, errno = %d (%s)",
+                 noteFileName, errno, strerror(errno));
+
+    fP = pm_openr(noteFileName);
+
+    MALLOCARRAY(fileContent, st.st_size + 1);
+
+    if (fileContent == NULL)
+        pm_error("Couldn't get %lu bytes of storage to read in note file",
+                 (unsigned long) st.st_size);
+
+    bytesRead = fread(fileContent, 1, st.st_size, fP);
+
+    if (bytesRead != st.st_size)
+        pm_error("Failed to read note file '%s'.  Errno = %d (%s)",
+                 noteFileName, errno, strerror(errno));
+
+    pm_close(fP);
+
+    /* Chop of trailing newlines */
+    for (n = strlen(fileContent) - 1; n >= 0 && fileContent[n] == '\n'; --n)
+        fileContent[n] = '\0';
+
+    insertText(pdbP, fileContent);
+}
+
+
+
+int
+main(int argc, const char **argv) {
+
+    struct cmdlineInfo cmdline;
+    IPDB * pdbP;
+    FILE * ifP;
+    int comp;
+
+    pm_proginit(&argc, argv);
+
+    parseCommandLine(argc, argv, &cmdline);
+
+    ifP = pm_openr(cmdline.inputFileName);
+
+    switch (cmdline.compMode) {
+    case COMPRESSED:   comp = IPDB_COMPRESS;   break;
+    case UNCOMPRESSED: comp = IPDB_NOCOMPRESS; break;
+    case MAYBE:        comp = IPDB_COMPMAYBE;  break;
+    }
+
+    pdbP = ipdb_alloc(cmdline.title);
+
+    if (pdbP == NULL)
+        pm_error("Failed to allocate IPDB structure");
+
+    readimg(pdbP, ifP, cmdline.depth4);
+
+    if (cmdline.notefile)
+        readtxt(pdbP, cmdline.notefile);
+
+    ipdbWrite(pdbP, comp, stdout);
+
+    if (comp == IPDB_COMPMAYBE && !ipdb_compressed(pdbP))
+        pm_message("Image too complex to be compressed.");
+
+    ipdb_free(pdbP);
+
+    pm_close(ifP);
+
+    return EXIT_SUCCESS;
+}
diff --git a/converter/other/pamtopfm.c b/converter/other/pamtopfm.c
index 129b8eee..25a8a0af 100644
--- a/converter/other/pamtopfm.c
+++ b/converter/other/pamtopfm.c
@@ -52,7 +52,7 @@ parseCommandLine(int argc,
    was passed to us as the argv array.  We also trash *argv.
 --------------------------------------------------------------------------*/
     optEntry *option_def = malloc( 100*sizeof( optEntry ) );
-    /* Instructions to optParseOptions3 on how to parse our options. */
+    /* Instructions to pm_optParseOptions3 on how to parse our options. */
     optStruct3 opt;
   
     unsigned int option_def_index;
@@ -67,7 +67,7 @@ parseCommandLine(int argc,
     opt.short_allowed = FALSE;  /* We have no short (old-fashioned) options */
     opt.allowNegNum = FALSE;   /* We have no parms that are negative numbers */
 
-    optParseOptions3( &argc, argv, opt, sizeof(opt), 0 );
+    pm_optParseOptions3( &argc, argv, opt, sizeof(opt), 0 );
     /* Uses and sets argc, argv, and some of *cmdline_p and others. */
 
     if (endianSpec) {
@@ -150,12 +150,12 @@ floatToPfmSample(float       const input,
    Type converter
 -----------------------------------------------------------------------------*/
     if (machineEndianness == pfmEndianness) {
-        *(float *)outputP->bytes = input;
+        MEMSCPY(&outputP->bytes, &input);
     } else {
         unsigned char reversed[sizeof(pfmSample)];
         unsigned int i, j;
 
-        *(float *)reversed = input;
+        MEMSCPY(&reversed, &input);
         
         for (i = 0, j = sizeof(pfmSample)-1; 
              i < sizeof(pfmSample); 
diff --git a/converter/other/pamtopng.c b/converter/other/pamtopng.c
new file mode 100644
index 00000000..fdeb6582
--- /dev/null
+++ b/converter/other/pamtopng.c
@@ -0,0 +1,825 @@
+/*
+** read a PNM/PAM image and produce a Portable Network Graphics (PNG) file
+**
+** derived from pnmtorast.c by Jef Poskanzer and pamrgbatopng.c by Bryan
+** Henderson <bryanh@giraffe-data.com> and probably some other sources
+**
+** Copyright (C) 1995-1998 by Alexander Lehmann <alex@hal.rhein-main.de>
+**                        and Willem van Schaik <willem@schaik.com>
+** Copyright (C) 1999,2001 by Greg Roelofs <newt@pobox.com>
+** Copyright (C) 2015 by Willem van Schaik <willem@schaik.com>
+**
+** 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.
+*/
+
+/*
+  This Netpbm program pamtopng was derived in 2015 from the Netpbm program
+  Pnmtopng. This was a nearly complete rewrite with the following goals:
+
+  - Add ability to create a PNG alpha channel from the alpha channel in a
+    PAM (format P7) file.
+
+  - Simplify the 20 year old pnmtopng code. Because of the many, many features
+    that program implements and its need for backward compatibility, the code
+    had become rather complex.  This program is roughly 1/3 the size of
+    pnmtopng.c that it replaces.
+
+  - In 1995 bandwith was limited and therefore filesize had to be kept
+    small. The original program tried to optimize for that by applying
+    many "clever tricks". Today that isn't an issue anymore, so gone 
+    are filters, palettes, etc. Also, image conversions were removed,
+    because those should be done with other NetPBM tools.
+
+  - Add ability to create iTXt (international language) chunks.
+*/
+
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <png.h>
+/* setjmp.h needs to be included after png.h */
+#include <setjmp.h>
+
+#include "pm_c_util.h"
+#include "mallocvar.h"
+#include "nstring.h"
+#include "shhopt.h"
+#include "pam.h"
+#include "pngx.h"
+#include "pngtxt.h"
+
+
+/* global variable */
+static bool verbose;
+
+
+struct CmdlineInfo {
+    const char * inputFileName;
+    unsigned int verbose;
+    unsigned int transparencySpec;
+    const char * transparency;
+    unsigned int chromaSpec;
+    struct pngx_chroma chroma;
+    unsigned int gammaSpec;
+    float gamma;
+    unsigned int srgbintentSpec;
+    pngx_srgbIntent srgbintent;
+    unsigned int textSpec;
+    const char * text;
+    unsigned int ztxtSpec;
+    const char * ztxt;
+    unsigned int itxtSpec;
+    const char * itxt;
+    unsigned int backgroundSpec;
+    const char * background;
+    unsigned int timeSpec;
+    time_t time;
+};
+
+
+
+static void
+parseChromaOpt(const char *         const chromaOpt,
+               struct pngx_chroma * const chromaP) {
+
+    int count;
+    
+    count = sscanf(chromaOpt, "%f %f %f %f %f %f %f %f",
+                   &chromaP->wx, &chromaP->wy,
+                   &chromaP->rx, &chromaP->ry,
+                   &chromaP->gx, &chromaP->gy,
+                   &chromaP->bx, &chromaP->by);
+
+    if (count != 6)
+        pm_error("Invalid syntax for the -rgb option value '%s'.  "
+                 "Should be 6 floating point number: "
+                 "x and y for each of white, red, green, and blue",
+                 chromaOpt);
+}
+
+
+
+static void
+parseSrgbintentOpt(const char *      const srgbintentOpt,
+                   pngx_srgbIntent * const srgbintentP) {
+    
+    if (streq(srgbintentOpt, "perceptual"))
+        *srgbintentP = PNGX_PERCEPTUAL;
+    else if (streq(srgbintentOpt, "relativecolorimetric"))
+        *srgbintentP = PNGX_RELATIVE_COLORIMETRIC;
+    else if (streq(srgbintentOpt, "saturation"))
+        *srgbintentP = PNGX_SATURATION;
+    else if (streq(srgbintentOpt, "absolutecolorimetric"))
+        *srgbintentP = PNGX_ABSOLUTE_COLORIMETRIC;
+    else
+        pm_error("Unrecognized sRGB intent value '%s'.  We understand "
+                 "only 'perceptual', 'relativecolorimetric', "
+                 "'saturation', and 'absolutecolorimetric'",
+                 srgbintentOpt);
+}
+
+
+
+static void
+parseTimeOpt(const char * const timeOpt,
+             time_t *     const timeP) {
+
+    struct tm brokenTime;
+    int year;
+    int month;
+    int count;
+
+    count = sscanf(timeOpt, "%d-%d-%d %d:%d:%d",
+                   &year,
+                   &month,
+                   &brokenTime.tm_mday,
+                   &brokenTime.tm_hour,
+                   &brokenTime.tm_min,
+                   &brokenTime.tm_sec);
+
+    if (count != 6)
+        pm_error("Invalid value for -time '%s'.   It should have "
+                 "the form [yy]yy-mm-dd hh:mm:ss.", timeOpt);
+    
+    if (year < 0)
+        pm_error("Year is negative in -time value '%s'", timeOpt);
+    if (year > 9999)
+        pm_error("Year is more than 4 digits in -time value '%s'",
+                 timeOpt);
+    if (month < 0)
+        pm_error("Month is negative in -time value '%s'", timeOpt);
+    if (month > 12)
+        pm_error("Month is >12 in -time value '%s'", timeOpt);
+    if (brokenTime.tm_mday < 0)
+        pm_error("Day of month is negative in -time value '%s'",
+                 timeOpt);
+    if (brokenTime.tm_mday > 31)
+        pm_error("Day of month is >31 in -time value '%s'", timeOpt);
+    if (brokenTime.tm_hour < 0)
+        pm_error("Hour is negative in -time value '%s'", timeOpt);
+    if (brokenTime.tm_hour > 23)
+        pm_error("Hour is >23 in -time value '%s'", timeOpt);
+    if (brokenTime.tm_min < 0)
+        pm_error("Minute is negative in -time value '%s'", timeOpt);
+    if (brokenTime.tm_min > 59)
+        pm_error("Minute is >59 in -time value '%s'", timeOpt);
+    if (brokenTime.tm_sec < 0)
+        pm_error("Second is negative in -time value '%s'", timeOpt);
+    if (brokenTime.tm_sec > 59)
+        pm_error("Second is >59 in -time value '%s'", timeOpt);
+
+    brokenTime.tm_mon = month - 1;
+    if (year >= 1900)
+        brokenTime.tm_year = year - 1900;
+    else
+        brokenTime.tm_year = year;
+
+    /* Note that mktime() considers brokeTime to be in local time.
+       This is what we want, since we got it from a user.  User should
+       set his local time zone to UTC if he wants absolute time.
+    */
+    *timeP = mktime(&brokenTime);
+}
+
+
+
+static void
+parseCommandLine (int                  argc,
+                  const char **        argv,
+                  struct CmdlineInfo * const cmdlineP) {
+    
+    optEntry * option_def;
+    optStruct3 opt;
+    unsigned int option_def_index = 0;  /* incremented by OPTENT3 */
+
+    const char * srgbintent;
+    const char * chroma;
+    const char * time;
+
+    MALLOCARRAY(option_def, 100);
+
+    OPTENT3(0,  "verbose",      OPT_FLAG,       NULL,
+            &cmdlineP->verbose,        0);
+    OPTENT3(0,  "transparency", OPT_STRING,     &cmdlineP->transparency,
+            &cmdlineP->transparencySpec, 0);
+    OPTENT3(0,  "chroma",       OPT_STRING,     &chroma,
+            &cmdlineP->chromaSpec,     0);
+    OPTENT3(0,  "gamma",        OPT_FLOAT,      &cmdlineP->gamma,
+            &cmdlineP->gammaSpec,      0);
+    OPTENT3(0,  "srgbintent",   OPT_STRING,     &srgbintent,
+            &cmdlineP->srgbintentSpec, 0);
+    OPTENT3(0,  "text",         OPT_STRING,     &cmdlineP->text,
+            &cmdlineP->textSpec,       0);
+    OPTENT3(0,  "ztxt",         OPT_STRING,     &cmdlineP->ztxt,
+            &cmdlineP->ztxtSpec,       0);
+    OPTENT3(0,  "itxt",         OPT_STRING,     &cmdlineP->itxt,
+            &cmdlineP->itxtSpec,       0);
+    OPTENT3(0,  "background",   OPT_STRING,     &cmdlineP->background,
+            &cmdlineP->backgroundSpec, 0);
+    OPTENT3(0,  "time",         OPT_STRING,        &time,
+            &cmdlineP->timeSpec,       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 */
+
+    /* uses and sets argc, argv, and some of *cmdlineP and others */
+    pm_optParseOptions3(&argc, (char **)argv, opt, sizeof(opt), 0);
+
+    if (cmdlineP->chromaSpec)
+        parseChromaOpt(chroma, &cmdlineP->chroma);
+
+    if (cmdlineP->srgbintentSpec)
+        parseSrgbintentOpt(srgbintent, &cmdlineP->srgbintent);
+
+    if (cmdlineP->timeSpec)
+        parseTimeOpt(time, &cmdlineP->time);
+    
+    /* get the input-file or stdin pipe */
+    if (argc-1 < 1)
+        cmdlineP->inputFileName = "-";
+    else if (argc-1 == 1)
+        cmdlineP->inputFileName = argv[1];
+    else
+        pm_error("Program takes at most one argument: input file name.");
+
+    free(option_def);
+}
+
+
+
+static png_byte
+colorTypeFromInputType(const struct pam * const pamP) {
+/*----------------------------------------------------------------------------
+  Analyse the Netpbm image for color-type and bit-depth
+-----------------------------------------------------------------------------*/
+    png_byte retval;
+
+    if (pamP->depth < 1 && pamP->depth > 4)
+        pm_error ("Number of color planes must be between 1 and 4 inclusive");
+
+    if (pamP->maxval != 1 && pamP->maxval != 3 && pamP->maxval != 15 &&
+        pamP->maxval != 255 && pamP->maxval != 65535)
+        pm_error("The maxval of the input image is %u; "
+                 "it must be 1, 3, 15, 255 or 65535", (unsigned)pamP->maxval);
+
+    if (strneq(pamP->tuple_type, "RGB_ALPHA", 9)) {
+        if (pamP->depth == 4)
+            retval = PNG_COLOR_TYPE_RGB_ALPHA;
+        else
+            pm_error("Input tuple type is RGB_ALPHA, "
+                     "but number of planes is %u instead of 4",
+                pamP->depth);
+    } else if (strneq(pamP->tuple_type, "RGB", 3)) {
+        if (pamP->depth == 3)
+            retval = PNG_COLOR_TYPE_RGB;
+        else
+            pm_error("Input tuple type is RGB, "
+                     "but number of planes is %u instead of 3",
+                     pamP->depth);
+    } else if (strneq(pamP->tuple_type, "GRAYSCALE_ALPHA", 15)) {
+        if (pamP->depth == 2)
+            retval = PNG_COLOR_TYPE_GRAY_ALPHA;
+        else
+            pm_error("Input tupel type is GRAYSCALE_ALPHA, "
+                     "but number of planes is %u instread of 2",
+                     pamP->depth);
+    } else if (strneq(pamP->tuple_type, "GRAYSCALE", 9)) {
+        if (pamP->depth == 1)
+            retval = PNG_COLOR_TYPE_GRAY;
+        else
+            pm_error("Input tuple type is GRAYSCALE, "
+                     "but number of planes is %u instead of 1",
+                     pamP->depth);
+    } else if (strneq(pamP->tuple_type, "BLACKANDWHITE", 3)) {
+        if (pamP->depth != 1)
+            pm_error("Input tuple type is BLACKANDWHITE, "
+                     "but number of planes is %u instead of 1",
+                     pamP->depth);
+        if (pamP->maxval != 1)
+            pm_error("Input tuple type is BLACKANDWHITE, "
+                     "but maxval is %u instead of 1", (unsigned)pamP->maxval);
+
+        retval = PNG_COLOR_TYPE_GRAY;
+    } else
+        pm_error("Unrecognized tuple type: '%s'", pamP->tuple_type);
+
+    return retval;
+}
+
+
+
+/*****************************************************************************
+*  Subroutines that create all the (ancillary) chunks
+*****************************************************************************/
+
+
+
+static png_color_16
+parseAndScaleColor(const char * const colorString,
+                   xelval       const pngMaxval) {
+
+    png_color_16 pngColor;
+
+    if (colorString) {
+        xel const inputColor = ppm_parsecolor(colorString, PNM_OVERALLMAXVAL);
+
+        xel scaledColor;
+
+        /* Scale the color down to the PNG bit depth */
+        PPM_DEPTH(scaledColor, inputColor, PNM_OVERALLMAXVAL, pngMaxval);
+
+        pngColor.red   = PPM_GETR(scaledColor);
+        pngColor.green = PPM_GETG(scaledColor);
+        pngColor.blue  = PPM_GETB(scaledColor);
+        pngColor.gray  = PNM_GET1(scaledColor);
+    }
+
+    return pngColor;
+}
+
+
+
+static png_color_8
+sigBitsFmImgType(unsigned int const pnmBitDepth,
+                 int          const pngColorType) {
+/*----------------------------------------------------------------------------
+   A representation used in PNG of color resolutions in an original image.
+-----------------------------------------------------------------------------*/
+    png_color_8 retval;
+
+    /* Initial values */
+    if (pnmBitDepth < 8) {
+        switch (pngColorType) {
+        case PNG_COLOR_TYPE_RGB:
+            retval.red   = pnmBitDepth;
+            retval.green = pnmBitDepth;
+            retval.blue  = pnmBitDepth;
+            retval.gray  = 0;
+            retval.alpha = 0;
+            break;
+        case PNG_COLOR_TYPE_RGB_ALPHA:
+            retval.red   = pnmBitDepth;
+            retval.green = pnmBitDepth;
+            retval.blue  = pnmBitDepth;
+            retval.gray  = 0;
+            retval.alpha = pnmBitDepth;
+            break;
+        case PNG_COLOR_TYPE_GRAY:
+            /* PNG can (so presumably will) use original bit depth */
+            retval.red   = 0;
+            retval.green = 0;
+            retval.blue  = 0;
+            retval.gray  = 0;
+            retval.alpha = 0;
+            break;
+        case PNG_COLOR_TYPE_GRAY_ALPHA:
+            retval.red   = 0;
+            retval.green = 0;
+            retval.blue  = 0;
+            retval.gray  = pnmBitDepth;
+            retval.alpha = pnmBitDepth;
+            break;
+        }
+    } else {
+        /* PNG can (so presumably will) use original bit depth */
+        retval.red   = 0;
+        retval.green = 0;
+        retval.blue  = 0;
+        retval.gray  = 0;
+        retval.alpha = 0;
+    }
+    return retval;
+}
+
+
+
+static void
+doTrnsChunk(const struct pam * const pamP,
+            struct pngx *      const pngxP,
+            const char *       const trans) {
+
+    if (pngx_colorType(pngxP) == PNG_COLOR_TYPE_GRAY_ALPHA || 
+        pngx_colorType(pngxP) == PNG_COLOR_TYPE_RGB_ALPHA)
+        pm_error("Both alpha channel and transparency chunk not allowed.");
+    else {
+        xelval const pngMaxval = pm_bitstomaxval(pngx_bitDepth(pngxP));
+        png_color_16 const pngColor = parseAndScaleColor(trans, pngMaxval);
+            /* Transparency color from text format scaled from 16-bit to
+               maxval.
+            */
+
+        pngx_setTrnsValue(pngxP, pngColor);
+
+        if (verbose) {
+            if (pngx_colorType(pngxP) == PNG_COLOR_TYPE_GRAY) {
+                pm_message("writing tRNS chunk with color {gray} = {%u}",
+                           pngColor.gray );
+            } else if (pngx_colorType(pngxP) == PNG_COLOR_TYPE_RGB) {
+                pm_message("writing tRNS chunk with color "
+                           "{red, green, blue} = {%u, %u, %u}",
+                           pngColor.red, pngColor.green, pngColor.blue);
+            }
+        }
+    }
+}
+
+
+
+static void
+doChrmChunk(struct pngx *      const pngxP,
+            struct pngx_chroma const chroma) {
+    
+    pngx_setChrm(pngxP, chroma);
+
+    if (verbose) {
+        pm_message("writing cHRM chunk { wx, wy, rx, ry, gx, gy, bx, by } = "
+                   "{ %4.2f, %4.2f, %4.2f, %4.2f, "
+                   "%4.2f, %4.2f, %4.2f, %4.2f }", 
+                   chroma.wx, chroma.wy,
+                   chroma.rx, chroma.ry,
+                   chroma.gx, chroma.gy,
+                   chroma.bx, chroma.by);
+    }
+}
+
+
+
+static void 
+doGamaChunk(struct pngx *  const pngxP,
+            float          const gamma) {
+
+    pngx_setGama(pngxP, gamma);
+
+    if (verbose) {
+        pm_message("writing gAMA chunk with image gamma value %4.2f", gamma);
+    }
+}
+
+
+
+static void
+doSbitChunk(const struct pam * const pamP,
+            struct pngx *      const pngxP,
+            png_color_8        const sigBits) {
+
+    if (sigBits.red + sigBits.green + sigBits.blue +
+        sigBits.gray + sigBits.alpha > 0) {
+        pngx_setSbit(pngxP, sigBits);
+    }
+}
+
+
+
+static void
+doSrgbChunk(struct pngx *   const pngxP,
+            pngx_srgbIntent const srgbIntent) {
+
+    pngx_setSrgb(pngxP, srgbIntent);
+
+    if (verbose) {
+        pm_message("writing sRGB chunk with intent value %s",
+                   pngx_srgbIntentDesc(srgbIntent));
+    }
+}
+
+
+
+static void
+doTextChunkSet(struct pngx * const pngxP,
+               const char *  const textFileName) {
+
+    bool const ztxt = true;
+    bool const itxt = false;
+
+    FILE * tfP;
+
+    tfP = pm_openr(textFileName);
+    
+    pngtxt_addChunk(pngxP, tfP, ztxt, itxt, verbose);
+    
+    pm_close(tfP);
+}
+
+
+
+static void
+doZtxtChunkSet(struct pngx * const pngxP,
+               const char *  const textFileName) {
+
+    bool const ztxt = true;
+    bool const itxt = false;
+
+    FILE * tfP;
+
+    tfP = pm_openr(textFileName);
+    
+    pngtxt_addChunk(pngxP, tfP, ztxt, itxt, verbose);
+    
+    pm_close(tfP);
+}
+
+
+
+
+static void
+doItxtChunkSet(struct pngx * const pngxP,
+               const char *  const textFileName) {
+
+    bool const ztxt = true;
+    bool const itxt = true;
+
+    FILE * tfP;
+
+    tfP = pm_openr(textFileName);
+
+    pngtxt_addChunk(pngxP, tfP, ztxt, itxt, verbose);
+}
+
+
+
+static void
+doBkgdChunk (const struct pam * const pamP,
+             struct pngx *      const pngxP,
+             const char *       const colorName)
+{
+    xelval const pngMaxval = pm_bitstomaxval(pngx_bitDepth(pngxP));
+
+    png_color_16 const pngColor = parseAndScaleColor(colorName, pngMaxval);
+        /* Background color from text format, scaled from 16-bit to maxval */
+
+    pngx_setBkgdRgb(pngxP, pngColor);
+
+    if (verbose) {
+        if (pngx_colorType(pngxP) == PNG_COLOR_TYPE_GRAY || 
+            pngx_colorType(pngxP) == PNG_COLOR_TYPE_GRAY_ALPHA) {
+            pm_message("writing bKGD chunk with gray level = %u",
+                       pngColor.gray);
+        } else if (pngx_colorType(pngxP) == PNG_COLOR_TYPE_RGB || 
+                   pngx_colorType(pngxP) == PNG_COLOR_TYPE_RGB_ALPHA) {
+            pm_message("writing bKGD chunk with color {red, green, blue} = "
+                       "{%u, %u, %u}",
+                       pngColor.red, pngColor.green, pngColor.blue);
+        }
+    }
+}
+
+
+
+static void
+doTimeChunk(struct pngx * const pngxP,
+            time_t        const time) {
+
+    pngx_setTime(pngxP, time);
+
+    if (verbose) {
+        struct tm * const brokenTimeP = gmtime(&time);
+
+        char buffer[100];
+
+        strftime(buffer, sizeof(buffer), "%Y-%m-%d %H:%M:%S", brokenTimeP);
+
+        pm_message("Writing tIME chunk specifying datetime %s", buffer);
+    }
+}
+
+
+
+static void
+setShift(struct pngx * const pngxP,
+         png_color_8   const sigBits) {
+
+    if (sigBits.red + sigBits.green + sigBits.blue +
+        sigBits.gray + sigBits.alpha > 0) {
+
+        /* Move the 1, 2, 4 bits to most significant bits */
+        pngx_setShift(pngxP, sigBits);
+    }
+}
+
+
+
+static void
+convertRaster(const struct pam * const pamP,
+              const tuple *      const tuplerow,
+              png_byte *         const pngRow,
+              unsigned int       const bitDepth) {
+
+    unsigned int col;
+
+    /* An image row consists of columns x planes like gray or rgb(a) x 8 or 16
+       bits.
+    */
+    for (col = 0; col < pamP->width; ++col) {
+        unsigned int plane;
+        for (plane = 0; plane < pamP->depth; ++plane) {
+            if (bitDepth > 8) {
+                /* Copy 2 bytes = 16 bits for one pixel */
+                pngRow[2 * (pamP->depth * col + plane)] =
+                    (tuplerow[col][plane] >> 8) & 0xff ;
+                pngRow[2 * (pamP->depth * col + plane) + 1] =
+                    tuplerow[col][plane] & 0xff ;
+            } else {
+                /* Copy 1 byte for one pixel. Later, a packing of 2, 4 or 8
+                   pixels into a single byte can still happen.
+                */
+                pngRow[pamP->depth * col + plane] = tuplerow[col][plane];
+            }
+        }
+    }
+}
+
+
+
+static void
+writeRaster(const struct pam * const pamP,
+            struct pngx *      const pngxP,
+            int                const bitDepth) {
+
+    tuple * tupleRow;
+    png_byte * pngRow;
+    unsigned int row;
+
+    /* We process row-by-row and do not read the complete image into memory */
+
+    tupleRow = pnm_allocpamrow(pamP);
+
+    MALLOCARRAY(pngRow, pamP->width * 8);
+        /* sufficient to store a 16-bit RGB+A row */
+
+    if (pngRow == NULL)
+        pm_error("Unable to allocate space for PNG pixel row for "
+                 "%u columns", pamP->width);
+    else {
+        for (row = 0; row < pamP->height; ++row) {
+            pnm_readpamrow(pamP, tupleRow);
+
+            convertRaster(pamP, tupleRow, pngRow, bitDepth);
+
+            png_write_row(pngxP->png_ptr, pngRow);
+        }
+        free(pngRow);
+    }
+    pnm_freepamrow(tupleRow);
+}
+
+
+
+static void
+writePng(const struct pam * const pamP,
+         FILE *             const ofP,
+         struct CmdlineInfo const cmdline) {
+
+    unsigned int const pnmBitDepth = pm_maxvaltobits(pamP->maxval);
+    int const pngColorType = colorTypeFromInputType(pamP);
+
+    struct pngx * pngxP;
+    unsigned int pngBitDepth;
+    png_color_8 sBit;
+
+    pngx_create(&pngxP, PNGX_WRITE, NULL);
+
+
+
+    if ((pngColorType == PNG_COLOR_TYPE_RGB ||
+         pngColorType == PNG_COLOR_TYPE_RGB_ALPHA) &&
+        pnmBitDepth < 8) {
+
+        pngBitDepth = 8;
+    } else
+        pngBitDepth = pnmBitDepth;
+
+    png_init_io(pngxP->png_ptr, ofP);
+
+    pngx_setIhdr(pngxP, pamP->width, pamP->height,
+                 pngBitDepth, pngColorType,
+                 PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_BASE,
+                 PNG_FILTER_TYPE_BASE);
+
+    sBit = sigBitsFmImgType(pnmBitDepth, pngColorType);
+
+    /* Where requested, add ancillary chunks */
+    if (cmdline.transparencySpec)
+        doTrnsChunk(pamP, pngxP,cmdline.transparency);
+
+    if (cmdline.chromaSpec)
+        doChrmChunk(pngxP, cmdline.chroma);
+
+    if (cmdline.gammaSpec)
+        doGamaChunk(pngxP, cmdline.gamma);
+
+    /* no iccp */
+
+    doSbitChunk(pamP, pngxP, sBit);
+
+    if (cmdline.srgbintentSpec)
+        doSrgbChunk(pngxP, cmdline.srgbintent);
+
+    if (cmdline.textSpec)
+        doTextChunkSet(pngxP, cmdline.text);
+
+    if (cmdline.ztxtSpec)
+        doZtxtChunkSet(pngxP, cmdline.ztxt);
+
+    if (cmdline.itxtSpec)
+        doItxtChunkSet(pngxP, cmdline.itxt);
+
+    if (cmdline.backgroundSpec)
+        doBkgdChunk(pamP, pngxP, cmdline.background);
+
+    /* no hist */
+
+    /* no phys */
+
+    /* no splt */
+
+    if (cmdline.timeSpec)
+        doTimeChunk(pngxP, cmdline.time);
+
+    setShift(pngxP, sBit);
+
+    /* Write the ancillary chunks to PNG file */
+    pngx_writeInfo(pngxP);
+
+    if (pngColorType != PNG_COLOR_TYPE_GRAY && pnmBitDepth < 8) {
+        /* Move the 1, 2, 4 bits to most significant bits */
+        pngx_setShift(pngxP, sBit);
+    }
+    if ((pngColorType == PNG_COLOR_TYPE_GRAY) && (pnmBitDepth < 8)) {
+        /* Pack multiple pixels in a byte */
+        pngx_setPacking(pngxP);
+    }
+
+    writeRaster(pamP, pngxP, pnmBitDepth);
+
+    pngx_writeEnd(pngxP);
+    pngx_destroy(pngxP);
+}
+
+
+
+
+static void
+reportInputFormat(const struct pam * const pamP) {
+
+    const char * formatDesc;
+
+    if (pamP->format == PBM_FORMAT || pamP->format == RPBM_FORMAT)
+        formatDesc = "PBM";
+    else if (pamP->format == PGM_FORMAT || pamP->format == RPGM_FORMAT)
+        formatDesc = "PGM";
+    else if (pamP->format == PPM_FORMAT || pamP->format == RPPM_FORMAT)
+        formatDesc = "PPM";
+    else if (pamP->format == PAM_FORMAT)
+        formatDesc = "PAM";
+    else
+        formatDesc = NULL;
+
+    if (formatDesc)
+        pm_message("Input format = %s", formatDesc);
+    else
+        pm_message("Unrecognized input format, format code = 0x%x",
+                   pamP->format);
+
+    pm_message("Input tuple type = '%s'", pamP->tuple_type);
+    pm_message("Input depth = %u", pamP->depth);
+    pm_message("Input maxval = %u", (unsigned int) pamP->maxval);
+}
+
+
+
+int
+main(int           argc,
+     const char ** argv) {
+
+    FILE * ifP;
+    struct CmdlineInfo cmdline;
+    struct pam pam;
+
+    pm_proginit(&argc, argv);
+
+    parseCommandLine(argc, argv, &cmdline);
+
+    verbose = cmdline.verbose;
+
+    ifP = pm_openr(cmdline.inputFileName);
+
+    pnm_readpaminit(ifP, &pam, PAM_STRUCT_SIZE(tuple_type));
+
+    if (verbose)
+        reportInputFormat(&pam);
+
+    writePng(&pam, stdout, cmdline);
+
+    pm_close(ifP);
+
+    return 0;
+}
+
+
+
diff --git a/converter/other/pamtopnm.c b/converter/other/pamtopnm.c
index 86f6514c..f043d721 100644
--- a/converter/other/pamtopnm.c
+++ b/converter/other/pamtopnm.c
@@ -17,23 +17,23 @@
 #include "shhopt.h"
 #include "mallocvar.h"
 
-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;  /* Filespecs of input files */
-    unsigned int assume;    /* -assume option */
+    const char * inputFileName;  /* Name of input file */
+    unsigned int assume;
 };
 
 
 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.
 -----------------------------------------------------------------------------*/
-    optEntry *option_def;
+    optEntry * option_def;
         /* Instructions to OptParseOptions3 on how to parse our options.
          */
     optStruct3 opt;
@@ -49,16 +49,18 @@ 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 */
 
-    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 (argc-1 == 0) 
-        cmdlineP->inputFilespec = "-";
+        cmdlineP->inputFileName = "-";
     else if (argc-1 != 1)
         pm_error("Program takes zero or one argument (filename).  You "
                  "specified %d", argc-1);
     else
-        cmdlineP->inputFilespec = argv[1];
+        cmdlineP->inputFileName = argv[1];
+
+    free(option_def);
 }
 
 
@@ -69,11 +71,11 @@ validateTupleType(struct pam const inpam,
 /*----------------------------------------------------------------------------
    Make sure the image has a tuple type we know how to convert to PNM.
 
-   We're quite liberal, trying to accomodate all sorts of future
+   We're quite liberal, trying to accommodate all sorts of future
    twists on the formats.  If the tuple type _starts with_
    BLACKANDWHITE, GRAYSCALE, or RGB, and has at least as many planes
    as we'd need to convert to PBM, PGM, or PPM, respectively, we
-   accept it.  We thus accomodate variations on these formats that add
+   accept it.  We thus accommodate variations on these formats that add
    planes and add to the right end of the tuple type to explain them.
 
    If Callers specified 'assumeTupleType', we're even more liberal.
@@ -105,19 +107,19 @@ validateTupleType(struct pam const inpam,
 
 
 int
-main(int argc, char *argv[]) {
+main(int argc, const char **argv) {
 
-    struct cmdlineInfo cmdline;
-    FILE* ifP;
-    bool eof;   /* no more images in input stream */
+    struct CmdlineInfo cmdline;
+    FILE * ifP;
+    int eof;   /* no more images in input stream */
     struct pam inpam;   /* Input PAM image */
     struct pam outpam;  /* Output PNM image */
 
-    pnm_init(&argc, argv);
+    pm_proginit(&argc, argv);
 
     parseCommandLine(argc, argv, &cmdline);
 
-    ifP = pm_openr(cmdline.inputFilespec);
+    ifP = pm_openr(cmdline.inputFileName);
 
     eof = FALSE;
     while (!eof) {
diff --git a/converter/other/pamtosrf.c b/converter/other/pamtosrf.c
new file mode 100644
index 00000000..3800d77c
--- /dev/null
+++ b/converter/other/pamtosrf.c
@@ -0,0 +1,217 @@
+/*
+ * Convert a Netpbm image to SRF (Garmin vehicle)
+ *
+ * Copyright (C) 2011 by Mike Frysinger <vapier@gentoo.org>
+ *
+ * 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.
+ */
+
+#include <stdio.h>
+
+#include "pm_c_util.h"
+#include "shhopt.h"
+#include "mallocvar.h"
+#include "nstring.h"
+#include "pam.h"
+#include "srf.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 */
+    unsigned int  verbose;
+};
+
+static bool verbose;
+
+
+
+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;
+
+  MALLOCARRAY_NOFAIL(option_def, 100);
+
+  option_def_index = 0;   /* incremented by OPTENT3 */
+  OPTENT3(0, "verbose",          OPT_FLAG,      NULL,
+          &cmdlineP->verbose,    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 (argc-1 < 1)
+    cmdlineP->inputFileName = "-";
+  else if (argc-1 == 1)
+    cmdlineP->inputFileName = argv[1];
+  else
+    pm_error("Program takes at most one argument:  input file name");
+}
+
+
+
+static uint8_t
+srfScale(sample             const unscaled,
+         const struct pam * const pamP) {
+
+    return pnm_scalesample(unscaled, pamP->maxval, 255);
+}
+
+
+
+static uint16_t
+srfColorFromTuple(tuple              const t,
+                  const struct pam * const pamP) {
+
+    unsigned int redPlane, grnPlane, bluPlane;
+
+    if (pamP->depth >= 3) {
+        redPlane = PAM_RED_PLANE;
+        grnPlane = PAM_GRN_PLANE;
+        bluPlane = PAM_BLU_PLANE;
+    } else {
+        redPlane = 0;
+        grnPlane = 0;
+        bluPlane = 0;
+    }
+    return
+        (((srfScale(t[redPlane], pamP) >> 3) & 0x1f) << 11) |
+        (((srfScale(t[grnPlane], pamP) >> 3) & 0x1f) <<  6) |
+        (((srfScale(t[bluPlane], pamP) >> 3) & 0x1f) <<  0);
+}
+
+
+
+static uint8_t
+srfAlphaFromTuple(tuple              const t,
+                  const struct pam * const pamP) {
+
+    uint8_t retval;
+    int haveOpacity;
+    unsigned int opacityPlane;
+
+    pnm_getopacity(pamP, &haveOpacity, &opacityPlane);
+
+    if (haveOpacity) {
+        uint8_t const scaled = srfScale(t[opacityPlane], pamP);
+
+        retval = scaled == 0xff ? SRF_ALPHA_OPAQUE :  128 - (scaled >> 1);
+    } else
+        retval = SRF_ALPHA_OPAQUE;
+
+    return retval;
+}
+
+
+
+static void
+convertRaster(struct pam *     const pamP,
+              struct srf_img * const imgP) {
+
+    tuple * tuplerow;
+    unsigned int row;
+
+    tuplerow = pnm_allocpamrow(pamP);
+
+    for (row = 0; row < pamP->height; ++row) {
+        uint32_t        const off   = row * pamP->width;
+        uint16_t *      const data  = &imgP->data.data[off];
+        unsigned char * const alpha = &imgP->alpha.data[off];
+
+        unsigned int col;
+
+        pnm_readpamrow(pamP, tuplerow);
+
+        for (col = 0; col < pamP->width; ++col) {
+            alpha[col] = srfAlphaFromTuple(tuplerow[col], pamP);
+            data[col]  = srfColorFromTuple(tuplerow[col], pamP);
+        }
+    }
+    pnm_freepamrow(tuplerow);
+}
+
+
+
+static void
+convertImage(FILE *       const ifP,
+             struct srf * const srfP) {
+
+    struct pam inpam;
+
+    pnm_readpaminit(ifP, &inpam, PAM_STRUCT_SIZE(tuple_type));
+
+    if (verbose)
+        pm_message("reading %ux%u image", inpam.width, inpam.height);
+
+    srf_create_img(srfP, inpam.width, inpam.height);
+
+    convertRaster(&inpam, &srfP->imgs[srfP->header.img_cnt-1]);
+}
+
+
+
+int
+main(int argc, const char * argv[]) {
+
+  struct cmdlineInfo cmdline;
+  FILE *             ifP;
+  struct srf         srf;
+  int                eof;   /* No more images in input */
+  unsigned int       imageSeq;
+      /* Sequence of current image in input file.  First = 0 */
+
+  pm_proginit(&argc, argv);
+
+  parseCommandLine(argc, argv, &cmdline);
+
+  verbose = cmdline.verbose;
+
+  ifP = pm_openr(cmdline.inputFileName);
+
+  srf_init(&srf);
+
+  eof = FALSE;
+  for (imageSeq = 0; !eof; ++imageSeq) {
+      if (verbose)
+          pm_message("Converting Image %u", imageSeq);
+
+      convertImage(ifP, &srf);
+
+      pnm_nextimage(ifP, &eof);
+  }
+
+  srf_write(stdout, &srf);
+    
+  srf_term(&srf);
+  pm_closer(ifP);
+
+  return 0;
+}
+
+
+
diff --git a/converter/other/pamtosvg/Makefile b/converter/other/pamtosvg/Makefile
index 8b033020..83f150d0 100644
--- a/converter/other/pamtosvg/Makefile
+++ b/converter/other/pamtosvg/Makefile
@@ -7,26 +7,13 @@ VPATH=.:$(SRCDIR)/$(SUBDIR)
 
 include $(BUILDDIR)/config.mk
 
-BINARIES = pamtosvg
+PORTBINARIES = pamtosvg
 
-PAMTOSVG_OBJECTS = \
-	pamtosvg.o \
-	output-svg.o \
-	fit.o \
-	spline.o \
-	curve.o \
-	vector.o \
-	epsilon-equal.o \
-	autotrace.o \
-	pxl-outline.o \
-	bitmap.o \
-	thin-image.o \
-	logreport.o \
-	exception.o \
-	image-proc.o \
+BINARIES = $(PORTBINARIES)
+
+MERGEBINARIES = $(BINARIES)
 
-MERGE_OBJECTS = \
-	pamtosvg.o2 \
+ADDL_OBJECTS = \
 	output-svg.o \
 	fit.o \
 	spline.o \
@@ -41,15 +28,12 @@ MERGE_OBJECTS = \
 	exception.o \
 	image-proc.o \
 
-OBJECTS = $(PAMTOSVG_OBJECTS)
+OBJECTS = pamtosvg.o $(ADDL_OBJECTS)
 
-MERGEBINARIES = $(BINARIES)
+MERGE_OBJECTS = pamtosvg.o2 $(ADDL_OBJECTS)
 
 all: $(BINARIES)
 
 include $(SRCDIR)/common.mk
 
-pamtosvg: $(PAMTOSVG_OBJECTS) $(NETPBMLIB) $(LIBOPT)
-	$(LD) -o $@ $(PAMTOSVG_OBJECTS) \
-	  $(shell $(LIBOPT) $(NETPBMLIB)) \
-	  $(MATHLIB) $(LDFLAGS) $(LDLIBS) $(RPATH) $(LADD)
+pamtosvg: $(ADDL_OBJECTS)
diff --git a/converter/other/pamtosvg/bitmap.c b/converter/other/pamtosvg/bitmap.c
index 1a00e748..84a8a8ae 100644
--- a/converter/other/pamtosvg/bitmap.c
+++ b/converter/other/pamtosvg/bitmap.c
@@ -59,8 +59,8 @@ at_bitmap_init(unsigned char * area,
             if (bitmap.bitmap == NULL)
                 pm_error("Unable to allocate %u x %u x %u bitmap array",
                          width, height, planes);
-            bzero(bitmap.bitmap,
-                  width * height * planes * sizeof(unsigned char));
+            memset(bitmap.bitmap,
+                   0, width * height * planes * sizeof(unsigned char));
         }
     }
     
diff --git a/converter/other/pamtosvg/bitmap.h b/converter/other/pamtosvg/bitmap.h
index 7334f138..b979e0c0 100644
--- a/converter/other/pamtosvg/bitmap.h
+++ b/converter/other/pamtosvg/bitmap.h
@@ -36,7 +36,7 @@ at_bitmap_type * at_bitmap_new(unsigned short width,
 			       unsigned int planes);
 at_bitmap_type * at_bitmap_copy(at_bitmap_type * src);
 
-/* We have to export functions that supports internal datum 
+/* We have to export functions that allows internal datum 
    access. Such functions might be useful for 
    at_bitmap_new user. */
 unsigned short at_bitmap_get_width (at_bitmap_type * bitmap);
diff --git a/converter/other/pamtosvg/image-proc.c b/converter/other/pamtosvg/image-proc.c
index 287e6384..d025ee1e 100644
--- a/converter/other/pamtosvg/image-proc.c
+++ b/converter/other/pamtosvg/image-proc.c
@@ -52,7 +52,7 @@ new_distance_map(bitmap_type bitmap, unsigned char target_value, bool padded, at
         MALLOCARRAY(dist.d[y], w);
         if (dist.d[y] == NULL)
             pm_error("Unable to get memory for distance map");
-        bzero(dist.d[y], w * sizeof(float));
+        memset(dist.d[y], 0, w * sizeof(float));
         
         MALLOCARRAY(dist.weight[y], w);
         if (dist.weight[y] == NULL)
@@ -330,7 +330,7 @@ binarize(bitmap_type *bitmap)
     }
     else
     {
-	    WARNING1("binarize: %u-plane images are not supported", spp);
+	    WARNING1("binarize: don't know how to interpret %u-plane images", spp);
     }
 }
 
diff --git a/converter/other/pamtosvg/message.h b/converter/other/pamtosvg/message.h
index 0a226206..0d0b9db5 100644
--- a/converter/other/pamtosvg/message.h
+++ b/converter/other/pamtosvg/message.h
@@ -10,10 +10,6 @@
 
 /* Define common sorts of messages.  */
 
-/* This should be called only after a system call fails.  */
-#define FATAL_PERROR(s) do { perror (s); exit (errno); } while (0)
-
-
 #define START_FATAL() do { fputs ("fatal: ", stderr); LOG("fatal: ")
 #define END_FATAL() fputs (".\n", stderr); exit (1); } while (0)
 
@@ -21,12 +17,6 @@
   START_FATAL (); fprintf (stderr, "%s", s); LOG (s); END_FATAL ()
 #define FATAL1(s, e1)							\
   START_FATAL (); fprintf (stderr, s, e1); LOG1 (s, e1); END_FATAL ()
-#define FATAL2(s, e1, e2)						\
-  START_FATAL (); fprintf (stderr, s, e1, e2); LOG2 (s, e1, e2); END_FATAL ()
-#define FATAL3(s, e1, e2, e3)						\
-  START_FATAL (); fprintf (stderr, s, e1, e2, e3); LOG3 (s, e1, e2, e3); END_FATAL ()
-#define FATAL4(s, e1, e2, e3, e4)					\
-  START_FATAL (); fprintf (stderr, s, e1, e2, e3, e4); LOG4 (s, e1, e2, e3, e4); END_FATAL ()
 
 
 #define START_WARNING() do { fputs ("warning: ", stderr); LOG ("warning: ")
@@ -36,12 +26,6 @@
   START_WARNING (); fprintf (stderr, "%s", s); LOG (s); END_WARNING ()
 #define WARNING1(s, e1)							\
   START_WARNING (); fprintf (stderr, s, e1); LOG1 (s, e1); END_WARNING ()
-#define WARNING2(s, e1, e2)						\
-  START_WARNING (); fprintf (stderr, s, e1, e2); LOG2 (s, e1, e2); END_WARNING ()
-#define WARNING3(s, e1, e2, e3)						\
-  START_WARNING (); fprintf (stderr, s, e1, e2, e3); LOG3 (s, e1, e2, e3); END_WARNING ()
-#define WARNING4(s, e1, e2, e3, e4)					\
-  START_WARNING (); fprintf (stderr, s, e1, e2, e3, e4); LOG4 (s, e1, e2, e3, e4); END_WARNING ()
 
 #endif /* not MESSAGE_H */
 
diff --git a/converter/other/pamtosvg/pamtosvg.c b/converter/other/pamtosvg/pamtosvg.c
index dbe67c74..adf76801 100644
--- a/converter/other/pamtosvg/pamtosvg.c
+++ b/converter/other/pamtosvg/pamtosvg.c
@@ -134,8 +134,8 @@ parseCommandLine(int argc,
    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 optParseOptions3 on how to parse our options. */
+    optEntry * option_def;
+    /* Instructions to pm_optParseOptions3 on how to parse our options. */
     optStruct3 opt;
 
     const char * background_colorOpt;
@@ -197,7 +197,7 @@ parseCommandLine(int argc,
     cmdlineP->tangent_surround         = 3;
     cmdlineP->width_weight_factor      = 6.0;
 
-    optParseOptions3( &argc, argv, opt, sizeof(opt), 0 );
+    pm_optParseOptions3( &argc, argv, opt, sizeof(opt), 0 );
     /* Uses and sets argc, argv, and some of *cmdlineP and others. */
 
     if (cmdlineP->backgroundSpec)
@@ -334,7 +334,7 @@ openLogFile(FILE **      const logFileP,
     const char * logfileName;
 
     if (streq(inputFileArg, "-"))
-        asprintfN(&logfileName, "pamtosvg.log");
+        pm_asprintf(&logfileName, "pamtosvg.log");
     else {
         const char * inputRootName;
 
@@ -343,14 +343,14 @@ openLogFile(FILE **      const logFileP,
             pm_error("Can't find the root portion of file name '%s'",
                      inputFileArg);
     
-        asprintfN(&logfileName, "%s.log", inputRootName);
+        pm_asprintf(&logfileName, "%s.log", inputRootName);
 
-        strfree(inputRootName);
+        pm_strfree(inputRootName);
     }
 
     *logFileP = pm_openw(logfileName);
 
-    strfree(logfileName);
+    pm_strfree(logfileName);
 }
     
 
diff --git a/converter/other/pamtosvg/pxl-outline.c b/converter/other/pamtosvg/pxl-outline.c
index a1fa5299..456f41e1 100644
--- a/converter/other/pamtosvg/pxl-outline.c
+++ b/converter/other/pamtosvg/pxl-outline.c
@@ -9,7 +9,6 @@
 
 #include "message.h"
 #include "bitmap.h"
-#include "bitmap.h"
 #include "logreport.h"
 #include "pxl-outline.h"
 
diff --git a/converter/other/pamtosvg/thin-image.c b/converter/other/pamtosvg/thin-image.c
index 40ced794..364f67cc 100644
--- a/converter/other/pamtosvg/thin-image.c
+++ b/converter/other/pamtosvg/thin-image.c
@@ -171,7 +171,7 @@ thin_image(bitmap_type *image, bool bgSpec, pixel bg,
 	    if (PPM_ISGRAY(background))
             bg_color = PPM_GETR(background);
 	    else
-            bg_color = PPM_LUMIN(background);
+            bg_color = ppm_luminosity(background);
 
 	    for (n = num_pixels - 1; n >= 0L; --n)
 	    {
@@ -189,7 +189,7 @@ thin_image(bitmap_type *image, bool bgSpec, pixel bg,
 
 	default:
 	{
-	  LOG1 ("thin_image: %u-plane images are not supported", spp);
+	  LOG1 ("thin_image: Don't know how to interpret %u-plane images", spp);
 	  at_exception_fatal(exp, "thin_image: wrong plane images are passed");
 	  goto cleanup;
 	}
@@ -306,7 +306,7 @@ void thin1(bitmap_type *image, unsigned char colour)
       if (PPM_ISGRAY(background))
           bg_color = PPM_GETR(background);
       else
-          bg_color = PPM_LUMIN(background);
+          bg_color = ppm_luminosity(background);
 
       LOG (" Thinning image.....\n "); 
       xsize = image->width;
diff --git a/converter/other/pamtosvg/vector.c b/converter/other/pamtosvg/vector.c
index 7678f73a..0a5ef3a9 100644
--- a/converter/other/pamtosvg/vector.c
+++ b/converter/other/pamtosvg/vector.c
@@ -1,5 +1,6 @@
 /* vector.c: vector/point operations. */
 
+#define _XOPEN_SOURCE   /* Make sure M_PI is in <math.h> */
 #include <math.h>
 #include <errno.h>
 #include <assert.h>
diff --git a/converter/other/pamtotga.c b/converter/other/pamtotga.c
index c23b92b1..aca93015 100644
--- a/converter/other/pamtotga.c
+++ b/converter/other/pamtotga.c
@@ -74,7 +74,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 */
 
-    optParseOptions3(&argc, argv, opt, sizeof(opt), 0);
+    pm_optParseOptions3(&argc, argv, opt, sizeof(opt), 0);
         /* Uses and sets argc, argv, and some of *cmdline_p and others. */
 
     if (cmap + mono + rgb > 1)
@@ -463,7 +463,7 @@ static void
 releaseTgaHeader(struct ImageHeader const tgaHeader) {
 
     if (tgaHeader.IdLength > 0)
-        strfree(tgaHeader.Id);
+        pm_strfree(tgaHeader.Id);
 }
 
 
@@ -567,7 +567,7 @@ main(int argc, char *argv[]) {
         pnm_freetupletable(&pam, chv);
 
     releaseTgaHeader(tgaHeader);
-    strfree(outName);
+    pm_strfree(outName);
     pnm_freepamarray(tuples, &pam);
 
     return 0;
diff --git a/converter/other/pamtotiff.c b/converter/other/pamtotiff.c
index 1b31c65b..7b645b23 100644
--- a/converter/other/pamtotiff.c
+++ b/converter/other/pamtotiff.c
@@ -27,12 +27,6 @@
 #include <unistd.h>
 #include <stdio.h>
 #include <fcntl.h>
-#ifdef VMS
-#ifdef SYSV
-#undef SYSV
-#endif
-#include <tiffioP.h>
-#endif
 /* tiffio.h has a weird problem on AIX.  tiffio.h wrongly typedefs
    "int32".  That's wrong because such a name is likely to be used in
    other parts of the program that includes tiffio.h.  And in fact, on
@@ -59,16 +53,19 @@
 #define COMPRESSION_ADOBE_DEFLATE 8
 #endif
 
-struct sizeset {
+typedef struct {
     bool b1, b2, b4, b8;
-};
+} SizeSet;
+
+typedef enum { TMPFILE, DIRECT_CREATE, DIRECT_APPEND } WriteMethod;
 
+typedef enum { MUST_EXIST, MAY_CREATE } CreatePolicy;
 
-struct cmdlineInfo {
+typedef struct {
     /* All the information the user supplied in the command line,
        in a form easy for the program to use.
     */
-    const char *input_filespec;  /* Filespecs of input files */
+    const char * inputFileName;
     int compression;
         /* COMPRESSION Tiff tag value, that corresponds to the compression
            option the user specified, or -1 if he didn't specify any.
@@ -84,14 +81,15 @@ struct cmdlineInfo {
     unsigned int color;        /* logical: assume not grayscale */
     float xresolution; /* XRESOLUTION Tiff tag value or -1 for none */
     float yresolution; /* YRESOLUTION Tiff tag value or -1 for none */
-    int resolutionUnit;  /* RESOLUTIONUNIT Tiff tag value */
-    struct sizeset indexsizeAllowed;
+    int resolutionunit;  /* RESOLUTIONUNIT Tiff tag value */
+    SizeSet indexsizeAllowed;
     /* Which bit widths are allowable in a raster of palette indices */
     unsigned int verbose;
-    unsigned int append;
+    WriteMethod writeMethod;  /* Output mode */
+    const char * output; /* -output option value.  NULL if none. */
     float resolution;  /* X and Y resolution */
     struct optNameValue * taglist;
-};
+} CmdlineInfo;
 
 
 
@@ -102,7 +100,7 @@ validateTagList(struct optNameValue const taglist[]) {
     for (i = 0; taglist[i].name; ++i) {
         const char * const tagName = taglist[i].name;
         const tagDefinition * tagDefP = tagDefFind(tagName);
-        
+
         if (!tagDefP)
             pm_error("Unknown tag name '%s'", tagName);
         else {
@@ -137,9 +135,9 @@ validateTagList(struct optNameValue const taglist[]) {
 
 
 static void
-parseCommandLine(int                        argc,
-                 char **              const argv,
-                 struct cmdlineInfo * const cmdlineP) {
+parseCommandLine(int                 argc,
+                 const char ** const argv,
+                 CmdlineInfo * const cmdlineP) {
 /*----------------------------------------------------------------------------
    Note that the file spec array we return is stored in the storage that
    was passed to us as the argv array.
@@ -151,10 +149,11 @@ parseCommandLine(int                        argc,
     unsigned int none, packbits, lzw, g3, g4, msb2lsb, lsb2msb, opt_2d, fill;
     unsigned int flate, adobeflate;
     char * indexbits;
-    char * resolutionUnit;
+    char * resolutionunit;
 
-    unsigned int predictorSpec, rowsperstripSpec, xresolutionSpec,
-        yresolutionSpec, indexbitsSpec, resolutionUnitSpec, tagSpec;
+    unsigned int appendSpec, outputSpec, predictorSpec, rowsperstripSpec,
+                 xresolutionSpec, yresolutionSpec, indexbitsSpec,
+      resolutionunitSpec, tagSpec;
 
     unsigned int option_def_index;
 
@@ -162,7 +161,6 @@ parseCommandLine(int                        argc,
 
     option_def_index = 0;   /* incremented by OPTENT3 */
     OPTENT3(0, "verbose",      OPT_FLAG,   NULL, &cmdlineP->verbose,       0);
-    OPTENT3(0, "append",       OPT_FLAG,   NULL, &cmdlineP->append,        0);
     OPTENT3(0, "none",         OPT_FLAG,   NULL, &none,                    0);
     OPTENT3(0, "packbits",     OPT_FLAG,   NULL, &packbits,                0);
     OPTENT3(0, "lzw",          OPT_FLAG,   NULL, &lzw,                     0);
@@ -180,17 +178,20 @@ parseCommandLine(int                        argc,
     OPTENT3(0, "mw",           OPT_FLAG,   NULL, &cmdlineP->miniswhite,    0);
     OPTENT3(0, "truecolor",    OPT_FLAG,   NULL, &cmdlineP->truecolor,     0);
     OPTENT3(0, "color",        OPT_FLAG,   NULL, &cmdlineP->color,         0);
-    OPTENT3(0, "predictor",    OPT_UINT,   &cmdlineP->predictor,    
+    OPTENT3(0, "append",       OPT_FLAG,   NULL, &appendSpec,       0);
+    OPTENT3(0, "output",       OPT_STRING, &cmdlineP->output,
+            &outputSpec,       0);
+    OPTENT3(0, "predictor",    OPT_UINT,   &cmdlineP->predictor,
             &predictorSpec,    0);
-    OPTENT3(0, "rowsperstrip", OPT_UINT,   &cmdlineP->rowsperstrip, 
+    OPTENT3(0, "rowsperstrip", OPT_UINT,   &cmdlineP->rowsperstrip,
             &rowsperstripSpec, 0);
-    OPTENT3(0, "xresolution",  OPT_FLOAT,  &cmdlineP->xresolution,  
+    OPTENT3(0, "xresolution",  OPT_FLOAT,  &cmdlineP->xresolution,
             &xresolutionSpec,  0);
-    OPTENT3(0, "yresolution",  OPT_FLOAT,  &cmdlineP->yresolution,  
+    OPTENT3(0, "yresolution",  OPT_FLOAT,  &cmdlineP->yresolution,
             &yresolutionSpec,  0);
-    OPTENT3(0, "resolutionunit", OPT_STRING, &resolutionUnit,
-            &resolutionUnitSpec,    0);
-    OPTENT3(0, "indexbits",    OPT_STRING,   &indexbits, 
+    OPTENT3(0, "resolutionunit", OPT_STRING, &resolutionunit,
+            &resolutionunitSpec,    0);
+    OPTENT3(0, "indexbits",    OPT_STRING,   &indexbits,
             &indexbitsSpec,    0);
     OPTENT3(0, "tag",          OPT_NAMELIST, &cmdlineP->taglist, &tagSpec, 0);
 
@@ -198,14 +199,14 @@ parseCommandLine(int                        argc,
     opt.short_allowed = FALSE;  /* We have no short (old-fashioned) options */
     opt.allowNegNum = FALSE;  /* We have no parms that are negative numbers */
 
-    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 (none + packbits + lzw + g3 + g4 + flate + adobeflate > 1)
         pm_error("You specified more than one compression option.  "
                  "Only one of -none, -packbits, -lze, -g3, and -g4 "
                  "is allowed.");
-    
+
     if (none)
         cmdlineP->compression = COMPRESSION_NONE;
     else if (packbits)
@@ -222,7 +223,7 @@ parseCommandLine(int                        argc,
         cmdlineP->compression = COMPRESSION_DEFLATE;
     else
         cmdlineP->compression = COMPRESSION_NONE;
-    
+
     if (msb2lsb + lsb2msb > 1)
         pm_error("You specified both -msb2lsb and -lsb2msb.  "
                  "These are conflicting options.");
@@ -231,9 +232,9 @@ parseCommandLine(int                        argc,
         cmdlineP->fillorder = FILLORDER_MSB2LSB;
     else if (lsb2msb)
         cmdlineP->fillorder = FILLORDER_LSB2MSB;
-    else 
+    else
         cmdlineP->fillorder = FILLORDER_MSB2LSB;
-    
+
 
     if (cmdlineP->miniswhite && cmdlineP->minisblack)
         pm_error("You cannot specify both -miniswhite and -minisblack");
@@ -244,9 +245,17 @@ parseCommandLine(int                        argc,
     if (fill)
         cmdlineP->g3options |= GROUP3OPT_FILLBITS;
 
+    if (outputSpec) {
+        if (appendSpec)
+            cmdlineP->writeMethod = DIRECT_APPEND;
+        else
+            cmdlineP->writeMethod = DIRECT_CREATE;
+    } else
+        cmdlineP->writeMethod = TMPFILE;
+
     if (predictorSpec) {
         if (cmdlineP->predictor != 1 && cmdlineP->predictor != 2)
-            pm_error("-predictor may be only 1 or 2.  You specified %d.", 
+            pm_error("-predictor may be only 1 or 2.  You specified %d.",
                      cmdlineP->predictor);
     } else
         cmdlineP->predictor = -1;
@@ -272,25 +281,25 @@ parseCommandLine(int                        argc,
     } else
         cmdlineP->yresolution = -1;
 
-    if (resolutionUnitSpec) {
-        if (streq(resolutionUnit, "inch"))
-            cmdlineP->resolutionUnit = RESUNIT_INCH;
-        else if (streq(resolutionUnit, "in"))
-            cmdlineP->resolutionUnit = RESUNIT_INCH;
-        else if (streq(resolutionUnit, "centimeter"))
-            cmdlineP->resolutionUnit = RESUNIT_CENTIMETER;
-        else if (streq(resolutionUnit, "cm"))
-            cmdlineP->resolutionUnit = RESUNIT_CENTIMETER;
-        else if (streq(resolutionUnit, "none"))
-            cmdlineP->resolutionUnit = RESUNIT_NONE;
-        else if (streq(resolutionUnit, "no"))
-            cmdlineP->resolutionUnit = RESUNIT_NONE;
+    if (resolutionunitSpec) {
+        if (streq(resolutionunit, "inch"))
+            cmdlineP->resolutionunit = RESUNIT_INCH;
+        else if (streq(resolutionunit, "in"))
+            cmdlineP->resolutionunit = RESUNIT_INCH;
+        else if (streq(resolutionunit, "centimeter"))
+            cmdlineP->resolutionunit = RESUNIT_CENTIMETER;
+        else if (streq(resolutionunit, "cm"))
+            cmdlineP->resolutionunit = RESUNIT_CENTIMETER;
+        else if (streq(resolutionunit, "none"))
+            cmdlineP->resolutionunit = RESUNIT_NONE;
+        else if (streq(resolutionunit, "no"))
+            cmdlineP->resolutionunit = RESUNIT_NONE;
         else
             pm_error("The only acceptable values for -resolutionunit are "
                      "inch, centimeter, none, in, cm, and no.  "
-                     "You specified '%s'.", resolutionUnit);
+                     "You specified '%s'.", resolutionunit);
     } else
-        cmdlineP->resolutionUnit = RESUNIT_INCH;
+        cmdlineP->resolutionunit = RESUNIT_INCH;
 
     if (indexbitsSpec) {
         if (strstr(indexbits, "1"))
@@ -324,46 +333,18 @@ parseCommandLine(int                        argc,
         cmdlineP->taglist[0].value = NULL;
     }
 
-    if (argc-1 == 0) 
-        cmdlineP->input_filespec = "-";
+    if (argc-1 == 0)
+        cmdlineP->inputFileName = "-";
     else if (argc-1 != 1)
         pm_error("Program takes zero or one argument (filename).  You "
                  "specified %d", argc-1);
     else
-        cmdlineP->input_filespec = argv[1];
+        cmdlineP->inputFileName = argv[1];
 }
 
 
 
 static void
-putSample(sample           const s,
-          sample           const maxval,
-          sample           const tiff_maxval,
-          unsigned int     const bitspersample,
-          unsigned char ** const tPP) {
-
-    xelval s2;
-
-    s2 = s;
-    if (maxval != tiff_maxval)
-        s2 = s * tiff_maxval / maxval;
-    if (bitspersample > 8) {
-        *((unsigned short *)(*tPP)) = s2;
-        (*tPP) += sizeof(short);
-    } else
-        *(*tPP)++ = s2 & 0xff;
-}
-
-
-
-
-/* Note: PUTSAMPLE doesn't work if bitspersample is 1-4. */
-
-#define PUTSAMPLE putSample(s, maxval, tiff_maxval, bitspersample, &tP);
-
-
-
-static void
 fillRowOfSubBytePixels(struct pam *    const pamP,
                        const tuple *   const tuplerow,
                        unsigned char * const buf,
@@ -380,9 +361,9 @@ fillRowOfSubBytePixels(struct pam *    const pamP,
     int bitshift;
         /* The number of bits we have to shift a pixel value left to line
            it up with where the current pixel goes in the current byte of
-           the output buffer.  
+           the output buffer.
         */
-    int const firstbitshift = 
+    int const firstbitshift =
         (fillorder == FILLORDER_MSB2LSB) ? 8 - bitspersample : 0;
         /* The value of 'bitshift' for the first pixel into a
            byte of the output buffer.  (MSB2LSB is normal).
@@ -397,7 +378,7 @@ fillRowOfSubBytePixels(struct pam *    const pamP,
         /* The under-construction value of the byte pointed to by
            tP, above.
         */
-                
+
     bitshift = firstbitshift;
     byte = 0;
     for (col = 0, tP = buf; col < pamP->width; ++col) {
@@ -406,7 +387,7 @@ fillRowOfSubBytePixels(struct pam *    const pamP,
             s = tuplerow[col][0];
             if (pamP->maxval != tiff_maxval )
                 s = (long) s * tiff_maxval / pamP->maxval;
- 
+
             if (photometric == PHOTOMETRIC_MINISWHITE)
                 s = tiff_maxval - s;
         } else {
@@ -440,6 +421,36 @@ fillRowOfSubBytePixels(struct pam *    const pamP,
 
 
 static void
+putSample(sample           const s,
+          sample           const maxval,
+          sample           const tiffMaxval,
+          unsigned int     const bitspersample,
+          bool             const minIsWhite,
+          unsigned char ** const tPP) {
+
+    /* Until release 10.48 (September 2009), we ignored the min-is-white
+       photometric (i.e. treated it like min-is-black).  Nobody has ever
+       complained, but it seems clear to me that that was wrong, so I
+       changed it.  We have always respected it for sub-byte samples,
+       and have always respected it going the other direction, in
+       Tifftopnm.
+       - Bryan.
+    */
+
+    xelval const s2 = maxval == tiffMaxval ? s : s * tiffMaxval / maxval;
+
+    xelval const s3 = minIsWhite ? tiffMaxval - s2 : s2;
+
+    if (bitspersample > 8) {
+        *((unsigned short *)(*tPP)) = s3;
+        (*tPP) += sizeof(short);
+    } else
+        *(*tPP)++ = s3 & 0xff;
+}
+
+
+
+static void
 fillRowOfWholeBytePixels(struct pam *    const pamP,
                          tuple *         const tuplerow,
                          unsigned char * const buf,
@@ -447,10 +458,12 @@ fillRowOfWholeBytePixels(struct pam *    const pamP,
                          unsigned short  const tiffMaxval,
                          unsigned int    const bitsPerSample) {
 
+    bool const minIsWhite = (photometric == PHOTOMETRIC_MINISWHITE);
+
     unsigned int col;
     unsigned char * tP;
     unsigned int planes;
-    
+
     if (photometric == PHOTOMETRIC_RGB)
         planes = pamP->depth;
     else
@@ -463,22 +476,22 @@ fillRowOfWholeBytePixels(struct pam *    const pamP,
         unsigned int plane;
         for (plane = 0; plane < planes; ++plane) {
             putSample(tuplerow[col][plane], pamP->maxval,
-                      tiffMaxval, bitsPerSample, &tP);
+                      tiffMaxval, bitsPerSample, minIsWhite, &tP);
             /* Advances tP */
         }
     }
-} 
+}
 
 
 
 static void
 writeScanLines(struct pam *   const pamP,
-               TIFF *         const tif, 
+               TIFF *         const tif,
                tuplehash      const cht,
                unsigned short const tiffMaxval,
-               unsigned short const bitspersample, 
+               unsigned short const bitspersample,
                unsigned short const photometric,
-               int            const bytesperrow, 
+               int            const bytesperrow,
                int            const fillorder) {
 /*----------------------------------------------------------------------------
    Write out the raster for the input image described by 'pamP', whose
@@ -492,15 +505,19 @@ writeScanLines(struct pam *   const pamP,
        it's 'buf' parameter, but here it is: Its format depends on the
        bits per pixel of the TIFF image.  If it's 16, 'buf' is an
        array of short (16 bit) integers, one per raster column.  If
-       it's 8, 'buf' is an array of characters (8 bit integers), one
-       per image column.  If it's less than 8, it's an array of characters,
-       each of which represents 1-8 raster columns, packed
+       it's 8, 'buf' is an array of 8 bit unsigned integers, one
+       per pixel sample.  If it's less than 8, it's an array of bytes,
+       each of which represents 1-8 pixel samples, packed
        into it in the order specified by the TIFF image's fill order,
        with don't-care bits on the right such that each byte contains only
-       whole pixels.
+       whole samples.
 
        In all cases, the array elements are in order left to right going
        from low array indices to high array indices.
+
+       The samples form pixel values according to the pixel format indicated
+       by the TIFF photometric.  E.g. if it is MINISWHITE, then a pixel is
+       one sample and a value of 0 for that sample means white.
     */
     MALLOCARRAY(buf, bytesperrow);
 
@@ -508,7 +525,7 @@ writeScanLines(struct pam *   const pamP,
         pm_error("can't allocate memory for row buffer");
 
     tuplerow = pnm_allocpamrow(pamP);
-    
+
     for (row = 0; row < pamP->height; ++row) {
         int col;
 
@@ -530,9 +547,9 @@ writeScanLines(struct pam *   const pamP,
                 for (col = 0; col < pamP->width; ++col) {
                     int si;
                     int found;
-                    
+
                     pnm_lookuptuple(pamP, cht, tuplerow[col], &found, &si);
-                    
+
                     if (!found)
                         pm_error("INTERNAL ERROR.  We made a color map, and a "
                                  "color map we need is not in it!  "
@@ -556,12 +573,12 @@ writeScanLines(struct pam *   const pamP,
 
 
 static void
-analyzeColorsInRgbInput(struct pam *        const pamP,
-                        struct cmdlineInfo  const cmdline,
-                        int                 const maxcolors, 
-                        tupletable *        const chvP, 
-                        unsigned int *      const colorsP, 
-                        bool *              const grayscaleP) {
+analyzeColorsInRgbInput(struct pam *   const pamP,
+                        CmdlineInfo    const cmdline,
+                        int            const maxcolors,
+                        tupletable *   const chvP,
+                        unsigned int * const colorsP,
+                        bool *         const grayscaleP) {
 /*----------------------------------------------------------------------------
    Same as analyzeColors(), except assuming input image has R/G/B tuples.
 -----------------------------------------------------------------------------*/
@@ -580,7 +597,7 @@ analyzeColorsInRgbInput(struct pam *        const pamP,
             grayscale = FALSE;
         } else {
             unsigned int i;
-            pm_message("%u color%s found", 
+            pm_message("%u color%s found",
                        *colorsP, *colorsP == 1 ? "" : "s");
             grayscale = TRUE;  /* initial assumption */
             for (i = 0; i < *colorsP && grayscale; ++i) {
@@ -613,15 +630,15 @@ analyzeColorsInRgbInput(struct pam *        const pamP,
 
 
 static void
-analyzeColors(struct pam *        const pamP,
-              struct cmdlineInfo  const cmdline,
-              int                 const maxcolors, 
-              tupletable *        const chvP, 
-              unsigned int *      const colorsP, 
-              bool *              const grayscaleP) {
+analyzeColors(struct pam *   const pamP,
+              CmdlineInfo    const cmdline,
+              int            const maxcolors,
+              tupletable *   const chvP,
+              unsigned int * const colorsP,
+              bool *         const grayscaleP) {
 /*----------------------------------------------------------------------------
    Analyze the colors in the input image described by 'pamP', whose file
-   is positioned to the raster. 
+   is positioned to the raster.
 
    If the colors, combined with command line options 'cmdline', indicate
    a colormapped TIFF should be generated, return as *chvP the address
@@ -650,13 +667,13 @@ analyzeColors(struct pam *        const pamP,
 
 static void
 computeRasterParm(struct pam *     const pamP,
-                  tupletable       const chv, 
-                  int              const colors, 
+                  tupletable       const chv,
+                  int              const colors,
                   bool             const grayscale,
                   int              const compression,
                   bool             const minisblack,
                   bool             const miniswhite,
-                  struct sizeset   const indexsizeAllowed,
+                  SizeSet          const indexsizeAllowed,
                   unsigned short * const samplesperpixelP,
                   unsigned short * const bitspersampleP,
                   unsigned short * const photometricP,
@@ -677,7 +694,7 @@ computeRasterParm(struct pam *     const pamP,
        option.  It is not clear why we don't use bits per pixel < 8
        for RGB images.  Note that code to handle maxvals <= 255 was
        written long before maxval > 255 was possible and there are
-       backward compatibility requirements.  
+       backward compatibility requirements.
     */
 
     if (pamP->depth == 1 && pamP->maxval == 1) {
@@ -691,7 +708,7 @@ computeRasterParm(struct pam *     const pamP,
     } else {
         if (chv) {
             *samplesperpixelP = 1;  /* Pixel is just the one index value */
-            *bitspersampleP = 
+            *bitspersampleP =
                 colors <=   2 && indexsizeAllowed.b1 ? 1 :
                 colors <=   4 && indexsizeAllowed.b2 ? 2 :
                 colors <=  16 && indexsizeAllowed.b4 ? 4 :
@@ -744,18 +761,53 @@ computeRasterParm(struct pam *     const pamP,
 
 
 
-static void
-validateSeekableOutputFile(int          const ofd,
-                           const char * const outFileName) {
 /*----------------------------------------------------------------------------
-   Validate that the file attached to file descriptor 'ofd' is capable
-   of seeking.  If not, fail the program.
+  WRITE MODES
+  -----------
+  
+  The Tiff library does all output.  There are several issues:
+  
+    1) The manner of output is opaque to the library client.  I.e.  we cannot
+       see or control it.
+
+    2) The output file must be random-access.
+
+    3) The output file must be writable and readable for multiple-image
+       streams.  (This includes append operations.)
+
+    4) The Tiff library produces unhelpful error messages when the above
+       conditions are not met.
+  
+  We provide two modes for output:
+  
+  1. Tmpfile mode (default)
+  
+     We have the Tiff library direct output to an unnamed temporary file we
+     create which is seekable and readable.  When output is complete, we copy
+     the file's contents to Standard Output.
+  
+  2. Direct mode (specified with -output)
+  
+     We have the Tiff library write output to the specified file.  As the Tiff
+     library requires taht it be be seekable and readable, we fail the program
+     rather than ask the Tiff library to use the file if it does not meet
+     these requirements.
+  
+     Direct mode is further divided into append and create.  They are the same
+     except that in append mode, we insist that the file already exist,
+     whereas with create mode, we create it if necessary.  In either case, if
+     the file already exists, he Tiff library appends the output to it.
+-----------------------------------------------------------------------------*/
+
 
-   This is useful because the TIFF library requires seekable output and
-   fails with an unhelpful error message about a file I/O error if it is
-   not.  We, on the other hand, give a helpful error message.
 
-   We leave the file positioned to the beginning.
+static bool
+fileIsSeekable(int          const ofd,
+               const char * const outFileName) {
+/*----------------------------------------------------------------------------
+  The file represented by 'ofd' iscapable of seeking.
+
+  As a side effect, we position the file to the beginning.
 -----------------------------------------------------------------------------*/
     int rc;
 
@@ -769,44 +821,170 @@ validateSeekableOutputFile(int          const ofd,
     */
     lseek(ofd, 1, SEEK_SET);
     rc = lseek(ofd, 0, SEEK_SET);
-            
-    if (rc < 0)
-        pm_error("Output file (%s) is not seekable.  lseek() returned "
-                 "errno %d (%s).  "
-                 "The TIFF library can write only to "
-                 "a seekable file.", 
-                 outFileName, errno, strerror(errno));
+
+    return rc >= 0;
+
+}
+
+
+
+static void
+validateReadableOutputFile(int const ofd) {
+/*----------------------------------------------------------------------------
+  Validate that file 'ofd' is readable and fail the program if it isn't.
+
+  This is useful because there are situations in which the TIFF library must
+  read the output file and if it can't, it fails with an unhelpful error
+  message about a file I/O error.  We, on the other hand, produce a helpful
+  error message.
+-----------------------------------------------------------------------------*/
+#if !MSVCRT
+
+    int flags;
+
+    flags = fcntl(ofd, F_GETFL);
+
+    if (flags < 0) {
+        /* We couldn't get the flags.  So just assume the file's OK */
+    } else {
+        if ((flags & O_RDONLY) || (flags & O_RDWR)) {
+            /* File is readable.  All is well. */
+        } else
+            pm_error("Output is not opened for reading.  "
+                     "In order to create a multi-image TIFF stream, "
+                     "output must be both readable and writable.");
+    }
+#endif
 }
 
 
 
 static void
-createTiffGenerator(int          const ofd, 
-                    const char * const outFileName,
-                    bool         const append,
-                    TIFF **      const tifPP) {
+createTiffGeneratorDirect(const char * const outputFileName,
+                          CreatePolicy const createPolicy,
+                          TIFF **      const tifPP,
+                          int  *       const ofdP) {
+/*----------------------------------------------------------------------------
+  Create a TIFF generator that writes its output to the specified file.
 
-    const char * option;
+  If the file doesn't already exist and 'createPolicy' is MayCreate,
+  create the file; otherwise fail the program.
 
-    validateSeekableOutputFile(ofd, outFileName);
+  Fail the program if the specified file is not seekable and readable.
 
-    if (append)
-        option = "a";
+  Return the handle of the TIFF generator as *tifPP.  Also return the
+  file descriptor for the output file as *ofdP.
+-----------------------------------------------------------------------------*/
+    int fd;
+
+    if (createPolicy == MUST_EXIST)
+        fd = open(outputFileName, O_RDWR);
     else
-        option = "w";
+        fd = open(outputFileName, (O_RDWR | O_CREAT), 00644);
+
+    if (fd == -1) {
+        if (errno == ENOENT) /* Possible only if MustExist */
+            pm_error ("Cannot open file : '%s'.  File does not exist.",
+                      outputFileName);
+        else
+            pm_error ("Cannot open file : '%s'.  open() failed with "
+                      "errno %d (%s).  ",
+                      outputFileName, errno, strerror(errno));
+    }
 
-    *tifPP = TIFFFdOpen(ofd, outFileName, option);
+    if (!fileIsSeekable(fd, outputFileName))
+        pm_error("Output file (%s) is not seekable.  "
+                 "lseek() returned errno %d (%s).  "
+                 "The TIFF library can write only to "
+                 "a seekable file.",
+                 outputFileName, errno, strerror(errno));
+
+    *tifPP = TIFFFdOpen(fd, outputFileName, "a");
     if (*tifPP == NULL)
-        pm_error("error opening standard output as TIFF file.  "
+        pm_error("error opening file %s as TIFF file.  "
+                 "TIFFFdOpen() failed.", outputFileName);
+
+    *ofdP = fd;
+}
+
+
+
+static void
+createTiffGeneratorTmpfile(TIFF ** const tifPP,
+                            int  * const ofdP) {
+/*----------------------------------------------------------------------------
+  Create a TIFF generator that writes its output to an unnnamed temporary file
+  we create.
+
+  Return the handle of the TIFF generator as *tifPP.  Also return the file
+  descriptor for the temporary file as *ofdP.
+
+  The TIFF generator has a file name attribute, but it is just for messages;
+  it is not the name of a file.  We use "Internal Temporary File".
+-----------------------------------------------------------------------------*/
+    int fd;
+
+    fd = pm_tmpfile_fd();
+
+    *tifPP = TIFFFdOpen(fd, "Internal Temporary File", "w");
+
+    if (*tifPP == NULL)
+        pm_error("error opening temporary file as TIFF file.  "
                  "TIFFFdOpen() failed.");
+
+    *ofdP = fd;
+}
+
+
+
+static void
+copyBufferToStdout(int const tmpfileFd) {
+
+    FILE * tmpfileP;
+
+    tmpfileP = fdopen(tmpfileFd, "rb");
+
+    fseek(tmpfileP, 0, SEEK_SET);
+
+    while (!feof(tmpfileP) && !ferror(tmpfileP) && !ferror(stdout)) {
+        char buffer[4096];
+        size_t bytesReadCt;
+
+        bytesReadCt = fread(buffer, 1, sizeof(buffer), tmpfileP);
+
+        if (ferror(tmpfileP))
+            pm_error("Error reading from temporary file.  "
+                     "Incomplete output.  "
+                     "Errno = %s (%d)", strerror(errno), errno);
+        else
+            fwrite(buffer, 1, bytesReadCt, stdout);
+    }
+
+    /* POSIX lets us create a FILE from an existing file descriptor, but
+       does not provide a way to destroy the FILE and keep the file
+       descriptor.  The following fclose() closes the file.  Caller
+       must not access the file again, and if he attempts to close it,
+       must ignore the failure of close
+    */
+    fclose(tmpfileP);
 }
 
 
 
 static void
-destroyTiffGenerator(TIFF * const tifP) {
+destroyTiffGenerator(WriteMethod const writeMethod,
+                     TIFF *      const tifP,
+                     int         const ofd) {
 
     TIFFFlushData(tifP);
+
+    if (writeMethod == TMPFILE)
+        copyBufferToStdout(ofd);
+
+    /* If we copied the buffer above, the buffer file is already closed
+       (copyBufferToStdout closes it), TIFFClose appears to tolerate that -
+       all it does is a close() and doesn't mind that it fails.
+    */
     TIFFClose(tifP);
 }
 
@@ -823,11 +1001,11 @@ createTiffColorMap(struct pam *       const pamP,
     unsigned short ** tiffColorMap;
     unsigned int plane;
     unsigned int i;
-    
+
     MALLOCARRAY_NOFAIL(tiffColorMap, pamP->depth);
     for (plane = 0; plane < pamP->depth; ++plane)
         MALLOCARRAY_NOFAIL(tiffColorMap[plane], colorMapSize);
-    
+
     for (i = 0; i < colorMapSize; ++i) {
         unsigned int plane;
         for (plane = 0; plane < pamP->depth; ++plane) {
@@ -840,7 +1018,7 @@ createTiffColorMap(struct pam *       const pamP,
     }
     *tiffColorMapP = tiffColorMap;
 }
-        
+
 
 
 static void
@@ -865,7 +1043,7 @@ setTagListFields(const struct optNameValue * const taglist,
 
     for (i = 0; taglist[i].name; ++i) {
         const tagDefinition * const tagDefP = tagDefFind(taglist[i].name);
-        
+
         if (tagDefP->put)
             tagDefP->put(tifP, tagDefP->tagnum, taglist[i].value,
                          tagDefP->choices);
@@ -876,7 +1054,7 @@ setTagListFields(const struct optNameValue * const taglist,
 
 static void
 setTiffFields(TIFF *              const tifP,
-              struct cmdlineInfo  const cmdline,
+              CmdlineInfo         const cmdline,
               struct pam *        const pamP,
               unsigned short      const bitspersample,
               unsigned short      const photometric,
@@ -911,12 +1089,17 @@ setTiffFields(TIFF *              const tifP,
     else
         TIFFSetField(tifP, TIFFTAG_ROWSPERSTRIP,
                      TIFFDefaultStripSize(tifP, 0));
+    /* Since Netpbm 10.31, we prefer that the user use -tags to specify
+       RESOLUTIONUNIT, XRESOLUTION, and YRESOLUTION, but retain
+       -xresolution, -yresolution, and -resolutionunit for backward
+       compatibility
+    */
     if (cmdline.xresolution != -1 ||
         cmdline.yresolution != -1 ||
-        cmdline.resolutionUnit != -1) {
+        cmdline.resolutionunit != -1) {
         TIFFSetField(tifP, TIFFTAG_RESOLUTIONUNIT,
-                     cmdline.resolutionUnit != -1 ?
-                     cmdline.resolutionUnit : RESUNIT_NONE);
+                     cmdline.resolutionunit != -1 ?
+                     cmdline.resolutionunit : RESUNIT_NONE);
     }
     if (cmdline.xresolution > 0)
         TIFFSetField(tifP, TIFFTAG_XRESOLUTION, cmdline.xresolution);
@@ -933,7 +1116,7 @@ setTiffFields(TIFF *              const tifP,
 
     TIFFSetField(tifP, TIFFTAG_DOCUMENTNAME,     inputFileDescription);
     TIFFSetField(tifP, TIFFTAG_IMAGEDESCRIPTION, "converted PNM file");
- 
+
     /* Some of taglist[] overrides defaults we set above.  But taglist[]
        is defined not to specify any tag types that are not purely user
        choice.
@@ -944,10 +1127,10 @@ setTiffFields(TIFF *              const tifP,
 
 
 static void
-convertImage(FILE *             const ifP,
-             TIFF *             const tifP,
-             const char *       const inputFileDescription,
-             struct cmdlineInfo const cmdline) {
+convertImage(FILE *       const ifP,
+             TIFF *       const tifP,
+             const char * const inputFileDescription,
+             CmdlineInfo  const cmdline) {
 
     tupletable chv;
     tuplehash cht;
@@ -959,7 +1142,7 @@ convertImage(FILE *             const ifP,
     unsigned short samplesperpixel;
     unsigned short bitspersample;
     unsigned short tiff_maxval;
-    /* This is the maxval of the samples in the tiff file.  It is 
+    /* This is the maxval of the samples in the tiff file.  It is
        determined solely by the bits per sample ('bitspersample').
        */
     int bytesperrow;
@@ -972,11 +1155,11 @@ convertImage(FILE *             const ifP,
     analyzeColors(&pam, cmdline, MAXCOLORS, &chv, &colors, &grayscale);
 
     /* Go back to beginning of raster */
-    pm_seek2(ifP, &rasterPos, sizeof(rasterPos));  
+    pm_seek2(ifP, &rasterPos, sizeof(rasterPos));
 
     /* Figure out TIFF parameters. */
 
-    computeRasterParm(&pam, chv, colors, grayscale, 
+    computeRasterParm(&pam, chv, colors, grayscale,
                       cmdline.compression,
                       cmdline.minisblack, cmdline.miniswhite,
                       cmdline.indexsizeAllowed,
@@ -1001,7 +1184,7 @@ convertImage(FILE *             const ifP,
                   cmdline.taglist);
 
     writeScanLines(&pam, tifP, cht,
-                   tiff_maxval, bitspersample, photometric, bytesperrow, 
+                   tiff_maxval, bitspersample, photometric, bytesperrow,
                    cmdline.fillorder);
 
     if (tiffColorMap)
@@ -1010,63 +1193,41 @@ convertImage(FILE *             const ifP,
 
 
 
-static void
-validateReadableStdout(void) {
-/*----------------------------------------------------------------------------
-  We validate that Standard Output is readable and fail the program if
-  it isn't.
-
-  This is useful because there are situations in which the TIFF library
-  must read the output file and if it can't, it fails with an unhelpful
-  error message about a file I/O error.  We, on the other hand, produce
-  a helpful error message.
------------------------------------------------------------------------------*/
-#if !defined(WIN32) || defined(__CYGWIN__)
-
-    int flags;
-
-    flags = fcntl(STDOUT_FILENO, F_GETFL);
-
-    if (flags < 0) {
-        /* We couldn't get the flags.  So just assume the file's OK */
-    } else {
-        if ((flags & O_RDONLY) || (flags & O_RDWR)) {
-            /* File is readable.  All is well. */
-        } else
-            pm_error("Standard Output is not opened for reading.  "
-                     "In order to create a multi-image TIFF stream, "
-                     "Standard Output must be both readable and writable.");
-    }
-#endif
-}
 
 
 
 int
-main(int argc, char *argv[]) {
-    struct cmdlineInfo cmdline;
+main(int argc, const char *argv[]) {
+    CmdlineInfo cmdline;
     const char * inputFileDescription;
-    FILE* ifP;
-    TIFF* tifP;
-    bool eof;
+    FILE * ifP;
+    TIFF * tifP;
+    int ofd;
+    int eof;
     unsigned int imageSeq;
-
-    pnm_init(&argc, argv);
-
-    parseCommandLine(argc, argv, &cmdline);
     
-    ifP = pm_openr_seekable(cmdline.input_filespec);
+    pm_proginit(&argc, argv);
 
-    if (streq(cmdline.input_filespec, "-"))
-        inputFileDescription = "Standard Input";
-    else 
-        inputFileDescription = cmdline.input_filespec;
+    parseCommandLine(argc, argv, &cmdline);
 
-    if (cmdline.append)
-        validateReadableStdout();
+    ifP = pm_openr_seekable(cmdline.inputFileName);
 
-    createTiffGenerator(STDOUT_FILENO, "Standard Output", cmdline.append,
-                        &tifP);
+    if (streq(cmdline.inputFileName, "-"))
+        inputFileDescription = "Standard Input";
+    else
+        inputFileDescription = cmdline.inputFileName;
+
+    switch (cmdline.writeMethod) {
+    case DIRECT_APPEND:
+        createTiffGeneratorDirect(cmdline.output, MUST_EXIST,  &tifP, &ofd);
+        break;
+    case DIRECT_CREATE:
+        createTiffGeneratorDirect(cmdline.output, MAY_CREATE,  &tifP, &ofd);
+        break;
+    case TMPFILE:
+        createTiffGeneratorTmpfile(&tifP, &ofd);
+        break;
+    }
 
     eof = FALSE;  /* initial assumption */
     imageSeq = 0;
@@ -1074,17 +1235,17 @@ main(int argc, char *argv[]) {
     while (!eof) {
         bool success;
 
-        if (cmdline.verbose)
-            pm_message("Converting Image %u", imageSeq);
-
         pnm_nextimage(ifP, &eof);
 
         if (!eof) {
             if (imageSeq > 0)
-                validateReadableStdout();
+                validateReadableOutputFile(ofd);
+
+            if (cmdline.verbose)
+                pm_message("Converting Image %u", imageSeq);
 
             convertImage(ifP, tifP, inputFileDescription, cmdline);
-            
+
             success = TIFFWriteDirectory(tifP);
             if (!success)
                 pm_error("Unable to write TIFF image %u to file.  "
@@ -1093,8 +1254,10 @@ main(int argc, char *argv[]) {
         }
     }
 
-    destroyTiffGenerator(tifP);
+    destroyTiffGenerator(cmdline.writeMethod, tifP, ofd);
     pm_close(ifP);
 
     return 0;
 }
+
+
diff --git a/converter/other/pamtouil.c b/converter/other/pamtouil.c
index 1a53be0f..ee7f5ae6 100644
--- a/converter/other/pamtouil.c
+++ b/converter/other/pamtouil.c
@@ -61,7 +61,7 @@ parseCommandLine(int argc, char ** argv,
    malloc'ed storage.
 -----------------------------------------------------------------------------*/
     optEntry *option_def = malloc( 100*sizeof( optEntry ) );
-        /* Instructions to optParseOptions3 on how to parse our options.
+        /* Instructions to pm_optParseOptions3 on how to parse our options.
          */
     optStruct3 opt;
 
@@ -79,7 +79,7 @@ parseCommandLine(int argc, char ** argv,
     opt.short_allowed = FALSE;  /* We have no short (old-fashioned) options */
     opt.allowNegNum = FALSE;  /* We may have parms that are negative numbers */
 
-    optParseOptions3(&argc, argv, opt, sizeof(opt), 0);
+    pm_optParseOptions3(&argc, argv, opt, sizeof(opt), 0);
         /* Uses and sets argc, argv, and some of *cmdlineP and others. */
 
     if (argc-1 == 0)
@@ -374,9 +374,9 @@ freeCmap(cixel_map    const cmap[],
     for (i = 0; i < ncolors; ++i) {
         cixel_map const cmapEntry = cmap[i];
         if (cmapEntry.uilname)
-            strfree(cmapEntry.uilname);
+            pm_strfree(cmapEntry.uilname);
         if (cmapEntry.rgbname)
-            strfree(cmapEntry.rgbname);
+            pm_strfree(cmapEntry.rgbname);
     }
 }
 
diff --git a/converter/other/pamtowinicon.c b/converter/other/pamtowinicon.c
new file mode 100644
index 00000000..7e2c9e86
--- /dev/null
+++ b/converter/other/pamtowinicon.c
@@ -0,0 +1,1177 @@
+#define _POSIX_SOURCE   /* Make sure fdopen() is in <stdio.h> */
+#include <assert.h>
+#include <string.h>
+#include <stdio.h>
+
+#include "netpbm/pm_config.h"
+#include "netpbm/pm_c_util.h"
+#include "netpbm/mallocvar.h"
+#include "netpbm/nstring.h"
+#include "netpbm/shhopt.h"
+#include "netpbm/pm_system.h"
+#include "netpbm/pam.h"
+#include "winicon.h"
+
+
+
+struct CmdlineInfo {
+    const char * inputFileName;
+    unsigned int verbose;
+    int          pngthreshold;
+    unsigned int truetransparent;
+};
+
+
+
+static void
+parseCommandLine(int argc, const char **argv,
+                 struct CmdlineInfo * const cmdlineP) {
+
+    optEntry *   option_def;
+    unsigned int option_def_index;
+    optStruct3   opt3;
+    unsigned int pngthresholdSpec;
+
+    MALLOCARRAY_NOFAIL(option_def, 100);
+
+    option_def_index = 0;
+
+    OPTENT3(0, "verbose",         OPT_FLAG, NULL,
+            &cmdlineP->verbose,         0);
+    OPTENT3(0, "pngthreshold",    OPT_UINT, &cmdlineP->pngthreshold,
+            &pngthresholdSpec,          0);
+    OPTENT3(0, "truetransparent", OPT_FLAG, NULL,
+            &cmdlineP->truetransparent, 0);
+
+    opt3.opt_table     = option_def;
+    opt3.short_allowed = false;
+    opt3.allowNegNum   = false;
+
+    pm_optParseOptions3(&argc, (char **)argv, opt3, sizeof(opt3), 0);
+
+    if (pngthresholdSpec) {
+        if (UINT_MAX / cmdlineP->pngthreshold < cmdlineP->pngthreshold)
+            pm_error("-pngthreshold is too large: %u", cmdlineP->pngthreshold);
+    } else
+        cmdlineP->pngthreshold = 128;
+
+    if (argc-1 > 0) {
+        cmdlineP->inputFileName = argv[1];
+
+        if (argc-1 > 1)
+            pm_error("Too many arguments: %u.  The only non-option "
+                     "argument is the optional input file name", argc-1);
+    } else
+        cmdlineP->inputFileName = "-";
+
+    free(option_def);
+}
+
+
+
+static bool verbose;
+
+static unsigned char const pngHeader[] = PNG_HEADER;
+
+
+
+struct Palette {
+    sample color[256][3];
+    unsigned int colorCt;
+        /* Number of colors in color[][] */
+    bool tooManyColors;
+        /* There are too many colors for a BMP palette (more than 256); only
+           the first 256 are in color[][]
+        */
+};
+
+
+
+static struct IconDir *
+newIconDir() {
+
+    struct IconDir * dirP;
+
+    MALLOCVAR_NOFAIL(dirP);
+
+    dirP->zero           = 0;
+    dirP->type           = ICONDIR_TYPE_ICO;
+    dirP->count          = 0;
+
+    dirP->entriesAllocCt = 0;
+    dirP->entries        = NULL;
+
+    return dirP;
+}
+
+
+
+static void
+freeIconDir(struct IconDir * const dirP) {
+    if (dirP->entries)
+        free(dirP->entries);
+
+    free(dirP);
+}
+
+
+
+static void
+addToDirectory(struct IconDirEntry * const dirEntryP,
+               struct IconDir *      const dirP) {
+/*----------------------------------------------------------------------------
+  Add an icon to the icon directory.
+-----------------------------------------------------------------------------*/
+    if (dirP->count + 1 > dirP->entriesAllocCt) {
+        /* Out of space in dirP->entries[].  Expand. */
+
+        dirP->entriesAllocCt += 8;
+
+        REALLOCARRAY(dirP->entries, dirP->entriesAllocCt);
+
+        if (!dirP->entries)
+            pm_error("Unable to get memory for %u entries "
+                     "in the Icon directory.", dirP->entriesAllocCt);
+    }
+
+    dirP->entries[dirP->count++] = *dirEntryP;
+}
+
+
+
+typedef void (GetPixelFn) (tuple **     const tuples,
+                           unsigned int const col,
+                           unsigned int const row,
+                           sample *     const pixel);
+
+
+
+static GetPixelFn get_grayscalePixel;
+
+static void
+get_grayscalePixel(tuple **     const tuples,
+                   unsigned int const col,
+                   unsigned int const row,
+                   sample *     const pixel) {
+/*----------------------------------------------------------------------------
+   Get a pixel from a grayscale PAM
+-----------------------------------------------------------------------------*/
+    pixel[0] = tuples[row][col][0];
+    pixel[1] = tuples[row][col][0];
+    pixel[2] = tuples[row][col][0];
+}
+
+
+
+static GetPixelFn get_rgbPixel;
+
+static void
+get_rgbPixel(tuple **     const tuples,
+             unsigned int const col,
+             unsigned int const row,
+             sample *     const pixel) {
+/*----------------------------------------------------------------------------
+   Get a pixel from an RGB PAM
+-----------------------------------------------------------------------------*/
+    pixel [0] = tuples [row][col][0];
+    pixel [1] = tuples [row][col][1];
+    pixel [2] = tuples [row][col][2];
+}
+
+
+static bool
+andMakesOpaque(const struct pam * const pamP,
+               tuple **           const tuples,
+               unsigned int       const row,
+               unsigned int       const col,
+               bool               const haveAlpha,
+               unsigned int       const alphaPlane,
+               bool               const haveAnd,
+               unsigned int       const andPlane) {
+/*----------------------------------------------------------------------------
+   The AND mask makes a pixel opaque
+-----------------------------------------------------------------------------*/
+    if (haveAnd)
+        return (pamP->maxval <= tuples[row][col][andPlane]);
+    else if (haveAlpha)
+        return (pamP->maxval <= tuples[row][col][alphaPlane]);
+    else
+        /* neither alpha channel nor AND mask: full opacity */
+        return true;
+}
+
+
+
+static void
+getPalette(struct pam *     const pamP,
+           tuple **         const tuples,
+           GetPixelFn *     const getPixel,
+           struct Palette * const paletteP) {
+/*----------------------------------------------------------------------------
+  Create the palette for all the colors in 'tuples'.
+-----------------------------------------------------------------------------*/
+    unsigned int row;
+
+    paletteP->colorCt = 0;  /* initial value */
+    paletteP->tooManyColors = false;  /* initial value */
+
+    for (row = 0; pamP->height > row && !paletteP->tooManyColors; ++row) {
+        unsigned int col;
+        for (col = 0; pamP->width > col && !paletteP->tooManyColors; ++col) {
+            sample pixel[3];
+            unsigned int i;
+
+            getPixel(tuples, col, row, pixel);
+
+            for (i = 0; i < paletteP->colorCt; ++i) {
+                if ((paletteP->color[i][0] == pixel[0])
+                    && (paletteP->color[i][1] == pixel[1])
+                    && (paletteP->color[i][2] == pixel[2]))
+                    break;
+            }
+            if (i == paletteP->colorCt) {
+                /* We didn't find the color. */
+                if (paletteP->colorCt >= 256) {
+                    /* Image exceeds the palette capacity */
+                    paletteP->tooManyColors = true;
+                } else {
+                    /* Add the color to the palette */
+                    paletteP->color[paletteP->colorCt][0] = pixel[0];
+                    paletteP->color[paletteP->colorCt][1] = pixel[1];
+                    paletteP->color[paletteP->colorCt][2] = pixel[2];
+
+                    ++paletteP->colorCt;
+                }
+            }
+        }
+    }
+}
+
+
+
+static bool
+realAlphaNeeded(const struct pam * const pamP,
+                tuple **           const tuples,
+                unsigned int       const alphaPlane) {
+/*----------------------------------------------------------------------------
+  A real alpha channel (in contrast to an AND mask) is needed to represent the
+  image in 'tuples', given that 'alphaPlane' is the alpha plane.
+
+  A real alpha channel is needed if any pixel is translucent (neither opaque
+  nor transparent).
+-----------------------------------------------------------------------------*/
+    unsigned int row;
+
+    for (row = 0; row < pamP->height; ++row) {
+        unsigned int col;
+        for (col = 0; col < pamP->width; ++col) {
+            sample const opacity = tuples[row][col][alphaPlane];
+
+            if (opacity != 0 && opacity != pamP->maxval)
+                return true;
+        }
+    }
+    return false;
+}
+
+
+
+static void
+writeBmpImageHeader(unsigned int const width,
+                    unsigned int const height,
+                    unsigned int const bpp,
+                    unsigned int const rasterSize,
+                    FILE *       const ofP) {
+/*----------------------------------------------------------------------------
+
+  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.
+-----------------------------------------------------------------------------*/
+    pm_writelittlelongu  (ofP, 40);              /* header_size          */
+    pm_writelittlelongu  (ofP, width);           /* bm_width             */
+    pm_writelittlelongu  (ofP, height *2);       /* bm_height            */
+    pm_writelittleshortu (ofP, 1);               /* color_planes         */
+    pm_writelittleshortu (ofP, bpp);             /* bits_per_pixel       */
+    pm_writelittlelongu  (ofP, BI_RGB);          /* compression_method   */
+    pm_writelittlelongu  (ofP, rasterSize);      /* image_size           */
+    pm_writelittlelongu  (ofP, 0);               /* horizontal_resolution*/
+    pm_writelittlelongu  (ofP, 0);               /* vertical_resolution  */
+    pm_writelittlelongu  (ofP, 0);               /* colors_in_palette    */
+    pm_writelittlelongu  (ofP, 0);               /* important_colors     */
+}
+
+
+
+static void
+write32BitBmp(const struct pam *   const pamP,
+              tuple     **         const tuples,
+              GetPixelFn *         const getPixel,
+              bool                 const haveAlpha,
+              unsigned int         const alphaPlane,
+              FILE *               const ofP,
+              uint32_t *           const sizeP) {
+/*----------------------------------------------------------------------------
+  Write a 32-bit BMP encoded image to file *ofP.
+-----------------------------------------------------------------------------*/
+    int row;
+    
+    writeBmpImageHeader(pamP->width, pamP->height, 32, 
+                        pamP->width * 4 * pamP->height, ofP);
+
+    /*  write "XOR mask" */
+    for (row = pamP->height - 1; row >= 0; --row) {
+        unsigned int col;
+        for (col = 0; col < pamP->width; ++col) {
+            sample   pixel[3];
+            uint32_t val;
+
+            getPixel(tuples, col, row, pixel);
+
+            val = ((uint32_t) pixel[PAM_RED_PLANE] << 16)
+                + ((uint32_t) pixel[PAM_GRN_PLANE] <<  8)
+                + ((uint32_t) pixel[PAM_BLU_PLANE] <<  0)
+                ;
+            
+            if (haveAlpha)
+                val += (uint32_t) tuples[row][col][alphaPlane] << 24;
+
+            pm_writelittlelongu(ofP, val);
+       }
+    }
+    *sizeP = 40 + pamP->height * pamP->width * 4;
+}
+
+
+
+static void
+writeBmpPalette(const struct Palette * const paletteP,
+                unsigned int           const maxColors,
+                FILE *                 const ofP) {
+/*----------------------------------------------------------------------------
+   Write the palette of a BMP image.
+-----------------------------------------------------------------------------*/
+    unsigned int i;
+
+    for (i = 0; i < paletteP->colorCt; ++i)
+        pm_writelittlelongu(ofP, 0
+                            +(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);
+}
+
+
+
+static void
+writeXorMask(const struct pam *     const pamP,
+             tuple **               const tuples,
+             GetPixelFn *           const getPixel,
+             const struct Palette * const paletteP,
+             unsigned int           const bpp,
+             FILE *                 const ofP) {
+/*----------------------------------------------------------------------------
+   Write the "XOR mask" part of a BMP image.
+
+   This is what one normally thinks of as the foreground image raster.
+-----------------------------------------------------------------------------*/
+    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;
+        unsigned int col;
+
+        mask = 0x1;
+        val  = 0x0;
+
+        for (col = 0; col < pamP->width; ++col) {
+            sample pixel[3];
+            unsigned int i;
+
+            mask <<= bpp;
+            val  <<= bpp;
+
+            getPixel(tuples, col, row, pixel);
+
+            for (i = 0; i < paletteP->colorCt; ++i)
+                if (true
+                    && (pixel[0] == paletteP->color[i][0])
+                    && (pixel[1] == paletteP->color[i][1])
+                    && (pixel[2] == paletteP->color[i][2]))
+                    break;
+
+            assert(i < paletteP->colorCt);
+
+            val |= i;
+
+            if (mask > 0xFF) {
+                pm_writecharu(ofP, val);
+                mask = 0x1;
+                val  = 0x0;
+            }
+        }
+        for (; col < maxCol; ++col) {
+            mask <<= bpp;
+            val  <<= bpp;
+
+            if (mask > 0xFF) {
+                pm_writecharu(ofP, val);
+                mask = 0x1;
+            }
+        }
+    }
+}
+
+
+
+static void
+writePaletteBmp(unsigned int           const bpp,
+                const struct pam   *   const pamP,
+                tuple **               const tuples,
+                GetPixelFn *           const getPixel,
+                const struct Palette * const paletteP,
+                FILE *                 const ofP,
+                uint32_t *             const sizeP) {
+/*----------------------------------------------------------------------------
+  Write a `BMP with palette' encoded image to file *ofP.
+
+  Unless it would be smaller as a 32-bit direct image, in which case
+  write that instead.
+-----------------------------------------------------------------------------*/
+    unsigned int const maxColors = 1 << bpp;
+
+    unsigned int const rasterSize =
+        pamP->height *((pamP->width * bpp + 31) & ~31) / 8;
+
+    if (pamP->height * pamP->width * 4 <= maxColors * 4 + rasterSize)
+        write32BitBmp(pamP, tuples, getPixel, false /*haveAlpha*/, 0,
+                      ofP, sizeP);
+    else {
+        unsigned int const headerSize = 40;
+        unsigned int const paletteSize = maxColors * 4;
+
+        writeBmpImageHeader(pamP->width, pamP->height, bpp, rasterSize, ofP);
+
+        writeBmpPalette(paletteP, maxColors, ofP);
+
+        writeXorMask(pamP, tuples, getPixel, paletteP, bpp, ofP);
+
+        *sizeP = headerSize + paletteSize + rasterSize;
+    }
+}
+
+
+
+static void
+writeAndMask(const struct pam * const pamP,
+             tuple     **       const tuples,
+             bool               const haveAlpha,
+             unsigned int       const alphaPlane,
+             bool               const haveAnd,
+             unsigned int       const andPlane,
+             FILE *             const ofP,
+             uint32_t *         const sizeP) {
+/*----------------------------------------------------------------------------
+  Write the AND mask to file *ofP.
+-----------------------------------------------------------------------------*/
+    unsigned int const maxCol =((pamP->width * 1 + 31) & ~31) / 1;
+
+    int row;
+    unsigned int sizeSoFar;
+
+    sizeSoFar = 0;
+
+    for (row = pamP->height - 1; row >= 0; --row) {
+        uint8_t  val;
+        uint16_t mask;
+        unsigned int col;
+
+        mask = 0x1;
+        val  = 0x0;
+
+        for (col = 0; col < pamP->width; ++col) {
+            mask <<= 1;
+            val  <<= 1;
+
+            if (!andMakesOpaque(pamP, tuples, row, col, 
+                                haveAlpha, alphaPlane, haveAnd, andPlane))
+                val |= 0x1;
+
+            if (mask > 0xFF) {
+                pm_writecharu(ofP, val);
+                sizeSoFar += 1;
+                mask = 0x1;
+                val  = 0x0;
+            }
+        }
+        for (; col < maxCol; ++col) {
+            mask <<= 1;
+            val  <<= 1;
+
+            if (mask > 0xFF){
+                pm_writecharu(ofP, val);
+                sizeSoFar += 1;
+                mask = 0x1;
+            }
+        }
+    }
+    *sizeP = sizeSoFar;
+}
+
+
+
+static void
+makeAlphaFile(const struct pam * const imagePamP,
+              tuple **           const imageTuples,
+              unsigned int       const alphaPlane,
+              const char **      const alphaFileNameP) {
+
+    FILE * alphaFileP;
+    struct pam alphaPam;
+    tuple ** alphaTuples;
+    unsigned int row;
+    
+    pm_make_tmpfile(&alphaFileP, alphaFileNameP);
+
+    alphaPam.size   = sizeof(alphaPam);
+    alphaPam.len    = PAM_STRUCT_SIZE(tuple_type);
+    alphaPam.file   = alphaFileP;
+    alphaPam.format = PAM_FORMAT;
+    alphaPam.width  = imagePamP->width;
+    alphaPam.height = imagePamP->height;
+    alphaPam.depth  = 1;
+    alphaPam.maxval = imagePamP->maxval;
+    strcpy(alphaPam.tuple_type, PAM_PGM_TUPLETYPE);
+
+    alphaTuples = pnm_allocpamarray(&alphaPam);
+
+    assert(alphaPlane < imagePamP->depth);
+
+    for (row = 0; row < alphaPam.height; ++row) {
+        unsigned int col;
+        for (col = 0; col < alphaPam.width; ++col)
+            alphaTuples[row][col][0] = imageTuples[row][col][alphaPlane];
+    }
+
+    pnm_writepam(&alphaPam, alphaTuples);
+
+    pnm_freepamarray(alphaTuples, &alphaPam);
+
+    pm_close(alphaFileP);
+}
+
+
+
+struct AcceptToFileParm {
+    FILE *   ofP;
+    size_t * writeCtP;
+};
+
+static void
+acceptToFile(int    const pipeToSuckFd,
+             void * const accepterParm) {
+
+    struct AcceptToFileParm * const parmP = accepterParm;
+
+    FILE * const inFileP = fdopen(pipeToSuckFd, "r");
+
+    bool eof;
+    size_t copyCt;
+
+    for (eof = false, copyCt = 0; !eof; ) {
+        size_t readCt;
+        unsigned char buffer[1024];
+
+        readCt = fread(buffer, 1, sizeof(buffer), inFileP);
+
+        if (readCt == 0)
+            eof = true;
+        else {
+            size_t writeCt;
+
+            writeCt = fwrite(buffer, 1, readCt, parmP->ofP);
+
+            if (writeCt != readCt)
+                pm_error("Write to images file failed.  errno=%d (%s)",
+                         errno, strerror(errno));
+
+            copyCt += writeCt;
+        }
+    }
+    *parmP->writeCtP = copyCt;
+}
+
+
+
+static void
+writePng(const struct pam * const pamP,
+         tuple **           const tuples,
+         bool               const haveAlpha,
+         unsigned int       const alphaPlane,
+         bool               const haveAnd,
+         unsigned int       const andPlane,
+         uint32_t *         const sizeP,
+         FILE *             const ofP) {
+
+    struct pamtuples pamTuples;
+    size_t pngSize;
+    struct AcceptToFileParm acceptParm;
+    struct pam pam;
+
+    pam = *pamP;
+    pam.depth = pamP->depth - (haveAlpha ? 1 : 0) - (haveAnd ? 1 : 0);
+
+    pamTuples.pamP    = &pam;
+    pamTuples.tuplesP = (tuple ***)&tuples;
+
+    /* We're going to fork a process to add stuff to *ofP, so we flush
+       out this process' previous writes to that file first:
+    */
+    fflush(ofP);
+
+    acceptParm.ofP = ofP;
+    acceptParm.writeCtP = &pngSize;
+    
+    if (haveAlpha || haveAnd) {
+        const char * alphaFileName;
+        const char * command;
+
+        if (haveAlpha)
+            makeAlphaFile(pamP, tuples, alphaPlane, &alphaFileName);
+        else
+            makeAlphaFile(pamP, tuples, andPlane, &alphaFileName);
+
+        strcpy (pam.tuple_type,
+                pam.depth == 3 ? PAM_PPM_TUPLETYPE: PAM_PGM_TUPLETYPE);
+        
+        pm_asprintf(&command, "pnmtopng -alpha=\"%s\"", alphaFileName);
+
+        pm_system(pm_feed_from_pamtuples, &pamTuples,
+                  acceptToFile, &acceptParm,
+                  command);
+    
+        pm_strfree(command);
+    
+        unlink(alphaFileName);
+    } else {
+        pm_system(pm_feed_from_pamtuples, &pamTuples,
+                  acceptToFile, &acceptParm,
+                  "pnmtopng");
+    }
+
+    *sizeP = pngSize;
+}
+
+
+
+static void
+blackenXor(const struct pam * const pamP,
+           tuple     **       const tuples,
+           bool               const haveAlpha,
+           unsigned int       const alphaPlane,
+           bool               const haveAnd,
+           unsigned int       const andPlane) {
+/*----------------------------------------------------------------------------
+  Set all pixels marked as transparent in AND mask to black.
+-----------------------------------------------------------------------------*/
+    unsigned int row;
+
+    for (row = 0; row < pamP->height; ++row) {
+        unsigned int col;
+        for (col = 0; col < pamP->width; ++col) {
+            if (!andMakesOpaque(pamP, tuples, row, col,
+                                haveAlpha, alphaPlane, haveAnd, andPlane)) {
+                tuples[row][col][0] = PAM_BLACK;
+
+                if (pamP->depth >= 3) {
+                    tuples[row][col][1] = PAM_BLACK;
+                    tuples[row][col][2] = PAM_BLACK;
+                }
+            }
+        }
+    }
+}
+
+
+
+
+static void
+readAndScalePam(struct pam * const pamP,
+                bool         const doingPng,
+                tuple **     const tuples) {
+
+    if (doingPng) {
+        /* Read the image with its native maxval */
+        unsigned int row;
+        for (row = 0; row < pamP->height; ++row)
+            pnm_readpamrow(pamP, tuples[row]);
+    } else {
+        /* Read the image and scale to maxval 255 */
+        tuple * tuplerow;
+        unsigned int row;
+        tuplerow = pnm_allocpamrow(pamP);
+
+        for (row = 0; row < pamP->height; ++row) {
+            pnm_readpamrow(pamP, tuplerow);
+            pnm_scaletuplerow(pamP, tuples[row], tuplerow, 255);
+        }
+        pnm_freepamrow(tuplerow);
+        pamP->maxval = 255;
+    }
+}
+
+
+
+static void
+determineImageType(const struct pam * const pamP,
+                   tuple **           const tuples,
+                   GetPixelFn **      const getPixelP,
+                   bool *             const haveAlphaP,
+                   unsigned int *     const alphaPlaneP,
+                   bool *             const haveAndP,
+                   unsigned int *     const andPlaneP) {
+
+    /*  PAM input channels:
+     *
+     *  1-channel PAM: Grayscale
+     *  2-channel PAM: Grayscale +Alpha
+     *  3-channel PAM: RGB
+     *  4-channel PAM: RGB +Alpha
+     *  5-channel PAM: RGB +Alpha +AND mask
+     */
+    switch (pamP->depth) {
+    case 1:
+        *getPixelP  = get_grayscalePixel;
+        *haveAlphaP = false;
+        *haveAndP   = false;
+        break;
+
+    case 2:
+        *getPixelP = get_grayscalePixel;
+        if (realAlphaNeeded(pamP, tuples, 1)) {
+            *haveAlphaP  = true;
+            *alphaPlaneP = 1;
+            *haveAndP    = false;
+        } else {
+            *haveAlphaP = false;
+            *haveAndP   = true;
+            *andPlaneP  = 1;
+        }
+        break;
+
+    case 3:
+        *getPixelP  = get_rgbPixel;
+        *haveAlphaP = false;
+        *haveAndP   = false;
+        break;
+
+    case 4:
+        *getPixelP = get_rgbPixel;
+        if (realAlphaNeeded(pamP, tuples, 3)) {
+            *haveAlphaP  = true;
+            *alphaPlaneP = 3;
+            *haveAndP    = false;
+        } else {
+            *haveAlphaP = false;
+            *haveAndP    = true;
+            *andPlaneP  = 3;
+        }
+        break;
+
+    case 5:
+        *getPixelP   = get_rgbPixel;
+        *haveAlphaP  = true;
+        *alphaPlaneP = 3;
+        *haveAndP    = true;
+        *andPlaneP   = 4;
+        break;
+
+    default:
+        pm_error("unexpected PAM depth %u.  "
+                 "We understand depths 1-5", pamP->depth);
+        break;
+    }
+}
+
+
+
+static void
+reportImageInfo(unsigned int           const imageNum,
+                const struct pam *     const pamP,
+                const struct Palette * const paletteP,
+                bool                   const haveAlpha,
+                bool                   const haveAnd) {
+
+    const char * colorCt;
+
+    if (paletteP->tooManyColors)
+        pm_asprintf(&colorCt, "> 256");
+    else
+        pm_asprintf(&colorCt, "%u", paletteP->colorCt);
+
+    pm_message("Image %2u:"
+               " %3u x %3u x %u, %s colors%s%s",
+               imageNum,
+               pamP->width, pamP->height, pamP->depth,
+               colorCt,
+               haveAlpha ? ", alpha channel": "",
+               haveAnd ? ", AND mask": "");
+
+    pm_strfree(colorCt);
+}
+
+
+
+static void
+writeIconAndCreateDirEntry(const struct pam *     const pamP,
+                           tuple **               const tuples,
+                           GetPixelFn *           const getPixel,
+                           bool                   const doingPng,
+                           bool                   const haveAlpha,
+                           unsigned int           const alphaPlane,
+                           bool                   const haveAnd,
+                           unsigned int           const andPlane,
+                           bool                   const mustBlackenXor,
+                           const struct Palette * const paletteP,
+                           FILE *                 const ofP,
+                           struct IconDirEntry *  const dirEntryP) {
+/*----------------------------------------------------------------------------
+   Write to *ofP the icon image for the image represented by *pamP and
+   'tuples'.
+
+   Generate the information for an icon directory entry for this image
+   and return it as *dirEntryP.  ==>BUT: the 'offset' member of this
+   structure will not be meaningful. <==
+
+   Make a PNG image if 'doingPng' is true; BMP otherwise.
+
+   'haveAlpha' means that there is an alpha plane in 'tuples' and it is
+   Plane 'alphaPlane'.
+
+   'haveAnd' means that there is an AND plane in 'tuples' and it is Plane
+   'andPlane'.
+
+   *paletteP is the color palette for the icon; it contains an entry for each
+   color in 'tuples'.  Except: it may simply indicate that there are too many
+   colors in 'tuples' to have a palette.
+
+   The 'bits_per_pixel' member of the directory entry is supposed to tell the
+   color resolution of the image so the user can decide which of many versions
+   of the icon in the file to use.  But we just call it 32 bits in every case
+   except paletted BMP, where it actually relates to how many colors are in
+   the image.
+-----------------------------------------------------------------------------*/
+    dirEntryP->width          = pamP->width;
+    dirEntryP->height         = pamP->height;
+    dirEntryP->color_planes   = 1;
+    dirEntryP->zero           = 0;
+
+    if (doingPng) {
+        dirEntryP->color_count    = 0;
+        dirEntryP->bits_per_pixel = 32;
+
+        writePng(pamP, tuples, haveAlpha, alphaPlane, haveAnd, andPlane,
+                 &dirEntryP->size, ofP);
+    } else {
+        uint32_t bmpSize;
+        uint32_t andMaskSize;
+
+        if (mustBlackenXor)
+            blackenXor(pamP, tuples,
+                       haveAlpha, alphaPlane, haveAnd, andPlane);
+
+        if (haveAlpha) {
+            dirEntryP->color_count    = 0;
+            dirEntryP->bits_per_pixel = 32;
+
+            write32BitBmp(pamP, tuples, getPixel, haveAlpha, alphaPlane,
+                          ofP, &bmpSize);
+        } else if (paletteP->tooManyColors) {
+            /* Do a truecolor image */
+            dirEntryP->color_count    = 0;
+            dirEntryP->bits_per_pixel = 32;
+
+            write32BitBmp(pamP, tuples, getPixel, false /*haveAlpha*/, 0,
+                          ofP, &bmpSize);
+        } else {
+            /* Do a paletted image */
+
+            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);
+            }
+        }
+        writeAndMask(pamP, tuples, haveAlpha, alphaPlane, haveAnd, andPlane,
+                     ofP, &andMaskSize);
+
+        dirEntryP->size = bmpSize + andMaskSize;
+    }
+}
+
+
+
+static void
+convertOneImage(unsigned int     const imageNum,
+                FILE *           const ifP,
+                unsigned int     const pngThreshold,
+                bool             const mustBlackenXor,
+                FILE *           const ofP,
+                struct IconDir * const dirP) {
+
+    struct IconDirEntry dirEntry;
+    struct pam          pam;
+    tuple **            tuples;
+    bool                haveAlpha;
+    unsigned int        alphaPlane;
+    bool                haveAnd;
+    unsigned int        andPlane;
+    GetPixelFn *        getPixel;
+    struct Palette      palette;
+    bool                doingPng;
+        
+    /*  Output:
+     *
+     *  threshold^2 pixels or more:
+     *      no alpha channel:        PNG (RGB)
+     *      alpha channel:           PNG (RGBA)
+     *      alpha channel +AND mask: PNG (RGBA), AND mask dropped
+     *  alpha values other than 0 and maxval: 32bit +alpha BMP
+     *  no more than   2 colors:  1bit or 32bit BMP
+     *  no more than  16 colors:  4bit or 32bit BMP
+     *  no more than 256 colors:  8bit or 32bit BMP
+     *  more than    256 colors: 32bit BMP
+     */
+    pnm_readpaminit(ifP, &pam, PAM_STRUCT_SIZE(tuple_type));
+
+    if (pam.width > 256 || pam.height > 256)
+        pm_error("Image %u: too large as a windows icon (%u x %u).  "
+                 "Maximum allowed dimension is 256",
+                 imageNum, pam.width, pam.height);
+
+    tuples = pnm_allocpamarray(&pam);
+
+    doingPng = pam.width * pam.height >= pngThreshold;
+
+    readAndScalePam(&pam, doingPng, tuples);
+
+    determineImageType(&pam, tuples, &getPixel,
+                       &haveAlpha, &alphaPlane, &haveAnd, &andPlane);
+
+    getPalette(&pam, tuples, getPixel, &palette);
+
+    if (verbose)
+        reportImageInfo(imageNum, &pam, &palette, haveAlpha, haveAnd);
+
+    writeIconAndCreateDirEntry(&pam, tuples, getPixel, doingPng,
+                               haveAlpha, alphaPlane,
+                               haveAnd, andPlane,
+                               mustBlackenXor,
+                               &palette,
+                               ofP, &dirEntry);
+
+    if (verbose)
+        pm_message("Image %2u: %u bytes", imageNum, dirEntry.size);
+
+    pnm_freepamarray(tuples, &pam);
+
+    addToDirectory(&dirEntry, dirP);
+}
+
+
+
+static void
+convert(FILE *           const ifP,
+        unsigned int     const pngThreshold,
+        bool             const mustBlackenXor,
+        struct IconDir * const dirP,
+        FILE *           const ofP) {
+/*----------------------------------------------------------------------------
+  Read a (multi-image) PAM file from *ifP and convert the individual images
+  to the proper format for a Windows icon file and write those to *ofP.
+
+  Where the number of pixels in an image is at least 'pngThreshold', use
+  a PNG image.  Otherwise, use a BMP.
+-----------------------------------------------------------------------------*/
+    unsigned int imageNum;
+    int eof;
+    
+    for (imageNum = 0, eof = false; !eof; ++imageNum) {
+        convertOneImage(imageNum, ifP, pngThreshold, mustBlackenXor,
+                        ofP, dirP);
+
+        pnm_nextimage(ifP, &eof);
+    }
+}
+
+
+
+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->offset);
+}
+
+
+
+static void
+writeIconDirectory(const struct IconDir * const dirP,
+                   FILE *                 const ofP) {
+/*----------------------------------------------------------------------------
+  Write to file *ofP the icon directory described by *dirP.
+
+  *dirP's image offset members are meaningless as input.  We fill them in.
+-----------------------------------------------------------------------------*/
+    uint32_t const hsize = 6 + dirP->count * 16;
+
+    unsigned int imageNum;
+    unsigned int imageOffset;
+
+    pm_writelittleshortu(ofP, dirP->zero);
+    pm_writelittleshortu(ofP, dirP->type);
+    pm_writelittleshortu(ofP, dirP->count);
+
+    for (imageNum = 0, imageOffset = hsize;
+         imageNum < dirP->count;
+         ++imageNum) {
+
+        struct IconDirEntry * const dirEntryP = &dirP->entries[imageNum];
+        
+        pm_message("image %2u: %3u x %3u x %2u",
+                   imageNum,
+                   dirEntryP->width,
+                   dirEntryP->height,
+                   dirEntryP->bits_per_pixel);
+
+        dirEntryP->offset = imageOffset;
+
+        writeIconDirEntry(dirEntryP, ofP);
+
+        imageOffset += dirEntryP->size;
+    }
+}
+
+
+
+static void
+copyFile(FILE * const ifP,
+         FILE * const ofP) {
+
+    bool eof;
+    
+    for (eof = false; !eof; ) {
+        unsigned char buffer[1024];
+        size_t bytesRead;
+
+        bytesRead = fread(buffer, 1, sizeof(buffer), ifP);
+
+        if (bytesRead == 0)
+            eof = true;
+        else {
+            size_t bytesWritten;
+
+            bytesWritten = fwrite(buffer, 1, bytesRead, ofP);
+
+            if (bytesWritten < bytesRead)
+                pm_error("Error writing to output file.");
+        }
+    }
+}
+
+
+
+static void
+writeIconFile(const struct IconDir * const dirP,
+              FILE *                 const imagesFileP,
+              FILE *                 const ofP) {
+/*----------------------------------------------------------------------------
+  Write a windows icon file.
+
+  *dirP is the icon directory to put in it.
+
+  *imagesFileP contains all the text of the icon images.  The contents of
+  this file go verbatim into the output.
+-----------------------------------------------------------------------------*/
+    writeIconDirectory(dirP, ofP);
+
+    copyFile(imagesFileP, ofP);
+}
+
+
+
+int
+main(int argc, const char *argv []) {
+
+    struct CmdlineInfo cmdline;
+    FILE * ifP;
+    FILE * imagesFileP;
+        /* This is the file in which we collect the individual icon
+           images to be copied later to the output.
+        */
+    struct IconDir * dirP;
+
+    pm_proginit(&argc, argv);
+
+    parseCommandLine(argc, argv, &cmdline);
+
+    verbose = cmdline.verbose;
+
+    /* The output icon file has directory information at the top that we
+       can't know until we have looked at the input images.  So as we pass
+       through the input, we collect the directory information and generate
+       the individual icon images and store them in *imageFileP.  When we've
+       been through all of the input, we write out the directory and then
+       copy the images from *imageFileP to the output.
+    */
+
+    dirP = newIconDir();
+
+    imagesFileP = pm_tmpfile();
+
+    ifP = pm_openr(cmdline.inputFileName);
+
+    convert(ifP, SQR(cmdline.pngthreshold), cmdline.truetransparent,
+            dirP, imagesFileP);
+
+    rewind(imagesFileP);
+
+    writeIconFile(dirP, imagesFileP, stdout);
+
+    freeIconDir(dirP);
+
+    return 0;
+}
+
+
+
diff --git a/converter/other/pamtoxvmini.c b/converter/other/pamtoxvmini.c
index e1aa9b52..b57bcc74 100644
--- a/converter/other/pamtoxvmini.c
+++ b/converter/other/pamtoxvmini.c
@@ -152,14 +152,14 @@ getPaletteIndexThroughCache(struct pam *      const pamP,
    If the tuple-index association is in *paletteIndexP, use it.  If not,
    find it the hard way and add it to *palettedIndexP for the next guy.
 -----------------------------------------------------------------------------*/
-    bool found;
+    int found;
     int paletteIndex;
 
     pnm_lookuptuple(pamP, paletteHash, tuple, &found, &paletteIndex);
     if (found)
         *paletteIndexP = paletteIndex;
     else {
-        bool fits;
+        int fits;
         findClosestColor(pamP, tuple, xvPaletteP, paletteIndexP);
         
         pnm_addtotuplehash(pamP, paletteHash, tuple, *paletteIndexP, &fits);
diff --git a/converter/other/pdbimgtopam.c b/converter/other/pdbimgtopam.c
new file mode 100644
index 00000000..3cb4129a
--- /dev/null
+++ b/converter/other/pdbimgtopam.c
@@ -0,0 +1,774 @@
+/*=============================================================================
+                               pamtopdbimg
+===============================================================================
+
+  Convert Palm Pilot PDB Image format (for viewing by
+  Pilot Image Viewer) to Netpbm image.
+
+  Bryan Henderson derived this from Eric Howe's program named
+  'imgvtopnm', in September 2010.
+=============================================================================*/
+/*
+ * Copyright (C) 1997 Eric A. Howe
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *   Authors:  Eric A. Howe (mu@trends.net)
+ *             Bryan Henderson
+ */
+#include <stdlib.h>
+#include <assert.h>
+
+#include "pm_c_util.h"
+#include "mallocvar.h"
+#include "nstring.h"
+#include "shhopt.h"
+#include "pam.h"
+
+#include "ipdb.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 */
+    const char * notefile;  /* NULL if not specified */
+    unsigned int verbose;
+};
+
+
+
+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 notefileSpec;
+
+    MALLOCARRAY_NOFAIL(option_def, 100);
+
+    option_def_index = 0;   /* incremented by OPTENT3 */
+    OPTENT3(0, "notefile",            OPT_STRING,    &cmdlineP->notefile,
+            &notefileSpec,            0);
+    OPTENT3(0, "verbose",             OPT_FLAG,    NULL,
+            &cmdlineP->verbose,       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 (!notefileSpec)
+        cmdlineP->notefile = NULL;
+    
+    if (argc-1 < 1)
+        cmdlineP->inputFileName = "-";
+    else if (argc-1 == 1)
+        cmdlineP->inputFileName = argv[1];
+    else
+        pm_error("Program takes at most one argument:  input file name");
+}
+
+
+
+#define getg16pixel(b,o)    (((b) >> (4 - 4*(o))) & 0x0f)
+#define getgpixel(b,o)      (((b) >> (6 - 2*(o))) & 0x03)
+#define getmpixel(b,o)      (((b) >> (7 - (o))) & 0x01)
+
+
+static void
+abortShort() {
+    pm_error("Invalid image.  Compression algorithm runs out of "
+             "compressed data before generating the expected "
+             "amount of image data");
+}
+
+
+
+static void
+abortOverrun() {
+    pm_error("Invalid image.  Compression algorithm finds the end of "
+             "the image in the middle of a run");
+}
+
+
+
+static void
+decompress(const uint8_t * const compressed,
+           size_t          const compressedSize,
+           size_t          const imageSize,
+           uint8_t **      const uncompressedP) {
+/*----------------------------------------------------------------------------
+   Decompress the data 'compressed', which is 'compressedSize' bytes long.
+   Return the decompressed data in newly malloced storage as
+   *decompressedP.  Decompression should yield exactly 'imageSize' bytes.
+-----------------------------------------------------------------------------*/
+    /*
+     * The compression scheme used is a simple RLE; the control codes,
+     * CODE, are one byte and have the following meanings:
+     *
+     *  CODE >  0x80    Insert (CODE + 1 - 0x80) copies of the next byte.
+     *  CODE <= 0x80    Insert the next (CODE + 1) literal bytes.
+     *
+     * Compressed pieces can (and do) cross row boundaries.
+     */
+    uint8_t * uncompressed;
+
+    MALLOCARRAY(uncompressed, imageSize);
+
+    if (uncompressed) {
+        const uint8_t * inP;
+        uint8_t *       outP;
+        size_t          bytesLeft;
+        
+        for (bytesLeft = imageSize,
+                 inP  = &compressed[0], outP = &uncompressed[0];
+             bytesLeft > 0;
+            ) {
+
+            int got, put;
+
+            if (inP > compressed + compressedSize)
+                abortShort();
+
+            if (*inP > 0x80) {
+                put = *inP++ + 1 - 0x80;
+                if (outP + put > uncompressed + imageSize)
+                    abortOverrun();
+                memset(outP, *inP, put);
+                got = 1;
+            } else {
+                put = *inP++ + 1;
+                if (inP + put > compressed + compressedSize)
+                    abortShort();
+                if (outP + put > uncompressed + imageSize)
+                    abortOverrun();
+                memcpy(outP, inP, put);
+                got = put;
+            }
+            inP       += got;
+            outP      += put;
+            assert(bytesLeft >= put);
+            bytesLeft -= put;
+        }
+    }
+    *uncompressedP = uncompressed;
+}
+
+
+
+#define UNKNOWN_OFFSET  (uint32_t)-1
+
+static void
+readCompressed(IMAGE *    const imgP,
+               uint32_t   const end_offset,
+               FILE *     const fP,
+               size_t *   const dataSizeP,
+               uint8_t ** const dataP,
+               int *      const retvalP) {
+/*----------------------------------------------------------------------------
+   Read the compressed data from file *fP (actually, if the image isn't
+   compressed, then it's just the regular data).
+
+   Return the data in newly malloced storage as *dataP, which is
+   *dataSizeP bytes long.
+-----------------------------------------------------------------------------*/
+    int retval;
+    uint8_t * buffer;
+    size_t dataSize;
+
+    dataSize = 0;  /* initial value */
+
+    if (end_offset == UNKNOWN_OFFSET) {
+        /*
+         * Read until EOF. Some of them have an extra zero byte
+         * dangling off the end.  I originally thought this was
+         * an empty note record (even though there was no record
+         * header for it); however, the release notes for Image
+         * Compression Manager 1.1 on http://www.pilotgear.com
+         * note this extra byte as a bug in Image Compression
+         * Manager 1.0 which 1.1 fixes.  We'll just blindly read
+         * this extra byte and ignore it by paying attention to
+         * the image dimensions.
+         */
+        MALLOCARRAY(buffer, ipdb_img_size(imgP));
+
+        if (buffer == NULL)
+            retval = ENOMEM;
+        else {
+            dataSize = fread(buffer, 1, ipdb_img_size(imgP), fP);
+            if (dataSize <= 0)
+                retval = EIO;
+            else
+                retval = 0;
+
+            if (retval != 0)
+                free(buffer);
+        }
+    } else {
+        /*
+         * Read to the indicated offset.
+         */
+        dataSize = end_offset - ftell(fP) + 1;
+        
+        MALLOCARRAY(buffer, dataSize);
+
+        if (buffer == NULL)
+            retval = ENOMEM;
+        else {
+            ssize_t rc;
+            rc = fread(buffer, 1, dataSize, fP);
+            if (rc != dataSize)
+                retval = EIO;
+            else
+                retval = 0;
+
+            if (retval != 0)
+                free(buffer);
+        }
+    }
+    *dataSizeP = dataSize;
+    *dataP = buffer;
+    *retvalP = retval;
+}
+
+
+
+static void
+imageReadHeader(FILE *  const fileP,
+                IMAGE * const imgP,
+                bool    const dump) {
+
+    fread(&imgP->name, 1, 32, fileP);
+    pm_readcharu(fileP, &imgP->version);
+    pm_readcharu(fileP, &imgP->type);
+    fread(&imgP->reserved1, 1, 4, fileP);
+    fread(&imgP->note, 1, 4, fileP);
+    pm_readbigshortu(fileP, &imgP->x_last);
+    pm_readbigshortu(fileP, &imgP->y_last);
+    fread(&imgP->reserved2, 1, 4, fileP);
+    pm_readbigshortu(fileP, &imgP->x_anchor);
+    pm_readbigshortu(fileP, &imgP->y_anchor);
+    pm_readbigshortu(fileP, &imgP->width);
+    pm_readbigshortu(fileP, &imgP->height);
+
+    if (dump) {
+        pm_message("PDB IMAGE header:");
+        pm_message("  Name: '%.*s'", (int)sizeof(imgP->name), imgP->name);
+        pm_message("  Version: %02x", imgP->version);
+        pm_message("  Type: %s", ipdb_typeName(imgP->type));
+        pm_message("  Note: %02x %02x %02x %02x",
+                   imgP->note[0], imgP->note[1], imgP->note[2], imgP->note[3]);
+        pm_message("  X_last: %u", imgP->x_last);
+        pm_message("  Y_last: %u", imgP->y_last);
+        pm_message("  X_anchor: %u", imgP->x_anchor);
+        pm_message("  Y_anchor: %u", imgP->y_anchor);
+        pm_message("  Width: %u", imgP->width);
+        pm_message("  Height: %u", imgP->height);
+        pm_message("Pixels per byte: %u", ipdb_img_ppb(imgP));
+        pm_message("Image size: %lu bytes",
+                   (unsigned long)ipdb_img_size(imgP));
+    }
+}
+
+
+static int
+imageReadData(FILE *   const fileP,
+              IMAGE *  const imgP,
+              uint32_t const end_offset) {
+
+    int retval;
+    size_t dataSize;
+    uint8_t * buffer;
+
+    readCompressed(imgP, end_offset, fileP, &dataSize, &buffer, &retval);
+
+    if (retval == 0) {
+        /*
+         * Compressed data can cross row boundaries so we decompress
+         * the data here to avoid messiness in the row access functions.
+         */
+        if (dataSize != ipdb_img_size(imgP)) {
+            decompress(buffer, dataSize, ipdb_img_size(imgP), &imgP->data);
+            if (imgP->data == NULL)
+                retval = ENOMEM;
+            else
+                imgP->compressed = true;
+            free(buffer);
+        } else {
+            imgP->compressed = false;
+            imgP->data       = buffer;
+            /* Storage at 'buffer' now belongs to *imgP */
+        }
+    }
+    return retval;
+}
+
+
+
+static int
+imageRead(IMAGE *  const imgP,
+          uint32_t const end_offset,
+          FILE *   const fileP,
+          bool     const verbose) {
+
+    if (imgP) {
+        imgP->r->offset = (uint32_t)ftell(fileP);
+
+        imageReadHeader(fileP, imgP, verbose);
+
+        imageReadData(fileP, imgP, end_offset);
+    }
+    return 0;
+}
+
+
+
+static int
+textRead(TEXT * const textP,
+         FILE * const fileP) {
+
+    int retval;
+    char    * s;
+    char    buf[128];
+    int used, alloced, len;
+
+    if (textP == NULL)
+        return 0;
+
+    textP->r->offset = (uint32_t)ftell(fileP);
+    
+    /*
+     * What a pain in the ass!  Why the hell isn't there a length
+     * attached to the text record?  I suppose the designer wasn't
+     * concerned about non-seekable (i.e. pipes) input streams.
+     * Perhaps I'm being a little harsh, the lack of a length probably
+     * isn't much of an issue on the Pilot.
+     */
+    used    = 0;
+    alloced = 0;
+    s       = NULL;
+    retval = 0;  /* initial value */
+    while ((len = fread(buf, 1, sizeof(buf), fileP)) != 0 && retval == 0) {
+        if (buf[len - 1] == '\0')
+            --len;
+        if (used + len > alloced) {
+            alloced += 2 * sizeof(buf);
+            REALLOCARRAY(s, alloced);
+
+            if (s == NULL)
+                retval = ENOMEM;
+        }
+        if (retval == 0) {
+            memcpy(s + used, buf, len);
+            used += len;
+        }
+    }
+    if (retval == 0) {
+        textP->data = calloc(1, used + 1);
+        if (textP->data == NULL)
+            retval = ENOMEM;
+        else
+            memcpy(textP->data, s, used);
+    }
+    if (s)
+        free(s);
+
+    return retval;
+}
+
+
+
+static int
+pdbheadRead(PDBHEAD * const pdbHeadP,
+            FILE *    const fileP) {
+
+    int retval;
+
+    fread(pdbHeadP->name, 1, 32, fileP);
+    pm_readbigshortu(fileP, &pdbHeadP->flags);
+    pm_readbigshortu(fileP, &pdbHeadP->version);
+    pm_readbiglongu2(fileP, &pdbHeadP->ctime);
+    pm_readbiglongu2(fileP, &pdbHeadP->mtime);
+    pm_readbiglongu2(fileP, &pdbHeadP->btime);
+    pm_readbiglongu2(fileP, &pdbHeadP->mod_num);
+    pm_readbiglongu2(fileP, &pdbHeadP->app_info);
+    pm_readbiglongu2(fileP, &pdbHeadP->sort_info);
+    fread(pdbHeadP->type, 1, 4,  fileP);
+    fread(pdbHeadP->id,   1, 4,  fileP);
+    pm_readbiglongu2(fileP, &pdbHeadP->uniq_seed);
+    pm_readbiglongu2(fileP, &pdbHeadP->next_rec);
+    pm_readbigshortu(fileP, &pdbHeadP->num_recs);
+
+    if (!memeq(pdbHeadP->type, IPDB_vIMG, 4) 
+        || !memeq(pdbHeadP->id, IPDB_View, 4))
+        retval = E_NOTIMAGE;
+    else
+        retval = 0;
+
+    return retval;
+}
+
+
+
+static int
+rechdrRead(RECHDR * const rechdrP,
+           FILE *   const fileP) {
+
+    int retval;
+    off_t   len;
+
+    pm_readbiglongu2(fileP, &rechdrP->offset);
+
+    len = (off_t)rechdrP->offset - ftell(fileP);
+    switch(len) {
+    case 4:
+    case 12:
+        /*
+         * Version zero (eight bytes of record header) or version
+         * two with a note (two chunks of eight record header bytes).
+         */
+        fread(&rechdrP->unknown[0], 1, 3, fileP);
+        fread(&rechdrP->rec_type,   1, 1, fileP);
+        rechdrP->n_extra = 0;
+        rechdrP->extra   = NULL;
+        retval = 0;
+        break;
+    case 6:
+        /*
+         * Version one (ten bytes of record header).
+         */
+        fread(&rechdrP->unknown[0], 1, 3, fileP);
+        fread(&rechdrP->rec_type,   1, 1, fileP);
+        rechdrP->n_extra = 2;
+        MALLOCARRAY(rechdrP->extra, rechdrP->n_extra);
+        if (rechdrP->extra == NULL)
+            retval = ENOMEM;
+        else {
+            fread(rechdrP->extra, 1, rechdrP->n_extra, fileP);
+            retval = 0;
+        }
+        break;
+    default:
+        /*
+         * hmmm.... I'll assume this is the record header
+         * for a text record.
+         */
+        fread(&rechdrP->unknown[0], 1, 3, fileP);
+        fread(&rechdrP->rec_type,   1, 1, fileP);
+        rechdrP->n_extra = 0;
+        rechdrP->extra   = NULL;
+        retval = 0;
+        break;
+    }
+    if (retval == 0) {
+        if ((rechdrP->rec_type != IMG_REC && rechdrP->rec_type != TEXT_REC)
+            || !memeq(rechdrP->unknown, IPDB_MYST, 3))
+            retval = E_NOTRECHDR;
+    }
+    return retval;
+}
+
+
+
+static int
+ipdbRead(IPDB * const pdbP,
+         FILE * const fileP,
+         bool   const verbose) {
+
+    int retval;
+
+    ipdb_clear(pdbP);
+
+    pdbP->p = ipdb_pdbhead_alloc(NULL);
+
+    if (pdbP->p == NULL)
+        retval = ENOMEM;
+    else {
+        int status;
+
+        status = pdbheadRead(pdbP->p, fileP);
+
+        if (status != 0)
+            retval = status;
+        else {
+            pdbP->i = ipdb_image_alloc(pdbP->p->name, IMG_GRAY, 0, 0);
+            if (pdbP->i == NULL)
+                retval = ENOMEM;
+            else {
+                int status;
+                status = rechdrRead(pdbP->i->r, fileP);
+                if (status != 0)
+                    retval = status;
+                else {
+                    if (pdbP->p->num_recs > 1) {
+                        pdbP->t = ipdb_text_alloc(NULL);
+                        if (pdbP->t == NULL)
+                            retval = ENOMEM;
+                        else {
+                            int status;
+                            status = rechdrRead(pdbP->t->r, fileP);
+                            if (status != 0)
+                                retval = status;
+                            else
+                                retval = 0;
+                        }
+                    } else
+                        retval = 0;
+                    
+                    if (retval == 0) {
+                        uint32_t const offset =
+                            pdbP->t == NULL ?
+                            UNKNOWN_OFFSET : pdbP->t->r->offset - 1;
+
+                        int status;
+
+                        status = imageRead(pdbP->i, offset, fileP, verbose);
+                        if (status != 0)
+                            retval = status;
+                        else {
+                            if (pdbP->t != NULL) {
+                                int status;
+                                
+                                status = textRead(pdbP->t, fileP);
+                                if (status != 0)
+                                    retval = status;
+                            }
+                        }
+                    }
+                }
+            }
+        }
+    }
+    return retval;
+}
+
+
+
+static void
+g16unpack(const uint8_t * const p,
+          uint8_t *       const g,
+          int             const w) {
+
+    static const uint8_t pal[] =
+        {0xff, 0xee, 0xdd, 0xcc, 0xbb, 0xaa, 0x99, 0x88,
+         0x77, 0x66, 0x55, 0x44, 0x33, 0x22, 0x11, 0x00};
+    const uint8_t * seg;
+    unsigned int i;
+
+    for (i = 0, seg = p; i < w; i += 2, ++seg) {
+        g[i + 0] = pal[getg16pixel(*seg, 0)];
+        g[i + 1] = pal[getg16pixel(*seg, 1)];
+    }
+}
+
+
+
+static void
+gunpack(const uint8_t * const p,
+        uint8_t *       const g,
+        int             const w) {
+
+    static const uint8_t pal[] = {0xff, 0xaa, 0x55, 0x00};
+    const uint8_t * seg;
+    unsigned int i;
+
+    for (i = 0, seg = p; i < w; i += 4, ++seg) {
+        g[i + 0] = pal[getgpixel(*seg, 0)];
+        g[i + 1] = pal[getgpixel(*seg, 1)];
+        g[i + 2] = pal[getgpixel(*seg, 2)];
+        g[i + 3] = pal[getgpixel(*seg, 3)];
+    }
+}
+
+
+
+static void
+munpack(const uint8_t * const p,
+        uint8_t *       const b,
+        int             const w) {
+
+    static const uint8_t pal[] = {PAM_BW_WHITE, PAM_BLACK};
+    const uint8_t * seg;
+    unsigned int i;
+
+    for (i = 0, seg = p; i < w; i += 8, ++seg) {
+        b[i + 0] = pal[getmpixel(*seg, 0)];
+        b[i + 1] = pal[getmpixel(*seg, 1)];
+        b[i + 2] = pal[getmpixel(*seg, 2)];
+        b[i + 3] = pal[getmpixel(*seg, 3)];
+        b[i + 4] = pal[getmpixel(*seg, 4)];
+        b[i + 5] = pal[getmpixel(*seg, 5)];
+        b[i + 6] = pal[getmpixel(*seg, 6)];
+        b[i + 7] = pal[getmpixel(*seg, 7)];
+    }
+}
+
+
+
+static void
+g16row(IPDB *       const pdbP,
+       unsigned int const row,
+       uint8_t *    const buffer) {
+    
+    g16unpack(ipdb_img_row(pdbP->i, row), buffer, ipdb_width(pdbP));
+}
+
+
+
+static void
+grow(IPDB *       const pdbP,
+     unsigned int const row,
+     uint8_t *    const buffer) {
+
+    gunpack(ipdb_img_row(pdbP->i, row), buffer, ipdb_width(pdbP));
+}
+
+
+
+static void
+mrow(IPDB *       const pdbP,
+     unsigned int const row,
+     uint8_t *    const buffer) {
+
+    munpack(ipdb_img_row(pdbP->i, row), buffer, ipdb_width(pdbP));
+}
+
+
+
+static void
+writeImgPam(IPDB * const pdbP,
+            FILE * const ofP) {
+
+    struct pam pam;
+    tuple * tupleRow;
+    unsigned int row;
+    uint8_t * imgRow;
+
+    MALLOCARRAY(imgRow, ipdb_width(pdbP));
+
+    pam.size             = sizeof(pam);
+    pam.len              = PAM_STRUCT_SIZE(tuple_type);
+    pam.file             = ofP;
+    pam.plainformat      = 0;
+    pam.width            = ipdb_width(pdbP);
+    pam.height           = ipdb_height(pdbP);
+    pam.depth            = 1;
+    pam.maxval           = ipdb_type(pdbP) == IMG_MONO ? 1 : 255;
+    pam.bytes_per_sample = pnm_bytespersample(pam.maxval);
+    pam.format           = PAM_FORMAT;
+    strcpy(pam.tuple_type,
+           ipdb_type(pdbP) == IMG_MONO ?
+           PAM_PBM_TUPLETYPE : PAM_PGM_TUPLETYPE);
+
+    pnm_writepaminit(&pam);
+    
+    tupleRow = pnm_allocpamrow(&pam);
+
+    for (row = 0; row < pam.height; ++row) {
+        unsigned int col;
+
+
+        if (ipdb_type(pdbP) == IMG_MONO)
+            mrow(pdbP, row, imgRow);
+        else if (ipdb_type(pdbP) == IMG_GRAY)
+            grow(pdbP, row, imgRow);
+        else
+            g16row(pdbP, row, imgRow);
+
+        for (col = 0; col < pam.width; ++col)
+            tupleRow[col][0] = imgRow[col];
+        
+        pnm_writepamrow(&pam, tupleRow);
+    }
+    pnm_freepamrow(tupleRow);
+
+    free(imgRow);
+}
+
+
+
+static void
+writeText(IPDB *       const pdbP,
+          const char * const name) {
+
+    const char * const note = ipdb_text(pdbP);
+
+    FILE * fP;
+
+    if (name == NULL || note == NULL) {
+    } else {
+        fP = pm_openw(name);
+        if (fP == NULL)
+            pm_error("Could not open note file '%s' for output", name);
+        
+        fprintf(fP, "%s\n", note);
+
+        pm_close(fP);
+    }
+}
+
+
+
+int
+main(int argc, const char ** argv) {
+
+    struct cmdlineInfo cmdline;
+    FILE * ifP;
+    IPDB * pdbP;
+    int status;
+
+    pm_proginit(&argc, argv);
+
+    parseCommandLine(argc, argv, &cmdline);
+
+    ifP = pm_openr(cmdline.inputFileName);
+
+    pdbP = ipdb_alloc(NULL);
+    if (pdbP == NULL)
+        pm_error("Could not allocate IPDB structure.");
+
+    status = ipdbRead(pdbP, ifP, cmdline.verbose);
+    if (status != 0)
+        pm_error("Image header read error: %s.", ipdb_err(status));
+
+    writeImgPam(pdbP, stdout);
+
+    writeText(pdbP, cmdline.notefile);
+
+    ipdb_free(pdbP);
+
+    pm_close(ifP);
+
+    return EXIT_SUCCESS;
+}
diff --git a/converter/other/pfmtopam.c b/converter/other/pfmtopam.c
index 1617ed31..080ec7ff 100644
--- a/converter/other/pfmtopam.c
+++ b/converter/other/pfmtopam.c
@@ -45,7 +45,7 @@ parseCommandLine(int argc,
    was passed to us as the argv array.  We also trash *argv.
 --------------------------------------------------------------------------*/
     optEntry *option_def = malloc( 100*sizeof( optEntry ) );
-    /* Instructions to optParseOptions3 on how to parse our options. */
+    /* Instructions to pm_optParseOptions3 on how to parse our options. */
     optStruct3 opt;
   
     unsigned int option_def_index;
@@ -59,7 +59,7 @@ parseCommandLine(int argc,
     opt.short_allowed = FALSE;  /* We have no short (old-fashioned) options */
     opt.allowNegNum = FALSE;   /* We have no parms that are negative numbers */
 
-    optParseOptions3( &argc, argv, opt, sizeof(opt), 0 );
+    pm_optParseOptions3( &argc, argv, opt, sizeof(opt), 0 );
     /* Uses and sets argc, argv, and some of *cmdline_p and others. */
 
     if (!maxvalSpec)
diff --git a/converter/other/pgmtopbm.c b/converter/other/pgmtopbm.c
index f828b716..67cac468 100644
--- a/converter/other/pgmtopbm.c
+++ b/converter/other/pgmtopbm.c
@@ -44,7 +44,7 @@ parseCommandLine(int argc, char ** argv,
    was passed to us as the argv array.
 -----------------------------------------------------------------------------*/
     optEntry *option_def;
-        /* Instructions to optParseOptions3 on how to parse our options.
+        /* Instructions to pm_optParseOptions3 on how to parse our options.
          */
     optStruct3 opt;
 
@@ -77,7 +77,7 @@ parseCommandLine(int argc, char ** argv,
     opt.short_allowed = FALSE;  /* We have no short (old-fashioned) options */
     opt.allowNegNum = FALSE;  /* We may have parms that are negative numbers */
 
-    optParseOptions3(&argc, argv, opt, sizeof(opt), 0);
+    pm_optParseOptions3(&argc, argv, opt, sizeof(opt), 0);
         /* Uses and sets argc, argv, and some of *cmdlineP and others. */
 
     if (floydOpt + thresholdOpt + hilbertOpt + dither8Opt + 
@@ -585,6 +585,7 @@ createDither8Converter(unsigned int const cols,
     converter.convertRow = &dither8ConvertRow;
     converter.destroy = dither8Destroy;
     converter.stateP = stateP;
+    converter.maxval = maxval;
 
     /* Scale dither matrix. */
     for (row = 0; row < 16; ++row) {
@@ -660,6 +661,7 @@ createClusterConverter(unsigned int const radius,
     unsigned int row;
 
     converter.cols = cols;
+    converter.maxval = maxval;
     converter.convertRow = &clusterConvertRow;
     converter.destroy = &clusterDestroy;
 
diff --git a/converter/other/pgmtoppm.c b/converter/other/pgmtoppm.c
index 7194db49..f8a69424 100644
--- a/converter/other/pgmtoppm.c
+++ b/converter/other/pgmtoppm.c
@@ -10,6 +10,7 @@
 ** implied warranty.
 */
 
+#define _XOPEN_SOURCE 500  /* Make sure strdup() is in string.h */
 #define _BSD_SOURCE  /* Make sure strdup() is in <string.h> */
 #include <string.h>
 
@@ -44,7 +45,7 @@ parseCommandLine(int argc, char ** argv,
    was passed to us as the argv array.  We also trash *argv.
 -----------------------------------------------------------------------------*/
     optEntry *option_def;
-        /* Instructions to optParseOptions3 on how to parse our options.
+        /* Instructions to pm_optParseOptions3 on how to parse our options.
          */
     optStruct3 opt;
 
@@ -62,7 +63,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 */
 
-    optParseOptions3(&argc, argv, opt, sizeof(opt), 0);
+    pm_optParseOptions3(&argc, argv, opt, sizeof(opt), 0);
         /* Uses and sets argc, argv, and some of *cmdlineP and others. */
 
     if (!mapSpec)
diff --git a/converter/other/pngtopam.c b/converter/other/pngtopam.c
index 89ac100a..8743174e 100644
--- a/converter/other/pngtopam.c
+++ b/converter/other/pngtopam.c
@@ -21,65 +21,52 @@
 #include <assert.h>
 #include <math.h>
 #include <float.h>
-#include <png.h>    /* includes zlib.h and setjmp.h */
-#define VERSION "2.37.4 (5 December 1999) +netpbm"
+#include <png.h>
+/* Becaues of a design error in png.h, you must not #include <setjmp.h> before
+   <png.h>.  If you do, png.h won't compile.
+*/
+#include <setjmp.h>
+#include <zlib.h>
+
 
 #include "pm_c_util.h"
 #include "mallocvar.h"
 #include "nstring.h"
 #include "shhopt.h"
 #include "pam.h"
+#include "pngx.h"
 
-/* A hack until we can remove direct access to png_info from the program */
-#if PNG_LIBPNG_VER >= 10400
-#define trans_values trans_color
-#define TRANS_ALPHA trans_alpha
-#else
-#define TRANS_ALPHA trans
-#endif
-
-typedef struct _jmpbuf_wrapper {
-  jmp_buf jmpbuf;
-} jmpbuf_wrapper;
+enum AlphaHandling {ALPHA_NONE, ALPHA_ONLY, ALPHA_MIX, ALPHA_IN};
 
-enum alpha_handling {ALPHA_NONE, ALPHA_ONLY, ALPHA_MIX, ALPHA_IN};
+typedef struct {
+    bool needCorrection;
+    double gamma;
+} GammaCorrection;
 
-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 * inputFileName;  /* '-' if stdin */
     unsigned int verbose;
-    enum alpha_handling alpha;
+    enum AlphaHandling alpha;
     const char * background;
-    float gamma;  /* -1.0 means unspecified */
+    unsigned int gammaSpec;
+    float gamma;
     const char * text;
     unsigned int time;
+    unsigned int byrow;
 };
 
 
-typedef struct {
-/*----------------------------------------------------------------------------
-   A color in a format compatible with the PNG library.
-
-   Note that the PNG library declares types png_color and png_color_16
-   which are similar.
------------------------------------------------------------------------------*/
-    png_uint_16 r;
-    png_uint_16 g;
-    png_uint_16 b;
-} pngcolor;
-
-
-static png_uint_16 maxval;
 static bool verbose;
-static jmpbuf_wrapper pngtopnm_jmpbuf_struct;
+
 
 
 static void
 parseCommandLine(int                  argc, 
                  const char **        argv,
-                 struct cmdlineInfo * cmdlineP ) {
+                 struct CmdlineInfo * cmdlineP ) {
 /*----------------------------------------------------------------------------
    Parse program command line described in Unix standard form by argc
    and argv.  Return the information in the options as *cmdlineP.  
@@ -91,14 +78,14 @@ parseCommandLine(int                  argc,
    was passed to us as the argv array.  We also trash *argv.
 -----------------------------------------------------------------------------*/
     optEntry * option_def;
-        /* Instructions to optParseOptions3 on how to parse our options.
+        /* Instructions to pm_optParseOptions3 on how to parse our options.
          */
     optStruct3 opt;
 
     unsigned int option_def_index;
 
     unsigned int alphaSpec, alphapamSpec, mixSpec,
-        backgroundSpec, gammaSpec, textSpec;
+        backgroundSpec, textSpec;
 
     MALLOCARRAY(option_def, 100);
 
@@ -114,17 +101,19 @@ parseCommandLine(int                  argc,
     OPTENT3(0, "background",  OPT_STRING, &cmdlineP->background,
             &backgroundSpec,          0);
     OPTENT3(0, "gamma",       OPT_FLOAT,  &cmdlineP->gamma,
-            &gammaSpec,               0);
+            &cmdlineP->gammaSpec,     0);
     OPTENT3(0, "text",        OPT_STRING, &cmdlineP->text,
             &textSpec,                0);
     OPTENT3(0, "time",        OPT_FLAG,   NULL,                  
             &cmdlineP->time,          0);
+    OPTENT3(0, "byrow",       OPT_FLAG,   NULL,                  
+            &cmdlineP->byrow,         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 */
 
-    optParseOptions3(&argc, (char **)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. */
 
 
@@ -145,16 +134,13 @@ parseCommandLine(int                  argc,
     if (!backgroundSpec)
         cmdlineP->background = NULL;
 
-    if (!gammaSpec)
-        cmdlineP->gamma = -1.0;
-
     if (!textSpec)
         cmdlineP->text = NULL;
 
     if (argc-1 < 1)
-        cmdlineP->inputFilespec = "-";
+        cmdlineP->inputFileName = "-";
     else if (argc-1 == 1)
-        cmdlineP->inputFilespec = argv[1];
+        cmdlineP->inputFileName = argv[1];
     else
         pm_error("Program takes at most one argument: input file name.  "
             "you specified %d", argc-1);
@@ -162,18 +148,299 @@ parseCommandLine(int                  argc,
 
 
 
+typedef struct {
+/*----------------------------------------------------------------------------
+   A color in a format compatible with the PNG library.
+
+   Note that the PNG library declares types png_color and png_color_16
+   which are similar.
+-----------------------------------------------------------------------------*/
+    png_uint_16 r;
+    png_uint_16 g;
+    png_uint_16 b;
+} pngcolor;
+
+
+
+static pngcolor
+pngcolorFrom16(png_color_16 const arg) {
+
+    pngcolor retval;
+
+    retval.r = arg.red;
+    retval.g = arg.green;
+    retval.b = arg.blue;
+
+    return retval;
+}
+
+
+
+static pngcolor
+pngcolorFromByte(png_color const arg) {
+
+    pngcolor retval;
+
+    retval.r = arg.red;
+    retval.g = arg.green;
+    retval.b = arg.blue;
+
+    return retval;
+}
+
+
+
+static bool
+pngColorEqual(pngcolor const comparand,
+              pngcolor const comparator) {
+
+    return (comparand.r == comparator.r
+            && comparand.g == comparator.g
+            && comparand.b == comparator.b);
+}
+
+
+
+static png_uint_16
+gammaCorrect(png_uint_16     const uncorrected,
+             GammaCorrection const gamma,
+             png_uint_16     const maxval) {
+
+    if (gamma.needCorrection) {
+        double const uncorrectedN = (double) uncorrected / maxval;
+        return (png_uint_16)
+            ROUNDU(pow(uncorrectedN, (1.0 / gamma.gamma)) * maxval);
+    } else
+        return uncorrected;
+}
+
+
+
+static pngcolor
+gammaCorrectColor(pngcolor        const color,
+                  GammaCorrection const gamma,
+                  png_uint_16     const maxval) {
+
+    pngcolor retval;
+
+    retval.r = gammaCorrect(color.r, gamma, maxval);
+
+    return retval;
+}
+
+
+
+static unsigned int
+computePngLineSize(struct pngx * const pngxP) {
+
+    unsigned int const bytesPerSample =
+        pngx_bitDepth(pngxP) == 16 ? 2 : 1;
+
+    unsigned int samplesPerPixel;
+
+    switch (pngx_colorType(pngxP)) {
+    case PNG_COLOR_TYPE_GRAY_ALPHA: samplesPerPixel = 2; break;
+    case PNG_COLOR_TYPE_RGB:        samplesPerPixel = 3; break;
+    case PNG_COLOR_TYPE_RGB_ALPHA:  samplesPerPixel = 4; break;
+    default:                        samplesPerPixel = 1;
+    }
+
+    if (UINT_MAX / bytesPerSample / samplesPerPixel < pngx_imageWidth(pngxP))
+        pm_error("Width %u of PNG is uncomputably large",
+                 pngx_imageWidth(pngxP));
+       
+    return pngx_imageWidth(pngxP) * bytesPerSample * samplesPerPixel;
+}
+
+
+
+static void
+allocPngRaster(struct pngx * const pngxP,
+               png_byte ***  const pngImageP) {
+
+    unsigned int const lineSize = computePngLineSize(pngxP);
+
+    png_byte ** pngImage;
+    unsigned int row;
+
+    MALLOCARRAY(pngImage, pngx_imageHeight(pngxP));
+
+    if (pngImage == NULL)
+        pm_error("couldn't allocate index space for %u PNG raster rows.  "
+                 "Try -byrow, which needs only 1 row of buffer space.  ",
+                 pngx_imageHeight(pngxP));
+
+    for (row = 0; row < pngx_imageHeight(pngxP); ++row) {
+        MALLOCARRAY(pngImage[row], lineSize);
+        if (pngImage[row] == NULL)
+            pm_error("couldn't allocate space for %uth row of PNG raster.  "
+                     "Try -byrow, which needs only 1 row of buffer space.  ",
+                     row);
+    }
+    *pngImageP = pngImage;
+}
+
+
+
+static void
+freePngRaster(png_byte **   const pngRaster,
+              struct pngx * const pngxP) {
+
+    unsigned int row;
+
+    for (row = 0; row < pngx_imageHeight(pngxP); ++row)
+        free(pngRaster[row]);
+
+    free(pngRaster);
+}
+
+
+
+typedef struct {
+/*----------------------------------------------------------------------------
+   This is an object for reading the raster of the PNG, a row at a time.
+-----------------------------------------------------------------------------*/
+    struct pngx * pngxP;
+    png_byte **   pngRaster;
+        /* The entire raster of the PNG.  Null if this is a
+           row-at-a-time object.  Constant.
+
+           We give a pointer into this to the user.
+        */
+    png_byte * rowBuf;
+        /* The buffer in which we put the most recently read row.
+           Null if this is an all-at-once object.  Constant.
+
+           We give a pointer into this to the user.
+        */
+    unsigned int  nextRowNum;
+        /* The number of the next row to be read from this object. */
+
+} Reader;
+
+
+
+static Reader *
+reader_createAllAtOnce(struct pngx * const pngxP,
+                       FILE *        const ifP) {
+/*----------------------------------------------------------------------------
+   Create a Reader object that uses libpng's all-at-once raster reading
+   interface (libpng calls this the "high level" interface).
+
+   The Reader object reads the PNG at construction time, stores the entire
+   raster, and hands it out as you call reader_read().
+
+   It is essential that *pngxP be already fully set up to read the image
+   (all options set).
+-----------------------------------------------------------------------------*/
+    Reader * readerP;
+
+    MALLOCVAR_NOFAIL(readerP);
+
+    readerP->pngxP = pngxP;
+
+    allocPngRaster(pngxP, &readerP->pngRaster);
+
+    readerP->rowBuf = NULL;
+
+    pngx_readImage(pngxP, readerP->pngRaster);
+
+    readerP->nextRowNum = 0;
+
+    return readerP;
+}
+
+
+
+static Reader *
+reader_createRowByRow(struct pngx * const pngxP,
+                      FILE *        const ifP) {
+/*----------------------------------------------------------------------------
+   Create a Reader object that uses libpng's one-row-at-a-time raster reading
+   interface (libpng calls this the "low level" interface).
+
+   The Reader object reads from the PNG file, via libpng, as its client
+   requests the rows.
+-----------------------------------------------------------------------------*/
+    Reader * readerP;
+
+    MALLOCVAR_NOFAIL(readerP);
+
+    readerP->pngxP = pngxP;
+
+    readerP->pngRaster = NULL;
+
+    MALLOCARRAY(readerP->rowBuf, computePngLineSize(pngxP)); 
+
+    if (!readerP->rowBuf)
+        pm_error("Could not allocate %u bytes for a PNG row buffer",
+                 computePngLineSize(pngxP));
+
+    readerP->nextRowNum = 0;
+
+    if (pngx_interlaceType(pngxP) != PNG_INTERLACE_NONE)
+        pm_message("WARNING: this is an interlaced PNG.  The PAM output "
+                   "will be interlaced.  To get proper output, "
+                   "don't use -byrow");
+
+    return readerP;
+}
+
+
+
+static void
+reader_destroy(Reader * const readerP) {
+
+    if (readerP->pngRaster)
+        freePngRaster(readerP->pngRaster, readerP->pngxP);
+   
+    if (readerP->rowBuf)
+        free(readerP->rowBuf);
+
+    free(readerP);
+}
+
+
+
+static png_byte *
+reader_read(Reader * const readerP) {
+/*----------------------------------------------------------------------------
+   Return a pointer to the next row of the raster.
+
+   The pointer is into storage owned by this object.  It is good until
+   the next read from the object, while the object exists.
+-----------------------------------------------------------------------------*/
+    png_byte * retval;
+
+    if (readerP->pngRaster) {
+        if (readerP->nextRowNum >= pngx_imageHeight(readerP->pngxP))
+            retval = NULL;
+        else
+            retval = readerP->pngRaster[readerP->nextRowNum];
+    } else {
+        pngx_readRow(readerP->pngxP, readerP->rowBuf, NULL);
+        retval = readerP->rowBuf;
+    }
+
+    ++readerP->nextRowNum;
+
+    return retval;
+}
+
+
+
 static png_uint_16
-get_png_val(const png_byte ** const pp,
-            int               const bit_depth) {
+getPngVal(const png_byte ** const pp,
+          int               const bitDepth) {
 
     png_uint_16 c;
     
-    if (bit_depth == 16)
-        c = (*((*pp)++)) << 8;
+    if (bitDepth == 16)
+        c = *(*pp)++ << 8;
     else
         c = 0;
 
-    c |= (*((*pp)++));
+    c |= *(*pp)++;
     
     return c;
 }
@@ -207,13 +474,14 @@ setTuple(const struct pam *  const pamP,
          tuple               const tuple,
          pngcolor            const foreground,
          pngcolor            const background,
-         enum alpha_handling const alphaHandling,
+         enum AlphaHandling  const alphaHandling,
+         const struct pngx * const pngxP,
          png_uint_16         const alpha) {
 
     if (alphaHandling == ALPHA_ONLY)
         tuple[0] = alpha;
     else if (alphaHandling == ALPHA_NONE ||
-             (alphaHandling == ALPHA_MIX && alpha == maxval)) {
+             (alphaHandling == ALPHA_MIX && alpha == pngxP->maxval)) {
         if (pamP->depth < 3)
             tuple[0] = foreground.r;
         else {
@@ -236,227 +504,228 @@ setTuple(const struct pam *  const pamP,
 
         if (pamP->depth < 3)
             tuple[0] =
-                alphaMix(foreground.r, background.r, alpha, maxval);
+                alphaMix(foreground.r, background.r, alpha, pngxP->maxval);
         else {
             tuple[PAM_RED_PLANE] =
-                alphaMix(foreground.r, background.r, alpha, maxval);
+                alphaMix(foreground.r, background.r, alpha, pngxP->maxval);
             tuple[PAM_GRN_PLANE] =
-                alphaMix(foreground.g, background.g, alpha, maxval);
+                alphaMix(foreground.g, background.g, alpha, pngxP->maxval);
             tuple[PAM_BLU_PLANE] =
-                alphaMix(foreground.b, background.b, alpha, maxval);
+                alphaMix(foreground.b, background.b, alpha, pngxP->maxval);
         }
     }
 }
 
 
 
-static png_uint_16
-gamma_correct(png_uint_16 const v,
-              float       const g) {
+static bool
+isColor(png_color const c) {
 
-    if (g != -1.0)
-        return (png_uint_16) ROUNDU(pow((double) v / maxval, (1.0 / g)) *
-                                    maxval);
-    else
-        return v;
+    return c.red != c.green || c.green != c.blue;
 }
 
 
 
-static int iscolor (png_color c)
-{
-  return c.red != c.green || c.green != c.blue;
-}
+static void
+saveText(struct pngx * const pngxP,
+         FILE *        const tfP) {
 
-static void save_text (png_info *info_ptr, FILE *tfp)
-{
-  int i, j, k;
-
-  for (i = 0 ; i < info_ptr->num_text ; i++) {
-    j = 0;
-    while (info_ptr->text[i].key[j] != '\0' && info_ptr->text[i].key[j] != ' ')
-      j++;    
-    if (info_ptr->text[i].key[j] != ' ') {
-      fprintf (tfp, "%s", info_ptr->text[i].key);
-      for (j = strlen (info_ptr->text[i].key) ; j < 15 ; j++)
-        putc (' ', tfp);
-    } else {
-      fprintf (tfp, "\"%s\"", info_ptr->text[i].key);
-      for (j = strlen (info_ptr->text[i].key) ; j < 13 ; j++)
-        putc (' ', tfp);
-    }
-    putc (' ', tfp); /* at least one space between key and text */
+    struct pngx_text const text = pngx_text(pngxP);
+
+    unsigned int i;
+
+    for (i = 0 ; i < text.size; ++i) {
+        unsigned int j;
+        j = 0;
+
+        while (text.line[i].key[j] != '\0' &&
+               text.line[i].key[j] != ' ')
+            ++j;    
+
+        if (text.line[i].key[j] != ' ') {
+            fprintf(tfP, "%s", text.line[i].key);
+            for (j = strlen (text.line[i].key); j < 15; ++j)
+                putc(' ', tfP);
+        } else {
+            fprintf(tfP, "\"%s\"", text.line[i].key);
+            for (j = strlen (text.line[i].key); j < 13; ++j)
+                putc(' ', tfP);
+        }
+        putc(' ', tfP); /* at least one space between key and text */
     
-    for (j = 0 ; j < info_ptr->text[i].text_length ; j++) {
-      putc (info_ptr->text[i].text[j], tfp);
-      if (info_ptr->text[i].text[j] == '\n')
-        for (k = 0 ; k < 16 ; k++)
-          putc ((int)' ', tfp);
+        for (j = 0; j < text.line[i].text_length; ++j) {
+            putc(text.line[i].text[j], tfP);
+            if (text.line[i].text[j] == '\n') {
+                unsigned int k;
+                for (k = 0; k < 16; ++k)
+                    putc(' ', tfP);
+            }
+        }
+        putc('\n', tfP);
     }
-    putc ((int)'\n', tfp);
-  }
 }
 
-static void show_time (png_info *info_ptr)
-{
-    static const char * const month[] = {
-        "", "January", "February", "March", "April", "May", "June",
-        "July", "August", "September", "October", "November", "December"
-    };
-
-  if (info_ptr->valid & PNG_INFO_tIME) {
-    if (info_ptr->mod_time.month < 1 ||
-      info_ptr->mod_time.month >= ARRAY_SIZE(month)) {
-      pm_message("tIME chunk in PNG input is invalid; "
-                 "modification time of image is unknown.  "
-                 "The month value, which should be in the range "
-                 "1-12, is %u", info_ptr->mod_time.month);
-    } else
-    pm_message ("modification time: %02d %s %d %02d:%02d:%02d",
-                info_ptr->mod_time.day, month[info_ptr->mod_time.month],
-                info_ptr->mod_time.year, info_ptr->mod_time.hour,
-                info_ptr->mod_time.minute, info_ptr->mod_time.second);
-  }
-}
 
-static void pngtopnm_error_handler (png_structp png_ptr, png_const_charp msg)
-{
-  jmpbuf_wrapper  *jmpbuf_ptr;
 
-  /* this function, aside from the extra step of retrieving the "error
-   * pointer" (below) and the fact that it exists within the application
-   * rather than within libpng, is essentially identical to libpng's
-   * default error handler.  The second point is critical:  since both
-   * setjmp() and longjmp() are called from the same code, they are
-   * guaranteed to have compatible notions of how big a jmp_buf is,
-   * regardless of whether _BSD_SOURCE or anything else has (or has not)
-   * been defined. */
+static void
+showTime(struct pngx * const pngxP) {
 
-  pm_message("fatal libpng error: %s", msg);
+    if (pngx_chunkIsPresent(pngxP, PNG_INFO_tIME)) {
+        png_time const modTime = pngx_time(pngxP);
 
-  jmpbuf_ptr = png_get_error_ptr(png_ptr);
-  if (jmpbuf_ptr == NULL) {
-      /* we are completely hosed now */
-      pm_error("EXTREMELY fatal error: jmpbuf unrecoverable; terminating.");
-  }
+        static const char * const month[] = {
+            "", "January", "February", "March", "April", "May", "June",
+            "July", "August", "September", "October", "November", "December"
+        };
 
-  longjmp(jmpbuf_ptr->jmpbuf, 1);
+        if (modTime.month < 1 || modTime.month >= ARRAY_SIZE(month)) {
+            pm_message("tIME chunk in PNG input is invalid; "
+                       "modification time of image is unknown.  "
+                       "The month value, which should be in the range "
+                       "1-12, is %u", modTime.month);
+        } else {
+            pm_message("modification time: %02d %s %d %02d:%02d:%02d",
+                       modTime.day,
+                       month[modTime.month],
+                       modTime.year,
+                       modTime.hour,
+                       modTime.minute,
+                       modTime.second);
+        }
+    }
 }
 
 
 
 static void
-dump_png_info(png_info *info_ptr) {
+dumpTypeAndFilter(struct pngx * const pngxP) {
 
-    const char *type_string;
-    const char *filter_string;
+    const char * typeString;
+    const char * filterString;
 
-    switch (info_ptr->color_type) {
-      case PNG_COLOR_TYPE_GRAY:
-        type_string = "gray";
+    switch (pngx_colorType(pngxP)) {
+    case PNG_COLOR_TYPE_GRAY:
+        typeString = "gray";
         break;
-
-      case PNG_COLOR_TYPE_GRAY_ALPHA:
-        type_string = "gray+alpha";
+        
+    case PNG_COLOR_TYPE_GRAY_ALPHA:
+        typeString = "gray+alpha";
         break;
-
-      case PNG_COLOR_TYPE_PALETTE:
-        type_string = "palette";
+        
+    case PNG_COLOR_TYPE_PALETTE:
+        typeString = "palette";
         break;
 
-      case PNG_COLOR_TYPE_RGB:
-        type_string = "truecolor";
+    case PNG_COLOR_TYPE_RGB:
+        typeString = "truecolor";
         break;
 
-      case PNG_COLOR_TYPE_RGB_ALPHA:
-        type_string = "truecolor+alpha";
+    case PNG_COLOR_TYPE_RGB_ALPHA:
+        typeString = "truecolor+alpha";
         break;
     }
 
-    switch (info_ptr->filter_type) {
+    switch (pngx_filterType(pngxP)) {
     case PNG_FILTER_TYPE_BASE:
-        asprintfN(&filter_string, "base filter");
+        pm_asprintf(&filterString, "base filter");
         break;
     default:
-        asprintfN(&filter_string, "unknown filter type %d", 
-                  info_ptr->filter_type);
+        pm_asprintf(&filterString, "unknown filter type %d", 
+                    pngx_filterType(pngxP));
     }
 
-    pm_message("reading a %ldw x %ldh image, %d bit%s",
-               info_ptr->width, info_ptr->height,
-               info_ptr->bit_depth, info_ptr->bit_depth > 1 ? "s" : "");
     pm_message("%s, %s, %s",
-               type_string,
-               info_ptr->interlace_type ? 
+               typeString,
+               pngx_interlaceType(pngxP) ? 
                "Adam7 interlaced" : "not interlaced",
-               filter_string);
-    pm_message("background {index, gray, red, green, blue} = "
-               "{%d, %d, %d, %d, %d}",
-               info_ptr->background.index,
-               info_ptr->background.gray,
-               info_ptr->background.red,
-               info_ptr->background.green,
-               info_ptr->background.blue);
-
-    strfree(filter_string);
-
-    if (info_ptr->valid & PNG_INFO_tRNS)
+               filterString);
+
+    pm_strfree(filterString);
+}
+
+
+
+static void
+dumpPngInfo(struct pngx * const pngxP) {
+
+    pm_message("reading a %u x %u image, %u bit%s",
+               pngx_imageWidth(pngxP),
+               pngx_imageHeight(pngxP),
+               pngx_bitDepth(pngxP),
+               pngx_bitDepth(pngxP) > 1 ? "s" : "");
+
+    dumpTypeAndFilter(pngxP);
+
+    if (pngx_chunkIsPresent(pngxP, PNG_INFO_bKGD)) {
+        png_color_16 const background = pngx_bkgd(pngxP);
+
+        pm_message("background {index, gray, red, green, blue} = "
+                   "{%d, %d, %d, %d, %d}",
+                   background.index,
+                   background.gray,
+                   background.red,
+                   background.green,
+                   background.blue);
+    }
+
+    if (pngx_chunkIsPresent(pngxP, PNG_INFO_tRNS))
         pm_message("tRNS chunk (transparency): %u entries",
-                   info_ptr->num_trans);
+                   pngx_trns(pngxP).numTrans);
     else
         pm_message("tRNS chunk (transparency): not present");
 
-    if (info_ptr->valid & PNG_INFO_gAMA)
-        pm_message("gAMA chunk (image gamma): gamma = %4.2f", info_ptr->gamma);
+    if (pngx_chunkIsPresent(pngxP, PNG_INFO_gAMA))
+        pm_message("gAMA chunk (image gamma): gamma = %4.2f",
+                   pngx_gama(pngxP));
     else
         pm_message("gAMA chunk (image gamma): not present");
-
-    if (info_ptr->valid & PNG_INFO_sBIT)
+    
+    if (pngx_chunkIsPresent(pngxP, PNG_INFO_sBIT))
         pm_message("sBIT chunk: present");
     else
         pm_message("sBIT chunk: not present");
 
-    if (info_ptr->valid & PNG_INFO_cHRM)
+    if (pngx_chunkIsPresent(pngxP, PNG_INFO_cHRM))
         pm_message("cHRM chunk: present");
     else
         pm_message("cHRM chunk: not present");
 
-    if (info_ptr->valid & PNG_INFO_PLTE)
-        pm_message("PLTE chunk: %d entries", info_ptr->num_palette);
+    if (pngx_chunkIsPresent(pngxP, PNG_INFO_PLTE))
+        pm_message("PLTE chunk: %d entries", pngx_plte(pngxP).size);
     else
         pm_message("PLTE chunk: not present");
 
-    if (info_ptr->valid & PNG_INFO_bKGD)
+    if (pngx_chunkIsPresent(pngxP, PNG_INFO_bKGD))
         pm_message("bKGD chunk: present");
     else
         pm_message("bKGD chunk: not present");
 
-    if (info_ptr->valid & PNG_INFO_hIST)
+    if (pngx_chunkIsPresent(pngxP, PNG_INFO_hIST))
         pm_message("hIST chunk: present");
     else
         pm_message("hIST chunk: not present");
 
-    if (info_ptr->valid & PNG_INFO_pHYs)
+    if (pngx_chunkIsPresent(pngxP, PNG_INFO_pHYs))
         pm_message("pHYs chunk: present");
     else
         pm_message("pHYs chunk: not present");
 
-    if (info_ptr->valid & PNG_INFO_oFFs)
+    if (pngx_chunkIsPresent(pngxP, PNG_INFO_oFFs))
         pm_message("oFFs chunk: present");
     else
         pm_message("oFFs chunk: not present");
 
-    if (info_ptr->valid & PNG_INFO_tIME)
+    if (pngx_chunkIsPresent(pngxP, PNG_INFO_tIME))
         pm_message("tIME chunk: present");
     else
         pm_message("tIME chunk: not present");
 
-    if (info_ptr->valid & PNG_INFO_pCAL)
+    if (pngx_chunkIsPresent(pngxP, PNG_INFO_pCAL))
         pm_message("pCAL chunk: present");
     else
         pm_message("pCAL chunk: not present");
 
-    if (info_ptr->valid & PNG_INFO_sRGB)
+    if (pngx_chunkIsPresent(pngxP, PNG_INFO_sRGB))
         pm_message("sRGB chunk: present");
     else
         pm_message("sRGB chunk: not present");
@@ -464,83 +733,34 @@ dump_png_info(png_info *info_ptr) {
 
 
 
-static unsigned int
-computePngLineSize(png_info * const pngInfoP) {
-
-    unsigned int const bytesPerSample = pngInfoP->bit_depth == 16 ? 2 : 1;
-
-    unsigned int samplesPerPixel;
-
-    switch (pngInfoP->color_type) {
-    case PNG_COLOR_TYPE_GRAY_ALPHA: samplesPerPixel = 2; break;
-    case PNG_COLOR_TYPE_RGB:        samplesPerPixel = 3; break;
-    case PNG_COLOR_TYPE_RGB_ALPHA:  samplesPerPixel = 4; break;
-    default:                        samplesPerPixel = 1;
-    }
-
-    if (UINT_MAX / bytesPerSample / samplesPerPixel < pngInfoP->width)
-        pm_error("Width %u of PNG is uncomputably large",
-                 (unsigned int)pngInfoP->width);
-       
-    return pngInfoP->width * bytesPerSample * samplesPerPixel;
-}
-
-
-
-static void
-allocPngRaster(png_info *   const pngInfoP,
-               png_byte *** const pngImageP) {
-
-    unsigned int const lineSize = computePngLineSize(pngInfoP);
-
-    png_byte ** pngImage;
-    unsigned int row;
-
-    MALLOCARRAY(pngImage, pngInfoP->height);
-
-    if (pngImage == NULL)
-        pm_error("couldn't allocate space for %u PNG raster rows",
-                 (unsigned int)pngInfoP->height);
-
-    for (row = 0; row < pngInfoP->height; ++row) {
-        MALLOCARRAY(pngImage[row], lineSize);
-        if (pngImage[row] == NULL)
-            pm_error("couldn't allocate space for %uth row of PNG raster",
-                     row);
-    }
-    *pngImageP = pngImage;
-}
-
-
-
-static void
-freePngRaster(png_byte ** const pngRaster,
-              png_info *  const pngInfoP) {
-
-    unsigned int row;
+static const png_color_16
+transColor(struct pngx * const pngxP) {
 
-    for (row = 0; row < pngInfoP->height; ++row)
-        free(pngRaster[row]);
+    struct pngx_trns const trans = pngx_trns(pngxP);
 
-    free(pngRaster);
+    assert(pngx_chunkIsPresent(pngxP, PNG_INFO_tRNS));
+    
+    return trans.transColor;
 }
 
 
 
 static bool
-isTransparentColor(pngcolor   const color,
-                   png_info * const pngInfoP,
-                   double     const totalgamma) {
+isTransparentColor(pngcolor        const color,
+                   struct pngx *   const pngxP,
+                   GammaCorrection const gamma) {
 /*----------------------------------------------------------------------------
    Return TRUE iff pixels of color 'color' are supposed to be transparent
    everywhere they occur.  Assume it's an RGB image.
 
-   'color' has been gamma-corrected.
+   'gamma' indicats what gamma correction has been applied to 'color' (we need
+   to know that because *pngxP identifies the color that is supposed to be
+   transparent in _not_ gamma-corrected form!).
 -----------------------------------------------------------------------------*/
     bool retval;
 
-    if (pngInfoP->valid & PNG_INFO_tRNS) {
-        const png_color_16 * const transColorP = &pngInfoP->trans_values;
+    if (pngx_chunkIsPresent(pngxP, PNG_INFO_tRNS)) {
+        png_color_16 const transColor16 = transColor(pngxP);
 
         /* It seems odd that libpng lets you get gamma-corrected pixel
            values, but not gamma-corrected transparency or background
@@ -556,15 +776,17 @@ isTransparentColor(pngcolor   const color,
            pixels, and just do it ourselves.
         */
     
-        switch (pngInfoP->color_type) {
+        switch (pngx_colorType(pngxP)) {
         case PNG_COLOR_TYPE_GRAY:
-            retval = color.r == gamma_correct(transColorP->gray, totalgamma);
+            retval = color.r == gammaCorrect(transColor16.gray, gamma,
+                                             pngxP->maxval);
             break;
-        default:
-            retval = 
-                color.r == gamma_correct(transColorP->red,   totalgamma) &&
-                color.g == gamma_correct(transColorP->green, totalgamma) &&
-                color.b == gamma_correct(transColorP->blue,  totalgamma);
+        default: {
+            pngcolor const transColor = pngcolorFrom16(transColor16);
+            retval = pngColorEqual(color,
+                                   gammaCorrectColor(transColor, gamma,
+                                                     pngxP->maxval));
+        }
         }
     } else 
         retval = FALSE;
@@ -574,60 +796,63 @@ isTransparentColor(pngcolor   const color,
 
 
 
-#define SIG_CHECK_SIZE 4
-
 static void
-read_sig_buf(FILE * const ifP) {
-
-    unsigned char sig_buf[SIG_CHECK_SIZE];
-    size_t bytesRead;
-
-    bytesRead = fread(sig_buf, 1, SIG_CHECK_SIZE, ifP);
-    if (bytesRead != SIG_CHECK_SIZE)
-        pm_error ("input file is empty or too short");
+setupGammaCorrection(struct pngx *     const pngxP,
+                     bool              const screenGammaIsKnown,
+                     float             const screenGamma,
+                     GammaCorrection * const gammaCorrectionP) {
+/*----------------------------------------------------------------------------
+   Set up to have values from the PNG gamma-corrected.
 
-    if (png_sig_cmp(sig_buf, (png_size_t) 0, (png_size_t) SIG_CHECK_SIZE)
-        != 0)
-        pm_error ("input file is not a PNG file");
-}
+   Return as *gammaCorrectionP the correction necessary and tell the
+   libpng image reader *pngxP to do that same correction - on the pixels
+   only, as it can't do it on anything else (hence, Caller will have to
+   use *gammaCorrectionP to do it).
 
+   'screenGammaIsKnown' means we know what the screen gamma is, and it is
+   'screenGamma'.  If we don't know what the screen gamma is, gamma 
+   correction is not possible, so we set up for no gamma correction.
 
+   The gamma correction we ordain is a combination of the image gamma,
+   recorded in the PNG input and represented by *pngxP, and the screen gamma.
 
-static void
-setupGammaCorrection(png_struct * const png_ptr,
-                     png_info *   const info_ptr,
-                     float        const displaygamma,
-                     float *      const totalgammaP) {
-
-    if (displaygamma == -1.0)
-        *totalgammaP = -1.0;
+   Note that "screen gamma" is a characteristic of both the display and the
+   viewing conditions.  There are also "display gamma" and "viewing gamma,"
+   respectively, but we don't care about the breakdown.  In a dimly lit room,
+   viewing gamma is 1 and screen gamma is the same as the display gamma.
+-----------------------------------------------------------------------------*/
+    if (!screenGammaIsKnown)
+        gammaCorrectionP->needCorrection = false;
     else {
         float imageGamma;
-        if (info_ptr->valid & PNG_INFO_gAMA)
-            imageGamma = info_ptr->gamma;
+        if (pngx_chunkIsPresent(pngxP, PNG_INFO_gAMA))
+            imageGamma = pngx_gama(pngxP);
         else {
             if (verbose)
                 pm_message("PNG doesn't specify image gamma.  Assuming 1.0");
             imageGamma = 1.0;
         }
 
-        if (fabs(displaygamma * imageGamma - 1.0) < .01) {
-            *totalgammaP = -1.0;
+        if (fabs(screenGamma * imageGamma - 1.0) < .01) {
+            gammaCorrectionP->needCorrection = false;
             if (verbose)
                 pm_message("image gamma %4.2f matches "
-                           "display gamma %4.2f.  No conversion.",
-                           imageGamma, displaygamma);
+                           "screen gamma %4.2f.  No conversion.",
+                           imageGamma, screenGamma);
         } else {
-            png_set_gamma(png_ptr, displaygamma, imageGamma);
-            *totalgammaP = imageGamma * displaygamma;
-            /* in case of gamma-corrections, sBIT's as in the
+            pngx_setGamma(pngxP, screenGamma, imageGamma);
+
+            gammaCorrectionP->needCorrection = true;
+            gammaCorrectionP->gamma = imageGamma * screenGamma;
+            /* In case of gamma-corrections, sBIT's as in the
                PNG-file are not valid anymore 
             */
-            info_ptr->valid &= ~PNG_INFO_sBIT;
+            pngx_removeChunk(pngxP, PNG_INFO_sBIT);
             if (verbose)
                 pm_message("image gamma is %4.2f, "
-                           "converted for display gamma of %4.2f",
-                           imageGamma, displaygamma);
+                           "display gamma is %4.2f; "
+                           "combined gamma is %4.2f",
+                           imageGamma, screenGamma, gammaCorrectionP->gamma);
         }
     }
 }
@@ -635,20 +860,21 @@ setupGammaCorrection(png_struct * const png_ptr,
 
 
 static bool
-paletteHasPartialTransparency(png_info * const info_ptr) {
+paletteHasPartialTransparency(struct pngx * const pngxP) {
 
     bool retval;
 
-    if (info_ptr->color_type == PNG_COLOR_TYPE_PALETTE) {
-        if (info_ptr->valid & PNG_INFO_tRNS) {
+    if (pngx_colorType(pngxP) == PNG_COLOR_TYPE_PALETTE) {
+        if (pngx_chunkIsPresent(pngxP, PNG_INFO_tRNS)) {
+            struct pngx_trns const trans = pngx_trns(pngxP);
+
             bool foundGray;
             unsigned int i;
             
             for (i = 0, foundGray = FALSE;
-                 i < info_ptr->num_trans && !foundGray;
+                 i < trans.numTrans && !foundGray;
                  ++i) {
-                if (info_ptr->TRANS_ALPHA[i] != 0 &&
-                    info_ptr->TRANS_ALPHA[i] != maxval) {
+                if (trans.trans[i] != 0 && trans.trans[i] != pngxP->maxval) {
                     foundGray = TRUE;
                 }
             }
@@ -664,61 +890,68 @@ paletteHasPartialTransparency(png_info * const info_ptr) {
 
 
 static void
-getComponentSbitFg(png_info * const pngInfoP,
-                   png_byte * const fgSbitP,
-                   bool *     const notUniformP) {
-
-    if (pngInfoP->color_type == PNG_COLOR_TYPE_RGB ||
-        pngInfoP->color_type == PNG_COLOR_TYPE_RGB_ALPHA ||
-        pngInfoP->color_type == PNG_COLOR_TYPE_PALETTE) {
-        if (pngInfoP->sig_bit.red == pngInfoP->sig_bit.blue &&
-            pngInfoP->sig_bit.red == pngInfoP->sig_bit.green) {
+getComponentSbitFg(struct pngx * const pngxP,
+                   png_byte *    const fgSbitP,
+                   bool *        const notUniformP) {
+
+    png_color_8 const sigBit = pngx_sbit(pngxP);
+
+    assert(pngx_chunkIsPresent(pngxP, PNG_INFO_sBIT));
+
+    if (pngx_colorType(pngxP) == PNG_COLOR_TYPE_RGB ||
+        pngx_colorType(pngxP) == PNG_COLOR_TYPE_RGB_ALPHA ||
+        pngx_colorType(pngxP) == PNG_COLOR_TYPE_PALETTE) {
+
+        if (sigBit.red == sigBit.blue &&
+            sigBit.red == sigBit.green) {
             *notUniformP = false;
-            *fgSbitP     = pngInfoP->sig_bit.red;
+            *fgSbitP     = sigBit.red;
         } else
             *notUniformP = true;
     } else {
         /* It has only a gray channel so it's obviously uniform */
         *notUniformP = false;
-        *fgSbitP     = pngInfoP->sig_bit.gray;
+        *fgSbitP     = sigBit.gray;
     }
 }
 
 
 
 static void
-getComponentSbit(png_info *          const pngInfoP,
-                 enum alpha_handling const alphaHandling,
+getComponentSbit(struct pngx *       const pngxP,
+                 enum AlphaHandling  const alphaHandling,
                  png_byte *          const componentSbitP,
                  bool *              const notUniformP) {
 
+    assert(pngx_chunkIsPresent(pngxP, PNG_INFO_sBIT));
+
     switch (alphaHandling) {
 
-    case ALPHA_ONLY:
+    case ALPHA_ONLY: {
         /* We care only about the alpha channel, so the uniform Sbit is
            the alpha Sbit
         */
         *notUniformP = false;
-        *componentSbitP = pngInfoP->sig_bit.alpha;
-        break;
+        *componentSbitP = pngx_sbit(pngxP).alpha;
+    } break;
     case ALPHA_NONE:
     case ALPHA_MIX:
         /* We aren't going to produce an alpha channel, so we care only
            about the uniformity of the foreground channels.
         */
-        getComponentSbitFg(pngInfoP, componentSbitP, notUniformP);
+        getComponentSbitFg(pngxP, componentSbitP, notUniformP);
         break;
     case ALPHA_IN: {
         /* We care about both the foreground and the alpha */
         bool fgNotUniform;
         png_byte fgSbit;
         
-        getComponentSbitFg(pngInfoP, &fgSbit, &fgNotUniform);
+        getComponentSbitFg(pngxP, &fgSbit, &fgNotUniform);
 
         if (fgNotUniform)
             *notUniformP = true;
         else {
-            if (fgSbit == pngInfoP->sig_bit.alpha) {
+            if (fgSbit == pngx_sbit(pngxP).alpha) {
                 *notUniformP    = false;
                 *componentSbitP = fgSbit;
             } else
@@ -731,8 +964,8 @@ getComponentSbit(png_info *          const pngInfoP,
                  
 
 static void
-shiftPalette(png_info *   const pngInfoP,
-             unsigned int const shift) {
+shiftPalette(struct pngx * const pngxP,
+             unsigned int  const shift) {
 /*----------------------------------------------------------------------------
    Shift every component of every color in the PNG palette right by
    'shift' bits because sBIT chunk says only those are significant.
@@ -743,12 +976,14 @@ shiftPalette(png_info *   const pngInfoP,
                  "but sBIT chunk says %u bits",
                  shift);
     else {
+        struct pngx_plte const palette = pngx_plte(pngxP);
+        
         unsigned int i;
         
-        for (i = 0; i < pngInfoP->num_palette; ++i) {
-            pngInfoP->palette[i].red   >>= (8 - shift);
-            pngInfoP->palette[i].green >>= (8 - shift);
-            pngInfoP->palette[i].blue  >>= (8 - shift);
+        for (i = 0; i < palette.size; ++i) {
+            palette.palette[i].red   >>= (8 - shift);
+            palette.palette[i].green >>= (8 - shift);
+            palette.palette[i].blue  >>= (8 - shift);
         }
     }
 }
@@ -756,12 +991,11 @@ shiftPalette(png_info *   const pngInfoP,
 
 
 static void
-computeMaxvalFromSbit(png_struct *        const pngP,
-                      png_info *          const pngInfoP,
-                      enum alpha_handling const alphaHandling,
+computeMaxvalFromSbit(struct pngx *       const pngxP,
+                      enum AlphaHandling  const alphaHandling,
                       png_uint_16 *       const maxvalP,
                       bool *              const succeededP,
-                      int *               const errorlevelP) {
+                      int *               const errorLevelP) {
 
     /* sBIT handling is very tricky. If we are extracting only the
        image, we can use the sBIT info for grayscale and color images,
@@ -782,37 +1016,38 @@ computeMaxvalFromSbit(png_struct *        const pngP,
            Meaningless if they aren't all the same (i.e. 'notUniform')
         */
 
-    getComponentSbit(pngInfoP, alphaHandling, &componentSigBit, &notUniform);
+    getComponentSbit(pngxP, alphaHandling, &componentSigBit, &notUniform);
 
     if (notUniform) {
         pm_message("This program cannot handle "
                    "different bit depths for color channels");
-        pm_message("writing file with %u bit resolution", pngInfoP->bit_depth);
+        pm_message("writing file with %u bit resolution",
+                   pngx_bitDepth(pngxP));
         *succeededP = false;
-        *errorlevelP = PNMTOPNG_WARNING_LEVEL;
+        *errorLevelP = PNMTOPNG_WARNING_LEVEL;
     } else if (componentSigBit > 15) {
         pm_message("Invalid PNG: says %u significant bits for a component; "
                    "max possible is 16.  Ignoring sBIT chunk.",
                    componentSigBit);
         *succeededP = false;
-        *errorlevelP = PNMTOPNG_WARNING_LEVEL;
+        *errorLevelP = PNMTOPNG_WARNING_LEVEL;
     } else {
         if (alphaHandling == ALPHA_MIX &&
-            (pngInfoP->color_type == PNG_COLOR_TYPE_RGB_ALPHA ||
-             pngInfoP->color_type == PNG_COLOR_TYPE_GRAY_ALPHA ||
-             paletteHasPartialTransparency(pngInfoP)))
+            (pngx_colorType(pngxP) == PNG_COLOR_TYPE_RGB_ALPHA ||
+             pngx_colorType(pngxP) == PNG_COLOR_TYPE_GRAY_ALPHA ||
+             paletteHasPartialTransparency(pngxP)))
             *succeededP = false;
         else {
-            if (componentSigBit < pngInfoP->bit_depth) {
+            if (componentSigBit < pngx_bitDepth(pngxP)) {
                 pm_message("Image has fewer significant bits, "
                            "writing file with %u bits", componentSigBit);
                 *maxvalP = (1l << componentSigBit) - 1;
                 *succeededP = true;
-
-                if (pngInfoP->color_type == PNG_COLOR_TYPE_PALETTE)
-                    shiftPalette(pngInfoP, componentSigBit);
+                
+                if (pngx_colorType(pngxP) == PNG_COLOR_TYPE_PALETTE)
+                    shiftPalette(pngxP, componentSigBit);
                 else
-                    png_set_shift(pngP, &pngInfoP->sig_bit);
+                    pngx_setShift(pngxP, pngx_sbit(pngxP));
             } else
                 *succeededP = false;
         }
@@ -822,50 +1057,48 @@ computeMaxvalFromSbit(png_struct *        const pngP,
 
 
 static void
-setupSignificantBits(png_struct *        const pngP,
-                     png_info *          const pngInfoP,
-                     enum alpha_handling const alphaHandling,
-                     png_uint_16 *       const maxvalP,
-                     int *               const errorlevelP) {
+setupSignificantBits(struct pngx *       const pngxP,
+                     enum AlphaHandling  const alphaHandling,
+                     int *               const errorLevelP) {
 /*----------------------------------------------------------------------------
-  Figure out what maxval would best express the information in the PNG
-  described by *pngP and *pngInfoP, with 'alpha' telling which
-  information in the PNG we care about (image or alpha mask).
+  Figure out what maxval is used in the PNG described by *pngxP, with 'alpha'
+  telling which information in the PNG we care about (image or alpha mask).
+  Update *pngxP with that information.
 
   Return the result as *maxvalP.
 
-  Also set up *pngP for the corresponding significant bits.
+  Also set up *pngxP for the corresponding significant bits.
 -----------------------------------------------------------------------------*/
     bool gotItFromSbit;
     
-    if (pngInfoP->valid & PNG_INFO_sBIT)
-        computeMaxvalFromSbit(pngP, pngInfoP, alphaHandling,
-                              maxvalP, &gotItFromSbit, errorlevelP);
+    if (pngx_chunkIsPresent(pngxP, PNG_INFO_sBIT))
+        computeMaxvalFromSbit(pngxP, alphaHandling,
+                              &pngxP->maxval, &gotItFromSbit, errorLevelP);
     else
         gotItFromSbit = false;
 
     if (!gotItFromSbit) {
-        if (pngInfoP->color_type == PNG_COLOR_TYPE_PALETTE) {
+        if (pngx_colorType(pngxP) == PNG_COLOR_TYPE_PALETTE) {
             if (alphaHandling == ALPHA_ONLY) {
-                if (pngInfoP->color_type == PNG_COLOR_TYPE_GRAY ||
-                    pngInfoP->color_type == PNG_COLOR_TYPE_RGB)
+                if (pngx_colorType(pngxP) == PNG_COLOR_TYPE_GRAY ||
+                    pngx_colorType(pngxP) == PNG_COLOR_TYPE_RGB)
                     /* The alpha mask will be all opaque, so maxval 1
                        is plenty
                     */
-                    *maxvalP = 1;
-                else if (paletteHasPartialTransparency(pngInfoP))
+                    pngxP->maxval = 1;
+                else if (paletteHasPartialTransparency(pngxP))
                     /* Use same maxval as PNG transparency palette for
                        simplicity
                     */
-                    *maxvalP = 255;
+                    pngxP->maxval = 255;
                 else
                     /* A common case, so we conserve bits */
-                    *maxvalP = 1;
+                    pngxP->maxval = 1;
             } else
                 /* Use same maxval as PNG palette for simplicity */
-                *maxvalP = 255;
+                pngxP->maxval = 255;
         } else {
-            *maxvalP = (1l << pngInfoP->bit_depth) - 1;
+            pngxP->maxval = (1l << pngx_bitDepth(pngxP)) - 1;
         }
     }
 }
@@ -873,22 +1106,24 @@ setupSignificantBits(png_struct *        const pngP,
 
 
 static bool
-imageHasColor(png_info * const info_ptr) {
+imageHasColor(struct pngx * const pngxP) {
 
     bool retval;
 
-    if (info_ptr->color_type == PNG_COLOR_TYPE_GRAY ||
-        info_ptr->color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
+    if (pngx_colorType(pngxP) == PNG_COLOR_TYPE_GRAY ||
+        pngx_colorType(pngxP) == PNG_COLOR_TYPE_GRAY_ALPHA)
 
         retval = FALSE;
-    else if (info_ptr->color_type == PNG_COLOR_TYPE_PALETTE) {
+    else if (pngx_colorType(pngxP) == PNG_COLOR_TYPE_PALETTE) {
+        struct pngx_plte const palette = pngx_plte(pngxP);
+
         bool foundColor;
         unsigned int i;
             
         for (i = 0, foundColor = FALSE;
-             i < info_ptr->num_palette && !foundColor;
+             i < palette.size && !foundColor;
              ++i) {
-            if (iscolor(info_ptr->palette[i]))
+            if (isColor(palette.palette[i]))
                 foundColor = TRUE;
         }
         retval = foundColor;
@@ -901,8 +1136,8 @@ imageHasColor(png_info * const info_ptr) {
 
 
 static void
-determineOutputType(png_info *          const pngInfoP,
-                    enum alpha_handling const alphaHandling,
+determineOutputType(struct pngx *       const pngxP,
+                    enum AlphaHandling  const alphaHandling,
                     pngcolor            const bgColor,
                     xelval              const maxval,
                     int *               const formatP,
@@ -916,7 +1151,7 @@ determineOutputType(png_info *          const pngInfoP,
     } else {            
         /* The output is a normal Netpbm image */
         bool const outputIsColor =
-            imageHasColor(pngInfoP) || !isGrayscale(bgColor);
+            imageHasColor(pngxP) || !isGrayscale(bgColor);
 
         if (alphaHandling == ALPHA_IN) {
             *formatP = PAM_FORMAT;
@@ -942,11 +1177,11 @@ determineOutputType(png_info *          const pngInfoP,
 
 
 static void
-getBackgroundColor(png_info *   const info_ptr,
-                   const char * const requestedColor,
-                   float        const totalgamma,
-                   xelval       const maxval,
-                   pngcolor *   const bgColorP) {
+getBackgroundColor(struct pngx *   const pngxP,
+                   const char *    const requestedColor,
+                   GammaCorrection const gamma,
+                   xelval          const maxval,
+                   pngcolor *      const bgColorP) {
 /*----------------------------------------------------------------------------
    Figure out what the background color should be.  If the user requested
    a particular color ('requestedColor' not null), that's the one.
@@ -964,31 +1199,31 @@ getBackgroundColor(png_info *   const info_ptr,
         bgColorP->g = PPM_GETG(backcolor);
         bgColorP->b = PPM_GETB(backcolor);
 
-    } else if (info_ptr->valid & PNG_INFO_bKGD) {
-        /* didn't manage to get libpng to work (bugs?) concerning background
+    } else if (pngx_chunkIsPresent(pngxP, PNG_INFO_bKGD)) {
+        /* Didn't manage to get libpng to work (bugs?) concerning background
            processing, therefore we do our own.
         */
-        switch (info_ptr->color_type) {
+        png_color_16 const background = pngx_bkgd(pngxP);
+        switch (pngx_colorType(pngxP)) {
         case PNG_COLOR_TYPE_GRAY:
         case PNG_COLOR_TYPE_GRAY_ALPHA:
             bgColorP->r = bgColorP->g = bgColorP->b = 
-                gamma_correct(info_ptr->background.gray, totalgamma);
+                gammaCorrect(background.gray, gamma, pngxP->maxval);
             break;
         case PNG_COLOR_TYPE_PALETTE: {
+            struct pngx_plte const palette = pngx_plte(pngxP);
             png_color const rawBgcolor = 
-                info_ptr->palette[info_ptr->background.index];
-            bgColorP->r = gamma_correct(rawBgcolor.red, totalgamma);
-            bgColorP->g = gamma_correct(rawBgcolor.green, totalgamma);
-            bgColorP->b = gamma_correct(rawBgcolor.blue, totalgamma);
+                palette.palette[background.index];
+            *bgColorP = gammaCorrectColor(pngcolorFromByte(rawBgcolor),
+                                          gamma, pngxP->maxval);
         }
         break;
         case PNG_COLOR_TYPE_RGB:
         case PNG_COLOR_TYPE_RGB_ALPHA: {
-            png_color_16 const rawBgcolor = info_ptr->background;
+            png_color_16 const rawBgcolor = background;
             
-            bgColorP->r = gamma_correct(rawBgcolor.red,   totalgamma);
-            bgColorP->g = gamma_correct(rawBgcolor.green, totalgamma);
-            bgColorP->b = gamma_correct(rawBgcolor.blue,  totalgamma);
+            *bgColorP = gammaCorrectColor(pngcolorFrom16(rawBgcolor),
+                                          gamma, pngxP->maxval);
         }
         break;
         }
@@ -999,31 +1234,88 @@ getBackgroundColor(png_info *   const info_ptr,
 
 
 
-#define GET_PNG_VAL(p) get_png_val(&(p), pngInfoP->bit_depth)
+static void
+warnNonsquarePixels(struct pngx * const pngxP,
+                    int *         const errorLevelP) {
+
+    if (pngx_pixelAspectRatioIsKnown(pngxP)) {
+        float const r = pngx_pixelAspectRatio(pngxP);
+
+        if (r != 1.0) {
+            const char * const baseMsg = "warning - non-square pixels";
+
+            if (pm_have_float_format())
+                pm_message("%s; to fix do a 'pamscale -%cscale %g'",
+                           baseMsg,
+                           r < 1.0 ? 'x' : 'y',
+                           r < 1.0 ? 1.0 / r : r);
+            else
+                pm_message("%s", baseMsg);
+
+            *errorLevelP = PNMTOPNG_WARNING_LEVEL;
+        }
+    }
+}
+
+
+
+static png_uint_16
+paletteAlpha(struct pngx * const pngxP,
+             png_uint_16   const index,
+             sample        const maxval) {
+
+    png_uint_16 retval;
+
+    if (pngx_chunkIsPresent(pngxP, PNG_INFO_tRNS)) {
+        struct pngx_trns const trans = pngx_trns(pngxP);
+
+        if (index < trans.numTrans)
+            retval = trans.trans[index];
+        else
+            retval = maxval;
+    } else
+        retval = maxval;
+
+    return retval;
+}
+
+
+
+#define GET_PNG_VAL(p) getPngVal(&(p), pngx_bitDepth(pngxP))
 
 
 
 static void
 makeTupleRow(const struct pam *  const pamP,
              const tuple *       const tuplerow,
-             png_info *          const pngInfoP,
+             struct pngx *       const pngxP,
              const png_byte *    const pngRasterRow,
              pngcolor            const bgColor,
-             enum alpha_handling const alphaHandling,
-             double              const totalgamma) {
-
+             enum AlphaHandling  const alphaHandling,
+             GammaCorrection     const gamma) {
+/*----------------------------------------------------------------------------
+   Convert a raster row as supplied by libpng, at 'pngRasterRow' and
+   described by *pngxP, to a libpam-style tuple row at 'tupleRow'.
+
+   Where the raster says the pixel isn't opaque, we either include that
+   opacity information in the output pixel or we mix the pixel with background
+   color 'bgColor', as directed by 'alphaHandling'.  Or, if 'alphaHandling'
+   says so, we may produce an output row of _only_ the transparency
+   information.
+-----------------------------------------------------------------------------*/
     const png_byte * pngPixelP;
     unsigned int col;
 
     pngPixelP = &pngRasterRow[0];  /* initial value */
-    for (col = 0; col < pngInfoP->width; ++col) {
-        switch (pngInfoP->color_type) {
+    for (col = 0; col < pngx_imageWidth(pngxP); ++col) {
+        switch (pngx_colorType(pngxP)) {
         case PNG_COLOR_TYPE_GRAY: {
             pngcolor fgColor;
             fgColor.r = fgColor.g = fgColor.b = GET_PNG_VAL(pngPixelP);
             setTuple(pamP, tuplerow[col], fgColor, bgColor, alphaHandling,
-                   isTransparentColor(fgColor, pngInfoP, totalgamma) ?
-                   0 : maxval);
+                     pngxP,
+                     isTransparentColor(fgColor, pngxP, gamma) ?
+                     0 : pngxP->maxval);
         }
         break;
 
@@ -1034,13 +1326,14 @@ makeTupleRow(const struct pam *  const pamP,
             fgColor.r = fgColor.g = fgColor.b = GET_PNG_VAL(pngPixelP);
             alpha = GET_PNG_VAL(pngPixelP);
             setTuple(pamP, tuplerow[col], fgColor, bgColor,
-                     alphaHandling, alpha);
+                     alphaHandling, pngxP, alpha);
         }
         break;
 
         case PNG_COLOR_TYPE_PALETTE: {
-            png_uint_16 const index        = GET_PNG_VAL(pngPixelP);
-            png_color   const paletteColor = pngInfoP->palette[index];
+            png_uint_16      const index        = GET_PNG_VAL(pngPixelP);
+            struct pngx_plte const palette      = pngx_plte(pngxP);
+            png_color        const paletteColor = palette.palette[index];
 
             pngcolor fgColor;
 
@@ -1049,9 +1342,7 @@ makeTupleRow(const struct pam *  const pamP,
             fgColor.b = paletteColor.blue;
 
             setTuple(pamP, tuplerow[col], fgColor, bgColor, alphaHandling,
-                     (pngInfoP->valid & PNG_INFO_tRNS) &&
-                     index < pngInfoP->num_trans ?
-                     pngInfoP->TRANS_ALPHA[index] : maxval);
+                     pngxP, paletteAlpha(pngxP, index, pngxP->maxval));
         }
         break;
                 
@@ -1062,8 +1353,9 @@ makeTupleRow(const struct pam *  const pamP,
             fgColor.g = GET_PNG_VAL(pngPixelP);
             fgColor.b = GET_PNG_VAL(pngPixelP);
             setTuple(pamP, tuplerow[col], fgColor, bgColor, alphaHandling,
-                     isTransparentColor(fgColor, pngInfoP, totalgamma) ?
-                     0 : maxval);
+                     pngxP,
+                     isTransparentColor(fgColor, pngxP, gamma) ?
+                     0 : pngxP->maxval);
         }
         break;
 
@@ -1076,12 +1368,13 @@ makeTupleRow(const struct pam *  const pamP,
             fgColor.b = GET_PNG_VAL(pngPixelP);
             alpha     = GET_PNG_VAL(pngPixelP);
             setTuple(pamP, tuplerow[col], fgColor, bgColor,
-                     alphaHandling, alpha);
+                     alphaHandling, pngxP, alpha);
         }
         break;
 
         default:
-            pm_error("unknown PNG color type: %d", pngInfoP->color_type);
+            pm_error("unknown PNG color type: %d",
+                     pngx_colorType(pngxP));
         }
     }
 }
@@ -1103,8 +1396,8 @@ reportOutputFormat(const struct pam * const pamP) {
         pm_message("Writing a PPM file with maxval %lu", pamP->maxval);
         break;
     case PAM_FORMAT:
-        pm_message("Writing a PAM file with tuple type %s, maxval %u",
-                   pamP->tuple_type, maxval);
+        pm_message("Writing a PAM file with tuple type %s, maxval %lu",
+                   pamP->tuple_type, pamP->maxval);
         break;
     default:
         assert(false); /* Every possible value handled above */
@@ -1115,15 +1408,15 @@ reportOutputFormat(const struct pam * const pamP) {
 
 static void
 writeNetpbm(struct pam *        const pamP,
-            png_info *          const pngInfoP,
-            png_byte **         const pngRaster,
+            struct pngx *       const pngxP,
+            Reader *            const rasterReaderP,
             pngcolor            const bgColor,
-            enum alpha_handling const alphaHandling,
-            double              const totalgamma) {
+            enum AlphaHandling  const alphaHandling,
+            GammaCorrection     const gamma) {
 /*----------------------------------------------------------------------------
    Write a Netpbm image of either the image or the alpha mask, according to
-   'alphaHandling' that is in the PNG image described by 'pngInfoP' and
-   pngRaster.
+   'alphaHandling' that is in the PNG image described by *pngxP, reading
+   its raster with the raster reader object *rasterReaderP.
 
    *pamP describes the required output image and is consistent with
    *pngInfoP.
@@ -1141,9 +1434,13 @@ writeNetpbm(struct pam *        const pamP,
 
     tuplerow = pnm_allocpamrow(pamP);
 
-    for (row = 0; row < pngInfoP->height; ++row) {
-        makeTupleRow(pamP, tuplerow, pngInfoP, pngRaster[row], bgColor,
-                     alphaHandling, totalgamma);
+    for (row = 0; row < pngx_imageHeight(pngxP); ++row) {
+        png_byte * const pngRow = reader_read(rasterReaderP);
+
+        assert(pngRow);
+
+        makeTupleRow(pamP, tuplerow, pngxP, pngRow, bgColor,
+                     alphaHandling, gamma);
 
         pnm_writepamrow(pamP, tuplerow);
     }
@@ -1153,97 +1450,68 @@ writeNetpbm(struct pam *        const pamP,
 
 
 static void 
-convertpng(FILE *             const ifp, 
-           FILE *             const tfp, 
-           struct cmdlineInfo const cmdline,
-           int *              const errorlevelP) {
-
-    png_struct * png_ptr;
-    png_info * info_ptr;
-    png_byte ** png_image;
+convertpng(FILE *             const ifP, 
+           FILE *             const tfP, 
+           struct CmdlineInfo const cmdline,
+           int *              const errorLevelP) {
+
+    Reader * rasterReaderP;
     pngcolor bgColor;
-    float totalgamma;
+    GammaCorrection gamma;
     struct pam pam;
+    jmp_buf jmpbuf;
+    struct pngx * pngxP;
 
-    *errorlevelP = 0;
-
-    read_sig_buf(ifp);
-
-    png_ptr = png_create_read_struct(
-        PNG_LIBPNG_VER_STRING,
-        &pngtopnm_jmpbuf_struct, pngtopnm_error_handler, NULL);
-    if (png_ptr == NULL)
-        pm_error("cannot allocate main libpng structure (png_ptr)");
+    *errorLevelP = 0;
 
-    info_ptr = png_create_info_struct (png_ptr);
-    if (info_ptr == NULL)
-        pm_error("cannot allocate LIBPNG structures");
-
-    if (setjmp(pngtopnm_jmpbuf_struct.jmpbuf))
+    if (setjmp(jmpbuf))
         pm_error ("setjmp returns error condition");
 
-    png_init_io (png_ptr, ifp);
-    png_set_sig_bytes (png_ptr, SIG_CHECK_SIZE);
-    png_read_info (png_ptr, info_ptr);
-
-    allocPngRaster(info_ptr, &png_image);
+    pngx_create(&pngxP, PNGX_READ, &jmpbuf);
 
-    if (info_ptr->bit_depth < 8)
-        png_set_packing (png_ptr);
-
-    setupGammaCorrection(png_ptr, info_ptr, cmdline.gamma, &totalgamma);
-
-    setupSignificantBits(png_ptr, info_ptr, cmdline.alpha,
-                         &maxval, errorlevelP);
-
-    getBackgroundColor(info_ptr, cmdline.background, totalgamma, maxval,
-                       &bgColor);
-
-    png_read_image(png_ptr, png_image);
-    png_read_end(png_ptr, info_ptr);
+    pngx_readStart(pngxP, ifP);
 
     if (verbose)
-        /* Note that some of info_ptr is not defined until png_read_end() 
-           completes.  That's because it comes from chunks that are at the
-           end of the stream.
-        */
-        dump_png_info(info_ptr);
+        dumpPngInfo(pngxP);
 
     if (cmdline.time)
-        show_time(info_ptr);
-    if (tfp)
-        save_text(info_ptr, tfp);
+        showTime(pngxP);
+    if (tfP)
+        saveText(pngxP, tfP);
 
-    if (info_ptr->valid & PNG_INFO_pHYs) {
-        float const r =
-            (float)info_ptr->x_pixels_per_unit / info_ptr->y_pixels_per_unit;
-        if (r != 1.0) {
-            pm_message ("warning - non-square pixels; "
-                        "to fix do a 'pamscale -%cscale %g'",
-                        r < 1.0 ? 'x' : 'y',
-                        r < 1.0 ? 1.0 / r : r );
-            *errorlevelP = PNMTOPNG_WARNING_LEVEL;
-        }
-    }
+    warnNonsquarePixels(pngxP, errorLevelP);
 
+    setupGammaCorrection(pngxP, cmdline.gammaSpec, cmdline.gamma, &gamma);
+
+    setupSignificantBits(pngxP, cmdline.alpha, errorLevelP);
+
+    getBackgroundColor(pngxP, cmdline.background, gamma, pngxP->maxval,
+                       &bgColor);
+  
     pam.size        = sizeof(pam);
     pam.len         = PAM_STRUCT_SIZE(tuple_type);
     pam.file        = stdout;
     pam.plainformat = 0;
-    pam.height      = info_ptr->height;
-    pam.width       = info_ptr->width;
-    pam.maxval      = maxval;
+    pam.height      = pngx_imageHeight(pngxP);
+    pam.width       = pngx_imageWidth(pngxP);
+    pam.maxval      = pngxP->maxval;
 
-    determineOutputType(info_ptr, cmdline.alpha, bgColor, maxval,
+    determineOutputType(pngxP, cmdline.alpha, bgColor, pngxP->maxval,
                         &pam.format, &pam.depth, pam.tuple_type);
 
-    writeNetpbm(&pam, info_ptr, png_image, bgColor, cmdline.alpha, totalgamma);
+    rasterReaderP = cmdline.byrow ? 
+        reader_createRowByRow(pngxP, ifP) : reader_createAllAtOnce(pngxP, ifP);
 
-    fflush(stdout);
+    writeNetpbm(&pam, pngxP, rasterReaderP, bgColor,
+                cmdline.alpha, gamma);
+
+    reader_destroy(rasterReaderP);
 
-    freePngRaster(png_image, info_ptr);
+    pngx_readEnd(pngxP);
 
-    png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
+    fflush(stdout);
+
+    pngx_destroy(pngxP);
 }
 
 
@@ -1251,10 +1519,10 @@ convertpng(FILE *             const ifp,
 int 
 main(int argc, const char *argv[]) {
 
-    struct cmdlineInfo cmdline;
+    struct CmdlineInfo cmdline;
     FILE * ifP;
     FILE * tfP;
-    int errorlevel;
+    int errorLevel;
 
     pm_proginit(&argc, argv);
 
@@ -1262,14 +1530,14 @@ main(int argc, const char *argv[]) {
 
     verbose = cmdline.verbose;
 
-    ifP = pm_openr(cmdline.inputFilespec);
+    ifP = pm_openr(cmdline.inputFileName);
 
     if (cmdline.text)
         tfP = pm_openw(cmdline.text);
     else
         tfP = NULL;
 
-    convertpng(ifP, tfP, cmdline, &errorlevel);
+    convertpng(ifP, tfP, cmdline, &errorLevel);
 
     if (tfP)
         pm_close(tfP);
@@ -1277,5 +1545,8 @@ main(int argc, const char *argv[]) {
     pm_close(ifP);
     pm_close(stdout);
 
-    return errorlevel;
+    return errorLevel;
 }
+
+
+
diff --git a/converter/other/pngtopnm.c b/converter/other/pngtopnm.c
deleted file mode 100644
index 205df654..00000000
--- a/converter/other/pngtopnm.c
+++ /dev/null
@@ -1,1255 +0,0 @@
-/*
-** pngtopnm.c -
-** read a Portable Network Graphics file and produce a PNM.
-**
-** Copyright (C) 1995,1998 by Alexander Lehmann <alex@hal.rhein-main.de>
-**                        and Willem van Schaik <willem@schaik.com>
-**
-** 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.
-**
-** modeled after giftopnm by David Koblas and
-** with lots of bits pasted from libpng.txt by Guy Eric Schalnat
-*/
-
-#ifndef PNMTOPNG_WARNING_LEVEL
-#  define PNMTOPNG_WARNING_LEVEL 0   /* use 0 for backward compatibility, */
-#endif                               /*  2 for warnings (1 == error) */
-
-#include <assert.h>
-#include <math.h>
-#include <float.h>
-#include <png.h>    /* includes zlib.h and setjmp.h */
-#define VERSION "2.37.4 (5 December 1999) +netpbm"
-
-#include "pm_c_util.h"
-#include "mallocvar.h"
-#include "nstring.h"
-#include "shhopt.h"
-#include "pnm.h"
-
-#if PNG_LIBPNG_VER >= 10500
-#error Your PNG library (<png.h>) is incompatible with this Netpbm source code.
-#error You need either an older PNG library (older than 1.5) or
-#error newer Netpbm source code (at least 10.55)
-#endif
-
-/* A hack until we can remove direct access to png_info from the program */
-#if PNG_LIBPNG_VER >= 10400
-#define TRANS_ALPHA trans_alpha
-#else
-#define TRANS_ALPHA trans
-#endif
-
-
-enum alpha_handling {ALPHA_NONE, ALPHA_ONLY, ALPHA_MIX};
-
-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 */
-    unsigned int verbose;
-    enum alpha_handling alpha;
-    const char * background;
-    float gamma;  /* -1.0 means unspecified */
-    const char * text;
-    unsigned int time;
-};
-
-
-typedef struct {
-/*----------------------------------------------------------------------------
-   A color in a format compatible with the PNG library.
-
-   Note that the PNG library declares types png_color and png_color_16
-   which are similar.
------------------------------------------------------------------------------*/
-    png_uint_16 r;
-    png_uint_16 g;
-    png_uint_16 b;
-} pngcolor;
-
-
-static png_uint_16 maxval;
-static bool verbose;
-
-
-static void
-parseCommandLine(int                  argc, 
-                 const char **        argv,
-                 struct cmdlineInfo * 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 optParseOptions3 on how to parse our options.
-         */
-    optStruct3 opt;
-
-    unsigned int option_def_index;
-
-    unsigned int alphaSpec, mixSpec, backgroundSpec, gammaSpec, textSpec;
-
-    MALLOCARRAY(option_def, 100);
-
-    option_def_index = 0;   /* incremented by OPTENT3 */
-    OPTENT3(0, "verbose",     OPT_FLAG,   NULL,                  
-            &cmdlineP->verbose,       0);
-    OPTENT3(0, "alpha",       OPT_FLAG,   NULL,                  
-            &alphaSpec,               0);
-    OPTENT3(0, "mix",         OPT_FLAG,   NULL,                  
-            &mixSpec,                 0);
-    OPTENT3(0, "background",  OPT_STRING, &cmdlineP->background,
-            &backgroundSpec,          0);
-    OPTENT3(0, "gamma",       OPT_FLOAT,  &cmdlineP->gamma,
-            &gammaSpec,               0);
-    OPTENT3(0, "text",        OPT_STRING, &cmdlineP->text,
-            &textSpec,                0);
-    OPTENT3(0, "time",        OPT_FLAG,   NULL,                  
-            &cmdlineP->time,          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 */
-
-    optParseOptions3(&argc, (char **)argv, opt, sizeof(opt), 0);
-        /* Uses and sets argc, argv, and some of *cmdlineP and others. */
-
-
-    if (alphaSpec && mixSpec)
-        pm_error("You cannot specify both -alpha and -mix");
-    else if (alphaSpec)
-        cmdlineP->alpha = ALPHA_ONLY;
-    else if (mixSpec)
-        cmdlineP->alpha = ALPHA_MIX;
-    else
-        cmdlineP->alpha = ALPHA_NONE;
-
-    if (backgroundSpec && !mixSpec)
-        pm_error("-background is useless without -mix");
-
-    if (!backgroundSpec)
-        cmdlineP->background = NULL;
-
-    if (!gammaSpec)
-        cmdlineP->gamma = -1.0;
-
-    if (!textSpec)
-        cmdlineP->text = NULL;
-
-    if (argc-1 < 1)
-        cmdlineP->inputFilespec = "-";
-    else if (argc-1 == 1)
-        cmdlineP->inputFilespec = argv[1];
-    else
-        pm_error("Program takes at most one argument: input file name.  "
-            "you specified %d", argc-1);
-}
-
-
-
-static void
-pngtopnmErrorHandler(png_structp     const png_ptr,
-                     png_const_charp const msg) {
-
-    jmp_buf * jmpbufP;
-
-    /* this function, aside from the extra step of retrieving the "error
-       pointer" (below) and the fact that it exists within the application
-       rather than within libpng, is essentially identical to libpng's
-       default error handler.  The second point is critical:  since both
-       setjmp() and longjmp() are called from the same code, they are
-       guaranteed to have compatible notions of how big a jmp_buf is,
-       regardless of whether _BSD_SOURCE or anything else has (or has not)
-       been defined.
-    */
-
-    pm_message("fatal libpng error: %s", msg);
-
-    jmpbufP = png_get_error_ptr(png_ptr);
-
-    if (!jmpbufP) {
-        /* we are completely hosed now */
-        pm_error("EXTREMELY fatal error: jmpbuf unrecoverable; terminating.");
-    }
-
-    longjmp(*jmpbufP, 1);
-}
-
-
-
-struct pngx {
-    png_structp png_ptr;
-    png_infop info_ptr;
-};
-
-
-
-static void
-pngx_createRead(struct pngx ** const pngxPP,
-                jmp_buf *      const jmpbufP) {
-
-    struct pngx * pngxP;
-
-    MALLOCVAR(pngxP);
-
-    if (!pngxP)
-        pm_error("Failed to allocate memory for PNG object");
-    else {
-        pngxP->png_ptr = png_create_read_struct(
-            PNG_LIBPNG_VER_STRING,
-            jmpbufP, pngtopnmErrorHandler, NULL);
-
-        if (!pngxP->png_ptr)
-            pm_error("cannot allocate main libpng structure (png_ptr)");
-        else {
-            pngxP->info_ptr = png_create_info_struct(pngxP->png_ptr);
-
-            if (!pngxP->info_ptr)
-                pm_error("cannot allocate libpng info structure (info_ptr)");
-            else
-                *pngxPP = pngxP;
-        }
-    }
-}
-
-
-
-static void
-pngx_destroy(struct pngx * const pngxP) {
-
-    png_destroy_read_struct(&pngxP->png_ptr, &pngxP->info_ptr, NULL);
-
-    free(pngxP);
-}
-
-
-
-static bool
-pngx_chunkIsPresent(struct pngx * const pngxP,
-                    uint32_t      const chunkType) {
-
-    return png_get_valid(pngxP->png_ptr, pngxP->info_ptr, chunkType);
-}
-
-
-
-static void
-verifyFileIsPng(FILE *   const ifP,
-                size_t * const consumedByteCtP) {
-
-    unsigned char buffer[4];
-    size_t bytesRead;
-
-    bytesRead = fread(buffer, 1, sizeof(buffer), ifP);
-    if (bytesRead != sizeof(buffer))
-        pm_error("input file is empty or too short");
-
-    if (png_sig_cmp(buffer, (png_size_t) 0, (png_size_t) sizeof(buffer)) != 0)
-        pm_error("input file is not a PNG file "
-                 "(does not have the PNG signature in its first 4 bytes)");
-    else
-        *consumedByteCtP = bytesRead;
-}
-
-
-
-static unsigned int
-computePngLineSize(struct pngx * const pngxP) {
-
-    unsigned int const bytesPerSample =
-        pngxP->info_ptr->bit_depth == 16 ? 2 : 1;
-
-    unsigned int samplesPerPixel;
-
-    switch (pngxP->info_ptr->color_type) {
-    case PNG_COLOR_TYPE_GRAY_ALPHA: samplesPerPixel = 2; break;
-    case PNG_COLOR_TYPE_RGB:        samplesPerPixel = 3; break;
-    case PNG_COLOR_TYPE_RGB_ALPHA:  samplesPerPixel = 4; break;
-    default:                        samplesPerPixel = 1;
-    }
-
-    if (UINT_MAX / bytesPerSample / samplesPerPixel < pngxP->info_ptr->width)
-        pm_error("Width %u of PNG is uncomputably large",
-                 (unsigned int)pngxP->info_ptr->width);
-       
-    return pngxP->info_ptr->width * bytesPerSample * samplesPerPixel;
-}
-
-
-
-static void
-allocPngRaster(struct pngx * const pngxP,
-               png_byte ***  const pngImageP) {
-
-    unsigned int const lineSize = computePngLineSize(pngxP);
-
-    png_byte ** pngImage;
-    unsigned int row;
-
-    MALLOCARRAY(pngImage, pngxP->info_ptr->height);
-
-    if (pngImage == NULL)
-        pm_error("couldn't allocate space for %u PNG raster rows",
-                 (unsigned int)pngxP->info_ptr->height);
-
-    for (row = 0; row < pngxP->info_ptr->height; ++row) {
-        MALLOCARRAY(pngImage[row], lineSize);
-        if (pngImage[row] == NULL)
-            pm_error("couldn't allocate space for %uth row of PNG raster",
-                     row);
-    }
-    *pngImageP = pngImage;
-}
-
-
-
-static void
-freePngRaster(png_byte **   const pngRaster,
-              struct pngx * const pngxP) {
-
-    unsigned int row;
-
-    for (row = 0; row < pngxP->info_ptr->height; ++row)
-        free(pngRaster[row]);
-
-    free(pngRaster);
-}
-
-
-
-static void
-readPng(struct pngx * const pngxP,
-        FILE *        const ifP,
-        png_byte ***  const pngRasterP) {
-
-    size_t sigByteCt;
-    png_byte ** pngRaster;
-            
-    verifyFileIsPng(ifP, &sigByteCt);
-
-    /* Declare that we already read the signature bytes */
-    png_set_sig_bytes(pngxP->png_ptr, (int)sigByteCt);
-
-    png_init_io(pngxP->png_ptr, ifP);
-
-    png_read_info(pngxP->png_ptr, pngxP->info_ptr);
-
-    allocPngRaster(pngxP, &pngRaster);
-
-    if (pngxP->info_ptr->bit_depth < 8)
-        png_set_packing(pngxP->png_ptr);
-
-    png_read_image(pngxP->png_ptr, pngRaster);
-
-    png_read_end(pngxP->png_ptr, pngxP->info_ptr);
-
-    /* Note that some of info_ptr is not defined until png_read_end() 
-       completes.  That's because it comes from chunks that are at the
-       end of the stream.
-    */
-
-    *pngRasterP = pngRaster;
-}
-
-
-
-static png_uint_16
-get_png_val(const png_byte ** const pp,
-            int               const bit_depth) {
-
-    png_uint_16 c;
-    
-    if (bit_depth == 16)
-        c = (*((*pp)++)) << 8;
-    else
-        c = 0;
-
-    c |= (*((*pp)++));
-    
-    return c;
-}
-
-
-
-static bool
-isGrayscale(pngcolor const color) {
-
-    return color.r == color.g && color.r == color.b;
-}
-
-
-
-static void 
-setXel(xel *               const xelP, 
-       pngcolor            const foreground,
-       pngcolor            const background,
-       enum alpha_handling const alpha_handling,
-       png_uint_16         const alpha) {
-
-    if (alpha_handling == ALPHA_ONLY) {
-        PNM_ASSIGN1(*xelP, alpha);
-    } else {
-        if ((alpha_handling == ALPHA_MIX) && (alpha != maxval)) {
-            double const opacity      = (double)alpha / maxval;
-            double const transparency = 1.0 - opacity;
-
-            pngcolor mix;
-
-            mix.r = foreground.r * opacity + background.r * transparency + 0.5;
-            mix.g = foreground.g * opacity + background.g * transparency + 0.5;
-            mix.b = foreground.b * opacity + background.b * transparency + 0.5;
-            PPM_ASSIGN(*xelP, mix.r, mix.g, mix.b);
-        } else
-            PPM_ASSIGN(*xelP, foreground.r, foreground.g, foreground.b);
-    }
-}
-
-
-
-static png_uint_16
-gamma_correct(png_uint_16 const v,
-              float       const g) {
-
-    if (g != -1.0)
-        return (png_uint_16) ROUNDU(pow((double) v / maxval, (1.0 / g)) *
-                                    maxval);
-    else
-        return v;
-}
-
-
-
-static bool
-iscolor(png_color const c) {
-
-    return c.red != c.green || c.green != c.blue;
-}
-
-
-
-static void
-saveText(struct pngx * const pngxP,
-         FILE *        const tfP) {
-
-    png_info * const info_ptr = pngxP->info_ptr;
-
-    unsigned int i;
-
-    for (i = 0 ; i < info_ptr->num_text; ++i) {
-        unsigned int j;
-        j = 0;
-
-        while (info_ptr->text[i].key[j] != '\0' &&
-               info_ptr->text[i].key[j] != ' ')
-            ++j;    
-
-        if (info_ptr->text[i].key[j] != ' ') {
-            fprintf(tfP, "%s", info_ptr->text[i].key);
-            for (j = strlen (info_ptr->text[i].key); j < 15; ++j)
-                putc(' ', tfP);
-        } else {
-            fprintf(tfP, "\"%s\"", info_ptr->text[i].key);
-            for (j = strlen (info_ptr->text[i].key); j < 13; ++j)
-                putc(' ', tfP);
-        }
-        putc(' ', tfP); /* at least one space between key and text */
-    
-        for (j = 0; j < info_ptr->text[i].text_length; ++j) {
-            putc(info_ptr->text[i].text[j], tfP);
-            if (info_ptr->text[i].text[j] == '\n') {
-                unsigned int k;
-                for (k = 0; k < 16; ++k)
-                    putc(' ', tfP);
-            }
-        }
-        putc('\n', tfP);
-    }
-}
-
-
-
-static void
-showTime(struct pngx * const pngxP) {
-
-    static const char * const month[] = {
-        "", "January", "February", "March", "April", "May", "June",
-        "July", "August", "September", "October", "November", "December"
-    };
-
-    if (pngxP->info_ptr->valid & PNG_INFO_tIME) {
-      if (pngxP->info_ptr->mod_time.month < 1 ||
-        pngxP->info_ptr->mod_time.month >= ARRAY_SIZE(month)) {
-        pm_message("tIME chunk in PNG input is invalid; "
-                   "modification time of image is unknown.  "
-                   "The month value, which should be in the range "
-                   "1-12, is %u", pngxP->info_ptr->mod_time.month);
-      } else
-        pm_message("modification time: %02d %s %d %02d:%02d:%02d",
-                   pngxP->info_ptr->mod_time.day,
-                   month[pngxP->info_ptr->mod_time.month],
-                   pngxP->info_ptr->mod_time.year,
-                   pngxP->info_ptr->mod_time.hour,
-                   pngxP->info_ptr->mod_time.minute,
-                   pngxP->info_ptr->mod_time.second);
-    }
-}
-
-
-
-static void
-dumpPngInfo(struct pngx * const pngxP) {
-
-    png_info * const info_ptr = pngxP->info_ptr;
-    const char *type_string;
-    const char *filter_string;
-
-    switch (info_ptr->color_type) {
-      case PNG_COLOR_TYPE_GRAY:
-        type_string = "gray";
-        break;
-
-      case PNG_COLOR_TYPE_GRAY_ALPHA:
-        type_string = "gray+alpha";
-        break;
-
-      case PNG_COLOR_TYPE_PALETTE:
-        type_string = "palette";
-        break;
-
-      case PNG_COLOR_TYPE_RGB:
-        type_string = "truecolor";
-        break;
-
-      case PNG_COLOR_TYPE_RGB_ALPHA:
-        type_string = "truecolor+alpha";
-        break;
-    }
-
-    switch (info_ptr->filter_type) {
-    case PNG_FILTER_TYPE_BASE:
-        asprintfN(&filter_string, "base filter");
-        break;
-    default:
-        asprintfN(&filter_string, "unknown filter type %d", 
-                  info_ptr->filter_type);
-    }
-
-    pm_message("reading a %ldw x %ldh image, %d bit%s",
-               info_ptr->width, info_ptr->height,
-               info_ptr->bit_depth, info_ptr->bit_depth > 1 ? "s" : "");
-    pm_message("%s, %s, %s",
-               type_string,
-               info_ptr->interlace_type ? 
-               "Adam7 interlaced" : "not interlaced",
-               filter_string);
-    pm_message("background {index, gray, red, green, blue} = "
-               "{%d, %d, %d, %d, %d}",
-               info_ptr->background.index,
-               info_ptr->background.gray,
-               info_ptr->background.red,
-               info_ptr->background.green,
-               info_ptr->background.blue);
-
-    strfree(filter_string);
-
-    if (info_ptr->valid & PNG_INFO_tRNS)
-        pm_message("tRNS chunk (transparency): %u entries",
-                   info_ptr->num_trans);
-    else
-        pm_message("tRNS chunk (transparency): not present");
-
-    if (info_ptr->valid & PNG_INFO_gAMA)
-        pm_message("gAMA chunk (image gamma): gamma = %4.2f", info_ptr->gamma);
-    else
-        pm_message("gAMA chunk (image gamma): not present");
-
-    if (info_ptr->valid & PNG_INFO_sBIT)
-        pm_message("sBIT chunk: present");
-    else
-        pm_message("sBIT chunk: not present");
-
-    if (info_ptr->valid & PNG_INFO_cHRM)
-        pm_message("cHRM chunk: present");
-    else
-        pm_message("cHRM chunk: not present");
-
-    if (info_ptr->valid & PNG_INFO_PLTE)
-        pm_message("PLTE chunk: %d entries", info_ptr->num_palette);
-    else
-        pm_message("PLTE chunk: not present");
-
-    if (info_ptr->valid & PNG_INFO_bKGD)
-        pm_message("bKGD chunk: present");
-    else
-        pm_message("bKGD chunk: not present");
-
-    if (info_ptr->valid & PNG_INFO_PLTE)
-        pm_message("hIST chunk: present");
-    else
-        pm_message("hIST chunk: not present");
-
-    if (info_ptr->valid & PNG_INFO_pHYs)
-        pm_message("pHYs chunk: present");
-    else
-        pm_message("pHYs chunk: not present");
-
-    if (info_ptr->valid & PNG_INFO_oFFs)
-        pm_message("oFFs chunk: present");
-    else
-        pm_message("oFFs chunk: not present");
-
-    if (info_ptr->valid & PNG_INFO_tIME)
-        pm_message("tIME chunk: present");
-    else
-        pm_message("tIME chunk: not present");
-
-    if (info_ptr->valid & PNG_INFO_pCAL)
-        pm_message("pCAL chunk: present");
-    else
-        pm_message("pCAL chunk: not present");
-
-    if (info_ptr->valid & PNG_INFO_sRGB)
-        pm_message("sRGB chunk: present");
-    else
-        pm_message("sRGB chunk: not present");
-}
-
-
-
-static const png_color_16 *
-transColor(struct pngx * const pngxP) {
-
-    png_bytep trans;
-    int numTrans;
-    png_color_16 * transColor;
-
-    assert(pngx_chunkIsPresent(pngxP, PNG_INFO_tRNS));
-    
-    png_get_tRNS(pngxP->png_ptr, pngxP->info_ptr,
-                 &trans, &numTrans, &transColor);
-
-    return transColor;
-}
-
-
-
-static bool
-isTransparentColor(pngcolor      const color,
-                   struct pngx * const pngxP,
-                   double        const totalgamma) {
-/*----------------------------------------------------------------------------
-   Return TRUE iff pixels of color 'color' are supposed to be transparent
-   everywhere they occur.  Assume it's an RGB image.
-
-   'color' has been gamma-corrected.
------------------------------------------------------------------------------*/
-    bool retval;
-
-    if (pngx_chunkIsPresent(pngxP, PNG_INFO_tRNS)) {
-        const png_color_16 * const transColorP = transColor(pngxP);
-
-        /* It seems odd that libpng lets you get gamma-corrected pixel
-           values, but not gamma-corrected transparency or background
-           values.  But as that is the case, we have to gamma-correct
-           the transparency values.
-
-           Note that because we compare the gamma-corrected values and
-           there may be many-to-one mapping of uncorrected to corrected
-           values, more pixels may be transparent than what the user
-           intended.
-
-           We could fix this by not letting libpng gamma-correct the
-           pixels, and just do it ourselves.
-        */
-    
-        switch (pngxP->info_ptr->color_type) {
-        case PNG_COLOR_TYPE_GRAY:
-            retval = color.r == gamma_correct(transColorP->gray, totalgamma);
-            break;
-        default:
-            retval = 
-                color.r == gamma_correct(transColorP->red,   totalgamma) &&
-                color.g == gamma_correct(transColorP->green, totalgamma) &&
-                color.b == gamma_correct(transColorP->blue,  totalgamma);
-        }
-    } else 
-        retval = FALSE;
-
-    return retval;
-}
-
-
-
-static void
-setupGammaCorrection(struct pngx * const pngxP,
-                     float         const displaygamma,
-                     float *       const totalgammaP) {
-
-    if (displaygamma == -1.0)
-        *totalgammaP = -1.0;
-    else {
-        float imageGamma;
-        if (pngxP->info_ptr->valid & PNG_INFO_gAMA)
-            imageGamma = pngxP->info_ptr->gamma;
-        else {
-            if (verbose)
-                pm_message("PNG doesn't specify image gamma.  Assuming 1.0");
-            imageGamma = 1.0;
-        }
-
-        if (fabs(displaygamma * imageGamma - 1.0) < .01) {
-            *totalgammaP = -1.0;
-            if (verbose)
-                pm_message("image gamma %4.2f matches "
-                           "display gamma %4.2f.  No conversion.",
-                           imageGamma, displaygamma);
-        } else {
-            png_set_gamma(pngxP->png_ptr, displaygamma, imageGamma);
-            *totalgammaP = imageGamma * displaygamma;
-            /* in case of gamma-corrections, sBIT's as in the
-               PNG-file are not valid anymore 
-            */
-            pngxP->info_ptr->valid &= ~PNG_INFO_sBIT;
-            if (verbose)
-                pm_message("image gamma is %4.2f, "
-                           "converted for display gamma of %4.2f",
-                           imageGamma, displaygamma);
-        }
-    }
-}
-
-
-
-static bool
-paletteHasPartialTransparency(png_info * const info_ptr) {
-
-    bool retval;
-
-    if (info_ptr->color_type == PNG_COLOR_TYPE_PALETTE) {
-        if (info_ptr->valid & PNG_INFO_tRNS) {
-            bool foundGray;
-            unsigned int i;
-            
-            for (i = 0, foundGray = FALSE;
-                 i < info_ptr->num_trans && !foundGray;
-                 ++i) {
-                if (info_ptr->TRANS_ALPHA[i] != 0 &&
-                    info_ptr->TRANS_ALPHA[i] != maxval) {
-                    foundGray = TRUE;
-                }
-            }
-            retval = foundGray;
-        } else
-            retval = FALSE;
-    } else
-        retval = FALSE;
-
-    return retval;
-}
-
-
-
-static void
-setupSignificantBits(struct pngx *       const pngxP,
-                     enum alpha_handling const alpha,
-                     png_uint_16 *       const maxvalP,
-                     int *               const errorLevelP) {
-/*----------------------------------------------------------------------------
-  Figure out what maxval would best express the information in the PNG
-  described by *pngxP, with 'alpha' telling which information in the PNG we
-  care about (image or alpha mask).
-
-  Return the result as *maxvalP.
------------------------------------------------------------------------------*/
-    png_info * const info_ptr = pngxP->info_ptr;
-
-    /* Initial assumption of maxval */
-    if (info_ptr->color_type == PNG_COLOR_TYPE_PALETTE) {
-        if (alpha == ALPHA_ONLY) {
-            if (info_ptr->color_type == PNG_COLOR_TYPE_GRAY ||
-                info_ptr->color_type == PNG_COLOR_TYPE_RGB)
-                /* The alpha mask will be all opaque, so maxval 1 is plenty */
-                *maxvalP = 1;
-            else if (paletteHasPartialTransparency(info_ptr))
-                /* Use same maxval as PNG transparency palette for simplicity*/
-                *maxvalP = 255;
-            else
-                /* A common case, so we conserve bits */
-                *maxvalP = 1;
-        } else
-            /* Use same maxval as PNG palette for simplicity */
-            *maxvalP = 255;
-    } else {
-        *maxvalP = (1l << info_ptr->bit_depth) - 1;
-    }
-
-    /* sBIT handling is very tricky. If we are extracting only the
-       image, we can use the sBIT info for grayscale and color images,
-       if the three values agree. If we extract the transparency/alpha
-       mask, sBIT is irrelevant for trans and valid for alpha. If we
-       mix both, the multiplication may result in values that require
-       the normal bit depth, so we will use the sBIT info only for
-       transparency, if we know that only solid and fully transparent
-       is used 
-    */
-    
-    if (info_ptr->valid & PNG_INFO_sBIT) {
-        switch (alpha) {
-        case ALPHA_MIX:
-            if (info_ptr->color_type == PNG_COLOR_TYPE_RGB_ALPHA ||
-                info_ptr->color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
-                break;
-            if (info_ptr->color_type == PNG_COLOR_TYPE_PALETTE &&
-                (info_ptr->valid & PNG_INFO_tRNS)) {
-
-                bool trans_mix;
-                unsigned int i;
-                trans_mix = TRUE;
-                for (i = 0; i < info_ptr->num_trans; ++i)
-                    if (info_ptr->TRANS_ALPHA[i] != 0 && info_ptr->TRANS_ALPHA[i] != 255) {
-                        trans_mix = FALSE;
-                        break;
-                    }
-                if (!trans_mix)
-                    break;
-            }
-
-            /* else fall though to normal case */
-
-        case ALPHA_NONE:
-            if ((info_ptr->color_type == PNG_COLOR_TYPE_PALETTE ||
-                 info_ptr->color_type == PNG_COLOR_TYPE_RGB ||
-                 info_ptr->color_type == PNG_COLOR_TYPE_RGB_ALPHA) &&
-                (info_ptr->sig_bit.red != info_ptr->sig_bit.green ||
-                 info_ptr->sig_bit.red != info_ptr->sig_bit.blue) &&
-                alpha == ALPHA_NONE) {
-                pm_message("This program cannot handle "
-                           "different bit depths for color channels");
-                pm_message("writing file with %d bit resolution",
-                           info_ptr->bit_depth);
-                *errorLevelP = PNMTOPNG_WARNING_LEVEL;
-            } else {
-                if ((info_ptr->color_type == PNG_COLOR_TYPE_PALETTE) &&
-                    (info_ptr->sig_bit.red < 255)) {
-                    unsigned int i;
-                    for (i = 0; i < info_ptr->num_palette; ++i) {
-                        info_ptr->palette[i].red   >>=
-                            (8 - info_ptr->sig_bit.red);
-                        info_ptr->palette[i].green >>=
-                            (8 - info_ptr->sig_bit.green);
-                        info_ptr->palette[i].blue  >>=
-                            (8 - info_ptr->sig_bit.blue);
-                    }
-                    *maxvalP = (1l << info_ptr->sig_bit.red) - 1;
-                    if (verbose)
-                        pm_message ("image has fewer significant bits, "
-                                    "writing file with %d bits per channel", 
-                                    info_ptr->sig_bit.red);
-                } else
-                    if ((info_ptr->color_type == PNG_COLOR_TYPE_RGB ||
-                         info_ptr->color_type == PNG_COLOR_TYPE_RGB_ALPHA) &&
-                        (info_ptr->sig_bit.red < info_ptr->bit_depth)) {
-                        png_set_shift(pngxP->png_ptr, &(info_ptr->sig_bit));
-                        *maxvalP = (1l << info_ptr->sig_bit.red) - 1;
-                        if (verbose)
-                            pm_message("image has fewer significant bits, "
-                                       "writing file with %d "
-                                       "bits per channel", 
-                                       info_ptr->sig_bit.red);
-                    } else 
-                        if ((info_ptr->color_type == PNG_COLOR_TYPE_GRAY ||
-                             info_ptr->color_type ==
-                                 PNG_COLOR_TYPE_GRAY_ALPHA) &&
-                            (info_ptr->sig_bit.gray < info_ptr->bit_depth)) {
-                            png_set_shift(pngxP->png_ptr, &info_ptr->sig_bit);
-                            *maxvalP = (1l << info_ptr->sig_bit.gray) - 1;
-                            if (verbose)
-                                pm_message("image has fewer significant bits, "
-                                           "writing file with %d bits",
-                                           info_ptr->sig_bit.gray);
-                        }
-            }
-            break;
-
-        case ALPHA_ONLY:
-            if ((info_ptr->color_type == PNG_COLOR_TYPE_RGB_ALPHA ||
-                 info_ptr->color_type == PNG_COLOR_TYPE_GRAY_ALPHA) && 
-                (info_ptr->sig_bit.gray < info_ptr->bit_depth)) {
-                png_set_shift(pngxP->png_ptr, &info_ptr->sig_bit);
-                if (verbose)
-                    pm_message ("image has fewer significant bits, "
-                                "writing file with %d bits", 
-                                info_ptr->sig_bit.alpha);
-                *maxvalP = (1l << info_ptr->sig_bit.alpha) - 1;
-            }
-            break;
-
-        }
-    }
-}
-
-
-
-static bool
-imageHasColor(struct pngx * const pngxP) {
-
-    bool retval;
-
-    if (pngxP->info_ptr->color_type == PNG_COLOR_TYPE_GRAY ||
-        pngxP->info_ptr->color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
-
-        retval = FALSE;
-    else if (pngxP->info_ptr->color_type == PNG_COLOR_TYPE_PALETTE) {
-        bool foundColor;
-        unsigned int i;
-            
-        for (i = 0, foundColor = FALSE;
-             i < pngxP->info_ptr->num_palette && !foundColor;
-             ++i) {
-            if (iscolor(pngxP->info_ptr->palette[i]))
-                foundColor = TRUE;
-        }
-        retval = foundColor;
-    } else
-        retval = TRUE;
-
-    return retval;
-}
-
-
-
-static void
-determineOutputType(struct pngx *       const pngxP,
-                    enum alpha_handling const alphaHandling,
-                    pngcolor            const bgColor,
-                    xelval              const maxval,
-                    int *               const pnmTypeP) {
-
-    if (alphaHandling != ALPHA_ONLY &&
-        (imageHasColor(pngxP) || !isGrayscale(bgColor)))
-        *pnmTypeP = PPM_TYPE;
-    else {
-        if (maxval > 1)
-            *pnmTypeP = PGM_TYPE;
-        else
-            *pnmTypeP = PBM_TYPE;
-    }
-}
-
-
-
-static void
-getBackgroundColor(struct pngx * const pngxP,
-                   const char *  const requestedColor,
-                   float         const totalgamma,
-                   xelval        const maxval,
-                   pngcolor *    const bgColorP) {
-/*----------------------------------------------------------------------------
-   Figure out what the background color should be.  If the user requested
-   a particular color ('requestedColor' not null), that's the one.
-   Otherwise, if the PNG specifies a background color, that's the one.
-   And otherwise, it's white.
------------------------------------------------------------------------------*/
-    if (requestedColor) {
-        /* Background was specified from the command-line; we always
-           use that.  I chose to do no gamma-correction in this case;
-           which is a bit arbitrary.  
-        */
-        pixel const backcolor = ppm_parsecolor(requestedColor, maxval);
-
-        bgColorP->r = PPM_GETR(backcolor);
-        bgColorP->g = PPM_GETG(backcolor);
-        bgColorP->b = PPM_GETB(backcolor);
-
-    } else if (pngxP->info_ptr->valid & PNG_INFO_bKGD) {
-        /* didn't manage to get libpng to work (bugs?) concerning background
-           processing, therefore we do our own.
-        */
-        switch (pngxP->info_ptr->color_type) {
-        case PNG_COLOR_TYPE_GRAY:
-        case PNG_COLOR_TYPE_GRAY_ALPHA:
-            bgColorP->r = bgColorP->g = bgColorP->b = 
-                gamma_correct(pngxP->info_ptr->background.gray, totalgamma);
-            break;
-        case PNG_COLOR_TYPE_PALETTE: {
-            png_color const rawBgcolor = 
-                pngxP->info_ptr->palette[pngxP->info_ptr->background.index];
-            bgColorP->r = gamma_correct(rawBgcolor.red, totalgamma);
-            bgColorP->g = gamma_correct(rawBgcolor.green, totalgamma);
-            bgColorP->b = gamma_correct(rawBgcolor.blue, totalgamma);
-        }
-        break;
-        case PNG_COLOR_TYPE_RGB:
-        case PNG_COLOR_TYPE_RGB_ALPHA: {
-            png_color_16 const rawBgcolor = pngxP->info_ptr->background;
-            
-            bgColorP->r = gamma_correct(rawBgcolor.red,   totalgamma);
-            bgColorP->g = gamma_correct(rawBgcolor.green, totalgamma);
-            bgColorP->b = gamma_correct(rawBgcolor.blue,  totalgamma);
-        }
-        break;
-        }
-    } else 
-        /* when no background given, we use white [from version 2.37] */
-        bgColorP->r = bgColorP->g = bgColorP->b = maxval;
-}
-
-
-
-static void
-warnNonsquarePixels(struct pngx * const pngxP,
-                    int *         const errorLevelP) {
-
-    if (pngxP->info_ptr->valid & PNG_INFO_pHYs) {
-        float const r =
-            (float)pngxP->info_ptr->x_pixels_per_unit /
-            pngxP->info_ptr->y_pixels_per_unit;
-
-        if (r != 1.0) {
-            pm_message ("warning - non-square pixels; "
-                        "to fix do a 'pamscale -%cscale %g'",
-                        r < 1.0 ? 'x' : 'y',
-                        r < 1.0 ? 1.0 / r : r );
-            *errorLevelP = PNMTOPNG_WARNING_LEVEL;
-        }
-    }
-}
-
-
-
-#define GET_PNG_VAL(p) get_png_val(&(p), pngxP->info_ptr->bit_depth)
-
-
-
-static void
-makeXelRow(xel *               const xelrow,
-           xelval              const maxval,
-           int                 const pnmType,
-           struct pngx *       const pngxP,
-           const png_byte *    const pngRasterRow,
-           pngcolor            const bgColor,
-           enum alpha_handling const alphaHandling,
-           double              const totalgamma) {
-
-    const png_byte * pngPixelP;
-    unsigned int col;
-
-    pngPixelP = &pngRasterRow[0];  /* initial value */
-    for (col = 0; col < pngxP->info_ptr->width; ++col) {
-        switch (pngxP->info_ptr->color_type) {
-        case PNG_COLOR_TYPE_GRAY: {
-            pngcolor fgColor;
-            fgColor.r = fgColor.g = fgColor.b = GET_PNG_VAL(pngPixelP);
-            setXel(&xelrow[col], fgColor, bgColor, alphaHandling,
-                   isTransparentColor(fgColor, pngxP, totalgamma) ?
-                   0 : maxval);
-        }
-        break;
-
-        case PNG_COLOR_TYPE_GRAY_ALPHA: {
-            pngcolor fgColor;
-            png_uint_16 alpha;
-
-            fgColor.r = fgColor.g = fgColor.b = GET_PNG_VAL(pngPixelP);
-            alpha = GET_PNG_VAL(pngPixelP);
-            setXel(&xelrow[col], fgColor, bgColor, alphaHandling, alpha);
-        }
-        break;
-
-        case PNG_COLOR_TYPE_PALETTE: {
-            png_uint_16 const index        = GET_PNG_VAL(pngPixelP);
-            png_color   const paletteColor = pngxP->info_ptr->palette[index];
-
-            pngcolor fgColor;
-
-            fgColor.r = paletteColor.red;
-            fgColor.g = paletteColor.green;
-            fgColor.b = paletteColor.blue;
-
-            setXel(&xelrow[col], fgColor, bgColor, alphaHandling,
-                   (pngxP->info_ptr->valid & PNG_INFO_tRNS) &&
-                   index < pngxP->info_ptr->num_trans ?
-                   pngxP->info_ptr->TRANS_ALPHA[index] : maxval);
-        }
-        break;
-                
-        case PNG_COLOR_TYPE_RGB: {
-            pngcolor fgColor;
-
-            fgColor.r = GET_PNG_VAL(pngPixelP);
-            fgColor.g = GET_PNG_VAL(pngPixelP);
-            fgColor.b = GET_PNG_VAL(pngPixelP);
-            setXel(&xelrow[col], fgColor, bgColor, alphaHandling,
-                   isTransparentColor(fgColor, pngxP, totalgamma) ?
-                   0 : maxval);
-        }
-        break;
-
-        case PNG_COLOR_TYPE_RGB_ALPHA: {
-            pngcolor fgColor;
-            png_uint_16 alpha;
-
-            fgColor.r = GET_PNG_VAL(pngPixelP);
-            fgColor.g = GET_PNG_VAL(pngPixelP);
-            fgColor.b = GET_PNG_VAL(pngPixelP);
-            alpha     = GET_PNG_VAL(pngPixelP);
-            setXel(&xelrow[col], fgColor, bgColor, alphaHandling, alpha);
-        }
-        break;
-
-        default:
-            pm_error("unknown PNG color type: %d",
-                     pngxP->info_ptr->color_type);
-        }
-    }
-}
-
-
-
-static void
-writePnm(FILE *              const ofP,
-         xelval              const maxval,
-         int                 const pnmType,
-         struct pngx *       const pngxP,
-         png_byte **         const pngRaster,
-         pngcolor            const bgColor,
-         enum alpha_handling const alphaHandling,
-         double              const totalgamma) {
-/*----------------------------------------------------------------------------
-   Write a PNM of either the image or the alpha mask, according to
-   'alphaHandling' that is in the PNG image described by *pngxP and
-   pngRaster[][].
-
-   'pnmType' and 'maxval' are of the output image.
-
-   Use background color 'bgColor' in the output if the PNG is such that a
-   background color is needed.
------------------------------------------------------------------------------*/
-    int const plainFalse = 0;
-
-    xel * xelrow;
-    unsigned int row;
-
-    if (verbose)
-        pm_message("writing a %s file (maxval=%u)",
-                   pnmType == PBM_TYPE ? "PBM" :
-                   pnmType == PGM_TYPE ? "PGM" :
-                   pnmType == PPM_TYPE ? "PPM" :
-                   "UNKNOWN!", 
-                   maxval);
-    
-    xelrow = pnm_allocrow(pngxP->info_ptr->width);
-
-    pnm_writepnminit(stdout,
-                     pngxP->info_ptr->width, pngxP->info_ptr->height, maxval,
-                     pnmType, plainFalse);
-
-    for (row = 0; row < pngxP->info_ptr->height; ++row) {
-        makeXelRow(xelrow, maxval, pnmType, pngxP, pngRaster[row], bgColor,
-                   alphaHandling, totalgamma);
-
-        pnm_writepnmrow(ofP, xelrow, pngxP->info_ptr->width, maxval,
-                        pnmType, plainFalse);
-    }
-    pnm_freerow (xelrow);
-}
-
-
-
-static void 
-convertpng(FILE *             const ifP, 
-           FILE *             const tfP, 
-           struct cmdlineInfo const cmdline,
-           int *              const errorLevelP) {
-
-    png_byte ** pngRaster;
-    int pnmType;
-    pngcolor bgColor;
-    float totalgamma;
-    jmp_buf jmpbuf;
-    struct pngx * pngxP;
-
-    *errorLevelP = 0;
-
-    if (setjmp(jmpbuf))
-        pm_error ("setjmp returns error condition");
-
-    pngx_createRead(&pngxP, &jmpbuf);
-
-    readPng(pngxP, ifP, &pngRaster);
-
-    if (verbose)
-        dumpPngInfo(pngxP);
-
-    if (cmdline.time)
-        showTime(pngxP);
-    if (tfP)
-        saveText(pngxP, tfP);
-
-    warnNonsquarePixels(pngxP, errorLevelP);
-
-    setupGammaCorrection(pngxP, cmdline.gamma, &totalgamma);
-
-    setupSignificantBits(pngxP, cmdline.alpha, &maxval, errorLevelP);
-
-    getBackgroundColor(pngxP, cmdline.background, totalgamma, maxval,
-                       &bgColor);
-
-    determineOutputType(pngxP, cmdline.alpha, bgColor, maxval, &pnmType);
-
-    writePnm(stdout, maxval, pnmType, pngxP, pngRaster, bgColor, 
-             cmdline.alpha, totalgamma);
-
-    fflush(stdout);
-
-    freePngRaster(pngRaster, pngxP);
-
-    pngx_destroy(pngxP);
-}
-
-
-
-int 
-main(int argc, const char *argv[]) {
-
-    struct cmdlineInfo cmdline;
-    FILE * ifP;
-    FILE * tfP;
-    int errorLevel;
-
-    pm_proginit(&argc, argv);
-
-    parseCommandLine(argc, argv, &cmdline);
-
-    verbose = cmdline.verbose;
-
-    ifP = pm_openr(cmdline.inputFilespec);
-
-    if (cmdline.text)
-        tfP = pm_openw(cmdline.text);
-    else
-        tfP = NULL;
-
-    convertpng(ifP, tfP, cmdline, &errorLevel);
-
-    if (tfP)
-        pm_close(tfP);
-
-    pm_close(ifP);
-    pm_close(stdout);
-
-    return errorLevel;
-}
diff --git a/converter/other/pngtxt.c b/converter/other/pngtxt.c
index bbbec099..e02ee227 100644
--- a/converter/other/pngtxt.c
+++ b/converter/other/pngtxt.c
@@ -1,122 +1,251 @@
+#define HAVE_PNGLIB_WITH_ITXT 0
+
 #include <stdlib.h>
 #include <string.h>
 #include <stdio.h>
+
 #include <png.h>
 
+#include "mallocvar.h"
 #include "nstring.h"
+#include "pngx.h"
 #include "pngtxt.h"
 #include "pm.h"
-#include "mallocvar.h"
-
-#define MAXCOMMENTS 256
 
 
 
 static void
-readOffKey(char           const textline[],
-           unsigned int   const lineLength,
-           unsigned int * const cursorP,
-           char **        const keyP) {
+readToken(char           const textline[],
+          unsigned int   const lineLength,
+          unsigned int * const cursorP,
+          const char **  const tokenP) {
+/*----------------------------------------------------------------------------
+   Read a token from 'textline' (whose length is 'lineLength'), assuming the
+   cursor is positioned to it now, leaving the cursor positioned after it.
 
-    /* Get the comment key */
+   Tokens are delimited by white space.  We don't skip any white space before
+   or after the token.  Ergo, if we are positioned to white space right now,
+   the token we read is a null string.
+-----------------------------------------------------------------------------*/
+    char * tokenBuffer;
     char * cp;
     unsigned int cursor;
 
     cursor = *cursorP;
     
-    MALLOCARRAY(cp, lineLength + 1);  /* leave room for terminating NUL */
-    if (cp == NULL) 
-        pm_error("Unable to allocate memory for text chunks");
-    
-    *keyP = cp;
+    MALLOCARRAY(tokenBuffer, lineLength + 1);
+    /* leave room for terminating NUL */
+    if (tokenBuffer == NULL) 
+        pm_error("Unable to allocate memory for a %u-character "
+                 "text string file line", lineLength);
+
+    cp = &tokenBuffer[0];  /* initial value */
     
     if (textline[0] == '"') {
-        ++cursor;  /* skip past opening " */
+        ++cursor;  /* skip past opening quotation mark */
         while (textline[cursor] != '"') {
-            if (textline[cursor] == '\0') {
-                *cp = '\0';
-                pm_error("Invalid comment file format:  keyword contains "
+            if (cursor >= lineLength)
+                pm_error("Invalid text string file format.  Line ends in "
+                         "the middle of a quoted token.  Text at the end of "
+                         "the line is '%s'", tokenBuffer);
+            if (textline[cursor] == '\0')
+                pm_error("Invalid text string file format:  Token contains "
                          "a NUL character.  Text leading up to the NUL "
-                         "character is '%s'", *keyP);
-            }
+                         "character is '%s'", tokenBuffer);
             *(cp++) = textline[cursor++];
         }
-        ++cursor;  /* skip past closing " */
+        ++cursor;  /* skip past closing quotation mark */
     } else {
-        while (cursor < lineLength && 
-               textline[cursor] != ' '  && textline[cursor] != '\t' &&
-               textline[cursor] != '\0')
+        while ((cursor < lineLength) && 
+               (textline[cursor] != ' ') && (textline[cursor] != '\t')) {
+            
+            if (textline[cursor] == '\0')
+                pm_error("Invalid text string file format:  Token contains "
+                         "a NUL character.  Text leading up to the NUL "
+                         "character is '%s'", tokenBuffer);
             *(cp++) = textline[cursor++];
+        }
     }
     *cp++ = '\0';
 
     *cursorP = cursor;
+
+    *tokenP = tokenBuffer;
 }
 
 
 
 
 static void
-startComment(struct png_text_struct * const commentP, 
-             char                     const textline[],
-             unsigned int             const lineLength,
-             bool                     const compressed) {
+skipWhiteSpace(char           const textline[],
+               unsigned int   const lineLength,
+               unsigned int * const cursorP) {
 /*----------------------------------------------------------------------------
-   Assuming 'textline' is the first line of a comment in a comment file,
-   put the information from it in the comment record *commentP.
-   Use the text on this line as the comment text, even though the true
-   comment text may include text from subsequent continuation lines as
-   well.
+   Move *cursorP past white space (or, for some reason, NUL characters),
+   in 'textline', which is 'lineLength' long.
+-----------------------------------------------------------------------------*/
+    unsigned int cursor;
 
-   'textline' is not NUL-terminated.  Its length is 'lineLength', and
-   it is at least one character long.  'textline' does not contain a
-   newline character.
+    cursor = *cursorP;  /* initial value */
+
+    while (cursor < lineLength && 
+           (textline[cursor] == ' ' || textline[cursor] == '\t' ||
+            textline[cursor] == '\0'))
+        ++cursor;
 
-   'compressed' means the comment text is compressed.
+    *cursorP = cursor;
+}
+
+
+
+static void
+readTextString(char          const textline[],
+               unsigned int  const lineLength,
+               unsigned int  const startPos,
+               png_charp *   const textStringP,
+               png_size_t *  const textStringLengthP) {
+/*----------------------------------------------------------------------------
+  Extract the text string at 'startPos' in the buffer 'textline', whose
+  length is 'lineLength'.  Return it in newly malloced storage with a
+  pointer to that storage as 'textString' and the size of the text as
+  *textStringLengthP.
 -----------------------------------------------------------------------------*/
-    unsigned int cursor;
+    char * cp;
+
+    MALLOCARRAY(cp, lineLength + 1);  /* incl '\0' */
+    if (!cp) 
+        pm_error("Unable to allocate memory for text chunks");
+
+    memcpy(cp, textline + startPos, lineLength - startPos);
+    cp[lineLength - startPos] = '\0';  /* for safety - not part of text */
+    *textStringP = cp;
+    *textStringLengthP = lineLength - startPos;
+}
+
 
-    /* the following is a not that accurate check on Author or Title */
-    if ((!compressed) || (textline[0] == 'A') || (textline[0] == 'T'))
-        commentP->compression = -1;
-    else
-        commentP->compression = 0;
+
+static void
+startTextChunkEngl(png_text *   const textChunkP, 
+                   char         const textline[],
+                   unsigned int const lineLength,
+                   bool         const isCompressed,
+                   bool         const verbose) {
+/*----------------------------------------------------------------------------
+   Assuming 'textline' is the first line of an entry in an English text
+   string file, put the information from it in the comment record *textChunkP.
+   Use the text on this line as the comment text, even though the true text
+   string may include text from subsequent continuation lines as well.
+
+   'textline' is not NUL-terminated.  Its length is 'lineLength', and it is at
+   least one character long.  'textline' does not contain a newline character.
+
+   'isCompressed' means it is a compressed text chunk.
+-----------------------------------------------------------------------------*/
+    unsigned int cursor;
 
     cursor = 0;
 
-    readOffKey(textline, lineLength, &cursor, &commentP->key);
+    {
+        const char * key;
+
+        readToken(textline, lineLength, &cursor, &key);
+
+        pngx_setTextKey(textChunkP, key);
+
+        pm_strfree(key);
+    }
+
+    skipWhiteSpace(textline, lineLength, &cursor);
+
+    pngx_setTextLang(textChunkP, NULL);
+
+    readTextString(textline, lineLength, cursor, &textChunkP->text,
+                   &textChunkP->text_length);
+
+    textChunkP->compression =
+        isCompressed ? PNG_TEXT_COMPRESSION_zTXt : PNG_TEXT_COMPRESSION_NONE;
+}
+
+
+
+static void
+startTextChunkIntl(png_text *   const textChunkP, 
+                   char         const textline[],
+                   unsigned int const lineLength,
+                   bool         const isCompressed,
+                   bool         const verbose) {
+/*----------------------------------------------------------------------------
+  Assuming 'textline' is the first line of an entry in an international (not
+  English) text string file, put the information from it in the text chunk
+  *textChunkP.  Use the text on this line as the text string, even though the
+  true text string may include text from subsequent continuation lines as
+  well.
+
+  'textline' is not NUL-terminated.  Its length is 'lineLength', and it is at
+  least one character long.  'textline' does not contain a newline character.
+
+  'isInternational' means it is an international (i.e. non-English) text
+  chunk.
+
+  Leave the language attribute (textChunkP->lang) unset.
+-----------------------------------------------------------------------------*/
+    unsigned int cursor;
+
+    cursor = 0;  /* Initial value */
 
-    /* skip over delimiters between key and comment text */
-    while (cursor < lineLength && 
-           (textline[cursor] == ' ' || textline[cursor] == '\t' ||
-           textline[cursor] == '\0'))
-        ++cursor;
-    
     {
-        /* Get the first line of the comment text */
-        unsigned int const startPos = cursor;
-        char *cp;
-
-        MALLOCARRAY(cp, lineLength+1);  /* leave room for safety NUL */
-        if (!cp) 
-            pm_error("Unable to allocate memory for text chunks");
-
-        memcpy(cp, textline + startPos, lineLength - startPos);
-        cp[lineLength - startPos] = '\0';  /* for safety - not part of text */
-        commentP->text = cp;
-        commentP->text_length = lineLength - startPos;
+        const char * key;
+
+        readToken(textline, lineLength, &cursor, &key);
+
+        pngx_setTextKey(textChunkP, key);
+
+        pm_strfree(key);
     }
+
+    skipWhiteSpace(textline, lineLength, &cursor);
+
+    {
+        const char * isoLang;
+
+        readToken(textline, lineLength, &cursor, &isoLang);
+
+        pngx_setTextLang(textChunkP, isoLang);
+
+        pm_strfree(isoLang);
+    }
+
+    skipWhiteSpace(textline, lineLength, &cursor);
+
+    {
+        const char * langKey;
+    
+        readToken(textline, lineLength, &cursor, &langKey);
+
+        pngx_setTextLangKey(textChunkP, langKey);
+
+        pm_strfree(langKey);
+    }
+
+    skipWhiteSpace(textline, lineLength, &cursor);
+
+    /* Beginning of text string (continuation lines may follow) */
+    readTextString(textline, lineLength, cursor, &textChunkP->text,
+                   &textChunkP->text_length);
+
+    textChunkP->compression = 
+        isCompressed ? PNG_ITXT_COMPRESSION_zTXt :PNG_ITXT_COMPRESSION_NONE;
 }
 
 
 
 static void
-continueComment(struct png_text_struct * const commentP, 
-                char                     const textline[],
-                unsigned int             const lineLength) {
+continueTextString(png_text *   const textChunkP, 
+                   char         const textline[],
+                   unsigned int const lineLength) {
 /*----------------------------------------------------------------------------
-   Update the comment record *commentP by adding to it the text
-   from textline[], which is a continuation line from a comment file.
+   Update the text chunk *textChunkP by adding to it the text from
+   textline[], which is a continuation line from a text string file.
 
    'textline' is not NUL-terminated.  Its length is 'lineLength', and
    it is at least one character long.  'textline' does not contain a
@@ -125,29 +254,27 @@ continueComment(struct png_text_struct * const commentP,
     unsigned int cursor;  /* cursor into textline[] */
 
     unsigned int const newTextLength =
-        commentP->text_length + lineLength + 1 + 1;
+        textChunkP->text_length + lineLength + 1 + 1;
 
-    REALLOCARRAY(commentP->text, newTextLength);
+    REALLOCARRAY(textChunkP->text, newTextLength);
 
-    if (commentP->text == NULL)
-        pm_error("Unable to allocate %u bytes of memory for comment chunk",
+    if (textChunkP->text == NULL)
+        pm_error("Unable to allocate %u bytes of memory for text string",
                  newTextLength);
 
-    commentP->text[commentP->text_length++] = '\n';
+    textChunkP->text[textChunkP->text_length++] = '\n';
 
-    /* Skip past leading delimiter characters in file line */
-    cursor = 0;
-    while (textline[cursor] == ' ' || textline[cursor] == '\t' ||
-           textline[cursor] == '\0')
-        ++cursor;
+    cursor = 0; 
+
+    skipWhiteSpace(textline, lineLength, &cursor);
 
-    memcpy(commentP->text + commentP->text_length,
+    memcpy(textChunkP->text + textChunkP->text_length,
            textline + cursor,
            lineLength - cursor);
 
-    commentP->text_length += lineLength - cursor;
+    textChunkP->text_length += lineLength - cursor;
 
-    commentP->text[commentP->text_length] = '\0';  /* for safety */
+    textChunkP->text[textChunkP->text_length] = '\0';  /* for safety */
 }
 
 
@@ -171,16 +298,16 @@ getFileLine(FILE *         const fileP,
 -----------------------------------------------------------------------------*/
     char * textline;  /* malloc'ed */
     unsigned int cursor;  /* cursor into textline[] */
-    unsigned int allocated;
+    unsigned int allocatedSz;
         /* The number of characters of space that are allocated for
            'textline' 
         */
     bool eol;
     bool gotSomething;
 
-    allocated = 128;  /* initial value */
+    allocatedSz = 128;  /* initial value */
 
-    MALLOCARRAY(textline, allocated);
+    MALLOCARRAY(textline, allocatedSz);
     if (textline == NULL)
         pm_error("Unable to allocate buffer to read a line of a file.");
     
@@ -197,9 +324,10 @@ getFileLine(FILE *         const fileP,
         if (c == '\n' || c == EOF)
             eol = TRUE;
         else {
-            if (cursor > allocated - 1 - 1) { /* leave space for safety NUL */
-                allocated *= 2;
-                REALLOCARRAY(textline, allocated);
+            /* leave space for safety NUL */
+            if (cursor > allocatedSz - 1 - 1) {
+                allocatedSz *= 2;
+                REALLOCARRAY(textline, allocatedSz);
                 if (textline == NULL)
                     pm_error("Unable to allocate buffer to read a line of "
                              "a file.");
@@ -222,93 +350,153 @@ getFileLine(FILE *         const fileP,
 
 static void
 handleArrayAllocation(png_text **    const arrayP,
-                      unsigned int * const allocatedCommentsP,
-                      unsigned int   const commentIdx) {
+                      unsigned int * const allocatedChunkCtP,
+                      unsigned int   const chunkIdx) {
 
-    if (commentIdx >= *allocatedCommentsP) {
-        *allocatedCommentsP *= 2;
-        REALLOCARRAY(*arrayP, *allocatedCommentsP);
+    if (chunkIdx >= *allocatedChunkCtP) {
+        *allocatedChunkCtP *= 2;
+        REALLOCARRAY(*arrayP, *allocatedChunkCtP);
         if (*arrayP == NULL) 
-            pm_error("unable to allocate memory for comment array");
+            pm_error("unable to allocate memory for %u text chunks",
+                *allocatedChunkCtP);
     }
 }
 
 
+
+static bool
+isContinuationLine(const char * const line) {
+/*----------------------------------------------------------------------------
+   Text line 'line', if it is from a text string file, is a continuation of a
+   text string started in an earlier line.
+
+   What identifies a line as a continuation line is that it starts with
+   a space or tab.
+-----------------------------------------------------------------------------*/
+    return line[0] == ' ' || line[0] == '\t';
+}
+
+
+
+static void
+reportChunkCt(bool         const ztxt,
+              bool         const itxt,
+              unsigned int const chunkCt) {
+
+    const char * chunkType;
+
+    if (itxt)
+        chunkType = "iTXt";
+    else {
+        if (ztxt)
+            chunkType = "zTXt";
+        else
+            chunkType = "tEXt";
+    }
+
+    pm_message("Writing %u %s chunks", chunkCt, chunkType);
+}
+
+
+
 /******************************************************************************
                             EXTERNAL SUBROUTINES
 ******************************************************************************/
 
 
 void 
-pnmpng_read_text (png_info * const info_ptr, 
-                  FILE *     const tfp, 
-                  bool       const ztxt,
-                  bool       const verbose) {
-
-    const char * textline;
-    unsigned int lineLength;
-    unsigned int commentIdx;
-    bool noCommentsYet;
+pngtxt_addChunk(struct pngx * const pngxP,
+                FILE *        const tfP, 
+                bool          const ztxt,
+                bool          const itxt,
+                bool          const verbose) {
+/*----------------------------------------------------------------------------
+   Add text chunks (tEXt, zTXt, or iTXt) to the PNG image represented by
+   *pngxP as directed by file *tfP.
+
+   'itxt' means to make them international language (iTXt) chunks.  Otherwise
+   they are either tEXt or zTXt chunks, depending upon 'ztxt'.
+
+   'ztxt' means to make the text compressed.  If the chunks are not
+   international (i.e. 'itxt' is false), this means the chunks are zTXt chunks
+   instead of 'tEXt' chunks.
+-----------------------------------------------------------------------------*/
+    bool noChunksYet;
     bool eof;
-    unsigned int allocatedComments;
-        /* Number of entries currently allocated for the info_ptr->text
-           array 
-        */
+    png_textp text;  /* An array; one chunk per element */
+    unsigned int chunkCt;
+        /* Number of chunks we have completed in the 'text' array */
+    unsigned int allocatedChunkCt;
+        /* Number of entries currently allocated for the PNG text array */
+
+    /* In an international text string file, the first entry tells the
+       language of all of the chunks, by having key 'Language'.
+    */
 
-    allocatedComments = 256;  /* initial value */
+    allocatedChunkCt = 256;  /* initial value */
 
-    MALLOCARRAY(info_ptr->text, allocatedComments);
-    if (info_ptr->text == NULL) 
-        pm_error("unable to allocate memory for comment array");
+    MALLOCARRAY(text, allocatedChunkCt);
+    if (text == NULL) 
+        pm_error("unable to allocate memory for text chunk array");
 
-    commentIdx = 0;
-    noCommentsYet = TRUE;
-   
-    eof = FALSE;
-    while (!eof) {
-        getFileLine(tfp, &textline, &lineLength);
+    for (chunkCt = 0, noChunksYet = true, eof = false; !eof; ) {
+        const char * textline;
+        unsigned int lineLength;
+
+        getFileLine(tfP, &textline, &lineLength);
         if (textline == NULL)
-            eof = TRUE;
+            eof = true;
         else {
             if (lineLength == 0) {
                 /* skip this empty line */
             } else {
-                handleArrayAllocation(&info_ptr->text, &allocatedComments,
-                                      commentIdx);
-                if ((textline[0] != ' ') && (textline[0] != '\t')) {
-                    /* Line doesn't start with white space, which
-                       means it starts a new comment.  
-                    */
-                    if (noCommentsYet) {
-                        /* No previous comment to move past */
-                    } else
-                        ++commentIdx;
-                    noCommentsYet = FALSE;
+                handleArrayAllocation(&text, &allocatedChunkCt, chunkCt);
+
+                if (!isContinuationLine(textline)) {
+                    png_text * textChunkP;
 
-                    startComment(&info_ptr->text[commentIdx], 
-                                 textline, lineLength, ztxt);
+                    if (noChunksYet) {
+                        /* No previous chunk to move past */
+                    } else
+                        ++chunkCt;
+                    noChunksYet = false;
+                    
+                    textChunkP = &text[chunkCt];
+                
+                    if (itxt)
+                        startTextChunkIntl(textChunkP, 
+                                           textline, lineLength, ztxt,
+                                           verbose);
+                    else
+                        startTextChunkEngl(textChunkP, 
+                                           textline, lineLength, ztxt,
+                                           verbose);
                 } else {
+                    png_text * const textChunkP = &text[chunkCt];
+
                     /* Line starts with whitespace, which means it is
-                       a continuation of the current comment.
+                       a continuation of the current text string.
                     */
-                    if (noCommentsYet)
-                        pm_error("Invalid comment file format: "
+                    if (noChunksYet)
+                        pm_error("Invalid text string file format: "
                                  "first line is a continuation line! "
                                  "(It starts with whitespace)");
-                    continueComment(&info_ptr->text[commentIdx], 
-                                    textline, lineLength);
+                    continueTextString(textChunkP, textline, lineLength);
                 }
             }
-            strfree(textline);
+            pm_strfree(textline);
         }
-    } 
-    if (noCommentsYet)
-        info_ptr->num_text = 0;
-    else
-        info_ptr->num_text = commentIdx + 1;
+    }
+    if (!noChunksYet)
+        ++chunkCt;
 
     if (verbose)
-        pm_message("%d comments placed in text chunk", info_ptr->num_text);
+        reportChunkCt(ztxt, itxt, chunkCt);
+
+    if (chunkCt > 0)
+        pngx_setText(pngxP, text, chunkCt);
+
+    free(text);
 }
 
 
diff --git a/converter/other/pngtxt.h b/converter/other/pngtxt.h
index ae7fe2c4..3e6ff2af 100644
--- a/converter/other/pngtxt.h
+++ b/converter/other/pngtxt.h
@@ -1,13 +1,17 @@
 #ifndef PNGTXT_H_INCLUDED
 #define PNGTXT_H_INCLUDED
 
-#include "pm_c_util.h"
+#include <stdbool.h>
+#include <stdio.h>
 #include <png.h>
 
+struct pngx;
+
 void 
-pnmpng_read_text (png_info * const info_ptr, 
-                  FILE *     const tfp, 
-                  bool const ztxt,
-                  bool const verbose);
+pngtxt_addChunk(struct pngx * const pngxP,
+                FILE *        const tfp, 
+                bool          const ztxt,
+                bool          const itxt,
+                bool          const verbose);
 
 #endif
diff --git a/converter/other/pngx.c b/converter/other/pngx.c
new file mode 100644
index 00000000..185b4a27
--- /dev/null
+++ b/converter/other/pngx.c
@@ -0,0 +1,757 @@
+#include <assert.h>
+#include <png.h>
+#include "pm_c_util.h"
+#include "mallocvar.h"
+#include "nstring.h"
+#include "pm.h"
+
+/* <png.h> defines (or doesn't) PNG_iTXt_SUPPORTED to tell us whether libpng
+   has facilities related to PNG iTXt chunks.
+*/
+#ifdef PNG_iTXt_SUPPORTED
+  #define HAVE_PNGLIB_WITH_ITXT 1
+#else
+  #define HAVE_PNGLIB_WITH_ITXT 0
+#endif
+
+#include "pngx.h"
+
+
+static void
+errorHandler(png_structp     const png_ptr,
+             png_const_charp const msg) {
+
+    jmp_buf * jmpbufP;
+
+    /* this function, aside from the extra step of retrieving the "error
+       pointer" (below) and the fact that it exists within the application
+       rather than within libpng, is essentially identical to libpng's
+       default error handler.  The second point is critical:  since both
+       setjmp() and longjmp() are called from the same code, they are
+       guaranteed to have compatible notions of how big a jmp_buf is,
+       regardless of whether _BSD_SOURCE or anything else has (or has not)
+       been defined.
+    */
+
+    pm_message("fatal libpng error: %s", msg);
+
+    jmpbufP = png_get_error_ptr(png_ptr);
+
+    if (!jmpbufP) {
+        /* we are completely hosed now */
+        pm_error("EXTREMELY fatal error: jmpbuf unrecoverable; terminating.");
+    }
+
+    longjmp(*jmpbufP, 1);
+}
+
+
+
+void
+pngx_create(struct pngx ** const pngxPP,
+            pngx_rw        const rw,
+            jmp_buf *      const jmpbufP) {
+
+    struct pngx * pngxP;
+
+    MALLOCVAR(pngxP);
+
+    if (!pngxP)
+        pm_error("Failed to allocate memory for PNG object");
+    else {
+        pngxP->numPassesRequired = 1;
+
+        switch(rw) {
+        case PNGX_READ:
+            pngxP->png_ptr = png_create_read_struct(
+                PNG_LIBPNG_VER_STRING,
+                jmpbufP, errorHandler, NULL);
+            break;
+        case PNGX_WRITE:
+            pngxP->png_ptr = png_create_write_struct(
+                PNG_LIBPNG_VER_STRING,
+                jmpbufP, errorHandler, NULL);
+            break;
+        }
+        if (!pngxP->png_ptr)
+            pm_error("cannot allocate main libpng structure (png_ptr)");
+        else {
+            pngxP->info_ptr = png_create_info_struct(pngxP->png_ptr);
+
+            if (!pngxP->info_ptr)
+                pm_error("cannot allocate libpng info structure (info_ptr)");
+            else
+                *pngxPP = pngxP;
+        }
+        pngxP->rw = rw;
+    }
+}
+
+
+
+void
+pngx_destroy(struct pngx * const pngxP) {
+
+    switch(pngxP->rw) {
+    case PNGX_READ:
+        png_destroy_read_struct(&pngxP->png_ptr, &pngxP->info_ptr, NULL);
+        break;
+    case PNGX_WRITE:
+        png_destroy_write_struct(&pngxP->png_ptr, &pngxP->info_ptr);
+        break;
+    }
+
+    free(pngxP);
+}
+
+
+
+bool
+pngx_chunkIsPresent(struct pngx * const pngxP,
+                    uint32_t      const chunkType) {
+
+    return png_get_valid(pngxP->png_ptr, pngxP->info_ptr, chunkType);
+}
+
+
+
+unsigned int
+pngx_bitDepth(struct pngx * const pngxP) {
+
+    return png_get_bit_depth(pngxP->png_ptr, pngxP->info_ptr);
+}
+
+
+
+png_color_16
+pngx_bkgd(struct pngx * const pngxP) {
+
+    png_color_16 * colorP;
+
+    png_get_bKGD(pngxP->png_ptr, pngxP->info_ptr, &colorP);
+
+    return *colorP;
+}
+
+
+
+png_byte
+pngx_colorType(struct pngx * const pngxP) {
+
+    return png_get_color_type(pngxP->png_ptr, pngxP->info_ptr);
+}
+
+
+
+png_byte
+pngx_filterType(struct pngx * const pngxP) {
+
+    return png_get_filter_type(pngxP->png_ptr, pngxP->info_ptr);
+}
+
+
+
+double
+pngx_gama(struct pngx * const pngxP) {
+
+    double retval;
+
+    png_get_gAMA(pngxP->png_ptr, pngxP->info_ptr, &retval);
+
+    return retval;
+}
+
+
+
+uint32_t
+pngx_imageHeight(struct pngx * const pngxP) {
+
+    return png_get_image_height(pngxP->png_ptr, pngxP->info_ptr);
+}
+
+
+
+uint32_t
+pngx_imageWidth(struct pngx * const pngxP) {
+
+    return png_get_image_width(pngxP->png_ptr, pngxP->info_ptr);
+}
+
+
+
+png_byte
+pngx_interlaceType(struct pngx * const pngxP) {
+
+    return png_get_interlace_type(pngxP->png_ptr, pngxP->info_ptr);
+}
+
+
+
+struct pngx_plte
+pngx_plte(struct pngx * const pngxP) {
+
+    struct pngx_plte retval;
+
+    int size;
+
+    png_get_PLTE(pngxP->png_ptr, pngxP->info_ptr, &retval.palette, &size);
+
+    assert(size >= 0);
+
+    retval.size = size;
+
+    return retval;
+}
+
+
+
+png_color_8
+pngx_sbit(struct pngx *   const pngxP) {
+
+    png_color_8 * sbitP;
+
+    png_get_sBIT(pngxP->png_ptr, pngxP->info_ptr, &sbitP);
+
+    return *sbitP;
+}
+
+
+
+struct pngx_text
+pngx_text(struct pngx * const pngxP) {
+
+    struct pngx_text retval;
+
+    int size;
+
+    png_get_text(pngxP->png_ptr, pngxP->info_ptr, &retval.line, &size);
+
+    assert(size >= 0);
+
+    retval.size = size;
+
+    return retval;
+}
+
+
+
+png_time
+pngx_time(struct pngx * const pngxP) {
+
+    png_time * timeP;
+
+    png_get_tIME(pngxP->png_ptr, pngxP->info_ptr, &timeP);
+
+    return *timeP;
+}
+
+
+
+struct pngx_trns
+pngx_trns(struct pngx * const pngxP) {
+
+    struct pngx_trns retval;
+
+    int numTrans;
+    png_color_16 * transColorP;
+
+    png_get_tRNS(pngxP->png_ptr, pngxP->info_ptr,
+                 &retval.trans, &numTrans, &transColorP);
+
+    assert(numTrans >= 0);
+
+    retval.numTrans = numTrans;
+    retval.transColor = *transColorP;
+
+    return retval;
+}
+
+
+
+uint32_t
+pngx_xPixelsPerMeter(struct pngx * const pngxP) {
+/*----------------------------------------------------------------------------
+  Horizontal pixel density in pixel per meter; 0 if unknown.
+-----------------------------------------------------------------------------*/
+    return png_get_x_pixels_per_meter(pngxP->png_ptr, pngxP->info_ptr);
+}
+
+
+
+float
+pngx_pixelAspectRatio(struct pngx * const pngxP) {
+/*----------------------------------------------------------------------------
+  Aspect ratio - y/x.  0.0 if unknown
+-----------------------------------------------------------------------------*/
+    return png_get_pixel_aspect_ratio(pngxP->png_ptr, pngxP->info_ptr);
+}
+
+
+
+bool
+pngx_pixelAspectRatioIsKnown(struct pngx * const pngxP) {
+/*----------------------------------------------------------------------------
+  There is pixel aspect ratio information in the PNG image.
+-----------------------------------------------------------------------------*/
+    return png_get_pixel_aspect_ratio(pngxP->png_ptr, pngxP->info_ptr) != 0.0;
+}
+
+
+
+uint32_t
+pngx_yPixelsPerMeter(struct pngx * const pngxP) {
+/*----------------------------------------------------------------------------
+  Vertical pixel density in pixel per meter; 0 if unknown.
+-----------------------------------------------------------------------------*/
+    return png_get_y_pixels_per_meter(pngxP->png_ptr, pngxP->info_ptr);
+}
+
+
+
+void
+pngx_removeChunk(struct pngx * const pngxP,
+                 uint32_t      const chunkType) {
+
+    png_set_invalid(pngxP->png_ptr, pngxP->info_ptr, chunkType);
+}
+
+
+
+void
+pngx_setBkgdPalette(struct pngx * const pngxP,
+                    unsigned int  const backgroundIndex) {
+
+    png_color_16 background;
+
+    background.index = backgroundIndex;
+
+    png_set_bKGD(pngxP->png_ptr, pngxP->info_ptr, &background);
+}
+
+
+
+void
+pngx_setBkgdRgb(struct pngx * const pngxP,
+                png_color_16  const backgroundArg) {
+
+    png_color_16 background;
+
+    background = backgroundArg;
+
+    png_set_bKGD(pngxP->png_ptr, pngxP->info_ptr, &background);
+}
+
+
+
+void
+pngx_setChrm(struct pngx *      const pngxP,
+             struct pngx_chroma const chroma) {
+
+    png_set_cHRM(pngxP->png_ptr, pngxP->info_ptr, 
+                 chroma.wx, chroma.wy,
+                 chroma.rx, chroma.ry,
+                 chroma.gx, chroma.gy,
+                 chroma.bx, chroma.by);
+}
+
+
+
+const char *
+pngx_srgbIntentDesc(pngx_srgbIntent const srgbIntent) {
+
+    switch (srgbIntent) {
+    case PNGX_PERCEPTUAL:            return "PERCEPTUAL";
+    case PNGX_RELATIVE_COLORIMETRIC: return "RELATIVE COLORIMETRIC";
+    case PNGX_SATURATION:            return "SATURATION";
+    case PNGX_ABSOLUTE_COLORIMETRIC: return "ABSOLUTE_COLORIMETRIC";
+    }
+    assert(false);
+}
+
+
+
+static int
+const libpngSrgbIntentCode(pngx_srgbIntent const srgbIntent) {
+
+    switch (srgbIntent) {
+    case PNGX_PERCEPTUAL:            return 0;
+    case PNGX_RELATIVE_COLORIMETRIC: return 1;
+    case PNGX_SATURATION:            return 2;
+    case PNGX_ABSOLUTE_COLORIMETRIC: return 3;
+    }
+
+    assert(false);  /* All cases above return */
+}
+
+
+
+void
+pngx_setSrgb(struct pngx *   const pngxP,
+             pngx_srgbIntent const srgbIntent) {
+
+    png_set_sRGB(pngxP->png_ptr, pngxP->info_ptr,
+                 libpngSrgbIntentCode(srgbIntent));
+}
+
+
+
+void
+pngx_setCompressionSize(struct pngx * const pngxP,
+                        unsigned int  const bufferSize) {
+
+#if PNG_LIBPNG_VER >= 10009
+    png_set_compression_buffer_size(pngxP->png_ptr, bufferSize);
+#else
+    pm_error("Your PNG library cannot set the compression buffer size.  "
+             "You need at least Version 1.0.9 of Libpng; you have Version %s",
+             PNG_LIBPNG_VER_STRING);
+#endif
+}
+
+
+
+void
+pngx_setFilter(struct pngx * const pngxP,
+               int           const filterSet) {
+
+    png_set_filter(pngxP->png_ptr, 0, filterSet);
+}
+
+
+
+void
+pngx_setGama(struct pngx * const pngxP,
+             float         const fileGamma) {
+
+    png_set_gAMA(pngxP->png_ptr, pngxP->info_ptr, fileGamma);
+}
+
+
+
+void
+pngx_setGamma(struct pngx * const pngxP,
+              float         const screenGamma,
+              float         const imageGamma) {
+
+    png_set_gamma(pngxP->png_ptr, screenGamma, imageGamma);
+}
+
+
+
+void
+pngx_setHist(struct pngx * const pngxP,
+             png_uint_16 * const histogram) {
+
+    png_set_hIST(pngxP->png_ptr, pngxP->info_ptr, histogram);
+}
+
+
+
+void
+pngx_setIhdr(struct pngx * const pngxP,
+             unsigned int  const width,
+             unsigned int  const height,
+             unsigned int  const bitDepth,
+             int           const colorType,
+             int           const interlaceMethod,
+             int           const compressionMethod,
+             int           const filterMethod) {
+
+    png_set_IHDR(pngxP->png_ptr, pngxP->info_ptr, width, height,
+                 bitDepth, colorType, interlaceMethod, compressionMethod,
+                 filterMethod);
+}
+
+
+
+void
+pngx_setInterlaceHandling(struct pngx * const pngxP) {
+
+    pngxP->numPassesRequired = png_set_interlace_handling(pngxP->png_ptr);
+}
+
+
+
+void
+pngx_setPacking(struct pngx * const pngxP) {
+
+    png_set_packing(pngxP->png_ptr);
+}
+
+
+
+void
+pngx_setPhys(struct pngx *    const pngxP,
+             struct pngx_phys const phys) {
+
+    png_set_pHYs(pngxP->png_ptr, pngxP->info_ptr, 
+                 phys.x, phys.y, phys.unit);
+}
+
+
+
+void
+pngx_setPlte(struct pngx * const pngxP,
+             png_color *   const palette,
+             unsigned int  const paletteSize) {
+
+    png_set_PLTE(pngxP->png_ptr, pngxP->info_ptr, palette, paletteSize);
+}
+
+
+
+void
+pngx_setSbit(struct pngx * const pngxP,
+             png_color_8   const sbitArg) {
+
+    png_color_8 sbit;
+
+    sbit = sbitArg;
+
+    png_set_sBIT(pngxP->png_ptr, pngxP->info_ptr, &sbit);
+}
+
+
+
+void
+pngx_setShift(struct pngx * const pngxP,
+              png_color_8   const sigBitArg) {
+
+    png_color_8 sigBit;
+
+    sigBit = sigBitArg;
+
+    png_set_shift(pngxP->png_ptr, &sigBit);
+}
+
+
+
+void
+pngx_setSigBytes(struct pngx * const pngxP,
+                 unsigned int  const sigByteCt) {
+
+    assert(sigByteCt <= INT_MAX);
+
+    png_set_sig_bytes(pngxP->png_ptr, sigByteCt);
+}
+
+
+
+void
+pngx_setTextKey(png_text *   const textP,
+                const char * const key) {
+
+    /* textP->key is improperly declared in libpng as char *; should
+       be const char *
+    */
+    textP->key = (char *)pm_strdup(key);
+}
+
+
+
+void
+pngx_setTextLang(png_text *   const textP,
+                 const char * const language) {
+
+#if HAVE_PNGLIB_WITH_ITXT
+    if (language)
+        textP->lang = (char *)pm_strdup(language);
+    else
+        textP->lang = NULL;
+#else
+    if (language)
+        pm_error("PNG library does not have ability to create an iTXT "
+                 "chunk (i.e. to create a PNG with text strings in a language "
+                 "other than English)");
+#endif
+}
+
+
+
+void
+pngx_setTextLangKey(png_text *   const textP,
+                    const char * const key) {
+
+#if HAVE_PNGLIB_WITH_ITXT
+    textP->lang_key = (char *)pm_strdup(key);
+#else
+    pm_error("PNG library does not have ability to create an iTXT "
+             "chunk (i.e. to create a PNG with text strings in a language "
+             "other than English)");
+#endif
+}
+
+
+void
+pngx_termText(png_text * const textP) {
+
+    pm_strfree(textP->key);
+
+#if HAVE_PNGLIB_WITH_ITXT
+    if (textP->lang) {
+        pm_strfree(textP->lang);
+        pm_strfree(textP->lang_key);
+    }
+#endif
+
+    free(textP->text);
+}
+
+
+
+void
+pngx_setText(struct pngx * const pngxP,
+             png_text *    const textP,
+             unsigned int  const count) {
+
+    png_set_text(pngxP->png_ptr, pngxP->info_ptr, textP, count);
+}
+
+
+
+void
+pngx_setTime(struct pngx * const pngxP,
+             time_t        const timeArg) {
+
+    png_time pngTime;
+
+    png_convert_from_time_t(&pngTime, timeArg);
+
+    png_set_tIME(pngxP->png_ptr, pngxP->info_ptr, &pngTime);
+}
+
+
+
+void
+pngx_setTrnsPalette(struct pngx *    const pngxP,
+                    const png_byte * const transPalette,
+                    unsigned int     const paletteSize) {
+
+    png_set_tRNS(pngxP->png_ptr, pngxP->info_ptr,
+                 (png_byte *)transPalette, paletteSize, NULL);
+}
+
+
+
+void
+pngx_setTrnsValue(struct pngx * const pngxP,
+                  png_color_16  const transColorArg) {
+
+    png_color_16 transColor;
+
+    transColor = transColorArg;
+
+    png_set_tRNS(pngxP->png_ptr, pngxP->info_ptr,
+                 NULL, 0, &transColor);
+}
+
+
+
+void
+pngx_readInfo(struct pngx * const pngxP) {
+
+    png_read_info(pngxP->png_ptr, pngxP->info_ptr);
+}
+
+
+
+void
+pngx_writeInfo(struct pngx * const pngxP) {
+
+    png_write_info(pngxP->png_ptr, pngxP->info_ptr);
+}
+
+
+
+static void
+verifyFileIsPng(FILE *   const ifP,
+                size_t * const consumedByteCtP) {
+
+    unsigned char buffer[4];
+    size_t bytesRead;
+
+    bytesRead = fread(buffer, 1, sizeof(buffer), ifP);
+    if (bytesRead != sizeof(buffer))
+        pm_error("input file is empty or too short");
+
+    if (png_sig_cmp(buffer, (png_size_t) 0, (png_size_t) sizeof(buffer)) != 0)
+        pm_error("input file is not a PNG file "
+                 "(does not have the PNG signature in its first 4 bytes)");
+    else
+        *consumedByteCtP = bytesRead;
+}
+
+
+
+void
+pngx_readStart(struct pngx * const pngxP,
+               FILE *        const ifP) {
+
+    size_t sigByteCt;
+            
+    verifyFileIsPng(ifP, &sigByteCt);
+
+    /* Declare that we already read the signature bytes */
+    pngx_setSigBytes(pngxP, (unsigned int)sigByteCt);
+
+    png_init_io(pngxP->png_ptr, ifP);
+
+    pngx_readInfo(pngxP);
+
+    if (pngx_bitDepth(pngxP) < 8)
+        pngx_setPacking(pngxP);
+}
+
+
+
+void
+pngx_readRow(struct pngx * const pngxP,
+             png_byte *    const rowBuf,
+             png_byte *    const displayRow) {
+
+    png_read_row(pngxP->png_ptr, rowBuf, displayRow);
+}
+
+
+
+void
+pngx_readImage(struct pngx * const pngxP,
+               png_byte **   const image) {
+
+    png_read_image(pngxP->png_ptr, image);
+}
+
+
+
+void
+pngx_writeRow(struct pngx *    const pngxP,
+              const png_byte * const line) {
+
+    png_write_row(pngxP->png_ptr, (png_byte *)line);
+}
+
+
+
+void
+pngx_readEnd(struct pngx * const pngxP) {
+
+    /* Note that some of info_ptr is not defined until png_read_end() 
+       completes.  That's because it comes from chunks that are at the
+       end of the stream.  In particular, text and time chunks may
+       be at the end.  Furthermore, they may be in both places, in
+       which case info_ptr contains different information before and
+       after png_read_end().
+    */
+    png_read_end(pngxP->png_ptr, pngxP->info_ptr);
+}
+
+
+
+void
+pngx_writeEnd(struct pngx * const pngxP) {
+
+    png_write_end(pngxP->png_ptr, pngxP->info_ptr);
+}
+
+
+
diff --git a/converter/other/pngx.h b/converter/other/pngx.h
new file mode 100644
index 00000000..81e0dc55
--- /dev/null
+++ b/converter/other/pngx.h
@@ -0,0 +1,274 @@
+#ifndef PNGX_H_INCLUDED
+#define PNGX_H_INCLUDED
+
+#include <png.h>
+#include "pm_c_util.h"
+
+/* pngx is designed to be an extension of the PNG library to make using
+   the PNG library easier and cleaner.
+*/
+
+struct pngx_chroma {
+    float wx;
+    float wy;
+    float rx;
+    float ry;
+    float gx;
+    float gy;
+    float bx;
+    float by;
+};
+
+struct pngx_phys {
+    int x;
+    int y;
+    int unit;
+};
+
+struct pngx_text {
+    png_text *   line;
+    unsigned int size;
+};
+
+struct pngx_plte {
+    png_color *  palette;
+    unsigned int size;
+};
+
+struct pngx_trns {
+    png_byte *    trans;
+    unsigned int  numTrans;
+    png_color_16  transColor;
+};
+
+typedef enum {PNGX_READ, PNGX_WRITE} pngx_rw;
+
+struct pngx {
+    png_structp  png_ptr;
+    png_infop    info_ptr;
+    pngx_rw      rw;
+    png_uint_16  maxval;
+    unsigned int numPassesRequired;
+        /* The number of times we have write the complete image to the
+           compressor.  This is more than one when the compressor is set
+           up to do an interlaced format.
+        */
+};
+
+void
+pngx_create(struct pngx ** const pngxPP,
+            pngx_rw        const rw,
+            jmp_buf *      const jmpbufP);
+
+void
+pngx_destroy(struct pngx * const pngxP);
+
+bool
+pngx_chunkIsPresent(struct pngx * const pngxP,
+                    uint32_t      const chunkType);
+
+unsigned int
+pngx_bitDepth(struct pngx * const pngxP);
+
+png_color_16
+pngx_bkgd(struct pngx *  const pngxP);
+
+png_byte
+pngx_colorType(struct pngx * const pngxP);
+
+png_byte
+pngx_filterType(struct pngx * const pngxP);
+
+double
+pngx_gama(struct pngx * const pngxP);
+
+uint32_t
+pngx_imageHeight(struct pngx * const pngxP);
+
+uint32_t
+pngx_imageWidth(struct pngx * const pngxP);
+
+png_byte
+pngx_interlaceType(struct pngx * const pngxP);
+
+struct pngx_plte
+pngx_plte(struct pngx * const pngxP);
+
+png_color_8
+pngx_sbit(struct pngx * const pngxP);
+
+struct pngx_text
+pngx_text(struct pngx * const pngxP);
+
+png_time
+pngx_time(struct pngx * const pngxP);
+
+struct pngx_trns
+pngx_trns(struct pngx * const pngxP);
+
+uint32_t
+pngx_xPixelsPerMeter(struct pngx * const pngxP);
+
+uint32_t
+pngx_yPixelsPerMeter(struct pngx * const pngxP);
+
+float
+pngx_pixelAspectRatio(struct pngx * const pngxP);
+
+bool
+pngx_pixelAspectRatioIsKnown(struct pngx * const pngxP);
+
+void
+pngx_removeChunk(struct pngx * const pngxP,
+                 uint32_t      const chunkType);
+
+void
+pngx_setBkgdPalette(struct pngx * const pngxP,
+                    unsigned int  const backgroundIndex);
+
+void
+pngx_setBkgdRgb(struct pngx * const pngxP,
+                png_color_16  const backgroundArg);
+
+void
+pngx_setChrm(struct pngx *      const pngxP,
+             struct pngx_chroma const chroma);
+
+typedef enum {
+    PNGX_PERCEPTUAL,
+    PNGX_RELATIVE_COLORIMETRIC,
+    PNGX_SATURATION,
+    PNGX_ABSOLUTE_COLORIMETRIC
+} pngx_srgbIntent;
+
+const char *
+pngx_srgbIntentDesc(pngx_srgbIntent const srgbIntent);
+
+void
+pngx_setSrgb(struct pngx *   const pngxP,
+             pngx_srgbIntent const srgbIntent);
+
+void
+pngx_setCompressionSize(struct pngx * const pngxP,
+                        unsigned int  const bufferSize);
+
+void
+pngx_setFilter(struct pngx * const pngxP,
+               int           const filterSet);
+
+void
+pngx_setGama(struct pngx * const pngxP,
+             float         const fileGamma);
+
+void
+pngx_setGamma(struct pngx * const pngxP,
+              float         const displayGamma,
+              float         const imageGamma);
+
+void
+pngx_setHist(struct pngx * const pngxP,
+             png_uint_16 * const histogram);
+
+void
+pngx_setIhdr(struct pngx * const pngxP,
+             unsigned int  const width,
+             unsigned int  const height,
+             unsigned int  const bitDepth,
+             int           const colorType,
+             int           const interlaceMethod,
+             int           const compressionMethod,
+             int           const filterMethod);
+
+void
+pngx_setInterlaceHandling(struct pngx * const pngxP);
+
+void
+pngx_setInvalid(struct pngx * const pngxP);
+
+void
+pngx_setPacking(struct pngx * const pngxP);
+
+void
+pngx_setPhys(struct pngx *    const pngxP,
+             struct pngx_phys const phys);
+
+void
+pngx_setPlte(struct pngx * const pngxP,
+             png_color *   const palette,
+             unsigned int  const paletteSize);
+
+void
+pngx_setSbit(struct pngx * const pngxP,
+             png_color_8   const sbit);
+
+void
+pngx_setShift(struct pngx * const pngxP,
+              png_color_8   const sigBitArg);
+
+void
+pngx_setSigBytes(struct pngx * const pngxP,
+                 unsigned int  const sigByteCt);
+
+void
+pngx_setTextKey(png_text *   const textP,
+                const char * const key);
+
+void
+pngx_setTextLang(png_text *   const textP,
+                 const char * const language);
+
+void
+pngx_setTextLangKey(png_text *   const textP,
+                    const char * const key);
+
+void
+pngx_termText(png_text * const textP);
+
+void
+pngx_setText(struct pngx * const pngxP,
+             png_textp     const textP,
+             unsigned int  const count);
+
+void
+pngx_setTime(struct pngx * const pngxP,
+             time_t        const timeArg);
+
+void
+pngx_setTrnsPalette(struct pngx *    const pngxP,
+                    const png_byte * const transPalette,
+                    unsigned int     const paletteSize);
+
+void
+pngx_setTrnsValue(struct pngx * const pngxP,
+                  png_color_16  const transColorArg);
+
+void
+pngx_readInfo(struct pngx * const pngxP);
+
+void
+pngx_writeInfo(struct pngx * const pngxP);
+
+void
+pngx_readStart(struct pngx * const pngxP,
+               FILE *        const ifP);
+
+void
+pngx_readRow(struct pngx * const pngxP,
+             png_byte *    const rowBuf,
+             png_byte *    const displayRow);
+
+void
+pngx_readImage(struct pngx * const pngxP,
+               png_byte **   const image);
+
+void
+pngx_writeRow(struct pngx *    const pngxP,
+              const png_byte * const line);
+
+void
+pngx_readEnd(struct pngx * const pngxP);
+
+void
+pngx_writeEnd(struct pngx * const pngxP);
+
+#endif
diff --git a/converter/other/pnmtojpeg.c b/converter/other/pnmtojpeg.c
index b33b36b3..7e7272a0 100644
--- a/converter/other/pnmtojpeg.c
+++ b/converter/other/pnmtojpeg.c
@@ -271,7 +271,7 @@ parseCommandLine(const int argc, char ** argv,
     cmdlineP->comment = NULL;
     cmdlineP->exif_filespec = NULL;
 
-    /* Make private copy of arguments for optParseOptions to corrupt */
+    /* Make private copy of arguments for pm_optParseOptions to corrupt */
     argc_parse = argc;
     for (i=0; i < argc+1; i++) argv_parse[i] = argv[i];
 
@@ -279,7 +279,7 @@ parseCommandLine(const 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 */
 
-    optParseOptions3(&argc_parse, argv_parse, opt, sizeof(opt), 0);
+    pm_optParseOptions3(&argc_parse, argv_parse, opt, sizeof(opt), 0);
 
     if (!qualitySpec)
         cmdlineP->quality = -1;  /* unspecified */
@@ -898,7 +898,7 @@ write_exif_header(struct jpeg_compress_struct * const cinfoP,
         pm_error("Invalid length %u at start of exif file", length);
     else {
         unsigned char * exif_data;
-        int rc;
+        size_t rc;
         size_t const data_length = length - 2;  
             /* Subtract 2 byte length field*/
 
@@ -906,14 +906,15 @@ write_exif_header(struct jpeg_compress_struct * const cinfoP,
 
         exif_data = malloc(data_length);
         if (exif_data == NULL)
-            pm_error("Unable to allocate %d bytes for exif header buffer",
-                     data_length);
+            pm_error("Unable to allocate %u bytes for exif header buffer",
+                     (unsigned)data_length);
 
         rc = fread(exif_data, 1, data_length, exif_file);
 
         if (rc != data_length)
             pm_error("Premature end of file on exif header file.  Should be "
-                     "%d bytes of data, read only %d", data_length, rc);
+                     "%u bytes of data, read only %u",
+                     (unsigned)data_length, (unsigned)rc);
 
         jpeg_write_marker(cinfoP, JPEG_APP0+1, 
                           (const JOCTET *) exif_data, data_length);
diff --git a/converter/other/pnmtopalm/Makefile b/converter/other/pnmtopalm/Makefile
index 7f99f95a..edc7da64 100644
--- a/converter/other/pnmtopalm/Makefile
+++ b/converter/other/pnmtopalm/Makefile
@@ -8,8 +8,10 @@ VPATH=.:$(SRCDIR)/$(SUBDIR)
 include $(BUILDDIR)/config.mk
 
 BINARIES = palmtopnm pnmtopalm
+PORTBINARIES = $(BINARIES) gen_palm_colormap
 SCRIPTS =
-OBJECTS = $(BINARIES:%=%.o) palmcolormap.o
+ADDL_OBJECTS = palmcolormap.o
+OBJECTS = $(BINARIES:%=%.o) $(ADDL_OBJECTS) gen_palm_colormap.o
 MERGE_OBJECTS = $(BINARIES:%=%.o2) palmcolormap.o
 MERGEBINARIES = $(BINARIES)
 DATAFILES = palmcolor8.map palmgray1.map palmgray2.map palmgray4.map
@@ -18,17 +20,7 @@ all: $(BINARIES)
 
 include $(SRCDIR)/common.mk
 
-LIBOPTS = $(shell $(LIBOPT) $(NETPBMLIB))
-
-$(BINARIES): %: %.o palmcolormap.o $(NETPBMLIB) $(LIBOPT)
-	$(LD) -o $@ $< palmcolormap.o $(LIBOPTS) \
-	  $(MATHLIB) $(LDFLAGS) $(LDLIBS) $(RPATH) $(LADD)
-
-gen_palm_colormap : % : %.c palmcolormap.o
-	$(CC) -I importinc $(CPPFLAGS) $(CFLAGS) -o $@ \
-	  $< palmcolormap.o \
-	  $(LIBOPTS) $(MATHLIB) $(LDFLAGS) $(LDLIBS) $(LADD)
-
+$(BINARIES): $(ADDL_OBJECTS)
 
 clean: cleanspecial
 .PHONY: cleanspecial
diff --git a/converter/other/pnmtopalm/gen_palm_colormap.c b/converter/other/pnmtopalm/gen_palm_colormap.c
index c7172c6b..0f3f8a5f 100644
--- a/converter/other/pnmtopalm/gen_palm_colormap.c
+++ b/converter/other/pnmtopalm/gen_palm_colormap.c
@@ -3,8 +3,8 @@
  * Based on an earlier version by Bill Janssen  <bill@janssen.org>
  */
 
-#include "ppm.h"
-#include "pm_c_util.h"
+#include "netpbm/ppm.h"
+#include "netpbm/pm_c_util.h"
 
 #include "palm.h"
 
diff --git a/converter/other/pnmtopalm/palm.h b/converter/other/pnmtopalm/palm.h
index 170c8cec..718a66cf 100644
--- a/converter/other/pnmtopalm/palm.h
+++ b/converter/other/pnmtopalm/palm.h
@@ -44,13 +44,9 @@ typedef struct {
 
 typedef Colormap_s * Colormap;
 
-int
-palmcolor_compare_indices(const void * const p1,
-                          const void * const p2);
+qsort_comparison_fn palmcolor_compare_indices;
 
-int
-palmcolor_compare_colors(const void * const p1,
-                         const void * const p2);
+qsort_comparison_fn palmcolor_compare_colors;
 
 Colormap
 palmcolor_build_custom_8bit_colormap(unsigned int const rows,
diff --git a/converter/other/pnmtopalm/palmcolormap.c b/converter/other/pnmtopalm/palmcolormap.c
index a1a1cec1..0f47558c 100644
--- a/converter/other/pnmtopalm/palmcolormap.c
+++ b/converter/other/pnmtopalm/palmcolormap.c
@@ -10,7 +10,9 @@
 int
 palmcolor_compare_indices(const void * const p1,
                           const void * const p2) {
-
+/*----------------------------------------------------------------------------
+   This is a 'qsort' collation function.
+-----------------------------------------------------------------------------*/
     if ((*((Color) p1) & 0xFF000000) < (*((Color) p2) & 0xFF000000))
         return -1;
     else if ((*((Color) p1) & 0xFF000000) > (*((Color) p2) & 0xFF000000))
@@ -24,7 +26,9 @@ palmcolor_compare_indices(const void * const p1,
 int
 palmcolor_compare_colors(const void * const p1,
                          const void * const p2) {
-
+/*----------------------------------------------------------------------------
+   This is a 'qsort' collation function.
+-----------------------------------------------------------------------------*/
     unsigned long const val1 = *((const unsigned long *) p1) & 0xFFFFFF;
     unsigned long const val2 = *((const unsigned long *) p2) & 0xFFFFFF;
 
diff --git a/converter/other/pnmtopalm/palmtopnm.c b/converter/other/pnmtopalm/palmtopnm.c
index e686571b..0f76207d 100644
--- a/converter/other/pnmtopalm/palmtopnm.c
+++ b/converter/other/pnmtopalm/palmtopnm.c
@@ -92,7 +92,7 @@ parseCommandLine(int argc, char ** argv,
    was passed to us as the argv array.
 -----------------------------------------------------------------------------*/
     optEntry *option_def = malloc( 100*sizeof( optEntry ) );
-        /* Instructions to optParseOptions3 on how to parse our options.
+        /* Instructions to pm_optParseOptions3 on how to parse our options.
          */
     optStruct3 opt;
 
@@ -114,7 +114,7 @@ parseCommandLine(int argc, char ** argv,
     opt.short_allowed = FALSE;  /* We have no short (old-fashioned) options */
     opt.allowNegNum = FALSE;  /* We may have parms that are negative numbers */
 
-    optParseOptions3(&argc, argv, opt, sizeof(opt), 0);
+    pm_optParseOptions3(&argc, argv, opt, sizeof(opt), 0);
         /* Uses and sets argc, argv, and some of *cmdlineP and others. */
 
 
diff --git a/converter/other/pnmtopalm/pnmtopalm.c b/converter/other/pnmtopalm/pnmtopalm.c
index 90737b78..a7d1fd46 100644
--- a/converter/other/pnmtopalm/pnmtopalm.c
+++ b/converter/other/pnmtopalm/pnmtopalm.c
@@ -13,7 +13,13 @@
  *
  * See LICENSE file for licensing information.
  *
- *  
+ * References for the Palm Bitmap format:
+ *
+ * https://web.archive.org/web/20030621112139/http://www.palmos.com:80/dev/support/docs/
+ * https://web.archive.org/web/20030413080018/http://www.palmos.com:80/dev/support/docs/palmos/ReferenceTOC.html
+ *
+ * http://www.trantor.de/kawt/doc/palmimages.html
+ * (above retrieved August 2017)
  */
 
 #include <string.h>
@@ -26,6 +32,7 @@
 #include "palm.h"
 #include "shhopt.h"
 #include "mallocvar.h"
+#include "runlength.h"
 
 enum compressionType {COMP_NONE, COMP_SCANLINE, COMP_RLE, COMP_PACKBITS};
 
@@ -33,8 +40,8 @@ struct cmdline_info {
     /* All the information the user supplied in the command line,
        in a form easy for the program to use.
     */
-    const char *inputFilespec;  /* Filespecs of input files */
-    char *transparent;          /* -transparent value.  Null if unspec */
+    const char * inputFilespec;  /* Filespecs of input files */
+    const char * transparent;    /* -transparent value.  Null if unspec */
     unsigned int depth;         /* -depth value.  0 if unspec */
     unsigned int maxdepth;      /* -maxdepth value.  0 if unspec */
     enum compressionType compression;
@@ -90,7 +97,7 @@ parseCommandLine(int argc, char ** argv, struct cmdline_info *cmdlineP) {
     opt.short_allowed = FALSE; /* We have some short (old-fashioned) options */
     opt.allowNegNum = FALSE;  /* We have no parms that are negative numbers */
 
-    optParseOptions3(&argc, argv, opt, sizeof(opt), 0);
+    pm_optParseOptions3(&argc, argv, opt, sizeof(opt), 0);
         /* Uses and sets argc, argv, and some of *cmdline_p and others. */
 
     if (depthSpec) {
@@ -289,7 +296,7 @@ formatName(int const format) {
         
 
 static void
-findTransparentColor(char *         const colorSpec, 
+findTransparentColor(const char *   const colorSpec, 
                      pixval         const newMaxval,
                      bool           const directColor, 
                      pixval         const maxval, 
@@ -497,7 +504,7 @@ writeDummy() {
    Write a dummy Palm Bitmap header.  This is a 16 byte header, of
    type version 1 and with (only) pixelSize set to 0xFF.
 
-   An old viewer will see this as invalid due to the pixelSize, and stop
+   An old viewer will see this as invalid because of the pixelSize, and stop
    reading the stream.  A new viewer will recognize this for what it is
    (a dummy header designed to stop old viewers from reading further in
    the stream) and continue reading the stream.  Presumably, what follows
@@ -836,101 +843,26 @@ rleCompressAndBufferRow(const unsigned char * const rowdata,
 
 
 static void
-computeNextPackbitsRun(const unsigned char * const rowdata,
-                       unsigned int          const rowbytes,
-                       unsigned int          const startPos,
-                       unsigned int *        const nextPosP,
-                       unsigned char *       const output,
-                       int *                 const countP) {
-
-    unsigned int pos;
-    int count;
-    
-    pos = startPos;
-    count = 0;
-    
-    if (rowdata[pos] == rowdata[pos + 1]) {
-        ++pos;
-        --count;
-        while ((count > -127) && (pos < (rowbytes - 1)) &&
-               (rowdata[pos] == rowdata[pos + 1])) {
-            ++pos;
-            --count;
-        }
-        ++pos;  /* push pos past end of this run */
-    } else {
-        output[count] = rowdata[pos];
-        ++pos;
-        while ((count < 127) && (pos < (rowbytes - 1)) && 
-               (rowdata[pos] != rowdata[pos + 1])) {
-            ++count;
-            output[count] = rowdata[pos];
-            ++pos;
-        }
-        /* trailing literal */
-        if ((count < 127) && (pos == (rowbytes - 1)) &&
-            (rowdata[pos - 1] != rowdata[pos])) {
-            ++count;
-            output[count] = rowdata[pos];
-            ++pos;
-        }
-    }
-    *nextPosP = pos;
-    *countP = count;
-}
-
-
-
-static void
-addPackbitsRunToBuffer(const unsigned char * const rowdata,
-                       unsigned int          const rowbytes,
-                       unsigned int          const pos,
-                       unsigned char *       const output,
-                       int                   const count,
-                       struct seqBuffer *    const rasterBufferP) {
-
-    addByteToBuffer(rasterBufferP, (unsigned char)(signed char)count);
-    if (count < 0) {
-        addByteToBuffer(rasterBufferP, rowdata[pos - 1]);
-    } else {
-        unsigned int j;
-        for (j = 0; j <= count; j++)
-            addByteToBuffer(rasterBufferP, output[j]);
-    }
-    
-    if (pos == (rowbytes - 1) && (rowdata[pos - 1] != rowdata[pos])) {
-        /* orphaned byte, treat as literal */
-        addByteToBuffer(rasterBufferP, 0);
-        addByteToBuffer(rasterBufferP, rowdata[pos]);
-    }
-}
-
-
-
-static void
 packbitsCompressAndBufferRow(const unsigned char * const rowdata,
                              unsigned int          const rowbytes,
                              struct seqBuffer *    const rasterBufferP) {
 /*----------------------------------------------------------------------------
-   Take the raw Palm Bitmap row 'rowdata', which is 'rowbytess' bytes, and
+   Take the raw Palm Bitmap row 'rowdata', which is 'rowbytes' bytes, and
    add the packbits-compressed representation of it to the buffer 
    with handle 'rasterBufferP'.
 -----------------------------------------------------------------------------*/
-    unsigned int position;
-        /* byte position within the row */
-
-    position = 0;  /* Start at beginning of row */
+    unsigned char * compressedData;
+    size_t          compressedDataCt;
+    unsigned int    byteCt;
 
-    while (position < rowbytes - 1) {
-        unsigned char output[128];
-        int count;
+    pm_rlenc_allocoutbuf(&compressedData, rowbytes, PM_RLE_PACKBITS);
+    pm_rlenc_compressbyte(rowdata, compressedData, PM_RLE_PACKBITS,
+                          rowbytes, &compressedDataCt);
 
-        computeNextPackbitsRun(rowdata, rowbytes, position, 
-                               &position, output, &count);
+    for (byteCt = 0; byteCt < compressedDataCt; ++byteCt)
+        addByteToBuffer(rasterBufferP, compressedData[byteCt]);
 
-        addPackbitsRunToBuffer(rowdata, rowbytes, position, output, count,
-                               rasterBufferP);
-    }
+    free(compressedData);
 }
 
 
@@ -1027,7 +959,13 @@ bufferRaster(xel **               const xels,
     createBuffer(rasterBufferPP);
     
     MALLOCARRAY_NOFAIL(rowdata, rowbytes);
-    MALLOCARRAY_NOFAIL(lastrow, rowbytes);
+    if (compression == COMP_SCANLINE)
+        MALLOCARRAY_NOFAIL(lastrow, rowbytes);
+    else
+        lastrow = NULL;
+
+    /* clear pad bytes to suppress valgrind error */
+    rowdata[rowbytes - 1] = rowdata[rowbytes - 2] = 0x00;
 
     /* And write out the data. */
     for (row = 0; row < rows; ++row) {
@@ -1039,8 +977,9 @@ bufferRaster(xel **               const xels,
         if (compression == COMP_SCANLINE)
             memcpy(lastrow, rowdata, rowbytes);
     }
-    free(lastrow);
     free(rowdata);
+    if (compression == COMP_SCANLINE)
+        free(lastrow);
 }
 
 
diff --git a/converter/other/pnmtopclxl.c b/converter/other/pnmtopclxl.c
index e16afb14..8cabb614 100644
--- a/converter/other/pnmtopclxl.c
+++ b/converter/other/pnmtopclxl.c
@@ -34,6 +34,7 @@
 #include "shhopt.h"
 #include "mallocvar.h"
 #include "nstring.h"
+#include "runlength.h"
 
 #include "pclxl.h"
 
@@ -54,7 +55,7 @@ struct cmdlineInfo {
        in a form easy for the program to use.
     */
     InputSource * sourceP;
-    int dpi;
+    unsigned int dpi;
     enum MediaSize format;
     unsigned int feederSpec;
     int feeder;
@@ -71,6 +72,7 @@ struct cmdlineInfo {
     unsigned int verbose;
     const char * jobsetup;  /* -jobsetup option value.  NULL if none */
     unsigned int rendergray;
+    unsigned int embedded;
 };
 
 
@@ -89,7 +91,7 @@ parseCommandLine(int argc, char ** argv,
    was passed to us as the argv array.  We also trash *argv.
 -----------------------------------------------------------------------------*/
     optEntry *option_def = malloc( 100*sizeof( optEntry ) );
-        /* Instructions to optParseOptions3 on how to parse our options.
+        /* Instructions to pm_optParseOptions3 on how to parse our options.
          */
     optStruct3 opt;
 
@@ -126,12 +128,14 @@ parseCommandLine(int argc, char ** argv,
             &jobsetupSpec,      0);
     OPTENT3(0, "rendergray", OPT_FLAG,    NULL,
             &cmdlineP->rendergray, 0 );
+    OPTENT3(0, "embedded", OPT_FLAG,    NULL,
+            &cmdlineP->embedded, 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 */
 
-    optParseOptions3( &argc, argv, opt, sizeof(opt), 0);
+    pm_optParseOptions3( &argc, argv, opt, sizeof(opt), 0);
         /* Uses and sets argc, argv, and some of *cmdlineP and others. */
 
     if (!dpiSpec)
@@ -174,6 +178,20 @@ parseCommandLine(int argc, char ** argv,
     if (!jobsetupSpec)
         cmdlineP->jobsetup = NULL;
 
+    if (cmdlineP->embedded) {
+        if (xoffsSpec || yoffsSpec || formatSpec || cmdlineP->duplexSpec
+            || cmdlineP->copiesSpec || dpiSpec || cmdlineP->center
+            || cmdlineP->feederSpec || cmdlineP->outtraySpec
+            || jobsetupSpec || cmdlineP->rendergray)
+            pm_error("With -embedded, you may not specify "
+                     "-xoffs, -yoffs, -format, -duplex, copies, -dpi, "
+                     "-center, -feeder, -outtray, -jobsetup, or -rendergray");
+
+        if (argc-1 > 1)
+            pm_message("With -embedded, you may not specify more than one "
+                       "input image.  You specified %u", argc-1);
+    }
+
     if (argc-1 < 1) {
         MALLOCVAR(cmdlineP->sourceP);
         cmdlineP->sourceP->name = "-";
@@ -196,154 +214,248 @@ parseCommandLine(int argc, char ** argv,
 
 
 
-#define XY_RLE_FBUFSIZE (1024)
-typedef struct XY_rle {
-    int error;
-    unsigned char buf[128];
-    int bpos;
-    int state;  
-    unsigned char *fbuf;
-    int fbpos;
-    int fbufsize;
-    int fd;
-} XY_rle;
-
+static void
+freeSource(InputSource * const firstSourceP) {
+    
+    InputSource * sourceP;
 
-static void 
-XY_RLEreset(XY_rle *rle) 
-{   
-    rle->state = eSTART;
-    rle->bpos = 0;
-    rle->fbpos=0;
-    rle->error=0;
-}
-static XY_rle * 
-XY_RLEnew(int size) {
-    XY_rle *rle;
-
-    MALLOCVAR(rle);
-    if(rle==NULL)
-        return rle;
-    if(size<1024)
-        size=1024;
-    rle->fbuf=malloc(size);
-    rle->fbufsize=size;
-    if(!rle->fbuf) {
-        free(rle);
-        return NULL;
+    sourceP = firstSourceP;
+    while(sourceP) {
+        InputSource * const nextP = sourceP->next;
+        free(sourceP);
+        sourceP = nextP;
     }
-    return rle;
 }
+
+
+
 static void
-XY_RLEdelete(XY_rle *rle) {
-    free(rle->fbuf);
-    free(rle);
+freeCmdline(struct cmdlineInfo const cmdline) {
+
+    freeSource(cmdline.sourceP);
 }
 
-static int 
-out(XY_rle *rle,int count) {
-    if(rle->state==eRLE) {
-        rle->fbuf[rle->fbpos++]=-count+1;
-        rle->fbuf[rle->fbpos++]=rle->buf[0];
-    } else if(rle->bpos>0) {
-        rle->fbuf[rle->fbpos++]=count-1;
-        memcpy(rle->fbuf+rle->fbpos,rle->buf,count);
-        rle->fbpos+=count;
+
+
+static int
+XY_Write(int          const fd,
+         const void * const buf,
+         int          const cnt) {
+
+    int len;
+    bool error;
+
+    for (len =0, error = false; len < cnt && !error;) {
+        ssize_t const rc = write(fd, (char*)buf + len , cnt - len);
+        if (rc <= 0)
+            error = true;
+        else
+            len += rc;
     }
-    if(rle->fbpos+129>rle->fbufsize) {
-        if (rle->fbufsize > INT_MAX/1.2)
-            pm_error("Arithmetic overflow during attempt to expand RLE "
-                     "output buffer beyond %u", rle->fbufsize);
-        rle->fbufsize*=1.2; 
-        rle->fbuf=realloc(rle->fbuf,rle->fbufsize);
-        if(rle->fbuf==NULL) {
-            pm_error("Out of memory while attempting to expand RLE "
-                     "output buffer beyond %u", rle->fbufsize);
-            rle->error=-1;
-            rle->fbpos=0;
-            return -1;
-        }
+    return error ? -1 : len;
+}
+
+
+
+#define XY_Puts(fd, str)  XY_Write(fd, str, strlen(str))
+
+
+
+typedef struct pclGenerator {
+    enum ColorDepth colorDepth;
+    enum Colorspace colorSpace;
+    int width,height;
+    unsigned int linelen;       /* bytes per line */
+    unsigned int paddedLinelen; /* bytes per line + padding */
+    unsigned char * data;
+    unsigned int cursor;
+    void (*getnextrow)(struct pclGenerator *, struct pam *);
+} pclGenerator;
+
+
+
+static void
+pnmToPcllinePackbits(pclGenerator * const pclGeneratorP,
+                     struct pam *   const pamP) {
+
+    tuple * tuplerow;
+    unsigned char accum;
+    unsigned char bitmask;
+    unsigned int col, padCt;
+    unsigned int const padsize =
+        pclGeneratorP->paddedLinelen - pclGeneratorP->linelen;
+        
+    tuplerow = pnm_allocpamrow(pamP);
+
+    pnm_readpamrow(pamP, tuplerow);
+
+    bitmask = 0x80; accum = 0x00;
+    for (col = 0; col < pamP->width; ++col) {
+        if (tuplerow[col][0] == PAM_PBM_WHITE)
+            accum |= bitmask;
+        bitmask >>= 1;
+        if (bitmask == 0) {
+            pclGeneratorP->data[pclGeneratorP->cursor++] = accum;
+            bitmask = 0x80; accum = 0x0;
+        } 
     }
-    rle->bpos=0;
-    rle->state=eSTART;
-    return 0;
+    if (bitmask != 0x80)
+        pclGeneratorP->data[pclGeneratorP->cursor++] = accum;
+
+    for (padCt = 0; padCt < padsize; ++padCt)
+        pclGeneratorP->data[pclGeneratorP->cursor++] = 0;
+
+    pnm_freepamrow(tuplerow);
 }
-static int
-XY_RLEfinish (XY_rle *rle) {
-    out(rle,rle->bpos);
-    if(rle->error<0) 
-        return rle->error;
-    else
-        return rle->fbpos;
+
+
+
+static unsigned int
+pclPaddedLinelen(unsigned int const linelen) {
+
+    if (UINT_MAX - 3 < linelen)
+        pm_error("Image too big to process");
+
+    return (((linelen + 3) / 4) * 4);
 }
-static  void
-rle_putbyte(XY_rle *rle,unsigned char u) 
-{
-    switch (rle->state) {
-        case eRLE:
-            if(u!=rle->buf[0]) {
-                out(rle,rle->bpos);
-            }   
-            break;
-        case eLIT:
-            if((u==rle->buf[rle->bpos-1])&&(u==rle->buf[rle->bpos-2])) {
-                out(rle,rle->bpos-2);
-                rle->buf[0]=u;
-                rle->bpos+=2;
-                rle->state=eRLE;
-            }   
-            break;
-        case eSTART:
-            if(rle->bpos==1) {
-                if(u==rle->buf[rle->bpos-1]) {
-                    rle->state=eRLE;
-                } else {
-                    rle->state=eLIT;
-                }   
-            }
-            break;
+
+
+
+static unsigned int
+pclDatabuffSize(unsigned int const paddedLinelen) {
+
+    if (UINT_MAX / 20 < paddedLinelen)
+        pm_error("Image too big to process");
+
+    return (paddedLinelen * 20);
+}
+
+
+
+static void
+createPclGeneratorPackbits(struct pam *    const pamP,
+                           pclGenerator ** const pclGeneratorPP) {
+
+    /* Samples are black or white and packed 8 to a byte */
+
+    pclGenerator * pclGeneratorP;
+
+    MALLOCVAR_NOFAIL(pclGeneratorP);
+
+    pclGeneratorP->colorDepth = e1Bit;
+    pclGeneratorP->colorSpace = eGray;
+    pclGeneratorP->linelen = (pamP->width+7)/8;
+    pclGeneratorP->paddedLinelen = pclPaddedLinelen(pclGeneratorP->linelen);
+    pclGeneratorP->height = pamP->height;
+    pclGeneratorP->width = (pamP->width);
+
+    pclGeneratorP->data =
+        malloc(pclDatabuffSize(pclGeneratorP->paddedLinelen));
     
+    if (pclGeneratorP->data == NULL)
+        pm_error("Unable to allocate row buffer.");
+
+    pclGeneratorP->getnextrow = pnmToPcllinePackbits;
+
+    *pclGeneratorPP = pclGeneratorP;
+}
+
+
+
+static void
+pnmToPcllineWholebytes(pclGenerator * const pclGeneratorP,
+                       struct pam *   const pamP) {
+
+    tuple * tuplerow;
+    unsigned int col, padCt;
+    unsigned int const padsize =
+        pclGeneratorP->paddedLinelen - pclGeneratorP->linelen;
+
+    tuplerow = pnm_allocpamrow(pamP);
+
+    pnm_readpamrow(pamP, tuplerow);
+
+    for (col = 0; col < pamP->width; ++col) {
+        unsigned int plane;
+        for (plane = 0; plane < pamP->depth; ++plane) {
+            pclGeneratorP->data[pclGeneratorP->cursor++] = 
+                pnm_scalesample(tuplerow[col][plane], pamP->maxval, 255);
+        }
     }
-    rle->buf[rle->bpos++]=u;
-    if(rle->bpos==128) {
-        out(rle,rle->bpos);
-    }
+
+    for(padCt=0; padCt < padsize; ++padCt)
+        pclGeneratorP->data[pclGeneratorP->cursor++] = 0;
+
+    pnm_freepamrow(tuplerow);
 }
 
 
 
 static void
-XY_RLEput(XY_rle *rle,const unsigned char buf[],int count) 
-{
-    int i;
-    for(i=0;i<count;i++) {
-        rle_putbyte(rle,buf[i]);
+createPclGeneratorWholebytes(struct pam *    const pamP,
+                             pclGenerator ** const pclGenPP) {
+    /* One sample per byte */
+
+    pclGenerator * pclGenP;
+
+    MALLOCVAR_NOFAIL(pclGenP);
+    
+    if (pamP->depth <  3)
+        pclGenP->colorSpace = eGray;
+    else
+        pclGenP->colorSpace = eRGB;
+
+    pclGenP->colorDepth = e8Bit;
+    pclGenP->height     = pamP->height;
+    pclGenP->width      = pamP->width;
+
+    if (UINT_MAX / pamP->width < pamP->depth)
+        pm_error("Image too big to process");
+    else {
+        pclGenP->linelen = pamP->width * pamP->depth;
+        pclGenP->paddedLinelen = pclPaddedLinelen(pclGenP->linelen);
+        pclGenP->data = malloc(pclDatabuffSize(pclGenP->paddedLinelen));
+        if (pclGenP->data == NULL)
+            pm_error("Unable to allocate row buffer.");
     }
     
+    pclGenP->getnextrow = pnmToPcllineWholebytes;
+
+    *pclGenPP = pclGenP;
 }
 
 
-static int
-XY_Write(int fd, const void *buf,int cnt) {
-        int len=0;
-        while(len<cnt) {
-                int n = write(fd,(char*)buf+len,cnt-len);
-                if(n<=0)
-                    pm_error("Failed to write %u bytes to fd %d", cnt - len, fd);
-                len+=n;
-        }
-        return len;
+
+static void
+destroyPclGenerator(pclGenerator * const pclGenP) {
+
+    free(pclGenP->data);
+
+    free(pclGenP);
+}
+
+
+
+static void 
+createPclGenerator(struct pam *        const pamP,
+                   pclGenerator **     const pclGeneratorPP,
+                   bool                const colorok) {
+
+    if (pamP->depth > 1 && !colorok)
+        pm_message("WARNING: generating a color print stream because the "
+                   "input image is PPM.  "
+                   "To generate a black and white print stream, run the input "
+                   "through Ppmtopgm.  To suppress this warning, use the "
+                   "-colorok option.");
+
+    if (pamP->depth == 1 && pamP->maxval == 1) 
+        createPclGeneratorPackbits(pamP, pclGeneratorPP);
+    else 
+        createPclGeneratorWholebytes(pamP, pclGeneratorPP);
 }
-#define XY_Puts(fd,str)  XY_Write(fd,str,strlen(str))
 
-typedef struct pclGenerator {
-    enum ColorDepth colorDepth;
-    enum Colorspace colorSpace;
-    int width,height;
-    int linelen; /* bytes per line */
-    unsigned char *data;
-    void (*getnextrow)(const struct pclGenerator *, struct pam *);
-} pclGenerator;
+
+
 
 struct tPrinter { 
     const char *name;
@@ -358,74 +470,85 @@ struct tPrinter {
 
 
 static int
-out_ubyte(int fd,unsigned char data) {
-    return XY_Write(fd,&data,1);
+out_ubyte(int           const fd,
+          unsigned char const data) {
+
+    return XY_Write(fd, &data, 1);
 }
-static  int 
-XL_Operator(int fd,enum Operator const data)  {
-    return out_ubyte(fd,data);
+
+
+
+static int 
+XL_Operator(int           const fd,
+            enum Operator const data)  {
+
+    return out_ubyte(fd, data);
 }
+
+
+
 static int
-out_uint16(int fd,unsigned short data ) {
+out_uint16(int            const fd,
+           unsigned short const data ) {
+
     unsigned char c[2];
-    c[0]=data&0xff; c[1]=data>>8;
-    return XY_Write(fd,c,2);
+
+    c[0] = data & 0xff;
+    c[1] = data >>8;
+
+    return XY_Write(fd, c , ARRAY_SIZE(c));
 }
+
+
+
 static int
 out_uint32(int fd,unsigned int data ) {
     unsigned char c[4];
     c[0] = data&0xff; c[1]=(data>>8)&0xff; c[2]=(data>>16)&0xff; c[3]=data>>24;
     return XY_Write(fd,c,4);
 }
+
+
+
 static int
-out_sint16(int fd,signed short sdata ) {
-    unsigned short data=(unsigned short)sdata;    
+out_sint16(int          const fd,
+           signed short const sdata ) {
+
+    unsigned short const data= (unsigned short)sdata;    
+
     unsigned char c[2];
-    c[0]=data&0xff; c[1]=data>>8;
-    return XY_Write(fd,c,2);
-}
-#if 0
-static int
-out_sint32(int fd,signed int sdata ) {
-    unsigned int data=(unsigned int)sdata;
-    unsigned char c[4];
-    c[0] = data&0xff; c[1]=(data>>8)&0xff; c[2]=(data>>16)&0xff; c[3]=data>>24;
-    return XY_Write(fd,c,4);
-}
-#endif
 
-static int
-xl_ubyte(int fd,unsigned char data) {
-    unsigned char const tag=0xc0;
-    XY_Write(fd,&tag,1);
-    return out_ubyte(fd,data);
-}
-static int
-xl_uint16(int fd,unsigned short data ) {
-    unsigned char const tag=0xc1;
-    XY_Write(fd,&tag,1);
-    return out_uint16(fd,data);
-}
-#if 0
-static int
-xl_uint32(int fd,unsigned int data ) {
-    unsigned char const c=0xc2;
-    XY_Write(fd,&c,1);
-    return out_uint32(fd,data);
+    c[0] = data & 0xff;
+    c[1] = data >> 8;
+
+    return XY_Write(fd, c, ARRAY_SIZE(c));
 }
+
+
+
 static int
-xl_sint16(int fd,signed short data ) {
-    unsigned char const c=0xc3;
-    XY_Write(fd,&c,1);
-    return out_sint16(fd,data);
+xl_ubyte(int           const fd,
+         unsigned char const data) {
+
+    unsigned char const tag = 0xc0;
+
+    XY_Write(fd, &tag, 1);
+
+    return out_ubyte(fd, data);
 }
+
+
+
 static int
-xl_sint32(int fd,signed int data ) {
-    unsigned char const c=0xc4;
-    XY_Write(fd,&c,1);
-    return out_sint32(fd,data);
+xl_uint16(int            const fd,
+          unsigned short const data) {
+
+    unsigned char const tag = 0xc1;
+
+    XY_Write(fd, &tag, 1);
+
+    return out_uint16(fd, data);
 }
-#endif
 
 
 
@@ -439,10 +562,10 @@ xl_ubyte_array(int                   const fd,
     
     head[0] = 0xc8;
     head[1] = 0xc1;
-    head[2] = len&0xff;
-    head[3] = (len>>8)&0xff;
+    head[2] = len & 0xff;
+    head[3] = (len >> 8) & 0xff;
 
-    XY_Write(fd, head, 4);
+    XY_Write(fd, head, ARRAY_SIZE(head));
 
     for (i = 0; i < len; ++i)
         out_ubyte(fd, data[i]);
@@ -452,123 +575,182 @@ xl_ubyte_array(int                   const fd,
 
 
 
-#if 0
-static int
-xl_uint16_array(int fd,unsigned short *data,int len) {
-    int i;
-    unsigned char head[4];
-    head[0]=0xc9;head[1]=0xc1;head[2]=len&0xff;head[3]=(len>>8)&0xff;
-    XY_Write(fd,head,4);
-    for(i=0;i<len;i++) {
-        out_uint16(fd,data[i]);
-    }
-    return 0;
-}
-static int
-xl_uint32_array(int fd,unsigned int *data,int len) {
-    int i;
-    unsigned char head[4];
-    head[0]=0xca;head[1]=0xc1;head[2]=len&0xff;head[3]=(len>>8)&0xff;
-    XY_Write(fd,head,4);
-    for(i=0;i<len;i++) {
-        out_uint32(fd,data[i]);
-    }
-    return 0;
-}
 static int
-xl_sint16_array(int fd,signed short *data,int len) {
-    int i;
-    unsigned char head[4];
-    head[0]=0xcb;head[1]=0xc1;head[2]=len&0xff;head[3]=(len>>8)&0xff;
-    XY_Write(fd,head,4);
-    for(i=0;i<len;i++) {
-        out_sint16(fd,data[i]);
-    }
-    return 0;
-}
-static int
-xl_sint32_array(int fd,signed int *data,int len) {
-    int i;
-    unsigned char head[4];
-    head[0]=0xcc;head[1]=0xc1;head[2]=len&0xff;head[3]=(len>>8)&0xff;
-    XY_Write(fd,head,4);
-    for(i=0;i<len;i++) {
-        out_sint32(fd,data[i]);
-    }
-    return 0;
-}
+xl_uint16_xy(int            const fd,
+             unsigned short const xdata,
+             unsigned short const ydata ) {
 
-static int
-xl_ubyte_xy(int fd,unsigned char xdata,unsigned char ydata) {
-    unsigned char const tag=0xd0;
-    XY_Write(fd,&data,1);
-    out_ubyte(fd,ydata);
-    return out_ubyte(fd,xdata);
+    unsigned char const tag = 0xd1;
+
+    XY_Write(fd, &tag, 1);
+    out_uint16(fd, xdata);
+
+    return out_uint16(fd, ydata);
 }
-#endif
+
+
+
 static int
-xl_uint16_xy(int fd,unsigned short xdata,unsigned short ydata ) {
-    unsigned char const tag=0xd1;
-    XY_Write(fd,&tag,1);
-    out_uint16(fd,xdata);
-    return out_uint16(fd,ydata);
+xl_sint16_xy(int          const fd,
+             signed short const xdata,
+             signed short const ydata ) {
+
+    unsigned char const tag = 0xd3;
+
+    XY_Write(fd, &tag, 1);
+
+    out_sint16(fd, xdata);
+
+    return out_sint16(fd, ydata);
 }
-#if 0
+
+
+
 static int
-xl_uint32_xy(int fd,unsigned int xdata,unsigned int ydata ) {
-    unsigned char const tag=0xd2;
-    XY_Write(fd,&tag,1);
-    out_uint32(fd,xdata);
-    return out_uint32(fd,ydata);
+xl_attr_ubyte(int            const fd,
+              enum Attribute const data) {
+
+    unsigned char const tag = 0xf8;
+
+    XY_Write(fd, &tag, 1);
+
+    return out_ubyte(fd, data);
 }
-#endif
+
+
+
 static int
-xl_sint16_xy(int fd,signed short xdata,signed short ydata ) {
-    unsigned char const tag=0xd3;
-    XY_Write(fd,&tag,1);
-    out_sint16(fd,xdata);
-    return out_sint16(fd,ydata);
+xl_dataLength(int          const fd,
+              unsigned int const dataLength ) {
+
+    unsigned char const tag = 0xfa;
+
+    XY_Write(fd, &tag, 1);
+
+    return out_uint32(fd, dataLength);
 }
 
-#if 0
-static int
-xl_sint32_xy(int fd,signed int xdata,signed int ydata ) {
-    unsigned char const tag=0xd4;
-    XY_Write(fd,&tag,1);
-    out_sint32(fd,xdata);
-    return out_sint32(fd,ydata);
+
+
+static void
+openDataSource(int             const outFd,
+               enum DataOrg    const dataOrg,
+               enum DataSource const dataSource) {
+
+    xl_ubyte(outFd, dataOrg);    xl_attr_ubyte(outFd, aDataOrg);
+    xl_ubyte(outFd, dataSource); xl_attr_ubyte(outFd, aSourceType);
+    XL_Operator(outFd, oOpenDataSource);
 }
-#endif
 
-static int
-xl_attr_ubyte(int fd,enum Attribute const data) {
-    unsigned char const tag=0xf8;
-    XY_Write(fd,&tag,1);
-    return out_ubyte(fd,data);
+
+
+static void
+closeDataSource(int const outFd) {
+
+    XL_Operator(outFd, oCloseDataSource);
 }
-#if 0
-static int
-xl_attr_uint16(int fd,enum Attribute const data ) {
-    unsigned char const tag=0xf9;
-    XY_Write(fd,&tag,1);
-    return out_uint16(fd,data);
+
+
+
+static void
+convertAndWriteRleBlock(int                  const outFd,
+                        pclGenerator *       const pclGeneratorP,
+                        struct pam *         const pamP,
+                        int                  const firstLine,
+                        int                  const lineCt,
+                        unsigned char *      const outbuf) {
+
+    size_t rlelen;
+    unsigned int line;
+
+    pclGeneratorP->cursor = 0;
+    for (line = firstLine; line < firstLine + lineCt; ++line) {
+        pclGeneratorP->getnextrow(pclGeneratorP, pamP);
+    }
+
+    pm_rlenc_compressbyte(pclGeneratorP->data, outbuf, PM_RLE_PACKBITS,
+                          pclGeneratorP->paddedLinelen * lineCt, &rlelen);
+
+    xl_dataLength(outFd, rlelen); 
+    XY_Write(outFd, outbuf, rlelen);
 }
-#endif
-static int
-xl_dataLength(int fd,unsigned int dataLength ) {
-    unsigned char const tag=0xfa;
-    XY_Write(fd,&tag,1);
-    return out_uint32(fd,dataLength);
+
+
+
+/*
+ * ------------------------------------------------------------
+ * XL_WriteImage
+ *  Write a PCL-XL image to the datastream 
+ * ------------------------------------------------------------
+ */
+static void 
+convertAndWriteImage(int            const outFd,
+                     pclGenerator * const pclGenP,
+                     struct pam *   const pamP) {
+
+    size_t const inSize = (pclGenP-> linelen + 3) * 20;
+
+    int blockStartLine;
+    unsigned char * outbuf;
+
+    xl_ubyte(outFd, eDirectPixel); xl_attr_ubyte(outFd, aColorMapping);
+    xl_ubyte(outFd, pclGenP->colorDepth); xl_attr_ubyte(outFd, aColorDepth);
+    xl_uint16(outFd, pclGenP->width); xl_attr_ubyte(outFd, aSourceWidth);  
+    xl_uint16(outFd, pclGenP->height); xl_attr_ubyte(outFd, aSourceHeight);    
+    xl_uint16_xy(outFd, pclGenP->width*1, pclGenP->height*1); 
+    xl_attr_ubyte(outFd, aDestinationSize);   
+    XL_Operator(outFd, oBeginImage);
+
+    pm_rlenc_allocoutbuf(&outbuf, inSize, PM_RLE_PACKBITS);
+
+    for (blockStartLine = 0; blockStartLine < pclGenP->height; ) {
+        unsigned int const blockHeight =
+            MIN(20, pclGenP->height-blockStartLine);
+
+        xl_uint16(outFd, blockStartLine); xl_attr_ubyte(outFd, aStartLine); 
+        xl_uint16(outFd, blockHeight); xl_attr_ubyte(outFd, aBlockHeight);
+        xl_ubyte(outFd, eRLECompression); xl_attr_ubyte(outFd, aCompressMode);
+        /* In modern PCL-XL, we could use a PadBytesMultiple attribute
+           here to avoid having to pad the data to a multiple of 4
+           bytes.  But PCL-XL 1.1 didn't have PadBytesMultiple.
+           xl_ubyte(outFd, 1); xl_attr_ubyte(outFd, aPadBytesMultiple); 
+        */
+        XL_Operator(outFd, oReadImage);
+        convertAndWriteRleBlock(outFd, pclGenP, pamP,
+                                blockStartLine, blockHeight, outbuf);
+        blockStartLine += blockHeight;
+    }
+    pm_rlenc_freebuf(outbuf);
+    XL_Operator(outFd, oEndImage);
 }
 
-#if 0
-static int
-xl_dataLengthbytes(int fd,unsigned char dataLengthBytes) {
-    unsigned char const tag=0xfb;
-    XY_Write(fd,&tag,1);
-    return out_ubyte(fd,dataLengthBytes);
+
+
+static void
+printEmbeddedImage(int                 const outFd,
+                   const InputSource * const sourceP,
+                   bool                const colorok) {
+
+    FILE * ifP;
+    struct pam pam;
+    pclGenerator * pclGeneratorP;
+
+    openDataSource(outFd, eBinaryLowByteFirst, eDefaultSource);
+
+    ifP = pm_openr(sourceP->name);
+
+    pnm_readpaminit(ifP, &pam, PAM_STRUCT_SIZE(tuple_type));
+                
+    createPclGenerator(&pam, &pclGeneratorP, colorok);
+
+    convertAndWriteImage(outFd, pclGeneratorP, &pam);
+    
+    destroyPclGenerator(pclGeneratorP);
+
+    pm_close(ifP);
+
+    closeDataSource(outFd);
 }
-#endif 
 
 
 
@@ -628,10 +810,10 @@ jobHead(int          const outFd,
         copyFile(userJobSetupFileName, outFd);
 
     if (renderGray)
-        XY_Puts(outFd,"@PJL SET RENDERMODE=GRAYSCALE\n");  
+        XY_Puts(outFd, "@PJL SET RENDERMODE=GRAYSCALE\n");  
 
-    XY_Puts(outFd,"@PJL ENTER LANGUAGE=PCLXL\n");  
-    XY_Puts(outFd,") HP-PCL XL;1;1;Generated by Netpbm Pnmtopclxl\n");  
+    XY_Puts(outFd, "@PJL ENTER LANGUAGE=PCLXL\n");  
+    XY_Puts(outFd, ") HP-PCL XL;1;1;Generated by Netpbm Pnmtopclxl\n");  
 }
 
 
@@ -683,18 +865,6 @@ beginPage(int                 const outFd,
 
 
 static void
-openDataSource(int             const outFd,
-               enum DataOrg    const dataOrg,
-               enum DataSource const dataSource) {
-
-    xl_ubyte(outFd, dataOrg); xl_attr_ubyte(outFd,aDataOrg);
-    xl_ubyte(outFd, dataSource); xl_attr_ubyte(outFd,aSourceType);
-    XL_Operator(outFd,oOpenDataSource);
-}
-
-
-
-static void
 setColorSpace(int                   const outFd,
               enum Colorspace       const colorSpace,
               const unsigned char * const palette,
@@ -747,7 +917,7 @@ positionCursor(int            const outFd,
                float          const yoffs,
                int            const imageWidth,
                int            const imageHeight,
-               int            const dpi,
+               unsigned int   const dpi,
                enum MediaSize const format) {
 /*----------------------------------------------------------------------------
    Emit printer control to position the cursor to start the page.
@@ -771,88 +941,6 @@ positionCursor(int            const outFd,
 
 
 static void
-convertAndWriteRleBlock(int                  const outFd,
-                        const pclGenerator * const pclGeneratorP,
-                        struct pam *         const pamP,
-                        int                  const firstLine,
-                        int                  const nlines,
-                        XY_rle *             const rle) {
-
-    unsigned char const pad[4] = {0,0,0,0};
-    unsigned int const paddedLinelen = ((pclGeneratorP->linelen+3)/4)*4;
-    int rlelen;
-    unsigned int line;
-    
-    XY_RLEreset(rle);
-
-    for (line = firstLine; line < firstLine + nlines; ++line) {
-        pclGeneratorP->getnextrow(pclGeneratorP, pamP);
-        XY_RLEput(rle, pclGeneratorP->data, pclGeneratorP->linelen);
-        XY_RLEput(rle, pad, paddedLinelen - pclGeneratorP->linelen);
-    }
-    rlelen = XY_RLEfinish(rle);
-    if (rlelen<0) 
-        pm_error("Error on Making rle");
-
-    xl_dataLength(outFd, rlelen); 
-    XY_Write(outFd, rle->fbuf, rlelen);
-}
-
-
-
-/*
- * ------------------------------------------------------------
- * XL_WriteImage
- *  Write a PCL-XL image to the datastream 
- * ------------------------------------------------------------
- */
-static void 
-convertAndWriteImage(int                  const outFd,
-                     const pclGenerator * const pclGenP,
-                     struct pam *         const pamP) {
-
-    int blockStartLine;
-    XY_rle * rle;
-
-    xl_ubyte(outFd, eDirectPixel); xl_attr_ubyte(outFd, aColorMapping);
-    xl_ubyte(outFd, pclGenP->colorDepth); xl_attr_ubyte(outFd, aColorDepth);
-    xl_uint16(outFd, pclGenP->width); xl_attr_ubyte(outFd, aSourceWidth);  
-    xl_uint16(outFd, pclGenP->height); xl_attr_ubyte(outFd, aSourceHeight);    
-    xl_uint16_xy(outFd, pclGenP->width*1, pclGenP->height*1); 
-    xl_attr_ubyte(outFd, aDestinationSize);   
-    XL_Operator(outFd, oBeginImage);
-
-    if (pclGenP->linelen > INT_MAX / 20)
-        pm_error("Image too big");
-    rle = XY_RLEnew(pclGenP->linelen*20);
-    if (!rle) 
-        pm_error("Unable to allocate %d bytes for the RLE buffer",
-                 pclGenP->linelen * 20);
-
-    blockStartLine = 0;
-    while (blockStartLine < pclGenP->height) {
-        unsigned int const blockHeight =
-            MIN(20, pclGenP->height-blockStartLine);
-        xl_uint16(outFd, blockStartLine); xl_attr_ubyte(outFd, aStartLine); 
-        xl_uint16(outFd, blockHeight); xl_attr_ubyte(outFd, aBlockHeight);
-        xl_ubyte(outFd, eRLECompression); xl_attr_ubyte(outFd, aCompressMode);
-        /* In modern PCL-XL, we could use a PadBytesMultiple attribute
-           here to avoid having to pad the data to a multiple of 4
-           bytes.  But PCL-XL 1.1 didn't have PadBytesMultiple.
-           xl_ubyte(outFd, 1); xl_attr_ubyte(outFd, aPadBytesMultiple); 
-        */
-        XL_Operator(outFd, oReadImage);
-        convertAndWriteRleBlock(outFd, pclGenP, pamP,
-                                blockStartLine, blockHeight, rle);
-        blockStartLine += blockHeight;
-    }
-    XY_RLEdelete(rle);
-    XL_Operator(outFd, oEndImage);
-}
-
-
-
-static void
 endPage(int          const outFd,
         bool         const doCopies,
         unsigned int const copies) {
@@ -870,10 +958,10 @@ endPage(int          const outFd,
 
 static void
 convertAndPrintPage(int                  const outFd,
-                    const pclGenerator * const pclGeneratorP,
+                    pclGenerator *       const pclGeneratorP,
                     struct pam *         const pamP,
                     enum MediaSize       const format,
-                    int                  const dpi,
+                    unsigned int         const dpi,
                     bool                 const center,
                     float                const xoffs,
                     float                const yoffs,
@@ -936,161 +1024,10 @@ endSession(int outFd) {
 
 
 static void
-pnmToPcllinePackbits(const pclGenerator * const pclGeneratorP,
-                     struct pam *         const pamP) {
-
-    tuple * tuplerow;
-    unsigned int pcl_cursor;
-    unsigned char accum;
-    unsigned char bitmask;
-    unsigned int col;
-        
-    tuplerow = pnm_allocpamrow(pamP);
-
-    pnm_readpamrow(pamP, tuplerow);
-
-    pcl_cursor = 0; bitmask = 0x80; accum = 0x00;
-    for (col = 0; col < pamP->width; ++col) {
-        if (tuplerow[col][0] == PAM_PBM_WHITE)
-            accum |= bitmask;
-        bitmask >>= 1;
-        if (bitmask == 0) {
-            pclGeneratorP->data[pcl_cursor++] = accum;
-            bitmask = 0x80; accum = 0x0;
-        } 
-    }
-    if (bitmask != 0x80)
-        pclGeneratorP->data[pcl_cursor++] = accum;
-
-    pnm_freepamrow(tuplerow);
-}
-
-
-
-static void
-createPclGeneratorPackbits(struct pam *    const pamP,
-                           pclGenerator ** const pclGeneratorPP) {
-
-    /* Samples are black or white and packed 8 to a byte */
-
-    pclGenerator * pclGeneratorP;
-
-    MALLOCVAR_NOFAIL(pclGeneratorP);
-
-    pclGeneratorP->colorDepth = e1Bit;
-    pclGeneratorP->colorSpace = eGray;
-    pclGeneratorP->linelen = (pamP->width+7)/8;
-    pclGeneratorP->height = pamP->height;
-    pclGeneratorP->width = (pamP->width);
-
-    pclGeneratorP->data = malloc(pclGeneratorP->linelen);
-    
-    if (pclGeneratorP->data == NULL)
-        pm_error("Unable to allocate row buffer.");
-
-    pclGeneratorP->getnextrow = pnmToPcllinePackbits;
-
-    *pclGeneratorPP = pclGeneratorP;
-}
-
-
-
-static void
-pnmToPcllineWholebytes(const pclGenerator * const pclGeneratorP,
-                       struct pam *         const pamP) {
-
-    tuple * tuplerow;
-    unsigned int pcl_cursor;
-    unsigned int col;
-
-    tuplerow = pnm_allocpamrow(pamP);
-
-    pnm_readpamrow(pamP, tuplerow);
-
-    pcl_cursor = 0; /* initial value */
-    
-    for (col = 0; col < pamP->width; ++col) {
-        unsigned int plane;
-        for (plane = 0; plane < pamP->depth; ++plane) {
-            pclGeneratorP->data[pcl_cursor++] = 
-                pnm_scalesample(tuplerow[col][plane], pamP->maxval, 255);
-        }
-    }
-    pnm_freepamrow(tuplerow);
-}
-
-
-
-static void
-createPclGeneratorWholebytes(struct pam *    const pamP,
-                             pclGenerator ** const pclGenPP) {
-    /* One sample per byte */
-
-    pclGenerator * pclGenP;
-
-    MALLOCVAR_NOFAIL(pclGenP);
-    
-    if (pamP->depth <  3)
-        pclGenP->colorSpace = eGray;
-    else
-        pclGenP->colorSpace = eRGB;
-
-    pclGenP->colorDepth = e8Bit;
-    pclGenP->height     = pamP->height;
-    pclGenP->width      = pamP->width;
-    pclGenP->linelen    = pamP->width * pamP->depth;
-
-    if (UINT_MAX / pamP->width < pamP->depth)
-        pm_error("Image to big to process");
-    else
-        pclGenP->data = malloc(pamP->width * pamP->depth);
-
-    if (pclGenP->data == NULL)
-        pm_error("Unable to allocate row buffer.");
-    
-    pclGenP->getnextrow = pnmToPcllineWholebytes;
-
-    *pclGenPP = pclGenP;
-}
-
-
-
-static void
-destroyPclGenerator(pclGenerator * const pclGenP) {
-
-    free(pclGenP->data);
-
-    free(pclGenP);
-}
-
-
-
-static void 
-createPclGenerator(struct pam *        const pamP,
-                   pclGenerator **     const pclGeneratorPP,
-                   bool                const colorok) {
-
-    if (pamP->depth > 1 && !colorok)
-        pm_message("WARNING: generating a color print stream because the "
-                   "input image is PPM.  "
-                   "To generate a black and white print stream, run the input "
-                   "through Ppmtopgm.  To suppress this warning, use the "
-                   "-colorok option.");
-
-    if (pamP->depth == 1 && pamP->maxval == 1) 
-        createPclGeneratorPackbits(pamP, pclGeneratorPP);
-    else 
-        createPclGeneratorWholebytes(pamP, pclGeneratorPP);
-}
-
-
-
-
-static void
 printPages(int                 const outFd,
            InputSource *       const firstSourceP,
            enum MediaSize      const format,
-           int                 const dpi,
+           unsigned int        const dpi,
            bool                const center,
            float               const xoffs,
            float               const yoffs,
@@ -1116,12 +1053,12 @@ printPages(int                 const outFd,
     sourceNum = 0;   /* initial value */
 
     while (sourceP) {
-        FILE * in_file;
+        FILE * ifP;
         struct pam pam;
-        bool eof;
+        int eof;
         unsigned int pageNum;
 
-        in_file = pm_openr(sourceP->name);
+        ifP = pm_openr(sourceP->name);
 
         ++sourceNum;
 
@@ -1129,14 +1066,14 @@ printPages(int                 const outFd,
 
         eof = FALSE;
         while(!eof) {
-            pnm_nextimage(in_file, &eof);
+            pnm_nextimage(ifP, &eof);
             if (!eof) {
                 pclGenerator * pclGeneratorP;
 
                 ++pageNum;
                 pm_message("Processing File %u, Page %u", sourceNum, pageNum);
 
-                pnm_readpaminit(in_file, &pam, PAM_STRUCT_SIZE(tuple_type));
+                pnm_readpaminit(ifP, &pam, PAM_STRUCT_SIZE(tuple_type));
                 
                 createPclGenerator(&pam, &pclGeneratorP, colorok);
                 
@@ -1149,25 +1086,10 @@ printPages(int                 const outFd,
                 destroyPclGenerator(pclGeneratorP);
             }
         }
-        pm_close(in_file);
+        pm_close(ifP);
         sourceP = sourceP->next; 
     }
-    XL_Operator(outFd, oCloseDataSource);
-}
-
-
-
-static void
-freeSource(InputSource * const firstSourceP) {
-    
-    InputSource * sourceP;
-
-    sourceP = firstSourceP;
-    while(sourceP) {
-        InputSource * const nextP = sourceP->next;
-        free(sourceP);
-        sourceP = nextP;
-    }
+    closeDataSource(outFd);
 }
 
 
@@ -1189,25 +1111,28 @@ main(int argc, char *argv[]) {
 
     parseCommandLine(argc, argv, &cmdline);
 
-    jobHead(outFd, cmdline.rendergray, cmdline.jobsetup);
-
-    beginSession(outFd, cmdline.dpi, cmdline.dpi, eInch, 
-                 FALSE, eBackChAndErrPage);
-
-    printPages(outFd,cmdline.sourceP,
-               cmdline.format, cmdline.dpi, cmdline.center,
-               cmdline.xoffs, cmdline.yoffs,
-               cmdline.duplexSpec, cmdline.duplex,
-               cmdline.copiesSpec, cmdline.copies,
-               cmdline.feederSpec, cmdline.feeder,
-               cmdline.outtraySpec, cmdline.outtray,
-               cmdline.colorok
-        );
-    endSession(outFd);
-
-    jobEnd(outFd);
-
-    freeSource(cmdline.sourceP);
+    if (cmdline.embedded)
+        printEmbeddedImage(outFd, cmdline.sourceP, cmdline.colorok);
+    else {
+        jobHead(outFd, cmdline.rendergray, cmdline.jobsetup);
+
+        beginSession(outFd, cmdline.dpi, cmdline.dpi, eInch, 
+                     FALSE, eBackChAndErrPage);
+
+        printPages(outFd, cmdline.sourceP,
+                   cmdline.format, cmdline.dpi, cmdline.center,
+                   cmdline.xoffs, cmdline.yoffs,
+                   cmdline.duplexSpec, cmdline.duplex,
+                   cmdline.copiesSpec, cmdline.copies,
+                   cmdline.feederSpec, cmdline.feeder,
+                   cmdline.outtraySpec, cmdline.outtray,
+                   cmdline.colorok
+            );
+        endSession(outFd);
+
+        jobEnd(outFd);
+    }
+    freeCmdline(cmdline);
 
     return 0;
 }
diff --git a/converter/other/pnmtopng.README b/converter/other/pnmtopng.README
deleted file mode 100644
index bfa524dc..00000000
--- a/converter/other/pnmtopng.README
+++ /dev/null
@@ -1,101 +0,0 @@
-Pnmtopng and Pngtopnm are based on programs of the same name in the 
-Pnmtopng package owned by Alexander Lehmann and Willem Van Schaik,
-available at http://www.libpng.org/pub/png/src on 2001.07.14.
-
-I added it to and adapted it to Netpbm on 2000.03.02 to make it more
-easily available to people.  I applied a patch on 2000.06.03 to bring
-it up the 2.37.4 release of that package.  I updated it again on
-2001.07.14 to bring it up to Release 2.37.5.  There is no process in
-place to bring improvements to the base package into the Netpbm
-version, but there hasn't been a lot of update activity anyway.
-
-Attached below is the file README from Release 2.37.5 of the base
-package.
-
-Here are the differences between the base and the Netpbm version:
-
-  I added an "unsigned" to make formal and actual arguments to png_sig_cmp()
-  match and quiet a compiler warning.
-
-  I fixed an "include" statement so the dependencies work out right.
-
-  I removed the BIGGRAYS stuff, which became obsolete in Netpbm 9.0
-
-  I replaced a PPM_MAXVAL with PPM_OVERALLMAXAL to handle the new 16 bits
-  formats.
-
-  macro VERSION is defined directly in pngtopnm.c and pnmtopng.c instead
-  of being included via file version.h.
-
-  Pnmtopng, since June 2001, reads one row at a time instead of holding 
-  the entire image in memory.  That makes it work with large bitmaps
-  where it would otherwise run out of memory.  It also works faster with
-  bitmaps since a bit takes up only a bit of memory in a cached input 
-  file, but 96 bits of memory after reading it into a Netpbm data 
-  structure.
-
-  The base Pnmtopng ignores -transparent if it specifies a color that
-  isn't in the image.  Netpbm's Pnmtopng selects a nearby color that _is_
-  in the image, which is what base Pnmtopng did before October 2000.
-  Netpbm's Pnmtopng lets you put an '=' sign before the color to specify
-  that you don't want a nearby color to be chosen, i.e. you want the
-  base Pnmtopng function.  This is consistent with Pnmtogif.
-
-There were some other changes necessary before Netpbm 9.0, but the change
-of the xelval type from 1 byte to 4 made them unnecessary.
-
-
-** PNMTOPNG / PNGTOPNM
-** version 2.37.5 - 24 October 2000
-
-[This is a semi-official bug-fix and enhancement release; I sort of took over
- maintenance of this package while Willem was on an extended bike trip, and
- for now I'm continuing with periodic, small updates.  Version 2.37 (March
- 1998) was never publicly released, partly because Willem had hoped to quiet
- gcc's "<var> might be clobbered by `longjmp'" warnings.  Those are fixed in
- 2.37.2; under Solaris, they resulted in stack corruption even when there was
- no error in the image files or libraries.  Version 2.37.3 fixes a minor bug
- w.r.t. error exits and generally does cleaner error exits (close files, etc.)
- Version 2.37.4 fixes a bug that caused 16-shade grayscale images to be written
- as 8-bit grayscale instead of (smaller) 4-bit colormapped images (bug report,
- analysis and fix by Rafal Rzeczkowski), and it supports the new/upcoming
- pbmplus release.  Version 2.37.5 fixes a bug in -transparent handling (pnmtopng
- no longer chooses an approximate color if the specified one isn't present) and
- quiets a gcc warning in the non-16-bit version.
- --Greg Roelofs]
-
-The utilities pnmtopng and pngtopnm are based on other pbm tools and require
-the libraries included in the pbmplus/netpbm package. Also required are the
-png library and the zlib compression library.
-
-These can be found at:
-	ftp://swrinde.nde.swri.edu/pub/png/src/libpng-*
-	ftp://swrinde.nde.swri.edu/pub/png/src/zlib-*
-	ftp://ftp.x.org/contrib/utilities/netpbm-1mar1994*
-or see
-	http://www.libpng.org/pub/png/apps/pnmtopng.html
-	http://netpbm.sourceforge.net/
-	http://www.acme.com/software/pbmplus/		[update coming soon?]
-
-To compile and install a makefile is provided. Do check the directories
-where you have put the required libraries. Then either accommodate the 
-makefile or make links from generic names (e.g., zlib) to version-specific
-directories (e.g., zlib-1.1.3), which is the recommended way.
-
-For testing purposes, have a look at the test-set PngSuite.tar.gz, which
-contains a small test-image for every PNG color type and for most PNG chunk
-types. It can be found at:
-	http://www.schaik.com/pngsuite/pngsuite.html
-	ftp://swrinde.nde.swri.edu/pub/png/images/suite/
-
-Other web pages with PNG images are at:
-	http://www.libpng.org/pub/png/png-textures.html
-	http://www.libpng.org/pub/png/pngs-img.html
-	http://www.libpng.org/pub/png/pngpic2.html
-	http://www.libpng.org/pub/png/colorcube/
-	http://www.libpng.org/pub/png/pngmisc.html#images
-
-------
-Alexander Lehmann <lehmann@usa.net>
-Willem van Schaik <willem@schaik.com>
-Greg Roelofs <newt@pobox.com>
diff --git a/converter/other/pnmtopng.c b/converter/other/pnmtopng.c
index 76c7a3a4..3899a9d2 100644
--- a/converter/other/pnmtopng.c
+++ b/converter/other/pnmtopng.c
@@ -1,6 +1,5 @@
 /*
-** pnmtopng.c -
-** read a portable anymap and produce a Portable Network Graphics file
+** read a PNM image and produce a Portable Network Graphics file
 **
 ** derived from pnmtorast.c (c) 1990,1991 by Jef Poskanzer and some
 ** parts derived from ppmtogif.c by Marcel Wijkstra <wijkstra@fwi.uva.nl>
@@ -59,31 +58,22 @@
 #include <assert.h>
 #include <string.h> /* strcat() */
 #include <limits.h>
-#include <png.h>    /* includes zlib.h and setjmp.h */
+#include <png.h>
+/* Because of a design error in png.h, you must not #include <setjmp.h> before
+   <png.h>.  If you do, png.h won't compile.
+*/
+#include <setjmp.h> 
+#include <zlib.h>
 
 #include "pm_c_util.h"
 #include "pnm.h"
+#include "pngx.h"
 #include "pngtxt.h"
 #include "shhopt.h"
 #include "mallocvar.h"
 #include "nstring.h"
 #include "version.h"
 
-#if PNG_LIBPNG_VER >= 10500
-#error Your PNG library (<png.h>) is incompatible with this Netpbm source code.
-#error You need either an older PNG library (older than 1.5) or
-#error newer Netpbm source code (at least 10.55)
-#endif
-
-/* A hack until we can remove direct access to png_info from the program */
-#if PNG_LIBPNG_VER >= 10400
-#define trans_values trans_color
-#define TRANS_ALPHA trans_alpha
-#else
-#define TRANS_ALPHA trans
-#endif
-
-
 struct zlibCompression {
     /* These are parameters that describe a form of zlib compression.
        Values have the same meaning as the similarly named arguments to
@@ -103,23 +93,6 @@ struct zlibCompression {
     unsigned int buffer_size;
 };
 
-struct chroma {
-    float wx;
-    float wy;
-    float rx;
-    float ry;
-    float gx;
-    float gy;
-    float bx;
-    float by;
-};
-
-struct phys {
-    int x;
-    int y;
-    int unit;
-};
-
 typedef struct cahitem {
     xel color;
     gray alpha;
@@ -133,7 +106,7 @@ 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 */
+    const char *  inputFileName;  /* '-' if stdin */
     const char *  alpha;
     unsigned int  verbose;
     unsigned int  downscale;
@@ -144,9 +117,11 @@ struct cmdlineInfo {
     float         gamma;        /* Meaningless if !gammaSpec */
     unsigned int  hist;
     unsigned int  rgbSpec;
-    struct chroma rgb;          /* Meaningless if !rgbSpec */
+    struct pngx_chroma rgb;          /* Meaningless if !rgbSpec */
     unsigned int  sizeSpec;
-    struct phys   size;         /* Meaningless if !sizeSpec */
+    struct pngx_phys   size;         /* Meaningless if !sizeSpec */
+    unsigned int srgbintentSpec;
+    pngx_srgbIntent srgbintent;
     const char *  text;         /* NULL if none */
     const char *  ztxt;         /* NULL if none */
     unsigned int  modtimeSpec;
@@ -156,7 +131,6 @@ struct cmdlineInfo {
     int           filterSet;
     unsigned int  force;
     unsigned int  libversion;
-    unsigned int  compressionSpec;
     struct zlibCompression zlibCompression;
 };
 
@@ -192,8 +166,8 @@ static int errorlevel;
 
 
 static void
-parseSizeOpt(const char *  const sizeOpt,
-             struct phys * const sizeP) {
+parseSizeOpt(const char *       const sizeOpt,
+             struct pngx_phys * const sizeP) {
 
     int count;
     
@@ -207,8 +181,8 @@ parseSizeOpt(const char *  const sizeOpt,
 
 
 static void
-parseRgbOpt(const char *    const rgbOpt,
-            struct chroma * const rgbP) {
+parseRgbOpt(const char *         const rgbOpt,
+            struct pngx_chroma * const rgbP) {
 
     int count;
     
@@ -228,6 +202,27 @@ parseRgbOpt(const char *    const rgbOpt,
 
 
 static void
+parseSrgbintentOpt(const char *      const srgbintentOpt,
+                   pngx_srgbIntent * const srgbintentP) {
+    
+    if (streq(srgbintentOpt, "perceptual"))
+        *srgbintentP = PNGX_PERCEPTUAL;
+    else if (streq(srgbintentOpt, "relativecolorimetric"))
+        *srgbintentP = PNGX_RELATIVE_COLORIMETRIC;
+    else if (streq(srgbintentOpt, "saturation"))
+        *srgbintentP = PNGX_SATURATION;
+    else if (streq(srgbintentOpt, "absolutecolorimetric"))
+        *srgbintentP = PNGX_ABSOLUTE_COLORIMETRIC;
+    else
+        pm_error("Unrecognized sRGB intent value '%s'.  We understand "
+                 "only 'perceptual', 'relativecolorimetric', "
+                 "'saturation', and 'absolutecolorimetric'",
+                 srgbintentOpt);
+}
+
+
+
+static void
 parseModtimeOpt(const char * const modtimeOpt,
                 time_t *     const modtimeP) {
 
@@ -291,7 +286,7 @@ parseModtimeOpt(const char * const modtimeOpt,
 
 
 static void
-parseCommandLine(int argc, char ** argv,
+parseCommandLine(int argc, const char ** argv,
                  struct cmdlineInfo * const cmdlineP) {
 /*----------------------------------------------------------------------------
    parse program command line described in Unix standard form by argc
@@ -304,7 +299,7 @@ parseCommandLine(int argc, char ** argv,
    was passed to us as the argv array.  We also trash *argv.
 -----------------------------------------------------------------------------*/
     optEntry *option_def;
-        /* Instructions to optParseOptions3 on how to parse our options.
+        /* Instructions to pm_optParseOptions3 on how to parse our options.
          */
     optStruct3 opt;
 
@@ -321,6 +316,7 @@ parseCommandLine(int argc, char ** argv,
     const char * modtime;
     const char * compMethod;
     const char * compStrategy;
+    const char * srgbintent;
 
     MALLOCARRAY_NOFAIL(option_def, 100);
 
@@ -335,6 +331,8 @@ parseCommandLine(int argc, char ** argv,
             &cmdlineP->rgbSpec,    0);
     OPTENT3(0, "size",             OPT_STRING,    &size,
             &cmdlineP->sizeSpec,   0);
+    OPTENT3(0,  "srgbintent",      OPT_STRING,    &srgbintent,
+            &cmdlineP->srgbintentSpec, 0);
     OPTENT3(0, "text",             OPT_STRING,    &cmdlineP->text,
             &textSpec,             0);
     OPTENT3(0, "ztxt",             OPT_STRING,    &cmdlineP->ztxt,
@@ -399,7 +397,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 */
 
-    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. */
 
 
@@ -469,6 +467,9 @@ parseCommandLine(int argc, char ** argv,
     if (cmdlineP->rgbSpec)
         parseRgbOpt(rgb, &cmdlineP->rgb);
     
+    if (cmdlineP->srgbintentSpec)
+        parseSrgbintentOpt(srgbintent, &cmdlineP->srgbintent);
+
     if (cmdlineP->modtimeSpec)
         parseModtimeOpt(modtime, &cmdlineP->modtime);
 
@@ -506,19 +507,41 @@ parseCommandLine(int argc, char ** argv,
 
 
     if (argc-1 < 1)
-        cmdlineP->inputFilename = "-";
+        cmdlineP->inputFileName = "-";
     else if (argc-1 == 1)
-        cmdlineP->inputFilename = argv[1];
+        cmdlineP->inputFileName = argv[1];
     else
         pm_error("Program takes at most one argument:  input file name");
 }
 
 
 
+static void
+reportInputType(int    const format,
+                xelval const maxval) {
+
+    switch (PNM_FORMAT_TYPE(format)) {
+    case PBM_TYPE:
+        pm_message ("reading a PBM file");
+        break;
+    case PGM_TYPE:
+        pm_message ("reading a PGM file (maxval=%d)", maxval);
+        break;
+    case PPM_TYPE:
+        pm_message ("reading a PPM file (maxval=%d)", maxval);
+        break;
+    default:
+        assert(false);
+    }
+}
+
+
+
 static png_color_16
-xelToPngColor_16(xel const input, 
+xelToPngColor_16(xel    const input, 
                  xelval const maxval, 
                  xelval const pngMaxval) {
+
     png_color_16 retval;
 
     xel scaled;
@@ -648,36 +671,6 @@ lookupColorAlpha(coloralphahash_table const caht,
 
 
 
-static void
-pnmtopng_error_handler(png_structp     const png_ptr,
-                       png_const_charp const msg) {
-
-  jmpbuf_wrapper  *jmpbuf_ptr;
-
-  /* this function, aside from the extra step of retrieving the "error
-   * pointer" (below) and the fact that it exists within the application
-   * rather than within libpng, is essentially identical to libpng's
-   * default error handler.  The second point is critical:  since both
-   * setjmp() and longjmp() are called from the same code, they are
-   * guaranteed to have compatible notions of how big a jmp_buf is,
-   * regardless of whether _BSD_SOURCE or anything else has (or has not)
-   * been defined. */
-
-  fprintf(stderr, "pnmtopng:  fatal libpng error: %s\n", msg);
-  fflush(stderr);
-
-  jmpbuf_ptr = png_get_error_ptr(png_ptr);
-  if (jmpbuf_ptr == NULL) {         /* we are completely hosed now */
-    fprintf(stderr,
-      "pnmtopng:  EXTREMELY fatal error: jmpbuf unrecoverable; terminating.\n");
-    fflush(stderr);
-    exit(99);
-  }
-
-  longjmp(jmpbuf_ptr->jmpbuf, 1);
-}
-
-
 /* The following variables belong to getChv() and freeChv() */
 static bool getChv_computed = FALSE;
 static colorhist_vector getChv_chv;
@@ -921,7 +914,7 @@ tryTransparentColor(FILE *     const ifp,
                     pixel      const transcolor,
                     bool *     const singleColorIsTransP) {
 
-    int const pnm_type = PNM_FORMAT_TYPE(format);
+    int const pnmType = PNM_FORMAT_TYPE(format);
 
     xel * xelrow;
     bool singleColorIsTrans;
@@ -942,7 +935,7 @@ tryTransparentColor(FILE *     const ifp,
                 /* If we have a second transparent color, we're
                    disqualified
                 */
-                if (pnm_type == PPM_TYPE) {
+                if (pnmType == PPM_TYPE) {
                     if (!PPM_EQUAL(xelrow[col], transcolor))
                         singleColorIsTrans = FALSE;
                 } else {
@@ -959,7 +952,7 @@ tryTransparentColor(FILE *     const ifp,
                    the same color as our candidate transparent color,
                    that disqualifies us.
                 */
-                if (pnm_type == PPM_TYPE) {
+                if (pnmType == PPM_TYPE) {
                     if (PPM_EQUAL(xelrow[col], transcolor))
                         singleColorIsTrans = FALSE;
                 } else {
@@ -1064,6 +1057,170 @@ analyzeAlpha(FILE *       const ifP,
 
 
 static void
+determineTransparency(struct cmdlineInfo const cmdline,
+                      FILE *             const ifP,
+                      pm_filepos         const rasterPos,
+                      unsigned int       const cols,
+                      unsigned int       const rows,
+                      xelval             const maxval,
+                      int                const format,
+                      FILE *             const afP,
+                      bool *             const alphaP,
+                      int *              const transparentP,
+                      pixel *            const transColorP,
+                      bool *             const transExactP,
+                      gray ***           const alphaMaskP,
+                      gray *             const alphaMaxvalP) {
+/*----------------------------------------------------------------------------
+   Determine the various aspects of transparency we need to generate the
+   PNG.
+
+   Note that there are two kinds of transparency: pixel-by-pixel
+   transparency/translucency with an alpha mask and all pixels of a certain
+   color being transparent.  Both these exist both in input from the user and
+   as representations in the PNG -- i.e. user may supply an alpha mask,
+   or identify a transparent color and the PNG may contain an alpha mask
+   or identify a transparent color.
+
+   We return as *transparentP:
+   
+     -1 PNG is not to have single-color transparency
+      1 PNG is to have single-color transparency as directed by user
+      2 PNG is to have single-color transparency that effects an alpha
+            mask that the user supplied.
+
+   In the cases where there is to be single-color transparency, *transColorP
+   is that color.
+-----------------------------------------------------------------------------*/
+    if (cmdline.alpha) {
+        pixel alphaTranscolor;
+        bool alphaCanBeTransparencyIndex;
+        bool allOpaque;
+        int alphaCols, alphaRows;
+        gray alphaMaxval;
+        gray ** alphaMask;
+
+        if (verbose)
+            pm_message("reading alpha-channel image...");
+        alphaMask = pgm_readpgm(afP, &alphaCols, &alphaRows, &alphaMaxval);
+
+        if (alphaCols != cols || alphaRows != rows) {
+            pm_error("dimensions for image and alpha mask do not agree");
+        }
+        analyzeAlpha(ifP, rasterPos, cols, rows, maxval, format, 
+                     alphaMask, alphaMaxval, &allOpaque,
+                     &alphaCanBeTransparencyIndex, &alphaTranscolor);
+
+        if (alphaCanBeTransparencyIndex && !cmdline.force) {
+            if (verbose)
+                pm_message("converting alpha mask to transparency index");
+            *alphaP       = FALSE;
+            *transparentP = 2;
+            *transColorP  = alphaTranscolor;
+        } else if (allOpaque) {
+            if (verbose)
+                pm_message("Skipping alpha because mask is all opaque");
+            *alphaP       = FALSE;
+            *transparentP = -1;
+        } else {
+            *alphaP       = TRUE;
+            *transparentP = -1;
+        }
+        *alphaMaxvalP = alphaMaxval;
+        *alphaMaskP   = alphaMask;
+    } else {
+        /* Though there's no alpha_mask, we still need an alpha_maxval for
+           use with trans[], which can have stuff in it if the user specified
+           a transparent color.
+        */
+        *alphaP       = FALSE;
+        *alphaMaxvalP = 255;
+
+        if (cmdline.transparent) {
+            const char * transstring2;  
+            /* The -transparent value, but with possible leading '=' removed */
+            if (cmdline.transparent[0] == '=') {
+                *transExactP = TRUE;
+                transstring2 = &cmdline.transparent[1];
+            } else {
+                *transExactP = FALSE;
+                transstring2 = cmdline.transparent;
+            }  
+            /* We do this funny PPM_DEPTH thing instead of just passing 'maxval'
+               to ppm_parsecolor() because ppm_parsecolor() does a cheap maxval
+               scaling, and this is more precise.
+            */
+            PPM_DEPTH(*transColorP, 
+                      ppm_parsecolor(transstring2, PNM_OVERALLMAXVAL),
+                      PNM_OVERALLMAXVAL, maxval);
+
+            *transparentP = 1;
+        } else
+            *transparentP = -1;
+    }
+}
+
+
+
+static void
+determineBackground(struct cmdlineInfo const cmdline,
+                    xelval             const maxval,
+                    xel *              const backColorP) {
+
+  if (cmdline.background) 
+      PPM_DEPTH(*backColorP,
+                ppm_parsecolor(cmdline.background, PNM_OVERALLMAXVAL), 
+                PNM_OVERALLMAXVAL, maxval);;
+}
+
+
+
+static bool
+hasColor(FILE *       const ifP,
+         unsigned int const cols,
+         unsigned int const rows,
+         xelval       const maxval,
+         int          const format,
+         pm_filepos   const rasterPos) {
+/*----------------------------------------------------------------------------
+   The image contains colors other than black, white, and gray.
+-----------------------------------------------------------------------------*/
+    bool retval;
+
+    if (PNM_FORMAT_TYPE(format) == PPM_TYPE) {
+        unsigned int row;
+        xel * xelrow;    /* malloc'ed */
+            /* The row of the input image currently being analyzed */
+        bool isGray;
+
+        xelrow = pnm_allocrow(cols);
+
+        pm_seek2(ifP, &rasterPos, sizeof(rasterPos));
+
+        for (row = 0, isGray = true; row < rows && isGray; ++row) {
+            unsigned int col;
+
+            pnm_readpnmrow(ifP, xelrow, cols, maxval, format);
+
+            for (col = 0; col < cols && isGray; ++col) {
+                    xel const p = xelrow[col];
+                if (PPM_GETR(p) != PPM_GETG(p) || PPM_GETG(p) != PPM_GETB(p))
+                    isGray = FALSE;
+            }
+        }
+
+        pnm_freerow(xelrow);
+
+        retval = !isGray;
+    } else
+        retval = false;
+
+    return retval;
+}
+
+
+
+static void
 findRedundantBits(FILE *         const ifp, 
                   int            const rasterPos, 
                   int            const cols,
@@ -1588,7 +1745,7 @@ makeOneColorTransparentInPalette(xel            const transColor,
         *transSizeP = 1;
         if (verbose) {
             pixel const p = palette_pnm[0];
-            pm_message("Making all occurences of color (%u, %u, %u) "
+            pm_message("Making all occurrences of color (%u, %u, %u) "
                        "transparent.",
                        PPM_GETR(p), PPM_GETG(p), PPM_GETB(p));
         }
@@ -1753,10 +1910,10 @@ tryAlphaPalette(FILE *         const ifP,
                           palette_pnm, trans_pnm, 
                           paletteSizeP, transSizeP, &tooBig);
     if (tooBig) {
-        asprintfN(impossibleReasonP,
-                  "too many color/transparency pairs "
-                  "(more than the PNG maximum of %u", 
-                  MAXPALETTEENTRIES);
+        pm_asprintf(impossibleReasonP,
+                    "too many color/transparency pairs "
+                    "(more than the PNG maximum of %u", 
+                    MAXPALETTEENTRIES);
     } else
         *impossibleReasonP = NULL;
 } 
@@ -1764,19 +1921,19 @@ tryAlphaPalette(FILE *         const ifP,
 
 
 static void
-computePixelWidth(int            const pnm_type,
-                  unsigned int   const pnm_meaningful_bits,
+computePixelWidth(bool           const colorPng,
+                  unsigned int   const pnmMeaningfulBitCt,
                   bool           const alpha,
                   unsigned int * const bitsPerSampleP,
                   unsigned int * const bitsPerPixelP) {
 
     unsigned int bitsPerSample, bitsPerPixel;
 
-    if (pnm_type == PPM_TYPE || alpha) {
+    if (colorPng || alpha) {
         /* PNG allows only depths of 8 and 16 for a truecolor image 
            and for a grayscale image with an alpha channel.
           */
-        if (pnm_meaningful_bits > 8)
+        if (pnmMeaningfulBitCt > 8)
             bitsPerSample = 16;
         else 
             bitsPerSample = 8;
@@ -1784,24 +1941,24 @@ computePixelWidth(int            const pnm_type,
         /* A grayscale, non-colormapped, no-alpha PNG may have any 
              bit depth from 1 to 16
           */
-        if (pnm_meaningful_bits > 8)
+        if (pnmMeaningfulBitCt > 8)
             bitsPerSample = 16;
-        else if (pnm_meaningful_bits > 4)
+        else if (pnmMeaningfulBitCt > 4)
             bitsPerSample = 8;
-        else if (pnm_meaningful_bits > 2)
+        else if (pnmMeaningfulBitCt > 2)
             bitsPerSample = 4;
-        else if (pnm_meaningful_bits > 1)
+        else if (pnmMeaningfulBitCt > 1)
             bitsPerSample = 2;
         else
             bitsPerSample = 1;
     }
     if (alpha) {
-        if (pnm_type == PPM_TYPE)
+        if (colorPng)
             bitsPerPixel = 4 * bitsPerSample;
         else
             bitsPerPixel = 2 * bitsPerSample;
     } else {
-        if (pnm_type == PPM_TYPE)
+        if (colorPng)
             bitsPerPixel = 3 * bitsPerSample;
         else
             bitsPerPixel = bitsPerSample;
@@ -1849,7 +2006,7 @@ computeColorMap(FILE *         const ifP,
                 int            const cols,
                 int            const rows,
                 xelval         const maxval,
-                int            const pnmType,
+                bool           const colorPng,
                 int            const format,
                 bool           const force,
                 FILE *         const pfP,
@@ -1882,29 +2039,35 @@ computeColorMap(FILE *         const ifP,
   palette_pnm[] and trans_pnm[], allocated by Caller, with sizes
   *paletteSizeP and *transSizeP.
 
+  'pfP' is a handle to the file that the user requested be used for the
+  palette (it's a Netpbm image whose colors are the colors of the palette).
+  'pfP' is null if the user did not request a particular palette.
+
   'background' means the image is to have a background color, and that
   color is 'backcolor'.  'backcolor' is meaningless when 'background'
   is false.
 
   If the image is to have a background color, we return the palette index
   of that color as *backgroundIndexP.
+
+  'colorPng' means the PNG will be of the RGB variety.
 -------------------------------------------------------------------------- */
     if (force)
-        asprintfN(noColormapReasonP, "You requested no color map");
+        pm_asprintf(noColormapReasonP, "You requested no color map");
     else if (maxval > PALETTEMAXVAL)
-        asprintfN(noColormapReasonP, "The maxval of the input image (%u) "
-                  "exceeds the PNG palette maxval (%u)", 
-                  maxval, PALETTEMAXVAL);
+        pm_asprintf(noColormapReasonP, "The maxval of the input image (%u) "
+                    "exceeds the PNG palette maxval (%u)", 
+                    maxval, PALETTEMAXVAL);
     else {
         unsigned int bitsPerPixel;
-        computePixelWidth(pnmType, pnm_meaningful_bits, alpha,
+        computePixelWidth(colorPng, pnm_meaningful_bits, alpha,
                           NULL, &bitsPerPixel);
 
         if (!pfP && bitsPerPixel == 1)
             /* No palette can beat 1 bit per pixel -- no need to waste time
                counting the colors.
             */
-            asprintfN(noColormapReasonP, "pixel is already only 1 bit");
+            pm_asprintf(noColormapReasonP, "pixel is already only 1 bit");
         else {
             /* We'll have to count the colors ('colors') to know if a
                palette is possible and desirable.  Along the way, we'll
@@ -1918,16 +2081,16 @@ computeColorMap(FILE *         const ifP,
                    &chv, &colors);
 
             if (chv == NULL) {
-                asprintfN(noColormapReasonP, 
-                          "More than %u colors found -- too many for a "
-                          "colormapped PNG", MAXCOLORS);
+                pm_asprintf(noColormapReasonP, 
+                            "More than %u colors found -- too many for a "
+                            "colormapped PNG", MAXCOLORS);
             } else {
                 /* There are few enough colors that a palette is possible */
                 if (bitsPerPixel <= paletteIndexBits(colors) && !pfP)
-                    asprintfN(noColormapReasonP, 
-                              "palette index for %u colors would be "
-                              "no smaller than the indexed value (%u bits)", 
-                              colors, bitsPerPixel);
+                    pm_asprintf(noColormapReasonP, 
+                                "palette index for %u colors would be "
+                                "no smaller than the indexed value (%u bits)", 
+                                colors, bitsPerPixel);
                 else {
                     unsigned int paletteSize;
                     unsigned int transSize;
@@ -2010,9 +2173,9 @@ static void computeColorMapLookupTable(
 
 static void
 computeRasterWidth(bool           const colorMapped,
-                   unsigned int   const palette_size,
-                   int            const pnm_type,
-                   unsigned int   const pnm_meaningful_bits,
+                   unsigned int   const paletteSize,
+                   bool           const colorPng,
+                   unsigned int   const pnmMeaningfulBitCt,
                    bool           const alpha,
                    unsigned int * const bitsPerSampleP,
                    unsigned int * const bitsPerPixelP) {
@@ -2023,24 +2186,24 @@ computeRasterWidth(bool           const colorMapped,
 -----------------------------------------------------------------------------*/
     if (colorMapped) {
         /* The raster element is a palette index */
-        if (palette_size <= 2)
+        if (paletteSize <= 2)
             *bitsPerSampleP = 1;
-        else if (palette_size <= 4)
+        else if (paletteSize <= 4)
             *bitsPerSampleP = 2;
-        else if (palette_size <= 16)
+        else if (paletteSize <= 16)
             *bitsPerSampleP = 4;
         else
             *bitsPerSampleP = 8;
         *bitsPerPixelP = *bitsPerSampleP;
         if (verbose)
-            pm_message("Writing %d-bit color indexes", *bitsPerSampleP);
+            pm_message("Writing %u-bit color indexes", *bitsPerSampleP);
     } else {
         /* The raster element is an explicit pixel -- color and transparency */
-        computePixelWidth(pnm_type, pnm_meaningful_bits, alpha,
+        computePixelWidth(colorPng, pnmMeaningfulBitCt, alpha,
                           bitsPerSampleP, bitsPerPixelP);
 
         if (verbose)
-            pm_message("Writing %d bits per component per pixel", 
+            pm_message("Writing %u bits per component per pixel", 
                        *bitsPerSampleP);
     }
 }
@@ -2082,41 +2245,28 @@ createPngPalette(pixel              palette_pnm[],
 
 
 static void
-setCompressionSize(png_struct * const png_ptr,
-                   int const    buffer_size) {
-
-#if PNG_LIBPNG_VER >= 10009
-    png_set_compression_buffer_size(png_ptr, buffer_size);
-#else
-    pm_error("Your PNG library cannot set the compression buffer size.  "
-             "You need at least Version 1.0.9 of Libpng; you have Version %s",
-             PNG_LIBPNG_VER_STRING);
-#endif
-}
-
-
-
-static void
-setZlibCompression(png_struct *           const png_ptr,
+setZlibCompression(struct pngx *          const pngxP,
                    struct zlibCompression const zlibCompression) {
 
     if (zlibCompression.levelSpec)
-        png_set_compression_level(png_ptr, zlibCompression.level);
+        png_set_compression_level(pngxP->png_ptr, zlibCompression.level);
 
     if (zlibCompression.memLevelSpec)
-        png_set_compression_mem_level(png_ptr, zlibCompression.mem_level);
+        png_set_compression_mem_level(pngxP->png_ptr,
+                                      zlibCompression.mem_level);
 
     if (zlibCompression.strategySpec)
-        png_set_compression_strategy(png_ptr, zlibCompression.strategy);
+        png_set_compression_strategy(pngxP->png_ptr, zlibCompression.strategy);
 
     if (zlibCompression.windowBitsSpec)
-        png_set_compression_window_bits(png_ptr, zlibCompression.window_bits);
+        png_set_compression_window_bits(pngxP->png_ptr,
+                                        zlibCompression.window_bits);
 
     if (zlibCompression.methodSpec)
-        png_set_compression_method(png_ptr, zlibCompression.method);
+        png_set_compression_method(pngxP->png_ptr, zlibCompression.method);
 
     if (zlibCompression.bufferSizeSpec) {
-        setCompressionSize(png_ptr, zlibCompression.buffer_size);
+        pngx_setCompressionSize(pngxP, zlibCompression.buffer_size);
     }
 }
                   
@@ -2131,7 +2281,7 @@ makePngLine(png_byte *           const line,
             gray *               const alpha_mask,
             colorhash_table      const cht,
             coloralphahash_table const caht,
-            png_info *           const info_ptr,
+            struct pngx *        const pngxP,
             xelval               const png_maxval,
             unsigned int         const depth) {
             
@@ -2143,20 +2293,20 @@ makePngLine(png_byte *           const line,
         xel p_png;
         xel const p = xelrow[col];
         PPM_DEPTH(p_png, p, maxval, png_maxval);
-        if (info_ptr->color_type == PNG_COLOR_TYPE_GRAY ||
-            info_ptr->color_type == PNG_COLOR_TYPE_GRAY_ALPHA) {
+        if (pngx_colorType(pngxP) == PNG_COLOR_TYPE_GRAY ||
+            pngx_colorType(pngxP) == PNG_COLOR_TYPE_GRAY_ALPHA) {
             if (depth == 16)
                 *pp++ = PNM_GET1(p_png) >> 8;
             *pp++ = PNM_GET1(p_png) & 0xff;
-        } else if (info_ptr->color_type == PNG_COLOR_TYPE_PALETTE) {
+        } else if (pngx_colorType(pngxP) == PNG_COLOR_TYPE_PALETTE) {
             unsigned int paletteIndex;
             if (alpha)
                 paletteIndex = lookupColorAlpha(caht, &p, &alpha_mask[col]);
             else
                 paletteIndex = ppm_lookupcolor(cht, &p);
             *pp++ = paletteIndex;
-        } else if (info_ptr->color_type == PNG_COLOR_TYPE_RGB ||
-                   info_ptr->color_type == PNG_COLOR_TYPE_RGB_ALPHA) {
+        } else if (pngx_colorType(pngxP) == PNG_COLOR_TYPE_RGB ||
+                   pngx_colorType(pngxP) == PNG_COLOR_TYPE_RGB_ALPHA) {
             if (depth == 16)
                 *pp++ = PPM_GETR(p_png) >> 8;
             *pp++ = PPM_GETR(p_png) & 0xff;
@@ -2169,7 +2319,7 @@ makePngLine(png_byte *           const line,
         } else
             pm_error("INTERNAL ERROR: undefined color_type");
                 
-        if (info_ptr->color_type & PNG_COLOR_MASK_ALPHA) {
+        if (pngx_colorType(pngxP) & PNG_COLOR_MASK_ALPHA) {
             int const png_alphaval = (int)
                 alpha_mask[col] * (float) png_maxval / maxval + 0.5;
             if (depth == 16)
@@ -2182,8 +2332,7 @@ makePngLine(png_byte *           const line,
 
 
 static void
-writeRaster(png_struct *         const png_ptr,
-            png_info *           const info_ptr,
+writeRaster(struct pngx *        const pngxP,
             FILE *               const ifP,
             pm_filepos           const rasterPos,
             unsigned int         const cols,
@@ -2191,14 +2340,14 @@ writeRaster(png_struct *         const png_ptr,
             xelval               const maxval,
             int                  const format,
             xelval               const png_maxval,
-            unsigned             const int depth,
+            unsigned int         const depth,
             bool                 const alpha,
             gray **              const alpha_mask,
             colorhash_table      const cht,
             coloralphahash_table const caht
             ) {
 /*----------------------------------------------------------------------------
-   Write the PNG raster via compressor *png_ptr, reading the PNM raster
+   Write the PNG raster via compressor *pngxP, reading the PNM raster
    from file *ifP, position 'rasterPos'.
 
    The PNG raster consists of IDAT chunks.
@@ -2216,7 +2365,7 @@ writeRaster(png_struct *         const png_ptr,
     if (line == NULL)
         pm_error("out of memory allocating PNG row buffer");
 
-    for (pass = 0; pass < png_set_interlace_handling(png_ptr); ++pass) {
+    for (pass = 0; pass < pngxP->numPassesRequired; ++pass) {
         unsigned int row;
         pm_seek2(ifP, &rasterPos, sizeof(rasterPos));
         for (row = 0; row < rows; ++row) {
@@ -2226,9 +2375,9 @@ writeRaster(png_struct *         const png_ptr,
             
             makePngLine(line, xelrow, cols, maxval,
                         alpha, alpha ? alpha_mask[row] : NULL,
-                        cht, caht, info_ptr, png_maxval, depth);
+                        cht, caht, pngxP, png_maxval, depth);
 
-            png_write_row(png_ptr, line);
+            pngx_writeRow(pngxP, line);
         }
     }
     pnm_freerow(xelrow);
@@ -2237,78 +2386,243 @@ writeRaster(png_struct *         const png_ptr,
 
 
 static void
-doGamaChunk(struct cmdlineInfo const cmdline,
-            png_info *         const info_ptr) {
+doHistChunk(struct pngx * const pngxP,
+            bool          const histRequested,
+            pixel         const palettePnm[],
+            FILE *        const ifP,
+            pm_filepos    const rasterPos,
+            unsigned int  const cols,
+            unsigned int  const rows,
+            xelval        const maxval,
+            int           const format,
+            bool          const verbose) {
+
+    if (histRequested) {
+        colorhist_vector chv;
+        unsigned int colorCt;
+        colorhash_table cht;
+        
+        getChv(ifP, rasterPos, cols, rows, maxval, format, MAXCOLORS, 
+               &chv, &colorCt);
+
+        cht = ppm_colorhisttocolorhash(chv, colorCt);
+                
+        { 
+            png_uint_16 * histogram;  /* malloc'ed */
+        
+            MALLOCARRAY(histogram, MAXCOLORS);
+
+            if (!histogram)
+                pm_error("Failed to allocate memory for %u-color histogram",
+                         MAXCOLORS);
+            else {
+                unsigned int i;
+                for (i = 0 ; i < MAXCOLORS; ++i) {
+                    int const chvIndex = ppm_lookupcolor(cht, &palettePnm[i]);
+                    if (chvIndex == -1)
+                        histogram[i] = 0;
+                    else
+                        histogram[i] = chv[chvIndex].value;
+                }
             
-    if (cmdline.gammaSpec) {
-        /* gAMA chunk */
-        info_ptr->valid |= PNG_INFO_gAMA;
-        info_ptr->gamma = cmdline.gamma;
+                pngx_setHist(pngxP, histogram);
+
+                if (verbose)
+                    pm_message("histogram created in PNG stream");
+            }
+        }
+        ppm_freecolorhash(cht);
     }
 }
 
 
 
 static void
+doIhdrChunk(struct pngx * const pngxP,
+            unsigned int  const width,
+            unsigned int  const height,
+            unsigned int  const depth,
+            bool          const colorMapped,
+            bool          const colorPng,
+            bool          const alpha,
+            bool          const interlace) {
+
+    int const interlaceMethod =
+        interlace ? PNG_INTERLACE_ADAM7 : PNG_INTERLACE_NONE;
+
+    int colorType;
+
+    if (colorMapped)
+        colorType = PNG_COLOR_TYPE_PALETTE;
+    else if (colorPng)
+        colorType = PNG_COLOR_TYPE_RGB;
+    else
+        colorType = PNG_COLOR_TYPE_GRAY;
+
+    if (alpha && colorType != PNG_COLOR_TYPE_PALETTE)
+        colorType |= PNG_COLOR_MASK_ALPHA;
+
+    pngx_setIhdr(pngxP, width, height, depth, colorType,
+                 interlaceMethod, 0, 0);
+}
+
+
+
+static void
+doGamaChunk(struct cmdlineInfo const cmdline,
+            struct pngx *      const pngxP) {
+            
+    if (cmdline.gammaSpec)
+        pngx_setGama(pngxP, cmdline.gamma);
+}
+
+
+
+static void
 doChrmChunk(struct cmdlineInfo const cmdline,
-            png_info *         const info_ptr) {
-
-    if (cmdline.rgbSpec) {
-        /* cHRM chunk */
-        info_ptr->valid |= PNG_INFO_cHRM;
-
-        info_ptr->x_white = cmdline.rgb.wx;
-        info_ptr->y_white = cmdline.rgb.wy;
-        info_ptr->x_red   = cmdline.rgb.rx;
-        info_ptr->y_red   = cmdline.rgb.ry;
-        info_ptr->x_green = cmdline.rgb.gx;
-        info_ptr->y_green = cmdline.rgb.gy;
-        info_ptr->x_blue  = cmdline.rgb.bx;
-        info_ptr->y_blue  = cmdline.rgb.by;
-    }
+            struct pngx *      const pngxP) {
+
+    if (cmdline.rgbSpec)
+        pngx_setChrm(pngxP, cmdline.rgb);
 }
 
 
 
 static void
 doPhysChunk(struct cmdlineInfo const cmdline,
-            png_info *         const info_ptr) {
+            struct pngx *      const pngxP) {
+
+    if (cmdline.sizeSpec)
+        pngx_setPhys(pngxP, cmdline.size);
+}
+
+
+
+static void
+doTimeChunk(struct cmdlineInfo const cmdline,
+            struct pngx *      const pngxP) {
+
+    if (cmdline.modtimeSpec)
+        pngx_setTime(pngxP, cmdline.modtime);
+}
+
+
 
-    if (cmdline.sizeSpec) {
-        /* pHYS chunk */
-        info_ptr->valid |= PNG_INFO_pHYs;
+static void
+reportFilterSet(int const filterSet) {
+
+    pm_message("Limiting filter to: %s%s%s%s%s",
+               (filterSet & PNG_FILTER_NONE)  ? "NONE "  : "",
+               (filterSet & PNG_FILTER_SUB)   ? "SUB "   : "",
+               (filterSet & PNG_FILTER_UP)    ? "UP "    : "",
+               (filterSet & PNG_FILTER_AVG)   ? "AVG "   : "",
+               (filterSet & PNG_FILTER_PAETH) ? "PAETH " : "");
+}
+
+
+
+static void
+doFilters(struct cmdlineInfo const cmdline,
+          struct pngx *      const pngxP) {
 
-        info_ptr->x_pixels_per_unit = cmdline.size.x;
-        info_ptr->y_pixels_per_unit = cmdline.size.y;
-        info_ptr->phys_unit_type    = cmdline.size.unit;
+    if (cmdline.filterSetSpec) {
+        if (verbose)
+            reportFilterSet(cmdline.filterSet);
+        pngx_setFilter(pngxP, cmdline.filterSet);
     }
 }
 
 
 
+static void
+reportTrans(struct pngx * const pngxP) {
+
+    if (pngx_chunkIsPresent(pngxP, PNG_INFO_tRNS)) {
+        struct pngx_trns const transInfo = pngx_trns(pngxP);
+
+        pm_message("%u transparency values", transInfo.numTrans);
+        
+        pm_message("Transparent color {gray, red, green, blue} = "
+                   "{%d, %d, %d, %d}",
+                   transInfo.transColor.gray,
+                   transInfo.transColor.red,
+                   transInfo.transColor.green,
+                   transInfo.transColor.blue);
+    } else
+        pm_message("No transparent color");
+}
+
 
 static void
-doTimeChunk(struct cmdlineInfo const cmdline,
-            png_info *         const info_ptr) {
+doTrnsChunk(struct pngx * const pngxP,
+            png_byte      const transPalette[],
+            unsigned int  const transPaletteSize,
+            int           const transparent,
+            pixel         const transColor,
+            xelval        const maxval,
+            xelval        const pngMaxval) {
+
+    switch (pngx_colorType(pngxP)) {
+    case PNG_COLOR_TYPE_PALETTE:
+        if (transPaletteSize > 0)
+            pngx_setTrnsPalette(pngxP, transPalette,
+                                transPaletteSize /* omit opaque values */);
+        break;
+    case PNG_COLOR_TYPE_GRAY:
+    case PNG_COLOR_TYPE_RGB:
+        if (transparent > 0)
+            pngx_setTrnsValue(pngxP,
+                              xelToPngColor_16(transColor, maxval, pngMaxval));
+        break;
+    default:
+        /* This is PNG_COLOR_MASK_ALPHA.  Transparency will be handled
+           by the alpha channel, not a transparency color.
+        */
+    {}
+    }
+    if (verbose)
+        reportTrans(pngxP);
+}
 
-    if (cmdline.modtimeSpec) {
-        /* tIME chunk */
-        info_ptr->valid |= PNG_INFO_tIME;
 
-        png_convert_from_time_t(&info_ptr->mod_time, cmdline.modtime);
+
+static void
+doBkgdChunk(struct pngx * const pngxP,
+            bool          const bkgdRequested,
+            unsigned int  const backgroundIndex,
+            pixel         const backColor,
+            xelval        const maxval,
+            xelval        const pngMaxval,
+            bool          const verbose) {
+    
+    if (bkgdRequested) {
+        if (pngx_colorType(pngxP) == PNG_COLOR_TYPE_PALETTE)
+            pngx_setBkgdPalette(pngxP, backgroundIndex);
+        else {
+            png_color_16 const pngBackground = 
+                xelToPngColor_16(backColor, maxval, pngMaxval);
+            pngx_setBkgdRgb(pngxP, pngBackground);
+            if (verbose)
+                pm_message("Writing bKGD chunk with background color "
+                           " {gray, red, green, blue} = {%d, %d, %d, %d}",
+                           pngBackground.gray, 
+                           pngBackground.red, 
+                           pngBackground.green, 
+                           pngBackground.blue ); 
+        }
     }
 }
 
 
 
 static void
-doSbitChunk(png_info * const pngInfoP,
-            xelval     const pngMaxval,
-            xelval     const maxval,
-            bool       const alpha,
-            xelval     const alphaMaxval) {
+doSbitChunk(struct pngx * const pngxP,
+            xelval        const pngMaxval,
+            xelval        const maxval,
+            bool          const alpha,
+            xelval        const alphaMaxval) {
 
-    if (pngInfoP->color_type != PNG_COLOR_TYPE_PALETTE &&
+    if (pngx_colorType(pngxP) != PNG_COLOR_TYPE_PALETTE &&
         (pngMaxval > maxval || (alpha && pngMaxval > alphaMaxval))) {
 
         /* We're writing in a bit depth that doesn't match the maxval
@@ -2327,38 +2641,55 @@ doSbitChunk(png_info * const pngInfoP,
            sBIT chunk.
         */
 
-        pngInfoP->valid |= PNG_INFO_sBIT;
-
         {
             int const sbitval = pm_maxvaltobits(MIN(maxval, pngMaxval));
 
-            if (pngInfoP->color_type & PNG_COLOR_MASK_COLOR) {
-                pngInfoP->sig_bit.red   = sbitval;
-                pngInfoP->sig_bit.green = sbitval;
-                pngInfoP->sig_bit.blue  = sbitval;
+            png_color_8 sbit;
+
+            if (pngx_colorType(pngxP) & PNG_COLOR_MASK_COLOR) {
+                sbit.red   = sbitval;
+                sbit.green = sbitval;
+                sbit.blue  = sbitval;
             } else
-                pngInfoP->sig_bit.gray = sbitval;
+                sbit.gray  = sbitval;
             
             if (verbose)
                 pm_message("Writing sBIT chunk with bits = %d", sbitval);
-        }
-        if (pngInfoP->color_type & PNG_COLOR_MASK_ALPHA) {
-            pngInfoP->sig_bit.alpha =
-                pm_maxvaltobits(MIN(alphaMaxval, pngMaxval));
-            if (verbose)
-                pm_message("  alpha bits = %d", pngInfoP->sig_bit.alpha);
+
+            if (pngx_colorType(pngxP) & PNG_COLOR_MASK_ALPHA) {
+                sbit.alpha = pm_maxvaltobits(MIN(alphaMaxval, pngMaxval));
+                if (verbose)
+                    pm_message("  alpha bits = %d", sbit.alpha);
+            }
+
+            pngx_setSbit(pngxP, sbit);
         }
     }
 }
 
 
 
+static void
+addSrgbChunk(struct pngx *   const pngxP,
+             pngx_srgbIntent const srgbIntent) {
+
+    pngx_setSrgb(pngxP, srgbIntent);
+
+    if (verbose) {
+        pm_message("writing sRGB chunk with intent value %s",
+                   pngx_srgbIntentDesc(srgbIntent));
+    }
+}
+
+
+
 static void 
 convertpnm(struct cmdlineInfo const cmdline,
-           FILE *             const ifp,
-           FILE *             const afp,
-           FILE *             const pfp,
-           FILE *             const tfp,
+           FILE *             const ifP,
+           FILE *             const ofP,
+           FILE *             const afP,
+           FILE *             const pfP,
+           FILE *             const tfP,
            int *              const errorLevelP
     ) {
 /*----------------------------------------------------------------------------
@@ -2367,442 +2698,237 @@ convertpnm(struct cmdlineInfo const cmdline,
    lazy -- it takes a great deal of work to carry all that information as
    separate arguments -- and it's only a very small violation.
 -----------------------------------------------------------------------------*/
-  xel p;
-  int rows, cols, format;
-  xelval maxval;
-      /* The maxval of the input image */
-  xelval png_maxval;
-      /* The maxval of the samples in the PNG output 
-         (must be 1, 3, 7, 15, 255, or 65535)
-      */
-  pixel transcolor;
-      /* The color that is to be transparent, with maxval equal to that
-         of the input image.
-      */
-  int transexact;  
-      /* boolean: the user wants only the exact color he specified to be
-         transparent; not just something close to it.
-      */
-  int transparent;
-  bool alpha;
-      /* There will be an alpha mask */
-  unsigned int pnm_meaningful_bits;
-  pixel backcolor;
-      /* The background color, with maxval equal to that of the input
-         image.
-      */
-  png_struct *png_ptr;
-  png_info *info_ptr;
-
-  bool colorMapped;
-  pixel palette_pnm[MAXCOLORS];
-  png_color palette[MAXCOLORS];
-      /* The color part of the color/alpha palette passed to the PNG
-         compressor 
-      */
-  unsigned int palette_size;
-
-  gray trans_pnm[MAXCOLORS];
-  png_byte  trans[MAXCOLORS];
-      /* The alpha part of the color/alpha palette passed to the PNG
-         compressor 
-      */
-  unsigned int trans_size;
-
-  colorhash_table cht;
-  coloralphahash_table caht;
-
-  unsigned int background_index;
-      /* Index into palette[] of the background color. */
-
-  png_uint_16 histogram[MAXCOLORS];
-  gray alpha_maxval;
-  int alpha_rows;
-  int alpha_cols;
-  const char * noColormapReason;
-      /* The reason that we shouldn't make a colormapped PNG, or NULL if
-         we should.  malloc'ed null-terminated string.
-      */
-  unsigned int depth;
-      /* The number of bits per sample in the (uncompressed) png 
-         raster -- if the raster contains palette indices, this is the
-         number of bits in the index.
-      */
-  unsigned int fulldepth;
-      /* The total number of bits per pixel in the (uncompressed) png
-         raster, including all channels.
-      */
-  pm_filepos rasterPos;  
-      /* file position in input image file of start of image (i.e. after
-         the header)
-      */
-  xel *xelrow;    /* malloc'ed */
-      /* The row of the input image currently being processed */
-
-  int pnm_type;
-  xelval maxmaxval;
-  gray ** alpha_mask;
-
-  /* these guys are initialized to quiet compiler warnings: */
-  maxmaxval = 255;
-  alpha_mask = NULL;
-  depth = 0;
-  errorlevel = 0;
-
-  png_ptr = png_create_write_struct (PNG_LIBPNG_VER_STRING,
-    &pnmtopng_jmpbuf_struct, pnmtopng_error_handler, NULL);
-  if (png_ptr == NULL) {
-    pm_closer (ifp);
-    pm_error ("cannot allocate main libpng structure (png_ptr)");
-  }
-
-  info_ptr = png_create_info_struct (png_ptr);
-  if (info_ptr == NULL) {
-    png_destroy_write_struct (&png_ptr, (png_infopp)NULL);
-    pm_closer (ifp);
-    pm_error ("cannot allocate libpng info structure (info_ptr)");
-  }
-
-  if (setjmp (pnmtopng_jmpbuf_struct.jmpbuf)) {
-    png_destroy_write_struct (&png_ptr, &info_ptr);
-    pm_closer (ifp);
-    pm_error ("setjmp returns error condition (1)");
-  }
-
-  pnm_readpnminit (ifp, &cols, &rows, &maxval, &format);
-  pm_tell2(ifp, &rasterPos, sizeof(rasterPos));
-  pnm_type = PNM_FORMAT_TYPE (format);
-
-  xelrow = pnm_allocrow(cols);
-
-  if (verbose) {
-    if (pnm_type == PBM_TYPE)    
-      pm_message ("reading a PBM file (maxval=%d)", maxval);
-    else if (pnm_type == PGM_TYPE)    
-      pm_message ("reading a PGM file (maxval=%d)", maxval);
-    else if (pnm_type == PPM_TYPE)    
-      pm_message ("reading a PPM file (maxval=%d)", maxval);
-  }
-
-  if (pnm_type == PGM_TYPE)
-    maxmaxval = PGM_OVERALLMAXVAL;
-  else if (pnm_type == PPM_TYPE)
-    maxmaxval = PPM_OVERALLMAXVAL;
-
-  if (cmdline.transparent) {
-      const char * transstring2;  
-          /* The -transparent value, but with possible leading '=' removed */
-      if (cmdline.transparent[0] == '=') {
-          transexact = 1;
-          transstring2 = &cmdline.transparent[1];
-      } else {
-          transexact = 0;
-          transstring2 = cmdline.transparent;
-      }  
-      /* We do this funny PPM_DEPTH thing instead of just passing 'maxval'
-         to ppm_parsecolor() because ppm_parsecolor() does a cheap maxval
-         scaling, and this is more precise.
-      */
-      PPM_DEPTH(transcolor, ppm_parsecolor(transstring2, maxmaxval),
-                maxmaxval, maxval);
-  }
-  if (cmdline.alpha) {
-    pixel alpha_transcolor;
-    bool alpha_can_be_transparency_index;
-    bool all_opaque;
+    int rows, cols, format;
+    xelval maxval;
+    /* The maxval of the input image */
+    xelval pngMaxval;
+        /* The maxval of the samples in the PNG output 
+           (must be 1, 3, 7, 15, 255, or 65535)
+        */
+    pixel transcolor;
+        /* The color that is to be transparent, with maxval equal to that
+           of the input image.
+        */
+    bool transExact;  
+        /* boolean: the user wants only the exact color he specified to be
+           transparent; not just something close to it.
+        */
+    int transparent;
+    bool alpha;
+        /* There will be an alpha mask */
+    unsigned int pnmMeaningfulBitCt;
+    pixel backColor;
+        /* The background color, with maxval equal to that of the input
+           image.
+        */
+    jmp_buf jmpbuf;
+    struct pngx * pngxP;
+
+    bool colorMapped;
+    pixel palettePnm[MAXCOLORS];
+    png_color palette[MAXCOLORS];
+        /* The color part of the color/alpha palette passed to the PNG
+           compressor 
+        */
+    unsigned int paletteSize;
+
+    gray transPnm[MAXCOLORS];
+    png_byte  trans[MAXCOLORS];
+        /* The alpha part of the color/alpha palette passed to the PNG
+           compressor 
+        */
+    unsigned int transSize;
+
+    colorhash_table cht;
+    coloralphahash_table caht;
+
+    unsigned int backgroundIndex;
+        /* Index into palette[] of the background color. */
+
+    gray alphaMaxval;
+    const char * noColormapReason;
+        /* The reason that we shouldn't make a colormapped PNG, or NULL if
+           we should.  malloc'ed null-terminated string.
+        */
+    unsigned int depth;
+        /* The number of bits per sample in the (uncompressed) png 
+           raster -- if the raster contains palette indices, this is the
+           number of bits in the index.
+        */
+    unsigned int fulldepth;
+        /* The total number of bits per pixel in the (uncompressed) png
+           raster, including all channels.
+        */
+    pm_filepos rasterPos;  
+        /* file position in input image file of start of image (i.e. after
+           the header)
+        */
+    xel * xelrow;    /* malloc'ed */
+        /* The row of the input image currently being processed */
+
+    gray ** alpha_mask;
+
+    bool colorPng;
+        /* The PNG shall be of the color (RGB) variety */
+
+    /* We initialize these guys to quiet compiler warnings: */
+    depth = 0;
+
+    errorlevel = 0;
+
+    if (setjmp(jmpbuf))
+        pm_error ("setjmp returns error condition");
+
+    pngx_create(&pngxP, PNGX_WRITE, &jmpbuf);
+
+    pnm_readpnminit(ifP, &cols, &rows, &maxval, &format);
+    pm_tell2(ifP, &rasterPos, sizeof(rasterPos));
+
+    xelrow = pnm_allocrow(cols);
 
     if (verbose)
-      pm_message ("reading alpha-channel image...");
-    alpha_mask = pgm_readpgm (afp, &alpha_cols, &alpha_rows, &alpha_maxval);
+        reportInputType(format, maxval);
+
+    determineTransparency(cmdline, ifP, rasterPos, cols, rows, maxval, format,
+                          afP,
+                          &alpha, &transparent, &transcolor, &transExact,
+                          &alpha_mask, &alphaMaxval);
 
-    if (alpha_cols != cols || alpha_rows != rows) {
-      png_destroy_write_struct (&png_ptr, &info_ptr);
-      pm_closer (ifp);
-      pm_error ("dimensions for image and alpha mask do not agree");
+    determineBackground(cmdline, maxval, &backColor);
+
+    if (cmdline.force)
+        colorPng = (PNM_FORMAT_TYPE(format) == PPM_TYPE);
+    else {
+        if (PNM_FORMAT_TYPE(format) == PPM_TYPE) {
+            colorPng = hasColor(ifP, cols, rows, maxval, format, rasterPos); 
+        } else
+            colorPng = false;
     }
-    analyzeAlpha(ifp, rasterPos, cols, rows, maxval, format, 
-                 alpha_mask, alpha_maxval, &all_opaque,
-                 &alpha_can_be_transparency_index, &alpha_transcolor);
-
-    if (alpha_can_be_transparency_index && !cmdline.force) {
-      if (verbose)
-        pm_message ("converting alpha mask to transparency index");
-      alpha = FALSE;
-      transparent = 2;
-      transcolor = alpha_transcolor;
-    } else if (all_opaque) {
-        alpha = FALSE;
-        transparent = -1;
-    } else {
-      alpha = TRUE;
-      transparent = -1;
+
+
+    /* handle `odd' maxvalues */
+
+    if (maxval > 65535 && !cmdline.downscale) {
+        pm_error("can only handle files up to 16-bit "
+                 "(use -downscale to override");
     }
-  } else {
-      /* Though there's no alpha_mask, we still need an alpha_maxval for
-         use with trans[], which can have stuff in it if the user specified
-         a transparent color.
-      */
-      alpha = FALSE;
-      alpha_maxval = 255;
-      transparent = cmdline.transparent ? 1 : -1;
-  }
-  if (cmdline.background) 
-      PPM_DEPTH(backcolor, ppm_parsecolor(cmdline.background, maxmaxval), 
-                maxmaxval, maxval);;
-
-  /* first of all, check if we have a grayscale image written as PPM */
-
-  if (pnm_type == PPM_TYPE && !cmdline.force) {
-      unsigned int row;
-      bool isgray;
-
-      isgray = TRUE;  /* initial assumption */
-      pm_seek2(ifp, &rasterPos, sizeof(rasterPos));
-      for (row = 0; row < rows && isgray; ++row) {
-          unsigned int col;
-          pnm_readpnmrow(ifp, xelrow, cols, maxval, format);
-          for (col = 0; col < cols && isgray; ++col) {
-              p = xelrow[col];
-              if (PPM_GETR(p) != PPM_GETG(p) || PPM_GETG(p) != PPM_GETB(p))
-                  isgray = FALSE;
-          }
-      }
-      if (isgray)
-          pnm_type = PGM_TYPE;
-  }
-
-  /* handle `odd' maxvalues */
-
-  if (maxval > 65535 && !cmdline.downscale) {
-      png_destroy_write_struct(&png_ptr, &info_ptr);
-      pm_closer(ifp);
-      pm_error("can only handle files up to 16-bit "
-               "(use -downscale to override");
-  }
-
-  findRedundantBits(ifp, rasterPos, cols, rows, maxval, format, alpha,
-                    cmdline.force, &pnm_meaningful_bits);
+
+    findRedundantBits(ifP, rasterPos, cols, rows, maxval, format, alpha,
+                      cmdline.force, &pnmMeaningfulBitCt);
   
-  computeColorMap(ifp, rasterPos, cols, rows, maxval, pnm_type, format,
-                  cmdline.force, pfp,
-                  alpha, transparent >= 0, transcolor, transexact, 
-                  !!cmdline.background, backcolor,
-                  alpha_mask, alpha_maxval, pnm_meaningful_bits,
-                  palette_pnm, &palette_size, trans_pnm, &trans_size,
-                  &background_index, &noColormapReason);
-
-  if (noColormapReason) {
-      if (pfp)
-          pm_error("You specified a particular palette, but this image "
-                   "cannot be represented by any palette.  %s",
-                   noColormapReason);
-      if (verbose)
-          pm_message("Not using color map.  %s", noColormapReason);
-      strfree(noColormapReason);
-      colorMapped = FALSE;
-  } else
-      colorMapped = TRUE;
+    computeColorMap(ifP, rasterPos, cols, rows, maxval, colorPng, format,
+                    cmdline.force, pfP,
+                    alpha, transparent >= 0, transcolor, transExact, 
+                    !!cmdline.background, backColor,
+                    alpha_mask, alphaMaxval, pnmMeaningfulBitCt,
+                    palettePnm, &paletteSize, transPnm, &transSize,
+                    &backgroundIndex, &noColormapReason);
+
+    if (noColormapReason) {
+        if (pfP)
+            pm_error("You specified a particular palette, but this image "
+                     "cannot be represented by any palette.  %s",
+                     noColormapReason);
+        if (verbose)
+            pm_message("Not using color map.  %s", noColormapReason);
+        pm_strfree(noColormapReason);
+        colorMapped = FALSE;
+    } else
+        colorMapped = TRUE;
   
-  computeColorMapLookupTable(colorMapped, palette_pnm, palette_size,
-                             trans_pnm, trans_size, alpha, alpha_maxval,
-                             &cht, &caht);
-
-  computeRasterWidth(colorMapped, palette_size, pnm_type, 
-                     pnm_meaningful_bits, alpha,
-                     &depth, &fulldepth);
-  if (verbose)
-    pm_message ("writing a%s %d-bit %s%s file%s",
-                fulldepth == 8 ? "n" : "", fulldepth,
-                colorMapped ? "palette": 
-                (pnm_type == PPM_TYPE ? "RGB" : "gray"),
-                alpha ? (colorMapped ? "+transparency" : "+alpha") : "",
-                cmdline.interlace ? " (interlaced)" : "");
-
-  /* now write the file */
-
-  png_maxval = pm_bitstomaxval(depth);
-
-  if (setjmp (pnmtopng_jmpbuf_struct.jmpbuf)) {
-    png_destroy_write_struct (&png_ptr, &info_ptr);
-    pm_closer (ifp);
-    pm_error ("setjmp returns error condition (2)");
-  }
-
-  png_init_io (png_ptr, stdout);
-  info_ptr->width = cols;
-  info_ptr->height = rows;
-  info_ptr->bit_depth = depth;
-
-  if (colorMapped)
-    info_ptr->color_type = PNG_COLOR_TYPE_PALETTE;
-  else if (pnm_type == PPM_TYPE)
-    info_ptr->color_type = PNG_COLOR_TYPE_RGB;
-  else
-    info_ptr->color_type = PNG_COLOR_TYPE_GRAY;
-
-  if (alpha && info_ptr->color_type != PNG_COLOR_TYPE_PALETTE)
-    info_ptr->color_type |= PNG_COLOR_MASK_ALPHA;
-
-  info_ptr->interlace_type = cmdline.interlace;
-
-  doGamaChunk(cmdline, info_ptr);
-
-  doChrmChunk(cmdline, info_ptr);
-
-  doPhysChunk(cmdline, info_ptr);
-
-  if (info_ptr->color_type == PNG_COLOR_TYPE_PALETTE) {
-
-    /* creating PNG palette  (PLTE and tRNS chunks) */
-
-    createPngPalette(palette_pnm, palette_size, maxval,
-                     trans_pnm, trans_size, alpha_maxval, 
-                     palette, trans);
-    info_ptr->valid |= PNG_INFO_PLTE;
-    info_ptr->palette = palette;
-    info_ptr->num_palette = palette_size;
-    if (trans_size > 0) {
-        info_ptr->valid |= PNG_INFO_tRNS;
-        info_ptr->TRANS_ALPHA = trans;
-        info_ptr->num_trans = trans_size;   /* omit opaque values */
-    }
-    /* creating hIST chunk */
-    if (cmdline.hist) {
-        colorhist_vector chv;
-        unsigned int colors;
-        colorhash_table cht;
-        
-        getChv(ifp, rasterPos, cols, rows, maxval, format, MAXCOLORS, 
-               &chv, &colors);
+    computeColorMapLookupTable(colorMapped, palettePnm, paletteSize,
+                               transPnm, transSize, alpha, alphaMaxval,
+                               &cht, &caht);
 
-        cht = ppm_colorhisttocolorhash (chv, colors);
-                
-        { 
-            unsigned int i;
-            for (i = 0 ; i < MAXCOLORS; ++i) {
-                int const chvIndex = ppm_lookupcolor(cht, &palette_pnm[i]);
-                if (chvIndex == -1)
-                    histogram[i] = 0;
-                else
-                    histogram[i] = chv[chvIndex].value;
-            }
-        }
+    computeRasterWidth(colorMapped, paletteSize, colorPng,
+                       pnmMeaningfulBitCt, alpha,
+                       &depth, &fulldepth);
+    if (verbose)
+        pm_message ("writing a%s %d-bit %s%s file%s",
+                    fulldepth == 8 ? "n" : "", fulldepth,
+                    colorMapped ? "palette": 
+                    colorPng ? "RGB" : "gray",
+                    alpha ? (colorMapped ? "+transparency" : "+alpha") : "",
+                    cmdline.interlace ? " (interlaced)" : "");
 
-        ppm_freecolorhash(cht);
+    /* now write the file */
 
-        info_ptr->valid |= PNG_INFO_hIST;
-        info_ptr->hist = histogram;
-        if (verbose)
-            pm_message("histogram created");
-    }
-  } else { /* color_type != PNG_COLOR_TYPE_PALETTE */
-    if (info_ptr->color_type == PNG_COLOR_TYPE_GRAY ||
-        info_ptr->color_type == PNG_COLOR_TYPE_RGB) {
-        if (transparent > 0) {
-            info_ptr->valid |= PNG_INFO_tRNS;
-            info_ptr->trans_values = 
-                xelToPngColor_16(transcolor, maxval, png_maxval);
-        }
-    } else {
-        /* This is PNG_COLOR_MASK_ALPHA.  Transparency will be handled
-           by the alpha channel, not a transparency color.
-        */
+    pngMaxval = pm_bitstomaxval(depth);
+
+    if (setjmp (pnmtopng_jmpbuf_struct.jmpbuf)) {
+        pm_error ("setjmp returns error condition (2)");
     }
-    if (verbose) {
-        if (info_ptr->valid && PNG_INFO_tRNS) 
-            pm_message("Transparent color {gray, red, green, blue} = "
-                       "{%d, %d, %d, %d}",
-                       info_ptr->trans_values.gray,
-                       info_ptr->trans_values.red,
-                       info_ptr->trans_values.green,
-                       info_ptr->trans_values.blue);
-        else
-            pm_message("No transparent color");
+
+    doIhdrChunk(pngxP, cols, rows, depth, colorMapped, colorPng, alpha,
+                cmdline.interlace);
+
+    doGamaChunk(cmdline, pngxP);
+
+    doChrmChunk(cmdline, pngxP);
+
+    doPhysChunk(cmdline, pngxP);
+
+    if (pngx_colorType(pngxP) == PNG_COLOR_TYPE_PALETTE) {
+
+        /* creating PNG palette (Not counting the transparency palette) */
+
+        createPngPalette(palettePnm, paletteSize, maxval,
+                         transPnm, transSize, alphaMaxval, 
+                         palette, trans);
+        pngx_setPlte(pngxP, palette, paletteSize);
+
+        doHistChunk(pngxP, cmdline.hist, palettePnm, ifP, rasterPos,
+                    cols, rows, maxval, format, cmdline.verbose);
     }
-  }
-
-  /* bKGD chunk */
-  if (cmdline.background) {
-      info_ptr->valid |= PNG_INFO_bKGD;
-      if (info_ptr->color_type == PNG_COLOR_TYPE_PALETTE) {
-          info_ptr->background.index = background_index;
-      } else {
-          info_ptr->background = 
-              xelToPngColor_16(backcolor, maxval, png_maxval);
-          if (verbose)
-              pm_message("Writing bKGD chunk with background color "
-                         " {gray, red, green, blue} = {%d, %d, %d, %d}",
-                         info_ptr->background.gray, 
-                         info_ptr->background.red, 
-                         info_ptr->background.green, 
-                         info_ptr->background.blue ); 
-      }
-  }
-
-  doSbitChunk(info_ptr, png_maxval, maxval, alpha, alpha_maxval);
-
-  /* tEXT and zTXT chunks */
-  if (cmdline.text || cmdline.ztxt)
-      pnmpng_read_text(info_ptr, tfp, !!cmdline.ztxt, cmdline.verbose);
-
-  doTimeChunk(cmdline, info_ptr);
-
-  if (cmdline.filterSetSpec)
-      png_set_filter(png_ptr, 0, cmdline.filterSet);
-
-  if (cmdline.filterSet != 0)
-      png_set_filter(png_ptr, 0, cmdline.filterSet);
-
-  setZlibCompression(png_ptr, cmdline.zlibCompression);
-
-  /* write the png-info struct */
-  png_write_info(png_ptr, info_ptr);
-
-  if (cmdline.text || cmdline.ztxt)
-      /* prevent from being written twice with png_write_end */
-      info_ptr->num_text = 0;
-
-  if (cmdline.modtime)
-      /* prevent from being written twice with png_write_end */
-      info_ptr->valid &= ~PNG_INFO_tIME;
-
-  /* let libpng take care of, e.g., bit-depth conversions */
-  png_set_packing (png_ptr);
-
-  writeRaster(png_ptr, info_ptr, ifp, rasterPos, cols, rows, maxval, format,
-              png_maxval, depth, alpha, alpha_mask, cht, caht);
-
-  png_write_end (png_ptr, info_ptr);
-
-
-#if 0
-  /* The following code may be intended to solve some segfault problem
-     that arises with png_destroy_write_struct().  The latter is the
-     method recommended in the libpng documentation and this program 
-     will not compile under Cygwin because the Windows DLL for libpng
-     does not contain png_write_destroy() at all.  Since the author's
-     comment below does not make it clear what the segfault issue is,
-     we cannot consider it.  -Bryan 00.09.15
-*/
 
-  png_write_destroy (png_ptr);
-  /* flush first because free(png_ptr) can segfault due to jmpbuf problems
-     in png_write_destroy */
-  fflush (stdout);
-  free (png_ptr);
-  free (info_ptr);
-#else
-  png_destroy_write_struct(&png_ptr, &info_ptr);
-#endif
+    doTrnsChunk(pngxP, trans, transSize,
+                transparent, transcolor, maxval, pngMaxval);
 
-  pnm_freerow(xelrow);
+    doBkgdChunk(pngxP, !!cmdline.background,
+                backgroundIndex, backColor,
+                maxval, pngMaxval, cmdline.verbose);
 
-  if (cht)
-      ppm_freecolorhash(cht);
-  if (caht)
-      freecoloralphahash(caht);
+    doSbitChunk(pngxP, pngMaxval, maxval, alpha, alphaMaxval);
+
+    if (cmdline.srgbintentSpec)
+        addSrgbChunk(pngxP, cmdline.srgbintent);
+
+    /* tEXT and zTXT chunks */
+    if (cmdline.text || cmdline.ztxt)
+        pngtxt_addChunk(pngxP, tfP, !!cmdline.ztxt, false, cmdline.verbose);
+
+    doTimeChunk(cmdline, pngxP);
+
+    doFilters(cmdline, pngxP);
+
+    setZlibCompression(pngxP, cmdline.zlibCompression);
+
+    png_init_io(pngxP->png_ptr, ofP);
+
+    /* write the png-info struct */
+    pngx_writeInfo(pngxP);
+
+    /* let libpng take care of, e.g., bit-depth conversions */
+    pngx_setPacking(pngxP);
+
+    pngx_setInterlaceHandling(pngxP);
+
+    writeRaster(pngxP, ifP, rasterPos,
+                cols, rows, maxval, format,
+                pngMaxval, depth, alpha, alpha_mask, cht, caht);
+
+    pngx_writeEnd(pngxP);
+
+    pngx_destroy(pngxP);
+
+    pnm_freerow(xelrow);
+
+    if (cht)
+        ppm_freecolorhash(cht);
+    if (caht)
+        freecoloralphahash(caht);
 
-  *errorLevelP = errorlevel;
+    *errorLevelP = errorlevel;
 }
 
 
@@ -2812,20 +2938,33 @@ displayVersion() {
 
     fprintf(stderr,"Pnmtopng version %s.\n", NETPBM_VERSION);
 
-    /* We'd like to display the version of libpng with which we're
-       linked, as we do for zlib, but it isn't practical.
-       While libpng is capable of telling you what it's level
-       is, different versions of it do it two different ways: with
-       png_libpng_ver or with png_get_header_ver.  So we have to be
-       compiled for a particular version just to find out what
-       version it is! It's not worth having a link failure, much
-       less a compile failure, if we choose wrong.
-       png_get_header_ver is not in anything older than libpng 1.0.2a
-       (Dec 1998).  png_libpng_ver is not there in libraries built
-       without USE_GLOBAL_ARRAYS.  Cygwin versions are normally built
-       without USE_GLOBAL_ARRAYS.  -bjh 2002.06.17.
+    /* We'd like to display the version of libpng with which we're _linked_ as
+       well as the one with which we're compiled, but it isn't practical.
+       While libpng is capable of telling you what it's level is, different
+       versions of it do it two different ways: with png_libpng_ver or with
+       png_get_header_ver.  So we have to be compiled for a particular version
+       just to find out what version it is! It's not worth having a link
+       failure, much less a compile failure, if we choose wrong.
+       png_get_header_ver is not in anything older than libpng 1.0.2a (Dec
+       1998).  png_libpng_ver is not there in libraries built without
+       USE_GLOBAL_ARRAYS.  Cygwin versions are normally built without
+       USE_GLOBAL_ARRAYS.  -bjh 2002.06.17.
+
+       We'd also like to display the version of libz with which we're linked,
+       with zlib_version (which nowadays is a macro for zlibVersion), but we
+       can't for reasons of modularity: We don't really link libz.  libpng
+       does.  It's none of our business whether libz is even present.  And at
+       least on Mac OS X, we can't access libz's symbols from here -- we get
+       undefined reference to zlibVersion.  We would have to explicitly link
+       libz just to find out its version.  The right way to do this is for a
+       subroutine in libpng to give us the information.  Until 10.07.08, we
+       did display zlib_version, but for years Mac OS X build was failing (and
+       we erroneously thought it was a libpng-config --ldflags bug).
+
+       We _do_ use the compile-time part of libpng (<png.h>), because it's
+       part of the interface to libpng.
     */
-    fprintf(stderr, "   Compiled with libpng %s.\n",
+    fprintf(stderr, "   Pnmtopng Compiled with libpng %s.\n",
             PNG_LIBPNG_VER_STRING);
     fprintf(stderr, "   Pnmtopng (not libpng) compiled with zlib %s.\n",
             ZLIB_VERSION);
@@ -2835,7 +2974,7 @@ displayVersion() {
 
 
 int 
-main(int argc, char *argv[]) {
+main(int argc, const char * argv[]) {
 
     struct cmdlineInfo cmdline;
     FILE * ifP;
@@ -2845,7 +2984,7 @@ main(int argc, char *argv[]) {
 
     int errorlevel;
     
-    pnm_init(&argc, argv);
+    pm_proginit(&argc, argv);
     
     parseCommandLine(argc, argv, &cmdline);
     
@@ -2855,7 +2994,7 @@ main(int argc, char *argv[]) {
     }
     verbose = cmdline.verbose;
     
-    ifP = pm_openr_seekable(cmdline.inputFilename);
+    ifP = pm_openr_seekable(cmdline.inputFileName);
     
     if (cmdline.alpha)
         afP = pm_openr(cmdline.alpha);
@@ -2874,7 +3013,7 @@ main(int argc, char *argv[]) {
     else
         tfP = NULL;
 
-    convertpnm(cmdline, ifP, afP, pfP, tfP, &errorlevel);
+    convertpnm(cmdline, ifP, stdout, afP, pfP, tfP, &errorlevel);
     
     if (afP)
         pm_close(afP);
diff --git a/converter/other/pnmtops.c b/converter/other/pnmtops.c
index 20395952..c1dadc3e 100644
--- a/converter/other/pnmtops.c
+++ b/converter/other/pnmtops.c
@@ -7,15 +7,19 @@
       1) Use built in Postscript filters /ASCII85Decode, /ASCIIHexDecode,
          /RunLengthDecode, and /FlateDecode;
 
-         We use methods we learned from Dirk Krause's program Bmeps and
-         raster encoding code copied almost directly from Bmeps.
+         We use methods we learned from Dirk Krause's program Bmeps.
+         Previous versions used raster encoding code based on Bmeps
+         code.  This program does not used any code from Bmeps.
 
       2) Use our own filters and redefine /readstring .  This is aboriginal
-         Netpbm code, from when Postscript was young.
+         Netpbm code, from when Postscript was young.  The filters are
+         nearly identical to /ASCIIHexDecode and /RunLengthDecode.  We
+         use the same raster encoding code with slight modifications.
 
-   (2) is the default, because it's been working for ages and we have
-   more confidence in it.  But (1) gives more options.  The user
-   selects (1) with the -psfilter option.
+   (2) is the default.  (1) gives more options, but relies on features
+   introduced in Postscript Level 2, which appeared in 1991.  Postcript
+   devices made before 1991 can't handle them.  The user selects (1)
+   with the -psfilter option.
 
    We also do a few other bold new things only when the user specifies
    -psfilter, because we're not sure they work for everyone.
@@ -31,23 +35,63 @@
 
 #define _BSD_SOURCE  /* Make sure string.h contains strdup() */
 #define _XOPEN_SOURCE 500  /* Make sure strdup() is in string.h */
-
-#include <string.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <unistd.h>
 #include <assert.h>
+#include <string.h>
+#include <errno.h>
+#include <signal.h>
+#ifndef NOFLATE
+#include <zlib.h>
+#endif
 
 #include "pm_c_util.h"
 #include "pam.h"
 #include "mallocvar.h"
 #include "shhopt.h"
 #include "nstring.h"
-#include "bmepsoe.h"
+#include "runlength.h"
+
+
+
+static void
+setSignals() {
+/*----------------------------------------------------------------------------
+   Set up the process-global signal-related state.
+
+   Note that we can't rely on defaults, because much of this is inherited
+   from the process that forked and exec'ed this program.
+-----------------------------------------------------------------------------*/
+    /* See waitForChildren() for why we do this to SIGCHLD */
+
+    struct sigaction sigchldAction;
+    int rc;
+    sigset_t emptySet;
+
+    sigemptyset(&emptySet);
+
+    sigchldAction.sa_handler = SIG_DFL;
+    sigchldAction.sa_mask = emptySet;
+    sigchldAction.sa_flags = SA_NOCLDSTOP;
+
+    rc = sigaction(SIGCHLD, &sigchldAction, NULL);
+
+    if (rc != 0)
+        pm_error("sigaction() to set up signal environment failed, "
+                 "errno = %d (%s)", errno, strerror(errno));
+}
+
+
 
 struct cmdlineInfo {
     /* All the information the user supplied in the command line,
        in a form easy for the program to use.
     */
     const char * inputFileName;  /* Filespecs of input file */
-    float scale;
+    float        scale;
     unsigned int dpiX;     /* horiz component of DPI option */
     unsigned int dpiY;     /* vert component of DPI option */
     unsigned int width;              /* in 1/72 inch */
@@ -59,6 +103,8 @@ struct cmdlineInfo {
     unsigned int imagewidth;         /* in 1/72 inch; zero if unspec */
     unsigned int imageheight;        /* in 1/72 inch; zero if unspec */
     unsigned int equalpixels;
+    unsigned int bitspersampleSpec;
+    unsigned int bitspersample;
     unsigned int setpage;
     bool         showpage;
     unsigned int level;
@@ -69,24 +115,29 @@ struct cmdlineInfo {
     unsigned int dict;
     unsigned int vmreclaim;
     unsigned int verbose;
+    unsigned int debug;
 };
 
-
+static bool debug;
 static bool verbose;
 
 
+
 static void
 parseDpi(const char *   const dpiOpt, 
          unsigned int * const dpiXP, 
          unsigned int * const dpiYP) {
 
     char *dpistr2;
-    unsigned int dpiX, dpiY;
+    unsigned long int dpiX, dpiY;
 
     dpiX = strtol(dpiOpt, &dpistr2, 10);
-    if (dpistr2 == dpiOpt) 
+    if (dpistr2 == dpiOpt)
         pm_error("Invalid value for -dpi: '%s'.  Must be either number "
                  "or NxN ", dpiOpt);
+    else if (dpiX > INT_MAX)
+        pm_error("Invalid value for -dpi: '%s'.  "
+                 "Value too large for computation", dpiOpt);
     else {
         if (*dpistr2 == '\0') {
             *dpiXP = dpiX;
@@ -95,8 +146,11 @@ parseDpi(const char *   const dpiOpt,
             char * dpistr3;
 
             dpistr2++;  /* Move past 'x' */
-            dpiY = strtol(dpistr2, &dpistr3, 10);        
-            if (dpistr3 != dpistr2 && *dpistr3 == '\0') {
+            dpiY = strtol(dpistr2, &dpistr3, 10);
+            if (dpiY > INT_MAX)
+                pm_error("Invalid value for -dpi: '%s'.  "
+                         "Value too large for computation", dpiOpt);
+            else if (dpistr3 != dpistr2 && *dpistr3 == '\0') {
                 *dpiXP = dpiX;
                 *dpiYP = dpiY;
             } else {
@@ -110,7 +164,50 @@ parseDpi(const char *   const dpiOpt,
 
 
 static void
-parseCommandLine(int argc, char ** argv,
+validateBps_1_2_4_8_12(unsigned int const bitsPerSample) {
+
+    switch (bitsPerSample) {
+    case 1:
+    case 2:
+    case 4:
+    case 8:
+    case 12:
+        break;
+    default:
+        pm_error("Invalid -bitspersample value: %u.  Must be "
+                 "1, 2, 4, 8, or 12", bitsPerSample);
+    }
+}
+
+
+
+static void
+validateCompDimension(unsigned int const value,
+                      unsigned int const scaleFactor,
+                      const char * const vname) {
+/*----------------------------------------------------------------------------
+  Validate that the image dimension (width or height) 'value' isn't so big
+  that in this program's calculations, involving scale factor 'scaleFactor',
+  it would cause a register overflow.  If it is, abort the program and refer
+  to the offending dimension as 'vname' in the error message.
+
+  Note that this early validation approach (calling this function) means
+  the actual computations don't have to be complicated with arithmetic
+  overflow checks, so they're easier to read.
+-----------------------------------------------------------------------------*/
+    if (value > 0) {
+        unsigned int const maxWidthHeight = INT_MAX - 2;
+        unsigned int const maxScaleFactor = maxWidthHeight / value;
+
+        if (scaleFactor > maxScaleFactor)
+            pm_error("%s is too large for compuations: %u", vname, value);
+    }
+}
+
+
+
+static void
+parseCommandLine(int argc, const char ** argv,
                  struct cmdlineInfo * const cmdlineP) {
 
     unsigned int imagewidthSpec, imageheightSpec;
@@ -120,19 +217,19 @@ parseCommandLine(int argc, char ** argv,
     float width, height;
     unsigned int noturn;
     unsigned int showpage, noshowpage;
-    const char *dpiOpt;
-    unsigned int dpiSpec;
+    const char * dpiOpt;
+    unsigned int dpiSpec, scaleSpec, widthSpec, heightSpec;
 
     optStruct3 opt;
     unsigned int option_def_index = 0;
-    optEntry *option_def;
+    optEntry * option_def;
 
     MALLOCARRAY_NOFAIL(option_def, 100);
 
-    OPTENT3(0, "scale",       OPT_FLOAT, &cmdlineP->scale, NULL,         0);
+    OPTENT3(0, "scale",       OPT_FLOAT, &cmdlineP->scale, &scaleSpec,   0);
     OPTENT3(0, "dpi",         OPT_STRING, &dpiOpt,         &dpiSpec,     0);
-    OPTENT3(0, "width",       OPT_FLOAT, &width,           NULL,         0);
-    OPTENT3(0, "height",      OPT_FLOAT, &height,          NULL,         0);
+    OPTENT3(0, "width",       OPT_FLOAT, &width,           &widthSpec,   0);
+    OPTENT3(0, "height",      OPT_FLOAT, &height,          &heightSpec,  0);
     OPTENT3(0, "psfilter",    OPT_FLAG,  NULL, &cmdlineP->psfilter,      0);
     OPTENT3(0, "turn",        OPT_FLAG,  NULL, &cmdlineP->mustturn,      0);
     OPTENT3(0, "noturn",      OPT_FLAG,  NULL, &noturn,                  0);
@@ -144,6 +241,8 @@ parseCommandLine(int argc, char ** argv,
     OPTENT3(0, "equalpixels", OPT_FLAG,  NULL, &cmdlineP->equalpixels,   0);
     OPTENT3(0, "imagewidth",  OPT_FLOAT, &imagewidth,  &imagewidthSpec,  0);
     OPTENT3(0, "imageheight", OPT_FLOAT, &imageheight, &imageheightSpec, 0);
+    OPTENT3(0, "bitspersample", OPT_UINT, &cmdlineP->bitspersample,
+            &cmdlineP->bitspersampleSpec, 0);
     OPTENT3(0, "nosetpage",   OPT_FLAG,  NULL, &nosetpage,               0);
     OPTENT3(0, "setpage",     OPT_FLAG,  NULL, &cmdlineP->setpage,       0);
     OPTENT3(0, "noshowpage",  OPT_FLAG,  NULL, &noshowpage,              0);
@@ -152,19 +251,15 @@ parseCommandLine(int argc, char ** argv,
     OPTENT3(0, "vmreclaim",   OPT_FLAG,  NULL, &cmdlineP->vmreclaim,     0);
     OPTENT3(0, "showpage",    OPT_FLAG,  NULL, &showpage,                0);
     OPTENT3(0, "verbose",     OPT_FLAG,  NULL, &cmdlineP->verbose,       0);
+    OPTENT3(0, "debug",       OPT_FLAG,  NULL, &cmdlineP->debug,         0);
     OPTENT3(0, "level",       OPT_UINT, &cmdlineP->level, 
             &cmdlineP->levelSpec,              0);
     
-    /* DEFAULTS */
-    cmdlineP->scale = 1.0;
-    width = 8.5;
-    height = 11.0;
-
     opt.opt_table = option_def;
     opt.short_allowed = FALSE;
     opt.allowNegNum = FALSE;
 
-    optParseOptions3(&argc, argv, opt, sizeof(opt), 0);
+    pm_optParseOptions3(&argc, (char **)argv, opt, sizeof(opt), 0);
 
     if (cmdlineP->mustturn && noturn)
         pm_error("You cannot specify both -turn and -noturn");
@@ -175,6 +270,15 @@ parseCommandLine(int argc, char ** argv,
     if (cmdlineP->setpage && nosetpage)
         pm_error("You cannot specify both -setpage and -nosetpage");
 
+    if (!scaleSpec)
+        cmdlineP->scale = 1.0;
+
+    if (!widthSpec)
+        width = 8.5;
+
+    if (!heightSpec)
+        height = 11.0;
+
     if (dpiSpec)
         parseDpi(dpiOpt, &cmdlineP->dpiX, &cmdlineP->dpiY);
     else {
@@ -185,16 +289,23 @@ parseCommandLine(int argc, char ** argv,
     cmdlineP->center  =  !nocenter;
     cmdlineP->canturn =  !noturn;
     cmdlineP->showpage = !noshowpage;
+
+    validateCompDimension(width, 72, "-width value");
+    validateCompDimension(height, 72, "-height value");
     
     cmdlineP->width  = width * 72;
     cmdlineP->height = height * 72;
 
-    if (imagewidthSpec)
+    if (imagewidthSpec) {
+        validateCompDimension(imagewidth, 72, "-imagewidth value");
         cmdlineP->imagewidth = imagewidth * 72;
+    }
     else
         cmdlineP->imagewidth = 0;
-    if (imageheightSpec)
+    if (imageheightSpec) {
+        validateCompDimension(imagewidth, 72, "-imageheight value");
         cmdlineP->imageheight = imageheight * 72;
+    }
     else
         cmdlineP->imageheight = 0;
 
@@ -203,6 +314,9 @@ parseCommandLine(int argc, char ** argv,
         pm_error("You must specify -psfilter in order to specify "
                  "-flate or -ascii85");
 
+    if (cmdlineP->bitspersampleSpec)
+        validateBps_1_2_4_8_12(cmdlineP->bitspersample);
+
     if (argc-1 == 0) 
         cmdlineP->inputFileName = "-";
     else if (argc-1 != 1)
@@ -211,320 +325,715 @@ parseCommandLine(int argc, char ** argv,
     else
         cmdlineP->inputFileName = argv[1];
 
+    free(option_def); 
 }
 
 
-/*===========================================================================
-  The native output encoder.  This is archaic and uses global variables.
-  It is probably obsoleted by the bmeps output encoder; we just haven't
-  had a chance to verify that yet.
-===========================================================================*/
 
+static bool
+progIsFlateCapable(void) {
+
+    return
+#ifdef NOFLATE
+        false
+#else
+        true
+#endif
+        ;
+}
+
+
+
+static const char *
+basebasename(const char * const filespec) {
 /*----------------------------------------------------------------------------
-   The following global variables are the native output encoder state.
+  Return filename up to first period
 -----------------------------------------------------------------------------*/
-static unsigned int itemsinline;
-    /* The number of items in the line we are currently building */
-static unsigned int bitsinitem;
-    /* The number of bits filled so far in the item we are currently
-       building 
-    */
-static unsigned int rlebitsinitem;
-    /* The number of bits filled so far in the item we are currently
-       building 
-    */
-static unsigned int bitspersample;
-static unsigned int item, bitshift, items;
-static unsigned int rleitem, rlebitshift;
-static unsigned int repeat, itembuf[128], count, repeatitem, repeatcount;
+    char const dirsep = '/';
+    const char * const lastSlashPos = strrchr(filespec, dirsep);
+
+    char * name;
+    const char * filename;
+
+    if (lastSlashPos)
+        filename = lastSlashPos + 1;
+    else
+        filename = filespec;
+
+    name = strdup(filename);
+    if (name != NULL) {
+        char * const dotPosition = strchr(name, '.');
+
+        if (dotPosition)
+            *dotPosition = '\0';
+    }
+    return name;
+}
 
 
 
 static void
-initNativeOutputEncoder(bool const rle, unsigned int const bitspersample) {
-/*----------------------------------------------------------------------------
-   Initialize the native output encoder.  Call this once per
-   Postscript image that you will write with putitem(), before for the
-   first putitem().
+writeFile(const unsigned char * const buffer,
+          size_t                const writeCt,
+          const char *          const name,
+          FILE *                const ofP) {
 
-   We initialize the item putter state variables, which are the
-   global variable defined above.
------------------------------------------------------------------------------*/
-    itemsinline = 0;
-    items = 0;
+    size_t writtenCt;
+
+    writtenCt = fwrite(buffer, 1, writeCt, ofP);
+
+    if (writtenCt != writeCt)
+        pm_error("Error writing to %s output file", name);
+}
+
+
+
+static void
+writeFileChar(const char * const buffer,
+              size_t       const writeCt,
+              const char * const name,
+              FILE *       const ofP) {
+
+    writeFile((const unsigned char *)buffer, writeCt, name, ofP);
+}
 
-    if (rle) {
-        rleitem = 0;
-        rlebitsinitem = 0;
-        rlebitshift = 8 - bitspersample;
-        repeat = 1;
-        count = 0;
-    } else {
-        item = 0;
-        bitsinitem = 0;
-        bitshift = 8 - bitspersample;
-    }
 
+
+#define MAX_FILTER_CT 10
+    /* The maximum number of filters this code is capable of applying */
+
+
+
+static void
+initPidList(pid_t * const pidList) {
+
+    pidList[0] = (pid_t)0;  /* end of list marker */
 }
 
 
 
 static void
-putitem(void) {
-    const char* const hexits = "0123456789abcdef";
+addToPidList(pid_t * const pidList,
+             pid_t   const newPid) {
+
+    unsigned int i;
+
+    for (i = 0; i < MAX_FILTER_CT && pidList[i]; ++i);
 
-    if (itemsinline == 30) {
-        putchar('\n');
-        itemsinline = 0;
+    assert(i < MAX_FILTER_CT);
+
+    pidList[i] = newPid;
+    pidList[i+1] = (pid_t)0;  /* end of list marker */
+}
+
+
+
+/*===========================================================================
+  The output encoder
+  ===========================================================================*/
+    
+enum OutputType {AsciiHex, Ascii85};
+
+typedef struct {
+    enum OutputType    outputType;
+    bool               compressRle;
+    bool               compressFlate;
+    unsigned int       runlengthRefresh;
+} OutputEncoder;
+
+
+
+static unsigned int
+bytesPerRow (unsigned int const cols,
+             unsigned int const bitsPerSample) {
+/*----------------------------------------------------------------------------
+  Size of row buffer, padded up to byte boundary, given that the image
+  has 'cols' samples per row, 'bitsPerSample' bits per sample.
+-----------------------------------------------------------------------------*/
+    unsigned int retval;
+
+    assert(bitsPerSample==1 || bitsPerSample==2 || bitsPerSample==4 || 
+           bitsPerSample==8 || bitsPerSample==12);
+
+    switch (bitsPerSample) {
+    case 1:
+    case 2:
+    case 4:
+        retval = cols / (8/bitsPerSample)
+            + (cols % (8/bitsPerSample) > 0 ? 1 : 0);
+        /* A more straightforward calculation would be
+           (cols * bitsPerSample + 7) / 8 ,
+           but this overflows when icols is large.
+        */
+        break;
+    case 8:
+        retval = cols;
+        break;
+    case 12:
+        retval = cols + (cols+1)/2;
+        break;
     }
-    assert(item >> 8 == 0);
-    putchar(hexits[item >> 4]);
-    putchar(hexits[item & 15]);
-    ++itemsinline;
-    ++items;
-    item = 0;
-    bitsinitem = 0;
-    bitshift = 8 - bitspersample;
+
+    return retval;
 }
 
 
 
 static void
-flushitem() {
-    if (bitsinitem > 0)
-        putitem();
+initOutputEncoder(OutputEncoder  * const oeP,
+                  unsigned int     const icols,
+                  unsigned int     const bitsPerSample,
+                  bool             const rle,
+                  bool             const flate,
+                  bool             const ascii85,
+                  bool             const psFilter) {
+
+    oeP->outputType = ascii85 ? Ascii85 : AsciiHex;
+
+    if (rle) {
+        oeP->compressRle = true;
+        oeP->runlengthRefresh =
+             psFilter ? 1024*1024*16 : bytesPerRow(icols, bitsPerSample);
+    } else
+        oeP->compressRle = false;
+
+    if (flate) {
+        assert(psFilter);
+        oeP->compressFlate = true;
+    } else
+        oeP->compressFlate = false;
+
+    if (ascii85) {
+        assert(psFilter);
+        oeP->outputType = Ascii85;
+    } else
+        oeP->outputType = AsciiHex;
 }
 
 
 
+typedef void FilterFn(FILE *          const ifP,
+                      FILE *          const ofP,
+                      OutputEncoder * const oeP);
+    /* This is a function that can be run in a separate process to do
+       arbitrary modifications of the raster data stream.
+    */
+       
+
+
+#ifndef NOFLATE
+static void
+initZlib(z_stream * const strmP) {
+
+    int const level = 9; /* maximum compression.  see zlib.h */
+
+    int ret;
+
+    /* allocate deflate state */
+    strmP->zalloc = Z_NULL;
+    strmP->zfree  = Z_NULL;
+    strmP->opaque = Z_NULL;
+
+    ret = deflateInit(strmP, level);
+    if (ret != Z_OK)
+        pm_error("Failed to initialize zlib.");
+}
+#endif
+
+
+
+static FilterFn flateFilter;
+
 static void 
-putxelval(xelval const xv) {
-    if (bitsinitem == 8)
-        putitem();
-    item += xv << bitshift;
-    bitsinitem += bitspersample;
-    bitshift -= bitspersample;
+flateFilter(FILE *          const ifP,
+            FILE *          const ofP,
+            OutputEncoder * const oeP) {
+
+#ifndef NOFLATE
+
+    /* This code is based on def() in zpipe.c.  zpipe is an example program
+       which comes with the zlib source package.  zpipe.c is public domain and
+       is available from the Zlib website: http://www.zlib.net/
+
+       See zlib.h for details on zlib parameters Z_NULL, Z_OK, etc.
+    */
+    unsigned int const chunkSz = 128*1024;
+        /* 128K recommended in zpipe.c.  4096 is not efficient but works. */
+
+    int flush;
+    z_stream strm;
+    unsigned char * in;
+    unsigned char * out;
+
+    in  = pm_allocrow(chunkSz, 1);
+    out = pm_allocrow(chunkSz, 1);
+
+    initZlib(&strm);
+
+    /* compress until end of file */
+    do {
+        strm.avail_in = fread(in, 1, chunkSz, ifP);
+        if (ferror(ifP)) {
+            deflateEnd(&strm);
+            pm_error("Error reading from internal pipe during "
+                     "flate compression.");
+        }
+        flush = feof(ifP) ? Z_FINISH : Z_NO_FLUSH;
+        strm.next_in = in;
+
+        /* run deflate() on input until output buffer not full, finish
+           compression if we have reached end of input.
+        */
+        do {
+            unsigned int have;
+
+            strm.avail_out = chunkSz;
+            strm.next_out = out;
+            deflate(&strm, flush);
+            have = chunkSz - strm.avail_out;
+            writeFile(out, have, "flate filter", ofP);
+        } while (strm.avail_out == 0);
+        assert(strm.avail_in == 0);     /* all input is used */
+
+        /* done when last data in file processed */
+    } while (flush != Z_FINISH);
+
+    free(in);
+    free(out); 
+    deflateEnd(&strm);
+    fclose(ifP);
+    fclose(ofP);
+#else
+    assert(false);    /* filter is never used */ 
+#endif
 }
 
 
 
+/* Run length encoding
+
+   In this simple run-length encoding scheme, compressed and uncompressed
+   strings follow a single index byte N.  N 0-127 means the next N+1
+   bytes are uncompressed; 129-255 means the next byte is to be repeated
+   257-N times.
+
+   In native (non-psfilter) mode, the run length filter must flush at
+   the end of every row.  But the entire raster is sent to the run length
+   filter as one continuous stream.  The run length filter learns the
+   refresh interval from oeP->runlengthRefresh.  In ps-filter mode the
+   run length filter ignores row boundaries and flushes every 4096 bytes.
+*/
+
+static FilterFn rleFilter;
+
 static void
-rleputbuffer() {
-    if (repeat) {
-        item = 256 - count;
-        putitem();
-        item = repeatitem;
-        putitem();
-    } else {
-        unsigned int i;
-    
-        item = count - 1;
-        putitem();
-        for (i = 0; i < count; ++i) {
-            item = itembuf[i];
-            putitem();
-        }
+rleFilter (FILE *          const ifP,
+           FILE *          const ofP,
+           OutputEncoder * const oeP) {
+
+    unsigned int const inSize = oeP->runlengthRefresh;
+
+    bool eof;
+    unsigned char * inbuf;
+    unsigned char * outbuf;
+    size_t outSize;
+
+    MALLOCARRAY(inbuf, inSize);
+    if (inbuf == NULL)
+        pm_error("Failed to allocate %u bytes of memory for RLE filter",
+                  inSize);
+    pm_rlenc_allocoutbuf(&outbuf, inSize, PM_RLE_PACKBITS);
+
+    for (eof = false; !eof; ) {
+        size_t const bytesRead = fread(inbuf, 1, inSize, ifP);
+
+        if (feof(ifP))
+            eof = true;
+        else if (ferror(ifP) || bytesRead == 0)
+            pm_error("Internal read error: RLE compression");
+
+        pm_rlenc_compressbyte(inbuf, outbuf, PM_RLE_PACKBITS,
+                              bytesRead, &outSize);
+        writeFile(outbuf, outSize, "rlePutBuffer", ofP);
     }
-    repeat = 1;
-    count = 0;
+
+    fclose(ifP);
+    fclose(ofP);
 }
 
 
 
+static FilterFn asciiHexFilter;
+
 static void
-rleputitem() {
-    int i;
+asciiHexFilter(FILE *          const ifP,
+               FILE *          const ofP,
+               OutputEncoder * const oeP) {
 
-    if ( count == 128 )
-        rleputbuffer();
+    char const hexits[16] = "0123456789abcdef";
 
-    if ( repeat && count == 0 )
-    { /* Still initializing a repeat buf. */
-        itembuf[count] = repeatitem = rleitem;
-        ++count;
-    }
-    else if ( repeat )
-    { /* Repeating - watch for end of run. */
-        if ( rleitem == repeatitem )
-        { /* Run continues. */
-            itembuf[count] = rleitem;
-            ++count;
-        }
-        else
-        { /* Run ended - is it long enough to dump? */
-            if ( count > 2 )
-            { /* Yes, dump a repeat-mode buffer and start a new one. */
-                rleputbuffer();
-                itembuf[count] = repeatitem = rleitem;
-                ++count;
-            }
-            else
-            { /* Not long enough - convert to non-repeat mode. */
-                repeat = 0;
-                itembuf[count] = repeatitem = rleitem;
-                ++count;
-                repeatcount = 1;
+    bool eof;
+    unsigned char inbuff[40], outbuff[81];
+
+    for (eof = false; !eof; ) {
+        size_t readCt;
+
+        readCt = fread(inbuff, 1, 40, ifP);
+
+        if (readCt == 0)
+            eof = true;
+        else {
+            unsigned int i;
+
+            for (i = 0; i < readCt; ++i) {
+                int const item = inbuff[i]; 
+                outbuff[i*2]   = hexits[item >> 4];
+                outbuff[i*2+1] = hexits[item & 15];
             }
+            outbuff[readCt * 2] = '\n';
+            writeFile(outbuff, readCt * 2 + 1, "asciiHex filter", ofP);
         }
     }
-    else
-    { /* Not repeating - watch for a run worth repeating. */
-        if ( rleitem == repeatitem )
-        { /* Possible run continues. */
-            ++repeatcount;
-            if ( repeatcount > 3 )
-            { /* Long enough - dump non-repeat part and start repeat. */
-                count = count - ( repeatcount - 1 );
-                rleputbuffer();
-                count = repeatcount;
-                for ( i = 0; i < count; ++i )
-                    itembuf[i] = rleitem;
+
+    fclose(ifP);
+    fclose(ofP);
+}
+
+
+
+static FilterFn ascii85Filter;
+
+static void
+ascii85Filter(FILE *          const ifP,
+              FILE *          const ofP,
+              OutputEncoder * const oeP) {
+
+    bool eof;
+    char outbuff[5];
+    unsigned long int value; /* requires 32 bits */
+    int count;
+    int outcount;
+
+    value = 0;  /* initial value */
+    count = 0;  /* initial value */
+    outcount = 0; /* initial value */
+
+    for (eof = false; !eof; ) {
+        int c;
+
+        c = fgetc(ifP);
+
+        if (c == EOF)
+            eof = true;
+        else {
+            value = value*256 + c;
+            ++count;
+
+            if (value == 0 && count == 4) {
+                writeFileChar("z", 1, "ASCII 85 filter", ofP);
+                    /* Ascii85 encoding z exception */
+                ++outcount;
+                count = 0;
+            } else if (count == 4) {
+                outbuff[4] = value % 85 + 33;  value/=85; 
+                outbuff[3] = value % 85 + 33;  value/=85;
+                outbuff[2] = value % 85 + 33;  value/=85;
+                outbuff[1] = value % 85 + 33;
+                outbuff[0] = value / 85 + 33;
+
+                writeFileChar(outbuff, count + 1, "ASCII 85 filter", ofP);
+
+                count = value = 0;
+                outcount += 5; 
             }
-            else
-            { /* Not long enough yet - continue as non-repeat buf. */
-                itembuf[count] = rleitem;
-                ++count;
+
+            if (outcount > 75) {
+                writeFileChar("\n", 1, "ASCII 85 filter", ofP);
+                outcount = 0;
             }
         }
-        else
-        { /* Broken run. */
-            itembuf[count] = repeatitem = rleitem;
-            ++count;
-            repeatcount = 1;
-        }
     }
 
-    rleitem = 0;
-    rlebitsinitem = 0;
-    rlebitshift = 8 - bitspersample;
-}
+    if (count > 0) { /* EOF, flush */
+        assert (count < 4);
 
+        value <<= (4 - count) * 8;   value/=85;
+        outbuff[3] = value % 85 + 33;  value/=85;
+        outbuff[2] = value % 85 + 33;  value/=85;
+        outbuff[1] = value % 85 + 33;
+        outbuff[0] = value / 85 + 33;
+        outbuff[count + 1] = '\n';
 
+        writeFileChar(outbuff, count + 2, "ASCII 85 filter", ofP);
+    }
 
-static void 
-rleputxelval(xelval const xv) {
-    if (rlebitsinitem == 8)
-        rleputitem();
-    rleitem += xv << rlebitshift;
-    rlebitsinitem += bitspersample;
-    rlebitshift -= bitspersample;
+    fclose(ifP);
+    fclose(ofP);
 }
 
 
 
 static void
-rleflush() {
-    if (rlebitsinitem > 0)
-        rleputitem();
-    if (count > 0)
-        rleputbuffer();
+makePipe(int * const pipeFdArray) {
+
+    int rc;
+    rc = pm_pipe(pipeFdArray);
+    if (rc == -1)
+        pm_error("pipe() failed, errno = %d (%s)", errno, strerror(errno));
 }
 
 
+
 static void
-flushNativeOutput(bool const rle) {
-    if (rle)
-        rleflush();
-    else
-        flushitem();
-    printf("\n");
-}
-        
-/*===========================================================================
-  The BMEPS output encoder.
-===========================================================================*/
+closeAllBut(int const saveFd0,
+            int const saveFd1,
+            int const saveFd2) {
+/*----------------------------------------------------------------------------
+   Close every file descriptor in this process except 'saveFd0',
+   'saveFd1', and 'saveFd2'.
 
-/* This code is just a wrapper around the output encoder that is part of
-   Bmeps, to give it better modularity.
-*/
+   This is helpful because even if this process doesn't touch other file
+   desriptors, its very existence will keep the files open.
+-----------------------------------------------------------------------------*/
+    
+    /* Unix provides no good way to do this; we just assume file descriptors
+       above 9 are not used in this program; Caller must ensure that is true.
+    */
+    int fd;
 
-struct bmepsoe {
-    Output_Encoder * oeP;
-    int * rleBuffer;
-    Byte * flateInBuffer;
-    Byte * flateOutBuffer;
-};
+    for (fd = 0; fd < 10; ++fd) {
+        if (fd != saveFd0 && fd != saveFd1 && fd != saveFd2)
+            close(fd);
+    }
+}
 
 
 
 static void
-createBmepsOutputEncoder(struct bmepsoe ** const bmepsoePP,
-                         FILE *            const ofP,
-                         bool              const rle,
-                         bool              const flate,
-                         bool              const ascii85) {
-
-    unsigned int const FLATE_IN_SIZE = 16384;
-    unsigned int const FLATE_OUT_SIZE = 17408;
-
-    struct bmepsoe * bmepsoeP;
-    int mode;
-
-    MALLOCVAR_NOFAIL(bmepsoeP);
-    MALLOCVAR_NOFAIL(bmepsoeP->oeP);
-    MALLOCARRAY_NOFAIL(bmepsoeP->rleBuffer, 129);
-    MALLOCARRAY_NOFAIL(bmepsoeP->flateInBuffer, FLATE_IN_SIZE);
-    MALLOCARRAY_NOFAIL(bmepsoeP->flateOutBuffer, FLATE_OUT_SIZE);
-
-    mode = 0;
-    if (rle)
-        mode |= OE_RL;
-    if (flate)
-        mode |= OE_FLATE;
-    if (ascii85)
-        mode |= OE_ASC85;
+spawnFilter(FILE *          const ofP,
+            FilterFn *      const filterFn,
+            OutputEncoder * const oeP,
+            FILE **         const feedFilePP,
+            pid_t *         const pidP) {
+/*----------------------------------------------------------------------------
+   Fork a child process to run filter function 'filterFn' and send its
+   output to *ofP.
+
+   Create a pipe for feeding the filter and return as *feedFilePP the
+   stream to which Caller can write to push stuff into the filter.
+
+   *oeP is the parameter to 'filterFn'.
+-----------------------------------------------------------------------------*/
+    int pipeFd[2];
+    pid_t rc;
+
+    makePipe(pipeFd);
+    
+    rc = fork();
+
+    if (rc == (pid_t)-1)
+        pm_error("fork() of filter process failed.  errno=%d (%s)", 
+                 errno, strerror(errno));
+    else if (rc == 0) {
+        /* This is the child process */
+ 
+        FILE * ifP;
+
+        ifP = fdopen(pipeFd[0], "r");
+
+        if (!ifP)
+            pm_error("filter process failed to make "
+                     "file stream (\"FILE\") "
+                     "out of the file descriptor which is input to the "
+                     "filter.  errno=%d (%s)",
+                     errno, strerror(errno));
+
+        closeAllBut(fileno(ifP), fileno(ofP), STDERR_FILENO);
+
+        filterFn(ifP, ofP, oeP);
+
+        exit(EXIT_SUCCESS);
+    } else {
+        /* This is the parent process */
+
+        pid_t const childPid = rc;
+
+        close(pipeFd[0]);
 
-    oe_init(bmepsoeP->oeP, ofP, mode, 9, 
-            bmepsoeP->rleBuffer, 
-            bmepsoeP->flateInBuffer, FLATE_IN_SIZE,
-            bmepsoeP->flateOutBuffer, FLATE_OUT_SIZE);
+        *feedFilePP = fdopen(pipeFd[1], "w");
 
-    *bmepsoePP = bmepsoeP;
+        *pidP = childPid;
+    }
 }
 
 
 
 static void
-destroyBmepsOutputEncoder(struct bmepsoe * const bmepsoeP) {
-    
-    free(bmepsoeP->rleBuffer);
-    free(bmepsoeP->flateInBuffer);
-    free(bmepsoeP->flateOutBuffer);
+addFilter(const char *    const description,
+          FilterFn *      const filter,
+          OutputEncoder * const oeP,
+          FILE **         const feedFilePP,
+          pid_t *         const pidList) {
+/*----------------------------------------------------------------------------
+   Add a filter to the front of the chain.
+
+   Spawn a process to do the filtering, by running function 'filter'.
+
+   *feedFilePP is the present head of the chain.  We make the new filter
+   process write its output to that and get its input from a new pipe.
+   We update *feedFilePP to the sending end of the new pipe.
+
+   Add to the list pidList[] the PID of the process we spawn.
+-----------------------------------------------------------------------------*/
+    FILE * const oldFeedFileP = *feedFilePP;
+
+    FILE * newFeedFileP;
+    pid_t pid;
+
+    spawnFilter(oldFeedFileP, filter, oeP, &newFeedFileP, &pid);
+            
+    if (verbose)
+        pm_message("%s filter spawned: pid %u",
+                   description, (unsigned)pid);
     
-    free(bmepsoeP);
+    if (debug) {
+        int const outFd    = fileno(oldFeedFileP);
+        int const supplyFd = fileno(newFeedFileP);
+        pm_message("PID %u writes to FD %u, its supplier writes to FD %u",
+                   (unsigned)pid, outFd, supplyFd);
+    }
+    fclose(oldFeedFileP);  /* Child keeps this open now */
+
+    addToPidList(pidList, pid);
+
+    *feedFilePP = newFeedFileP;
 }
 
 
 
 static void
-outputBmepsSample(struct bmepsoe * const bmepsoeP,
-                  unsigned int     const sampleValue,
-                  unsigned int     const bitsPerSample) {
+spawnFilters(FILE *          const ofP,
+             OutputEncoder * const oeP,
+             FILE **         const feedFilePP,
+             pid_t *         const pidList) {
+/*----------------------------------------------------------------------------
+   Get all the child processes for the filters running and connected.
+   Return at *feedFileP the file stream to which to write the raw data,
+   with the filtered data going to *ofP.
 
-    if (bitsPerSample == 8)
-        oe_byte_add(bmepsoeP->oeP, sampleValue);
-    else {
-        unsigned int m;
+   Filter according to *oeP.
+-----------------------------------------------------------------------------*/
 
-        for (m = 1 << (bitsPerSample-1); m != 0; m >>= 1)
-            /* depends on oe_bit_add accepting any value !=0 as 1 */
-            oe_bit_add(bmepsoeP->oeP, sampleValue & m); 
-    }
+    /* Build up the pipeline from the final to the initial stage.  The
+       result is one of:
+
+          FEED | convertRow | asciiHexFilter | *ofP
+          FEED | convertRow | ascii85Filter | *ofP
+          FEED | convertRow | rleFilter   | asciiHexFilter | *ofP
+          FEED | convertRow | flateFilter | asciiHexFilter | *ofP
+          FEED | convertRow | flateFilter | rleFilter | asciiHexFilter | *ofP
+    */
+
+    FILE * feedFileP;
+        /* The current head of the filter chain; changes as we add filters */
+
+    initPidList(pidList);
+
+    feedFileP = ofP;  /* Initial state: no filter at all */
+
+    addFilter(
+        "output",
+        oeP->outputType == Ascii85 ? &ascii85Filter : asciiHexFilter,
+        oeP,
+        &feedFileP,
+        pidList);
+
+    if (oeP->compressFlate)
+        addFilter("flate", flateFilter, oeP, &feedFileP, pidList);
+
+    if (oeP->compressRle)
+        addFilter("rle", rleFilter, oeP, &feedFileP, pidList);
+
+    *feedFilePP = feedFileP;
 }
 
 
 
 static void
-flushBmepsOutput(struct bmepsoe * const bmepsoeP) {
-    oe_byte_flush(bmepsoeP->oeP);
+waitForChildren(const pid_t * const pidList) {
+/*----------------------------------------------------------------------------
+   Wait for all child processes with PIDs in pidList[] to exit.
+   In pidList[], end-of-list is marked with a special zero value.
+-----------------------------------------------------------------------------*/
+    /* There's an odd behavior in Unix such that if you have set the
+       action for SIGCHLD to ignore the signal (even though ignoring the
+       signal is the default), the process' children do not become
+       zombies.  Consequently, waitpid() always fails with ECHILD - but
+       nonetheless waits for the child to exit.
+    
+       We expect the process not to have the action for SIGCHLD set that
+       way.
+    */
+    unsigned int i;
+
+    for (i = 0; pidList[i]; ++i) {
+        pid_t rc;
+        int status;
+
+        if (verbose)
+            pm_message("Waiting for PID %u to exit", (unsigned)pidList[i]);
+
+        rc = waitpid(pidList[i], &status, 0);
+        if (rc == -1)
+            pm_error ("waitpid() for child %u failed, errno=%d (%s)",
+                      i, errno, strerror(errno));
+        else if (status != EXIT_SUCCESS)
+            pm_error ("Child process %u terminated abnormally", i);
+    }
+    if (verbose)
+        pm_message("All children have exited");
 }
 
 
+
 /*============================================================================
-   END OF OUTPUT ENCODERS
+  END OF OUTPUT ENCODERS
 ============================================================================*/
 
 
+
+static void
+validateComputableBoundingBox(float const scols, 
+                              float const srows,
+                              float const llx, 
+                              float const lly) {
+
+    float const bbWidth  = llx + scols + 0.5;
+    float const bbHeight = lly + srows + 0.5;
+
+    if (bbHeight < INT_MIN || bbHeight > INT_MAX ||
+        bbWidth  < INT_MIN || bbWidth  > INT_MAX)
+        pm_error("Bounding box dimensions %.1f x %.1f are too large "
+                 "for computations.  "
+                 "This probably means input image width, height, "
+                 "or scale factor is too large", bbWidth, bbHeight);
+}
+
+
+
+static void
+warnUserRescaling(float const scale) {
+
+    const char * const baseMsg = "warning, image too large for page";
+
+    if (pm_have_float_format())
+        pm_message("%s; rescaling to %g", baseMsg, scale);
+    else
+        pm_message("%s; rescaling", baseMsg);
+}
+
+
+
 static void
 computeImagePosition(int     const dpiX, 
                      int     const dpiY, 
@@ -545,39 +1054,41 @@ computeImagePosition(int     const dpiX,
                      float * const llyP,
                      bool *  const turnedP ) {
 /*----------------------------------------------------------------------------
-   Determine where on the page the image is to go.  This means position,
-   dimensions, and orientation.
+  Determine where on the page the image is to go.  This means position,
+  dimensions, and orientation.
 
-   icols/irows are the dimensions of the PNM input in xels.
+  icols/irows are the dimensions of the PNM input in xels.
 
-   'mustturn' means we are required to rotate the image.
+  'mustturn' means we are required to rotate the image.
 
-   'canturn' means we may rotate the image if it fits better, but don't
-   have to.
+  'canturn' means we may rotate the image if it fits better, but don't
+  have to.
 
-   *scolsP, *srowsP are the dimensions of the image in 1/72 inch.
+  *scolsP, *srowsP are the dimensions of the image in 1/72 inch.
 
-   *llxP, *llyP are the coordinates, in 1/72 inch, of the lower left
-   corner of the image on the page.
+  *llxP, *llyP are the coordinates in the Postcript frame, of the lower left
+  corner of the image on the page.  The Postscript frame is different from the
+  Neptbm frame: units are 1/72 inch (1 point) and (0,0) is the lower left
+  corner.
 
-   *turnedP is true iff the image is to be rotated 90 degrees on the page.
+  *turnedP is true iff the image is to be rotated 90 degrees on the page.
 
-   imagewidth/imageheight are the requested dimensions of the image on
-   the page, in 1/72 inch.  Image will be as large as possible within
-   those dimensions.  Zero means unspecified, so 'scale', 'pagewid',
-   'pagehgt', 'irows', and 'icols' determine image size.
+  imagewidth/imageheight are the requested dimensions of the image on
+  the page, in 1/72 inch.  Image will be as large as possible within
+  those dimensions.  Zero means unspecified, so 'scale', 'pagewid',
+  'pagehgt', 'irows', and 'icols' determine image size.
 
-   'equalpixels' means the user wants one printed pixel per input pixel.
-   It is inconsistent with imagewidth or imageheight != 0
+  'equalpixels' means the user wants one printed pixel per input pixel.
+  It is inconsistent with imagewidth or imageheight != 0
 
-   'requestedScale' is meaningful only when imageheight/imagewidth == 0
-   and equalpixels == FALSE.  It tells how many inches the user wants
-   72 pixels of input to occupy, if it fits on the page.
+  'requestedScale' is meaningful only when imageheight/imagewidth == 0
+  and equalpixels == FALSE.  It tells how many inches the user wants
+  72 pixels of input to occupy, if it fits on the page.
 -----------------------------------------------------------------------------*/
     int cols, rows;
-        /* Number of columns, rows of input xels in the output, as
-           rotated if applicable
-        */
+    /* Number of columns, rows of input xels in the output, as
+       rotated if applicable
+    */
     bool shouldturn;  /* The image fits the page better if we turn it */
     
     if (icols > irows && pagehgt > pagewid)
@@ -608,7 +1119,7 @@ computeImagePosition(int     const dpiX,
             scale = (float) imagewidth/cols;
         else
             scale = MIN((float)imagewidth/cols, (float)imageheight/rows);
-        
+    
         *scolsP = cols*scale;
         *srowsP = rows*scale;
     } else {
@@ -617,8 +1128,8 @@ computeImagePosition(int     const dpiX,
         */
         const int devpixX = dpiX / 72.0 + 0.5;        
         const int devpixY = dpiY / 72.0 + 0.5;        
-            /* How many device pixels make up 1/72 inch, rounded to
-               nearest integer */
+        /* How many device pixels make up 1/72 inch, rounded to
+           nearest integer */
         const float pixfacX = 72.0 / dpiX * devpixX;  /* 1, approx. */
         const float pixfacY = 72.0 / dpiY * devpixY;  /* 1, approx. */
         float scale;
@@ -628,10 +1139,9 @@ computeImagePosition(int     const dpiX,
 
         *scolsP = scale * cols * pixfacX;
         *srowsP = scale * rows * pixfacY;
-        
+    
         if (scale != requestedScale)
-            pm_message("warning, image too large for page, rescaling to %g", 
-                       scale );
+            warnUserRescaling(scale);
 
         /* Before May 2001, Pnmtops enforced a 5% margin around the page.
            If the image would be too big to leave a 5% margin, Pnmtops would
@@ -644,6 +1154,7 @@ computeImagePosition(int     const dpiX,
     *llxP = (center) ? ( pagewid - *scolsP ) / 2 : 0;
     *llyP = (center) ? ( pagehgt - *srowsP ) / 2 : 0;
 
+    validateComputableBoundingBox( *scolsP, *srowsP, *llxP, *llyP);
 
     if (verbose)
         pm_message("Image will be %3.2f points wide by %3.2f points high, "
@@ -677,7 +1188,7 @@ determineDictionaryRequirement(bool           const userWantsDict,
 static void
 defineReadstring(bool const rle) {
 /*----------------------------------------------------------------------------
-   Write to Standard Output Postscript statements to define /readstring.
+  Write to Standard Output Postscript statements to define /readstring.
 -----------------------------------------------------------------------------*/
     if (rle) {
         printf("/rlestr1 1 string def\n");
@@ -692,7 +1203,7 @@ defineReadstring(bool const rle) {
         printf("    readhexstring pop\n");            /* s */
         printf("    length\n");               /* nr */
         printf("  } {\n");                    /* c */
-        printf("    256 exch sub dup\n");         /* n n */
+        printf("    257 exch sub dup\n");         /* n n */
         printf("    currentfile rlestr1 readhexstring pop\n");/* n n s1 */
         printf("    0 get\n");                /* n n c */
         printf("    exch 0 exch 1 exch 1 sub {\n");       /* n c 0 1 n-1*/
@@ -725,13 +1236,14 @@ static void
 setupReadstringNative(bool         const rle,
                       bool         const color,
                       unsigned int const icols, 
-                      unsigned int const padright, 
-                      unsigned int const bps) {
+                      unsigned int const bitsPerSample) {
 /*----------------------------------------------------------------------------
-   Write to Standard Output statements to define /readstring and also
-   arguments for it (/picstr or /rpicstr, /gpicstr, and /bpicstr).
+  Write to Standard Output statements to define /readstring and also
+  arguments for it (/picstr or /rpicstr, /gpicstr, and /bpicstr).
 -----------------------------------------------------------------------------*/
-    unsigned int const bytesPerRow = (icols + padright) * bps / 8;
+    unsigned int const bytesPerRow = icols / (8/bitsPerSample) +
+        (icols % (8/bitsPerSample) > 0 ? 1 : 0);
+        /* Size of row buffer, padded up to byte boundary. */
 
     defineReadstring(rle);
     
@@ -754,13 +1266,17 @@ putFilters(unsigned int const postscriptLevel,
 
     assert(postscriptLevel > 1);
     
+    /* We say to decode flate, then rle, so Caller must ensure it encodes
+       rel, then flate.
+    */
+
     if (ascii85)
         printf("/ASCII85Decode filter ");
     else 
         printf("/ASCIIHexDecode filter ");
     if (flate)
         printf("/FlateDecode filter ");
-    if (rle) /* bmeps encodes rle before flate, so must decode after! */
+    if (rle) 
         printf("/RunLengthDecode filter ");
 }
 
@@ -785,10 +1301,9 @@ putSetup(unsigned int const dictSize,
          bool         const rle,
          bool         const color,
          unsigned int const icols,
-         unsigned int const padright,
-         unsigned int const bps) {
+         unsigned int const bitsPerSample) {
 /*----------------------------------------------------------------------------
-   Put the setup section in the Postscript program on Standard Output.
+  Put the setup section in the Postscript program on Standard Output.
 -----------------------------------------------------------------------------*/
     printf("%%%%BeginSetup\n");
 
@@ -797,7 +1312,7 @@ putSetup(unsigned int const dictSize,
         printf("%u dict begin\n", dictSize);
     
     if (!psFilter)
-        setupReadstringNative(rle, color, icols, padright, bps);
+        setupReadstringNative(rle, color, icols, bitsPerSample);
 
     printf("%%%%EndSetup\n");
 }
@@ -808,8 +1323,8 @@ static void
 putImage(bool const psFilter,
          bool const color) {
 /*----------------------------------------------------------------------------
-   Put the image/colorimage statement in the Postscript program on
-   Standard Output.
+  Put the image/colorimage statement in the Postscript program on
+  Standard Output.
 -----------------------------------------------------------------------------*/
     if (color) {
         if (psFilter)
@@ -864,8 +1379,7 @@ putInit(unsigned int const postscriptLevel,
         float        const srows,
         float        const llx, 
         float        const lly,
-        int          const padright, 
-        int          const bps,
+        int          const bitsPerSample,
         int          const pagewid, 
         int          const pagehgt,
         bool         const color, 
@@ -877,8 +1391,8 @@ putInit(unsigned int const postscriptLevel,
         bool         const psFilter,
         unsigned int const dictSize) {
 /*----------------------------------------------------------------------------
-   Write out to Standard Output the headers stuff for the Postscript
-   program (everything up to the raster).
+  Write out to Standard Output the headers stuff for the Postscript
+  program (everything up to the raster).
 -----------------------------------------------------------------------------*/
     /* The numbers in the %! line often confuse people. They are NOT the
        PostScript language level.  The first is the level of the DSC comment
@@ -897,7 +1411,7 @@ putInit(unsigned int const postscriptLevel,
         (int) (llx + scols + 0.5), (int) (lly + srows + 0.5));
     printf("%%%%EndComments\n");
 
-    putSetup(dictSize, psFilter, rle, color, icols, padright, bps);
+    putSetup(dictSize, psFilter, rle, color, icols, bitsPerSample);
 
     printf("%%%%Page: 1 1\n");
     if (setpage)
@@ -908,7 +1422,7 @@ putInit(unsigned int const postscriptLevel,
     printf("%g %g scale\n", scols, srows);
     if (turned)
         printf("0.5 0.5 translate  90 rotate  -0.5 -0.5 translate\n");
-    printf("%d %d %d\n", icols, irows, bps);
+    printf("%d %d %d\n", icols, irows, bitsPerSample);
     printf("[ %d 0 0 -%d 0 %d ]\n", icols, irows, irows);
 
     if (psFilter)
@@ -917,6 +1431,7 @@ putInit(unsigned int const postscriptLevel,
         putInitReadstringNative(color);
 
     printf("\n");
+    fflush(stdout);
 }
 
 
@@ -957,8 +1472,57 @@ putEnd(bool         const showpage,
 
 
 static void
+validateBpsRequest(unsigned int const bitsPerSampleReq,
+                   unsigned int const postscriptLevel,
+                   bool         const psFilter) {
+
+    if (postscriptLevel < 2 && bitsPerSampleReq > 8)
+        pm_error("You requested %u bits per sample, but in Postscript "
+                 "level 1, 8 is the maximum.  You can get 12 with "
+                 "-level 2 and -psfilter", bitsPerSampleReq);
+    else if (!psFilter && bitsPerSampleReq > 8)
+        pm_error("You requested %u bits per sample, but without "
+                 "-psfilter, the maximum is 8", bitsPerSampleReq);
+}
+
+    
+
+static unsigned int
+bpsFromInput(unsigned int const bitsRequiredByMaxval,
+             unsigned int const postscriptLevel,
+             bool         const psFilter) {
+
+    unsigned int retval;
+
+    if (bitsRequiredByMaxval <= 1)
+        retval = 1;
+    else if (bitsRequiredByMaxval <= 2)
+        retval = 2;
+    else if (bitsRequiredByMaxval <= 4)
+        retval = 4;
+    else if (bitsRequiredByMaxval <= 8)
+        retval = 8;
+    else {
+        /* Post script level 2 defines a format with 12 bits per sample,
+           but I don't know the details of that format (both RLE and
+           non-RLE variations) and existing native raster generation code
+           simply can't handle bps > 8.  But the built-in filters know
+           how to do 12 bps.
+        */
+        if (postscriptLevel >= 2 && psFilter)
+            retval = 12;
+        else
+            retval = 8;
+    }
+    return retval;
+}
+
+
+
+static void
 warnUserAboutReducedDepth(unsigned int const bitsGot,
                           unsigned int const bitsWanted,
+                          bool         const userRequested,
                           unsigned int const postscriptLevel,
                           bool         const psFilter) {
 
@@ -967,15 +1531,19 @@ warnUserAboutReducedDepth(unsigned int const bitsGot,
                    "though the input has %u bits.",
                    bitsGot, bitsWanted);
 
-        if (postscriptLevel < 2)
-            pm_message("Postscript level %u has a maximum depth of 8 bits.  "
-                       "You could get up to 12 with -level=2 and -psfilter.",
-                       postscriptLevel);
-        else {
-            if (!psFilter)
-                pm_message("You can get up to 12 bits with -psfilter");
-            else
-                pm_message("The Postscript maximum is 12.");
+        if (!userRequested) {
+            if (postscriptLevel < 2)
+                pm_message("Postscript level %u has a maximum depth of "
+                           "8 bits.  "
+                           "You could get up to 12 with -level=2 "
+                           "and -psfilter.",
+                           postscriptLevel);
+            else {
+                if (!psFilter)
+                    pm_message("You can get up to 12 bits with -psfilter");
+                else
+                    pm_message("The Postscript maximum is 12.");
+            }
         }
     }
 }
@@ -986,76 +1554,237 @@ static void
 computeDepth(xelval         const inputMaxval,
              unsigned int   const postscriptLevel, 
              bool           const psFilter,
-             unsigned int * const bitspersampleP,
-             unsigned int * const psMaxvalP) {
+             unsigned int   const bitsPerSampleReq,
+             unsigned int * const bitsPerSampleP) {
 /*----------------------------------------------------------------------------
-   Figure out how many bits will represent each sample in the Postscript
-   program, and the maxval of the Postscript program samples.  The maxval
-   is just the maximum value allowable in the number of bits.
+  Figure out how many bits will represent each sample in the Postscript
+  program, and the maxval of the Postscript program samples.  The maxval
+  is just the maximum value allowable in the number of bits.
+
+  'bitsPerSampleReq' is the bits per sample that the user requests, or
+  zero if he made no request.
 -----------------------------------------------------------------------------*/
     unsigned int const bitsRequiredByMaxval = pm_maxvaltobits(inputMaxval);
 
-    if (bitsRequiredByMaxval <= 1)
-        *bitspersampleP = 1;
-    else if (bitsRequiredByMaxval <= 2)
-        *bitspersampleP = 2;
-    else if (bitsRequiredByMaxval <= 4)
-        *bitspersampleP = 4;
-    else if (bitsRequiredByMaxval <= 8)
-        *bitspersampleP = 8;
-    else {
-        /* Post script level 2 defines a format with 12 bits per sample,
-           but I don't know the details of that format (both RLE and
-           non-RLE variations) and existing native raster generation code
-           simply can't handle bps > 8.  But the built-in filters know
-           how to do 12 bps.
-        */
-        if (postscriptLevel >= 2 && psFilter)
-            *bitspersampleP = 12;
-        else
-            *bitspersampleP = 8;
+    if (bitsPerSampleReq != 0) {
+        validateBpsRequest(bitsPerSampleReq, postscriptLevel, psFilter);
+        *bitsPerSampleP = bitsPerSampleReq;
+    } else {
+        *bitsPerSampleP = bpsFromInput(bitsRequiredByMaxval,
+                                       postscriptLevel, psFilter);
     }
-
-    warnUserAboutReducedDepth(*bitspersampleP, bitsRequiredByMaxval,
+    warnUserAboutReducedDepth(*bitsPerSampleP, bitsRequiredByMaxval,
+                              bitsPerSampleReq != 0,
                               postscriptLevel, psFilter);
 
-    *psMaxvalP = pm_bitstomaxval(*bitspersampleP);
-
-    if (verbose)
+    if (verbose) {
+        unsigned int const psMaxval = pm_bitstomaxval(*bitsPerSampleP);
         pm_message("Input maxval is %u.  Postscript raster will have "
                    "%u bits per sample, so maxval = %u",
-                   inputMaxval, *bitspersampleP, *psMaxvalP);
+                   inputMaxval, *bitsPerSampleP, psMaxval);
+    }
 }    
 
 
 
+/*===========================================================================
+  The bit accumulator
+===========================================================================*/
+
+typedef struct {
+    unsigned int value;
+    unsigned int consumed;
+} BitAccumulator;
+
+
+
 static void
-convertRowNative(struct pam * const pamP, 
-                 tuple *      const tuplerow, 
-                 unsigned int const psMaxval, 
-                 bool         const rle, 
-                 unsigned int const padright) {
+ba_init(BitAccumulator * const baP) {
+
+    baP->value    = 0;
+    baP->consumed = 0;
+}
+
+
+
+static void
+ba_add12(BitAccumulator * const baP,
+         unsigned int     const new12,
+         FILE           * const fP) {
+/*----------------------------------------------------------------------------
+  Read a 12-bit string into the bit accumulator baP->value.
+  On every other call, combine two 12-bit strings and write out three bytes.
+-----------------------------------------------------------------------------*/
+    assert (baP->consumed == 12 || baP->consumed == 0);
+
+    if (baP->consumed == 12){
+        char const oldHi8 = (baP->value) >> 4;
+        char const oldLo4 = (baP->value) & 0x0f;
+        char const newHi4 = new12 >> 8;
+        char const newLo8 = new12 & 0xff;
+
+        fputc(oldHi8, fP);
+        fputc((oldLo4 << 4) | newHi4 , fP);
+        fputc(newLo8, fP);
+        baP->value = 0; baP->consumed = 0;
+    } else {
+        baP->value = new12;  baP->consumed = 12;
+    }
+}
+
+
+
+static void
+ba_add(BitAccumulator * const baP,
+       unsigned int     const b,
+       unsigned int     const bitsPerSample,
+       FILE           * const fP) {
+/*----------------------------------------------------------------------------
+  Combine bit sequences that do not fit into a byte.
+
+  Used when bitsPerSample =1, 2, 4.  
+  Logic also works for bitsPerSample = 8, 16.
+
+  The accumulator, baP->value is unsigned int (usually 32 bits), but
+  only 8 bits are used.
+-----------------------------------------------------------------------------*/
+    unsigned int const bufSize = 8;
+
+    assert (bitsPerSample == 1 || bitsPerSample == 2 || bitsPerSample == 4);
+
+    baP->value = (baP->value << bitsPerSample) | b ;
+    baP->consumed += bitsPerSample;
+    if (baP->consumed == bufSize) {
+        /* flush */
+        fputc( baP->value, fP);
+        baP->value = 0;
+        baP->consumed = 0;
+    }
+}
+
+
+
+static void
+ba_flush(BitAccumulator * const baP,
+         FILE *           const fP) {
+/*----------------------------------------------------------------------------
+  Flush partial bits in baP->consumed.
+-----------------------------------------------------------------------------*/
+    if (baP->consumed == 12) {
+        char const oldHi8 = (baP->value) >> 4;
+        char const oldLo4 = (baP->value) & 0x0f;
+        fputc(oldHi8, fP);
+        fputc(oldLo4 << 4, fP);
+    } else if (baP->consumed == 8)
+        fputc(baP->value , fP);
+    else if (baP->consumed > 0) {
+        unsigned int const leftShift = 8 - baP->consumed;
+        assert(baP->consumed <= 8);  /* why? */
+        baP->value <<= leftShift;
+        fputc(baP->value , fP);
+    }
+    baP->value = 0;
+    baP->consumed = 0;
+}
+
+
+
+static void
+outputSample(BitAccumulator * const baP,
+             unsigned int     const sampleValue,
+             unsigned int     const bitsPerSample,
+             FILE           * const fP) {
+
+    if (bitsPerSample == 8)
+        fputc(sampleValue, fP);
+    else if (bitsPerSample == 12)
+        ba_add12(baP, sampleValue, fP);
+    else
+        ba_add(baP, sampleValue, bitsPerSample, fP);
+}
+
+
+
+static void
+flushOutput(BitAccumulator * const baP,
+            FILE *           const fP) {
+    ba_flush(baP, fP);
+}
+
+
+
+/*----------------------------------------------------------------------
+  Row converters
+
+  convertRowPbm is a fast routine for PBM images.
+  It is used only when the input is PBM and the user does not specify
+  a -bitspersample value greater than 1.  It is not used when the input
+  image is PGM or PPM and the output resolution is brought down to one
+  bit per pixel by -bitpersample=1 .
+
+  convertRowNative and convertRowPsFilter are the general converters.
+  They are quite similar, the differences being:
+  (1) Native output separates the color planes: 
+  (RRR...RRR GGG...GGG BBB...BBB),
+  whereas psFilter does not:
+  (RGB RGB RGB RGB ......... RGB).
+  (2) Native flushes the run-length encoder at the end of each row if
+  grayscale, at the end of each plane if color.
+
+  Both convertRowNative and convertRowPsFilter can handle PBM, though we
+  don't use them.
+
+  If studying the code, read convertRowPbm first.  convertRowNative and
+  convertRowPsFilter are constructs that pack raster data into a form
+  similar to a binary PBM bitrow.
+  ----------------------------------------------------------------------*/
+
+static void
+convertRowPbm(struct pam *     const pamP,
+              unsigned char  * const bitrow,
+              bool             const psFilter,
+              FILE *           const fP) {
+/*---------------------------------------------------------------------
+  Feed PBM raster data directly to the output encoder.
+  Invert bits: 0 is "white" in PBM, 0 is "black" in postscript.
+----------------------------------------------------------------------*/
+    unsigned int colChar;
+    unsigned int const colChars = pbm_packed_bytes(pamP->width);
+
+    pbm_readpbmrow_packed(pamP->file, bitrow, pamP->width, pamP->format);
+
+    for (colChar = 0; colChar < colChars; ++colChar)
+        bitrow[colChar] =  ~ bitrow[colChar];
+
+    /* Zero clear padding beyond right edge */
+    pbm_cleanrowend_packed(bitrow, pamP->width);
+    writeFile(bitrow, colChars, "PBM reader", fP);
+}
+
+
+
+static void
+convertRowNative(struct pam *     const pamP, 
+                 tuple *                tuplerow, 
+                 unsigned int     const bitsPerSample,
+                 FILE           * const fP) { 
+
+    unsigned int const psMaxval = pm_bitstomaxval(bitsPerSample);
 
     unsigned int plane;
+    BitAccumulator ba;
+
+    ba_init(&ba);
+
+    pnm_readpamrow(pamP, tuplerow);
+    pnm_scaletuplerow(pamP, tuplerow, tuplerow, psMaxval);
 
     for (plane = 0; plane < pamP->depth; ++plane) {
         unsigned int col;
-        for (col= 0; col < pamP->width; ++col) {
-            sample const scaledSample = 
-                pnm_scalesample(tuplerow[col][plane], pamP->maxval, psMaxval);
+        for (col= 0; col < pamP->width; ++col)
+            outputSample(&ba, tuplerow[col][plane], bitsPerSample, fP);
 
-            if (rle)
-                rleputxelval(scaledSample);
-            else
-                putxelval(scaledSample);
-        }
-        for (col = 0; col < padright; ++col)
-            if (rle)
-                rleputxelval(0);
-        else
-            putxelval(0);
-        if (rle)
-            rleflush();
+        flushOutput(&ba, fP);
     }
 }
 
@@ -1063,34 +1792,27 @@ convertRowNative(struct pam * const pamP,
 
 static void
 convertRowPsFilter(struct pam *     const pamP,
-                   tuple *          const tuplerow,
-                   struct bmepsoe * const bmepsoeP,
-                   unsigned int     const psMaxval) {
+                   tuple *                tuplerow,
+                   unsigned int     const bitsPerSample,
+                   FILE           * const fP) { 
 
-    unsigned int const bitsPerSample = pm_maxvaltobits(psMaxval);
-    unsigned int const stragglers =
-        (((bitsPerSample * pamP->depth) % 8) * pamP->width) % 8;
-        /* Number of bits at the right edge that don't fill out a
-           whole byte */
+    unsigned int const psMaxval = pm_bitstomaxval(bitsPerSample);
 
     unsigned int col;
-    tuple scaledTuple;
-    
-    scaledTuple = pnm_allocpamtuple(pamP);
+    BitAccumulator ba;
+
+    ba_init(&ba);
+
+    pnm_readpamrow(pamP, tuplerow);
+    pnm_scaletuplerow(pamP, tuplerow, tuplerow, psMaxval);
 
     for (col = 0; col < pamP->width; ++col) {
         unsigned int plane;
-        pnm_scaletuple(pamP, scaledTuple, tuplerow[col], psMaxval);
-        
         for (plane = 0; plane < pamP->depth; ++plane)
-            outputBmepsSample(bmepsoeP, scaledTuple[plane], bitsPerSample);
-    }
-    if (stragglers > 0) {
-        unsigned int i;
-        for (i = stragglers; i < 8; ++i)
-            oe_bit_add(bmepsoeP->oeP, 0);
+            outputSample(&ba, tuplerow[col][plane], bitsPerSample, fP);
     }
-    pnm_freepamtuple(scaledTuple);
+    flushOutput(&ba, fP);
+
 }
 
 
@@ -1146,50 +1868,111 @@ selectPostscriptLevel(bool           const levelIsGiven,
 
 
 static void
-convertPage(FILE * const ifP, 
-            int    const turnflag, 
-            int    const turnokflag, 
-            bool   const psFilter,
-            bool   const rle, 
-            bool   const flate,
-            bool   const ascii85,
-            bool   const setpage,
-            bool   const showpage,
-            bool   const center, 
-            float  const scale,
-            int    const dpiX, 
-            int    const dpiY, 
-            int    const pagewid, 
-            int    const pagehgt,
-            int    const imagewidth, 
-            int    const imageheight, 
-            bool   const equalpixels,
-            char   const name[],
-            bool   const dict,
-            bool   const vmreclaim,
-            bool   const levelIsGiven,
+convertRaster(struct pam * const inpamP,
+              unsigned int const bitsPerSample,
+              bool         const psFilter,
+              FILE *       const fP) {
+/*----------------------------------------------------------------------------
+   Read the raster described by *inpamP, and write a bit stream of samples
+   to *fP.  This stream has to be compressed and converted to text before it
+   can be part of a Postscript program.
+   
+   'psFilter' means to do the conversion using built in Postscript filters, as
+   opposed to our own filters via /readstring.
+
+   'bitsPerSample' is how many bits each sample is to take in the Postscript
+   output.
+-----------------------------------------------------------------------------*/
+    if (PAM_FORMAT_TYPE(inpamP->format) == PBM_TYPE && bitsPerSample == 1)  {
+        unsigned char * bitrow;
+        unsigned int row;
+
+        bitrow = pbm_allocrow_packed(inpamP->width);
+
+        for (row = 0; row < inpamP->height; ++row)
+            convertRowPbm(inpamP, bitrow, psFilter, fP);
+
+        pbm_freerow(bitrow);
+    } else  {
+        tuple *tuplerow;
+        unsigned int row;
+        
+        tuplerow = pnm_allocpamrow(inpamP);
+
+        for (row = 0; row < inpamP->height; ++row) {
+            if (psFilter)
+                convertRowPsFilter(inpamP, tuplerow, bitsPerSample, fP);
+            else
+                convertRowNative(inpamP, tuplerow, bitsPerSample, fP);
+        }
+        pnm_freepamrow(tuplerow);
+    }
+}
+
+
+
+/* FILE MANAGEMENT: File management is pretty hairy here.  A filter, which
+   runs in its own process, needs to be able to cause its output file to
+   close because it might be an internal pipe and the next stage needs to
+   know output is done.  So the forking process must close its copy of the
+   file descriptor.  BUT: if the output of the filter is not an internal
+   pipe but this program's output, then we don't want it closed when the
+   filter terminates because we'll need it to be open for the next image
+   the program converts (with a whole new chain of filters).
+   
+   To prevent the progam output file from getting closed, we pass a
+   duplicate of it to spawnFilters() and keep the original open.
+*/
+
+
+
+static void
+convertPage(FILE *       const ifP, 
+            int          const turnflag, 
+            int          const turnokflag, 
+            bool         const psFilter,
+            bool         const rle, 
+            bool         const flate,
+            bool         const ascii85,
+            bool         const setpage,
+            bool         const showpage,
+            bool         const center, 
+            float        const scale,
+            int          const dpiX, 
+            int          const dpiY, 
+            int          const pagewid, 
+            int          const pagehgt,
+            int          const imagewidth, 
+            int          const imageheight, 
+            bool         const equalpixels,
+            unsigned int const bitsPerSampleReq,
+            char         const name[],
+            bool         const dict,
+            bool         const vmreclaim,
+            bool         const levelIsGiven,
             unsigned int const levelGiven) {
     
     struct pam inpam;
-    tuple* tuplerow;
-    unsigned int padright;
-        /* Number of bits we must add to the right end of each Postscript
-           output line in order to have an integral number of bytes of output.
-           E.g. at 2 bits per sample with 10 columns, this would be 4.
-        */
-    int row;
-    unsigned int psMaxval;
-        /* The maxval of the Postscript program */
     float scols, srows;
     float llx, lly;
     bool turned;
     bool color;
     unsigned int postscriptLevel;
-    struct bmepsoe * bmepsoeP;
-    unsigned int dictSize;
+    unsigned int bitsPerSample;
+    unsigned int dictSize;  
         /* Size of Postscript dictionary we should define */
+    OutputEncoder oe;
+    pid_t filterPidList[MAX_FILTER_CT + 1];
+
+    FILE * feedFileP;
+        /* The file stream which is the head of the filter chain; we write to
+           this and filtered stuff comes out the other end.
+        */
+    FILE * filterChainOfP;
 
     pnm_readpaminit(ifP, &inpam, PAM_STRUCT_SIZE(tuple_type));
+
+    validateCompDimension(inpam.width, 16, "Input image width");
     
     if (!STRSEQ(inpam.tuple_type, PAM_PBM_TUPLETYPE) &&
         !STRSEQ(inpam.tuple_type, PAM_PGM_TUPLETYPE) &&
@@ -1206,13 +1989,9 @@ convertPage(FILE * const ifP,
     if (color)
         pm_message("generating color Postscript program.");
 
-    computeDepth(inpam.maxval, postscriptLevel, psFilter,
-                 &bitspersample, &psMaxval);
-    {
-        unsigned int const realBitsPerLine = inpam.width * bitspersample;
-        unsigned int const paddedBitsPerLine = ((realBitsPerLine + 7) / 8) * 8;
-        padright = (paddedBitsPerLine - realBitsPerLine) / bitspersample;
-    }
+    computeDepth(inpam.maxval, postscriptLevel, psFilter, bitsPerSampleReq,
+                 &bitsPerSample);
+
     /* In positioning/scaling the image, we treat the input image as if
        it has a density of 72 pixels per inch.
     */
@@ -1225,84 +2004,65 @@ convertPage(FILE * const ifP,
     determineDictionaryRequirement(dict, psFilter, &dictSize);
     
     putInit(postscriptLevel, name, inpam.width, inpam.height, 
-            scols, srows, llx, lly, padright, bitspersample, 
+            scols, srows, llx, lly, bitsPerSample, 
             pagewid, pagehgt, color,
             turned, rle, flate, ascii85, setpage, psFilter, dictSize);
 
-    createBmepsOutputEncoder(&bmepsoeP, stdout, rle, flate, ascii85);
-    initNativeOutputEncoder(rle, bitspersample);
+    initOutputEncoder(&oe, inpam.width, bitsPerSample,
+                      rle, flate, ascii85, psFilter);
 
-    tuplerow = pnm_allocpamrow(&inpam);
-
-    for (row = 0; row < inpam.height; ++row) {
-        pnm_readpamrow(&inpam, tuplerow);
-        if (psFilter)
-            convertRowPsFilter(&inpam, tuplerow, bmepsoeP, psMaxval);
-        else
-            convertRowNative(&inpam, tuplerow, psMaxval, rle, padright);
-    }
+    fflush(stdout);
+    filterChainOfP = fdopen(dup(fileno(stdout)), "w");
+        /* spawnFilters() closes this.  See FILE MANAGEMENT above */
 
-    pnm_freepamrow(tuplerow);
+    spawnFilters(filterChainOfP, &oe, &feedFileP, filterPidList);
+ 
+    convertRaster(&inpam, bitsPerSample, psFilter, feedFileP);
 
-    if (psFilter)
-        flushBmepsOutput(bmepsoeP);
-    else
-        flushNativeOutput(rle);
+    fflush(feedFileP);
+    fclose(feedFileP);
 
-    destroyBmepsOutputEncoder(bmepsoeP);
+    waitForChildren(filterPidList);
 
     putEnd(showpage, psFilter, ascii85, dictSize, vmreclaim);
 }
 
 
 
-static const char *
-basebasename(const char * const filespec) {
-/*----------------------------------------------------------------------------
-    Return filename up to first period
------------------------------------------------------------------------------*/
-    char const dirsep = '/';
-    const char * const lastSlashPos = strrchr(filespec, dirsep);
-
-    char * name;
-    const char * filename;
-
-    if (lastSlashPos)
-        filename = lastSlashPos + 1;
-    else
-        filename = filespec;
-
-    name = strdup(filename);
-    if (name != NULL) {
-        char * const dotPosition = strchr(name, '.');
-
-        if (dotPosition)
-            *dotPosition = '\0';
-    }
-    return name;
-}
-
-
-
 int
-main(int argc, char * argv[]) {
+main(int argc, const char * argv[]) {
 
-    FILE* ifp;
-    const char *name;  /* malloc'ed */
+    FILE * ifP;
+    const char * name;  /* malloc'ed */
     struct cmdlineInfo cmdline;
 
-    pnm_init(&argc, argv);
+    pm_proginit(&argc, argv);
+
+    setSignals();
 
     parseCommandLine(argc, argv, &cmdline);
 
-    verbose = cmdline.verbose;
+    verbose = cmdline.verbose || cmdline.debug;
+    debug   = cmdline.debug;
 
-    ifp = pm_openr(cmdline.inputFileName);
+    if (cmdline.flate && !progIsFlateCapable())
+        pm_error("This program cannot do flate compression.  "
+                 "(There are other versions of the program that do, "
+                 "though -- it's a build-time option");
+
+    ifP = pm_openr(cmdline.inputFileName);
 
     if (streq(cmdline.inputFileName, "-"))
         name = strdup("noname");
     else
         name = basebasename(cmdline.inputFileName);
+
+    /* This program manages file descriptors in a way that assumes
+       that new files will get file descriptor numbers less than 10,
+       so we close superfluous files now to make sure that's true.
+    */
+    closeAllBut(fileno(ifP), fileno(stdout), fileno(stderr));
+
     {
         int eof;  /* There are no more images in the input file */
         unsigned int imageSeq;
@@ -1320,7 +2080,7 @@ main(int argc, char * argv[]) {
 
         eof = FALSE;  /* There is always at least one image */
         for (imageSeq = 0; !eof; ++imageSeq) {
-            convertPage(ifp, cmdline.mustturn, cmdline.canturn, 
+            convertPage(ifP, cmdline.mustturn, cmdline.canturn, 
                         cmdline.psfilter,
                         cmdline.rle, cmdline.flate, cmdline.ascii85, 
                         cmdline.setpage, cmdline.showpage,
@@ -1328,15 +2088,17 @@ main(int argc, char * argv[]) {
                         cmdline.dpiX, cmdline.dpiY,
                         cmdline.width, cmdline.height, 
                         cmdline.imagewidth, cmdline.imageheight, 
-                        cmdline.equalpixels, name, 
+                        cmdline.equalpixels,
+                        cmdline.bitspersampleSpec ? cmdline.bitspersample : 0,
+                        name, 
                         cmdline.dict, cmdline.vmreclaim,
                         cmdline.levelSpec, cmdline.level);
-            pnm_nextimage(ifp, &eof);
+            pnm_nextimage(ifP, &eof);
         }
     }
-    strfree(name);
+    pm_strfree(name);
 
-    pm_close(ifp);
+    pm_close(ifP);
 
     return 0;
 }
@@ -1357,4 +2119,9 @@ main(int argc, char * argv[]) {
 ** -nocenter option added November 1993 by Wolfgang Stuerzlinger,
 **  wrzl@gup.uni-linz.ac.at.
 **
+** July 2011 afu
+** row convertors rewritten, fast PBM-only row convertor added,
+** rle compression slightly modified, flate compression added
+** ascii85 output end added.
+**
 */
diff --git a/converter/other/pnmtorast.c b/converter/other/pnmtorast.c
index 605e815c..e11d3cb7 100644
--- a/converter/other/pnmtorast.c
+++ b/converter/other/pnmtorast.c
@@ -19,103 +19,285 @@
 
 
 static colormap_t *
-alloc_pr_colormap(void) {
-
-    colormap_t* pr_colormapP;
-
-    MALLOCVAR(pr_colormapP);
-    if ( pr_colormapP == NULL )
-        pm_error( "out of memory" );
-    pr_colormapP->type = RMT_EQUAL_RGB;
-    pr_colormapP->length = MAXCOLORS;
-    MALLOCARRAY(pr_colormapP->map[0], MAXCOLORS);
-    MALLOCARRAY(pr_colormapP->map[1], MAXCOLORS);
-    MALLOCARRAY(pr_colormapP->map[2], MAXCOLORS);
-    if ( pr_colormapP->map[0] == NULL || 
-         pr_colormapP->map[1] == NULL ||
-         pr_colormapP->map[2] == NULL )
-        pm_error( "out of memory" );
-
-    return pr_colormapP;
+allocPrColormap(void) {
+
+    colormap_t * prColormapP;
+
+    MALLOCVAR(prColormapP);
+    if (prColormapP == NULL)
+        pm_error("out of memory");
+    prColormapP->type = RMT_EQUAL_RGB;
+    prColormapP->length = MAXCOLORS;
+    MALLOCARRAY(prColormapP->map[0], MAXCOLORS);
+    MALLOCARRAY(prColormapP->map[1], MAXCOLORS);
+    MALLOCARRAY(prColormapP->map[2], MAXCOLORS);
+    if (prColormapP->map[0] == NULL || 
+        prColormapP->map[1] == NULL ||
+        prColormapP->map[2] == NULL)
+        pm_error("out of memory");
+
+    return prColormapP;
 }
 
 
 
-static colormap_t*
-make_pr_colormap(colorhist_vector const chv,
-                 int              const colors) {
+static colormap_t *
+makePrColormap(colorhist_vector const chv,
+               unsigned int     const colors) {
 
-    colormap_t* pr_colormapP;
-    int i;
+    colormap_t * prColormapP;
+    unsigned int i;
 
-    pr_colormapP = alloc_pr_colormap( );
+    prColormapP = allocPrColormap();
 
-    for ( i = 0; i < colors; ++i )
-    {
-        pr_colormapP->map[0][i] = PPM_GETR( chv[i].color );
-        pr_colormapP->map[1][i] = PPM_GETG( chv[i].color );
-        pr_colormapP->map[2][i] = PPM_GETB( chv[i].color );
+    for (i = 0; i < colors; ++i) {
+        prColormapP->map[0][i] = PPM_GETR(chv[i].color);
+        prColormapP->map[1][i] = PPM_GETG(chv[i].color);
+        prColormapP->map[2][i] = PPM_GETB(chv[i].color);
     }
-    for ( ; i < MAXCOLORS; ++i )
-        pr_colormapP->map[0][i] = pr_colormapP->map[1][i] =
-            pr_colormapP->map[2][i] = 0;
-
-    return pr_colormapP;
+    for ( ; i < MAXCOLORS; ++i) {
+        prColormapP->map[0][i] = 0;
+        prColormapP->map[1][i] = 0;
+        prColormapP->map[2][i] = 0;
+    }
+    return prColormapP;
 }
 
 
 
 static colormap_t *
-make_gray_pr_colormap(void) {
+makeGrayPrColormap(void) {
 
-    colormap_t* pr_colormapP;
-    int i;
+    colormap_t * prColormapP;
+    unsigned int i;
 
-    pr_colormapP = alloc_pr_colormap( );
+    prColormapP = allocPrColormap();
 
-    for ( i = 0; i < MAXCOLORS; ++i )
-    {
-        pr_colormapP->map[0][i] = i;
-        pr_colormapP->map[1][i] = i;
-        pr_colormapP->map[2][i] = i;
+    for (i = 0; i < MAXCOLORS; ++i) {
+        prColormapP->map[0][i] = i;
+        prColormapP->map[1][i] = i;
+        prColormapP->map[2][i] = i;
+    }
+
+    return prColormapP;
+}
+
+
+
+static void
+doRowDepth1(const xel *     const xelrow,
+            unsigned char * const rastRow,
+            unsigned int    const cols,
+            int             const format,
+            xelval          const maxval,
+            colorhash_table const cht,
+            unsigned int *  const lenP) {
+                
+    unsigned int col;
+    int bitcount;
+    unsigned int cursor;
+
+    cursor = 0;
+
+    rastRow[cursor] = 0;
+    bitcount = 7;
+
+    for (col = 0; col < cols; ++col) {
+        switch (PNM_FORMAT_TYPE(format)) {
+        case PPM_TYPE: {
+            xel adjustedXel;
+            int color;
+            if (maxval != 255)
+                PPM_DEPTH(adjustedXel, xelrow[col], maxval, 255 );
+            color = ppm_lookupcolor(cht, &adjustedXel);
+            if (color == -1)
+                pm_error("color not found?!?  "
+                         "col=%u  r=%u g=%u b=%u",
+                         col,
+                         PPM_GETR(adjustedXel),
+                         PPM_GETG(adjustedXel),
+                         PPM_GETB(adjustedXel));
+            if (color)
+                rastRow[cursor] |= 1 << bitcount;
+        } break;
+
+        default: {
+            int const color = PNM_GET1(xelrow[col]);
+            if (!color)
+                rastRow[cursor] |= 1 << bitcount;
+            break;
+        }
+        }
+        --bitcount;
+        if (bitcount < 0) {
+            ++cursor;
+            rastRow[cursor] = 0;
+            bitcount = 7;
+        }
+    }
+    *lenP = cursor;
+}
+
+
+
+static void
+doRowDepth8(const xel *     const xelrow,
+            unsigned char * const rastRow,
+            unsigned int    const cols,
+            int             const format,
+            xelval          const maxval,
+            colorhash_table const cht,
+            unsigned int *  const lenP) {
+
+    unsigned int col;
+    unsigned int cursor;
+
+    for (col = 0, cursor = 0; col < cols; ++col) {
+        int color;  /* color index of pixel or -1 if not in 'cht' */
+
+        switch (PNM_FORMAT_TYPE(format)) {
+        case PPM_TYPE: {
+            xel adjustedXel;
+
+            if (maxval == 255)
+                adjustedXel = xelrow[col];
+            else
+                PPM_DEPTH(adjustedXel, xelrow[col], maxval, 255);
+
+            color = ppm_lookupcolor(cht, &adjustedXel);
+            if (color == -1)
+                pm_error("color not found?!?  "
+                         "col=%u  r=%u g=%u b=%u",
+                         col,
+                         PPM_GETR(adjustedXel),
+                         PPM_GETG(adjustedXel),
+                         PPM_GETB(adjustedXel));
+        } break;
+
+        case PGM_TYPE: {
+            int const rawColor = PNM_GET1(xelrow[col]);
+
+            color = maxval == 255 ? rawColor : rawColor * 255 / maxval;
+
+        } break;
+
+        default:
+            color = PNM_GET1(xelrow[col]);
+        }
+        rastRow[cursor++] = color;
     }
+    *lenP = cursor;
+}
+
 
-    return pr_colormapP;
+
+
+static void
+doRowDepth24(const xel *     const xelrow,
+             unsigned char * const rastRow,
+             unsigned int    const cols,
+             int             const format,
+             xelval          const maxval,
+             unsigned int *  const lenP) {
+
+    /* Since depth is 24, we do NOT have a valid cht. */
+
+    unsigned int col;
+    unsigned int cursor;
+
+    for (col = 0, cursor = 0; col < cols; ++col) {
+        xel adjustedXel;
+
+        if (maxval == 255)
+            adjustedXel = xelrow[col];
+        else
+            PPM_DEPTH(adjustedXel, xelrow[col], maxval, 255);
+
+        rastRow[cursor++] = PPM_GETB(adjustedXel);
+        rastRow[cursor++] = PPM_GETG(adjustedXel);
+        rastRow[cursor++] = PPM_GETR(adjustedXel);
+    }
+    *lenP = cursor;
+}
+
+
+
+static void
+computeRaster(unsigned char * const rastRaster,
+              unsigned int    const lineSize,
+              unsigned int    const depth,
+              unsigned int    const cols,
+              unsigned int    const rows,
+              int             const format,
+              xelval          const maxval,
+              xel **          const xels,
+              colorhash_table const cht) {
+                  
+    unsigned int row;
+    unsigned char * rastRow;
+
+    for (row = 0, rastRow = &rastRaster[0]; row < rows; ++row) {
+        xel * const xelrow = xels[row];
+
+        unsigned int len; /* Number of bytes of rast data added to rastRow[] */
+
+        switch (depth) {
+        case 1:
+            doRowDepth1(xelrow, rastRow, cols, format, maxval, cht, &len);
+            break;
+        case 8:
+            doRowDepth8(xelrow, rastRow, cols, format, maxval, cht, &len);
+            break;
+        case 24:
+            doRowDepth24(xelrow, rastRow, cols, format, maxval, &len);
+            break;
+        default:
+            pm_error("INTERNAL ERROR: impossible depth %u", depth);
+        }
+        {
+            /* Pad out the line (which has a rounded size) with zeroes so
+               the resulting file is repeatable.
+            */
+            unsigned int i;
+            for (i = len; i < lineSize; ++i)
+                rastRow[i] = 0;
+        }
+        rastRow += lineSize;
+    }
 }
 
 
 
 int
-main(int argc, char ** argv) {
+main(int argc, const char ** argv) {
 
-    FILE* ifp;
-    xel** xels;
-    xel* xelrow;
+    FILE * ifP;
+    xel ** xels;
     xel p;
-    register xel* xP;
     colorhist_vector chv;
     colorhash_table cht;
-    colormap_t* pr_colormapP;
-    int argn, pr_type, rows, cols, format, i;
-    int depth, colors, linesize, row;
-    register int col, bitcount;
+    colormap_t * prColormapP;
+    int argn;
+    int prType;
+    int rows, cols;
+    int format;
+    unsigned int depth;
+    int colorCt;
     xelval maxval;
-    struct pixrect* pr;
-    unsigned char* data;
-    register unsigned char* byteP;
-    const char* const usage = "[-standard|-rle] [pnmfile]";
+    struct pixrect * prP;
+    const char * const usage = "[-standard|-rle] [pnmfile]";
 
-    pnm_init( &argc, argv );
+    pm_proginit(&argc, argv);
 
     argn = 1;
-    pr_type = RT_BYTE_ENCODED;
+    prType = RT_BYTE_ENCODED;
 
     while ( argn < argc && argv[argn][0] == '-' && argv[argn][1] != '\0' )
     {
         if ( pm_keymatch( argv[argn], "-standard", 2 ) )
-            pr_type = RT_STANDARD;
+            prType = RT_STANDARD;
         else if ( pm_keymatch( argv[argn], "-rle", 2 ) )
-            pr_type = RT_BYTE_ENCODED;
+            prType = RT_BYTE_ENCODED;
         else
             pm_usage( usage );
         ++argn;
@@ -123,191 +305,96 @@ main(int argc, char ** argv) {
 
     if ( argn != argc )
     {
-        ifp = pm_openr( argv[argn] );
+        ifP = pm_openr( argv[argn] );
         ++argn;
     }
     else
-        ifp = stdin;
+        ifP = stdin;
 
     if ( argn != argc )
         pm_usage( usage );
 
-    xels = pnm_readpnm( ifp, &cols, &rows, &maxval, &format );
+    xels = pnm_readpnm(ifP, &cols, &rows, &maxval, &format);
 
-    pm_close( ifp );
+    pm_close(ifP);
 
     /* Figure out the proper depth and colormap. */
-    switch ( PNM_FORMAT_TYPE(format) )
-    {
+    switch (PNM_FORMAT_TYPE(format)) {
     case PPM_TYPE:
-        pm_message( "computing colormap..." );
-        chv = ppm_computecolorhist( xels, cols, rows, MAXCOLORS, &colors );
-        if ( chv == (colorhist_vector) 0 )
-        {
+        pm_message("computing colormap...");
+        chv = ppm_computecolorhist(xels, cols, rows, MAXCOLORS, &colorCt);
+        if (!chv) {
             pm_message(
-                "Too many colors - proceeding to write a 24-bit non-mapped" );
+                "Too many colors - proceeding to write a 24-bit non-mapped");
             pm_message(
                 "rasterfile.  If you want 8 bits, try doing a 'pnmquant %d'.",
-                MAXCOLORS );
+                MAXCOLORS);
             depth = 24;
-            pr_type = RT_STANDARD;
-            pr_colormapP = (colormap_t*) 0;
-        }
-        else
-        {
-            pm_message( "%d colors found", colors );
-
-            if ( maxval != 255 )
-                for ( i = 0; i < colors; ++i )
-                    PPM_DEPTH( chv[i].color, chv[i].color, maxval, 255 );
-
+            prType = RT_STANDARD;
+            prColormapP = NULL;
+        } else {
+            pm_message("%u colors found", colorCt);
+
+            if (maxval != 255) {
+                unsigned int i;
+                for (i = 0; i < colorCt; ++i)
+                    PPM_DEPTH(chv[i].color, chv[i].color, maxval, 255);
+            }
             /* Force white to slot 0 and black to slot 1, if possible. */
-            PPM_ASSIGN( p, 255, 255, 255 );
-            ppm_addtocolorhist( chv, &colors, MAXCOLORS, &p, 0, 0 );
-            PPM_ASSIGN( p, 0, 0, 0 );
-            ppm_addtocolorhist( chv, &colors, MAXCOLORS, &p, 0, 1 );
-
-            if ( colors == 2 )
-            {
-                /* Monochrome. */
+            PPM_ASSIGN(p, 255, 255, 255);
+            ppm_addtocolorhist(chv, &colorCt, MAXCOLORS, &p, 0, 0);
+            PPM_ASSIGN(p, 0, 0, 0);
+            ppm_addtocolorhist(chv, &colorCt, MAXCOLORS, &p, 0, 1);
+
+            if (colorCt == 2) {
+                /* Monochrome */
                 depth = 1;
-                pr_colormapP = (colormap_t*) 0;
-            }
-            else
-            {
+                prColormapP = NULL;
+            } else {
                 /* Turn the ppm colormap into the appropriate Sun colormap. */
                 depth = 8;
-                pr_colormapP = make_pr_colormap( chv, colors );
+                prColormapP = makePrColormap(chv, colorCt);
             }
-            cht = ppm_colorhisttocolorhash( chv, colors );
-            ppm_freecolorhist( chv );
+            cht = ppm_colorhisttocolorhash(chv, colorCt);
+            ppm_freecolorhist(chv);
         }
 
         break;
 
     case PGM_TYPE:
         depth = 8;
-        pr_colormapP = make_gray_pr_colormap( );
+        prColormapP = makeGrayPrColormap();
         break;
 
     default:
         depth = 1;
-        pr_colormapP = (colormap_t*) 0;
+        prColormapP = NULL;
         break;
     }
 
-    if ( maxval > 255 && depth != 1 )
+    if (maxval > 255 && depth != 1)
         pm_message(
-            "maxval is not 255 - automatically rescaling colors" );
+            "maxval is not 255 - automatically rescaling colors");
     
     /* Allocate space for the Sun-format image. */
-    if ( (pr = mem_create(cols, rows, depth)) == (struct pixrect*) 0 )
-        pm_error( "unable to create new pixrect" );
-    data = ( (struct mpr_data*) pr->pr_data )->md_image;
-    linesize = ( (struct mpr_data*) pr->pr_data )->md_linebytes;
-
-    /* And compute the Sun image.  The variables at this point are:
-    **   cht is null or not
-    **   depth is 1, 8, or 24
-    */
-    for ( row = 0; row < rows; ++row )
-    {
-        xelrow = xels[row];
-        byteP = data;
-        switch ( depth )
-        {
-        case 1:
-            *byteP = 0;
-            bitcount = 7;
-            for ( col = 0, xP = xelrow; col < cols; ++col, ++xP )
-            {
-                register int color;
-
-                switch ( PNM_FORMAT_TYPE(format) )
-                {
-                case PPM_TYPE:
-                    if ( maxval != 255 )
-                        PPM_DEPTH( *xP, *xP, maxval, 255 );
-                    color = ppm_lookupcolor( cht, xP );
-                    if ( color == -1 )
-                        pm_error(
-                            "color not found?!?  row=%d col=%d  r=%d g=%d b=%d",
-                            row, col, PPM_GETR(*xP), PPM_GETG(*xP),
-                            PPM_GETB(*xP) );
-                    if ( color )
-                        *byteP |= 1 << bitcount;
-                    break;
-
-                default:
-                    color = PNM_GET1( *xP );
-                    if ( ! color )
-                        *byteP |= 1 << bitcount;
-                    break;
-                }
-                --bitcount;
-                if ( bitcount < 0 )
-                {
-                    ++byteP;
-                    *byteP = 0;
-                    bitcount = 7;
-                }
-            }
-            break;
-
-        case 8:
-            for ( col = 0, xP = xelrow; col < cols; ++col, ++xP )
-            {
-                register int color;
-
-                switch ( PNM_FORMAT_TYPE(format) )
-                {
-                case PPM_TYPE:
-                    if ( maxval != 255 )
-                        PPM_DEPTH( *xP, *xP, maxval, 255 );
-                    color = ppm_lookupcolor( cht, xP );
-                    if ( color == -1 )
-                        pm_error(
-                            "color not found?!?  row=%d col=%d  r=%d g=%d b=%d",
-                            row, col, PPM_GETR(*xP), PPM_GETG(*xP),
-                            PPM_GETB(*xP) );
-                    break;
-
-                case PGM_TYPE:
-                    color = PNM_GET1( *xP );
-                    if ( maxval != 255 )
-                        color = color * 255 / maxval;
-                    break;
-
-                default:
-                    color = PNM_GET1( *xP );
-                }
-                *byteP++ = color;
-            }
-            break;
+    prP = mem_create(cols, rows, depth);
+    if (!prP)
+        pm_error("unable to create new pixrect");
 
-        case 24:
-            /* If depth is 24, we do NOT have a valid cht. */
-            for ( col = 0, xP = xelrow; col < cols; ++col, ++xP )
-            {
-                if ( maxval != 255 )
-                    PPM_DEPTH( *xP, *xP, maxval, 255 );
-                *byteP++ = PPM_GETB( *xP );
-                *byteP++ = PPM_GETG( *xP );
-                *byteP++ = PPM_GETR( *xP );
-            }
-            break;
+    computeRaster(prP->pr_data->md_image,
+                  prP->pr_data->md_linebytes,
+                  depth,
+                  cols, rows, format, maxval, xels, cht);
 
-        default:
-            pm_error( "can't happen" );
-        }
-        data += linesize;
-    }
-    pnm_freearray( xels, rows );
+    pnm_freearray(xels, rows);
 
-    /* Finally, write the sucker out. */
-    if ( pr_dump( pr, stdout, pr_colormapP, pr_type, 0 ) == PIX_ERR )
-        pm_error( "error writing rasterfile" );
+    {
+        int rc;
 
-    exit( 0 );
+        rc = pr_dump(prP, stdout, prColormapP, prType, 0);
+        if (rc == PIX_ERR )
+            pm_error("error writing rasterfile");
+    }
+    return 0;
 }
 
diff --git a/converter/other/pnmtosgi.c b/converter/other/pnmtosgi.c
index 472b5197..cc57349f 100644
--- a/converter/other/pnmtosgi.c
+++ b/converter/other/pnmtosgi.c
@@ -13,342 +13,349 @@
 ** implied warranty.
 **
 ** 29Jan94: first version
+
+** Feb 2010 afu
+** Added dimension check to prevent short int from overflowing
 */
+
+#include <assert.h>
+
 #include "pnm.h"
 #include "sgi.h"
 #include "mallocvar.h"
+#include "runlength.h"
+
 
 /*#define DEBUG*/
 
-typedef short       ScanElem;
+typedef uint16_t       ScanElem;
 typedef struct {
     ScanElem *  data;
     long        length;
 } ScanLine;
 
-/* prototypes */
-static void put_big_short ARGS((short s));
-static void put_big_long ARGS((long l));
-#define put_byte(b)     (void)(putc((unsigned char)(b), stdout))
-static void put_short_as_byte ARGS((short s));
-static void write_table  ARGS((long *table, int tabsize));
-static void write_channels ARGS((int cols, int rows, int channels, void (*put) ARGS((short)) ));
-static long * build_channels ARGS((FILE *ifp, int cols, int rows, xelval maxval, int format, int bpc, int channels));
-static ScanElem *compress ARGS((ScanElem *temp, int row, int rows, int cols, int chan_no, long *table, int bpc));
-static int rle_compress ARGS((ScanElem *inbuf, int cols));
-
-#define WORSTCOMPR(x)   (2*(x) + 2)
-
-
 #define MAXVAL_BYTE     255
 #define MAXVAL_WORD     65535
+#define INT16MAX        32767
 
 static char storage = STORAGE_RLE;
 static ScanLine * channel[3];
-static ScanElem * rletemp;
 static xel * pnmrow;
 
 
-static void
-write_header(int const cols, 
-             int const rows, 
-             xelval const maxval, 
-             int const bpc, 
-             int const dimensions, 
-             int const channels, 
-             const char * const imagename)
-{
-    int i;
-
-#ifdef DEBUG
-    pm_message("writing header");
-#endif
-
-    put_big_short(SGI_MAGIC);
-    put_byte(storage);
-    put_byte((char)bpc);
-    put_big_short(dimensions);
-    put_big_short(cols);
-    put_big_short(rows);
-    put_big_short(channels);
-    put_big_long(0);                /* PIXMIN */
-    put_big_long(maxval);           /* PIXMAX */
-    for( i = 0; i < 4; i++ )
-        put_byte(0);
-    for( i = 0; i < 79 && imagename[i] != '\0'; i++ )
-        put_byte(imagename[i]);
-    for(; i < 80; i++ )
-        put_byte(0);
-    put_big_long(CMAP_NORMAL);
-    for( i = 0; i < 404; i++ )
-        put_byte(0);
-}
 
+#define putByte(b) (void)(putc((unsigned char)(b), stdout))
 
 
-int
-main(argc, argv)
-    int argc;
-    char *argv[];
-{
-    FILE *ifp;
-    int argn;
-    const char * const usage = "[-verbatim|-rle] [-imagename <name>] [pnmfile]";
-    int cols, rows, format;
-    xelval maxval, newmaxval;
-    const char *imagename = "no name";
-    int bpc, dimensions, channels;
-    long *table = NULL;
+static void
+putBigShort(short const s) {
 
-    pnm_init(&argc, argv);
+    if (pm_writebigshort(stdout, s ) == -1)
+        pm_error( "write error" );
+}
 
-    argn = 1;
-    while( argn < argc && argv[argn][0] == '-' && argv[argn][1] != '\0' ) {
-        if( pm_keymatch(argv[argn], "-verbatim", 2) )
-            storage = STORAGE_VERBATIM;
-        else
-        if( pm_keymatch(argv[argn], "-rle", 2) )
-            storage = STORAGE_RLE;
-        else
-        if( pm_keymatch(argv[argn], "-imagename", 2) ) {
-            if( ++argn >= argc )
-                pm_usage(usage);
-            imagename = argv[argn];
-        }
-        else
-            pm_usage(usage);
-        ++argn;
-    }
 
-    if( argn < argc ) {
-        ifp = pm_openr( argv[argn] );
-        argn++;
-    }
-    else
-        ifp = stdin;
 
-    if( argn != argc )
-        pm_usage(usage);
+static void
+putBigLong(long const l) {
 
-    pnm_readpnminit(ifp, &cols, &rows, &maxval, &format);
-    pnmrow = pnm_allocrow(cols);
+    if (pm_writebiglong( stdout, l ) == -1)
+        pm_error( "write error" );
+}
 
-    switch( PNM_FORMAT_TYPE(format) ) {
-        case PBM_TYPE:
-            newmaxval = PGM_MAXMAXVAL;
-            pm_message("promoting PBM to PGM");
-        case PGM_TYPE:
-            newmaxval = maxval;
-            dimensions = 2; channels = 1;
-            break;
-        case PPM_TYPE:
-            newmaxval = maxval;
-            dimensions = 3; channels = 3;
-            break;
-        default:
-            pm_error("can\'t happen");
-    }
-    if( newmaxval <= MAXVAL_BYTE )
-        bpc = 1;
-    else if( newmaxval <= MAXVAL_WORD )
-        bpc = 2;
-    else
-        pm_error("maxval too large - try using \"pnmdepth %d\"", MAXVAL_WORD);
 
-    table = build_channels(ifp, cols, rows, newmaxval, format, bpc, channels);
-    pnm_freerow(pnmrow);
-    pm_close(ifp);
 
-    write_header(cols, rows, newmaxval, bpc, dimensions, channels, imagename);
-    if( table )
-        write_table(table, rows * channels);
-    if( bpc == 1 )
-        write_channels(cols, rows, channels, put_short_as_byte);
-    else
-        write_channels(cols, rows, channels, put_big_short);
+static void
+putShortAsByte(short const s) {
 
-    exit(0);
+    putByte((unsigned char)s);
 }
 
 
+
 static void
-write_table(table, tabsize)
-    long *table;
-    int tabsize;
-{
-    int i;
-    long offset;
+writeTable(long *       const table,
+           unsigned int const tabsize) {
 
-#ifdef DEBUG
-    pm_message("writing table");
-#endif
+    unsigned int i;
+    unsigned long offset;
 
     offset = HeaderSize + tabsize * 8;
-    for( i = 0; i < tabsize; i++ ) {
-        put_big_long(offset);
+
+    for (i = 0; i < tabsize; ++i) {
+        putBigLong(offset);
         offset += table[i];
     }
-    for( i = 0; i < tabsize; i++ )
-        put_big_long(table[i]);
+    for (i = 0; i < tabsize; ++i)
+        putBigLong(table[i]);
 }
 
 
+
 static void
-write_channels(cols, rows, channels, put)
-    int cols, rows, channels;
-    void (*put) ARGS((short));
-{
-    int i, row, col;
-
-#ifdef DEBUG
-    pm_message("writing image data");
-#endif
-
-    for( i = 0; i < channels; i++ ) {
-        for( row = 0; row < rows; row++ ) {
-            for( col = 0; col < channel[i][row].length; col++ ) {
+writeChannels(unsigned int const cols,
+              unsigned int const rows,
+              unsigned int const channels,
+              void (*put) (short)) {
+
+    unsigned int i;
+
+    for (i = 0; i < channels; ++i) {
+        unsigned int row;
+        for (row = 0; row < rows; ++row) {
+            unsigned int col;
+            for (col = 0; col < channel[i][row].length; ++col) {
                 (*put)(channel[i][row].data[col]);
             }
+            pm_rlenc_freebuf((unsigned char *) channel[i][row].data);
         }
     }
 }
 
-static void
-put_big_short(short s)
-{
-    if ( pm_writebigshort( stdout, s ) == -1 )
-        pm_error( "write error" );
-}
 
 
-static void
-put_big_long(l)
-    long l;
-{
-    if ( pm_writebiglong( stdout, l ) == -1 )
-        pm_error( "write error" );
+static ScanElem *
+compress(ScanElem *   const tempArg,
+         unsigned int const row,
+         unsigned int const rows,
+         unsigned int const cols,
+         unsigned int const chanNum,
+         long *       const table,
+         unsigned int const bpc) {
+/*----------------------------------------------------------------------------
+   Compress a row, putting results in global 'channel' array, in newly
+   allocated storage (which Caller must free).
+
+   Except that if the compression is null compression, we make 'channel'
+   point to existing storage, which Caller must not free.  Yuck.
+-----------------------------------------------------------------------------*/
+    ScanElem * retval;
+
+    switch (storage) {
+    case STORAGE_VERBATIM:
+        channel[chanNum][row].length = cols;
+        channel[chanNum][row].data = tempArg;
+        MALLOCARRAY_NOFAIL(retval, cols);
+        break;
+    case STORAGE_RLE: {
+        unsigned int const tabrow = chanNum * rows + row;
+
+        unsigned int len;
+        size_t lenBytes;
+        ScanElem * p;
+
+        pm_rlenc_allocoutbuf((unsigned char **) &p, cols, PM_RLE_SGI16);
+
+        pm_rlenc_compressword(tempArg,(unsigned char *) p, PM_RLE_SGI16,
+                              cols, &lenBytes);
+
+        assert((unsigned)lenBytes == lenBytes);
+            /* Guaranteed by pm_rlenc_compressword() */
+
+        len = lenBytes / 2;  /* sizeof(ScanElem) */
+        channel[chanNum][row].length = len;
+        REALLOCARRAY(p, len);   /* reclaim some space */
+        if (p == NULL)
+            pm_error("realloc failure while reclaiming memory space "
+                     "for output");
+        channel[chanNum][row].data = p;
+        table[tabrow] = len * bpc;
+        retval = tempArg;
+    } break;
+    default:
+        pm_error("unknown storage type - can't happen");
+    }
+    return retval;
 }
 
 
-static void
-put_short_as_byte(short s)
-{
-    put_byte((unsigned char)s);
-}
-
 
 static long *
-build_channels(FILE *ifp, int cols, int rows, xelval maxval, 
-               int format, int bpc, int channels)
-{
-    int i, row, col, sgirow;
-    long *table = NULL;
-    ScanElem *temp;
-
-#ifdef DEBUG
-    pm_message("building channels");
-#endif
-
-    if( storage != STORAGE_VERBATIM ) {
+buildChannels(FILE *       const ifP,
+              unsigned int const cols,
+              unsigned int const rows,
+              xelval       const maxval,
+              int          const format,
+              unsigned int const bpc,
+              unsigned int const channels) {
+
+    unsigned int row;
+    unsigned int sgirow;
+    long * table;
+    ScanElem * temp;
+
+    if (storage != STORAGE_VERBATIM) {
         MALLOCARRAY_NOFAIL(table, channels * rows);
-        MALLOCARRAY_NOFAIL(rletemp, WORSTCOMPR(cols));
-    }
+    } else
+        table = NULL;
+
     MALLOCARRAY_NOFAIL(temp, cols);
 
-    for( i = 0; i < channels; i++ )
-        MALLOCARRAY_NOFAIL(channel[i], rows);
+    {
+        unsigned int i;
+        for (i = 0; i < channels; ++i)
+            MALLOCARRAY_NOFAIL(channel[i], rows);
+    }
 
-    for( row = 0, sgirow = rows-1; row < rows; row++, sgirow-- ) {
-        pnm_readpnmrow(ifp, pnmrow, cols, maxval, format);
-        if( channels == 1 ) {
-            for( col = 0; col < cols; col++ )
+    for (row = 0, sgirow = rows-1; row < rows; ++row, --sgirow) {
+        pnm_readpnmrow(ifP, pnmrow, cols, maxval, format);
+        if (channels == 1) {
+            unsigned int col;
+            for (col = 0; col < cols; ++col)
                 temp[col] = (ScanElem)PNM_GET1(pnmrow[col]);
             temp = compress(temp, sgirow, rows, cols, 0, table, bpc);
-        }
-        else {
-            for( col = 0; col < cols; col++ )
+        } else {
+            unsigned int col;
+            for (col = 0; col < cols; ++col)
                 temp[col] = (ScanElem)PPM_GETR(pnmrow[col]);
             temp = compress(temp, sgirow, rows, cols, 0, table, bpc);
-            for( col = 0; col < cols; col++ )
+            for (col = 0; col < cols; ++col)
                 temp[col] = (ScanElem)PPM_GETG(pnmrow[col]);
             temp = compress(temp, sgirow, rows, cols, 1, table, bpc);
-            for( col = 0; col < cols; col++ )
+            for (col = 0; col < cols; ++col)
                 temp[col] = (ScanElem)PPM_GETB(pnmrow[col]);
             temp = compress(temp, sgirow, rows, cols, 2, table, bpc);
         }
     }
 
     free(temp);
-    if( table )
-        free(rletemp);
     return table;
 }
 
 
-static ScanElem *
-compress(temp, row, rows, cols, chan_no, table, bpc)
-    ScanElem *temp;
-    int row, rows, cols, chan_no;
-    long *table;
-    int bpc;
-{
-    int len, i, tabrow;
-    ScanElem *p;
-
-    switch( storage ) {
-        case STORAGE_VERBATIM:
-            channel[chan_no][row].length = cols;
-            channel[chan_no][row].data = temp;
-            MALLOCARRAY_NOFAIL(temp, cols);
+
+static void
+writeHeader(unsigned int const cols, 
+            unsigned int const rows, 
+            xelval       const maxval, 
+            unsigned int const bpc, 
+            unsigned int const dimensions, 
+            unsigned int const channels, 
+            const char * const imagename) {
+
+    unsigned int i;
+
+    putBigShort(SGI_MAGIC);
+    putByte(storage);
+    putByte((char)bpc);
+    putBigShort(dimensions);
+    putBigShort(cols);
+    putBigShort(rows);
+    putBigShort(channels);
+    putBigLong(0);                /* PIXMIN */
+    putBigLong(maxval);           /* PIXMAX */
+
+    for(i = 0; i < 4; ++i)
+        putByte(0);
+
+    for (i = 0; i < 79 && imagename[i] != '\0'; ++i)
+        putByte(imagename[i]);
+
+    for(; i < 80; ++i)
+        putByte(0);
+
+    putBigLong(CMAP_NORMAL);
+
+    for (i = 0; i < 404; ++i)
+        putByte(0);
+}
+
+
+
+int
+main(int argc,char * argv[]) {
+
+    FILE * ifP;
+    int argn;
+    const char * const usage = "[-verbatim|-rle] [-imagename <name>] [pnmfile]";
+    int cols, rows;
+    int format;
+    xelval maxval, newmaxval;
+    const char * imagename;
+    unsigned int bpc;
+    unsigned int dimensions;
+    unsigned int channels;
+    long * table;
+
+    pnm_init(&argc, argv);
+
+    imagename = "no name";  /* default value */
+    argn = 1;
+    while( argn < argc && argv[argn][0] == '-' && argv[argn][1] != '\0' ) {
+        if( pm_keymatch(argv[argn], "-verbatim", 2) )
+            storage = STORAGE_VERBATIM;
+        else
+        if( pm_keymatch(argv[argn], "-rle", 2) )
+            storage = STORAGE_RLE;
+        else
+        if( pm_keymatch(argv[argn], "-imagename", 2) ) {
+            if( ++argn >= argc )
+                pm_usage(usage);
+            imagename = argv[argn];
+        }
+        else
+            pm_usage(usage);
+        ++argn;
+    }
+
+    if( argn < argc ) {
+        ifP = pm_openr( argv[argn] );
+        argn++;
+    }
+    else
+        ifP = stdin;
+
+    if( argn != argc )
+        pm_usage(usage);
+
+    pnm_readpnminit(ifP, &cols, &rows, &maxval, &format);
+
+    if (rows > INT16MAX || cols > INT16MAX)
+        pm_error ("Input image is too large.");
+
+    pnmrow = pnm_allocrow(cols);
+    
+    switch (PNM_FORMAT_TYPE(format)) {
+        case PBM_TYPE:
+            pm_message("promoting PBM to PGM");
+            newmaxval = PGM_MAXMAXVAL;
+        case PGM_TYPE:
+            newmaxval = maxval;
+            dimensions = 2;
+            channels = 1;
             break;
-        case STORAGE_RLE:
-            tabrow = chan_no * rows + row;
-            len = rle_compress(temp, cols);    /* writes result into rletemp */
-            channel[chan_no][row].length = len;
-            MALLOCARRAY(p, len);
-            channel[chan_no][row].data = p;
-            for( i = 0; i < len; i++, p++ )
-                *p = rletemp[i];
-            table[tabrow] = len * bpc;
+        case PPM_TYPE:
+            newmaxval = maxval;
+            dimensions = 3;
+            channels = 3;
             break;
         default:
-            pm_error("unknown storage type - can\'t happen");
+            pm_error("can\'t happen");
     }
-    return temp;
-}
+    if (newmaxval <= MAXVAL_BYTE)
+        bpc = 1;
+    else if (newmaxval <= MAXVAL_WORD)
+        bpc = 2;
+    else
+        pm_error("maxval too large - try using \"pnmdepth %u\"", MAXVAL_WORD);
 
+    table = buildChannels(ifP, cols, rows, newmaxval, format, bpc, channels);
 
-/*
-slightly modified RLE algorithm from ppmtoilbm.c
-written by Robert A. Knop (rknop@mop.caltech.edu)
-*/
-static int
-rle_compress(inbuf, size)
-    ScanElem *inbuf;
-    int size;
-{
-    int in, out, hold, count;
-    ScanElem *outbuf = rletemp;
-
-    in=out=0;
-    while( in<size ) {
-        if( (in<size-1) && (inbuf[in]==inbuf[in+1]) ) {     /*Begin replicate run*/
-            for( count=0,hold=in; in<size && inbuf[in]==inbuf[hold] && count<127; in++,count++)
-                ;
-            outbuf[out++]=(ScanElem)(count);
-            outbuf[out++]=inbuf[hold];
-        }
-        else {  /*Do a literal run*/
-            hold=out; out++; count=0;
-            while( ((in>=size-2)&&(in<size)) || ((in<size-2) && ((inbuf[in]!=inbuf[in+1])||(inbuf[in]!=inbuf[in+2]))) ) {
-                outbuf[out++]=inbuf[in++];
-                if( ++count>=127 )
-                    break;
-            }
-            outbuf[hold]=(ScanElem)(count | 0x80);
-        }
-    }
-    outbuf[out++] = (ScanElem)0;     /* terminator */
-    return(out);
+    pnm_freerow(pnmrow);
+
+    pm_close(ifP);
+
+    writeHeader(cols, rows, newmaxval, bpc, dimensions, channels, imagename);
+
+    if (table)
+        writeTable(table, rows * channels);
+
+    if (bpc == 1)
+        writeChannels(cols, rows, channels, putShortAsByte);
+    else
+        writeChannels(cols, rows, channels, putBigShort);
+
+    return 0;
 }
 
+
diff --git a/converter/other/pnmtoxwd.c b/converter/other/pnmtoxwd.c
index b6439d28..eda2ee8f 100644
--- a/converter/other/pnmtoxwd.c
+++ b/converter/other/pnmtoxwd.c
@@ -20,11 +20,11 @@
 #include "x11wd.h"
 
 
-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;  /* Filespecs of input file */
+    const char * inputFilename;  /* Filename of input file */
     unsigned int pseudodepth;
     unsigned int directcolor;
 };
@@ -34,7 +34,7 @@ struct cmdlineInfo {
 static void 
 parseCommandLine(int argc, 
                  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.  
@@ -46,7 +46,7 @@ parseCommandLine(int argc,
    was passed to us as the argv array.  We also trash *argv.
 --------------------------------------------------------------------------*/
     optEntry *option_def;
-    /* Instructions to optParseOptions3 on how to parse our options. */
+    /* Instructions to pm_optParseOptions3 on how to parse our options. */
     optStruct3 opt;
 
     unsigned int option_def_index;
@@ -63,7 +63,7 @@ parseCommandLine(int argc,
     opt.short_allowed = FALSE;  /* We have no short (old-fashioned) options */
     opt.allowNegNum = FALSE;   /* We have no parms that are negative numbers */
 
-    optParseOptions3( &argc, argv, opt, sizeof(opt), 0 );
+    pm_optParseOptions3( &argc, argv, opt, sizeof(opt), 0 );
     /* Uses and sets argc, argv, and some of *cmdlineP and others. */
 
     if (!depthSpec)
@@ -78,12 +78,12 @@ parseCommandLine(int argc,
     }
 
     if (argc-1 == 0) 
-        cmdlineP->inputFilespec = "-";
+        cmdlineP->inputFilename = "-";
     else if (argc-1 != 1)
         pm_error("Program takes zero or one argument (filename).  You "
                  "specified %d", argc-1);
     else
-        cmdlineP->inputFilespec = argv[1];
+        cmdlineP->inputFilename = argv[1];
 }
 
 
@@ -410,7 +410,7 @@ writeRaster(FILE *           const ofP,
 int
 main(int argc, char * argv[]) {
 
-    struct cmdlineInfo cmdline;
+    struct CmdlineInfo cmdline;
     FILE* ifP;
     xel ** xels;
     int rows, cols, format, colors;
@@ -426,7 +426,7 @@ main(int argc, char * argv[]) {
 
     parseCommandLine(argc, argv, &cmdline);
 
-    ifP = pm_openr(cmdline.inputFilespec);
+    ifP = pm_openr(cmdline.inputFilename);
 
     xels = pnm_readpnm(ifP, &cols, &rows, &maxval, &format);
     xmaxval = (1 << cmdline.pseudodepth) - 1;
@@ -473,13 +473,13 @@ main(int argc, char * argv[]) {
         }
     }
 
-    if (streq(cmdline.inputFilespec, "-"))
+    if (streq(cmdline.inputFilename, "-"))
         dumpname = "stdin";
     else {
-        if (strlen(cmdline.inputFilespec) > XWDVAL_MAX - sizeof(h11) - 1)
+        if (strlen(cmdline.inputFilename) > XWDVAL_MAX - sizeof(h11) - 1)
             pm_error("Input file name is ridiculously long.");
         else
-            dumpname = cmdline.inputFilespec;
+            dumpname = cmdline.inputFilename;
     }
 
     setupX11Header(&h11, dumpname, cols, rows, format, 
diff --git a/converter/other/ppmtopgm.c b/converter/other/ppmtopgm.c
index 86e7ae6a..e20c5660 100644
--- a/converter/other/ppmtopgm.c
+++ b/converter/other/ppmtopgm.c
@@ -36,9 +36,9 @@ convertRaster(FILE *       const ifP,
                 outputRow[col] = (gray) ppm_fastlumin(inputRow[col]);
         } else {
             /* Can't use fast approximation, so fall back on floats. */
-            int col;
+            unsigned int col;
             for (col = 0; col < cols; ++col) 
-                outputRow[col] = (gray) (PPM_LUMIN(inputRow[col]) + 0.5);
+                outputRow[col] = ppm_luminosity(inputRow[col]);
         }
         pgm_writepgmrow(ofP, outputRow, cols, maxval, 0);
     }
diff --git a/converter/other/pstopnm.c b/converter/other/pstopnm.c
index 0e91ad9c..19b1630a 100644
--- a/converter/other/pstopnm.c
+++ b/converter/other/pstopnm.c
@@ -18,6 +18,7 @@
 #define _XOPEN_SOURCE 500  
     /* Make sure fdopen() is in stdio.h and strdup() is in string.h */
 
+#include <assert.h>
 #include <string.h>
 #include <unistd.h>
 #include <stdlib.h>
@@ -27,12 +28,15 @@
 #include <sys/stat.h>
 
 #include "pm_c_util.h"
+#include "mallocvar.h"
 #include "pnm.h"
 #include "shhopt.h"
 #include "nstring.h"
 
-enum orientation {PORTRAIT, LANDSCAPE, UNSPECIFIED};
-struct box {
+static bool verbose;
+
+enum Orientation {PORTRAIT, LANDSCAPE, UNSPECIFIED};
+struct Box {
     /* Description of a rectangle within an image; all coordinates 
        measured in points (1/72") with lower left corner of page being the 
        origin.
@@ -44,15 +48,28 @@ struct box {
     int ury;  /* upper right Y coord */
 };
 
-struct cmdlineInfo {
+struct Dimensions {
+/*----------------------------------------------------------------------------
+  Horizontal and vertical dimensions of something, both in pixels and
+  spatial distance (points).
+
+  Sizes are in pixels.  Resolutions are in dots per inch (pixels per inch);
+-----------------------------------------------------------------------------*/
+    unsigned int xsize;
+    unsigned int ysize;
+    unsigned int xres;
+    unsigned int yres;
+};
+
+struct CmdlineInfo {
     /* All the information the user supplied in the command line,
        in a form easy for the program to use.
     */
-    const char *input_filespec;  /* Filespecs of input files */
+    const char * inputFileName;  /* Names of input files */
     unsigned int forceplain;
-    struct box extract_box;
+    struct Box extractBox;
     unsigned int nocrop;
-    unsigned int format_type;
+    unsigned int formatType;
     unsigned int verbose;
     float xborder;
     unsigned int xmax;
@@ -61,30 +78,34 @@ struct cmdlineInfo {
     unsigned int ymax;
     unsigned int ysize;  /* zero means unspecified */
     unsigned int dpi;    /* zero means unspecified */
-    enum orientation orientation;
-    unsigned int goto_stdout;
+    enum Orientation orientation;
+    unsigned int stdoutSpec;
+    unsigned int textalphabits;
 };
 
 
 static void
 parseCommandLine(int argc, char ** argv,
-                 struct cmdlineInfo * const cmdlineP) {
+                 struct CmdlineInfo * const cmdlineP) {
 /*----------------------------------------------------------------------------
    Note that the file spec array we return is stored in the storage that
    was passed to us as the argv array.
 -----------------------------------------------------------------------------*/
-    optEntry *option_def = malloc( 100*sizeof( optEntry ) );
-        /* Instructions to optParseOptions3 on how to parse our options.
+    optEntry * option_def;
+        /* Instructions to pm_optParseOptions3 on how to parse our options.
          */
     optStruct3 opt;
 
     unsigned int option_def_index;
 
-    unsigned int pbm_opt, pgm_opt, ppm_opt;
-    unsigned int portrait_opt, landscape_opt;
+    unsigned int pbmOpt, pgmOpt, ppmOpt;
+    unsigned int portraitOpt, landscapeOpt;
     float llx, lly, urx, ury;
     unsigned int llxSpec, llySpec, urxSpec, urySpec;
     unsigned int xmaxSpec, ymaxSpec, xsizeSpec, ysizeSpec, dpiSpec;
+    unsigned int textalphabitsSpec;
+
+    MALLOCARRAY_NOFAIL(option_def, 100);
     
     option_def_index = 0;   /* incremented by OPTENTRY */
     OPTENT3(0, "forceplain", OPT_FLAG,  NULL, &cmdlineP->forceplain,     0);
@@ -93,9 +114,9 @@ parseCommandLine(int argc, char ** argv,
     OPTENT3(0, "urx",        OPT_FLOAT, &urx, &urxSpec,                  0);
     OPTENT3(0, "ury",        OPT_FLOAT, &ury, &urySpec,                  0);
     OPTENT3(0, "nocrop",     OPT_FLAG,  NULL, &cmdlineP->nocrop,         0);
-    OPTENT3(0, "pbm",        OPT_FLAG,  NULL, &pbm_opt,                  0);
-    OPTENT3(0, "pgm",        OPT_FLAG,  NULL, &pgm_opt,                  0);
-    OPTENT3(0, "ppm",        OPT_FLAG,  NULL, &ppm_opt,                  0);
+    OPTENT3(0, "pbm",        OPT_FLAG,  NULL, &pbmOpt ,                  0);
+    OPTENT3(0, "pgm",        OPT_FLAG,  NULL, &pgmOpt,                   0);
+    OPTENT3(0, "ppm",        OPT_FLAG,  NULL, &ppmOpt,                   0);
     OPTENT3(0, "verbose",    OPT_FLAG,  NULL, &cmdlineP->verbose,        0);
     OPTENT3(0, "xborder",    OPT_FLOAT, &cmdlineP->xborder, NULL,        0);
     OPTENT3(0, "xmax",       OPT_UINT,  &cmdlineP->xmax, &xmaxSpec,      0);
@@ -104,9 +125,11 @@ parseCommandLine(int argc, char ** argv,
     OPTENT3(0, "ymax",       OPT_UINT,  &cmdlineP->ymax, &ymaxSpec,      0);
     OPTENT3(0, "ysize",      OPT_UINT,  &cmdlineP->ysize, &ysizeSpec,    0);
     OPTENT3(0, "dpi",        OPT_UINT,  &cmdlineP->dpi, &dpiSpec,        0);
-    OPTENT3(0, "portrait",   OPT_FLAG,  NULL, &portrait_opt,             0);
-    OPTENT3(0, "landscape",  OPT_FLAG,  NULL, &landscape_opt,            0);
-    OPTENT3(0, "stdout",     OPT_FLAG,  NULL, &cmdlineP->goto_stdout,    0);
+    OPTENT3(0, "portrait",   OPT_FLAG,  NULL, &portraitOpt,              0);
+    OPTENT3(0, "landscape",  OPT_FLAG,  NULL, &landscapeOpt,             0);
+    OPTENT3(0, "stdout",     OPT_FLAG,  NULL, &cmdlineP->stdoutSpec,     0);
+    OPTENT3(0, "textalphabits", OPT_UINT,
+            &cmdlineP->textalphabits,  &textalphabitsSpec, 0);
 
     /* Set the defaults */
     cmdlineP->xborder = cmdlineP->yborder = 0.1;
@@ -115,7 +138,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 */
 
-    optParseOptions3(&argc, argv, opt, sizeof(opt), 0);
+    pm_optParseOptions3(&argc, argv, opt, sizeof(opt), 0);
         /* Uses and sets argc, argv, and some of *cmdlineP and others. */
 
     if (xmaxSpec) {
@@ -142,38 +165,38 @@ parseCommandLine(int argc, char ** argv,
     } else 
         cmdlineP->ysize = 0;
 
-    if (portrait_opt & !landscape_opt)
+    if (portraitOpt && !landscapeOpt)
         cmdlineP->orientation = PORTRAIT;
-    else if (!portrait_opt & landscape_opt)
+    else if (!portraitOpt && landscapeOpt)
         cmdlineP->orientation = LANDSCAPE;
-    else if (!portrait_opt & !landscape_opt)
+    else if (!portraitOpt && !landscapeOpt)
         cmdlineP->orientation = UNSPECIFIED;
     else
         pm_error("Cannot specify both -portrait and -landscape options");
 
-    if (pbm_opt)
-        cmdlineP->format_type = PBM_TYPE;
-    else if (pgm_opt)
-        cmdlineP->format_type = PGM_TYPE;
-    else if (ppm_opt)
-        cmdlineP->format_type = PPM_TYPE;
+    if (pbmOpt)
+        cmdlineP->formatType = PBM_TYPE;
+    else if (pgmOpt)
+        cmdlineP->formatType = PGM_TYPE;
+    else if (ppmOpt)
+        cmdlineP->formatType = PPM_TYPE;
     else
-        cmdlineP->format_type = PPM_TYPE;
+        cmdlineP->formatType = PPM_TYPE;
 
     /* If any one of the 4 bounding box coordinates is given on the
        command line, we default any of the 4 that aren't.  
     */
     if (llxSpec || llySpec || urxSpec || urySpec) {
-        if (!llxSpec) cmdlineP->extract_box.llx = 72;
-        else cmdlineP->extract_box.llx = llx * 72;
-        if (!llySpec) cmdlineP->extract_box.lly = 72;
-        else cmdlineP->extract_box.lly = lly * 72;
-        if (!urxSpec) cmdlineP->extract_box.urx = 540;
-        else cmdlineP->extract_box.urx = urx * 72;
-        if (!urySpec) cmdlineP->extract_box.ury = 720;
-        else cmdlineP->extract_box.ury = ury * 72;
+        if (!llxSpec) cmdlineP->extractBox.llx = 72;
+        else cmdlineP->extractBox.llx = llx * 72;
+        if (!llySpec) cmdlineP->extractBox.lly = 72;
+        else cmdlineP->extractBox.lly = lly * 72;
+        if (!urxSpec) cmdlineP->extractBox.urx = 540;
+        else cmdlineP->extractBox.urx = urx * 72;
+        if (!urySpec) cmdlineP->extractBox.ury = 720;
+        else cmdlineP->extractBox.ury = ury * 72;
     } else {
-        cmdlineP->extract_box.llx = -1;
+        cmdlineP->extractBox.llx = -1;
     }
 
     if (dpiSpec) {
@@ -185,79 +208,93 @@ parseCommandLine(int argc, char ** argv,
     if (dpiSpec && xsizeSpec + ysizeSpec + xmaxSpec + ymaxSpec > 0)
         pm_error("You may not specify both size options and -dpi");
 
+    if (textalphabitsSpec) {
+        if (cmdlineP->textalphabits != 1 && cmdlineP->textalphabits != 2
+            && cmdlineP->textalphabits != 4) {
+            /* Pstopnm won't take this value, and we don't want to inflict
+               a Pstopnm failure error message on the user.
+            */
+            pm_error("Valid values for -textalphabits are 1, 2, and 4.  "
+                     "You specified %u", cmdlineP->textalphabits );
+        }
+    } else
+        cmdlineP->textalphabits = 4;
+
     if (argc-1 == 0)
-        cmdlineP->input_filespec = "-";  /* stdin */
+        cmdlineP->inputFileName = "-";  /* stdin */
     else if (argc-1 == 1)
-        cmdlineP->input_filespec = argv[1];
+        cmdlineP->inputFileName = argv[1];
     else 
         pm_error("Too many arguments (%d).  "
-                 "Only need one: the Postscript filespec", argc-1);
+                 "Only need one: the Postscript file name", argc-1);
+
+    free(option_def);
 }
 
 
 
 static void
-addPsToFilespec(char          const orig_filespec[],
-                const char ** const new_filespec_p,
-                bool          const verbose) {
+addPsToFileName(char          const origFileName[],
+                const char ** const newFileNameP) {
 /*----------------------------------------------------------------------------
-   If orig_filespec[] does not name an existing file, but the same
+   If origFileName[] does not name an existing file, but the same
    name with ".ps" added to the end does, return the name with the .ps
-   attached.  Otherwise, just return orig_filespec[].
+   attached.  Otherwise, just return origFileName[].
 
    Return the name in newly malloc'ed storage, pointed to by
-   *new_filespec_p.
+   *newFileNameP.
 -----------------------------------------------------------------------------*/
     struct stat statbuf;
-    int stat_rc;
+    int statRc;
 
-    stat_rc = lstat(orig_filespec, &statbuf);
+    statRc = lstat(origFileName, &statbuf);
     
-    if (stat_rc == 0)
-        *new_filespec_p = strdup(orig_filespec);
+    if (statRc == 0)
+        *newFileNameP = strdup(origFileName);
     else {
-        const char *filespec_plus_ps;
+        const char * fileNamePlusPs;
 
-        asprintfN(&filespec_plus_ps, "%s.ps", orig_filespec);
+        pm_asprintf(&fileNamePlusPs, "%s.ps", origFileName);
 
-        stat_rc = lstat(filespec_plus_ps, &statbuf);
-        if (stat_rc == 0)
-            *new_filespec_p = strdup(filespec_plus_ps);
+        statRc = lstat(fileNamePlusPs, &statbuf);
+        if (statRc == 0)
+            *newFileNameP = strdup(fileNamePlusPs);
         else
-            *new_filespec_p = strdup(orig_filespec);
-        strfree(filespec_plus_ps);
+            *newFileNameP = strdup(origFileName);
+        pm_strfree(fileNamePlusPs);
     }
     if (verbose)
-        pm_message("Input file is %s", *new_filespec_p);
+        pm_message("Input file is %s", *newFileNameP);
 }
 
 
 
 static void
-computeSizeResFromSizeSpec(unsigned int   const requestedXsize,
-                           unsigned int   const requestedYsize,
-                           unsigned int   const imageWidth,
-                           unsigned int   const imageHeight,
-                           unsigned int * const xsizeP,
-                           unsigned int * const ysizeP,
-                           unsigned int * const xresP,
-                           unsigned int * const yresP) {
+computeSizeResFromSizeSpec(unsigned int        const requestedXsize,
+                           unsigned int        const requestedYsize,
+                           unsigned int        const imageWidth,
+                           unsigned int        const imageHeight,
+                           struct Dimensions * const imageDimP) {
 
     if (requestedXsize) {
-        *xsizeP = requestedXsize;
-        *xresP = (unsigned int) (requestedXsize * 72 / imageWidth + 0.5);
+        imageDimP->xsize = requestedXsize;
+        imageDimP->xres = (unsigned int)
+            (requestedXsize * 72 / imageWidth + 0.5);
         if (!requestedYsize) {
-            *yresP = *xresP;
-            *ysizeP = (unsigned int) (imageHeight * (float)*yresP/72 + 0.5);
+            imageDimP->yres = imageDimP->xres;
+            imageDimP->ysize = (unsigned int)
+                (imageHeight * (float)imageDimP->yres/72 + 0.5);
             }
         }
 
     if (requestedYsize) {
-        *ysizeP = requestedYsize;
-        *yresP = (unsigned int) (requestedYsize * 72 / imageHeight + 0.5);
+        imageDimP->ysize = requestedYsize;
+        imageDimP->yres = (unsigned int)
+            (requestedYsize * 72 / imageHeight + 0.5);
         if (!requestedXsize) {
-            *xresP = *yresP;
-            *xsizeP = (unsigned int) (imageWidth * (float)*xresP/72 + 0.5);
+            imageDimP->xres = imageDimP->yres;
+            imageDimP->xsize = (unsigned int)
+                (imageWidth * (float)imageDimP->xres/72 + 0.5);
         }
     } 
 }
@@ -265,46 +302,40 @@ computeSizeResFromSizeSpec(unsigned int   const requestedXsize,
 
 
 static void
-computeSizeResBlind(unsigned int   const xmax,
-                    unsigned int   const ymax,
-                    unsigned int   const imageWidth,
-                    unsigned int   const imageHeight,
-                    bool           const nocrop,
-                    unsigned int * const xsizeP,
-                    unsigned int * const ysizeP,
-                    unsigned int * const xresP,
-                    unsigned int * const yresP) {
+computeSizeResBlind(unsigned int        const xmax,
+                    unsigned int        const ymax,
+                    unsigned int        const imageWidth,
+                    unsigned int        const imageHeight,
+                    bool                const nocrop,
+                    struct Dimensions * const imageDimP) {
 
     if (imageWidth == 0 || imageHeight == 0) {
-        *xresP = *yresP = 72;
+        imageDimP->xres = imageDimP->yres = 72;
     } else {
-        *xresP = *yresP = MIN(xmax * 72 / imageWidth,
-                              ymax * 72 / imageHeight);
+        imageDimP->xres = imageDimP->yres = MIN(xmax * 72 / imageWidth,
+                                                ymax * 72 / imageHeight);
     }
 
     if (nocrop) {
-        *xsizeP = xmax;
-        *ysizeP = ymax;
+        imageDimP->xsize = xmax;
+        imageDimP->ysize = ymax;
     } else {
-        *xsizeP = (unsigned int) (imageWidth * (float)*xresP / 72 + 0.5);
-        *ysizeP = (unsigned int) (imageHeight * (float)*yresP / 72 + 0.5);
+        imageDimP->xsize = (unsigned int)
+            (imageWidth * (float)imageDimP->xres / 72 + 0.5);
+        imageDimP->ysize = (unsigned int)
+            (imageHeight * (float)imageDimP->yres / 72 + 0.5);
     }
 }
 
 
 
 static void
-computeSizeRes(struct cmdlineInfo const cmdline, 
-               enum orientation   const orientation, 
-               struct box         const bordered_box,
-               unsigned int *     const xsizeP, 
-               unsigned int *     const ysizeP,
-               unsigned int *     const xresP, 
-               unsigned int *     const yresP) {
+computeSizeRes(struct CmdlineInfo  const cmdline, 
+               struct Box          const borderedBox,
+               struct Dimensions * const imageDimP) {
 /*----------------------------------------------------------------------------
-  Figure out how big the output image should be (return as
-  *xsizeP and *ysizeP) and what output device resolution Ghostscript
-  should assume (return as *xresP, *yresP).
+  Figure out how big the output image should be and what output device
+  resolution Ghostscript should assume (return as *imageDimP).
 
   A resolution number is the number of pixels per inch that the a
   printer prints.  Since we're emulating a printed page with a PNM
@@ -319,59 +350,53 @@ computeSizeRes(struct cmdlineInfo const cmdline,
   tell Ghostscript that our horizontal output device resolution is 500
   pixels per inch.
   
-  *xresP and *yresP are in dots per inch.
+  X and Y in all returned values is with respect to the image, not the
+  page.  Note that the image might be placed sideways on the page, so that
+  page X and Y would be reversed from image X and Y.
 -----------------------------------------------------------------------------*/
-    unsigned int sx, sy;
-        /* The horizontal and vertical sizes of the input image, in points
-           (1/72 inch)
-        */
-
-    if (orientation == LANDSCAPE) {
-        sx = bordered_box.ury - bordered_box.lly;
-        sy = bordered_box.urx - bordered_box.llx;
-    } else {
-        sx = bordered_box.urx - bordered_box.llx;
-        sy = bordered_box.ury - bordered_box.lly;
-    }
+    /* The horizontal and vertical sizes of the input image, in points
+       (1/72 inch)
+    */
+    unsigned int const sx = borderedBox.urx - borderedBox.llx;
+    unsigned int const sy = borderedBox.ury - borderedBox.lly;
 
     if (cmdline.dpi) {
         /* User gave resolution; we figure out output image size */
-        *xresP = *yresP = cmdline.dpi;
-        *xsizeP = (int) (cmdline.dpi * sx / 72 + 0.5);
-        *ysizeP = (int) (cmdline.dpi * sy / 72 + 0.5);
+        imageDimP->xres = imageDimP->yres = cmdline.dpi;
+        imageDimP->xsize = ROUNDU(cmdline.dpi * sx / 72.0);
+        imageDimP->ysize = ROUNDU(cmdline.dpi * sy / 72.0);
     } else  if (cmdline.xsize || cmdline.ysize) {
         if (sx == 0 || sy == 0)
             pm_error("Input image is zero size; we cannot satisfy your "
                      "produce your requested output dimensions");
         computeSizeResFromSizeSpec(cmdline.xsize, cmdline.ysize, sx, sy,
-                                   xsizeP, ysizeP, xresP, yresP);
+                                   imageDimP);
     } else
         computeSizeResBlind(cmdline.xmax, cmdline.ymax, sx, sy, cmdline.nocrop,
-                            xsizeP, ysizeP, xresP, yresP);
+                            imageDimP);
 
     if (cmdline.verbose) {
         pm_message("output is %u pixels wide X %u pixels high",
-                   *xsizeP, *ysizeP);
+                   imageDimP->xsize, imageDimP->ysize);
         pm_message("output device resolution is %u dpi horiz, %u dpi vert",
-                   *xresP, *yresP);
+                   imageDimP->xres, imageDimP->yres);
     }
 }
 
 
 
-enum postscript_language {COMMON_POSTSCRIPT, ENCAPSULATED_POSTSCRIPT};
+enum PostscriptLanguage {COMMON_POSTSCRIPT, ENCAPSULATED_POSTSCRIPT};
 
-static enum postscript_language
-languageDeclaration(char const input_filespec[],
-                    bool const verbose) {
+static enum PostscriptLanguage
+languageDeclaration(char const inputFileName[]) {
 /*----------------------------------------------------------------------------
   Return the Postscript language in which the file declares it is written.
   (Except that if the file is on Standard Input or doesn't validly declare
   a languages, just say it is Common Postscript).
 -----------------------------------------------------------------------------*/
-    enum postscript_language language;
+    enum PostscriptLanguage language;
 
-    if (streq(input_filespec, "-"))
+    if (streq(inputFileName, "-"))
         /* Can't read stdin, because we need it to remain positioned for the 
            Ghostscript interpreter to read it.
         */
@@ -380,14 +405,14 @@ languageDeclaration(char const input_filespec[],
         FILE *infile;
         char line[80];
 
-        infile = pm_openr(input_filespec);
+        infile = pm_openr(inputFileName);
 
         if (fgets(line, sizeof(line), infile) == NULL)
             language = COMMON_POSTSCRIPT;
         else {
-            const char eps_header[] = " EPSF-";
+            const char epsHeader[] = " EPSF-";
 
-            if (strstr(line, eps_header))
+            if (strstr(line, epsHeader))
                 language = ENCAPSULATED_POSTSCRIPT;
             else
                 language = COMMON_POSTSCRIPT;
@@ -404,61 +429,63 @@ languageDeclaration(char const input_filespec[],
 
 
 
-static struct box
-computeBoxToExtract(struct box const cmdline_extract_box,
-                    char       const input_filespec[],
-                    bool       const verbose) {
+static struct Box
+computeBoxToExtract(struct Box const cmdlineExtractBox,
+                    char       const inputFileName[]) {
 
-    struct box retval;
+    struct Box retval;
 
-    if (cmdline_extract_box.llx != -1)
+    if (cmdlineExtractBox.llx != -1)
         /* User told us what box to extract, so that's what we'll do */
-        retval = cmdline_extract_box;
+        retval = cmdlineExtractBox;
     else {
         /* Try to get the bounding box from the DSC %%BoundingBox
            statement (A Postscript comment) in the input.
         */
-        struct box ps_bb;  /* Box described by %%BoundingBox stmt in input */
+        struct Box psBb;  /* Box described by %%BoundingBox stmt in input */
 
-        if (streq(input_filespec, "-"))
+        if (streq(inputFileName, "-"))
             /* Can't read stdin, because we need it to remain
                positioned for the Ghostscript interpreter to read it.  
             */
-            ps_bb.llx = -1;
+            psBb.llx = -1;
         else {
-            FILE *infile;
-            int found_BB, eof;  /* logical */
-            infile = pm_openr(input_filespec);
+            FILE * ifP;
+            bool foundBb;
+            bool eof;
+
+            ifP = pm_openr(inputFileName);
             
-            found_BB = FALSE;
-            eof = FALSE;
-            while (!eof && !found_BB) {
+            for (foundBb = FALSE, eof = FALSE; !foundBb && !eof; ) {
                 char line[200];
-                
-                if (fgets(line, sizeof(line), infile) == NULL)
+                char * fgetsRc;
+
+                fgetsRc = fgets(line, sizeof(line), ifP);
+
+                if (fgetsRc == NULL)
                     eof = TRUE;
                 else {
                     int rc;
                     rc = sscanf(line, "%%%%BoundingBox: %d %d %d %d",
-                                &ps_bb.llx, &ps_bb.lly, 
-                                &ps_bb.urx, &ps_bb.ury);
+                                &psBb.llx, &psBb.lly, 
+                                &psBb.urx, &psBb.ury);
                     if (rc == 4) 
-                        found_BB = TRUE;
+                        foundBb = TRUE;
                 }
             }
-            fclose(infile);
+            fclose(ifP);
 
-            if (!found_BB) {
-                ps_bb.llx = -1;
+            if (!foundBb) {
+                psBb.llx = -1;
                 pm_message("Warning: no %%%%BoundingBox statement "
-                           "in the input or command line.\n"
+                           "in the input or command line.  "
                            "Will use defaults");
             }
         }
-        if (ps_bb.llx != -1) {
+        if (psBb.llx != -1) {
             if (verbose)
                 pm_message("Using %%%%BoundingBox statement from input.");
-            retval = ps_bb;
+            retval = psBb;
         } else { 
             /* Use the center of an 8.5" x 11" page with 1" border all around*/
             retval.llx = 72;
@@ -475,44 +502,75 @@ computeBoxToExtract(struct box const cmdline_extract_box,
 
 
 
-static enum orientation
-computeOrientation(struct cmdlineInfo const cmdline, 
-                   struct box         const extract_box) {
+static enum Orientation
+computeOrientation(struct CmdlineInfo const cmdline, 
+                   struct Box         const extractBox) {
+/*----------------------------------------------------------------------------
+   The proper orientation of the image on the page, given the user's
+   parameters 'cmdline' and the image dimensions 'extractBox'.
+-----------------------------------------------------------------------------*/
+    /* We're putting an _image_ on a _page_.  Either one can have portrait or
+       landscape aspect ratio.  In our return value, orientation just means
+       whether the image is rotated on the page: Portrait means it isn't
+       Landscape means it is.  The result can be confusing: Consider an image
+       which is a landscape, wider than it is tall, being printed on a page
+       which is also wider than it is tall.  The orientation we would return
+       for that case is Portrait.
+
+       The decision is simple: if the user didn't request a particular
+       orientation, we return the value that makes the image orientation match
+       the page orientation.  If both possibilities match equally (because the
+       image or the page is square), we return Portrait.
+    */
 
-    enum orientation retval;
-    unsigned int const input_width  = extract_box.urx - extract_box.llx;
-    unsigned int const input_height = extract_box.ury - extract_box.lly;
+    enum Orientation retval;
 
     if (cmdline.orientation != UNSPECIFIED)
         retval = cmdline.orientation;
     else {
-        if ((!cmdline.xsize || !cmdline.ysize) &
-            (cmdline.xsize || cmdline.ysize)) {
-            /* User specified one output dimension, but not the other,
-               so we can't use output dimensions to make the decision.  So
-               just use the input dimensions.
-            */
-            if (input_height > input_width) retval = PORTRAIT;
-            else retval = LANDSCAPE;
+        /* Dimensions of image to print, in points */
+        unsigned int const imageWidPt = extractBox.urx - extractBox.llx;
+        unsigned int const imageHgtPt = extractBox.ury - extractBox.lly;
+        
+        /* Dimensions of image to print, in pixels (possibly of assumed
+           resolution)
+        */
+        unsigned int imageWidXel;
+        unsigned int imageHgtXel;
+
+        /* We have to deal with the awkward case that the printed pixels are
+           not square.  We match up the aspect ratio of the image in _pixels_
+           and the aspect ratio of the page in _pixels_.  But only the ratio
+           matters; we don't care what the absolute size of the pixels is.
+           And that's good, because if the user didn't specify xsize/ysize, we
+           don't know the absolute size in pixels.  In that case, fortunately,
+           the pixels are guaranteed to be square so we can just pretend it is
+           one point per pixel and get the right result.
+        */
+
+        if (cmdline.xsize && cmdline.ysize) {
+            imageWidXel = cmdline.xsize;
+            imageHgtXel = cmdline.ysize;
         } else {
-            int output_width, output_height;
-            if (cmdline.xsize) {
-                /* He gave xsize and ysize, so that's the output size */
-                output_width = cmdline.xsize;
-                output_height = cmdline.ysize;
-            } else {
-                /* Well then we'll just use his (or default) xmax, ymax */
-                output_width = cmdline.xmax;
-                output_height = cmdline.ymax;
-            }
+            /* Pixels are square, so it doesn't matter what the resolution
+               is; just call it one pixel per point.
+            */
+            imageWidXel = imageWidPt;
+            imageHgtXel = imageHgtPt;
+        }
 
-            if (input_height > input_width && output_height > output_width)
-                retval = PORTRAIT;
-            else if (input_height < input_width && 
-                     output_height < output_width)
-                retval = PORTRAIT;
-            else 
-                retval = LANDSCAPE;
+        if (imageHgtXel >= imageWidXel && cmdline.ymax >= cmdline.xmax) {
+            /* Both image and page are higher than wide, so no rotation */
+            retval = PORTRAIT;
+        } else if (imageHgtXel < imageWidXel &&
+                   cmdline.ymax < cmdline.xmax) {
+            /* Both image and page are wider than high, so no rotation */
+            retval = PORTRAIT;
+        } else {
+            /* Image and pixel have opposite aspect ratios, so rotate
+               for best fit.
+            */
+            retval = LANDSCAPE;
         }
     }
     return retval;
@@ -520,29 +578,32 @@ computeOrientation(struct cmdlineInfo const cmdline,
 
 
 
-static struct box
-addBorders(struct box const input_box, 
-           float      const xborder_scale,
-           float      const yborder_scale,
-           bool       const verbose) {
+static struct Box
+addBorders(struct Box const inputBox, 
+           float      const xborderScale,
+           float      const yborderScale) {
 /*----------------------------------------------------------------------------
-   Return a box which is 'input_box' plus some borders.
+   Return a box which is 'inputBox' plus some borders.
 
-   Add left and right borders that are the fraction 'xborder_scale' of the
+   Add left and right borders that are the fraction 'xborderScale' of the
    width of the input box; likewise for top and bottom borders with 
-   'yborder_scale'.
+   'yborderScale'.
 -----------------------------------------------------------------------------*/
-    struct box retval;
+    unsigned int const leftRightBorderSize = 
+        ROUNDU((inputBox.urx - inputBox.llx) * xborderScale);
+    unsigned int const topBottomBorderSize = 
+        ROUNDU((inputBox.ury - inputBox.lly) * yborderScale);
+
+    struct Box retval;
+
 
-    const int left_right_border_size = 
-        (int) ((input_box.urx - input_box.llx) * xborder_scale + 0.5);
-    const int top_bottom_border_size = 
-        (int) ((input_box.ury - input_box.lly) * yborder_scale + 0.5);
+    assert(inputBox.urx >= inputBox.llx);
+    assert(inputBox.ury >= inputBox.lly);
 
-    retval.llx = input_box.llx - left_right_border_size;
-    retval.lly = input_box.lly - top_bottom_border_size;
-    retval.urx = input_box.urx + left_right_border_size;
-    retval.ury = input_box.ury + top_bottom_border_size;
+    retval.llx = inputBox.llx - (int)leftRightBorderSize;
+    retval.lly = inputBox.lly - (int)topBottomBorderSize;
+    retval.urx = inputBox.urx + (int)leftRightBorderSize;
+    retval.ury = inputBox.ury + (int)topBottomBorderSize;
 
     if (verbose)
         pm_message("With borders, extracted box is ((%d,%d),(%d,%d))",
@@ -553,65 +614,87 @@ addBorders(struct box const input_box,
 
 
 
-static const char *
-computePstrans(struct box       const box,
-               enum orientation const orientation,
-               int              const xsize,
-               int              const ysize, 
-               int              const xres,
-               int              const yres) {
+static void
+writePstrans(struct Box        const box,
+             struct Dimensions const d,
+             enum Orientation  const orientation,
+             FILE *            const pipeToGsP) {
 
-    const char * retval;
+    int const xsize = d.xsize;
+    int const ysize = d.ysize;
+    int const xres  = d.xres;
+    int const yres  = d.yres;
 
-    if (orientation == PORTRAIT) {
+    const char * pstrans;
+
+    switch (orientation) {
+    case PORTRAIT: {
         int llx, lly;
         llx = box.llx - (xsize * 72 / xres - (box.urx - box.llx)) / 2;
         lly = box.lly - (ysize * 72 / yres - (box.ury - box.lly)) / 2;
-        asprintfN(&retval, "%d neg %d neg translate", llx, lly);
-    } else {
+        pm_asprintf(&pstrans, "%d neg %d neg translate", llx, lly);
+    } break;
+    case LANDSCAPE: {
         int llx, ury;
-        llx = box.llx - (ysize * 72 / yres - (box.urx - box.llx)) / 2;
-        ury = box.ury + (xsize * 72 / xres - (box.ury - box.lly)) / 2;
-        asprintfN(&retval, "90 rotate %d neg %d neg translate", llx, ury);
+        llx = box.llx - (xsize * 72 / xres - (box.urx - box.llx)) / 2;
+        ury = box.ury + (ysize * 72 / yres - (box.ury - box.lly)) / 2;
+        pm_asprintf(&pstrans, "90 rotate %d neg %d neg translate", llx, ury);
+    } break;
+    case UNSPECIFIED:
+        assert(false);
     }
 
-    if (retval == NULL)
+    if (pstrans == pm_strsol)
         pm_error("Unable to allocate memory for pstrans");
 
-    return retval;
+    if (verbose) 
+        pm_message("Postscript prefix command: '%s'", pstrans);
+
+    fprintf(pipeToGsP, "%s\n", pstrans);
+
+    pm_strfree(pstrans);
 }
 
 
 
 static const char *
-computeOutfileArg(struct cmdlineInfo const cmdline) {
-
-    const char *retval;  /* malloc'ed */
+computeOutfileArg(struct CmdlineInfo const cmdline) {
+/*----------------------------------------------------------------------------
+   Determine the value for the "OutputFile" variable to pass to Ghostscript,
+   which is what tells Ghostscript where to put its output.  This is either
+   a pattern such as "foo%03d.ppm" or "-" to indicate Standard Output.
+
+   We go with "-" if, according to 'cmdline', the user asked for
+   Standard Output or is giving his input on Standard Input.  Otherwise,
+   we go with the pattern, based on the name of the input file and output
+   format type the user requested.
+-----------------------------------------------------------------------------*/
+    const char * retval;  /* malloc'ed */
 
-    if (cmdline.goto_stdout)
+    if (cmdline.stdoutSpec)
         retval = strdup("-");
-    else if (streq(cmdline.input_filespec, "-"))
+    else if (streq(cmdline.inputFileName, "-"))
         retval = strdup("-");
     else {
         char * basename;
         const char * suffix;
         
-        basename  = strdup(cmdline.input_filespec);
+        basename  = strdup(cmdline.inputFileName);
         if (strlen(basename) > 3 && 
             streq(basename+strlen(basename)-3, ".ps")) 
-            /* The input filespec ends in ".ps".  Chop it off. */
+            /* The input file name ends in ".ps".  Chop it off. */
             basename[strlen(basename)-3] = '\0';
 
-        switch (cmdline.format_type) {
+        switch (cmdline.formatType) {
         case PBM_TYPE: suffix = "pbm"; break;
         case PGM_TYPE: suffix = "pgm"; break;
         case PPM_TYPE: suffix = "ppm"; break;
-        default: pm_error("Internal error: invalid value for format_type: %d",
-                          cmdline.format_type);
+        default: pm_error("Internal error: invalid value for formatType: %d",
+                          cmdline.formatType);
         }
-        asprintfN(&retval, "%s%%03d.%s", basename, suffix);
+        pm_asprintf(&retval, "%s%%03d.%s", basename, suffix);
 
-        strfree(basename);
+        pm_strfree(basename);
     }
     return(retval);
 }
@@ -619,22 +702,22 @@ computeOutfileArg(struct cmdlineInfo const cmdline) {
 
 
 static const char *
-computeGsDevice(int  const format_type,
+computeGsDevice(int  const formatType,
                 bool const forceplain) {
 
     const char * basetype;
     const char * retval;
 
-    switch (format_type) {
+    switch (formatType) {
     case PBM_TYPE: basetype = "pbm"; break;
     case PGM_TYPE: basetype = "pgm"; break;
     case PPM_TYPE: basetype = "ppm"; break;
-    default: pm_error("Internal error: invalid value format_type");
+    default: pm_error("Internal error: invalid value formatType");
     }
     if (forceplain)
         retval = strdup(basetype);
     else
-        asprintfN(&retval, "%sraw", basetype);
+        pm_asprintf(&retval, "%sraw", basetype);
 
     if (retval == NULL)
         pm_error("Unable to allocate memory for gs device");
@@ -652,7 +735,7 @@ findGhostscriptProg(const char ** const retvalP) {
         *retvalP = strdup(getenv("GHOSTSCRIPT"));
     if (*retvalP == NULL) {
         if (getenv("PATH") != NULL) {
-            char *pathwork;  /* malloc'ed */
+            char * pathwork;  /* malloc'ed */
             const char * candidate;
 
             pathwork = strdup(getenv("PATH"));
@@ -665,7 +748,7 @@ findGhostscriptProg(const char ** const retvalP) {
                 const char * filename;
                 int rc;
 
-                asprintfN(&filename, "%s/gs", candidate);
+                pm_asprintf(&filename, "%s/gs", candidate);
                 rc = stat(filename, &statbuf);
                 if (rc == 0) {
                     if (S_ISREG(statbuf.st_mode))
@@ -674,7 +757,7 @@ findGhostscriptProg(const char ** const retvalP) {
                     pm_error("Error looking for Ghostscript program.  "
                              "stat(\"%s\") returns errno %d (%s)",
                              filename, errno, strerror(errno));
-                strfree(filename);
+                pm_strfree(filename);
 
                 candidate = strtok(NULL, ":");
             }
@@ -688,22 +771,26 @@ findGhostscriptProg(const char ** const retvalP) {
 
 
 static void
-execGhostscript(int  const inputPipeFd,
-                char const ghostscript_device[],
-                char const outfile_arg[], 
-                int  const xsize,
-                int  const ysize, 
-                int  const xres,
-                int  const yres,
-                char const input_filespec[],
-                bool const verbose) {
-    
+execGhostscript(int               const inputPipeFd,
+                char              const ghostscriptDevice[],
+                char              const outfileArg[], 
+                struct Dimensions const pageDim,
+                unsigned int      const textalphabits) {
+/*----------------------------------------------------------------------------
+   Exec the Ghostscript program and have it execute the Postscript program
+   that it receives on 'inputPipeFd', then exit.
+
+   'pageDim' describes the print area.  X and Y in 'pageDim' are with respect
+   to the page, independent of whether the program we receive on 'inputPipeFd'
+   puts an image in there sideways.
+-----------------------------------------------------------------------------*/
     const char * arg0;
     const char * ghostscriptProg;
     const char * deviceopt;
     const char * outfileopt;
     const char * gopt;
     const char * ropt;
+    const char * textalphabitsopt;
     int rc;
 
     findGhostscriptProg(&ghostscriptProg);
@@ -712,11 +799,12 @@ execGhostscript(int  const inputPipeFd,
     rc = dup2(inputPipeFd, STDIN_FILENO);
     close(inputPipeFd);
 
-    asprintfN(&arg0, "gs");
-    asprintfN(&deviceopt, "-sDEVICE=%s", ghostscript_device);
-    asprintfN(&outfileopt, "-sOutputFile=%s", outfile_arg);
-    asprintfN(&gopt, "-g%dx%d", xsize, ysize);
-    asprintfN(&ropt, "-r%dx%d", xres, yres);
+    pm_asprintf(&arg0, "gs");
+    pm_asprintf(&deviceopt, "-sDEVICE=%s", ghostscriptDevice);
+    pm_asprintf(&outfileopt, "-sOutputFile=%s", outfileArg);
+    pm_asprintf(&gopt, "-g%dx%d", pageDim.xsize, pageDim.ysize);
+    pm_asprintf(&ropt, "-r%dx%d", pageDim.xres, pageDim.yres);
+    pm_asprintf(&textalphabitsopt, "-dTextAlphaBits=%u", textalphabits);
 
     /* -dSAFER causes Postscript to disable %pipe and file operations,
        which are almost certainly not needed here.  This prevents our
@@ -726,14 +814,15 @@ execGhostscript(int  const inputPipeFd,
 
     if (verbose) {
         pm_message("execing '%s' with args '%s' (arg 0), "
-                   "'%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s'",
+                   "'%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s'",
                    ghostscriptProg, arg0,
-                   deviceopt, outfileopt, gopt, ropt, "-q", "-dNOPAUSE", 
+                   deviceopt, outfileopt, gopt, ropt, textalphabitsopt,
+                   "-q", "-dNOPAUSE", 
                    "-dSAFER", "-");
     }
 
-    execl(ghostscriptProg, arg0, deviceopt, outfileopt, gopt, ropt, "-q",
-          "-dNOPAUSE", "-dSAFER", "-", NULL);
+    execl(ghostscriptProg, arg0, deviceopt, outfileopt, gopt, ropt, 
+	  textalphabitsopt, "-q", "-dNOPAUSE", "-dSAFER", "-", NULL);
     
     pm_error("execl() of Ghostscript ('%s') failed, errno=%d (%s)",
              ghostscriptProg, errno, strerror(errno));
@@ -742,28 +831,126 @@ execGhostscript(int  const inputPipeFd,
 
 
 static void
-executeGhostscript(char                     const pstrans[],
-                   char                     const ghostscript_device[],
-                   char                     const outfile_arg[], 
-                   int                      const xsize,
-                   int                      const ysize, 
-                   int                      const xres,
-                   int                      const yres,
-                   char                     const input_filespec[], 
-                   enum postscript_language const language,
-                   bool                     const verbose) {
-
-    int gs_exit;  /* wait4 exit code from Ghostscript */
-    FILE *gs;  /* Pipe to Ghostscript's standard input */
-    FILE *infile;
+feedPsToGhostScript(const char *            const inputFileName,
+                    struct Box              const borderedBox,
+                    struct Dimensions       const imageDim,
+                    enum Orientation        const orientation,
+                    int                     const pipeToGhostscriptFd,
+                    enum PostscriptLanguage const language) {
+/*----------------------------------------------------------------------------
+   Send a Postscript program to the Ghostscript process running on the
+   other end of the pipe 'pipeToGhostscriptFd'.  That program is mostly
+   the contents of file 'inputFileName' (special value "-" means Standard
+   Input), but we may add a little to it.
+
+   The image has dimensions 'imageDim' and is oriented on the page according
+   to 'orientation' ('imageDim' X and Y are with respect to the image itself,
+   without regard to how it is oriented on the page).
+-----------------------------------------------------------------------------*/
+    FILE * pipeToGsP;  /* Pipe to Ghostscript's standard input */
+    FILE * ifP;
+    bool eof;  /* End of file on input */
+
+    pipeToGsP = fdopen(pipeToGhostscriptFd, "w");
+    if (pipeToGsP == NULL) 
+        pm_error("Unable to open stream on pipe to Ghostscript process.");
+    
+    ifP = pm_openr(inputFileName);
+    /*
+      In encapsulated Postscript, we the encapsulator are supposed to
+      handle showing the page (which we do by passing a showpage
+      statement to Ghostscript).  Any showpage statement in the 
+      input must be defined to have no effect.
+          
+      See "Enscapsulated PostScript Format File Specification",
+      v. 3.0, 1 May 1992, in particular Example 2, p. 21.  I found
+      it at 
+      http://partners.adobe.com/asn/developer/pdfs/tn/5002.EPSF_Spec.pdf
+      The example given is a much fancier solution than we need
+      here, I think, so I boiled it down a bit.  JM 
+    */
+    if (language == ENCAPSULATED_POSTSCRIPT)
+        fprintf(pipeToGsP, "\n/b4_Inc_state save def /showpage { } def\n");
+ 
+    writePstrans(borderedBox, imageDim, orientation, pipeToGsP);
+
+    /* If our child dies, it closes the pipe and when we next write to it,
+       we get a SIGPIPE.  We must survive that signal in order to report
+       on the fate of the child.  So we ignore SIGPIPE:
+    */
+    signal(SIGPIPE, SIG_IGN);
+
+    eof = FALSE;
+    while (!eof) {
+        char buffer[4096];
+        size_t readCt;
+            
+        readCt = fread(buffer, 1, sizeof(buffer), ifP);
+        if (readCt == 0) 
+            eof = TRUE;
+        else 
+            fwrite(buffer, 1, readCt, pipeToGsP);
+    }
+    pm_close(ifP);
+
+    if (language == ENCAPSULATED_POSTSCRIPT)
+        fprintf(pipeToGsP, "\nb4_Inc_state restore showpage\n");
+
+    fclose(pipeToGsP);
+}        
+
+
+
+static struct Dimensions
+pageDimFromImageDim(struct Dimensions const imageDim,
+                    enum Orientation  const orientation) {
+/*----------------------------------------------------------------------------
+   The dimensions of the page of an image whose dimensions are
+   'imageDim', if we place it on the page with orientation 'orientation'.
+
+   (I.e. swap and X and Y if landscape orientation).
+
+   'orientation' must not be UNSPECIFIED.
+-----------------------------------------------------------------------------*/
+    struct Dimensions retval;
+
+    switch (orientation) {
+    case PORTRAIT:
+        retval = imageDim;
+        break;
+    case LANDSCAPE:
+        retval.xsize = imageDim.ysize;
+        retval.ysize = imageDim.xsize;
+        retval.xres  = imageDim.yres;
+        retval.yres  = imageDim.xres;
+        break;
+    case UNSPECIFIED:
+        assert(false);
+        break;
+    }
+
+    return retval;
+}
+
+
+
+static void
+executeGhostscript(char                    const inputFileName[],
+                   struct Box              const borderedBox,
+                   struct Dimensions       const imageDim,
+                   enum Orientation        const orientation,
+                   char                    const ghostscriptDevice[],
+                   char                    const outfileArg[], 
+                   unsigned int            const textalphabits,
+                   enum PostscriptLanguage const language) {
+
     int rc;
-    int eof;  /* End of file on input */
     int pipefd[2];
 
-    if (strlen(outfile_arg) > 80)
+    if (strlen(outfileArg) > 80)
         pm_error("output file spec too long.");
     
-    rc = pipe(pipefd);
+    rc = pm_pipe(pipefd);
     if (rc < 0)
         pm_error("Unable to create pipe to talk to Ghostscript process.  "
                  "errno = %d (%s)", errno, strerror(errno));
@@ -775,79 +962,38 @@ executeGhostscript(char                     const pstrans[],
     else if (rc == 0) {
         /* Child process */
         close(pipefd[1]);
-        execGhostscript(pipefd[0], ghostscript_device, outfile_arg,
-                        xsize, ysize, xres, yres, input_filespec, verbose);
+        execGhostscript(pipefd[0], ghostscriptDevice, outfileArg,
+                        pageDimFromImageDim(imageDim, orientation),
+                        textalphabits);
     } else {
+        /* parent process */
         pid_t const ghostscriptPid = rc;
         int const pipeToGhostscriptFd = pipefd[1];
-        /* parent process */
-        close(pipefd[0]);
-
-        gs = fdopen(pipeToGhostscriptFd, "w");
-        if (gs == NULL) 
-            pm_error("Unable to open stream on pipe to Ghostscript process.");
-    
-        infile = pm_openr(input_filespec);
-        /*
-          In encapsulated Postscript, we the encapsulator are supposed to
-          handle showing the page (which we do by passing a showpage
-          statement to Ghostscript).  Any showpage statement in the 
-          input must be defined to have no effect.
-          
-          See "Enscapsulated PostScript Format File Specification",
-          v. 3.0, 1 May 1992, in particular Example 2, p. 21.  I found
-          it at 
-          http://partners.adobe.com/asn/developer/pdfs/tn/5002.EPSF_Spec.pdf
-          The example given is a much fancier solution than we need
-          here, I think, so I boiled it down a bit.  JM 
-        */
-        if (language == ENCAPSULATED_POSTSCRIPT)
-            fprintf(gs, "\n/b4_Inc_state save def /showpage { } def\n");
- 
-        if (verbose) 
-            pm_message("Postscript prefix command: '%s'", pstrans);
-
-        fprintf(gs, "%s\n", pstrans);
 
-        /* If our child dies, it closes the pipe and when we next write to it,
-           we get a SIGPIPE.  We must survive that signal in order to report
-           on the fate of the child.  So we ignore SIGPIPE:
-        */
-        signal(SIGPIPE, SIG_IGN);
+        int gsTermStatus;  /* termination status of Ghostscript process */
+        pid_t rc;
 
-        eof = FALSE;
-        while (!eof) {
-            char buffer[4096];
-            int bytes_read;
-            
-            bytes_read = fread(buffer, 1, sizeof(buffer), infile);
-            if (bytes_read == 0) 
-                eof = TRUE;
-            else 
-                fwrite(buffer, 1, bytes_read, gs);
-        }
-        pm_close(infile);
+        close(pipefd[0]);
 
-        if (language == ENCAPSULATED_POSTSCRIPT)
-            fprintf(gs, "\nb4_Inc_state restore showpage\n");
+        feedPsToGhostScript(inputFileName, borderedBox,
+                            imageDim, orientation,
+                            pipeToGhostscriptFd, language);
 
-        fclose(gs);
-        
-        waitpid(ghostscriptPid, &gs_exit, 0);
+        rc = waitpid(ghostscriptPid, &gsTermStatus, 0);
         if (rc < 0)
             pm_error("Wait for Ghostscript process to terminated failed.  "
                      "errno = %d (%s)", errno, strerror(errno));
 
-        if (gs_exit != 0) {
-            if (WIFEXITED(gs_exit))
+        if (gsTermStatus != 0) {
+            if (WIFEXITED(gsTermStatus))
                 pm_error("Ghostscript failed.  Exit code=%d\n", 
-                         WEXITSTATUS(gs_exit));
-            else if (WIFSIGNALED(gs_exit))
-                pm_error("Ghostscript process died due to a signal %d.",
-                         WTERMSIG(gs_exit));
+                         WEXITSTATUS(gsTermStatus));
+            else if (WIFSIGNALED(gsTermStatus))
+                pm_error("Ghostscript process died because of a signal %d.",
+                         WTERMSIG(gsTermStatus));
             else 
                 pm_error("Ghostscript process died with exit code %d", 
-                         gs_exit);
+                         gsTermStatus);
         }
     }
 }
@@ -857,65 +1003,59 @@ executeGhostscript(char                     const pstrans[],
 int
 main(int argc, char ** argv) {
 
-    struct cmdlineInfo cmdline;
-    const char * input_filespec;  /* malloc'ed */
+    struct CmdlineInfo cmdline;
+    const char * inputFileName;  /* malloc'ed */
         /* The file specification of our Postscript input file */
-    unsigned int xres, yres;    /* Resolution in pixels per inch */
-    unsigned int xsize, ysize;  /* output image size in pixels */
-    struct box extract_box;
+    struct Dimensions imageDim;
+        /* Size and resolution of the input image */
+    struct Box extractBox;
         /* coordinates of the box within the input we are to extract; i.e.
            that will become the output. 
            */
-    struct box bordered_box;
+    struct Box borderedBox;
         /* Same as above, but expanded to include borders */
 
-    enum postscript_language language;
-    enum orientation orientation;
-    const char * ghostscript_device;
-    const char * outfile_arg;
-    const char * pstrans;
+    enum PostscriptLanguage language;
+    enum Orientation orientation;
+    const char * ghostscriptDevice;
+    const char * outfileArg;
 
     pnm_init(&argc, argv);
 
     parseCommandLine(argc, argv, &cmdline);
 
-    addPsToFilespec(cmdline.input_filespec, &input_filespec, cmdline.verbose);
-
-    extract_box = computeBoxToExtract(cmdline.extract_box, input_filespec, 
-                                      cmdline.verbose);
+    verbose = cmdline.verbose;
 
-    language = languageDeclaration(input_filespec, cmdline.verbose);
-    
-    orientation = computeOrientation(cmdline, extract_box);
+    addPsToFileName(cmdline.inputFileName, &inputFileName);
 
-    bordered_box = addBorders(extract_box, cmdline.xborder, cmdline.yborder,
-                              cmdline.verbose);
+    extractBox = computeBoxToExtract(cmdline.extractBox, inputFileName);
 
-    computeSizeRes(cmdline, orientation, bordered_box, 
-                   &xsize, &ysize, &xres, &yres);
+    language = languageDeclaration(inputFileName);
+    
+    orientation = computeOrientation(cmdline, extractBox);
 
-    if (xres == 0)
-        xres = 1;
-    if (yres == 0)
-        yres = 1;
+    borderedBox = addBorders(extractBox, cmdline.xborder, cmdline.yborder);
 
-    pstrans = computePstrans(bordered_box, orientation,
-                             xsize, ysize, xres, yres);
+    computeSizeRes(cmdline, borderedBox, &imageDim);
 
-    outfile_arg = computeOutfileArg(cmdline);
+    if (imageDim.xres == 0)
+        imageDim.xres = 1;
+    if (imageDim.yres == 0)
+        imageDim.yres = 1;
+    
+    outfileArg = computeOutfileArg(cmdline);
 
-    ghostscript_device = 
-        computeGsDevice(cmdline.format_type, cmdline.forceplain);
+    ghostscriptDevice = 
+        computeGsDevice(cmdline.formatType, cmdline.forceplain);
     
-    pm_message("Writing %s file", ghostscript_device);
+    pm_message("Writing %s format", ghostscriptDevice);
     
-    executeGhostscript(pstrans, ghostscript_device, outfile_arg, 
-                       xsize, ysize, xres, yres, input_filespec,
-                       language, cmdline.verbose);
+    executeGhostscript(inputFileName, borderedBox, imageDim, orientation,
+                       ghostscriptDevice, outfileArg, cmdline.textalphabits,
+                       language);
 
-    strfree(ghostscript_device);
-    strfree(outfile_arg);
-    strfree(pstrans);
+    pm_strfree(ghostscriptDevice);
+    pm_strfree(outfileArg);
     
     return 0;
 }
diff --git a/converter/other/rast.c b/converter/other/rast.c
index 91c50ccd..1c787089 100644
--- a/converter/other/rast.c
+++ b/converter/other/rast.c
@@ -269,32 +269,71 @@ pr_dump( p, out, colormap, type, copy_flag )
     return 0;
 }
 
+
+
 int
-pr_load_header( in, hP )
-    FILE* in;
-    struct rasterfile* hP;
-{
-    if ( pm_readbiglong( in, &(hP->ras_magic) ) == -1 )
-        return PIX_ERR;
-    if ( hP->ras_magic != RAS_MAGIC )
-        return PIX_ERR;
-    if ( pm_readbiglong( in, &(hP->ras_width) ) == -1 )
-        return PIX_ERR;
-    if ( pm_readbiglong( in, &(hP->ras_height) ) == -1 )
-        return PIX_ERR;
-    if ( pm_readbiglong( in, &(hP->ras_depth) ) == -1 )
-        return PIX_ERR;
-    if ( pm_readbiglong( in, &(hP->ras_length) ) == -1 )
-        return PIX_ERR;
-    if ( pm_readbiglong( in, &(hP->ras_type) ) == -1 )
-        return PIX_ERR;
-    if ( pm_readbiglong( in, &(hP->ras_maptype) ) == -1 )
-        return PIX_ERR;
-    if ( pm_readbiglong( in, &(hP->ras_maplength) ) == -1 )
-        return PIX_ERR;
+pr_load_header(FILE * const ifP, struct rasterfile * const headerP) {
+
+    {
+        long magic;
+
+        pm_readbiglong(ifP, &magic);
+        if (magic != RAS_MAGIC)
+            pm_error("Wrong magic number for a RAST file");
+    }
+    {
+        long width;
+        pm_readbiglong(ifP, &width);
+
+        if (width < 0)
+            pm_error("Negative width in RAST header");
+        else
+            headerP->ras_width = width;
+    }
+    {
+        long height;
+        pm_readbiglong(ifP, &height);
+
+        if (height < 0)
+            pm_error("Negative height in RAST header");
+        else
+            headerP->ras_height = height;
+    }
+    {
+        long depth;
+        pm_readbiglong(ifP, &depth);
+
+        if (depth < 0)
+            pm_error("Negative depth in RAST header");
+        else
+            headerP->ras_depth = depth;
+    }
+    {
+        long length;
+        pm_readbiglong(ifP, &length);
+
+        if (length < 0)
+            pm_error("Negative length in RAST header");
+        else
+            headerP->ras_length = length;
+    }
+    pm_readbiglong(ifP, &headerP->ras_type);
+
+    pm_readbiglong(ifP, &headerP->ras_maptype);
+    {
+        long mapLength;
+        pm_readbiglong(ifP, &mapLength);
+
+        if (mapLength < 0)
+            pm_error("Negative map length in RAST header");
+        else
+            headerP->ras_maplength = mapLength;
+    }
     return 0;
 }
 
+
+
 int
 pr_load_colormap( in, hP, colormap )
     FILE* in;
diff --git a/converter/other/rast.h b/converter/other/rast.h
index e79896ea..eb6f4ec4 100644
--- a/converter/other/rast.h
+++ b/converter/other/rast.h
@@ -49,7 +49,7 @@ struct rasterfile {
 #define RMT_EQUAL_RGB	1
 #define RMT_RAW		2
     long ras_maplength;
-    };
+};
 
 struct pixrectops {
     int	(*pro_rop)();
@@ -65,21 +65,22 @@ struct pixrectops {
     int	(*pro_getcolormap)();
     int	(*pro_putattributes)();
     int	(*pro_getattributes)();
-    };
+};
 
 struct pr_size {
     int x, y;
-    };
+};
+
 struct pr_pos {
     int x, y;
-    };
+};
 
 struct pixrect {
     struct pixrectops* pr_ops;
     struct pr_size pr_size;
     int pr_depth;
     struct mpr_data* pr_data;	/* work-alike only handles memory pixrects */
-    };
+};
 
 struct mpr_data {
     int md_linebytes;
@@ -87,13 +88,13 @@ struct mpr_data {
     struct pr_pos md_offset;
     short md_primary;
     short md_flags;
-    };
+};
 
 typedef struct {
     int type;
     int length;
     unsigned char* map[3];
-    } colormap_t;
+} colormap_t;
 
 /* And the routine definitions. */
 
diff --git a/converter/other/rasttopnm.c b/converter/other/rasttopnm.c
index aa55850b..285fc5e0 100644
--- a/converter/other/rasttopnm.c
+++ b/converter/other/rasttopnm.c
@@ -10,254 +10,489 @@
 ** implied warranty.
 */
 
+#include "pm_c_util.h"
+#include "mallocvar.h"
+#include "shhopt.h"
 #include "pnm.h"
 #include "rast.h"
 
-int
-main( argc, argv )
-    int argc;
-    char* argv[];
-    {
-    FILE* ifp;
-    struct rasterfile header;
-    colormap_t pr_colormap;
-    int grayscale;
-    struct pixrect* pr;
-    xel* xelrow;
-    register xel* xP;
-    int argn, rows, cols, format, depth, i, row, mask;
-    register int col;
-    xelval maxval;
-    xel zero, one;
-    int linesize;
-    unsigned char* data;
-    unsigned char* byteP;
 
-    pnm_init( &argc, argv );
 
-    argn = 1;
+struct cmdlineInfo {
+    /* All the information the user supplied in the command line,
+       in a form easy for the program to use.
+    */
+    const char * inputFileName;
+    unsigned int index;
+    unsigned int dumpheader;
+    unsigned int dumpcolormap;
+};
+
+
+
+static void
+parseCommandLine(int argc, const char ** argv,
+                 struct cmdlineInfo * const cmdlineP) {
+/*----------------------------------------------------------------------------
+   Note that the file spec array we return is stored in the storage that
+   was passed to us as the argv array.
+-----------------------------------------------------------------------------*/
+    optEntry * option_def;
+        /* Instructions to OptParseOptions2 on how to parse our options.
+         */
+    optStruct3 opt;
+
+    unsigned int option_def_index;
 
-    if ( argn != argc )
-	{
-	ifp = pm_openr( argv[argn] );
-	++argn;
-	}
+    MALLOCARRAY_NOFAIL(option_def, 100);
+
+    option_def_index = 0;   /* incremented by OPTENT3 */
+ 
+    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 */
+
+    OPTENT3(0,   "index",        OPT_FLAG,   NULL,
+            &cmdlineP->index,          0);
+    OPTENT3(0,   "dumpheader",   OPT_FLAG,   NULL,
+            &cmdlineP->dumpheader,     0);
+    OPTENT3(0,   "dumpcolormap", OPT_FLAG,   NULL,
+            &cmdlineP->dumpcolormap,   0);
+
+    pm_optParseOptions3(&argc, (char **)argv, opt, sizeof(opt), 0);
+        /* Uses and sets argc, argv, and some of *cmdlineP and others. */
+
+    if (argc-1 == 0) 
+        cmdlineP->inputFileName = "-";
+    else if (argc-1 != 1)
+        pm_error("Program takes zero or one argument (filename).  You "
+                 "specified %d", argc-1);
     else
-	ifp = stdin;
-
-    if ( argn != argc )
-	pm_usage( "[rastfile]" );
-
-    /* Read in the rasterfile.  First the header. */
-    if ( pr_load_header( ifp, &header ) != 0 )
-	pm_error( "unable to read in rasterfile header" );
-
-    cols = header.ras_width;
-    rows = header.ras_height;
-    depth = header.ras_depth;
-
-    if ( cols <= 0 )
-	pm_error( "invalid cols: %d", cols );
-    if ( rows <= 0 )
-	pm_error( "invalid rows: %d", rows );
-
-    /* If there is a color map, read it. */
-    grayscale = 1;
-    if ( header.ras_maplength != 0 )
-	{
-	if ( pr_load_colormap( ifp, &header, &pr_colormap ) != 0 )
-	    pm_error( "unable to skip colormap data" );
-	for ( i = 0; i < header.ras_maplength / 3; ++i )
-	    if ( pr_colormap.map[0][i] != pr_colormap.map[1][i] ||
-		 pr_colormap.map[1][i] != pr_colormap.map[2][i] )
-		{
-		grayscale = 0;
-		break;
-		}
-	}
-
-    /* Check the depth and color map. */
-    switch ( depth )
-	{
-	case 1:
-	if ( header.ras_maptype == RMT_NONE && header.ras_maplength == 0 )
-	    {
-	    maxval = 1;
-	    format = PBM_TYPE;
-	    PNM_ASSIGN1( zero, maxval );
-	    PNM_ASSIGN1( one, 0 );
-	    }
-	else if ( header.ras_maptype == RMT_EQUAL_RGB &&
-		  header.ras_maplength == 6 )
-	    {
-	    if ( grayscale )
-		{
-		maxval = 255;
-		format = PGM_TYPE;
-		PNM_ASSIGN1( zero, pr_colormap.map[0][0] );
-		PNM_ASSIGN1( one, pr_colormap.map[0][1] );
-		}
-	    else
-		{
-		maxval = 255;
-		format = PPM_TYPE;
-		PPM_ASSIGN(
-		    zero, pr_colormap.map[0][0], pr_colormap.map[1][0],
-		    pr_colormap.map[2][0] );
-		PPM_ASSIGN(
-		    one, pr_colormap.map[0][1], pr_colormap.map[1][1],
-		    pr_colormap.map[2][1] );
-		}
-	    }
-	else
-	    pm_error(
-            "this depth-1 rasterfile has a non-standard colormap - "
-            "type %ld length %ld",
-            header.ras_maptype, header.ras_maplength );
-	break;
-
-	case 8:
-	if ( grayscale )
-	    {
-	    maxval = 255;
-	    format = PGM_TYPE;
-	    }
-	else if ( header.ras_maptype == RMT_EQUAL_RGB )
-	    {
-	    maxval = 255;
-	    format = PPM_TYPE;
-	    }
-	else
-	    pm_error(
-            "this depth-8 rasterfile has a non-standard colormap - "
-            "type %ld length %ld",
-            header.ras_maptype, header.ras_maplength );
-	break;
-
-	case 24:
-	case 32:
-	if ( header.ras_maptype == RMT_NONE && header.ras_maplength == 0 )
-	    ;
-	else if ( header.ras_maptype == RMT_RAW || header.ras_maplength == 768 )
-	    ;
-	else
-	    pm_error(
-            "this depth-%d rasterfile has a non-standard colormap - "
-            "type %ld length %ld",
-            depth, header.ras_maptype, header.ras_maplength );
-	maxval = 255;
-	format = PPM_TYPE;
-	break;
-
-	default:
-	pm_error(
-	    "invalid depth: %d.  Can only handle depth 1, 8, 24, or 32.",
-	    depth );
-	}
-
-    /* Now load the data.  The pixrect returned is a memory pixrect. */
-    if ( ( pr = pr_load_image( ifp, &header, NULL ) ) == NULL )
-	pm_error(
-	    "unable to read in the image from the rasterfile" );
-
-    linesize = ( (struct mpr_data*) pr->pr_data )->md_linebytes;
-    data = ( (struct mpr_data*) pr->pr_data )->md_image;
-
-    pm_close( ifp );
-
-    /* Now write out the anymap. */
-    pnm_writepnminit( stdout, cols, rows, maxval, format, 0 );
-    xelrow = pnm_allocrow( cols );
-    switch ( PNM_FORMAT_TYPE(format) )
-        {
-        case PBM_TYPE:
-        pm_message( "writing PBM file" );
+        cmdlineP->inputFileName = argv[1];
+}
+
+
+
+static bool
+colorMapIsGrayscale(colormap_t const colorMap) {
+/*----------------------------------------------------------------------------
+   The color map contains only gray.
+-----------------------------------------------------------------------------*/
+    unsigned int i;
+    bool grayscale;
+
+    for (i = 0, grayscale = true; i < colorMap.length; ++i) {
+        if (colorMap.map[0][i] != colorMap.map[1][i] ||
+            colorMap.map[1][i] != colorMap.map[2][i]) {
+            grayscale = false;
+        }
+    }
+    return grayscale;
+}
+
+
+
+static void
+analyzeImage(struct rasterfile const header,
+             colormap_t        const colorMap,
+             int *             const formatP,
+             xelval *          const maxvalP,
+             bool *            const grayscaleP,
+             xel *             const zeroP,
+             xel *             const oneP) {
+
+    bool const grayscale =
+        header.ras_maplength == 0 || colorMapIsGrayscale(colorMap);
+
+    *grayscaleP = grayscale;
+
+    switch (header.ras_depth) {
+    case 1:
+        if (header.ras_maptype == RMT_NONE && header.ras_maplength == 0) {
+            *maxvalP = 1;
+            *formatP = PBM_TYPE;
+            PNM_ASSIGN1(*zeroP, 1);
+            PNM_ASSIGN1(*oneP, 0);
+        } else if (header.ras_maptype == RMT_EQUAL_RGB &&
+                   header.ras_maplength == 6) {
+            if (grayscale) {
+                *maxvalP = 255;
+                *formatP = PGM_TYPE;
+                PNM_ASSIGN1(*zeroP, colorMap.map[0][0]);
+                PNM_ASSIGN1(*oneP, colorMap.map[0][1]);
+            } else {
+                *maxvalP = 255;
+                *formatP = PPM_TYPE;
+                PPM_ASSIGN(
+                    *zeroP, colorMap.map[0][0], colorMap.map[1][0],
+                    colorMap.map[2][0]);
+                PPM_ASSIGN(
+                    *oneP, colorMap.map[0][1], colorMap.map[1][1],
+                    colorMap.map[2][1]);
+            }
+        } else
+            pm_error(
+                "this depth-1 rasterfile has a non-standard colormap - "
+                "type %ld length %ld",
+                header.ras_maptype, header.ras_maplength);
+        break;
+
+    case 8:
+        if (grayscale) {
+            *maxvalP = 255;
+            *formatP = PGM_TYPE;
+        } else if (header.ras_maptype == RMT_EQUAL_RGB) {
+            *maxvalP = 255;
+            *formatP = PPM_TYPE;
+        } else
+            pm_error(
+                "this depth-8 rasterfile has a non-standard colormap - "
+                "type %ld length %ld",
+                header.ras_maptype, header.ras_maplength);
         break;
 
-        case PGM_TYPE:
-        pm_message( "writing PGM file" );
+    case 24:
+    case 32:
+        if (header.ras_maptype == RMT_NONE && header.ras_maplength == 0);
+        else if (header.ras_maptype == RMT_RAW || header.ras_maplength == 768);
+        else
+            pm_error(
+                "this depth-%ld rasterfile has a non-standard colormap - "
+                "type %ld length %ld",
+                header.ras_depth, header.ras_maptype, header.ras_maplength);
+        *maxvalP = 255;
+        *formatP = PPM_TYPE;
         break;
 
-        case PPM_TYPE:
-        pm_message( "writing PPM file" );
+    default:
+        pm_error("invalid depth: %ld.  Can handle only depth 1, 8, 24, or 32.",
+                 header.ras_depth);
+    }
+}
+
+
+
+static void
+reportOutputType(int const format) {
+
+    switch (PNM_FORMAT_TYPE(format)) {
+    case PBM_TYPE:
+        pm_message("writing PBM file");
+        break;
+    case PGM_TYPE:
+        pm_message("writing PGM file");
+        break;
+    case PPM_TYPE:
+        pm_message("writing PPM file");
         break;
+    default:
+        abort();
+    }
+}
+
+
+
+static void
+convertRowDepth1(const unsigned char * const rastLine,
+                 unsigned int          const cols,
+                 xel                   const zeroXel,
+                 xel                   const oneXel,
+                 xel *                 const xelrow) {
+
+    const unsigned char * byteP;
+     unsigned int col;
+    unsigned char mask;
+
+    byteP = rastLine;  /* initial value */
+
+    for (col = 0, mask = 0x80; col < cols; ++col) {
+        if (mask == 0x00) {
+            ++byteP;
+            mask = 0x80;
+        }
+        xelrow[col] = (*byteP & mask) ? oneXel : zeroXel;
+        mask = mask >> 1;
+    }
+}
+
+
+
+static void
+convertRowDepth8(const unsigned char * const lineStart,
+                 unsigned int          const cols,
+                 bool                  const colorMapped,
+                 bool                  const useIndexForColor,
+                 bool                  const grayscale,
+                 colormap_t            const colorMap,
+                 xel *                 const xelrow) {
+/*----------------------------------------------------------------------------
+   Convert a line of raster data from the RAST input to a row of raster
+   data for the PNM output.
+
+   'lineStart' is where the RAST row starts.   'xelrow' is where to put the
+   PNM row.  'cols' is the number of pixels in the row.
+
+   'colorMapped' means the RAST image is colormapped.  If so, 'colorMap'
+   is the color map from the RAST file and 'useIndexForColor' means not
+   to use that map but instead to create a PGM row of the colormap
+   _indices_.
+
+   'grayscale' means it is a grayscale image; the output is PGM.
+-----------------------------------------------------------------------------*/
+    const unsigned char * byteP;
+    unsigned int col;
+
+    byteP = lineStart; /* initial value */
+
+    for (col = 0; col < cols; ++col) {
+        if (colorMapped && !useIndexForColor) {
+            if (grayscale)
+                PNM_ASSIGN1(xelrow[col], colorMap.map[0][*byteP]);
+            else
+                PPM_ASSIGN(xelrow[col],
+                           colorMap.map[0][*byteP],
+                           colorMap.map[1][*byteP],
+                           colorMap.map[2][*byteP]);
+        } else
+            PNM_ASSIGN1(xelrow[col], *byteP);
+
+        ++byteP;
+    }
+} 
+
+
+
+static void
+convertRowRgb(const unsigned char * const lineStart,
+              unsigned int          const cols,
+              unsigned int          const depth,
+              long                  const rastType,
+              bool                  const colorMapped,
+              bool                  const useIndexForColor,
+              colormap_t            const colorMap,
+              xel *                 const xelrow) {
+
+    const unsigned char * byteP;
+    unsigned int col;
+
+    byteP = lineStart; /* initial value */
+
+    for (col = 0; col < cols; ++col) {
+        xelval r, g, b;
 
+        if (depth == 32)
+            ++byteP;
+        if (rastType == RT_FORMAT_RGB) {
+            r = *byteP++;
+            g = *byteP++;
+            b = *byteP++;
+        } else {
+            b = *byteP++;
+            g = *byteP++;
+            r = *byteP++;
+        }
+        if (colorMapped && !useIndexForColor)
+            PPM_ASSIGN(xelrow[col],
+                       colorMap.map[0][r],
+                       colorMap.map[1][g],
+                       colorMap.map[2][b]);
+        else
+            PPM_ASSIGN(xelrow[col], r, g, b);
+    }
+} 
+
+
+
+static void
+writePnm(FILE *                 const ofP,
+         const struct pixrect * const pixRectP,
+         unsigned int           const cols,
+         unsigned int           const rows,
+         xelval                 const maxval,
+         int                    const format,
+         unsigned int           const depth,
+         long                   const rastType,
+         bool                   const grayscale,
+         bool                   const colorMapped,
+         colormap_t             const colorMap,
+         xel                    const zeroXel,
+         xel                    const oneXel,
+         bool                   const useIndexForColor) {
+
+    struct mpr_data const mprData = *pixRectP->pr_data;
+
+    xel * xelrow;
+    unsigned int row;
+    unsigned char * lineStart;
+
+    pnm_writepnminit(ofP, cols, rows, maxval, format, 0);
+
+    xelrow = pnm_allocrow(cols);
+
+    reportOutputType(format);
+
+    for (row = 0, lineStart = mprData.md_image;
+         row < rows;
+         ++row, lineStart += mprData.md_linebytes) {
+
+        switch (depth) {
+        case 1:
+            convertRowDepth1(lineStart, cols, zeroXel, oneXel, xelrow);
+            break;
+        case 8:
+            convertRowDepth8(lineStart, cols, colorMapped, useIndexForColor,
+                             grayscale, colorMap, xelrow);
+            break;
+        case 24:
+        case 32:
+            convertRowRgb(lineStart, cols, depth, rastType, colorMapped,
+                          useIndexForColor, colorMap, xelrow);
+            break;
         default:
-        pm_error( "shouldn't happen" );
+            pm_error("Invalid depth value: %u", depth);
         }
+        pnm_writepnmrow(ofP, xelrow, cols, maxval, format, 0);
+    }
+}
+
+
+
+static void
+dumpHeader(struct rasterfile const header) {
+
+    const char * typeName;
+
+    switch (header.ras_type) {
+    case RT_OLD:            typeName = "old";           break;
+    case RT_STANDARD:       typeName = "standard";      break;
+    case RT_BYTE_ENCODED:   typeName = "byte encoded";  break;
+    case RT_FORMAT_RGB:     typeName = "format rgb";    break;
+    case RT_FORMAT_TIFF:    typeName = "format_tiff";   break;
+    case RT_FORMAT_IFF:     typeName = "format_iff";    break;
+    case RT_EXPERIMENTAL:   typeName = "experimental";  break;
+    default:                typeName = "???";
+    }
+
+    pm_message("type: %s (%lu)", typeName, (unsigned long)header.ras_type);
+    pm_message("%luw x %lul x %lud",
+               (unsigned long)header.ras_width,
+               (unsigned long)header.ras_height,
+               (unsigned long)header.ras_depth);
+    pm_message("raster length: %lu", (unsigned long)header.ras_length);
+
+    if (header.ras_maplength)
+        pm_message("Has color map");
+}
+
+
+
+static void
+dumpHeaderAnalysis(bool         const grayscale, 
+                   unsigned int const depth,
+                   xel          const zero, 
+                   xel          const one) {
+
+    pm_message("grayscale: %s", grayscale ? "YES" : "NO");
+
+    if (depth == 1) {
+        pm_message("Zero color: (%u,%u,%u)",
+                   PNM_GETR(zero),
+                   PNM_GETG(zero),
+                   PNM_GETB(zero));
+
+        pm_message("One color: (%u,%u,%u)",
+                   PNM_GETR(one),
+                   PNM_GETG(one),
+                   PNM_GETB(one));
+    }
+}
+
 
-    for ( row = 0; row < rows; ++row )
-	{
-	byteP = data;
-	switch ( depth )
-	    {
-	    case 1:
-	    mask = 0x80;
-	    for ( col = 0, xP = xelrow; col < cols; ++col, ++xP )
-		{
-		if ( mask == 0 )
-		    {
-		    ++byteP;
-		    mask = 0x80;
-		    }
-		*xP = ( *byteP & mask ) ? one : zero;
-		mask = mask >> 1;
-		}
-	    break;
-
-	    case 8:
-	    for ( col = 0, xP = xelrow; col < cols; ++col, ++xP )
-		{
-		if ( header.ras_maplength == 0 )
-		    PNM_ASSIGN1( *xP, *byteP );
-		else if ( grayscale )
-		    PNM_ASSIGN1( *xP, pr_colormap.map[0][*byteP] );
-		else
-		    PPM_ASSIGN(
-			*xP, pr_colormap.map[0][*byteP],
-			pr_colormap.map[1][*byteP],
-			pr_colormap.map[2][*byteP] );
-		++byteP;
-		}
-	    break;
-
-	    case 24:
-	    case 32:
-	    for ( col = 0, xP = xelrow; col < cols; ++col, ++xP )
-		{
-		register xelval r, g, b;
-
-		if ( depth == 32 )
-		    ++byteP;
-		if ( header.ras_type == RT_FORMAT_RGB )
-		    {
-		    r = *byteP++;
-		    g = *byteP++;
-		    b = *byteP++;
-		    }
-		else
-		    {
-		    b = *byteP++;
-		    g = *byteP++;
-		    r = *byteP++;
-		    }
-		if ( header.ras_maplength == 0 )
-		    PPM_ASSIGN( *xP, r, g, b );
-		else
-		    PPM_ASSIGN(
-			*xP, pr_colormap.map[0][r], pr_colormap.map[1][g],
-			pr_colormap.map[2][b] );
-		}
-	    break;
-
-	    default:
-	    pm_error( "can't happen" );
-	    }
-	data += linesize;
-	pnm_writepnmrow( stdout, xelrow, cols, maxval, format, 0 );
-	}
-
-    pm_close( stdout );
-
-    exit( 0 );
+
+static void
+dumpColorMap(colormap_t const colorMap) {
+
+    unsigned int i;
+    const char * typeName;
+
+    switch (colorMap.type) {
+    case RMT_NONE:      typeName = "NONE";      break;
+    case RMT_EQUAL_RGB: typeName = "EQUAL_RGB"; break;
+    case RMT_RAW:       typeName = "RAW";       break;
+    default:            typeName = "???";
     }
+
+    pm_message("color map type = %s (%u)", typeName, colorMap.type);
+
+    pm_message("color map size = %u", colorMap.length);
+
+    for (i = 0; i < colorMap.length; ++i)
+        pm_message("color %u: (%u, %u, %u)", i,
+                   (unsigned char)colorMap.map[0][i],
+                   (unsigned char)colorMap.map[1][i],
+                   (unsigned char)colorMap.map[2][i]);
+}
+
+
+
+int
+main(int argc, const char ** const argv) {
+
+    struct cmdlineInfo cmdline;
+    FILE * ifP;
+    struct rasterfile header;
+    colormap_t colorMap;
+    bool grayscale;
+    struct pixrect * pr;
+    int format;
+    xelval maxval;
+    xel zero, one;
+    int rc;
+
+    pm_proginit(&argc, argv);
+
+    parseCommandLine(argc, argv, &cmdline);
+
+    ifP = pm_openr(cmdline.inputFileName);
+
+    rc = pr_load_header(ifP, &header);
+    if (rc != 0 )
+        pm_error("unable to read in rasterfile header");
+
+    if (cmdline.dumpheader)
+        dumpHeader(header);
+
+    if (header.ras_maplength != 0) {
+        int rc;
+        
+        rc = pr_load_colormap(ifP, &header, &colorMap);
+        
+        if (rc != 0 )
+            pm_error("unable to read colormap from RAST file");
+
+        if (cmdline.dumpcolormap)
+            dumpColorMap(colorMap);
+    }
+
+    analyzeImage(header, colorMap, &format, &maxval, &grayscale, &zero, &one);
+
+    if (cmdline.dumpheader)
+        dumpHeaderAnalysis(grayscale, header.ras_depth, zero, one);
+
+    pr = pr_load_image(ifP, &header, NULL);
+    if (pr == NULL )
+        pm_error("unable to read in the image from the rasterfile" );
+
+    if (cmdline.index && header.ras_maplength == 0)
+        pm_error("You requested to use color map indices as colors (-index), "
+                 "but this is not a color mapped image");
+
+    writePnm(stdout, pr, header.ras_width, header.ras_height, maxval, format,
+             header.ras_depth, header.ras_type, grayscale, 
+             header.ras_maplength > 0, colorMap, zero, one, cmdline.index);
+
+    pm_close(ifP);
+    pm_close(stdout);
+
+    return 0;
+}
diff --git a/converter/other/rletopnm.c b/converter/other/rletopnm.c
index 83ada51b..99959141 100644
--- a/converter/other/rletopnm.c
+++ b/converter/other/rletopnm.c
@@ -61,19 +61,19 @@
 /*
  * Utah type declarations.
  */
-rle_hdr     hdr;
-rle_map     *colormap;
+static rle_hdr hdr;
+static rle_map * colormap;
 
 
-struct cmdlineInfo {
+struct CmdlineInfo {
     /* All the information the user supplied in the command line,
        in a form easy for the program to use.
     */
-    char *input_filename;
+    char *       inputFilename;
     unsigned int headerdump;
     unsigned int verbose;
-    char *alpha_filename;
-    bool alpha_stdout;
+    char *       alphaout;
+    bool         alphaStdout;
 };
 
 
@@ -81,15 +81,14 @@ struct cmdlineInfo {
 /*
  * Other declarations.
  */
-int     visual, maplen;
-int     width, height;
-
+static int visual, maplen;
+static int width, height;
 
 
 
 static void
 parseCommandLine(int argc, char ** argv,
-                   struct cmdlineInfo * const cmdlineP) {
+                 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
@@ -110,34 +109,34 @@ parseCommandLine(int argc, char ** argv,
     OPTENT3('v', "verbose",    OPT_FLAG,   
             NULL,                      &cmdlineP->verbose,        0);
     OPTENT3(0,   "alphaout",   OPT_STRING, 
-            &cmdlineP->alpha_filename, &alphaoutSpec,             0);
+            &cmdlineP->alphaout, &alphaoutSpec,                   0);
 
     opt.opt_table = option_def;
     opt.short_allowed = TRUE;  /* We have short (old-fashioned) options */
     opt.allowNegNum = FALSE;  /* We have no parms that are negative numbers */
 
-    optParseOptions3(&argc, argv, opt, sizeof(opt), 0);
+    pm_optParseOptions3(&argc, argv, opt, sizeof(opt), 0);
         /* Uses and sets argc, argv, and all of *cmdlineP. */
 
     if (!alphaoutSpec)
-        cmdlineP->alpha_filename = NULL;
+        cmdlineP->alphaout = NULL;
 
     if (argc - 1 == 0)
-        cmdlineP->input_filename = NULL;  /* he wants stdin */
+        cmdlineP->inputFilename = NULL;  /* he wants stdin */
     else if (argc - 1 == 1) {
         if (streq(argv[1], "-"))
-            cmdlineP->input_filename = NULL;  /* he wants stdin */
+            cmdlineP->inputFilename = NULL;  /* he wants stdin */
         else 
-            cmdlineP->input_filename = strdup(argv[1]);
+            cmdlineP->inputFilename = strdup(argv[1]);
     } else 
         pm_error("Too many arguments.  The only argument accepted "
                  "is the input file specification");
 
-    if (cmdlineP->alpha_filename && 
-        streq(cmdlineP->alpha_filename, "-"))
-        cmdlineP->alpha_stdout = TRUE;
+    if (cmdlineP->alphaout && 
+        streq(cmdlineP->alphaout, "-"))
+        cmdlineP->alphaStdout = TRUE;
     else 
-        cmdlineP->alpha_stdout = FALSE;
+        cmdlineP->alphaStdout = FALSE;
 }
 
 
@@ -167,15 +166,14 @@ reportRleGetSetupError(int const rleGetSetupRc) {
 }
 
 
-/*-----------------------------------------------------------------------------
- *                                                         Read the rle header.
- */
+
 static void 
-read_rle_header(FILE * const ifp,
-                bool   const headerDump) {
+readRleHeader(FILE * const ifP,
+              bool   const headerDump) {
+
     int rc;
     int  i;
-    hdr.rle_file = ifp;
+    hdr.rle_file = ifP;
     rc = rle_get_setup(&hdr);
     if (rc != 0)
         reportRleGetSetupError(rc);
@@ -254,12 +252,12 @@ read_rle_header(FILE * const ifp,
         for (i = 0; hdr.comments[i] != NULL; i++)
             HMSG("%s", hdr.comments[i]);
 }
-/*-----------------------------------------------------------------------------
- *                                                    Write the ppm image data.
- */
+
+
+
 static void 
-write_ppm_data(FILE * const imageout_file,
-               FILE * const alpha_file) {
+writePpmRaster(FILE * const imageoutFileP,
+               FILE * const alphaFileP) {
 
     rle_pixel ***scanlines, **scanline;
     pixval r, g, b;
@@ -341,17 +339,17 @@ write_ppm_data(FILE * const imageout_file,
         /*
          * Write the scan line.
          */
-        if (imageout_file ) 
-            ppm_writeppmrow(imageout_file, pixelrow, width, RLE_MAXVAL, 0);
-        if (alpha_file)
-            pgm_writepgmrow(alpha_file, alpharow, width, RLE_MAXVAL, 0);
+        if (imageoutFileP) 
+            ppm_writeppmrow(imageoutFileP, pixelrow, width, RLE_MAXVAL, 0);
+        if (alphaFileP)
+            pgm_writepgmrow(alphaFileP, alpharow, width, RLE_MAXVAL, 0);
 
     } /* end of for scan = 0 to height */
 
     /* Free scanline memory. */
-    for ( scan = 0; scan < height; scan++ )
-        rle_row_free( &hdr, scanlines[scan] );
-    free( scanlines );
+    for (scan = 0; scan < height; ++scan)
+        rle_row_free(&hdr, scanlines[scan]);
+    free (scanlines);
     ppm_freerow(pixelrow);
     pgm_freerow(alpharow);
 }
@@ -359,8 +357,8 @@ write_ppm_data(FILE * const imageout_file,
 
 
 static void 
-write_pgm_data(FILE * const imageout_file,
-               FILE * const alpha_file) {
+writePgmRaster(FILE * const imageoutFileP,
+               FILE * const alphaFileP) {
 /*----------------------------------------------------------------------------
    Write the PGM image data
 -----------------------------------------------------------------------------*/
@@ -397,10 +395,10 @@ write_pgm_data(FILE * const imageout_file,
             else
                 alpharow[x] = 0;
         }
-        if (imageout_file) 
-            pgm_writepgmrow(imageout_file, pixelrow, width, RLE_MAXVAL, 0);
-        if (alpha_file)
-            pgm_writepgmrow(alpha_file, alpharow, width, RLE_MAXVAL, 0);
+        if (imageoutFileP) 
+            pgm_writepgmrow(imageoutFileP, pixelrow, width, RLE_MAXVAL, 0);
+        if (alphaFileP)
+            pgm_writepgmrow(alphaFileP, alpharow, width, RLE_MAXVAL, 0);
 
         }   /* end of for scan = 0 to height */
 
@@ -414,59 +412,59 @@ write_pgm_data(FILE * const imageout_file,
 
 
 
-/*-----------------------------------------------------------------------------
- *                               Convert a Utah rle file to a pbmplus pnm file.
- */
 int
 main(int argc, char ** argv) {
 
-    struct cmdlineInfo cmdline;
-    FILE        *ifp;
-    FILE *imageout_file, *alpha_file;
-    char *fname = NULL;
+    struct CmdlineInfo cmdline;
+    FILE * ifP;
+    FILE * imageoutFileP;
+    FILE * alphaFileP;
+    char * fname;
 
     pnm_init( &argc, argv );
 
     parseCommandLine(argc, argv, &cmdline);
 
-    if ( cmdline.input_filename != NULL ) 
-        ifp = pm_openr( cmdline.input_filename );
+    fname = NULL;  /* initial value */
+
+    if (cmdline.inputFilename != NULL ) 
+        ifP = pm_openr(cmdline.inputFilename);
     else
-        ifp = stdin;
+        ifP = stdin;
 
-    if (cmdline.alpha_stdout)
-        alpha_file = stdout;
-    else if (cmdline.alpha_filename == NULL) 
-        alpha_file = NULL;
+    if (cmdline.alphaStdout)
+        alphaFileP = stdout;
+    else if (cmdline.alphaout == NULL) 
+        alphaFileP = NULL;
     else {
-        alpha_file = pm_openw(cmdline.alpha_filename);
+        alphaFileP = pm_openw(cmdline.alphaout);
     }
 
-    if (cmdline.alpha_stdout) 
-        imageout_file = NULL;
+    if (cmdline.alphaStdout) 
+        imageoutFileP = NULL;
     else
-        imageout_file = stdout;
+        imageoutFileP = stdout;
 
 
     /*
      * Open the file.
      */
     /* Initialize header. */
-    hdr = *rle_hdr_init( (rle_hdr *)NULL );
-    rle_names( &hdr, cmd_name( argv ), fname, 0 );
+    hdr = *rle_hdr_init(NULL);
+    rle_names(&hdr, cmd_name( argv ), fname, 0);
 
     /*
      * Read the rle file header.
      */
-    read_rle_header(ifp, cmdline.headerdump || cmdline.verbose);
+    readRleHeader(ifP, cmdline.headerdump || cmdline.verbose);
     if (cmdline.headerdump)
         exit(0);
 
     /* 
      * Write the alpha file header
      */
-    if (alpha_file)
-        pgm_writepgminit(alpha_file, width, height, RLE_MAXVAL, 0);
+    if (alphaFileP)
+        pgm_writepgminit(alphaFileP, width, height, RLE_MAXVAL, 0);
 
     /*
      * Write the pnm file header.
@@ -475,24 +473,24 @@ main(int argc, char ** argv) {
     case GRAYSCALE:   /* 8 bits without colormap -> pgm */
         if (cmdline.verbose)
             pm_message("Writing pgm file.");
-        if (imageout_file)
-            pgm_writepgminit(imageout_file, width, height, RLE_MAXVAL, 0);
-        write_pgm_data(imageout_file, alpha_file);
+        if (imageoutFileP)
+            pgm_writepgminit(imageoutFileP, width, height, RLE_MAXVAL, 0);
+        writePgmRaster(imageoutFileP, alphaFileP);
         break;
     default:      /* anything else -> ppm */
         if (cmdline.verbose)
             pm_message("Writing ppm file.");
-        if (imageout_file)
-            ppm_writeppminit(imageout_file, width, height, RLE_MAXVAL, 0);
-        write_ppm_data(imageout_file, alpha_file);
+        if (imageoutFileP)
+            ppm_writeppminit(imageoutFileP, width, height, RLE_MAXVAL, 0);
+        writePpmRaster(imageoutFileP, alphaFileP);
         break;
     }
    
-    pm_close(ifp);
-    if (imageout_file) 
-        pm_close( imageout_file );
-    if (alpha_file)
-        pm_close( alpha_file );
+    pm_close(ifP);
+    if (imageoutFileP) 
+        pm_close(imageoutFileP);
+    if (alphaFileP)
+        pm_close(alphaFileP);
 
     return 0;
 }
diff --git a/converter/other/sgi.h b/converter/other/sgi.h
index 3700d356..2f57f52d 100644
--- a/converter/other/sgi.h
+++ b/converter/other/sgi.h
@@ -5,7 +5,7 @@
 
 typedef struct {
     short           magic;
-    char            storage;
+    unsigned char   storage;
     char            bpc;            /* pixel size: 1 = bytes, 2 = shorts */
     unsigned short  dimension;      /* 1 = single row, 2 = B/W, 3 = RGB */
     unsigned short  xsize,          /* width in pixels */
@@ -25,9 +25,9 @@ typedef struct {
 #define STORAGE_RLE         1
 
 #define CMAP_NORMAL         0
-#define CMAP_DITHERED       1   /* not supported */
-#define CMAP_SCREEN         2   /* not supported */
-#define CMAP_COLORMAP       3   /* not supported */
+#define CMAP_DITHERED       1   /* can't handle this */
+#define CMAP_SCREEN         2   /* can't handle this */
+#define CMAP_COLORMAP       3   /* can't handle this */
 
 #endif
 
diff --git a/converter/other/sgitopnm.c b/converter/other/sgitopnm.c
index 0d26bb9c..6fd4efcf 100644
--- a/converter/other/sgitopnm.c
+++ b/converter/other/sgitopnm.c
@@ -5,6 +5,11 @@
 ** Based on the SGI image description v0.9 by Paul Haeberli (paul@sgi.comp)
 ** Available via ftp from sgi.com:graphics/SGIIMAGESPEC
 **
+** The definitive document describing the SGI image file format,
+** SGI Image File Format Version 1.00 is available from
+** ftp://ftp.sgi.com/graphics/grafica/sgiimage.html
+**
+**
 ** 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
@@ -12,314 +17,451 @@
 ** documentation.  This software is provided "as is" without express or
 ** implied warranty.
 **
-** 29Jan94: first version
-** 08Feb94: minor bugfix
-** 29Jul00: added -channel option (smar@reptiles.org)
 */
+
+
+#include <unistd.h>
+#include <limits.h>
+#include "pm_c_util.h"
+#include "mallocvar.h"
+#include "shhopt.h"
 #include "pnm.h"
 #include "sgi.h"
-#include "mallocvar.h"
-#ifndef VMS
-#include <unistd.h>
-#endif
 
-/*#define DEBUG*/
+#define MAX_ZSIZE 256
 
-#ifndef SEEK_SET
-#define SEEK_SET    0
-#endif
 
+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 */
+    unsigned int verbose;
+    unsigned int channelSpec;
+    unsigned int channel;
+};
 
-/* entry in RLE offset table */
-typedef struct {
-    long start;     /* offset in file */
-    long length;    /* length of compressed scanline */
-} TabEntry;
 
-typedef short       ScanElem;
-typedef ScanElem *  ScanLine;
-
-/* prototypes */
-static unsigned char get_byte ARGS(( FILE* f ));
-static long get_big_long ARGS((FILE *f));
-static short get_big_short ARGS((FILE *f));
-static short get_byte_as_short ARGS((FILE *f));
-static void readerr ARGS((FILE *f));
-static const char *
-compression_name(char compr);
-static void       read_bytes ARGS((FILE *ifp, int n, char *buf));
-static Header *   read_header ARGS((FILE *ifp, int channel));
-static TabEntry * read_table ARGS((FILE *ifp, int tablen));
-static ScanLine * read_channels ARGS((FILE *ifp, Header *head, TabEntry *table, short (*func) ARGS((FILE *)), int ochan ));
-static void       image_to_pnm ARGS((Header *head, ScanLine *image, xelval maxval, int channel));
-static void       rle_decompress ARGS((ScanElem *src, int srclen, ScanElem *dest, int destlen));
 
-#define WORSTCOMPR(x)   (2*(x) + 2)
+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;
+
+    MALLOCARRAY_NOFAIL(option_def, 100);
+
+    option_def_index = 0;   /* incremented by OPTENT3 */
+    OPTENT3(0, "channel",      OPT_UINT,
+            &cmdlineP->channel,
+            &cmdlineP->channelSpec,            0);
+    OPTENT3(0, "verbose",             OPT_FLAG,      NULL,
+            &cmdlineP->verbose,       0);
+    OPTENT3(0, "noverbose",           OPT_FLAG,      NULL,
+            NULL,       0);  /* backward compatibility */
+
+    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. */
+
+    free(option_def);
+
+    if (!cmdlineP->channelSpec)
+        cmdlineP->channel = MAX_ZSIZE + 1;
+            /* Invalid value; to suppress Valgrind error */
+
+    if (argc-1 < 1)
+        cmdlineP->inputFileName = "-";
+    else if (argc-1 == 1)
+        cmdlineP->inputFileName = argv[1];
+    else
+        pm_error("Program takes at most one argument:  input file name");
+}
 
 
-static short verbose = 0;
 
+/* basic I/O functions, taken from ilbmtoppm.c */
 
-int
-main(argc, argv)
-    int argc;
-    char *argv[];
-{
-    FILE *ifp;
-    int argn;
-    const char * const usage = "[-verbose] [-channel n] [sgifile]";
-    TabEntry *table = NULL;
-    ScanLine *image;
-    Header *head;
-    pixval maxval;
-    int channel = -1;
-
-    pnm_init(&argc, argv);
-
-    argn = 1;
-    while( argn < argc && argv[argn][0] == '-' && argv[argn][1] != '\0' ) {
-        if( pm_keymatch(argv[argn], "-verbose", 2) )
-            verbose++;
-        else
-        if( pm_keymatch(argv[argn], "-noverbose", 4) )
-            verbose = 0;
-        else
-        if( pm_keymatch(argv[argn], "-channel", 2) ) {
-            char *s;
-
-            ++argn;
-            if( argn >= argc )
-                pm_usage(usage);
-
-            s = argv[argn];
-            channel = strtol(argv[argn], &s, 10);
-            if( s == argv[argn] || channel < 0)
-                pm_usage(usage);
-        }
-        else
-            pm_usage(usage);
-        ++argn;
-    }
+static void
+readerr(FILE * const f) {
 
-    if( argn < argc ) {
-        ifp = pm_openr( argv[argn] );
-        argn++;
-    }
+    if (ferror(f))
+        pm_error("read error");
     else
-        ifp = stdin;
+        pm_error("premature EOF");
+}
 
-    if( argn != argc )
-        pm_usage(usage);
 
-    head = read_header(ifp, channel);
-    maxval = head->pixmax - head->pixmin;
-    if( maxval > PNM_OVERALLMAXVAL )
-        pm_error("Maximum sample value in input image (%d) is too large.  "
-                 "This program's limit is %d.",
-                 maxval, PNM_OVERALLMAXVAL);
-    if (channel >= head->zsize)
-        pm_error("channel out of range - only %d channels in image",
-            head->zsize);
-    if( head->storage != STORAGE_VERBATIM )
-        table = read_table(ifp, head->ysize * head->zsize);
-    if( head->bpc == 1 )
-        image = read_channels(ifp, head, table, get_byte_as_short, channel);
-    else
-        image = read_channels(ifp, head, table, get_big_short, channel);
 
-    image_to_pnm(head, image, (xelval)maxval, channel);
-    pm_close(ifp);
+static short
+getBigShort(FILE * const ifP) {
+
+    short s;
+
+    if (pm_readbigshort(ifP, &s) == -1)
+        readerr(ifP);
+
+    return s;
+}
+
+
+
+static long
+getBigLong(FILE * const ifP) {
+
+    long l;
+
+    if (pm_readbiglong(ifP, &l) == -1)
+        readerr(ifP);
 
-    exit(0);
+    return l;
 }
 
 
+
+static unsigned char
+getByte(FILE * const ifP) {
+
+    int i;
+
+    i = getc(ifP);
+    if (i == EOF)
+        readerr(ifP);
+
+    return (unsigned char) i;
+}
+
+
+
+static void
+readBytes(FILE * const ifP,
+          int    const n,
+          char * const buf) {
+
+    int r;
+
+    r = fread((void *)buf, 1, n, ifP);
+
+    if (r != n)
+        readerr(ifP);
+}
+
+
+
+static short
+getByteAsShort(FILE * const ifP) {
+
+    return (short)getByte(ifP);
+}
+
+
+
+static const char *
+compressionName(unsigned char const storageCode) {
+
+    switch (storageCode) {
+    case STORAGE_VERBATIM:
+        return "none";
+    case STORAGE_RLE:
+        return "RLE";
+    default:
+        return "unknown";
+    }
+}
+
+
+
+/* entry in RLE offset table */
+typedef struct {
+    long start;     /* offset in file */
+    long length;    /* length of compressed scanline */
+} TabEntry;
+
+typedef short       ScanElem;
+typedef ScanElem *  ScanLine;
+
+#define WORSTCOMPR(x)   (2*(x) + 2)
+
+
+
 static Header *
-read_header(ifp, channel)
-    FILE *ifp;
-    int channel;
-{
-    Header *head;
-
-    MALLOCVAR_NOFAIL(head);
-
-    head->magic     = get_big_short(ifp);
-    head->storage   = get_byte(ifp);
-    head->bpc       = get_byte(ifp);
-    head->dimension = get_big_short(ifp);
-    head->xsize     = get_big_short(ifp);
-    head->ysize     = get_big_short(ifp);
-    head->zsize     = get_big_short(ifp);
-    head->pixmin    = get_big_long(ifp);
-    head->pixmax    = get_big_long(ifp);
-    read_bytes(ifp, 4, head->dummy1);
-    read_bytes(ifp, 80, head->name);
-    head->colormap  = get_big_long(ifp);
-    read_bytes(ifp, 404, head->dummy2);
-
-    if( head->magic != SGI_MAGIC )
+readHeader(FILE *       const ifP,
+           bool         const outChannelSpec,
+           bool         const verbose) {
+
+    Header * headP;
+
+    MALLOCVAR_NOFAIL(headP);
+
+    headP->magic     = getBigShort(ifP);
+    headP->storage   = getByte(ifP);
+    headP->bpc       = getByte(ifP);
+    headP->dimension = getBigShort(ifP);
+    headP->xsize     = getBigShort(ifP);
+    headP->ysize     = getBigShort(ifP);
+    headP->zsize     = getBigShort(ifP);
+    if (headP->zsize > MAX_ZSIZE)
+        pm_error("Too many channels in input image: %u",
+                 (unsigned int) headP->zsize );
+    headP->pixmin    = getBigLong(ifP);
+    headP->pixmax    = getBigLong(ifP);
+    if (headP->pixmin >= headP->pixmax)
+        pm_error("Invalid sgi image header: pixmin larger than pixmax");
+    readBytes(ifP, 4, headP->dummy1);
+    readBytes(ifP, 80, headP->name);
+    headP->colormap  = getBigLong(ifP);
+    readBytes(ifP, 404, headP->dummy2);
+
+    if (headP->magic != SGI_MAGIC)
         pm_error("bad magic number - not an SGI image");
-    if( head->storage != STORAGE_VERBATIM && head->storage != STORAGE_RLE )
+    if (headP->storage != STORAGE_VERBATIM && headP->storage != STORAGE_RLE)
         pm_error("unknown compression type");
-    if( head->bpc < 1 || head->bpc > 2 )
-        pm_error("illegal precision value %d (only 1-2 allowed)", head->bpc );
-    if( head->colormap != CMAP_NORMAL )
+    if (headP->bpc < 1 || headP->bpc > 2)
+        pm_error("illegal precision value %d (only 1-2 allowed)", headP->bpc);
+    if (headP->colormap != CMAP_NORMAL)
         pm_error("non-normal pixel data of a form we don't recognize");
 
     /* adjust ysize/zsize to dimension, just to be sure */
-    switch( head->dimension ) {
+    switch (headP->dimension) {
+    case 1:
+        headP->ysize = 1;
+        break;
+    case 2:
+        headP->zsize = 1;
+        break;
+    case 3:
+        switch (headP->zsize) {
         case 1:
-            head->ysize = 1;
+            headP->dimension = 2;
             break;
         case 2:
-            head->zsize = 1;
+            if (!outChannelSpec)
+                pm_message("2-channel image, using only first channel.  "
+                           "Extract alpha channel with -channel=1");
             break;
         case 3:
-            switch( head->zsize ) {
-                case 1:
-                    head->dimension = 2;
-                    break;
-                case 2:
-                    pm_error("don\'t know how to interpret 2-channel image");
-                    break;
-                case 3:
-                    break;
-                default:
-                    if (channel < 0)
-                        pm_message("%d-channel image, using only first 3 channels", head->zsize);
-                    break;
-            }
             break;
         default:
-            pm_error("illegal dimension value %d (only 1-3 allowed)", head->dimension);
+            if (!outChannelSpec)
+                pm_message("%u-channel image, using only first 3 channels  "
+                           "Extract %s with -channel=%c",
+                            headP->zsize,
+                            headP->zsize==4 ?
+                                "alpha channel" : "additional channels",
+                            headP->zsize==4 ? '3' : 'N');
+            break;
+        }
+        break;
+    default:
+        pm_error("illegal dimension value %u (only 1-3 allowed)",
+                 headP->dimension);
     }
 
-    if( verbose ) {
-        pm_message("raster size %dx%d, %d channels", head->xsize, head->ysize, head->zsize);
-        pm_message("compression: %d = %s", head->storage, compression_name(head->storage));
-        head->name[79] = '\0';  /* just to be safe */
-        pm_message("Image name: \"%s\"", head->name);
-#ifdef DEBUG
-        pm_message("bpc: %d    dimension: %d    zsize: %d", head->bpc, head->dimension, head->zsize);
-        pm_message("pixmin: %ld    pixmax: %ld    colormap: %ld", head->pixmin, head->pixmax, head->colormap);
-#endif
+    if (verbose) {
+        pm_message("raster size %ux%u, %u channels",
+                   headP->xsize, headP->ysize, headP->zsize);
+        pm_message("compression: 0x%02x = %s",
+                   headP->storage, compressionName(headP->storage));
+        headP->name[79] = '\0';  /* just to be safe */
+        pm_message("Image name: '%s'", headP->name);
     }
 
-    return head;
+    return headP;
 }
 
 
+
 static TabEntry *
-read_table(ifp, tablen)
-    FILE *ifp;
-    int tablen;
-{
-    TabEntry *table;
-    int i;
+readTable(FILE * const ifP,
+          int    const tablen) {
 
-    MALLOCARRAY_NOFAIL(table, tablen);
+    TabEntry * table;
+    unsigned int i;
 
-#ifdef DEBUG
-    pm_message("reading offset table");
-#endif
+    MALLOCARRAY_NOFAIL(table, tablen);
 
-    for( i = 0; i < tablen; i++ )
-        table[i].start = get_big_long(ifp);
-    for( i = 0; i < tablen; i++ )
-        table[i].length = get_big_long(ifp);
+    for (i = 0; i < tablen; ++i)
+        table[i].start = getBigLong(ifP);
+    for (i = 0; i < tablen; ++i)
+        table[i].length = getBigLong(ifP);
 
     return table;
 }
 
 
 
+static void
+rleDecompress(ScanElem * const srcStart,
+              int        const srcleftStart,
+              ScanElem * const destStart,
+              int        const destleftStart) {
+
+    ScanElem * src;
+    int srcleft;
+    ScanElem * dest;
+    int destleft;
+
+    for (src = srcStart,
+             srcleft = srcleftStart,
+             dest = destStart,
+             destleft = destleftStart; srcleft; ) {
+
+        unsigned char const el = (unsigned char)(*src++ & 0xff);
+        unsigned int const count = (unsigned int)(el & 0x7f);
+
+        --srcleft;
+
+        if (count == 0)
+            return;
+        if (destleft < count)
+            pm_error("RLE error: too much input data "
+                     "(space left %d, need %d)", destleft, count);
+        destleft -= count;
+        if (el & 0x80) {
+            unsigned int i;
+            if (srcleft < count)
+                pm_error("RLE error: not enough data for literal run "
+                         "(data left %d, need %d)", srcleft, count);
+            srcleft -= count;
+            for (i = 0; i < count; ++i)
+                *dest++ = *src++;
+        } else {
+            unsigned int i;
+            if (srcleft == 0)
+                pm_error("RLE error: not enough data for replicate run");
+            for (i = 0; i < count; ++i)
+                *dest++ = *src;
+            ++src;
+            --srcleft;
+        }
+    }
+    pm_error("RLE error: no terminating 0-byte");
+}
+
+
+
 static ScanLine *
-read_channels(ifp, head, table, func, ochan)
-    FILE *ifp;
-    Header *head;
-    TabEntry *table;
-    short (*func) ARGS((FILE *));
-    int ochan;
-{
-    ScanLine *image;
-    ScanElem *temp;
-    int channel, maxchannel, row, sgi_index, i;
-    long offset, length;
-
-#ifdef DEBUG
-    pm_message("reading channels");
-#endif
-
-    if (ochan < 0) {
-        maxchannel = (head->zsize < 3) ? head->zsize : 3;
-        MALLOCARRAY_NOFAIL(image, head->ysize * maxchannel);
-    } else {
-        maxchannel = ochan + 1;
+readChannels(FILE *       const ifP,
+             Header *     const head,
+             TabEntry *   const table,
+             bool         const outChannelSpec,
+             unsigned int const outChannel) {
+
+    ScanLine * image;
+    ScanElem * temp;
+    unsigned int channel;
+    unsigned int maxchannel;
+
+    if (outChannelSpec) {
+        maxchannel = outChannel + 1;
+        MALLOCARRAY_NOFAIL(image, head->ysize);
+    } else if (head->zsize <= 2) {
+        maxchannel = 1;
         MALLOCARRAY_NOFAIL(image, head->ysize);
+    } else {
+        maxchannel = 3;
+        MALLOCARRAY_NOFAIL(image, head->ysize * maxchannel);
     }
-    if ( table ) 
+    if (table)
         MALLOCARRAY_NOFAIL(temp, WORSTCOMPR(head->xsize));
 
-    for( channel = 0; channel < maxchannel;  channel++ ) {
-#ifdef DEBUG
-        pm_message("    channel %d", channel);
-#endif
-        for( row = 0; row < head->ysize; row++ ) {
-            int iindex;
+    for (channel = 0; channel < maxchannel; ++channel) {
+        unsigned int row;
+        for (row = 0; row < head->ysize; ++row) {
+            int const sgiIndex = channel * head->ysize + row;
+
+            unsigned long int iindex;
 
-            sgi_index = channel * head->ysize + row;
-            iindex = (ochan < 0) ? sgi_index : row;
-            if (ochan < 0 || ochan == channel)
+            iindex = outChannelSpec ? row : sgiIndex;
+            if (!outChannelSpec || outChannel == channel)
                 MALLOCARRAY_NOFAIL(image[iindex], head->xsize);
 
-            if( table ) {
-                if (channel < ochan)
-                    continue;
-
-                offset = table[sgi_index].start;
-                length = table[sgi_index].length;
-                if( head->bpc == 2 )
-                    length /= 2;   
-                    /* doc says length is in bytes, we are reading words */
-                if( fseek(ifp, offset, SEEK_SET) != 0 )
-                    pm_error("seek error for offset %ld", offset);
-
-                for( i = 0; i < length; i++ )
-                    temp[i] = (*func)(ifp);
-                rle_decompress(temp, length, image[iindex], head->xsize);
-            }
-            else {
-                for( i = 0; i < head->xsize; i++ )
-                    image[iindex][i] = (*func)(ifp);
+            if (table) {
+                if (!outChannelSpec || channel >= outChannel) {
+                    pm_filepos const offset = (pm_filepos)
+                        table[sgiIndex].start;
+                    long const length = head->bpc == 2 ?
+                        table[sgiIndex].length / 2 :
+                        table[sgiIndex].length;
+
+                    unsigned int i;
+
+                    /* Note: (offset < currentPosition) can happen */
+
+                    pm_seek2(ifP, &offset, sizeof(offset));
+
+                    for (i = 0; i < length; ++i)
+                        if (head->bpc == 1)
+                            temp[i] = getByteAsShort(ifP);
+                        else
+                            temp[i] = getBigShort(ifP);
+                    rleDecompress(temp, length, image[iindex], head->xsize);
+                }
+            } else {
+                unsigned int i;
+                for (i = 0; i < head->xsize; ++i) {
+                    ScanElem p;
+                    if (head->bpc == 1)
+                        p = getByteAsShort(ifP);
+                    else
+                        p = getBigShort(ifP);
+
+                    if (!outChannelSpec || outChannel == channel)
+                        image[iindex][i] = p;
+                }
             }
         }
     }
-
-    if( table ) free(temp);
+    if (table)
+        free(temp);
     return image;
 }
 
 
+
 static void
-image_to_pnm(Header *head, ScanLine *image, xelval maxval, int channel)
-{
-    int col, row, format;
-    xel *pnmrow = pnm_allocrow(head->xsize);
-    int sub = head->pixmin;
+imageToPnm(Header   *   const head,
+           ScanLine *   const image,
+           xelval       const maxval,
+           bool         const outChannelSpec,
+           unsigned int const outChannel) {
+
+    int const sub = head->pixmin;
+    xel * const pnmrow = pnm_allocrow(head->xsize);
+
+    int row;
+    int format;
 
-    if( head->zsize == 1 || channel >= 0) {
+    if (head->zsize <= 2 || outChannelSpec) {
         pm_message("writing PGM image");
         format = PGM_TYPE;
-    }
-    else {
+    } else {
         pm_message("writing PPM image");
         format = PPM_TYPE;
     }
 
-    pnm_writepnminit(stdout, head->xsize, head->ysize, (xelval)maxval, format, 0);
-    for( row = head->ysize-1; row >= 0; row-- ) {
-        for( col = 0; col < head->xsize; col++ ) {
-            if( format == PGM_TYPE )
+    pnm_writepnminit(stdout, head->xsize, head->ysize, maxval, format, 0);
+    for (row = head->ysize-1; row >= 0; --row) {
+        unsigned int col;
+        for (col = 0; col < head->xsize; ++col) {
+            if (format == PGM_TYPE)
                 PNM_ASSIGN1(pnmrow[col], image[row][col] - sub);
             else {
                 pixval r, g, b;
@@ -329,135 +471,54 @@ image_to_pnm(Header *head, ScanLine *image, xelval maxval, int channel)
                 PPM_ASSIGN(pnmrow[col], r, g, b);
             }
         }
-        pnm_writepnmrow(stdout, pnmrow, head->xsize, (xelval)maxval, format, 0);
+        pnm_writepnmrow(stdout, pnmrow, head->xsize, maxval, format, 0);
     }
     pnm_freerow(pnmrow);
 }
 
 
-static void
-rle_decompress(src, srcleft, dest, destleft)
-    ScanElem *src;
-    int srcleft;
-    ScanElem *dest;
-    int destleft;
-{
-    int count;
-    unsigned char el;
-
-    while( srcleft ) {
-        el = (unsigned char)(*src++ & 0xff);
-        --srcleft;
-        count = (int)(el & 0x7f);
 
-        if( count == 0 )
-            return;
-        if( destleft < count )
-            pm_error("RLE error: too much input data (space left %d, need %d)", destleft, count);
-        destleft -= count;
-        if( el & 0x80 ) {
-            if( srcleft < count )
-                pm_error("RLE error: not enough data for literal run (data left %d, need %d)", srcleft, count);
-            srcleft -= count;
-            while( count-- )
-                *dest++ = *src++;
-        }
-        else {
-            if( srcleft == 0 )
-                pm_error("RLE error: not enough data for replicate run");
-            while( count-- )
-                *dest++ = *src;
-            ++src;
-            --srcleft;
-        }
-    }
-    pm_error("RLE error: no terminating 0-byte");
-}
-
-
-/* basic I/O functions, taken from ilbmtoppm.c */
-
-static short
-get_big_short(ifp)
-    FILE *ifp;
-{
-    short s;
-
-    if( pm_readbigshort(ifp, &s) == -1 )
-        readerr(ifp);
-
-    return s;
-}
+int
+main(int argc, const char * argv[]) {
 
-static long
-get_big_long(ifp)
-    FILE *ifp;
-{
-    long l;
+    struct CmdlineInfo cmdline;
+    FILE * ifP;
+    TabEntry * table;
+    ScanLine * image;
+    Header * headP;
+    xelval maxval;
 
-    if( pm_readbiglong(ifp, &l) == -1 )
-        readerr(ifp);
+    pm_proginit(&argc, argv);
 
-    return l;
-}
+    parseCommandLine(argc, argv, &cmdline);
 
-static unsigned char
-get_byte(ifp)
-    FILE* ifp;
-{
-    int i;
+    ifP = pm_openr_seekable(cmdline.inputFileName);
 
-    i = getc(ifp);
-    if( i == EOF )
-        readerr(ifp);
+    headP = readHeader(ifP, cmdline.channelSpec, cmdline.verbose);
 
-    return (unsigned char) i;
-}
+    maxval = headP->pixmax - headP->pixmin;
+    if (maxval > PNM_OVERALLMAXVAL)
+        pm_error("Maximum sample value in input image (%d) is too large.  "
+                 "This program's limit is %d.",
+                 maxval, PNM_OVERALLMAXVAL);
 
+    if (cmdline.channelSpec && cmdline.channel >= headP->zsize)
+        pm_error("channel out of range - only %d channels in image",
+                 headP->zsize);
 
-static void
-readerr(f)
-    FILE *f;
-{
-    if( ferror(f) )
-        pm_error("read error");
+    if (headP->storage != STORAGE_VERBATIM)
+        table = readTable(ifP, headP->ysize * headP->zsize);
     else
-        pm_error("premature EOF");
-}
-
+        table = NULL;
 
-static void
-read_bytes(ifp, n, buf)
-    FILE *ifp;
-    int n;
-    char *buf;
-{
-    int r;
+    image = readChannels(ifP, headP, table,
+                         cmdline.channelSpec, cmdline.channel);
 
-    r = fread((void *)buf, 1, n, ifp);
-    if( r != n )
-        readerr(ifp);
-}
+    imageToPnm(headP, image, maxval, cmdline.channelSpec, cmdline.channel);
 
+    pm_close(ifP);
 
-static short
-get_byte_as_short(ifp)
-    FILE *ifp;
-{
-    return (short)get_byte(ifp);
+    return 0;
 }
 
 
-static const char *
-compression_name(char compr)
-{
-    switch( compr ) {
-        case STORAGE_VERBATIM:
-            return "none";
-        case STORAGE_RLE:
-            return "RLE";
-        default:
-            return "unknown";
-    }
-}
-
diff --git a/converter/other/srf.c b/converter/other/srf.c
new file mode 100644
index 00000000..b0f97242
--- /dev/null
+++ b/converter/other/srf.c
@@ -0,0 +1,653 @@
+/*
+ * Funcs for working with SRF (Garmin vehicle) files
+ *
+ * Written by Mike Frysinger <vapier@gentoo.org>
+ * Released into the public domain
+ */
+
+#include <stdio.h>
+
+#include "pm_c_util.h"
+#include "mallocvar.h"
+#include "nstring.h"
+#include "srf.h"
+
+
+static unsigned char
+csumRaw(void * const p,
+       size_t const len) {
+
+    unsigned char retval;
+
+    unsigned int i;
+    unsigned char * c;
+
+    for (i = 0, retval = 0, c = p; i < len; ++i)
+        retval += *c++;
+    
+    return retval;
+}
+
+
+
+static unsigned char
+csumPstring(struct srf_pstring * const pstringP) {
+
+  return
+      csumRaw(&pstringP->len, 4) + csumRaw(pstringP->val, pstringP->len);
+}
+
+
+
+static bool
+readPstring(FILE *               const ifP,
+            struct srf_pstring * const pstringP) {
+
+    size_t bytesRead;
+
+    pm_readlittlelong2u(ifP, &pstringP->len);
+
+    MALLOCARRAY(pstringP->val, pstringP->len + 1);
+
+    if (!pstringP->val)
+        pm_error("Failed to allocate buffer to read %u-byte pstring",
+                 pstringP->len);
+
+    bytesRead = fread(pstringP->val, 1, pstringP->len, ifP);
+    if (bytesRead != pstringP->len)
+        pm_error("Failed to read pstring.  Requested %u bytes, got %u",
+                 (unsigned)pstringP->len,  (unsigned)bytesRead);
+
+    pstringP->val[pstringP->len] = '\0';
+
+    return true;
+}
+
+
+
+static bool
+writePstring(FILE *               const ofP,
+             struct srf_pstring * const pstringP) {
+
+    bool retval;
+    size_t bytesWritten;
+
+    pm_writelittlelongu(ofP, pstringP->len);
+
+    bytesWritten = fwrite(pstringP->val, 1, pstringP->len, ofP);
+
+    if (bytesWritten == pstringP->len)
+        retval = true;
+    else
+        retval = false;
+
+    return retval;
+}
+
+
+
+static size_t
+lenHeader(struct srf_header * const headerP) {
+
+    return 16 + (4 * 4) + 4 + headerP->s578.len
+        + 4 + 4 + headerP->ver.len
+        + 4 + 4 + headerP->prod.len;
+}
+
+
+
+static unsigned char
+csumHeader(struct srf_header * const headerP) {
+
+    return
+        csumRaw(headerP->magic, 16) +
+        csumRaw(&headerP->_int4, 2 * 4) +
+        csumRaw(&headerP->img_cnt, 4) +
+        csumRaw(&headerP->_int5, 4) +
+        csumPstring(&headerP->s578) +
+        csumRaw(&headerP->_int6, 4) +
+        csumPstring(&headerP->ver) +
+        csumRaw(&headerP->_int7, 4) +
+        csumPstring(&headerP->prod);
+}
+
+
+
+static bool
+readHeader(FILE *              const ifP,
+           struct srf_header * const headerP) {
+
+    bool const retval =
+        fread(headerP->magic, 1, 16, ifP) == 16 &&
+        pm_readlittlelong2u(ifP, &headerP->_int4[0]) == 0 &&
+        pm_readlittlelong2u(ifP, &headerP->_int4[1]) == 0 &&
+        pm_readlittlelong2u(ifP, &headerP->img_cnt) == 0 &&
+        pm_readlittlelong2u(ifP, &headerP->_int5) == 0 &&
+        readPstring(ifP, &headerP->s578) &&
+        pm_readlittlelong2u(ifP, &headerP->_int6) == 0 &&
+        readPstring(ifP, &headerP->ver) &&
+        pm_readlittlelong2u(ifP, &headerP->_int7) == 0 &&
+        readPstring(ifP, &headerP->prod);
+
+    headerP->magic[16] = '\0';
+
+    return retval;
+}
+
+
+
+static bool
+writeHeader(FILE *              const ofP,
+            struct srf_header * const headerP) {
+
+    return
+        fwrite(headerP->magic, 1, 16, ofP) == 16 &&
+        pm_writelittlelongu(ofP, headerP->_int4[0]) == 0 &&
+        pm_writelittlelongu(ofP, headerP->_int4[1]) == 0 &&
+        pm_writelittlelongu(ofP, headerP->img_cnt) == 0 &&
+        pm_writelittlelongu(ofP, headerP->_int5) == 0 &&
+        writePstring(ofP, &headerP->s578) &&
+        pm_writelittlelongu(ofP, headerP->_int6) == 0 &&
+        writePstring(ofP, &headerP->ver) &&
+        pm_writelittlelongu(ofP, headerP->_int7) == 0 &&
+        writePstring(ofP, &headerP->prod);
+}
+
+
+
+static bool
+checkHeader(struct srf_header * const headerP) {
+
+    return
+        streq(headerP->magic, SRF_MAGIC) &&
+        headerP->_int4[0] == 4 &&
+        headerP->_int4[1] == 4 &&
+        /* Should we require img_cnt to be multiple of 2 ? */
+        headerP->img_cnt > 0 &&
+        headerP->_int5 == 5 &&
+        headerP->s578.len == 3 &&
+        strcmp(headerP->s578.val, "578") == 0 &&
+        headerP->_int6 == 6 &&
+        headerP->ver.len == 4 &&
+        /* Allow any headerP->ver value */
+        headerP->_int7 == 7 &&
+        headerP->prod.len == 12;
+    /* Allow any headerP->prod value */
+}
+
+
+
+static size_t
+lenImg(struct srf_img * const imgP) {
+
+    return
+        (4 * 3) + (2 * 2) + (1 * 2) + 2 + 4 +
+        4 + 4 + imgP->alpha.data_len +
+        4 + 4 + imgP->data.data_len;
+}
+
+
+
+static unsigned char
+csumImg(struct srf_img * const imgP) {
+
+    struct srf_img_header * const headerP = &imgP->header;
+    struct srf_img_alpha *  const alphaP  = &imgP->alpha;
+    struct srf_img_data *   const dataP   = &imgP->data;
+
+    return
+        csumRaw(&headerP->_ints, 4 * 3) +
+        csumRaw(&headerP->height, 2) +
+        csumRaw(&headerP->width, 2) +
+        csumRaw(headerP->_bytes, 2) +
+        csumRaw(&headerP->line_len, 2) +
+        csumRaw(&headerP->zeros, 4) +
+        csumRaw(&alphaP->type, 4) +
+        csumRaw(&alphaP->data_len, 4) +
+        csumRaw(alphaP->data, alphaP->data_len) +
+        csumRaw(&dataP->type, 4) +
+        csumRaw(&dataP->data_len, 4) +
+        csumRaw(dataP->data, dataP->data_len);
+}
+
+
+
+static bool
+readImgHeader(FILE *                  const ifP,
+              struct srf_img_header * const headerP) {
+    return
+        pm_readlittlelong2u(ifP, &headerP->_ints[0]) == 0 &&
+        pm_readlittlelong2u(ifP, &headerP->_ints[1]) == 0 &&
+        pm_readlittlelong2u(ifP, &headerP->_ints[2]) == 0 &&
+        pm_readlittleshortu(ifP, &headerP->height) == 0 &&
+        pm_readlittleshortu(ifP, &headerP->width) == 0 &&
+        fread(&headerP->_bytes[0], 1, 1, ifP) == 1 &&
+        fread(&headerP->_bytes[1], 1, 1, ifP) == 1 &&
+        pm_readlittleshortu(ifP, &headerP->line_len) == 0 &&
+        pm_readlittlelong2u(ifP, &headerP->zeros) == 0;
+}
+
+
+
+static bool
+writeImgHeader(FILE *                  const ofP,
+               struct srf_img_header * const headerP) {
+    return
+        pm_writelittlelongu(ofP, headerP->_ints[0]) == 0 &&
+        pm_writelittlelongu(ofP, headerP->_ints[1]) == 0 &&
+        pm_writelittlelongu(ofP, headerP->_ints[2]) == 0 &&
+        pm_writelittleshortu(ofP, headerP->height) == 0 &&
+        pm_writelittleshortu(ofP, headerP->width) == 0 &&
+        fwrite(&headerP->_bytes[0], 1, 1, ofP) == 1 &&
+        fwrite(&headerP->_bytes[1], 1, 1, ofP) == 1 &&
+        pm_writelittleshortu(ofP, headerP->line_len) == 0 &&
+        pm_writelittlelongu(ofP, headerP->zeros) == 0;
+}
+
+
+
+static bool
+checkImgHeader(struct srf_img_header * const headerP) {
+
+    return
+        headerP->_ints[0] == 0 &&
+        headerP->_ints[1] == 16 &&
+        headerP->_ints[2] == 0 &&
+        headerP->_bytes[0] == 16 &&
+        headerP->_bytes[1] == 8 &&
+        headerP->line_len == headerP->width * 2 &&
+        headerP->zeros == 0;
+}
+
+
+
+static bool
+readImgAlpha(FILE *                 const ifP,
+                   struct srf_img_alpha * const alphaP) {
+
+    bool retval;
+
+    pm_readlittlelong2u(ifP, &alphaP->type);
+    pm_readlittlelong2u(ifP, &alphaP->data_len);
+
+    MALLOCARRAY(alphaP->data, alphaP->data_len);
+
+    if (!alphaP->data)
+        retval = false;
+    else {
+        size_t bytesRead;
+
+        bytesRead = fread(alphaP->data, 1, alphaP->data_len, ifP);
+        retval = (bytesRead ==alphaP->data_len);
+    }
+    return retval;
+}
+
+
+
+static bool
+writeImageAlpha(FILE *                 const ofP,
+                    struct srf_img_alpha * const alphaP) {
+
+    return
+        pm_writelittlelongu(ofP, alphaP->type) == 0 &&
+        pm_writelittlelongu(ofP, alphaP->data_len) == 0 &&
+        fwrite(alphaP->data, 1, alphaP->data_len, ofP) == alphaP->data_len;
+}
+
+
+
+static bool
+checkImgAlpha(struct srf_img_alpha * const alphaP) {
+
+    return (alphaP->type == 11);
+}
+
+
+
+static bool
+readImgData(FILE *                const ifP,
+                  struct srf_img_data * const dataP) {
+
+    bool retval;
+
+    pm_readlittlelong2u(ifP, &dataP->type);
+    pm_readlittlelong2u(ifP, &dataP->data_len);
+
+    MALLOCARRAY(dataP->data, dataP->data_len / 2);
+
+    if (!dataP->data)
+        retval = false;
+    else {
+        size_t bytesRead;
+        bytesRead = fread(dataP->data, 2, dataP->data_len / 2, ifP);
+
+        retval = (bytesRead == dataP->data_len / 2);
+    }
+    return retval;
+}
+
+
+
+static bool
+writeImgData(FILE *                const ofP,
+                   struct srf_img_data * const dataP) {
+
+    return
+        pm_writelittlelongu(ofP, dataP->type) == 0 &&
+        pm_writelittlelongu(ofP, dataP->data_len) == 0 &&
+        fwrite(dataP->data, 2, dataP->data_len / 2, ofP)
+        == dataP->data_len / 2;
+}
+
+
+
+static bool
+checkImgData(struct srf_img_data * const dataP) {
+  return dataP->type == 1;
+}
+
+
+
+static bool
+readImg(FILE *           const ifP,
+             bool             const verbose,
+             uint32_t         const i,
+             struct srf_img * const imgP) {
+
+    if (!readImgHeader(ifP, &imgP->header))
+        pm_error("short srf image %u header", i);
+    if (!checkImgHeader(&imgP->header))
+        pm_error("invalid srf image %u header", i);
+
+    if (verbose)
+        pm_message("reading srf 16-bit RGB %ux%u image %u",
+                   imgP->header.width, imgP->header.height, i);
+
+    if (!readImgAlpha(ifP, &imgP->alpha))
+        pm_error("short srf image %u alpha mask", i);
+    if (!checkImgAlpha(&imgP->alpha))
+        pm_error("invalid srf image %u alpha mask", i);
+
+    if (!readImgData(ifP, &imgP->data))
+        pm_error("short srf image %u data", i);
+    if (!checkImgData(&imgP->data))
+        pm_error("invalid srf image %u data", i);
+
+    return true;
+}
+
+
+
+static bool
+writeImg(FILE *           const ofP,
+              uint32_t         const i,
+              struct srf_img * const imgP) {
+
+    if (!checkImgHeader(&imgP->header))
+        pm_error("invalid srf image %u header", i);
+    if (!writeImgHeader(ofP, &imgP->header))
+        pm_error("short srf image %u header", i);
+
+    if (!checkImgAlpha(&imgP->alpha))
+        pm_error("invalid srf image %u alpha mask", i);
+    if (!writeImageAlpha(ofP, &imgP->alpha))
+        pm_error("short srf image %u alpha mask", i);
+
+    if (!checkImgData(&imgP->data))
+        pm_error("invalid srf image %u data", i);
+    if (!writeImgData(ofP, &imgP->data))
+        pm_error("short srf image %u data", i);
+
+    return true;
+}
+
+
+
+static uint8_t
+csum(struct srf * const srfP,
+     size_t       const padLen) {
+/*----------------------------------------------------------------------------
+   The sum of everything in the SRF image except the checksum byte.  The
+   checksum byte is supposed to be the arithmetic opposite of this so that the
+   sum of everything is zero.
+-----------------------------------------------------------------------------*/
+    unsigned char retval;
+    unsigned int i;
+
+    retval = csumHeader(&srfP->header);
+
+    for (i = 0; i < srfP->header.img_cnt; ++i)
+        retval += csumImg(&srfP->imgs[i]);
+    
+    for (i = 0; i < padLen; ++i)
+        retval += 0xff;
+    
+    return retval;
+}
+
+
+
+void
+srf_read(FILE *       const ifP,
+         bool         const verbose,
+         struct srf * const srfP) {
+
+    uint8_t       trialCsum;
+    size_t        padLen;
+    unsigned char pad[256];
+    unsigned int  i;
+
+    if (!readHeader(ifP, &srfP->header))
+        pm_error("short srf header");
+    if (!checkHeader(&srfP->header))
+        pm_error("invalid srf header");
+
+    if (verbose)
+        pm_message("reading srf ver %s with prod code %s and %u images",
+                   srfP->header.ver.val, srfP->header.prod.val,
+                   srfP->header.img_cnt);
+
+    MALLOCARRAY(srfP->imgs, srfP->header.img_cnt);
+
+    if (!srfP->imgs)
+        pm_error("Could not allocate memory for %u images",
+                 srfP->header.img_cnt);
+
+    for (i = 0; i < srfP->header.img_cnt; ++i)
+        if (!readImg(ifP, verbose, i, &srfP->imgs[i]))
+            pm_error("invalid srf image %u", i);
+
+    padLen = fread(pad, 1, sizeof(pad), ifP);
+    if (!feof(ifP)) {
+        pm_errormsg("excess data at end of file");
+        return;
+    }
+
+    trialCsum = csum(srfP, 0);  /* initial value */
+    for (i = 0; i < padLen; ++i)
+        trialCsum += pad[i];
+    if (trialCsum != 0)
+        pm_errormsg("checksum does not match");
+}
+
+
+
+void
+srf_write(FILE *       const ofP,
+          struct srf * const srfP) {
+
+    uint8_t      srfCsum;    /* checksum value in SRF image */
+    size_t       padLen;
+    unsigned int i;
+    size_t       bytesWritten;
+
+    padLen = 1;  /* initial value */
+
+    if (!checkHeader(&srfP->header))
+        pm_error("invalid srf header");
+    if (!writeHeader(ofP, &srfP->header))
+        pm_error("write srf header");
+    padLen += lenHeader(&srfP->header);
+
+    for (i = 0; i < srfP->header.img_cnt; ++i) {
+        if (!writeImg(ofP, i, &srfP->imgs[i]))
+            pm_error("invalid srf image %u", i);
+        padLen += lenImg(&srfP->imgs[i]);
+    }
+
+    /* Pad to 256 bytes */
+    padLen = 256 - (padLen % 256);
+    if (padLen) {
+        char * d;
+        size_t bytesWritten;
+
+        MALLOCARRAY(d, padLen);
+
+        if (!d)
+            pm_error("Could not allocate memory for %u bytes of padding",
+                     (unsigned)padLen);
+
+        memset(d, 0xff, padLen);
+
+        bytesWritten = fwrite(d, 1, padLen, ofP);
+
+        if (bytesWritten != padLen)
+            pm_error("unable to 0xff pad file");
+
+        free(d);
+    }
+
+    /* Write out checksum byte */
+    srfCsum = 0xff - csum(srfP, padLen) + 1;
+    bytesWritten = fwrite(&srfCsum, 1, 1, ofP);
+    if (bytesWritten != 1)
+        pm_error("unable to write checksum");
+}
+
+
+
+static void
+freeImg(struct srf_img * const imgP) {
+
+    free(imgP->alpha.data);
+    free(imgP->data.data);
+}
+
+
+
+void
+srf_term(struct srf * const srfP) {
+
+    unsigned int i;
+    
+    free(srfP->header.s578.val);
+    free(srfP->header.ver.val);
+    free(srfP->header.prod.val);
+
+    for (i = 0; i < srfP->header.img_cnt; ++i)
+        freeImg(&srfP->imgs[i]);
+
+    free(srfP->imgs);
+}
+
+
+
+static void
+srf_img_init(struct srf_img * const imgP,
+             uint16_t         const width,
+             uint16_t         const height) {
+
+    struct srf_img_header * const headerP = &imgP->header;
+    struct srf_img_alpha *  const alphaP  = &imgP->alpha;
+    struct srf_img_data *   const dataP   = &imgP->data;
+
+    headerP->_ints[0]   = 0;
+    headerP->_ints[1]   = 16;
+    headerP->_ints[2]   = 0;
+    headerP->height     = height;
+    headerP->width      = width;
+    headerP->_bytes[0]  = 16;
+    headerP->_bytes[1]  = 8;
+    headerP->line_len   = width * 2;
+    headerP->zeros      = 0;
+
+    alphaP->type     = 11;
+    alphaP->data_len = height * width;
+    MALLOCARRAY(alphaP->data, alphaP->data_len);
+
+    if (!alphaP->data)
+        pm_error("Could not allocate buffer for %u bytes of alpha",
+                 alphaP->data_len);
+
+    dataP->type     = 1;
+    dataP->data_len = height * width * 2;
+    MALLOCARRAY(dataP->data, dataP->data_len / 2);
+
+    if (!dataP->data)
+        pm_error("Could not allocation buffer for %u units of data",
+                 dataP->data_len);
+}
+
+
+
+static void
+initPstring(struct srf_pstring * const pstringP,
+            const char *         const s) {
+
+    pstringP->len = strlen(s);
+
+    MALLOCARRAY(pstringP->val, pstringP->len + 1);
+
+    if (!pstringP->val)
+        pm_error("Could not allocate memory for string of length %u",
+                 pstringP->len);
+
+    memcpy(pstringP->val, s, pstringP->len + 1);
+}
+
+
+
+void
+srf_init(struct srf * const srfP) {
+
+    struct srf_header * const headerP = &srfP->header;
+
+    strcpy(headerP->magic, SRF_MAGIC);
+    headerP->_int4[0] = 4;
+    headerP->_int4[1] = 4;
+    headerP->img_cnt = 0;
+    headerP->_int5 = 5;
+    initPstring(&headerP->s578, "578");
+    headerP->_int6 = 6;
+    initPstring(&headerP->ver, "1.00");
+    headerP->_int7 = 7;
+    initPstring(&headerP->prod, "006-D0578-XX");
+
+    srfP->imgs = NULL;
+}
+
+
+
+void
+srf_create_img(struct srf * const srfP,
+               uint16_t     const width,
+               uint16_t     const height) {
+/*----------------------------------------------------------------------------
+   Add an "image" to the SRF.  An image is a horizontal series of 36 
+   square frames, each showing a different angle view of an object, 10
+   degrees about.  At least that's what it's supposed to be.  We don't
+   really care -- it's just an arbitrary rectangular raster image to us.
+-----------------------------------------------------------------------------*/
+    
+    ++srfP->header.img_cnt;
+
+    REALLOCARRAY(srfP->imgs, srfP->header.img_cnt);
+
+    if (!srfP->imgs)
+        pm_error("Could not allocate memory for %u images",
+                 srfP->header.img_cnt);
+
+    srf_img_init(&srfP->imgs[srfP->header.img_cnt-1], width, height);
+}
+                 
diff --git a/converter/other/srf.h b/converter/other/srf.h
new file mode 100644
index 00000000..e06355a4
--- /dev/null
+++ b/converter/other/srf.h
@@ -0,0 +1,170 @@
+#ifndef SRF_H_INCLUDED
+#define SRF_H_INCLUDED
+
+/*
+ * Structures for working with SRF (Garmin vehicle) files
+ * http://www.techmods.net/nuvi/
+ *
+ * Written by Mike Frysinger <vapier@gentoo.org>
+ * Released into the public domain
+ */
+
+#include "pm_config.h"
+#include "pam.h"
+
+struct srf_pstring {
+    uint32_t len;
+    char *   val;
+};
+
+#define SRF_NUM_FRAMES 36
+
+/*
+  File Header
+      16 bytes - string - "GARMIN BITMAP 01"
+      32 bytes - two 32-bit ints, [4, 4] -- purpose unknown
+      4 bytes - 32-bit int -- number of images (usually just 2)
+      4 bytes - 32-bit int, [5] -- purpose unknown
+      7 bytes - PString - "578"
+      4 bytes - 32-bit int, [6] -- purpose unknown
+      8 bytes - PString - version number ("1.00", "2.00", "2.10", or "2.20")
+      4 bytes - 32-bit int, [7] -- purpose unknown
+      16 bytes - PString - "006-D0578-XX" (where "XX" changes) --
+                           I assume this is Garmin's product code?
+*/
+#define SRF_MAGIC "GARMIN BITMAP 01"
+
+struct srf_header {
+    char magic[16 + 1];
+
+    uint32_t           _int4[2];
+
+    uint32_t           img_cnt;
+
+    uint32_t           _int5;
+
+    struct srf_pstring s578;
+
+    uint32_t           _int6;
+
+    struct srf_pstring ver;
+
+    uint32_t           _int7;
+
+    struct srf_pstring prod;
+};
+
+/*
+  Image Header
+     12 bytes - three 32-bit ints, [0,16,0] -- purpose unknown
+     2 bytes - 16-bit int -- height of image (just the 3D section, so it's 80)
+     2 bytes - 16-bit int -- width of image (just the 3D section, 2880 or 2881)
+     2 bytes - [16, 8] -- purpose unknown
+     2 bytes - 16-bit int -- byte length of each line of image RGB data
+                             (16-bit RGB), so "width * 2"
+     4 bytes - all zeroes -- purpose unknown
+*/
+struct srf_img_header {
+    uint32_t _ints[3];
+
+    uint16_t height, width;
+
+    char     _bytes[2];
+
+    uint16_t line_len;
+
+    uint32_t zeros;
+};
+
+/*
+  Image Alpha Mask
+
+      4 bytes - 32-bit int, [11] -- Might specify the type of data that
+                follows?
+
+      4 bytes - 32-bit int, length of following data (width*height of 3D
+                section)
+
+      width*height bytes - alpha mask data, 0 = opaque, 128 = transparent
+                           (across, then down)
+
+  Notes: The Garmin format has 129 values: [0..128] [opaque..transparent]
+         The PNG format has 256 values:    [0..255] [transparent..opaque]
+         So we have to do a little edge case tweaking to keep things lossless.
+*/
+
+#define SRF_ALPHA_OPAQUE 0
+#define SRF_ALPHA_TRANS  128
+
+struct srf_img_alpha {
+    uint32_t        type;
+
+    uint32_t        data_len;
+    unsigned char * data;
+};
+
+/*
+  Image RGB Data
+      4 bytes - 32-bit int, [1] -- Might specify the type of data that follows?
+      4 bytes - 32-bit int, length of following data (width*height*2 of 3D
+                            section, as the RGB data is 16-bit)
+      width*height*2 bytes - RBG values as "rrrrrggggg0bbbbb" bits
+                             (across, then down)
+*/
+
+struct srf_img_data {
+    uint32_t   type;
+
+    uint32_t   data_len;
+    uint16_t * data;
+};
+
+struct srf_img {
+    struct srf_img_header header;
+    struct srf_img_alpha  alpha;
+    struct srf_img_data   data;
+};
+
+/*
+  Footer
+      arbitrary number of bytes - all 0xFF -- these are used (as well as the
+                                              checksum byte) to pad the file
+                                              size to a multiple of 256.
+
+      1 byte - checksum byte -- use this byte to adjust so that the ascii sum
+                                of all bytes in the file is a multiple of 256.
+ */
+
+struct srf {
+    struct srf_header header;
+    struct srf_img *  imgs;
+};
+
+uint8_t
+srf_alpha_srftopam(uint8_t const d);
+
+uint8_t
+srf_alpha_pamtosrf(uint8_t const d);
+
+void
+srf_read(FILE *       const ifP,
+         bool         const verbose,
+         struct srf * const srfP);
+
+void
+srf_write(FILE *       const ofP,
+          struct srf * const srfP);
+
+void
+srf_term(struct srf * const srfP);
+
+void
+srf_init(struct srf * const srfP);
+
+void
+srf_create_img(struct srf * const srfP,
+               uint16_t     const width,
+               uint16_t     const height);
+
+#endif
+
diff --git a/converter/other/srftopam.c b/converter/other/srftopam.c
new file mode 100644
index 00000000..efe55253
--- /dev/null
+++ b/converter/other/srftopam.c
@@ -0,0 +1,226 @@
+/*
+ * Convert a SRF (Garmin vehicle) to a PAM image
+ *
+ * Copyright (C) 2011 by Mike Frysinger <vapier@gentoo.org>
+ *
+ * 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.
+ */
+
+#include <assert.h>
+#include <stdio.h>
+
+#include "pm_c_util.h"
+#include "shhopt.h"
+#include "mallocvar.h"
+#include "nstring.h"
+#include "pam.h"
+#include "srf.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 */
+  unsigned int  verbose;
+};
+
+static bool verbose;
+
+
+
+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;
+
+    MALLOCARRAY_NOFAIL(option_def, 100);
+
+    option_def_index = 0;   /* incremented by OPTENT3 */
+    OPTENT3(0, "verbose",          OPT_FLAG,      NULL,
+            &cmdlineP->verbose,    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 (argc-1 < 1)
+        cmdlineP->inputFileName = "-";
+    else if (argc-1 == 1)
+        cmdlineP->inputFileName = argv[1];
+    else
+        pm_error("Program takes at most one argument:  input file name");
+}
+
+
+
+static unsigned int
+srfRed(uint16_t const pixel) {
+    return ((pixel >> 11) & 0x1f) << 3;
+}
+
+
+static unsigned int
+srfGrn(uint16_t const pixel) {
+    return ((pixel >>  6) & 0x1f) << 3;
+}
+
+
+static unsigned int
+srfBlu(uint16_t const pixel) {
+    return ((pixel >>  0) & 0x1f) << 3;
+}
+
+
+static uint8_t
+srfAlpha(uint8_t const d) {
+
+    uint8_t retval;
+
+    if (d == SRF_ALPHA_OPAQUE)
+        retval = 0xff;
+    else
+        retval = (128 - d) << 1;
+
+    return retval;
+}
+
+
+
+static void
+writeRaster(struct pam *     const pamP,
+            struct srf_img * const imgP) {
+
+    tuple *  tuplerow;
+    unsigned int row;
+
+    assert(imgP->header.width <= pamP->width);
+
+    tuplerow = pnm_allocpamrow(pamP);
+
+    for (row = 0; row < imgP->header.height; ++row) {
+        unsigned int const rowStart = row * imgP->header.width;
+
+        unsigned int col;
+
+        for (col = 0; col < imgP->header.width; ++col) {
+            uint16_t const data  = imgP->data.data[rowStart + col];
+            uint16_t const alpha = imgP->alpha.data[rowStart + col];
+
+            assert(col < pamP->width);
+            
+            tuplerow[col][PAM_RED_PLANE] = srfRed(data);
+            tuplerow[col][PAM_GRN_PLANE] = srfGrn(data);
+            tuplerow[col][PAM_BLU_PLANE] = srfBlu(data);
+            tuplerow[col][PAM_TRN_PLANE] = srfAlpha(alpha);
+        }
+
+        for (; col < pamP->width; ++col) {
+            tuplerow[col][PAM_RED_PLANE] = 0;
+            tuplerow[col][PAM_GRN_PLANE] = 0;
+            tuplerow[col][PAM_BLU_PLANE] = 0;
+            tuplerow[col][PAM_TRN_PLANE] = 0;
+        }            
+
+        pnm_writepamrow(pamP, tuplerow);
+    }
+    pnm_freepamrow(tuplerow);
+}
+
+
+
+static void
+convertOneImage(struct srf_img * const imgP,
+                FILE *           const ofP) {
+
+    const char * comment = "Produced by srftopam";  /* constant */
+
+    struct pam   outPam;
+
+    outPam.size             = sizeof(struct pam);
+    outPam.len              = PAM_STRUCT_SIZE(comment_p);
+    outPam.file             = ofP;
+    outPam.format           = PAM_FORMAT;
+    outPam.plainformat      = 0;
+    outPam.width            = imgP->header.width;
+    outPam.height           = imgP->header.height;
+    outPam.depth            = 4;
+    outPam.maxval           = 255;
+    outPam.bytes_per_sample = 1;
+    sprintf(outPam.tuple_type, "RGB_ALPHA");
+    outPam.allocation_depth = 4;
+    outPam.comment_p        = &comment;
+
+    pnm_writepaminit(&outPam);
+
+    writeRaster(&outPam, imgP);
+}
+
+
+
+static void
+srftopam(struct cmdlineInfo const cmdline,
+         FILE *             const ifP,
+         FILE *             const ofP) {
+
+    unsigned int imgSeq;
+    struct srf   srf;
+
+    srf_read(ifP, verbose, &srf);
+
+    for (imgSeq = 0; imgSeq < srf.header.img_cnt; ++imgSeq) {
+        if (verbose)
+            pm_message("Converting Image %u", imgSeq);
+        convertOneImage(&srf.imgs[imgSeq], ofP);
+    }
+
+    srf_term(&srf);
+}
+
+
+
+int
+main(int argc, const char * argv[]) {
+
+    struct cmdlineInfo cmdline;
+    FILE *             ifP;
+
+    pm_proginit(&argc, argv);
+
+    parseCommandLine(argc, argv, &cmdline);
+
+    verbose = cmdline.verbose;
+
+    ifP = pm_openr(cmdline.inputFileName);
+
+    srftopam(cmdline, ifP, stdout);
+
+    pm_closer(ifP);
+
+    return 0;
+}
+
+
+
diff --git a/converter/other/sunicontopnm.c b/converter/other/sunicontopnm.c
new file mode 100644
index 00000000..eff1be58
--- /dev/null
+++ b/converter/other/sunicontopnm.c
@@ -0,0 +1,172 @@
+/* icontopbm.c - read a Sun icon file and produce a Netbpbm image.
+**
+** Copyright (C) 1988 by Jef Poskanzer.
+**
+** 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.
+*/
+
+/*
+  Most icon images are monochrome: Depth=1
+  Depth=8 images are extremely rare.  At least some of these are color
+  images but we can't tell the palette color order.
+  Output will be in pgm.  Convert to ppm with pgmtoppm or pamlookup
+  if necessary.
+*/
+
+#include <assert.h>
+#include <string.h>
+
+#include "nstring.h"
+#include "pbm.h"
+#include "pgm.h"
+
+
+
+static void
+ReadIconFileHeader(FILE * const file, 
+                   int *  const widthP, 
+                   int *  const heightP, 
+                   int *  const depthP,
+                   int *  const bitsPerItemP) {
+
+    unsigned int fieldCt;
+
+    fieldCt = 0;
+    *widthP = *heightP = -1;
+
+    for ( ; ; ) {
+        char variable[80+1];
+        int ch;
+        unsigned int i;
+        int value;
+
+        while ((ch = getc(file)) == ',' || ch == '\n' || ch == '\t' ||
+                ch == ' ')
+            ;
+        for (i = 0;
+             ch != '=' && ch != ',' && ch != '\n' && ch != '\t' && 
+                 ch != ' ' && (i < (sizeof(variable) - 1));
+             ++i) {
+            variable[i] = ch;
+            if ((ch = getc( file )) == EOF)
+                pm_error( "invalid input file -- premature EOF" );
+        }
+        variable[i] = '\0';
+
+        if (streq(variable, "*/") && fieldCt > 0)
+            break;
+
+        if (fscanf( file, "%d", &value ) != 1)
+            continue;
+
+        if (streq( variable, "Width")) {
+            *widthP = value;
+            ++fieldCt;
+        } else if (streq( variable, "Height")) {
+            *heightP = value;
+            ++fieldCt;
+        } else if (streq( variable, "Depth")) {
+            if (value != 1 && value != 8)
+                pm_error("invalid depth");
+            *depthP = value;
+            ++fieldCt;
+        } else if (streq(variable, "Format_version")) {
+            if (value != 1)
+                pm_error("invalid Format_version");
+            ++fieldCt;
+        } else if (streq(variable, "Valid_bits_per_item")) {
+            if (value != 16 && value !=32)
+                pm_error("invalid Valid_bits_per_item");
+            *bitsPerItemP = value; 
+            ++fieldCt;
+        }
+    }
+
+    if (fieldCt < 5)
+        pm_error("invalid sun icon file header: "
+                 "only %u out of required 5 fields present", fieldCt);
+
+    if (*widthP <= 0)
+        pm_error("invalid width (must be positive): %d", *widthP);
+    if (*heightP <= 0)
+        pm_error("invalid height (must be positive): %d", *heightP);
+
+}
+
+
+int
+main(int argc, const char ** argv) {
+
+    FILE * ifP;
+    bit * bitrow;
+    gray * grayrow;
+    int rows, cols, depth, row, format, maxval, colChars, bitsPerItem;
+
+    pm_proginit(&argc, argv);
+
+    if (argc-1 > 1)
+        pm_error("Too many arguments (%u).  Program takes at most one: "
+                 "name of input file", argc-1);
+
+    if (argc-1 == 1)
+        ifP = pm_openr(argv[1]);
+    else
+        ifP = stdin;
+
+    ReadIconFileHeader(ifP, &cols, &rows, &depth, &bitsPerItem);
+
+    if (depth == 1) {
+        format = PBM_TYPE;
+        maxval = 1;
+        pbm_writepbminit(stdout, cols, rows, 0);
+        bitrow = pbm_allocrow_packed(cols);
+        colChars = cols / 8;
+    } else {
+        assert(depth == 8);
+        format = PGM_TYPE;
+        maxval = 255;
+        pgm_writepgminit(stdout, cols, rows, maxval, 0);
+        grayrow = pgm_allocrow(cols);
+        colChars = cols;
+    }
+
+    for (row = 0; row < rows; ++row) {
+        unsigned int colChar;
+        for (colChar = 0; colChar < colChars; ++colChar) {
+            unsigned int data;
+            int status;
+
+            /* read 8 bits */
+            if (row==0 && colChar == 0)
+                status = fscanf(ifP, " 0x%2x", &data);
+            else if (colChar % (bitsPerItem/8) == 0)
+                status = fscanf(ifP, ", 0x%2x", &data);
+            else
+                status = fscanf(ifP, "%2x", &data);
+
+            /* write 8 bits */
+            if (status == 1) {
+                if (format == PBM_TYPE)
+                    bitrow[colChar]  = data;
+                else
+                    grayrow[colChar] = data;
+            } else
+                pm_error("error scanning bits item %u" , colChar);
+        }
+
+        /* output row */
+        if (format == PBM_TYPE)
+            pbm_writepbmrow_packed(stdout, bitrow, cols, 0);
+        else
+            pgm_writepgmrow(stdout, grayrow, cols, maxval, 0);
+    }
+
+    pm_close(ifP);
+    pm_close(stdout);
+    return 0;
+}
diff --git a/converter/other/svgtopam.c b/converter/other/svgtopam.c
index 68deb3e0..58e7928f 100644
--- a/converter/other/svgtopam.c
+++ b/converter/other/svgtopam.c
@@ -26,7 +26,9 @@
    
 ============================================================================*/
 
+#define _XOPEN_SOURCE 500  /* Make sure strdup() is in string.h */
 #define _BSD_SOURCE  /* Make sure strdup() is in <string.h> */
+#define _POSIX_SOURCE   /* Make sure fileno() is in <stdio.h> */
 #include <assert.h>
 #include <string.h>
 #include <stdio.h>
@@ -66,7 +68,7 @@ parseCommandLine(int argc,
    was passed to us as the argv array.  We also trash *argv.
 --------------------------------------------------------------------------*/
     optEntry *option_def;
-        /* Instructions to optParseOptions3 on how to parse our options. */
+        /* Instructions to pm_optParseOptions3 on how to parse our options. */
     optStruct3 opt;
 
     unsigned int option_def_index;
@@ -81,7 +83,7 @@ parseCommandLine(int argc,
     opt.short_allowed = FALSE;  /* We have no short (old-fashioned) options */
     opt.allowNegNum = FALSE;   /* We have no parms that are negative numbers */
 
-    optParseOptions3( &argc, argv, opt, sizeof(opt), 0 );
+    pm_optParseOptions3( &argc, argv, opt, sizeof(opt), 0 );
     /* Uses and sets argc, argv, and some of *cmdlineP and others. */
 
     if (argc-1 < 1)
@@ -205,7 +207,7 @@ destroyPath(path * const pathP) {
     
     assert(pathP->pathTextLength == strlen(pathP->pathText));
 
-    strfree(pathP->pathText);
+    pm_strfree(pathP->pathText);
 
     free(pathP);
 }
@@ -531,7 +533,7 @@ interpretStyle(const char * const styleAttr) {
     p = &buffer[0];
 
     while (p) {
-        const char * const token = strsepN(&p, ";");
+        const char * const token = pm_strsep(&p, ";");
         const char * strippedToken;
         const char * p;
         char * buffer;
@@ -674,14 +676,14 @@ stringToUint(const char *   const string,
     /* TODO: move this to nstring.c */
 
     if (strlen(string) == 0)
-        asprintfN(errorP, "Value is a null string");
+        pm_asprintf(errorP, "Value is a null string");
     else {
         char * tailptr;
 
         *uintP = strtoul(string, &tailptr, 10);
 
         if (*tailptr != '\0')
-            asprintfN(errorP, "Non-numeric crap in string: '%s'", tailptr);
+            pm_asprintf(errorP, "Non-numeric crap in string: '%s'", tailptr);
         else
             *errorP = NULL;
     }
@@ -702,12 +704,12 @@ getSvgAttributes(xmlTextReaderPtr const xmlReaderP,
     stringToUint(width, colsP, &error);
     if (error) {
         pm_error("'width' attribute of <svg> has invalid value.  %s", error);
-        strfree(error);
+        pm_strfree(error);
     }
     stringToUint(height, rowsP, &error);
     if (error) {
         pm_error("'height' attribute of <svg> has invalid value.  %s", error);
-        strfree(error);
+        pm_strfree(error);
     }
 }
 
diff --git a/converter/other/tiff.c b/converter/other/tiff.c
index 90d50710..d0cbbd74 100644
--- a/converter/other/tiff.c
+++ b/converter/other/tiff.c
@@ -10,12 +10,6 @@
 
 #include <string.h>
 
-#ifdef VMS
-#ifdef SYSV
-#undef SYSV
-#endif
-#include <tiffioP.h>
-#endif
 #include <tiffio.h>
 
 #include "pm_c_util.h"
diff --git a/converter/other/tifftopnm.c b/converter/other/tifftopnm.c
index 4d40d117..4a8cf902 100644
--- a/converter/other/tifftopnm.c
+++ b/converter/other/tifftopnm.c
@@ -52,7 +52,6 @@
 #include <assert.h>
 #include <string.h>
 #include <stdio.h>
-#include <sys/wait.h>
 
 #include "pm_c_util.h"
 #include "shhopt.h"
@@ -60,12 +59,6 @@
 #include "nstring.h"
 #include "pnm.h"
 
-#ifdef VMS
-#ifdef SYSV
-#undef SYSV
-#endif
-#include <tiffioP.h>
-#endif
 /* See warning about tiffio.h in pamtotiff.c */
 #include <tiffio.h>
 
@@ -85,7 +78,7 @@
 #define PHOTOMETRIC_DEPTH 32768
 #endif
 
-struct cmdlineInfo {
+struct CmdlineInfo {
     /* All the information the user supplied in the command line,
        in a form easy for the program to use.
     */
@@ -103,7 +96,7 @@ struct cmdlineInfo {
 
 static void
 parseCommandLine(int argc, const char ** const argv,
-                 struct cmdlineInfo * const cmdlineP) {
+                 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
@@ -135,7 +128,7 @@ parseCommandLine(int argc, const char ** const argv,
     OPTENT3(0,   "alphaout",   
             OPT_STRING, &cmdlineP->alphaFilename, &alphaSpec,  0);
 
-    optParseOptions3(&argc, (char **)argv, opt, sizeof(opt), 0);
+    pm_optParseOptions3(&argc, (char **)argv, opt, sizeof(opt), 0);
 
     if (argc - 1 == 0)
         cmdlineP->inputFilename = strdup("-");  /* he wants stdin */
@@ -158,6 +151,31 @@ parseCommandLine(int argc, const char ** const argv,
 
 
 
+static TIFF *
+newTiffImageObject(const char * const inputFileName) {
+/*----------------------------------------------------------------------------
+   Create a TIFF library object for accessing the TIFF input in file
+   named 'inputFileName'.  If 'inputFileName' is "-", that means
+   Standard Input.
+-----------------------------------------------------------------------------*/
+    const char * const tiffSourceName =
+        streq(inputFileName, "-") ? "Standard Input" : inputFileName;
+
+    TIFF * retval;
+
+    retval = TIFFFdOpen(fileno(pm_openr_seekable(inputFileName)),
+                        tiffSourceName,
+                        "r");
+
+    if (retval == NULL)
+        pm_error("Failed to access input file.  The OS opened the file fine, "
+                 "but the TIFF library's TIFFFdOpen rejected the open file.");
+
+    return retval;
+}
+
+
+
 static void
 getBps(TIFF *           const tif,
        unsigned short * const bpsP) {
@@ -226,6 +244,8 @@ tiffToImageDim(unsigned int   const tiffCols,
     }
 }
 
+
+
 static void
 getTiffDimensions(TIFF *         const tiffP,
                   unsigned int * const colsP,
@@ -345,15 +365,15 @@ readDirectory(TIFF *               const tiffP,
 
 
 static void
-readscanline(TIFF *         const tif, 
-             unsigned char  scanbuf[], 
-             int            const row, 
-             int            const plane,
-             unsigned int   const cols, 
-             unsigned short const bps,
-             unsigned short const spp,
-             unsigned short const fillorder,
-             unsigned int * const samplebuf) {
+readscanline(TIFF *          const tif, 
+             unsigned char * const scanbuf,
+             int             const row, 
+             int             const plane,
+             unsigned int    const cols, 
+             unsigned short  const bps,
+             unsigned short  const spp,
+             unsigned short  const fillorder,
+             unsigned int *  const samplebuf) {
 /*----------------------------------------------------------------------------
    Read one scanline out of the Tiff input and store it into samplebuf[].
    Unlike the scanline returned by the Tiff library function, samplebuf[]
@@ -381,8 +401,8 @@ readscanline(TIFF *         const tif,
                   "TIFFReadScanline() failed.",
                   row, plane);
     else if (bps == 8) {
-        int sample;
-        for (sample = 0; sample < cols*spp; sample++) 
+        unsigned int sample;
+        for (sample = 0; sample < cols * spp; ++sample) 
             samplebuf[sample] = scanbuf[sample];
     } else if (bps < 8) {
         /* Note that in this format, samples do not span bytes.  Rather,
@@ -390,12 +410,12 @@ readscanline(TIFF *         const tif,
            At least that's how I infer the format from reading pnmtotiff.c
            -Bryan 00.11.18
            */
-        int sample;
-        int bitsleft;
+        unsigned int sample;
+        unsigned int bitsleft;
         unsigned char * inP;
 
-        for (sample = 0, bitsleft=8, inP=scanbuf; 
-             sample < cols*spp; 
+        for (sample = 0, bitsleft = 8, inP = scanbuf; 
+             sample < cols * spp; 
              ++sample) {
             if (bitsleft == 0) {
                 ++inP; 
@@ -412,6 +432,7 @@ readscanline(TIFF *         const tif,
                 pm_error("Internal error: invalid value for fillorder: %u", 
                          fillorder);
             }
+            assert(bitsleft >= bps);
             bitsleft -= bps; 
             if (bitsleft < bps)
                 /* Don't count dregs at end of byte */
@@ -433,10 +454,10 @@ readscanline(TIFF *         const tif,
         for (sample = 0; sample < cols*spp; ++sample)
             samplebuf[sample] = scanbuf16[sample];
     } else if (bps == 32) {
-        uint32 * const scanbuf32 = (uint32 *) scanbuf;
+        const uint32 * const scanbuf32 = (const uint32 *) scanbuf;
         unsigned int sample;
         
-        for (sample = 0; sample < cols*spp; ++sample)
+        for (sample = 0; sample < cols * spp; ++sample)
             samplebuf[sample] = scanbuf32[sample];
     } else 
         pm_error("Internal error: invalid bits per sample passed to "
@@ -446,8 +467,11 @@ readscanline(TIFF *         const tif,
 
 
 static void
-pick_cmyk_pixel(const unsigned int samplebuf[], const int sample_cursor,
-                xelval * const r_p, xelval * const b_p, xelval * const g_p) {
+pick_cmyk_pixel(unsigned int const samplebuf[],
+                int          const sampleCursor,
+                xelval *     const redP,
+                xelval *     const bluP,
+                xelval *     const grnP) {
 
     /* Note that the TIFF spec does not say which of the 4 samples is
        which, but common sense says they're in order C,M,Y,K.  Before
@@ -455,10 +479,10 @@ pick_cmyk_pixel(const unsigned int samplebuf[], const int sample_cursor,
        But combined with a compensating error in the CMYK->RGB
        calculation, it had the same effect as C,M,Y,K.
     */
-    unsigned int const c = samplebuf[sample_cursor+0];
-    unsigned int const m = samplebuf[sample_cursor+1];
-    unsigned int const y = samplebuf[sample_cursor+2];
-    unsigned int const k = samplebuf[sample_cursor+3];
+    unsigned int const c = samplebuf[sampleCursor + 0];
+    unsigned int const m = samplebuf[sampleCursor + 1];
+    unsigned int const y = samplebuf[sampleCursor + 2];
+    unsigned int const k = samplebuf[sampleCursor + 3];
 
     /* The CMYK->RGB formula used by TIFFRGBAImageGet() in the TIFF 
        library is the following, (with some apparent confusion with
@@ -476,9 +500,9 @@ pick_cmyk_pixel(const unsigned int samplebuf[], const int sample_cursor,
        Yellow ink removes blue light from what the white paper reflects.  
     */
 
-    *r_p = 255 - MIN(255, c + k);
-    *g_p = 255 - MIN(255, m + k);
-    *b_p = 255 - MIN(255, y + k);
+    *redP = 255 - MIN(255, c + k);
+    *grnP = 255 - MIN(255, m + k);
+    *bluP = 255 - MIN(255, y + k);
 }
 
 
@@ -515,9 +539,9 @@ analyzeImageType(TIFF *             const tif,
                  unsigned short     const photomet,
                  xelval *           const maxvalP, 
                  int *              const formatP, 
-                 xel                      colormap[],
+                 xel *              const colormap,
                  bool               const headerdump,
-                 struct cmdlineInfo const cmdline) {
+                 struct CmdlineInfo const cmdline) {
 
     bool grayscale; 
 
@@ -726,44 +750,40 @@ spawnWithInputPipe(const char *  const shellCmd,
     int fd[2];
     int rc;
 
-    rc = pipe(fd);
+    rc = pm_pipe(fd);
 
     if (rc != 0)
-        asprintfN(errorP, "Failed to create pipe for process input.  "
-                  "Errno=%d (%s)", errno, strerror(errno));
+        pm_asprintf(errorP, "Failed to create pipe for process input.  "
+                    "Errno=%d (%s)", errno, strerror(errno));
     else {
-        int rc;
-
-        rc = fork();
+        int iAmParent;
+        pid_t childPid;
 
-        if (rc < 0) {
-            asprintfN(errorP, "Failed to fork a process.  errno=%d (%s)",
-                      errno, strerror(errno));
-        } else if (rc == 0) {
-            /* This is the child */
-            int rc;
-            close(fd[PIPE_WRITE]);
-            close(STDIN_FILENO);
-            dup2(fd[PIPE_READ], STDIN_FILENO);
+        pm_fork(&iAmParent, &childPid, errorP);
 
-            rc = system(shellCmd);
+        if (!*errorP) {
+            if (iAmParent) {
+                close(fd[PIPE_READ]);
 
-            exit(rc);
-        } else {
-            /* Parent */
-            pid_t const childPid = rc;
-
-            close(fd[PIPE_READ]);
+                *pidP   = childPid;
+                *pipePP = fdopen(fd[PIPE_WRITE], "w");
+                
+                if (*pipePP == NULL)
+                    pm_asprintf(errorP,"Unable to create stream from pipe.  "
+                                "fdopen() fails with errno=%d (%s)",
+                                errno, strerror(errno));
+                else
+                    *errorP = NULL;
+            } else {
+                int rc;
+                close(fd[PIPE_WRITE]);
+                close(STDIN_FILENO);
+                dup2(fd[PIPE_READ], STDIN_FILENO);
 
-            *pidP   = childPid;
-            *pipePP = fdopen(fd[PIPE_WRITE], "w");
+                rc = system(shellCmd);
 
-            if (*pipePP == NULL)
-                asprintfN(errorP,"Unable to create stream from pipe.  "
-                          "fdopen() fails with errno=%d (%s)",
-                          errno, strerror(errno));
-            else
-                *errorP = NULL;
+                exit(rc);
+            }
         }
     }
 }
@@ -780,7 +800,7 @@ createFlipProcess(FILE *         const outFileP,
    Create a process that runs the program Pamflip and writes its output
    to *imageoutFileP.
 
-   The process takes it input from a pipe that we create.  We return as
+   The process takes its input from a pipe that we create.  We return as
    *inPipePP a file stream connected to the other end of that pipe.
 
    I.e. Caller will write a Netpbm file stream to **inPipePP and a flipped
@@ -803,8 +823,8 @@ createFlipProcess(FILE *         const outFileP,
        file descriptor is equivalent to writing to the stream.
     */
 
-    asprintfN(&pamflipCmd, "pamflip -xform=%s >&%u",
-              xformNeeded(orientation), fileno(outFileP));
+    pm_asprintf(&pamflipCmd, "pamflip -xform=%s >&%u",
+                xformNeeded(orientation), fileno(outFileP));
 
     if (verbose)
         pm_message("Reorienting raster with shell command '%s'", pamflipCmd);
@@ -816,7 +836,7 @@ createFlipProcess(FILE *         const outFileP,
                  "raster, failed.  %s.  To work around this, you can use "
                  "the -orientraw option.", pamflipCmd, error);
 
-        strfree(error);
+        pm_strfree(error);
     }
 }
 
@@ -966,12 +986,12 @@ pnmOut_init(FILE *         const imageoutFileP,
    data, pnmOut get 'cols' x 'rows' data, but its output file may be
    'rows x cols'.
 
-   Because the pnmOut object must be set up to receive flipped or not
-   flipped input, we have *flipOkP and *noflipOkP outputs that tell
-   Caller whether he has to flip or not.  In the unique case that
-   the TIFF matrix is already oriented the way the output PNM file needs
-   to be, flipping is idempotent, so both *flipOkP and *noflipOkP are
-   true.
+   Because we must set up the pnmOut object either to receive flipped or not
+   flipped input, we have *flipOkP and *noflipOkP outputs that tell Caller
+   whether he has to flip or not.  Note that Caller also influences which way
+   we set up pnmOut, with his 'flipIfNeeded' argument.  In the unique case
+   that the TIFF matrix is already oriented the way the output PNM file needs
+   to be, flipping is idempotent, so both *flipOkP and *noflipOkP are true.
 -----------------------------------------------------------------------------*/
     pnmOutP->imageoutFileP = imageoutFileP;
     pnmOutP->alphaFileP    = alphaFileP;
@@ -1033,14 +1053,12 @@ pnmOut_term(pnmOut * const pnmOutP,
                        "waiting for Pamflip to terminate");
 
         if (pnmOutP->imagePipeP) {
-            int status;
             fclose(pnmOutP->imagePipeP);
-            waitpid(pnmOutP->imageFlipPid, &status, 0);
+            pm_waitpidSimple(pnmOutP->imageFlipPid);
         }
         if (pnmOutP->alphaPipeP) {
-            int status;
             fclose(pnmOutP->alphaPipeP);
-            waitpid(pnmOutP->alphaFlipPid, &status, 0);
+            pm_waitpidSimple(pnmOutP->alphaFlipPid);
         }
     } else {
         if (pnmOutP->imageoutFileP)
@@ -1083,8 +1101,8 @@ pnmOut_writeRow(pnmOut *     const pnmOutP,
 
 static void
 convertRow(unsigned int   const samplebuf[], 
-           xel                  xelrow[], 
-           gray                 alpharow[], 
+           xel *          const xelrow, 
+           gray *         const alpharow,
            int            const cols, 
            xelval         const maxval, 
            unsigned short const photomet, 
@@ -1160,9 +1178,9 @@ convertRow(unsigned int   const samplebuf[],
 
 
 static void
-scale32to16(unsigned int       samplebuf[],
-            unsigned int const cols,
-            unsigned int const spp) {
+scale32to16(unsigned int * const samplebuf,
+            unsigned int   const cols,
+            unsigned int   const spp) {
 /*----------------------------------------------------------------------------
   Convert every sample in samplebuf[] to something that can be expressed
   in 16 bits, assuming it takes 32 bits now.
@@ -1175,9 +1193,9 @@ scale32to16(unsigned int       samplebuf[],
 
 
 static void
-convertMultiPlaneRow(TIFF *         const tif,
-                     xel                   xelrow[],
-                     gray                  alpharow[],
+convertMultiPlaneRow(TIFF *          const tif,
+                     xel *           const xelrow,
+                     gray *          const alpharow,
                      int             const cols,
                      xelval          const maxval,
                      int             const row,
@@ -1193,15 +1211,15 @@ convertMultiPlaneRow(TIFF *         const tif,
        for the blues.
     */
 
-    int col;
-
     if (photomet != PHOTOMETRIC_RGB)
         pm_error("This is a multiple-plane file, but is not an RGB "
                  "file.  This program does not know how to handle that.");
     else {
+        unsigned int col;
+
         /* First, clear the buffer so we can add red, green,
            and blue one at a time.  
-                */
+        */
         for (col = 0; col < cols; ++col) 
             PPM_ASSIGN(xelrow[col], 0, 0, 0);
 
@@ -1254,8 +1272,8 @@ convertRasterByRows(pnmOut *       const pnmOutP,
                     bool           const verbose) {
 /*----------------------------------------------------------------------------
    With the TIFF header all processed (and relevant information from it in 
-   our arguments), write out the TIFF raster to the file images *imageoutFile
-   and *alphaFile.
+   our arguments), write out the TIFF raster to the Netpbm output files
+   as described by *pnmOutP.
 
    Do this one row at a time, employing the TIFF library's
    TIFFReadScanline.
@@ -1275,12 +1293,12 @@ convertRasterByRows(pnmOut *       const pnmOutP,
            row we are presently converting.
         */
 
-    int row;
+    unsigned int row;
 
     if (verbose)
         pm_message("Converting row by row ...");
 
-    scanbuf = (unsigned char *) malloc(TIFFScanlineSize(tif));
+    MALLOCARRAY(scanbuf, TIFFScanlineSize(tif));
     if (scanbuf == NULL)
         pm_error("can't allocate memory for scanline buffer");
 
@@ -1355,7 +1373,7 @@ warnBrokenTiffLibrary(TIFF * const tiffP) {
         case ORIENTATION_RIGHTBOT:
         case ORIENTATION_LEFTBOT:
             pm_message("WARNING: This TIFF image has an orientation that "
-                       "most TIFF libraries converts incorrectly.  "
+                       "most TIFF libraries convert incorrectly.  "
                        "Use -byrow to circumvent.");
             break;
         }
@@ -1414,20 +1432,23 @@ convertTiffRaster(uint32 *        const raster,
 
 
 
-enum convertDisp {CONV_DONE, CONV_OOM, CONV_UNABLE, CONV_FAILED, 
+enum convertDisp {CONV_DONE,
+                  CONV_OOM,
+                  CONV_UNABLE,
+                  CONV_FAILED, 
                   CONV_NOTATTEMPTED};
 
 static void
-convertRasterInMemory(pnmOut *       const pnmOutP,
-                      xelval         const maxval,
-                      TIFF *         const tif,
-                      unsigned short const photomet, 
-                      unsigned short const planarconfig,
-                      unsigned short const bps,
-                      unsigned short const spp,
-                      unsigned short const fillorder,
-                      xel            const colormap[],
-                      bool           const verbose,
+convertRasterInMemory(pnmOut *           const pnmOutP,
+                      xelval             const maxval,
+                      TIFF *             const tif,
+                      unsigned short     const photomet, 
+                      unsigned short     const planarconfig,
+                      unsigned short     const bps,
+                      unsigned short     const spp,
+                      unsigned short     const fillorder,
+                      xel                const colormap[],
+                      bool               const verbose,
                       enum convertDisp * const statusP) {
 /*----------------------------------------------------------------------------
    With the TIFF header all processed (and relevant information from
@@ -1462,7 +1483,7 @@ convertRasterInMemory(pnmOut *       const pnmOutP,
         int ok;
         ok = TIFFRGBAImageOK(tif, emsg);
         if (!ok) {
-            pm_message(emsg);
+            pm_message("%s", emsg);
             *statusP = CONV_UNABLE;
         } else {
             uint32 * raster;
@@ -1489,14 +1510,14 @@ convertRasterInMemory(pnmOut *       const pnmOutP,
                 
                 ok = TIFFRGBAImageBegin(&img, tif, stopOnErrorFalse, emsg);
                 if (!ok) {
-                    pm_message(emsg);
+                    pm_message("%s", emsg);
                     *statusP = CONV_FAILED;
                 } else {
                     int ok;
                     ok = TIFFRGBAImageGet(&img, raster, cols, rows);
                     TIFFRGBAImageEnd(&img) ;
                     if (!ok) {
-                        pm_message(emsg);
+                        pm_message("%s", emsg);
                         *statusP = CONV_FAILED;
                     } else {
                         *statusP = CONV_DONE;
@@ -1524,6 +1545,7 @@ convertRaster(pnmOut *           const pnmOutP,
               bool               const verbose) {
 
     enum convertDisp status;
+
     if (byrow || !flipOk)
         status = CONV_NOTATTEMPTED;
     else {
@@ -1563,7 +1585,7 @@ static void
 convertImage(TIFF *             const tifP,
              FILE *             const alphaFileP,
              FILE *             const imageoutFileP,
-             struct cmdlineInfo const cmdline) {
+             struct CmdlineInfo const cmdline) {
 
     struct tiffDirInfo tiffDir;
     int format;
@@ -1600,7 +1622,7 @@ static void
 convertIt(TIFF *             const tifP,
           FILE *             const alphaFile, 
           FILE *             const imageoutFile,
-          struct cmdlineInfo const cmdline) {
+          struct CmdlineInfo const cmdline) {
 
     unsigned int imageSeq;
     bool eof;
@@ -1625,8 +1647,8 @@ convertIt(TIFF *             const tifP,
 int
 main(int argc, const char * argv[]) {
 
-    struct cmdlineInfo cmdline;
-    TIFF * tif;
+    struct CmdlineInfo cmdline;
+    TIFF * tiffP;
     FILE * alphaFile;
     FILE * imageoutFile;
 
@@ -1634,15 +1656,7 @@ main(int argc, const char * argv[]) {
 
     parseCommandLine(argc, argv, &cmdline);
 
-    if (!streq(cmdline.inputFilename, "-")) {
-        tif = TIFFOpen(cmdline.inputFilename, "r");
-        if (tif == NULL)
-            pm_error("error opening TIFF file %s", cmdline.inputFilename);
-    } else {
-        tif = TIFFFdOpen(0, "Standard Input", "r");
-        if (tif == NULL)
-            pm_error("error opening standard input as TIFF file");
-    }
+    tiffP = newTiffImageObject(cmdline.inputFilename);
 
     if (cmdline.alphaStdout)
         alphaFile = stdout;
@@ -1656,16 +1670,19 @@ main(int argc, const char * argv[]) {
     else
         imageoutFile = stdout;
 
-    convertIt(tif, alphaFile, imageoutFile, cmdline);
+    convertIt(tiffP, alphaFile, imageoutFile, cmdline);
 
     if (imageoutFile != NULL) 
         pm_close( imageoutFile );
     if (alphaFile != NULL)
         pm_close( alphaFile );
 
-    strfree(cmdline.inputFilename);
+    TIFFClose(tiffP);
+
+    pm_strfree(cmdline.inputFilename);
 
     /* If the program failed, it previously aborted with nonzero completion
-       code, via various function calls.  */
+       code, via various function calls.
+    */
     return 0;
 }
diff --git a/converter/other/winicon.h b/converter/other/winicon.h
new file mode 100644
index 00000000..9ede01f5
--- /dev/null
+++ b/converter/other/winicon.h
@@ -0,0 +1,82 @@
+#include "pm_c_util.h"
+
+#define ICONDIR_TYPE_ICO (1)
+
+/*  windows icon structures  */
+struct IconDirEntry {
+    uint16_t width;               /* image width in pixels 0 == 256 */
+    uint16_t height;              /* image height in pixels 0 == 256 */
+    uint8_t  color_count;         /* 0 if bits_per_pixel >= 8 */
+    uint8_t  zero;                /* 0 */
+    uint16_t color_planes;        /* 1 */
+    uint16_t bits_per_pixel;      /* allowed values: 1, 4, 8, 16 or 32 (1) */
+    uint32_t size;                /* size of image */
+    uint32_t offset;              /* file offset of image */
+
+    uint16_t index;               /* extra field (not in file) */
+};
+
+/*  (1) This is from
+ *  http://blogs.msdn.com/b/oldnewthing/archive/2010/10/19/10077610.aspx.
+ *
+ *  However, the bpp value in the icon directory is used as a hint for
+ *  image selection only.  It seems to be legal to set this value to
+ *  zero, and e.g. in SHELL32.DLL of Win98SE, there are many 8bpp
+ *  images described as 24 bit images in the icon directory.
+ *
+ *  The bpp value of image 1 in icon 150 in SHELL32.DLL of WinXP is 24
+ *  (in header and BMP).  This may be a bug, as the 32 x 32 x 8 image
+ *  is missing, but it shows the Windows icon rendering engine is able
+ *  to cope with 24 bit images).
+ *
+ *  16bpp icons are at least rare in the wild.
+ */
+struct IconDir {
+    uint16_t zero;                /* 0 */
+    uint16_t type;                /* 1 */
+    uint16_t count;               /* number of images in icon */
+
+    unsigned int entriesAllocCt;     /* # of allocated slots in 'entries'*/
+    struct IconDirEntry * entries;   /* one entry for each image */
+};
+
+/*  BMP image structures  */
+
+struct BitmapInfoHeader {
+    uint32_t header_size;         /* >= 40 */
+    int32_t  bm_width;
+    int32_t  bm_height;
+    uint16_t color_planes;
+    uint16_t bits_per_pixel;
+    uint32_t compression_method;
+    uint32_t image_size;
+    int32_t  horizontal_resolution; /* pixels per meter (!) */
+    int32_t  vertical_resolution;   /* pixels per meter (!) */
+    uint32_t colors_in_palette;
+    uint32_t important_colors;
+
+    bool top_down;                /* extra field (not in file) */
+
+};
+
+typedef enum {
+    BI_RGB       = 0,
+    BI_BITFIELDS = 3
+
+} BiCompression;
+
+/*  PNG image structures  */
+#define PNG_HEADER { 0x89, 'P', 'N', 'G', '\r', '\n', 0x1A /* ^Z */, '\n' }
+
+struct PngIhdr {
+    uint32_t length;              /* 13 */
+    uint32_t signature;           /* "IHDR" */
+    uint32_t width;               /* image width in pixels */
+    uint32_t height;              /* image height in pixels */
+    uint8_t  bit_depth;           /* depth per channel */
+    uint8_t  color_type;          /* recognized values: 0, 2, 3, 4 and 6 */
+    uint8_t  compression;
+    uint8_t  filter;
+    uint8_t  interlace;
+    uint32_t crc;
+};
diff --git a/converter/other/winicontopam.c b/converter/other/winicontopam.c
new file mode 100644
index 00000000..664b4ef9
--- /dev/null
+++ b/converter/other/winicontopam.c
@@ -0,0 +1,1286 @@
+#include <assert.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "netpbm/pm_config.h"
+#include "netpbm/pm_c_util.h"
+#include "netpbm/mallocvar.h"
+#include "netpbm/nstring.h"
+#include "netpbm/shhopt.h"
+#include "netpbm/pam.h"
+#include "netpbm/pm_system.h"
+
+#include "winicon.h"
+
+#define RED   0
+#define GRN   1
+#define BLU   2
+#define ALPHA 3
+#define CHANNEL_CHARS "RGBA"
+
+
+
+static bool verbose;
+
+
+
+struct CmdlineInfo {
+    
+    const char * inputFileName;
+    unsigned int allimages;
+    unsigned int imageSpec;
+    unsigned int image;
+    unsigned int andmasks;
+    unsigned int headerdump;
+    unsigned int verbose;
+};
+
+
+
+static void
+parseCommandLine(int argc, const char **argv,
+                 struct CmdlineInfo * const cmdlineP) {
+
+    optEntry *   option_def;
+    unsigned int option_def_index;
+    optStruct3   opt3;
+
+    MALLOCARRAY_NOFAIL(option_def, 100);
+
+    option_def_index = 0;
+
+    OPTENT3(0, "allimages",   OPT_FLAG,   NULL,
+            &cmdlineP->allimages,         0);
+    OPTENT3(0, "image",     OPT_UINT,   &cmdlineP->image,
+            &cmdlineP->imageSpec,         0);
+    OPTENT3(0, "andmasks",  OPT_FLAG,   NULL,
+            &cmdlineP->andmasks,          0);
+    OPTENT3(0, "headerdump",   OPT_FLAG,   NULL,
+            &cmdlineP->headerdump,        0);
+    OPTENT3(0, "verbose",   OPT_FLAG,   NULL,
+            &cmdlineP->verbose,           0);
+
+    opt3.opt_table     = option_def;
+    opt3.short_allowed = false;
+    opt3.allowNegNum   = false;
+
+    pm_optParseOptions3(&argc, (char **)argv, opt3, sizeof(opt3), 0);
+
+    if (cmdlineP->allimages && cmdlineP->imageSpec)
+        pm_error("You cannot specify both -allimages and -image");
+
+    if (argc-1 < 1)
+        cmdlineP->inputFileName = "-";
+    else {
+        cmdlineP->inputFileName = argv[1];
+
+        if (argc-1 > 1)
+            pm_error("Too many arguments.  The only possible "
+                     "non-option argument is the input file name");
+    }
+        
+    free(option_def);
+}
+
+
+
+static unsigned char const pngHeader[] = PNG_HEADER;
+
+
+
+struct File {
+
+    FILE *       fileP;
+    const char * name;
+    pm_filepos   pos;
+    
+};
+
+
+
+static uint32_t
+u8_le(const unsigned char * const buf,
+      size_t                const offset) {
+
+    return buf[offset + 0];
+}
+
+
+
+static uint32_t
+u16_le(const unsigned char * const buf,
+       size_t                const offset) {
+
+    return
+        ((uint32_t)buf[offset + 0] << 0) +
+        ((uint32_t)buf[offset + 1] << 8);
+}
+
+
+
+static uint32_t
+u32_le(const unsigned char * const buf,
+       size_t                const offset) {
+
+    return 
+        ((uint32_t)buf[offset + 0] <<  0) +
+        ((uint32_t)buf[offset + 1] <<  8) +
+        ((uint32_t)buf[offset + 2] << 16) +
+        ((uint32_t)buf[offset + 3] << 24);
+}
+
+
+
+static uint32_t
+s32_le(const unsigned char * const buf,
+       size_t                const offset) {
+
+    return 
+        ((uint32_t)buf[offset + 0] <<  0) +
+        ((uint32_t)buf[offset + 1] <<  8) +
+        ((uint32_t)buf[offset + 2] << 16) +
+        ((uint32_t)buf[offset + 3] << 24);
+}
+
+
+
+static uint32_t
+u8_be(const unsigned char * const buf,
+      size_t                const offset) {
+
+    return buf[offset + 0];
+}
+
+
+
+static uint32_t
+u32_be(const unsigned char * const buf,
+       size_t                const offset) {
+    
+    return 
+        ((uint32_t)buf[offset + 0] << 24) +
+        ((uint32_t)buf[offset + 1] << 16) +
+        ((uint32_t)buf[offset + 2] <<  8) +
+        ((uint32_t)buf[offset + 3] <<  0);
+}
+
+
+
+static uint32_t
+u32_xx(const unsigned char * const buf,
+       size_t                const offset) {
+
+    uint32_t u32;
+
+    ((uint8_t*) &u32)[0] = buf[offset + 0];
+    ((uint8_t*) &u32)[1] = buf[offset + 1];
+    ((uint8_t*) &u32)[2] = buf[offset + 2];
+    ((uint8_t*) &u32)[3] = buf[offset + 3];
+
+    return (u32);
+}
+
+
+
+#ifndef LITERAL_FN_DEF_MATCH
+static qsort_comparison_fn cmpfn;
+#endif
+
+static int
+cmpfn(const void * const aP,
+      const void * const bP) {
+
+    const struct IconDirEntry * const dirEntryAP = aP;
+    const struct IconDirEntry * const dirEntryBP = bP;
+
+    if (dirEntryAP->offset < dirEntryBP->offset)
+        return -1;
+    else if (dirEntryAP->offset > dirEntryBP->offset)
+        return +1;
+    else
+        return 0;
+}
+
+
+
+static void
+dumpIconDir(const struct IconDir * const dirP) {
+
+    unsigned int i;
+
+    pm_message("Type: %u", dirP->type);
+    pm_message("Icon directory has %u images:", dirP->count);
+
+    for (i = 0; i < dirP->count; ++i) {
+        const struct IconDirEntry * const dirEntryP = &dirP->entries[i];
+
+        pm_message("width: %u", dirEntryP->width);
+        pm_message("height: %u", dirEntryP->height);
+        pm_message("color count: %u", dirEntryP->color_count);
+        pm_message("# color planes: %u", dirEntryP->color_planes);
+        pm_message("bits per pixel: %u", dirEntryP->bits_per_pixel);
+        pm_message("offset in file of image: %u", dirEntryP->offset);
+        pm_message("size of image: %u", dirEntryP->size);
+        pm_message("zero field: %u", dirEntryP->zero);
+    }
+}
+
+            
+
+static struct IconDir *
+readIconDir(struct File * const fP,
+            bool          const needHeaderDump) {
+
+    struct IconDir head;
+    struct IconDir * dirP;
+    uint32_t  imageIndex; /* more bits than dir.count */
+
+    pm_readlittleshortu(fP->fileP, &head.zero);
+    pm_readlittleshortu(fP->fileP, &head.type);
+    pm_readlittleshortu(fP->fileP, &head.count);
+    fP->pos += 6;
+
+    if (head.zero != 0 || head.type != ICONDIR_TYPE_ICO)
+        pm_error("Not a valid windows icon file");
+
+    MALLOCVAR(dirP);
+
+    if (dirP == NULL)
+        pm_error("Could't allocate memory for Icon directory");
+
+    MALLOCARRAY(dirP->entries, head.count);
+
+    if (dirP->entries == NULL)
+        pm_error("Could not allocate memory for %u entries in icon directory",
+                 head.count);
+
+    dirP->zero           = head.zero;
+    dirP->type           = head.type;
+    dirP->count          = head.count;
+    dirP->entriesAllocCt = head.count;
+
+    for (imageIndex = 0; imageIndex < head.count; ++imageIndex) {
+        struct IconDirEntry * const dirEntryP = &dirP->entries[imageIndex];
+
+        unsigned char widthField, heightField;
+
+        unsigned long ul;
+
+        pm_readcharu(fP->fileP, &widthField);
+        dirEntryP->width  = (widthField == 0 ? 256 : widthField);
+
+        pm_readcharu(fP->fileP, &heightField);
+        dirEntryP->height = (heightField == 0 ? 256 : heightField);
+        
+        pm_readcharu(fP->fileP, &dirEntryP->color_count);
+
+        pm_readcharu(fP->fileP, &dirEntryP->zero);
+
+        pm_readlittleshortu(fP->fileP, &dirEntryP->color_planes);
+
+        pm_readlittleshortu(fP->fileP, &dirEntryP->bits_per_pixel);
+
+        pm_readlittlelongu(fP->fileP, &ul); dirEntryP->size = ul;
+
+        pm_readlittlelongu(fP->fileP, &ul); dirEntryP->offset = ul;
+
+        fP->pos += 16;
+
+        dirEntryP->index = imageIndex;
+    }
+
+    /* The following is paranoia code only:
+     
+       I've never seen a windows icon file in the wild with having the entries
+       in the directory stored in a different order than the images
+       themselves.  However, the file format allows for it ...
+     */
+    qsort(dirP->entries, dirP->count, sizeof(struct IconDirEntry), cmpfn);
+
+    if (verbose) {
+        pm_message("%s icon directory (%u image%s):",
+                   fP->name,
+                   dirP->count, dirP->count == 1 ? "" : "s");
+        
+        for (imageIndex = 0; imageIndex < dirP->count; ++imageIndex) {
+            const struct IconDirEntry * const dirEntryP =
+                &dirP->entries[imageIndex];
+
+            uint32_t colorCt;
+
+            if (dirEntryP->bits_per_pixel == 0)
+                colorCt = 0;
+            else if (dirEntryP->bits_per_pixel >= 32)
+                colorCt = 1u << 24;
+            else
+                colorCt = 1u << dirEntryP->bits_per_pixel;
+
+            if (dirEntryP->color_count != 0 &&
+                colorCt > dirEntryP->color_count) {
+                colorCt = dirEntryP->color_count;
+            }
+            pm_message ("%5u: %3u x %3u, %8u colors, %5u bytes",
+                        dirEntryP->index,
+                        dirEntryP->width,
+                        dirEntryP->height,
+                        colorCt,
+                        dirEntryP->size);
+        }
+    }
+
+    if (needHeaderDump)
+        dumpIconDir(dirP);
+
+    return dirP;
+}
+
+
+
+static void
+freeIconDir(struct IconDir * const dirP) {
+
+    free(dirP->entries);
+    free(dirP);
+}
+
+
+
+static const unsigned char *
+readImage(struct File *         const fP,
+          struct IconDirEntry * const dirEntryP) {
+
+    size_t rc;
+    unsigned char * image;
+    uint32_t skippedCt;
+
+    /*  Don't try to read an image that is smaller than the
+        BITMAPINFOHEADER of BMP images (40 bytes).
+     
+        PNG compressed images can't be smaller than that either, as the
+        PNG header plus the mandantory IHDR and IEND chunks already take
+        8 + 25 + 12 = 35 bytes, and there is to be a IDAT chunk too.
+     */
+    if (dirEntryP->size < 40) {
+        pm_error("image %2u: format violation: too small as an image.",
+                  dirEntryP->index);
+    }
+    if ((pm_filepos) dirEntryP->offset < fP->pos)
+        pm_error("image %2u: format violation: invalid offset.",
+                 dirEntryP->index);
+
+    /* The following is paranoia code only:
+     
+       I've never seen a windows icon file in the wild with gaps between
+       the images, but the file format allows for it, and Microsoft
+       expects the user to fseek() to the start of each image.
+     */
+    skippedCt = 0;
+
+    while ((pm_filepos) dirEntryP->offset > fP->pos) {
+        if (getc(fP->fileP) == EOF) {
+            pm_error("seeking to image %u: unexpected EOF", dirEntryP->index);
+        }
+        ++fP->pos;
+        ++skippedCt;
+    }
+
+    /*  The additional four bytes are for purify and friends, as the
+        routines reading BMP XOR and AND masks might read (but not
+        evaluate) some bytes beyond the image data.
+     */
+    image = malloc(dirEntryP->size + sizeof(uint32_t));
+    if (image == NULL)
+        pm_error("out of memory.");
+
+    rc = fread (image, 1, dirEntryP->size, fP->fileP);
+    if (rc != dirEntryP->size) {
+        pm_error("reading image %2u: unexpected EOF", dirEntryP->index);
+    }
+    fP->pos += dirEntryP->size;
+
+    return image;
+}
+
+
+
+static uint8_t
+getIdx1(const unsigned char * const bitmap,
+        uint32_t              const offset,
+        int16_t               const col) {
+
+    return u8_le(bitmap, offset + (col >> 3)) >> (7 - (col & 0x07)) & 0x1;
+}
+
+
+
+static uint8_t
+getIdx4(const unsigned char * const bitmap,
+        uint32_t              const offset,
+        int16_t               const col) {
+
+    if ((col & 1) == 0x0000)
+        return u8_le(bitmap, offset + (col >> 1)) >> 4 & 0x0F;
+    else
+        return u8_le(bitmap, offset + (col >> 1)) >> 0 & 0x0F;
+}
+
+
+
+static uint8_t
+getIdx8(const unsigned char * const bitmap,
+        uint32_t              const offset,
+        int16_t               const col) {
+
+    return u8_le(bitmap, offset + col);
+}
+
+
+
+typedef unsigned char PaletteEntry[4];
+
+
+
+static void
+dumpPalette(const PaletteEntry * const palette,
+            unsigned int         const colorCt) {
+
+    unsigned int i;
+
+    for (i = 0; i < colorCt; ++i) {
+        pm_message("Color %u: (%u, %u, %u)",
+                   i, palette[i][2], palette[i][1], palette[i][0]);
+    }
+}
+
+
+
+static void
+readXorPalette(struct BitmapInfoHeader * const hdrP,
+               const unsigned char *     const bitmap,
+               uint32_t                  const maxSize,
+               tuple **                  const tuples,
+               uint16_t                  const index,
+               bool                      const needHeaderDump,
+               uint32_t *                const bytesConsumedP) {
+
+    uint32_t paletteSize;
+
+    int16_t     row;
+    const PaletteEntry * palette;
+    uint32_t    truncatedXorSize;
+    uint32_t    bytesConsumed;
+    uint32_t    bytesPerRow;
+    const unsigned char * bitmapCursor;
+    uint32_t sizeRemaining;
+  
+    uint8_t (*getIdx) (const unsigned char * bitmap,
+                       uint32_t rowOffset,
+                       int16_t col);
+  
+    if (hdrP->compression_method != BI_RGB)
+        pm_error("image %2u: invalid compression method %u.",
+                 index, hdrP->compression_method);
+
+    assert(hdrP->bits_per_pixel < 16);
+
+    switch (hdrP->bits_per_pixel) {
+    case 1:
+        if (hdrP->colors_in_palette == 0)
+            hdrP->colors_in_palette = 2;
+        getIdx = getIdx1;
+        break;
+
+    case 4:
+        if (hdrP->colors_in_palette == 0)
+            hdrP->colors_in_palette = 16;
+        getIdx = getIdx4;
+        break;
+
+    case 8:
+        if (hdrP->colors_in_palette == 0)
+            hdrP->colors_in_palette = 256;
+        getIdx = getIdx8;
+        break;
+
+    default:
+        pm_error("image %2u: "
+                 "bits per pixel is a value we don't understand: %u",
+                  index, hdrP->bits_per_pixel);
+        getIdx = NULL;
+    }
+
+    bitmapCursor = &bitmap[0];  /* initial value */
+    sizeRemaining = maxSize;    /* initial value */
+    bytesConsumed = 0;          /* initial value */
+
+    paletteSize = hdrP->colors_in_palette * 4;
+
+    if (sizeRemaining < paletteSize)
+        pm_error("image %2u: "
+                 "reading palette: image truncated.", index);
+    
+    palette = (const PaletteEntry *) bitmapCursor;
+
+    if (needHeaderDump)
+        dumpPalette(palette, hdrP->colors_in_palette);
+
+    bitmapCursor  += paletteSize;
+    sizeRemaining -= paletteSize;
+    bytesConsumed += paletteSize;
+
+    {
+        uint32_t const xorSize = (uint32_t)
+            (((hdrP->bits_per_pixel * hdrP->bm_width + 31) / 32)
+             * 4 * hdrP->bm_height / 2);
+
+        if (sizeRemaining < xorSize) {
+            pm_message("image %2u: "
+                       "reading XOR mask: image truncated.", index);
+            truncatedXorSize = sizeRemaining;
+        } else
+            truncatedXorSize = xorSize;
+    }
+
+    bytesPerRow = ((hdrP->bits_per_pixel * hdrP->bm_width + 31) / 32) * 4;
+
+    for (row = 0; hdrP->bm_height / 2 > row; ++row) {
+        uint32_t rowOffset;
+
+        if (hdrP->top_down)
+            rowOffset = row * bytesPerRow;
+        else
+            rowOffset = (hdrP->bm_height / 2 - row - 1) * bytesPerRow;
+
+        if (rowOffset + bytesPerRow <= truncatedXorSize) {
+            int16_t col;
+            for (col = 0; hdrP->bm_width > col; ++col) {
+                uint8_t const idx = getIdx(bitmapCursor, rowOffset, col);
+
+                if (idx > hdrP->colors_in_palette)
+                    pm_error("invalid palette index in row %u, column %u.",
+                             row, col);
+
+                /*  The palette is an array of little-endian 32-bit values,
+                    where the RGB value is encoded as follows:
+                 
+                    red:   bits 2^16..2^23
+                    green: bits 2^8 ..2^15
+                    blue:  bits 2^0 ..2^7
+                 */
+                tuples[row][col][PAM_RED_PLANE] = palette[idx][2];
+                tuples[row][col][PAM_GRN_PLANE] = palette[idx][1];
+                tuples[row][col][PAM_BLU_PLANE] = palette[idx][0];
+            }
+        }
+    }
+
+    bitmapCursor  += truncatedXorSize;
+    sizeRemaining -= truncatedXorSize;
+    bytesConsumed += truncatedXorSize;
+
+    *bytesConsumedP = bytesConsumed;
+}
+
+
+
+static void
+readXorBitfields(struct BitmapInfoHeader * const hdrP,
+                 const unsigned char *     const bitmap,
+                 uint32_t                  const maxSize,
+                 tuple **                  const tuples,
+                 uint16_t                  const index,
+                 bool *                    const haveAlphaP,
+                 uint32_t *                const bytesConsumedP) {
+
+    uint32_t   bitfields[4];
+    uint8_t    shift    [4];
+    sample     maxval   [4];
+
+    int16_t      row;
+    uint32_t     bytesConsumed;
+    uint32_t     bytesPerSample;
+    uint32_t     bytesPerRow;
+    const unsigned char * bitmapCursor;
+    uint32_t     sizeRemaining;
+    uint32_t     truncatedXorSize;
+
+    static uint8_t alphas [256];
+    bool         allOpaque;
+    bool         allTransparent;
+
+    bytesConsumed = 0;
+
+    if (hdrP->compression_method != BI_RGB
+        && hdrP->compression_method != BI_BITFIELDS)
+        pm_error("image %2u: invalid compression method %u.",
+                 index, hdrP->compression_method);
+
+    assert(hdrP->bits_per_pixel >= 16);
+
+    switch (hdrP->bits_per_pixel) {
+    case 16:
+        bytesPerSample = 2;
+        bitfields[RED]   = 0x7C00;
+        bitfields[GRN]   = 0x03E0;
+        bitfields[BLU]   = 0x001F;
+        bitfields[ALPHA] = 0x0000;
+        break;
+
+    case 24:
+        bytesPerSample = 3;
+        bitfields[RED]   = 0xFF0000;
+        bitfields[GRN]   = 0x00FF00;
+        bitfields[BLU]   = 0x0000FF;
+        bitfields[ALPHA] = 0x000000;
+        break;
+
+    case 32:
+        bytesPerSample = 4;
+        bitfields[RED]   = 0x00FF0000;
+        bitfields[GRN]   = 0x0000FF00;
+        bitfields[BLU]   = 0x000000FF;
+        bitfields[ALPHA] = 0xFF000000;
+        break;
+
+    default:
+        pm_error("image %2u: bits per pixel is one we don't understand: %u.",
+                 index, hdrP->bits_per_pixel);
+        bytesPerSample = 0;
+    }
+
+    bitmapCursor = &bitmap[0]; /* initial value */
+    sizeRemaining = maxSize;  /* initial value */
+
+    /*  read bit fields from image data  */
+    if (hdrP->compression_method == BI_BITFIELDS) {
+        if (sizeRemaining < 12)
+            pm_error("image %2u: "
+                     "reading bit fields: image truncated.", index);
+
+        bitfields[RED]   = u32_le(bitmapCursor, 0);
+        bitfields[GRN]   = u32_le(bitmapCursor, 4);
+        bitfields[BLU]   = u32_le(bitmapCursor, 8);
+        bitfields[ALPHA] = 0;
+
+        bitmapCursor  += 12;
+        sizeRemaining -= 12;
+        bytesConsumed += 12;
+    }
+
+    /*  determine shift and maxval from bit field for each channel */
+    {
+        unsigned int i;
+
+        for (i = 0; 4 > i; ++i) {
+            if (bitfields[i] == 0) {
+                maxval[i] = 1;
+                shift [i] = 0;
+            } else {
+                unsigned int j;
+
+                maxval[i] = bitfields[i];
+
+                for (j = 0; 32 > j; ++j) {
+                    if ((maxval[i] & 0x1) != 0)
+                        break;
+                    maxval[i] >>= 1;
+                }
+                shift[i] = j;
+            }
+
+        }
+    }
+
+    /*  read the XOR mask */
+    {
+        uint32_t const xorSize = (uint32_t)
+            (((hdrP->bits_per_pixel * hdrP->bm_width + 31) / 32)
+             * 4 * hdrP->bm_height / 2);
+
+        if (sizeRemaining < xorSize) {
+            pm_message("image %2u: "
+                       "reading XOR mask: image truncated.", index);
+            truncatedXorSize = sizeRemaining;
+        } else
+            truncatedXorSize = xorSize;
+    }
+
+    bytesPerRow = ((hdrP->bits_per_pixel * hdrP->bm_width + 31) / 32) * 4;
+    MEMSZERO(alphas);
+
+    for (row = 0, allOpaque = true, allTransparent = true;
+         hdrP->bm_height / 2 > row;
+         ++row) {
+
+        uint32_t offset;
+
+        if (hdrP->top_down)
+            offset = row * bytesPerRow;
+        else
+            offset = (hdrP->bm_height / 2 - row - 1) * bytesPerRow;
+
+        if (offset + bytesPerRow <= truncatedXorSize) {
+            unsigned int col;
+            for (col = 0; col < hdrP->bm_width; ++col) {
+                uint32_t const pixel = u32_le(bitmapCursor, offset);
+                offset += bytesPerSample;
+
+                tuples[row][col][PAM_RED_PLANE] =
+                    pnm_scalesample((pixel & bitfields[RED]) >> shift[RED],
+                                    maxval[RED], 255);
+                tuples[row][col][PAM_GRN_PLANE] =
+                    pnm_scalesample((pixel & bitfields[GRN]) >> shift[GRN],
+                                    maxval[GRN], 255);
+                tuples [row][col][PAM_BLU_PLANE]
+                    = pnm_scalesample((pixel & bitfields[BLU]) >> shift[BLU],
+                                      maxval[BLU], 255);
+
+                if (bitfields [ALPHA] != 0) {
+                    tuples[row][col][PAM_TRN_PLANE]
+                        = pnm_scalesample(
+                            (pixel & bitfields[ALPHA]) >> shift[ALPHA],
+                            maxval[ALPHA], 255);
+
+                    if (tuples[row][col][PAM_TRN_PLANE] != 0)
+                        allTransparent = false;
+
+                    if (tuples [row][col][PAM_TRN_PLANE] != 255)
+                        allOpaque = false;
+
+                    alphas[tuples[row][col][PAM_TRN_PLANE]] = !0;
+                }
+            }
+        }
+    }
+
+    bitmapCursor  += truncatedXorSize;
+    sizeRemaining -= truncatedXorSize;
+    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.
+    */
+    *haveAlphaP = !allTransparent && !allOpaque;
+
+    if (!allTransparent && verbose) {
+        unsigned int i;
+        unsigned int c;
+
+        for (i = 0, c = 0; 256 > i; ++i) {
+            if (alphas[i] != 0)
+                ++c;
+        }
+        pm_message("image %2u: %u distinct transparency value%s",
+                   index, c, (c == 1) ? "": "s");
+    }
+    *bytesConsumedP = bytesConsumed;
+}
+
+
+
+static void
+readAnd(struct BitmapInfoHeader * const hdrP,
+        const unsigned char *     const bitmap,
+        uint32_t                  const maxSize,
+        tuple **                  const tuples,
+        uint16_t                  const index,
+        unsigned int              const plane,
+        sample                    const maxval) {
+
+    int16_t  row;
+    uint32_t bytesConsumed;
+    uint32_t bytesPerRow;
+    uint32_t sizeRemaining;
+    uint32_t truncatedAndSize;
+
+    sizeRemaining = maxSize;  /* initial value */
+    bytesConsumed = 0;  /* initial value */
+
+    {
+        uint32_t const andSize = (uint32_t)
+            (((1 * hdrP->bm_width + 31) / 32) * 4 * hdrP->bm_height / 2);
+
+        if (sizeRemaining < andSize) {
+            pm_message ("image %2u: "
+                        "Input image ends %u bytes into the %u-byte "
+                        "AND mask.  Implying remainder of mask",
+                        index, sizeRemaining, andSize);
+            truncatedAndSize = sizeRemaining;
+        } else
+            truncatedAndSize = andSize;
+    }
+
+    bytesPerRow = ((1 * hdrP->bm_width + 31) / 32) * 4;
+
+    for (row = 0; row < hdrP->bm_height / 2; ++row) {
+        uint32_t offset;
+
+        if (hdrP->top_down)
+            offset = row * bytesPerRow;
+        else
+            offset = (hdrP->bm_height / 2 - row - 1) * bytesPerRow;
+
+        if (offset + bytesPerRow <= sizeRemaining) {
+            unsigned int col;
+            
+            for (col = 0; col < hdrP->bm_width; ++col) {
+                tuples[row][col][plane] =
+                    ((u8_le(bitmap, offset + col/8)
+                      & (1 << (7 - (col & 0x7)))) == 0x00) ?
+                    maxval : 0
+                ;
+            }
+        }
+    }
+    sizeRemaining -= truncatedAndSize;
+    bytesConsumed += truncatedAndSize;
+}
+
+
+
+static void
+dumpBmpHeader(struct BitmapInfoHeader const hdr,
+              unsigned int            const imageIndex) {
+
+    pm_message("BMP header for Image %u:", imageIndex);
+
+    pm_message("header size: %u", hdr.header_size);
+    pm_message("bitmap width: %u", hdr.bm_width);
+    pm_message("bitmap height * 2: %u", hdr.bm_height);
+    pm_message("row order: %s", hdr.top_down ? "top down" : "bottom up");
+    pm_message("# color planes: %u", hdr.color_planes);
+    pm_message("bits per pixel: %u", hdr.bits_per_pixel);
+    pm_message("image size: %u", hdr.image_size);
+    pm_message("horizontal resolution: %u", hdr.horizontal_resolution);
+    pm_message("vertical resolution: %u", hdr.vertical_resolution);
+    pm_message("# colors in palette: %u", hdr.colors_in_palette);
+    pm_message("# important colors: %u", hdr.important_colors);
+}
+
+
+
+static void
+readBmpHeader(const unsigned char *     const image,
+              uint32_t                  const size,
+              unsigned int              const imageIndex,
+              bool                      const needHeaderDump,
+              struct BitmapInfoHeader * const hdrP) {
+
+    /*  BITMAPINFOHEADER structure */
+
+    if (size < 40)
+        pm_error("image %2u: reading BITMAPINFOHEADER: not enough data.",
+                 imageIndex);
+
+    hdrP->header_size           = u32_le(image,  0);
+    hdrP->bm_width              = s32_le(image,  4);
+    hdrP->bm_height             = s32_le(image,  8);
+    hdrP->color_planes          = u16_le(image, 12);
+    hdrP->bits_per_pixel        = u16_le(image, 14);
+    hdrP->compression_method    = u32_le(image, 16);
+    hdrP->image_size            = u32_le(image, 20);
+    hdrP->horizontal_resolution = s32_le(image, 24);
+    hdrP->vertical_resolution   = s32_le(image, 28);
+    hdrP->colors_in_palette     = u32_le(image, 32);
+    hdrP->important_colors      = u32_le(image, 36);
+
+    if (hdrP->bm_height > 0) {
+        hdrP->top_down = false;
+    } else {
+        hdrP->top_down   = true;
+        hdrP->bm_height *= -1;
+    }
+
+    if (hdrP->header_size < 36
+        || hdrP->bm_width == 0 || hdrP->bm_height == 0
+        || (hdrP->bm_height & 1) != 0x0000) {
+        pm_error("image %2u: format violation: invalid BMP header.",
+                 imageIndex);
+    }
+
+    if (needHeaderDump)
+        dumpBmpHeader(*hdrP, imageIndex);
+}
+
+
+
+static void
+readXorMask(struct BitmapInfoHeader * const hdrP,
+            const unsigned char *     const imageCursor,
+            uint32_t                  const imageSize,
+            tuple **                  const tuples,
+            uint16_t                  const index,
+            bool                      const needHeaderDump,
+            bool *                    const haveAlphaP,
+            uint32_t *                const bytesConsumedP) {
+/*----------------------------------------------------------------------------
+   Read the so-called XOR mask (for non-monochrome images, this is the
+   color pixmap)
+-----------------------------------------------------------------------------*/
+    /*  preset the PAM with fully opaque black (just in case the image
+        is truncated and not all pixels are filled in below).
+    */
+    {
+        unsigned int row;
+
+        for (row = 0; row < hdrP->bm_height / 2; ++row) {
+            unsigned int col;
+            for (col = 0; col < hdrP->bm_width; ++col) {
+                tuples[row][col][PAM_RED_PLANE] = 0;
+                tuples[row][col][PAM_GRN_PLANE] = 0;
+                tuples[row][col][PAM_BLU_PLANE] = 0;
+                tuples[row][col][PAM_TRN_PLANE] = 255;
+            }
+        }
+    }
+
+    if (hdrP->bits_per_pixel < 16) {
+        readXorPalette(hdrP, imageCursor, imageSize, tuples, index,
+                       needHeaderDump,
+                       bytesConsumedP);
+        *haveAlphaP = false;
+    } else
+        readXorBitfields(hdrP, imageCursor, imageSize, tuples, index,
+                         haveAlphaP, bytesConsumedP);
+}
+
+
+
+static void
+reportImage(unsigned int            const imageIndex,
+            struct BitmapInfoHeader const hdr,
+            bool                    const haveAlpha) {
+
+    const char * const style = 
+        haveAlpha ? "RGB +alpha" :
+        hdr.bits_per_pixel < 16 ? "RGB/palette" :
+        "RGB"
+        ;
+
+    pm_message("image %2u: "
+               "BMP %3u x %3u x %2u (%s)",
+               imageIndex,
+               hdr.bm_width, hdr.bm_height / 2, hdr.bits_per_pixel,
+               style);
+}
+
+
+
+static void
+convertBmp(const unsigned char * const image,
+           FILE *                const ofP,
+           struct IconDirEntry * const dirEntryP,
+           bool                  const needHeaderDump,
+           bool                  const wantAndMaskPlane) {
+    
+    struct BitmapInfoHeader hdr;
+    uint32_t                offset;
+    bool                    haveAlpha;
+    uint32_t                xorByteCt;
+
+    struct pam outpam;
+    tuple **   tuples;
+
+    readBmpHeader(image, dirEntryP->size, dirEntryP->index, needHeaderDump,
+                  &hdr);
+
+    offset = hdr.header_size;  /* Start after header */
+
+    if ((dirEntryP->width != hdr.bm_width)
+        || (dirEntryP->height != hdr.bm_height / 2)) {
+        pm_message("image %2u: "
+                   "mismatch in header and image dimensions "
+                   "(%u x %u vs. %u x %u)",
+                   dirEntryP->index,
+                   dirEntryP->width,
+                   dirEntryP->height,
+                   hdr.bm_width,
+                   hdr.bm_height / 2);
+    }
+
+    if ((dirEntryP->bits_per_pixel != 0)
+        && (dirEntryP->bits_per_pixel != hdr.bits_per_pixel)) {
+        pm_message("image %2u "
+                   "mismatch in header and image bpp value"
+                   "(%u vs. %u)",
+                   dirEntryP->index,
+                   dirEntryP->bits_per_pixel,
+                   hdr.bits_per_pixel);
+    }
+
+    outpam.size   = sizeof(struct pam);
+    outpam.len    = PAM_STRUCT_SIZE(allocation_depth);
+    outpam.file   = ofP;
+    outpam.format = PAM_FORMAT;
+    outpam.width  = hdr.bm_width;
+    outpam.height = hdr.bm_height / 2;
+    outpam.maxval = 255;
+    outpam.allocation_depth = 5;
+    outpam.depth  = 0;
+        /* Just for tuple array allocation; we set the value for the actual
+           output image below.
+        */
+
+    tuples = pnm_allocpamarray(&outpam);
+
+    readXorMask(&hdr, &image[offset], 
+                dirEntryP->size - offset,
+                tuples, dirEntryP->index, needHeaderDump,
+                &haveAlpha, &xorByteCt);
+
+    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
+        */
+        bool haveAnd;
+        unsigned int andPlane;
+
+        if (!haveAlpha) {
+            haveAnd = true;
+            andPlane = PAM_TRN_PLANE;
+            strcpy (outpam.tuple_type, "RGB_ALPHA");
+            outpam.depth  = 4;
+        } else if (wantAndMaskPlane) {
+            haveAnd = true;
+            andPlane = PAM_TRN_PLANE + 1;
+            outpam.depth  = 5;
+            strcpy(outpam.tuple_type, "RGB_ALPHA_ANDMASK");
+        } else {
+            haveAnd = false;
+            strcpy (outpam.tuple_type, "RGB_ALPHA");
+            outpam.depth  = 4;
+        }
+        if (haveAnd) {
+            readAnd(&hdr, &image[offset], dirEntryP->size - offset,
+                    tuples, dirEntryP->index, andPlane, outpam.maxval);
+        }
+    }
+    pnm_writepam(&outpam, tuples);
+    pnm_freepamarray(tuples, &outpam);
+
+    reportImage(dirEntryP->index, hdr, haveAlpha);
+}
+
+
+
+static void
+reportPngInfo(const unsigned char * const image,
+              struct IconDirEntry * const dirEntryP) {
+    
+    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);
+
+    if ((ihdr.length != 13)
+        || ihdr.signature != *(uint32_t*)"IHDR") {
+        pm_message("image %2u: PNG (uncommonly formatted)",
+                   dirEntryP->index);
+    } else {
+        uint32_t depth;
+        const char * colorType;
+
+        switch (ihdr.color_type) {
+        case 0:
+            colorType = "grayscale";
+            depth     = ihdr.bit_depth;
+            break;
+
+        case 2:
+            colorType = "RGB";
+            depth     = ihdr.bit_depth * 3;
+            break;
+
+        case 3:
+            colorType = "RGB/palette";
+            depth     = 8;
+            break;
+
+        case 4:
+            colorType = "grayscale + alpha";
+            depth     = ihdr.bit_depth * 2;
+            break;
+
+        case 6:
+            colorType = "RGB + alpha";
+            depth     = ihdr.bit_depth * 4;
+            break;
+
+        default:
+            colorType = "unknown color system";
+            depth     = 0;
+            break;
+        }
+        pm_message("image %2u: PNG %3u x %3u x %2u (%s)",
+                   dirEntryP->index,
+                   ihdr.width, ihdr.height, depth, colorType);
+
+        if ((dirEntryP->width != ihdr.width)
+            || (dirEntryP->height != ihdr.height)) {
+            pm_message("image %2u:"
+                       " mismatch in header and image dimensions"
+                       " (%u x %u vs %u x %u)",
+                       dirEntryP->index, dirEntryP->width, dirEntryP->height,
+                       ihdr.width, ihdr.height);
+        }
+        /* Mismatch between dirEntryP->bits_per_pixel and 'depth' is
+           normal, because the creator of the winicon file doesn't necessarily
+           know the true color resolution.
+        */
+    }
+}
+
+
+
+static void
+convertPng(const unsigned char * const image,
+           FILE *                const ofP,
+           struct IconDirEntry * const dirEntryP) {
+
+    struct bufferDesc imageBuffer;
+
+    reportPngInfo(image, dirEntryP);
+
+    imageBuffer.size = dirEntryP->size;
+    imageBuffer.buffer = (unsigned char *)image;
+
+    fflush (stdout);
+    pm_system(pm_feed_from_memory, &imageBuffer,
+              NULL /* stdout accepter */, NULL,
+              "pngtopam -alphapam");
+}
+
+
+
+static uint32_t
+bestImage(struct IconDir * const dirP) {
+
+    uint32_t imageIndex;
+    uint32_t bestPixelCt;
+    uint32_t bestColorCt;
+    uint16_t best;
+
+    bestPixelCt = 0;  /* initial value */
+    bestColorCt = 0;  /* initial value */
+    best        = 0;  /* initial value */
+    
+    for (imageIndex = 0; dirP->count > imageIndex; ++imageIndex) {
+        struct IconDirEntry * const dirEntryP = &dirP->entries[imageIndex];
+
+        uint32_t const pixelCt = dirEntryP->width * dirEntryP->height;
+
+        uint32_t colorCt;
+
+        /*  32-bit icons have 24 bit color information only.
+         
+            Since NT 5.1 (aka WinXP), it is allowed to place 8-bit
+            transparency information in the remaining bits (to check,
+            you have to read all these bits in the image!), so I prefer
+            32-bit images over 24-bit images (which violate the
+            spec. anyway).
+        */
+        if (dirEntryP->bits_per_pixel > 24)
+            colorCt = 1u << 25;
+        else
+            colorCt = 1u << dirEntryP->bits_per_pixel;
+
+        if (dirEntryP->color_count != 0 && colorCt > dirEntryP->color_count)
+            colorCt = dirEntryP->color_count;
+
+        if ((pixelCt > bestPixelCt)
+            || ((pixelCt == bestPixelCt) && (colorCt > bestColorCt))) {
+            /* This is a new best */
+            bestPixelCt = pixelCt;
+            bestColorCt = colorCt;
+            best        = imageIndex;
+        }
+    }
+    return best;
+}
+
+
+
+static void
+convertImage(struct File *         const icoP,
+             struct IconDirEntry * const dirEntryP,
+             FILE *                const ofP,
+             bool                  const needHeaderDump,
+             bool                  const wantAndMaskPlane) {
+
+    const unsigned char * image;  /* malloced */
+
+    image = readImage(icoP, dirEntryP);
+
+    if (MEMEQ(image, pngHeader, sizeof (pngHeader)))
+        convertPng(image, ofP, dirEntryP);
+    else
+        convertBmp(image, ofP, dirEntryP, needHeaderDump, wantAndMaskPlane);
+
+    free((void *)image);
+}
+
+
+
+int
+main (int argc, const char *argv []) {
+
+    struct File ico;
+    struct IconDir * dirP;
+    struct CmdlineInfo cmdline;
+
+    pm_proginit (&argc, argv);
+
+    parseCommandLine(argc, argv, &cmdline);
+
+    verbose = cmdline.verbose;
+
+    ico.name =
+        streq(cmdline.inputFileName, "-") ?  "<stdin>" : cmdline.inputFileName;
+    ico.pos   = 0;
+    ico.fileP = pm_openr(cmdline.inputFileName);
+
+    dirP = readIconDir(&ico, cmdline.headerdump);
+
+    if (cmdline.allimages) {
+        unsigned int i;
+        for (i = 0; i < dirP->count; ++i)
+            convertImage(&ico, &dirP->entries[i], stdout,
+                         cmdline.headerdump, cmdline.andmasks);
+    } else if (cmdline.imageSpec) {
+        unsigned int i;
+        bool found;
+        for (i = 0, found = false; i < dirP->count; ++i) {
+            if (dirP->entries[i].index == cmdline.image) {
+                found = true;
+                convertImage(&ico, &dirP->entries[i], stdout,
+                             cmdline.headerdump, cmdline.andmasks);
+            }
+        }
+        if (!found)
+            pm_error("no image index %u in.input", cmdline.image);
+    } else {
+        convertImage(&ico, &dirP->entries[bestImage(dirP)], stdout,
+                     cmdline.headerdump, cmdline.andmasks);
+    }
+    
+    freeIconDir(dirP);
+
+    if (ico.fileP != stdin)
+        pm_close(ico.fileP);
+
+    return 0;
+}
+
+
+
diff --git a/converter/other/xwdtopnm.c b/converter/other/xwdtopnm.c
index 2cf1d39b..d49a2b09 100644
--- a/converter/other/xwdtopnm.c
+++ b/converter/other/xwdtopnm.c
@@ -113,7 +113,7 @@ parseCommandLine(int argc, char ** argv,
     opt.short_allowed = FALSE;  /* We have no short (old-fashioned) options */
     opt.allowNegNum = FALSE;  /* We may have parms that are negative numbers */
 
-    optParseOptions3(&argc, argv, opt, sizeof(opt), 0);
+    pm_optParseOptions3(&argc, argv, opt, sizeof(opt), 0);
         /* Uses and sets argc, argv, and some of *cmdlineP and others. */
 
     if (argc - 1 == 0)
@@ -837,7 +837,7 @@ typedef struct {
 
            'nBitsLeft' tells how many bits are in the buffer now.  It's
            zero when nothing has ever been read from the file.  Only
-           the least signficant 'nBitsLeft' bits are meaningful.
+           the least significant 'nBitsLeft' bits are meaningful.
 
            The numeric value of the member is the number whose pure
            binary representation is the bit string in the buffer.
@@ -974,7 +974,7 @@ readItem(pixelReader * const rdrP) {
 
 static unsigned long const lsbmask[] = {
 /*----------------------------------------------------------------------------
-   lsbmask[i] is the mask you use to select the i least signficant bits
+   lsbmask[i] is the mask you use to select the i least significant bits
    of a bit string.
 -----------------------------------------------------------------------------*/
     0x00000000,
diff --git a/converter/other/yuy2topam.c b/converter/other/yuy2topam.c
new file mode 100644
index 00000000..40ab98b3
--- /dev/null
+++ b/converter/other/yuy2topam.c
@@ -0,0 +1,266 @@
+/* Convert an YUY2 image to a PAM image
+ *
+ * See
+ * http://msdn.microsoft.com/en-us/library/aa904813%28VS.80%29.aspx#yuvformats_2
+ * and http://www.digitalpreservation.gov/formats/fdd/fdd000364.shtml for
+ * details.
+ *
+ * By Michael Haardt 2014.
+ *
+ * Contributed to the public domain by its author.
+ *
+ * Recoded in Netpbm style by Bryan Henderson
+ */
+
+#include <stdio.h>
+#include <string.h>
+
+#include "pm_c_util.h"
+#include "mallocvar.h"
+#include "pm.h"
+#include "pam.h"
+#include "shhopt.h"
+
+
+
+struct CmdlineInfo {
+    const char * inputFileName;
+    unsigned int width;
+    unsigned int height;
+};
+
+
+
+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 widthSpec, heightSpec;
+    unsigned int option_def_index;
+
+    MALLOCARRAY_NOFAIL(option_def, 100);
+
+    option_def_index = 0;   /* incremented by OPTENT3 */
+    OPTENT3(0, "width",    OPT_UINT,
+            &cmdlineP->width,   &widthSpec,                             0);
+    OPTENT3(0, "height",   OPT_UINT,
+            &cmdlineP->height,  &heightSpec,                            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 (!widthSpec)
+        pm_error("You must specify the image width with -width");
+    if (cmdlineP->width == 0)
+        pm_error("-width cannot be zero");
+
+    if (cmdlineP->width % 2 != 0)
+        pm_error("-width %u is odd, but YUY2 images must have an even width.",
+                 cmdlineP->width);
+
+    if (!heightSpec)
+        pm_error("You must specify the image height with -height");
+    if (cmdlineP->height == 0)
+        pm_error("-height cannot be zero");
+
+    if (argc-1 < 1)
+        cmdlineP->inputFileName = "-";
+    else {
+        cmdlineP->inputFileName = argv[1];
+        
+        if (argc-1 > 1)
+            pm_error("Too many arguments (%u).  The only non-option argument "
+                     "is the input file name.", argc-1);
+    }
+}
+
+
+
+typedef struct {
+    int y0;
+    int y1;
+    int u;
+    int v;
+} Yuy2Pixel;
+
+
+
+static Yuy2Pixel
+readPixel(FILE * const ifP) {
+/*----------------------------------------------------------------------------
+   Read one pixel from the YUY2 input.  YUY2 represents a pixel in 4 bytes.
+-----------------------------------------------------------------------------*/
+    Yuy2Pixel retval;
+    unsigned char c;
+
+    pm_readcharu(ifP, &c); retval.y0 = c -  16;
+    pm_readcharu(ifP, &c); retval.u  = c - 128;
+    pm_readcharu(ifP, &c); retval.y1 = c -  16;
+    pm_readcharu(ifP, &c); retval.v  = c - 128;
+
+    return retval;
+}
+
+
+
+typedef struct {
+    int a1;
+    int a2;
+    int a3;
+    int a4;
+} UvCoeff;
+
+typedef struct {
+    int a0a;
+    int a0b;
+    UvCoeff uv;
+} Coeff;
+
+
+
+static Coeff
+coeffFromYuy2(Yuy2Pixel const yuy2) {
+
+    Coeff retval;
+
+    retval.a0a   = 298 * yuy2.y0;
+    retval.a0b   = 298 * yuy2.y1;
+    retval.uv.a1 = 409 * yuy2.v;
+    retval.uv.a2 = 100 * yuy2.u;
+    retval.uv.a3 = 208 * yuy2.v;
+    retval.uv.a4 = 516 * yuy2.u;
+
+    return retval;
+}
+
+
+
+typedef struct {
+    int r;
+    int g;
+    int b;
+} Rgb;
+
+
+
+static Rgb
+rgbFromCoeff(int     const a0,
+             UvCoeff const uv) {
+
+    Rgb retval;
+
+    retval.r = (a0 + uv.a1 + 128) >> 8;
+    retval.g = (a0 - uv.a2 - uv.a3 + 128) >> 8;
+    retval.b = (a0 + uv.a4 + 128) >> 8;
+
+    return retval;
+}
+
+
+
+static Rgb
+rgbFromCoeff0(Coeff const coeff) {
+
+    return rgbFromCoeff(coeff.a0a, coeff.uv);
+}
+
+
+
+static Rgb
+rgbFromCoeff1(Coeff const coeff) {
+
+    return rgbFromCoeff(coeff.a0b, coeff.uv);
+}
+
+
+
+static void
+rgbToTuple(Rgb   const rgb,
+           tuple const out) {
+
+    out[PAM_RED_PLANE] = MIN(255, MAX(0, rgb.r));
+    out[PAM_GRN_PLANE] = MIN(255, MAX(0, rgb.g));
+    out[PAM_BLU_PLANE] = MIN(255, MAX(0, rgb.b));
+}
+
+
+
+static void
+yuy2topam(const char * const fileName,
+          unsigned int const width,
+          unsigned int const height) {
+
+    FILE * ifP;
+    struct pam outpam;
+    tuple * tuplerow;
+    unsigned int row;
+
+    outpam.size             = sizeof(struct pam);
+    outpam.len              = PAM_STRUCT_SIZE(allocation_depth);
+    outpam.file             = stdout;
+    outpam.format           = PAM_FORMAT;
+    outpam.plainformat      = 0;
+    outpam.width            = width;
+    outpam.height           = height;
+    outpam.depth            = 3;
+    outpam.maxval           = 255;
+    outpam.bytes_per_sample = 1;
+    strcpy(outpam.tuple_type, PAM_PPM_TUPLETYPE);
+    outpam.allocation_depth = 3;
+
+    ifP = pm_openr(fileName);
+
+    pnm_writepaminit(&outpam);
+
+    tuplerow = pnm_allocpamrow(&outpam);
+
+    for (row = 0; row < outpam.height; ++row) {
+        unsigned int col;
+
+        for (col = 0; col < outpam.width; col += 2) {
+            Yuy2Pixel const yuy2 = readPixel(ifP);
+
+            Coeff const coeff = coeffFromYuy2(yuy2);
+
+            rgbToTuple(rgbFromCoeff0(coeff), tuplerow[col]);
+            rgbToTuple(rgbFromCoeff1(coeff), tuplerow[col+1]);
+        }
+        pnm_writepamrow(&outpam, tuplerow);
+    }
+    pnm_freepamrow(tuplerow);
+
+    pm_closer(ifP);
+}
+
+
+
+int
+main(int argc, const char *argv[]) {
+
+    struct CmdlineInfo cmdline;
+
+    pm_proginit(&argc, argv);
+
+    parseCommandLine(argc, argv, &cmdline);
+
+    yuy2topam(cmdline.inputFileName, cmdline.width, cmdline.height);
+
+    return 0;
+}