Update code to better handle the raspberry pi mode

This commit is contained in:
nono 2025-10-17 17:33:53 +02:00
parent 34bffe93af
commit 670ab495d8
3 changed files with 191 additions and 60 deletions

View File

@ -98,46 +98,37 @@ class Printer(object):
return True return True
def print_sms(self, msg, signature="Guest") -> None: def print_sms(self, msg, signature="",bold=False):
clean_msg = str(msg) clean_msg = str(msg) + "\n"
clean_signature = str(signature) clean_signature = str(signature)
if len(clean_msg) > 4096 or len(clean_msg) < 3 : if len(clean_msg) > 4096:
self.app.logger.warning("Could not print message of this length: " + str(len(clean_msg))) self.app.logger.warning("Could not print message of this length: " + str(len(clean_msg)))
raise Exception("Could not print message of this length :" + str(len(clean_msg)) + ", needs to between 3 and 4096 caracters long.") raise Exception("Could not print message of this length :" + str(len(clean_msg)) + ", needs to be below 4096 caracters long.")
if len(signature) > 256 or len(signature) < 1: if len(signature) > 256:
self.app.logger.warning("Could not print signature of this length: " + str(len(clean_signature))) self.app.logger.warning("Could not print signature of this length: " + str(len(clean_signature)))
raise Exception("Could not print signature of this length :" + str(len(clean_signature)) + ", needs to between 3 and 256 caracters long.") raise Exception("Could not print signature of this length :" + str(len(clean_signature)) + ", needs to be below 256 caracters long.")
self.check_paper()
try: try:
self.printer.open(self.usb_args); self.printer.open(self.usb_args);
self.printer.set(align='left', font='a', bold=False, underline=0, width=1, height=1, density=8, invert=False, smooth=True, flip=False, double_width=False, double_height=False, custom_size=False) self.printer.set(align='center', font='a', bold=bold)
self.printer.set(align='left', font='a', bold=True, underline=1, width=1, height=1, density=6, invert=False, smooth=True, flip=False, double_width=False, double_height=False, custom_size=False) self.printer.textln(clean_msg )
self.printer.textln(clean_msg) if clean_signature:
self.printer.textln("") self.printer.textln(clean_signature )
self.printer.set(align='left', font='b', bold=False, underline=1, width=1, height=1, density=9, invert=False, smooth=True, flip=False, double_width=False, double_height=False, custom_size=False)
self.printer.textln("> " + clean_signature + " @ " + strftime("%Y-%m-%d %H:%M:%S", gmtime()))
self.printer.textln("")
self.printer.textln("Printed by LittlePrinter ")
self.printer.textln("n07070.xyz/articles/littleprynter")
self.printer.textln("")
self.printer.cut()
self.printer.close() self.printer.close()
except Exception as e: except Exception as e:
self.app.logger.error("Unable to print because : " + str(e)) self.app.logger.error("Unable to print because : " + str(e))
raise e
self.app.logger.info("Printed text")
return True return True
def print_img(self, path, sign) -> None: def print_img(self, path, sign="",center=True,process=False):
clean_signature = str(sign) clean_signature = str(sign)
if len(sign) > 256 or len(sign) < 1: if len(sign) > 256:
self.app.logger.warning("Could not print signature of this length: " + str(len(clean_signature))) self.app.logger.warning("Could not print signature of this length: " + str(len(clean_signature)))
raise Exception("Could not print signature of this length :" + str(len(clean_signature)) + ", needs to between 3 and 256 caracters long.") raise Exception("Could not print signature of this length :" + str(len(clean_signature)) + ", needs to be below 256 caracters long.")
if not os.path.isfile(str(path)): if not os.path.isfile(str(path)):
self.app.logger.warning("File does not exist : " + str(path)) self.app.logger.warning("File does not exist : " + str(path))
@ -145,31 +136,61 @@ class Printer(object):
else: else:
self.app.logger.debug("Printing file from " + str(path)) self.app.logger.debug("Printing file from " + str(path))
if process:
try: try:
self.app.logger.debug("Proccessing the image") self.app.logger.debug("Proccessing the image")
path = process_image(self, path) path = process_image(self, path)
except Exception as e: except Exception as e:
self.app.logger.error(str(e)) self.app.logger.error(str(e))
raise e return False
else:
self.app.logger.warning("Not proccessing the image")
try: try:
self.check_paper()
self.printer.open(self.usb_args) self.printer.open(self.usb_args)
self.printer.image(path) self.printer.image(path,center=center)
self.printer.textln("Printed by LittlePrynter ")
self.printer.textln("n07070.xyz/articles/littleprynter")
self.printer.textln(clean_signature + " @ " + strftime("%Y-%m-%d %H:%M:%S", gmtime()))
self.printer.cut()
self.printer.close() self.printer.close()
self.app.logger.debug("Printed an image : " + str(path)) self.app.logger.debug("Printed an image : " + str(path))
os.remove(path) os.remove(path)
self.app.logger.debug("Removed image.") self.app.logger.debug("Removed image : " + str(path))
except Exception as e:
self.printer.close()
self.app.logger.error(str(e))
return False
self.app.logger.info("Printed a picture")
return True
def qr(self, content):
try:
self.printer.open(self.usb_args)
self.printer.qr(content, center=True)
self.printer.close()
except Exception as e:
self.printer.close()
self.app.logger.error(str(e))
return False
self.app.logger.info("Printed a QR")
return True
def cut(self):
try:
self.printer.open(self.usb_args)
self.printer.cut()
self.printer.close()
except Exception as e: except Exception as e:
self.printer.close() self.printer.close()
self.app.logger.error(str(e)) self.app.logger.error(str(e))
raise e raise e
self.app.logger.info("Did a cut")
return True
def process_image(self, path): def process_image(self, path):
brightness_factor = 1.5 # Used only if image is too dark brightness_factor = 1.5 # Used only if image is too dark
brightness_threshold = 100 # Brightness threshold (0255) brightness_threshold = 100 # Brightness threshold (0255)
@ -187,9 +208,9 @@ def process_image(self, path):
original_img.thumbnail((max_width, max_height), Image.LANCZOS) original_img.thumbnail((max_width, max_height), Image.LANCZOS)
self.app.logger.debug("Resized the image") self.app.logger.debug("Resized the image")
# Convert to grayscale for dithering # # Convert to grayscale for dithering
dithered_img = original_img.convert("L").convert("1") # Dithering using default method (FloydSteinberg) # dithered_img = original_img.convert("L").convert("1") # Dithering using default method (FloydSteinberg)
self.app.logger.debug("Dithered the image") # self.app.logger.debug("Dithered the image")
# Compute brightness of original image (grayscale average) # Compute brightness of original image (grayscale average)
grayscale = original_img.convert("L") grayscale = original_img.convert("L")
@ -204,9 +225,9 @@ def process_image(self, path):
enhancer = ImageEnhance.Brightness(original_img) enhancer = ImageEnhance.Brightness(original_img)
original_img = enhancer.enhance(brightness_factor) original_img = enhancer.enhance(brightness_factor)
# Reduce contrast # # Reduce contrast
contrast_enhancer = ImageEnhance.Contrast(original_img) # contrast_enhancer = ImageEnhance.Contrast(original_img)
original_img = contrast_enhancer.enhance(contrast_factor) # original_img = contrast_enhancer.enhance(contrast_factor)
# Final resize check # Final resize check
if original_img.height > max_height: if original_img.height > max_height:

View File

@ -1,8 +1,10 @@
from flask_socketio import SocketIO from flask_socketio import SocketIO
from gpiozero import Button, LED, DigitalOutputDevice from gpiozero import Button, LED, DigitalOutputDevice
from time import sleep from time import sleep, gmtime, strftime
from PIL import Image
import io # To check if we are on a Raspberry Pi import io # To check if we are on a Raspberry Pi
import subprocess import subprocess
import os
class Raspberry(object): class Raspberry(object):
""" """
@ -65,24 +67,16 @@ class Raspberry(object):
self.led = LED(self.led_gpio) self.led = LED(self.led_gpio)
self.app.logger.debug('Activated indicator LED') self.app.logger.debug('Activated indicator LED')
self.indicator_countdown(iters=3)
self.button = Button(self.button_gpio, pull_up=True, bounce_time=0.1) self.button = Button(self.button_gpio, pull_up=True, bounce_time=0.1)
self.button.when_pressed = self.on_button_pressed self.button.when_pressed = self.on_button_pressed
self.app.logger.debug('Activated button') self.app.logger.debug('Activated button')
# The "flash" is a relay-controlled device ( light bulb for example ) # The "flash" is a relay-controlled device ( light bulb for example )
self.flash = DigitalOutputDevice(self.flash_gpio) self.flash = DigitalOutputDevice(self.flash_gpio)
self.flash_toggle()
self.app.logger.debug('Activated flash') self.app.logger.debug('Activated flash')
def take_picture(self):
try:
subprocess.run(['fswebcam', '--no-banner', self.image_path])
except Exception as e:
self.app.logger.error('Unable to take a picture :' + str(e))
raise e
return True
def indicator_countdown(self,iters=10,multi=10): def indicator_countdown(self,iters=10,multi=10):
for i in range(iters,0,-1): for i in range(iters,0,-1):
self.led.on() self.led.on()
@ -106,17 +100,131 @@ class Raspberry(object):
self.flash.off() self.flash.off()
self.app.logger.debug("Flash turned off") self.app.logger.debug("Flash turned off")
def take_picture(self):
# Validate if the image path is valid
if not os.path.isdir(os.path.dirname(self.image_path)):
self.app.logger.error(f"Invalid directory for image path: {self.image_path}")
return False
try:
result = subprocess.run(
['fswebcam', '--no-banner', '-r', '1920x1080', self.image_path],
check=True, # Will raise CalledProcessError if the command fails
stdout=subprocess.PIPE, # Capture standard output
stderr=subprocess.PIPE # Capture error output
)
# Optionally log the command output
self.app.logger.debug(f"Image captured successfully: {result.stdout.decode()}")
except subprocess.CalledProcessError as e:
# Log error output if available
self.app.logger.error(f"Unable to take a picture. Error: {e.stderr.decode()}")
return False
except Exception as e:
# Catch any unexpected errors
self.app.logger.error(f"Unexpected error while taking picture: {str(e)}")
return False
# # Overlay logo
# logo_path = 'src/static/images/requin.png' # Update path as needed
# if not self.overlay_logo(self.image_path, logo_path):
# self.app.logger.warning("Picture taken but failed to overlay logo.")
return True
def overlay_logo(self, image_path, logo_path, output_path=None, position='bottom_right', margin=10):
try:
image = Image.open(image_path).convert("RGBA")
logo = Image.open(logo_path).convert("RGBA")
# Resize logo if it's too big (logo will be 30% the width of the image)
logo_ratio = 0.30 # You can change the ratio if you want the logo bigger or smaller
logo_width = int(image.width * logo_ratio)
logo_height = int(logo.height * (logo_width / logo.width))
logo = logo.resize((logo_width, logo_height), Image.Resampling.LANCZOS)
# Calculate position based on the chosen location
if position == 'bottom_right':
x = image.width - logo.width - margin
y = image.height - logo.height - margin
elif position == 'top_left':
x, y = margin, margin
elif position == 'top_right':
x = image.width - logo.width - margin
y = margin
elif position == 'bottom_left':
x = margin
y = image.height - logo.height - margin
else:
raise ValueError("Invalid position. Choose from 'bottom_right', 'top_left', 'top_right', or 'bottom_left'.")
# Composite the logo onto the image
image.paste(logo, (x, y), logo) # Use logo as its own alpha mask
# Save the result
if not output_path:
output_path = image_path # Overwrite the original image if no output path is given
image.save(output_path)
except Exception as e:
self.app.logger.error(f"Error overlaying logo: {e}")
return False
return True
def crop_to_square(self, image_path, output_path=None):
try:
image = Image.open(image_path)
width, height = image.size
# Determine shorter side
new_edge = min(width, height)
# Calculate cropping box (centered)
left = (width - new_edge) // 2
top = (height - new_edge) // 2
right = left + new_edge
bottom = top + new_edge
image = image.crop((left, top, right, bottom))
if not output_path:
output_path = image_path # Overwrite original
image.save(output_path)
except Exception as e:
self.app.logger.error(f"Error cropping image to square: {e}")
return False
return True
def on_button_pressed(self): def on_button_pressed(self):
self.app.logger.debug("Button has been pressed") self.app.logger.debug("Button has been pressed")
self.socketio.emit('button_pressed') # Notify clients that a button has been pressed on the raspberry pi self.led.on()
self.indicator_countdown(iters=5,multi=20) # The indicator will flash a countdown LED self.app.logger.debug("Counting down")
self.flash_toggle() self.indicator_countdown(iters=4,multi=20) # The indicator will flash a countdown LED
self.app.logger.debug("Taking picture")
try: try:
self.flash.on()
self.take_picture() self.take_picture()
self.printer.print_image(self.image_path)
self.socketio.emit('picture_taken') # Notify clients that a picture has been taken
except Exception as e: except Exception as e:
self.app.logger.error("Could not take a picture after the button press : " + str(e)) self.app.logger.error("Could not take a picture after the button press : " + str(e))
finally:
self.flash.off()
self.app.logger.debug("Printing picture")
self.led.on()
self.crop_to_square(self.image_path)
self.printer.print_img('src/static/images/extase-club.png',process=True)
self.printer.print_img(self.image_path,process=True)
self.printer.print_sms("")
self.printer.print_sms("With Love From Société.Vide",signature="",bold=True)
self.printer.print_sms("Printed by LittlePrynter",signature="")
self.printer.print_sms("n07070.xyz",signature="")
self.printer.print_sms(strftime("%Y-%m-%d %H:%M", gmtime()),signature="")
self.printer.qr("https://n07070.xyz/articles/littleprynter")
self.printer.cut()
self.led.off()
self.app.logger.debug("Done printing picture")
return True return True

View File

@ -17,6 +17,7 @@ class Web(object):
self.app.logger.debug("Printing : " + str(texte) + " from " + str(sign)) self.app.logger.debug("Printing : " + str(texte) + " from " + str(sign))
try: try:
self.printer.print_sms(texte, sign) self.printer.print_sms(texte, sign)
self.printer.cut()
except Exception as e: except Exception as e:
self.app.logger.error(e) self.app.logger.error(e)
flash("Error while printing the SMS : "+ str(e)) flash("Error while printing the SMS : "+ str(e))
@ -24,13 +25,14 @@ class Web(object):
flash("You message " + str( texte ) + " has been printed :)") flash("You message " + str( texte ) + " has been printed :)")
def print_image(self, image, sign: str): def print_image(self, image, sign):
self.app.logger.debug("Uploading file") self.app.logger.debug("Uploading file")
try: try:
self.app.logger.debug("Uploading file from " + str(sign)) self.app.logger.debug("Uploading file from " + str(sign))
if self.upload_file(image): if self.upload_file(image):
self.app.logger.debug("File has been uploaded, printing...") self.app.logger.debug("File has been uploaded, printing...")
self.printer.print_img(os.path.join(self.app.config['UPLOAD_FOLDER'], secure_filename(image.filename)), sign) self.printer.print_img(os.path.join(self.app.config['UPLOAD_FOLDER'], secure_filename(image.filename)), sign=sign,process=True)
self.printer.cut()
except Exception as e: except Exception as e:
self.app.logger.error(e) self.app.logger.error(e)
flash("Could not upload file." + str(e)) flash("Could not upload file." + str(e))