From e8a17b6a9ef8da7dc4a4e07f6e16979de6ffbc38 Mon Sep 17 00:00:00 2001 From: ske087 Date: Thu, 19 Jun 2025 11:11:56 +0300 Subject: [PATCH] Final tuch of the Print label --- app.py | 181 +++++++++++++++++++++++++++++++++++++++------------------ 1 file changed, 125 insertions(+), 56 deletions(-) diff --git a/app.py b/app.py index 3c8be49..df4e915 100644 --- a/app.py +++ b/app.py @@ -10,49 +10,110 @@ def get_printers(): conn = cups.Connection() return list(conn.getPrinters().keys()) -def print_label(printer_name, text): - # Generate barcode image without text +def create_label_image(text): + # Label dimensions for 9x5 cm at 300 DPI + label_width = 1063 # 9 cm + label_height = 591 # 5 cm + + # Outer frame (95% of label, centered) + outer_frame_width = int(label_width * 0.95) + outer_frame_height = int(label_height * 0.95) + outer_frame_x = (label_width - outer_frame_width) // 2 + outer_frame_y = (label_height - outer_frame_height) // 2 + + # Barcode frame (top, inside outer frame) + barcode_frame_width = int(outer_frame_width * 0.90) + barcode_frame_height = int(outer_frame_height * 0.60) + barcode_frame_x = outer_frame_x + (outer_frame_width - barcode_frame_width) // 2 + barcode_frame_y = outer_frame_y + + # Text frame (immediately below barcode frame) + text_frame_width = int(outer_frame_width * 0.90) + text_frame_height = int(outer_frame_height * 0.35) + text_frame_x = outer_frame_x + (outer_frame_width - text_frame_width) // 2 + gap_between_frames = 5 # or 0 for no gap + text_frame_y = barcode_frame_y + barcode_frame_height + gap_between_frames + + # Generate barcode image (no text), at higher resolution CODE128 = barcode.get_barcode_class('code128') + writer_options = { + "write_text": False, + "module_width": 0.5, # default is 0.2, increase for higher res + "module_height": barcode_frame_height, # match frame height + "quiet_zone": 3.5, # default, can adjust if needed + "font_size": 0 # no text + } code = CODE128(text, writer=ImageWriter()) - filename = code.save('label_barcode', options={"write_text": False}) - - # Load barcode image + filename = code.save('label_barcode', options=writer_options) barcode_img = Image.open(filename) - # Set font path (adjust if needed) + + # Now resize barcode to exactly fit barcode frame (stretch, do not keep aspect ratio) + barcode_resized = barcode_img.resize((barcode_frame_width, barcode_frame_height), Image.LANCZOS) + + # Create label image + label_img = Image.new('RGB', (label_width, label_height), 'white') + + # Paste barcode centered in barcode frame + label_img.paste(barcode_resized, (barcode_frame_x, barcode_frame_y)) + + # Draw text in text frame, maximize font size to fit frame (keep sharpness) + font_path = "/usr/share/fonts/truetype/dejavu/DejaVuSans-Bold.ttf" + max_font_size = text_frame_height + min_font_size = 10 + best_font_size = min_font_size + for font_size in range(min_font_size, max_font_size + 1): + try: + font = ImageFont.truetype(font_path, font_size) + except IOError: + font = ImageFont.load_default() + break + dummy_img = Image.new('RGB', (1, 1)) + dummy_draw = ImageDraw.Draw(dummy_img) + text_bbox = dummy_draw.textbbox((0, 0), text, font=font) + text_width = text_bbox[2] - text_bbox[0] + text_height = text_bbox[3] - text_bbox[1] + if text_width > text_frame_width or text_height > text_frame_height: + break + best_font_size = font_size + + # Use the best font size found try: - font = ImageFont.truetype("arialbd.ttf", 32) # Arial Black, 24pt + font = ImageFont.truetype(font_path, best_font_size) except IOError: font = ImageFont.load_default() - # Calculate text size - draw = ImageDraw.Draw(barcode_img) - text_width, text_height = draw.textbbox((0, 0), text, font=font)[2:] - # Create label image with extra space for text - label_height = barcode_img.height + text_height + 10 - label_img = Image.new('RGB', (barcode_img.width, label_height), 'white') - label_img.paste(barcode_img, (0, 0)) - # Draw text centered under barcode draw = ImageDraw.Draw(label_img) - x = (barcode_img.width - text_width) // 2 - y = barcode_img.height + 5 - draw.text((x, y), text, font=font, fill='black') + text_bbox = draw.textbbox((0, 0), text, font=font) + text_width = text_bbox[2] - text_bbox[0] + text_height = text_bbox[3] - text_bbox[1] + text_x = text_frame_x + (text_frame_width - text_width) // 2 + text_y = text_frame_y + (text_frame_height - text_height) // 2 + draw.text((text_x, text_y), text, font=font, fill='black') + + os.remove(filename) + return label_img + +def print_label(printer_name, text): + label_img = create_label_image(text) label_img.save('final_label.png') - - # Print using CUPS conn = cups.Connection() conn.printFile(printer_name, 'final_label.png', "Label Print", {}) - os.remove(filename) os.remove('final_label.png') -def show_preview(image_path): +def show_preview(image_path, on_print): preview = tk.Toplevel() preview.title("Label Preview") + preview.geometry("1063x591") + preview.resizable(False, False) img = Image.open(image_path) img_tk = ImageTk.PhotoImage(img) label = tk.Label(preview, image=img_tk) label.image = img_tk # Keep reference label.pack() - btn = tk.Button(preview, text="Print", command=preview.destroy) - btn.pack() + def print_and_close(): + on_print() + preview.destroy() + # Auto-close and print after 4 seconds (4000 ms) + preview.after(4000, print_and_close) preview.grab_set() preview.wait_window() @@ -74,6 +135,38 @@ def select_printer(printers): dialog.wait_window() return selected['printer'] +def ask_label_text_with_preview(): + dialog = tk.Toplevel() + dialog.title("Label Text") + tk.Label(dialog, text="Enter text for the label:").pack(padx=10, pady=(10, 2)) + text_var = tk.StringVar() + entry = tk.Entry(dialog, textvariable=text_var, width=40) + entry.pack(padx=10, pady=2) + preview_var = tk.BooleanVar(value=True) + chk = tk.Checkbutton(dialog, text="Show print preview", variable=preview_var) + chk.pack(padx=10, pady=2) + result = {'text': None, 'preview': True} + def on_ok(): + result['text'] = text_var.get() + result['preview'] = preview_var.get() + dialog.destroy() + btn = tk.Button(dialog, text="OK", command=on_ok) + btn.pack(pady=10) + entry.focus() + dialog.grab_set() + dialog.wait_window() + return result['text'], result['preview'] + +def show_auto_close_info(title, message, timeout=3000): + info = tk.Toplevel() + info.title(title) + info.geometry("300x100") + info.resizable(False, False) + tk.Label(info, text=message, font=("Arial", 12)).pack(expand=True, padx=10, pady=10) + info.after(timeout, info.destroy) + info.grab_set() + info.wait_window() + def main(): root = tk.Tk() root.withdraw() @@ -88,43 +181,19 @@ def main(): messagebox.showerror("Error", "No printer selected.") return - text = simpledialog.askstring("Label Text", "Enter text for the label:") + text, do_preview = ask_label_text_with_preview() if not text: messagebox.showerror("Error", "No text entered.") return - # Generate label image for preview - CODE128 = barcode.get_barcode_class('code128') - code = CODE128(text, writer=ImageWriter()) - filename = code.save('label_barcode', options={"write_text": False}) - barcode_img = Image.open(filename) - # Set font path (adjust if needed) - try: - font = ImageFont.truetype("arialbd.ttf", 32) # Arial Black, 24pt - except IOError: - font = ImageFont.load_default() - # Calculate text size - draw = ImageDraw.Draw(barcode_img) - text_width, text_height = draw.textbbox((0, 0), text, font=font)[2:] - # Create label image with extra space for text - label_height = barcode_img.height + text_height + 10 - label_img = Image.new('RGB', (barcode_img.width, label_height), 'white') - label_img.paste(barcode_img, (0, 0)) - # Draw text centered under barcode - draw = ImageDraw.Draw(label_img) - x = (barcode_img.width - text_width) // 2 - y = barcode_img.height + 5 - draw.text((x, y), text, font=font, fill='black') + label_img = create_label_image(text) label_img.save('final_label.png') - os.remove(filename) - - # Show preview window - show_preview('final_label.png') - - # Print after preview - print_label(printer, text) - messagebox.showinfo("Done", "Label sent to printer.") - os.remove('final_label.png') + if do_preview: + show_preview('final_label.png', lambda: print_label(printer, text)) + show_auto_close_info("Done", "Label sent to printer.", timeout=2000) + else: + print_label(printer, text) + show_auto_close_info("Done", "Label sent to printer.", timeout=5000) if __name__ == "__main__": main() \ No newline at end of file