diff options
-rw-r--r-- | doc/HISTORY | 10 | ||||
-rw-r--r-- | lib/libpnm3.c | 198 |
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; - } +} |