Complete label printer redesign: file monitoring, SVG templates, sharp print quality
- Redesigned GUI for automatic file monitoring workflow - Changed label format to 35x25mm landscape - Implemented SVG template support with variable substitution - Added configuration auto-save/load (conf/app.conf) - Added system tray minimize functionality - Fixed print quality: landscape orientation, vector fonts, 600 DPI - Auto-clear file after print to prevent duplicates - All popups auto-dismiss after 2-3 seconds - Semicolon separator for data format (article;nr_art;serial) - SumatraPDF integration with noscale settings - Printer configured for outline fonts (sharp output) - Reorganized documentation into documentation/ folder
This commit is contained in:
2
.gitignore
vendored
2
.gitignore
vendored
@@ -2,3 +2,5 @@ label/
|
|||||||
build/
|
build/
|
||||||
logs/
|
logs/
|
||||||
pdf_backup/
|
pdf_backup/
|
||||||
|
venv/
|
||||||
|
|
||||||
|
|||||||
@@ -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
|
|
||||||
@@ -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! 🚀
|
|
||||||
234
README.md
234
README.md
@@ -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
|
|
||||||
Binary file not shown.
Binary file not shown.
@@ -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"
|
|
||||||
67
check_printer_quality.ps1
Normal file
67
check_printer_quality.ps1
Normal file
@@ -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
|
||||||
|
}
|
||||||
|
}
|
||||||
94
conf/SumatraPDF-settings.txt
Normal file
94
conf/SumatraPDF-settings.txt
Normal file
@@ -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
|
||||||
BIN
conf/SumatraPDF.exe
Normal file
BIN
conf/SumatraPDF.exe
Normal file
Binary file not shown.
BIN
conf/accepted.png
Normal file
BIN
conf/accepted.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 16 KiB |
4
conf/app.conf
Normal file
4
conf/app.conf
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
[Settings]
|
||||||
|
file_path = C:\Users\Public\Documents\check.txt
|
||||||
|
printer = Labels
|
||||||
|
|
||||||
63
conf/label_template.svg
Normal file
63
conf/label_template.svg
Normal file
@@ -0,0 +1,63 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
||||||
|
<!-- Creator: CorelDRAW -->
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" xml:space="preserve" width="35mm" height="25mm" version="1.1" style="shape-rendering:geometricPrecision; text-rendering:geometricPrecision; image-rendering:optimizeQuality; fill-rule:evenodd; clip-rule:evenodd"
|
||||||
|
viewBox="0 0 35 25"
|
||||||
|
xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||||
|
xmlns:xodm="http://www.corel.com/coreldraw/odm/2003">
|
||||||
|
<defs>
|
||||||
|
<font id="FontID0" horiz-adv-x="722" font-variant="normal" style="fill-rule:nonzero" font-style="normal" font-weight="700">
|
||||||
|
<font-face
|
||||||
|
font-family="Arial">
|
||||||
|
<font-face-src>
|
||||||
|
<font-face-name name="Arial Bold"/>
|
||||||
|
</font-face-src>
|
||||||
|
</font-face>
|
||||||
|
<missing-glyph><path d="M0 0z"/></missing-glyph>
|
||||||
|
<glyph unicode="." horiz-adv-x="277" d="M71.0096 0l0 136.998 136.998 0 0 -136.998 -136.998 0z"/>
|
||||||
|
<glyph unicode=":" horiz-adv-x="332" d="M98.0096 381.997l0 136.998 136.998 0 0 -136.998 -136.998 0zm0 -381.997l0 136.998 136.998 0 0 -136.998 -136.998 0z"/>
|
||||||
|
<glyph unicode="A" horiz-adv-x="722" d="M718.011 0l-156.185 0 -61.8388 162.999 -287.163 0 -59.482 -162.999 -153.342 0 277.993 715.987 153.162 0 286.856 -715.987zm-265.005 284.013l-99.4954 264.979 -96.6775 -264.979 196.173 0z"/>
|
||||||
|
<glyph unicode="C" horiz-adv-x="722" d="M531.009 264.006l139.995 -43.0105c-21.4924,-78.8227 -57.3302,-137.331 -107.334,-175.654 -50.0038,-38.1689 -113.328,-57.3302 -190.179,-57.3302 -95.1661,0 -173.323,32.482 -234.649,97.4972 -61.1727,64.9896 -91.836,153.828 -91.836,266.67 0,119.143 30.8169,211.825 92.3227,277.813 61.5058,66.0143 142.506,99.0086 242.847,99.0086 87.6604,0 158.824,-26.001 213.49,-77.8236 32.6613,-30.6888 56.9972,-74.6727 73.3407,-132.182l-143.018 -33.9934c-8.47914,36.9905 -26.1547,66.3217 -52.9754,87.8397 -27,21.4924 -59.687,32.149 -98.0096,32.149 -53.1803,0 -96.3445,-18.982 -129.339,-57.1509 -33.1737,-38.0152 -49.6708,-99.6747 -49.6708,-185.004 0,-90.3246 16.3435,-154.827 48.8511,-193.176 32.6613,-38.5019 74.9801,-57.6632 127.161,-57.6632 38.5019,0 71.65,12.1679 99.316,36.6831 27.6661,24.4896 47.6727,62.8122 59.687,115.326z"/>
|
||||||
|
<glyph unicode="N" horiz-adv-x="722" d="M73.0077 0l0 715.987 140.328 0 294.669 -479.827 0 479.827 134.001 0 0 -715.987 -144.837 0 -290.161 470.656 0 -470.656 -134.001 0z"/>
|
||||||
|
<glyph unicode="S" horiz-adv-x="667" d="M34.9924 232.011l141.02 13.9867c8.47914,-47.1604 25.4886,-81.6661 51.3103,-103.825 25.8473,-22.1841 60.686,-33.1737 104.516,-33.1737 46.315,0 81.3331,9.83682 104.824,29.5105 23.5162,19.648 35.3255,42.6518 35.3255,68.9858 0,17.0095 -4.99526,31.3293 -14.8321,43.3435 -9.8112,11.8349 -27.1537,22.1585 -51.8226,30.8169 -16.8302,6.01993 -55.1784,16.3435 -115.173,31.3549 -77.1576,19.315 -131.337,42.9849 -162.487,71.1633 -43.8302,39.501 -65.6813,87.6604 -65.6813,144.504 0,36.4782 10.3492,70.8302 30.8425,102.646 20.6727,31.8416 50.3369,55.9982 89.1718,72.6746 38.835,16.6765 85.483,25.0019 140.482,25.0019 89.5048,0 157.005,-19.8273 202.167,-59.6613 45.3416,-39.834 69.0115,-92.835 71.3426,-159.336l-144.991 -4.99526c-6.17363,36.9905 -19.3406,63.5039 -39.501,79.668 -20.186,16.1642 -50.5162,24.3359 -90.8369,24.3359 -41.6784,0 -74.3397,-8.68407 -97.8303,-26.001 -15.1651,-11.1689 -22.8501,-26.001 -22.8501,-44.6756 0,-17.0095 7.17268,-31.5086 21.518,-43.4972 18.1623,-15.4981 62.3255,-31.5086 132.49,-48.1594 70.1642,-16.5228 122.012,-33.8397 155.494,-51.5152 33.686,-17.8292 60.02,-41.9858 79.002,-72.8283 19.0076,-30.8425 28.5114,-68.8321 28.5114,-113.994 0,-41.0124 -11.3482,-79.5143 -34.1727,-115.352 -22.8245,-35.8122 -54.9991,-62.4792 -96.6775,-79.8217 -41.6528,-17.4962 -93.6547,-26.1547 -155.827,-26.1547 -90.5039,0 -160.002,20.8264 -208.495,62.6585 -48.4925,41.6528 -77.3369,102.493 -86.8407,182.34z"/>
|
||||||
|
<glyph unicode="a" horiz-adv-x="556" d="M173.989 358.993l-123.985 22.0048c13.9867,50.6699 38.1689,88.1728 72.3416,112.509 34.1471,24.3359 84.9963,36.5038 152.317,36.5038 61.1727,0 106.847,-7.17268 136.845,-21.6717 29.8179,-14.4991 51.0029,-32.8406 63.1708,-55.1784 12.1679,-22.3378 18.316,-63.1708 18.316,-122.832l-1.9981 -160.002c0,-45.4953 2.17742,-79.1557 6.50665,-100.827 4.32923,-21.6717 12.501,-44.8293 24.4896,-69.4982l-135.999 0c-3.48387,8.99147 -7.99242,22.3378 -13.167,39.9877 -2.1518,8.17173 -3.81689,13.5 -4.81594,16.0105 -23.3368,-23.0038 -48.3388,-40.167 -75.0058,-51.6689 -26.667,-11.5019 -54.9991,-17.3169 -85.1756,-17.3169 -53.1547,0 -95.1661,14.4991 -125.829,43.4972 -30.6632,28.8188 -46.0076,65.502 -46.0076,109.819 0,29.1774 7.01898,55.3321 21.0057,78.3359 14.0123,22.8245 33.5067,40.5 58.8416,52.668 25.1556,12.1679 61.5058,22.8245 108.999,31.9953 63.9906,12.0142 108.487,23.3368 133.156,33.6604l0 13.833c0,26.667 -6.48103,45.6746 -19.4943,57.1765 -13.167,11.3482 -37.8359,17.0095 -74.0067,17.0095 -24.4896,0 -43.4972,-4.84156 -57.1509,-14.6784 -13.833,-9.6575 -24.8482,-26.8207 -33.353,-51.3359zm184.005 -110.997c-17.4962,-5.84061 -45.316,-12.834 -83.4849,-21.0057 -38.0152,-8.14612 -63.0171,-16.1642 -74.6727,-23.8236 -17.8292,-12.834 -26.8463,-28.8444 -26.8463,-48.3388 0,-19.315 7.17268,-35.8378 21.518,-49.8245 14.3197,-14.0123 32.482,-21.0057 54.6661,-21.0057 24.6689,0 48.3388,8.17173 70.8302,24.3359 16.4972,12.501 27.4867,27.5124 32.6613,45.4953 3.50949,11.6812 5.32828,33.9934 5.32828,66.834l0 27.333z"/>
|
||||||
|
<glyph unicode="c" horiz-adv-x="556" d="M523.99 365.013l-135 -24.0029c-4.48293,26.8207 -14.8321,46.9811 -30.9962,60.6604 -16.1642,13.5 -36.9905,20.3397 -62.6585,20.3397 -34.1727,0 -61.5058,-11.8349 -81.8454,-35.5048 -20.3141,-23.6699 -30.4839,-63.1708 -30.4839,-118.682 0,-61.6595 10.3235,-105.157 30.9962,-130.645 20.6727,-25.5143 48.3388,-38.1689 82.9982,-38.1689 26.001,0 47.3397,7.48008 63.8369,22.3122 16.6509,14.8577 28.3321,40.3463 35.1718,76.6709l135 -23.0038c-14.0123,-61.9925 -40.8331,-108.82 -80.5134,-140.482 -39.6547,-31.6623 -92.835,-47.4934 -159.669,-47.4934 -75.6718,0 -136.153,23.9773 -181.161,71.8293 -45.1623,47.9801 -67.6538,114.327 -67.6538,199.17 0,85.816 22.6452,152.496 67.8331,200.323 45.1623,47.8264 106.309,71.6756 183.493,71.6756 62.9915,0 113.175,-13.6793 150.498,-40.8331 37.1699,-27.1793 63.8369,-68.4991 80.1547,-124.164z"/>
|
||||||
|
<glyph unicode="d" horiz-adv-x="610" d="M547.993 0l-126.982 0 0 76.1585c-21.185,-29.6642 -46.3407,-51.8226 -75.1851,-66.834 -28.8188,-14.8321 -57.9963,-22.3122 -87.3274,-22.3122 -59.8407,0 -110.997,23.9773 -153.675,72.1623 -42.4981,48.1594 -63.8113,115.147 -63.8113,201.322 0,87.9934 20.6471,155.007 62.1462,200.835 41.4991,45.8283 93.8341,68.6784 157.184,68.6784 57.9963,0 108.333,-24.1822 150.652,-72.3416l0 258.319 136.998 0 0 -715.987zm-365.986 269.488c0,-55.4858 7.6594,-95.6528 22.8245,-120.475 22.1585,-36.0171 53.001,-54.0001 92.6813,-54.0001 31.483,0 58.3293,13.5 80.3084,40.5 22.1841,27 33.1737,67.1414 33.1737,120.808 0,59.8407 -10.6566,102.851 -32.149,129.185 -21.518,26.334 -48.8511,39.501 -82.3578,39.501 -32.482,0 -59.6613,-13.0133 -81.6661,-39.0143 -21.8254,-26.001 -32.815,-64.8359 -32.815,-116.505z"/>
|
||||||
|
<glyph unicode="e" horiz-adv-x="556" d="M372.006 163.998l136.998 -23.0038c-17.4962,-50.1575 -45.3416,-88.3265 -83.1775,-114.66 -37.9896,-26.1547 -85.483,-39.3217 -142.327,-39.3217 -90.1709,0 -157.005,29.4848 -200.169,88.4802 -34.1727,47.3397 -51.3359,107.001 -51.3359,179.163 0,86.021 22.5171,153.521 67.3464,202.167 44.8293,48.8511 101.647,73.187 170.326,73.187 77.0039,0 137.844,-25.5143 182.494,-76.5172 44.4962,-51.0029 65.835,-129.16 63.8369,-234.495l-343.008 0c0.999052,-40.6537 12.0142,-72.3416 33.1737,-94.9868 21.0057,-22.6708 47.3397,-34.019 78.669,-34.019 21.4924,0 39.501,5.84061 54.0001,17.4962 14.6784,11.6812 25.668,30.5095 33.1737,56.5105zm7.99242 138.996c-0.999052,39.834 -11.1689,70.1642 -30.6632,90.8369 -19.4943,20.8264 -43.1642,31.1756 -71.1633,31.1756 -29.8435,0 -54.5124,-11.0152 -74.0067,-32.8406 -19.4943,-21.8254 -28.9981,-51.6689 -28.6651,-89.1718l204.498 0z"/>
|
||||||
|
<glyph unicode="i" horiz-adv-x="277" d="M72.0086 589.005l0 126.982 136.998 0 0 -126.982 -136.998 0zm0 -589.005l0 518.995 136.998 0 0 -518.995 -136.998 0z"/>
|
||||||
|
<glyph unicode="l" horiz-adv-x="277" d="M72.0086 0l0 715.987 136.998 0 0 -715.987 -136.998 0z"/>
|
||||||
|
<glyph unicode="m" horiz-adv-x="889" d="M61.9925 518.995l126.009 0 0 -70.8302c45.1623,54.5124 99.0086,81.8454 161.488,81.8454 33.1737,0 62.0181,-6.83966 86.354,-20.519 24.4896,-13.6537 44.4962,-34.3264 59.9944,-61.9925 22.8245,27.6661 47.4934,48.3388 73.8274,61.9925 26.334,13.6793 54.5124,20.519 84.5096,20.519 37.9896,0 70.1642,-7.68502 96.6519,-23.1831 26.334,-15.4981 46.0076,-38.1689 58.9953,-68.1661 9.5038,-22.0048 14.166,-57.8169 14.166,-107.334l0 -331.327 -136.998 0 0 296.155c0,51.5152 -4.66224,84.6889 -14.166,99.521 -12.6547,19.4943 -32.3283,29.3311 -58.6623,29.3311 -19.1613,0 -37.3236,-5.84061 -54.3331,-17.4962 -16.8302,-11.8349 -29.1518,-28.9981 -36.6575,-51.5152 -7.5057,-22.6708 -11.1689,-58.3293 -11.1689,-107.155l0 -248.841 -136.998 0 0 284.013c0,50.3112 -2.51044,82.9982 -7.32638,97.4972 -4.84156,14.6528 -12.3473,25.668 -22.6708,32.815 -10.1698,7.17268 -24.1822,10.6822 -41.6784,10.6822 -21.1594,0 -40.167,-5.6613 -56.9972,-17.0095 -17.0095,-11.5019 -28.9981,-27.8198 -36.3245,-49.3378 -7.352,-21.4924 -11.0152,-57.1509 -11.0152,-106.822l0 -251.838 -136.998 0 0 518.995z"/>
|
||||||
|
<glyph unicode="n" horiz-adv-x="610" d="M543.997 0l-136.998 0 0 264.493c0,55.9982 -2.99716,92.169 -8.83777,108.512 -5.99431,16.4972 -15.4981,29.1518 -28.8188,38.3226 -13.3463,9.17079 -29.3311,13.6793 -48.0057,13.6793 -24.0029,0 -45.4953,-6.50665 -64.5029,-19.4943 -19.1613,-13.0133 -32.1746,-30.3558 -39.168,-51.6689 -7.17268,-21.518 -10.6566,-61.1727 -10.6566,-119.169l0 -234.675 -136.998 0 0 518.995 126.982 0 0 -76.1585c45.4953,58.1756 102.672,87.1737 171.837,87.1737 30.3302,0 58.1756,-5.5076 83.3312,-16.3435 25.3349,-10.9896 44.3425,-24.8226 57.1765,-41.6784 12.9877,-16.9839 22.0048,-36.1452 27,-57.6632 5.17458,-21.4924 7.6594,-52.1556 7.6594,-92.169l0 -322.156z"/>
|
||||||
|
<glyph unicode="o" horiz-adv-x="610" d="M39.9877 265.825c0,45.6746 11.1689,89.8378 33.686,132.515 22.4915,42.8312 54.3331,75.3388 95.4991,97.8303 41.1661,22.4915 86.9944,33.8397 137.818,33.8397 78.5153,0 142.685,-25.5143 192.843,-76.5172 50.1575,-51.1566 75.1595,-115.48 75.1595,-193.483 0,-78.669 -25.3349,-143.838 -75.8255,-195.507 -50.6699,-51.6689 -114.327,-77.4906 -191.178,-77.4906 -47.4934,0 -92.835,10.8103 -135.999,32.3283 -42.9849,21.4924 -75.8255,53.001 -98.317,94.6538 -22.5171,41.4991 -33.686,92.169 -33.686,151.83zm141.02 -7.32638c0,-51.4896 12.1679,-90.9906 36.5038,-118.324 24.4896,-27.5124 54.4868,-41.1661 90.3246,-41.1661 35.6585,0 65.6557,13.6537 89.8378,41.1661 24.1566,27.333 36.3245,67.167 36.3245,119.323 0,50.8236 -12.1679,89.9915 -36.3245,117.325 -24.1822,27.5124 -54.1794,41.1661 -89.8378,41.1661 -35.8378,0 -65.835,-13.6537 -90.3246,-41.1661 -24.3359,-27.333 -36.5038,-66.834 -36.5038,-118.324z"/>
|
||||||
|
<glyph unicode="r" horiz-adv-x="389" d="M203.013 0l-137.024 0 0 518.995 127.008 0 0 -73.6737c21.8254,34.8387 41.4991,57.6889 58.9953,68.5247 17.4962,10.8103 37.3492,16.1642 59.5076,16.1642 31.3293,0 61.5058,-8.68407 90.5039,-25.8473l-42.4981 -119.656c-23.1831,14.9858 -44.6756,22.4915 -64.5029,22.4915 -19.3406,0 -35.6585,-5.32828 -49.0048,-15.8311 -13.3207,-10.6566 -23.8236,-29.6642 -31.5086,-57.3302 -7.6594,-27.6661 -11.4763,-85.6623 -11.4763,-173.835l0 -160.002z"/>
|
||||||
|
<glyph unicode="t" horiz-adv-x="332" d="M308.989 518.995l0 -108.999 -93.9878 0 0 -210.16c0,-42.6775 0.819735,-67.5001 2.66414,-74.4934 1.8444,-7.01898 5.84061,-12.834 12.3473,-17.5218 6.32733,-4.48293 13.9867,-6.81405 23.1575,-6.81405 12.834,0 31.1756,4.32923 55.3321,13.167l11.5019 -106.668c-31.8416,-13.6793 -67.8331,-20.4934 -108.179,-20.4934 -24.6689,0 -46.8274,4.14991 -66.6547,12.4753 -19.8273,8.35105 -34.3264,19.1869 -43.4972,32.3539 -9.3501,13.3207 -15.6774,31.1499 -19.3406,53.8207 -2.84346,16.0105 -4.32923,48.3388 -4.32923,97.1642l0 227.169 -62.9915 0 0 108.999 62.9915 0 0 103.005 136.998 81.0001 0 -184.005 93.9878 0z"/>
|
||||||
|
<glyph unicode="{" horiz-adv-x="389" d="M28.9981 200.989l0 117.017c23.8236,1.33207 41.6784,4.81594 53.8464,10.8359 11.9886,5.815 22.3122,15.6518 31.1499,29.4848 8.83777,13.833 14.8321,31.1756 18.1623,52.0019 2.51044,15.6774 3.84251,42.8312 3.84251,81.6661 0,63.1708 2.99716,107.18 8.83777,132.182 5.84061,25.0019 16.3179,44.983 31.6623,60.1481 15.3444,15.1651 37.6566,27 66.834,35.8378 19.8273,5.84061 51.1566,8.83777 93.8341,8.83777l25.8217 0 0 -116.992c-36.3245,0 -59.482,-1.9981 -69.8312,-6.17363 -10.3235,-3.99621 -17.8292,-10.1698 -22.8245,-18.4953 -4.84156,-8.35105 -7.32638,-22.5171 -7.32638,-42.6775 0,-20.4934 -1.33207,-59.5076 -3.99621,-116.659 -1.66509,-32.3283 -5.84061,-58.3293 -12.6803,-78.5153 -6.83966,-19.981 -15.4981,-36.4782 -26.1547,-49.4915 -10.5029,-12.9877 -26.667,-26.4877 -48.5181,-40.5 19.3406,-10.9896 35.0181,-24.0029 47.3397,-38.835 12.3473,-14.8321 21.6717,-32.8406 28.1784,-54.0001 6.66035,-21.1594 10.8359,-49.6708 12.834,-85.15 1.9981,-54.0001 2.99716,-88.6851 2.99716,-103.671 0,-21.518 2.66414,-36.5038 7.83872,-45.0086 5.14896,-8.32543 12.9877,-14.8321 23.6442,-19.1613 10.5029,-4.50854 33.353,-6.66035 68.4991,-6.66035l0 -117.017 -25.8217 0c-44.0095,0 -77.6699,3.50949 -101.16,10.5029 -23.3368,6.99337 -43.1642,18.6746 -59.1746,34.9924 -16.1642,16.1898 -27,36.3501 -32.5076,60.353 -5.48198,23.8236 -8.32543,61.6595 -8.32543,113.149 0,59.8407 -2.66414,98.8293 -7.83872,116.684 -7.17268,26.1547 -17.9829,44.8293 -32.482,55.9982 -14.4991,11.3226 -36.6831,17.6499 -66.6803,19.315z"/>
|
||||||
|
<glyph unicode="}" horiz-adv-x="389" d="M355.996 200.989c-23.8236,-1.33207 -41.6528,-4.81594 -53.667,-10.6566 -12.1679,-5.99431 -22.4915,-15.8311 -31.1499,-29.6642 -8.50475,-13.833 -14.6784,-31.1756 -18.3416,-52.0019 -2.51044,-15.6774 -3.84251,-42.6775 -3.84251,-81.1538 0,-63.1708 -2.81784,-107.334 -8.50475,-132.515 -5.6613,-25.0019 -16.1642,-45.1623 -31.483,-60.3274 -15.3444,-15.1651 -37.8359,-27 -67.3464,-35.8378 -19.8273,-5.84061 -51.1566,-8.83777 -93.8341,-8.83777l-25.8217 0 0 117.017c34.9924,0 57.8169,2.1518 68.6528,6.66035 10.6822,4.32923 18.6746,10.6566 23.6699,19.0076 5.17458,8.32543 7.68502,22.3122 7.83872,42.3188 0.179317,19.8273 1.51139,57.8426 3.84251,113.841 1.66509,33.9934 5.99431,60.9934 13.167,81.4868 7.14707,20.3397 16.6509,37.6822 28.4858,51.8482 12.0142,14.166 27.1793,26.4877 45.6746,37.3236 -24.0029,15.6774 -41.6784,30.9962 -52.668,45.8283 -15.3444,21.518 -25.8473,48.8511 -31.3293,82.1784 -3.50949,22.6708 -5.99431,72.8283 -7.32638,150.319 -0.333017,24.3359 -2.51044,40.6794 -6.68596,48.8511 -3.99621,7.99242 -11.3226,14.3197 -22.0048,18.649 -10.6566,4.50854 -34.3264,6.68596 -71.317,6.68596l0 116.992 25.8217 0c44.0095,0 77.6699,-3.50949 101.186,-10.3235 23.3112,-6.83966 42.9849,-18.5209 58.9953,-34.8387 15.9848,-16.4972 26.8207,-36.6831 32.482,-60.6604 5.68691,-23.8492 8.50475,-61.6851 8.50475,-113.175 0,-59.5076 2.51044,-98.4963 7.32638,-116.659 7.17268,-26.1803 18.0086,-44.8549 32.6869,-56.0238 14.6528,-11.3226 36.9905,-17.6499 66.9877,-19.315l0 -117.017z"/>
|
||||||
|
</font>
|
||||||
|
<style type="text/css">
|
||||||
|
<![CDATA[
|
||||||
|
@font-face { font-family:"Arial";font-variant:normal;font-style:normal;font-weight:bold;src:url("#FontID0") format(svg)}
|
||||||
|
.fil0 {fill:#373435}
|
||||||
|
.fil1 {fill:black}
|
||||||
|
.fnt0 {font-weight:bold;font-size:3.9037px;font-family:'Arial'}
|
||||||
|
]]>
|
||||||
|
</style>
|
||||||
|
</defs>
|
||||||
|
<g id="Layer_x0020_1">
|
||||||
|
<metadata id="CorelCorpID_0Corel-Layer"/>
|
||||||
|
<g transform="matrix(0.576293 0 0 1 -8.27317 4.15816)">
|
||||||
|
<text x="17.5" y="12.5" class="fil0 fnt0">Nr. Comanda:{Article}</text>
|
||||||
|
</g>
|
||||||
|
<g transform="matrix(0.576293 0 0 1 -8.27317 7.72657)">
|
||||||
|
<text x="17.5" y="12.5" class="fil0 fnt0">Nr. Art.:{NrArt}</text>
|
||||||
|
</g>
|
||||||
|
<g transform="matrix(0.576293 0 0 1 -8.33607 11.0472)">
|
||||||
|
<text x="17.5" y="12.5" class="fil0 fnt0">Serial No.:{Serial}</text>
|
||||||
|
</g>
|
||||||
|
<g id="_1383785436736">
|
||||||
|
<path class="fil1" d="M12.82 7.2323c-0.1161,0.0271 -0.6403,0.41 -0.7023,0.417 -0.0438,0.005 -0.4125,-0.272 -0.4735,-0.3166 -0.0598,-0.0436 -0.0888,-0.0806 -0.163,-0.1004 0,0.0747 0.0169,0.2103 0.0281,0.3011 0.0331,0.269 0.0855,0.5861 0.1616,0.848 0.103,0.3544 0.2131,0.6687 0.3663,0.9726 0.2431,0.4823 0.4418,0.7936 0.7893,1.208 0.9583,1.1426 2.579,1.9598 4.0759,1.9598 1.0308,0 1.7035,-0.1145 2.5607,-0.512 0.3018,-0.1399 0.5873,-0.307 0.8502,-0.4886 0.4492,-0.3106 0.7746,-0.6264 1.1172,-1.0338 0.0352,-0.0419 0.0492,-0.052 0.0813,-0.0942 0.6831,-0.895 1.0205,-1.7074 1.1757,-2.8408 0.0122,-0.0889 0.0311,-0.2456 0.0311,-0.3201 -0.1148,-0.0768 -0.2364,-0.1435 -0.3512,-0.2195 -0.4402,-0.2912 -0.3377,-0.2606 -0.7083,0.016 -0.4465,0.3331 -0.1917,0.0604 -0.3623,0.801 -0.0383,0.1665 -0.0787,0.3029 -0.1284,0.4642 -0.2415,0.783 -0.8476,1.5453 -1.4754,2.0363 -0.1897,0.1484 -0.5097,0.3427 -0.7199,0.4433 -1.4392,0.6888 -3.2727,0.5256 -4.5139,-0.4835 -0.1901,-0.1546 -0.4507,-0.3749 -0.5984,-0.5649 -0.2922,-0.3762 -0.4778,-0.591 -0.6835,-1.0723 -0.1761,-0.412 -0.3573,-0.9691 -0.3573,-1.4206z"/>
|
||||||
|
<path class="fil1" d="M11.4812 6.5739c0.1103,0.0738 0.2091,0.1467 0.3248,0.2238 0.4133,0.2755 0.2641,0.2761 0.6717,0.0045 0.1215,-0.0811 0.227,-0.1511 0.3423,-0.2283 0,-0.7199 0.395,-1.6532 0.8432,-2.2515 0.2017,-0.2693 0.6154,-0.6932 0.9082,-0.8915 0.7337,-0.4969 1.3743,-0.7636 2.287,-0.8077 0.3218,-0.0155 0.0567,-0.0336 0.4622,-0.0011 0.2873,0.023 0.3574,0.0038 0.706,0.0841 0.5154,0.1187 1.0246,0.3291 1.4484,0.6147 0.8452,0.5696 1.4617,1.4005 1.7486,2.3776 0.063,0.2147 0.1562,0.6133 0.1562,0.8754 0.1055,-0.0282 0.5565,-0.4104 0.6145,-0.417 0.0786,0.021 0.2734,0.1575 0.3607,0.2099 0.0787,0.0473 0.2939,0.1908 0.3636,0.2071l-0.0687 -0.5898c-0.1423,-0.8307 -0.4834,-1.7021 -0.9879,-2.3701 -0.2122,-0.2809 -0.5138,-0.6564 -0.7903,-0.8778 -0.2016,-0.1613 -0.3013,-0.2735 -0.5584,-0.4512 -0.8199,-0.5666 -1.9324,-1.0006 -3.0378,-1.0006 -1.0533,0 -1.6632,0.1218 -2.5238,0.5051 -1.6549,0.7371 -2.8948,2.3661 -3.1985,4.176 -0.0172,0.1027 -0.0262,0.1807 -0.0409,0.2883 -0.0122,0.0889 -0.0311,0.2456 -0.0311,0.3201z"/>
|
||||||
|
<path class="fil1" d="M16.4195 7.4518l-1.4213 -1.41 -1.0534 1.0643 2.4473 2.4582 3.8738 -3.8629 -1.0537 -1.0423 -0.1758 0.164c-0.0315,0.0363 -0.0538,0.0557 -0.0893,0.0863l-0.6063 0.6008c-0.003,0.0034 -0.0071,0.0084 -0.0101,0.0119l-0.1755 0.1757c-0.0032,0.0032 -0.0077,0.0078 -0.0109,0.011l-0.2499 0.2549c-0.0507,0.0484 -0.0461,0.0309 -0.092,0.0836 -0.1863,0.2139 -1.3182,1.3079 -1.3829,1.4045z"/>
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 18 KiB |
BIN
conf/refused.png
Normal file
BIN
conf/refused.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 104 KiB |
103
dist/pdf_backup/final_label_20260205_234513.pdf
vendored
103
dist/pdf_backup/final_label_20260205_234513.pdf
vendored
File diff suppressed because one or more lines are too long
103
dist/pdf_backup/final_label_20260205_234602.pdf
vendored
103
dist/pdf_backup/final_label_20260205_234602.pdf
vendored
File diff suppressed because one or more lines are too long
@@ -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.
|
|
||||||
@@ -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!
|
|
||||||
@@ -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`
|
|
||||||
|
|
||||||
@@ -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!** 🎊
|
|
||||||
@@ -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! 🖨️
|
|
||||||
@@ -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** ✓
|
|
||||||
|
|
||||||
@@ -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
|
|
||||||
@@ -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
|
|
||||||
@@ -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)
|
|
||||||
@@ -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
|
|
||||||
@@ -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.
|
|
||||||
@@ -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
|
|
||||||
@@ -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
|
|
||||||
|
|
||||||
@@ -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
|
|
||||||
@@ -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** ✓
|
|
||||||
@@ -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.
|
|
||||||
@@ -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)
|
|
||||||
@@ -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())
|
|
||||||
@@ -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
|
|
||||||
@@ -1,5 +0,0 @@
|
|||||||
python-barcode
|
|
||||||
pillow
|
|
||||||
pycups
|
|
||||||
reportlab
|
|
||||||
pycups
|
|
||||||
@@ -1,5 +0,0 @@
|
|||||||
python-barcode
|
|
||||||
pillow
|
|
||||||
reportlab
|
|
||||||
kivy
|
|
||||||
pywin32
|
|
||||||
@@ -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()
|
|
||||||
@@ -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
|
|
||||||
|
|
||||||
@@ -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())
|
|
||||||
@@ -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)
|
|
||||||
@@ -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")
|
|
||||||
@@ -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())
|
|
||||||
@@ -15,6 +15,7 @@ from kivy.uix.popup import Popup
|
|||||||
from kivy.core.window import Window
|
from kivy.core.window import Window
|
||||||
from kivy.uix.image import Image as KivyImage
|
from kivy.uix.image import Image as KivyImage
|
||||||
from kivy.graphics import Color, Rectangle
|
from kivy.graphics import Color, Rectangle
|
||||||
|
from kivy.uix.filechooser import FileChooserListView
|
||||||
|
|
||||||
import os
|
import os
|
||||||
import threading
|
import threading
|
||||||
@@ -22,8 +23,14 @@ import platform
|
|||||||
import time
|
import time
|
||||||
import datetime
|
import datetime
|
||||||
import glob
|
import glob
|
||||||
|
import configparser
|
||||||
from print_label import print_label_standalone, get_available_printers
|
from print_label import print_label_standalone, get_available_printers
|
||||||
from kivy.clock import Clock
|
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)
|
# Set window size - portrait/phone dimensions (375x667 like iPhone)
|
||||||
# Adjusted to be slightly wider for touch-friendly UI
|
# 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):
|
class LabelPrinterApp(App):
|
||||||
"""Simplified Kivy application for label printing"""
|
"""Simplified Kivy application for label printing with file monitoring"""
|
||||||
|
|
||||||
def __init__(self, **kwargs):
|
def __init__(self, **kwargs):
|
||||||
super().__init__(**kwargs)
|
super().__init__(**kwargs)
|
||||||
@@ -49,6 +74,15 @@ class LabelPrinterApp(App):
|
|||||||
display_name = full_name[:20]
|
display_name = full_name[:20]
|
||||||
self.printer_display_map[display_name] = full_name
|
self.printer_display_map[display_name] = full_name
|
||||||
self.available_printers.append(display_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
|
# Clean old PDF backup files on startup
|
||||||
self.cleanup_old_pdfs()
|
self.cleanup_old_pdfs()
|
||||||
# Clean old log files on startup
|
# Clean old log files on startup
|
||||||
@@ -149,14 +183,60 @@ class LabelPrinterApp(App):
|
|||||||
except Exception as e:
|
except Exception as e:
|
||||||
print(f"Error during log cleanup: {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).
|
Log the print action to a CSV log file (table format).
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
sap_nr (str): SAP article number
|
article (str): Article/Comanda number
|
||||||
quantity (str): Quantity value
|
nr_art (str): Nr. Art. value
|
||||||
cable_id (str): Cable ID
|
serial (str): Serial number
|
||||||
printer (str): Printer name
|
printer (str): Printer name
|
||||||
pdf_filename (str): Path to the generated PDF file
|
pdf_filename (str): Path to the generated PDF file
|
||||||
success (bool): Whether the print was successful
|
success (bool): Whether the print was successful
|
||||||
@@ -186,9 +266,9 @@ class LabelPrinterApp(App):
|
|||||||
# Create CSV line
|
# Create CSV line
|
||||||
log_line = (
|
log_line = (
|
||||||
f"{timestamp},{status},"
|
f"{timestamp},{status},"
|
||||||
f"{escape_csv(sap_nr)},"
|
f"{escape_csv(article)},"
|
||||||
f"{escape_csv(quantity)},"
|
f"{escape_csv(nr_art)},"
|
||||||
f"{escape_csv(cable_id)},"
|
f"{escape_csv(serial)},"
|
||||||
f"{escape_csv(printer)},"
|
f"{escape_csv(printer)},"
|
||||||
f"{escape_csv(pdf_filename)}\n"
|
f"{escape_csv(pdf_filename)}\n"
|
||||||
)
|
)
|
||||||
@@ -200,7 +280,7 @@ class LabelPrinterApp(App):
|
|||||||
with open(log_filename, 'a', encoding='utf-8') as f:
|
with open(log_filename, 'a', encoding='utf-8') as f:
|
||||||
# Add header if file is new
|
# Add header if file is new
|
||||||
if not file_exists:
|
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
|
# Append log entry
|
||||||
f.write(log_line)
|
f.write(log_line)
|
||||||
|
|
||||||
@@ -209,15 +289,15 @@ class LabelPrinterApp(App):
|
|||||||
print(f"Error saving log entry: {e}")
|
print(f"Error saving log entry: {e}")
|
||||||
|
|
||||||
def build(self):
|
def build(self):
|
||||||
"""Build the simplified single-column UI"""
|
"""Build the simplified file monitoring UI"""
|
||||||
self.title = "Label Printing"
|
self.title = "Label Printing - File Monitor"
|
||||||
|
|
||||||
# Main container - single column layout
|
# Main container - single column layout
|
||||||
main_layout = BoxLayout(orientation='vertical', spacing=8, padding=12)
|
main_layout = BoxLayout(orientation='vertical', spacing=8, padding=12)
|
||||||
|
|
||||||
# Title
|
# Title
|
||||||
title = Label(
|
title = Label(
|
||||||
text='[b]Label Printing[/b]',
|
text='[b]Label Printing - File Monitor[/b]',
|
||||||
markup=True,
|
markup=True,
|
||||||
size_hint_y=0.08,
|
size_hint_y=0.08,
|
||||||
font_size='18sp',
|
font_size='18sp',
|
||||||
@@ -226,70 +306,56 @@ class LabelPrinterApp(App):
|
|||||||
main_layout.add_widget(title)
|
main_layout.add_widget(title)
|
||||||
|
|
||||||
# Scroll view for form fields
|
# 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 = GridLayout(cols=1, spacing=8, size_hint_y=None, padding=8)
|
||||||
form_layout.bind(minimum_height=form_layout.setter('height'))
|
form_layout.bind(minimum_height=form_layout.setter('height'))
|
||||||
|
|
||||||
# SAP-Nr. Articol
|
# File path input
|
||||||
sap_label = Label(
|
file_label = Label(
|
||||||
text='SAP-Nr. Articol:',
|
text='Monitor File Path:',
|
||||||
size_hint_y=None,
|
size_hint_y=None,
|
||||||
height=30,
|
height=30,
|
||||||
font_size='12sp'
|
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,
|
multiline=False,
|
||||||
size_hint_y=None,
|
size_hint_x=0.75,
|
||||||
height=45,
|
font_size='12sp',
|
||||||
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',
|
|
||||||
background_color=(0.95, 0.95, 0.95, 1),
|
background_color=(0.95, 0.95, 0.95, 1),
|
||||||
padding=(10, 10),
|
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)
|
file_row.add_widget(self.file_input)
|
||||||
form_layout.add_widget(self.qty_input)
|
|
||||||
|
|
||||||
# ID rola cablu
|
browse_button = Button(
|
||||||
cable_id_label = Label(
|
text='Browse',
|
||||||
text='ID rola cablu:',
|
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,
|
size_hint_y=None,
|
||||||
height=30,
|
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(
|
# Add spacing
|
||||||
multiline=False,
|
form_layout.add_widget(Label(text='', size_hint_y=None, height=20))
|
||||||
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)
|
|
||||||
|
|
||||||
# Printer selection
|
# Printer selection
|
||||||
printer_label = Label(
|
printer_label = Label(
|
||||||
@@ -309,55 +375,346 @@ class LabelPrinterApp(App):
|
|||||||
sync_height=True,
|
sync_height=True,
|
||||||
)
|
)
|
||||||
self.printer_spinner = printer_spinner
|
self.printer_spinner = printer_spinner
|
||||||
|
# Save config when printer changes
|
||||||
|
printer_spinner.bind(text=self.on_printer_changed)
|
||||||
form_layout.add_widget(printer_spinner)
|
form_layout.add_widget(printer_spinner)
|
||||||
|
|
||||||
scroll.add_widget(form_layout)
|
scroll.add_widget(form_layout)
|
||||||
main_layout.add_widget(scroll)
|
main_layout.add_widget(scroll)
|
||||||
|
|
||||||
# Print button
|
# Buttons layout
|
||||||
print_button = Button(
|
buttons_layout = BoxLayout(orientation='vertical', size_hint_y=0.30, spacing=5)
|
||||||
text='PRINT LABEL',
|
|
||||||
size_hint_y=0.15,
|
# Start/Stop monitoring button
|
||||||
|
self.monitor_button = Button(
|
||||||
|
text='START MONITORING',
|
||||||
|
size_hint_y=0.7,
|
||||||
font_size='14sp',
|
font_size='14sp',
|
||||||
background_color=(0.2, 0.6, 0.2, 1),
|
background_color=(0.2, 0.5, 0.8, 1),
|
||||||
background_normal='',
|
background_normal='',
|
||||||
bold=True
|
bold=True
|
||||||
)
|
)
|
||||||
print_button.bind(on_press=self.print_label)
|
self.monitor_button.bind(on_press=self.toggle_monitoring)
|
||||||
main_layout.add_widget(print_button)
|
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
|
return main_layout
|
||||||
|
|
||||||
def on_sap_text_change(self, instance, value):
|
def apply_config(self):
|
||||||
"""Limit SAP input to 25 characters"""
|
"""
|
||||||
if len(value) > 25:
|
Load and apply saved configuration.
|
||||||
self.sap_input.text = value[:25]
|
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):
|
def on_printer_changed(self, spinner, text):
|
||||||
"""Limit Quantity input to 25 characters"""
|
"""
|
||||||
if len(value) > 25:
|
Called when printer selection changes.
|
||||||
self.qty_input.text = value[:25]
|
Save configuration.
|
||||||
|
"""
|
||||||
|
self.save_config()
|
||||||
|
|
||||||
def on_cable_id_text_change(self, instance, value):
|
def create_tray_icon_image(self):
|
||||||
"""Limit Cable ID input to 25 characters"""
|
"""
|
||||||
if len(value) > 25:
|
Create a simple icon for the system tray.
|
||||||
self.cable_id_input.text = value[:25]
|
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):
|
def print_label(self, instance):
|
||||||
"""Handle print button press"""
|
"""Handle print button press - read from file and print"""
|
||||||
sap_nr = self.sap_input.text.strip()
|
# Read variables from file
|
||||||
quantity = self.qty_input.text.strip()
|
article, nr_art, serial = self.read_file_variables()
|
||||||
cable_id = self.cable_id_input.text.strip()
|
|
||||||
# Resolve display name to full printer name
|
# Resolve display name to full printer name
|
||||||
printer = self._get_full_printer_name(self.printer_spinner.text)
|
printer = self._get_full_printer_name(self.printer_spinner.text)
|
||||||
|
|
||||||
# Validate input
|
# Validate input
|
||||||
if not sap_nr and not quantity and not cable_id:
|
if not article and not nr_art and not serial:
|
||||||
self.show_popup("Error", "Please enter at least one field")
|
self.show_popup("Error", "No data in file or file not set", auto_dismiss_after=3)
|
||||||
return
|
return
|
||||||
|
|
||||||
# Create combined label text
|
# Create combined label text using semicolon separator
|
||||||
label_text = f"{sap_nr}|{quantity}|{cable_id}"
|
label_text = f"{article};{nr_art};{serial}"
|
||||||
|
|
||||||
# Show loading popup
|
# Show loading popup
|
||||||
popup = Popup(
|
popup = Popup(
|
||||||
@@ -389,39 +746,39 @@ class LabelPrinterApp(App):
|
|||||||
|
|
||||||
if success:
|
if success:
|
||||||
# Log the successful print action
|
# 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
|
# Use Clock.schedule_once to update UI from main thread
|
||||||
Clock.schedule_once(lambda dt: popup.dismiss(), 0)
|
Clock.schedule_once(lambda dt: popup.dismiss(), 0)
|
||||||
Clock.schedule_once(lambda dt: self.show_popup("Success", "Label printed successfully!"), 0.1)
|
Clock.schedule_once(lambda dt: self.show_popup("Success", "Label printed successfully!", auto_dismiss_after=3), 0.1)
|
||||||
# Clear inputs after successful print (but keep printer selection)
|
|
||||||
Clock.schedule_once(lambda dt: self.clear_inputs(), 0.2)
|
|
||||||
else:
|
else:
|
||||||
# Log the failed print action
|
# 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: 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:
|
except Exception as e:
|
||||||
# Log the error
|
# 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: 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 = threading.Thread(target=print_thread)
|
||||||
thread.daemon = True
|
thread.daemon = True
|
||||||
thread.start()
|
thread.start()
|
||||||
|
|
||||||
def clear_inputs(self):
|
def show_popup(self, title, message, auto_dismiss_after=None):
|
||||||
"""Clear only the input fields, preserving printer selection"""
|
"""Show a popup message
|
||||||
self.sap_input.text = ''
|
|
||||||
self.qty_input.text = ''
|
Args:
|
||||||
self.cable_id_input.text = ''
|
title (str): Popup title
|
||||||
# Printer selection is NOT cleared - it persists until user changes it
|
message (str): Popup message
|
||||||
|
auto_dismiss_after (float): Seconds after which to auto-dismiss (None = manual dismiss only)
|
||||||
def show_popup(self, title, message):
|
"""
|
||||||
"""Show a popup message"""
|
|
||||||
popup = Popup(
|
popup = Popup(
|
||||||
title=title,
|
title=title,
|
||||||
content=BoxLayout(
|
content=BoxLayout(
|
||||||
@@ -439,6 +796,10 @@ class LabelPrinterApp(App):
|
|||||||
popup.content.add_widget(close_button)
|
popup.content.add_widget(close_button)
|
||||||
|
|
||||||
popup.open()
|
popup.open()
|
||||||
|
|
||||||
|
# Auto-dismiss if specified
|
||||||
|
if auto_dismiss_after:
|
||||||
|
Clock.schedule_once(lambda dt: popup.dismiss(), auto_dismiss_after)
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
|
|||||||
121
print_label.py
121
print_label.py
@@ -200,16 +200,16 @@ def create_label_pdf(text):
|
|||||||
PDFs are saved to the pdf_backup folder.
|
PDFs are saved to the pdf_backup folder.
|
||||||
|
|
||||||
Args:
|
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:
|
Returns:
|
||||||
str: Path to the generated PDF file
|
str: Path to the generated PDF file
|
||||||
"""
|
"""
|
||||||
# Parse the text input
|
# Parse the text input - using semicolon separator
|
||||||
parts = text.split('|') if '|' in text else [text, '', '']
|
parts = text.split(';') if ';' in text else [text, '', '']
|
||||||
sap_nr = parts[0].strip() if len(parts) > 0 else ''
|
article = parts[0].strip() if len(parts) > 0 else ''
|
||||||
cantitate = parts[1].strip() if len(parts) > 1 else ''
|
nr_art = parts[1].strip() if len(parts) > 1 else ''
|
||||||
lot_number = parts[2].strip() if len(parts) > 2 else ''
|
serial = parts[2].strip() if len(parts) > 2 else ''
|
||||||
|
|
||||||
# Create PDF using high-quality generator
|
# Create PDF using high-quality generator
|
||||||
generator = PDFLabelGenerator()
|
generator = PDFLabelGenerator()
|
||||||
@@ -221,7 +221,16 @@ def create_label_pdf(text):
|
|||||||
timestamp = datetime.datetime.now().strftime("%Y%m%d_%H%M%S")
|
timestamp = datetime.datetime.now().strftime("%Y%m%d_%H%M%S")
|
||||||
pdf_filename = os.path.join(pdf_backup_dir, f"final_label_{timestamp}.pdf")
|
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):
|
def print_to_printer(printer_name, file_path):
|
||||||
@@ -249,58 +258,68 @@ def print_to_printer(printer_name, file_path):
|
|||||||
return True
|
return True
|
||||||
|
|
||||||
elif SYSTEM == "Windows":
|
elif SYSTEM == "Windows":
|
||||||
# Windows: Print directly without opening PDF viewer
|
# Windows: Print PDF using various methods
|
||||||
try:
|
try:
|
||||||
if WIN32_AVAILABLE:
|
if file_path.endswith('.pdf'):
|
||||||
import win32print
|
# Method 1: Try SumatraPDF for best silent printing
|
||||||
import win32api
|
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'):
|
sumatra_found = False
|
||||||
# Use SumatraPDF command-line or direct raw printing
|
for sumatra_path in sumatra_paths:
|
||||||
# Try printing via subprocess to avoid opening a PDF viewer window
|
if os.path.exists(sumatra_path):
|
||||||
|
sumatra_found = True
|
||||||
# Method: Use win32print raw API to send to printer silently
|
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:
|
try:
|
||||||
hprinter = win32print.OpenPrinter(printer_name)
|
import win32api
|
||||||
try:
|
win32api.ShellExecute(
|
||||||
# Start a print job
|
0, "printto", file_path,
|
||||||
job_info = ("Label Print", None, "RAW")
|
f'"{printer_name}"', ".", 0
|
||||||
hjob = win32print.StartDocPrinter(hprinter, 1, job_info)
|
)
|
||||||
win32print.StartPagePrinter(hprinter)
|
print(f"Label sent to printer via ShellExecute: {printer_name}")
|
||||||
|
|
||||||
# Read PDF file and send to printer
|
|
||||||
with open(file_path, 'rb') as f:
|
|
||||||
pdf_data = f.read()
|
|
||||||
win32print.WritePrinter(hprinter, pdf_data)
|
|
||||||
|
|
||||||
win32print.EndPagePrinter(hprinter)
|
|
||||||
win32print.EndDocPrinter(hprinter)
|
|
||||||
print(f"Label sent to printer: {printer_name}")
|
|
||||||
finally:
|
|
||||||
win32print.ClosePrinter(hprinter)
|
|
||||||
return True
|
return True
|
||||||
except Exception as raw_err:
|
except Exception as shell_err:
|
||||||
print(f"Raw print failed ({raw_err}), trying ShellExecute silently...")
|
print(f"ShellExecute print failed: {shell_err}")
|
||||||
# Fallback: Use ShellExecute with printto (minimized, auto-closes)
|
# Method 3: Open PDF with default viewer (last resort)
|
||||||
try:
|
try:
|
||||||
win32api.ShellExecute(
|
os.startfile(file_path, "print")
|
||||||
0, "printto", file_path,
|
print(f"Opened PDF for printing: {file_path}")
|
||||||
f'"{printer_name}"', ".", 0
|
print("Please close the PDF viewer after printing.")
|
||||||
)
|
|
||||||
print(f"Label sent to printer: {printer_name}")
|
|
||||||
return True
|
return True
|
||||||
except Exception as shell_err:
|
except Exception as startfile_err:
|
||||||
print(f"ShellExecute print failed: {shell_err}")
|
print(f"Could not open PDF: {startfile_err}")
|
||||||
|
print("PDF saved as backup only")
|
||||||
return True
|
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:
|
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
|
return True
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
print(f"Windows print error: {e}")
|
print(f"Windows print error: {e}")
|
||||||
|
|||||||
@@ -1,116 +1,223 @@
|
|||||||
"""
|
"""
|
||||||
PDF-based Label Printing Module
|
PDF-based Label Printing Module
|
||||||
Generates high-quality PDF labels with barcodes for printing.
|
Generates high-quality PDF labels with image and text.
|
||||||
Uses reportlab for superior PDF generation compared to PNG rasterization.
|
Uses reportlab for superior PDF generation.
|
||||||
Simplified layout: no borders, just field names and barcodes.
|
Layout: 35mm x 25mm landscape - supports SVG templates with variable substitution.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
from reportlab.lib.pagesizes import landscape
|
from reportlab.lib.pagesizes import landscape
|
||||||
from reportlab.lib.units import cm, mm
|
from reportlab.lib.units import cm, mm
|
||||||
from reportlab.pdfgen import canvas
|
from reportlab.pdfgen import canvas
|
||||||
from barcode import Code128
|
from reportlab.graphics import renderPDF
|
||||||
from barcode.writer import ImageWriter
|
|
||||||
import io
|
import io
|
||||||
from PIL import Image
|
from PIL import Image
|
||||||
import os
|
import os
|
||||||
import tempfile
|
import tempfile
|
||||||
import datetime
|
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:
|
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.
|
Initialize PDF label generator.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
label_width (float): Width in cm (default 11.5 cm)
|
label_width (float): Width in cm (default 3.5 cm = 35mm)
|
||||||
label_height (float): Height in cm (default 8 cm)
|
label_height (float): Height in cm (default 2.5 cm = 25mm)
|
||||||
dpi (int): DPI for barcode generation (default 300 for print quality)
|
dpi (int): DPI for image rendering (default 600 for high quality print)
|
||||||
"""
|
"""
|
||||||
self.label_width = label_width * cm
|
self.label_width = label_width * cm
|
||||||
self.label_height = label_height * cm
|
self.label_height = label_height * cm
|
||||||
self.dpi = dpi
|
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:
|
Args:
|
||||||
value (str): Text to encode in barcode (max 25 chars)
|
image_path (str): Path to image file
|
||||||
height_mm (int): Barcode height in mm (default 18mm for 1.8cm)
|
|
||||||
|
|
||||||
Returns:
|
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
|
return None
|
||||||
|
|
||||||
try:
|
try:
|
||||||
# Truncate to 25 characters (Code128 limitation)
|
img = Image.open(image_path)
|
||||||
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)
|
|
||||||
# Convert to RGB if needed
|
# Convert to RGB if needed
|
||||||
if img.mode != 'RGB':
|
if img.mode not in ['RGB', 'L']:
|
||||||
img = img.convert('RGB')
|
img = img.convert('RGB')
|
||||||
|
|
||||||
# Clean up temp file
|
|
||||||
try:
|
|
||||||
os.remove(temp_path)
|
|
||||||
except:
|
|
||||||
pass
|
|
||||||
|
|
||||||
return img
|
return img
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
# Log error but don't fail silently
|
print(f"Image loading error: {e}")
|
||||||
print(f"Barcode generation error for '{value}': {e}")
|
|
||||||
return None
|
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.
|
Replace variables in SVG template with actual values.
|
||||||
Each row shows label name, barcode, and value text.
|
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
sap_nr (str): SAP article number
|
svg_content (str): SVG file content as string
|
||||||
cantitate (str): Quantity value
|
variables (dict): Dictionary of variable replacements
|
||||||
lot_number (str): Lot/Cable ID
|
|
||||||
|
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)
|
filename (str): Output filename (if None, returns bytes)
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
bytes or str: PDF content as bytes or filename if saved
|
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
|
# Prepare data for rows
|
||||||
rows_data = [
|
rows_data = [
|
||||||
("SAP-Nr", sap_nr),
|
("Nr. Comanda:", comanda),
|
||||||
("Cantitate", cantitate),
|
("Nr. Art.:", article),
|
||||||
("Lot Nr", lot_number),
|
("Serial No.:", serial),
|
||||||
]
|
]
|
||||||
|
|
||||||
# Create PDF canvas in memory or to file
|
# Create PDF canvas in memory or to file
|
||||||
@@ -122,101 +229,76 @@ class PDFLabelGenerator:
|
|||||||
# Create canvas with label dimensions
|
# Create canvas with label dimensions
|
||||||
c = canvas.Canvas(pdf_buffer, pagesize=(self.label_width, self.label_height))
|
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
|
# Calculate dimensions
|
||||||
usable_width = self.label_width - 2 * self.margin
|
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
|
# Image area: 1/3 of width on the left
|
||||||
for idx, (label_name, value) in enumerate(rows_data):
|
image_width = usable_width / 3
|
||||||
y_position = self.label_height - self.margin - (idx + 1) * row_height
|
image_x = self.margin
|
||||||
|
image_y = self.margin
|
||||||
# Draw label name (small, at top of row)
|
image_height = usable_height
|
||||||
c.setFont("Helvetica-Bold", 8)
|
|
||||||
c.drawString(
|
# Text area: 2/3 of width on the right
|
||||||
self.margin,
|
text_area_x = self.margin + image_width + 1 * mm # Small gap
|
||||||
y_position + row_height - 3 * mm,
|
text_area_width = usable_width - image_width - 1 * mm
|
||||||
label_name
|
row_height = usable_height / 3
|
||||||
)
|
|
||||||
|
# Draw image on left if available
|
||||||
# Generate and draw barcode if value exists
|
if image_path and os.path.exists(image_path):
|
||||||
if value and value.strip():
|
try:
|
||||||
barcode_value = value.strip()[:25]
|
img = self.load_image(image_path)
|
||||||
|
if img:
|
||||||
# Fixed barcode height: 1.6 cm (16mm) for optimal readability
|
# Save temp file for reportlab
|
||||||
barcode_height_mm = 16
|
temp_img_file = tempfile.NamedTemporaryFile(suffix='.png', delete=False)
|
||||||
barcode_height = barcode_height_mm * mm
|
temp_img_path = temp_img_file.name
|
||||||
|
temp_img_file.close()
|
||||||
try:
|
|
||||||
barcode_img = self.generate_barcode_image(barcode_value, height_mm=barcode_height_mm)
|
|
||||||
|
|
||||||
if barcode_img:
|
# Convert to grayscale for black and white
|
||||||
# Calculate barcode dimensions
|
img_bw = img.convert('L')
|
||||||
max_barcode_width = usable_width - 2 * mm
|
img_bw.save(temp_img_path, 'PNG')
|
||||||
aspect_ratio = barcode_img.width / barcode_img.height
|
|
||||||
barcode_width = barcode_height * aspect_ratio
|
# Draw image maintaining aspect ratio
|
||||||
|
c.drawImage(
|
||||||
# Constrain width to fit in label
|
temp_img_path,
|
||||||
if barcode_width > max_barcode_width:
|
image_x,
|
||||||
barcode_width = max_barcode_width
|
image_y,
|
||||||
|
width=image_width,
|
||||||
# Save barcode temporarily and draw on PDF
|
height=image_height,
|
||||||
barcode_temp = tempfile.NamedTemporaryFile(suffix='.png', delete=False)
|
preserveAspectRatio=True,
|
||||||
barcode_path = barcode_temp.name
|
anchor='c'
|
||||||
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}]"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# 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:
|
else:
|
||||||
# Empty value - show placeholder
|
text = f"{label_name} -"
|
||||||
c.setFont("Helvetica", 8)
|
|
||||||
c.drawString(
|
# Use appropriate font size to fit (6pt = ~2.1mm height)
|
||||||
self.margin,
|
font_size = 6
|
||||||
y_position + row_height / 2,
|
c.setFont("Helvetica-Bold", font_size)
|
||||||
"(empty)"
|
|
||||||
)
|
try:
|
||||||
|
c.drawString(text_area_x, y_position, text)
|
||||||
|
except Exception as e:
|
||||||
|
print(f"Error drawing text row {idx}: {e}")
|
||||||
|
|
||||||
# Save PDF
|
# Save PDF
|
||||||
c.save()
|
c.save()
|
||||||
@@ -228,15 +310,16 @@ class PDFLabelGenerator:
|
|||||||
pdf_buffer.seek(0)
|
pdf_buffer.seek(0)
|
||||||
return pdf_buffer.getvalue()
|
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.
|
Create PDF label file and return the filename.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
sap_nr (str): SAP article number
|
comanda (str): Nr. Comanda value
|
||||||
cantitate (str): Quantity value
|
article (str): Nr. Art. value
|
||||||
lot_number (str): Lot/Cable ID
|
serial (str): Serial No. value
|
||||||
filename (str): Output filename (if None, auto-generates)
|
filename (str): Output filename (if None, auto-generates)
|
||||||
|
image_path (str): Path to accepted.png image
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
str: Path to created PDF file
|
str: Path to created PDF file
|
||||||
@@ -245,51 +328,75 @@ class PDFLabelGenerator:
|
|||||||
timestamp = datetime.datetime.now().strftime("%Y%m%d_%H%M%S")
|
timestamp = datetime.datetime.now().strftime("%Y%m%d_%H%M%S")
|
||||||
filename = f"label_{timestamp}.pdf"
|
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:
|
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:
|
Returns:
|
||||||
bytes: PDF content
|
bytes: PDF content
|
||||||
"""
|
"""
|
||||||
# Parse text
|
# Parse text - using semicolon separator
|
||||||
parts = text.split('|') if '|' in text else [text, '', '']
|
parts = text.split(';') if ';' in text else [text, '', '']
|
||||||
sap_nr = parts[0].strip() if len(parts) > 0 else ''
|
article = parts[0].strip() if len(parts) > 0 else ''
|
||||||
cantitate = parts[1].strip() if len(parts) > 1 else ''
|
nr_art = parts[1].strip() if len(parts) > 1 else ''
|
||||||
lot_number = parts[2].strip() if len(parts) > 2 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()
|
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
|
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.
|
Create PDF label file from combined text.
|
||||||
|
|
||||||
Args:
|
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)
|
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:
|
Returns:
|
||||||
str: Path to created PDF file
|
str: Path to created PDF file
|
||||||
"""
|
"""
|
||||||
# Parse text
|
# Parse text - using semicolon separator
|
||||||
parts = text.split('|') if '|' in text else [text, '', '']
|
parts = text.split(';') if ';' in text else [text, '', '']
|
||||||
sap_nr = parts[0].strip() if len(parts) > 0 else ''
|
article = parts[0].strip() if len(parts) > 0 else ''
|
||||||
cantitate = parts[1].strip() if len(parts) > 1 else ''
|
nr_art = parts[1].strip() if len(parts) > 1 else ''
|
||||||
lot_number = parts[2].strip() if len(parts) > 2 else ''
|
serial = parts[2].strip() if len(parts) > 2 else ''
|
||||||
|
|
||||||
if not filename:
|
if not filename:
|
||||||
timestamp = datetime.datetime.now().strftime("%Y%m%d_%H%M%S")
|
timestamp = datetime.datetime.now().strftime("%Y%m%d_%H%M%S")
|
||||||
filename = f"label_{timestamp}.pdf"
|
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()
|
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)
|
||||||
|
|||||||
@@ -5,3 +5,7 @@ reportlab
|
|||||||
pyinstaller>=6.0.0
|
pyinstaller>=6.0.0
|
||||||
pywin32
|
pywin32
|
||||||
wmi
|
wmi
|
||||||
|
watchdog
|
||||||
|
svglib
|
||||||
|
cairosvg
|
||||||
|
pystray
|
||||||
|
|||||||
1
sample_data.txt
Normal file
1
sample_data.txt
Normal file
@@ -0,0 +1 @@
|
|||||||
|
COM-2024-002;ART-67890;SN-20260212-TEST
|
||||||
159
test_svg_template.py
Normal file
159
test_svg_template.py
Normal file
@@ -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)
|
||||||
Reference in New Issue
Block a user