Merge pull request #13 from neox95/v3.0
V3.0.8 release and now working on 3.1
5
.gitignore
vendored
@ -8,3 +8,8 @@
|
||||
|
||||
build/*
|
||||
dist/*
|
||||
src/Tesseract-OCR4/*
|
||||
src/downloads/*
|
||||
src/config/*
|
||||
src/logs/*
|
||||
signtool_8.1/*
|
||||
|
@ -1,2 +1,2 @@
|
||||
# ver|url|checksum, and | as separator, one version per ||
|
||||
3.0.4|https://github.com/neox95/CNIRevelator/releases/download/3.0.4/CNIRevelator.zip|d03a18b35dfbb20d90664dc2c0f990adc5522e46||3.0.5|https://github.com/neox95/CNIRevelator/releases/download/3.0.5/CNIRevelator.zip|8b52290fb0910d8b9c4ec43293b08017e0031ca2||3.0.6|https://github.com/neox95/CNIRevelator/releases/download/3.0.6/CNIRevelator.zip|4bb4606dc9310d7b34b1fb38f9a0c2daf9518dc5||
|
||||
3.0.4|https://github.com/neox95/CNIRevelator/releases/download/3.0.4/CNIRevelator.zip|d03a18b35dfbb20d90664dc2c0f990adc5522e46||3.0.5|https://github.com/neox95/CNIRevelator/releases/download/3.0.5/CNIRevelator.zip|8b52290fb0910d8b9c4ec43293b08017e0031ca2||3.0.6|https://github.com/neox95/CNIRevelator/releases/download/3.0.6/CNIRevelator.zip|4bb4606dc9310d7b34b1fb38f9a0c2daf9518dc5||3.0.7|https://github.com/neox95/CNIRevelator/releases/download/3.0.7/CNIRevelator.zip|9aea1627c0b75610225a02458d5705563ca0d6af||3.0.8|https://github.com/neox95/CNIRevelator/releases/download/3.0.8/CNIRevelator.zip|8e849f8fcb5c952c09bdd4eb3392456ec9c6cf8f||
|
||||
|
BIN
id-card.ico
Before Width: | Height: | Size: 1.9 KiB |
6
make.bat
@ -4,15 +4,15 @@ title Compilation de CNIRevelator
|
||||
|
||||
|
||||
|
||||
call pyinstaller -w -D --exclude-module PyQt5 --bootloader-ignore-signals --add-data "C:\Users\pf04950\AppData\Local\Continuum\anaconda3\Lib\site-packages\tld\res\effective_tld_names.dat.txt";"tld\res" --add-data "id-card.ico";"id-card.ico" -i "id-card.ico" -n CNIRevelator src\CNIRevelator.py
|
||||
call pyinstaller -w -D --exclude-module PyQt5 --bootloader-ignore-signals --add-data "C:\Users\adrie\Anaconda3\Lib\site-packages\tld\res\effective_tld_names.dat.txt";"tld\res" --add-data "src\id-card.ico";"id-card.ico" -i "src\id-card.ico" -n CNIRevelator src\CNIRevelator.py
|
||||
|
||||
|
||||
|
||||
copy LICENSE dist\CNIRevelator\LICENSE
|
||||
copy src\id-card.ico dist\CNIRevelator\id-card.ico
|
||||
copy src\background.png dist\CNIRevelator\background.png
|
||||
copy src\*.png dist\CNIRevelator\*.png
|
||||
|
||||
D:\Public\CNIRevelator-master\CNIRevelator-master\signtool_8.1\signtool\signtool.exe sign /n "CNIRevelator by Adrien Bourmault (neox95)" dist\CNIRevelator\CNIRevelator.exe
|
||||
signtool_8.1\signtool\signtool.exe sign /n "CNIRevelator by Adrien Bourmault (neox95)" dist\CNIRevelator\CNIRevelator.exe
|
||||
|
||||
pause
|
||||
|
||||
|
@ -31,7 +31,7 @@ import threading
|
||||
import traceback
|
||||
import psutil
|
||||
|
||||
import launcher # launcher.py
|
||||
import launcher # launcher.py"
|
||||
import updater # updater.py
|
||||
import globs # globs.py
|
||||
import pytesseract # pytesseract.py
|
||||
|
BIN
src/Invert.png
Normal file
After Width: | Height: | Size: 553 B |
BIN
src/OCR.png
Normal file
After Width: | Height: | Size: 512 B |
12
src/globs.py
@ -25,18 +25,13 @@
|
||||
import os
|
||||
|
||||
# CNIRevelator version
|
||||
verType = "alpha"
|
||||
version = [3, 0, 6]
|
||||
verType = "final release"
|
||||
version = [3, 1, 0]
|
||||
verstring_full = "{}.{}.{} {}".format(version[0], version[1], version[2], verType)
|
||||
verstring = "{}.{}".format(version[0], version[1])
|
||||
debug = True
|
||||
|
||||
changelog = "Version 3.0.6 \nMise-à-jour mineure avec les corrections suivantes :\n- Changement de l'apparence du launcher de l'application\n- Améliorations de l'interface, notamment de la stabilité\n- Ajout de la signature numérique de l'exécutable\n\n" + \
|
||||
"Version 3.0.5 \nMise-à-jour mineure avec les corrections suivantes :\n- Changement de l'icône de l'exécutable afin de refléter le changement de version majeur accompli en 3.0\n\n" + \
|
||||
"Version 3.0.4 \nMise-à-jour mineure avec les corrections suivantes :\n- Correction d'un bug affectant le système de mise-à-jour\n\n" + \
|
||||
"Version 3.0.3 \nMise-à-jour mineure avec les corrections suivantes :\n- Correction d'un bug affectant le changelog\n- Correction d'une erreur avec la touche Suppr Arrière et Suppr causant une perte de données\n\n" + \
|
||||
"Version 3.0.2 \nMise-à-jour mineure avec les corrections suivantes :\n- Changement d'icône de l'exécutable\n- Correction d'un bug affectant le logging\n- Correction d'un bug affectant la détection de documents\n- Et autres modifications mineures\n\n" + \
|
||||
"Version 3.0.1 \nMise-à-jour majeure avec les corrections suivantes :\n- Renouvellement de la signature numérique de l'exécutable\n- Amélioration de présentation du log en cas d'erreur\n- Refonte totale du code source et désobfuscation\n- Téléchargements en HTTPS fiables avec somme de contrôle\n- Nouveaux terminaux d'entrées : un rapide (731) et un complet\n- Détection des documents améliorée, possibilité de choix plus fin\nEt les regressions suivantes :\n- Suppression temporaire de la fonction de lecture OCR. Retour planifié pour une prochaine version"
|
||||
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()
|
||||
@ -46,6 +41,7 @@ CNIRCryptoKey = '82Xh!efX3#@P~2eG'
|
||||
CNIRNewVersion = False
|
||||
|
||||
CNIRConfig = CNIRFolder + '\\config\\conf.ig'
|
||||
CNIRTesser = CNIRFolder + '\\Tesseract-OCR4\\'
|
||||
CNIRErrLog = CNIRFolder + '\\logs\\error.log'
|
||||
CNIRMainLog = CNIRFolder + '\\logs\\main.log'
|
||||
CNIRUrlConfig = CNIRFolder + '\\config\\urlconf.ig'
|
||||
|
54
src/ihm.py
@ -32,7 +32,6 @@ import PIL.Image, PIL.ImageTk
|
||||
|
||||
import logger # logger.py
|
||||
import globs # globs.py
|
||||
import image # image.py
|
||||
|
||||
|
||||
controlKeys = ["Escape", "Right", "Left", "Up", "Down", "Home", "End", "BackSpace", "Delete", "Inser", "Shift_L", "Shift_R", "Control_R", "Control_L"]
|
||||
@ -70,6 +69,44 @@ class DocumentAsk(Toplevel):
|
||||
def ok(self):
|
||||
self.destroy()
|
||||
|
||||
|
||||
class OpenScanDialog(Toplevel):
|
||||
|
||||
def __init__(self, parent, text):
|
||||
super().__init__(parent)
|
||||
self.parent = parent
|
||||
self.title('Validation de la MRZ détectée par OCR')
|
||||
self.resizable(width=False, height=False)
|
||||
self.termtext = Text(self, state='normal', width=45, height=2, wrap='none', font='Terminal 17', fg='#121f38')
|
||||
self.termtext.grid(column=0, row=0, sticky='NEW', padx=5, pady=5)
|
||||
self.termtext.insert('end', text + '\n')
|
||||
self.button = Button(self, text='Valider', command=(self.valid))
|
||||
self.button.grid(column=0, row=1, sticky='S', padx=5, pady=5)
|
||||
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.validatedtext = self.termtext.get('1.0', 'end')
|
||||
texting = self.parent.validatedtext.replace(' ', '').replace('\r', '').split('\n')
|
||||
for i in range(len(texting)):
|
||||
for char in texting[i]:
|
||||
if char not in 'ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789<':
|
||||
showerror('Erreur de validation', 'La MRZ soumise contient des caractères invalides', parent=self)
|
||||
self.parent.validatedtext = ''
|
||||
|
||||
self.destroy()
|
||||
|
||||
class LoginDialog(Toplevel):
|
||||
|
||||
def __init__(self, parent):
|
||||
@ -178,21 +215,6 @@ class LauncherWindow(Tk):
|
||||
def exit(self):
|
||||
self.after(1000, self.destroy)
|
||||
|
||||
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 ResizeableCanvas(Canvas):
|
||||
def __init__(self,parent,**kwargs):
|
||||
Canvas.__init__(self,parent,**kwargs)
|
||||
|
25
src/image.py
@ -1,25 +0,0 @@
|
||||
"""
|
||||
********************************************************************************
|
||||
* 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/>. *
|
||||
********************************************************************************
|
||||
"""
|
||||
|
475
src/main.py
@ -35,13 +35,14 @@ import re
|
||||
import traceback
|
||||
import cv2
|
||||
import PIL.Image, PIL.ImageTk
|
||||
import os, shutil
|
||||
import webbrowser
|
||||
|
||||
import ihm # ihm.py
|
||||
import logger # logger.py
|
||||
import mrz # mrz.py
|
||||
import globs # globs.py
|
||||
import pytesseract # pytesseract.py
|
||||
from image import * # image.py
|
||||
|
||||
# Global handler
|
||||
logfile = logger.logCur
|
||||
@ -53,10 +54,12 @@ class mainWindow(Tk):
|
||||
self.initialize()
|
||||
|
||||
def initialize(self):
|
||||
self.mrzChar = ''
|
||||
self.mrzChar = ""
|
||||
self.mrzDecided = False
|
||||
self.Tags = []
|
||||
self.compliance = True
|
||||
self.corners = []
|
||||
self.validatedtext = ""
|
||||
|
||||
# Hide during construction
|
||||
self.withdraw()
|
||||
@ -89,6 +92,9 @@ class mainWindow(Tk):
|
||||
self.lecteur_ci.grid_rowconfigure(5, weight=1)
|
||||
|
||||
# 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)
|
||||
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)
|
||||
self.nom = ttk.Label((self.lecteur_ci), text=' ')
|
||||
self.nom.grid(column=1, row=1, padx=5, pady=5)
|
||||
@ -146,18 +152,110 @@ class mainWindow(Tk):
|
||||
"INDIC" : self.indic,
|
||||
}
|
||||
|
||||
# The STATUS indicator + image display
|
||||
self.STATUT = ttk.Labelframe(self, text='Affichage de documents et statut')
|
||||
self.STATUT.grid_columnconfigure(0, weight=1)
|
||||
self.STATUT.grid_rowconfigure(0, weight=1)
|
||||
self.STATUT.frame = Frame(self.STATUT)
|
||||
self.STATUT.frame.grid(column=0, row=0, sticky='NSEW')
|
||||
self.STATUT.frame.grid_columnconfigure(0, weight=1)
|
||||
self.STATUT.frame.grid_rowconfigure(0, weight=1)
|
||||
self.STATUT.ZONE = ihm.ResizeableCanvas(self.STATUT.frame, bg=self["background"])
|
||||
self.STATUT.ZONE.pack(fill="both", expand=True)
|
||||
self.STATUSimg = self.STATUT.ZONE.create_image(0,0, image=None)
|
||||
self.STATUStxt = self.STATUT.ZONE.create_text(0,0, text='', font='Times 24', fill='#FFBF00')
|
||||
# The the image viewer
|
||||
self.imageViewer = ttk.Labelframe(self, text='Affichage et traitement de documents')
|
||||
self.imageViewer.grid_columnconfigure(0, weight=1)
|
||||
self.imageViewer.grid_columnconfigure(1, weight=0)
|
||||
self.imageViewer.grid_rowconfigure(0, weight=1)
|
||||
self.imageViewer.grid_rowconfigure(1, weight=1)
|
||||
self.imageViewer.grid_rowconfigure(2, weight=1)
|
||||
self.imageViewer.frame = Frame(self.imageViewer)
|
||||
self.imageViewer.frame.grid(column=0, row=0, sticky='NSEW')
|
||||
self.imageViewer.frame.grid_columnconfigure(0, weight=1)
|
||||
self.imageViewer.frame.grid_rowconfigure(0, weight=1)
|
||||
# + toolbar
|
||||
self.toolbar = ttk.Frame(self.imageViewer)
|
||||
self.toolbar.grid_columnconfigure(0, weight=1)
|
||||
self.toolbar.grid_columnconfigure(1, weight=1)
|
||||
self.toolbar.grid_columnconfigure(2, weight=1)
|
||||
self.toolbar.grid_columnconfigure(3, weight=1)
|
||||
self.toolbar.grid_columnconfigure(4, weight=1)
|
||||
self.toolbar.grid_columnconfigure(5, weight=1)
|
||||
self.toolbar.grid_columnconfigure(6, weight=1, minsize=10)
|
||||
self.toolbar.grid_columnconfigure(7, weight=1)
|
||||
self.toolbar.grid_columnconfigure(8, weight=1, minsize=10)
|
||||
self.toolbar.grid_columnconfigure(9, weight=1)
|
||||
self.toolbar.grid_columnconfigure(10, weight=1)
|
||||
self.toolbar.grid_columnconfigure(11, weight=1)
|
||||
self.toolbar.grid_columnconfigure(12, weight=1)
|
||||
self.toolbar.grid_columnconfigure(13, weight=1, minsize=10)
|
||||
self.toolbar.grid_columnconfigure(14, weight=1)
|
||||
self.toolbar.grid_columnconfigure(15, weight=1, minsize=10)
|
||||
self.toolbar.grid_columnconfigure(16, weight=1)
|
||||
self.toolbar.grid_rowconfigure(0, weight=1)
|
||||
|
||||
self.toolbar.zoomIn50Img = ImageTk.PhotoImage(PIL.Image.open("zoomIn50.png"))
|
||||
self.toolbar.zoomIn50 = ttk.Button(self.toolbar, image=self.toolbar.zoomIn50Img, command=self.zoomInScan50)
|
||||
self.toolbar.zoomIn50.grid(column=0, row=0)
|
||||
|
||||
self.toolbar.zoomIn20Img = ImageTk.PhotoImage(PIL.Image.open("zoomIn20.png"))
|
||||
self.toolbar.zoomIn20 = ttk.Button(self.toolbar, image=self.toolbar.zoomIn20Img, command=self.zoomInScan20)
|
||||
self.toolbar.zoomIn20.grid(column=1, row=0)
|
||||
|
||||
self.toolbar.zoomInImg = ImageTk.PhotoImage(PIL.Image.open("zoomIn.png"))
|
||||
self.toolbar.zoomIn = ttk.Button(self.toolbar, image=self.toolbar.zoomInImg, command=self.zoomInScan)
|
||||
self.toolbar.zoomIn.grid(column=2, row=0)
|
||||
|
||||
self.toolbar.zoomOutImg = ImageTk.PhotoImage(PIL.Image.open("zoomOut.png"))
|
||||
self.toolbar.zoomOut = ttk.Button(self.toolbar, image=self.toolbar.zoomOutImg, command=self.zoomOutScan)
|
||||
self.toolbar.zoomOut.grid(column=3, row=0)
|
||||
|
||||
self.toolbar.zoomOut20Img = ImageTk.PhotoImage(PIL.Image.open("zoomOut20.png"))
|
||||
self.toolbar.zoomOut20 = ttk.Button(self.toolbar, image=self.toolbar.zoomOut20Img, command=self.zoomOutScan20)
|
||||
self.toolbar.zoomOut20.grid(column=4, row=0)
|
||||
|
||||
self.toolbar.zoomOut50Img = ImageTk.PhotoImage(PIL.Image.open("zoomOut50.png"))
|
||||
self.toolbar.zoomOut50 = ttk.Button(self.toolbar, image=self.toolbar.zoomOut50Img, command=self.zoomOutScan50)
|
||||
self.toolbar.zoomOut50.grid(column=5, row=0)
|
||||
|
||||
self.toolbar.invertImg = ImageTk.PhotoImage(PIL.Image.open("invert.png"))
|
||||
self.toolbar.invert = ttk.Button(self.toolbar, image=self.toolbar.invertImg, command=self.negativeScan)
|
||||
self.toolbar.invert.grid(column=7, row=0)
|
||||
|
||||
self.toolbar.rotateLeftImg = ImageTk.PhotoImage(PIL.Image.open("rotateLeft.png"))
|
||||
self.toolbar.rotateLeft = ttk.Button(self.toolbar, image=self.toolbar.rotateLeftImg, command=self.rotateLeft)
|
||||
self.toolbar.rotateLeft.grid(column=9, row=0)
|
||||
|
||||
self.toolbar.rotateLeft1Img = ImageTk.PhotoImage(PIL.Image.open("rotateLeft1.png"))
|
||||
self.toolbar.rotateLeft1 = ttk.Button(self.toolbar, image=self.toolbar.rotateLeft1Img, command=self.rotateLeft1)
|
||||
self.toolbar.rotateLeft1.grid(column=10, row=0)
|
||||
|
||||
self.toolbar.rotateRight1Img = ImageTk.PhotoImage(PIL.Image.open("rotateRight1.png"))
|
||||
self.toolbar.rotateRight1 = ttk.Button(self.toolbar, image=self.toolbar.rotateRight1Img, command=self.rotateRight1)
|
||||
self.toolbar.rotateRight1.grid(column=11, row=0)
|
||||
|
||||
self.toolbar.rotateRightImg = ImageTk.PhotoImage(PIL.Image.open("rotateRight.png"))
|
||||
self.toolbar.rotateRight = ttk.Button(self.toolbar, image=self.toolbar.rotateRightImg, command=self.rotateRight)
|
||||
self.toolbar.rotateRight.grid(column=12, row=0)
|
||||
|
||||
self.toolbar.goOCRImg = ImageTk.PhotoImage(PIL.Image.open("OCR.png"))
|
||||
self.toolbar.goOCR = ttk.Button(self.toolbar, image=self.toolbar.goOCRImg, command=self.goOCRDetection)
|
||||
self.toolbar.goOCR.grid(column=14, row=0)
|
||||
|
||||
self.toolbar.pagenumber = StringVar()
|
||||
self.toolbar.pageChooser = ttk.Combobox(self.toolbar, textvariable=self.toolbar.pagenumber)
|
||||
self.toolbar.pageChooser.bind("<<ComboboxSelected>>", self.goPageChoice)
|
||||
self.toolbar.pageChooser['values'] = ('1')
|
||||
self.toolbar.pageChooser.current(0)
|
||||
self.toolbar.pageChooser.grid(column=16, row=0)
|
||||
|
||||
self.toolbar.grid(column=0, row=2, padx=0, pady=0)
|
||||
|
||||
# + image with scrollbars
|
||||
self.imageViewer.hbar = ttk.Scrollbar(self.imageViewer, orient='horizontal')
|
||||
self.imageViewer.vbar = ttk.Scrollbar(self.imageViewer, orient='vertical')
|
||||
self.imageViewer.hbar.grid(row=1, column=0, sticky="NSEW")
|
||||
self.imageViewer.vbar.grid(row=0, column=1, sticky="NSEW")
|
||||
|
||||
self.imageViewer.ZONE = ihm.ResizeableCanvas(self.imageViewer.frame, bg=self["background"], xscrollcommand=(self.imageViewer.hbar.set),
|
||||
yscrollcommand=(self.imageViewer.vbar.set))
|
||||
self.imageViewer.ZONE.grid(sticky="NSEW")
|
||||
|
||||
self.imageViewer.hbar.config(command=self.imageViewer.ZONE.xview)
|
||||
self.imageViewer.vbar.config(command=self.imageViewer.ZONE.yview)
|
||||
|
||||
self.STATUSimg = self.imageViewer.ZONE.create_image(0,0, image=None, anchor="nw")
|
||||
|
||||
|
||||
# The terminal to enter the MRZ
|
||||
self.terminal = ttk.Labelframe(self, text='Terminal de saisie de MRZ complète')
|
||||
@ -191,9 +289,9 @@ class mainWindow(Tk):
|
||||
self.speed731.grid_columnconfigure(9, weight=1)
|
||||
self.speed731.grid_rowconfigure(0, weight=1)
|
||||
self.speed731text = Entry(self.speed731, font='Terminal 14')
|
||||
self.speed731text.grid(column=0, row=0, sticky='NEW', padx=5)
|
||||
self.speed731text.grid(column=0, row=0, sticky='NEW', padx=5, pady=5)
|
||||
self.speedResult = Text((self.speed731), state='disabled', width=1, height=1, wrap='none', font='Terminal 14')
|
||||
self.speedResult.grid(column=2, row=0, sticky='NEW')
|
||||
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')
|
||||
@ -206,8 +304,8 @@ class mainWindow(Tk):
|
||||
self.monitor.grid_rowconfigure(0, weight=1)
|
||||
|
||||
# All the items griding
|
||||
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.lecteur_ci.grid(column=2, row=0, sticky='EWNS', columnspan=1, padx=5, pady=5)
|
||||
self.imageViewer.grid(column=0, row=0, sticky='EWNS', columnspan=2, padx=5, pady=5)
|
||||
self.terminal.grid(column=0, row=2, sticky='EWNS', columnspan=2, padx=5, pady=5)
|
||||
self.terminal2.grid(column=0, row=1, sticky='EWNS', columnspan=2, padx=5, pady=5)
|
||||
self.monitor.grid(column=2, row=1, sticky='EWNS', columnspan=1, rowspan=2, padx=5, pady=5)
|
||||
@ -222,6 +320,8 @@ class mainWindow(Tk):
|
||||
menubar.add_cascade(label='Fichier', menu=menu1)
|
||||
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_separator()
|
||||
menu3.add_command(label='A propos de CNIRevelator', command=(self.infobox))
|
||||
menubar.add_cascade(label='Aide', menu=menu3)
|
||||
self.config(menu=menubar)
|
||||
@ -249,35 +349,118 @@ class mainWindow(Tk):
|
||||
self.deiconify()
|
||||
self.minsize(self.winfo_width(), self.winfo_height())
|
||||
|
||||
# Load an image using OpenCV
|
||||
cv_img = cv2.imread("background.png")
|
||||
cv_img = cv2.cvtColor(cv_img, cv2.COLOR_BGR2GRAY)
|
||||
cv_img = cv2.blur(cv_img, (15, 15))
|
||||
# Get the image dimensions (OpenCV stores image data as NumPy ndarray)
|
||||
height, width = cv_img.shape
|
||||
# Get the image dimensions (OpenCV stores image data as NumPy ndarray)
|
||||
height, width = 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("EN ATTENTE", "#FFBF00", photo, setplace=True)
|
||||
|
||||
# Set image
|
||||
self.imageViewer.image = None
|
||||
self.imageViewer.imagePath = None
|
||||
self.imageViewer.imgZoom = 1
|
||||
self.imageViewer.rotateCount = 0
|
||||
self.imageViewer.blackhat = False
|
||||
self.imageViewer.pagenumber = 0
|
||||
|
||||
# Some bindings
|
||||
self.termtext.bind('<Key>', self.entryValidation)
|
||||
self.termtext.bind('<<Paste>>', self.pasteValidation)
|
||||
self.speed731text.bind('<Control_R>', self.speedValidation)
|
||||
self.imageViewer.ZONE.bind("<Button-1>", self.rectangleSelectScan)
|
||||
|
||||
logfile.printdbg('Initialization successful')
|
||||
|
||||
def statusUpdate(self, msg, color, image=None, setplace=False):
|
||||
def statusUpdate(self, image=None, setplace=False):
|
||||
if image:
|
||||
self.STATUT.image = 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"))
|
||||
|
||||
self.STATUT.ZONE.itemconfigure(self.STATUSimg, image=(self.STATUT.image))
|
||||
self.STATUT.ZONE.itemconfigure(self.STATUStxt, text=(msg), fill=color)
|
||||
def rectangleSelectScan(self, event):
|
||||
if self.imageViewer.image:
|
||||
canvas = event.widget
|
||||
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]))
|
||||
if len(self.corners) > 2:
|
||||
self.corners = []
|
||||
self.imageViewer.ZONE.delete(self.select)
|
||||
|
||||
def goOCRDetection(self):
|
||||
if self.imageViewer.image:
|
||||
cv_img = cv2.imreadmulti(self.imageViewer.imagePath)[1][self.imageViewer.pagenumber]
|
||||
cv_img = cv2.cvtColor(cv_img, cv2.COLOR_BGR2RGB)
|
||||
if self.imageViewer.blackhat:
|
||||
cv_img = cv2.cvtColor(cv_img, cv2.COLOR_BGR2GRAY)
|
||||
cv_img = cv2.GaussianBlur(cv_img, (3, 3), 0)
|
||||
cv_img = cv2.bitwise_not(cv_img)
|
||||
try:
|
||||
# Get the image dimensions (OpenCV stores image data as NumPy ndarray)
|
||||
height, width, channels_no = cv_img.shape
|
||||
# Get the image dimensions (OpenCV stores image data as NumPy ndarray)
|
||||
height, width, channels_no = cv_img.shape
|
||||
except ValueError:
|
||||
# Get the image dimensions (OpenCV stores image data as NumPy ndarray)
|
||||
height, width = cv_img.shape
|
||||
# Get the image dimensions (OpenCV stores image data as NumPy ndarray)
|
||||
height, width = cv_img.shape
|
||||
# Rotate
|
||||
rotationMatrix=cv2.getRotationMatrix2D((width/2, height/2),int(self.imageViewer.rotateCount*90),1)
|
||||
cv_img=cv2.warpAffine(cv_img,rotationMatrix,(width,height))
|
||||
# Resize
|
||||
dim = (int(width * (self.imageViewer.imgZoom + 100) / 100), int(height * (self.imageViewer.imgZoom + 100) / 100))
|
||||
cv_img = cv2.resize(cv_img, dim, interpolation = cv2.INTER_AREA)
|
||||
|
||||
x0 = int(self.corners[0][0])
|
||||
y0 = int(self.corners[0][1])
|
||||
x1 = int(self.corners[1][0])
|
||||
y1 = int(self.corners[1][1])
|
||||
|
||||
crop_img = cv_img[y0:y1, x0:x1]
|
||||
|
||||
# Get the text by OCR
|
||||
try:
|
||||
os.environ['PATH'] = globs.CNIRTesser
|
||||
os.environ['TESSDATA_PREFIX'] = globs.CNIRTesser + '\\tessdata'
|
||||
|
||||
text = pytesseract.image_to_string(crop_img, lang='ocrb', boxes=False, config='--psm 6 --oem 0 -c tessedit_char_whitelist=ABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890<')
|
||||
|
||||
# manual validation
|
||||
# the regex
|
||||
regex = re.compile("[^A-Z0-9<\n]")
|
||||
text = re.sub(regex, '', text)
|
||||
self.validatedtext = ''
|
||||
invite = ihm.OpenScanDialog(self, text)
|
||||
invite.transient(self)
|
||||
invite.grab_set()
|
||||
invite.focus_force()
|
||||
self.wait_window(invite)
|
||||
|
||||
print("text : {}".format(self.validatedtext))
|
||||
|
||||
self.mrzChar = ""
|
||||
|
||||
# Get that
|
||||
for char in self.validatedtext:
|
||||
self.termtext.delete("1.0","end")
|
||||
self.termtext.insert("1.0", self.mrzChar)
|
||||
self.mrzChar = self.mrzChar + char
|
||||
|
||||
self.stringValidation("")
|
||||
print(self.mrzChar)
|
||||
|
||||
# Reinstall tesseract
|
||||
except pytesseract.TesseractNotFoundError as e:
|
||||
try:
|
||||
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))
|
||||
|
||||
# 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)
|
||||
|
||||
if setplace:
|
||||
self.STATUT.ZONE.move(self.STATUSimg, self.STATUT.ZONE.winfo_reqwidth() / 2, self.STATUT.ZONE.winfo_reqheight() / 2)
|
||||
self.STATUT.ZONE.move(self.STATUStxt, self.STATUT.ZONE.winfo_reqwidth() / 2, self.STATUT.ZONE.winfo_reqheight() / 2)
|
||||
|
||||
def stringValidation(self, keysym):
|
||||
# analysis
|
||||
@ -427,9 +610,11 @@ class mainWindow(Tk):
|
||||
|
||||
# Get that
|
||||
for char in lines:
|
||||
self.termtext.delete("1.0","end")
|
||||
self.termtext.insert("1.0", self.mrzChar)
|
||||
self.mrzChar = self.mrzChar + char
|
||||
self.stringValidation("")
|
||||
self.termtext.insert("1.0", self.mrzChar)
|
||||
|
||||
return "break"
|
||||
|
||||
@ -459,6 +644,9 @@ class mainWindow(Tk):
|
||||
self.speedResult.insert('end', text)
|
||||
self.speedResult['state'] = 'disabled'
|
||||
|
||||
def goPageChoice(self, event):
|
||||
self.imageViewer.pagenumber = int(self.toolbar.pageChooser.get()) - 1
|
||||
self.resizeScan()
|
||||
|
||||
def openingScan(self):
|
||||
path = ''
|
||||
@ -466,8 +654,165 @@ class mainWindow(Tk):
|
||||
('TIF files', '*.tiff'),
|
||||
('JPEG files', '*.jpg'),
|
||||
('JPEG files', '*.jpeg')))
|
||||
self.mrzdetected = ''
|
||||
self.mrzdict = {}
|
||||
# Load an image using OpenCV
|
||||
self.imageViewer.imagePath = path
|
||||
self.imageViewer.imgZoom = 1
|
||||
self.imageViewer.blackhat = False
|
||||
self.imageViewer.rotateCount = 0
|
||||
self.imageViewer.pagenumber = 0
|
||||
|
||||
# Determine how many pages
|
||||
self.toolbar.pageChooser['values'] = ('1')
|
||||
total = len(cv2.imreadmulti(self.imageViewer.imagePath)[1])
|
||||
|
||||
for i in range(2, total + 1):
|
||||
self.toolbar.pageChooser['values'] += tuple(str(i))
|
||||
|
||||
# Open the first page
|
||||
cv_img = cv2.imreadmulti(self.imageViewer.imagePath)[1][self.imageViewer.pagenumber]
|
||||
cv_img = cv2.cvtColor(cv_img, cv2.COLOR_BGR2RGB)
|
||||
|
||||
try:
|
||||
# Get the image dimensions (OpenCV stores image data as NumPy ndarray)
|
||||
height, width, channels_no = cv_img.shape
|
||||
# Get the image dimensions (OpenCV stores image data as NumPy ndarray)
|
||||
height, width, channels_no = cv_img.shape
|
||||
except ValueError:
|
||||
# Get the image dimensions (OpenCV stores image data as NumPy ndarray)
|
||||
height, width = cv_img.shape
|
||||
# Get the image dimensions (OpenCV stores image data as NumPy ndarray)
|
||||
height, width = 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)
|
||||
|
||||
def zoomInScan50(self, quantity = 50):
|
||||
if self.imageViewer.image:
|
||||
self.imageViewer.imgZoom += quantity
|
||||
self.resizeScan()
|
||||
|
||||
def zoomOutScan50(self, quantity = 50):
|
||||
if self.imageViewer.image:
|
||||
self.imageViewer.imgZoom -= quantity
|
||||
self.resizeScan()
|
||||
|
||||
def zoomInScan20(self, quantity = 20):
|
||||
if self.imageViewer.image:
|
||||
self.imageViewer.imgZoom += quantity
|
||||
self.resizeScan()
|
||||
|
||||
def zoomOutScan20(self, quantity = 20):
|
||||
if self.imageViewer.image:
|
||||
self.imageViewer.imgZoom -= quantity
|
||||
self.resizeScan()
|
||||
|
||||
def zoomInScan(self, quantity = 1):
|
||||
if self.imageViewer.image:
|
||||
self.imageViewer.imgZoom += quantity
|
||||
self.resizeScan()
|
||||
|
||||
def zoomOutScan(self, quantity = 1):
|
||||
if self.imageViewer.image:
|
||||
self.imageViewer.imgZoom -= quantity
|
||||
self.resizeScan()
|
||||
|
||||
def rotateRight(self):
|
||||
if self.imageViewer.image:
|
||||
self.imageViewer.rotateCount -= 1
|
||||
if self.imageViewer.rotateCount < 0:
|
||||
self.imageViewer.rotateCount = 4
|
||||
self.resizeScan()
|
||||
|
||||
def rotateLeft(self):
|
||||
if self.imageViewer.image:
|
||||
self.imageViewer.rotateCount += 1
|
||||
if self.imageViewer.rotateCount > 4:
|
||||
self.imageViewer.rotateCount = 0
|
||||
self.resizeScan()
|
||||
|
||||
def rotateLeft1(self):
|
||||
if self.imageViewer.image:
|
||||
self.imageViewer.rotateCount += 0.01
|
||||
if self.imageViewer.rotateCount > 4:
|
||||
self.imageViewer.rotateCount = 0
|
||||
self.resizeScan()
|
||||
|
||||
def rotateRight1(self):
|
||||
if self.imageViewer.image:
|
||||
self.imageViewer.rotateCount -= 0.01
|
||||
if self.imageViewer.rotateCount < 0:
|
||||
self.imageViewer.rotateCount = 4
|
||||
self.resizeScan()
|
||||
|
||||
def negativeScan(self):
|
||||
if self.imageViewer.image:
|
||||
# Load an image using OpenCV
|
||||
cv_img = cv2.imreadmulti(self.imageViewer.imagePath)[1][self.imageViewer.pagenumber]
|
||||
cv_img = cv2.cvtColor(cv_img, cv2.COLOR_BGR2RGB)
|
||||
if not self.imageViewer.blackhat:
|
||||
self.imageViewer.blackhat = True
|
||||
cv_img = cv2.cvtColor(cv_img, cv2.COLOR_BGR2GRAY)
|
||||
cv_img = cv2.GaussianBlur(cv_img, (3, 3), 0)
|
||||
cv_img = cv2.bitwise_not(cv_img)
|
||||
else:
|
||||
self.imageViewer.blackhat = False
|
||||
self.resizeScan(cv_img)
|
||||
|
||||
def resizeScan(self, cv_img = None):
|
||||
if self.imageViewer.image:
|
||||
try:
|
||||
if not hasattr(cv_img, 'shape'):
|
||||
# Load an image using OpenCV
|
||||
cv_img = cv2.imreadmulti(self.imageViewer.imagePath)[1][self.imageViewer.pagenumber]
|
||||
cv_img = cv2.cvtColor(cv_img, cv2.COLOR_BGR2RGB)
|
||||
if self.imageViewer.blackhat:
|
||||
cv_img = cv2.cvtColor(cv_img, cv2.COLOR_BGR2GRAY)
|
||||
cv_img = cv2.GaussianBlur(cv_img, (3, 3), 0)
|
||||
cv_img = cv2.bitwise_not(cv_img)
|
||||
|
||||
try:
|
||||
# Get the image dimensions (OpenCV stores image data as NumPy ndarray)
|
||||
height, width, channels_no = cv_img.shape
|
||||
# Get the image dimensions (OpenCV stores image data as NumPy ndarray)
|
||||
height, width, channels_no = cv_img.shape
|
||||
except ValueError:
|
||||
# Get the image dimensions (OpenCV stores image data as NumPy ndarray)
|
||||
height, width = cv_img.shape
|
||||
# Get the image dimensions (OpenCV stores image data as NumPy ndarray)
|
||||
height, width = cv_img.shape
|
||||
# Rotate
|
||||
rotationMatrix=cv2.getRotationMatrix2D((width/2, height/2),int(self.imageViewer.rotateCount*90),1)
|
||||
cv_img=cv2.warpAffine(cv_img,rotationMatrix,(width,height))
|
||||
# Resize
|
||||
dim = (int(width * (self.imageViewer.imgZoom + 100) / 100), int(height * (self.imageViewer.imgZoom + 100) / 100))
|
||||
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)
|
||||
except Exception as e:
|
||||
logfile.printerr("Error with opencv : {}".format(e))
|
||||
traceback.print_exc(file=sys.stdout)
|
||||
try:
|
||||
# Reload an image using OpenCV
|
||||
path = self.imageViewer.imagePath
|
||||
self.imageViewer.imgZoom = 1
|
||||
self.imageViewer.blackhat = False
|
||||
self.imageViewer.rotateCount = 0
|
||||
cv_img = cv2.imreadmulti(path)
|
||||
cv_img = cv2.cvtColor(cv_img, cv2.COLOR_BGR2RGB)
|
||||
# Get the image dimensions (OpenCV stores image data as NumPy ndarray)
|
||||
height, width, channels_no = cv_img.shape
|
||||
# Get the image dimensions (OpenCV stores image data as NumPy ndarray)
|
||||
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)
|
||||
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")
|
||||
self.initialize()
|
||||
|
||||
def newEntry(self):
|
||||
self.initialize()
|
||||
@ -477,25 +822,27 @@ class mainWindow(Tk):
|
||||
Tk().withdraw()
|
||||
|
||||
showinfo('A propos de CNIRevelator',
|
||||
( 'Version du logiciel : CNIRevelator ' + globs.verstring_full + '\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" +
|
||||
" En cas de problèmes ou demande particulière, ouvrez-y une issue ou bien envoyez un mail à neox@os-k.eu !"
|
||||
( '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"
|
||||
),
|
||||
|
||||
parent=self)
|
||||
@ -521,6 +868,12 @@ class mainWindow(Tk):
|
||||
|
||||
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
|
||||
@ -580,9 +933,11 @@ class mainWindow(Tk):
|
||||
self.compliance = False
|
||||
|
||||
if self.compliance == True:
|
||||
self.statusUpdate("CONFORME", "chartreuse2")
|
||||
self.STATUStxt["text"] = "CONFORME"
|
||||
self.STATUStxt["foreground"] = "green"
|
||||
else:
|
||||
self.statusUpdate("NON-CONFORME","red")
|
||||
self.STATUStxt["text"] = "NON CONFORME"
|
||||
self.STATUStxt["foreground"] = "red"
|
||||
|
||||
return
|
||||
|
||||
|
48
src/mrz.py
@ -640,27 +640,26 @@ AC = [
|
||||
"Certificat de membre d'équipage"
|
||||
]
|
||||
|
||||
## XXXXXXXXXXX
|
||||
# VB = [
|
||||
# ["11222333333333333333333333333333333333333333", "444444444566677777789AAAAAABCCCCCCCCCCCCCCCDE"],
|
||||
# {
|
||||
# "1": ["2", "CODE", "V."],
|
||||
# "2": ["3", "PAYS", "[A-Z]+"],
|
||||
# "3": ["39", "NOM", "[A-Z]+"],
|
||||
# "4": ["9", "NO", ".+"],
|
||||
# "5": ["1", "CTRL", "[0-9]","4"],
|
||||
# "6": ["3", "NAT", "[A-Z]+"],
|
||||
# "7": ["6", "BDATE", "[0-9]+"],
|
||||
# "8": ["1", "CTRL", "[0-9]", "7"],
|
||||
# "9": ["1", "SEX", "[A-Z]"],
|
||||
# "A": ["6", "EDATE", "[0-9]+"],
|
||||
# "B": ["1", "CTRL", "[0-9]", "A"],
|
||||
# "C": ["14", "FACULT", ".+"]
|
||||
# },
|
||||
# "Visa de type B"
|
||||
# ]
|
||||
|
||||
VA = [
|
||||
["11222333333333333333333333333333333333333333", "444444444566677777789AAAAAABCCCCCCCCCCCCCCCCC"],
|
||||
{
|
||||
"1": ["2", "CODE", "V."],
|
||||
"2": ["3", "PAYS", "[A-Z]+"],
|
||||
"3": ["39", "NOM", "[A-Z]+"],
|
||||
"4": ["9", "NO", ".+"],
|
||||
"5": ["1", "CTRL", "[0-9]","4"],
|
||||
"6": ["3", "NAT", "[A-Z]+"],
|
||||
"7": ["6", "BDATE", "[0-9]+"],
|
||||
"8": ["1", "CTRL", "[0-9]", "7"],
|
||||
"9": ["1", "SEX", "[A-Z]"],
|
||||
"A": ["6", "EDATE", "[0-9]+"],
|
||||
"B": ["1", "CTRL", "[0-9]", "A"],
|
||||
"C": ["16", "FACULT", ".+"]
|
||||
},
|
||||
"Visa de type A"
|
||||
]
|
||||
|
||||
VB = [
|
||||
["112223333333333333333333333333333333", "444444444566677777789AAAAAABCCCCCC"],
|
||||
{
|
||||
"1": ["2", "CODE", "V."],
|
||||
@ -676,14 +675,14 @@ VA = [
|
||||
"B": ["1", "CTRL", "[0-9]", "A"],
|
||||
"C": ["8", "FACULT", ".+"]
|
||||
},
|
||||
"Visa de type A"
|
||||
"Visa de type B"
|
||||
]
|
||||
|
||||
TSF = [
|
||||
["112223333333333333333333333333333333", "444444444566677777789AAAAAABCCCCCC"],
|
||||
{
|
||||
"1": ["2", "CODE", "TS"],
|
||||
"2": ["3", "PAYS", "[A-Z]+"],
|
||||
"2": ["3", "PAYS", "FRA"],
|
||||
"3": ["31", "NOM", "([A-Z]|<)+"],
|
||||
"4": ["9", "NO", ".+"],
|
||||
"5": ["1", "CTRL", "[0-9]","4"],
|
||||
@ -695,7 +694,7 @@ TSF = [
|
||||
"B": ["1", "CTRL", "[0-9]", "A"],
|
||||
"C": ["8", "FACULT", ".+"]
|
||||
},
|
||||
"Titre de séjour"
|
||||
"Carte de séjour"
|
||||
]
|
||||
|
||||
I__ = [
|
||||
@ -752,8 +751,7 @@ DL = [
|
||||
"Permis de conduire"
|
||||
]
|
||||
|
||||
#TYPES = [ID, I__, VB, VA, AC, I_, IP, P, DL]
|
||||
TYPES = [IDFR, I__, VA, AC, I_, IP, P, DL, TSF]
|
||||
TYPES = [IDFR, I__, VB, VA, AC, I_, IP, P, DL, TSF]
|
||||
|
||||
# longest document MRZ line
|
||||
longest = max([len(x[0][0]) for x in TYPES])
|
||||
|
BIN
src/rotateLeft.png
Normal file
After Width: | Height: | Size: 750 B |
BIN
src/rotateLeft1.png
Normal file
After Width: | Height: | Size: 450 B |
BIN
src/rotateRight.png
Normal file
After Width: | Height: | Size: 738 B |
BIN
src/rotateRight1.png
Normal file
After Width: | Height: | Size: 428 B |
@ -56,7 +56,7 @@ def createShortcut(path, target='', wDir='', icon=''):
|
||||
shortcut.close()
|
||||
else:
|
||||
shell = Dispatch('WScript.Shell')
|
||||
shortcut = shell.CreateShortCut(path)
|
||||
shortcut = shell.CreateShortCut(shell.SpecialFolders("Desktop") + r"\{}".format(path))
|
||||
shortcut.Targetpath = target
|
||||
shortcut.WorkingDirectory = wDir
|
||||
if icon == '':
|
||||
@ -192,7 +192,6 @@ def getLatestVersion(credentials):
|
||||
return (finalver, finalurl, finalchecksum)
|
||||
|
||||
|
||||
# XXX Warning : when tesseracturl is not found, it seems to hang and freeze
|
||||
def tessInstall(PATH, credentials):
|
||||
# Global Handlers
|
||||
logfile = logger.logCur
|
||||
@ -207,18 +206,43 @@ def tessInstall(PATH, credentials):
|
||||
logfile.printdbg('Preparing download of Tesseract OCR 4...')
|
||||
getTesseract = downloader.newdownload(credentials, tesseracturl, PATH + '\\downloads\\TsrtPackage.zip', "Tesseract 4 OCR Module").download()
|
||||
|
||||
try:
|
||||
# CHECKSUM
|
||||
BUF_SIZE = 65536 # lets read stuff in 64kb chunks!
|
||||
|
||||
sha1 = hashlib.sha1()
|
||||
|
||||
with open(globs.CNIRFolder + '\\downloads\\TsrtPackage.zip', 'rb') as f:
|
||||
while True:
|
||||
data = f.read(BUF_SIZE)
|
||||
if not data:
|
||||
break
|
||||
sha1.update(data)
|
||||
|
||||
check = sha1.hexdigest()
|
||||
logfile.printdbg("SHA1: {0}".format(check))
|
||||
|
||||
if not check == globs.CNIRTesserHash:
|
||||
logfile.printerr("Checksum error")
|
||||
return False
|
||||
|
||||
# Unzip Tesseract
|
||||
logfile.printdbg("Unzipping the package")
|
||||
launcherWindow.printmsg('Installing the updates')
|
||||
zip_ref = zipfile.ZipFile(PATH + '\\downloads\\TsrtPackage.zip', 'r')
|
||||
zip_ref.extractall(PATH)
|
||||
zip_ref.close()
|
||||
|
||||
# Cleanup
|
||||
try:
|
||||
os.remove(UPATH + '\\downloads\\TsrtPackage.zip')
|
||||
except:
|
||||
pass
|
||||
return True
|
||||
|
||||
except:
|
||||
return False
|
||||
else:
|
||||
return True
|
||||
|
||||
## Main Batch Function
|
||||
def batch(credentials):
|
||||
@ -284,6 +308,9 @@ def batch(credentials):
|
||||
shutil.rmtree(UPATH + 'temp')
|
||||
logfile.printdbg('Extracted :' + UPATH + '\\CNIRevelator.exe')
|
||||
|
||||
# Make a shortcut
|
||||
createShortcut("CNIRevelator.lnk", UPATH + '\\CNIRevelator.exe', UPATH)
|
||||
|
||||
launcherWindow.printmsg('Success !')
|
||||
|
||||
# Cleanup
|
||||
@ -366,8 +393,6 @@ def umain():
|
||||
logfile.printerr(str(e))
|
||||
launcherWindow.printmsg('Fail :{}'.format(e))
|
||||
launcherWindow.printmsg('Starting...')
|
||||
else:
|
||||
tessInstall(globs.CNIRFolder, credentials)
|
||||
|
||||
try:
|
||||
try:
|
||||
@ -390,11 +415,42 @@ def umain():
|
||||
launcherWindow.exit()
|
||||
return 0
|
||||
|
||||
if UPDATE_IS_MADE:
|
||||
launcherWindow.exit()
|
||||
return 0
|
||||
except:
|
||||
logfile.printerr("A FATAL ERROR OCCURED : " + str(traceback.format_exc()))
|
||||
launcherWindow.exit()
|
||||
sys.exit(2)
|
||||
return 2
|
||||
|
||||
try:
|
||||
try:
|
||||
# INSTALLING TESSERACT OCR
|
||||
success = tessInstall(globs.CNIRFolder, credentials)
|
||||
except Exception as e:
|
||||
logfile.printerr("An error occured on the thread : " + str(traceback.format_exc()))
|
||||
launcherWindow.printmsg('ERROR : ' + str(e))
|
||||
time.sleep(3)
|
||||
launcherWindow.exit()
|
||||
return 1
|
||||
|
||||
if success:
|
||||
logfile.printdbg("Software is up-to-date !")
|
||||
launcherWindow.printmsg('Software is up-to-date !')
|
||||
else:
|
||||
logfile.printerr("An error occured. No effective update !")
|
||||
launcherWindow.printmsg('An error occured. No effective update !')
|
||||
time.sleep(2)
|
||||
launcherWindow.exit()
|
||||
return 0
|
||||
|
||||
except:
|
||||
logfile.printerr("A FATAL ERROR OCCURED : " + str(traceback.format_exc()))
|
||||
launcherWindow.exit()
|
||||
sys.exit(2)
|
||||
return 2
|
||||
|
||||
return
|
||||
|
||||
time.sleep(2)
|
||||
launcherWindow.exit()
|
||||
return 0
|
||||
|
BIN
src/zoomIn.png
Normal file
After Width: | Height: | Size: 772 B |
BIN
src/zoomIn20.png
Normal file
After Width: | Height: | Size: 1.2 KiB |
BIN
src/zoomIn50.png
Normal file
After Width: | Height: | Size: 1.2 KiB |
BIN
src/zoomOut.png
Normal file
After Width: | Height: | Size: 735 B |
BIN
src/zoomOut20.png
Normal file
After Width: | Height: | Size: 1013 B |
BIN
src/zoomOut50.png
Normal file
After Width: | Height: | Size: 1.1 KiB |