This commit is contained in:
Adrien Bourmault 2019-06-30 17:54:41 +02:00
parent b3587b770c
commit 6c25739051
6 changed files with 1511 additions and 1948 deletions

View File

@ -10,41 +10,38 @@
********************************************************************************
"""
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"
class changelog:
def __init__(self):
self.isOn = False
self.text = "Mise-à-jour de sécurité avec corrections suivantes :\n- ajout de la signature numérique de l'exécutable\n- ajout d'une clé de cryptage plus performante pour le stockage des identifiants\n- passage à la méthode de cryptage AES256\n\nAjout/correction des fonctionnalités suivantes :\n- somme de contrôle des téléchargements pour une meilleure fiabilité\n- amélioration de présentation du log en cas d'erreur\n- correction d'un bug affectant l'analyse des MRZ après la correction manuelle\n\nEt un petit bonjour à tout le monde! ;)"
import base64
import hashlib
CST_REV = '0'
CST_VERTITLE = '2.2'
CST_TAB_VER = ['2', '2', '5']
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 = 'http://neoxgroup.eu/ftpaccess/Applicatifs/CNIRevelator/'
CST_COLOR = '#003380'
CST_TesserHash = '5b58db27f7bc08c58a2cb33d01533b034b067cf8'
import base64, 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 tkinter import ttk
import os, time, threading, sys, urllib.request as urllib2, urllib.error as URLExcept, random
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/"
CST_FOLDER = os.getenv('APPDATA') + '/CNIRevelator/'
CST_CRYPTOKEY = '82Xh!efX3#@P~2eG'
CST_CHANGELOG = changelog()

View File

@ -10,122 +10,97 @@
********************************************************************************
"""
###IMPORTS GLOBAUX
from CNI_GLOBALVAR import *
##LOGGING
from CNI_GLOBALVAR import *
try:
os.remove("error.log")
os.remove("conf.ig")
os.remove('error.log')
os.remove('conf.ig')
except:
print("pass log deletion")
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
if not os.path.exists(CST_FOLDER):
try:
os.environ["PATH"] = CST_FOLDER + "Tesseract-OCR4\\"
os.environ["TESSDATA_PREFIX"] = CST_FOLDER + "Tesseract-OCR4\\tessdata"
tesser_version = pytesseract.get_tesseract_version()
os.makedirs(CST_FOLDER)
except IOError:
print("pass IO ERROR")
pass
import logging
from logging import FileHandler
logger = logging.getLogger()
logger.setLevel(logging.INFO)
formatter = logging.Formatter('%(asctime)s :: %(levelname)s :: %(message)s')
error_handler = FileHandler((CST_FOLDER + '\\error.log'), mode='w', encoding='utf-8', delay=True)
info_handler = FileHandler((CST_FOLDER + '\\cnirevelator.log'), mode='w', encoding='utf-8')
error_handler.setLevel(logging.ERROR)
logger.addHandler(error_handler)
info_handler.setLevel(logging.DEBUG)
info_handler.setFormatter(formatter)
logger.addHandler(info_handler)
from CNI_classes import *
from CNI_Update import *
def main(logger):
logger.error('')
logger.info('main() : **** Creating App_main() ****')
main_w = App_main(logger)
main_w.montext('* ' + CST_NAME + ' ' + CST_VER + ' ' + CST_TYPE + ' Revision ' + CST_REV + ' *\n')
import CNI_pytesseract as pytesseract
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')
if CST_CHANGELOG.isOn:
showinfo('Changelog : résumé de mise à jour', ('Version du logiciel : ' + CST_VER + ' ' + CST_TYPE + ' Revision ' + CST_REV + '\n\n' + CST_CHANGELOG.text), parent=main_w)
logger.info('main() : **** Launching App_main() ****')
main_w.mainloop()
logger.info('main() : **** Ending App_main() ****')
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.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)
logger.info('launcher : *****FATAL ERROR*****' + str(e))
os.abort()
sys.exit(0)
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)
try:
with open(CST_FOLDER + '\\error.log') as (echo):
try:
os.remove('error.log')
except OSError:
pass
from shutil import copyfile
temptwo = str(echo.read())
if len(temptwo) != 1:
copyfile(CST_FOLDER + '\\cnirevelator.log', 'error.log')
except IOError:
pass
print("exit")
#sys.exit(0)

View File

@ -10,559 +10,484 @@
********************************************************************************
"""
###IMPORTS GLOBAUX
from CNI_GLOBALVAR import *
###IMPORTS LOCAUX
from CNI_GLOBALVAR import *
from CNI_classes import *
import hashlib
from pypac import PACSession
from requests.auth import HTTPProxyAuth
import subprocess
###BEGIN
def SoftUpdate(logger): #Fonction de mise à jour de l'application
def SoftUpdate(logger):
global ret
global upwin
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...")
for f in os.listdir(CST_FOLDER):
if f[-4:] == '.tif':
try:
os.remove(CST_FOLDER + '\\' + f)
except PermissionError as e:
logger.info('SoftUpdate() : Failing to purge : ' + str(e))
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(".")
if file.startswith('CNIRevelator_'):
temp = ['0', '0', '0']
ver = file[13:].split('.')
for i in range(len(ver)):
if ver[i] != "exe" :
if ver[i] != 'exe':
try:
temp[i] = ver[i]
except:
None
pass
ver = temp.copy()
try :
sum_ver = int(ver[0])*100 + int(ver[1])*10 + int(ver[2])
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 !")
if file[-3:] == 'exe':
os.remove(file)
logger.info('SoftUpdate() : Removed old version : ' + str(file))
CST_CHANGELOG.isOn = True
except Exception as e:
logger.error('SoftUpdate() : Failing to remove old version ' + str(file) + ' : ' + str(e))
def updating():
def updator():
global ret
logger.info('[updator() thread] : Welcome !')
ret = 11
canvas.itemconfigure(message, text="Recherche de mises-à-jour...")
p.configure(mode = "indeterminate", value = 0, maximum = 20)
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
logger.info('[updator() thread] : Looking for updates...')
try:
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))
global key
global login
try:
logger.info('[download() thread] : Trying getting credentials in the config file')
with open(CST_FOLDER + 'conf.ig', 'rb') as (config):
AESObj = AESCipher(CST_CRYPTOKEY)
try:
tempone = AESObj.decrypt(config.read())
if tempone != '||':
if tempone.find('||') != -1:
IPN, IPN_PASS = tempone.split('||')[0:2]
else:
raise ValueError('Cryptokey is bad !')
else:
IPN = ''
IPN_PASS = ''
except Exception as e:
raise IOError(str(e))
else:
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:
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
class LoginDialog(Toplevel):
def __init__(self, parent):
super().__init__(parent)
self.title("Connexion")
# ---------------------------------------
Label(self, text="IPN : ").pack()
self.title('Connexion')
Label(self, text='IPN : ').pack()
self.entry_login = Entry(self)
self.entry_login.insert(0, "")
self.entry_login.insert(0, '')
self.entry_login.pack()
# ---------------------------------------
Label(self, text="Mot de passe : ").pack()
Label(self, text='Mot de passe : ').pack()
self.entry_pass = Entry(self, show='*')
self.entry_pass.insert(0, "")
self.entry_pass.insert(0, '')
self.entry_pass.pack()
# ---------------------------------------
Button(self, text="Connexion", command=self.connecti).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()
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")
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.iconbitmap('id-card.ico')
upwin.update()
x = ws / 2 - w / 2
y = hs / 2 - h / 2
self.geometry('%dx%d+%d+%d' % (w, h, x, y))
def connecti(self):
global login
global key
global login
login = self.entry_login.get().strip()
key = self.entry_pass.get().strip()
self.destroy()
session = PACSession()
if session.get_pac() == None:
IPN = ""
IPN_PASS = ""
IPN = ''
IPN_PASS = ''
NoConnect = False
break
canvas.itemconfigure(message, text="En attente de connexion au serveur proxy...")
global login
global key
login = ""
key = ""
canvas.itemconfigure(message, text='En attente de connexion au serveur proxy...')
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")
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 !")
if str(Ans) == '<Response [200]>':
logger.info('[download() thread] : Connection ok !')
NoConnect = False
else:
raise IOError()
AESObj = AESCipher(CST_CRYPTOKEY)
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 !')
else:
if IPN == 'i020251':
canvas.itemconfigure(message, text='Bienvenue Samia !')
else:
if IPN == 'i018410':
canvas.itemconfigure(message, text='Bienvenue Adrien !')
else:
if IPN == 'i003067':
canvas.itemconfigure(message, text='Bienvenue Remy !')
else:
if 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 } )
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 )
server = urllib2.build_opener(ph, auth, urllib2.HTTPHandler)
urllib2.install_opener(server)
logger.info("[download() thread] : " + "Proxy connection initiated successfully")
logger.info('[download() thread] : Proxy connection initiated successfully')
except:
logger.info("[download() thread] : " + "Proxy connection not initiated")
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 " )
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)
logger.info('[updator() thread] : Prepare downloading the version recap file...')
tempfile = CST_FOLDER + 'temp' + str(random.randint(11111, 99999)) + '.cniu'
isOk = download(CST_LINK + 'cnir.ver', tempfile)
if not isOk:
raise(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...")
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("|")
logger.info('[updator() thread] : Closing version recap file...')
repert = version.split('|')
file_ver.close()
logger.info("[updator() thread] : " + "Deleting version recap file...")
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))
logger.info('[updator() thread] : Parsing informations about version...')
final_f = 'CNI_file'
final_ver = ['0', '0', '0']
final_hash = ''
for sentence in repert:
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:
file, hashref = sentence.split(':')
except ValueError:
pass
else:
if str.startswith(file, CST_NAME):
ver = file.replace(CST_NAME + '_', '').split('.')
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
final_hash = hashref
sum_ver = int(final_ver[0]) * 100 + int(final_ver[1]) * 10 + int(final_ver[2])
if final_f != 'CNI_file':
if sum_ver > CST_SUM_VER:
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(CST_CRYPTOKEY)
IPN, IPN_PASS = AESObj.decrypt(config.read()).split('||')[0:2]
session = PACSession(proxy_auth=(HTTPProxyAuth(IPN, IPN_PASS)))
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)
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)
BLOCKSIZE = 65536
hasher = hashlib.sha1()
try:
with open(final_f, 'rb') as (afile):
buf = afile.read(BLOCKSIZE)
while len(buf) > 0:
hasher.update(buf)
buf = afile.read(BLOCKSIZE)
hashcod = hasher.hexdigest()
if hashcod != final_hash:
Statut.success = False
logger.error('[updator() thread] : Hashcode Error :' + final_f)
try:
os.remove(final_f)
except IOError:
pass
else:
logger.info('[updator() thread] : Hashcode pass :' + final_f)
except FileNotFoundError as e:
logger.error('[updator() thread] : File not found ' + final_f)
if Statut.success:
try:
os.rename(final_f, final_f + ".exe")
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")
logger.error('[updator() thread] : Unable to rename the file ! 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 !")
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', parent=upwin)
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)
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"
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))
final_f = 'tesseract_4'
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(CST_CRYPTOKEY)
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 } )
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 !")
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 )
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)
hashcod = ''
logger.info('[updator() thread] : Verifying hashcode of ' + final_f)
BLOCKSIZE = 65536
hasher = hashlib.sha1()
try:
with open(CST_FOLDER + final_f, 'rb') as (afile):
buf = afile.read(BLOCKSIZE)
while len(buf) > 0:
hasher.update(buf)
buf = afile.read(BLOCKSIZE)
hashcod = hasher.hexdigest()
if hashcod != CST_TesserHash:
Statut.success = False
logger.error('[updator() thread] : Hashcode Error : ' + final_f)
try:
os.remove(CST_FOLDER + final_f)
except IOError:
pass
else:
logger.info('[updator() thread] : Hashcode pass : ' + final_f)
except FileNotFoundError as e:
logger.error('[updator() thread] : File not found ' + final_f)
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)
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 !")
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")
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 !")
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))
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 != "":
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...")
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"
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")
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")
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) )
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)
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)
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
logger.info('updating() : Launching updator() thread...')
threading.Thread(target=updator, daemon=True).start()
logger.info('updating() [Thread] : Ending updator() thread')
ret = 11
global upwin
root = Tk()
root.attributes('-alpha', 0.0) #For icon
#root.lower()
root.attributes('-alpha', 0.0)
root.iconify()
upwin = Toplevel(root)
upwin.overrideredirect(1)
upwin.configure(bg = CST_COLOR)
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()
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
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.15), text=' ', font='Calibri 9', fill='white')
upwin.update()
x = ws / 2 - w / 2
y = hs / 2 - h / 2
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")
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())
root.iconbitmap('id-card.ico')
logger.info('SoftUpdate() : Entering upwin mainloop()')
upwin.protocol('WM_DELETE_WINDOW', lambda : root.destroy())
upwin.mainloop()
logger.info("SoftUpdate() : " + "Exiting upwin mainloop()")
logger.info('SoftUpdate() : Exiting upwin mainloop()')
if ret == 11:
logger.info("SoftUpdate() : " + "OK to start to main() normally !")
logger.info('SoftUpdate() : OK to start to main() normally !')
return True
else:
logger.info("SoftUpdate() : " + "Program will stop !")
logger.info('SoftUpdate() : Program will stop !')
return False

File diff suppressed because one or more lines are too long

View File

@ -10,52 +10,42 @@
*****
"""
#!/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
import os, sys, subprocess, tempfile, shlex, 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)
}
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"
STRING = 'string'
BYTES = 'bytes'
DICT = 'dict'
class TesseractError(RuntimeError):
def __init__(self, status, message):
self.status = status
self.message = message
@ -63,20 +53,19 @@ class TesseractError(RuntimeError):
class TesseractNotFoundError(EnvironmentError):
def __init__(self):
super(TesseractNotFoundError, self).__init__(
tesseract_cmd + " is not installed or it's not in your path"
)
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'
)
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)
@ -87,13 +76,11 @@ def run_once(func):
def get_errors(error_string):
return u' '.join(
line for line in error_string.decode('utf-8').splitlines()
).strip()
return ' '.join(line for line in error_string.decode('utf-8').splitlines()).strip()
def cleanup(temp_name):
''' Tries to remove files by filename wildcard path. '''
""" Tries to remove files by filename wildcard path. """
for filename in iglob(temp_name + '*' if temp_name else temp_name):
try:
os.remove(filename)
@ -104,138 +91,88 @@ def cleanup(temp_name):
def prepare(image):
if isinstance(image, Image.Image):
return image
if numpy_installed and isinstance(image, ndarray):
if numpy_installed:
if isinstance(image, ndarray):
pass
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
return (temp_name, realpath(normpath(normcase(image))))
else:
image = prepare(image)
img_extension = image.format
if image.format not in frozenset({'BMP', 'JPEG', 'GIF', 'TIFF', 'PNG'}):
img_extension = 'PNG'
if not image.mode.startswith(RGB_MODE):
image = image.convert(RGB_MODE)
if 'A' in image.getbands():
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
})
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):
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))
if not sys.platform.startswith('win32'):
if 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())
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 = '', ''
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
}
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:
with open(filename, 'rb') as (output_file):
if return_bytes:
return output_file.read()
return output_file.read().decode('utf-8').strip()
@ -248,166 +185,127 @@ def file_to_dict(tsv, cell_delimiter, str_col_idx):
rows = [row.split(cell_delimiter) for row in tsv.split('\n')]
if not rows:
return result
else:
header = rows.pop(0)
if len(rows[(-1)]) < len(header):
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]
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
return result
def is_valid(val, _type):
if _type is int:
return val.isdigit()
if _type is float:
else:
if _type is float:
pass
try:
float(val)
return True
except ValueError:
return False
return True
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])
}
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 if 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:])
)
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):
'''
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')
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)
else:
args = [
image, 'txt', lang, config, nice]
if output_type == Output.DICT:
return {'text': run_and_get_output(*args)}
if 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):
'''
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)
else:
if 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):
'''
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)
else:
if 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):
'''
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]
"""
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)
else:
if 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)
if len(sys.argv) == 4:
if sys.argv[1] == '-l':
filename, lang = sys.argv[3], sys.argv[2]
sys.stderr.write('Usage: python pytesseract.py [-l lang] input_file\n')
exit(2)
try:
print(image_to_string(Image.open(filename), lang=lang))
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()
main()

BIN
id-card.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB