Big reorganization of the sources

This commit is contained in:
Adrien Bourmault 2019-07-09 16:13:16 +02:00 committed by GitHub
parent a0692aa5ba
commit 2e93361728
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 2424 additions and 0 deletions

110
CNIRevelator.py Normal file
View File

@ -0,0 +1,110 @@
"""
********************************************************************************
* CNIRevelator *
* *
* Desc: Application launcher & updater *
* *
* Copyright © 2018-2019 Adrien Bourmault (neox95) *
* *
* This file is part of CNIRevelator. *
* *
* CNIRevelator is free software: you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation, either version 3 of the License, or *
* any later version. *
* *
* CNIRevelator is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY*without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with CNIRevelator. If not, see <https:*www.gnu.org/licenses/>. *
********************************************************************************
"""
from CNI_GLOBALVAR import *
try:
os.remove('error.log')
os.remove('conf.ig')
except:
print("pass log deletion")
pass
if not os.path.exists(CST_FOLDER):
try:
os.makedirs(CST_FOLDER)
except IOError:
print("pass IO ERROR")
pass
print("debug")
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()*****')
logger.info('launcher : *****Launching main()*****')
State = main(logger)
logger.info('launcher : *****Ending main()*****')
logger.info('launcher : *****Goodbye!*****')
handlers = logger.handlers[:]
for handler in handlers:
handler.close()
logger.removeHandler(handler)
try:
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)

1332
CNI_classes.py Normal file

File diff suppressed because it is too large Load Diff

207
downloader.py Normal file
View File

@ -0,0 +1,207 @@
"""
********************************************************************************
* CNIRevelator *
* *
* Desc: Application launcher download stuff *
* *
* Copyright © 2018-2019 Adrien Bourmault (neox95) *
* *
* This file is part of CNIRevelator. *
* *
* CNIRevelator is free software: you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation, either version 3 of the License, or *
* any later version. *
* *
* CNIRevelator is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY*without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with CNIRevelator. If not, see <https:*www.gnu.org/licenses/>. *
********************************************************************************
"""
import hashlib
import base64, hashlib
import os
from pypac import PACSession
from requests.auth import HTTPProxyAuth
from Crypto import Random
from Crypto.Cipher import AES
from requests import Session
from time import time
import logger # logger.py
import globs # globs.py
import ihm # ihm.py
class AESCipher(object):
def __init__(self, key):
self.bs = 32
self.key = hashlib.sha256(key.encode()).digest()
def encrypt(self, raw):
raw = self._pad(raw)
iv = Random.new().read(AES.block_size)
cipher = AES.new(self.key, AES.MODE_CBC, iv)
return base64.b64encode(iv + cipher.encrypt(raw))
def decrypt(self, enc):
enc = base64.b64decode(enc)
iv = enc[:AES.block_size]
cipher = AES.new(self.key, AES.MODE_CBC, iv)
return self._unpad(cipher.decrypt(enc[AES.block_size:])).decode('utf-8')
def _pad(self, s):
return s + (self.bs - len(s) % self.bs) * chr(self.bs - len(s) % self.bs)
@staticmethod
def _unpad(s):
return s[:-ord(s[len(s) - 1:])]
class newcredentials:
def __init__(self):
logfile = logger.logCur
self.login = ''
self.password = ''
self.valid = False
self.readInTheBooks = False
self.trying = 0
while True:
session = PACSession(proxy_auth=(HTTPProxyAuth(self.login, self.password)))
self.trying += 1
try:
sessionAnswer = session.get('https://www.google.com')
except Exception as e:
logfile.printerr('Network Error : ' + str(e))
sessionAnswer = ''
logfile.printdbg("Session Answer : " + str(sessionAnswer))
if str(sessionAnswer) == '<Response [200]>':
logfile.printdbg('Successfully connected to the Internet !')
self.sessionHandler = session
self.valid = True
return
if str(sessionAnswer) != '<Response [407]>' and self.trying > 2:
# because sometimes the proxy does not return an error (especially if we do not provide either credentials)
logfile.printerr('Network Error, or need a proxy !')
return
if self.trying > 4:
logfile.printerr('Invalid credentials : access denied, a maximum of 3 trials have been raised !')
return
logfile.printdbg('Invalid credentials : access denied')
# Deleting the root of Evil if needed
if self.readInTheBooks:
os.remove(globs.CNIRConfig)
logfile.printdbg("Deleting the root of Evil")
try:
with open(globs.CNIRConfig, 'rb') as (configFile):
self.readInTheBooks = True
# Decrypt the config file
AESObj = AESCipher(globs.CNIRCryptoKey)
try:
# Reading it
reading = AESObj.decrypt(configFile.read())
# Parsing it
if reading != '||':
if reading.find('||') != -1:
# TADAAA
self.login, self.password = reading.split('||')[0:2]
else:
# UPS
logfile.printerr('Cryptokey is bad !')
return
except Exception as e:
raise IOError(str(e))
except FileNotFoundError:
logfile.printdbg('We will ask for credentials then')
launcherWindow = ihm.launcherWindowCur
# Parameters for the password invite
invite = ihm.LoginDialog(launcherWindow)
invite.transient(launcherWindow)
invite.grab_set()
launcherWindow.wait_window(invite)
# Getting the credentials
self.login = invite.login
self.password = invite.key
AESObj = AESCipher(globs.CNIRCryptoKey)
with open(globs.CNIRConfig, 'wb+') as (configFile):
logfile.printdbg('Saving credentials in encrypted config file')
configFile.write(AESObj.encrypt(self.login + '||' + self.password))
return
class newdownload:
def __init__(self, credentials, urlFile, destinationFile):
self.urlFile = urlFile
self.destinationFile = destinationFile
self.session = credentials.sessionHandler
logfile = logger.logCur
launcherWindow = ihm.launcherWindowCur
logfile.printdbg('Requesting download of {}'.format(self.urlFile))
self.handler = self.session.get(self.urlFile, stream=True, headers={'Connection' : 'close', "Cache-Control": "no-cache", "Pragma": "no-cache"})
self.handler.raise_for_status()
self.filesize = int(self.handler.headers['Content-length'])
self.chunksize = int(self.filesize / 7)
self.count = 0
def download(self):
logfile = logger.logCur
launcherWindow = ihm.launcherWindowCur
url = self.urlFile
filename = self.destinationFile
reducedFilename = filename.split("\\")[-1]
launcherWindow.mainCanvas.itemconfigure(launcherWindow.msg, text=('Downloading {}'.format(reducedFilename)))
launcherWindow.progressBar.stop()
launcherWindow.progressBar.configure(mode='determinate', value=0, maximum=100)
try:
os.remove(filename)
except:
pass
with open(filename, 'wb') as fh:
for chunk in self.handler.iter_content(chunk_size=self.chunksize):
fh.write(chunk)
self.count = os.path.getsize(self.destinationFile)
Percent = int(self.count / self.filesize * 100)
launcherWindow.progressBar.configure(mode='determinate', value=(int(Percent)))
launcherWindow.mainCanvas.itemconfigure(launcherWindow.msg, text=('Downloading {}'.format(reducedFilename) + ' : ' + str((Percent)) + ' %'))
launcherWindow.progressBar.configure(mode='indeterminate', value=0, maximum=20)
launcherWindow.progressBar.start()
logfile.printdbg('Successful retrieved {}'.format(filename))
return filename

44
globs.py Normal file
View File

@ -0,0 +1,44 @@
"""
********************************************************************************
* CNIRevelator *
* *
* Desc: Application launcher global variables *
* *
* Copyright © 2018-2019 Adrien Bourmault (neox95) *
* *
* This file is part of CNIRevelator. *
* *
* CNIRevelator is free software: you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation, either version 3 of the License, or *
* any later version. *
* *
* CNIRevelator is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY*without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with CNIRevelator. If not, see <https:*www.gnu.org/licenses/>. *
********************************************************************************
"""
import os
# CNIRevelator version
version = [3, 0, 0]
verstring_full = "{}.{}.{}".format(version[0], version[1], version[2])
verstring = "{}.{}".format(version[0], version[1])
changelog = "Mise-à-jour majeure avec corrections suivantes :\n- Renouvellement de la signature numérique de l'exécutable\n- Amélioration de présentation du log en cas d'erreur\n- Refonte totale du code source et désobfuscation\n- Téléchargements en HTTPS fiables avec somme de contrôle"
CNIRTesserHash = '5b58db27f7bc08c58a2cb33d01533b034b067cf8'
CNIRFolder = os.getcwd()
CNIRLColor = "#006699"
CNIRName = "CNIRevelator {}".format(verstring)
CNIRCryptoKey = '82Xh!efX3#@P~2eG'
CNIRConfig = CNIRFolder + '\\conf.ig'
CNIRErrLog = CNIRFolder + '\\error.log'
CNIRLauncherLog = CNIRFolder + '\\launcher.log'
CNIRUrlConfig = CNIRFolder + '\\urlconf.ig'
CNIREnv = os.getenv('APPDATA') + '/CNIRevelator/'

116
ihm.py Normal file
View File

@ -0,0 +1,116 @@
"""
********************************************************************************
* CNIRevelator *
* *
* Desc: Application launcher graphical interface *
* *
* Copyright © 2018-2019 Adrien Bourmault (neox95) *
* *
* This file is part of CNIRevelator. *
* *
* CNIRevelator is free software: you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation, either version 3 of the License, or *
* any later version. *
* *
* CNIRevelator is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY*without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with CNIRevelator. If not, see <https:*www.gnu.org/licenses/>. *
********************************************************************************
"""
from tkinter import *
from tkinter.messagebox import *
from tkinter import filedialog
from tkinter import ttk
import logger # logger.py
import globs # globs.py
class LoginDialog(Toplevel):
def __init__(self, parent):
self.key = ''
self.login = ''
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)
ws = self.winfo_screenwidth()
hs = self.winfo_screenheight()
w = hs / 10
h = ws / 18
self.update()
if getattr(sys, 'frozen', False):
self.iconbitmap(sys._MEIPASS + '\\id-card.ico\\id-card.ico')
else:
self.iconbitmap('id-card.ico')
x = ws / 2 - w / 2
y = hs / 2 - h / 2
self.geometry('%dx%d+%d+%d' % (w, h, x, y))
def connecti(self):
self.login = self.entry_login.get().strip()
self.key = self.entry_pass.get().strip()
self.destroy()
class LauncherWindow(Tk):
def __init__(self):
# Initialize the tkinter main class
Tk.__init__(self)
self.configure(bg=globs.CNIRLColor)
self.resizable(width=False, height=False)
self.queue = []
# Setting up the geometry
ws = self.winfo_screenwidth()
hs = self.winfo_screenheight()
wheight = hs /4
wwidth = ws /4
# Creating objects
self.mainCanvas = Canvas(self, width=wwidth, height=wheight*9/10, bg=globs.CNIRLColor, highlightthickness=0)
self.pBarZone = Canvas(self, width=wwidth, height=wheight/10, bg=globs.CNIRLColor)
self.progressBar = ttk.Progressbar(self.pBarZone, orient=HORIZONTAL, length=wwidth-10, mode='determinate')
self.mainCanvas.create_text((wwidth / 2), (wheight / 3), text=(globs.CNIRName), font='Helvetica 30', fill='white')
self.msg = self.mainCanvas.create_text((wwidth / 2.05), (wheight / 1.20), text='Booting up...', font='Helvetica 9', fill='white')
self.wm_title(globs.CNIRName)
# Centering
x = ws / 2 - wwidth / 2
y = hs / 2 - wheight / 2
self.geometry('%dx%d+%d+%d' % (wwidth, wheight, x, y))
self.mainCanvas.grid()
self.pBarZone.grid()
self.progressBar.grid()
if getattr(sys, 'frozen', False):
self.iconbitmap(sys._MEIPASS + '\\id-card.ico\\id-card.ico')
else:
self.iconbitmap('id-card.ico')
logfile = logger.logCur
logfile.printdbg('Launcher IHM successful')
self.protocol('WM_DELETE_WINDOW', lambda : self.destroy())
self.update()
## Global Handler
launcherWindowCur = LauncherWindow()

69
launcher.py Normal file
View File

@ -0,0 +1,69 @@
"""
********************************************************************************
* CNIRevelator *
* *
* Desc: Application launcher & updater main file *
* *
* Copyright © 2018-2019 Adrien Bourmault (neox95) *
* *
* This file is part of CNIRevelator. *
* *
* CNIRevelator is free software: you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation, either version 3 of the License, or *
* any later version. *
* *
* CNIRevelator is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY*without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with CNIRevelator. If not, see <https:*www.gnu.org/licenses/>. *
********************************************************************************
"""
import sys
import os
import subprocess
import threading
import traceback
import updater # updater.py
import ihm # ihm.py
import globs # globs.py
import logger # logger.py
## Global Handlers
logfile = logger.logCur
launcherWindow = ihm.launcherWindowCur
## Main function
def main():
# Hello world
logfile.printdbg('*** CNIRLauncher LOGFILE. Hello World ! ***')
#logfile.printdbg('Files in directory : ' + str(os.listdir(globs.CNIRFolder)))
# Hello user
launcherWindow.progressBar.configure(mode='indeterminate', value=0, maximum=20)
launcherWindow.mainCanvas.itemconfigure(launcherWindow.msg, text='Starting...')
launcherWindow.progressBar.start()
# Starting the main update thread
mainThread.start()
launcherWindow.mainloop()
logfile.printdbg('*** CNIRLauncher LOGFILE. Goodbye World ! ***')
return
## Bootstrap
try:
mainThread = threading.Thread(target=updater.umain, daemon=False)
main()
except Exception:
logfile.printerr("A FATAL ERROR OCCURED : " + str(traceback.format_exc()))
sys.exit(1)
sys.exit(0)

64
logger.py Normal file
View File

@ -0,0 +1,64 @@
"""
********************************************************************************
* CNIRevelator *
* *
* Desc: Application launcher logging stuff *
* *
* Copyright © 2018-2019 Adrien Bourmault (neox95) *
* *
* This file is part of CNIRevelator. *
* *
* CNIRevelator is free software: you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation, either version 3 of the License, or *
* any later version. *
* *
* CNIRevelator is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY*without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with CNIRevelator. If not, see <https:*www.gnu.org/licenses/>. *
********************************************************************************
"""
import logging
import os
import globs # globs.py
## The logging class
class NewLoggingSystem:
def __init__(self):
# Deleting the error log
try:
os.remove(globs.CNIRErrLog)
except Exception as e:
pass
# Create new logging handle
logger = logging.getLogger()
logger.setLevel(logging.INFO) # To make sure we can have a debug channel
# Create channels
formatter = logging.Formatter("\n[ %(module)s/%(funcName)s ] %(asctime)s :: %(levelname)s :: %(message)s")
error_handler = logging.FileHandler((globs.CNIRErrLog), mode='w', encoding='utf-8', delay=True)
info_handler = logging.FileHandler((globs.CNIRLauncherLog), mode='w', encoding='utf-8')
error_handler.setLevel(logging.ERROR)
error_handler.setFormatter(formatter)
logger.addHandler(error_handler)
info_handler.setLevel(logging.DEBUG)
info_handler.setFormatter(formatter)
logger.addHandler(info_handler)
self.logger = logger
self.printerr = logger.error
self.printdbg = logger.info
## Global Handler
logCur = NewLoggingSystem()

326
pytesseract.py Normal file
View File

@ -0,0 +1,326 @@
"""
********************************************************************************
* CNIRevelator *
* *
* Desc: Pytesseract modification to comply with Pyinstaller *
* *
* Copyright © 2017-2018 Matthias A. Lee (madmaze) *
* Copyright © 2018-2019 Adrien Bourmault (neox95) *
* *
* This file is part of CNIRevelator. *
* *
* CNIRevelator is free software: you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation, either version 3 of the License, or *
* any later version. *
* *
* CNIRevelator is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY*without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with CNIRevelator. If not, see <https:*www.gnu.org/licenses/>. *
********************************************************************************
"""
try:
import Image
except ImportError:
from PIL import Image
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
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 ' '.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:
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))))
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):
if hasattr(subprocess, 'STARTUPINFO'):
si = subprocess.STARTUPINFO()
si.dwFlags |= subprocess.STARTF_USESHOWWINDOW
env = os.environ
else:
si = None
env = None
if include_stdout:
ret = {'stdout': subprocess.PIPE}
else:
ret = {}
ret.update({'stdin':subprocess.PIPE, 'stderr':subprocess.PIPE,
'startupinfo':si,
'env':env})
return ret
def run_tesseract(input_filename, output_filename_base, extension, lang, config='', nice=0):
cmd_args = []
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())
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
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]
return result
def is_valid(val, _type):
if _type is int:
return val.isdigit()
else:
if _type is float:
pass
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 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:]))
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:
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)
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):
"""
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)
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):
"""
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)
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):
"""
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))
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
else:
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))
except IOError:
sys.stderr.write('ERROR: Could not open file "%s"\n' % filename)
exit(1)
if __name__ == '__main__':
main()

154
updater.py Normal file
View File

@ -0,0 +1,154 @@
"""
********************************************************************************
* CNIRevelator *
* *
* Desc: Application launcher updating system *
* *
* Copyright © 2018-2019 Adrien Bourmault (neox95) *
* *
* This file is part of CNIRevelator. *
* *
* CNIRevelator is free software: you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation, either version 3 of the License, or *
* any later version. *
* *
* CNIRevelator is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY*without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with CNIRevelator. If not, see <https:*www.gnu.org/licenses/>. *
********************************************************************************
"""
from win32com.client import Dispatch
import traceback
import sys
import time
import logger # logger.py
import globs # globs.py
import ihm # ihm.py
import downloader # downloader.py
def createShortcut(path, target='', wDir='', icon=''):
ext = path[-3:]
if ext == 'url':
shortcut = file(path, 'w')
shortcut.write('[InternetShortcut]\n')
shortcut.write('URL=%s' % target)
shortcut.close()
else:
shell = Dispatch('WScript.Shell')
shortcut = shell.CreateShortCut(path)
shortcut.Targetpath = target
shortcut.WorkingDirectory = wDir
if icon == '':
pass
else:
shortcut.IconLocation = icon
shortcut.save()
## Main Batch Function
def batch():
# Global Handlers
logfile = logger.logCur
launcherWindow = ihm.launcherWindowCur
credentials = downloader.newcredentials()
if not credentials.valid:
return False
# First retrieving the urls !
while True:
try:
# Open the config file
logfile.printdbg('Reading urlconf.ig')
with open(globs.CNIRUrlConfig, 'r') as (configFile):
try:
# Reading it
reading = configFile.read()
# Parsing it
urlparsed = reading.split("\n")
break
except Exception as e:
raise IOError(str(e))
except FileNotFoundError:
logfile.printdbg('Recreate urlconf.ig')
# Recreating the url file
with open(globs.CNIRUrlConfig, 'w') as (configFile):
configFile.write("https://raw.githubusercontent.com/neox95/CNIRevelator/master/VERSIONS.LST\n0\n0") #XXX
# Getting the list of versions of the software
logfile.printdbg('Retrieving the software versions')
getTheVersions = downloader.newdownload(credentials, urlparsed[0], globs.CNIRFolder + '\\versions.lst').download()
logfile.printdbg('Parsing the software versions')
with open(globs.CNIRFolder + '\\versions.lst') as versionsFile:
versionsTab = versionsFile.read().split("\n")[1].split("||")
logfile.printdbg('Versions retrieved : {}'.format(versionsTab))
# Choose the newer
finalver = globs.version.copy()
for entry in versionsTab:
verstr, url, checksum = entry.split("|")
# Calculating sum considering we can have 99 sub versions
ver = verstr.split(".")
ver = [int(i) for i in ver]
finalsum = finalver[2] + finalver[1]*100 + finalver[0]*100*100
sum = ver[2] + ver[1]*100 + ver[0]*100*100
# Make a statement
if sum > finalsum:
finalver = ver.copy()
finalurl = url
if finalver == globs.version:
logfile.printdbg('The software is already the newer version')
return True
logfile.printdbg('Preparing download for the new version')
getTheUpdate = downloader.newdownload(credentials, finalurl, globs.CNIRFolder + '\\..\\CNIPackage.zip').download()
return True
## Main Function
def umain():
try:
# Global Handlers
logfile = logger.logCur
launcherWindow = ihm.launcherWindowCur
try:
# EXECUTING THE UPDATE BATCH
success = batch()
except Exception as e:
logfile.printerr("An error occured on the thread : " + str(traceback.format_exc()))
launcherWindow.mainCanvas.itemconfigure(launcherWindow.msg, text=('ERROR : ' + str(e)))
time.sleep(3)
launcherWindow.destroy()
return 1
if success:
logfile.printdbg("Software is up-to-date !")
launcherWindow.mainCanvas.itemconfigure(launcherWindow.msg, text='Software is up-to-date !')
else:
logfile.printerr("An error occured. No effective update !")
launcherWindow.mainCanvas.itemconfigure(launcherWindow.msg, text='An error occured. No effective update !')
time.sleep(2)
launcherWindow.destroy()
return 0
except:
logfile.printerr("A FATAL ERROR OCCURED : " + str(traceback.format_exc()))
launcherWindow.destroy()
sys.exit(2)
return 2
return

2
versions.lst Normal file
View File

@ -0,0 +1,2 @@
# ver|url|checksum, and | as separator, one version per ||
0.0.0|https://neoxgroup.eu/ftpaccess/Applicatifs/CNIRevelator/CNIRevelator_2.2.5|1234||3.0.1|https://neoxgroup.eu/ftpaccess/Applicatifs/CNIRevelator/CNIRevelator_2.2.5|1234||0.0.1|https://www.os-k.eu|1234||3.0.2|https://neoxgroup.eu/ftpaccess/Applicatifs/CNIRevelator/CNIRevelator_2.2.5|1234