about summary refs log tree commit diff
path: root/lib
diff options
context:
space:
mode:
authorgiraffedata <giraffedata@9d0c8265-081b-0410-96cb-a4ca84ce46f8>2019-03-30 15:18:58 +0000
committergiraffedata <giraffedata@9d0c8265-081b-0410-96cb-a4ca84ce46f8>2019-03-30 15:18:58 +0000
commitaad47e743f21763ac13b73eb927ad7d001254572 (patch)
tree2be395fe14e199ac00f002dc8b0ded2f0304c557 /lib
parentb10a418cefe3413a727b89300848dc84e8a6195d (diff)
downloadnetpbm-mirror-aad47e743f21763ac13b73eb927ad7d001254572.tar.gz
netpbm-mirror-aad47e743f21763ac13b73eb927ad7d001254572.tar.xz
netpbm-mirror-aad47e743f21763ac13b73eb927ad7d001254572.zip
Promote Development to Advanced
git-svn-id: http://svn.code.sf.net/p/netpbm/code/advanced@3587 9d0c8265-081b-0410-96cb-a4ca84ce46f8
Diffstat (limited to 'lib')
-rw-r--r--lib/Makefile15
-rw-r--r--lib/colorname.c6
-rw-r--r--lib/libpamcolor.c4
-rw-r--r--lib/libpamn.c17
-rw-r--r--lib/libpgm.h6
-rw-r--r--lib/libpnm3.c293
-rw-r--r--lib/libppmcolor.c6
-rw-r--r--lib/pam.h7
-rw-r--r--lib/pgm.h38
-rw-r--r--lib/pnm.h53
-rw-r--r--lib/ppm.h3
-rw-r--r--lib/util/pm_c_util.h7
-rw-r--r--lib/util/shhopt.h34
13 files changed, 295 insertions, 194 deletions
diff --git a/lib/Makefile b/lib/Makefile
index 65177758..bc758df4 100644
--- a/lib/Makefile
+++ b/lib/Makefile
@@ -221,7 +221,7 @@ libpm.o: compile.h
 .PHONY: install.lib
 ifeq ($(NETPBMLIBTYPE),unixshared)
 # install a Unix-style shared library
-install.lib: $(PKGDIR)/lib $(PKGDIR)/link
+install.lib: $(PKGDIR)/lib $(PKGDIR)/sharedlink
 	cd $(PKGDIR)/lib ; rm -f libnetpbm.$(NETPBMLIBSUFFIX).$(MAJ).*
 	$(INSTALL) -c -m $(INSTALL_PERM_LIBD) \
 	  libnetpbm.$(NETPBMLIBSUFFIX).$(MAJ).$(MIN)  $(PKGDIR)/lib/
@@ -263,26 +263,27 @@ $(INTERFACE_HEADERS:%=%_installhdr): $(PKGDIR)/include/netpbm
 	  $(SRCDIR)/lib/$(@:%_installhdr=%) $(PKGDIR)/include/netpbm/
 
 .PHONY: install.staticlib
-install.staticlib: $(PKGDIR)/link
+install.staticlib: $(PKGDIR)/staticlink
 	$(INSTALL) -c -m $(INSTALL_PERM_LIBS) libnetpbm.$(STATICLIBSUFFIX) \
-	  $(PKGDIR)/link
+	  $(PKGDIR)/staticlink
 
 # Install a shared library stub -- the ".so" file used at link time to
 # prepare a program for dynamically linking a library at run time 
 .PHONY: install.sharedlibstub
-install.sharedlibstub: $(PKGDIR)/link
+install.sharedlibstub: $(PKGDIR)/sharedlink
 ifeq ($(NETPBMLIBTYPE),unixshared)
 # install the link-time (.so) links to the runtime libraries
-	cd $(PKGDIR)/link ; \
+	cd $(PKGDIR)/sharedlink ; \
           rm -f libnetpbm.$(NETPBMLIBSUFFIX); \
           $(SYMLINK) ../lib/libnetpbm.$(NETPBMLIBSUFFIX).$(MAJ) \
             libnetpbm.$(NETPBMLIBSUFFIX)
 endif
 ifeq ($(NETPBMLIBTYPE),dll)
-	$(INSTALL) -c -m $(INSTALL_PERM_LIBS) libnetpbm.dll.a $(PKGDIR)/link
+	$(INSTALL) -c -m $(INSTALL_PERM_LIBS) libnetpbm.dll.a \
+	  $(PKGDIR)/sharedlink
 endif
 ifeq ($(NETPBMLIBTYPE),dylib)
-	cd $(PKGDIR)/link/ ; \
+	cd $(PKGDIR)/sharedlink/ ; \
           rm -f libnetpbm.dylib; \
 	$(SYMLINK) ../lib/libnetpbm.$(MAJ).$(MIN).dylib libnetpbm.dylib
 endif
diff --git a/lib/colorname.c b/lib/colorname.c
index 9400adf7..fe580cb9 100644
--- a/lib/colorname.c
+++ b/lib/colorname.c
@@ -247,9 +247,9 @@ pm_parse_dictionary_name(char    const colorname[],
 
     pm_parse_dictionary_namen(colorname, color);
 
-    r = ROUNDU(color[PAM_RED_PLANE] * maxval);
-    g = ROUNDU(color[PAM_GRN_PLANE] * maxval);
-    b = ROUNDU(color[PAM_BLU_PLANE] * maxval);
+    r = ppm_unnormalize(color[PAM_RED_PLANE], maxval);
+    g = ppm_unnormalize(color[PAM_GRN_PLANE], maxval);
+    b = ppm_unnormalize(color[PAM_BLU_PLANE], maxval);
 
     if (!closeOk) {
         if (maxval != PAM_COLORFILE_MAXVAL) {
diff --git a/lib/libpamcolor.c b/lib/libpamcolor.c
index f9add1a1..e1a24c66 100644
--- a/lib/libpamcolor.c
+++ b/lib/libpamcolor.c
@@ -366,9 +366,7 @@ pnm_parsecolor2(const char * const colorname,
 
     color = pnm_parsecolorn(colorname);
 
-    retval[PAM_RED_PLANE] = ROUNDU(color[PAM_RED_PLANE] * maxval);
-    retval[PAM_GRN_PLANE] = ROUNDU(color[PAM_GRN_PLANE] * maxval);
-    retval[PAM_BLU_PLANE] = ROUNDU(color[PAM_BLU_PLANE] * maxval);
+    pnm_unnormalizetuple(&pam, color, retval);
 
     if (!closeOk) {
         warnIfNotExact(colorname, retval, color, maxval, PAM_RED_PLANE);
diff --git a/lib/libpamn.c b/lib/libpamn.c
index 8ae57037..ae28283a 100644
--- a/lib/libpamn.c
+++ b/lib/libpamn.c
@@ -414,6 +414,19 @@ pnm_writepamn(struct pam * const pamP,
 
 
 
+samplen
+pnm_normalized_sample(struct pam * const pamP,
+                      sample       const sample) {
+    return (samplen)sample/pamP->maxval;
+}
+
+sample
+pnm_unnormalized_sample(struct pam * const pamP,
+                        samplen      const sampleVal) {
+    double const epsilon = 1e-6;
+    return (sample)((sampleVal + epsilon) * pamP->maxval + 0.5);
+}
+
 void
 pnm_normalizetuple(struct pam * const pamP,
                    tuple        const tuple,
@@ -422,7 +435,7 @@ pnm_normalizetuple(struct pam * const pamP,
     unsigned int plane;
 
     for (plane = 0; plane < pamP->depth; ++plane)
-        tuplen[plane] = (samplen)tuple[plane] / pamP->maxval;
+        tuplen[plane] = pnm_normalized_sample(pamP, tuple[plane]);
 }
 
 
@@ -435,7 +448,7 @@ pnm_unnormalizetuple(struct pam * const pamP,
     unsigned int plane;
 
     for (plane = 0; plane < pamP->depth; ++plane)
-        tuple[plane] = tuplen[plane] * pamP->maxval + 0.5;
+        tuple[plane] = pnm_unnormalized_sample(pamP, tuplen[plane]);
 }
 
 
diff --git a/lib/libpgm.h b/lib/libpgm.h
index 7523faaf..eb292c80 100644
--- a/lib/libpgm.h
+++ b/lib/libpgm.h
@@ -7,9 +7,9 @@
 #include "pgm.h"
 
 void
-pgm_readpgminitrest(FILE * const file, 
-                    int *  const colsP, 
-                    int *  const rowsP, 
+pgm_readpgminitrest(FILE * const file,
+                    int *  const colsP,
+                    int *  const rowsP,
                     gray * const maxvalP);
 
 #endif
diff --git a/lib/libpnm3.c b/lib/libpnm3.c
index 0426ebcb..3970c734 100644
--- a/lib/libpnm3.c
+++ b/lib/libpnm3.c
@@ -10,6 +10,9 @@
 ** implied warranty.
 */
 
+#include <stdbool.h>
+#include <assert.h>
+
 #include "pnm.h"
 #include "ppm.h"
 #include "pgm.h"
@@ -199,22 +202,22 @@ pnm_blackxel(xelval const maxval,
     default:
         pm_error("Invalid format %d passed to pnm_blackxel()", format);
     }
-    
+
     return retval;
 }
 
 
 
 void
-pnm_invertxel(xel*   const xP, 
-              xelval const maxval, 
+pnm_invertxel(xel*   const xP,
+              xelval const maxval,
               int    const format) {
 
     switch (PNM_FORMAT_TYPE(format)) {
     case PPM_TYPE:
-        PPM_ASSIGN(*xP, 
+        PPM_ASSIGN(*xP,
                    maxval - PPM_GETR(*xP),
-                   maxval - PPM_GETG(*xP), 
+                   maxval - PPM_GETG(*xP),
                    maxval - PPM_GETB(*xP));
         break;
 
@@ -234,145 +237,199 @@ pnm_invertxel(xel*   const xP,
 
 
 void
-pnm_promoteformat( xel** xels, int cols, int rows, xelval maxval, int format, xelval newmaxval, int newformat )
-    {
-    int row;
+pnm_promoteformat(xel ** const xels,
+                  int    const cols,
+                  int    const rows,
+                  xelval const maxval,
+                  int    const format,
+                  xelval const newmaxval,
+                  int    const newformat) {
 
-    for ( row = 0; row < rows; ++row )
-    pnm_promoteformatrow(
-        xels[row], cols, maxval, format, newmaxval, newformat );
-    }
+    unsigned int row;
 
-void
-pnm_promoteformatrow( xel* xelrow, int cols, xelval maxval, int format, xelval newmaxval, int newformat )
-    {
-    register int col;
-    register xel* xP;
-
-    if ( ( PNM_FORMAT_TYPE(format) == PPM_TYPE &&
-       ( PNM_FORMAT_TYPE(newformat) == PGM_TYPE ||
-         PNM_FORMAT_TYPE(newformat) == PBM_TYPE ) ) ||
-     ( PNM_FORMAT_TYPE(format) == PGM_TYPE &&
-       PNM_FORMAT_TYPE(newformat) == PBM_TYPE ) )
-    pm_error( "pnm_promoteformatrow: can't promote downwards!" );
-
-    /* Are we promoting to the same type? */
-    if ( PNM_FORMAT_TYPE(format) == PNM_FORMAT_TYPE(newformat) )
-    {
-    if ( PNM_FORMAT_TYPE(format) == PBM_TYPE )
-        return;
-    if ( newmaxval < maxval )
-        pm_error(
-       "pnm_promoteformatrow: can't decrease maxval - try using pnmdepth" );
-    if ( newmaxval == maxval )
-        return;
-    /* Increase maxval. */
-    switch ( PNM_FORMAT_TYPE(format) )
-        {
-        case PGM_TYPE:
-        for ( col = 0, xP = xelrow; col < cols; ++col, ++xP )
-        PNM_ASSIGN1(
-            *xP, (int) PNM_GET1(*xP) * newmaxval / maxval );
-        break;
+    for (row = 0; row < rows; ++row)
+        pnm_promoteformatrow(
+            xels[row], cols, maxval, format, newmaxval, newformat);
+}
 
-        case PPM_TYPE:
-        for ( col = 0, xP = xelrow; col < cols; ++col, ++xP )
-        PPM_DEPTH( *xP, *xP, maxval, newmaxval );
-        break;
 
-        default:
-        pm_error( "Invalid old format passed to pnm_promoteformatrow()" );
-        }
-    return;
-    }
 
-    /* We must be promoting to a higher type. */
-    switch ( PNM_FORMAT_TYPE(format) )
-    {
-    case PBM_TYPE:
-    switch ( PNM_FORMAT_TYPE(newformat) )
-        {
-        case PGM_TYPE:
-        for ( col = 0, xP = xelrow; col < cols; ++col, ++xP )
-        if ( PNM_GET1(*xP) == 0 )
-            PNM_ASSIGN1( *xP, 0 );
-        else
-            PNM_ASSIGN1( *xP, newmaxval );
-        break;
-
-        case PPM_TYPE:
-        for ( col = 0, xP = xelrow; col < cols; ++col, ++xP )
-        if ( PNM_GET1(*xP) == 0 )
-            PPM_ASSIGN( *xP, 0, 0, 0 );
-        else
-            PPM_ASSIGN( *xP, newmaxval, newmaxval, newmaxval );
-        break;
-
-        default:
-        pm_error( "Invalid new format passed to pnm_promoteformatrow()" );
+void
+pnm_promoteformatrow(xel *  const xelrow,
+                     int    const cols,
+                     xelval const maxval,
+                     int    const format,
+                     xelval const newmaxval,
+                     int    const newformat) {
+
+    if ((PNM_FORMAT_TYPE(format) == PPM_TYPE &&
+         (PNM_FORMAT_TYPE(newformat) == PGM_TYPE ||
+          PNM_FORMAT_TYPE(newformat) == PBM_TYPE)) ||
+        (PNM_FORMAT_TYPE(format) == PGM_TYPE &&
+         PNM_FORMAT_TYPE(newformat) == PBM_TYPE)) {
+
+        pm_error( "pnm_promoteformatrow: can't promote downwards!" );
+    } else if (PNM_FORMAT_TYPE(format) == PNM_FORMAT_TYPE(newformat)) {
+        /* We're promoting to the same type - but not necessarily maxval */
+        if (PNM_FORMAT_TYPE(format) == PBM_TYPE) {
+            /* PBM doesn't have maxval, so this is idempotent */
+        } else if (newmaxval < maxval)
+            pm_error("pnm_promoteformatrow: can't decrease maxval - "
+                     "try using pamdepth");
+        else if (newmaxval == maxval) {
+            /* Same type, same maxval => idempotent function */
+        } else {
+            /* Increase maxval. */
+            switch (PNM_FORMAT_TYPE(format)) {
+            case PGM_TYPE: {
+                unsigned int col;
+                for (col = 0; col < cols; ++col)
+                    PNM_ASSIGN1(xelrow[col],
+                                PNM_GET1(xelrow[col]) * newmaxval / maxval);
+            } break;
+
+            case PPM_TYPE: {
+                unsigned int col;
+                for (col = 0; col < cols; ++col)
+                    PPM_DEPTH(xelrow[col], xelrow[col], maxval, newmaxval);
+            } break;
+
+            default:
+                pm_error("Invalid old format passed to "
+                         "pnm_promoteformatrow()");
+            }
         }
-    break;
+    } else {
+        /* Promote to a higher type. */
+        switch (PNM_FORMAT_TYPE(format)) {
+        case PBM_TYPE:
+            switch (PNM_FORMAT_TYPE(newformat)) {
+            case PGM_TYPE: {
+                unsigned int col;
+                for (col = 0; col < cols; ++col) {
+                    if (PNM_GET1(xelrow[col]) == 0)
+                        PNM_ASSIGN1(xelrow[col], 0);
+                    else
+                        PNM_ASSIGN1(xelrow[col], newmaxval);
+                }
+            } break;
+
+            case PPM_TYPE: {
+                unsigned int col;
+                for (col = 0; col < cols; ++col) {
+                    if (PNM_GET1(xelrow[col]) == 0)
+                        PPM_ASSIGN(xelrow[col], 0, 0, 0);
+                    else
+                        PPM_ASSIGN(xelrow[col],
+                                   newmaxval, newmaxval, newmaxval );
+                }
+            } break;
+
+            default:
+                pm_error("Invalid new format passed to "
+                         "pnm_promoteformatrow()");
+            }
+            break;
 
-    case PGM_TYPE:
-    switch ( PNM_FORMAT_TYPE(newformat) )
-        {
-        case PPM_TYPE:
-        if ( newmaxval < maxval )
-        pm_error(
-       "pnm_promoteformatrow: can't decrease maxval - try using pnmdepth" );
-        if ( newmaxval == maxval )
-        {
-        for ( col = 0, xP = xelrow; col < cols; ++col, ++xP )
-            PPM_ASSIGN(
-            *xP, PNM_GET1(*xP), PNM_GET1(*xP), PNM_GET1(*xP) );
-        }
-        else
-        { /* Increase maxval. */
-        for ( col = 0, xP = xelrow; col < cols; ++col, ++xP )
-            PPM_ASSIGN(
-            *xP, (int) PNM_GET1(*xP) * newmaxval / maxval,
-            (int) PNM_GET1(*xP) * newmaxval / maxval,
-            (int) PNM_GET1(*xP) * newmaxval / maxval );
-        }
-        break;
+        case PGM_TYPE:
+            switch (PNM_FORMAT_TYPE(newformat)) {
+            case PPM_TYPE:
+                if (newmaxval < maxval)
+                    pm_error("pnm_promoteformatrow: can't decrease maxval - "
+                             "try using pamdepth");
+                else if (newmaxval == maxval) {
+                    unsigned int col;
+                    for (col = 0; col < cols; ++col) {
+                        PPM_ASSIGN(xelrow[col],
+                                   PNM_GET1(xelrow[col]),
+                                   PNM_GET1(xelrow[col]),
+                                   PNM_GET1(xelrow[col]));
+                    }
+                } else {
+                    /* Increase maxval. */
+                    unsigned int col;
+                    for (col = 0; col < cols; ++col) {
+                        PPM_ASSIGN(xelrow[col],
+                                   PNM_GET1(xelrow[col]) * newmaxval / maxval,
+                                   PNM_GET1(xelrow[col]) * newmaxval / maxval,
+                                   PNM_GET1(xelrow[col]) * newmaxval / maxval);
+                    }
+                }
+                break;
+
+            default:
+                pm_error("Invalid new format passed to "
+                         "pnm_promoteformatrow()");
+            }
+            break;
 
         default:
-        pm_error( "Invalid new format passed to pnm_promoteformatrow()" );
+            pm_error("Invalid old format passed to pnm_promoteformatrow()");
         }
-    break;
-
-    default:
-        pm_error( "Invalid old format passed to pnm_promoteformatrow()" );
-    }
     }
+}
+
 
 
 pixel
-pnm_xeltopixel(xel const inputxel,
+pnm_xeltopixel(xel const inputXel,
                int const format) {
-    
-    pixel outputpixel;
+
+    pixel outputPixel;
 
     switch (PNM_FORMAT_TYPE(format)) {
     case PPM_TYPE:
-        PPM_ASSIGN(outputpixel,
-                   PPM_GETR(inputxel),
-                   PPM_GETG(inputxel),
-                   PPM_GETB(inputxel));
+        PPM_ASSIGN(outputPixel,
+                   PNM_GETR(inputXel),
+                   PNM_GETG(inputXel),
+                   PNM_GETB(inputXel));
         break;
     case PGM_TYPE:
     case PBM_TYPE:
-        PPM_ASSIGN(outputpixel,
-                   PNM_GET1(inputxel),
-                   PNM_GET1(inputxel),
-                   PNM_GET1(inputxel));
+        PPM_ASSIGN(outputPixel,
+                   PNM_GET1(inputXel),
+                   PNM_GET1(inputXel),
+                   PNM_GET1(inputXel));
         break;
     default:
         pm_error("Invalid format code %d passed to pnm_xeltopixel()",
                  format);
     }
 
-    return outputpixel;
+    return outputPixel;
+}
+
+
+
+xel
+pnm_pixeltoxel(pixel const inputPixel) {
+
+    return inputPixel;
+}
+
+
+
+xel
+pnm_graytoxel(gray const inputGray) {
+
+    xel outputXel;
+
+    PNM_ASSIGN1(outputXel, inputGray);
+
+    return outputXel;
+}
+
+
+xel
+pnm_bittoxel(bit    const inputBit,
+             xelval const maxval) {
+
+    switch (inputBit) {
+    case PBM_BLACK: return pnm_blackxel(maxval, PBM_TYPE); break;
+    case PBM_WHITE: return pnm_whitexel(maxval, PBM_TYPE); break;
+    default:
+        assert(false);
+    }
 }
 
 
@@ -413,6 +470,6 @@ pnm_parsecolorxel(const char * const colorName,
         pm_error("Invalid format code %d passed to pnm_parsecolorxel()",
                  format);
     }
-    
+
     return retval;
 }
diff --git a/lib/libppmcolor.c b/lib/libppmcolor.c
index 7079482c..c0a88dc2 100644
--- a/lib/libppmcolor.c
+++ b/lib/libppmcolor.c
@@ -553,9 +553,9 @@ ppm_color_from_hsv(struct hsv const hsv,
         }
     }
     PPM_ASSIGN(retval,
-               ROUNDU(R * maxval),
-               ROUNDU(G * maxval),
-               ROUNDU(B * maxval));
+               ppm_unnormalize(R, maxval),
+               ppm_unnormalize(G, maxval),
+               ppm_unnormalize(B, maxval));
 
     return retval;
 }
diff --git a/lib/pam.h b/lib/pam.h
index 74b20f46..0055858b 100644
--- a/lib/pam.h
+++ b/lib/pam.h
@@ -438,6 +438,13 @@ void
 pnm_writepamn(struct pam * const pamP,
               tuplen **    const tuplenarray);
 
+samplen
+pnm_normalized_sample(struct pam * const pamP,
+                      sample       const sample);
+
+sample
+pnm_unnormalized_sample(struct pam * const pamP,
+                        samplen      const sampleVal);
 
 void
 pnm_normalizetuple(struct pam * const pamP,
diff --git a/lib/pgm.h b/lib/pgm.h
index 2de8d531..d4655239 100644
--- a/lib/pgm.h
+++ b/lib/pgm.h
@@ -24,7 +24,7 @@ typedef unsigned int gray;
    (because then old Netpbm programs can process them, and they're
    only half as big).
 
-   So we keep PGM_MAXMAXVAL = 255, even though it's kind of a misnomer.  
+   So we keep PGM_MAXMAXVAL = 255, even though it's kind of a misnomer.
 
    Note that one could always write a file with maxval > PGM_MAXMAXVAL and
    it would just go into plain (text) format instead of raw (binary) format.
@@ -42,6 +42,8 @@ typedef unsigned int gray;
 #define PGM_OVERALLMAXVAL 65535
 #define PGM_MAXMAXVAL 255
 
+#define pgm_unnormalize(value, maxval) \
+  ((gray)((value + 1e-6) * (maxval) + 0.5))
 
 /* Magic constants. */
 
@@ -62,7 +64,7 @@ typedef unsigned int gray;
 
 /* Declarations of routines. */
 
-void 
+void
 pgm_init(int *   const argcP,
          char ** const argv);
 
@@ -78,35 +80,35 @@ pgm_allocrow(unsigned int const cols);
 gray **
 pgm_readpgm(FILE * const file,
             int *  const colsP,
-            int *  const rowsP, 
+            int *  const rowsP,
             gray * const maxvalP);
 
 void
 pgm_readpgminit(FILE * const file,
-                int *  const colsP, 
+                int *  const colsP,
                 int *  const rowsP,
                 gray * const maxvalP,
                 int *  const formatP);
 
 void
 pgm_readpgmrow(FILE * const file,
-               gray * const grayrow, 
+               gray * const grayrow,
                int    const cols,
                gray   const maxval,
                int    const format);
 
 void
-pgm_writepgminit(FILE * const fileP, 
-                 int    const cols, 
-                 int    const rows, 
-                 gray   const maxval, 
+pgm_writepgminit(FILE * const fileP,
+                 int    const cols,
+                 int    const rows,
+                 gray   const maxval,
                  int    const forceplain);
 
 void
-pgm_writepgmrow(FILE *       const fileP, 
-                const gray * const grayrow, 
-                int          const cols, 
-                gray         const maxval, 
+pgm_writepgmrow(FILE *       const fileP,
+                const gray * const grayrow,
+                int          const cols,
+                gray         const maxval,
                 int          const forceplain);
 
 void
@@ -121,11 +123,11 @@ void
 pgm_nextimage(FILE * const file, int * const eofP);
 
 void
-pgm_check(FILE *               const file, 
-          enum pm_check_type   const check_type, 
-          int                  const format, 
-          int                  const cols, 
-          int                  const rows, 
+pgm_check(FILE *               const file,
+          enum pm_check_type   const check_type,
+          int                  const format,
+          int                  const cols,
+          int                  const rows,
           gray                 const maxval,
           enum pm_check_code * const retval_p);
 
diff --git a/lib/pnm.h b/lib/pnm.h
index 3b490552..0625cb5c 100644
--- a/lib/pnm.h
+++ b/lib/pnm.h
@@ -5,6 +5,8 @@
 #define _PNM_H_
 
 #include <netpbm/pm.h>
+#include <netpbm/pbm.h>
+#include <netpbm/pgm.h>
 #include <netpbm/ppm.h>
 
 #ifdef __cplusplus
@@ -19,6 +21,7 @@ typedef pixel xel;
 typedef pixval xelval;
 #define PNM_OVERALLMAXVAL PPM_OVERALLMAXVAL
 #define PNM_MAXMAXVAL PPM_MAXMAXVAL
+#define pnm_unnormalize ppm_unnormalize
 #define PNM_GET1(x) PPM_GETB(x)
 #define PNM_GETR(x) PPM_GETR(x)
 #define PNM_GETG(x) PPM_GETG(x)
@@ -72,7 +75,7 @@ pnm_readpnm(FILE *   const fileP,
 
 void
 pnm_check(FILE *               const fileP,
-          enum pm_check_type   const check_type, 
+          enum pm_check_type   const check_type,
           int                  const format,
           int                  const cols,
           int                  const rows,
@@ -81,19 +84,19 @@ pnm_check(FILE *               const fileP,
 
 
 void
-pnm_writepnminit(FILE * const fileP, 
-                 int    const cols, 
-                 int    const rows, 
-                 xelval const maxval, 
-                 int    const format, 
+pnm_writepnminit(FILE * const fileP,
+                 int    const cols,
+                 int    const rows,
+                 xelval const maxval,
+                 int    const format,
                  int    const forceplain);
 
 void
-pnm_writepnmrow(FILE *      const fileP, 
-                const xel * const xelrow, 
-                int         const cols, 
-                xelval      const maxval, 
-                int         const format, 
+pnm_writepnmrow(FILE *      const fileP,
+                const xel * const xelrow,
+                int         const cols,
+                xelval      const maxval,
+                int         const format,
                 int         const forceplain);
 
 void
@@ -105,28 +108,28 @@ pnm_writepnm(FILE * const fileP,
              int    const format,
              int    const forceplain);
 
-xel 
+xel
 pnm_backgroundxel(xel** xels, int cols, int rows, xelval maxval, int format);
 
-xel 
+xel
 pnm_backgroundxelrow(xel* xelrow, int cols, xelval maxval, int format);
 
-xel 
+xel
 pnm_whitexel(xelval maxval, int format);
 
-xel 
+xel
 pnm_blackxel(xelval maxval, int format);
 
-void 
+void
 pnm_invertxel(xel *  const x,
               xelval const maxval,
               int    const format);
 
-void 
-pnm_promoteformat(xel** xels, int cols, int rows, xelval maxval, int format, 
+void
+pnm_promoteformat(xel** xels, int cols, int rows, xelval maxval, int format,
                   xelval newmaxval, int newformat);
-void 
-pnm_promoteformatrow(xel* xelrow, int cols, xelval maxval, int format, 
+void
+pnm_promoteformatrow(xel* xelrow, int cols, xelval maxval, int format,
                      xelval newmaxval, int newformat);
 
 pixel
@@ -134,6 +137,16 @@ pnm_xeltopixel(xel const inputxel,
                int const format);
 
 xel
+pnm_pixeltoxel(pixel const inputPixel);
+
+xel
+pnm_graytoxel(gray const inputGray);
+
+xel
+pnm_bittoxel(bit    const inputBit,
+             xelval const maxval);
+
+xel
 pnm_parsecolorxel(const char * const colorName,
                   xelval       const maxval,
                   int          const format);
diff --git a/lib/ppm.h b/lib/ppm.h
index 7c483b59..9fc90bb3 100644
--- a/lib/ppm.h
+++ b/lib/ppm.h
@@ -23,6 +23,9 @@ typedef gray pixval;
 
 #define PPM_OVERALLMAXVAL PGM_OVERALLMAXVAL
 #define PPM_MAXMAXVAL PGM_MAXMAXVAL
+
+#define ppm_unnormalize pgm_unnormalize
+
 typedef struct {
     pixval r, g, b;
 } pixel;
diff --git a/lib/util/pm_c_util.h b/lib/util/pm_c_util.h
index 4890da05..a093adb6 100644
--- a/lib/util/pm_c_util.h
+++ b/lib/util/pm_c_util.h
@@ -20,6 +20,13 @@
 #define ROUND(X) (((X) >= 0) ? (int)((X)+0.5) : (int)((X)-0.5))
 #undef ROUNDU
 #define ROUNDU(X) ((unsigned int)((X)+0.5))
+    /* Note that imprecision in floating point arithmetic can make an exact
+       half fractional part round down instead of up.  What should be
+       1000.5 might actually be 1000.49999999999.
+
+       Use 'pnm_unnormalized_sample' instead of ROUNDU(samplen*maxval) to get
+       consistent rounding up when you are unnormalizing sample values.
+    */
 
 /* ROUNDUP rounds up to a specified multiple.  E.g. ROUNDUP(22, 8) == 24 */
 
diff --git a/lib/util/shhopt.h b/lib/util/shhopt.h
index 5effa5fd..d9304f9f 100644
--- a/lib/util/shhopt.h
+++ b/lib/util/shhopt.h
@@ -4,7 +4,7 @@ HERE IS AN EXAMPLE OF THE USE OF SHHOPT:
 
 
 #include <shhopt.h>
-int 
+int
 main ( int argc, char **argv ) {
 
     /* initial values here are just to demonstrate what gets set and
@@ -20,7 +20,7 @@ main ( int argc, char **argv ) {
     int debug_flag=7;
     char ** methodlist;
     struct optNameValue * optlist;
-    
+
     optStruct3 opt;
     unsigned int option_def_index = 0;
     optEntry * option_def;
@@ -40,7 +40,7 @@ main ( int argc, char **argv ) {
 
 
     pm_optParseOptions3(&argc, argv, opt, sizeof(opt), 0);
-    
+
 
     printf("argc=%d\n", argc);
     printf("help_flag=%d\n", help_flag);
@@ -129,7 +129,7 @@ typedef struct {
                             * or pointer to function if type == OPT_FUNC. */
     int        flags;      /* modifier flags. */
 } optStruct;
-    
+
 typedef struct {
     /* This structure describes a single program option in a form for
      use by the pm_optParseOptions3() function.
@@ -137,10 +137,10 @@ typedef struct {
     char       shortName;  /* short option name. */
     const char *longName;  /* long option name, not including '--' or '-' */
     optArgType type;       /* option type. */
-    void       *arg;       
+    void       *arg;
         /* pointer to variable in which to return option's argument (or TRUE
-           if it's a flag option), or pointer to function if 
-           type == OPT_FUNC.  If the option is specified multiple times, only 
+           if it's a flag option), or pointer to function if
+           type == OPT_FUNC.  If the option is specified multiple times, only
            the rightmost one affects this return value.
         */
     unsigned int *specified;
@@ -149,7 +149,7 @@ typedef struct {
         */
     int        flags;      /* modifier flags. */
 } optEntry;
-    
+
 
 typedef struct {
     /* This structure describes the options of a program in a form for
@@ -159,20 +159,20 @@ typedef struct {
         /* The syntax may include short (i.e. one-character) options.
            These options may be stacked within a single token (e.g.
            -abc = -a -b -c).  If this value is not true, the short option
-           member of the option table entry is meaningless and long 
+           member of the option table entry is meaningless and long
            options may have either one or two dashes.
            */
     unsigned char allowNegNum;  /* boolean */
         /* Anything that starts with - and then a digit is a numeric
-           parameter, not an option 
+           parameter, not an option
            */
     optStruct *opt_table;
 } optStruct2;
 
 typedef struct {
     /* Same as optStruct2, but for pm_optParseOptions3() */
-    unsigned char short_allowed;  
-    unsigned char allowNegNum;    
+    unsigned char short_allowed;
+    unsigned char allowNegNum;
     optEntry *opt_table;
 } optStruct3;
 
@@ -186,9 +186,9 @@ typedef struct {
        optStruct *option_def = malloc(100*sizeof(optStruct));
        OPTENTRY('h', "help",     OPT_FLAG, &help_flag, 0);
        OPTENTRY(0,   "alphaout", OPT_STRING, &alpha_filename, 0);
-*/   
+*/
 
-/* If you name your variables option_def and option_def_index like in the 
+/* If you name your variables option_def and option_def_index like in the
    example above, everything's easy.  If you want to use OPTENTRY with other
    variables, define macros OPTION_DEF and OPTION_DEF_INDEX before calling
    OPTENTRY.
@@ -242,7 +242,7 @@ struct optNameValue {
 };
 
 
-        
+
 void
 pm_optSetFatalFunc(void (*f)(const char *, ...));
 
@@ -250,10 +250,10 @@ void
 pm_optParseOptions(int *argc, char *argv[],
                    optStruct opt[], int allowNegNum);
 void
-pm_optParseOptions2(int * const argc_p, char *argv[], const optStruct2 opt, 
+pm_optParseOptions2(int * const argc_p, char *argv[], const optStruct2 opt,
                  const unsigned long flags);
 void
-pm_optParseOptions3(int * const argc_p, char *argv[], const optStruct3 opt, 
+pm_optParseOptions3(int * const argc_p, char *argv[], const optStruct3 opt,
                  const unsigned int optStructSize, const unsigned long flags);
 
 void