From eb6d5232b45adf6aa6450e3b378d2bc5a7427fc4 Mon Sep 17 00:00:00 2001 From: Ger Hobbelt Date: Mon, 27 Feb 2023 18:44:05 +0100 Subject: [PATCH] Introducing new APIs to assist with detecting and reporting overlarge input images. Available to both userland and tesseract internal code, these can be used to report & early fail images which are too large to fit in memory. Some very lenient defaults are used for the memory pressure allowance (1.5 GByte for 32bit builds, 64GByte for 64bit builds) but this can be tweaked to your liking and local machine shop via Tesseract Global Variable `allowed_image_memory_capacity` (DOUBLE type). NOTE: the allowance limit can be effectively removed by setting this variable to an 'insane' value, e.g. `1.0e30`. HOWEVER, the CheckAndReportIfImageTooLarge() API will still fire for images with either width or high dimension >= TDIMENSION_MAX, which in the default built is the classic INT16_MAX (32767px); when compiled with defined(LARGE_IMAGES), then the width/height limit is raised to 24bit i.e. ~ 16.7 Mpx, which would then tolerate images smaller than 16777216 x 16777216px. (This latter part is a work-in-progress.) Related: - https://github.com/tesseract-ocr/tesseract/issues/3184 - https://github.com/tesseract-ocr/tesseract/issues/3885 - https://github.com/tesseract-ocr/tesseract/pull/3435 (pullreq by @stweil -- WIP) --- include/tesseract/baseapi.h | 32 +++ include/tesseract/memcost_estimate.h | 62 +++++ src/api/baseapi.cpp | 86 +++++- src/ccmain/tesseractclass.cpp | 41 +++ src/ccmain/tesseractclass.h | 23 +- src/ccmain/thresholder.cpp | 19 +- src/ccutil/memcost_estimate.cpp | 381 +++++++++++++++++++++++++++ src/ccutil/params.h | 6 + src/ccutil/tesstypes.h | 10 +- src/textord/tordmain.cpp | 11 +- 10 files changed, 652 insertions(+), 19 deletions(-) create mode 100644 include/tesseract/memcost_estimate.h create mode 100644 src/ccutil/memcost_estimate.cpp diff --git a/include/tesseract/baseapi.h b/include/tesseract/baseapi.h index 5db32e6413..58d5f317ff 100644 --- a/include/tesseract/baseapi.h +++ b/include/tesseract/baseapi.h @@ -28,6 +28,7 @@ #include "unichar.h" #include +#include // for ImageCostEstimate #include #include // for std::tuple @@ -119,6 +120,37 @@ class TESS_API TessBaseAPI { void SetVisibleImage(Pix *pix); Pix* GetVisibleImage(); + /** + * Return a memory capacity cost estimate for the given image dimensions and + * some heuristics re tesseract behaviour, e.g. input images will be normalized/greyscaled, + * then thresholded, all of which will be kept in memory while the session runs. + * + * Also uses the Tesseract Variable `allowed_image_memory_capacity` to indicate + * whether the estimated cost is oversized --> `cost.is_too_large()` + * + * For user convenience, static functions are provided: + * the static functions MAY be used by userland code *before* the high cost of + * instantiating a Tesseract instance is incurred. + */ + static ImageCostEstimate EstimateImageMemoryCost(int image_width, int image_height, float allowance = 1.0e30f /* a.k.a.dont_care, use system limit and be done */ ); + static ImageCostEstimate EstimateImageMemoryCost(const Pix* pix, float allowance = 1.0e30f /* a.k.a. dont_care, use system limit and be done */ ); + + /** + * Ditto, but this API may be invoked after SetInputImage() or equivalent has been called + * and reports the cost estimate for the current instance/image. + */ + ImageCostEstimate EstimateImageMemoryCost() const; + + /** + * Helper, which may be invoked after SetInputImage() or equivalent has been called: + * reports the cost estimate for the current instance/image via `tprintf()` and returns + * `true` when the cost is expected to be too high. + * + * You can use this as a fast pre-flight check. Many major tesseract APIs perform + * this same check as part of their startup routine. + */ + bool CheckAndReportIfImageTooLarge(const Pix* pix = nullptr /* default: use GetInputImage() data */ ) const; + /** Set the name of the bonus output files. Needed only for debugging. */ void SetOutputName(const char *name); const std::string &GetOutputName(); diff --git a/include/tesseract/memcost_estimate.h b/include/tesseract/memcost_estimate.h new file mode 100644 index 0000000000..a27307fb37 --- /dev/null +++ b/include/tesseract/memcost_estimate.h @@ -0,0 +1,62 @@ +/********************************************************************** + * File: memcost_estimate.h + * Description: Inline routines and macros for serialisation functions + * Author: Ger Hobbelt + * + * (C) Copyright 1990, Hewlett-Packard Ltd. + ** Licensed under the Apache License, Version 2.0 (the "License"); + ** you may not use this file except in compliance with the License. + ** You may obtain a copy of the License at + ** http://www.apache.org/licenses/LICENSE-2.0 + ** Unless required by applicable law or agreed to in writing, software + ** distributed under the License is distributed on an "AS IS" BASIS, + ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + ** See the License for the specific language governing permissions and + ** limitations under the License. + * + **********************************************************************/ + +#ifndef T_MEMCOST_ESTIMATE_H +#define T_MEMCOST_ESTIMATE_H + +#include + +namespace tesseract { + + // Image memory capacity cost estimate report. Cost is measured in BYTES. Cost is reported + // (`to_string()`) in GBYTES. + // + // Uses `allowed_image_memory_capacity` plus some compile-time heuristics to indicate + // whether the estimated cost is oversized --> `cost.is_too_large()` + struct ImageCostEstimate { + float cost; + + protected: + float allowed_image_memory_capacity; + + public: + ImageCostEstimate() + : ImageCostEstimate(0.0f, 1e30f) { + } + + ImageCostEstimate(float c, float allowance = 1e30f); + + static float get_max_system_allowance(); + + float get_max_allowance() const; + + void set_max_allowance(float allowance); + + bool is_too_large() const; + + std::string to_string() const; + + // implicit conversion + operator std::string() const; + + static std::string capacity_to_string(float cost); + }; + +} // namespace tesseract. + +#endif diff --git a/src/api/baseapi.cpp b/src/api/baseapi.cpp index 8737789b4a..4da5f6dfea 100644 --- a/src/api/baseapi.cpp +++ b/src/api/baseapi.cpp @@ -75,6 +75,7 @@ #include // for std::pair #include // for std::stringstream #include // for std::vector +#include #include // for pixDestroy, boxCreate, boxaAddBox, box... #ifdef HAVE_LIBCURL @@ -106,14 +107,15 @@ namespace tesseract { FZ_HEAPDBG_TRACKER_SECTION_START_MARKER(_) -static BOOL_VAR(stream_filelist, false, "Stream a filelist from stdin"); -static STRING_VAR(document_title, "", "Title of output document (used for hOCR and PDF output)"); +BOOL_VAR(stream_filelist, false, "Stream a filelist from stdin"); +STRING_VAR(document_title, "", "Title of output document (used for hOCR and PDF output)"); #ifdef HAVE_LIBCURL -static INT_VAR(curl_timeout, 0, "Timeout for curl in seconds"); +INT_VAR(curl_timeout, 0, "Timeout for curl in seconds"); #endif BOOL_VAR(debug_all, false, "Turn on all the debugging features"); STRING_VAR(vars_report_file, "+", "Filename/path to write the 'Which -c variables were used' report. File may be 'stdout', '1' or '-' to be output to stdout. File may be 'stderr', '2' or '+' to be output to stderr. Empty means no report will be produced."); BOOL_VAR(report_all_variables, true, "When reporting the variables used (via 'vars_report_file') also report all *unused* variables, hence the report will always list *all available variables."); +double_VAR(allowed_image_memory_capacity, ImageCostEstimate::get_max_system_allowance(), "Set maximum memory allowance for image data: this will be used as part of a sanity check for oversized input images."); /** Minimum sensible image size to be worth running tesseract. */ @@ -295,6 +297,66 @@ void TessBaseAPI::SetVisibleImageFilename(const char* name) { visible_image_file_ = name ? name : ""; } +/** +* Return a memory capacity cost estimate for the given image dimensions and +* some heuristics re tesseract behaviour, e.g. input images will be normalized/greyscaled, +* then thresholded, all of which will be kept in memory while the session runs. +* +* Also uses the Tesseract Variable `allowed_image_memory_capacity` to indicate +* whether the estimated cost is oversized --> `cost.is_too_large()` +* +* For user convenience, static functions are provided: +* the static functions MAY be used by userland code *before* the high cost of +* instantiating a Tesseract instance is incurred. +*/ +ImageCostEstimate TessBaseAPI::EstimateImageMemoryCost(int image_width, int image_height, float allowance) { + // The heuristics used: + // + // we reckon with leptonica Pix storage at 4 bytes per pixel, + // tesseract storing (worst case) 3 different images: original, greyscale, binary thresholded, + // we DO NOT reckon with the extra image that may serve as background for PDF outputs, etc. + // we DO NOT reckon with the memory cost for the OCR match tree, etc. + // However, we attempt a VERY ROUGH estimate by calculating a 20% overdraft for internal operations' + // storage costs. + float cost = 4 * 3 * 1.20f; + cost *= image_width; + cost *= image_height; + + if (allowed_image_memory_capacity > 0.0) { + // any rediculous input values will be replaced by the Tesseract configuration value: + if (allowance > allowed_image_memory_capacity || allowance <= 0.0) + allowance = allowed_image_memory_capacity; + } + + return ImageCostEstimate(cost, allowance); +} + +ImageCostEstimate TessBaseAPI::EstimateImageMemoryCost(const Pix* pix, float allowance) { + auto w = pixGetWidth(pix); + auto h = pixGetHeight(pix); + return EstimateImageMemoryCost(w, h, allowance); +} + +/** +* Ditto, but this API may be invoked after SetInputImage() or equivalent has been called +* and reports the cost estimate for the current instance/image. +*/ +ImageCostEstimate TessBaseAPI::EstimateImageMemoryCost() const { + return tesseract_->EstimateImageMemoryCost(); +} + +/** +* Helper, which may be invoked after SetInputImage() or equivalent has been called: +* reports the cost estimate for the current instance/image via `tprintf()` and returns +* `true` when the cost is expected to be too high. +* +* You can use this as a fast pre-flight check. Many major tesseract APIs perform +* this same check as part of their startup routine. +*/ +bool TessBaseAPI::CheckAndReportIfImageTooLarge(const Pix* pix) const { + return tesseract_->CheckAndReportIfImageTooLarge(pix); +} + /** Set the name of the output files. Needed only for debugging. */ void TessBaseAPI::SetOutputName(const char *name) { output_file_ = name ? name : ""; @@ -1448,6 +1510,22 @@ bool TessBaseAPI::ProcessPage(Pix *pix, int page_index, const char *filename, SetImage(pix); + // Before wee start to do *real* work, do a preliminary sanity check re expected memory pressure. + // The check MAY recur in some (semi)public APIs that MAY be called later, but this is the big one + // and it's a simple check at negligible cost, saving us some headaches when we start feeding large + // material to the Tesseract animal. + // + // TODO: rescale overlarge input images? Or is that left to userland code? (as it'll be pretty fringe anyway) + { + auto cost = TessBaseAPI::EstimateImageMemoryCost(pix); + std::string cost_report = cost; + tprintf("Estimated memory pressure: {} for input image size {} x {} px\n", cost_report, pixGetWidth(pix), pixGetHeight(pix)); + + if (CheckAndReportIfImageTooLarge(pix)) { + return false; // fail early + } + } + // Image preprocessing on image // Grayscale normalization int graynorm_mode = tesseract_->preprocess_graynorm_mode; @@ -1465,7 +1543,7 @@ bool TessBaseAPI::ProcessPage(Pix *pix, int page_index, const char *filename, } // Recognition - + bool failed = false; if (tesseract_->tessedit_pageseg_mode == PSM_AUTO_ONLY) { diff --git a/src/ccmain/tesseractclass.cpp b/src/ccmain/tesseractclass.cpp index 378785f171..0f2214f190 100644 --- a/src/ccmain/tesseractclass.cpp +++ b/src/ccmain/tesseractclass.cpp @@ -668,4 +668,45 @@ void Tesseract::PrepareForTessOCR(BLOCK_LIST *block_list, Tesseract *osd_tess, O splitter_.Clear(); } +// Return a memory capacity cost estimate for the given image / current original image. +// +// uses the current original image for the estimate, i.e. tells you the cost estimate of this run: +ImageCostEstimate Tesseract::EstimateImageMemoryCost(const Pix* pix) const { + // default: use pix_original() data + if (pix == nullptr) { + pix = pix_original(); + } + + return TessBaseAPI::EstimateImageMemoryCost(pix, allowed_image_memory_capacity); +} + +// Helper, which may be invoked after SetInputImage() or equivalent has been called: +// reports the cost estimate for the current instance/image via `tprintf()` and returns +// `true` when the cost is expected to be too high. +bool Tesseract::CheckAndReportIfImageTooLarge(const Pix* pix) const { + // default: use pix_original() data + if (pix == nullptr) { + pix = pix_original(); + } + + auto w = pixGetWidth(pix); + auto h = pixGetHeight(pix); + return CheckAndReportIfImageTooLarge(w, h); +} + +bool Tesseract::CheckAndReportIfImageTooLarge(int width, int height) const { + auto cost = TessBaseAPI::EstimateImageMemoryCost(width, height, allowed_image_memory_capacity); + + if (debug_all) { + tprintf("Image size & memory cost estimate: {} x {} px, estimated cost {} vs. {} allowed capacity.\n", + width, height, cost.to_string(), ImageCostEstimate::capacity_to_string(allowed_image_memory_capacity)); + } + + if (width >= TDIMENSION_MAX || height >= TDIMENSION_MAX || cost.is_too_large()) { + tprintf("ERROR: Image is too large: ({} x {} px, {})\n", width, height, cost.to_string()); + return true; + } + return false; +} + } // namespace tesseract diff --git a/src/ccmain/tesseractclass.h b/src/ccmain/tesseractclass.h index f57db9f7af..5bb27dd5ac 100644 --- a/src/ccmain/tesseractclass.h +++ b/src/ccmain/tesseractclass.h @@ -45,10 +45,11 @@ #include "wordrec.h" // for Wordrec #include "imagefind.h" // for ImageFind #include "linefind.h" // for LineFinder -#include "genericvector.h" // for PointerVector (ptr only) +#include "genericvector.h" // for PointerVector (ptr only) #include // for OcrEngineMode, PageSegMode, OEM_L... #include // for UNICHAR_ID +#include // for ImageCostEstimate #include // for pixDestroy, pixGetWidth, pixGetHe... @@ -181,6 +182,7 @@ struct WordData { PointerVector lang_words; }; + // Definition of a Tesseract WordRecognizer. The WordData provides the context // of row/block, in_word holds an initialized, possibly pre-classified word, // that the recognizer may or may not consume (but if so it sets @@ -231,9 +233,11 @@ class TESS_API Tesseract: public Wordrec { pix_grey_.destroy(); pix_grey_ = grey_pix; } - //DebugPixa &pix_debug() { - // return pixa_debug_; - //} +#if 0 + DebugPixa &pix_debug() { + return pixa_debug_; + } +#endif Image pix_original() const { return pix_original_; } @@ -247,6 +251,17 @@ class TESS_API Tesseract: public Wordrec { } } + // Return a memory capacity cost estimate for the given image / current original image. + // + // (unless overridden by the `pix` argument) uses the current original image for the estimate, + // i.e. tells you the cost estimate of this run: + ImageCostEstimate EstimateImageMemoryCost(const Pix* pix = nullptr /* default: use pix_original() data */) const; + // Helper, which may be invoked after SetInputImage() or equivalent has been called: + // reports the cost estimate for the current instance/image via `tprintf()` and returns + // `true` when the cost is expected to be too high. + bool CheckAndReportIfImageTooLarge(const Pix* pix = nullptr /* default: use pix_original() data */) const; + bool CheckAndReportIfImageTooLarge(int width, int height) const; + // Returns a pointer to a Pix representing the best available resolution image // of the page, with best available bit depth as second priority. Result can // be of any bit depth, but never color-mapped, as that has always been diff --git a/src/ccmain/thresholder.cpp b/src/ccmain/thresholder.cpp index 1f179a207b..15189582a9 100644 --- a/src/ccmain/thresholder.cpp +++ b/src/ccmain/thresholder.cpp @@ -534,15 +534,24 @@ std::tuple ImageThresholder::Threshold( // Threshold the source image as efficiently as possible to the output Pix. // Creates a Pix and sets pix to point to the resulting pointer. // Caller must use pixDestroy to free the created Pix. +// /// Returns false on error. bool ImageThresholder::ThresholdToPix(Image *pix) { -#if !defined(LARGE_IMAGES) - if (image_width_ > INT16_MAX || image_height_ > INT16_MAX) { - tprintf("ERROR: Image too large: ({}, {})\n", image_width_, image_height_); - return false; + // tolerate overlarge images when they're about to be cropped by GetPixRect(): + if (IsFullImage()) { + if (tesseract_->CheckAndReportIfImageTooLarge(pix_)) { + return false; + } } -#endif + else { + // validate against the future cropped image size: + if (tesseract_->CheckAndReportIfImageTooLarge(rect_width_, rect_height_)) { + return false; + } + } + Image original = GetPixRect(); + if (pix_channels_ == 0) { // We have a binary image, but it still has to be copied, as this API // allows the caller to modify the output. diff --git a/src/ccutil/memcost_estimate.cpp b/src/ccutil/memcost_estimate.cpp new file mode 100644 index 0000000000..3669ebf88d --- /dev/null +++ b/src/ccutil/memcost_estimate.cpp @@ -0,0 +1,381 @@ +/********************************************************************** + * File: memcost_estimate.cpp + * Description: Inline routines and macros for serialisation functions + * Author: Ger Hobbelt + * + * (C) Copyright 1990, Hewlett-Packard Ltd. + ** Licensed under the Apache License, Version 2.0 (the "License"); + ** you may not use this file except in compliance with the License. + ** You may obtain a copy of the License at + ** http://www.apache.org/licenses/LICENSE-2.0 + ** Unless required by applicable law or agreed to in writing, software + ** distributed under the License is distributed on an "AS IS" BASIS, + ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + ** See the License for the specific language governing permissions and + ** limitations under the License. + * + **********************************************************************/ + +#include // FileReader +#include +#include +#include +#include + +#include + + +namespace tesseract { + + ImageCostEstimate::ImageCostEstimate(float c, float allowance) + : cost(c), allowed_image_memory_capacity(allowance) { + } + + float ImageCostEstimate::get_max_system_allowance() { + const float max_reasonable_RAM_usage = (sizeof(size_t) <= 4 ? 1.5e9 /* 1.5 GByte) */ : 64e9 /* 64 GByte */); + return max_reasonable_RAM_usage; + } + + float ImageCostEstimate::get_max_allowance() const { + return fmin(get_max_system_allowance(), allowed_image_memory_capacity); + } + + void ImageCostEstimate::set_max_allowance(float allowance) { + allowed_image_memory_capacity = allowance; + } + + bool ImageCostEstimate::is_too_large() const { + return cost > get_max_allowance(); + } + + std::string ImageCostEstimate::capacity_to_string(float cost) { + if (cost < 0) + return "?negative/NaN cost?"; + + char buf[30]; + int pwr = (int) log10f(cost); + pwr++; + int mil = pwr / 3; + static const char* range[] = { "", "K", "M", "G", "T", "P" }; + const int max_range = sizeof(range) / sizeof(range[0]) - 1; + int prec = 3 - (pwr % 3); // % --> {0,1,2}--> {3,2,1} --> {2,2,1} + if (prec > 2) { + prec = 0; + mil--; + } + if (mil <= 0) { // `mil` can now be -1 when cost is tiny (few bytes) or hard negative for cost==NaN + prec = 0; // and there cannot be *partial* bytes in a cost report + mil = 0; + } + if (mil > max_range) { + mil = max_range; + prec = 0; + } + + float val = cost / pow(10, mil * 3); + snprintf(buf, sizeof(buf), "%0.*f %sByte%s", prec, val, range[mil], (mil == 0 ? "s" : "")); + return buf; + } + + std::string ImageCostEstimate::to_string() const { + return std::move(ImageCostEstimate::capacity_to_string(cost)); + } + + // implicit conversion + ImageCostEstimate:: operator std::string() const { + return std::move(to_string()); + } + +} // namespace tesseract. + + + +// test code: + +#if 0 + +#include "tesseractclass.h" + +using namespace tesseract; + +int main() { + auto cost = Tesseract::EstimateImageMemoryCost(1280,1920, 1.0e30f); + std::string cost_report = cost; + printf("Demo: estimated memory pressure: %s\nDisplay test ...\n", cost_report.c_str()); + + for (float sz = 0; sz < 1e30; sz += 1 + sz * 0.3) { + cost.cost = sz; + cost_report = cost; + printf("%s\n", cost_report.c_str()); + } + return 0; +} + +/* +Expected: 3 significant digits in display. Tested ! OK ! for *extended* expected working range, up to Petabytes. + +Display test output: + +0 Bytes +1 Bytes +2 Bytes +4 Bytes +6 Bytes +9 Bytes +13 Bytes +18 Bytes +24 Bytes +32 Bytes +43 Bytes +56 Bytes +74 Bytes +98 Bytes +128 Bytes +167 Bytes +218 Bytes +285 Bytes +372 Bytes +484 Bytes +630 Bytes +820 Bytes +1.07 KByte +1.39 KByte +1.81 KByte +2.35 KByte +3.05 KByte +3.97 KByte +5.16 KByte +6.71 KByte +8.73 KByte +11.3 KByte +14.8 KByte +19.2 KByte +24.9 KByte +32.4 KByte +42.2 KByte +54.8 KByte +71.2 KByte +92.6 KByte +120 KByte +157 KByte +203 KByte +265 KByte +344 KByte +447 KByte +581 KByte +755 KByte +982 KByte +1.28 MByte +1.66 MByte +2.16 MByte +2.80 MByte +3.65 MByte +4.74 MByte +6.16 MByte +8.01 MByte +10.4 MByte +13.5 MByte +17.6 MByte +22.9 MByte +29.7 MByte +38.7 MByte +50.3 MByte +65.4 MByte +85.0 MByte +110 MByte +144 MByte +187 MByte +243 MByte +315 MByte +410 MByte +533 MByte +693 MByte +901 MByte +1.17 GByte +1.52 GByte +1.98 GByte +2.57 GByte +3.35 GByte +4.35 GByte +5.65 GByte +7.35 GByte +9.55 GByte +12.4 GByte +16.1 GByte +21.0 GByte +27.3 GByte +35.5 GByte +46.1 GByte +59.9 GByte +77.9 GByte +101 GByte +132 GByte +171 GByte +223 GByte +289 GByte +376 GByte +489 GByte +636 GByte +826 GByte +1.07 TByte +1.40 TByte +1.82 TByte +2.36 TByte +3.07 TByte +3.99 TByte +5.19 TByte +6.74 TByte +8.76 TByte +11.4 TByte +14.8 TByte +19.3 TByte +25.0 TByte +32.5 TByte +42.3 TByte +55.0 TByte +71.5 TByte +92.9 TByte +121 TByte +157 TByte +204 TByte +265 TByte +345 TByte +449 TByte +583 TByte +758 TByte +986 TByte +1.28 PByte +1.67 PByte +2.17 PByte +2.81 PByte +3.66 PByte +4.76 PByte +6.18 PByte +8.04 PByte +10.5 PByte +13.6 PByte +17.7 PByte +23.0 PByte +29.9 PByte +38.8 PByte +50.4 PByte +65.6 PByte +85.3 PByte +111 PByte +144 PByte +187 PByte +243 PByte +317 PByte +412 PByte +535 PByte +695 PByte +904 PByte +1175 PByte +1528 PByte +1986 PByte +2582 PByte +3357 PByte +4364 PByte +5673 PByte +7375 PByte +9587 PByte +12464 PByte +16203 PByte +21064 PByte +27383 PByte +35597 PByte +46277 PByte +60160 PByte +78208 PByte +101670 PByte +132171 PByte +171822 PByte +223369 PByte +290379 PByte +377493 PByte +490741 PByte +637963 PByte +829352 PByte +1078158 PByte +1401605 PByte +1822086 PByte +2368712 PByte +3079326 PByte +4003124 PByte +5204061 PByte +6765279 PByte +8794863 PByte +11433322 PByte +14863319 PByte +19322314 PByte +25119008 PByte +32654710 PByte +42451124 PByte +55186460 PByte +71742400 PByte +93265120 PByte +121244648 PByte +157618048 PByte +204903456 PByte +266374496 PByte +346286848 PByte +450172896 PByte +585224768 PByte +760792128 PByte +989029824 PByte +1285738752 PByte +1671460352 PByte +2172898560 PByte +2824768000 PByte +3672198656 PByte +4773857792 PByte +6206015488 PByte +8067820032 PByte +10488166400 PByte +13634615296 PByte +17724999680 PByte +23042500608 PByte +29955252224 PByte +38941827072 PByte +50624376832 PByte +65811693568 PByte +85555200000 PByte +111221760000 PByte +144588275712 PByte +187964751872 PByte +244354187264 PByte +317660463104 PByte +412958588928 PByte +536846139392 PByte +697900007424 PByte +907270029312 PByte +1179451129856 PByte +1533286416384 PByte +1993272328192 PByte +2591253856256 PByte +3368630091776 PByte +4379219329024 PByte +5692984918016 PByte +7400880865280 PByte +9621145124864 PByte +12507488976896 PByte +16259735355392 PByte +21137656381440 PByte +27478955393024 PByte +35722639704064 PByte +46439434551296 PByte +60371268272128 PByte +78482650431488 PByte +102027443044352 PByte +132635678474240 PByte +172426394599424 PByte +224154309623808 PByte +291400579022848 PByte +378820746018816 PByte +492466989957120 PByte +640207086944256 PByte +832269166051328 PByte + +*/ + +#endif diff --git a/src/ccutil/params.h b/src/ccutil/params.h index a38337a8a0..3e997b31b4 100644 --- a/src/ccutil/params.h +++ b/src/ccutil/params.h @@ -521,9 +521,15 @@ ParamsVectors *GlobalParams(); // ------------------------------------ +extern BOOL_VAR_H(stream_filelist); +extern STRING_VAR_H(document_title); +#ifdef HAVE_LIBCURL +extern INT_VAR_H(curl_timeout); +#endif extern BOOL_VAR_H(debug_all); extern STRING_VAR_H(vars_report_file); extern BOOL_VAR_H(report_all_variables); +extern double_VAR_H(allowed_image_memory_capacity); } // namespace tesseract diff --git a/src/ccutil/tesstypes.h b/src/ccutil/tesstypes.h index cb5c978da6..521a832892 100644 --- a/src/ccutil/tesstypes.h +++ b/src/ccutil/tesstypes.h @@ -27,9 +27,15 @@ namespace tesseract { // Image dimensions (width and height, coordinates). #if defined(LARGE_IMAGES) -using TDimension = int32_t; +typedef int32_t TDimension; + +#define TDIMENSION_MAX (1 << 24) // cutline() and otheer code has * 256 operations, so we try to keep this safe by keeping 8 bits headspace. +#define TDIMENSION_MIN (-TDIMENSION_MAX) #else -using TDimension = int16_t; +typedef int16_t TDimension; + +#define TDIMENSION_MAX INT16_MAX +#define TDIMENSION_MAX (-INT16_MAX) #endif // Floating point data type used for LSTM calculations. diff --git a/src/textord/tordmain.cpp b/src/textord/tordmain.cpp index 150bdbd242..537d163207 100644 --- a/src/textord/tordmain.cpp +++ b/src/textord/tordmain.cpp @@ -212,11 +212,14 @@ void assign_blobs_to_blocks2(Image pix, void Textord::find_components(Image pix, BLOCK_LIST *blocks, TO_BLOCK_LIST *to_blocks) { auto width = pixGetWidth(pix); auto height = pixGetHeight(pix); - - if (width > INT16_MAX || height > INT16_MAX) { - tprintf("ERROR: Input image too large! ({}, {})\n", width, height); - return; // Can't handle it. + +#if 0 // no check as this is not a public-facing API; the check should've happened already, before you got here. + auto est_cost = tesseract_->EstimateImageMemoryCost(width, height); + if (width > TDIMENSION_MAX || height > TDIMENSION_MAX || est_cost.is_too_large()) { + tprintf("ERROR: Image too large: ({}, {}, {})\n", width, height, est_cost.to_string()); + return; } +#endif BLOCK_IT block_it(blocks); // iterator for (block_it.mark_cycle_pt(); !block_it.cycled_list(); block_it.forward()) {