tesseract  4.1.0
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 #include "allheaders.h" // for pixDestroy, boxCreate, boxaAddBox, box...
53 #include "blobclass.h" // for ExtractFontName
54 #include "boxword.h" // for BoxWord
55 #include "config_auto.h" // for PACKAGE_VERSION
56 #include "coutln.h" // for C_OUTLINE_IT, C_OUTLINE_LIST
57 #include "dawg_cache.h" // for DawgCache
58 #include "dict.h" // for Dict
59 #include "edgblob.h" // for extract_edges
60 #include "elst.h" // for ELIST_ITERATOR, ELISTIZE, ELISTIZEH
61 #include "environ.h" // for l_uint8
62 #include "equationdetect.h" // for EquationDetect
63 #include "errcode.h" // for ASSERT_HOST
64 #include "helpers.h" // for IntCastRounded, chomp_string
65 #include "imageio.h" // for IFF_TIFF_G4, IFF_TIFF, IFF_TIFF_G3, ...
66 #ifndef DISABLED_LEGACY_ENGINE
67 #include "intfx.h" // for INT_FX_RESULT_STRUCT
68 #endif
69 #include "mutableiterator.h" // for MutableIterator
70 #include "normalis.h" // for kBlnBaselineOffset, kBlnXHeight
71 #include "ocrclass.h" // for ETEXT_DESC
72 #if defined(USE_OPENCL)
73 #include "openclwrapper.h" // for OpenclDevice
74 #endif
75 #include "osdetect.h" // for OSResults, OSBestResult, OrientationId...
76 #include "pageres.h" // for PAGE_RES_IT, WERD_RES, PAGE_RES, CR_DE...
77 #include "paragraphs.h" // for DetectParagraphs
78 #include "params.h" // for BoolParam, IntParam, DoubleParam, Stri...
79 #include "pdblock.h" // for PDBLK
80 #include "points.h" // for FCOORD
81 #include "polyblk.h" // for POLY_BLOCK
82 #include "rect.h" // for TBOX
83 #include "renderer.h" // for TessResultRenderer
84 #include "resultiterator.h" // for ResultIterator
85 #include "stepblob.h" // for C_BLOB_IT, C_BLOB, C_BLOB_LIST
86 #include "strngs.h" // for STRING
87 #include "tessdatamanager.h" // for TessdataManager, kTrainedDataSuffix
88 #include "tesseractclass.h" // for Tesseract
89 #include "thresholder.h" // for ImageThresholder
90 #include "tprintf.h" // for tprintf
91 #include "werd.h" // for WERD, WERD_IT, W_FUZZY_NON, W_FUZZY_SP
92 
93 static BOOL_VAR(stream_filelist, false, "Stream a filelist from stdin");
94 
95 namespace tesseract {
96 
98 const int kMinRectSize = 10;
100 const char kTesseractReject = '~';
102 const char kUNLVReject = '~';
104 const char kUNLVSuspect = '^';
109 static const char* kInputFile = "noname.tif";
113 static const char* kOldVarsFile = "failed_vars.txt";
115 const int kMaxIntSize = 22;
116 
117 /* Add all available languages recursively.
118 */
119 static void addAvailableLanguages(const STRING &datadir, const STRING &base,
120  GenericVector<STRING>* langs)
121 {
122  const STRING base2 = (base.string()[0] == '\0') ? base : base + "/";
123  const size_t extlen = sizeof(kTrainedDataSuffix);
124 #ifdef _WIN32
125  WIN32_FIND_DATA data;
126  HANDLE handle = FindFirstFile((datadir + base2 + "*").string(), &data);
127  if (handle != INVALID_HANDLE_VALUE) {
128  BOOL result = TRUE;
129  for (; result;) {
130  char *name = data.cFileName;
131  // Skip '.', '..', and hidden files
132  if (name[0] != '.') {
133  if ((data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) ==
134  FILE_ATTRIBUTE_DIRECTORY) {
135  addAvailableLanguages(datadir, base2 + name, langs);
136  } else {
137  size_t len = strlen(name);
138  if (len > extlen && name[len - extlen] == '.' &&
139  strcmp(&name[len - extlen + 1], kTrainedDataSuffix) == 0) {
140  name[len - extlen] = '\0';
141  langs->push_back(base2 + name);
142  }
143  }
144  }
145  result = FindNextFile(handle, &data);
146  }
147  FindClose(handle);
148  }
149 #else // _WIN32
150  DIR* dir = opendir((datadir + base).string());
151  if (dir != nullptr) {
152  dirent *de;
153  while ((de = readdir(dir))) {
154  char *name = de->d_name;
155  // Skip '.', '..', and hidden files
156  if (name[0] != '.') {
157  struct stat st;
158  if (stat((datadir + base2 + name).string(), &st) == 0 &&
159  (st.st_mode & S_IFDIR) == S_IFDIR) {
160  addAvailableLanguages(datadir, base2 + name, langs);
161  } else {
162  size_t len = strlen(name);
163  if (len > extlen && name[len - extlen] == '.' &&
164  strcmp(&name[len - extlen + 1], kTrainedDataSuffix) == 0) {
165  name[len - extlen] = '\0';
166  langs->push_back(base2 + name);
167  }
168  }
169  }
170  }
171  closedir(dir);
172  }
173 #endif
174 }
175 
176 // Compare two STRING values (used for sorting).
177 static int CompareSTRING(const void* p1, const void* p2) {
178  const auto* s1 = static_cast<const STRING*>(p1);
179  const auto* s2 = static_cast<const STRING*>(p2);
180  return strcmp(s1->c_str(), s2->c_str());
181 }
182 
184  : tesseract_(nullptr),
185  osd_tesseract_(nullptr),
186  equ_detect_(nullptr),
187  reader_(nullptr),
188  // Thresholder is initialized to nullptr here, but will be set before use by:
189  // A constructor of a derived API, SetThresholder(), or
190  // created implicitly when used in InternalSetImage.
191  thresholder_(nullptr),
192  paragraph_models_(nullptr),
193  block_list_(nullptr),
194  page_res_(nullptr),
195  input_file_(nullptr),
196  output_file_(nullptr),
197  datapath_(nullptr),
198  language_(nullptr),
199  last_oem_requested_(OEM_DEFAULT),
200  recognition_done_(false),
201  truth_cb_(nullptr),
202  rect_left_(0),
203  rect_top_(0),
204  rect_width_(0),
205  rect_height_(0),
206  image_width_(0),
207  image_height_(0) {
208 #if defined(DEBUG)
209  // The Tesseract executables would use the "C" locale by default,
210  // but other software which is linked against the Tesseract library
211  // typically uses the locale from the user's environment.
212  // Here the default is overridden to allow debugging of potential
213  // problems caused by the locale settings.
214 
215  // Use the current locale if building debug code.
216  std::locale::global(std::locale(""));
217 #endif
218 }
219 
221  End();
222 }
223 
227 const char* TessBaseAPI::Version() {
228  return PACKAGE_VERSION;
229 }
230 
238 size_t TessBaseAPI::getOpenCLDevice(void **data) {
239 #ifdef USE_OPENCL
240  ds_device device = OpenclDevice::getDeviceSelection();
241  if (device.type == DS_DEVICE_OPENCL_DEVICE) {
242  *data = new cl_device_id;
243  memcpy(*data, &device.oclDeviceID, sizeof(cl_device_id));
244  return sizeof(cl_device_id);
245  }
246 #endif
247 
248  *data = nullptr;
249  return 0;
250 }
251 
257  // Warn API users that an implementation is needed.
258  tprintf("Deprecated method CatchSignals has only a dummy implementation!\n");
259 }
260 
265 void TessBaseAPI::SetInputName(const char* name) {
266  if (input_file_ == nullptr)
267  input_file_ = new STRING(name);
268  else
269  *input_file_ = name;
270 }
271 
273 void TessBaseAPI::SetOutputName(const char* name) {
274  if (output_file_ == nullptr)
275  output_file_ = new STRING(name);
276  else
277  *output_file_ = name;
278 }
279 
280 bool TessBaseAPI::SetVariable(const char* name, const char* value) {
281  if (tesseract_ == nullptr) tesseract_ = new Tesseract;
283  tesseract_->params());
284 }
285 
286 bool TessBaseAPI::SetDebugVariable(const char* name, const char* value) {
287  if (tesseract_ == nullptr) tesseract_ = new Tesseract;
289  tesseract_->params());
290 }
291 
292 bool TessBaseAPI::GetIntVariable(const char *name, int *value) const {
293  auto *p = ParamUtils::FindParam<IntParam>(
295  if (p == nullptr) return false;
296  *value = (int32_t)(*p);
297  return true;
298 }
299 
300 bool TessBaseAPI::GetBoolVariable(const char *name, bool *value) const {
301  auto *p = ParamUtils::FindParam<BoolParam>(
303  if (p == nullptr) return false;
304  *value = bool(*p);
305  return true;
306 }
307 
308 const char *TessBaseAPI::GetStringVariable(const char *name) const {
309  auto *p = ParamUtils::FindParam<StringParam>(
311  return (p != nullptr) ? p->string() : nullptr;
312 }
313 
314 bool TessBaseAPI::GetDoubleVariable(const char *name, double *value) const {
315  auto *p = ParamUtils::FindParam<DoubleParam>(
317  if (p == nullptr) return false;
318  *value = (double)(*p);
319  return true;
320 }
321 
323 bool TessBaseAPI::GetVariableAsString(const char *name, STRING *val) {
324  return ParamUtils::GetParamAsString(name, tesseract_->params(), val);
325 }
326 
328 void TessBaseAPI::PrintVariables(FILE *fp) const {
330 }
331 
340 int TessBaseAPI::Init(const char* datapath, const char* language,
341  OcrEngineMode oem, char **configs, int configs_size,
342  const GenericVector<STRING> *vars_vec,
343  const GenericVector<STRING> *vars_values,
344  bool set_only_non_debug_params) {
345  return Init(datapath, 0, language, oem, configs, configs_size, vars_vec,
346  vars_values, set_only_non_debug_params, nullptr);
347 }
348 
349 // In-memory version reads the traineddata file directly from the given
350 // data[data_size] array. Also implements the version with a datapath in data,
351 // flagged by data_size = 0.
352 int TessBaseAPI::Init(const char* data, int data_size, const char* language,
353  OcrEngineMode oem, char** configs, int configs_size,
354  const GenericVector<STRING>* vars_vec,
355  const GenericVector<STRING>* vars_values,
356  bool set_only_non_debug_params, FileReader reader) {
357  // Default language is "eng".
358  if (language == nullptr) language = "eng";
359  STRING datapath = data_size == 0 ? data : language;
360  // If the datapath, OcrEngineMode or the language have changed - start again.
361  // Note that the language_ field stores the last requested language that was
362  // initialized successfully, while tesseract_->lang stores the language
363  // actually used. They differ only if the requested language was nullptr, in
364  // which case tesseract_->lang is set to the Tesseract default ("eng").
365  if (tesseract_ != nullptr &&
366  (datapath_ == nullptr || language_ == nullptr || *datapath_ != datapath ||
367  last_oem_requested_ != oem ||
368  (*language_ != language && tesseract_->lang != language))) {
369  delete tesseract_;
370  tesseract_ = nullptr;
371  }
372 #ifdef USE_OPENCL
373  OpenclDevice od;
374  od.InitEnv();
375 #endif
376  bool reset_classifier = true;
377  if (tesseract_ == nullptr) {
378  reset_classifier = false;
379  tesseract_ = new Tesseract;
380  if (reader != nullptr) reader_ = reader;
382  if (data_size != 0) {
383  mgr.LoadMemBuffer(language, data, data_size);
384  }
386  datapath.string(),
387  output_file_ != nullptr ? output_file_->string() : nullptr,
388  language, oem, configs, configs_size, vars_vec, vars_values,
389  set_only_non_debug_params, &mgr) != 0) {
390  return -1;
391  }
392  }
393 
394  // Update datapath and language requested for the last valid initialization.
395  if (datapath_ == nullptr)
396  datapath_ = new STRING(datapath);
397  else
398  *datapath_ = datapath;
399  if ((strcmp(datapath_->string(), "") == 0) &&
400  (strcmp(tesseract_->datadir.string(), "") != 0))
402 
403  if (language_ == nullptr)
404  language_ = new STRING(language);
405  else
406  *language_ = language;
408 
409 #ifndef DISABLED_LEGACY_ENGINE
410  // For same language and datapath, just reset the adaptive classifier.
411  if (reset_classifier) {
413  }
414 #endif // ndef DISABLED_LEGACY_ENGINE
415  return 0;
416 }
417 
427  return (language_ == nullptr || language_->string() == nullptr) ?
428  "" : language_->string();
429 }
430 
437  GenericVector<STRING>* langs) const {
438  langs->clear();
439  if (tesseract_ != nullptr) {
440  langs->push_back(tesseract_->lang);
441  int num_subs = tesseract_->num_sub_langs();
442  for (int i = 0; i < num_subs; ++i)
443  langs->push_back(tesseract_->get_sub_lang(i)->lang);
444  }
445 }
446 
451  GenericVector<STRING>* langs) const {
452  langs->clear();
453  if (tesseract_ != nullptr) {
454  addAvailableLanguages(tesseract_->datadir, "", langs);
455  langs->sort(CompareSTRING);
456  }
457 }
458 
459 //TODO(amit): Adapt to lstm
460 #ifndef DISABLED_LEGACY_ENGINE
461 
467 int TessBaseAPI::InitLangMod(const char* datapath, const char* language) {
468  if (tesseract_ == nullptr)
469  tesseract_ = new Tesseract;
470  else
472  TessdataManager mgr;
473  return tesseract_->init_tesseract_lm(datapath, nullptr, language, &mgr);
474 }
475 #endif // ndef DISABLED_LEGACY_ENGINE
476 
482  if (tesseract_ == nullptr) {
483  tesseract_ = new Tesseract;
484  #ifndef DISABLED_LEGACY_ENGINE
486  #endif
487  }
488 }
489 
495 void TessBaseAPI::ReadConfigFile(const char* filename) {
497 }
498 
500 void TessBaseAPI::ReadDebugConfigFile(const char* filename) {
502 }
503 
510  if (tesseract_ == nullptr)
511  tesseract_ = new Tesseract;
512  tesseract_->tessedit_pageseg_mode.set_value(mode);
513 }
514 
517  if (tesseract_ == nullptr)
518  return PSM_SINGLE_BLOCK;
519  return static_cast<PageSegMode>(
520  static_cast<int>(tesseract_->tessedit_pageseg_mode));
521 }
522 
536 char* TessBaseAPI::TesseractRect(const unsigned char* imagedata,
537  int bytes_per_pixel,
538  int bytes_per_line,
539  int left, int top,
540  int width, int height) {
541  if (tesseract_ == nullptr || width < kMinRectSize || height < kMinRectSize)
542  return nullptr; // Nothing worth doing.
543 
544  // Since this original api didn't give the exact size of the image,
545  // we have to invent a reasonable value.
546  int bits_per_pixel = bytes_per_pixel == 0 ? 1 : bytes_per_pixel * 8;
547  SetImage(imagedata, bytes_per_line * 8 / bits_per_pixel, height + top,
548  bytes_per_pixel, bytes_per_line);
549  SetRectangle(left, top, width, height);
550 
551  return GetUTF8Text();
552 }
553 
554 #ifndef DISABLED_LEGACY_ENGINE
555 
560  if (tesseract_ == nullptr)
561  return;
564 }
565 #endif // ndef DISABLED_LEGACY_ENGINE
566 
574 void TessBaseAPI::SetImage(const unsigned char* imagedata,
575  int width, int height,
576  int bytes_per_pixel, int bytes_per_line) {
577  if (InternalSetImage()) {
578  thresholder_->SetImage(imagedata, width, height,
579  bytes_per_pixel, bytes_per_line);
581  }
582 }
583 
585  if (thresholder_)
587  else
588  tprintf("Please call SetImage before SetSourceResolution.\n");
589 }
590 
599 void TessBaseAPI::SetImage(Pix* pix) {
600  if (InternalSetImage()) {
601  if (pixGetSpp(pix) == 4 && pixGetInputFormat(pix) == IFF_PNG) {
602  // remove alpha channel from png
603  Pix* p1 = pixRemoveAlpha(pix);
604  pixSetSpp(p1, 3);
605  (void)pixCopy(pix, p1);
606  pixDestroy(&p1);
607  }
608  thresholder_->SetImage(pix);
610  }
611 }
612 
618 void TessBaseAPI::SetRectangle(int left, int top, int width, int height) {
619  if (thresholder_ == nullptr)
620  return;
621  thresholder_->SetRectangle(left, top, width, height);
622  ClearResults();
623 }
624 
630  if (tesseract_ == nullptr || thresholder_ == nullptr) return nullptr;
631  if (tesseract_->pix_binary() == nullptr &&
633  return nullptr;
634  }
635  return pixClone(tesseract_->pix_binary());
636 }
637 
643 Boxa* TessBaseAPI::GetRegions(Pixa** pixa) {
644  return GetComponentImages(RIL_BLOCK, false, pixa, nullptr);
645 }
646 
655 Boxa* TessBaseAPI::GetTextlines(const bool raw_image, const int raw_padding,
656  Pixa** pixa, int** blockids, int** paraids) {
657  return GetComponentImages(RIL_TEXTLINE, true, raw_image, raw_padding,
658  pixa, blockids, paraids);
659 }
660 
669 Boxa* TessBaseAPI::GetStrips(Pixa** pixa, int** blockids) {
670  return GetComponentImages(RIL_TEXTLINE, false, pixa, blockids);
671 }
672 
678 Boxa* TessBaseAPI::GetWords(Pixa** pixa) {
679  return GetComponentImages(RIL_WORD, true, pixa, nullptr);
680 }
681 
689  return GetComponentImages(RIL_SYMBOL, true, pixa, nullptr);
690 }
691 
701  bool text_only, bool raw_image,
702  const int raw_padding,
703  Pixa** pixa, int** blockids,
704  int** paraids) {
705  PageIterator* page_it = GetIterator();
706  if (page_it == nullptr)
707  page_it = AnalyseLayout();
708  if (page_it == nullptr)
709  return nullptr; // Failed.
710 
711  // Count the components to get a size for the arrays.
712  int component_count = 0;
713  int left, top, right, bottom;
714 
715  TessResultCallback<bool>* get_bbox = nullptr;
716  if (raw_image) {
717  // Get bounding box in original raw image with padding.
719  level, raw_padding,
720  &left, &top, &right, &bottom);
721  } else {
722  // Get bounding box from binarized imaged. Note that this could be
723  // differently scaled from the original image.
724  get_bbox = NewPermanentTessCallback(page_it,
726  level, &left, &top, &right, &bottom);
727  }
728  do {
729  if (get_bbox->Run() &&
730  (!text_only || PTIsTextType(page_it->BlockType())))
731  ++component_count;
732  } while (page_it->Next(level));
733 
734  Boxa* boxa = boxaCreate(component_count);
735  if (pixa != nullptr)
736  *pixa = pixaCreate(component_count);
737  if (blockids != nullptr)
738  *blockids = new int[component_count];
739  if (paraids != nullptr)
740  *paraids = new int[component_count];
741 
742  int blockid = 0;
743  int paraid = 0;
744  int component_index = 0;
745  page_it->Begin();
746  do {
747  if (get_bbox->Run() &&
748  (!text_only || PTIsTextType(page_it->BlockType()))) {
749  Box* lbox = boxCreate(left, top, right - left, bottom - top);
750  boxaAddBox(boxa, lbox, L_INSERT);
751  if (pixa != nullptr) {
752  Pix* pix = nullptr;
753  if (raw_image) {
754  pix = page_it->GetImage(level, raw_padding, GetInputImage(), &left,
755  &top);
756  } else {
757  pix = page_it->GetBinaryImage(level);
758  }
759  pixaAddPix(*pixa, pix, L_INSERT);
760  pixaAddBox(*pixa, lbox, L_CLONE);
761  }
762  if (paraids != nullptr) {
763  (*paraids)[component_index] = paraid;
764  if (page_it->IsAtFinalElement(RIL_PARA, level))
765  ++paraid;
766  }
767  if (blockids != nullptr) {
768  (*blockids)[component_index] = blockid;
769  if (page_it->IsAtFinalElement(RIL_BLOCK, level)) {
770  ++blockid;
771  paraid = 0;
772  }
773  }
774  ++component_index;
775  }
776  } while (page_it->Next(level));
777  delete page_it;
778  delete get_bbox;
779  return boxa;
780 }
781 
783  if (thresholder_ == nullptr) {
784  return 0;
785  }
786  return thresholder_->GetScaleFactor();
787 }
788 
805 
806 PageIterator* TessBaseAPI::AnalyseLayout(bool merge_similar_words) {
807  if (FindLines() == 0) {
808  if (block_list_->empty())
809  return nullptr; // The page was empty.
810  page_res_ = new PAGE_RES(merge_similar_words, block_list_, nullptr);
811  DetectParagraphs(false);
812  return new PageIterator(
816  }
817  return nullptr;
818 }
819 
825  if (tesseract_ == nullptr)
826  return -1;
827  if (FindLines() != 0)
828  return -1;
829  delete page_res_;
830  if (block_list_->empty()) {
831  page_res_ = new PAGE_RES(false, block_list_,
833  return 0; // Empty page.
834  }
835 
837  recognition_done_ = true;
838 #ifndef DISABLED_LEGACY_ENGINE
843  } else
844 #endif // ndef DISABLED_LEGACY_ENGINE
845  {
848  }
849 
850  if (page_res_ == nullptr) {
851  return -1;
852  }
853 
857  return 0;
858  }
859 #ifndef DISABLED_LEGACY_ENGINE
862  return 0;
863  }
864 #endif // ndef DISABLED_LEGACY_ENGINE
865 
866  if (truth_cb_ != nullptr) {
867  tesseract_->wordrec_run_blamer.set_value(true);
868  auto *page_it = new PageIterator(
873  image_height_, page_it, this->tesseract()->pix_grey());
874  delete page_it;
875  }
876 
877  int result = 0;
879  #ifndef GRAPHICS_DISABLED
881  #endif // GRAPHICS_DISABLED
882  // The page_res is invalid after an interactive session, so cleanup
883  // in a way that lets us continue to the next page without crashing.
884  delete page_res_;
885  page_res_ = nullptr;
886  return -1;
887  #ifndef DISABLED_LEGACY_ENGINE
889  STRING fontname;
890  ExtractFontName(*output_file_, &fontname);
892  } else if (tesseract_->tessedit_ambigs_training) {
893  FILE *training_output_file = tesseract_->init_recog_training(*input_file_);
894  // OCR the page segmented into words by tesseract.
896  *input_file_, page_res_, monitor, training_output_file);
897  fclose(training_output_file);
898  #endif // ndef DISABLED_LEGACY_ENGINE
899  } else {
900  // Now run the main recognition.
901  bool wait_for_text = true;
902  GetBoolVariable("paragraph_text_based", &wait_for_text);
903  if (!wait_for_text) DetectParagraphs(false);
904  if (tesseract_->recog_all_words(page_res_, monitor, nullptr, nullptr, 0)) {
905  if (wait_for_text) DetectParagraphs(true);
906  } else {
907  result = -1;
908  }
909  }
910  return result;
911 }
912 
913 #ifndef DISABLED_LEGACY_ENGINE
914 
916  if (tesseract_ == nullptr)
917  return -1;
918  if (thresholder_ == nullptr || thresholder_->IsEmpty()) {
919  tprintf("Please call SetImage before attempting recognition.\n");
920  return -1;
921  }
922  if (page_res_ != nullptr)
923  ClearResults();
924  if (FindLines() != 0)
925  return -1;
926  // Additional conditions under which chopper test cannot be run
927  if (tesseract_->interactive_display_mode) return -1;
928 
929  recognition_done_ = true;
930 
931  page_res_ = new PAGE_RES(false, block_list_,
933 
934  PAGE_RES_IT page_res_it(page_res_);
935 
936  while (page_res_it.word() != nullptr) {
937  WERD_RES *word_res = page_res_it.word();
938  GenericVector<TBOX> boxes;
939  tesseract_->MaximallyChopWord(boxes, page_res_it.block()->block,
940  page_res_it.row()->row, word_res);
941  page_res_it.forward();
942  }
943  return 0;
944 }
945 #endif // ndef DISABLED_LEGACY_ENGINE
946 
947 // Takes ownership of the input pix.
949 
951 
953  if (input_file_)
954  return input_file_->c_str();
955  return nullptr;
956 }
957 
958 const char * TessBaseAPI::GetDatapath() {
959  return tesseract_->datadir.c_str();
960 }
961 
964 }
965 
966 // If flist exists, get data from there. Otherwise get data from buf.
967 // Seems convoluted, but is the easiest way I know of to meet multiple
968 // goals. Support streaming from stdin, and also work on platforms
969 // lacking fmemopen.
970 bool TessBaseAPI::ProcessPagesFileList(FILE *flist,
971  STRING *buf,
972  const char* retry_config,
973  int timeout_millisec,
974  TessResultRenderer* renderer,
975  int tessedit_page_number) {
976  if (!flist && !buf) return false;
977  int page = (tessedit_page_number >= 0) ? tessedit_page_number : 0;
978  char pagename[MAX_PATH];
979 
980  GenericVector<STRING> lines;
981  if (!flist) {
982  buf->split('\n', &lines);
983  if (lines.empty()) return false;
984  }
985 
986  // Skip to the requested page number.
987  for (int i = 0; i < page; i++) {
988  if (flist) {
989  if (fgets(pagename, sizeof(pagename), flist) == nullptr) break;
990  }
991  }
992 
993  // Begin producing output
994  if (renderer && !renderer->BeginDocument(unknown_title_)) {
995  return false;
996  }
997 
998  // Loop over all pages - or just the requested one
999  while (true) {
1000  if (flist) {
1001  if (fgets(pagename, sizeof(pagename), flist) == nullptr) break;
1002  } else {
1003  if (page >= lines.size()) break;
1004  snprintf(pagename, sizeof(pagename), "%s", lines[page].c_str());
1005  }
1006  chomp_string(pagename);
1007  Pix *pix = pixRead(pagename);
1008  if (pix == nullptr) {
1009  tprintf("Image file %s cannot be read!\n", pagename);
1010  return false;
1011  }
1012  tprintf("Page %d : %s\n", page, pagename);
1013  bool r = ProcessPage(pix, page, pagename, retry_config,
1014  timeout_millisec, renderer);
1015  pixDestroy(&pix);
1016  if (!r) return false;
1017  if (tessedit_page_number >= 0) break;
1018  ++page;
1019  }
1020 
1021  // Finish producing output
1022  if (renderer && !renderer->EndDocument()) {
1023  return false;
1024  }
1025  return true;
1026 }
1027 
1028 bool TessBaseAPI::ProcessPagesMultipageTiff(const l_uint8 *data,
1029  size_t size,
1030  const char* filename,
1031  const char* retry_config,
1032  int timeout_millisec,
1033  TessResultRenderer* renderer,
1034  int tessedit_page_number) {
1035 #ifndef ANDROID_BUILD
1036  Pix *pix = nullptr;
1037  int page = (tessedit_page_number >= 0) ? tessedit_page_number : 0;
1038  size_t offset = 0;
1039  for (; ; ++page) {
1040  if (tessedit_page_number >= 0) {
1041  page = tessedit_page_number;
1042  pix = (data) ? pixReadMemTiff(data, size, page)
1043  : pixReadTiff(filename, page);
1044  } else {
1045  pix = (data) ? pixReadMemFromMultipageTiff(data, size, &offset)
1046  : pixReadFromMultipageTiff(filename, &offset);
1047  }
1048  if (pix == nullptr) break;
1049  tprintf("Page %d\n", page + 1);
1050  char page_str[kMaxIntSize];
1051  snprintf(page_str, kMaxIntSize - 1, "%d", page);
1052  SetVariable("applybox_page", page_str);
1053  bool r = ProcessPage(pix, page, filename, retry_config,
1054  timeout_millisec, renderer);
1055  pixDestroy(&pix);
1056  if (!r) return false;
1057  if (tessedit_page_number >= 0) break;
1058  if (!offset) break;
1059  }
1060  return true;
1061 #else
1062  return false;
1063 #endif
1064 }
1065 
1066 // Master ProcessPages calls ProcessPagesInternal and then does any post-
1067 // processing required due to being in a training mode.
1068 bool TessBaseAPI::ProcessPages(const char* filename, const char* retry_config,
1069  int timeout_millisec,
1070  TessResultRenderer* renderer) {
1071  bool result =
1072  ProcessPagesInternal(filename, retry_config, timeout_millisec, renderer);
1073  #ifndef DISABLED_LEGACY_ENGINE
1074  if (result) {
1077  tprintf("Write of TR file failed: %s\n", output_file_->string());
1078  return false;
1079  }
1080  }
1081  #endif // ndef DISABLED_LEGACY_ENGINE
1082  return result;
1083 }
1084 
1085 // In the ideal scenario, Tesseract will start working on data as soon
1086 // as it can. For example, if you stream a filelist through stdin, we
1087 // should start the OCR process as soon as the first filename is
1088 // available. This is particularly useful when hooking Tesseract up to
1089 // slow hardware such as a book scanning machine.
1090 //
1091 // Unfortunately there are tradeoffs. You can't seek on stdin. That
1092 // makes automatic detection of datatype (TIFF? filelist? PNG?)
1093 // impractical. So we support a command line flag to explicitly
1094 // identify the scenario that really matters: filelists on
1095 // stdin. We'll still do our best if the user likes pipes.
1096 bool TessBaseAPI::ProcessPagesInternal(const char* filename,
1097  const char* retry_config,
1098  int timeout_millisec,
1099  TessResultRenderer* renderer) {
1100  bool stdInput = !strcmp(filename, "stdin") || !strcmp(filename, "-");
1101  if (stdInput) {
1102 #ifdef WIN32
1103  if (_setmode(_fileno(stdin), _O_BINARY) == -1)
1104  tprintf("ERROR: cin to binary: %s", strerror(errno));
1105 #endif // WIN32
1106  }
1107 
1108  if (stream_filelist) {
1109  return ProcessPagesFileList(stdin, nullptr, retry_config,
1110  timeout_millisec, renderer,
1112  }
1113 
1114  // At this point we are officially in autodection territory.
1115  // That means any data in stdin must be buffered, to make it
1116  // seekable.
1117  std::string buf;
1118  const l_uint8 *data = nullptr;
1119  if (stdInput) {
1120  buf.assign((std::istreambuf_iterator<char>(std::cin)),
1121  (std::istreambuf_iterator<char>()));
1122  data = reinterpret_cast<const l_uint8 *>(buf.data());
1123  } else {
1124  // Check whether the input file can be read.
1125  if (FILE* file = fopen(filename, "rb")) {
1126  fclose(file);
1127  } else {
1128  fprintf(stderr, "Error, cannot read input file %s: %s\n",
1129  filename, strerror(errno));
1130  return false;
1131  }
1132  }
1133 
1134  // Here is our autodetection
1135  int format;
1136  int r = (stdInput) ?
1137  findFileFormatBuffer(data, &format) :
1138  findFileFormat(filename, &format);
1139 
1140  // Maybe we have a filelist
1141  if (r != 0 || format == IFF_UNKNOWN) {
1142  STRING s;
1143  if (stdInput) {
1144  s = buf.c_str();
1145  } else {
1146  std::ifstream t(filename);
1147  std::string u((std::istreambuf_iterator<char>(t)),
1148  std::istreambuf_iterator<char>());
1149  s = u.c_str();
1150  }
1151  return ProcessPagesFileList(nullptr, &s, retry_config,
1152  timeout_millisec, renderer,
1154  }
1155 
1156  // Maybe we have a TIFF which is potentially multipage
1157  bool tiff = (format == IFF_TIFF || format == IFF_TIFF_PACKBITS ||
1158  format == IFF_TIFF_RLE || format == IFF_TIFF_G3 ||
1159  format == IFF_TIFF_G4 || format == IFF_TIFF_LZW ||
1160 #if LIBLEPT_MAJOR_VERSION > 1 || LIBLEPT_MINOR_VERSION > 76
1161  format == IFF_TIFF_JPEG ||
1162 #endif
1163  format == IFF_TIFF_ZIP);
1164 
1165  // Fail early if we can, before producing any output
1166  Pix *pix = nullptr;
1167  if (!tiff) {
1168  pix = (stdInput) ? pixReadMem(data, buf.size()) : pixRead(filename);
1169  if (pix == nullptr) {
1170  return false;
1171  }
1172  }
1173 
1174  // Begin the output
1175  if (renderer && !renderer->BeginDocument(unknown_title_)) {
1176  pixDestroy(&pix);
1177  return false;
1178  }
1179 
1180  // Produce output
1181  r = (tiff) ?
1182  ProcessPagesMultipageTiff(data, buf.size(), filename, retry_config,
1183  timeout_millisec, renderer,
1185  ProcessPage(pix, 0, filename, retry_config,
1186  timeout_millisec, renderer);
1187 
1188  // Clean up memory as needed
1189  pixDestroy(&pix);
1190 
1191  // End the output
1192  if (!r || (renderer && !renderer->EndDocument())) {
1193  return false;
1194  }
1195  return true;
1196 }
1197 
1198 bool TessBaseAPI::ProcessPage(Pix* pix, int page_index, const char* filename,
1199  const char* retry_config, int timeout_millisec,
1200  TessResultRenderer* renderer) {
1201  SetInputName(filename);
1202  SetImage(pix);
1203  bool failed = false;
1204 
1206  // Disabled character recognition
1207  PageIterator* it = AnalyseLayout();
1208 
1209  if (it == nullptr) {
1210  failed = true;
1211  } else {
1212  delete it;
1213  }
1215  failed = FindLines() != 0;
1216  } else if (timeout_millisec > 0) {
1217  // Running with a timeout.
1218  ETEXT_DESC monitor;
1219  monitor.cancel = nullptr;
1220  monitor.cancel_this = nullptr;
1221  monitor.set_deadline_msecs(timeout_millisec);
1222 
1223  // Now run the main recognition.
1224  failed = Recognize(&monitor) < 0;
1225  } else {
1226  // Normal layout and character recognition with no timeout.
1227  failed = Recognize(nullptr) < 0;
1228  }
1229 
1231 #ifndef ANDROID_BUILD
1232  Pix* page_pix = GetThresholdedImage();
1233  pixWrite("tessinput.tif", page_pix, IFF_TIFF_G4);
1234 #endif // ANDROID_BUILD
1235  }
1236 
1237  if (failed && retry_config != nullptr && retry_config[0] != '\0') {
1238  // Save current config variables before switching modes.
1239  FILE* fp = fopen(kOldVarsFile, "wb");
1240  if (fp == nullptr) {
1241  tprintf("Error, failed to open file \"%s\"\n", kOldVarsFile);
1242  } else {
1243  PrintVariables(fp);
1244  fclose(fp);
1245  }
1246  // Switch to alternate mode for retry.
1247  ReadConfigFile(retry_config);
1248  SetImage(pix);
1249  Recognize(nullptr);
1250  // Restore saved config variables.
1251  ReadConfigFile(kOldVarsFile);
1252  }
1253 
1254  if (renderer && !failed) {
1255  failed = !renderer->AddImage(this);
1256  }
1257 
1258  return !failed;
1259 }
1260 
1266  if (tesseract_ == nullptr || page_res_ == nullptr)
1267  return nullptr;
1268  return new LTRResultIterator(
1272 }
1273 
1283  if (tesseract_ == nullptr || page_res_ == nullptr)
1284  return nullptr;
1289 }
1290 
1300  if (tesseract_ == nullptr || page_res_ == nullptr)
1301  return nullptr;
1302  return new MutableIterator(page_res_, tesseract_,
1306 }
1307 
1310  if (tesseract_ == nullptr ||
1311  (!recognition_done_ && Recognize(nullptr) < 0))
1312  return nullptr;
1313  STRING text("");
1314  ResultIterator *it = GetIterator();
1315  do {
1316  if (it->Empty(RIL_PARA)) continue;
1317  const std::unique_ptr<const char[]> para_text(it->GetUTF8Text(RIL_PARA));
1318  text += para_text.get();
1319  } while (it->Next(RIL_PARA));
1320  char* result = new char[text.length() + 1];
1321  strncpy(result, text.string(), text.length() + 1);
1322  delete it;
1323  return result;
1324 }
1325 
1326 static void AddBoxToTSV(const PageIterator* it, PageIteratorLevel level,
1327  STRING* text) {
1328  int left, top, right, bottom;
1329  it->BoundingBox(level, &left, &top, &right, &bottom);
1330  text->add_str_int("\t", left);
1331  text->add_str_int("\t", top);
1332  text->add_str_int("\t", right - left);
1333  text->add_str_int("\t", bottom - top);
1334 }
1335 
1341 char* TessBaseAPI::GetTSVText(int page_number) {
1342  if (tesseract_ == nullptr || (page_res_ == nullptr && Recognize(nullptr) < 0))
1343  return nullptr;
1344 
1345  int lcnt = 1, bcnt = 1, pcnt = 1, wcnt = 1;
1346  int page_id = page_number + 1; // we use 1-based page numbers.
1347 
1348  STRING tsv_str("");
1349 
1350  int page_num = page_id;
1351  int block_num = 0;
1352  int par_num = 0;
1353  int line_num = 0;
1354  int word_num = 0;
1355 
1356  tsv_str.add_str_int("1\t", page_num); // level 1 - page
1357  tsv_str.add_str_int("\t", block_num);
1358  tsv_str.add_str_int("\t", par_num);
1359  tsv_str.add_str_int("\t", line_num);
1360  tsv_str.add_str_int("\t", word_num);
1361  tsv_str.add_str_int("\t", rect_left_);
1362  tsv_str.add_str_int("\t", rect_top_);
1363  tsv_str.add_str_int("\t", rect_width_);
1364  tsv_str.add_str_int("\t", rect_height_);
1365  tsv_str += "\t-1\t\n";
1366 
1367  ResultIterator* res_it = GetIterator();
1368  while (!res_it->Empty(RIL_BLOCK)) {
1369  if (res_it->Empty(RIL_WORD)) {
1370  res_it->Next(RIL_WORD);
1371  continue;
1372  }
1373 
1374  // Add rows for any new block/paragraph/textline.
1375  if (res_it->IsAtBeginningOf(RIL_BLOCK)) {
1376  block_num++;
1377  par_num = 0;
1378  line_num = 0;
1379  word_num = 0;
1380  tsv_str.add_str_int("2\t", page_num); // level 2 - block
1381  tsv_str.add_str_int("\t", block_num);
1382  tsv_str.add_str_int("\t", par_num);
1383  tsv_str.add_str_int("\t", line_num);
1384  tsv_str.add_str_int("\t", word_num);
1385  AddBoxToTSV(res_it, RIL_BLOCK, &tsv_str);
1386  tsv_str += "\t-1\t\n"; // end of row for block
1387  }
1388  if (res_it->IsAtBeginningOf(RIL_PARA)) {
1389  par_num++;
1390  line_num = 0;
1391  word_num = 0;
1392  tsv_str.add_str_int("3\t", page_num); // level 3 - paragraph
1393  tsv_str.add_str_int("\t", block_num);
1394  tsv_str.add_str_int("\t", par_num);
1395  tsv_str.add_str_int("\t", line_num);
1396  tsv_str.add_str_int("\t", word_num);
1397  AddBoxToTSV(res_it, RIL_PARA, &tsv_str);
1398  tsv_str += "\t-1\t\n"; // end of row for para
1399  }
1400  if (res_it->IsAtBeginningOf(RIL_TEXTLINE)) {
1401  line_num++;
1402  word_num = 0;
1403  tsv_str.add_str_int("4\t", page_num); // level 4 - line
1404  tsv_str.add_str_int("\t", block_num);
1405  tsv_str.add_str_int("\t", par_num);
1406  tsv_str.add_str_int("\t", line_num);
1407  tsv_str.add_str_int("\t", word_num);
1408  AddBoxToTSV(res_it, RIL_TEXTLINE, &tsv_str);
1409  tsv_str += "\t-1\t\n"; // end of row for line
1410  }
1411 
1412  // Now, process the word...
1413  int left, top, right, bottom;
1414  res_it->BoundingBox(RIL_WORD, &left, &top, &right, &bottom);
1415  word_num++;
1416  tsv_str.add_str_int("5\t", page_num); // level 5 - word
1417  tsv_str.add_str_int("\t", block_num);
1418  tsv_str.add_str_int("\t", par_num);
1419  tsv_str.add_str_int("\t", line_num);
1420  tsv_str.add_str_int("\t", word_num);
1421  tsv_str.add_str_int("\t", left);
1422  tsv_str.add_str_int("\t", top);
1423  tsv_str.add_str_int("\t", right - left);
1424  tsv_str.add_str_int("\t", bottom - top);
1425  tsv_str.add_str_int("\t", res_it->Confidence(RIL_WORD));
1426  tsv_str += "\t";
1427 
1428  // Increment counts if at end of block/paragraph/textline.
1429  if (res_it->IsAtFinalElement(RIL_TEXTLINE, RIL_WORD)) lcnt++;
1430  if (res_it->IsAtFinalElement(RIL_PARA, RIL_WORD)) pcnt++;
1431  if (res_it->IsAtFinalElement(RIL_BLOCK, RIL_WORD)) bcnt++;
1432 
1433  do {
1434  tsv_str +=
1435  std::unique_ptr<const char[]>(res_it->GetUTF8Text(RIL_SYMBOL)).get();
1436  res_it->Next(RIL_SYMBOL);
1437  } while (!res_it->Empty(RIL_BLOCK) && !res_it->IsAtBeginningOf(RIL_WORD));
1438  tsv_str += "\n"; // end of row
1439  wcnt++;
1440  }
1441 
1442  char* ret = new char[tsv_str.length() + 1];
1443  strcpy(ret, tsv_str.string());
1444  delete res_it;
1445  return ret;
1446 }
1447 
1449 const int kNumbersPerBlob = 5;
1454 const int kBytesPerNumber = 5;
1460 const int kBytesPerBoxFileLine = (kBytesPerNumber + 1) * kNumbersPerBlob + 1;
1462 const int kBytesPer64BitNumber = 20;
1469 const int kMaxBytesPerLine = kNumbersPerBlob * (kBytesPer64BitNumber + 1) + 1 +
1470  UNICHAR_LEN;
1471 
1478 char* TessBaseAPI::GetBoxText(int page_number) {
1479  if (tesseract_ == nullptr ||
1480  (!recognition_done_ && Recognize(nullptr) < 0))
1481  return nullptr;
1482  int blob_count;
1483  int utf8_length = TextLength(&blob_count);
1484  int total_length = blob_count * kBytesPerBoxFileLine + utf8_length +
1486  char* result = new char[total_length];
1487  result[0] = '\0';
1488  int output_length = 0;
1490  do {
1491  int left, top, right, bottom;
1492  if (it->BoundingBox(RIL_SYMBOL, &left, &top, &right, &bottom)) {
1493  const std::unique_ptr</*non-const*/ char[]> text(
1494  it->GetUTF8Text(RIL_SYMBOL));
1495  // Tesseract uses space for recognition failure. Fix to a reject
1496  // character, kTesseractReject so we don't create illegal box files.
1497  for (int i = 0; text[i] != '\0'; ++i) {
1498  if (text[i] == ' ')
1499  text[i] = kTesseractReject;
1500  }
1501  snprintf(result + output_length, total_length - output_length,
1502  "%s %d %d %d %d %d\n", text.get(), left, image_height_ - bottom,
1503  right, image_height_ - top, page_number);
1504  output_length += strlen(result + output_length);
1505  // Just in case...
1506  if (output_length + kMaxBytesPerLine > total_length)
1507  break;
1508  }
1509  } while (it->Next(RIL_SYMBOL));
1510  delete it;
1511  return result;
1512 }
1513 
1519 const int kUniChs[] = {
1520  0x20ac, 0x201c, 0x201d, 0x2018, 0x2019, 0x2022, 0x2014, 0
1521 };
1523 const int kLatinChs[] = {
1524  0x00a2, 0x0022, 0x0022, 0x0027, 0x0027, 0x00b7, 0x002d, 0
1525 };
1526 
1533  if (tesseract_ == nullptr ||
1534  (!recognition_done_ && Recognize(nullptr) < 0))
1535  return nullptr;
1536  bool tilde_crunch_written = false;
1537  bool last_char_was_newline = true;
1538  bool last_char_was_tilde = false;
1539 
1540  int total_length = TextLength(nullptr);
1541  PAGE_RES_IT page_res_it(page_res_);
1542  char* result = new char[total_length];
1543  char* ptr = result;
1544  for (page_res_it.restart_page(); page_res_it.word () != nullptr;
1545  page_res_it.forward()) {
1546  WERD_RES *word = page_res_it.word();
1547  // Process the current word.
1548  if (word->unlv_crunch_mode != CR_NONE) {
1549  if (word->unlv_crunch_mode != CR_DELETE &&
1550  (!tilde_crunch_written ||
1551  (word->unlv_crunch_mode == CR_KEEP_SPACE &&
1552  word->word->space() > 0 &&
1553  !word->word->flag(W_FUZZY_NON) &&
1554  !word->word->flag(W_FUZZY_SP)))) {
1555  if (!word->word->flag(W_BOL) &&
1556  word->word->space() > 0 &&
1557  !word->word->flag(W_FUZZY_NON) &&
1558  !word->word->flag(W_FUZZY_SP)) {
1559  /* Write a space to separate from preceding good text */
1560  *ptr++ = ' ';
1561  last_char_was_tilde = false;
1562  }
1563  if (!last_char_was_tilde) {
1564  // Write a reject char.
1565  last_char_was_tilde = true;
1566  *ptr++ = kUNLVReject;
1567  tilde_crunch_written = true;
1568  last_char_was_newline = false;
1569  }
1570  }
1571  } else {
1572  // NORMAL PROCESSING of non tilde crunched words.
1573  tilde_crunch_written = false;
1575  const char* wordstr = word->best_choice->unichar_string().string();
1576  const STRING& lengths = word->best_choice->unichar_lengths();
1577  int length = lengths.length();
1578  int i = 0;
1579  int offset = 0;
1580 
1581  if (last_char_was_tilde &&
1582  word->word->space() == 0 && wordstr[offset] == ' ') {
1583  // Prevent adjacent tilde across words - we know that adjacent tildes
1584  // within words have been removed.
1585  // Skip the first character.
1586  offset = lengths[i++];
1587  }
1588  if (i < length && wordstr[offset] != 0) {
1589  if (!last_char_was_newline)
1590  *ptr++ = ' ';
1591  else
1592  last_char_was_newline = false;
1593  for (; i < length; offset += lengths[i++]) {
1594  if (wordstr[offset] == ' ' ||
1595  wordstr[offset] == kTesseractReject) {
1596  *ptr++ = kUNLVReject;
1597  last_char_was_tilde = true;
1598  } else {
1599  if (word->reject_map[i].rejected())
1600  *ptr++ = kUNLVSuspect;
1601  UNICHAR ch(wordstr + offset, lengths[i]);
1602  int uni_ch = ch.first_uni();
1603  for (int j = 0; kUniChs[j] != 0; ++j) {
1604  if (kUniChs[j] == uni_ch) {
1605  uni_ch = kLatinChs[j];
1606  break;
1607  }
1608  }
1609  if (uni_ch <= 0xff) {
1610  *ptr++ = static_cast<char>(uni_ch);
1611  last_char_was_tilde = false;
1612  } else {
1613  *ptr++ = kUNLVReject;
1614  last_char_was_tilde = true;
1615  }
1616  }
1617  }
1618  }
1619  }
1620  if (word->word->flag(W_EOL) && !last_char_was_newline) {
1621  /* Add a new line output */
1622  *ptr++ = '\n';
1623  tilde_crunch_written = false;
1624  last_char_was_newline = true;
1625  last_char_was_tilde = false;
1626  }
1627  }
1628  *ptr++ = '\n';
1629  *ptr = '\0';
1630  return result;
1631 }
1632 
1633 #ifndef DISABLED_LEGACY_ENGINE
1634 
1644 bool TessBaseAPI::DetectOrientationScript(int* orient_deg, float* orient_conf,
1645  const char** script_name,
1646  float* script_conf) {
1647  OSResults osr;
1648 
1649  bool osd = DetectOS(&osr);
1650  if (!osd) {
1651  return false;
1652  }
1653 
1654  int orient_id = osr.best_result.orientation_id;
1655  int script_id = osr.get_best_script(orient_id);
1656  if (orient_conf) *orient_conf = osr.best_result.oconfidence;
1657  if (orient_deg) *orient_deg = orient_id * 90; // convert quadrant to degrees
1658 
1659  if (script_name) {
1660  const char* script = osr.unicharset->get_script_from_script_id(script_id);
1661 
1662  *script_name = script;
1663  }
1664 
1665  if (script_conf) *script_conf = osr.best_result.sconfidence;
1666 
1667  return true;
1668 }
1669 
1675 char* TessBaseAPI::GetOsdText(int page_number) {
1676  int orient_deg;
1677  float orient_conf;
1678  const char* script_name;
1679  float script_conf;
1680 
1681  if (!DetectOrientationScript(&orient_deg, &orient_conf, &script_name,
1682  &script_conf))
1683  return nullptr;
1684 
1685  // clockwise rotation needed to make the page upright
1686  int rotate = OrientationIdToValue(orient_deg / 90);
1687 
1688  std::stringstream stream;
1689  // Use "C" locale (needed for float values orient_conf and script_conf).
1690  stream.imbue(std::locale::classic());
1691  // Use fixed notation with 2 digits after the decimal point for float values.
1692  stream.precision(2);
1693  stream
1694  << std::fixed
1695  << "Page number: " << page_number << "\n"
1696  << "Orientation in degrees: " << orient_deg << "\n"
1697  << "Rotate: " << rotate << "\n"
1698  << "Orientation confidence: " << orient_conf << "\n"
1699  << "Script: " << script_name << "\n"
1700  << "Script confidence: " << script_conf << "\n";
1701  const std::string& text = stream.str();
1702  char* result = new char[text.length() + 1];
1703  strcpy(result, text.c_str());
1704  return result;
1705 }
1706 
1707 #endif // ndef DISABLED_LEGACY_ENGINE
1708 
1711  int* conf = AllWordConfidences();
1712  if (!conf) return 0;
1713  int sum = 0;
1714  int *pt = conf;
1715  while (*pt >= 0) sum += *pt++;
1716  if (pt != conf) sum /= pt - conf;
1717  delete [] conf;
1718  return sum;
1719 }
1720 
1723  if (tesseract_ == nullptr ||
1724  (!recognition_done_ && Recognize(nullptr) < 0))
1725  return nullptr;
1726  int n_word = 0;
1727  PAGE_RES_IT res_it(page_res_);
1728  for (res_it.restart_page(); res_it.word() != nullptr; res_it.forward())
1729  n_word++;
1730 
1731  int* conf = new int[n_word+1];
1732  n_word = 0;
1733  for (res_it.restart_page(); res_it.word() != nullptr; res_it.forward()) {
1734  WERD_RES *word = res_it.word();
1735  WERD_CHOICE* choice = word->best_choice;
1736  int w_conf = static_cast<int>(100 + 5 * choice->certainty());
1737  // This is the eq for converting Tesseract confidence to 1..100
1738  if (w_conf < 0) w_conf = 0;
1739  if (w_conf > 100) w_conf = 100;
1740  conf[n_word++] = w_conf;
1741  }
1742  conf[n_word] = -1;
1743  return conf;
1744 }
1745 
1746 #ifndef DISABLED_LEGACY_ENGINE
1747 
1757 bool TessBaseAPI::AdaptToWordStr(PageSegMode mode, const char* wordstr) {
1758  int debug = 0;
1759  GetIntVariable("applybox_debug", &debug);
1760  bool success = true;
1761  PageSegMode current_psm = GetPageSegMode();
1762  SetPageSegMode(mode);
1763  SetVariable("classify_enable_learning", "0");
1764  const std::unique_ptr<const char[]> text(GetUTF8Text());
1765  if (debug) {
1766  tprintf("Trying to adapt \"%s\" to \"%s\"\n", text.get(), wordstr);
1767  }
1768  if (text != nullptr) {
1769  PAGE_RES_IT it(page_res_);
1770  WERD_RES* word_res = it.word();
1771  if (word_res != nullptr) {
1772  word_res->word->set_text(wordstr);
1773  // Check to see if text matches wordstr.
1774  int w = 0;
1775  int t;
1776  for (t = 0; text[t] != '\0'; ++t) {
1777  if (text[t] == '\n' || text[t] == ' ')
1778  continue;
1779  while (wordstr[w] == ' ') ++w;
1780  if (text[t] != wordstr[w])
1781  break;
1782  ++w;
1783  }
1784  if (text[t] != '\0' || wordstr[w] != '\0') {
1785  // No match.
1786  delete page_res_;
1787  GenericVector<TBOX> boxes;
1791  PAGE_RES_IT pr_it(page_res_);
1792  if (pr_it.word() == nullptr)
1793  success = false;
1794  else
1795  word_res = pr_it.word();
1796  } else {
1797  word_res->BestChoiceToCorrectText();
1798  }
1799  if (success) {
1800  tesseract_->EnableLearning = true;
1801  tesseract_->LearnWord(nullptr, word_res);
1802  }
1803  } else {
1804  success = false;
1805  }
1806  } else {
1807  success = false;
1808  }
1809  SetPageSegMode(current_psm);
1810  return success;
1811 }
1812 #endif // ndef DISABLED_LEGACY_ENGINE
1813 
1821  if (thresholder_ != nullptr)
1822  thresholder_->Clear();
1823  ClearResults();
1824  if (tesseract_ != nullptr) SetInputImage(nullptr);
1825 }
1826 
1834  Clear();
1835  delete thresholder_;
1836  thresholder_ = nullptr;
1837  delete page_res_;
1838  page_res_ = nullptr;
1839  delete block_list_;
1840  block_list_ = nullptr;
1841  if (paragraph_models_ != nullptr) {
1843  delete paragraph_models_;
1844  paragraph_models_ = nullptr;
1845  }
1846  if (osd_tesseract_ == tesseract_) osd_tesseract_ = nullptr;
1847  delete tesseract_;
1848  tesseract_ = nullptr;
1849  delete osd_tesseract_;
1850  osd_tesseract_ = nullptr;
1851  delete equ_detect_;
1852  equ_detect_ = nullptr;
1853  delete input_file_;
1854  input_file_ = nullptr;
1855  delete output_file_;
1856  output_file_ = nullptr;
1857  delete datapath_;
1858  datapath_ = nullptr;
1859  delete language_;
1860  language_ = nullptr;
1861 }
1862 
1863 // Clear any library-level memory caches.
1864 // There are a variety of expensive-to-load constant data structures (mostly
1865 // language dictionaries) that are cached globally -- surviving the Init()
1866 // and End() of individual TessBaseAPI's. This function allows the clearing
1867 // of these caches.
1870 }
1871 
1876 int TessBaseAPI::IsValidWord(const char *word) {
1877  return tesseract_->getDict().valid_word(word);
1878 }
1879 // Returns true if utf8_character is defined in the UniCharset.
1880 bool TessBaseAPI::IsValidCharacter(const char *utf8_character) {
1881  return tesseract_->unicharset.contains_unichar(utf8_character);
1882 }
1883 
1884 
1885 // TODO(rays) Obsolete this function and replace with a more aptly named
1886 // function that returns image coordinates rather than tesseract coordinates.
1887 bool TessBaseAPI::GetTextDirection(int* out_offset, float* out_slope) {
1888  PageIterator* it = AnalyseLayout();
1889  if (it == nullptr) {
1890  return false;
1891  }
1892  int x1, x2, y1, y2;
1893  it->Baseline(RIL_TEXTLINE, &x1, &y1, &x2, &y2);
1894  // Calculate offset and slope (NOTE: Kind of ugly)
1895  if (x2 <= x1) x2 = x1 + 1;
1896  // Convert the point pair to slope/offset of the baseline (in image coords.)
1897  *out_slope = static_cast<float>(y2 - y1) / (x2 - x1);
1898  *out_offset = static_cast<int>(y1 - *out_slope * x1);
1899  // Get the y-coord of the baseline at the left and right edges of the
1900  // textline's bounding box.
1901  int left, top, right, bottom;
1902  if (!it->BoundingBox(RIL_TEXTLINE, &left, &top, &right, &bottom)) {
1903  delete it;
1904  return false;
1905  }
1906  int left_y = IntCastRounded(*out_slope * left + *out_offset);
1907  int right_y = IntCastRounded(*out_slope * right + *out_offset);
1908  // Shift the baseline down so it passes through the nearest bottom-corner
1909  // of the textline's bounding box. This is the difference between the y
1910  // at the lowest (max) edge of the box and the actual box bottom.
1911  *out_offset += bottom - std::max(left_y, right_y);
1912  // Switch back to bottom-up tesseract coordinates. Requires negation of
1913  // the slope and height - offset for the offset.
1914  *out_slope = -*out_slope;
1915  *out_offset = rect_height_ - *out_offset;
1916  delete it;
1917 
1918  return true;
1919 }
1920 
1923  if (tesseract_ != nullptr) {
1925  }
1926 }
1927 
1937  if (tesseract_ != nullptr) {
1939  // Set it for the sublangs too.
1940  int num_subs = tesseract_->num_sub_langs();
1941  for (int i = 0; i < num_subs; ++i) {
1943  }
1944  }
1945 }
1946 
1947 #ifndef DISABLED_LEGACY_ENGINE
1948 
1950  if (tesseract_ != nullptr) tesseract_->fill_lattice_ = f;
1951 }
1952 #endif // ndef DISABLED_LEGACY_ENGINE
1953 
1956  if (tesseract_ == nullptr) {
1957  tprintf("Please call Init before attempting to set an image.\n");
1958  return false;
1959  }
1960  if (thresholder_ == nullptr)
1962  ClearResults();
1963  return true;
1964 }
1965 
1972 bool TessBaseAPI::Threshold(Pix** pix) {
1973  ASSERT_HOST(pix != nullptr);
1974  if (*pix != nullptr)
1975  pixDestroy(pix);
1976  // Zero resolution messes up the algorithms, so make sure it is credible.
1977  int user_dpi = 0;
1978  GetIntVariable("user_defined_dpi", &user_dpi);
1979  int y_res = thresholder_->GetScaledYResolution();
1980  if (user_dpi && (user_dpi < kMinCredibleResolution ||
1981  user_dpi > kMaxCredibleResolution)) {
1982  tprintf("Warning: User defined image dpi is outside of expected range "
1983  "(%d - %d)!\n",
1985  }
1986  // Always use user defined dpi
1987  if (user_dpi) {
1989  } else if (y_res < kMinCredibleResolution ||
1990  y_res > kMaxCredibleResolution) {
1991  tprintf("Warning: Invalid resolution %d dpi. Using %d instead.\n",
1992  y_res, kMinCredibleResolution);
1994  }
1995  auto pageseg_mode =
1996  static_cast<PageSegMode>(
1997  static_cast<int>(tesseract_->tessedit_pageseg_mode));
1998  if (!thresholder_->ThresholdToPix(pageseg_mode, pix)) return false;
2002  if (!thresholder_->IsBinary()) {
2005  } else {
2006  tesseract_->set_pix_thresholds(nullptr);
2007  tesseract_->set_pix_grey(nullptr);
2008  }
2009  // Set the internal resolution that is used for layout parameters from the
2010  // estimated resolution, rather than the image resolution, which may be
2011  // fabricated, but we will use the image resolution, if there is one, to
2012  // report output point sizes.
2013  int estimated_res = ClipToRange(thresholder_->GetScaledEstimatedResolution(),
2016  if (estimated_res != thresholder_->GetScaledEstimatedResolution()) {
2017  tprintf("Estimated internal resolution %d out of range! "
2018  "Corrected to %d.\n",
2019  thresholder_->GetScaledEstimatedResolution(), estimated_res);
2020  }
2021  tesseract_->set_source_resolution(estimated_res);
2022  return true;
2023 }
2024 
2027  if (thresholder_ == nullptr || thresholder_->IsEmpty()) {
2028  tprintf("Please call SetImage before attempting recognition.\n");
2029  return -1;
2030  }
2031  if (recognition_done_)
2032  ClearResults();
2033  if (!block_list_->empty()) {
2034  return 0;
2035  }
2036  if (tesseract_ == nullptr) {
2037  tesseract_ = new Tesseract;
2038  #ifndef DISABLED_LEGACY_ENGINE
2040  #endif
2041  }
2042  if (tesseract_->pix_binary() == nullptr &&
2044  return -1;
2045  }
2046 
2048 
2049 #ifndef DISABLED_LEGACY_ENGINE
2051  if (equ_detect_ == nullptr && datapath_ != nullptr) {
2052  equ_detect_ = new EquationDetect(datapath_->string(), nullptr);
2053  }
2054  if (equ_detect_ == nullptr) {
2055  tprintf("Warning: Could not set equation detector\n");
2056  } else {
2058  }
2059  }
2060 #endif // ndef DISABLED_LEGACY_ENGINE
2061 
2062  Tesseract* osd_tess = osd_tesseract_;
2063  OSResults osr;
2065  osd_tess == nullptr) {
2066  if (strcmp(language_->string(), "osd") == 0) {
2067  osd_tess = tesseract_;
2068  } else {
2069  osd_tesseract_ = new Tesseract;
2070  TessdataManager mgr(reader_);
2071  if (datapath_ == nullptr) {
2072  tprintf("Warning: Auto orientation and script detection requested,"
2073  " but data path is undefined\n");
2074  delete osd_tesseract_;
2075  osd_tesseract_ = nullptr;
2076  } else if (osd_tesseract_->init_tesseract(datapath_->string(), nullptr,
2077  "osd", OEM_TESSERACT_ONLY,
2078  nullptr, 0, nullptr, nullptr,
2079  false, &mgr) == 0) {
2080  osd_tess = osd_tesseract_;
2083  } else {
2084  tprintf("Warning: Auto orientation and script detection requested,"
2085  " but osd language failed to load\n");
2086  delete osd_tesseract_;
2087  osd_tesseract_ = nullptr;
2088  }
2089  }
2090  }
2091 
2092  if (tesseract_->SegmentPage(input_file_, block_list_, osd_tess, &osr) < 0)
2093  return -1;
2094 
2095  // If Devanagari is being recognized, we use different images for page seg
2096  // and for OCR.
2097  tesseract_->PrepareForTessOCR(block_list_, osd_tess, &osr);
2098  return 0;
2099 }
2100 
2103  if (tesseract_ != nullptr) {
2104  tesseract_->Clear();
2105  }
2106  delete page_res_;
2107  page_res_ = nullptr;
2108  recognition_done_ = false;
2109  if (block_list_ == nullptr)
2110  block_list_ = new BLOCK_LIST;
2111  else
2112  block_list_->clear();
2113  if (paragraph_models_ != nullptr) {
2115  delete paragraph_models_;
2116  paragraph_models_ = nullptr;
2117  }
2118 }
2119 
2127 int TessBaseAPI::TextLength(int* blob_count) {
2128  if (tesseract_ == nullptr || page_res_ == nullptr)
2129  return 0;
2130 
2131  PAGE_RES_IT page_res_it(page_res_);
2132  int total_length = 2;
2133  int total_blobs = 0;
2134  // Iterate over the data structures to extract the recognition result.
2135  for (page_res_it.restart_page(); page_res_it.word () != nullptr;
2136  page_res_it.forward()) {
2137  WERD_RES *word = page_res_it.word();
2138  WERD_CHOICE* choice = word->best_choice;
2139  if (choice != nullptr) {
2140  total_blobs += choice->length() + 2;
2141  total_length += choice->unichar_string().length() + 2;
2142  for (int i = 0; i < word->reject_map.length(); ++i) {
2143  if (word->reject_map[i].rejected())
2144  ++total_length;
2145  }
2146  }
2147  }
2148  if (blob_count != nullptr)
2149  *blob_count = total_blobs;
2150  return total_length;
2151 }
2152 
2153 #ifndef DISABLED_LEGACY_ENGINE
2154 
2159  if (tesseract_ == nullptr)
2160  return false;
2161  ClearResults();
2162  if (tesseract_->pix_binary() == nullptr &&
2164  return false;
2165  }
2166 
2167  if (input_file_ == nullptr)
2168  input_file_ = new STRING(kInputFile);
2170 }
2171 #endif // ndef DISABLED_LEGACY_ENGINE
2172 
2174  tesseract_->min_orientation_margin.set_value(margin);
2175 }
2176 
2191 void TessBaseAPI::GetBlockTextOrientations(int** block_orientation,
2192  bool** vertical_writing) {
2193  delete[] *block_orientation;
2194  *block_orientation = nullptr;
2195  delete[] *vertical_writing;
2196  *vertical_writing = nullptr;
2197  BLOCK_IT block_it(block_list_);
2198 
2199  block_it.move_to_first();
2200  int num_blocks = 0;
2201  for (block_it.mark_cycle_pt(); !block_it.cycled_list(); block_it.forward()) {
2202  if (!block_it.data()->pdblk.poly_block()->IsText()) {
2203  continue;
2204  }
2205  ++num_blocks;
2206  }
2207  if (!num_blocks) {
2208  tprintf("WARNING: Found no blocks\n");
2209  return;
2210  }
2211  *block_orientation = new int[num_blocks];
2212  *vertical_writing = new bool[num_blocks];
2213  block_it.move_to_first();
2214  int i = 0;
2215  for (block_it.mark_cycle_pt(); !block_it.cycled_list();
2216  block_it.forward()) {
2217  if (!block_it.data()->pdblk.poly_block()->IsText()) {
2218  continue;
2219  }
2220  FCOORD re_rotation = block_it.data()->re_rotation();
2221  float re_theta = re_rotation.angle();
2222  FCOORD classify_rotation = block_it.data()->classify_rotation();
2223  float classify_theta = classify_rotation.angle();
2224  double rot_theta = - (re_theta - classify_theta) * 2.0 / M_PI;
2225  if (rot_theta < 0) rot_theta += 4;
2226  int num_rotations = static_cast<int>(rot_theta + 0.5);
2227  (*block_orientation)[i] = num_rotations;
2228  // The classify_rotation is non-zero only if the text has vertical
2229  // writing direction.
2230  (*vertical_writing)[i] = classify_rotation.y() != 0.0f;
2231  ++i;
2232  }
2233 }
2234 
2235 
2236 void TessBaseAPI::DetectParagraphs(bool after_text_recognition) {
2237  int debug_level = 0;
2238  GetIntVariable("paragraph_debug_level", &debug_level);
2239  if (paragraph_models_ == nullptr)
2241  MutableIterator *result_it = GetMutableIterator();
2242  do { // Detect paragraphs for this block
2244  ::tesseract::DetectParagraphs(debug_level, after_text_recognition,
2245  result_it, &models);
2246  *paragraph_models_ += models;
2247  } while (result_it->Next(RIL_BLOCK));
2248  delete result_it;
2249 }
2250 
2252 const char* TessBaseAPI::GetUnichar(int unichar_id) {
2253  return tesseract_->unicharset.id_to_unichar(unichar_id);
2254 }
2255 
2257 const Dawg *TessBaseAPI::GetDawg(int i) const {
2258  if (tesseract_ == nullptr || i >= NumDawgs()) return nullptr;
2259  return tesseract_->getDict().GetDawg(i);
2260 }
2261 
2264  return tesseract_ == nullptr ? 0 : tesseract_->getDict().NumDawgs();
2265 }
2266 
2268 STRING HOcrEscape(const char* text) {
2269  STRING ret;
2270  const char *ptr;
2271  for (ptr = text; *ptr; ptr++) {
2272  switch (*ptr) {
2273  case '<': ret += "&lt;"; break;
2274  case '>': ret += "&gt;"; break;
2275  case '&': ret += "&amp;"; break;
2276  case '"': ret += "&quot;"; break;
2277  case '\'': ret += "&#39;"; break;
2278  default: ret += *ptr;
2279  }
2280  }
2281  return ret;
2282 }
2283 
2284 
2285 #ifndef DISABLED_LEGACY_ENGINE
2286 
2287 
2288 // ____________________________________________________________________________
2289 // Ocropus add-ons.
2290 
2293  ASSERT_HOST(FindLines() == 0);
2294  BLOCK_LIST* result = block_list_;
2295  block_list_ = nullptr;
2296  return result;
2297 }
2298 
2304 void TessBaseAPI::DeleteBlockList(BLOCK_LIST *block_list) {
2305  delete block_list;
2306 }
2307 
2308 
2310  float xheight,
2311  float descender,
2312  float ascender) {
2313  int32_t xstarts[] = {-32000};
2314  double quad_coeffs[] = {0, 0, baseline};
2315  return new ROW(1,
2316  xstarts,
2317  quad_coeffs,
2318  xheight,
2319  ascender - (baseline + xheight),
2320  descender - baseline,
2321  0,
2322  0);
2323 }
2324 
2327  int width = pixGetWidth(pix);
2328  int height = pixGetHeight(pix);
2329  BLOCK block("a character", true, 0, 0, 0, 0, width, height);
2330 
2331  // Create C_BLOBs from the page
2332  extract_edges(pix, &block);
2333 
2334  // Merge all C_BLOBs
2335  C_BLOB_LIST *list = block.blob_list();
2336  C_BLOB_IT c_blob_it(list);
2337  if (c_blob_it.empty())
2338  return nullptr;
2339  // Move all the outlines to the first blob.
2340  C_OUTLINE_IT ol_it(c_blob_it.data()->out_list());
2341  for (c_blob_it.forward();
2342  !c_blob_it.at_first();
2343  c_blob_it.forward()) {
2344  C_BLOB *c_blob = c_blob_it.data();
2345  ol_it.add_list_after(c_blob->out_list());
2346  }
2347  // Convert the first blob to the output TBLOB.
2348  return TBLOB::PolygonalCopy(false, c_blob_it.data());
2349 }
2350 
2356 void TessBaseAPI::NormalizeTBLOB(TBLOB *tblob, ROW *row, bool numeric_mode) {
2357  TBOX box = tblob->bounding_box();
2358  float x_center = (box.left() + box.right()) / 2.0f;
2359  float baseline = row->base_line(x_center);
2360  float scale = kBlnXHeight / row->x_height();
2361  tblob->Normalize(nullptr, nullptr, nullptr, x_center, baseline, scale, scale,
2362  0.0f, static_cast<float>(kBlnBaselineOffset), false, nullptr);
2363 }
2364 
2369 static TBLOB *make_tesseract_blob(float baseline, float xheight,
2370  float descender, float ascender,
2371  bool numeric_mode, Pix* pix) {
2372  TBLOB *tblob = TessBaseAPI::MakeTBLOB(pix);
2373 
2374  // Normalize TBLOB
2375  ROW *row =
2376  TessBaseAPI::MakeTessOCRRow(baseline, xheight, descender, ascender);
2377  TessBaseAPI::NormalizeTBLOB(tblob, row, numeric_mode);
2378  delete row;
2379  return tblob;
2380 }
2381 
2387 void TessBaseAPI::AdaptToCharacter(const char *unichar_repr,
2388  int length,
2389  float baseline,
2390  float xheight,
2391  float descender,
2392  float ascender) {
2393  UNICHAR_ID id = tesseract_->unicharset.unichar_to_id(unichar_repr, length);
2394  TBLOB *blob = make_tesseract_blob(baseline, xheight, descender, ascender,
2396  tesseract_->pix_binary());
2397  float threshold;
2398  float best_rating = -100;
2399 
2400 
2401  // Classify to get a raw choice.
2402  BLOB_CHOICE_LIST choices;
2403  tesseract_->AdaptiveClassifier(blob, &choices);
2404  BLOB_CHOICE_IT choice_it;
2405  choice_it.set_to_list(&choices);
2406  for (choice_it.mark_cycle_pt(); !choice_it.cycled_list();
2407  choice_it.forward()) {
2408  if (choice_it.data()->rating() > best_rating) {
2409  best_rating = choice_it.data()->rating();
2410  }
2411  }
2412 
2413  threshold = tesseract_->matcher_good_threshold;
2414 
2415  if (blob->outlines)
2416  tesseract_->AdaptToChar(blob, id, kUnknownFontinfoId, threshold,
2418  delete blob;
2419 }
2420 
2421 
2422 PAGE_RES* TessBaseAPI::RecognitionPass1(BLOCK_LIST* block_list) {
2423  auto *page_res = new PAGE_RES(false, block_list,
2425  tesseract_->recog_all_words(page_res, nullptr, nullptr, nullptr, 1);
2426  return page_res;
2427 }
2428 
2429 PAGE_RES* TessBaseAPI::RecognitionPass2(BLOCK_LIST* block_list,
2430  PAGE_RES* pass1_result) {
2431  if (!pass1_result)
2432  pass1_result = new PAGE_RES(false, block_list,
2434  tesseract_->recog_all_words(pass1_result, nullptr, nullptr, nullptr, 2);
2435  return pass1_result;
2436 }
2437 
2440  int length; // of unicode_repr
2441  float cost;
2443 
2444  TESS_CHAR(float _cost, const char *repr, int len = -1) : cost(_cost) {
2445  length = (len == -1 ? strlen(repr) : len);
2446  unicode_repr = new char[length + 1];
2447  strncpy(unicode_repr, repr, length);
2448  }
2449 
2451  : unicode_repr(nullptr),
2452  length(0),
2453  cost(0.0f)
2454  { // Satisfies ELISTIZE.
2455  }
2457  delete [] unicode_repr;
2458  }
2459 };
2460 
2463 
2464 static void add_space(TESS_CHAR_IT* it) {
2465  auto *t = new TESS_CHAR(0, " ");
2466  it->add_after_then_move(t);
2467 }
2468 
2469 
2470 static float rating_to_cost(float rating) {
2471  rating = 100 + rating;
2472  // cuddled that to save from coverage profiler
2473  // (I have never seen ratings worse than -100,
2474  // but the check won't hurt)
2475  if (rating < 0) rating = 0;
2476  return rating;
2477 }
2478 
2483 static void extract_result(TESS_CHAR_IT* out,
2484  PAGE_RES* page_res) {
2485  PAGE_RES_IT page_res_it(page_res);
2486  int word_count = 0;
2487  while (page_res_it.word() != nullptr) {
2488  WERD_RES *word = page_res_it.word();
2489  const char *str = word->best_choice->unichar_string().string();
2490  const char *len = word->best_choice->unichar_lengths().string();
2491  TBOX real_rect = word->word->bounding_box();
2492 
2493  if (word_count)
2494  add_space(out);
2495  int n = strlen(len);
2496  for (int i = 0; i < n; i++) {
2497  auto *tc = new TESS_CHAR(rating_to_cost(word->best_choice->rating()),
2498  str, *len);
2499  tc->box = real_rect.intersection(word->box_word->BlobBox(i));
2500  out->add_after_then_move(tc);
2501  str += *len;
2502  len++;
2503  }
2504  page_res_it.forward();
2505  word_count++;
2506  }
2507 }
2508 
2514  int** lengths,
2515  float** costs,
2516  int** x0,
2517  int** y0,
2518  int** x1,
2519  int** y1,
2520  PAGE_RES* page_res) {
2521  TESS_CHAR_LIST tess_chars;
2522  TESS_CHAR_IT tess_chars_it(&tess_chars);
2523  extract_result(&tess_chars_it, page_res);
2524  tess_chars_it.move_to_first();
2525  int n = tess_chars.length();
2526  int text_len = 0;
2527  *lengths = new int[n];
2528  *costs = new float[n];
2529  *x0 = new int[n];
2530  *y0 = new int[n];
2531  *x1 = new int[n];
2532  *y1 = new int[n];
2533  int i = 0;
2534  for (tess_chars_it.mark_cycle_pt();
2535  !tess_chars_it.cycled_list();
2536  tess_chars_it.forward(), i++) {
2537  TESS_CHAR *tc = tess_chars_it.data();
2538  text_len += (*lengths)[i] = tc->length;
2539  (*costs)[i] = tc->cost;
2540  (*x0)[i] = tc->box.left();
2541  (*y0)[i] = tc->box.bottom();
2542  (*x1)[i] = tc->box.right();
2543  (*y1)[i] = tc->box.top();
2544  }
2545  char *p = *text = new char[text_len];
2546 
2547  tess_chars_it.move_to_first();
2548  for (tess_chars_it.mark_cycle_pt();
2549  !tess_chars_it.cycled_list();
2550  tess_chars_it.forward()) {
2551  TESS_CHAR *tc = tess_chars_it.data();
2552  strncpy(p, tc->unicode_repr, tc->length);
2553  p += tc->length;
2554  }
2555  return n;
2556 }
2557 
2559 // The resulting features are returned in int_features, which must be
2560 // of size MAX_NUM_INT_FEATURES. The number of features is returned in
2561 // num_features (or 0 if there was a failure).
2562 // On return feature_outline_index is filled with an index of the outline
2563 // corresponding to each feature in int_features.
2564 // TODO(rays) Fix the caller to out outline_counts instead.
2566  INT_FEATURE_STRUCT* int_features,
2567  int* num_features,
2568  int* feature_outline_index) {
2569  GenericVector<int> outline_counts;
2572  INT_FX_RESULT_STRUCT fx_info;
2573  tesseract_->ExtractFeatures(*blob, false, &bl_features,
2574  &cn_features, &fx_info, &outline_counts);
2575  if (cn_features.empty() || cn_features.size() > MAX_NUM_INT_FEATURES) {
2576  *num_features = 0;
2577  return; // Feature extraction failed.
2578  }
2579  *num_features = cn_features.size();
2580  memcpy(int_features, &cn_features[0], *num_features * sizeof(cn_features[0]));
2581  // TODO(rays) Pass outline_counts back and simplify the calling code.
2582  if (feature_outline_index != nullptr) {
2583  int f = 0;
2584  for (int i = 0; i < outline_counts.size(); ++i) {
2585  while (f < outline_counts[i])
2586  feature_outline_index[f++] = i;
2587  }
2588  }
2589 }
2590 
2591 // This method returns the row to which a box of specified dimensions would
2592 // belong. If no good match is found, it returns nullptr.
2593 ROW* TessBaseAPI::FindRowForBox(BLOCK_LIST* blocks,
2594  int left, int top, int right, int bottom) {
2595  TBOX box(left, bottom, right, top);
2596  BLOCK_IT b_it(blocks);
2597  for (b_it.mark_cycle_pt(); !b_it.cycled_list(); b_it.forward()) {
2598  BLOCK* block = b_it.data();
2599  if (!box.major_overlap(block->pdblk.bounding_box()))
2600  continue;
2601  ROW_IT r_it(block->row_list());
2602  for (r_it.mark_cycle_pt(); !r_it.cycled_list(); r_it.forward()) {
2603  ROW* row = r_it.data();
2604  if (!box.major_overlap(row->bounding_box()))
2605  continue;
2606  WERD_IT w_it(row->word_list());
2607  for (w_it.mark_cycle_pt(); !w_it.cycled_list(); w_it.forward()) {
2608  WERD* word = w_it.data();
2609  if (box.major_overlap(word->bounding_box()))
2610  return row;
2611  }
2612  }
2613  }
2614  return nullptr;
2615 }
2616 
2619  int num_max_matches,
2620  int* unichar_ids,
2621  float* ratings,
2622  int* num_matches_returned) {
2623  auto* choices = new BLOB_CHOICE_LIST;
2624  tesseract_->AdaptiveClassifier(blob, choices);
2625  BLOB_CHOICE_IT choices_it(choices);
2626  int& index = *num_matches_returned;
2627  index = 0;
2628  for (choices_it.mark_cycle_pt();
2629  !choices_it.cycled_list() && index < num_max_matches;
2630  choices_it.forward()) {
2631  BLOB_CHOICE* choice = choices_it.data();
2632  unichar_ids[index] = choice->unichar_id();
2633  ratings[index] = choice->rating();
2634  ++index;
2635  }
2636  *num_matches_returned = index;
2637  delete choices;
2638 }
2639 #endif // ndef DISABLED_LEGACY_ENGINE
2640 
2641 } // namespace tesseract.
bool WriteTRFile(const STRING &filename)
Definition: blobclass.cpp:101
int IntCastRounded(double x)
Definition: helpers.h:175
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:375
void SetSourceResolution(int ppi)
Definition: baseapi.cpp:584
UNICHAR_ID unichar_id() const
Definition: ratngs.h:77
static ROW * FindRowForBox(BLOCK_LIST *blocks, int left, int top, int right, int bottom)
Definition: baseapi.cpp:2593
MutableIterator * GetMutableIterator()
Definition: baseapi.cpp:1299
ParamsVectors * params()
Definition: ccutil.h:65
STRING HOcrEscape(const char *text)
Definition: baseapi.cpp:2268
Definition: werd.h:56
bool IsAtBeginningOf(PageIteratorLevel level) const override
void set_text(const char *new_text)
Definition: werd.h:115
const int kBlnXHeight
Definition: normalis.h:24
bool ProcessPage(Pix *pix, int page_index, const char *filename, const char *retry_config, int timeout_millisec, TessResultRenderer *renderer)
Definition: baseapi.cpp:1198
void GetLoadedLanguagesAsVector(GenericVector< STRING > *langs) const
Definition: baseapi.cpp:436
Tesseract * osd_tesseract_
For orientation & script detection.
Definition: baseapi.h:889
BLOCK * block
Definition: pageres.h:116
int16_t top() const
Definition: rect.h:58
void GetAvailableLanguagesAsVector(GenericVector< STRING > *langs) const
Definition: baseapi.cpp:450
const Dawg * GetDawg(int i) const
Definition: baseapi.cpp:2257
virtual char * GetUTF8Text(PageIteratorLevel level) const
bool BoundingBoxInternal(PageIteratorLevel level, int *left, int *top, int *right, int *bottom) const
bool GetIntVariable(const char *name, int *value) const
Definition: baseapi.cpp:292
C_OUTLINE_LIST * out_list()
Definition: stepblob.h:70
WERD_RES * restart_page()
Definition: pageres.h:702
void delete_data_pointers()
float x_height() const
Definition: ocrrow.h:64
void ReadDebugConfigFile(const char *filename)
Definition: baseapi.cpp:500
Definition: rect.h:34
TESS_LOCAL void AdaptToCharacter(const char *unichar_repr, int length, float baseline, float xheight, float descender, float ascender)
Definition: baseapi.cpp:2387
bool major_overlap(const TBOX &box) const
Definition: rect.h:368
fuzzy nonspace
Definition: werd.h:40
int valid_word(const WERD_CHOICE &word, bool numbers_ok) const
Definition: dict.cpp:787
STRING * input_file_
Name used by training code.
Definition: baseapi.h:896
static bool GetParamAsString(const char *name, const ParamsVectors *member_params, STRING *value)
Definition: params.cpp:142
float angle() const
find angle
Definition: points.h:247
void SetInputName(const char *name)
Definition: baseapi.cpp:265
const char * GetInitLanguagesAsString() const
Definition: baseapi.cpp:426
virtual bool Next(PageIteratorLevel level)
PageSegMode GetPageSegMode() const
Definition: baseapi.cpp:516
bool IsEmpty() const
Return true if no image has been set.
Definition: thresholder.cpp:53
virtual void Clear()
Destroy the Pix if there is one, freeing memory.
Definition: thresholder.cpp:48
const char * GetStringVariable(const char *name) const
Definition: baseapi.cpp:308
OcrEngineMode last_oem_requested_
Last ocr language mode requested.
Definition: baseapi.h:900
void(Wordrec::* fill_lattice_)(const MATRIX &ratings, const WERD_CHOICE_LIST &best_choices, const UNICHARSET &unicharset, BlamerBundle *blamer_bundle)
Definition: wordrec.h:485
int32_t length() const
Definition: rejctmap.h:223
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
bool IsBinary() const
Returns true if the source image is binary.
Definition: thresholder.h:74
void set_pix_grey(Pix *grey_pix)
char * TesseractRect(const unsigned char *imagedata, int bytes_per_pixel, int bytes_per_line, int left, int top, int width, int height)
Definition: baseapi.cpp:536
float rating() const
Definition: ratngs.h:80
static void DeleteBlockList(BLOCK_LIST *block_list)
Definition: baseapi.cpp:2304
void SetRectangle(int left, int top, int width, int height)
Definition: baseapi.cpp:618
Definition: strngs.h:45
Definition: points.h:188
Orientation and script detection only.
Definition: publictypes.h:164
bool wordrec_run_blamer
Definition: wordrec.h:237
Tesseract * get_sub_lang(int index) const
TESS_LOCAL int TextLength(int *blob_count)
Definition: baseapi.cpp:2127
void AdaptiveClassifier(TBLOB *Blob, BLOB_CHOICE_LIST *Choices)
Definition: adaptmatch.cpp:191
WERD_CHOICE * prev_word_best_choice_
Definition: wordrec.h:481
bool PTIsTextType(PolyBlockType type)
Definition: publictypes.h:82
bool Baseline(PageIteratorLevel level, int *x1, int *y1, int *x2, int *y2) const
float sconfidence
Definition: osdetect.h:45
STRING * datapath_
Current location of tessdata.
Definition: baseapi.h:898
void PrepareForTessOCR(BLOCK_LIST *block_list, Tesseract *osd_tess, OSResults *osr)
GenericVector< IntParam * > int_params
Definition: params.h:43
tesseract::ParamsVectors * GlobalParams()
Definition: params.cpp:35
void SetImage(const unsigned char *imagedata, int width, int height, int bytes_per_pixel, int bytes_per_line)
Definition: thresholder.cpp:65
ResultIterator * GetIterator()
Definition: baseapi.cpp:1282
Pix * GetBinaryImage(PageIteratorLevel level) const
const int kMaxBytesPerLine
Definition: baseapi.cpp:1469
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:303
Boxa * GetWords(Pixa **pixa)
Definition: baseapi.cpp:678
static void PrintParams(FILE *fp, const ParamsVectors *member_params)
Definition: params.cpp:180
void AdaptToChar(TBLOB *Blob, CLASS_ID ClassId, int FontinfoId, float Threshold, ADAPT_TEMPLATES adaptive_templates)
Definition: adaptmatch.cpp:853
ADAPT_TEMPLATES AdaptedTemplates
Definition: classify.h:513
TBOX bounding_box() const
Definition: blobs.cpp:472
TESSLINE * outlines
Definition: blobs.h:379
void set_min_orientation_margin(double margin)
Definition: baseapi.cpp:2173
void add_str_int(const char *str, int number)
Definition: strngs.cpp:377
const STRING & unichar_string() const
Definition: ratngs.h:541
Pix * GetThresholdedImage()
Definition: baseapi.cpp:629
ROW_RES * row() const
Definition: pageres.h:758
TESS_LOCAL LTRResultIterator * GetLTRIterator()
Definition: baseapi.cpp:1265
UNICHARSET unicharset
Definition: ccutil.h:71
start of line
Definition: werd.h:32
int32_t length() const
Definition: strngs.cpp:189
void SetDictFunc(DictFunc f)
Definition: baseapi.cpp:1922
float oconfidence
Definition: osdetect.h:46
STRING * language_
Last initialized language.
Definition: baseapi.h:899
void extract_edges(Pix *pix, BLOCK *block)
Definition: edgblob.cpp:330
int init_tesseract_lm(const char *arg0, const char *textbase, const char *language, TessdataManager *mgr)
Definition: tessedit.cpp:450
const char * get_script_from_script_id(int id) const
Definition: unicharset.h:854
static ResultIterator * StartOfParagraph(const LTRResultIterator &resit)
BLOCK_RES * block() const
Definition: pageres.h:761
int IsValidWord(const char *word)
Definition: baseapi.cpp:1876
void ExtractFontName(const STRING &filename, STRING *fontname)
Definition: blobclass.cpp:46
int length() const
Definition: ratngs.h:303
bool GetVariableAsString(const char *name, STRING *val)
Definition: baseapi.cpp:323
bool IsValidCharacter(const char *utf8_character)
Definition: baseapi.cpp:1880
void ClearAdaptiveClassifier()
Definition: baseapi.cpp:559
void DetectParagraphs(int debug_level, GenericVector< RowInfo > *row_infos, GenericVector< PARA * > *row_owners, PARA_LIST *paragraphs, GenericVector< ParagraphModel * > *models)
bool PSM_OSD_ENABLED(int pageseg_mode)
Definition: publictypes.h:191
const int kMinRectSize
Definition: baseapi.cpp:98
int GetScaledEstimatedResolution() const
Definition: thresholder.h:105
void SetEquationDetect(EquationDetect *detector)
int GetSourceYResolution() const
Definition: thresholder.h:89
void set_pix_thresholds(Pix *thresholds)
void ReadConfigFile(const char *filename)
Definition: baseapi.cpp:495
Definition: blobs.h:263
static void NormalizeTBLOB(TBLOB *tblob, ROW *row, bool numeric_mode)
Definition: baseapi.cpp:2356
virtual R Run()=0
TBOX intersection(const TBOX &box) const
Definition: rect.cpp:87
int SegmentPage(const STRING *input_file, BLOCK_LIST *blocks, Tesseract *osd_tess, OSResults *osr)
Definition: pagesegmain.cpp:99
bool BoundingBox(PageIteratorLevel level, int *left, int *top, int *right, int *bottom) const
void ApplyBoxTraining(const STRING &fontname, PAGE_RES *page_res)
Definition: applybox.cpp:807
const TBOX & BlobBox(int index) const
Definition: boxword.h:84
const char * id_to_unichar(UNICHAR_ID id) const
Definition: unicharset.cpp:291
const int kBytesPer64BitNumber
Definition: baseapi.cpp:1462
BLOCK_LIST * FindLinesCreateBlockList()
Definition: baseapi.cpp:2292
bool GetBoolVariable(const char *name, bool *value) const
Definition: baseapi.cpp:300
virtual void Run(A1, A2, A3, A4)=0
void SetImage(const unsigned char *imagedata, int width, int height, int bytes_per_pixel, int bytes_per_line)
Definition: baseapi.cpp:574
bool ProcessPagesInternal(const char *filename, const char *retry_config, int timeout_millisec, TessResultRenderer *renderer)
Definition: baseapi.cpp:1096
PolyBlockType BlockType() const
const int kMaxIntSize
Definition: baseapi.cpp:115
double matcher_good_threshold
Definition: classify.h:460
fuzzy space
Definition: werd.h:39
const char * GetDatapath()
Definition: baseapi.cpp:958
void set_pix_original(Pix *original_pix)
bool AdaptToWordStr(PageSegMode mode, const char *wordstr)
Definition: baseapi.cpp:1757
OSBestResult best_result
Definition: osdetect.h:81
bool GetDoubleVariable(const char *name, double *value) const
Definition: baseapi.cpp:314
int first_uni() const
Definition: unichar.cpp:98
#define MAX_PATH
Definition: platform.h:29
Automatic page segmentation, but no OSD, or OCR.
Definition: publictypes.h:167
TESS_LOCAL PAGE_RES * RecognitionPass2(BLOCK_LIST *block_list, PAGE_RES *pass1_result)
Definition: baseapi.cpp:2429
virtual TESS_LOCAL bool Threshold(Pix **pix)
Definition: baseapi.cpp:1972
bool LoadMemBuffer(const char *name, const char *data, int size)
UNICHARSET * unicharset
Definition: osdetect.h:80
static void ResetToDefaults(ParamsVectors *member_params)
Definition: params.cpp:205
int(Dict::*)(void *, const UNICHARSET &, UNICHAR_ID, bool) const DictFunc
Definition: baseapi.h:76
const Dawg * GetDawg(int index) const
Return i-th dawg pointer recorded in the dawgs_ vector.
Definition: dict.h:423
#define MAX_NUM_INT_FEATURES
Definition: intproto.h:129
end of line
Definition: werd.h:33
static TESS_LOCAL int TesseractExtractResult(char **text, int **lengths, float **costs, int **x0, int **y0, int **x1, int **y1, PAGE_RES *page_res)
Definition: baseapi.cpp:2513
REJMAP reject_map
Definition: pageres.h:286
GenericVector< BoolParam * > bool_params
Definition: params.h:44
void bounding_box(ICOORD &bottom_left, ICOORD &top_right) const
get box
Definition: pdblock.h:60
FileReader reader_
Reads files from any filesystem.
Definition: baseapi.h:891
float y() const
Definition: points.h:210
virtual ~TessBaseAPI()
Definition: baseapi.cpp:220
Pix * pix_original() const
bool SetDebugVariable(const char *name, const char *value)
Definition: baseapi.cpp:286
Boxa * GetTextlines(bool raw_image, int raw_padding, Pixa **pixa, int **blockids, int **paraids)
Definition: baseapi.cpp:655
static size_t getOpenCLDevice(void **device)
Definition: baseapi.cpp:238
static const char * Version()
Definition: baseapi.cpp:227
TESS_LOCAL PAGE_RES * RecognitionPass1(BLOCK_LIST *block_list)
Definition: baseapi.cpp:2422
const int kBlnBaselineOffset
Definition: normalis.h:25
#define ELISTIZE(CLASSNAME)
Definition: elst.h:955
void SetPageSegMode(PageSegMode mode)
Definition: baseapi.cpp:509
void chomp_string(char *str)
Definition: helpers.h:77
#define DIR
Definition: polyaprx.cpp:41
TESS_LOCAL void DetectParagraphs(bool after_text_recognition)
Definition: baseapi.cpp:2236
Boxa * GetConnectedComponents(Pixa **cc)
Definition: baseapi.cpp:688
constexpr int kMaxCredibleResolution
Definition: publictypes.h:40
TruthCallback * truth_cb_
Definition: baseapi.h:902
char * GetBoxText(int page_number)
Definition: baseapi.cpp:1478
const char kTesseractReject
Definition: baseapi.cpp:100
Pix * GetImage(PageIteratorLevel level, int padding, Pix *original_img, int *left, int *top) const
void MaximallyChopWord(const GenericVector< TBOX > &boxes, BLOCK *block, ROW *row, WERD_RES *word_res)
Definition: applybox.cpp:243
CRUNCH_MODE unlv_crunch_mode
Definition: pageres.h:309
void SetSourceYResolution(int ppi)
Definition: thresholder.h:85
void * cancel_this
monitor-aware progress callback
Definition: ocrclass.h:116
void SetInputImage(Pix *pix)
Definition: baseapi.cpp:948
bool IsAtFinalElement(PageIteratorLevel level, PageIteratorLevel element) const override
char * GetOsdText(int page_number)
Definition: baseapi.cpp:1675
float rating() const
Definition: ratngs.h:327
int RecognizeForChopTest(ETEXT_DESC *monitor)
Definition: baseapi.cpp:915
Boxa * GetStrips(Pixa **pixa, int **blockids)
Definition: baseapi.cpp:669
static ROW * MakeTessOCRRow(float baseline, float xheight, float descender, float ascender)
Definition: baseapi.cpp:2309
static void ClearPersistentCache()
Definition: baseapi.cpp:1868
UNICHAR_ID unichar_to_id(const char *const unichar_repr) const
Definition: unicharset.cpp:210
void ReSegmentByClassification(PAGE_RES *page_res)
Definition: applybox.cpp:510
int num_sub_langs() const
int NumDawgs() const
Return the number of dawgs in the dawgs_ vector.
Definition: dict.h:421
void PrintVariables(FILE *fp) const
Definition: baseapi.cpp:328
int orientation_and_script_detection(STRING &filename, OSResults *osr, tesseract::Tesseract *tess)
Definition: osdetect.cpp:190
const char * string() const
Definition: strngs.cpp:194
PAGE_RES * SetupApplyBoxes(const GenericVector< TBOX > &boxes, BLOCK_LIST *block_list)
Definition: applybox.cpp:207
void TidyUp(PAGE_RES *page_res)
Definition: applybox.cpp:712
DLLSYM void tprintf(const char *format,...)
Definition: tprintf.cpp:36
char * GetTSVText(int page_number)
Definition: baseapi.cpp:1341
void recog_training_segmented(const STRING &fname, PAGE_RES *page_res, volatile ETEXT_DESC *monitor, FILE *output_file)
bool(*)(const STRING &, GenericVector< char > *) FileReader
Definition: serialis.h:49
bool empty() const
Definition: genericvector.h:89
void(Wordrec::*)(const MATRIX &, const WERD_CHOICE_LIST &, const UNICHARSET &, BlamerBundle *) FillLatticeFunc
Definition: baseapi.h:79
void assign(const char *cstr, int len)
Definition: strngs.cpp:420
bool AddImage(TessBaseAPI *api)
Definition: renderer.cpp:83
bool GetTextDirection(int *out_offset, float *out_slope)
Definition: baseapi.cpp:1887
tesseract::BoxWord * box_word
Definition: pageres.h:265
int push_back(T object)
void SetProbabilityInContextFunc(ProbabilityInContextFunc f)
Definition: baseapi.cpp:1936
WERD_RES * word() const
Definition: pageres.h:755
Dict & getDict() override
virtual Pix * GetPixRectGrey()
WERD_RES * forward()
Definition: pageres.h:735
const int kBytesPerNumber
Definition: baseapi.cpp:1454
bool BeginDocument(const char *title)
Definition: renderer.cpp:72
int(Dict::* letter_is_okay_)(void *void_dawg_args, const UNICHARSET &unicharset, UNICHAR_ID unichar_id, bool word_end) const
Definition: dict.h:363
PDBLK pdblk
Page Description Block.
Definition: ocrblock.h:191
#define UNICHAR_LEN
Definition: unichar.h:30
bool recognition_done_
page_res_ contains recognition data.
Definition: baseapi.h:901
int GetScaledYResolution() const
Definition: thresholder.h:92
void set_deadline_msecs(int32_t deadline_msecs)
Definition: ocrclass.h:129
void SetRectangle(int left, int top, int width, int height)
STRING lang
Definition: ccutil.h:69
void DeleteUnusedDawgs()
Definition: dawg_cache.h:43
#define ELISTIZEH(CLASSNAME)
Definition: elst.h:942
int16_t right() const
Definition: rect.h:79
TESS_API int get_best_script(int orientation_id) const
Definition: osdetect.cpp:112
void GetFeaturesForBlob(TBLOB *blob, INT_FEATURE_STRUCT *int_features, int *num_features, int *feature_outline_index)
Definition: baseapi.cpp:2565
int16_t bottom() const
Definition: rect.h:65
bool contains_unichar(const char *const unichar_repr) const
Definition: unicharset.cpp:671
int InitLangMod(const char *datapath, const char *language)
Definition: baseapi.cpp:467
Tesseract * tesseract() const
Definition: baseapi.h:801
uint8_t space()
Definition: werd.h:99
STRING datadir
Definition: ccutil.h:67
void TrainLineRecognizer(const STRING &input_imagename, const STRING &output_basename, BLOCK_LIST *block_list)
Definition: linerec.cpp:43
void RunAdaptiveClassifier(TBLOB *blob, int num_max_matches, int *unichar_ids, float *ratings, int *num_matches_returned)
Definition: baseapi.cpp:2618
TBOX bounding_box() const
Definition: werd.cpp:148
int NumDawgs() const
Definition: baseapi.cpp:2263
static bool SetParam(const char *name, const char *value, SetParamConstraint constraint, ParamsVectors *member_params)
Definition: params.cpp:92
float certainty() const
Definition: ratngs.h:330
void BestChoiceToCorrectText()
Definition: pageres.cpp:927
OcrEngineMode oem() const
Definition: baseapi.h:803
void set_unlv_suspects(WERD_RES *word)
Definition: output.cpp:273
TESS_LOCAL int FindLines()
Definition: baseapi.cpp:2026
bool Empty(PageIteratorLevel level) const
bool tessedit_resegment_from_line_boxes
virtual bool ThresholdToPix(PageSegMode pageseg_mode, Pix **pix)
Returns false on error.
TESS_LOCAL bool InternalSetImage()
Definition: baseapi.cpp:1955
bool AnyLSTMLang() const
T ClipToRange(const T &x, const T &lower_bound, const T &upper_bound)
Definition: helpers.h:108
WERD_CHOICE * best_choice
Definition: pageres.h:234
Pix * pix_grey() const
GenericVector< ParagraphModel * > * paragraph_models_
Definition: baseapi.h:893
virtual void GetImageSizes(int *left, int *top, int *width, int *height, int *imagewidth, int *imageheight)
PAGE_RES * page_res_
The page-level data.
Definition: baseapi.h:895
static void CatchSignals()
Definition: baseapi.cpp:256
#define ASSERT_HOST(x)
Definition: errcode.h:88
void InitAdaptiveClassifier(TessdataManager *mgr)
Definition: adaptmatch.cpp:527
float base_line(float xpos) const
Definition: ocrrow.h:59
bool ProcessPages(const char *filename, const char *retry_config, int timeout_millisec, TessResultRenderer *renderer)
Definition: baseapi.cpp:1068
Boxa * GetComponentImages(PageIteratorLevel level, bool text_only, bool raw_image, int raw_padding, Pixa **pixa, int **blockids, int **paraids)
Definition: baseapi.cpp:700
Pix * pix_binary() const
constexpr int kMinCredibleResolution
Definition: publictypes.h:38
int16_t left() const
Definition: rect.h:72
const UNICHARSET & getUnicharset() const
Definition: dict.h:97
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:284
void set_source_resolution(int ppi)
Boxa * GetRegions(Pixa **pixa)
Definition: baseapi.cpp:643
WERD_LIST * word_list()
Definition: ocrrow.h:55
bool flag(WERD_FLAGS mask) const
Definition: werd.h:117
ImageThresholder * thresholder_
Image thresholding module.
Definition: baseapi.h:892
char * GetUTF8Text(PageIteratorLevel level) const
TBOX bounding_box() const
Definition: ocrrow.h:88
int orientation_id
Definition: osdetect.h:43
#define BOOL_VAR(name, val, comment)
Definition: params.h:306
const int kLatinChs[]
Definition: baseapi.cpp:1523
static TESS_API DawgCache * GlobalDawgCache()
Definition: dict.cpp:193
bool Next(PageIteratorLevel level) override
_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
int OrientationIdToValue(const int &id)
Definition: osdetect.cpp:566
int UNICHAR_ID
Definition: unichar.h:34
void split(char c, GenericVector< STRING > *splited)
Definition: strngs.cpp:282
void LearnWord(const char *fontname, WERD_RES *word)
Definition: adaptmatch.cpp:250
void SetFillLatticeFunc(FillLatticeFunc f)
Definition: baseapi.cpp:1949
STRING * output_file_
Name used by debug code.
Definition: baseapi.h:897
GenericVector< StringParam * > string_params
Definition: params.h:45
virtual Pix * GetPixRectThresholds()
virtual bool IsAtFinalElement(PageIteratorLevel level, PageIteratorLevel element) const
static TBLOB * MakeTBLOB(Pix *pix)
Definition: baseapi.cpp:2326
TESS_CHAR(float _cost, const char *repr, int len=-1)
Definition: baseapi.cpp:2444
const char kUNLVSuspect
Definition: baseapi.cpp:104
Tesseract * tesseract_
The underlying data object.
Definition: baseapi.h:888
const STRING & unichar_lengths() const
Definition: ratngs.h:548
double(Dict::*)(const char *, const char *, int, const char *, int) ProbabilityInContextFunc
Definition: baseapi.h:77
Definition: ocrrow.h:36
GenericVector< DoubleParam * > double_params
Definition: params.h:46
ROW_LIST * row_list()
get rows
Definition: ocrblock.h:117
int Recognize(ETEXT_DESC *monitor)
Definition: baseapi.cpp:824
bool SetVariable(const char *name, const char *value)
Definition: baseapi.cpp:280
Assume a single uniform block of text. (Default.)
Definition: publictypes.h:172
int size() const
Definition: genericvector.h:70
C_BLOB_LIST * blob_list()
get blobs
Definition: ocrblock.h:129
const int kBytesPerBoxFileLine
Definition: baseapi.cpp:1460
ROW * row
Definition: pageres.h:142
PageIterator * AnalyseLayout()
Definition: baseapi.cpp:804
float Confidence(PageIteratorLevel level) const
void pgeditor_main(int width, int height, PAGE_RES *page_res)
Definition: pgedit.cpp:380
void GetBlockTextOrientations(int **block_orientation, bool **vertical_writing)
Definition: baseapi.cpp:2191
#define TRUE
Definition: capi.h:51
PAGE_RES * ApplyBoxes(const STRING &fname, bool find_segmentation, BLOCK_LIST *block_list)
Definition: applybox.cpp:109
void CorrectClassifyWords(PAGE_RES *page_res)
Definition: applybox.cpp:780
#define BOOL
Definition: capi.h:50
const char kUNLVReject
Definition: baseapi.cpp:102
const char * GetUnichar(int unichar_id)
Definition: baseapi.cpp:2252
WERD * word
Definition: pageres.h:188
const int kNumbersPerBlob
Definition: baseapi.cpp:1449
const char * GetInputName()
Definition: baseapi.cpp:952
static TBLOB * PolygonalCopy(bool allow_detailed_fx, C_BLOB *src)
Definition: blobs.cpp:331
bool DetectOS(OSResults *)
Definition: baseapi.cpp:2158
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:340
const int kUniChs[]
Definition: baseapi.cpp:1519
EquationDetect * equ_detect_
The equation detector.
Definition: baseapi.h:890
int GetThresholdedImageScaleFactor() const
Definition: baseapi.cpp:782
Definition: ocrblock.h:29
bool classify_bln_numeric_mode
Definition: classify.h:540
BLOCK_LIST * block_list_
The page layout.
Definition: baseapi.h:894
void read_config_file(const char *filename, SetParamConstraint constraint)
Definition: tessedit.cpp:49
void SetOutputName(const char *name)
Definition: baseapi.cpp:273
const char * c_str() const
Definition: strngs.cpp:205
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:401
FILE * init_recog_training(const STRING &fname)
CANCEL_FUNC cancel
for errcode use
Definition: ocrclass.h:112
bool DetectOrientationScript(int *orient_deg, float *orient_conf, const char **script_name, float *script_conf)
Definition: baseapi.cpp:1644