diff --git a/CNIRevelator Documentation.docx b/CNIRevelator Documentation.docx index 5ee8079..d361ab2 100644 Binary files a/CNIRevelator Documentation.docx and b/CNIRevelator Documentation.docx differ diff --git a/VERSIONS.LST b/VERSIONS.LST index 2f449bd..5a70410 100644 --- a/VERSIONS.LST +++ b/VERSIONS.LST @@ -1,2 +1,2 @@ -# ver|url|checksum, and | as separator, one version per || -3.1.2|https://github.com/neox95/CNIRevelator/releases/download/3.1.2d/CNIRevelator.zip|8ed839f59ac63994fab1a5ceefbe183f04e89162|| +# ver|url|checksum, and | as separator, one version per || +3.1.3|https://github.com/neox95/CNIRevelator/releases/download/3.1.3e/CNIRevelator.zip|f42bb2cc8e72aa21caae4ea058ca1603e4153f48|| diff --git a/make.bat b/make.bat index 5d6414b..2f31cc6 100644 --- a/make.bat +++ b/make.bat @@ -4,9 +4,9 @@ title Compilation de CNIRevelator -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 - +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 "src\id-card.ico";"id-card.ico" -i "src\id-card.ico" --version-file "src\version.res" -n CNIRevelator src\CNIRevelator.py +rem call pyi-set_version "src\version.res" "dist\CNIRevelator\CNIRevelator.exe" copy LICENSE dist\CNIRevelator\LICENSE copy src\id-card.ico dist\CNIRevelator\id-card.ico diff --git a/src/critical.py b/src/critical.py index 3e6fb08..d04f643 100644 --- a/src/critical.py +++ b/src/critical.py @@ -31,9 +31,10 @@ import traceback import psutil import os -import lang # lang.py -import logger # logger.py -import globs # globs.py +import lang # lang.py +import logger # logger.py +import globs # globs.py +import github # github.py def crashCNIR(shutdown=True): """ @@ -45,13 +46,29 @@ def crashCNIR(shutdown=True): root.withdraw() logfile = logger.logCur logfile.printerr("FATAL ERROR : see traceback below.\n{}".format(traceback.format_exc())) + showerror(lang.all[globs.CNIRlang]["CNIRevelator Fatal Eror"], lang.all[globs.CNIRlang]["CNIRevelator crashed because a fatal error occured. View log for more infos and please open an issue on Github"]) - res = askquestion(lang.all[globs.CNIRlang]["CNIRevelator Fatal Eror"], lang.all[globs.CNIRlang]["Would you like to open the log file ?"]) + + res = askquestion(lang.all[globs.CNIRlang]["CNIRevelator Fatal Eror"], lang.all[globs.CNIRlang]["Would you like to report this bug ?"]) if res == "yes": - webbrowser.open_new(globs.CNIRErrLog) - res = askquestion(lang.all[globs.CNIRlang]["CNIRevelator Fatal Eror"], lang.all[globs.CNIRlang]["Would you like to open an issue on Github to report this bug ?"]) - if res == "yes": - webbrowser.open_new("https://github.com/neox95/CNIRevelator/issues") + # read the log + data = "No log." + try: + with open(globs.CNIRMainLog, 'r') as file: + data = file.read() + except: + pass + + # send it + success = github.reportBug(traceback.format_exc(), data) + + if not success: + res = askquestion(lang.all[globs.CNIRlang]["CNIRevelator Fatal Eror"], lang.all[globs.CNIRlang]["Would you like to open the log file ?"]) + if res == "yes": + webbrowser.open_new(globs.CNIRErrLog) + else: + showinfo(lang.all[globs.CNIRlang]["CNIRevelator Fatal Eror"], lang.all[globs.CNIRlang]["Bug reported successfully. Thanks."]) + root.destroy() # Quit ? diff --git a/src/github.py b/src/github.py new file mode 100644 index 0000000..47c4730 --- /dev/null +++ b/src/github.py @@ -0,0 +1,49 @@ +# -*- coding: utf8 -*- +""" +******************************************************************************** +* CNIRevelator * +* * +* Desc: Github Stuff for CNIRevelator * +* * +* Copyright © 2018-2019 Adrien Bourmault (neox95) * +* * +* This file is part of CNIRevelator. * +* * +* CNIRevelator is free software: you can redistribute it and/or modify * +* it under the terms of the GNU General Public License as published by * +* the Free Software Foundation, either version 3 of the License, or * +* any later version. * +* * +* CNIRevelator is distributed in the hope that it will be useful, * +* but WITHOUT ANY WARRANTY*without even the implied warranty of * +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * +* GNU General Public License for more details. * +* * +* You should have received a copy of the GNU General Public License * +* along with CNIRevelator. If not, see . * +******************************************************************************** +""" +from requests.auth import HTTPProxyAuth +from pypac import PACSession +from requests import Session +import json + +credentials = False + +def reportBug(reason="",log=""): + + if not credentials: + return False + + session = credentials.sessionHandler + + payload = {'title':"CNIRevelator Bug Report", 'body':"**An error has been reported by a CNIRevelator instance.**\n\n**Here is the full reason of this issue:**\n{}\n\n**The full log is here:** {}".format(reason, log), "assignees":["neox95"], "labels":["bug", "AUTO"]} + + handler = session.post('https://api.github.com/repos/neox95/cnirevelator/issues', headers={'Authorization': 'token %s' % "1a3c589eafc2b6557a1da852a3b2cc279bd5bf33"}, data=json.dumps(payload)) + + if handler.reason == "Created": + return True + else: + return False + + diff --git a/src/globs.py b/src/globs.py index a0e031f..742343e 100644 --- a/src/globs.py +++ b/src/globs.py @@ -27,7 +27,7 @@ import os # CNIRevelator version verType = "final release" -version = [3, 1, 2] +version = [3, 1, 3] verstring_full = "{}.{}.{} {}".format(version[0], version[1], version[2], verType) verstring = "{}.{}".format(version[0], version[1]) diff --git a/src/ihm.py b/src/ihm.py index 672233f..ca5e68a 100644 --- a/src/ihm.py +++ b/src/ihm.py @@ -296,8 +296,6 @@ class LauncherWindow(Tk): # if getattr(sys, 'frozen', False): # cv_img = cv2.imread(sys._MEIPASS + r"\background.png\background.png") # else: - cv_img = cv2.imread("background.png") - cv_img = cv2.imread("background.png") cv_img = cv2.cvtColor(cv_img, cv2.COLOR_BGR2RGB) cv_img = cv2.blur(cv_img, (15, 15)) diff --git a/src/lang.py b/src/lang.py index 6706883..66505a7 100644 --- a/src/lang.py +++ b/src/lang.py @@ -51,11 +51,13 @@ french = \ "CNIRevelator crashed because a " "fatal error occured. View log for " "more infos and please open " -"an issue on Github" : "CNIRevelator s'est arrêté car une erreur fatale s'est produite. Consultez le journal pour plus d'informations et ouvrez s'il vous plaît un ticket sur Github.", +"an issue on Github" : "CNIRevelator s'est arrêté car une erreur fatale s'est produite. Consultez le journal pour plus d'informations et signalez le bogue.", "Would you like to open the " -"log file ?" : "Souhaitez-vous ouvrir le fichier de log ?", -"Would you like to open an issue " -"on Github to report this bug ?" : "Souhaitez-vous ouvrir un ticket sur Github pour signaler ce bogue?", +"log file ?" : "Le signalement a échoué. Souhaitez-vous ouvrir le fichier de log ?", +"Bug reported successfully. " +"Thanks." : "Bogue signalé avec succès, merci.", +"Would you like to report this " +"bug ?" : "Souhaitez-vous signaler ce bogue?", "Starting..." : "Lancement...", "Informations about the current " "document" : "Informations sur la pièce d'identité", @@ -139,7 +141,8 @@ french = \ "Coller :\t\t\t\tCtrl-V \n" "Forcer une nouvelle détection du document :\tEchap\n", -"CHANGELOG" : "Version 3.1.2 \nMise-à-jour mineure avec les progressions suivantes :\n- Montée de version de Tesseract OCR : 5.0\n- Correction de noms des documents\n- Résolution d'un problème avec le système de mise-à-jour\n- Amélioration des effets sur images\n\n" + \ +"CHANGELOG" : "Version 3.1.3 \nMise-à-jour mineure avec les progressions suivantes :\n- Correction d'un bug de la détection automatique de documents\n- Ajout d'une fonctionnalité de rapport d'erreur\n\n" + \ +"Version 3.1.2 \nMise-à-jour mineure avec les progressions suivantes :\n- Montée de version de Tesseract OCR : 5.0\n- Correction de noms des documents\n- Résolution d'un problème avec le système de mise-à-jour\n- Amélioration des effets sur images\n\n" + \ "Version 3.1.1 \nMise-à-jour mineure avec les progressions suivantes :\n- Correction d'un bug sévère du système de mise à jour\n\n" + \ "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\n- Rationalisation du système de langues\n- Ajout des canaux de mise-à-jour\n\n" + \ "Version 3.0.8 finale\nCorrectif : bug du système de mise-à-jour'\n\n" + \ @@ -751,11 +754,13 @@ english = \ "CNIRevelator crashed because a " "fatal error occured. View log for " "more infos and please open " -"an issue on Github" : "CNIRevelator crashed because a fatal error occured. View log for more infos and please open an issue on Github", -"Would you like to open an issue " -"on Github to report this bug ?" : "Would you like to open an issue on Github to report this bug ?", +"an issue on Github" : "CNIRevelator crashed because a fatal error occured. View log for more infos and please report this bug.", +"Would you like to report this " +"bug ?" : "Would you like to report this bug ?", "Would you like to open the " -"log file ?" : "Would you like to open the log file ?", +"log file ?" : "Reporting the bug has failed. Would you like to open the log file ?", +"Bug reported successfully. " +"Thanks." : "Bug reported successfully. Thanks.", "Starting..." : "Starting...", "Informations about the current " "document" : "Informations about the current document", @@ -841,7 +846,8 @@ english = \ "Paste:\t\t\t\tCtrl-V\n" "Force a new document detection:\tEchap\n", -"CHANGELOG" : "Version 3.1.2 \nMinor update with the following progressions: \n- Tesseract OCR version upgrade : 5.0\n- Correction of document names\n- Fixed a problem with the update system\n- Some enhancements about effects on images\n\n" + \ +"CHANGELOG" : "Version 3.1.3 \nMinor update with the following progressions:\n- Correction of a bug affecting automated document detection\n- Added bug reporting functionnality\n\n" + \ +"Version 3.1.2 \nMinor update with the following progressions: \n- Tesseract OCR version upgrade : 5.0\n- Correction of document names\n- Fixed a problem with the update system\n- Some enhancements about effects on images\n\n" + \ "Version 3.1.1 \nMinor update with the following progressions: \n- Fixed a severe bug in the update system\n\n" + \ "Version 3.1.0 \nMajor update with the following progressions: \n- Cosmetic modifications of the user interface \n- Stabilization of the changes made on the minor version 3.0 : user interface, OCR, VISA A and B, logging\n- Rationalization of the language system\n- Added update channels\n\n" + \ "Version 3.0.8 final\nCorrection: bug in the update system'\n\n" + \ diff --git a/src/main.py b/src/main.py index cd4ea93..0274f76 100644 --- a/src/main.py +++ b/src/main.py @@ -311,9 +311,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, pady=5) + self.speed731text.grid(column=0, row=0, columnspan=7, 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', padx=5, pady=5) + self.speedResult.grid(column=7, row=0, sticky='NEW', padx=5, pady=5) # The monitor that indicates some useful infos self.monitor = ttk.Labelframe(self, text=lang.all[globs.CNIRlang]["Monitor"]) @@ -384,7 +384,7 @@ class mainWindow(Tk): self.imageViewer.pagenumber = 0 # Some bindings - self.termtext.bind('', self.entryValidation) + self.bind('', self.entryValidation) self.termtext.bind('<>', self.pasteValidation) self.speed731text.bind('', self.speedValidation) self.imageViewer.ZONE.bind("", self.rectangleSelectScan) @@ -478,7 +478,7 @@ class mainWindow(Tk): self.termtext.insert("1.0", self.mrzChar) self.mrzChar = self.mrzChar + char - self.stringValidation("") + self.stringValidation(isFull=True) #print(self.mrzChar) # Reinstall tesseract @@ -497,7 +497,7 @@ class mainWindow(Tk): ## Regex and document detection + control related functions - def stringValidation(self, keysym): + def stringValidation(self, keysym="", isFull=False): """ Analysis of the already typed document """ @@ -505,7 +505,7 @@ class mainWindow(Tk): # If we must decide the type of the document if not self.mrzDecided: # Get the candidates - candidates = mrz.allDocMatch(self.mrzChar.split("\n")) + candidates = mrz.allDocMatch(self.mrzChar.split("\n"), final=isFull) if len(candidates) == 2 and len(self.mrzChar) >= 8: # Parameters for the choice invite @@ -545,10 +545,13 @@ class mainWindow(Tk): self.termtext.insert("1.0", self.mrzChar) # stop when limit reached elif (len(self.mrzChar) - 3 >= 2 * len(self.mrzDecided[0][0])): - self.mrzChar = self.termtext.get("1.0", "end")[:-1] - self.termtext.delete("1.0","end") - self.termtext.insert("1.0", self.mrzChar[:-1]) - self.termtext.mark_set(INSERT, curPos) + i = len(self.mrzChar) - 3 + while i >= 2 * len(self.mrzDecided[0][0]): + i-=1 + self.mrzChar = self.termtext.get("1.0", "end")[:-1] + self.termtext.delete("1.0","end") + self.termtext.insert("1.0", self.mrzChar[:-1]) + self.termtext.mark_set(INSERT, curPos) # compute the control sum if needed self.computeSigma() @@ -720,9 +723,14 @@ class mainWindow(Tk): if key in ["CODE", "CTRL", "CTRLF"]: continue if not docInfos[key] == False: - self.infoList[key]['text'] = docInfos[key] - self.infoList[key]['background'] = self['background'] - self.infoList[key]['foreground'] = "black" + if not docInfos[key] == "": + self.infoList[key]['text'] = docInfos[key] + self.infoList[key]['background'] = self['background'] + self.infoList[key]['foreground'] = "black" + else: + self.infoList[key]['text'] = lang.all[globs.CNIRlang]["Unknown"] + self.infoList[key]['background'] = self['background'] + self.infoList[key]['foreground'] = "black" else: self.infoList[key]['background'] = "red" self.infoList[key]['foreground'] = "white" @@ -789,6 +797,7 @@ class mainWindow(Tk): """ Open the scan, ask its path and displays it """ + self.initialize() path = '' path = filedialog.askopenfilename(parent=self, title=lang.all[globs.CNIRlang]["Open a scan of document..."], filetypes=(('TIF files', '*.tif'), ('TIF files', '*.tiff'), @@ -806,7 +815,7 @@ class mainWindow(Tk): and path[-4:] != 'jpeg' and path[-4:] != 'tiff' ) or not os.path.isfile(path): showerror(lang.all[globs.CNIRlang]["Open a scan of document..."], lang.all[globs.CNIRlang]["The file you provided is not valid : {}"].format(path)) - return + return # Load an image using OpenCV self.imageViewer.imagePath = path diff --git a/src/mrz.py b/src/mrz.py index 190b5b4..a2013d4 100644 --- a/src/mrz.py +++ b/src/mrz.py @@ -151,7 +151,7 @@ VA = [ { "1": ["2", "CODE", "V."], "2": ["3", "PAYS", "[A-Z]+"], - "3": ["39", "NOM", "[A-Z]+"], + "3": ["39", "NOM", "([A-Z]|<)+"], "4": ["9", "NO", ".+"], "5": ["1", "CTRL", "[0-9]","4"], "6": ["3", "NAT", "[A-Z]+"], @@ -342,7 +342,7 @@ def docMatch(doc, strs): # logfile.printdbg(" REGEX : {}, match : {}".format(regex, matching)) # exit the loop - #logfile.printdbg("{} level : {}/{} (+{})".format(doc[2], level, nchar, bonus)) + logfile.printdbg("{} level : {}/{} (+{})".format(doc[2], level, nchar, bonus)) return (level, nchar, bonus) def allDocMatch(strs, final=False): @@ -368,14 +368,25 @@ def allDocMatch(strs, final=False): candidate = SCORES.index(max(SCORES)) candidates = [] canditxt = [] + # Search the candidates for i in range(len(SCORES)): if SCORES[i] == SCORES[candidate]: candidates += [TYPES[i]] canditxt += [TYPES[i][2]] + # Continue searching + if len(candidates) < 2: + tempRemovedCandidate = SCORES.pop(candidate) + if (SCORES.index(max(SCORES)) != candidate) and (max(SCORES) >= tempRemovedCandidate - 20): + if SCORES.index(max(SCORES)) < candidate: + candidates += [ TYPES[SCORES.index(max(SCORES))] ] + else: + candidates += [ TYPES[SCORES.index(max(SCORES)) + 1] ] + SCORES.insert(candidate, tempRemovedCandidate) + # Return the candidates - #logfile.printdbg("Scores : {}".format(SCORES)) - #logfile.printdbg("Candidates : {}".format(canditxt)) + logfile.printdbg("Scores : {}".format(SCORES)) + logfile.printdbg("Candidates : {}".format(canditxt)) return candidates def computeControlSum(code): @@ -413,6 +424,11 @@ def computeAllControlSum(doc, code): # iteration on each char of the given MRZ for charPos in range(len(code)): + + # Sanity check + if len(getDocString(doc)) <= charPos: + break + field = getDocString(doc)[charPos] if doc[1][field][1] == "CTRL": @@ -421,6 +437,12 @@ def computeAllControlSum(doc, code): codeChain = "" # iteration on the fields to control for pos in range(len(code)): + + #print("Len : {}, pos : {}".format(len(getDocString(doc)), pos)) + # Sanity check + if len(getDocString(doc)) <= pos: + break + target = getDocString(doc)[pos] if target in doc[1][field][3]: #print("__field : {} {} {} {}".format(target, pos, field, doc[1][field][3])) diff --git a/src/updater.py b/src/updater.py index 54e08ae..4f69f94 100644 --- a/src/updater.py +++ b/src/updater.py @@ -38,6 +38,7 @@ import subprocess import psutil import critical # critical.py +import github # github.py import ihm # ihm.py import logger # logger.py import globs # globs.py @@ -316,7 +317,6 @@ def umain(): # Global Handlers logfile = logger.logCur - credentials = downloader.newcredentials() if not credentials.valid: @@ -325,6 +325,8 @@ def umain(): time.sleep(2) launcherWindow.exit() return 0 + + github.credentials = credentials # Cleaner for the old version if detected if len(sys.argv) > 2 and str(sys.argv[1]) == "DELETE": diff --git a/src/version.res b/src/version.res new file mode 100644 index 0000000..43adb08 --- /dev/null +++ b/src/version.res @@ -0,0 +1,43 @@ +# UTF-8 +# +# For more details about fixed file info 'ffi' see: +# http://msdn.microsoft.com/en-us/library/ms646997.aspx +VSVersionInfo( + ffi=FixedFileInfo( +# filevers and prodvers should be always a tuple with four items: (1, 2, 3, 4) +# Set not needed items to zero 0. +filevers=(3, 1, 3, 0), +prodvers=(3, 1, 3, 0), +# Contains a bitmask that specifies the valid bits 'flags'r +mask=0x3f, +# Contains a bitmask that specifies the Boolean attributes of the file. +flags=0x0, +# The operating system for which this file was designed. +# 0x4 - NT and there is no need to change it. +OS=0x4, +# The general type of file. +# 0x1 - the file is an application. +fileType=0x1, +# The function of the file. +# 0x0 - the function is not defined for this fileType +subtype=0x0, +# Creation date and time stamp. +date=(0, 0) +), + kids=[ +StringFileInfo( + [ + StringTable( + u'040904B0', + [StringStruct(u'CompanyName', u'Adrien Bourmault (neox95)'), + StringStruct(u'FileDescription', u'This file is part of CNIRevelator.'), + StringStruct(u'FileVersion', u'3.1.3'), + StringStruct(u'InternalName', u'CNIRevelator'), + StringStruct(u'LegalCopyright', u'Copyright (c) Adrien Bourmault (neox95)'), + StringStruct(u'OriginalFilename', u'CNIRevelator.exe'), + StringStruct(u'ProductName', u'CNIRevelator 3'), + StringStruct(u'ProductVersion', u'3.1.3')]) + ]), +VarFileInfo([VarStruct(u'Translation', [1033, 1200])]) + ] +) \ No newline at end of file