diff --git a/prog/croppdf.c b/prog/croppdf.c index d1d7f0c82..dcc2f457b 100644 --- a/prog/croppdf.c +++ b/prog/croppdf.c @@ -39,7 +39,7 @@ * * Syntax: * croppdf basedir lrclear tbclear edgeclean lradd tbadd maxwiden - * title fileout + * printwiden title fileout * * The %basedir is a directory where the input pdf files are located. * The program will operate on every file in this directory with @@ -62,6 +62,11 @@ * 8.5 x 11 inch printed page. It gives the maximum fractional horizontal * stretching allowed. Suggested values are between 1.0 and 1.15. * + * If you are not concerned with printing on paper, use the default + * value 0 for %printwiden to skip; 1 for 8.5 x 11 paper; 2 for A4. + * Widening only takes place if the ratio h/w exceeds the specified paper + * size by 3%, and the horizontal scaling factor will not exceed 1.20. + * * The %title is the title given to the pdf. Use %title == "none" * to omit the title. * diff --git a/src/pageseg.c b/src/pageseg.c index 8ee94c8b6..3209a5a7a 100644 --- a/src/pageseg.c +++ b/src/pageseg.c @@ -34,7 +34,6 @@ * Halftone region extraction * PIX *pixGenHalftoneMask() **Deprecated wrapper** * PIX *pixGenerateHalftoneMask() - * * Textline extraction * PIX *pixGenTextlineMask() @@ -559,8 +558,10 @@ PIX *pix1, *pix2, *pix3, *pixd; * (c) If %edgeclean > 0, it removes isolated sets of pixels, * using a close/open operation of size %edgeclean + 1. * If %edgeclean < 0, it uses a large vertical morphological - * closing and the extraction of the largest resulting - * connected component to eliminate noise on left and right sides. + * close/open and the extraction of either the largest + * resulting connected component (or the largest two components + * if the page has 2 columns), to eliminate noise on left + * and right sides. * (d) Find the bounding box of remaining fg pixels and scales * the box up 2x back to full resolution. * (e) Crops the binarized image to the bounding box. @@ -705,7 +706,7 @@ PIXA *pixa1; /* Optionally widen image if possible, for printing on 8.5 x 11 inch * or A4 paper. Specifically, widen the image if the h/w asperity * ratio of the input image exceeds that of the selected paper by - * more than 3%. Do not widen by more than 25%. */ + * more than 3%. Do not widen by more than 20%. */ r1 = (l_float32)h / (l_float32)w; r2 = 0.0; /* for default case */ if (printwiden == 1) /* standard */ @@ -713,6 +714,7 @@ PIXA *pixa1; else if (printwiden == 2) /* A4 */ r2 = r1 / 1.414; if (r2 > 1.03) { + r2 = L_MIN(r2, 1.20); lept_stderr("oversize h/w ratio by factor %6.3f\n", r2); pix4 = pixScale(pix3, r2, 1.0); } else { @@ -748,9 +750,11 @@ PIXA *pixa1; * at the input resolution. * (2) The input %pixs should be at a resolution 100 - 150 ppi. * (3) It does two 2x level1 rank binary reductions, followed - * by a large vertical close/open, and then a 4x expansion - * back to the input resolution. - * (4) It is used as an option to pixCropImage(), when given + * by a large vertical close/open, with a very small horizontal + * close/oopen, and then a 4x expansion back to the input resolution. + * (4) To work properly with 2-column layout, if the largest and + * second-largest regions are comparable in size, both are included. + * (5) This is used as an option to pixCropImage(), when given * a negative %edgecrop parameter. * */ @@ -758,8 +762,9 @@ l_int32 pixMaxCompAfterVClosing(PIX *pixs, BOX **pbox) { -l_int32 w, h, i, n, maxindex, maxarea, empty; -BOXA *boxa1; +l_int32 w1, h1, w2, h2, n, empty; +BOX *box1, *box2; +BOXA *boxa1, *boxa2; PIX *pix1; if (!pbox) @@ -769,26 +774,35 @@ PIX *pix1; return ERROR_INT("pixs undefined or not 1 bpp", __func__, 1); /* Strong vertical closing */ - pix1 = pixMorphSequence(pixs, "r11 + c1.50 + o1.50 + x4", 0); + pix1 = pixMorphSequence(pixs, "r11 + c3.80 + o3.80 + x4", 0); pixZero(pix1, &empty); if (empty) return ERROR_INT("pix1 is empty", __func__, 1); - /* Find the c.c. with largest area and return its bounding box */ + /* Find the two c.c. with largest area. If they are not comparable + * in area, return the bounding box of the largest; otherwise, + * return the bounding box of both regions. */ boxa1 = pixConnCompBB(pix1, 8); pixDestroy(&pix1); - n = boxaGetCount(boxa1); - maxindex = 0; - maxarea = 0; - for (i = 0; i < n; i++) { - boxaGetBoxGeometry(boxa1, i, NULL, NULL, &w, &h); - if (w * h > maxarea) { - maxarea = w * h; - maxindex = i; + boxa2 = boxaSort(boxa1, L_SORT_BY_AREA, L_SORT_DECREASING, NULL); + box1 = boxaGetBox(boxa2, 0, L_COPY); + if ((n = boxaGetCount(boxa2)) == 1) { + *pbox = box1; + } else { /* 2 or more */ + box1 = boxaGetBox(boxa2, 0, L_COPY); + box2 = boxaGetBox(boxa2, 1, L_COPY); + boxGetGeometry(box1, NULL, NULL, &w1, &h1); + boxGetGeometry(box2, NULL, NULL, &w2, &h2); + if (((l_float32)(w2 * h2) / (l_float32)(w1 * h1)) > 0.7) { + *pbox = boxBoundingRegion(box1, box2); + boxDestroy(&box1); + } else { + *pbox = box1; } + boxDestroy(&box2); } - *pbox = boxaGetBox(boxa1, maxindex, L_COPY); boxaDestroy(&boxa1); + boxaDestroy(&boxa2); return 0; }