about summary refs log tree commit diff
path: root/editor
diff options
context:
space:
mode:
authorgiraffedata <giraffedata@9d0c8265-081b-0410-96cb-a4ca84ce46f8>2020-08-22 23:04:22 +0000
committergiraffedata <giraffedata@9d0c8265-081b-0410-96cb-a4ca84ce46f8>2020-08-22 23:04:22 +0000
commit7e040257350d11f891d2b7379e08adf94344480f (patch)
treed31e147e249038ee23e3f3ff3190ad67ea816fba /editor
parentcef9e3fe7284012a932817a70c3b3639cff87932 (diff)
downloadnetpbm-mirror-7e040257350d11f891d2b7379e08adf94344480f.tar.gz
netpbm-mirror-7e040257350d11f891d2b7379e08adf94344480f.tar.xz
netpbm-mirror-7e040257350d11f891d2b7379e08adf94344480f.zip
Make -margin effective with -blank=image=minimize
git-svn-id: http://svn.code.sf.net/p/netpbm/code/trunk@3923 9d0c8265-081b-0410-96cb-a4ca84ce46f8
Diffstat (limited to 'editor')
-rw-r--r--editor/pnmcrop.c162
1 files changed, 115 insertions, 47 deletions
diff --git a/editor/pnmcrop.c b/editor/pnmcrop.c
index f41e67bd..43027da0 100644
--- a/editor/pnmcrop.c
+++ b/editor/pnmcrop.c
@@ -1123,64 +1123,135 @@ noCrops(struct CmdlineInfo const cmdline) {
 
 
 
+static void
+divideAllBackgroundIntoBorders(unsigned int   const totalSz,
+                               bool           const wantCropSideA,
+                               bool           const wantCropSideB,
+                               unsigned int   const wantMargin,
+                               unsigned int * const sideASzP,
+                               unsigned int * const sideBSzP) {
+/*----------------------------------------------------------------------------
+   Divide up an all-background space into fictional borders (that can be
+   trimmed or padded).
+
+   If there is to be a margin, those borders touch - the entire image is
+   borders.  But if there is not to be a margin, there has to be one pixel,
+   row, or column between the borders so that there is something left after we
+   crop off those borders (because there's no such thing as a zero-pixel
+   image).
+
+   This function does the borders in one direction - top and bottom or left
+   and right.  Top or left is called "Side A"; bottom or right is called "Side
+   B".  'totalSz' is the width of the image in the top/bottom case and the
+   height of the image in the left/right case.
+-----------------------------------------------------------------------------*/
+    unsigned int sideASz, sideBSz;
+
+    if (wantCropSideA && wantCropSideB) {
+        sideASz = totalSz/2;
+        if (wantMargin)
+            sideBSz = totalSz - sideASz;
+        else
+            sideBSz = totalSz - sideASz - 1;
+    } else if (wantCropSideA) {
+        if (wantMargin)
+            sideASz = totalSz;
+        else
+            sideASz = totalSz - 1;
+        sideBSz = 0;
+    } else if (wantCropSideB) {
+        sideASz = 0;
+        if (wantMargin)
+            sideBSz = totalSz;
+        else
+            sideBSz = totalSz - 1;
+    } else {
+        sideASz = 0;
+        sideBSz = 0;
+    }
+    *sideASzP = sideASz;
+    *sideBSzP = sideBSz;
+}
+
+
+
+static CropOp
+oneSideCrop(bool         const wantCrop,
+            unsigned int const borderSz,
+            unsigned int const margin) {
+
+    CropOp retval;
+
+    if (wantCrop) {
+        if (borderSz >= margin) {
+            retval.removeSize = borderSz - margin;
+            retval.padSize    = 0;
+        } else {
+            retval.removeSize = 0;
+            retval.padSize    = margin - borderSz;
+        }
+    } else {
+        retval.removeSize = 0;
+        retval.padSize    = 0;
+    }
+
+    return retval;
+}
+
+
+
 static CropSet
 extremeCrops(struct CmdlineInfo const cmdline,
              unsigned int       const cols,
              unsigned int       const rows) {
 /*----------------------------------------------------------------------------
    Crops that crop as much as possible, reducing output to a single
-   row, column, or pixel.
+   row, column, or pixel, plus margins.
 -----------------------------------------------------------------------------*/
     CropSet retval;
 
+    unsigned int leftBorderSz, rghtBorderSz;
+    unsigned int topBorderSz, botBorderSz;
+
     if (cmdline.verbose)
         pm_message("Input image has no distinction between "
                    "border and content");
 
-    /* We can't just pick a representative pixel, say top-left corner.
-       If -top and/or -bottom was specified but not -left and -right,
-       the output should be one row, not a single pixel.
+    /* Note that the "entirely background" image may have several colors: this
+       happens when -closeness was specified.  That means we can't just build
+       up an image from background color - we actually have to preserve some
+       of the original image.
 
-       The "entirely background" image may have several colors: this
-       happens when -closeness was specified.
+       We divide the background into individual borders, with a foreground of
+       either nothing at all or a single row, column, or pixel, then crop
+       those fictional borders the same as if they were real.  The "nothing
+       at all" case is feasible only when there is to be a margin, because
+       otherwise cropping the borders would leave nothing.
     */
 
-    if (cmdline.wantCrop[LEFT] && cmdline.wantCrop[RIGHT]) {
-        retval.op[LEFT ].removeSize = cols / 2;
-        retval.op[RIGHT].removeSize = cols - retval.op[LEFT].removeSize -1;
-    } else if (cmdline.wantCrop[LEFT]) {
-        retval.op[LEFT ].removeSize = cols - 1;
-        retval.op[RIGHT].removeSize = 0;
-    } else if (cmdline.wantCrop[RIGHT]) {
-        retval.op[LEFT ].removeSize = 0;
-        retval.op[RIGHT].removeSize = cols - 1;
-    } else {
-        retval.op[LEFT ].removeSize = 0;
-        retval.op[RIGHT].removeSize = 0;
-    }
-
-    if (cmdline.wantCrop[TOP] && cmdline.wantCrop[BOTTOM]) {
-        retval.op[ TOP  ].removeSize = rows / 2;
-        retval.op[BOTTOM].removeSize = rows - retval.op[TOP].removeSize -1;
-    } else if (cmdline.wantCrop[TOP]) {
-        retval.op[ TOP  ].removeSize = rows - 1;
-        retval.op[BOTTOM].removeSize = 0;
-    } else if (cmdline.wantCrop[BOTTOM]) {
-        retval.op[ TOP  ].removeSize = 0;
-        retval.op[BOTTOM].removeSize = rows - 1;
-    } else {
-        retval.op[ TOP  ].removeSize = 0;
-        retval.op[BOTTOM].removeSize = 0;
-    }
+    divideAllBackgroundIntoBorders(cols,
+                                   cmdline.wantCrop[LEFT],
+                                   cmdline.wantCrop[RIGHT],
+                                   cmdline.margin > 0,
+                                   &leftBorderSz,
+                                   &rghtBorderSz);
+
+    divideAllBackgroundIntoBorders(rows,
+                                   cmdline.wantCrop[TOP],
+                                   cmdline.wantCrop[BOTTOM],
+                                   cmdline.margin > 0,
+                                   &topBorderSz,
+                                   &botBorderSz);
+
+    retval.op[LEFT  ] =
+        oneSideCrop(cmdline.wantCrop[LEFT  ], leftBorderSz, cmdline.margin);
+    retval.op[RIGHT ] =
+        oneSideCrop(cmdline.wantCrop[RIGHT ], rghtBorderSz, cmdline.margin);
+    retval.op[TOP   ] =
+        oneSideCrop(cmdline.wantCrop[TOP   ], topBorderSz,  cmdline.margin);
+    retval.op[BOTTOM] =
+        oneSideCrop(cmdline.wantCrop[BOTTOM], botBorderSz,  cmdline.margin);
 
-    if (cmdline.margin > 0)
-        pm_message ("-margin value %u ignored", cmdline.margin);
-
-    {
-        EdgeLocation i;
-        for (i = 0; i < ARRAY_SIZE(retval.op); ++i)
-            retval.op[i].padSize = 0;
-    }
     return retval;
 }
 
@@ -1330,12 +1401,9 @@ cropOneImage(struct CmdlineInfo const cmdline,
             pm_error("The image is entirely background; "
                      "there is nothing to crop.");
             break;
-        case BLANK_PASS:
-            crop = noCrops(cmdline);                   break;
-        case BLANK_MINIMIZE:
-            crop = extremeCrops(cmdline, cols, rows);  break;
-        case BLANK_MAXCROP:
-            crop = maxcropReport(cmdline, cols, rows); break;
+        case BLANK_PASS:     crop = noCrops(cmdline);                   break;
+        case BLANK_MINIMIZE: crop = extremeCrops(cmdline, cols, rows);  break;
+        case BLANK_MAXCROP:  crop = maxcropReport(cmdline, cols, rows); break;
         }
     } else {
         crop = crops(cmdline, oldBorder);