Mercurial > hgrepos > Python2 > PyMuPDF
view mupdf-source/thirdparty/tesseract/src/ccstruct/pdblock.cpp @ 21:2f43e400f144
Provide an "all" target to build both the sdist and the wheel
| author | Franz Glasner <fzglas.hg@dom66.de> |
|---|---|
| date | Fri, 19 Sep 2025 10:28:53 +0200 |
| parents | b50eed0cc0ef |
| children |
line wrap: on
line source
/********************************************************************** * File: pdblock.cpp * Description: PDBLK member functions and iterator functions. * Author: Ray Smith * * (C) Copyright 1991, 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. * **********************************************************************/ // Include automatically generated configuration file if running autoconf. #ifdef HAVE_CONFIG_H # include "config_auto.h" #endif #include "pdblock.h" #include <allheaders.h> #include <cinttypes> // for PRId32 #include <cstdlib> #include <memory> // std::unique_ptr namespace tesseract { #define BLOCK_LABEL_HEIGHT 150 // char height of block id constexpr ERRCODE BADBLOCKLINE("Y coordinate in block out of bounds"); constexpr ERRCODE LOSTBLOCKLINE("Can't find rectangle for line"); /********************************************************************** * PDBLK::PDBLK * * Constructor for a simple rectangular block. **********************************************************************/ PDBLK::PDBLK( // rectangular block TDimension xmin, // bottom left TDimension ymin, TDimension xmax, // top right TDimension ymax) : box(ICOORD(xmin, ymin), ICOORD(xmax, ymax)) { // boundaries ICOORDELT_IT left_it = &leftside; ICOORDELT_IT right_it = &rightside; hand_poly = nullptr; left_it.set_to_list(&leftside); right_it.set_to_list(&rightside); // make default box left_it.add_to_end(new ICOORDELT(xmin, ymin)); left_it.add_to_end(new ICOORDELT(xmin, ymax)); right_it.add_to_end(new ICOORDELT(xmax, ymin)); right_it.add_to_end(new ICOORDELT(xmax, ymax)); index_ = 0; } /********************************************************************** * PDBLK::set_sides * * Sets left and right vertex lists **********************************************************************/ void PDBLK::set_sides( // set vertex lists ICOORDELT_LIST *left, // left vertices ICOORDELT_LIST *right // right vertices ) { // boundaries ICOORDELT_IT left_it = &leftside; ICOORDELT_IT right_it = &rightside; leftside.clear(); left_it.move_to_first(); left_it.add_list_before(left); rightside.clear(); right_it.move_to_first(); right_it.add_list_before(right); } /********************************************************************** * PDBLK::contains * * Return true if the given point is within the block. **********************************************************************/ bool PDBLK::contains( // test containment ICOORD pt // point to test ) { BLOCK_RECT_IT it = this; // rectangle iterator ICOORD bleft, tright; // corners of rectangle for (it.start_block(); !it.cycled_rects(); it.forward()) { // get rectangle it.bounding_box(bleft, tright); // inside rect if (pt.x() >= bleft.x() && pt.x() <= tright.x() && pt.y() >= bleft.y() && pt.y() <= tright.y()) { return true; // is inside } } return false; // not inside } /********************************************************************** * PDBLK::move * * Reposition block **********************************************************************/ void PDBLK::move( // reposition block const ICOORD vec // by vector ) { ICOORDELT_IT it(&leftside); for (it.mark_cycle_pt(); !it.cycled_list(); it.forward()) { *(it.data()) += vec; } it.set_to_list(&rightside); for (it.mark_cycle_pt(); !it.cycled_list(); it.forward()) { *(it.data()) += vec; } box.move(vec); } // Returns a binary Pix mask with a 1 pixel for every pixel within the // block. Rotates the coordinate system by rerotation prior to rendering. Image PDBLK::render_mask(const FCOORD &rerotation, TBOX *mask_box) { TBOX rotated_box(box); rotated_box.rotate(rerotation); Image pix = pixCreate(rotated_box.width(), rotated_box.height(), 1); if (hand_poly != nullptr) { // We are going to rotate, so get a deep copy of the points and // make a new POLY_BLOCK with it. ICOORDELT_LIST polygon; polygon.deep_copy(hand_poly->points(), ICOORDELT::deep_copy); POLY_BLOCK image_block(&polygon, hand_poly->isA()); image_block.rotate(rerotation); // Block outline is a polygon, so use a PB_LINE_IT to get the // rasterized interior. (Runs of interior pixels on a line.) auto *lines = new PB_LINE_IT(&image_block); for (int y = box.bottom(); y < box.top(); ++y) { const std::unique_ptr</*non-const*/ ICOORDELT_LIST> segments(lines->get_line(y)); if (!segments->empty()) { ICOORDELT_IT s_it(segments.get()); // Each element of segments is a start x and x size of the // run of interior pixels. for (s_it.mark_cycle_pt(); !s_it.cycled_list(); s_it.forward()) { int start = s_it.data()->x(); int xext = s_it.data()->y(); // Set the run of pixels to 1. pixRasterop(pix, start - rotated_box.left(), rotated_box.height() - 1 - (y - rotated_box.bottom()), xext, 1, PIX_SET, nullptr, 0, 0); } } } delete lines; } else { // Just fill the whole block as there is only a bounding box. pixRasterop(pix, 0, 0, rotated_box.width(), rotated_box.height(), PIX_SET, nullptr, 0, 0); } if (mask_box != nullptr) { *mask_box = rotated_box; } return pix; } /********************************************************************** * PDBLK::plot * * Plot the outline of a block in the given colour. **********************************************************************/ #ifndef GRAPHICS_DISABLED void PDBLK::plot( // draw outline ScrollView *window, // window to draw in int32_t serial, // serial number ScrollView::Color colour // colour to draw in ) { ICOORD startpt; // start of outline ICOORD endpt; // end of outline ICOORD prevpt; // previous point ICOORDELT_IT it = &leftside; // iterator // set the colour window->Pen(colour); window->TextAttributes("Times", BLOCK_LABEL_HEIGHT, false, false, false); if (hand_poly != nullptr) { hand_poly->plot(window, serial); } else if (!leftside.empty()) { startpt = *(it.data()); // bottom left corner // tprintf("Block %d bottom left is (%d,%d)\n", // serial,startpt.x(),startpt.y()); char temp_buff[34]; # if !defined(_WIN32) || defined(__MINGW32__) snprintf(temp_buff, sizeof(temp_buff), "%" PRId32, serial); # else _ultoa(serial, temp_buff, 10); # endif window->Text(startpt.x(), startpt.y(), temp_buff); window->SetCursor(startpt.x(), startpt.y()); do { prevpt = *(it.data()); // previous point it.forward(); // move to next point // draw round corner window->DrawTo(prevpt.x(), it.data()->y()); window->DrawTo(it.data()->x(), it.data()->y()); } while (!it.at_last()); // until end of list endpt = *(it.data()); // end point // other side of boundary window->SetCursor(startpt.x(), startpt.y()); it.set_to_list(&rightside); prevpt = startpt; for (it.mark_cycle_pt(); !it.cycled_list(); it.forward()) { // draw round corner window->DrawTo(prevpt.x(), it.data()->y()); window->DrawTo(it.data()->x(), it.data()->y()); prevpt = *(it.data()); // previous point } // close boundary window->DrawTo(endpt.x(), endpt.y()); } } #endif /********************************************************************** * PDBLK::operator= * * Assignment - duplicate the block structure, but with an EMPTY row list. **********************************************************************/ PDBLK &PDBLK::operator=( // assignment const PDBLK &source // from this ) { // this->ELIST_LINK::operator=(source); if (!leftside.empty()) { leftside.clear(); } if (!rightside.empty()) { rightside.clear(); } leftside.deep_copy(&source.leftside, &ICOORDELT::deep_copy); rightside.deep_copy(&source.rightside, &ICOORDELT::deep_copy); box = source.box; return *this; } /********************************************************************** * BLOCK_RECT_IT::BLOCK_RECT_IT * * Construct a block rectangle iterator. **********************************************************************/ BLOCK_RECT_IT::BLOCK_RECT_IT( // iterate rectangles PDBLK *blkptr // from block ) : left_it(&blkptr->leftside), right_it(&blkptr->rightside) { block = blkptr; // remember block // non empty list if (!blkptr->leftside.empty()) { start_block(); // ready for iteration } } /********************************************************************** * BLOCK_RECT_IT::set_to_block * * Start a new block. **********************************************************************/ void BLOCK_RECT_IT::set_to_block( // start (new) block PDBLK *blkptr) { // block to start block = blkptr; // remember block // set iterators left_it.set_to_list(&blkptr->leftside); right_it.set_to_list(&blkptr->rightside); if (!blkptr->leftside.empty()) { start_block(); // ready for iteration } } /********************************************************************** * BLOCK_RECT_IT::start_block * * Restart a block. **********************************************************************/ void BLOCK_RECT_IT::start_block() { // start (new) block left_it.move_to_first(); right_it.move_to_first(); left_it.mark_cycle_pt(); right_it.mark_cycle_pt(); ymin = left_it.data()->y(); // bottom of first box ymax = left_it.data_relative(1)->y(); if (right_it.data_relative(1)->y() < ymax) { // smallest step ymax = right_it.data_relative(1)->y(); } } /********************************************************************** * BLOCK_RECT_IT::forward * * Move to the next rectangle in the block. **********************************************************************/ void BLOCK_RECT_IT::forward() { // next rectangle if (!left_it.empty()) { // non-empty list if (left_it.data_relative(1)->y() == ymax) { left_it.forward(); // move to meet top } if (right_it.data_relative(1)->y() == ymax) { right_it.forward(); } // last is special if (left_it.at_last() || right_it.at_last()) { left_it.move_to_first(); // restart right_it.move_to_first(); // now at bottom ymin = left_it.data()->y(); } else { ymin = ymax; // new bottom } // next point ymax = left_it.data_relative(1)->y(); if (right_it.data_relative(1)->y() < ymax) { // least step forward ymax = right_it.data_relative(1)->y(); } } } /********************************************************************** * BLOCK_LINE_IT::get_line * * Get the start and width of a line in the block. **********************************************************************/ TDimension BLOCK_LINE_IT::get_line( // get a line TDimension y, // line to get TDimension &xext // output extent ) { ICOORD bleft; // bounding box ICOORD tright; // of block & rect // get block box block->bounding_box(bleft, tright); if (y < bleft.y() || y >= tright.y()) { // block->print(stderr,false); BADBLOCKLINE.error("BLOCK_LINE_IT::get_line", ABORT, "Y=%d", y); } // get rectangle box rect_it.bounding_box(bleft, tright); // inside rectangle if (y >= bleft.y() && y < tright.y()) { // width of line xext = tright.x() - bleft.x(); return bleft.x(); // start of line } for (rect_it.start_block(); !rect_it.cycled_rects(); rect_it.forward()) { // get rectangle box rect_it.bounding_box(bleft, tright); // inside rectangle if (y >= bleft.y() && y < tright.y()) { // width of line xext = tright.x() - bleft.x(); return bleft.x(); // start of line } } LOSTBLOCKLINE.error("BLOCK_LINE_IT::get_line", ABORT, "Y=%d", y); return 0; // dummy to stop warning } } // namespace tesseract
