2019-07-09 23:01:09 +02:00
"""
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* CNIRevelator *
* *
* Desc : Application IHM & work main class *
* *
* Copyright © 2018 - 2019 Adrien Bourmault ( neox95 ) *
* *
* This file is part of CNIRevelator . *
* *
* CNIRevelator is free software : you can redistribute it and / or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation , either version 3 of the License , or *
* any later version . *
* *
* CNIRevelator is distributed in the hope that it will be useful , *
* but WITHOUT ANY WARRANTY * without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the *
* GNU General Public License for more details . *
* *
* You should have received a copy of the GNU General Public License *
* along with CNIRevelator . If not , see < https : * www . gnu . org / licenses / > . *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
"""
from PIL import Image , ImageFont , ImageDraw , ImageTk , ImageEnhance , ImageFilter
import math , warnings , string
2019-07-11 11:16:41 +02:00
from tkinter import *
from tkinter . messagebox import *
from tkinter import filedialog
from tkinter import ttk
2019-07-12 16:12:44 +02:00
import threading
from datetime import datetime
2019-07-17 17:12:21 +02:00
import re
2019-07-09 23:01:09 +02:00
2019-07-19 17:17:30 +02:00
import ihm # ihm.py
2019-07-12 16:12:44 +02:00
import logger # logger.py
2019-07-09 23:01:09 +02:00
import mrz # mrz.py
2019-07-12 10:57:03 +02:00
import globs # globs.py
2019-07-12 16:12:44 +02:00
import pytesseract # pytesseract.py
from image import * # image.py
# Global handler
logfile = logger . logCur
2019-07-09 23:01:09 +02:00
class mainWindow ( Tk ) :
2019-07-12 16:12:44 +02:00
def __init__ ( self ) :
2019-07-09 23:01:09 +02:00
Tk . __init__ ( self )
2019-07-12 16:12:44 +02:00
self . initialize ( )
2019-07-09 23:01:09 +02:00
2019-07-12 16:12:44 +02:00
def initialize ( self ) :
2019-07-18 15:37:58 +02:00
self . mrzChar = ' '
self . mrzDecided = False
2019-07-19 17:17:30 +02:00
self . Tags = [ ]
2019-08-01 16:52:36 +02:00
self . compliance = True
2019-07-09 23:01:09 +02:00
2019-07-12 16:12:44 +02:00
# Get the screen size
2019-07-09 23:01:09 +02:00
ws = self . winfo_screenwidth ( )
hs = self . winfo_screenheight ( )
2019-07-31 17:08:15 +02:00
logfile . printdbg ( ' Launching main window with resolution ' + str ( ws ) + ' x ' + str ( hs ) )
2019-07-09 23:01:09 +02:00
self . grid ( )
2019-07-12 16:12:44 +02:00
# Configuring the size of each part of the window
2019-07-09 23:01:09 +02:00
self . grid_columnconfigure ( 0 , weight = 1 , minsize = ( ws / 2 * 0.3333333333333333 ) )
self . grid_columnconfigure ( 1 , weight = 1 , minsize = ( ws / 2 * 0.3333333333333333 ) )
self . grid_columnconfigure ( 2 , weight = 1 , minsize = ( ws / 2 * 0.3333333333333333 ) )
self . grid_rowconfigure ( 0 , weight = 1 , minsize = ( hs / 2 * 0.5 ) )
2019-07-31 17:08:15 +02:00
self . grid_rowconfigure ( 1 , weight = 1 , minsize = ( hs / 2 * 0.10 ) )
self . grid_rowconfigure ( 2 , weight = 1 , minsize = ( hs / 2 * 0.35 ) )
2019-07-12 16:12:44 +02:00
# Prepare the data sections
2019-07-09 23:01:09 +02:00
self . lecteur_ci = ttk . Labelframe ( self , text = " Informations sur la pièce d ' identité " )
self . lecteur_ci . grid_columnconfigure ( 0 , weight = 1 )
self . lecteur_ci . grid_columnconfigure ( 1 , weight = 1 )
self . lecteur_ci . grid_columnconfigure ( 2 , weight = 1 )
self . lecteur_ci . grid_columnconfigure ( 3 , weight = 1 )
self . lecteur_ci . grid_columnconfigure ( 4 , weight = 1 )
self . lecteur_ci . grid_columnconfigure ( 5 , weight = 1 )
self . lecteur_ci . grid_rowconfigure ( 1 , weight = 1 )
self . lecteur_ci . grid_rowconfigure ( 2 , weight = 1 )
self . lecteur_ci . grid_rowconfigure ( 3 , weight = 1 )
self . lecteur_ci . grid_rowconfigure ( 4 , weight = 1 )
self . lecteur_ci . grid_rowconfigure ( 5 , weight = 1 )
2019-07-12 16:12:44 +02:00
# Fill the data sections
2019-07-09 23:01:09 +02:00
ttk . Label ( ( self . lecteur_ci ) , text = ' Nom : ' ) . grid ( column = 0 , row = 1 , padx = 5 , pady = 5 )
self . nom = ttk . Label ( ( self . lecteur_ci ) , text = ' ' )
self . nom . grid ( column = 1 , row = 1 , padx = 5 , pady = 5 )
ttk . Label ( ( self . lecteur_ci ) , text = ' Nom (2) : ' ) . grid ( column = 0 , row = 2 , padx = 5 , pady = 5 )
self . prenom = ttk . Label ( ( self . lecteur_ci ) , text = ' ' )
self . prenom . grid ( column = 1 , row = 2 , padx = 5 , pady = 5 )
ttk . Label ( ( self . lecteur_ci ) , text = ' Date de naissance : ' ) . grid ( column = 0 , row = 3 , padx = 5 , pady = 5 )
self . bdate = ttk . Label ( ( self . lecteur_ci ) , text = ' ' )
self . bdate . grid ( column = 1 , row = 3 , padx = 5 , pady = 5 )
ttk . Label ( ( self . lecteur_ci ) , text = ' Date de délivrance : ' ) . grid ( column = 0 , row = 4 , padx = 5 , pady = 5 )
self . ddate = ttk . Label ( ( self . lecteur_ci ) , text = ' ' )
self . ddate . grid ( column = 1 , row = 4 , padx = 5 , pady = 5 )
ttk . Label ( ( self . lecteur_ci ) , text = " Date d ' expiration : " ) . grid ( column = 0 , row = 5 , padx = 5 , pady = 5 )
self . edate = ttk . Label ( ( self . lecteur_ci ) , text = ' ' )
self . edate . grid ( column = 1 , row = 5 , padx = 5 , pady = 5 )
ttk . Label ( ( self . lecteur_ci ) , text = ' Sexe du porteur : ' ) . grid ( column = 4 , row = 1 , padx = 5 , pady = 5 )
self . sex = ttk . Label ( ( self . lecteur_ci ) , text = ' ' )
self . sex . grid ( column = 5 , row = 1 , padx = 5 , pady = 5 )
ttk . Label ( ( self . lecteur_ci ) , text = ' Pays de délivrance : ' ) . grid ( column = 4 , row = 2 , padx = 5 , pady = 5 )
self . pays = ttk . Label ( ( self . lecteur_ci ) , text = ' ' )
self . pays . grid ( column = 5 , row = 2 , padx = 5 , pady = 5 )
ttk . Label ( ( self . lecteur_ci ) , text = ' Nationalité du porteur : ' ) . grid ( column = 4 , row = 3 , padx = 5 , pady = 5 )
self . nat = ttk . Label ( ( self . lecteur_ci ) , text = ' ' )
self . nat . grid ( column = 5 , row = 3 , padx = 5 , pady = 5 )
ttk . Label ( ( self . lecteur_ci ) , text = ' Immatriculation : ' ) . grid ( column = 4 , row = 4 , padx = 5 , pady = 5 )
self . indic = ttk . Label ( ( self . lecteur_ci ) , text = ' ' )
self . indic . grid ( column = 5 , row = 4 , padx = 5 , pady = 5 )
ttk . Label ( ( self . lecteur_ci ) , text = ' Numéro de document : ' ) . grid ( column = 4 , row = 5 , padx = 5 , pady = 5 )
self . no = ttk . Label ( ( self . lecteur_ci ) , text = ' ' )
self . no . grid ( column = 5 , row = 5 , padx = 5 , pady = 5 )
2019-07-12 16:12:44 +02:00
2019-07-09 23:01:09 +02:00
self . nom [ ' text ' ] = ' Inconnu(e) '
self . prenom [ ' text ' ] = ' Inconnu(e) '
self . bdate [ ' text ' ] = ' Inconnu(e) '
self . ddate [ ' text ' ] = ' Inconnu(e) '
self . edate [ ' text ' ] = ' Inconnu(e) '
self . no [ ' text ' ] = ' Inconnu(e) '
self . sex [ ' text ' ] = ' Inconnu(e) '
self . nat [ ' text ' ] = ' Inconnu(e) '
self . pays [ ' text ' ] = ' Inconnu(e) '
self . indic [ ' text ' ] = ' Inconnu(e) '
2019-07-12 16:12:44 +02:00
2019-08-01 16:52:36 +02:00
self . infoList = \
{
" NOM " : self . nom ,
" PRENOM " : self . prenom ,
" BDATE " : self . bdate ,
" DDATE " : self . ddate ,
" EDATE " : self . edate ,
" NO " : self . no ,
" SEX " : self . sex ,
" NAT " : self . nat ,
" PAYS " : self . pays ,
" INDIC " : self . indic ,
}
2019-07-12 16:12:44 +02:00
# The STATUS indicator
2019-07-09 23:01:09 +02:00
self . STATUT = ttk . Labelframe ( self , text = ' Statut ' )
self . STATUT . grid_columnconfigure ( 0 , weight = 1 )
self . STATUT . grid_rowconfigure ( 0 , weight = 1 )
self . STATUStxt = Label ( ( self . STATUT ) , text = ' ' , font = ' Times 24 ' , fg = ' #FFBF00 ' )
self . STATUStxt . grid ( column = 0 , row = 0 , padx = 0 , pady = 0 , sticky = ' EWNS ' )
self . STATUStxt [ ' text ' ] = ' EN ATTENTE '
2019-07-12 16:12:44 +02:00
# The terminal to enter the MRZ
2019-07-31 17:08:15 +02:00
self . terminal = ttk . Labelframe ( self , text = ' Terminal de saisie de MRZ complète ' )
2019-07-09 23:01:09 +02:00
self . terminal . grid_columnconfigure ( 0 , weight = 1 )
self . terminal . grid_rowconfigure ( 0 , weight = 1 )
self . termframe = Frame ( self . terminal )
self . termframe . grid ( column = 0 , row = 0 , sticky = ' EW ' )
self . termframe . grid_columnconfigure ( 0 , weight = 1 )
self . termframe . grid_rowconfigure ( 0 , weight = 1 )
2019-07-31 17:08:15 +02:00
self . termguide = Label ( ( self . termframe ) , text = ' ' , font = ' Terminal 17 ' , fg = ' #006699 ' )
self . termguide . grid ( column = 0 , row = 0 , padx = 5 , pady = 0 , sticky = ' NW ' )
self . termguide [ ' text ' ] = ' 0 |5 |10 |15 |20 |25 |30 |35 |40 |45 '
2019-07-17 17:12:21 +02:00
self . termtext = Text ( ( self . termframe ) , state = ' normal ' , width = 60 , height = 4 , wrap = ' none ' , font = ' Terminal 17 ' , fg = ' #121f38 ' )
2019-07-31 17:08:15 +02:00
self . termtext . grid ( column = 0 , row = 0 , sticky = ' SW ' , padx = 5 , pady = 25 )
# Speed Entry Zone for 731
self . terminal2 = ttk . Labelframe ( self , text = ' Terminal de saisie rapide (731) ' )
self . terminal2 . grid_columnconfigure ( 0 , weight = 1 )
self . terminal2 . grid_rowconfigure ( 0 , weight = 1 )
self . speed731 = Frame ( self . terminal2 )
self . speed731 . grid ( column = 0 , row = 0 , sticky = ' EW ' )
self . speed731 . grid_columnconfigure ( 0 , weight = 1 )
self . speed731 . grid_columnconfigure ( 1 , weight = 1 )
self . speed731 . grid_columnconfigure ( 2 , weight = 1 )
self . speed731 . grid_columnconfigure ( 3 , weight = 1 )
self . speed731 . grid_columnconfigure ( 4 , weight = 1 )
self . speed731 . grid_columnconfigure ( 5 , weight = 1 )
self . speed731 . grid_columnconfigure ( 6 , weight = 1 )
self . speed731 . grid_columnconfigure ( 7 , weight = 1 )
self . speed731 . grid_columnconfigure ( 8 , weight = 1 )
self . speed731 . grid_columnconfigure ( 9 , weight = 1 )
self . speed731 . grid_rowconfigure ( 0 , weight = 1 )
self . speed731text = Entry ( self . speed731 , font = ' Terminal 14 ' )
self . speed731text . grid ( column = 0 , row = 0 , sticky = ' NEW ' , padx = 5 )
self . speedResult = Text ( ( self . speed731 ) , state = ' disabled ' , width = 1 , height = 1 , wrap = ' none ' , font = ' Terminal 14 ' )
self . speedResult . grid ( column = 2 , row = 0 , sticky = ' NEW ' )
2019-07-12 16:12:44 +02:00
# The monitor that indicates some useful infos
2019-07-09 23:01:09 +02:00
self . monitor = ttk . Labelframe ( self , text = ' Moniteur ' )
self . monlog = Text ( ( self . monitor ) , state = ' disabled ' , width = 60 , height = 10 , wrap = ' word ' )
self . monlog . grid ( column = 0 , row = 0 , sticky = ' EWNS ' , padx = 5 , pady = 5 )
self . scrollb = ttk . Scrollbar ( ( self . monitor ) , command = ( self . monlog . yview ) )
self . scrollb . grid ( column = 1 , row = 0 , sticky = ' EWNS ' , padx = 5 , pady = 5 )
self . monlog [ ' yscrollcommand ' ] = self . scrollb . set
self . monitor . grid_columnconfigure ( 0 , weight = 1 )
self . monitor . grid_rowconfigure ( 0 , weight = 1 )
2019-07-12 16:12:44 +02:00
# All the items griding
2019-07-09 23:01:09 +02:00
self . lecteur_ci . grid ( column = 0 , row = 0 , sticky = ' EWNS ' , columnspan = 2 , padx = 5 , pady = 5 )
self . STATUT . grid ( column = 2 , row = 0 , sticky = ' EWNS ' , columnspan = 1 , padx = 5 , pady = 5 )
2019-07-31 17:08:15 +02:00
self . terminal . grid ( column = 0 , row = 2 , sticky = ' EWNS ' , columnspan = 2 , padx = 5 , pady = 5 )
self . terminal2 . grid ( column = 0 , row = 1 , sticky = ' EWNS ' , columnspan = 2 , padx = 5 , pady = 5 )
self . monitor . grid ( column = 2 , row = 1 , sticky = ' EWNS ' , columnspan = 1 , rowspan = 2 , padx = 5 , pady = 5 )
2019-07-12 16:12:44 +02:00
self . update ( )
# What is a window without a menu bar ?
2019-07-09 23:01:09 +02:00
menubar = Menu ( self )
menu1 = Menu ( menubar , tearoff = 0 )
menu1 . add_command ( label = ' Nouveau ' , command = ( self . newEntry ) )
menu1 . add_command ( label = ' Ouvrir scan... ' , command = ( self . openingScan ) )
menu1 . add_separator ( )
menu1 . add_command ( label = ' Quitter ' , command = ( self . destroy ) )
menubar . add_cascade ( label = ' Fichier ' , menu = menu1 )
menu3 = Menu ( menubar , tearoff = 0 )
2019-07-31 17:08:15 +02:00
menu3 . add_command ( label = ' Commandes au clavier ' , command = ( self . helpbox ) )
menu3 . add_command ( label = ' A propos de CNIRevelator ' , command = ( self . infobox ) )
2019-07-09 23:01:09 +02:00
menubar . add_cascade ( label = ' Aide ' , menu = menu3 )
self . config ( menu = menubar )
2019-07-12 16:12:44 +02:00
# The title
2019-07-12 10:57:03 +02:00
self . wm_title ( globs . CNIRName )
2019-07-12 16:12:44 +02:00
# The icon
2019-07-09 23:01:09 +02:00
if getattr ( sys , ' frozen ' , False ) :
self . iconbitmap ( sys . _MEIPASS + ' \\ id-card.ico \\ id-card.ico ' )
else :
self . iconbitmap ( ' id-card.ico ' )
2019-07-12 16:12:44 +02:00
# Make this window resizable and set her size
2019-07-09 23:01:09 +02:00
self . resizable ( width = True , height = True )
self . minsize ( self . winfo_width ( ) , self . winfo_height ( ) )
w = int ( self . winfo_width ( ) )
h = int ( self . winfo_height ( ) )
ws = self . winfo_screenwidth ( )
hs = self . winfo_screenheight ( )
x = ws / 2 - w / 2
y = hs / 2 - h / 2
self . geometry ( ' %d x %d + %d + %d ' % ( w , h , x , y ) )
2019-07-12 16:12:44 +02:00
# Some bindings
2019-07-17 17:12:21 +02:00
self . termtext . bind ( ' <Key> ' , self . entryValidation )
2019-07-18 15:37:58 +02:00
self . termtext . bind ( ' <<Paste>> ' , self . pasteValidation )
2019-08-01 16:52:36 +02:00
self . speed731text . bind ( ' <Control_R> ' , self . speedValidation )
2019-07-09 23:01:09 +02:00
self . update ( )
2019-07-17 17:12:21 +02:00
logfile . printdbg ( ' Initialization successful ' )
2019-07-09 23:01:09 +02:00
2019-08-01 16:52:36 +02:00
def stringValidation ( self , char ) :
2019-07-19 17:17:30 +02:00
# 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 )
2019-08-01 16:52:36 +02:00
self . logOnTerm ( " Document detecté : {} \n " . format ( candidates [ invite . choice ] [ 2 ] ) )
2019-07-19 17:17:30 +02:00
self . mrzDecided = candidates [ invite . choice ]
elif len ( candidates ) == 1 :
2019-08-01 16:52:36 +02:00
self . logOnTerm ( " Document detecté : {} \n " . format ( candidates [ 0 ] [ 2 ] ) )
2019-07-19 17:17:30 +02:00
self . mrzDecided = candidates [ 0 ]
else :
2019-08-05 15:52:02 +02:00
# get the cursor position
curPos = self . termtext . index ( INSERT )
2019-07-19 17:17:30 +02:00
# break the line
2019-07-31 17:08:15 +02:00
if ( len ( self . mrzChar ) - 2 > = len ( self . mrzDecided [ 0 ] [ 0 ] ) ) and ( " \n " not in self . mrzChar [ : - 1 ] ) :
# In case of there is no second line
if len ( self . mrzDecided [ 0 ] [ 1 ] ) == 0 :
2019-08-01 16:52:36 +02:00
self . mrzChar = self . termtext . get ( " 1.0 " , " end " ) [ : - 1 ]
2019-07-31 17:08:15 +02:00
self . termtext . delete ( " 1.0 " , " end " )
2019-08-01 16:52:36 +02:00
self . termtext . insert ( " 1.0 " , self . mrzChar [ : - 1 ] )
2019-08-05 15:52:02 +02:00
self . termtext . mark_set ( INSERT , curPos )
2019-07-31 17:08:15 +02:00
else :
# In case of there is a second line
self . mrzChar = self . termtext . get ( " 1.0 " , " end " ) [ : - 1 ] + ' \n '
self . termtext . delete ( " 1.0 " , " end " )
self . termtext . insert ( " 1.0 " , self . mrzChar )
# stop when limit reached
elif ( len ( self . mrzChar ) - 3 > = 2 * len ( self . mrzDecided [ 0 ] [ 0 ] ) ) :
2019-08-01 16:52:36 +02:00
self . mrzChar = self . termtext . get ( " 1.0 " , " end " ) [ : - 1 ]
2019-07-19 17:17:30 +02:00
self . termtext . delete ( " 1.0 " , " end " )
2019-08-01 16:52:36 +02:00
self . termtext . insert ( " 1.0 " , self . mrzChar [ : - 1 ] )
2019-08-05 15:52:02 +02:00
self . termtext . mark_set ( INSERT , curPos )
2019-07-31 17:08:15 +02:00
# compute the control sum if needed
self . computeSigma ( )
2019-07-17 17:12:21 +02:00
def entryValidation ( self , event ) :
"""
On the fly validation with regex
"""
2019-07-18 15:37:58 +02:00
controlled = False
2019-07-09 23:01:09 +02:00
2019-08-01 16:52:36 +02:00
# get the cursor
if self . mrzDecided :
position = self . termtext . index ( INSERT ) . split ( " . " )
pos = ( int ( position [ 0 ] ) - 1 ) * len ( self . mrzDecided [ 0 ] [ 0 ] ) + ( int ( position [ 1 ] ) - 1 )
else :
position = self . termtext . index ( INSERT ) . split ( " . " )
pos = ( int ( position [ 1 ] ) - 1 )
2019-07-18 15:37:58 +02:00
# verifying that there is no Ctrl-C/Ctrl-V and others
if event . state & 0x0004 and ( event . keysym == " c " or
event . keysym == " v " or
event . keysym == " a " or
event . keysym == " z " or
event . keysym == " y " ) :
controlled = True
2019-07-12 16:12:44 +02:00
2019-07-31 17:08:15 +02:00
if event . keysym == " Tab " :
if self . mrzDecided :
controlled = True
self . mrzChar = self . termtext . get ( " 1.0 " , " end " ) [ : - 1 ]
# the regex
regex = re . compile ( " [^A-Z0-9<] " )
code = re . sub ( regex , ' ' , self . mrzChar )
number = mrz . completeDocField ( self . mrzDecided , code , pos ) - 1
if number == 0 :
return " break "
self . mrzChar = self . termtext . get ( " 1.0 " , " end " ) [ : - 1 ] + " < " * number
self . termtext . delete ( " 1.0 " , " end " )
self . termtext . insert ( " 1.0 " , self . mrzChar )
self . termtext . mark_set ( " insert " , " %d . %d " % ( int ( position [ 0 ] ) , int ( position [ 1 ] ) + number ) )
return " break "
2019-08-05 15:52:02 +02:00
if event . keysym == " Escape " :
if 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 re-detecté : {} \n " . format ( candidates [ invite . choice ] [ 2 ] ) )
self . mrzDecided = candidates [ invite . choice ]
elif len ( candidates ) == 1 :
self . logOnTerm ( " Document re-detecté : {} \n " . format ( candidates [ 0 ] [ 2 ] ) )
self . mrzDecided = candidates [ 0 ]
return " break "
2019-07-31 17:08:15 +02:00
2019-07-18 15:37:58 +02:00
# If not a control char
2019-07-19 17:17:30 +02:00
if not controlled and not event . keysym in ihm . controlKeys :
2019-07-18 15:37:58 +02:00
# the regex
regex = re . compile ( " [A-Z]|<|[0-9] " )
# match !
if not regex . fullmatch ( event . char ) :
self . logOnTerm ( " Caractère non accepté ! \n " )
return " break "
2019-08-01 16:52:36 +02:00
# Adds the entry
tempChar = self . termtext . get ( " 1.0 " , " end " ) [ : - 1 ]
self . mrzChar = tempChar [ : pos + 1 ] + event . char + tempChar [ pos + 1 : ] + ' \n '
2019-07-18 15:37:58 +02:00
2019-07-31 17:08:15 +02:00
# validation of the mrz string
2019-08-01 16:52:36 +02:00
self . stringValidation ( event . char )
2019-07-18 15:37:58 +02:00
def pasteValidation ( self , event ) :
"""
On the fly validation of pasted text
"""
# cleanup
self . termtext . delete ( " 1.0 " , " end " )
# get the clipboard content
lines = self . clipboard_get ( )
2019-07-19 17:17:30 +02:00
self . mrzChar = " "
2019-07-18 15:37:58 +02:00
# the regex
regex = re . compile ( " [^A-Z0-9<] " )
lines = re . sub ( regex , ' ' , lines )
2019-07-19 17:17:30 +02:00
# Get that
for char in lines :
self . termtext . insert ( " 1.0 " , self . mrzChar )
self . mrzChar = self . mrzChar + char
2019-08-01 16:52:36 +02:00
self . stringValidation ( " " )
2019-07-19 17:17:30 +02:00
2019-07-18 15:37:58 +02:00
return " break "
2019-07-17 17:12:21 +02:00
2019-07-31 17:08:15 +02:00
def speedValidation ( self , event ) :
"""
Computation of the speed entry
"""
char = self . speed731text . get ( )
self . speedResultPrint ( str ( mrz . computeControlSum ( char ) ) )
return " break "
2019-07-09 23:01:09 +02:00
def logOnTerm ( self , text ) :
self . monlog [ ' state ' ] = ' normal '
self . monlog . insert ( ' end ' , text )
self . monlog [ ' state ' ] = ' disabled '
self . monlog . yview ( END )
2019-08-01 16:52:36 +02:00
def clearTerm ( self ) :
self . monlog [ ' state ' ] = ' normal '
self . monlog . delete ( ' 1.0 ' , ' end ' )
self . monlog [ ' state ' ] = ' disabled '
self . monlog . yview ( END )
2019-07-31 17:08:15 +02:00
def speedResultPrint ( self , text ) :
self . speedResult [ ' state ' ] = ' normal '
self . speedResult . delete ( " 1.0 " , ' end ' )
self . speedResult . insert ( ' end ' , text )
self . speedResult [ ' state ' ] = ' disabled '
2019-07-09 23:01:09 +02:00
def openingScan ( self ) :
2019-07-17 17:12:21 +02:00
pass
2019-07-12 16:12:44 +02:00
# OPEN A SCAN
2019-07-09 23:01:09 +02:00
def newEntry ( self ) :
2019-07-12 16:12:44 +02:00
self . initialize ( )
2019-07-09 23:01:09 +02:00
self . logOnTerm ( ' \n \n Entrez la première ligne de MRZ svp \n ' )
def infobox ( self ) :
Tk ( ) . withdraw ( )
2019-07-12 16:12:44 +02:00
2019-07-31 17:08:15 +02:00
showinfo ( ' A propos de CNIRevelator ' ,
2019-07-12 16:12:44 +02:00
( ' Version du logiciel : CNIRevelator ' + globs . verstring_full + ' \n \n ' +
2019-07-31 17:08:15 +02:00
" CNIRevelator est un logiciel libre : vous avez le droit de le modifier et/ou le distribuer " +
" dans les termes de la GNU General Public License telle que publiée par " +
" la Free Software Foundation, dans sa version 3 ou " +
" ultérieure. " + " \n \n " +
" CNIRevelator est distribué dans l ' espoir d ' être utile, sans toutefois " +
" impliquer une quelconque garantie de " +
" QUALITÉ MARCHANDE ou APTITUDE À UN USAGE PARTICULIER. Référez vous à la " +
" GNU General Public License pour plus de détails à ce sujet. " +
2019-07-12 16:12:44 +02:00
" \n \n " +
2019-07-31 17:08:15 +02:00
" Vous devriez avoir reçu une copie de la GNU General Public License " +
" avec CNIRevelator. Si cela n ' est pas le cas, jetez un oeil à ' <https://www.gnu.org/licenses/>. " +
2019-07-12 16:12:44 +02:00
" \n \n " +
2019-07-31 17:08:15 +02:00
" Le module d ' OCR Tesseract 4.0 est soumis à l ' Apache License 2004 " +
2019-07-12 16:12:44 +02:00
" \n \n " +
2019-07-31 17:08:15 +02:00
" Les bibliothèques python et l ' environnement Anaconda 3 sont soumis à la licence BSD 2018-2019 " +
2019-07-12 16:12:44 +02:00
" \n \n " +
2019-07-31 17:08:15 +02:00
" Le code source de ce programme est disponible sur Github à l ' adresse <https://github.com/neox95/CNIRevelator>. \n " +
" En cas de problèmes ou demande particulière, ouvrez-y une issue ou bien envoyez un mail à neox@os-k.eu ! "
2019-07-12 16:12:44 +02:00
) ,
parent = self )
2019-07-09 23:01:09 +02:00
2019-07-31 17:08:15 +02:00
def helpbox ( self ) :
Tk ( ) . withdraw ( )
showinfo ( ' Aide sur les contrôles au clavier ' ,
2019-08-05 15:52:02 +02:00
( " Terminal de saisie rapide (731) : \n \n "
" Caractères autorisés : Alphanumériques en majuscule et le caractère ' < ' . Pas de minuscules ni caractères spéciaux, autrement la somme est mise à zéro \n \n "
" Calculer résultat : \t \t \t Touche Ctrl droite \n "
" Copier : \t \t \t \t Ctrl-C \n "
" Coller : \t \t \t \t Ctrl-V \n "
" \n \n "
" Terminal de saisie MRZ complète : \n \n "
" Caractères autorisés : Alphanumériques en majuscule et le caractère ' < ' . Pas de minuscules ni caractères spéciaux, autrement la somme est mise à zéro \n \n "
" Calculer résultat : \t \t \t Touche Ctrl droite \n "
" Compléter champ : \t \t \t Touche Tab \n "
" Copier : \t \t \t \t Ctrl-C \n "
" Coller : \t \t \t \t Ctrl-V \n "
" Forcer une nouvelle détection du document : \t Echap \n "
2019-07-31 17:08:15 +02:00
) ,
parent = self )
def computeSigma ( self ) :
2019-08-01 16:52:36 +02:00
"""
Launch the checksum computation , infos validation and display the results
"""
2019-07-31 17:08:15 +02:00
# the regex
regex = re . compile ( " [^A-Z0-9<] " )
code = re . sub ( regex , ' ' , self . mrzChar )
2019-08-01 16:52:36 +02:00
self . compliance = True
2019-07-31 17:08:15 +02:00
2019-08-01 16:52:36 +02:00
allSums = mrz . computeAllControlSum ( self . mrzDecided , code ) [ " ctrlSumList " ]
#print("Code : _{}_ | Sums : {}".format(code, allSums))
2019-07-31 17:08:15 +02:00
2019-08-01 16:52:36 +02:00
self . termtext . tag_remove ( " conforme " , " 1.0 " , " end " )
self . termtext . tag_remove ( " nonconforme " , " 1.0 " , " end " )
2019-07-31 17:08:15 +02:00
2019-08-01 16:52:36 +02:00
self . clearTerm ( )
self . logOnTerm ( " Examen du document : {} \n \n " . format ( self . mrzDecided [ 2 ] ) )
2019-07-31 17:08:15 +02:00
2019-08-01 16:52:36 +02:00
for sum in allSums :
x = sum [ 1 ] / / len ( self . mrzDecided [ 0 ] [ 0 ] ) + 1
y = sum [ 1 ] % len ( self . mrzDecided [ 0 ] [ 0 ] )
#print("index : {}.{}".format(x,y))
#print("{} == {}".format(code[sum[1]], sum[2]))
2019-07-31 17:08:15 +02:00
2019-08-01 16:52:36 +02:00
self . logOnTerm ( " Somme de contrôle position {} : Lu {} VS Calculé {} \n " . format ( sum [ 1 ] , code [ sum [ 1 ] ] , sum [ 2 ] ) )
2019-07-31 17:08:15 +02:00
2019-08-01 16:52:36 +02:00
# if sum is facultative or if sum is ok
2019-08-05 15:52:02 +02:00
try :
if sum [ 3 ] or int ( code [ sum [ 1 ] ] ) == int ( sum [ 2 ] ) :
self . termtext . tag_add ( " conforme " , " {} . {} " . format ( x , y ) , " {} . {} " . format ( x , y + 1 ) )
self . termtext . tag_configure ( " conforme " , background = " green " , foreground = " white " )
else :
self . termtext . tag_add ( " nonconforme " , " {} . {} " . format ( x , y ) , " {} . {} " . format ( x , y + 1 ) )
self . termtext . tag_configure ( " nonconforme " , background = " red " , relief = ' raised ' , foreground = " white " )
self . compliance = False
except ValueError :
2019-08-01 16:52:36 +02:00
self . termtext . tag_add ( " nonconforme " , " {} . {} " . format ( x , y ) , " {} . {} " . format ( x , y + 1 ) )
self . termtext . tag_configure ( " nonconforme " , background = " red " , relief = ' raised ' , foreground = " white " )
self . compliance = False
2019-07-31 17:08:15 +02:00
2019-08-01 16:52:36 +02:00
if self . compliance == True :
self . STATUStxt [ ' text ' ] = ' CONFORME '
self . STATUStxt [ ' fg ' ] = " green "
else :
self . STATUStxt [ ' text ' ] = ' NON CONFORME '
self . STATUStxt [ ' fg ' ] = " red "
# get the infos
docInfos = mrz . getDocInfos ( self . mrzDecided , code )
#print(docInfos)
# display the infos
for key in [ e for e in docInfos ] :
2019-08-02 10:28:14 +02:00
#print(docInfos[key])
2019-08-01 16:52:36 +02:00
if key in [ " CODE " , " CTRL " ] :
continue
if not docInfos [ key ] == False :
self . infoList [ key ] [ ' text ' ] = docInfos [ key ]
self . infoList [ key ] [ ' background ' ] = self [ ' background ' ]
self . infoList [ key ] [ ' foreground ' ] = " black "
else :
self . infoList [ key ] [ ' background ' ] = " red "
self . infoList [ key ] [ ' foreground ' ] = " white "
self . infoList [ key ] [ ' text ' ] = " NC "
return
2019-07-31 17:08:15 +02:00
2019-07-09 23:01:09 +02:00