/* +++++++++++++++++++++++++++++++++++++++++++++++++++++++ Main +++++++++++++++++++++++++++++++++++++++++++++++++++++++ */ uint8_t ADM_ocr_engine( void) { // uint32_t nbSub=0; FILE *out=NULL; head.next=NULL; ADMVideoVobSub *vobsub=NULL; uint32_t startTime,endTime; uint32_t w,h,oldw=0,oldh=0; uint32_t oldbitmapw=0; uint32_t oldbitmaph=0; uint32_t first,last; uint32_t seqNum; char text[1024]; lang_index=0; nbGlyphs=0; ReplyType reply; // Create UI && prepare callback dialog=DIA_ocr(); gtk_register_dialog(dialog); #define ASSOCIATE(x,y) gtk_dialog_add_action_widget (GTK_DIALOG (dialog), WID(x),y) ASSOCIATE(buttonStart,actionGo); ASSOCIATE(buttonOk, actionAccept); ASSOCIATE(buttonSkip, actionSkip); ASSOCIATE(buttonSkipAll, actionSkipAll); ASSOCIATE(buttonIgnore, actionIgnore); ASSOCIATE(buttonCalibrate, actionCalibrate); ASSOCIATE(buttonGlyphLoad, actionLoadGlyph); ASSOCIATE(buttonGlyphSave, actionSaveGlyph); ASSOCIATE(buttonVobsub, actionLoadVob); ASSOCIATE(buttonSrt, actionSaveSub); gtk_widget_show(dialog); // disable mainDisplay=WID(drawingareaBitmap); smallDisplay=WID(drawingareaSmall); CONNECT(drawingareaBitmap,expose_event,gui_draw); CONNECT(drawingareaSmall,expose_event,gui_draw_small); CONNECT(entry,activate,cb_accept); _again: reply=setup(); if(reply==ReplyClose) goto endIt; printf("Go go go\n"); // Everything ready go go go redraw_x=redraw_y=0; GTK_PURGE; // Time to go // Inactivate frame1=glyph frame2=in/out buttonStart gtk_widget_set_sensitive(WID(buttonStart),0); gtk_widget_set_sensitive(WID(frameGlyph),0); gtk_widget_set_sensitive(WID(frameLoad),0); gtk_widget_set_sensitive(WID(frameBitmap),1); gtk_widget_set_sensitive(WID(buttonStart),0); char *fileout; fileout=(char *)gtk_label_get_text(GTK_LABEL(WID(labelSrt))); if(!fileout) { GUI_Error_HIG(_("Incorrect output file"), NULL); goto _again; } out=fopen(fileout,"wb"); if(!out) { GUI_Error_HIG(_("Output file error"), _("Could not open \"%s\" for writing."), fileout); goto _again; } vobsub=new ADMVideoVobSub(subparam.subname,subparam.index); nbSub=vobsub->getNbImage(); if(!nbSub) { GUI_Error_HIG(_("Problem loading sub"), NULL); delete vobsub; vobsub=NULL; goto _again; } seqNum=1; // Sub number in srt file oldw=oldh=0; //****************** // Load all bitmaps //****************** for(uint32_t i=0;i<nbSub;i++) { first=last=0; bitmap=vobsub->getBitmap(i,&startTime, &endTime,&first,&last); ADM_assert(last>=first); // something ? if(!bitmap) continue; if(first==last) continue; // If the bitmap size changed or does not exist yet... if(!workArea || oldbitmapw!=bitmap->_width || oldbitmaph!=bitmap->_height) { if(workArea) { delete [] workArea; workArea=NULL; } // Workarea is actually bigger than what we use workArea=new uint8_t[bitmap->_width*(bitmap->_height)]; memset(workArea,0,bitmap->_width*(bitmap->_height)); } oldbitmaph=bitmap->_height; oldbitmapw=bitmap->_width; // w=bitmap->_width; h=last-first+1; redraw_x=w; redraw_y=h; //** // Build againPlease: mergeBitmap(bitmap->_bitmap+first*w, workArea, bitmap->_alphaMask+first*w, w, h); if(oldw!=w || oldh !=h) { GTK_PURGE; // Force redaw } // Merge GTK_PURGE; gui_draw(); GTK_PURGE; // OCR reply=ocrBitmap(workArea,w,h); if(reply==ReplyClose) goto endIt; if(reply==ReplyCalibrate) { // //printf("TADA!!!!\n"); int val; #if 0 val=minAlpha; if(DIA_GetIntegerValue(&val, 3, 7, "Minimum alpha value", "Enter new minimum alpha")) { minAlpha=val; } #endif val=minThreshold; if(DIA_GetIntegerValue(&val, 0x30, 0x80, "Minimum pixel value", "Enter new minimum pixel")) { minThreshold=val; } goto againPlease; } // gtk_label_set_text(GTK_LABEL(WID(labelText)),decodedString); fprintf(out,"%d\n",seqNum++); uint16_t hh,mm,ss,ms; ms2time(startTime, &hh, &mm, &ss, &ms); fprintf(out,"%02d:%02d:%02d,%03d --> ",hh,mm,ss,ms); ms2time(endTime, &hh, &mm, &ss, &ms); fprintf(out,"%02d:%02d:%02d,%03d\n",hh,mm,ss,ms); fprintf(out,"%s\n\n",decodedString); // oldw=w; oldh=h; // Update infos sprintf(text,"%03d/%03d",i+1,nbSub); gtk_label_set_text(GTK_LABEL(WID(labelNbLines)),text); sprintf(text,"%03d",nbGlyphs); gtk_label_set_text(GTK_LABEL(WID(labelNbGlyphs)),text); } endIt: // Final round gtk_widget_set_sensitive(WID(frameGlyph),1); gtk_widget_set_sensitive(WID(frameLoad),0); gtk_widget_set_sensitive(WID(buttonStart),0); gtk_widget_set_sensitive(WID(frameBitmap),0); // gtk_widget_set_sensitive(WID(Current_Glyph),0); if(nbGlyphs && actionSaveGlyph==gtk_dialog_run(GTK_DIALOG(dialog))) saveGlyph(); if(vobsub) delete vobsub; vobsub=NULL; if(out) fclose(out); out=NULL; gtk_unregister_dialog(dialog); gtk_widget_destroy(dialog); if(head.next) destroyGlyphTree(&head); head.next=NULL; return 1; }
/** \fn DIA_ocrGen \brief Dialog to select input & output files before calling the actual ocr engine */ uint8_t DIA_ocrGen(void) { vobSubParam subparam={NULL,0,0}; char *srtFileName=NULL; char *glyphFileName=NULL; admGlyph head(16,16); char *globalGlyph=NULL; uint32_t globalGlyphOn=0; ADM_OCR_SOURCE source; memset(&source,0,sizeof(source)); source.type=ADM_OCR_TYPE_VOBSUB; source.subparam=&subparam; prefs->get(FEATURE_GLOBAL_GLYPH_ACTIVE,&globalGlyphOn); if(globalGlyphOn) { prefs->get(FEATURE_GLOBAL_GLYPH_NAME,&globalGlyph); if(!*globalGlyph) { ADM_dezalloc(globalGlyph); globalGlyph=NULL; } } if(globalGlyph) { glyphFileName=globalGlyph; } _again: // Fist build a dialogFactory to get input and output files diaElemButton selectIdx(QT_TR_NOOP("Select idx file:"), cb_idx,&subparam,NULL); diaElemFile selectGlyph(1,&glyphFileName,QT_TR_NOOP("Use GlyphSet (optional):"), NULL, QT_TR_NOOP("Select GlyphSet file")); diaElemFile selectSrt(1,&srtFileName,QT_TR_NOOP("Output SRT file"), NULL, QT_TR_NOOP("Save SRT file")); diaElem *elems[]={&selectIdx,&selectSrt,&selectGlyph}; uint32_t n=3; if(globalGlyph) { n--; // Remove glyph from dialog } if(!diaFactoryRun(QT_TR_NOOP("Select input and ouput files"),n,elems)) { cleanupSub(&source); if(srtFileName )ADM_dezalloc(srtFileName); srtFileName=NULL; destroyGlyphTree(&head); return 0; } if(!ADM_fileExist(subparam.subname)) { GUI_Error_HIG(QT_TR_NOOP("File error"),QT_TR_NOOP("The idx/sub file does not exist.")); goto _again; } if(!srtFileName || !*srtFileName) { GUI_Error_HIG(QT_TR_NOOP("File error"),QT_TR_NOOP("Please Select a valid output SRT file.")); goto _again; } if(glyphFileName && *glyphFileName) { if(!ADM_fileExist(glyphFileName)) { GUI_Error_HIG(QT_TR_NOOP("File error"),QT_TR_NOOP("The idx/sub file does not exist.")); goto _again; } // Purge previous glyph set if any destroyGlyphTree(&head); uint32_t nb; printf("[OCR] Loading glyphset :<%s>\n",glyphFileName); if(!loadGlyph(glyphFileName,&head,&nb)) { GUI_Error_HIG(QT_TR_NOOP("File error"),QT_TR_NOOP("Cannot load the glyphset file.")); goto _again; } printf("[GLYPH] Found %u glyph\n"); } // We have our SRT and our idx/sub files : Go go go if(ADM_ocr_engine(source,srtFileName,&head)) { // Save glyph set if(globalGlyph) { uint32_t nb=1; saveGlyph(globalGlyph,&head,nb); } else { char *save=NULL; uint32_t nb=1; diaElemFile selectSave(1,&save,QT_TR_NOOP("GlyphSet filename"), NULL, QT_TR_NOOP("Save GlyphSet file")); diaElem *elems2[]={&selectSave}; if(diaFactoryRun(QT_TR_NOOP("Save Glyph"),1,elems2)) { saveGlyph(save,&head,nb); } if(save) ADM_dezalloc(save); } } cleanupSub(&source); if(srtFileName )ADM_dezalloc(srtFileName); srtFileName=NULL; destroyGlyphTree(&head); return 1; }
/** \fn DIA_glyphEdit \brief Dialog to edit glyph */ uint8_t DIA_glyphEdit(void) { char *glyphName; admGlyph head(1,1); uint32_t nbGlyph=0; uint8_t ret=0; // First select a file GUI_FileSelRead(QT_TR_NOOP("Select GlyphFile to edit"), &glyphName); if(!glyphName) return 0; // Try to load it if(!loadGlyph(glyphName,&head,&nbGlyph) || !nbGlyph) { destroyGlyphTree(&head); return 0; } // Convert the linear glyph to glyph array admGlyph *glyphArray[nbGlyph]; admGlyph *cur=head.next; uint32_t idx=0; while(cur) { glyphArray[idx++]=cur; cur=cur->next; } ADM_assert(idx<=nbGlyph); nbGlyph=idx; // Glyph loaded, here we go currentGlyph=head.next; dialog=create_dialog1 (); gtk_register_dialog(dialog); // Register callbacks #define ASSOCIATE(x,y) gtk_dialog_add_action_widget (GTK_DIALOG (dialog), WID(x),y) #define CONNECT(x,y,z) gtk_signal_connect(GTK_OBJECT(WID(x)), #y,GTK_SIGNAL_FUNC(z), NULL); #define ACTION_PREV 10 #define ACTION_NEXT 20 #define ACTION_PREV_EMPTY 30 #define ACTION_NEXT_EMPTY 40 #define ACTION_SAVE 50 #define ACTION_DELETE 60 #define ACTION_ACTIVATE 70 #define ACTION_SEARCH 80 #define ACTION_REWIND 90 ASSOCIATE(buttonPrev,ACTION_PREV); ASSOCIATE(buttonNext,ACTION_NEXT); ASSOCIATE(buttonEmptyPrev,ACTION_PREV_EMPTY); ASSOCIATE(buttonNextEmpty,ACTION_NEXT_EMPTY); ASSOCIATE(buttonSave,ACTION_SAVE); ASSOCIATE(buttonDelete,ACTION_DELETE); ASSOCIATE(buttonSearch,ACTION_SEARCH); ASSOCIATE(buttonRewind,ACTION_REWIND); CONNECT(drawingarea1,expose_event,glyphDraw); CONNECT(entry1,activate,glyphActivate); gtk_widget_show(dialog); glyphUpdate(); while(1) { gint b=gtk_dialog_run(GTK_DIALOG(dialog)); switch(b) { case ACTION_REWIND: currentGlyph=head.next; glyphUpdate(); continue; case ACTION_SEARCH: { char *tomatch=NULL; { // Dialog Factory to the rescue ! diaElemText txt(&tomatch,QT_TR_NOOP("String"),NULL); diaElem *elems[]={&txt}; if(!diaFactoryRun(QT_TR_NOOP("Search string"),1,elems)) { continue; break; } } printf("Searched string <%s>\n",tomatch); while(currentGlyph->next) { currentGlyph=currentGlyph->next; glyphUpdate(); if(currentGlyph->code) { printf("%s vs %s\n",currentGlyph->code,tomatch); if(!strcmp(currentGlyph->code,tomatch)) { glyphUpdate(); break; } } } ADM_dezalloc(tomatch); if(!currentGlyph->next) GUI_Error_HIG(QT_TR_NOOP("End reached"),QT_TR_NOOP("No more glyphs")); } continue; break; ; case ACTION_PREV: printf("PREV\n"); if(currentGlyph!=head.next) { admGlyph *father; father=glyphSearchFather(currentGlyph,&head); if(father) { currentGlyph=father; glyphUpdate(); } } continue;break; case ACTION_NEXT: printf("NEXT\n"); if(currentGlyph->next) { currentGlyph=currentGlyph->next; glyphUpdate(); } continue;break; case ACTION_NEXT_EMPTY: printf("NEXT EMPTY\n"); while(1) { if(currentGlyph->next) { currentGlyph=currentGlyph->next; glyphUpdate(); if(!currentGlyph->code || !*(currentGlyph->code)) { break; } } else { GUI_Error_HIG(QT_TR_NOOP("End reached"),QT_TR_NOOP("No more glyphs")); break; } } continue;break; case ACTION_PREV_EMPTY: printf("PREV EMPTY\n"); while(1) { if(currentGlyph!=head.next) { admGlyph *father; father=glyphSearchFather(currentGlyph,&head); if(father) { currentGlyph=father; glyphUpdate(); if(!currentGlyph->code || !*(currentGlyph->code)) { break; } continue; } } GUI_Error_HIG(QT_TR_NOOP("Head reached"),QT_TR_NOOP("No more glyphs")); break; } continue;break; case ACTION_SAVE: saveGlyph(glyphName,&head,nbGlyph); continue;break; case ACTION_DELETE: { admGlyph *father; father=glyphSearchFather(currentGlyph,&head); ADM_assert(father); father->next=currentGlyph->next; delete currentGlyph; currentGlyph=father; if(father==&head && head.next) currentGlyph=head.next; nbGlyph--; glyphUpdate(); continue;break; } case ACTION_ACTIVATE: { const gchar *old; if(currentGlyph->code) delete [] currentGlyph->code; currentGlyph->code=NULL; // Retrieve new one old=gtk_entry_get_text (GTK_ENTRY (WID(entry1))); if(old && strlen(old)) { currentGlyph->code=new char[strlen(old)+1]; strcpy(currentGlyph->code,old); } } continue;break; } break; // exit while(1) } gtk_unregister_dialog(dialog); gtk_widget_destroy(dialog); destroyGlyphTree(&head); return ret; }
/** \fn DIA_ocrDvb \brief Dialog to select input & output files before calling the actual ocr engine */ uint8_t DIA_ocrDvb(void) { vobSubParam subparam={NULL,0,0}; char *srtFileName=NULL; char *glyphFileName=NULL; char *tsFileName=NULL; admGlyph head(16,16); char *globalGlyph=NULL; uint32_t globalGlyphOn=0; uint32_t pid=0x96; ADM_OCR_SOURCE source; memset(&source,0,sizeof(source)); source.type=ADM_OCR_TYPE_TS; prefs->get(FEATURE_GLOBAL_GLYPH_ACTIVE,&globalGlyphOn); if(globalGlyphOn) { prefs->get(FEATURE_GLOBAL_GLYPH_NAME,&globalGlyph); if(!*globalGlyph) { ADM_dezalloc(globalGlyph); globalGlyph=NULL; } } if(globalGlyph) { glyphFileName=globalGlyph; } _againX: // Fist build a dialogFactory to get input and output files diaElemFile selectTs(1,&tsFileName,QT_TR_NOOP("Input TS:"), NULL, QT_TR_NOOP("Select TS file")); diaElemUInteger selectPid(&pid,QT_TR_NOOP("Subtitle PID:"),0,255); diaElemFile selectGlyph(1,&glyphFileName,QT_TR_NOOP("Use glyphset (optional):"), NULL, QT_TR_NOOP("Select GlyphSet file")); diaElemFile selectSrt(1,&srtFileName,QT_TR_NOOP("Output SRT file"), NULL, QT_TR_NOOP("Save SRT file")); diaElem *elems[]={&selectTs,&selectPid,&selectSrt,&selectGlyph}; uint32_t n=4; if(globalGlyph) { n--; // Remove glyph from dialog } if( !diaFactoryRun(QT_TR_NOOP("Select input and ouput files"),n,elems)) { cleanupSub(&source); if(srtFileName )ADM_dezalloc(srtFileName); srtFileName=NULL; destroyGlyphTree(&head); return 0; } // TS file exists ? if(!ADM_fileExist(tsFileName)) { GUI_Error_HIG(QT_TR_NOOP("File error"),QT_TR_NOOP("Please Select a valid TS file.")); goto _againX; } if(!srtFileName || !*srtFileName) { GUI_Error_HIG(QT_TR_NOOP("File error"),QT_TR_NOOP("Please Select a valid output SRT file.")); goto _againX; } if(glyphFileName && *glyphFileName) { if(!ADM_fileExist(glyphFileName)) { GUI_Error_HIG(QT_TR_NOOP("File error"),QT_TR_NOOP("The idx/sub file does not exist.")); goto _againX; } // Purge previous glyph set if any destroyGlyphTree(&head); uint32_t nb; printf("[OCR] Loading glyphset :<%s>\n",glyphFileName); if(!loadGlyph(glyphFileName,&head,&nb)) { GUI_Error_HIG(QT_TR_NOOP("File error"),QT_TR_NOOP("Cannot load the glyphset file.")); goto _againX; } printf("[GLYPH] Found %u glyph\n"); } // We have our SRT and our TS file // Call the OCR engine... source.TsFile=ADM_strdup(tsFileName); source.TsPid=pid; ADM_ocr_engine(source,srtFileName,&head); // Save glyph set if(globalGlyph) { uint32_t nb=1; saveGlyph(globalGlyph,&head,nb); }else { char *save=NULL; uint32_t nb=1; diaElemFile selectSave(1,&save,QT_TR_NOOP("GlyphSet filename"), NULL, QT_TR_NOOP("Save GlyphSet file")); diaElem *elems2[]={&selectSave}; if( diaFactoryRun(QT_TR_NOOP("Save GlyphSet"),1,elems2)) { saveGlyph(save,&head,nb); } if(save) ADM_dezalloc(save); } cleanupSub(&source); if(srtFileName )ADM_dezalloc(srtFileName); srtFileName=NULL; if(tsFileName )ADM_dezalloc(tsFileName); tsFileName=NULL; destroyGlyphTree(&head); return 1; }