""" Improved printing module that explicitly sets paper size for thermal label printers. This prevents the printer from using default paper size (continuous roll). """ import win32print import win32ui import win32con from PIL import Image import os def mm_to_inches(mm): """Convert millimeters to inches""" return mm / 25.4 def mm_to_hundredths_inch(mm): """Convert millimeters to hundredths of an inch (used by Windows print API)""" return int(mm_to_inches(mm) * 100) def print_pdf_with_custom_size(pdf_path, printer_name, width_mm=35, height_mm=25): """ Print PDF with explicit paper size settings for thermal label printers. Args: pdf_path (str): Path to PDF file printer_name (str): Name of the printer width_mm (int): Label width in millimeters (default 35mm) height_mm (int): Label height in millimeters (default 25mm) Returns: bool: True if successful """ try: # Convert PDF to image first for better control from pdf2image import pdfimages print("Converting PDF to image for precise printing...") # Use pdftoppm or pdf2image import subprocess # Try using pdftoppm if available temp_image = pdf_path.replace('.pdf', '_temp.png') try: # Try pdftoppm first (better quality) subprocess.run([ 'pdftoppm', '-png', '-singlefile', '-r', '1200', # High DPI pdf_path, pdf_path.replace('.pdf', '_temp') ], check=True) except: # Fallback: convert using Pillow/reportlab from reportlab.pdfgen import canvas from PyPDF2 import PdfReader print("Using alternative PDF conversion method...") if os.path.exists(temp_image): return print_image_with_custom_size(temp_image, printer_name, width_mm, height_mm) else: print("Could not convert PDF to image") return False except Exception as e: print(f"Error in advanced printing: {e}") return False def print_image_with_custom_size(image_path, printer_name, width_mm=35, height_mm=25): """ Print image with explicit paper size for thermal label printers. Args: image_path (str): Path to image file printer_name (str): Name of the printer width_mm (int): Label width in millimeters height_mm (int): Label height in millimeters Returns: bool: True if successful """ try: # Open the printer hprinter = win32print.OpenPrinter(printer_name) try: # Get printer device context hdc = win32ui.CreateDC() hdc.CreatePrinterDC(printer_name) # Get printer properties props = win32print.GetPrinter(hprinter, 2) # Get DEVMODE structure devmode = props["pDevMode"] # Set custom paper size (DMPAPER_USER = 256) devmode.PaperSize = 256 # Custom paper size # Set paper dimensions in tenths of millimeter devmode.PaperLength = height_mm * 10 # Height in 0.1mm units devmode.PaperWidth = width_mm * 10 # Width in 0.1mm units # Set orientation to landscape (2) for 35x25mm devmode.Orientation = 2 # 2 = Landscape # Set print quality to high devmode.PrintQuality = win32print.DMRES_HIGH # Apply the devmode props["pDevMode"] = devmode win32print.SetPrinter(hprinter, 2, props, 0) # Start document doc_info = ("Label Print", None, None, 0) hdc.StartDoc("Label Print") hdc.StartPage() # Load image img = Image.open(image_path) # Get printer DPI printer_dpi_x = hdc.GetDeviceCaps(win32con.LOGPIXELSX) printer_dpi_y = hdc.GetDeviceCaps(win32con.LOGPIXELSY) # Calculate image size in pixels based on mm dimensions width_pixels = int(mm_to_inches(width_mm) * printer_dpi_x) height_pixels = int(mm_to_inches(height_mm) * printer_dpi_y) # Resize image to exact label dimensions img_resized = img.resize((width_pixels, height_pixels), Image.Resampling.LANCZOS) # Convert to bitmap dib = ImageWin.Dib(img_resized) # Print at position (0,0) with exact size dib.draw(hdc.GetHandleOutput(), (0, 0, width_pixels, height_pixels)) # End document hdc.EndPage() hdc.EndDoc() print(f"Label printed successfully with custom size: {width_mm}x{height_mm}mm") return True finally: win32print.ClosePrinter(hprinter) except Exception as e: print(f"Error printing with custom size: {e}") import traceback traceback.print_exc() return False def set_printer_paper_size(printer_name, width_mm=35, height_mm=25): """ Configure printer to use custom paper size. This sets the printer default to the label size. Args: printer_name (str): Name of the printer width_mm (int): Label width in millimeters height_mm (int): Label height in millimeters Returns: bool: True if successful """ try: hprinter = win32print.OpenPrinter(printer_name) try: # Get current printer properties props = win32print.GetPrinter(hprinter, 2) devmode = props["pDevMode"] # Configure for custom label size devmode.PaperSize = 256 # DMPAPER_USER (custom) devmode.PaperLength = height_mm * 10 # in 0.1mm units devmode.PaperWidth = width_mm * 10 # in 0.1mm units devmode.Orientation = 2 # Landscape devmode.PrintQuality = win32print.DMRES_HIGH # Update fields flags devmode.Fields = ( win32print.DM_PAPERSIZE | win32print.DM_PAPERLENGTH | win32print.DM_PAPERWIDTH | win32print.DM_ORIENTATION | win32print.DM_PRINTQUALITY ) # Apply settings props["pDevMode"] = devmode win32print.SetPrinter(hprinter, 2, props, 0) print(f"Printer '{printer_name}' configured for {width_mm}x{height_mm}mm labels") return True finally: win32print.ClosePrinter(hprinter) except Exception as e: print(f"Error configuring printer: {e}") import traceback traceback.print_exc() return False if __name__ == "__main__": # Test configuration printer_name = "Labels" print("Testing printer configuration...") success = set_printer_paper_size(printer_name, 35, 25) if success: print("\n✅ Printer configured successfully!") print("The printer should now use 35x25mm label size by default.") else: print("\n❌ Failed to configure printer") print("You may need to set the paper size manually in printer preferences.")