Compare commits

..

No commits in common. "3dc6a41724c0d8595008dcc81ca8c64a9625e04f" and "38b3acfb89cfe352cf36fbce6b521d2b5c07779c" have entirely different histories.

5 changed files with 56 additions and 73 deletions

View File

@ -1,36 +1,31 @@
Adafruit_Thermal==1.1.0 Adafruit-Thermal~=1.1.0
appdirs==1.4.4 appdirs~=1.4.4
argcomplete==2.0.6 argcomplete~=2.0.0
cffi==1.17.1 click~=8.1.3
click==8.1.8 commonmark~=0.9.1
commonmark==0.9.1 Deprecated~=1.2.13
cryptography==45.0.4 escpos~=2.0.0
Deprecated==1.2.18 Flask~=2.1.2
escpos==2.0.0 Flask-Limiter~=2.4.5.1
Flask==2.1.3 future~=0.18.2
Flask-Limiter==2.4.5.1 itsdangerous~=2.1.2
future==0.18.3 Jinja2~=3.1.2
itsdangerous==2.1.2 limits~=2.6.1
Jinja2==3.1.6 MarkupSafe~=2.1.1
limits==2.6.3 packaging~=21.3
MarkupSafe==2.1.5 Pillow
numpy==2.3.0 Pygments~=2.12.0
packaging==21.3 pyparsing~=3.0.8
pillow==11.2.1 pyserial~=3.5
pycparser==2.22 python-barcode~=0.13.1
Pygments==2.12.0 pyusb~=1.2.1
pyparsing==3.0.9 PyYAML~=6.0
pyserial==3.5 qrcode~=7.3.1
python-barcode==0.13.1 rich~=12.4.1
pyusb==1.2.1 six~=1.16.0
PyYAML==6.0.2 toml~=0.10.2
qrcode==7.3.1 typing_extensions~=4.2.0
rich==12.4.4 Unidecode~=1.3.4
setuptools==80.9.0 viivakoodi~=0.8.0
six==1.16.0 Werkzeug~=2.1.2
toml==0.10.2 wrapt~=1.14.1
typing_extensions==4.2.0
Unidecode==1.3.8
viivakoodi==0.8.0
Werkzeug==2.1.2
wrapt==1.14.1

View File

@ -40,16 +40,6 @@ vendor_id = configuration_file["printer"]["vendor_id"]
device_id = configuration_file["printer"]["device_id"] device_id = configuration_file["printer"]["device_id"]
UPLOAD_FOLDER = str(configuration_file["printer"]["upload_folder"]) UPLOAD_FOLDER = str(configuration_file["printer"]["upload_folder"])
try:
os.mkdir(UPLOAD_FOLDER)
app.logger.debug(f"Directory '{UPLOAD_FOLDER}' created successfully.")
except FileExistsError:
app.logger.error(f"Directory '{UPLOAD_FOLDER}' already exists.")
except PermissionError:
app.logger.error(f"Permission denied: Unable to create '{UPLOAD_FOLDER}'.")
except Exception as e:
app.logger.error(f"An error occurred: {e}")
ALLOWED_EXTENSIONS = {'png', 'jpg', 'jpeg', 'gif'} ALLOWED_EXTENSIONS = {'png', 'jpg', 'jpeg', 'gif'}
# Output the config file # Output the config file
@ -71,9 +61,6 @@ printer.init_printer()
# Web routes # Web routes
web = Web(app, printer) web = Web(app, printer)
if __name__ == "__main__":
app.run(ssl_context='adhoc')
limiter = Limiter( limiter = Limiter(
app, app,
@ -116,16 +103,15 @@ def api_print_sms():
txt = request.form["txt"] txt = request.form["txt"]
sign = request.form["signature"] sign = request.form["signature"]
except Exception as e: except Exception as e:
app.logger.error(str(e) + " - Whoops, no forms submitted or missing signature.") flash(e,'error')
return jsonify({'message': 'Error getting the information from the form :' + e}), 500 redirect(url_for('index'))
try: try:
web.print_sms(txt,sign) web.print_sms(txt,sign)
except Exception as e: except Exception as e:
return jsonify({'message': 'Error printing the SMS:' + e}), 500 pass
return redirect(url_for('index'))
return jsonify({'message': 'Message printed'}), 200
@app.route('/api/print/img', methods=['POST']) @app.route('/api/print/img', methods=['POST'])
@limiter.limit("6/minute", override_defaults=False) @limiter.limit("6/minute", override_defaults=False)
@ -135,41 +121,43 @@ def api_print_image():
try: try:
sign = request.form["signature"] sign = request.form["signature"]
except Exception as e: except Exception as e:
flash(str(e),'error')
app.logger.error(str(e) + " - Whoops, no forms submitted or missing signature.") app.logger.error(str(e) + " - Whoops, no forms submitted or missing signature.")
return jsonify({'message': 'Error getting the information from the form :' + e}), 500 return redirect(url_for('index'))
if request.method == 'POST': if request.method == 'POST':
# check if the post request has the file part # check if the post request has the file part
try: try:
if 'img' not in request.files: if 'img' not in request.files:
flash('No file found. Did you use the good form ?', 'error')
app.logger.error("No file found. Did you use the good form ?") app.logger.error("No file found. Did you use the good form ?")
return jsonify({'message': 'No file found. Did you use the good form ?'}), 500 return redirect(url_for("index"))
else: else:
file = request.files['img'] file = request.files['img']
except Exception as e: except Exception as e:
app.logger.error('Error getting the files :' + e) if sign is not None and photo is not None:
return jsonify({'message': 'Error getting the files :' + e}), 500 pass
else:
flash(str(e), 'error')
app.logger.error("Couldn't get an image nor signature : " + str(e))
# If the user does not select a file, the browser submits an # If the user does not select a file, the browser submits an
# empty file without a filename. # empty file without a filename.
if file.filename == '': if file.filename == '':
app.logger.error("Submitted file has no filename !") app.logger.error("Submitted file has no filename !")
return jsonify({'message': "Submitted file has no filename !" + e}), 500 flash('No file submitted, please select a file','error')
return redirect(url_for("index"))
try: try:
app.logger.debug("Sending the image to the printer.") app.logger.debug("Sending the image to the printer.")
web.print_image(file, sign) web.print_image(file, sign)
except Exception as e: except Exception as e:
app.logger.error("The image could not be printed : " + e ) pass
return jsonify({'message': "The image could not be printed :" + e}), 500
else: else:
return jsonify({'message': "Method Not Allowed, please POST"}), 403 flash('Cannot access to page with this method.','error')
app.logger.debug('Bad access type to this API, please POST') app.logger.debug('Bad access type to this API.')
return jsonify({'message': 'Message printed'}), 200
return redirect(url_for("index"))
@app.route('/login') @app.route('/login')
@limiter.limit("1/second", override_defaults=False) @limiter.limit("1/second", override_defaults=False)
@ -186,12 +174,10 @@ def logout_page():
@app.errorhandler(429) @app.errorhandler(429)
def ratelimit_handler(e): def ratelimit_handler(e):
flash("Rate limit reached, please slow down :) ( Currently at "+ e.description + ")", 'error') flash("Rate limit reached, please slow down :) ( Currently at "+ e.description + ")", 'error')
app.logger.debug('Rate limit reached ' + e)
return redirect(url_for("index")) return redirect(url_for("index"))
@app.route("/ping") @app.route("/ping")
@limiter.exempt @limiter.exempt
def ping(): def ping():
flash("🏓 Pong !",'info') flash("🏓 Pong !",'info')
app.logger.debug('🏓 Pong !')
return redirect(url_for("index")) return redirect(url_for("index"))

View File

@ -177,7 +177,7 @@ class Printer(object):
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 = 150 # Brightness threshold (0255) brightness_threshold = 150 # Brightness threshold (0255)
contrast_factor = 1.2 # Less than 1.0 = lower contrast contrast_factor = 0.8 # Less than 1.0 = lower contrast
max_width = 575 max_width = 575
max_height = 1000 max_height = 1000

View File

@ -190,9 +190,6 @@ async function get_webcam(options){
printButton.removeAttribute("disabled",""); printButton.removeAttribute("disabled","");
current_stream = stream; current_stream = stream;
video.srcObject = stream; video.srcObject = stream;
video.setAttribute('autoplay', '');
video.setAttribute('muted', '');
video.setAttribute('playsinline', '')
video.play(); video.play();
return true; return true;
}) })

View File

@ -27,6 +27,11 @@
<path d="M15 12a1 1 0 0 1-1 1H2a1 1 0 0 1-1-1V6a1 1 0 0 1 1-1h1.172a3 3 0 0 0 2.12-.879l.83-.828A1 1 0 0 1 6.827 3h2.344a1 1 0 0 1 .707.293l.828.828A3 3 0 0 0 12.828 5H14a1 1 0 0 1 1 1v6zM2 4a2 2 0 0 0-2 2v6a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V6a2 2 0 0 0-2-2h-1.172a2 2 0 0 1-1.414-.586l-.828-.828A2 2 0 0 0 9.172 2H6.828a2 2 0 0 0-1.414.586l-.828.828A2 2 0 0 1 3.172 4H2z"/> <path d="M15 12a1 1 0 0 1-1 1H2a1 1 0 0 1-1-1V6a1 1 0 0 1 1-1h1.172a3 3 0 0 0 2.12-.879l.83-.828A1 1 0 0 1 6.827 3h2.344a1 1 0 0 1 .707.293l.828.828A3 3 0 0 0 12.828 5H14a1 1 0 0 1 1 1v6zM2 4a2 2 0 0 0-2 2v6a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V6a2 2 0 0 0-2-2h-1.172a2 2 0 0 1-1.414-.586l-.828-.828A2 2 0 0 0 9.172 2H6.828a2 2 0 0 0-1.414.586l-.828.828A2 2 0 0 1 3.172 4H2z"/>
<path d="M8 11a2.5 2.5 0 1 1 0-5 2.5 2.5 0 0 1 0 5zm0 1a3.5 3.5 0 1 0 0-7 3.5 3.5 0 0 0 0 7zM3 6.5a.5.5 0 1 1-1 0 .5.5 0 0 1 1 0z"/> <path d="M8 11a2.5 2.5 0 1 1 0-5 2.5 2.5 0 0 1 0 5zm0 1a3.5 3.5 0 1 0 0-7 3.5 3.5 0 0 0 0 7zM3 6.5a.5.5 0 1 1-1 0 .5.5 0 0 1 1 0z"/>
</svg> </svg>
<b>&</b>
<svg xmlns="http://www.w3.org/2000/svg" width="54" height="54" fill="currentColor" class="bi bi-printer" viewBox="0 0 16 16">
<path d="M2.5 8a.5.5 0 1 0 0-1 .5.5 0 0 0 0 1z"/>
<path d="M5 1a2 2 0 0 0-2 2v2H2a2 2 0 0 0-2 2v3a2 2 0 0 0 2 2h1v1a2 2 0 0 0 2 2h6a2 2 0 0 0 2-2v-1h1a2 2 0 0 0 2-2V7a2 2 0 0 0-2-2h-1V3a2 2 0 0 0-2-2H5zM4 3a1 1 0 0 1 1-1h6a1 1 0 0 1 1 1v2H4V3zm1 5a2 2 0 0 0-2 2v1H2a1 1 0 0 1-1-1V7a1 1 0 0 1 1-1h12a1 1 0 0 1 1 1v3a1 1 0 0 1-1 1h-1v-1a2 2 0 0 0-2-2H5zm7 2v3a1 1 0 0 1-1 1H5a1 1 0 0 1-1-1v-3a1 1 0 0 1 1-1h6a1 1 0 0 1 1 1z"/>
</svg>
</button> </button>
<button class="col-sm col-lg-3 offset-lg-2 btn btn-secondary justify-content-center" name="flip" id="flip" data-bs-toggle="tooltip" data-bs-placement="top" title="Change camera" disabled=""> <button class="col-sm col-lg-3 offset-lg-2 btn btn-secondary justify-content-center" name="flip" id="flip" data-bs-toggle="tooltip" data-bs-placement="top" title="Change camera" disabled="">
<svg xmlns="http://www.w3.org/2000/svg" width="54" height="54" fill="currentColor" class="bi bi-arrow-repeat" viewBox="0 0 16 16"> <svg xmlns="http://www.w3.org/2000/svg" width="54" height="54" fill="currentColor" class="bi bi-arrow-repeat" viewBox="0 0 16 16">