home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / netpbma.zip / pbm / pbmmask.c < prev    next >
C/C++ Source or Header  |  1993-10-04  |  5KB  |  224 lines

  1. /* pbmmask.c - create a mask bitmap from a portable bitmap
  2. **
  3. ** Copyright (C) 1989, 1991 by Jef Poskanzer.
  4. **
  5. ** Permission to use, copy, modify, and distribute this software and its
  6. ** documentation for any purpose and without fee is hereby granted, provided
  7. ** that the above copyright notice appear in all copies and that both that
  8. ** copyright notice and this permission notice appear in supporting
  9. ** documentation.  This software is provided "as is" without express or
  10. ** implied warranty.
  11. */
  12.  
  13. #include "pbm.h"
  14.  
  15. static void addflood ARGS(( int col, int row ));
  16. static void flood ARGS(( void ));
  17.  
  18. static bit** bits;
  19. static bit** mask;
  20. static bit backcolor;
  21. static int rows, cols;
  22.  
  23. int
  24. main( argc, argv )
  25.     int argc;
  26.     char* argv[];
  27.     {
  28.     FILE* ifp;
  29.     int argn, expand, wcount;
  30.     register int row, col;
  31.     char* usage = "[-expand] [pbmfile]";
  32.  
  33.  
  34.     pbm_init( &argc, argv );
  35.  
  36.     argn = 1;
  37.     expand = 0;
  38.  
  39.     if ( argn < argc && argv[argn][0] == '-' && argv[argn][1] != '\0' )
  40.     {
  41.     if ( pm_keymatch( argv[argn], "-expand", 2 ) )
  42.         expand = 1;
  43.     else if ( pm_keymatch( argv[argn], "-noexpand", 2 ) )
  44.         expand = 0;
  45.     else
  46.         pm_usage( usage );
  47.     ++argn;
  48.     }
  49.  
  50.     if ( argn == argc )
  51.     ifp = stdin;
  52.     else
  53.     {
  54.     ifp = pm_openr( argv[argn] );
  55.     ++argn;
  56.     }
  57.  
  58.     if ( argn != argc )
  59.     pm_usage( usage );
  60.  
  61.     bits = pbm_readpbm( ifp, &cols, &rows );
  62.     pm_close( ifp );
  63.     mask = pbm_allocarray( cols, rows );
  64.  
  65.     /* Clear out the mask. */
  66.     for ( row = 0; row < rows; ++row )
  67.         for ( col = 0; col < cols; ++col )
  68.         mask[row][col] = PBM_BLACK;
  69.  
  70.     /* Figure out the background color, by counting along the edge. */
  71.     wcount = 0;
  72.     for ( row = 0; row < rows; ++row )
  73.     {
  74.     if ( bits[row][0] == PBM_WHITE )
  75.         ++wcount;
  76.     if ( bits[row][cols - 1] == PBM_WHITE )
  77.         ++wcount;
  78.     }
  79.     for ( col = 1; col < cols - 1; ++col )
  80.     {
  81.     if ( bits[0][col] == PBM_WHITE )
  82.         ++wcount;
  83.     if ( bits[rows - 1][col] == PBM_WHITE )
  84.         ++wcount;
  85.     }
  86.     if ( wcount >= rows + cols - 2 )
  87.     backcolor = PBM_WHITE;
  88.     else
  89.     backcolor = PBM_BLACK;
  90.  
  91.     /* Flood the entire edge.  Probably the first call will be enough, but
  92.     ** might as well be sure. */
  93.     for ( col = cols - 3; col >= 2; col -= 2 )
  94.     {
  95.     addflood( col, rows - 1 );
  96.     addflood( col, 0 );
  97.     }
  98.     for ( row = rows - 1; row >= 0; row -= 2 )
  99.     {
  100.     addflood( cols - 1, row );
  101.     addflood( 0, row );
  102.     }
  103.     flood( );
  104.  
  105.     if ( ! expand )
  106.     /* Done. */
  107.     pbm_writepbm( stdout, mask, cols, rows, 0 );
  108.     else
  109.     { /* Expand by one pixel. */
  110.     register int srow, scol;
  111.     bit** emask;
  112.  
  113.     emask = pbm_allocarray( cols, rows );
  114.  
  115.     for ( row = 0; row < rows; ++row )
  116.         for ( col = 0; col < cols; ++col )
  117.         if ( mask[row][col] == PBM_BLACK )
  118.             emask[row][col] = PBM_BLACK;
  119.         else
  120.             {
  121.             emask[row][col] = PBM_WHITE;
  122.             for ( srow = row - 1; srow <= row + 1; ++srow )
  123.             for ( scol = col - 1; scol <= col + 1; ++scol )
  124.                 if ( srow >= 0 && srow < rows &&
  125.                  scol >= 0 && scol < cols &&
  126.                  mask[srow][scol] == PBM_BLACK )
  127.                 {
  128.                 emask[row][col] = PBM_BLACK;
  129.                 break;
  130.                 }
  131.             }
  132.  
  133.     /* Done. */
  134.     pbm_writepbm( stdout, emask, cols, rows, 0 );
  135.     }
  136.  
  137.     pm_close( stdout );
  138.     exit( 0 );
  139.     }
  140.  
  141. static short* fcols;
  142. static short* frows;
  143. static int fstacksize = 0, fstackp = 0;
  144.  
  145. static void
  146. addflood( col, row )
  147. int col, row;
  148.     {
  149.     if ( bits[row][col] == backcolor && mask[row][col] == PBM_BLACK )
  150.     {
  151.     if ( fstackp >= fstacksize )
  152.         {
  153.         if ( fstacksize == 0 )
  154.         {
  155.         fstacksize = 1000;
  156.         fcols = (short*) malloc( fstacksize * sizeof(short) );
  157.         frows = (short*) malloc( fstacksize * sizeof(short) );
  158.         if ( fcols == (short*) 0 || frows == (short*) 0 )
  159.             pm_error( "out of memory" );
  160.         }
  161.         else
  162.         {
  163.         fstacksize *= 2;
  164.         fcols = (short*) realloc(
  165.             (char*) fcols, fstacksize * sizeof(short) );
  166.         frows = (short*) realloc(
  167.             (char*) frows, fstacksize * sizeof(short) );
  168.         if ( fcols == (short*) 0 || frows == (short*) 0 )
  169.             pm_error( "out of memory" );
  170.         }
  171.         }
  172.     fcols[fstackp] = col;
  173.     frows[fstackp] = row;
  174.     ++fstackp;
  175.     }
  176.     }
  177.  
  178. static void
  179. flood( )
  180.     {
  181.     register int col, row, c;
  182.  
  183.     while ( fstackp > 0 )
  184.     {
  185.     --fstackp;
  186.     col = fcols[fstackp];
  187.     row = frows[fstackp];
  188.     if ( bits[row][col] == backcolor && mask[row][col] == PBM_BLACK )
  189.         {
  190.         mask[row][col] = PBM_WHITE;
  191.         if ( row - 1 >= 0 )
  192.         addflood( col, row - 1 );
  193.         if ( row + 1 < rows )
  194.         addflood( col, row + 1 );
  195.         for ( c = col + 1; c < cols; ++c )
  196.         {
  197.         if ( bits[row][c] == backcolor && mask[row][c] == PBM_BLACK )
  198.             {
  199.             mask[row][c] = PBM_WHITE;
  200.             if ( row - 1 >= 0 && ( bits[row - 1][c - 1] != backcolor || mask[row - 1][c - 1] != PBM_BLACK ) )
  201.             addflood( c, row - 1 );
  202.             if ( row + 1 < rows && ( bits[row + 1][c - 1] != backcolor || mask[row + 1][c - 1] != PBM_BLACK ) )
  203.             addflood( c, row + 1 );
  204.             }
  205.         else
  206.             break;
  207.         }
  208.         for ( c = col - 1; c >= 0; --c )
  209.         {
  210.         if ( bits[row][c] == backcolor && mask[row][c] == PBM_BLACK )
  211.             {
  212.             mask[row][c] = PBM_WHITE;
  213.             if ( row - 1 >= 0 && ( bits[row - 1][c + 1] != backcolor || mask[row - 1][c + 1] != PBM_BLACK ) )
  214.             addflood( c, row - 1 );
  215.             if ( row + 1 < rows && ( bits[row + 1][c + 1] != backcolor || mask[row + 1][c + 1] != PBM_BLACK ) )
  216.             addflood( c, row + 1 );
  217.             }
  218.         else
  219.             break;
  220.         }
  221.         }
  222.     }
  223.     }
  224.