Mercurial > hgrepos > Python2 > PyMuPDF
diff 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 |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mupdf-source/thirdparty/tesseract/src/textord/drawtord.cpp Mon Sep 15 11:43:07 2025 +0200 @@ -0,0 +1,413 @@ +/********************************************************************** + * File: drawtord.cpp (Formerly drawto.c) + * Description: Draw things to do with textord. + * Author: Ray Smith + * + * (C) Copyright 1992, Hewlett-Packard Ltd. + ** Licensed under the Apache License, Version 2.0 (the "License"); + ** you may not use this file except in compliance with the License. + ** You may obtain a copy of the License at + ** http://www.apache.org/licenses/LICENSE-2.0 + ** Unless required by applicable law or agreed to in writing, software + ** distributed under the License is distributed on an "AS IS" BASIS, + ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + ** See the License for the specific language governing permissions and + ** limitations under the License. + * + **********************************************************************/ + +#ifdef HAVE_CONFIG_H +# include "config_auto.h" +#endif + +#include "drawtord.h" + +#include "pithsync.h" +#include "topitch.h" + +namespace tesseract { + +#define TO_WIN_XPOS 0 // default window pos +#define TO_WIN_YPOS 0 +#define TO_WIN_NAME "Textord" +// title of window + +BOOL_VAR(textord_show_fixed_cuts, false, "Draw fixed pitch cell boundaries"); + +ScrollView *to_win = nullptr; + +#ifndef GRAPHICS_DISABLED + +/********************************************************************** + * create_to_win + * + * Create the to window used to show the fit. + **********************************************************************/ + +ScrollView *create_to_win(ICOORD page_tr) { + if (to_win != nullptr) { + return to_win; + } + to_win = new ScrollView(TO_WIN_NAME, TO_WIN_XPOS, TO_WIN_YPOS, page_tr.x() + 1, page_tr.y() + 1, + page_tr.x(), page_tr.y(), true); + return to_win; +} + +void close_to_win() { + // to_win is leaked, but this enables the user to view the contents. + if (to_win != nullptr) { + to_win->Update(); + } +} + +/********************************************************************** + * plot_box_list + * + * Draw a list of blobs. + **********************************************************************/ + +void plot_box_list( // make gradients win + ScrollView *win, // window to draw in + BLOBNBOX_LIST *list, // blob list + ScrollView::Color body_colour // colour to draw +) { + BLOBNBOX_IT it = list; // iterator + + win->Pen(body_colour); + win->Brush(ScrollView::NONE); + for (it.mark_cycle_pt(); !it.cycled_list(); it.forward()) { + it.data()->bounding_box().plot(win); + } +} + +/********************************************************************** + * plot_to_row + * + * Draw the blobs of a row in a given colour and draw the line fit. + **********************************************************************/ + +void plot_to_row( // draw a row + TO_ROW *row, // row to draw + ScrollView::Color colour, // colour to draw in + FCOORD rotation // rotation for line +) { + FCOORD plot_pt; // point to plot + // blobs + BLOBNBOX_IT it = row->blob_list(); + float left, right; // end of row + + if (it.empty()) { + tprintf("No blobs in row at %g\n", row->parallel_c()); + return; + } + left = it.data()->bounding_box().left(); + it.move_to_last(); + right = it.data()->bounding_box().right(); + plot_blob_list(to_win, row->blob_list(), colour, ScrollView::BROWN); + to_win->Pen(colour); + plot_pt = FCOORD(left, row->line_m() * left + row->line_c()); + plot_pt.rotate(rotation); + to_win->SetCursor(plot_pt.x(), plot_pt.y()); + plot_pt = FCOORD(right, row->line_m() * right + row->line_c()); + plot_pt.rotate(rotation); + to_win->DrawTo(plot_pt.x(), plot_pt.y()); +} + +/********************************************************************** + * plot_parallel_row + * + * Draw the blobs of a row in a given colour and draw the line fit. + **********************************************************************/ + +void plot_parallel_row( // draw a row + TO_ROW *row, // row to draw + float gradient, // gradients of lines + int32_t left, // edge of block + ScrollView::Color colour, // colour to draw in + FCOORD rotation // rotation for line +) { + FCOORD plot_pt; // point to plot + // blobs + BLOBNBOX_IT it = row->blob_list(); + auto fleft = static_cast<float>(left); // floating version + float right; // end of row + + // left=it.data()->bounding_box().left(); + it.move_to_last(); + right = it.data()->bounding_box().right(); + plot_blob_list(to_win, row->blob_list(), colour, ScrollView::BROWN); + to_win->Pen(colour); + plot_pt = FCOORD(fleft, gradient * left + row->max_y()); + plot_pt.rotate(rotation); + to_win->SetCursor(plot_pt.x(), plot_pt.y()); + plot_pt = FCOORD(fleft, gradient * left + row->min_y()); + plot_pt.rotate(rotation); + to_win->DrawTo(plot_pt.x(), plot_pt.y()); + plot_pt = FCOORD(fleft, gradient * left + row->parallel_c()); + plot_pt.rotate(rotation); + to_win->SetCursor(plot_pt.x(), plot_pt.y()); + plot_pt = FCOORD(right, gradient * right + row->parallel_c()); + plot_pt.rotate(rotation); + to_win->DrawTo(plot_pt.x(), plot_pt.y()); +} + +/********************************************************************** + * draw_occupation + * + * Draw the row occupation with points above the threshold in white + * and points below the threshold in black. + **********************************************************************/ + +void draw_occupation( // draw projection + int32_t xleft, // edge of block + int32_t ybottom, // bottom of block + int32_t min_y, // coordinate limits + int32_t max_y, int32_t occupation[], // projection counts + int32_t thresholds[] // for drop out +) { + int32_t line_index; // pixel coord + ScrollView::Color colour; // of histogram + auto fleft = static_cast<float>(xleft); // float version + + colour = ScrollView::WHITE; + to_win->Pen(colour); + to_win->SetCursor(fleft, static_cast<float>(ybottom)); + for (line_index = min_y; line_index <= max_y; line_index++) { + if (occupation[line_index - min_y] < thresholds[line_index - min_y]) { + if (colour != ScrollView::BLUE) { + colour = ScrollView::BLUE; + to_win->Pen(colour); + } + } else { + if (colour != ScrollView::WHITE) { + colour = ScrollView::WHITE; + to_win->Pen(colour); + } + } + to_win->DrawTo(fleft + occupation[line_index - min_y] / 10.0, static_cast<float>(line_index)); + } + colour = ScrollView::STEEL_BLUE; + to_win->Pen(colour); + to_win->SetCursor(fleft, static_cast<float>(ybottom)); + for (line_index = min_y; line_index <= max_y; line_index++) { + to_win->DrawTo(fleft + thresholds[line_index - min_y] / 10.0, static_cast<float>(line_index)); + } +} + +/********************************************************************** + * draw_meanlines + * + * Draw the meanlines of the given block in the given colour. + **********************************************************************/ + +void draw_meanlines( // draw a block + TO_BLOCK *block, // block to draw + float gradient, // gradients of lines + int32_t left, // edge of block + ScrollView::Color colour, // colour to draw in + FCOORD rotation // rotation for line +) { + FCOORD plot_pt; // point to plot + // rows + TO_ROW_IT row_it = block->get_rows(); + TO_ROW *row; // current row + BLOBNBOX_IT blob_it; // blobs + float right; // end of row + to_win->Pen(colour); + for (row_it.mark_cycle_pt(); !row_it.cycled_list(); row_it.forward()) { + row = row_it.data(); + blob_it.set_to_list(row->blob_list()); + blob_it.move_to_last(); + right = blob_it.data()->bounding_box().right(); + plot_pt = FCOORD(static_cast<float>(left), gradient * left + row->parallel_c() + row->xheight); + plot_pt.rotate(rotation); + to_win->SetCursor(plot_pt.x(), plot_pt.y()); + plot_pt = FCOORD(right, gradient * right + row->parallel_c() + row->xheight); + plot_pt.rotate(rotation); + to_win->DrawTo(plot_pt.x(), plot_pt.y()); + } +} + +/********************************************************************** + * plot_word_decisions + * + * Plot a row with words in different colours and fuzzy spaces + * highlighted. + **********************************************************************/ + +void plot_word_decisions( // draw words + ScrollView *win, // window tro draw in + int16_t pitch, // of block + TO_ROW *row // row to draw +) { + ScrollView::Color colour = ScrollView::MAGENTA; // current colour + ScrollView::Color rect_colour; // fuzzy colour + int32_t prev_x; // end of prev blob + int16_t blob_count; // blobs in word + BLOBNBOX *blob; // current blob + TBOX blob_box; // bounding box + // iterator + BLOBNBOX_IT blob_it = row->blob_list(); + BLOBNBOX_IT start_it = blob_it; // word start + + rect_colour = ScrollView::BLACK; + prev_x = -INT16_MAX; + blob_count = 0; + for (blob_it.mark_cycle_pt(); !blob_it.cycled_list(); blob_it.forward()) { + blob = blob_it.data(); + blob_box = blob->bounding_box(); + if (!blob->joined_to_prev() && blob_box.left() - prev_x > row->max_nonspace) { + if ((blob_box.left() - prev_x >= row->min_space || + blob_box.left() - prev_x > row->space_threshold) && + blob_count > 0) { + if (pitch > 0 && textord_show_fixed_cuts) { + plot_fp_cells(win, colour, &start_it, pitch, blob_count, &row->projection, + row->projection_left, row->projection_right, + row->xheight * textord_projection_scale); + } + blob_count = 0; + start_it = blob_it; + } + if (colour == ScrollView::MAGENTA) { + colour = ScrollView::RED; + } else { + colour = static_cast<ScrollView::Color>(colour + 1); + } + if (blob_box.left() - prev_x < row->min_space) { + if (blob_box.left() - prev_x > row->space_threshold) { + rect_colour = ScrollView::GOLDENROD; + } else { + rect_colour = ScrollView::CORAL; + } + // fill_color_index(win, rect_colour); + win->Brush(rect_colour); + win->Rectangle(prev_x, blob_box.bottom(), blob_box.left(), blob_box.top()); + } + } + if (!blob->joined_to_prev()) { + prev_x = blob_box.right(); + } + if (blob->cblob() != nullptr) { + blob->cblob()->plot(win, colour, colour); + } + if (!blob->joined_to_prev() && blob->cblob() != nullptr) { + blob_count++; + } + } + if (pitch > 0 && textord_show_fixed_cuts && blob_count > 0) { + plot_fp_cells(win, colour, &start_it, pitch, blob_count, &row->projection, row->projection_left, + row->projection_right, row->xheight * textord_projection_scale); + } +} + +/********************************************************************** + * plot_fp_cells + * + * Make a list of fixed pitch cuts and draw them. + **********************************************************************/ + +void plot_fp_cells( // draw words + ScrollView *win, // window tro draw in + ScrollView::Color colour, // colour of lines + BLOBNBOX_IT *blob_it, // blobs + int16_t pitch, // of block + int16_t blob_count, // no of real blobs + STATS *projection, // vertical + int16_t projection_left, // edges //scale factor + int16_t projection_right, float projection_scale) { + int16_t occupation; // occupied cells + TBOX word_box; // bounding box + FPSEGPT_LIST seg_list; // list of cuts + FPSEGPT_IT seg_it; + FPSEGPT *segpt; // current point + + if (pitsync_linear_version) { + check_pitch_sync2(blob_it, blob_count, pitch, 2, projection, projection_left, projection_right, + projection_scale, occupation, &seg_list, 0, 0); + } else { + check_pitch_sync(blob_it, blob_count, pitch, 2, projection, &seg_list); + } + word_box = blob_it->data()->bounding_box(); + for (; blob_count > 0; blob_count--) { + word_box += box_next(blob_it); + } + seg_it.set_to_list(&seg_list); + for (seg_it.mark_cycle_pt(); !seg_it.cycled_list(); seg_it.forward()) { + segpt = seg_it.data(); + if (segpt->faked) { + colour = ScrollView::WHITE; + win->Pen(colour); + } else { + win->Pen(colour); + } + win->Line(segpt->position(), word_box.bottom(), segpt->position(), word_box.top()); + } +} + +/********************************************************************** + * plot_fp_cells2 + * + * Make a list of fixed pitch cuts and draw them. + **********************************************************************/ + +void plot_fp_cells2( // draw words + ScrollView *win, // window tro draw in + ScrollView::Color colour, // colour of lines + TO_ROW *row, // for location + FPSEGPT_LIST *seg_list // segments to plot +) { + TBOX word_box; // bounding box + FPSEGPT_IT seg_it = seg_list; + // blobs in row + BLOBNBOX_IT blob_it = row->blob_list(); + FPSEGPT *segpt; // current point + + word_box = blob_it.data()->bounding_box(); + for (blob_it.mark_cycle_pt(); !blob_it.cycled_list();) { + word_box += box_next(&blob_it); + } + for (seg_it.mark_cycle_pt(); !seg_it.cycled_list(); seg_it.forward()) { + segpt = seg_it.data(); + if (segpt->faked) { + colour = ScrollView::WHITE; + win->Pen(colour); + } else { + win->Pen(colour); + } + win->Line(segpt->position(), word_box.bottom(), segpt->position(), word_box.top()); + } +} + +/********************************************************************** + * plot_row_cells + * + * Make a list of fixed pitch cuts and draw them. + **********************************************************************/ + +void plot_row_cells( // draw words + ScrollView *win, // window tro draw in + ScrollView::Color colour, // colour of lines + TO_ROW *row, // for location + float xshift, // amount of shift + ICOORDELT_LIST *cells // cells to draw +) { + TBOX word_box; // bounding box + ICOORDELT_IT cell_it = cells; + // blobs in row + BLOBNBOX_IT blob_it = row->blob_list(); + ICOORDELT *cell; // current cell + + word_box = blob_it.data()->bounding_box(); + for (blob_it.mark_cycle_pt(); !blob_it.cycled_list();) { + word_box += box_next(&blob_it); + } + win->Pen(colour); + for (cell_it.mark_cycle_pt(); !cell_it.cycled_list(); cell_it.forward()) { + cell = cell_it.data(); + win->Line(cell->x() + xshift, word_box.bottom(), cell->x() + xshift, word_box.top()); + } +} + +#endif // !GRAPHICS_DISABLED + +} // namespace tesseract
