mirror of
https://gitlab.os-k.eu/neox/CNIRevelator.git
synced 2023-08-25 14:03:10 +02:00
Finishing reorganization of code
This commit is contained in:
parent
03b339f266
commit
0baa7f3400
BIN
CNIPackage.zip
Normal file
BIN
CNIPackage.zip
Normal file
Binary file not shown.
@ -1,2 +1,2 @@
|
|||||||
# ver|url|checksum, and | as separator, one version per ||
|
# ver|url|checksum, and | as separator, one version per ||
|
||||||
0.0.0|https://neoxgroup.eu/ftpaccess/Applicatifs/CNIRevelator/CNIRevelator_2.2.5|1234||3.0.1|https://neoxgroup.eu/ftpaccess/Applicatifs/CNIRevelator/CNIRevelator_2.2.5|1234||0.0.1|https://www.os-k.eu|1234||3.0.2|https://neoxgroup.eu/ftpaccess/Applicatifs/CNIRevelator/CNIRevelator_2.2.5|1234
|
3.0.0|https://neoxgroup.eu/ftpaccess/Applicatifs/CNIRevelator/CNIRevelator_2.2.5|1234||
|
||||||
|
@ -23,42 +23,24 @@
|
|||||||
********************************************************************************
|
********************************************************************************
|
||||||
"""
|
"""
|
||||||
|
|
||||||
from CNI_GLOBALVAR import *
|
import sys
|
||||||
try:
|
import os
|
||||||
os.remove('error.log')
|
import subprocess
|
||||||
os.remove('conf.ig')
|
import threading
|
||||||
except:
|
import traceback
|
||||||
print("pass log deletion")
|
|
||||||
pass
|
|
||||||
|
|
||||||
if not os.path.exists(CST_FOLDER):
|
import launcher # launcher.py
|
||||||
try:
|
import ihm # ihm.py
|
||||||
os.makedirs(CST_FOLDER)
|
import logger # logger.py
|
||||||
except IOError:
|
import updater # updater.py
|
||||||
print("pass IO ERROR")
|
|
||||||
pass
|
|
||||||
|
|
||||||
print("debug")
|
## Global Handlers
|
||||||
import logging
|
logfile = logger.logCur
|
||||||
from logging import FileHandler
|
launcherWindow = ihm.launcherWindowCur
|
||||||
logger = logging.getLogger()
|
|
||||||
logger.setLevel(logging.INFO)
|
|
||||||
formatter = logging.Formatter('%(asctime)s :: %(levelname)s :: %(message)s')
|
|
||||||
error_handler = FileHandler((CST_FOLDER + '\\error.log'), mode='w', encoding='utf-8', delay=True)
|
|
||||||
info_handler = FileHandler((CST_FOLDER + '\\cnirevelator.log'), mode='w', encoding='utf-8')
|
|
||||||
error_handler.setLevel(logging.ERROR)
|
|
||||||
logger.addHandler(error_handler)
|
|
||||||
info_handler.setLevel(logging.DEBUG)
|
|
||||||
info_handler.setFormatter(formatter)
|
|
||||||
logger.addHandler(info_handler)
|
|
||||||
from CNI_classes import *
|
|
||||||
from CNI_Update import *
|
|
||||||
|
|
||||||
|
## MAIN FUNCTION OF CNIREVELATOR
|
||||||
def main(logger):
|
def main(logger):
|
||||||
logger.error('')
|
|
||||||
logger.info('main() : **** Creating App_main() ****')
|
|
||||||
main_w = App_main(logger)
|
|
||||||
main_w.montext('* ' + CST_NAME + ' ' + CST_VER + ' ' + CST_TYPE + ' Revision ' + CST_REV + ' *\n')
|
|
||||||
import CNI_pytesseract as pytesseract
|
import CNI_pytesseract as pytesseract
|
||||||
try:
|
try:
|
||||||
os.environ['PATH'] = CST_FOLDER + 'Tesseract-OCR4\\'
|
os.environ['PATH'] = CST_FOLDER + 'Tesseract-OCR4\\'
|
||||||
@ -70,6 +52,7 @@ def main(logger):
|
|||||||
text = 'Tesseract version ' + str(tesser_version) + ' Licensed Apache 2004 successfully initiated\n'
|
text = 'Tesseract version ' + str(tesser_version) + ' Licensed Apache 2004 successfully initiated\n'
|
||||||
main_w.montext(text)
|
main_w.montext(text)
|
||||||
main_w.montext('\n\nEntrez la première ligne de MRZ svp \n')
|
main_w.montext('\n\nEntrez la première ligne de MRZ svp \n')
|
||||||
|
|
||||||
if CST_CHANGELOG.isOn:
|
if CST_CHANGELOG.isOn:
|
||||||
showinfo('Changelog : résumé de mise à jour', ('Version du logiciel : ' + CST_VER + ' ' + CST_TYPE + ' Revision ' + CST_REV + '\n\n' + CST_CHANGELOG.text), parent=main_w)
|
showinfo('Changelog : résumé de mise à jour', ('Version du logiciel : ' + CST_VER + ' ' + CST_TYPE + ' Revision ' + CST_REV + '\n\n' + CST_CHANGELOG.text), parent=main_w)
|
||||||
logger.info('main() : **** Launching App_main() ****')
|
logger.info('main() : **** Launching App_main() ****')
|
||||||
@ -77,34 +60,14 @@ def main(logger):
|
|||||||
logger.info('main() : **** Ending App_main() ****')
|
logger.info('main() : **** Ending App_main() ****')
|
||||||
|
|
||||||
|
|
||||||
logger.info('launcher : ' + CST_NAME + ' ' + CST_VER)
|
## BOOTSTRAP OF CNIREVELATOR
|
||||||
logger.info('launcher : *****Hello World*****')
|
|
||||||
logger.info('launcher : *****Launching SoftUpdate()*****')
|
|
||||||
|
|
||||||
logger.info('launcher : *****Launching main()*****')
|
|
||||||
State = main(logger)
|
|
||||||
|
|
||||||
|
|
||||||
logger.info('launcher : *****Ending main()*****')
|
|
||||||
logger.info('launcher : *****Goodbye!*****')
|
|
||||||
handlers = logger.handlers[:]
|
|
||||||
for handler in handlers:
|
|
||||||
handler.close()
|
|
||||||
logger.removeHandler(handler)
|
|
||||||
|
|
||||||
try:
|
try:
|
||||||
with open(CST_FOLDER + '\\error.log') as (echo):
|
launcherThread = threading.Thread(target=updater.umain, daemon=False)
|
||||||
try:
|
launcher.lmain(launcherThread)
|
||||||
os.remove('error.log')
|
except Exception:
|
||||||
except OSError:
|
logfile.printerr("A FATAL ERROR OCCURED : " + str(traceback.format_exc()))
|
||||||
pass
|
sys.exit(1)
|
||||||
|
|
||||||
from shutil import copyfile
|
main()
|
||||||
temptwo = str(echo.read())
|
|
||||||
if len(temptwo) != 1:
|
|
||||||
copyfile(CST_FOLDER + '\\cnirevelator.log', 'error.log')
|
|
||||||
except IOError:
|
|
||||||
pass
|
|
||||||
|
|
||||||
print("exit")
|
|
||||||
sys.exit(0)
|
sys.exit(0)
|
||||||
|
1332
src/CNI_classes.py
1332
src/CNI_classes.py
File diff suppressed because it is too large
Load Diff
55
src/ihm.py
55
src/ihm.py
@ -111,6 +111,61 @@ class LauncherWindow(Tk):
|
|||||||
|
|
||||||
self.update()
|
self.update()
|
||||||
|
|
||||||
|
class AutoScrollbar(ttk.Scrollbar):
|
||||||
|
|
||||||
|
def set(self, lo, hi):
|
||||||
|
if float(lo) <= 0.0:
|
||||||
|
if float(hi) >= 1.0:
|
||||||
|
self.grid_remove()
|
||||||
|
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__)
|
||||||
|
|
||||||
|
class OpenPageDialog(Toplevel):
|
||||||
|
|
||||||
|
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)
|
||||||
|
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)
|
||||||
|
self.combotry = ttk.Combobox(self)
|
||||||
|
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)
|
||||||
|
self.update()
|
||||||
|
hs = self.winfo_screenheight()
|
||||||
|
w = int(self.winfo_width())
|
||||||
|
h = int(self.winfo_height())
|
||||||
|
ws = self.winfo_screenwidth()
|
||||||
|
hs = self.winfo_screenheight()
|
||||||
|
x = ws / 2 - w / 2
|
||||||
|
y = hs / 2 - h / 2
|
||||||
|
self.geometry('%dx%d+%d+%d' % (w, h, x, y))
|
||||||
|
if getattr(sys, 'frozen', False):
|
||||||
|
self.iconbitmap(sys._MEIPASS + '\\id-card.ico\\id-card.ico')
|
||||||
|
else:
|
||||||
|
self.iconbitmap('id-card.ico')
|
||||||
|
|
||||||
|
def valid(self):
|
||||||
|
self.parent.page = self.combotry.current()
|
||||||
|
self.destroy()
|
||||||
|
|
||||||
|
|
||||||
|
class OpenScanWin(Toplevel):
|
||||||
|
|
||||||
|
def __init__(self, parent, file, type, nframe=1):
|
||||||
|
super().__init__(parent)
|
||||||
|
self.parent = parent
|
||||||
|
app = OpenScan(self, file, type, nframe)
|
||||||
|
|
||||||
## Global Handler
|
## Global Handler
|
||||||
launcherWindowCur = LauncherWindow()
|
launcherWindowCur = LauncherWindow()
|
||||||
|
|
||||||
|
275
src/image.py
Normal file
275
src/image.py
Normal file
@ -0,0 +1,275 @@
|
|||||||
|
"""
|
||||||
|
********************************************************************************
|
||||||
|
* CNIRevelator *
|
||||||
|
* *
|
||||||
|
* Desc: Image calculation for CNI printing *
|
||||||
|
* *
|
||||||
|
* 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/>. *
|
||||||
|
********************************************************************************
|
||||||
|
"""
|
||||||
|
|
||||||
|
class CanvasImage:
|
||||||
|
|
||||||
|
def __init__(self, placeholder, file, type):
|
||||||
|
""" Initialize the ImageFrame """
|
||||||
|
self.type = type
|
||||||
|
self.angle = 0
|
||||||
|
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')
|
||||||
|
hbar.grid(row=1, column=0, sticky='we')
|
||||||
|
vbar.grid(row=0, column=1, sticky='ns')
|
||||||
|
self.canvas = Canvas((self._CanvasImage__imframe), highlightthickness=0, xscrollcommand=(hbar.set),
|
||||||
|
yscrollcommand=(vbar.set))
|
||||||
|
self.canvas.grid(row=0, column=0, sticky='nswe')
|
||||||
|
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():
|
||||||
|
warnings.simplefilter('ignore')
|
||||||
|
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
|
||||||
|
try:
|
||||||
|
self._CanvasImage__pyramid.append(self._CanvasImage__pyramid[(-1)].resize((int(w), int(h)), self._CanvasImage__filter))
|
||||||
|
except TypeError:
|
||||||
|
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
|
||||||
|
|
||||||
|
self.container = self.canvas.create_rectangle((0, 0, self.imwidth, self.imheight), width=0)
|
||||||
|
self._CanvasImage__show_image()
|
||||||
|
self.canvas.focus_set()
|
||||||
|
|
||||||
|
def rotatem(self):
|
||||||
|
self.angle += 1
|
||||||
|
self._CanvasImage__show_image()
|
||||||
|
|
||||||
|
def rotatep(self):
|
||||||
|
self.angle -= 1
|
||||||
|
self._CanvasImage__show_image()
|
||||||
|
|
||||||
|
def rotatemm(self):
|
||||||
|
self.angle += 90
|
||||||
|
self._CanvasImage__show_image()
|
||||||
|
|
||||||
|
def rotatepp(self):
|
||||||
|
self.angle -= 90
|
||||||
|
self._CanvasImage__show_image()
|
||||||
|
|
||||||
|
def smaller(self):
|
||||||
|
""" Resize image proportionally and return smaller image """
|
||||||
|
w1, h1 = float(self.imwidth), float(self.imheight)
|
||||||
|
w2, h2 = float(self._CanvasImage__huge_size), float(self._CanvasImage__huge_size)
|
||||||
|
aspect_ratio1 = w1 / h1
|
||||||
|
aspect_ratio2 = w2 / h2
|
||||||
|
if aspect_ratio1 == aspect_ratio2:
|
||||||
|
image = Image.new('RGB', (int(w2), int(h2)))
|
||||||
|
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)
|
||||||
|
while i < self.imheight:
|
||||||
|
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)))
|
||||||
|
i += band
|
||||||
|
j += 1
|
||||||
|
|
||||||
|
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 """
|
||||||
|
(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)
|
||||||
|
|
||||||
|
def __scroll_x(self, *args, **kwargs):
|
||||||
|
""" Scroll canvas horizontally and redraw the image """
|
||||||
|
(self.canvas.xview)(*args)
|
||||||
|
self._CanvasImage__show_image()
|
||||||
|
|
||||||
|
def __scroll_y(self, *args, **kwargs):
|
||||||
|
""" Scroll canvas vertically and redraw the image """
|
||||||
|
(self.canvas.yview)(*args)
|
||||||
|
self._CanvasImage__show_image()
|
||||||
|
|
||||||
|
def __show_image(self):
|
||||||
|
""" Show image on the Canvas. Implements correct image zoom almost like in Google Maps """
|
||||||
|
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)
|
||||||
|
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]
|
||||||
|
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
|
||||||
|
|
||||||
|
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 """
|
||||||
|
self.canvas.scan_dragto((event.x), (event.y), gain=1)
|
||||||
|
self._CanvasImage__show_image()
|
||||||
|
|
||||||
|
def outside(self, x, y):
|
||||||
|
""" Checks if the point (x,y) is outside the image area """
|
||||||
|
bbox = self.canvas.coords(self.container)
|
||||||
|
if bbox[0] < x < bbox[2]:
|
||||||
|
if bbox[1] < y < bbox[3]:
|
||||||
|
pass
|
||||||
|
return False
|
||||||
|
else:
|
||||||
|
return True
|
||||||
|
|
||||||
|
def __wheel(self, event):
|
||||||
|
""" Zoom with mouse wheel """
|
||||||
|
x = self.canvas.canvasx(event.x)
|
||||||
|
y = self.canvas.canvasy(event.y)
|
||||||
|
if self.outside(x, y):
|
||||||
|
return
|
||||||
|
scale = 1.0
|
||||||
|
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:
|
||||||
|
i = min(self.canvas.winfo_width(), self.canvas.winfo_height()) >> 1
|
||||||
|
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()
|
||||||
|
|
||||||
|
def crop(self, bbox):
|
||||||
|
""" Crop rectangle from the image and return it """
|
||||||
|
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)
|
||||||
|
|
||||||
|
def destroy(self):
|
||||||
|
""" ImageFrame destructor """
|
||||||
|
self._CanvasImage__image.close()
|
||||||
|
map(lambda i: i.close, self._CanvasImage__pyramid)
|
||||||
|
del self._CanvasImage__pyramid[:]
|
||||||
|
del self._CanvasImage__pyramid
|
||||||
|
self.canvas.destroy()
|
@ -39,8 +39,7 @@ logfile = logger.logCur
|
|||||||
launcherWindow = ihm.launcherWindowCur
|
launcherWindow = ihm.launcherWindowCur
|
||||||
|
|
||||||
## Main function
|
## Main function
|
||||||
def main():
|
def lmain(mainThread):
|
||||||
|
|
||||||
# Hello world
|
# Hello world
|
||||||
logfile.printdbg('*** CNIRLauncher LOGFILE. Hello World ! ***')
|
logfile.printdbg('*** CNIRLauncher LOGFILE. Hello World ! ***')
|
||||||
#logfile.printdbg('Files in directory : ' + str(os.listdir(globs.CNIRFolder)))
|
#logfile.printdbg('Files in directory : ' + str(os.listdir(globs.CNIRFolder)))
|
||||||
@ -57,13 +56,3 @@ def main():
|
|||||||
|
|
||||||
logfile.printdbg('*** CNIRLauncher LOGFILE. Goodbye World ! ***')
|
logfile.printdbg('*** CNIRLauncher LOGFILE. Goodbye World ! ***')
|
||||||
return
|
return
|
||||||
|
|
||||||
## Bootstrap
|
|
||||||
try:
|
|
||||||
mainThread = threading.Thread(target=updater.umain, daemon=False)
|
|
||||||
main()
|
|
||||||
except Exception:
|
|
||||||
logfile.printerr("A FATAL ERROR OCCURED : " + str(traceback.format_exc()))
|
|
||||||
sys.exit(1)
|
|
||||||
|
|
||||||
sys.exit(0)
|
|
||||||
|
681
src/main.py
Normal file
681
src/main.py
Normal file
@ -0,0 +1,681 @@
|
|||||||
|
"""
|
||||||
|
********************************************************************************
|
||||||
|
* CNIRevelator *
|
||||||
|
* *
|
||||||
|
* Desc: Application IHM & work main class *
|
||||||
|
* *
|
||||||
|
* Copyright © 2018-2019 Adrien Bourmault (neox95) *
|
||||||
|
* *
|
||||||
|
* This file is part of CNIRevelator. *
|
||||||
|
* *
|
||||||
|
* CNIRevelator is free software: you can redistribute it and/or modify *
|
||||||
|
* it under the terms of the GNU General Public License as published by *
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or *
|
||||||
|
* any later version. *
|
||||||
|
* *
|
||||||
|
* CNIRevelator is distributed in the hope that it will be useful, *
|
||||||
|
* but WITHOUT ANY WARRANTY*without even the implied warranty of *
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||||
|
* GNU General Public License for more details. *
|
||||||
|
* *
|
||||||
|
* You should have received a copy of the GNU General Public License *
|
||||||
|
* along with CNIRevelator. If not, see <https:*www.gnu.org/licenses/>. *
|
||||||
|
********************************************************************************
|
||||||
|
"""
|
||||||
|
|
||||||
|
from PIL import Image, ImageFont, ImageDraw, ImageTk, ImageEnhance, ImageFilter
|
||||||
|
import math, warnings, string
|
||||||
|
|
||||||
|
import mrz # mrz.py
|
||||||
|
from image import CanvasImage # image.py
|
||||||
|
|
||||||
|
class mainWindow(Tk):
|
||||||
|
|
||||||
|
def __init__(self, logger):
|
||||||
|
Tk.__init__(self)
|
||||||
|
self.initialize(logger)
|
||||||
|
|
||||||
|
def initialize(self, logger):
|
||||||
|
self.logger = logger
|
||||||
|
self.PILE_ETAT = []
|
||||||
|
self.MRZCHAR = ''
|
||||||
|
self.varnum = 10
|
||||||
|
self.Score = []
|
||||||
|
for type in mrz.TYPES:
|
||||||
|
self.Score += [0]
|
||||||
|
|
||||||
|
ws = self.winfo_screenwidth()
|
||||||
|
hs = self.winfo_screenheight()
|
||||||
|
self.logger.info('mainWindow() : 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é")
|
||||||
|
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)
|
||||||
|
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')
|
||||||
|
self.STATUT.grid_columnconfigure(0, weight=1)
|
||||||
|
self.STATUT.grid_rowconfigure(0, weight=1)
|
||||||
|
self.STATUStxt = Label((self.STATUT), text='', font='Times 24', fg='#FFBF00')
|
||||||
|
self.STATUStxt.grid(column=0, row=0, padx=0, pady=0, sticky='EWNS')
|
||||||
|
self.STATUStxt['text'] = 'EN ATTENTE'
|
||||||
|
self.terminal = ttk.Labelframe(self, text='Terminal de saisie')
|
||||||
|
self.terminal.grid_columnconfigure(0, weight=1)
|
||||||
|
self.terminal.grid_rowconfigure(0, weight=1)
|
||||||
|
self.termframe = Frame(self.terminal)
|
||||||
|
self.termframe.grid(column=0, row=0, sticky='EW')
|
||||||
|
self.termframe.grid_columnconfigure(0, weight=1)
|
||||||
|
self.termframe.grid_rowconfigure(0, weight=1)
|
||||||
|
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.entryValidation), '%S', '%P', '%d')
|
||||||
|
self.termentry = Entry((self.termframe), font='Terminal 17', entryValidation='all', entryValidationcommand=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
|
||||||
|
self.monitor.grid_columnconfigure(0, weight=1)
|
||||||
|
self.monitor.grid_rowconfigure(0, weight=1)
|
||||||
|
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)
|
||||||
|
menubar = Menu(self)
|
||||||
|
menu1 = Menu(menubar, tearoff=0)
|
||||||
|
menu1.add_command(label='Nouveau', command=(self.newEntry))
|
||||||
|
menu1.add_command(label='Ouvrir scan...', command=(self.openingScan))
|
||||||
|
menu1.add_separator()
|
||||||
|
menu1.add_command(label='Quitter', command=(self.destroy))
|
||||||
|
menubar.add_cascade(label='Fichier', menu=menu1)
|
||||||
|
menu3 = Menu(menubar, tearoff=0)
|
||||||
|
menu3.add_command(label='A propos', command=(self.infobox))
|
||||||
|
menubar.add_cascade(label='Aide', menu=menu3)
|
||||||
|
self.config(menu=menubar)
|
||||||
|
self.wm_title(CST_TITLE)
|
||||||
|
if getattr(sys, 'frozen', False):
|
||||||
|
self.iconbitmap(sys._MEIPASS + '\\id-card.ico\\id-card.ico')
|
||||||
|
else:
|
||||||
|
self.iconbitmap('id-card.ico')
|
||||||
|
self.resizable(width=True, height=True)
|
||||||
|
self.update()
|
||||||
|
self.minsize(self.winfo_width(), self.winfo_height())
|
||||||
|
w = int(self.winfo_width())
|
||||||
|
h = int(self.winfo_height())
|
||||||
|
ws = self.winfo_screenwidth()
|
||||||
|
hs = self.winfo_screenheight()
|
||||||
|
x = ws / 2 - w / 2
|
||||||
|
y = hs / 2 - h / 2
|
||||||
|
self.geometry('%dx%d+%d+%d' % (w, h, x, y))
|
||||||
|
self.termentry.bind('<Return>', self.preentryValidation)
|
||||||
|
self.termtext.bind('<Return>', self.preentryValidation)
|
||||||
|
self.termentry.bind('<Escape>', self.onTabPressed)
|
||||||
|
self.update()
|
||||||
|
self.logger.info('mainWindow() : Initialization successful')
|
||||||
|
|
||||||
|
def preentryValidation(self, event):
|
||||||
|
self.logger.debug('preentryValidation() : Entering Validation')
|
||||||
|
if self.PILE_ETAT != [] and len(self.PILE_ETAT) == 1:
|
||||||
|
thetext = self.termentry.get()
|
||||||
|
self.logger.debug('preentryValidation() : PILE_ETAT Satisfy the requisites : ' + str(self.PILE_ETAT))
|
||||||
|
n = len(thetext)
|
||||||
|
champ = mrz.TYPES[self.PILE_ETAT[0]][0]
|
||||||
|
if not n % champ.find('|') == 0:
|
||||||
|
self.logger.debug('preentryValidation() : Line not complete, operation aborted')
|
||||||
|
return 'break'
|
||||||
|
self.MRZCHAR += thetext
|
||||||
|
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.logOnTerm('Entrez la seconde ligne de la MRZ ou \nappuyez sur Entrée pour terminer.\n')
|
||||||
|
self.logger.debug('preentryValidation() : First line accepted')
|
||||||
|
self.MRZCHAR += '|'
|
||||||
|
else:
|
||||||
|
if len(self.MRZCHAR) == champ.find('|') * 2 + 1 or len(champ) == champ.find('|') + 1:
|
||||||
|
self.logOnTerm('\nCalcul des sommes ...\n')
|
||||||
|
self.logger.info('preentryValidation() : 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('preentryValidation() : PILE_ETAT Satisfy the requisites : ' + str(self.PILE_ETAT))
|
||||||
|
n = len(self.MRZCHAR)
|
||||||
|
champ = mrz.TYPES[self.PILE_ETAT[1]][0]
|
||||||
|
for char in self.MRZCHAR:
|
||||||
|
if char not in 'ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789<|':
|
||||||
|
self.logOnTerm('\nSyntaxe 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('preentryValidation() : : ' + str(self.PILE_ETAT))
|
||||||
|
self.logOnTerm('\nCalcul des sommes ...\n')
|
||||||
|
self.logger.info('preentryValidation() : Launching calculSigma() thread')
|
||||||
|
threading.Thread(target=(self.calculSigma), args=[self.MRZCHAR, self.PILE_ETAT[1]]).start()
|
||||||
|
return 'break'
|
||||||
|
|
||||||
|
def onTabPressed(self, event):
|
||||||
|
if self.PILE_ETAT != [] and len(self.PILE_ETAT) == 1:
|
||||||
|
thetext = self.termentry.get()
|
||||||
|
n = len(thetext)
|
||||||
|
champ = mrz.TYPES[self.PILE_ETAT[0]][0]
|
||||||
|
if len(self.MRZCHAR) <= champ.find('|'):
|
||||||
|
champ_type = mrz.TYPES[self.PILE_ETAT[0]][1][champ[(n - 1)]].split('|')
|
||||||
|
self.logger.debug('onTabPressed() : First line detected')
|
||||||
|
self.logger.debug('onTabPressed() : champ_type[0] : ' + str(champ_type[0]))
|
||||||
|
self.logger.debug('onTabPressed() : champ : ' + str(champ))
|
||||||
|
self.logger.debug('onTabPressed() : champ[n-1] : ' + str(champ[(n - 1)]))
|
||||||
|
self.logger.debug('onTabPressed() : champ.find(champ[n-1]) : ' + str(champ.find(champ[(n - 1)])))
|
||||||
|
nb = int(champ_type[0]) - (n - champ.find(champ[(n - 1)]))
|
||||||
|
else:
|
||||||
|
self.logger.debug('onTabPressed() : Second line detected')
|
||||||
|
champ = champ[champ.find('|') + 1:]
|
||||||
|
champ_type = mrz.TYPES[self.PILE_ETAT[0]][1][champ[(n - 1)]].split('|')
|
||||||
|
self.logger.debug('onTabPressed() : champ_type[0] : ' + str(champ_type[0]))
|
||||||
|
self.logger.debug('onTabPressed() : champ : ' + str(champ))
|
||||||
|
self.logger.debug('onTabPressed() : champ[n-1] : ' + str(champ[(n - 1)]))
|
||||||
|
self.logger.debug('onTabPressed() : champ.find(champ[n-1]) : ' + str(champ.find(champ[(n - 1)])))
|
||||||
|
self.logger.debug('onTabPressed() : n : ' + str(n))
|
||||||
|
nb = int(champ_type[0]) - (n - champ.find(champ[(n - 1)]))
|
||||||
|
self.termentry.insert('end', '<' * nb)
|
||||||
|
self.logger.debug('onTabPressed() : Completing entry with ' + str(nb) + ' characters <')
|
||||||
|
return 'break'
|
||||||
|
|
||||||
|
def entryValidation(self, char, entry_value, typemod):
|
||||||
|
set = False
|
||||||
|
isValid = True
|
||||||
|
if typemod == '1':
|
||||||
|
SUM = 0
|
||||||
|
for ch in char:
|
||||||
|
if ch in 'ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789<':
|
||||||
|
continue
|
||||||
|
self.bell()
|
||||||
|
isValid = False
|
||||||
|
|
||||||
|
else:
|
||||||
|
if typemod == '0':
|
||||||
|
for ch in char:
|
||||||
|
if ch in 'ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789<':
|
||||||
|
continue
|
||||||
|
self.bell()
|
||||||
|
isValid = False
|
||||||
|
|
||||||
|
n = len(entry_value)
|
||||||
|
if (n % self.varnum == 0 or len(char) > 3) and n < 45 and self.PILE_ETAT == []:
|
||||||
|
for i in range(len(self.Score)):
|
||||||
|
self.Score[i] = 0
|
||||||
|
|
||||||
|
for type, t in zip(mrz.TYPES, range(len(mrz.TYPES))):
|
||||||
|
for e in range(len(entry_value)):
|
||||||
|
try:
|
||||||
|
champchartest = type[0][:type[0].find('|')][e]
|
||||||
|
champchar = type[0][e]
|
||||||
|
except IndexError:
|
||||||
|
self.logger.debug('entryValidation() : type : ' + str(t))
|
||||||
|
self.logger.debug('entryValidation() : Too short to be ok')
|
||||||
|
self.Score[t] += -5
|
||||||
|
break
|
||||||
|
else:
|
||||||
|
self.logger.debug('entryValidation() : 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('entryValidation() : champ_type[2][pos] : ' + str(champ_type[2][pos]))
|
||||||
|
self.logger.debug('entryValidation() : champ_type[1] : ' + str(champ_type[1]))
|
||||||
|
if champ_type[1] == 'CODE':
|
||||||
|
if champ_type[2][pos] == '*':
|
||||||
|
self.Score[t] += 0
|
||||||
|
else:
|
||||||
|
if champ_type[2][pos] == entry_value[e]:
|
||||||
|
self.Score[t] += 1
|
||||||
|
self.logger.debug('entryValidation() : +1')
|
||||||
|
else:
|
||||||
|
self.Score[t] += -50
|
||||||
|
elif champ_type[2][pos] == '*':
|
||||||
|
self.Score[t] += 1
|
||||||
|
self.logger.debug('entryValidation() : +1')
|
||||||
|
else:
|
||||||
|
if champ_type[2][pos] == 'A':
|
||||||
|
if entry_value[e].isalpha():
|
||||||
|
self.Score[t] += 1
|
||||||
|
self.logger.debug('entryValidation() : +1')
|
||||||
|
if champ_type[2][pos] == '0':
|
||||||
|
if entry_value[e].isnumeric():
|
||||||
|
self.Score[t] += 1
|
||||||
|
self.logger.debug('entryValidation() : +1')
|
||||||
|
if champ_type[1] == 'CTRL':
|
||||||
|
if entry_value[e].isnumeric():
|
||||||
|
self.Score[t] += 1
|
||||||
|
self.logger.debug('entryValidation() : +1')
|
||||||
|
if champ_type[2][pos] == '&':
|
||||||
|
if entry_value[e].isalpha() or entry_value[e] == '<':
|
||||||
|
self.Score[t] += 1
|
||||||
|
self.logger.debug('entryValidation() : +1')
|
||||||
|
self.Score[t] += -1
|
||||||
|
continue
|
||||||
|
|
||||||
|
self.logger.debug('entryValidation() : self.Score : ' + str(self.Score))
|
||||||
|
m = max(self.Score)
|
||||||
|
typem = [i for i, j in enumerate(self.Score) if j == m if m > 5]
|
||||||
|
for h in typem:
|
||||||
|
self.PILE_ETAT += [h]
|
||||||
|
|
||||||
|
if len(self.PILE_ETAT) > 1:
|
||||||
|
self.varnum += 3
|
||||||
|
self.PILE_ETAT = []
|
||||||
|
else:
|
||||||
|
if len(self.PILE_ETAT) == 1:
|
||||||
|
TOPOS = mrz.TYPES[self.PILE_ETAT[0]][2]
|
||||||
|
self.logOnTerm(TOPOS + " détectée !\nAppuyez sur Echap pour compléter les champs avec des '<'\nAppuyez sur Entrée pour terminer.\n")
|
||||||
|
self.logger.debug('entryValidation() : Detection : ' + str(TOPOS))
|
||||||
|
else:
|
||||||
|
if len(self.PILE_ETAT) == 1:
|
||||||
|
if len(entry_value) > len(mrz.TYPES[self.PILE_ETAT[0]][0].split('|')[0]):
|
||||||
|
isValid = False
|
||||||
|
return isValid
|
||||||
|
|
||||||
|
def logOnTerm(self, text):
|
||||||
|
self.monlog['state'] = 'normal'
|
||||||
|
self.monlog.insert('end', text)
|
||||||
|
self.monlog['state'] = 'disabled'
|
||||||
|
self.monlog.yview(END)
|
||||||
|
|
||||||
|
def openingScan(self):
|
||||||
|
self.initialize(self.logger)
|
||||||
|
self.update()
|
||||||
|
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))
|
||||||
|
im = Image.open(path)
|
||||||
|
try:
|
||||||
|
nframe = im.n_frames
|
||||||
|
except AttributeError:
|
||||||
|
nframe = 1
|
||||||
|
|
||||||
|
if nframe == 1:
|
||||||
|
self.mrzdetected = ''
|
||||||
|
self.mrzdict = {}
|
||||||
|
try:
|
||||||
|
opening = OpenScanWin(self, path, 0)
|
||||||
|
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.error('openingScan() : Incompatible file with path ' + str(path))
|
||||||
|
return
|
||||||
|
self.logger.debug('openingScan() : ' + str(self.mrzdetected))
|
||||||
|
else:
|
||||||
|
if nframe > 1:
|
||||||
|
self.mrzdetected = ''
|
||||||
|
self.mrzdict = {}
|
||||||
|
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))
|
||||||
|
try:
|
||||||
|
os.remove(CST_FOLDER + '\\temp.tif')
|
||||||
|
except IOError:
|
||||||
|
pass
|
||||||
|
|
||||||
|
else:
|
||||||
|
raise Exception
|
||||||
|
mrzsoumisetab = self.mrzdetected.replace(' ', '').split('\n')
|
||||||
|
for chain in mrzsoumisetab:
|
||||||
|
self.termentry.insert('end', chain)
|
||||||
|
if len(chain) >= 5:
|
||||||
|
self.preentryValidation('<Return>')
|
||||||
|
|
||||||
|
def newEntry(self):
|
||||||
|
self.initialize(self.logger)
|
||||||
|
self.logOnTerm('\n\nEntrez la première ligne de MRZ svp \n')
|
||||||
|
|
||||||
|
def infobox(self):
|
||||||
|
Tk().withdraw()
|
||||||
|
showinfo('A propos du logiciel', ('Version du logiciel : \n' + CST_NAME + ' ' + CST_VER + ' ' + CST_TYPE + ' Revision ' + CST_REV + "\nLicence GNU/GPL 2018\n\nAuteur : NeoX_ ; devadmin@neoxgroup.eu\n\nTesseract 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 mrz.TYPES[numtype][1].items() if 'CTRL' in v]
|
||||||
|
self.logger.info('[calculSigma() thread] : Sigma calculation launched!')
|
||||||
|
self.logger.debug('[calculSigma() thread] : CTRList = ' + str(CTRList))
|
||||||
|
self.Falsitude = 0
|
||||||
|
self.logOnTerm('\n')
|
||||||
|
for i in CTRList:
|
||||||
|
sumtxt = mrz.TYPES[numtype][1][i]
|
||||||
|
length = mrz.TYPES[numtype][0].find('|')
|
||||||
|
index = mrz.TYPES[numtype][0].find(i)
|
||||||
|
sum_read = MRZtxt[index]
|
||||||
|
if len(sumtxt.split('|')[2]) == 1:
|
||||||
|
debut = mrz.TYPES[numtype][0].find(sumtxt.split('|')[2][0])
|
||||||
|
sum_calc = mrz.MRZ(MRZtxt[int(debut):index])
|
||||||
|
else:
|
||||||
|
transm_chain = ''
|
||||||
|
for y in sumtxt.split('|')[2]:
|
||||||
|
debut = mrz.TYPES[numtype][0].find(y)
|
||||||
|
fin = debut + int(mrz.TYPES[numtype][1][y].split('|')[0])
|
||||||
|
transm_chain += MRZtxt[int(debut):int(fin)]
|
||||||
|
|
||||||
|
sum_calc = mrz.MRZ(transm_chain)
|
||||||
|
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.logOnTerm('Somme : Lu ' + str(sum_read) + ' VS calculé ' + str(sum_calc) + '\n')
|
||||||
|
|
||||||
|
NameList = [c for c, v in mrz.TYPES[numtype][1].items() if '|NOM' in v]
|
||||||
|
SurnameList = [c for c, v in mrz.TYPES[numtype][1].items() if 'PRENOM' in v]
|
||||||
|
DDateList = [c for c, v in mrz.TYPES[numtype][1].items() if 'DDATE' in v]
|
||||||
|
BDateList = [c for c, v in mrz.TYPES[numtype][1].items() if 'BDATE' in v]
|
||||||
|
EDateList = [c for c, v in mrz.TYPES[numtype][1].items() if 'EDATE' in v]
|
||||||
|
PAYSList = [c for c, v in mrz.TYPES[numtype][1].items() if 'PAYS' in v]
|
||||||
|
NATList = [c for c, v in mrz.TYPES[numtype][1].items() if 'NAT' in v]
|
||||||
|
SEXList = [c for c, v in mrz.TYPES[numtype][1].items() if 'SEX' in v]
|
||||||
|
NOINTList = [c for c, v in mrz.TYPES[numtype][1].items() if 'NOINT' in v]
|
||||||
|
NOList = [c for c, v in mrz.TYPES[numtype][1].items() if 'NO|' in v]
|
||||||
|
FACULTList = [c for c, v in mrz.TYPES[numtype][1].items() if 'FACULT' in v]
|
||||||
|
INDICList = [c for c, v in mrz.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]
|
||||||
|
for i in range(len(BIGList)):
|
||||||
|
for champ, champnum in zip(BIGList[i], range(len(BIGList[i]))):
|
||||||
|
debut = mrz.TYPES[numtype][0].find(champ)
|
||||||
|
fin = debut + int(mrz.TYPES[numtype][1][champ].split('|')[0])
|
||||||
|
if BIGObj[i] == self.pays or BIGObj[i] == self.nat:
|
||||||
|
try:
|
||||||
|
BIGObj[i]['text'] = mrz.landcode[MRZtxt[int(debut):int(fin)].replace('<', '')]
|
||||||
|
except KeyError:
|
||||||
|
self.Falsitude += 1
|
||||||
|
self.logOnTerm('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')
|
||||||
|
elif BIGObj[i] == self.sex:
|
||||||
|
try:
|
||||||
|
BIGObj[i]['text'] = mrz.sexcode[MRZtxt[int(debut):int(fin)]]
|
||||||
|
except KeyError:
|
||||||
|
self.Falsitude += 1
|
||||||
|
self.logOnTerm('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'
|
||||||
|
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')
|
||||||
|
else:
|
||||||
|
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.logOnTerm('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.logOnTerm('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')
|
||||||
|
else:
|
||||||
|
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 !')
|
||||||
|
else:
|
||||||
|
self.STATUStxt['text'] = 'NON CONFORME'
|
||||||
|
self.STATUStxt['fg'] = '#760808'
|
||||||
|
self.logger.debug('[calculSigma() thread] : Non conforme !')
|
||||||
|
self.logOnTerm('** Score de non conformité : ' + str(self.Falsitude) + '**\n')
|
||||||
|
self.termtext['state'] = 'normal'
|
||||||
|
self.PILE_ETAT = [self.Falsitude, numtype]
|
||||||
|
|
||||||
|
|
||||||
|
class OpenScan(ttk.Frame):
|
||||||
|
|
||||||
|
def __init__(self, mainframe, fileorig, type, nframe=1, pagenum=0, file=None):
|
||||||
|
""" Initialize the main Frame """
|
||||||
|
if file == None:
|
||||||
|
file = fileorig
|
||||||
|
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()
|
||||||
|
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
|
||||||
|
self.master.geometry('%dx%d+%d+%d' % (w, h, x, y))
|
||||||
|
if getattr(sys, 'frozen', False):
|
||||||
|
self.master.iconbitmap(sys._MEIPASS + '\\id-card.ico\\id-card.ico')
|
||||||
|
else:
|
||||||
|
self.master.iconbitmap('id-card.ico')
|
||||||
|
self.master.rowconfigure(0, weight=1)
|
||||||
|
self.master.columnconfigure(0, weight=1)
|
||||||
|
self.cadre = CanvasImage(self.master, self.file, type)
|
||||||
|
self.cadre.grid(row=0, column=0)
|
||||||
|
self.master.menubar = Menu(self.master)
|
||||||
|
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))
|
||||||
|
self.cadre.canvas.bind('<ButtonPress-3>', self.motionprep)
|
||||||
|
self.cadre.canvas.bind('<B3-Motion>', self.motionize)
|
||||||
|
self.cadre.canvas.bind('<ButtonRelease-3>', self.motionend)
|
||||||
|
|
||||||
|
def pages(self):
|
||||||
|
if self.pagenum + 1 < self.nframe:
|
||||||
|
im = Image.open(self.fileorig)
|
||||||
|
im.seek(self.pagenum + 1)
|
||||||
|
newpath = CST_FOLDER + '\\temp' + str(random.randint(11111, 99999)) + '.tif'
|
||||||
|
im.save(newpath)
|
||||||
|
im.close()
|
||||||
|
self.cadre.destroy()
|
||||||
|
self.__init__(self.master, self.fileorig, 1, self.nframe, self.pagenum + 1, newpath)
|
||||||
|
|
||||||
|
def pagep(self):
|
||||||
|
if self.pagenum - 1 >= 0:
|
||||||
|
im = Image.open(self.fileorig)
|
||||||
|
im.seek(self.pagenum - 1)
|
||||||
|
newpath = CST_FOLDER + '\\temp' + str(random.randint(11111, 99999)) + '.tif'
|
||||||
|
im.save(newpath)
|
||||||
|
im.close()
|
||||||
|
self.cadre.destroy()
|
||||||
|
self.__init__(self.master, self.fileorig, 1, self.nframe, self.pagenum - 1, newpath)
|
||||||
|
|
||||||
|
def motionprep(self, event):
|
||||||
|
if hasattr(self, 'rect'):
|
||||||
|
self.begx = event.x
|
||||||
|
self.begy = event.y
|
||||||
|
self.ix = self.cadre.canvas.canvasx(event.x)
|
||||||
|
self.iy = self.cadre.canvas.canvasy(event.y)
|
||||||
|
self.cadre.canvas.coords(self.rect, self.cadre.canvas.canvasx(event.x), self.cadre.canvas.canvasy(event.y), self.ix, self.iy)
|
||||||
|
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)
|
||||||
|
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):
|
||||||
|
event.x
|
||||||
|
event.y
|
||||||
|
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):
|
||||||
|
self.endx = event.x
|
||||||
|
self.endy = event.y
|
||||||
|
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)))
|
||||||
|
im = self.imtotreat
|
||||||
|
import CNI_pytesseract as pytesseract
|
||||||
|
try:
|
||||||
|
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<')
|
||||||
|
except pytesseract.TesseractNotFoundError as e:
|
||||||
|
try:
|
||||||
|
os.remove(CST_FOLDER + '\\Tesseract-OCR4\\*.*')
|
||||||
|
except Exception:
|
||||||
|
pass
|
||||||
|
|
||||||
|
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)
|
||||||
|
except pytesseract.TesseractError as e:
|
||||||
|
pass
|
||||||
|
|
||||||
|
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()
|
||||||
|
|
756
src/mrz.py
Normal file
756
src/mrz.py
Normal file
@ -0,0 +1,756 @@
|
|||||||
|
"""
|
||||||
|
********************************************************************************
|
||||||
|
* CNIRevelator *
|
||||||
|
* *
|
||||||
|
* Desc: MRZ data dictionnary for CNIRevelator analyzer and *
|
||||||
|
* functions to analyze these data *
|
||||||
|
* *
|
||||||
|
* 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/>. *
|
||||||
|
********************************************************************************
|
||||||
|
"""
|
||||||
|
|
||||||
|
## 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"
|
||||||
|
}
|
||||||
|
|
||||||
|
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"
|
||||||
|
}
|
||||||
|
|
||||||
|
## DOCUMENTS TYPES
|
||||||
|
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]
|
||||||
|
|
||||||
|
## THE ROOT OF THIS PROJECT !
|
||||||
|
def MRZ(code):
|
||||||
|
"""
|
||||||
|
This function computes a control sum for a range of characters
|
||||||
|
"""
|
||||||
|
resultat = 0
|
||||||
|
i = -1
|
||||||
|
facteur = [7, 3, 1]
|
||||||
|
for car in code:
|
||||||
|
if car == '<' or car == '|':
|
||||||
|
valeur = 0
|
||||||
|
i += 1
|
||||||
|
else:
|
||||||
|
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
|
Loading…
Reference in New Issue
Block a user