Compare commits
28 Commits
33c9c3d099
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
| 58082ed171 | |||
| f09c365384 | |||
| b204ce38fc | |||
| 1cf4482914 | |||
| b9025fcabe | |||
|
|
fa5c846ebb | ||
| 6bcfc3102b | |||
| 92714bcb51 | |||
|
|
396bf19214 | ||
|
|
37c7a5bd7a | ||
|
|
69e0f7f8b1 | ||
|
|
44771dcd11 | ||
|
|
ca42c8e3c7 | ||
|
|
9f45a02f13 | ||
|
|
6f07bb9cba | ||
|
|
1536f26fee | ||
|
|
e838d25c44 | ||
|
|
8e3893e85c | ||
|
|
f2a2ca7d97 | ||
|
|
8301fc8ef4 | ||
|
|
82949fb9bf | ||
|
|
9bfc40d733 | ||
|
|
e7aac91d51 | ||
|
|
795dd5cac2 | ||
|
|
ba54bbfa75 | ||
|
|
5e1cdfb9e5 | ||
|
|
8619debd71 | ||
|
|
184178275b |
3
.gitignore
vendored
3
.gitignore
vendored
@@ -1 +1,4 @@
|
||||
label/
|
||||
build/
|
||||
logs/
|
||||
pdf_backup/
|
||||
|
||||
178
BUILD_ON_WINDOWS.md
Normal file
178
BUILD_ON_WINDOWS.md
Normal file
@@ -0,0 +1,178 @@
|
||||
# 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
|
||||
88
DEPLOYMENT.md
Normal file
88
DEPLOYMENT.md
Normal file
@@ -0,0 +1,88 @@
|
||||
# Label Printer - Portable Deployment Guide
|
||||
|
||||
## Deployment Structure
|
||||
|
||||
The app is now **fully self-contained** with SumatraPDF embedded inside:
|
||||
|
||||
```
|
||||
LabelPrinter/
|
||||
├── LabelPrinter.exe # Main application (includes SumatraPDF inside)
|
||||
├── pdf_backup/ # Auto-created: PDF backups
|
||||
└── logs/ # Auto-created: Print logs
|
||||
```
|
||||
|
||||
**No visible folders!** SumatraPDF is bundled inside LabelPrinter.exe and extracted to a temporary location at runtime.
|
||||
|
||||
## Setup Instructions
|
||||
|
||||
### 1. Download SumatraPDF (For Building Only)
|
||||
|
||||
**This step is only needed when building the app.** SumatraPDF will be embedded inside the executable.
|
||||
|
||||
```powershell
|
||||
# PowerShell command to download SumatraPDF
|
||||
powershell -ExecutionPolicy Bypass -File setup_sumatra.ps1
|
||||
```
|
||||
|
||||
This downloads SumatraPDF portable (~5 MB) to the `SumatraPDF` folder.
|
||||
|
||||
### 2. Build the Application
|
||||
|
||||
```powershell
|
||||
.\build_windows.ps1
|
||||
```
|
||||
|
||||
The build script will:
|
||||
- Check for SumatraPDF
|
||||
- Bundle it inside the executable
|
||||
- Create `dist\LabelPrinter.exe` (~80 MB including all dependencies)
|
||||
|
||||
### 3. Deploy
|
||||
|
||||
**Simply copy `LabelPrinter.exe` to any Windows machine!**
|
||||
|
||||
```
|
||||
📁 Deployment (any folder)
|
||||
└── LabelPrinter.exe ← Just this one file!
|
||||
```
|
||||
|
||||
- No installation needed
|
||||
- No additional files or folders
|
||||
- Double-click to run
|
||||
- Works on any Windows 10/11 machine
|
||||
|
||||
## Features
|
||||
|
||||
- ✅ **Single Executable** - Everything bundled in one .exe file (~80 MB)
|
||||
- ✅ **Fully Portable** - No installation needed, no external dependencies
|
||||
- ✅ **Silent Printing** - No PDF viewer windows pop up
|
||||
- ✅ **Network Printers** - Supports printers from print servers (e.g. `\\server\printer`)
|
||||
- ✅ **PDF Backup** - All labels saved to `pdf_backup/` folder
|
||||
- ✅ **Print Logging** - CSV logs in `logs/` folder
|
||||
- ✅ **SumatraPDF Hidden** - Embedded inside, not visible to users
|
||||
|
||||
## Printer Name Display
|
||||
|
||||
Network printer names (e.g. `\\filesibiusb05\ZDesigner_ZQ630`) are automatically shortened to 20 characters in the dropdown for better display. The full printer name is used for actual printing.
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### Printing Not Working
|
||||
|
||||
1. **Check Printer Connection**: Verify printer is online and accessible
|
||||
2. **Check PDF Backup**: Labels are always saved to `pdf_backup/` folder even if printing fails
|
||||
3. **Check Logs**: View print logs in `logs/` folder for error messages
|
||||
4. **Rebuild App**: If you built the app yourself, ensure `setup_sumatra.ps1` was run first to download SumatraPDF before building
|
||||
|
||||
### Network Printers Not Showing
|
||||
|
||||
- Network printers must be installed/connected on the machine before running the app
|
||||
- For print server printers like `\\filesibiusb05\printer`, ensure the share is accessible
|
||||
- Run as administrator if printer enumeration fails
|
||||
|
||||
## Notes
|
||||
|
||||
- First run may be slower (Kivy initialization)
|
||||
- PDF backups are auto-deleted after 5 days
|
||||
- Log files are auto-deleted after 5 days
|
||||
- Supports Python 3.10-3.13 (Python 3.14+ may have issues with Kivy)
|
||||
38
LabelPrinter.spec
Normal file
38
LabelPrinter.spec
Normal file
@@ -0,0 +1,38 @@
|
||||
# -*- mode: python ; coding: utf-8 -*-
|
||||
|
||||
|
||||
a = Analysis(
|
||||
['label_printer_gui.py'],
|
||||
pathex=[],
|
||||
binaries=[('SumatraPDF\\SumatraPDF.exe', '.')],
|
||||
datas=[],
|
||||
hiddenimports=['kivy', 'PIL', 'barcode', 'reportlab', 'print_label', 'print_label_pdf'],
|
||||
hookspath=[],
|
||||
hooksconfig={},
|
||||
runtime_hooks=[],
|
||||
excludes=[],
|
||||
noarchive=False,
|
||||
optimize=0,
|
||||
)
|
||||
pyz = PYZ(a.pure)
|
||||
|
||||
exe = EXE(
|
||||
pyz,
|
||||
a.scripts,
|
||||
a.binaries,
|
||||
a.datas,
|
||||
[],
|
||||
name='LabelPrinter',
|
||||
debug=False,
|
||||
bootloader_ignore_signals=False,
|
||||
strip=False,
|
||||
upx=True,
|
||||
upx_exclude=[],
|
||||
runtime_tmpdir=None,
|
||||
console=False,
|
||||
disable_windowed_traceback=False,
|
||||
argv_emulation=False,
|
||||
target_arch=None,
|
||||
codesign_identity=None,
|
||||
entitlements_file=None,
|
||||
)
|
||||
227
PYINSTALLER_GUIDE.md
Normal file
227
PYINSTALLER_GUIDE.md
Normal file
@@ -0,0 +1,227 @@
|
||||
# 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
Normal file
234
README.md
Normal file
@@ -0,0 +1,234 @@
|
||||
# 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
|
||||
BIN
SumatraPDF/SumatraPDF.exe
Normal file
BIN
SumatraPDF/SumatraPDF.exe
Normal file
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
83
build_exe.py
Normal file
83
build_exe.py
Normal file
@@ -0,0 +1,83 @@
|
||||
"""
|
||||
PyInstaller build script for Label Printer GUI
|
||||
Run this to create a standalone Windows executable
|
||||
|
||||
IMPORTANT: This script MUST be run on Windows to generate a Windows .exe file.
|
||||
If run on Linux/macOS, it will create a Linux/macOS binary that won't work on Windows.
|
||||
|
||||
To build for Windows:
|
||||
1. Copy this project to a Windows machine
|
||||
2. Install dependencies: pip install -r requirements_windows.txt
|
||||
3. Run this script: python build_exe.py
|
||||
4. The Windows .exe will be created in the dist/ folder
|
||||
"""
|
||||
|
||||
import os
|
||||
import sys
|
||||
import subprocess
|
||||
|
||||
# Get the current directory
|
||||
script_dir = os.path.dirname(os.path.abspath(__file__))
|
||||
|
||||
# PyInstaller arguments
|
||||
args = [
|
||||
'label_printer_gui.py',
|
||||
'--onefile', # Create a single executable
|
||||
'--windowed', # Don't show console window
|
||||
'--name=LabelPrinter', # Executable name
|
||||
'--distpath=./dist', # Output directory
|
||||
'--workpath=./build', # Work directory (was --buildpath)
|
||||
'--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',
|
||||
]
|
||||
|
||||
if __name__ == '__main__':
|
||||
print("=" * 60)
|
||||
print("Label Printer GUI - PyInstaller Build")
|
||||
print("=" * 60)
|
||||
print("\nBuilding standalone executable...")
|
||||
print("This may take a few minutes...\n")
|
||||
|
||||
# Change to script directory
|
||||
os.chdir(script_dir)
|
||||
|
||||
# Run PyInstaller directly with subprocess for better error reporting
|
||||
try:
|
||||
result = subprocess.run(['pyinstaller'] + args, check=True)
|
||||
|
||||
print("\n" + "=" * 60)
|
||||
print("Build Complete!")
|
||||
print("=" * 60)
|
||||
print("\nExecutable location: ./dist/LabelPrinter.exe")
|
||||
print("\nYou can now:")
|
||||
print("1. Double-click LabelPrinter.exe to run")
|
||||
print("2. Share the exe with others")
|
||||
print("3. Create a shortcut on desktop")
|
||||
print("\nNote: First run may take a moment as Kivy initializes")
|
||||
except subprocess.CalledProcessError as e:
|
||||
print("\n" + "=" * 60)
|
||||
print("Build Failed!")
|
||||
print("=" * 60)
|
||||
print(f"\nError code: {e.returncode}")
|
||||
print("\nPlease check the error messages above for details.")
|
||||
sys.exit(1)
|
||||
except Exception as e:
|
||||
print(f"\nFatal error: {e}")
|
||||
sys.exit(1)
|
||||
99
build_windows.bat
Normal file
99
build_windows.bat
Normal file
@@ -0,0 +1,99 @@
|
||||
@echo off
|
||||
REM Label Printer - Windows Build Script (Single File EXE)
|
||||
REM This script builds a standalone LabelPrinter.exe on Windows
|
||||
REM Requirements: Python 3.10-3.13 installed and in PATH
|
||||
REM Note: Python 3.14+ may have compatibility issues
|
||||
|
||||
setlocal enabledelayedexpansion
|
||||
|
||||
echo.
|
||||
echo ========================================================
|
||||
echo Label Printer - Windows Build Script
|
||||
echo Creates: LabelPrinter.exe (Single File)
|
||||
echo ========================================================
|
||||
echo.
|
||||
|
||||
REM Check if Python is installed
|
||||
python --version >nul 2>&1
|
||||
if errorlevel 1 (
|
||||
echo ERROR: Python is not installed or not in PATH
|
||||
echo Please install Python 3.10-3.13 from https://www.python.org/
|
||||
echo Make sure to check "Add Python to PATH" during installation
|
||||
pause
|
||||
exit /b 1
|
||||
)
|
||||
|
||||
echo [1/5] Checking Python installation...
|
||||
python --version
|
||||
echo.
|
||||
|
||||
REM Upgrade pip
|
||||
echo [2/5] Upgrading pip, setuptools, and wheel...
|
||||
python -m pip install --upgrade pip setuptools wheel
|
||||
if errorlevel 1 (
|
||||
echo ERROR: Failed to upgrade pip
|
||||
pause
|
||||
exit /b 1
|
||||
)
|
||||
echo.
|
||||
|
||||
REM Install dependencies
|
||||
echo [3/5] Installing dependencies...
|
||||
echo Installing: python-barcode, pillow, reportlab, kivy, pyinstaller, pywin32, wmi...
|
||||
pip install python-barcode pillow reportlab kivy==2.2.1 pyinstaller==6.1.0 pywin32 wmi
|
||||
if errorlevel 1 (
|
||||
echo ERROR: Failed to install dependencies
|
||||
pause
|
||||
exit /b 1
|
||||
)
|
||||
echo.
|
||||
|
||||
REM Clean old build
|
||||
echo [4/5] Cleaning old build artifacts...
|
||||
if exist "dist" rmdir /s /q dist
|
||||
if exist "build" rmdir /s /q build
|
||||
if exist "*.spec" del *.spec
|
||||
echo.
|
||||
|
||||
REM Build with PyInstaller
|
||||
echo [5/5] Building executable with PyInstaller...
|
||||
echo This may take 5-15 minutes, please wait...
|
||||
echo.
|
||||
|
||||
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
|
||||
|
||||
if errorlevel 1 (
|
||||
echo.
|
||||
echo ERROR: Build failed!
|
||||
echo Please check the error messages above.
|
||||
pause
|
||||
exit /b 1
|
||||
)
|
||||
|
||||
echo.
|
||||
echo ========================================================
|
||||
echo BUILD SUCCESSFUL!
|
||||
echo ========================================================
|
||||
echo.
|
||||
echo Executable Location: dist\LabelPrinter.exe
|
||||
echo.
|
||||
echo Next steps:
|
||||
echo 1. Navigate to the dist folder
|
||||
echo 2. Double-click LabelPrinter.exe to run
|
||||
echo 3. You can copy LabelPrinter.exe to other machines
|
||||
echo.
|
||||
echo Note: First run may take a moment as Kivy initializes
|
||||
echo.
|
||||
pause
|
||||
130
build_windows.ps1
Normal file
130
build_windows.ps1
Normal file
@@ -0,0 +1,130 @@
|
||||
# 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/6] Checking for SumatraPDF..." -ForegroundColor Cyan
|
||||
$sumatraPath = "SumatraPDF\SumatraPDF.exe"
|
||||
if (-not (Test-Path $sumatraPath)) {
|
||||
Write-Host ""
|
||||
Write-Host "WARNING: SumatraPDF not found!" -ForegroundColor Yellow
|
||||
Write-Host "SumatraPDF is required for silent PDF printing." -ForegroundColor Yellow
|
||||
Write-Host ""
|
||||
Write-Host "Run the setup script first:" -ForegroundColor Yellow
|
||||
Write-Host " powershell -ExecutionPolicy Bypass -File setup_sumatra.ps1" -ForegroundColor Cyan
|
||||
Write-Host ""
|
||||
$response = Read-Host "Continue building without SumatraPDF? (y/n)"
|
||||
if ($response -ne "y") {
|
||||
Write-Host "Build cancelled."
|
||||
Read-Host "Press Enter to exit"
|
||||
exit 1
|
||||
}
|
||||
Write-Host ""
|
||||
Write-Host "Building without SumatraPDF (PDF printing will not work)..." -ForegroundColor Yellow
|
||||
$addBinaryArg = @()
|
||||
} else {
|
||||
Write-Host "Found: $sumatraPath" -ForegroundColor Green
|
||||
# Add SumatraPDF as bundled binary (will be embedded inside the exe)
|
||||
$addBinaryArg = @("--add-binary", "$sumatraPath;.")
|
||||
}
|
||||
Write-Host ""
|
||||
|
||||
Write-Host "[5/6] 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 "[6/6] 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"
|
||||
)
|
||||
|
||||
# Add SumatraPDF binary if available (bundles inside the exe)
|
||||
if ($addBinaryArg) {
|
||||
$pyinstallerArgs += $addBinaryArg
|
||||
}
|
||||
|
||||
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"
|
||||
BIN
dist/LabelPrinter.exe
vendored
Normal file
BIN
dist/LabelPrinter.exe
vendored
Normal file
Binary file not shown.
114
documentation/WINDOWS_SETUP.md
Normal file
114
documentation/WINDOWS_SETUP.md
Normal file
@@ -0,0 +1,114 @@
|
||||
# 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.
|
||||
5
documentation/requirements_windows.txt
Normal file
5
documentation/requirements_windows.txt
Normal file
@@ -0,0 +1,5 @@
|
||||
python-barcode
|
||||
pillow
|
||||
reportlab
|
||||
kivy
|
||||
pywin32
|
||||
@@ -18,7 +18,11 @@ from kivy.graphics import Color, Rectangle
|
||||
|
||||
import os
|
||||
import threading
|
||||
from print_label import print_label_standalone
|
||||
import platform
|
||||
import time
|
||||
import datetime
|
||||
import glob
|
||||
from print_label import print_label_standalone, get_available_printers
|
||||
from kivy.clock import Clock
|
||||
|
||||
# Set window size - portrait/phone dimensions (375x667 like iPhone)
|
||||
@@ -34,18 +38,175 @@ class LabelPrinterApp(App):
|
||||
|
||||
def __init__(self, **kwargs):
|
||||
super().__init__(**kwargs)
|
||||
self.available_printers = self.get_available_printers()
|
||||
# Build printer display names and mapping to full names
|
||||
full_printers = get_available_printers()
|
||||
self.printer_display_map = {} # display_name -> full_name
|
||||
self.available_printers = []
|
||||
for full_name in full_printers:
|
||||
display_name = self._shorten_printer_name(full_name)
|
||||
# Ensure unique display names
|
||||
if display_name in self.printer_display_map:
|
||||
display_name = full_name[:20]
|
||||
self.printer_display_map[display_name] = full_name
|
||||
self.available_printers.append(display_name)
|
||||
# Clean old PDF backup files on startup
|
||||
self.cleanup_old_pdfs()
|
||||
# Clean old log files on startup
|
||||
self.cleanup_old_logs()
|
||||
|
||||
def get_available_printers(self):
|
||||
"""Get list of available printers from CUPS"""
|
||||
def _shorten_printer_name(self, name, max_len=20):
|
||||
"""Shorten printer name for display (max 20 chars).
|
||||
For network printers like \\\\server\\printer, show just the printer part."""
|
||||
if name.startswith('\\\\'):
|
||||
# Network printer: \\server\printer -> extract printer name
|
||||
parts = name.strip('\\').split('\\')
|
||||
if len(parts) >= 2:
|
||||
short = parts[-1] # Just the printer name
|
||||
else:
|
||||
short = name
|
||||
else:
|
||||
short = name
|
||||
# Truncate to max_len
|
||||
if len(short) > max_len:
|
||||
short = short[:max_len]
|
||||
return short
|
||||
|
||||
def _get_full_printer_name(self, display_name):
|
||||
"""Resolve display name back to full printer name for printing."""
|
||||
return self.printer_display_map.get(display_name, display_name)
|
||||
|
||||
def cleanup_old_pdfs(self, days=5):
|
||||
"""
|
||||
Delete PDF files older than specified days from pdf_backup folder.
|
||||
|
||||
Args:
|
||||
days (int): Delete files older than this many days (default: 5)
|
||||
"""
|
||||
pdf_backup_dir = 'pdf_backup'
|
||||
|
||||
# Create folder if it doesn't exist
|
||||
if not os.path.exists(pdf_backup_dir):
|
||||
os.makedirs(pdf_backup_dir, exist_ok=True)
|
||||
return
|
||||
|
||||
try:
|
||||
import cups
|
||||
conn = cups.Connection()
|
||||
printers = conn.getPrinters()
|
||||
return list(printers.keys()) if printers else ["PDF"]
|
||||
current_time = time.time()
|
||||
cutoff_time = current_time - (days * 24 * 3600) # Convert days to seconds
|
||||
|
||||
for filename in os.listdir(pdf_backup_dir):
|
||||
file_path = os.path.join(pdf_backup_dir, filename)
|
||||
|
||||
# Only process PDF files
|
||||
if not filename.endswith('.pdf'):
|
||||
continue
|
||||
|
||||
# Check if file is older than cutoff
|
||||
if os.path.isfile(file_path):
|
||||
file_mtime = os.path.getmtime(file_path)
|
||||
if file_mtime < cutoff_time:
|
||||
try:
|
||||
os.remove(file_path)
|
||||
print(f"Deleted old PDF: {filename}")
|
||||
except Exception as e:
|
||||
print(f"Failed to delete {filename}: {e}")
|
||||
except Exception as e:
|
||||
print(f"Error getting printers: {e}")
|
||||
return ["PDF"]
|
||||
print(f"Error during PDF cleanup: {e}")
|
||||
|
||||
def cleanup_old_logs(self, days=5):
|
||||
"""
|
||||
Delete log files older than specified days from logs folder.
|
||||
|
||||
Args:
|
||||
days (int): Delete files older than this many days (default: 5)
|
||||
"""
|
||||
logs_dir = 'logs'
|
||||
|
||||
# Create folder if it doesn't exist
|
||||
if not os.path.exists(logs_dir):
|
||||
os.makedirs(logs_dir, exist_ok=True)
|
||||
return
|
||||
|
||||
try:
|
||||
current_time = time.time()
|
||||
cutoff_time = current_time - (days * 24 * 3600) # Convert days to seconds
|
||||
|
||||
for filename in os.listdir(logs_dir):
|
||||
file_path = os.path.join(logs_dir, filename)
|
||||
|
||||
# Process both .log and .csv files
|
||||
if not (filename.endswith('.log') or filename.endswith('.csv')):
|
||||
continue
|
||||
|
||||
# Check if file is older than cutoff
|
||||
if os.path.isfile(file_path):
|
||||
file_mtime = os.path.getmtime(file_path)
|
||||
if file_mtime < cutoff_time:
|
||||
try:
|
||||
os.remove(file_path)
|
||||
print(f"Deleted old log: {filename}")
|
||||
except Exception as e:
|
||||
print(f"Failed to delete {filename}: {e}")
|
||||
except Exception as e:
|
||||
print(f"Error during log cleanup: {e}")
|
||||
|
||||
def log_print_action(self, sap_nr, quantity, cable_id, printer, pdf_filename, success):
|
||||
"""
|
||||
Log the print action to a CSV log file (table format).
|
||||
|
||||
Args:
|
||||
sap_nr (str): SAP article number
|
||||
quantity (str): Quantity value
|
||||
cable_id (str): Cable ID
|
||||
printer (str): Printer name
|
||||
pdf_filename (str): Path to the generated PDF file
|
||||
success (bool): Whether the print was successful
|
||||
"""
|
||||
logs_dir = 'logs'
|
||||
|
||||
# Create logs folder if it doesn't exist
|
||||
os.makedirs(logs_dir, exist_ok=True)
|
||||
|
||||
try:
|
||||
# Create log filename with date
|
||||
log_date = datetime.datetime.now().strftime("%Y%m%d")
|
||||
log_filename = os.path.join(logs_dir, f"print_log_{log_date}.csv")
|
||||
|
||||
# Create log entry values
|
||||
timestamp = datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")
|
||||
status = "SUCCESS" if success else "FAILED"
|
||||
|
||||
# Escape CSV values (handle commas and quotes)
|
||||
def escape_csv(value):
|
||||
"""Escape CSV special characters"""
|
||||
value = str(value)
|
||||
if ',' in value or '"' in value or '\n' in value:
|
||||
value = '"' + value.replace('"', '""') + '"'
|
||||
return value
|
||||
|
||||
# Create CSV line
|
||||
log_line = (
|
||||
f"{timestamp},{status},"
|
||||
f"{escape_csv(sap_nr)},"
|
||||
f"{escape_csv(quantity)},"
|
||||
f"{escape_csv(cable_id)},"
|
||||
f"{escape_csv(printer)},"
|
||||
f"{escape_csv(pdf_filename)}\n"
|
||||
)
|
||||
|
||||
# Check if file exists to add header on first entry
|
||||
file_exists = os.path.isfile(log_filename)
|
||||
|
||||
# Write to log file
|
||||
with open(log_filename, 'a', encoding='utf-8') as f:
|
||||
# Add header if file is new
|
||||
if not file_exists:
|
||||
f.write("Timestamp,Status,SAP-Nr,Quantity,Cable ID,Printer,PDF File\n")
|
||||
# Append log entry
|
||||
f.write(log_line)
|
||||
|
||||
print(f"Log entry saved to: {log_filename}")
|
||||
except Exception as e:
|
||||
print(f"Error saving log entry: {e}")
|
||||
|
||||
def build(self):
|
||||
"""Build the simplified single-column UI"""
|
||||
@@ -144,7 +305,8 @@ class LabelPrinterApp(App):
|
||||
values=self.available_printers,
|
||||
size_hint_y=None,
|
||||
height=45,
|
||||
font_size='12sp'
|
||||
font_size='12sp',
|
||||
sync_height=True,
|
||||
)
|
||||
self.printer_spinner = printer_spinner
|
||||
form_layout.add_widget(printer_spinner)
|
||||
@@ -186,7 +348,8 @@ class LabelPrinterApp(App):
|
||||
sap_nr = self.sap_input.text.strip()
|
||||
quantity = self.qty_input.text.strip()
|
||||
cable_id = self.cable_id_input.text.strip()
|
||||
printer = self.printer_spinner.text
|
||||
# Resolve display name to full printer name
|
||||
printer = self._get_full_printer_name(self.printer_spinner.text)
|
||||
|
||||
# Validate input
|
||||
if not sap_nr and not quantity and not cable_id:
|
||||
@@ -212,18 +375,37 @@ class LabelPrinterApp(App):
|
||||
|
||||
# Print in background thread (using PDF by default)
|
||||
def print_thread():
|
||||
pdf_filename = None
|
||||
success = False
|
||||
try:
|
||||
success = print_label_standalone(label_text, printer, preview=0, use_pdf=True)
|
||||
|
||||
# Get the PDF filename that was created
|
||||
# Files are saved to pdf_backup/ with timestamp
|
||||
pdf_files = glob.glob('pdf_backup/final_label_*.pdf')
|
||||
if pdf_files:
|
||||
# Get the most recently created PDF file
|
||||
pdf_filename = max(pdf_files, key=os.path.getctime)
|
||||
|
||||
if success:
|
||||
# Log the successful print action
|
||||
self.log_print_action(sap_nr, quantity, cable_id, printer, pdf_filename or "unknown", True)
|
||||
|
||||
# Use Clock.schedule_once to update UI from main thread
|
||||
Clock.schedule_once(lambda dt: popup.dismiss(), 0)
|
||||
Clock.schedule_once(lambda dt: self.show_popup("Success", "Label printed successfully!"), 0.1)
|
||||
# Clear inputs after successful print
|
||||
Clock.schedule_once(lambda dt: self.show_popup("Success", "Label printed successfully!", auto_dismiss=True), 0.1)
|
||||
# Clear inputs after successful print (but keep printer selection)
|
||||
Clock.schedule_once(lambda dt: self.clear_inputs(), 0.2)
|
||||
else:
|
||||
# Log the failed print action
|
||||
self.log_print_action(sap_nr, quantity, cable_id, printer, pdf_filename or "unknown", False)
|
||||
|
||||
Clock.schedule_once(lambda dt: popup.dismiss(), 0)
|
||||
Clock.schedule_once(lambda dt: self.show_popup("Error", "Failed to print label"), 0.1)
|
||||
except Exception as e:
|
||||
# Log the error
|
||||
self.log_print_action(sap_nr, quantity, cable_id, printer, pdf_filename or "unknown", False)
|
||||
|
||||
Clock.schedule_once(lambda dt: popup.dismiss(), 0)
|
||||
Clock.schedule_once(lambda dt: self.show_popup("Error", f"Print error: {str(e)}"), 0.1)
|
||||
|
||||
@@ -232,13 +414,20 @@ class LabelPrinterApp(App):
|
||||
thread.start()
|
||||
|
||||
def clear_inputs(self):
|
||||
"""Clear all input fields"""
|
||||
"""Clear only the input fields, preserving printer selection"""
|
||||
self.sap_input.text = ''
|
||||
self.qty_input.text = ''
|
||||
self.cable_id_input.text = ''
|
||||
# Printer selection is NOT cleared - it persists until user changes it
|
||||
|
||||
def show_popup(self, title, message):
|
||||
"""Show a popup message"""
|
||||
def show_popup(self, title, message, auto_dismiss=False):
|
||||
"""Show a popup message
|
||||
|
||||
Args:
|
||||
title (str): Popup title
|
||||
message (str): Popup message
|
||||
auto_dismiss (bool): If True, popup will auto-dismiss after 3 seconds
|
||||
"""
|
||||
popup = Popup(
|
||||
title=title,
|
||||
content=BoxLayout(
|
||||
@@ -256,6 +445,10 @@ class LabelPrinterApp(App):
|
||||
popup.content.add_widget(close_button)
|
||||
|
||||
popup.open()
|
||||
|
||||
# Auto-dismiss after 3 seconds if requested
|
||||
if auto_dismiss:
|
||||
Clock.schedule_once(lambda dt: popup.dismiss(), 3)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
|
||||
7
logs/print_log_20260206.log
Normal file
7
logs/print_log_20260206.log
Normal file
@@ -0,0 +1,7 @@
|
||||
[2026-02-06 08:30:44] SUCCESS
|
||||
SAP-Nr: jgvkdjrdkh
|
||||
Quantity: 300
|
||||
Cable ID: jdflhfgvkjdzhee6465758382
|
||||
Printer: PDF
|
||||
PDF File: pdf_backup/final_label_20260206_083044.pdf
|
||||
---
|
||||
103
pdf_backup/final_label_20260206_083044.pdf
Normal file
103
pdf_backup/final_label_20260206_083044.pdf
Normal file
File diff suppressed because one or more lines are too long
309
print_label.py
309
print_label.py
@@ -1,31 +1,92 @@
|
||||
from PIL import Image, ImageDraw, ImageFont
|
||||
import barcode
|
||||
from barcode.writer import ImageWriter
|
||||
import cups, time, os, datetime
|
||||
import time
|
||||
import os
|
||||
import sys
|
||||
import datetime
|
||||
import platform
|
||||
import subprocess
|
||||
from print_label_pdf import PDFLabelGenerator
|
||||
|
||||
#functie de printare etichete pe un printer specificat cu un preview opțional
|
||||
# Aceasta funcție creează o imagine cu un cod de bare și text, apoi o trimite la imprimantă.
|
||||
# Dacă este specificat un preview, afișează o fereastră de previzualizare înainte de a imprima.
|
||||
# Dimensiunea etichetei este de 9x5 cm la 300 DPI, cu un cadru exterior și două cadre interioare pentru codul de bare și text.
|
||||
# Codul de bare este generat folosind formatul Code128, iar textul este afișat sub codul de bare cu
|
||||
# o dimensiune de font maximizată pentru a se potrivi în cadrul textului
|
||||
# Imaginile sunt create folosind biblioteca PIL, iar imprimarea se face prin intermediul
|
||||
# bibliotecii CUPS pentru gestionarea imprimantelor.
|
||||
# Această funcție este utilă pentru a crea etichete personalizate cu coduri de bare și text, care pot fi utilizate în diverse aplicații, cum ar fi etichetarea produselor, inventariere sau organizarea documentelor
|
||||
#mod de utilizare in cadrul unui program se copie fisierul print_label.py in directorul de lucru
|
||||
# si se apeleaza functia print_label_standalone cu parametrii corespunzători:
|
||||
# - value: textul de afișat pe etichetă
|
||||
# - printer: numele imprimantei pe care se va face printarea
|
||||
# - preview: 0 pentru a nu afișa previzualizarea, 1-3 pentru o previzualizare de 3 secunde, >3 pentru o previzualizare de 5 secunde
|
||||
# Cross-platform printer support
|
||||
try:
|
||||
import cups
|
||||
CUPS_AVAILABLE = True
|
||||
except ImportError:
|
||||
CUPS_AVAILABLE = False
|
||||
|
||||
# se recomanda instalarea si setarea imprimantei in sistemul de operare
|
||||
# pentru a putea fi utilizata de catre biblioteca CUPS
|
||||
# se verifica proprietatile imprimantei in cups sa fie setata dimensiunea corecta a etichetei
|
||||
# pentru a instala biblioteca barcode se foloseste comanda pip install python-barcode
|
||||
# pentru a instala biblioteca PIL se foloseste comanda pip install pillow
|
||||
# pentru a instala biblioteca CUPS se foloseste comanda pip install pycups
|
||||
# pentru a instala biblioteca Tkinter se foloseste comanda sudo apt-get install python3-tk
|
||||
try:
|
||||
import win32api
|
||||
import win32print
|
||||
WIN32_AVAILABLE = True
|
||||
except ImportError:
|
||||
WIN32_AVAILABLE = False
|
||||
|
||||
SYSTEM = platform.system() # 'Linux', 'Windows', 'Darwin'
|
||||
|
||||
|
||||
def get_available_printers():
|
||||
"""
|
||||
Get list of available printers (cross-platform).
|
||||
Includes both local and network printers on Windows.
|
||||
|
||||
Returns:
|
||||
list: List of available printer names, with "PDF" as fallback
|
||||
"""
|
||||
try:
|
||||
if SYSTEM == "Linux" and CUPS_AVAILABLE:
|
||||
# Linux: Use CUPS
|
||||
conn = cups.Connection()
|
||||
printers = conn.getPrinters()
|
||||
return list(printers.keys()) if printers else ["PDF"]
|
||||
|
||||
elif SYSTEM == "Windows":
|
||||
# Windows: Get local + connected printers (includes print server connections)
|
||||
try:
|
||||
printers = []
|
||||
|
||||
# PRINTER_ENUM_LOCAL | PRINTER_ENUM_CONNECTIONS captures:
|
||||
# - Locally installed printers
|
||||
# - Printers connected from a print server (e.g. \\server\printer)
|
||||
try:
|
||||
flags = win32print.PRINTER_ENUM_LOCAL | win32print.PRINTER_ENUM_CONNECTIONS
|
||||
for printer_info in win32print.EnumPrinters(flags):
|
||||
printer_name = printer_info[2]
|
||||
if printer_name and printer_name not in printers:
|
||||
printers.append(printer_name)
|
||||
except Exception as e:
|
||||
print(f"Error enumerating printers: {e}")
|
||||
|
||||
# Add PDF as fallback option
|
||||
if "PDF" not in printers:
|
||||
printers.append("PDF")
|
||||
|
||||
return printers if printers else ["PDF"]
|
||||
except Exception as e:
|
||||
print(f"Error getting Windows printers: {e}")
|
||||
return ["PDF"]
|
||||
|
||||
elif SYSTEM == "Darwin":
|
||||
# macOS: Use lpstat command
|
||||
try:
|
||||
result = subprocess.run(["lpstat", "-p", "-d"],
|
||||
capture_output=True, text=True)
|
||||
printers = []
|
||||
for line in result.stdout.split('\n'):
|
||||
if line.startswith('printer'):
|
||||
printer_name = line.split()[1]
|
||||
printers.append(printer_name)
|
||||
return printers if printers else ["PDF"]
|
||||
except:
|
||||
return ["PDF"]
|
||||
|
||||
else:
|
||||
return ["PDF"]
|
||||
|
||||
except Exception as e:
|
||||
print(f"Error getting printers: {e}")
|
||||
return ["PDF"]
|
||||
|
||||
|
||||
def create_label_image(text):
|
||||
@@ -164,6 +225,194 @@ def create_label_pdf(text):
|
||||
return generator.create_label_pdf(sap_nr, cantitate, lot_number, pdf_filename)
|
||||
|
||||
|
||||
def print_to_printer(printer_name, file_path):
|
||||
"""
|
||||
Print file to printer (cross-platform).
|
||||
|
||||
Args:
|
||||
printer_name (str): Name of printer or "PDF" for PDF output
|
||||
file_path (str): Path to file to print
|
||||
|
||||
Returns:
|
||||
bool: True if successful
|
||||
"""
|
||||
try:
|
||||
if printer_name == "PDF":
|
||||
# PDF output - file is already saved
|
||||
print(f"PDF output: {file_path}")
|
||||
return True
|
||||
|
||||
elif SYSTEM == "Linux" and CUPS_AVAILABLE:
|
||||
# Linux: Use CUPS
|
||||
conn = cups.Connection()
|
||||
conn.printFile(printer_name, file_path, "Label Print", {})
|
||||
print(f"Label sent to printer: {printer_name}")
|
||||
return True
|
||||
|
||||
elif SYSTEM == "Windows":
|
||||
# Windows: Print PDF silently without any viewer opening
|
||||
try:
|
||||
if WIN32_AVAILABLE:
|
||||
import win32print
|
||||
import win32api
|
||||
|
||||
if file_path.endswith('.pdf'):
|
||||
# Try silent printing methods (no viewer opens)
|
||||
import os
|
||||
import winreg
|
||||
|
||||
printed = False
|
||||
|
||||
# Method 1: SumatraPDF (bundled inside exe or external)
|
||||
sumatra_paths = []
|
||||
|
||||
# Get the directory where this script/exe is running
|
||||
if getattr(sys, 'frozen', False):
|
||||
# Running as compiled executable
|
||||
# PyInstaller extracts bundled files to sys._MEIPASS temp folder
|
||||
if hasattr(sys, '_MEIPASS'):
|
||||
# Check bundled version first (inside the exe)
|
||||
bundled_sumatra = os.path.join(sys._MEIPASS, 'SumatraPDF.exe')
|
||||
sumatra_paths.append(bundled_sumatra)
|
||||
|
||||
# Also check app directory for external version
|
||||
app_dir = os.path.dirname(sys.executable)
|
||||
sumatra_paths.append(os.path.join(app_dir, "SumatraPDF", "SumatraPDF.exe"))
|
||||
sumatra_paths.append(os.path.join(app_dir, "SumatraPDF.exe"))
|
||||
else:
|
||||
# Running as script - check local folders
|
||||
app_dir = os.path.dirname(os.path.abspath(__file__))
|
||||
sumatra_paths.append(os.path.join(app_dir, "SumatraPDF", "SumatraPDF.exe"))
|
||||
sumatra_paths.append(os.path.join(app_dir, "SumatraPDF.exe"))
|
||||
|
||||
# Then check system installations
|
||||
sumatra_paths.extend([
|
||||
r"C:\Program Files\SumatraPDF\SumatraPDF.exe",
|
||||
r"C:\Program Files (x86)\SumatraPDF\SumatraPDF.exe",
|
||||
])
|
||||
|
||||
for sumatra_path in sumatra_paths:
|
||||
if os.path.exists(sumatra_path):
|
||||
try:
|
||||
subprocess.run([
|
||||
sumatra_path,
|
||||
"-print-to",
|
||||
printer_name,
|
||||
file_path,
|
||||
"-print-settings",
|
||||
"fit,landscape",
|
||||
"-silent",
|
||||
"-exit-when-done"
|
||||
], check=False, creationflags=subprocess.CREATE_NO_WINDOW)
|
||||
print(f"Label sent to printer via SumatraPDF: {printer_name}")
|
||||
printed = True
|
||||
break
|
||||
except Exception as e:
|
||||
print(f"SumatraPDF error: {e}")
|
||||
|
||||
# Method 2: Adobe Reader silent printing
|
||||
if not printed:
|
||||
adobe_path = None
|
||||
for key_path in [
|
||||
r"SOFTWARE\Microsoft\Windows\CurrentVersion\App Paths\AcroRd32.exe",
|
||||
r"SOFTWARE\Microsoft\Windows\CurrentVersion\App Paths\Acrobat.exe"
|
||||
]:
|
||||
try:
|
||||
key = winreg.OpenKey(winreg.HKEY_LOCAL_MACHINE, key_path)
|
||||
adobe_path, _ = winreg.QueryValueEx(key, "")
|
||||
winreg.CloseKey(key)
|
||||
break
|
||||
except:
|
||||
pass
|
||||
|
||||
if adobe_path and os.path.exists(adobe_path):
|
||||
try:
|
||||
subprocess.run([
|
||||
adobe_path,
|
||||
"/t", # Print and close
|
||||
file_path,
|
||||
printer_name
|
||||
], check=False, creationflags=subprocess.CREATE_NO_WINDOW)
|
||||
print(f"Label sent to printer via Adobe Reader: {printer_name}")
|
||||
printed = True
|
||||
except:
|
||||
pass
|
||||
|
||||
# Method 3: GhostScript (if installed)
|
||||
if not printed:
|
||||
gs_paths = [
|
||||
r"C:\Program Files\gs\gs10.02.1\bin\gswin64c.exe",
|
||||
r"C:\Program Files (x86)\gs\gs10.02.1\bin\gswin32c.exe",
|
||||
]
|
||||
# Try to find gswin in PATH
|
||||
try:
|
||||
gs_result = subprocess.run(['where', 'gswin64c'],
|
||||
capture_output=True, text=True, check=False)
|
||||
if gs_result.returncode == 0:
|
||||
gs_paths.insert(0, gs_result.stdout.strip().split('\n')[0])
|
||||
except:
|
||||
pass
|
||||
|
||||
for gs_path in gs_paths:
|
||||
if os.path.exists(gs_path):
|
||||
try:
|
||||
subprocess.run([
|
||||
gs_path,
|
||||
"-dNOPAUSE", "-dBATCH", "-dQUIET",
|
||||
f"-sDEVICE=mswinpr2",
|
||||
f"-sOutputFile=%printer%{printer_name}",
|
||||
file_path
|
||||
], check=False, creationflags=subprocess.CREATE_NO_WINDOW)
|
||||
print(f"Label sent to printer via GhostScript: {printer_name}")
|
||||
printed = True
|
||||
break
|
||||
except:
|
||||
pass
|
||||
|
||||
if not printed:
|
||||
# Fallback: Let user know and save PDF
|
||||
print("=" * 60)
|
||||
print("NOTICE: Silent PDF printing requires SumatraPDF")
|
||||
print("SumatraPDF not found (should be bundled inside the app)")
|
||||
print("If you built the app yourself, ensure SumatraPDF.exe is downloaded first.")
|
||||
print("Run: setup_sumatra.ps1 before building")
|
||||
print("=" * 60)
|
||||
print(f"PDF saved to: {file_path}")
|
||||
print("The PDF can be printed manually.")
|
||||
|
||||
return True
|
||||
else:
|
||||
# Non-PDF files
|
||||
subprocess.run(['notepad', '/p', file_path],
|
||||
check=False,
|
||||
creationflags=subprocess.CREATE_NO_WINDOW)
|
||||
print(f"Label sent to printer: {printer_name}")
|
||||
return True
|
||||
else:
|
||||
print("win32print not available, PDF saved as backup only")
|
||||
return True
|
||||
except Exception as e:
|
||||
print(f"Windows print error: {e}")
|
||||
print("PDF backup saved as fallback")
|
||||
return True
|
||||
|
||||
elif SYSTEM == "Darwin":
|
||||
# macOS: Use lp command
|
||||
subprocess.run(["lp", "-d", printer_name, file_path], check=True)
|
||||
print(f"Label sent to printer: {printer_name}")
|
||||
return True
|
||||
|
||||
else:
|
||||
print(f"Unsupported system: {SYSTEM}")
|
||||
return False
|
||||
|
||||
except Exception as e:
|
||||
print(f"Printer error: {str(e)}")
|
||||
print("Label already saved to file as fallback...")
|
||||
print(f"Label file: {file_path}")
|
||||
return True
|
||||
|
||||
|
||||
def print_label_standalone(value, printer, preview=0, use_pdf=True):
|
||||
"""
|
||||
Print a label with the specified text on the specified printer.
|
||||
@@ -226,23 +475,11 @@ def print_label_standalone(value, printer, preview=0, use_pdf=True):
|
||||
|
||||
# Print after preview
|
||||
print("Sending to printer...")
|
||||
conn = cups.Connection()
|
||||
conn.printFile(printer, temp_file, "Label Print", {})
|
||||
return True
|
||||
return print_to_printer(printer, temp_file)
|
||||
else:
|
||||
print("Direct printing without preview...")
|
||||
# Direct printing without preview (preview = 0)
|
||||
try:
|
||||
conn = cups.Connection()
|
||||
conn.printFile(printer, temp_file, "Label Print", {})
|
||||
print(f"Label sent to printer: {printer}")
|
||||
return True
|
||||
except Exception as e:
|
||||
# If printing fails, save to file as fallback
|
||||
print(f"Printer error: {str(e)}")
|
||||
print("Label already saved to file as fallback...")
|
||||
print(f"Label file: {temp_file}")
|
||||
return True
|
||||
return print_to_printer(printer, temp_file)
|
||||
|
||||
except Exception as e:
|
||||
print(f"Error printing label: {str(e)}")
|
||||
|
||||
7
requirements_windows.txt
Normal file
7
requirements_windows.txt
Normal file
@@ -0,0 +1,7 @@
|
||||
python-barcode
|
||||
pillow
|
||||
kivy>=2.1.0
|
||||
reportlab
|
||||
pyinstaller>=6.0.0
|
||||
pywin32
|
||||
wmi
|
||||
95
setup_sumatra.ps1
Normal file
95
setup_sumatra.ps1
Normal file
@@ -0,0 +1,95 @@
|
||||
# Download and Setup SumatraPDF Portable for Label Printer
|
||||
# This script downloads SumatraPDF portable and sets up the deployment structure
|
||||
|
||||
Write-Host ""
|
||||
Write-Host "========================================================"
|
||||
Write-Host " Label Printer - SumatraPDF Setup"
|
||||
Write-Host "========================================================"
|
||||
Write-Host ""
|
||||
|
||||
# Create SumatraPDF folder if it doesn't exist
|
||||
$sumatraFolder = "SumatraPDF"
|
||||
if (-not (Test-Path $sumatraFolder)) {
|
||||
New-Item -ItemType Directory -Path $sumatraFolder -Force | Out-Null
|
||||
}
|
||||
|
||||
# Check if SumatraPDF.exe already exists
|
||||
$sumatraExe = Join-Path $sumatraFolder "SumatraPDF.exe"
|
||||
if (Test-Path $sumatraExe) {
|
||||
Write-Host "[OK] SumatraPDF.exe already exists at: $sumatraExe" -ForegroundColor Green
|
||||
Write-Host ""
|
||||
Read-Host "Press Enter to exit"
|
||||
exit 0
|
||||
}
|
||||
|
||||
Write-Host "[1/3] Downloading SumatraPDF portable (64-bit, ~5 MB)..." -ForegroundColor Cyan
|
||||
|
||||
# SumatraPDF download URL (latest stable version)
|
||||
$url = "https://www.sumatrapdfreader.org/dl/rel/3.5.2/SumatraPDF-3.5.2-64.zip"
|
||||
$zipFile = "SumatraPDF-temp.zip"
|
||||
|
||||
try {
|
||||
# Download with progress
|
||||
$progressPreference = 'SilentlyContinue'
|
||||
Invoke-WebRequest -Uri $url -OutFile $zipFile -ErrorAction Stop
|
||||
Write-Host "[OK] Download complete" -ForegroundColor Green
|
||||
} catch {
|
||||
Write-Host "[ERROR] Failed to download SumatraPDF" -ForegroundColor Red
|
||||
Write-Host "Error: $_" -ForegroundColor Red
|
||||
Write-Host ""
|
||||
Write-Host "Please download manually from:" -ForegroundColor Yellow
|
||||
Write-Host " https://www.sumatrapdfreader.org/download-free-pdf-viewer" -ForegroundColor Yellow
|
||||
Write-Host " Extract SumatraPDF.exe to the 'SumatraPDF' folder" -ForegroundColor Yellow
|
||||
Write-Host ""
|
||||
Read-Host "Press Enter to exit"
|
||||
exit 1
|
||||
}
|
||||
|
||||
Write-Host ""
|
||||
Write-Host "[2/3] Extracting..." -ForegroundColor Cyan
|
||||
|
||||
try {
|
||||
# Extract ZIP file
|
||||
Add-Type -AssemblyName System.IO.Compression.FileSystem
|
||||
[System.IO.Compression.ZipFile]::ExtractToDirectory($zipFile, $sumatraFolder)
|
||||
Write-Host "[OK] Extraction complete" -ForegroundColor Green
|
||||
} catch {
|
||||
Write-Host "[ERROR] Failed to extract ZIP file" -ForegroundColor Red
|
||||
Write-Host "Error: $_" -ForegroundColor Red
|
||||
Read-Host "Press Enter to exit"
|
||||
exit 1
|
||||
}
|
||||
|
||||
Write-Host ""
|
||||
Write-Host "[3/3] Cleaning up..." -ForegroundColor Cyan
|
||||
|
||||
# Remove temporary ZIP file
|
||||
if (Test-Path $zipFile) {
|
||||
Remove-Item $zipFile -Force
|
||||
}
|
||||
|
||||
Write-Host "[OK] Cleanup complete" -ForegroundColor Green
|
||||
Write-Host ""
|
||||
|
||||
# Verify installation
|
||||
if (Test-Path $sumatraExe) {
|
||||
Write-Host "========================================================"
|
||||
Write-Host " SETUP SUCCESSFUL!" -ForegroundColor Green
|
||||
Write-Host "========================================================"
|
||||
Write-Host ""
|
||||
Write-Host "SumatraPDF portable is now installed at:" -ForegroundColor Green
|
||||
Write-Host " $sumatraExe" -ForegroundColor Green
|
||||
Write-Host ""
|
||||
Write-Host "The Label Printer app will now be able to print PDFs silently." -ForegroundColor Green
|
||||
Write-Host ""
|
||||
} else {
|
||||
Write-Host "========================================================"
|
||||
Write-Host " SETUP INCOMPLETE" -ForegroundColor Yellow
|
||||
Write-Host "========================================================"
|
||||
Write-Host ""
|
||||
Write-Host "Could not find SumatraPDF.exe after extraction." -ForegroundColor Yellow
|
||||
Write-Host "Please check the SumatraPDF folder and ensure SumatraPDF.exe is present." -ForegroundColor Yellow
|
||||
Write-Host ""
|
||||
}
|
||||
|
||||
Read-Host "Press Enter to exit"
|
||||
Reference in New Issue
Block a user