1 /*************************************************************************** 2 3 Very simple OCR engine 4 5 We do it in 3 passes 6 7 Ask the vobsub decoder for a bitmap 8 Try to split the bitmap in lines 9 For each lines try to split in glyph (i.e. horizontal line) 10 Detour the glyph 11 If the detoured glyph has a width much less inferiror to its width 12 it probably means we have a italic or kerning. 13 In that case use the detouring to isolate the glyphs 14 15 16 A bit of warning. 17 The UI code is ugly. 18 Bottom is the last actual line so to get height you have to to last-first +1 ! 19 20 begin : Jan 2005 21 copyright : (C) 2002 by mean 22 email : fixounet@free.fr 23 ***************************************************************************/ 24 25 /*************************************************************************** 26 * * 27 * This program is free software; you can redistribute it and/or modify * 28 * it under the terms of the GNU General Public License as published by * 29 * the Free Software Foundation; either version 2 of the License, or * 30 * (at your option) any later version. * 31 * * 32 ***************************************************************************/ 33 #include "ADM_toolkitGtk.h" 34 35 #include "DIA_coreToolkit.h" 36 #include "ADM_editor/ADM_edit.hxx" 37 #include "DIA_fileSel.h" 38 39 #if 0 40 //#include "ADM_videoFilter/ADM_vobsubinfo.h" 41 //#include "ADM_videoFilter/ADM_vidVobSub.h" 42 #include "ADM_ocr/ADM_leftturn.h" 43 #include "DIA_enter.h" 44 45 #include "ADM_ocr/ADM_ocr.h" 46 #include "ADM_ocr/ADM_ocrInternal.h" 47 /******************************/ 48 49 #define TESTSUB "/home/fx/usbstick/subs/vts_01_0.idx" 50 #define CONNECT(x,y,z) gtk_signal_connect(GTK_OBJECT(WID(x)), #y,GTK_SIGNAL_FUNC(z), NULL); 51 52 53 /* Minimal size of the current glyph display window */ 54 #define MAX_W 65 55 #define MAX_H 65 56 57 58 extern uint8_t DIA_vobsub(vobSubParam *param); 59 //******************************************** 60 extern GtkWidget *DIA_ocr(void); 61 62 63 //******************************************** 64 65 66 67 68 typedef enum 69 { 70 actionLoadVob=10, 71 actionSaveSub, 72 actionGo, 73 actionLoadGlyph, 74 actionSaveGlyph, 75 actionSkip, 76 actionSkipAll, 77 actionAccept, 78 actionIgnore, 79 actionCalibrate 80 }ocrAction; 81 82 83 /************************ UI Dependant part ********************/ 84 /** 85 Search throught the existing glyphs , if not present create it 86 and append the text to decodedString 87 */ 88 89 static GtkWidget *dialog=NULL; 90 static GtkWidget *mainDisplay=NULL; 91 static GtkWidget *smallDisplay=NULL; 92 93 static uint32_t clipW=0,clipH=0; 94 95 static gboolean gui_draw( void ); 96 static gboolean gui_draw_small( void ); 97 static void displaySmall( admGlyph *glyph ); 98 static int cb_accept(GtkObject * object, gpointer user_data); 99 100 101 ReplyType glyphToText(admGlyph *glyph,admGlyph *head,char *decodedString) 102 { 103 admGlyph *cand; 104 //printf("2t: %d x %d\n",glyph->width,glyph->height); 105 if(glyph->width<2 && glyph->height<2) 106 { 107 delete glyph; 108 return ReplyOk; 109 } 110 cand=searchGlyph(head,glyph); 111 if(!cand) // New glyph 112 { 113 char *string; 114 // Draw it 115 displaySmall(glyph); 116 gtk_label_set_text(GTK_LABEL(WID(labelText)),decodedString); 117 gtk_editable_delete_text(GTK_EDITABLE(WID(entry)), 0,-1); 118 119 //gtk_widget_set_sensitive(WID(buttonAccept),1); 120 //gtk_widget_set_sensitive(WID(buttonSkip),1); 121 //gtk_widget_set_sensitive(WID(entryEntry),1); 122 123 gtk_widget_grab_focus (WID(entry)); 124 gtk_widget_grab_default (WID(buttonOk)); 125 126 //printf("i\n"); 127 switch(gtk_dialog_run(GTK_DIALOG(dialog))) 128 { 129 case actionIgnore: 130 glyph->code=NULL; 131 insertInGlyphTree(head,glyph); 132 //*nbGl++; 133 break; 134 case actionCalibrate: return ReplyCalibrate; 135 case actionAccept: 136 string =gtk_editable_get_chars(GTK_EDITABLE (WID(entry)), 0, -1); 137 if(string&& strlen(string)) 138 { 139 glyph->code=ADM_strdup(string); 140 insertInGlyphTree(head,glyph); 141 //printf("New glyph:%s\n",glyph->code); 142 strcat(decodedString,glyph->code); 143 //*nbGl++; 144 145 } 146 else delete glyph; 147 break; 148 case actionSkip: //SKIP 149 return ReplySkip; 150 break; 151 case actionSkipAll: 152 return ReplySkipAll; 153 break; 154 case GTK_RESPONSE_CLOSE: 155 if(GUI_Question(QT_TR_NOOP("Sure ?"))) return ReplyClose; 156 break; // Abort 157 158 } 159 gtk_editable_delete_text(GTK_EDITABLE(WID(entry)), 0,-1); 160 //gtk_widget_set_sensitive(WID(buttonAccept),0); 161 //gtk_widget_set_sensitive(WID(buttonSkip),0); 162 //gtk_widget_set_sensitive(WID(entryEntry),0); 163 } 164 else 165 { 166 //printf("Glyph known :%s \n",cand->code); 167 if(cand->code) 168 strcat(decodedString,cand->code); 169 delete glyph; 170 } 171 return ReplyOk; 172 173 } 174 static int sx=0,sy=0,sw=0,sh=0; 175 static int redraw_x=0,redraw_y=0; 176 static uint8_t *drawing=NULL; 177 static uint8_t *sdata=NULL; 178 uint8_t ADM_ocrSetRedrawSize(void *ui,uint32_t w,uint32_t h) 179 { 180 redraw_x=w; 181 redraw_y=h; 182 return 1; 183 } 184 185 //***************************************************************************************** 186 gboolean gui_draw( void ) 187 { 188 static int lastx=0,lasty=0; 189 if(!drawing) return true; 190 if(lastx!=redraw_x || lasty!=redraw_y) 191 gtk_widget_set_usize(mainDisplay, redraw_x, redraw_y); 192 lastx=redraw_x; 193 lasty=redraw_y; 194 195 gdk_draw_gray_image(mainDisplay->window, mainDisplay->style->fg_gc[GTK_STATE_NORMAL], 196 0, // X 197 0, // y 198 redraw_x, //width 199 redraw_y, //h*2, // heigth 200 GDK_RGB_DITHER_NONE, 201 drawing, // buffer 202 redraw_x ); 203 return true; 204 } 205 //***************************************************************************************** 206 207 void displaySmall( admGlyph *glyph) 208 { 209 if(sw!=glyph->width || sh!=glyph->height) 210 { 211 212 if(sdata) delete [] sdata; 213 sdata=NULL; 214 sw=glyph->width; 215 sh=glyph->height; 216 sdata=new uint8_t[(sw*2+2)*(sh*2+2)]; 217 clipW= sw*2+2; 218 clipH= sh*2+2; 219 #ifndef MAX 220 #define MAX(a,b) a>b?a:b 221 #endif 222 clipW=MAX(MAX_W,clipW); 223 clipH=MAX(MAX_H,clipH); 224 gtk_widget_set_usize(smallDisplay, clipW,clipH); 225 } 226 uint32_t stride=sw*2+2; 227 uint8_t *in=glyph->data; 228 uint8_t *out=sdata; 229 230 memset(out,0,stride); 231 out+=stride; 232 for(uint32_t y=0;y<sh;y++) 233 { 234 *(out++)=0; 235 for(uint32_t x=0;x<sw;x++) 236 { 237 out[1]=out[0]=out[stride]=out[stride+1]=*in; 238 out+=2; 239 in++; 240 241 } 242 *(out++)=0; 243 out+=stride; 244 } 245 memset(out,0,stride); 246 //memcpy(sdata,glyph->data,sw*sh); 247 gui_draw_small(); 248 } 249 250 gboolean gui_draw_small(void) 251 { 252 if(clipW && clipH) 253 { 254 gdk_draw_rectangle(smallDisplay->window, 255 smallDisplay->style->fg_gc[GTK_STATE_NORMAL], 256 1, // Filled 257 0, // X 258 0, // y 259 clipW, 260 clipH); 261 262 263 } 264 if(sw && sh && sdata) 265 { 266 gdk_draw_gray_image(smallDisplay->window, smallDisplay->style->fg_gc[GTK_STATE_NORMAL], 267 1, // X 268 1, // y 269 sw*2+1, //width 270 sh*2+1, //h*2, // heigth 271 GDK_RGB_DITHER_NONE, 272 sdata, // buffer 273 sw*2+2 ); 274 } 275 return true; 276 } 277 278 279 /** 280 \fn cb_accept 281 \brief Bridge between dialog/Accept and gtk signals 282 */ 283 int cb_accept(GtkObject * object, gpointer user_data) 284 { 285 //printf("Hopla\n"); 286 gtk_signal_emit_by_name(GTK_OBJECT(WID(buttonOk)),"clicked",(gpointer)1); 287 return 0; 288 } 289 uint8_t ADM_ocrUpdateNbLines(void *ui,uint32_t cur,uint32_t total) 290 { 291 char text[50]; 292 snprintf(text,50,"%03d/%03d",cur,total); 293 gtk_label_set_text(GTK_LABEL(WID(labelNbLines)),text); 294 return 1; 295 } 296 uint8_t ADM_ocrUpdateNbGlyphs(void *ui,uint32_t nbGlyphs) 297 { 298 char text[50]; 299 snprintf(text,50,"%03d",nbGlyphs); 300 gtk_label_set_text(GTK_LABEL(WID(labelNbGlyphs)),text); 301 return 1; 302 } 303 uint8_t ADM_ocrUpdateTextAndTime(void *ui,char *decodedString,char *timeCode) 304 { 305 gtk_label_set_text(GTK_LABEL(WID(labelText)),decodedString); 306 gtk_label_set_text(GTK_LABEL(WID(labelTime)),timeCode); 307 return 1; 308 } 309 uint8_t ADM_ocrDrawFull(void *d,uint8_t *data) 310 { 311 drawing=data;; 312 UI_purge(); 313 gui_draw(); 314 UI_purge(); 315 return 1; 316 } 317 318 uint8_t ADM_ocrUiEnd(void *d) 319 { 320 GtkWidget *dialog=(GtkWidget *)d; 321 ADM_assert(dialog); 322 // Final round 323 gtk_widget_set_sensitive(WID(frameBitmap),0); 324 // gtk_widget_set_sensitive(WID(Current_Glyph),0); 325 326 327 gtk_unregister_dialog(dialog); 328 gtk_widget_destroy(dialog); 329 330 } 331 void *ADM_ocrUiSetup(void) 332 { 333 // Create UI && prepare callback 334 dialog=NULL; 335 mainDisplay=NULL; 336 smallDisplay=NULL; 337 drawing=NULL; 338 sdata=NULL; 339 clipW=0; 340 clipH=0; 341 dialog=DIA_ocr(); 342 gtk_register_dialog(dialog); 343 #define ASSOCIATE(x,y) gtk_dialog_add_action_widget (GTK_DIALOG (dialog), WID(x),y) 344 345 ASSOCIATE(buttonOk, actionAccept); 346 ASSOCIATE(buttonSkip, actionSkip); 347 ASSOCIATE(buttonSkipAll, actionSkipAll); 348 ASSOCIATE(buttonIgnore, actionIgnore); 349 ASSOCIATE(buttonCalibrate, actionCalibrate); 350 351 352 gtk_widget_show(dialog); 353 // 354 355 // disable 356 357 mainDisplay=WID(drawingareaBitmap); 358 smallDisplay=WID(drawingareaSmall); 359 360 361 362 CONNECT(drawingareaBitmap,expose_event,gui_draw); 363 CONNECT(drawingareaSmall,expose_event,gui_draw_small); 364 365 CONNECT(entry,activate,cb_accept); 366 return (void *)dialog; 367 368 } 369 #endif 370 //; 371