about summary refs log tree commit diff
path: root/converter
diff options
context:
space:
mode:
Diffstat (limited to 'converter')
-rw-r--r--converter/bmp.h4
-rw-r--r--converter/other/Makefile128
-rw-r--r--converter/other/cameratopam/Makefile14
-rw-r--r--converter/other/exif.c1197
-rw-r--r--converter/other/exif.h22
-rw-r--r--converter/other/fiasco/Makefile16
-rw-r--r--converter/other/fiasco/codec/ip.c4
-rw-r--r--converter/other/fiasco/codec/tiling.c2
-rw-r--r--converter/other/fiasco/codec/wfa.h2
-rw-r--r--converter/other/fiasco/display.c3
-rw-r--r--converter/other/fiasco/lib/image.c2
-rw-r--r--converter/other/fiasco/params.c2
-rw-r--r--converter/other/fiasco/pnmtofiasco.c2
-rw-r--r--converter/other/jbig/ANNOUNCE243
-rw-r--r--converter/other/jbig/Makefile32
-rw-r--r--converter/other/jbig/README.Netpbm12
-rw-r--r--converter/other/jbig/jbig.c2905
-rw-r--r--converter/other/jbig/jbig.doc721
-rw-r--r--converter/other/jbig/jbig.h267
-rw-r--r--converter/other/jbig/jbig_tab.c428
-rw-r--r--converter/other/jbig/jbigtopnm.c2
-rw-r--r--converter/other/jpeg2000/Makefile13
-rw-r--r--converter/other/jpeg2000/jpeg2ktopam.c3
-rw-r--r--converter/other/jpeg2000/libjasper/base/jas_image.c2
-rw-r--r--converter/other/jpeg2000/libjasper/include/jasper/jas_image.h38
-rw-r--r--converter/other/jpeg2000/libjasper/jp2/jp2_dec.c4
-rw-r--r--converter/other/jpeg2000/libjasper/jpc/jpc_cs.c2
-rw-r--r--converter/other/jpeg2000/libjasper/jpc/jpc_enc.c2
-rw-r--r--converter/other/jpeg2000/libjasper/jpc/jpc_qmfb.c8
-rw-r--r--converter/other/jpeg2000/pamtojpeg2k.c3
-rw-r--r--converter/other/jpegtopnm.c12
-rw-r--r--converter/other/pamtosvg/Makefile32
-rw-r--r--converter/other/pamtosvg/bitmap.h2
-rw-r--r--converter/other/pamtosvg/image-proc.c2
-rw-r--r--converter/other/pamtosvg/thin-image.c2
-rw-r--r--converter/other/pamtotiff.c452
-rw-r--r--converter/other/pnmtopalm/Makefile16
-rw-r--r--converter/other/pnmtopalm/gen_palm_colormap.c4
-rw-r--r--converter/other/pnmtosgi.c512
-rw-r--r--converter/other/sgi.h8
-rw-r--r--converter/other/sgitopnm.c86
-rw-r--r--converter/other/tifftopnm.c6
-rw-r--r--converter/pbm/cmuwmtopbm.c8
-rw-r--r--converter/pbm/pbmtoppa/Makefile17
-rw-r--r--converter/ppm/ilbm.h6
-rw-r--r--converter/ppm/ppmtompeg/Makefile62
-rw-r--r--converter/ppm/ppmtompeg/gethostname_win32.c2
47 files changed, 5819 insertions, 1493 deletions
diff --git a/converter/bmp.h b/converter/bmp.h
index 524bbf7e..6a883394 100644
--- a/converter/bmp.h
+++ b/converter/bmp.h
@@ -105,8 +105,8 @@ BMPCompTypeName(BMPCompType const compression) {
     case BMPCOMP_RLE4:      return "4 bit run-length coding";
     case BMPCOMP_RLE8:      return "8 bit run-length coding";
     case BMPCOMP_BITFIELDS: return "none (bitfields)";
-    case BMPCOMP_JPEG:      return "JPEG";
-    case BMPCOMP_PNG:       return "PNG";   
+    case BMPCOMP_JPEG:      return "JPEG (not supported)";
+    case BMPCOMP_PNG:       return "PNG (not supported)";   
     }
     return 0;  /* Default compiler warning */
 }
diff --git a/converter/other/Makefile b/converter/other/Makefile
index bbc40a3f..1a44017f 100644
--- a/converter/other/Makefile
+++ b/converter/other/Makefile
@@ -117,38 +117,46 @@ PORTBINARIES =  avstopam bmptopnm fitstopnm \
 		gemtopnm giftopnm hdifftopam infotopam \
 		pamtoavs pamtodjvurle pamtofits pamtogif \
 		pamtohdiff pamtohtmltbl pamtompfont pamtooctaveimg \
-		pamtopam pamtopdbimg pamtopfm pamtopnm pamtosrf pamtouil \
+		pamtopam pamtopfm pamtopnm pamtouil \
 		pamtowinicon pamtoxvmini \
-		pbmtopgm pdbimgtopam pfmtopam \
+		pbmtopgm pfmtopam \
 	        pgmtopbm pgmtoppm ppmtopgm pnmtoddif \
-		pnmtopclxl pnmtorast \
+		pnmtopclxl \
 		pnmtosgi pnmtosir pamtotga pnmtoxwd \
-		rasttopnm rlatopam sgitopnm sirtopnm srftopam sunicontopnm \
+		rlatopam sgitopnm sirtopnm sunicontopnm \
 		winicontopam xwdtopnm zeisstopnm
 
+BINARIES = \
+  $(PORTBINARIES) \
+  pamtopdbimg \
+  pamtosrf \
+  pdbimgtopam \
+  pnmtorast \
+  rasttopnm \
+  srftopam \
+
 ifneq ($(DONT_HAVE_PROCESS_MGMT),Y)
-  PORTBINARIES += pstopnm pnmtops
+  PORTBINARIES += pstopnm
+  BINARIES += pnmtops
 endif
 
 ifeq ($(HAVE_PNGLIB),Y)
-  PORTBINARIES += pnmtopng pngtopam pamrgbatopng
+  BINARIES += pnmtopng pngtopam pamrgbatopng
 endif
 ifneq ($(JPEGLIB),NONE)
-  PORTBINARIES += jpegtopnm pnmtojpeg
+  BINARIES += jpegtopnm pnmtojpeg
 endif
 ifneq ($(TIFF_PREREQ_MISSING),Y)
-  PORTBINARIES += tifftopnm pamtotiff pnmtotiffcmyk
+  BINARIES += tifftopnm pamtotiff pnmtotiffcmyk
 endif
 ifneq ($(URTLIB),NONE)
-  PORTBINARIES += rletopnm pnmtorle
+  BINARIES += rletopnm pnmtorle
 endif
 
 ifneq ($(XML2_LIBS),NONE)
-  PORTBINARIES += svgtopam
+  BINARIES += svgtopam
 endif 
 
-BINARIES = $(PORTBINARIES)
-
 MERGEBINARIES = $(BINARIES)
 
 EXTRA_OBJECTS = exif.o rast.o ipdb.o srf.o
@@ -181,14 +189,12 @@ else
   LIBOPTR =
 endif
 
-LIBOPTS_TIFF = $(shell $(LIBOPT) \
+LIBOPTS_TIFF = $(shell $(LIBOPT) $(NETPBMLIB) \
   $(LIBOPTR) $(TIFFLIB) $(TIFFLIB_EXTRALIBS))
 
-tifftopnm pamtotiff pnmtotiffcmyk: tiff.o
-tifftopnm pamtotiff pnmtotiffcmyk: ADDL_OBJECTS = tiff.o
-tifftopnm pamtotiff pnmtotiffcmyk: \
-  LDFLAGS_TARGET = \
- $(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)
 
 ifneq ($(shell $(TEST_PKGCONFIG_LIBPNG)),)
   # pkg-config libpng works on this system
@@ -203,44 +209,66 @@ else
   endif
 endif
 
-pngtopam: pngx.o
-pngtopam: ADDL_OBJECTS = pngx.o
-pngtopam: LDFLAGS_TARGET = $(PNGLIB_LIBOPTS)
-
-pnmtopng: pngx.o pngtxt.o
-pnmtopng: ADDL_OBJECTS = pngx.o pngtxt.o
-pnmtopng: LDFLAGS_TARGET = $(PNGLIB_LIBOPTS)
-
-pamrgbatopng: pngx.o
-pamrgbatopng: ADDL_OBJECTS = pngx.o
-pamrgbatopng: LDFLAGS_TARGET = $(PNGLIB_LIBOPTS)
-
-jpegtopnm: jpegdatasource.o exif.o
-jpegtopnm: ADDL_OBJECTS = jpegdatasource.o exif.o
-jpegtopnm: LDFLAGS_TARGET = $(shell $(LIBOPT) $(LIBOPTR) $(JPEGLIB))
-
-srftopam pamtosrf: srf.o
-srftopam pamtosrf: ADDL_OBJECTS = srf.o
-
-pnmtojpeg: LDFLAGS_TARGET = $(shell $(LIBOPT) $(LIBOPTR) $(JPEGLIB))
-
-svgtopam: LDFLAGS_TARGET = $(XML2_LIBS)
+pngtopam: %: %.o pngx.o $(NETPBMLIB) $(LIBOPT)
+	$(LD) -o $@ $@.o pngx.o \
+	  $(shell $(LIBOPT) $(NETPBMLIB)) \
+	  $(PNGLIB_LIBOPTS) $(MATHLIB) $(LDFLAGS) $(LDLIBS) $(RPATH) $(LADD)
+
+pnmtopng: %: %.o pngx.o pngtxt.o $(NETPBMLIB) $(LIBOPT)
+	$(LD) -o $@ $@.o pngx.o pngtxt.o \
+	  $(shell $(LIBOPT) $(NETPBMLIB)) \
+	  $(PNGLIB_LIBOPTS) $(MATHLIB) $(LDFLAGS) $(LDLIBS) $(RPATH) $(LADD)
+
+pamrgbatopng: %: %.o pngx.o $(NETPBMLIB) $(LIBOPT)
+	$(LD) -o $@ $@.o pngx.o \
+	  $(shell $(LIBOPT) $(NETPBMLIB)) $(PNGLIB_LIBOPTS) \
+	  $(MATHLIB) $(LDFLAGS) $(LDLIBS) $(RPATH) $(LADD)
+
+jpegtopnm: %: %.o jpegdatasource.o exif.o $(NETPBMLIB) $(LIBOPT)
+	$(LD) -o $@ $< jpegdatasource.o exif.o \
+	  $(shell $(LIBOPT) $(NETPBMLIB) $(LIBOPTR) $(JPEGLIB)) \
+	  $(MATHLIB) $(LDFLAGS) $(LDLIBS) $(RPATH) $(LADD) 
+
+pnmtojpeg: %: %.o $(NETPBMLIB) $(LIBOPT)
+	$(LD) -o $@ $@.o \
+	  $(shell $(LIBOPT) $(NETPBMLIB) $(LIBOPTR) $(JPEGLIB)) \
+	  $(MATHLIB) $(LDFLAGS) $(LDLIBS) $(RPATH) $(LADD)
+
+srftopam pamtosrf: %: %.o srf.o $(NETPBMLIB) $(LIBOPT)
+	$(LD) -o $@ $@.o srf.o \
+	  $(shell $(LIBOPT) $(NETPBMLIB)) \
+	  $(MATHLIB) $(LDFLAGS) $(LDLIBS) $(RPATH) $(LADD)
+
+svgtopam: %: %.o $(NETPBMLIB) $(LIBOPT)
+	$(LD) -o $@ $@.o \
+	  $(shell $(LIBOPT) $(NETPBMLIB) $(LIBOPTR)) \
+	  $(XML2_LIBS) $(MATHLIB) $(LDFLAGS) $(LDLIBS) $(RPATH) $(LADD)
 
 # If URTLIB is BUNDLED_URTLIB, then we're responsible for building it, which
 # means it needs to be a dependency:
 ifeq ($(URTLIB), $(BUNDLED_URTLIB))
-rletopnm pnmtorle: $(URTLIB)
+  URTLIBDEP = $(URTLIB)
 endif
 
-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
-
-pdbimgtopam pamtopdbimg: ipdb.o
-pdbimgtopam pamtopdbimg: ADDL_OBJECTS = ipdb.o
+rletopnm pnmtorle: %: %.o $(NETPBMLIB) $(URTLIBDEP) $(LIBOPT)
+	$(LD) -o $@ $@.o \
+	  $(shell $(LIBOPT) $(URTLIB) $(NETPBMLIB)) \
+	  $(MATHLIB) $(LDFLAGS) $(LDLIBS) $(RPATH) $(LADD)
+
+pnmtops: %: %.o $(NETPBMLIB) $(LIBOPT)
+	$(LD) -o $@ $@.o \
+	  $(shell $(LIBOPT) $(NETPBMLIB) $(PNMTOPS_ZLIB_OPT)) \
+	  $(MATHLIB) $(LDFLAGS) $(LDLIBS) $(RPATH) $(LADD)
+
+pnmtorast rasttopnm: %: %.o rast.o $(NETPBMLIB) $(LIBOPT)
+	$(LD) -o $@ $@.o rast.o \
+	  $(shell $(LIBOPT) $(NETPBMLIB)) \
+	  $(MATHLIB) $(LDFLAGS) $(LDLIBS) $(RPATH) $(LADD)
+
+pdbimgtopam pamtopdbimg: %: %.o ipdb.o $(NETPBMLIB) $(LIBOPT)
+	$(LD) -o $@ $@.o ipdb.o \
+	  $(shell $(LIBOPT) $(NETPBMLIB)) \
+	  $(MATHLIB) $(LDFLAGS) $(LDLIBS) $(RPATH) $(LADD)
 
 bmptopnm.o bmptopnm.o2: bmp.h
 
diff --git a/converter/other/cameratopam/Makefile b/converter/other/cameratopam/Makefile
index 11ca4e1d..4470d472 100644
--- a/converter/other/cameratopam/Makefile
+++ b/converter/other/cameratopam/Makefile
@@ -19,20 +19,22 @@ include $(BUILDDIR)/config.mk
 .PHONY: all
 all: cameratopam
 
-ADDL_OBJECTS = util.o identify.o camera.o foveon.o decode.o \
+OBJECTS = util.o identify.o cameratopam.o camera.o foveon.o decode.o \
 	canon.o ljpeg.o dng.o
 
-OBJECTS = cameratopam.o $(ADDL_OBJECTS)
-
 camera.o camera.o2: CFLAGS_TARGET = $(HAVE_JPEG_DEFINE)
 
 MERGE_OBJECTS =
 
-PORTBINARIES = cameratopam
-BINARIES = $(PORTBINARIES)
+BINARIES = cameratopam
 MERGEBINARIES = 
 SCRIPTS = 
 
 include $(SRCDIR)/common.mk
 
-cameratopam: $(ADDL_OBJECTS)
+cameratopam: $(OBJECTS) $(NETPBMLIB) $(LIBOPT)
+	$(LD) -o $@ \
+          $(OBJECTS) $(shell $(LIBOPT) $(NETPBMLIB) $(LIBOPTR)) \
+	  $(MATHLIB) $(LDFLAGS) $(LDLIBS) \
+	  $(RPATH) $(LADD)
+
diff --git a/converter/other/exif.c b/converter/other/exif.c
index 1bfe4b2b..87d89bd7 100644
--- a/converter/other/exif.c
+++ b/converter/other/exif.c
@@ -46,21 +46,22 @@
 
 #include "exif.h"
 
-static const unsigned char * DirWithThumbnailPtrs;
+static unsigned char * LastExifRefd;
+static 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;
-
+}TagTable_t;
 
 
 /* Describes format descriptor */
-static int const bytesPerFormat[] = {0,1,1,2,4,8,1,1,2,4,8,4,8};
+static int BytesPerFormat[] = {0,1,1,2,4,8,1,1,2,4,8,4,8};
 #define NUM_FORMATS 12
 
 #define FMT_BYTE       1 
@@ -119,7 +120,7 @@ static int const 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 const tagTable[] = {
+static TagTable_t const TagTable[] = {
   {   0x100,   "ImageWidth"},
   {   0x101,   "ImageLength"},
   {   0x102,   "BitsPerSample"},
@@ -207,583 +208,498 @@ static TagTable 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
 --------------------------------------------------------------------------*/
-    if (byteOrder == MOTOROLA){
-        return (((const unsigned char *)data)[0] << 8) | 
-            ((const unsigned char *)data)[1];
+static int Get16u(void * Short)
+{
+    if (MotorolaOrder){
+        return (((unsigned char *)Short)[0] << 8) | 
+            ((unsigned char *)Short)[1];
     }else{
-        return (((const unsigned char *)data)[1] << 8) | 
-            ((const unsigned char *)data)[0];
+        return (((unsigned char *)Short)[1] << 8) | 
+            ((unsigned char *)Short)[0];
     }
 }
 
-
-
-static int32_t
-get32s(const void * const data,
-       ByteOrder    const byteOrder) {
 /*--------------------------------------------------------------------------
    Convert a 32 bit signed value from file's native byte order
 --------------------------------------------------------------------------*/
-    if (byteOrder == MOTOROLA){
+static int Get32s(void * Long)
+{
+    if (MotorolaOrder){
         return  
-            (((const char *)data)[0] << 24) |
-            (((const unsigned char *)data)[1] << 16) |
-            (((const unsigned char *)data)[2] << 8 ) | 
-            (((const unsigned char *)data)[3] << 0 );
-    } else {
+            ((( char *)Long)[0] << 24) | (((unsigned char *)Long)[1] << 16) |
+            (((unsigned char *)Long)[2] << 8 ) | 
+            (((unsigned char *)Long)[3] << 0 );
+    }else{
         return  
-            (((const char *)data)[3] << 24) |
-            (((const unsigned char *)data)[2] << 16) |
-            (((const unsigned char *)data)[1] << 8 ) | 
-            (((const unsigned char *)data)[0] << 0 );
+            ((( char *)Long)[3] << 24) | (((unsigned char *)Long)[2] << 16) |
+            (((unsigned char *)Long)[1] << 8 ) | 
+            (((unsigned char *)Long)[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
 --------------------------------------------------------------------------*/
-    return (uint32_t)get32s(data, byteOrder) & 0xffffffff;
+static unsigned Get32u(void * Long)
+{
+    return (unsigned)Get32s(Long) & 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:
-        fprintf(fileP, "%02x\n", *(unsigned char *)ValuePtr);
-        break;
-    case FMT_USHORT:
-        fprintf(fileP, "%d\n",get16u(ValuePtr, byteOrder));
-        break;
+    case FMT_BYTE:      printf("%02x\n",*(unsigned char *)ValuePtr); break;
+    case FMT_USHORT:    fprintf(file, "%d\n",Get16u(ValuePtr));    break;
     case FMT_ULONG:     
-    case FMT_SLONG:
-        fprintf(fileP, "%d\n",get32s(ValuePtr, byteOrder));
-        break;
+    case FMT_SLONG:     fprintf(file, "%d\n",Get32s(ValuePtr));    break;
     case FMT_SSHORT:    
-        fprintf(fileP, "%hd\n",(signed short)get16u(ValuePtr, byteOrder));
-        break;
+        fprintf(file, "%hd\n",(signed short)Get16u(ValuePtr));     break;
     case FMT_URATIONAL:
     case FMT_SRATIONAL: 
-        fprintf(fileP, "%d/%d\n",get32s(ValuePtr, byteOrder),
-                get32s(4+(char *)ValuePtr, byteOrder));
+        fprintf(file, "%d/%d\n",Get32s(ValuePtr), Get32s(4+(char *)ValuePtr));
         break;
     case FMT_SINGLE:    
-        fprintf(fileP, "%f\n",(double)*(float *)ValuePtr);
-        break;
-    case FMT_DOUBLE:
-        fprintf(fileP, "%f\n",*(double *)ValuePtr);
-        break;
+        fprintf(file, "%f\n",(double)*(float *)ValuePtr);          break;
+    case FMT_DOUBLE:    fprintf(file, "%f\n",*(double *)ValuePtr); break;
     default: 
-        fprintf(fileP, "Unknown format %d:", Format);
+        fprintf(file, "Unknown format %d:", Format);
         {
-            unsigned int a;
-            for (a = 0; a < ByteCount && a < 16; ++a)
+            int a;
+            for (a=0; a < ByteCount && a < 16; ++a)
                 printf("%02x", ((unsigned char *)ValuePtr)[a]);
         }
-        fprintf(fileP, "\n");
+        fprintf(file, "\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, 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;
-    }
-    return Value;
-}
-
-
-
-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.
-                */
-                if (!noPrint){
-                    fprintf(stderr, "?");
-                    noPrint = true;
+        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;
             }
-        }
-        fprintf(stderr, "\"\n");
-    } break;
 
-    default:
-        /* Handle arrays of numbers later (will there ever be?)*/
-        printFormatNumber(stderr, valuePtr, format, byteCount, byteOrder);
+        case FMT_SSHORT:    Value = (signed short)Get16u(ValuePtr);  break;
+        case FMT_SLONG:     Value = Get32s(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;
 }
 
-
-
-/* Forward declaration for recursion */
-
+/*--------------------------------------------------------------------------
+   Process one of the nested EXIF directories.
+--------------------------------------------------------------------------*/
 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;
+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))
 
-    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;
+    {
+        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.
+                */
+                pm_message("Illegal directory entry size");
+                return;
+            }
         }
-        valuePtr = &exifData[offsetVal];
-    } else {
-        /* 4 bytes or less and value is in the dir entry itself */
-        valuePtr = &dirEntry[8];
+        if (DirEnd > LastExifRefd) LastExifRefd = DirEnd;
     }
 
-    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;
+    if (ShowTags){
+        pm_message("Directory with %d entries",NumDirEntries);
     }
 
-    if (wantTagTrace)
-        traceTag(tag, format, valuePtr, byteCount, byteOrder);
-
-    *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);
-        }
-        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;
+    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);
 
-    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;
+        Tag = Get16u(DirEntry);
+        Format = Get16u(DirEntry+2);
+        Components = Get32u(DirEntry+4);
 
-    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)));
+        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;
         }
-        break;
-
-    case TAG_FLASH:
-        if ((int)convertAnyFormat(valuePtr, format, byteOrder) & 0x7){
-            imageInfoP->FlashUsed = TRUE;
+        
+        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;
         }else{
-            imageInfoP->FlashUsed = FALSE;
-        }
-        break;
-
-    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;
+            /* 4 bytes or less and value is in the dir entry itself */
+            ValuePtr = DirEntry+8;
         }
-        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;
-
-    case TAG_FOCALPLANEXRES:
-        HaveXRes = TRUE;
-        FocalplaneXRes = convertAnyFormat(valuePtr, format, byteOrder);
-        break;
 
-    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.  
+        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.
             */
-            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*/
+            *LastExifRefdP = ValuePtr+ByteCount;
         }
-        break;
-
-        /* Remaining cases contributed by: Volker C. Schoech
-           (schoech@gmx.de)
-        */
-
-    case TAG_EXPOSURE_BIAS:
-        imageInfoP->ExposureBias = 
-            (float) convertAnyFormat(valuePtr, format, byteOrder);
-        break;
 
-    case TAG_WHITEBALANCE:
-        imageInfoP->Whitebalance = 
-            (int)convertAnyFormat(valuePtr, format, byteOrder);
-        break;
-
-    case TAG_METERING_MODE:
-        imageInfoP->MeteringMode = 
-            (int)convertAnyFormat(valuePtr, format, byteOrder);
-        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_EXPOSURE_PROGRAM:
-        imageInfoP->ExposureProgram = 
-            (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_ISO_EQUIVALENT:
-        imageInfoP->ISOequivalent = 
-            (int)convertAnyFormat(valuePtr, format, byteOrder);
-        if ( imageInfoP->ISOequivalent < 50 ) 
-            imageInfoP->ISOequivalent *= 200;
-        break;
+                default:
+                    /* Handle arrays of numbers later (will there ever be?)*/
+                    PrintFormatNumber(stderr, ValuePtr, Format, ByteCount);
+            }
+        }
 
-    case TAG_COMPRESSION_LEVEL:
-        imageInfoP->CompressionLevel = 
-            (int)convertAnyFormat(valuePtr, format, byteOrder);
-        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;
+                }
 
-    case TAG_THUMBNAIL_OFFSET:
-        *thumbnailOffsetP = (unsigned int)
-            convertAnyFormat(valuePtr, format, byteOrder);
-        break;
+                /* 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_THUMBNAIL_LENGTH:
-        *thumbnailSizeP = (unsigned int)
-            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_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;
-    }
-}
+                ImageInfoP->FocalLength = 
+                    (float)ConvertAnyFormat(ValuePtr, Format);
+                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_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;
 
-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;
+            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;
 
-    #define DIR_ENTRY_ADDR(Start, Entry) (Start+2+12*(Entry))
+                    case 3: FocalplaneUnits = 10;   break;  /* 1 centimeter*/
+                    case 4: FocalplaneUnits = 1;    break;  /* 1 millimeter*/
+                    case 5: FocalplaneUnits = .001; break;  /* 1 micrometer*/
+                }
+                break;
 
-    {
-        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.
+                /* Remaining cases contributed by: Volker C. Schoech
+                   (schoech@gmx.de)
                 */
-            }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 */
+            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;
+                }
+        }
 
-    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,
@@ -791,30 +707,28 @@ processExifDir(const 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, byteOrder);
-            if (subdirOffset){
-                const 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);
+            if (SubdirOffset){
+                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 (wantTagTrace) 
+                        if (ShowTags) 
                             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, byteOrder, wantTagTrace,
-                                       lastExifRefdP);
+                    if (SubdirOffset <= ExifLength)
+                        ProcessExifDir(ExifData, ExifLength, SubdirOffset,
+                                       ImageInfoP, ShowTags, LastExifRefdP);
                 }
             }
         }else{
@@ -822,14 +736,14 @@ processExifDir(const 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 (wantTagTrace){
-                fprintf(stderr, "Thumbnail size: %u bytes\n", thumbnailSize);
+            if (ShowTags){
+                fprintf(stderr, "Thumbnail size: %d bytes\n",ThumbnailSize);
             }
         }
     }
@@ -838,46 +752,46 @@ processExifDir(const unsigned char *  const exifData,
 
 
 void 
-exif_parse(const unsigned char * const exifData,
-           unsigned int          const length,
-           exif_ImageInfo *      const imageInfoP, 
-           bool                  const wantTagTrace,
-           const char **         const errorP) {
+process_EXIF(unsigned char * const ExifData,
+             unsigned int    const length,
+             ImageInfo_t *   const ImageInfoP, 
+             int             const ShowTags,
+             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;
-    const unsigned char * lastExifRefd;
+    unsigned char * LastExifRefd;
 
     *errorP = NULL;  /* initial assumption */
 
-    if (wantTagTrace)
+    if (ShowTags){
         fprintf(stderr, "Exif header %d bytes long\n",length);
+    }
 
-    if (MEMEQ(exifData + 0, "II" , 2)) {
-        if (wantTagTrace) 
+    if (memcmp(ExifData+0,"II",2) == 0) {
+        if (ShowTags) 
             fprintf(stderr, "Exif header in Intel order\n");
-        byteOrder = NORMAL;
+        MotorolaOrder = 0;
     } else {
-        if (MEMEQ(exifData + 0, "MM", 2)) {
-            if (wantTagTrace) 
+        if (memcmp(ExifData+0, "MM", 2) == 0) {
+            if (ShowTags) 
                 fprintf(stderr, "Exif header in Motorola order\n");
-            byteOrder = MOTOROLA;
+            MotorolaOrder = 1;
         } else {
             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]);
+                        ExifData[0], ExifData[1], ExifData[0], ExifData[1]);
         }
     }
     if (!*errorP) {
-        unsigned short const start = get16u(exifData + 2, byteOrder);
+        unsigned short const start = Get16u(ExifData + 2);
         /* Check the next value for correctness. */
         if (start != 0x002a){
             pm_asprintf(errorP, "Invalid Exif header start.  "
@@ -887,7 +801,7 @@ exif_parse(const unsigned char * const exifData,
         }
     }
     if (!*errorP) {
-        FirstOffset = get32u(exifData + 4, byteOrder);
+        FirstOffset = Get32u(ExifData + 4);
         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
@@ -896,54 +810,51 @@ exif_parse(const 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, byteOrder, wantTagTrace, &lastExifRefd);
+        ProcessExifDir(ExifData, length, FirstOffset, 
+                       ImageInfoP, ShowTags, &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 (wantTagTrace){
+        if (ShowTags){
             fprintf(stderr, 
                     "Non-settings part of Exif header: %lu bytes\n",
-                    (unsigned long)(exifData + length - lastExifRefd));
+                    (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.
 --------------------------------------------------------------------------*/
-    if (imageInfoP->CameraMake[0]) {
-        fprintf(fileP, "Camera make  : %s\n", imageInfoP->CameraMake);
-        fprintf(fileP, "Camera model : %s\n", imageInfoP->CameraModel);
+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->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) {
+    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){
 
         /* Only print orientation if one was supplied, and if its not
            1 (normal orientation)
@@ -980,144 +891,154 @@ exif_showImageInfo(const exif_ImageInfo * const imageInfoP,
             "rotate 270",       /* rotate 270 to right it. */
         };
 
-        fprintf(fileP, "Orientation  : %s\n", 
-                OrientTab[imageInfoP->Orientation]);
+        fprintf(stderr, "Orientation  : %s\n", 
+                OrientTab[ImageInfoP->Orientation]);
     }
 
-    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)",
+    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)",
                     (int)
-                    (imageInfoP->FocalLength/imageInfoP->CCDWidth*36 + 0.5));
+                    (ImageInfoP->FocalLength/ImageInfoP->CCDWidth*36 + 0.5));
         }
-        fprintf(fileP, "\n");
+        fprintf(stderr, "\n");
     }
 
-    if (imageInfoP->HaveCCDWidth)
-        fprintf(fileP, "CCD width    : %2.4fmm\n",
-                (double)imageInfoP->CCDWidth);
+    if (ImageInfoP->HaveCCDWidth){
+        fprintf(stderr, "CCD width    : %2.4fmm\n",
+                (double)ImageInfoP->CCDWidth);
+    }
 
-    if (imageInfoP->ExposureTime) {
-        if (imageInfoP->ExposureTime < 0.010){
-            fprintf(fileP, 
+    if (ImageInfoP->ExposureTime){ 
+        if (ImageInfoP->ExposureTime < 0.010){
+            fprintf(stderr, 
                     "Exposure time: %6.4f s ",
-                    (double)imageInfoP->ExposureTime);
+                    (double)ImageInfoP->ExposureTime);
         }else{
-            fprintf(fileP, 
+            fprintf(stderr, 
                     "Exposure time: %5.3f s ",
-                    (double)imageInfoP->ExposureTime);
+                    (double)ImageInfoP->ExposureTime);
         }
-        if (imageInfoP->ExposureTime <= 0.5){
-            fprintf(fileP, " (1/%d)",(int)(0.5 + 1/imageInfoP->ExposureTime));
+        if (ImageInfoP->ExposureTime <= 0.5){
+            fprintf(stderr, " (1/%d)",(int)(0.5 + 1/ImageInfoP->ExposureTime));
         }
-        fprintf(fileP, "\n");
+        fprintf(stderr, "\n");
     }
-    if (imageInfoP->ApertureFNumber){
-        fprintf(fileP, "Aperture     : f/%3.1f\n",
-                (double)imageInfoP->ApertureFNumber);
+    if (ImageInfoP->ApertureFNumber){
+        fprintf(stderr, "Aperture     : f/%3.1f\n",
+                (double)ImageInfoP->ApertureFNumber);
     }
-    if (imageInfoP->Distance){
-        if (imageInfoP->Distance < 0){
-            fprintf(fileP, "Focus dist.  : Infinite\n");
+    if (ImageInfoP->Distance){
+        if (ImageInfoP->Distance < 0){
+            fprintf(stderr, "Focus dist.  : Infinite\n");
         }else{
-            fprintf(fileP, "Focus dist.  :%5.2fm\n",
-                    (double)imageInfoP->Distance);
+            fprintf(stderr, "Focus dist.  :%5.2fm\n",
+                    (double)ImageInfoP->Distance);
         }
     }
 
-    if (imageInfoP->ISOequivalent){ /* 05-jan-2001 vcs */
-        fprintf(fileP, "ISO equiv.   : %2d\n",(int)imageInfoP->ISOequivalent);
+
+
+
+
+    if (ImageInfoP->ISOequivalent){ /* 05-jan-2001 vcs */
+        fprintf(stderr, "ISO equiv.   : %2d\n",(int)ImageInfoP->ISOequivalent);
     }
-    if (imageInfoP->ExposureBias){ /* 05-jan-2001 vcs */
-        fprintf(fileP, "Exposure bias:%4.2f\n",
-                (double)imageInfoP->ExposureBias);
+    if (ImageInfoP->ExposureBias){ /* 05-jan-2001 vcs */
+        fprintf(stderr, "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(fileP, "Whitebalance : sunny\n");
+            fprintf(stderr, "Whitebalance : sunny\n");
             break;
         case 2:
-            fprintf(fileP, "Whitebalance : fluorescent\n");
+            fprintf(stderr, "Whitebalance : fluorescent\n");
             break;
         case 3:
-            fprintf(fileP, "Whitebalance : incandescent\n");
+            fprintf(stderr, "Whitebalance : incandescent\n");
             break;
         default:
-            fprintf(fileP, "Whitebalance : cloudy\n");
+            fprintf(stderr, "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(fileP, "Metering Mode: center weight\n");
+            fprintf(stderr, "Metering Mode: center weight\n");
             break;
         case 3:
-            fprintf(fileP, "Metering Mode: spot\n");
+            fprintf(stderr, "Metering Mode: spot\n");
             break;
         case 5:
-            fprintf(fileP, "Metering Mode: matrix\n");
+            fprintf(stderr, "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(fileP, "Exposure     : program (auto)\n");
+            fprintf(stderr, "Exposure     : program (auto)\n");
             break;
         case 3:
-            fprintf(fileP, "Exposure     : aperture priority (semi-auto)\n");
+            fprintf(stderr, "Exposure     : aperture priority (semi-auto)\n");
             break;
         case 4:
-            fprintf(fileP, "Exposure     : shutter priority (semi-auto)\n");
+            fprintf(stderr, "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(fileP, "Jpeg Quality  : basic\n");
+            fprintf(stderr, "Jpeg Quality  : basic\n");
             break;
         case 2:
-            fprintf(fileP, "Jpeg Quality  : normal\n");
+            fprintf(stderr, "Jpeg Quality  : normal\n");
             break;
         case 4:
-            fprintf(fileP, "Jpeg Quality  : fine\n");
+            fprintf(stderr, "Jpeg Quality  : fine\n");
             break;
        }
     }
 
-    /* Print the comment. Print 'Comment:' for each new line of comment. */
-    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];
+    /* 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 (c == '\n'){
                 /* Do not start a new line if the string ends with a cr */
-                if (imageInfoP->Comments[a+1] != '\0')
-                    fprintf(fileP, "\nComment      : ");
-                else
-                    fprintf(fileP, "\n");
-            } else
-                putc(c, fileP);
+                if (ImageInfoP->Comments[a+1] != '\0'){
+                    fprintf(stderr, "\nComment      : ");
+                }else{
+                    fprintf(stderr, "\n");
+                }
+            }else{
+                putc(c, stderr);
+            }
         }
-        fprintf(fileP, "\n");
+        fprintf(stderr, "\n");
     }
 
-    fprintf(fileP, "\n");
+    fprintf(stderr, "\n");
 }
 
 
+
+
diff --git a/converter/other/exif.h b/converter/other/exif.h
index 57eb745b..490e08ed 100644
--- a/converter/other/exif.h
+++ b/converter/other/exif.h
@@ -1,9 +1,6 @@
 #ifndef EXIF_H_INCLUDED
 #define EXIF_H_INCLUDED
 
-#include <stdio.h>
-#include "netpbm/pm_c_util.h"
-
 #define MAX_COMMENT 2000
 
 #if MSVCRT
@@ -38,24 +35,23 @@ typedef struct {
     int   CompressionLevel;
     char  Comments[MAX_COMMENT];
 
-    const unsigned char * ThumbnailPointer;  /* Pointer at the thumbnail */
+    unsigned char * ThumbnailPointer;  /* Pointer at the thumbnail */
     unsigned ThumbnailSize;     /* Size of thumbnail. */
 
-    const char * DatePointer;
-} exif_ImageInfo;
+    char * DatePointer;
+}ImageInfo_t;
 
 
 /* Prototypes for exif.c functions. */
 
 void 
-exif_parse(const unsigned char * const exifSection, 
-           unsigned int          const length,
-           exif_ImageInfo *      const imageInfoP, 
-           bool                  const wantTagTrace,
-           const char **         const errorP);
+process_EXIF(unsigned char * const ExifSection, 
+             unsigned int    const length,
+             ImageInfo_t *   const ImageInfoP, 
+             int             const ShowTags,
+             const char **   const errorP);
 
 void 
-exif_showImageInfo(const exif_ImageInfo * const imageInfoP,
-                   FILE *                 const fileP);
+ShowImageInfo(ImageInfo_t * const ImageInfoP);
 
 #endif
diff --git a/converter/other/fiasco/Makefile b/converter/other/fiasco/Makefile
index 392e843c..16221d77 100644
--- a/converter/other/fiasco/Makefile
+++ b/converter/other/fiasco/Makefile
@@ -11,9 +11,8 @@ COMP_INCLUDES = \
 	-I$(SRCDIR)/$(SUBDIR)/codec -I$(SRCDIR)/$(SUBDIR)/input \
 	-I$(SRCDIR)/$(SUBDIR)/output -I$(SRCDIR)/$(SUBDIR)/lib \
 
-PORTBINARIES = pnmtofiasco fiascotopnm
+BINARIES = pnmtofiasco fiascotopnm
 
-BINARIES = $(PORTBINARIES)
 MERGEBINARIES = $(BINARIES)
 
 SCRIPTS =
@@ -25,18 +24,21 @@ FIASCOLIBS = codec/libfiasco_codec.a \
 	     output/libfiasco_output.a \
 	     lib/libfiasco_lib.a 
 
-ADDL_OBJECTS = binerror.o getopt.o getopt1.o params.o
+COMMON_OBJECTS = binerror.o getopt.o getopt1.o params.o
 
-OBJECTS = $(BINARIES:%=%.o) $(ADDL_OBJECTS)
+OBJECTS = $(BINARIES:%=%.o) $(COMMON_OBJECTS)
 
-MERGE_OBJECTS = $(BINARIES:%=%.o2) $(ADDL_OBJECTS) $(FIASCOLIBS)
+MERGE_OBJECTS = $(BINARIES:%=%.o2) $(COMMON_OBJECTS)  $(FIASCOLIBS)
 
 SUBDIRS = codec input output lib
 
 include $(SRCDIR)/common.mk
 
-$(BINARIES):%:%.o $(ADDL_OBJECTS) $(FIASCOLIBS)
-$(BINARIES): LDFLAGS_TARGET = $(shell $(LIBOPT) $(FIASCOLIBS))
+$(BINARIES):%:%.o $(COMMON_OBJECTS) $(FIASCOLIBS) $(NETPBMLIB) \
+   $(LIBOPT)
+	$(LD) -o $@ $< $(COMMON_OBJECTS) \
+	$(shell $(LIBOPT) $(FIASCOLIBS) $(NETPBMLIB)) $(MATHLIB) \
+	$(LDFLAGS) $(LDLIBS) $(RPATH) $(LADD)
 
 codec/libfiasco_codec.a: $(BUILDDIR)/$(SUBDIR)/codec FORCE
 	$(MAKE) -C codec -f $(SRCDIR)/$(SUBDIR)/codec/Makefile \
diff --git a/converter/other/fiasco/codec/ip.c b/converter/other/fiasco/codec/ip.c
index ade0d916..caa97baf 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 ("We cannot interpret a Level %d image.", level);
+      error ("Level %d not supported.", 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 ("We cannot interpret and image with Level %d.", level);
+      error ("Level %d not supported.", 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/tiling.c b/converter/other/fiasco/codec/tiling.c
index 21e4428a..89fe3111 100644
--- a/converter/other/fiasco/codec/tiling.c
+++ b/converter/other/fiasco/codec/tiling.c
@@ -224,7 +224,7 @@ perform_tiling (const image_t *image, tiling_t *tiling)
       }
       else
       {
-	 warning ("We do not know the tiling method.\n"
+	 warning ("Unsupported image tiling method.\n"
 		  "Skipping image tiling step.");
 	 tiling->exponent = 0;
       }
diff --git a/converter/other/fiasco/codec/wfa.h b/converter/other/fiasco/codec/wfa.h
index 9253affd..0b96ba8c 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 possible anymore */
+#define MAXLABELS 2			/* only bintree supported anymore */
 #define MAXLEVEL  22 
 
 #define FIASCO_BINFILE_RELEASE   2
diff --git a/converter/other/fiasco/display.c b/converter/other/fiasco/display.c
index cf160329..368fd3c9 100644
--- a/converter/other/fiasco/display.c
+++ b/converter/other/fiasco/display.c
@@ -307,8 +307,7 @@ alloc_ximage (x11_info_t *xinfo, unsigned width, unsigned height)
       shmem_flag = 0;
       if (fiasco_get_verbosity ())
 	 fprintf (stderr,
-              "Shared memory does not work on this system\n"
-              "Reverting to normal Xlib.\n");
+		  "Shared memory not supported\nReverting to normal Xlib.\n");
    }
 
    if (shmem_flag)
diff --git a/converter/other/fiasco/lib/image.c b/converter/other/fiasco/lib/image.c
index fa3b2db5..56275f2e 100644
--- a/converter/other/fiasco/lib/image.c
+++ b/converter/other/fiasco/lib/image.c
@@ -449,7 +449,7 @@ write_image (const char *image_name, const image_t *image)
    
    if (image->format == FORMAT_4_2_0)
    {
-      warning ("We cannot write images in 4:2:0 format.");
+      warning ("Writing of images in 4:2:0 format not supported.");
       return;
    }
    
diff --git a/converter/other/fiasco/params.c b/converter/other/fiasco/params.c
index afacbada..a4d843a8 100644
--- a/converter/other/fiasco/params.c
+++ b/converter/other/fiasco/params.c
@@ -656,7 +656,7 @@ usage (const param_t *params, const char *progname, const char *synopsis,
     fprintf (stderr, "Usage: %s [OPTION]...%s\n", progname,
              non_opt_string ? non_opt_string : " ");
     if (synopsis != NULL)
-        fprintf (stderr, "%s", synopsis);
+        fprintf (stderr, synopsis);
     fprintf (stderr, "\n\n");
     fprintf (stderr, "Mandatory or optional arguments to long options "
              "are mandatory or optional\nfor short options too. "
diff --git a/converter/other/fiasco/pnmtofiasco.c b/converter/other/fiasco/pnmtofiasco.c
index eebd09a9..d78ff6b1 100644
--- a/converter/other/fiasco/pnmtofiasco.c
+++ b/converter/other/fiasco/pnmtofiasco.c
@@ -170,7 +170,7 @@ main (int argc, char **argv)
       return 0;
    else
    {
-       fprintf (stderr, "%s", fiasco_get_error_message ());
+      fprintf (stderr, fiasco_get_error_message ());
       fprintf (stderr, "\n");
       return 1;
    }
diff --git a/converter/other/jbig/ANNOUNCE b/converter/other/jbig/ANNOUNCE
new file mode 100644
index 00000000..edbcc3f8
--- /dev/null
+++ b/converter/other/jbig/ANNOUNCE
@@ -0,0 +1,243 @@
+
+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 0625edd3..812bbbde 100644
--- a/converter/other/jbig/Makefile
+++ b/converter/other/jbig/Makefile
@@ -5,14 +5,9 @@ endif
 SUBDIR = converter/other/jbig
 VPATH=.:$(SRCDIR)/$(SUBDIR)
 
-SUBDIRS = libjbig
-
 include $(BUILDDIR)/config.mk
 
-# 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
+LIBJBIG_OBJECTS = jbig.o jbig_tab.o
 
 EXTERN_INCLUDES =
 ifneq ($(JBIGHDR_DIR),NONE)
@@ -23,33 +18,32 @@ endif
 
 ifneq ($(JBIGHDR_DIR),NONE)
   ifneq ($(JBIGLIB),NONE)
-    PORTBINARIES = jbigtopnm pnmtojbig
+    BINARIES = jbigtopnm pnmtojbig
   endif
 endif
 
-BINARIES = $(PORTBINARIES)
-
 SCRIPTS =
 
-ifeq ($(JBIGLIB),$(INTERNAL_JBIGLIB))
+ifeq ($(JBIGLIB),$(BUILDDIR)/$(SUBDIR)/libjbig.a)
   JBIGLIB_DEP = $(JBIGLIB)
 else
   # It's not our internal version; user's on his own to make sure it's built
 endif
 
-OBJECTS = $(BINARIES:%=%.o)
-MERGE_OBJECTS = $(BINARIES:%=%.o2)
+OBJECTS = $(BINARIES:%=%.o) $(LIBJBIG_OBJECTS)
+MERGE_OBJECTS = $(BINARIES:%=%.o2) $(LIBJBIG_OBJECTS)
 
 all: $(BINARIES)
 
 include $(SRCDIR)/common.mk
 
-$(BINARIES): %: %.o $(JBIGLIB_DEP) $(LIBOPT)
-$(BINARIES): LDFLAGS_TARGET = $(shell $(LIBOPT) $(JBIGLIB))
+$(BINARIES): %: %.o $(JBIGLIB_DEP) $(NETPBMLIB) $(LIBOPT)
+	$(LD) -o $@ $< \
+	  $(shell $(LIBOPT) $(NETPBMLIB) $(JBIGLIB)) $(MATHLIB) \
+	  $(LDFLAGS) $(LDLIBS) $(RPATH) $(LADD)
+
 
-$(INTERNAL_JBIGLIB): $(BUILDDIR)/$(SUBDIR)/libjbig FORCE
-	$(MAKE) -f $(SRCDIR)/$(SUBDIR)/libjbig/Makefile \
-	  -C $(dir $@) $(notdir $@)
+$(BUILDDIR)/$(SUBDIR)/libjbig.a: $(LIBJBIG_OBJECTS)
+	$(AR) -rc $@ $^
+	$(RANLIB) $@
 
-.PHONY: FORCE
-FORCE:
diff --git a/converter/other/jbig/README.Netpbm b/converter/other/jbig/README.Netpbm
new file mode 100644
index 00000000..3d593b92
--- /dev/null
+++ b/converter/other/jbig/README.Netpbm
@@ -0,0 +1,12 @@
+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.c b/converter/other/jbig/jbig.c
new file mode 100644
index 00000000..90295d8b
--- /dev/null
+++ b/converter/other/jbig/jbig.c
@@ -0,0 +1,2905 @@
+/*
+ *  Portable Free JBIG image compression library
+ *
+ *  Markus Kuhn -- mkuhn@acm.org
+ *
+ *  $Id: jbig.c,v 1.12 2000-04-08 11:42:18+01 mgk25 Rel $
+ *
+ *  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.
+ *
+ *  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.
+ *
+ *  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>
+#endif
+
+#include <stdlib.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 TPB2CX  0x195  /* contexts for TP special pixels */
+#define TPB3CX  0x0e5
+#define TPDCX   0xc3f
+
+/* marker codes */
+#define MARKER_STUFF    0x00
+#define MARKER_RESERVE  0x01
+#define MARKER_SDNORM   0x02
+#define MARKER_SDRST    0x03
+#define MARKER_ABORT    0x04
+#define MARKER_NEWLEN   0x05
+#define MARKER_ATMOVE   0x06
+#define MARKER_COMMENT  0x07
+#define MARKER_ESC      0xff
+
+/* loop array indices */
+#define STRIPE  0
+#define LAYER   1
+#define PLANE   2
+
+/* special jbg_buf pointers (instead of NULL) */
+#define SDE_DONE ((struct jbg_buf *) -1)
+#define SDE_TODO ((struct jbg_buf *) 0)
+
+/* 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 $ ";
+
+/*
+ * 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] = {
+  { 2, 1, 0 },    /* no ordering bit set */
+  { -1, -1, -1},  /* SMID -> illegal combination */
+  { 2, 0, 1 },    /* ILEAVE */
+  { 1, 0, 2 },    /* SMID + ILEAVE */
+  { 0, 2, 1 },    /* SEQ */
+  { 1, 2, 0 },    /* SEQ + SMID */
+  { 0, 1, 2 },    /* SEQ + ILEAVE */
+  { -1, -1, -1 }  /* SEQ + SMID + ILEAVE -> illegal combination */
+};
+
+
+/*
+ * Array [language][message] with text string 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 */
+  }
+};
+
+
+
+/*
+ * 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
+ * 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.
+ */
+
+static void *checked_malloc(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. */
+  if (!p)
+    abort();
+
+#if 0
+  fprintf(stderr, "%p = malloc(%ld)\n", p, (long) size);
+#endif
+
+  return p;
+}
+
+
+static void *checked_realloc(void *ptr, 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. */
+  if (!p)
+    abort();
+
+#if 0
+  fprintf(stderr, "%p = realloc(%p, %ld)\n", p, ptr, (long) size);
+#endif
+
+  return p;
+}
+
+
+static void checked_free(void *ptr)
+{
+  free(ptr);
+
+#if 0
+  fprintf(stderr, "free(%p)\n", ptr);
+#endif
+
+}
+
+
+
+/*
+ * 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
+ * storing SDEs by the encoder.
+ *
+ * The following functions manage a set of struct jbg_buf storage
+ * containers were each can keep JBG_BUFSIZE bytes. The jbg_buf
+ * containers can be linked to form linear double-chained lists for
+ * which a number of operations are provided. Blocks which are
+ * tempoarily not used any more are returned to a freelist which each
+ * encoder keeps. Only the destructor of the encoder actually returns
+ * the block via checked_free() to the stdlib memory management.
+ */
+
+
+/*
+ * Allocate a new buffer block and initialize it. Try to get it from
+ * the free_list, and if it is empty, call checked_malloc().
+ */
+static struct jbg_buf *jbg_buf_init(struct jbg_buf **free_list)
+{
+  struct jbg_buf *new_block;
+  
+  /* Test whether a block from the free list is available */
+  if (*free_list) {
+    new_block = *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->len = 0;
+  new_block->next = NULL;
+  new_block->previous = NULL;
+  new_block->last = new_block;
+  new_block->free_list = free_list;
+
+  return new_block;
+}
+
+
+/*
+ * Return an entire free_list to the memory management of stdlib.
+ * This is only done by jbg_enc_free().
+ */
+static void jbg_buf_free(struct jbg_buf **free_list)
+{
+  struct jbg_buf *tmp;
+  
+  while (*free_list) {
+    tmp = (*free_list)->next;
+    checked_free(*free_list);
+    *free_list = tmp;
+  }
+  
+  return;
+}
+
+
+/*
+ * Append a single byte to a single list that starts with the block
+ * *(struct jbg_buf *) head. The type of *head is void here in order to
+ * keep the interface of the arithmetic encoder gereric, which uses this
+ * function as a call-back function in order to deliver single bytes
+ * for a PSCD.
+ */
+static void jbg_buf_write(int b, void *head)
+{
+  struct jbg_buf *now;
+
+  now = ((struct jbg_buf *) head)->last;
+  if (now->len < JBG_BUFSIZE - 1) {
+    now->d[now->len++] = b;
+    return;
+  }
+  now->next = jbg_buf_init(((struct jbg_buf *) head)->free_list);
+  now->next->previous = now;
+  now->next->d[now->next->len++] = b;
+  ((struct jbg_buf *) head)->last = now->next;
+
+  return;
+}
+
+
+/*
+ * Remove any trailing zero bytes from the end of a linked jbg_buf list,
+ * however make sure that no zero byte is removed which directly
+ * follows a 0xff byte (i.e., keep MARKER_ESC MARKER_STUFF sequences
+ * intact). This function is used to remove any redundant final zero
+ * bytes from a PSCD.
+ */
+static void jbg_buf_remove_zeros(struct jbg_buf *head)
+{
+  struct jbg_buf *last;
+
+  while (1) {
+    /* remove trailing 0x00 in last block of list until this block is empty */
+    last = head->last;
+    while (last->len && last->d[last->len - 1] == 0)
+      last->len--;
+    /* if block became really empty, remove it in case it is not the
+     * only remaining block and then loop to next block */
+    if (last->previous && !last->len) {
+      head->last->next = *head->free_list;
+      *head->free_list = head->last;
+      head->last = last->previous;
+      head->last->next = NULL;
+    } else
+      break;
+  }
+
+  /*
+   * If the final non-zero byte is 0xff (MARKER_ESC), then we just have
+   * removed a MARKER_STUFF and we will append it again now in order
+   * to preserve PSCD status of byte stream.
+   */
+  if (head->last->len && head->last->d[head->last->len - 1] == MARKER_ESC)
+    jbg_buf_write(MARKER_STUFF, head);
+ 
+  return;
+}
+
+
+/*
+ * The jbg_buf list which starts with block *new_prefix is concatenated
+ * with the list which starts with block **start and *start will then point
+ * to the first block of the new list.
+ */
+static void jbg_buf_prefix(struct jbg_buf *new_prefix, struct jbg_buf **start)
+{
+  new_prefix->last->next = *start;
+  new_prefix->last->next->previous = new_prefix->last;
+  new_prefix->last = new_prefix->last->next->last;
+  *start = new_prefix;
+  
+  return;
+}
+
+
+/*
+ * Send the contents of a jbg_buf list that starts with block **head to
+ * the call back function data_out and return the blocks of the jbg_buf
+ * list to the freelist from which these jbg_buf blocks have been taken.
+ * After the call, *head == NULL.
+ */
+static void jbg_buf_output(struct jbg_buf **head,
+			void (*data_out)(unsigned char *start,
+					 size_t len, void *file),
+			void *file)
+{
+  struct jbg_buf *tmp;
+  
+  while (*head) {
+    data_out((*head)->d, (*head)->len, file);
+    tmp = (*head)->next;
+    (*head)->next = *(*head)->free_list;
+    *(*head)->free_list = *head;
+    *head = tmp;
+  }
+  
+  return;
+}
+
+
+/*
+ * Calculate y = ceil(x/2) applied n times. 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.
+ */
+unsigned long jbg_ceil_half(unsigned long x, int n)
+{
+  unsigned long mask;
+  
+  mask = (1UL << n) - 1;     /* the lowest n bits are 1 here */
+  return (x >> n) + ((mask & x) != 0);
+}
+
+
+/*
+ * Initialize the status struct for the encoder.
+ */
+void jbg_enc_init(struct jbg_enc_state *s, unsigned long x, unsigned long y,
+                  int planes, unsigned char **p,
+                  void (*data_out)(unsigned char *start, size_t len,
+				   void *file),
+		  void *file)
+{
+  unsigned long l, lx;
+  int i;
+  size_t bufsize;
+
+  extern char jbg_resred[], jbg_dptable[];
+
+  s->xd = x;
+  s->yd = y;
+  s->planes = planes;
+  s->data_out = data_out;
+  s->file = file;
+
+  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;
+  s->mx = 8;
+  s->my = 0;
+  s->order = JBG_ILEAVE | JBG_SMID;
+  s->options = JBG_TPBON | JBG_TPDON | JBG_DPON;
+  s->dppriv = jbg_dptable;
+  s->res_tab = jbg_resred;
+  
+  s->highres = 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);
+  for (i = 0; i < planes; i++) {
+    s->highres[i] = 0;
+    s->lhp[1][i] = checked_malloc(sizeof(unsigned char) * bufsize);
+  }
+  
+  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));
+  lx = jbg_ceil_half(x, 1);
+  s->tp = (char *) checked_malloc(lx * sizeof(char));
+  for (l = 0; l < lx; s->tp[l++] = 2);
+  s->sde = NULL;
+
+  return;
+}
+
+
+/*
+ * This function selects the number of differential layers based on
+ * the maximum size requested for the lowest resolution layer. If
+ * possible, a number of differential layers is selected, which will
+ * keep the size of the lowest resolution layer below or equal to the
+ * given width x and height y. However not more than 6 differential
+ * resolution layers will be used. In addition, a reasonable value for
+ * l0 (height of one stripe in the lowest resolution layer) is
+ * selected, which obeys the recommended limitations for l0 in annex A
+ * and C of the JBIG standard. The selected number of resolution layers
+ * is returned. 
+ */
+int jbg_enc_lrlmax(struct jbg_enc_state *s, unsigned long x, 
+		   unsigned long y)
+{
+  for (s->d = 0; s->d < 6; s->d++)
+    if (jbg_ceil_half(s->xd, s->d) <= x && jbg_ceil_half(s->yd, s->d) <= y)
+      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;
+
+  return s->d;
+}
+
+
+/*
+ * As an alternative to jbg_enc_lrlmax(), the following function allows
+ * to specify the number of layers directly. The stripe height and layer
+ * range is also adjusted automatically here.
+ */
+void jbg_enc_layers(struct jbg_enc_state *s, int d)
+{
+  if (d < 0 || d > 255)
+    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;
+
+  return;
+}
+
+
+/*
+ * Specify the highest and lowest resolution layers which will be
+ * written to the output file. Call this function not before
+ * jbg_enc_layers() or jbg_enc_lrlmax(), because these two functions
+ * reset the lowest and highest resolution layer to default values.
+ * Negative values are ignored. The total number of layers is returned.
+ */
+int jbg_enc_lrange(struct jbg_enc_state *s, int dl, int dh)
+{
+  if (dl >= 0     && dl <= s->d) s->dl = dl;
+  if (dh >= s->dl && dh <= s->d) s->dh = dh;
+
+  return s->d;
+}
+
+
+/*
+ * The following function allows to specify the bits describing the
+ * options of the format as well as the maximum AT movement window and
+ * 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)
+{
+  if (order >= 0 && order <= 0x0f) s->order = order;
+  if (options >= 0) s->options = options;
+  if (l0 >= 0) s->l0 = l0;
+  if (mx >= 0 && my < 128) s->mx = mx;
+  if (my >= 0 && my < 256) s->my = my;
+
+  return;
+}
+
+
+/*
+ * This function actually does all the tricky work involved in producing
+ * a SDE, which is stored in the appropriate s->sde[][][] element
+ * for later output in the correct order.
+ */
+static void encode_sde(struct jbg_enc_state *s,
+		       long stripe, int layer, int plane)
+{
+  unsigned char *hp, *lp1, *lp2, *p0, *p1, *q1, *q2;
+  unsigned long hl, ll, hx, hy, lx, ly, hbpl, lbpl;
+  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;
+  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;
+  struct jbg_buf *new_jbg_buf;
+
+#ifdef DEBUG
+  static long tp_lines, tp_exceptions, tp_pixels, dp_pixels;
+  static long encoded_pixels;
+#endif
+
+  /* return immediately if this stripe has already been encoded */
+  if (s->sde[stripe][layer][plane] != SDE_TODO)
+    return;
+
+#ifdef DEBUG
+  if (stripe == 0)
+    tp_lines = tp_exceptions = tp_pixels = dp_pixels = encoded_pixels = 0;
+  fprintf(stderr, "encode_sde: s/d/p = %2ld/%2d/%2d\n",
+	  stripe, layer, plane);
+#endif
+
+  /* number of lines per stripe in highres image */
+  hl = s->l0 << layer;
+  /* number of lines per stripe in lowres image */
+  ll = hl >> 1;
+  /* current line number in highres image */
+  y = stripe * hl;
+  /* number of pixels in highres image */
+  hx = jbg_ceil_half(s->xd, s->d - layer);
+  hy = jbg_ceil_half(s->yd, s->d - layer);
+  /* number of pixels in lowres image */
+  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;
+  /* 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;
+  
+  /* initialize arithmetic encoder */
+  se = s->s + plane;
+  arith_encode_init(se, stripe != 0);
+  s->sde[stripe][layer][plane] = jbg_buf_init(&s->free_list);
+  se->byte_out = jbg_buf_write;
+  se->file = s->sde[stripe][layer][plane];
+
+  /* initialize adaptive template movement algorithm */
+  c_all = 0;
+  for (t = 0; t <= s->mx; t++)
+    c[t] = 0;
+  if (stripe == 0)
+    s->tx[plane] = 0;
+  new_tx = -1;
+  at_determined = 0;  /* we haven't yet decided the template move */
+  if (s->mx == 0)
+    at_determined = 1;
+
+  /* initialize typical prediction */
+  ltp = 0;
+  if (stripe == 0)
+    ltp_old = 0;
+  else {
+    ltp_old = 1;
+    p1 = hp - hbpl;
+    if (y > 1) {
+      q1 = p1 - hbpl;
+      while (p1 < hp && (ltp_old = (*p1++ == *q1++)) != 0);
+    } else
+      while (p1 < hp && (ltp_old = (*p1++ == 0)) != 0);
+  }
+
+  if (layer == 0) {
+
+    /*
+     *  Encode lowest resolution layer
+     */
+
+    for (i = 0; i < hl && y < hy; i++, y++) {
+
+      /* check whether it is worth to perform an ATMOVE */
+      if (!at_determined && c_all > 2048) {
+	cmin = clmin = 0xffffffffL;
+	cmax = clmax = 0;
+	tmax = 0;
+	for (t = (s->options & JBG_LRLTWO) ? 5 : 3; t <= s->mx; t++) {
+	  if (c[t] > cmax) cmax = c[t];
+	  if (c[t] < cmin) cmin = c[t];
+	  if (c[t] > c[tmax]) tmax = t;
+	}
+	clmin = (c[0] < cmin) ? c[0] : cmin;
+	clmax = (c[0] > cmax) ? c[0] : cmax;
+	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 ? */
+	    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) &&
+	    (s->tx[plane] || clmax - clmin > (c_all >> 3))) {
+	  /* we have decided to perform an ATMOVE */
+	  new_tx = tmax;
+	  if (!(s->options & JBG_DELAY_AT)) {
+	    new_tx_line = i;
+	    s->tx[plane] = new_tx;
+	  }
+	}
+	at_determined = 1;
+      }
+      
+      /* typical prediction */
+      if (s->options & JBG_TPBON) {
+	ltp = 1;
+	p1 = hp;
+	if (y > 0) {
+	  q1 = hp - hbpl;
+	  while (q1 < hp && (ltp = (*p1++ == *q1++)) != 0);
+	} else
+	  while (p1 < hp + hbpl && (ltp = (*p1++ == 0)) != 0);
+	arith_encode(se, (s->options & JBG_LRLTWO) ? TPB2CX : TPB3CX,
+		     ltp == ltp_old);
+#ifdef DEBUG
+	tp_lines += ltp;
+#endif
+	ltp_old = ltp;
+	if (ltp) {
+	  /* skip next line */
+	  hp += hbpl;
+	  continue;
+	}
+      }
+
+      /*
+       * Layout of the variables line_h1, line_h2, line_h3, which contain
+       * as bits the neighbour pixels of the currently coded pixel X:
+       *
+       *          76543210765432107654321076543210     line_h3
+       *          76543210765432107654321076543210     line_h2
+       *  76543210765432107654321X76543210             line_h1
+       */
+      
+      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;
+      
+      /* encode line */
+      for (j = 0; j < hx; hp++) {
+	line_h1 |= *hp;
+	if (j < hbpl * 8 - 8 && y > 0) {
+	  line_h2 |= *(hp - hbpl + 1);
+	  if (y > 1)
+	    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) |
+				((line_h1 >>  9) & 0x00f)),
+			   (line_h1 >> 8) & 1);
+	    else
+	      arith_encode(se, (((line_h2 >> 10) & 0x3f0) |
+				((line_h1 >>  9) & 0x00f)),
+			   (line_h1 >> 8) & 1);
+#ifdef DEBUG
+	    encoded_pixels++;
+#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);
+	      ++c_all;
+	    }
+	  } while (++j & 7 && j < hx);
+	} else {
+	  /* three line template */
+	  do {
+	    line_h1 <<= 1;  line_h2 <<= 1;  line_h3 <<= 1;
+	    if (s->tx[plane]) 
+	      arith_encode(se, (((line_h3 >>  8) & 0x380) |
+				((line_h2 >> 12) & 0x078) |
+				((line_h1 >> (6 + s->tx[plane])) & 0x004) |
+				((line_h1 >>  9) & 0x003)),
+			   (line_h1 >> 8) & 1);
+	    else
+	      arith_encode(se, (((line_h3 >>  8) & 0x380) |
+				((line_h2 >> 12) & 0x07c) |
+				((line_h1 >>  9) & 0x003)),
+			   (line_h1 >> 8) & 1);
+#ifdef DEBUG
+	    encoded_pixels++;
+#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);
+	      ++c_all;
+	    }
+	  } while (++j & 7 && j < hx);
+	} /* if (s->options & JBG_LRLTWO) */
+      } /* for (j = ...) */
+    } /* for (i = ...) */
+
+  } else {
+
+    /*
+     *  Encode differential layer
+     */
+    
+    for (i = 0; i < hl && y < hy; i++, y++) {
+
+      /* check whether it is worth to perform an ATMOVE */
+      if (!at_determined && c_all > 2048) {
+	cmin = clmin = 0xffffffffL;
+	cmax = clmax = 0;
+	tmax = 0;
+	for (t = 3; t <= s->mx; t++) {
+	  if (c[t] > cmax) cmax = c[t];
+	  if (c[t] < cmin) cmin = c[t];
+	  if (c[t] > c[tmax]) tmax = t;
+	}
+	clmin = (c[0] < cmin) ? c[0] : cmin;
+	clmax = (c[0] > cmax) ? c[0] : cmax;
+	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 ? */
+	    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) &&
+	    (s->tx[plane] || clmax - clmin > (c_all >> 3))) {
+	  /* we have decided to perform an ATMOVE */
+	  new_tx = tmax;
+	  if (!(s->options & JBG_DELAY_AT)) {
+	    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;
+      }
+      
+      if ((i >> 1) >= ll - 1 || (y >> 1) >= ly - 1)
+	lp1 = lp2;
+
+      /* typical prediction */
+      if (s->options & JBG_TPDON && (i & 1) == 0) {
+	q1 = lp1; q2 = lp2;
+	p0 = p1 = hp;
+	if (i < hl - 1 && y < hy - 1)
+	  p0 = hp + hbpl;
+	if (y > 1)
+	  line_l3 = (long)*(q2 - lbpl) << 8;
+	else
+	  line_l3 = 0;
+	line_l2 = (long)*q2 << 8;
+	line_l1 = (long)*q1 << 8;
+	ltp = 1;
+	for (j = 0; j < lx && ltp; q1++, q2++) {
+	  if (j < lbpl * 8 - 8) {
+	    if (y > 1)
+	      line_l3 |= *(q2 - lbpl + 1);
+	    line_l2 |= *(q2 + 1);
+	    line_l1 |= *(q1 + 1);
+	  }
+	  do {
+	    if ((j >> 2) < hbpl) {
+	      line_h1 = *(p1++);
+	      line_h0 = *(p0++);
+	    }
+	    do {
+	      line_l3 <<= 1;
+	      line_l2 <<= 1;
+	      line_l1 <<= 1;
+	      line_h1 <<= 2;
+	      line_h0 <<= 2;
+	      cx = (((line_l3 >> 15) & 0x007) |
+		    ((line_l2 >> 12) & 0x038) |
+		    ((line_l1 >> 9)  & 0x1c0));
+	      if (cx == 0x000)
+		if ((line_h1 & 0x300) == 0 && (line_h0 & 0x300) == 0)
+		  s->tp[j] = 0;
+		else {
+		  ltp = 0;
+#ifdef DEBUG
+		  tp_exceptions++;
+#endif
+		}
+	      else if (cx == 0x1ff)
+		if ((line_h1 & 0x300) == 0x300 && (line_h0 & 0x300) == 0x300)
+		  s->tp[j] = 1;
+		else {
+		  ltp = 0;
+#ifdef DEBUG
+		  tp_exceptions++;
+#endif
+		}
+	      else
+		s->tp[j] = 2;
+	    } while (++j & 3 && j < lx);
+	  } while (j & 7 && j < lx);
+	} /* for (j = ...) */
+	arith_encode(se, TPDCX, !ltp);
+#ifdef DEBUG
+	tp_lines += ltp;
+#endif
+      }
+
+
+      /*
+       * Layout of the variables line_h1, line_h2, line_h3, which contain
+       * as bits the high resolution neighbour pixels of the currently coded
+       * highres pixel X:
+       *
+       *            76543210 76543210 76543210 76543210     line_h3
+       *            76543210 76543210 76543210 76543210     line_h2
+       *   76543210 76543210 7654321X 76543210              line_h1
+       *
+       * Layout of the variables line_l1, line_l2, line_l3, which contain
+       * the low resolution pixels near the currently coded pixel as bits.
+       * The lowres pixel in which the currently coded highres pixel is
+       * located is marked as Y:
+       *
+       *            76543210 76543210 76543210 76543210     line_l3
+       *            76543210 7654321Y 76543210 76543210     line_l2
+       *            76543210 76543210 76543210 76543210     line_l1
+       */
+      
+
+      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) {
+	line_h3 = (long)*(hp - hbpl - hbpl) << 8;
+	line_l3 = (long)*(lp2 - lbpl) << 8;
+      }
+      line_l2 = (long)*lp2 << 8;
+      line_l1 = (long)*lp1 << 8;
+      
+      /* encode line */
+      for (j = 0; j < hx; lp1++, lp2++) {
+	if ((j >> 1) < lbpl * 8 - 8) {
+	  if (y > 1)
+	    line_l3 |= *(lp2 - lbpl + 1);
+	  line_l2 |= *(lp2 + 1);
+	  line_l1 |= *(lp1 + 1);
+	}
+	do {
+
+	  assert(hp - (s->lhp[s->highres[plane]][plane] +
+		       (stripe * hl + i) * hbpl)
+		 == (ptrdiff_t) j >> 3);
+
+	  assert(lp2 - (s->lhp[1-s->highres[plane]][plane] +
+			(stripe * ll + (i>>1)) * lbpl)
+		 == (ptrdiff_t) j >> 4);
+
+	  line_h1 |= *(hp++);
+	  if (j < hbpl * 8 - 8) {
+	    if (y > 0) {
+	      line_h2 |= *(hp - hbpl);
+	      if (y > 1)
+		line_h3 |= *(hp - hbpl - hbpl);
+	    }
+	  }
+	  do {
+	    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 */
+	      line_h1 <<= 2;  line_h2 <<= 2;  line_h3 <<= 2;
+#ifdef DEBUG
+	      do {
+		++tp_pixels;
+	      } while (++j & 1 && j < hx);
+#else
+	      j += 2;
+#endif
+	    } else
+	      do {
+		line_h1 <<= 1;  line_h2 <<= 1;  line_h3 <<= 1;
+
+		/* deterministic prediction */
+		if (s->options & JBG_DPON) {
+		  if ((y & 1) == 0) {
+		    if ((j & 1) == 0) {
+		      /* phase 0 */
+		      if (s->dppriv[((line_l3 >> 16) & 0x003) |
+				    ((line_l2 >> 14) & 0x00c) |
+				    ((line_h1 >> 5)  & 0x010) |
+				    ((line_h2 >> 10) & 0x0e0)] < 2) {
+#ifdef DEBUG
+			++dp_pixels;
+#endif
+			continue;
+		      }
+		    } else {
+		      /* phase 1 */
+		      if (s->dppriv[(((line_l3 >> 16) & 0x003) |
+				     ((line_l2 >> 14) & 0x00c) |
+				     ((line_h1 >> 5)  & 0x030) |
+				     ((line_h2 >> 10) & 0x1c0)) + 256] < 2) {
+#ifdef DEBUG
+			++dp_pixels;
+#endif
+			continue;
+		      }
+		    }
+		  } else {
+		    if ((j & 1) == 0) {
+		      /* phase 2 */
+		      if (s->dppriv[(((line_l3 >> 16) & 0x003) |
+				     ((line_l2 >> 14) & 0x00c) |
+				     ((line_h1 >> 5)  & 0x010) |
+				     ((line_h2 >> 10) & 0x0e0) |
+				     ((line_h3 >> 7) & 0x700)) + 768] < 2) {
+#ifdef DEBUG
+			++dp_pixels;
+#endif
+			continue;
+		      }
+		    } else {
+		      /* phase 3 */
+		      if (s->dppriv[(((line_l3 >> 16) & 0x003) |
+				     ((line_l2 >> 14) & 0x00c) |
+				     ((line_h1 >> 5)  & 0x030) |
+				     ((line_h2 >> 10) & 0x1c0) |
+				     ((line_h3 >> 7)  & 0xe00)) + 2816] < 2) {
+#ifdef DEBUG
+			++dp_pixels;
+#endif
+			continue;
+		      }
+		    }	
+		  }	
+		}
+
+		/* determine context */
+		if (s->tx[plane])
+		  cx = (((line_h1 >> 9)  & 0x003) |
+			((line_h1 >> (4 + s->tx[plane])) & 0x010) |
+			((line_h2 >> 13) & 0x00c) |
+			((line_h3 >> 11) & 0x020));
+		else
+		  cx = (((line_h1 >> 9)  & 0x003) |
+			((line_h2 >> 13) & 0x01c) |
+			((line_h3 >> 11) & 0x020));
+		if (j & 1)
+		  cx |= (((line_l2 >> 9)  & 0x0c0) |
+			 ((line_l1 >> 7)  & 0x300)) | (1UL << 10);
+		else
+		  cx |= (((line_l2 >> 10) & 0x0c0) |
+			 ((line_l1 >> 8)  & 0x300));
+		cx |= (y & 1) << 11;
+
+		arith_encode(se, cx, (line_h1 >> 8) & 1);
+#ifdef DEBUG
+		encoded_pixels++;
+#endif
+		
+		/* statistics for adaptive template changes */
+		if (!at_determined && j >= s->mx) {
+		  c[0] += !(((line_h2 >> 6) ^ line_h1) & 0x100);
+		  for (t = 3; t <= s->mx; t++)
+		    c[t] += !(((line_h1 >> t) ^ line_h1) & 0x100);
+		  ++c_all;
+		}
+		
+	      } while (++j & 1 && j < hx);
+	  } while (j & 7 && j < hx);
+	} while (j & 15 && j < hx);
+      } /* for (j = ...) */
+
+      /* low resolution pixels are used twice */
+      if ((i & 1) == 0) {
+	lp1 -= lbpl;
+	lp2 -= lbpl;
+      }
+      
+    } /* for (i = ...) */
+  }
+  
+  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]);
+
+  /* add ATMOVE */
+  if (new_tx != -1) {
+    if (s->options & JBG_DELAY_AT) {
+      /* ATMOVE will become active at the first line of the next stripe */
+      s->tx[plane] = new_tx;
+      jbg_buf_write(MARKER_ESC, s->sde[stripe][layer][plane]);
+      jbg_buf_write(MARKER_ATMOVE, s->sde[stripe][layer][plane]);
+      jbg_buf_write(0, s->sde[stripe][layer][plane]);
+      jbg_buf_write(0, s->sde[stripe][layer][plane]);
+      jbg_buf_write(0, s->sde[stripe][layer][plane]);
+      jbg_buf_write(0, s->sde[stripe][layer][plane]);
+      jbg_buf_write(s->tx[plane], s->sde[stripe][layer][plane]);
+      jbg_buf_write(0, s->sde[stripe][layer][plane]);
+    } else {
+      /* ATMOVE has already become active during this stripe
+       * => we have to prefix the SDE data with an ATMOVE marker */
+      new_jbg_buf = jbg_buf_init(&s->free_list);
+      jbg_buf_write(MARKER_ESC, new_jbg_buf);
+      jbg_buf_write(MARKER_ATMOVE, new_jbg_buf);
+      jbg_buf_write((new_tx_line >> 24) & 0xff, new_jbg_buf);
+      jbg_buf_write((new_tx_line >> 16) & 0xff, new_jbg_buf);
+      jbg_buf_write((new_tx_line >> 8) & 0xff, new_jbg_buf);
+      jbg_buf_write(new_tx_line & 0xff, new_jbg_buf);
+      jbg_buf_write(new_tx, new_jbg_buf);
+      jbg_buf_write(0, new_jbg_buf);
+      jbg_buf_prefix(new_jbg_buf, &s->sde[stripe][layer][plane]);
+    }
+  }
+
+#if 0
+  if (stripe == s->stripes - 1)
+    fprintf(stderr, "tp_lines = %ld, tp_exceptions = %ld, tp_pixels = %ld, "
+	    "dp_pixels = %ld, encoded_pixels = %ld\n",
+	    tp_lines, tp_exceptions, tp_pixels, dp_pixels, encoded_pixels);
+#endif
+
+  return;
+}
+
+
+/*
+ * Create the next lower resolution version of an image
+ */
+static void resolution_reduction(struct jbg_enc_state *s, int plane,
+				 int higher_layer)
+{
+  unsigned long 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;
+  int pix, k, l;
+
+  /* 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);
+  /* number of pixels in lowres image */
+  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;
+  /* pointers to first image bytes */
+  hp2 = s->lhp[s->highres[plane]][plane];
+  hp1 = hp2 + hbpl;
+  hp3 = hp2 - hbpl;
+  lp = s->lhp[1 - s->highres[plane]][plane];
+  
+#ifdef DEBUG
+  fprintf(stderr, "resolution_reduction: plane = %d, higher_layer = %d\n",
+	  plane, higher_layer);
+#endif
+
+  /*
+   * Layout of the variables line_h1, line_h2, line_h3, which contain
+   * as bits the high resolution neighbour pixels of the currently coded
+   * lowres pixel /\:
+   *              \/
+   *
+   *   76543210 76543210 76543210 76543210     line_h3
+   *   76543210 76543210 765432/\ 76543210     line_h2
+   *   76543210 76543210 765432\/ 76543210     line_h1
+   *
+   * Layout of the variable line_l2, which contains the low resolution
+   * pixels near the currently coded pixel as bits. The lowres pixel
+   * which is currently coded is marked as X:
+   *
+   *   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;
+	}
+      }
+      ++lp;
+    }
+    *(lp - 1) <<= lbpl * 8 - lx;
+    hp1 += hbpl;
+    hp2 += hbpl;
+    hp3 += hbpl;
+  }
+
+#ifdef DEBUG
+  {
+    FILE *f;
+    char fn[50];
+    
+    sprintf(fn, "dbg_d=%02d.pbm", higher_layer - 1);
+    f = fopen(fn, "wb");
+    fprintf(f, "P4\n%lu %lu\n", lx, ly);
+    fwrite(s->lhp[1 - s->highres[plane]][plane], 1, lbpl * ly, f);
+    fclose(f);
+  }
+#endif
+
+  return;
+}
+
+
+/* 
+ * This function is called inside the three loops of jbg_enc_out() in
+ * 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
+ * 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.
+ */
+static void output_sde(struct jbg_enc_state *s,
+		       unsigned long stripe, int layer, int plane)
+{
+  int lfcl;     /* lowest fully coded layer */
+  long i;
+  unsigned long u;
+  
+  assert(s->sde[stripe][layer][plane] != SDE_DONE);
+
+  if (s->sde[stripe][layer][plane] != SDE_TODO) {
+#ifdef DEBUG
+    fprintf(stderr, "writing SDE: s/d/p = %2lu/%2d/%2d\n",
+	    stripe, layer, plane);
+#endif
+    jbg_buf_output(&s->sde[stripe][layer][plane], s->data_out, s->file);
+    s->sde[stripe][layer][plane] = SDE_DONE;
+    return;
+  }
+
+  /* Determine the smallest resolution layer in this plane for which
+   * not yet all stripes have been encoded into SDEs. This layer will
+   * have to be completely coded, before we can apply the next
+   * resolution reduction step. */
+  lfcl = 0;
+  for (i = s->d; i >= 0; i--)
+    if (s->sde[s->stripes - 1][i][plane] == SDE_TODO) {
+      lfcl = i + 1;
+      break;
+    }
+  if (lfcl > s->d && s->d > 0 && stripe == 0) {
+    /* perform the first resolution reduction */
+    resolution_reduction(s, plane, s->d);
+  }
+  /* In case HITOLO is not used, we have to encode and store the higher
+   * resolution layers first, although we do not need them right now. */
+  while (lfcl - 1 > layer) {
+    for (u = 0; u < s->stripes; u++)
+      encode_sde(s, u, lfcl - 1, plane);
+    --lfcl;
+    s->highres[plane] ^= 1;
+    if (lfcl > 1)
+      resolution_reduction(s, plane, lfcl - 1);
+  }
+  
+  encode_sde(s, stripe, layer, plane);
+
+#ifdef DEBUG
+  fprintf(stderr, "writing SDE: s/d/p = %2lu/%2d/%2d\n", stripe, layer, plane);
+#endif
+  jbg_buf_output(&s->sde[stripe][layer][plane], s->data_out, s->file);
+  s->sde[stripe][layer][plane] = SDE_DONE;
+  
+  if (stripe == s->stripes - 1 && layer > 0 &&
+      s->sde[0][layer-1][plane] == SDE_TODO) {
+    s->highres[plane] ^= 1;
+    if (layer > 1)
+      resolution_reduction(s, plane, layer - 1);
+  }
+  
+  return;
+}
+
+
+/*
+ * Convert the table which controls the deterministic prediction
+ * process from the internal format into the representation required
+ * for the 1728 byte long DPTABLE element of a BIH.
+ *
+ * The bit order of the DPTABLE format (see also ITU-T T.82 figure 13) is
+ *
+ * high res:   4  5  6     low res:  0  1
+ *             7  8  9               2  3
+ *            10 11 12
+ *
+ * were 4 table entries are packed into one byte, while we here use
+ * internally an unpacked 6912 byte long table indexed by the following
+ * bit order:
+ *
+ * high res:   7  6  5     high res:   8  7  6     low res:  1  0
+ * (phase 0)   4  .  .     (phase 1)   5  4  .               3  2
+ *             .  .  .                 .  .  .
+ *
+ * high res:  10  9  8     high res:  11 10  9
+ * (phase 2)   7  6  5     (phase 3)   8  7  6
+ *             4  .  .                 5  4  .
+ */
+void jbg_int2dppriv(unsigned char *dptable, const char *internal)
+{
+  int i, j, k;
+  int trans0[ 8] = { 1, 0, 3, 2, 7, 6, 5, 4 };
+  int trans1[ 9] = { 1, 0, 3, 2, 8, 7, 6, 5, 4 };
+  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);
+
+#define FILL_TABLE1(offset, len, trans) \
+  for (i = 0; i < len; i++) { \
+    k = 0; \
+    for (j = 0; j < 8; j++) \
+      k |= ((i >> j) & 1) << trans[j]; \
+    dptable[(i + offset) >> 2] |= \
+      (internal[k + offset] & 3) << ((3 - (i&3)) << 1); \
+  }
+
+  FILL_TABLE1(   0,  256, trans0);
+  FILL_TABLE1( 256,  512, trans1);
+  FILL_TABLE1( 768, 2048, trans2);
+  FILL_TABLE1(2816, 4096, trans3);
+
+  return;
+}
+
+
+/*
+ * Convert the table which controls the deterministic prediction
+ * process from the 1728 byte long DPTABLE format into the 6912 byte long
+ * internal format.
+ */
+void jbg_dppriv2int(char *internal, const unsigned char *dptable)
+{
+  int i, j, k;
+  int trans0[ 8] = { 1, 0, 3, 2, 7, 6, 5, 4 };
+  int trans1[ 9] = { 1, 0, 3, 2, 8, 7, 6, 5, 4 };
+  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 };
+  
+#define FILL_TABLE2(offset, len, trans) \
+  for (i = 0; i < len; i++) { \
+    k = 0; \
+    for (j = 0; j < 8; j++) \
+      k |= ((i >> j) & 1) << trans[j]; \
+    internal[k + offset] = \
+      (dptable[(i + offset) >> 2] >> ((3 - (i & 3)) << 1)) & 3; \
+  }
+
+  FILL_TABLE2(   0,  256, trans0);
+  FILL_TABLE2( 256,  512, trans1);
+  FILL_TABLE2( 768, 2048, trans2);
+  FILL_TABLE2(2816, 4096, trans3);
+
+  return;
+}
+
+
+/*
+ * Encode one full BIE and pass the generated data to the specified
+ * call-back function
+ */
+void jbg_enc_out(struct jbg_enc_state *s)
+{
+  long bpl;
+  unsigned char bih[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)
+    s->order = order = JBG_SMID | JBG_ILEAVE;
+  if (s->options & JBG_DPON && s->dppriv != jbg_dptable)
+    s->options |= JBG_DPPRIV;
+  if (s->mx > MX_MAX)
+    s->mx = MX_MAX;
+  s->my = 0;
+  if (s->mx && s->mx < ((s->options & JBG_LRLTWO) ? 5U : 3U))
+    s->mx = 0;
+  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;
+
+  /* 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 */
+    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);
+  }
+
+  /* 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;
+
+  /* allocate buffers for SDE pointers */
+  if (s->sde == NULL) {
+    s->sde = (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 **));
+      for (layer = 0; layer < s->d + 1; layer++) {
+	s->sde[stripe][layer] = (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;
+      }
+    }
+  }
+
+  /* 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);
+  if ((s->options & (JBG_DPON | JBG_DPPRIV | JBG_DPLAST)) ==
+      (JBG_DPON | JBG_DPPRIV)) {
+    /* write private table */
+    jbg_int2dppriv(dpbuf, s->dppriv);
+    s->data_out(dpbuf, 1728, s->file);
+  }
+
+#if 0
+  /*
+   * Encode everything first. This is a simple-minded alternative to
+   * all the tricky on-demand encoding logic in output_sde() for
+   * debugging purposes.
+   */
+  for (layer = s->dh; layer >= s->dl; layer--) {
+    for (plane = 0; plane < s->planes; plane++) {
+      if (layer > 0)
+	resolution_reduction(s, plane, layer);
+      for (stripe = 0; stripe < s->stripes; stripe++)
+	encode_sde(s, stripe, layer, plane);
+      s->highres[plane] ^= 1;
+    }
+  }
+#endif
+
+  /*
+   * Generic loops over all SDEs. Which loop represents layer, plane and
+   * 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;
+
+  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]];
+	if (s->order & JBG_HITOLO)
+	  layer = s->dh - (ii[index[order][LAYER]] - s->dl);
+	else
+	  layer = ii[index[order][LAYER]];
+	plane = ii[index[order][PLANE]];
+
+	output_sde(s, stripe, layer, plane);
+
+      }
+
+  return;
+}
+
+
+void jbg_enc_free(struct jbg_enc_state *s)
+{
+  unsigned long stripe;
+  int layer, plane;
+
+#ifdef DEBUG
+  fprintf(stderr, "jbg_enc_free(%p)\n", s);
+#endif
+
+  /* clear buffers for SDEs */
+  if (s->sde) {
+    for (stripe = 0; stripe < s->stripes; stripe++) {
+      for (layer = 0; layer < s->d + 1; layer++) {
+	for (plane = 0; plane < s->planes; plane++)
+	  if (s->sde[stripe][layer][plane] != SDE_DONE &&
+	      s->sde[stripe][layer][plane] != SDE_TODO)
+	    jbg_buf_free(&s->sde[stripe][layer][plane]);
+	checked_free(s->sde[stripe][layer]);
+      }
+      checked_free(s->sde[stripe]);
+    }
+    checked_free(s->sde);
+  }
+
+  /* clear free_list */
+  jbg_buf_free(&s->free_list);
+
+  /* clear memory for arithmetic encoder states */
+  checked_free(s->s);
+
+  /* clear memory for differential-layer typical prediction buffer */
+  checked_free(s->tp);
+
+  /* clear memory for adaptive template pixel offsets */
+  checked_free(s->tx);
+
+  /* clear lowres image buffers */
+  if (s->lhp[1]) {
+    for (plane = 0; plane < s->planes; plane++)
+      checked_free(s->lhp[1][plane]);
+    checked_free(s->lhp[1]);
+  }
+
+  return;
+}
+
+
+/*
+ * Convert the error codes used by jbg_dec_in() into a string
+ * written in the selected language and character set.
+ */
+const char *jbg_strerror(int errnum, int language)
+{
+  if (errnum < 0 || errnum >= NEMSG)
+    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];
+}
+
+
+/*
+ * The constructor for a decoder 
+ */
+void jbg_dec_init(struct jbg_dec_state *s)
+{
+  s->order = 0;
+  s->d = -1;
+  s->bie_len = 0;
+  s->buf_len = 0;
+  s->dppriv = NULL;
+  s->xmax = 4294967295UL;
+  s->ymax = 4294967295UL;
+  s->dmax = 256;
+  s->s = NULL;
+
+  return;
+}
+
+
+/*
+ * Specify a maximum image size for the decoder. If the JBIG file has
+ * the order bit ILEAVE, but not the bit SEQ set, then the decoder
+ * will abort to decode after the image has reached the maximal
+ * resolution layer which is still not wider than xmax or higher than
+ * ymax.
+ */
+void jbg_dec_maxsize(struct jbg_dec_state *s, unsigned long xmax,
+		     unsigned long ymax)
+{
+  if (xmax > 0) s->xmax = xmax;
+  if (ymax > 0) s->ymax = ymax;
+
+  return;
+}
+
+
+/*
+ * 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.
+ */
+static size_t decode_pscd(struct jbg_dec_state *s, unsigned char *data,
+			  size_t len)
+{
+  unsigned long stripe;
+  unsigned int layer, plane;
+  unsigned long hl, ll, y, hx, hy, lx, ly, hbpl, lbpl;
+  unsigned char *hp, *lp1, *lp2, *p1, *q1;
+  register unsigned long line_h1, line_h2, line_h3;
+  register unsigned long line_l1, line_l2, line_l3;
+  struct jbg_ardec_state *se;
+  unsigned long x;
+  int n;
+  int pix, cx = 0, slntp, shift, 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]];
+
+  /* forward data to arithmetic decoder */
+  se = s->s[plane] + layer - s->dl;
+  se->pscd_ptr = data;
+  se->pscd_end = data + len;
+  
+  /* number of lines per stripe in highres image */
+  hl = s->l0 << layer;
+  /* number of lines per stripe in lowres image */
+  ll = hl >> 1;
+  /* current line number in highres image */
+  y = stripe * hl + s->i;
+  /* number of pixels in highres image */
+  hx = jbg_ceil_half(s->xd, s->d - layer);
+  hy = jbg_ceil_half(s->yd, s->d - layer);
+  /* number of pixels in lowres image */
+  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;
+  /* pointer to highres and lowres image bytes */
+  hp  = s->lhp[ layer    & 1][plane] + (stripe * hl + s->i) * hbpl +
+    (s->x >> 3);
+  lp2 = s->lhp[(layer-1) & 1][plane] + (stripe * ll + (s->i >> 1)) * lbpl +
+    (s->x >> 4);
+  lp1 = lp2 + lbpl;
+
+  /* restore a few local variables */
+  line_h1 = s->line_h1;
+  line_h2 = s->line_h2;
+  line_h3 = s->line_h3;
+  line_l1 = s->line_l1;
+  line_l2 = s->line_l2;
+  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);
+#endif
+
+  if (layer == 0) {
+
+    /*
+     *  Decode lowest resolution layer
+     */
+
+    for (; s->i < hl && y < hy; s->i++, y++) {
+
+      /* adaptive template changes */
+      if (x == 0)
+	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];
+	    s->ty[plane][layer - s->dl] = s->at_ty[n];
+#ifdef DEBUG
+	    fprintf(stderr, "ATMOVE: line=%lu, tx=%d, ty=%d.\n", s->i,
+		    s->tx[plane][layer - s->dl], s->ty[plane][layer - s->dl]);
+#endif
+	  }
+      tx = s->tx[plane][layer - s->dl];
+      shift =  tx - ((s->options & JBG_LRLTWO) ? 5 : 3);
+
+      /* 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)
+	  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 {
+	  /* 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]))
+	    while (p1 < hp + hbpl) *p1++ = 0;
+	  else {
+	    q1 = hp - hbpl;
+	    while (q1 < hp) *p1++ = *q1++;
+	  }
+	  hp += hbpl;
+	  continue;
+	}
+      }
+      
+      /*
+       * Layout of the variables line_h1, line_h2, line_h3, which contain
+       * as bits the neighbour pixels of the currently decoded pixel X:
+       *
+       *                     76543210 76543210 76543210 76543210     line_h3
+       *                     76543210 76543210 76543210 76543210     line_h2
+       *   76543210 76543210 76543210 76543210 X                     line_h1
+       */
+      
+      if (x == 0) {
+	line_h1 = line_h2 = line_h3 = 0;
+	if (s->i > 0 || (y > 0 && !s->reset[plane][layer - s->dl]))
+	  line_h2 = (long)*(hp - hbpl) << 8;
+	if (s->i > 1 || (y > 1 && !s->reset[plane][layer - s->dl]))
+	  line_h3 = (long)*(hp - hbpl - hbpl) << 8;
+      }
+      
+      /*
+       * Another tiny JBIG standard bug:
+       *
+       * While implementing the line_h3 handling here, I discovered
+       * another problem with the ITU-T T.82(1993 E) specification.
+       * This might be a somewhat pathological case, however. The
+       * standard is unclear about how a decoder should behave in the
+       * following situation:
+       *
+       * Assume we are in layer 0 and all stripes are single lines
+       * (L0=1 allowed by table 9). We are now decoding the first (and
+       * only) line of the third stripe. Assume, the first stripe was
+       * terminated by SDRST and the second stripe was terminated by
+       * SDNORM. While decoding the only line of the third stripe with
+       * the three-line template, we need access to pixels from the
+       * previous two stripes. We know that the previous stripe
+       * terminated with SDNROM, so we access the pixel from the
+       * second stripe. But do we have to replace the pixels from the
+       * first stripe by background pixels, because this stripe ended
+       * with SDRST? The standard, especially clause 6.2.5 does never
+       * mention this case, so the behaviour is undefined here. My
+       * current implementation remembers only the marker used to
+       * terminate the previous stripe. In the above example, the
+       * pixels of the first stripe are accessed despite the fact that
+       * this stripe ended with SDRST. An alternative (only slightly
+       * more complicated) implementation would be to remember the end
+       * marker (SDNORM or SDRST) of the previous two stripes in a
+       * plane/layer and to act accordingly when accessing the two
+       * previous lines. What am I supposed to do here?
+       *
+       * As the standard is unclear about the correct behaviour in the
+       * situation of the above example, I strongly suggest to avoid
+       * the following situation while encoding data with JBIG:
+       *
+       *   LRLTWO = 0, L0=1 and both SDNORM and SDRST appear in layer 0.
+       *
+       * I guess that only a very few if any encoders will switch
+       * between SDNORM and SDRST, so let us hope that this ambiguity
+       * in the standard will never cause any interoperability
+       * problems.
+       *
+       * Markus Kuhn -- 1995-04-30
+       */
+
+      /* decode line */
+      while (x < hx) {
+	if ((x & 7) == 0) {
+	  if (x < hbpl * 8 - 8 &&
+	      (s->i > 0 || (y > 0 && !s->reset[plane][layer - s->dl]))) {
+	    line_h2 |= *(hp - hbpl + 1);
+	    if (s->i > 1 || (y > 1 && !s->reset[plane][layer - s->dl]))
+	      line_h3 |= *(hp - hbpl - hbpl + 1);
+	  }
+	}
+	if (s->options & JBG_LRLTWO) {
+	  /* two line template */
+	  do {
+	    if (tx)
+	      pix = arith_decode(se, (((line_h2 >> 9) & 0x3e0) |
+				      ((line_h1 >> shift) & 0x010) |
+				      (line_h1 & 0x00f)));
+	    else
+	      pix = arith_decode(se, (((line_h2 >> 9) & 0x3f0) |
+				      (line_h1 & 0x00f)));
+	    if (se->result == JBG_MORE || se->result == JBG_MARKER)
+	      goto leave;
+	    line_h1 = (line_h1 << 1) | pix;
+	    line_h2 <<= 1;
+	  } while ((++x & 7) && x < hx);
+	} else {
+	  /* three line template */
+	  do {
+	    if (tx) 
+	      pix = arith_decode(se, (((line_h3 >>  7) & 0x380) |
+				      ((line_h2 >> 11) & 0x078) |
+				      ((line_h1 >> shift) & 0x004) |
+				      (line_h1 & 0x003)));
+	    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)
+	      goto leave;
+	    
+	    line_h1 = (line_h1 << 1) | pix;
+	    line_h2 <<= 1;
+	    line_h3 <<= 1;
+	  } while ((++x & 7) && x < hx);
+	} /* if (s->options & JBG_LRLTWO) */
+	*hp++ = line_h1;
+      } /* while */
+      *(hp - 1) <<= hbpl * 8 - hx;
+      x = 0;
+      s->pseudo = 1;
+    } /* for (i = ...) */
+    
+  } else {
+
+    /*
+     *  Decode differential layer
+     */
+
+    for (; s->i < hl && y < hy; s->i++, y++) {
+
+      /* adaptive template changes */
+      if (x == 0)
+	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];
+	    s->ty[plane][layer - s->dl] = s->at_ty[n];
+#ifdef DEBUG
+	    fprintf(stderr, "ATMOVE: line=%lu, tx=%d, ty=%d.\n", s->i,
+		    s->tx[plane][layer - s->dl], s->ty[plane][layer - s->dl]);
+#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)
+	  goto leave;
+	s->pseudo = 0;
+      }
+
+
+      /*
+       * Layout of the variables line_h1, line_h2, line_h3, which contain
+       * as bits the high resolution neighbour pixels of the currently
+       * decoded highres pixel X:
+       *
+       *                     76543210 76543210 76543210 76543210     line_h3
+       *                     76543210 76543210 76543210 76543210     line_h2
+       *   76543210 76543210 76543210 76543210 X                     line_h1
+       *
+       * Layout of the variables line_l1, line_l2, line_l3, which contain
+       * the low resolution pixels near the currently decoded pixel as bits.
+       * The lowres pixel in which the currently coded highres pixel is
+       * located is marked as Y:
+       *
+       *                     76543210 76543210 76543210 76543210     line_l3
+       *                     76543210 76543210 Y6543210 76543210     line_l2
+       *                     76543210 76543210 76543210 76543210     line_l1
+       */
+      
+
+      if (x == 0) {
+	line_h1 = line_h2 = line_h3 = line_l1 = line_l2 = line_l3 = 0;
+	if (s->i > 0 || (y > 0 && !s->reset[plane][layer - s->dl])) {
+	  line_h2 = (long)*(hp - hbpl) << 8;
+	  if (s->i > 1 || (y > 1 && !s->reset[plane][layer - s->dl]))
+	    line_h3 = (long)*(hp - hbpl - hbpl) << 8;
+	}
+	if (s->i > 1 || (y > 1 && !s->reset[plane][layer-s->dl]))
+	  line_l3 = (long)*(lp2 - lbpl) << 8;
+	line_l2 = (long)*lp2 << 8;
+	line_l1 = (long)*lp1 << 8;
+      }
+      
+      /* decode line */
+      while (x < hx) {
+	if ((x & 15) == 0)
+	  if ((x >> 1) < lbpl * 8 - 8) {
+	    line_l1 |= *(lp1 + 1);
+	    line_l2 |= *(lp2 + 1);
+	    if (s->i > 1 || 
+		(y > 1 && !s->reset[plane][layer - s->dl]))
+	      line_l3 |= *(lp2 - lbpl + 1);
+	  }
+	do {
+
+	  assert(hp  - (s->lhp[ layer     &1][plane] + (stripe * hl + s->i)
+			* hbpl) == (ptrdiff_t) x >> 3);
+	  assert(lp2 - (s->lhp[(layer-1) &1][plane] + (stripe * ll + (s->i>>1))
+			* lbpl) == (ptrdiff_t) x >> 4);
+
+	  if ((x & 7) == 0)
+	    if (x < hbpl * 8 - 8) {
+	      if (s->i > 0 || (y > 0 && !s->reset[plane][layer - s->dl])) {
+		line_h2 |= *(hp + 1 - hbpl);
+		if (s->i > 1 || (y > 1 && !s->reset[plane][layer - s->dl]))
+		  line_h3 |= *(hp + 1 - hbpl - hbpl);
+	      }
+	    }
+	  do {
+	    if (!s->lntp[plane][layer - s->dl])
+              cx = (((line_l3 >> 14) & 0x007) |
+                    ((line_l2 >> 11) & 0x038) |
+                    ((line_l1 >> 8)  & 0x1c0));
+	    if (!s->lntp[plane][layer - s->dl] &&
+		(cx == 0x000 || cx == 0x1ff)) {
+	      /* pixels are typical and have not to be decoded */
+	      do {
+		line_h1 = (line_h1 << 1) | (cx & 1);
+	      } while ((++x & 1) && x < hx);
+	      line_h2 <<= 2;  line_h3 <<= 2;
+	    } else 
+	      do {
+		
+		/* deterministic prediction */
+		if (s->options & JBG_DPON)
+		  if ((y & 1) == 0)
+		    if ((x & 1) == 0) 
+		      /* phase 0 */
+		      pix = s->dppriv[((line_l3 >> 15) & 0x003) |
+				      ((line_l2 >> 13) & 0x00c) |
+				      ((line_h1 <<  4) & 0x010) |
+				      ((line_h2 >>  9) & 0x0e0)];
+		    else
+		      /* phase 1 */
+		      pix = s->dppriv[(((line_l3 >> 15) & 0x003) |
+				       ((line_l2 >> 13) & 0x00c) |
+				       ((line_h1 <<  4) & 0x030) |
+				       ((line_h2 >>  9) & 0x1c0)) + 256];
+		  else
+		    if ((x & 1) == 0)
+		      /* phase 2 */
+		      pix = s->dppriv[(((line_l3 >> 15) & 0x003) |
+				       ((line_l2 >> 13) & 0x00c) |
+				       ((line_h1 <<  4) & 0x010) |
+				       ((line_h2 >>  9) & 0x0e0) |
+				       ((line_h3 >>  6) & 0x700)) + 768];
+		    else
+		      /* phase 3 */
+		      pix = s->dppriv[(((line_l3 >> 15) & 0x003) |
+				       ((line_l2 >> 13) & 0x00c) |
+				       ((line_h1 <<  4) & 0x030) |
+				       ((line_h2 >>  9) & 0x1c0) |
+				       ((line_h3 >>  6) & 0xe00)) + 2816];
+		else
+		  pix = 2;
+
+		if (pix & 2) {
+		  if (tx)
+		    cx = ((line_h1         & 0x003) |
+			  (((line_h1 << 2) >> shift) & 0x010) |
+			  ((line_h2 >> 12) & 0x00c) |
+			  ((line_h3 >> 10) & 0x020));
+		  else
+		    cx = ((line_h1         & 0x003) |
+			  ((line_h2 >> 12) & 0x01c) |
+			  ((line_h3 >> 10) & 0x020));
+		  if (x & 1)
+		    cx |= (((line_l2 >> 8) & 0x0c0) |
+			   ((line_l1 >> 6) & 0x300)) | (1UL << 10);
+		  else
+		    cx |= (((line_l2 >> 9) & 0x0c0) |
+			   ((line_l1 >> 7) & 0x300));
+		  cx |= (y & 1) << 11;
+
+		  pix = arith_decode(se, cx);
+		  if (se->result == JBG_MORE || se->result == JBG_MARKER)
+		    goto leave;
+		}
+
+		line_h1 = (line_h1 << 1) | pix;
+		line_h2 <<= 1;
+		line_h3 <<= 1;
+		
+	      } while ((++x & 1) && x < hx);
+	    line_l1 <<= 1; line_l2 <<= 1;  line_l3 <<= 1;
+	  } while ((x & 7) && x < hx);
+	  *hp++ = line_h1;
+	} while ((x & 15) && x < hx);
+	++lp1;
+	++lp2;
+      } /* while */
+      x = 0;
+      
+      *(hp - 1) <<= hbpl * 8 - hx;
+      if ((s->i & 1) == 0) {
+	/* low resolution pixels are used twice */
+	lp1 -= lbpl;
+	lp2 -= lbpl;
+      } else
+	s->pseudo = 1;
+      
+    } /* for (i = ...) */
+    
+  }
+
+ leave:
+
+  /* save a few local variables */
+  s->line_h1 = line_h1;
+  s->line_h2 = line_h2;
+  s->line_h3 = line_h3;
+  s->line_l1 = line_l1;
+  s->line_l2 = line_l2;
+  s->line_l3 = line_l3;
+  s->x = x;
+
+  return se->pscd_ptr - data;
+}
+
+
+/*
+ * Provide a new BIE fragment to the decoder.
+ *
+ * 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 occurred 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).
+ */
+int jbg_dec_in(struct jbg_dec_state *s, unsigned char *data, size_t len,
+	       size_t *cnt)
+{
+  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;
+
+  if (!cnt) cnt = &dummy_cnt;
+  *cnt = 0;
+  if (len < 1) return JBG_EAGAIN;
+
+  /* read in 20-byte BIH */
+  if (s->bie_len < 20) {
+    while (s->bie_len < 20 && *cnt < 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[0] != s->d + 1)
+      return JBG_ENOCONT;
+    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;
+    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;
+    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;
+    s->mx = s->buffer[16];
+    if (s->mx > 127)
+      return JBG_EINVAL;
+    s->my = s->buffer[17];
+    if (s->mx > 32 || s->my > 0) 
+      return JBG_EIMPL;
+    s->order = s->buffer[18];
+    if (index[s->order & 7][0] < 0)
+      return JBG_EINVAL;
+    /* HITOLO and SEQ currently not yet implemented */
+    if (s->dl != s->d && (s->order & JBG_HITOLO || s->order & JBG_SEQ))
+      return JBG_EIMPL;
+    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;
+
+    /* 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);
+    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 *));
+      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);
+      }
+    } 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);
+      }
+    }
+    for (i = 0; i < s->planes; i++)
+      for (j = 0; j <= s->d - s->dl; j++)
+	arith_decode_init(s->s[i] + j, 0);
+    if (s->dl == 0 || (s->options & JBG_DPON && !(s->options & JBG_DPPRIV)))
+      s->dppriv = jbg_dptable;
+    s->comment_skip = 0;
+    s->buf_len = 0;
+    s->x = 0;
+    s->i = 0;
+    s->pseudo = 1;
+    s->at_moves = 0;
+  }
+
+  /* read in DPTABLE */
+  if (s->bie_len < 20 + 1728 && 
+      (s->options & (JBG_DPON | JBG_DPPRIV | JBG_DPLAST)) ==
+      (JBG_DPON | JBG_DPPRIV)) {
+    assert(s->bie_len >= 20);
+    while (s->bie_len < 20 + 1728 && *cnt < len)
+      s->buffer[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);
+  }
+
+  /*
+   * BID processing loop
+   */
+  
+  while (*cnt < len) {
+
+    /* process floating marker segments */
+
+    /* skip COMMENT contents */
+    if (s->comment_skip) {
+      if (s->comment_skip <= len - *cnt) {
+	*cnt += s->comment_skip;
+	s->comment_skip = 0;
+      } else {
+	s->comment_skip -= len - *cnt;
+	*cnt = len;
+      }
+      continue;
+    }
+
+    /* load complete marker segments into s->buffer for processing */
+    if (s->buf_len > 0) {
+      assert(s->buffer[0] == MARKER_ESC);
+      while (s->buf_len < 2 && *cnt < len)
+	s->buffer[s->buf_len++] = data[(*cnt)++];
+      if (s->buf_len < 2) continue;
+      switch (s->buffer[1]) {
+      case MARKER_COMMENT: required_length = 6; break;
+      case MARKER_ATMOVE:  required_length = 8; break;
+      case MARKER_NEWLEN:  required_length = 6; break;
+      case MARKER_ABORT:
+      case MARKER_SDNORM:
+      case MARKER_SDRST:   required_length = 2; break;
+      case MARKER_STUFF:
+	/* forward stuffed 0xff to arithmetic decoder */
+	s->buf_len = 0;
+	decode_pscd(s, s->buffer, 2);
+	continue;
+      default:
+	return JBG_EMARKER;
+      }
+      while (s->buf_len < required_length && *cnt < len)
+	s->buffer[s->buf_len++] = data[(*cnt)++];
+      if (s->buf_len < required_length) continue;
+      /* now the buffer is filled with exactly one marker segment */
+      switch (s->buffer[1]) {
+      case MARKER_COMMENT:
+	s->comment_skip = 
+	  (((long) s->buffer[2] << 24) | ((long) s->buffer[3] << 16) |
+	   ((long) s->buffer[4] <<  8) | (long) s->buffer[5]);
+	break;
+      case MARKER_ATMOVE:
+	if (s->at_moves < JBG_ATMOVES_MAX) {
+	  s->at_line[s->at_moves] =
+	    (((long) s->buffer[2] << 24) | ((long) s->buffer[3] << 16) |
+	     ((long) s->buffer[4] <<  8) | (long) s->buffer[5]);
+	  s->at_tx[s->at_moves] = (signed char) s->buffer[6];
+	  s->at_ty[s->at_moves] = s->buffer[7];
+	  if (s->at_tx[s->at_moves] < - (int) s->mx ||
+	      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;
+	  s->at_moves++;
+	} else
+	  return JBG_EINVAL;
+	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;
+	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;
+	break;
+      case MARKER_ABORT:
+	return JBG_EABORT;
+	
+      case MARKER_SDNORM:
+      case MARKER_SDRST:
+	/* 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
+			  && s->buffer[1] != MARKER_SDRST);
+	
+	s->reset[s->ii[index[s->order & 7][PLANE]]]
+	  [s->ii[index[s->order & 7][LAYER]] - s->dl] =
+	    (s->buffer[1] == MARKER_SDRST);
+	
+	/* prepare for next SDE */
+	s->x = 0;
+	s->i = 0;
+	s->pseudo = 1;
+	s->at_moves = 0;
+	
+	/* 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;
+	i = 2;  /* index to innermost loop */
+	do {
+	  j = 0;  /* carry flag */
+	  if (++s->ii[i] > ie[i]) {
+	    /* handling overflow of loop variable */
+	    j = 1;
+	    if (i > 0)
+	      s->ii[i] = is[i];
+	  }
+	} while (--i >= 0 && j);
+
+	s->buf_len = 0;
+	
+	/* check whether this have been all SDEs */
+	if (j) {
+	  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) {
+	  /* 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) {
+	    s->xmax = 4294967295UL;
+	    s->ymax = 4294967295UL;
+	    return JBG_EOK_INTR;
+	  }
+	  if (s->ii[0] > (unsigned long) s->dmax) {
+	    s->dmax = 256;
+	    return JBG_EOK_INTR;
+	  }
+	}
+
+	break;
+      }
+      s->buf_len = 0;
+
+    } else if (data[*cnt] == MARKER_ESC)
+      s->buffer[s->buf_len++] = data[(*cnt)++];
+
+    else {
+
+      /* we have found PSCD bytes */
+      *cnt += decode_pscd(s, data + *cnt, len - *cnt);
+      if (*cnt < len && data[*cnt] != 0xff) {
+#ifdef DEBUG
+	fprintf(stderr, "PSCD was longer than expected, unread bytes "
+		"%02x %02x %02x %02x ...\n", data[*cnt], data[*cnt+1],
+		data[*cnt+2], data[*cnt+3]);
+#endif
+	return JBG_EINVAL;
+      }
+      
+    }
+  }  /* of BID processing loop 'while (*cnt < len) ...' */
+
+  return JBG_EAGAIN;
+}
+
+
+/*
+ * 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.
+ */
+long jbg_dec_getwidth(const struct jbg_dec_state *s)
+{
+  if (s->d < 0)
+    return -1;
+  if (index[s->order & 7][LAYER] == 0) {
+    if (s->ii[0] < 1)
+      return -1;
+    else
+      return jbg_ceil_half(s->xd, s->d - (s->ii[0] - 1));
+  }
+
+  return s->xd;
+}
+
+
+/*
+ * 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.
+ */
+long jbg_dec_getheight(const struct jbg_dec_state *s)
+{
+  if (s->d < 0)
+    return -1;
+  if (index[s->order & 7][LAYER] == 0) {
+    if (s->ii[0] < 1)
+      return -1;
+    else
+      return jbg_ceil_half(s->yd, s->d - (s->ii[0] - 1));
+  }
+  
+  return s->yd;
+}
+
+
+/*
+ * 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.
+ */
+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 (s->ii[0] < 1)
+      return NULL;
+    else
+      return s->lhp[(s->ii[0] - 1) & 1][plane];
+  }
+  
+  return s->lhp[s->d & 1][plane];
+}
+
+
+/*
+ * After jbg_dec_in() returned JBG_EOK or JBG_EOK_INTR, you can call
+ * 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)
+{
+  if (s->d < 0)
+    return -1;
+  if (index[s->order & 7][LAYER] == 0) {
+    if (s->ii[0] < 1)
+      return -1;
+    else
+      return 
+	((jbg_ceil_half(s->xd, s->d - (s->ii[0] - 1)) + 7) / 8) *
+	jbg_ceil_half(s->yd, s->d - (s->ii[0] - 1));
+  }
+  
+  return ((s->xd + 7) / 8) * s->yd;
+}
+
+
+/*
+ * After jbg_dec_in() returned JBG_EOK or JBG_EOK_INTR, you can call
+ * 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)
+{
+  if (s->d < 0)
+    return -1;
+  if (index[s->order & 7][LAYER] == 0) {
+    if (s->ii[0] < 1)
+      return -1;
+    else
+      return 
+	jbg_ceil_half(s->xd, s->d - (s->ii[0] - 1)) *
+	jbg_ceil_half(s->yd, s->d - (s->ii[0] - 1)) *
+	((s->planes + 7) / 8);
+  }
+  
+  return s->xd * s->yd * ((s->planes + 7) / 8);
+}
+
+
+/* 
+ * The destructor function which releases any resources obtained by the
+ * other decoder functions.
+ */
+void jbg_dec_free(struct jbg_dec_state *s)
+{
+  int i;
+
+  if (s->d < 0 || s->s == NULL)
+    return;
+  s->d = -2;
+
+  for (i = 0; i < s->planes; i++) {
+    checked_free(s->s[i]);
+    checked_free(s->tx[i]);
+    checked_free(s->ty[i]);
+    checked_free(s->reset[i]);
+    checked_free(s->lntp[i]);
+    checked_free(s->lhp[0][i]);
+    checked_free(s->lhp[1][i]);
+  }
+  
+  checked_free(s->s);
+  checked_free(s->tx);
+  checked_free(s->ty);
+  checked_free(s->reset);
+  checked_free(s->lntp);
+  checked_free(s->lhp[0]);
+  checked_free(s->lhp[1]);
+
+  s->s = NULL;
+
+  return;
+}
+
+
+/*
+ * Split bigendian integer pixel field into separate bit planes. In the
+ * src array, every pixel is represented by a ((has_planes + 7) / 8) byte
+ * long word, most significant byte first. While has_planes describes
+ * the number of used bits per pixel in the source image, encode_plane
+ * is the number of most significant bits among those that we
+ * actually transfer to dest.
+ */
+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)
+{
+  unsigned bpl = (x + 7) / 8;           /* bytes per line in dest plane */
+  unsigned i, 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;
+
+  /* sanity checks */
+  if (encode_planes > has_planes)
+    encode_planes = has_planes;
+  use_graycode = use_graycode != 0 && encode_planes > 1;
+  
+  for (p = 0; p < encode_planes; p++)
+    memset(dest[p], 0, bpl * y);
+  
+  for (line = 0; line < y; line++) {                 /* lines loop */
+    for (i = 0; i * 8 < x; i++) {                    /* dest bytes loop */
+      for (k = 0; k < 8 && i * 8 + k < x; k++) {     /* pixel loop */
+	prev = 0;
+	for (p = 0; p < encode_planes; p++) {        /* bit planes loop */
+	  /* calculate which bit in *src do we want */
+	  bitno = (msb - p) & 7;
+	  /* put this bit with its left neighbor right adjusted into bits */
+	  bits = (prev | *src) >> bitno;
+	  /* go to next *src byte, but keep old */
+	  if (bitno == 0)
+	    prev = *src++;
+	  /* make space for inserting new bit */
+	  dest[p][bpl * line + i] <<= 1;
+	  /* insert bit, if requested apply Gray encoding */
+	  dest[p][bpl * line + i] |= (bits ^ (use_graycode & (bits>>1))) & 1;
+	  /*
+	   * Theorem: Let b(n),...,b(1),b(0) be the digits of a
+	   * binary word and let g(n),...,g(1),g(0) be the digits of the
+	   * corresponding Gray code word, then g(i) = b(i) xor b(i+1).
+	   */
+	}
+	/* skip unused *src bytes */
+	for (;p < has_planes; p++)
+	  if (((has_planes - 1 - p) & 7) == 0)
+	    src++;
+      }
+    }
+    for (p = 0; p < encode_planes; p++)              /* right padding loop */
+      dest[p][bpl * (line + 1) - 1] <<= 8 - k;
+  }
+  
+  return;
+}
+
+/* 
+ * Merge the separate bit planes decoded by the JBIG decoder into an
+ * integer pixel field. This is essentially the counterpart to
+ * 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 char buf[BUFLEN];
+  unsigned char *bp = buf;
+  unsigned char **src;
+  unsigned long x, y;
+  unsigned v;
+
+  /* sanity check */
+  use_graycode = use_graycode != 0;
+  
+  x = jbg_dec_getwidth(s);
+  y = jbg_dec_getheight(s);
+  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 */
+
+  if (index[s->order & 7][LAYER] == 0)
+    if (s->ii[0] < 1)
+      return;
+    else
+      src = s->lhp[(s->ii[0] - 1) & 1];
+  else
+    src = s->lhp[s->d & 1];
+  
+  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 = (v << 1) |
+	      (((src[p+q][bpl * line + i] >> (7 - k)) & 1) ^
+	       (use_graycode & v));
+	  *bp++ = v;
+	  if (bp - buf == BUFLEN) {
+	    data_out(buf, BUFLEN, file);
+	    bp = buf;
+	  }
+	}
+      }
+    }
+  }
+  
+  if (bp - buf > 0)
+    data_out(buf, bp - buf, file);
+  
+  return;
+}
diff --git a/converter/other/jbig/jbig.doc b/converter/other/jbig/jbig.doc
new file mode 100644
index 00000000..10eeda80
--- /dev/null
+++ b/converter/other/jbig/jbig.doc
@@ -0,0 +1,721 @@
+
+Using the JBIG-KIT library
+--------------------------
+
+Markus Kuhn -- 1998-04-10
+
+
+This text explains how to include the functions provided by the
+JBIG-KIT portable image compression library into your application
+software.
+
+
+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/>.
+
+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.
+
+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:
+
+
+          +------------------------------------------------+
+          |                                                |
+          |  20-byte header (with image size, #planes,     |
+          |  #layers, stripe size, first layer, options,   |
+          |  SDE ordering, ...)                            |
+          |                                                |
+          +------------------------------------------------+
+          |                                                |
+          |           optional 1728-byte table             |
+          |                                                |
+          +------------------------------------------------+
+          |                                                |
+          |              stripe data entity                |
+          |                                                |
+          +------------------------------------------------+
+          |                                                |
+          |       optional floating marker segments        |
+          |                                                |
+          +------------------------------------------------+
+          |                                                |
+          |              stripe data entity                |
+          |                                                |
+          +------------------------------------------------+
+            ...
+          +------------------------------------------------+
+          |                                                |
+          |              stripe data entity                |
+          |                                                |
+          +------------------------------------------------+
+
+
+One BIE can contain all resolution layers of an image, but it is also
+possible to store various resolution layers in several BIEs. The BIE
+header contains the number of the first and the last resolution layer
+stored in this BIE, as well as the size of the highest resolution
+layer stored in this BIE. Progressive coding is deactivated by simply
+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.
+
+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:
+
+  - 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
+    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.
+
+  - a checksum that ensures image integrity
+
+  - encryption and signature mechanisms
+
+  - many things more
+
+Raw BIE data streams alone are consequently no 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.
+
+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.
+
+
+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.
+
+For example the 23x5 pixels large single plane image:
+
+   .XXXXX..XXX...X...XXX..
+   .....X..X..X..X..X.....
+   .....X..XXX...X..X.XXX.
+   .X...X..X..X..X..X...X.
+   ..XXX...XXX...X...XXX..
+
+is represented by the 15 bytes
+
+   01111100 11100010 00111000
+   00000100 10010010 01000000
+   00000100 11100010 01011100
+   01000100 10010010 01000100
+   00111000 11100010 00111000
+
+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.
+
+As JBIG can also handle images with several bit planes, the JBIG-KIT
+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
+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.
+
+For greyscale 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
+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:
+
+                           normal
+              number    binary code     Gray code
+            ---------------------------------------
+                0           000            000
+                1           001            001
+                2           010            011
+                3           011            010
+                4           100            110
+                5           101            111
+                6           110            101
+                7           111            100
+
+The form of Gray code shown above has the property that the second
+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
+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
+pixel intensity in several bit planes, it always makes sense to store
+the most significant (leftmost) bit in plane 0, which is transmitted
+first. This way, a decoder could increase the precision of the
+displayed pixel intensities while data is still being received and the
+basic structure of the image will become visible as early as possible
+during the transmission.
+
+
+2.2  A simple compression application
+
+In order to use JBIG-KIT 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
+directory and put the line
+
+  #include "jbig.h"
+
+into your source code.
+
+The library interface follows the concepts of object-oriented
+programming. You have to declare a variable (object)
+
+  struct jbg_enc_state se;
+
+which contains the current status of an encoder. Then you initialize
+the encoder by calling the constructor function
+
+  void jbg_enc_init(struct jbg_enc_state *s, unsigned long x, unsigned long y,
+                    int pl, unsigned char **p,
+                    void (*data_out)(unsigned char *start, size_t len,
+                                     void *file),
+                    void *file);
+
+The parameters have the following meaning:
+
+  s             A pointer to the jbg_enc_state structure which you want
+                to initialize.
+
+  x             The width of your image.
+
+  y             The height of your image.
+
+  pl            the number of bitmap planes you want to encode.
+
+  p             A pointer to an array of pl pointers, where each is again
+                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.
+
+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
+
+  void jbg_enc_free(struct jbg_enc_state *s);
+
+will release any 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 sample JBIG encoding application */
+
+#include <stdio.h>
+#include "jbig.h"
+
+void output_bie(unsigned char *start, size_t len, void *file)
+{
+  fwrite(start, 1, len, (FILE *) file);
+  
+  return;
+}
+
+int main()
+{
+  unsigned char bitmap[15] = {
+    /* 23 x 5 pixels, "JBIG" */
+    0x7c, 0xe2, 0x38, 0x04, 0x92, 0x40, 0x04, 0xe2,
+    0x5c, 0x44, 0x92, 0x44, 0x38, 0xe2, 0x38
+  };
+  unsigned char *bitmaps[1] = { bitmap };
+  struct jbg_enc_state se;
+  
+  jbg_enc_init(&se, 23, 5, 1, bitmaps, 
+	       output_bie, stdout);              /* initialize encoder */
+  jbg_enc_out(&se);                                    /* encode image */
+  jbg_enc_free(&se);                    /* release allocated resources */
+  
+  return 0;
+}
+---------------------------------------------------------------------------
+
+This software produces a 42 byte long BIE. (JBIG is not very good at
+compressing extremely small images like in this example, because the
+arithmetic encoder requires some startup data in order to generate
+reasonable statistics which influence the compression process and
+because there is some header overhead.)
+
+
+2.3  More about compression
+
+If jbg_enc_out() is called directly after jbg_enc_init(), the
+following default values are used for various compression parameters:
+
+  - Only one single resolution layer is used, i.e. no progressive
+    mode.
+
+  - 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
+    are used in order to stay within the suggested minimum parameter
+    support range specified in annex A of the standard).
+
+  - All optional parts of the JBIG algorithm are activated (TPBON,
+    TPDON and DPON).
+
+  - The default resolution reduction table and the default deterministic
+    prediction tables are used
+
+  - The maximal vertical offset of the adaptive template pixel is 0
+    and the maximal horizontal offset is 8 (mx = 8, my = 0).
+
+In order to change any of these default parameters, additional
+functions have to be called between jbg_enc_init() and jbg_enc_out().
+
+In order to activate progressive encoding, it is possible to specify
+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
+
+  jbg_enc_layers(&se, 2);
+
+will cause three resolution layers with 75, 150 and 300 dots per inch.
+
+If the application does not know what typical resolutions are used and
+simply wants to ensure that the lowest resolution layer will fit into
+a given maximal window size, then as an alternative, a call to
+
+  int jbg_enc_lrlmax(struct jbg_enc_state *s, unsigned long mwidth,
+                     unsigned long mheight);
+
+will cause the library to automatically determine the suitable number
+of resolutions so that the lowest resolution layer 0 will not be
+larger than mwidth x mheight pixels. E.g. if one wants to ensure that
+systems with a 640 x 480 pixel large screen can decode the required
+resolution directly, then call
+
+  jbg_enc_lrlmax(&se, 640, 480);
+
+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
+
+  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
+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
+
+  jbg_enc_lrange(&se, 0, 0);
+
+and before writing the second BIE with jbg_enc_out(), one calls
+
+  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
+the input image. This way, jbg_enc_lrange(&se, -1, -1) can be used to
+query the layer of the full image.
+
+A number of other more exotic options of the JBIG algorithm can be
+modified by calling
+
+  void jbg_enc_options(struct jbg_enc_state *s, int order, int options,
+                       long l0, int mx, int my);
+
+before calling jbg_enc_out().
+
+The order parameter can be a combination of the bits JBG_HITOLO,
+JBG_SEQ, JBG_ILEAVE and JBG_SMID and it determines in which order
+the SDEs are stored in the BIE. The bits have the following meaning:
+
+  JBG_HITOLO   Usually, the lower resolution layers are stored before
+               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
+               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
+               normally not use it.
+
+  JBG_SEQ      Usually, at first all stripes of one resolution layer
+               are written to the BIE and then all stripes of the next
+               layer, and so on. When the SEQ bit is set however, then
+               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.
+
+  JBG_SMID     In case there exist several bit planes, then the order of
+               the stripes is determined by 3 loops over all stripes,
+               all planes and all layers. When SMID is set, the loop
+               over all stripes is the middle loop.
+
+  JBG_ILEAVE   If this bit is set, then at first all layers of one
+               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
+JBG_SEQ, JBIG_ILEAVE and JBG_SMID influence the ordering of the loops
+over all stripes, planes and layers:
+
+
+                                                 Loops:
+    JBG_SEQ   JBG_ILEAVE   JBG_SMID   |  Outer   Middle    Inner
+  ------------------------------------+---------------------------
+       0           0           0      |    p        d        s
+       0           1           0      |    d        p        s
+       0           1           1      |    d        s        p
+       1           0           0      |    s        p        d
+       1           0           1      |    p        s        d
+       1           1           0      |    s        d        p
+
+                                       p: plane, s: stripe, d: layer
+
+
+By default, the order combination JBG_ILEAVE | JBG_SMID is used.
+
+The options value can contain the following bits, which activate
+some of the optional algorithms defined by JBIG:
+
+  JBG_LRLTWO     Normally, in the lowest resolution layer, pixels
+                 from three lines around the next pixel are used
+                 in order to determine the context in which the next
+                 pixel is encoded. Some people in the JBIG committee
+                 seem to have argued that using only 2 lines will
+                 make software implementations a little bit faster,
+                 however others have argued that using only two lines
+                 will decrease compression efficiency by around 5%.
+                 As you might expect from a committee, now both
+                 alternatives are allowed and if JBG_LRLTWO is set,
+                 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
+                 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.
+                 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
+                 option.
+
+  JBG_TPBON      Like JBG_TPDON this activates the "typical prediction"
+                 algorithm in the lowest resolution layer. Also activated
+                 by default.
+
+  JBG_DPON       This bit activates for the differential resolution
+                 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
+                 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.
+
+  JBG_DELAY_AT   Use a slightly less efficient algorithm to determine
+                 when an adaptive template change is necessary. With
+                 this bit set, the encoder output is compatible to the
+                 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
+                 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,
+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.
+
+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
+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
+function
+
+  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);
+
+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
+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
+which each contains up to eight bits, the total length of the input
+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
+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
+encode_planes = 8. If use_graycode is zero, then the binary code of
+the pixel integer values will be used instead of the Gray code. Plane
+0 contains always the most significant bit.
+
+
+3  Decompressing an image
+
+Like with the compression functions, if you want to use the JBIG-KIT
+library, you have to put the line
+
+  #include "jbig.h"
+
+into your source code and link your executable with libjbig.a.
+
+The state of a JBIG decoder is stored completely in a struct and you
+will have to define a variable like
+
+  struct jbg_dec_state sd;
+
+which is initialized by a call to
+
+  void jbg_dec_init(struct jbg_dec_state *s);
+
+After this, you can directly start to pass data from the BIE to the decoder
+by calling the function
+
+  int jbg_dec_in(struct jbg_dec_state *s, unsigned char *data, size_t len,
+                 size_t *cnt);
+
+The pointer data points to the first byte of a data block with length
+len, which contains bytes from a BIE. It is not necessary to pass a
+whole BIE at once to jbg_dec_in(), it can arrive fragmented in any way
+by calling jbg_dec_in() several times. It is also possible to send
+several BIEs concatenated to jbg_dec_in(), however these then have to
+fit together. If you send several BIEs to the decoder, the lowest
+resolution layer in each following BIE has to be the highest
+resolution layer in the previous BIE plus one and the image sizes and
+number of planes also have to fit together, otherwise jbg_dec_in()
+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.
+
+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);
+  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);
+
+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
+stored as described in section 2.1. The function jbg_dec_getsize()
+calculates the number of bytes which one bitmap requires.
+
+The function
+
+  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);
+
+allows you to merge the bitplanes 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);
+
+determines how long the data array delivered by jbg_dec_merge_planes()
+is going to be.
+
+Before calling jbg_dec_in() the first time, it is possible to specify with
+a call to
+
+  void jbg_dec_maxsize(struct jbg_dec_state *s, unsigned long xmax,
+                       unsigned long ymax);
+
+an abort criterion for progressively encoded images. For instance if an
+application will display a whole document on a screen which is 1024 x
+768 pixels large, then this application should call
+
+  jbg_dec_maxsize(&sd, 1024, 768);
+
+before the decoding process starts. If the image has been encoded in
+progressive mode (i.e. with several resolution layers), then the
+decoder will stop with a return value JBG_EOK_INTR after the largest
+resolution layer that is still smaller than 1024 x 768. However this
+is no guarantee that the image which can then be read out using
+jbg_dec_getimage(), etc. is really not larger than the specified
+maximal size. The application will have to check the size of the
+image, because the decoder does not automatically apply a resolution
+reduction if no suitable resolution layer is available in the BIE.
+
+If jbg_dec_in() returned JBG_EOK_INTR or JBG_EOK, then it is possible
+to continue calling jbg_dec_in() with the remaining data in order to
+either decode the remaining resolution layers of the current BIE or in
+order to add another BIE with additional resolution layers. In both
+cases, after jbg_dec_in() returned JBG_EOK_INTR or JBG_EOK, *cnt is
+probably not equal to len and the remainder of the data block which
+has not yet been processed by the decoder has to be delivered to
+jbg_dec_in() again.
+
+If any other return value than JBG_EOK, JBG_EOK_INTR or JBG_EAGAIN
+has been returned by jbg_dec_in(), then an error has occurred and
+
+  void jbg_dec_free(struct jbg_dec_state *s);
+
+should be called in order to release any allocated memory. The
+destructor jbg_dec_free() should of course also be called, once the
+decoded bitmap returned by jbg_dec_getimage() is no longer required
+and the memory can be released.
+
+The function
+
+  const char *jbg_strerror(int errnum, int language);
+
+returns a pointer to a short single line test message which 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
+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.
+
+  - HITOLO and SEQ bits must not be set in the order value.
+
+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,
+  Erlangen, July 1995. (German, 62 pages)
+  <http://www.cl.cam.ac.uk/~mgk25/kuhn-sta.pdf>
+
+Please quote the above if you use JBIG-KIT in your research project.
+
+*** Happy compressing ***
+
+[end]
diff --git a/converter/other/jbig/jbig.h b/converter/other/jbig/jbig.h
new file mode 100644
index 00000000..dd9a76f3
--- /dev/null
+++ b/converter/other/jbig/jbig.h
@@ -0,0 +1,267 @@
+/*
+ *  Header file for the portable free JBIG compression library
+ *
+ *  Markus Kuhn -- mkuhn@acm.org
+ *
+ *  $Id: jbig.h,v 1.9 1999-11-16 15:58:45+00 mgk25 Rel $
+ */
+
+#ifndef JBG_H
+#define JBG_H
+
+#include <stddef.h>
+
+/*
+ * JBIG-KIT version number
+ */
+
+#define JBG_VERSION    "1.1"
+
+/*
+ * Buffer block for SDEs which are temporarily stored by encoder
+ */
+
+#define JBG_BUFSIZE 4000
+
+struct jbg_buf {
+  unsigned char d[JBG_BUFSIZE];              /* one block of a buffer list */
+  int len;                             /* length of the data in this block */
+  struct jbg_buf *next;                           /* pointer to next block */
+  struct jbg_buf *previous;                   /* pointer to previous block *
+					       * (unused in freelist)      */
+  struct jbg_buf *last;     /* only used in list head: final block of list */
+  struct jbg_buf **free_list;   /* pointer to pointer to head of free list */
+};
+
+/*
+ * Maximum number of allowed ATMOVEs per stripe
+ */
+
+#define JBG_ATMOVES_MAX  64
+
+/*
+ * Option and order flags
+ */
+
+#define JBG_HITOLO     0x08
+#define JBG_SEQ        0x04
+#define JBG_ILEAVE     0x02
+#define JBG_SMID       0x01
+
+#define JBG_LRLTWO     0x40
+#define JBG_VLENGTH    0x20
+#define JBG_TPDON      0x10
+#define JBG_TPBON      0x08
+#define JBG_DPON       0x04
+#define JBG_DPPRIV     0x02
+#define JBG_DPLAST     0x01
+
+#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.*/
+
+
+/*
+ * 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
+
+ 
+/*
+ * Status of a JBIG encoder
+ */
+
+struct jbg_enc_state {
+  int d;                            /* resolution layer of the input image */
+  unsigned long xd, yd;    /* size of the input image (resolution layer d) */
+  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 */
+  unsigned long l0;                /* number of lines per stripe at lowest *
+                                    * resolution layer 0                   */
+  unsigned long stripes;    /* number of stripes required  (determ. by l0) */
+  unsigned char **lhp[2];    /* pointers to lower/higher resolution images */
+  int *highres;                 /* index [plane] of highres image in lhp[] */
+  int order;                                    /* SDE ordering parameters */
+  int options;                                      /* encoding parameters */
+  unsigned mx, my;                           /* maximum ATMOVE window size */
+  int *tx;       /* array [plane] with x-offset of adaptive template pixel */
+  char *dppriv;         /* optional private deterministic prediction table */
+  char *res_tab;           /* table for the resolution reduction algorithm */
+  struct jbg_buf ****sde;      /* array [stripe][layer][plane] pointers to *
+				* buffers for stored SDEs                  */
+  struct jbg_arenc_state *s;  /* array [planes] for arithm. encoder status */
+  struct jbg_buf *free_list; /* list of currently unused SDE block buffers */
+  void (*data_out)(unsigned char *start, size_t len, void *file);
+                                                    /* data write callback */
+  void *file;                            /* parameter passed to data_out() */
+  char *tp;    /* buffer for temp. values used by diff. typical prediction */
+};
+
+
+/*
+ * Status of a JBIG decoder
+ */
+
+struct jbg_dec_state {
+  /* data from BIH */
+  int d;                             /* resolution layer of the full image */
+  int dl;                            /* first resolution layer in this BIE */
+  unsigned long xd, yd;     /* size of the full image (resolution layer d) */
+  int planes;                         /* number of different bitmap planes */
+  unsigned long l0;                /* number of lines per stripe at lowest *
+				    * resolution layer 0                   */
+  unsigned long stripes;    /* number of stripes required  (determ. by l0) */
+  int order;                                    /* SDE ordering parameters */
+  int options;                                      /* encoding parameters */
+  int mx, my;                                /* maximum ATMOVE window size */
+  char *dppriv;         /* optional private deterministic prediction table */
+
+  /* loop variables */
+  unsigned long ii[3];  /* current stripe, layer, plane (outer loop first) */
+
+  /*
+   * Pointers to array [planes] of lower/higher resolution images.
+   * lhp[d & 1] contains image of layer d. 
+   */
+  unsigned char **lhp[2];
+
+  /* status information */
+  int **tx, **ty;   /* array [plane][layer-dl] with x,y-offset of AT pixel */
+  struct jbg_ardec_state **s;    /* array [plane][layer-dl] for arithmetic *
+				  * decoder status */
+  int **reset;     /* array [plane][layer-dl] remembers if previous stripe *
+		    * in that plane/resolution ended with SDRST.           */
+  unsigned long bie_len;                    /* number of bytes read so far */
+  unsigned char buffer[20]; /* used to store BIH or marker segments fragm. */
+  int buf_len;                                /* number of bytes in buffer */
+  unsigned long comment_skip;      /* remaining bytes of a COMMENT segment */
+  unsigned long x;              /* x position of next pixel in current SDE */
+  unsigned long i; /* line in current SDE (first line of each stripe is 0) */ 
+  int at_moves;                /* number of AT moves in the current stripe */
+  unsigned long at_line[JBG_ATMOVES_MAX];           /* lines at which an   *
+					             * AT move will happen */
+  int at_tx[JBG_ATMOVES_MAX], at_ty[JBG_ATMOVES_MAX]; /* ATMOVE offsets in *
+						       * current stripe    */
+  unsigned long line_h1, line_h2, line_h3;     /* variables of decode_pscd */
+  unsigned long line_l1, line_l2, line_l3;
+  int pseudo;         /* flag for TPBON/TPDON:  next pixel is pseudo pixel */
+  int **lntp;        /* flag [plane][layer-dl] for TP: line is not typical */
+
+  unsigned long xmax, ymax;         /* if possible abort before image gets *
+				     * larger than this size */
+  int dmax;                                      /* abort after this layer */
+};
+
+
+/* some macros (too trivial for a function) */
+
+#define jbg_dec_getplanes(s)     ((s)->planes)
+
+
+/* function prototypes */
+
+void jbg_enc_init(struct jbg_enc_state *s, unsigned long x, unsigned long y,
+		  int planes, unsigned char **p,
+		  void (*data_out)(unsigned char *start, size_t len,
+				   void *file),
+		  void *file);
+int jbg_enc_lrlmax(struct jbg_enc_state *s, unsigned long mwidth,
+		   unsigned long mheight);
+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);
+void jbg_enc_out(struct jbg_enc_state *s);
+void jbg_enc_free(struct jbg_enc_state *s);
+
+void jbg_dec_init(struct jbg_dec_state *s);
+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 char *jbg_dec_getimage(const struct jbg_dec_state *s, int plane);
+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);
+void jbg_dec_free(struct jbg_dec_state *s);
+
+const char *jbg_strerror(int errnum, int language);
+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);
+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);
+
+#endif /* JBG_H */
diff --git a/converter/other/jbig/jbig_tab.c b/converter/other/jbig/jbig_tab.c
new file mode 100644
index 00000000..55183503
--- /dev/null
+++ b/converter/other/jbig/jbig_tab.c
@@ -0,0 +1,428 @@
+/*
+ *  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 733ba227..7a6e95c1 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));
+                 fnin, jbg_strerror(result, JBG_EN));
     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/jpeg2000/Makefile b/converter/other/jpeg2000/Makefile
index 009232d7..7b008906 100644
--- a/converter/other/jpeg2000/Makefile
+++ b/converter/other/jpeg2000/Makefile
@@ -40,17 +40,16 @@ endif
 
 ifneq ($(JASPERHDR_DIR),NONE)
   ifneq ($(JASPERLIB_USE),NONE)
-    PORTBINARIES = pamtojpeg2k jpeg2ktopam
+    BINARIES = 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 directory.
+  # be relative to the current relative to the current directory.
   MERGE_OBJECTS += $(JASPERLIB)
 endif
 MERGEBINARIES = $(BINARIES)
@@ -60,10 +59,12 @@ all: $(BINARIES)
 
 include $(SRCDIR)/common.mk
 
-LIBOPTS = $(shell $(LIBOPT) $(JASPERLIB_USE))
+LIBOPTS = $(shell $(LIBOPT) $(JASPERLIB_USE) $(NETPBMLIB))
 
-$(BINARIES): %: %.o $(JASPERLIB_DEP) $(LIBOPT)
-$(BINARIES): LDFLAGS_TARGET = $(LIBOPTS) $(JASPERDEPLIBS)
+$(BINARIES): %: %.o $(JASPERLIB_DEP) $(NETPBMLIB) $(LIBOPT)
+	$(LD) -o $@ $< \
+	  $(LIBOPTS) $(JASPERDEPLIBS) $(MATHLIB) $(RPATH) \
+	  $(LDFLAGS) $(LDLIBS) $(LADD)
 
 $(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 858c0fa4..49479774 100644
--- a/converter/other/jpeg2000/jpeg2ktopam.c
+++ b/converter/other/jpeg2000/jpeg2ktopam.c
@@ -13,14 +13,13 @@
 #define _XOPEN_SOURCE 600
 #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};
diff --git a/converter/other/jpeg2000/libjasper/base/jas_image.c b/converter/other/jpeg2000/libjasper/base/jas_image.c
index 903b45c6..8d62b48d 100644
--- a/converter/other/jpeg2000/libjasper/base/jas_image.c
+++ b/converter/other/jpeg2000/libjasper/base/jas_image.c
@@ -623,7 +623,7 @@ int jas_image_getfmt(jas_stream_t *in)
 	int found;
 	int i;
 
-	/* Check for data in each of the formats we know. */
+	/* Check for data in each of the supported formats. */
 	found = 0;
 	for (i = 0, fmtinfo = jas_image_fmtinfos; i < jas_image_numfmts; ++i,
 	  ++fmtinfo) {
diff --git a/converter/other/jpeg2000/libjasper/include/jasper/jas_image.h b/converter/other/jpeg2000/libjasper/include/jasper/jas_image.h
index 6e914efd..558f4368 100644
--- a/converter/other/jpeg2000/libjasper/include/jasper/jas_image.h
+++ b/converter/other/jpeg2000/libjasper/include/jasper/jas_image.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 we can handle. */
+/* The maximum number of image data formats supported. */
 
 /* Image format-dependent operations. */
 
@@ -530,57 +530,57 @@ int jas_image_getfmt(jas_stream_t *in);
 * Image format-dependent operations.
 \******************************************************************************/
 
-#if !defined(EXCLUDE_JPG_CAPABILITY)
-/* Format-dependent operations for JPG capability. */
+#if !defined(EXCLUDE_JPG_SUPPORT)
+/* Format-dependent operations for JPG support. */
 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_CAPABILITY)
-/* Format-dependent operations for MIF capability. */
+#if !defined(EXCLUDE_MIF_SUPPORT)
+/* Format-dependent operations for MIF support. */
 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_CAPABILITY)
-/* Format-dependent operations for PNM capability. */
+#if !defined(EXCLUDE_PNM_SUPPORT)
+/* Format-dependent operations for PNM support. */
 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_CAPABILITY)
-/* Format-dependent operations for Sun Rasterfile capability. */
+#if !defined(EXCLUDE_RAS_SUPPORT)
+/* Format-dependent operations for Sun Rasterfile support. */
 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_CAPABILITY)
-/* Format-dependent operations for BMP capability. */
+#if !defined(EXCLUDE_BMP_SUPPORT)
+/* Format-dependent operations for BMP support. */
 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_CAPABILITY)
-/* Format-dependent operations for JP2 capability. */
+#if !defined(EXCLUDE_JP2_SUPPORT)
+/* Format-dependent operations for JP2 support. */
 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_CAPABILITY)
-/* Format-dependent operations for JPEG-2000 code stream capability. */
+#if !defined(EXCLUDE_JPC_SUPPORT)
+/* Format-dependent operations for JPEG-2000 code stream support. */
 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_CAPABILITY)
-/* Format-dependent operations for PGX capability. */
+#if !defined(EXCLUDE_PGX_SUPPORT)
+/* Format-dependent operations for PGX support. */
 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/jp2/jp2_dec.c b/converter/other/jpeg2000/libjasper/jp2/jp2_dec.c
index 91ce6c51..aaebf411 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");
 	}
 
-	/* Can we handle the compression type? */
+	/* Is the compression type supported? */
 	if (dec->ihdr->data.ihdr.comptype != JP2_IHDR_COMPTYPE) {
-		jas_eprintf("error: not capable of this compression type\n");
+		jas_eprintf("error: unsupported compression type\n");
 		goto error;
 	}
 
diff --git a/converter/other/jpeg2000/libjasper/jpc/jpc_cs.c b/converter/other/jpeg2000/libjasper/jpc/jpc_cs.c
index 559f36cf..ffe6aab5 100644
--- a/converter/other/jpeg2000/libjasper/jpc/jpc_cs.c
+++ b/converter/other/jpeg2000/libjasper/jpc/jpc_cs.c
@@ -1461,6 +1461,8 @@ static int jpc_unk_getparms(jpc_ms_t *ms, jpc_cstate_t *cstate, jas_stream_t *in
 
 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;
 }
 
diff --git a/converter/other/jpeg2000/libjasper/jpc/jpc_enc.c b/converter/other/jpeg2000/libjasper/jpc/jpc_enc.c
index d17e9aa3..b52dcc27 100644
--- a/converter/other/jpeg2000/libjasper/jpc/jpc_enc.c
+++ b/converter/other/jpeg2000/libjasper/jpc/jpc_enc.c
@@ -346,7 +346,7 @@ static jpc_enc_cp_t *cp_create(char *optstr, jas_image_t *image)
         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");
+            fprintf(stderr, "unsupported image type\n");
             goto error;
         }
         /* Note: We ought to be calculating the LCMs here.  Fix some day. */
diff --git a/converter/other/jpeg2000/libjasper/jpc/jpc_qmfb.c b/converter/other/jpeg2000/libjasper/jpc/jpc_qmfb.c
index 80bc5aa5..1d41d5c5 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 valid for this
-		  transform. */
+		/* The reversible integer-to-integer mode is not supported
+		  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 valid
-           for this transform. */
+		/* The reversible integer-to-integer mode is not supported
+		  for this transform. */
 		abort();
 	}
 }
diff --git a/converter/other/jpeg2000/pamtojpeg2k.c b/converter/other/jpeg2000/pamtojpeg2k.c
index 349018e1..15ea0f31 100644
--- a/converter/other/jpeg2000/pamtojpeg2k.c
+++ b/converter/other/jpeg2000/pamtojpeg2k.c
@@ -13,14 +13,13 @@
 #define _XOPEN_SOURCE 600
 #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"
 
 
diff --git a/converter/other/jpegtopnm.c b/converter/other/jpegtopnm.c
index ab3b18e5..f09cd04f 100644
--- a/converter/other/jpegtopnm.c
+++ b/converter/other/jpegtopnm.c
@@ -652,20 +652,19 @@ 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.
 -----------------------------------------------------------------------------*/
-    bool const wantTagTrace = false;
-    exif_ImageInfo imageInfo;
+    ImageInfo_t imageInfo;
     const char * error;
 
     assert(marker.data_length >= 6);
 
-    exif_parse(marker.data+6, marker.data_length-6, 
-               &imageInfo, wantTagTrace, &error);
+    process_EXIF(marker.data+6, marker.data_length-6, 
+                 &imageInfo, FALSE, &error);
 
     if (error) {
         pm_message("EXIF header is invalid.  %s", error);
         pm_strfree(error);
     } else
-        exif_showImageInfo(&imageInfo, stderr);
+        ShowImageInfo(&imageInfo);
 }
 
 
@@ -701,7 +700,8 @@ 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/pamtosvg/Makefile b/converter/other/pamtosvg/Makefile
index 83f150d0..8b033020 100644
--- a/converter/other/pamtosvg/Makefile
+++ b/converter/other/pamtosvg/Makefile
@@ -7,13 +7,26 @@ VPATH=.:$(SRCDIR)/$(SUBDIR)
 
 include $(BUILDDIR)/config.mk
 
-PORTBINARIES = pamtosvg
+BINARIES = pamtosvg
 
-BINARIES = $(PORTBINARIES)
-
-MERGEBINARIES = $(BINARIES)
+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 \
 
-ADDL_OBJECTS = \
+MERGE_OBJECTS = \
+	pamtosvg.o2 \
 	output-svg.o \
 	fit.o \
 	spline.o \
@@ -28,12 +41,15 @@ ADDL_OBJECTS = \
 	exception.o \
 	image-proc.o \
 
-OBJECTS = pamtosvg.o $(ADDL_OBJECTS)
+OBJECTS = $(PAMTOSVG_OBJECTS)
 
-MERGE_OBJECTS = pamtosvg.o2 $(ADDL_OBJECTS)
+MERGEBINARIES = $(BINARIES)
 
 all: $(BINARIES)
 
 include $(SRCDIR)/common.mk
 
-pamtosvg: $(ADDL_OBJECTS)
+pamtosvg: $(PAMTOSVG_OBJECTS) $(NETPBMLIB) $(LIBOPT)
+	$(LD) -o $@ $(PAMTOSVG_OBJECTS) \
+	  $(shell $(LIBOPT) $(NETPBMLIB)) \
+	  $(MATHLIB) $(LDFLAGS) $(LDLIBS) $(RPATH) $(LADD)
diff --git a/converter/other/pamtosvg/bitmap.h b/converter/other/pamtosvg/bitmap.h
index b979e0c0..7334f138 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 allows internal datum 
+/* We have to export functions that supports 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 d025ee1e..b044b547 100644
--- a/converter/other/pamtosvg/image-proc.c
+++ b/converter/other/pamtosvg/image-proc.c
@@ -330,7 +330,7 @@ binarize(bitmap_type *bitmap)
     }
     else
     {
-	    WARNING1("binarize: don't know how to interpret %u-plane images", spp);
+	    WARNING1("binarize: %u-plane images are not supported", spp);
     }
 }
 
diff --git a/converter/other/pamtosvg/thin-image.c b/converter/other/pamtosvg/thin-image.c
index 364f67cc..86d1037c 100644
--- a/converter/other/pamtosvg/thin-image.c
+++ b/converter/other/pamtosvg/thin-image.c
@@ -189,7 +189,7 @@ thin_image(bitmap_type *image, bool bgSpec, pixel bg,
 
 	default:
 	{
-	  LOG1 ("thin_image: Don't know how to interpret %u-plane images", spp);
+	  LOG1 ("thin_image: %u-plane images are not supported", spp);
 	  at_exception_fatal(exp, "thin_image: wrong plane images are passed");
 	  goto cleanup;
 	}
diff --git a/converter/other/pamtotiff.c b/converter/other/pamtotiff.c
index f2cc0e2b..0206678d 100644
--- a/converter/other/pamtotiff.c
+++ b/converter/other/pamtotiff.c
@@ -53,19 +53,16 @@
 #define COMPRESSION_ADOBE_DEFLATE 8
 #endif
 
-typedef struct {
+struct sizeset {
     bool b1, b2, b4, b8;
-} SizeSet;
+};
 
-typedef enum { TMPFILE, DIRECT_CREATE, DIRECT_APPEND } WriteMethod;
 
-typedef enum { MUST_EXIST, MAY_CREATE } CreatePolicy;
-
-typedef struct {
+struct cmdlineInfo {
     /* All the information the user supplied in the command line,
        in a form easy for the program to use.
     */
-    const char * inputFileName;
+    const char *input_filespec;  /* Filespecs of input files */
     int compression;
         /* COMPRESSION Tiff tag value, that corresponds to the compression
            option the user specified, or -1 if he didn't specify any.
@@ -82,14 +79,13 @@ typedef struct {
     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 */
-    SizeSet indexsizeAllowed;
+    struct sizeset indexsizeAllowed;
     /* Which bit widths are allowable in a raster of palette indices */
     unsigned int verbose;
-    WriteMethod writeMethod;  /* Output mode */
-    const char * output; /* -output option value.  NULL if none. */
+    unsigned int append;
     float resolution;  /* X and Y resolution */
     struct optNameValue * taglist;
-} CmdlineInfo;
+};
 
 
 
@@ -100,7 +96,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 {
@@ -135,9 +131,9 @@ validateTagList(struct optNameValue const taglist[]) {
 
 
 static void
-parseCommandLine(int                 argc,
-                 const char ** const argv,
-                 CmdlineInfo * const cmdlineP) {
+parseCommandLine(int                        argc,
+                 char **              const 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.
@@ -151,9 +147,8 @@ parseCommandLine(int                 argc,
     char * indexbits;
     char * resolutionunit;
 
-    unsigned int appendSpec, outputSpec, predictorSpec, rowsperstripSpec,
-                 xresolutionSpec, yresolutionSpec, indexbitsSpec,
-      resolutionunitSpec, tagSpec;
+    unsigned int predictorSpec, rowsperstripSpec, xresolutionSpec,
+        yresolutionSpec, indexbitsSpec, resolutionunitSpec, tagSpec;
 
     unsigned int option_def_index;
 
@@ -161,6 +156,7 @@ 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);
@@ -178,20 +174,17 @@ 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, "append",       OPT_FLAG,   NULL, &appendSpec,       0);
-    OPTENT3(0, "output",       OPT_STRING, &cmdlineP->output,
-            &outputSpec,       0);
-    OPTENT3(0, "predictor",    OPT_UINT,   &cmdlineP->predictor,
+    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, "indexbits",    OPT_STRING,   &indexbits, 
             &indexbitsSpec,    0);
     OPTENT3(0, "tag",          OPT_NAMELIST, &cmdlineP->taglist, &tagSpec, 0);
 
@@ -199,14 +192,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 */
 
-    pm_optParseOptions3(&argc, (char**)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 (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)
@@ -223,7 +216,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.");
@@ -232,9 +225,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");
@@ -245,17 +238,9 @@ 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;
@@ -333,13 +318,13 @@ parseCommandLine(int                 argc,
         cmdlineP->taglist[0].value = NULL;
     }
 
-    if (argc-1 == 0)
-        cmdlineP->inputFileName = "-";
+    if (argc-1 == 0) 
+        cmdlineP->input_filespec = "-";
     else if (argc-1 != 1)
         pm_error("Program takes zero or one argument (filename).  You "
                  "specified %d", argc-1);
     else
-        cmdlineP->inputFileName = argv[1];
+        cmdlineP->input_filespec = argv[1];
 }
 
 
@@ -361,9 +346,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).
@@ -378,7 +363,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) {
@@ -387,7 +372,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 {
@@ -463,7 +448,7 @@ fillRowOfWholeBytePixels(struct pam *    const pamP,
     unsigned int col;
     unsigned char * tP;
     unsigned int planes;
-
+    
     if (photometric == PHOTOMETRIC_RGB)
         planes = pamP->depth;
     else
@@ -480,18 +465,18 @@ fillRowOfWholeBytePixels(struct pam *    const pamP,
             /* 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
@@ -525,7 +510,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;
 
@@ -547,9 +532,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!  "
@@ -573,12 +558,12 @@ writeScanLines(struct pam *   const pamP,
 
 
 static void
-analyzeColorsInRgbInput(struct pam *   const pamP,
-                        CmdlineInfo    const cmdline,
-                        int            const maxcolors,
-                        tupletable *   const chvP,
-                        unsigned int * const colorsP,
-                        bool *         const grayscaleP) {
+analyzeColorsInRgbInput(struct pam *        const pamP,
+                        struct 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.
 -----------------------------------------------------------------------------*/
@@ -597,7 +582,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) {
@@ -630,15 +615,15 @@ analyzeColorsInRgbInput(struct pam *   const pamP,
 
 
 static void
-analyzeColors(struct pam *   const pamP,
-              CmdlineInfo    const cmdline,
-              int            const maxcolors,
-              tupletable *   const chvP,
-              unsigned int * const colorsP,
-              bool *         const grayscaleP) {
+analyzeColors(struct pam *        const pamP,
+              struct 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
@@ -667,13 +652,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,
-                  SizeSet          const indexsizeAllowed,
+                  struct sizeset   const indexsizeAllowed,
                   unsigned short * const samplesperpixelP,
                   unsigned short * const bitspersampleP,
                   unsigned short * const photometricP,
@@ -694,7 +679,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) {
@@ -708,7 +693,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 :
@@ -761,53 +746,18 @@ computeRasterParm(struct pam *     const pamP,
 
 
 
+static void
+validateSeekableOutputFile(int          const ofd,
+                           const char * const outFileName) {
 /*----------------------------------------------------------------------------
-  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.
------------------------------------------------------------------------------*/
-
-
+   Validate that the file attached to file descriptor 'ofd' is capable
+   of seeking.  If not, fail the program.
 
-static bool
-fileIsSeekable(int          const ofd,
-               const char * const outFileName) {
-/*----------------------------------------------------------------------------
-  The file represented by 'ofd' iscapable of seeking.
+   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.
 
-  As a side effect, we position the file to the beginning.
+   We leave the file positioned to the beginning.
 -----------------------------------------------------------------------------*/
     int rc;
 
@@ -821,160 +771,44 @@ fileIsSeekable(int          const ofd,
     */
     lseek(ofd, 1, SEEK_SET);
     rc = lseek(ofd, 0, SEEK_SET);
-
-    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
-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.
-
-  If the file doesn't already exist and 'createPolicy' is MayCreate,
-  create the file; otherwise fail the program.
-
-  Fail the program if the specified file is not seekable and readable.
-
-  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
-        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));
-    }
-
-    if (!fileIsSeekable(fd, outputFileName))
-        pm_error("Output file (%s) is not seekable.  "
-                 "lseek() returned errno %d (%s).  "
+            
+    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.",
-                 outputFileName, errno, strerror(errno));
-
-    *tifPP = TIFFFdOpen(fd, outputFileName, "a");
-    if (*tifPP == NULL)
-        pm_error("error opening file %s as TIFF file.  "
-                 "TIFFFdOpen() failed.", outputFileName);
-
-    *ofdP = fd;
+                 "a seekable file.", 
+                 outFileName, errno, strerror(errno));
 }
 
 
 
 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.
+createTiffGenerator(int          const ofd, 
+                    const char * const outFileName,
+                    bool         const append,
+                    TIFF **      const tifPP) {
 
-  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;
+    const char * option;
 
-    fd = pm_tmpfile_fd();
+    validateSeekableOutputFile(ofd, outFileName);
 
-    *tifPP = TIFFFdOpen(fd, "Internal Temporary File", "w");
+    if (append)
+        option = "a";
+    else
+        option = "w";
 
+    *tifPP = TIFFFdOpen(ofd, outFileName, option);
     if (*tifPP == NULL)
-        pm_error("error opening temporary file as TIFF file.  "
+        pm_error("error opening standard output 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);
-    }
-
-    fclose(tmpfileP);
 }
 
 
 
 static void
-destroyTiffGenerator(WriteMethod const writeMethod,
-                     TIFF *      const tifP,
-                     int         const ofd) {
+destroyTiffGenerator(TIFF * const tifP) {
 
     TIFFFlushData(tifP);
-
-    if (writeMethod == TMPFILE)
-        copyBufferToStdout(ofd);
-
     TIFFClose(tifP);
 }
 
@@ -991,11 +825,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) {
@@ -1008,7 +842,7 @@ createTiffColorMap(struct pam *       const pamP,
     }
     *tiffColorMapP = tiffColorMap;
 }
-
+        
 
 
 static void
@@ -1033,7 +867,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);
@@ -1044,7 +878,7 @@ setTagListFields(const struct optNameValue * const taglist,
 
 static void
 setTiffFields(TIFF *              const tifP,
-              CmdlineInfo         const cmdline,
+              struct cmdlineInfo  const cmdline,
               struct pam *        const pamP,
               unsigned short      const bitspersample,
               unsigned short      const photometric,
@@ -1106,7 +940,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.
@@ -1117,10 +951,10 @@ setTiffFields(TIFF *              const tifP,
 
 
 static void
-convertImage(FILE *       const ifP,
-             TIFF *       const tifP,
-             const char * const inputFileDescription,
-             CmdlineInfo  const cmdline) {
+convertImage(FILE *             const ifP,
+             TIFF *             const tifP,
+             const char *       const inputFileDescription,
+             struct cmdlineInfo const cmdline) {
 
     tupletable chv;
     tuplehash cht;
@@ -1132,7 +966,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;
@@ -1145,11 +979,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,
@@ -1174,7 +1008,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)
@@ -1183,41 +1017,63 @@ 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 !MSVCRT
+
+    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, const char *argv[]) {
-    CmdlineInfo cmdline;
+main(int argc, char *argv[]) {
+    struct cmdlineInfo cmdline;
     const char * inputFileDescription;
-    FILE * ifP;
-    TIFF * tifP;
-    int ofd;
+    FILE* ifP;
+    TIFF* tifP;
     int eof;
     unsigned int imageSeq;
-    
-    pm_proginit(&argc, argv);
 
-    parseCommandLine(argc, argv, &cmdline);
+    pnm_init(&argc, argv);
 
-    ifP = pm_openr_seekable(cmdline.inputFileName);
+    parseCommandLine(argc, argv, &cmdline);
+    
+    ifP = pm_openr_seekable(cmdline.input_filespec);
 
-    if (streq(cmdline.inputFileName, "-"))
+    if (streq(cmdline.input_filespec, "-"))
         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;
-    }
+    else 
+        inputFileDescription = cmdline.input_filespec;
+
+    if (cmdline.append)
+        validateReadableStdout();
+
+    createTiffGenerator(STDOUT_FILENO, "Standard Output", cmdline.append,
+                        &tifP);
 
     eof = FALSE;  /* initial assumption */
     imageSeq = 0;
@@ -1225,17 +1081,17 @@ main(int argc, const char *argv[]) {
     while (!eof) {
         bool success;
 
+        if (cmdline.verbose)
+            pm_message("Converting Image %u", imageSeq);
+
         pnm_nextimage(ifP, &eof);
 
         if (!eof) {
             if (imageSeq > 0)
-                validateReadableOutputFile(ofd);
-
-            if (cmdline.verbose)
-                pm_message("Converting Image %u", imageSeq);
+                validateReadableStdout();
 
             convertImage(ifP, tifP, inputFileDescription, cmdline);
-
+            
             success = TIFFWriteDirectory(tifP);
             if (!success)
                 pm_error("Unable to write TIFF image %u to file.  "
@@ -1244,10 +1100,8 @@ main(int argc, const char *argv[]) {
         }
     }
 
-    destroyTiffGenerator(cmdline.writeMethod, tifP, ofd);
+    destroyTiffGenerator(tifP);
     pm_close(ifP);
 
     return 0;
 }
-
-
diff --git a/converter/other/pnmtopalm/Makefile b/converter/other/pnmtopalm/Makefile
index edc7da64..65790002 100644
--- a/converter/other/pnmtopalm/Makefile
+++ b/converter/other/pnmtopalm/Makefile
@@ -8,10 +8,8 @@ VPATH=.:$(SRCDIR)/$(SUBDIR)
 include $(BUILDDIR)/config.mk
 
 BINARIES = palmtopnm pnmtopalm
-PORTBINARIES = $(BINARIES) gen_palm_colormap
 SCRIPTS =
-ADDL_OBJECTS = palmcolormap.o
-OBJECTS = $(BINARIES:%=%.o) $(ADDL_OBJECTS) gen_palm_colormap.o
+OBJECTS = $(BINARIES:%=%.o) palmcolormap.o
 MERGE_OBJECTS = $(BINARIES:%=%.o2) palmcolormap.o
 MERGEBINARIES = $(BINARIES)
 DATAFILES = palmcolor8.map palmgray1.map palmgray2.map palmgray4.map
@@ -20,7 +18,17 @@ all: $(BINARIES)
 
 include $(SRCDIR)/common.mk
 
-$(BINARIES): $(ADDL_OBJECTS)
+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 $(CFLAGS_ALL) -o $@ \
+	  $< palmcolormap.o \
+	  $(LIBOPTS) $(MATHLIB) $(LDFLAGS) $(LDLIBS) $(LADD)
+
 
 clean: cleanspecial
 .PHONY: cleanspecial
diff --git a/converter/other/pnmtopalm/gen_palm_colormap.c b/converter/other/pnmtopalm/gen_palm_colormap.c
index 0f3f8a5f..c7172c6b 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 "netpbm/ppm.h"
-#include "netpbm/pm_c_util.h"
+#include "ppm.h"
+#include "pm_c_util.h"
 
 #include "palm.h"
 
diff --git a/converter/other/pnmtosgi.c b/converter/other/pnmtosgi.c
index a8df5328..169125b3 100644
--- a/converter/other/pnmtosgi.c
+++ b/converter/other/pnmtosgi.c
@@ -31,6 +31,17 @@ typedef struct {
     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)
 
 
@@ -44,348 +55,301 @@ 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))
 
 
-static void
-putBigShort(short const s) {
+int
+main(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;
 
-    if (pm_writebigshort(stdout, s ) == -1)
-        pm_error( "write error" );
-}
+    pnm_init(&argc, argv);
 
+    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;
 
-static void
-putBigLong(long const l) {
+    if( argn != argc )
+        pm_usage(usage);
 
-    if (pm_writebiglong( stdout, l ) == -1)
-        pm_error( "write error" );
-}
+    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:
+            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);
 
-static void
-putShortAsByte(short const s) {
+    table = build_channels(ifp, cols, rows, newmaxval, format, bpc, channels);
+    pnm_freerow(pnmrow);
+    pm_close(ifp);
 
-    putByte((unsigned char)s);
-}
+    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);
 
+    exit(0);
+}
 
 
 static void
-writeTable(long *       const table,
-           unsigned int const tabsize) {
+write_table(long * table, int const tabsize)
+{
+    int i;
+    long offset;
 
-    unsigned int i;
-    unsigned long offset;
+#ifdef DEBUG
+    pm_message("writing table");
+#endif
 
     offset = HeaderSize + tabsize * 8;
-
-    for (i = 0; i < tabsize; ++i) {
-        putBigLong(offset);
+    for( i = 0; i < tabsize; i++ ) {
+        put_big_long(offset);
         offset += table[i];
     }
-    for (i = 0; i < tabsize; ++i)
-        putBigLong(table[i]);
+    for( i = 0; i < tabsize; i++ )
+        put_big_long(table[i]);
 }
 
 
-
 static void
-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) {
+write_channels(int const cols,int const rows, int const channels,
+               void (*put) (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++ ) {
                 (*put)(channel[i][row].data[col]);
             }
         }
     }
 }
 
+static void
+put_big_short(short const s)
+{
+    if ( pm_writebigshort( stdout, s ) == -1 )
+        pm_error( "write error" );
+}
 
 
-static int
-rleCompress(ScanElem *   const inbuf,
-            unsigned int const size) {
-
-    /* slightly modified RLE algorithm from ppmtoilbm.c written by Robert
-       A. Knop (rknop@mop.caltech.edu)
-    */
-
-    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;
+static void
+put_big_long(long const 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) {
-
-    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 const len = rleCompress(tempArg, cols);
-            /* writes result into rletemp */
-        unsigned int i;
-        ScanElem * p;
-        
-        channel[chanNum][row].length = len;
-        MALLOCARRAY(p, len);
-        channel[chanNum][row].data = p;
-        for (i = 0; i < len; ++i)
-            p[i] = rletemp[i];
-        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 const s)
+{
+    put_byte((unsigned char)s);
 }
 
 
-
 static long *
-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) {
+build_channels(FILE * const ifp, int const cols, int const rows,
+               xelval const maxval, int const format,
+               int const bpc, int const channels)
+{
+    int i, row, col, sgirow;
+    long *table = NULL;
+    ScanElem *temp;
+
+#ifdef DEBUG
+    pm_message("building channels");
+#endif
+
+    if( storage != STORAGE_VERBATIM ) {
         MALLOCARRAY_NOFAIL(table, channels * rows);
         MALLOCARRAY_NOFAIL(rletemp, WORSTCOMPR(cols));
-    } else
-        table = NULL;
-
+    }
     MALLOCARRAY_NOFAIL(temp, cols);
 
-    {
-        unsigned int i;
-        for (i = 0; i < channels; ++i)
-            MALLOCARRAY_NOFAIL(channel[i], rows);
-    }
+    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) {
-            unsigned int col;
-            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 ) {
+            for( col = 0; col < cols; col++ )
                 temp[col] = (ScanElem)PNM_GET1(pnmrow[col]);
             temp = compress(temp, sgirow, rows, cols, 0, table, bpc);
-        } else {
-            unsigned int col;
-            for (col = 0; col < cols; ++col)
+        }
+        else {
+            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)
+    if( table )
         free(rletemp);
     return table;
 }
 
 
-
-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;
+static ScanElem *
+compress(ScanElem * temp,
+         int const row,  int const rows,
+         int const cols, int const chan_no,
+         long * table, int const 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);
             break;
-        case PPM_TYPE:
-            newmaxval = maxval;
-            dimensions = 3;
-            channels = 3;
+        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;
             break;
         default:
-            pm_error("can\'t happen");
+            pm_error("unknown storage type - 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 %u\"", MAXVAL_WORD);
-
-    table = buildChannels(ifP, cols, rows, newmaxval, format, bpc, channels);
-
-    pnm_freerow(pnmrow);
-
-    pm_close(ifP);
-
-    writeHeader(cols, rows, newmaxval, bpc, dimensions, channels, imagename);
+    return temp;
+}
 
-    if (table)
-        writeTable(table, rows * channels);
 
-    if (bpc == 1)
-        writeChannels(cols, rows, channels, putShortAsByte);
-    else
-        writeChannels(cols, rows, channels, putBigShort);
+/*
+slightly modified RLE algorithm from ppmtoilbm.c
+written by Robert A. Knop (rknop@mop.caltech.edu)
+*/
+static int
+rle_compress(ScanElem * const inbuf, int const size)
+{
+    int in, out, hold, count;
+    ScanElem *outbuf = rletemp;
 
-    return 0;
+    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);
 }
 
-
diff --git a/converter/other/sgi.h b/converter/other/sgi.h
index 2f57f52d..3700d356 100644
--- a/converter/other/sgi.h
+++ b/converter/other/sgi.h
@@ -5,7 +5,7 @@
 
 typedef struct {
     short           magic;
-    unsigned char   storage;
+    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   /* can't handle this */
-#define CMAP_SCREEN         2   /* can't handle this */
-#define CMAP_COLORMAP       3   /* can't handle this */
+#define CMAP_DITHERED       1   /* not supported */
+#define CMAP_SCREEN         2   /* not supported */
+#define CMAP_COLORMAP       3   /* not supported */
 
 #endif
 
diff --git a/converter/other/sgitopnm.c b/converter/other/sgitopnm.c
index 008d5376..ea2daef3 100644
--- a/converter/other/sgitopnm.c
+++ b/converter/other/sgitopnm.c
@@ -5,11 +5,6 @@
 ** 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
@@ -17,9 +12,12 @@
 ** 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)
+** 19Oct10: added checks for artihmetic overflows
+**          fixed problem with -channel on verbatim sgi images (afu)
 */
-
-
 #include <unistd.h>
 #include <limits.h>
 #include "pm_c_util.h"
@@ -30,12 +28,12 @@
 
 
 
-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 * inputFileName;  /* '-' if stdin */
-    unsigned int verbose;
+    const char *  inputFileName;  /* '-' if stdin */
+    unsigned int  verbose;
     unsigned int channelSpec;
     unsigned int channel;
 };
@@ -44,10 +42,10 @@ struct CmdlineInfo {
 
 static void
 parseCommandLine(int argc, const char ** argv,
-                 struct CmdlineInfo * const cmdlineP) {
+                 struct cmdlineInfo * const cmdlineP) {
 /*----------------------------------------------------------------------------
    parse program command line described in Unix standard form by argc
-   and argv.  Return the information in the options as *cmdlineP.
+   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.
@@ -55,7 +53,7 @@ parseCommandLine(int argc, const char ** argv,
    Note that the strings we return are stored in the storage that
    was passed to us as the argv array.  We also trash *argv.
 -----------------------------------------------------------------------------*/
-    optEntry * option_def;
+    optEntry *option_def;
         /* Instructions to pm_optParseOptions3 on how to parse our options.
          */
     optStruct3 opt;
@@ -70,7 +68,7 @@ parseCommandLine(int argc, const char ** argv,
             &cmdlineP->channelSpec,            0);
     OPTENT3(0, "verbose",             OPT_FLAG,      NULL,
             &cmdlineP->verbose,       0);
-    OPTENT3(0, "noverbose",           OPT_FLAG,      NULL,
+    OPTENT3(0, "noverbose",             OPT_FLAG,      NULL,
             NULL,       0);  /* backward compatibility */
 
     opt.opt_table = option_def;
@@ -80,8 +78,6 @@ parseCommandLine(int argc, const char ** argv,
     pm_optParseOptions3(&argc, (char **)argv, opt, sizeof(opt), 0);
         /* Uses and sets argc, argv, and some of *cmdlineP and others. */
 
-    free(option_def);
-
     if (argc-1 < 1)
         cmdlineP->inputFileName = "-";
     else if (argc-1 == 1)
@@ -169,9 +165,9 @@ getByteAsShort(FILE * const ifP) {
 
 
 static const char *
-compressionName(unsigned char const storageCode) {
+compressionName(char const compr) {
 
-    switch (storageCode) {
+    switch (compr) {
     case STORAGE_VERBATIM:
         return "none";
     case STORAGE_RLE:
@@ -218,7 +214,7 @@ readHeader(FILE *       const ifP,
     headP->pixmin    = getBigLong(ifP);
     headP->pixmax    = getBigLong(ifP);
     if (headP->pixmin >= headP->pixmax)
-        pm_error("Invalid sgi image header: pixmin larger than 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);
@@ -247,32 +243,26 @@ readHeader(FILE *       const ifP,
             headP->dimension = 2;
             break;
         case 2:
-            if (!outChannelSpec)
-                pm_message("2-channel image, using only first channel.  "
-                           "Extract alpha channel with -channel=1");
+            pm_error("don't know how to interpret 2-channel image");
             break;
         case 3:
             break;
         default:
             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');
+                pm_message("%d-channel image, using only first 3 channels",
+                           headP->zsize);
             break;
         }
         break;
     default:
-        pm_error("illegal dimension value %u (only 1-3 allowed)",
+        pm_error("illegal dimension value %d (only 1-3 allowed)",
                  headP->dimension);
     }
 
     if (verbose) {
-        pm_message("raster size %ux%u, %u channels",
+        pm_message("raster size %dx%d, %d channels",
                    headP->xsize, headP->ysize, headP->zsize);
-        pm_message("compression: 0x%02x = %s",
+        pm_message("compression: %d = %s",
                    headP->storage, compressionName(headP->storage));
         headP->name[79] = '\0';  /* just to be safe */
         pm_message("Image name: '%s'", headP->name);
@@ -355,7 +345,7 @@ rleDecompress(ScanElem * const srcStart,
 static ScanLine *
 readChannels(FILE *       const ifP,
              Header *     const head,
-             TabEntry *   const table,
+             TabEntry *   const table, 
              bool         const outChannelSpec,
              unsigned int const outChannel) {
 
@@ -367,14 +357,11 @@ readChannels(FILE *       const ifP,
     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;
+        maxchannel = MIN(3, head->zsize);
         MALLOCARRAY_NOFAIL(image, head->ysize * maxchannel);
     }
-    if (table)
+    if (table) 
         MALLOCARRAY_NOFAIL(temp, WORSTCOMPR(head->xsize));
 
     for (channel = 0; channel < maxchannel; ++channel) {
@@ -390,17 +377,16 @@ readChannels(FILE *       const ifP,
 
             if (table) {
                 if (!outChannelSpec || channel >= outChannel) {
-                    pm_filepos const offset = (pm_filepos)
-                        table[sgiIndex].start;
+                    long const offset = 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));
+                    /* 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)
                         if (head->bpc == 1)
@@ -418,7 +404,7 @@ readChannels(FILE *       const ifP,
                     else
                         p = getBigShort(ifP);
 
-                    if (!outChannelSpec || outChannel == channel)
+                    if (channel == outChannel || !outChannelSpec)
                         image[iindex][i] = p;
                 }
             }
@@ -444,7 +430,7 @@ imageToPnm(Header   *   const head,
     int row;
     int format;
 
-    if (head->zsize <= 2 || outChannelSpec) {
+    if (head->zsize == 1 || outChannelSpec) {
         pm_message("writing PGM image");
         format = PGM_TYPE;
     } else {
@@ -473,10 +459,10 @@ imageToPnm(Header   *   const head,
 
 
 
-int
+int 
 main(int argc, const char * argv[]) {
 
-    struct CmdlineInfo cmdline;
+    struct cmdlineInfo cmdline;
     FILE * ifP;
     TabEntry * table;
     ScanLine * image;
@@ -486,8 +472,8 @@ main(int argc, const char * argv[]) {
     pm_proginit(&argc, argv);
 
     parseCommandLine(argc, argv, &cmdline);
-
-    ifP = pm_openr_seekable(cmdline.inputFileName);
+    
+    ifP = pm_openr(cmdline.inputFileName);    
 
     headP = readHeader(ifP, cmdline.channelSpec, cmdline.verbose);
 
@@ -505,14 +491,14 @@ main(int argc, const char * argv[]) {
         table = readTable(ifP, headP->ysize * headP->zsize);
     else
         table = NULL;
-
+ 
     image = readChannels(ifP, headP, table,
                          cmdline.channelSpec, cmdline.channel);
 
     imageToPnm(headP, image, maxval, cmdline.channelSpec, cmdline.channel);
 
     pm_close(ifP);
-
+ 
     return 0;
 }
 
diff --git a/converter/other/tifftopnm.c b/converter/other/tifftopnm.c
index 214c02aa..fcfb03f6 100644
--- a/converter/other/tifftopnm.c
+++ b/converter/other/tifftopnm.c
@@ -1457,7 +1457,7 @@ convertRasterInMemory(pnmOut *       const pnmOutP,
         int ok;
         ok = TIFFRGBAImageOK(tif, emsg);
         if (!ok) {
-            pm_message("%s", emsg);
+            pm_message(emsg);
             *statusP = CONV_UNABLE;
         } else {
             uint32 * raster;
@@ -1477,14 +1477,14 @@ convertRasterInMemory(pnmOut *       const pnmOutP,
                 
                 ok = TIFFRGBAImageBegin(&img, tif, stopOnErrorFalse, emsg);
                 if (!ok) {
-                    pm_message("%s", emsg);
+                    pm_message(emsg);
                     *statusP = CONV_FAILED;
                 } else {
                     int ok;
                     ok = TIFFRGBAImageGet(&img, raster, cols, rows);
                     TIFFRGBAImageEnd(&img) ;
                     if (!ok) {
-                        pm_message("%s", emsg);
+                        pm_message(emsg);
                         *statusP = CONV_FAILED;
                     } else {
                         *statusP = CONV_DONE;
diff --git a/converter/pbm/cmuwmtopbm.c b/converter/pbm/cmuwmtopbm.c
index ccf8cfc9..1f2d21f1 100644
--- a/converter/pbm/cmuwmtopbm.c
+++ b/converter/pbm/cmuwmtopbm.c
@@ -48,20 +48,20 @@ readCmuwmHeader(FILE *         const ifP,
 
     rc = pm_readbiglong(ifP, &l);
     if (rc == -1 )
-        pm_error("%s", initReadError);
+        pm_error(initReadError);
     if ((uint32_t)l != cmuwmMagic)
         pm_error("bad magic number in CMU window manager file");
     rc = pm_readbiglong(ifP, &l);
     if (rc == -1)
-        pm_error("%s", initReadError);
+        pm_error(initReadError);
     *colsP = l;
     rc = pm_readbiglong(ifP, &l);
     if (rc == -1 )
-        pm_error("%s", initReadError);
+        pm_error(initReadError);
     *rowsP = l;
     rc = pm_readbigshort(ifP, &s);
     if (rc == -1)
-        pm_error("%s", initReadError);
+        pm_error(initReadError);
     *depthP = s;
 }
 
diff --git a/converter/pbm/pbmtoppa/Makefile b/converter/pbm/pbmtoppa/Makefile
index cf31ded6..5f205230 100644
--- a/converter/pbm/pbmtoppa/Makefile
+++ b/converter/pbm/pbmtoppa/Makefile
@@ -9,18 +9,17 @@ include $(BUILDDIR)/config.mk
 
 all: pbmtoppa
 
-PORTBINARIES = pbmtoppa
-
-BINARIES = $(PORTBINARIES)
+BINARIES = pbmtoppa
 
 MERGEBINARIES = $(BINARIES)
 
-ADDL_OBJECTS = ppa.o pbm.o cutswath.o
-
-OBJECTS = pbmtoppa.o $(ADDL_OBJECTS)
-
-MERGE_OBJECTS = pbmtoppa.o2 $(ADDL_OBJECTS)
+OBJECTS = pbmtoppa.o ppa.o pbm.o cutswath.o
+MERGE_OBJECTS = pbmtoppa.o2 ppa.o pbm.o cutswath.o
 
 include $(SRCDIR)/common.mk
 
-pbmtoppa: $(OBJECTS)
+pbmtoppa: $(OBJECTS) $(NETPBMLIB) $(LIBOPT)
+	$(LD) -o pbmtoppa $(OBJECTS) \
+	  -lm $(shell $(LIBOPT) $(NETPBMLIB)) $(LDFLAGS) $(LDLIBS) \
+	  $(RPATH) $(LADD)
+
diff --git a/converter/ppm/ilbm.h b/converter/ppm/ilbm.h
index dbe47758..68657956 100644
--- a/converter/ppm/ilbm.h
+++ b/converter/ppm/ilbm.h
@@ -23,7 +23,7 @@ typedef struct {
 #define mskNone                 0
 #define mskHasMask              1
 #define mskHasTransparentColor  2
-#define mskLasso                3       /* can't handle this */
+#define mskLasso                3       /* not supported */
 #define mskMAXKNOWN             mskLasso
 static const char * mskNAME[] = { 
     "none", "mask plane", "transparent color", "lasso" 
@@ -127,8 +127,8 @@ typedef struct {
 #define CLUT_RED    1
 #define CLUT_GREEN  2
 #define CLUT_BLUE   3
-#define CLUT_HUE    4   /* can't handle this */
-#define CLUT_SAT    5   /* can't handle this */
+#define CLUT_HUE    4   /* not supported */
+#define CLUT_SAT    5   /* not supported */
 
 
 /* unofficial DCOL chunk for direct-color */
diff --git a/converter/ppm/ppmtompeg/Makefile b/converter/ppm/ppmtompeg/Makefile
index 49aeb7f8..4f244ae9 100644
--- a/converter/ppm/ppmtompeg/Makefile
+++ b/converter/ppm/ppmtompeg/Makefile
@@ -38,13 +38,7 @@ endif
 #	-DHEINOUS_DEBUG_MODE
 #
 
-MP_BASE_OBJS = \
-  mfwddct.o \
-  postdct.o \
-  huff.o \
-  bitio.o \
-  mheaders.o \
-
+MP_BASE_OBJS = mfwddct.o postdct.o huff.o bitio.o mheaders.o
 MP_ENCODE_OBJS = \
   frames.o \
   iframe.o \
@@ -52,24 +46,11 @@ MP_ENCODE_OBJS = \
   bframe.o \
   psearch.o \
   bsearch.o \
-  block.o \
-
-MP_OTHER_OBJS = \
-  mpeg.o \
-  subsample.o \
-  param.o \
-  rgbtoycc.o \
-  readframe.o \
-  combine.o \
-  jrevdct.o \
-  frame.o \
-  fsize.o \
-  frametype.o \
-  specifics.o \
-  rate.o \
-  opts.o \
-  input.o \
+  block.o 
 
+MP_OTHER_OBJS = mpeg.o subsample.o param.o rgbtoycc.o \
+	readframe.o combine.o jrevdct.o frame.o fsize.o frametype.o \
+	specifics.o rate.o opts.o input.o
 ifeq ($(OMIT_NETWORK),Y)
   MP_OTHER_OBJS += noparallel.o
 else
@@ -81,19 +62,14 @@ else
   MP_OTHER_OBJS += gethostname.o
 endif
 
-ADDL_OBJECTS = \
-  $(MP_BASE_OBJS) \
-  $(MP_OTHER_OBJS) \
-  $(MP_ENCODE_OBJS) \
-  $(JPEG_MODULE).o \
-
-OBJECTS = ppmtompeg.o $(ADDL_OBJECTS)
-MERGE_OBJECTS = ppmtompeg.o2 $(ADDL_OBJECTS)
+NONMAIN_OBJS = $(MP_BASE_OBJS) $(MP_OTHER_OBJS) $(MP_ENCODE_OBJS) \
+	      	$(JPEG_MODULE).o
+OBJECTS = ppmtompeg.o $(NONMAIN_OBJS)
+MERGE_OBJECTS = ppmtompeg.o2 $(NONMAIN_OBJS)
 MP_INCLUDE = mproto.h mtypes.h huff.h bitio.h
 MP_MISC = Makefile huff.table parse_huff.pl
 
-PORTBINARIES = ppmtompeg
-BINARIES = $(PORTBINARIES)
+BINARIES = ppmtompeg
 MERGEBINARIES = $(BINARIES)
 SCRIPTS = 
 
@@ -108,14 +84,18 @@ else
   LIBOPTR =
 endif
 
-ppmtompeg: $(ADDL_OBJECTS) $(LIBOPT)
-ppmtompeg: LDFLAGS_TARGET = \
-  $(shell $(LIBOPT) $(LIBOPTR) $(JPEGLIBX)) $(NETWORKLD)
+ppmtompeg: $(OBJECTS) $(NETPBMLIB) $(LIBOPT)
+	$(LD) -o $@ \
+          $(OBJECTS) $(shell $(LIBOPT) $(NETPBMLIB) $(LIBOPTR) $(JPEGLIBX)) \
+	  $(NETWORKLD) $(MATHLIB) $(LDFLAGS) $(LDLIBS) \
+	  $(RPATH) $(LADD)
+
+profile: $(OBJECTS) $(NETPBMLIB) $(LIBOPT)
+	$(LD) -o $@ -Bstatic -pg \
+          $(OBJECTS) $(shell $(LIBOPT) $(NETPBMLIB) $(LIBOPTR) $(JPEGLIBX)) \
+	  $(NETWORKLD) $(MATHLIB) $(LDFLAGS) $(LDLIBS) \
+	  $(RPATH) $(LADD)
 
-profile: $(ADDL_OBJECTS) $(LIBOPT)
-profile: LDFLAGS_TARGET = \
-  -Bstatic -pg \
-  $(shell $(LIBOPT) $(LIBOPTR) $(JPEGLIBX)) $(NETWORKLD)
 
 #########
 # OTHER #
diff --git a/converter/ppm/ppmtompeg/gethostname_win32.c b/converter/ppm/ppmtompeg/gethostname_win32.c
index e37fbb37..383f4e55 100644
--- a/converter/ppm/ppmtompeg/gethostname_win32.c
+++ b/converter/ppm/ppmtompeg/gethostname_win32.c
@@ -94,7 +94,7 @@ get_string_version(push_string_t *str)
             return FALSE;
     }
 
-    /* Call GetNativeSystemInfo if available; GetSystemInfo otherwise. */
+    /* Call GetNativeSystemInfo if supported or GetSystemInfo otherwise. */
     pGNSI = (PGNSI)
             GetProcAddress(GetModuleHandle(TEXT("kernel32.dll")), 
             "GetNativeSystemInfo");