diff --git a/src/CNIRevelator.py b/src/CNIRevelator.py index 0ca7543..44dbac7 100644 --- a/src/CNIRevelator.py +++ b/src/CNIRevelator.py @@ -36,6 +36,7 @@ import globs # globs.py import pytesseract # pytesseract.py import logger # logger.py + from main import * # main.py # Global handler diff --git a/src/ihm.py b/src/ihm.py index 850794a..0d7f4de 100644 --- a/src/ihm.py +++ b/src/ihm.py @@ -31,6 +31,42 @@ from tkinter import ttk import logger # logger.py import globs # globs.py + +controlKeys = ["Return", "Right", "Left", "Up", "Down", "Home", "End", "Delete", "BackSpace", "Inser", "Shift_L", "Shift_R", "Control_R", "Control_L"] + +class DocumentAsk(Toplevel): + + def __init__(self, parent, choices): + self.choice = 0 + vals = [0, 1] + super().__init__(parent) + self.title("Choisir le document d'identité :") + + ttk.Radiobutton(self, text=choices[0], command=self.register0, value=vals[0]).pack() + ttk.Radiobutton(self, text=choices[1], command=self.register1, value=vals[1]).pack() + + self.button = Button(self, text='OK', command=(self.ok)).pack() + self.resizable(width=False, height=False) + ws = self.winfo_screenwidth() + hs = self.winfo_screenheight() + w = hs / 3 + h = ws / 20 + self.update() + if getattr(sys, 'frozen', False): + self.iconbitmap(sys._MEIPASS + '\\id-card.ico\\id-card.ico') + else: + self.iconbitmap('id-card.ico') + x = ws / 2 - w / 2 + y = hs / 2 - h / 2 + self.geometry('%dx%d+%d+%d' % (w, h, x, y)) + + def register0(self): + self.choice = 0 + def register1(self): + self.choice = 1 + def ok(self): + self.destroy() + class LoginDialog(Toplevel): def __init__(self, parent): diff --git a/src/main.py b/src/main.py index 441a113..e3695d0 100644 --- a/src/main.py +++ b/src/main.py @@ -33,6 +33,7 @@ import threading from datetime import datetime import re +import ihm # ihm.py import logger # logger.py import mrz # mrz.py import globs # globs.py @@ -51,6 +52,7 @@ class mainWindow(Tk): def initialize(self): self.mrzChar = '' self.mrzDecided = False + self.Tags = [] # Get the screen size ws = self.winfo_screenwidth() @@ -198,9 +200,37 @@ class mainWindow(Tk): logfile.printdbg('Initialization successful') def onTabPressed(self, event): - return 'break' + def stringValidation(self): + # analysis + # If we must decide the type of the document + if not self.mrzDecided: + # Get the candidates + candidates = mrz.allDocMatch(self.mrzChar.split("\n")) + + if len(candidates) == 2 and len(self.mrzChar) >= 8: + # Parameters for the choice invite + invite = ihm.DocumentAsk(self, [candidates[0][2], candidates[1][2]]) + invite.transient(self) + invite.grab_set() + invite.focus_force() + + self.wait_window(invite) + + self.logOnTerm("Document detecté : {}".format(candidates[invite.choice][2])) + self.mrzDecided = candidates[invite.choice] + + elif len(candidates) == 1: + self.logOnTerm("Document detecté : {}".format(candidates[0][2])) + self.mrzDecided = candidates[0] + else: + print("LEN mrzChar {} VS {}".format(len(self.mrzChar) - 2, len(self.mrzDecided[0][0]))) + # break the line + if len(self.mrzChar) - 2 == len(self.mrzDecided[0][0]): + self.termtext.delete("1.0","end") + self.termtext.insert("1.0", self.mrzChar) + def entryValidation(self, event): """ On the fly validation with regex @@ -216,7 +246,7 @@ class mainWindow(Tk): controlled = True # If not a control char - if not controlled and not event.keysym in ["Return", "Right", "Left", "Home", "End", "Delete", "BackSpace", "Inser", "Shift", "Control"]: + if not controlled and not event.keysym in ihm.controlKeys: # the regex regex = re.compile("[A-Z]|<|[0-9]") # match ! @@ -224,21 +254,12 @@ class mainWindow(Tk): self.logOnTerm("Caractère non accepté !\n") return "break" - # analysis + # Adds the entry self.mrzChar = self.termtext.get("1.0", "end")[:-1] + event.char + '\n' - # If we must decide the type of the document - if not self.mrzDecided: - # Get the candidates - candidates = mrz.allDocMatch(self.mrzChar.split("\n")) + self.stringValidation() + - if len(candidates) == 2: - # XXX demander ! - elif len(candidates) == 1: - self.logOnTerm("Document detecté : {}".format(candidates[0])) - self.mrzDecided = candidates[0] - else: - # Work with the document decided def pasteValidation(self, event): @@ -250,14 +271,19 @@ class mainWindow(Tk): # get the clipboard content lines = self.clipboard_get() + self.mrzChar = "" # the regex regex = re.compile("[^A-Z0-9<]") lines = re.sub(regex, '', lines) - # breaking the lines - self.termtext.insert("1.0", lines[:mrz.longest] + '\n' + lines[mrz.longest:mrz.longest*2] ) + # Get that + for char in lines: + self.termtext.insert("1.0", self.mrzChar) + self.mrzChar = self.mrzChar + char + self.stringValidation() + return "break" diff --git a/src/mrz.py b/src/mrz.py index 55e0f9a..69be2ec 100644 --- a/src/mrz.py +++ b/src/mrz.py @@ -639,7 +639,7 @@ AC = [ ] ## XXXXXXXXXXX -# VA = [ +# VB = [ # ["11222333333333333333333333333333333333333333", "444444444566677777789AAAAAABCCCCCCCCCCCCCCCDE"], # { # "1": ["2", "CODE", "V."], @@ -655,10 +655,10 @@ AC = [ # "B": ["1", "CTRL", "[0-9]", "A"], # "C": ["14", "FACULT", ".+"] # }, -# "Visa de type A" +# "Visa de type B" # ] -VB = [ +VA = [ ["112223333333333333333333333333333333", "444444444566677777789AAAAAABCCCCCC"], { "1": ["2", "CODE", "V."], @@ -674,7 +674,26 @@ VB = [ "B": ["1", "CTRL", "[0-9]", "A"], "C": ["8", "FACULT", ".+"] }, - "Visa de type B" + "Visa de type A" +] + +TSF = [ + ["112223333333333333333333333333333333", "444444444566677777789AAAAAABCCCCCC"], + { + "1": ["2", "CODE", "TS"], + "2": ["3", "PAYS", "[A-Z]+"], + "3": ["31", "NOM", "([A-Z]|<)+"], + "4": ["9", "NO", ".+"], + "5": ["1", "CTRL", "[0-9]","4"], + "6": ["3", "NAT", "[A-Z]+"], + "7": ["6", "BDATE", "[0-9]+"], + "8": ["1", "CTRL", "[0-9]", "7"], + "9": ["1", "SEX", "[A-Z]"], + "A": ["6", "EDATE", "[0-9]+"], + "B": ["1", "CTRL", "[0-9]", "A"], + "C": ["8", "FACULT", ".+"] + }, + "Titre de séjour" ] I__ = [ @@ -732,7 +751,7 @@ DL = [ ] #TYPES = [ID, I__, VB, VA, AC, I_, IP, P, DL] -TYPES = [IDFR, I__, VB, AC, I_, IP, P, DL] +TYPES = [IDFR, I__, VA, AC, I_, IP, P, DL, TSF] # longest document MRZ line longest = max([len(x[0][0]) for x in TYPES]) @@ -745,7 +764,6 @@ def limits(line, fieldtype): b = line.rfind(fieldtype) return (a,b+1) - def docMatch(doc, strs): # Global handler logfile = logger.logCur @@ -782,8 +800,8 @@ def docMatch(doc, strs): # Print for debug - #print("Field : {}, type = {}, on str : {}".format(field, fieldtype, fstr)) - #logfile.printdbg(" REGEX : {}, match : {}".format(regex, matching)) + # print("Field : {}, type = {}, on str : {}".format(field, fieldtype, fstr)) + # logfile.printdbg(" REGEX : {}, match : {}".format(regex, matching)) # exit the loop logfile.printdbg("{} level : {}/{} (+{})".format(doc[2], level, nchar, bonus)) @@ -793,7 +811,7 @@ def allDocMatch(strs, final=False): # Global handler logfile = logger.logCur - print(strs) + #print(strs) SCORES = [] for doc in TYPES: @@ -815,11 +833,11 @@ def allDocMatch(strs, final=False): candidates += [TYPES[i]] canditxt += [TYPES[i][2]] # Return the candidates - logfile.printdbg("Scores : {}".format(SCORES)) - logfile.printdbg("Candidates : {}".format(canditxt)) + #logfile.printdbg("Scores : {}".format(SCORES)) + #logfile.printdbg("Candidates : {}".format(canditxt)) return candidates -def MRZ(code): +def computeControlSum(code): """ This function computes a control sum for the given characters """