mirror of
https://gitlab.os-k.eu/neox/CNIRevelator.git
synced 2023-08-25 14:03:10 +02:00
Main files of the project
This commit is contained in:
parent
ccf4adc566
commit
6a5a01c117
50
CNI_GLOBALVAR.py
Normal file
50
CNI_GLOBALVAR.py
Normal file
@ -0,0 +1,50 @@
|
||||
"""
|
||||
********************************************************************************
|
||||
*** Projet CNI_Revelator ***
|
||||
|
||||
GNU GPL * 07/2018
|
||||
|
||||
Adrien Bourmault
|
||||
|
||||
VARIABLES
|
||||
|
||||
********************************************************************************
|
||||
"""
|
||||
CST_REV = "8"
|
||||
CST_VERTITLE = "2.2"
|
||||
CST_TAB_VER = ["2","2","1"]
|
||||
CST_VER = "{0}.{1}.{2}".format(CST_TAB_VER[0], CST_TAB_VER[1], CST_TAB_VER[2])
|
||||
CST_TYPE = "Final Release"
|
||||
CST_NAME = "CNIRevelator"
|
||||
CST_TITLE = CST_NAME + " " + CST_VER + " - GNU/GPL Licensing 2018"
|
||||
CST_MARK = CST_NAME + " " + CST_TYPE + " " + CST_VER + " - by NeoX, GNU/GPL Licensing 2018"
|
||||
CST_SUM_VER = int(CST_TAB_VER[0])*100 + int(CST_TAB_VER[1])*10 + int(CST_TAB_VER[2])
|
||||
CST_LINK = <lien vers serveur>
|
||||
CST_COLOR = "#003380"
|
||||
|
||||
|
||||
import base64
|
||||
import hashlib
|
||||
from Crypto import Random
|
||||
from Crypto.Cipher import AES
|
||||
from tkinter import *
|
||||
from tkinter.messagebox import *
|
||||
from tkinter import filedialog
|
||||
from tkinter import ttk as ttk
|
||||
import os
|
||||
import time
|
||||
import threading
|
||||
import sys
|
||||
import urllib.request as urllib2
|
||||
import urllib.error as URLExcept
|
||||
import random
|
||||
from pypac import PACSession
|
||||
from requests.auth import HTTPProxyAuth
|
||||
import subprocess
|
||||
from datetime import datetime
|
||||
from PIL import Image, ImageFont, ImageDraw, ImageTk, ImageEnhance, ImageFilter
|
||||
import math
|
||||
import warnings
|
||||
import string
|
||||
|
||||
CST_FOLDER = os.getenv('APPDATA') + "/CNIRevelator/"
|
131
CNI_Revelator.py
Normal file
131
CNI_Revelator.py
Normal file
@ -0,0 +1,131 @@
|
||||
"""
|
||||
********************************************************************************
|
||||
*** Projet CNI_Revelator ***
|
||||
|
||||
GNU GPL * 07/2018
|
||||
|
||||
Adrien Bourmault
|
||||
|
||||
main
|
||||
|
||||
********************************************************************************
|
||||
"""
|
||||
|
||||
###IMPORTS GLOBAUX
|
||||
from CNI_GLOBALVAR import *
|
||||
|
||||
|
||||
##LOGGING
|
||||
|
||||
try:
|
||||
os.remove("error.log")
|
||||
os.remove("conf.ig")
|
||||
except:
|
||||
pass
|
||||
import logging
|
||||
|
||||
CST_NIVEAU_LOG = logging.ERROR
|
||||
|
||||
from logging.handlers import RotatingFileHandler
|
||||
|
||||
# création de l'objet logger qui va nous servir à écrire dans les logs
|
||||
logger = logging.getLogger()
|
||||
# on met le niveau du logger à DEBUG, comme ça il écrit tout
|
||||
logger.setLevel(CST_NIVEAU_LOG)
|
||||
|
||||
# création d'un formateur qui va ajouter le temps, le niveau
|
||||
# de chaque message quand on écrira un message dans le log
|
||||
formatter = logging.Formatter('%(asctime)s :: %(levelname)s :: %(message)s')
|
||||
# création d'un handler qui va rediriger une écriture du log vers
|
||||
# un fichier en mode 'append', avec 1 backup et une taille max de 1Mo
|
||||
file_handler = RotatingFileHandler('error.log', 'a', 1000000, 1)
|
||||
# on lui met le niveau sur DEBUG, on lui dit qu'il doit utiliser le formateur
|
||||
# créé précédement et on ajoute ce handler au logger
|
||||
file_handler.setLevel(CST_NIVEAU_LOG)
|
||||
file_handler.setFormatter(formatter)
|
||||
logger.addHandler(file_handler)
|
||||
|
||||
##History
|
||||
|
||||
|
||||
|
||||
### IMPORTS LOCAUX
|
||||
from CNI_classes import *
|
||||
from CNI_Update import *
|
||||
|
||||
### FONCTION PRINCIPALE
|
||||
|
||||
|
||||
def main(logger):
|
||||
|
||||
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
|
||||
|
||||
try:
|
||||
|
||||
os.environ["PATH"] = CST_FOLDER + "Tesseract-OCR4\\"
|
||||
os.environ["TESSDATA_PREFIX"] = CST_FOLDER + "Tesseract-OCR4\\tessdata"
|
||||
tesser_version = pytesseract.get_tesseract_version()
|
||||
|
||||
except Exception as e:
|
||||
logger.error("main() : " +"**** ERROR WITH TESSERACT MODULE " + str(e) + " ****")
|
||||
else:
|
||||
text = "Tesseract version " + str(tesser_version) +" Licensed Apache 2004 successfully initiated\n"
|
||||
main_w.montext(text)
|
||||
|
||||
|
||||
main_w.montext("\n\nEntrez la première ligne de MRZ svp \n")
|
||||
|
||||
|
||||
|
||||
logger.info("main() : " +"**** Launching App_main() ****")
|
||||
main_w.mainloop()
|
||||
logger.info("main() : " +"**** Ending App_main() ****")
|
||||
|
||||
|
||||
|
||||
##Launcher
|
||||
|
||||
logger.info("launcher : " + CST_NAME +" "+ CST_VER)
|
||||
logger.info("launcher : " +"*****Hello World*****")
|
||||
|
||||
logger.info("launcher : " +"*****Launching SoftUpdate()*****")
|
||||
try:
|
||||
Answer = SoftUpdate(logger)
|
||||
except Exception as e:
|
||||
logger.info("launcher : " +"*****FATAL ERROR*****" + str(e))
|
||||
os.abort()
|
||||
logger.info("launcher : " +"*****Ending SoftUpdate()*****")
|
||||
|
||||
|
||||
try:
|
||||
if Answer == True:
|
||||
logger.info("launcher : " +"*****Launching main()*****")
|
||||
State = main(logger)
|
||||
except Exception as e:
|
||||
logger.info("launcher : " +"*****FATAL ERROR*****" + str(e))
|
||||
os.abort()
|
||||
|
||||
logger.info("launcher : " +"*****Ending main()*****")
|
||||
logger.info("launcher : " +"*****Goodbye!*****")
|
||||
|
||||
handlers = logger.handlers[:]
|
||||
for handler in handlers:
|
||||
handler.close()
|
||||
logger.removeHandler(handler)
|
||||
|
||||
|
||||
if os.path.getsize("error.log") == 0:
|
||||
try:
|
||||
os.remove("error.log")
|
||||
except:
|
||||
raise(OSError)
|
||||
os.abort()
|
||||
|
||||
sys.exit(0)
|
||||
|
||||
|
568
CNI_Update.py
Normal file
568
CNI_Update.py
Normal file
@ -0,0 +1,568 @@
|
||||
"""
|
||||
********************************************************************************
|
||||
*** Projet CNI_Revelator ***
|
||||
|
||||
GNU GPL * 07/2018
|
||||
|
||||
Adrien Bourmault
|
||||
|
||||
UPDATE
|
||||
|
||||
********************************************************************************
|
||||
"""
|
||||
|
||||
|
||||
###IMPORTS GLOBAUX
|
||||
from CNI_GLOBALVAR import *
|
||||
|
||||
|
||||
###IMPORTS LOCAUX
|
||||
from CNI_classes import *
|
||||
|
||||
|
||||
###BEGIN
|
||||
|
||||
def SoftUpdate(logger): #Fonction de mise à jour de l'application
|
||||
|
||||
import zipfile
|
||||
# zip_ref = zipfile.ZipFile(path_to_zip_file, 'r')
|
||||
# zip_ref.extractall(directory_to_extract_to)
|
||||
# zip_ref.close()
|
||||
|
||||
logger.info("SoftUpdate() : " +"Verifying local data dir...")
|
||||
if not os.path.exists(CST_FOLDER):
|
||||
os.makedirs(CST_FOLDER)
|
||||
logger.info("SoftUpdate() : " +"Data dir created !")
|
||||
|
||||
logger.info("SoftUpdate() : " +"Looking for older version in dir...")
|
||||
list = os.listdir('.')
|
||||
|
||||
for file in list:
|
||||
|
||||
if file.startswith("CNIRevelator_"):
|
||||
|
||||
temp = ["0","0","0"]
|
||||
ver = file[13:].split(".")
|
||||
|
||||
|
||||
for i in range(len(ver)):
|
||||
|
||||
|
||||
|
||||
if ver[i] != "exe" :
|
||||
try:
|
||||
temp[i] = ver[i]
|
||||
except:
|
||||
None
|
||||
|
||||
|
||||
ver = temp.copy()
|
||||
|
||||
try :
|
||||
sum_ver = int(ver[0])*100 + int(ver[1])*10 + int(ver[2])
|
||||
|
||||
if sum_ver < CST_SUM_VER:
|
||||
|
||||
os.remove(file)
|
||||
logger.info("SoftUpdate() : " + "Removed old version : " + str(file) )
|
||||
|
||||
except:
|
||||
|
||||
logger.error("SoftUpdate() : " +"Failing to remove old version : " + str(file) )
|
||||
|
||||
None
|
||||
|
||||
|
||||
def updating(): #Fonction de lancement du thread de maj
|
||||
|
||||
def updator(): #Fonction d'exécution de la maj
|
||||
|
||||
logger.info("[updator() thread] : " + "Welcome !")
|
||||
global ret
|
||||
ret = 11
|
||||
canvas.itemconfigure(message, text="Recherche de mises-à-jour...")
|
||||
p.configure(mode = "indeterminate", value = 0, maximum = 20)
|
||||
p.start()
|
||||
upwin.update()
|
||||
logger.info("[updator() thread] : " + "Looking for updates...")
|
||||
|
||||
try:#Essai par proxy
|
||||
|
||||
def download(url, filename):
|
||||
|
||||
try: # if identifiants disponibles dans un fichier
|
||||
|
||||
logger.info("[download() thread] : " + "Trying getting credentials in the config file")
|
||||
|
||||
with open(CST_FOLDER +'conf.ig', "rb") as config:
|
||||
|
||||
AESObj = AESCipher("<clé>")
|
||||
IPN, IPN_PASS = AESObj.decrypt(config.read()).split("||")[0:2]
|
||||
logger.info("[download() thread] : " + "Got credentials !")
|
||||
|
||||
session = PACSession(proxy_auth=HTTPProxyAuth(IPN, IPN_PASS))
|
||||
logger.info("[download() thread] : " + "Authenticated to proxy successfully")
|
||||
|
||||
|
||||
except IOError as e: #Else : on vérifie les identifiants de proxy
|
||||
|
||||
logger.error("[download() thread] : " + "False or absent credentials in the config file : " + str(e))
|
||||
|
||||
NoConnect = True
|
||||
|
||||
while NoConnect:
|
||||
|
||||
class LoginDialog(Toplevel):
|
||||
global login
|
||||
global key
|
||||
|
||||
def __init__(self, parent):
|
||||
super().__init__(parent)
|
||||
self.title("Connexion")
|
||||
# ---------------------------------------
|
||||
Label(self, text="IPN : ").pack()
|
||||
self.entry_login = Entry(self)
|
||||
self.entry_login.insert(0, "")
|
||||
self.entry_login.pack()
|
||||
# ---------------------------------------
|
||||
Label(self, text="Mot de passe : ").pack()
|
||||
self.entry_pass = Entry(self, show='*')
|
||||
self.entry_pass.insert(0, "")
|
||||
self.entry_pass.pack()
|
||||
# ---------------------------------------
|
||||
Button(self, text="Connexion", command=self.connecti).pack()
|
||||
self.resizable(width=False, height=False)
|
||||
#taille souhaite de la fenetre
|
||||
w = 150
|
||||
h = 110
|
||||
#pour centrer la fenetre
|
||||
#taille de l'ecran
|
||||
self.update()
|
||||
ws = self.winfo_screenwidth()
|
||||
hs = self.winfo_screenheight()
|
||||
|
||||
if getattr( sys, 'frozen', False ) :
|
||||
self.iconbitmap(sys._MEIPASS + "\id-card.ico\id-card.ico")
|
||||
else:
|
||||
self.iconbitmap("id-card.ico")
|
||||
|
||||
upwin.update()
|
||||
#calcul la position de la fenetre
|
||||
x = (ws/2) - (w/2)
|
||||
y = (hs/2) - (h/2)
|
||||
#applique la taille et la position
|
||||
self.geometry('%dx%d+%d+%d' % (w, h, x, y))
|
||||
|
||||
def connecti(self):
|
||||
global login
|
||||
global key
|
||||
login = self.entry_login.get().strip()
|
||||
key = self.entry_pass.get().strip()
|
||||
self.destroy()
|
||||
|
||||
session = PACSession()
|
||||
|
||||
if session.get_pac() == None:
|
||||
IPN = ""
|
||||
IPN_PASS = ""
|
||||
NoConnect = False
|
||||
|
||||
break
|
||||
|
||||
canvas.itemconfigure(message, text="En attente de connexion au serveur proxy...")
|
||||
global login
|
||||
global key
|
||||
login = ""
|
||||
key = ""
|
||||
|
||||
result = LoginDialog(upwin)
|
||||
result.transient(upwin)
|
||||
result.grab_set()
|
||||
upwin.wait_window(result)
|
||||
|
||||
IPN = login
|
||||
IPN_PASS = key
|
||||
|
||||
session = PACSession(proxy_auth=HTTPProxyAuth(IPN, IPN_PASS))
|
||||
Ans = session.get("http://www.google.com")
|
||||
|
||||
if str(Ans) == "<Response [407]>":
|
||||
canvas.itemconfigure(message, text="Identifiants erronés, accès refusé")
|
||||
logger.info("[download() thread] : " + "407 Error")
|
||||
time.sleep(1)
|
||||
elif str(Ans) == "<Response [200]>":
|
||||
logger.info("[download() thread] : " + "Connection ok !")
|
||||
NoConnect = False
|
||||
else:
|
||||
raise(IOError())
|
||||
|
||||
AESObj = AESCipher("<clé>")
|
||||
|
||||
with open(CST_FOLDER +"conf.ig","wb+") as f:
|
||||
logger.info("[download() thread] : " + "Saving credentials in encrypted config file")
|
||||
f.write(AESObj.encrypt(IPN + "||" + IPN_PASS))
|
||||
|
||||
|
||||
|
||||
if IPN == "i005316":
|
||||
canvas.itemconfigure(message, text="Bienvenue Thierry !")
|
||||
elif IPN == "i020251":
|
||||
canvas.itemconfigure(message, text="Bienvenue Samia !")
|
||||
elif IPN == "i018410":
|
||||
canvas.itemconfigure(message, text="Bienvenue Adrien !")
|
||||
elif IPN == "i003067":
|
||||
canvas.itemconfigure(message, text="Bienvenue Remy !")
|
||||
elif IPN == "i018422":
|
||||
canvas.itemconfigure(message, text="Bienvenue Eloise !")
|
||||
time.sleep(1)
|
||||
|
||||
try:
|
||||
Prox_us = session.get_pac().find_proxy_for_url(CST_LINK,"neoxgroup.eu")
|
||||
PROXY_USABLE = Prox_us[6:-1].split(";")[0]
|
||||
proxy_server_url = IPN +":"+IPN_PASS+"@" + PROXY_USABLE
|
||||
ph = urllib2.ProxyHandler( { 'http' : proxy_server_url } )
|
||||
auth = urllib2.ProxyBasicAuthHandler()
|
||||
server= urllib2.build_opener( ph, auth, urllib2.HTTPHandler )
|
||||
urllib2.install_opener(server)
|
||||
logger.info("[download() thread] : " + "Proxy connection initiated successfully")
|
||||
|
||||
except:
|
||||
|
||||
logger.info("[download() thread] : " + "Proxy connection not initiated")
|
||||
|
||||
try:
|
||||
urllib2.urlretrieve(url, filename)
|
||||
return True
|
||||
except Exception as e:
|
||||
logger.error("[download() thread] : " + "HTTP ERROR " )
|
||||
return e
|
||||
|
||||
##updator()
|
||||
logger.info("[updator() thread] : " + "Prepare downloading the version recap file...")
|
||||
tempfile = CST_FOLDER + 'temp' + str(random.randint(11111,99999)) + ".cniu"
|
||||
isOk = download(CST_LINK+"Version.txt", tempfile)
|
||||
|
||||
if not isOk:
|
||||
raise(isOk)
|
||||
|
||||
urllib2.urlcleanup()
|
||||
logger.info("[updator() thread] : " + "Opening version recap file...")
|
||||
file_ver = open(tempfile, "r")
|
||||
logger.info("[updator() thread] : " + "Reading version recap file...")
|
||||
version = file_ver.read()
|
||||
logger.info("[updator() thread] : " + "Closing version recap file...")
|
||||
repert = version.split("|")
|
||||
file_ver.close()
|
||||
logger.info("[updator() thread] : " + "Deleting version recap file...")
|
||||
os.remove(tempfile)
|
||||
logger.info("[updator() thread] : " + "Parsing informations about version...")
|
||||
final_f = "CNI_file"
|
||||
final_ver = ['0','0','0']
|
||||
|
||||
for file in repert:
|
||||
|
||||
if str.startswith(file,CST_NAME): #On prend les fichiers d'interêt du répertoire
|
||||
|
||||
ver = file.replace(CST_NAME+"_","").split(".") #On ne garde que le numéro de version
|
||||
|
||||
temp = ["0","0","0"]
|
||||
|
||||
for i in range(len(ver)):
|
||||
|
||||
temp[i] = ver[i]
|
||||
|
||||
ver = temp.copy()
|
||||
|
||||
sum_fver = int(final_ver[0])*100 + int(final_ver[1])*10 + int(final_ver[2])
|
||||
|
||||
sum_ver = int(ver[0])*100 + int(ver[1])*10 + int(ver[2])
|
||||
|
||||
|
||||
if sum_ver > sum_fver:
|
||||
|
||||
final_ver = ver.copy()
|
||||
final_f = file
|
||||
|
||||
sum_ver = int(final_ver[0])*100 + int(final_ver[1])*10 + int(final_ver[2])
|
||||
|
||||
if final_f != "CNI_file" and (sum_ver > CST_SUM_VER):
|
||||
#On a une maj
|
||||
logger.info("[updator() thread] : " + "New version of CNIRevelator found !")
|
||||
canvas.itemconfigure(message, text="Mise à jour disponible ! Préparation du téléchargement...")
|
||||
logger.info("[updator() thread] : " + "Preparing download")
|
||||
|
||||
with open(CST_FOLDER +'conf.ig', "rb") as config:
|
||||
|
||||
logger.info("[updator() thread] : " + "Reading credentials for proxy in config file...")
|
||||
|
||||
AESObj = AESCipher("<clé>")
|
||||
IPN, IPN_PASS = AESObj.decrypt(config.read()).split("||")[0:2]
|
||||
|
||||
session = PACSession(proxy_auth=HTTPProxyAuth(IPN, IPN_PASS))
|
||||
|
||||
try:
|
||||
|
||||
Prox_us = session.get_pac().find_proxy_for_url(CST_LINK,"neoxgroup.eu")
|
||||
PROXY_USABLE = Prox_us[6:-1].split(";")[0]
|
||||
proxy_server_url = IPN +":"+IPN_PASS+"@" + PROXY_USABLE
|
||||
ph = urllib2.ProxyHandler( { 'http' : proxy_server_url } )
|
||||
auth = urllib2.ProxyBasicAuthHandler()
|
||||
server= urllib2.build_opener( ph, auth, urllib2.HTTPHandler )
|
||||
logger.info("[updator() thread] : " + "Connection to the proxy initiated successfully !")
|
||||
|
||||
|
||||
except:
|
||||
|
||||
canvas.itemconfigure(message, text="Téléchargement en connexion directe...")
|
||||
server= urllib2.build_opener()
|
||||
logger.info("[updator() thread] : " + "Direct connection initiated successfully")
|
||||
|
||||
logger.info("[updator() thread] : " + "Launching download of " + final_f)
|
||||
Statut = Download( CST_LINK + final_f, final_f, final_f, server, p, canvas, message, logger )
|
||||
|
||||
if Statut.success:
|
||||
|
||||
try:
|
||||
os.rename(final_f, final_f + ".exe")
|
||||
except IOError:
|
||||
logger.error("[updator() thread] : " + "Unable to rename the file ! Wait 3 sec and retry")
|
||||
time.sleep(3)
|
||||
try:
|
||||
os.rename(final_f, final_f + ".exe")
|
||||
except IOError:
|
||||
logger.critical("[updator() thread] : " + "Unable to rename the file !")
|
||||
|
||||
else:
|
||||
canvas.itemconfigure(message, text="Téléchargement terminé ! Préparation du lancement...")
|
||||
logger.info("[updator() thread] : " + "Download of " + final_f + "finished successfully")
|
||||
p.configure(mode = "indeterminate", value = 0, maximum = 20)
|
||||
p.start()
|
||||
time.sleep(1)
|
||||
logger.info("[updator() thread] : " + "Launching " + final_f)
|
||||
try:
|
||||
proc = subprocess.Popen(final_f + ".exe", shell=False,stdin=None, stdout=None, stderr=None, close_fds=True)
|
||||
except:
|
||||
logger.error("[updator() thread] : " + "Unable to start the new version ! Wait 3 sec and retry")
|
||||
time.sleep(3)
|
||||
try:
|
||||
proc = subprocess.Popen(final_f + ".exe", shell=False,stdin=None, stdout=None, stderr=None, close_fds=True)
|
||||
except Exception as e:
|
||||
logger.critical("[updator() thread] : " + "Unable to start the new version ! Stopping : " + str(e))
|
||||
showerror("Erreur d'appel de procédure distante", "Le lancement du nouveau programme a échoué, vous devez le lancer manuellement une fois cette fenêtre fermée")
|
||||
ret = 12
|
||||
else:
|
||||
canvas.itemconfigure(message, text="Echec de la mise à jour : Erreur HTTP. Préparation du lancement...")
|
||||
logger.error("[updator() thread] : " + "Update has failed with HTTP error")
|
||||
time.sleep(1)
|
||||
|
||||
|
||||
|
||||
else:
|
||||
canvas.itemconfigure(message, text="Logiciel déjà à jour. Préparation du lancement...")
|
||||
logger.info("[updator() thread] : " + "CNIRevelator is up to date !")
|
||||
time.sleep(1)
|
||||
ret = 11
|
||||
|
||||
|
||||
#Tesseract
|
||||
if os.path.exists(CST_FOLDER + "Tesseract-OCR4\\tesseract.exe"):
|
||||
os.environ["PATH"] = CST_FOLDER + "Tesseract-OCR4\\"
|
||||
os.environ["TESSDATA_PREFIX"] = CST_FOLDER + "Tesseract-OCR4\\tessdata"
|
||||
|
||||
|
||||
else:
|
||||
|
||||
final_f = "tesseract_4"
|
||||
|
||||
#On a une maj
|
||||
logger.info("[updator() thread] : " + "Downloading tesseract 4 !")
|
||||
canvas.itemconfigure(message, text="Mise à jour du module OCR ! Préparation du téléchargement...")
|
||||
logger.info("[updator() thread] : " + "Preparing download")
|
||||
|
||||
with open(CST_FOLDER +'conf.ig', "rb") as config:
|
||||
|
||||
logger.info("[updator() thread] : " + "Reading credentials for proxy in config file...")
|
||||
|
||||
AESObj = AESCipher("<clé>")
|
||||
IPN, IPN_PASS = AESObj.decrypt(config.read()).split("||")[0:2]
|
||||
|
||||
session = PACSession(proxy_auth=HTTPProxyAuth(IPN, IPN_PASS))
|
||||
|
||||
try:
|
||||
|
||||
Prox_us = session.get_pac().find_proxy_for_url(CST_LINK,"neoxgroup.eu")
|
||||
PROXY_USABLE = Prox_us[6:-1].split(";")[0]
|
||||
proxy_server_url = IPN +":"+IPN_PASS+"@" + PROXY_USABLE
|
||||
ph = urllib2.ProxyHandler( { 'http' : proxy_server_url } )
|
||||
auth = urllib2.ProxyBasicAuthHandler()
|
||||
server= urllib2.build_opener( ph, auth, urllib2.HTTPHandler )
|
||||
logger.info("[updator() thread] : " + "Connection to the proxy initiated successfully !")
|
||||
|
||||
|
||||
except:
|
||||
|
||||
canvas.itemconfigure(message, text="Téléchargement en connexion directe...")
|
||||
server= urllib2.build_opener()
|
||||
logger.info("[updator() thread] : " + "Direct connection initiated successfully")
|
||||
|
||||
logger.info("[updator() thread] : " + "Launching download of " + final_f)
|
||||
|
||||
Statut = Download( CST_LINK + final_f, CST_FOLDER + final_f, final_f, server, p, canvas, message, logger )
|
||||
|
||||
if Statut.success:
|
||||
|
||||
canvas.itemconfigure(message, text="Téléchargement terminé ! Installation...")
|
||||
logger.info("[updator() thread] : " + "Download of " + final_f + "finished successfully")
|
||||
p.configure(mode = "indeterminate", value = 0, maximum = 20)
|
||||
p.start()
|
||||
|
||||
try:
|
||||
zip_ref = zipfile.ZipFile(CST_FOLDER + final_f, 'r')
|
||||
zip_ref.extractall(CST_FOLDER)
|
||||
zip_ref.close()
|
||||
os.environ["PATH"] = CST_FOLDER + "Tesseract-OCR4\\"
|
||||
os.environ["TESSDATA_PREFIX"] = CST_FOLDER + "Tesseract-OCR4\\tessdata"
|
||||
canvas.itemconfigure(message, text="Installation terminée !")
|
||||
|
||||
|
||||
|
||||
except:
|
||||
logger.error("[updator() thread] : " + "Unable to install the module. Wait and retry")
|
||||
time.sleep(3)
|
||||
try:
|
||||
zip_ref = zipfile.ZipFile(CST_FOLDER + final_f, 'r')
|
||||
zip_ref.extractall(CST_FOLDER)
|
||||
zip_ref.close()
|
||||
os.environ["PATH"] = CST_FOLDER + "Tesseract-OCR4\\"
|
||||
os.environ["TESSDATA_PREFIX"] = CST_FOLDER + "Tesseract-OCR4\\tessdata"
|
||||
canvas.itemconfigure(message, text="Installation terminée !")
|
||||
|
||||
|
||||
|
||||
except Exception as e:
|
||||
logger.critical("[updator() thread] : " + "Unable to install the module ! Stopping : " + str(e))
|
||||
showerror("Erreur d'appel de procédure distante", "L'installation du module OCR a échoué, contactez le développeur.")
|
||||
ret = 11
|
||||
|
||||
else:
|
||||
|
||||
logger.critical("[updator() thread] : " + "Unable to download the module ! ")
|
||||
showerror("Erreur de téléchargement", "L'installation du module OCR a échoué, merci d'indiquer le chemin d'accès au fichier tesseract_4 dans la fenêtre suivante")
|
||||
|
||||
path = filedialog.askopenfilename(title = "Indiquez le chemin d'accès à tesseract_4...",filetypes = (("Tesseract_4","*.cni4"), ("Tesseract_4","*.cni4")))
|
||||
|
||||
if path != "":
|
||||
|
||||
try:
|
||||
canvas.itemconfigure(message, text="Installation...")
|
||||
zip_ref = zipfile.ZipFile(path, 'r')
|
||||
zip_ref.extractall(CST_FOLDER)
|
||||
zip_ref.close()
|
||||
logger.error("[updator() thread] : " + "Manual installation successed")
|
||||
canvas.itemconfigure(message, text="Installation terminée !")
|
||||
os.environ["PATH"] = CST_FOLDER + "Tesseract-OCR4\\"
|
||||
os.environ["TESSDATA_PREFIX"] = CST_FOLDER + "Tesseract-OCR4\\tessdata"
|
||||
|
||||
|
||||
except Exception as e:
|
||||
|
||||
logger.error("[updator() thread] : " + "Manual installation has failed" + str(e) )
|
||||
showerror("Erreur de lecture", "Le module OCR n'a pas pu être installé, la saisie automatique de scans ne pourra donc fonctionner")
|
||||
|
||||
|
||||
else:
|
||||
|
||||
showerror("Opération annulée", "Le module OCR n'a été installé, la saisie automatique de scans ne pourra donc fonctionner")
|
||||
|
||||
|
||||
except URLExcept.HTTPError as e:
|
||||
|
||||
canvas.itemconfigure(message, text="Echec de la mise à jour : Erreur HTTP " + str(e.code) + " . Préparation du lancement...")
|
||||
logger.error("[updator() thread] : " + "Update has failed with HTTP error" + str(e.code) )
|
||||
|
||||
if int(e.code) == 407:
|
||||
showerror("Erreur 407", "Attention : le système de mise à jour automatique a fait face à une erreur 407, signifiant que la connexion au serveur proxy a été refusée. Vos identifiants vous seront redemandés au prochain démarrage. La mise à jour a échoué.")
|
||||
logger.info("[updator() thread] : " + "Credential error. Deleting the config file...")
|
||||
os.remove(CST_FOLDER +"conf.ig")
|
||||
p.configure(mode = "indeterminate", value = 0, maximum = 20)
|
||||
p.start()
|
||||
time.sleep(3)
|
||||
|
||||
except Exception as e:
|
||||
|
||||
canvas.itemconfigure(message, text="Echec de la mise à jour. Préparation du lancement...")
|
||||
logger.error("[updator() thread] : " + "Error from the updating system : " + str(e))
|
||||
p.configure(mode = "indeterminate", value = 0, maximum = 20)
|
||||
p.start()
|
||||
time.sleep(2)
|
||||
|
||||
|
||||
p.stop()
|
||||
upwin.destroy()
|
||||
root.destroy()
|
||||
return ret
|
||||
|
||||
##updating()
|
||||
global ret
|
||||
logger.info("updating() : " + "Launching updator() thread...")
|
||||
threading.Thread(target=updator, daemon=True).start()
|
||||
logger.info("updating() [Thread] : " + "Ending updator() thread")
|
||||
return None
|
||||
|
||||
##SoftUpdate()
|
||||
|
||||
global ret
|
||||
ret = 11
|
||||
global upwin
|
||||
root = Tk()
|
||||
root.attributes('-alpha', 0.0) #For icon
|
||||
#root.lower()
|
||||
root.iconify()
|
||||
|
||||
upwin = Toplevel(root)
|
||||
upwin.overrideredirect(1)
|
||||
upwin.configure(bg = CST_COLOR)
|
||||
|
||||
upwin.resizable(width=False, height=False)
|
||||
#taille souhaite de la fenetre
|
||||
w = 600
|
||||
h = 300
|
||||
#pour centrer la fenetre
|
||||
#taille de l'ecran
|
||||
upwin.update()
|
||||
canvas = Canvas(upwin, width=600, height=270, bg=CST_COLOR, highlightthickness=0)
|
||||
pbar = Canvas(upwin, width=600, height=30, bg=CST_COLOR)
|
||||
p = ttk.Progressbar(pbar, orient=HORIZONTAL, length=590, mode='determinate')
|
||||
upwin.update()
|
||||
ws = upwin.winfo_screenwidth()
|
||||
hs = upwin.winfo_screenheight()
|
||||
canvas.create_text(w/2, h/3, text=CST_NAME + " " + CST_VERTITLE, font="Calibri 30 bold", fill="white")
|
||||
message = canvas.create_text(w/2, h/1.150, text=" ", font="Calibri 9", fill="white")
|
||||
upwin.update()
|
||||
#calcul la position de la fenetre
|
||||
x = (ws/2) - (w/2)
|
||||
y = (hs/2) - (h/2)
|
||||
#applique la taille et la position
|
||||
upwin.geometry('%dx%d+%d+%d' % (w, h, x, y))
|
||||
canvas.grid()
|
||||
pbar.grid()
|
||||
p.grid()
|
||||
upwin.after(2000, updating)
|
||||
|
||||
if getattr( sys, 'frozen', False ) :
|
||||
root.iconbitmap(sys._MEIPASS + "\id-card.ico\id-card.ico")
|
||||
else:
|
||||
root.iconbitmap("id-card.ico")
|
||||
|
||||
# On démarre la boucle Tkinter qui s'interrompt quand on ferme la fenêtre
|
||||
logger.info("SoftUpdate() : " + "Entering upwin mainloop()")
|
||||
upwin.protocol('WM_DELETE_WINDOW', lambda: root.destroy())
|
||||
upwin.mainloop()
|
||||
logger.info("SoftUpdate() : " + "Exiting upwin mainloop()")
|
||||
|
||||
if ret == 11:
|
||||
logger.info("SoftUpdate() : " + "OK to start to main() normally !")
|
||||
return True
|
||||
else:
|
||||
logger.info("SoftUpdate() : " + "Program will stop !")
|
||||
return False
|
1551
CNI_classes.py
Normal file
1551
CNI_classes.py
Normal file
File diff suppressed because one or more lines are too long
413
CNI_pytesseract.py
Normal file
413
CNI_pytesseract.py
Normal file
@ -0,0 +1,413 @@
|
||||
"""
|
||||
********************************************************************************
|
||||
*** Projet CNI_Revelator ***
|
||||
|
||||
GNU GPL * 07/2018
|
||||
|
||||
Adrien Bourmault
|
||||
|
||||
Pytesseract modification to comply with Pyinstaller
|
||||
|
||||
*****
|
||||
"""
|
||||
#!/usr/bin/env python
|
||||
|
||||
'''
|
||||
Python-tesseract. For more information: https://github.com/madmaze/pytesseract
|
||||
'''
|
||||
|
||||
try:
|
||||
import Image
|
||||
except ImportError:
|
||||
from PIL import Image
|
||||
|
||||
import os
|
||||
import sys
|
||||
import subprocess
|
||||
import tempfile
|
||||
import shlex
|
||||
import string
|
||||
from glob import iglob
|
||||
from pkgutil import find_loader
|
||||
from distutils.version import LooseVersion
|
||||
from os.path import realpath, normpath, normcase
|
||||
|
||||
numpy_installed = find_loader('numpy') is not None
|
||||
if numpy_installed:
|
||||
from numpy import ndarray
|
||||
|
||||
# CHANGE THIS IF TESSERACT IS NOT IN YOUR PATH, OR IS NAMED DIFFERENTLY
|
||||
tesseract_cmd = 'tesseract'
|
||||
RGB_MODE = 'RGB'
|
||||
OSD_KEYS = {
|
||||
'Page number': ('page_num', int),
|
||||
'Orientation in degrees': ('orientation', int),
|
||||
'Rotate': ('rotate', int),
|
||||
'Orientation confidence': ('orientation_conf', float),
|
||||
'Script': ('script', str),
|
||||
'Script confidence': ('script_conf', float)
|
||||
}
|
||||
|
||||
|
||||
class Output:
|
||||
STRING = "string"
|
||||
BYTES = "bytes"
|
||||
DICT = "dict"
|
||||
|
||||
|
||||
class TesseractError(RuntimeError):
|
||||
def __init__(self, status, message):
|
||||
self.status = status
|
||||
self.message = message
|
||||
self.args = (status, message)
|
||||
|
||||
|
||||
class TesseractNotFoundError(EnvironmentError):
|
||||
def __init__(self):
|
||||
super(TesseractNotFoundError, self).__init__(
|
||||
tesseract_cmd + " is not installed or it's not in your path"
|
||||
)
|
||||
|
||||
|
||||
class TSVNotSupported(EnvironmentError):
|
||||
def __init__(self):
|
||||
super(TSVNotSupported, self).__init__(
|
||||
'TSV output not supported. Tesseract >= 3.05 required'
|
||||
)
|
||||
|
||||
|
||||
def run_once(func):
|
||||
def wrapper(*args, **kwargs):
|
||||
if wrapper._result is wrapper:
|
||||
wrapper._result = func(*args, **kwargs)
|
||||
return wrapper._result
|
||||
|
||||
wrapper._result = wrapper
|
||||
return wrapper
|
||||
|
||||
|
||||
def get_errors(error_string):
|
||||
return u' '.join(
|
||||
line for line in error_string.decode('utf-8').splitlines()
|
||||
).strip()
|
||||
|
||||
|
||||
def cleanup(temp_name):
|
||||
''' Tries to remove files by filename wildcard path. '''
|
||||
for filename in iglob(temp_name + '*' if temp_name else temp_name):
|
||||
try:
|
||||
os.remove(filename)
|
||||
except OSError:
|
||||
pass
|
||||
|
||||
|
||||
def prepare(image):
|
||||
if isinstance(image, Image.Image):
|
||||
return image
|
||||
|
||||
if numpy_installed and isinstance(image, ndarray):
|
||||
return Image.fromarray(image)
|
||||
|
||||
raise TypeError('Unsupported image object')
|
||||
|
||||
|
||||
def save_image(image):
|
||||
temp_name = tempfile.mktemp(prefix='tess_')
|
||||
if isinstance(image, str):
|
||||
return temp_name, realpath(normpath(normcase(image)))
|
||||
|
||||
image = prepare(image)
|
||||
img_extension = image.format
|
||||
if image.format not in {'JPEG', 'PNG', 'TIFF', 'BMP', 'GIF'}:
|
||||
img_extension = 'PNG'
|
||||
|
||||
if not image.mode.startswith(RGB_MODE):
|
||||
image = image.convert(RGB_MODE)
|
||||
|
||||
if 'A' in image.getbands():
|
||||
# discard and replace the alpha channel with white background
|
||||
background = Image.new(RGB_MODE, image.size, (255, 255, 255))
|
||||
background.paste(image, (0, 0), image)
|
||||
image = background
|
||||
|
||||
input_file_name = temp_name + os.extsep + img_extension
|
||||
image.save(input_file_name, format=img_extension, **image.info)
|
||||
return temp_name, input_file_name
|
||||
|
||||
|
||||
def subprocess_args(include_stdout=True):
|
||||
# The following is true only on Windows.
|
||||
if hasattr(subprocess, 'STARTUPINFO'):
|
||||
# On Windows, subprocess calls will pop up a command window by default
|
||||
# when run from Pyinstaller with the ``--noconsole`` option. Avoid this
|
||||
# distraction.
|
||||
si = subprocess.STARTUPINFO()
|
||||
si.dwFlags |= subprocess.STARTF_USESHOWWINDOW
|
||||
# Windows doesn't search the path by default. Pass it an environment so
|
||||
# it will.
|
||||
env = os.environ
|
||||
else:
|
||||
si = None
|
||||
env = None
|
||||
|
||||
# ``subprocess.check_output`` doesn't allow specifying ``stdout``::
|
||||
#
|
||||
# Traceback (most recent call last):
|
||||
# File "test_subprocess.py", line 58, in <module>
|
||||
# **subprocess_args(stdout=None))
|
||||
# File "C:\Python27\lib\subprocess.py", line 567, in check_output
|
||||
# raise ValueError('stdout argument not allowed, it will be overridden.')
|
||||
# ValueError: stdout argument not allowed, it will be overridden.
|
||||
#
|
||||
# So, add it only if it's needed.
|
||||
if include_stdout:
|
||||
ret = {'stdout': subprocess.PIPE}
|
||||
else:
|
||||
ret = {}
|
||||
|
||||
# On Windows, running this from the binary produced by Pyinstaller
|
||||
# with the ``--noconsole`` option requires redirecting everything
|
||||
# (stdin, stdout, stderr) to avoid an OSError exception
|
||||
# "[Error 6] the handle is invalid."
|
||||
ret.update({'stdin': subprocess.PIPE,
|
||||
'stderr': subprocess.PIPE,
|
||||
'startupinfo': si,
|
||||
'env': env
|
||||
})
|
||||
return ret
|
||||
|
||||
return kwargs
|
||||
|
||||
|
||||
def run_tesseract(input_filename,
|
||||
output_filename_base,
|
||||
extension,
|
||||
lang,
|
||||
config='',
|
||||
nice=0):
|
||||
cmd_args = []
|
||||
|
||||
if not sys.platform.startswith('win32') and nice != 0:
|
||||
cmd_args += ('nice', '-n', str(nice))
|
||||
|
||||
cmd_args += (tesseract_cmd, input_filename, output_filename_base)
|
||||
|
||||
if lang is not None:
|
||||
cmd_args += ('-l', lang)
|
||||
|
||||
cmd_args += shlex.split(config)
|
||||
|
||||
if extension not in ('box', 'osd', 'tsv'):
|
||||
cmd_args.append(extension)
|
||||
|
||||
try:
|
||||
proc = subprocess.Popen(cmd_args, **subprocess_args())
|
||||
except OSError:
|
||||
raise TesseractNotFoundError()
|
||||
|
||||
status_code, error_string = proc.wait(), proc.stderr.read()
|
||||
proc.stderr.close()
|
||||
|
||||
if status_code:
|
||||
raise TesseractError(status_code, get_errors(error_string))
|
||||
|
||||
return True
|
||||
|
||||
|
||||
def run_and_get_output(image,
|
||||
extension,
|
||||
lang=None,
|
||||
config='',
|
||||
nice=0,
|
||||
return_bytes=False):
|
||||
|
||||
temp_name, input_filename = '', ''
|
||||
try:
|
||||
temp_name, input_filename = save_image(image)
|
||||
kwargs = {
|
||||
'input_filename': input_filename,
|
||||
'output_filename_base': temp_name + '_out',
|
||||
'extension': extension,
|
||||
'lang': lang,
|
||||
'config': config,
|
||||
'nice': nice
|
||||
}
|
||||
|
||||
run_tesseract(**kwargs)
|
||||
filename = kwargs['output_filename_base'] + os.extsep + extension
|
||||
with open(filename, 'rb') as output_file:
|
||||
if return_bytes:
|
||||
return output_file.read()
|
||||
return output_file.read().decode('utf-8').strip()
|
||||
finally:
|
||||
cleanup(temp_name)
|
||||
|
||||
|
||||
def file_to_dict(tsv, cell_delimiter, str_col_idx):
|
||||
result = {}
|
||||
rows = [row.split(cell_delimiter) for row in tsv.split('\n')]
|
||||
if not rows:
|
||||
return result
|
||||
|
||||
header = rows.pop(0)
|
||||
if len(rows[-1]) < len(header):
|
||||
# Fixes bug that occurs when last text string in TSV is null, and
|
||||
# last row is missing a final cell in TSV file
|
||||
rows[-1].append('')
|
||||
|
||||
if str_col_idx < 0:
|
||||
str_col_idx += len(header)
|
||||
|
||||
for i, head in enumerate(header):
|
||||
result[head] = [
|
||||
int(row[i]) if i != str_col_idx else row[i] for row in rows
|
||||
]
|
||||
|
||||
return result
|
||||
|
||||
|
||||
def is_valid(val, _type):
|
||||
if _type is int:
|
||||
return val.isdigit()
|
||||
|
||||
if _type is float:
|
||||
try:
|
||||
float(val)
|
||||
return True
|
||||
except ValueError:
|
||||
return False
|
||||
|
||||
return True
|
||||
|
||||
|
||||
def osd_to_dict(osd):
|
||||
return {
|
||||
OSD_KEYS[kv[0]][0]: OSD_KEYS[kv[0]][1](kv[1]) for kv in (
|
||||
line.split(': ') for line in osd.split('\n')
|
||||
) if len(kv) == 2 and is_valid(kv[1], OSD_KEYS[kv[0]][1])
|
||||
}
|
||||
|
||||
|
||||
@run_once
|
||||
def get_tesseract_version():
|
||||
'''
|
||||
Returns LooseVersion object of the Tesseract version
|
||||
'''
|
||||
try:
|
||||
return LooseVersion(
|
||||
subprocess.check_output([tesseract_cmd, '--version'],
|
||||
**subprocess_args(False)).decode('utf-8').split()[1].lstrip(string.printable[10:])
|
||||
)
|
||||
except OSError:
|
||||
raise TesseractNotFoundError()
|
||||
|
||||
|
||||
def image_to_string(image,
|
||||
lang=None,
|
||||
config='',
|
||||
nice=0,
|
||||
boxes=False,
|
||||
output_type=Output.STRING):
|
||||
'''
|
||||
Returns the result of a Tesseract OCR run on the provided image to string
|
||||
'''
|
||||
if boxes:
|
||||
# Added for backwards compatibility
|
||||
print('\nWarning: Argument \'boxes\' is deprecated and will be removed'
|
||||
' in future versions. Use function image_to_boxes instead.\n')
|
||||
return image_to_boxes(image, lang, config, nice, output_type)
|
||||
|
||||
args = [image, 'txt', lang, config, nice]
|
||||
|
||||
if output_type == Output.DICT:
|
||||
return {'text': run_and_get_output(*args)}
|
||||
elif output_type == Output.BYTES:
|
||||
args.append(True)
|
||||
|
||||
return run_and_get_output(*args)
|
||||
|
||||
|
||||
def image_to_boxes(image,
|
||||
lang=None,
|
||||
config='',
|
||||
nice=0,
|
||||
output_type=Output.STRING):
|
||||
'''
|
||||
Returns string containing recognized characters and their box boundaries
|
||||
'''
|
||||
config += ' batch.nochop makebox'
|
||||
args = [image, 'box', lang, config, nice]
|
||||
|
||||
if output_type == Output.DICT:
|
||||
box_header = 'char left bottom right top page\n'
|
||||
return file_to_dict(box_header + run_and_get_output(*args), ' ', 0)
|
||||
elif output_type == Output.BYTES:
|
||||
args.append(True)
|
||||
|
||||
return run_and_get_output(*args)
|
||||
|
||||
|
||||
def image_to_data(image,
|
||||
lang=None,
|
||||
config='',
|
||||
nice=0,
|
||||
output_type=Output.STRING):
|
||||
'''
|
||||
Returns string containing box boundaries, confidences,
|
||||
and other information. Requires Tesseract 3.05+
|
||||
'''
|
||||
|
||||
if get_tesseract_version() < '3.05':
|
||||
raise TSVNotSupported()
|
||||
|
||||
config = '{} {}'.format('-c tessedit_create_tsv=1', config.strip()).strip()
|
||||
args = [image, 'tsv', lang, config, nice]
|
||||
|
||||
if output_type == Output.DICT:
|
||||
return file_to_dict(run_and_get_output(*args), '\t', -1)
|
||||
elif output_type == Output.BYTES:
|
||||
args.append(True)
|
||||
|
||||
return run_and_get_output(*args)
|
||||
|
||||
|
||||
def image_to_osd(image,
|
||||
lang='osd',
|
||||
config='',
|
||||
nice=0,
|
||||
output_type=Output.STRING):
|
||||
'''
|
||||
Returns string containing the orientation and script detection (OSD)
|
||||
'''
|
||||
config = '{}-psm 0 {}'.format(
|
||||
'' if get_tesseract_version() < '3.05' else '-',
|
||||
config.strip()
|
||||
).strip()
|
||||
args = [image, 'osd', lang, config, nice]
|
||||
|
||||
if output_type == Output.DICT:
|
||||
return osd_to_dict(run_and_get_output(*args))
|
||||
elif output_type == Output.BYTES:
|
||||
args.append(True)
|
||||
|
||||
return run_and_get_output(*args)
|
||||
|
||||
|
||||
def main():
|
||||
if len(sys.argv) == 2:
|
||||
filename, lang = sys.argv[1], None
|
||||
elif len(sys.argv) == 4 and sys.argv[1] == '-l':
|
||||
filename, lang = sys.argv[3], sys.argv[2]
|
||||
else:
|
||||
sys.stderr.write('Usage: python pytesseract.py [-l lang] input_file\n')
|
||||
exit(2)
|
||||
|
||||
try:
|
||||
print(image_to_string(Image.open(filename), lang=lang))
|
||||
except IOError:
|
||||
sys.stderr.write('ERROR: Could not open file "%s"\n' % filename)
|
||||
exit(1)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
Loading…
Reference in New Issue
Block a user