display/pgedit.cpp

Go to the documentation of this file.
00001 
00033 #include "mfcpch.h"
00034 #include          <ctype.h>
00035 #include          <math.h>
00036 #include          "cmndwin.h"
00037 #include          "genblob.h"
00038 #include          "pgedit.h"
00039 #include          "pgeditx.h"
00040 #include          "tessio.h"
00041 #include          "tessout.h"
00042 #include          "submen.h"
00043 #include          "varblwin.h"
00044 #include          "tordmain.h"
00045 #include          "statistc.h"
00046 #include          "debugwin.h"
00047 #include          "showim.h"
00048 #include          "mainblk.h"
00049 #include          "evnts.h"
00050 
00051 #define ASC_HEIGHT      (2 * bln_baseline_offset + bln_x_height)
00052 #define X_HEIGHT        (bln_baseline_offset + bln_x_height)
00053 #define BL_HEIGHT     bln_baseline_offset
00054 #define DESC_HEIGHT     0
00055 
00056 #define MAXSPACING      128
00057 
00058 const ERRCODE EMPTYBLOCKLIST = "No blocks to edit";
00059 extern IMAGE page_image;
00060 
00065 enum CMD_EVENTS
00066 {
00067   NULL_CMD_EVENT,
00068   DELETE_CMD_EVENT,
00069   COPY_CMD_EVENT,
00070   CHANGE_DISP_CMD_EVENT,
00071   CHANGE_TEXT_CMD_EVENT,
00072   TOGGLE_SEG_CMD_EVENT,
00073   DUMP_WERD_CMD_EVENT,
00074   SHOW_POINT_CMD_EVENT,
00075   ROW_SPACE_STAT_CMD_EVENT,
00076   BLOCK_SPACE_STAT_CMD_EVENT,
00077   SHOW_BLN_WERD_CMD_EVENT,
00078   SEGMENT_WERD_CMD_EVENT,
00079   BOUNDING_BOX_CMD_EVENT,
00080   CORRECT_TEXT_CMD_EVENT,
00081   POLYGONAL_CMD_EVENT,
00082   BL_NORM_CMD_EVENT,
00083   BITMAP_CMD_EVENT,
00084   TIDY_CMD_EVENT,
00085   VIEW_CMD_EVENT,
00086   IMAGE_CMD_EVENT,
00087   BLOCKS_CMD_EVENT,
00088   BASELINES_CMD_EVENT,
00089   WRITE_CMD_EVENT,
00090   SMD_CMD_EVENT,
00091   NEW_SOURCE_CMD_EVENT,
00092   UNIFORM_DISP_CMD_EVENT,
00093   REFRESH_CMD_EVENT,
00094   QUIT_CMD_EVENT
00095 };
00096 
00097 #define EXTENDED_MODES_BASE 1000 //for extended cmd ids
00098 #define EXTENDED_OTHER_BASE 2000
00099 
00100 /* ==================
00101    Some global data
00102  ==================== */
00103 
00104 RADIO_MENU *modes_menu_item;
00105 RADIO_MENU_LEAF *change_display_menu_item;
00106 SIMPLE_MENU_LEAF *view_menu_item;
00107 RADIO_MENU_LEAF *copy_menu_item;
00108 VARIABLE_MENU_LEAF *write_menu_item;
00109 
00110 #ifdef __UNIX__
00111 FILE *debug_window = NULL;       //opened on demand
00112 #endif
00113                                  //baseline norm words
00114 WINDOW bln_word_window = NO_WINDOW;
00115 
00116 CMD_EVENTS mode = CHANGE_DISP_CMD_EVENT;
00117                                  //Selected words op
00118 
00119 BITS16 word_display_mode;
00120 BOOL8 display_image = FALSE;
00121 BOOL8 display_blocks = FALSE;
00122 BOOL8 display_baselines = FALSE;
00123 BOOL8 viewing_source = TRUE;
00124 
00125 BLOCK_LIST *source_block_list = NULL;    //image blocks
00126 BLOCK_LIST target_block_list;    //target blocks
00127 BLOCK_LIST *other_block_list = &target_block_list;
00128 
00129 BOOL8 source_changed = FALSE;    //Changes not saved
00130 BOOL8 target_changed = FALSE;    //Changes not saved
00131 BOOL8 *other_image_changed = &target_changed;
00132 
00133 /* Public globals */
00134 
00135 #define EXTERN
00136 
00137                                  //image window
00138 EXTERN WINDOW image_win = NO_WINDOW;
00139 EXTERN COMMAND_WINDOW *command_window;
00140 
00141 EXTERN BLOCK_LIST *current_block_list = NULL;
00142 EXTERN BOOL8 *current_image_changed = &source_changed;
00143 EXTERN void (*show_pt_handler) (GRAPHICS_EVENT *) = NULL;
00144 
00145 /* Variables */
00146 
00149 EXTERN STRING_VAR (editor_image_win_name, "EditorImage",
00150 "Editor image window name");
00151 EXTERN INT_VAR (editor_image_xpos, 590, "Editor image X Pos");
00152 EXTERN INT_VAR (editor_image_ypos, 10, "Editor image Y Pos");
00153 EXTERN INT_VAR (editor_image_height, 680, "Editor image height");
00154 EXTERN INT_VAR (editor_image_width, 655, "Editor image width");
00155 EXTERN INT_VAR (editor_image_word_bb_color, BLUE, "Word bounding box colour");
00156 EXTERN INT_VAR (editor_image_blob_bb_color, YELLOW,
00157 "Blob bounding box colour");
00158 EXTERN INT_VAR (editor_image_text_color, WHITE, "Correct text colour");
00159 
00160 EXTERN STRING_VAR (editor_dbwin_name, "EditorDBWin",
00161 "Editor debug window name");
00162 EXTERN INT_VAR (editor_dbwin_xpos, 50, "Editor debug window X Pos");
00163 EXTERN INT_VAR (editor_dbwin_ypos, 500, "Editor debug window Y Pos");
00164 EXTERN INT_VAR (editor_dbwin_height, 24, "Editor debug window height");
00165 EXTERN INT_VAR (editor_dbwin_width, 80, "Editor debug window width");
00166 
00167 EXTERN STRING_VAR (editor_word_name, "BlnWords", "BL normalised word window");
00168 EXTERN INT_VAR (editor_word_xpos, 60, "Word window X Pos");
00169 EXTERN INT_VAR (editor_word_ypos, 510, "Word window Y Pos");
00170 EXTERN INT_VAR (editor_word_height, 240, "Word window height");
00171 EXTERN INT_VAR (editor_word_width, 655, "Word window width");
00172 
00173 EXTERN double_VAR (editor_smd_scale_factor, 1.0, "Scaling for smd image");
00193 void add_word(                             //to block list
00194               WERD *word,                  //word to be added
00195               ROW *src_row,                //source row
00196               BLOCK *src_block,            //source block
00197               BLOCK_LIST *dest_block_list  //add to this
00198              ) {
00199   BLOCK_IT block_it(dest_block_list);
00200   BLOCK *block;                  //current block
00201   BLOCK *dest_block = NULL;      //destination block
00202   ROW_IT row_it;
00203   ROW *row;                      //destination row
00204   ROW *dest_row = NULL;          //destination row
00205   WERD_IT word_it;
00206   BOX word_box = word->bounding_box ();
00207   BOX insert_point_word_box;
00208   BOOL8 seen_blocks_for_current_file = FALSE;
00209 
00210   block_it.mark_cycle_pt ();
00211   while (!block_it.cycled_list () && (dest_block == NULL)) {
00212     block = block_it.data ();
00213     if ((block->bounding_box ().contains (word_box)) &&
00214     (strcmp (block->name (), src_block->name ()) == 0)) {
00215       dest_block = block;        //found dest block
00216       row_it.set_to_list (block->row_list ());
00217       row_it.mark_cycle_pt ();
00218       while ((!row_it.cycled_list ()) && (dest_row == NULL)) {
00219         row = row_it.data ();
00220         if (row->bounding_box ().contains (word_box))
00221           dest_row = row;        //found dest row
00222         else
00223           row_it.forward ();
00224       }
00225     }
00226     else
00227       block_it.forward ();
00228   }
00229 
00230   if (dest_block == NULL) {      //make a new one
00231     dest_block = new BLOCK;
00232     *dest_block = *src_block;
00233 
00234     block_it.set_to_list (dest_block_list);
00235     for (block_it.mark_cycle_pt ();
00236     !block_it.cycled_list (); block_it.forward ()) {
00237       block = block_it.data ();
00238 
00239       if (!seen_blocks_for_current_file &&
00240         (strcmp (block->name (), dest_block->name ()) == 0))
00241         seen_blocks_for_current_file = TRUE;
00242 
00243       if (seen_blocks_for_current_file &&
00244         ((strcmp (block->name (), dest_block->name ()) != 0) ||
00245         (block->bounding_box ().top () <
00246         dest_block->bounding_box ().top ())))
00247         break;
00248     }
00249 
00250     if (block_it.cycled_list ())
00251                                  //didn't find insrt pt
00252       block_it.add_to_end (dest_block);
00253     else
00254                                  //did find insert pt
00255       block_it.add_before_stay_put (dest_block);
00256   }
00257 
00258   if (dest_row == NULL) {        //make a new one
00259     dest_row = new ROW;
00260     *dest_row = *src_row;
00261 
00262     row_it.set_to_list (dest_block->row_list ());
00263     for (row_it.mark_cycle_pt (); !row_it.cycled_list (); row_it.forward ()) {
00264       if (row_it.data ()->bounding_box ().top () <
00265         dest_row->bounding_box ().top ())
00266         break;
00267     }
00268 
00269     if (row_it.cycled_list ())
00270                                  //didn't find insrt pt
00271         row_it.add_to_end (dest_row);
00272     else
00273                                  //did find insert pt
00274       row_it.add_before_stay_put (dest_row);
00275   }
00276 
00277   /* dest_block and dest_row are now found or built and inserted as necessesary
00278     so add the word to dest row */
00279 
00280   word_it.set_to_list (dest_row->word_list ());
00281   for (word_it.mark_cycle_pt (); !word_it.cycled_list (); word_it.forward ()) {
00282     if (word_it.data ()->bounding_box ().right () >= word_box.left ())
00283       break;
00284   }
00285 
00286   if (word_it.cycled_list ())
00287     word_it.add_to_end (word);   //didn't find insrt pt
00288   else {                         //did find insert pt
00289     insert_point_word_box = word_it.data ()->bounding_box ();
00290     if (insert_point_word_box.contains (word_box) ||
00291       word_box.contains (insert_point_word_box))
00292       command_window->
00293         msg
00294         ("Refusing to add words which obliterate, or are obliterated by, others");
00295     else {
00296       if (word_it.data ()->bounding_box ().left () >
00297         word->bounding_box ().left ())
00298                                  //infront of insert pt
00299         word_it.add_before_stay_put (word);
00300       else
00301                                  //behind insert pt
00302         word_it.add_after_stay_put (word);
00303     }
00304   }
00305 }
00306 
00307 
00311 WINDOW bln_word_window_handle() {  //return handle
00312                                  //not opened yet
00313   if (bln_word_window == NO_WINDOW) {
00314     pgeditor_msg ("Creating BLN word window...");
00315                                  // xmin, xmax
00316     bln_word_window = create_window (editor_word_name.string (),
00317       SCROLLINGWIN, editor_word_xpos, editor_word_ypos,
00318       editor_word_width, editor_word_height, -2000.0, 2000.0,
00319       DESC_HEIGHT - 30.0f,
00320       ASC_HEIGHT + 30.0f,
00321                                  // ymin, ymax
00322       TRUE, FALSE, FALSE, FALSE);
00323     // down event only
00324 
00325     pgeditor_msg ("Creating BLN word window...Done");
00326   }
00327   return bln_word_window;
00328 }
00329 
00330 
00336 void build_image_window(BOX page_bounding_box) {
00337   if (image_win != NO_WINDOW)
00338     destroy_window(image_win);
00339 
00340                                  // xmin
00341   image_win = create_window (editor_image_win_name.string (),
00342    SCROLLINGWIN, editor_image_xpos, editor_image_ypos,
00343    editor_image_width, editor_image_height, 0.0,
00344     (float) page_bounding_box.right () + 1,
00345   // xmax
00346     0.0,                         // ymin
00347     (float) page_bounding_box.top () + 1,
00348   // ymax
00349     TRUE, FALSE, TRUE, FALSE);   //down and up only
00350 }
00351 
00352 
00356 MENU_ROOT *build_menu() {
00357   NON_RADIO_MENU *parent_menu;
00358   MENU_ROOT *root_menu_item;
00359 
00360   root_menu_item = new MENU_ROOT ();
00361 
00362   modes_menu_item = new RADIO_MENU ("MODES");
00363   root_menu_item->add_child (modes_menu_item);
00364 
00365   change_display_menu_item = new RADIO_MENU_LEAF ("Change Display",
00366     CHANGE_DISP_CMD_EVENT);
00367   modes_menu_item->add_child (change_display_menu_item);
00368   modes_menu_item->add_child (new RADIO_MENU_LEAF ("Delete",
00369     DELETE_CMD_EVENT));
00370   copy_menu_item = new RADIO_MENU_LEAF ("Copy to TARGET", COPY_CMD_EVENT);
00371   modes_menu_item->add_child (copy_menu_item);
00372   modes_menu_item->add_child (new RADIO_MENU_LEAF ("Change Text",
00373     CHANGE_TEXT_CMD_EVENT));
00374   modes_menu_item->add_child (new RADIO_MENU_LEAF ("Toggle Correct Seg Flg",
00375     TOGGLE_SEG_CMD_EVENT));
00376   modes_menu_item->add_child (new RADIO_MENU_LEAF ("Dump Word",
00377     DUMP_WERD_CMD_EVENT));
00378   modes_menu_item->add_child (new RADIO_MENU_LEAF ("Show Point",
00379     SHOW_POINT_CMD_EVENT));
00380   modes_menu_item->add_child (new RADIO_MENU_LEAF ("Row gaps hist",
00381     ROW_SPACE_STAT_CMD_EVENT));
00382   modes_menu_item->add_child (new RADIO_MENU_LEAF ("Block gaps hist",
00383     BLOCK_SPACE_STAT_CMD_EVENT));
00384   modes_menu_item->add_child (new RADIO_MENU_LEAF ("Show BL Norm Word",
00385     SHOW_BLN_WERD_CMD_EVENT));
00386   modes_menu_item->add_child (new RADIO_MENU_LEAF ("Re-Segment Word",
00387     SEGMENT_WERD_CMD_EVENT));
00388 
00389   parent_menu = new NON_RADIO_MENU ("DISPLAY");
00390   root_menu_item->add_child (parent_menu);
00391 
00392   parent_menu->add_child (new TOGGLE_MENU_LEAF ("Bounding Boxes",
00393     BOUNDING_BOX_CMD_EVENT,
00394     TRUE));
00395   parent_menu->add_child (new TOGGLE_MENU_LEAF ("Correct Text",
00396     CORRECT_TEXT_CMD_EVENT,
00397     FALSE));
00398   parent_menu->add_child (new TOGGLE_MENU_LEAF ("Polygonal Approx",
00399     POLYGONAL_CMD_EVENT, FALSE));
00400   parent_menu->add_child (new TOGGLE_MENU_LEAF ("Baseline Normalised",
00401     BL_NORM_CMD_EVENT, FALSE));
00402   parent_menu->add_child (new TOGGLE_MENU_LEAF ("Edge Steps",
00403     BITMAP_CMD_EVENT, FALSE));
00404 
00405   parent_menu = new NON_RADIO_MENU ("OTHER");
00406   root_menu_item->add_child (parent_menu);
00407 
00408   parent_menu->add_child (new SIMPLE_MENU_LEAF ("Quit", QUIT_CMD_EVENT));
00409   parent_menu->add_child (new SIMPLE_MENU_LEAF ("Tidy Target",
00410     TIDY_CMD_EVENT));
00411   view_menu_item = new SIMPLE_MENU_LEAF ("View TARGET", VIEW_CMD_EVENT);
00412   parent_menu->add_child (view_menu_item);
00413   parent_menu->add_child (new TOGGLE_MENU_LEAF ("Show Image",
00414     IMAGE_CMD_EVENT, FALSE));
00415   parent_menu->add_child (new TOGGLE_MENU_LEAF ("ShowBlock Outlines",
00416     BLOCKS_CMD_EVENT, FALSE));
00417   parent_menu->add_child (new TOGGLE_MENU_LEAF ("Show Baselines",
00418     BASELINES_CMD_EVENT, FALSE));
00419   write_menu_item = new VARIABLE_MENU_LEAF ("Write File",
00420     WRITE_CMD_EVENT,
00421     imagebasename.string ());
00422   parent_menu->add_child (write_menu_item);
00423   parent_menu->add_child (new SIMPLE_MENU_LEAF ("Make SMD Image",
00424     SMD_CMD_EVENT));
00425   parent_menu->add_child (new VARIABLE_MENU_LEAF ("New Source File",
00426     NEW_SOURCE_CMD_EVENT,
00427     imagebasename.string ()));
00428   parent_menu->add_child (new SIMPLE_MENU_LEAF ("Uniform Display",
00429     UNIFORM_DISP_CMD_EVENT));
00430   parent_menu->add_child (new SIMPLE_MENU_LEAF ("Refresh Display",
00431     REFRESH_CMD_EVENT));
00432 
00433                                  //Call driver program
00434   extend_menu(modes_menu_item,
00435               EXTENDED_MODES_BASE,
00436               parent_menu,
00437               EXTENDED_OTHER_BASE);
00438   return root_menu_item;
00439 }
00440 
00441 
00445 void debug_window_handle() {  //return handle
00446   //      if      ( debug_winth == NULL )                                                                 //not opened yet
00447   //      {
00448   //    pgeditor_msg( "Creating debug window..." );
00449   //  create_debug_window();
00450   pgeditor_msg ("Creating debug window...Done");
00451   //      }
00452 }
00453 
00454 
00458 void display_bln_lines(WINDOW window,
00459                        COLOUR colour,
00460                        float scale_factor,
00461                        float y_offset,
00462                        float minx,
00463                        float maxx) {
00464   line_color_index(window, colour);
00465   line_type(window, SOLID);
00466   move2d (window, minx, y_offset + scale_factor * DESC_HEIGHT);
00467   draw2d (window, maxx, y_offset + scale_factor * DESC_HEIGHT);
00468   move2d (window, minx, y_offset + scale_factor * BL_HEIGHT);
00469   draw2d (window, maxx, y_offset + scale_factor * BL_HEIGHT);
00470   move2d (window, minx, y_offset + scale_factor * X_HEIGHT);
00471   draw2d (window, maxx, y_offset + scale_factor * X_HEIGHT);
00472   move2d (window, minx, y_offset + scale_factor * ASC_HEIGHT);
00473   draw2d (window, maxx, y_offset + scale_factor * ASC_HEIGHT);
00474 }
00475 
00476 
00480 void do_new_source(            //serialise
00481                    char *name  //file name
00482                   ) {
00483   FILE *infp;                    //input file
00484   char msg_str[MAX_CHARS + 1];
00485   STRING name_str(name);
00486   char response_str[MAX_CHARS + 1];
00487   char *token;                   //first response token
00488 
00489   if (source_changed) {
00490     response_str[0] = '\0';
00491     command_window->prompt ("Source changes will be LOST.  Continue? (Y/N)",
00492       response_str);
00493     token = strtok (response_str, " ");
00494     if (tolower (token[0]) != 'y')
00495       return;
00496   }
00497 
00498                                  //if not file exists
00499   if (!(infp = fopen (name, "r"))) {
00500     sprintf (msg_str, "Cant open file " "%s" "", name);
00501     command_window->msg (msg_str);
00502     return;
00503   }
00504 
00505   fclose(infp);
00506   sprintf (msg_str, "Reading file " "%s" "...", name);
00507   command_window->msg (msg_str);
00508   source_block_list->clear ();
00509                                  //appends to SOURCE
00510   pgeditor_read_file(name_str, source_block_list);
00511   source_changed = FALSE;
00512   command_window->msg ("Doing automatic Tidy Target...");
00513   viewing_source = FALSE;        //Force viewing source
00514   do_tidy_cmd();
00515   command_window->msg ("Doing automatic Tidy Target...Done");
00516 }
00517 
00518 
00522 void do_re_display (
00523 BOOL8 word_painter ( //function to call
00524 BLOCK *, ROW *, WERD *)
00525 ) {
00526   BLOCK_IT block_it(current_block_list);
00527   BLOCK *block;
00528   int block_count = 1;
00529 
00530   ROW_IT row_it;
00531   ROW *row;
00532 
00533   WERD_IT word_it;
00534   WERD *word;
00535 
00536   clear_view_surface(image_win);
00537   if (display_image) {
00538     show_sub_image (&page_image, 0, 0,
00539       page_image.get_xsize (), page_image.get_ysize (),
00540       image_win, 0, 0);
00541   }
00542 
00543   for (block_it.mark_cycle_pt ();
00544   !block_it.cycled_list (); block_it.forward ()) {
00545     block = block_it.data ();
00546     row_it.set_to_list (block->row_list ());
00547     for (row_it.mark_cycle_pt (); !row_it.cycled_list (); row_it.forward ()) {
00548       row = row_it.data ();
00549       word_it.set_to_list (row->word_list ());
00550       for (word_it.mark_cycle_pt ();
00551       !word_it.cycled_list (); word_it.forward ()) {
00552         word = word_it.data ();
00553         word_painter(block, row, word);
00554       }
00555       if (display_baselines)
00556         row->plot_baseline (image_win, GREEN);
00557     }
00558     if (display_blocks)
00559       block->plot (image_win, block_count++, RED);
00560   }
00561 }
00562 
00563 
00567 const BOX do_tidy_cmd() {  //tidy
00568   ICOORD shift_vector;
00569   BOX tidy_box;                  //Just the tidy area
00570   BOX source_box;                //source file area
00571 
00572   source_box = block_list_bounding_box (source_block_list);
00573   //find src area
00574 
00575   if (!target_block_list.empty ()) {
00576     tidy_box = block_list_compress (&target_block_list);
00577 
00578     /* Shift tidied target above the source image area. */
00579 
00580     shift_vector = ICOORD (0, source_box.top () + BLOCK_SPACING)
00581       - tidy_box.botleft ();
00582     block_list_move(&target_block_list, shift_vector);
00583     tidy_box.move (shift_vector);
00584   }
00585   source_box += tidy_box;
00586                                  //big enough for both
00587   build_image_window(source_box);
00588   do_view_cmd();
00589   return tidy_box;
00590 }
00591 
00592 
00596 void do_view_cmd() {
00597   viewing_source = !viewing_source;
00598   clear_view_surface(image_win);
00599   if (viewing_source) {
00600     current_block_list = source_block_list;
00601     current_image_changed = &source_changed;
00602     other_block_list = &target_block_list;
00603     other_image_changed = &target_changed;
00604     do_re_display(&word_display);
00605 
00606     command_window->replace_menu_text (view_menu_item, "View TARGET");
00607     command_window->replace_menu_text (copy_menu_item, "Copy to TARGET");
00608     write_menu_item->replace_value (imagebasename.string ());
00609   }
00610   else {
00611     current_block_list = &target_block_list;
00612     current_image_changed = &target_changed;
00613     other_block_list = source_block_list;
00614     other_image_changed = &source_changed;
00615     do_re_display(&word_display);
00616 
00617     command_window->replace_menu_text (view_menu_item, "View SOURCE");
00618     command_window->replace_menu_text (copy_menu_item, "");
00619     write_menu_item->replace_value ((imagebasename + ".bits.pg").string ());
00620   }
00621 }
00622 
00623 
00629 void do_write_file(            //serialise
00630                    char *name  //file name
00631                   ) {
00632   FILE *infp;                    //input file
00633   char msg_str[MAX_CHARS + 1];
00634   char response_str[MAX_CHARS + 1];
00635   char *token;                   //first response token
00636   BOX enclosing_box;
00637 
00638                                  //if file exists
00639   if ((infp = fopen (name, "r")) != NULL) {
00640     fclose(infp);
00641     sprintf (msg_str, "Overwrite file " "%s" "? (Y/N)", name);
00642     response_str[0] = '\0';
00643     if (!command_window->prompt (msg_str, response_str))
00644       return;
00645     token = strtok (response_str, " ");
00646     if (tolower (token[0]) != 'y')
00647       return;                    // dont write
00648   }
00649 
00650   infp = fopen (name, "w");      //can we write to it?
00651   if (infp == NULL) {
00652     sprintf (msg_str, "Cant write to file " "%s" "", name);
00653     command_window->msg (msg_str);
00654     return;
00655   }
00656   fclose(infp);
00657 
00658   if (!viewing_source && !target_block_list.empty ()) {
00659                                  //Tidy & move to (0,0)
00660     command_window->msg ("Automatic tidy...");
00661     viewing_source = TRUE;       //Stay viewing target!
00662     enclosing_box = do_tidy_cmd ();
00663     block_list_move (&target_block_list, -enclosing_box.botleft ());
00664     command_window->msg ("Writing file...");
00665     pgeditor_write_file(name, &target_block_list);
00666                                  //move back
00667     block_list_move (&target_block_list,
00668       enclosing_box.botleft ());
00669   }
00670   else {
00671     command_window->msg ("Writing file...");
00672     pgeditor_write_file(name, current_block_list);
00673   }
00674   command_window->msg ("Writing file...Done");
00675   *current_image_changed = FALSE;
00676 }
00677 
00678 
00682 void smd_cmd() {
00683   char response_str[MAX_CHARS + 1];
00684   WINDOW display_window;         //temp
00685   ICOORD tr, bl;
00686   BOX page_box = block_list_bounding_box (current_block_list);
00687 
00688   bl = ICOORD (0, 0);
00689   tr = ICOORD (page_image.get_xsize () + 1, page_image.get_ysize () + 1);
00690   page_box += BOX (bl, tr);
00691 
00692   strcpy (response_str, imagebasename.string ());
00693   strcpy (response_str + imagebasename.length (), ".smd.tif");
00694   command_window->prompt ("SMD File Name?", response_str);
00695 
00696   display_window = image_win;
00697                                  // xmin
00698   image_win = create_window (response_str, SMDWINDOW, 0, 0,
00699    (INT16) (page_box.width () * editor_smd_scale_factor),
00700    (INT16) (page_box.height () * editor_smd_scale_factor), 0.0,
00701     page_box.width (),           // xmax
00702     0.0,                         // ymin
00703     page_box.height (),          // ymax
00704     FALSE, FALSE, FALSE, FALSE); //down and up only
00705   do_re_display(&word_display);
00706   destroy_window(image_win);  //Dumps sbd file
00707   image_win = display_window;
00708 }
00709 
00710 
00715 void pgeditor_main(BLOCK_LIST *blocks) {
00716   GRAPHICS_EVENT event;
00717   INT32 cmd_event = 0;
00718   char new_value[MAX_CHARS + 1];
00719   BOOL8 exit = FALSE;
00720 
00721   source_block_list = blocks;
00722   current_block_list = blocks;
00723   if (current_block_list->empty ())
00724     return;
00725 
00726   command_window = new COMMAND_WINDOW ("WordEditorCmd", build_menu ());
00727   build_image_window (block_list_bounding_box (source_block_list));
00728   do_re_display(&word_display);
00729   word_display_mode.turn_on_bit (DF_BOX);
00730 
00731   while (!exit) {
00732     overlap_picture_ops(TRUE);
00733     await_event (0,              //all windows
00734       TRUE,                      //wait for event
00735       ANY_EVENT, &event);
00736                                  //Command win event
00737     if (event.fd == command_window->window ()) {
00738       command_window->msg ("");  //Clear old message
00739       command_window->event (event, &cmd_event, new_value);
00740       exit = process_cmd_win_event (cmd_event, new_value);
00741     }
00742     else {
00743       if (event.fd == image_win)
00744         process_image_event(event);
00745       else
00746         pgeditor_show_point(&event);
00747     }
00748     current_word_quit.set_value (FALSE);
00749     selection_quit.set_value (FALSE);
00750                                  //replot all var wins
00751     VARIABLES_WINDOW::plot_all();
00752   }
00753 }
00754 
00755 
00759 void pgeditor_msg(  //message display
00760                   const char *msg) {
00761   if (command_window == NO_WINDOW) {
00762     tprintf(msg);
00763     tprintf ("\n");
00764   }
00765   else
00766     command_window->msg (msg);
00767 }
00768 
00769 
00773 void pgeditor_read_file(                    //of serialised file
00774                         STRING &name,
00775                         BLOCK_LIST *blocks  //block list to add to
00776                        ) {
00777   int c;                         //input character
00778   FILE *infp;                    //input file
00779   BLOCK_IT block_it(blocks);  //iterator
00780   BLOCK *block;                  //current block
00781 
00782   ICOORD page_tr;                //topright of page
00783 
00784   char *filename_extension;
00785 
00786   block_it.move_to_last ();
00787 
00788                                  // ptr to last dot
00789   filename_extension = strrchr (name.string (), '.');
00790   #ifdef __UNIX__
00791   /*    TEXTROW*                tessrows;
00792       TBLOB*                  tessblobs;
00793       TPOINT                  tess_tr;
00794 
00795     if (strcmp( filename_extension, ".r" ) == 0)
00796     {
00797       tprintf( "Converting from .r file format.\n" );
00798       tessrows = get_tess_row_file( name.string(), //get the row file
00799                           &tess_tr );
00800       page_tr = ICOORD( tess_tr.x, tess_tr.y );
00801       make_blocks_from_rows( tessrows, name.string(), //reconstruct blocks
00802                     page_tr, TRUE, &block_it );
00803     }
00804     else if (strcmp( filename_extension, ".b" ) == 0)
00805     {
00806       tprintf( "Converting from .b file format.\n" );
00807       tessblobs = get_tess_blob_file( name.string(),  //get the blob file
00808                           &tess_tr );
00809       page_tr = ICOORD( tess_tr.x, tess_tr.y );
00810       make_blocks_from_blobs( tessblobs, name.string(),
00811                               //reconstruct blocks
00812                     page_tr, FALSE,blocks);
00813     }
00814      else*/
00815   if (strcmp (filename_extension, ".pb") == 0) {
00816     tprintf ("Converting from .pb file format.\n");
00817                                  //construct blocks
00818     read_and_textord (name.string (), blocks);
00819   }
00820   else
00821   #endif
00822   if ((strcmp (filename_extension, ".pg") == 0) ||
00823     // read a .pg file
00824                                // or a .sp file
00825   (strcmp (filename_extension, ".sp") == 0)) {
00826     tprintf ("Reading %s file format.\n", filename_extension);
00827     infp = fopen (name.string (), "r");
00828     if (infp == NULL)
00829       CANTOPENFILE.error ("pgeditor_read_file", EXIT, name.string ());
00830     //can't open file
00831 
00832     while (((c = fgetc (infp)) != EOF) && (ungetc (c, infp) != EOF)) {
00833                                //get one
00834       block = BLOCK::de_serialise (infp);
00835                                //add to list
00836       block_it.add_after_then_move (block);
00837     }
00838     fclose(infp);
00839   } else {
00840     edges_and_textord (name.string (), blocks);
00841   }
00842 }
00843 
00844 
00848 void pgeditor_show_point(  //display coords
00849                          GRAPHICS_EVENT *event) {
00850   char msg[160];
00851 
00852   sprintf (msg, "Pointing at (%f, %f)", event->x, event->y);
00853   command_window->msg (msg);
00854 }
00855 
00856 
00860 void pgeditor_write_file(                    //serialise
00861                          char *name,         //file name
00862                          BLOCK_LIST *blocks  //block list to write
00863                         ) {
00864   FILE *infp;                    //input file
00865   BLOCK_IT block_it(blocks);  //block iterator
00866   BLOCK *block;                  //current block
00867   ROW_IT row_it;                 //row iterator
00868 
00869   infp = fopen (name, "w");      //create output file
00870   if (infp == NULL)
00871     CANTCREATEFILE.error ("pgeditor_write_file", EXIT, name);
00872 
00873   for (block_it.mark_cycle_pt ();
00874   !block_it.cycled_list (); block_it.forward ()) {
00875     block = block_it.extract ();
00876 
00877     row_it.set_to_list (block->row_list ());
00878     for (row_it.mark_cycle_pt (); !row_it.cycled_list (); row_it.forward ())
00879                                  //ensure correct
00880       row_it.data ()->recalc_bounding_box ();
00881 
00882     block->serialise (infp);     //serialize     non-empty
00883     block_it.add_after_then_move (block);
00884   }
00885   fclose(infp);
00886 }
00887 
00888 
00893 BOOL8 process_cmd_win_event(                  //UI command semantics
00894                             INT32 cmd_event,  //which menu item?
00895                             char *new_value   //any prompt data
00896                            ) {
00897   char msg[160];
00898   BOOL8 exit = FALSE;
00899   char response_str[MAX_CHARS + 1];
00900   char *token;                   //first response token
00901 
00902   switch (cmd_event) {
00903     case NULL_CMD_EVENT:
00904       break;
00905 
00906     case VIEW_CMD_EVENT:
00907       do_view_cmd();
00908       break;
00909     case CHANGE_DISP_CMD_EVENT:
00910     case DELETE_CMD_EVENT:
00911     case CHANGE_TEXT_CMD_EVENT:
00912     case TOGGLE_SEG_CMD_EVENT:
00913     case DUMP_WERD_CMD_EVENT:
00914     case SHOW_POINT_CMD_EVENT:
00915     case ROW_SPACE_STAT_CMD_EVENT:
00916     case BLOCK_SPACE_STAT_CMD_EVENT:
00917     case SHOW_BLN_WERD_CMD_EVENT:
00918     case SEGMENT_WERD_CMD_EVENT:
00919       mode = (CMD_EVENTS) cmd_event;
00920       break;
00921     case COPY_CMD_EVENT:
00922       mode = (CMD_EVENTS) cmd_event;
00923       if (!viewing_source)
00924         command_window->msg ("Can't COPY while viewing target!");
00925       break;
00926     case BOUNDING_BOX_CMD_EVENT:
00927       if (new_value[0] == 'T')
00928         word_display_mode.turn_on_bit (DF_BOX);
00929       else
00930         word_display_mode.turn_off_bit (DF_BOX);
00931       command_window->press_radio_button (modes_menu_item,
00932         change_display_menu_item);
00933       mode = CHANGE_DISP_CMD_EVENT;
00934       break;
00935     case CORRECT_TEXT_CMD_EVENT:
00936       if (new_value[0] == 'T')
00937         word_display_mode.turn_on_bit (DF_TEXT);
00938       else
00939         word_display_mode.turn_off_bit (DF_TEXT);
00940       command_window->press_radio_button (modes_menu_item,
00941         change_display_menu_item);
00942       mode = CHANGE_DISP_CMD_EVENT;
00943       break;
00944     case POLYGONAL_CMD_EVENT:
00945       if (new_value[0] == 'T')
00946         word_display_mode.turn_on_bit (DF_POLYGONAL);
00947       else
00948         word_display_mode.turn_off_bit (DF_POLYGONAL);
00949       command_window->press_radio_button (modes_menu_item,
00950         change_display_menu_item);
00951       mode = CHANGE_DISP_CMD_EVENT;
00952       break;
00953     case BL_NORM_CMD_EVENT:
00954       if (new_value[0] == 'T')
00955         word_display_mode.turn_on_bit (DF_BN_POLYGONAL);
00956       else
00957         word_display_mode.turn_off_bit (DF_BN_POLYGONAL);
00958       command_window->press_radio_button (modes_menu_item,
00959         change_display_menu_item);
00960       mode = CHANGE_DISP_CMD_EVENT;
00961       break;
00962     case BITMAP_CMD_EVENT:
00963       if (new_value[0] == 'T')
00964         word_display_mode.turn_on_bit (DF_EDGE_STEP);
00965       else
00966         word_display_mode.turn_off_bit (DF_EDGE_STEP);
00967       command_window->press_radio_button (modes_menu_item,
00968         change_display_menu_item);
00969       mode = CHANGE_DISP_CMD_EVENT;
00970       break;
00971     case UNIFORM_DISP_CMD_EVENT:
00972       do_re_display(&word_set_display);
00973       *current_image_changed = TRUE;
00974       break;
00975     case WRITE_CMD_EVENT:
00976       do_write_file(new_value);
00977       break;
00978     case SMD_CMD_EVENT:
00979       smd_cmd();
00980       break;
00981     case TIDY_CMD_EVENT:
00982       if (!target_block_list.empty ()) {
00983         viewing_source = TRUE;   //Force viewing target
00984         do_tidy_cmd();
00985       }
00986       break;
00987     case NEW_SOURCE_CMD_EVENT:
00988       do_new_source(new_value);
00989       break;
00990     case IMAGE_CMD_EVENT:
00991       display_image = (new_value[0] == 'T');
00992       do_re_display(&word_display);
00993       break;
00994     case BLOCKS_CMD_EVENT:
00995       display_blocks = (new_value[0] == 'T');
00996       do_re_display(&word_display);
00997       break;
00998     case BASELINES_CMD_EVENT:
00999       display_baselines = (new_value[0] == 'T');
01000       do_re_display(&word_display);
01001       break;
01002     case REFRESH_CMD_EVENT:
01003       do_re_display(&word_display);
01004       break;
01005     case QUIT_CMD_EVENT:
01006       if (source_changed || target_changed) {
01007         response_str[0] = '\0';
01008         command_window->prompt ("Changes not saved. Exit anyway? (Y/N)",
01009           response_str);
01010         token = strtok (response_str, " ");
01011         if (tolower (token[0]) == 'y')
01012           exit = TRUE;
01013       }
01014       else
01015         exit = TRUE;
01016       break;
01017     default:
01018       if ((cmd_event >= EXTENDED_MODES_BASE) &&
01019         (cmd_event < EXTENDED_OTHER_BASE))
01020         mode = (CMD_EVENTS) cmd_event;
01021       else {
01022         if (cmd_event >= EXTENDED_OTHER_BASE)
01023           extend_unmoded_commands (cmd_event - EXTENDED_OTHER_BASE,
01024             new_value);
01025         else {
01026           sprintf (msg, "Unrecognised event " INT32FORMAT " (%s)",
01027             cmd_event, new_value);
01028           command_window->msg (msg);
01029         }
01030       }
01031       break;
01032   }
01033   return exit;
01034 }
01035 
01036 
01045 void process_image_event(  //action in image win
01046                          GRAPHICS_EVENT event) {
01047   static ICOORD down;
01048   ICOORD up;
01049   BOX selection_box;
01050   char msg[80];
01051 
01052   switch (event.type) {
01053     case DOWN_EVENT:
01054       down.set_x ((INT16) floor (event.x + 0.5));
01055       down.set_y ((INT16) floor (event.y + 0.5));
01056       if (mode == SHOW_POINT_CMD_EVENT)
01057         show_point (current_block_list, event.x, event.y);
01058       break;
01059 
01060     case UP_EVENT:
01061     case SELECT_EVENT:
01062       if (event.type == SELECT_EVENT) {
01063         down.set_x ((INT16) floor (event.xmax + 0.5));
01064         down.set_y ((INT16) floor (event.ymax + 0.5));
01065         if (mode == SHOW_POINT_CMD_EVENT)
01066           show_point (current_block_list, event.x, event.y);
01067       }
01068       if (mode != SHOW_POINT_CMD_EVENT)
01069         command_window->msg ("");//Clear old message
01070       up.set_x ((INT16) floor (event.x + 0.5));
01071       up.set_y ((INT16) floor (event.y + 0.5));
01072       selection_box = BOX (up, down);
01073 
01074       switch (mode) {
01075         case CHANGE_DISP_CMD_EVENT:
01076           process_selected_words(current_block_list,
01077                                  selection_box,
01078                                  &word_blank_and_set_display);
01079           break;
01080         case COPY_CMD_EVENT:
01081           if (!viewing_source)
01082             command_window->msg ("Can't COPY while viewing target!");
01083           else
01084             process_selected_words(current_block_list,
01085                                    selection_box,
01086                                    &word_copy);
01087           break;
01088         case DELETE_CMD_EVENT:
01089           process_selected_words_it(current_block_list,
01090                                     selection_box,
01091                                     &word_delete);
01092           break;
01093         case CHANGE_TEXT_CMD_EVENT:
01094           process_selected_words(current_block_list,
01095                                  selection_box,
01096                                  &word_change_text);
01097           break;
01098         case TOGGLE_SEG_CMD_EVENT:
01099           process_selected_words(current_block_list,
01100                                  selection_box,
01101                                  &word_toggle_seg);
01102           break;
01103         case DUMP_WERD_CMD_EVENT:
01104           process_selected_words(current_block_list,
01105                                  selection_box,
01106                                  &word_dumper);
01107           break;
01108         case SHOW_BLN_WERD_CMD_EVENT:
01109           process_selected_words(current_block_list,
01110                                  selection_box,
01111                                  &word_bln_display);
01112           break;
01113         case SEGMENT_WERD_CMD_EVENT:
01114           re_segment_word(current_block_list, selection_box);
01115           break;
01116         case ROW_SPACE_STAT_CMD_EVENT:
01117           row_space_stat(current_block_list, selection_box);
01118           break;
01119         case BLOCK_SPACE_STAT_CMD_EVENT:
01120           block_space_stat(current_block_list, selection_box);
01121           break;
01122         case SHOW_POINT_CMD_EVENT:
01123           break;                 //ignore up event
01124         default:
01125           if ((mode >= EXTENDED_MODES_BASE) && (mode < EXTENDED_OTHER_BASE))
01126             extend_moded_commands (mode - EXTENDED_MODES_BASE, selection_box);
01127           else {
01128             sprintf (msg, "Mode %d not yet implemented", mode);
01129             command_window->msg (msg);
01130           }
01131           break;
01132       }
01133     default:
01134       break;
01135   }
01136 }
01137 
01138 
01144 float re_scale_and_move_bln_word(   //put bln word in box
01145                                  WERD *norm_word,  //BL normalised word
01146                                  const BOX &box    //destination box
01147                                 ) {
01148   BOX norm_box = norm_word->bounding_box ();
01149   float width_scale_factor;
01150   float height_scale_factor;
01151   float selected_scale_factor;
01152 
01153   width_scale_factor = box.width () / (float) norm_box.width ();
01154   height_scale_factor = box.height () / (float) ASC_HEIGHT;
01155 
01156   if ((ASC_HEIGHT * width_scale_factor) <= box.height ())
01157     selected_scale_factor = width_scale_factor;
01158   else
01159     selected_scale_factor = height_scale_factor;
01160 
01161   norm_word->scale (selected_scale_factor);
01162   norm_word->move (ICOORD ((box.left () + box.width () / 2), box.bottom ()));
01163   return selected_scale_factor;
01164 }
01165 
01166 
01173 void re_segment_word(                         //break/join words
01174                      BLOCK_LIST *block_list,  //blocks to check
01175                      BOX &selection_box) {
01176   BLOCK_IT block_it(block_list);
01177   BLOCK *block;
01178   BLOCK *block_to_process = NULL;
01179   ROW_IT row_it;
01180   ROW *row;
01181   ROW *row_to_process = NULL;
01182   WERD_IT word_it;
01183   WERD *word;
01184   WERD *new_word = NULL;
01185   BOOL8 polyg = false;
01186   PBLOB_IT blob_it;
01187   PBLOB_LIST dummy;  // Just to initialize new_blob_it.
01188   PBLOB_IT new_blob_it = &dummy;
01189   PBLOB *blob;
01190 
01191   /* Find row to process - error if selections from more than one row */
01192 
01193   for (block_it.mark_cycle_pt ();
01194   !block_it.cycled_list (); block_it.forward ()) {
01195     block = block_it.data ();
01196     if (block->bounding_box ().overlap (selection_box)) {
01197       row_it.set_to_list (block->row_list ());
01198       for (row_it.mark_cycle_pt ();
01199       !row_it.cycled_list (); row_it.forward ()) {
01200         row = row_it.data ();
01201         if (row->bounding_box ().overlap (selection_box)) {
01202           if (row_to_process == NULL) {
01203             block_to_process = block;
01204             row_to_process = row;
01205           }
01206           else {
01207             command_window->
01208               msg ("Cant resegment words in more than one row");
01209             return;
01210           }
01211         }
01212       }
01213     }
01214   }
01215   /* Continue with row_to_process */
01216 
01217   word_it.set_to_list (row_to_process->word_list ());
01218   for (word_it.mark_cycle_pt (); !word_it.cycled_list (); word_it.forward ()) {
01219     word = word_it.data ();
01220     polyg = word->flag (W_POLYGON);
01221     if (word->bounding_box ().overlap (selection_box)) {
01222       blob_it.set_to_list (word->gblob_list ());
01223       for (blob_it.mark_cycle_pt ();
01224       !blob_it.cycled_list (); blob_it.forward ()) {
01225         blob = blob_it.data ();
01226         if (gblob_bounding_box (blob, polyg).overlap (selection_box)) {
01227           if (new_word == NULL) {
01228             new_word = word->shallow_copy ();
01229             new_blob_it.set_to_list (new_word->gblob_list ());
01230           }
01231           new_blob_it.add_to_end (blob_it.extract ());
01232           //move blob
01233         }
01234       }
01235       if (blob_it.empty ()) {    //no blobs in word
01236                                  //so delete word
01237         delete word_it.extract ();
01238       }
01239     }
01240   }
01241   if (new_word != NULL) {
01242     gblob_sort_list (new_word->gblob_list (), polyg);
01243     word_it.add_to_end (new_word);
01244     word_it.sort (word_comparator);
01245     row_to_process->bounding_box ().plot (image_win,
01246       INT_SOLID, FALSE, BLACK, BLACK);
01247     word_it.set_to_list (row_to_process->word_list ());
01248     for (word_it.mark_cycle_pt ();
01249       !word_it.cycled_list (); word_it.forward ())
01250     word_display (block_to_process, row_to_process, word_it.data ());
01251     *current_image_changed = TRUE;
01252   }
01253 }
01254 
01255 
01259 void block_space_stat(                         //show space stats
01260                       BLOCK_LIST *block_list,  //blocks to check
01261                       BOX &selection_box) {
01262   BLOCK_IT block_it(block_list);
01263   BLOCK *block;
01264   ROW_IT row_it;
01265   ROW *row;
01266   int block_idx = 0;
01267   STATS all_gap_stats (0, MAXSPACING);
01268   WERD_IT word_it;
01269   WERD *word;
01270   PBLOB_IT blob_it;
01271   PBLOB *blob;
01272   C_BLOB_IT cblob_it;
01273   C_BLOB *cblob;
01274   BOX box;
01275   INT16 prev_box_right;
01276   INT16 gap_width;
01277   INT16 min_inter_word_gap;
01278   INT16 max_inter_char_gap;
01279 
01280   /* Find blocks to process */
01281 
01282   for (block_it.mark_cycle_pt ();
01283   !block_it.cycled_list (); block_it.forward ()) {
01284     block_idx++;
01285     block = block_it.data ();
01286     if (block->bounding_box ().overlap (selection_box)) {
01287       /* Process a block */
01288       tprintf ("\nBlock %d\n", block_idx);
01289       min_inter_word_gap = 3000;
01290       max_inter_char_gap = 0;
01291       all_gap_stats.clear ();
01292       row_it.set_to_list (block->row_list ());
01293       for (row_it.mark_cycle_pt ();
01294       !row_it.cycled_list (); row_it.forward ()) {
01295         row = row_it.data ();
01296         prev_box_right = -1;
01297         word_it.set_to_list (row->word_list ());
01298         for (word_it.mark_cycle_pt ();
01299         !word_it.cycled_list (); word_it.forward ()) {
01300           word = word_it.data ();
01301           if (word->flag (W_POLYGON)) {
01302             blob_it.set_to_list (word->blob_list ());
01303             for (blob_it.mark_cycle_pt ();
01304             !blob_it.cycled_list (); blob_it.forward ()) {
01305               blob = blob_it.data ();
01306               box = blob->bounding_box ();
01307               if (prev_box_right > -1) {
01308                 gap_width = box.left () - prev_box_right;
01309                 all_gap_stats.add (gap_width, 1);
01310                 if (blob_it.at_first ()) {
01311                   if (gap_width < min_inter_word_gap)
01312                     min_inter_word_gap = gap_width;
01313                 }
01314                 else {
01315                   if (gap_width > max_inter_char_gap)
01316                     max_inter_char_gap = gap_width;
01317                 }
01318               }
01319               prev_box_right = box.right ();
01320             }
01321           }
01322           else {
01323             cblob_it.set_to_list (word->cblob_list ());
01324             for (cblob_it.mark_cycle_pt ();
01325             !cblob_it.cycled_list (); cblob_it.forward ()) {
01326               cblob = cblob_it.data ();
01327               box = cblob->bounding_box ();
01328               if (prev_box_right > -1) {
01329                 gap_width = box.left () - prev_box_right;
01330                 all_gap_stats.add (gap_width, 1);
01331                 if (cblob_it.at_first ()) {
01332                   if (gap_width < min_inter_word_gap)
01333                     min_inter_word_gap = gap_width;
01334                 }
01335                 else {
01336                   if (gap_width > max_inter_char_gap)
01337                     max_inter_char_gap = gap_width;
01338                 }
01339               }
01340               prev_box_right = box.right ();
01341             }
01342           }
01343         }
01344       }
01345       tprintf ("Max inter char gap = %d.\nMin inter word gap = %d.\n",
01346         max_inter_char_gap, min_inter_word_gap);
01347       all_gap_stats.short_print (NULL, TRUE);
01348       all_gap_stats.smooth (2);
01349       tprintf ("SMOOTHED DATA...\n");
01350       all_gap_stats.short_print (NULL, TRUE);
01351     }
01352   }
01353 }
01354 
01355 
01359 void row_space_stat(                         //show space stats
01360                     BLOCK_LIST *block_list,  //blocks to check
01361                     BOX &selection_box) {
01362   BLOCK_IT block_it(block_list);
01363   BLOCK *block;
01364   ROW_IT row_it;
01365   ROW *row;
01366   int block_idx = 0;
01367   int row_idx;
01368   STATS all_gap_stats (0, MAXSPACING);
01369   WERD_IT word_it;
01370   WERD *word;
01371   PBLOB_IT blob_it;
01372   PBLOB *blob;
01373   C_BLOB_IT cblob_it;
01374   C_BLOB *cblob;
01375   BOX box;
01376   INT16 prev_box_right;
01377   INT16 gap_width;
01378   INT16 min_inter_word_gap;
01379   INT16 max_inter_char_gap;
01380 
01381   /* Find rows to process */
01382 
01383   for (block_it.mark_cycle_pt ();
01384   !block_it.cycled_list (); block_it.forward ()) {
01385     block_idx++;
01386     block = block_it.data ();
01387     if (block->bounding_box ().overlap (selection_box)) {
01388       row_it.set_to_list (block->row_list ());
01389       row_idx = 0;
01390       for (row_it.mark_cycle_pt ();
01391       !row_it.cycled_list (); row_it.forward ()) {
01392         row_idx++;
01393         row = row_it.data ();
01394         if (row->bounding_box ().overlap (selection_box)) {
01395           /* Process a row */
01396 
01397           tprintf ("\nBlock %d Row %d\n", block_idx, row_idx);
01398           min_inter_word_gap = 3000;
01399           max_inter_char_gap = 0;
01400           prev_box_right = -1;
01401           all_gap_stats.clear ();
01402           word_it.set_to_list (row->word_list ());
01403           for (word_it.mark_cycle_pt ();
01404           !word_it.cycled_list (); word_it.forward ()) {
01405             word = word_it.data ();
01406             if (word->flag (W_POLYGON)) {
01407               blob_it.set_to_list (word->blob_list ());
01408               for (blob_it.mark_cycle_pt ();
01409               !blob_it.cycled_list (); blob_it.forward ()) {
01410                 blob = blob_it.data ();
01411                 box = blob->bounding_box ();
01412                 if (prev_box_right > -1) {
01413                   gap_width = box.left () - prev_box_right;
01414                   all_gap_stats.add (gap_width, 1);
01415                   if (blob_it.at_first ()) {
01416                     if (gap_width < min_inter_word_gap)
01417                       min_inter_word_gap = gap_width;
01418                   }
01419                   else {
01420                     if (gap_width > max_inter_char_gap)
01421                       max_inter_char_gap = gap_width;
01422                   }
01423                 }
01424                 prev_box_right = box.right ();
01425               }
01426             }
01427             else {
01428               cblob_it.set_to_list (word->cblob_list ());
01429               for (cblob_it.mark_cycle_pt ();
01430               !cblob_it.cycled_list (); cblob_it.forward ()) {
01431                 cblob = cblob_it.data ();
01432                 box = cblob->bounding_box ();
01433                 if (prev_box_right > -1) {
01434                   gap_width = box.left () - prev_box_right;
01435                   all_gap_stats.add (gap_width, 1);
01436                   if (cblob_it.at_first ()) {
01437                     if (gap_width < min_inter_word_gap)
01438                       min_inter_word_gap = gap_width;
01439                   }
01440                   else {
01441                     if (gap_width > max_inter_char_gap)
01442                       max_inter_char_gap = gap_width;
01443                   }
01444                 }
01445                 prev_box_right = box.right ();
01446               }
01447             }
01448           }
01449           tprintf
01450             ("Max inter char gap = %d.\nMin inter word gap = %d.\n",
01451             max_inter_char_gap, min_inter_word_gap);
01452           all_gap_stats.short_print (NULL, TRUE);
01453           all_gap_stats.smooth (2);
01454           tprintf ("SMOOTHED DATA...\n");
01455           all_gap_stats.short_print (NULL, TRUE);
01456         }
01457       }
01458     }
01459   }
01460 }
01461 
01462 
01467 void show_point(                         //display posn of bloba word
01468                 BLOCK_LIST *block_list,  //blocks to check
01469                 float x,
01470                 float y) {
01471   FCOORD pt(x, y);
01472   BOX box;
01473   BLOCK_IT block_it(block_list);
01474   BLOCK *block;
01475   ROW_IT row_it;
01476   ROW *row;
01477   WERD_IT word_it;
01478   WERD *word;
01479   PBLOB_IT blob_it;
01480   PBLOB *blob;
01481   C_BLOB_IT cblob_it;
01482   C_BLOB *cblob;
01483 
01484   char msg[160];
01485   char *msg_ptr = msg;
01486 
01487   msg_ptr += sprintf (msg_ptr, "Pt:(%0.3f, %0.3f) ", x, y);
01488 
01489   for (block_it.mark_cycle_pt ();
01490   !block_it.cycled_list (); block_it.forward ()) {
01491     block = block_it.data ();
01492     if (block->bounding_box ().contains (pt)) {
01493       row_it.set_to_list (block->row_list ());
01494       for (row_it.mark_cycle_pt ();
01495       !row_it.cycled_list (); row_it.forward ()) {
01496         row = row_it.data ();
01497         if (row->bounding_box ().contains (pt)) {
01498           msg_ptr += sprintf (msg_ptr, "BL(x)=%0.3f ",
01499             row->base_line (x));
01500 
01501           word_it.set_to_list (row->word_list ());
01502           for (word_it.mark_cycle_pt ();
01503           !word_it.cycled_list (); word_it.forward ()) {
01504             word = word_it.data ();
01505             box = word->bounding_box ();
01506             if (box.contains (pt)) {
01507               msg_ptr += sprintf (msg_ptr,
01508                 "Wd(%d, %d)/(%d, %d) ",
01509                 box.left (), box.bottom (),
01510                 box.right (), box.top ());
01511 
01512               if (word->flag (W_POLYGON)) {
01513                 blob_it.set_to_list (word->blob_list ());
01514                 for (blob_it.mark_cycle_pt ();
01515                   !blob_it.cycled_list ();
01516                 blob_it.forward ()) {
01517                   blob = blob_it.data ();
01518                   box = blob->bounding_box ();
01519                   if (box.contains (pt)) {
01520                     msg_ptr += sprintf (msg_ptr,
01521                       "Blb(%d, %d)/(%d, %d) ",
01522                       box.left (),
01523                       box.bottom (),
01524                       box.right (),
01525                       box.top ());
01526                   }
01527                 }
01528               }
01529               else {
01530                 cblob_it.set_to_list (word->cblob_list ());
01531                 for (cblob_it.mark_cycle_pt ();
01532                   !cblob_it.cycled_list ();
01533                 cblob_it.forward ()) {
01534                   cblob = cblob_it.data ();
01535                   box = cblob->bounding_box ();
01536                   if (box.contains (pt)) {
01537                     msg_ptr += sprintf (msg_ptr,
01538                       "CBlb(%d, %d)/(%d, %d) ",
01539                       box.left (),
01540                       box.bottom (),
01541                       box.right (),
01542                       box.top ());
01543                   }
01544                 }
01545               }
01546             }
01547           }
01548         }
01549       }
01550     }
01551   }
01552   command_window->msg (msg);
01553 }
01554 
01555 
01560 BOOL8 word_blank_and_set_display(               //display a word
01561                                  BLOCK *block,  //block holding word
01562                                  ROW *row,      //row holding word
01563                                  WERD *word     //word to be processed
01564                                 ) {
01565   word->bounding_box ().plot (image_win, INT_SOLID, FALSE, BLACK, BLACK);
01566   return word_set_display (block, row, word);
01567 }
01568 
01569 
01573 BOOL8 word_bln_display(            //bln & display
01574                        BLOCK *,    //block holding word
01575                        ROW *row,   //row holding word
01576                        WERD *word  //word to be processed
01577                       ) {
01578   WERD *bln_word;
01579 
01580   bln_word = word->poly_copy (row->x_height ());
01581   bln_word->baseline_normalise (row);
01582   clear_view_surface (bln_word_window_handle ());
01583   display_bln_lines (bln_word_window_handle (), CYAN, 1.0, 0.0f, -1000.0f,
01584     1000.0f);
01585   bln_word->plot (bln_word_window_handle (), RED);
01586   delete bln_word;
01587   return TRUE;
01588 }
01589 
01590 
01594 BOOL8 word_change_text(               //change correct text
01595                        BLOCK *block,  //block holding word
01596                        ROW *row,      //row holding word
01597                        WERD *word     //word to be processed
01598                       ) {
01599   char response_str[MAX_CHARS + 1];
01600 
01601   strcpy (response_str, word->text ());
01602   if (!command_window->
01603     prompt ("Enter/edit the correct text and press <<RETURN>>",
01604     response_str))
01605     return FALSE;
01606   else
01607     word->set_text (response_str);
01608 
01609   if (word_display_mode.bit (DF_TEXT) || word->display_flag (DF_TEXT)) {
01610     word_blank_and_set_display(block, row, word);
01611     overlap_picture_ops(TRUE);
01612   }
01613 
01614   *current_image_changed = TRUE;
01615   return TRUE;
01616 }
01617 
01618 
01622 BOOL8 word_copy(               //copy a word
01623                 BLOCK *block,  //block holding word
01624                 ROW *row,      //row holding word
01625                 WERD *word     //word to be processed
01626                ) {
01627   WERD *copy_word = new WERD;
01628 
01629   *copy_word = *word;
01630   add_word(copy_word, row, block, other_block_list);
01631   *other_image_changed = TRUE;
01632   return TRUE;
01633 }
01634 
01635 
01639 BOOL8 word_delete(                     //delete a word
01640                   BLOCK *block,        //block holding word
01641                   ROW *row,            //row holding word
01642                   WERD *word,          //word to be processed
01643                   BLOCK_IT &block_it,  //block list iterator
01644                   ROW_IT &row_it,      //row list iterator
01645                   WERD_IT &word_it     //word list iterator
01646                  ) {
01647   word_it.extract ();
01648   word->bounding_box ().plot (image_win, INT_SOLID, FALSE, BLACK, BLACK);
01649   delete(word);
01650 
01651   if (word_it.empty ()) {        //no words left in row
01652                                  //so delete row
01653     row_it.extract ();
01654     row->bounding_box ().plot (image_win, INT_SOLID, FALSE, BLACK, BLACK);
01655     delete(row);
01656 
01657     if (row_it.empty ()) {       //no rows left in blk
01658                                  //so delete block
01659       block_it.extract ();
01660       block->bounding_box ().plot (image_win, INT_SOLID, FALSE,
01661         BLACK, BLACK);
01662       delete(block);
01663     }
01664   }
01665   *current_image_changed = TRUE;
01666   return TRUE;
01667 }
01668 
01669 
01673 BOOL8 word_display(            // display a word
01674                    BLOCK *,    //block holding word
01675                    ROW *row,   //row holding word
01676                    WERD *word  //word to be processed
01677                   ) {
01678   BOX word_bb;                   //word bounding box
01679   int word_height;               //ht of word BB
01680   BOOL8 displayed_something = FALSE;
01681   BOOL8 displayed_rainbow = FALSE;
01682   float shift;                   //from bot left
01683   PBLOB_IT it;                   //blob iterator
01684   C_BLOB_IT c_it;                //cblob iterator
01685   WERD *word_ptr;                //poly copy
01686   WERD temp_word;
01687   float scale_factor;            //for BN_POLYGON
01688 
01689   /*
01690     Note the double coercions of (COLOUR)((INT32)editor_image_word_bb_color)
01691     etc. are to keep the compiler happy.
01692   */
01693 
01694                                  //display bounding box
01695   if (word->display_flag (DF_BOX)) {
01696     word->bounding_box ().plot (image_win, INT_HOLLOW, TRUE,
01697       (COLOUR) ((INT32)
01698       editor_image_word_bb_color),
01699       (COLOUR) ((INT32)
01700       editor_image_word_bb_color));
01701 
01702     perimeter_color_index (image_win,
01703       (COLOUR) ((INT32) editor_image_blob_bb_color));
01704     if (word->flag (W_POLYGON)) {
01705       it.set_to_list (word->blob_list ());
01706       for (it.mark_cycle_pt (); !it.cycled_list (); it.forward ())
01707         it.data ()->bounding_box ().plot (image_win);
01708     }
01709     else {
01710       c_it.set_to_list (word->cblob_list ());
01711       for (c_it.mark_cycle_pt (); !c_it.cycled_list (); c_it.forward ())
01712         c_it.data ()->bounding_box ().plot (image_win);
01713     }
01714     displayed_something = TRUE;
01715   }
01716 
01717                                  //display edge steps
01718   if (word->display_flag (DF_EDGE_STEP) &&
01719   !word->flag (W_POLYGON)) {     //edgesteps available
01720     word->plot (image_win);      //rainbow colors
01721     displayed_something = TRUE;
01722     displayed_rainbow = TRUE;
01723   }
01724 
01725                                  //display poly approx
01726   if (word->display_flag (DF_POLYGONAL)) {
01727                                  //need to convert
01728     if (!word->flag (W_POLYGON)) {
01729       word_ptr = word->poly_copy (row->x_height ());
01730 
01731       /* CALL POLYGONAL APPROXIMATOR WHEN AVAILABLE - on a temp_word */
01732 
01733       if (displayed_rainbow)
01734                                  //ensure its visible
01735         word_ptr->plot (image_win, WHITE);
01736       else
01737                                  //rainbow colors
01738           word_ptr->plot (image_win);
01739       delete word_ptr;
01740     }
01741     else {
01742       if (displayed_rainbow)
01743                                  //ensure its visible
01744         word->plot (image_win, WHITE);
01745       else
01746         word->plot (image_win);  //rainbow colors
01747     }
01748 
01749     displayed_rainbow = TRUE;
01750     displayed_something = TRUE;
01751   }
01752 
01753                                  //disp BN poly approx
01754   if (word->display_flag (DF_BN_POLYGONAL)) {
01755                                  //need to convert
01756     if (!word->flag (W_POLYGON)) {
01757       word_ptr = word->poly_copy (row->x_height ());
01758       temp_word = *word_ptr;
01759       delete word_ptr;
01760 
01761       /* CALL POLYGONAL APPROXIMATOR WHEN AVAILABLE - on a temp_word */
01762 
01763     }
01764     else
01765       temp_word = *word;         //copy word
01766     word_bb = word->bounding_box ();
01767     if (!temp_word.flag (W_NORMALIZED))
01768       temp_word.baseline_normalise (row);
01769 
01770     scale_factor = re_scale_and_move_bln_word (&temp_word, word_bb);
01771     display_bln_lines (image_win, CYAN, scale_factor, word_bb.bottom (),
01772       word_bb.left (), word_bb.right ());
01773 
01774     if (displayed_rainbow)
01775                                  //ensure its visible
01776       temp_word.plot (image_win, WHITE);
01777     else
01778       temp_word.plot (image_win);//rainbow colors
01779 
01780     displayed_rainbow = TRUE;
01781     displayed_something = TRUE;
01782   }
01783 
01784                                  //display correct       text
01785   if (word->display_flag (DF_TEXT)) {
01786     word_bb = word->bounding_box ();
01787     text_color_index (image_win,
01788       (COLOUR) ((INT32) editor_image_text_color));
01789     text_font_index (image_win, 1);
01790     word_height = word_bb.height ();
01791     character_height (image_win, 0.75 * word_height);
01792 
01793     if (word_height < word_bb.width ())
01794       shift = 0.25 * word_height;
01795     else
01796       shift = 0.0f;
01797 
01798     text2d (image_win,
01799       word_bb.left () + shift,
01800       word_bb.bottom () + 0.25 * word_height,
01801       word->text (), 0, FALSE);
01802     if (strlen (word->text ()) > 0)
01803       displayed_something = TRUE;
01804   }
01805 
01806   if (!displayed_something)      //display BBox anyway
01807     word->bounding_box ().plot (image_win, INT_HOLLOW, TRUE,
01808       (COLOUR) ((INT32) editor_image_word_bb_color),
01809       (COLOUR) ((INT32)
01810       editor_image_word_bb_color));
01811   return TRUE;
01812 }
01813 
01814 
01818 BOOL8 word_dumper(               //dump word
01819                   BLOCK *block,  //block holding word
01820                   ROW *row,      //row holding word
01821                   WERD *word     //word to be processed
01822                  ) {
01823 
01824   tprintf ("\nBlock data...\n");
01825   block->print (NULL, FALSE);
01826   tprintf ("\nRow data...\n");
01827   row->print (NULL);
01828   tprintf ("\nWord data...\n");
01829   word->print (NULL);
01830   return TRUE;
01831 }
01832 
01833 
01837 BOOL8 word_set_display(               //display a word
01838                        BLOCK *block,  //block holding word
01839                        ROW *row,      //row holding word
01840                        WERD *word     //word to be processed
01841                       ) {
01842   BOX word_bb;                   //word bounding box
01843 
01844   word->set_display_flag (DF_BOX, word_display_mode.bit (DF_BOX));
01845   word->set_display_flag (DF_TEXT, word_display_mode.bit (DF_TEXT));
01846   word->set_display_flag (DF_POLYGONAL, word_display_mode.bit (DF_POLYGONAL));
01847   word->set_display_flag (DF_EDGE_STEP, word_display_mode.bit (DF_EDGE_STEP));
01848   word->set_display_flag (DF_BN_POLYGONAL,
01849     word_display_mode.bit (DF_BN_POLYGONAL));
01850   *current_image_changed = TRUE;
01851   return word_display (block, row, word);
01852 }
01853 
01854 
01858 BOOL8 word_toggle_seg(            //toggle seg flag
01859                       BLOCK *,    //block holding word
01860                       ROW *,      //row holding word
01861                       WERD *word  //word to be processed
01862                      ) {
01863   word->set_flag (W_SEGMENTED, !word->flag (W_SEGMENTED));
01864   *current_image_changed = TRUE;
01865   return TRUE;
01866 }
01867 
01871 void do_check_mem(  //do it
01872                   INT32 level) {
01873   check_mem ("Doing it", level);
01874 }

Generated on Wed Feb 28 19:49:11 2007 for Tesseract by  doxygen 1.5.1