about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--GNUmakefile5
-rwxr-xr-xbuildtools/configure.pl2
-rwxr-xr-xbuildtools/installnetpbm.pl259
-rw-r--r--buildtools/pkgconfig_template7
-rw-r--r--converter/other/pnmtorast.c501
-rw-r--r--converter/other/rast.h15
-rw-r--r--converter/other/rasttopnm.c295
-rw-r--r--converter/other/tifftopnm.c2
-rw-r--r--converter/ppm/ppmtompeg/headers/dct.h1
-rw-r--r--converter/ppm/ppmtompeg/headers/general.h8
-rw-r--r--converter/ppm/ppmtompeg/mfwddct.c180
-rw-r--r--converter/ppm/ppmtompeg/opts.c2
-rw-r--r--converter/ppm/ppmtompeg/ppmtompeg.c2
-rw-r--r--doc/COPYRIGHT.PATENT93
-rw-r--r--doc/HISTORY29
-rw-r--r--doc/patent_summary85
-rw-r--r--generator/pamstereogram.c20
-rw-r--r--version.mk4
18 files changed, 944 insertions, 566 deletions
diff --git a/GNUmakefile b/GNUmakefile
index 9066f2a7..f923aa1f 100644
--- a/GNUmakefile
+++ b/GNUmakefile
@@ -103,10 +103,13 @@ $(PROG_SUBDIRS:%=%/all): lib/all $(SUPPORT_SUBDIRS:%=%/all)
 lib/all: lib/util/all
 
 .PHONY: lib/util/all
-lib/util/all:
+lib/util/all: lib/util
 	$(MAKE) -C lib/util -f $(SRCDIR)/lib/util/Makefile \
 	    SRCDIR=$(SRCDIR) BUILDDIR=$(BUILDDIR) all
 
+lib/util: lib
+	mkdir $@
+
 OMIT_CONFIG_RULE = 1
 OMIT_VERSION_H_RULE = 1
 OMIT_INTTYPES_RULE = 1
diff --git a/buildtools/configure.pl b/buildtools/configure.pl
index 7a2f5513..2179454b 100755
--- a/buildtools/configure.pl
+++ b/buildtools/configure.pl
@@ -478,10 +478,10 @@ sub getPlatform() {
     print("Which of the following best describes your platform?\n");
  
     print("gnu      GNU/Linux\n");
+    print("win      Windows/DOS (Cygwin, DJGPP, Mingw32)\n");
     print("sun      Solaris or SunOS\n");
     print("hp       HP-UX\n");
     print("aix      AIX\n");
-    print("win      Windows/DOS (Cygwin, DJGPP, Mingw32)\n");
     print("tru64    Tru64\n");
     print("irix     Irix\n");
     print("bsd      NetBSD, BSD/OS\n");
diff --git a/buildtools/installnetpbm.pl b/buildtools/installnetpbm.pl
index 1e0355df..3c3d9b9d 100755
--- a/buildtools/installnetpbm.pl
+++ b/buildtools/installnetpbm.pl
@@ -47,7 +47,10 @@ sub prompt($$) {
 
 
 sub getPkgdir() {
-
+#-----------------------------------------------------------------------------
+#  Find out from the user where the Netpbm package is (i.e. where
+#  'make package' put it).
+#-----------------------------------------------------------------------------
     my $pkgdir;
 
     while (!$pkgdir) {
@@ -141,7 +144,7 @@ sub getPrefix() {
 
 sub getCpCommand() {
 #-----------------------------------------------------------------------------
-# compute the command + options need to do a recursive copy, preserving
+# Compute the command + options need to do a recursive copy, preserving
 # symbolic links and file attributes.
 #-----------------------------------------------------------------------------
     my $cpCommand;
@@ -168,7 +171,10 @@ sub getCpCommand() {
 
 
 sub getBinDir($) {
-
+#-----------------------------------------------------------------------------
+#  Find out from the user where he wants the programs installed, and return
+#  that.
+#-----------------------------------------------------------------------------
     my ($prefix) = @_;
 
     print("Where do you want the programs installed?\n");
@@ -223,7 +229,10 @@ sub installProgram($$$) {
 
 
 sub getLibDir($) {
-
+#-----------------------------------------------------------------------------
+#  Find out from the user where he wants the runtime libraries installed and
+#  return that.
+#-----------------------------------------------------------------------------
     my ($prefix) = @_;
 
     print("Where do you want the shared library installed?\n");
@@ -320,8 +329,7 @@ sub ldConfigKnowsDir($) {
 
 
 
-sub
-warnNonstandardShlibDirLdconfig($) {
+sub warnNonstandardShlibDirLdconfig($) {
     my ($shlibDir) = @_;
 #-----------------------------------------------------------------------------
 #  Assuming this is a system that has an 'ldconfig' program, warn the user
@@ -356,8 +364,7 @@ warnNonstandardShlibDirLdconfig($) {
 
 
 
-sub
-warnNonstandardShlibDirCrle($) {
+sub warnNonstandardShlibDirCrle($) {
     my ($shlibDir) = @_;
 #-----------------------------------------------------------------------------
 #  Assuming this is a system that has a 'crle' program, warn the user
@@ -386,8 +393,7 @@ warnNonstandardShlibDirCrle($) {
         
 
 
-sub
-warnNonstandardShlibDirGeneric($) {
+sub warnNonstandardShlibDirGeneric($) {
     my ($shlibDir) = @_;
 #-----------------------------------------------------------------------------
 #  Without assuming any particular shared library search scheme on this
@@ -426,8 +432,7 @@ sub warnNonstandardShlibDir($) {
 
 
 
-sub 
-execLdconfig() {
+sub execLdconfig() {
 #-----------------------------------------------------------------------------
 #  Run Ldconfig.  Try with the -X option first, and if that is an invalid
 #  option (which we have seen on an openBSD system), try it without -X.
@@ -481,8 +486,7 @@ execLdconfig() {
 
 
 
-sub
-doLdconfig() {
+sub doLdconfig() {
 #-----------------------------------------------------------------------------
 #  Run Ldconfig where appropriate.
 #-----------------------------------------------------------------------------
@@ -556,7 +560,10 @@ sub installSharedLib($$$) {
 
 
 sub getLinkDir($) {
-
+#-----------------------------------------------------------------------------
+#  Find out from the user where he wants the link-edit libraries installed and
+#  return that.
+#-----------------------------------------------------------------------------
     my ($prefix) = @_;
 
     print("Where do you want the static link library installed?\n");
@@ -616,7 +623,10 @@ sub installStaticLib($$$) {
 
 
 sub getDataDir($) {
-
+#-----------------------------------------------------------------------------
+#  Find out from the user where he wants the runtime data files installed and
+#  return that.
+#-----------------------------------------------------------------------------
     my ($prefix) = @_;
 
     print("Where do you want the data files installed?\n");
@@ -650,7 +660,10 @@ sub getDataDir($) {
 
 
 sub getHdrDir($) {
-
+#-----------------------------------------------------------------------------
+#  Find out from the user where he wants the compile-time header files
+#  installed and return that.
+#-----------------------------------------------------------------------------
     my ($prefix) = @_;
 
     print("Where do you want the library interface header files installed?\n");
@@ -740,7 +753,10 @@ sub installHeader($$$) {
 
 
 sub getManDir($) {
-
+#-----------------------------------------------------------------------------
+#  Find out from the user where he wants the pointer man pages
+#  installed and return that.
+#-----------------------------------------------------------------------------
     my ($prefix) = @_;
 
     print("Where do you want the man pages installed?\n");
@@ -958,10 +974,37 @@ sub installManPage($$$) {
 
 
 
+sub netpbmVersion($) {
+    my ($pkgdir) = @_;
+
+    my $versionOpened = open(VERSION, "<$pkgdir/VERSION");
+
+    my $version;
+    my $error;
+
+    if (!$versionOpened) {
+        $error = "Unable to open $pkgdir/VERSION for reading.  " .
+            "Errno=$ERRNO\n";
+    } else {
+        $version = <VERSION>;
+        chomp($version);
+        close(VERSION);
+    }
+
+    if ($error) {
+        print("Failed to determine the version of Netpbm from the package, "
+              . "so that will not be correct in netpbm.config and netpbm.pc.  "
+              . $error . "\n");
+        $version = "???";
+    }
+    return $version;
+}
+
+
+
 sub 
-processTemplate($$$$$$$$$) {
-    my ($templateR, $version, $bindir, $libdir, $linkdir, $datadir, 
-        $includedir, $mandir, $outputR) = @_;
+processTemplate($$$) {
+    my ($templateR, $infoR, $outputR) = @_;
 
     my @output;
 
@@ -969,26 +1012,26 @@ processTemplate($$$$$$$$$) {
         if (m{^@}) {
             # Comment -- ignore it.
         } else {
-            if (defined($version)) {
-                s/\@VERSION\@/$version/;
+            if (defined($infoR->{VERSION})) {
+                s/\@VERSION\@/$infoR->{VERSION}/;
             }
-            if (defined($bindir)) {
-                s/\@BINDIR@/$bindir/;
+            if (defined($infoR->{BINDIR})) {
+                s/\@BINDIR@/$infoR->{BINDIR}/;
             }
-            if (defined($libdir)) {
-                s/\@LIBDIR@/$libdir/;
+            if (defined($infoR->{LIBDIR})) {
+                s/\@LIBDIR@/$infoR-.{LIBDIR}/;
             }
-            if (defined($linkdir)) {
-                s/\@LINKDIR@/$linkdir/;
+            if (defined($infoR->{LINKDIR})) {
+                s/\@LINKDIR@/$infoR->{LINKDIR}/;
             }
-            if (defined($datadir)) {
-                s/\@DATADIR@/$datadir/;
+            if (defined($infoR->{DATADIR})) {
+                s/\@DATADIR@/$infoR->{DATADIR}/;
             }
-            if (defined($includedir)) {
-                s/\@INCLUDEDIR@/$includedir/;
+            if (defined($infoR->{INCLUDEDIR})) {
+                s/\@INCLUDEDIR@/$infoR->{INCLUDEDIR}/;
             }
-            if (defined($mandir)) {
-                s/\@MANDIR@/$mandir/;
+            if (defined($infoR->{MANDIR})) {
+                s/\@MANDIR@/$infoR->{MANDIR}/;
             }
             push(@output, $_);
         }
@@ -998,11 +1041,12 @@ processTemplate($$$$$$$$$) {
 
 
 
-sub
-installConfig($$$$$$$) {
-    my ($pkgdir, 
-        $bindir, $libdir, $linkdir, $datadir, $includedir, $mandir) = @_;
-
+sub installConfig($$) {
+    my ($installdir, $templateSubsR) = @_;
+#-----------------------------------------------------------------------------
+# Install 'netpbm-config' -- a program you run to tell you things about
+# how Netpbm is installed.
+#-----------------------------------------------------------------------------
     my $error;
 
     my $configTemplateFilename = dirname($0) . "/config_template";
@@ -1015,41 +1059,108 @@ installConfig($$$$$$$) {
 
         close(TEMPLATE);
 
-        my $versionOpened = open(VERSION, "<$pkgdir/VERSION");
+        processTemplate(\@template, $templateSubsR, \my $fileContentsR);
 
-        my $version;
-        if (!$versionOpened) {
-            $error = "Unable to open $pkgdir/VERSION for reading.  " .
-                "Errno=$ERRNO\n";
+        # TODO: Really, this ought to go in an independent directory,
+        # because you might want to have the Netpbm executables in
+        # some place not in the PATH and use this program, via the
+        # PATH, to find them.
+        
+        my $filename = "$installdir/netpbm-config";
+        
+        my $success = open(NETPBM_CONFIG, ">$filename");
+        if ($success) {
+            chmod(0755, $filename);
+            foreach (@{$fileContentsR}) { print NETPBM_CONFIG; }
+            close(NETPBM_CONFIG);
         } else {
-            $version = <VERSION>;
-            chomp($version);
-            close(VERSION);
-
-            processTemplate(\@template, $version, $bindir, $libdir,
-                            $linkdir, $datadir, $includedir, $mandir,
-                            \my $fileContentsR);
-
-            # TODO: Really, this ought to go in an independent directory,
-            # because you might want to have the Netpbm executables in
-            # some place not in the PATH and use this program, via the
-            # PATH, to find them.
-            
-            my $filename = "$bindir/netpbm-config";
+            $error = "Unable to open the file " .
+                "'$filename' for writing.  Errno=$ERRNO\n";
+        }
+    }
+    if ($error) {
+        print(STDERR "Failed to create the Netpbm configuration program.  " .
+              "$error\n");
+    }
+}
+
+
+
+
+sub getPkgconfigDir($) {
+#-----------------------------------------------------------------------------
+#  Find out from the user where he wants the Pkg-config file for the
+#  installation (netpbm.pc) and return that.
+#-----------------------------------------------------------------------------
+    my ($prefix) = @_;
+
+    print("Where do you want the Pkg-config file netpbm.pc installed?\n");
+    print("\n");
+
+    my $pkgconfigDir;
+
+    while (!$pkgconfigDir) {
+        my $default = "$prefix/lib/pkgconfig";
+
+        my $response = prompt("Pkg-config directory", $default);
+        
+        if (-d($response)) {
+            $pkgconfigDir = $response;
+        } else {
+            my $succeeded = mkdir($response, 0777);
             
-            my $success = open(NETPBM_CONFIG, ">$filename");
-            if ($success) {
-                chmod(0755, $filename);
-                foreach (@{$fileContentsR}) { print NETPBM_CONFIG; }
-                close(NETPBM_CONFIG);
+            if (!$succeeded) {
+                print("Unable to create directory '$response'.  " .
+                      "Error=$ERRNO\n");
             } else {
-                $error = "Unable to open the file " .
-                    "'$filename' for writing.  Errno=$ERRNO\n";
+                $pkgconfigDir = $response;
             }
         }
     }
+    print("\n");
+
+    return $pkgconfigDir;
+}
+
+
+
+sub installPkgConfig($$) {
+    my ($prefix, $templateSubsR) = @_;
+#-----------------------------------------------------------------------------
+# Install a pkg-config file (netpbm.pc) - used by the 'pkg-config' program to
+# find out various things about how Netpbm is installed.
+#-----------------------------------------------------------------------------
+    my $pkgconfigDir = getPkgconfigDir($prefix);
+
+    my $error;
+
+    my $pcTemplateFilename = dirname($0) . "/pkgconfig_template";
+
+    my $templateOpened = open(TEMPLATE, "<$pcTemplateFilename");
+    if (!$templateOpened) {
+        $error = "Can't open template file '$pcTemplateFilename'.\n";
+    } else {
+        my @template = <TEMPLATE>;
+
+        close(TEMPLATE);
+
+        processTemplate(\@template, $templateSubsR,
+                        \my $fileContentsR);
+
+        my $filename = "$pkgconfigDir/netpbm.pc";
+        
+        my $success = open(NETPBM_PC, ">$filename");
+        if ($success) {
+            chmod(0755, $filename);
+            foreach (@{$fileContentsR}) { print NETPBM_PC; }
+            close(NETPBM_PC);
+        } else {
+            $error = "Unable to open the file " .
+                "'$filename' for writing.  Errno=$ERRNO\n";
+        }
+    }
     if ($error) {
-        print(STDERR "Failed to create the Netpbm configuration program.  " .
+        print(STDERR "Failed to create the Netpbm Pkg-config file.  " .
               "$error\n");
     }
 }
@@ -1095,8 +1206,18 @@ print("\n");
 installManPage($pkgdir, $prefix, \my $mandir);
 print("\n");
 
-installConfig($pkgdir, 
-              $bindir, $libdir, $linkdir, $datadir, $includedir, $mandir);
+my $templateSubsR =
+    {VERSION    => netpbmVersion($pkgdir),
+     BINDIR     => $bindir,
+     LIBDIR     => $libdir,
+     LINKDIR    => $linkdir,
+     DATADIR    => $datadir,
+     INCLUDEDIR => $includedir,
+     MANDIR     => $mandir};
+
+installConfig($bindir, $templateSubsR);
+
+installPkgConfig($prefix, $templateSubsR);
 
 print("Installation is complete (except where previous error messages have\n");
 print("indicated otherwise).\n");
diff --git a/buildtools/pkgconfig_template b/buildtools/pkgconfig_template
new file mode 100644
index 00000000..7288a76f
--- /dev/null
+++ b/buildtools/pkgconfig_template
@@ -0,0 +1,7 @@
+Name: Netpbm
+Description: Graphics utilities
+Version: @VERSION@
+Requires: 
+Libs: -L@LINKDIR@ -lnetpbm
+Libs.private: 
+Cflags: -I@INCLUDEDIR@
diff --git a/converter/other/pnmtorast.c b/converter/other/pnmtorast.c
index 605e815c..e11d3cb7 100644
--- a/converter/other/pnmtorast.c
+++ b/converter/other/pnmtorast.c
@@ -19,103 +19,285 @@
 
 
 static colormap_t *
-alloc_pr_colormap(void) {
-
-    colormap_t* pr_colormapP;
-
-    MALLOCVAR(pr_colormapP);
-    if ( pr_colormapP == NULL )
-        pm_error( "out of memory" );
-    pr_colormapP->type = RMT_EQUAL_RGB;
-    pr_colormapP->length = MAXCOLORS;
-    MALLOCARRAY(pr_colormapP->map[0], MAXCOLORS);
-    MALLOCARRAY(pr_colormapP->map[1], MAXCOLORS);
-    MALLOCARRAY(pr_colormapP->map[2], MAXCOLORS);
-    if ( pr_colormapP->map[0] == NULL || 
-         pr_colormapP->map[1] == NULL ||
-         pr_colormapP->map[2] == NULL )
-        pm_error( "out of memory" );
-
-    return pr_colormapP;
+allocPrColormap(void) {
+
+    colormap_t * prColormapP;
+
+    MALLOCVAR(prColormapP);
+    if (prColormapP == NULL)
+        pm_error("out of memory");
+    prColormapP->type = RMT_EQUAL_RGB;
+    prColormapP->length = MAXCOLORS;
+    MALLOCARRAY(prColormapP->map[0], MAXCOLORS);
+    MALLOCARRAY(prColormapP->map[1], MAXCOLORS);
+    MALLOCARRAY(prColormapP->map[2], MAXCOLORS);
+    if (prColormapP->map[0] == NULL || 
+        prColormapP->map[1] == NULL ||
+        prColormapP->map[2] == NULL)
+        pm_error("out of memory");
+
+    return prColormapP;
 }
 
 
 
-static colormap_t*
-make_pr_colormap(colorhist_vector const chv,
-                 int              const colors) {
+static colormap_t *
+makePrColormap(colorhist_vector const chv,
+               unsigned int     const colors) {
 
-    colormap_t* pr_colormapP;
-    int i;
+    colormap_t * prColormapP;
+    unsigned int i;
 
-    pr_colormapP = alloc_pr_colormap( );
+    prColormapP = allocPrColormap();
 
-    for ( i = 0; i < colors; ++i )
-    {
-        pr_colormapP->map[0][i] = PPM_GETR( chv[i].color );
-        pr_colormapP->map[1][i] = PPM_GETG( chv[i].color );
-        pr_colormapP->map[2][i] = PPM_GETB( chv[i].color );
+    for (i = 0; i < colors; ++i) {
+        prColormapP->map[0][i] = PPM_GETR(chv[i].color);
+        prColormapP->map[1][i] = PPM_GETG(chv[i].color);
+        prColormapP->map[2][i] = PPM_GETB(chv[i].color);
     }
-    for ( ; i < MAXCOLORS; ++i )
-        pr_colormapP->map[0][i] = pr_colormapP->map[1][i] =
-            pr_colormapP->map[2][i] = 0;
-
-    return pr_colormapP;
+    for ( ; i < MAXCOLORS; ++i) {
+        prColormapP->map[0][i] = 0;
+        prColormapP->map[1][i] = 0;
+        prColormapP->map[2][i] = 0;
+    }
+    return prColormapP;
 }
 
 
 
 static colormap_t *
-make_gray_pr_colormap(void) {
+makeGrayPrColormap(void) {
 
-    colormap_t* pr_colormapP;
-    int i;
+    colormap_t * prColormapP;
+    unsigned int i;
 
-    pr_colormapP = alloc_pr_colormap( );
+    prColormapP = allocPrColormap();
 
-    for ( i = 0; i < MAXCOLORS; ++i )
-    {
-        pr_colormapP->map[0][i] = i;
-        pr_colormapP->map[1][i] = i;
-        pr_colormapP->map[2][i] = i;
+    for (i = 0; i < MAXCOLORS; ++i) {
+        prColormapP->map[0][i] = i;
+        prColormapP->map[1][i] = i;
+        prColormapP->map[2][i] = i;
+    }
+
+    return prColormapP;
+}
+
+
+
+static void
+doRowDepth1(const xel *     const xelrow,
+            unsigned char * const rastRow,
+            unsigned int    const cols,
+            int             const format,
+            xelval          const maxval,
+            colorhash_table const cht,
+            unsigned int *  const lenP) {
+                
+    unsigned int col;
+    int bitcount;
+    unsigned int cursor;
+
+    cursor = 0;
+
+    rastRow[cursor] = 0;
+    bitcount = 7;
+
+    for (col = 0; col < cols; ++col) {
+        switch (PNM_FORMAT_TYPE(format)) {
+        case PPM_TYPE: {
+            xel adjustedXel;
+            int color;
+            if (maxval != 255)
+                PPM_DEPTH(adjustedXel, xelrow[col], maxval, 255 );
+            color = ppm_lookupcolor(cht, &adjustedXel);
+            if (color == -1)
+                pm_error("color not found?!?  "
+                         "col=%u  r=%u g=%u b=%u",
+                         col,
+                         PPM_GETR(adjustedXel),
+                         PPM_GETG(adjustedXel),
+                         PPM_GETB(adjustedXel));
+            if (color)
+                rastRow[cursor] |= 1 << bitcount;
+        } break;
+
+        default: {
+            int const color = PNM_GET1(xelrow[col]);
+            if (!color)
+                rastRow[cursor] |= 1 << bitcount;
+            break;
+        }
+        }
+        --bitcount;
+        if (bitcount < 0) {
+            ++cursor;
+            rastRow[cursor] = 0;
+            bitcount = 7;
+        }
+    }
+    *lenP = cursor;
+}
+
+
+
+static void
+doRowDepth8(const xel *     const xelrow,
+            unsigned char * const rastRow,
+            unsigned int    const cols,
+            int             const format,
+            xelval          const maxval,
+            colorhash_table const cht,
+            unsigned int *  const lenP) {
+
+    unsigned int col;
+    unsigned int cursor;
+
+    for (col = 0, cursor = 0; col < cols; ++col) {
+        int color;  /* color index of pixel or -1 if not in 'cht' */
+
+        switch (PNM_FORMAT_TYPE(format)) {
+        case PPM_TYPE: {
+            xel adjustedXel;
+
+            if (maxval == 255)
+                adjustedXel = xelrow[col];
+            else
+                PPM_DEPTH(adjustedXel, xelrow[col], maxval, 255);
+
+            color = ppm_lookupcolor(cht, &adjustedXel);
+            if (color == -1)
+                pm_error("color not found?!?  "
+                         "col=%u  r=%u g=%u b=%u",
+                         col,
+                         PPM_GETR(adjustedXel),
+                         PPM_GETG(adjustedXel),
+                         PPM_GETB(adjustedXel));
+        } break;
+
+        case PGM_TYPE: {
+            int const rawColor = PNM_GET1(xelrow[col]);
+
+            color = maxval == 255 ? rawColor : rawColor * 255 / maxval;
+
+        } break;
+
+        default:
+            color = PNM_GET1(xelrow[col]);
+        }
+        rastRow[cursor++] = color;
     }
+    *lenP = cursor;
+}
+
 
-    return pr_colormapP;
+
+
+static void
+doRowDepth24(const xel *     const xelrow,
+             unsigned char * const rastRow,
+             unsigned int    const cols,
+             int             const format,
+             xelval          const maxval,
+             unsigned int *  const lenP) {
+
+    /* Since depth is 24, we do NOT have a valid cht. */
+
+    unsigned int col;
+    unsigned int cursor;
+
+    for (col = 0, cursor = 0; col < cols; ++col) {
+        xel adjustedXel;
+
+        if (maxval == 255)
+            adjustedXel = xelrow[col];
+        else
+            PPM_DEPTH(adjustedXel, xelrow[col], maxval, 255);
+
+        rastRow[cursor++] = PPM_GETB(adjustedXel);
+        rastRow[cursor++] = PPM_GETG(adjustedXel);
+        rastRow[cursor++] = PPM_GETR(adjustedXel);
+    }
+    *lenP = cursor;
+}
+
+
+
+static void
+computeRaster(unsigned char * const rastRaster,
+              unsigned int    const lineSize,
+              unsigned int    const depth,
+              unsigned int    const cols,
+              unsigned int    const rows,
+              int             const format,
+              xelval          const maxval,
+              xel **          const xels,
+              colorhash_table const cht) {
+                  
+    unsigned int row;
+    unsigned char * rastRow;
+
+    for (row = 0, rastRow = &rastRaster[0]; row < rows; ++row) {
+        xel * const xelrow = xels[row];
+
+        unsigned int len; /* Number of bytes of rast data added to rastRow[] */
+
+        switch (depth) {
+        case 1:
+            doRowDepth1(xelrow, rastRow, cols, format, maxval, cht, &len);
+            break;
+        case 8:
+            doRowDepth8(xelrow, rastRow, cols, format, maxval, cht, &len);
+            break;
+        case 24:
+            doRowDepth24(xelrow, rastRow, cols, format, maxval, &len);
+            break;
+        default:
+            pm_error("INTERNAL ERROR: impossible depth %u", depth);
+        }
+        {
+            /* Pad out the line (which has a rounded size) with zeroes so
+               the resulting file is repeatable.
+            */
+            unsigned int i;
+            for (i = len; i < lineSize; ++i)
+                rastRow[i] = 0;
+        }
+        rastRow += lineSize;
+    }
 }
 
 
 
 int
-main(int argc, char ** argv) {
+main(int argc, const char ** argv) {
 
-    FILE* ifp;
-    xel** xels;
-    xel* xelrow;
+    FILE * ifP;
+    xel ** xels;
     xel p;
-    register xel* xP;
     colorhist_vector chv;
     colorhash_table cht;
-    colormap_t* pr_colormapP;
-    int argn, pr_type, rows, cols, format, i;
-    int depth, colors, linesize, row;
-    register int col, bitcount;
+    colormap_t * prColormapP;
+    int argn;
+    int prType;
+    int rows, cols;
+    int format;
+    unsigned int depth;
+    int colorCt;
     xelval maxval;
-    struct pixrect* pr;
-    unsigned char* data;
-    register unsigned char* byteP;
-    const char* const usage = "[-standard|-rle] [pnmfile]";
+    struct pixrect * prP;
+    const char * const usage = "[-standard|-rle] [pnmfile]";
 
-    pnm_init( &argc, argv );
+    pm_proginit(&argc, argv);
 
     argn = 1;
-    pr_type = RT_BYTE_ENCODED;
+    prType = RT_BYTE_ENCODED;
 
     while ( argn < argc && argv[argn][0] == '-' && argv[argn][1] != '\0' )
     {
         if ( pm_keymatch( argv[argn], "-standard", 2 ) )
-            pr_type = RT_STANDARD;
+            prType = RT_STANDARD;
         else if ( pm_keymatch( argv[argn], "-rle", 2 ) )
-            pr_type = RT_BYTE_ENCODED;
+            prType = RT_BYTE_ENCODED;
         else
             pm_usage( usage );
         ++argn;
@@ -123,191 +305,96 @@ main(int argc, char ** argv) {
 
     if ( argn != argc )
     {
-        ifp = pm_openr( argv[argn] );
+        ifP = pm_openr( argv[argn] );
         ++argn;
     }
     else
-        ifp = stdin;
+        ifP = stdin;
 
     if ( argn != argc )
         pm_usage( usage );
 
-    xels = pnm_readpnm( ifp, &cols, &rows, &maxval, &format );
+    xels = pnm_readpnm(ifP, &cols, &rows, &maxval, &format);
 
-    pm_close( ifp );
+    pm_close(ifP);
 
     /* Figure out the proper depth and colormap. */
-    switch ( PNM_FORMAT_TYPE(format) )
-    {
+    switch (PNM_FORMAT_TYPE(format)) {
     case PPM_TYPE:
-        pm_message( "computing colormap..." );
-        chv = ppm_computecolorhist( xels, cols, rows, MAXCOLORS, &colors );
-        if ( chv == (colorhist_vector) 0 )
-        {
+        pm_message("computing colormap...");
+        chv = ppm_computecolorhist(xels, cols, rows, MAXCOLORS, &colorCt);
+        if (!chv) {
             pm_message(
-                "Too many colors - proceeding to write a 24-bit non-mapped" );
+                "Too many colors - proceeding to write a 24-bit non-mapped");
             pm_message(
                 "rasterfile.  If you want 8 bits, try doing a 'pnmquant %d'.",
-                MAXCOLORS );
+                MAXCOLORS);
             depth = 24;
-            pr_type = RT_STANDARD;
-            pr_colormapP = (colormap_t*) 0;
-        }
-        else
-        {
-            pm_message( "%d colors found", colors );
-
-            if ( maxval != 255 )
-                for ( i = 0; i < colors; ++i )
-                    PPM_DEPTH( chv[i].color, chv[i].color, maxval, 255 );
-
+            prType = RT_STANDARD;
+            prColormapP = NULL;
+        } else {
+            pm_message("%u colors found", colorCt);
+
+            if (maxval != 255) {
+                unsigned int i;
+                for (i = 0; i < colorCt; ++i)
+                    PPM_DEPTH(chv[i].color, chv[i].color, maxval, 255);
+            }
             /* Force white to slot 0 and black to slot 1, if possible. */
-            PPM_ASSIGN( p, 255, 255, 255 );
-            ppm_addtocolorhist( chv, &colors, MAXCOLORS, &p, 0, 0 );
-            PPM_ASSIGN( p, 0, 0, 0 );
-            ppm_addtocolorhist( chv, &colors, MAXCOLORS, &p, 0, 1 );
-
-            if ( colors == 2 )
-            {
-                /* Monochrome. */
+            PPM_ASSIGN(p, 255, 255, 255);
+            ppm_addtocolorhist(chv, &colorCt, MAXCOLORS, &p, 0, 0);
+            PPM_ASSIGN(p, 0, 0, 0);
+            ppm_addtocolorhist(chv, &colorCt, MAXCOLORS, &p, 0, 1);
+
+            if (colorCt == 2) {
+                /* Monochrome */
                 depth = 1;
-                pr_colormapP = (colormap_t*) 0;
-            }
-            else
-            {
+                prColormapP = NULL;
+            } else {
                 /* Turn the ppm colormap into the appropriate Sun colormap. */
                 depth = 8;
-                pr_colormapP = make_pr_colormap( chv, colors );
+                prColormapP = makePrColormap(chv, colorCt);
             }
-            cht = ppm_colorhisttocolorhash( chv, colors );
-            ppm_freecolorhist( chv );
+            cht = ppm_colorhisttocolorhash(chv, colorCt);
+            ppm_freecolorhist(chv);
         }
 
         break;
 
     case PGM_TYPE:
         depth = 8;
-        pr_colormapP = make_gray_pr_colormap( );
+        prColormapP = makeGrayPrColormap();
         break;
 
     default:
         depth = 1;
-        pr_colormapP = (colormap_t*) 0;
+        prColormapP = NULL;
         break;
     }
 
-    if ( maxval > 255 && depth != 1 )
+    if (maxval > 255 && depth != 1)
         pm_message(
-            "maxval is not 255 - automatically rescaling colors" );
+            "maxval is not 255 - automatically rescaling colors");
     
     /* Allocate space for the Sun-format image. */
-    if ( (pr = mem_create(cols, rows, depth)) == (struct pixrect*) 0 )
-        pm_error( "unable to create new pixrect" );
-    data = ( (struct mpr_data*) pr->pr_data )->md_image;
-    linesize = ( (struct mpr_data*) pr->pr_data )->md_linebytes;
-
-    /* And compute the Sun image.  The variables at this point are:
-    **   cht is null or not
-    **   depth is 1, 8, or 24
-    */
-    for ( row = 0; row < rows; ++row )
-    {
-        xelrow = xels[row];
-        byteP = data;
-        switch ( depth )
-        {
-        case 1:
-            *byteP = 0;
-            bitcount = 7;
-            for ( col = 0, xP = xelrow; col < cols; ++col, ++xP )
-            {
-                register int color;
-
-                switch ( PNM_FORMAT_TYPE(format) )
-                {
-                case PPM_TYPE:
-                    if ( maxval != 255 )
-                        PPM_DEPTH( *xP, *xP, maxval, 255 );
-                    color = ppm_lookupcolor( cht, xP );
-                    if ( color == -1 )
-                        pm_error(
-                            "color not found?!?  row=%d col=%d  r=%d g=%d b=%d",
-                            row, col, PPM_GETR(*xP), PPM_GETG(*xP),
-                            PPM_GETB(*xP) );
-                    if ( color )
-                        *byteP |= 1 << bitcount;
-                    break;
-
-                default:
-                    color = PNM_GET1( *xP );
-                    if ( ! color )
-                        *byteP |= 1 << bitcount;
-                    break;
-                }
-                --bitcount;
-                if ( bitcount < 0 )
-                {
-                    ++byteP;
-                    *byteP = 0;
-                    bitcount = 7;
-                }
-            }
-            break;
-
-        case 8:
-            for ( col = 0, xP = xelrow; col < cols; ++col, ++xP )
-            {
-                register int color;
-
-                switch ( PNM_FORMAT_TYPE(format) )
-                {
-                case PPM_TYPE:
-                    if ( maxval != 255 )
-                        PPM_DEPTH( *xP, *xP, maxval, 255 );
-                    color = ppm_lookupcolor( cht, xP );
-                    if ( color == -1 )
-                        pm_error(
-                            "color not found?!?  row=%d col=%d  r=%d g=%d b=%d",
-                            row, col, PPM_GETR(*xP), PPM_GETG(*xP),
-                            PPM_GETB(*xP) );
-                    break;
-
-                case PGM_TYPE:
-                    color = PNM_GET1( *xP );
-                    if ( maxval != 255 )
-                        color = color * 255 / maxval;
-                    break;
-
-                default:
-                    color = PNM_GET1( *xP );
-                }
-                *byteP++ = color;
-            }
-            break;
+    prP = mem_create(cols, rows, depth);
+    if (!prP)
+        pm_error("unable to create new pixrect");
 
-        case 24:
-            /* If depth is 24, we do NOT have a valid cht. */
-            for ( col = 0, xP = xelrow; col < cols; ++col, ++xP )
-            {
-                if ( maxval != 255 )
-                    PPM_DEPTH( *xP, *xP, maxval, 255 );
-                *byteP++ = PPM_GETB( *xP );
-                *byteP++ = PPM_GETG( *xP );
-                *byteP++ = PPM_GETR( *xP );
-            }
-            break;
+    computeRaster(prP->pr_data->md_image,
+                  prP->pr_data->md_linebytes,
+                  depth,
+                  cols, rows, format, maxval, xels, cht);
 
-        default:
-            pm_error( "can't happen" );
-        }
-        data += linesize;
-    }
-    pnm_freearray( xels, rows );
+    pnm_freearray(xels, rows);
 
-    /* Finally, write the sucker out. */
-    if ( pr_dump( pr, stdout, pr_colormapP, pr_type, 0 ) == PIX_ERR )
-        pm_error( "error writing rasterfile" );
+    {
+        int rc;
 
-    exit( 0 );
+        rc = pr_dump(prP, stdout, prColormapP, prType, 0);
+        if (rc == PIX_ERR )
+            pm_error("error writing rasterfile");
+    }
+    return 0;
 }
 
diff --git a/converter/other/rast.h b/converter/other/rast.h
index e79896ea..eb6f4ec4 100644
--- a/converter/other/rast.h
+++ b/converter/other/rast.h
@@ -49,7 +49,7 @@ struct rasterfile {
 #define RMT_EQUAL_RGB	1
 #define RMT_RAW		2
     long ras_maplength;
-    };
+};
 
 struct pixrectops {
     int	(*pro_rop)();
@@ -65,21 +65,22 @@ struct pixrectops {
     int	(*pro_getcolormap)();
     int	(*pro_putattributes)();
     int	(*pro_getattributes)();
-    };
+};
 
 struct pr_size {
     int x, y;
-    };
+};
+
 struct pr_pos {
     int x, y;
-    };
+};
 
 struct pixrect {
     struct pixrectops* pr_ops;
     struct pr_size pr_size;
     int pr_depth;
     struct mpr_data* pr_data;	/* work-alike only handles memory pixrects */
-    };
+};
 
 struct mpr_data {
     int md_linebytes;
@@ -87,13 +88,13 @@ struct mpr_data {
     struct pr_pos md_offset;
     short md_primary;
     short md_flags;
-    };
+};
 
 typedef struct {
     int type;
     int length;
     unsigned char* map[3];
-    } colormap_t;
+} colormap_t;
 
 /* And the routine definitions. */
 
diff --git a/converter/other/rasttopnm.c b/converter/other/rasttopnm.c
index 2d081489..285fc5e0 100644
--- a/converter/other/rasttopnm.c
+++ b/converter/other/rasttopnm.c
@@ -24,6 +24,8 @@ struct cmdlineInfo {
     */
     const char * inputFileName;
     unsigned int index;
+    unsigned int dumpheader;
+    unsigned int dumpcolormap;
 };
 
 
@@ -50,7 +52,12 @@ parseCommandLine(int argc, const char ** argv,
     opt.short_allowed = false;  /* We have no short (old-fashioned) options */
     opt.allowNegNum = false;  /* We have no parms that are negative numbers */
 
-    OPTENT3(0,   "index",     OPT_FLAG,   NULL, &cmdlineP->index,   0);
+    OPTENT3(0,   "index",        OPT_FLAG,   NULL,
+            &cmdlineP->index,          0);
+    OPTENT3(0,   "dumpheader",   OPT_FLAG,   NULL,
+            &cmdlineP->dumpheader,     0);
+    OPTENT3(0,   "dumpcolormap", OPT_FLAG,   NULL,
+            &cmdlineP->dumpcolormap,   0);
 
     pm_optParseOptions3(&argc, (char **)argv, opt, sizeof(opt), 0);
         /* Uses and sets argc, argv, and some of *cmdlineP and others. */
@@ -67,13 +74,14 @@ parseCommandLine(int argc, const char ** argv,
 
 
 static bool
-colorMapIsGrayscale(colormap_t   const colorMap,
-                    unsigned int const mapLength) {
-
+colorMapIsGrayscale(colormap_t const colorMap) {
+/*----------------------------------------------------------------------------
+   The color map contains only gray.
+-----------------------------------------------------------------------------*/
     unsigned int i;
     bool grayscale;
 
-    for (i = 0, grayscale = true; i < mapLength / 3; ++i) {
+    for (i = 0, grayscale = true; i < colorMap.length; ++i) {
         if (colorMap.map[0][i] != colorMap.map[1][i] ||
             colorMap.map[1][i] != colorMap.map[2][i]) {
             grayscale = false;
@@ -94,8 +102,7 @@ analyzeImage(struct rasterfile const header,
              xel *             const oneP) {
 
     bool const grayscale =
-        header.ras_maplength == 0 ||
-        colorMapIsGrayscale(colorMap, header.ras_maplength);
+        header.ras_maplength == 0 || colorMapIsGrayscale(colorMap);
 
     *grayscaleP = grayscale;
 
@@ -186,6 +193,117 @@ reportOutputType(int const format) {
 
 
 static void
+convertRowDepth1(const unsigned char * const rastLine,
+                 unsigned int          const cols,
+                 xel                   const zeroXel,
+                 xel                   const oneXel,
+                 xel *                 const xelrow) {
+
+    const unsigned char * byteP;
+     unsigned int col;
+    unsigned char mask;
+
+    byteP = rastLine;  /* initial value */
+
+    for (col = 0, mask = 0x80; col < cols; ++col) {
+        if (mask == 0x00) {
+            ++byteP;
+            mask = 0x80;
+        }
+        xelrow[col] = (*byteP & mask) ? oneXel : zeroXel;
+        mask = mask >> 1;
+    }
+}
+
+
+
+static void
+convertRowDepth8(const unsigned char * const lineStart,
+                 unsigned int          const cols,
+                 bool                  const colorMapped,
+                 bool                  const useIndexForColor,
+                 bool                  const grayscale,
+                 colormap_t            const colorMap,
+                 xel *                 const xelrow) {
+/*----------------------------------------------------------------------------
+   Convert a line of raster data from the RAST input to a row of raster
+   data for the PNM output.
+
+   'lineStart' is where the RAST row starts.   'xelrow' is where to put the
+   PNM row.  'cols' is the number of pixels in the row.
+
+   'colorMapped' means the RAST image is colormapped.  If so, 'colorMap'
+   is the color map from the RAST file and 'useIndexForColor' means not
+   to use that map but instead to create a PGM row of the colormap
+   _indices_.
+
+   'grayscale' means it is a grayscale image; the output is PGM.
+-----------------------------------------------------------------------------*/
+    const unsigned char * byteP;
+    unsigned int col;
+
+    byteP = lineStart; /* initial value */
+
+    for (col = 0; col < cols; ++col) {
+        if (colorMapped && !useIndexForColor) {
+            if (grayscale)
+                PNM_ASSIGN1(xelrow[col], colorMap.map[0][*byteP]);
+            else
+                PPM_ASSIGN(xelrow[col],
+                           colorMap.map[0][*byteP],
+                           colorMap.map[1][*byteP],
+                           colorMap.map[2][*byteP]);
+        } else
+            PNM_ASSIGN1(xelrow[col], *byteP);
+
+        ++byteP;
+    }
+} 
+
+
+
+static void
+convertRowRgb(const unsigned char * const lineStart,
+              unsigned int          const cols,
+              unsigned int          const depth,
+              long                  const rastType,
+              bool                  const colorMapped,
+              bool                  const useIndexForColor,
+              colormap_t            const colorMap,
+              xel *                 const xelrow) {
+
+    const unsigned char * byteP;
+    unsigned int col;
+
+    byteP = lineStart; /* initial value */
+
+    for (col = 0; col < cols; ++col) {
+        xelval r, g, b;
+
+        if (depth == 32)
+            ++byteP;
+        if (rastType == RT_FORMAT_RGB) {
+            r = *byteP++;
+            g = *byteP++;
+            b = *byteP++;
+        } else {
+            b = *byteP++;
+            g = *byteP++;
+            r = *byteP++;
+        }
+        if (colorMapped && !useIndexForColor)
+            PPM_ASSIGN(xelrow[col],
+                       colorMap.map[0][r],
+                       colorMap.map[1][g],
+                       colorMap.map[2][b]);
+        else
+            PPM_ASSIGN(xelrow[col], r, g, b);
+    }
+} 
+
+
+
+static void
 writePnm(FILE *                 const ofP,
          const struct pixrect * const pixRectP,
          unsigned int           const cols,
@@ -201,10 +319,7 @@ writePnm(FILE *                 const ofP,
          xel                    const oneXel,
          bool                   const useIndexForColor) {
 
-    unsigned int const lineSize =
-        ((struct mpr_data*) pixRectP->pr_data)->md_linebytes;
-    unsigned char * const data =
-        ((struct mpr_data*) pixRectP->pr_data)->md_image;
+    struct mpr_data const mprData = *pixRectP->pr_data;
 
     xel * xelrow;
     unsigned int row;
@@ -216,66 +331,23 @@ writePnm(FILE *                 const ofP,
 
     reportOutputType(format);
 
-    for (row = 0, lineStart = data; row < rows; ++row, lineStart += lineSize) {
-        unsigned char * byteP;
-
-        byteP = lineStart; /* initial value */
+    for (row = 0, lineStart = mprData.md_image;
+         row < rows;
+         ++row, lineStart += mprData.md_linebytes) {
 
         switch (depth) {
-        case 1: {
-            unsigned int col;
-            unsigned char mask;
-            for (col = 0, mask = 0x80; col < cols; ++col) {
-                if (mask == 0x00) {
-                    ++byteP;
-                    mask = 0x80;
-                }
-                xelrow[col] = (*byteP & mask) ? oneXel : zeroXel;
-                mask = mask >> 1;
-            }
-        } break;
-        case 8: {
-            unsigned int col;
-            for (col = 0; col < cols; ++col) {
-                if (colorMapped && !useIndexForColor)
-                    if (grayscale)
-                        PNM_ASSIGN1(xelrow[col], colorMap.map[0][*byteP]);
-                    else
-                        PPM_ASSIGN(xelrow[col],
-                                   colorMap.map[0][*byteP],
-                                   colorMap.map[1][*byteP],
-                                   colorMap.map[2][*byteP]);
-                else
-                    PNM_ASSIGN1(xelrow[col], *byteP);
-                ++byteP;
-            }
-        } break;
+        case 1:
+            convertRowDepth1(lineStart, cols, zeroXel, oneXel, xelrow);
+            break;
+        case 8:
+            convertRowDepth8(lineStart, cols, colorMapped, useIndexForColor,
+                             grayscale, colorMap, xelrow);
+            break;
         case 24:
-        case 32: {
-            unsigned int col;
-            for (col = 0; col < cols; ++col) {
-                xelval r, g, b;
-
-                if (depth == 32)
-                    ++byteP;
-                if (rastType == RT_FORMAT_RGB) {
-                    r = *byteP++;
-                    g = *byteP++;
-                    b = *byteP++;
-                } else {
-                    b = *byteP++;
-                    g = *byteP++;
-                    r = *byteP++;
-                }
-                if (colorMapped && !useIndexForColor)
-                    PPM_ASSIGN(xelrow[col],
-                               colorMap.map[0][r],
-                               colorMap.map[1][g],
-                               colorMap.map[2][b]);
-                else
-                    PPM_ASSIGN(xelrow[col], r, g, b);
-            }
-        } break;
+        case 32:
+            convertRowRgb(lineStart, cols, depth, rastType, colorMapped,
+                          useIndexForColor, colorMap, xelrow);
+            break;
         default:
             pm_error("Invalid depth value: %u", depth);
         }
@@ -285,6 +357,84 @@ writePnm(FILE *                 const ofP,
 
 
 
+static void
+dumpHeader(struct rasterfile const header) {
+
+    const char * typeName;
+
+    switch (header.ras_type) {
+    case RT_OLD:            typeName = "old";           break;
+    case RT_STANDARD:       typeName = "standard";      break;
+    case RT_BYTE_ENCODED:   typeName = "byte encoded";  break;
+    case RT_FORMAT_RGB:     typeName = "format rgb";    break;
+    case RT_FORMAT_TIFF:    typeName = "format_tiff";   break;
+    case RT_FORMAT_IFF:     typeName = "format_iff";    break;
+    case RT_EXPERIMENTAL:   typeName = "experimental";  break;
+    default:                typeName = "???";
+    }
+
+    pm_message("type: %s (%lu)", typeName, (unsigned long)header.ras_type);
+    pm_message("%luw x %lul x %lud",
+               (unsigned long)header.ras_width,
+               (unsigned long)header.ras_height,
+               (unsigned long)header.ras_depth);
+    pm_message("raster length: %lu", (unsigned long)header.ras_length);
+
+    if (header.ras_maplength)
+        pm_message("Has color map");
+}
+
+
+
+static void
+dumpHeaderAnalysis(bool         const grayscale, 
+                   unsigned int const depth,
+                   xel          const zero, 
+                   xel          const one) {
+
+    pm_message("grayscale: %s", grayscale ? "YES" : "NO");
+
+    if (depth == 1) {
+        pm_message("Zero color: (%u,%u,%u)",
+                   PNM_GETR(zero),
+                   PNM_GETG(zero),
+                   PNM_GETB(zero));
+
+        pm_message("One color: (%u,%u,%u)",
+                   PNM_GETR(one),
+                   PNM_GETG(one),
+                   PNM_GETB(one));
+    }
+}
+
+
+
+static void
+dumpColorMap(colormap_t const colorMap) {
+
+    unsigned int i;
+    const char * typeName;
+
+    switch (colorMap.type) {
+    case RMT_NONE:      typeName = "NONE";      break;
+    case RMT_EQUAL_RGB: typeName = "EQUAL_RGB"; break;
+    case RMT_RAW:       typeName = "RAW";       break;
+    default:            typeName = "???";
+    }
+
+    pm_message("color map type = %s (%u)", typeName, colorMap.type);
+
+    pm_message("color map size = %u", colorMap.length);
+
+    for (i = 0; i < colorMap.length; ++i)
+        pm_message("color %u: (%u, %u, %u)", i,
+                   (unsigned char)colorMap.map[0][i],
+                   (unsigned char)colorMap.map[1][i],
+                   (unsigned char)colorMap.map[2][i]);
+}
+
+
+
 int
 main(int argc, const char ** const argv) {
 
@@ -309,6 +459,9 @@ main(int argc, const char ** const argv) {
     if (rc != 0 )
         pm_error("unable to read in rasterfile header");
 
+    if (cmdline.dumpheader)
+        dumpHeader(header);
+
     if (header.ras_maplength != 0) {
         int rc;
         
@@ -316,10 +469,16 @@ main(int argc, const char ** const argv) {
         
         if (rc != 0 )
             pm_error("unable to read colormap from RAST file");
+
+        if (cmdline.dumpcolormap)
+            dumpColorMap(colorMap);
     }
 
     analyzeImage(header, colorMap, &format, &maxval, &grayscale, &zero, &one);
 
+    if (cmdline.dumpheader)
+        dumpHeaderAnalysis(grayscale, header.ras_depth, zero, one);
+
     pr = pr_load_image(ifP, &header, NULL);
     if (pr == NULL )
         pm_error("unable to read in the image from the rasterfile" );
diff --git a/converter/other/tifftopnm.c b/converter/other/tifftopnm.c
index 679dff71..fcfb03f6 100644
--- a/converter/other/tifftopnm.c
+++ b/converter/other/tifftopnm.c
@@ -1350,7 +1350,7 @@ warnBrokenTiffLibrary(TIFF * const tiffP) {
         case ORIENTATION_RIGHTBOT:
         case ORIENTATION_LEFTBOT:
             pm_message("WARNING: This TIFF image has an orientation that "
-                       "most TIFF libraries converts incorrectly.  "
+                       "most TIFF libraries convert incorrectly.  "
                        "Use -byrow to circumvent.");
             break;
         }
diff --git a/converter/ppm/ppmtompeg/headers/dct.h b/converter/ppm/ppmtompeg/headers/dct.h
index e024b6c1..d5ea9f4a 100644
--- a/converter/ppm/ppmtompeg/headers/dct.h
+++ b/converter/ppm/ppmtompeg/headers/dct.h
@@ -47,6 +47,7 @@ typedef DCTELEM DCTBLOCK_2D[DCTSIZE][DCTSIZE];
 /*  
  *  from mfwddct.c:
  */
+void init_fdct _ANSI_ARGS_((void));
 extern void mp_fwd_dct_block2 _ANSI_ARGS_((DCTBLOCK_2D src, DCTBLOCK_2D dest));
 
 /* jrevdct.c */
diff --git a/converter/ppm/ppmtompeg/headers/general.h b/converter/ppm/ppmtompeg/headers/general.h
index e41e2adb..59c33c73 100644
--- a/converter/ppm/ppmtompeg/headers/general.h
+++ b/converter/ppm/ppmtompeg/headers/general.h
@@ -111,15 +111,7 @@ int pclose();
 #define NEWLINE '\n'
 
 
-/*==================*
- * TYPE DEFINITIONS *
- *==================*/
-
-#ifndef HAVE_BOOLEAN
 typedef int boolean;
-#define HAVE_BOOLEAN
-/* JPEG library also defines boolean */
-#endif
 
 /* In the following, we need the "signed" in order to make these typedefs
    match those in AIX system header files.  Otherwise, compile fails on 
diff --git a/converter/ppm/ppmtompeg/mfwddct.c b/converter/ppm/ppmtompeg/mfwddct.c
index 4643bf25..75c3a718 100644
--- a/converter/ppm/ppmtompeg/mfwddct.c
+++ b/converter/ppm/ppmtompeg/mfwddct.c
@@ -122,33 +122,68 @@
 #define OSIN_5_16 OCOS_3_16
 #define OCOS_5_16 OSIN_3_16
 
-/* Prototypes */
-void reference_fwd_dct _ANSI_ARGS_((Block block, Block dest));
-void mp_fwd_dct_fast _ANSI_ARGS_((Block data2d, Block dest2d));
-void init_fdct _ANSI_ARGS_((void));
 
-/*
- * --------------------------------------------------------------
- *
- * mp_fwd_dct_block2 --
- *
- * Select the appropriate mp_fwd_dct routine
- *
- * Results: None
- *
- * Side effects: None
- *
- * --------------------------------------------------------------
- */
-extern boolean pureDCT;
-void
-mp_fwd_dct_block2(data, dest)
-    Block data, dest;
+static double trans_coef[8][8]; /* transform coefficients */
+
+
+
+static void reference_fwd_dct(block, dest)
+Block block, dest;
 {
-  if (pureDCT) reference_fwd_dct(data, dest);
-  else mp_fwd_dct_fast(data, dest);
+  int i, j, k;
+  double s;
+  double tmp[64];
+
+  if (DoLaplace) {
+    LaplaceNum++;
+  }
+
+  for (i=0; i<8; i++)
+    for (j=0; j<8; j++)
+    {
+      s = 0.0;
+
+      for (k=0; k<8; k++)
+        s += trans_coef[j][k] * block[i][k];
+
+      tmp[8*i+j] = s;
+    }
+
+  for (i=0; i<8; i++)
+    for (j=0; j<8; j++)
+    {
+      s = 0.0;
+
+      for (k=0; k<8; k++)
+        s += trans_coef[i][k] * tmp[8*k+j];
+
+      if (collect_quant) {
+	fprintf(collect_quant_fp, "%d %f\n", 8*i+j, s);
+      } 
+      if (DoLaplace) {
+	L1[LaplaceCnum][i*8+j] += s*s;
+	L2[LaplaceCnum][i*8+j] += s;
+      }
+
+
+      dest[i][j] = (int)floor(s+0.499999);
+      /*
+       * reason for adding 0.499999 instead of 0.5:
+       * s is quite often x.5 (at least for i and/or j = 0 or 4)
+       * and setting the rounding threshold exactly to 0.5 leads to an
+       * extremely high arithmetic implementation dependency of the result;
+       * s being between x.5 and x.500001 (which is now incorrectly rounded
+       * downwards instead of upwards) is assumed to occur less often
+       * (if at all)
+       */
+    }
 }
 
+
+
+static void
+mp_fwd_dct_fast(data2d, dest2d)
+    Block data2d, dest2d;
 /*
  * --------------------------------------------------------------
  *
@@ -166,9 +201,6 @@ mp_fwd_dct_block2(data, dest)
  * --------------------------------------------------------------
  */
 
-void
-mp_fwd_dct_fast(data2d, dest2d)
-    Block data2d, dest2d;
 {
     int16 *data = (int16 *) data2d;	/* this algorithm wants
 					 * a 1-d array */
@@ -236,10 +268,12 @@ mp_fwd_dct_fast(data2d, dest2d)
 	    tmp13 = tmp0 - tmp3;
 
 	    outptr[0] = (int16) UNFIXH((tmp10 + tmp11) * SIN_1_4);
-	    outptr[DCTSIZE * 4] = (int16) UNFIXH((tmp10 - tmp11) * COS_1_4);
-
-	    outptr[DCTSIZE * 2] = (int16) UNFIXH(tmp13 * COS_1_8 + tmp12 * SIN_1_8);
-	    outptr[DCTSIZE * 6] = (int16) UNFIXH(tmp13 * SIN_1_8 - tmp12 * COS_1_8);
+	    outptr[DCTSIZE * 4] =
+            (int16) UNFIXH((tmp10 - tmp11) * COS_1_4);
+	    outptr[DCTSIZE * 2] =
+            (int16) UNFIXH(tmp13 * COS_1_8 + tmp12 * SIN_1_8);
+	    outptr[DCTSIZE * 6] =
+            (int16) UNFIXH(tmp13 * SIN_1_8 - tmp12 * COS_1_8);
 
 	    tmp16 = UNFIXO((tmp6 + tmp5) * SIN_1_4);
 	    tmp15 = UNFIXO((tmp6 - tmp5) * COS_1_4);
@@ -257,10 +291,14 @@ mp_fwd_dct_fast(data2d, dest2d)
 	    tmp26 = tmp7 - tmp16;
 	    tmp17 = tmp7 + tmp16;
 
-	    outptr[DCTSIZE] = (int16) UNFIXH(tmp17 * OCOS_1_16 + tmp14 * OSIN_1_16);
-	    outptr[DCTSIZE * 7] = (int16) UNFIXH(tmp17 * OCOS_7_16 - tmp14 * OSIN_7_16);
-	    outptr[DCTSIZE * 5] = (int16) UNFIXH(tmp26 * OCOS_5_16 + tmp25 * OSIN_5_16);
-	    outptr[DCTSIZE * 3] = (int16) UNFIXH(tmp26 * OCOS_3_16 - tmp25 * OSIN_3_16);
+	    outptr[DCTSIZE] =
+            (int16) UNFIXH(tmp17 * OCOS_1_16 + tmp14 * OSIN_1_16);
+	    outptr[DCTSIZE * 7] =
+            (int16) UNFIXH(tmp17 * OCOS_7_16 - tmp14 * OSIN_7_16);
+	    outptr[DCTSIZE * 5] =
+            (int16) UNFIXH(tmp26 * OCOS_5_16 + tmp25 * OSIN_5_16);
+	    outptr[DCTSIZE * 3] =
+            (int16) UNFIXH(tmp26 * OCOS_3_16 - tmp25 * OSIN_3_16);
 
 	    inptr += DCTSIZE;	/* advance inptr to next row */
 	    outptr++;		/* advance outptr to next column */
@@ -285,6 +323,28 @@ mp_fwd_dct_fast(data2d, dest2d)
 }
 
 
+extern boolean pureDCT;
+void
+mp_fwd_dct_block2(data, dest)
+    DCTBLOCK_2D data, dest;
+/*
+ * --------------------------------------------------------------
+ *
+ * mp_fwd_dct_block2 --
+ *
+ * Select the appropriate mp_fwd_dct routine
+ *
+ * Results: None
+ *
+ * Side effects: None
+ *
+ * --------------------------------------------------------------
+ */
+{
+  if (pureDCT) reference_fwd_dct(data, dest);
+  else mp_fwd_dct_fast(data, dest);
+}
+
 /* Modifies from the MPEG2 verification coder */
 /* fdctref.c, forward discrete cosine transform, double precision           */
 
@@ -323,9 +383,6 @@ mp_fwd_dct_fast(data2d, dest2d)
 #endif
 #endif
 
-/* private data */
-static double trans_coef[8][8]; /* transform coefficients */
-
 void init_fdct()
 {
   int i, j;
@@ -340,54 +397,5 @@ void init_fdct()
   }
 }
 
-void reference_fwd_dct(block, dest)
-Block block, dest;
-{
-  int i, j, k;
-  double s;
-  double tmp[64];
-
-  if (DoLaplace) {
-    LaplaceNum++;
-  }
-
-  for (i=0; i<8; i++)
-    for (j=0; j<8; j++)
-    {
-      s = 0.0;
-
-      for (k=0; k<8; k++)
-        s += trans_coef[j][k] * block[i][k];
 
-      tmp[8*i+j] = s;
-    }
 
-  for (i=0; i<8; i++)
-    for (j=0; j<8; j++)
-    {
-      s = 0.0;
-
-      for (k=0; k<8; k++)
-        s += trans_coef[i][k] * tmp[8*k+j];
-
-      if (collect_quant) {
-	fprintf(collect_quant_fp, "%d %f\n", 8*i+j, s);
-      } 
-      if (DoLaplace) {
-	L1[LaplaceCnum][i*8+j] += s*s;
-	L2[LaplaceCnum][i*8+j] += s;
-      }
-
-
-      dest[i][j] = (int)floor(s+0.499999);
-      /*
-       * reason for adding 0.499999 instead of 0.5:
-       * s is quite often x.5 (at least for i and/or j = 0 or 4)
-       * and setting the rounding threshold exactly to 0.5 leads to an
-       * extremely high arithmetic implementation dependency of the result;
-       * s being between x.5 and x.500001 (which is now incorrectly rounded
-       * downwards instead of upwards) is assumed to occur less often
-       * (if at all)
-       */
-    }
-}
diff --git a/converter/ppm/ppmtompeg/opts.c b/converter/ppm/ppmtompeg/opts.c
index 5b92d829..9eee971f 100644
--- a/converter/ppm/ppmtompeg/opts.c
+++ b/converter/ppm/ppmtompeg/opts.c
@@ -40,6 +40,7 @@
 #include <stdlib.h>
 #include <math.h>
 #include "opts.h"
+#include "dct.h"
 
 /*==============*
  * EXTERNALS    *
@@ -52,7 +53,6 @@ extern int     ZAG[];
 extern boolean printSNR, decodeRefFrames;
 
 void init_idctref _ANSI_ARGS_((void));
-void init_fdct _ANSI_ARGS_((void));
 
 
 /*===================*
diff --git a/converter/ppm/ppmtompeg/ppmtompeg.c b/converter/ppm/ppmtompeg/ppmtompeg.c
index 1440d88c..6e7e9833 100644
--- a/converter/ppm/ppmtompeg/ppmtompeg.c
+++ b/converter/ppm/ppmtompeg/ppmtompeg.c
@@ -36,6 +36,7 @@
 
 #include "all.h"
 #include "mtypes.h"
+#include "dct.h"
 #include "mpeg.h"
 #include "motion_search.h"
 #include "prototypes.h"
@@ -92,7 +93,6 @@ const char * hostname;
  *================================*/
 
 void init_idctref _ANSI_ARGS_((void));
-void init_fdct _ANSI_ARGS_((void));
 
 
 struct cmdlineInfo {
diff --git a/doc/COPYRIGHT.PATENT b/doc/COPYRIGHT.PATENT
index fe3c242a..24b1583a 100644
--- a/doc/COPYRIGHT.PATENT
+++ b/doc/COPYRIGHT.PATENT
@@ -34,92 +34,7 @@ all the above to be modified by "to the best of the Netpbm
 maintainer's knowledge."
 
 
-
-PATENTS
--------
-
-These are the patents the Netpbm maintainer knows about that relate to
-Netpbm.  It is basically just information the maintainer has stumbled
-over at some point -- no search has been done.
-
-No licenses have been granted by patent owners to the maintainer of
-Netpbm.  Therefore, if you need a patent to use something in Netpbm,
-you need your own license.
-
-A note about patents in general: A patent gives an inventor the
-exclusive right to make, sell, or use the invention.  If you
-independently invent something without knowing that the patent holder
-already did, that makes no difference -- the patent holder still has
-the exclusive right.  It makes no difference if you give the original
-inventor credit.  The patent applies to a method, not its expression,
-so writing a program from scratch to implement a certain method is
-still a patent infringement.  Infringing a patent is not a crime per
-se, but to the extent that it costs the patent holder money, the
-infringer has to make it up.
-
-The original purpose of patents is probably perverted when patents are
-applied to things you implement in computer programs.  This is one of
-the Free Software Foundation's causes.  See 
-<http://www.gnu.org/philosophy.html#laws>.
-
-
-Unisys owns patents on LZW compression, which is used by Ppmtogif, and
-maybe on LZW decompression, which is used by Giftopnm.  IBM also owns
-a patent that may cover the GIF tools.  Unisys offers a license of the
-patent for trivial use for $5000.  Its U.S. patent (Number 4,558,302)
-EXPIRED June 20, 2003.  In most of Europe, the patent expires June 18,
-2004.  In Japan, it's June 20, 2004 and in Canada, July 7, 2004.
-IBM's U.S. patent expirs August 11, 2006.
-
-Neither company has ever enforced the patent against trivial users of
-it.  <http://news.cnet.com/news/0-1005-200-1713278.html> is an article
-dated April 18, 2000 on the issue.
-http://www.unisys.com/about__unisys/lzw/> is Unisys' view of the
-matter.  For information from another perspective, see
-<http://burnallgifs.org>.
-
-The following Netpbm components may be restricted by these patents:
-Ppmtogif, Giftopnm.
-
-A good substitute for GIF if the patents are a problem is PNG (see
-pngtopnm, pnmtopng), which was developed with a primary purpose of not
-using any patented technology.
-
-You can also use the -nolzw option on ppmtogif to avoid using the LZW
-patent.  The images so generated are larger than traditional
-LZW-compressed GIFs, but any GIF decoder can decode them just the
-same.
-
-I repeat: The Unisys U.S. patent has expired.  It is not an issue
-for any future use of Netpbm.
-
-
-The Pnmtojpeg and possibly Jpegtopnm programs in some cases may use
-the arithmetic coding patents owned by IBM, AT&T, and Mitsubishi.
-There is difference of opinion on whether they do.
-
-Forgent owns a patent it believes covers JPEG compression.  This
-patent was virtually unknown before July 2002, when Forgent began to
-enforce it.  It has successfully enforced it against two companies
-(Sony and an unnamed Japanese digital camera maker), but without court
-ruling.  This patent, U.S. Patent No. 4,698,672, expires in 2006.
-
-Philips and Lucent Technologies also own patents they claim cover
-JPEG.
-
-The following Netpbm components may be restricted by these patents:
-Jpegtopnm, Pnmtojpeg, Ppmtompeg, Tifftopnm, Pnmtotiff.  These all
-do their JPEG work via a JPEG library not distributed with Netpbm.
-Your JPEG-related liability for using Netpbm is limited to your 
-liability for using your JPEG library.
-
-The next best alternative to JPEG is probably PNG and maybe JBIG for
-bilevel (black and white) images.
-
-http://burnalljpegs.org contains information on this issue.
-
-
-The Jbigtopnm and Pnmtojbig programs use arithmetic coding patents and
-other patents covering various aspects of the "front end."
-
-
+Netpbm may practice valid patents, which would mean that you owe someone
+royalties if you use the code.  This is a miniscule risk, though.
+What is known about patents related to Netpbm is in the file
+'doc/patent_summary' in the Netpbm source tree.
diff --git a/doc/HISTORY b/doc/HISTORY
index 13dea532..becb0ba6 100644
--- a/doc/HISTORY
+++ b/doc/HISTORY
@@ -4,31 +4,28 @@ Netpbm.
 CHANGE HISTORY 
 --------------
 
-13.02.26 BJH  Release 10.61.04
+12.03.28 BJH  Release 10.62.00
 
-              rasttopnm: fix bug: incorrect output due to used-before-set
-              variable.  Introduced in 10.56 (September 2011).
-
-13.02.23 BJH  Release 10.61.03
-
-              Fix to 10.61.02 MinGW build fix.
-
-13.02.20 BJH  Release 10.61.02
-
-              MinGW build: various fixes.
+              pnmtorast: set don't care bytes to zero to make output
+              repeatable.
 
-12.12.31 BJH  Release 10.61.01
+              rasttopnm: add -dumpheader, dumpcolormap.
 
               pamstereogram: change -guidesize default from 10 to 20
-              (relevant since 10.61.00).
+              (relevant since 10.61).
+
+              rasttopnm: fix bug: incorrect output due to used-before-set
+              variable.  Introduced in 10.56 (September 2011).
 
               pamstereogram: fix bug: doesn't reject negative guidesize.
-              Broken since 10.61.00.
+              Broken since 10.61.
 
               pamstereogram: fix bug: garbage in -verbose listing.  Broken
-              since 10.61.00
+              since 10.61
+
+              MinGW build: various fixes.
 
-12.12.31 BJH  Release 10.61.00
+12.12.30 BJH  Release 10.61.00
 
               pgmhist: Add -machine option.
 
diff --git a/doc/patent_summary b/doc/patent_summary
new file mode 100644
index 00000000..271f227c
--- /dev/null
+++ b/doc/patent_summary
@@ -0,0 +1,85 @@
+These are the patents the Netpbm maintainer knows about that relate to
+Netpbm.  It is basically just information the maintainer has stumbled
+over at some point -- no search has been done.
+
+No licenses have been granted by patent owners to the maintainer of
+Netpbm.  Therefore, if you need a patent to use something in Netpbm,
+you need your own license.
+
+A note about patents in general: A patent gives an inventor the
+exclusive right to make, sell, or use the invention.  If you
+independently invent something without knowing that the patent holder
+already did, that makes no difference -- the patent holder still has
+the exclusive right.  It makes no difference if you give the original
+inventor credit.  The patent applies to a method, not its expression,
+so writing a program from scratch to implement a certain method is
+still a patent infringement.  Infringing a patent is not a crime per
+se, but to the extent that it costs the patent holder money, the
+infringer has to make it up.
+
+The original purpose of patents is probably perverted when patents are
+applied to things you implement in computer programs.  This is one of
+the Free Software Foundation's causes.  See 
+<http://www.gnu.org/philosophy.html#laws>.
+
+The Jbigtopnm and Pnmtojbig programs use arithmetic coding patents and
+other patents covering various aspects of the "front end."
+
+
+JPEG patents
+------------
+
+The Pnmtojpeg and possibly Jpegtopnm programs in some cases may use
+the arithmetic coding patents owned by IBM, AT&T, and Mitsubishi.
+There is difference of opinion on whether they do.
+
+Forgent owns a patent it believes covers JPEG compression.  This
+patent was virtually unknown before July 2002, when Forgent began to
+enforce it.  It has successfully enforced it against two companies
+(Sony and an unnamed Japanese digital camera maker), but without court
+ruling.  This patent, U.S. Patent No. 4,698,672, expires in 2006.
+
+Philips and Lucent Technologies also own patents they claim cover
+JPEG.
+
+The following Netpbm components may be restricted by these patents:
+Jpegtopnm, Pnmtojpeg, Ppmtompeg, Tifftopnm, Pnmtotiff.  These all
+do their JPEG work via a JPEG library not distributed with Netpbm.
+Your JPEG-related liability for using Netpbm is limited to your 
+liability for using your JPEG library.
+
+The next best alternative to JPEG is probably PNG and maybe JBIG for
+bilevel (black and white) images.
+
+http://burnalljpegs.org contains information on this issue.
+
+
+Expired LZW patents
+-------------------
+
+Unisys owns patents on LZW compression, which is used by
+Ppmtogif, and maybe on LZW decompression, which is used by Giftopnm.  IBM also
+owns a patent that may cover the GIF tools.  Unisys offers a license of the
+patent for trivial use for $5000.  Its U.S. patent (Number 4,558,302) expired
+June 20, 2003.  In most of Europe, the patent expired June 18, 2004.  In
+Japan, it was June 20, 2004 and in Canada, July 7, 2004.  IBM's U.S. patent
+expired August 11, 2006.
+
+Neither company has ever enforced the patent against trivial users of
+it.  <http://news.cnet.com/news/0-1005-200-1713278.html> is an article
+dated April 18, 2000 on the issue.
+http://www.unisys.com/about__unisys/lzw/> is Unisys' view of the
+matter.  For information from another perspective, see
+<http://burnallgifs.org>.
+
+The following Netpbm components may be restricted by these patents:
+Ppmtogif, Giftopnm.
+
+A good substitute for GIF if the patents are a problem is PNG (see
+pngtopnm, pnmtopng), which was developed with a primary purpose of not
+using any patented technology.
+
+You can also use the -nolzw option on ppmtogif to avoid using the LZW
+patent.  The images so generated are larger than traditional
+LZW-compressed GIFs, but any GIF decoder can decode them just the
+same.
diff --git a/generator/pamstereogram.c b/generator/pamstereogram.c
index ac71c702..6bcababa 100644
--- a/generator/pamstereogram.c
+++ b/generator/pamstereogram.c
@@ -762,10 +762,10 @@ drawguides(unsigned int       const guidesize,
 /*----------------------------------------------------------------------------
    Draw a pair of guide boxes, left and right.
 -----------------------------------------------------------------------------*/
-    int const far = separation(0, eyesep, dpi, depthOfField);
+    unsigned int const far = separation(0, eyesep, dpi, depthOfField);
         /* Space between the two guide boxes. */
-    int const width = outPamP->width;    /* Width of the output image */
-
+    unsigned int const width = outPamP->width;  /* Width of the output image */
+    
     tuple * outrow;             /* One row of output data */
     tuple blackTuple;
     unsigned int col;
@@ -874,8 +874,8 @@ makeStereoRow(const struct pam * const inPamP,
             } while (visible && zt < 1);
 
             if (visible) {
-                int l;
-
+                unsigned int l;
+                
                 l = same[left];
                 while (l != left && l != right) {
                     if (l < right) {
@@ -979,18 +979,20 @@ averageFromPattern(struct pam *         const pamP,
        every column that should have the same color.
     */
     for (col = pamP->width-1; col >= 0; --col) {
-        tuple onetuple = textureRow[(col+same[col])/2];
-        int targetcol = sameFp[col];
+        tuple const onetuple = textureRow[(col+same[col])/2];
+        unsigned int const targetcol = sameFp[col];
         int eqcol;
 
-        if (!pnm_tupleequal(pamP, onetuple, bgColor))
-            for (eqcol = pamP->width-1; eqcol >= 0; --eqcol)
+        if (!pnm_tupleequal(pamP, onetuple, bgColor)) {
+            for (eqcol = pamP->width-1; eqcol >= 0; --eqcol) {
                 if (sameFp[eqcol] == targetcol) {
                     unsigned int plane;
                     for (plane = 0; plane < pamP->depth; ++plane)
                         outRow[eqcol][plane] += onetuple[plane];
                     tuplesInCol[eqcol]++;
                 }
+            }
+        }
     }
     /* Take the average of all colors associated with each column.
        Tuples that can be any color are assigned the same color as was
diff --git a/version.mk b/version.mk
index b731924a..62cf5c53 100644
--- a/version.mk
+++ b/version.mk
@@ -1,4 +1,4 @@
 NETPBM_MAJOR_RELEASE = 10
-NETPBM_MINOR_RELEASE = 61
-NETPBM_POINT_RELEASE = 4
+NETPBM_MINOR_RELEASE = 62
+NETPBM_POINT_RELEASE = 0