1
0
mirror of https://gitlab.os-k.eu/neox/CNIRevelator.git synced 2023-08-25 14:03:10 +02:00

Working on image display

This commit is contained in:
Adrien Bourmault 2019-08-07 15:27:44 +02:00 committed by GitHub
parent b77283a3ae
commit d93b4fe893
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 171 additions and 451 deletions

View File

@ -6,6 +6,7 @@
* *
* Copyright © 2018-2019 Adrien Bourmault (neox95) *
* *
* *
* This file is part of CNIRevelator. *
* *
* CNIRevelator is free software: you can redistribute it and/or modify *
@ -63,7 +64,10 @@ def main():
if globs.CNIRNewVersion:
showinfo('Changelog : résumé de mise à jour', ('Version du logiciel : CNIRevelator ' + globs.verstring_full + '\n\n' + globs.changelog), parent=mainw)
logfile.printdbg('main() : **** Launching App_main() ****')
mainw.mainloop()
try:
mainw.mainloop()
except Exception as e:
showerror("CNIRevelator Fatal Error", "An error has occured : {}".format(e), parent=mainw)
logfile.printdbg('main() : **** Ending App_main() ****')
logfile.printdbg('*** CNIRevelator LOGFILE. Goodbye World ! ***')

BIN
src/background.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 82 KiB

View File

@ -26,12 +26,13 @@ import os
# CNIRevelator version
verType = "alpha"
version = [3, 0, 5]
version = [3, 0, 6]
verstring_full = "{}.{}.{} {}".format(version[0], version[1], version[2], verType)
verstring = "{}.{}".format(version[0], version[1])
debug = True
changelog = "Version 3.0.5 \nMise-à-jour mineure avec les corrections suivantes :\n- Changement de l'icône de l'exécutable afin de refléter le changement de version majeur accompli en 3.0\n\n" + \
changelog = "Version 3.0.6 \nMise-à-jour mineure avec les corrections suivantes :\n- Changement de l'apparence du launcher de l'application\n- Améliorations de l'interface, notamment de la stabilité\n- Ajout de la signature numérique de l'exécutable\n\n" + \
"Version 3.0.5 \nMise-à-jour mineure avec les corrections suivantes :\n- Changement de l'icône de l'exécutable afin de refléter le changement de version majeur accompli en 3.0\n\n" + \
"Version 3.0.4 \nMise-à-jour mineure avec les corrections suivantes :\n- Correction d'un bug affectant le système de mise-à-jour\n\n" + \
"Version 3.0.3 \nMise-à-jour mineure avec les corrections suivantes :\n- Correction d'un bug affectant le changelog\n- Correction d'une erreur avec la touche Suppr Arrière et Suppr causant une perte de données\n\n" + \
"Version 3.0.2 \nMise-à-jour mineure avec les corrections suivantes :\n- Changement d'icône de l'exécutable\n- Correction d'un bug affectant le logging\n- Correction d'un bug affectant la détection de documents\n- Et autres modifications mineures\n\n" + \

View File

@ -27,9 +27,12 @@ from tkinter import *
from tkinter.messagebox import *
from tkinter import filedialog
from tkinter import ttk
import cv2
import PIL.Image, PIL.ImageTk
import logger # logger.py
import globs # globs.py
import image # image.py
controlKeys = ["Escape", "Right", "Left", "Up", "Down", "Home", "End", "BackSpace", "Delete", "Inser", "Shift_L", "Shift_R", "Control_R", "Control_L"]
@ -108,35 +111,50 @@ 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
wheight = 274
wwidth = 480
# Centering
x = ws / 2 - wwidth / 2
y = hs / 2 - wheight / 2
self.geometry('%dx%d+%d+%d' % (wwidth, wheight, x, y))
# 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)
# Load an image using OpenCV
cv_img = cv2.imread("background.png")
cv_img = cv2.cvtColor(cv_img, cv2.COLOR_BGR2RGB)
cv_img = cv2.blur(cv_img, (15, 15))
# Get the image dimensions (OpenCV stores image data as NumPy ndarray)
height, width, no_channels = cv_img.shape
# Get the image dimensions (OpenCV stores image data as NumPy ndarray)
height, width, no_channels = cv_img.shape
# Use PIL (Pillow) to convert the NumPy ndarray to a PhotoImage
self.photo = PIL.ImageTk.PhotoImage(image = PIL.Image.fromarray(cv_img))
self.mainCanvas = Canvas(self, width=wwidth, height=wheight, bg=globs.CNIRLColor, highlightthickness=0)
self.mainCanvas.create_image(wwidth /2, wheight /2, image=self.photo)
self.progressBar = ttk.Progressbar(self.pBarZone, orient=HORIZONTAL, length=wwidth-10, mode='determinate')
# Column
self.mainCanvas.grid_rowconfigure(0, weight=1, minsize=(wheight / 10 * 9))
self.mainCanvas.grid_rowconfigure(1, weight=1, minsize=(wheight / 10 * 1))
self.mainCanvas.create_text((wwidth / 2), (wheight / 3), text=(globs.CNIRName), font='Helvetica 30', fill='white')
self.mainCanvas.create_text((wwidth / 2), (wheight / 2), text="version " + (globs.verstring_full), font='Helvetica 8', fill='white')
self.msg = self.mainCanvas.create_text((wwidth / 2), (wheight / 1.20), text='Booting up...', font='Helvetica 9', fill='white')
#self.pBarZone = Frame(self.mainCanvas, width=wwidth, height=wheight/10)
self.update()
self.progressBar = ttk.Progressbar(self.mainCanvas, orient=HORIZONTAL, length=wwidth, mode='determinate')
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()
self.mainCanvas.grid(row=0)
self.update()
self.progressBar.grid(row=1, sticky='S')
if getattr(sys, 'frozen', False):
@ -152,6 +170,9 @@ class LauncherWindow(Tk):
def printmsg(self, msg):
self.mainCanvas.itemconfigure(self.msg, text=(msg))
def exit(self):
self.after(1000, self.destroy)
class AutoScrollbar(ttk.Scrollbar):
def set(self, lo, hi):
@ -167,156 +188,21 @@ class AutoScrollbar(ttk.Scrollbar):
def place(self, **kw):
raise TclError('Cannot use place with the widget ' + self.__class__.__name__)
class OpenPageDialog(Toplevel):
def __init__(self, parent, number):
super().__init__(parent)
self.parent = parent
self.title("Choisir la page à afficher de l'image selectionnée")
self.resizable(width=False, height=False)
self.termtext = Label(self, text='Merci de selectionner un numéro de page dans la liste ci-dessous.')
self.termtext.grid(column=0, row=0, sticky='N', padx=5, pady=5)
self.combotry = ttk.Combobox(self)
self.combotry['values'] = tuple(str(x) for x in range(1, number + 1))
self.combotry.grid(column=0, row=1, sticky='N', padx=5, pady=5)
self.button = Button(self, text='Valider', command=(self.valid))
self.button.grid(column=0, row=2, sticky='S', padx=5, pady=5)
self.update()
hs = self.winfo_screenheight()
w = int(self.winfo_width())
h = int(self.winfo_height())
ws = self.winfo_screenwidth()
hs = self.winfo_screenheight()
x = ws / 2 - w / 2
y = hs / 2 - h / 2
self.geometry('%dx%d+%d+%d' % (w, h, x, y))
if getattr(sys, 'frozen', False):
self.iconbitmap(sys._MEIPASS + '\\id-card.ico\\id-card.ico')
else:
self.iconbitmap('id-card.ico')
def valid(self):
self.parent.page = self.combotry.current()
self.destroy()
class OpenScanWin(Toplevel):
def __init__(self, parent, file, type, nframe=1):
super().__init__(parent)
self.parent = parent
app = OpenScan(self, file, type, nframe)
class OpenScan(ttk.Frame):
def __init__(self, mainframe, fileorig, type, nframe=1, pagenum=0, file=None):
""" Initialize the main Frame """
if file == None:
file = fileorig
self.file = file
self.fileorig = fileorig
self.nframe = nframe
self.pagenum = pagenum
self.parent = mainframe.parent
ttk.Frame.__init__(self, master=mainframe)
self.master.title('Ouvrir un scan... (Utilisez la roulette pour zoomer, clic gauche pour déplacer et clic droit pour sélectionner la MRZ)')
self.master.resizable(width=False, height=False)
hs = self.winfo_screenheight()
w = int(self.winfo_screenheight() / 1.5)
h = int(self.winfo_screenheight() / 2)
ws = self.winfo_screenwidth()
hs = self.winfo_screenheight()
x = ws / 2 - w / 2
y = hs / 2 - h / 2
self.master.geometry('%dx%d+%d+%d' % (w, h, x, y))
if getattr(sys, 'frozen', False):
self.master.iconbitmap(sys._MEIPASS + '\\id-card.ico\\id-card.ico')
else:
self.master.iconbitmap('id-card.ico')
self.master.rowconfigure(0, weight=1)
self.master.columnconfigure(0, weight=1)
self.cadre = CanvasImage(self.master, self.file, type)
self.cadre.grid(row=0, column=0)
self.master.menubar = Menu(self.master)
if type == 1:
self.master.menubar.add_command(label='Page précédente', command=(self.pagep))
self.master.menubar.add_command(label='Pivoter -90°', command=(self.cadre.rotatemm))
self.master.menubar.add_command(label='Pivoter -1°', command=(self.cadre.rotatem))
self.master.menubar.add_command(label='Pivoter +1°', command=(self.cadre.rotatep))
self.master.menubar.add_command(label='Pivoter +90°', command=(self.cadre.rotatepp))
if type == 1:
self.master.menubar.add_command(label='Page suivante', command=(self.pages))
self.master.config(menu=(self.master.menubar))
self.cadre.canvas.bind('<ButtonPress-3>', self.motionprep)
self.cadre.canvas.bind('<B3-Motion>', self.motionize)
self.cadre.canvas.bind('<ButtonRelease-3>', self.motionend)
def pages(self):
if self.pagenum + 1 < self.nframe:
im = Image.open(self.fileorig)
im.seek(self.pagenum + 1)
newpath = globs.CNIREnv + '\\temp' + str(random.randint(11111, 99999)) + '.tif'
im.save(newpath)
im.close()
self.cadre.destroy()
self.__init__(self.master, self.fileorig, 1, self.nframe, self.pagenum + 1, newpath)
def pagep(self):
if self.pagenum - 1 >= 0:
im = Image.open(self.fileorig)
im.seek(self.pagenum - 1)
newpath = globs.CNIREnv + '\\temp' + str(random.randint(11111, 99999)) + '.tif'
im.save(newpath)
im.close()
self.cadre.destroy()
self.__init__(self.master, self.fileorig, 1, self.nframe, self.pagenum - 1, newpath)
def motionprep(self, event):
if hasattr(self, 'rect'):
self.begx = event.x
self.begy = event.y
self.ix = self.cadre.canvas.canvasx(event.x)
self.iy = self.cadre.canvas.canvasy(event.y)
self.cadre.canvas.coords(self.rect, self.cadre.canvas.canvasx(event.x), self.cadre.canvas.canvasy(event.y), self.ix, self.iy)
else:
self.begx = event.x
self.begy = event.y
self.ix = self.cadre.canvas.canvasx(event.x)
self.iy = self.cadre.canvas.canvasy(event.y)
self.rect = self.cadre.canvas.create_rectangle((self.cadre.canvas.canvasx(event.x)), (self.cadre.canvas.canvasy(event.y)), (self.ix), (self.iy), outline='red')
def motionize(self, event):
event.x
event.y
self.cadre.canvas.coords(self.rect, self.ix, self.iy, self.cadre.canvas.canvasx(event.x), self.cadre.canvas.canvasy(event.y))
def motionend(self, event):
self.endx = event.x
self.endy = event.y
self.imtotreat = self.cadre.resizedim.crop((min(self.begx, self.endx), min(self.begy, self.endy), max(self.endx, self.begx), max(self.endy, self.begy)))
im = self.imtotreat
import CNI_pytesseract as pytesseract
try:
os.environ['PATH'] = globs.CNIREnv + '\\Tesseract-OCR4\\'
os.environ['TESSDATA_PREFIX'] = globs.CNIREnv + '\\Tesseract-OCR4\\tessdata'
self.text = pytesseract.image_to_string(im, lang='ocrb', boxes=False, config='--psm 6 --oem 0 -c tessedit_char_whitelist=ABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890<')
except pytesseract.TesseractNotFoundError as e:
try:
os.remove(globs.CNIREnv + '\\Tesseract-OCR4\\*.*')
except Exception:
pass
showerror('Erreur de module OCR', ('Le module OCR localisé en ' + str(os.environ['PATH']) + 'est introuvable. Il sera réinstallé à la prochaine exécution'), parent=self)
except pytesseract.TesseractError as e:
pass
self.master.success = False
dialogconf = OpenScanDialog(self.master, self.text)
dialogconf.transient(self)
dialogconf.grab_set()
self.wait_window(dialogconf)
if self.master.success:
self.master.destroy()
class ResizeableCanvas(Canvas):
def __init__(self,parent,**kwargs):
Canvas.__init__(self,parent,**kwargs)
self.bind("<Configure>", self.on_resize)
self.height = self.winfo_reqheight()
self.width = self.winfo_reqwidth()
def on_resize(self,event):
# determine the ratio of old width/height to new width/height
wscale = float(event.width)/self.width
hscale = float(event.height)/self.height
self.width = event.width
self.height = event.height
# rescale all the objects tagged with the "all" tag
self.scale("all",0,0,wscale,hscale)
## Global Handler
launcherWindowCur = LauncherWindow()

View File

@ -23,253 +23,3 @@
********************************************************************************
"""
class CanvasImage:
def __init__(self, placeholder, file, type):
""" Initialize the ImageFrame """
self.type = type
self.angle = 0
self.imscale = 1.0
self._CanvasImage__delta = 1.3
self._CanvasImage__filter = Image.ANTIALIAS
self._CanvasImage__previous_state = 0
self.path = file
self._CanvasImage__imframe = ttk.Frame(placeholder)
self.placeholder = placeholder
hbar = AutoScrollbar((self._CanvasImage__imframe), orient='horizontal')
vbar = AutoScrollbar((self._CanvasImage__imframe), orient='vertical')
hbar.grid(row=1, column=0, sticky='we')
vbar.grid(row=0, column=1, sticky='ns')
self.canvas = Canvas((self._CanvasImage__imframe), highlightthickness=0, xscrollcommand=(hbar.set),
yscrollcommand=(vbar.set))
self.canvas.grid(row=0, column=0, sticky='nswe')
self.canvas.update()
hbar.configure(command=(self._CanvasImage__scroll_x))
vbar.configure(command=(self._CanvasImage__scroll_y))
self.canvas.bind('<Configure>', lambda event: self._CanvasImage__show_image())
self.canvas.bind('<ButtonPress-1>', self._CanvasImage__move_from)
self.canvas.bind('<B1-Motion>', self._CanvasImage__move_to)
self.canvas.bind('<MouseWheel>', self._CanvasImage__wheel)
self._CanvasImage__huge = False
self._CanvasImage__huge_size = 14000
self._CanvasImage__band_width = 1024
Image.MAX_IMAGE_PIXELS = 1000000000
with warnings.catch_warnings():
warnings.simplefilter('ignore')
self._CanvasImage__image = Image.open(self.path)
self.imwidth, self.imheight = self._CanvasImage__image.size
if self.imwidth * self.imheight > self._CanvasImage__huge_size * self._CanvasImage__huge_size:
if self._CanvasImage__image.tile[0][0] == 'raw':
self._CanvasImage__huge = True
self._CanvasImage__offset = self._CanvasImage__image.tile[0][2]
self._CanvasImage__tile = [self._CanvasImage__image.tile[0][0],
[
0, 0, self.imwidth, 0],
self._CanvasImage__offset,
self._CanvasImage__image.tile[0][3]]
self._CanvasImage__min_side = min(self.imwidth, self.imheight)
self._CanvasImage__pyramid = [self.smaller()] if self._CanvasImage__huge else [Image.open(self.path)]
self._CanvasImage__ratio = max(self.imwidth, self.imheight) / self._CanvasImage__huge_size if self._CanvasImage__huge else 1.0
self._CanvasImage__curr_img = 0
self._CanvasImage__scale = self.imscale * self._CanvasImage__ratio
self._CanvasImage__reduction = 2
w, h = self._CanvasImage__pyramid[(-1)].size
while w > 512 and h > 512:
w /= self._CanvasImage__reduction
h /= self._CanvasImage__reduction
try:
self._CanvasImage__pyramid.append(self._CanvasImage__pyramid[(-1)].resize((int(w), int(h)), self._CanvasImage__filter))
except TypeError:
showerror(title='Erreur de fichier', message="Image incompatible. Merci d'utiliser une autre image ou de la convertir dans un format standard accepté!", parent=(self.placeholder))
self.placeholder.parent.openerrored = True
self.placeholder.destroy()
self.destroy()
return
self.container = self.canvas.create_rectangle((0, 0, self.imwidth, self.imheight), width=0)
self._CanvasImage__show_image()
self.canvas.focus_set()
def rotatem(self):
self.angle += 1
self._CanvasImage__show_image()
def rotatep(self):
self.angle -= 1
self._CanvasImage__show_image()
def rotatemm(self):
self.angle += 90
self._CanvasImage__show_image()
def rotatepp(self):
self.angle -= 90
self._CanvasImage__show_image()
def smaller(self):
""" Resize image proportionally and return smaller image """
w1, h1 = float(self.imwidth), float(self.imheight)
w2, h2 = float(self._CanvasImage__huge_size), float(self._CanvasImage__huge_size)
aspect_ratio1 = w1 / h1
aspect_ratio2 = w2 / h2
if aspect_ratio1 == aspect_ratio2:
image = Image.new('RGB', (int(w2), int(h2)))
k = h2 / h1
w = int(w2)
else:
if aspect_ratio1 > aspect_ratio2:
image = Image.new('RGB', (int(w2), int(w2 / aspect_ratio1)))
k = h2 / w1
w = int(w2)
else:
image = Image.new('RGB', (int(h2 * aspect_ratio1), int(h2)))
k = h2 / h1
w = int(h2 * aspect_ratio1)
i, j, n = 0, 1, round(0.5 + self.imheight / self._CanvasImage__band_width)
while i < self.imheight:
band = min(self._CanvasImage__band_width, self.imheight - i)
self._CanvasImage__tile[1][3] = band
self._CanvasImage__tile[2] = self._CanvasImage__offset + self.imwidth * i * 3
self._CanvasImage__image.close()
self._CanvasImage__image = Image.open(self.path)
self._CanvasImage__image.size = (self.imwidth, band)
self._CanvasImage__image.tile = [self._CanvasImage__tile]
cropped = self._CanvasImage__image.crop((0, 0, self.imwidth, band))
image.paste(cropped.resize((w, int(band * k) + 1), self._CanvasImage__filter), (0, int(i * k)))
i += band
j += 1
return image
def redraw_figures(self):
""" Dummy function to redraw figures in the children classes """
pass
def grid(self, **kw):
""" Put CanvasImage widget on the parent widget """
(self._CanvasImage__imframe.grid)(**kw)
self._CanvasImage__imframe.grid(sticky='nswe')
self._CanvasImage__imframe.rowconfigure(0, weight=1)
self._CanvasImage__imframe.columnconfigure(0, weight=1)
def __scroll_x(self, *args, **kwargs):
""" Scroll canvas horizontally and redraw the image """
(self.canvas.xview)(*args)
self._CanvasImage__show_image()
def __scroll_y(self, *args, **kwargs):
""" Scroll canvas vertically and redraw the image """
(self.canvas.yview)(*args)
self._CanvasImage__show_image()
def __show_image(self):
""" Show image on the Canvas. Implements correct image zoom almost like in Google Maps """
box_image = self.canvas.coords(self.container)
box_canvas = (self.canvas.canvasx(0),
self.canvas.canvasy(0),
self.canvas.canvasx(self.canvas.winfo_width()),
self.canvas.canvasy(self.canvas.winfo_height()))
box_img_int = tuple(map(int, box_image))
box_scroll = [
min(box_img_int[0], box_canvas[0]), min(box_img_int[1], box_canvas[1]),
max(box_img_int[2], box_canvas[2]), max(box_img_int[3], box_canvas[3])]
if box_scroll[0] == box_canvas[0]:
if box_scroll[2] == box_canvas[2]:
box_scroll[0] = box_img_int[0]
box_scroll[2] = box_img_int[2]
if box_scroll[1] == box_canvas[1] and box_scroll[3] == box_canvas[3]:
box_scroll[1] = box_img_int[1]
box_scroll[3] = box_img_int[3]
self.canvas.configure(scrollregion=(tuple(map(int, box_scroll))))
x1 = max(box_canvas[0] - box_image[0], 0)
y1 = max(box_canvas[1] - box_image[1], 0)
x2 = min(box_canvas[2], box_image[2]) - box_image[0]
y2 = min(box_canvas[3], box_image[3]) - box_image[1]
if int(x2 - x1) > 0:
if int(y2 - y1) > 0:
if self._CanvasImage__huge:
if self._CanvasImage__curr_img < 0:
h = int((y2 - y1) / self.imscale)
self._CanvasImage__tile[1][3] = h
self._CanvasImage__tile[2] = self._CanvasImage__offset + self.imwidth * int(y1 / self.imscale) * 3
self._CanvasImage__image.close()
self._CanvasImage__image = Image.open(self.path)
self._CanvasImage__image.size = (self.imwidth, h)
self._CanvasImage__image.tile = [self._CanvasImage__tile]
image = self._CanvasImage__image.crop((int(x1 / self.imscale), 0, int(x2 / self.imscale), h))
image = self._CanvasImage__pyramid[max(0, self._CanvasImage__curr_img)].crop((
int(x1 / self._CanvasImage__scale), int(y1 / self._CanvasImage__scale),
int(x2 / self._CanvasImage__scale), int(y2 / self._CanvasImage__scale)))
self.resizedim = image.resize((int(x2 - x1), int(y2 - y1)), self._CanvasImage__filter).rotate((self.angle), resample=(Image.BICUBIC), expand=1)
imagetk = ImageTk.PhotoImage((self.resizedim), master=(self.placeholder))
imageid = self.canvas.create_image((max(box_canvas[0], box_img_int[0])), (max(box_canvas[1], box_img_int[1])),
anchor='nw',
image=imagetk)
self.canvas.lower(imageid)
self.canvas.imagetk = imagetk
def __move_from(self, event):
""" Remember previous coordinates for scrolling with the mouse """
self.canvas.scan_mark(event.x, event.y)
def __move_to(self, event):
""" Drag (move) canvas to the new position """
self.canvas.scan_dragto((event.x), (event.y), gain=1)
self._CanvasImage__show_image()
def outside(self, x, y):
""" Checks if the point (x,y) is outside the image area """
bbox = self.canvas.coords(self.container)
if bbox[0] < x < bbox[2]:
if bbox[1] < y < bbox[3]:
pass
return False
else:
return True
def __wheel(self, event):
""" Zoom with mouse wheel """
x = self.canvas.canvasx(event.x)
y = self.canvas.canvasy(event.y)
if self.outside(x, y):
return
scale = 1.0
if event.delta == -120:
if round(self._CanvasImage__min_side * self.imscale) < int(self.placeholder.winfo_screenheight()):
return
self.imscale /= self._CanvasImage__delta
scale /= self._CanvasImage__delta
if event.delta == 120:
i = min(self.canvas.winfo_width(), self.canvas.winfo_height()) >> 1
if i < self.imscale:
return
self.imscale *= self._CanvasImage__delta
scale *= self._CanvasImage__delta
k = self.imscale * self._CanvasImage__ratio
self._CanvasImage__curr_img = min(-1 * int(math.log(k, self._CanvasImage__reduction)), len(self._CanvasImage__pyramid) - 1)
self._CanvasImage__scale = k * math.pow(self._CanvasImage__reduction, max(0, self._CanvasImage__curr_img))
self.canvas.scale('all', x, y, scale, scale)
self.redraw_figures()
self._CanvasImage__show_image()
def crop(self, bbox):
""" Crop rectangle from the image and return it """
if self._CanvasImage__huge:
band = bbox[3] - bbox[1]
self._CanvasImage__tile[1][3] = band
self._CanvasImage__tile[2] = self._CanvasImage__offset + self.imwidth * bbox[1] * 3
self._CanvasImage__image.close()
self._CanvasImage__image = Image.open(self.path)
self._CanvasImage__image.size = (self.imwidth, band)
self._CanvasImage__image.tile = [self._CanvasImage__tile]
return self._CanvasImage__image.crop((bbox[0], 0, bbox[2], band))
else:
return self._CanvasImage__pyramid[0].crop(bbox)
def destroy(self):
""" ImageFrame destructor """
self._CanvasImage__image.close()
map(lambda i: i.close, self._CanvasImage__pyramid)
del self._CanvasImage__pyramid[:]
del self._CanvasImage__pyramid
self.canvas.destroy()

View File

@ -32,6 +32,9 @@ from tkinter import ttk
import threading
from datetime import datetime
import re
import traceback
import cv2
import PIL.Image, PIL.ImageTk
import ihm # ihm.py
import logger # logger.py
@ -55,11 +58,13 @@ class mainWindow(Tk):
self.Tags = []
self.compliance = True
# Get the screen size
# Hide during construction
self.withdraw()
# Get the screen size and center
ws = self.winfo_screenwidth()
hs = self.winfo_screenheight()
logfile.printdbg('Launching main window with resolution' + str(ws) + 'x' + str(hs))
self.grid()
# Configuring the size of each part of the window
self.grid_columnconfigure(0, weight=1, minsize=(ws / 2 * 0.3333333333333333))
@ -141,13 +146,18 @@ class mainWindow(Tk):
"INDIC" : self.indic,
}
# The STATUS indicator
self.STATUT = ttk.Labelframe(self, text='Statut')
# The STATUS indicator + image display
self.STATUT = ttk.Labelframe(self, text='Affichage de documents et statut')
self.STATUT.grid_columnconfigure(0, weight=1)
self.STATUT.grid_rowconfigure(0, weight=1)
self.STATUStxt = Label((self.STATUT), text='', font='Times 24', fg='#FFBF00')
self.STATUStxt.grid(column=0, row=0, padx=0, pady=0, sticky='EWNS')
self.STATUStxt['text'] = 'EN ATTENTE'
self.STATUT.frame = Frame(self.STATUT)
self.STATUT.frame.grid(column=0, row=0, sticky='NSEW')
self.STATUT.frame.grid_columnconfigure(0, weight=1)
self.STATUT.frame.grid_rowconfigure(0, weight=1)
self.STATUT.ZONE = ihm.ResizeableCanvas(self.STATUT.frame, bg=self["background"])
self.STATUT.ZONE.pack(fill="both", expand=True)
self.STATUSimg = self.STATUT.ZONE.create_image(0,0, image=None)
self.STATUStxt = self.STATUT.ZONE.create_text(0,0, text='', font='Times 24', fill='#FFBF00')
# The terminal to enter the MRZ
self.terminal = ttk.Labelframe(self, text='Terminal de saisie de MRZ complète')
@ -201,7 +211,6 @@ class mainWindow(Tk):
self.terminal.grid(column=0, row=2, sticky='EWNS', columnspan=2, padx=5, pady=5)
self.terminal2.grid(column=0, row=1, sticky='EWNS', columnspan=2, padx=5, pady=5)
self.monitor.grid(column=2, row=1, sticky='EWNS', columnspan=1, rowspan=2, padx=5, pady=5)
self.update()
# What is a window without a menu bar ?
menubar = Menu(self)
@ -228,22 +237,48 @@ class mainWindow(Tk):
# Make this window resizable and set her size
self.resizable(width=True, height=True)
self.minsize(self.winfo_width(), self.winfo_height())
w = int(self.winfo_width())
h = int(self.winfo_height())
self.update()
w = int(self.winfo_reqwidth())
h = int(self.winfo_reqheight())
ws = self.winfo_screenwidth()
hs = self.winfo_screenheight()
x = ws / 2 - w / 2
y = hs / 2 - h / 2
x = (ws - w)/2
y = (hs - h)/2
self.geometry('%dx%d+%d+%d' % (w, h, x, y))
self.update()
self.deiconify()
self.minsize(self.winfo_width(), self.winfo_height())
# Load an image using OpenCV
cv_img = cv2.imread("background.png")
cv_img = cv2.cvtColor(cv_img, cv2.COLOR_BGR2GRAY)
cv_img = cv2.blur(cv_img, (15, 15))
# Get the image dimensions (OpenCV stores image data as NumPy ndarray)
height, width = cv_img.shape
# Get the image dimensions (OpenCV stores image data as NumPy ndarray)
height, width = cv_img.shape
# Use PIL (Pillow) to convert the NumPy ndarray to a PhotoImage
photo = PIL.ImageTk.PhotoImage(image = PIL.Image.fromarray(cv_img))
self.statusUpdate("EN ATTENTE", "#FFBF00", photo, setplace=True)
# Some bindings
self.termtext.bind('<Key>', self.entryValidation)
self.termtext.bind('<<Paste>>', self.pasteValidation)
self.speed731text.bind('<Control_R>', self.speedValidation)
self.update()
logfile.printdbg('Initialization successful')
def statusUpdate(self, msg, color, image=None, setplace=False):
if image:
self.STATUT.image = image
self.STATUT.ZONE.itemconfigure(self.STATUSimg, image=(self.STATUT.image))
self.STATUT.ZONE.itemconfigure(self.STATUStxt, text=(msg), fill=color)
if setplace:
self.STATUT.ZONE.move(self.STATUSimg, self.STATUT.ZONE.winfo_reqwidth() / 2, self.STATUT.ZONE.winfo_reqheight() / 2)
self.STATUT.ZONE.move(self.STATUStxt, self.STATUT.ZONE.winfo_reqwidth() / 2, self.STATUT.ZONE.winfo_reqheight() / 2)
def stringValidation(self, keysym):
# analysis
# If we must decide the type of the document
@ -426,8 +461,13 @@ class mainWindow(Tk):
def openingScan(self):
pass
# OPEN A SCAN
path = ''
path = filedialog.askopenfilename(parent=self, title='Ouvrir un scan de CNI...', filetypes=(('TIF files', '*.tif'),
('TIF files', '*.tiff'),
('JPEG files', '*.jpg'),
('JPEG files', '*.jpeg')))
self.mrzdetected = ''
self.mrzdict = {}
def newEntry(self):
self.initialize()
@ -521,13 +561,6 @@ class mainWindow(Tk):
self.termtext.tag_configure("nonconforme", background="red", relief='raised', foreground="white")
self.compliance = False
if self.compliance == True:
self.STATUStxt['text'] = 'CONFORME'
self.STATUStxt['fg'] = "green"
else:
self.STATUStxt['text'] = 'NON CONFORME'
self.STATUStxt['fg'] = "red"
# get the infos
docInfos = mrz.getDocInfos(self.mrzDecided, code)
#print(docInfos)
@ -544,6 +577,12 @@ class mainWindow(Tk):
self.infoList[key]['background'] = "red"
self.infoList[key]['foreground'] = "white"
self.infoList[key]['text'] = "NC"
self.compliance = False
if self.compliance == True:
self.statusUpdate("CONFORME", "chartreuse2")
else:
self.statusUpdate("NON-CONFORME","red")
return

View File

@ -989,7 +989,7 @@ def getDocInfos(doc, code):
try:
datetime.datetime.strptime(value,"%d/%m/%y")
except ValueError:
print(value)
#print(value)
if value != "":
res[field[0]] = False
else:

View File

@ -42,6 +42,8 @@ import downloader # downloader.py
UPDATE_IS_MADE = False
UPATH = ' '
launcherWindow = ihm.launcherWindowCur
def createShortcut(path, target='', wDir='', icon=''):
"""
Creates a shortcut for a program or an internet link
@ -79,6 +81,47 @@ def exitProcess(arg):
process.terminate()
sys.exit(arg)
def runPowershell(scriptblock, cwd=os.getcwd()):
"""
Executes a powershell command
"""
log.debug("Running PowerShell Block:\r\n%s", scriptblock)
log.debug("Current Directory: %s\r\n" % cwd)
psProc = subprocess.Popen([r'C:\WINDOWS\system32\WindowsPowerShell\v1.0\powershell.exe',
'-ExecutionPolicy', 'Bypass',
'-noprofile',
'-c', '-',],
cwd=cwd,
stdin=subprocess.PIPE,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE)
stdoutdata, stderrdata = psProc.communicate(scriptblock)
if stdoutdata:
log.debug("Script Output:\r\n%s" % stdoutdata)
elif not stderrdata:
log.debug("Script completed succssfully (no stdout/stderr).")
if stderrdata:
log.error("Script Error:\r\n%s" % stderrdata)
return stdoutdata, stderrdata
def getCertificates(server_list, location="LocalMachine", store="My"):
"""
Returns the json data of all installed certificates
"""
cmd = '''
$sb = { ls Cert:\%s\%s | Select Subject,ThumbPrint }
$Servers = '%s' | ConvertFrom-Json
Invoke-Command -ComputerName $Servers -ScriptBlock $sb -Authentication Negotiate | ConvertTo-Json -Depth 999
''' % (location, store, json.dumps(server_list))
stdoutdata, stderrdata = runPowershell(cmd)
return json.loads(stdoutdata)
def getLatestVersion(credentials):
"""
Returns the latest version of the software
@ -86,7 +129,7 @@ def getLatestVersion(credentials):
# Global Handlers
logfile = logger.logCur
launcherWindow = ihm.launcherWindowCur
# First retrieving the urls !
while True:
@ -153,7 +196,7 @@ def getLatestVersion(credentials):
def tessInstall(PATH, credentials):
# Global Handlers
logfile = logger.logCur
launcherWindow = ihm.launcherWindowCur
# Verifying that Tesseract is installed
if not os.path.exists(PATH + '\\Tesseract-OCR4\\'):
@ -181,7 +224,7 @@ def tessInstall(PATH, credentials):
def batch(credentials):
# Global Handlers
logfile = logger.logCur
launcherWindow = ihm.launcherWindowCur
# Get the latest version of CNIRevelator
finalver, finalurl, finalchecksum = getLatestVersion(credentials)
@ -259,7 +302,7 @@ def umain():
# Global Handlers
logfile = logger.logCur
launcherWindow = ihm.launcherWindowCur
credentials = downloader.newcredentials()
@ -267,8 +310,7 @@ def umain():
logfile.printerr("Credentials Error. No effective update !")
launcherWindow.printmsg('Credentials Error. No effective update !')
time.sleep(2)
launcherWindow = ihm.launcherWindowCur
launcherWindow.destroy()
launcherWindow.exit()
return 0
# Cleaner for the old version if detected
@ -335,7 +377,7 @@ def umain():
logfile.printerr("An error occured on the thread : " + str(traceback.format_exc()))
launcherWindow.printmsg('ERROR : ' + str(e))
time.sleep(3)
launcherWindow.destroy()
launcherWindow.exit()
return 1
if success:
@ -345,14 +387,12 @@ def umain():
logfile.printerr("An error occured. No effective update !")
launcherWindow.printmsg('An error occured. No effective update !')
time.sleep(2)
launcherWindow = ihm.launcherWindowCur
launcherWindow.destroy()
launcherWindow.exit()
return 0
except:
logfile.printerr("A FATAL ERROR OCCURED : " + str(traceback.format_exc()))
launcherWindow = ihm.launcherWindowCur
launcherWindow.destroy()
launcherWindow.exit()
sys.exit(2)
return 2