about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--editor/pbmmask.c333
1 files changed, 221 insertions, 112 deletions
diff --git a/editor/pbmmask.c b/editor/pbmmask.c
index 0def35cc..7fc3f446 100644
--- a/editor/pbmmask.c
+++ b/editor/pbmmask.c
@@ -10,13 +10,56 @@
 ** implied warranty.
 */
 
+#include <stdbool.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,8 +71,59 @@ 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;
+
+    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;
+
+    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) {
@@ -38,15 +132,15 @@ addflood(int const col,
                 MALLOCARRAY(fcols, fstacksize);
                 MALLOCARRAY(frows, fstacksize);
                 if (fcols == NULL || frows == NULL)
-                    pm_error( "out of memory" );
+                    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,7 +152,38 @@ 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.
+    */
+    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) {
+
+    floodEdge(bits, cols, rows, backcolor, mask);
 
     while (fstackp > 0) {
         int col, row;
@@ -69,35 +194,35 @@ flood(void) {
             int c;
             mask[row][col] = PBM_WHITE;
             if (row - 1 >= 0)
-                addflood(col, row - 1);
+                addflood(bits, mask, col, row - 1, backcolor);
             if (row + 1 < rows)
-                addflood(col, row + 1);
+                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);
+                        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(c, row + 1);
+                        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 ) {
+                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);
+                        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(c, row + 1);
+                        addflood(bits, mask, c, row + 1, backcolor);
                 } else
                     break;
             }
@@ -107,115 +232,99 @@ 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. */
 
-    if (argn != argc)
-        pm_usage(usage);
+    bit ** const emask = pbm_allocarray(cols, rows);
 
-    bits = pbm_readpbm(ifp, &cols, &rows);
-    pm_close(ifp);
-    mask = pbm_allocarray(cols, rows);
+    unsigned int row;
 
-    /* Clear out the mask. */
-    for (row = 0; row < rows; ++row)
+    for (row = 0; row < rows; ++row) {
+        unsigned int col;
         for (col = 0; col < cols; ++col)
-            mask[row][col] = PBM_BLACK;
+            if (mask[row][col] == PBM_BLACK)
+                emask[row][col] = PBM_BLACK;
+            else {
+                unsigned int srow;
 
-    /* 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;
+                emask[row][col] = PBM_WHITE;
 
-    /* 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);
+                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;
+                        }
+                    }
+                }
+            }
     }
-    flood();
+    return emask;
+}
+
+
+
+static void
+pbmmask(FILE *             const ifP,
+        FILE *             const ofP,
+        struct CmdlineInfo const cmdline) {
+
+    int cols, rows;
+    bit ** mask;
+    bit ** bits;
+    bit backcolor;
 
-    if (!expand)
+    bits = pbm_readpbm(ifP, &cols, &rows);
+
+    mask = pbm_allocarray(cols, rows);
+
+    clearMask(mask, cols, rows);
+
+    backcolor = backcolorFmImage(bits, cols, rows);
+
+    flood(bits, cols, rows, backcolor, mask);
+
+    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;
-                            }
-                }
-        }
+    } 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) {
+
+    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;
 }
 
+