Complete label printer redesign: file monitoring, SVG templates, sharp print quality

- Redesigned GUI for automatic file monitoring workflow
- Changed label format to 35x25mm landscape
- Implemented SVG template support with variable substitution
- Added configuration auto-save/load (conf/app.conf)
- Added system tray minimize functionality
- Fixed print quality: landscape orientation, vector fonts, 600 DPI
- Auto-clear file after print to prevent duplicates
- All popups auto-dismiss after 2-3 seconds
- Semicolon separator for data format (article;nr_art;serial)
- SumatraPDF integration with noscale settings
- Printer configured for outline fonts (sharp output)
- Reorganized documentation into documentation/ folder
This commit is contained in:
NAME
2026-02-12 22:25:51 +02:00
parent 0743c44051
commit 8954135f93
51 changed files with 1209 additions and 6396 deletions

View File

@@ -200,16 +200,16 @@ def create_label_pdf(text):
PDFs are saved to the pdf_backup folder.
Args:
text (str): Combined text in format "SAP|CANTITATE|LOT" or single value
text (str): Combined text in format "article;nr_art;serial" or single value
Returns:
str: Path to the generated PDF file
"""
# Parse the text input
parts = text.split('|') if '|' in text else [text, '', '']
sap_nr = parts[0].strip() if len(parts) > 0 else ''
cantitate = parts[1].strip() if len(parts) > 1 else ''
lot_number = parts[2].strip() if len(parts) > 2 else ''
# Parse the text input - using semicolon separator
parts = text.split(';') if ';' in text else [text, '', '']
article = parts[0].strip() if len(parts) > 0 else ''
nr_art = parts[1].strip() if len(parts) > 1 else ''
serial = parts[2].strip() if len(parts) > 2 else ''
# Create PDF using high-quality generator
generator = PDFLabelGenerator()
@@ -221,7 +221,16 @@ def create_label_pdf(text):
timestamp = datetime.datetime.now().strftime("%Y%m%d_%H%M%S")
pdf_filename = os.path.join(pdf_backup_dir, f"final_label_{timestamp}.pdf")
return generator.create_label_pdf(sap_nr, cantitate, lot_number, pdf_filename)
# Check for default SVG template
svg_template = None
default_svg = os.path.join('conf', 'label_template.svg')
if os.path.exists(default_svg):
svg_template = default_svg
# Check for default image path
image_path = os.path.join('conf', 'accepted.png')
return generator.create_label_pdf(article, nr_art, serial, pdf_filename, image_path, svg_template)
def print_to_printer(printer_name, file_path):
@@ -249,58 +258,68 @@ def print_to_printer(printer_name, file_path):
return True
elif SYSTEM == "Windows":
# Windows: Print directly without opening PDF viewer
# Windows: Print PDF using various methods
try:
if WIN32_AVAILABLE:
import win32print
import win32api
if file_path.endswith('.pdf'):
# Method 1: Try SumatraPDF for best silent printing
sumatra_paths = [
os.path.join(os.path.dirname(os.path.abspath(__file__)), 'conf', 'SumatraPDF.exe'),
os.path.join(os.path.dirname(os.path.abspath(__file__)), 'conf', 'SumatraPDF-portable.exe'),
r"C:\Program Files\SumatraPDF\SumatraPDF.exe",
r"C:\Program Files (x86)\SumatraPDF\SumatraPDF.exe",
os.path.expandvars(r"%LOCALAPPDATA%\SumatraPDF\SumatraPDF.exe"),
]
if file_path.endswith('.pdf'):
# Use SumatraPDF command-line or direct raw printing
# Try printing via subprocess to avoid opening a PDF viewer window
# Method: Use win32print raw API to send to printer silently
sumatra_found = False
for sumatra_path in sumatra_paths:
if os.path.exists(sumatra_path):
sumatra_found = True
try:
# Use SumatraPDF silent printing with high quality settings
# noscale = print at actual size without scaling
# landscape = force landscape orientation for 35x25mm labels
# Note: SumatraPDF uses printer driver's quality settings
subprocess.run([
sumatra_path,
'-print-to', printer_name,
'-silent',
'-print-settings', 'noscale,landscape',
file_path
], check=True, creationflags=subprocess.CREATE_NO_WINDOW)
print(f"Label sent to printer via SumatraPDF: {printer_name}")
return True
except Exception as sumatra_err:
print(f"SumatraPDF print failed: {sumatra_err}")
break
# Method 2: Use ShellExecute with printto (requires default PDF viewer)
if not sumatra_found or WIN32_AVAILABLE:
try:
hprinter = win32print.OpenPrinter(printer_name)
try:
# Start a print job
job_info = ("Label Print", None, "RAW")
hjob = win32print.StartDocPrinter(hprinter, 1, job_info)
win32print.StartPagePrinter(hprinter)
# Read PDF file and send to printer
with open(file_path, 'rb') as f:
pdf_data = f.read()
win32print.WritePrinter(hprinter, pdf_data)
win32print.EndPagePrinter(hprinter)
win32print.EndDocPrinter(hprinter)
print(f"Label sent to printer: {printer_name}")
finally:
win32print.ClosePrinter(hprinter)
import win32api
win32api.ShellExecute(
0, "printto", file_path,
f'"{printer_name}"', ".", 0
)
print(f"Label sent to printer via ShellExecute: {printer_name}")
return True
except Exception as raw_err:
print(f"Raw print failed ({raw_err}), trying ShellExecute silently...")
# Fallback: Use ShellExecute with printto (minimized, auto-closes)
except Exception as shell_err:
print(f"ShellExecute print failed: {shell_err}")
# Method 3: Open PDF with default viewer (last resort)
try:
win32api.ShellExecute(
0, "printto", file_path,
f'"{printer_name}"', ".", 0
)
print(f"Label sent to printer: {printer_name}")
os.startfile(file_path, "print")
print(f"Opened PDF for printing: {file_path}")
print("Please close the PDF viewer after printing.")
return True
except Exception as shell_err:
print(f"ShellExecute print failed: {shell_err}")
except Exception as startfile_err:
print(f"Could not open PDF: {startfile_err}")
print("PDF saved as backup only")
return True
else:
# Non-PDF files: print silently with notepad
subprocess.run(['notepad', '/p', file_path],
check=False,
creationflags=subprocess.CREATE_NO_WINDOW)
print(f"Label sent to printer: {printer_name}")
return True
else:
print("win32print not available, PDF saved as backup only")
# Non-PDF files: print silently with notepad
subprocess.run(['notepad', '/p', file_path],
check=False,
creationflags=subprocess.CREATE_NO_WINDOW)
print(f"Label sent to printer: {printer_name}")
return True
except Exception as e:
print(f"Windows print error: {e}")