From 301ffd557ab1227433e02c067056a571400c2ddc Mon Sep 17 00:00:00 2001 From: Dan Bloomberg Date: Fri, 20 Dec 2024 17:50:23 +0100 Subject: [PATCH 1/4] Replace use of a global threshold with an adaptive threshold algorithm --- AUTHORS | 1 + src/jbig2.cc | 36 ++++++++++++------------------------ 2 files changed, 13 insertions(+), 24 deletions(-) diff --git a/AUTHORS b/AUTHORS index f46860f..5552139 100644 --- a/AUTHORS +++ b/AUTHORS @@ -4,6 +4,7 @@ Adam Langley Contributors: ============= +Dan Bloomberg Misty De Meo zdenop Steven Lee http://www.rubypdf.com diff --git a/src/jbig2.cc b/src/jbig2.cc index 79816d4..4ff764f 100644 --- a/src/jbig2.cc +++ b/src/jbig2.cc @@ -47,9 +47,6 @@ #define JBIG2_WEIGHT_MIN 0.1f #define JBIG2_WEIGHT_MAX 0.9f #define JBIG2_WEIGHT_DEF 0.5f -#define BW_THRESHOLD_MIN 0 -#define BW_THRESHOLD_MAX 255 -#define BW_THRESHOLD_DEF 128 static void usage(const char *argv0) { @@ -61,7 +58,6 @@ usage(const char *argv0) { fprintf(stderr, " -s --symbol-mode: use text region, not generic coder\n"); fprintf(stderr, " -t : set classification threshold for symbol coder (def: %0.2f)\n", JBIG2_THRESHOLD_DEF); fprintf(stderr, " -w : set classification weight for symbol coder (def: %0.2f)\n", JBIG2_WEIGHT_DEF); - fprintf(stderr, " -T : set 1 bpp threshold (def: %d)\n", BW_THRESHOLD_DEF); fprintf(stderr, " -r --refine: use refinement (requires -s: lossless)\n"); fprintf(stderr, " -O : dump thresholded image as PNG\n"); fprintf(stderr, " -2: upsample 2x before thresholding\n"); @@ -215,7 +211,6 @@ main(int argc, char **argv) { bool pdfmode = false; float threshold = JBIG2_THRESHOLD_DEF; float weight = JBIG2_WEIGHT_DEF; - int bw_threshold = BW_THRESHOLD_DEF; bool symbol_mode = false; bool refine = false; bool up2 = false, up4 = false; @@ -320,9 +315,11 @@ main(int argc, char **argv) { return 1; } - if ((threshold < JBIG2_THRESHOLD_MIN) || (threshold > JBIG2_THRESHOLD_MAX)) { + if ((threshold < JBIG2_THRESHOLD_MIN) || + (threshold > JBIG2_THRESHOLD_MAX)) { fprintf(stderr, "Invalid value for threshold\n"); - fprintf(stderr, "(must be between %0.2f and %0.2f)\n", JBIG2_THRESHOLD_MIN, JBIG2_THRESHOLD_MAX); + fprintf(stderr, "(must be between %0.2f and %0.2f)\n", + JBIG2_THRESHOLD_MIN, JBIG2_THRESHOLD_MAX); return 10; } i++; @@ -340,7 +337,8 @@ main(int argc, char **argv) { if ((weight < JBIG2_WEIGHT_MIN) || (weight > JBIG2_WEIGHT_MAX)) { fprintf(stderr, "Invalid value for weight\n"); - fprintf(stderr, "(must be between %0.2f and %0.2f)\n", JBIG2_WEIGHT_MIN, JBIG2_WEIGHT_MAX); + fprintf(stderr, "(must be between %0.2f and %0.2f)\n", + JBIG2_WEIGHT_MIN, JBIG2_WEIGHT_MAX); return 10; } i++; @@ -348,17 +346,7 @@ main(int argc, char **argv) { } if (strcmp(argv[i], "-T") == 0) { - char *endptr; - bw_threshold = strtol(argv[i+1], &endptr, 10); - if (*endptr) { - fprintf(stderr, "Cannot parse int value: %s\n", argv[i+1]); - usage(argv[0]); - return 1; - } - if (bw_threshold < BW_THRESHOLD_MIN || bw_threshold > BW_THRESHOLD_MAX) { - fprintf(stderr, "Invalid bw threshold: (%d..%d)\n", BW_THRESHOLD_MIN, BW_THRESHOLD_MAX); - return 11; - } + fprintf(stderr, "Binary thresholds 'T' are no longer used\n"); i++; continue; } @@ -456,7 +444,7 @@ main(int argc, char **argv) { if (verbose) pixInfo(source, "source image:"); - PIX *pixl, *gray, *pixt; + PIX *pixl, *gray, *adapt, *pixt; if ((pixl = pixRemoveColormap(source, REMOVE_CMAP_BASED_ON_SRC)) == NULL) { fprintf(stderr, "Failed to remove colormap from %s\n", argv[i]); return 1; @@ -474,14 +462,14 @@ main(int argc, char **argv) { fprintf(stderr, "Unsupported input image depth: %d\n", pixl->d); return 1; } - Pix *adapt = pixBackgroundNormSimple(gray, NULL, NULL); + adapt = pixCleanBackgroundToWhite(gray, NULL, NULL, 1.0, 90, 190); pixDestroy(&gray); if (up2) { - pixt = pixScaleGray2xLIThresh(adapt, bw_threshold); + pixt = pixScaleGray2xLIThresh(adapt, 220); } else if (up4) { - pixt = pixScaleGray4xLIThresh(adapt, bw_threshold); + pixt = pixScaleGray4xLIThresh(adapt, 220); } else { - pixt = pixThresholdToBinary(adapt, bw_threshold); + pixt = pixThresholdToBinary(adapt, 220); } pixDestroy(&adapt); } else { From 4f1f4a0a8c2947895b9799241d168351ead61311 Mon Sep 17 00:00:00 2001 From: zvezdochiot Date: Fri, 20 Dec 2024 18:11:52 +0100 Subject: [PATCH 2/4] Keep threshold parameter, select clean/normalize background --- src/jbig2.cc | 28 ++++++++++++++++++++++++---- 1 file changed, 24 insertions(+), 4 deletions(-) diff --git a/src/jbig2.cc b/src/jbig2.cc index 4ff764f..9067295 100644 --- a/src/jbig2.cc +++ b/src/jbig2.cc @@ -47,6 +47,9 @@ #define JBIG2_WEIGHT_MIN 0.1f #define JBIG2_WEIGHT_MAX 0.9f #define JBIG2_WEIGHT_DEF 0.5f +#define BW_THRESHOLD_MIN 0 +#define BW_THRESHOLD_MAX 255 +#define BW_THRESHOLD_DEF 192 static void usage(const char *argv0) { @@ -58,6 +61,8 @@ usage(const char *argv0) { fprintf(stderr, " -s --symbol-mode: use text region, not generic coder\n"); fprintf(stderr, " -t : set classification threshold for symbol coder (def: %0.2f)\n", JBIG2_THRESHOLD_DEF); fprintf(stderr, " -w : set classification weight for symbol coder (def: %0.2f)\n", JBIG2_WEIGHT_DEF); + fprintf(stderr, " -T : set 1 bpp threshold (def: %d)\n", BW_THRESHOLD_DEF); + fprintf(stderr, " -N --normalize: background clean/normalize\n"); fprintf(stderr, " -r --refine: use refinement (requires -s: lossless)\n"); fprintf(stderr, " -O : dump thresholded image as PNG\n"); fprintf(stderr, " -2: upsample 2x before thresholding\n"); @@ -209,8 +214,11 @@ int main(int argc, char **argv) { bool duplicate_line_removal = false; bool pdfmode = false; + bool bgnmode = false; float threshold = JBIG2_THRESHOLD_DEF; float weight = JBIG2_WEIGHT_DEF; + int bw_threshold = BW_THRESHOLD_DEF; + int bwthresdelta = 0; bool symbol_mode = false; bool refine = false; bool up2 = false, up4 = false; @@ -351,6 +359,11 @@ main(int argc, char **argv) { continue; } + if (strcmp(argv[i], "-N") == 0 || +strcmp(argv[i], "--normalize") == 0) { + bgnmode = true; + continue; + } + // engage auto thresholding if (strcmp(argv[i], "--auto-thresh") == 0 || strcmp(argv[i], "-a") == 0 ) { @@ -409,6 +422,9 @@ main(int argc, char **argv) { struct jbig2ctx *ctx = jbig2_init(threshold, weight, 0, 0, !pdfmode, refine ? 10 : -1); int pageno = -1; + bwthresdelta = (bgnmode) ? 0 : 64; + bw_threshold = ((bw_threshold + bwthresdelta) < 256) ? (bw_threshold + bwthresdelta) : 255; + int numsubimages=0, subimage=0, num_pages = 0; while (i < argc) { if (subimage==numsubimages) { @@ -462,14 +478,18 @@ main(int argc, char **argv) { fprintf(stderr, "Unsupported input image depth: %d\n", pixl->d); return 1; } - adapt = pixCleanBackgroundToWhite(gray, NULL, NULL, 1.0, 90, 190); + if (bgnmode) { + adapt = pixBackgroundNormSimple(gray, NULL, NULL); + } else { + adapt = pixCleanBackgroundToWhite(gray, NULL, NULL, 1.0, 90, 190); + } pixDestroy(&gray); if (up2) { - pixt = pixScaleGray2xLIThresh(adapt, 220); + pixt = pixScaleGray2xLIThresh(adapt, bw_threshold); } else if (up4) { - pixt = pixScaleGray4xLIThresh(adapt, 220); + pixt = pixScaleGray4xLIThresh(adapt, bw_threshold); } else { - pixt = pixThresholdToBinary(adapt, 220); + pixt = pixThresholdToBinary(adapt, bw_threshold); } pixDestroy(&adapt); } else { From fbc9fda3229d8573c0a5472d20e53ec8859ae886 Mon Sep 17 00:00:00 2001 From: zvezdochiot Date: Fri, 20 Dec 2024 18:59:45 +0100 Subject: [PATCH 3/4] fix BW_THRESHOLD_DEF --- src/jbig2.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/jbig2.cc b/src/jbig2.cc index 9067295..f877504 100644 --- a/src/jbig2.cc +++ b/src/jbig2.cc @@ -49,7 +49,7 @@ #define JBIG2_WEIGHT_DEF 0.5f #define BW_THRESHOLD_MIN 0 #define BW_THRESHOLD_MAX 255 -#define BW_THRESHOLD_DEF 192 +#define BW_THRESHOLD_DEF 128 static void usage(const char *argv0) { From e9092153032fdb85ff76d48ad90d27e6cf4052e4 Mon Sep 17 00:00:00 2001 From: zvezdochiot Date: Sat, 21 Dec 2024 11:15:44 +0100 Subject: [PATCH 4/4] Implement `--global` option simple threshold for BW images --- src/jbig2.cc | 21 +++++++++++++++++---- 1 file changed, 17 insertions(+), 4 deletions(-) diff --git a/src/jbig2.cc b/src/jbig2.cc index f877504..dc98fe4 100644 --- a/src/jbig2.cc +++ b/src/jbig2.cc @@ -62,6 +62,7 @@ usage(const char *argv0) { fprintf(stderr, " -t : set classification threshold for symbol coder (def: %0.2f)\n", JBIG2_THRESHOLD_DEF); fprintf(stderr, " -w : set classification weight for symbol coder (def: %0.2f)\n", JBIG2_WEIGHT_DEF); fprintf(stderr, " -T : set 1 bpp threshold (def: %d)\n", BW_THRESHOLD_DEF); + fprintf(stderr, " -G --global: simply threshold for BW images\n"); fprintf(stderr, " -N --normalize: background clean/normalize\n"); fprintf(stderr, " -r --refine: use refinement (requires -s: lossless)\n"); fprintf(stderr, " -O : dump thresholded image as PNG\n"); @@ -214,6 +215,7 @@ int main(int argc, char **argv) { bool duplicate_line_removal = false; bool pdfmode = false; + bool globalmode = false; bool bgnmode = false; float threshold = JBIG2_THRESHOLD_DEF; float weight = JBIG2_WEIGHT_DEF; @@ -359,7 +361,14 @@ main(int argc, char **argv) { continue; } - if (strcmp(argv[i], "-N") == 0 || +strcmp(argv[i], "--normalize") == 0) { + if (strcmp(argv[i], "-G") == 0 || + strcmp(argv[i], "--global") == 0) { + globalmode = true; + continue; + } + + if (strcmp(argv[i], "-N") == 0 || + strcmp(argv[i], "--normalize") == 0) { bgnmode = true; continue; } @@ -422,8 +431,10 @@ main(int argc, char **argv) { struct jbig2ctx *ctx = jbig2_init(threshold, weight, 0, 0, !pdfmode, refine ? 10 : -1); int pageno = -1; - bwthresdelta = (bgnmode) ? 0 : 64; - bw_threshold = ((bw_threshold + bwthresdelta) < 256) ? (bw_threshold + bwthresdelta) : 255; + if (!globalmode) { + bwthresdelta = (bgnmode) ? 0 : 64; + bw_threshold = ((bw_threshold + bwthresdelta) < 256) ? (bw_threshold + bwthresdelta) : 255; + } int numsubimages=0, subimage=0, num_pages = 0; while (i < argc) { @@ -478,7 +489,9 @@ main(int argc, char **argv) { fprintf(stderr, "Unsupported input image depth: %d\n", pixl->d); return 1; } - if (bgnmode) { + if (globalmode) { + adapt = pixClone(gray); + } else if (bgnmode) { adapt = pixBackgroundNormSimple(gray, NULL, NULL); } else { adapt = pixCleanBackgroundToWhite(gray, NULL, NULL, 1.0, 90, 190);