284 lines
9.7 KiB
Python
284 lines
9.7 KiB
Python
|
#!/usr/bin/python3
|
||
|
|
||
|
# Written by Jordan ERNST Q1 2018.
|
||
|
# Contact : pro.ernst@gmail.com
|
||
|
# v1.0 : 23/03/2018
|
||
|
|
||
|
# https://www.pyimagesearch.com/2015/12/21/increasing-webcam-fps-with-python-and-opencv/
|
||
|
|
||
|
import sys
|
||
|
import os
|
||
|
import re
|
||
|
from contextlib import contextmanager # To hide output
|
||
|
from datetime import date, timedelta
|
||
|
import csv
|
||
|
import code128
|
||
|
import cv2
|
||
|
from pywinauto.findwindows import find_window
|
||
|
from pywinauto.win32functions import SetForegroundWindow
|
||
|
from PIL import Image, ImageDraw, ImageFont
|
||
|
from PyPDF2 import PdfFileReader, PdfFileWriter
|
||
|
import subprocess
|
||
|
from shutil import copyfile
|
||
|
from pyfiglet import Figlet
|
||
|
from colorama import init
|
||
|
from termcolor import colored
|
||
|
|
||
|
|
||
|
version = '1.0'
|
||
|
|
||
|
computer = '' # 'test', 'mediatheque' or 'accueil'
|
||
|
|
||
|
if computer == 'test':
|
||
|
IFPassdir = '\\\\192.168.1.1\SSIC\\04-Projets\IFPass\\'
|
||
|
elif computer == 'mediatheque':
|
||
|
IFPassdir = '\\\\192.168.1.1\IFPass\\'
|
||
|
printername = ' XPS Pink Card Printer'
|
||
|
elif computer == 'accueil':
|
||
|
IFPassdir = '\\\\192.168.1.1\IFPass\\'
|
||
|
printername = ' XPS Blue Card Printer'
|
||
|
else:
|
||
|
print('La variable "computer" est mal définie.')
|
||
|
sys.exit()
|
||
|
|
||
|
clientsfile = IFPassdir + 'Clients_IFPass.csv'
|
||
|
clientsbkpfile = IFPassdir + 'Clients_IFPass_bakup.csv'
|
||
|
imgdir = IFPassdir + 'Cartes\\'
|
||
|
pdftemplate = IFPassdir + 'Templates\IFPass_PDF_Template.pdf'
|
||
|
pngtemplate = IFPassdir + 'Templates\IFPass_PNG_Template.png'
|
||
|
fonttemplate = IFPassdir + 'Templates\Roboto-Bold.ttf'
|
||
|
|
||
|
|
||
|
@contextmanager
|
||
|
def HideOutput(to=os.devnull):
|
||
|
fd = sys.stdout.fileno()
|
||
|
|
||
|
def _redirect_stdout(to):
|
||
|
sys.stdout.close() # + implicit flush()
|
||
|
os.dup2(to.fileno(), fd) # fd writes to 'to' file
|
||
|
sys.stdout = os.fdopen(fd, 'w') # Python writes to fd
|
||
|
|
||
|
with os.fdopen(os.dup(fd), 'w') as old_stdout:
|
||
|
with open(to, 'w') as file:
|
||
|
_redirect_stdout(to=file)
|
||
|
try:
|
||
|
yield # allow code to be run with the redirected stdout
|
||
|
finally:
|
||
|
_redirect_stdout(to=old_stdout) # restore stdout. # cv2.selectROI
|
||
|
|
||
|
|
||
|
def get_fullname():
|
||
|
firstname = input("Prénom : ").strip()
|
||
|
firstname = firstname[0].upper() + firstname[1:].lower()
|
||
|
if '-' in firstname:
|
||
|
pos = firstname.find("-")
|
||
|
firstname = firstname[:pos + 1] + firstname[pos + 1].upper() + \
|
||
|
firstname[pos + 2:] # Check if compound name
|
||
|
if ' ' in firstname:
|
||
|
pos = firstname.find(" ")
|
||
|
firstname = firstname[:pos + 1] + firstname[pos + 1].upper() + \
|
||
|
firstname[pos + 2:] # Check if compound name
|
||
|
surname = input("Nom : ").upper().strip()
|
||
|
docteur = yes_or_no('Est-ce un Docteur ?')
|
||
|
if docteur:
|
||
|
titre = 'Dr.'
|
||
|
fullname = titre + ' ' + surname + ' ' + firstname
|
||
|
else:
|
||
|
titre = ''
|
||
|
fullname = surname + ' ' + firstname
|
||
|
return titre, firstname, surname, fullname
|
||
|
|
||
|
|
||
|
def yes_or_no(question):
|
||
|
while "the answer is invalid":
|
||
|
reply = input(question + " O/N : ").lower().strip()
|
||
|
if reply[:1] in ['oui', 'ou', 'o']:
|
||
|
return True
|
||
|
if reply[:1] in ['non', 'no', 'n']:
|
||
|
return False
|
||
|
|
||
|
|
||
|
def getclientID():
|
||
|
with open(clientsfile, 'r', newline='', encoding='utf-8') as csvfile:
|
||
|
lastline = csvfile.readlines()[-1]
|
||
|
lastID = lastline.split(';')[3]
|
||
|
if lastID == "Numéro de client":
|
||
|
clientID = "0000000001"
|
||
|
else:
|
||
|
clientID = str(int(lastID) + 1).zfill(10)
|
||
|
|
||
|
writeindb(clientID)
|
||
|
return clientID
|
||
|
|
||
|
|
||
|
def barcode_gen(clientID):
|
||
|
print("Génération du code barre... ", end='')
|
||
|
barcode = code128.image(clientID, thickness=4) # .save(imgdir + clientID + '.png')
|
||
|
print(colored('[OK]', 'green'))
|
||
|
return barcode
|
||
|
|
||
|
|
||
|
def getpic():
|
||
|
while True:
|
||
|
print("Prendre la photo... ", end='')
|
||
|
sys.stdout.flush()
|
||
|
cap = cv2.VideoCapture(0)
|
||
|
while True: # Loop stream webcam
|
||
|
try:
|
||
|
ret, frame = cap.read()
|
||
|
cv2.rectangle(frame, (170, 73), (470, 407), (0, 255, 0), 2)
|
||
|
cv2.imshow('IFCamera - Touche Espace pour prendre la photo, Echap pour une carte sans photo, Q pour quitter.',
|
||
|
frame)
|
||
|
except cv2.error:
|
||
|
print('\nLa webcam est débranchée. Branchez-la, puis relancez le programme.')
|
||
|
os.system("pause")
|
||
|
sys.exit(0)
|
||
|
SetForegroundWindow(find_window(title='IFCamera - Touche Espace '
|
||
|
'pour prendre la photo, Echap pour une carte sans photo, Q pour quitter.'))
|
||
|
k = cv2.waitKey(1)
|
||
|
if k == 27: # Echap
|
||
|
print(colored('[OK]', 'green'))
|
||
|
cv2.destroyAllWindows()
|
||
|
defaultpicture = IFPassdir + 'Templates\default_avatar.jpg'
|
||
|
picture = Image.open(defaultpicture)
|
||
|
return picture
|
||
|
elif k & 0xFF == ord(' '): # Space
|
||
|
break
|
||
|
elif k & 0xFF == ord('q'): # Q or q to quit
|
||
|
cap.release()
|
||
|
cv2.destroyAllWindows()
|
||
|
sys.exit()
|
||
|
cap.release()
|
||
|
cv2.destroyAllWindows()
|
||
|
cropped = frame[75:405, 172:468]
|
||
|
cv2.imshow('IFCamera - Espace pour valider, Echap pour modifier, Q pour quitter', cropped)
|
||
|
while True:
|
||
|
k = cv2.waitKey(1)
|
||
|
if k == 27: # Echap
|
||
|
print(colored('[KO]', 'red'))
|
||
|
cv2.destroyAllWindows()
|
||
|
break
|
||
|
|
||
|
elif k & 0xFF == ord(' '): # Space
|
||
|
print(colored('[OK]', 'green'))
|
||
|
cv2.destroyAllWindows()
|
||
|
# Color conversion and cv2 img to Pillow img
|
||
|
cropped = cv2.cvtColor(cropped, cv2.COLOR_BGR2RGB)
|
||
|
picture = Image.fromarray(cropped)
|
||
|
return picture
|
||
|
|
||
|
|
||
|
elif k & 0xFF == ord('q'): # Q or q to quit
|
||
|
cv2.destroyAllWindows()
|
||
|
sys.exit()
|
||
|
|
||
|
|
||
|
def writeindb(clientID):
|
||
|
print("Ajout dans la base de données... ", end="")
|
||
|
with open(clientsfile, 'a', newline='', encoding='utf-8') as csvfile:
|
||
|
writer = csv.writer(csvfile, delimiter=';')
|
||
|
writer.writerow([titre, firstname, surname, clientID, dateinsc, dateexp])
|
||
|
print(colored('[OK]', 'green'))
|
||
|
|
||
|
|
||
|
def bkpdb():
|
||
|
copyfile(clientsfile, clientsbkpfile)
|
||
|
|
||
|
|
||
|
def fillcard(barcode):
|
||
|
print("Création de la carte avec les informations...", end='')
|
||
|
im = Image.open(pngtemplate)
|
||
|
draw = ImageDraw.Draw(im)
|
||
|
|
||
|
# Name embedding :
|
||
|
font = ImageFont.truetype(fonttemplate, 45)
|
||
|
draw.text((401, 310), fullname, fill=(0,0,0), font=font)
|
||
|
|
||
|
# Date embedding :
|
||
|
font = ImageFont.truetype(fonttemplate, 30)
|
||
|
draw.text((401, 390), dateexp, fill=(0,0,0), font=font)
|
||
|
|
||
|
# ID embedding :
|
||
|
font = ImageFont.truetype('arial.ttf', 30)
|
||
|
draw.text((693, 560), clientID, fill=(0,0,0), font=font)
|
||
|
|
||
|
# Barcode + picture embedding :
|
||
|
im.paste(barcode,(556, 460))
|
||
|
im.paste(picture,(47, 49))
|
||
|
|
||
|
# Create PDF :
|
||
|
im = im.convert("RGB")
|
||
|
im.save(imgdir + clientID + '_Front.pdf', 'PDF', resolution=299.0, quality=98)
|
||
|
|
||
|
print(colored('[OK]', 'green'))
|
||
|
|
||
|
|
||
|
def mergepdf():
|
||
|
cartefilename = imgdir + clientID + '.pdf'
|
||
|
output = PdfFileWriter()
|
||
|
|
||
|
pdf1 = PdfFileReader(imgdir + clientID + '_Front.pdf', 'rb')
|
||
|
recto = pdf1.getPage(0)
|
||
|
output.addPage(recto)
|
||
|
|
||
|
pdf2 = PdfFileReader(pdftemplate, 'rb')
|
||
|
verso = pdf2.getPage(1)
|
||
|
output.addPage(verso)
|
||
|
|
||
|
with open(cartefilename, 'wb') as f:
|
||
|
output.write(f)
|
||
|
|
||
|
os.remove(imgdir + clientID + '_Front.pdf')
|
||
|
|
||
|
return cartefilename
|
||
|
|
||
|
|
||
|
def printcard(cartefilename):
|
||
|
# CMD : "C:\Program Files (x86)\Adobe\Acrobat Reader DC\Reader\AcroRd32.exe" /h /n /t Carte.pdf "XPS Pink Card Printer"
|
||
|
subprocess.Popen('"C:\Program Files (x86)\Adobe\Acrobat Reader DC\Reader\AcroRd32.exe" /h /n /t ' + cartefilename + printername, shell=False)
|
||
|
print('test')
|
||
|
|
||
|
|
||
|
while "the informations are incorrect": # Loop Filling informations
|
||
|
os.system('cls')
|
||
|
init()
|
||
|
f = Figlet(font='big')
|
||
|
print(colored(f.renderText('IFPass'), 'cyan', attrs=['bold']))
|
||
|
print('Version :', version)
|
||
|
print('\nLe programme IFPass à été écrit par Jordan ERNST Q1 2018.')
|
||
|
print('Pour toute question ou problème contactez-moi à pro.ernst@gmail.com.\n')
|
||
|
titre, firstname, surname, fullname = get_fullname()
|
||
|
dateinsc = date.today()
|
||
|
dateexp = dateinsc + timedelta(days=365)
|
||
|
|
||
|
dateinsc = dateinsc.strftime('%d/%m/%Y')
|
||
|
dateexp = dateexp.strftime('%d/%m/%Y')
|
||
|
changeexp = yes_or_no('Voulez-vous choisir la date d\'expiration ?')
|
||
|
if changeexp:
|
||
|
while True:
|
||
|
dateexp = input('Quelle date d\'expiration voulez-vous mettre (Format : JJ/MM/AAAA)? : ')
|
||
|
match = re.fullmatch(r'^(0[1-9]|1[0-9]|2[0-9]|3[0-1])/(0[1-9]|1[0-2])/([0-9]){4}$', dateexp)
|
||
|
if match:
|
||
|
break
|
||
|
else:
|
||
|
print('Mauvais format ! JJ/MM/AAAA, exemple : 01/08/2042')
|
||
|
|
||
|
os.system('cls')
|
||
|
print("Titre : ", colored(titre, 'green'))
|
||
|
print("Prénom : ", colored(firstname, 'green'))
|
||
|
print("Nom : ", colored(surname, 'green'))
|
||
|
print("Date d'inscription :", colored(dateinsc, 'green'))
|
||
|
print("Date d'expiration : ", colored(dateexp, 'green'))
|
||
|
correct = yes_or_no("Ces informations sont elles correctes ?")
|
||
|
|
||
|
if correct:
|
||
|
os.system('cls')
|
||
|
picture = getpic()
|
||
|
clientID = getclientID()
|
||
|
barcode = barcode_gen(clientID)
|
||
|
fillcard(barcode)
|
||
|
cartefilename = mergepdf()
|
||
|
bkpdb()
|
||
|
if computer == 'mediatheque' or computer == 'accueil':
|
||
|
printcard(cartefilename)
|