tesseract  5.0.0
paramsd.cpp
Go to the documentation of this file.
1 // File: paramsd.cpp
3 // Description: Tesseract parameter Editor
4 // Author: Joern Wanke
5 //
6 // (C) Copyright 2007, 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 //
18 //
19 // The parameters editor is used to edit all the parameters used within
20 // tesseract from the ui.
21 
22 // Include automatically generated configuration file if running autoconf.
23 #ifdef HAVE_CONFIG_H
24 # include "config_auto.h"
25 #endif
26 
27 #ifndef GRAPHICS_DISABLED
28 
29 # include "params.h" // for ParamsVectors, StringParam, BoolParam
30 # include "paramsd.h"
31 # include "scrollview.h" // for SVEvent, ScrollView, SVET_POPUP
32 # include "svmnode.h" // for SVMenuNode
33 # include "tesseractclass.h" // for Tesseract
34 
35 # include <cstdio> // for fclose, fopen, fprintf, sprintf, FILE
36 # include <cstdlib> // for atoi
37 # include <cstring> // for strcmp, strcspn, strlen, strncpy
38 # include <locale> // for std::locale::classic
39 # include <map> // for map, _Rb_tree_iterator, map<>::iterator
40 # include <memory> // for unique_ptr
41 # include <sstream> // for std::stringstream
42 # include <utility> // for pair
43 
44 namespace tesseract {
45 
46 # define VARDIR "configs/" /*parameters files */
47 # define MAX_ITEMS_IN_SUBMENU 30
48 
49 // The following variables should remain static globals, since they
50 // are used by debug editor, which uses a single Tesseract instance.
51 //
52 // Contains the mappings from unique VC ids to their actual pointers.
53 static std::map<int, ParamContent *> vcMap;
54 static int nrParams = 0;
55 static int writeCommands[2];
56 
57 // Constructors for the various ParamTypes.
59  my_id_ = nrParams;
60  nrParams++;
61  param_type_ = VT_STRING;
62  sIt = it;
63  vcMap[my_id_] = this;
64 }
65 // Constructors for the various ParamTypes.
67  my_id_ = nrParams;
68  nrParams++;
69  param_type_ = VT_INTEGER;
70  iIt = it;
71  vcMap[my_id_] = this;
72 }
73 // Constructors for the various ParamTypes.
75  my_id_ = nrParams;
76  nrParams++;
77  param_type_ = VT_BOOLEAN;
78  bIt = it;
79  vcMap[my_id_] = this;
80 }
81 // Constructors for the various ParamTypes.
83  my_id_ = nrParams;
84  nrParams++;
85  param_type_ = VT_DOUBLE;
86  dIt = it;
87  vcMap[my_id_] = this;
88 }
89 
90 // Gets a VC object identified by its ID.
92  return vcMap[id];
93 }
94 
95 // Copy the first N words from the source string to the target string.
96 // Words are delimited by "_".
97 void ParamsEditor::GetFirstWords(const char *s, // source string
98  int n, // number of words
99  char *t // target string
100 ) {
101  int full_length = strlen(s);
102  int reqd_len = 0; // No. of chars requird
103  const char *next_word = s;
104 
105  while ((n > 0) && reqd_len < full_length) {
106  reqd_len += strcspn(next_word, "_") + 1;
107  next_word += reqd_len;
108  n--;
109  }
110  strncpy(t, s, reqd_len);
111  t[reqd_len] = '\0'; // ensure null terminal
112 }
113 
114 // Getter for the name.
115 const char *ParamContent::GetName() const {
116  if (param_type_ == VT_INTEGER) {
117  return iIt->name_str();
118  } else if (param_type_ == VT_BOOLEAN) {
119  return bIt->name_str();
120  } else if (param_type_ == VT_DOUBLE) {
121  return dIt->name_str();
122  } else if (param_type_ == VT_STRING) {
123  return sIt->name_str();
124  } else {
125  return "ERROR: ParamContent::GetName()";
126  }
127 }
128 
129 // Getter for the description.
130 const char *ParamContent::GetDescription() const {
131  if (param_type_ == VT_INTEGER) {
132  return iIt->info_str();
133  } else if (param_type_ == VT_BOOLEAN) {
134  return bIt->info_str();
135  } else if (param_type_ == VT_DOUBLE) {
136  return dIt->info_str();
137  } else if (param_type_ == VT_STRING) {
138  return sIt->info_str();
139  } else {
140  return nullptr;
141  }
142 }
143 
144 // Getter for the value.
145 std::string ParamContent::GetValue() const {
146  std::string result;
147  if (param_type_ == VT_INTEGER) {
148  result += std::to_string(*iIt);
149  } else if (param_type_ == VT_BOOLEAN) {
150  result += std::to_string(*bIt);
151  } else if (param_type_ == VT_DOUBLE) {
152  result += std::to_string(*dIt);
153  } else if (param_type_ == VT_STRING) {
154  result = sIt->c_str();
155  }
156  return result;
157 }
158 
159 // Setter for the value.
160 void ParamContent::SetValue(const char *val) {
161  // TODO (wanke) Test if the values actually are properly converted.
162  // (Quickly visible impacts?)
163  changed_ = true;
164  if (param_type_ == VT_INTEGER) {
165  iIt->set_value(atoi(val));
166  } else if (param_type_ == VT_BOOLEAN) {
167  bIt->set_value(atoi(val));
168  } else if (param_type_ == VT_DOUBLE) {
169  std::stringstream stream(val);
170  // Use "C" locale for reading double value.
171  stream.imbue(std::locale::classic());
172  double d = 0;
173  stream >> d;
174  dIt->set_value(d);
175  } else if (param_type_ == VT_STRING) {
176  sIt->set_value(val);
177  }
178 }
179 
180 // Gets the up to the first 3 prefixes from s (split by _).
181 // For example, tesseract_foo_bar will be split into tesseract,foo and bar.
182 void ParamsEditor::GetPrefixes(const char *s, std::string *level_one, std::string *level_two,
183  std::string *level_three) {
184  std::unique_ptr<char[]> p(new char[1024]);
185  GetFirstWords(s, 1, p.get());
186  *level_one = p.get();
187  GetFirstWords(s, 2, p.get());
188  *level_two = p.get();
189  GetFirstWords(s, 3, p.get());
190  *level_three = p.get();
191 }
192 
193 // Compare two VC objects by their name.
194 int ParamContent::Compare(const void *v1, const void *v2) {
195  const ParamContent *one = *static_cast<const ParamContent *const *>(v1);
196  const ParamContent *two = *static_cast<const ParamContent *const *>(v2);
197  return strcmp(one->GetName(), two->GetName());
198 }
199 
200 // Find all editable parameters used within tesseract and create a
201 // SVMenuNode tree from it.
202 // TODO (wanke): This is actually sort of hackish.
203 SVMenuNode *ParamsEditor::BuildListOfAllLeaves(tesseract::Tesseract *tess) {
204  auto *mr = new SVMenuNode();
205  ParamContent_LIST vclist;
206  ParamContent_IT vc_it(&vclist);
207  // Amount counts the number of entries for a specific char*.
208  // TODO(rays) get rid of the use of std::map.
209  std::map<const char *, int> amount;
210 
211  // Add all parameters to a list.
212  int num_iterations = (tess->params() == nullptr) ? 1 : 2;
213  for (int v = 0; v < num_iterations; ++v) {
214  tesseract::ParamsVectors *vec = (v == 0) ? GlobalParams() : tess->params();
215  for (auto &param : vec->int_params) {
216  vc_it.add_after_then_move(new ParamContent(param));
217  }
218  for (auto &param : vec->bool_params) {
219  vc_it.add_after_then_move(new ParamContent(param));
220  }
221  for (auto &param : vec->string_params) {
222  vc_it.add_after_then_move(new ParamContent(param));
223  }
224  for (auto &param : vec->double_params) {
225  vc_it.add_after_then_move(new ParamContent(param));
226  }
227  }
228 
229  // Count the # of entries starting with a specific prefix.
230  for (vc_it.mark_cycle_pt(); !vc_it.cycled_list(); vc_it.forward()) {
231  ParamContent *vc = vc_it.data();
232  std::string tag;
233  std::string tag2;
234  std::string tag3;
235 
236  GetPrefixes(vc->GetName(), &tag, &tag2, &tag3);
237  amount[tag.c_str()]++;
238  amount[tag2.c_str()]++;
239  amount[tag3.c_str()]++;
240  }
241 
242  vclist.sort(ParamContent::Compare); // Sort the list alphabetically.
243 
244  SVMenuNode *other = mr->AddChild("OTHER");
245 
246  // go through the list again and this time create the menu structure.
247  vc_it.move_to_first();
248  for (vc_it.mark_cycle_pt(); !vc_it.cycled_list(); vc_it.forward()) {
249  ParamContent *vc = vc_it.data();
250  std::string tag;
251  std::string tag2;
252  std::string tag3;
253  GetPrefixes(vc->GetName(), &tag, &tag2, &tag3);
254 
255  if (amount[tag.c_str()] == 1) {
256  other->AddChild(vc->GetName(), vc->GetId(), vc->GetValue().c_str(), vc->GetDescription());
257  } else { // More than one would use this submenu -> create submenu.
258  SVMenuNode *sv = mr->AddChild(tag.c_str());
259  if ((amount[tag.c_str()] <= MAX_ITEMS_IN_SUBMENU) || (amount[tag2.c_str()] <= 1)) {
260  sv->AddChild(vc->GetName(), vc->GetId(), vc->GetValue().c_str(), vc->GetDescription());
261  } else { // Make subsubmenus.
262  SVMenuNode *sv2 = sv->AddChild(tag2.c_str());
263  sv2->AddChild(vc->GetName(), vc->GetId(), vc->GetValue().c_str(), vc->GetDescription());
264  }
265  }
266  }
267  return mr;
268 }
269 
270 // Event listener. Waits for SVET_POPUP events and processes them.
271 void ParamsEditor::Notify(const SVEvent *sve) {
272  if (sve->type == SVET_POPUP) { // only catch SVET_POPUP!
273  char *param = sve->parameter;
274  if (sve->command_id == writeCommands[0]) {
275  WriteParams(param, false);
276  } else if (sve->command_id == writeCommands[1]) {
277  WriteParams(param, true);
278  } else {
280  vc->SetValue(param);
281  sv_window_->AddMessageF("Setting %s to %s", vc->GetName(), vc->GetValue().c_str());
282  }
283  }
284 }
285 
286 // Integrate the parameters editor as popupmenu into the existing scrollview
287 // window (usually the pg editor). If sv == null, create a new empty
288 // empty window and attach the parameters editor to that window (ugly).
290  if (sv == nullptr) {
291  const char *name = "ParamEditorMAIN";
292  sv = new ScrollView(name, 1, 1, 200, 200, 300, 200);
293  }
294 
295  sv_window_ = sv;
296 
297  // Only one event handler per window.
298  // sv->AddEventHandler((SVEventHandler*) this);
299 
300  SVMenuNode *svMenuRoot = BuildListOfAllLeaves(tess);
301 
302  std::string paramfile;
303  paramfile = tess->datadir;
304  paramfile += VARDIR; // parameters dir
305  paramfile += "edited"; // actual name
306 
307  SVMenuNode *std_menu = svMenuRoot->AddChild("Build Config File");
308 
309  writeCommands[0] = nrParams + 1;
310  std_menu->AddChild("All Parameters", writeCommands[0], paramfile.c_str(), "Config file name?");
311 
312  writeCommands[1] = nrParams + 2;
313  std_menu->AddChild("changed_ Parameters Only", writeCommands[1], paramfile.c_str(),
314  "Config file name?");
315 
316  svMenuRoot->BuildMenu(sv, false);
317 }
318 
319 // Write all (changed_) parameters to a config file.
320 void ParamsEditor::WriteParams(char *filename, bool changes_only) {
321  FILE *fp; // input file
322  char msg_str[255];
323  // if file exists
324  if ((fp = fopen(filename, "rb")) != nullptr) {
325  fclose(fp);
326  sprintf(msg_str,
327  "Overwrite file "
328  "%s"
329  "? (Y/N)",
330  filename);
331  int a = sv_window_->ShowYesNoDialog(msg_str);
332  if (a == 'n') {
333  return;
334  } // don't write
335  }
336 
337  fp = fopen(filename, "wb"); // can we write to it?
338  if (fp == nullptr) {
339  sv_window_->AddMessageF("Can't write to file %s", filename);
340  return;
341  }
342  for (auto &iter : vcMap) {
343  ParamContent *cur = iter.second;
344  if (!changes_only || cur->HasChanged()) {
345  fprintf(fp, "%-25s %-12s # %s\n", cur->GetName(), cur->GetValue().c_str(),
346  cur->GetDescription());
347  }
348  }
349  fclose(fp);
350 }
351 
352 } // namespace tesseract
353 
354 #endif // !GRAPHICS_DISABLED
#define VARDIR
Definition: paramsd.cpp:46
#define MAX_ITEMS_IN_SUBMENU
Definition: paramsd.cpp:47
@ SVET_POPUP
Definition: scrollview.h:61
@ VT_INTEGER
Definition: paramsd.h:40
@ VT_STRING
Definition: paramsd.h:40
@ VT_BOOLEAN
Definition: paramsd.h:40
@ VT_DOUBLE
Definition: paramsd.h:40
tesseract::ParamsVectors * GlobalParams()
Definition: params.cpp:36
void SetValue(const char *val)
Definition: paramsd.cpp:160
std::string GetValue() const
Definition: paramsd.cpp:145
static int Compare(const void *v1, const void *v2)
Definition: paramsd.cpp:194
tesseract::StringParam * sIt
Definition: paramsd.h:84
const char * GetDescription() const
Definition: paramsd.cpp:130
static ParamContent * GetParamContentById(int id)
Definition: paramsd.cpp:91
tesseract::IntParam * iIt
Definition: paramsd.h:85
const char * GetName() const
Definition: paramsd.cpp:115
tesseract::BoolParam * bIt
Definition: paramsd.h:86
tesseract::DoubleParam * dIt
Definition: paramsd.h:87
void Notify(const SVEvent *sve) override
Definition: paramsd.cpp:271
ParamsEditor(tesseract::Tesseract *, ScrollView *sv=nullptr)
Definition: paramsd.cpp:289
ParamsVectors * params()
Definition: ccutil.h:53
std::string datadir
Definition: ccutil.h:57
std::vector< BoolParam * > bool_params
Definition: params.h:47
std::vector< StringParam * > string_params
Definition: params.h:48
std::vector< IntParam * > int_params
Definition: params.h:46
std::vector< DoubleParam * > double_params
Definition: params.h:49
const char * info_str() const
Definition: params.h:119
const char * name_str() const
Definition: params.h:116
void set_value(int32_t value)
Definition: params.h:165
void set_value(bool value)
Definition: params.h:207
void set_value(const std::string &value)
Definition: params.h:262
const char * c_str() const
Definition: params.h:247
void set_value(double value)
Definition: params.h:304
SVEventType type
Definition: scrollview.h:73
void AddMessageF(const char *format,...) __attribute__((format(printf
Definition: scrollview.cpp:555
int ShowYesNoDialog(const char *msg)
Definition: scrollview.cpp:747
SVMenuNode * AddChild(const char *txt)
Definition: svmnode.cpp:59
void BuildMenu(ScrollView *sv, bool menu_bar=true)
Definition: svmnode.cpp:120