Compare commits

..

No commits in common. "master" and "v1.0" have entirely different histories.
master ... v1.0

19 changed files with 124 additions and 737 deletions

11
.gitignore vendored
View File

@ -1,12 +1 @@
.ropeproject .ropeproject
Cartes
Clients_IFPass.csv
Clients_IFPass_backup.csv
IFPass.conf
Templates/IFPass_PDF_Template.pdf
Templates/IFPass_PNG_Template.png
build/x86/*
build/x64/*
# Except builds:
!build/x86/*x86.exe
!build/x64/*x64.exe

3
CHANGELOG.md Normal file
View File

@ -0,0 +1,3 @@
## 1.0 (23/03/2018)
### First IFPass release

View File

@ -0,0 +1 @@
Titre;Prénom;Nom;Numéro de client;Date d'inscripton;Date d'expiration
1 Titre Prénom Nom Numéro de client Date d'inscripton Date d'expiration

1
Clients_IFPass.csv Normal file
View File

@ -0,0 +1 @@
Titre;Prénom;Nom;Numéro de client;Date d'inscripton;Date d'expiration
1 Titre Prénom Nom Numéro de client Date d'inscripton Date d'expiration

BIN
IF.ico

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.9 KiB

508
IFPass.py
View File

@ -1,13 +1,16 @@
#!python3 #!/usr/bin/python3
# Written by Jordan ERNST Q1 2018. # Written by Jordan ERNST Q1 2018.
# Contact : pro.ernst@gmail.com # 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 configparser
import sys import sys
import os import os
import re import re
from datetime import date, timedelta, datetime from contextlib import contextmanager # To hide output
from datetime import date, timedelta
import csv import csv
import code128 import code128
import cv2 import cv2
@ -15,91 +18,57 @@ from pywinauto.findwindows import find_window
from pywinauto.win32functions import SetForegroundWindow from pywinauto.win32functions import SetForegroundWindow
from PIL import Image, ImageDraw, ImageFont from PIL import Image, ImageDraw, ImageFont
from PyPDF2 import PdfFileReader, PdfFileWriter from PyPDF2 import PdfFileReader, PdfFileWriter
import fitz # = PyMuPDF : To convert pdf to png
import subprocess import subprocess
from shutil import copyfile, move from shutil import copyfile
from pyfiglet import Figlet from pyfiglet import Figlet
from colorama import init from colorama import init
from termcolor import colored from termcolor import colored
version = '3.2' # dev/devnocam version = '1.0'
configdir = os.path.join(os.getenv('PROGRAMDATA'), 'IFPass') computer = '' # 'test', 'mediatheque' or 'accueil'
config = os.path.join(configdir, 'IFPass.conf')
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'
def initialisation(): @contextmanager
conf = configparser.ConfigParser() def HideOutput(to=os.devnull):
conf.optionxform = str # For case sensitive config file fd = sys.stdout.fileno()
if not os.path.exists(config): # Check if config file exists def _redirect_stdout(to):
print('Fichier de configuration introuvable.') sys.stdout.close() # + implicit flush()
IFPassDBdir = input(r'Quel est le répertoire de la base de données IFPass ? (Ex : \\192.168.1.1\IFPass) : ') os.dup2(to.fileno(), fd) # fd writes to 'to' file
printername = input("Quel est le nom de l'imprimante à cartes ? : ") sys.stdout = os.fdopen(fd, 'w') # Python writes to fd
adobex86 = os.path.join(os.getenv('PROGRAMFILES(x86)'), 'Adobe', "Acrobat Reader DC", "Reader", "AcroRd32.exe")
adobex64 = os.path.join(os.getenv('PROGRAMFILES'), 'Adobe', "Acrobat Reader DC", "Reader", "AcroRd32.exe")
if os.path.exists(adobex86):
AcrobatReader = adobex86
elif os.path.exists(adobex64):
AcrobatReader = adobex64
else:
acrinstalled = yes_or_no("Acrobat Reader est nécessaire pour imprimer les cartes. Est il installé ?")
if acrinstalled:
while "Wrong path":
AcrobatReader = input(r"Quel est le chemin vers Acrobat Reader ? ( Ex : C:\Program Files (x86)\Adobe\Acrobat Reader DC\Reader\AcroRd32.exe) : ")
if os.path.exists(AcrobatReader):
break
else:
print(colored('\nChemin invalide !', 'red'))
else:
print(colored('\nInstallez Acrobat Reader, puis relancez IFPass.', 'red'))
os.system("pause")
sys.exit()
conf['DEFAULT'] = {'IFPassDBdir': IFPassDBdir, 'printername': printername, 'AcrobatReader': AcrobatReader}
os.makedirs(configdir, 0o777)
with open(config, 'w') as configfile:
conf.write(configfile)
else:
conf.read(config)
IFPassDBdir = conf['DEFAULT']['IFPassDBdir']
printername = conf['DEFAULT']['printername']
AcrobatReader = conf['DEFAULT']['AcrobatReader']
clientsfile = os.path.join(IFPassDBdir, 'Clients_IFPass.csv') with os.fdopen(os.dup(fd), 'w') as old_stdout:
clientsbkpfile = os.path.join(IFPassDBdir, 'Clients_IFPass_backup.csv') with open(to, 'w') as file:
imgdir = os.path.join(IFPassDBdir, 'Cartes') _redirect_stdout(to=file)
templatesdir = os.path.join(IFPassDBdir, 'Templates') try:
pdftemplate = os.path.join(templatesdir, 'IFPass_PDF_Template.pdf') yield # allow code to be run with the redirected stdout
pngtemplate = os.path.join(templatesdir, 'IFPass_PNG_Template.png') finally:
fonttemplate = os.path.join(templatesdir, 'Roboto-Bold.ttf') _redirect_stdout(to=old_stdout) # restore stdout. # cv2.selectROI
if not os.path.exists(imgdir): # Cartes dir creation if it doesn't exist
os.makedirs(imgdir, 0o777)
if not os.path.exists(clientsfile): # Creation Clients_File if it doesn't exist
with open(clientsfile, 'w', newline='', encoding='utf-8') as csvfile:
writer = csv.writer(csvfile, delimiter=';')
writer.writerow(['Titre', 'Prénom', 'Nom', 'Numéro de client', "Date d'inscription", "Date d'expiration"])
if not os.path.exists(templatesdir):
move('Templates', IFPassDBdir)
return IFPassDBdir, printername, AcrobatReader, clientsfile, clientsbkpfile, imgdir, templatesdir, pdftemplate, pngtemplate, fonttemplate
def get_fullname(**kwargs): # **kwargs => Optionnal arguments def get_fullname():
if 'firstname' in kwargs: firstname = input("Prénom : ").strip()
firstname = kwargs['firstname']
newfirstname = input("Prénom (" + firstname + "): ").strip()
if len(newfirstname) != 0:
firstname = newfirstname
else:
while "Empty firstname":
firstname = input("Prénom : ").strip()
if len(firstname) == 0:
os.system('cls')
print(colored("\nLe Prénom ne peut pas être vide.", 'red'))
else:
break
firstname = firstname[0].upper() + firstname[1:].lower() firstname = firstname[0].upper() + firstname[1:].lower()
if '-' in firstname: if '-' in firstname:
pos = firstname.find("-") pos = firstname.find("-")
@ -109,29 +78,15 @@ def get_fullname(**kwargs): # **kwargs => Optionnal arguments
pos = firstname.find(" ") pos = firstname.find(" ")
firstname = firstname[:pos + 1] + firstname[pos + 1].upper() + \ firstname = firstname[:pos + 1] + firstname[pos + 1].upper() + \
firstname[pos + 2:] # Check if compound name firstname[pos + 2:] # Check if compound name
surname = input("Nom : ").upper().strip()
if 'surname' in kwargs:
surname = kwargs['surname']
newsurname = input("Nom (" + surname + "): ").strip()
if len(newsurname) != 0:
surname = newsurname
else:
while "Empty surname":
surname = input("Nom : ").strip()
if len(surname) == 0:
os.system('cls')
print(colored("\nLe Nom ne peut pas être vide.", 'red'))
else:
break
surname = surname.upper()
docteur = yes_or_no('Est-ce un Docteur ?') docteur = yes_or_no('Est-ce un Docteur ?')
if docteur: if docteur:
titre = 'Dr.' titre = 'Dr.'
titrename = titre + ' ' + surname fullname = titre + ' ' + surname + ' ' + firstname
else: else:
titre = '' titre = ''
titrename = surname fullname = surname + ' ' + firstname
return titre, firstname, surname, titrename return titre, firstname, surname, fullname
def yes_or_no(question): def yes_or_no(question):
@ -152,12 +107,13 @@ def getclientID():
else: else:
clientID = str(int(lastID) + 1).zfill(10) clientID = str(int(lastID) + 1).zfill(10)
writeindb(clientID)
return clientID return clientID
def barcode_gen(clientID): def barcode_gen(clientID):
print("Génération du code barre... ", end='') print("Génération du code barre... ", end='')
barcode = code128.image(clientID, thickness=4) # .save(imgdir + clientID + '.png') barcode = code128.image(clientID, thickness=4) # .save(imgdir + clientID + '.png')
print(colored('[OK]', 'green')) print(colored('[OK]', 'green'))
return barcode return barcode
@ -171,29 +127,29 @@ def getpic():
try: try:
ret, frame = cap.read() ret, frame = cap.read()
cv2.rectangle(frame, (170, 73), (470, 407), (0, 255, 0), 2) 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) cv2.imshow('IFCamera - Touche Espace pour prendre la photo, Echap pour une carte sans photo, Q pour quitter.',
frame)
except cv2.error: except cv2.error:
print(colored('\nLa webcam est débranchée. Branchez-la, puis relancez le programme.', 'red')) print('\nLa webcam est débranchée. Branchez-la, puis relancez le programme.')
os.system("pause") os.system("pause")
sys.exit() sys.exit(0)
SetForegroundWindow(find_window(title='IFCamera - Touche Espace ' SetForegroundWindow(find_window(title='IFCamera - Touche Espace '
'pour prendre la photo, Echap pour une carte sans photo, Q pour quitter.')) 'pour prendre la photo, Echap pour une carte sans photo, Q pour quitter.'))
k = cv2.waitKey(1) k = cv2.waitKey(1)
if k == 27: # Echap if k == 27: # Echap
cap.release()
print(colored('[OK]', 'green')) print(colored('[OK]', 'green'))
cv2.destroyAllWindows() cv2.destroyAllWindows()
defaultpicture = os.path.join(IFPassDBdir, 'Templates', 'default_avatar.jpg') defaultpicture = IFPassdir + 'Templates\default_avatar.jpg'
picture = Image.open(defaultpicture) picture = Image.open(defaultpicture)
return picture return picture
elif k & 0xFF == ord(' '): # Space elif k & 0xFF == ord(' '): # Space
cap.release()
cv2.destroyAllWindows()
break break
elif k & 0xFF == ord('q'): # Q or q to quit elif k & 0xFF == ord('q'): # Q or q to quit
cap.release() cap.release()
cv2.destroyAllWindows() cv2.destroyAllWindows()
sys.exit() sys.exit()
cap.release()
cv2.destroyAllWindows()
cropped = frame[75:405, 172:468] cropped = frame[75:405, 172:468]
cv2.imshow('IFCamera - Espace pour valider, Echap pour modifier, Q pour quitter', cropped) cv2.imshow('IFCamera - Espace pour valider, Echap pour modifier, Q pour quitter', cropped)
while True: while True:
@ -211,73 +167,44 @@ def getpic():
picture = Image.fromarray(cropped) picture = Image.fromarray(cropped)
return picture return picture
elif k & 0xFF == ord('q'): # Q or q to quit elif k & 0xFF == ord('q'): # Q or q to quit
cv2.destroyAllWindows() cv2.destroyAllWindows()
sys.exit() sys.exit()
def writeindb(titre, firstname, surname, clientID, dateinsc, dateexp, new): def writeindb(clientID):
if new is True: print("Ajout dans la base de données... ", end="")
print("Ajout dans la base de données... ", end="") with open(clientsfile, 'a', newline='', encoding='utf-8') as csvfile:
with open(clientsfile, 'a', newline='', encoding='utf-8') as csvfile: writer = csv.writer(csvfile, delimiter=';')
writer = csv.writer(csvfile, delimiter=';') writer.writerow([titre, firstname, surname, clientID, dateinsc, dateexp])
writer.writerow([titre, firstname, surname, clientID, dateinsc, dateexp]) print(colored('[OK]', 'green'))
print(colored('[OK]', 'green'))
elif new is False:
print("Modification de la base de données... ", end="")
with open(clientsfile, 'r+', newline='', encoding='utf-8') as csvfile:
content = csvfile.readlines()
for index, member in enumerate(content):
member = member.split(';')
if member[3] == clientID:
tochange = index
break
content.pop(tochange)
changewith = ";".join([titre, firstname, surname, clientID, dateinsc, dateexp]) + '\n'
content.insert(tochange, changewith)
content = "".join(content)
csvfile.seek(0)
csvfile.truncate(0)
csvfile.write(content)
print(colored('[OK]', 'green'))
def bkpdb(): def bkpdb():
copyfile(clientsfile, clientsbkpfile) copyfile(clientsfile, clientsbkpfile)
def fillcard(clientID, titrename, firstname, dateexp, barcode, picture): def fillcard(barcode):
print("Création du verso de la carte avec les informations...", end='') print("Création de la carte avec les informations...", end='')
try: im = Image.open(pngtemplate)
im = Image.open(pngtemplate)
except FileNotFoundError:
os.system('cls')
print(colored('Vous avez besoin de 2 fichiers dans le dossier Templates pour générer des cartes :', 'red'))
print(templatesdir + '\\IFPass_PDF_Template.pdf : Modèle de la carte (recto et verso)')
print(templatesdir + '\\IFPass_PNG_Template.png : La face avant de la carte (celle à remplir)')
os.system("pause")
sys.exit()
draw = ImageDraw.Draw(im) draw = ImageDraw.Draw(im)
# Name embedding : # Name embedding :
font = ImageFont.truetype(fonttemplate, 40) font = ImageFont.truetype(fonttemplate, 45)
draw.text((401, 296), titrename, fill=(0, 0, 0), font=font) draw.text((401, 310), fullname, fill=(0,0,0), font=font)
draw.text((401, 334), firstname, fill=(0, 0, 0), font=font)
# Date embedding : # Date embedding :
font = ImageFont.truetype(fonttemplate, 30) font = ImageFont.truetype(fonttemplate, 30)
draw.text((401, 400), dateexp, fill=(0, 0, 0), font=font) draw.text((401, 390), dateexp, fill=(0,0,0), font=font)
# ID embedding : # ID embedding :
font = ImageFont.truetype('arial.ttf', 30) font = ImageFont.truetype('arial.ttf', 30)
draw.text((693, 560), clientID, fill=(0, 0, 0), font=font) draw.text((693, 560), clientID, fill=(0,0,0), font=font)
# Barcode + picture embedding : # Barcode + picture embedding :
im.paste(barcode, (556, 460)) im.paste(barcode,(556, 460))
im.paste(picture,(47, 49))
if version != 'devnocam':
im.paste(picture, (47, 49))
# Create PDF : # Create PDF :
im = im.convert("RGB") im = im.convert("RGB")
@ -286,9 +213,8 @@ def fillcard(clientID, titrename, firstname, dateexp, barcode, picture):
print(colored('[OK]', 'green')) print(colored('[OK]', 'green'))
def mergepdf(clientID): def mergepdf():
print("Fusion du recto et du verso de la carte...", end='') cartefilename = imgdir + clientID + '.pdf'
cartefilename = os.path.join(imgdir, clientID + '.pdf')
output = PdfFileWriter() output = PdfFileWriter()
pdf1 = PdfFileReader(imgdir + clientID + '_Front.pdf', 'rb') pdf1 = PdfFileReader(imgdir + clientID + '_Front.pdf', 'rb')
@ -303,261 +229,55 @@ def mergepdf(clientID):
output.write(f) output.write(f)
os.remove(imgdir + clientID + '_Front.pdf') os.remove(imgdir + clientID + '_Front.pdf')
print(colored('[OK]', 'green'))
return cartefilename return cartefilename
def printcard(cartefilename): def printcard(cartefilename):
# Working : subprocess.Popen('"C:\Program Files (x86)\Adobe\Acrobat Reader DC\Reader\AcroRd32.exe" /h /n /t ' + cartefilename + ' '+ printername, shell=False) # CMD : "C:\Program Files (x86)\Adobe\Acrobat Reader DC\Reader\AcroRd32.exe" /h /n /t Carte.pdf "XPS Pink Card Printer"
subprocess.Popen('"' + AcrobatReader + '"' + ' /h /n /t ' + cartefilename + ' ' + printername, shell=False) subprocess.Popen('"C:\Program Files (x86)\Adobe\Acrobat Reader DC\Reader\AcroRd32.exe" /h /n /t ' + cartefilename + printername, shell=False)
print('test')
def getdateexp(): while "the informations are incorrect": # Loop Filling informations
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')
return dateexp
def newmember():
while "the informations are incorrect": # Loop Filling informations
os.system('cls')
titre, firstname, surname, titrename = 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:
dateexp = getdateexp()
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')
if version != 'devnocam':
picture = getpic()
clientID = getclientID()
barcode = barcode_gen(clientID)
fillcard(clientID, titrename, firstname, dateexp, barcode, picture)
cartefilename = mergepdf(clientID)
if version not in ('dev', 'devnocam'):
bkpdb()
printcard(cartefilename)
writeindb(titre, firstname, surname, clientID, dateinsc, dateexp, new=True)
break
def membersearch():
with open(clientsfile, 'r', newline='', encoding='utf-8') as csvfile:
reader = csv.reader(csvfile, delimiter=';')
csvlist = list(map(list, reader))
del csvlist[0] # We dele the first line (Prénom, Nom...)
research = input('Entrez une partie du nom, prénom, ou numéro de carte (ou flashez) : ').lower()
os.system('cls') os.system('cls')
results = [] 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)
for member in csvlist: dateinsc = dateinsc.strftime('%d/%m/%Y')
resfirstname = member[1].lower() dateexp = dateexp.strftime('%d/%m/%Y')
ressurname = member[2].lower() changeexp = yes_or_no('Voulez-vous choisir la date d\'expiration ?')
resnumber = member[3] if changeexp:
if any(research in data for data in [resfirstname, ressurname, resnumber]): while True:
results.append(member) 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 results: if match:
if len(results) == 1: break
member = results[0]
else:
print('-' * 56)
print(f'{"Choix":8} {"Prénom":15} {"Nom":15} {"Numéro de carte":15}')
print('-' * 56)
for index, result in enumerate(results, start=1):
print(f'{index:^8} {result[1]:15} {result[2]:15} {result[3]:^15}')
del member
while 'The choice is not valid':
try:
memberchoice = input("De quel membre s'agit il ? (Colonne Choix) : ")
member = results[int(memberchoice) - 1]
break
except (IndexError, ValueError):
print(colored('Choix invalide ! Veillez bien à sélectionner le numéro de la colonne "Choix"', 'red', attrs=['bold']))
os.system('cls')
while 'Choix incorect':
print("Titre : ", colored(member[0], 'green'))
print("Prénom : ", colored(member[1], 'green'))
print("Nom : ", colored(member[2], 'green'))
print("Numéro de carte : ", colored(member[3], 'green'))
print("Date d'inscription :", member[4])
print("Date d'expiration : ", member[5])
dateexp = datetime.strptime(member[5], '%d/%m/%Y').date()
diff = (dateexp - date.today()).days
if diff > 0:
print(colored(f"L'abonnement est encore valable {diff} jours.", 'green', attrs=['bold']))
elif diff < 0:
print(colored(f"L'abonnement est expiré depuis {abs(diff)} jours.", 'red', attrs=['bold'])) # abs() to remove minus sign
elif diff == 0:
print(colored("Il s'agit du dernier jour de l'abonnement, il expirera demain.", 'yellow', attrs=['bold']))
print('\n1 - Modifier', "2 - Renouveller l'abonnement / Choisir un nouvelle date d'expiration", '3 - Imprimer la carte', '0 - Menu principal', sep='\n')
choix = input('Choix : ')
if choix == '0':
os.system('cls')
return
# We update values with new (edited) values :
newtitre, newfirstname, newsurname, newdateexp = memberdo(choix, member)
member[0], member[1], member[2], member[5] = newtitre, newfirstname, newsurname, newdateexp
else:
print(colored("Aucun membre n'a été trouvé.", 'red', attrs=['bold']))
os.system("pause")
def memberdo(choix, member):
titre = member[0]
firstname = member[1]
surname = member[2]
clientID = member[3]
dateinsc = member[4]
dateexp = member[5]
os.system('cls')
if choix == '1': # Edit member
titre, firstname, surname, dateexp = memberedit(titre, firstname, surname, clientID, dateinsc, dateexp)
elif choix == '2': # Renew subscription
changeexp = yes_or_no("Voulez-vous choisir la date d'expiration ?")
if changeexp:
dateexp = getdateexp()
else:
dateexp = datetime.strptime(dateexp, '%d/%m/%Y').date()
diff = (dateexp - date.today()).days
if diff >= 0:
dateexp = dateexp + timedelta(days=365)
elif diff < 0:
dateexp = date.today() + timedelta(days=365)
dateexp = dateexp.strftime('%d/%m/%Y')
if titre == 'Dr.':
titrename = titre + ' ' + surname
else:
titrename = surname
wantnewpic = yes_or_no("Voulez-vous prendre une nouvelle photo ?")
os.system('cls')
if wantnewpic:
os.system('cls')
if version != 'devnocam':
picture = getpic()
else:
# We crop pic from the previous card
cartefilename = os.path.join(imgdir, clientID + '.pdf')
pdf = fitz.open(cartefilename)
page = pdf.loadPage(0)
mat = fitz.Matrix(4.165, 4.165) # To obtain good resolution
pix = page.getPixmap(matrix=mat)
pageimg = Image.frombytes("RGBA", [pix.width, pix.height], pix.samples)
picture = pageimg.crop((47, 49, 343, 378))
barcode = barcode_gen(clientID)
fillcard(clientID, titrename, firstname, dateexp, barcode, picture)
cartefilename = mergepdf(clientID)
if version not in ('dev', 'devnocam'):
bkpdb()
printcard(cartefilename)
writeindb(titre, firstname, surname, clientID, dateinsc, dateexp, new=False)
os.system('cls')
print(colored("La date d'expiration a bien été mise à jour !\n", 'blue', attrs=['bold']))
elif choix == '3': # Print card
cartefilename = os.path.join(imgdir, clientID + '.pdf')
printcard(cartefilename)
else:
print(colored('Choix incorrect !\n', 'red', attrs=['bold']))
return titre, firstname, surname, dateexp
def memberedit(titre, firstname, surname, clientID, dateinsc, dateexp):
while "the informations are incorrect": # Loop Filling informations
titre, firstname, surname, titrename = get_fullname(titre=titre, firstname=firstname, surname=surname)
print("Titre : ", colored(titre, 'green'))
print("Prénom : ", colored(firstname, 'green'))
print("Nom : ", colored(surname, 'green'))
correct = yes_or_no("Ces informations sont elles correctes ?")
os.system('cls')
if correct:
wantnewpic = yes_or_no("Voulez-vous prendre une nouvelle photo ?")
os.system('cls')
if wantnewpic:
os.system('cls')
if version != 'devnocam':
picture = getpic()
else: else:
# We crop pic from the previous card print('Mauvais format ! JJ/MM/AAAA, exemple : 01/08/2042')
cartefilename = os.path.join(imgdir, clientID + '.pdf')
pdf = fitz.open(cartefilename)
page = pdf.loadPage(0)
mat = fitz.Matrix(4.165, 4.165) # To obtain good resolution
pix = page.getPixmap(matrix=mat)
pageimg = Image.frombytes("RGBA", [pix.width, pix.height], pix.samples) os.system('cls')
picture = pageimg.crop((47, 49, 343, 378)) print("Titre : ", colored(titre, 'green'))
print("Prénom : ", colored(firstname, 'green'))
barcode = barcode_gen(clientID) print("Nom : ", colored(surname, 'green'))
fillcard(clientID, titrename, firstname, dateexp, barcode, picture) print("Date d'inscription :", colored(dateinsc, 'green'))
cartefilename = mergepdf(clientID) print("Date d'expiration : ", colored(dateexp, 'green'))
if version not in ('dev', 'devnocam'): correct = yes_or_no("Ces informations sont elles correctes ?")
bkpdb()
printcard(cartefilename)
writeindb(titre, firstname, surname, clientID, dateinsc, dateexp, new=False)
os.system('cls')
break
return titre, firstname, surname, dateexp
def main():
global IFPassDBdir, clientsfile, imgdir, clientsbkpfile, templatesdir, pngtemplate, fonttemplate, pdftemplate, printername, AcrobatReader
while "The program is running":
init() # Initialisation of colorama
IFPassDBdir, printername, AcrobatReader, clientsfile, clientsbkpfile, imgdir, templatesdir, pdftemplate, pngtemplate, fonttemplate = initialisation()
if correct:
os.system('cls') os.system('cls')
f = Figlet(font='big') picture = getpic()
print(colored(f.renderText('IFPass'), 'cyan', attrs=['bold'])) clientID = getclientID()
print('Version : ', version) barcode = barcode_gen(clientID)
if version in ('dev', 'devnocam'): fillcard(barcode)
print(colored("\nATTENTION : Il s'agit d'une version en cours de développement, potentiellement instable !", 'red')) cartefilename = mergepdf()
print("\nCe programme est developpé par par Jordan ERNST pour l'Institut Français en Hongrie.") bkpdb()
print("Il est disponible sou licence MIT à cette addresse : https://framagit.org/SecT0uch/IFPass\n") if computer == 'mediatheque' or computer == 'accueil':
print('Pour toute question, problème ou requête contactez-moi à pro.ernst@gmail.com.\n') printcard(cartefilename)
print('1 - Nouveau membre', '2 - Rechercher un membre', '0 - Quitter', sep='\n')
choix = input('Choix : ')
if choix == '1':
newmember()
elif choix == '2':
os.system('cls')
membersearch()
elif choix == '0':
sys.exit()
else:
os.system('cls')
print(colored('Choix incorrect !', 'red', attrs=['bold']))

5
INSTALL.txt Normal file
View File

@ -0,0 +1,5 @@
-Installer python 3.6 VERSION 64 bits : https://www.python.org/ftp/python/3.6.4/python-3.6.4-amd64-webinstall.exe
-Téléchargez (cp36 pour Python 3.6) : https://www.lfd.uci.edu/~gohlke/pythonlibs/#opencv
-Installer les modules python termcolor, colorama, pyfiglet, code128, Pillow, numpy, pywinauto, PyPDF2 et opencv:
-Lancer cmd.exe en tant qu'admin
-Exécuter : pip install termcolor colorama pyfiglet code128 Pillow pywinauto PyPDF2 numpy C:\path\to\opencv_python-3.4.0-cp36-cp36m-win_amd64.whl

View File

@ -1,189 +0,0 @@
!define PRODUCT_NAME "[[ib.appname]]"
!define PRODUCT_VERSION "[[ib.version]]"
!define PY_VERSION "[[ib.py_version]]"
!define PY_MAJOR_VERSION "[[ib.py_major_version]]"
!define BITNESS "[[ib.py_bitness]]"
!define ARCH_TAG "[[arch_tag]]"
!define INSTALLER_NAME "[[ib.installer_name]]"
!define PRODUCT_ICON "[[icon]]"
; Marker file to tell the uninstaller that it's a user installation
!define USER_INSTALL_MARKER _user_install_marker
Unicode true
InstallDir "C:\IFPass"
SetCompressor lzma
[% block modernui %]
; Modern UI installer stuff
!include "MUI2.nsh"
!define MUI_ABORTWARNING
!define MUI_ICON "[[icon]]"
!define MUI_UNICON "[[icon]]"
; UI pages
[% block ui_pages %]
!insertmacro MUI_PAGE_WELCOME
[% if license_file %]
!insertmacro MUI_PAGE_LICENSE [[license_file]]
[% endif %]
!insertmacro MUI_PAGE_INSTFILES
!insertmacro MUI_PAGE_FINISH
[% endblock ui_pages %]
!insertmacro MUI_LANGUAGE "French"
[% endblock modernui %]
Name "${PRODUCT_NAME} ${PRODUCT_VERSION}"
OutFile "${INSTALLER_NAME}"
ShowInstDetails show
Section -SETTINGS
SetOutPath "$INSTDIR"
SetOverwrite ifnewer
SectionEnd
[% block sections %]
Section "!${PRODUCT_NAME}" sec_app
SetRegView [[ib.py_bitness]]
SetShellVarContext all
SectionIn RO
File ${PRODUCT_ICON}
SetOutPath "$INSTDIR\pkgs"
File /r "pkgs\*.*"
SetOutPath "$INSTDIR"
[% block install_files %]
; Install files
[% for destination, group in grouped_files %]
SetOutPath "[[destination]]"
[% for file in group %]
File "[[ file ]]"
[% endfor %]
[% endfor %]
; Install directories
[% for dir, destination in ib.install_dirs %]
SetOutPath "[[ pjoin(destination, dir) ]]"
File /r "[[dir]]\*.*"
[% endfor %]
[% endblock install_files %]
[% block install_shortcuts %]
; Install shortcuts
; The output path becomes the working directory for shortcuts
SetOutPath "$INSTDIR"
[% if single_shortcut %]
[% for scname, sc in ib.shortcuts.items() %]
CreateShortCut "$SMPROGRAMS\[[scname]].lnk" "[[sc['target'] ]]" \
'[[ sc['parameters'] ]]' "$INSTDIR\[[ sc['icon'] ]]"
CreateShortCut "$DESKTOP\[[scname]].lnk" "[[sc['target'] ]]" \
'[[ sc['parameters'] ]]' "$INSTDIR\[[ sc['icon'] ]]"
[% endfor %]
[% else %]
[# Multiple shortcuts: create a directory for them #]
CreateDirectory "$SMPROGRAMS\${PRODUCT_NAME}"
[% for scname, sc in ib.shortcuts.items() %]
CreateShortCut "$SMPROGRAMS\${PRODUCT_NAME}\[[scname]].lnk" "[[sc['target'] ]]" \
'[[ sc['parameters'] ]]' "$INSTDIR\[[ sc['icon'] ]]"
[% endfor %]
[% endif %]
SetOutPath "$INSTDIR"
[% endblock install_shortcuts %]
[% block install_commands %]
[% if has_commands %]
DetailPrint "Setting up command-line launchers..."
nsExec::ExecToLog '[[ python ]] -Es "$INSTDIR\_assemble_launchers.py" "$INSTDIR\bin"'
[% endif %]
[% endblock install_commands %]
; Byte-compile Python files.
DetailPrint "Byte-compiling Python modules..."
nsExec::ExecToLog '[[ python ]] -m compileall -q "$INSTDIR\pkgs"'
WriteUninstaller $INSTDIR\uninstall.exe
; Add ourselves to Add/remove programs
WriteRegStr SHCTX "Software\Microsoft\Windows\CurrentVersion\Uninstall\${PRODUCT_NAME}" \
"DisplayName" "${PRODUCT_NAME}"
WriteRegStr SHCTX "Software\Microsoft\Windows\CurrentVersion\Uninstall\${PRODUCT_NAME}" \
"UninstallString" '"$INSTDIR\uninstall.exe"'
WriteRegStr SHCTX "Software\Microsoft\Windows\CurrentVersion\Uninstall\${PRODUCT_NAME}" \
"InstallLocation" "$INSTDIR"
WriteRegStr SHCTX "Software\Microsoft\Windows\CurrentVersion\Uninstall\${PRODUCT_NAME}" \
"DisplayIcon" "$INSTDIR\${PRODUCT_ICON}"
[% if ib.publisher is not none %]
WriteRegStr SHCTX "Software\Microsoft\Windows\CurrentVersion\Uninstall\${PRODUCT_NAME}" \
"Publisher" "[[ib.publisher]]"
[% endif %]
WriteRegStr SHCTX "Software\Microsoft\Windows\CurrentVersion\Uninstall\${PRODUCT_NAME}" \
"DisplayVersion" "${PRODUCT_VERSION}"
WriteRegDWORD SHCTX "Software\Microsoft\Windows\CurrentVersion\Uninstall\${PRODUCT_NAME}" \
"NoModify" 1
WriteRegDWORD SHCTX "Software\Microsoft\Windows\CurrentVersion\Uninstall\${PRODUCT_NAME}" \
"NoRepair" 1
; Check if we need to reboot
IfRebootFlag 0 noreboot
MessageBox MB_YESNO "A reboot is required to finish the installation. Do you wish to reboot now?" \
/SD IDNO IDNO noreboot
Reboot
noreboot:
SectionEnd
Section "Uninstall"
SetRegView [[ib.py_bitness]]
SetShellVarContext all
Delete $INSTDIR\uninstall.exe
Delete "$INSTDIR\${PRODUCT_ICON}"
RMDir /r "$INSTDIR\pkgs"
; Remove ourselves from %PATH%
[% block uninstall_commands %]
[% if has_commands %]
nsExec::ExecToLog '[[ python ]] -Es "$INSTDIR\_system_path.py" remove "$INSTDIR\bin"'
[% endif %]
[% endblock uninstall_commands %]
[% block uninstall_files %]
; Uninstall files
[% for file, destination in ib.install_files %]
Delete "[[pjoin(destination, file)]]"
[% endfor %]
; Uninstall directories
[% for dir, destination in ib.install_dirs %]
RMDir /r "[[pjoin(destination, dir)]]"
[% endfor %]
[% endblock uninstall_files %]
[% block uninstall_shortcuts %]
; Uninstall shortcuts
[% if single_shortcut %]
[% for scname in ib.shortcuts %]
Delete "$SMPROGRAMS\[[scname]].lnk"
Delete "$DESKTOP\[[scname]].lnk"
[% endfor %]
[% else %]
RMDir /r "$SMPROGRAMS\${PRODUCT_NAME}"
[% endif %]
[% endblock uninstall_shortcuts %]
RMDir $INSTDIR
DeleteRegKey SHCTX "Software\Microsoft\Windows\CurrentVersion\Uninstall\${PRODUCT_NAME}"
SectionEnd
[% endblock sections %]
; Functions
Function .onMouseOverSection
; Find which section the mouse is over, and set the corresponding description.
FindWindow $R0 "#32770" "" $HWNDPARENT
GetDlgItem $R0 $R0 1043 ; description item (must be added to the UI)
[% block mouseover_messages %]
StrCmp $0 ${sec_app} "" +2
SendMessage $R0 ${WM_SETTEXT} 0 "STR:${PRODUCT_NAME}"
[% endblock mouseover_messages %]
FunctionEnd

View File

@ -1,7 +0,0 @@
Copyright © 2018 "Institut Français en Hongrie"
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

View File

@ -1,12 +0,0 @@
# IFPass
IFPass is a python project developped for the "Institut Français en Hongrie" and published under [MIT license](https://framagit.org/SecT0uch/IFPass/blob/master/LICENSE).
It allows to manage a subscriber database and print member cards.
## Build
1. Install [NSIS](http://nsis.sourceforge.net/Download).
2. Install python 3 and pip.
3. Install the modules with `sudo -H pip install pynsist PyPDF2 termcolor`
4. If pynsist version < 2.4, replace `/usr/lib/python3.*/site-packages/nsist/__init__.py` with https://raw.githubusercontent.com/takluyver/pynsist/master/nsist/__init__.py
5. Run `./build.sh`

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

View File

@ -1,3 +0,0 @@
Here you need two files :
* IFPass_PDF_Template.pdf : Template of the card (both sides)
* IFPass_PNG_Template.png : First side of the card (the one to fill up)

BIN
Templates/Thumbs.db Normal file

Binary file not shown.

View File

@ -1,3 +0,0 @@
#!/usr/bin/bash
pynsist installer-x86.cfg
pynsist installer-x64.cfg

Binary file not shown.

Binary file not shown.

View File

@ -1,59 +0,0 @@
[Application]
name=IFPass
version=3.2
entry_point=IFPass:main
icon=IF.ico
console=true
license_file=LICENSE
[Python]
version=3.7.3
bitness=64
[Include]
# Packages from PyPI that your application requires, one per line
# These must have wheels on PyPI:
# https://pypi.org/project/code128/
# https://pypi.org/project/colorama/
# https://pypi.org/project/pyfiglet/
# https://pypi.org/project/numpy/
# https://pypi.org/project/opencv-python/
# https://pypi.org/project/Pillow/
# https://pypi.org/project/pywin32/
# https://pypi.org/project/six/
# https://pypi.org/project/setuptools/
# https://pypi.org/project/PyMuPDF/
# https://pypi.org/project/pywinauto/
pypi_wheels=code128==0.3
colorama==0.4.1
pyfiglet==0.8.post1
numpy==1.16.4
opencv-python==4.1.0.25
Pillow==6.0.0
pywin32==224
six==1.12.0
setuptools==41.0.1
PyMuPDF==1.14.16
pywinauto==0.6.6
# Must check if future updates of the following packages provide .whl files
# Packages without wheels (Must be installed locally):
packages=PyPDF2
termcolor
# Other files and folders that should be installed
files = LICENSE
Templates
# This optional section adds a command which can be run from the Windows
# command prompt.
[Command IFPass]
entry_point=IFPass:main
[Build]
directory=build/x64
installer_name=${PRODUCT_NAME}_${PRODUCT_VERSION}-x64.exe
# Custom Installer :
# Added Desktop shortcut, modified working directory, modified default install and utf-8...
nsi_template=Installer_Template.nsi

View File

@ -1,59 +0,0 @@
[Application]
name=IFPass
version=3.2
entry_point=IFPass:main
icon=IF.ico
console=true
license_file=LICENSE
[Python]
version=3.7.3
bitness=32
[Include]
# Packages from PyPI that your application requires, one per line
# These must have wheels on PyPI:
# https://pypi.org/project/code128/
# https://pypi.org/project/colorama/
# https://pypi.org/project/pyfiglet/
# https://pypi.org/project/numpy/
# https://pypi.org/project/opencv-python/
# https://pypi.org/project/Pillow/
# https://pypi.org/project/pywin32/
# https://pypi.org/project/six/
# https://pypi.org/project/setuptools/
# https://pypi.org/project/PyMuPDF/
# https://pypi.org/project/pywinauto/
pypi_wheels=code128==0.3
colorama==0.4.1
pyfiglet==0.8.post1
numpy==1.16.4
opencv-python==4.1.0.25
Pillow==6.0.0
pywin32==224
six==1.12.0
setuptools==41.0.1
PyMuPDF==1.14.16
pywinauto==0.6.6
# Must check if future updates of the following packages provide .whl files
# Packages without wheels (Must be installed locally):
packages=PyPDF2
termcolor
# Other files and folders that should be installed
files = LICENSE
Templates
# This optional section adds a command which can be run from the Windows
# command prompt.
[Command IFPass]
entry_point=IFPass:main
[Build]
directory=build/x86
installer_name=${PRODUCT_NAME}_${PRODUCT_VERSION}-x86.exe
# Custom Installer :
# Added Desktop shortcut, modified working directory, modified default install and utf-8...
nsi_template=Installer_Template.nsi