Fix printer detection, implement portable deployment with SumatraPDF
- Fixed network printer enumeration (PRINTER_ENUM_LOCAL | PRINTER_ENUM_CONNECTIONS) - Added printer name truncation to 20 chars with full name mapping - Implemented silent PDF printing using SumatraPDF with landscape orientation - Added auto-dismiss for success popup (3 seconds) - Bundled SumatraPDF inside executable for portable single-file deployment - Updated build script to embed SumatraPDF - Added setup_sumatra.ps1 for downloading SumatraPDF portable - Added DEPLOYMENT.md documentation
This commit is contained in:
161
print_label.py
161
print_label.py
@@ -3,6 +3,7 @@ import barcode
|
||||
from barcode.writer import ImageWriter
|
||||
import time
|
||||
import os
|
||||
import sys
|
||||
import datetime
|
||||
import platform
|
||||
import subprocess
|
||||
@@ -249,51 +250,139 @@ def print_to_printer(printer_name, file_path):
|
||||
return True
|
||||
|
||||
elif SYSTEM == "Windows":
|
||||
# Windows: Print directly without opening PDF viewer
|
||||
# Windows: Print PDF silently without any viewer opening
|
||||
try:
|
||||
if WIN32_AVAILABLE:
|
||||
import win32print
|
||||
import win32api
|
||||
|
||||
if file_path.endswith('.pdf'):
|
||||
# Use SumatraPDF command-line or direct raw printing
|
||||
# Try printing via subprocess to avoid opening a PDF viewer window
|
||||
# Try silent printing methods (no viewer opens)
|
||||
import os
|
||||
import winreg
|
||||
|
||||
# Method: Use win32print raw API to send to printer silently
|
||||
try:
|
||||
hprinter = win32print.OpenPrinter(printer_name)
|
||||
printed = False
|
||||
|
||||
# Method 1: SumatraPDF (bundled inside exe or external)
|
||||
sumatra_paths = []
|
||||
|
||||
# Get the directory where this script/exe is running
|
||||
if getattr(sys, 'frozen', False):
|
||||
# Running as compiled executable
|
||||
# PyInstaller extracts bundled files to sys._MEIPASS temp folder
|
||||
if hasattr(sys, '_MEIPASS'):
|
||||
# Check bundled version first (inside the exe)
|
||||
bundled_sumatra = os.path.join(sys._MEIPASS, 'SumatraPDF.exe')
|
||||
sumatra_paths.append(bundled_sumatra)
|
||||
|
||||
# Also check app directory for external version
|
||||
app_dir = os.path.dirname(sys.executable)
|
||||
sumatra_paths.append(os.path.join(app_dir, "SumatraPDF", "SumatraPDF.exe"))
|
||||
sumatra_paths.append(os.path.join(app_dir, "SumatraPDF.exe"))
|
||||
else:
|
||||
# Running as script - check local folders
|
||||
app_dir = os.path.dirname(os.path.abspath(__file__))
|
||||
sumatra_paths.append(os.path.join(app_dir, "SumatraPDF", "SumatraPDF.exe"))
|
||||
sumatra_paths.append(os.path.join(app_dir, "SumatraPDF.exe"))
|
||||
|
||||
# Then check system installations
|
||||
sumatra_paths.extend([
|
||||
r"C:\Program Files\SumatraPDF\SumatraPDF.exe",
|
||||
r"C:\Program Files (x86)\SumatraPDF\SumatraPDF.exe",
|
||||
])
|
||||
|
||||
for sumatra_path in sumatra_paths:
|
||||
if os.path.exists(sumatra_path):
|
||||
try:
|
||||
subprocess.run([
|
||||
sumatra_path,
|
||||
"-print-to",
|
||||
printer_name,
|
||||
file_path,
|
||||
"-print-settings",
|
||||
"fit,landscape",
|
||||
"-silent",
|
||||
"-exit-when-done"
|
||||
], check=False, creationflags=subprocess.CREATE_NO_WINDOW)
|
||||
print(f"Label sent to printer via SumatraPDF: {printer_name}")
|
||||
printed = True
|
||||
break
|
||||
except Exception as e:
|
||||
print(f"SumatraPDF error: {e}")
|
||||
|
||||
# Method 2: Adobe Reader silent printing
|
||||
if not printed:
|
||||
adobe_path = None
|
||||
for key_path in [
|
||||
r"SOFTWARE\Microsoft\Windows\CurrentVersion\App Paths\AcroRd32.exe",
|
||||
r"SOFTWARE\Microsoft\Windows\CurrentVersion\App Paths\Acrobat.exe"
|
||||
]:
|
||||
try:
|
||||
key = winreg.OpenKey(winreg.HKEY_LOCAL_MACHINE, key_path)
|
||||
adobe_path, _ = winreg.QueryValueEx(key, "")
|
||||
winreg.CloseKey(key)
|
||||
break
|
||||
except:
|
||||
pass
|
||||
|
||||
if adobe_path and os.path.exists(adobe_path):
|
||||
try:
|
||||
subprocess.run([
|
||||
adobe_path,
|
||||
"/t", # Print and close
|
||||
file_path,
|
||||
printer_name
|
||||
], check=False, creationflags=subprocess.CREATE_NO_WINDOW)
|
||||
print(f"Label sent to printer via Adobe Reader: {printer_name}")
|
||||
printed = True
|
||||
except:
|
||||
pass
|
||||
|
||||
# Method 3: GhostScript (if installed)
|
||||
if not printed:
|
||||
gs_paths = [
|
||||
r"C:\Program Files\gs\gs10.02.1\bin\gswin64c.exe",
|
||||
r"C:\Program Files (x86)\gs\gs10.02.1\bin\gswin32c.exe",
|
||||
]
|
||||
# Try to find gswin in PATH
|
||||
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)
|
||||
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)
|
||||
try:
|
||||
win32api.ShellExecute(
|
||||
0, "printto", file_path,
|
||||
f'"{printer_name}"', ".", 0
|
||||
)
|
||||
print(f"Label sent to printer: {printer_name}")
|
||||
return True
|
||||
except Exception as shell_err:
|
||||
print(f"ShellExecute print failed: {shell_err}")
|
||||
return True
|
||||
gs_result = subprocess.run(['where', 'gswin64c'],
|
||||
capture_output=True, text=True, check=False)
|
||||
if gs_result.returncode == 0:
|
||||
gs_paths.insert(0, gs_result.stdout.strip().split('\n')[0])
|
||||
except:
|
||||
pass
|
||||
|
||||
for gs_path in gs_paths:
|
||||
if os.path.exists(gs_path):
|
||||
try:
|
||||
subprocess.run([
|
||||
gs_path,
|
||||
"-dNOPAUSE", "-dBATCH", "-dQUIET",
|
||||
f"-sDEVICE=mswinpr2",
|
||||
f"-sOutputFile=%printer%{printer_name}",
|
||||
file_path
|
||||
], check=False, creationflags=subprocess.CREATE_NO_WINDOW)
|
||||
print(f"Label sent to printer via GhostScript: {printer_name}")
|
||||
printed = True
|
||||
break
|
||||
except:
|
||||
pass
|
||||
|
||||
if not printed:
|
||||
# Fallback: Let user know and save PDF
|
||||
print("=" * 60)
|
||||
print("NOTICE: Silent PDF printing requires SumatraPDF")
|
||||
print("SumatraPDF not found (should be bundled inside the app)")
|
||||
print("If you built the app yourself, ensure SumatraPDF.exe is downloaded first.")
|
||||
print("Run: setup_sumatra.ps1 before building")
|
||||
print("=" * 60)
|
||||
print(f"PDF saved to: {file_path}")
|
||||
print("The PDF can be printed manually.")
|
||||
|
||||
return True
|
||||
else:
|
||||
# Non-PDF files: print silently with notepad
|
||||
# Non-PDF files
|
||||
subprocess.run(['notepad', '/p', file_path],
|
||||
check=False,
|
||||
creationflags=subprocess.CREATE_NO_WINDOW)
|
||||
|
||||
Reference in New Issue
Block a user