from flask import Flask, request, jsonify import os import threading import queue import pdf2image from brother_ql.conversion import convert from brother_ql.backends.helpers import send, status from brother_ql.raster import BrotherQLRaster from PIL import Image import mimetypes import logging from logging.handlers import RotatingFileHandler import time app = Flask(__name__) # Set up logging log_file = 'log.txt' # Create a rotating file handler for logging log_handler = RotatingFileHandler(log_file, maxBytes=10*1024*1024, backupCount=5) # 10MB per log file, keep 5 backups log_handler.setLevel(logging.DEBUG) log_formatter = logging.Formatter('%(asctime)s - %(levelname)s - %(message)s') log_handler.setFormatter(log_formatter) # Add the log handler to the Flask app's logger app.logger.addHandler(log_handler) # Ensure Flask app uses our logger, not its default one app.logger.setLevel(logging.DEBUG) # Create a queue to hold the files for processing file_queue = queue.Queue() # Directory to save uploaded files (you can modify this path) UPLOAD_FOLDER = './uploads' os.makedirs(UPLOAD_FOLDER, exist_ok=True) # Printer configuration printer_model = "QL-1100" backend = 'pyusb' printer = 'usb://0x04f9:0x20a7' # Convert PDF to image def convert_pdf_to_images(pdf_path): """Converts a PDF to a PIL Image""" try: # Convert PDF to image (get the first page) images = pdf2image.convert_from_path(pdf_path) if images: return images return None except Exception as e: app.logger.error(f"Error converting PDF: {str(e)}") return None # Function to print address labels def print_address_label(images, pdf_path): try: for image in images: if 'address' in pdf_path.lower(): target_width = 1660 target_height = 1164 image = image.convert("RGB") image = image.resize((target_width, target_height), Image.LANCZOS) image = image.rotate(90, expand=True) else: target_width = 1164 target_height = 1660 image = image.convert("RGB") image = image.resize((target_width, target_height), Image.LANCZOS) qlr = BrotherQLRaster(printer_model) qlr.exception_on_warning = True app.logger.info("Converting image to printer instructions...") instructions = convert( qlr=qlr, images=images, label='102x152', threshold=70.0, dither=False, compress=False, red=False, dpi_600=False, hq=True, cut=True ) app.logger.info("Sending to printer...") status = send( instructions=instructions, printer_identifier=printer, backend_identifier=backend, blocking=True ) app.logger.info(f"Printer status: {status}") app.logger.info("Print job sent successfully") except Exception as e: app.logger.error(f"Error during printing: {str(e)}") # Worker thread that processes files from the queue def process_queue(): while True: # Wait until a file is available in the queue file_path = file_queue.get() if file_path is None: # Shutdown signal break # Process the file (convert and print) app.logger.info(f"Processing file: {file_path}") images = convert_pdf_to_images(file_path) if images: print_address_label(images, file_path) else: app.logger.error(f"Failed to convert PDF to images: {file_path}") # Signal that the task is done file_queue.task_done() # Start the worker thread thread = threading.Thread(target=process_queue, daemon=True) thread.start() @app.route('/upload', methods=['POST']) def upload_file(): # Check if a file is part of the request if 'file' not in request.files: app.logger.warning('No file part in request') return jsonify({'error': 'No file part'}), 400 file = request.files['file'] if file.filename == '': app.logger.warning('No selected file') return jsonify({'error': 'No selected file'}), 400 # Check file type (ensure it's a PDF) mime_type, _ = mimetypes.guess_type(file.filename) if mime_type != 'application/pdf': app.logger.warning(f"Invalid file type: {mime_type}. Only PDF files are allowed.") return jsonify({'error': 'Only PDF files are allowed'}), 400 # Save the file to the uploads folder file_path = os.path.join(UPLOAD_FOLDER, file.filename) file.save(file_path) app.logger.info(f"File {file.filename} uploaded and saved to {file_path}") # Add the file path to the queue for processing file_queue.put(file_path) return jsonify({'message': f'File {file.filename} uploaded and queued for processing'}), 200 if __name__ == '__main__': app.run(debug=True)