void read_and_textord(                       //read .pb file
                      const char *filename,  //.pb file
                      BLOCK_LIST *blocks) {
  int c;                         //input character
  FILE *infp;                    //input file
  BLOCK *block;                  //current block
  BOX page_box;                  //bounding_box
  BLOCK_IT block_it = blocks;    //iterator
                                 //different orientations
  TO_BLOCK_LIST land_blocks, port_blocks;

  infp = fopen (filename, "r");
  if (infp == NULL)
    CANTOPENFILE.error ("read_and_textord", EXIT, filename);

  while (((c = fgetc (infp)) != EOF) && (ungetc (c, infp) != EOF)) {
                                 //get one
    block = BLOCK::de_serialise (infp);
                                 //add to list
    block_it.add_after_then_move (block);
                                 //find page size
    page_box += block->bounding_box ();
  }
  fclose(infp);

  assign_blobs_to_blocks2(blocks, &land_blocks, &port_blocks);
  filter_blobs (page_box.topright (), &port_blocks, !textord_test_landscape);
  filter_blobs (page_box.topright (), &land_blocks, textord_test_landscape);
  textord_page (page_box.topright (), blocks, &land_blocks, &port_blocks);
}
// Segment the page according to the current value of tessedit_pageseg_mode.
// If the pix_binary_ member is not NULL, it is used as the source image,
// and copied to image, otherwise it just uses image as the input.
// On return the blocks list owns all the constructed page layout.
int Tesseract::SegmentPage(const STRING* input_file,
                           IMAGE* image, BLOCK_LIST* blocks) {
  int width = image->get_xsize();
  int height = image->get_ysize();
  int resolution = image->get_res();
#ifdef HAVE_LIBLEPT
  if (pix_binary_ != NULL) {
    width = pixGetWidth(pix_binary_);
    height = pixGetHeight(pix_binary_);
    resolution = pixGetXRes(pix_binary_);
  }
#endif
  // Zero resolution messes up the algorithms, so make sure it is credible.
  if (resolution < kMinCredibleResolution)
    resolution = kDefaultResolution;
  // Get page segmentation mode.
  PageSegMode pageseg_mode = static_cast<PageSegMode>(
      static_cast<int>(tessedit_pageseg_mode));
  // If a UNLV zone file can be found, use that instead of segmentation.
  if (pageseg_mode != tesseract::PSM_AUTO &&
      input_file != NULL && input_file->length() > 0) {
    STRING name = *input_file;
    const char* lastdot = strrchr(name.string(), '.');
    if (lastdot != NULL)
      name[lastdot - name.string()] = '\0';
    read_unlv_file(name, width, height, blocks);
  }
  bool single_column = pageseg_mode > PSM_AUTO;
  if (blocks->empty()) {
    // No UNLV file present. Work according to the PageSegMode.
    // First make a single block covering the whole image.
    BLOCK_IT block_it(blocks);
    BLOCK* block = new BLOCK("", TRUE, 0, 0, 0, 0, width, height);
    block_it.add_to_end(block);
  } else {
    // UNLV file present. Use PSM_SINGLE_COLUMN.
    pageseg_mode = PSM_SINGLE_COLUMN;
  }

  TO_BLOCK_LIST land_blocks, port_blocks;
  TBOX page_box;
  if (pageseg_mode <= PSM_SINGLE_COLUMN) {
    if (AutoPageSeg(width, height, resolution, single_column,
                    image, blocks, &port_blocks) < 0) {
      return -1;
    }
    // To create blobs from the image region bounds uncomment this line:
    //  port_blocks.clear();  // Uncomment to go back to the old mode.
  } else {
#if HAVE_LIBLEPT
    image->FromPix(pix_binary_);
#endif
    deskew_ = FCOORD(1.0f, 0.0f);
    reskew_ = FCOORD(1.0f, 0.0f);
  }
  if (blocks->empty()) {
    tprintf("Empty page\n");
    return 0;  // AutoPageSeg found an empty page.
  }

  if (port_blocks.empty()) {
    // AutoPageSeg was not used, so we need to find_components first.
    find_components(blocks, &land_blocks, &port_blocks, &page_box);
  } else {
    // AutoPageSeg does not need to find_components as it did that already.
    page_box.set_left(0);
    page_box.set_bottom(0);
    page_box.set_right(width);
    page_box.set_top(height);
    // Filter_blobs sets up the TO_BLOCKs the same as find_components does.
    filter_blobs(page_box.topright(), &port_blocks, true);
  }

  TO_BLOCK_IT to_block_it(&port_blocks);
  ASSERT_HOST(!port_blocks.empty());
  TO_BLOCK* to_block = to_block_it.data();
  if (pageseg_mode <= PSM_SINGLE_BLOCK ||
      to_block->line_size < 2) {
    // For now, AUTO, SINGLE_COLUMN and SINGLE_BLOCK all map to the old
    // textord. The difference is the number of blocks and how the are made.
    textord_page(page_box.topright(), blocks, &land_blocks, &port_blocks,
                 this);
  } else {
    // SINGLE_LINE, SINGLE_WORD and SINGLE_CHAR all need a single row.
    float gradient = make_single_row(page_box.topright(),
                                     to_block, &port_blocks, this);
    if (pageseg_mode == PSM_SINGLE_LINE) {
      // SINGLE_LINE uses the old word maker on the single line.
      make_words(page_box.topright(), gradient, blocks,
                 &land_blocks, &port_blocks, this);
    } else {
      // SINGLE_WORD and SINGLE_CHAR cram all the blobs into a
      // single word, and in SINGLE_CHAR mode, all the outlines
      // go in a single blob.
      make_single_word(pageseg_mode == PSM_SINGLE_CHAR,
                       to_block->get_rows(), to_block->block->row_list());
    }
  }
  return 0;
}
void edges_and_textord(                       //read .pb file
                       const char *filename,  //.pb file
                       BLOCK_LIST *blocks) {
  BLOCK *block;                  //current block
  char *lastdot;                 //of name
  STRING name = filename;        //truncated name
  ICOORD page_tr;
  BOX page_box;                  //bounding_box
  PDBLK_CLIST pd_blocks;         //copy of list
  BLOCK_IT block_it = blocks;    //iterator
  PDBLK_C_IT pd_it = &pd_blocks; //iterator
                                 //different orientations
  TO_BLOCK_LIST land_blocks, port_blocks;
  IMAGE thresh_image;            //thresholded

  lastdot = strrchr (name.string (), '.');
  if (lastdot != NULL)
    *lastdot = '\0';
  if (page_image.get_bpp () == 0) {
    name += tessedit_image_ext;
    if (page_image.read_header (name.string ()))
      CANTOPENFILE.error ("edges_and_textord", EXIT, name.string ());
    if (page_image.read (0))
      READFAILED.error ("edges_and_textord", EXIT, name.string ());
    name = filename;
    lastdot = strrchr (name.string (), '.');
    if (lastdot != NULL)
      *lastdot = '\0';
  }
  page_tr = ICOORD (page_image.get_xsize (), page_image.get_ysize ());
  read_pd_file (name, page_image.get_xsize (), page_image.get_ysize (),
    blocks);
  block_it.set_to_list (blocks);
  if (global_monitor != NULL)
    global_monitor->ocr_alive = TRUE;

  if (page_image.get_bpp () > 1) {
    set_global_loc_code(LOC_ADAPTIVE);
    for (block_it.mark_cycle_pt (); !block_it.cycled_list ();
    block_it.forward ()) {
      block = block_it.data ();
      pd_it.add_after_then_move (block);
    }
    //              adaptive_threshold(&page_image,&pd_blocks,&thresh_image);
    set_global_loc_code(LOC_EDGE_PROG);
#ifndef EMBEDDED
    previous_cpu = clock ();
#endif
    for (block_it.mark_cycle_pt (); !block_it.cycled_list ();
    block_it.forward ()) {
      block = block_it.data ();
      if (!polygon_tess_approximation)
        invert_image(&page_image);
#ifndef GRAPHICS_DISABLED
      extract_edges(NO_WINDOW, &page_image, &thresh_image, page_tr, block);
#else
      extract_edges(&page_image, &thresh_image, page_tr, block);
#endif
      page_box += block->bounding_box ();
    }
    page_image = thresh_image;   //everyone else gets it
  }
  else {
    set_global_loc_code(LOC_EDGE_PROG);
    if (!page_image.white_high ())
      invert_image(&page_image);

#ifndef EMBEDDED
    previous_cpu = clock ();
#endif

    for (block_it.mark_cycle_pt (); !block_it.cycled_list ();
    block_it.forward ()) {
      block = block_it.data ();
#ifndef GRAPHICS_DISABLED
      extract_edges(NO_WINDOW, &page_image, &page_image, page_tr, block);
#else
      extract_edges(&page_image, &page_image, page_tr, block);
#endif
      page_box += block->bounding_box ();
    }
  }
  if (global_monitor != NULL) {
    global_monitor->ocr_alive = TRUE;
    global_monitor->progress = 10;
  }

  assign_blobs_to_blocks2(blocks, &land_blocks, &port_blocks);
  if (global_monitor != NULL)
    global_monitor->ocr_alive = TRUE;
  filter_blobs (page_box.topright (), &land_blocks, textord_test_landscape);
#ifndef EMBEDDED
  previous_cpu = clock ();
#endif
  filter_blobs (page_box.topright (), &port_blocks, !textord_test_landscape);
  if (global_monitor != NULL)
    global_monitor->ocr_alive = TRUE;
  textord_page (page_box.topright (), blocks, &land_blocks, &port_blocks);
}