about summary refs log tree commit diff
path: root/editor/pnmcrop.c
diff options
context:
space:
mode:
authorgiraffedata <giraffedata@9d0c8265-081b-0410-96cb-a4ca84ce46f8>2009-03-11 21:13:04 +0000
committergiraffedata <giraffedata@9d0c8265-081b-0410-96cb-a4ca84ce46f8>2009-03-11 21:13:04 +0000
commit84bc8df8540455f0c725f86fbdece022ad70c62e (patch)
tree876751511c615a17b9fd988e868c6b09db146ef4 /editor/pnmcrop.c
parent150c1c5999ddf9fb1f0a638bf628c000649e8735 (diff)
downloadnetpbm-mirror-84bc8df8540455f0c725f86fbdece022ad70c62e.tar.gz
netpbm-mirror-84bc8df8540455f0c725f86fbdece022ad70c62e.tar.xz
netpbm-mirror-84bc8df8540455f0c725f86fbdece022ad70c62e.zip
Use border file instead of original image to determine background color
git-svn-id: http://svn.code.sf.net/p/netpbm/code/trunk@851 9d0c8265-081b-0410-96cb-a4ca84ce46f8
Diffstat (limited to 'editor/pnmcrop.c')
-rw-r--r--editor/pnmcrop.c246
1 files changed, 141 insertions, 105 deletions
diff --git a/editor/pnmcrop.c b/editor/pnmcrop.c
index e9dcbe4a..c2e07805 100644
--- a/editor/pnmcrop.c
+++ b/editor/pnmcrop.c
@@ -40,7 +40,17 @@ static const char * const edgeName[] = {
     "bottom"
 };
 
+typedef struct {
+    unsigned int size[4];
+} borderSet;
 
+typedef enum {
+    /* A position in a PNM image file stream */
+    FILEPOS_BEG,
+        /* Immediately before the raster */
+    FILEPOS_END
+        /* Immediately after the raster */
+} imageFilePos;
 
 struct cmdlineInfo {
     /* All the information the user supplied in the command line,
@@ -155,6 +165,11 @@ typedef struct {
 } cropOp;
 
 
+typedef struct {
+    cropOp op[4];
+} cropSet;
+
+
 
 static xel
 background3Corners(FILE * const ifP,
@@ -223,8 +238,7 @@ computeBackground(FILE *         const ifP,
                   int            const rows,
                   xelval         const maxval,
                   int            const format,
-                  enum bg_choice const backgroundChoice,
-                  bool           const verbose) {
+                  enum bg_choice const backgroundChoice) {
 /*----------------------------------------------------------------------------
    Determine what color is the background color of the image in file
    *ifP, which is described by 'cols', 'rows', 'maxval', and 'format'.
@@ -254,11 +268,6 @@ computeBackground(FILE *         const ifP,
         break;
     }
 
-    if (verbose) {
-        pixel const backgroundPixel = pnm_xeltopixel(background, format);
-        pm_message("Background color is %s", 
-                   ppm_colorname(&backgroundPixel, maxval, TRUE /*hexok*/));
-    }
     return(background);
 }
 
@@ -271,9 +280,8 @@ findBordersInImage(FILE *         const ifP,
                    xelval         const maxval,
                    int            const format,
                    xel            const backgroundColor,
-                   bool           const verbose, 
                    bool *         const hasBordersP,
-                   unsigned int * const borderSize) {
+                   borderSet *    const borderSizeP) {
 /*----------------------------------------------------------------------------
    Find the left, right, top, and bottom borders in the image 'ifP'.
    Return their sizes in pixels as borderSize[n].
@@ -335,38 +343,58 @@ findBordersInImage(FILE *         const ifP,
     else {
         *hasBordersP = TRUE;
         assert(right <= cols); assert(bottom <= rows);
-        borderSize[LEFT]   = left - 0;
-        borderSize[RIGHT]  = cols - right;
-        borderSize[TOP]    = top - 0;
-        borderSize[BOTTOM] = rows - bottom;
+        borderSizeP->size[LEFT]   = left - 0;
+        borderSizeP->size[RIGHT]  = cols - right;
+        borderSizeP->size[TOP]    = top - 0;
+        borderSizeP->size[BOTTOM] = rows - bottom;
     }
 }
 
 
 
 static void
-findBordersInFile(unsigned int   const icols,
-                  unsigned int   const irows,
-                  FILE *         const borderFileP, 
-                  xel            const backgroundColor,
-                  bool           const verbose, 
-                  bool *         const hasBordersP,
-                  unsigned int * const borderSize) {
-
-    int bcols;  /* cols and rows in the borderfile */
-    int brows;
-    xelval maxval;
-    int format;
-    
-    pnm_readpnminit(borderFileP, &bcols, &brows, &maxval, &format);
+analyzeImage(FILE *         const ifP,
+             unsigned int   const cols,
+             unsigned int   const rows,
+             xelval         const maxval,
+             int            const format,
+             enum bg_choice const backgroundReq,
+             imageFilePos   const newFilePos,
+             xel *          const backgroundColorP,
+             bool *         const hasBordersP,
+             borderSet *    const borderSizeP) {
+/*----------------------------------------------------------------------------
+   Analyze the PNM image on file stream *ifP to determine its borders
+   and the color of those borders (the assumed background color).
 
-    if (bcols != icols || brows != irows)
-      pm_error("Image file and border file differ in size: %ux%u %ux%u",
-           icols, irows, bcols, brows);
-    
-    findBordersInImage(borderFileP, bcols, brows, maxval, format, 
-                       backgroundColor, verbose, hasBordersP, borderSize);
-} 
+   Return as *backgroundColorP the background color.
+
+   Return as *borderSizeP the set of border sizes (one for each of the
+   four edges).  But iff there are no borders, don't return anything as
+   *borderSizeP and return *hasBordersP == false.
+
+   Expect *ifP to be positioned right after the header and seekable.
+   Return with it positioned either before or after the raster, as
+   requested by 'newFilePos'.
+-----------------------------------------------------------------------------*/
+    pm_filepos rasterpos;
+    xel background;
+
+    pm_tell2(ifP, &rasterpos, sizeof(rasterpos));
+
+    background = computeBackground(ifP, cols, rows, maxval, format,
+                                   backgroundReq);
+
+    pm_seek2(ifP, &rasterpos, sizeof(rasterpos));
+
+    findBordersInImage(ifP, cols, rows, maxval, format, 
+                       background, hasBordersP, borderSizeP);
+
+    if (newFilePos == FILEPOS_BEG)
+        pm_seek2(ifP, &rasterpos, sizeof(rasterpos));
+
+    *backgroundColorP = background;
+}
 
 
 
@@ -379,21 +407,22 @@ ending(unsigned int const n) {
 
 
 static void
-reportCroppingParameters(cropOp const crop[]) {
+reportCroppingParameters(cropSet const crop) {
 
     unsigned int i;
 
     for (i = 0; i < 4; ++i) {
-        if (crop[i].removeSize == 0 && crop[i].padSize == 0)
+        if (crop.op[i].removeSize == 0 && crop.op[i].padSize == 0)
             pm_message("Not cropping %s edge", edgeName[i]);
         else {
-            if (crop[i].padSize > 0)
+            if (crop.op[i].padSize > 0)
                 pm_message("Adding %u pixel%s to the %s border",
-                           crop[i].padSize, ending(crop[i].padSize),
+                           crop.op[i].padSize, ending(crop.op[i].padSize),
                            edgeName[i]);
-            if (crop[i].removeSize > 0)
+            if (crop.op[i].removeSize > 0)
                 pm_message("Cropping %u pixel%s from the %s border",
-                           crop[i].removeSize, ending(crop[i].removeSize),
+                           crop.op[i].removeSize,
+                           ending(crop.op[i].removeSize),
                            edgeName[i]);
         }
     }
@@ -467,7 +496,7 @@ writeCroppedNonPbm(FILE *       const ifP,
                    unsigned int const rows,
                    xelval       const maxval,
                    int          const format,
-                   cropOp       const crop[],
+                   cropSet      const crop,
                    xel          const backgroundColor,
                    FILE *       const ofP) {
 
@@ -511,22 +540,23 @@ writeCroppedNonPbm(FILE *       const ifP,
     */
 
     unsigned int const foregroundCols =
-        cols - crop[LEFT].removeSize - crop[RIGHT].removeSize;
+        cols - crop.op[LEFT].removeSize - crop.op[RIGHT].removeSize;
     unsigned int const outputCols     = 
-        foregroundCols + crop[LEFT].padSize + crop[RIGHT].padSize;
+        foregroundCols + crop.op[LEFT].padSize + crop.op[RIGHT].padSize;
     unsigned int const foregroundRows =
-        rows - crop[TOP].removeSize - crop[BOTTOM].removeSize;
+        rows - crop.op[TOP].removeSize - crop.op[BOTTOM].removeSize;
     unsigned int const outputRows     =
-        foregroundRows + crop[TOP].padSize + crop[BOTTOM].padSize;
+        foregroundRows + crop.op[TOP].padSize + crop.op[BOTTOM].padSize;
 
     unsigned int const foregroundLeft  =
-        MAX(crop[LEFT].removeSize, crop[LEFT].padSize);
+        MAX(crop.op[LEFT].removeSize, crop.op[LEFT].padSize);
         /* Index into xelrow[] of leftmost pixel of foreground */
     unsigned int const foregroundRight = foregroundLeft + foregroundCols;
         /* Index into xelrow[] just past rightmost pixel of foreground */
 
     unsigned int const allocCols =
-        foregroundRight + MAX(crop[RIGHT].removeSize, crop[RIGHT].padSize);
+        foregroundRight + MAX(crop.op[RIGHT].removeSize,
+                              crop.op[RIGHT].padSize);
 
     xel * xelrow;
     unsigned int i;
@@ -535,33 +565,35 @@ writeCroppedNonPbm(FILE *       const ifP,
 
     xelrow = pnm_allocrow(allocCols);
 
-    readOffBorderNonPbm(crop[TOP].removeSize, ifP, cols, maxval, format);
+    readOffBorderNonPbm(crop.op[TOP].removeSize, ifP, cols, maxval, format);
 
-    outputNewBorderNonPbm(crop[TOP].padSize, outputCols, backgroundColor,
+    outputNewBorderNonPbm(crop.op[TOP].padSize, outputCols, backgroundColor,
                           ofP, maxval, format);
 
     /* Set left border pixels */
-    fillRow(&xelrow[foregroundLeft - crop[LEFT].padSize], crop[LEFT].padSize,
+    fillRow(&xelrow[foregroundLeft - crop.op[LEFT].padSize],
+            crop.op[LEFT].padSize,
             backgroundColor);
 
     /* Set right border pixels */
-    fillRow(&xelrow[foregroundRight], crop[RIGHT].padSize, backgroundColor);
+    fillRow(&xelrow[foregroundRight], crop.op[RIGHT].padSize, backgroundColor);
 
     /* Read and output foreground rows */
     for (i = 0; i < foregroundRows; ++i) {
  
         /* Read foreground pixels */
-        pnm_readpnmrow(ifP, &(xelrow[foregroundLeft - crop[LEFT].removeSize]),
+        pnm_readpnmrow(ifP,
+                       &(xelrow[foregroundLeft - crop.op[LEFT].removeSize]),
                        cols, maxval, format);
         
         pnm_writepnmrow(ofP,
-                        &(xelrow[foregroundLeft - crop[LEFT].padSize]),
+                        &(xelrow[foregroundLeft - crop.op[LEFT].padSize]),
                         outputCols, maxval, format, 0);
     }
 
-    readOffBorderNonPbm(crop[BOTTOM].removeSize, ifP, cols, maxval, format);
+    readOffBorderNonPbm(crop.op[BOTTOM].removeSize, ifP, cols, maxval, format);
     
-    outputNewBorderNonPbm(crop[BOTTOM].padSize, outputCols,
+    outputNewBorderNonPbm(crop.op[BOTTOM].padSize, outputCols,
                           backgroundColor,
                           ofP, maxval, format);
 
@@ -642,7 +674,7 @@ writeCroppedPBM(FILE *       const ifP,
                 unsigned int const cols,
                 unsigned int const rows,
                 int          const format,
-                cropOp       const crop[],
+                cropSet      const crop,
                 xel          const backgroundColor,
                 FILE *       const ofP) {
     
@@ -651,26 +683,28 @@ writeCroppedPBM(FILE *       const ifP,
     */
 
     unsigned int const foregroundCols =
-        cols - crop[LEFT].removeSize - crop[RIGHT].removeSize;
+        cols - crop.op[LEFT].removeSize - crop.op[RIGHT].removeSize;
     unsigned int const outputCols     = 
-        foregroundCols + crop[LEFT].padSize + crop[RIGHT].padSize;
+        foregroundCols + crop.op[LEFT].padSize + crop.op[RIGHT].padSize;
     unsigned int const foregroundRows =
-        rows - crop[TOP].removeSize - crop[BOTTOM].removeSize;
+        rows - crop.op[TOP].removeSize - crop.op[BOTTOM].removeSize;
     unsigned int const outputRows     =
-        foregroundRows + crop[TOP].padSize + crop[BOTTOM].padSize;
+        foregroundRows + crop.op[TOP].padSize + crop.op[BOTTOM].padSize;
 
     unsigned int const foregroundLeft  =
-        MAX(crop[LEFT].removeSize, crop[LEFT].padSize);
+        MAX(crop.op[LEFT].removeSize, crop.op[LEFT].padSize);
     unsigned int const foregroundRight = foregroundLeft + foregroundCols;
 
     unsigned int const allocCols =
-        foregroundRight + MAX(crop[RIGHT].removeSize, crop[RIGHT].padSize);
+        foregroundRight + 
+        MAX(crop.op[RIGHT].removeSize, crop.op[RIGHT].padSize);
 
     unsigned int const backgroundBlackWhite =
         PNM_EQUAL(backgroundColor, pnm_whitexel(1, PBM_TYPE)) ? 0: 1;
 
-    unsigned int const readOffset    = foregroundLeft - crop[LEFT].removeSize;
-    unsigned int const writeOffset   = foregroundLeft - crop[LEFT].padSize;
+    unsigned int const readOffset    =
+        foregroundLeft - crop.op[LEFT].removeSize;
+    unsigned int const writeOffset   = foregroundLeft - crop.op[LEFT].padSize;
     unsigned int const lastWriteChar = writeOffset/8 + (outputCols-1)/8;
     unsigned char * bitrow;
     unsigned int i;
@@ -679,9 +713,9 @@ writeCroppedPBM(FILE *       const ifP,
 
     bitrow = pbm_allocrow_packed(allocCols);
 
-    readOffBorderPbm(crop[TOP].removeSize, ifP, cols, format);
+    readOffBorderPbm(crop.op[TOP].removeSize, ifP, cols, format);
 
-    outputNewBorderPbm(crop[TOP].padSize, outputCols, backgroundBlackWhite,
+    outputNewBorderPbm(crop.op[TOP].padSize, outputCols, backgroundBlackWhite,
                        ofP);
 
     /* Prepare padding: left and/or right */
@@ -699,13 +733,14 @@ writeCroppedPBM(FILE *       const ifP,
            distorted by pbm_writepbmrow_bitoffset() 
            (No need to mend any left-side padding)
         */
-        if (crop[RIGHT].padSize > 0)    
+        if (crop.op[RIGHT].padSize > 0)    
             bitrow[lastWriteChar] = backgroundBlackWhite * 0xff;
     }
 
-    readOffBorderPbm(crop[BOTTOM].removeSize, ifP, cols, format);
+    readOffBorderPbm(crop.op[BOTTOM].removeSize, ifP, cols, format);
 
-    outputNewBorderPbm(crop[BOTTOM].padSize, outputCols, backgroundBlackWhite,
+    outputNewBorderPbm(crop.op[BOTTOM].padSize, outputCols,
+                       backgroundBlackWhite,
                        ofP);
 
     pbm_freerow_packed(bitrow);
@@ -715,23 +750,25 @@ writeCroppedPBM(FILE *       const ifP,
 
 static void
 determineCrops(struct cmdlineInfo const cmdline,
-               unsigned int       const oldBorderSize[],
-               cropOp *           const cropArray) {
+               borderSet *        const oldBorderSizeP,
+               cropSet *          const cropP) {
 
     edgeLocation i;
 
     for (i = 0; i < 4; ++i) {
         if (cmdline.wantCrop[i]) {
-            if (oldBorderSize[i] > cmdline.margin) {
-                cropArray[i].removeSize = oldBorderSize[i] - cmdline.margin;
-                cropArray[i].padSize    = 0;
+            if (oldBorderSizeP->size[i] > cmdline.margin) {
+                cropP->op[i].removeSize =
+                    oldBorderSizeP->size[i] - cmdline.margin;
+                cropP->op[i].padSize    = 0;
             } else {
-                cropArray[i].removeSize = 0;
-                cropArray[i].padSize    = cmdline.margin - oldBorderSize[i];
+                cropP->op[i].removeSize = 0;
+                cropP->op[i].padSize    =
+                    cmdline.margin - oldBorderSizeP->size[i];
             }
         } else {
-            cropArray[i].removeSize = 0;
-            cropArray[i].padSize    = 0;
+            cropP->op[i].removeSize = 0;
+            cropP->op[i].padSize    = 0;
         }
     }
 }
@@ -741,15 +778,15 @@ determineCrops(struct cmdlineInfo const cmdline,
 static void
 validateComputableSize(unsigned int const cols,
                        unsigned int const rows,
-                       cropOp       const crop[]) {
+                       cropSet      const crop) {
 
     double const newcols =
         (double)cols +
-        (double)crop[LEFT].padSize + (double)crop[RIGHT].padSize;
+        (double)crop.op[LEFT].padSize + (double)crop.op[RIGHT].padSize;
 
     double const newrows =
         (double)rows +
-        (double)crop[TOP].padSize + (double)crop[BOTTOM].padSize;
+        (double)crop.op[TOP].padSize + (double)crop.op[BOTTOM].padSize;
 
     if (newcols > INT_MAX)
        pm_error("Output width too large: %.0f.", newcols);
@@ -771,50 +808,48 @@ cropOneImage(struct cmdlineInfo const cmdline,
    (the file that tells us where the existing borders are in the input
    image).  Leave *ifP and *bdfP positioned after the image.
 
-   *ifP is seekable; *bdfP may not be.
+   Both files are seekable.
 -----------------------------------------------------------------------------*/
-    xelval maxval;
-    int format;
-    int rows, cols;   /* dimensions of input image */
+    xelval maxval, bmaxval;
+    int format, bformat;
+    int rows, cols, brows, bcols;
     bool hasBorders;
-    unsigned int oldBorder[4];
+    borderSet oldBorder;
         /* The sizes of the borders in the input image */
-    cropOp crop[4];
+    cropSet crop;
         /* The crops we have to do on each side */
-    
     xel background;
-    pm_filepos rasterpos;
 
     pnm_readpnminit(ifP, &cols, &rows, &maxval, &format);
 
-    pm_tell2(ifP, &rasterpos, sizeof(rasterpos));
-
-    background = computeBackground(ifP, cols, rows, maxval, format,
-                                   cmdline.background, cmdline.verbose);
+    if (bdfP)
+        pnm_readpnminit(bdfP, &bcols, &brows, &bmaxval, &bformat);
 
-    if (cmdline.borderfile) {
-        findBordersInFile(cols, rows, bdfP, background,
-                          cmdline.verbose, &hasBorders, oldBorder);
-    } else {
-        pm_seek2(ifP, &rasterpos, sizeof(rasterpos));
+    if (bdfP)
+        analyzeImage(bdfP, bcols, brows, bmaxval, bformat, cmdline.background,
+                     FILEPOS_END,
+                     &background, &hasBorders, &oldBorder);
+    else
+        analyzeImage(ifP, cols, rows, maxval, format, cmdline.background,
+                     FILEPOS_BEG,
+                     &background, &hasBorders, &oldBorder);
 
-        findBordersInImage(ifP, cols, rows, maxval, format, 
-                           background, cmdline.verbose, &hasBorders,
-                           oldBorder);
+    if (cmdline.verbose) {
+        pixel const backgroundPixel = pnm_xeltopixel(background, format);
+        pm_message("Background color is %s", 
+                   ppm_colorname(&backgroundPixel, maxval, TRUE /*hexok*/));
     }
     if (!hasBorders)
         pm_error("The image is entirely background; "
                  "there is nothing to crop.");
 
-    determineCrops(cmdline, oldBorder, crop);
+    determineCrops(cmdline, &oldBorder, &crop);
 
     validateComputableSize(cols, rows, crop);
 
     if (cmdline.verbose) 
         reportCroppingParameters(crop);
 
-    pm_seek2(ifP, &rasterpos, sizeof(rasterpos));
-
     if (PNM_FORMAT_TYPE(format) == PBM_TYPE)
         writeCroppedPBM(ifP, cols, rows, format, crop, background, ofP);
     else
@@ -832,7 +867,8 @@ main(int argc, const char *argv[]) {
         /* The program's regular input file.  Could be a seekable copy of
            it in a temporary file.
         */
-    FILE * bdfP; /* The borderfile; NULL if none.  No seeks.  */
+    FILE * bdfP;
+        /* The border file.  NULL if none. */
     bool eof;    /* no more images in input stream */
     bool beof;   /* no more images in borderfile stream */