about summary refs log tree commit diff
path: root/lib
diff options
context:
space:
mode:
Diffstat (limited to 'lib')
-rw-r--r--lib/libpam.c190
-rw-r--r--lib/libpbm3.c100
-rw-r--r--lib/libpbmfont.c211
-rw-r--r--lib/libppm1.c108
-rw-r--r--lib/pam.h110
-rw-r--r--lib/pbmfont.h53
-rw-r--r--lib/pm_gamma.h24
-rw-r--r--lib/ppm.h90
-rw-r--r--lib/util/nstring.c36
-rw-r--r--lib/util/shhopt.c58
10 files changed, 590 insertions, 390 deletions
diff --git a/lib/libpam.c b/lib/libpam.c
index fa1be8f4..a8f140b3 100644
--- a/lib/libpam.c
+++ b/lib/libpam.c
@@ -12,7 +12,7 @@
    offset stuff.
 */
 #define _FILE_OFFSET_BITS 64
-#define _LARGE_FILES  
+#define _LARGE_FILES
 #define _DEFAULT_SOURCE 1  /* New name for SVID & BSD source defines */
 #define _BSD_SOURCE 1      /* Make sure strdup() is in string.h */
 #define _XOPEN_SOURCE 500  /* Make sure strdup() is in string.h */
@@ -108,7 +108,7 @@ validateComputableSize(struct pam * const pamP) {
                  INT_MAX - depth * sizeof(tuple *))
             pm_error("image width and depth (%u, %u) too large "
                      "to be processed.", pamP->width, depth);
-        
+
         if (depth > INT_MAX - 2)
             pm_error("image depth (%u) too large to be processed", depth);
         if (pamP->width > INT_MAX - 2)
@@ -130,7 +130,7 @@ pnm_allocpamtuple(const struct pam * const pamP) {
     retval = malloc(allocationDepth(pamP) * sizeof(retval[0]));
 
     if (retval == NULL)
-        pm_error("Out of memory allocating %u-plane tuple", 
+        pm_error("Out of memory allocating %u-plane tuple",
                  allocationDepth(pamP));
 
     return retval;
@@ -139,15 +139,15 @@ pnm_allocpamtuple(const struct pam * const pamP) {
 
 
 int
-pnm_tupleequal(const struct pam * const pamP, 
-               tuple              const comparand, 
+pnm_tupleequal(const struct pam * const pamP,
+               tuple              const comparand,
                tuple              const comparator) {
 
     unsigned int plane;
     bool equal;
 
     equal = TRUE;  /* initial value */
-    for (plane = 0; plane < pamP->depth; ++plane) 
+    for (plane = 0; plane < pamP->depth; ++plane)
         if (comparand[plane] != comparator[plane])
             equal = FALSE;
 
@@ -173,11 +173,11 @@ pnm_assigntuple(const struct pam * const pamP,
 static void
 scaleTuple(const struct pam * const pamP,
            tuple              const dest,
-           tuple              const source, 
+           tuple              const source,
            sample             const newmaxval) {
 
     unsigned int plane;
-    for (plane = 0; plane < pamP->depth; ++plane) 
+    for (plane = 0; plane < pamP->depth; ++plane)
         dest[plane] = pnm_scalesample(source[plane], pamP->maxval, newmaxval);
 }
 
@@ -186,7 +186,7 @@ scaleTuple(const struct pam * const pamP,
 void
 pnm_scaletuple(const struct pam * const pamP,
                tuple              const dest,
-               tuple              const source, 
+               tuple              const source,
                sample             const newmaxval) {
 
     scaleTuple(pamP, dest, source, newmaxval);
@@ -195,7 +195,7 @@ pnm_scaletuple(const struct pam * const pamP,
 
 
 void
-pnm_createBlackTuple(const struct pam * const pamP, 
+pnm_createBlackTuple(const struct pam * const pamP,
                      tuple *            const blackTupleP) {
 /*----------------------------------------------------------------------------
    Create a "black" tuple.  By that we mean a tuple all of whose elements
@@ -205,7 +205,7 @@ pnm_createBlackTuple(const struct pam * const pamP,
 
     *blackTupleP = pnm_allocpamtuple(pamP);
 
-    for (i = 0; i < pamP->depth; ++i) 
+    for (i = 0; i < pamP->depth; ++i)
         (*blackTupleP)[i] = 0;
 }
 
@@ -226,14 +226,14 @@ allocPamRow(const struct pam * const pamP) {
     tuple * tuplerow;
 
     tuplerow = malloc(pamP->width * (sizeof(tuple *) + bytesPerTuple));
-                      
+
     if (tuplerow != NULL) {
         /* Now we initialize the pointers to the individual tuples
-           to make this a regulation C two dimensional array.  
+           to make this a regulation C two dimensional array.
         */
         char * p;
         unsigned int col;
-        
+
         p = (char*) (tuplerow + pamP->width);  /* location of Tuple 0 */
         for (col = 0; col < pamP->width; ++col) {
                 tuplerow[col] = (tuple) p;
@@ -261,7 +261,7 @@ pnm_allocpamrow(const struct pam * const pamP) {
 
 
 
-static unsigned int 
+static unsigned int
 rowimagesize(const struct pam * const pamP) {
 
     /* If repeatedly calculating this turns out to be a significant
@@ -271,7 +271,7 @@ rowimagesize(const struct pam * const pamP) {
 
     if (PAM_FORMAT_TYPE(pamP->format) == PBM_TYPE)
         return pbm_packed_bytes(pamP->width);
-    else 
+    else
         return (pamP->width * pamP->bytes_per_sample * pamP->depth);
 }
 
@@ -307,7 +307,7 @@ pnm_freerowimage(unsigned char * const rowimage) {
 
 
 
-void 
+void
 pnm_scaletuplerow(const struct pam * const pamP,
                   tuple *            const destRow,
                   tuple *            const sourceRow,
@@ -321,26 +321,26 @@ pnm_scaletuplerow(const struct pam * const pamP,
             for (col = 0; col < pamP->width; ++col)
                 pnm_assigntuple(pamP, destRow[col], sourceRow[col]);
         }
-    } else {        
+    } else {
         unsigned int col;
-        for (col = 0; col < pamP->width; ++col) 
+        for (col = 0; col < pamP->width; ++col)
             scaleTuple(pamP, destRow[col], sourceRow[col], newMaxval);
     }
 }
 
- 
+
 
 tuple **
 pnm_allocpamarray(const struct pam * const pamP) {
-    
+
     tuple **tuplearray;
 
     /* If the speed of this is ever an issue, it might be sped up a little
        by allocating one large chunk.
     */
-    
+
     MALLOCARRAY(tuplearray, pamP->height);
-    if (tuplearray == NULL) 
+    if (tuplearray == NULL)
         pm_error("Out of memory allocating the row pointer section of "
                  "a %u row array", pamP->height);
     else {
@@ -353,14 +353,14 @@ pnm_allocpamarray(const struct pam * const pamP) {
             if (tuplearray[row] == NULL) {
                 unsigned int freerow;
                 outOfMemory = TRUE;
-                
+
                 for (freerow = 0; freerow < row; ++freerow)
                     pnm_freepamrow(tuplearray[row]);
             }
         }
         if (outOfMemory) {
             free(tuplearray);
-            
+
             pm_error("Out of memory allocating the %u rows %u columns wide by "
                      "%u planes deep", pamP->height, pamP->width,
                      allocationDepth(pamP));
@@ -383,7 +383,7 @@ pnm_freepamarray(tuple ** const tuplearray, const struct pam * const pamP) {
 
 
 
-void 
+void
 pnm_setminallocationdepth(struct pam * const pamP,
                           unsigned int const allocationDepth) {
 
@@ -394,7 +394,7 @@ pnm_setminallocationdepth(struct pam * const pamP,
                  pamP->len, (unsigned)PAM_STRUCT_SIZE(allocation_depth));
 
     pamP->allocation_depth = MAX(allocationDepth, pamP->depth);
-        
+
     validateComputableSize(pamP);
 }
 
@@ -402,13 +402,13 @@ pnm_setminallocationdepth(struct pam * const pamP,
 
 void
 pnm_setpamrow(const struct pam * const pamP,
-              tuple *            const tuplerow, 
+              tuple *            const tuplerow,
               sample             const value) {
 
     int col;
     for (col = 0; col < pamP->width; ++col) {
         int plane;
-        for (plane = 0; plane < pamP->depth; ++plane) 
+        for (plane = 0; plane < pamP->depth; ++plane)
             tuplerow[col][plane] = value;
     }
 }
@@ -421,9 +421,9 @@ pnm_setpamrow(const struct pam * const pamP,
 
 static void
 parseHeaderLine(const char buffer[],
-                char label[MAX_LABEL_LENGTH+1], 
+                char label[MAX_LABEL_LENGTH+1],
                 char value[MAX_VALUE_LENGTH+1]) {
-    
+
     int buffer_curs;
 
     buffer_curs = 0;
@@ -435,12 +435,12 @@ parseHeaderLine(const char buffer[],
         int label_curs;
         label_curs = 0;
         while (!ISSPACE(buffer[buffer_curs]) && buffer[buffer_curs] != '\0') {
-            if (label_curs < MAX_LABEL_LENGTH) 
+            if (label_curs < MAX_LABEL_LENGTH)
                 label[label_curs++] = buffer[buffer_curs];
             buffer_curs++;
         }
         label[label_curs] = '\0';  /* null terminate it */
-    }    
+    }
 
     /* Skip white space between label and value */
     while (ISSPACE(buffer[buffer_curs])) buffer_curs++;
@@ -452,7 +452,7 @@ parseHeaderLine(const char buffer[],
         /* Remove trailing white space from value[] */
         int value_curs;
         value_curs = strlen(value)-1;
-        while (value_curs >= 0 && ISSPACE(value[value_curs])) 
+        while (value_curs >= 0 && ISSPACE(value[value_curs]))
             value[value_curs--] = '\0';
     }
 }
@@ -494,10 +494,10 @@ parseHeaderUint(const char *   const valueString,
         if (errno != 0)
             pm_error("Too-large value for %s in "
                      "PAM file header: '%s'", name, valueString);
-        else if (*endptr != '\0') 
+        else if (*endptr != '\0')
             pm_error("Non-numeric value for %s in "
                      "PAM file header: '%s'", name, valueString);
-        else if (valueNum < 0) 
+        else if (valueNum < 0)
             pm_error("Negative value for %s in "
                      "PAM file header: '%s'", name, valueString);
         else if ((unsigned int)valueNum != valueNum)
@@ -583,7 +583,7 @@ processHeaderLine(char                const buffer[],
             }
             pamP->tuple_type[sizeof(pamP->tuple_type)-1] = '\0';
         }
-    } else 
+    } else
         pm_error("Unrecognized header line type: '%s'.  "
                  "Possible missing ENDHDR line?", label);
 }
@@ -644,13 +644,13 @@ readpaminitrest(struct pam * const pamP) {
 
     comments = strdup("");
 
-    { 
+    {
         int c;
-        /* Read off rest of 1st line -- probably just the newline after the 
-           magic number 
+        /* Read off rest of 1st line -- probably just the newline after the
+           magic number
         */
         while ((c = getc(pamP->file)) != -1 && c != '\n');
-    }    
+    }
 
     while (!headerSeen.endhdr) {
         char buffer[256];
@@ -665,7 +665,7 @@ readpaminitrest(struct pam * const pamP) {
                 appendComment(&comments, buffer);
             else if (pm_stripeq(buffer, ""));
                 /* Ignore it; it's a blank line */
-            else 
+            else
                 processHeaderLine(buffer, pamP, &headerSeen);
         }
     }
@@ -681,13 +681,13 @@ readpaminitrest(struct pam * const pamP) {
     if (!headerSeen.maxval)
         pm_error("No MAXVAL header line in PAM header");
 
-    if (pamP->height == 0) 
+    if (pamP->height == 0)
         pm_error("HEIGHT value is zero in PAM header");
-    if (pamP->width == 0) 
+    if (pamP->width == 0)
         pm_error("WIDTH value is zero in PAM header");
-    if (pamP->depth == 0) 
+    if (pamP->depth == 0)
         pm_error("DEPTH value is zero in PAM header");
-    if (pamP->maxval == 0) 
+    if (pamP->maxval == 0)
         pm_error("MAXVAL value is zero in PAM header");
     if (pamP->maxval > PAM_OVERALL_MAXVAL)
         pm_error("MAXVAL value (%lu) in PAM header is greater than %u",
@@ -697,9 +697,9 @@ readpaminitrest(struct pam * const pamP) {
 
 
 void
-pnm_readpaminitrestaspnm(FILE * const fileP, 
-                         int *  const colsP, 
-                         int *  const rowsP, 
+pnm_readpaminitrestaspnm(FILE * const fileP,
+                         int *  const colsP,
+                         int *  const rowsP,
                          gray * const maxvalP,
                          int *  const formatP) {
 /*----------------------------------------------------------------------------
@@ -743,7 +743,7 @@ pnm_readpaminitrestaspnm(FILE * const fileP,
 }
 
 
-                
+
 unsigned int
 pnm_bytespersample(sample const maxval) {
 /*----------------------------------------------------------------------------
@@ -871,17 +871,17 @@ interpretTupleType(struct pam * const pamP) {
 
 
 
-void 
-pnm_readpaminit(FILE *       const file, 
-                struct pam * const pamP, 
+void
+pnm_readpaminit(FILE *       const file,
+                struct pam * const pamP,
                 int          const size) {
 
-    if (size < PAM_STRUCT_SIZE(tuple_type)) 
+    if (size < PAM_STRUCT_SIZE(tuple_type))
         pm_error("pam object passed to pnm_readpaminit() is too small.  "
                  "It must be large "
                  "enough to hold at least up to the "
                  "'tuple_type' member, but according "
-                 "to the 'size' argument, it is only %d bytes long.", 
+                 "to the 'size' argument, it is only %d bytes long.",
                  size);
 
     pamP->size = size;
@@ -895,7 +895,7 @@ pnm_readpaminit(FILE *       const file,
     pamP->format = pm_readmagicnumber(file);
 
     switch (PAM_FORMAT_TYPE(pamP->format)) {
-    case PAM_TYPE: 
+    case PAM_TYPE:
         readpaminitrest(pamP);
         break;
     case PPM_TYPE: {
@@ -926,12 +926,12 @@ pnm_readpaminit(FILE *       const file,
         if (pamCommentP(pamP))
             *pamP->comment_p = strdup("");
         break;
-        
+
     default:
         pm_error("bad magic number 0x%x - not a PAM, PPM, PGM, or PBM file",
                  pamP->format);
     }
-    
+
     pamP->bytes_per_sample = pnm_bytespersample(pamP->maxval);
     pamP->plainformat = FALSE;
         /* See below for complex explanation of why this is FALSE. */
@@ -959,7 +959,7 @@ writeComments(const struct pam * const pamP) {
         for (p = &comment[0], startOfLine = TRUE; *p; ++p) {
             if (startOfLine)
                 fputc('#', pamP->file);
-                
+
             fputc(*p, pamP->file);
 
             if (*p == '\n')
@@ -986,7 +986,7 @@ writeComments(const struct pam * const pamP) {
    pam structure is what determines whether it is raw or plain.  So we
    set it false here so that it is false in the copied output pam
    structure.
-   
+
    Before 10.32, we set 'plainformat' according to the
    plainness of the input image, and thought it was a good
    idea for a program that reads a plain format input image to
@@ -997,7 +997,7 @@ writeComments(const struct pam * const pamP) {
    facilities to pam.
 */
 
-void 
+void
 pnm_writepaminit(struct pam * const pamP) {
 
     const char * tupleType;
@@ -1014,7 +1014,7 @@ pnm_writepaminit(struct pam * const pamP) {
                  "It must be large "
                  "enough to hold at least up through the "
                  "'bytes_per_sample' member, but according "
-                 "to its 'size' member, it is only %u bytes long.", 
+                 "to its 'size' member, it is only %u bytes long.",
                  pamP->size);
     if (pamP->len < PAM_STRUCT_SIZE(maxval))
         pm_error("pam object must contain members at least through 'maxval', "
@@ -1045,7 +1045,7 @@ pnm_writepaminit(struct pam * const pamP) {
     interpretTupleType(pamP);
 
     pamP->len = MIN(pamP->size, PAM_STRUCT_SIZE(opacity_plane));
-    
+
     switch (PAM_FORMAT_TYPE(pamP->format)) {
     case PAM_TYPE:
         /* See explanation below of why we ignore 'pm_plain_output' here. */
@@ -1065,13 +1065,13 @@ pnm_writepaminit(struct pam * const pamP) {
         */
         if (pamP->depth != 3)
             pm_error("pnm_writepaminit() got PPM format, but depth = %d "
-                     "instead of 3, as required for PPM.", 
+                     "instead of 3, as required for PPM.",
                      pamP->depth);
-        if (pamP->maxval > PPM_OVERALLMAXVAL) 
+        if (pamP->maxval > PPM_OVERALLMAXVAL)
             pm_error("pnm_writepaminit() got PPM format, but maxval = %ld, "
-                     "which exceeds the maximum allowed for PPM: %d", 
+                     "which exceeds the maximum allowed for PPM: %d",
                      pamP->maxval, PPM_OVERALLMAXVAL);
-        ppm_writeppminit(pamP->file, pamP->width, pamP->height, 
+        ppm_writeppminit(pamP->file, pamP->width, pamP->height,
                          (pixval) pamP->maxval, pamP->plainformat);
         break;
 
@@ -1082,9 +1082,9 @@ pnm_writepaminit(struct pam * const pamP) {
                      pamP->depth);
         if (pamP->maxval > PGM_OVERALLMAXVAL)
             pm_error("pnm_writepaminit() got PGM format, but maxval = %ld, "
-                     "which exceeds the maximum allowed for PGM: %d", 
+                     "which exceeds the maximum allowed for PGM: %d",
                      pamP->maxval, PGM_OVERALLMAXVAL);
-        pgm_writepgminit(pamP->file, pamP->width, pamP->height, 
+        pgm_writepgminit(pamP->file, pamP->width, pamP->height,
                          (gray) pamP->maxval, pamP->plainformat);
         break;
 
@@ -1093,10 +1093,10 @@ pnm_writepaminit(struct pam * const pamP) {
             pm_error("pnm_writepaminit() got PBM format, but depth = %d "
                      "instead of 1, as required for PBM.",
                      pamP->depth);
-        if (pamP->maxval != 1) 
+        if (pamP->maxval != 1)
             pm_error("pnm_writepaminit() got PBM format, but maxval = %ld "
                      "instead of 1, as required for PBM.", pamP->maxval);
-        pbm_writepbminit(pamP->file, pamP->width, pamP->height, 
+        pbm_writepbminit(pamP->file, pamP->width, pamP->height,
                          pamP->plainformat);
         break;
 
@@ -1126,29 +1126,29 @@ pnm_writepaminit(struct pam * const pamP) {
 
 
 void
-pnm_checkpam(const struct pam *   const pamP, 
-             enum pm_check_type   const checkType, 
+pnm_checkpam(const struct pam *   const pamP,
+             enum pm_check_type   const checkType,
              enum pm_check_code * const retvalP) {
 
     if (checkType != PM_CHECK_BASIC) {
         if (retvalP) *retvalP = PM_CHECK_UNKNOWN_TYPE;
     } else switch (PAM_FORMAT_TYPE(pamP->format)) {
     case PAM_TYPE: {
-        pm_filepos const need_raster_size = 
+        pm_filepos const need_raster_size =
             pamP->width * pamP->height * pamP->depth * pamP->bytes_per_sample;
         pm_check(pamP->file, checkType, need_raster_size, retvalP);
     }
         break;
     case PPM_TYPE:
-        pgm_check(pamP->file, checkType, pamP->format, 
+        pgm_check(pamP->file, checkType, pamP->format,
                   pamP->width, pamP->height, pamP->maxval, retvalP);
         break;
     case PGM_TYPE:
-        pgm_check(pamP->file, checkType, pamP->format, 
+        pgm_check(pamP->file, checkType, pamP->format,
                   pamP->width, pamP->height, pamP->maxval, retvalP);
         break;
     case PBM_TYPE:
-        pbm_check(pamP->file, checkType, pamP->format, 
+        pbm_check(pamP->file, checkType, pamP->format,
                   pamP->width, pamP->height, retvalP);
         break;
     default:
@@ -1158,7 +1158,7 @@ pnm_checkpam(const struct pam *   const pamP,
 
 
 
-void 
+void
 pnm_maketuplergb(const struct pam * const pamP,
                  tuple              const tuple) {
 
@@ -1172,29 +1172,27 @@ pnm_maketuplergb(const struct pam * const pamP,
 
 
 
-void 
+void
 pnm_makerowrgb(const struct pam * const pamP,
                tuple *            const tuplerow) {
-    
+
     if (pamP->depth < 3) {
         unsigned int col;
 
         if (allocationDepth(pamP) < 3)
             pm_error("allocation depth %u passed to pnm_makerowrgb().  "
                      "Must be at least 3.", allocationDepth(pamP));
-        
-        if (strncmp(pamP->tuple_type, "RGB", 3) != 0) {
-            for (col = 0; col < pamP->width; ++col) {
-                tuple const thisTuple = tuplerow[col];
-                thisTuple[2] = thisTuple[1] = thisTuple[0];
-            }
+
+        for (col = 0; col < pamP->width; ++col) {
+            tuple const thisTuple = tuplerow[col];
+            thisTuple[2] = thisTuple[1] = thisTuple[0];
         }
     }
 }
 
 
 
-void 
+void
 pnm_makearrayrgb(const struct pam * const pamP,
                  tuple **           const tuples) {
 
@@ -1203,7 +1201,7 @@ pnm_makearrayrgb(const struct pam * const pamP,
         if (allocationDepth(pamP) < 3)
             pm_error("allocation depth %u passed to pnm_makearrayrgb().  "
                      "Must be at least 3.", allocationDepth(pamP));
-        
+
         for (row = 0; row < pamP->height; ++row) {
             tuple * const tuplerow = tuples[row];
             unsigned int col;
@@ -1217,7 +1215,7 @@ pnm_makearrayrgb(const struct pam * const pamP,
 
 
 
-void 
+void
 pnm_makerowrgba(const struct pam * const pamP,
                 tuple *            const tuplerow) {
 /*----------------------------------------------------------------------------
@@ -1238,7 +1236,7 @@ pnm_makerowrgba(const struct pam * const pamP,
     } else {
         if (!pamP->visual)
             pm_error("Non-visual tuples given to pnm_addopacityrow()");
-        
+
         if (pamP->color_depth >= 3 && pamP->have_opacity) {
             /* It's already in RGBA format.  Leave it alone. */
         } else {
@@ -1247,10 +1245,10 @@ pnm_makerowrgba(const struct pam * const pamP,
             if (allocationDepth(pamP) < 4)
                 pm_error("allocation depth %u passed to pnm_makerowrgba().  "
                          "Must be at least 4.", allocationDepth(pamP));
-        
+
             for (col = 0; col < pamP->width; ++col) {
                 tuple const thisTuple = tuplerow[col];
-                thisTuple[PAM_TRN_PLANE] = 
+                thisTuple[PAM_TRN_PLANE] =
                     pamP->have_opacity ? thisTuple[pamP->opacity_plane] :
                     pamP->maxval;
 
@@ -1264,7 +1262,7 @@ pnm_makerowrgba(const struct pam * const pamP,
 
 
 
-void 
+void
 pnm_addopacityrow(const struct pam * const pamP,
                   tuple *            const tuplerow) {
 /*----------------------------------------------------------------------------
@@ -1285,7 +1283,7 @@ pnm_addopacityrow(const struct pam * const pamP,
     } else {
         if (!pamP->visual)
             pm_error("Non-visual tuples given to pnm_addopacityrow()");
-        
+
         if (pamP->have_opacity) {
             /* It already has opacity.  Leave it alone. */
         } else {
@@ -1297,7 +1295,7 @@ pnm_addopacityrow(const struct pam * const pamP,
                 pm_error("allocation depth %u passed to pnm_addopacityrow().  "
                          "Must be at least %u.",
                          allocationDepth(pamP), opacityPlane + 1);
-        
+
             for (col = 0; col < pamP->width; ++col)
                 tuplerow[col][opacityPlane] = pamP->maxval;
         }
@@ -1388,7 +1386,7 @@ pnm_backgroundtuple(struct pam *  const pamP,
 
 
 /*=============================================================================
-   pm_system() Standard Input feeder and Standard Output accepter functions.   
+   pm_system() Standard Input feeder and Standard Output accepter functions.
 =============================================================================*/
 
 void
diff --git a/lib/libpbm3.c b/lib/libpbm3.c
index c8389824..0144abe2 100644
--- a/lib/libpbm3.c
+++ b/lib/libpbm3.c
@@ -40,9 +40,9 @@
 
 
 void
-pbm_writepbminit(FILE * const fileP, 
-                 int    const cols, 
-                 int    const rows, 
+pbm_writepbminit(FILE * const fileP,
+                 int    const cols,
+                 int    const rows,
                  int    const forceplain) {
 
     if (!forceplain && !pm_plain_output) {
@@ -55,14 +55,20 @@ pbm_writepbminit(FILE * const fileP,
 
 static void
 writePackedRawRow(FILE *                const fileP,
-                  const unsigned char * const packed_bits,
-                  int                   const cols) {
+                  const unsigned char * const packedBits,
+                  unsigned int          const cols) {
 
-    int bytesWritten;
-    bytesWritten = fwrite(packed_bits, 1, pbm_packed_bytes(cols), fileP);
-    if (bytesWritten < pbm_packed_bytes(cols)) 
-        pm_error("I/O error writing packed row to raw PBM file.");
-} 
+    unsigned int const packedByteCt = pbm_packed_bytes(cols);
+
+    size_t writtenByteCt;
+
+    writtenByteCt = fwrite(packedBits, 1, packedByteCt, fileP);
+    if (writtenByteCt < packedByteCt)
+        pm_error("I/O error writing packed row to raw PBM file.  "
+                 "(Attempted fwrite() of %u packed bytes; "
+                 "only %u got written)",
+                 packedByteCt, (unsigned)writtenByteCt);
+}
 
 
 
@@ -83,21 +89,21 @@ packBitsWithSse2(  FILE *          const fileP,
 -----------------------------------------------------------------------------*/
     /*
       We use 2 SSE registers.
-    
+
       The key machine instructions are:
-        
+
       PCMPGTB128  Packed CoMPare Greater Than Byte
-    
+
         Compares 16 bytes in parallel
         Result is x00 if greater than, xFF if not for each byte
 
-    
-      PMOVMSKB128 Packed MOVe MaSK Byte 
-    
+
+      PMOVMSKB128 Packed MOVe MaSK Byte
+
         Result is 16 bits, the MSBs of 16 bytes
-        x00 xFF x00 xFF xFF xFF x00 x00 xFF xFF xFF xFF x00 x00 x00 x00 
+        x00 xFF x00 xFF xFF xFF x00 x00 xFF xFF xFF xFF x00 x00 x00 x00
         --> 0101110011110000B = 0x5CF0
-        
+
         The result is actually a 64 bit int, but the higher bits are
         always 0.
 
@@ -133,7 +139,7 @@ packBitsWithSse2(  FILE *          const fileP,
             v16qi const compare = (v16qi)
                 _mm_cmpgt_epi8((__m128i)bit128.v16, (__m128i) zero128);
             uint16_t const blackMask = _mm_movemask_epi8 ((__m128i)compare);
-            
+
             *(uint16_t *) & packedBits[col/8] = blackMask;
         }
     }
@@ -142,10 +148,10 @@ packBitsWithSse2(  FILE *          const fileP,
         unsigned int i, j;
 
         bit128.v16 = bit128.v16 ^ bit128.v16;
-    
-        for (i = 0, j = col ; j < cols; ++i, ++j) 
+
+        for (i = 0, j = col ; j < cols; ++i, ++j)
             bit128.byte[ (i&8) + 7-(i&7) ] = bitrow[j];
-      
+
         {
             v16qi const compare = (v16qi)
                 _mm_cmpgt_epi8((__m128i)bit128.v16, (__m128i) zero128);
@@ -211,22 +217,22 @@ packPartialBytes(const bit *     const bitrow,
                  unsigned int    const cols,
                  unsigned int    const nextCol,
                  unsigned char * const packedBits) {
-              
+
     /* routine for partial byte at the end of packedBits[]
        Prior to addition of the above enhancement,
        this method was used for the entire process
-    */                   
-    
+    */
+
     unsigned int col;
     int bitshift;
     unsigned char item;
-    
+
     bitshift = 7;  /* initial value */
     item = 0;      /* initial value */
     for (col = nextCol; col < cols; ++col, --bitshift)
         if (bitrow[col] != 0)
             item |= 1 << bitshift;
-    
+
     packedBits[col/8] = item;
 }
 
@@ -252,7 +258,7 @@ writePbmRowRaw(FILE *      const fileP,
         pm_setjmpbufsave(&jmpbuf, &origJmpbufP);
 
         switch (PACKBITS_SSE) {
-        case 2: 
+        case 2:
             packBitsWithSse2(fileP, bitrow, packedBits, cols);
             break;
         default: {
@@ -273,9 +279,9 @@ writePbmRowRaw(FILE *      const fileP,
 
 static void
 writePbmRowPlain(FILE *      const fileP,
-                 const bit * const bitrow, 
+                 const bit * const bitrow,
                  int         const cols) {
-    
+
     int col, charcount;
 
     charcount = 0;
@@ -293,9 +299,9 @@ writePbmRowPlain(FILE *      const fileP,
 
 
 void
-pbm_writepbmrow(FILE *       const fileP, 
-                const bit *  const bitrow, 
-                int          const cols, 
+pbm_writepbmrow(FILE *       const fileP,
+                const bit *  const bitrow,
+                int          const cols,
                 int          const forceplain) {
 
     if (!forceplain && !pm_plain_output)
@@ -307,9 +313,9 @@ pbm_writepbmrow(FILE *       const fileP,
 
 
 void
-pbm_writepbmrow_packed(FILE *                const fileP, 
+pbm_writepbmrow_packed(FILE *                const fileP,
                        const unsigned char * const packedBits,
-                       int                   const cols, 
+                       int                   const cols,
                        int                   const forceplain) {
 
     if (!forceplain && !pm_plain_output)
@@ -327,11 +333,11 @@ pbm_writepbmrow_packed(FILE *                const fileP,
             pm_longjmp();
         } else {
             unsigned int col;
-            
+
             pm_setjmpbufsave(&jmpbuf, &origJmpbufP);
 
-            for (col = 0; col < cols; ++col) 
-                bitrow[col] = 
+            for (col = 0; col < cols; ++col)
+                bitrow[col] =
                     packedBits[col/8] & (0x80 >> (col%8)) ?
                     PBM_BLACK : PBM_WHITE;
 
@@ -395,13 +401,13 @@ pbm_writepbmrow_bitoffset(FILE *          const fileP,
     bool const carryover = (csh == 0 || rsh + csh > 8);
         /* TRUE:  Input comes from colByteCnt bytes and one extra byte.
            FALSE: Input comes from colByteCnt bytes.  For example:
-           TRUE:  xxxxxxii iiiiiiii iiiiiiii iiixxxxx  cols=21, offset=6 
+           TRUE:  xxxxxxii iiiiiiii iiiiiiii iiixxxxx  cols=21, offset=6
            FALSE: xiiiiiii iiiiiiii iiiiiixx ________  cols=21, offset=1
 
            We treat these differently for in the FALSE case the byte after
            last (indicated by ________) may not exist.
         */
-       
+
     if (rsh > 0) {
         unsigned int const shiftBytes =  carryover ? colByteCnt : colByteCnt-1;
 
@@ -412,26 +418,26 @@ pbm_writepbmrow_bitoffset(FILE *          const fileP,
         if (!carryover)
             window[last] = window[last] << rsh;
     }
-      
+
     if (csh > 0)
         window[last] = leftBits(window[last], csh);
-          
+
     pbm_writepbmrow_packed(fileP, window, cols, 0);
 }
 
 
 
 void
-pbm_writepbm(FILE * const fileP, 
-             bit ** const bits, 
-             int    const cols, 
-             int    const rows, 
+pbm_writepbm(FILE * const fileP,
+             bit ** const bits,
+             int    const cols,
+             int    const rows,
              int    const forceplain) {
 
     int row;
 
     pbm_writepbminit(fileP, cols, rows, forceplain);
-    
+
     for (row = 0; row < rows; ++row)
         pbm_writepbmrow(fileP, bits[row], cols, forceplain);
 }
diff --git a/lib/libpbmfont.c b/lib/libpbmfont.c
index 8e854aa6..8f308eda 100644
--- a/lib/libpbmfont.c
+++ b/lib/libpbmfont.c
@@ -256,7 +256,7 @@ pbm_dissectfont(const bit ** const font,
     /* Initialize all character positions to "undefined."  Those that
        are defined in the font will be filled in below.
     */
-    for (i = 0; i < 256; i++)
+    for (i = 0; i < PM_FONT_MAXGLYPH + 1; i++)
         fn->glyph[i] = NULL;
 
     MALLOCARRAY(glyph, nCharsInFont);
@@ -294,7 +294,7 @@ pbm_dissectfont(const bit ** const font,
             row += cellHeight;
         }
     }
-    for (i = firstCodePoint + nCharsInFont; i < 256; ++i)
+    for (i = firstCodePoint + nCharsInFont; i < PM_FONT_MAXGLYPH + 1; ++i)
         fn->glyph[i] = NULL;
     
     return fn;
@@ -377,14 +377,14 @@ pbm_dumpfont(struct font * const fontP,
         pm_message("Netpbm no longer has the capability to generate "
                    "a font in long hexadecimal data format");
 
-    for (i = 0, ng = 0; i < 256; ++i) {
+    for (i = 0, ng = 0; i < PM_FONT_MAXGLYPH +1; ++i) {
         if (fontP->glyph[i])
             ++ng;
     }
 
     printf("static struct glyph _g[%d] = {\n", ng);
 
-    for (i = 0; i < 256; ++i) {
+    for (i = 0; i < PM_FONT_MAXGLYPH + 1; ++i) {
         struct glyph * const glyphP = fontP->glyph[i];
         if (glyphP) {
             unsigned int j;
@@ -409,13 +409,13 @@ pbm_dumpfont(struct font * const fontP,
     {
         unsigned int i;
 
-        for (i = 0; i < 256; ++i) {
+        for (i = 0; i < PM_FONT_MAXGLYPH + 1; ++i) {
             if (fontP->glyph[i])
                 printf(" _g + %d", ng++);
             else
                 printf(" NULL");
         
-            if (i != 255) printf(",");
+            if (i != PM_FONT_MAXGLYPH) printf(",");
             printf("\n");
         }
     }
@@ -738,7 +738,8 @@ skipCharacter(Readline * const readlineP) {
 static void
 interpEncoding(const char **  const arg,
                unsigned int * const codepointP,
-               bool *         const badCodepointP) {
+               bool *         const badCodepointP,
+               PM_WCHAR       const maxglyph) {
 /*----------------------------------------------------------------------------
    With arg[] being the ENCODING statement from the font, return as
    *codepointP the codepoint that it indicates (code point is the character
@@ -746,8 +747,9 @@ interpEncoding(const char **  const arg,
 
    But if the statement doesn't give an acceptable codepoint return
    *badCodepointP == TRUE.
------------------------------------------------------------------------------*/
 
+   'maxglyph' is the maximum codepoint in the font.
+-----------------------------------------------------------------------------*/
     bool gotCodepoint;
     bool badCodepoint;
     unsigned int codepoint;
@@ -763,7 +765,7 @@ interpEncoding(const char **  const arg,
             gotCodepoint = false;
     }
     if (gotCodepoint) {
-        if (codepoint > 255)
+        if (codepoint > maxglyph)
             badCodepoint = true;
         else
             badCodepoint = false;
@@ -779,17 +781,18 @@ interpEncoding(const char **  const arg,
 static void
 readEncoding(Readline *     const readlineP,
              unsigned int * const codepointP,
-             bool *         const badCodepointP) {
+             bool *         const badCodepointP,
+             PM_WCHAR       const maxglyph) {
 
     readExpectedStatement(readlineP, "ENCODING");
     
-    interpEncoding(readlineP->arg, codepointP, badCodepointP);
+    interpEncoding(readlineP->arg, codepointP, badCodepointP, maxglyph);
 }
 
 
 
 static void
-validateFontLimits(const struct font * const fontP) {
+validateFontLimits(const struct font2 * const fontP) {
 
     assert(pbm_maxfontheight() > 0 && pbm_maxfontwidth() > 0);
 
@@ -797,22 +800,27 @@ validateFontLimits(const struct font * const fontP) {
         fontP->maxheight <= 0 ||
         fontP->maxwidth  > pbm_maxfontwidth()  ||
         fontP->maxheight > pbm_maxfontheight() ||
-        fontP->x < - fontP->maxwidth  +1 ||
-        fontP->y < - fontP->maxheight +1 ||
+        -fontP->x + 1 > fontP->maxwidth ||
+        -fontP->y + 1 > fontP->maxheight ||
         fontP->x > fontP->maxwidth  ||
         fontP->y > fontP->maxheight ||
         fontP->x + fontP->maxwidth  > pbm_maxfontwidth() || 
         fontP->y + fontP->maxheight > pbm_maxfontheight()
         ) {
 
-        pm_error("Global font metric(s) out of bounds.\n"); 
+        pm_error("Global font metric(s) out of bounds."); 
     }
+
+    if (fontP->maxglyph > PM_FONT2_MAXGLYPH)
+        pm_error("Internal error.  Glyph table too large: %u glyphs; "
+                 "Maximum possible in Netpbm is %u",
+                 fontP->maxglyph, PM_FONT2_MAXGLYPH);
 }
 
 
 
 static void
-validateGlyphLimits(const struct font  * const fontP,
+validateGlyphLimits(const struct font2 * const fontP,
                     const struct glyph * const glyphP,
                     const char *         const charName) {
 
@@ -842,7 +850,8 @@ validateGlyphLimits(const struct font  * const fontP,
 
 static void
 processChars(Readline *     const readlineP,
-             struct font  * const fontP) {
+             struct font2 * const fontP,
+             PM_WCHAR       const maxglyph ) {
 /*----------------------------------------------------------------------------
    Process the CHARS block in a BDF font file, assuming the file is positioned
    just after the CHARS line.  Read the rest of the block and apply its
@@ -880,7 +889,7 @@ processChars(Readline *     const readlineP,
                 pm_error("no memory for font glyph for '%s' character",
                          charName);
 
-            readEncoding(readlineP, &codepoint, &badCodepoint);
+            readEncoding(readlineP, &codepoint, &badCodepoint, maxglyph);
 
             if (badCodepoint)
                 skipCharacter(readlineP);
@@ -907,7 +916,7 @@ processChars(Readline *     const readlineP,
 
                 readExpectedStatement(readlineP, "ENDCHAR");
 
-                assert(codepoint < 256); /* Ensured by readEncoding() */
+                assert(codepoint <= maxglyph); /* Ensured by readEncoding() */
 
                 fontP->glyph[codepoint] = glyphP;
                 pm_strfree(charName);
@@ -921,8 +930,9 @@ processChars(Readline *     const readlineP,
 
 static void
 processBdfFontLine(Readline     * const readlineP,
-                   struct font  * const fontP,
-                   bool         * const endOfFontP) {
+                   struct font2 * const fontP,
+                   bool         * const endOfFontP,
+                   PM_WCHAR       const maxglyph) {
 /*----------------------------------------------------------------------------
    Process a nonblank line just read from a BDF font file.
 
@@ -964,7 +974,7 @@ processBdfFontLine(Readline     * const readlineP,
       pm_error("Encountered CHARS before FONTBOUNDINGBOX " 
                    "in BDF font file");
       else
-        processChars(readlineP, fontP);
+        processChars(readlineP, fontP, maxglyph);
     } else {
         /* ignore */
     }
@@ -972,36 +982,57 @@ processBdfFontLine(Readline     * const readlineP,
 
 
 
-struct font *
-pbm_loadbdffont(const char * const name) {
+struct font2 *
+pbm_loadbdffont2(const char * const filename,
+                 PM_WCHAR     const maxglyph) {
+/*----------------------------------------------------------------------------
+   Read a BDF font file "filename" as a 'font2' structure.  A 'font2'
+   structure is more expressive than a 'font' structure, most notably in that
+   it can handle wide code points and many more glyphs.
 
-    FILE * ifP;
-    Readline readline;
-    struct font * fontP;
-    bool endOfFont;
+   Codepoints up to maxglyph inclusive are valid in the file.
 
-    ifP = fopen(name, "rb");
+   The returned object is in new malloc'ed storage, in many pieces, and
+   cannot be destroyed.
+-----------------------------------------------------------------------------*/
+    /* For our return object to be destroyable, we need to supply a destroy
+       function, and it needs to return glyph and raster memory, and
+       struct font needs to manage glyph memory separately from mapping
+       code points to glyphs.
+    */
+    FILE *         ifP;
+    Readline       readline;
+    struct font2 * font2P;
+    bool           endOfFont;
+
+    ifP = fopen(filename, "rb");
     if (!ifP)
         pm_error("Unable to open BDF font file name '%s'.  errno=%d (%s)",
-                 name, errno, strerror(errno));
+                 filename, errno, strerror(errno));
 
     readline_init(&readline, ifP);
 
-    MALLOCVAR(fontP);
-    if (fontP == NULL)
+    MALLOCVAR(font2P);
+    if (font2P == NULL)
         pm_error("no memory for font");
 
-    fontP->oldfont = 0;
-    { 
+    MALLOCARRAY(font2P->glyph, maxglyph + 1);
+    if (font2P->glyph == NULL)
+        pm_error("no memory for font glyphs");
+
+    font2P->maxglyph = maxglyph;
+
+    font2P->oldfont = NULL;
+    {
         /* Initialize all characters to nonexistent; we will fill the ones we
            find in the bdf file later.
         */
-        unsigned int i;
-        for (i = 0; i < 256; ++i) 
-            fontP->glyph[i] = NULL;
+        PM_WCHAR i;
+        for (i = 0; i <= maxglyph; ++i)
+            font2P->glyph[i] = NULL;
     }
 
-    fontP->maxwidth = fontP->maxheight = fontP->x = fontP->y = 0;
+    font2P->maxwidth = font2P->maxheight = font2P->x = font2P->y = 0;
 
     readExpectedStatement(&readline, "STARTFONT");
 
@@ -1013,10 +1044,112 @@ pbm_loadbdffont(const char * const name) {
         if (eof)
             pm_error("End of file before ENDFONT statement in BDF font file");
 
-        processBdfFontLine(&readline, fontP, &endOfFont);
+        processBdfFontLine(&readline, font2P, &endOfFont, maxglyph);
     }
+    return font2P;
+}
+
+
+
+struct font *
+pbm_loadbdffont(const char * const filename) {
+/*----------------------------------------------------------------------------
+   Read a BDF font file "filename" into a traditional font structure.
+
+   Codepoints up to 255 (PM_FONT_MAXGLYPH) are valid.
+
+   Can handle ASCII, ISO-8859-1, ISO-8859-2, ISO-8859-15, etc.
+
+   The returned object is in new malloc'ed storage, in many pieces, and
+   cannot be destroyed.
+-----------------------------------------------------------------------------*/
+    /* For our return object to deep copy the glyphs and fonts from
+       the struct font2be destroyable, we need to supply a destroy
+       function, and it needs to return glyph and raster memory, and
+       struct font needs to manage glyph memory separately from mapping
+       code points to glyphs.
+    */
+    struct font  * fontP;
+    struct font2 * font2P;
+    unsigned int   codePoint;
+
+    MALLOCVAR(fontP);
+    if (fontP == NULL)
+        pm_error("no memory for font");
+
+    font2P = pbm_loadbdffont2(filename, PM_FONT_MAXGLYPH);
+
+    fontP->maxwidth  = font2P->maxwidth;
+    fontP->maxheight = font2P->maxheight;
+
+    fontP->x = font2P->x;
+    fontP->y = font2P->y;
+
+    for (codePoint = 0; codePoint < PM_FONT_MAXGLYPH + 1; ++codePoint)
+        fontP->glyph[codePoint] = font2P->glyph[codePoint];
+
+    fontP->oldfont = NULL;
+
+    fontP->fcols = 0;
+    fontP->frows = 0;
+
+    /* Note that *fontP2 is unfreeable.  See pbm_loadbdffont2.  And even if it
+       were, we hooked *fontP into it above, so that would have to turn into a
+       deep copy before we could free *fontP2.
+    */
+
     return fontP;
 }
 
 
 
+struct font2 *
+pbm_expandbdffont(const struct font * const fontP) {
+/*----------------------------------------------------------------------------
+  Convert a traditional font structure into an expanded font2 structure.
+
+  This function depends upon the fact that *fontP, like any struct font,
+  cannot be destroyed.  The returned object refers to memory that belongs
+  to *fontP.
+
+  The returned object is in new malloc'ed storage, in many pieces, and
+  cannot be destroyed.
+-----------------------------------------------------------------------------*/
+    /* If we ever make struct font destroyable, this function needs to
+       copy the glyphs and rasters, and struct font and struct font2 need
+       to manage glyph memory separately from mapping code points to the
+       glyphs.
+    */
+    PM_WCHAR const maxglyph = PM_FONT_MAXGLYPH;
+
+    struct font2 * font2P;
+    unsigned int   codePoint;
+
+    MALLOCVAR(font2P);
+    if (font2P == NULL)
+        pm_error("no memory for font");
+
+    MALLOCARRAY(font2P->glyph, maxglyph + 1);
+    if (font2P->glyph == NULL)
+        pm_error("no memory for font glyphs");
+
+    font2P->maxwidth  = fontP->maxwidth;
+    font2P->maxheight = fontP->maxheight;
+
+    font2P->x = fontP->x;
+    font2P->y = fontP->y;
+
+    font2P->maxglyph = maxglyph;
+
+    for (codePoint = 0; codePoint < maxglyph + 1; ++codePoint)
+        font2P->glyph[codePoint] = fontP->glyph[codePoint];
+
+    font2P->oldfont = fontP->oldfont;
+
+    font2P->fcols = fontP->fcols;
+    font2P->frows = fontP->frows;
+
+    return font2P;
+}
+
+
diff --git a/lib/libppm1.c b/lib/libppm1.c
index c1eb152c..ccc8adb5 100644
--- a/lib/libppm1.c
+++ b/lib/libppm1.c
@@ -14,7 +14,7 @@
    offset stuff.
 */
 #define _FILE_OFFSET_BITS 64
-#define _LARGE_FILES  
+#define _LARGE_FILES
 
 #include <string.h>
 #include <stdio.h>
@@ -56,7 +56,7 @@ ppm_init(int * const argcP, char ** const argv) {
 
 
 void
-ppm_nextimage(FILE * const fileP, 
+ppm_nextimage(FILE * const fileP,
               int *  const eofP) {
     pm_nextimage(fileP, eofP);
 }
@@ -64,9 +64,9 @@ ppm_nextimage(FILE * const fileP,
 
 
 void
-ppm_readppminitrest(FILE *   const fileP, 
-                    int *    const colsP, 
-                    int *    const rowsP, 
+ppm_readppminitrest(FILE *   const fileP,
+                    int *    const colsP,
+                    int *    const rowsP,
                     pixval * const maxvalP) {
     unsigned int maxval;
 
@@ -79,7 +79,7 @@ ppm_readppminitrest(FILE *   const fileP,
     if (maxval > PPM_OVERALLMAXVAL)
         pm_error("maxval of input image (%u) is too large.  "
                  "The maximum allowed by the PPM format is %u.",
-                 maxval, PPM_OVERALLMAXVAL); 
+                 maxval, PPM_OVERALLMAXVAL);
     if (maxval == 0)
         pm_error("maxval of input image is zero.");
 
@@ -114,10 +114,10 @@ validateComputableSize(unsigned int const cols,
 
 
 void
-ppm_readppminit(FILE *   const fileP, 
-                int *    const colsP, 
-                int *    const rowsP, 
-                pixval * const maxvalP, 
+ppm_readppminit(FILE *   const fileP,
+                int *    const colsP,
+                int *    const rowsP,
+                pixval * const maxvalP,
                 int *    const formatP) {
 
     int realFormat;
@@ -156,10 +156,10 @@ ppm_readppminit(FILE *   const fileP,
 
 
 static void
-readPpmRow(FILE *       const fileP, 
-           pixel *      const pixelrow, 
-           unsigned int const cols, 
-           pixval       const maxval, 
+readPpmRow(FILE *       const fileP,
+           pixel *      const pixelrow,
+           unsigned int const cols,
+           pixval       const maxval,
            int          const format) {
 
     unsigned int col;
@@ -168,7 +168,7 @@ readPpmRow(FILE *       const fileP,
         pixval const r = pm_getuint(fileP);
         pixval const g = pm_getuint(fileP);
         pixval const b = pm_getuint(fileP);
-        
+
         if (r > maxval)
             pm_error("Red sample value %u is greater than maxval (%u)",
                      r, maxval);
@@ -178,7 +178,7 @@ readPpmRow(FILE *       const fileP,
         if (b > maxval)
             pm_error("Blue sample value %u is greater than maxval (%u)",
                      b, maxval);
-        
+
         PPM_ASSIGN(pixelrow[col], r, g, b);
     }
 }
@@ -194,7 +194,7 @@ interpRasterRowRaw(const unsigned char * const rowBuffer,
     unsigned int bufferCursor;
 
     bufferCursor = 0;  /* start at beginning of rowBuffer[] */
-        
+
     if (bytesPerSample == 1) {
         unsigned int col;
         for (col = 0; col < cols; ++col) {
@@ -208,16 +208,16 @@ interpRasterRowRaw(const unsigned char * const rowBuffer,
         unsigned int col;
         for (col = 0; col < cols; ++col) {
             pixval r, g, b;
-                    
+
             r = rowBuffer[bufferCursor++] << 8;
             r |= rowBuffer[bufferCursor++];
-                    
+
             g = rowBuffer[bufferCursor++] << 8;
             g |= rowBuffer[bufferCursor++];
-                    
+
             b = rowBuffer[bufferCursor++] << 8;
             b |= rowBuffer[bufferCursor++];
-                    
+
             PPM_ASSIGN(pixelrow[col], r, g, b);
         }
     }
@@ -231,7 +231,7 @@ validateRppmRow(pixel *       const pixelrow,
                 pixval        const maxval,
                 const char ** const errorP) {
 /*----------------------------------------------------------------------------
-  Check for sample values above maxval in input.  
+  Check for sample values above maxval in input.
 
   Note: a program that wants to deal with invalid sample values itself can
   simply make sure it uses a sufficiently high maxval on the read function
@@ -272,20 +272,20 @@ validateRppmRow(pixel *       const pixelrow,
 
 
 static void
-readRppmRow(FILE *       const fileP, 
-            pixel *      const pixelrow, 
-            unsigned int const cols, 
-            pixval       const maxval, 
+readRppmRow(FILE *       const fileP,
+            pixel *      const pixelrow,
+            unsigned int const cols,
+            pixval       const maxval,
             int          const format) {
 
     unsigned int const bytesPerSample = maxval < 256 ? 1 : 2;
     unsigned int const bytesPerRow    = cols * 3 * bytesPerSample;
-        
+
     unsigned char * rowBuffer;
     const char * error;
-    
+
     MALLOCARRAY(rowBuffer, bytesPerRow);
-        
+
     if (rowBuffer == NULL)
         pm_asprintf(&error, "Unable to allocate memory for row buffer "
                     "for %u columns", cols);
@@ -293,7 +293,7 @@ readRppmRow(FILE *       const fileP,
         ssize_t rc;
 
         rc = fread(rowBuffer, 1, bytesPerRow, fileP);
-    
+
         if (feof(fileP))
             pm_asprintf(&error, "Unexpected EOF reading row of PPM image.");
         else if (ferror(fileP))
@@ -323,10 +323,10 @@ readRppmRow(FILE *       const fileP,
 
 
 static void
-readPgmRow(FILE *       const fileP, 
-           pixel *      const pixelrow, 
-           unsigned int const cols, 
-           pixval       const maxval, 
+readPgmRow(FILE *       const fileP,
+           pixel *      const pixelrow,
+           unsigned int const cols,
+           pixval       const maxval,
            int          const format) {
 
     jmp_buf jmpbuf;
@@ -341,7 +341,7 @@ readPgmRow(FILE *       const fileP,
         pm_longjmp();
     } else {
         unsigned int col;
-    
+
         pm_setjmpbufsave(&jmpbuf, &origJmpbufP);
 
         pgm_readpgmrow(fileP, grayrow, cols, maxval, format);
@@ -358,10 +358,10 @@ readPgmRow(FILE *       const fileP,
 
 
 static void
-readPbmRow(FILE *       const fileP, 
-           pixel *      const pixelrow, 
-           unsigned int const cols, 
-           pixval       const maxval, 
+readPbmRow(FILE *       const fileP,
+           pixel *      const pixelrow,
+           unsigned int const cols,
+           pixval       const maxval,
            int          const format) {
 
     jmp_buf jmpbuf;
@@ -395,10 +395,10 @@ readPbmRow(FILE *       const fileP,
 
 
 void
-ppm_readppmrow(FILE *  const fileP, 
-               pixel * const pixelrow, 
-               int     const cols, 
-               pixval  const maxval, 
+ppm_readppmrow(FILE *  const fileP,
+               pixel * const pixelrow,
+               int     const cols,
+               pixval  const maxval,
                int     const format) {
 
     switch (format) {
@@ -432,9 +432,9 @@ ppm_readppmrow(FILE *  const fileP,
 
 
 pixel**
-ppm_readppm(FILE *   const fileP, 
-            int *    const colsP, 
-            int *    const rowsP, 
+ppm_readppm(FILE *   const fileP,
+            int *    const colsP,
+            int *    const rowsP,
             pixval * const maxvalP) {
 
     jmp_buf jmpbuf;
@@ -472,11 +472,11 @@ ppm_readppm(FILE *   const fileP,
 
 
 void
-ppm_check(FILE *               const fileP, 
-          enum pm_check_type   const checkType, 
-          int                  const format, 
-          int                  const cols, 
-          int                  const rows, 
+ppm_check(FILE *               const fileP,
+          enum pm_check_type   const checkType,
+          int                  const format,
+          int                  const cols,
+          int                  const rows,
           pixval               const maxval,
           enum pm_check_code * const retvalP) {
 
@@ -484,7 +484,7 @@ ppm_check(FILE *               const fileP,
         pm_error("Invalid number of rows passed to ppm_check(): %d", rows);
     if (cols < 0)
         pm_error("Invalid number of columns passed to ppm_check(): %d", cols);
-    
+
     if (checkType != PM_CHECK_BASIC) {
         if (retvalP)
             *retvalP = PM_CHECK_UNKNOWN_TYPE;
@@ -495,10 +495,10 @@ ppm_check(FILE *               const fileP,
     } else if (format != RPPM_FORMAT) {
         if (retvalP)
             *retvalP = PM_CHECK_UNCHECKABLE;
-    } else {        
+    } else {
         pm_filepos const bytesPerRow    = cols * 3 * (maxval > 255 ? 2 : 1);
         pm_filepos const needRasterSize = rows * bytesPerRow;
-        
+
         pm_check(fileP, checkType, needRasterSize, retvalP);
     }
 }
diff --git a/lib/pam.h b/lib/pam.h
index 1cf7b855..d8d0e5c7 100644
--- a/lib/pam.h
+++ b/lib/pam.h
@@ -29,8 +29,8 @@ struct pam {
     /* This structure describes an open PAM image file.  It consists
        entirely of information that belongs in the header of a PAM image
        and filesystem information.  It does not contain any state
-       information about the processing of that image.  
-       
+       information about the processing of that image.
+
        This is not considered to be an opaque object.  The user of Netbpm
        libraries is free to access and set any of these fields whenever
        appropriate.  The structure exists to make coding of function calls
@@ -41,11 +41,11 @@ struct pam {
        backward compatibility between library functions and calling programs
        as this structure grows.
        */
-    unsigned int size;   
+    unsigned int size;
         /* The storage size of this entire structure, in bytes */
-    unsigned int len;    
+    unsigned int len;
         /* The length, in bytes, of the information in this structure.
-           The information starts in the first byte and is contiguous.  
+           The information starts in the first byte and is contiguous.
            This cannot be greater than 'size'
 
            Use PAM_STRUCT_SIZE() to compute or interpret a value for this.
@@ -76,12 +76,12 @@ struct pam {
            have plain and raw variations.
         */
     int height;  /* Height of image in rows */
-    int width;   
+    int width;
         /* Width of image in number of columns (tuples per row) */
-    unsigned int depth;   
+    unsigned int depth;
         /* Depth of image (number of samples in each tuple). */
     sample maxval;  /* Maximum defined value for a sample */
-    unsigned int bytes_per_sample;  
+    unsigned int bytes_per_sample;
         /* Number of bytes used to represent each sample in the image file.
            Note that this is strictly a function of 'maxval'.  It is in a
            a separate member for computational speed.
@@ -100,7 +100,7 @@ struct pam {
 
            The purpose of this is to make it possible for a program to
            change the type of a tuple to one with more or fewer
-           planes.  
+           planes.
 
            0 means the allocation depth is the same as the image depth.
         */
@@ -141,7 +141,7 @@ struct pam {
 #define PAM_HAVE_ALLOCATION_DEPTH 1
 #define PAM_HAVE_COMMENT_P 1
 
-/* PAM_STRUCT_SIZE(x) tells you how big a struct pam is up through the 
+/* PAM_STRUCT_SIZE(x) tells you how big a struct pam is up through the
    member named x.  This is useful in conjunction with the 'len' value
    to determine which fields are present in the structure.
 */
@@ -172,7 +172,7 @@ struct pam {
     /* These are values of samples in a PAM image that represents a black
        and white bitmap image.  They are the values of black and white,
        respectively.  For example, if you use pnm_readpamrow() to read a
-       row from a PBM file, the black pixels get returned as 
+       row from a PBM file, the black pixels get returned as
        PAM_PBM_BLACK.
     */
 
@@ -192,7 +192,7 @@ struct pam {
 #define PAM_GRAY_TRN_PLANE 1
     /* For a "GRAYSCALE" tuple type, this is the transparency plane */
 
-typedef sample *tuple;  
+typedef sample *tuple;
     /* A tuple in a PAM.  This is an array such that tuple[i-1] is the
        ith sample (element) in the tuple.  It's dimension is the depth
        of the image (see pam.depth above).
@@ -203,7 +203,7 @@ typedef sample *tuple;
 /* Note: xv uses the same "P7" signature for its thumbnail images (it
    started using it years before PAM and unbeknownst to the designer
    of PAM).  But these images are still easily distinguishable from
-   PAMs 
+   PAMs
 */
 #define PAM_MAGIC1 'P'
 #define PAM_MAGIC2 '7'
@@ -221,9 +221,9 @@ struct pamtuples {
 
 
 typedef float * pnm_transformMap;
-    /* This is an array of transform maps.  transform[N] is the 
+    /* This is an array of transform maps.  transform[N] is the
        array that is the map for Plane N.
-   
+
        Transform maps define a transformation between PAM sample value
        to normalized libnetpbm "samplen" value, i.e. what you get back
        from pnm_readpamrown() or pass to pnm_writepamrown().
@@ -244,7 +244,7 @@ typedef float * pnm_transformMap;
        obvious table lookup.  The samplen -> sample transformation is
        more complicated -- if the samplen value is between map[N]
        and map[N+1], then the sample value is N.  And only transforms
-       where map[N+1] > map[N] are allowed.  
+       where map[N+1] > map[N] are allowed.
     */
 
 /* Declarations of library functions. */
@@ -257,8 +257,8 @@ unsigned int
 pnm_bytespersample(sample const maxval);
 
 int
-pnm_tupleequal(const struct pam * const pamP, 
-               tuple              const comparand, 
+pnm_tupleequal(const struct pam * const pamP,
+               tuple              const comparand,
                tuple              const comparator);
 
 void
@@ -267,14 +267,14 @@ pnm_assigntuple(const struct pam * const pamP,
                 tuple              const source);
 
 static __inline__ sample
-pnm_scalesample(sample const source, 
-                sample const oldmaxval, 
+pnm_scalesample(sample const source,
+                sample const oldmaxval,
                 sample const newmaxval) {
 
     if (oldmaxval == newmaxval)
         /* Fast path for common case */
         return source;
-    else 
+    else
         return (source * newmaxval + (oldmaxval/2)) / oldmaxval;
 }
 
@@ -283,24 +283,24 @@ pnm_scalesample(sample const source,
 void
 pnm_scaletuple(const struct pam * const pamP,
                tuple              const dest,
-               tuple              const source, 
+               tuple              const source,
                sample             const newmaxval);
 
-void 
+void
 pnm_scaletuplerow(const struct pam * const pamP,
                   tuple *            const destRow,
                   tuple *            const sourceRow,
                   sample             const newMaxval);
 
-void 
+void
 pnm_maketuplergb(const struct pam * const pamP,
                  tuple              const tuple);
 
-void 
+void
 pnm_makerowrgb(const struct pam * const pamP,
                tuple *            const tuplerow);
 
-void 
+void
 pnm_makearrayrgb(const struct pam * const pamP,
                  tuple **           const tuples);
 
@@ -336,13 +336,13 @@ pnm_allocpamarray(const struct pam * const pamP);
 void
 pnm_freepamarray(tuple ** const tuplearray, const struct pam * const pamP);
 
-void 
+void
 pnm_setminallocationdepth(struct pam * const pamP,
                           unsigned int const allocationDepth);
 
 void
-pnm_setpamrow(const struct pam * const pam, 
-              tuple *            const tuplerow, 
+pnm_setpamrow(const struct pam * const pam,
+              tuple *            const tuplerow,
               sample             const value);
 
 unsigned char *
@@ -351,20 +351,20 @@ pnm_allocrowimage(const struct pam * const pamP);
 void
 pnm_freerowimage(unsigned char * const rowimage);
 
-void 
-pnm_readpaminit(FILE *       const file, 
-                struct pam * const pamP, 
+void
+pnm_readpaminit(FILE *       const file,
+                struct pam * const pamP,
                 int          const size);
 
-void 
+void
 pnm_readpamrow(const struct pam * const pamP, tuple* const tuplerow);
 
-tuple ** 
-pnm_readpam(FILE *       const file, 
-            struct pam * const pamP, 
+tuple **
+pnm_readpam(FILE *       const file,
+            struct pam * const pamP,
             int          const size);
 
-void 
+void
 pnm_writepaminit(struct pam * const pamP);
 
 void
@@ -373,19 +373,19 @@ pnm_formatpamrow(const struct pam * const pamP,
                  unsigned char *    const outbuf,
                  unsigned int *     const rowSizeP);
 
-void 
+void
 pnm_writepamrow(const struct pam * const pamP, const tuple * const tuplerow);
 
 void
-pnm_writepamrowmult(const struct pam * const pamP, 
+pnm_writepamrowmult(const struct pam * const pamP,
                     const tuple *      const tuplerow,
                     unsigned int       const rptcnt);
 
-void 
+void
 pnm_writepam(struct pam * const pamP, tuple ** const tuplearray);
 
 void
-pnm_checkpam(const struct pam *   const pamP, 
+pnm_checkpam(const struct pam *   const pamP,
              enum pm_check_type   const checkType,
              enum pm_check_code * const retvalP);
 
@@ -409,28 +409,28 @@ pnm_allocpamrown(const struct pam * const pamP);
 tuplen *
 pnm_allocpamrown(const struct pam * const pamP);
 
-void 
-pnm_readpamrown(const struct pam * const pamP, 
+void
+pnm_readpamrown(const struct pam * const pamP,
                 tuplen *           const tuplenrow);
 
-void 
-pnm_writepamrown(const struct pam * const pamP, 
+void
+pnm_writepamrown(const struct pam * const pamP,
                  const tuplen *     const tuplenrow);
 
 tuplen **
 pnm_allocpamarrayn(const struct pam * const pamP);
 
 void
-pnm_freepamarrayn(tuplen **          const tuplenarray, 
+pnm_freepamarrayn(tuplen **          const tuplenarray,
                   const struct pam * const pamP);
 
-tuplen** 
-pnm_readpamn(FILE *       const file, 
-             struct pam * const pamP, 
+tuplen**
+pnm_readpamn(FILE *       const file,
+             struct pam * const pamP,
              int          const size);
 
-void 
-pnm_writepamn(struct pam * const pamP, 
+void
+pnm_writepamn(struct pam * const pamP,
               tuplen **    const tuplenarray);
 
 
@@ -501,18 +501,18 @@ pnm_colorname(struct pam * const pamP,
               tuple        const color,
               int          const hexok);
 
-extern double 
+extern double
 pnm_lumin_factor[3];
 
 void
-pnm_YCbCrtuple(const tuple tuple, 
+pnm_YCbCrtuple(const tuple tuple,
                double * const YP, double * const CbP, double * const CrP);
 
-void 
+void
 pnm_YCbCr_to_rgbtuple(const struct pam * const pamP,
                       tuple              const tuple,
                       double             const Y,
-                      double             const Cb, 
+                      double             const Cb,
                       double             const Cr,
                       int *              const overflowP);
 
diff --git a/lib/pbmfont.h b/lib/pbmfont.h
index 5111a075..ad5d3acf 100644
--- a/lib/pbmfont.h
+++ b/lib/pbmfont.h
@@ -20,6 +20,23 @@ extern "C" {
        a 65536 x 65536 glyph occupies 4G pixels. 
     */
 
+typedef wchar_t PM_WCHAR;
+    /* Precaution to make adjustments, if necessary, for systems with
+       unique wchar_t.
+    */
+
+#define PM_FONT_MAXGLYPH 255
+
+#define PM_FONT2_MAXGLYPH 65535
+    /* Upper limit of codepoint value.
+
+       This is large enough to handle Unicode Plane 0 (Basic Multilingual
+       Plane: BMP) which defines the great majority of characters used in
+       modern languages.
+
+       This can be set to a higher value at some cost to efficiency.
+       As of Unicode v. 11.0.0 planes up to 16 are defined.
+    */
 
 struct glyph {
     /* A glyph consists of white borders and the "central glyph" which
@@ -60,7 +77,7 @@ struct font {
        an code point in the range 0..255, this structure describes the
        glyph for that character.
     */
-    int maxwidth, maxheight;
+    unsigned int maxwidth, maxheight;
     int x;
         /* The minimum value of glyph.font.  The left edge of the glyph
            in the glyph set which advances furthest to the left. */
@@ -76,6 +93,33 @@ struct font {
     int fcols, frows;
 };
 
+
+struct font2 {
+    /* Font structure for expanded character set.  Code point is in the
+       range 0..maxglyph .
+     */
+    int maxwidth, maxheight;
+
+    int x;
+        /* The minimum value of glyph.font.  The left edge of the glyph
+           in the glyph set which advances furthest to the left. */
+    int y;
+        /* Amount of white space that should be added between lines of
+           this font.  Can be negative.
+        */
+    struct glyph ** glyph;
+        /* glyph[i] is the glyph for code point i */
+
+    PM_WCHAR maxglyph;
+        /* max code point for glyphs, including vacant slots */
+
+    const bit ** oldfont;
+        /* for compatibility with old pbmtext routines */
+        /* oldfont is NULL if the font is BDF derived */
+
+    unsigned int fcols, frows;
+};
+
 struct font *
 pbm_defaultfont(const char* const which);
 
@@ -93,6 +137,13 @@ pbm_loadpbmfont(const char * const filename);
 struct font *
 pbm_loadbdffont(const char * const filename);
 
+struct font2 *
+pbm_loadbdffont2(const char * const filename,
+                 PM_WCHAR     const maxglyph);
+
+struct font2 *
+pbm_expandbdffont(const struct font * const font);
+
 void
 pbm_dumpfont(struct font * const fontP,
              FILE *        const ofP);
diff --git a/lib/pm_gamma.h b/lib/pm_gamma.h
index 6630e05c..00d551fc 100644
--- a/lib/pm_gamma.h
+++ b/lib/pm_gamma.h
@@ -15,18 +15,28 @@ extern "C" {
 static __inline__ float
 pm_gamma709(float const intensity) {
 
-    /* Here are parameters of the gamma transfer function
-       for the Netpbm formats.  This is CIE Rec 709.
-       
-       This transfer function is linear for sample values 0 .. .018 
+    /* Here are parameters of the gamma transfer function for the Netpbm
+       formats.  This is ITU-R Recommendation BT.709, FKA CIE Rec 709.  It is
+       also ITU-R Recommendation BT.601, FKA CCIR 601.
+
+       This transfer function is linear for sample values 0 .. .018
        and an exponential for larger sample values.
        The exponential is slightly stretched and translated, though,
        unlike the popular pure exponential gamma transfer function.
+
+       The standard actually defines the linear expansion as 4.500, which
+       means there is a discontinuity at linear intensity .018.  We instead
+       use ~4.514 to make a continuous function.  This may have been simply
+       a mistake when this code was written or based on an actual benefit
+       to having a continuous function -- The history is not clear.
+
+       Note that the discrepancy is below the precision of a maxval 255
+       image.
     */
     float const gamma = 2.2;
     float const oneOverGamma = 1.0 / gamma;
     float const linearCutoff = 0.018;
-    float const linearExpansion = 
+    float const linearExpansion =
         (1.099 * pow(linearCutoff, oneOverGamma) - 0.099) / linearCutoff;
 
     float brightness;
@@ -49,9 +59,9 @@ pm_ungamma709(float const brightness) {
     float const gamma = 2.2;
     float const oneOverGamma = 1.0 / gamma;
     float const linearCutoff = 0.018;
-    float const linearExpansion = 
+    float const linearExpansion =
         (1.099 * pow(linearCutoff, oneOverGamma) - 0.099) / linearCutoff;
-    
+
     float intensity;
 
     if (brightness < linearCutoff * linearExpansion)
diff --git a/lib/ppm.h b/lib/ppm.h
index 82241b70..7c483b59 100644
--- a/lib/ppm.h
+++ b/lib/ppm.h
@@ -90,61 +90,61 @@ ppm_allocrow(unsigned int const cols);
 #define ppm_freerow(pixelrow) pm_freerow(pixelrow);
 
 pixel**
-ppm_readppm(FILE *   const fileP, 
-            int *    const colsP, 
-            int *    const rowsP, 
+ppm_readppm(FILE *   const fileP,
+            int *    const colsP,
+            int *    const rowsP,
             pixval * const maxvalP);
 
 void
-ppm_readppminit(FILE *   const fileP, 
-                int *    const colsP, 
-                int *    const rowsP, 
-                pixval * const maxvalP, 
+ppm_readppminit(FILE *   const fileP,
+                int *    const colsP,
+                int *    const rowsP,
+                pixval * const maxvalP,
                 int *    const formatP);
 
 void
-ppm_readppmrow(FILE*  const fileP, 
-               pixel* const pixelrow, 
-               int    const cols, 
-               pixval const maxval, 
+ppm_readppmrow(FILE*  const fileP,
+               pixel* const pixelrow,
+               int    const cols,
+               pixval const maxval,
                int    const format);
 
 void
-ppm_writeppm(FILE *  const fileP, 
-             pixel** const pixels, 
-             int     const cols, 
-             int     const rows, 
-             pixval  const maxval, 
+ppm_writeppm(FILE *  const fileP,
+             pixel** const pixels,
+             int     const cols,
+             int     const rows,
+             pixval  const maxval,
              int     const forceplain);
 
 void
-ppm_writeppminit(FILE*  const fileP, 
-                 int    const cols, 
-                 int    const rows, 
-                 pixval const maxval, 
+ppm_writeppminit(FILE*  const fileP,
+                 int    const cols,
+                 int    const rows,
+                 pixval const maxval,
                  int    const forceplain);
 
 void
-ppm_writeppmrow(FILE *        const fileP, 
-                const pixel * const pixelrow, 
-                int           const cols, 
-                pixval        const maxval, 
+ppm_writeppmrow(FILE *        const fileP,
+                const pixel * const pixelrow,
+                int           const cols,
+                pixval        const maxval,
                 int           const forceplain);
 
 void
-ppm_check(FILE *               const fileP, 
-          enum pm_check_type   const check_type, 
-          int                  const format, 
-          int                  const cols, 
-          int                  const rows, 
+ppm_check(FILE *               const fileP,
+          enum pm_check_type   const check_type,
+          int                  const format,
+          int                  const cols,
+          int                  const rows,
           pixval               const maxval,
           enum pm_check_code * const retval_p);
 
 void
-ppm_nextimage(FILE * const fileP, 
+ppm_nextimage(FILE * const fileP,
               int *  const eofP);
 
-pixel 
+pixel
 ppm_parsecolor(const char * const colorname,
                pixval       const maxval);
 
@@ -154,8 +154,8 @@ ppm_parsecolor2(const char * const colorname,
                 int          const closeOk);
 
 char*
-ppm_colorname(const pixel* const colorP, 
-              pixval       const maxval, 
+ppm_colorname(const pixel* const colorP,
+              pixval       const maxval,
               int          const hexok);
 
 void
@@ -167,9 +167,9 @@ ppm_readcolordict(const char *      const fileName,
                   colorhash_table * const chtP);
 
 void
-ppm_readcolornamefile(const char *      const fileName, 
+ppm_readcolornamefile(const char *      const fileName,
                       int               const mustOpen,
-                      colorhash_table * const chtP, 
+                      colorhash_table * const chtP,
                       const char ***    const colornamesP);
 
 void
@@ -211,9 +211,7 @@ PPM_DISTANCE(pixel const p1,
    combination of intensities, whereas luma is a linear combination of
    gamma-adjusted intensities, as you would find in a Netpbm image.
 
-   These are from ITU-R BT.601.5.  That means they probably aren't technically
-   right for use with PPM images, because the PPM spec says ITU-R BT.709.
-   The two are similar, though.
+   These are from ITU-R BT.601.5.
 */
 #define PPM_LUMINR (0.2989)
 #define PPM_LUMING (0.5866)
@@ -222,16 +220,20 @@ PPM_DISTANCE(pixel const p1,
 #define PPM_LUMIN(p) ( PPM_LUMINR * PPM_GETR(p) \
                        + PPM_LUMING * PPM_GETG(p) \
                        + PPM_LUMINB * PPM_GETB(p) )
-#define PPM_CHROM_B(p) ( -0.16874 * PPM_GETR(p) \
-                         - 0.33126 * PPM_GETG(p) \
+
+/* The coefficients in the following formulae are functions of
+   PPM_LUMIN{R,G,B} and nothing else.
+*/
+#define PPM_CHROM_B(p) ( -0.168736 * PPM_GETR(p) \
+                         - 0.331264 * PPM_GETG(p) \
                          + 0.5 * PPM_GETB(p) )
 #define PPM_CHROM_R(p) ( 0.5 * PPM_GETR(p) \
-                         - 0.41869 * PPM_GETG(p) \
-                         - 0.08131 * PPM_GETB(p) )
+                         - 0.418688 * PPM_GETG(p) \
+                         - 0.081312 * PPM_GETB(p) )
 
 pixel
-ppm_color_from_ycbcr(unsigned int const y, 
-                     int          const cb, 
+ppm_color_from_ycbcr(unsigned int const y,
+                     int          const cb,
                      int          const cr);
 
 /* Hue/Saturation/Value calculations */
diff --git a/lib/util/nstring.c b/lib/util/nstring.c
index 9b132ee2..8cff4d56 100644
--- a/lib/util/nstring.c
+++ b/lib/util/nstring.c
@@ -3,7 +3,7 @@
  *
 
    THIS MODULE WAS ADAPTED FOR NETPBM BY BRYAN HENDERSON ON 2002.03.24.
-   Bryan got the base from 
+   Bryan got the base from
    http://www.ijs.si/software/snprintf/snprintf-2.2.tar.gz, but made
    a lot of changes and additions.
 
@@ -215,7 +215,7 @@ pm_vsnprintf(char *       const str,
              const char * const fmt,
              va_list            ap,
              size_t *     const sizeP) {
-    
+
     size_t str_l = 0;
     const char *p = fmt;
 
@@ -417,7 +417,7 @@ pm_vsnprintf(char *       const str,
                         str_arg_l = 0;
                     else if (!precision_specified)
                         /* truncate string if necessary as requested by
-                           precision 
+                           precision
                         */
                         str_arg_l = strlen(str_arg);
                     else if (precision == 0)
@@ -469,7 +469,7 @@ pm_vsnprintf(char *       const str,
                       undefined. (Actually %hp converts only 16-bits
                       of address and %llp treats address as 64-bit
                       data which is incompatible with (void *)
-                      argument on a 32-bit system). 
+                      argument on a 32-bit system).
                     */
 
                     length_modifier = '\0';
@@ -602,7 +602,7 @@ pm_vsnprintf(char *       const str,
                         && !(zero_padding_insertion_ind < str_arg_l
                              && tmp[zero_padding_insertion_ind] == '0')) {
                         /* assure leading zero for alternate-form
-                           octal numbers 
+                           octal numbers
                         */
                         if (!precision_specified ||
                             precision < num_of_digits+1) {
@@ -616,7 +616,7 @@ pm_vsnprintf(char *       const str,
                         }
                     }
                     /* zero padding to specified precision? */
-                    if (num_of_digits < precision) 
+                    if (num_of_digits < precision)
                         number_of_zeros_to_pad = precision - num_of_digits;
                 }
                 /* zero padding to specified minimal field width? */
@@ -768,7 +768,7 @@ pm_snprintf(char *       const dest,
     va_list ap;
 
     va_start(ap, fmt);
-    
+
     pm_vsnprintf(dest, str_m, fmt, ap, &size);
 
     va_end(ap);
@@ -807,12 +807,12 @@ pm_strdup(const char * const arg) {
 
 void PM_GNU_PRINTF_ATTR(2,3)
 pm_asprintf(const char ** const resultP,
-            const char *  const fmt, 
+            const char *  const fmt,
             ...) {
 
     const char * result;
     va_list varargs;
-    
+
 #if HAVE_VASPRINTF
     int rc;
     va_start(varargs, fmt);
@@ -822,7 +822,7 @@ pm_asprintf(const char ** const resultP,
         result = pm_strsol;
 #else
     size_t dryRunLen;
-    
+
     va_start(varargs, fmt);
 
     pm_vsnprintf(NULL, 0, fmt, varargs, &dryRunLen);
@@ -843,7 +843,7 @@ pm_asprintf(const char ** const resultP,
             va_start(varargs, fmt);
 
             pm_vsnprintf(buffer, allocSize, fmt, varargs, &realLen);
-                
+
             assert(realLen == dryRunLen);
             va_end(varargs);
 
@@ -871,7 +871,7 @@ pm_strfree(const char * const string) {
 
 const char *
 pm_strsep(char ** const stringP, const char * const delim) {
-    const char * retval;   
+    const char * retval;
 
     if (stringP == NULL || *stringP == NULL)
         retval = NULL;
@@ -881,16 +881,16 @@ pm_strsep(char ** const stringP, const char * const delim) {
         retval = *stringP;
 
         for (p = *stringP; *p && strchr(delim, *p) == NULL; ++p);
- 
+
         if (*p) {
-            /* We hit a delimiter, not end-of-string.  So null out the 
+            /* We hit a delimiter, not end-of-string.  So null out the
                delimiter and advance user's pointer to the next token
             */
             *p++ = '\0';
             *stringP = p;
         } else {
-            /* We ran out of string.  So the end-of-string delimiter is 
-               already there, and we set the user's pointer to NULL to 
+            /* We ran out of string.  So the end-of-string delimiter is
+               already there, and we set the user's pointer to NULL to
                indicate there are no more tokens.
             */
             *stringP = NULL;
@@ -914,7 +914,7 @@ pm_stripeq(const char * const comparand,
     const char * px;
     const char * qx;
     bool equal;
-  
+
     /* Make p and q point to the first non-blank character in each string.
        If there are no non-blank characters, make them point to the terminating
        NUL.
@@ -1021,7 +1021,7 @@ pm_interpret_uint(const char *   const string,
         */
         char * tail;
         unsigned long ulongValue;
-        
+
         errno = 0;  /* So we can tell if strtoul() overflowed */
 
         ulongValue = strtoul(string, &tail, 10);
diff --git a/lib/util/shhopt.c b/lib/util/shhopt.c
index ccf2d1eb..ab489fef 100644
--- a/lib/util/shhopt.c
+++ b/lib/util/shhopt.c
@@ -168,7 +168,7 @@ optString(const optEntry opte, int lng)
 }
 
 
-    
+
 static optEntry
 optStructToEntry(const optStruct opt) {
 /*----------------------------------------------------------------------------
@@ -202,7 +202,7 @@ optStructTblToEntryTbl(const optStruct optStructTable[]) {
     int i;
 
     optEntry *optEntryTable;  /* malloc'ed array */
-    
+
     /* Count the entries in optStructTable[] */
     for (i = 0; optStructTable[i].type != OPT_END && i < 500; i++);
     count = i+1;
@@ -210,7 +210,7 @@ optStructTblToEntryTbl(const optStruct optStructTable[]) {
     optEntryTable = (optEntry *) malloc(count * sizeof(optEntry));
     if (optEntryTable) {
         int i;
-        for (i = 0; i < count; i++) 
+        for (i = 0; i < count; i++)
             optEntryTable[i] = optStructToEntry(optStructTable[i]);
     }
     return(optEntryTable);
@@ -284,7 +284,7 @@ getToken(const char *  const tokenStart,
    doesn't necessarily advance.
 -----------------------------------------------------------------------------*/
     const char * error;
-    
+
     pm_gettoken(tokenStart, delimiter, tokenP, nextP, &error);
 
     if (error)
@@ -383,7 +383,7 @@ parseStringList(const char *   const listText,
  |
  |  FUNCTION      Perform the action of an option.
  |
- |  INPUT         opt     element in array of defined options that 
+ |  INPUT         opt     element in array of defined options that
  |                        applies to this option
  |                arg     argument to option, if it applies.
  |                lng     was the option given as a long option?
@@ -411,7 +411,7 @@ optExecute(optEntry  const opt, char *arg, int lng)
     case OPT_LONG: {
         long tmp;
         char *e;
-	  
+
         if (arg == NULL)
             optFatal("internal error: optExecute() called with NULL argument "
                      "'%s'", optString(opt, lng));
@@ -429,12 +429,12 @@ optExecute(optEntry  const opt, char *arg, int lng)
                 *((long *) opt.arg) = tmp;
         }
     } break;
-	
+
     case OPT_UINT:
     case OPT_ULONG: {
         unsigned long tmp;
         char * tailPtr;
-        
+
         if (arg == NULL)
             optFatal("internal error: optExecute() called with NULL argument "
                      "'%s'", optString(opt, lng));
@@ -460,7 +460,7 @@ optExecute(optEntry  const opt, char *arg, int lng)
     case OPT_FLOAT: {
         float tmp;
         char *e;
-	  
+
         if (arg == NULL)
             optFatal("internal error: optExecute() called with NULL argument "
                      "'%s'", optString(opt, lng));
@@ -597,7 +597,7 @@ pm_optParseOptions(int *argc, char *argv[], optStruct opt[], int allowNegNum)
             arg = NULL;
             if ((p = strchr(argv[ai], '=')) != NULL)
                 arg = p + 1;
-	    
+
             /* does this option take an argument? */
             optarg = -1;
             if (optNeedsArgument(opt_table[mi])) {
@@ -666,7 +666,7 @@ pm_optParseOptions(int *argc, char *argv[], optStruct opt[], int allowNegNum)
 
 static void
 parse_short_option_token(char *argv[], const int argc, const int ai,
-                         const optEntry opt_table[], 
+                         const optEntry opt_table[],
                          int * const tokens_consumed_p) {
 /*----------------------------------------------------------------------------
    Parse a cluster of short options, e.g. -walne .
@@ -681,7 +681,7 @@ parse_short_option_token(char *argv[], const int argc, const int ai,
     char *arg;
     int mi;   /* index into option table */
     unsigned char processed_arg;  /* boolean */
-        /* We processed an argument to one of the one-character options. 
+        /* We processed an argument to one of the one-character options.
            This necessarily means there are no more options in this token
            to process.
            */
@@ -707,7 +707,7 @@ parse_short_option_token(char *argv[], const int argc, const int ai,
             (*tokens_consumed_p)++;
 		    }
 		    processed_arg = 1;
-		} else 
+		} else
             arg = NULL;
 		/* perform the action of this option. */
 		optExecute(opt_table[mi], arg, 0);
@@ -761,7 +761,7 @@ parse_long_option(char *   const argv[],
                   int      const argc,
                   int      const ai,
                   int      const namepos,
-                  optEntry const opt_table[], 
+                  optEntry const opt_table[],
                   int *    const tokens_consumed_p) {
 /*----------------------------------------------------------------------------
    Parse a long option, e.g. -verbose or --verbose.
@@ -788,11 +788,11 @@ parse_long_option(char *   const argv[],
         fatalUnrecognizedLongOption(argv[ai], opt_table);
 
     /* possibly locate the argument to this option. */
-    { 
+    {
         char *p;
         if ((p = strchr(argv[ai], '=')) != NULL)
             equals_arg = p + 1;
-        else 
+        else
             equals_arg = NULL;
     }
     /* does this option take an argument? */
@@ -812,7 +812,7 @@ parse_long_option(char *   const argv[],
             optFatal("option `%s' doesn't allow an argument, but you "
                      "have specified it in the form name=value",
                      optString(opt_table[mi], 1));
-        else 
+        else
             arg = NULL;
     }
     /* perform the action of this option. */
@@ -849,7 +849,7 @@ parse_long_option(char *   const argv[],
  |
  |                This differs from pm_optParseOptions in that it accepts
  |                long options with just one hyphen and doesn't accept
- |                any short options.  It also has accommodations for 
+ |                any short options.  It also has accommodations for
  |                future expansion.
  |
  |                Options and arguments used are removed from the argv-
@@ -858,11 +858,11 @@ parse_long_option(char *   const argv[],
  |                Any error leads to program abortion.
  */
 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)
 /*----------------------------------------------------------------------------
    This does the same thing as pm_optParseOptions3(), except that there is no
-   "specified" return value.  
+   "specified" return value.
 
    This function exists for backward compatibility.
 -----------------------------------------------------------------------------*/
@@ -877,7 +877,7 @@ pm_optParseOptions2(int * const argc_p, char *argv[], const optStruct2 opt,
     if (opt3.opt_table == NULL)
         optFatal("Memory allocation failed (trying to allocate space for "
                  "new-format option table)");
-    
+
     pm_optParseOptions3(argc_p, argv, opt3, sizeof(opt3), flags);
 
     free(opt3.opt_table);
@@ -914,13 +914,13 @@ zero_specified(optEntry opt_table[]) {
  |                        Size of "opt" (since the caller may be older
  |                        than this function, it may be using a structure
  |                        with fewer fields than exist today.  We use this
- |                        parameter to handle those older callers). 
+ |                        parameter to handle those older callers).
  |                flags   Result is undefined if not zero.
  |                        For future expansion.
  |
  |  OUTPUT        argc    new argument count.
  |                argv    array with arguments removed.
- |                
+ |
  |                Areas pointed to by pointers in 'opt' get updated with
  |                option values and counts.
  |
@@ -934,7 +934,7 @@ zero_specified(optEntry opt_table[]) {
  |
  |                This differs from pm_optParseOptions in that it accepts
  |                long options with just one hyphen and doesn't accept
- |                any short options.  It also has accommodations for 
+ |                any short options.  It also has accommodations for
  |                future expansion.
  |
  |                Options and arguments used are removed from the argv-
@@ -943,7 +943,7 @@ zero_specified(optEntry opt_table[]) {
  |                Any error leads to program abortion.
  */
 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)
 {
     int  ai;        /* argv index. */
@@ -958,10 +958,10 @@ pm_optParseOptions3(int * const argc_p, char *argv[], const optStruct3 opt,
      */
     no_more_options = 0;  /* initial value */
     for (ai = 0; ai < *argc_p; ) {
-        if (no_more_options) 
+        if (no_more_options)
             /* Can't be an option -- there aren't any more */
             ai++;
-        else if (argv[ai][0] != '-') 
+        else if (argv[ai][0] != '-')
             /* Can't be an option -- doesn't start with a dash */
             ai++;
         else {
@@ -980,7 +980,7 @@ pm_optParseOptions3(int * const argc_p, char *argv[], const optStruct3 opt,
                     /* The entire thing is "--".  That means no more options */
                     tokens_consumed = 1;
                     no_more_options = 1;
-                } else 
+                } else
                     /* It's an option that starts with "--" */
                     parse_long_option(argv, *argc_p, ai, 2,
                                       opt.opt_table, &tokens_consumed);
@@ -994,7 +994,7 @@ pm_optParseOptions3(int * const argc_p, char *argv[], const optStruct3 opt,
                     parse_long_option(argv, *argc_p, ai, 1,
                                       opt.opt_table, &tokens_consumed);
                 }
-            
+
             }
             /* remove option and any argument from the argv-array. */
             {