/* libpnm3.c - pnm utility library part 3 ** ** Copyright (C) 1989, 1991 by Jef Poskanzer. ** ** Permission to use, copy, modify, and distribute this software and its ** documentation for any purpose and without fee is hereby granted, provided ** that the above copyright notice appear in all copies and that both that ** copyright notice and this permission notice appear in supporting ** documentation. This software is provided "as is" without express or ** implied warranty. */ #include "pnm.h" #include "ppm.h" #include "libppm.h" #include "pgm.h" #include "libpgm.h" #include "pbm.h" #include "libpbm.h" #if __STDC__ xel pnm_backgroundxel( xel** xels, int cols, int rows, xelval maxval, int format ) #else /*__STDC__*/ xel pnm_backgroundxel( xels, cols, rows, maxval, format ) xel** xels; int cols, rows, format; xelval maxval; #endif /*__STDC__*/ { xel bgxel, ul, ur, ll, lr; /* Guess a good background value. */ ul = xels[0][0]; ur = xels[0][cols-1]; 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; 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; } case PBM_TYPE: pm_error( "pnm_backgroundxel: four bits no two of which equal each other??" ); default: pm_error( "Invalid format passed to pnm_backgroundxel()"); } } return bgxel; } #if __STDC__ xel pnm_backgroundxelrow( xel* xelrow, int cols, xelval maxval, int format ) #else /*__STDC__*/ xel pnm_backgroundxelrow( xelrow, cols, maxval, format ) xel* xelrow; int cols, format; xelval maxval; #endif /*__STDC__*/ { 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) ) { 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; 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; } default: pm_error( "Invalid format passed to pnm_backgroundxelrow()"); } } return bgxel; } #if __STDC__ xel pnm_whitexel( xelval maxval, int format ) #else /*__STDC__*/ xel pnm_whitexel( maxval, format ) xelval maxval; int format; #endif /*__STDC__*/ { xel x; switch ( PNM_FORMAT_TYPE(format) ) { case PPM_TYPE: PPM_ASSIGN( x, maxval, maxval, maxval ); break; case PGM_TYPE: PNM_ASSIGN1( x, maxval ); break; case PBM_TYPE: PNM_ASSIGN1( x, maxval ); break; default: pm_error( "Invalid format passed to pnm_whitexel()"); } return x; } #if __STDC__ xel pnm_blackxel( xelval maxval, int format ) #else /*__STDC__*/ xel pnm_blackxel( maxval, format ) xelval maxval; int format; #endif /*__STDC__*/ { xel x; switch ( PNM_FORMAT_TYPE(format) ) { case PPM_TYPE: PPM_ASSIGN( x, 0, 0, 0 ); break; case PGM_TYPE: PNM_ASSIGN1( x, (xelval) 0 ); break; case PBM_TYPE: PNM_ASSIGN1( x, (xelval) 0 ); break; default: pm_error( "Invalid format passed to pnm_blackxel(): %d", format); } return x; } void pnm_invertxel(xel* const xP, xelval const maxval, int const format) { switch (PNM_FORMAT_TYPE(format)) { case PPM_TYPE: PPM_ASSIGN(*xP, maxval - PPM_GETR(*xP), maxval - PPM_GETG(*xP), maxval - PPM_GETB(*xP)); break; case PGM_TYPE: PNM_ASSIGN1(*xP, maxval - PNM_GET1(*xP)); break; case PBM_TYPE: PNM_ASSIGN1(*xP, (PNM_GET1(*xP) == 0) ? maxval : 0); break; default: pm_error("Invalid format passed to pnm_invertxel()"); } } #if __STDC__ void pnm_promoteformat( xel** xels, int cols, int rows, xelval maxval, int format, xelval newmaxval, int newformat ) #else /*__STDC__*/ void pnm_promoteformat( xels, cols, rows, maxval, format, newmaxval, newformat ) xel** xels; xelval maxval, newmaxval; int cols, rows, format, newformat; #endif /*__STDC__*/ { int row; for ( row = 0; row < rows; ++row ) pnm_promoteformatrow( xels[row], cols, maxval, format, newmaxval, newformat ); } #if __STDC__ void pnm_promoteformatrow( xel* xelrow, int cols, xelval maxval, int format, xelval newmaxval, int newformat ) #else /*__STDC__*/ void pnm_promoteformatrow( xelrow, cols, maxval, format, newmaxval, newformat ) xel* xelrow; xelval maxval, newmaxval; int cols, format, newformat; #endif /*__STDC__*/ { register int col; register xel* xP; if ( ( PNM_FORMAT_TYPE(format) == PPM_TYPE && ( PNM_FORMAT_TYPE(newformat) == PGM_TYPE || PNM_FORMAT_TYPE(newformat) == PBM_TYPE ) ) || ( PNM_FORMAT_TYPE(format) == PGM_TYPE && PNM_FORMAT_TYPE(newformat) == PBM_TYPE ) ) pm_error( "pnm_promoteformatrow: can't promote downwards!" ); /* Are we promoting to the same type? */ if ( PNM_FORMAT_TYPE(format) == PNM_FORMAT_TYPE(newformat) ) { if ( PNM_FORMAT_TYPE(format) == PBM_TYPE ) return; if ( newmaxval < maxval ) pm_error( "pnm_promoteformatrow: can't decrease maxval - try using pnmdepth" ); if ( newmaxval == maxval ) return; /* Increase maxval. */ switch ( PNM_FORMAT_TYPE(format) ) { case PGM_TYPE: for ( col = 0, xP = xelrow; col < cols; ++col, ++xP ) PNM_ASSIGN1( *xP, (int) PNM_GET1(*xP) * newmaxval / maxval ); break; case PPM_TYPE: for ( col = 0, xP = xelrow; col < cols; ++col, ++xP ) PPM_DEPTH( *xP, *xP, maxval, newmaxval ); break; default: pm_error( "Invalid old format passed to pnm_promoteformatrow()" ); } return; } /* We must be promoting to a higher type. */ switch ( PNM_FORMAT_TYPE(format) ) { case PBM_TYPE: switch ( PNM_FORMAT_TYPE(newformat) ) { case PGM_TYPE: for ( col = 0, xP = xelrow; col < cols; ++col, ++xP ) if ( PNM_GET1(*xP) == 0 ) PNM_ASSIGN1( *xP, 0 ); else PNM_ASSIGN1( *xP, newmaxval ); break; case PPM_TYPE: for ( col = 0, xP = xelrow; col < cols; ++col, ++xP ) if ( PNM_GET1(*xP) == 0 ) PPM_ASSIGN( *xP, 0, 0, 0 ); else PPM_ASSIGN( *xP, newmaxval, newmaxval, newmaxval ); break; default: pm_error( "Invalid new format passed to pnm_promoteformatrow()" ); } break; case PGM_TYPE: switch ( PNM_FORMAT_TYPE(newformat) ) { case PPM_TYPE: if ( newmaxval < maxval ) pm_error( "pnm_promoteformatrow: can't decrease maxval - try using pnmdepth" ); if ( newmaxval == maxval ) { for ( col = 0, xP = xelrow; col < cols; ++col, ++xP ) PPM_ASSIGN( *xP, PNM_GET1(*xP), PNM_GET1(*xP), PNM_GET1(*xP) ); } else { /* Increase maxval. */ for ( col = 0, xP = xelrow; col < cols; ++col, ++xP ) PPM_ASSIGN( *xP, (int) PNM_GET1(*xP) * newmaxval / maxval, (int) PNM_GET1(*xP) * newmaxval / maxval, (int) PNM_GET1(*xP) * newmaxval / maxval ); } break; default: pm_error( "Invalid new format passed to pnm_promoteformatrow()" ); } break; default: pm_error( "Invalid old format passed to pnm_promoteformatrow()" ); } } pixel pnm_xeltopixel(xel const inputxel, int const format) { pixel outputpixel; switch (PNM_FORMAT_TYPE(format)) { case PPM_TYPE: PPM_ASSIGN(outputpixel, PPM_GETR(inputxel), PPM_GETG(inputxel), PPM_GETB(inputxel)); break; case PGM_TYPE: case PBM_TYPE: PPM_ASSIGN(outputpixel, PNM_GET1(inputxel), PNM_GET1(inputxel), PNM_GET1(inputxel)); break; default: pm_error("Invalid format code %d passed to pnm_xeltopixel()", format); } return outputpixel; }