def analyzeDocumentWithTemplate(self, cr, uid, documentId, templateId, context): # Whether templateId is valid or not # Remove previous properties ids = self.pool.get('nan.document.property').search( cr, uid, [('document_id','=',documentId)], context=context ) self.pool.get('nan.document.property').unlink( cr, uid, ids, context ) if templateId: template = self.pool.get('nan.template').getTemplateFromId( cr, uid, templateId, context ) documents = self.read(cr, uid, [documentId], context=context) if not documents: return document = documents[0] fp, image = tempfile.mkstemp() fp = os.fdopen( fp, 'wb+' ) try: fp.write( base64.decodestring( document['datas'] ) ) finally: fp.close() recognizer = Recognizer() recognizer.recognize( QImage( image ) ) doc = recognizer.extractWithTemplate( image, template ) for box in doc.boxes: obj.create(cr, uid, { 'name': box.templateBox.name, 'value': box.text, 'document_id': document['id'], 'template_box_id': box.templateBox.id }, context) self.executeAttachs( cr, uid, [documentId], context ) self.executeActions( cr, uid, [documentId], True, context )
def scanDocumentWithTemplate(self, cr, uid, documentId, templateId): # Whether templateId is valid or not # Remove previous properties obj = self.pool.get('nan.document.property') ids = obj.search(cr, uid, [('document', '=', documentId)]) obj.unlink(cr, uid, ids) if templateId: # Initialize Ocr System (Gamera) initOcrSystem() template = self.pool.get('nan.template').getTemplateFromId( cr, uid, templateId) documents = self.read(cr, uid, [documentId]) if not documents: return document = documents[0] fp, image = tempfile.mkstemp() fp = os.fdopen(fp, 'wb+') fp.write(base64.decodestring(document['datas'])) fp.close() recognizer = Recognizer() recognizer.recognize(QImage(image)) doc = recognizer.extractWithTemplate(image, template) for box in doc.boxes: obj.create( cr, uid, { 'name': box.templateBox.name, 'value': box.text, 'document': document['id'], 'template_box': box.templateBox.id }) self.executeAttachs(cr, uid, [documentId]) self.executeActions(cr, uid, [documentId], True) cr.commit()
def scan_document(self, cr, uid, imageIds, notify=False): print "Scan_documentcalled" # Load templates into 'templates' list templates = self.pool.get('nan.template').getAllTemplates(cr, uid) # Initialize Ocr System (Gamera) initOcrSystem() recognizer = Recognizer() # Iterate over all images and try to find the most similar template for document in self.browse(cr, uid, imageIds): if document.state not in ('pending', 'scanning'): continue fp, image = tempfile.mkstemp() fp = os.fdopen(fp, 'wb+') fp.write(base64.decodestring(document.datas)) fp.close() recognizer.recognize(QImage(image)) result = recognizer.findMatchingTemplateByOffset(templates) template = result['template'] doc = result['document'] if not template: print "No template found for document %s." % document.name else: print "The best template found for document %s is %s." % ( document.name, template.name) if template: template_id = template.id else: template_id = False self.write(cr, uid, [document.id], { 'template': template_id, 'state': 'scanned' }) if doc: obj = self.pool.get('nan.document.property') for box in doc.boxes: obj.create( cr, uid, { 'name': box.templateBox.name, 'value': box.text, 'document': document.id, 'template_box': box.templateBox.id }) if notify: self.pool.get('res.request').create( cr, uid, { 'act_from': uid, 'act_to': uid, 'name': 'Finished scanning document', 'body': 'The auto_attach system has finished scanning the document you requested. A reference to the document can be found in field Document Ref 1.', 'ref_doc1': 'nan.document,%d' % document.id, }) self.executeAttachs(cr, uid, imageIds) self.executeActions(cr, uid, imageIds, True) cr.commit()
def __init__(self, parent=None): QMainWindow.__init__(self, parent) loadUi('mainwindow.ui', self) self.scene = DocumentScene() self.uiView.setScene(self.scene) self.uiView.setRenderHints(QPainter.Antialiasing | QPainter.TextAntialiasing | QPainter.SmoothPixmapTransform) self.uiView.setCacheMode(QGraphicsView.CacheBackground) self._template = Template(self.Unnamed) self.scene.setTemplate(self._template) self.uiTool = ToolWidget(self.uiToolDock) self.undoGroup = QUndoGroup(self) stack = QUndoStack(self.undoGroup) self.undoGroup.setActiveStack(stack) # Let default Qt Undo and Redo Actions handle the Undo/Redo actions # And put them at the very beggining of the Edit menu undoAction = self.undoGroup.createUndoAction(self.menuEdit) undoAction.setShortcut("Ctrl+Z") redoAction = self.undoGroup.createRedoAction(self.menuEdit) redoAction.setShortcut("Ctrl+Shift+Z") if self.menuEdit.actions(): firstAction = self.menuEdit.actions()[0] else: firstAction = None self.menuEdit.insertAction(firstAction, undoAction) self.menuEdit.insertAction(firstAction, redoAction) self.connect(self.scene, SIGNAL('newTemplateBox(QRectF)'), self.newTemplateBox) self.connect( self.scene, SIGNAL('currentTemplateBoxChanged(PyQt_PyObject,PyQt_PyObject)'), self.currentTemplateBoxChanged) self.connect(self.scene, SIGNAL('mouseMoved'), self.sceneMouseMoved) self.connect(self.actionExit, SIGNAL('triggered()'), self.close) self.connect(self.actionOpenImage, SIGNAL('triggered()'), self.openImage) self.connect(self.actionOpenTemplate, SIGNAL('triggered()'), self.openTemplate) self.connect(self.actionToggleImageBoxes, SIGNAL('triggered()'), self.toggleImageBoxes) self.connect(self.actionToggleTemplateBoxes, SIGNAL('triggered()'), self.toggleTemplateBoxes) self.connect(self.actionToggleFeatureBoxes, SIGNAL('triggered()'), self.toggleFeatureBoxes) self.connect(self.actionToggleBinarized, SIGNAL('triggered()'), self.toggleBinarized) self.connect(self.actionLogin, SIGNAL('triggered()'), self.login) self.connect(self.actionSaveTemplate, SIGNAL('triggered()'), self.saveTemplate) self.connect(self.actionSaveTemplateAs, SIGNAL('triggered()'), self.saveTemplateAs) self.connect(self.actionNewTemplate, SIGNAL('triggered()'), self.newTemplate) self.connect(self.actionDelete, SIGNAL('triggered()'), self.removeTemplateBox) self.connect(self.actionZoom, SIGNAL('triggered()'), self.zoom) self.connect(self.actionUnzoom, SIGNAL('triggered()'), self.unzoom) self.connect(self.actionFindMatchingTemplateByOffset, SIGNAL('triggered()'), self.findMatchingTemplateByOffset) self.connect(self.actionFindMatchingTemplateByText, SIGNAL('triggered()'), self.findMatchingTemplateByText) self.connect(self.actionRecognizeInvoice, SIGNAL('triggered()'), self.recognizeInvoice) self.toggleImageBoxes() QTimer.singleShot(1000, self.setup) self.updateTitle() self.updateActions() # Login defaults LoginDialog.defaultHost = 'localhost' LoginDialog.defaultPort = 8070 LoginDialog.defaultProtocol = 'socket://' LoginDialog.defaultUserName = '******' self.recognizer = Recognizer() self.connect(self.recognizer, SIGNAL('finished()'), self.recognized)
class MainWindow(QMainWindow): Unnamed = _('unnamed') def __init__(self, parent=None): QMainWindow.__init__(self, parent) loadUi('mainwindow.ui', self) self.scene = DocumentScene() self.uiView.setScene(self.scene) self.uiView.setRenderHints(QPainter.Antialiasing | QPainter.TextAntialiasing | QPainter.SmoothPixmapTransform) self.uiView.setCacheMode(QGraphicsView.CacheBackground) self._template = Template(self.Unnamed) self.scene.setTemplate(self._template) self.uiTool = ToolWidget(self.uiToolDock) self.undoGroup = QUndoGroup(self) stack = QUndoStack(self.undoGroup) self.undoGroup.setActiveStack(stack) # Let default Qt Undo and Redo Actions handle the Undo/Redo actions # And put them at the very beggining of the Edit menu undoAction = self.undoGroup.createUndoAction(self.menuEdit) undoAction.setShortcut("Ctrl+Z") redoAction = self.undoGroup.createRedoAction(self.menuEdit) redoAction.setShortcut("Ctrl+Shift+Z") if self.menuEdit.actions(): firstAction = self.menuEdit.actions()[0] else: firstAction = None self.menuEdit.insertAction(firstAction, undoAction) self.menuEdit.insertAction(firstAction, redoAction) self.connect(self.scene, SIGNAL('newTemplateBox(QRectF)'), self.newTemplateBox) self.connect( self.scene, SIGNAL('currentTemplateBoxChanged(PyQt_PyObject,PyQt_PyObject)'), self.currentTemplateBoxChanged) self.connect(self.scene, SIGNAL('mouseMoved'), self.sceneMouseMoved) self.connect(self.actionExit, SIGNAL('triggered()'), self.close) self.connect(self.actionOpenImage, SIGNAL('triggered()'), self.openImage) self.connect(self.actionOpenTemplate, SIGNAL('triggered()'), self.openTemplate) self.connect(self.actionToggleImageBoxes, SIGNAL('triggered()'), self.toggleImageBoxes) self.connect(self.actionToggleTemplateBoxes, SIGNAL('triggered()'), self.toggleTemplateBoxes) self.connect(self.actionToggleFeatureBoxes, SIGNAL('triggered()'), self.toggleFeatureBoxes) self.connect(self.actionToggleBinarized, SIGNAL('triggered()'), self.toggleBinarized) self.connect(self.actionLogin, SIGNAL('triggered()'), self.login) self.connect(self.actionSaveTemplate, SIGNAL('triggered()'), self.saveTemplate) self.connect(self.actionSaveTemplateAs, SIGNAL('triggered()'), self.saveTemplateAs) self.connect(self.actionNewTemplate, SIGNAL('triggered()'), self.newTemplate) self.connect(self.actionDelete, SIGNAL('triggered()'), self.removeTemplateBox) self.connect(self.actionZoom, SIGNAL('triggered()'), self.zoom) self.connect(self.actionUnzoom, SIGNAL('triggered()'), self.unzoom) self.connect(self.actionFindMatchingTemplateByOffset, SIGNAL('triggered()'), self.findMatchingTemplateByOffset) self.connect(self.actionFindMatchingTemplateByText, SIGNAL('triggered()'), self.findMatchingTemplateByText) self.connect(self.actionRecognizeInvoice, SIGNAL('triggered()'), self.recognizeInvoice) self.toggleImageBoxes() QTimer.singleShot(1000, self.setup) self.updateTitle() self.updateActions() # Login defaults LoginDialog.defaultHost = 'localhost' LoginDialog.defaultPort = 8070 LoginDialog.defaultProtocol = 'socket://' LoginDialog.defaultUserName = '******' self.recognizer = Recognizer() self.connect(self.recognizer, SIGNAL('finished()'), self.recognized) def setup(self): #initOcrSystem() #self.scene.setDocument( 'c-0.tif' ) self.connect(self.uiTool, SIGNAL('recognizerChanged(QString)'), self.recognizerChanged) self.uiTool.show() self.uiToolDock.setWidget(self.uiTool) #Rpc.session.login( 'http://*****:*****@127.0.0.1:8069', 'g1' ) def sceneMouseMoved(self, pos): self.updatePosition(pos) def findMatchingTemplateByOffset(self): self.findMatchingTemplate('offset') def findMatchingTemplateByText(self): self.findMatchingTemplate('text') def recognizeInvoice(self): from NanScan.Generics.InvoiceRecognizer import InvoiceRecognizer p = InvoiceRecognizer() result = p.recognize(self.recognizer) QMessageBox.information(self, _('Invoice Recognition'), result) def findMatchingTemplate(self, type): if type == 'offset': title = _('Template search by offset') else: title = _('Template search by text') if not self.recognizer.image: QMessageBox.information( self, title, _('No image opened. Please open an image to find a matching template.' )) return if not Rpc.session.logged(): if not self.login(): return templates = TemplateStorageManager.loadAll() time = QTime() time.start() if type == 'offset': result = self.recognizer.findMatchingTemplateByOffset(templates) else: result = self.recognizer.findMatchingTemplateByText(templates) elapsed = time.elapsed() if not result['template']: QMessageBox.information( self, title, _('No template found for the current image. Took %d milliseconds' ) % elapsed) return self._template = result['template'] self.scene.setTemplate(self._template) self.updateTitle() QMessageBox.information( self, title, _('Template found with offset (%.2f, %.2f) in %d milliseconds') % (result['xOffset'], result['yOffset'], elapsed)) def recognizerChanged(self, recognizer): rect = self.uiTool.box.rect self.uiTool.setText( self.scene.recognizer.textInRegion(rect, unicode(recognizer))) def newTemplateBox(self, rect): # Creating and adding the box to the template # will automatically create the Rect in the Scene box = TemplateBox() box.rect = rect box.text = self.scene.recognizer.textInRegion(rect, 'text') box.featureRect = self.scene.recognizer.featureRectInRegion( rect, 'text') add = AddTemplateBoxUndoCommand(self._template, box) self.undoGroup.activeStack().push(add) #def setCurrentTemplateBox(self, box): #if self.uiTool.box: #self.uiTool.store() #self.uiTool.box = box def currentTemplateBoxChanged(self, current, previous): if self.uiTool.box: self.uiTool.store() self.uiTool.box = current self.actionDelete.setEnabled(bool(current)) def openImage(self): self.fileName = QFileDialog.getOpenFileName(self) if self.fileName.isNull(): return QApplication.setOverrideCursor(Qt.BusyCursor) self.recognizer.startRecognition(QImage(self.fileName)) def recognized(self): self.scene.setDocument(self.recognizer) QApplication.restoreOverrideCursor() def toggleImageBoxes(self): self.scene.setImageBoxesVisible( self.actionToggleImageBoxes.isChecked()) def toggleTemplateBoxes(self): self.scene.setTemplateBoxesVisible( self.actionToggleTemplateBoxes.isChecked()) def toggleFeatureBoxes(self): self.scene.setFeatureBoxesVisible( self.actionToggleFeatureBoxes.isChecked()) def toggleBinarized(self): self.scene.setBinarizedVisible(self.actionToggleBinarized.isChecked()) def removeTemplateBox(self): if not self.uiTool.box: return delete = DeleteUndoCommand(self._template, self.uiTool.box) self.undoGroup.activeStack().push(delete) def zoom(self): self.uiView.scale(1.2, 1.2) def unzoom(self): self.uiView.scale(0.8, 0.8) def login(self): dialog = LoginDialog(self) if dialog.exec_() == QDialog.Rejected: return False if Rpc.session.login(dialog.url, dialog.databaseName) > 0: self.updateTitle() return True else: self.updateTitle() return False def newTemplate(self): answer = QMessageBox.question( self, _('New Template'), _('Do you want to save changes to the current template?'), QMessageBox.Save | QMessageBox.No | QMessageBox.Cancel) if answer == QMessageBox.Cancel: return elif answer == QMessageBox.Save: if not self.saveTemplate(): return self._template = Template(self.Unnamed) self.scene.setTemplate(self._template) self.updateTitle() def saveTemplate(self): self.uiTool.store() if not Rpc.session.logged(): if not self.login(): return False if not self._template.id: (name, ok) = QInputDialog.getText(self, _('Save template'), _('Template name:')) if not ok: return False self._template.name = unicode(name) if self._template.id: Rpc.session.call('/object', 'execute', 'nan.template', 'write', [self._template.id], {'name': self._template.name}) ids = Rpc.session.call('/object', 'execute', 'nan.template.box', 'search', [('template', '=', self._template.id)]) Rpc.session.call('/object', 'execute', 'nan.template.box', 'unlink', ids) else: self._template.id = Rpc.session.call('/object', 'execute', 'nan.template', 'create', {'name': self._template.name}) for x in self._template.boxes: values = { 'x': x.rect.x(), 'y': x.rect.y(), 'width': x.rect.width(), 'height': x.rect.height(), 'feature_x': x.featureRect.x(), 'feature_y': x.featureRect.y(), 'feature_width': x.featureRect.width(), 'feature_height': x.featureRect.height(), 'template': self._template.id, 'name': x.name, 'text': x.text, 'recognizer': x.recognizer, 'type': x.type, 'filter': x.filter } Rpc.session.call('/object', 'execute', 'nan.template.box', 'create', values) self.updateTitle() return True def saveTemplateAs(self): id = self._template.id self._template.id = 0 if not self.saveTemplate(): self._template.id = id self.updateTitle() def openTemplate(self): if not Rpc.session.logged(): if not self.login(): return dialog = OpenTemplateDialog(self) if dialog.exec_() == QDialog.Rejected: return model = dialog.group[dialog.id] self._template = Template(model.value('name')) self._template.id = model.id fields = Rpc.session.execute('/object', 'execute', 'nan.template.box', 'fields_get') model.value('boxes').addFields(fields) for x in model.value('boxes'): box = TemplateBox() box.rect = QRectF(x.value('x'), x.value('y'), x.value('width'), x.value('height')) box.featureRect = QRectF(x.value('feature_x'), x.value('feature_y'), x.value('feature_width'), x.value('feature_height')) box.name = x.value('name') box.text = x.value('text') box.recognizer = x.value('recognizer') box.type = x.value('type') box.filter = x.value('filter') self._template.addBox(box) self.scene.setTemplate(self._template) self.updateTitle() def updateTitle(self): self.setWindowTitle("Planta - [%s]" % self._template.name) if Rpc.session.logged(): server = '%s [%s]' % (Rpc.session.url, Rpc.session.databaseName) else: shortcut = unicode(self.actionLogin.shortcut().toString()) if shortcut: server = _('Press %s to login') % shortcut else: server = 'not logged in' self.uiServer.setText(server) def updatePosition(self, pos): pos = self.uiView.mapToScene(self.uiView.mapFromGlobal(QCursor.pos())) pos = self.scene.mapPointToRecognizer(pos) position = _('(%.2f, %.2f)') % (pos.x(), pos.y()) self.uiPosition.setText(position) def updateActions(self): # Allow deleting if there's a TemplateBox selected self.actionDelete.setEnabled(bool(self.uiTool.box))
def analyze_document(self, cr, uid, imageIds, context=None): # Load templates into 'templates' list templates = self.pool.get('nan.template').getAllTemplates( cr, uid, context ) templatesWithAnalysis = [x for x in templates if x.analysisFunction] templatesWithoutAnalysis = [x for x in templates if not x.analysisFunction] # Search what recognizers are used so we do not execute unnecessary processes. recognizers = set() for template in templates: for box in template.boxes: recognizers.add( box.recognizer ) recognizers = list(recognizers) recognizer = Recognizer() # Iterate over all images and try to find the most similar template for document in self.browse(cr, uid, imageIds, context): if document.state not in ('pending','analyzing'): continue if not document.datas: continue fp, image = tempfile.mkstemp() fp = os.fdopen( fp, 'wb+' ) try: fp.write( base64.decodestring(document.datas) ) finally: fp.close() recognizer.recognize( QImage( image ), recognizers ) template = False doc = False for template in templatesWithAnalysis: function = re.sub( ' *', '', template.analysisFunction ) if function.endswith('()'): function = function[:-2] doc = eval( 'self.%s(cr, uid, document, template, recognizer, context)' % function ) if doc: break if not doc: result = recognizer.findMatchingTemplateByOffset( templatesWithoutAnalysis ) template = result['template'] doc = result['document'] if not template: print("No template found for document %s." % document.name) else: print("The best template found for document %s is %s." % (document.name, template.name)) if template: template_id = template.id else: template_id = False self.write(cr, uid, [document.id], { 'template_id': template_id, 'state': 'analyzed' }, context=context) if doc: for box in doc.boxes: self.pool.get('nan.document.property').create(cr, uid, { 'name': box.name, 'value': box.text, 'document_id': document.id, 'template_box_id': box.templateBox and box.templateBox.id or False }, context) if document.state == 'analyzing': self.pool.get('res.request').create( cr, uid, { 'act_from': uid, 'act_to': uid, 'name': 'Finished analyzing document', 'body': 'The auto_attach system has finished analyzing the document you requested. A reference to the document can be found in field Document Ref 1.', 'ref_doc1': 'nan.document,%d' % document.id, }, context) self.executeAttachs( cr, uid, imageIds, context ) self.executeActions( cr, uid, imageIds, True, context )
def __init__(self, parent=None): QMainWindow.__init__(self, parent) loadUi( 'mainwindow.ui', self ) self.scene = DocumentScene() self.uiView.setScene( self.scene ) self.uiView.setRenderHints( QPainter.Antialiasing | QPainter.TextAntialiasing | QPainter.SmoothPixmapTransform ) self.uiView.setCacheMode( QGraphicsView.CacheBackground ) self._template = Template( self.Unnamed ) self.scene.setTemplate(self._template) self.uiTool = ToolWidget( self.uiToolDock ) self.undoGroup = QUndoGroup( self ) stack = QUndoStack( self.undoGroup ) self.undoGroup.setActiveStack( stack ) # Let default Qt Undo and Redo Actions handle the Undo/Redo actions # And put them at the very beggining of the Edit menu undoAction = self.undoGroup.createUndoAction( self.menuEdit ) undoAction.setShortcut( "Ctrl+Z" ) redoAction = self.undoGroup.createRedoAction( self.menuEdit ) redoAction.setShortcut( "Ctrl+Shift+Z" ) if self.menuEdit.actions(): firstAction = self.menuEdit.actions()[0] else: firstAction = None self.menuEdit.insertAction( firstAction, undoAction ) self.menuEdit.insertAction( firstAction, redoAction ) self.connect( self.scene, SIGNAL('newTemplateBox(QRectF)'), self.newTemplateBox ) self.connect( self.scene, SIGNAL('currentTemplateBoxChanged(PyQt_PyObject,PyQt_PyObject)'), self.currentTemplateBoxChanged) self.connect( self.scene, SIGNAL('mouseMoved'), self.sceneMouseMoved ) self.connect( self.actionExit, SIGNAL('triggered()'), self.close ) self.connect( self.actionOpenImage, SIGNAL('triggered()'), self.openImage ) self.connect( self.actionOpenTemplate, SIGNAL('triggered()'), self.openTemplate ) self.connect( self.actionToggleImageBoxes, SIGNAL('triggered()'), self.toggleImageBoxes ) self.connect( self.actionToggleTemplateBoxes, SIGNAL('triggered()'), self.toggleTemplateBoxes ) self.connect( self.actionToggleFeatureBoxes, SIGNAL('triggered()'), self.toggleFeatureBoxes ) self.connect( self.actionToggleBinarized, SIGNAL('triggered()'), self.toggleBinarized ) self.connect( self.actionLogin, SIGNAL('triggered()'), self.login ) self.connect( self.actionSaveTemplate, SIGNAL('triggered()'), self.saveTemplate ) self.connect( self.actionSaveTemplateAs, SIGNAL('triggered()'), self.saveTemplateAs ) self.connect( self.actionNewTemplate, SIGNAL('triggered()'), self.newTemplate ) self.connect( self.actionDelete, SIGNAL('triggered()'), self.removeTemplateBox ) self.connect( self.actionZoom, SIGNAL('triggered()'), self.zoom ) self.connect( self.actionUnzoom, SIGNAL('triggered()'), self.unzoom ) self.connect( self.actionFindMatchingTemplateByOffset, SIGNAL('triggered()'), self.findMatchingTemplateByOffset ) self.connect( self.actionFindMatchingTemplateByText, SIGNAL('triggered()'), self.findMatchingTemplateByText ) self.connect( self.actionRecognizeInvoice, SIGNAL('triggered()'), self.recognizeInvoice ) self.toggleImageBoxes() QTimer.singleShot( 1000, self.setup ) self.updateTitle() self.updateActions() # Login defaults LoginDialog.defaultHost = 'localhost' LoginDialog.defaultPort = 8070 LoginDialog.defaultProtocol = 'socket://' LoginDialog.defaultUserName = '******' self.recognizer = Recognizer() self.connect( self.recognizer, SIGNAL('finished()'), self.recognized )
class MainWindow(QMainWindow): Unnamed = _('unnamed') def __init__(self, parent=None): QMainWindow.__init__(self, parent) loadUi( 'mainwindow.ui', self ) self.scene = DocumentScene() self.uiView.setScene( self.scene ) self.uiView.setRenderHints( QPainter.Antialiasing | QPainter.TextAntialiasing | QPainter.SmoothPixmapTransform ) self.uiView.setCacheMode( QGraphicsView.CacheBackground ) self._template = Template( self.Unnamed ) self.scene.setTemplate(self._template) self.uiTool = ToolWidget( self.uiToolDock ) self.undoGroup = QUndoGroup( self ) stack = QUndoStack( self.undoGroup ) self.undoGroup.setActiveStack( stack ) # Let default Qt Undo and Redo Actions handle the Undo/Redo actions # And put them at the very beggining of the Edit menu undoAction = self.undoGroup.createUndoAction( self.menuEdit ) undoAction.setShortcut( "Ctrl+Z" ) redoAction = self.undoGroup.createRedoAction( self.menuEdit ) redoAction.setShortcut( "Ctrl+Shift+Z" ) if self.menuEdit.actions(): firstAction = self.menuEdit.actions()[0] else: firstAction = None self.menuEdit.insertAction( firstAction, undoAction ) self.menuEdit.insertAction( firstAction, redoAction ) self.connect( self.scene, SIGNAL('newTemplateBox(QRectF)'), self.newTemplateBox ) self.connect( self.scene, SIGNAL('currentTemplateBoxChanged(PyQt_PyObject,PyQt_PyObject)'), self.currentTemplateBoxChanged) self.connect( self.scene, SIGNAL('mouseMoved'), self.sceneMouseMoved ) self.connect( self.actionExit, SIGNAL('triggered()'), self.close ) self.connect( self.actionOpenImage, SIGNAL('triggered()'), self.openImage ) self.connect( self.actionOpenTemplate, SIGNAL('triggered()'), self.openTemplate ) self.connect( self.actionToggleImageBoxes, SIGNAL('triggered()'), self.toggleImageBoxes ) self.connect( self.actionToggleTemplateBoxes, SIGNAL('triggered()'), self.toggleTemplateBoxes ) self.connect( self.actionToggleFeatureBoxes, SIGNAL('triggered()'), self.toggleFeatureBoxes ) self.connect( self.actionToggleBinarized, SIGNAL('triggered()'), self.toggleBinarized ) self.connect( self.actionLogin, SIGNAL('triggered()'), self.login ) self.connect( self.actionSaveTemplate, SIGNAL('triggered()'), self.saveTemplate ) self.connect( self.actionSaveTemplateAs, SIGNAL('triggered()'), self.saveTemplateAs ) self.connect( self.actionNewTemplate, SIGNAL('triggered()'), self.newTemplate ) self.connect( self.actionDelete, SIGNAL('triggered()'), self.removeTemplateBox ) self.connect( self.actionZoom, SIGNAL('triggered()'), self.zoom ) self.connect( self.actionUnzoom, SIGNAL('triggered()'), self.unzoom ) self.connect( self.actionFindMatchingTemplateByOffset, SIGNAL('triggered()'), self.findMatchingTemplateByOffset ) self.connect( self.actionFindMatchingTemplateByText, SIGNAL('triggered()'), self.findMatchingTemplateByText ) self.connect( self.actionRecognizeInvoice, SIGNAL('triggered()'), self.recognizeInvoice ) self.toggleImageBoxes() QTimer.singleShot( 1000, self.setup ) self.updateTitle() self.updateActions() # Login defaults LoginDialog.defaultHost = 'localhost' LoginDialog.defaultPort = 8070 LoginDialog.defaultProtocol = 'socket://' LoginDialog.defaultUserName = '******' self.recognizer = Recognizer() self.connect( self.recognizer, SIGNAL('finished()'), self.recognized ) def setup(self): #initOcrSystem() #self.scene.setDocument( 'c-0.tif' ) self.connect( self.uiTool, SIGNAL('recognizerChanged(QString)'), self.recognizerChanged ) self.uiTool.show() self.uiToolDock.setWidget( self.uiTool ) #Rpc.session.login( 'http://*****:*****@127.0.0.1:8069', 'g1' ) def sceneMouseMoved(self, pos): self.updatePosition( pos ) def findMatchingTemplateByOffset(self): self.findMatchingTemplate( 'offset' ) def findMatchingTemplateByText(self): self.findMatchingTemplate( 'text' ) def recognizeInvoice(self): from NanScan.Generics.InvoiceRecognizer import InvoiceRecognizer p = InvoiceRecognizer() result = p.recognize( self.recognizer ) QMessageBox.information( self, _('Invoice Recognition'), result ) def findMatchingTemplate(self, type): if type == 'offset': title = _('Template search by offset') else: title = _('Template search by text') if not self.recognizer.image: QMessageBox.information( self, title, _('No image opened. Please open an image to find a matching template.') ) return if not Rpc.session.logged(): if not self.login(): return templates = TemplateStorageManager.loadAll() time = QTime() time.start() if type == 'offset': result = self.recognizer.findMatchingTemplateByOffset( templates ) else: result = self.recognizer.findMatchingTemplateByText( templates ) elapsed = time.elapsed() if not result['template']: QMessageBox.information( self, title, _('No template found for the current image. Took %d milliseconds') % elapsed ) return self._template = result['template'] self.scene.setTemplate(self._template) self.updateTitle() QMessageBox.information( self, title, _('Template found with offset (%.2f, %.2f) in %d milliseconds') % (result['xOffset'], result['yOffset'], elapsed) ) def recognizerChanged(self, recognizer): rect = self.uiTool.box.rect self.uiTool.setText( self.scene.recognizer.textInRegion( rect, unicode(recognizer) ) ) def newTemplateBox(self, rect): # Creating and adding the box to the template # will automatically create the Rect in the Scene box = TemplateBox() box.rect = rect box.text = self.scene.recognizer.textInRegion( rect, 'text' ) box.featureRect = self.scene.recognizer.featureRectInRegion( rect, 'text' ) add = AddTemplateBoxUndoCommand( self._template, box ) self.undoGroup.activeStack().push( add ) #def setCurrentTemplateBox(self, box): #if self.uiTool.box: #self.uiTool.store() #self.uiTool.box = box def currentTemplateBoxChanged(self, current, previous): if self.uiTool.box: self.uiTool.store() self.uiTool.box = current self.actionDelete.setEnabled( bool(current) ) def openImage(self): self.fileName = QFileDialog.getOpenFileName( self ) if self.fileName.isNull(): return QApplication.setOverrideCursor( Qt.BusyCursor ) self.recognizer.startRecognition( QImage(self.fileName) ) def recognized(self): self.scene.setDocument( self.recognizer ) QApplication.restoreOverrideCursor() def toggleImageBoxes(self): self.scene.setImageBoxesVisible( self.actionToggleImageBoxes.isChecked() ) def toggleTemplateBoxes(self): self.scene.setTemplateBoxesVisible( self.actionToggleTemplateBoxes.isChecked() ) def toggleFeatureBoxes(self): self.scene.setFeatureBoxesVisible( self.actionToggleFeatureBoxes.isChecked() ) def toggleBinarized(self): self.scene.setBinarizedVisible( self.actionToggleBinarized.isChecked() ) def removeTemplateBox(self): if not self.uiTool.box: return delete = DeleteUndoCommand( self._template, self.uiTool.box ) self.undoGroup.activeStack().push( delete ) def zoom(self): self.uiView.scale( 1.2, 1.2 ) def unzoom(self): self.uiView.scale( 0.8, 0.8 ) def login(self): dialog = LoginDialog( self ) if dialog.exec_() == QDialog.Rejected: return False if Rpc.session.login( dialog.url, dialog.databaseName ) > 0: self.updateTitle() return True else: self.updateTitle() return False def newTemplate(self): answer = QMessageBox.question(self, _('New Template'), _('Do you want to save changes to the current template?'), QMessageBox.Save | QMessageBox.No | QMessageBox.Cancel ) if answer == QMessageBox.Cancel: return elif answer == QMessageBox.Save: if not self.saveTemplate(): return self._template = Template( self.Unnamed ) self.scene.setTemplate( self._template ) self.updateTitle() def saveTemplate(self): self.uiTool.store() if not Rpc.session.logged(): if not self.login(): return False if not self._template.id: (name, ok) = QInputDialog.getText( self, _('Save template'), _('Template name:') ) if not ok: return False self._template.name = unicode(name) if self._template.id: Rpc.session.call( '/object', 'execute', 'nan.template', 'write', [self._template.id], {'name': self._template.name } ) ids = Rpc.session.call( '/object', 'execute', 'nan.template.box', 'search', [('template','=',self._template.id)] ) Rpc.session.call( '/object', 'execute', 'nan.template.box', 'unlink', ids ) else: self._template.id = Rpc.session.call( '/object', 'execute', 'nan.template', 'create', {'name': self._template.name } ) for x in self._template.boxes: values = { 'x': x.rect.x(), 'y': x.rect.y(), 'width': x.rect.width(), 'height': x.rect.height(), 'feature_x' : x.featureRect.x(), 'feature_y' : x.featureRect.y(), 'feature_width' : x.featureRect.width(), 'feature_height' : x.featureRect.height(), 'template': self._template.id, 'name': x.name, 'text': x.text, 'recognizer': x.recognizer, 'type': x.type, 'filter': x.filter } Rpc.session.call( '/object', 'execute', 'nan.template.box', 'create', values ) self.updateTitle() return True def saveTemplateAs(self): id = self._template.id self._template.id = 0 if not self.saveTemplate(): self._template.id = id self.updateTitle() def openTemplate(self): if not Rpc.session.logged(): if not self.login(): return dialog = OpenTemplateDialog(self) if dialog.exec_() == QDialog.Rejected: return model = dialog.group[dialog.id] self._template = Template( model.value('name') ) self._template.id = model.id fields = Rpc.session.execute('/object', 'execute', 'nan.template.box', 'fields_get') model.value('boxes').addFields( fields ) for x in model.value('boxes'): box = TemplateBox() box.rect = QRectF( x.value('x'), x.value('y'), x.value('width'), x.value('height') ) box.featureRect = QRectF( x.value('feature_x'), x.value('feature_y'), x.value('feature_width'), x.value('feature_height') ) box.name = x.value('name') box.text = x.value('text') box.recognizer = x.value('recognizer') box.type = x.value('type') box.filter = x.value('filter') self._template.addBox( box ) self.scene.setTemplate(self._template) self.updateTitle() def updateTitle(self): self.setWindowTitle( "Planta - [%s]" % self._template.name ) if Rpc.session.logged(): server = '%s [%s]' % (Rpc.session.url, Rpc.session.databaseName) else: shortcut = unicode( self.actionLogin.shortcut().toString() ) if shortcut: server = _('Press %s to login') % shortcut else: server = 'not logged in' self.uiServer.setText( server ) def updatePosition(self, pos): pos = self.uiView.mapToScene( self.uiView.mapFromGlobal( QCursor.pos() ) ) pos = self.scene.mapPointToRecognizer( pos ) position = _('(%.2f, %.2f)') % (pos.x(), pos.y()) self.uiPosition.setText( position ) def updateActions(self): # Allow deleting if there's a TemplateBox selected self.actionDelete.setEnabled( bool(self.uiTool.box) )