Final tuch of the Print label

This commit is contained in:
2025-06-19 11:11:56 +03:00
parent 17a549c8f6
commit e8a17b6a9e

181
app.py
View File

@@ -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()