Mercurial > hgrepos > Python2 > PyMuPDF
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 ¶m : vec->int_params) { | |
| 216 vc_it.add_after_then_move(new ParamContent(param)); | |
| 217 } | |
| 218 for (auto ¶m : vec->bool_params) { | |
| 219 vc_it.add_after_then_move(new ParamContent(param)); | |
| 220 } | |
| 221 for (auto ¶m : vec->string_params) { | |
| 222 vc_it.add_after_then_move(new ParamContent(param)); | |
| 223 } | |
| 224 for (auto ¶m : 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 |
