/* pbmmask.c - create a mask bitmap from a portable bitmap ** ** 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 "pbm.h" #include "mallocvar.h" static bit ** bits; static bit ** mask; static bit backcolor; static int rows, cols; static short * fcols; static short * frows; static int fstacksize = 0; static int fstackp = 0; static void addflood(int const col, int const row) { 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" ); } else { fstacksize *= 2; fcols = (short*) realloc( (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" ); } } fcols[fstackp] = col; frows[fstackp] = row; ++fstackp; } } static void flood(void) { while ( fstackp > 0 ) { int col, row; --fstackp; col = fcols[fstackp]; row = frows[fstackp]; 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 ) { 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 ); } else break; } 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 ); } else break; } } } } 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; } if ( argn == argc ) ifp = stdin; else { ifp = pm_openr( argv[argn] ); ++argn; } if ( argn != argc ) pm_usage( usage ); bits = pbm_readpbm( ifp, &cols, &rows ); pm_close( ifp ); 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; /* 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; /* 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( ); if ( ! 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 ); } pm_close( stdout ); return 0; }