diff --git a/.gitignore b/.gitignore index 82c1a96..96a9dad 100644 --- a/.gitignore +++ b/.gitignore @@ -2,3 +2,5 @@ label/ build/ logs/ pdf_backup/ +venv/ + diff --git a/BUILD_ON_WINDOWS.md b/BUILD_ON_WINDOWS.md deleted file mode 100644 index c024f6f..0000000 --- a/BUILD_ON_WINDOWS.md +++ /dev/null @@ -1,178 +0,0 @@ -# Building LabelPrinter.exe on Windows - -This guide explains how to build a standalone `LabelPrinter.exe` single-file executable on a Windows machine. - -## Prerequisites - -1. **Python 3.10, 3.11, 3.12, or 3.13** - Download from https://www.python.org/ - - ⚠️ **IMPORTANT**: Check "Add Python to PATH" during installation - - ⚠️ **Note**: Python 3.14+ may have compatibility issues with Kivy 2.2.1 - - Verify: Open Command Prompt and type `python --version` - -2. **Git** (optional, for cloning the repository) - -3. **Internet connection** - To download dependencies - -## Quick Start (Using Provided Scripts) - -### Option 1: Batch Script (Recommended for CMD users) - -1. Open **Command Prompt** (cmd.exe) -2. Navigate to the project folder: - ``` - cd C:\path\to\label_print - ``` -3. Run the build script: - ``` - build_windows.bat - ``` -4. Wait 5-15 minutes for the build to complete -5. The executable will be in: `dist\LabelPrinter.exe` - -### Option 2: PowerShell Script - -1. Open **PowerShell** (as Administrator recommended) -2. Navigate to the project folder: - ``` - cd C:\path\to\label_print - ``` -3. Allow script execution (if needed): - ``` - Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope CurrentUser - ``` -4. Run the build script: - ``` - .\build_windows.ps1 - ``` -5. Wait 5-15 minutes for the build to complete -6. The executable will be in: `dist\LabelPrinter.exe` - -## Manual Build Steps - -If you prefer to run commands manually: - -### Step 1: Prepare Python Environment - -```bash -# Upgrade pip, setuptools, and wheel -python -m pip install --upgrade pip setuptools wheel -``` - -### Step 2: Install Dependencies - -```bash -# Install required Python packages -pip install python-barcode pillow reportlab kivy==2.2.1 pyinstaller==6.1.0 -``` - -### Step 3: Build the Executable - -```bash -# Create single-file executable -pyinstaller label_printer_gui.py ^ - --onefile ^ - --windowed ^ - --name=LabelPrinter ^ - --distpath=./dist ^ - --workpath=./build ^ - --hidden-import=kivy ^ - --hidden-import=PIL ^ - --hidden-import=barcode ^ - --hidden-import=reportlab ^ - --hidden-import=print_label ^ - --hidden-import=print_label_pdf ^ - -y -``` - -The build process will take 5-15 minutes depending on your PC speed. - -### Step 4: Test the Executable - -```bash -# Run the built executable -dist\LabelPrinter.exe -``` - -## Output - -After successful build, you'll have: - -``` -dist/ -└── LabelPrinter.exe ← Single executable file -``` - -## Distributing the Executable - -You can: -1. **Copy `LabelPrinter.exe`** to any Windows PC (no Python needed!) -2. **Share via USB** or file transfer -3. **Create an installer** using NSIS or InnoSetup (optional) -4. **Upload to GitHub Releases** for public distribution - -## Troubleshooting - -### Error: "Python is not recognized" -- Reinstall Python and check "Add Python to PATH" -- Restart Command Prompt after reinstalling Python - -### Error: "pip command not found" -- Use `python -m pip` instead of `pip` - -### Build takes too long (>30 minutes) -- **Normal for first build** - Kivy framework is large -- Subsequent builds will be faster due to caching -- Close other applications to free up RAM - -### Error: "No module named 'kivy'" -- Make sure dependencies installed correctly: `pip install kivy==2.2.1` -- Check internet connection - -### Python 3.14 Compatibility Issues -If you have Python 3.14 installed and get errors like: -- `ModuleNotFoundError: No module named 'kivy'` -- `ImportError: DLL load failed` -- PyInstaller compatibility errors - -**Solution:** -- Install Python 3.11, 3.12, or 3.13 instead -- Download from: https://www.python.org/downloads/ -- Uninstall Python 3.14 first -- Then use one of the recommended versions -- Make sure all files are in the project folder: - - `label_printer_gui.py` - - `print_label.py` - - `print_label_pdf.py` -- Antivirus might be blocking it - check security software - -## Build Time Reference - -- **First build**: 10-15 minutes (downloading dependencies) -- **Subsequent builds**: 5-10 minutes (cached dependencies) - -## Advanced Options - -### Reduce Build Time -```bash -pyinstaller label_printer_gui.py --onefile --windowed --name=LabelPrinter -y -``` - -### Add Icon to Executable -```bash -pyinstaller label_printer_gui.py --onefile --windowed --name=LabelPrinter --icon=path\to\icon.ico -y -``` - -### Faster: Use --onedir (Directory) instead of --onefile -```bash -pyinstaller label_printer_gui.py --onedir --windowed --name=LabelPrinter -y -# Builds in ~3-5 minutes, but creates a folder instead of single file -``` - -## Support - -If you encounter issues: -1. Check the error message carefully -2. Make sure Python 3.10+ is installed -3. Verify all dependencies: `pip list` -4. Check internet connection -5. Try again with a fresh Command Prompt window diff --git a/PYINSTALLER_GUIDE.md b/PYINSTALLER_GUIDE.md deleted file mode 100644 index 9280de0..0000000 --- a/PYINSTALLER_GUIDE.md +++ /dev/null @@ -1,227 +0,0 @@ -# Building a Standalone EXE with PyInstaller - -This guide explains how to create a standalone Windows executable (`.exe`) file that doesn't require Python to be installed. - -## Quick Start (Windows) - -### Prerequisites -- Python 3.11+ installed -- Virtual environment activated -- All dependencies installed - -### One-Command Build - -```bash -# Activate virtual environment -venv\Scripts\activate - -# Build the executable -python build_exe.py -``` - -That's it! Your executable will be in `dist/LabelPrinter.exe` - ---- - -## What Happens During Build - -1. **Analyzes your code** - Finds all imported modules -2. **Collects dependencies** - Bundles Kivy, PIL, barcode, reportlab, etc. -3. **Creates executable** - Packages everything into one `.exe` file -4. **Output**: `dist/LabelPrinter.exe` (~150-200 MB) - ---- - -## Detailed Build Instructions - -### Step 1: Install PyInstaller -```bash -venv\Scripts\activate -pip install pyinstaller -``` - -### Step 2: Build Using Script -```bash -python build_exe.py -``` - -### Step 3: Alternative Manual Build -If the script doesn't work, use this command directly: - -```bash -pyinstaller ^ - --onefile ^ - --windowed ^ - --name=LabelPrinter ^ - --hidden-import=kivy ^ - --hidden-import=kivy.core.window ^ - --hidden-import=kivy.core.text ^ - --hidden-import=kivy.core.image ^ - --hidden-import=kivy.uix.boxlayout ^ - --hidden-import=kivy.uix.gridlayout ^ - --hidden-import=kivy.uix.label ^ - --hidden-import=kivy.uix.textinput ^ - --hidden-import=kivy.uix.button ^ - --hidden-import=kivy.uix.spinner ^ - --hidden-import=kivy.uix.scrollview ^ - --hidden-import=kivy.uix.popup ^ - --hidden-import=kivy.clock ^ - --hidden-import=kivy.graphics ^ - --hidden-import=PIL ^ - --hidden-import=barcode ^ - --hidden-import=reportlab ^ - --hidden-import=print_label ^ - --hidden-import=print_label_pdf ^ - --collect-all=kivy ^ - --collect-all=PIL ^ - label_printer_gui.py -``` - ---- - -## Output Files - -After building, you'll have: - -``` -Label-design/ -├── dist/ -│ └── LabelPrinter.exe ← Your standalone executable (150-200 MB) -├── build/ ← Temporary build files (can delete) -└── label_printer.spec ← PyInstaller spec file -``` - ---- - -## Running the Executable - -### On Your Computer -1. Double-click `dist/LabelPrinter.exe` -2. App starts immediately (first run takes ~5 seconds) -3. Works like the Python version - -### Sharing with Others -1. Copy `dist/LabelPrinter.exe` to a folder -2. Create a shortcut to it on the desktop -3. Share the folder or executable -4. **No Python installation needed on their computer!** - -### Creating a Shortcut -1. Right-click `LabelPrinter.exe` -2. Send to → Desktop (create shortcut) -3. Double-click the shortcut to run - ---- - -## Troubleshooting - -### "Failed to build the executable" - -**Solution 1**: Check Python version -```bash -python --version # Should be 3.11+ -``` - -**Solution 2**: Update PyInstaller -```bash -pip install --upgrade pyinstaller -``` - -**Solution 3**: Install missing dependencies -```bash -pip install -r requirements_windows.txt -pip install pyinstaller -``` - -### "DLL load failed" when running exe - -This usually means a library isn't bundled correctly. - -**Solution**: Rebuild with verbose output -```bash -pyinstaller --debug=imports label_printer_gui.py -``` - -### Executable is very large (200+ MB) - -This is normal for Kivy applications. The size includes: -- Python runtime (~50 MB) -- Kivy framework (~30 MB) -- Dependencies (PIL, barcode, reportlab, etc.) (~20 MB) -- Your code (~1 KB) - -You can reduce size slightly with: -```bash ---exclude-module=matplotlib ---exclude-module=numpy ---exclude-module=scipy -``` - -### Slow to start (5-10 seconds) - -Normal for Kivy apps. The first startup initializes: -- Python runtime -- Kivy graphics system -- Font rendering -- Window initialization - -Subsequent runs are faster (~3 seconds). - ---- - -## Advanced Options - -### Add an Icon -1. Create a 256x256 PNG icon: `app_icon.png` -2. Convert to ICO: Use an online tool or ImageMagick -3. Build with icon: -```bash -pyinstaller --icon=app_icon.ico label_printer_gui.py -``` - -### Two-File Distribution -Instead of `--onefile`, use separate files for faster startup: -```bash -pyinstaller label_printer_gui.py -``` -Creates `dist/` folder with all files (faster to run, easier to debug). - -### Console Output -To see error messages, remove `--windowed`: -```bash -pyinstaller --onefile --name=LabelPrinter label_printer_gui.py -``` - ---- - -## Build Options Reference - -| Option | Purpose | -|--------|---------| -| `--onefile` | Single executable (recommended) | -| `--windowed` | No console window | -| `--icon=file.ico` | Custom icon | -| `--hidden-import=module` | Include module that's not imported directly | -| `--collect-all=module` | Include all module data | -| `--distpath=folder` | Output directory | -| `--name=AppName` | Executable name | - ---- - -## Final Steps - -1. **Test the executable**: Run `LabelPrinter.exe` and test all features -2. **Verify PDF backup**: Check `pdf_backup/` folder is created -3. **Test printing**: Print a label to ensure PDF output works -4. **Share**: Distribute the `.exe` file to users - ---- - -## Questions? - -- Check the error message in the console -- Try rebuilding with `python build_exe.py` -- Ensure all dependencies are installed: `pip install -r requirements_windows.txt` -- Check that Python 3.11+ is installed: `python --version` - -Good luck! 🚀 diff --git a/README.md b/README.md deleted file mode 100644 index 1e04416..0000000 --- a/README.md +++ /dev/null @@ -1,234 +0,0 @@ -# Label Printer GUI - -A cross-platform barcode label printing application with a modern GUI. Create, generate, and print labels with automatic Code128 barcode encoding. - -## Features - -✨ **Core Features** -- 🎨 Beautiful Kivy GUI interface -- 📊 Automatic Code128 barcode generation -- 📄 High-quality PDF label generation -- 💾 Automatic PDF backup system -- ✅ Input validation with 25-character limit -- 🔢 Number-only filter for quantity field - -🖨️ **Printer Support** -- Windows printer detection and printing -- Linux CUPS printer support -- macOS printing support -- PDF fallback (works everywhere) - -🚀 **Distribution** -- PyInstaller support for standalone Windows .exe -- No Python installation needed -- Cross-platform source code (Windows, Linux, macOS) - -## Quick Start - -### Option 1: Python Source (Recommended for Development) - -```bash -# 1. Clone/Download the project -cd Label-design - -# 2. Create virtual environment -python -m venv venv -source venv/bin/activate # On Windows: venv\Scripts\activate - -# 3. Install dependencies -pip install -r requirements_gui.txt - -# 4. Run the app -python label_printer_gui.py -``` - -### Option 2: Windows Standalone Executable - -1. Download `LabelPrinter.exe` from releases -2. Double-click to run (no Python needed!) -3. First run takes ~5 seconds to initialize - -## Building Your Own Executable - -### Windows Build Steps - -```bash -# 1. Activate virtual environment -venv\Scripts\activate - -# 2. Install PyInstaller -pip install pyinstaller - -# 3. Build executable -python build_exe.py -``` - -Your executable will be in `dist/LabelPrinter.exe` (~200 MB) - -### Manual Build Command - -```bash -pyinstaller --onefile --windowed --name=LabelPrinter ^ - --hidden-import=kivy ^ - --hidden-import=kivy.core.window ^ - --hidden-import=kivy.core.text ^ - --hidden-import=kivy.core.image ^ - --hidden-import=kivy.uix.boxlayout ^ - --hidden-import=kivy.uix.gridlayout ^ - --hidden-import=kivy.uix.label ^ - --hidden-import=kivy.uix.textinput ^ - --hidden-import=kivy.uix.button ^ - --hidden-import=kivy.uix.spinner ^ - --hidden-import=kivy.uix.scrollview ^ - --hidden-import=kivy.uix.popup ^ - --hidden-import=kivy.clock ^ - --hidden-import=kivy.graphics ^ - --hidden-import=PIL ^ - --hidden-import=barcode ^ - --hidden-import=reportlab ^ - --hidden-import=print_label ^ - --hidden-import=print_label_pdf ^ - label_printer_gui.py -``` - -## File Structure - -``` -Label-design/ -├── label_printer_gui.py # Main GUI application -├── print_label.py # Printing functionality -├── print_label_pdf.py # PDF generation -├── build_exe.py # PyInstaller build script -├── requirements_gui.txt # GUI dependencies -├── pdf_backup/ # Generated label PDFs -├── dist/ # Built executables -├── documentation/ # Docs and guides -│ ├── WINDOWS_SETUP.md -│ ├── PYINSTALLER_GUIDE.md -│ └── [other docs] -└── venv/ # Python virtual environment -``` - -## Dependencies - -**Required (Core):** -- `python-barcode` - Barcode generation -- `pillow` - Image processing -- `reportlab` - PDF generation - -**GUI:** -- `kivy` - Cross-platform GUI framework - -**Optional (Printing):** -- `pycups` - Linux CUPS support -- `pywin32` - Windows printer support - -## Usage - -### Basic Workflow - -1. **Enter Data:** - - **SAP-Nr**: Article code (up to 25 chars) - - **Cantitate**: Quantity (numbers only) - - **ID rola**: Reel/Cable ID (up to 25 chars) - -2. **Select Printer:** - - Choose from detected printers - - Or select "PDF" for PDF output - -3. **Print:** - - Click "PRINT LABEL" - - PDF is auto-saved to `pdf_backup/` folder - - Label sent to printer - -### PDF Backup - -All generated labels are automatically saved with timestamps: -``` -pdf_backup/ -├── final_label_20260205_120530.pdf -├── final_label_20260205_120542.pdf -└── final_label_20260205_120555.pdf -``` - -## Guides - -- **[WINDOWS_SETUP.md](documentation/WINDOWS_SETUP.md)** - Windows installation guide -- **[PYINSTALLER_GUIDE.md](documentation/PYINSTALLER_GUIDE.md)** - Building executables -- **[documentation/](documentation/)** - All documentation - -## Troubleshooting - -### "No Printers Found" -This is normal. Select "PDF" option - labels will be saved to `pdf_backup/` folder. - -### "GUI Won't Start" -Ensure all dependencies are installed: -```bash -pip install -r requirements_gui.txt -``` - -### Windows Executable Issues -- Update PyInstaller: `pip install --upgrade pyinstaller` -- Rebuild: `python build_exe.py` -- Check dependencies: `pip list` - -### Kivy Graphics Issues -On Linux, you may need SDL2 dependencies: -```bash -sudo apt-get install libsdl2-dev libsdl2-image-dev libsdl2-mixer-dev libsdl2-ttf-dev -``` - -## Platform Support - -| Platform | Source | Executable | Status | -|----------|--------|-----------|--------| -| Windows | ✅ Yes | ✅ Yes | ✅ Fully Supported | -| Linux | ✅ Yes | ❌ No | ✅ Fully Supported | -| macOS | ✅ Yes | ⚠️ Possible | ⚠️ Untested | - -## Technical Details - -### Barcode Format -- **Type**: Code128 -- **Max Length**: 25 characters -- **DPI**: 300 (print quality) - -### PDF Specifications -- **Page Size**: 11.5 x 8 cm (landscape) -- **Quality**: High-resolution barcodes -- **Font**: Helvetica with automatic sizing - -### GUI Specifications -- **Framework**: Kivy 2.3+ -- **Size**: 420 x 700 pixels (mobile-optimized) -- **Color**: White text on dark background - -## Contributing - -Feel free to fork, modify, and improve! - -Suggested improvements: -- [ ] Custom barcode formats (QR, Code39, etc.) -- [ ] Batch label printing -- [ ] Label preview before printing -- [ ] Printer-specific settings -- [ ] Multi-language support -- [ ] Database integration - -## License - -Open source - modify and use freely - -## Support - -For issues, questions, or suggestions: -1. Check the documentation in `documentation/` folder -2. Review the code comments -3. Test with the source code first before building exe - ---- - -**Status**: Production Ready ✅ - -Last Updated: February 2026 diff --git a/__pycache__/print_label.cpython-313.pyc b/__pycache__/print_label.cpython-313.pyc index cacd18d..ba8207a 100644 Binary files a/__pycache__/print_label.cpython-313.pyc and b/__pycache__/print_label.cpython-313.pyc differ diff --git a/__pycache__/print_label_pdf.cpython-313.pyc b/__pycache__/print_label_pdf.cpython-313.pyc index b0ee2ab..1e7265f 100644 Binary files a/__pycache__/print_label_pdf.cpython-313.pyc and b/__pycache__/print_label_pdf.cpython-313.pyc differ diff --git a/build_windows.ps1 b/build_windows.ps1 deleted file mode 100644 index f563c1d..0000000 --- a/build_windows.ps1 +++ /dev/null @@ -1,99 +0,0 @@ -# Label Printer - Windows Build Script (Single File EXE) -# This script builds a standalone LabelPrinter.exe on Windows -# Requirements: Python 3.10-3.13 installed and in PATH -# Note: Python 3.14+ may have compatibility issues - -Write-Host "" -Write-Host "========================================================" -Write-Host " Label Printer - Windows Build Script" -Write-Host " Creates: LabelPrinter.exe (Single File)" -Write-Host "========================================================" -Write-Host "" - -# Check if Python is installed -try { - $pythonVersion = python --version 2>&1 - if ($LASTEXITCODE -ne 0) { - throw "Python not found" - } -} catch { - Write-Host "ERROR: Python is not installed or not in PATH" -ForegroundColor Red - Write-Host "Please install Python 3.10-3.13 from https://www.python.org/" - Write-Host "Make sure to check 'Add Python to PATH' during installation" - Read-Host "Press Enter to exit" - exit 1 -} - -Write-Host "[1/5] Checking Python installation..." -ForegroundColor Cyan -Write-Host $pythonVersion -Write-Host "" - -Write-Host "[2/5] Upgrading pip, setuptools, and wheel..." -ForegroundColor Cyan -python -m pip install --upgrade pip setuptools wheel -if ($LASTEXITCODE -ne 0) { - Write-Host "ERROR: Failed to upgrade pip" -ForegroundColor Red - Read-Host "Press Enter to exit" - exit 1 -} -Write-Host "" - -Write-Host "[3/5] Installing dependencies..." -ForegroundColor Cyan -Write-Host "Installing: python-barcode, pillow, reportlab, kivy, pyinstaller, pywin32, wmi..." -pip install python-barcode pillow reportlab kivy pyinstaller pywin32 wmi -if ($LASTEXITCODE -ne 0) { - Write-Host "ERROR: Failed to install dependencies" -ForegroundColor Red - Read-Host "Press Enter to exit" - exit 1 -} -Write-Host "" - -Write-Host "[4/5] Cleaning old build artifacts..." -ForegroundColor Cyan -if (Test-Path "dist") { Remove-Item -Recurse -Force "dist" } -if (Test-Path "build") { Remove-Item -Recurse -Force "build" } -Remove-Item -Force "*.spec" -ErrorAction SilentlyContinue -Write-Host "" - -Write-Host "[5/5] Building executable with PyInstaller..." -ForegroundColor Cyan -Write-Host "This may take 5-15 minutes, please wait..." -Write-Host "" - -$pyinstallerArgs = @( - "label_printer_gui.py", - "--onefile", - "--windowed", - "--name=LabelPrinter", - "--distpath=./dist", - "--workpath=./build", - "--hidden-import=kivy", - "--hidden-import=PIL", - "--hidden-import=barcode", - "--hidden-import=reportlab", - "--hidden-import=print_label", - "--hidden-import=print_label_pdf", - "-y" -) - -pyinstaller @pyinstallerArgs -if ($LASTEXITCODE -ne 0) { - Write-Host "" - Write-Host "ERROR: Build failed!" -ForegroundColor Red - Write-Host "Please check the error messages above." -ForegroundColor Red - Read-Host "Press Enter to exit" - exit 1 -} - -Write-Host "" -Write-Host "========================================================" -Write-Host " BUILD SUCCESSFUL!" -ForegroundColor Green -Write-Host "========================================================" -Write-Host "" -Write-Host "Executable Location: dist\LabelPrinter.exe" -ForegroundColor Green -Write-Host "" -Write-Host "Next steps:" -Write-Host " 1. Navigate to the dist folder" -Write-Host " 2. Double-click LabelPrinter.exe to run" -Write-Host " 3. You can copy LabelPrinter.exe to other machines" -Write-Host "" -Write-Host "Note: First run may take a moment as Kivy initializes" -Write-Host "" -Read-Host "Press Enter to exit" diff --git a/check_printer_quality.ps1 b/check_printer_quality.ps1 new file mode 100644 index 0000000..844e525 --- /dev/null +++ b/check_printer_quality.ps1 @@ -0,0 +1,67 @@ +# Check and configure printer quality settings for Labels printer + +$printerName = "Labels" + +Write-Host "=== Checking Printer: $printerName ===" -ForegroundColor Cyan +Write-Host "" + +# Get printer object +$printer = Get-Printer -Name $printerName -ErrorAction SilentlyContinue + +if ($null -eq $printer) { + Write-Host "ERROR: Printer '$printerName' not found!" -ForegroundColor Red + exit 1 +} + +Write-Host "Printer Name: $($printer.Name)" -ForegroundColor Green +Write-Host "Driver Name: $($printer.DriverName)" -ForegroundColor Green +Write-Host "Port Name: $($printer.PortName)" -ForegroundColor Green +Write-Host "" + +# Get printer configuration +try { + $printerConfig = Get-PrintConfiguration -PrinterName $printerName + Write-Host "=== Current Print Configuration ===" -ForegroundColor Cyan + Write-Host "Print Quality: $($printerConfig.PrintQuality)" + Write-Host "Color Mode: $($printerConfig.Color)" + Write-Host "Duplex Mode: $($printerConfig.DuplexingMode)" + Write-Host "" +} catch { + Write-Host "Could not retrieve print configuration: $_" -ForegroundColor Yellow +} + +# Get printer driver properties +Write-Host "=== Checking Printer Properties ===" -ForegroundColor Cyan +try { + $printerProperties = Get-PrinterProperty -PrinterName $printerName + foreach ($prop in $printerProperties) { + Write-Host "$($prop.PropertyName): $($prop.Value)" + } +} catch { + Write-Host "Could not retrieve printer properties: $_" -ForegroundColor Yellow +} + +Write-Host "" +Write-Host "=== Recommendations ===" -ForegroundColor Cyan +Write-Host "1. Open Windows Settings > Devices > Printers & scanners" +Write-Host "2. Click on 'Labels' printer" +Write-Host "3. Click 'Manage' > 'Printing preferences'" +Write-Host "4. Look for quality settings and set to:" +Write-Host " - Print Quality: Best/Highest/600 DPI or higher" +Write-Host " - Graphics Mode: Vector or High Quality" +Write-Host " - Dithering: None (for sharp text)" +Write-Host "5. Save settings and try printing again" +Write-Host "" +Write-Host "Would you like to try setting print quality to high? (Y/N)" -ForegroundColor Yellow +$response = Read-Host + +if ($response -eq 'Y' -or $response -eq 'y') { + try { + # Try to set print quality to high + Set-PrintConfiguration -PrinterName $printerName -PrintQuality 4 # 4 = High quality + Write-Host "Print quality set to HIGH" -ForegroundColor Green + } catch { + Write-Host "Could not set print quality automatically: $_" -ForegroundColor Yellow + Write-Host "Please set manually through printer preferences" -ForegroundColor Yellow + } +} diff --git a/conf/SumatraPDF-settings.txt b/conf/SumatraPDF-settings.txt new file mode 100644 index 0000000..7787273 --- /dev/null +++ b/conf/SumatraPDF-settings.txt @@ -0,0 +1,94 @@ +# For documentation, see https://www.sumatrapdfreader.org/settings/settings3-5-1.html +Theme = Light +FixedPageUI [ + TextColor = #000000 + BackgroundColor = #ffffff + SelectionColor = #f5fc0c + WindowMargin = 2 4 2 4 + PageSpacing = 4 4 + InvertColors = false + HideScrollbars = false +] +ComicBookUI [ + WindowMargin = 0 0 0 0 + PageSpacing = 4 4 + CbxMangaMode = false +] +ChmUI [ + UseFixedPageUI = false +] + +SelectionHandlers [ +] +ExternalViewers [ +] + +ZoomLevels = 8.33 12.5 18 25 33.33 50 66.67 75 100 125 150 200 300 400 600 800 1000 1200 1600 2000 2400 3200 4800 6400 +ZoomIncrement = 0 + +PrinterDefaults [ + PrintScale = noscale +] +ForwardSearch [ + HighlightOffset = 0 + HighlightWidth = 15 + HighlightColor = #6581ff + HighlightPermanent = false +] +Annotations [ + HighlightColor = #ffff00 + UnderlineColor = #00ff00 + SquigglyColor = #ff00ff + StrikeOutColor = #ff0000 + FreeTextColor = + FreeTextSize = 12 + FreeTextBorderWidth = 1 + TextIconColor = + TextIconType = + DefaultAuthor = +] + +RememberOpenedFiles = true +RememberStatePerDocument = true +RestoreSession = true +UiLanguage = en +EnableTeXEnhancements = false +DefaultDisplayMode = automatic +DefaultZoom = fit page +Shortcuts [ +] +EscToExit = false +ReuseInstance = false +ReloadModifiedDocuments = true + +MainWindowBackground = #80fff200 +FullPathInTitle = false +ShowMenubar = true +ShowToolbar = true +ShowFavorites = false +ShowToc = true +NoHomeTab = false +TocDy = 0 +SidebarDx = 0 +ToolbarSize = 18 +TabWidth = 300 +TreeFontSize = 0 +TreeFontWeightOffset = 0 +TreeFontName = automatic +SmoothScroll = false +ShowStartPage = false +CheckForUpdates = true +WindowState = 1 +WindowPos = 566 0 788 1020 +UseTabs = true +UseSysColors = false +CustomScreenDPI = 0 + +FileStates [ +] +SessionData [ +] +TimeOfLastUpdateCheck = 0 0 +OpenCountWeek = 788 + +# Settings below are not recognized by the current version diff --git a/conf/SumatraPDF.exe b/conf/SumatraPDF.exe new file mode 100644 index 0000000..f034e5e Binary files /dev/null and b/conf/SumatraPDF.exe differ diff --git a/conf/accepted.png b/conf/accepted.png new file mode 100644 index 0000000..d0d769d Binary files /dev/null and b/conf/accepted.png differ diff --git a/conf/app.conf b/conf/app.conf new file mode 100644 index 0000000..8fc5773 --- /dev/null +++ b/conf/app.conf @@ -0,0 +1,4 @@ +[Settings] +file_path = C:\Users\Public\Documents\check.txt +printer = Labels + diff --git a/conf/label_template.svg b/conf/label_template.svg new file mode 100644 index 0000000..1846eb1 --- /dev/null +++ b/conf/label_template.svg @@ -0,0 +1,63 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Nr. Comanda:{Article} + + + Nr. Art.:{NrArt} + + + Serial No.:{Serial} + + + + + + + + diff --git a/conf/refused.png b/conf/refused.png new file mode 100644 index 0000000..0270983 Binary files /dev/null and b/conf/refused.png differ diff --git a/dist/pdf_backup/final_label_20260205_234513.pdf b/dist/pdf_backup/final_label_20260205_234513.pdf deleted file mode 100644 index 36f4cd1..0000000 --- a/dist/pdf_backup/final_label_20260205_234513.pdf +++ /dev/null @@ -1,103 +0,0 @@ -%PDF-1.3 -% ReportLab Generated PDF document (opensource) -1 0 obj -<< -/F1 2 0 R /F2 3 0 R ->> -endobj -2 0 obj -<< -/BaseFont /Helvetica /Encoding /WinAnsiEncoding /Name /F1 /Subtype /Type1 /Type /Font ->> -endobj -3 0 obj -<< -/BaseFont /Helvetica-Bold /Encoding /WinAnsiEncoding /Name /F2 /Subtype /Type1 /Type /Font ->> -endobj -4 0 obj -<< -/BitsPerComponent 8 /ColorSpace /DeviceRGB /Filter [ /ASCII85Decode /FlateDecode ] /Height 118 /Length 7282 /Subtype /Image - /Type /XObject /Width 773 ->> -stream -Gb"/__/00,%)][Vdd7;p#gt]*eiT&:r;L"TQcnK2\QgbRbN3cT>V;Adj`7n:/sjcCEk,F-QcnK2\QgbRbN3cT>V;Adj`7n:/sjcCEk,F-QcnK2\QgbRbN3cT>V;Adj`7n:/sjcCEk,F-QZml_RC'c3:4]f<3Z(LU3FjQ=i"!bAJ_:NO9me/(`0isN37Q`rodLa)MQDTV$8;ilB&^u"j:H[5-q*>!iS!K1=::pWYnWEiQ3%'S@&t-2mI8]F-W3X..27e0c-9IbJcW!pHFU$VZ`n!fY09WNYr@P,PjTWbX\OGT5WT`T5riI)!8n@,C4Y%JDbYU'`Pe02iAf?B]_*]jd#+o[b6fp2>@um;m,S_)UF8Opro)Pq'Nba=K'h,/qKg6K'oRgq<;/(sn/ALW^#Y$X76&b3\1#H_VuWl2KYpl4d>.Uk>odPXC`G$KJXiPguX8oT2AL=S(:(FNfMF*Qq+.fT0J[Ia((e[.TA17N:%`W77fa_ppHm6PJR6ojleD._0.2^EhXG=t+0FM)sil^WK&::0#7-X^0g$08R$`&E['U1tN!W_XrX;72jnCGN*;G!iS!K1=::pWYnWEiQ3%'S@&t-2mI8]F-W3X..27e0c-9IbJcW!pHFU$VZ`n!fY09WNYr@P,PjTWbX\OGT5WT`T5riI)!8n@,C4Y%JDbYU'`Pe02iAf?B]_*]jd#+o[b6fp2>@um;m,S_)UF8Opro)Pq'Nba=K'h,/qKg6K'oRgq<;/(sn/ALW^#Y$X76&b3\1#H_VuWl2KYpl4d>.Uk>odPXC`G$KJXiPguX8oT2AL=S(:(FNfMF*Qq+.fT0J[Ia((e[.TA17N:%`W77fa_ppHm6PJR6ojleD._0.2^EhXG=t+0FM)sil^WK&::0#7-X^0g$08R$`&E['U1tN!W_XrX;72jnCGN*;G!iS!K1=::pWYnWEiQ3%'S@&t-2mI8]F-W3X..27e0c-9IbJcW!pHFU$VZ`n!fY09WNYr@P,PjTWbX\OGT5WT`T5riI)!8n@,C4Y%JDbYU'`Pe02iAf?B]_*]jd#+o[b6fp2>@um;m,S_)UF8Opro)Pq'Nba=K'h,/qKg6K'oRgq<;/(sn/ALW^#Y$X76&b3\1#H_VuWl2KYpl4d>.Uk>odPXC`G$KJXiPguX8oT2AL=S(:(FNfMF*Qq+.fT0J[Ia((e[.TA17N:%`W77fa_ppHm6PJR6ojleD._0.2^EhXG=t+0FM)sil^WK&::0#7-X^0g$08R$`&E['U1tN!W_XrX;72jnCGN*;G!iS!K1=::pWYnWEiQ3%'S@&t-2mI8]F-W3X..27e0c-9IbJcW!pHFU$VZ`n!fY09WNYr@P,PjTWbX\OGT5WT`T5riI)!8n@,C4Y%JDbYU'`Pe02iAf?B]_*]jd#+o[b6fp2>@um;m,S_)UF8Opro)Pq'Nba=K'h,/qKg6K'oRgq<;/(sn/ALW^#Y$X76&b3\1#H_VuWl2KYpl4d>.Uk>odPXC`G$KJXiPguX8oT2AL=S(:(FNfMF*Qq+.fT0J[Ia((e[.TA17N:%`W77fa_ppHm6PJR6ojleD._0.2^EhXG=t+0FM)sil^WK&::0#7-X^0g$08R$`&E['U1tN!W_XrX;72jnCGN*;G!iS!K1=::pWYnWEiQ3%'S@&t-2mI8]F-W3X..27e0c-9IbJcW!pHFU$VZ`n!fY09WNYr@P,PjTWbX\OGT5WT`T5riI)!8n@,C4Y%JDbYU'`Pe02iAf?B]_*]jd#+o[b6fp2>@um;m,S_)UF8Opro)Pq'Nba=K'h,/qKg6K'oRgq<;/(sn/ALW^#Y$X76&b3\1#H_VuWl2KYpl4d>.Uk>odPXC`G$KJXiPguX8oT2AL=S(:(FNfMF*Qq+.fT0J[Ia((e[.TA17N:%`W77fa_ppHm6PJR6ojleD._0.2^EhXG=t+0FM)sil^WK&::0#7-X^0g$08R$`&E['U1tN!W_XrX;72jnCGN*;G!iS!K1=::pWYnWEiQ3%'S@&t-2mI8]F-W3X..27e0c-9IbJcW!pHFU$VZ`n!fY09WNYr@P,PjTWbX\OGT5WT`T5riI)!8n@,C4Y%JDbYU'`Pe02iAf?B]_*]jd#+o[b6fp2>@um;m,S_)UF8Opro)Pq'Nba=K'h,/qKg6K'oRgq<;/(sn/ALW^#Y$X76&b3\1#H_VuWl2KYpl4d>.Uk>odPXC`G$KJXiPguX8oT2AL=S(:(FNfMF*Qq+.fT0J[Ia((e[.TA17N:%`W77fa_ppHm6PJR6ojleD._0.2^EhXG=t+0FM)sil^WK&::0#7-X^0g$08R$`&E['U1tN!W_XrX;72jnCGN*;G!iS!K1=::pWYnWEiQ3%'S@&t-2mI8]F-W3X..27e0c-9IbJcW!pHFU$VZ`n!fY09WNYr@P,PjTWbX\OGT5WT`T5riI)!8n@,C4Y%JDbYU'`Pe02iAf?B]_*]jd#+o[b6fp2>@um;m,S_)UF8Opro)Pq'Nba=K'h,/qKg6K'oRgq<;/(sn/ALW^#Y$X76&b3\1#H_VuWl2KYpl4d>.Uk>odPXC`G$KJXiPguX8oT2AL=S(:(FNfMF*Qq+.fT0J[Ia((e[.TA17N:%`W77fa_ppHm6PJR6ojleD._0.2^EhXG=t+0FM)sil^WK&::0#7-X^0g$08R$`&E['U1tN!W_XrX;72jnCGN*;G!iS!K1=::pWYnWEiQ3%'S@&t-2mI8]F-W3X..27e0c-9IbJcW!pHFU$VZ`n!fY09WNYr@P,PjTWbX\OGT5WT`T5riI)!8n@,C4Y%JDbYU'`Pe02iAf?B]_*]jd#+o[b6fp2>@um;m,S_)UF8Opro)Pq'Nba=K'h,/qKg6K'oRgq<;/(sn/ALW^#Y$X76&b3\1#H_VuWl2KYpl4d>.Uk>odPXC`G$KJXiPguX8oT2AL=S(:(FNfMF*Qq+.fT0J[Ia((e[.TA17N:%`W77fa_ppHm6PJR6ojleD._0.2^EhXG=t+0FM)sil^WK&::0#7-X^0g$08R$`&E['U1tN!W_XrX;72jnCGN*;G!iS!K1=::pWYnWEiQ3%'S@&t-2mI8]F-W3X..27e0c-9IbJcW!pHFU$VZ`n!fY09WNYr@P,PjTWbX\OGT5WT`T5riI)!8n@,C4Y%JDbYU'`Pe02iAf?B]_*]jd#+o[b6fp2>@um;m,S_)UF8Opro)Pq'Nba=K'h,/qKg6K'oRgq<;/(sn/ALW^#Y$X76&b3\1#H_VuWl2KYpl4d>.Uk>odPXC`G$KJXiPguX8oT2AL=S(:(FNfMF*Qq+.fT0J[Ia((e[.TA17N:%`W77fa_ppHm6PJR6ojleD._0.2^EhXG=t+0FM)sil^WK&::0#7-X^0g$08R$`&E['U1tN!W_XrX;72jnCGN*;G!iS!K1=::pWYnWEiQ3%'S@&t-2mI8]F-W3X..27e0c-9IbJcW!pHFU$VZ`n!fY09WNYr@P,PjTWbX\OGT5WT`T5riI)!8n@,C4Y%JDbYU'`Pe02iAf?B]_*]jd#+o[b6fp2>@um;m,S_)UF8Opro)Pq'Nba=K'h,/qKg6K'oRgq<;/(sn/ALW^#Y$X76&b3\1#H_VuWl2KYpl4d>.Uk>odPXC`G$KJXiPguX8oT2AL=S(:(FNfMF*Qq+.fT0J[Ia((e[.TA17N:%`W77fa_ppHm6PJR6ojleD._0.2^EhXG=t+0FM)sil^WK&::0#7-X^0g$08R$`&E['U1tN!W_XrX;72jnCGN*;G!iS!K1=::pWYnWEiQ3%'S@&t-2mI8]F-W3X..27e0c-9IbJcW!pHFU$VZ`n!fY09WNYr@P,PjTWbX\OGT5WT`T5riI)!8n@,C4Y%JDbYU'`Pe02iAf?B]_*]jd#+o[b6fp2>@um;m,S_)UF8Opro)Pq'Nba=K'h,/qKg6K'oRgq<;/(sn/ALW^#Y$X76&b3\1#H_VuWl2KYpl4d>.Uk>odPXC`G$KJXiPguX8oT2AL=S(:(FNfMF*Qq+.fT0J[Ia((e[.TA17N:%`W77fa_ppHm6PJR6ojleD._0.2^EhXG=t+0FM)sil^WK&::0#7-X^0g$08R$`&E['U1tN!W_XrX;72jnCGN*;G!iS!K1=::pWYnWEiQ3%'S@&t-2mI8]F-W3X..27e0c-9IbJcW!pHFU$VZ`n!fY09WNYr@P,PjTWbX\OGT5WT`T5riI)!8n@,C4Y%JDbYU'`Pe02iAf?B]_*]jd#+o[b6fp2>@um;m,S_)UF8Opro)Pq'Nba=K'h,/qKg6K'oRgq<;/(sn/ALW^#Y$X76&b3\1#H_VuWl2KYpl4d>.Uk>odPXC`G$KJXiPguX8oT2AL=S(:(FNfMF*Qq+.fT0J[Ia((e[.TA17N:%`W77fa_ppHm6PJR6ojleD._0.2^EhXG=t+0FM)sil^WK&::0#7-X^0g$08R$`&E['U1tN!W_XrX;72jnCGN*;GK6Ek,F-QcnK2\QgbRbN3cT>V;Adj`7n:/sjcCEk,F-QcnK2\QgbRbN3cT>V;Adj`7n:/sjcCEk,F-QcnK2\QgbRbN3cT>V;Adj`7n:/sjcCndkendstream -endobj -5 0 obj -<< -/BitsPerComponent 8 /ColorSpace /DeviceRGB /Filter [ /ASCII85Decode /FlateDecode ] /Height 118 /Length 3991 /Subtype /Image - /Type /XObject /Width 383 ->> -stream -Gb"/_3J%>u#fH65:FH*!A$j)fY!G7chp^h33h9$De*1s8SPH*3l#\tW:8cS*F?5sfVpjmP3h9$De*1s8SPH*3J+X,4Hs'b_FuI0iUBCeRd-GtpYZ:p]CrNGT8?aXOXhp7pG$nV`FuI0iUBCeRd-GtpYZ:p]CrNGT8?aXOXhp7pG$nV`FuI0iUBCeRd-GtpYZ:p]CrNGT8?aXOXhp7pG$nV`FuI0iUBCeRd-GtpYZ:p]CrNGT8?aXOXhp7pG$nV`FuI0iUBCeRd-GtpYZ:p]CrNGT8?aXOXhp7pG$nV`FuI0iUBCeRd-GtpYZ:p]CrNGT8?aXOXhp7pG$nV`FuI0iUBCeRd-GtpYZ:p]CrNGT8?aXOXhp7pG$nV`FuI0iUBCeRd-GtpYZ:p]CrNGT8?aXOXhp7pG$nV`FuI0iUBCeRd-GtpYZ:p]CrNGT8?aXOXhp7pG$nV`FuI0iUBCeRd-GtpYZ:p]CrNGT8?aXOXhp7pG$nV`FuI0iUBCeRd-GtpYZ:p]CrNGT8?aXOXhp7pG$nV`FuI0iUBCeRd-GtpYZ:p]CrNGT8?aXOXhp7pG$nV`FuI0iUBCeRd-GtpYZ:p]CrNGT8?aXOXhp7pG$nV`FuI0iUBCeRd-GtpYZ:p]CrNGT8?aXOXhp7pG$nV`FuI0iUBCeRd-GtpYZ:p]CrNGT8?aXOXhp7pG$nV`FuI0iUBCeRd-GtpYZ:p]CrNGT8?aXOXhp7pG$nV`FuI0iUBCeRd-GtpYZ:p]CrNGT8?aXOXhp7pG$nV`FuI0iUBCeRd-GtpYZ:p]CrNGT8?aXOXhp7pG$nV`FuI0iUBCeRd-GtpYZ:p]CrNGT8?aXOXhp7pG$nV`FuI0iUBCeRd-GtpYZ:p]CrNGT8?aXOXhp7pG$nV`FuI0iUBCeRd-GtpYZ:p]CrNGT8?aXOXhp7pG$nV`FuI0iUBCeRd-GtpYZ:p]CrNGT8?aXOXhp7pG$nV`FuI0iUBCeRd-GtpYZ:p]CrNGT8?aXOXhp7pG$nV`FuI0iUBCeRd-GtpYZ:p]CrNGT8?aXOXhp7pG$nV`FuI0iUBCeRd-GtpYZ:p]CrNGT8?aXOXhp7pG$nV`FuI0iUBCeRd-GtpYZ:p]CrNGT8?aXOXhp7pG$nV`FuI0iUBCeRd-GtpYZ:p]CrNGT8?aXOXhp7pG$nV`FuI0iUBCeRd-GtpYZ:p]CrNGT8?aXOXhp7pG$nV`FuI0iUBCeRd-GtpYZ:p]CrNGT8?aXOXhp7pG$nV`FuI0iUBCeRd-GtpYZ:p]CrNGT8?aXOXhp7pG$nV`FuI0iUBCeRd-GtpYZ:p]CrNGT8?aXOXhp7pG$nV`FuI0iUBCeRd-GtpYZ:p]CrNGT8?aXOXhp7pG$nV`FuI0iUBCeRd-GtpYZ:p]CrNGT8?aXOXhp7pG$nV`FuI0iUBCeRd-GtpYZ:p]CrNGT8?aXOXhp7pG$nV`FuI0iUBCeRd-GtpYZ:p]CrNGT8?aXOXhp7pG$nV`FuI0iUBCeRd-GtpYZ:p]CrNGT8?aXOXhp7pG$nV`FuI0iUBCeRd-GtpYZ:p]CrNGT8?aXOXhp7pG$nV`FuI0iUBCeRd-GtpYZ:p]CrNGT8?aXOXhp7pG$nV`FuI0iUBCeRd-GtpYZ:p]CrNGT8?aXOXhp7pG$nV`FuI0iUBCeRd-GtpYZ:p]CrNGT8?aXOXhp7pG$nV`FuI0iUBCeRd-GtpYZ:p]CrNGT8?aXOXhp7pG$nV`FuI0iUBCeRd-GtpYZ:p]CrNGT8?aXOXhp7pG$nV`FuI0iUBCeRd-GtpYZ:p]CrNGT8?aXOXhp7pG$nV`FuI0iUBCeRd-GtpYZ:p]CrNGT8?aXOXhp7pG$nV`FuI0iUBCeRd-GtpYZ:p]CrNGT8?aXOXhp7pG$nV`FuI0iUBCeRd-GtpYZ:p]CrNGT8?aXOXhp7pG$nV`FuI0iUBCeRd-GtpYZ:p]CrNGT8?aXOXhp7pG$nV`FuI0iUBCeRd-GtpYZ:p]CrNGT8?aXOXhp7pG$nV`FuI0iUBCeRd-GtpYZ:p]CrNGT8?aXOXhp7pG$nV`FuI0iUBCeRd-GtpYZ:p]CrNGT8?aXOXhp7pG$nV`FuI0iUBCeRd-GtpYZ:p]CrNGT8?aXOXhp7pG$nV`FuI0iUBCeRd-GtpYZ:p]CrNGT8?aXOXhp7pG$nV`FuI0iUBCeRd-GtpYZ:p]CrNGT8?aXOXhp7pG$nV`FuI0iUBCeRd-GtpYZ:p]CrNGT8?aXOXhp7pG$nV`FuI0iUBCeRd-GtpYZ:p]CrNGT8?aXOXhp7pG$nV`FuI0iUBCeRd-GtpYZ:p]CrNGT8?aXOXhp7pG$nV`FuI0iUBCeRd-GtpYZ:p]CrNGT8?aXOXhp7pG$nV`FuI0iUBCeRd-GtpYZ:p]CrNGT8?aXOXhp7pG$nV`FuI0iUBCeRd-GtpYZ:p]CrNGT8?aXOXhp7pG$nV`FuI0iUBCeRd-GtpYZ:p]CrNGT8?aXOXhp7pG$nV`FuI0iUBCeRd-GtpYZ:p]CrNGT8?aXOXhp7pG$nV`FuI0iUBCeRd-GtpYZ:p]CrNGT8?aXOXhp7pG$nV`FuI0iUBCeRd-GtpYZ:p]CrNGT8?aXOXhp7pG$nV`FuI0iUBCeRd-GtpYZ:p]CrNGT8?aXOXhp7pG$nV`FuI0iUBCeRd-GtpYZ:p]CrNGT8?aXOXhp7pG$nV`FuI0iUBCeRd-GtpYZ:p]CrNGT8?aXOXhp7pG$nV`FuI0iUBCeRd-GtpYZ:p]CrNGT8?aXOXhp7pG$nV`FuI0iUBCeRd-GtpYZ:p]CrNGT8?aXOXhp7pG$nV`FuI0iUBCeRd-GtpYZ:p]CrNGT8?aXOXhp7pG$nV`FuI0iUBCeRd-GtpYZ:p]CrNGT8?aXOXhp7pG$nV`FuI0iUBCeRd-GtpYZ:p]CrNGT8?aXOXhp7pG$nV`FuI0iUBCeRd-GtpYZ:p]CrNGT8?aXOXhp7pG$nV`FuI0iUBCeRd-GtpYZ:p]CrNGT8?aXOXhp7pG$nV`FuI0iUBCeRd-GtpYZ:p]CrNGT8?aXOXhp7pG$nV`FuI0iUBCeRd-GtpYZ:p]CrNGT8?aXOXhp7pG$nV`FuI0iUBCeRd-GtpYZ:p]CrNGT8?aXOXhp7pG$nV`FuI0iUBCeRd-GtpYZ:p]CrNGT8?aXOXhp7pG$nV`FuI0iUBCeRd-GtpYZ:p]CrNGT8?aXOXhp7pG$nV`FuI0iUBCeRd-GtpYZ:p]CrNGT8?aXOXhp7pG$nV`FuI0iUBCeRd-GtpYZ:p]CrNGT8?aXOXhp7pG$nV`FuI0iUBCeRd-GtpYZ:p]CrNGT8?aXOXhp7pG$nV`FuI0iUBCeRd-GtpYZ:p]CrNGT8?aXOXhp7pG$nV`FuI0iUBCeRd-GtpYZ:p]CrNGT8?aXOXhp7pG$nV`FuI0iUBCeRd-GtpYZ:p]CrNGT8?aXOXhp7pG$nV`FuI0iUBCeRd-GtpYZ:p]CrNGT8?aXOXhp7pG$nV`FuI0iUBCeRd-GtpYZ:p]CrNGT8?aXOXhp7pG$nV`FuI0iUBCeRd-GtpYZ:p]CrNGT8?aXOXhp7pG$nV`FuI0iUBCeRd-GtpYZ:p]CrNGT8?aXOXhp7pG$nV`FuI0iUBCeRd-GtpYZ:p]CrNGT8?aXOXhp7pG$nV`FuI0iUBCeRd-GtpYZ:p]CrNGT8?aXOXhp7pG$nV`FuI0iUBCeRd-GtpYZ:p]CrNGT8?aXOXhp7pG$nV`FuI0iUBCeRd-GtpYZ:p]CrNGT8?aXOXhp7pG$nV`FuI0iUBCeRd-GtpYZ:p]CrNGT8?aXOXhp7pG$nV`FuI0iUBCeRd-GtpYZ:p]CrNGT8?aXOXhp7pG$nV`FuI0iUBCeRd-GtpYZ:p]CrNGT8?aXOXhp7pG$nV`FuI0iUBCeRd-GtpYZ:p]CrNGT8?aXOXhs=E3h9$De*1s8SPH*3l#\tW:8cS*F?5sfVpjmP3h9$De*1s8SPH*3l&U:2_7C'~>endstream -endobj -6 0 obj -<< -/BitsPerComponent 8 /ColorSpace /DeviceRGB /Filter [ /ASCII85Decode /FlateDecode ] /Height 118 /Length 13122 /Subtype /Image - /Type /XObject /Width 1293 ->> -stream -Gb"/_;%DDA&B"5@QgS0&5kGmK70Dl1,EquqkN(^bjQ,C_jQ,C_jQ,C_jQ,C_jQ,C_jQ,C_jQ,C_jQ,C_jQ,C_jQ,C_jQ,C_jQ,C_jQ,C_jQ,C_jQ,C_jQ,C_jQ,C_jQ,C_jQ,C_jQ,C_jQ,C_jQ,C_jQ,C_jQ,C_jQ,C_jQ,C_jQ,C_jQ,C_jQ,C_jQ,C_jQ,C_jQ,C_jQ,C_jQ,C_jQ,C_jQ,C_jQ,C_jQ,C_jQ,C_jQ,C_jQ,4>Im]MPn5lMqome_Y9*%Rd0\/4m=3HF(UPN+r0c6qrK]+Y>#l"K/S`]=iCY"er#K-$F"U8InZT!cYElFK>)rW5WBoauh]H9`;g;i#rgT[7E0?G0rfM0CW^:JkLRQ8j5d-nJH$q7.*OZC6?PZB_A]e1u$E3Pkl*00C7/J74:L0:S`I\uh:\jf`#5L^I"D*Cd#A#A`:0MJ+M5!D$?Iei:-?bD?CtLg(rU(ommpiA$#lp]Ckok3^]7es:Oc_se?D#%NLr2i>Im`L?D`OeZ4qhR"_3O5HaTAG0T*C5&VI?75StP@Lk%^_ctV?C]k2,S_PS"mO*Xd8,2Y?rB-$;m$.7]C&+CZ/i^BIc^V86IXt34Du4M$9Z1>9>R:Ws==:0nfo.!t(U]mF?"'Q?WYPn.Z$1@u7NNMSaDQR\(PX/#sOi.pIi;8hC^cRNjraoto/Y!uR?&p9H]IX4qB'?N0foJZ',KfjU,&G-D`gVMM[d'S)DO@uYPV[@C>QMR`J[MeKW1_WqEN;+:"(*]D*AE"PM/"]5UUdtHeSEa%GR).U'En\NM6f-u_K*VaT,Z`>Wu5"i>DW\Z/JGU^,3AVt.O9*%Rd0\/4m=3HF(UPN+r0c6qrK]+Y>#l"K/S`]=iCY"er#K-$F"U8InZT!cYElFK>)rW5WBoauh]H9`;g;i#rgT[7E0?G0rfM0CW^:JkLRQ8j5d-nJH$q7.*OZC6?PZB_A]e1u$E3Pkl*00C7/J74:L0:S`I\uh:\jf`#5L^I"D*Cd#A#A`:0MJ+M5!D$?Iei:-?bD?CtLg(rU(ommpiA$#lp]Ckok3^]7es:Oc_se?D#%NLr2i>Im`L?D`OeZ4qhR"_3O5HaTAG0T*C5&VI?75StP@Lk%^_ctV?C]k2,S_PS"mO*Xd8,2Y?rB-$;m$.7]C&+CZ/i^BIc^V86IXt34Du4M$9Z1>9>R:Ws==:0nfo.!t(U]mF?"'Q?WYPn.Z$1@u7NNMSaDQR\(PX/#sOi.pIi;8hC^cRNjraoto/Y!uR?&p9H]IX4qB'?N0foJZ',KfjU,&G-D`gVMM[d'S)DO@uYPV[@C>QMR`J[MeKW1_WqEN;+:"(*]D*AE"PM/"]5UUdtHeSEa%GR).U'En\NM6f-u_K*VaT,Z`>Wu5"i>DW\Z/JGU^,3AVt.O9*%Rd0\/4m=3HF(UPN+r0c6qrK]+Y>#l"K/S`]=iCY"er#K-$F"U8InZT!cYElFK>)rW5WBoauh]H9`;g;i#rgT[7E0?G0rfM0CW^:JkLRQ8j5d-nJH$q7.*OZC6?PZB_A]e1u$E3Pkl*00C7/J74:L0:S`I\uh:\jf`#5L^I"D*Cd#A#A`:0MJ+M5!D$?Iei:-?bD?CtLg(rU(ommpiA$#lp]Ckok3^]7es:Oc_se?D#%NLr2i>Im`L?D`OeZ4qhR"_3O5HaTAG0T*C5&VI?75StP@Lk%^_ctV?C]k2,S_PS"mO*Xd8,2Y?rB-$;m$.7]C&+CZ/i^BIc^V86IXt34Du4M$9Z1>9>R:Ws==:0nfo.!t(U]mF?"'Q?WYPn.Z$1@u7NNMSaDQR\(PX/#sOi.pIi;8hC^cRNjraoto/Y!uR?&p9H]IX4qB'?N0foJZ',KfjU,&G-D`gVMM[d'S)DO@uYPV[@C>QMR`J[MeKW1_WqEN;+:"(*]D*AE"PM/"]5UUdtHeSEa%GR).U'En\NM6f-u_K*VaT,Z`>Wu5"i>DW\Z/JGU^,3AVt.O9*%Rd0\/4m=3HF(UPN+r0c6qrK]+Y>#l"K/S`]=iCY"er#K-$F"U8InZT!cYElFK>)rW5WBoauh]H9`;g;i#rgT[7E0?G0rfM0CW^:JkLRQ8j5d-nJH$q7.*OZC6?PZB_A]e1u$E3Pkl*00C7/J74:L0:S`I\uh:\jf`#5L^I"D*Cd#A#A`:0MJ+M5!D$?Iei:-?bD?CtLg(rU(ommpiA$#lp]Ckok3^]7es:Oc_se?D#%NLr2i>Im`L?D`OeZ4qhR"_3O5HaTAG0T*C5&VI?75StP@Lk%^_ctV?C]k2,S_PS"mO*Xd8,2Y?rB-$;m$.7]C&+CZ/i^BIc^V86IXt34Du4M$9Z1>9>R:Ws==:0nfo.!t(U]mF?"'Q?WYPn.Z$1@u7NNMSaDQR\(PX/#sOi.pIi;8hC^cRNjraoto/Y!uR?&p9H]IX4qB'?N0foJZ',KfjU,&G-D`gVMM[d'S)DO@uYPV[@C>QMR`J[MeKW1_WqEN;+:"(*]D*AE"PM/"]5UUdtHeSEa%GR).U'En\NM6f-u_K*VaT,Z`>Wu5"i>DW\Z/JGU^,3AVt.O9*%Rd0\/4m=3HF(UPN+r0c6qrK]+Y>#l"K/S`]=iCY"er#K-$F"U8InZT!cYElFK>)rW5WBoauh]H9`;g;i#rgT[7E0?G0rfM0CW^:JkLRQ8j5d-nJH$q7.*OZC6?PZB_A]e1u$E3Pkl*00C7/J74:L0:S`I\uh:\jf`#5L^I"D*Cd#A#A`:0MJ+M5!D$?Iei:-?bD?CtLg(rU(ommpiA$#lp]Ckok3^]7es:Oc_se?D#%NLr2i>Im`L?D`OeZ4qhR"_3O5HaTAG0T*C5&VI?75StP@Lk%^_ctV?C]k2,S_PS"mO*Xd8,2Y?rB-$;m$.7]C&+CZ/i^BIc^V86IXt34Du4M$9Z1>9>R:Ws==:0nfo.!t(U]mF?"'Q?WYPn.Z$1@u7NNMSaDQR\(PX/#sOi.pIi;8hC^cRNjraoto/Y!uR?&p9H]IX4qB'?N0foJZ',KfjU,&G-D`gVMM[d'S)DO@uYPV[@C>QMR`J[MeKW1_WqEN;+:"(*]D*AE"PM/"]5UUdtHeSEa%GR).U'En\NM6f-u_K*VaT,Z`>Wu5"i>DW\Z/JGU^,3AVt.O9*%Rd0\/4m=3HF(UPN+r0c6qrK]+Y>#l"K/S`]=iCY"er#K-$F"U8InZT!cYElFK>)rW5WBoauh]H9`;g;i#rgT[7E0?G0rfM0CW^:JkLRQ8j5d-nJH$q7.*OZC6?PZB_A]e1u$E3Pkl*00C7/J74:L0:S`I\uh:\jf`#5L^I"D*Cd#A#A`:0MJ+M5!D$?Iei:-?bD?CtLg(rU(ommpiA$#lp]Ckok3^]7es:Oc_se?D#%NLr2i>Im`L?D`OeZ4qhR"_3O5HaTAG0T*C5&VI?75StP@Lk%^_ctV?C]k2,S_PS"mO*Xd8,2Y?rB-$;m$.7]C&+CZ/i^BIc^V86IXt34Du4M$9Z1>9>R:Ws==:0nfo.!t(U]mF?"'Q?WYPn.Z$1@u7NNMSaDQR\(PX/#sOi.pIi;8hC^cRNjraoto/Y!uR?&p9H]IX4qB'?N0foJZ',KfjU,&G-D`gVMM[d'S)DO@uYPV[@C>QMR`J[MeKW1_WqEN;+:"(*]D*AE"PM/"]5UUdtHeSEa%GR).U'En\NM6f-u_K*VaT,Z`>Wu5"i>DW\Z/JGU^,3AVt.O9*%Rd0\/4m=3HF(UPN+r0c6qrK]+Y>#l"K/S`]=iCY"er#K-$F"U8InZT!cYElFK>)rW5WBoauh]H9`;g;i#rgT[7E0?G0rfM0CW^:JkLRQ8j5d-nJH$q7.*OZC6?PZB_A]e1u$E3Pkl*00C7/J74:L0:S`I\uh:\jf`#5L^I"D*Cd#A#A`:0MJ+M5!D$?Iei:-?bD?CtLg(rU(ommpiA$#lp]Ckok3^]7es:Oc_se?D#%NLr2i>Im`L?D`OeZ4qhR"_3O5HaTAG0T*C5&VI?75StP@Lk%^_ctV?C]k2,S_PS"mO*Xd8,2Y?rB-$;m$.7]C&+CZ/i^BIc^V86IXt34Du4M$9Z1>9>R:Ws==:0nfo.!t(U]mF?"'Q?WYPn.Z$1@u7NNMSaDQR\(PX/#sOi.pIi;8hC^cRNjraoto/Y!uR?&p9H]IX4qB'?N0foJZ',KfjU,&G-D`gVMM[d'S)DO@uYPV[@C>QMR`J[MeKW1_WqEN;+:"(*]D*AE"PM/"]5UUdtHeSEa%GR).U'En\NM6f-u_K*VaT,Z`>Wu5"i>DW\Z/JGU^,3AVt.O9*%Rd0\/4m=3HF(UPN+r0c6qrK]+Y>#l"K/S`]=iCY"er#K-$F"U8InZT!cYElFK>)rW5WBoauh]H9`;g;i#rgT[7E0?G0rfM0CW^:JkLRQ8j5d-nJH$q7.*OZC6?PZB_A]e1u$E3Pkl*00C7/J74:L0:S`I\uh:\jf`#5L^I"D*Cd#A#A`:0MJ+M5!D$?Iei:-?bD?CtLg(rU(ommpiA$#lp]Ckok3^]7es:Oc_se?D#%NLr2i>Im`L?D`OeZ4qhR"_3O5HaTAG0T*C5&VI?75StP@Lk%^_ctV?C]k2,S_PS"mO*Xd8,2Y?rB-$;m$.7]C&+CZ/i^BIc^V86IXt34Du4M$9Z1>9>R:Ws==:0nfo.!t(U]mF?"'Q?WYPn.Z$1@u7NNMSaDQR\(PX/#sOi.pIi;8hC^cRNjraoto/Y!uR?&p9H]IX4qB'?N0foJZ',KfjU,&G-D`gVMM[d'S)DO@uYPV[@C>QMR`J[MeKW1_WqEN;+:"(*]D*AE"PM/"]5UUdtHeSEa%GR).U'En\NM6f-u_K*VaT,Z`>Wu5"i>DW\Z/JGU^,3AVt.O9*%Rd0\/4m=3HF(UPN+r0c6qrK]+Y>#l"K/S`]=iCY"er#K-$F"U8InZT!cYElFK>)rW5WBoauh]H9`;g;i#rgT[7E0?G0rfM0CW^:JkLRQ8j5d-nJH$q7.*OZC6?PZB_A]e1u$E3Pkl*00C7/J74:L0:S`I\uh:\jf`#5L^I"D*Cd#A#A`:0MJ+M5!D$?Iei:-?bD?CtLg(rU(ommpiA$#lp]Ckok3^]7es:Oc_se?D#%NLr2i>Im`L?D`OeZ4qhR"_3O5HaTAG0T*C5&VI?75StP@Lk%^_ctV?C]k2,S_PS"mO*Xd8,2Y?rB-$;m$.7]C&+CZ/i^BIc^V86IXt34Du4M$9Z1>9>R:Ws==:0nfo.!t(U]mF?"'Q?WYPn.Z$1@u7NNMSaDQR\(PX/#sOi.pIi;8hC^cRNjraoto/Y!uR?&p9H]IX4qB'?N0foJZ',KfjU,&G-D`gVMM[d'S)DO@uYPV[@C>QMR`J[MeKW1_WqEN;+:"(*]D*AE"PM/"]5UUdtHeSEa%GR).U'En\NM6f-u_K*VaT,Z`>Wu5"i>DW\Z/JGU^,3AVt.O9*%Rd0\/4m=3HF(UPN+r0c6qrK]+Y>#l"K/S`]=iCY"er#K-$F"U8InZT!cYElFK>)rW5WBoauh]H9`;g;i#rgT[7E0?G0rfM0CW^:JkLRQ8j5d-nJH$q7.*OZC6?PZB_A]e1u$E3Pkl*00C7/J74:L0:S`I\uh:\jf`#5L^I"D*Cd#A#A`:0MJ+M5!D$?Iei:-?bD?CtLg(rU(ommpiA$#lp]Ckok3^]7es:Oc_se?D#%NLr2i>Im`L?D`OeZ4qhR"_3O5HaTAG0T*C5&VI?75StP@Lk%^_ctV?C]k2,S_PS"mO*Xd8,2Y?rB-$;m$.7]C&+CZ/i^BIc^V86IXt34Du4M$9Z1>9>R:Ws==:0nfo.!t(U]mF?"'Q?WYPn.Z$1@u7NNMSaDQR\(PX/#sOi.pIi;8hC^cRNjraoto/Y!uR?&p9H]IX4qB'?N0foJZ',KfjU,&G-D`gVMM[d'S)DO@uYPV[@C>QMR`J[MeKW1_WqEN;+:"(*]D*AE"PM/"]5UUdtHeSEa%GR).U'En\NM6f-u_K*VaT,Z`>Wu5"i>DW\Z/JGU^,3AVt.O9*%Rd0\/4m=3HF(UPN+r0c6qrK]+Y>#l"K/S`]=iCY"er#K-$F"U8InZT!cYElFK>)rW5WBoauh]H9`;g;i#rgT[7E0?G0rfM0CW^:JkLRQ8j5d-nJH$q7.*OZC6?PZB_A]e1u$E3Pkl*00C7/J74:L0:S`I\uh:\jf`#5L^I"D*Cd#A#A`:0MJ+M5!D$?Iei:-?bD?CtLg(rU(ommpiA$#lp]Ckok3^]7es:Oc_se?D#%NLr2i>Im`L?D`OeZ4qhR"_3O5HaTAG0T*C5&VI?75StP@Lk%^_ctV?C]k2,S_PS"mO*Xd8,2Y?rB-$;m$.7]C&+CZ/i^BIc^V86IXt34Du4M$9Z1>9>R:Ws==:0nfo.!t(U]mF?"'Q?WYPn.Z$1@u7NNMSaDQR\(PX/#sOi.pIi;8hC^cRNjraoto/Y!uR?&p9H]IX4qB'?N0foJZ',KfjU,&G-D`gVMM[d'S)DO@uYPV[@C>QMR`J[MeKW1_WqEN;+:"(*]D*AE"PM/"]5UUdtHeSEa%GR).U'En\NM6f-u_K*VaT,Z`>Wu5"i>DW\Z/JGU^,3AVt.O9*%Rd0\/4m=3HF(UPN+r0c6qrK]+Y>#l"K/S`]=iCY"er#K-$F"U8InZT!cYElFK>)rW5WBoauh]H9`;g;i#rgT[7E0?G0rfM0CW^:JkLRQ8j5d-nJH$q7.*OZC6?PZB_A]e1u$E3Pkl*00C7/J74:L0:S`I\uh:\jf`#5L^I"D*Cd#A#A`:0MJ+M5!D$?Iei:-?bD?CtLg(rU(ommpiA$#lp]Ckok3^]7es:Oc_se?D#%NLr2i>Im`L?D`OeZ4qhR"_3O5HaTAG0T*C5&VI?75StP@Lk%^_ctV?C]k2,S_PS"mO*Xd8,2Y?rB-$;m$.7]C&+CZ/i^BIc^V86IXt34Du4M$9Z1>9>R:Ws==:0nfo.!t(U]mF?"'Q?WYPn.Z$1@u7NNMSaDQR\(PX/#sOi.pIi;8hC^cRNjraoto/Y!uR?&p9H]IX4qB'?N0foJZ',KfjU,&G-D`gVMM[d'S)DO@uYPV[@C>QMR`J[MeKW1_WqEN;+:"(*]D*AE"PM/"]5UUdtHeSEa%GR).U'En\NM6f-u_K*VaT,Z`>Wu5"i>DW\Z/JGU^,endstream -endobj -7 0 obj -<< -/Contents 11 0 R /MediaBox [ 0 0 325.9843 226.7717 ] /Parent 10 0 R /Resources << -/Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ] /XObject << -/FormXob.31f20d2c3d12a2e1a4d0cbb0d6c03d1a 6 0 R /FormXob.4dcba5c7e7b32fb305cf8452a9d760c3 5 0 R /FormXob.cb5bfd4238beff6b36fe7701d5477479 4 0 R ->> ->> /Rotate 0 /Trans << - ->> - /Type /Page ->> -endobj -8 0 obj -<< -/PageMode /UseNone /Pages 10 0 R /Type /Catalog ->> -endobj -9 0 obj -<< -/Author (anonymous) /CreationDate (D:20260205234513+02'00') /Creator (anonymous) /Keywords () /ModDate (D:20260205234513+02'00') /Producer (ReportLab PDF Library - \(opensource\)) - /Subject (unspecified) /Title (untitled) /Trapped /False ->> -endobj -10 0 obj -<< -/Count 1 /Kids [ 7 0 R ] /Type /Pages ->> -endobj -11 0 obj -<< -/Filter [ /ASCII85Decode /FlateDecode ] /Length 426 ->> -stream -Gat=f_+Gt-&;KZP'Qqn/A#62g8rgOOH4j*A_]HI4P)_LU2V[jHoChmb,Bbi)R'_]pBH?m5_@=i\BAn8fXcTP1d_jeDN*_kYd5a?14/endstream -endobj -xref -0 12 -0000000000 65535 f -0000000061 00000 n -0000000102 00000 n -0000000209 00000 n -0000000321 00000 n -0000007794 00000 n -0000011976 00000 n -0000025291 00000 n -0000025655 00000 n -0000025724 00000 n -0000025985 00000 n -0000026045 00000 n -trailer -<< -/ID -[<170dcca34c6c28ac1909b295b7132cdd><170dcca34c6c28ac1909b295b7132cdd>] -% ReportLab generated PDF document -- digest (opensource) - -/Info 9 0 R -/Root 8 0 R -/Size 12 ->> -startxref -26562 -%%EOF diff --git a/dist/pdf_backup/final_label_20260205_234602.pdf b/dist/pdf_backup/final_label_20260205_234602.pdf deleted file mode 100644 index e9ad8c3..0000000 --- a/dist/pdf_backup/final_label_20260205_234602.pdf +++ /dev/null @@ -1,103 +0,0 @@ -%PDF-1.3 -% ReportLab Generated PDF document (opensource) -1 0 obj -<< -/F1 2 0 R /F2 3 0 R ->> -endobj -2 0 obj -<< -/BaseFont /Helvetica /Encoding /WinAnsiEncoding /Name /F1 /Subtype /Type1 /Type /Font ->> -endobj -3 0 obj -<< -/BaseFont /Helvetica-Bold /Encoding /WinAnsiEncoding /Name /F2 /Subtype /Type1 /Type /Font ->> -endobj -4 0 obj -<< -/BitsPerComponent 8 /ColorSpace /DeviceRGB /Filter [ /ASCII85Decode /FlateDecode ] /Height 118 /Length 12784 /Subtype /Image - /Type /XObject /Width 1293 ->> -stream -Gb"/__$s[1%)fUSVR%RNi$Xd+5]aA(jS\gp\QgbRbN3cT>V;Adj`7n:/sjcCEk,F-QcnK2\QgbRbN3cT>V;Adj`7n:/sjcCEk,F-QcnK2\QgbRbN3cT>V;Adj`7n:/sjcCEk,F-QcnK2\QgbRbN3cT>V;Adj`7n:/sjcCEk,F-QcnK2\QgbRbN3cT>V;Adj`7n:/sjcCEk,F-QcnK2\QgbRIj=t&1AM)kD(74gTW'Jpa'hn/:Kq`].99n,7,h#.Tn4IG3V9@kg`.mjNhbNT$6\\WpP\^Gi@3$q3a-.:ZNe)<$e0?ET\72?'YY(d'KR(BS4SQXBIF%50g#XRoe6QM)9fLf&4P8\-l),';.*9e;csh([G5A;js+s[*4VE%=%I\W9s(>Z\92EHlj1RF>1isP7m!(:^[,0GRPqa@1$$kQtoVDMR(,r.b\=*^ncLXZ4%e0:%:>_]nrOeM5:c?5HT\JMU^_6YJP:#[#?u)K%DH%Yg_D]f!C+/1c+H2R3BlpnE)B#gYm]q$SPEQ4togs@$GXX--DpT'_oZ:(eiGs'Wbn#f;:kKAVZsY[)5:_8HDOs)*ACuid'7('1oGA9-Fpt=q;>^WQCi@L#_YF0Vn6<;B+7XNB%G?b6_60nc!R-P_ZS.!?DR(=@%bl_.-!unPX@een;H6[R&Gch=Nt6V9nb"<%R[4/LPZ(r!h.7eGT8W\oLPA^b(W0`:;%HU0R_`6u$;m$.L/QD/'*T]d1mMYA3,FK8C$SJ=`C_\88Gm0b<)BA;LOKtuS"jQ5E>6&\!JI$3I^,J%4JeHK8';3e_Y8V463j9E1FZ02%AginL2j"e)YnSDPVtEkPOd[9daKl)`q$Y\qGbEa,M\Nl9$kt`>AXl>KEbHj)IPEqh'D4$_Wu9-hW=VMO@42lX0Mu4U5Z:eiO2Ii>T!mKD;QRf7Lr>q:6NonnEp-T`\2d_^*(Rj2'L:=8mMG1l_c*"lFgTASB+9+W(T?`j5dQ.\.=<3S.!./c30P!:cqk)I@X&;.lW%[_i3l(1*g+I:/_p_'n>;8sD\1.I`8S0pnnp.9Oi&Y"aTuappe%MK!m"Z2KUn2P6Ak@s6V,fNA,Kh2,U4]G7R-AR$bNgleT`,QL(:'$$=mXDF42*@_'=\$XDH.IL)It?;`%l@L8Oi$jDJO0U:N&)n[%Lo8M08@MTU)p1>21rFt'r!*<%&K[=-43ERBI_3`ES(uOe(1!ZMNq9NOndCOW1Z[U%fIjs2b2&Ij!]/C!XLmDrF.p*GY0cuNg:RRX9!8=!js$iBX[CSL$o*GKapQiB2YHD)G5Qf%$/4m4\W\,#'4W26rA+E8jtg8'UTT]<0kA\YUQ0AXZ)@V/$Td4nYc%V6'7TUqGfLmNg:9t;=HUM&9bY^`Hp,)P\+MJ/MlHj"5`qZC-+Q)CuIeihZj>m*K2c!UdR4"PQJT:*eT;qR"Eisk1WdjU?jRuMKY@80I`Zo/;(uO;`mi[D^$W2@OX_):[=^++uMCQX)Qi6/L-:Ni,oALlu_u[orR+$c-/4PB#q:_]_MrbG'K\5_M],B%h'.5(hK4/M/m8X"b&0g"r$Y`"fiNb[Aa^+fjQ9Dm4_CF;F"/`#*6[!Gb2A#6rL,);M`8`ejBU0C3&N>iOCmO7N=q7lP)V:l0]AR=i41,R<>m\OCo#Io,"@mn3F=6(Fa_R(asJ[auGRtjj6g2r*jmZ-L,"H<\p+Y;^%%(_b_i:@A:Q5J>TU\*f!J[4DhcgUf`JM&;`WRLC/pgjNt*IEHALG30&UB.=eYOh(R?cL8QjalY)\0cPl<802UE^JS#9C;YWF0;!;;OE@*!STqN1q`UF^2)%\)I'g3OE(YnB\Q&q='q'bmXhTjNN6k%GWP*!NNE!+De;?`[lL:MFFld5"(\2;l_dTXM`?bnaW]n9n];d(q-j9M1O:6RhM_iA$^uLFH?M@'34X.*<#eWG%'D!g<\Sate2]2T>9pod5i2-'gkCrj3^r-rQ6r^C&$+d5']@$=9V1_G5al'tPT>KVd1-fn-3Z5kAahZqMW\^>9dI\M/;6XmBg#ElUaCkG'oncYA]/R&]M8K\SaLs3Si&X,R9<&'%!gES2h-D4%M(C#G`fl;JUp,mUPpuX;%=&3^b:G_@%n^>?o:p4i,RB`cdUI78;`[7$Bb,4HDmK-9b.+O*&gC2LuTn.SH9'Yh>LeGCNrH-Z]:=hnuMk1rW9JJ*b`"O,),If",.4S).ujA*#_G#?OW"36p45[C'J`r.R[-W(eR4Y9GEj.cr?=Ij00u(Vl_n?'J$F&,4VT(:dL54*;WYpDN:"pa&2=e"V>jgqo*m4n<@Ns*A').=TdOY"_p+]ctqZ0$Ju'm$6>'\cD3ig1mA'V(`nAk]7%Yj^#/'a>e96)0ftrX]^(1Vd3Z)Fu8VqJ$-j>&S49cJl0EnKpbdFD]7G2)t(%!\P?rB6g=U'r)VKe]@hF(8C`);E0T@Q@57;?l,=5gYL>"0K%_J$m(0unN:[%M5471V%AJJXbR7@eE"u[_JsY(N&ZiLf-u6Se(l\.Z\GA71[A_B+jV(rjtBQciIPSK02hR/0Mpt@P]8#rb+YLCpr2_>9[proXCa0Zer+S;n:o#FnIMIm4ULhA`'YI0AKUqO[Z(Bl:IpORl^#G[56.8^QaV8+a=a'bV_VI296\Mb1s-p%j6U)bQf9F>G_bM[Bm'[P7ZRn/F%=:12cds@sc850Tm.NCB;bD>1,Gb"mA45KjE4_o:71UE+-)=jj0DuKgG*?Jn&n03ST!s=5e7N#i:U)Y(DJR8hH_*gF[_.j0qD(7qNFr3h?4%p?U'[TgF_;haKSu8\LOVB=N'I*(Foh[r:RN20(3,XbB&][c<3X$(<])0Hmf'no9AfWHZjB2TAqupgs4O@p'71.oW"puB01h([G5A;js+s[*4VE%=%I\W9s(>Z\92EHlj1RF>1isP7m!(:^[,0GRPqa@1$$kQtoVDMR(,r.b\=*^ncLXZ4%e0:%:>_]nrOeM5:c?5HT\JMU^_6YJP:#[#?u)K%DH%Yg_D]f!C+/1c+H2R3BlpnE)B#gYm]q$SPEQ4togs@$GXX--DpT'_oZ:(eiGs'Wbn#f;:kKAVZsY[)5:_8HDOs)*ACuid'7('1oGA9-Fpt=q;>^WQCi@L#_YF0Vn6<;B+7XNB%G?b6_60nc!R-P_ZS.!?DR(=@%bl_.-!unPX@een;H6[R&Gch=Nt6V9nb"<%R[4/LPZ(r!h.7eGT8W\oLPA^b(W0`:;%HU0R_`6u$;m$.L/QD/'*T]d1mMYA3,FK8C$SJ=`C_\88Gm0b<)BA;LOKtuS"jQ5E>6&\!JI$3I^,J%4JeHK8';3e_Y8V463j9E1FZ02%AginL2j"e)YnSDPVtEkPOd[9daKl)`q$Y\qGbEa,M\Nl9$kt`>AXl>KEbHj)IPEqh'D4$_Wu9-hW=VMO@42lX0Mu4U5Z:eiO2Ii>T!mKD;QRf7Lr>q:6NonnEp-T`\2d_^*(Rj2'L:=8mMG1l_c*"lFgTASB+9+W(T?`j5dQ.\.=<3S.!./c30P!:cqk)I@X&;.lW%[_i3l(1*g+I:/_p_'n>;8sD\1.I`8S0pnnp.9Oi&Y"aTuappe%MK!m"Z2KUn2P6Ak@s6V,fNA,Kh2,U4]G7R-AR$bNgleT`,QL(:'$$=mXDF42*@_'=\$XDH.IL)It?;`%l@L8Oi$jDJO0U:N&)n[%Lo8M08@MTU)p1>21rFt'r!*<%&K[=-43ERBI_3`ES(uOe(1!ZMNq9NOndCOW1Z[U%fIjs2b2&Ij!]/C!XLmDrF.p*GY0cuNg:RRX9!8=!js$iBX[CSL$o*GKapQiB2YHD)G5Qf%$/4m4\W\,#'4W26rA+E8jtg8'UTT]<0kA\YUQ0AXZ)@V/$Td4nYc%V6'7TUqGfLmNg:9t;=HUM&9bY^`Hp,)P\+MJ/MlHj"5`qZC-+Q)CuIeihZj>m*K2c!UdR4"PQJT:*eT;qR"Eisk1WdjU?jRuMKY@80I`Zo/;(uO;`mi[D^$W2@OX_):[=^++uMCQX)Qi6/L-:Ni,oALlu_u[orR+$c-/4PB#q:_]_MrbG'K\5_M],B%h'.5(hK4/M/m8X"b&0g"r$Y`"fiNb[Aa^+fjQ9Dm4_CF;F"/`#*6[!Gb2A#6rL,);M`8`ejBU0C3&N>iOCmO7N=q7lP)V:l0]AR=i41,R<>m\OCo#Io,"@mn3F=6(Fa_R(asJ[auGRtjj6g2r*jmZ-L,"H<\p+Y;^%%(_b_i:@A:Q5J>TU\*f!J[4DhcgUf`JM&;`WRLC/pgjNt*IEHALG30&UB.=eYOh(R?cL8QjalY)\0cPl<802UE^JS#9C;YWF0;!;;OE@*!STqN1q`UF^2)%\)I'g3OE(YnB\Q&q='q'bmXhTjNN6k%GWP*!NNE!+De;?`[lL:MFFld5"(\2;l_dTXM`?bnaW]n9n];d(q-j9M1O:6RhM_iA$^uLFH?M@'34X.*<#eWG%'D!g<\Sate2]2T>9pod5i2-'gkCrj3^r-rQ6r^C&$+d5']@$=9V1_G5al'tPT>KVd1-fn-3Z5kAahZqMW\^>9dI\M/;6XmBg#ElUaCkG'oncYA]/R&]M8K\SaLs3Si&X,R9<&'%!gES2h-D4%M(C#G`fl;JUp,mUPpuX;%=&3^b:G_@%n^>?o:p4i,RB`cdUI78;`[7$Bb,4HDmK-9b.+O*&gC2LuTn.SH9'Yh>LeGCNrH-Z]:=hnuMk1rW9JJ*b`"O,),If",.4S).ujA*#_G#?OW"36p45[C'J`r.R[-W(eR4Y9GEj.cr?=Ij00u(Vl_n?'J$F&,4VT(:dL54*;WYpDN:"pa&2=e"V>jgqo*m4n<@Ns*A').=TdOY"_p+]ctqZ0$Ju'm$6>'\cD3ig1mA'V(`nAk]7%Yj^#/'a>e96)0ftrX]^(1Vd3Z)Fu8VqJ$-j>&S49cJl0EnKpbdFD]7G2)t(%!\P?rB6g=U'r)VKe]@hF(8C`);E0T@Q@57;?l,=5gYL>"0K%_J$m(0unN:[%M5471V%AJJXbR7@eE"u[_JsY(N&ZiLf-u6Se(l\.Z\GA71[A_B+jV(rjtBQciIPSK02hR/0Mpt@P]8#rb+YLCpr2_>9[proXCa0Zer+S;n:o#FnIMIm4ULhA`'YI0AKUqO[Z(Bl:IpORl^#G[56.8^QaV8+a=a'bV_VI296\Mb1s-p%j6U)bQf9F>G_bM[Bm'[P7ZRn/F%=:12cds@sc850Tm.NCB;bD>1,Gb"mA45KjE4_o:71UE+-)=jj0DuKgG*?Jn&n03ST!s=5e7N#i:U)Y(DJR8hH_*gF[_.j0qD(7qNFr3h?4%p?U'[TgF_;haKSu8\LOVB=N'I*(Foh[r:RN20(3,XbB&][c<3X$(<])0Hmf'no9AfWHZjB2TAqupgs4O@p'71.oW"puB01h([G5A;js+s[*4VE%=%I\W9s(>Z\92EHlj1RF>1isP7m!(:^[,0GRPqa@1$$kQtoVDMR(,r.b\=*^ncLXZ4%e0:%:>_]nrOeM5:c?5HT\JMU^_6YJP:#[#?u)K%DH%Yg_D]f!C+/1c+H2R3BlpnE)B#gYm]q$SPEQ4togs@$GXX--DpT'_oZ:(eiGs'Wbn#f;:kKAVZsY[)5:_8HDOs)*ACuid'7('1oGA9-Fpt=q;>^WQCi@L#_YF0Vn6<;B+7XNB%G?b6_60nc!R-P_ZS.!?DR(=@%bl_.-!unPX@een;H6[R&Gch=Nt6V9nb"<%R[4/LPZ(r!h.7eGT8W\oLPA^b(W0`:;%HU0R_`6u$;m$.L/QD/'*T]d1mMYA3,FK8C$SJ=`C_\88Gm0b<)BA;LOKtuS"jQ5E>6&\!JI$3I^,J%4JeHK8';3e_Y8V463j9E1FZ02%AginL2j"e)YnSDPVtEkPOd[9daKl)`q$Y\qGbEa,M\Nl9$kt`>AXl>KEbHj)IPEqh'D4$_Wu9-hW=VMO@42lX0Mu4U5Z:eiO2Ii>T!mKD;QRf7Lr>q:6NonnEp-T`\2d_^*(Rj2'L:=8mMG1l_c*"lFgTASB+9+W(T?`j5dQ.\.=<3S.!./c30P!:cqk)I@X&;.lW%[_i3l(1*g+I:/_p_'n>;8sD\1.I`8S0pnnp.9Oi&Y"aTuappe%MK!m"Z2KUn2P6Ak@s6V,fNA,Kh2,U4]G7R-AR$bNgleT`,QL(:'$$=mXDF42*@_'=\$XDH.IL)It?;`%l@L8Oi$jDJO0U:N&)n[%Lo8M08@MTU)p1>21rFt'r!*<%&K[=-43ERBI_3`ES(uOe(1!ZMNq9NOndCOW1Z[U%fIjs2b2&Ij!]/C!XLmDrF.p*GY0cuNg:RRX9!8=!js$iBX[CSL$o*GKapQiB2YHD)G5Qf%$/4m4\W\,#'4W26rA+E8jtg8'UTT]<0kA\YUQ0AXZ)@V/$Td4nYc%V6'7TUqGfLmNg:9t;=HUM&9bY^`Hp,)P\+MJ/MlHj"5`qZC-+Q)CuIeihZj>m*K2c!UdR4"PQJT:*eT;qR"Eisk1WdjU?jRuMKY@80I`Zo/;(uO;`mi[D^$W2@OX_):[=^++uMCQX)Qi6/L-:Ni,oALlu_u[orR+$c-/4PB#q:_]_MrbG'K\5_M],B%h'.5(hK4/M/m8X"b&0g"r$Y`"fiNb[Aa^+fjQ9Dm4_CF;F"/`#*6[!Gb2A#6rL,);M`8`ejBU0C3&N>iOCmO7N=q7lP)V:l0]AR=i41,R<>m\OCo#Io,"@mn3F=6(Fa_R(asJ[auGRtjj6g2r*jmZ-L,"H<\p+Y;^%%(_b_i:@A:Q5J>TU\*f!J[4DhcgUf`JM&;`WRLC/pgjNt*IEHALG30&UB.=eYOh(R?cL8QjalY)\0cPl<802UE^JS#9C;YWF0;!;;OE@*!STqN1q`UF^2)%\)I'g3OE(YnB\Q&q='q'bmXhTjNN6k%GWP*!NNE!+De;?`[lL:MFFld5"(\2;l_dTXM`?bnaW]n9n];d(q-j9M1O:6RhM_iA$^uLFH?M@'34X.*<#eWG%'D!g<\Sate2]2T>9pod5i2-'gkCrj3^r-rQ6r^C&$+d5']@$=9V1_G5al'tPT>KVd1-fn-3Z5kAahZqMW\^>9dI\M/;6XmBg#ElUaCkG'oncYA]/R&]M8K\SaLs3Si&X,R9<&'%!gES2h-D4%M(C#G`fl;JUp,mUPpuX;%=&3^b:G_@%n^>?o:p4i,RB`cdUI78;`[7$Bb,4HDmK-9b.+O*&gC2LuTn.SH9'Yh>LeGCNrH-Z]:=hnuMk1rW9JJ*b`"O,),If",.4S).ujA*#_G#?OW"36p45[C'J`r.R[-W(eR4Y9GEj.cr?=Ij00u(Vl_n?'J$F&,4VT(:dL54*;WYpDN:"pa&2=e"V>jgqo*m4n<@Ns*A').=TdOY"_p+]ctqZ0$Ju'm$6>'\cD3ig1mA'V(`nAk]7%Yj^#/'a>e96)0ftrX]^(1Vd3Z)Fu8VqJ$-j>&S49cJl0EnKpbdFD]7G2)t(%!\P?rB6g=U'r)VKe]@hF(8C`);E0T@Q@57;?l,=5gYL>"0K%_J$m(0unN:[%M5471V%AJJXbR7@eE"u[_JsY(N&ZiLf-u6Se(l\.Z\GA71[A_B+jV(rjtBQciIPSK02hR/0Mpt@P]8#rb+YLCpr2_>9[proXCa0Zer+S;n:o#FnIMIm4ULhA`'YI0AKUqO[Z(Bl:IpORl^#G[56.8^QaV8+a=a'bV_VI296\Mb1s-p%j6U)bQf9F>G_bM[Bm'[P7ZRn/F%=:12cds@sc850Tm.NCB;bD>1,Gb"mA45KjE4_o:71UE+-)=jj0DuKgG*?Jn&n03ST!s=5e7N#i:U)Y(DJR8hH_*gF[_.j0qD(7qNFr3h?4%p?U'[TgF_;haKSu8\LOVB=N'I*(Foh[r:RN20(3,XbB&][c<3X$(<])0Hmf'no9AfWHZjB2TAqupgs4O@p'71.oW"puB01V;Adj`7n:/sjcCEk,F-QcnK2\QgbRbN3cT>V;Adj`7n:/sjcCEk,F-QcnK2\QgbRbN3cT>V;Adj`7n:/sjcCEk,F-QcnK2\QgbRbN3cT>V;Adj`7n:/sjcCEk,F-QcnK2\QgbRbN3cT>V;Adj`7n:/sjcCEk,F-QciaXs3h9Ue,~>endstream -endobj -5 0 obj -<< -/BitsPerComponent 8 /ColorSpace /DeviceRGB /Filter [ /ASCII85Decode /FlateDecode ] /Height 118 /Length 3410 /Subtype /Image - /Type /XObject /Width 383 ->> -stream -Gb"0J3Gnpa&-G5us3l#V88&gEaY;o*r-V8;e*1s8SPH*3l#\tW:8cS*F?5sfVpjmP3h9$De*1s8SPH*3l#\tW:B/kj(]).J\k&oCOa0$A0UP[L(WfP#..C'hMB3t#[/6P>O]^]ho6(CJ0VQcEP,"UGi1[^s4[^-$pI"6jZ-#Mtm1@-B6ChC-7m3W_6Zjo*LbR9FLXnn'Q&El@+b[[b3kIqCH:EI@l;mNg@AM]iXc(+I(R_a"#_NG+G**d;MujO?XlpqF8@osI(Pu-E12hpZ"r$:g,!"p+"Wj[Jd6iSLG!E>d'!#8Jh@:\;-Ig^;EmulP4B/eaLBo-lIV<"4$7&OtLQd(2cLEfkW/KJ8ciB,AZecRA9Zh236tN3rJUFcfef,4fs`@5+D#/sL>fkO`isr/eY3iADRe>$msKW7<6m6$9V:sU5'"!m=&_S,Z_Is]H'#[oE\c7Y9TSl+F>\eR@r(hr_3lQWUV7HWtK_I,^$>pMp'UVK6>.sd"*ddDnA7:MO?bhF:o_1Xk]8\)\$+Uf^IfgTr21C?6D\"\W`,OKqn>pNI]aLiN[(egm7Mr^gL'R6Qo71Tu"gATC08??ioGrp[5Qr%E3a\gA4n5.qu*[6QMqk8.p=QLauFpMM1U!>9RURk?@Tt1t%6l9Y46gGr$b!kI[&AhgASR!L24eoe[FXqco0[fBEejX&5Mp0p!KY`=&]1@s.7Y-?[NhK*c[DOW=%Q!YO]^]ho6(CJ0VQcEP,"UGi1[^s4[^-$pI"6jZ-#Mtm1@-B6ChC-7m3W_6Zjo*LbR9FLXnn'Q&El@+b[[b3kIqCH:EI@l;mNg@AM]iXc(+I(R_a"#_NG+G**d;MujO?XlpqF8@osI(Pu-E12hpZ"r$:g,!"p+"Wj[Jd6iSLG!E>d'!#8Jh@:\;-Ig^;EmulP4B/eaLBo-lIV<"4$7&OtLQd(2cLEfkW/KJ8ciB,AZecRA9Zh236tN3rJUFcfef,4fs`@5+D#/sL>fkO`isr/eY3iADRe>$msKW7<6m6$9V:sU5'"!m=&_S,Z_Is]H'#[oE\c7Y9TSl+F>\eR@r(hr_3lQWUV7HWtK_I,^$>pMp'UVK6>.sd"*ddDnA7:MO?bhF:o_1Xk]8\)\$+Uf^IfgTr21C?6D\"\W`,OKqn>pNI]aLiN[(egm7Mr^gL'R6Qo71Tu"gATC08??ioGrp[5Qr%E3a\gA4n5.qu*[6QMqk8.p=QLauFpMM1U!>9RURk?@Tt1t%6l9Y46gGr$b!kI[&AhgASR!L24eoe[FXqco0[fBEejX&5Mp0p!KY`=&]1@s.7Y-?[NhK*c[DOW=%Q!YO]^]ho6(CJ0VQcEP,"UGi1[^s4[^-$pI"6jZ-#Mtm1@-B6ChC-7m3W_6Zjo*LbR9FLXnn'Q&El@+b[[b3kIqCH:EI@l;mNg@AM]iXc(+I(R_a"#_NG+G**d;MujO?XlpqF8@osI(Pu-E12hpZ"r$:g,!"p+"Wj[Jd6iSLG!E>d'!#8Jh@:\;-Ig^;EmulP4B/eaLBo-lIV<"4$7&OtLQd(2cLEfkW/KJ8ciB,AZecRA9Zh236tN3rJUFcfef,4fs`@5+D#/sL>fkO`isr/eY3iADRe>$msKW7<6m6$9V:sU5'"!m=&_S,Z_Is]H'#[oE\c7Y9TSl+F>\eR@r(hr_3lQWUV7HWtK_I,^$>pMp'UVK6>.sd"*ddDnA7:MO?bhF:o_1Xk]8\)\$+Uf^IfgTr21C?6D\"\W`,OKqn>pNI]aLiN[(egm7Mr^gL'R6Qo71Tu"gATC08??ioGrp[5Qr%E3a\gA4n5.qu*[6QMqk8.p=QLauFpMM1U!>9RURk?@Tt1t%6l9Y46gGr$b!kI[&AhgASR!L24eoe[FXqco0[fBEejX&5Mp0p!KY`=&]1@s.7Y-?[NhK*c[DOW=%Q!Yendstream -endobj -6 0 obj -<< -/BitsPerComponent 8 /ColorSpace /DeviceRGB /Filter [ /ASCII85Decode /FlateDecode ] /Height 118 /Length 12761 /Subtype /Image - /Type /XObject /Width 1423 ->> -stream -Gb"/`_6N)U%)]ORVZ.En*;D4\jiiO)K7s0s\(PRUS'>QOfk`R9c"=<8Cc7d-B!^0,2Ohs'Ze9.QS'>QOfk`R9c"=<8Cc7d-B!^0,2Ohs'Ze9.QS'>QOfk`R9c"=<8Cc7d-B!^0,2Ohs'Ze9.QS'>QOfk`R9c"=<8Cc7d-B!^0,2Ohs'Ze9.QS'>QOfk`R9c"=<8Cc7d-B!^0,2Ohs'Ze9.QS'>QOfk`R9c"=<8Cc7cBPCGl]='!oj/='0B#UU'3r;Heq6E.Q:RBdSC'We-FFb)9"*-MQfbrEbDXa.r$Ai7?"?k$/VK]JWC,j.dW!*5=^Y_g5ik2l3+Y8F\q"hN@!d[6hG!<0P6Eam_Gh?k?,,Ln!Ltnk-l&+_9/.,I.N`d>Y,OCMGad>;&IfqI,=H0_tKlk(RnJEPB>&!PemV\WMJhg(/$*/9@ZTd^Y\9,:rHfl1a&/JW:9ZpQjT\T*bWW!<)BfbVUYji%!'u@=>f+YX1%.2;jc,5Q@^tr)&&0O*g<*E.0K"Z^TcLYQcUf6LrB2P&hpt*WdC6bCJdC6>+/J.(c06AG@8s[F0+)aG>)FGo32RQ?tE#&^3NCmY+u>274AD0-k'is54A<)@=(nFMp3c38\/LK8n!@?<75mnMkuZSVMOJN![TbO%IW^'EP9`V-jsj6-[U94^Tp[:C;3KH)35ef;q:fCbV&F]$=]gPVTaJS`KA-]tOP:/=&U)K#rWP^]/h`:o`r'VQ<2i"`%gU?!tl!LY[M]1X<7?CYge"=j:k6=G)kn+o17TagmQYJ/+mpCn`V^H25,9.u*F_JM&ja1a_IU<@EP1Al;4P)(_(O#+)?R>^jB<=.kAg;J83EC"A4/O^4q(2bcYVIONh`N5G=&K1*U6L7('F$EJTD*`PYWXG^`TEH*,[I_`V6Id0.d9!H`DXk:;K\/GYP7l#'X:aI%1"9k.fB8JVF%8na-j4K'bmaGBm"t]K,f%>-O%*6][E1CCK@,C2OI&^?"^BD8f:m6:3-1'?=/7-(/(>%_;mn9hg`F@-rp"$;q@[pK!dG;/hgn!_sY=?)#\>&QDW19`XHn?*EY2Z*36O1*E/?Ur0Dpl=;_d8D]Y+4.k(O%;+eYO$A4e6c[3B8fU`f@@e33%P-.rA;V5A(Q#rS5@OYl-WB//_f6_oLMHDE`"pC+p'n6/`;k[1Hj%NU6$4>A4[(=&?5n:L/X(Il3e^hBC$F?2Y;Qp?U@m]b2A!1mZ70"i1.G.$s;"O7'cW:P0P6,$+?>3*]260O\)pG+@Xts02V$ntV-b9/$YHL2'Ml"dN@.Ku-mlt20PcB)#.;MdH_-3:.(DnsL@BhLFcS=i/Li/N9@N/-@g4s[%]l+=N`B$YO[+G\d(ga2i)4]\bHL[:$5BaI$4R7f%k@MV"/\Da]#U5E()7ObV.k('0nUHh#?K)/a/Z7e`tW,C^SPOMgM%WYsu%[5IE?_Q;n/'Wf-nR#l^eR,hLD&\s9%$8t`ue@^1co+f1:Ud,`c(:D8M7d7lRPfM@OX,VQoq>:q[]&$VWb-<@>?THEXM;&WlAFmW#,*70Nj1Bj+eMbTM\sJQ4MOZ"e(20nicTD^ee@PqaHXjtXugOs5DkV%da?0W99m]]Uf"m7Dj]2Qnqal'bU#KahWl8_4h2Q;RpRWfp\:^"6>YLrE8*5VRI[iV+EJ'h[">cBP`8TO9?GWsak(jKL_MC;r87D9Y/>0WY"$"`(=t-7%J2-95.*"L+VbJkZp`2(tTrI)Wtq%9CK%jI=18k=UU3cLP>q=S'$JKbk&T`N!j6&"3G^f2^^pGc+&U4S!)1p&AaArspu^oA:8=LC$TR)5re[hPp[b*\9KdeO_C.hWl[g`*t/P+IG9inG<``$Dm#/B?FCW:p?7_eHNr$EnDC72<,[W[cST/R+;,#Ji-XJ'9[8TPFO-P!a&;l_'TMAR[;?I^1,`d'^0#t8n4$e=bTc+?m_.\S\\baAT4V0alV-$I0GL1/;492P6VhOrrH&l<8HS.=c3Uof$^q:^mICt]*#*GS7C+#]OM;TRbq#I"tO1Mo$([-F!X6T.nV8C6t&p`np/P_%,6sI?#3h]9[Yf!:^S/cUlql:==g9W/la:0r-GQM5S8pNd"#NpTYg.^?n.D@H^lO#;*i$%RT:4A1WX!K@+C3WXP0+e9OUun>7/qhAP>Y/Gt`7]U^1?s.0Z1h$u0*4n+hiLHW$Mpbq"cF\n2[L@=stIdWGbPV3Jfml6M^'n+@DD@^-Uc&54-Eq#(FkKi3&S1M&-f-s0-kl2kH"3U@6WRW4?f>P!k(b\DT"_&BD6$->,e8^B#UU'3r;Heq6E.Q:RBdSC'We-FFb)9"*-MQfbrEbDXa.r$Ai7?"?k$/VK]JWC,j.dW!*5=^Y_g5ik2l3+Y8F\q"hN@!d[6hG!<0P6Eam_Gh?k?,,Ln!Ltnk-l&+_9/.,I.N`d>Y,OCMGad>;&IfqI,=H0_tKlk(RnJEPB>&!PemV\WMJhg(/$*/9@ZTd^Y\9,:rHfl1a&/JW:9ZpQjT\T*bWW!<)BfbVUYji%!'u@=>f+YX1%.2;jc,5Q@^tr)&&0O*g<*E.0K"Z^TcLYQcUf6LrB2P&hpt*WdC6bCJdC6>+/J.(c06AG@8s[F0+)aG>)FGo32RQ?tE#&^3NCmY+u>274AD0-k'is54A<)@=(nFMp3c38\/LK8n!@?<75mnMkuZSVMOJN![TbO%IW^'EP9`V-jsj6-[U94^Tp[:C;3KH)35ef;q:fCbV&F]$=]gPVTaJS`KA-]tOP:/=&U)K#rWP^]/h`:o`r'VQ<2i"`%gU?!tl!LY[M]1X<7?CYge"=j:k6=G)kn+o17TagmQYJ/+mpCn`V^H25,9.u*F_JM&ja1a_IU<@EP1Al;4P)(_(O#+)?R>^jB<=.kAg;J83EC"A4/O^4q(2bcYVIONh`N5G=&K1*U6L7('F$EJTD*`PYWXG^`TEH*,[I_`V6Id0.d9!H`DXk:;K\/GYP7l#'X:aI%1"9k.fB8JVF%8na-j4K'bmaGBm"t]K,f%>-O%*6][E1CCK@,C2OI&^?"^BD8f:m6:3-1'?=/7-(/(>%_;mn9hg`F@-rp"$;q@[pK!dG;/hgn!_sY=?)#\>&QDW19`XHn?*EY2Z*36O1*E/?Ur0Dpl=;_d8D]Y+4.k(O%;+eYO$A4e6c[3B8fU`f@@e33%P-.rA;V5A(Q#rS5@OYl-WB//_f6_oLMHDE`"pC+p'n6/`;k[1Hj%NU6$4>A4[(=&?5n:L/X(Il3e^hBC$F?2Y;Qp?U@m]b2A!1mZ70"i1.G.$s;"O7'cW:P0P6,$+?>3*]260O\)pG+@Xts02V$ntV-b9/$YHL2'Ml"dN@.Ku-mlt20PcB)#.;MdH_-3:.(DnsL@BhLFcS=i/Li/N9@N/-@g4s[%]l+=N`B$YO[+G\d(ga2i)4]\bHL[:$5BaI$4R7f%k@MV"/\Da]#U5E()7ObV.k('0nUHh#?K)/a/Z7e`tW,C^SPOMgM%WYsu%[5IE?_Q;n/'Wf-nR#l^eR,hLD&\s9%$8t`ue@^1co+f1:Ud,`c(:D8M7d7lRPfM@OX,VQoq>:q[]&$VWb-<@>?THEXM;&WlAFmW#,*70Nj1Bj+eMbTM\sJQ4MOZ"e(20nicTD^ee@PqaHXjtXugOs5DkV%da?0W99m]]Uf"m7Dj]2Qnqal'bU#KahWl8_4h2Q;RpRWfp\:^"6>YLrE8*5VRI[iV+EJ'h[">cBP`8TO9?GWsak(jKL_MC;r87D9Y/>0WY"$"`(=t-7%J2-95.*"L+VbJkZp`2(tTrI)Wtq%9CK%jI=18k=UU3cLP>q=S'$JKbk&T`N!j6&"3G^f2^^pGc+&U4S!)1p&AaArspu^oA:8=LC$TR)5re[hPp[b*\9KdeO_C.hWl[g`*t/P+IG9inG<``$Dm#/B?FCW:p?7_eHNr$EnDC72<,[W[cST/R+;,#Ji-XJ'9[8TPFO-P!a&;l_'TMAR[;?I^1,`d'^0#t8n4$e=bTc+?m_.\S\\baAT4V0alV-$I0GL1/;492P6VhOrrH&l<8HS.=c3Uof$^q:^mICt]*#*GS7C+#]OM;TRbq#I"tO1Mo$([-F!X6T.nV8C6t&p`np/P_%,6sI?#3h]9[Yf!:^S/cUlql:==g9W/la:0r-GQM5S8pNd"#NpTYg.^?n.D@H^lO#;*i$%RT:4A1WX!K@+C3WXP0+e9OUun>7/qhAP>Y/Gt`7]U^1?s.0Z1h$u0*4n+hiLHW$Mpbq"cF\n2[L@=stIdWGbPV3Jfml6M^'n+@DD@^-Uc&54-Eq#(FkKi3&S1M&-f-s0-kl2kH"3U@6WRW4?f>P!k(b\DT"_&BD6$->,e8^B#UU'3r;Heq6E.Q:RBdSC'We-FFb)9"*-MQfbrEbDXa.r$Ai7?"?k$/VK]JWC,j.dW!*5=^Y_g5ik2l3+Y8F\q"hN@!d[6hG!<0P6Eam_Gh?k?,,Ln!Ltnk-l&+_9/.,I.N`d>Y,OCMGad>;&IfqI,=H0_tKlk(RnJEPB>&!PemV\WMJhg(/$*/9@ZTd^Y\9,:rHfl1a&/JW:9ZpQjT\T*bWW!<)BfbVUYji%!'u@=>f+YX1%.2;jc,5Q@^tr)&&0O*g<*E.0K"Z^TcLYQcUf6LrB2P&hpt*WdC6bCJdC6>+/J.(c06AG@8s[F0+)aG>)FGo32RQ?tE#&^3NCmY+u>274AD0-k'is54A<)@=(nFMp3c38\/LK8n!@?<75mnMkuZSVMOJN![TbO%IW^'EP9`V-jsj6-[U94^Tp[:C;3KH)35ef;q:fCbV&F]$=]gPVTaJS`KA-]tOP:/=&U)K#rWP^]/h`:o`r'VQ<2i"`%gU?!tl!LY[M]1X<7?CYge"=j:k6=G)kn+o17TagmQYJ/+mpCn`V^H25,9.u*F_JM&ja1a_IU<@EP1Al;4P)(_(O#+)?R>^jB<=.kAg;J83EC"A4/O^4q(2bcYVIONh`N5G=&K1*U6L7('F$EJTD*`PYWXG^`TEH*,[I_`V6Id0.d9!H`DXk:;K\/GYP7l#'X:aI%1"9k.fB8JVF%8na-j4K'bmaGBm"t]K,f%>-O%*6][E1CCK@,C2OI&^?"^BD8f:m6:3-1'?=/7-(/(>%_;mn9hg`F@-rp"$;q@[pK!dG;/hgn!_sY=?)#\>&QDW19`XHn?*EY2Z*36O1*E/?Ur0Dpl=;_d8D]Y+4.k(O%;+eYO$A4e6c[3B8fU`f@@e33%P-.rA;V5A(Q#rS5@OYl-WB//_f6_oLMHDE`"pC+p'n6/`;k[1Hj%NU6$4>A4[(=&?5n:L/X(Il3e^hBC$F?2Y;Qp?U@m]b2A!1mZ70"i1.G.$s;"O7'cW:P0P6,$+?>3*]260O\)pG+@Xts02V$ntV-b9/$YHL2'Ml"dN@.Ku-mlt20PcB)#.;MdH_-3:.(DnsL@BhLFcS=i/Li/N9@N/-@g4s[%]l+=N`B$YO[+G\d(ga2i)4]\bHL[:$5BaI$4R7f%k@MV"/\Da]#U5E()7ObV.k('0nUHh#?K)/a/Z7e`tW,C^SPOMgM%WYsu%[5IE?_Q;n/'Wf-nR#l^eR,hLD&\s9%$8t`ue@^1co+f1:Ud,`c(:D8M7d7lRPfM@OX,VQoq>:q[]&$VWb-<@>?THEXM;&WlAFmW#,*70Nj1Bj+eMbTM\sJQ4MOZ"e(20nicTD^ee@PqaHXjtXugOs5DkV%da?0W99m]]Uf"m7Dj]2Qnqal'bU#KahWl8_4h2Q;RpRWfp\:^"6>YLrE8*5VRI[iV+EJ'h[">cBP`8TO9?GWsak(jKL_MC;r87D9Y/>0WY"$"`(=t-7%J2-95.*"L+VbJkZp`2(tTrI)Wtq%9CK%jI=18k=UU3cLP>q=S'$JKbk&T`N!j6&"3G^f2^^pGc+&U4S!)1p&AaArspu^oA:8=LC$TR)5re[hPp[b*\9KdeO_C.hWl[g`*t/P+IG9inG<``$Dm#/B?FCW:p?7_eHNr$EnDC72<,[W[cST/R+;,#Ji-XJ'9[8TPFO-P!a&;l_'TMAR[;?I^1,`d'^0#t8n4$e=bTc+?m_.\S\\baAT4V0alV-$I0GL1/;492P6VhOrrH&l<8HS.=c3Uof$^q:^mICt]*#*GS7C+#]OM;TRbq#I"tO1Mo$([-F!X6T.nV8C6t&p`np/P_%,6sI?#3h]9[Yf!:^S/cUlql:==g9W/la:0r-GQM5S8pNd"#NpTYg.^?n.D@H^lO#;*i$%RT:4A1WX!K@+C3WXP0+e9OUun>7/qhAP>Y/Gt`7]U^1?s.0Z1h$u0*4n+hiLHW$Mpbq"cF\n2[L@=stIdWGbPV3Jfml6M^'n+@DD@^-Uc&54-Eq#(FkKi3&S1M&-f-s0-kl2kH"3U@6WRW4?f>P!k(b\DT"_&BD6$->,e8^QOfk`R9c"=<8Cc7d-B!^0,2Ohs'Ze9.QS'>QOfk`R9c"=<8Cc7d-B!^0,2Ohs'Ze9.QS'>QOfk`R9c"=<8Cc7d-B!^0,2Ohs'Ze9.QS'>QOfk`R9c"=<8Cc7d-B!^0,2Ohs'Ze9.QS'>QOfk`R9c"=<8Cc7d-B!^0,2OhtR2?*^/nOWQ~>endstream -endobj -7 0 obj -<< -/Contents 11 0 R /MediaBox [ 0 0 325.9843 226.7717 ] /Parent 10 0 R /Resources << -/Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ] /XObject << -/FormXob.5fb0f5b9d8a1c1e6be9b323c0d1e5205 4 0 R /FormXob.7bb6fcb6cbc7564e1c052f74aaf834aa 5 0 R /FormXob.eeba72e80779200243540ec13ed3b32a 6 0 R ->> ->> /Rotate 0 /Trans << - ->> - /Type /Page ->> -endobj -8 0 obj -<< -/PageMode /UseNone /Pages 10 0 R /Type /Catalog ->> -endobj -9 0 obj -<< -/Author (anonymous) /CreationDate (D:20260205234602+02'00') /Creator (anonymous) /Keywords () /ModDate (D:20260205234602+02'00') /Producer (ReportLab PDF Library - \(opensource\)) - /Subject (unspecified) /Title (untitled) /Trapped /False ->> -endobj -10 0 obj -<< -/Count 1 /Kids [ 7 0 R ] /Type /Pages ->> -endobj -11 0 obj -<< -/Filter [ /ASCII85Decode /FlateDecode ] /Length 437 ->> -stream -Gat=e:JVoa&B4,8.HUo$C?CRiCoaI#b6_1N\d&^MerD[4&6>V>lGp*7%1Tk@;H]I+Gi%Z_jq2!J1tT#63:GhmP(4DG&]d$Er=s_J]=H6!GO=JXd&$\mkS,=7!64)O8XnMNanLj'hg]o6KmjL0]:IqO-R__Dr6]M'((XTSjLhn8ZK]XeVoR'TPb!gP8'P`[#:`\)f9Cuci.@sa.X[\rDr'9[m0j3>Y8ANr7r5NHS!+B33o@,B:Nt![okH%mDGFQKrHE">jJ$:X[pBIRgY;,"X[h=1RkIHaQ?m\J?KA=6TaM^^Nn?_E2O8/*Q_endstream -endobj -xref -0 12 -0000000000 65535 f -0000000061 00000 n -0000000102 00000 n -0000000209 00000 n -0000000321 00000 n -0000013298 00000 n -0000016899 00000 n -0000029853 00000 n -0000030217 00000 n -0000030286 00000 n -0000030547 00000 n -0000030607 00000 n -trailer -<< -/ID -[<0001e7101d165277b2b7bca234b76ade><0001e7101d165277b2b7bca234b76ade>] -% ReportLab generated PDF document -- digest (opensource) - -/Info 9 0 R -/Root 8 0 R -/Size 12 ->> -startxref -31135 -%%EOF diff --git a/documentation/BARCODE_HEIGHT_CORRECTION.md b/documentation/BARCODE_HEIGHT_CORRECTION.md deleted file mode 100644 index 6f941f7..0000000 --- a/documentation/BARCODE_HEIGHT_CORRECTION.md +++ /dev/null @@ -1,246 +0,0 @@ -# Barcode Height Correction - Final Configuration - -**Date:** February 5, 2026 -**Status:** ✓ **COMPLETED AND TESTED** - -## Changes Made - -### 1. **Fixed Barcode Height** ✓ -- **Previous:** Variable height (2-6mm, too small) -- **Current:** Fixed 18mm (1.8cm) - optimal for scanning -- **Result:** Barcodes now easily readable and scannable - -### 2. **Corrected Label Dimensions** ✓ -- **Label Size:** 11.5 cm × 8 cm (confirmed correct) -- **3 Rows:** ~2.67 cm per row -- **Barcode Height:** 18mm per row (fits within row space) -- **Margins:** 3mm on all sides - -### 3. **Character Limit Enforcement** ✓ -- **Limit:** 25 characters maximum per field -- **Barcode Type:** Code128 (supports max 25 chars) -- **Overflow Handling:** Automatically truncates longer values -- **Display:** Shows truncated value in barcode field - -## Technical Details - -### PDF Generation Parameters - -```python -Label Configuration: -├── Width: 11.5 cm -├── Height: 8 cm -├── Barcode Height: 18 mm (1.8 cm) -├── DPI: 300 (print-ready) -├── Margin: 3 mm -└── Character Limit: 25 characters - -Row Layout (3 rows): -├── Row 1 (SAP-Nr): 18mm barcode -├── Row 2 (Cantitate): 18mm barcode -└── Row 3 (Lot Nr): 18mm barcode -``` - -### Barcode Generation - -```python -generate_barcode_image(value, height_mm=18): - ├── Input: Text value (max 25 chars) - ├── Format: Code128 - ├── Height: 18mm (fixed) - ├── Module Width: 0.5mm - ├── DPI: 300 (matches PDF) - └── Quality: High-definition for scanning -``` - -## Testing Results - -### Test Case 1: Short Values ✓ -``` -Input: "SHORT|100|LOT" -Result: PDF generated successfully -Barcode Height: 18mm ✓ -File Size: 1.7 KB -``` - -### Test Case 2: Medium Values ✓ -``` -Input: "SAP-MEDIUM-CODE|Qty:250|LOT-XYZ" -Result: PDF generated successfully -Barcode Height: 18mm ✓ -File Size: 1.7 KB -``` - -### Test Case 3: Long Values (Truncated) ✓ -``` -Input: "VERY-LONG-SAP-NUMBER-123456789|Qty:999|LOT-EXTENDED-CODE-ABC" -Processed: "VERY-LONG-SAP-NUMBER-1|Qty:999|LOT-EXTENDED-CODE-A" (truncated) -Result: PDF generated successfully -Barcode Height: 18mm ✓ -File Size: 1.7 KB -``` - -## Quality Improvements - -### Before Correction -| Aspect | Value | Status | -|--------|-------|--------| -| Barcode Height | ~2-6mm | Too small, hard to scan | -| Label Size | Inconsistent | 8.5×6cm (wrong) | -| Character Limit | Not enforced | Caused barcode errors | -| Scanability | Poor | Inconsistent bar width | - -### After Correction -| Aspect | Value | Status | -|--------|-------|--------| -| Barcode Height | 18mm (1.8cm) | ✓ Perfect for scanning | -| Label Size | 11.5×8cm | ✓ Confirmed correct | -| Character Limit | 25 chars max | ✓ Automatically enforced | -| Scanability | Excellent | ✓ Professional quality | - -## File Structure & Components - -### Updated Files - -1. **print_label_pdf.py** - - Fixed `generate_barcode_image()` method - - Implemented fixed 18mm barcode height - - Added character truncation to 25 chars - - Proper module height calculation - -2. **print_label.py** - - Updated to use corrected PDF generator - - Maintains backward compatibility - - PNG fallback still available - -3. **label_printer_gui.py** - - No changes needed (uses updated print_label.py) - - GUI automatically benefits from fixes - -## Configuration Summary - -```python -# Default Configuration (Optimized) -PDFLabelGenerator( - label_width=11.5, # cm - label_height=8, # cm - dpi=300 # print-ready -) - -# Barcode Parameters (Fixed) -barcode_height = 18 # mm (1.8 cm) -barcode_width = auto # constrained to label width -character_limit = 25 # max per field -module_width = 0.5 # mm per bar -``` - -## Print Quality Specifications - -### Optimal Printer Settings -- **DPI:** 300 or higher -- **Paper Size:** Custom 11.5cm × 8cm (or similar) -- **Color Mode:** Monochrome (black & white) -- **Quality:** Best available -- **Margins:** Borderless printing recommended - -### Barcode Scanning -- **Format:** Code128 -- **Module Width:** 0.5mm (readable) -- **Height:** 18mm (optimal for most scanners) -- **Quiet Zone:** 2mm (maintained automatically) - -## Validation Tests ✓ - -- [x] Barcode height fixed to 18mm -- [x] Label dimensions correct (11.5×8cm) -- [x] Character limit enforced (25 chars) -- [x] PDF generation functional -- [x] GUI integration working -- [x] Backward compatibility maintained -- [x] All tests passed - -## Usage Examples - -### Python API -```python -from print_label import print_label_standalone - -# Generate and print label -print_label_standalone( - "SAP-12345|100|LOT-ABC", - "printer_name", - use_pdf=True # Uses corrected PDF settings -) -``` - -### GUI Application -```bash -python label_printer_gui.py -``` -- Enter SAP number (auto-truncated to 25 chars) -- Enter quantity (auto-truncated to 25 chars) -- Enter lot number (auto-truncated to 25 chars) -- Click Print -- PDF with 18mm barcodes generated - -## Performance Metrics - -| Metric | Value | Notes | -|--------|-------|-------| -| PDF Generation | 200-500ms | Per label | -| File Size | 1.7-2.0 KB | Consistent | -| Barcode Height | 18mm | Fixed ✓ | -| Label Size | 11.5×8cm | Confirmed ✓ | -| Scan Success Rate | >99% | Professional quality | - -## Troubleshooting Guide - -### Barcode Not Scanning -- Check printer DPI (300+ recommended) -- Verify label dimensions (11.5cm × 8cm) -- Ensure "Borderless" printing if available -- Test with standard barcode scanner - -### Text Truncation -- Values >25 characters auto-truncate -- Truncation happens during PDF generation -- Original value is preserved in memory -- Only barcode value is truncated - -### Height Issues -- Barcode height is FIXED at 18mm -- Cannot be smaller (won't scan) -- Cannot be larger (won't fit in row) -- This is optimal size for Code128 - -## Recommendations - -1. **Use These Settings** - Optimal for production -2. **Test First** - Print test label before large batch -3. **Keep Records** - Archive PDFs for reference -4. **Verify Scanning** - Test barcode with scanner -5. **Monitor Quality** - Check first 10 prints - -## Support & Reference - -- **PDF Dimensions:** 11.5cm × 8cm -- **Barcode Height:** 18mm (1.8cm) -- **Character Limit:** 25 characters -- **DPI:** 300 (print-ready) -- **Format:** PDF (vector-based) - -## Future Enhancements - -Potential improvements: -- Adjustable barcode height (with limits) -- Batch processing with configuration -- Multi-label per page -- Advanced barcode types (QR codes, etc.) - ---- - -**Status:** ✓ Production Ready -**Tested:** February 5, 2026 -**Last Updated:** February 5, 2026 - -The label printing system is now fully optimized with correct barcode dimensions and is ready for production use. diff --git a/documentation/FILE_GUIDE.md b/documentation/FILE_GUIDE.md deleted file mode 100644 index dd33e91..0000000 --- a/documentation/FILE_GUIDE.md +++ /dev/null @@ -1,296 +0,0 @@ -# 📋 File Reference Guide - -## Project Files Overview - -All files in `/srv/Label-design/` are listed below with their purposes: - ---- - -## 🆕 NEW FILES (Created for GUI Application) - -### Core Application -| File | Size | Purpose | -|------|------|---------| -| [label_printer_gui.py](label_printer_gui.py) | ~400 lines | Main Kivy GUI application - Start here! | - -### Setup & Launchers -| File | Purpose | -|------|---------| -| [setup_and_run.py](setup_and_run.py) | Python setup script (recommended way to start) | -| [start_gui.sh](start_gui.sh) | Bash launcher script (alternative method) | - -### Dependencies -| File | Purpose | -|------|---------| -| [requirements_gui.txt](requirements_gui.txt) | Python packages needed for GUI (kivy, etc) | - -### Documentation -| File | Best For | -|------|----------| -| [GETTING_STARTED.md](GETTING_STARTED.md) | 👈 **START HERE** - Quick start (15 min read) | -| [README_GUI.md](README_GUI.md) | Complete feature documentation (30 min read) | -| [TECHNICAL_DOCS.md](TECHNICAL_DOCS.md) | Architecture, customization, development (1 hour read) | -| [IMPLEMENTATION_SUMMARY.md](IMPLEMENTATION_SUMMARY.md) | What was built and how to use it | - ---- - -## 📦 ORIGINAL FILES (Preserved) - -### Core Printing Engine -| File | Size | Purpose | -|------|------|---------| -| [print_label.py](print_label.py) | ~270 lines | Core label printing functions | - -### Original Documentation -| File | Purpose | -|------|---------| -| [how_to.txt](how_to.txt) | Original usage instructions | -| [requirements.txt](requirements.txt) | Original dependencies (barcode, pillow, pycups) | - ---- - -## 🎯 How to Start - -### ✅ Recommended: Automatic Setup -```bash -cd /srv/Label-design -python3 setup_and_run.py -``` - -This will: -1. Check Python version -2. Verify CUPS printer service -3. Install dependencies -4. Launch the GUI - -### 📖 Alternative: Manual Start - -**Step 1:** Install dependencies -```bash -pip install -r requirements_gui.txt -``` - -**Step 2:** Run the application -```bash -python3 label_printer_gui.py -``` - -### 🐚 Alternative: Bash Script -```bash -chmod +x start_gui.sh -./start_gui.sh -``` - ---- - -## 📚 Documentation Reading Order - -### For Users: -1. **[GETTING_STARTED.md](GETTING_STARTED.md)** ← Read this first! (15 min) -2. **[README_GUI.md](README_GUI.md)** ← For detailed features (30 min) -3. **[IMPLEMENTATION_SUMMARY.md](IMPLEMENTATION_SUMMARY.md)** ← Overview of what was built (15 min) - -### For Developers: -1. **[TECHNICAL_DOCS.md](TECHNICAL_DOCS.md)** ← Architecture and implementation details -2. **[label_printer_gui.py](label_printer_gui.py)** ← Read the code with comments -3. **[print_label.py](print_label.py)** ← Understand printing engine - ---- - -## 🗂️ File Relationships - -``` -Your Application Structure: - -Entry Points: -├── setup_and_run.py ──────────► Checks env & starts GUI -├── start_gui.sh ───────────────► Bash alternative -└── label_printer_gui.py ──────► Main GUI (runs here) - -GUI Application: -└── label_printer_gui.py - ├── imports → print_label.py (printing functions) - ├── imports → Kivy (UI framework) - ├── LabelPreviewWidget class (preview display) - └── LabelPrinterApp class (main app logic) - -Printing Engine (unchanged): -└── print_label.py - ├── create_label_image(text) → PIL Image - └── print_label_standalone(value, printer, preview) → prints - -Documentation: -├── GETTING_STARTED.md (quick start) -├── README_GUI.md (features) -├── TECHNICAL_DOCS.md (development) -└── IMPLEMENTATION_SUMMARY.md (overview) - -Dependencies: -├── requirements_gui.txt (new - Kivy stack) -└── requirements.txt (original - printing) -``` - ---- - -## 🔍 Finding Things - -### "How do I...?" - -| Question | See File | -|----------|----------| -| ...get started quickly? | [GETTING_STARTED.md](GETTING_STARTED.md) | -| ...understand all features? | [README_GUI.md](README_GUI.md) | -| ...modify the GUI? | [TECHNICAL_DOCS.md](TECHNICAL_DOCS.md) | -| ...understand the code? | [label_printer_gui.py](label_printer_gui.py) (with comments) | -| ...see what was implemented? | [IMPLEMENTATION_SUMMARY.md](IMPLEMENTATION_SUMMARY.md) | -| ...fix a problem? | [GETTING_STARTED.md](GETTING_STARTED.md#troubleshooting) | -| ...change label size? | [TECHNICAL_DOCS.md](TECHNICAL_DOCS.md#customization-guide) | -| ...use just the printing functions? | [print_label.py](print_label.py) | - ---- - -## 💾 File Details - -### label_printer_gui.py -```python -# Main GUI application -# ~400 lines -# Classes: LabelPreviewWidget, LabelPrinterApp -# Features: Data entry, live preview, printing, notifications -``` - -### setup_and_run.py -```python -# Automatic environment setup -# ~100 lines -# Checks: Python, CUPS, dependencies -# Action: Installs packages and launches GUI -``` - -### start_gui.sh -```bash -# Bash launcher -# ~40 lines -# Portable way to start GUI on Linux/Unix -# Handles: Path issues, package installation -``` - -### requirements_gui.txt -``` -kivy -python-barcode -pillow -pycups -``` - ---- - -## 🚀 Quick Reference - -| To Do This | Use This File | Command | -|-----------|--------------|---------| -| Start GUI | setup_and_run.py | `python3 setup_and_run.py` | -| Quick help | GETTING_STARTED.md | Read in editor | -| Learn features | README_GUI.md | Read in editor | -| Debug issues | TECHNICAL_DOCS.md | Read in editor | -| View code | label_printer_gui.py | Open in editor | -| Use printing API | print_label.py | Import functions | - ---- - -## 📊 Statistics - -``` -Total Project Files: 11 -├── Code: 3 (gui + 2 setup scripts) -├── Configuration: 2 (requirements files) -├── Documentation: 4 (guides + summary) -└── Original: 2 (preserved from original project) - -Total Lines of Code: ~600 -├── GUI Application: ~400 lines -├── Setup Scripts: ~140 lines -└── Launcher: ~40 lines - -Total Documentation: ~5000 lines -├── Getting Started: ~400 lines -├── README GUI: ~600 lines -├── Technical Docs: ~2500 lines -├── Summary: ~1500 lines -└── This File: ~200 lines -``` - ---- - -## 🎯 Recommended Reading Path - -``` -Day 1: -└─ Setup and Run - ├─ Read: GETTING_STARTED.md (15 min) - ├─ Run: python3 setup_and_run.py (5 min) - └─ Use: Print your first label! (5 min) - -Day 2: -└─ Understand Features - ├─ Read: README_GUI.md (30 min) - └─ Use: Try all features in GUI (20 min) - -Day 3: -└─ Customize - ├─ Read: TECHNICAL_DOCS.md (1 hour) - ├─ Edit: Modify label_printer_gui.py - └─ Test: Try your modifications (30 min) -``` - ---- - -## ✅ Verification Checklist - -To verify everything is set up: - -```bash -# 1. Check files exist -ls -la /srv/Label-design/ - -# 2. Check Python installed -python3 --version - -# 3. Check Git (optional) -git log --oneline -5 - -# 4. Install dependencies -python3 setup_and_run.py # This installs for you - -# 5. Run application -python3 label_printer_gui.py -``` - ---- - -## 💡 Tips - -- **First time?** Start with `python3 setup_and_run.py` -- **Lost?** Check `GETTING_STARTED.md` -- **Questions?** Look in `README_GUI.md` -- **Customize?** Read `TECHNICAL_DOCS.md` -- **Code examples?** Check function comments in `label_printer_gui.py` - ---- - -## 📞 Quick Help - -| Issue | Solution | -|-------|----------| -| Can't start GUI | Run: `python3 setup_and_run.py` (installs deps) | -| Want quick start | Read: `GETTING_STARTED.md` | -| Need all features | Read: `README_GUI.md` | -| Want to customize | Read: `TECHNICAL_DOCS.md` | -| Printer not found | Check: `GETTING_STARTED.md#Printer-Setup` | - ---- - -**Last Updated:** February 4, 2026 -**Project Status:** ✅ Complete and Ready to Use - -**👉 Next Step:** Run `python3 setup_and_run.py` to get started! diff --git a/documentation/GETTING_STARTED.md b/documentation/GETTING_STARTED.md deleted file mode 100644 index c93a78e..0000000 --- a/documentation/GETTING_STARTED.md +++ /dev/null @@ -1,206 +0,0 @@ -# Getting Started with Label Printer GUI - -## Overview - -Your Label Printer application now has a modern Kivy-based GUI interface! This guide will help you get started. - -## Quick Start (3 Steps) - -### Option 1: Python Script (Recommended) -```bash -python3 setup_and_run.py -``` -This handles everything - checks dependencies, installs packages, and starts the GUI. - -### Option 2: Bash Script -```bash -chmod +x start_gui.sh -./start_gui.sh -``` - -### Option 3: Manual -```bash -pip install -r requirements_gui.txt -python3 label_printer_gui.py -``` - -## What You'll See - -### Main Window Layout - -``` -┌─────────────────────────────────────────────────────────────┐ -│ Label Printer Interface │ -├──────────────────┬──────────────────────────────────────────┤ -│ Input Column │ Preview Column │ -│ (40%) │ (60%) │ -│ │ │ -│ ✓ SAP-Nr. Input │ ╔════════════════════╗ │ -│ [________] │ ║ Live Preview ║ │ -│ │ ║ 11.5cm x 8cm ║ │ -│ ✓ Quantity │ ║ ║ │ -│ [________] │ ║ [Barcode] ║ │ -│ │ ║ SAP | QTY | ID ║ │ -│ ✓ Cable ID │ ║ ║ │ -│ [________] │ ╚════════════════════╝ │ -│ │ │ -│ ✓ Printer ▼ │ │ -│ [PDF ▼] │ │ -│ │ │ -│ [PRINT LABEL] │ │ -│ │ │ -└──────────────────┴──────────────────────────────────────────┘ -``` - -## Features Explained - -### Left Column - Data Entry - -1. **SAP-Nr. Articol** - - Enter the SAP article number or identifier - - Example: `A012345` - - Updates preview automatically - -2. **Cantitate (Quantity)** - - Numbers only - - Example: `100` - - Numeric input only - -3. **ID rola cablu (Cable Reel ID)** - - Cable reel identifier - - Example: `REEL-001` - - Updates preview automatically - -4. **Printer Selection** - - Dropdown menu with available system printers - - Shows all CUPS-configured printers - - Default: PDF printer (if no others available) - -5. **Print Label Button** - - Green button at bottom - - Triggers printing to selected printer - - Shows status notifications - -### Right Column - Live Preview - -- Shows exactly what will print -- Updates in real-time as you type -- Label dimensions: 11.5 cm × 8 cm -- Displays: - - Barcode (Code128 format) - - SAP number, quantity, and cable ID combined - - High quality 300 DPI rendering - -## Workflow Example - -1. **Start the application:** - ```bash - python3 setup_and_run.py - ``` - -2. **Enter data:** - - SAP-Nr: `A456789` - - Cantitate: `50` - - ID rola cablu: `REEL-042` - -3. **Check preview** (automatically updates on right) - -4. **Select printer** (use dropdown) - -5. **Click PRINT LABEL** button - -6. **Confirm** when notification appears - -## Printer Setup - -### Check Available Printers -```bash -lpstat -p -d -``` - -### Add a Printer (if needed) -```bash -# Use CUPS web interface -http://localhost:631 -``` - -### Common Printer Names -- `PDF` - Virtual PDF printer (for testing) -- `Brother_HL_L2350DW` - Brother laser printer -- `Canon_PIXMA` - Canon printer -- Check your system for exact name - -## Troubleshooting - -### "No Printers Found" -```bash -# Start CUPS service -sudo systemctl start cups - -# Check status -sudo systemctl status cups - -# List printers -lpstat -p -d -``` - -### Preview Not Updating -- Check Python console for errors -- Verify all dependencies installed: `pip list | grep -E 'kivy|barcode|pillow'` -- Try restarting the application - -### Print Fails -```bash -# Test print command manually -echo "test" | lp -d PDF - -# Check printer status -lpstat -p -l -``` - -### Kivy Window Issues -- If window doesn't open, check X11 display: - ```bash - echo $DISPLAY - ``` -- Resize window manually if elements overlap - -## File Guide - -- **label_printer_gui.py** - Main GUI application -- **print_label.py** - Core printing functions -- **setup_and_run.py** - Automatic setup script -- **start_gui.sh** - Bash launcher script -- **requirements_gui.txt** - Python dependencies -- **README_GUI.md** - Complete documentation - -## Tips & Tricks - -1. **Fast Printing:** - - Preset SAP number as most common value - - Just change quantity/ID for each label - -2. **Batch Printing:** - - Print one label at a time - - Small UI makes it quick - -3. **Testing:** - - Use "PDF" printer to save test labels - - Check output files to verify format - -4. **Keyboard:** - - Tab between fields - - Enter in printer dropdown to confirm selection - - Alt+P might activate Print button (Kivy dependent) - -## Next Steps - -- **Learn More:** See [README_GUI.md](README_GUI.md) -- **Customize:** Modify `label_printer_gui.py` for your needs -- **Integrate:** Use functions in other Python applications -- **Support:** Check console output for detailed error messages - ---- - -**Ready to print?** Start with: `python3 setup_and_run.py` - diff --git a/documentation/IMPLEMENTATION_SUMMARY.md b/documentation/IMPLEMENTATION_SUMMARY.md deleted file mode 100644 index fc69e69..0000000 --- a/documentation/IMPLEMENTATION_SUMMARY.md +++ /dev/null @@ -1,307 +0,0 @@ -# Label Printer GUI - Implementation Summary - -## ✅ Completed Implementation - -Your Label Printer GUI application has been successfully created with all requested features! - -## 📋 Features Implemented - -### ✓ Two-Column Layout -- **Left Column (40%):** Data entry form -- **Right Column (60%):** Real-time label preview - -### ✓ Data Entry Fields (Left Column) -1. **SAP-Nr. Articol** - Text input for SAP article number -2. **Cantitate** - Numeric input for quantity -3. **ID rola cablu** - Text input for cable reel identifier -4. **Printer Selection** - Dropdown menu with CUPS printers -5. **Print Label Button** - Green button to trigger printing - -### ✓ Live Preview (Right Column) -- Real-time preview of label as you type -- Label size: 11.5 cm × 8 cm (adjustable) -- Displays barcode + all three fields combined -- High-quality 300 DPI rendering - -### ✓ Advanced Features -- **Dynamic Preview:** Updates instantly with each keystroke -- **Printer Detection:** Auto-detects all CUPS-installed printers -- **Non-blocking Printing:** Background threads prevent UI freezing -- **Error Handling:** User-friendly error messages -- **Status Notifications:** Popups confirm print success/failure - -## 📁 Project Structure - -``` -/srv/Label-design/ -├── print_label.py # Core printing engine (ORIGINAL) -├── label_printer_gui.py # Kivy GUI application (NEW) -├── setup_and_run.py # Python setup launcher (NEW) -├── start_gui.sh # Bash launcher script (NEW) -├── requirements_gui.txt # Kivy dependencies (NEW) -├── README_GUI.md # Full documentation (NEW) -├── GETTING_STARTED.md # Quick start guide (NEW) -├── TECHNICAL_DOCS.md # Technical reference (NEW) -├── requirements.txt # Original dependencies -└── how_to.txt # Original how-to guide -``` - -## 🚀 Quick Start - -### Three Ways to Launch - -**Option 1: Automatic Setup (Recommended)** -```bash -python3 setup_and_run.py -``` - -**Option 2: Bash Script** -```bash -chmod +x start_gui.sh -./start_gui.sh -``` - -**Option 3: Manual** -```bash -pip install -r requirements_gui.txt -python3 label_printer_gui.py -``` - -## 🎯 How It Works - -### User Workflow -1. Enter SAP Number in first field -2. Enter Quantity (numbers only) -3. Enter Cable Reel ID -4. **Preview updates automatically** on the right -5. Select printer from dropdown -6. Click **PRINT LABEL** button -7. Receive confirmation message - -### Technical Workflow -``` -User Input - ↓ -TextInput event → on_input_change() - ↓ -Combine fields: "SAP|QTY|CABLE_ID" - ↓ -create_label_image(text) from print_label.py - ↓ -Generate barcode + render text - ↓ -Display in preview widget - ↓ -User clicks Print - ↓ -Background thread: print_label_standalone() - ↓ -Send to CUPS printer - ↓ -Success/Error notification -``` - -## 💻 System Requirements - -- **OS:** Linux/Unix with CUPS -- **Python:** 3.7 or higher -- **Display:** X11 or Wayland -- **Printer:** Any CUPS-configured printer (or PDF virtual printer) - -## 📦 Dependencies - -| Package | Purpose | Version | -|---------|---------|---------| -| kivy | GUI framework | 2.0+ | -| python-barcode | Barcode generation | Latest | -| pillow | Image processing | 8.0+ | -| pycups | CUPS printer interface | Latest | - -## 🎨 UI Layout - -``` -┌────────────────────────────────────────────────────────────┐ -│ Label Printer Interface (1600×900) │ -├──────────────────┬─────────────────────────────────────────┤ -│ │ │ -│ INPUT COLUMN │ PREVIEW COLUMN │ -│ (40% width) │ (60% width) │ -│ │ │ -│ ┌──────────────┐ │ ┌─────────────────────────────────┐ │ -│ │ SAP-Nr. Artic│ │ │ Label Preview │ │ -│ │ [text input] │ │ │ 11.5 cm × 8 cm │ │ -│ ├──────────────┤ │ │ │ │ -│ │ Cantitate │ │ │ ┌─────────────────────────────┐│ │ -│ │ [0 input] │ │ │ │ ╔═══════════════════════╗ ││ │ -│ ├──────────────┤ │ │ │ ║ [BARCODE] ║ ││ │ -│ │ ID rola │ │ │ │ ║ SAP|QTY|CABLE_ID ║ ││ │ -│ │ [text input] │ │ │ │ ╚═══════════════════════╝ ││ │ -│ ├──────────────┤ │ │ └─────────────────────────────┘│ │ -│ │ Printer: [PDF│ │ │ │ │ -│ │ ▼] │ │ │ │ │ -│ ├──────────────┤ │ │ │ │ -│ │ [PRINT LABEL]│ │ └─────────────────────────────────┘ │ -│ │ │ │ │ -│ └──────────────┘ │ │ -│ │ │ -└──────────────────┴─────────────────────────────────────────┘ -``` - -## 🔧 Customization - -All aspects can be customized: - -### UI Elements -- Window size -- Colors and fonts -- Field labels and types -- Button layout - -### Label Format -- Label physical size -- Barcode type (currently Code128) -- Text positioning -- DPI/quality - -### Data Fields -- Add/remove input fields -- Change field validation rules -- Modify data combination format - -See `TECHNICAL_DOCS.md` for customization examples. - -## 🐛 Troubleshooting - -### Common Issues & Solutions - -**"No printers found"** -```bash -sudo systemctl start cups -lpstat -p -d -``` - -**"Kivy window won't open"** -- Check X11 display: `echo $DISPLAY` -- Or use headless mode - -**"Preview not updating"** -- Check Python console for errors -- Verify Pillow installed: `python3 -c "from PIL import Image"` - -**"Print fails with permission error"** -- Add user to lpadmin group: `sudo usermod -aG lpadmin $USER` - -## 📚 Documentation - -- **GETTING_STARTED.md** - Quick start and workflow guide -- **README_GUI.md** - Full feature documentation -- **TECHNICAL_DOCS.md** - Architecture and development reference -- **print_label.py** - Inline code comments explaining functions - -## 🎓 Learning Path - -1. **Start:** Read `GETTING_STARTED.md` -2. **Use:** Run `python3 setup_and_run.py` -3. **Explore:** Open files in VS Code -4. **Customize:** Follow `TECHNICAL_DOCS.md` -5. **Integrate:** Use functions in your own code - -## 🔌 Integration with Other Code - -Use the printing function in your own Python applications: - -```python -from print_label import print_label_standalone, create_label_image - -# Just the barcode image (no printing) -image = create_label_image("YOUR_TEXT_HERE") -image.save("my_label.png") - -# Print directly -success = print_label_standalone( - value="YOUR_TEXT", - printer="PDF", - preview=0 -) - -if success: - print("Printed successfully!") -``` - -## 📊 Key Files - -| File | Purpose | Modified | -|------|---------|----------| -| label_printer_gui.py | Main GUI application | NEW | -| print_label.py | Printing engine | Updated (removed main code) | -| setup_and_run.py | Setup automation | NEW | -| start_gui.sh | Bash launcher | NEW | -| requirements_gui.txt | Kivy dependencies | NEW | -| README_GUI.md | Feature documentation | NEW | -| GETTING_STARTED.md | Quick start | NEW | -| TECHNICAL_DOCS.md | Developer reference | NEW | - -## ✨ Special Features - -1. **Real-time Preview** - - Instant visual feedback - - See exactly what will print - -2. **Intelligent Printer Detection** - - Auto-detects CUPS printers - - Falls back to PDF if none found - -3. **Non-blocking UI** - - Printing in background threads - - Never freezes the interface - -4. **Professional Layout** - - Two-column responsive design - - Scales to any window size - -5. **Data Persistence** - - Fields retain values - - Quick reprinting with modifications - -## 🚦 Status - -| Component | Status | Notes | -|-----------|--------|-------| -| GUI Framework | ✅ Complete | Kivy 2.0+ ready | -| Data Entry | ✅ Complete | All 3 fields + printer | -| Live Preview | ✅ Complete | Real-time updates | -| Printing | ✅ Complete | CUPS integration | -| Error Handling | ✅ Complete | User-friendly messages | -| Documentation | ✅ Complete | 3 documentation files | -| Setup Scripts | ✅ Complete | Python + Bash launchers | - -## 🎉 You're Ready! - -Everything is set up and ready to use. Start with: - -```bash -python3 setup_and_run.py -``` - -## 📝 Notes - -- Original `print_label.py` functionality fully preserved -- GUI adds modern interface without changing core logic -- Can be used independently or integrated with other systems -- Fully customizable for your needs - -## 🆘 Support - -1. Check **GETTING_STARTED.md** for quick help -2. See **TECHNICAL_DOCS.md** for detailed reference -3. Check console output for error details -4. Review inline code comments - ---- - -**Created:** February 4, 2026 -**Status:** Production Ready -**Version:** 1.0 -**Fully Implemented:** ✅ All Requirements Met - -**Enjoy your new Label Printer GUI!** 🎊 diff --git a/documentation/INDEX.md b/documentation/INDEX.md deleted file mode 100644 index 668d48e..0000000 --- a/documentation/INDEX.md +++ /dev/null @@ -1,415 +0,0 @@ -# 🎉 Label Printer GUI - Complete Project Index - -## Welcome! 👋 - -Your Label Printer GUI application is **complete and ready to use**! - ---- - -## ⚡ Quick Start (60 seconds) - -```bash -cd /srv/Label-design -python3 setup_and_run.py -``` - -That's it! The script will: -1. ✅ Check your system -2. ✅ Install dependencies -3. ✅ Launch the GUI - ---- - -## 📖 Documentation Overview - -### For First-Time Users 👶 -Start with these in order: - -1. **[GETTING_STARTED.md](GETTING_STARTED.md)** ⭐ - - 15-minute quick start - - Screenshots of the interface - - Basic workflow - - Troubleshooting guide - -2. **[README_GUI.md](README_GUI.md)** - - Complete feature list - - Detailed instructions - - Usage examples - - Common problems - -### For Advanced Users 🚀 -Dive deeper with these: - -3. **[TECHNICAL_DOCS.md](TECHNICAL_DOCS.md)** - - Architecture overview - - Code structure - - Customization guide - - Integration examples - -4. **[FILE_GUIDE.md](FILE_GUIDE.md)** - - File-by-file reference - - Project structure - - Quick lookup table - -### Reference 📚 -Quick lookups: - -- **[IMPLEMENTATION_SUMMARY.md](IMPLEMENTATION_SUMMARY.md)** - What was built -- **[validate_project.py](validate_project.py)** - Check if everything is set up - ---- - -## 🗂️ Project Files (13 files total) - -### Application Code (3 files) - -| File | Lines | Purpose | -|------|-------|---------| -| [label_printer_gui.py](label_printer_gui.py) | ~400 | Main Kivy GUI application ⭐ | -| [setup_and_run.py](setup_and_run.py) | ~100 | Python setup launcher | -| [start_gui.sh](start_gui.sh) | ~40 | Bash launcher script | - -### Configuration (2 files) - -| File | Purpose | -|------|---------| -| [requirements_gui.txt](requirements_gui.txt) | Python packages for GUI (new) | -| [requirements.txt](requirements.txt) | Python packages for printing (original) | - -### Documentation (5 files) - -| File | Target Audience | Read Time | -|------|-----------------|-----------| -| [GETTING_STARTED.md](GETTING_STARTED.md) | Everyone | 15 min ⭐ | -| [README_GUI.md](README_GUI.md) | Users | 30 min | -| [TECHNICAL_DOCS.md](TECHNICAL_DOCS.md) | Developers | 60 min | -| [FILE_GUIDE.md](FILE_GUIDE.md) | Developers | 10 min | -| [IMPLEMENTATION_SUMMARY.md](IMPLEMENTATION_SUMMARY.md) | Everyone | 15 min | - -### Validation (1 file) - -| File | Purpose | -|------|---------| -| [validate_project.py](validate_project.py) | Check if setup is complete | - -### Original Files (2 files - preserved) - -| File | Purpose | -|------|---------| -| [print_label.py](print_label.py) | Original printing engine | -| [how_to.txt](how_to.txt) | Original documentation | - ---- - -## 🎯 What You Can Do - -### ✅ Use the GUI -```bash -python3 setup_and_run.py -``` -Beautiful interface to: -- Enter label data -- See live preview -- Select printer -- Print labels - -### ✅ Use the API -```python -from print_label import print_label_standalone, create_label_image - -# Create image -image = create_label_image("DATA_HERE") -image.save("label.png") - -# Print directly -print_label_standalone("DATA", "PrinterName", preview=1) -``` - -### ✅ Customize Everything -- UI colors and layout -- Label size and format -- Data fields -- Printing behavior - -### ✅ Integrate with Systems -- Use printing functions in your apps -- Call GUI programmatically -- Extend with new features - ---- - -## 🚀 Getting Started Paths - -### Path 1: Just Use It (5 minutes) -``` -Setup → Run → Print → Done! -└─ python3 setup_and_run.py -``` - -### Path 2: Understand It (30 minutes) -``` -Read GETTING_STARTED.md - ↓ -Run setup_and_run.py - ↓ -Use the GUI - ↓ -Read README_GUI.md -``` - -### Path 3: Modify It (2 hours) -``` -Read FILE_GUIDE.md - ↓ -Read TECHNICAL_DOCS.md - ↓ -Edit label_printer_gui.py - ↓ -Test your changes -``` - -### Path 4: Integrate It (1 hour) -``` -Read TECHNICAL_DOCS.md - ↓ -Check integration examples - ↓ -Import functions in your code - ↓ -Use in your application -``` - ---- - -## 💡 Features at a Glance - -| Feature | Details | -|---------|---------| -| **Data Entry** | 3 input fields + printer dropdown | -| **Live Preview** | Real-time label preview (11.5×8 cm) | -| **Barcode** | Code128 format, auto-generated | -| **Printing** | Direct to CUPS printers | -| **UI** | Two-column responsive layout | -| **Threading** | Background printing (non-blocking) | -| **Notifications** | Success/error popups | -| **Auto-Detection** | Finds installed printers automatically | - ---- - -## 🔧 System Requirements - -- **OS:** Linux/Unix with CUPS -- **Python:** 3.7 or higher -- **Display:** X11 or Wayland -- **Disk:** ~50MB (with dependencies) -- **RAM:** 2GB minimum - ---- - -## 📦 Dependencies - -Automatically installed by setup_and_run.py: - -``` -kivy - GUI framework -python-barcode - Barcode generation -pillow - Image processing -pycups - Printer interface -``` - ---- - -## ✅ Verification - -Check if everything is working: - -```bash -python3 validate_project.py -``` - -This will check: -- ✅ All files present -- ✅ Python version -- ✅ Dependencies installed -- ✅ CUPS available -- ✅ Printers configured - ---- - -## 📞 Quick Troubleshooting - -| Problem | Solution | -|---------|----------| -| Can't run GUI | `python3 setup_and_run.py` (installs deps) | -| No printers | `sudo systemctl start cups` | -| Python too old | Install Python 3.7+ | -| Dependencies fail | Check internet connection, retry | -| Window won't open | Check `echo $DISPLAY` | - -See **[GETTING_STARTED.md](GETTING_STARTED.md#Troubleshooting)** for more help. - ---- - -## 🎓 Learning Resources - -### Quick Reference -- [FILE_GUIDE.md](FILE_GUIDE.md) - Find what you need -- Inline comments in [label_printer_gui.py](label_printer_gui.py) - -### Step-by-Step Guides -- [GETTING_STARTED.md](GETTING_STARTED.md) - How to use -- [README_GUI.md](README_GUI.md) - Features explained - -### In-Depth Knowledge -- [TECHNICAL_DOCS.md](TECHNICAL_DOCS.md) - Architecture & customization -- [print_label.py](print_label.py) - Printing engine code - ---- - -## 🎯 Next Steps - -### Immediate (now): -1. Run: `python3 setup_and_run.py` -2. Read: [GETTING_STARTED.md](GETTING_STARTED.md) -3. Print: Your first label - -### Soon (today): -1. Explore all GUI features -2. Try different printers -3. Read: [README_GUI.md](README_GUI.md) - -### Later (this week): -1. Customize colors/layout (if needed) -2. Read: [TECHNICAL_DOCS.md](TECHNICAL_DOCS.md) -3. Integrate with your systems - ---- - -## 📊 Project Statistics - -``` -📁 Total Files: 13 - ├─ Code Files: 3 (GUI app + setup scripts) - ├─ Config Files: 2 (dependencies) - ├─ Documentation: 5 (guides) - └─ Other: 3 (validation + original) - -💻 Total Code Lines: ~600 - ├─ GUI Application: ~400 lines - ├─ Setup Scripts: ~140 lines - └─ Validation: ~60 lines - -📚 Total Documentation: ~6,000 lines - ├─ Technical Docs: ~2,500 lines - ├─ README: ~600 lines - ├─ Getting Started: ~400 lines - └─ Other guides: ~2,500 lines - -⏱️ Time to First Print: 5-10 minutes -``` - ---- - -## 🎉 You're All Set! - -Everything is ready to go. Choose your path: - -### 🏃 Just Want to Start? -```bash -python3 setup_and_run.py -``` - -### 📖 Want to Learn First? -→ Read [GETTING_STARTED.md](GETTING_STARTED.md) - -### 🔍 Want to Explore? -→ Check [FILE_GUIDE.md](FILE_GUIDE.md) - -### 🔧 Want to Customize? -→ Read [TECHNICAL_DOCS.md](TECHNICAL_DOCS.md) - ---- - -## 📝 Quick Reference Card - -``` -┌─────────────────────────────────────────────────┐ -│ LABEL PRINTER GUI - QUICK REFERENCE │ -├─────────────────────────────────────────────────┤ -│ │ -│ Start GUI: │ -│ $ python3 setup_and_run.py │ -│ │ -│ Check Status: │ -│ $ python3 validate_project.py │ -│ │ -│ Manual Start: │ -│ $ python3 label_printer_gui.py │ -│ │ -│ First Read: │ -│ → GETTING_STARTED.md │ -│ │ -│ File Reference: │ -│ → FILE_GUIDE.md │ -│ │ -│ Full Docs: │ -│ → README_GUI.md │ -│ │ -│ Technical Details: │ -│ → TECHNICAL_DOCS.md │ -│ │ -└─────────────────────────────────────────────────┘ -``` - ---- - -## 🏆 Implementation Status - -| Component | Status | Notes | -|-----------|--------|-------| -| GUI Framework | ✅ Complete | Kivy 2.0+ | -| Data Entry Fields | ✅ Complete | 3 fields + printer | -| Live Preview | ✅ Complete | Real-time updates | -| Printing | ✅ Complete | CUPS integration | -| Barcode | ✅ Complete | Code128 format | -| Error Handling | ✅ Complete | User-friendly | -| Documentation | ✅ Complete | 5 guide files | -| Setup Automation | ✅ Complete | Python + Bash | -| All Requirements | ✅ Met | 100% complete | - ---- - -## 👏 Summary - -Your label printing application now has: -- ✅ Modern Kivy GUI interface -- ✅ Two-column responsive design -- ✅ Real-time barcode preview -- ✅ Automatic printer detection -- ✅ Non-blocking background printing -- ✅ Comprehensive documentation -- ✅ Easy setup and installation -- ✅ Complete code comments -- ✅ Ready for customization -- ✅ Production-ready quality - ---- - -## 🚀 Ready to Print? - -**Run this command and you're off:** - -```bash -python3 setup_and_run.py -``` - -**That's it!** Enjoy your new Label Printer GUI! 🎊 - ---- - -**Version:** 1.0 -**Status:** ✅ Production Ready -**Last Updated:** February 4, 2026 -**All Requirements:** ✅ Implemented - -Happy printing! 🖨️ diff --git a/documentation/OPTIMIZATION_SUMMARY.md b/documentation/OPTIMIZATION_SUMMARY.md deleted file mode 100644 index 4b28beb..0000000 --- a/documentation/OPTIMIZATION_SUMMARY.md +++ /dev/null @@ -1,254 +0,0 @@ -# PDF Label System - Final Optimization Summary - -**Date:** February 5, 2026 -**Status:** ✓ **OPTIMIZED & PRODUCTION READY** - -## Recent Improvements - -### 1. Label Dimensions Corrected ✓ -- **Previous:** 8.5 cm × 6 cm -- **Current:** 11.5 cm × 8 cm -- **Result:** Much larger working area for barcodes - -### 2. Barcode Height Optimized ✓ -- **Previous:** Variable, up to ~2.5 cm (row height - 8mm) -- **Current:** Fixed at 1.6 cm (optimal for scanners) -- **Range:** 1.5-1.8 cm recommended (1.6 cm is center) -- **Benefit:** Consistent, readable barcodes - -### 3. Text Character Limit ✓ -- **Enforcement:** Maximum 25 characters per field -- **Barcode Format:** Code128 (native limit: 25 characters) -- **Truncation:** Automatic, silent (doesn't break) -- **Result:** 100% barcode compatibility - -### 4. Layout Improvements ✓ -- **Margins:** Reduced to 3mm (was 5mm) -- **Usable Width:** Increased for barcode display -- **Centering:** Barcodes vertically centered in rows -- **Spacing:** Optimized for three-row layout - -## Current Specifications - -### Label Format -``` -┌─────────────────────────────────┐ -│ 11.5 cm × 8 cm (Full Label) │ -│ │ -│ ┌──────────────────────────────┐│ -│ │ SAP-Nr [BARCODE] ││ 1.6 cm height -│ ├──────────────────────────────┤│ -│ │ Cantitate [BARCODE] ││ 1.6 cm height -│ ├──────────────────────────────┤│ -│ │ Lot Nr [BARCODE] ││ 1.6 cm height -│ └──────────────────────────────┘│ -└─────────────────────────────────┘ -``` - -### Technical Details -| Parameter | Value | -|-----------|-------| -| Label Width | 11.5 cm | -| Label Height | 8 cm | -| Rows | 3 (SAP-Nr, Cantitate, Lot Nr) | -| Barcode Height | 1.6 cm per row | -| Barcode Format | Code128 | -| Max Text Length | 25 characters | -| Margins | 3 mm all sides | -| DPI (Default) | 300 (print-quality) | -| File Format | PDF (vector-based) | - -## Test Results - -### Generated Test Cases -``` -Test 1: Short values - Input: SAP-123 | 100 | LOT-ABC - Output: test_height_1.pdf (8.5 KB) - Status: ✓ PASS - -Test 2: Medium values - Input: SAP-12345678901234567890 | 250 | LOT-XYZ123456789 - Output: test_height_2.pdf (11.6 KB) - Status: ✓ PASS - -Test 3: Long values (truncation test) - Input: VERYLONGSAPNUMBERTEST12345 | 999 | LOT-EXTENDED-TEST - Truncated: VERYLONGSAPNUMBERTEST1234 (25 chars) - Output: test_height_3.pdf (13.5 KB) - Status: ✓ PASS (automatic truncation) -``` - -### System Integration Test -``` -Function: print_label_standalone("SAP-98765|Qty:500|LOT-FINAL", printer) -Generated: final_label_20260205_001351.pdf (10.1 KB) -Status: ✓ PASS - -Specifications Applied: - ✓ Correct dimensions (11.5 × 8 cm) - ✓ Correct barcode height (1.6 cm) - ✓ Text truncation (25 chars max) - ✓ PDF format (high quality) - ✓ Ready for printing -``` - -## Performance - -| Operation | Time | Notes | -|-----------|------|-------| -| Single PDF generation | ~200-500ms | Per label | -| Batch processing (4 labels) | ~1.5s | Total time | -| Barcode generation | ~100-200ms | Per barcode | -| Text truncation | <1ms | Per field | - -## Quality Improvements - -### Barcode Readability -- ✓ Optimal height for scanners (1.6 cm) -- ✓ Consistent size across all rows -- ✓ Proper spacing within label -- ✓ No overflow or clipping -- ✓ 100% Code128 compatibility - -### Label Layout -- ✓ Balanced three-row design -- ✓ Proper vertical centering -- ✓ Optimized horizontal spacing -- ✓ Clean, professional appearance -- ✓ Consistent formatting - -### Text Handling -- ✓ Automatic truncation at 25 characters -- ✓ No barcode generation failures -- ✓ Graceful fallback to text display -- ✓ Clear visual separation -- ✓ Readable label names - -## Backward Compatibility - -| Feature | Status | Notes | -|---------|--------|-------| -| PNG fallback | ✓ Supported | `use_pdf=False` | -| Original API | ✓ Maintained | All functions work | -| Custom dimensions | ✓ Supported | Override defaults | -| High DPI mode | ✓ Supported | 600 DPI available | -| GUI integration | ✓ Working | Full compatibility | - -## Usage Examples - -### Basic Usage (Recommended) -```python -from print_label import print_label_standalone - -# PDF format (default, recommended) -print_label_standalone("SAP-123|100|LOT-ABC", "printer_name") -``` - -### With Text Truncation Handling -```python -from print_label_pdf import PDFLabelGenerator - -# Long text automatically truncates to 25 chars -generator = PDFLabelGenerator() -pdf = generator.create_label_pdf( - sap_nr="VERYLONGSAPNUMBER123456789", # Will truncate to 25 chars - cantitate="100", - lot_number="LOT-ABC", - filename="label.pdf" -) -``` - -### Custom Label Size -```python -# Create different label size -generator = PDFLabelGenerator(label_width=10, label_height=7, dpi=600) -pdf = generator.create_label_pdf(sap_nr, qty, lot, filename) -``` - -## Known Limitations - -| Limitation | Details | Workaround | -|-----------|---------|-----------| -| Text Length | Max 25 chars | Truncates automatically | -| Barcode Types | Code128 only | Covers 95% of use cases | -| Rows | 3 fixed | Meets all current needs | -| DPI | 300 default | Change via constructor | - -## Deployment Checklist - -- [x] Barcode height optimized (1.6 cm) -- [x] Label dimensions corrected (11.5 × 8 cm) -- [x] Text truncation implemented (25 chars) -- [x] All tests passing (✓ 100%) -- [x] GUI integration verified -- [x] PDF quality verified -- [x] Backward compatibility maintained -- [x] Documentation updated -- [x] Performance validated -- [x] Error handling tested - -## Recommendations for Users - -1. **Always use PDF format** - Superior quality and smaller files -2. **Test with your printer** - Verify barcode scanning -3. **Use standard text** - Keep values under 25 characters -4. **Archive PDFs** - Much smaller than PNG backups -5. **Monitor first batch** - Ensure everything scans properly - -## File Manifest - -**Core Files:** -- `print_label_pdf.py` - PDF generation engine -- `print_label.py` - Printing interface -- `label_printer_gui.py` - GUI application - -**Documentation:** -- `PDF_UPGRADE_GUIDE.md` - Full documentation -- `QUICK_START.md` - Quick reference -- `TEST_RESULTS_PDF_SYSTEM.md` - Test results - -**Demo:** -- `demo_pdf_system.py` - Comprehensive demo - -## Support & Troubleshooting - -### Barcode Not Scanning -1. Check text length (should be ≤ 25 characters) -2. Verify printer supports PDF format -3. Ensure 300 DPI minimum for barcodes -4. Test with known barcode scanner - -### Text Truncation -1. This is automatic and intentional -2. Values over 25 characters are silently truncated -3. Fallback to text display if barcode fails -4. Check console output for details - -### Label Overflow -1. Labels will now fit within 11.5 × 8 cm -2. Barcodes limited to 1.6 cm height -3. Text auto-truncates at 25 characters -4. Should not overflow in normal use - -## Next Steps - -1. **Deploy to production** - All optimizations complete -2. **Update printer settings** - Verify PDF support -3. **Test with actual printer** - First batch verification -4. **Train users** - Document new specifications -5. **Monitor usage** - Collect feedback - ---- - -## Summary - -The PDF label generation system is now **fully optimized** with: -- ✓ Correct label dimensions (11.5 × 8 cm) -- ✓ Optimal barcode height (1.6 cm) -- ✓ Automatic text truncation (25 chars max) -- ✓ Professional quality output -- ✓ 100% production ready - -**Status: APPROVED FOR PRODUCTION DEPLOYMENT** ✓ - diff --git a/documentation/PDF_UPGRADE_GUIDE.md b/documentation/PDF_UPGRADE_GUIDE.md deleted file mode 100644 index 077c76a..0000000 --- a/documentation/PDF_UPGRADE_GUIDE.md +++ /dev/null @@ -1,179 +0,0 @@ -# PDF Label Generation System - Upgrade Guide - -## Overview -The label printing system has been upgraded from PNG-based printing to **high-quality PDF generation**. This provides significantly better print quality, sharper barcodes, and professional results. - -## Key Improvements - -### 1. **Vector-Based PDF Generation** - - **Before**: PNG rasterization at 300 DPI (blurry when zoomed) - - **After**: PDF with vector graphics and embedded barcodes (sharp at any scale) - - Result: Professional print quality with crisp barcodes and text - -### 2. **Better Barcode Rendering** - - PDF format preserves barcode quality for reliable scanning - - 300 DPI barcode generation ensures readability - - Proper spacing and quiet zones maintained - -### 3. **Improved Printing Pipeline** - - Files are retained with timestamps for easy reference - - Better error handling and fallback support - - Both PDF and PNG formats supported (backward compatible) - -## New Files - -### `print_label_pdf.py` -High-quality PDF label generator using ReportLab library. - -**Key Classes:** -- `PDFLabelGenerator`: Main class for PDF generation - - `__init__(label_width=8.5, label_height=6, dpi=300)`: Initialize with custom dimensions - - `create_label_pdf()`: Generate PDF bytes or file - - `generate_barcode_image()`: Create high-quality barcodes - -**Functions:** -- `create_label_pdf_simple(text)`: Simple wrapper for PDF generation -- `create_label_pdf_file(text, filename)`: Generate PDF file with auto-naming - -## Updated Files - -### `print_label.py` -Enhanced with PDF support while maintaining backward compatibility. - -**New Functions:** -- `create_label_pdf(text)`: Create high-quality PDF labels - -**Updated Functions:** -- `print_label_standalone(value, printer, preview=0, use_pdf=True)` - - New parameter: `use_pdf` (default: True) - - Set `use_pdf=False` to use PNG format - -### `label_printer_gui.py` -Updated Kivy GUI to use PDF by default. - -**Changes:** -- Preview now shows "High-quality PDF format for printing" indicator -- Print button uses PDF generation by default -- Success message mentions superior PDF quality -- Updated imports for PDF module - -## Installation - -### Install New Dependencies -```bash -pip install reportlab -``` - -Or install all requirements: -```bash -pip install -r requirements_gui.txt -``` - -## Usage - -### Using the GUI -1. Launch the application as usual -2. Enter SAP number, Quantity, and Lot ID -3. Select printer -4. Click "PRINT LABEL" -5. PDF is automatically generated and sent to printer - -### Programmatic Usage - -**Using PDF (Recommended):** -```python -from print_label import print_label_standalone - -# Generate and print PDF (default) -print_label_standalone("SAP123|100|LOT456", "printer_name") - -# With preview -print_label_standalone("SAP123|100|LOT456", "printer_name", preview=1, use_pdf=True) -``` - -**Using PNG (Backward Compatible):** -```python -from print_label import print_label_standalone - -print_label_standalone("SAP123|100|LOT456", "printer_name", use_pdf=False) -``` - -**Direct PDF Generation:** -```python -from print_label import create_label_pdf - -# Create PDF file -pdf_file = create_label_pdf("SAP123|100|LOT456") -print(f"Generated: {pdf_file}") -``` - -## Quality Comparison - -| Aspect | PNG | PDF | -|--------|-----|-----| -| **Print Quality** | Rasterized, may blur | Vector, always sharp | -| **Barcode Reliability** | Fair | Excellent | -| **File Size** | ~50-100 KB | ~20-40 KB | -| **Scalability** | Fixed resolution | Infinite | -| **Color Accuracy** | Good | Excellent | - -## Technical Details - -### PDF Dimensions -- Label Size: 11.5 cm × 8 cm (3 rows × 1 column layout) -- DPI: 300 (print-ready) -- Margins: 3 mm on all sides - -### Barcode Specifications -- Format: Code128 -- Height: 1.6 cm per row (optimized for 1.5-1.8 cm range) -- Maximum text length: 25 characters (Code128 limitation) -- Module Width: Auto-scaled for row width -- Quiet Zone: 2 modules - -## Troubleshooting - -### PDF Not Printing -1. Check printer CUPS configuration -2. Verify PDF viewer support on printer -3. Check PDF file was created: `ls -lh label_*.pdf` - -### Barcode Quality Issues -1. Check printer resolution (300 DPI recommended minimum) -2. Verify printer supports PDF format -3. Ensure proper barcode values (max 25 characters) - -### Font Issues -1. System uses DejaVu fonts by default -2. Fallback to default fonts if not available -3. PDF embeds font metrics automatically - -## Performance - -- PDF generation: ~200-500ms per label -- Print queue submission: ~100ms -- Total time: Similar to PNG but with superior quality - -## Backward Compatibility - -The system is fully backward compatible: -- Old PNG files still work -- Can switch between PDF and PNG with `use_pdf` parameter -- All existing code continues to function - -## Future Enhancements - -Potential improvements for future versions: -- Custom label sizes and layouts -- Multi-label per page support -- Batch printing with optimization -- Advanced barcode types (QR, EAN, etc.) -- Label preview in PDF format - -## Support - -For issues or questions: -1. Check the error messages in console output -2. Verify all dependencies are installed -3. Ensure printer is properly configured in CUPS -4. Check file permissions in working directory diff --git a/documentation/QUICK_REFERENCE.md b/documentation/QUICK_REFERENCE.md deleted file mode 100644 index 297f993..0000000 --- a/documentation/QUICK_REFERENCE.md +++ /dev/null @@ -1,246 +0,0 @@ -# Label Printing System - Quick Reference Card - -## System Specifications ✓ - -| Parameter | Value | Notes | -|-----------|-------|-------| -| **Label Width** | 11.5 cm | Full width | -| **Label Height** | 8 cm | Full height | -| **Rows** | 3 | SAP-Nr, Cantitate, Lot Nr | -| **Barcode Height** | 18 mm (1.8 cm) | Fixed, optimal for scanning | -| **Barcode Format** | Code128 | Standard barcode format | -| **Character Limit** | 25 chars max | Per field | -| **DPI** | 300 | Print-ready quality | -| **File Format** | PDF | Vector-based, professional | -| **Margin** | 3 mm | All sides | - -## Quick Start - -### 1. Activate Environment -```bash -cd /srv/Label-design -source venv/bin/activate -``` - -### 2. Run GUI -```bash -python label_printer_gui.py -``` - -### 3. Enter Data -- SAP-Nr: Up to 25 characters -- Cantitate: Up to 25 characters -- Lot Nr: Up to 25 characters -- Select Printer - -### 4. Print -- Click "PRINT LABEL" -- PDF generates automatically -- Sends to printer - -## Command Line Usage - -```bash -# Generate PDF label -python3 -c "from print_label import print_label_standalone; \ -print_label_standalone('SAP-123|100|LOT-ABC', 'printer_name')" - -# Generate without printing (test) -python3 -c "from print_label import create_label_pdf; \ -pdf = create_label_pdf('SAP-123|100|LOT-ABC'); \ -print(f'Generated: {pdf}')" -``` - -## Label Data Format - -``` -Input Format: "SAP|CANTITATE|LOT" - -Example: "SAP-12345|100|LOT-ABC" - └─────┬─────┘ └──┬──┘ └──┬──┘ - SAP-Nr Qty Lot Nr - -Each becomes a barcode row in the PDF -``` - -## Barcode Specifications - -| Aspect | Specification | Details | -|--------|---------------|---------| -| **Type** | Code128 | Standard barcode | -| **Height** | 18 mm | Fixed (1.8 cm) | -| **Width** | Auto | Fits within label | -| **Module Width** | 0.5 mm | Bar thickness | -| **Quiet Zone** | 2 mm | Auto-applied | -| **Max Length** | 25 chars | Auto-truncates | - -## File Locations - -``` -/srv/Label-design/ -├── label_printer_gui.py ← GUI application -├── print_label.py ← Main module (PDF/PNG) -├── print_label_pdf.py ← PDF generation engine -├── requirements_gui.txt ← Dependencies -└── venv/ ← Virtual environment -``` - -## Generated Files - -Labels are saved with timestamps: -``` -final_label_20260205_001617.pdf - └─────────┬─────────┘ - YYYYMMDD_HHMMSS -``` - -Files are retained in working directory for reprinting. - -## Troubleshooting - -### PDF Won't Generate -```bash -# Check dependencies -pip list | grep reportlab - -# Reinstall if needed -pip install reportlab -``` - -### Barcode Won't Scan -- Verify printer DPI (300+ required) -- Check label dimensions (11.5cm × 8cm) -- Use "Borderless" printing -- Test with standard scanner - -### Text Gets Cut Off -- Max 25 characters per field -- Longer text auto-truncates -- Check for special characters - -### File Not Found -```bash -# Verify virtual environment is active -which python -# Should show: /srv/Label-design/venv/bin/python -``` - -## Printer Setup (CUPS) - -### View Available Printers -```bash -lpstat -p -d -``` - -### Configure Printer Size -```bash -# Open CUPS web interface -http://localhost:631 -``` - -### Test Print -```bash -python3 -c "from print_label import print_label_standalone; \ -print_label_standalone('TEST|123|ABC', 'your_printer_name', use_pdf=True)" -``` - -## Documentation - -- **Full Guide:** `PDF_UPGRADE_GUIDE.md` -- **Setup Guide:** `QUICK_START.md` -- **Barcode Details:** `BARCODE_HEIGHT_CORRECTION.md` -- **Test Results:** `TEST_RESULTS_PDF_SYSTEM.md` - -## API Summary - -### Simple Function -```python -from print_label import print_label_standalone -print_label_standalone(text, printer, use_pdf=True) -``` - -### PDF Generation -```python -from print_label import create_label_pdf -pdf_file = create_label_pdf("SAP|QTY|LOT") -``` - -### Advanced (Custom Size) -```python -from print_label_pdf import PDFLabelGenerator -gen = PDFLabelGenerator(label_width=11.5, label_height=8) -pdf = gen.create_label_pdf("SAP", "QTY", "LOT", "output.pdf") -``` - -## Performance - -| Task | Time | -|------|------| -| Single label PDF | 200-500ms | -| Single label PNG | 300-600ms | -| Batch (4 labels) | ~1.5 sec | -| Print submission | ~100ms | - -## Quality Levels - -### Standard (300 DPI) -- Good for most applications -- Barcode easily scannable -- Default setting - -### High Quality (600 DPI) -```python -gen = PDFLabelGenerator(dpi=600) -``` -- Premium color reproduction -- Extra-high barcode precision - -## Common Issues & Solutions - -| Issue | Cause | Solution | -|-------|-------|----------| -| Barcode too small | Old config | Update to v2.0+ | -| Text cut off | >25 chars | Values auto-truncate | -| PDF won't print | Printer config | Check CUPS settings | -| Module not found | Missing venv | Run `source venv/bin/activate` | -| No barcodes | Generation error | Falls back to text | - -## Environment Variables (Optional) - -```bash -# Set default printer -export CUPS_DEFAULT_PRINTER="your_printer" - -# Set temporary directory -export TMPDIR="/tmp/labels" -``` - -## Support Resources - -1. **Error Messages** - Check console output -2. **GUI Issues** - Verify Kivy installation -3. **Print Issues** - Check CUPS configuration -4. **Barcode Issues** - Test with standard scanner - -## System Requirements - -- **Python:** 3.10+ -- **OS:** Linux (CUPS required) -- **Printer:** Any CUPS-compatible printer -- **Display:** For GUI (optional, can run headless) - -## Version Info - -- **System Version:** 2.0 (PDF-based) -- **Release Date:** February 5, 2026 -- **Status:** ✓ Production Ready - ---- - -**Quick Notes:** -- Always activate venv before running -- Label size is 11.5cm × 8cm (fixed) -- Barcode height 18mm (fixed) -- Max 25 characters per field (auto-truncates) -- PDF format for best quality -- Use CUPS for printing diff --git a/documentation/QUICK_START.md b/documentation/QUICK_START.md deleted file mode 100644 index 60a3f0b..0000000 --- a/documentation/QUICK_START.md +++ /dev/null @@ -1,226 +0,0 @@ -# Quick Start Guide - PDF Label Printing System - -## Installation & Setup - -### 1. Activate Virtual Environment -```bash -cd /srv/Label-design -source venv/bin/activate -``` - -### 2. Install Dependencies (One-time) -```bash -pip install -r requirements_gui.txt -``` - -Or manually: -```bash -pip install python-barcode pillow pycups kivy reportlab -``` - -## Running the Application - -### GUI Application (Recommended for Users) -```bash -source venv/bin/activate -python label_printer_gui.py -``` - -The GUI will open with: -- Input fields for SAP number, quantity, and lot ID -- Real-time label preview -- Printer selection dropdown -- Print button for easy printing - -### Command Line (For Scripts/Integration) -```bash -source venv/bin/activate -python3 -c "from print_label import print_label_standalone; print_label_standalone('SAP-123|100|LOT-456', 'printer_name')" -``` - -## Using the System - -### Basic PDF Label Generation -```python -from print_label import create_label_pdf - -# Generate PDF file -pdf_file = create_label_pdf("SAP-123|100|LOT-456") -print(f"Created: {pdf_file}") -``` - -### Print to Printer -```python -from print_label import print_label_standalone - -# PDF (recommended - highest quality) -print_label_standalone("SAP-123|100|LOT-456", "printer_name", use_pdf=True) - -# PNG (fallback) -print_label_standalone("SAP-123|100|LOT-456", "printer_name", use_pdf=False) -``` - -### Advanced: Custom Label Size -```python -from print_label_pdf import PDFLabelGenerator - -# Create 6cm × 4cm labels at 600 DPI -generator = PDFLabelGenerator(label_width=6, label_height=4, dpi=600) -pdf = generator.create_label_pdf( - sap_nr="SAP-123", - cantitate="100", - lot_number="LOT-456", - filename="custom_label.pdf" -) -``` - -## Key Features - -### PDF Generation (Default) -- **Quality:** Professional vector-based format -- **File Size:** ~1.7 KB per label (91% smaller than PNG) -- **Scalability:** Works at any print resolution -- **Speed:** 200-500ms per label -- **Barcodes:** Sharp, reliable Code128 barcodes - -### PNG Format (Fallback) -- **Quality:** Rasterized at 300 DPI -- **Compatibility:** Works with older systems -- **File Size:** ~19 KB per label -- **Use Case:** Legacy printer support - -## Finding Printer Name - -To see available printers: -```bash -# Using CUPS -lpstat -p -d - -# Or in Python -import cups -conn = cups.Connection() -printers = conn.getPrinters() -for name in printers.keys(): - print(name) -``` - -## Generated Files - -Labels are saved with timestamps: -- `final_label_20260205_000537.pdf` (timestamp format) -- Files are retained in current directory -- Easy to retrieve for reprinting - -## Format Options - -### Text Format: "SAP|QUANTITY|LOT" -``` -"SAP-12345|100|LOT-ABC123" - ↓ ↓ ↓ - SAP-Nr Cantitate Lot Nr -``` - -Each part becomes a barcode + label row in the output. - -## Troubleshooting - -### "No module named reportlab" -```bash -source venv/bin/activate -pip install reportlab -``` - -### "No such file or directory" (printer error) -This is normal - it means the printer doesn't exist. -Create a valid printer in CUPS first: -```bash -# Configure printer in CUPS web interface -http://localhost:631 -``` - -### GUI Won't Start -Make sure display is available: -```bash -# Check if X11 is running -echo $DISPLAY -``` - -### Barcode Not Showing -The system falls back to text if barcode generation fails. -Make sure: -- Value is under 25 characters -- Text contains valid barcode characters -- System has write access to temp directory - -## Testing - -Run the comprehensive demo: -```bash -source venv/bin/activate -python demo_pdf_system.py -``` - -This tests: -- Basic PDF generation -- Custom dimensions -- Batch processing -- High DPI support -- PNG fallback -- API usage examples - -## File Structure - -``` -/srv/Label-design/ -├── label_printer_gui.py # GUI Application -├── print_label.py # Main printing module (updated with PDF support) -├── print_label_pdf.py # PDF generation engine -├── demo_pdf_system.py # Comprehensive demo -├── requirements.txt # Base dependencies -├── requirements_gui.txt # GUI dependencies -├── PDF_UPGRADE_GUIDE.md # Full documentation -├── TEST_RESULTS_PDF_SYSTEM.md # Test results -├── QUICK_START.md # This file -└── venv/ # Virtual environment -``` - -## Performance - -| Task | Time | Notes | -|------|------|-------| -| Single PDF generation | 200-500ms | Per label | -| Single PNG generation | 300-600ms | Legacy | -| Batch (4 labels) | ~1.5 seconds | PDF format | -| Print submission | ~100ms | To CUPS | - -## Tips & Best Practices - -1. **Use PDF by default** - Better quality, smaller files -2. **Keep PNG option** - For backward compatibility -3. **Use 300 DPI** - Standard for barcode scanning -4. **Archive PDFs** - Smaller file sizes = less storage -5. **Test printer** - Verify PDF support before large runs - -## Support Resources - -- **Full Documentation:** See `PDF_UPGRADE_GUIDE.md` -- **Test Results:** See `TEST_RESULTS_PDF_SYSTEM.md` -- **Demo Code:** Run `demo_pdf_system.py` -- **Code Examples:** Look at function docstrings - -## Environment Variables - -Optional environment customization: -```bash -# Set default printer -export CUPS_DEFAULT_PRINTER="your_printer_name" - -# Set temp directory for label files -export TMPDIR="/path/to/temp" -``` - ---- - -**Status:** ✓ Production Ready -**Last Updated:** February 5, 2026 -**Version:** 2.0 (PDF-based) diff --git a/documentation/README_GUI.md b/documentation/README_GUI.md deleted file mode 100644 index 6830065..0000000 --- a/documentation/README_GUI.md +++ /dev/null @@ -1,168 +0,0 @@ -# Label Printer GUI Application - -A modern Kivy-based graphical interface for printing labels with barcodes, featuring real-time preview and printer selection. - -## Features - -✓ **Two-Column Layout** - - Left: Data entry form with input fields - - Right: Real-time label preview - -✓ **Input Fields** - - SAP-Nr. Articol (SAP Number/Article) - - Cantitate (Quantity) - - ID rola cablu (Cable Reel ID) - -✓ **Live Preview** - - Real-time preview of label as you type - - Label size: 11.5 cm × 8 cm - - Shows barcode and all entered information - -✓ **Printer Management** - - Dropdown to select from available system printers - - Automatic detection of installed CUPS printers - -✓ **Printing** - - Direct printing to selected printer - - Background printing with status notifications - - Error handling and user feedback - -## Installation - -### Prerequisites -- Python 3.7 or higher -- CUPS (Common Unix Printing System) - usually pre-installed on Linux -- System printer configured and installed - -### Setup Steps - -1. **Install dependencies:** -```bash -pip install -r requirements_gui.txt -``` - -2. **Install Kivy garden dependencies** (if using matplotlib preview): -```bash -garden install matplotlib -``` - -3. **Ensure system printer is configured:** -```bash -# Check available printers -lpstat -p -d - -# Or using CUPS web interface -# Open: http://localhost:631 -``` - -## Usage - -### Run the GUI Application - -```bash -python label_printer_gui.py -``` - -### Operation - -1. **Enter Label Data:** - - Type the SAP Number in the first field - - Enter the quantity (numbers only) - - Enter the Cable Reel ID - -2. **Monitor Preview:** - - The preview updates automatically as you type - - Shows combined barcode with all entered data - -3. **Select Printer:** - - Use the dropdown to select your target printer - - Default is "PDF" if no other printers available - -4. **Print:** - - Click "PRINT LABEL" button - - Wait for confirmation message - - Label will print to selected printer - -## Label Format - -The label contains: -- **Row 1:** SAP Number | Quantity | Cable ID (combined in barcode) -- **Barcode:** Code128 format encoding the combined information -- **Size:** 11.5 cm width × 8 cm height -- **DPI:** 300 DPI for high-quality printing - -## File Structure - -``` -/srv/Label-design/ -├── print_label.py # Core printing functions -├── label_printer_gui.py # Kivy GUI application -├── requirements.txt # Original dependencies -├── requirements_gui.txt # GUI-specific dependencies -└── how_to.txt # Original documentation -``` - -## Troubleshooting - -### No printers detected -- Check CUPS service: `sudo systemctl status cups` -- List printers: `lpstat -p` -- Restart CUPS if needed: `sudo systemctl restart cups` - -### Preview not updating -- Ensure all input fields are properly connected -- Check console for error messages -- Verify PIL/Pillow installation: `python -c "from PIL import Image; print('OK')"` - -### Print fails -- Verify printer name is correct -- Check printer status: `lpstat -p -d` -- Test direct print: `echo "test" | lp -d printername` -- Ensure CUPS daemon is running - -### Kivy window sizing issues -- The app defaults to 1600×900 window -- Can be resized freely after launch -- Modify `Window.size = (1600, 900)` in code to change default - -## Code Integration - -To integrate the printing function into other applications: - -```python -from print_label import print_label_standalone - -# Print a label -success = print_label_standalone( - value="YOUR_TEXT", - printer="printername", - preview=0 # 0=no preview, 1-3=3s preview, >3=5s preview -) -``` - -## Requirements - -- **kivy**: GUI framework -- **python-barcode**: Barcode generation -- **pillow**: Image processing -- **pycups**: CUPS printer interface -- **matplotlib**: (Optional) For advanced visualization - -## License - -Based on the existing print_label.py printing framework. - -## Notes - -- All data is combined into a single barcode for easy scanning -- Labels are printed at 300 DPI for sharp quality -- Temporary files are cleaned up automatically -- Printing happens in background threads to prevent UI blocking - -## Support - -For issues or questions, check: -1. Console output for error messages -2. CUPS printer configuration -3. System printer availability -4. Required dependencies installation diff --git a/documentation/SIMPLIFIED_LAYOUT.md b/documentation/SIMPLIFIED_LAYOUT.md deleted file mode 100644 index c78c904..0000000 --- a/documentation/SIMPLIFIED_LAYOUT.md +++ /dev/null @@ -1,251 +0,0 @@ -# PDF Label Layout - Simplified & Fixed - -**Date:** February 5, 2026 -**Status:** ✓ **FIXED AND TESTED** - -## Changes Made - -### 1. **Removed All Borders** ✓ -- No rectangle borders around rows -- No visual boxes/frames -- Clean, minimal layout - -### 2. **Simplified Layout** ✓ -- Field names at top of each row (small text) -- Barcodes below field names -- Empty space around for clean appearance -- More usable space for barcodes - -### 3. **Fixed Barcode Height** ✓ -- Height: 18mm (1.8cm) - FIXED -- Properly displayed and readable -- No longer cut off or too small - -### 4. **Character Limit Enforced** ✓ -- Maximum 25 characters per field -- Automatic truncation -- No barcode generation errors - -## Layout Structure - -``` -┌─ Label (11.5cm × 8cm) ─┐ -│ │ -│ SAP-Nr (small text) │ -│ [ BARCODE ] │ 18mm height -│ │ -│ Cantitate (small text) │ -│ [ BARCODE ] │ 18mm height -│ │ -│ Lot Nr (small text) │ -│ [ BARCODE ] │ 18mm height -│ │ -└────────────────────────┘ -``` - -## PDF Specifications - -| Parameter | Value | Notes | -|-----------|-------|-------| -| Label Width | 11.5 cm | Full width | -| Label Height | 8 cm | Full height | -| Barcode Height | 18 mm | Fixed, professional | -| Barcode Width | Auto | Fits within label | -| Margin | 3 mm | Minimal | -| Rows | 3 | SAP-Nr, Cantitate, Lot Nr | -| Border | None | Removed for clean look | -| Format | Code128 | Standard barcode | -| DPI | 300 | Print-ready | - -## Field Layout - -``` -Row 1: SAP-Nr - - Field name: 8pt Helvetica-Bold - - Barcode: 18mm height - - Width: Auto-fit to label - -Row 2: Cantitate - - Field name: 8pt Helvetica-Bold - - Barcode: 18mm height - - Width: Auto-fit to label - -Row 3: Lot Nr - - Field name: 8pt Helvetica-Bold - - Barcode: 18mm height - - Width: Auto-fit to label -``` - -## File Changes - -### print_label_pdf.py - RECREATED -- Removed all border drawing code -- Simplified row layout -- Fixed barcode height at 18mm -- Clean implementation -- No duplicate code - -### print_label.py - NO CHANGES -- Still works with updated PDF module -- Backward compatible -- PNG fallback still available - -### label_printer_gui.py - NO CHANGES -- Imports work correctly -- GUI functions unchanged -- Benefits from improved PDF layout - -## Testing Results ✓ - -``` -Test 1: Basic Label -Input: "SAP-ABC123|Qty:500|LOT-2024-XYZ" -Result: ✓ PDF generated (1,635 bytes) -Barcode Height: ✓ 18mm visible -Borders: ✓ None (clean layout) - -Test 2: Truncation -Input: "VERY-LONG-SAP-NUMBER-LONGER|Qty|LOT" -Result: ✓ Auto-truncated to 25 chars -Barcode: ✓ Generated successfully - -Test 3: GUI Integration -Result: ✓ All imports successful -Status: ✓ Ready to use -``` - -## Benefits of Simplified Layout - -1. **Cleaner Appearance** - - No boxes or borders - - Professional look - - More space for content - -2. **Better Barcode Visibility** - - More horizontal space - - No crowding - - Easier to scan - -3. **Simpler Code** - - Fewer drawing operations - - Faster generation - - Less error-prone - -4. **More Flexible** - - Easy to adjust spacing - - Easy to modify fonts - - Easier to extend - -## Technical Details - -### Barcode Generation -```python -barcode_height = 18 mm # Fixed -barcode_width = auto # Constrained to label width -barcode_format = Code128 -character_limit = 25 -``` - -### PDF Creation -```python -page_size = 11.5cm × 8cm -rows = 3 -row_height = ~2.67cm each -margin = 3mm -``` - -### Field Names -```python -Font: Helvetica-Bold -Size: 8pt -Position: Top of each row -``` - -## Usage - -### Command Line -```bash -python -c "from print_label import print_label_standalone; \ -print_label_standalone('SAP-123|100|LOT-ABC', 'printer_name')" -``` - -### Python Script -```python -from print_label import create_label_pdf - -pdf_file = create_label_pdf("SAP-123|100|LOT-ABC") -print(f"Generated: {pdf_file}") -``` - -### GUI Application -```bash -python label_printer_gui.py -# Enter data and click Print -``` - -## Barcode Quality - -- **Format:** Code128 (professional standard) -- **Height:** 18mm (easily scannable) -- **Width:** Auto-fit to label (no overflow) -- **Module Width:** 0.5mm (optimal for 300 DPI) -- **Quiet Zone:** 2mm (maintained automatically) - -## Performance - -| Metric | Value | -|--------|-------| -| PDF Generation | 200-500ms | -| File Size | ~1.6 KB | -| Barcode Height | 18mm ✓ | -| Character Limit | 25 chars ✓ | -| Layout Simplicity | High ✓ | - -## Verification Checklist - -- [x] PDF generation works -- [x] No borders in layout -- [x] Barcode height is 18mm -- [x] Fields display correctly -- [x] Character limit enforced -- [x] GUI imports successfully -- [x] All tests passed -- [x] System is production-ready - -## Print Settings Recommended - -- **Printer DPI:** 300+ -- **Paper Size:** 11.5cm × 8cm (custom) -- **Margins:** Borderless if available -- **Color Mode:** Monochrome/Black & White -- **Quality:** Best available - -## Troubleshooting - -### Barcode Not Visible -- Check printer DPI (300+ required) -- Verify PDF viewer supports images -- Try borderless printing mode - -### Text Overlapping -- This shouldn't happen (simplified layout) -- Check if fields are too long (truncate to 25 chars) - -### PDF Won't Print -- Check CUPS configuration -- Verify printer supports PDF -- Check printer connection - -## Summary - -The label printing system now has: -- ✓ Simplified, clean layout (no borders) -- ✓ Fixed 18mm barcode height -- ✓ 25-character limit per field -- ✓ 11.5cm × 8cm label size -- ✓ 300 DPI print quality -- ✓ Professional appearance - -**Status:** ✓ **PRODUCTION READY** - -All tests passed. System is ready for deployment and use. diff --git a/documentation/TECHNICAL_DOCS.md b/documentation/TECHNICAL_DOCS.md deleted file mode 100644 index 90cbb3b..0000000 --- a/documentation/TECHNICAL_DOCS.md +++ /dev/null @@ -1,390 +0,0 @@ -# Technical Documentation - Label Printer GUI - -## Architecture Overview - -### Component Structure - -``` -label_printer_gui.py -├── LabelPreviewWidget (ScatterLayout) -│ ├── update_preview(text) -│ ├── display_preview() -│ └── Displays PIL image as Kivy widget -│ -└── LabelPrinterApp (App) - ├── build() → Main UI layout - ├── create_input_column() → Left side form - ├── create_preview_column() → Right side preview - ├── get_available_printers() → CUPS integration - ├── on_input_change() → Live preview update - ├── print_label() → Print workflow - └── show_popup() → User notifications -``` - -### Data Flow - -``` -User Input (TextInput) - ↓ -on_input_change() event - ↓ -Combine fields: f"{sap}|{qty}|{cable_id}" - ↓ -create_label_image() from print_label.py - ↓ -LabelPreviewWidget.update_preview() - ↓ -Display in right column -``` - -## Class Details - -### LabelPreviewWidget - -**Purpose:** Display real-time label preview - -**Methods:** -- `update_preview(text)` - Create new label image from text -- `display_preview()` - Render image in Kivy widget - -**Attributes:** -- `label_image` - Current PIL Image object -- `temp_preview_path` - Temporary PNG file path - -**Key Features:** -- Uses PIL to generate labels at 300 DPI -- Displays in KivyImage widget -- Maintains aspect ratio (11.5cm × 8cm) -- Auto-updates on input change - -### LabelPrinterApp - -**Purpose:** Main application orchestrator - -**Methods:** - -| Method | Purpose | -|--------|---------| -| `build()` | Construct main UI layout | -| `create_input_column()` | Build left form panel | -| `create_preview_column()` | Build right preview panel | -| `get_available_printers()` | Fetch CUPS printer list | -| `on_input_change()` | Handle input updates | -| `print_label()` | Execute print workflow | -| `show_popup()` | Display notifications | - -**Event Flow:** - -1. **Initialization:** - ``` - __init__() → get_available_printers() - → build() - → create_input_column() - → create_preview_column() - ``` - -2. **User Interaction:** - ``` - TextInput.on_text → on_input_change() - → preview_widget.update_preview() - ``` - -3. **Printing:** - ``` - Button.on_press → print_label() - → threading.Thread(print_thread) - → print_label_standalone() - → show_popup() - ``` - -## Integration with print_label.py - -### Functions Used - -```python -from print_label import create_label_image, print_label_standalone -``` - -**create_label_image(text)** -- Input: Combined text (e.g., "SAP123|50|REEL001") -- Output: PIL Image (11.5cm × 8cm @ 300 DPI) -- Generates Code128 barcode -- Centers text below barcode - -**print_label_standalone(value, printer, preview)** -- Input: - - `value`: Text to encode in barcode - - `printer`: CUPS printer name (e.g., "PDF") - - `preview`: 0=no preview, 1-3=3s, >3=5s -- Output: Boolean (True=success) -- Handles CUPS printing -- Manages temporary files - -## UI Layout Structure - -### Main Layout -``` -BoxLayout (horizontal) -├── Left Column (40%) -│ BoxLayout (vertical) -│ ├── Title Label -│ ├── ScrollView -│ │ └── GridLayout (1 col) -│ │ ├── Label: "SAP-Nr. Articol" -│ │ ├── TextInput (sap_input) -│ │ ├── Label: "Cantitate" -│ │ ├── TextInput (qty_input) -│ │ ├── Label: "ID rola cablu" -│ │ ├── TextInput (cable_id_input) -│ │ ├── Label: "Select Printer" -│ │ └── Spinner (printer_spinner) -│ └── Button: "PRINT LABEL" -│ -└── Right Column (60%) - BoxLayout (vertical) - ├── Title Label - └── LabelPreviewWidget -``` - -### Styling - -**Colors:** -- Print Button: `(0.2, 0.6, 0.2, 1)` - Green -- Background: Default Kivy theme -- Text: Black on white/gray - -**Fonts:** -- Title: 18sp, bold -- Labels: 14sp, regular -- Input: 16sp, regular - -**Sizing:** -- Window: 1600×900 (adjustable) -- Left column: 40% of width -- Right column: 60% of width - -## Threading Model - -### Background Printing - -```python -def print_label(self, instance): - # ... validation ... - - popup = Popup(...) # Show loading - popup.open() - - def print_thread(): - try: - success = print_label_standalone(...) - # Update UI in main thread - popup.dismiss() - self.show_popup(...) - except Exception as e: - # Error handling - self.show_popup("Error", str(e)) - - thread = threading.Thread(target=print_thread) - thread.daemon = True - thread.start() -``` - -**Why threading?** -- Prevents UI freezing during print -- CUPS operations can be slow -- User can continue working while printing - -## Error Handling - -### Validation - -1. **Input Validation:** - ```python - if not sap_nr and not quantity and not cable_id: - show_popup("Error", "Please enter at least one field") - ``` - -2. **Printer Validation:** - - Fallback to "PDF" if none available - - Checks printer existence before print - -3. **Exception Handling:** - - Try-except in preview generation - - Try-except in print thread - - User-friendly error messages - -### Logging - -- Console output for debugging -- Error messages in popups -- Exception info in thread callbacks - -## Performance Considerations - -### Preview Updates - -- Only regenerates label when text changes -- Debouncing happens naturally via Kivy events -- PIL image operations are fast (~100ms) - -### Memory Management - -- Temporary files auto-deleted -- PIL images cached during preview -- Temp preview file cleaned when updated - -### CUPS Operations - -- Non-blocking via threading -- Timeout handling for printer ops -- Connection pooled by pycups - -## Customization Guide - -### Change Label Size - -In `print_label.py`: -```python -# Modify label dimensions -label_width = 1063 # pixels for 9cm @ 300 DPI -label_height = 591 # pixels for 5cm @ 300 DPI -``` - -For 11.5cm × 8cm @ 300 DPI: -```python -label_width = 1378 # 11.5cm @ 300 DPI -label_height = 944 # 8cm @ 300 DPI -``` - -### Modify UI Colors - -In `label_printer_gui.py`: -```python -# Change print button color -Button( - ... - background_color=(R, G, B, A), # RGBA: 0.0-1.0 - ... -) -``` - -### Add New Input Fields - -```python -# In create_input_column(): -new_label = Label(text='New Field:', size_hint_y=None, height=40) -form_layout.add_widget(new_label) - -self.new_input = TextInput(...) -self.new_input.bind(text=self.on_input_change) -form_layout.add_widget(self.new_input) - -# In on_input_change(): -new_field = self.new_input.text -``` - -## Dependencies Deep Dive - -### Kivy -- **Version:** 2.0+ -- **Role:** GUI framework -- **Key classes:** App, BoxLayout, TextInput, Button, Spinner - -### python-barcode -- **Version:** Latest -- **Role:** Code128 barcode generation -- **Integration:** Used in print_label.py - -### Pillow (PIL) -- **Version:** 8.0+ -- **Role:** Image generation and processing -- **Features:** ImageDraw for text, Image for resizing - -### pycups -- **Version:** Latest -- **Role:** CUPS printer interface -- **Functions:** getPrinters(), printFile() - -## Testing - -### Unit Test Example - -```python -def test_label_preview_update(): - app = LabelPrinterApp() - test_text = "TEST|123|REEL" - app.preview_widget.update_preview(test_text) - assert app.preview_widget.label_image is not None - -def test_printer_list(): - app = LabelPrinterApp() - printers = app.get_available_printers() - assert isinstance(printers, list) - assert len(printers) > 0 -``` - -### Manual Testing - -1. **Preview Update Test:** - - Type in each field - - Verify preview updates - - Check barcode changes - -2. **Printer Test:** - - Select different printers - - Verify dropdown updates - -3. **Print Test:** - - Use PDF printer for testing - - Check output file generated - -## Deployment Notes - -### System Requirements -- Linux/Unix (CUPS-based) -- X11 or Wayland display -- ~50MB disk space -- 2GB RAM minimum - -### Installation Steps -1. Clone/download repository -2. Install Python 3.7+ -3. Run setup_and_run.py -4. Configure system printer - -### Containerization - -For Docker deployment: -```dockerfile -FROM python:3.9-slim -RUN apt-get update && apt-get install -y cups -COPY . /app -WORKDIR /app -RUN pip install -r requirements_gui.txt -CMD ["python3", "label_printer_gui.py"] -``` - -## Future Enhancements - -1. **Database Integration** - - Store label history - - Batch printing from CSV - -2. **Label Templates** - - Multiple label formats - - Custom field layouts - -3. **Advanced Features** - - QR code support - - Image/logo inclusion - - Multi-language support - -4. **Mobile Integration** - - REST API server - - Web interface - ---- - -**Last Updated:** February 4, 2026 -**Version:** 1.0 -**Status:** Production Ready diff --git a/documentation/TESTING_SUMMARY.txt b/documentation/TESTING_SUMMARY.txt deleted file mode 100644 index 9607df3..0000000 --- a/documentation/TESTING_SUMMARY.txt +++ /dev/null @@ -1,199 +0,0 @@ -╔══════════════════════════════════════════════════════════════════════════════╗ -║ ║ -║ LABEL PRINTER APPLICATION - TEST SUMMARY ║ -║ ║ -╚══════════════════════════════════════════════════════════════════════════════╝ - -DATE: February 4, 2026 -STATUS: ✅ ALL CORE FUNCTIONALITY WORKING - -━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - -TEST RESULTS SUMMARY -━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - -Functional Tests (test_functional.py): - ✅ TEST 1: Module Imports [PASS] - ✅ TEST 2: Label Image Generation [PASS] - ✅ TEST 3: Printer Detection [PASS] - ✅ TEST 4: Save Label to File [PASS] - ✅ TEST 5: Data Format Testing [PASS] - - RESULT: 5/5 tests PASSED ✅ - -Demonstration Tests (demo_usage.py): - ✅ DEMO 1: Create Label Image [PASS] - ✅ DEMO 2: Print Label (Simulated) [PASS] - ✅ DEMO 3: Create Multiple Labels [PASS] - - RESULT: All demonstrations successful ✅ - -━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - -COMPONENT STATUS -━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - -Core Printing Engine: - ✅ Label image generation - ✅ Barcode generation (Code128) - ✅ Image file output (PNG) - ✅ Data formatting and combining - ✅ Error handling and validation - ✅ File I/O operations - ✅ Temporary file cleanup - -CUPS Integration: - ✅ Printer detection - ✅ Printer listing - ✅ Print file operations - ⚠️ No printers configured (PDF available for testing) - -GUI Application: - ✅ Code implementation complete - ✅ All layouts and widgets defined - ✅ Event handling functional - ✅ Preview system implemented - ⚠️ Graphics display issue (system-level, not code issue) - -API Functions: - ✅ create_label_image() - Working - ✅ print_label_standalone() - Working - ✅ Integration-ready - ✅ Well-documented - -━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - -ISSUES FOUND & RESOLVED -━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - -Issue 1: Tkinter Not Available ❌ → ✅ FIXED - Problem: print_label.py imported ImageTk/tkinter - Solution: Removed GUI framework dependency - Result: Application now works without tkinter - -Issue 2: Graphics Driver Problems ⚠️ → ℹ️ DOCUMENTED - Problem: Kivy GUI crashes on this system - Cause: System-level graphics driver issue - Status: Not an application issue, expected on headless systems - Solution: Deploy on systems with proper X11/graphics support - Workaround: Use API functions directly - -━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - -WHAT WORKS ✅ -━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - -Creating Labels: - ✅ Single labels - ✅ Batch labels - ✅ Complex data formatting - ✅ Long strings - ✅ Special characters - -Printing: - ✅ CUPS integration - ✅ Printer detection - ✅ File generation - ✅ Error handling - -API Usage: - ✅ Import modules - ✅ Generate images - ✅ Save files - ✅ Integration with other apps - -━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - -VERIFICATION COMMANDS -━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - -Run these commands to verify: - - # Test all functionality - $ python3 test_functional.py - - # Run functional demo - $ python3 demo_usage.py - - # Validate project - $ python3 validate_project.py - - # Check git status - $ git log --oneline -3 - -Expected Results: - ✅ test_functional.py: 5/5 tests PASS - ✅ demo_usage.py: All demos complete successfully - ✅ validate_project.py: All files present - ✅ git: Latest commits visible - -━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - -DEPLOYMENT READINESS -━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - -API/Headless Mode: ✅ READY - Use: print_label_standalone() and create_label_image() - Status: Fully tested and functional - -Command-Line Mode: ✅ READY - Use: Python scripts or CLI wrapper - Status: Fully tested and functional - -GUI Mode: ✅ CODE READY - Use: label_printer_gui.py - Status: Code complete, needs compatible display system - Deployment: Ready for systems with graphics support - -Production: ✅ READY - Status: All core components tested and verified - Requirements: Hardware printer, display (GUI), or headless usage - -━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - -USAGE EXAMPLES -━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - -# Python API Usage -from print_label import create_label_image, print_label_standalone - -# Generate label -image = create_label_image("SAP123|50|REEL001") -image.save("my_label.png") - -# Print to printer -success = print_label_standalone( - value="SAP123|50|REEL001", - printer="PDF", - preview=0 -) - -# Command-line test -python3 -c " -from print_label import create_label_image -img = create_label_image('TEST|100|REEL') -img.save('output.png') -print('Label created: output.png') -" - -━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - -CONCLUSION -━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - -✅ ALL TESTS PASSED -✅ CORE FUNCTIONALITY VERIFIED -✅ READY FOR PRODUCTION - -The Label Printer application is fully functional and ready for deployment. -All core printing, label generation, and data processing features are working. - -The GUI requires a system with proper graphics support, but the underlying -API is production-ready for immediate use. - -━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - -Test Date: February 4, 2026 -Repository: https://gitea.moto-adv.com/ske087/label_printer.git -Status: ✅ PRODUCTION READY - diff --git a/documentation/TEST_REPORT.md b/documentation/TEST_REPORT.md deleted file mode 100644 index d96eeb6..0000000 --- a/documentation/TEST_REPORT.md +++ /dev/null @@ -1,271 +0,0 @@ -# Testing Report - Label Printer Application - -**Date:** February 4, 2026 -**Status:** ✅ **FULLY FUNCTIONAL** - ---- - -## Executive Summary - -The Label Printer application has been **successfully implemented and tested**. All core functionality is operational and ready for production use. - -### Test Results - -| Component | Status | Notes | -|-----------|--------|-------| -| Module Imports | ✅ PASS | All dependencies available | -| Label Generation | ✅ PASS | Barcode creation working | -| Image File Output | ✅ PASS | PNG files generated correctly | -| Data Formatting | ✅ PASS | Multiple data formats supported | -| Printer Detection | ✅ PASS | CUPS integration functional | -| **GUI Application** | ⚠️ LIMITED | Graphics driver issues on this system | -| **API Functions** | ✅ PASS | Ready for integration | - ---- - -## Test Results Details - -### ✅ Test 1: Module Imports -``` -✓ PIL - Image processing -✓ barcode - Barcode generation -✓ cups - Printer interface -✓ print_label - Label printing module -``` -**Result:** All modules import successfully - -### ✅ Test 2: Label Image Generation -``` -✓ Generated label for: 'SAP123' - Size: (1063, 591) -✓ Generated label for: 'SAP456|100' - Size: (1063, 591) -✓ Generated label for: 'SAP789|50|REEL001' - Size: (1063, 591) -``` -**Result:** Label generation working at any data complexity - -### ✅ Test 3: Printer Detection -``` -⚠ No printers configured (will use PDF) -``` -**Result:** CUPS integration ready, PDF printer available for testing - -### ✅ Test 4: Save Label to File -``` -✓ Label saved successfully - - File: /tmp/tmpvkuc_fzh.png - - Size: 15,769 bytes - - Cleaned up temporary file -``` -**Result:** File I/O operations working correctly - -### ✅ Test 5: Data Format Testing -``` -✓ SAP only - OK -✓ SAP + Quantity - OK -✓ SAP + Quantity + Cable ID - OK -✓ Complex format - OK -✓ Long string - OK -``` -**Result:** All data format combinations supported - -### ⚠️ GUI Test (Graphics Issue) - -**Finding:** The Kivy GUI requires X11/graphics drivers that are not properly configured on this system. This is a **system-level graphics driver issue**, not an application issue. - -**Status:** GUI code is correct and ready for deployment on systems with proper graphics support. - ---- - -## Fixes Applied During Testing - -### 1. Removed Tkinter Dependency ✅ -- **Issue:** Original `print_label.py` imported `tkinter` which was not available -- **Solution:** Removed `ImageTk` and `tkinter` imports -- **Result:** Application now works without GUI framework dependencies - -### 2. Simplified Preview Function ✅ -- **Issue:** Preview required Tkinter windows -- **Solution:** Replaced with command-line countdown timer -- **Result:** Preview functionality works in headless/CLI mode - -### 3. Fixed Import Statements ✅ -- **Issue:** Unused tkinter imports were breaking functionality -- **Solution:** Removed all tkinter references -- **Result:** Clean imports, no dependency conflicts - ---- - -## What Works ✅ - -### Core Printing Functions -```python -# Create label image -from print_label import create_label_image -image = create_label_image("SAP123|50|REEL001") -image.save("my_label.png") - -# Print to printer -from print_label import print_label_standalone -success = print_label_standalone( - value="SAP123|50|REEL001", - printer="PDF", - preview=0 -) -``` - -### Features Tested & Working -- ✅ Barcode generation (Code128 format) -- ✅ Label image creation (1063×591 pixels @ 300 DPI) -- ✅ Data combining (SAP|QTY|CABLE_ID) -- ✅ File output (PNG format) -- ✅ Printer detection (CUPS integration) -- ✅ Multiple label batches -- ✅ Error handling -- ✅ File cleanup - -### Data Formats Supported -- ✅ Simple text: `"DATA"` -- ✅ SAP + Quantity: `"SAP123|50"` -- ✅ Full format: `"SAP123|50|REEL001"` -- ✅ Complex values: `"SPEC-123|999|CABLE-X"` -- ✅ Long strings: Multi-character barcodes - ---- - -## What Needs System Configuration ⚠️ - -### GUI Application -- **Status:** Code is correct, ready to deploy -- **Limitation:** This specific system has graphics driver issues -- **Solution:** - - Deploy on system with proper X11/graphics drivers - - Or use the Python API directly (recommended) - - Or access GUI remotely via X11 forwarding - -### Printer Configuration -- **Status:** CUPS integration ready -- **Current:** PDF printer available for testing -- **Next:** Configure actual hardware printer on this system - ---- - -## System Information - -``` -OS: Linux -Python: 3.13.5 -Kivy: 2.3.1 -Pillow: 12.1.0 -python-barcode: Latest -pycups: Latest -Display: :1 (Available) -Disk Status: Root full, /srv has 194GB free -``` - ---- - -## Files Created for Testing - -| File | Purpose | -|------|---------| -| `test_functional.py` | Comprehensive functional tests (5/5 PASS) | -| `test_gui_simple.py` | Simple GUI component test | -| `demo_usage.py` | Functional demonstration | - ---- - -## Recommended Usage - -### For Immediate Use (API) -```bash -python3 -c " -from print_label import create_label_image -image = create_label_image('TEST|100|REEL') -image.save('label.png') -print('Label created: label.png') -" -``` - -### For GUI Use -Deploy on a system with graphics support: -```bash -python3 label_printer_gui.py -``` - -### For Integration -```python -from print_label import create_label_image, print_label_standalone - -# Generate -image = create_label_image(data) - -# Print -success = print_label_standalone(data, printer_name, preview=0) -``` - ---- - -## Test Commands - -Run these to verify functionality: - -```bash -# All tests (5/5 should pass) -python3 test_functional.py - -# Functional demo -python3 demo_usage.py - -# Check validation -python3 validate_project.py -``` - ---- - -## Known Issues & Solutions - -| Issue | Status | Solution | -|-------|--------|----------| -| GUI crashes on this system | ⚠️ EXPECTED | Graphics driver issue, not code issue | -| Root disk full | ⚠️ KNOWN | Use /srv or other partition | -| No printers configured | ℹ️ EXPECTED | Configure system printer for production | -| Tkinter missing | ✅ FIXED | Removed dependency | - ---- - -## Deployment Checklist - -- [x] Code implemented -- [x] Core functionality tested -- [x] Dependencies installed -- [x] Printing API verified -- [x] Label generation verified -- [x] Error handling tested -- [ ] Graphics driver fixed (requires system admin) -- [ ] Production printer configured (requires hardware setup) -- [ ] GUI deployed to compatible system - ---- - -## Conclusion - -**✅ The Label Printer application is fully functional and ready for production use.** - -### Status Summary -- **Core functionality:** ✅ 100% operational -- **Testing:** ✅ 5/5 tests pass -- **API:** ✅ Ready for integration -- **GUI:** ✅ Code ready, awaiting compatible display system -- **Documentation:** ✅ Comprehensive -- **Code quality:** ✅ Production-ready - -### Next Steps -1. Deploy on system with graphics support for GUI -2. Configure production printer -3. Integrate API into applications as needed -4. Monitor and maintain - ---- - -**Test Date:** February 4, 2026 -**Tested By:** Automated Test Suite -**Approval Status:** ✅ READY FOR PRODUCTION diff --git a/documentation/TEST_RESULTS_PDF_SYSTEM.md b/documentation/TEST_RESULTS_PDF_SYSTEM.md deleted file mode 100644 index f4d58c0..0000000 --- a/documentation/TEST_RESULTS_PDF_SYSTEM.md +++ /dev/null @@ -1,231 +0,0 @@ -# PDF Label Generation System - Test Results - -**Date:** February 5, 2026 -**Status:** ✓ **ALL TESTS PASSED** - -## Environment Setup - -``` -Python Version: 3.13.5 -Virtual Environment: /srv/Label-design/venv -``` - -### Installed Packages -- ✓ python-barcode 0.16.1 -- ✓ pillow 12.1.0 -- ✓ pycups 2.0.4 -- ✓ kivy 2.3.1 -- ✓ reportlab 4.4.9 (newly installed) - -## Test Results - -### 1. Basic PDF Generation ✓ -``` -Test: create_label_pdf("TEST-SAP|100|LOT123") -Result: Generated final_label_20260205_000537.pdf -Size: 8.2 KB -Status: ✓ PASS -``` - -### 2. PNG Fallback Format ✓ -``` -Test: print_label_standalone(..., use_pdf=False) -Result: Generated final_label.png (19 KB) -Status: ✓ PASS -``` - -### 3. PDF Format (Recommended) ✓ -``` -Test: print_label_standalone(..., use_pdf=True) -Result: Generated final_label_20260205_000543.pdf (9 KB) -Status: ✓ PASS -``` - -### 4. File Size Comparison ✓ -| Format | Size | Notes | -|--------|------|-------| -| PNG | 18,669 bytes | Legacy/Fallback | -| PDF | 1,678 bytes | **91% smaller** | - -### 5. Batch Processing ✓ -``` -Test: Generated 4 labels in batch -Results: - - demo_batch_label_01.pdf - - demo_batch_label_02.pdf - - demo_batch_label_03.pdf - - demo_batch_label_04.pdf -Total Size: 6,713 bytes -Status: ✓ PASS -``` - -### 6. Custom Dimensions ✓ -``` -Test: PDFLabelGenerator(label_width=6, label_height=4, dpi=300) -Result: Generated demo_label_custom.pdf (1.7 KB) -Status: ✓ PASS -``` - -### 7. High DPI Printing ✓ -``` -Test: PDFLabelGenerator(..., dpi=600) -Result: Generated demo_label_600dpi.pdf (1.7 KB) -Status: ✓ PASS -Recommended for: Color-critical and high-volume production -``` - -### 8. GUI Integration ✓ -``` -Test: from label_printer_gui import LabelPrinterApp -Result: All imports successful -GUI Framework: Kivy 2.3.1 -OpenGL: 4.6 (Mesa Intel Iris Xe Graphics) -Status: ✓ PASS -``` - -### 9. Backward Compatibility ✓ -- ✓ PNG format still works with use_pdf=False -- ✓ Original create_label_image() function intact -- ✓ All existing code paths supported - -### 10. Error Handling ✓ -- ✓ Graceful barcode generation failures (fallback to text) -- ✓ Printer not found handled gracefully -- ✓ Files retained for fallback usage - -## Feature Testing - -### PDF Generation Features -- ✓ Multiple label rows with barcodes -- ✓ Customizable dimensions (width, height) -- ✓ Adjustable DPI (300, 600, custom) -- ✓ Barcode encoding (Code128) -- ✓ Fallback text rendering -- ✓ File naming with timestamps - -### Printing Features -- ✓ CUPS integration -- ✓ Preview mode support -- ✓ Format selection (PDF/PNG) -- ✓ Graceful error handling -- ✓ File persistence - -### GUI Features -- ✓ Input fields for SAP number, quantity, lot ID -- ✓ Real-time preview generation -- ✓ Printer selection dropdown -- ✓ Status messages and popups -- ✓ Threading for non-blocking operations - -## Performance Metrics - -| Operation | Time | Notes | -|-----------|------|-------| -| PDF Generation | ~200-500ms | Per label | -| PNG Generation | ~300-600ms | Legacy format | -| Batch (4 labels) | ~1.5s | Total time | -| File I/O | ~100ms | Average | - -## Quality Improvements - -### Before (PNG) -- Rasterized format -- Fixed resolution (300 DPI) -- File size: 18.7 KB per label -- Barcode quality: Good (acceptable) - -### After (PDF) -- Vector-based format -- Infinite scalability -- File size: 1.7 KB per label -- Barcode quality: Excellent (professional) -- **91% smaller files** -- **Better print reliability** - -## Generated Test Files - -The following test files were generated and verified: -- `final_label_20260205_000524.pdf` (1.7 KB) -- `final_label_20260205_000537.pdf` (8.2 KB) -- `final_label_20260205_000543.pdf` (9.0 KB) -- `final_label.png` (19 KB) - -All files successfully generated and verified. - -## Comprehensive Test Suite - -Run the included demo to verify all functionality: -```bash -cd /srv/Label-design -. venv/bin/activate -python demo_pdf_system.py -``` - -This demo includes: -1. Basic PDF generation -2. Custom dimensions -3. Batch processing -4. High DPI support -5. API usage examples -6. PNG vs PDF comparison - -## Compatibility Summary - -| Component | Status | Notes | -|-----------|--------|-------| -| Python 3.13 | ✓ | Fully compatible | -| ReportLab | ✓ | Installed successfully | -| Barcode Library | ✓ | Works with fallback | -| Kivy GUI | ✓ | All imports successful | -| CUPS Printing | ✓ | Properly integrated | -| File System | ✓ | Proper persistence | - -## System Ready for Production - -### ✓ Requirements Met -- [x] PDF generation implemented -- [x] High-quality barcode rendering -- [x] Improved print quality -- [x] Backward compatibility maintained -- [x] All dependencies installed -- [x] Full test coverage -- [x] Error handling robust -- [x] GUI fully functional - -### Next Steps -1. **Deploy to production** - All tests pass -2. **Train users** on PDF benefits (91% smaller, better quality) -3. **Monitor** first few printing jobs -4. **Document** any printer-specific settings needed - -## Recommendations - -1. **Use PDF by default** - Superior quality and smaller files -2. **Keep PNG option** - For legacy systems if needed -3. **Monitor printer settings** - Ensure printer supports PDF correctly -4. **Use 300 DPI** - Standard for barcode printing (default) -5. **Archive labels** - PDFs are smaller, easier to archive - -## Test Coverage - -- Unit tests: ✓ 10/10 passed -- Integration tests: ✓ 5/5 passed -- GUI tests: ✓ 8/8 passed -- Performance tests: ✓ 3/3 passed -- Compatibility tests: ✓ 4/4 passed - -**Overall Score: 100% ✓** - ---- - -## Conclusion - -The PDF-based label generation system is **fully functional**, **production-ready**, and provides **significant improvements** over the previous PNG-based system: - -- **91% file size reduction** (18.7 KB → 1.7 KB) -- **Professional print quality** (vector vs rasterized) -- **Reliable barcode scanning** (precise spacing/quiet zones) -- **Backward compatible** (PNG still supported) -- **Easy to use** (same API with optional parameters) - -**Status: APPROVED FOR PRODUCTION** ✓ diff --git a/documentation/WINDOWS_SETUP.md b/documentation/WINDOWS_SETUP.md deleted file mode 100644 index 2ac7753..0000000 --- a/documentation/WINDOWS_SETUP.md +++ /dev/null @@ -1,114 +0,0 @@ -# Label Printer GUI - Windows Setup Guide - -## Installation Steps - -### 1. Install Python -- Download Python 3.11+ from [python.org](https://www.python.org/downloads/) -- **Important**: Check "Add Python to PATH" during installation - -### 2. Create Virtual Environment -```bash -python -m venv venv -venv\Scripts\activate -``` - -### 3. Install Dependencies -```bash -pip install -r requirements_windows.txt -``` - -### 4. Optional: Windows Printer Support (pywin32) -After installing requirements, run: -```bash -python -m pip install --upgrade pywin32 -python Scripts/pywin32_postinstall.py -install -``` - -This enables native Windows printer detection. - -## Running the App - -### From Command Prompt -```bash -venv\Scripts\activate -python label_printer_gui.py -``` - -### Create Shortcut (Optional) -Create a batch file `run_app.bat`: -```batch -@echo off -call venv\Scripts\activate.bat -python label_printer_gui.py -pause -``` - -Then double-click the batch file to run the app. - -## Features - -✅ **Cross-Platform GUI** - Works on Windows, Linux, and macOS -✅ **Barcode Generation** - Automatic Code128 barcode creation -✅ **PDF Output** - High-quality PDF labels stored in `pdf_backup/` folder -✅ **Printer Support** - Automatic printer detection (Windows, Linux, macOS) -✅ **Input Validation** - 25-character limit with real-time validation -✅ **PDF Backup** - All generated labels automatically saved - -## Printer Setup - -### Windows -1. Go to Settings → Devices → Printers & Scanners -2. Add your label printer -3. Run the app - printer will be auto-detected -4. Select printer from dropdown - -### Alternative (No Printer) -- Select "PDF" option -- Labels will be saved to `pdf_backup/` folder -- Open and print from any PDF viewer - -## Troubleshooting - -### "No Printers Found" -- This is normal - select "PDF" option -- You can print PDFs manually from the backup folder -- Or install your printer driver - -### Windows Defender Warning -- Click "More info" → "Run anyway" -- This is safe - the app is open-source - -### Missing Dependencies -```bash -pip install --upgrade pip -pip install -r requirements_windows.txt -``` - -### Port Already in Use -If you get an error about ports, restart your computer or: -```bash -python -m pip uninstall -y pywin32 -python -m pip install pywin32 -``` - -## File Structure - -``` -Label-design/ -├── label_printer_gui.py # Main GUI application -├── print_label.py # Print functionality -├── print_label_pdf.py # PDF generation -├── requirements_windows.txt # Windows dependencies -├── pdf_backup/ # Stored PDF labels -├── venv/ # Virtual environment -└── documentation/ # Documentation files -``` - -## Tips - -- **Character Limit**: Each field supports up to 25 characters (barcode limit) -- **Quantity Field**: Only numbers allowed -- **PDF Backup**: All labels automatically saved with timestamp -- **Cross-Platform**: Same code runs on Windows, Linux, and macOS - -For more information, see the documentation folder. diff --git a/documentation/demo_pdf_system.py b/documentation/demo_pdf_system.py deleted file mode 100644 index c9c648a..0000000 --- a/documentation/demo_pdf_system.py +++ /dev/null @@ -1,237 +0,0 @@ -#!/usr/bin/env python3 -""" -Demo: PDF Label Generation System -Shows how to use the new PDF-based label printing system -""" - -import os -import sys - -# Add current directory to path -sys.path.insert(0, os.path.dirname(__file__)) - -from print_label_pdf import PDFLabelGenerator, create_label_pdf_file -from print_label import print_label_standalone, create_label_pdf - - -def demo_basic_pdf_generation(): - """Demo 1: Basic PDF generation""" - print("=" * 60) - print("DEMO 1: Basic PDF Label Generation") - print("=" * 60) - - # Create a simple label - pdf_file = create_label_pdf_file( - text="SAP-12345|Qty:100|LOT-ABC", - filename="demo_label_basic.pdf" - ) - - print(f"✓ Generated: {pdf_file}") - print(f"✓ File size: {os.path.getsize(pdf_file)} bytes") - print() - - -def demo_custom_dimensions(): - """Demo 2: Custom label dimensions""" - print("=" * 60) - print("DEMO 2: Custom Label Dimensions") - print("=" * 60) - - # Create generator with custom size (smaller label) - generator = PDFLabelGenerator(label_width=6, label_height=4, dpi=300) - - pdf_file = generator.create_label_pdf( - sap_nr="SAP-67890", - cantitate="Qty:250", - lot_number="LOT-XYZ", - filename="demo_label_custom.pdf" - ) - - print(f"✓ Custom 6cm × 4cm label generated") - print(f"✓ File: {pdf_file}") - print(f"✓ File size: {os.path.getsize(pdf_file)} bytes") - print() - - -def demo_batch_generation(): - """Demo 3: Batch label generation""" - print("=" * 60) - print("DEMO 3: Batch Label Generation") - print("=" * 60) - - labels_data = [ - ("SAP-001", "Qty:100", "LOT-A"), - ("SAP-002", "Qty:200", "LOT-B"), - ("SAP-003", "Qty:300", "LOT-C"), - ("SAP-004", "Qty:150", "LOT-D"), - ] - - generator = PDFLabelGenerator() - generated_files = [] - - for idx, (sap, qty, lot) in enumerate(labels_data, 1): - pdf_file = generator.create_label_pdf( - sap_nr=sap, - cantitate=qty, - lot_number=lot, - filename=f"demo_batch_label_{idx:02d}.pdf" - ) - generated_files.append(pdf_file) - print(f" [{idx}] Generated {pdf_file}") - - total_size = sum(os.path.getsize(f) for f in generated_files) - print(f"\n✓ Total: {len(generated_files)} labels generated") - print(f"✓ Combined size: {total_size} bytes") - print() - - -def demo_high_dpi(): - """Demo 4: High DPI for ultra-quality printing""" - print("=" * 60) - print("DEMO 4: High DPI Generation (600 DPI)") - print("=" * 60) - - # Create generator with higher DPI for premium printing - generator = PDFLabelGenerator(label_width=8.5, label_height=6, dpi=600) - - pdf_file = generator.create_label_pdf( - sap_nr="SAP-PREMIUM", - cantitate="Qty:500", - lot_number="LOT-PREMIUM", - filename="demo_label_600dpi.pdf" - ) - - print(f"✓ 600 DPI Ultra-quality label generated") - print(f"✓ File: {pdf_file}") - print(f"✓ File size: {os.path.getsize(pdf_file)} bytes") - print(f"✓ Use this for color-critical or high-volume production") - print() - - -def demo_api_usage(): - """Demo 5: Using the convenience API""" - print("=" * 60) - print("DEMO 5: Convenience API Usage") - print("=" * 60) - - # Method 1: Simple function - print("Method 1: Using print_label_standalone()") - print(" Usage: print_label_standalone(text, printer, preview=0, use_pdf=True)") - print() - - # Method 2: Direct PDF creation - print("Method 2: Using create_label_pdf()") - pdf_file = create_label_pdf("SAP-TEST|Qty:999|LOT-TEST") - print(f" ✓ Generated: {pdf_file}") - print() - - # Method 3: Generator class - print("Method 3: Using PDFLabelGenerator class") - print(" Usage:") - print(" generator = PDFLabelGenerator()") - print(" pdf = generator.create_label_pdf(sap_nr, qty, lot, filename)") - print() - - -def demo_comparison(): - """Demo 6: PNG vs PDF comparison""" - print("=" * 60) - print("DEMO 6: PNG vs PDF Comparison") - print("=" * 60) - - from print_label import create_label_image - - # Generate PNG - png_img = create_label_image("SAP-CMP|Qty:100|LOT-CMP") - png_file = "demo_comparison_png.png" - png_img.save(png_file) - png_size = os.path.getsize(png_file) - - # Generate PDF - pdf_file = create_label_pdf_file("SAP-CMP|Qty:100|LOT-CMP", "demo_comparison_pdf.pdf") - pdf_size = os.path.getsize(pdf_file) - - print("File Size Comparison:") - print(f" PNG: {png_size:,} bytes") - print(f" PDF: {pdf_size:,} bytes") - print(f" Savings: {png_size - pdf_size:,} bytes ({((png_size-pdf_size)/png_size)*100:.1f}%)") - print() - - print("Quality Comparison:") - print(" PNG: Rasterized, fixed resolution") - print(" PDF: Vector-based, infinite scalability") - print() - - print("Recommended Use:") - print(" ✓ Use PDF for production printing (recommended)") - print(" ✓ Use PNG for legacy systems or special cases") - print() - - -def cleanup_demo_files(): - """Clean up generated demo files""" - print("=" * 60) - print("Cleaning up demo files...") - print("=" * 60) - - demo_files = [ - "demo_label_basic.pdf", - "demo_label_custom.pdf", - "demo_batch_label_01.pdf", - "demo_batch_label_02.pdf", - "demo_batch_label_03.pdf", - "demo_batch_label_04.pdf", - "demo_label_600dpi.pdf", - "demo_comparison_png.png", - "demo_comparison_pdf.pdf", - ] - - for filename in demo_files: - if os.path.exists(filename): - os.remove(filename) - print(f" ✓ Removed {filename}") - - print("\n✓ Cleanup complete") - print() - - -if __name__ == "__main__": - print("\n") - print("╔" + "═" * 58 + "╗") - print("║" + " " * 58 + "║") - print("║" + " PDF Label Generation System - Comprehensive Demo".center(58) + "║") - print("║" + " " * 58 + "║") - print("╚" + "═" * 58 + "╝") - print("\n") - - try: - # Run all demos - demo_basic_pdf_generation() - demo_custom_dimensions() - demo_batch_generation() - demo_high_dpi() - demo_api_usage() - demo_comparison() - - # Ask about cleanup - print("\nDo you want to clean up demo files? (y/n): ", end="") - # For automated testing, auto-cleanup - cleanup_demo_files() - - print("\n" + "=" * 60) - print("✓ All demos completed successfully!") - print("=" * 60) - print("\nKey Takeaways:") - print(" 1. PDF generation is the recommended format for printing") - print(" 2. Supports custom dimensions and DPI settings") - print(" 3. File sizes are comparable to PNG with better quality") - print(" 4. Batch processing is simple and efficient") - print(" 5. Full backward compatibility with PNG option") - print("\nFor more information, see PDF_UPGRADE_GUIDE.md") - print() - - except Exception as e: - print(f"\n❌ Error during demo: {e}") - import traceback - traceback.print_exc() - sys.exit(1) diff --git a/documentation/demo_usage.py b/documentation/demo_usage.py deleted file mode 100644 index ebbf482..0000000 --- a/documentation/demo_usage.py +++ /dev/null @@ -1,153 +0,0 @@ -#!/usr/bin/env python3 -""" -Label Printer - Quick Functional Test & Printing Demo -Demonstrates printing without GUI -""" - -from print_label import create_label_image, print_label_standalone -import os - -def demo_create_label(): - """Demo: Create a label image""" - print("\n" + "=" * 70) - print("DEMO 1: Create Label Image") - print("=" * 70) - - # Example data - sap_nr = "A456789" - quantity = "50" - cable_id = "REEL-042" - - # Combine data - label_data = f"{sap_nr}|{quantity}|{cable_id}" - - print(f"\nLabel Information:") - print(f" SAP-Nr. Articol: {sap_nr}") - print(f" Cantitate: {quantity}") - print(f" ID rola cablu: {cable_id}") - print(f"\nCombined data: {label_data}") - - # Create label - print("\nGenerating label...") - image = create_label_image(label_data) - - # Save label - output_file = "demo_label.png" - image.save(output_file) - - file_size = os.path.getsize(output_file) - print(f"✓ Label created successfully!") - print(f" File: {output_file}") - print(f" Size: {image.size} (width x height)") - print(f" File size: {file_size:,} bytes") - - return output_file - -def demo_print_label(): - """Demo: Print a label""" - print("\n" + "=" * 70) - print("DEMO 2: Print Label (Simulated)") - print("=" * 70) - - sap_nr = "TEST-001" - quantity = "100" - cable_id = "DEMO-REEL" - - label_data = f"{sap_nr}|{quantity}|{cable_id}" - - print(f"\nLabel data: {label_data}") - print("\nNote: Printing is simulated (no actual printer output)") - print(" In production, use: print_label_standalone(data, printer_name, preview)") - - # Just show what would happen - print("\n✓ Would send to printer: PDF") - print("✓ Label file would be: final_label.png") - print("✓ Print format: Code128 barcode with text") - -def demo_multiple_labels(): - """Demo: Create multiple labels with different data""" - print("\n" + "=" * 70) - print("DEMO 3: Create Multiple Labels") - print("=" * 70) - - labels_data = [ - ("SAP001", "10", "REEL-1"), - ("SAP002", "20", "REEL-2"), - ("SAP003", "30", "REEL-3"), - ] - - print(f"\nCreating {len(labels_data)} label(s)...\n") - - for sap, qty, reel in labels_data: - label_data = f"{sap}|{qty}|{reel}" - image = create_label_image(label_data) - print(f"✓ {label_data:<30} - Label size: {image.size}") - - print(f"\n✓ All {len(labels_data)} labels created successfully!") - -def main(): - """Run demonstrations""" - print("\n") - print("╔" + "=" * 68 + "╗") - print("║" + " " * 68 + "║") - print("║" + "LABEL PRINTER - FUNCTIONAL DEMO".center(68) + "║") - print("║" + " " * 68 + "║") - print("╚" + "=" * 68 + "╝") - - try: - # Run demos - demo_file = demo_create_label() - demo_print_label() - demo_multiple_labels() - - # Summary - print("\n" + "=" * 70) - print("DEMO SUMMARY") - print("=" * 70) - print(""" -✓ Label image generation: WORKING -✓ Data formatting: WORKING -✓ Barcode generation: WORKING -✓ Image file output: WORKING -✓ Multiple label support: WORKING - -System Status: - - Core printing functionality: ✓ OPERATIONAL - - Label preview (GUI): ⚠ Requires X11/graphics driver fix - - Command-line usage: ✓ READY - - Printer detection: ✓ READY - - Image generation: ✓ READY - -Next Steps: - 1. Use the command-line API for label generation - 2. Integrate with your application - 3. Or fix X11 graphics and run the GUI - -Example Usage: - from print_label import create_label_image, print_label_standalone - - # Create label - image = create_label_image("DATA_HERE") - image.save("my_label.png") - - # Print to printer - success = print_label_standalone("DATA", "PrinterName", preview=0) -""") - - # Cleanup demo file - if os.path.exists(demo_file): - os.remove(demo_file) - print(f"Cleaned up: {demo_file}") - - print("=" * 70) - return 0 - - except Exception as e: - print(f"\n✗ Demo failed: {e}") - import traceback - traceback.print_exc() - return 1 - -if __name__ == '__main__': - import sys - sys.exit(main()) diff --git a/documentation/how_to.txt b/documentation/how_to.txt deleted file mode 100644 index 120d0ea..0000000 --- a/documentation/how_to.txt +++ /dev/null @@ -1,11 +0,0 @@ -install - -sudo apt-get install libcups2-dev - - -create venv or install with --breack-system-pakage - - -python -m venv label - -pip install -r requirements.txt diff --git a/documentation/readme.md b/documentation/readme.md deleted file mode 100644 index e69de29..0000000 diff --git a/documentation/reqiurements.txt b/documentation/reqiurements.txt deleted file mode 100644 index e69de29..0000000 diff --git a/documentation/requirements.txt b/documentation/requirements.txt deleted file mode 100644 index 803ce5b..0000000 --- a/documentation/requirements.txt +++ /dev/null @@ -1,5 +0,0 @@ -python-barcode -pillow -pycups -reportlab -pycups \ No newline at end of file diff --git a/documentation/requirements_windows.txt b/documentation/requirements_windows.txt deleted file mode 100644 index 8da1f24..0000000 --- a/documentation/requirements_windows.txt +++ /dev/null @@ -1,5 +0,0 @@ -python-barcode -pillow -reportlab -kivy -pywin32 diff --git a/documentation/setup_and_run.py b/documentation/setup_and_run.py deleted file mode 100644 index 6875467..0000000 --- a/documentation/setup_and_run.py +++ /dev/null @@ -1,104 +0,0 @@ -#!/usr/bin/env python3 -""" -Label Printer GUI - Setup and Launcher Script -Handles installation and execution of the Label Printer GUI application -""" - -import subprocess -import sys -import os -import shutil - -def check_python_version(): - """Check if Python version is 3.7 or higher""" - version_info = sys.version_info - if version_info.major < 3 or (version_info.major == 3 and version_info.minor < 7): - print("❌ Python 3.7 or higher required") - return False - print(f"✓ Python {version_info.major}.{version_info.minor}.{version_info.micro} found") - return True - -def check_cups(): - """Check if CUPS is installed""" - if shutil.which('lpstat'): - print("✓ CUPS found") - # Try to get printer list - try: - result = subprocess.run(['lpstat', '-p', '-d'], - capture_output=True, text=True, timeout=5) - if result.returncode == 0: - print(" Available printers:") - for line in result.stdout.strip().split('\n')[:5]: - if line: - print(f" {line}") - return True - except: - print("⚠ CUPS found but couldn't list printers") - return True - else: - print("⚠ CUPS not found. Printer functionality may be limited.") - print(" Install with: sudo apt-get install cups") - return False - -def install_dependencies(): - """Install required Python packages""" - packages = [ - 'kivy', - 'python-barcode', - 'pillow', - 'pycups' - ] - - print("Installing Python dependencies...") - try: - subprocess.check_call([sys.executable, '-m', 'pip', 'install'] + packages) - print("✓ Dependencies installed successfully") - return True - except subprocess.CalledProcessError: - print("❌ Failed to install dependencies") - return False - -def run_gui(): - """Run the GUI application""" - try: - print("\nStarting Label Printer GUI...") - print("=" * 50) - subprocess.call([sys.executable, 'label_printer_gui.py']) - return True - except Exception as e: - print(f"❌ Failed to run GUI: {e}") - return False - -def main(): - """Main setup and launcher""" - print("=" * 50) - print("Label Printer GUI - Setup & Launcher") - print("=" * 50) - print() - - # Step 1: Check Python - print("[1/4] Checking Python installation...") - if not check_python_version(): - sys.exit(1) - print() - - # Step 2: Check CUPS - print("[2/4] Checking printer service...") - check_cups() - print() - - # Step 3: Install dependencies - print("[3/4] Installing dependencies...") - if not install_dependencies(): - print("⚠ Some dependencies may not have installed") - response = input("Continue anyway? (y/n): ").lower() - if response != 'y': - sys.exit(1) - print() - - # Step 4: Run application - print("[4/4] Launching application...") - run_gui() - -if __name__ == '__main__': - main() diff --git a/documentation/start_gui.sh b/documentation/start_gui.sh deleted file mode 100644 index 55f0404..0000000 --- a/documentation/start_gui.sh +++ /dev/null @@ -1,52 +0,0 @@ -#!/bin/bash - -# Label Printer GUI - Quick Start Script -# This script sets up and runs the Label Printer GUI application - -set -e - -echo "==========================================" -echo "Label Printer GUI - Setup & Run" -echo "==========================================" -echo "" - -# Check Python installation -echo "[1/4] Checking Python installation..." -if ! command -v python3 &> /dev/null; then - echo "❌ Python 3 not found. Please install Python 3.7 or higher." - exit 1 -fi -PYTHON_VERSION=$(python3 --version | cut -d' ' -f2) -echo "✓ Python $PYTHON_VERSION found" -echo "" - -# Check CUPS -echo "[2/4] Checking CUPS (printer service)..." -if ! command -v lpstat &> /dev/null; then - echo "⚠ CUPS not found. Please install with: sudo apt-get install cups" - echo " Proceeding anyway - will use PDF printer" -else - echo "✓ CUPS found" - echo " Available printers:" - lpstat -p -d | head -5 -fi -echo "" - -# Install dependencies -echo "[3/4] Installing Python dependencies..." -if [ -f "requirements_gui.txt" ]; then - pip install -r requirements_gui.txt - echo "✓ Dependencies installed" -else - echo "⚠ requirements_gui.txt not found" - echo " Installing Kivy and related packages manually..." - pip install kivy python-barcode pillow pycups -fi -echo "" - -# Run the application -echo "[4/4] Starting Label Printer GUI..." -echo "==========================================" -echo "" -python3 label_printer_gui.py - diff --git a/documentation/test_functional.py b/documentation/test_functional.py deleted file mode 100644 index b2916de..0000000 --- a/documentation/test_functional.py +++ /dev/null @@ -1,205 +0,0 @@ -#!/usr/bin/env python3 -""" -Test Label Printer - Non-GUI Tests -Tests printing functionality without GUI/graphics -""" - -import os -import sys - -def test_module_imports(): - """Test that all required modules can be imported""" - print("=" * 60) - print("TEST 1: Module Imports") - print("=" * 60) - - modules = { - 'PIL': 'Image processing', - 'barcode': 'Barcode generation', - 'cups': 'Printer interface', - 'print_label': 'Label printing module' - } - - all_ok = True - for module, description in modules.items(): - try: - __import__(module) - print(f"✓ {module:<20} - {description}") - except ImportError as e: - print(f"✗ {module:<20} - FAILED: {e}") - all_ok = False - - return all_ok - -def test_label_generation(): - """Test label image generation""" - print("\n" + "=" * 60) - print("TEST 2: Label Image Generation") - print("=" * 60) - - try: - from print_label import create_label_image - - test_cases = [ - "SAP123", - "SAP456|100", - "SAP789|50|REEL001" - ] - - for test_text in test_cases: - image = create_label_image(test_text) - print(f"✓ Generated label for: '{test_text}' - Size: {image.size}") - - return True - except Exception as e: - print(f"✗ Label generation failed: {e}") - import traceback - traceback.print_exc() - return False - -def test_printer_detection(): - """Test printer detection""" - print("\n" + "=" * 60) - print("TEST 3: Printer Detection") - print("=" * 60) - - try: - import cups - - conn = cups.Connection() - printers = conn.getPrinters() - - if printers: - print(f"✓ Found {len(printers)} printer(s):") - for name, details in list(printers.items())[:5]: - status = details.get('printer-state', 'unknown') - print(f" - {name:<30} (State: {status})") - else: - print("⚠ No printers configured (will use PDF)") - - return True - except Exception as e: - print(f"✗ Printer detection failed: {e}") - return False - -def test_save_label(): - """Test saving label to file""" - print("\n" + "=" * 60) - print("TEST 4: Save Label to File") - print("=" * 60) - - try: - from print_label import create_label_image - import tempfile - - # Create test label - test_text = "TEST_LABEL|123|REEL" - image = create_label_image(test_text) - - # Save to temporary file - with tempfile.NamedTemporaryFile(suffix='.png', delete=False) as tmp: - image.save(tmp.name) - tmp_path = tmp.name - - # Check if file exists and has content - file_size = os.path.getsize(tmp_path) - print(f"✓ Label saved successfully") - print(f" - File: {tmp_path}") - print(f" - Size: {file_size:,} bytes") - - # Clean up - os.remove(tmp_path) - print(f" - Cleaned up temporary file") - - return True - except Exception as e: - print(f"✗ Save label test failed: {e}") - import traceback - traceback.print_exc() - return False - -def test_data_formats(): - """Test different data format combinations""" - print("\n" + "=" * 60) - print("TEST 5: Data Format Testing") - print("=" * 60) - - try: - from print_label import create_label_image - - test_formats = [ - ("A012345", "SAP only"), - ("A012345|50", "SAP + Quantity"), - ("A012345|50|REEL001", "SAP + Quantity + Cable ID"), - ("SPEC-123|999|CABLE-X", "Complex format"), - ("123456789012345678901234567890", "Long string"), - ] - - for data, description in test_formats: - try: - image = create_label_image(data) - print(f"✓ {description:<30} - OK") - except Exception as e: - print(f"✗ {description:<30} - FAILED: {e}") - return False - - return True - except Exception as e: - print(f"✗ Data format test failed: {e}") - return False - -def main(): - """Run all tests""" - print("\n") - print("╔" + "=" * 58 + "╗") - print("║" + " " * 58 + "║") - print("║" + " LABEL PRINTER - FUNCTIONAL TESTS".center(58) + "║") - print("║" + " " * 58 + "║") - print("╚" + "=" * 58 + "╝") - print() - - tests = [ - ("Module Imports", test_module_imports), - ("Label Generation", test_label_generation), - ("Printer Detection", test_printer_detection), - ("Save Label to File", test_save_label), - ("Data Format Testing", test_data_formats), - ] - - results = [] - for test_name, test_func in tests: - try: - result = test_func() - results.append((test_name, result)) - except Exception as e: - print(f"\n✗ Test '{test_name}' crashed: {e}") - results.append((test_name, False)) - - # Summary - print("\n" + "=" * 60) - print("TEST SUMMARY") - print("=" * 60) - - passed = sum(1 for _, result in results if result) - total = len(results) - - for test_name, result in results: - status = "✓ PASS" if result else "✗ FAIL" - print(f"{status} - {test_name}") - - print() - print(f"Results: {passed}/{total} tests passed") - print() - - if passed == total: - print("✓ ALL TESTS PASSED! System is ready to use.") - print("\nNext steps:") - print(" 1. Fix graphics driver issue for GUI display") - print(" 2. Or use the printing API directly in your code") - return 0 - else: - print("✗ Some tests failed. Please review the output above.") - return 1 - -if __name__ == '__main__': - sys.exit(main()) diff --git a/documentation/test_gui_simple.py b/documentation/test_gui_simple.py deleted file mode 100644 index 7bdbeb7..0000000 --- a/documentation/test_gui_simple.py +++ /dev/null @@ -1,88 +0,0 @@ -#!/usr/bin/env python3 -""" -Simple test to verify GUI components work -""" - -print("Testing Label Printer GUI components...") -print() - -# Test 1: Import modules -print("[1/5] Testing imports...") -try: - from kivy.app import App - from kivy.uix.boxlayout import BoxLayout - from kivy.uix.label import Label - from kivy.uix.textinput import TextInput - from kivy.uix.button import Button - print("✓ Kivy imports successful") -except Exception as e: - print(f"✗ Kivy import failed: {e}") - exit(1) - -# Test 2: Import printing modules -print() -print("[2/5] Testing printing module...") -try: - from print_label import create_label_image, print_label_standalone - print("✓ Printing module imports successful") -except Exception as e: - print(f"✗ Printing module import failed: {e}") - exit(1) - -# Test 3: Test label image generation -print() -print("[3/5] Testing label image generation...") -try: - test_text = "TEST|123|REEL001" - image = create_label_image(test_text) - print(f"✓ Label image created: {image.size}") -except Exception as e: - print(f"✗ Label image generation failed: {e}") - exit(1) - -# Test 4: Test printer detection -print() -print("[4/5] Testing printer detection...") -try: - import cups - conn = cups.Connection() - printers = conn.getPrinters() - printer_list = list(printers.keys()) if printers else [] - if printer_list: - print(f"✓ Printers found: {', '.join(printer_list[:3])}") - else: - print("⚠ No printers found (will use PDF)") -except Exception as e: - print(f"✗ Printer detection failed: {e}") - -# Test 5: Create simple test app -print() -print("[5/5] Creating test application...") -try: - class TestApp(App): - def build(self): - layout = BoxLayout(orientation='vertical', padding=10, spacing=10) - layout.add_widget(Label(text='Label Printer GUI Test', size_hint_y=0.2)) - layout.add_widget(Label(text='✓ All components loaded successfully!', size_hint_y=0.3)) - btn = Button(text='Close', size_hint_y=0.2) - btn.bind(on_press=lambda x: App.get_running_app().stop()) - layout.add_widget(btn) - return layout - - print("✓ Test application created") - print() - print("=" * 60) - print("🚀 Starting test GUI (close window to continue)...") - print("=" * 60) - - app = TestApp() - app.run() - - print() - print("✓ GUI test completed successfully!") - -except Exception as e: - print(f"✗ Test application failed: {e}") - import traceback - traceback.print_exc() - exit(1) diff --git a/documentation/test_ui_features.py b/documentation/test_ui_features.py deleted file mode 100644 index 691d4af..0000000 --- a/documentation/test_ui_features.py +++ /dev/null @@ -1,107 +0,0 @@ -#!/usr/bin/env python3 -""" -Test UI Features - Validates that the GUI application components work correctly -This test verifies all the UI elements and functionality that the Kivy GUI would provide -""" - -import sys -from print_label import create_label_image, print_label_standalone - -print("╔════════════════════════════════════════════════════════════╗") -print("║ LABEL PRINTER UI - FEATURE TEST ║") -print("╚════════════════════════════════════════════════════════════╝") -print() - -# Test 1: UI Input Validation -print("[1/5] Testing UI Input Validation...") -test_inputs = [ - ("SAP123", "Basic SAP code"), - ("SAP456|100", "SAP with Quantity"), - ("SAP789|50|REEL001", "SAP with Quantity and Cable ID"), - ("", "Empty input (should handle gracefully)"), -] - -for input_val, description in test_inputs: - try: - if input_val: # Skip empty test - img = create_label_image(input_val) - print(f" ✓ {description}: '{input_val}'") - else: - print(f" ✓ {description}: Handled gracefully") - except Exception as e: - print(f" ✗ {description}: {e}") - -print() - -# Test 2: Printer Selection (UI Spinner) -print("[2/5] Testing Printer Selection (UI Spinner Component)...") -try: - import cups - conn = cups.Connection() - printers = conn.getPrinters() - printer_list = list(printers.keys()) if printers else ["PDF"] - - if printer_list: - print(f" ✓ Available printers: {', '.join(printer_list)}") - print(f" ✓ Printer selector would show {len(printer_list)} option(s)") - else: - print(f" ✓ No printers found, PDF selected as default") -except Exception as e: - print(f" ✗ Printer detection failed: {e}") - -print() - -# Test 3: Label Preview (Image Generation) -print("[3/5] Testing Label Preview (Image Generation)...") -try: - test_label = "TEST|500|CABLE1" - img = create_label_image(test_label) - print(f" ✓ Label preview generated: {img.size[0]}x{img.size[1]}px") - print(f" ✓ Preview would display in UI") -except Exception as e: - print(f" ✗ Preview generation failed: {e}") - -print() - -# Test 4: Button Functionality - Print Action -print("[4/5] Testing Button Functionality (Print Action)...") -print(" ✓ Print button would trigger print_label_standalone()") -print(" ✓ Clear button would reset input fields") -print(" ✓ Reset button would clear all selections") - -print() - -# Test 5: UI Responsiveness (Threading) -print("[5/5] Testing UI Threading (Background Operations)...") -import threading - -def simulate_print(): - """Simulate a print operation in background thread""" - try: - label_text = "ASYNC|TEST|001" - create_label_image(label_text) - return True - except: - return False - -thread = threading.Thread(target=simulate_print) -thread.start() -thread.join(timeout=5) - -if not thread.is_alive(): - print(" ✓ Background operations complete without blocking UI") - print(" ✓ Threading system ready for printing tasks") -else: - print(" ✗ Threading operation timed out") - -print() -print("╔════════════════════════════════════════════════════════════╗") -print("║ TEST SUMMARY ║") -print("╚════════════════════════════════════════════════════════════╝") -print() -print("✓ All UI features are functional and ready") -print("✓ GUI application can be launched successfully") -print() -print("Note: For full GUI testing in headless environment,") -print(" use a machine with X11 display or use:") -print(" xvfb-run -a python3 label_printer_gui.py") diff --git a/documentation/validate_project.py b/documentation/validate_project.py deleted file mode 100644 index 129a66e..0000000 --- a/documentation/validate_project.py +++ /dev/null @@ -1,158 +0,0 @@ -#!/usr/bin/env python3 -""" -Label Printer GUI - Project Validation Script -Checks if the project is properly set up and ready to run -""" - -import os -import sys -import subprocess - -def print_header(text): - print(f"\n{'='*60}") - print(f" {text}") - print(f"{'='*60}\n") - -def check_file(filepath, description): - """Check if a file exists""" - if os.path.exists(filepath): - size = os.path.getsize(filepath) - print(f"✅ {description:<40} ({size:,} bytes)") - return True - else: - print(f"❌ {description:<40} MISSING!") - return False - -def check_python(): - """Check Python version""" - version = sys.version_info - version_str = f"{version.major}.{version.minor}.{version.micro}" - - if version.major >= 3 and version.minor >= 7: - print(f"✅ Python version {version_str:<30} OK") - return True - else: - print(f"❌ Python version {version_str:<30} TOO OLD (need 3.7+)") - return False - -def check_module(module_name): - """Check if a Python module is installed""" - try: - __import__(module_name) - print(f"✅ {module_name:<40} installed") - return True - except ImportError: - print(f"⚠ {module_name:<40} not installed (will install on first run)") - return False - -def check_cups(): - """Check if CUPS is available""" - try: - result = subprocess.run(['lpstat', '-p'], - capture_output=True, text=True, timeout=5) - if result.returncode == 0: - printer_count = result.stdout.count('printer') - print(f"✅ CUPS available ({printer_count} printer(s) configured)") - return True - except: - pass - print(f"⚠ CUPS not accessible (install with: sudo apt-get install cups)") - return False - -def main(): - print_header("Label Printer GUI - Project Validation") - - all_ok = True - - # Check required files - print("📋 Checking Required Files:") - print("-" * 60) - - files_to_check = [ - ("label_printer_gui.py", "Main GUI Application"), - ("print_label.py", "Printing Engine"), - ("setup_and_run.py", "Setup Script"), - ("requirements_gui.txt", "GUI Dependencies"), - ("requirements.txt", "Original Dependencies"), - ] - - for filepath, description in files_to_check: - if not check_file(filepath, description): - all_ok = False - - # Check documentation - print("\n📚 Checking Documentation:") - print("-" * 60) - - docs_to_check = [ - ("GETTING_STARTED.md", "Quick Start Guide"), - ("README_GUI.md", "Feature Documentation"), - ("TECHNICAL_DOCS.md", "Technical Reference"), - ("FILE_GUIDE.md", "File Reference Guide"), - ("IMPLEMENTATION_SUMMARY.md", "Implementation Summary"), - ] - - for filepath, description in docs_to_check: - if not check_file(filepath, description): - all_ok = False - - # Check Python version - print("\n🐍 Checking Python Environment:") - print("-" * 60) - if not check_python(): - all_ok = False - - # Check optional modules - print("\n📦 Checking Python Modules:") - print("-" * 60) - - modules = [ - ('kivy', 'Kivy GUI Framework'), - ('PIL', 'Pillow (Image Processing)'), - ('barcode', 'Barcode Generation'), - ('cups', 'CUPS Interface'), - ] - - optional_found = False - for module_name, description in modules: - try: - __import__(module_name) - print(f"✅ {description:<40} installed") - optional_found = True - except ImportError: - print(f"⚠ {description:<40} not installed (will install on first run)") - - # Check CUPS - print("\n🖨️ Checking Printer Service:") - print("-" * 60) - check_cups() - - # Summary - print_header("Summary & Next Steps") - - if all_ok: - print("✅ All required files are present!\n") - print("🚀 Ready to run! Use one of these commands:\n") - print(" Option 1 (Recommended):") - print(" $ python3 setup_and_run.py\n") - print(" Option 2 (Manual):") - print(" $ pip install -r requirements_gui.txt") - print(" $ python3 label_printer_gui.py\n") - print(" Option 3 (Bash):") - print(" $ chmod +x start_gui.sh") - print(" $ ./start_gui.sh\n") - else: - print("⚠️ Some files might be missing or issues detected.\n") - print("👉 First run setup_and_run.py to install everything:") - print(" $ python3 setup_and_run.py\n") - - print("📖 For detailed help, read:") - print(" • GETTING_STARTED.md - Quick start guide") - print(" • README_GUI.md - Full documentation") - print(" • FILE_GUIDE.md - File reference") - print() - - return 0 if all_ok else 1 - -if __name__ == '__main__': - sys.exit(main()) diff --git a/label_printer_gui.py b/label_printer_gui.py index 5708c67..6920277 100644 --- a/label_printer_gui.py +++ b/label_printer_gui.py @@ -15,6 +15,7 @@ from kivy.uix.popup import Popup from kivy.core.window import Window from kivy.uix.image import Image as KivyImage from kivy.graphics import Color, Rectangle +from kivy.uix.filechooser import FileChooserListView import os import threading @@ -22,8 +23,14 @@ import platform import time import datetime import glob +import configparser from print_label import print_label_standalone, get_available_printers from kivy.clock import Clock +from watchdog.observers import Observer +from watchdog.events import FileSystemEventHandler +import pystray +from pystray import MenuItem as item +from PIL import Image, ImageDraw # Set window size - portrait/phone dimensions (375x667 like iPhone) # Adjusted to be slightly wider for touch-friendly UI @@ -33,8 +40,26 @@ Window.size = (420, 700) +class FileMonitorHandler(FileSystemEventHandler): + """Handler for file system events""" + + def __init__(self, app, file_path): + self.app = app + self.file_path = file_path + self.last_modified = 0 + + def on_modified(self, event): + """Called when a file is modified""" + if event.src_path == self.file_path: + # Debounce - avoid multiple triggers + current_time = time.time() + if current_time - self.last_modified > 1: # 1 second debounce + self.last_modified = current_time + Clock.schedule_once(lambda dt: self.app.on_file_changed(), 0) + + class LabelPrinterApp(App): - """Simplified Kivy application for label printing""" + """Simplified Kivy application for label printing with file monitoring""" def __init__(self, **kwargs): super().__init__(**kwargs) @@ -49,6 +74,15 @@ class LabelPrinterApp(App): display_name = full_name[:20] self.printer_display_map[display_name] = full_name self.available_printers.append(display_name) + # File monitoring variables + self.observer = None + self.monitored_file = None + self.monitoring_active = False + # Configuration file path + self.config_file = os.path.join('conf', 'app.conf') + # System tray variables + self.tray_icon = None + self.is_minimized = False # Clean old PDF backup files on startup self.cleanup_old_pdfs() # Clean old log files on startup @@ -149,14 +183,60 @@ class LabelPrinterApp(App): except Exception as e: print(f"Error during log cleanup: {e}") - def log_print_action(self, sap_nr, quantity, cable_id, printer, pdf_filename, success): + def load_config(self): + """ + Load configuration from conf/app.conf file. + Returns dict with 'file_path' and 'printer' keys. + """ + config = {'file_path': '', 'printer': ''} + + if not os.path.exists(self.config_file): + return config + + try: + parser = configparser.ConfigParser() + parser.read(self.config_file, encoding='utf-8') + + if 'Settings' in parser: + config['file_path'] = parser['Settings'].get('file_path', '') + config['printer'] = parser['Settings'].get('printer', '') + + print(f"Configuration loaded from {self.config_file}") + except Exception as e: + print(f"Error loading config: {e}") + + return config + + def save_config(self): + """ + Save current configuration to conf/app.conf file. + Saves file_path and selected printer. + """ + # Ensure conf folder exists + os.makedirs(os.path.dirname(self.config_file), exist_ok=True) + + try: + parser = configparser.ConfigParser() + parser['Settings'] = { + 'file_path': self.file_input.text.strip(), + 'printer': self.printer_spinner.text + } + + with open(self.config_file, 'w', encoding='utf-8') as f: + parser.write(f) + + print(f"Configuration saved to {self.config_file}") + except Exception as e: + print(f"Error saving config: {e}") + + def log_print_action(self, article, nr_art, serial, printer, pdf_filename, success): """ Log the print action to a CSV log file (table format). Args: - sap_nr (str): SAP article number - quantity (str): Quantity value - cable_id (str): Cable ID + article (str): Article/Comanda number + nr_art (str): Nr. Art. value + serial (str): Serial number printer (str): Printer name pdf_filename (str): Path to the generated PDF file success (bool): Whether the print was successful @@ -186,9 +266,9 @@ class LabelPrinterApp(App): # Create CSV line log_line = ( f"{timestamp},{status}," - f"{escape_csv(sap_nr)}," - f"{escape_csv(quantity)}," - f"{escape_csv(cable_id)}," + f"{escape_csv(article)}," + f"{escape_csv(nr_art)}," + f"{escape_csv(serial)}," f"{escape_csv(printer)}," f"{escape_csv(pdf_filename)}\n" ) @@ -200,7 +280,7 @@ class LabelPrinterApp(App): with open(log_filename, 'a', encoding='utf-8') as f: # Add header if file is new if not file_exists: - f.write("Timestamp,Status,SAP-Nr,Quantity,Cable ID,Printer,PDF File\n") + f.write("Timestamp,Status,Article,Nr Art,Serial No,Printer,PDF File\n") # Append log entry f.write(log_line) @@ -209,15 +289,15 @@ class LabelPrinterApp(App): print(f"Error saving log entry: {e}") def build(self): - """Build the simplified single-column UI""" - self.title = "Label Printing" + """Build the simplified file monitoring UI""" + self.title = "Label Printing - File Monitor" # Main container - single column layout main_layout = BoxLayout(orientation='vertical', spacing=8, padding=12) # Title title = Label( - text='[b]Label Printing[/b]', + text='[b]Label Printing - File Monitor[/b]', markup=True, size_hint_y=0.08, font_size='18sp', @@ -226,70 +306,56 @@ class LabelPrinterApp(App): main_layout.add_widget(title) # Scroll view for form fields - scroll = ScrollView(size_hint_y=0.75) + scroll = ScrollView(size_hint_y=0.60) form_layout = GridLayout(cols=1, spacing=8, size_hint_y=None, padding=8) form_layout.bind(minimum_height=form_layout.setter('height')) - # SAP-Nr. Articol - sap_label = Label( - text='SAP-Nr. Articol:', + # File path input + file_label = Label( + text='Monitor File Path:', size_hint_y=None, height=30, font_size='12sp' ) - form_layout.add_widget(sap_label) + form_layout.add_widget(file_label) - self.sap_input = TextInput( + # File path row with input and browse button + file_row = BoxLayout(orientation='horizontal', size_hint_y=None, height=45, spacing=5) + + self.file_input = TextInput( multiline=False, - size_hint_y=None, - height=45, - font_size='14sp', - background_color=(0.95, 0.95, 0.95, 1), - padding=(10, 10) - ) - self.sap_input.bind(text=self.on_sap_text_change) - form_layout.add_widget(self.sap_input) - - # Cantitate - qty_label = Label( - text='Cantitate:', - size_hint_y=None, - height=30, - font_size='12sp' - ) - form_layout.add_widget(qty_label) - - self.qty_input = TextInput( - multiline=False, - size_hint_y=None, - height=45, - font_size='14sp', + size_hint_x=0.75, + font_size='12sp', background_color=(0.95, 0.95, 0.95, 1), padding=(10, 10), - input_filter='int' # Only allow numbers + hint_text='Enter file path to monitor' ) - self.qty_input.bind(text=self.on_qty_text_change) - form_layout.add_widget(self.qty_input) + file_row.add_widget(self.file_input) - # ID rola cablu - cable_id_label = Label( - text='ID rola cablu:', + browse_button = Button( + text='Browse', + size_hint_x=0.25, + font_size='11sp', + background_color=(0.3, 0.5, 0.7, 1), + background_normal='' + ) + browse_button.bind(on_press=self.browse_file) + file_row.add_widget(browse_button) + + form_layout.add_widget(file_row) + + # Monitoring status + self.status_label = Label( + text='Status: Not monitoring', size_hint_y=None, height=30, - font_size='12sp' + font_size='11sp', + color=(1, 0.5, 0, 1) ) - form_layout.add_widget(cable_id_label) + form_layout.add_widget(self.status_label) - self.cable_id_input = TextInput( - multiline=False, - size_hint_y=None, - height=45, - font_size='14sp', - background_color=(0.95, 0.95, 0.95, 1), - padding=(10, 10) - ) - self.cable_id_input.bind(text=self.on_cable_id_text_change) - form_layout.add_widget(self.cable_id_input) + # Add spacing + form_layout.add_widget(Label(text='', size_hint_y=None, height=20)) # Printer selection printer_label = Label( @@ -309,55 +375,346 @@ class LabelPrinterApp(App): sync_height=True, ) self.printer_spinner = printer_spinner + # Save config when printer changes + printer_spinner.bind(text=self.on_printer_changed) form_layout.add_widget(printer_spinner) scroll.add_widget(form_layout) main_layout.add_widget(scroll) - # Print button - print_button = Button( - text='PRINT LABEL', - size_hint_y=0.15, + # Buttons layout + buttons_layout = BoxLayout(orientation='vertical', size_hint_y=0.30, spacing=5) + + # Start/Stop monitoring button + self.monitor_button = Button( + text='START MONITORING', + size_hint_y=0.7, font_size='14sp', - background_color=(0.2, 0.6, 0.2, 1), + background_color=(0.2, 0.5, 0.8, 1), background_normal='', bold=True ) - print_button.bind(on_press=self.print_label) - main_layout.add_widget(print_button) + self.monitor_button.bind(on_press=self.toggle_monitoring) + buttons_layout.add_widget(self.monitor_button) + + # Minimize to tray button + minimize_button = Button( + text='MINIMIZE TO TRAY', + size_hint_y=0.3, + font_size='11sp', + background_color=(0.5, 0.5, 0.5, 1), + background_normal='' + ) + minimize_button.bind(on_press=self.minimize_to_tray) + buttons_layout.add_widget(minimize_button) + + main_layout.add_widget(buttons_layout) + + # Load configuration after UI is built + Clock.schedule_once(lambda dt: self.apply_config(), 0.5) return main_layout - def on_sap_text_change(self, instance, value): - """Limit SAP input to 25 characters""" - if len(value) > 25: - self.sap_input.text = value[:25] + def apply_config(self): + """ + Load and apply saved configuration. + Auto-start monitoring if both file and printer are configured. + """ + config = self.load_config() + + # Apply file path + if config['file_path']: + self.file_input.text = config['file_path'] + print(f"Loaded file path: {config['file_path']}") + + # Apply printer selection + if config['printer'] and config['printer'] in self.available_printers: + self.printer_spinner.text = config['printer'] + print(f"Loaded printer: {config['printer']}") + + # Auto-start monitoring if both are configured and file exists + if config['file_path'] and config['printer']: + if os.path.exists(config['file_path']) and os.path.isfile(config['file_path']): + print("Auto-starting monitoring with saved configuration...") + self.start_monitoring() + else: + print(f"Configured file not found: {config['file_path']}") - def on_qty_text_change(self, instance, value): - """Limit Quantity input to 25 characters""" - if len(value) > 25: - self.qty_input.text = value[:25] + def on_printer_changed(self, spinner, text): + """ + Called when printer selection changes. + Save configuration. + """ + self.save_config() - def on_cable_id_text_change(self, instance, value): - """Limit Cable ID input to 25 characters""" - if len(value) > 25: - self.cable_id_input.text = value[:25] + def create_tray_icon_image(self): + """ + Create a simple icon for the system tray. + Returns PIL Image. + """ + # Create a 64x64 icon with a simple printer symbol + width = 64 + height = 64 + image = Image.new('RGB', (width, height), color='white') + draw = ImageDraw.Draw(image) + + # Draw a simple printer icon (rectangle with lines) + draw.rectangle([10, 20, 54, 40], fill='blue', outline='black', width=2) + draw.rectangle([15, 40, 49, 50], fill='lightblue', outline='black', width=2) + draw.rectangle([20, 10, 44, 20], fill='lightgray', outline='black', width=1) + + return image + + def minimize_to_tray(self, instance=None): + """ + Minimize the application to system tray. + """ + if self.is_minimized: + return + + # Hide the window + Window.hide() + self.is_minimized = True + + # Create tray icon if not exists + if not self.tray_icon: + icon_image = self.create_tray_icon_image() + + menu = pystray.Menu( + item('Restore', self.restore_from_tray), + item('Exit', self.exit_from_tray) + ) + + self.tray_icon = pystray.Icon( + 'Label Printer', + icon_image, + 'Label Printer - Monitoring', + menu + ) + + # Run tray icon in separate thread + tray_thread = threading.Thread(target=self.tray_icon.run, daemon=True) + tray_thread.start() + + def restore_from_tray(self, icon=None, item=None): + """ + Restore the application from system tray. + """ + if not self.is_minimized: + return + + # Stop tray icon + if self.tray_icon: + self.tray_icon.stop() + self.tray_icon = None + + # Show the window + Clock.schedule_once(lambda dt: Window.show(), 0) + self.is_minimized = False + + def exit_from_tray(self, icon=None, item=None): + """ + Exit the application from system tray. + """ + # Stop tray icon + if self.tray_icon: + self.tray_icon.stop() + self.tray_icon = None + + # Stop monitoring + if self.observer: + self.observer.stop() + self.observer.join() + + # Stop the app + Clock.schedule_once(lambda dt: self.stop(), 0) + + def browse_file(self, instance): + """Open file browser to select file to monitor""" + content = BoxLayout(orientation='vertical', spacing=10, padding=10) + + # File chooser + file_chooser = FileChooserListView( + path=os.path.expanduser('~'), + size_hint=(1, 0.9) + ) + content.add_widget(file_chooser) + + # Buttons + buttons = BoxLayout(size_hint_y=0.1, spacing=10) + + popup = Popup( + title='Select File to Monitor', + content=content, + size_hint=(0.9, 0.9) + ) + + def select_file(instance): + if file_chooser.selection: + self.file_input.text = file_chooser.selection[0] + # Save config when file is selected + self.save_config() + popup.dismiss() + + select_btn = Button(text='Select') + select_btn.bind(on_press=select_file) + buttons.add_widget(select_btn) + + cancel_btn = Button(text='Cancel') + cancel_btn.bind(on_press=popup.dismiss) + buttons.add_widget(cancel_btn) + + content.add_widget(buttons) + popup.open() + + def toggle_monitoring(self, instance): + """Start or stop file monitoring""" + if not self.monitoring_active: + self.start_monitoring() + else: + self.stop_monitoring() + + def start_monitoring(self): + """Start monitoring the specified file""" + file_path = self.file_input.text.strip() + + if not file_path: + self.show_popup("Error", "Please enter a file path to monitor", auto_dismiss_after=3) + return + + if not os.path.exists(file_path): + self.show_popup("Error", "File does not exist", auto_dismiss_after=3) + return + + if not os.path.isfile(file_path): + self.show_popup("Error", "Path is not a file", auto_dismiss_after=3) + return + + try: + # Stop existing observer if any + if self.observer: + self.observer.stop() + self.observer.join() + + # Create and start new observer + self.monitored_file = os.path.abspath(file_path) + event_handler = FileMonitorHandler(self, self.monitored_file) + self.observer = Observer() + self.observer.schedule(event_handler, os.path.dirname(self.monitored_file), recursive=False) + self.observer.start() + + self.monitoring_active = True + self.monitor_button.text = 'STOP MONITORING' + self.monitor_button.background_color = (0.8, 0.2, 0.2, 1) + self.status_label.text = f'Status: Monitoring {os.path.basename(file_path)}' + self.status_label.color = (0, 1, 0, 1) + + self.show_popup("Success", f"Started monitoring:\n{file_path}", auto_dismiss_after=2) + except Exception as e: + self.show_popup("Error", f"Failed to start monitoring:\n{str(e)}", auto_dismiss_after=3) + + def stop_monitoring(self): + """Stop file monitoring""" + try: + if self.observer: + self.observer.stop() + self.observer.join() + self.observer = None + + self.monitoring_active = False + self.monitor_button.text = 'START MONITORING' + self.monitor_button.background_color = (0.2, 0.5, 0.8, 1) + self.status_label.text = 'Status: Not monitoring' + self.status_label.color = (1, 0.5, 0, 1) + + self.show_popup("Success", "Stopped monitoring", auto_dismiss_after=2) + except Exception as e: + self.show_popup("Error", f"Failed to stop monitoring:\n{str(e)}", auto_dismiss_after=3) + + def on_file_changed(self): + """Called when monitored file changes""" + if not self.monitoring_active or not self.monitored_file: + return + + # Automatically print label when file changes + self.print_label(None) + + def clear_file_after_print(self): + """Clear the monitored file and write '-' to prevent re-printing""" + if not self.monitored_file or not os.path.exists(self.monitored_file): + return + + try: + with open(self.monitored_file, 'w', encoding='utf-8') as f: + f.write('-') + print(f"Cleared file: {self.monitored_file}") + except Exception as e: + print(f"Error clearing file: {e}") + + def read_file_variables(self): + """Read variables from monitored file""" + if not self.monitored_file or not os.path.exists(self.monitored_file): + return None, None, None + + try: + with open(self.monitored_file, 'r', encoding='utf-8') as f: + content = f.read().strip() + + # Skip if file is empty or only contains "-" (cleared marker) + if not content or content == '-': + return None, None, None + + # Parse file content - expecting format: article;nr_art;serial + # or key=value pairs on separate lines + lines = content.split('\n') + article = "" + nr_art = "" + serial = "" + + # Try semicolon-separated format first + if ';' in content: + parts = content.split(';') + if len(parts) >= 1: + article = parts[0].strip() + if len(parts) >= 2: + nr_art = parts[1].strip() + if len(parts) >= 3: + serial = parts[2].strip() + else: + # Try key=value format + for line in lines: + if '=' in line: + key, value = line.split('=', 1) + key = key.strip().lower() + value = value.strip() + + if key in ['article', 'articol', 'comanda', 'nr_comanda']: + article = value + elif key in ['nr_art', 'nr-art', 'nrart']: + nr_art = value + elif key in ['serial', 'serial_no', 'serial-no', 'serialno']: + serial = value + + return article, nr_art, serial + except Exception as e: + print(f"Error reading file: {e}") + return None, None, None def print_label(self, instance): - """Handle print button press""" - sap_nr = self.sap_input.text.strip() - quantity = self.qty_input.text.strip() - cable_id = self.cable_id_input.text.strip() + """Handle print button press - read from file and print""" + # Read variables from file + article, nr_art, serial = self.read_file_variables() + # Resolve display name to full printer name printer = self._get_full_printer_name(self.printer_spinner.text) # Validate input - if not sap_nr and not quantity and not cable_id: - self.show_popup("Error", "Please enter at least one field") + if not article and not nr_art and not serial: + self.show_popup("Error", "No data in file or file not set", auto_dismiss_after=3) return - # Create combined label text - label_text = f"{sap_nr}|{quantity}|{cable_id}" + # Create combined label text using semicolon separator + label_text = f"{article};{nr_art};{serial}" # Show loading popup popup = Popup( @@ -389,39 +746,39 @@ class LabelPrinterApp(App): if success: # Log the successful print action - self.log_print_action(sap_nr, quantity, cable_id, printer, pdf_filename or "unknown", True) + self.log_print_action(article, nr_art, serial, printer, pdf_filename or "unknown", True) + + # Clear the file and write "-" to prevent re-printing + Clock.schedule_once(lambda dt: self.clear_file_after_print(), 0) # Use Clock.schedule_once to update UI from main thread Clock.schedule_once(lambda dt: popup.dismiss(), 0) - Clock.schedule_once(lambda dt: self.show_popup("Success", "Label printed successfully!"), 0.1) - # Clear inputs after successful print (but keep printer selection) - Clock.schedule_once(lambda dt: self.clear_inputs(), 0.2) + Clock.schedule_once(lambda dt: self.show_popup("Success", "Label printed successfully!", auto_dismiss_after=3), 0.1) else: # Log the failed print action - self.log_print_action(sap_nr, quantity, cable_id, printer, pdf_filename or "unknown", False) + self.log_print_action(article, nr_art, serial, printer, pdf_filename or "unknown", False) Clock.schedule_once(lambda dt: popup.dismiss(), 0) - Clock.schedule_once(lambda dt: self.show_popup("Error", "Failed to print label"), 0.1) + Clock.schedule_once(lambda dt: self.show_popup("Error", "Failed to print label", auto_dismiss_after=3), 0.1) except Exception as e: # Log the error - self.log_print_action(sap_nr, quantity, cable_id, printer, pdf_filename or "unknown", False) + self.log_print_action(article, nr_art, serial, printer, pdf_filename or "unknown", False) Clock.schedule_once(lambda dt: popup.dismiss(), 0) - Clock.schedule_once(lambda dt: self.show_popup("Error", f"Print error: {str(e)}"), 0.1) + Clock.schedule_once(lambda dt: self.show_popup("Error", f"Print error: {str(e)}", auto_dismiss_after=3), 0.1) thread = threading.Thread(target=print_thread) thread.daemon = True thread.start() - def clear_inputs(self): - """Clear only the input fields, preserving printer selection""" - self.sap_input.text = '' - self.qty_input.text = '' - self.cable_id_input.text = '' - # Printer selection is NOT cleared - it persists until user changes it - - def show_popup(self, title, message): - """Show a popup message""" + def show_popup(self, title, message, auto_dismiss_after=None): + """Show a popup message + + Args: + title (str): Popup title + message (str): Popup message + auto_dismiss_after (float): Seconds after which to auto-dismiss (None = manual dismiss only) + """ popup = Popup( title=title, content=BoxLayout( @@ -439,6 +796,10 @@ class LabelPrinterApp(App): popup.content.add_widget(close_button) popup.open() + + # Auto-dismiss if specified + if auto_dismiss_after: + Clock.schedule_once(lambda dt: popup.dismiss(), auto_dismiss_after) if __name__ == '__main__': diff --git a/print_label.py b/print_label.py index 06da2ac..36552aa 100644 --- a/print_label.py +++ b/print_label.py @@ -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}") diff --git a/print_label_pdf.py b/print_label_pdf.py index 7cae50f..75481a9 100644 --- a/print_label_pdf.py +++ b/print_label_pdf.py @@ -1,116 +1,223 @@ """ PDF-based Label Printing Module -Generates high-quality PDF labels with barcodes for printing. -Uses reportlab for superior PDF generation compared to PNG rasterization. -Simplified layout: no borders, just field names and barcodes. +Generates high-quality PDF labels with image and text. +Uses reportlab for superior PDF generation. +Layout: 35mm x 25mm landscape - supports SVG templates with variable substitution. """ from reportlab.lib.pagesizes import landscape from reportlab.lib.units import cm, mm from reportlab.pdfgen import canvas -from barcode import Code128 -from barcode.writer import ImageWriter +from reportlab.graphics import renderPDF import io from PIL import Image import os import tempfile import datetime +import re +import traceback + +# SVG support +try: + from svglib.svglib import svg2rlg + SVG_AVAILABLE = True +except ImportError: + SVG_AVAILABLE = False + print("Warning: svglib not available. Install with: pip install svglib") + +try: + import cairosvg + CAIROSVG_AVAILABLE = True +except (ImportError, OSError) as e: + CAIROSVG_AVAILABLE = False + # Only show warning if it's an import error, not missing Cairo library + if isinstance(e, ImportError): + print("Warning: cairosvg not available. Install with: pip install cairosvg") class PDFLabelGenerator: - """Generate high-quality PDF labels with barcodes""" + """Generate high-quality PDF labels with image and text""" - def __init__(self, label_width=11.5, label_height=8, dpi=300): + def __init__(self, label_width=3.5, label_height=2.5, dpi=600): """ Initialize PDF label generator. Args: - label_width (float): Width in cm (default 11.5 cm) - label_height (float): Height in cm (default 8 cm) - dpi (int): DPI for barcode generation (default 300 for print quality) + label_width (float): Width in cm (default 3.5 cm = 35mm) + label_height (float): Height in cm (default 2.5 cm = 25mm) + dpi (int): DPI for image rendering (default 600 for high quality print) """ self.label_width = label_width * cm self.label_height = label_height * cm self.dpi = dpi - self.margin = 3 * mm # Minimal margin + self.margin = 1 * mm # Minimal margin - def generate_barcode_image(self, value, height_mm=18): + def load_image(self, image_path): """ - Generate barcode image from text value. + Load and prepare image for embedding in PDF. Args: - value (str): Text to encode in barcode (max 25 chars) - height_mm (int): Barcode height in mm (default 18mm for 1.8cm) + image_path (str): Path to image file Returns: - PIL.Image or None: Generated barcode image + PIL.Image or None: Loaded image """ - if not value or not value.strip(): + if not image_path or not os.path.exists(image_path): + print(f"Image not found: {image_path}") return None try: - # Truncate to 25 characters (Code128 limitation) - value_truncated = value.strip()[:25] - - # Create barcode - barcode_instance = Code128(value_truncated, writer=ImageWriter()) - - # Generate in memory using a temporary directory - temp_dir = tempfile.gettempdir() - temp_name = f"barcode_{datetime.datetime.now().strftime('%Y%m%d_%H%M%S_%f')}" - temp_base_path = os.path.join(temp_dir, temp_name) - - # Barcode options - generate at high DPI for quality - options = { - 'write_text': False, - 'module_width': 0.5, # Width of each bar in mm - 'module_height': 8, # Height in mm - 'quiet_zone': 2, - 'font_size': 0 - } - - barcode_instance.save(temp_base_path, options=options) - - # The barcode.save() adds .png extension automatically - temp_path = temp_base_path + '.png' - - # Load and return image - img = Image.open(temp_path) + img = Image.open(image_path) # Convert to RGB if needed - if img.mode != 'RGB': + if img.mode not in ['RGB', 'L']: img = img.convert('RGB') - - # Clean up temp file - try: - os.remove(temp_path) - except: - pass - return img except Exception as e: - # Log error but don't fail silently - print(f"Barcode generation error for '{value}': {e}") + print(f"Image loading error: {e}") return None - def create_label_pdf(self, sap_nr, cantitate, lot_number, filename=None): + def replace_svg_variables(self, svg_content, variables): """ - Create a PDF label with three rows of data and barcodes. - Each row shows label name, barcode, and value text. + Replace variables in SVG template with actual values. Args: - sap_nr (str): SAP article number - cantitate (str): Quantity value - lot_number (str): Lot/Cable ID + svg_content (str): SVG file content as string + variables (dict): Dictionary of variable replacements + + Returns: + str: SVG content with replaced variables + """ + # Replace placeholders like {Article}, {NrArt}, {Serial} + for key, value in variables.items(): + placeholder = f"{{{key}}}" + svg_content = svg_content.replace(placeholder, str(value or '')) + + return svg_content + + def create_label_from_svg_template(self, template_path, variables, filename=None): + """ + Create PDF label from SVG template with variable substitution. + + Args: + template_path (str): Path to SVG template file + variables (dict): Dictionary with keys: Article, NrArt, Serial filename (str): Output filename (if None, returns bytes) Returns: bytes or str: PDF content as bytes or filename if saved """ + if not os.path.exists(template_path): + print(f"SVG template not found: {template_path}") + return None + + try: + # Read SVG template + with open(template_path, 'r', encoding='utf-8') as f: + svg_content = f.read() + + # Replace variables + svg_content = self.replace_svg_variables(svg_content, variables) + + # Save modified SVG to temp file + temp_svg = tempfile.NamedTemporaryFile(mode='w', suffix='.svg', delete=False, encoding='utf-8') + temp_svg.write(svg_content) + temp_svg.close() + temp_svg_path = temp_svg.name + + # Convert SVG to PDF + if filename: + pdf_output = filename + else: + pdf_output = tempfile.NamedTemporaryFile(suffix='.pdf', delete=False).name + + # Try svglib first (more portable, no external dependencies) + if SVG_AVAILABLE: + try: + drawing = svg2rlg(temp_svg_path) + if drawing: + # Render at original size - quality depends on PDF rendering + # The PDF will contain vector graphics for sharp output + renderPDF.drawToFile(drawing, pdf_output) + + # Clean up temp SVG + try: + os.remove(temp_svg_path) + except: + pass + + if filename: + return pdf_output + else: + with open(pdf_output, 'rb') as f: + pdf_bytes = f.read() + os.remove(pdf_output) + return pdf_bytes + except Exception as svg_err: + print(f"svglib conversion failed: {svg_err}, trying cairosvg...") + + # Fallback: Try cairosvg (requires system Cairo library) + if CAIROSVG_AVAILABLE: + try: + # Render at high DPI for sharp output + cairosvg.svg2pdf(url=temp_svg_path, write_to=pdf_output, dpi=self.dpi) + # Clean up temp SVG + try: + os.remove(temp_svg_path) + except: + pass + + if filename: + return pdf_output + else: + with open(pdf_output, 'rb') as f: + pdf_bytes = f.read() + os.remove(pdf_output) + return pdf_bytes + except Exception as cairo_err: + print(f"CairoSVG conversion failed: {cairo_err}") + + print("SVG conversion failed. svglib and cairosvg both unavailable or failed.") + return None + + except Exception as e: + print(f"SVG template error: {e}") + traceback.print_exc() + return None + + def create_label_pdf(self, comanda, article, serial, filename=None, image_path=None, svg_template=None): + """ + Create a PDF label with image on left and text on right. + Label: 35mm x 25mm landscape + Layout: 1/3 left = image, 2/3 right = 3 rows of text + Or use SVG template if provided. + + Args: + comanda (str): Nr. Comanda value + article (str): Nr. Art. value + serial (str): Serial No. value + filename (str): Output filename (if None, returns bytes) + image_path (str): Path to accepted.png image + svg_template (str): Path to SVG template file (optional) + + Returns: + bytes or str: PDF content as bytes or filename if saved + """ + # If SVG template is provided, use it instead + if svg_template and os.path.exists(svg_template): + variables = { + 'Article': comanda, + 'NrArt': article, + 'Serial': serial, + 'Comanda': comanda, # Alternative name + } + return self.create_label_from_svg_template(svg_template, variables, filename) + + # Fallback to standard layout # Prepare data for rows rows_data = [ - ("SAP-Nr", sap_nr), - ("Cantitate", cantitate), - ("Lot Nr", lot_number), + ("Nr. Comanda:", comanda), + ("Nr. Art.:", article), + ("Serial No.:", serial), ] # Create PDF canvas in memory or to file @@ -122,101 +229,76 @@ class PDFLabelGenerator: # Create canvas with label dimensions c = canvas.Canvas(pdf_buffer, pagesize=(self.label_width, self.label_height)) + # Set higher resolution for better quality + c.setPageCompression(1) # Enable compression + # Calculate dimensions usable_width = self.label_width - 2 * self.margin - row_height = (self.label_height - 2 * self.margin) / 3 + usable_height = self.label_height - 2 * self.margin - # Draw each row - label name, barcode, and value text - for idx, (label_name, value) in enumerate(rows_data): - y_position = self.label_height - self.margin - (idx + 1) * row_height - - # Draw label name (small, at top of row) - c.setFont("Helvetica-Bold", 8) - c.drawString( - self.margin, - y_position + row_height - 3 * mm, - label_name - ) - - # Generate and draw barcode if value exists - if value and value.strip(): - barcode_value = value.strip()[:25] - - # Fixed barcode height: 1.6 cm (16mm) for optimal readability - barcode_height_mm = 16 - barcode_height = barcode_height_mm * mm - - try: - barcode_img = self.generate_barcode_image(barcode_value, height_mm=barcode_height_mm) + # Image area: 1/3 of width on the left + image_width = usable_width / 3 + image_x = self.margin + image_y = self.margin + image_height = usable_height + + # Text area: 2/3 of width on the right + text_area_x = self.margin + image_width + 1 * mm # Small gap + text_area_width = usable_width - image_width - 1 * mm + row_height = usable_height / 3 + + # Draw image on left if available + if image_path and os.path.exists(image_path): + try: + img = self.load_image(image_path) + if img: + # Save temp file for reportlab + temp_img_file = tempfile.NamedTemporaryFile(suffix='.png', delete=False) + temp_img_path = temp_img_file.name + temp_img_file.close() - if barcode_img: - # Calculate barcode dimensions - max_barcode_width = usable_width - 2 * mm - aspect_ratio = barcode_img.width / barcode_img.height - barcode_width = barcode_height * aspect_ratio - - # Constrain width to fit in label - if barcode_width > max_barcode_width: - barcode_width = max_barcode_width - - # Save barcode temporarily and draw on PDF - barcode_temp = tempfile.NamedTemporaryFile(suffix='.png', delete=False) - barcode_path = barcode_temp.name - barcode_temp.close() - - barcode_img.save(barcode_path, 'PNG') - - # Position barcode vertically centered in middle of row - barcode_y = y_position + (row_height - barcode_height) / 2 - - # Draw barcode image - c.drawImage( - barcode_path, - self.margin, - barcode_y, - width=barcode_width, - height=barcode_height, - preserveAspectRatio=True - ) - - # Draw small text below barcode showing the value - c.setFont("Helvetica", 6) - c.drawString( - self.margin, - barcode_y - 3 * mm, - f"({barcode_value})" - ) - - # Clean up - try: - os.remove(barcode_path) - except: - pass - else: - # If barcode generation failed, show text - c.setFont("Helvetica", 10) - c.drawString( - self.margin, - y_position + row_height / 2, - f"[No Barcode: {barcode_value}]" - ) - except Exception as e: - # Fallback: draw value as text with error indicator - print(f"PDF barcode error: {e}") - c.setFont("Helvetica", 10) - c.drawString( - self.margin, - y_position + row_height / 2, - f"[Text: {barcode_value}]" + # Convert to grayscale for black and white + img_bw = img.convert('L') + img_bw.save(temp_img_path, 'PNG') + + # Draw image maintaining aspect ratio + c.drawImage( + temp_img_path, + image_x, + image_y, + width=image_width, + height=image_height, + preserveAspectRatio=True, + anchor='c' ) + + # Clean up + try: + os.remove(temp_img_path) + except: + pass + except Exception as e: + print(f"Error drawing image: {e}") + + # Draw text rows on right + for idx, (label_name, value) in enumerate(rows_data): + # Calculate y position for this row (top to bottom) + y_position = self.label_height - self.margin - (idx * row_height) - row_height/2 + + # Draw text with better quality + if value and value.strip(): + text = f"{label_name} {value.strip()}" else: - # Empty value - show placeholder - c.setFont("Helvetica", 8) - c.drawString( - self.margin, - y_position + row_height / 2, - "(empty)" - ) + text = f"{label_name} -" + + # Use appropriate font size to fit (6pt = ~2.1mm height) + font_size = 6 + c.setFont("Helvetica-Bold", font_size) + + try: + c.drawString(text_area_x, y_position, text) + except Exception as e: + print(f"Error drawing text row {idx}: {e}") # Save PDF c.save() @@ -228,15 +310,16 @@ class PDFLabelGenerator: pdf_buffer.seek(0) return pdf_buffer.getvalue() - def create_label_pdf_file(self, sap_nr, cantitate, lot_number, filename=None): + def create_label_pdf_file(self, comanda, article, serial, filename=None, image_path=None): """ Create PDF label file and return the filename. Args: - sap_nr (str): SAP article number - cantitate (str): Quantity value - lot_number (str): Lot/Cable ID + comanda (str): Nr. Comanda value + article (str): Nr. Art. value + serial (str): Serial No. value filename (str): Output filename (if None, auto-generates) + image_path (str): Path to accepted.png image Returns: str: Path to created PDF file @@ -245,51 +328,75 @@ class PDFLabelGenerator: timestamp = datetime.datetime.now().strftime("%Y%m%d_%H%M%S") filename = f"label_{timestamp}.pdf" - return self.create_label_pdf(sap_nr, cantitate, lot_number, filename) + return self.create_label_pdf(comanda, article, serial, filename, image_path) -def create_label_pdf_simple(text): +def create_label_pdf_simple(text, image_path=None, svg_template=None): """ - Simple wrapper to create PDF from combined text (SAP|CANTITATE|LOT). + Simple wrapper to create PDF from combined text (article;nr_art;serial). Args: - text (str): Combined text in format "SAP|CANTITATE|LOT" + text (str): Combined text in format "article;nr_art;serial" + image_path (str): Path to accepted.png image + svg_template (str): Path to SVG template file (optional, checks conf/label_template.svg by default) Returns: bytes: PDF content """ - # Parse text - 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 text - 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 '' + + # Use default image path if not provided + if not image_path: + image_path = os.path.join('conf', 'accepted.png') + + # Check for default SVG template if not provided + if not svg_template: + default_svg = os.path.join('conf', 'label_template.svg') + if os.path.exists(default_svg): + svg_template = default_svg generator = PDFLabelGenerator() - pdf_bytes = generator.create_label_pdf(sap_nr, cantitate, lot_number) + pdf_bytes = generator.create_label_pdf(article, nr_art, serial, None, image_path, svg_template) return pdf_bytes -def create_label_pdf_file(text, filename=None): +def create_label_pdf_file(text, filename=None, image_path=None, svg_template=None): """ Create PDF label file from combined text. Args: - text (str): Combined text in format "SAP|CANTITATE|LOT" + text (str): Combined text in format "article;nr_art;serial" filename (str): Output filename (auto-generates if None) + image_path (str): Path to accepted.png image + svg_template (str): Path to SVG template file (optional, checks conf/label_template.svg by default) Returns: str: Path to created PDF file """ - # Parse text - 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 text - 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 '' if not filename: timestamp = datetime.datetime.now().strftime("%Y%m%d_%H%M%S") filename = f"label_{timestamp}.pdf" + # Use default image path if not provided + if not image_path: + image_path = os.path.join('conf', 'accepted.png') + + # Check for default SVG template if not provided + if not svg_template: + default_svg = os.path.join('conf', 'label_template.svg') + if os.path.exists(default_svg): + svg_template = default_svg + generator = PDFLabelGenerator() - return generator.create_label_pdf(sap_nr, cantitate, lot_number, filename) + return generator.create_label_pdf(article, nr_art, serial, filename, image_path, svg_template) diff --git a/requirements_windows.txt b/requirements_windows.txt index e269f67..9d16dae 100644 --- a/requirements_windows.txt +++ b/requirements_windows.txt @@ -5,3 +5,7 @@ reportlab pyinstaller>=6.0.0 pywin32 wmi +watchdog +svglib +cairosvg +pystray diff --git a/sample_data.txt b/sample_data.txt new file mode 100644 index 0000000..396a030 --- /dev/null +++ b/sample_data.txt @@ -0,0 +1 @@ +COM-2024-002;ART-67890;SN-20260212-TEST \ No newline at end of file diff --git a/test_svg_template.py b/test_svg_template.py new file mode 100644 index 0000000..041333d --- /dev/null +++ b/test_svg_template.py @@ -0,0 +1,159 @@ +""" +Test SVG template functionality +""" +import os +import sys + +# Import the PDF generator +from print_label_pdf import PDFLabelGenerator + +def test_svg_template(): + """Test SVG template with sample data""" + print("=== Testing SVG Template Functionality ===\n") + + # Check if template exists + template_path = os.path.join('conf', 'label_template.svg') + if not os.path.exists(template_path): + print(f"❌ Template not found: {template_path}") + return False + + print(f"✓ Template found: {template_path}") + + # Sample data + test_data = { + 'Article': 'COM-2024-001', + 'NrArt': 'ART-12345', + 'Serial': 'SN-20260212-001' + } + + print(f"✓ Test data: {test_data}") + + # Create generator + generator = PDFLabelGenerator() + print("✓ PDF generator initialized") + + # Test SVG template method + print("\n--- Testing SVG Template Method ---") + try: + pdf_output = 'test_label_svg.pdf' + result = generator.create_label_from_svg_template( + template_path, + test_data, + filename=pdf_output + ) + + if result and os.path.exists(pdf_output): + file_size = os.path.getsize(pdf_output) + print(f"✓ SVG template PDF created: {pdf_output} ({file_size} bytes)") + return True + else: + print("❌ SVG template PDF creation failed") + return False + + except Exception as e: + print(f"❌ Error: {e}") + import traceback + traceback.print_exc() + return False + +def test_programmatic_layout(): + """Test programmatic layout (fallback)""" + print("\n--- Testing Programmatic Layout (Fallback) ---") + + generator = PDFLabelGenerator() + + try: + pdf_output = 'test_label_programmatic.pdf' + result = generator.create_label_pdf( + comanda='COM-2024-001', + article='ART-12345', + serial='SN-20260212-001', + filename=pdf_output, + image_path=os.path.join('conf', 'accepted.png') + ) + + if result and os.path.exists(pdf_output): + file_size = os.path.getsize(pdf_output) + print(f"✓ Programmatic layout PDF created: {pdf_output} ({file_size} bytes)") + return True + else: + print("❌ Programmatic layout PDF creation failed") + return False + + except Exception as e: + print(f"❌ Error: {e}") + import traceback + traceback.print_exc() + return False + +def test_wrapper_functions(): + """Test convenience wrapper functions""" + print("\n--- Testing Wrapper Functions ---") + + from print_label_pdf import create_label_pdf_simple, create_label_pdf_file + + # Test data string + test_string = "COM-2024-001;ART-12345;SN-20260212-001" + + try: + # Test create_label_pdf_simple (returns bytes) + print("Testing create_label_pdf_simple()...") + pdf_bytes = create_label_pdf_simple(test_string) + if pdf_bytes: + print(f"✓ create_label_pdf_simple returned {len(pdf_bytes)} bytes") + else: + print("❌ create_label_pdf_simple failed") + return False + + # Test create_label_pdf_file (returns filename) + print("Testing create_label_pdf_file()...") + pdf_file = create_label_pdf_file(test_string, filename='test_label_wrapper.pdf') + if pdf_file and os.path.exists(pdf_file): + file_size = os.path.getsize(pdf_file) + print(f"✓ create_label_pdf_file created: {pdf_file} ({file_size} bytes)") + return True + else: + print("❌ create_label_pdf_file failed") + return False + + except Exception as e: + print(f"❌ Error: {e}") + import traceback + traceback.print_exc() + return False + +if __name__ == '__main__': + print("SVG Template Test Suite\n") + print("=" * 50) + + results = [] + + # Test 1: SVG template + results.append(("SVG Template", test_svg_template())) + + # Test 2: Programmatic layout + results.append(("Programmatic Layout", test_programmatic_layout())) + + # Test 3: Wrapper functions + results.append(("Wrapper Functions", test_wrapper_functions())) + + # Summary + print("\n" + "=" * 50) + print("SUMMARY") + print("=" * 50) + + for test_name, passed in results: + status = "✓ PASS" if passed else "❌ FAIL" + print(f"{status}: {test_name}") + + total = len(results) + passed = sum(1 for _, p in results if p) + + print(f"\nTotal: {passed}/{total} tests passed") + + if passed == total: + print("\n🎉 All tests passed!") + sys.exit(0) + else: + print("\n⚠ Some tests failed") + sys.exit(1)