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