about summary refs log tree commit diff
path: root/editor/ppmchange.c
diff options
context:
space:
mode:
Diffstat (limited to 'editor/ppmchange.c')
-rw-r--r--editor/ppmchange.c94
1 files changed, 53 insertions, 41 deletions
diff --git a/editor/ppmchange.c b/editor/ppmchange.c
index dea85a77..cfc34769 100644
--- a/editor/ppmchange.c
+++ b/editor/ppmchange.c
@@ -19,20 +19,22 @@
 #include "mallocvar.h"
 
 #define TCOLS 256
-#define SQRT3 1.73205080756887729352
+static double const sqrt3 = 1.73205080756887729352;
     /* The square root of 3 */
+static double const EPSILON = 1.0e-5;
 
-struct cmdlineInfo {
+struct CmdlineInfo {
     /* All the information the user supplied in the command line,
        in a form easy for the program to use.
     */
     const char *input_filespec;  /* Filespecs of input files */
     int ncolors;      /* Number of valid entries in color0[], color1[] */
-    char * oldcolorname[TCOLS];  /* colors user wants replaced */
-    char * newcolorname[TCOLS];  /* colors with which he wants them replaced */
-    int closeness;    
-       /* -closeness option value.  Zero if no -closeness option */
-    char * remainder_colorname;  
+    const char * oldcolorname[TCOLS];
+        /* colors user wants replaced */
+    const char * newcolorname[TCOLS];
+        /* colors with which he wants them replaced */
+    float closeness;    
+    const char * remainder_colorname;  
       /* Color user specified for -remainder.  Null pointer if he didn't
          specify -remainder.
       */
@@ -42,8 +44,8 @@ struct cmdlineInfo {
 
 
 static void
-parseCommandLine(int argc, char ** argv,
-                 struct cmdlineInfo * const cmdlineP) {
+parseCommandLine(int argc, const char ** const 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.
@@ -59,7 +61,7 @@ parseCommandLine(int argc, char ** argv,
     MALLOCARRAY_NOFAIL(option_def, 100);
 
     option_def_index = 0;   /* incremented by OPTENTRY */
-    OPTENT3(0, "closeness",     OPT_UINT,
+    OPTENT3(0, "closeness",     OPT_FLOAT,
             &cmdlineP->closeness,           &closenessSpec,     0);
     OPTENT3(0, "remainder",     OPT_STRING,
             &cmdlineP->remainder_colorname, &remainderSpec,     0);
@@ -70,15 +72,22 @@ parseCommandLine(int argc, char ** argv,
     opt.short_allowed = FALSE;  /* We have no short (old-fashioned) options */
     opt.allowNegNum = FALSE;  /* We may have parms that are negative numbers */
 
-    pm_optParseOptions3(&argc, argv, opt, sizeof(opt), 0);
+    pm_optParseOptions3(&argc, (char **)argv, opt, sizeof(opt), 0);
         /* Uses and sets argc, argv, and some of *cmdlineP and others. */
 
     if (!remainderSpec)
         cmdlineP->remainder_colorname = NULL;
 
     if (!closenessSpec)
-        cmdlineP->closeness = 0;
+        cmdlineP->closeness = 0.0;
 
+    if (cmdlineP->closeness < 0.0)
+        pm_error("-closeness value %f is negative", cmdlineP->closeness);
+
+    if (cmdlineP->closeness > 100)
+        pm_error("-closeness value %f is more than 100%%",
+                 cmdlineP->closeness);
+    
     if ((argc-1) % 2 == 0) 
         cmdlineP->input_filespec = "-";
     else
@@ -99,26 +108,19 @@ parseCommandLine(int argc, char ** argv,
 
 
 
-static double
-sqrf(float const F) {
-    return F*F;
-}
-
-
-
-static int 
-colormatch(pixel const comparand, 
-           pixel const comparator, 
-           float const closeness) {
+static bool
+colorMatches(pixel        const comparand, 
+             pixel        const comparator, 
+             unsigned int const allowableDiff) {
 /*----------------------------------------------------------------------------
-   Return true iff 'comparand' matches 'comparator' in color within the
-   fuzz factor 'closeness'.
+   The colors 'comparand' and 'comparator' are within 'allowableDiff'
+   color levels of each other, in cartesian distance.
 -----------------------------------------------------------------------------*/
     /* Fast path for usual case */
-    if (closeness == 0)
+    if (allowableDiff < EPSILON)
         return PPM_EQUAL(comparand, comparator);
 
-    return PPM_DISTANCE(comparand, comparator) <= sqrf(closeness);
+    return PPM_DISTANCE(comparand, comparator) <= SQR(allowableDiff);
 }
 
 
@@ -132,15 +134,18 @@ changeRow(const pixel * const inrow,
           const pixel         colorto[],
           bool          const remainder_specified, 
           pixel         const remainder_color, 
-          float         const closeness) {
+          unsigned int  const allowableDiff) {
 /*----------------------------------------------------------------------------
    Replace the colors in a single row.  There are 'ncolors' colors to 
    replace.  The to-replace colors are in the array colorfrom[], and the
    replace-with colors are in corresponding elements of colorto[].
    Iff 'remainder_specified' is true, replace all colors not mentioned
-   in colorfrom[] with 'remainder_color'.  Use the closeness factor
-   'closeness' in determining if something in the input row matches
-   a color in colorfrom[].
+   in colorfrom[] with 'remainder_color'.  
+
+   Consider the color in inrow[] to match a color in colorfrom[] if it is
+   within 'allowableDiff' color levels of it, in cartesian distance (e.g.
+   color (1,1,1) is sqrt(12) = 3.5 color levels distant from (3,3,3),
+   so if 'allowableDiff' is 4, they match).
 
    The input row is 'inrow'.  The output is returned as 'outrow', in
    storage which must be already allocated.  Both are 'cols' columns wide.
@@ -157,7 +162,7 @@ changeRow(const pixel * const inrow,
 
         haveMatch = FALSE;  /* haven't found a match yet */
         for (i = 0; i < ncolors && !haveMatch; ++i) {
-            haveMatch = colormatch(inrow[col], colorfrom[i], closeness);
+            haveMatch = colorMatches(inrow[col], colorfrom[i], allowableDiff);
             newcolor = colorto[i];
         }
         if (haveMatch)
@@ -172,16 +177,23 @@ changeRow(const pixel * const inrow,
 
 
 int
-main(int argc, char *argv[]) {
-    struct cmdlineInfo cmdline;
+main(int argc, const char ** const argv) {
+
+    struct CmdlineInfo cmdline;
     FILE * ifP;
     int format;
     int rows, cols;
     pixval maxval;
-    float closeness;
+    unsigned int allowableDiff;
+        /* The amount of difference between two colors we allow and still
+           consider those colors to be the same, for the purposes of
+           determining which pixels in the image to change.  This is a
+           cartesian distance between the color triples, on a maxval scale
+           (which means it can be as high as sqrt(3) * maxval)
+        */
     int row;
-    pixel* inrow;
-    pixel* outrow;
+    pixel * inrow;
+    pixel * outrow;
 
     pixel oldcolor[TCOLS];  /* colors user wants replaced */
     pixel newcolor[TCOLS];  /* colors with which he wants them replaced */
@@ -190,7 +202,7 @@ main(int argc, char *argv[]) {
          specify -remainder.
       */
 
-    ppm_init(&argc, argv);
+    pm_proginit(&argc, argv);
 
     parseCommandLine(argc, argv, &cmdline);
     
@@ -210,8 +222,8 @@ main(int argc, char *argv[]) {
                                           cmdline.closeok);
         }
     }
-    closeness = SQRT3 * maxval * cmdline.closeness/100;
-
+    allowableDiff = ROUNDU(sqrt3 * maxval * cmdline.closeness/100);
+    
     ppm_writeppminit( stdout, cols, rows, maxval, 0 );
     inrow = ppm_allocrow(cols);
     outrow = ppm_allocrow(cols);
@@ -222,7 +234,7 @@ main(int argc, char *argv[]) {
 
         changeRow(inrow, outrow, cols, cmdline.ncolors, oldcolor, newcolor,
                   cmdline.remainder_colorname != NULL,
-                  remainder_color, closeness);
+                  remainder_color, allowableDiff);
 
         ppm_writeppmrow(stdout, outrow, cols, maxval, 0);
     }