Mercurial > hgrepos > Python2 > PyMuPDF
comparison mupdf-source/thirdparty/tesseract/src/textord/drawtord.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: drawtord.cpp (Formerly drawto.c) | |
| 3 * Description: Draw things to do with textord. | |
| 4 * Author: Ray Smith | |
| 5 * | |
| 6 * (C) Copyright 1992, Hewlett-Packard Ltd. | |
| 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 #ifdef HAVE_CONFIG_H | |
| 20 # include "config_auto.h" | |
| 21 #endif | |
| 22 | |
| 23 #include "drawtord.h" | |
| 24 | |
| 25 #include "pithsync.h" | |
| 26 #include "topitch.h" | |
| 27 | |
| 28 namespace tesseract { | |
| 29 | |
| 30 #define TO_WIN_XPOS 0 // default window pos | |
| 31 #define TO_WIN_YPOS 0 | |
| 32 #define TO_WIN_NAME "Textord" | |
| 33 // title of window | |
| 34 | |
| 35 BOOL_VAR(textord_show_fixed_cuts, false, "Draw fixed pitch cell boundaries"); | |
| 36 | |
| 37 ScrollView *to_win = nullptr; | |
| 38 | |
| 39 #ifndef GRAPHICS_DISABLED | |
| 40 | |
| 41 /********************************************************************** | |
| 42 * create_to_win | |
| 43 * | |
| 44 * Create the to window used to show the fit. | |
| 45 **********************************************************************/ | |
| 46 | |
| 47 ScrollView *create_to_win(ICOORD page_tr) { | |
| 48 if (to_win != nullptr) { | |
| 49 return to_win; | |
| 50 } | |
| 51 to_win = new ScrollView(TO_WIN_NAME, TO_WIN_XPOS, TO_WIN_YPOS, page_tr.x() + 1, page_tr.y() + 1, | |
| 52 page_tr.x(), page_tr.y(), true); | |
| 53 return to_win; | |
| 54 } | |
| 55 | |
| 56 void close_to_win() { | |
| 57 // to_win is leaked, but this enables the user to view the contents. | |
| 58 if (to_win != nullptr) { | |
| 59 to_win->Update(); | |
| 60 } | |
| 61 } | |
| 62 | |
| 63 /********************************************************************** | |
| 64 * plot_box_list | |
| 65 * | |
| 66 * Draw a list of blobs. | |
| 67 **********************************************************************/ | |
| 68 | |
| 69 void plot_box_list( // make gradients win | |
| 70 ScrollView *win, // window to draw in | |
| 71 BLOBNBOX_LIST *list, // blob list | |
| 72 ScrollView::Color body_colour // colour to draw | |
| 73 ) { | |
| 74 BLOBNBOX_IT it = list; // iterator | |
| 75 | |
| 76 win->Pen(body_colour); | |
| 77 win->Brush(ScrollView::NONE); | |
| 78 for (it.mark_cycle_pt(); !it.cycled_list(); it.forward()) { | |
| 79 it.data()->bounding_box().plot(win); | |
| 80 } | |
| 81 } | |
| 82 | |
| 83 /********************************************************************** | |
| 84 * plot_to_row | |
| 85 * | |
| 86 * Draw the blobs of a row in a given colour and draw the line fit. | |
| 87 **********************************************************************/ | |
| 88 | |
| 89 void plot_to_row( // draw a row | |
| 90 TO_ROW *row, // row to draw | |
| 91 ScrollView::Color colour, // colour to draw in | |
| 92 FCOORD rotation // rotation for line | |
| 93 ) { | |
| 94 FCOORD plot_pt; // point to plot | |
| 95 // blobs | |
| 96 BLOBNBOX_IT it = row->blob_list(); | |
| 97 float left, right; // end of row | |
| 98 | |
| 99 if (it.empty()) { | |
| 100 tprintf("No blobs in row at %g\n", row->parallel_c()); | |
| 101 return; | |
| 102 } | |
| 103 left = it.data()->bounding_box().left(); | |
| 104 it.move_to_last(); | |
| 105 right = it.data()->bounding_box().right(); | |
| 106 plot_blob_list(to_win, row->blob_list(), colour, ScrollView::BROWN); | |
| 107 to_win->Pen(colour); | |
| 108 plot_pt = FCOORD(left, row->line_m() * left + row->line_c()); | |
| 109 plot_pt.rotate(rotation); | |
| 110 to_win->SetCursor(plot_pt.x(), plot_pt.y()); | |
| 111 plot_pt = FCOORD(right, row->line_m() * right + row->line_c()); | |
| 112 plot_pt.rotate(rotation); | |
| 113 to_win->DrawTo(plot_pt.x(), plot_pt.y()); | |
| 114 } | |
| 115 | |
| 116 /********************************************************************** | |
| 117 * plot_parallel_row | |
| 118 * | |
| 119 * Draw the blobs of a row in a given colour and draw the line fit. | |
| 120 **********************************************************************/ | |
| 121 | |
| 122 void plot_parallel_row( // draw a row | |
| 123 TO_ROW *row, // row to draw | |
| 124 float gradient, // gradients of lines | |
| 125 int32_t left, // edge of block | |
| 126 ScrollView::Color colour, // colour to draw in | |
| 127 FCOORD rotation // rotation for line | |
| 128 ) { | |
| 129 FCOORD plot_pt; // point to plot | |
| 130 // blobs | |
| 131 BLOBNBOX_IT it = row->blob_list(); | |
| 132 auto fleft = static_cast<float>(left); // floating version | |
| 133 float right; // end of row | |
| 134 | |
| 135 // left=it.data()->bounding_box().left(); | |
| 136 it.move_to_last(); | |
| 137 right = it.data()->bounding_box().right(); | |
| 138 plot_blob_list(to_win, row->blob_list(), colour, ScrollView::BROWN); | |
| 139 to_win->Pen(colour); | |
| 140 plot_pt = FCOORD(fleft, gradient * left + row->max_y()); | |
| 141 plot_pt.rotate(rotation); | |
| 142 to_win->SetCursor(plot_pt.x(), plot_pt.y()); | |
| 143 plot_pt = FCOORD(fleft, gradient * left + row->min_y()); | |
| 144 plot_pt.rotate(rotation); | |
| 145 to_win->DrawTo(plot_pt.x(), plot_pt.y()); | |
| 146 plot_pt = FCOORD(fleft, gradient * left + row->parallel_c()); | |
| 147 plot_pt.rotate(rotation); | |
| 148 to_win->SetCursor(plot_pt.x(), plot_pt.y()); | |
| 149 plot_pt = FCOORD(right, gradient * right + row->parallel_c()); | |
| 150 plot_pt.rotate(rotation); | |
| 151 to_win->DrawTo(plot_pt.x(), plot_pt.y()); | |
| 152 } | |
| 153 | |
| 154 /********************************************************************** | |
| 155 * draw_occupation | |
| 156 * | |
| 157 * Draw the row occupation with points above the threshold in white | |
| 158 * and points below the threshold in black. | |
| 159 **********************************************************************/ | |
| 160 | |
| 161 void draw_occupation( // draw projection | |
| 162 int32_t xleft, // edge of block | |
| 163 int32_t ybottom, // bottom of block | |
| 164 int32_t min_y, // coordinate limits | |
| 165 int32_t max_y, int32_t occupation[], // projection counts | |
| 166 int32_t thresholds[] // for drop out | |
| 167 ) { | |
| 168 int32_t line_index; // pixel coord | |
| 169 ScrollView::Color colour; // of histogram | |
| 170 auto fleft = static_cast<float>(xleft); // float version | |
| 171 | |
| 172 colour = ScrollView::WHITE; | |
| 173 to_win->Pen(colour); | |
| 174 to_win->SetCursor(fleft, static_cast<float>(ybottom)); | |
| 175 for (line_index = min_y; line_index <= max_y; line_index++) { | |
| 176 if (occupation[line_index - min_y] < thresholds[line_index - min_y]) { | |
| 177 if (colour != ScrollView::BLUE) { | |
| 178 colour = ScrollView::BLUE; | |
| 179 to_win->Pen(colour); | |
| 180 } | |
| 181 } else { | |
| 182 if (colour != ScrollView::WHITE) { | |
| 183 colour = ScrollView::WHITE; | |
| 184 to_win->Pen(colour); | |
| 185 } | |
| 186 } | |
| 187 to_win->DrawTo(fleft + occupation[line_index - min_y] / 10.0, static_cast<float>(line_index)); | |
| 188 } | |
| 189 colour = ScrollView::STEEL_BLUE; | |
| 190 to_win->Pen(colour); | |
| 191 to_win->SetCursor(fleft, static_cast<float>(ybottom)); | |
| 192 for (line_index = min_y; line_index <= max_y; line_index++) { | |
| 193 to_win->DrawTo(fleft + thresholds[line_index - min_y] / 10.0, static_cast<float>(line_index)); | |
| 194 } | |
| 195 } | |
| 196 | |
| 197 /********************************************************************** | |
| 198 * draw_meanlines | |
| 199 * | |
| 200 * Draw the meanlines of the given block in the given colour. | |
| 201 **********************************************************************/ | |
| 202 | |
| 203 void draw_meanlines( // draw a block | |
| 204 TO_BLOCK *block, // block to draw | |
| 205 float gradient, // gradients of lines | |
| 206 int32_t left, // edge of block | |
| 207 ScrollView::Color colour, // colour to draw in | |
| 208 FCOORD rotation // rotation for line | |
| 209 ) { | |
| 210 FCOORD plot_pt; // point to plot | |
| 211 // rows | |
| 212 TO_ROW_IT row_it = block->get_rows(); | |
| 213 TO_ROW *row; // current row | |
| 214 BLOBNBOX_IT blob_it; // blobs | |
| 215 float right; // end of row | |
| 216 to_win->Pen(colour); | |
| 217 for (row_it.mark_cycle_pt(); !row_it.cycled_list(); row_it.forward()) { | |
| 218 row = row_it.data(); | |
| 219 blob_it.set_to_list(row->blob_list()); | |
| 220 blob_it.move_to_last(); | |
| 221 right = blob_it.data()->bounding_box().right(); | |
| 222 plot_pt = FCOORD(static_cast<float>(left), gradient * left + row->parallel_c() + row->xheight); | |
| 223 plot_pt.rotate(rotation); | |
| 224 to_win->SetCursor(plot_pt.x(), plot_pt.y()); | |
| 225 plot_pt = FCOORD(right, gradient * right + row->parallel_c() + row->xheight); | |
| 226 plot_pt.rotate(rotation); | |
| 227 to_win->DrawTo(plot_pt.x(), plot_pt.y()); | |
| 228 } | |
| 229 } | |
| 230 | |
| 231 /********************************************************************** | |
| 232 * plot_word_decisions | |
| 233 * | |
| 234 * Plot a row with words in different colours and fuzzy spaces | |
| 235 * highlighted. | |
| 236 **********************************************************************/ | |
| 237 | |
| 238 void plot_word_decisions( // draw words | |
| 239 ScrollView *win, // window tro draw in | |
| 240 int16_t pitch, // of block | |
| 241 TO_ROW *row // row to draw | |
| 242 ) { | |
| 243 ScrollView::Color colour = ScrollView::MAGENTA; // current colour | |
| 244 ScrollView::Color rect_colour; // fuzzy colour | |
| 245 int32_t prev_x; // end of prev blob | |
| 246 int16_t blob_count; // blobs in word | |
| 247 BLOBNBOX *blob; // current blob | |
| 248 TBOX blob_box; // bounding box | |
| 249 // iterator | |
| 250 BLOBNBOX_IT blob_it = row->blob_list(); | |
| 251 BLOBNBOX_IT start_it = blob_it; // word start | |
| 252 | |
| 253 rect_colour = ScrollView::BLACK; | |
| 254 prev_x = -INT16_MAX; | |
| 255 blob_count = 0; | |
| 256 for (blob_it.mark_cycle_pt(); !blob_it.cycled_list(); blob_it.forward()) { | |
| 257 blob = blob_it.data(); | |
| 258 blob_box = blob->bounding_box(); | |
| 259 if (!blob->joined_to_prev() && blob_box.left() - prev_x > row->max_nonspace) { | |
| 260 if ((blob_box.left() - prev_x >= row->min_space || | |
| 261 blob_box.left() - prev_x > row->space_threshold) && | |
| 262 blob_count > 0) { | |
| 263 if (pitch > 0 && textord_show_fixed_cuts) { | |
| 264 plot_fp_cells(win, colour, &start_it, pitch, blob_count, &row->projection, | |
| 265 row->projection_left, row->projection_right, | |
| 266 row->xheight * textord_projection_scale); | |
| 267 } | |
| 268 blob_count = 0; | |
| 269 start_it = blob_it; | |
| 270 } | |
| 271 if (colour == ScrollView::MAGENTA) { | |
| 272 colour = ScrollView::RED; | |
| 273 } else { | |
| 274 colour = static_cast<ScrollView::Color>(colour + 1); | |
| 275 } | |
| 276 if (blob_box.left() - prev_x < row->min_space) { | |
| 277 if (blob_box.left() - prev_x > row->space_threshold) { | |
| 278 rect_colour = ScrollView::GOLDENROD; | |
| 279 } else { | |
| 280 rect_colour = ScrollView::CORAL; | |
| 281 } | |
| 282 // fill_color_index(win, rect_colour); | |
| 283 win->Brush(rect_colour); | |
| 284 win->Rectangle(prev_x, blob_box.bottom(), blob_box.left(), blob_box.top()); | |
| 285 } | |
| 286 } | |
| 287 if (!blob->joined_to_prev()) { | |
| 288 prev_x = blob_box.right(); | |
| 289 } | |
| 290 if (blob->cblob() != nullptr) { | |
| 291 blob->cblob()->plot(win, colour, colour); | |
| 292 } | |
| 293 if (!blob->joined_to_prev() && blob->cblob() != nullptr) { | |
| 294 blob_count++; | |
| 295 } | |
| 296 } | |
| 297 if (pitch > 0 && textord_show_fixed_cuts && blob_count > 0) { | |
| 298 plot_fp_cells(win, colour, &start_it, pitch, blob_count, &row->projection, row->projection_left, | |
| 299 row->projection_right, row->xheight * textord_projection_scale); | |
| 300 } | |
| 301 } | |
| 302 | |
| 303 /********************************************************************** | |
| 304 * plot_fp_cells | |
| 305 * | |
| 306 * Make a list of fixed pitch cuts and draw them. | |
| 307 **********************************************************************/ | |
| 308 | |
| 309 void plot_fp_cells( // draw words | |
| 310 ScrollView *win, // window tro draw in | |
| 311 ScrollView::Color colour, // colour of lines | |
| 312 BLOBNBOX_IT *blob_it, // blobs | |
| 313 int16_t pitch, // of block | |
| 314 int16_t blob_count, // no of real blobs | |
| 315 STATS *projection, // vertical | |
| 316 int16_t projection_left, // edges //scale factor | |
| 317 int16_t projection_right, float projection_scale) { | |
| 318 int16_t occupation; // occupied cells | |
| 319 TBOX word_box; // bounding box | |
| 320 FPSEGPT_LIST seg_list; // list of cuts | |
| 321 FPSEGPT_IT seg_it; | |
| 322 FPSEGPT *segpt; // current point | |
| 323 | |
| 324 if (pitsync_linear_version) { | |
| 325 check_pitch_sync2(blob_it, blob_count, pitch, 2, projection, projection_left, projection_right, | |
| 326 projection_scale, occupation, &seg_list, 0, 0); | |
| 327 } else { | |
| 328 check_pitch_sync(blob_it, blob_count, pitch, 2, projection, &seg_list); | |
| 329 } | |
| 330 word_box = blob_it->data()->bounding_box(); | |
| 331 for (; blob_count > 0; blob_count--) { | |
| 332 word_box += box_next(blob_it); | |
| 333 } | |
| 334 seg_it.set_to_list(&seg_list); | |
| 335 for (seg_it.mark_cycle_pt(); !seg_it.cycled_list(); seg_it.forward()) { | |
| 336 segpt = seg_it.data(); | |
| 337 if (segpt->faked) { | |
| 338 colour = ScrollView::WHITE; | |
| 339 win->Pen(colour); | |
| 340 } else { | |
| 341 win->Pen(colour); | |
| 342 } | |
| 343 win->Line(segpt->position(), word_box.bottom(), segpt->position(), word_box.top()); | |
| 344 } | |
| 345 } | |
| 346 | |
| 347 /********************************************************************** | |
| 348 * plot_fp_cells2 | |
| 349 * | |
| 350 * Make a list of fixed pitch cuts and draw them. | |
| 351 **********************************************************************/ | |
| 352 | |
| 353 void plot_fp_cells2( // draw words | |
| 354 ScrollView *win, // window tro draw in | |
| 355 ScrollView::Color colour, // colour of lines | |
| 356 TO_ROW *row, // for location | |
| 357 FPSEGPT_LIST *seg_list // segments to plot | |
| 358 ) { | |
| 359 TBOX word_box; // bounding box | |
| 360 FPSEGPT_IT seg_it = seg_list; | |
| 361 // blobs in row | |
| 362 BLOBNBOX_IT blob_it = row->blob_list(); | |
| 363 FPSEGPT *segpt; // current point | |
| 364 | |
| 365 word_box = blob_it.data()->bounding_box(); | |
| 366 for (blob_it.mark_cycle_pt(); !blob_it.cycled_list();) { | |
| 367 word_box += box_next(&blob_it); | |
| 368 } | |
| 369 for (seg_it.mark_cycle_pt(); !seg_it.cycled_list(); seg_it.forward()) { | |
| 370 segpt = seg_it.data(); | |
| 371 if (segpt->faked) { | |
| 372 colour = ScrollView::WHITE; | |
| 373 win->Pen(colour); | |
| 374 } else { | |
| 375 win->Pen(colour); | |
| 376 } | |
| 377 win->Line(segpt->position(), word_box.bottom(), segpt->position(), word_box.top()); | |
| 378 } | |
| 379 } | |
| 380 | |
| 381 /********************************************************************** | |
| 382 * plot_row_cells | |
| 383 * | |
| 384 * Make a list of fixed pitch cuts and draw them. | |
| 385 **********************************************************************/ | |
| 386 | |
| 387 void plot_row_cells( // draw words | |
| 388 ScrollView *win, // window tro draw in | |
| 389 ScrollView::Color colour, // colour of lines | |
| 390 TO_ROW *row, // for location | |
| 391 float xshift, // amount of shift | |
| 392 ICOORDELT_LIST *cells // cells to draw | |
| 393 ) { | |
| 394 TBOX word_box; // bounding box | |
| 395 ICOORDELT_IT cell_it = cells; | |
| 396 // blobs in row | |
| 397 BLOBNBOX_IT blob_it = row->blob_list(); | |
| 398 ICOORDELT *cell; // current cell | |
| 399 | |
| 400 word_box = blob_it.data()->bounding_box(); | |
| 401 for (blob_it.mark_cycle_pt(); !blob_it.cycled_list();) { | |
| 402 word_box += box_next(&blob_it); | |
| 403 } | |
| 404 win->Pen(colour); | |
| 405 for (cell_it.mark_cycle_pt(); !cell_it.cycled_list(); cell_it.forward()) { | |
| 406 cell = cell_it.data(); | |
| 407 win->Line(cell->x() + xshift, word_box.bottom(), cell->x() + xshift, word_box.top()); | |
| 408 } | |
| 409 } | |
| 410 | |
| 411 #endif // !GRAPHICS_DISABLED | |
| 412 | |
| 413 } // namespace tesseract |
