diff options
Diffstat (limited to 'editor/pbmmask.c')
-rw-r--r-- | editor/pbmmask.c | 394 |
1 files changed, 254 insertions, 140 deletions
diff --git a/editor/pbmmask.c b/editor/pbmmask.c index 25c71226..0be10435 100644 --- a/editor/pbmmask.c +++ b/editor/pbmmask.c @@ -10,13 +10,57 @@ ** implied warranty. */ +#include <stdbool.h> +#include <assert.h> + #include "pbm.h" +#include "shhopt.h" #include "mallocvar.h" -static bit ** bits; -static bit ** mask; -static bit backcolor; -static int rows, cols; +struct CmdlineInfo { + /* All the information the user supplied in the command line, + in a form easy for the program to use. + */ + const char * inputFileName; /* File name of input file */ + unsigned int expand; +}; + + + +static void +parseCommandLine(int argc, const char ** argv, + struct CmdlineInfo * const cmdlineP) { +/*---------------------------------------------------------------------------- + Note that the file spec array we return is stored in the storage that + was passed to us as the argv array. +-----------------------------------------------------------------------------*/ + optStruct3 opt; /* set by OPTENT3 */ + optEntry * option_def; + unsigned int option_def_index; + + MALLOCARRAY(option_def, 100); + + option_def_index = 0; /* incremented by OPTENT3 */ + OPTENT3(0, "expand", OPT_FLAG, NULL, &cmdlineP->expand, 0); + + opt.opt_table = option_def; + opt.short_allowed = false; /* We have no short (old-fashioned) options */ + opt.allowNegNum = true; /* We sort of allow negative numbers as parms */ + + pm_optParseOptions3(&argc, (char **)argv, opt, sizeof(opt), 0); + /* Uses and sets argc, argv, and some of *cmdlineP and others. */ + + free(option_def); + + if (argc-1 < 1) + cmdlineP->inputFileName = "-"; + else if (argc-1 == 1) + cmdlineP->inputFileName = argv[1]; + else + pm_error("You specified too many arguments (%u). The only " + "possible argument is the optional input file specification.", + argc-1); +} @@ -28,25 +72,78 @@ static int fstackp = 0; static void -addflood(int const col, - int const row) { +clearMask(bit ** const mask, + unsigned int const cols, + unsigned int const rows) { + + /* Clear out the mask. */ + unsigned int row; - if ( bits[row][col] == backcolor && mask[row][col] == PBM_BLACK ) { - if ( fstackp >= fstacksize ) { - if ( fstacksize == 0 ) { + for (row = 0; row < rows; ++row) { + unsigned int col; + + for (col = 0; col < cols; ++col) + mask[row][col] = PBM_BLACK; + } +} + + + +static bit +backcolorFmImage(bit ** const bits, + unsigned int const cols, + unsigned int const rows) { + + /* Figure out the background color, by counting along the edge. */ + + unsigned int row; + unsigned int col; + unsigned int wcount; + + assert(cols > 0); assert(rows > 0); + + wcount = 0; + for (row = 0; row < rows; ++row) { + if (bits[row][0] == PBM_WHITE) + ++wcount; + if (bits[row][cols - 1] == PBM_WHITE) + ++wcount; + } + for (col = 1; col < cols - 1; ++col) { + if (bits[0][col] == PBM_WHITE) + ++wcount; + if (bits[rows - 1][col] == PBM_WHITE) + ++wcount; + } + + return (wcount >= rows + cols - 2) ? PBM_WHITE : PBM_BLACK; +} + + + +static void +addflood(bit ** const bits, + bit ** const mask, + unsigned int const col, + unsigned int const row, + bit const backcolor) { + + if (bits[row][col] == backcolor && mask[row][col] == PBM_BLACK) { + if (fstackp >= fstacksize) { + if (fstacksize == 0) { fstacksize = 1000; MALLOCARRAY(fcols, fstacksize); MALLOCARRAY(frows, fstacksize); - if ( fcols == NULL || frows == NULL ) - pm_error( "out of memory" ); + if (fcols == NULL || frows == NULL) + pm_error("out of memory"); } else { fstacksize *= 2; fcols = (short*) realloc( - (char*) fcols, fstacksize * sizeof(short) ); + (char*) fcols, fstacksize * sizeof(short)); frows = (short*) realloc( - (char*) frows, fstacksize * sizeof(short) ); - if ( fcols == (short*) 0 || frows == (short*) 0 ) - pm_error( "out of memory" ); + (char*) frows, fstacksize * sizeof(short)); + if (fcols == (short*) 0 || frows == (short*)0) + pm_error("out of memory"); } } fcols[fstackp] = col; @@ -58,46 +155,81 @@ addflood(int const col, static void -flood(void) { +floodEdge(bit ** const bits, + unsigned int const cols, + unsigned int const rows, + bit const backcolor, + bit ** const mask) { + + int col; + int row; + + /* Flood the entire edge. Probably the first call will be enough, but + might as well be sure. + */ + assert(cols > 0); assert(rows > 0); + + for (col = cols - 3; col >= 2; col -= 2) { + addflood(bits, mask, col, rows - 1, backcolor); + addflood(bits, mask, col, 0, backcolor); + } + for (row = rows - 1; row >= 0; row -= 2) { + addflood(bits, mask, cols - 1, row, backcolor); + addflood(bits, mask, 0, row, backcolor); + } +} + + + +static void +flood(bit ** const bits, + unsigned int const cols, + unsigned int const rows, + bit const backcolor, + bit ** const mask) { + + assert(cols > 0); assert(rows > 0); - while ( fstackp > 0 ) { + floodEdge(bits, cols, rows, backcolor, mask); + + while (fstackp > 0) { int col, row; --fstackp; col = fcols[fstackp]; row = frows[fstackp]; - if ( bits[row][col] == backcolor && mask[row][col] == PBM_BLACK ) { + if (bits[row][col] == backcolor && mask[row][col] == PBM_BLACK) { int c; mask[row][col] = PBM_WHITE; - if ( row - 1 >= 0 ) - addflood( col, row - 1 ); - if ( row + 1 < rows ) - addflood( col, row + 1 ); - for ( c = col + 1; c < cols; ++c ) { - if ( bits[row][c] == backcolor && mask[row][c] == PBM_BLACK ) { + if (row - 1 >= 0) + addflood(bits, mask, col, row - 1, backcolor); + if (row + 1 < rows) + addflood(bits, mask, col, row + 1, backcolor); + for (c = col + 1; c < cols; ++c) { + if (bits[row][c] == backcolor && mask[row][c] == PBM_BLACK) { mask[row][c] = PBM_WHITE; - if ( row - 1 >= 0 && - ( bits[row - 1][c - 1] != backcolor || - mask[row - 1][c - 1] != PBM_BLACK ) ) - addflood( c, row - 1 ); - if ( row + 1 < rows && - ( bits[row + 1][c - 1] != backcolor || - mask[row + 1][c - 1] != PBM_BLACK ) ) - addflood( c, row + 1 ); + if (row - 1 >= 0 && + (bits[row - 1][c - 1] != backcolor || + mask[row - 1][c - 1] != PBM_BLACK)) + addflood(bits, mask, c, row - 1, backcolor); + if (row + 1 < rows && + (bits[row + 1][c - 1] != backcolor || + mask[row + 1][c - 1] != PBM_BLACK)) + addflood(bits, mask, c, row + 1, backcolor); } else break; } - for ( c = col - 1; c >= 0; --c ) { - if ( bits[row][c] == backcolor && mask[row][c] == PBM_BLACK ) { + for (c = col - 1; c >= 0; --c) { + if (bits[row][c] == backcolor && mask[row][c] == PBM_BLACK) { mask[row][c] = PBM_WHITE; - if ( row - 1 >= 0 && - ( bits[row - 1][c + 1] != backcolor || - mask[row - 1][c + 1] != PBM_BLACK ) ) - addflood( c, row - 1 ); - if ( row + 1 < rows && - ( bits[row + 1][c + 1] != backcolor || - mask[row + 1][c + 1] != PBM_BLACK ) ) - addflood( c, row + 1 ); + if (row - 1 >= 0 && + (bits[row - 1][c + 1] != backcolor || + mask[row - 1][c + 1] != PBM_BLACK)) + addflood(bits, mask, c, row - 1, backcolor); + if (row + 1 < rows && + (bits[row + 1][c + 1] != backcolor || + mask[row + 1][c + 1] != PBM_BLACK)) + addflood(bits, mask, c, row + 1, backcolor); } else break; } @@ -107,121 +239,103 @@ flood(void) { -int -main(int argc, char * argv[]) { - - FILE* ifp; - int argn, expand, wcount; - register int row, col; - const char* const usage = "[-expand] [pbmfile]"; - - pbm_init( &argc, argv ); - - argn = 1; - expand = 0; - - if ( argn < argc && argv[argn][0] == '-' && argv[argn][1] != '\0' ) - { - if ( pm_keymatch( argv[argn], "-expand", 2 ) ) - expand = 1; - else if ( pm_keymatch( argv[argn], "-noexpand", 2 ) ) - expand = 0; - else - pm_usage( usage ); - ++argn; - } +static bit ** +expandedByOnePixel(bit ** const mask, + unsigned int const cols, + unsigned int const rows) { - if ( argn == argc ) - ifp = stdin; - else - { - ifp = pm_openr( argv[argn] ); - ++argn; + /* Expand by one pixel. */ + + bit ** const emask = pbm_allocarray(cols, rows); + + unsigned int row; + + for (row = 0; row < rows; ++row) { + unsigned int col; + for (col = 0; col < cols; ++col) + if (mask[row][col] == PBM_BLACK) + emask[row][col] = PBM_BLACK; + else { + unsigned int srow; + + emask[row][col] = PBM_WHITE; + + for (srow = row - 1; srow <= row + 1; ++srow) { + unsigned int scol; + + for (scol = col - 1; scol <= col + 1; ++scol) { + if (srow >= 0 && srow < rows && + scol >= 0 && scol < cols && + mask[srow][scol] == PBM_BLACK) { + + emask[row][col] = PBM_BLACK; + break; + } + } + } + } } + return emask; +} + + - if ( argn != argc ) - pm_usage( usage ); +static void +pbmmask(FILE * const ifP, + FILE * const ofP, + struct CmdlineInfo const cmdline) { + + int cols, rows; + bit ** mask; + bit ** bits; + bit backcolor; - bits = pbm_readpbm( ifp, &cols, &rows ); + bits = pbm_readpbm(ifP, &cols, &rows); if (cols == 0 || rows == 0) pm_error("Image contains no pixels, so there is no such thing " "as background and foreground"); - pm_close( ifp ); - mask = pbm_allocarray( cols, rows ); + mask = pbm_allocarray(cols, rows); - /* Clear out the mask. */ - for ( row = 0; row < rows; ++row ) - for ( col = 0; col < cols; ++col ) - mask[row][col] = PBM_BLACK; + clearMask(mask, cols, rows); - /* Figure out the background color, by counting along the edge. */ - wcount = 0; - for ( row = 0; row < rows; ++row ) { - if ( bits[row][0] == PBM_WHITE ) - ++wcount; - if ( bits[row][cols - 1] == PBM_WHITE ) - ++wcount; - } - for ( col = 1; col < cols - 1; ++col ) { - if ( bits[0][col] == PBM_WHITE ) - ++wcount; - if ( bits[rows - 1][col] == PBM_WHITE ) - ++wcount; - } - if ( wcount >= rows + cols - 2 ) - backcolor = PBM_WHITE; - else - backcolor = PBM_BLACK; + backcolor = backcolorFmImage(bits, cols, rows); - /* Flood the entire edge. Probably the first call will be enough, but - might as well be sure. - */ - for ( col = cols - 3; col >= 2; col -= 2 ) { - addflood( col, rows - 1 ); - addflood( col, 0 ); - } - for ( row = rows - 1; row >= 0; row -= 2 ) { - addflood( cols - 1, row ); - addflood( 0, row ); - } - flood( ); + flood(bits, cols, rows, backcolor, mask); - if ( ! expand ) + if (!cmdline.expand) { /* Done. */ - pbm_writepbm( stdout, mask, cols, rows, 0 ); - else { - /* Expand by one pixel. */ - int srow, scol; - unsigned int row; - bit ** emask; - - emask = pbm_allocarray( cols, rows ); - - for ( row = 0; row < rows; ++row ) { - unsigned int col; - for ( col = 0; col < cols; ++col ) - if ( mask[row][col] == PBM_BLACK ) - emask[row][col] = PBM_BLACK; - else { - emask[row][col] = PBM_WHITE; - for ( srow = row - 1; srow <= row + 1; ++srow ) - for ( scol = col - 1; scol <= col + 1; ++scol ) - if ( srow >= 0 && srow < rows && - scol >= 0 && scol < cols && - mask[srow][scol] == PBM_BLACK ) { - - emask[row][col] = PBM_BLACK; - break; - } - } - } - pbm_writepbm( stdout, emask, cols, rows, 0 ); + pbm_writepbm(stdout, mask, cols, rows, 0); + } else { + bit ** const emask = expandedByOnePixel(mask, cols, rows); + + pbm_writepbm(stdout, emask, cols, rows, 0); + + pbm_freearray(emask, rows); } +} + + + +int +main(int argc, const char ** argv) { - pm_close( stdout ); + struct CmdlineInfo cmdline; + FILE * ifP; + + pm_proginit(&argc, argv); + + parseCommandLine(argc, argv, &cmdline); + + ifP = pm_openr(cmdline.inputFileName); + + pbmmask(ifP, stdout, cmdline); + + pm_close(ifP); + pm_close(stdout); return 0; } + |