tesseract 4.1.1
Loading...
Searching...
No Matches
baseapi.cpp
Go to the documentation of this file.
1/**********************************************************************
2 * File: baseapi.cpp
3 * Description: Simple API for calling tesseract.
4 * Author: Ray Smith
5 *
6 * (C) Copyright 2006, Google Inc.
7 ** Licensed under the Apache License, Version 2.0 (the "License");
8 ** you may not use this file except in compliance with the License.
9 ** You may obtain a copy of the License at
10 ** http://www.apache.org/licenses/LICENSE-2.0
11 ** Unless required by applicable law or agreed to in writing, software
12 ** distributed under the License is distributed on an "AS IS" BASIS,
13 ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 ** See the License for the specific language governing permissions and
15 ** limitations under the License.
16 *
17 **********************************************************************/
18
19#define _USE_MATH_DEFINES // for M_PI
20
21// Include automatically generated configuration file if running autoconf.
22#ifdef HAVE_CONFIG_H
23#include "config_auto.h"
24#endif
25
26#include "baseapi.h"
27#ifdef __linux__
28#include <csignal> // for sigaction, SA_RESETHAND, SIGBUS, SIGFPE
29#endif
30
31#if defined(_WIN32)
32#include <fcntl.h>
33#include <io.h>
34#else
35#include <dirent.h> // for closedir, opendir, readdir, DIR, dirent
36#include <libgen.h>
37#include <sys/types.h>
38#include <sys/stat.h> // for stat, S_IFDIR
39#include <unistd.h>
40#endif // _WIN32
41
42#include <cmath> // for round, M_PI
43#include <cstdint> // for int32_t
44#include <cstring> // for strcmp, strcpy
45#include <fstream> // for size_t
46#include <iostream> // for std::cin
47#include <locale> // for std::locale::classic
48#include <memory> // for std::unique_ptr
49#include <set> // for std::pair
50#include <sstream> // for std::stringstream
51#include <vector> // for std::vector
52#ifdef HAVE_LIBCURL
53#include <curl/curl.h>
54#endif
55#include "allheaders.h" // for pixDestroy, boxCreate, boxaAddBox, box...
56#ifndef DISABLED_LEGACY_ENGINE
57#include "blobclass.h" // for ExtractFontName
58#endif
59#include "boxword.h" // for BoxWord
60#include "config_auto.h" // for PACKAGE_VERSION
61#include "coutln.h" // for C_OUTLINE_IT, C_OUTLINE_LIST
62#include "dawg_cache.h" // for DawgCache
63#include "dict.h" // for Dict
64#include "edgblob.h" // for extract_edges
65#include "elst.h" // for ELIST_ITERATOR, ELISTIZE, ELISTIZEH
66#include "environ.h" // for l_uint8
67#include "equationdetect.h" // for EquationDetect
68#include "errcode.h" // for ASSERT_HOST
69#include "helpers.h" // for IntCastRounded, chomp_string
70#include "imageio.h" // for IFF_TIFF_G4, IFF_TIFF, IFF_TIFF_G3, ...
71#ifndef DISABLED_LEGACY_ENGINE
72#include "intfx.h" // for INT_FX_RESULT_STRUCT
73#endif
74#include "mutableiterator.h" // for MutableIterator
75#include "normalis.h" // for kBlnBaselineOffset, kBlnXHeight
76#include "ocrclass.h" // for ETEXT_DESC
77#if defined(USE_OPENCL)
78#include "openclwrapper.h" // for OpenclDevice
79#endif
80#include "osdetect.h" // for OSResults, OSBestResult, OrientationId...
81#include "pageres.h" // for PAGE_RES_IT, WERD_RES, PAGE_RES, CR_DE...
82#include "paragraphs.h" // for DetectParagraphs
83#include "params.h" // for BoolParam, IntParam, DoubleParam, Stri...
84#include "pdblock.h" // for PDBLK
85#include "points.h" // for FCOORD
86#include "polyblk.h" // for POLY_BLOCK
87#include "rect.h" // for TBOX
88#include "renderer.h" // for TessResultRenderer
89#include "resultiterator.h" // for ResultIterator
90#include "stepblob.h" // for C_BLOB_IT, C_BLOB, C_BLOB_LIST
91#include "strngs.h" // for STRING
92#include "tessdatamanager.h" // for TessdataManager, kTrainedDataSuffix
93#include "tesseractclass.h" // for Tesseract
94#include "thresholder.h" // for ImageThresholder
95#include "tprintf.h" // for tprintf
96#include "werd.h" // for WERD, WERD_IT, W_FUZZY_NON, W_FUZZY_SP
97
98static BOOL_VAR(stream_filelist, false, "Stream a filelist from stdin");
99static STRING_VAR(document_title, "", "Title of output document (used for hOCR and PDF output)");
100
101namespace tesseract {
102
104const int kMinRectSize = 10;
106const char kTesseractReject = '~';
108const char kUNLVReject = '~';
110const char kUNLVSuspect = '^';
115static const char* kInputFile = "noname.tif";
119static const char* kOldVarsFile = "failed_vars.txt";
121const int kMaxIntSize = 22;
122
123/* Add all available languages recursively.
124*/
125static void addAvailableLanguages(const STRING &datadir, const STRING &base,
127{
128 const STRING base2 = (base.string()[0] == '\0') ? base : base + "/";
129 const size_t extlen = sizeof(kTrainedDataSuffix);
130#ifdef _WIN32
131 WIN32_FIND_DATA data;
132 HANDLE handle = FindFirstFile((datadir + base2 + "*").string(), &data);
133 if (handle != INVALID_HANDLE_VALUE) {
134 BOOL result = TRUE;
135 for (; result;) {
136 char *name = data.cFileName;
137 // Skip '.', '..', and hidden files
138 if (name[0] != '.') {
139 if ((data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) ==
140 FILE_ATTRIBUTE_DIRECTORY) {
141 addAvailableLanguages(datadir, base2 + name, langs);
142 } else {
143 size_t len = strlen(name);
144 if (len > extlen && name[len - extlen] == '.' &&
145 strcmp(&name[len - extlen + 1], kTrainedDataSuffix) == 0) {
146 name[len - extlen] = '\0';
147 langs->push_back(base2 + name);
148 }
149 }
150 }
151 result = FindNextFile(handle, &data);
152 }
153 FindClose(handle);
154 }
155#else // _WIN32
156 DIR* dir = opendir((datadir + base).string());
157 if (dir != nullptr) {
158 dirent *de;
159 while ((de = readdir(dir))) {
160 char *name = de->d_name;
161 // Skip '.', '..', and hidden files
162 if (name[0] != '.') {
163 struct stat st;
164 if (stat((datadir + base2 + name).string(), &st) == 0 &&
165 (st.st_mode & S_IFDIR) == S_IFDIR) {
166 addAvailableLanguages(datadir, base2 + name, langs);
167 } else {
168 size_t len = strlen(name);
169 if (len > extlen && name[len - extlen] == '.' &&
170 strcmp(&name[len - extlen + 1], kTrainedDataSuffix) == 0) {
171 name[len - extlen] = '\0';
172 langs->push_back(base2 + name);
173 }
174 }
175 }
176 }
177 closedir(dir);
178 }
179#endif
180}
181
182// Compare two STRING values (used for sorting).
183static int CompareSTRING(const void* p1, const void* p2) {
184 const auto* s1 = static_cast<const STRING*>(p1);
185 const auto* s2 = static_cast<const STRING*>(p2);
186 return strcmp(s1->c_str(), s2->c_str());
187}
188
189TessBaseAPI::TessBaseAPI()
190 : tesseract_(nullptr),
191 osd_tesseract_(nullptr),
192 equ_detect_(nullptr),
193 reader_(nullptr),
194 // Thresholder is initialized to nullptr here, but will be set before use by:
195 // A constructor of a derived API, SetThresholder(), or
196 // created implicitly when used in InternalSetImage.
197 thresholder_(nullptr),
198 paragraph_models_(nullptr),
199 block_list_(nullptr),
200 page_res_(nullptr),
201 input_file_(nullptr),
202 output_file_(nullptr),
203 datapath_(nullptr),
204 language_(nullptr),
205 last_oem_requested_(OEM_DEFAULT),
206 recognition_done_(false),
207 truth_cb_(nullptr),
208 rect_left_(0),
209 rect_top_(0),
210 rect_width_(0),
211 rect_height_(0),
212 image_width_(0),
213 image_height_(0) {
214#if defined(DEBUG)
215 // The Tesseract executables would use the "C" locale by default,
216 // but other software which is linked against the Tesseract library
217 // typically uses the locale from the user's environment.
218 // Here the default is overridden to allow debugging of potential
219 // problems caused by the locale settings.
220
221 // Use the current locale if building debug code.
222 std::locale::global(std::locale(""));
223#endif
224}
225
226TessBaseAPI::~TessBaseAPI() {
227 End();
228}
229
233const char* TessBaseAPI::Version() {
234 return PACKAGE_VERSION;
235}
236
244size_t TessBaseAPI::getOpenCLDevice(void **data) {
245#ifdef USE_OPENCL
246 ds_device device = OpenclDevice::getDeviceSelection();
247 if (device.type == DS_DEVICE_OPENCL_DEVICE) {
248 *data = new cl_device_id;
249 memcpy(*data, &device.oclDeviceID, sizeof(cl_device_id));
250 return sizeof(cl_device_id);
251 }
252#endif
253
254 *data = nullptr;
255 return 0;
256}
257
262void TessBaseAPI::CatchSignals() {
263 // Warn API users that an implementation is needed.
264 tprintf("Deprecated method CatchSignals has only a dummy implementation!\n");
265}
266
271void TessBaseAPI::SetInputName(const char* name) {
272 if (input_file_ == nullptr)
273 input_file_ = new STRING(name);
274 else
275 *input_file_ = name;
276}
277
279void TessBaseAPI::SetOutputName(const char* name) {
280 if (output_file_ == nullptr)
281 output_file_ = new STRING(name);
282 else
283 *output_file_ = name;
284}
285
286bool TessBaseAPI::SetVariable(const char* name, const char* value) {
287 if (tesseract_ == nullptr) tesseract_ = new Tesseract;
289 tesseract_->params());
290}
291
292bool TessBaseAPI::SetDebugVariable(const char* name, const char* value) {
293 if (tesseract_ == nullptr) tesseract_ = new Tesseract;
295 tesseract_->params());
296}
297
298bool TessBaseAPI::GetIntVariable(const char *name, int *value) const {
299 auto *p = ParamUtils::FindParam<IntParam>(
300 name, GlobalParams()->int_params, tesseract_->params()->int_params);
301 if (p == nullptr) return false;
302 *value = (int32_t)(*p);
303 return true;
304}
305
306bool TessBaseAPI::GetBoolVariable(const char *name, bool *value) const {
307 auto *p = ParamUtils::FindParam<BoolParam>(
308 name, GlobalParams()->bool_params, tesseract_->params()->bool_params);
309 if (p == nullptr) return false;
310 *value = bool(*p);
311 return true;
312}
313
314const char *TessBaseAPI::GetStringVariable(const char *name) const {
315 auto *p = ParamUtils::FindParam<StringParam>(
316 name, GlobalParams()->string_params, tesseract_->params()->string_params);
317 return (p != nullptr) ? p->string() : nullptr;
318}
319
320bool TessBaseAPI::GetDoubleVariable(const char *name, double *value) const {
321 auto *p = ParamUtils::FindParam<DoubleParam>(
322 name, GlobalParams()->double_params, tesseract_->params()->double_params);
323 if (p == nullptr) return false;
324 *value = (double)(*p);
325 return true;
326}
327
329bool TessBaseAPI::GetVariableAsString(const char *name, STRING *val) {
330 return ParamUtils::GetParamAsString(name, tesseract_->params(), val);
331}
332
334void TessBaseAPI::PrintVariables(FILE *fp) const {
336}
337
346int TessBaseAPI::Init(const char* datapath, const char* language,
347 OcrEngineMode oem, char **configs, int configs_size,
348 const GenericVector<STRING> *vars_vec,
349 const GenericVector<STRING> *vars_values,
350 bool set_only_non_debug_params) {
351 return Init(datapath, 0, language, oem, configs, configs_size, vars_vec,
352 vars_values, set_only_non_debug_params, nullptr);
353}
354
355// In-memory version reads the traineddata file directly from the given
356// data[data_size] array. Also implements the version with a datapath in data,
357// flagged by data_size = 0.
358int TessBaseAPI::Init(const char* data, int data_size, const char* language,
359 OcrEngineMode oem, char** configs, int configs_size,
360 const GenericVector<STRING>* vars_vec,
361 const GenericVector<STRING>* vars_values,
362 bool set_only_non_debug_params, FileReader reader) {
363 // Default language is "eng".
364 if (language == nullptr) language = "eng";
365 STRING datapath = data_size == 0 ? data : language;
366 // If the datapath, OcrEngineMode or the language have changed - start again.
367 // Note that the language_ field stores the last requested language that was
368 // initialized successfully, while tesseract_->lang stores the language
369 // actually used. They differ only if the requested language was nullptr, in
370 // which case tesseract_->lang is set to the Tesseract default ("eng").
371 if (tesseract_ != nullptr &&
372 (datapath_ == nullptr || language_ == nullptr || *datapath_ != datapath ||
374 (*language_ != language && tesseract_->lang != language))) {
375 delete tesseract_;
376 tesseract_ = nullptr;
377 }
378#ifdef USE_OPENCL
379 OpenclDevice od;
380 od.InitEnv();
381#endif
382 bool reset_classifier = true;
383 if (tesseract_ == nullptr) {
384 reset_classifier = false;
385 tesseract_ = new Tesseract;
386 if (reader != nullptr) reader_ = reader;
388 if (data_size != 0) {
389 mgr.LoadMemBuffer(language, data, data_size);
390 }
392 datapath.string(),
393 output_file_ != nullptr ? output_file_->string() : nullptr,
394 language, oem, configs, configs_size, vars_vec, vars_values,
395 set_only_non_debug_params, &mgr) != 0) {
396 return -1;
397 }
398 }
399
400 // Update datapath and language requested for the last valid initialization.
401 if (datapath_ == nullptr)
402 datapath_ = new STRING(datapath);
403 else
404 *datapath_ = datapath;
405 if ((strcmp(datapath_->string(), "") == 0) &&
406 (strcmp(tesseract_->datadir.string(), "") != 0))
408
409 if (language_ == nullptr)
410 language_ = new STRING(language);
411 else
412 *language_ = language;
414
415#ifndef DISABLED_LEGACY_ENGINE
416 // For same language and datapath, just reset the adaptive classifier.
417 if (reset_classifier) {
419 }
420#endif // ndef DISABLED_LEGACY_ENGINE
421 return 0;
422}
423
432const char* TessBaseAPI::GetInitLanguagesAsString() const {
433 return (language_ == nullptr || language_->string() == nullptr) ?
434 "" : language_->string();
435}
436
442void TessBaseAPI::GetLoadedLanguagesAsVector(
443 GenericVector<STRING>* langs) const {
444 langs->clear();
445 if (tesseract_ != nullptr) {
446 langs->push_back(tesseract_->lang);
447 int num_subs = tesseract_->num_sub_langs();
448 for (int i = 0; i < num_subs; ++i)
450 }
451}
452
456void TessBaseAPI::GetAvailableLanguagesAsVector(
457 GenericVector<STRING>* langs) const {
458 langs->clear();
459 if (tesseract_ != nullptr) {
460 addAvailableLanguages(tesseract_->datadir, "", langs);
461 langs->sort(CompareSTRING);
462 }
463}
464
465//TODO(amit): Adapt to lstm
466#ifndef DISABLED_LEGACY_ENGINE
473int TessBaseAPI::InitLangMod(const char* datapath, const char* language) {
474 if (tesseract_ == nullptr)
475 tesseract_ = new Tesseract;
476 else
478 TessdataManager mgr;
479 return tesseract_->init_tesseract_lm(datapath, nullptr, language, &mgr);
480}
481#endif // ndef DISABLED_LEGACY_ENGINE
482
487void TessBaseAPI::InitForAnalysePage() {
488 if (tesseract_ == nullptr) {
489 tesseract_ = new Tesseract;
490 #ifndef DISABLED_LEGACY_ENGINE
492 #endif
493 }
494}
495
501void TessBaseAPI::ReadConfigFile(const char* filename) {
503}
504
506void TessBaseAPI::ReadDebugConfigFile(const char* filename) {
508}
509
515void TessBaseAPI::SetPageSegMode(PageSegMode mode) {
516 if (tesseract_ == nullptr)
517 tesseract_ = new Tesseract;
518 tesseract_->tessedit_pageseg_mode.set_value(mode);
519}
520
522PageSegMode TessBaseAPI::GetPageSegMode() const {
523 if (tesseract_ == nullptr)
524 return PSM_SINGLE_BLOCK;
525 return static_cast<PageSegMode>(
526 static_cast<int>(tesseract_->tessedit_pageseg_mode));
527}
528
542char* TessBaseAPI::TesseractRect(const unsigned char* imagedata,
543 int bytes_per_pixel,
544 int bytes_per_line,
545 int left, int top,
546 int width, int height) {
547 if (tesseract_ == nullptr || width < kMinRectSize || height < kMinRectSize)
548 return nullptr; // Nothing worth doing.
549
550 // Since this original api didn't give the exact size of the image,
551 // we have to invent a reasonable value.
552 int bits_per_pixel = bytes_per_pixel == 0 ? 1 : bytes_per_pixel * 8;
553 SetImage(imagedata, bytes_per_line * 8 / bits_per_pixel, height + top,
554 bytes_per_pixel, bytes_per_line);
555 SetRectangle(left, top, width, height);
556
557 return GetUTF8Text();
558}
559
560#ifndef DISABLED_LEGACY_ENGINE
565void TessBaseAPI::ClearAdaptiveClassifier() {
566 if (tesseract_ == nullptr)
567 return;
570}
571#endif // ndef DISABLED_LEGACY_ENGINE
572
580void TessBaseAPI::SetImage(const unsigned char* imagedata,
581 int width, int height,
582 int bytes_per_pixel, int bytes_per_line) {
583 if (InternalSetImage()) {
584 thresholder_->SetImage(imagedata, width, height,
585 bytes_per_pixel, bytes_per_line);
587 }
588}
589
590void TessBaseAPI::SetSourceResolution(int ppi) {
591 if (thresholder_)
593 else
594 tprintf("Please call SetImage before SetSourceResolution.\n");
595}
596
605void TessBaseAPI::SetImage(Pix* pix) {
606 if (InternalSetImage()) {
607 if (pixGetSpp(pix) == 4 && pixGetInputFormat(pix) == IFF_PNG) {
608 // remove alpha channel from png
609 Pix* p1 = pixRemoveAlpha(pix);
610 pixSetSpp(p1, 3);
611 (void)pixCopy(pix, p1);
612 pixDestroy(&p1);
613 }
616 }
617}
618
624void TessBaseAPI::SetRectangle(int left, int top, int width, int height) {
625 if (thresholder_ == nullptr)
626 return;
627 thresholder_->SetRectangle(left, top, width, height);
628 ClearResults();
629}
630
635Pix* TessBaseAPI::GetThresholdedImage() {
636 if (tesseract_ == nullptr || thresholder_ == nullptr) return nullptr;
637 if (tesseract_->pix_binary() == nullptr &&
639 return nullptr;
640 }
641 return pixClone(tesseract_->pix_binary());
642}
643
649Boxa* TessBaseAPI::GetRegions(Pixa** pixa) {
650 return GetComponentImages(RIL_BLOCK, false, pixa, nullptr);
651}
652
661Boxa* TessBaseAPI::GetTextlines(const bool raw_image, const int raw_padding,
662 Pixa** pixa, int** blockids, int** paraids) {
663 return GetComponentImages(RIL_TEXTLINE, true, raw_image, raw_padding,
664 pixa, blockids, paraids);
665}
666
675Boxa* TessBaseAPI::GetStrips(Pixa** pixa, int** blockids) {
676 return GetComponentImages(RIL_TEXTLINE, false, pixa, blockids);
677}
678
684Boxa* TessBaseAPI::GetWords(Pixa** pixa) {
685 return GetComponentImages(RIL_WORD, true, pixa, nullptr);
686}
687
694Boxa* TessBaseAPI::GetConnectedComponents(Pixa** pixa) {
695 return GetComponentImages(RIL_SYMBOL, true, pixa, nullptr);
696}
697
706Boxa* TessBaseAPI::GetComponentImages(PageIteratorLevel level,
707 bool text_only, bool raw_image,
708 const int raw_padding,
709 Pixa** pixa, int** blockids,
710 int** paraids) {
711 PageIterator* page_it = GetIterator();
712 if (page_it == nullptr)
713 page_it = AnalyseLayout();
714 if (page_it == nullptr)
715 return nullptr; // Failed.
716
717 // Count the components to get a size for the arrays.
718 int component_count = 0;
719 int left, top, right, bottom;
720
721 TessResultCallback<bool>* get_bbox = nullptr;
722 if (raw_image) {
723 // Get bounding box in original raw image with padding.
725 level, raw_padding,
726 &left, &top, &right, &bottom);
727 } else {
728 // Get bounding box from binarized imaged. Note that this could be
729 // differently scaled from the original image.
730 get_bbox = NewPermanentTessCallback(page_it,
732 level, &left, &top, &right, &bottom);
733 }
734 do {
735 if (get_bbox->Run() &&
736 (!text_only || PTIsTextType(page_it->BlockType())))
737 ++component_count;
738 } while (page_it->Next(level));
739
740 Boxa* boxa = boxaCreate(component_count);
741 if (pixa != nullptr)
742 *pixa = pixaCreate(component_count);
743 if (blockids != nullptr)
744 *blockids = new int[component_count];
745 if (paraids != nullptr)
746 *paraids = new int[component_count];
747
748 int blockid = 0;
749 int paraid = 0;
750 int component_index = 0;
751 page_it->Begin();
752 do {
753 if (get_bbox->Run() &&
754 (!text_only || PTIsTextType(page_it->BlockType()))) {
755 Box* lbox = boxCreate(left, top, right - left, bottom - top);
756 boxaAddBox(boxa, lbox, L_INSERT);
757 if (pixa != nullptr) {
758 Pix* pix = nullptr;
759 if (raw_image) {
760 pix = page_it->GetImage(level, raw_padding, GetInputImage(), &left,
761 &top);
762 } else {
763 pix = page_it->GetBinaryImage(level);
764 }
765 pixaAddPix(*pixa, pix, L_INSERT);
766 pixaAddBox(*pixa, lbox, L_CLONE);
767 }
768 if (paraids != nullptr) {
769 (*paraids)[component_index] = paraid;
770 if (page_it->IsAtFinalElement(RIL_PARA, level))
771 ++paraid;
772 }
773 if (blockids != nullptr) {
774 (*blockids)[component_index] = blockid;
775 if (page_it->IsAtFinalElement(RIL_BLOCK, level)) {
776 ++blockid;
777 paraid = 0;
778 }
779 }
780 ++component_index;
781 }
782 } while (page_it->Next(level));
783 delete page_it;
784 delete get_bbox;
785 return boxa;
786}
787
788int TessBaseAPI::GetThresholdedImageScaleFactor() const {
789 if (thresholder_ == nullptr) {
790 return 0;
791 }
793}
794
810PageIterator* TessBaseAPI::AnalyseLayout() { return AnalyseLayout(false); }
811
812PageIterator* TessBaseAPI::AnalyseLayout(bool merge_similar_words) {
813 if (FindLines() == 0) {
814 if (block_list_->empty())
815 return nullptr; // The page was empty.
816 page_res_ = new PAGE_RES(merge_similar_words, block_list_, nullptr);
817 DetectParagraphs(false);
818 return new PageIterator(
822 }
823 return nullptr;
824}
825
830int TessBaseAPI::Recognize(ETEXT_DESC* monitor) {
831 if (tesseract_ == nullptr)
832 return -1;
833 if (FindLines() != 0)
834 return -1;
835 delete page_res_;
836 if (block_list_->empty()) {
837 page_res_ = new PAGE_RES(false, block_list_,
839 return 0; // Empty page.
840 }
841
843 recognition_done_ = true;
844#ifndef DISABLED_LEGACY_ENGINE
849 } else
850#endif // ndef DISABLED_LEGACY_ENGINE
851 {
854 }
855
856 if (page_res_ == nullptr) {
857 return -1;
858 }
859
862 return -1;
863 }
865 return 0;
866 }
867#ifndef DISABLED_LEGACY_ENGINE
870 return 0;
871 }
872#endif // ndef DISABLED_LEGACY_ENGINE
873
874 if (truth_cb_ != nullptr) {
875 tesseract_->wordrec_run_blamer.set_value(true);
876 auto *page_it = new PageIterator(
881 image_height_, page_it, this->tesseract()->pix_grey());
882 delete page_it;
883 }
884
885 int result = 0;
887 #ifndef GRAPHICS_DISABLED
889 #endif // GRAPHICS_DISABLED
890 // The page_res is invalid after an interactive session, so cleanup
891 // in a way that lets us continue to the next page without crashing.
892 delete page_res_;
893 page_res_ = nullptr;
894 return -1;
895 #ifndef DISABLED_LEGACY_ENGINE
897 STRING fontname;
898 ExtractFontName(*output_file_, &fontname);
901 FILE *training_output_file = tesseract_->init_recog_training(*input_file_);
902 // OCR the page segmented into words by tesseract.
904 *input_file_, page_res_, monitor, training_output_file);
905 fclose(training_output_file);
906 #endif // ndef DISABLED_LEGACY_ENGINE
907 } else {
908 // Now run the main recognition.
909 bool wait_for_text = true;
910 GetBoolVariable("paragraph_text_based", &wait_for_text);
911 if (!wait_for_text) DetectParagraphs(false);
912 if (tesseract_->recog_all_words(page_res_, monitor, nullptr, nullptr, 0)) {
913 if (wait_for_text) DetectParagraphs(true);
914 } else {
915 result = -1;
916 }
917 }
918 return result;
919}
920
921#ifndef DISABLED_LEGACY_ENGINE
923int TessBaseAPI::RecognizeForChopTest(ETEXT_DESC* monitor) {
924 if (tesseract_ == nullptr)
925 return -1;
926 if (thresholder_ == nullptr || thresholder_->IsEmpty()) {
927 tprintf("Please call SetImage before attempting recognition.\n");
928 return -1;
929 }
930 if (page_res_ != nullptr)
931 ClearResults();
932 if (FindLines() != 0)
933 return -1;
934 // Additional conditions under which chopper test cannot be run
935 if (tesseract_->interactive_display_mode) return -1;
936
937 recognition_done_ = true;
938
939 page_res_ = new PAGE_RES(false, block_list_,
941
942 PAGE_RES_IT page_res_it(page_res_);
943
944 while (page_res_it.word() != nullptr) {
945 WERD_RES *word_res = page_res_it.word();
947 tesseract_->MaximallyChopWord(boxes, page_res_it.block()->block,
948 page_res_it.row()->row, word_res);
949 page_res_it.forward();
950 }
951 return 0;
952}
953#endif // ndef DISABLED_LEGACY_ENGINE
954
955// Takes ownership of the input pix.
956void TessBaseAPI::SetInputImage(Pix* pix) { tesseract_->set_pix_original(pix); }
957
958Pix* TessBaseAPI::GetInputImage() { return tesseract_->pix_original(); }
959
960const char * TessBaseAPI::GetInputName() {
961 if (input_file_)
962 return input_file_->c_str();
963 return nullptr;
964}
965
966const char * TessBaseAPI::GetDatapath() {
967 return tesseract_->datadir.c_str();
968}
969
970int TessBaseAPI::GetSourceYResolution() {
972}
973
974// If flist exists, get data from there. Otherwise get data from buf.
975// Seems convoluted, but is the easiest way I know of to meet multiple
976// goals. Support streaming from stdin, and also work on platforms
977// lacking fmemopen.
978bool TessBaseAPI::ProcessPagesFileList(FILE *flist,
979 STRING *buf,
980 const char* retry_config,
981 int timeout_millisec,
982 TessResultRenderer* renderer,
983 int tessedit_page_number) {
984 if (!flist && !buf) return false;
985 int page = (tessedit_page_number >= 0) ? tessedit_page_number : 0;
986 char pagename[MAX_PATH];
987
989 if (!flist) {
990 buf->split('\n', &lines);
991 if (lines.empty()) return false;
992 }
993
994 // Skip to the requested page number.
995 for (int i = 0; i < page; i++) {
996 if (flist) {
997 if (fgets(pagename, sizeof(pagename), flist) == nullptr) break;
998 }
999 }
1000
1001 // Begin producing output
1002 if (renderer && !renderer->BeginDocument(document_title.c_str())) {
1003 return false;
1004 }
1005
1006 // Loop over all pages - or just the requested one
1007 while (true) {
1008 if (flist) {
1009 if (fgets(pagename, sizeof(pagename), flist) == nullptr) break;
1010 } else {
1011 if (page >= lines.size()) break;
1012 snprintf(pagename, sizeof(pagename), "%s", lines[page].c_str());
1013 }
1014 chomp_string(pagename);
1015 Pix *pix = pixRead(pagename);
1016 if (pix == nullptr) {
1017 tprintf("Image file %s cannot be read!\n", pagename);
1018 return false;
1019 }
1020 tprintf("Page %d : %s\n", page, pagename);
1021 bool r = ProcessPage(pix, page, pagename, retry_config,
1022 timeout_millisec, renderer);
1023 pixDestroy(&pix);
1024 if (!r) return false;
1025 if (tessedit_page_number >= 0) break;
1026 ++page;
1027 }
1028
1029 // Finish producing output
1030 if (renderer && !renderer->EndDocument()) {
1031 return false;
1032 }
1033 return true;
1034}
1035
1036bool TessBaseAPI::ProcessPagesMultipageTiff(const l_uint8 *data,
1037 size_t size,
1038 const char* filename,
1039 const char* retry_config,
1040 int timeout_millisec,
1041 TessResultRenderer* renderer,
1042 int tessedit_page_number) {
1043#ifndef ANDROID_BUILD
1044 Pix *pix = nullptr;
1045 int page = (tessedit_page_number >= 0) ? tessedit_page_number : 0;
1046 size_t offset = 0;
1047 for (; ; ++page) {
1048 if (tessedit_page_number >= 0) {
1049 page = tessedit_page_number;
1050 pix = (data) ? pixReadMemTiff(data, size, page)
1051 : pixReadTiff(filename, page);
1052 } else {
1053 pix = (data) ? pixReadMemFromMultipageTiff(data, size, &offset)
1054 : pixReadFromMultipageTiff(filename, &offset);
1055 }
1056 if (pix == nullptr) break;
1057 tprintf("Page %d\n", page + 1);
1058 char page_str[kMaxIntSize];
1059 snprintf(page_str, kMaxIntSize - 1, "%d", page);
1060 SetVariable("applybox_page", page_str);
1061 bool r = ProcessPage(pix, page, filename, retry_config,
1062 timeout_millisec, renderer);
1063 pixDestroy(&pix);
1064 if (!r) return false;
1065 if (tessedit_page_number >= 0) break;
1066 if (!offset) break;
1067 }
1068 return true;
1069#else
1070 return false;
1071#endif
1072}
1073
1074// Master ProcessPages calls ProcessPagesInternal and then does any post-
1075// processing required due to being in a training mode.
1076bool TessBaseAPI::ProcessPages(const char* filename, const char* retry_config,
1077 int timeout_millisec,
1078 TessResultRenderer* renderer) {
1079 bool result =
1080 ProcessPagesInternal(filename, retry_config, timeout_millisec, renderer);
1081 #ifndef DISABLED_LEGACY_ENGINE
1082 if (result) {
1085 tprintf("Write of TR file failed: %s\n", output_file_->string());
1086 return false;
1087 }
1088 }
1089 #endif // ndef DISABLED_LEGACY_ENGINE
1090 return result;
1091}
1092
1093static size_t
1094WriteMemoryCallback(void *contents, size_t size, size_t nmemb, void *userp)
1095{
1096 size = size * nmemb;
1097 std::string* buf = reinterpret_cast<std::string*>(userp);
1098 buf->append(reinterpret_cast<const char*>(contents), size);
1099 return size;
1100}
1101
1102// In the ideal scenario, Tesseract will start working on data as soon
1103// as it can. For example, if you stream a filelist through stdin, we
1104// should start the OCR process as soon as the first filename is
1105// available. This is particularly useful when hooking Tesseract up to
1106// slow hardware such as a book scanning machine.
1107//
1108// Unfortunately there are tradeoffs. You can't seek on stdin. That
1109// makes automatic detection of datatype (TIFF? filelist? PNG?)
1110// impractical. So we support a command line flag to explicitly
1111// identify the scenario that really matters: filelists on
1112// stdin. We'll still do our best if the user likes pipes.
1113bool TessBaseAPI::ProcessPagesInternal(const char* filename,
1114 const char* retry_config,
1115 int timeout_millisec,
1116 TessResultRenderer* renderer) {
1117 bool stdInput = !strcmp(filename, "stdin") || !strcmp(filename, "-");
1118 if (stdInput) {
1119#ifdef WIN32
1120 if (_setmode(_fileno(stdin), _O_BINARY) == -1)
1121 tprintf("ERROR: cin to binary: %s", strerror(errno));
1122#endif // WIN32
1123 }
1124
1125 if (stream_filelist) {
1126 return ProcessPagesFileList(stdin, nullptr, retry_config,
1127 timeout_millisec, renderer,
1129 }
1130
1131 // At this point we are officially in autodection territory.
1132 // That means any data in stdin must be buffered, to make it
1133 // seekable.
1134 std::string buf;
1135 const l_uint8 *data = nullptr;
1136 if (stdInput) {
1137 buf.assign((std::istreambuf_iterator<char>(std::cin)),
1138 (std::istreambuf_iterator<char>()));
1139 data = reinterpret_cast<const l_uint8 *>(buf.data());
1140 } else if (strncmp(filename, "http:", 5) == 0 ||
1141 strncmp(filename, "https:", 6) == 0 ) {
1142 // Get image or image list by URL.
1143#ifdef HAVE_LIBCURL
1144 CURL* curl = curl_easy_init();
1145 if (curl == nullptr) {
1146 fprintf(stderr, "Error, curl_easy_init failed\n");
1147 return false;
1148 } else {
1149 CURLcode curlcode;
1150 curlcode = curl_easy_setopt(curl, CURLOPT_URL, filename);
1151 ASSERT_HOST(curlcode == CURLE_OK);
1152 curlcode = curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, WriteMemoryCallback);
1153 ASSERT_HOST(curlcode == CURLE_OK);
1154 curlcode = curl_easy_setopt(curl, CURLOPT_WRITEDATA, &buf);
1155 ASSERT_HOST(curlcode == CURLE_OK);
1156 curlcode = curl_easy_perform(curl);
1157 ASSERT_HOST(curlcode == CURLE_OK);
1158 curl_easy_cleanup(curl);
1159 data = reinterpret_cast<const l_uint8 *>(buf.data());
1160 }
1161#else
1162 fprintf(stderr, "Error, this tesseract has no URL support\n");
1163 return false;
1164#endif
1165 } else {
1166 // Check whether the input file can be read.
1167 if (FILE* file = fopen(filename, "rb")) {
1168 fclose(file);
1169 } else {
1170 fprintf(stderr, "Error, cannot read input file %s: %s\n",
1171 filename, strerror(errno));
1172 return false;
1173 }
1174 }
1175
1176 // Here is our autodetection
1177 int format;
1178 int r = (data != nullptr) ?
1179 findFileFormatBuffer(data, &format) :
1180 findFileFormat(filename, &format);
1181
1182 // Maybe we have a filelist
1183 if (r != 0 || format == IFF_UNKNOWN) {
1184 STRING s;
1185 if (data != nullptr) {
1186 s = buf.c_str();
1187 } else {
1188 std::ifstream t(filename);
1189 std::string u((std::istreambuf_iterator<char>(t)),
1190 std::istreambuf_iterator<char>());
1191 s = u.c_str();
1192 }
1193 return ProcessPagesFileList(nullptr, &s, retry_config,
1194 timeout_millisec, renderer,
1196 }
1197
1198 // Maybe we have a TIFF which is potentially multipage
1199 bool tiff = (format == IFF_TIFF || format == IFF_TIFF_PACKBITS ||
1200 format == IFF_TIFF_RLE || format == IFF_TIFF_G3 ||
1201 format == IFF_TIFF_G4 || format == IFF_TIFF_LZW ||
1202#if LIBLEPT_MAJOR_VERSION > 1 || LIBLEPT_MINOR_VERSION > 76
1203 format == IFF_TIFF_JPEG ||
1204#endif
1205 format == IFF_TIFF_ZIP);
1206
1207 // Fail early if we can, before producing any output
1208 Pix *pix = nullptr;
1209 if (!tiff) {
1210 pix = (data != nullptr) ? pixReadMem(data, buf.size()) : pixRead(filename);
1211 if (pix == nullptr) {
1212 return false;
1213 }
1214 }
1215
1216 // Begin the output
1217 if (renderer && !renderer->BeginDocument(document_title.c_str())) {
1218 pixDestroy(&pix);
1219 return false;
1220 }
1221
1222 // Produce output
1223 r = (tiff) ?
1224 ProcessPagesMultipageTiff(data, buf.size(), filename, retry_config,
1225 timeout_millisec, renderer,
1227 ProcessPage(pix, 0, filename, retry_config,
1228 timeout_millisec, renderer);
1229
1230 // Clean up memory as needed
1231 pixDestroy(&pix);
1232
1233 // End the output
1234 if (!r || (renderer && !renderer->EndDocument())) {
1235 return false;
1236 }
1237 return true;
1238}
1239
1240bool TessBaseAPI::ProcessPage(Pix* pix, int page_index, const char* filename,
1241 const char* retry_config, int timeout_millisec,
1242 TessResultRenderer* renderer) {
1243 SetInputName(filename);
1244 SetImage(pix);
1245 bool failed = false;
1246
1248 // Disabled character recognition
1250
1251 if (it == nullptr) {
1252 failed = true;
1253 } else {
1254 delete it;
1255 }
1257 failed = FindLines() != 0;
1258 } else if (timeout_millisec > 0) {
1259 // Running with a timeout.
1260 ETEXT_DESC monitor;
1261 monitor.cancel = nullptr;
1262 monitor.cancel_this = nullptr;
1263 monitor.set_deadline_msecs(timeout_millisec);
1264
1265 // Now run the main recognition.
1266 failed = Recognize(&monitor) < 0;
1267 } else {
1268 // Normal layout and character recognition with no timeout.
1269 failed = Recognize(nullptr) < 0;
1270 }
1271
1273#ifndef ANDROID_BUILD
1274 Pix* page_pix = GetThresholdedImage();
1275 pixWrite("tessinput.tif", page_pix, IFF_TIFF_G4);
1276#endif // ANDROID_BUILD
1277 }
1278
1279 if (failed && retry_config != nullptr && retry_config[0] != '\0') {
1280 // Save current config variables before switching modes.
1281 FILE* fp = fopen(kOldVarsFile, "wb");
1282 if (fp == nullptr) {
1283 tprintf("Error, failed to open file \"%s\"\n", kOldVarsFile);
1284 } else {
1285 PrintVariables(fp);
1286 fclose(fp);
1287 }
1288 // Switch to alternate mode for retry.
1289 ReadConfigFile(retry_config);
1290 SetImage(pix);
1291 Recognize(nullptr);
1292 // Restore saved config variables.
1293 ReadConfigFile(kOldVarsFile);
1294 }
1295
1296 if (renderer && !failed) {
1297 failed = !renderer->AddImage(this);
1298 }
1299
1300 return !failed;
1301}
1302
1307LTRResultIterator* TessBaseAPI::GetLTRIterator() {
1308 if (tesseract_ == nullptr || page_res_ == nullptr)
1309 return nullptr;
1310 return new LTRResultIterator(
1314}
1315
1324ResultIterator* TessBaseAPI::GetIterator() {
1325 if (tesseract_ == nullptr || page_res_ == nullptr)
1326 return nullptr;
1331}
1332
1341MutableIterator* TessBaseAPI::GetMutableIterator() {
1342 if (tesseract_ == nullptr || page_res_ == nullptr)
1343 return nullptr;
1348}
1349
1351char* TessBaseAPI::GetUTF8Text() {
1352 if (tesseract_ == nullptr ||
1353 (!recognition_done_ && Recognize(nullptr) < 0))
1354 return nullptr;
1355 STRING text("");
1357 do {
1358 if (it->Empty(RIL_PARA)) continue;
1359 const std::unique_ptr<const char[]> para_text(it->GetUTF8Text(RIL_PARA));
1360 text += para_text.get();
1361 } while (it->Next(RIL_PARA));
1362 char* result = new char[text.length() + 1];
1363 strncpy(result, text.string(), text.length() + 1);
1364 delete it;
1365 return result;
1366}
1367
1368static void AddBoxToTSV(const PageIterator* it, PageIteratorLevel level,
1369 STRING* text) {
1370 int left, top, right, bottom;
1371 it->BoundingBox(level, &left, &top, &right, &bottom);
1372 text->add_str_int("\t", left);
1373 text->add_str_int("\t", top);
1374 text->add_str_int("\t", right - left);
1375 text->add_str_int("\t", bottom - top);
1376}
1377
1383char* TessBaseAPI::GetTSVText(int page_number) {
1384 if (tesseract_ == nullptr || (page_res_ == nullptr && Recognize(nullptr) < 0))
1385 return nullptr;
1386
1387 int lcnt = 1, bcnt = 1, pcnt = 1, wcnt = 1;
1388 int page_id = page_number + 1; // we use 1-based page numbers.
1389
1390 STRING tsv_str("");
1391
1392 int page_num = page_id;
1393 int block_num = 0;
1394 int par_num = 0;
1395 int line_num = 0;
1396 int word_num = 0;
1397
1398 tsv_str.add_str_int("1\t", page_num); // level 1 - page
1399 tsv_str.add_str_int("\t", block_num);
1400 tsv_str.add_str_int("\t", par_num);
1401 tsv_str.add_str_int("\t", line_num);
1402 tsv_str.add_str_int("\t", word_num);
1403 tsv_str.add_str_int("\t", rect_left_);
1404 tsv_str.add_str_int("\t", rect_top_);
1405 tsv_str.add_str_int("\t", rect_width_);
1406 tsv_str.add_str_int("\t", rect_height_);
1407 tsv_str += "\t-1\t\n";
1408
1409 ResultIterator* res_it = GetIterator();
1410 while (!res_it->Empty(RIL_BLOCK)) {
1411 if (res_it->Empty(RIL_WORD)) {
1412 res_it->Next(RIL_WORD);
1413 continue;
1414 }
1415
1416 // Add rows for any new block/paragraph/textline.
1417 if (res_it->IsAtBeginningOf(RIL_BLOCK)) {
1418 block_num++;
1419 par_num = 0;
1420 line_num = 0;
1421 word_num = 0;
1422 tsv_str.add_str_int("2\t", page_num); // level 2 - block
1423 tsv_str.add_str_int("\t", block_num);
1424 tsv_str.add_str_int("\t", par_num);
1425 tsv_str.add_str_int("\t", line_num);
1426 tsv_str.add_str_int("\t", word_num);
1427 AddBoxToTSV(res_it, RIL_BLOCK, &tsv_str);
1428 tsv_str += "\t-1\t\n"; // end of row for block
1429 }
1430 if (res_it->IsAtBeginningOf(RIL_PARA)) {
1431 par_num++;
1432 line_num = 0;
1433 word_num = 0;
1434 tsv_str.add_str_int("3\t", page_num); // level 3 - paragraph
1435 tsv_str.add_str_int("\t", block_num);
1436 tsv_str.add_str_int("\t", par_num);
1437 tsv_str.add_str_int("\t", line_num);
1438 tsv_str.add_str_int("\t", word_num);
1439 AddBoxToTSV(res_it, RIL_PARA, &tsv_str);
1440 tsv_str += "\t-1\t\n"; // end of row for para
1441 }
1442 if (res_it->IsAtBeginningOf(RIL_TEXTLINE)) {
1443 line_num++;
1444 word_num = 0;
1445 tsv_str.add_str_int("4\t", page_num); // level 4 - line
1446 tsv_str.add_str_int("\t", block_num);
1447 tsv_str.add_str_int("\t", par_num);
1448 tsv_str.add_str_int("\t", line_num);
1449 tsv_str.add_str_int("\t", word_num);
1450 AddBoxToTSV(res_it, RIL_TEXTLINE, &tsv_str);
1451 tsv_str += "\t-1\t\n"; // end of row for line
1452 }
1453
1454 // Now, process the word...
1455 int left, top, right, bottom;
1456 res_it->BoundingBox(RIL_WORD, &left, &top, &right, &bottom);
1457 word_num++;
1458 tsv_str.add_str_int("5\t", page_num); // level 5 - word
1459 tsv_str.add_str_int("\t", block_num);
1460 tsv_str.add_str_int("\t", par_num);
1461 tsv_str.add_str_int("\t", line_num);
1462 tsv_str.add_str_int("\t", word_num);
1463 tsv_str.add_str_int("\t", left);
1464 tsv_str.add_str_int("\t", top);
1465 tsv_str.add_str_int("\t", right - left);
1466 tsv_str.add_str_int("\t", bottom - top);
1467 tsv_str.add_str_int("\t", res_it->Confidence(RIL_WORD));
1468 tsv_str += "\t";
1469
1470 // Increment counts if at end of block/paragraph/textline.
1471 if (res_it->IsAtFinalElement(RIL_TEXTLINE, RIL_WORD)) lcnt++;
1472 if (res_it->IsAtFinalElement(RIL_PARA, RIL_WORD)) pcnt++;
1473 if (res_it->IsAtFinalElement(RIL_BLOCK, RIL_WORD)) bcnt++;
1474
1475 do {
1476 tsv_str +=
1477 std::unique_ptr<const char[]>(res_it->GetUTF8Text(RIL_SYMBOL)).get();
1478 res_it->Next(RIL_SYMBOL);
1479 } while (!res_it->Empty(RIL_BLOCK) && !res_it->IsAtBeginningOf(RIL_WORD));
1480 tsv_str += "\n"; // end of row
1481 wcnt++;
1482 }
1483
1484 char* ret = new char[tsv_str.length() + 1];
1485 strcpy(ret, tsv_str.string());
1486 delete res_it;
1487 return ret;
1488}
1489
1491const int kNumbersPerBlob = 5;
1496const int kBytesPerNumber = 5;
1513
1520char* TessBaseAPI::GetBoxText(int page_number) {
1521 if (tesseract_ == nullptr ||
1522 (!recognition_done_ && Recognize(nullptr) < 0))
1523 return nullptr;
1524 int blob_count;
1525 int utf8_length = TextLength(&blob_count);
1526 int total_length = blob_count * kBytesPerBoxFileLine + utf8_length +
1528 char* result = new char[total_length];
1529 result[0] = '\0';
1530 int output_length = 0;
1532 do {
1533 int left, top, right, bottom;
1534 if (it->BoundingBox(RIL_SYMBOL, &left, &top, &right, &bottom)) {
1535 const std::unique_ptr</*non-const*/ char[]> text(
1536 it->GetUTF8Text(RIL_SYMBOL));
1537 // Tesseract uses space for recognition failure. Fix to a reject
1538 // character, kTesseractReject so we don't create illegal box files.
1539 for (int i = 0; text[i] != '\0'; ++i) {
1540 if (text[i] == ' ')
1541 text[i] = kTesseractReject;
1542 }
1543 snprintf(result + output_length, total_length - output_length,
1544 "%s %d %d %d %d %d\n", text.get(), left, image_height_ - bottom,
1545 right, image_height_ - top, page_number);
1546 output_length += strlen(result + output_length);
1547 // Just in case...
1548 if (output_length + kMaxBytesPerLine > total_length)
1549 break;
1550 }
1551 } while (it->Next(RIL_SYMBOL));
1552 delete it;
1553 return result;
1554}
1555
1561const int kUniChs[] = {
1562 0x20ac, 0x201c, 0x201d, 0x2018, 0x2019, 0x2022, 0x2014, 0
1563};
1565const int kLatinChs[] = {
1566 0x00a2, 0x0022, 0x0022, 0x0027, 0x0027, 0x00b7, 0x002d, 0
1567};
1568
1574char* TessBaseAPI::GetUNLVText() {
1575 if (tesseract_ == nullptr ||
1576 (!recognition_done_ && Recognize(nullptr) < 0))
1577 return nullptr;
1578 bool tilde_crunch_written = false;
1579 bool last_char_was_newline = true;
1580 bool last_char_was_tilde = false;
1581
1582 int total_length = TextLength(nullptr);
1583 PAGE_RES_IT page_res_it(page_res_);
1584 char* result = new char[total_length];
1585 char* ptr = result;
1586 for (page_res_it.restart_page(); page_res_it.word () != nullptr;
1587 page_res_it.forward()) {
1588 WERD_RES *word = page_res_it.word();
1589 // Process the current word.
1590 if (word->unlv_crunch_mode != CR_NONE) {
1591 if (word->unlv_crunch_mode != CR_DELETE &&
1592 (!tilde_crunch_written ||
1593 (word->unlv_crunch_mode == CR_KEEP_SPACE &&
1594 word->word->space() > 0 &&
1595 !word->word->flag(W_FUZZY_NON) &&
1596 !word->word->flag(W_FUZZY_SP)))) {
1597 if (!word->word->flag(W_BOL) &&
1598 word->word->space() > 0 &&
1599 !word->word->flag(W_FUZZY_NON) &&
1600 !word->word->flag(W_FUZZY_SP)) {
1601 /* Write a space to separate from preceding good text */
1602 *ptr++ = ' ';
1603 last_char_was_tilde = false;
1604 }
1605 if (!last_char_was_tilde) {
1606 // Write a reject char.
1607 last_char_was_tilde = true;
1608 *ptr++ = kUNLVReject;
1609 tilde_crunch_written = true;
1610 last_char_was_newline = false;
1611 }
1612 }
1613 } else {
1614 // NORMAL PROCESSING of non tilde crunched words.
1615 tilde_crunch_written = false;
1617 const char* wordstr = word->best_choice->unichar_string().string();
1618 const STRING& lengths = word->best_choice->unichar_lengths();
1619 int length = lengths.length();
1620 int i = 0;
1621 int offset = 0;
1622
1623 if (last_char_was_tilde &&
1624 word->word->space() == 0 && wordstr[offset] == ' ') {
1625 // Prevent adjacent tilde across words - we know that adjacent tildes
1626 // within words have been removed.
1627 // Skip the first character.
1628 offset = lengths[i++];
1629 }
1630 if (i < length && wordstr[offset] != 0) {
1631 if (!last_char_was_newline)
1632 *ptr++ = ' ';
1633 else
1634 last_char_was_newline = false;
1635 for (; i < length; offset += lengths[i++]) {
1636 if (wordstr[offset] == ' ' ||
1637 wordstr[offset] == kTesseractReject) {
1638 *ptr++ = kUNLVReject;
1639 last_char_was_tilde = true;
1640 } else {
1641 if (word->reject_map[i].rejected())
1642 *ptr++ = kUNLVSuspect;
1643 UNICHAR ch(wordstr + offset, lengths[i]);
1644 int uni_ch = ch.first_uni();
1645 for (int j = 0; kUniChs[j] != 0; ++j) {
1646 if (kUniChs[j] == uni_ch) {
1647 uni_ch = kLatinChs[j];
1648 break;
1649 }
1650 }
1651 if (uni_ch <= 0xff) {
1652 *ptr++ = static_cast<char>(uni_ch);
1653 last_char_was_tilde = false;
1654 } else {
1655 *ptr++ = kUNLVReject;
1656 last_char_was_tilde = true;
1657 }
1658 }
1659 }
1660 }
1661 }
1662 if (word->word->flag(W_EOL) && !last_char_was_newline) {
1663 /* Add a new line output */
1664 *ptr++ = '\n';
1665 tilde_crunch_written = false;
1666 last_char_was_newline = true;
1667 last_char_was_tilde = false;
1668 }
1669 }
1670 *ptr++ = '\n';
1671 *ptr = '\0';
1672 return result;
1673}
1674
1675#ifndef DISABLED_LEGACY_ENGINE
1676
1686bool TessBaseAPI::DetectOrientationScript(int* orient_deg, float* orient_conf,
1687 const char** script_name,
1688 float* script_conf) {
1689 OSResults osr;
1690
1691 bool osd = DetectOS(&osr);
1692 if (!osd) {
1693 return false;
1694 }
1695
1696 int orient_id = osr.best_result.orientation_id;
1697 int script_id = osr.get_best_script(orient_id);
1698 if (orient_conf) *orient_conf = osr.best_result.oconfidence;
1699 if (orient_deg) *orient_deg = orient_id * 90; // convert quadrant to degrees
1700
1701 if (script_name) {
1702 const char* script = osr.unicharset->get_script_from_script_id(script_id);
1703
1704 *script_name = script;
1705 }
1706
1707 if (script_conf) *script_conf = osr.best_result.sconfidence;
1708
1709 return true;
1710}
1711
1717char* TessBaseAPI::GetOsdText(int page_number) {
1718 int orient_deg;
1719 float orient_conf;
1720 const char* script_name;
1721 float script_conf;
1722
1723 if (!DetectOrientationScript(&orient_deg, &orient_conf, &script_name,
1724 &script_conf))
1725 return nullptr;
1726
1727 // clockwise rotation needed to make the page upright
1728 int rotate = OrientationIdToValue(orient_deg / 90);
1729
1730 std::stringstream stream;
1731 // Use "C" locale (needed for float values orient_conf and script_conf).
1732 stream.imbue(std::locale::classic());
1733 // Use fixed notation with 2 digits after the decimal point for float values.
1734 stream.precision(2);
1735 stream
1736 << std::fixed
1737 << "Page number: " << page_number << "\n"
1738 << "Orientation in degrees: " << orient_deg << "\n"
1739 << "Rotate: " << rotate << "\n"
1740 << "Orientation confidence: " << orient_conf << "\n"
1741 << "Script: " << script_name << "\n"
1742 << "Script confidence: " << script_conf << "\n";
1743 const std::string& text = stream.str();
1744 char* result = new char[text.length() + 1];
1745 strcpy(result, text.c_str());
1746 return result;
1747}
1748
1749#endif // ndef DISABLED_LEGACY_ENGINE
1750
1752int TessBaseAPI::MeanTextConf() {
1753 int* conf = AllWordConfidences();
1754 if (!conf) return 0;
1755 int sum = 0;
1756 int *pt = conf;
1757 while (*pt >= 0) sum += *pt++;
1758 if (pt != conf) sum /= pt - conf;
1759 delete [] conf;
1760 return sum;
1761}
1762
1764int* TessBaseAPI::AllWordConfidences() {
1765 if (tesseract_ == nullptr ||
1766 (!recognition_done_ && Recognize(nullptr) < 0))
1767 return nullptr;
1768 int n_word = 0;
1769 PAGE_RES_IT res_it(page_res_);
1770 for (res_it.restart_page(); res_it.word() != nullptr; res_it.forward())
1771 n_word++;
1772
1773 int* conf = new int[n_word+1];
1774 n_word = 0;
1775 for (res_it.restart_page(); res_it.word() != nullptr; res_it.forward()) {
1776 WERD_RES *word = res_it.word();
1777 WERD_CHOICE* choice = word->best_choice;
1778 int w_conf = static_cast<int>(100 + 5 * choice->certainty());
1779 // This is the eq for converting Tesseract confidence to 1..100
1780 if (w_conf < 0) w_conf = 0;
1781 if (w_conf > 100) w_conf = 100;
1782 conf[n_word++] = w_conf;
1783 }
1784 conf[n_word] = -1;
1785 return conf;
1786}
1787
1788#ifndef DISABLED_LEGACY_ENGINE
1799bool TessBaseAPI::AdaptToWordStr(PageSegMode mode, const char* wordstr) {
1800 int debug = 0;
1801 GetIntVariable("applybox_debug", &debug);
1802 bool success = true;
1803 PageSegMode current_psm = GetPageSegMode();
1804 SetPageSegMode(mode);
1805 SetVariable("classify_enable_learning", "0");
1806 const std::unique_ptr<const char[]> text(GetUTF8Text());
1807 if (debug) {
1808 tprintf("Trying to adapt \"%s\" to \"%s\"\n", text.get(), wordstr);
1809 }
1810 if (text != nullptr) {
1812 WERD_RES* word_res = it.word();
1813 if (word_res != nullptr) {
1814 word_res->word->set_text(wordstr);
1815 // Check to see if text matches wordstr.
1816 int w = 0;
1817 int t;
1818 for (t = 0; text[t] != '\0'; ++t) {
1819 if (text[t] == '\n' || text[t] == ' ')
1820 continue;
1821 while (wordstr[w] == ' ') ++w;
1822 if (text[t] != wordstr[w])
1823 break;
1824 ++w;
1825 }
1826 if (text[t] != '\0' || wordstr[w] != '\0') {
1827 // No match.
1828 delete page_res_;
1829 GenericVector<TBOX> boxes;
1833 PAGE_RES_IT pr_it(page_res_);
1834 if (pr_it.word() == nullptr)
1835 success = false;
1836 else
1837 word_res = pr_it.word();
1838 } else {
1839 word_res->BestChoiceToCorrectText();
1840 }
1841 if (success) {
1842 tesseract_->EnableLearning = true;
1843 tesseract_->LearnWord(nullptr, word_res);
1844 }
1845 } else {
1846 success = false;
1847 }
1848 } else {
1849 success = false;
1850 }
1851 SetPageSegMode(current_psm);
1852 return success;
1853}
1854#endif // ndef DISABLED_LEGACY_ENGINE
1855
1862void TessBaseAPI::Clear() {
1863 if (thresholder_ != nullptr)
1865 ClearResults();
1866 if (tesseract_ != nullptr) SetInputImage(nullptr);
1867}
1868
1875void TessBaseAPI::End() {
1876 Clear();
1877 delete thresholder_;
1878 thresholder_ = nullptr;
1879 delete page_res_;
1880 page_res_ = nullptr;
1881 delete block_list_;
1882 block_list_ = nullptr;
1883 if (paragraph_models_ != nullptr) {
1885 delete paragraph_models_;
1886 paragraph_models_ = nullptr;
1887 }
1888 if (osd_tesseract_ == tesseract_) osd_tesseract_ = nullptr;
1889 delete tesseract_;
1890 tesseract_ = nullptr;
1891 delete osd_tesseract_;
1892 osd_tesseract_ = nullptr;
1893 delete equ_detect_;
1894 equ_detect_ = nullptr;
1895 delete input_file_;
1896 input_file_ = nullptr;
1897 delete output_file_;
1898 output_file_ = nullptr;
1899 delete datapath_;
1900 datapath_ = nullptr;
1901 delete language_;
1902 language_ = nullptr;
1903}
1904
1905// Clear any library-level memory caches.
1906// There are a variety of expensive-to-load constant data structures (mostly
1907// language dictionaries) that are cached globally -- surviving the Init()
1908// and End() of individual TessBaseAPI's. This function allows the clearing
1909// of these caches.
1910void TessBaseAPI::ClearPersistentCache() {
1912}
1913
1918int TessBaseAPI::IsValidWord(const char *word) {
1919 return tesseract_->getDict().valid_word(word);
1920}
1921// Returns true if utf8_character is defined in the UniCharset.
1922bool TessBaseAPI::IsValidCharacter(const char *utf8_character) {
1923 return tesseract_->unicharset.contains_unichar(utf8_character);
1924}
1925
1926
1927// TODO(rays) Obsolete this function and replace with a more aptly named
1928// function that returns image coordinates rather than tesseract coordinates.
1929bool TessBaseAPI::GetTextDirection(int* out_offset, float* out_slope) {
1931 if (it == nullptr) {
1932 return false;
1933 }
1934 int x1, x2, y1, y2;
1935 it->Baseline(RIL_TEXTLINE, &x1, &y1, &x2, &y2);
1936 // Calculate offset and slope (NOTE: Kind of ugly)
1937 if (x2 <= x1) x2 = x1 + 1;
1938 // Convert the point pair to slope/offset of the baseline (in image coords.)
1939 *out_slope = static_cast<float>(y2 - y1) / (x2 - x1);
1940 *out_offset = static_cast<int>(y1 - *out_slope * x1);
1941 // Get the y-coord of the baseline at the left and right edges of the
1942 // textline's bounding box.
1943 int left, top, right, bottom;
1944 if (!it->BoundingBox(RIL_TEXTLINE, &left, &top, &right, &bottom)) {
1945 delete it;
1946 return false;
1947 }
1948 int left_y = IntCastRounded(*out_slope * left + *out_offset);
1949 int right_y = IntCastRounded(*out_slope * right + *out_offset);
1950 // Shift the baseline down so it passes through the nearest bottom-corner
1951 // of the textline's bounding box. This is the difference between the y
1952 // at the lowest (max) edge of the box and the actual box bottom.
1953 *out_offset += bottom - std::max(left_y, right_y);
1954 // Switch back to bottom-up tesseract coordinates. Requires negation of
1955 // the slope and height - offset for the offset.
1956 *out_slope = -*out_slope;
1957 *out_offset = rect_height_ - *out_offset;
1958 delete it;
1959
1960 return true;
1961}
1962
1964void TessBaseAPI::SetDictFunc(DictFunc f) {
1965 if (tesseract_ != nullptr) {
1967 }
1968}
1969
1978void TessBaseAPI::SetProbabilityInContextFunc(ProbabilityInContextFunc f) {
1979 if (tesseract_ != nullptr) {
1981 // Set it for the sublangs too.
1982 int num_subs = tesseract_->num_sub_langs();
1983 for (int i = 0; i < num_subs; ++i) {
1985 }
1986 }
1987}
1988
1989#ifndef DISABLED_LEGACY_ENGINE
1991void TessBaseAPI::SetFillLatticeFunc(FillLatticeFunc f) {
1992 if (tesseract_ != nullptr) tesseract_->fill_lattice_ = f;
1993}
1994#endif // ndef DISABLED_LEGACY_ENGINE
1995
1997bool TessBaseAPI::InternalSetImage() {
1998 if (tesseract_ == nullptr) {
1999 tprintf("Please call Init before attempting to set an image.\n");
2000 return false;
2001 }
2002 if (thresholder_ == nullptr)
2004 ClearResults();
2005 return true;
2006}
2007
2014bool TessBaseAPI::Threshold(Pix** pix) {
2015 ASSERT_HOST(pix != nullptr);
2016 if (*pix != nullptr)
2017 pixDestroy(pix);
2018 // Zero resolution messes up the algorithms, so make sure it is credible.
2019 int user_dpi = 0;
2020 GetIntVariable("user_defined_dpi", &user_dpi);
2021 int y_res = thresholder_->GetScaledYResolution();
2022 if (user_dpi && (user_dpi < kMinCredibleResolution ||
2023 user_dpi > kMaxCredibleResolution)) {
2024 tprintf("Warning: User defined image dpi is outside of expected range "
2025 "(%d - %d)!\n",
2027 }
2028 // Always use user defined dpi
2029 if (user_dpi) {
2031 } else if (y_res < kMinCredibleResolution ||
2032 y_res > kMaxCredibleResolution) {
2033 tprintf("Warning: Invalid resolution %d dpi. Using %d instead.\n",
2034 y_res, kMinCredibleResolution);
2036 }
2037 auto pageseg_mode =
2038 static_cast<PageSegMode>(
2039 static_cast<int>(tesseract_->tessedit_pageseg_mode));
2040 if (!thresholder_->ThresholdToPix(pageseg_mode, pix)) return false;
2044 if (!thresholder_->IsBinary()) {
2047 } else {
2049 tesseract_->set_pix_grey(nullptr);
2050 }
2051 // Set the internal resolution that is used for layout parameters from the
2052 // estimated resolution, rather than the image resolution, which may be
2053 // fabricated, but we will use the image resolution, if there is one, to
2054 // report output point sizes.
2058 if (estimated_res != thresholder_->GetScaledEstimatedResolution()) {
2059 tprintf("Estimated internal resolution %d out of range! "
2060 "Corrected to %d.\n",
2061 thresholder_->GetScaledEstimatedResolution(), estimated_res);
2062 }
2063 tesseract_->set_source_resolution(estimated_res);
2064 return true;
2065}
2066
2068int TessBaseAPI::FindLines() {
2069 if (thresholder_ == nullptr || thresholder_->IsEmpty()) {
2070 tprintf("Please call SetImage before attempting recognition.\n");
2071 return -1;
2072 }
2074 ClearResults();
2075 if (!block_list_->empty()) {
2076 return 0;
2077 }
2078 if (tesseract_ == nullptr) {
2079 tesseract_ = new Tesseract;
2080 #ifndef DISABLED_LEGACY_ENGINE
2082 #endif
2083 }
2084 if (tesseract_->pix_binary() == nullptr &&
2086 return -1;
2087 }
2088
2090
2091#ifndef DISABLED_LEGACY_ENGINE
2093 if (equ_detect_ == nullptr && datapath_ != nullptr) {
2094 equ_detect_ = new EquationDetect(datapath_->string(), nullptr);
2095 }
2096 if (equ_detect_ == nullptr) {
2097 tprintf("Warning: Could not set equation detector\n");
2098 } else {
2100 }
2101 }
2102#endif // ndef DISABLED_LEGACY_ENGINE
2103
2104 Tesseract* osd_tess = osd_tesseract_;
2105 OSResults osr;
2107 osd_tess == nullptr) {
2108 if (strcmp(language_->string(), "osd") == 0) {
2109 osd_tess = tesseract_;
2110 } else {
2113 if (datapath_ == nullptr) {
2114 tprintf("Warning: Auto orientation and script detection requested,"
2115 " but data path is undefined\n");
2116 delete osd_tesseract_;
2117 osd_tesseract_ = nullptr;
2118 } else if (osd_tesseract_->init_tesseract(datapath_->string(), nullptr,
2119 "osd", OEM_TESSERACT_ONLY,
2120 nullptr, 0, nullptr, nullptr,
2121 false, &mgr) == 0) {
2122 osd_tess = osd_tesseract_;
2125 } else {
2126 tprintf("Warning: Auto orientation and script detection requested,"
2127 " but osd language failed to load\n");
2128 delete osd_tesseract_;
2129 osd_tesseract_ = nullptr;
2130 }
2131 }
2132 }
2133
2134 if (tesseract_->SegmentPage(input_file_, block_list_, osd_tess, &osr) < 0)
2135 return -1;
2136
2137 // If Devanagari is being recognized, we use different images for page seg
2138 // and for OCR.
2139 tesseract_->PrepareForTessOCR(block_list_, osd_tess, &osr);
2140 return 0;
2141}
2142
2144void TessBaseAPI::ClearResults() {
2145 if (tesseract_ != nullptr) {
2146 tesseract_->Clear();
2147 }
2148 delete page_res_;
2149 page_res_ = nullptr;
2150 recognition_done_ = false;
2151 if (block_list_ == nullptr)
2152 block_list_ = new BLOCK_LIST;
2153 else
2154 block_list_->clear();
2155 if (paragraph_models_ != nullptr) {
2157 delete paragraph_models_;
2158 paragraph_models_ = nullptr;
2159 }
2160}
2161
2169int TessBaseAPI::TextLength(int* blob_count) {
2170 if (tesseract_ == nullptr || page_res_ == nullptr)
2171 return 0;
2172
2173 PAGE_RES_IT page_res_it(page_res_);
2174 int total_length = 2;
2175 int total_blobs = 0;
2176 // Iterate over the data structures to extract the recognition result.
2177 for (page_res_it.restart_page(); page_res_it.word () != nullptr;
2178 page_res_it.forward()) {
2179 WERD_RES *word = page_res_it.word();
2180 WERD_CHOICE* choice = word->best_choice;
2181 if (choice != nullptr) {
2182 total_blobs += choice->length() + 2;
2183 total_length += choice->unichar_string().length() + 2;
2184 for (int i = 0; i < word->reject_map.length(); ++i) {
2185 if (word->reject_map[i].rejected())
2186 ++total_length;
2187 }
2188 }
2189 }
2190 if (blob_count != nullptr)
2191 *blob_count = total_blobs;
2192 return total_length;
2193}
2194
2195#ifndef DISABLED_LEGACY_ENGINE
2200bool TessBaseAPI::DetectOS(OSResults* osr) {
2201 if (tesseract_ == nullptr)
2202 return false;
2203 ClearResults();
2204 if (tesseract_->pix_binary() == nullptr &&
2206 return false;
2207 }
2208
2209 if (input_file_ == nullptr)
2210 input_file_ = new STRING(kInputFile);
2212}
2213#endif // ndef DISABLED_LEGACY_ENGINE
2214
2215void TessBaseAPI::set_min_orientation_margin(double margin) {
2216 tesseract_->min_orientation_margin.set_value(margin);
2217}
2218
2233void TessBaseAPI::GetBlockTextOrientations(int** block_orientation,
2234 bool** vertical_writing) {
2235 delete[] *block_orientation;
2236 *block_orientation = nullptr;
2237 delete[] *vertical_writing;
2238 *vertical_writing = nullptr;
2239 BLOCK_IT block_it(block_list_);
2240
2241 block_it.move_to_first();
2242 int num_blocks = 0;
2243 for (block_it.mark_cycle_pt(); !block_it.cycled_list(); block_it.forward()) {
2244 if (!block_it.data()->pdblk.poly_block()->IsText()) {
2245 continue;
2246 }
2247 ++num_blocks;
2248 }
2249 if (!num_blocks) {
2250 tprintf("WARNING: Found no blocks\n");
2251 return;
2252 }
2253 *block_orientation = new int[num_blocks];
2254 *vertical_writing = new bool[num_blocks];
2255 block_it.move_to_first();
2256 int i = 0;
2257 for (block_it.mark_cycle_pt(); !block_it.cycled_list();
2258 block_it.forward()) {
2259 if (!block_it.data()->pdblk.poly_block()->IsText()) {
2260 continue;
2261 }
2262 FCOORD re_rotation = block_it.data()->re_rotation();
2263 float re_theta = re_rotation.angle();
2264 FCOORD classify_rotation = block_it.data()->classify_rotation();
2265 float classify_theta = classify_rotation.angle();
2266 double rot_theta = - (re_theta - classify_theta) * 2.0 / M_PI;
2267 if (rot_theta < 0) rot_theta += 4;
2268 int num_rotations = static_cast<int>(rot_theta + 0.5);
2269 (*block_orientation)[i] = num_rotations;
2270 // The classify_rotation is non-zero only if the text has vertical
2271 // writing direction.
2272 (*vertical_writing)[i] = classify_rotation.y() != 0.0f;
2273 ++i;
2274 }
2275}
2276
2277
2278void TessBaseAPI::DetectParagraphs(bool after_text_recognition) {
2279 int debug_level = 0;
2280 GetIntVariable("paragraph_debug_level", &debug_level);
2281 if (paragraph_models_ == nullptr)
2283 MutableIterator *result_it = GetMutableIterator();
2284 do { // Detect paragraphs for this block
2286 ::tesseract::DetectParagraphs(debug_level, after_text_recognition,
2287 result_it, &models);
2288 *paragraph_models_ += models;
2289 } while (result_it->Next(RIL_BLOCK));
2290 delete result_it;
2291}
2292
2294const char* TessBaseAPI::GetUnichar(int unichar_id) {
2295 return tesseract_->unicharset.id_to_unichar(unichar_id);
2296}
2297
2299const Dawg *TessBaseAPI::GetDawg(int i) const {
2300 if (tesseract_ == nullptr || i >= NumDawgs()) return nullptr;
2301 return tesseract_->getDict().GetDawg(i);
2302}
2303
2305int TessBaseAPI::NumDawgs() const {
2306 return tesseract_ == nullptr ? 0 : tesseract_->getDict().NumDawgs();
2307}
2308
2310STRING HOcrEscape(const char* text) {
2311 STRING ret;
2312 const char *ptr;
2313 for (ptr = text; *ptr; ptr++) {
2314 switch (*ptr) {
2315 case '<': ret += "&lt;"; break;
2316 case '>': ret += "&gt;"; break;
2317 case '&': ret += "&amp;"; break;
2318 case '"': ret += "&quot;"; break;
2319 case '\'': ret += "&#39;"; break;
2320 default: ret += *ptr;
2321 }
2322 }
2323 return ret;
2324}
2325
2326
2327#ifndef DISABLED_LEGACY_ENGINE
2328
2329
2330// ____________________________________________________________________________
2331// Ocropus add-ons.
2332
2334BLOCK_LIST* TessBaseAPI::FindLinesCreateBlockList() {
2335 ASSERT_HOST(FindLines() == 0);
2336 BLOCK_LIST* result = block_list_;
2337 block_list_ = nullptr;
2338 return result;
2339}
2340
2346void TessBaseAPI::DeleteBlockList(BLOCK_LIST *block_list) {
2347 delete block_list;
2348}
2349
2350
2351ROW *TessBaseAPI::MakeTessOCRRow(float baseline,
2352 float xheight,
2353 float descender,
2354 float ascender) {
2355 int32_t xstarts[] = {-32000};
2356 double quad_coeffs[] = {0, 0, baseline};
2357 return new ROW(1,
2358 xstarts,
2359 quad_coeffs,
2360 xheight,
2361 ascender - (baseline + xheight),
2362 descender - baseline,
2363 0,
2364 0);
2365}
2366
2368TBLOB *TessBaseAPI::MakeTBLOB(Pix *pix) {
2369 int width = pixGetWidth(pix);
2370 int height = pixGetHeight(pix);
2371 BLOCK block("a character", true, 0, 0, 0, 0, width, height);
2372
2373 // Create C_BLOBs from the page
2374 extract_edges(pix, &block);
2375
2376 // Merge all C_BLOBs
2377 C_BLOB_LIST *list = block.blob_list();
2378 C_BLOB_IT c_blob_it(list);
2379 if (c_blob_it.empty())
2380 return nullptr;
2381 // Move all the outlines to the first blob.
2382 C_OUTLINE_IT ol_it(c_blob_it.data()->out_list());
2383 for (c_blob_it.forward();
2384 !c_blob_it.at_first();
2385 c_blob_it.forward()) {
2386 C_BLOB *c_blob = c_blob_it.data();
2387 ol_it.add_list_after(c_blob->out_list());
2388 }
2389 // Convert the first blob to the output TBLOB.
2390 return TBLOB::PolygonalCopy(false, c_blob_it.data());
2391}
2392
2398void TessBaseAPI::NormalizeTBLOB(TBLOB *tblob, ROW *row, bool numeric_mode) {
2399 TBOX box = tblob->bounding_box();
2400 float x_center = (box.left() + box.right()) / 2.0f;
2401 float baseline = row->base_line(x_center);
2402 float scale = kBlnXHeight / row->x_height();
2403 tblob->Normalize(nullptr, nullptr, nullptr, x_center, baseline, scale, scale,
2404 0.0f, static_cast<float>(kBlnBaselineOffset), false, nullptr);
2405}
2406
2411static TBLOB *make_tesseract_blob(float baseline, float xheight,
2412 float descender, float ascender,
2413 bool numeric_mode, Pix* pix) {
2414 TBLOB *tblob = TessBaseAPI::MakeTBLOB(pix);
2415
2416 // Normalize TBLOB
2417 ROW *row =
2418 TessBaseAPI::MakeTessOCRRow(baseline, xheight, descender, ascender);
2419 TessBaseAPI::NormalizeTBLOB(tblob, row, numeric_mode);
2420 delete row;
2421 return tblob;
2422}
2423
2429void TessBaseAPI::AdaptToCharacter(const char *unichar_repr,
2430 int length,
2431 float baseline,
2432 float xheight,
2433 float descender,
2434 float ascender) {
2435 UNICHAR_ID id = tesseract_->unicharset.unichar_to_id(unichar_repr, length);
2436 TBLOB *blob = make_tesseract_blob(baseline, xheight, descender, ascender,
2439 float threshold;
2440 float best_rating = -100;
2441
2442
2443 // Classify to get a raw choice.
2444 BLOB_CHOICE_LIST choices;
2445 tesseract_->AdaptiveClassifier(blob, &choices);
2446 BLOB_CHOICE_IT choice_it;
2447 choice_it.set_to_list(&choices);
2448 for (choice_it.mark_cycle_pt(); !choice_it.cycled_list();
2449 choice_it.forward()) {
2450 if (choice_it.data()->rating() > best_rating) {
2451 best_rating = choice_it.data()->rating();
2452 }
2453 }
2454
2456
2457 if (blob->outlines)
2458 tesseract_->AdaptToChar(blob, id, kUnknownFontinfoId, threshold,
2460 delete blob;
2461}
2462
2463
2464PAGE_RES* TessBaseAPI::RecognitionPass1(BLOCK_LIST* block_list) {
2465 auto *page_res = new PAGE_RES(false, block_list,
2467 tesseract_->recog_all_words(page_res, nullptr, nullptr, nullptr, 1);
2468 return page_res;
2469}
2470
2471PAGE_RES* TessBaseAPI::RecognitionPass2(BLOCK_LIST* block_list,
2472 PAGE_RES* pass1_result) {
2473 if (!pass1_result)
2474 pass1_result = new PAGE_RES(false, block_list,
2476 tesseract_->recog_all_words(pass1_result, nullptr, nullptr, nullptr, 2);
2477 return pass1_result;
2478}
2479
2482 int length; // of unicode_repr
2483 float cost;
2485
2486 TESS_CHAR(float _cost, const char *repr, int len = -1) : cost(_cost) {
2487 length = (len == -1 ? strlen(repr) : len);
2488 unicode_repr = new char[length + 1];
2489 strncpy(unicode_repr, repr, length);
2490 }
2491
2493 : unicode_repr(nullptr),
2494 length(0),
2495 cost(0.0f)
2496 { // Satisfies ELISTIZE.
2497 }
2499 delete [] unicode_repr;
2500 }
2501};
2502
2503ELISTIZEH(TESS_CHAR)
2504ELISTIZE(TESS_CHAR)
2505
2506static void add_space(TESS_CHAR_IT* it) {
2507 auto *t = new TESS_CHAR(0, " ");
2508 it->add_after_then_move(t);
2509}
2510
2511
2512static float rating_to_cost(float rating) {
2513 rating = 100 + rating;
2514 // cuddled that to save from coverage profiler
2515 // (I have never seen ratings worse than -100,
2516 // but the check won't hurt)
2517 if (rating < 0) rating = 0;
2518 return rating;
2519}
2520
2525static void extract_result(TESS_CHAR_IT* out,
2526 PAGE_RES* page_res) {
2527 PAGE_RES_IT page_res_it(page_res);
2528 int word_count = 0;
2529 while (page_res_it.word() != nullptr) {
2530 WERD_RES *word = page_res_it.word();
2531 const char *str = word->best_choice->unichar_string().string();
2532 const char *len = word->best_choice->unichar_lengths().string();
2533 TBOX real_rect = word->word->bounding_box();
2534
2535 if (word_count)
2536 add_space(out);
2537 int n = strlen(len);
2538 for (int i = 0; i < n; i++) {
2539 auto *tc = new TESS_CHAR(rating_to_cost(word->best_choice->rating()),
2540 str, *len);
2541 tc->box = real_rect.intersection(word->box_word->BlobBox(i));
2542 out->add_after_then_move(tc);
2543 str += *len;
2544 len++;
2545 }
2546 page_res_it.forward();
2547 word_count++;
2548 }
2549}
2550
2555int TessBaseAPI::TesseractExtractResult(char** text,
2556 int** lengths,
2557 float** costs,
2558 int** x0,
2559 int** y0,
2560 int** x1,
2561 int** y1,
2562 PAGE_RES* page_res) {
2563 TESS_CHAR_LIST tess_chars;
2564 TESS_CHAR_IT tess_chars_it(&tess_chars);
2565 extract_result(&tess_chars_it, page_res);
2566 tess_chars_it.move_to_first();
2567 int n = tess_chars.length();
2568 int text_len = 0;
2569 *lengths = new int[n];
2570 *costs = new float[n];
2571 *x0 = new int[n];
2572 *y0 = new int[n];
2573 *x1 = new int[n];
2574 *y1 = new int[n];
2575 int i = 0;
2576 for (tess_chars_it.mark_cycle_pt();
2577 !tess_chars_it.cycled_list();
2578 tess_chars_it.forward(), i++) {
2579 TESS_CHAR *tc = tess_chars_it.data();
2580 text_len += (*lengths)[i] = tc->length;
2581 (*costs)[i] = tc->cost;
2582 (*x0)[i] = tc->box.left();
2583 (*y0)[i] = tc->box.bottom();
2584 (*x1)[i] = tc->box.right();
2585 (*y1)[i] = tc->box.top();
2586 }
2587 char *p = *text = new char[text_len];
2588
2589 tess_chars_it.move_to_first();
2590 for (tess_chars_it.mark_cycle_pt();
2591 !tess_chars_it.cycled_list();
2592 tess_chars_it.forward()) {
2593 TESS_CHAR *tc = tess_chars_it.data();
2594 strncpy(p, tc->unicode_repr, tc->length);
2595 p += tc->length;
2596 }
2597 return n;
2598}
2599
2601// The resulting features are returned in int_features, which must be
2602// of size MAX_NUM_INT_FEATURES. The number of features is returned in
2603// num_features (or 0 if there was a failure).
2604// On return feature_outline_index is filled with an index of the outline
2605// corresponding to each feature in int_features.
2606// TODO(rays) Fix the caller to out outline_counts instead.
2607void TessBaseAPI::GetFeaturesForBlob(TBLOB* blob,
2608 INT_FEATURE_STRUCT* int_features,
2609 int* num_features,
2610 int* feature_outline_index) {
2611 GenericVector<int> outline_counts;
2614 INT_FX_RESULT_STRUCT fx_info;
2615 tesseract_->ExtractFeatures(*blob, false, &bl_features,
2616 &cn_features, &fx_info, &outline_counts);
2617 if (cn_features.empty() || cn_features.size() > MAX_NUM_INT_FEATURES) {
2618 *num_features = 0;
2619 return; // Feature extraction failed.
2620 }
2621 *num_features = cn_features.size();
2622 memcpy(int_features, &cn_features[0], *num_features * sizeof(cn_features[0]));
2623 // TODO(rays) Pass outline_counts back and simplify the calling code.
2624 if (feature_outline_index != nullptr) {
2625 int f = 0;
2626 for (int i = 0; i < outline_counts.size(); ++i) {
2627 while (f < outline_counts[i])
2628 feature_outline_index[f++] = i;
2629 }
2630 }
2631}
2632
2633// This method returns the row to which a box of specified dimensions would
2634// belong. If no good match is found, it returns nullptr.
2635ROW* TessBaseAPI::FindRowForBox(BLOCK_LIST* blocks,
2636 int left, int top, int right, int bottom) {
2637 TBOX box(left, bottom, right, top);
2638 BLOCK_IT b_it(blocks);
2639 for (b_it.mark_cycle_pt(); !b_it.cycled_list(); b_it.forward()) {
2640 BLOCK* block = b_it.data();
2641 if (!box.major_overlap(block->pdblk.bounding_box()))
2642 continue;
2643 ROW_IT r_it(block->row_list());
2644 for (r_it.mark_cycle_pt(); !r_it.cycled_list(); r_it.forward()) {
2645 ROW* row = r_it.data();
2646 if (!box.major_overlap(row->bounding_box()))
2647 continue;
2648 WERD_IT w_it(row->word_list());
2649 for (w_it.mark_cycle_pt(); !w_it.cycled_list(); w_it.forward()) {
2650 WERD* word = w_it.data();
2651 if (box.major_overlap(word->bounding_box()))
2652 return row;
2653 }
2654 }
2655 }
2656 return nullptr;
2657}
2658
2660void TessBaseAPI::RunAdaptiveClassifier(TBLOB* blob,
2661 int num_max_matches,
2662 int* unichar_ids,
2663 float* ratings,
2664 int* num_matches_returned) {
2665 auto* choices = new BLOB_CHOICE_LIST;
2666 tesseract_->AdaptiveClassifier(blob, choices);
2667 BLOB_CHOICE_IT choices_it(choices);
2668 int& index = *num_matches_returned;
2669 index = 0;
2670 for (choices_it.mark_cycle_pt();
2671 !choices_it.cycled_list() && index < num_max_matches;
2672 choices_it.forward()) {
2673 BLOB_CHOICE* choice = choices_it.data();
2674 unichar_ids[index] = choice->unichar_id();
2675 ratings[index] = choice->rating();
2676 ++index;
2677 }
2678 *num_matches_returned = index;
2679 delete choices;
2680}
2681#endif // ndef DISABLED_LEGACY_ENGINE
2682
2683} // namespace tesseract.
struct TessResultRenderer TessResultRenderer
Definition: capi.h:87
#define TRUE
Definition: capi.h:51
#define BOOL
Definition: capi.h:50
int OrientationIdToValue(const int &id)
Definition: osdetect.cpp:566
int orientation_and_script_detection(STRING &filename, OSResults *osr, tesseract::Tesseract *tess)
Definition: osdetect.cpp:190
const int kBlnBaselineOffset
Definition: normalis.h:25
const int kBlnXHeight
Definition: normalis.h:24
@ CR_DELETE
Definition: pageres.h:161
@ CR_NONE
Definition: pageres.h:158
@ CR_KEEP_SPACE
Definition: pageres.h:159
#define DIR
Definition: polyaprx.cpp:40
bool PTIsTextType(PolyBlockType type)
Definition: publictypes.h:82
constexpr int kMinCredibleResolution
Definition: publictypes.h:38
constexpr int kMaxCredibleResolution
Definition: publictypes.h:40
@ W_FUZZY_SP
fuzzy space
Definition: werd.h:39
@ W_EOL
end of line
Definition: werd.h:33
@ W_FUZZY_NON
fuzzy nonspace
Definition: werd.h:40
@ W_BOL
start of line
Definition: werd.h:32
#define ELISTIZEH(CLASSNAME)
Definition: elst.h:918
#define ELISTIZE(CLASSNAME)
Definition: elst.h:931
#define ASSERT_HOST(x)
Definition: errcode.h:88
void chomp_string(char *str)
Definition: helpers.h:77
int IntCastRounded(double x)
Definition: helpers.h:175
T ClipToRange(const T &x, const T &lower_bound, const T &upper_bound)
Definition: helpers.h:108
tesseract::ParamsVectors * GlobalParams()
Definition: params.cpp:32
#define BOOL_VAR(name, val, comment)
Definition: params.h:306
#define STRING_VAR(name, val, comment)
Definition: params.h:309
#define MAX_PATH
Definition: platform.h:29
_ConstTessMemberResultCallback_5_0< false, R, T1, P1, P2, P3, P4, P5 >::base * NewPermanentTessCallback(const T1 *obj, R(T2::*member)(P1, P2, P3, P4, P5) const, typename Identity< P1 >::type p1, typename Identity< P2 >::type p2, typename Identity< P3 >::type p3, typename Identity< P4 >::type p4, typename Identity< P5 >::type p5)
Definition: tesscallback.h:258
DLLSYM void tprintf(const char *format,...)
Definition: tprintf.cpp:35
#define UNICHAR_LEN
Definition: unichar.h:30
int UNICHAR_ID
Definition: unichar.h:34
#define MAX_NUM_INT_FEATURES
Definition: intproto.h:129
@ baseline
Definition: mfoutline.h:63
void extract_edges(Pix *pix, BLOCK *block)
Definition: edgblob.cpp:329
@ OEM_TESSERACT_ONLY
Definition: publictypes.h:269
@ SET_PARAM_CONSTRAINT_NON_INIT_ONLY
Definition: params.h:39
@ SET_PARAM_CONSTRAINT_DEBUG_ONLY
Definition: params.h:37
const char kTesseractReject
Definition: baseapi.cpp:106
const int kMinRectSize
Definition: baseapi.cpp:104
bool(*)(const STRING &, GenericVector< char > *) FileReader
Definition: serialis.h:49
const int kBytesPerBoxFileLine
Definition: baseapi.cpp:1502
bool PSM_OSD_ENABLED(int pageseg_mode)
Definition: publictypes.h:191
@ PSM_OSD_ONLY
Orientation and script detection only.
Definition: publictypes.h:164
@ PSM_AUTO_ONLY
Automatic page segmentation, but no OSD, or OCR.
Definition: publictypes.h:167
@ PSM_SINGLE_BLOCK
Assume a single uniform block of text. (Default.)
Definition: publictypes.h:172
void(Wordrec::*)(const MATRIX &, const WERD_CHOICE_LIST &, const UNICHARSET &, BlamerBundle *) FillLatticeFunc
Definition: baseapi.h:79
const int kMaxIntSize
Definition: baseapi.cpp:121
int(Dict::*)(void *, const UNICHARSET &, UNICHAR_ID, bool) const DictFunc
Definition: baseapi.h:76
const int kBytesPer64BitNumber
Definition: baseapi.cpp:1504
double(Dict::*)(const char *, const char *, int, const char *, int) ProbabilityInContextFunc
Definition: baseapi.h:77
const int kMaxBytesPerLine
Definition: baseapi.cpp:1511
const int kLatinChs[]
Definition: baseapi.cpp:1565
STRING HOcrEscape(const char *text)
Definition: baseapi.cpp:2310
const int kBytesPerNumber
Definition: baseapi.cpp:1496
const char kUNLVReject
Definition: baseapi.cpp:108
void ExtractFontName(const STRING &filename, STRING *fontname)
Definition: blobclass.cpp:45
const int kNumbersPerBlob
Definition: baseapi.cpp:1491
void DetectParagraphs(int debug_level, GenericVector< RowInfo > *row_infos, GenericVector< PARA * > *row_owners, PARA_LIST *paragraphs, GenericVector< ParagraphModel * > *models)
const char kUNLVSuspect
Definition: baseapi.cpp:110
const int kUniChs[]
Definition: baseapi.cpp:1561
TESS_CHAR(float _cost, const char *repr, int len=-1)
Definition: baseapi.cpp:2486
int push_back(T object)
bool empty() const
Definition: genericvector.h:91
int size() const
Definition: genericvector.h:72
void delete_data_pointers()
EquationDetect * equ_detect_
The equation detector.
Definition: baseapi.h:890
GenericVector< ParagraphModel * > * paragraph_models_
Definition: baseapi.h:893
bool ProcessPagesInternal(const char *filename, const char *retry_config, int timeout_millisec, TessResultRenderer *renderer)
Definition: baseapi.cpp:1113
virtual TESS_LOCAL bool Threshold(Pix **pix)
Definition: baseapi.cpp:2014
bool ProcessPage(Pix *pix, int page_index, const char *filename, const char *retry_config, int timeout_millisec, TessResultRenderer *renderer)
Definition: baseapi.cpp:1240
int Recognize(ETEXT_DESC *monitor)
Definition: baseapi.cpp:830
PAGE_RES * page_res_
The page-level data.
Definition: baseapi.h:895
void SetPageSegMode(PageSegMode mode)
Definition: baseapi.cpp:515
TESS_LOCAL bool InternalSetImage()
Definition: baseapi.cpp:1997
STRING * output_file_
Name used by debug code.
Definition: baseapi.h:897
Tesseract * tesseract_
The underlying data object.
Definition: baseapi.h:888
bool GetIntVariable(const char *name, int *value) const
Definition: baseapi.cpp:298
void SetRectangle(int left, int top, int width, int height)
Definition: baseapi.cpp:624
int NumDawgs() const
Definition: baseapi.cpp:2305
MutableIterator * GetMutableIterator()
Definition: baseapi.cpp:1341
bool SetVariable(const char *name, const char *value)
Definition: baseapi.cpp:286
TESS_LOCAL void DetectParagraphs(bool after_text_recognition)
Definition: baseapi.cpp:2278
STRING * input_file_
Name used by training code.
Definition: baseapi.h:896
ResultIterator * GetIterator()
Definition: baseapi.cpp:1324
bool DetectOS(OSResults *)
Definition: baseapi.cpp:2200
PageSegMode GetPageSegMode() const
Definition: baseapi.cpp:522
STRING * language_
Last initialized language.
Definition: baseapi.h:899
bool recognition_done_
page_res_ contains recognition data.
Definition: baseapi.h:901
FileReader reader_
Reads files from any filesystem.
Definition: baseapi.h:891
TESS_LOCAL int FindLines()
Definition: baseapi.cpp:2068
void SetInputName(const char *name)
Definition: baseapi.cpp:271
int Init(const char *datapath, const char *language, OcrEngineMode mode, char **configs, int configs_size, const GenericVector< STRING > *vars_vec, const GenericVector< STRING > *vars_values, bool set_only_non_debug_params)
Definition: baseapi.cpp:346
OcrEngineMode oem() const
Definition: baseapi.h:803
void PrintVariables(FILE *fp) const
Definition: baseapi.cpp:334
ImageThresholder * thresholder_
Image thresholding module.
Definition: baseapi.h:892
void SetImage(const unsigned char *imagedata, int width, int height, int bytes_per_pixel, int bytes_per_line)
Definition: baseapi.cpp:580
Boxa * GetComponentImages(PageIteratorLevel level, bool text_only, bool raw_image, int raw_padding, Pixa **pixa, int **blockids, int **paraids)
Definition: baseapi.cpp:706
PageIterator * AnalyseLayout()
Definition: baseapi.cpp:810
void ReadConfigFile(const char *filename)
Definition: baseapi.cpp:501
BLOCK_LIST * block_list_
The page layout.
Definition: baseapi.h:894
TruthCallback * truth_cb_
Definition: baseapi.h:902
bool DetectOrientationScript(int *orient_deg, float *orient_conf, const char **script_name, float *script_conf)
Definition: baseapi.cpp:1686
TESS_LOCAL LTRResultIterator * GetLTRIterator()
Definition: baseapi.cpp:1307
Tesseract * osd_tesseract_
For orientation & script detection.
Definition: baseapi.h:889
STRING * datapath_
Current location of tessdata.
Definition: baseapi.h:898
bool GetBoolVariable(const char *name, bool *value) const
Definition: baseapi.cpp:306
TESS_LOCAL int TextLength(int *blob_count)
Definition: baseapi.cpp:2169
Pix * GetThresholdedImage()
Definition: baseapi.cpp:635
void SetInputImage(Pix *pix)
Definition: baseapi.cpp:956
OcrEngineMode last_oem_requested_
Last ocr language mode requested.
Definition: baseapi.h:900
bool AddImage(TessBaseAPI *api)
Definition: renderer.cpp:83
bool BeginDocument(const char *title)
Definition: renderer.cpp:72
char * GetUTF8Text(PageIteratorLevel level) const
float Confidence(PageIteratorLevel level) const
float oconfidence
Definition: osdetect.h:46
int orientation_id
Definition: osdetect.h:43
float sconfidence
Definition: osdetect.h:45
OSBestResult best_result
Definition: osdetect.h:81
UNICHARSET * unicharset
Definition: osdetect.h:80
TESS_API int get_best_script(int orientation_id) const
Definition: osdetect.cpp:112
bool BoundingBoxInternal(PageIteratorLevel level, int *left, int *top, int *right, int *bottom) const
virtual bool Next(PageIteratorLevel level)
PolyBlockType BlockType() const
Pix * GetImage(PageIteratorLevel level, int padding, Pix *original_img, int *left, int *top) const
bool Empty(PageIteratorLevel level) const
bool Baseline(PageIteratorLevel level, int *x1, int *y1, int *x2, int *y2) const
Pix * GetBinaryImage(PageIteratorLevel level) const
bool BoundingBox(PageIteratorLevel level, int *left, int *top, int *right, int *bottom) const
virtual bool IsAtFinalElement(PageIteratorLevel level, PageIteratorLevel element) const
bool IsAtFinalElement(PageIteratorLevel level, PageIteratorLevel element) const override
virtual char * GetUTF8Text(PageIteratorLevel level) const
bool IsAtBeginningOf(PageIteratorLevel level) const override
bool Next(PageIteratorLevel level) override
static ResultIterator * StartOfParagraph(const LTRResultIterator &resit)
void recog_training_segmented(const STRING &fname, PAGE_RES *page_res, volatile ETEXT_DESC *monitor, FILE *output_file)
void SetEquationDetect(EquationDetect *detector)
int init_tesseract(const char *arg0, const char *textbase, const char *language, OcrEngineMode oem, char **configs, int configs_size, const GenericVector< STRING > *vars_vec, const GenericVector< STRING > *vars_values, bool set_only_init_params, TessdataManager *mgr)
Definition: tessedit.cpp:286
void set_unlv_suspects(WERD_RES *word)
Definition: output.cpp:273
Pix * pix_binary() const
void set_pix_grey(Pix *grey_pix)
int SegmentPage(const STRING *input_file, BLOCK_LIST *blocks, Tesseract *osd_tess, OSResults *osr)
Definition: pagesegmain.cpp:99
int num_sub_langs() const
void TidyUp(PAGE_RES *page_res)
Definition: applybox.cpp:708
void read_config_file(const char *filename, SetParamConstraint constraint)
Definition: tessedit.cpp:48
FILE * init_recog_training(const STRING &fname)
void ReSegmentByClassification(PAGE_RES *page_res)
Definition: applybox.cpp:506
Dict & getDict() override
void ApplyBoxTraining(const STRING &fontname, PAGE_RES *page_res)
Definition: applybox.cpp:803
Tesseract * get_sub_lang(int index) const
bool tessedit_resegment_from_line_boxes
void PrepareForTessOCR(BLOCK_LIST *block_list, Tesseract *osd_tess, OSResults *osr)
PAGE_RES * SetupApplyBoxes(const GenericVector< TBOX > &boxes, BLOCK_LIST *block_list)
Definition: applybox.cpp:207
Pix * pix_original() const
void set_pix_thresholds(Pix *thresholds)
int init_tesseract_lm(const char *arg0, const char *textbase, const char *language, TessdataManager *mgr)
Definition: tessedit.cpp:452
void set_source_resolution(int ppi)
void CorrectClassifyWords(PAGE_RES *page_res)
Definition: applybox.cpp:776
void MaximallyChopWord(const GenericVector< TBOX > &boxes, BLOCK *block, ROW *row, WERD_RES *word_res)
Definition: applybox.cpp:243
void pgeditor_main(int width, int height, PAGE_RES *page_res)
Definition: pgedit.cpp:378
bool TrainLineRecognizer(const STRING &input_imagename, const STRING &output_basename, BLOCK_LIST *block_list)
Definition: linerec.cpp:44
PAGE_RES * ApplyBoxes(const STRING &fname, bool find_segmentation, BLOCK_LIST *block_list)
Definition: applybox.cpp:109
void set_pix_original(Pix *original_pix)
bool AnyLSTMLang() const
bool recog_all_words(PAGE_RES *page_res, ETEXT_DESC *monitor, const TBOX *target_word_box, const char *word_config, int dopasses)
Definition: control.cpp:302
int GetScaledEstimatedResolution() const
Definition: thresholder.h:105
virtual Pix * GetPixRectGrey()
virtual bool ThresholdToPix(PageSegMode pageseg_mode, Pix **pix)
Returns false on error.
int GetSourceYResolution() const
Definition: thresholder.h:89
virtual void GetImageSizes(int *left, int *top, int *width, int *height, int *imagewidth, int *imageheight)
bool IsEmpty() const
Return true if no image has been set.
Definition: thresholder.cpp:53
void SetImage(const unsigned char *imagedata, int width, int height, int bytes_per_pixel, int bytes_per_line)
Definition: thresholder.cpp:65
int GetScaledYResolution() const
Definition: thresholder.h:92
virtual Pix * GetPixRectThresholds()
void SetRectangle(int left, int top, int width, int height)
bool IsBinary() const
Returns true if the source image is binary.
Definition: thresholder.h:74
void SetSourceYResolution(int ppi)
Definition: thresholder.h:85
virtual void Clear()
Destroy the Pix if there is one, freeing memory.
Definition: thresholder.cpp:48
Definition: blobs.h:284
TESSLINE * outlines
Definition: blobs.h:400
TBOX bounding_box() const
Definition: blobs.cpp:468
void Normalize(const BLOCK *block, const FCOORD *rotation, const DENORM *predecessor, float x_origin, float y_origin, float x_scale, float y_scale, float final_xshift, float final_yshift, bool inverse, Pix *pix)
Definition: blobs.cpp:397
static TBLOB * PolygonalCopy(bool allow_detailed_fx, C_BLOB *src)
Definition: blobs.cpp:327
const TBOX & BlobBox(int index) const
Definition: boxword.h:84
Definition: ocrblock.h:31
ROW_LIST * row_list()
get rows
Definition: ocrblock.h:116
C_BLOB_LIST * blob_list()
get blobs
Definition: ocrblock.h:128
PDBLK pdblk
Page Description Block.
Definition: ocrblock.h:190
Definition: ocrrow.h:37
WERD_LIST * word_list()
Definition: ocrrow.h:55
float base_line(float xpos) const
Definition: ocrrow.h:59
TBOX bounding_box() const
Definition: ocrrow.h:88
float x_height() const
Definition: ocrrow.h:64
BLOCK * block
Definition: pageres.h:116
ROW * row
Definition: pageres.h:140
tesseract::BoxWord * box_word
Definition: pageres.h:272
WERD_CHOICE * best_choice
Definition: pageres.h:241
CRUNCH_MODE unlv_crunch_mode
Definition: pageres.h:315
void BestChoiceToCorrectText()
Definition: pageres.cpp:923
REJMAP reject_map
Definition: pageres.h:294
WERD * word
Definition: pageres.h:186
WERD_RES * word() const
Definition: pageres.h:754
ROW_RES * row() const
Definition: pageres.h:757
BLOCK_RES * block() const
Definition: pageres.h:760
WERD_RES * restart_page()
Definition: pageres.h:701
WERD_RES * forward()
Definition: pageres.h:734
void bounding_box(ICOORD &bottom_left, ICOORD &top_right) const
get box
Definition: pdblock.h:59
Definition: points.h:189
float angle() const
find angle
Definition: points.h:247
float y() const
Definition: points.h:210
float rating() const
Definition: ratngs.h:80
UNICHAR_ID unichar_id() const
Definition: ratngs.h:77
const STRING & unichar_string() const
Definition: ratngs.h:531
float certainty() const
Definition: ratngs.h:320
int length() const
Definition: ratngs.h:293
const STRING & unichar_lengths() const
Definition: ratngs.h:538
float rating() const
Definition: ratngs.h:317
Definition: rect.h:34
int16_t top() const
Definition: rect.h:58
bool major_overlap(const TBOX &box) const
Definition: rect.h:368
int16_t left() const
Definition: rect.h:72
int16_t bottom() const
Definition: rect.h:65
TBOX intersection(const TBOX &box) const
Definition: rect.cpp:87
int16_t right() const
Definition: rect.h:79
int32_t length() const
Definition: rejctmap.h:223
C_OUTLINE_LIST * out_list()
Definition: stepblob.h:70
Definition: werd.h:56
uint8_t space()
Definition: werd.h:99
void set_text(const char *new_text)
Definition: werd.h:115
TBOX bounding_box() const
Definition: werd.cpp:148
bool flag(WERD_FLAGS mask) const
Definition: werd.h:117
ParamsVectors * params()
Definition: ccutil.h:67
STRING datadir
Definition: ccutil.h:69
UNICHARSET unicharset
Definition: ccutil.h:73
STRING lang
Definition: ccutil.h:71
void set_deadline_msecs(int32_t deadline_msecs)
Definition: ocrclass.h:129
void * cancel_this
monitor-aware progress callback
Definition: ocrclass.h:116
CANCEL_FUNC cancel
for errcode use
Definition: ocrclass.h:112
GenericVector< IntParam * > int_params
Definition: params.h:43
GenericVector< DoubleParam * > double_params
Definition: params.h:46
GenericVector< BoolParam * > bool_params
Definition: params.h:44
GenericVector< StringParam * > string_params
Definition: params.h:45
static bool GetParamAsString(const char *name, const ParamsVectors *member_params, STRING *value)
Definition: params.cpp:129
static void ResetToDefaults(ParamsVectors *member_params)
Definition: params.cpp:199
static void PrintParams(FILE *fp, const ParamsVectors *member_params)
Definition: params.cpp:168
static bool SetParam(const char *name, const char *value, SetParamConstraint constraint, ParamsVectors *member_params)
Definition: params.cpp:79
Definition: strngs.h:45
const char * c_str() const
Definition: strngs.cpp:205
void add_str_int(const char *str, int number)
Definition: strngs.cpp:377
int32_t length() const
Definition: strngs.cpp:189
const char * string() const
Definition: strngs.cpp:194
void split(char c, GenericVector< STRING > *splited)
Definition: strngs.cpp:282
virtual R Run()=0
virtual void Run(A1, A2, A3, A4)=0
bool LoadMemBuffer(const char *name, const char *data, int size)
int first_uni() const
Definition: unichar.cpp:98
bool contains_unichar(const char *const unichar_repr) const
Definition: unicharset.cpp:671
const char * get_script_from_script_id(int id) const
Definition: unicharset.h:854
const char * id_to_unichar(UNICHAR_ID id) const
Definition: unicharset.cpp:291
UNICHAR_ID unichar_to_id(const char *const unichar_repr) const
Definition: unicharset.cpp:210
static void ExtractFeatures(const TBLOB &blob, bool nonlinear_norm, GenericVector< INT_FEATURE_STRUCT > *bl_features, GenericVector< INT_FEATURE_STRUCT > *cn_features, INT_FX_RESULT_STRUCT *results, GenericVector< int > *outline_cn_counts)
Definition: intfx.cpp:442
void LearnWord(const char *fontname, WERD_RES *word)
Definition: adaptmatch.cpp:250
ADAPT_TEMPLATES AdaptedTemplates
Definition: classify.h:515
bool classify_bln_numeric_mode
Definition: classify.h:508
bool WriteTRFile(const STRING &filename)
Definition: blobclass.cpp:98
void AdaptiveClassifier(TBLOB *Blob, BLOB_CHOICE_LIST *Choices)
Definition: adaptmatch.cpp:191
void InitAdaptiveClassifier(TessdataManager *mgr)
Definition: adaptmatch.cpp:527
double matcher_good_threshold
Definition: classify.h:456
void AdaptToChar(TBLOB *Blob, CLASS_ID ClassId, int FontinfoId, float Threshold, ADAPT_TEMPLATES adaptive_templates)
Definition: adaptmatch.cpp:853
void DeleteUnusedDawgs()
Definition: dawg_cache.h:43
static TESS_API DawgCache * GlobalDawgCache()
Definition: dict.cpp:184
int(Dict::* letter_is_okay_)(void *void_dawg_args, const UNICHARSET &unicharset, UNICHAR_ID unichar_id, bool word_end) const
Definition: dict.h:372
int valid_word(const WERD_CHOICE &word, bool numbers_ok) const
Definition: dict.cpp:778
int NumDawgs() const
Return the number of dawgs in the dawgs_ vector.
Definition: dict.h:430
const Dawg * GetDawg(int index) const
Return i-th dawg pointer recorded in the dawgs_ vector.
Definition: dict.h:432
double(Dict::* probability_in_context_)(const char *lang, const char *context, int context_bytes, const char *character, int character_bytes)
Probability in context function used by the ngram permuter.
Definition: dict.h:384
const UNICHARSET & getUnicharset() const
Definition: dict.h:101
void(Wordrec::* fill_lattice_)(const MATRIX &ratings, const WERD_CHOICE_LIST &best_choices, const UNICHARSET &unicharset, BlamerBundle *blamer_bundle)
Definition: wordrec.h:480
WERD_CHOICE * prev_word_best_choice_
Definition: wordrec.h:476
bool wordrec_run_blamer
Definition: wordrec.h:232