about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--doc/HISTORY10
-rw-r--r--lib/libpnm3.c198
2 files changed, 116 insertions, 92 deletions
diff --git a/doc/HISTORY b/doc/HISTORY
index e1a4ac1b..f0f96ff1 100644
--- a/doc/HISTORY
+++ b/doc/HISTORY
@@ -18,9 +18,19 @@ not yet  BJH  Release 10.44.00
 
               pnmpaste: fail if user specified stdin for both images.
 
+              pnm_backgroundxel(), pnm_backgroundxelrow() (affects
+              pnmrotate, pnmshear, pnmcrop, pnmcat: correctly average
+              corner colors to determine background (fill) color.
+
               pamcut: don't crash when cutting a region entirely to the
               left or right of the input image, with -pad.
 
+              pgmhist: arbitrary output when total pixels doesn't fit in an
+              integer.
+
+              pamcomp: fix bug: arbitrary output when combined number of rows
+              doesn't fit in an integer.
+
               pamtosvg: remove "needed exchange" debug trace.
 
               Add pbmminkowski (source code has been in package since 10.12
diff --git a/lib/libpnm3.c b/lib/libpnm3.c
index 71df0cbf..c41a2108 100644
--- a/lib/libpnm3.c
+++ b/lib/libpnm3.c
@@ -11,16 +11,54 @@
 */
 
 #include "pnm.h"
-
 #include "ppm.h"
-
 #include "pgm.h"
-
 #include "pbm.h"
 
+
+
+static xel
+mean4(int const format,
+      xel const a,
+      xel const b,
+      xel const c,
+      xel const d) {
+/*----------------------------------------------------------------------------
+   Return cartesian mean of the 4 colors.
+-----------------------------------------------------------------------------*/
+    xel retval;
+
+    switch (PNM_FORMAT_TYPE(format)) {
+    case PPM_TYPE:
+        PPM_ASSIGN(
+            retval,
+            (PPM_GETR(a) + PPM_GETR(b) + PPM_GETR(c) + PPM_GETR(d)) / 4,
+            (PPM_GETG(a) + PPM_GETG(b) + PPM_GETG(c) + PPM_GETG(d)) / 4,
+            (PPM_GETB(a) + PPM_GETB(b) + PPM_GETB(c) + PPM_GETB(d)) / 4);
+        break;
+
+    case PGM_TYPE:
+    case PBM_TYPE:
+        PNM_ASSIGN1(
+            retval,
+            (PNM_GET1(a) + PNM_GET1(b) + PNM_GET1(c) + PNM_GET1(d))/4);
+        break;
+
+    default:
+        pm_error( "Invalid format passed to pnm_backgroundxel()");
+    }
+    return retval;
+}
+
+
+
 xel
-pnm_backgroundxel( xel** xels, int cols, int rows, xelval maxval, int format )
-    {
+pnm_backgroundxel(xel**  const xels,
+                  int    const cols,
+                  int    const rows,
+                  xelval const maxval,
+                  int    const format) {
+
     xel bgxel, ul, ur, ll, lr;
 
     /* Guess a good background value. */
@@ -29,115 +67,91 @@ pnm_backgroundxel( xel** xels, int cols, int rows, xelval maxval, int format )
     ll = xels[rows-1][0];
     lr = xels[rows-1][cols-1];
 
-    /* First check for three corners equal. */
-    if ( PNM_EQUAL( ul, ur ) && PNM_EQUAL( ur, ll ) )
-    bgxel = ul;
-    else if ( PNM_EQUAL( ul, ur ) && PNM_EQUAL( ur, lr ) )
-    bgxel = ul;
-    else if ( PNM_EQUAL( ul, ll ) && PNM_EQUAL( ll, lr ) )
-    bgxel = ul;
-    else if ( PNM_EQUAL( ur, ll ) && PNM_EQUAL( ll, lr ) )
-    bgxel = ur;
-    /* Nope, check for two corners equal. */
-    else if ( PNM_EQUAL( ul, ur ) || PNM_EQUAL( ul, ll ) ||
-          PNM_EQUAL( ul, lr ) )
-    bgxel = ul;
-    else if ( PNM_EQUAL( ur, ll ) || PNM_EQUAL( ur, lr ) )
-    bgxel = ur;
-    else if ( PNM_EQUAL( ll, lr ) )
-    bgxel = ll;
+    /* We first recognize three corners equal.  If not, we look for any
+       two.  If not, we just average all four.
+    */
+    if (PNM_EQUAL(ul, ur) && PNM_EQUAL(ur, ll))
+        bgxel = ul;
+    else if (PNM_EQUAL(ul, ur) && PNM_EQUAL(ur, lr))
+        bgxel = ul;
+    else if (PNM_EQUAL(ul, ll) && PNM_EQUAL(ll, lr))
+        bgxel = ul;
+    else if (PNM_EQUAL(ur, ll) && PNM_EQUAL(ll, lr))
+        bgxel = ur;
+    else if (PNM_EQUAL(ul, ur))
+        bgxel = ul;
+    else if (PNM_EQUAL(ul, ll))
+        bgxel = ul;
+    else if (PNM_EQUAL(ul, lr))
+        bgxel = ul;
+    else if (PNM_EQUAL(ur, ll))
+        bgxel = ur;
+    else if (PNM_EQUAL(ur, lr))
+        bgxel = ur;
+    else if (PNM_EQUAL(ll, lr))
+        bgxel = ll;
     else
-    {
-    /* Nope, we have to average the four corners.  This breaks the
-    ** rules of pnm, but oh well.  Let's try to do it portably. */
-    switch ( PNM_FORMAT_TYPE(format) )
-        {
-        case PPM_TYPE:
-        PPM_ASSIGN( bgxel,
-        PPM_GETR(ul) + PPM_GETR(ur) + PPM_GETR(ll) + PPM_GETR(lr) / 4,
-        PPM_GETG(ul) + PPM_GETG(ur) + PPM_GETG(ll) + PPM_GETG(lr) / 4,
-        PPM_GETB(ul) + PPM_GETB(ur) + PPM_GETB(ll) + PPM_GETB(lr) / 4 );
-        break;
-
-        case PGM_TYPE:
-        {
-        gray gul, gur, gll, glr;
-        gul = (gray) PNM_GET1( ul );
-        gur = (gray) PNM_GET1( ur );
-        gll = (gray) PNM_GET1( ll );
-        glr = (gray) PNM_GET1( lr );
-        PNM_ASSIGN1( bgxel, ( ( gul + gur + gll + glr ) / 4 ) );
-        break;
-        }
+        bgxel = mean4(format, ul, ur, ll, lr);
 
-        case PBM_TYPE:
-        pm_error(
-        "pnm_backgroundxel: four bits no two of which equal each other??" );
+    return bgxel;
+}
 
-        default:
-        pm_error( "Invalid format passed to pnm_backgroundxel()");
-        }
-    }
 
-    return bgxel;
-    }
 
 xel
-pnm_backgroundxelrow( xel* xelrow, int cols, xelval maxval, int format )
-    {
+pnm_backgroundxelrow(xel *  const xelrow,
+                     int    const cols,
+                     xelval const maxval,
+                     int    const format) {
+
     xel bgxel, l, r;
 
     /* Guess a good background value. */
     l = xelrow[0];
     r = xelrow[cols-1];
 
-    /* First check for both corners equal. */
-    if ( PNM_EQUAL( l, r ) )
-    bgxel = l;
-    else
-    {
-    /* Nope, we have to average the two corners.  This breaks the
-    ** rules of pnm, but oh well.  Let's try to do it portably. */
-    switch ( PNM_FORMAT_TYPE(format) )
-        {
+    if (PNM_EQUAL(l, r))
+        /* Both corners are same color, so that's the background color,
+           without any extra computation.
+        */
+        bgxel = l;
+    else {
+        /* Corners are different, so use cartesian mean of them */
+        switch (PNM_FORMAT_TYPE(format)) {
         case PPM_TYPE:
-        PPM_ASSIGN( bgxel, PPM_GETR(l) + PPM_GETR(r) / 2,
-        PPM_GETG(l) + PPM_GETG(r) / 2, PPM_GETB(l) + PPM_GETB(r) / 2 );
-        break;
+            PPM_ASSIGN(bgxel,
+                       (PPM_GETR(l) + PPM_GETR(r)) / 2,
+                       (PPM_GETG(l) + PPM_GETG(r)) / 2,
+                       (PPM_GETB(l) + PPM_GETB(r)) / 2
+                );
+            break;
 
         case PGM_TYPE:
-        {
-        gray gl, gr;
-        gl = (gray) PNM_GET1( l );
-        gr = (gray) PNM_GET1( r );
-        PNM_ASSIGN1( bgxel, ( ( gl + gr ) / 2 ) );
-        break;
-        }
-
-        case PBM_TYPE:
-        {
-        int col, blacks;
-
-        /* One black, one white.  Gotta count. */
-        for ( col = 0, blacks = 0; col < cols; ++col )
-        {
-        if ( PNM_GET1( xelrow[col] ) == 0 )
-            ++blacks;
-        }
-        if ( blacks >= cols / 2 )
-        PNM_ASSIGN1( bgxel, 0 );
-        else
-        PNM_ASSIGN1( bgxel, maxval );
-        break;
+            PNM_ASSIGN1(bgxel, (PNM_GET1(l) + PNM_GET1(r)) / 2);
+            break;
+
+        case PBM_TYPE: {
+            unsigned int col, blackCnt;
+
+            /* One black, one white.  Gotta count. */
+            for (col = 0, blackCnt = 0; col < cols; ++col) {
+                if (PNM_GET1(xelrow[col] ) == 0)
+                    ++blackCnt;
+            }
+            if (blackCnt >= cols / 2)
+                PNM_ASSIGN1(bgxel, 0);
+            else
+                PNM_ASSIGN1(bgxel, maxval);
+            break;
         }
 
         default:
-        pm_error( "Invalid format passed to pnm_backgroundxelrow()");
+            pm_error("Invalid format passed to pnm_backgroundxelrow()");
         }
     }
 
     return bgxel;
-    }
+}