mirror of
https://gitlab.os-k.eu/neox/CNIRevelator.git
synced 2023-08-25 14:03:10 +02:00
commit
9bc808d785
@ -1,2 +1,2 @@
|
||||
# ver|url|checksum, and | as separator, one version per ||
|
||||
|
||||
3.1.2|https://github.com/neox95/CNIRevelator/releases/download/3.1.1/CNIRevelator.zip|cb2f4999e7265297008074e0e2beacbb2943a004||
|
@ -23,22 +23,26 @@
|
||||
* along with CNIRevelator. If not, see <https:*www.gnu.org/licenses/>. *
|
||||
********************************************************************************
|
||||
"""
|
||||
|
||||
import sys
|
||||
# Import critical files
|
||||
import os
|
||||
import subprocess
|
||||
import threading
|
||||
import traceback
|
||||
import psutil
|
||||
|
||||
import lang # lang.py
|
||||
import logger # logger.py
|
||||
import globs # globs.py
|
||||
import critical # critical.py
|
||||
|
||||
# Import all other files and crash if necessary
|
||||
try:
|
||||
|
||||
import launcher # launcher.py"
|
||||
import updater # updater.py
|
||||
import globs # globs.py
|
||||
import pytesseract # pytesseract.py
|
||||
import logger # logger.py
|
||||
|
||||
|
||||
from main import * # main.py
|
||||
import ihm # ihm.py
|
||||
from tkinter.messagebox import *
|
||||
from tkinter import *
|
||||
except:
|
||||
critical.crashCNIR()
|
||||
|
||||
# Global handler
|
||||
logfile = logger.logCur
|
||||
@ -59,15 +63,17 @@ def main():
|
||||
text = 'Tesseract version ' + str(tesser_version) + ' Licensed Apache 2004 successfully initiated\n'
|
||||
mainw.logOnTerm(text)
|
||||
|
||||
mainw.logOnTerm('\n\nEntrez la première ligne de MRZ svp \n')
|
||||
mainw.logOnTerm('\n\n{} \n'.format(lang.all[globs.CNIRlang]["Please type a MRZ or open a scan"]))
|
||||
|
||||
# changelog
|
||||
if globs.CNIRNewVersion:
|
||||
showinfo('Changelog : résumé de mise à jour', ('Version du logiciel : CNIRevelator ' + globs.verstring_full + '\n\n' + globs.changelog), parent=mainw)
|
||||
mainw.after_idle(mainw.showChangeLog)
|
||||
|
||||
logfile.printdbg('main() : **** Launching App_main() ****')
|
||||
try:
|
||||
mainw.mainloop()
|
||||
except Exception as e:
|
||||
showerror("CNIRevelator Fatal Error", "An error has occured : {}".format(e), parent=mainw)
|
||||
showerror(lang.all[globs.CNIRlang]["CNIRevelator Fatal Error"], "{} : {}".format(lang.all[globs.CNIRlang]["An error has occured"],e), parent=mainw)
|
||||
logfile.printdbg('main() : **** Ending App_main() ****')
|
||||
|
||||
logfile.printdbg('*** CNIRevelator LOGFILE. Goodbye World ! ***')
|
||||
@ -75,16 +81,27 @@ def main():
|
||||
|
||||
|
||||
## BOOTSTRAP OF CNIREVELATOR
|
||||
try:
|
||||
|
||||
try:
|
||||
# LANGUAGE
|
||||
lang.readLang()
|
||||
except:
|
||||
critical.crashCNIR()
|
||||
updater.exitProcess(1)
|
||||
|
||||
from main import * # main.py
|
||||
# GO
|
||||
try:
|
||||
launcherThread = threading.Thread(target=updater.umain, daemon=False)
|
||||
launcher.lmain(launcherThread)
|
||||
except Exception:
|
||||
critical.crashCNIR()
|
||||
updater.exitProcess(1)
|
||||
|
||||
if updater.UPDATE_IS_MADE:
|
||||
# Launch app !
|
||||
args = updater.UPATH + '\\CNIRevelator.exe ' + globs.CNIRFolder
|
||||
args = updater.UPATH + '\\CNIRevelator.exe' + " DELETE " + globs.CNIRFolder
|
||||
cd = updater.UPATH
|
||||
for i in range(0,3):
|
||||
try:
|
||||
@ -99,6 +116,10 @@ if updater.UPDATE_IS_MADE:
|
||||
try:
|
||||
main()
|
||||
except Exception as e:
|
||||
traceback.print_exc(file=sys.stdout)
|
||||
critical.crashCNIR()
|
||||
updater.exitProcess(1)
|
||||
|
||||
except:
|
||||
critical.crashCNIR()
|
||||
|
||||
updater.exitProcess(0)
|
66
src/critical.py
Normal file
66
src/critical.py
Normal file
@ -0,0 +1,66 @@
|
||||
"""
|
||||
********************************************************************************
|
||||
* CNIRevelator *
|
||||
* *
|
||||
* Desc: Critical Stuff for CNIRevelator *
|
||||
* *
|
||||
* 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 tkinter.messagebox import *
|
||||
from importlib import reload
|
||||
from tkinter import *
|
||||
import webbrowser
|
||||
import traceback
|
||||
import psutil
|
||||
import os
|
||||
|
||||
import lang # lang.py
|
||||
import logger # logger.py
|
||||
import globs # globs.py
|
||||
|
||||
def crashCNIR(shutdown=True):
|
||||
"""
|
||||
very last solution
|
||||
"""
|
||||
|
||||
try:
|
||||
root = Tk()
|
||||
root.withdraw()
|
||||
logfile = logger.logCur
|
||||
logfile.printerr("FATAL ERROR : see traceback below.\n{}".format(traceback.format_exc()))
|
||||
showerror(lang.all[globs.CNIRlang]["CNIRevelator Fatal Eror"], lang.all[globs.CNIRlang]["CNIRevelator crashed because a fatal error occured. View log for more infos and please open an issue on Github"], parent=root)
|
||||
res = askquestion(lang.all[globs.CNIRlang]["CNIRevelator Fatal Eror"], lang.all[globs.CNIRlang]["Would you like to open the log file ?"], parent=root)
|
||||
if res == "yes":
|
||||
webbrowser.open_new(globs.CNIRErrLog)
|
||||
res = askquestion(lang.all[globs.CNIRlang]["CNIRevelator Fatal Eror"], lang.all[globs.CNIRlang]["Would you like to open an issue on Github to report this bug ?"], parent=root)
|
||||
if res == "yes":
|
||||
webbrowser.open_new("https://github.com/neox95/CNIRevelator/issues")
|
||||
root.destroy()
|
||||
|
||||
# Quit ?
|
||||
if not shutdown:
|
||||
return
|
||||
|
||||
# Quit totally without remain in memory
|
||||
for process in psutil.process_iter():
|
||||
if process.pid == os.getpid():
|
||||
process.terminate()
|
||||
sys.exit(arg)
|
||||
except:
|
||||
traceback.print_exc()
|
@ -32,9 +32,11 @@ from Crypto.Cipher import AES
|
||||
from requests import Session
|
||||
from time import time
|
||||
|
||||
import critical # critical.py
|
||||
import logger # logger.py
|
||||
import globs # globs.py
|
||||
import ihm # ihm.py
|
||||
import lang # lang.py
|
||||
|
||||
class AESCipher(object):
|
||||
|
||||
@ -184,8 +186,8 @@ class newdownload:
|
||||
|
||||
reducedFilename = filename.split("\\")[-1]
|
||||
|
||||
launcherWindow.printmsg('Downloading {}'.format(title))
|
||||
logfile.printdbg('Requesting download of {}'.format(reducedFilename))
|
||||
launcherWindow.printmsg('{} {}'.format(lang.all[globs.CNIRlang]["Downloading"], title))
|
||||
logfile.printdbg('{} {}'.format("Downloading", reducedFilename))
|
||||
|
||||
try:
|
||||
os.remove(filename)
|
||||
@ -201,12 +203,12 @@ class newdownload:
|
||||
|
||||
launcherWindow.progressBar.stop()
|
||||
launcherWindow.progressBar.configure(mode='determinate', value=(int(Percent)), maximum=100)
|
||||
launcherWindow.printmsg('Downloading {}'.format(title) + ' : {:4.2f} %'.format(Percent))
|
||||
launcherWindow.printmsg('{} {}'.format(lang.all[globs.CNIRlang]["Downloading"], title) + ' : {:4.2f} %'.format(Percent))
|
||||
|
||||
launcherWindow.progressBar.configure(mode='indeterminate', value=0, maximum=20)
|
||||
launcherWindow.progressBar.start()
|
||||
|
||||
logfile.printdbg('Successful retrieved {}'.format(filename))
|
||||
logfile.printdbg('{} {}'.format(lang.all[globs.CNIRlang]["Successful retrieved"], filename))
|
||||
|
||||
return filename
|
||||
|
||||
|
30
src/globs.py
30
src/globs.py
@ -26,12 +26,9 @@ import os
|
||||
|
||||
# CNIRevelator version
|
||||
verType = "final release"
|
||||
version = [3, 1, 0]
|
||||
version = [3, 1, 1]
|
||||
verstring_full = "{}.{}.{} {}".format(version[0], version[1], version[2], verType)
|
||||
verstring = "{}.{}".format(version[0], version[1])
|
||||
debug = True
|
||||
|
||||
changelog = "Version 3.1.0 \nMise-à-jour majeure avec les progressions suivantes :\n- Modifications cosmétiques de l'interface utilisateur\n- Stabilisation des changements effectués sur la version mineure 3.0 : interface utilisateur, OCR, VISA A et B, logging"
|
||||
|
||||
CNIRTesserHash = '5b58db27f7bc08c58a2cb33d01533b034b067cf8'
|
||||
CNIRFolder = os.getcwd()
|
||||
@ -47,3 +44,28 @@ CNIRMainLog = CNIRFolder + '\\logs\\main.log'
|
||||
CNIRUrlConfig = CNIRFolder + '\\config\\urlconf.ig'
|
||||
CNIRVerStock = CNIRFolder + '\\downloads\\versions.lst'
|
||||
CNIREnv = CNIRFolder + '\\Data\\'
|
||||
|
||||
|
||||
CNIRTesserHash = '5b58db27f7bc08c58a2cb33d01533b034b067cf8'
|
||||
CNIRFolder = os.path.dirname(os.path.realpath(__file__))
|
||||
CNIRLColor = "#006699"
|
||||
CNIRName = "CNIRevelator {}".format(verstring)
|
||||
CNIRCryptoKey = '82Xh!efX3#@P~2eG'
|
||||
|
||||
CNIRLangFile = CNIRFolder + '\\config\\lang.ig'
|
||||
CNIRlang = "fr"
|
||||
|
||||
CNIRConfig = CNIRFolder + '\\config\\conf.ig'
|
||||
CNIRTesser = CNIRFolder + '\\Tesseract-OCR4\\'
|
||||
CNIRErrLog = CNIRFolder + '\\logs\\error.log'
|
||||
CNIRMainLog = CNIRFolder + '\\logs\\main.log'
|
||||
CNIRUrlConfig = CNIRFolder + '\\config\\urlconf.ig'
|
||||
CNIRVerStock = CNIRFolder + '\\downloads\\versions.lst'
|
||||
CNIREnv = CNIRFolder + '\\Data\\'
|
||||
|
||||
CNIRBetaURL = "https://raw.githubusercontent.com/neox95/CNIRevelator/v3.1/VERSIONS.LST"
|
||||
CNIRDefaultURL = "https://raw.githubusercontent.com/neox95/CNIRevelator/master/VERSIONS.LST"
|
||||
|
||||
CNIRNewVersion = False
|
||||
CNIROpenFile = False
|
||||
debug = True
|
187
src/ihm.py
187
src/ihm.py
@ -1,4 +1,4 @@
|
||||
"""
|
||||
"""
|
||||
********************************************************************************
|
||||
* CNIRevelator *
|
||||
* *
|
||||
@ -23,19 +23,22 @@
|
||||
********************************************************************************
|
||||
"""
|
||||
|
||||
from tkinter import *
|
||||
import webbrowser
|
||||
from tkinter.messagebox import *
|
||||
from tkinter import *
|
||||
from tkinter import filedialog
|
||||
from tkinter import ttk
|
||||
import cv2
|
||||
import PIL.Image, PIL.ImageTk
|
||||
import traceback
|
||||
import webbrowser
|
||||
import cv2
|
||||
|
||||
import critical # critical.py
|
||||
import logger # logger.py
|
||||
import globs # globs.py
|
||||
import lang # lang.py
|
||||
|
||||
import updater # updater.py
|
||||
import critical # critical.py
|
||||
|
||||
controlKeys = ["Escape", "Right", "Left", "Up", "Down", "Home", "End", "BackSpace", "Delete", "Inser", "Shift_L", "Shift_R", "Control_R", "Control_L"]
|
||||
|
||||
@ -117,21 +120,22 @@ class LoginDialog(Toplevel):
|
||||
self.login = ''
|
||||
super().__init__(parent)
|
||||
self.title(lang.all[globs.CNIRlang]["Connection"])
|
||||
Label(self, text='IPN : ').pack()
|
||||
self.entry_login = Entry(self)
|
||||
self["background"] = "white"
|
||||
Label(self, text='IPN : ', bg="white").pack(fill=Y)
|
||||
self.entry_login = ttk.Entry(self)
|
||||
self.entry_login.insert(0, '')
|
||||
self.entry_login.pack()
|
||||
Label(self, text='{} : '.format(lang.all[globs.CNIRlang]["Password"])).pack()
|
||||
self.entry_pass = Entry(self, show='*')
|
||||
Label(self, text='{} : '.format(lang.all[globs.CNIRlang]["Password"]), bg="white").pack(fill=Y)
|
||||
self.entry_pass = ttk.Entry(self, show='*')
|
||||
self.entry_pass.insert(0, '')
|
||||
self.entry_pass.pack()
|
||||
Button(self, text=lang.all[globs.CNIRlang]["Connection"], command=(self.connecti)).pack()
|
||||
self.entry_pass.pack(fill=Y)
|
||||
ttk.Button(self, text=lang.all[globs.CNIRlang]["Connection"], command=(self.connecti)).pack(fill=Y, pady=10)
|
||||
self.update()
|
||||
self.resizable(width=False, height=False)
|
||||
ws = self.winfo_screenwidth()
|
||||
hs = self.winfo_screenheight()
|
||||
w = hs / 10
|
||||
h = ws / 18
|
||||
self.update()
|
||||
w = self.winfo_reqwidth() + 5
|
||||
h = self.winfo_reqheight()
|
||||
if getattr(sys, 'frozen', False):
|
||||
self.iconbitmap(sys._MEIPASS + '\\id-card.ico\\id-card.ico')
|
||||
else:
|
||||
@ -146,6 +150,124 @@ class LoginDialog(Toplevel):
|
||||
self.key = self.entry_pass.get().strip()
|
||||
self.destroy()
|
||||
|
||||
class ChangelogDialog(Toplevel):
|
||||
|
||||
def __init__(self, parent, text):
|
||||
super().__init__(parent)
|
||||
|
||||
self.title(lang.all[globs.CNIRlang]["Show Changelog"])
|
||||
self["background"] = "white"
|
||||
|
||||
self.grid_columnconfigure(0, weight=1)
|
||||
self.grid_rowconfigure(0, weight=1)
|
||||
|
||||
self.text = Text(self, wrap='word', width=55, height=15, borderwidth=0, font="TkDefaultFont", bg="white")
|
||||
self.text.grid(column=0, row=0, sticky='EWNS', padx=5, pady=5)
|
||||
|
||||
ttk.Button(self, text="OK", command=(self.oki)).grid(column=0, row=1, pady=5)
|
||||
|
||||
self.scrollb = ttk.Scrollbar(self, command=(self.text.yview))
|
||||
self.scrollb.grid(column=1, row=0, sticky='EWNS', padx=5, pady=5)
|
||||
self.text['yscrollcommand'] = self.scrollb.set
|
||||
|
||||
self.text.insert('end', text)
|
||||
self.text['state'] = 'disabled'
|
||||
|
||||
self.update()
|
||||
self.resizable(width=False, height=False)
|
||||
ws = self.winfo_screenwidth()
|
||||
hs = self.winfo_screenheight()
|
||||
w = self.winfo_reqwidth() + 5
|
||||
h = self.winfo_reqheight()
|
||||
if getattr(sys, 'frozen', False):
|
||||
self.iconbitmap(sys._MEIPASS + '\\id-card.ico\\id-card.ico')
|
||||
else:
|
||||
self.iconbitmap('id-card.ico')
|
||||
x = ws / 2 - w / 2
|
||||
y = hs / 2 - h / 2
|
||||
self.geometry('%dx%d+%d+%d' % (w, h, x, y))
|
||||
self.bind("<Return>", self.oki)
|
||||
|
||||
def oki(self, event=None):
|
||||
self.destroy()
|
||||
|
||||
class langDialog(Toplevel):
|
||||
|
||||
def __init__(self, parent):
|
||||
super().__init__(parent)
|
||||
|
||||
self.title(lang.all[globs.CNIRlang]["Language"])
|
||||
|
||||
Label(self, text=lang.all[globs.CNIRlang]["Please choose your language : "]).pack(fill=Y)
|
||||
|
||||
vals = [i for i in lang.all]
|
||||
for i in range(len(lang.all)):
|
||||
ttk.Radiobutton(self, text=vals[i], command=self.createRegister(i), value=vals[i]).pack(fill=Y)
|
||||
|
||||
ttk.Button(self, text="OK", command=(self.oki)).pack(fill=Y, pady=5)
|
||||
|
||||
self.update()
|
||||
self.resizable(width=False, height=False)
|
||||
ws = self.winfo_screenwidth()
|
||||
hs = self.winfo_screenheight()
|
||||
w = self.winfo_reqwidth() + 5
|
||||
h = self.winfo_reqheight()
|
||||
if getattr(sys, 'frozen', False):
|
||||
self.iconbitmap(sys._MEIPASS + '\\id-card.ico\\id-card.ico')
|
||||
else:
|
||||
self.iconbitmap('id-card.ico')
|
||||
x = ws / 2 - w / 2
|
||||
y = hs / 2 - h / 2
|
||||
self.geometry('%dx%d+%d+%d' % (w, h, x, y))
|
||||
self.bind("<Return>", self.oki)
|
||||
|
||||
def oki(self, event=None):
|
||||
self.destroy()
|
||||
|
||||
def createRegister(self, i):
|
||||
def register():
|
||||
lang.updateLang([j for j in lang.all][i])
|
||||
return register
|
||||
|
||||
class updateSetDialog(Toplevel):
|
||||
|
||||
def __init__(self, parent):
|
||||
super().__init__(parent)
|
||||
|
||||
self.title(lang.all[globs.CNIRlang]["Update options"])
|
||||
|
||||
Label(self, text=lang.all[globs.CNIRlang]["Please choose your update channel : "]).pack(fill=Y)
|
||||
|
||||
self.vals = ["Stable", "Beta"]
|
||||
vals = self.vals
|
||||
for i in range(len(vals)):
|
||||
ttk.Radiobutton(self, text=vals[i], command=self.createRegister(i), value=vals[i]).pack(fill=Y)
|
||||
|
||||
ttk.Button(self, text="OK", command=(self.oki)).pack(fill=Y, pady=5)
|
||||
|
||||
self.update()
|
||||
self.resizable(width=False, height=False)
|
||||
ws = self.winfo_screenwidth()
|
||||
hs = self.winfo_screenheight()
|
||||
w = self.winfo_reqwidth() + 5
|
||||
h = self.winfo_reqheight()
|
||||
if getattr(sys, 'frozen', False):
|
||||
self.iconbitmap(sys._MEIPASS + '\\id-card.ico\\id-card.ico')
|
||||
else:
|
||||
self.iconbitmap('id-card.ico')
|
||||
x = ws / 2 - w / 2
|
||||
y = hs / 2 - h / 2
|
||||
self.geometry('%dx%d+%d+%d' % (w, h, x, y))
|
||||
self.bind("<Return>", self.oki)
|
||||
|
||||
def oki(self, event=None):
|
||||
self.destroy()
|
||||
|
||||
def createRegister(self, i):
|
||||
def register():
|
||||
updater.updateChannel(self.vals[i])
|
||||
return register
|
||||
|
||||
class LauncherWindow(Tk):
|
||||
|
||||
def __init__(self):
|
||||
@ -153,6 +275,12 @@ class LauncherWindow(Tk):
|
||||
Tk.__init__(self)
|
||||
self.resizable(width=False, height=False)
|
||||
|
||||
# icon
|
||||
if getattr(sys, 'frozen', False):
|
||||
self.iconbitmap(sys._MEIPASS + '\\id-card.ico\\id-card.ico')
|
||||
else:
|
||||
self.iconbitmap('id-card.ico')
|
||||
|
||||
# Setting up the geometry
|
||||
ws = self.winfo_screenwidth()
|
||||
hs = self.winfo_screenheight()
|
||||
@ -201,11 +329,6 @@ class LauncherWindow(Tk):
|
||||
self.update()
|
||||
self.progressBar.grid(row=1, sticky='S')
|
||||
|
||||
|
||||
if getattr(sys, 'frozen', False):
|
||||
self.iconbitmap(sys._MEIPASS + '\\id-card.ico\\id-card.ico')
|
||||
else:
|
||||
self.iconbitmap('id-card.ico')
|
||||
logfile = logger.logCur
|
||||
logfile.printdbg('Launcher IHM successful')
|
||||
self.protocol('WM_DELETE_WINDOW', lambda : 0)
|
||||
@ -233,22 +356,20 @@ class ResizeableCanvas(Canvas):
|
||||
# rescale all the objects tagged with the "all" tag
|
||||
self.scale("all",0,0,wscale,hscale)
|
||||
|
||||
def crashCNIR():
|
||||
"""
|
||||
last solution
|
||||
"""
|
||||
# Global handler
|
||||
logfile = logger.logCur
|
||||
# hide main window
|
||||
root = Tk()
|
||||
root.withdraw()
|
||||
logfile.printerr("FATAL ERROR : see traceback below.\n{}".format(traceback.format_exc()))
|
||||
showerror(lang.all[globs.CNIRlang]["CNIRevelator Fatal Eror"], lang.all[globs.CNIRlang]["CNIRevelator crashed because a fatal error occured. View log for more infos and please open an issue on Github"])
|
||||
res = askquestion(lang.all[globs.CNIRlang]["CNIRevelator Fatal Eror"], lang.all[globs.CNIRlang]["Would you like to open an issue on Github to report this bug ?"])
|
||||
if res == "yes":
|
||||
webbrowser.open_new("https://github.com/neox95/CNIRevelator/issues")
|
||||
root.destroy()
|
||||
class StatusBar(Frame):
|
||||
|
||||
def __init__(self, master):
|
||||
Frame.__init__(self, master)
|
||||
self.label = Label(self, bd=1, relief=SUNKEN, anchor=W)
|
||||
self.label.pack(fill=X)
|
||||
|
||||
def set(self, text):
|
||||
self.label.config(text="Document : " + text.lower())
|
||||
self.label.update_idletasks()
|
||||
|
||||
def clear(self):
|
||||
self.label.config(text="")
|
||||
self.label.update_idletasks()
|
||||
|
||||
## Global Handler
|
||||
launcherWindowCur = LauncherWindow()
|
||||
|
1465
src/lang.py
Normal file
1465
src/lang.py
Normal file
File diff suppressed because it is too large
Load Diff
@ -26,12 +26,13 @@
|
||||
import sys
|
||||
import os
|
||||
import threading
|
||||
import traceback
|
||||
|
||||
import critical # critical.py
|
||||
import updater # updater.py
|
||||
import ihm # ihm.py
|
||||
import globs # globs.py
|
||||
import logger # logger.py
|
||||
import lang # lang.py
|
||||
|
||||
## Main function
|
||||
def lmain(mainThread):
|
||||
@ -44,7 +45,7 @@ def lmain(mainThread):
|
||||
|
||||
# Hello user
|
||||
launcherWindow.progressBar.configure(mode='indeterminate', value=0, maximum=20)
|
||||
launcherWindow.printmsg('Starting...')
|
||||
launcherWindow.printmsg(lang.all[globs.CNIRlang]["Starting..."])
|
||||
launcherWindow.progressBar.start()
|
||||
|
||||
# Starting the main update thread
|
||||
|
@ -26,6 +26,7 @@
|
||||
import logging
|
||||
import os
|
||||
|
||||
import critical # critical.py
|
||||
import globs # globs.py
|
||||
|
||||
## The logging class
|
||||
|
479
src/main.py
479
src/main.py
@ -31,29 +31,37 @@ from tkinter import filedialog
|
||||
from tkinter import ttk
|
||||
import threading
|
||||
from datetime import datetime
|
||||
from importlib import reload
|
||||
import re
|
||||
import traceback
|
||||
import cv2
|
||||
import PIL.Image, PIL.ImageTk
|
||||
import os, shutil
|
||||
import webbrowser
|
||||
import sys, os
|
||||
|
||||
import critical # critical.py
|
||||
import ihm # ihm.py
|
||||
import logger # logger.py
|
||||
import mrz # mrz.py
|
||||
import globs # globs.py
|
||||
import pytesseract # pytesseract.py
|
||||
import lang # lang.py
|
||||
|
||||
# Global handler
|
||||
logfile = logger.logCur
|
||||
|
||||
class mainWindow(Tk):
|
||||
|
||||
## App Pattern
|
||||
|
||||
def __init__(self):
|
||||
Tk.__init__(self)
|
||||
self.initialize()
|
||||
|
||||
def initialize(self):
|
||||
"""
|
||||
Initializes the main window
|
||||
"""
|
||||
self.mrzChar = ""
|
||||
self.mrzDecided = False
|
||||
self.Tags = []
|
||||
@ -61,6 +69,12 @@ class mainWindow(Tk):
|
||||
self.corners = []
|
||||
self.validatedtext = ""
|
||||
|
||||
# The icon
|
||||
if getattr(sys, 'frozen', False):
|
||||
self.iconbitmap(sys._MEIPASS + '\\id-card.ico\\id-card.ico')
|
||||
else:
|
||||
self.iconbitmap('id-card.ico')
|
||||
|
||||
# Hide during construction
|
||||
self.withdraw()
|
||||
|
||||
@ -70,15 +84,16 @@ class mainWindow(Tk):
|
||||
logfile.printdbg('Launching main window with resolution' + str(ws) + 'x' + str(hs))
|
||||
|
||||
# Configuring the size of each part of the window
|
||||
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(0, minsize=(ws / 2 * 0.3333333333333333))
|
||||
self.grid_columnconfigure(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.10))
|
||||
self.grid_rowconfigure(2, weight=1, minsize=(hs / 2 * 0.35))
|
||||
self.grid_rowconfigure(0, minsize=(hs / 2 * 0.5))
|
||||
self.grid_rowconfigure(1, minsize=(hs / 2 * 0.10))
|
||||
self.grid_rowconfigure(2, minsize=(hs / 2 * 0.35))
|
||||
self.grid_rowconfigure(3, minsize=10)
|
||||
|
||||
# Prepare the data sections
|
||||
self.lecteur_ci = ttk.Labelframe(self, text="Informations sur la pièce d'identité")
|
||||
self.lecteur_ci = ttk.Labelframe(self, text=lang.all[globs.CNIRlang]["Informations about the current document"])
|
||||
self.lecteur_ci.grid_columnconfigure(0, weight=1)
|
||||
self.lecteur_ci.grid_columnconfigure(1, weight=1)
|
||||
self.lecteur_ci.grid_columnconfigure(2, weight=1)
|
||||
@ -91,51 +106,56 @@ class mainWindow(Tk):
|
||||
self.lecteur_ci.grid_rowconfigure(4, weight=1)
|
||||
self.lecteur_ci.grid_rowconfigure(5, weight=1)
|
||||
|
||||
# And what about the status bar ?
|
||||
self.statusbar = ihm.StatusBar(self)
|
||||
self.statusbar.grid(row=3, columnspan=3, sticky="NSEW")
|
||||
|
||||
# Fill the data sections
|
||||
ttk.Label((self.lecteur_ci), text='Statut : ').grid(column=0, row=0, padx=5, pady=5)
|
||||
self.STATUStxt = ttk.Label((self.lecteur_ci), text='EN ATTENTE', font=("TkDefaultFont", 13, "bold"), foreground="orange", anchor=CENTER)
|
||||
ttk.Label((self.lecteur_ci), text='{} : '.format(lang.all[globs.CNIRlang]["Status"])).grid(column=0, row=0, padx=5, pady=5)
|
||||
self.statusbar.set(lang.all[globs.CNIRlang]["IDLE"])
|
||||
self.STATUStxt = ttk.Label((self.lecteur_ci), text=lang.all[globs.CNIRlang]["IDLE"], font=("TkDefaultFont", 13, "bold"), foreground="orange", anchor=CENTER)
|
||||
self.STATUStxt.grid(column=1, row=0, padx=5, pady=5)
|
||||
ttk.Label((self.lecteur_ci), text='Nom : ').grid(column=0, row=1, padx=5, pady=5)
|
||||
ttk.Label((self.lecteur_ci), text='{} : '.format(lang.all[globs.CNIRlang]["Name"])).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)
|
||||
ttk.Label((self.lecteur_ci), text='{} (2) : '.format(lang.all[globs.CNIRlang]["Name"])).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)
|
||||
ttk.Label((self.lecteur_ci), text='{} : '.format(lang.all[globs.CNIRlang]["Birth date"])).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)
|
||||
ttk.Label((self.lecteur_ci), text='{} : '.format(lang.all[globs.CNIRlang]["Issue date"])).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)
|
||||
ttk.Label((self.lecteur_ci), text="{} : ".format(lang.all[globs.CNIRlang]["Expiration date"])).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)
|
||||
ttk.Label((self.lecteur_ci), text='{} : '.format(lang.all[globs.CNIRlang]["Sex"])).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)
|
||||
ttk.Label((self.lecteur_ci), text='{} : '.format(lang.all[globs.CNIRlang]["Issuing country"])).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)
|
||||
ttk.Label((self.lecteur_ci), text='{} : '.format(lang.all[globs.CNIRlang]["Nationality"])).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)
|
||||
ttk.Label((self.lecteur_ci), text='{} : '.format(lang.all[globs.CNIRlang]["Registration"])).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)
|
||||
ttk.Label((self.lecteur_ci), text='{} : '.format(lang.all[globs.CNIRlang]["Document number"])).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.nom['text'] = lang.all[globs.CNIRlang]["Unknown"]
|
||||
self.prenom['text'] = lang.all[globs.CNIRlang]["Unknown"]
|
||||
self.bdate['text'] = lang.all[globs.CNIRlang]["Unknown"]
|
||||
self.ddate['text'] = lang.all[globs.CNIRlang]["Unknown"]
|
||||
self.edate['text'] = lang.all[globs.CNIRlang]["Unknown"]
|
||||
self.no['text'] = lang.all[globs.CNIRlang]["Unknown"]
|
||||
self.sex['text'] = lang.all[globs.CNIRlang]["Unknown"]
|
||||
self.nat['text'] = lang.all[globs.CNIRlang]["Unknown"]
|
||||
self.pays['text'] = lang.all[globs.CNIRlang]["Unknown"]
|
||||
self.indic['text'] = lang.all[globs.CNIRlang]["Unknown"]
|
||||
|
||||
|
||||
self.infoList = \
|
||||
@ -153,7 +173,7 @@ class mainWindow(Tk):
|
||||
}
|
||||
|
||||
# The the image viewer
|
||||
self.imageViewer = ttk.Labelframe(self, text='Affichage et traitement de documents')
|
||||
self.imageViewer = ttk.Labelframe(self, text=lang.all[globs.CNIRlang]["Display and processing of documents"])
|
||||
self.imageViewer.grid_columnconfigure(0, weight=1)
|
||||
self.imageViewer.grid_columnconfigure(1, weight=0)
|
||||
self.imageViewer.grid_rowconfigure(0, weight=1)
|
||||
@ -258,7 +278,7 @@ class mainWindow(Tk):
|
||||
|
||||
|
||||
# The terminal to enter the MRZ
|
||||
self.terminal = ttk.Labelframe(self, text='Terminal de saisie de MRZ complète')
|
||||
self.terminal = ttk.Labelframe(self, text=lang.all[globs.CNIRlang]["Complete MRZ capture terminal"])
|
||||
self.terminal.grid_columnconfigure(0, weight=1)
|
||||
self.terminal.grid_rowconfigure(0, weight=1)
|
||||
self.termframe = Frame(self.terminal)
|
||||
@ -272,7 +292,7 @@ class mainWindow(Tk):
|
||||
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 = ttk.Labelframe(self, text=lang.all[globs.CNIRlang]["Quick entry terminal (731)"])
|
||||
self.terminal2.grid_columnconfigure(0, weight=1)
|
||||
self.terminal2.grid_rowconfigure(0, weight=1)
|
||||
self.speed731 = Frame(self.terminal2)
|
||||
@ -294,7 +314,7 @@ class mainWindow(Tk):
|
||||
self.speedResult.grid(column=2, row=0, sticky='NEW', padx=5, pady=5)
|
||||
|
||||
# The monitor that indicates some useful infos
|
||||
self.monitor = ttk.Labelframe(self, text='Moniteur')
|
||||
self.monitor = ttk.Labelframe(self, text=lang.all[globs.CNIRlang]["Monitor"])
|
||||
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))
|
||||
@ -313,41 +333,45 @@ class mainWindow(Tk):
|
||||
# What is a window without a menu bar ?
|
||||
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_command(label=lang.all[globs.CNIRlang]["New"], command=(self.newEntry))
|
||||
menu1.add_command(label=lang.all[globs.CNIRlang]["Open scan..."], command=(self.openingScan))
|
||||
menu1.add_separator()
|
||||
menu1.add_command(label='Quitter', command=(self.destroy))
|
||||
menubar.add_cascade(label='Fichier', menu=menu1)
|
||||
menu1.add_command(label=lang.all[globs.CNIRlang]["Quit"], command=(self.destroy))
|
||||
menubar.add_cascade(label=lang.all[globs.CNIRlang]["File"], menu=menu1)
|
||||
menu2 = Menu(menubar, tearoff=0)
|
||||
menu2.add_command(label=lang.all[globs.CNIRlang]["Update options"], command=(self.updateSet))
|
||||
menu2.add_command(label=lang.all[globs.CNIRlang]["Show Changelog"], command=(self.showChangeLog))
|
||||
menu2.add_separator()
|
||||
menu2.add_command(label=lang.all[globs.CNIRlang]["Language"], command=(self.languageSet))
|
||||
menubar.add_cascade(label=lang.all[globs.CNIRlang]["Settings"], menu=menu2)
|
||||
menu3 = Menu(menubar, tearoff=0)
|
||||
menu3.add_command(label='Commandes au clavier', command=(self.helpbox))
|
||||
menu3.add_command(label='Signaler un problème', command=(self.openIssuePage))
|
||||
menu3.add_command(label=lang.all[globs.CNIRlang]["Keyboard commands"], command=(self.helpbox))
|
||||
menu3.add_command(label=lang.all[globs.CNIRlang]["Report a bug"], command=(self.openIssuePage))
|
||||
menu3.add_separator()
|
||||
menu3.add_command(label='A propos de CNIRevelator', command=(self.infobox))
|
||||
menubar.add_cascade(label='Aide', menu=menu3)
|
||||
menu3.add_command(label=lang.all[globs.CNIRlang]["About CNIRevelator"], command=(self.infobox))
|
||||
menubar.add_cascade(label=lang.all[globs.CNIRlang]["Help"], menu=menu3)
|
||||
menubar.add_command(label="<|>", command=(self.panelResize))
|
||||
self.config(menu=menubar)
|
||||
|
||||
# The title
|
||||
self.wm_title(globs.CNIRName)
|
||||
|
||||
# The icon
|
||||
if getattr(sys, 'frozen', False):
|
||||
self.iconbitmap(sys._MEIPASS + '\\id-card.ico\\id-card.ico')
|
||||
else:
|
||||
self.iconbitmap('id-card.ico')
|
||||
|
||||
# Make this window resizable and set her size
|
||||
self.resizable(width=True, height=True)
|
||||
self.resizable(0, 0)
|
||||
self.update()
|
||||
w = int(self.winfo_reqwidth())
|
||||
h = int(self.winfo_reqheight())
|
||||
ws = self.winfo_screenwidth()
|
||||
hs = self.winfo_screenheight()
|
||||
x = (ws - w)/2
|
||||
y = (hs - h)/2
|
||||
self.geometry('%dx%d+%d+%d' % (w, h, x, y))
|
||||
self.w = int(self.winfo_reqwidth())
|
||||
self.h = int(self.winfo_reqheight())
|
||||
self.ws = self.winfo_screenwidth()
|
||||
self.hs = self.winfo_screenheight()
|
||||
self.x = (self.ws - self.w)/2
|
||||
self.y = (self.hs - self.h)/2
|
||||
self.geometry('%dx%d+%d+%d' % (self.w, self.h, self.x, self.y))
|
||||
self.update()
|
||||
self.deiconify()
|
||||
self.minsize(self.winfo_width(), self.winfo_height())
|
||||
self.attributes("-topmost", 1)
|
||||
self.maxsize(self.w, self.h)
|
||||
self.minsize(int(2.15 * (self.ws / 2 * 0.3333333333333333)), self.h)
|
||||
self.currentw = self.w
|
||||
|
||||
# Set image
|
||||
self.imageViewer.image = None
|
||||
@ -365,26 +389,32 @@ class mainWindow(Tk):
|
||||
|
||||
logfile.printdbg('Initialization successful')
|
||||
|
||||
def statusUpdate(self, image=None, setplace=False):
|
||||
if image:
|
||||
self.imageViewer.image = image
|
||||
self.imageViewer.ZONE.itemconfigure(self.STATUSimg, image=(self.imageViewer.image))
|
||||
self.imageViewer.ZONE.configure(scrollregion=self.imageViewer.ZONE.bbox("all"))
|
||||
if globs.CNIROpenFile:
|
||||
self.after_idle(lambda : self.openScanFile(sys.argv[1]))
|
||||
|
||||
|
||||
## OCR related functions
|
||||
|
||||
def rectangleSelectScan(self, event):
|
||||
"""
|
||||
Realises the selection of the MRZ to make OCR possible
|
||||
"""
|
||||
if self.imageViewer.image:
|
||||
canvas = event.widget
|
||||
print("Get coordinates : [{}, {}], for [{}, {}]".format(canvas.canvasx(event.x), canvas.canvasy(event.y), event.x, event.y))
|
||||
#print("Get coordinates : [{}, {}], for [{}, {}]".format(canvas.canvasx(event.x), canvas.canvasy(event.y), event.x, event.y))
|
||||
|
||||
self.corners.append([canvas.canvasx(event.x), canvas.canvasy(event.y)])
|
||||
if len(self.corners) == 2:
|
||||
self.select = self.imageViewer.ZONE.create_rectangle(self.corners[0][0], self.corners[0][1], self.corners[1][0], self.corners[1][1], outline ='cyan', width = 2)
|
||||
print("Get rectangle : [{}, {}], for [{}, {}]".format(self.corners[0][0], self.corners[0][1], self.corners[1][0], self.corners[1][1]))
|
||||
#print("Get rectangle : [{}, {}], for [{}, {}]".format(self.corners[0][0], self.corners[0][1], self.corners[1][0], self.corners[1][1]))
|
||||
if len(self.corners) > 2:
|
||||
self.corners = []
|
||||
self.imageViewer.ZONE.delete(self.select)
|
||||
|
||||
def goOCRDetection(self):
|
||||
"""
|
||||
Realises the OCR detection and get the text in self.mrzChar (and prints it)
|
||||
"""
|
||||
if self.imageViewer.image:
|
||||
cv_img = cv2.imreadmulti(self.imageViewer.imagePath)[1][self.imageViewer.pagenumber]
|
||||
cv_img = cv2.cvtColor(cv_img, cv2.COLOR_BGR2RGB)
|
||||
@ -434,7 +464,7 @@ class mainWindow(Tk):
|
||||
invite.focus_force()
|
||||
self.wait_window(invite)
|
||||
|
||||
print("text : {}".format(self.validatedtext))
|
||||
#print("text : {}".format(self.validatedtext))
|
||||
|
||||
self.mrzChar = ""
|
||||
|
||||
@ -445,7 +475,7 @@ class mainWindow(Tk):
|
||||
self.mrzChar = self.mrzChar + char
|
||||
|
||||
self.stringValidation("")
|
||||
print(self.mrzChar)
|
||||
#print(self.mrzChar)
|
||||
|
||||
# Reinstall tesseract
|
||||
except pytesseract.TesseractNotFoundError as e:
|
||||
@ -453,16 +483,20 @@ class mainWindow(Tk):
|
||||
shutil.rmtree(globs.CNIRTesser)
|
||||
except Exception:
|
||||
pass
|
||||
showerror('Erreur de module OCR', ('Le module OCR localisé en ' + str(os.environ['PATH']) + 'est introuvable ou corrompu. Il sera réinstallé à la prochaine exécution'), parent=self)
|
||||
logfile.printerr("Tesseract error : {}. Will be reinstallated".format(e))
|
||||
showerror(lang.all[globs.CNIRlang]["OCR module error"], (lang.all[globs.CNIRlang]["The OCR module located at {} can not be found or corrupted. It will be reinstalled at the next run"].format(os.environ['PATH'])), parent=self)
|
||||
logfile.printerr(lang.all[globs.CNIRlang]["Tesseract error : {}. Will be reinstallated"].format(e))
|
||||
|
||||
# Tesseract error
|
||||
except pytesseract.TesseractError as e:
|
||||
logfile.printerr("Tesseract error : {}".format(e))
|
||||
showerror('Erreur de module OCR', ("Le module Tesseract a rencontré un problème : {}".format(e)), parent=self)
|
||||
showerror(lang.all[globs.CNIRlang]["OCR module error"], (lang.all[globs.CNIRlang]["The Tesseract module encountered a problem: {}"].format(e)), parent=self)
|
||||
|
||||
## Regex and document detection + control related functions
|
||||
|
||||
def stringValidation(self, keysym):
|
||||
"""
|
||||
Analysis of the already typed document
|
||||
"""
|
||||
# analysis
|
||||
# If we must decide the type of the document
|
||||
if not self.mrzDecided:
|
||||
@ -478,11 +512,13 @@ class mainWindow(Tk):
|
||||
|
||||
self.wait_window(invite)
|
||||
|
||||
self.logOnTerm("Document detecté : {}\n".format(candidates[invite.choice][2]))
|
||||
self.logOnTerm(lang.all[globs.CNIRlang]["Document detected: {}\n"].format(candidates[invite.choice][2]))
|
||||
self.statusbar.set(candidates[invite.choice][2])
|
||||
self.mrzDecided = candidates[invite.choice]
|
||||
|
||||
elif len(candidates) == 1:
|
||||
self.logOnTerm("Document detecté : {}\n".format(candidates[0][2]))
|
||||
self.logOnTerm(lang.all[globs.CNIRlang]["Document detected: {}\n"].format(candidates[0][2]))
|
||||
self.statusbar.set(candidates[0][2])
|
||||
self.mrzDecided = candidates[0]
|
||||
else:
|
||||
# corrects some problems
|
||||
@ -569,11 +605,13 @@ class mainWindow(Tk):
|
||||
|
||||
self.wait_window(invite)
|
||||
|
||||
self.logOnTerm("Document re-detecté : {}\n".format(candidates[invite.choice][2]))
|
||||
self.logOnTerm(lang.all[globs.CNIRlang]["Document detected again: {}\n"].format(candidates[invite.choice][2]))
|
||||
self.statusbar.set(candidates[invite.choice][2])
|
||||
self.mrzDecided = candidates[invite.choice]
|
||||
|
||||
elif len(candidates) == 1:
|
||||
self.logOnTerm("Document re-detecté : {}\n".format(candidates[0][2]))
|
||||
self.logOnTerm(lang.all[globs.CNIRlang]["Document detected again: {}\n"].format(candidates[0][2]))
|
||||
self.statusbar.set(candidates[0][2])
|
||||
self.mrzDecided = candidates[0]
|
||||
return "break"
|
||||
|
||||
@ -583,7 +621,7 @@ class mainWindow(Tk):
|
||||
regex = re.compile("[A-Z]|<|[0-9]")
|
||||
# match !
|
||||
if not regex.fullmatch(event.char):
|
||||
self.logOnTerm("Caractère non accepté !\n")
|
||||
self.logOnTerm(lang.all[globs.CNIRlang]["Character not accepted !\n"])
|
||||
return "break"
|
||||
# Adds the entry
|
||||
tempChar = self.termtext.get("1.0", "end")[:-1]
|
||||
@ -626,34 +664,146 @@ class mainWindow(Tk):
|
||||
self.speedResultPrint(str(mrz.computeControlSum(char)))
|
||||
return "break"
|
||||
|
||||
def computeSigma(self):
|
||||
"""
|
||||
Launch the checksum computation, infos validation and print/display the results
|
||||
"""
|
||||
# the regex
|
||||
regex = re.compile("[^A-Z0-9<]")
|
||||
code = re.sub(regex, '', self.mrzChar)
|
||||
self.compliance = True
|
||||
|
||||
allSums = mrz.computeAllControlSum(self.mrzDecided, code)["ctrlSumList"]
|
||||
#print("Code : _{}_ | Sums : {}".format(code, allSums))
|
||||
|
||||
self.termtext.tag_remove("conforme", "1.0", "end")
|
||||
self.termtext.tag_remove("nonconforme", "1.0", "end")
|
||||
|
||||
self.clearTerm()
|
||||
self.logOnTerm(lang.all[globs.CNIRlang]["Document Review: {}\n\n"].format(self.mrzDecided[2]))
|
||||
|
||||
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]))
|
||||
|
||||
if sum[3]:
|
||||
self.logOnTerm(lang.all[globs.CNIRlang]["Checksum position {}: Lu {} VS Calculated {} [facultative]\n"].format(sum[1], code[sum[1]], sum[2]))
|
||||
else:
|
||||
self.logOnTerm(lang.all[globs.CNIRlang]["Checksum position {}: Lu {} VS Calculated {}\n"].format(sum[1], code[sum[1]], sum[2]))
|
||||
|
||||
# if sum is facultative or if sum is ok
|
||||
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:
|
||||
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
|
||||
|
||||
# get the infos
|
||||
docInfos = mrz.getDocInfos(self.mrzDecided, code)
|
||||
#print(docInfos)
|
||||
# display the infos
|
||||
for key in [ e for e in docInfos ]:
|
||||
#print(docInfos[key])
|
||||
if key in ["CODE", "CTRL", "CTRLF"]:
|
||||
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"
|
||||
self.compliance = False
|
||||
|
||||
if self.compliance == True:
|
||||
self.STATUStxt["text"] = lang.all[globs.CNIRlang]["COMPLIANT"]
|
||||
self.STATUStxt["foreground"] = "green"
|
||||
self.statusbar.set(lang.all[globs.CNIRlang]["COMPLIANT"])
|
||||
else:
|
||||
self.STATUStxt["text"] = lang.all[globs.CNIRlang]["IMPROPER"]
|
||||
self.STATUStxt["foreground"] = "red"
|
||||
self.statusbar.set(lang.all[globs.CNIRlang]["IMPROPER"])
|
||||
|
||||
## Print functions
|
||||
|
||||
def logOnTerm(self, text):
|
||||
"""
|
||||
Writes on the monitor
|
||||
"""
|
||||
self.monlog['state'] = 'normal'
|
||||
self.monlog.insert('end', text)
|
||||
self.monlog['state'] = 'disabled'
|
||||
self.monlog.yview(END)
|
||||
|
||||
def clearTerm(self):
|
||||
"""
|
||||
Clears the monitor
|
||||
"""
|
||||
self.monlog['state'] = 'normal'
|
||||
self.monlog.delete('1.0', 'end')
|
||||
self.monlog['state'] = 'disabled'
|
||||
self.monlog.yview(END)
|
||||
|
||||
def speedResultPrint(self, text):
|
||||
"""
|
||||
Prints a result in the quick entry terminal
|
||||
"""
|
||||
self.speedResult['state'] = 'normal'
|
||||
self.speedResult.delete("1.0", 'end')
|
||||
self.speedResult.insert('end', text)
|
||||
self.speedResult['state'] = 'disabled'
|
||||
|
||||
## Document display related functions
|
||||
|
||||
def DisplayUpdate(self, image=None, setplace=False):
|
||||
"""
|
||||
Reload the displayer to display the image or not
|
||||
"""
|
||||
if image:
|
||||
self.imageViewer.image = image
|
||||
self.imageViewer.ZONE.itemconfigure(self.STATUSimg, image=(self.imageViewer.image))
|
||||
self.imageViewer.ZONE.configure(scrollregion=self.imageViewer.ZONE.bbox("all"))
|
||||
|
||||
def goPageChoice(self, event):
|
||||
"""
|
||||
Change the current viewed page of the multipage tiff if needed
|
||||
"""
|
||||
self.imageViewer.pagenumber = int(self.toolbar.pageChooser.get()) - 1
|
||||
self.resizeScan()
|
||||
|
||||
def openingScan(self):
|
||||
"""
|
||||
Open the scan, ask its path and displays it
|
||||
"""
|
||||
path = ''
|
||||
path = filedialog.askopenfilename(parent=self, title='Ouvrir un scan de CNI...', filetypes=(('TIF files', '*.tif'),
|
||||
path = filedialog.askopenfilename(parent=self, title=lang.all[globs.CNIRlang]["Open a scan of document..."], filetypes=(('TIF files', '*.tif'),
|
||||
('TIF files', '*.tiff'),
|
||||
('JPEG files', '*.jpg'),
|
||||
('JPEG files', '*.jpeg')))
|
||||
self.openScanFile(path)
|
||||
|
||||
def openScanFile(self, path):
|
||||
"""
|
||||
Open an image file at path to display it on the displayer
|
||||
"""
|
||||
# Check if the file is valid
|
||||
if ( path[-3:] != 'jpg'
|
||||
and path[-3:] != 'tif'
|
||||
and path[-4:] != 'jpeg'
|
||||
and path[-4:] != 'tiff' ) or not os.path.isfile(path):
|
||||
showerror(lang.all[globs.CNIRlang]["Open a scan of document..."], lang.all[globs.CNIRlang]["The file you provided is not valid : {}"].format(path))
|
||||
return
|
||||
|
||||
# Load an image using OpenCV
|
||||
self.imageViewer.imagePath = path
|
||||
self.imageViewer.imgZoom = 1
|
||||
@ -685,7 +835,7 @@ class mainWindow(Tk):
|
||||
|
||||
# Use PIL (Pillow) to convert the NumPy ndarray to a PhotoImage
|
||||
photo = PIL.ImageTk.PhotoImage(image = PIL.Image.fromarray(cv_img))
|
||||
self.statusUpdate(photo)
|
||||
self.DisplayUpdate(photo)
|
||||
|
||||
def zoomInScan50(self, quantity = 50):
|
||||
if self.imageViewer.image:
|
||||
@ -746,6 +896,9 @@ class mainWindow(Tk):
|
||||
self.resizeScan()
|
||||
|
||||
def negativeScan(self):
|
||||
"""
|
||||
Invert the bits to make a negative of the scan (and highlight the contrasts)
|
||||
"""
|
||||
if self.imageViewer.image:
|
||||
# Load an image using OpenCV
|
||||
cv_img = cv2.imreadmulti(self.imageViewer.imagePath)[1][self.imageViewer.pagenumber]
|
||||
@ -760,6 +913,9 @@ class mainWindow(Tk):
|
||||
self.resizeScan(cv_img)
|
||||
|
||||
def resizeScan(self, cv_img = None):
|
||||
"""
|
||||
Reloads the image according to settings
|
||||
"""
|
||||
if self.imageViewer.image:
|
||||
try:
|
||||
if not hasattr(cv_img, 'shape'):
|
||||
@ -789,10 +945,10 @@ class mainWindow(Tk):
|
||||
cv_img = cv2.resize(cv_img, dim, interpolation = cv2.INTER_AREA)
|
||||
# Use PIL (Pillow) to convert the NumPy ndarray to a PhotoImage
|
||||
photo = PIL.ImageTk.PhotoImage(image = PIL.Image.fromarray(cv_img))
|
||||
self.statusUpdate( photo)
|
||||
self.DisplayUpdate( photo)
|
||||
except Exception as e:
|
||||
logfile.printerr("Error with opencv : {}".format(e))
|
||||
traceback.print_exc(file=sys.stdout)
|
||||
critical.crashCNIR()
|
||||
try:
|
||||
# Reload an image using OpenCV
|
||||
path = self.imageViewer.imagePath
|
||||
@ -807,144 +963,97 @@ class mainWindow(Tk):
|
||||
height, width, channels_no = cv_img.shape
|
||||
# Use PIL (Pillow) to convert the NumPy ndarray to a PhotoImage
|
||||
photo = PIL.ImageTk.PhotoImage(image = PIL.Image.fromarray(cv_img))
|
||||
self.statusUpdate(photo)
|
||||
self.DisplayUpdate(photo)
|
||||
except Exception as e:
|
||||
logfile.printerr("Critical error with opencv : ".format(e))
|
||||
traceback.print_exc(file=sys.stdout)
|
||||
showerror("Erreur OpenCV (traitement d'images)", "Une erreur critique s'est produite dans le gestionnaire de traitement d'images OpenCV utilisé par CNIRevelator. L'application va se réinitialiser")
|
||||
critical.crashCNIR()
|
||||
showerror(lang.all[globs.CNIRlang]["OpenCV error (image processing)"], lang.all[globs.CNIRlang]["A critical error has occurred in the OpenCV image processing manager used by CNIRevelator, the application will reset itself"])
|
||||
self.initialize()
|
||||
|
||||
## IHM and user interface related functions
|
||||
|
||||
def newEntry(self):
|
||||
"""
|
||||
Reinits the IHM and invite
|
||||
"""
|
||||
self.initialize()
|
||||
self.logOnTerm('\n\nEntrez la première ligne de MRZ svp \n')
|
||||
self.logOnTerm('\n\n{}\n'.format(lang.all[globs.CNIRlang]["Please type a MRZ or open a scan"]))
|
||||
|
||||
def infobox(self):
|
||||
"""
|
||||
Shows the About dialog
|
||||
"""
|
||||
Tk().withdraw()
|
||||
|
||||
showinfo('A propos de CNIRevelator',
|
||||
( 'Version du logiciel : CNIRevelator ' + globs.verstring_full + '\n\n'
|
||||
"Copyright © 2018-2019 Adrien Bourmault (neox95)" + "\n\n"
|
||||
"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. "
|
||||
"\n\n"
|
||||
"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/>. "
|
||||
"\n\n"
|
||||
"Le module d'OCR Tesseract 4.0 est soumis à l'Apache License 2004."
|
||||
"\n\n"
|
||||
"Les bibliothèques python et l'environnement Anaconda 3 sont soumis à la licence BSD 2018-2019."
|
||||
"\n\n"
|
||||
"Le code source de ce programme est disponible sur Github à l'adresse <https://github.com/neox95/CNIRevelator>.\n"
|
||||
"Son fonctionnement est conforme aux normes et directives du document 9303 de l'OACI régissant les documents de voyages et d'identité." + '\n\n'
|
||||
" En cas de problèmes ou demande particulière, ouvrez-y une issue ou bien envoyez un mail à neox@os-k.eu !\n\n"
|
||||
showinfo( lang.all[globs.CNIRlang]["About CNIRevelator"],
|
||||
(
|
||||
lang.all[globs.CNIRlang]["ABOUT"]
|
||||
),
|
||||
|
||||
parent=self)
|
||||
|
||||
def helpbox(self):
|
||||
"""
|
||||
Shows the keyboard help summary
|
||||
"""
|
||||
Tk().withdraw()
|
||||
|
||||
showinfo('Aide sur les contrôles au clavier',
|
||||
( "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\tTouche Ctrl droite \n"
|
||||
" Copier :\t\t\t\tCtrl-C \n"
|
||||
" Coller :\t\t\t\tCtrl-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\tTouche Ctrl droite \n"
|
||||
" Compléter champ :\t\t\tTouche Tab \n"
|
||||
" Copier :\t\t\t\tCtrl-C \n"
|
||||
" Coller :\t\t\t\tCtrl-V \n"
|
||||
" Forcer une nouvelle détection du document :\tEchap\n"
|
||||
showinfo( lang.all[globs.CNIRlang]["Keyboard commands"],
|
||||
(
|
||||
lang.all[globs.CNIRlang]["KEYBHELP"]
|
||||
),
|
||||
|
||||
parent=self)
|
||||
|
||||
def openIssuePage(self):
|
||||
self.openBrowser("https://github.com/neox95/CNIRevelator/issues")
|
||||
|
||||
def openBrowser(self, url):
|
||||
webbrowser.open_new(url)
|
||||
|
||||
def computeSigma(self):
|
||||
"""
|
||||
Launch the checksum computation, infos validation and display the results
|
||||
Opens the Github Issue Repository page
|
||||
"""
|
||||
# the regex
|
||||
regex = re.compile("[^A-Z0-9<]")
|
||||
code = re.sub(regex, '', self.mrzChar)
|
||||
self.compliance = True
|
||||
webbrowser.open_new("https://github.com/neox95/CNIRevelator/issues")
|
||||
|
||||
allSums = mrz.computeAllControlSum(self.mrzDecided, code)["ctrlSumList"]
|
||||
#print("Code : _{}_ | Sums : {}".format(code, allSums))
|
||||
def showChangeLog(self):
|
||||
changelogWin = ihm.ChangelogDialog(self, ('{} : CNIRevelator {}\n\n{}'.format(lang.all[globs.CNIRlang]["Program version"], globs.verstring_full, lang.all[globs.CNIRlang]["CHANGELOG"])))
|
||||
changelogWin.transient(self)
|
||||
changelogWin.grab_set()
|
||||
changelogWin.focus_force()
|
||||
self.wait_window(changelogWin)
|
||||
|
||||
self.termtext.tag_remove("conforme", "1.0", "end")
|
||||
self.termtext.tag_remove("nonconforme", "1.0", "end")
|
||||
def updateSet(self):
|
||||
"""
|
||||
Update Settings
|
||||
"""
|
||||
changeupdateWin = ihm.updateSetDialog(self)
|
||||
changeupdateWin.transient(self)
|
||||
changeupdateWin.grab_set()
|
||||
changeupdateWin.focus_force()
|
||||
self.wait_window(changeupdateWin)
|
||||
|
||||
self.clearTerm()
|
||||
self.logOnTerm("Examen du document : {}\n\n".format(self.mrzDecided[2]))
|
||||
def languageSet(self):
|
||||
"""
|
||||
Lang Settings
|
||||
"""
|
||||
changelangWin = ihm.langDialog(self)
|
||||
changelangWin.transient(self)
|
||||
changelangWin.grab_set()
|
||||
changelangWin.focus_force()
|
||||
self.wait_window(changelangWin)
|
||||
|
||||
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]))
|
||||
global mrz
|
||||
mrz = reload(mrz)
|
||||
|
||||
self.logOnTerm("Somme de contrôle position {} : Lu {} VS Calculé {}\n".format(sum[1], code[sum[1]], sum[2]))
|
||||
self.initialize()
|
||||
|
||||
# if sum is facultative or if sum is ok
|
||||
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")
|
||||
def panelResize(self):
|
||||
"""
|
||||
Shows or hides the panel
|
||||
"""
|
||||
if self.currentw > int(2.15 * (self.ws / 2 * 0.3333333333333333)):
|
||||
self.currentw = int(2.15 * (self.ws / 2 * 0.3333333333333333))
|
||||
self.geometry('%dx%d+%d+%d' % (self.currentw, self.h, self.x, self.y))
|
||||
self.update()
|
||||
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:
|
||||
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
|
||||
|
||||
# get the infos
|
||||
docInfos = mrz.getDocInfos(self.mrzDecided, code)
|
||||
#print(docInfos)
|
||||
# display the infos
|
||||
for key in [ e for e in docInfos ]:
|
||||
#print(docInfos[key])
|
||||
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"
|
||||
self.compliance = False
|
||||
|
||||
if self.compliance == True:
|
||||
self.STATUStxt["text"] = "CONFORME"
|
||||
self.STATUStxt["foreground"] = "green"
|
||||
else:
|
||||
self.STATUStxt["text"] = "NON CONFORME"
|
||||
self.STATUStxt["foreground"] = "red"
|
||||
|
||||
return
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
self.currentw = self.w
|
||||
self.geometry('%dx%d+%d+%d' % (self.currentw, self.h, self.x, self.y))
|
||||
self.update()
|
||||
|
||||
|
||||
|
||||
|
557
src/mrz.py
557
src/mrz.py
@ -24,537 +24,22 @@
|
||||
********************************************************************************
|
||||
"""
|
||||
|
||||
import re
|
||||
import logger # logger.py
|
||||
import re
|
||||
import datetime
|
||||
|
||||
import logger # logger.py
|
||||
import globs # globs.py
|
||||
import lang # lang.py
|
||||
import critical # critical.py
|
||||
|
||||
## SEX CODES
|
||||
sexcode = {'M':'Homme', 'F':'Femme', 'X':'Non spécifié'}
|
||||
|
||||
## COUNTRY CODES
|
||||
|
||||
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'
|
||||
}
|
||||
landcode2 = lang.all[globs.CNIRlang]["LANDCODE2"]
|
||||
|
||||
landcode3 = {
|
||||
'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 Organization',
|
||||
'XOM': 'Sovereign Military Order of Malta',
|
||||
'RKS': 'Kosovo',
|
||||
'WSA': 'World Service Authority World Passport'
|
||||
}
|
||||
landcode3 = lang.all[globs.CNIRlang]["LANDCODE3"]
|
||||
|
||||
## DOCUMENTS TYPES
|
||||
|
||||
@ -576,7 +61,7 @@ P = [
|
||||
"D": ["1", "CTRLF", "[0-9]", "C"],
|
||||
"E": ["1", "CTRL", "[0-9]", "4578ABCD"]
|
||||
},
|
||||
"Passeport"
|
||||
lang.all[globs.CNIRlang]["Passeport"]
|
||||
]
|
||||
|
||||
IP = [
|
||||
@ -596,7 +81,7 @@ IP = [
|
||||
"C": ["11", "FACULT", ".+"],
|
||||
"D": ["1", "CTRL", "[0-9]", "345679AC"]
|
||||
},
|
||||
"Carte-passeport"
|
||||
lang.all[globs.CNIRlang]["Carte-passeport"]
|
||||
]
|
||||
|
||||
I_ = [
|
||||
@ -616,7 +101,7 @@ I_ = [
|
||||
"C": ["11", "FACULT", ".+"],
|
||||
"D": ["1", "CTRL", "[0-9]", "345679AC"]
|
||||
},
|
||||
"Titre d'identité/de voyage"
|
||||
lang.all[globs.CNIRlang]["Titre d'identité/de voyage"]
|
||||
]
|
||||
|
||||
AC = [
|
||||
@ -637,7 +122,7 @@ AC = [
|
||||
"C": ["11", "FACULT", ".+"],
|
||||
"D": ["1", "CTRL", "[0-9]","345679AC"]
|
||||
},
|
||||
"Certificat de membre d'équipage"
|
||||
lang.all[globs.CNIRlang]["Certificat de membre d'équipage"]
|
||||
]
|
||||
|
||||
VA = [
|
||||
@ -656,7 +141,7 @@ VA = [
|
||||
"B": ["1", "CTRL", "[0-9]", "A"],
|
||||
"C": ["16", "FACULT", ".+"]
|
||||
},
|
||||
"Visa de type A"
|
||||
lang.all[globs.CNIRlang]["Visa de type A"]
|
||||
]
|
||||
|
||||
VB = [
|
||||
@ -675,7 +160,7 @@ VB = [
|
||||
"B": ["1", "CTRL", "[0-9]", "A"],
|
||||
"C": ["8", "FACULT", ".+"]
|
||||
},
|
||||
"Visa de type B"
|
||||
lang.all[globs.CNIRlang]["Visa de type B"]
|
||||
]
|
||||
|
||||
TSF = [
|
||||
@ -694,7 +179,7 @@ TSF = [
|
||||
"B": ["1", "CTRL", "[0-9]", "A"],
|
||||
"C": ["8", "FACULT", ".+"]
|
||||
},
|
||||
"Carte de séjour"
|
||||
lang.all[globs.CNIRlang]["Carte de séjour"]
|
||||
]
|
||||
|
||||
I__ = [
|
||||
@ -714,7 +199,7 @@ I__ = [
|
||||
"C": ["7", "FACULT", ".+"],
|
||||
"D": ["1", "CTRL", "[0-9]", "4578ABC"]
|
||||
},
|
||||
"Pièce d'identité/de voyage"
|
||||
lang.all[globs.CNIRlang]["Pièce d'identité/de voyage"]
|
||||
]
|
||||
|
||||
IDFR = [
|
||||
@ -734,7 +219,7 @@ IDFR = [
|
||||
"C": ["1", "SEX", "[A-Z]"],
|
||||
"D": ["1", "CTRL", "[0-9]", "123456789ABCE"]
|
||||
},
|
||||
"Pièce d'identité FR"
|
||||
lang.all[globs.CNIRlang]["Pièce d'identité FR"]
|
||||
]
|
||||
|
||||
DL = [
|
||||
@ -748,7 +233,7 @@ DL = [
|
||||
"6": ["8", "NOM", "([A-Z]|<)+"],
|
||||
"7": ["1", "CTRL", "[0-9]", "123456"]
|
||||
},
|
||||
"Permis de conduire"
|
||||
lang.all[globs.CNIRlang]["Permis de conduire"]
|
||||
]
|
||||
|
||||
TYPES = [IDFR, I__, VB, VA, AC, I_, IP, P, DL, TSF]
|
||||
@ -1010,6 +495,14 @@ def getDocInfos(doc, code):
|
||||
res["INDIC"] += value
|
||||
except KeyError:
|
||||
res["INDIC"] = value
|
||||
|
||||
# Sex
|
||||
elif field[0] == 'SEX':
|
||||
if not value in "MF":
|
||||
res[field[0]] = False
|
||||
else:
|
||||
res[field[0]] = value
|
||||
|
||||
# All other cases
|
||||
else:
|
||||
if value != "":
|
||||
|
138
src/updater.py
138
src/updater.py
@ -24,7 +24,9 @@
|
||||
"""
|
||||
|
||||
from win32com.client import Dispatch
|
||||
import traceback
|
||||
from tkinter.messagebox import *
|
||||
from tkinter import *
|
||||
import pythoncom
|
||||
import sys
|
||||
import time
|
||||
import os
|
||||
@ -34,10 +36,12 @@ import hashlib
|
||||
import subprocess
|
||||
import psutil
|
||||
|
||||
import critical # critical.py
|
||||
import ihm # ihm.py
|
||||
import logger # logger.py
|
||||
import globs # globs.py
|
||||
import downloader # downloader.py
|
||||
import lang # lang.py
|
||||
|
||||
UPDATE_IS_MADE = False
|
||||
UPATH = ' '
|
||||
@ -81,52 +85,21 @@ def exitProcess(arg):
|
||||
process.terminate()
|
||||
sys.exit(arg)
|
||||
|
||||
def runPowershell(scriptblock, cwd=os.getcwd()):
|
||||
"""
|
||||
Executes a powershell command
|
||||
"""
|
||||
log.debug("Running PowerShell Block:\r\n%s", scriptblock)
|
||||
log.debug("Current Directory: %s\r\n" % cwd)
|
||||
psProc = subprocess.Popen([r'C:\WINDOWS\system32\WindowsPowerShell\v1.0\powershell.exe',
|
||||
'-ExecutionPolicy', 'Bypass',
|
||||
'-noprofile',
|
||||
'-c', '-',],
|
||||
cwd=cwd,
|
||||
stdin=subprocess.PIPE,
|
||||
stdout=subprocess.PIPE,
|
||||
stderr=subprocess.PIPE)
|
||||
stdoutdata, stderrdata = psProc.communicate(scriptblock)
|
||||
|
||||
if stdoutdata:
|
||||
log.debug("Script Output:\r\n%s" % stdoutdata)
|
||||
elif not stderrdata:
|
||||
log.debug("Script completed succssfully (no stdout/stderr).")
|
||||
if stderrdata:
|
||||
log.error("Script Error:\r\n%s" % stderrdata)
|
||||
|
||||
return stdoutdata, stderrdata
|
||||
|
||||
|
||||
def getCertificates(server_list, location="LocalMachine", store="My"):
|
||||
"""
|
||||
Returns the json data of all installed certificates
|
||||
"""
|
||||
cmd = '''
|
||||
$sb = { ls Cert:\%s\%s | Select Subject,ThumbPrint }
|
||||
$Servers = '%s' | ConvertFrom-Json
|
||||
|
||||
Invoke-Command -ComputerName $Servers -ScriptBlock $sb -Authentication Negotiate | ConvertTo-Json -Depth 999
|
||||
''' % (location, store, json.dumps(server_list))
|
||||
stdoutdata, stderrdata = runPowershell(cmd)
|
||||
return json.loads(stdoutdata)
|
||||
|
||||
|
||||
def updateChannel(choice):
|
||||
if choice == "Beta":
|
||||
with open(globs.CNIRUrlConfig, 'w') as (configFile):
|
||||
configFile.write("{}\n0\n0".format(globs.CNIRBetaURL))
|
||||
else:
|
||||
with open(globs.CNIRUrlConfig, 'w') as (configFile):
|
||||
configFile.write("{}\n0\n0".format(globs.CNIRDefaultURL))
|
||||
|
||||
def getLatestVersion(credentials):
|
||||
"""
|
||||
Returns the latest version of the software
|
||||
"""
|
||||
|
||||
finalver, finalurl, finalchecksum = [None]*3
|
||||
|
||||
# Global Handlers
|
||||
logfile = logger.logCur
|
||||
|
||||
@ -155,7 +128,7 @@ def getLatestVersion(credentials):
|
||||
except:
|
||||
pass
|
||||
with open(globs.CNIRUrlConfig, 'w') as (configFile):
|
||||
configFile.write("https://raw.githubusercontent.com/neox95/CNIRevelator/master/VERSIONS.LST\n0\n0")
|
||||
configFile.write("{}\n0\n0".format(globs.CNIRDefaultURL))
|
||||
|
||||
# Getting the list of versions of the software
|
||||
logfile.printdbg('Retrieving the software versions')
|
||||
@ -200,6 +173,11 @@ def tessInstall(PATH, credentials):
|
||||
# Verifying that Tesseract is installed
|
||||
if not os.path.exists(PATH + '\\Tesseract-OCR4\\'):
|
||||
finalver, finalurl, finalchecksum = getLatestVersion(credentials)
|
||||
|
||||
if finalurl == None:
|
||||
logfile.printerr('Unable to get the Tesseract url')
|
||||
return False
|
||||
|
||||
tesseracturl = finalurl.replace("CNIRevelator.zip", "tesseract_4.zip")
|
||||
|
||||
# WE ASSUME THAT THE MAIN FILE IS CNIRevelator.zip AND THAT THE TESSERACT PACKAGE IS tesseract_4.zip
|
||||
@ -228,7 +206,7 @@ def tessInstall(PATH, credentials):
|
||||
|
||||
# Unzip Tesseract
|
||||
logfile.printdbg("Unzipping the package")
|
||||
launcherWindow.printmsg('Installing the updates')
|
||||
launcherWindow.printmsg(lang.all[globs.CNIRlang]["Installing the updates"])
|
||||
zip_ref = zipfile.ZipFile(PATH + '\\downloads\\TsrtPackage.zip', 'r')
|
||||
zip_ref.extractall(PATH)
|
||||
zip_ref.close()
|
||||
@ -261,7 +239,7 @@ def batch(credentials):
|
||||
|
||||
getTheUpdate = downloader.newdownload(credentials, finalurl, globs.CNIRFolder + '\\downloads\\CNIPackage.zip', "CNIRevelator {}.{}.{}".format(finalver[0], finalver[1], finalver[2])).download()
|
||||
|
||||
launcherWindow.printmsg('Verifying download...')
|
||||
launcherWindow.printmsg(lang.all[globs.CNIRlang]["Verifying download..."])
|
||||
|
||||
# CHECKSUM
|
||||
BUF_SIZE = 65536 # lets read stuff in 64kb chunks!
|
||||
@ -286,7 +264,7 @@ def batch(credentials):
|
||||
global UPATH
|
||||
UPATH = globs.CNIRFolder + '\\..\\CNIRevelator' + "{}.{}.{}".format(finalver[0], finalver[1], finalver[2])
|
||||
logfile.printdbg("Make place")
|
||||
launcherWindow.printmsg('Preparing installation...')
|
||||
launcherWindow.printmsg(lang.all[globs.CNIRlang]["Preparing installation..."])
|
||||
# Cleanup
|
||||
try:
|
||||
shutil.rmtree(UPATH + 'temp')
|
||||
@ -298,7 +276,7 @@ def batch(credentials):
|
||||
logfile.printdbg('Unable to cleanup : ' +str(e))
|
||||
# Unzip
|
||||
logfile.printdbg("Unzipping the package")
|
||||
launcherWindow.printmsg('Installing the updates')
|
||||
launcherWindow.printmsg(lang.all[globs.CNIRlang]["Installing the updates"])
|
||||
zip_ref = zipfile.ZipFile(globs.CNIRFolder + '\\downloads\\CNIPackage.zip', 'r')
|
||||
zip_ref.extractall(UPATH + "temp")
|
||||
zip_ref.close()
|
||||
@ -309,9 +287,16 @@ def batch(credentials):
|
||||
logfile.printdbg('Extracted :' + UPATH + '\\CNIRevelator.exe')
|
||||
|
||||
# Make a shortcut
|
||||
# hide main window
|
||||
pythoncom.CoInitialize()
|
||||
root = Tk()
|
||||
root.withdraw()
|
||||
res = askquestion(lang.all[globs.CNIRlang]["Shortcut creation"], lang.all[globs.CNIRlang]["Would you like to create/update the shortcut for CNIRevelator on your desktop ?"])
|
||||
if res == "yes":
|
||||
createShortcut("CNIRevelator.lnk", UPATH + '\\CNIRevelator.exe', UPATH)
|
||||
root.destroy()
|
||||
|
||||
launcherWindow.printmsg('Success !')
|
||||
launcherWindow.printmsg(lang.all[globs.CNIRlang]["Success !"])
|
||||
|
||||
# Cleanup
|
||||
try:
|
||||
@ -319,7 +304,7 @@ def batch(credentials):
|
||||
except:
|
||||
pass
|
||||
# Time to quit
|
||||
launcherWindow.printmsg('Launched the new process.')
|
||||
launcherWindow.printmsg(lang.all[globs.CNIRlang]["Launching the new version..."])
|
||||
global UPDATE_IS_MADE
|
||||
UPDATE_IS_MADE = True
|
||||
return True
|
||||
@ -335,19 +320,19 @@ def umain():
|
||||
|
||||
if not credentials.valid:
|
||||
logfile.printerr("Credentials Error. No effective update !")
|
||||
launcherWindow.printmsg('Credentials Error. No effective update !')
|
||||
launcherWindow.printmsg(lang.all[globs.CNIRlang]["Credentials Error. No effective update !"])
|
||||
time.sleep(2)
|
||||
launcherWindow.exit()
|
||||
return 0
|
||||
|
||||
# Cleaner for the old version if detected
|
||||
if len(sys.argv) > 2:
|
||||
if len(sys.argv) > 2 and str(sys.argv[1]) == "DELETE":
|
||||
globs.CNIRNewVersion = True
|
||||
launcherWindow.printmsg('Deleting old version !')
|
||||
launcherWindow.printmsg(lang.all[globs.CNIRlang]["Deleting old version"])
|
||||
logfile.printdbg("Old install detected : {}".format(sys.argv[1]))
|
||||
while os.path.exists(str(sys.argv[2])):
|
||||
try:
|
||||
os.remove(str(sys.argv[2]))
|
||||
shutil.rmtree(str(sys.argv[2]))
|
||||
except Exception as e:
|
||||
logfile.printerr(str(e))
|
||||
logfile.printdbg('Trying stop the process !')
|
||||
@ -361,45 +346,24 @@ def umain():
|
||||
else:
|
||||
logfile.printdbg('Terminating process !')
|
||||
process.terminate()
|
||||
os.remove(str(sys.argv[2]))
|
||||
shutil.rmtree(str(sys.argv[2]))
|
||||
break
|
||||
except Exception as e:
|
||||
logfile.printerr(str(e))
|
||||
launcherWindow.printmsg('Fail :{}'.format(e))
|
||||
launcherWindow.printmsg('Starting...')
|
||||
elif len(sys.argv) > 1:
|
||||
globs.CNIRNewVersion = True
|
||||
launcherWindow.printmsg('Deleting old version !')
|
||||
logfile.printdbg("Old install detected : {}".format(sys.argv[1]))
|
||||
while os.path.exists(str(sys.argv[1])):
|
||||
try:
|
||||
shutil.rmtree(str(sys.argv[1]))
|
||||
except Exception as e:
|
||||
logfile.printerr(str(e))
|
||||
logfile.printdbg('Trying stop the process !')
|
||||
launcherWindow.printmsg('Fail :{}'.format(e))
|
||||
try:
|
||||
for process in psutil.process_iter():
|
||||
if process.name() == 'CNIRevelator.exe':
|
||||
logfile.printdbg('Process found. Command line: {}'.format(process.cmdline()))
|
||||
if process.pid == os.getpid():
|
||||
logfile.printdbg("Don't touch us ! {} = {}".format(process.pid, os.getpid()))
|
||||
else:
|
||||
logfile.printdbg('Terminating process !')
|
||||
process.terminate()
|
||||
shutil.rmtree(str(sys.argv[1]))
|
||||
break
|
||||
except Exception as e:
|
||||
logfile.printerr(str(e))
|
||||
launcherWindow.printmsg('Fail :{}'.format(e))
|
||||
launcherWindow.printmsg('Starting...')
|
||||
launcherWindow.printmsg(lang.all[globs.CNIRlang]['Starting...'])
|
||||
|
||||
# check we want open a file
|
||||
elif len(sys.argv) > 1 and str(sys.argv[1]) != "DELETE":
|
||||
globs.CNIROpenFile = True
|
||||
print(sys.argv)
|
||||
|
||||
try:
|
||||
try:
|
||||
# EXECUTING THE UPDATE BATCH
|
||||
success = batch(credentials)
|
||||
except Exception as e:
|
||||
logfile.printerr("An error occured on the thread : " + str(traceback.format_exc()))
|
||||
critical.crashCNIR()
|
||||
launcherWindow.printmsg('ERROR : ' + str(e))
|
||||
time.sleep(3)
|
||||
launcherWindow.exit()
|
||||
@ -410,7 +374,7 @@ def umain():
|
||||
launcherWindow.printmsg('Software is up-to-date !')
|
||||
else:
|
||||
logfile.printerr("An error occured. No effective update !")
|
||||
launcherWindow.printmsg('An error occured. No effective update !')
|
||||
launcherWindow.printmsg(lang.all[globs.CNIRlang]['An error occured. No effective update !'])
|
||||
time.sleep(2)
|
||||
launcherWindow.exit()
|
||||
return 0
|
||||
@ -419,7 +383,7 @@ def umain():
|
||||
launcherWindow.exit()
|
||||
return 0
|
||||
except:
|
||||
logfile.printerr("A FATAL ERROR OCCURED : " + str(traceback.format_exc()))
|
||||
critical.crashCNIR()
|
||||
launcherWindow.exit()
|
||||
sys.exit(2)
|
||||
return 2
|
||||
@ -429,7 +393,7 @@ def umain():
|
||||
# INSTALLING TESSERACT OCR
|
||||
success = tessInstall(globs.CNIRFolder, credentials)
|
||||
except Exception as e:
|
||||
logfile.printerr("An error occured on the thread : " + str(traceback.format_exc()))
|
||||
critical.crashCNIR()
|
||||
launcherWindow.printmsg('ERROR : ' + str(e))
|
||||
time.sleep(3)
|
||||
launcherWindow.exit()
|
||||
@ -437,16 +401,16 @@ def umain():
|
||||
|
||||
if success:
|
||||
logfile.printdbg("Software is up-to-date !")
|
||||
launcherWindow.printmsg('Software is up-to-date !')
|
||||
launcherWindow.printmsg(lang.all[globs.CNIRlang]['Software is up-to-date !'])
|
||||
else:
|
||||
logfile.printerr("An error occured. No effective update !")
|
||||
launcherWindow.printmsg('An error occured. No effective update !')
|
||||
launcherWindow.printmsg(lang.all[globs.CNIRlang]['An error occured. No effective update !'])
|
||||
time.sleep(2)
|
||||
launcherWindow.exit()
|
||||
return 0
|
||||
|
||||
except:
|
||||
logfile.printerr("A FATAL ERROR OCCURED : " + str(traceback.format_exc()))
|
||||
critical.crashCNIR()
|
||||
launcherWindow.exit()
|
||||
sys.exit(2)
|
||||
return 2
|
||||
|
Loading…
Reference in New Issue
Block a user