Final tuch of the Print label
This commit is contained in:
181
app.py
181
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()
|
||||
Reference in New Issue
Block a user