comparison mupdf-source/thirdparty/tesseract/src/ccmain/paramsd.cpp @ 2:b50eed0cc0ef upstream

ADD: MuPDF v1.26.7: the MuPDF source as downloaded by a default build of PyMuPDF 1.26.4. The directory name has changed: no version number in the expanded directory now.
author Franz Glasner <fzglas.hg@dom66.de>
date Mon, 15 Sep 2025 11:43:07 +0200
parents
children
comparison
equal deleted inserted replaced
1:1d09e1dec1d9 2:b50eed0cc0ef
1 ///////////////////////////////////////////////////////////////////////
2 // 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 //
17 ///////////////////////////////////////////////////////////////////////
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, 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.
58 ParamContent::ParamContent(tesseract::StringParam *it) {
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.
66 ParamContent::ParamContent(tesseract::IntParam *it) {
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.
74 ParamContent::ParamContent(tesseract::BoolParam *it) {
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.
82 ParamContent::ParamContent(tesseract::DoubleParam *it) {
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.
91 ParamContent *ParamContent::GetParamContentById(int 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 required
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 {
279 ParamContent *vc = ParamContent::GetParamContentById(sve->command_id);
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).
289 ParamsEditor::ParamsEditor(tesseract::Tesseract *tess, ScrollView *sv) {
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 // if file exists
323 if ((fp = fopen(filename, "rb")) != nullptr) {
324 fclose(fp);
325 std::stringstream msg;
326 msg << "Overwrite file " << filename << "? (Y/N)";
327 int a = sv_window_->ShowYesNoDialog(msg.str().c_str());
328 if (a == 'n') {
329 return;
330 } // don't write
331 }
332
333 fp = fopen(filename, "wb"); // can we write to it?
334 if (fp == nullptr) {
335 sv_window_->AddMessageF("Can't write to file %s", filename);
336 return;
337 }
338 for (auto &iter : vcMap) {
339 ParamContent *cur = iter.second;
340 if (!changes_only || cur->HasChanged()) {
341 fprintf(fp, "%-25s %-12s # %s\n", cur->GetName(), cur->GetValue().c_str(),
342 cur->GetDescription());
343 }
344 }
345 fclose(fp);
346 }
347
348 } // namespace tesseract
349
350 #endif // !GRAPHICS_DISABLED