2018-08-29 17:04:00 +02:00
"""
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* * * Projet CNI_Revelator * * *
GNU GPL * 07 / 2018
Adrien Bourmault
CLASSES
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
"""
2019-06-30 17:54:41 +02:00
from CNI_GLOBALVAR import *
from PIL import Image , ImageFont , ImageDraw , ImageTk , ImageEnhance , ImageFilter
import math , warnings , string
2018-08-29 17:04:00 +02:00
class App_main ( Tk ) :
2019-06-30 17:54:41 +02:00
2018-08-29 17:04:00 +02:00
def __init__ ( self , logger ) :
Tk . __init__ ( self )
self . initialize ( logger )
2019-06-30 17:54:41 +02:00
2018-08-29 17:04:00 +02:00
def initialize ( self , logger ) :
self . logger = logger
self . PILE_ETAT = [ ]
2019-06-30 17:54:41 +02:00
self . MRZCHAR = ' '
2018-08-29 17:04:00 +02:00
self . varnum = 10
self . Score = [ ]
for type in MRZCODE . TYPES :
self . Score + = [ 0 ]
2019-06-30 17:54:41 +02:00
2018-08-29 17:04:00 +02:00
ws = self . winfo_screenwidth ( )
hs = self . winfo_screenheight ( )
2019-06-30 17:54:41 +02:00
self . logger . info ( ' App_main() : Launching main window with resolution ' + str ( ws ) + ' x ' + str ( hs ) )
self . grid ( )
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 ) )
self . grid_rowconfigure ( 1 , weight = 1 , minsize = ( hs / 2 * 0.5 ) )
self . lecteur_ci = ttk . Labelframe ( self , text = " Informations sur la pièce d ' identité " )
2018-08-29 17:04:00 +02:00
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-06-30 17:54:41 +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 )
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) '
self . STATUT = ttk . Labelframe ( self , text = ' Statut ' )
2018-08-29 17:04:00 +02:00
self . STATUT . grid_columnconfigure ( 0 , weight = 1 )
self . STATUT . grid_rowconfigure ( 0 , weight = 1 )
2019-06-30 17:54:41 +02:00
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 '
self . terminal = ttk . Labelframe ( self , text = ' Terminal de saisie ' )
2018-08-29 17:04:00 +02:00
self . terminal . grid_columnconfigure ( 0 , weight = 1 )
self . terminal . grid_rowconfigure ( 0 , weight = 1 )
self . termframe = Frame ( self . terminal )
2019-06-30 17:54:41 +02:00
self . termframe . grid ( column = 0 , row = 0 , sticky = ' EW ' )
2018-08-29 17:04:00 +02:00
self . termframe . grid_columnconfigure ( 0 , weight = 1 )
self . termframe . grid_rowconfigure ( 0 , weight = 1 )
2019-06-30 17:54:41 +02:00
self . termtext = Text ( ( self . termframe ) , state = ' disabled ' , width = 60 , height = 4 , wrap = ' none ' , font = ' Terminal 17 ' , fg = ' #121f38 ' )
self . termtext . grid ( column = 0 , row = 0 , sticky = ' NEW ' , padx = 5 )
vcmd = ( self . register ( self . validate ) , ' % S ' , ' % P ' , ' %d ' )
self . termentry = Entry ( ( self . termframe ) , font = ' Terminal 17 ' , validate = ' all ' , validatecommand = vcmd , fg = ' #121f38 ' , width = 44 )
self . termentry . grid ( column = 0 , row = 0 , sticky = ' SEW ' , padx = 5 )
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
2018-08-29 17:04:00 +02:00
self . monitor . grid_columnconfigure ( 0 , weight = 1 )
self . monitor . grid_rowconfigure ( 0 , weight = 1 )
2019-06-30 17:54:41 +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 )
self . terminal . grid ( column = 0 , row = 1 , sticky = ' EWNS ' , columnspan = 2 , padx = 5 , pady = 5 )
self . monitor . grid ( column = 2 , row = 1 , sticky = ' EWNS ' , columnspan = 1 , padx = 5 , pady = 5 )
2018-08-29 17:04:00 +02:00
menubar = Menu ( self )
menu1 = Menu ( menubar , tearoff = 0 )
2019-06-30 17:54:41 +02:00
menu1 . add_command ( label = ' Nouveau ' , command = ( self . newbie ) )
menu1 . add_command ( label = ' Ouvrir scan... ' , command = ( self . openingscan ) )
2018-08-29 17:04:00 +02:00
menu1 . add_separator ( )
2019-06-30 17:54:41 +02:00
menu1 . add_command ( label = ' Quitter ' , command = ( self . destroy ) )
menubar . add_cascade ( label = ' Fichier ' , menu = menu1 )
2018-08-29 17:04:00 +02:00
menu3 = Menu ( menubar , tearoff = 0 )
2019-06-30 17:54:41 +02:00
menu3 . add_command ( label = ' A propos ' , command = ( self . infobox ) )
menubar . add_cascade ( label = ' Aide ' , menu = menu3 )
self . config ( menu = menubar )
2018-08-29 17:04:00 +02:00
self . wm_title ( CST_TITLE )
2019-06-30 17:54:41 +02:00
if getattr ( sys , ' frozen ' , False ) :
self . iconbitmap ( sys . _MEIPASS + ' \\ id-card.ico \\ id-card.ico ' )
2018-08-29 17:04:00 +02:00
else :
2019-06-30 17:54:41 +02:00
self . iconbitmap ( ' id-card.ico ' )
2018-08-29 17:04:00 +02:00
self . resizable ( width = True , height = True )
self . update ( )
self . minsize ( self . winfo_width ( ) , self . winfo_height ( ) )
2019-06-30 17:54:41 +02:00
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
2018-08-29 17:04:00 +02:00
self . geometry ( ' %d x %d + %d + %d ' % ( w , h , x , y ) )
2019-06-30 17:54:41 +02:00
self . termentry . bind ( ' <Return> ' , self . returnaj )
self . termtext . bind ( ' <Return> ' , self . returnaj )
self . termentry . bind ( ' <Escape> ' , self . tabaj )
self . update ( )
self . logger . info ( ' App_main() : Initialization successful ' )
2018-08-29 17:04:00 +02:00
def returnaj ( self , event ) :
2019-06-30 17:54:41 +02:00
self . logger . debug ( ' returnaj() : Entering Validation ' )
if self . PILE_ETAT != [ ] and len ( self . PILE_ETAT ) == 1 :
2018-08-29 17:04:00 +02:00
thetext = self . termentry . get ( )
2019-06-30 17:54:41 +02:00
self . logger . debug ( ' returnaj() : PILE_ETAT Satisfy the requisites : ' + str ( self . PILE_ETAT ) )
2018-08-29 17:04:00 +02:00
n = len ( thetext )
champ = MRZCODE . TYPES [ self . PILE_ETAT [ 0 ] ] [ 0 ]
2019-06-30 17:54:41 +02:00
if not n % champ . find ( ' | ' ) == 0 :
self . logger . debug ( ' returnaj() : Line not complete, operation aborted ' )
return ' break '
2018-08-29 17:04:00 +02:00
self . MRZCHAR + = thetext
2019-06-30 17:54:41 +02:00
self . termtext [ ' state ' ] = ' normal '
self . termtext . insert ( ' end ' , thetext + ' \n ' )
self . termtext [ ' state ' ] = ' disabled '
self . termentry . delete ( 0 , ' end ' )
if len ( self . MRZCHAR ) == champ . find ( ' | ' ) :
self . montext ( ' Entrez la seconde ligne de la MRZ ou \n appuyez sur Entrée pour terminer. \n ' )
self . logger . debug ( ' returnaj() : First line accepted ' )
self . MRZCHAR + = ' | '
else :
if len ( self . MRZCHAR ) == champ . find ( ' | ' ) * 2 + 1 or len ( champ ) == champ . find ( ' | ' ) + 1 :
self . montext ( ' \n Calcul des sommes ... \n ' )
self . logger . info ( ' returnaj() : Launching calculsigma() thread ' )
threading . Thread ( target = ( self . calculsigma ) , args = [ self . MRZCHAR , self . PILE_ETAT [ 0 ] ] ) . start ( )
else :
if self . PILE_ETAT != [ ] :
if len ( self . PILE_ETAT ) == 2 :
self . MRZCHAR = self . termtext . get ( ' 1.0 ' , ' end ' ) . replace ( ' \n ' , ' | ' )
temp = self . termtext . get ( ' 1.0 ' , ' end ' )
self . termtext . delete ( ' 1.0 ' , ' end ' )
self . termtext . insert ( ' 1.0 ' , temp )
self . logger . debug ( ' returnaj() : PILE_ETAT Satisfy the requisites : ' + str ( self . PILE_ETAT ) )
n = len ( self . MRZCHAR )
champ = MRZCODE . TYPES [ self . PILE_ETAT [ 1 ] ] [ 0 ]
for char in self . MRZCHAR :
if char not in ' ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789<| ' :
self . montext ( ' \n Syntaxe erronée, caractère incompatible ' )
return ' break '
if self . MRZCHAR [ ( - 1 ) ] == ' | ' :
self . MRZCHAR = self . MRZCHAR [ : - 1 ]
if len ( self . MRZCHAR ) == champ . find ( ' | ' ) * 2 + 1 or len ( champ ) == champ . find ( ' | ' ) + 1 :
self . logger . debug ( ' returnaj() : : ' + str ( self . PILE_ETAT ) )
self . montext ( ' \n Calcul des sommes ... \n ' )
self . logger . info ( ' returnaj() : Launching calculsigma() thread ' )
threading . Thread ( target = ( self . calculsigma ) , args = [ self . MRZCHAR , self . PILE_ETAT [ 1 ] ] ) . start ( )
return ' break '
def tabaj ( self , event ) :
if self . PILE_ETAT != [ ] and len ( self . PILE_ETAT ) == 1 :
2018-08-29 17:04:00 +02:00
thetext = self . termentry . get ( )
n = len ( thetext )
champ = MRZCODE . TYPES [ self . PILE_ETAT [ 0 ] ] [ 0 ]
2019-06-30 17:54:41 +02:00
if len ( self . MRZCHAR ) < = champ . find ( ' | ' ) :
champ_type = MRZCODE . TYPES [ self . PILE_ETAT [ 0 ] ] [ 1 ] [ champ [ ( n - 1 ) ] ] . split ( ' | ' )
self . logger . debug ( ' tabaj() : First line detected ' )
self . logger . debug ( ' tabaj() : champ_type[0] : ' + str ( champ_type [ 0 ] ) )
self . logger . debug ( ' tabaj() : champ : ' + str ( champ ) )
self . logger . debug ( ' tabaj() : champ[n-1] : ' + str ( champ [ ( n - 1 ) ] ) )
self . logger . debug ( ' tabaj() : champ.find(champ[n-1]) : ' + str ( champ . find ( champ [ ( n - 1 ) ] ) ) )
nb = int ( champ_type [ 0 ] ) - ( n - champ . find ( champ [ ( n - 1 ) ] ) )
2018-08-29 17:04:00 +02:00
else :
2019-06-30 17:54:41 +02:00
self . logger . debug ( ' tabaj() : Second line detected ' )
champ = champ [ champ . find ( ' | ' ) + 1 : ]
champ_type = MRZCODE . TYPES [ self . PILE_ETAT [ 0 ] ] [ 1 ] [ champ [ ( n - 1 ) ] ] . split ( ' | ' )
self . logger . debug ( ' tabaj() : champ_type[0] : ' + str ( champ_type [ 0 ] ) )
self . logger . debug ( ' tabaj() : champ : ' + str ( champ ) )
self . logger . debug ( ' tabaj() : champ[n-1] : ' + str ( champ [ ( n - 1 ) ] ) )
self . logger . debug ( ' tabaj() : champ.find(champ[n-1]) : ' + str ( champ . find ( champ [ ( n - 1 ) ] ) ) )
self . logger . debug ( ' tabaj() : n : ' + str ( n ) )
nb = int ( champ_type [ 0 ] ) - ( n - champ . find ( champ [ ( n - 1 ) ] ) )
self . termentry . insert ( ' end ' , ' < ' * nb )
self . logger . debug ( ' tabaj() : Completing entry with ' + str ( nb ) + ' characters < ' )
return ' break '
2018-08-29 17:04:00 +02:00
def validate ( self , char , entry_value , typemod ) :
set = False
isValid = True
2019-06-30 17:54:41 +02:00
if typemod == ' 1 ' :
2018-08-29 17:04:00 +02:00
SUM = 0
for ch in char :
2019-06-30 17:54:41 +02:00
if ch in ' ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789< ' :
continue
self . bell ( )
isValid = False
else :
if typemod == ' 0 ' :
for ch in char :
if ch in ' ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789< ' :
continue
2018-08-29 17:04:00 +02:00
self . bell ( )
isValid = False
2019-06-30 17:54:41 +02:00
2018-08-29 17:04:00 +02:00
n = len ( entry_value )
2019-06-30 17:54:41 +02:00
if ( n % self . varnum == 0 or len ( char ) > 3 ) and n < 45 and self . PILE_ETAT == [ ] :
for i in range ( len ( self . Score ) ) :
2018-08-29 17:04:00 +02:00
self . Score [ i ] = 0
2019-06-30 17:54:41 +02:00
for type , t in zip ( MRZCODE . TYPES , range ( len ( MRZCODE . TYPES ) ) ) :
for e in range ( len ( entry_value ) ) :
2018-08-29 17:04:00 +02:00
try :
2019-06-30 17:54:41 +02:00
champchartest = type [ 0 ] [ : type [ 0 ] . find ( ' | ' ) ] [ e ]
champchar = type [ 0 ] [ e ]
2018-08-29 17:04:00 +02:00
except IndexError :
2019-06-30 17:54:41 +02:00
self . logger . debug ( ' validate() : type : ' + str ( t ) )
self . logger . debug ( ' validate() : Too short to be ok ' )
2018-08-29 17:04:00 +02:00
self . Score [ t ] + = - 5
break
else :
2019-06-30 17:54:41 +02:00
self . logger . debug ( ' validate() : type : ' + str ( t ) )
if len ( entry_value ) < = type [ 0 ] . find ( ' | ' ) :
champ_type = type [ 1 ] [ str ( champchar ) ] . split ( ' | ' )
pos = e - type [ 0 ] . find ( champchar )
self . logger . debug ( ' validate() : champ_type[2][pos] : ' + str ( champ_type [ 2 ] [ pos ] ) )
self . logger . debug ( ' validate() : champ_type[1] : ' + str ( champ_type [ 1 ] ) )
if champ_type [ 1 ] == ' CODE ' :
if champ_type [ 2 ] [ pos ] == ' * ' :
2018-08-29 17:04:00 +02:00
self . Score [ t ] + = 0
else :
2019-06-30 17:54:41 +02:00
if champ_type [ 2 ] [ pos ] == entry_value [ e ] :
self . Score [ t ] + = 1
self . logger . debug ( ' validate() : +1 ' )
else :
self . Score [ t ] + = - 50
elif champ_type [ 2 ] [ pos ] == ' * ' :
self . Score [ t ] + = 1
self . logger . debug ( ' validate() : +1 ' )
2018-08-29 17:04:00 +02:00
else :
2019-06-30 17:54:41 +02:00
if champ_type [ 2 ] [ pos ] == ' A ' :
if entry_value [ e ] . isalpha ( ) :
self . Score [ t ] + = 1
self . logger . debug ( ' validate() : +1 ' )
if champ_type [ 2 ] [ pos ] == ' 0 ' :
if entry_value [ e ] . isnumeric ( ) :
self . Score [ t ] + = 1
self . logger . debug ( ' validate() : +1 ' )
if champ_type [ 1 ] == ' CTRL ' :
if entry_value [ e ] . isnumeric ( ) :
self . Score [ t ] + = 1
self . logger . debug ( ' validate() : +1 ' )
if champ_type [ 2 ] [ pos ] == ' & ' :
if entry_value [ e ] . isalpha ( ) or entry_value [ e ] == ' < ' :
self . Score [ t ] + = 1
self . logger . debug ( ' validate() : +1 ' )
self . Score [ t ] + = - 1
continue
self . logger . debug ( ' validate() : self.Score : ' + str ( self . Score ) )
m = max ( self . Score )
typem = [ i for i , j in enumerate ( self . Score ) if j == m if m > 5 ]
2018-08-29 17:04:00 +02:00
for h in typem :
2019-06-30 17:54:41 +02:00
self . PILE_ETAT + = [ h ]
2018-08-29 17:04:00 +02:00
if len ( self . PILE_ETAT ) > 1 :
self . varnum + = 3
self . PILE_ETAT = [ ]
2019-06-30 17:54:41 +02:00
else :
if len ( self . PILE_ETAT ) == 1 :
TOPOS = MRZCODE . TYPES [ self . PILE_ETAT [ 0 ] ] [ 2 ]
self . montext ( TOPOS + " détectée ! \n Appuyez sur Echap pour compléter les champs avec des ' < ' \n Appuyez sur Entrée pour terminer. \n " )
self . logger . debug ( ' validate() : Detection : ' + str ( TOPOS ) )
else :
if len ( self . PILE_ETAT ) == 1 :
if len ( entry_value ) > len ( MRZCODE . TYPES [ self . PILE_ETAT [ 0 ] ] [ 0 ] . split ( ' | ' ) [ 0 ] ) :
isValid = False
2018-08-29 17:04:00 +02:00
return isValid
2019-06-30 17:54:41 +02:00
def montext ( self , text ) :
self . monlog [ ' state ' ] = ' normal '
self . monlog . insert ( ' end ' , text )
self . monlog [ ' state ' ] = ' disabled '
self . monlog . yview ( END )
2018-08-29 17:04:00 +02:00
def openingscan ( self ) :
self . initialize ( self . logger )
self . update ( )
2019-06-30 17:54:41 +02:00
path = ' '
path = filedialog . askopenfilename ( parent = self , title = ' Ouvrir un scan de CNI... ' , filetypes = ( ( ' TIF files ' , ' *.tif ' ) ,
( ' TIF files ' , ' *.tiff ' ) ,
( ' JPEG files ' , ' *.jpg ' ) ,
( ' JPEG files ' , ' *.jpeg ' ) ) )
self . openerrored = False
if path != ' ' :
self . logger . info ( ' openingscan() : Opening file with path ' + str ( path ) )
2018-08-29 17:04:00 +02:00
im = Image . open ( path )
2019-06-30 17:54:41 +02:00
try :
nframe = im . n_frames
except AttributeError :
nframe = 1
if nframe == 1 :
self . mrzdetected = ' '
self . mrzdict = { }
2018-08-29 17:04:00 +02:00
try :
opening = OpenScanWin ( self , path , 0 )
opening . transient ( self )
opening . grab_set ( )
self . wait_window ( opening )
2019-06-30 17:54:41 +02:00
except TclError :
pass
except Exception as e :
self . logger . critical ( ' openingscan() : ' + str ( e ) )
if self . openerrored == True :
self . logger . error ( ' openingscan() : Incompatible file with path ' + str ( path ) )
return
self . logger . debug ( ' openingscan() : ' + str ( self . mrzdetected ) )
else :
if nframe > 1 :
self . mrzdetected = ' '
2018-08-29 17:04:00 +02:00
self . mrzdict = { }
2019-06-30 17:54:41 +02:00
try :
opening = OpenScanWin ( self , path , 1 , nframe )
opening . transient ( self )
opening . grab_set ( )
self . wait_window ( opening )
except TclError :
pass
except Exception as e :
self . logger . critical ( ' openingscan() : ' + str ( e ) )
if self . openerrored == True :
self . logger . critical ( ' openingscan() : Incompatible file with path ' + str ( path ) )
return
self . logger . debug ( ' openingscan() : ' + str ( self . mrzdetected ) )
2018-08-29 17:04:00 +02:00
try :
os . remove ( CST_FOLDER + ' \\ temp.tif ' )
except IOError :
pass
2019-06-30 17:54:41 +02:00
2018-08-29 17:04:00 +02:00
else :
2019-06-30 17:54:41 +02:00
raise Exception
mrzsoumisetab = self . mrzdetected . replace ( ' ' , ' ' ) . split ( ' \n ' )
2018-08-29 17:04:00 +02:00
for chain in mrzsoumisetab :
2019-06-30 17:54:41 +02:00
self . termentry . insert ( ' end ' , chain )
if len ( chain ) > = 5 :
self . returnaj ( ' <Return> ' )
2018-08-29 17:04:00 +02:00
def newbie ( self ) :
self . initialize ( self . logger )
2019-06-30 17:54:41 +02:00
self . montext ( ' \n \n Entrez la première ligne de MRZ svp \n ' )
2018-08-29 17:04:00 +02:00
def infobox ( self ) :
Tk ( ) . withdraw ( )
2019-06-30 17:54:41 +02:00
showinfo ( ' A propos du logiciel ' , ( ' Version du logiciel : \n ' + CST_NAME + ' ' + CST_VER + ' ' + CST_TYPE + ' Revision ' + CST_REV + " \n Licence GNU/GPL 2018 \n \n Auteur : NeoX_ ; devadmin@neoxgroup.eu \n \n Tesseract 4.0 est soumis à l ' Apache License 2004 \n \n N ' hésitez pas à faire part de vos commentaires ! " ) , parent = self )
def calculsigma ( self , MRZtxt , numtype ) :
CST_BACKGROUND = self [ ' background ' ]
CTRList = [ c for c , v in MRZCODE . TYPES [ numtype ] [ 1 ] . items ( ) if ' CTRL ' in v ]
self . logger . info ( ' [calculsigma() thread] : Sigma calculation launched! ' )
self . logger . debug ( ' [calculsigma() thread] : CTRList = ' + str ( CTRList ) )
2018-08-29 17:04:00 +02:00
self . Falsitude = 0
2019-06-30 17:54:41 +02:00
self . montext ( ' \n ' )
2018-08-29 17:04:00 +02:00
for i in CTRList :
2019-06-30 17:54:41 +02:00
sumtxt = MRZCODE . TYPES [ numtype ] [ 1 ] [ i ]
length = MRZCODE . TYPES [ numtype ] [ 0 ] . find ( ' | ' )
index = MRZCODE . TYPES [ numtype ] [ 0 ] . find ( i )
sum_read = MRZtxt [ index ]
if len ( sumtxt . split ( ' | ' ) [ 2 ] ) == 1 :
debut = MRZCODE . TYPES [ numtype ] [ 0 ] . find ( sumtxt . split ( ' | ' ) [ 2 ] [ 0 ] )
sum_calc = MRZCODE . MRZ ( MRZtxt [ int ( debut ) : index ] )
else :
transm_chain = ' '
for y in sumtxt . split ( ' | ' ) [ 2 ] :
2018-08-29 17:04:00 +02:00
debut = MRZCODE . TYPES [ numtype ] [ 0 ] . find ( y )
2019-06-30 17:54:41 +02:00
fin = debut + int ( MRZCODE . TYPES [ numtype ] [ 1 ] [ y ] . split ( ' | ' ) [ 0 ] )
transm_chain + = MRZtxt [ int ( debut ) : int ( fin ) ]
2018-08-29 17:04:00 +02:00
sum_calc = MRZCODE . MRZ ( transm_chain )
2019-06-30 17:54:41 +02:00
if str ( sum_read ) [ 0 ] != str ( sum_calc ) [ 0 ] :
if not ( sumtxt . split ( ' | ' ) [ 1 ] == ' CTRLF ' and str ( sum_read ) [ 0 ] == ' < ' ) :
self . Falsitude + = 1
self . logger . debug ( ' [calculsigma() thread] : Falsitude +1, sum errored : ' + str ( i ) )
self . termtext . tag_add ( ' highLOW ' , ' 1.0+ ' + str ( index ) + ' c ' , ' 1.0+ ' + str ( index + 1 ) + ' c ' )
self . termtext . tag_configure ( ' highLOW ' , background = ' #760808 ' , relief = ' raised ' , foreground = ' white ' )
self . termtext . tag_add ( ' highLOWB ' , ' 1.0+ ' + str ( index ) + ' c ' , ' 1.0+ ' + str ( index + 1 ) + ' c ' )
self . termtext . tag_configure ( ' highLOWB ' , background = ' #04B404 ' , relief = ' raised ' , foreground = ' white ' )
self . montext ( ' Somme : Lu ' + str ( sum_read ) + ' VS calculé ' + str ( sum_calc ) + ' \n ' )
NameList = [ c for c , v in MRZCODE . TYPES [ numtype ] [ 1 ] . items ( ) if ' |NOM ' in v ]
SurnameList = [ c for c , v in MRZCODE . TYPES [ numtype ] [ 1 ] . items ( ) if ' PRENOM ' in v ]
DDateList = [ c for c , v in MRZCODE . TYPES [ numtype ] [ 1 ] . items ( ) if ' DDATE ' in v ]
BDateList = [ c for c , v in MRZCODE . TYPES [ numtype ] [ 1 ] . items ( ) if ' BDATE ' in v ]
EDateList = [ c for c , v in MRZCODE . TYPES [ numtype ] [ 1 ] . items ( ) if ' EDATE ' in v ]
PAYSList = [ c for c , v in MRZCODE . TYPES [ numtype ] [ 1 ] . items ( ) if ' PAYS ' in v ]
NATList = [ c for c , v in MRZCODE . TYPES [ numtype ] [ 1 ] . items ( ) if ' NAT ' in v ]
SEXList = [ c for c , v in MRZCODE . TYPES [ numtype ] [ 1 ] . items ( ) if ' SEX ' in v ]
NOINTList = [ c for c , v in MRZCODE . TYPES [ numtype ] [ 1 ] . items ( ) if ' NOINT ' in v ]
NOList = [ c for c , v in MRZCODE . TYPES [ numtype ] [ 1 ] . items ( ) if ' NO| ' in v ]
FACULTList = [ c for c , v in MRZCODE . TYPES [ numtype ] [ 1 ] . items ( ) if ' FACULT ' in v ]
INDICList = [ c for c , v in MRZCODE . TYPES [ numtype ] [ 1 ] . items ( ) if ' INDIC ' in v ]
BIGList = [
NameList , SurnameList , DDateList , BDateList , EDateList , PAYSList , NATList , SEXList , NOList , INDICList , NOINTList ]
BIGObj = [
self . nom , self . prenom , self . ddate , self . bdate , self . edate , self . pays , self . nat , self . sex , self . no , self . indic , self . no ]
2018-08-29 17:04:00 +02:00
for i in range ( len ( BIGList ) ) :
2019-06-30 17:54:41 +02:00
for champ , champnum in zip ( BIGList [ i ] , range ( len ( BIGList [ i ] ) ) ) :
2018-08-29 17:04:00 +02:00
debut = MRZCODE . TYPES [ numtype ] [ 0 ] . find ( champ )
2019-06-30 17:54:41 +02:00
fin = debut + int ( MRZCODE . TYPES [ numtype ] [ 1 ] [ champ ] . split ( ' | ' ) [ 0 ] )
2018-08-29 17:04:00 +02:00
if BIGObj [ i ] == self . pays or BIGObj [ i ] == self . nat :
try :
2019-06-30 17:54:41 +02:00
BIGObj [ i ] [ ' text ' ] = MRZCODE . landcode [ MRZtxt [ int ( debut ) : int ( fin ) ] . replace ( ' < ' , ' ' ) ]
2018-08-29 17:04:00 +02:00
except KeyError :
self . Falsitude + = 1
2019-06-30 17:54:41 +02:00
self . montext ( ' Code pays : ' + str ( MRZtxt [ int ( debut ) : int ( fin ) ] ) + ' est inconnu \n ' )
self . logger . debug ( ' [calculsigma() thread] : Falsitude +1, unknown state ' )
self . termtext . tag_add ( ' highLOW ' , ' 1.0+ ' + str ( debut ) + ' c ' , ' 1.0+ ' + str ( fin ) + ' c ' )
self . termtext . tag_configure ( ' highLOW ' , background = ' #760808 ' , relief = ' raised ' , foreground = ' white ' )
BIGObj [ i ] [ ' background ' ] = ' #760808 '
BIGObj [ i ] [ ' foreground ' ] = ' white '
else :
BIGObj [ i ] [ ' background ' ] = CST_BACKGROUND
BIGObj [ i ] [ ' foreground ' ] = ' black '
self . termtext . tag_add ( ' highLOWN ' , ' 1.0+ ' + str ( debut ) + ' c ' , ' 1.0+ ' + str ( fin ) + ' c ' )
self . termtext . tag_configure ( ' highLOWN ' , background = ' white ' , relief = ' raised ' , foreground = ' #121f38 ' )
2018-08-29 17:04:00 +02:00
elif BIGObj [ i ] == self . sex :
try :
2019-06-30 17:54:41 +02:00
BIGObj [ i ] [ ' text ' ] = MRZCODE . sexcode [ MRZtxt [ int ( debut ) : int ( fin ) ] ]
2018-08-29 17:04:00 +02:00
except KeyError :
self . Falsitude + = 1
2019-06-30 17:54:41 +02:00
self . montext ( ' Sexe : ' + str ( MRZtxt [ int ( debut ) : int ( fin ) ] ) + ' est inconnu \n ' )
self . logger . debug ( ' [calculsigma() thread] : Falsitude +1, unknown state ' )
self . termtext . tag_add ( ' highLOW ' , ' 1.0+ ' + str ( debut ) + ' c ' , ' 1.0+ ' + str ( fin ) + ' c ' )
self . termtext . tag_configure ( ' highLOW ' , background = ' #760808 ' , relief = ' raised ' , foreground = ' white ' )
BIGObj [ i ] [ ' background ' ] = ' #760808 '
BIGObj [ i ] [ ' foreground ' ] = ' white '
2018-08-29 17:04:00 +02:00
else :
2019-06-30 17:54:41 +02:00
BIGObj [ i ] [ ' background ' ] = CST_BACKGROUND
BIGObj [ i ] [ ' foreground ' ] = ' black '
self . termtext . tag_add ( ' highLOWN ' , ' 1.0+ ' + str ( debut ) + ' c ' , ' 1.0+ ' + str ( fin ) + ' c ' )
self . termtext . tag_configure ( ' highLOWN ' , background = ' white ' , relief = ' raised ' , foreground = ' #121f38 ' )
2018-08-29 17:04:00 +02:00
else :
2019-06-30 17:54:41 +02:00
if BIGObj [ i ] == self . edate or BIGObj [ i ] == self . ddate or BIGObj [ i ] == self . bdate :
txtl = MRZtxt [ int ( debut ) : int ( fin ) ] . replace ( ' <<< ' , ' ' ) . replace ( ' < ' , ' ' )
if len ( txtl ) < 6 :
txtl + = ' 0 ' * ( 6 - len ( txtl ) )
BIGObj [ i ] [ ' text ' ] = ' {0} / {1} / {2} ' . format ( txtl [ 4 : ] , txtl [ 2 : 4 ] , txtl [ : 2 ] )
if BIGObj [ i ] == self . edate :
present = datetime . now ( )
try :
expiration = datetime ( 2000 + int ( txtl [ : 2 ] ) , int ( txtl [ 2 : 4 ] ) , int ( txtl [ 4 : ] ) )
except ValueError :
BIGObj [ i ] [ ' background ' ] = ' #760808 '
BIGObj [ i ] [ ' foreground ' ] = ' white '
self . Falsitude + = 1
self . montext ( ' Date : ' + str ( BIGObj [ i ] [ ' text ' ] ) + ' est invalide \n ' )
self . logger . debug ( ' [calculsigma() thread] : Falsitude +1, invalid expiration date ' )
self . termtext . tag_add ( ' highLOW ' , ' 1.0+ ' + str ( debut ) + ' c ' , ' 1.0+ ' + str ( fin ) + ' c ' )
self . termtext . tag_configure ( ' highLOW ' , background = ' #760808 ' , relief = ' raised ' , foreground = ' white ' )
else :
BIGObj [ i ] [ ' background ' ] = CST_BACKGROUND
BIGObj [ i ] [ ' foreground ' ] = ' black '
self . termtext . tag_add ( ' highLOWN ' , ' 1.0+ ' + str ( debut ) + ' c ' , ' 1.0+ ' + str ( fin ) + ' c ' )
self . termtext . tag_configure ( ' highLOWN ' , background = ' white ' , relief = ' raised ' , foreground = ' #121f38 ' )
if expiration < present :
BIGObj [ i ] [ ' background ' ] = ' #e67300 '
BIGObj [ i ] [ ' foreground ' ] = ' white '
self . termtext . tag_add ( ' highLOWN ' , ' 1.0+ ' + str ( debut ) + ' c ' , ' 1.0+ ' + str ( fin ) + ' c ' )
self . termtext . tag_configure ( ' highLOWN ' , background = ' white ' , relief = ' raised ' , foreground = ' #121f38 ' )
else :
BIGObj [ i ] [ ' background ' ] = CST_BACKGROUND
BIGObj [ i ] [ ' foreground ' ] = ' black '
else :
try :
if int ( txtl [ 4 : ] ) == 0 :
verif = datetime ( 2000 + int ( txtl [ : 2 ] ) , int ( txtl [ 2 : 4 ] ) , 1 )
else :
verif = datetime ( 2000 + int ( txtl [ : 2 ] ) , int ( txtl [ 2 : 4 ] ) , int ( txtl [ 4 : ] ) )
except ValueError :
BIGObj [ i ] [ ' background ' ] = ' #760808 '
BIGObj [ i ] [ ' foreground ' ] = ' white '
self . Falsitude + = 1
self . montext ( ' Date : ' + str ( BIGObj [ i ] [ ' text ' ] ) + ' est invalide \n ' )
self . logger . debug ( ' [calculsigma() thread] : Falsitude +1, invalid datetime ' )
self . termtext . tag_add ( ' highLOW ' , ' 1.0+ ' + str ( debut ) + ' c ' , ' 1.0+ ' + str ( fin ) + ' c ' )
self . termtext . tag_configure ( ' highLOW ' , background = ' #760808 ' , relief = ' raised ' , foreground = ' white ' )
else :
BIGObj [ i ] [ ' background ' ] = CST_BACKGROUND
BIGObj [ i ] [ ' foreground ' ] = ' black '
self . termtext . tag_add ( ' highLOWN ' , ' 1.0+ ' + str ( debut ) + ' c ' , ' 1.0+ ' + str ( fin ) + ' c ' )
self . termtext . tag_configure ( ' highLOWN ' , background = CST_BACKGROUND , relief = ' raised ' , foreground = ' #121f38 ' )
2018-08-29 17:04:00 +02:00
else :
2019-06-30 17:54:41 +02:00
if champnum == 0 :
BIGObj [ i ] [ ' text ' ] = MRZtxt [ int ( debut ) : int ( fin ) ] . replace ( ' <<< ' , ' ' ) . replace ( ' < ' , ' ' )
else :
BIGObj [ i ] [ ' text ' ] + = MRZtxt [ int ( debut ) : int ( fin ) ] . replace ( ' <<< ' , ' ' ) . replace ( ' < ' , ' ' )
if self . Falsitude == 0 :
self . STATUStxt [ ' text ' ] = ' CONFORME '
self . STATUStxt [ ' fg ' ] = ' #04B404 '
self . logger . debug ( ' [calculsigma() thread] : Conforme ! ' )
2018-08-29 17:04:00 +02:00
else :
2019-06-30 17:54:41 +02:00
self . STATUStxt [ ' text ' ] = ' NON CONFORME '
self . STATUStxt [ ' fg ' ] = ' #760808 '
self . logger . debug ( ' [calculsigma() thread] : Non conforme ! ' )
self . montext ( ' ** Score de non conformité : ' + str ( self . Falsitude ) + ' ** \n ' )
self . termtext [ ' state ' ] = ' normal '
self . PILE_ETAT = [ self . Falsitude , numtype ]
2018-08-29 17:04:00 +02:00
class MRZCODE :
2019-06-30 17:54:41 +02:00
2018-08-29 17:04:00 +02:00
def MRZ ( code ) :
"""
Calcul sommes de contrôle de la chaîne transmise
"""
2019-06-30 17:54:41 +02:00
resultat = 0
i = - 1
facteur = [ 7 , 3 , 1 ]
for car in code :
if car == ' < ' or car == ' | ' :
2018-08-29 17:04:00 +02:00
valeur = 0
i + = 1
else :
2019-06-30 17:54:41 +02:00
if car in ' 0123456789 ' :
valeur = int ( car )
i + = 1
else :
if car in ' ABCDEFGHIJKLMNOPQRSTUVWXYZ ' :
valeur = ord ( car ) - 55
i + = 1
else :
break
resultat + = valeur * facteur [ ( i % 3 ) ]
return resultat % 10
sexcode = { ' M ' : ' Homme ' ,
' F ' : ' Femme ' , ' X ' : ' Non spécifié ' }
landcode2 = { ' AW ' : ' Aruba ' ,
' AF ' : ' Afghanistan ' , ' AO ' : ' Angola ' , ' AI ' : ' Anguilla ' , ' AL ' : ' Albanie ' , ' AD ' : ' Andorre ' , ' AE ' : ' Emirats arabes unis ' , ' AR ' : ' Argentine ' , ' AM ' : ' Arménie ' , ' AS ' : ' Samoa américaines ' , ' AQ ' : ' Antarctique ' , ' TF ' : ' Terres australes et antarctiques françaises ' , ' AG ' : ' Antigua-et-Barbuda ' , ' AU ' : ' Australie ' , ' AT ' : ' Autriche ' , ' AZ ' : ' Azerbaidjan ' , ' BI ' : ' Burundi ' , ' BE ' : ' Belgique ' , ' BJ ' : ' Benin ' , ' BQ ' : ' Pays-Bas caribéens ' , ' BF ' : ' Burkina Faso ' , ' BD ' : ' Bangladesh ' , ' BG ' : ' Bulgarie ' , ' BH ' : ' Bahrein ' , ' BS ' : ' Bahamas ' , ' BA ' : ' Bosnie-Herzegovine ' , ' BL ' : ' Saint-Barthélemy ' , ' BY ' : ' Bielorussie ' , ' BZ ' : ' Belize ' , ' BM ' : ' Bermudes ' , ' BO ' : ' Bolivie ' , ' BR ' : ' Brésil ' , ' BB ' : ' Barbade ' , ' BN ' : ' Brunei ' , ' BT ' : ' Bhoutan ' , ' BW ' : ' Botswana ' , ' CF ' : ' République Centrafricaine ' , ' CA ' : ' Canada ' , ' CC ' : ' Îles Cocos ' , ' CH ' : ' Suisse ' , ' CL ' : ' Chili ' ,
' CN ' : ' Chine ' , ' CI ' : " Côte d ' Ivoire " ,
' CM ' : ' Cameroun ' , ' CD ' : ' Congo (République démocratique) ' ,
' CG ' : ' Congo (République) ' , ' CK ' : ' Îles Cook ' ,
' CO ' : ' Colombie ' , ' KM ' : ' Comores ' ,
' CV ' : ' Cap-Vert ' , ' CR ' : ' Costa Rica ' ,
' CU ' : ' Cuba ' , ' CW ' : ' Curaçao ' ,
' CX ' : ' Île Christmas ' , ' KY ' : ' Caimans ' ,
' CY ' : ' Chypre ' , ' CZ ' : ' Tchéquie ' ,
' DE ' : ' Allemagne ' , ' DJ ' : ' Djibouti ' ,
' DM ' : ' Dominique ' , ' DK ' : ' Danemark ' ,
' DO ' : ' République dominicaine ' , ' DZ ' : ' Algérie ' ,
' EC ' : ' Equateur ' , ' EG ' : ' Egypte ' ,
' ER ' : ' Erythrée ' , ' EH ' : ' Sahara occidental ' ,
' ES ' : ' Espagne ' , ' EE ' : ' Estonie ' ,
' ET ' : ' Ethiopie ' , ' FI ' : ' Finlande ' , ' FJ ' : ' Fidji ' , ' FK ' : ' Îles Malouines ' , ' FR ' : ' France ' ,
' FO ' : ' Féroé ' , ' FM ' : ' Micronésie ' , ' GA ' : ' Gabon ' , ' GB ' : ' Royaume-Uni ' ,
' GE ' : ' Géorgie ' , ' GG ' : ' Guernesey ' ,
' GH ' : ' Ghana ' , ' GI ' : ' Gibraltar ' ,
' GN ' : ' Guinée ' , ' GP ' : ' Guadeloupe ' ,
' GM ' : ' Gambie ' , ' GW ' : ' Guinée-Bissau ' ,
' GQ ' : ' Guinée équatoriale ' , ' GR ' : ' Grèce ' ,
' GD ' : ' Grenade ' , ' GL ' : ' Groenland ' ,
' GT ' : ' Guatemala ' , ' GF ' : ' Guyane ' ,
' GU ' : ' Guam ' , ' GY ' : ' Guyana ' ,
' HK ' : ' Hong Kong ' , ' HN ' : ' Honduras ' ,
' HR ' : ' Croatie ' , ' HT ' : ' Haïti ' ,
' HU ' : ' Hongrie ' , ' ID ' : ' Indonésie ' ,
' IM ' : ' Île de Man ' , ' IN ' : ' Inde ' ,
' IO ' : " Territoire britannique de l ' océan Indien " , ' IE ' : ' Irlande ' ,
' IR ' : ' Irak ' , ' IQ ' : ' Iran ' , ' IS ' : ' Islande ' , ' IL ' : ' Israël ' , ' IT ' : ' Italie ' ,
' JM ' : ' Jamaïque ' , ' JE ' : ' Jersey ' , ' JO ' : ' Jordanie ' , ' JP ' : ' Japon ' ,
' KZ ' : ' Kazakhstan ' , ' KE ' : ' Kenya ' ,
' KG ' : ' Kirghizistan ' , ' KH ' : ' Cambodge ' ,
' KI ' : ' Kiribati ' , ' KN ' : ' Saint-Christophe-et-Niévès ' ,
' KR ' : ' Corée du Sud ' , ' KW ' : ' Koweït ' ,
' LA ' : ' Laos ' , ' LB ' : ' Liban ' ,
' LR ' : ' Liberia ' , ' LY ' : ' Libye ' ,
' LC ' : ' Sainte-Lucie ' , ' LI ' : ' Liechtenstein ' ,
' LK ' : ' Sri Lanka ' , ' LS ' : ' Lesotho ' ,
' LT ' : ' Lituanie ' , ' LU ' : ' Luxembourg ' ,
' LV ' : ' Lettonie ' , ' MO ' : ' Macao ' ,
' MF ' : ' Sint-Maarten ' , ' MA ' : ' Maroc ' ,
' MC ' : ' Monaco ' , ' MD ' : ' Moldavie ' ,
' MG ' : ' Madagascar ' , ' MV ' : ' Maldives ' ,
' MX ' : ' Mexique ' , ' MH ' : ' Marshall ' , ' MK ' : ' Macedoine ' , ' ML ' : ' Mali ' , ' MT ' : ' Malte ' ,
' MM ' : ' Birmanie ' , ' ME ' : ' Monténégro ' , ' MN ' : ' Mongolie ' , ' MP ' : ' Îles Mariannes du Nord ' ,
' MZ ' : ' Mozambique ' , ' MR ' : ' Mauritanie ' ,
' MS ' : ' Montserrat ' , ' MQ ' : ' Martinique ' ,
' MU ' : ' Maurice ' , ' MW ' : ' Malawi ' ,
' MY ' : ' Malaisie ' , ' YT ' : ' Mayotte ' ,
' NA ' : ' Namibie ' , ' NC ' : ' Nouvelle-Calédonie ' ,
' NE ' : ' Niger ' , ' NF ' : ' Île Norfolk ' ,
' NG ' : ' Nigeria ' , ' NI ' : ' Nicaragua ' ,
' NU ' : ' Niue ' , ' NL ' : ' Pays-Bas ' ,
' NO ' : ' Norvège ' , ' NP ' : ' Nepal ' ,
' NR ' : ' Nauru ' , ' NZ ' : ' Nouvelle-Zélande ' ,
' OM ' : ' Oman ' , ' PK ' : ' Pakistan ' ,
' PA ' : ' Panama ' , ' PN ' : ' Îles Pitcairn ' ,
' PE ' : ' Pérou ' , ' PH ' : ' Philippines ' ,
' PW ' : ' Palaos ' , ' PG ' : ' Papouasie-Nouvelle-Guinée ' ,
' PL ' : ' Pologne ' , ' PR ' : ' Porto Rico ' , ' KP ' : ' Corée du Nord ' , ' PT ' : ' Portugal ' , ' PY ' : ' Paraguay ' ,
' PS ' : ' Palestine ' , ' PF ' : ' Polynésie française ' , ' QA ' : ' Qatar ' , ' RE ' : ' Réunion ' ,
' RO ' : ' Roumanie ' , ' RU ' : ' Russie ' ,
' RW ' : ' Rwanda ' , ' SA ' : ' Arabie saoudite ' ,
' SD ' : ' Soudan ' , ' SN ' : ' Sénégal ' ,
' SG ' : ' Singapour ' , ' GS ' : ' Georgie du Sud-et-les iles Sandwich du Sud ' ,
' SH ' : ' Sainte-Hélène, Ascension et Tristan da Cunha ' , ' SJ ' : ' Svalbard et île Jan Mayen ' ,
' SB ' : ' Salomon ' , ' SL ' : ' Sierra Leone ' ,
' SV ' : ' Salvador ' , ' SM ' : ' Saint-Marin ' ,
' SO ' : ' Somalie ' , ' PM ' : ' Saint-Pierre-et-Miquelon ' ,
' RS ' : ' Serbie ' , ' SS ' : ' Soudan du Sud ' ,
' ST ' : ' Sao Tomé-et-Principe ' , ' SR ' : ' Suriname ' ,
' SK ' : ' Slovaquie ' , ' SI ' : ' Slovénie ' ,
' SE ' : ' Suède ' , ' SZ ' : ' eSwatani ' ,
' SX ' : ' Saint-Martin ' , ' SC ' : ' Seychelles ' , ' SY ' : ' Syrie ' , ' TC ' : ' Îles Turques-et-Caïques ' , ' TD ' : ' Tchad ' ,
' TG ' : ' Togo ' , ' TH ' : ' Thaïlande ' , ' TJ ' : ' Tadjikistan ' , ' TK ' : ' Tokelau ' ,
' TM ' : ' Turkmenistan ' , ' TL ' : ' Timor oriental ' ,
' TO ' : ' Tonga ' , ' TT ' : ' Trinité-et-Tobago ' ,
' TN ' : ' Tunisie ' , ' TR ' : ' Turquie ' ,
' TV ' : ' Tuvalu ' , ' TW ' : ' Taiwan ' ,
' TZ ' : ' Tanzanie ' , ' UG ' : ' Ouganda ' ,
' UA ' : ' Ukraine ' , ' UY ' : ' Uruguay ' ,
' US ' : ' Etats-Unis ' , ' UZ ' : ' Ouzbékistan ' ,
' VA ' : ' Saint-Siège (État de la Cité du Vatican) ' , ' VC ' : ' Saint-Vincent-et-les-Grenadines ' ,
' VE ' : ' Venezuela ' , ' VG ' : ' Îles Vierges britanniques ' ,
' VI ' : ' Îles Vierges des États-Unis ' , ' VN ' : ' Viêt Nam ' ,
' VU ' : ' Vanuatu ' , ' WF ' : ' Wallis-et-Futuna ' ,
' WS ' : ' Samoa ' , ' XK ' : ' Kosovo ' ,
' YE ' : ' Yémen ' , ' ZA ' : ' Afrique du Sud ' , ' ZM ' : ' Zambie ' , ' ZW ' : ' Zimbabwe ' }
landcode = { ' ABW ' : ' Aruba ' , ' AFG ' : ' Afghanistan ' ,
' AGO ' : ' Angola ' , ' AIA ' : ' Anguilla ' ,
' ALB ' : ' Albanie ' , ' AND ' : ' Andorre ' ,
' ARE ' : ' Emirats arabes unis ' , ' ARG ' : ' Argentine ' ,
' ARM ' : ' Arménie ' , ' ASM ' : ' Samoa américaines ' ,
' ATA ' : ' Antarctique ' , ' ATF ' : ' Terres australes et antarctiques françaises ' ,
' ATG ' : ' Antigua-et-Barbuda ' , ' AUS ' : ' Australie ' ,
' AUT ' : ' Autriche ' , ' AZE ' : ' Azerbaidjan ' ,
' BDI ' : ' Burundi ' , ' BEL ' : ' Belgique ' ,
' BEN ' : ' Benin ' , ' BES ' : ' Pays-Bas caribéens ' ,
' BFA ' : ' Burkina Faso ' , ' BGD ' : ' Bangladesh ' ,
' BGR ' : ' Bulgarie ' , ' BHR ' : ' Bahrein ' ,
' BHS ' : ' Bahamas ' , ' BIH ' : ' Bosnie-Herzegovine ' ,
' BLM ' : ' Saint-Barthélemy ' , ' BLR ' : ' Bielorussie ' ,
' BLZ ' : ' Belize ' , ' BMU ' : ' Bermudes ' , ' BOL ' : ' Bolivie ' , ' BRA ' : ' Brésil ' , ' BRB ' : ' Barbade ' ,
' BRN ' : ' Brunei ' , ' BTN ' : ' Bhoutan ' , ' BWA ' : ' Botswana ' , ' CAF ' : ' République Centrafricaine ' ,
' CAN ' : ' Canada ' , ' CCK ' : ' Îles Cocos ' ,
' CHE ' : ' Suisse ' , ' CHL ' : ' Chili ' ,
' CHN ' : ' Chine ' , ' CIV ' : " Côte d ' Ivoire " ,
' CMR ' : ' Cameroun ' , ' COD ' : ' Congo (République démocratique) ' ,
' COG ' : ' Congo (République) ' , ' COK ' : ' Îles Cook ' ,
' COL ' : ' Colombie ' , ' COM ' : ' Comores ' ,
' CPV ' : ' Cap-Vert ' , ' CRI ' : ' Costa Rica ' ,
' CUB ' : ' Cuba ' , ' CUW ' : ' Curaçao ' ,
' CXR ' : ' Île Christmas ' , ' CYM ' : ' Caimans ' ,
' CYP ' : ' Chypre ' , ' CZE ' : ' Tchéquie ' ,
' DEU ' : ' Allemagne ' , ' DJI ' : ' Djibouti ' ,
' DMA ' : ' Dominique ' , ' DNK ' : ' Danemark ' ,
' DOM ' : ' République dominicaine ' , ' DZA ' : ' Algérie ' ,
' ECU ' : ' Equateur ' , ' EGY ' : ' Egypte ' , ' ERI ' : ' Erythrée ' , ' ESH ' : ' Sahara occidental ' , ' ESP ' : ' Espagne ' ,
' EST ' : ' Estonie ' , ' ETH ' : ' Ethiopie ' , ' FIN ' : ' Finlande ' , ' FJI ' : ' Fidji ' ,
' FLK ' : ' Îles Malouines ' , ' FRA ' : ' France ' ,
' FRO ' : ' Féroé ' , ' FSM ' : ' Micronésie ' ,
' GAB ' : ' Gabon ' , ' GBR ' : ' Royaume-Uni ' ,
' GEO ' : ' Géorgie ' , ' GGY ' : ' Guernesey ' ,
' GHA ' : ' Ghana ' , ' GIB ' : ' Gibraltar ' ,
' GIN ' : ' Guinée ' , ' GLP ' : ' Guadeloupe ' ,
' GMB ' : ' Gambie ' , ' GNB ' : ' Guinée-Bissau ' ,
' GNQ ' : ' Guinée équatoriale ' , ' GRC ' : ' Grèce ' , ' GRD ' : ' Grenade ' , ' GRL ' : ' Groenland ' , ' GTM ' : ' Guatemala ' ,
' GUF ' : ' Guyane ' , ' GUM ' : ' Guam ' , ' GUY ' : ' Guyana ' , ' HKG ' : ' Hong Kong ' ,
' HND ' : ' Honduras ' , ' HRV ' : ' Croatie ' , ' HTI ' : ' Haïti ' , ' HUN ' : ' Hongrie ' , ' IDN ' : ' Indonésie ' , ' IMN ' : ' Île de Man ' , ' IND ' : ' Inde ' , ' IOT ' : " Territoire britannique de l ' océan Indien " , ' IRL ' : ' Irlande ' , ' IRN ' : ' Irak ' , ' IRQ ' : ' Iran ' , ' ISL ' : ' Islande ' , ' ISR ' : ' Israël ' , ' ITA ' : ' Italie ' , ' JAM ' : ' Jamaïque ' , ' JEY ' : ' Jersey ' , ' JOR ' : ' Jordanie ' , ' JPN ' : ' Japon ' , ' KAZ ' : ' Kazakhstan ' , ' KEN ' : ' Kenya ' , ' KGZ ' : ' Kirghizistan ' , ' KHM ' : ' Cambodge ' , ' KIR ' : ' Kiribati ' , ' KNA ' : ' Saint-Christophe-et-Niévès ' , ' KOR ' : ' Corée du Sud ' , ' KWT ' : ' Koweït ' , ' LAO ' : ' Laos ' , ' LBN ' : ' Liban ' , ' LBR ' : ' Liberia ' , ' LBY ' : ' Libye ' , ' LCA ' : ' Sainte-Lucie ' , ' LIE ' : ' Liechtenstein ' , ' LKA ' : ' Sri Lanka ' , ' LSO ' : ' Lesotho ' , ' LTU ' : ' Lituanie ' , ' LUX ' : ' Luxembourg ' , ' LVA ' : ' Lettonie ' , ' MAC ' : ' Macao ' , ' MAF ' : ' Sint-Maarten ' , ' MAR ' : ' Maroc ' , ' MCO ' : ' Monaco ' , ' MDA ' : ' Moldavie ' , ' MDG ' : ' Madagascar ' , ' MDV ' : ' Maldives ' , ' MEX ' : ' Mexique ' , ' MHL ' : ' Marshall ' , ' MKD ' : ' Macedoine ' , ' MLI ' : ' Mali ' , ' MLT ' : ' Malte ' , ' MMR ' : ' Birmanie ' , ' MNE ' : ' Monténégro ' , ' MNG ' : ' Mongolie ' , ' MNP ' : ' Îles Mariannes du Nord ' , ' MOZ ' : ' Mozambique ' , ' MRT ' : ' Mauritanie ' , ' MSR ' : ' Montserrat ' , ' MTQ ' : ' Martinique ' , ' MUS ' : ' Maurice ' , ' MWI ' : ' Malawi ' , ' MYS ' : ' Malaisie ' , ' MYT ' : ' Mayotte ' , ' NAM ' : ' Namibie ' , ' NCL ' : ' Nouvelle-Calédonie ' , ' NER ' : ' Niger ' , ' NFK ' : ' Île Norfolk ' , ' NGA ' : ' Nigeria ' , ' NIC ' : ' Nicaragua ' , ' NIU ' : ' Niue ' , ' NLD ' : ' Pays-Bas ' , ' NOR ' : ' Norvège ' , ' NPL ' : ' Nepal ' , ' NRU ' : ' Nauru ' , ' NZL ' : ' Nouvelle-Zélande ' , ' OMN ' : ' Oman ' , ' PAK ' : ' Pakistan ' , ' PAN ' : ' Panama ' , ' PCN ' : ' Îles Pitcairn ' , ' PER ' : ' Pérou ' , ' PHL ' : ' Philippines ' , ' PLW ' : ' Palaos ' , ' PNG ' : ' Papouasie-Nouvelle-Guinée ' , ' POL ' : ' Pologne ' , ' PRI ' : ' Porto Rico ' , ' PRK ' : ' Corée du Nord ' , ' PRT ' : ' Portugal ' , ' PRY ' : ' Paraguay ' , ' PSE ' : ' Palestine ' , ' PYF ' : ' Polynésie française ' , ' QAT ' : ' Qatar ' , ' REU ' : ' Réunion ' , ' ROU ' : ' Roumanie ' , ' RUS ' : ' Russie ' , ' RWA ' : ' Rwanda ' , ' SAU ' : ' Arabie saoudite ' , ' SDN ' : ' Soudan ' , ' SEN ' : ' Sénégal ' , ' SGP ' : ' Singapour ' , ' SGS ' : ' Georgie du Sud-et-les iles Sandwich du Sud ' , ' SHN ' : ' Sainte-Hélène, Ascension et Tristan da Cunha ' , ' SJM ' : ' Svalbard et île Jan Mayen ' , ' SLB ' : ' Salomon ' , ' SLE ' : ' Sierra Leone ' , ' SLV ' : ' Salvador ' , ' SMR ' : ' Saint-Marin ' , ' SOM ' : ' Somalie ' , ' SPM ' : ' Saint-Pierre-et-Miquelon ' , ' SRB ' : ' Serbie ' , ' SSD ' : ' Soudan du Sud ' , ' STP ' : ' Sao Tomé-et-Principe ' , ' SUR ' : ' Suriname ' , ' SVK ' : ' Slovaquie ' , ' SVN ' : ' Slovénie ' , ' SWE ' : ' Suède ' , ' SWZ ' : ' eSwatani ' , ' SXM ' : ' Saint-Martin ' , ' SYC ' : ' Seychelles ' , ' SYR ' : ' Syrie ' , ' TCA ' : ' Îles Turques-et-Caïques ' , ' TCD ' : ' Tchad ' , ' TGO ' : ' Togo ' , ' THA ' : ' Thaïlande ' , ' TJK ' : ' Tadjikistan ' , ' TKL ' : ' Tokelau ' , ' TKM ' : ' Turkmenistan ' , ' TLS ' : ' Timor oriental ' , ' TON ' : ' Tonga ' , ' TTO ' : ' Trinité-et-Tobago ' , ' TUN ' : ' Tunisie ' , ' TUR ' : ' Turquie ' , ' TUV ' : ' Tuvalu ' , ' TWN ' : ' Taiwan ' , ' TZA ' : ' Tanzanie ' , ' UGA ' : ' Ouganda ' , ' UKR ' : ' Ukraine ' , ' URY ' : ' Uruguay ' , ' USA ' : ' Etats-Unis ' , ' UZB ' : ' Ouzbékistan ' , ' VAT ' : ' Saint-Siège (État de la Cité du Vatican) ' , ' VCT ' : ' Saint-Vincent-et-les-Grenadines ' , ' VEN ' : ' Venezuela ' , ' VGB ' : ' Îles Vierges britanniques ' , ' VIR ' : ' Îles Vierges des États-Unis ' , ' VNM ' : ' Viêt Nam ' , ' VUT ' : ' Vanuatu ' , ' WLF ' : ' Wallis-et-Futuna ' , ' WSM ' : ' Samoa ' , ' XKX ' : ' Kosovo ' , ' YEM ' : ' Yémen ' , ' ZAF ' : ' Afrique du Sud ' , ' ZMB ' : ' Zambie ' , ' ZWE ' : ' Zimbabwe ' , ' NTZ ' : ' Zone neutre ' , ' UNO ' : ' Fonctionnaire des Nations Unies ' , ' UNA ' : " Fonctionnaire d ' une organisation affiliée aux Nations Unies " , ' UNK ' : ' Représentant des Nations Unies au Kosovo ' , ' XXA ' : ' Apatride Convention 1954 ' , ' XXB ' : ' Réfugié Convention 1954 ' , ' XXC ' : ' Réfugié autre ' , ' XXX ' : ' Résident Légal de Nationalité Inconnue ' , ' D ' : ' Allemagne ' , ' EUE ' : ' Union Européenne ' , ' GBD ' : " Citoyen Britannique d ' Outre-mer (BOTC) " , ' GBN ' : ' British National (Overseas) ' , ' GBO ' : ' British Overseas Citizen ' , ' GBP ' : ' British Protected Person ' , ' GBS ' : ' British Subject ' , ' XBA ' : ' Banque Africaine de Développement ' , ' XIM ' : " Banque Africaine d ' Export– Import " , ' XCC ' : ' Caribbean Community or one of its emissaries ' , ' XCO ' : ' Common Market for Eastern and Southern Africa ' , ' XEC ' : ' Economic Community of West African States ' , ' XPO ' : ' International Criminal Police Or
P = [ ' 11222333333333333333333333333333333333333333|444444444566677777789AAAAAABCCCCCCCCCCCCCCDE ' , { ' 1 ' : ' 2|CODE|P* ' , ' 2 ' : ' 3|PAYS|AAA ' , ' 3 ' : ' 39|NOM|&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& ' , ' 4 ' : ' 9|NO|********* ' , ' 5 ' : ' 1|CTRL|4 ' , ' 6 ' : ' 3|NAT|AAA ' , ' 7 ' : ' 6|BDATE|000000 ' , ' 8 ' : ' 1|CTRL|7 ' , ' 9 ' : ' 1|SEX|A ' , ' A ' : ' 6|EDATE|000000 ' , ' B ' : ' 1|CTRL|A ' , ' C ' : ' 14|FACULT|************** ' , ' D ' : ' 1|CTRLF|C ' , ' E ' : ' 1|CTRL|4578ABCD ' } , ' Passeport ' ]
IP = [ ' 112223333333334555555555555555|66666678999999ABBBCCCCCCCCCCCD ' , { ' 1 ' : ' 2|CODE|IP ' , ' 2 ' : ' 3|PAYS|AAA ' , ' 3 ' : ' 9|NO|********* ' , ' 4 ' : ' 1|CTRL|3 ' , ' 5 ' : ' 15|FACULT|*************** ' , ' 6 ' : ' 6|BDATE|000000 ' , ' 7 ' : ' 1|CTRL|6 ' , ' 8 ' : ' 1|SEX|A ' , ' 9 ' : ' 6|EDATE|000000 ' , ' A ' : ' 1|CTRL|9 ' , ' B ' : ' 3|NAT|AAA ' , ' C ' : ' 11|FACULT|*********** ' , ' D ' : ' 1|CTRL|345679AC ' } , ' Carte-passeport ' ]
I_ = [ ' 112223333333334555555555555555|66666678999999ABBBCCCCCCCCCCCD ' , { ' 1 ' : ' 2|CODE|I* ' , ' 2 ' : ' 3|PAYS|AAA ' , ' 3 ' : ' 9|NO|********* ' , ' 4 ' : ' 1|CTRL|3 ' , ' 5 ' : ' 15|FACULT|*************** ' , ' 6 ' : ' 6|BDATE|000000 ' , ' 7 ' : ' 1|CTRL|6 ' , ' 8 ' : ' 1|SEX|A ' , ' 9 ' : ' 6|EDATE|000000 ' , ' A ' : ' 1|CTRL|9 ' , ' B ' : ' 3|NAT|AAA ' , ' C ' : ' 11|FACULT|*********** ' , ' D ' : ' 1|CTRL|345679AC ' } , " Titre d ' identité/de voyage " ]
AC = [ ' 112223333333334EEE555555555555|66666678999999ABBBCCCCCCCCCCCD ' , { ' 1 ' : ' 2|CODE|AC ' , ' 2 ' : ' 3|PAYS|AAA ' , ' 3 ' : ' 9|NO|********* ' , ' 4 ' : ' 1|CTRL|3 ' , ' 5 ' : ' 15|FACULT|*************** ' , ' 6 ' : ' 6|BDATE|000000 ' , ' 7 ' : ' 1|CTRL|6 ' , ' 8 ' : ' 1|SEX|A ' , ' 9 ' : ' 6|EDATE|000000 ' , ' A ' : ' 1|CTRL|9 ' , ' B ' : ' 3|NAT|AAA ' , ' C ' : ' 11|FACULT|*********** ' , ' D ' : ' 1|CTRL|345679AC ' , ' E ' : ' 3|INDIC|AA& ' } , " Certificat de membre d ' équipage " ]
VA = [ ' 11222333333333333333333333333333333333333333|444444444566677777789AAAAAABCCCCCCCCCCCCCCDE ' , { ' 1 ' : ' 2|CODE|V* ' , ' 2 ' : ' 3|PAYS|AAA ' , ' 3 ' : ' 39|NOM|&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& ' , ' 4 ' : ' 9|NO|********* ' , ' 5 ' : ' 1|CTRL|4 ' , ' 6 ' : ' 3|NAT|AAA ' , ' 7 ' : ' 6|BDATE|000000 ' , ' 8 ' : ' 1|CTRL|7 ' , ' 9 ' : ' 1|SEX|A ' , ' A ' : ' 6|EDATE|000000 ' , ' B ' : ' 1|CTRL|A ' , ' C ' : ' 14|FACULT|************** ' } , ' Visa de type A ' ]
VB = [ ' 112223333333333333333333333333333333|444444444566677777789AAAAAABCCCCCC ' , { ' 1 ' : ' 2|CODE|V* ' , ' 2 ' : ' 3|PAYS|AAA ' , ' 3 ' : ' 31|NOM|&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& ' , ' 4 ' : ' 9|NO|********* ' , ' 5 ' : ' 1|CTRL|4 ' , ' 6 ' : ' 3|NAT|AAA ' , ' 7 ' : ' 6|BDATE|000000 ' , ' 8 ' : ' 1|CTRL|7 ' , ' 9 ' : ' 1|SEX|A ' , ' A ' : ' 6|EDATE|000000 ' , ' B ' : ' 1|CTRL|A ' , ' C ' : ' 8|FACULT|******** ' } , ' Visa de type B ' ]
I__ = [ ' 112223333333333333333333333333333333|444444444566677777789AAAAAABCCCCCCCD ' , { ' 1 ' : ' 2|CODE|I* ' , ' 2 ' : ' 3|PAYS|AAA ' , ' 3 ' : ' 31|NOM|&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& ' , ' 4 ' : ' 9|NO|********* ' , ' 5 ' : ' 1|CTRL|4 ' , ' 6 ' : ' 3|NAT|AAA ' , ' 7 ' : ' 6|BDATE|000000 ' , ' 8 ' : ' 1|CTRL|7 ' , ' 9 ' : ' 1|SEX|A ' , ' A ' : ' 6|EDATE|000000 ' , ' B ' : ' 1|CTRL|A ' , ' C ' : ' 7|FACULT|******* ' , ' D ' : ' 1|CTRL|4578ABC ' } , " Pièce d ' identité/de voyage " ]
ID = [ ' 112223333333333333333333333333444444|555566677777899999999999999AAAAAABCD ' , { ' 1 ' : ' 2|CODE|ID ' , ' 2 ' : ' 3|PAYS|AAA ' , ' 3 ' : ' 25|NOM|&&&&&&&&&&&&&&&&&&&&&&&&& ' , ' 4 ' : ' 6|NOINT|000*** ' , ' 5 ' : ' 4|DDATE|0000 ' , ' 6 ' : ' 3|NOINT2|000 ' , ' 7 ' : ' 5|NOINT3|00000 ' , ' 8 ' : ' 1|CTRL|567 ' , ' 9 ' : ' 14|PRENOM|A ' , ' A ' : ' 6|BDATE|000000 ' , ' B ' : ' 1|CTRL|A ' , ' C ' : ' 1|SEX|A ' , ' D ' : ' 1|CTRL|123456789ABC ' } , " Pièce d ' identité FR " ]
DL = [ ' 112223333333334555555666666667| ' , { ' 1 ' : ' 2|CODE|D1 ' , ' 2 ' : ' 3|PAYS|AAA ' , ' 3 ' : ' 9|NO|00AA00000 ' , ' 4 ' : ' 1|CTRL|123 ' , ' 5 ' : ' 6|EDATE|000000 ' , ' 6 ' : ' 8|NOM|&&&&&&&& ' , ' 7 ' : ' 1|CTRL|123456 ' } , ' Permis de conduire ' ]
TYPES = [ ID , I__ , VB , VA , AC , I_ , IP , P , DL ]
2018-08-29 17:04:00 +02:00
class AESCipher ( object ) :
2019-06-30 17:54:41 +02:00
def __init__ ( self , key ) :
2018-08-29 17:04:00 +02:00
self . bs = 32
self . key = hashlib . sha256 ( key . encode ( ) ) . digest ( )
def encrypt ( self , raw ) :
raw = self . _pad ( raw )
iv = Random . new ( ) . read ( AES . block_size )
cipher = AES . new ( self . key , AES . MODE_CBC , iv )
return base64 . b64encode ( iv + cipher . encrypt ( raw ) )
def decrypt ( self , enc ) :
enc = base64 . b64decode ( enc )
iv = enc [ : AES . block_size ]
cipher = AES . new ( self . key , AES . MODE_CBC , iv )
return self . _unpad ( cipher . decrypt ( enc [ AES . block_size : ] ) ) . decode ( ' utf-8 ' )
def _pad ( self , s ) :
return s + ( self . bs - len ( s ) % self . bs ) * chr ( self . bs - len ( s ) % self . bs )
@staticmethod
def _unpad ( s ) :
2019-06-30 17:54:41 +02:00
return s [ : - ord ( s [ len ( s ) - 1 : ] ) ]
2018-08-29 17:04:00 +02:00
2019-06-30 17:54:41 +02:00
class Download :
2018-08-29 17:04:00 +02:00
2019-06-30 17:54:41 +02:00
def __init__ ( self , url , localfile , namefile , opener , p , canvas , message , logger ) :
2018-08-29 17:04:00 +02:00
from socket import timeout
self . retry = 6
self . logger = logger
self . opener = opener
self . url = url
self . localfile = localfile
self . success = False
self . time = 5
2019-06-30 17:54:41 +02:00
self . count = 0
2018-08-29 17:04:00 +02:00
self . success = False
self . downloading = True
2019-06-30 17:54:41 +02:00
self . logger . info ( ' [Download() class] : Initialization ok ' )
while not self . success and self . downloading :
2018-08-29 17:04:00 +02:00
try :
2019-06-30 17:54:41 +02:00
self . Err = ' '
self . _netfile = self . opener . open ( ( self . url ) , timeout = ( self . time ) )
2018-08-29 17:04:00 +02:00
self . filesize = float ( self . _netfile . info ( ) [ ' Content-Length ' ] )
2019-06-30 17:54:41 +02:00
if os . path . exists ( self . localfile ) :
if os . path . isfile ( self . localfile ) :
self . count = os . path . getsize ( self . localfile )
2018-08-29 17:04:00 +02:00
if self . count > = self . filesize :
self . downloading = False
self . success = True
self . _netfile . close ( )
return
2019-06-30 17:54:41 +02:00
if os . path . exists ( self . localfile ) :
if os . path . isfile ( self . localfile ) :
self . _netfile . close ( )
req = urllib2 . Request ( self . url )
req . add_header ( ' Range ' , ' bytes= %s - ' % self . count )
self . _netfile = self . opener . open ( req , timeout = ( self . time ) )
if self . downloading :
self . _outfile = open ( self . localfile , ' ab ' )
2018-08-29 17:04:00 +02:00
next = self . _netfile . read ( 1024 )
p . stop ( )
2019-06-30 17:54:41 +02:00
p . configure ( mode = ' determinate ' , value = 0 , maximum = 100 )
while len ( next ) > 0 :
if self . downloading :
self . _outfile . write ( next )
self . count + = len ( next )
next = self . _netfile . read ( 1024 )
Percent = int ( self . count / self . filesize * 100 )
p . configure ( mode = ' determinate ' , value = ( int ( Percent ) ) )
canvas . itemconfigure ( message , text = ( ' Téléchargement de ' + str ( namefile ) + ' de taille ' + str ( int ( self . filesize / 1024 / 1024 ) ) + ' Mo : ' + str ( Percent ) + ' % ' ) )
2018-08-29 17:04:00 +02:00
self . _netfile . close ( )
self . _outfile . close ( )
self . success = True
except urllib2 . HTTPError as e :
2019-06-30 17:54:41 +02:00
self . logger . error ( ' [Download() class] : HTTP ERROR ' + str ( e . code ) )
2018-08-29 17:04:00 +02:00
try :
self . _netfile . close ( )
self . _outfile . close ( )
except Exception as err :
2019-06-30 17:54:41 +02:00
self . logger . critical ( ' [Download() class] : FILE I/O ERROR : ' + str ( err ) )
2018-08-29 17:04:00 +02:00
self . retry + = - 1
2019-06-30 17:54:41 +02:00
canvas . itemconfigure ( message , text = ( ' Erreur HTTP ' + str ( e . code ) + ' . Nouvelles tentatives : ' + str ( self . retry ) ) )
2018-08-29 17:04:00 +02:00
if self . retry < = 0 :
self . downloading = False
except timeout as e :
2019-06-30 17:54:41 +02:00
self . logger . error ( ' [Download() class] : TIMEOUT ERROR : ' + str ( e ) )
2018-08-29 17:04:00 +02:00
try :
self . _netfile . close ( )
self . _outfile . close ( )
except Exception as err :
2019-06-30 17:54:41 +02:00
self . logger . critical ( ' [Download() class] : FILE I/O ERROR : ' + str ( err ) )
2018-08-29 17:04:00 +02:00
self . retry + = - 1
self . time * = 2
2019-06-30 17:54:41 +02:00
canvas . itemconfigure ( message , text = ( ' Connexion expirée. Nouvelles tentatives : ' + str ( self . retry ) + ' , ' + str ( self . time ) + ' s ' ) )
2018-08-29 17:04:00 +02:00
if self . retry < = 0 :
self . downloading = False
except IOError as e :
2019-06-30 17:54:41 +02:00
self . logger . error ( ' [Download() class] : I/O ERROR : ' + str ( e ) )
2018-08-29 17:04:00 +02:00
try :
self . _netfile . close ( )
self . _outfile . close ( )
except Exception as err :
2019-06-30 17:54:41 +02:00
self . logger . critical ( ' [Download() class] : FILE I/O ERROR : ' + str ( err ) )
2018-08-29 17:04:00 +02:00
self . retry + = - 1
self . time * = 2
2019-06-30 17:54:41 +02:00
canvas . itemconfigure ( message , text = ( ' Connexion expirée. Nouvelles tentatives : ' + str ( self . retry ) + ' , ' + str ( self . time ) + ' s ' ) )
2018-08-29 17:04:00 +02:00
if self . retry < = 0 :
self . downloading = False
except Exception as e :
2019-06-30 17:54:41 +02:00
self . logger . error ( ' [Download() class] : UNKNOWN ERROR : ' + str ( e ) )
2018-08-29 17:04:00 +02:00
try :
self . _netfile . close ( )
self . _outfile . close ( )
except Exception as err :
2019-06-30 17:54:41 +02:00
self . logger . critical ( ' [Download() class] : FILE I/O ERROR : ' + str ( err ) )
2018-08-29 17:04:00 +02:00
self . retry + = - 1
2019-06-30 17:54:41 +02:00
canvas . itemconfigure ( message , text = ( ' Erreur inconnue. Nouvelles tentatives : ' + str ( self . retry ) ) )
2018-08-29 17:04:00 +02:00
if self . retry < = 0 :
self . downloading = False
2019-06-30 17:54:41 +02:00
2018-08-29 17:04:00 +02:00
class AutoScrollbar ( ttk . Scrollbar ) :
2019-06-30 17:54:41 +02:00
""" " A scrollbar that hides itself if it ' s not needed. Works only for grid geometry manager \" """
2018-08-29 17:04:00 +02:00
def set ( self , lo , hi ) :
2019-06-30 17:54:41 +02:00
if float ( lo ) < = 0.0 :
if float ( hi ) > = 1.0 :
self . grid_remove ( )
2018-08-29 17:04:00 +02:00
self . grid ( )
ttk . Scrollbar . set ( self , lo , hi )
def pack ( self , * * kw ) :
raise TclError ( ' Cannot use pack with the widget ' + self . __class__ . __name__ )
def place ( self , * * kw ) :
raise TclError ( ' Cannot use place with the widget ' + self . __class__ . __name__ )
2019-06-30 17:54:41 +02:00
2018-08-29 17:04:00 +02:00
class CanvasImage :
2019-06-30 17:54:41 +02:00
""" ' Display and zoom image ' """
2018-08-29 17:04:00 +02:00
def __init__ ( self , placeholder , file , type ) :
""" Initialize the ImageFrame """
2019-06-30 17:54:41 +02:00
self . type = type
2018-08-29 17:04:00 +02:00
self . angle = 0
2019-06-30 17:54:41 +02:00
self . imscale = 1.0
self . _CanvasImage__delta = 1.3
self . _CanvasImage__filter = Image . ANTIALIAS
self . _CanvasImage__previous_state = 0
self . path = file
self . _CanvasImage__imframe = ttk . Frame ( placeholder )
self . placeholder = placeholder
hbar = AutoScrollbar ( ( self . _CanvasImage__imframe ) , orient = ' horizontal ' )
vbar = AutoScrollbar ( ( self . _CanvasImage__imframe ) , orient = ' vertical ' )
2018-08-29 17:04:00 +02:00
hbar . grid ( row = 1 , column = 0 , sticky = ' we ' )
vbar . grid ( row = 0 , column = 1 , sticky = ' ns ' )
2019-06-30 17:54:41 +02:00
self . canvas = Canvas ( ( self . _CanvasImage__imframe ) , highlightthickness = 0 , xscrollcommand = ( hbar . set ) ,
yscrollcommand = ( vbar . set ) )
2018-08-29 17:04:00 +02:00
self . canvas . grid ( row = 0 , column = 0 , sticky = ' nswe ' )
2019-06-30 17:54:41 +02:00
self . canvas . update ( )
hbar . configure ( command = ( self . _CanvasImage__scroll_x ) )
vbar . configure ( command = ( self . _CanvasImage__scroll_y ) )
self . canvas . bind ( ' <Configure> ' , lambda event : self . _CanvasImage__show_image ( ) )
self . canvas . bind ( ' <ButtonPress-1> ' , self . _CanvasImage__move_from )
self . canvas . bind ( ' <B1-Motion> ' , self . _CanvasImage__move_to )
self . canvas . bind ( ' <MouseWheel> ' , self . _CanvasImage__wheel )
self . _CanvasImage__huge = False
self . _CanvasImage__huge_size = 14000
self . _CanvasImage__band_width = 1024
Image . MAX_IMAGE_PIXELS = 1000000000
with warnings . catch_warnings ( ) :
2018-08-29 17:04:00 +02:00
warnings . simplefilter ( ' ignore ' )
2019-06-30 17:54:41 +02:00
self . _CanvasImage__image = Image . open ( self . path )
self . imwidth , self . imheight = self . _CanvasImage__image . size
if self . imwidth * self . imheight > self . _CanvasImage__huge_size * self . _CanvasImage__huge_size :
if self . _CanvasImage__image . tile [ 0 ] [ 0 ] == ' raw ' :
self . _CanvasImage__huge = True
self . _CanvasImage__offset = self . _CanvasImage__image . tile [ 0 ] [ 2 ]
self . _CanvasImage__tile = [ self . _CanvasImage__image . tile [ 0 ] [ 0 ] ,
[
0 , 0 , self . imwidth , 0 ] ,
self . _CanvasImage__offset ,
self . _CanvasImage__image . tile [ 0 ] [ 3 ] ]
self . _CanvasImage__min_side = min ( self . imwidth , self . imheight )
self . _CanvasImage__pyramid = [ self . smaller ( ) ] if self . _CanvasImage__huge else [ Image . open ( self . path ) ]
self . _CanvasImage__ratio = max ( self . imwidth , self . imheight ) / self . _CanvasImage__huge_size if self . _CanvasImage__huge else 1.0
self . _CanvasImage__curr_img = 0
self . _CanvasImage__scale = self . imscale * self . _CanvasImage__ratio
self . _CanvasImage__reduction = 2
w , h = self . _CanvasImage__pyramid [ ( - 1 ) ] . size
while w > 512 and h > 512 :
w / = self . _CanvasImage__reduction
h / = self . _CanvasImage__reduction
2018-08-29 17:04:00 +02:00
try :
2019-06-30 17:54:41 +02:00
self . _CanvasImage__pyramid . append ( self . _CanvasImage__pyramid [ ( - 1 ) ] . resize ( ( int ( w ) , int ( h ) ) , self . _CanvasImage__filter ) )
2018-08-29 17:04:00 +02:00
except TypeError :
2019-06-30 17:54:41 +02:00
showerror ( title = ' Erreur de fichier ' , message = " Image incompatible. Merci d ' utiliser une autre image ou de la convertir dans un format standard accepté! " , parent = ( self . placeholder ) )
self . placeholder . parent . openerrored = True
self . placeholder . destroy ( )
self . destroy ( )
return
2018-08-29 17:04:00 +02:00
self . container = self . canvas . create_rectangle ( ( 0 , 0 , self . imwidth , self . imheight ) , width = 0 )
2019-06-30 17:54:41 +02:00
self . _CanvasImage__show_image ( )
self . canvas . focus_set ( )
2018-08-29 17:04:00 +02:00
def rotatem ( self ) :
self . angle + = 1
2019-06-30 17:54:41 +02:00
self . _CanvasImage__show_image ( )
2018-08-29 17:04:00 +02:00
def rotatep ( self ) :
self . angle - = 1
2019-06-30 17:54:41 +02:00
self . _CanvasImage__show_image ( )
2018-08-29 17:04:00 +02:00
def rotatemm ( self ) :
self . angle + = 90
2019-06-30 17:54:41 +02:00
self . _CanvasImage__show_image ( )
2018-08-29 17:04:00 +02:00
def rotatepp ( self ) :
self . angle - = 90
2019-06-30 17:54:41 +02:00
self . _CanvasImage__show_image ( )
2018-08-29 17:04:00 +02:00
def smaller ( self ) :
""" Resize image proportionally and return smaller image """
w1 , h1 = float ( self . imwidth ) , float ( self . imheight )
2019-06-30 17:54:41 +02:00
w2 , h2 = float ( self . _CanvasImage__huge_size ) , float ( self . _CanvasImage__huge_size )
2018-08-29 17:04:00 +02:00
aspect_ratio1 = w1 / h1
2019-06-30 17:54:41 +02:00
aspect_ratio2 = w2 / h2
2018-08-29 17:04:00 +02:00
if aspect_ratio1 == aspect_ratio2 :
image = Image . new ( ' RGB ' , ( int ( w2 ) , int ( h2 ) ) )
2019-06-30 17:54:41 +02:00
k = h2 / h1
w = int ( w2 )
else :
if aspect_ratio1 > aspect_ratio2 :
image = Image . new ( ' RGB ' , ( int ( w2 ) , int ( w2 / aspect_ratio1 ) ) )
k = h2 / w1
w = int ( w2 )
else :
image = Image . new ( ' RGB ' , ( int ( h2 * aspect_ratio1 ) , int ( h2 ) ) )
k = h2 / h1
w = int ( h2 * aspect_ratio1 )
i , j , n = 0 , 1 , round ( 0.5 + self . imheight / self . _CanvasImage__band_width )
2018-08-29 17:04:00 +02:00
while i < self . imheight :
2019-06-30 17:54:41 +02:00
band = min ( self . _CanvasImage__band_width , self . imheight - i )
self . _CanvasImage__tile [ 1 ] [ 3 ] = band
self . _CanvasImage__tile [ 2 ] = self . _CanvasImage__offset + self . imwidth * i * 3
self . _CanvasImage__image . close ( )
self . _CanvasImage__image = Image . open ( self . path )
self . _CanvasImage__image . size = ( self . imwidth , band )
self . _CanvasImage__image . tile = [ self . _CanvasImage__tile ]
cropped = self . _CanvasImage__image . crop ( ( 0 , 0 , self . imwidth , band ) )
image . paste ( cropped . resize ( ( w , int ( band * k ) + 1 ) , self . _CanvasImage__filter ) , ( 0 , int ( i * k ) ) )
2018-08-29 17:04:00 +02:00
i + = band
j + = 1
2019-06-30 17:54:41 +02:00
2018-08-29 17:04:00 +02:00
return image
def redraw_figures ( self ) :
""" Dummy function to redraw figures in the children classes """
pass
def grid ( self , * * kw ) :
""" Put CanvasImage widget on the parent widget """
2019-06-30 17:54:41 +02:00
( self . _CanvasImage__imframe . grid ) ( * * kw )
self . _CanvasImage__imframe . grid ( sticky = ' nswe ' )
self . _CanvasImage__imframe . rowconfigure ( 0 , weight = 1 )
self . _CanvasImage__imframe . columnconfigure ( 0 , weight = 1 )
2018-08-29 17:04:00 +02:00
def __scroll_x ( self , * args , * * kwargs ) :
""" Scroll canvas horizontally and redraw the image """
2019-06-30 17:54:41 +02:00
( self . canvas . xview ) ( * args )
self . _CanvasImage__show_image ( )
2018-08-29 17:04:00 +02:00
def __scroll_y ( self , * args , * * kwargs ) :
""" Scroll canvas vertically and redraw the image """
2019-06-30 17:54:41 +02:00
( self . canvas . yview ) ( * args )
self . _CanvasImage__show_image ( )
2018-08-29 17:04:00 +02:00
def __show_image ( self ) :
""" Show image on the Canvas. Implements correct image zoom almost like in Google Maps """
2019-06-30 17:54:41 +02:00
box_image = self . canvas . coords ( self . container )
box_canvas = ( self . canvas . canvasx ( 0 ) ,
self . canvas . canvasy ( 0 ) ,
self . canvas . canvasx ( self . canvas . winfo_width ( ) ) ,
self . canvas . canvasy ( self . canvas . winfo_height ( ) ) )
box_img_int = tuple ( map ( int , box_image ) )
box_scroll = [
min ( box_img_int [ 0 ] , box_canvas [ 0 ] ) , min ( box_img_int [ 1 ] , box_canvas [ 1 ] ) ,
max ( box_img_int [ 2 ] , box_canvas [ 2 ] ) , max ( box_img_int [ 3 ] , box_canvas [ 3 ] ) ]
if box_scroll [ 0 ] == box_canvas [ 0 ] :
if box_scroll [ 2 ] == box_canvas [ 2 ] :
box_scroll [ 0 ] = box_img_int [ 0 ]
box_scroll [ 2 ] = box_img_int [ 2 ]
if box_scroll [ 1 ] == box_canvas [ 1 ] and box_scroll [ 3 ] == box_canvas [ 3 ] :
box_scroll [ 1 ] = box_img_int [ 1 ]
box_scroll [ 3 ] = box_img_int [ 3 ]
self . canvas . configure ( scrollregion = ( tuple ( map ( int , box_scroll ) ) ) )
x1 = max ( box_canvas [ 0 ] - box_image [ 0 ] , 0 )
2018-08-29 17:04:00 +02:00
y1 = max ( box_canvas [ 1 ] - box_image [ 1 ] , 0 )
x2 = min ( box_canvas [ 2 ] , box_image [ 2 ] ) - box_image [ 0 ]
y2 = min ( box_canvas [ 3 ] , box_image [ 3 ] ) - box_image [ 1 ]
2019-06-30 17:54:41 +02:00
if int ( x2 - x1 ) > 0 :
if int ( y2 - y1 ) > 0 :
if self . _CanvasImage__huge :
if self . _CanvasImage__curr_img < 0 :
h = int ( ( y2 - y1 ) / self . imscale )
self . _CanvasImage__tile [ 1 ] [ 3 ] = h
self . _CanvasImage__tile [ 2 ] = self . _CanvasImage__offset + self . imwidth * int ( y1 / self . imscale ) * 3
self . _CanvasImage__image . close ( )
self . _CanvasImage__image = Image . open ( self . path )
self . _CanvasImage__image . size = ( self . imwidth , h )
self . _CanvasImage__image . tile = [ self . _CanvasImage__tile ]
image = self . _CanvasImage__image . crop ( ( int ( x1 / self . imscale ) , 0 , int ( x2 / self . imscale ) , h ) )
image = self . _CanvasImage__pyramid [ max ( 0 , self . _CanvasImage__curr_img ) ] . crop ( (
int ( x1 / self . _CanvasImage__scale ) , int ( y1 / self . _CanvasImage__scale ) ,
int ( x2 / self . _CanvasImage__scale ) , int ( y2 / self . _CanvasImage__scale ) ) )
self . resizedim = image . resize ( ( int ( x2 - x1 ) , int ( y2 - y1 ) ) , self . _CanvasImage__filter ) . rotate ( ( self . angle ) , resample = ( Image . BICUBIC ) , expand = 1 )
imagetk = ImageTk . PhotoImage ( ( self . resizedim ) , master = ( self . placeholder ) )
imageid = self . canvas . create_image ( ( max ( box_canvas [ 0 ] , box_img_int [ 0 ] ) ) , ( max ( box_canvas [ 1 ] , box_img_int [ 1 ] ) ) ,
anchor = ' nw ' ,
image = imagetk )
self . canvas . lower ( imageid )
self . canvas . imagetk = imagetk
2018-08-29 17:04:00 +02:00
def __move_from ( self , event ) :
""" Remember previous coordinates for scrolling with the mouse """
self . canvas . scan_mark ( event . x , event . y )
def __move_to ( self , event ) :
""" Drag (move) canvas to the new position """
2019-06-30 17:54:41 +02:00
self . canvas . scan_dragto ( ( event . x ) , ( event . y ) , gain = 1 )
self . _CanvasImage__show_image ( )
2018-08-29 17:04:00 +02:00
def outside ( self , x , y ) :
""" Checks if the point (x,y) is outside the image area """
2019-06-30 17:54:41 +02:00
bbox = self . canvas . coords ( self . container )
if bbox [ 0 ] < x < bbox [ 2 ] :
if bbox [ 1 ] < y < bbox [ 3 ] :
pass
return False
2018-08-29 17:04:00 +02:00
else :
2019-06-30 17:54:41 +02:00
return True
2018-08-29 17:04:00 +02:00
def __wheel ( self , event ) :
""" Zoom with mouse wheel """
2019-06-30 17:54:41 +02:00
x = self . canvas . canvasx ( event . x )
2018-08-29 17:04:00 +02:00
y = self . canvas . canvasy ( event . y )
2019-06-30 17:54:41 +02:00
if self . outside ( x , y ) :
return
2018-08-29 17:04:00 +02:00
scale = 1.0
2019-06-30 17:54:41 +02:00
if event . delta == - 120 :
if round ( self . _CanvasImage__min_side * self . imscale ) < int ( self . placeholder . winfo_screenheight ( ) ) :
return
self . imscale / = self . _CanvasImage__delta
scale / = self . _CanvasImage__delta
if event . delta == 120 :
2018-08-29 17:04:00 +02:00
i = min ( self . canvas . winfo_width ( ) , self . canvas . winfo_height ( ) ) >> 1
2019-06-30 17:54:41 +02:00
if i < self . imscale :
return
self . imscale * = self . _CanvasImage__delta
scale * = self . _CanvasImage__delta
k = self . imscale * self . _CanvasImage__ratio
self . _CanvasImage__curr_img = min ( - 1 * int ( math . log ( k , self . _CanvasImage__reduction ) ) , len ( self . _CanvasImage__pyramid ) - 1 )
self . _CanvasImage__scale = k * math . pow ( self . _CanvasImage__reduction , max ( 0 , self . _CanvasImage__curr_img ) )
self . canvas . scale ( ' all ' , x , y , scale , scale )
self . redraw_figures ( )
self . _CanvasImage__show_image ( )
2018-08-29 17:04:00 +02:00
def crop ( self , bbox ) :
""" Crop rectangle from the image and return it """
2019-06-30 17:54:41 +02:00
if self . _CanvasImage__huge :
band = bbox [ 3 ] - bbox [ 1 ]
self . _CanvasImage__tile [ 1 ] [ 3 ] = band
self . _CanvasImage__tile [ 2 ] = self . _CanvasImage__offset + self . imwidth * bbox [ 1 ] * 3
self . _CanvasImage__image . close ( )
self . _CanvasImage__image = Image . open ( self . path )
self . _CanvasImage__image . size = ( self . imwidth , band )
self . _CanvasImage__image . tile = [ self . _CanvasImage__tile ]
return self . _CanvasImage__image . crop ( ( bbox [ 0 ] , 0 , bbox [ 2 ] , band ) )
else :
return self . _CanvasImage__pyramid [ 0 ] . crop ( bbox )
2018-08-29 17:04:00 +02:00
def destroy ( self ) :
""" ImageFrame destructor """
2019-06-30 17:54:41 +02:00
self . _CanvasImage__image . close ( )
map ( lambda i : i . close , self . _CanvasImage__pyramid )
del self . _CanvasImage__pyramid [ : ]
del self . _CanvasImage__pyramid
2018-08-29 17:04:00 +02:00
self . canvas . destroy ( )
2019-06-30 17:54:41 +02:00
2018-08-29 17:04:00 +02:00
class OpenScan ( ttk . Frame ) :
2019-06-30 17:54:41 +02:00
""" ' Main window class ' """
def __init__ ( self , mainframe , fileorig , type , nframe = 1 , pagenum = 0 , file = None ) :
2018-08-29 17:04:00 +02:00
""" Initialize the main Frame """
2019-06-30 17:54:41 +02:00
if file == None :
file = fileorig
2018-08-29 17:04:00 +02:00
self . file = file
self . fileorig = fileorig
self . nframe = nframe
self . pagenum = pagenum
self . parent = mainframe . parent
ttk . Frame . __init__ ( self , master = mainframe )
self . master . title ( ' Ouvrir un scan... (Utilisez la roulette pour zoomer, clic gauche pour déplacer et clic droit pour sélectionner la MRZ) ' )
self . master . resizable ( width = False , height = False )
hs = self . winfo_screenheight ( )
2019-06-30 17:54:41 +02:00
w = int ( self . winfo_screenheight ( ) / 1.5 )
h = int ( self . winfo_screenheight ( ) / 2 )
ws = self . winfo_screenwidth ( )
hs = self . winfo_screenheight ( )
x = ws / 2 - w / 2
y = hs / 2 - h / 2
2018-08-29 17:04:00 +02:00
self . master . geometry ( ' %d x %d + %d + %d ' % ( w , h , x , y ) )
2019-06-30 17:54:41 +02:00
if getattr ( sys , ' frozen ' , False ) :
self . master . iconbitmap ( sys . _MEIPASS + ' \\ id-card.ico \\ id-card.ico ' )
2018-08-29 17:04:00 +02:00
else :
2019-06-30 17:54:41 +02:00
self . master . iconbitmap ( ' id-card.ico ' )
self . master . rowconfigure ( 0 , weight = 1 )
2018-08-29 17:04:00 +02:00
self . master . columnconfigure ( 0 , weight = 1 )
2019-06-30 17:54:41 +02:00
self . cadre = CanvasImage ( self . master , self . file , type )
2018-08-29 17:04:00 +02:00
self . cadre . grid ( row = 0 , column = 0 )
self . master . menubar = Menu ( self . master )
2019-06-30 17:54:41 +02:00
if type == 1 :
self . master . menubar . add_command ( label = ' Page précédente ' , command = ( self . pagep ) )
self . master . menubar . add_command ( label = ' Pivoter -90° ' , command = ( self . cadre . rotatemm ) )
self . master . menubar . add_command ( label = ' Pivoter -1° ' , command = ( self . cadre . rotatem ) )
self . master . menubar . add_command ( label = ' Pivoter +1° ' , command = ( self . cadre . rotatep ) )
self . master . menubar . add_command ( label = ' Pivoter +90° ' , command = ( self . cadre . rotatepp ) )
if type == 1 :
self . master . menubar . add_command ( label = ' Page suivante ' , command = ( self . pages ) )
self . master . config ( menu = ( self . master . menubar ) )
2018-08-29 17:04:00 +02:00
self . cadre . canvas . bind ( ' <ButtonPress-3> ' , self . motionprep )
self . cadre . canvas . bind ( ' <B3-Motion> ' , self . motionize )
self . cadre . canvas . bind ( ' <ButtonRelease-3> ' , self . motionend )
2019-06-30 17:54:41 +02:00
2018-08-29 17:04:00 +02:00
def pages ( self ) :
2019-06-30 17:54:41 +02:00
if self . pagenum + 1 < self . nframe :
2018-08-29 17:04:00 +02:00
im = Image . open ( self . fileorig )
2019-06-30 17:54:41 +02:00
im . seek ( self . pagenum + 1 )
newpath = CST_FOLDER + ' \\ temp ' + str ( random . randint ( 11111 , 99999 ) ) + ' .tif '
2018-08-29 17:04:00 +02:00
im . save ( newpath )
im . close ( )
self . cadre . destroy ( )
2019-06-30 17:54:41 +02:00
self . __init__ ( self . master , self . fileorig , 1 , self . nframe , self . pagenum + 1 , newpath )
2018-08-29 17:04:00 +02:00
def pagep ( self ) :
if self . pagenum - 1 > = 0 :
im = Image . open ( self . fileorig )
im . seek ( self . pagenum - 1 )
2019-06-30 17:54:41 +02:00
newpath = CST_FOLDER + ' \\ temp ' + str ( random . randint ( 11111 , 99999 ) ) + ' .tif '
2018-08-29 17:04:00 +02:00
im . save ( newpath )
im . close ( )
self . cadre . destroy ( )
2019-06-30 17:54:41 +02:00
self . __init__ ( self . master , self . fileorig , 1 , self . nframe , self . pagenum - 1 , newpath )
def motionprep ( self , event ) :
if hasattr ( self , ' rect ' ) :
2018-08-29 17:04:00 +02:00
self . begx = event . x
self . begy = event . y
self . ix = self . cadre . canvas . canvasx ( event . x )
self . iy = self . cadre . canvas . canvasy ( event . y )
2019-06-30 17:54:41 +02:00
self . cadre . canvas . coords ( self . rect , self . cadre . canvas . canvasx ( event . x ) , self . cadre . canvas . canvasy ( event . y ) , self . ix , self . iy )
2018-08-29 17:04:00 +02:00
else :
self . begx = event . x
self . begy = event . y
self . ix = self . cadre . canvas . canvasx ( event . x )
self . iy = self . cadre . canvas . canvasy ( event . y )
2019-06-30 17:54:41 +02:00
self . rect = self . cadre . canvas . create_rectangle ( ( self . cadre . canvas . canvasx ( event . x ) ) , ( self . cadre . canvas . canvasy ( event . y ) ) , ( self . ix ) , ( self . iy ) , outline = ' red ' )
def motionize ( self , event ) :
2018-08-29 17:04:00 +02:00
event . x
event . y
2019-06-30 17:54:41 +02:00
self . cadre . canvas . coords ( self . rect , self . ix , self . iy , self . cadre . canvas . canvasx ( event . x ) , self . cadre . canvas . canvasy ( event . y ) )
def motionend ( self , event ) :
2018-08-29 17:04:00 +02:00
self . endx = event . x
self . endy = event . y
2019-06-30 17:54:41 +02:00
self . imtotreat = self . cadre . resizedim . crop ( ( min ( self . begx , self . endx ) , min ( self . begy , self . endy ) , max ( self . endx , self . begx ) , max ( self . endy , self . begy ) ) )
2018-08-29 17:04:00 +02:00
im = self . imtotreat
import CNI_pytesseract as pytesseract
try :
2019-06-30 17:54:41 +02:00
os . environ [ ' PATH ' ] = CST_FOLDER + ' \\ Tesseract-OCR4 \\ '
os . environ [ ' TESSDATA_PREFIX ' ] = CST_FOLDER + ' \\ Tesseract-OCR4 \\ tessdata '
self . text = pytesseract . image_to_string ( im , lang = ' ocrb ' , boxes = False , config = ' --psm 6 --oem 0 -c tessedit_char_whitelist=ABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890< ' )
2018-08-29 17:04:00 +02:00
except pytesseract . TesseractNotFoundError as e :
try :
2019-06-30 17:54:41 +02:00
os . remove ( CST_FOLDER + ' \\ Tesseract-OCR4 \\ *.* ' )
2018-08-29 17:04:00 +02:00
except Exception :
pass
2019-06-30 17:54:41 +02:00
showerror ( ' Erreur de module OCR ' , ( ' Le module OCR localisé en ' + str ( os . environ [ ' PATH ' ] ) + ' est introuvable. Il sera réinstallé à la prochaine exécution ' ) , parent = self )
2018-08-29 17:04:00 +02:00
except pytesseract . TesseractError as e :
pass
2019-06-30 17:54:41 +02:00
2018-08-29 17:04:00 +02:00
self . master . success = False
dialogconf = OpenScanDialog ( self . master , self . text )
dialogconf . transient ( self )
dialogconf . grab_set ( )
self . wait_window ( dialogconf )
if self . master . success :
self . master . destroy ( )
2019-06-30 17:54:41 +02:00
2018-08-29 17:04:00 +02:00
class OpenScanWin ( Toplevel ) :
2019-06-30 17:54:41 +02:00
def __init__ ( self , parent , file , type , nframe = 1 ) :
2018-08-29 17:04:00 +02:00
super ( ) . __init__ ( parent )
self . parent = parent
app = OpenScan ( self , file , type , nframe )
2019-06-30 17:54:41 +02:00
2018-08-29 17:04:00 +02:00
class OpenScanDialog ( Toplevel ) :
2019-06-30 17:54:41 +02:00
2018-08-29 17:04:00 +02:00
def __init__ ( self , parent , text ) :
super ( ) . __init__ ( parent )
self . parent = parent
self . title ( ' Validation de la MRZ détectée ' )
self . resizable ( width = False , height = False )
2019-06-30 17:54:41 +02:00
self . termtext = Text ( self , state = ' normal ' , width = 45 , height = 2 , wrap = ' none ' , font = ' Terminal 17 ' , fg = ' #121f38 ' )
self . termtext . grid ( column = 0 , row = 0 , sticky = ' NEW ' , padx = 5 , pady = 5 )
self . termtext . insert ( ' end ' , text + ' \n ' )
self . button = Button ( self , text = ' Valider ' , command = ( self . valid ) )
self . button . grid ( column = 0 , row = 1 , sticky = ' S ' , padx = 5 , pady = 5 )
2018-08-29 17:04:00 +02:00
self . update ( )
hs = self . winfo_screenheight ( )
2019-06-30 17:54:41 +02:00
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
2018-08-29 17:04:00 +02:00
self . geometry ( ' %d x %d + %d + %d ' % ( w , h , x , y ) )
2019-06-30 17:54:41 +02:00
if getattr ( sys , ' frozen ' , False ) :
self . iconbitmap ( sys . _MEIPASS + ' \\ id-card.ico \\ id-card.ico ' )
2018-08-29 17:04:00 +02:00
else :
2019-06-30 17:54:41 +02:00
self . iconbitmap ( ' id-card.ico ' )
2018-08-29 17:04:00 +02:00
def valid ( self ) :
self . parent . parent . mrzdetected = self . termtext . get ( ' 1.0 ' , ' end ' )
2019-06-30 17:54:41 +02:00
texting = self . parent . parent . mrzdetected . replace ( ' ' , ' ' ) . replace ( ' \r ' , ' ' ) . split ( ' \n ' )
2018-08-29 17:04:00 +02:00
for i in range ( len ( texting ) ) :
for char in texting [ i ] :
2019-06-30 17:54:41 +02:00
if char not in ' ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789< ' :
showerror ( ' Erreur de validation ' , ' La MRZ soumise contient des caractères invalides ' , parent = self )
self . parent . parent . mrzdetected = ' '
2018-08-29 17:04:00 +02:00
return
2019-06-30 17:54:41 +02:00
2018-08-29 17:04:00 +02:00
self . parent . success = True
self . destroy ( )
2019-06-30 17:54:41 +02:00
2018-08-29 17:04:00 +02:00
class OpenPageDialog ( Toplevel ) :
2019-06-30 17:54:41 +02:00
2018-08-29 17:04:00 +02:00
def __init__ ( self , parent , number ) :
super ( ) . __init__ ( parent )
self . parent = parent
self . title ( " Choisir la page à afficher de l ' image selectionnée " )
self . resizable ( width = False , height = False )
2019-06-30 17:54:41 +02:00
self . termtext = Label ( self , text = ' Merci de selectionner un numéro de page dans la liste ci-dessous. ' )
self . termtext . grid ( column = 0 , row = 0 , sticky = ' N ' , padx = 5 , pady = 5 )
2018-08-29 17:04:00 +02:00
self . combotry = ttk . Combobox ( self )
2019-06-30 17:54:41 +02:00
self . combotry [ ' values ' ] = tuple ( str ( x ) for x in range ( 1 , number + 1 ) )
self . combotry . grid ( column = 0 , row = 1 , sticky = ' N ' , padx = 5 , pady = 5 )
self . button = Button ( self , text = ' Valider ' , command = ( self . valid ) )
self . button . grid ( column = 0 , row = 2 , sticky = ' S ' , padx = 5 , pady = 5 )
2018-08-29 17:04:00 +02:00
self . update ( )
hs = self . winfo_screenheight ( )
2019-06-30 17:54:41 +02:00
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
2018-08-29 17:04:00 +02:00
self . geometry ( ' %d x %d + %d + %d ' % ( w , h , x , y ) )
2019-06-30 17:54:41 +02:00
if getattr ( sys , ' frozen ' , False ) :
self . iconbitmap ( sys . _MEIPASS + ' \\ id-card.ico \\ id-card.ico ' )
2018-08-29 17:04:00 +02:00
else :
2019-06-30 17:54:41 +02:00
self . iconbitmap ( ' id-card.ico ' )
2018-08-29 17:04:00 +02:00
def valid ( self ) :
self . parent . page = self . combotry . current ( )
self . destroy ( )