Compare commits
13 Commits
63b46206b6
...
master
| Author | SHA1 | Date | |
|---|---|---|---|
| 71ccdb7b96 | |||
| be1b494527 | |||
| b35f278c1e | |||
| faef90f98b | |||
| 7197df9f5c | |||
| f67e1fb0da | |||
| f7833ed4b9 | |||
| 7a77199fcf | |||
| cbf324eb76 | |||
| 71558cc983 | |||
| 7437c547ec | |||
| 461426fd89 | |||
| 3f3da62543 |
3
.gitignore
vendored
3
.gitignore
vendored
@@ -2,10 +2,13 @@ label/
|
|||||||
build/
|
build/
|
||||||
logs/
|
logs/
|
||||||
pdf_backup/
|
pdf_backup/
|
||||||
|
conf/ghostscript/
|
||||||
venv/
|
venv/
|
||||||
.venv/
|
.venv/
|
||||||
__pycache__/
|
__pycache__/
|
||||||
*.pyc
|
*.pyc
|
||||||
*.pyo
|
*.pyo
|
||||||
*.pyd
|
*.pyd
|
||||||
|
build_output.log
|
||||||
|
.vscode/
|
||||||
|
|
||||||
|
|||||||
@@ -1,12 +1,71 @@
|
|||||||
# -*- mode: python ; coding: utf-8 -*-
|
# -*- mode: python ; coding: utf-8 -*-
|
||||||
|
#
|
||||||
|
# LabelPrinter PyInstaller spec file.
|
||||||
|
#
|
||||||
|
# GhostScript bundling
|
||||||
|
# --------------------
|
||||||
|
# Run build_windows.bat (or prepare_ghostscript.bat) BEFORE pyinstaller.
|
||||||
|
# That script copies the following directories from the system
|
||||||
|
# GhostScript installation into conf\ghostscript\:
|
||||||
|
#
|
||||||
|
# conf\ghostscript\bin\ <- gswin64c.exe + gsdll64.dll
|
||||||
|
# conf\ghostscript\lib\ <- all .ps init files
|
||||||
|
#
|
||||||
|
# This spec detects those directories automatically and adds them to the
|
||||||
|
# bundle under ghostscript\bin\ and ghostscript\lib\ inside _MEIPASS so
|
||||||
|
# that print_label.py can find and launch the bundled executable.
|
||||||
|
# If the directories are absent the build still succeeds (prints will fall
|
||||||
|
# back to SumatraPDF on the target machine).
|
||||||
|
|
||||||
|
import os
|
||||||
|
import glob as _glob
|
||||||
|
|
||||||
|
# ── GhostScript: collect binaries and lib init files ──────────────────────
|
||||||
|
_gs_bin_src = os.path.join('conf', 'ghostscript', 'bin')
|
||||||
|
_gs_lib_src = os.path.join('conf', 'ghostscript', 'lib')
|
||||||
|
|
||||||
|
gs_binaries = [] # (src_path, dest_folder_in_bundle)
|
||||||
|
gs_datas = [] # (src_path, dest_folder_in_bundle)
|
||||||
|
|
||||||
|
if os.path.isdir(_gs_bin_src):
|
||||||
|
for _fn in ['gswin64c.exe', 'gsdll64.dll', 'gswin32c.exe', 'gsdll32.dll']:
|
||||||
|
_fp = os.path.join(_gs_bin_src, _fn)
|
||||||
|
if os.path.exists(_fp):
|
||||||
|
# Put executables/DLLs in binaries so PyInstaller handles deps
|
||||||
|
gs_binaries.append((_fp, 'ghostscript/bin'))
|
||||||
|
print(f'[spec] Bundling GhostScript binaries from: {_gs_bin_src}')
|
||||||
|
else:
|
||||||
|
print('[spec] WARNING: conf/ghostscript/bin not found.'
|
||||||
|
' GhostScript will NOT be bundled in the exe.')
|
||||||
|
|
||||||
|
if os.path.isdir(_gs_lib_src):
|
||||||
|
for _fp in _glob.glob(os.path.join(_gs_lib_src, '*')):
|
||||||
|
if os.path.isfile(_fp):
|
||||||
|
gs_datas.append((_fp, 'ghostscript/lib'))
|
||||||
|
print(f'[spec] Bundling GhostScript lib from: {_gs_lib_src}')
|
||||||
|
|
||||||
|
# ── Base data files ────────────────────────────────────────────────────────
|
||||||
|
base_datas = [
|
||||||
|
('conf\\SumatraPDF.exe', '.'),
|
||||||
|
('conf\\SumatraPDF-settings.txt', 'conf'),
|
||||||
|
('conf\\label_template_ok.svg', 'conf'),
|
||||||
|
('conf\\label_template_nok.svg', 'conf'),
|
||||||
|
('conf\\label_template.svg', 'conf'),
|
||||||
|
]
|
||||||
|
|
||||||
a = Analysis(
|
a = Analysis(
|
||||||
['label_printer_gui.py'],
|
['label_printer_gui.py'],
|
||||||
pathex=[],
|
pathex=[],
|
||||||
binaries=[],
|
binaries=gs_binaries,
|
||||||
datas=[],
|
datas=base_datas + gs_datas,
|
||||||
hiddenimports=['kivy', 'kivy.core.window', 'kivy.core.text', 'kivy.core.image', 'kivy.uix.boxlayout', 'kivy.uix.gridlayout', 'kivy.uix.label', 'kivy.uix.textinput', 'kivy.uix.button', 'kivy.uix.spinner', 'kivy.uix.scrollview', 'kivy.uix.popup', 'kivy.clock', 'kivy.graphics', 'PIL', 'barcode', 'reportlab', 'print_label', 'print_label_pdf', 'svglib', 'cairosvg', 'watchdog', 'watchdog.observers', 'watchdog.events', 'pystray', 'win32timezone'],
|
hiddenimports=[
|
||||||
|
'kivy', 'PIL', 'PIL.ImageWin', 'barcode', 'reportlab',
|
||||||
|
'print_label', 'print_label_pdf',
|
||||||
|
'fitz', 'pymupdf',
|
||||||
|
'svglib', 'cairosvg',
|
||||||
|
'watchdog', 'watchdog.observers', 'watchdog.events',
|
||||||
|
'pystray', 'win32api', 'win32print', 'win32ui', 'win32con', 'win32timezone',
|
||||||
|
],
|
||||||
hookspath=[],
|
hookspath=[],
|
||||||
hooksconfig={},
|
hooksconfig={},
|
||||||
runtime_hooks=[],
|
runtime_hooks=[],
|
||||||
|
|||||||
103
build_exe.py
103
build_exe.py
@@ -1,6 +1,6 @@
|
|||||||
"""
|
"""
|
||||||
PyInstaller build script for Label Printer GUI
|
PyInstaller build script for Label Printer GUI
|
||||||
Run this to create a standalone Windows executable
|
Run this to create a standalone Windows executable.
|
||||||
|
|
||||||
IMPORTANT: This script MUST be run on Windows to generate a Windows .exe file.
|
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.
|
If run on Linux/macOS, it will create a Linux/macOS binary that won't work on Windows.
|
||||||
@@ -10,6 +10,12 @@ To build for Windows:
|
|||||||
2. Install dependencies: pip install -r requirements_windows.txt
|
2. Install dependencies: pip install -r requirements_windows.txt
|
||||||
3. Run this script: python build_exe.py
|
3. Run this script: python build_exe.py
|
||||||
4. The Windows .exe will be created in the dist/ folder
|
4. The Windows .exe will be created in the dist/ folder
|
||||||
|
|
||||||
|
Printing method
|
||||||
|
---------------
|
||||||
|
SumatraPDF is bundled inside the exe and used for all printing.
|
||||||
|
It sends the PDF at its exact 35x25 mm page size via -print-settings noscale.
|
||||||
|
No GhostScript installation required on the build or target machine.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
import os
|
import os
|
||||||
@@ -19,64 +25,66 @@ import subprocess
|
|||||||
# Get the current directory
|
# Get the current directory
|
||||||
script_dir = os.path.dirname(os.path.abspath(__file__))
|
script_dir = os.path.dirname(os.path.abspath(__file__))
|
||||||
|
|
||||||
# PyInstaller arguments
|
|
||||||
args = [
|
def check_conf_folder():
|
||||||
'label_printer_gui.py',
|
"""
|
||||||
'--onefile', # Create a single executable
|
Verify that required files are present in the conf\ folder before building.
|
||||||
'--windowed', # Don't show console window
|
Returns True if all required files exist, False otherwise.
|
||||||
'--name=LabelPrinter', # Executable name
|
"""
|
||||||
'--distpath=./dist', # Output directory
|
required = [
|
||||||
'--workpath=./build', # Work directory (was --buildpath)
|
os.path.join('conf', 'SumatraPDF.exe'),
|
||||||
'--hidden-import=kivy',
|
os.path.join('conf', 'SumatraPDF-settings.txt'),
|
||||||
'--hidden-import=kivy.core.window',
|
os.path.join('conf', 'label_template_ok.svg'),
|
||||||
'--hidden-import=kivy.core.text',
|
os.path.join('conf', 'label_template_nok.svg'),
|
||||||
'--hidden-import=kivy.core.image',
|
os.path.join('conf', 'label_template.svg'),
|
||||||
'--hidden-import=kivy.uix.boxlayout',
|
]
|
||||||
'--hidden-import=kivy.uix.gridlayout',
|
all_ok = True
|
||||||
'--hidden-import=kivy.uix.label',
|
for f in required:
|
||||||
'--hidden-import=kivy.uix.textinput',
|
if os.path.exists(f):
|
||||||
'--hidden-import=kivy.uix.button',
|
print(f" OK: {f}")
|
||||||
'--hidden-import=kivy.uix.spinner',
|
else:
|
||||||
'--hidden-import=kivy.uix.scrollview',
|
print(f" MISSING: {f}")
|
||||||
'--hidden-import=kivy.uix.popup',
|
all_ok = False
|
||||||
'--hidden-import=kivy.clock',
|
return all_ok
|
||||||
'--hidden-import=kivy.graphics',
|
|
||||||
'--hidden-import=PIL',
|
|
||||||
'--hidden-import=barcode',
|
|
||||||
'--hidden-import=reportlab',
|
|
||||||
'--hidden-import=print_label',
|
|
||||||
'--hidden-import=print_label_pdf',
|
|
||||||
'--hidden-import=svglib',
|
|
||||||
'--hidden-import=cairosvg',
|
|
||||||
'--hidden-import=watchdog',
|
|
||||||
'--hidden-import=watchdog.observers',
|
|
||||||
'--hidden-import=watchdog.events',
|
|
||||||
'--hidden-import=pystray',
|
|
||||||
'--hidden-import=win32timezone',
|
|
||||||
]
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
print("=" * 60)
|
print("=" * 60)
|
||||||
print("Label Printer GUI - PyInstaller Build")
|
print("Label Printer GUI - PyInstaller Build")
|
||||||
print("=" * 60)
|
print("=" * 60)
|
||||||
print("\nBuilding standalone executable...")
|
|
||||||
print("This may take a few minutes...\n")
|
# Change to script directory so relative paths work
|
||||||
|
|
||||||
# Change to script directory
|
|
||||||
os.chdir(script_dir)
|
os.chdir(script_dir)
|
||||||
|
|
||||||
# Run PyInstaller directly with subprocess for better error reporting
|
# Step 1: Verify conf\ folder contents
|
||||||
|
print("\n[1/2] Checking conf\\ folder...")
|
||||||
|
if not check_conf_folder():
|
||||||
|
print("\nERROR: One or more required conf\\ files are missing.")
|
||||||
|
print("Place SumatraPDF.exe and the SVG templates in the conf\\ folder, then retry.")
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
# Step 2: Build with PyInstaller using the handcrafted spec file.
|
||||||
|
print("\n[2/2] Building standalone executable via LabelPrinter.spec...")
|
||||||
|
print("This may take a few minutes...\n")
|
||||||
|
|
||||||
try:
|
try:
|
||||||
result = subprocess.run(['pyinstaller'] + args, check=True)
|
result = subprocess.run(
|
||||||
|
['pyinstaller', 'LabelPrinter.spec',
|
||||||
|
'--distpath=./dist', '--workpath=./build', '-y'],
|
||||||
|
check=True,
|
||||||
|
)
|
||||||
|
|
||||||
print("\n" + "=" * 60)
|
print("\n" + "=" * 60)
|
||||||
print("Build Complete!")
|
print("Build Complete!")
|
||||||
print("=" * 60)
|
print("=" * 60)
|
||||||
print("\nExecutable location: ./dist/LabelPrinter.exe")
|
print("\nExecutable location: ./dist/LabelPrinter.exe")
|
||||||
|
print("\nBundled components:")
|
||||||
|
print(" - SumatraPDF (primary printing, noscale 35x25 mm)")
|
||||||
|
print(" - SVG templates, conf files")
|
||||||
print("\nYou can now:")
|
print("\nYou can now:")
|
||||||
print("1. Double-click LabelPrinter.exe to run")
|
print(" 1. Double-click LabelPrinter.exe to run")
|
||||||
print("2. Share the exe with others")
|
print(" 2. Copy the dist\\ folder to target machines")
|
||||||
print("3. Create a shortcut on desktop")
|
print(" 3. No extra software installation required on target machines")
|
||||||
print("\nNote: First run may take a moment as Kivy initializes")
|
print("\nNote: First run may take a moment as Kivy initializes")
|
||||||
except subprocess.CalledProcessError as e:
|
except subprocess.CalledProcessError as e:
|
||||||
print("\n" + "=" * 60)
|
print("\n" + "=" * 60)
|
||||||
@@ -88,3 +96,4 @@ if __name__ == '__main__':
|
|||||||
except Exception as e:
|
except Exception as e:
|
||||||
print(f"\nFatal error: {e}")
|
print(f"\nFatal error: {e}")
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
|
|
||||||
|
|||||||
@@ -23,12 +23,12 @@ if errorlevel 1 (
|
|||||||
exit /b 1
|
exit /b 1
|
||||||
)
|
)
|
||||||
|
|
||||||
echo [1/5] Checking Python installation...
|
echo [1/6] Checking Python installation...
|
||||||
python --version
|
python --version
|
||||||
echo.
|
echo.
|
||||||
|
|
||||||
REM Upgrade pip
|
REM Upgrade pip
|
||||||
echo [2/5] Upgrading pip, setuptools, and wheel...
|
echo [2/6] Upgrading pip, setuptools, and wheel...
|
||||||
python -m pip install --upgrade pip setuptools wheel
|
python -m pip install --upgrade pip setuptools wheel
|
||||||
if errorlevel 1 (
|
if errorlevel 1 (
|
||||||
echo ERROR: Failed to upgrade pip
|
echo ERROR: Failed to upgrade pip
|
||||||
@@ -38,7 +38,7 @@ if errorlevel 1 (
|
|||||||
echo.
|
echo.
|
||||||
|
|
||||||
REM Install dependencies
|
REM Install dependencies
|
||||||
echo [3/5] Installing dependencies...
|
echo [3/6] Installing dependencies...
|
||||||
echo Installing: python-barcode, pillow, reportlab, kivy, pyinstaller, pywin32, wmi, watchdog, svglib, cairosvg, pystray...
|
echo Installing: python-barcode, pillow, reportlab, kivy, pyinstaller, pywin32, wmi, watchdog, svglib, cairosvg, pystray...
|
||||||
pip install python-barcode pillow reportlab kivy pyinstaller pywin32 wmi watchdog svglib cairosvg pystray
|
pip install python-barcode pillow reportlab kivy pyinstaller pywin32 wmi watchdog svglib cairosvg pystray
|
||||||
if errorlevel 1 (
|
if errorlevel 1 (
|
||||||
@@ -48,38 +48,36 @@ if errorlevel 1 (
|
|||||||
)
|
)
|
||||||
echo.
|
echo.
|
||||||
|
|
||||||
REM Clean old build
|
REM Copy GhostScript binaries for bundling (optional but strongly recommended)
|
||||||
echo [4/5] Cleaning old build artifacts...
|
echo [4/6] Preparing GhostScript for bundling...
|
||||||
if exist "dist" rmdir /s /q dist
|
python prepare_ghostscript.py
|
||||||
if exist "build" rmdir /s /q build
|
|
||||||
if exist "*.spec" del *.spec
|
|
||||||
echo.
|
echo.
|
||||||
|
|
||||||
REM Build with PyInstaller
|
REM Check that SumatraPDF.exe exists before building
|
||||||
echo [5/5] Building executable with PyInstaller...
|
if not exist "conf\SumatraPDF.exe" (
|
||||||
|
echo ERROR: conf\SumatraPDF.exe not found!
|
||||||
|
echo Please download SumatraPDF portable exe and place it at conf\SumatraPDF.exe
|
||||||
|
echo Download from: https://www.sumatrapdfreader.org/download-free-pdf-viewer
|
||||||
|
pause
|
||||||
|
exit /b 1
|
||||||
|
)
|
||||||
|
echo conf\SumatraPDF.exe found - will be bundled into executable.
|
||||||
|
echo.
|
||||||
|
|
||||||
|
REM Clean old build (keep the spec file - it's handcrafted)
|
||||||
|
echo [5/6] Cleaning old build artifacts...
|
||||||
|
if exist "dist" rmdir /s /q dist
|
||||||
|
if exist "build" rmdir /s /q build
|
||||||
|
echo.
|
||||||
|
|
||||||
|
REM Build with PyInstaller using the spec file.
|
||||||
|
REM The spec (LabelPrinter.spec) contains Python code that detects whether
|
||||||
|
REM conf\ghostscript\ was prepared and includes those files automatically.
|
||||||
|
echo [6/6] Building executable with PyInstaller...
|
||||||
echo This may take 5-15 minutes, please wait...
|
echo This may take 5-15 minutes, please wait...
|
||||||
echo.
|
echo.
|
||||||
|
|
||||||
pyinstaller label_printer_gui.py ^
|
pyinstaller LabelPrinter.spec --distpath=./dist --workpath=./build -y
|
||||||
--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 ^
|
|
||||||
--hidden-import=svglib ^
|
|
||||||
--hidden-import=cairosvg ^
|
|
||||||
--hidden-import=watchdog ^
|
|
||||||
--hidden-import=watchdog.observers ^
|
|
||||||
--hidden-import=watchdog.events ^
|
|
||||||
--hidden-import=pystray ^
|
|
||||||
--hidden-import=win32timezone ^
|
|
||||||
-y
|
|
||||||
|
|
||||||
if errorlevel 1 (
|
if errorlevel 1 (
|
||||||
echo.
|
echo.
|
||||||
@@ -94,12 +92,27 @@ echo ========================================================
|
|||||||
echo BUILD SUCCESSFUL!
|
echo BUILD SUCCESSFUL!
|
||||||
echo ========================================================
|
echo ========================================================
|
||||||
echo.
|
echo.
|
||||||
|
echo Copying conf folder to dist\conf ...
|
||||||
|
if exist dist\conf rmdir /s /q dist\conf
|
||||||
|
xcopy /e /i /q conf dist\conf
|
||||||
|
if errorlevel 1 (
|
||||||
|
echo WARNING: Could not copy conf folder to dist\conf
|
||||||
|
echo You must manually copy the conf folder next to LabelPrinter.exe before deployment.
|
||||||
|
) else (
|
||||||
|
echo conf folder copied to dist\conf successfully.
|
||||||
|
)
|
||||||
|
echo.
|
||||||
echo Executable Location: dist\LabelPrinter.exe
|
echo Executable Location: dist\LabelPrinter.exe
|
||||||
echo.
|
echo.
|
||||||
|
echo Deployment folder contents:
|
||||||
|
dir dist
|
||||||
|
echo.
|
||||||
echo Next steps:
|
echo Next steps:
|
||||||
echo 1. Navigate to the dist folder
|
echo 1. Copy the entire dist\ folder to the target machine
|
||||||
echo 2. Double-click LabelPrinter.exe to run
|
echo (it contains LabelPrinter.exe AND the conf\ folder)
|
||||||
echo 3. You can copy LabelPrinter.exe to other machines
|
echo 2. Run LabelPrinter.exe from the dist folder
|
||||||
|
echo 3. GhostScript is bundled inside the exe for sharp vector printing
|
||||||
|
echo 4. SumatraPDF (conf\SumatraPDF.exe) is also bundled as fallback
|
||||||
echo.
|
echo.
|
||||||
echo Note: First run may take a moment as Kivy initializes
|
echo Note: First run may take a moment as Kivy initializes
|
||||||
echo.
|
echo.
|
||||||
|
|||||||
@@ -1,20 +1,110 @@
|
|||||||
from reportlab.lib.pagesizes import landscape
|
"""
|
||||||
from reportlab.lib.utils import ImageReader
|
check_pdf_size.py – verify that a PDF's page dimensions match 35 mm × 25 mm.
|
||||||
from reportlab.pdfgen import canvas
|
|
||||||
|
Usage:
|
||||||
|
python check_pdf_size.py [path/to/label.pdf]
|
||||||
|
|
||||||
|
If no path is given the script operates on every PDF found in pdf_backup/.
|
||||||
|
Exit code 0 = all OK, 1 = mismatch or error.
|
||||||
|
"""
|
||||||
|
|
||||||
import os
|
import os
|
||||||
|
import sys
|
||||||
|
|
||||||
# Check the test PDF file
|
# ── Target dimensions ────────────────────────────────────────────────────────
|
||||||
if os.path.exists('test_label.pdf'):
|
TARGET_W_MM = 35.0 # width (landscape, wider side)
|
||||||
file_size = os.path.getsize('test_label.pdf')
|
TARGET_H_MM = 25.0 # height
|
||||||
print(f'test_label.pdf exists ({file_size} bytes)')
|
TOLERANCE_MM = 0.5 # ± 0.5 mm is acceptable rounding from PDF viewers
|
||||||
print(f'Expected: 35mm x 25mm landscape (99.2 x 70.9 points)')
|
|
||||||
print(f'')
|
PT_PER_MM = 72.0 / 25.4 # 1 mm in points
|
||||||
print(f'Open test_label.pdf in a PDF viewer to verify:')
|
|
||||||
print(f' - Page size should be wider than tall')
|
|
||||||
print(f' - Content should be correctly oriented')
|
def read_page_size_pt(pdf_path):
|
||||||
print(f'')
|
"""
|
||||||
print(f'In Adobe Reader: File > Properties > Description')
|
Return (width_pt, height_pt) of the first page of *pdf_path*.
|
||||||
print(f' Page size should show: 3.5 x 2.5 cm or 1.38 x 0.98 in')
|
Tries pypdf first, then pymupdf (fitz) as a fallback.
|
||||||
else:
|
Raises RuntimeError if neither library is available.
|
||||||
print('test_label.pdf not found')
|
"""
|
||||||
|
# ── pypdf ────────────────────────────────────────────────────────────────
|
||||||
|
try:
|
||||||
|
from pypdf import PdfReader # type: ignore
|
||||||
|
reader = PdfReader(pdf_path)
|
||||||
|
page = reader.pages[0]
|
||||||
|
w = float(page.mediabox.width)
|
||||||
|
h = float(page.mediabox.height)
|
||||||
|
return w, h
|
||||||
|
except ImportError:
|
||||||
|
pass
|
||||||
|
|
||||||
|
# ── pymupdf (fitz) ───────────────────────────────────────────────────────
|
||||||
|
try:
|
||||||
|
import fitz # type: ignore
|
||||||
|
doc = fitz.open(pdf_path)
|
||||||
|
rect = doc[0].rect
|
||||||
|
return rect.width, rect.height
|
||||||
|
except ImportError:
|
||||||
|
pass
|
||||||
|
|
||||||
|
raise RuntimeError(
|
||||||
|
"Install pypdf or pymupdf:\n"
|
||||||
|
" pip install pypdf\n"
|
||||||
|
" pip install pymupdf"
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def check_file(pdf_path):
|
||||||
|
"""Print a pass/fail line for one PDF. Returns True if dimensions match."""
|
||||||
|
if not os.path.exists(pdf_path):
|
||||||
|
print(f" MISS {pdf_path} (file not found)")
|
||||||
|
return False
|
||||||
|
|
||||||
|
try:
|
||||||
|
w_pt, h_pt = read_page_size_pt(pdf_path)
|
||||||
|
except Exception as e:
|
||||||
|
print(f" ERR {pdf_path} ({e})")
|
||||||
|
return False
|
||||||
|
|
||||||
|
w_mm = w_pt / PT_PER_MM
|
||||||
|
h_mm = h_pt / PT_PER_MM
|
||||||
|
|
||||||
|
w_ok = abs(w_mm - TARGET_W_MM) <= TOLERANCE_MM
|
||||||
|
h_ok = abs(h_mm - TARGET_H_MM) <= TOLERANCE_MM
|
||||||
|
ok = w_ok and h_ok
|
||||||
|
|
||||||
|
status = "PASS" if ok else "FAIL"
|
||||||
|
print(
|
||||||
|
f" {status} {os.path.basename(pdf_path)}"
|
||||||
|
f" {w_mm:.2f}×{h_mm:.2f} mm"
|
||||||
|
f" (target {TARGET_W_MM}×{TARGET_H_MM} mm ±{TOLERANCE_MM} mm)"
|
||||||
|
)
|
||||||
|
return ok
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
targets = sys.argv[1:]
|
||||||
|
|
||||||
|
if not targets:
|
||||||
|
backup_dir = os.path.join(os.path.dirname(__file__), "pdf_backup")
|
||||||
|
if os.path.isdir(backup_dir):
|
||||||
|
targets = [
|
||||||
|
os.path.join(backup_dir, f)
|
||||||
|
for f in sorted(os.listdir(backup_dir))
|
||||||
|
if f.lower().endswith(".pdf")
|
||||||
|
]
|
||||||
|
if not targets:
|
||||||
|
# fall back to test_label.pdf in cwd
|
||||||
|
targets = ["test_label.pdf"]
|
||||||
|
|
||||||
|
print(f"Checking {len(targets)} PDF(s)…")
|
||||||
|
results = [check_file(p) for p in targets]
|
||||||
|
|
||||||
|
total = len(results)
|
||||||
|
passed = sum(results)
|
||||||
|
failed = total - passed
|
||||||
|
print(f"\n {passed}/{total} passed" + (f", {failed} FAILED" if failed else ""))
|
||||||
|
sys.exit(0 if failed == 0 else 1)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
||||||
|
|
||||||
|
|||||||
@@ -89,6 +89,6 @@ FileStates [
|
|||||||
SessionData [
|
SessionData [
|
||||||
]
|
]
|
||||||
TimeOfLastUpdateCheck = 0 0
|
TimeOfLastUpdateCheck = 0 0
|
||||||
OpenCountWeek = 788
|
OpenCountWeek = 790
|
||||||
|
|
||||||
# Settings below are not recognized by the current version
|
# Settings below are not recognized by the current version
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
[Settings]
|
[Settings]
|
||||||
file_path = C:\temp\check.txt
|
file_path = C:\temp\check.txt
|
||||||
printer = ZDesigner ZQ630 Plus
|
printer = PDF
|
||||||
|
|
||||||
|
|||||||
BIN
dist/LabelPrinter.exe
vendored
BIN
dist/LabelPrinter.exe
vendored
Binary file not shown.
4
dist/conf/app.conf
vendored
4
dist/conf/app.conf
vendored
@@ -1,4 +0,0 @@
|
|||||||
[Settings]
|
|
||||||
file_path = C:\Users\Public\Documents\check.txt
|
|
||||||
printer = Microsoft Print to P
|
|
||||||
|
|
||||||
16
dist/conf/label_template.svg
vendored
16
dist/conf/label_template.svg
vendored
@@ -1,16 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<svg xmlns="http://www.w3.org/2000/svg" width="35mm" height="25mm" viewBox="0 0 35 25">
|
|
||||||
<defs>
|
|
||||||
<style type="text/css">
|
|
||||||
.text { font-family: Arial; font-weight: bold; font-size: 3.5px; fill: #000000; }
|
|
||||||
.checkmark { fill: #008000; }
|
|
||||||
</style>
|
|
||||||
</defs>
|
|
||||||
<g id="content">
|
|
||||||
<text x="2" y="7" class="text">Nr. Comanda: {Article}</text>
|
|
||||||
<text x="2" y="12" class="text">Nr. Art.: {NrArt}</text>
|
|
||||||
<text x="2" y="17" class="text">Serial No.: {Serial}</text>
|
|
||||||
<circle cx="31" cy="7" r="2.5" class="checkmark"/>
|
|
||||||
<path d="M30,7 L30.8,7.8 L32,6" stroke="white" stroke-width="0.5" fill="none"/>
|
|
||||||
</g>
|
|
||||||
</svg>
|
|
||||||
|
Before Width: | Height: | Size: 672 B |
64
dist/conf/label_template_nok.svg
vendored
64
dist/conf/label_template_nok.svg
vendored
@@ -1,64 +0,0 @@
|
|||||||
<?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:#373435}
|
|
||||||
.fil2 {fill:#373435;fill-rule:nonzero}
|
|
||||||
.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="_1503869020736">
|
|
||||||
<path class="fil1" d="M13.9026 6.1147c-0.0969,0.0226 -0.5344,0.3421 -0.5861,0.348 -0.0365,0.0041 -0.3442,-0.227 -0.3951,-0.2642 -0.0499,-0.0364 -0.0741,-0.0672 -0.136,-0.0838 0,0.0623 0.0141,0.1755 0.0234,0.2513 0.0277,0.2244 0.0714,0.489 0.1349,0.7076 0.086,0.2957 0.1778,0.558 0.3056,0.8116 0.2029,0.4024 0.3688,0.6622 0.6587,1.008 0.7996,0.9535 2.1521,1.6354 3.4012,1.6354 0.8602,0 1.4215,-0.0956 2.1368,-0.4273 0.2518,-0.1167 0.4901,-0.2561 0.7094,-0.4077 0.3749,-0.2591 0.6465,-0.5227 0.9323,-0.8626 0.0294,-0.035 0.0411,-0.0435 0.0679,-0.0786 0.57,-0.7469 0.8516,-1.4248 0.9811,-2.3706 0.0101,-0.0742 0.0259,-0.2049 0.0259,-0.2671 -0.0958,-0.0641 -0.1973,-0.1198 -0.293,-0.1831 -0.3674,-0.243 -0.2819,-0.2176 -0.5911,0.0133 -0.3726,0.278 -0.1599,0.0504 -0.3023,0.6684 -0.032,0.1389 -0.0657,0.2528 -0.1072,0.3873 -0.2015,0.6534 -0.7073,1.2896 -1.2311,1.6992 -0.1584,0.1239 -0.4254,0.286 -0.6008,0.37 -1.2009,0.5747 -2.7309,0.4386 -3.7667,-0.4035 -0.1586,-0.1289 -0.3761,-0.3128 -0.4993,-0.4714 -0.2438,-0.3139 -0.3987,-0.4932 -0.5704,-0.8948 -0.1469,-0.3437 -0.2981,-0.8086 -0.2981,-1.1854z"/>
|
|
||||||
<path class="fil1" d="M12.7854 5.5653c0.092,0.0616 0.1745,0.1224 0.2711,0.1868 0.3448,0.2298 0.2204,0.2304 0.5604,0.0037 0.1015,-0.0677 0.1895,-0.1261 0.2857,-0.1905 0,-0.6008 0.3296,-1.3796 0.7036,-1.8788 0.1683,-0.2248 0.5135,-0.5784 0.7579,-0.7439 0.6122,-0.4147 1.1468,-0.6373 1.9084,-0.674 0.2685,-0.013 0.0473,-0.0281 0.3856,-0.001 0.2398,0.0192 0.2983,0.0032 0.5892,0.0702 0.4301,0.0991 0.855,0.2746 1.2086,0.513 0.7053,0.4753 1.2198,1.1687 1.4592,1.984 0.0526,0.1792 0.1303,0.5118 0.1303,0.7305 0.0881,-0.0235 0.4644,-0.3425 0.5128,-0.348 0.0656,0.0175 0.2282,0.1315 0.301,0.1752 0.0656,0.0395 0.2453,0.1592 0.3034,0.1728l-0.0573 -0.4922c-0.1187,-0.6931 -0.4034,-1.4203 -0.8244,-1.9778 -0.177,-0.2344 -0.4287,-0.5477 -0.6595,-0.7324 -0.1682,-0.1347 -0.2514,-0.2282 -0.466,-0.3765 -0.6841,-0.4728 -1.6125,-0.835 -2.5349,-0.835 -0.8789,0 -1.3878,0.1016 -2.106,0.4215 -1.3809,0.6151 -2.4156,1.9744 -2.669,3.4847 -0.0144,0.0857 -0.0219,0.1508 -0.0342,0.2406 -0.0101,0.0742 -0.0259,0.2049 -0.0259,0.2671z"/>
|
|
||||||
<polygon class="fil2" points="14.8273,3.5997 16.8077,3.5997 17.5,4.8137 18.3014,3.5997 20.1392,3.5997 18.658,5.6752 20.2482,7.9549 18.3014,7.9549 17.5,6.5521 16.5476,7.9549 14.7434,7.9549 16.328,5.6752 "/>
|
|
||||||
</g>
|
|
||||||
</g>
|
|
||||||
</svg>
|
|
||||||
|
Before Width: | Height: | Size: 18 KiB |
63
dist/conf/label_template_ok.svg
vendored
63
dist/conf/label_template_ok.svg
vendored
@@ -1,63 +0,0 @@
|
|||||||
<?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="_1503865902032">
|
|
||||||
<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>
|
|
||||||
|
Before Width: | Height: | Size: 18 KiB |
@@ -982,23 +982,13 @@ printer = PDF
|
|||||||
success = False
|
success = False
|
||||||
all_success = True
|
all_success = True
|
||||||
try:
|
try:
|
||||||
# Print multiple copies if count > 1
|
# Send all copies in ONE print job to prevent blank labels
|
||||||
for i in range(count):
|
# being ejected between separate jobs on thermal printers.
|
||||||
if count > 1:
|
success = print_label_standalone(
|
||||||
Clock.schedule_once(lambda dt, idx=i: popup.content.children[0].text.replace(
|
label_text, printer, preview=0,
|
||||||
f'Processing {count} label(s)...',
|
svg_template=template_path, copies=count
|
||||||
f'Printing {idx+1} of {count}...'
|
)
|
||||||
), 0)
|
all_success = success
|
||||||
|
|
||||||
success = print_label_standalone(label_text, printer, preview=0, use_pdf=True, svg_template=template_path)
|
|
||||||
|
|
||||||
if not success:
|
|
||||||
all_success = False
|
|
||||||
break
|
|
||||||
|
|
||||||
# Small delay between prints for multiple copies
|
|
||||||
if i < count - 1:
|
|
||||||
time.sleep(0.5)
|
|
||||||
|
|
||||||
# Get the PDF filename that was created
|
# Get the PDF filename that was created
|
||||||
# Files are saved to pdf_backup/ with timestamp
|
# Files are saved to pdf_backup/ with timestamp
|
||||||
|
|||||||
121
prepare_ghostscript.bat
Normal file
121
prepare_ghostscript.bat
Normal file
@@ -0,0 +1,121 @@
|
|||||||
|
@echo off
|
||||||
|
REM ============================================================
|
||||||
|
REM prepare_ghostscript.bat
|
||||||
|
REM Finds the system GhostScript installation and copies the
|
||||||
|
REM files needed for bundling into conf\ghostscript\
|
||||||
|
REM
|
||||||
|
REM Files copied:
|
||||||
|
REM conf\ghostscript\bin\gswin64c.exe (or gswin32c.exe)
|
||||||
|
REM conf\ghostscript\bin\gsdll64.dll (or gsdll32.dll)
|
||||||
|
REM conf\ghostscript\lib\*.ps (PostScript init files)
|
||||||
|
REM
|
||||||
|
REM Run this ONCE before building the exe with build_windows.bat.
|
||||||
|
REM Only the two executables + the lib/ folder are needed (~15-20 MB).
|
||||||
|
REM The full GhostScript fonts/Resources are NOT bundled to keep
|
||||||
|
REM the exe size manageable; Windows system fonts are used instead.
|
||||||
|
REM ============================================================
|
||||||
|
|
||||||
|
setlocal enabledelayedexpansion
|
||||||
|
|
||||||
|
set GS_FOUND=0
|
||||||
|
set GS_BIN_SRC=
|
||||||
|
set GS_LIB_SRC=
|
||||||
|
set GS_EXE=
|
||||||
|
|
||||||
|
REM Pre-assign ProgramFiles(x86) to avoid batch parser choking on the parentheses
|
||||||
|
set "PF64=%ProgramFiles%"
|
||||||
|
set "PF32=%ProgramFiles(x86)%"
|
||||||
|
|
||||||
|
echo.
|
||||||
|
echo ============================================================
|
||||||
|
echo GhostScript Bundle Preparation
|
||||||
|
echo ============================================================
|
||||||
|
echo.
|
||||||
|
|
||||||
|
REM ---- Search for GhostScript in both Program Files locations ----
|
||||||
|
for %%P in ("%PF64%" "%PF32%") do (
|
||||||
|
if exist "%%~P\gs" (
|
||||||
|
for /d %%V in ("%%~P\gs\gs*") do (
|
||||||
|
if exist "%%~V\bin\gswin64c.exe" (
|
||||||
|
set GS_BIN_SRC=%%~V\bin
|
||||||
|
set GS_LIB_SRC=%%~V\lib
|
||||||
|
set GS_EXE=gswin64c.exe
|
||||||
|
set GS_DLL=gsdll64.dll
|
||||||
|
set GS_FOUND=1
|
||||||
|
echo Found GhostScript (64-bit): %%~V
|
||||||
|
)
|
||||||
|
if !GS_FOUND!==0 (
|
||||||
|
if exist "%%~V\bin\gswin32c.exe" (
|
||||||
|
set GS_BIN_SRC=%%~V\bin
|
||||||
|
set GS_LIB_SRC=%%~V\lib
|
||||||
|
set GS_EXE=gswin32c.exe
|
||||||
|
set GS_DLL=gsdll32.dll
|
||||||
|
set GS_FOUND=1
|
||||||
|
echo Found GhostScript (32-bit): %%~V
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
if %GS_FOUND%==0 (
|
||||||
|
echo.
|
||||||
|
echo WARNING: GhostScript is NOT installed on this machine.
|
||||||
|
echo.
|
||||||
|
echo The exe will still build successfully, but GhostScript will
|
||||||
|
echo NOT be bundled. On the target machine the app will fall back
|
||||||
|
echo to SumatraPDF for printing (which may produce dotted output).
|
||||||
|
echo.
|
||||||
|
echo To get sharp vector-quality printing, install GhostScript:
|
||||||
|
echo https://ghostscript.com/releases/gsdnld.html
|
||||||
|
echo Then re-run this script before building.
|
||||||
|
echo.
|
||||||
|
exit /b 0
|
||||||
|
)
|
||||||
|
|
||||||
|
REM ---- Create destination folders ----
|
||||||
|
set GS_DEST_BIN=conf\ghostscript\bin
|
||||||
|
set GS_DEST_LIB=conf\ghostscript\lib
|
||||||
|
|
||||||
|
if not exist "%GS_DEST_BIN%" mkdir "%GS_DEST_BIN%"
|
||||||
|
if not exist "%GS_DEST_LIB%" mkdir "%GS_DEST_LIB%"
|
||||||
|
|
||||||
|
REM ---- Copy executable and DLL ----
|
||||||
|
echo.
|
||||||
|
echo Copying GhostScript binaries...
|
||||||
|
copy /y "%GS_BIN_SRC%\%GS_EXE%" "%GS_DEST_BIN%\%GS_EXE%" >nul
|
||||||
|
if errorlevel 1 ( echo ERROR copying %GS_EXE% & exit /b 1 )
|
||||||
|
echo + %GS_EXE%
|
||||||
|
|
||||||
|
copy /y "%GS_BIN_SRC%\%GS_DLL%" "%GS_DEST_BIN%\%GS_DLL%" >nul
|
||||||
|
if errorlevel 1 ( echo ERROR copying %GS_DLL% & exit /b 1 )
|
||||||
|
echo + %GS_DLL%
|
||||||
|
|
||||||
|
REM ---- Copy lib/ (PostScript init files .ps) ----
|
||||||
|
echo.
|
||||||
|
echo Copying GhostScript lib (PostScript init files)...
|
||||||
|
for %%F in ("%GS_LIB_SRC%\*.ps") do (
|
||||||
|
copy /y "%%F" "%GS_DEST_LIB%\" >nul
|
||||||
|
)
|
||||||
|
echo + *.ps copied from %GS_LIB_SRC%
|
||||||
|
|
||||||
|
REM ---- Report ----
|
||||||
|
echo.
|
||||||
|
echo ============================================================
|
||||||
|
echo GhostScript prepared successfully in conf\ghostscript\
|
||||||
|
echo ============================================================
|
||||||
|
echo.
|
||||||
|
|
||||||
|
REM Show size summary
|
||||||
|
set BIN_COUNT=0
|
||||||
|
set LIB_COUNT=0
|
||||||
|
for %%F in ("%GS_DEST_BIN%\*") do set /a BIN_COUNT+=1
|
||||||
|
for %%F in ("%GS_DEST_LIB%\*") do set /a LIB_COUNT+=1
|
||||||
|
echo bin\ : %BIN_COUNT% file(s)
|
||||||
|
echo lib\ : %LIB_COUNT% file(s)
|
||||||
|
echo.
|
||||||
|
echo GhostScript will be embedded into LabelPrinter.exe at build time.
|
||||||
|
echo.
|
||||||
|
|
||||||
|
endlocal
|
||||||
|
exit /b 0
|
||||||
115
prepare_ghostscript.py
Normal file
115
prepare_ghostscript.py
Normal file
@@ -0,0 +1,115 @@
|
|||||||
|
"""
|
||||||
|
prepare_ghostscript.py
|
||||||
|
Finds the system GhostScript installation and copies the files needed for
|
||||||
|
bundling into conf/ghostscript/
|
||||||
|
|
||||||
|
Files copied:
|
||||||
|
conf/ghostscript/bin/gswin64c.exe (or gswin32c.exe)
|
||||||
|
conf/ghostscript/bin/gsdll64.dll (or gsdll32.dll)
|
||||||
|
conf/ghostscript/lib/*.ps (PostScript init files)
|
||||||
|
|
||||||
|
Run this ONCE before building the exe with build_windows.bat.
|
||||||
|
"""
|
||||||
|
|
||||||
|
import os
|
||||||
|
import shutil
|
||||||
|
import glob
|
||||||
|
import sys
|
||||||
|
|
||||||
|
SCRIPT_DIR = os.path.dirname(os.path.abspath(__file__))
|
||||||
|
DEST_BIN = os.path.join(SCRIPT_DIR, "conf", "ghostscript", "bin")
|
||||||
|
DEST_LIB = os.path.join(SCRIPT_DIR, "conf", "ghostscript", "lib")
|
||||||
|
|
||||||
|
SEARCH_ROOTS = [
|
||||||
|
os.environ.get("ProgramFiles", r"C:\Program Files"),
|
||||||
|
os.environ.get("ProgramFiles(x86)", r"C:\Program Files (x86)"),
|
||||||
|
os.environ.get("ProgramW6432", r"C:\Program Files"),
|
||||||
|
]
|
||||||
|
|
||||||
|
FLAVOURS = [
|
||||||
|
("gswin64c.exe", "gsdll64.dll"),
|
||||||
|
("gswin32c.exe", "gsdll32.dll"),
|
||||||
|
]
|
||||||
|
|
||||||
|
print()
|
||||||
|
print("=" * 60)
|
||||||
|
print(" GhostScript Bundle Preparation")
|
||||||
|
print("=" * 60)
|
||||||
|
print()
|
||||||
|
|
||||||
|
|
||||||
|
def find_ghostscript():
|
||||||
|
"""Return (bin_dir, lib_dir, exe_name, dll_name) or None."""
|
||||||
|
for root in dict.fromkeys(r for r in SEARCH_ROOTS if r): # unique, preserve order
|
||||||
|
gs_root = os.path.join(root, "gs")
|
||||||
|
if not os.path.isdir(gs_root):
|
||||||
|
continue
|
||||||
|
# Each versioned sub-folder, newest first
|
||||||
|
versions = sorted(
|
||||||
|
[d for d in glob.glob(os.path.join(gs_root, "gs*")) if os.path.isdir(d)],
|
||||||
|
reverse=True,
|
||||||
|
)
|
||||||
|
for ver_dir in versions:
|
||||||
|
bin_dir = os.path.join(ver_dir, "bin")
|
||||||
|
lib_dir = os.path.join(ver_dir, "lib")
|
||||||
|
for exe, dll in FLAVOURS:
|
||||||
|
if os.path.isfile(os.path.join(bin_dir, exe)):
|
||||||
|
print(f"Found GhostScript: {ver_dir}")
|
||||||
|
return bin_dir, lib_dir, exe, dll
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
|
result = find_ghostscript()
|
||||||
|
|
||||||
|
if result is None:
|
||||||
|
print("WARNING: GhostScript is NOT installed on this machine.")
|
||||||
|
print()
|
||||||
|
print(" The exe will still build successfully, but GhostScript will")
|
||||||
|
print(" NOT be bundled. On the target machine the app will fall back")
|
||||||
|
print(" to SumatraPDF for printing (which may produce dotted output).")
|
||||||
|
print()
|
||||||
|
print(" To get sharp vector-quality printing, install GhostScript:")
|
||||||
|
print(" https://ghostscript.com/releases/gsdnld.html")
|
||||||
|
print(" Then re-run this script before building.")
|
||||||
|
print()
|
||||||
|
sys.exit(0)
|
||||||
|
|
||||||
|
src_bin, src_lib, exe_name, dll_name = result
|
||||||
|
|
||||||
|
# Create destination folders
|
||||||
|
os.makedirs(DEST_BIN, exist_ok=True)
|
||||||
|
os.makedirs(DEST_LIB, exist_ok=True)
|
||||||
|
|
||||||
|
# Copy executable and DLL
|
||||||
|
print("Copying GhostScript binaries...")
|
||||||
|
for fname in (exe_name, dll_name):
|
||||||
|
src = os.path.join(src_bin, fname)
|
||||||
|
dst = os.path.join(DEST_BIN, fname)
|
||||||
|
if os.path.isfile(src):
|
||||||
|
shutil.copy2(src, dst)
|
||||||
|
print(f" + {fname}")
|
||||||
|
else:
|
||||||
|
print(f" WARNING: {fname} not found in {src_bin}")
|
||||||
|
|
||||||
|
# Copy lib/ (PostScript init files .ps)
|
||||||
|
print()
|
||||||
|
print("Copying GhostScript lib (PostScript init files)...")
|
||||||
|
ps_files = glob.glob(os.path.join(src_lib, "*.ps"))
|
||||||
|
for ps in ps_files:
|
||||||
|
shutil.copy2(ps, DEST_LIB)
|
||||||
|
print(f" + {len(ps_files)} .ps files copied from {src_lib}")
|
||||||
|
|
||||||
|
# Report
|
||||||
|
bin_count = len(os.listdir(DEST_BIN))
|
||||||
|
lib_count = len(os.listdir(DEST_LIB))
|
||||||
|
|
||||||
|
print()
|
||||||
|
print("=" * 60)
|
||||||
|
print(" GhostScript prepared successfully in conf\\ghostscript\\")
|
||||||
|
print("=" * 60)
|
||||||
|
print()
|
||||||
|
print(f" bin\\ : {bin_count} file(s)")
|
||||||
|
print(f" lib\\ : {lib_count} file(s)")
|
||||||
|
print()
|
||||||
|
print("GhostScript will be embedded into LabelPrinter.exe at build time.")
|
||||||
|
print()
|
||||||
533
print_label.py
533
print_label.py
@@ -1,6 +1,3 @@
|
|||||||
from PIL import Image, ImageDraw, ImageFont
|
|
||||||
import barcode
|
|
||||||
from barcode.writer import ImageWriter
|
|
||||||
import time
|
import time
|
||||||
import os
|
import os
|
||||||
import sys
|
import sys
|
||||||
@@ -9,6 +6,21 @@ import platform
|
|||||||
import subprocess
|
import subprocess
|
||||||
from print_label_pdf import PDFLabelGenerator
|
from print_label_pdf import PDFLabelGenerator
|
||||||
|
|
||||||
|
|
||||||
|
def _write_print_log(msg):
|
||||||
|
"""Write a timestamped debug line to print_debug.log next to the exe / script."""
|
||||||
|
try:
|
||||||
|
if getattr(sys, 'frozen', False):
|
||||||
|
log_dir = os.path.dirname(sys.executable)
|
||||||
|
else:
|
||||||
|
log_dir = os.path.dirname(os.path.abspath(__file__))
|
||||||
|
log_path = os.path.join(log_dir, 'print_debug.log')
|
||||||
|
ts = datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S')
|
||||||
|
with open(log_path, 'a', encoding='utf-8') as f:
|
||||||
|
f.write(f"[{ts}] {msg}\n")
|
||||||
|
except Exception:
|
||||||
|
pass
|
||||||
|
|
||||||
# Cross-platform printer support
|
# Cross-platform printer support
|
||||||
try:
|
try:
|
||||||
import cups
|
import cups
|
||||||
@@ -89,119 +101,6 @@ def get_available_printers():
|
|||||||
return ["PDF"]
|
return ["PDF"]
|
||||||
|
|
||||||
|
|
||||||
def create_label_image(text):
|
|
||||||
"""
|
|
||||||
Create a label image with 3 rows: label + barcode for each field.
|
|
||||||
|
|
||||||
Args:
|
|
||||||
text (str): Combined text in format "SAP|CANTITATE|LOT" or single value
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
PIL.Image: The generated label image
|
|
||||||
"""
|
|
||||||
# Parse the text input
|
|
||||||
parts = text.split('|') if '|' in text else [text, '', '']
|
|
||||||
sap_nr = parts[0].strip() if len(parts) > 0 else ''
|
|
||||||
cantitate = parts[1].strip() if len(parts) > 1 else ''
|
|
||||||
lot_number = parts[2].strip() if len(parts) > 2 else ''
|
|
||||||
|
|
||||||
# Label dimensions (narrower, 3 rows)
|
|
||||||
label_width = 800 # 8 cm
|
|
||||||
label_height = 600 # 6 cm
|
|
||||||
|
|
||||||
# Create canvas
|
|
||||||
label_img = Image.new('RGB', (label_width, label_height), 'white')
|
|
||||||
draw = ImageDraw.Draw(label_img)
|
|
||||||
|
|
||||||
# Row setup - 3 equal rows
|
|
||||||
row_height = label_height // 3
|
|
||||||
left_margin = 15
|
|
||||||
row_spacing = 3
|
|
||||||
|
|
||||||
# Fonts
|
|
||||||
font_path = "/usr/share/fonts/truetype/dejavu/DejaVuSans-Bold.ttf"
|
|
||||||
try:
|
|
||||||
label_font = ImageFont.truetype(font_path, 16)
|
|
||||||
value_font = ImageFont.truetype(font_path, 14)
|
|
||||||
except IOError:
|
|
||||||
label_font = ImageFont.load_default()
|
|
||||||
value_font = ImageFont.load_default()
|
|
||||||
|
|
||||||
# Data for 3 rows
|
|
||||||
rows_data = [
|
|
||||||
("SAP-Nr", sap_nr),
|
|
||||||
("Cantitate", cantitate),
|
|
||||||
("Lot Nr", lot_number),
|
|
||||||
]
|
|
||||||
|
|
||||||
# Generate barcodes first
|
|
||||||
CODE128 = barcode.get_barcode_class('code128')
|
|
||||||
writer_options = {
|
|
||||||
"write_text": False,
|
|
||||||
"module_width": 0.4,
|
|
||||||
"module_height": 8,
|
|
||||||
"quiet_zone": 2,
|
|
||||||
"font_size": 0
|
|
||||||
}
|
|
||||||
|
|
||||||
barcode_images = []
|
|
||||||
for _, value in rows_data:
|
|
||||||
if value:
|
|
||||||
try:
|
|
||||||
code = CODE128(value[:25], writer=ImageWriter())
|
|
||||||
filename = code.save('temp_barcode', options=writer_options)
|
|
||||||
barcode_img = Image.open(filename)
|
|
||||||
barcode_images.append(barcode_img)
|
|
||||||
except:
|
|
||||||
barcode_images.append(None)
|
|
||||||
else:
|
|
||||||
barcode_images.append(None)
|
|
||||||
|
|
||||||
# Draw each row with label and barcode
|
|
||||||
for idx, ((label_name, value), barcode_img) in enumerate(zip(rows_data, barcode_images)):
|
|
||||||
row_y = idx * row_height
|
|
||||||
|
|
||||||
# Draw label name
|
|
||||||
draw.text(
|
|
||||||
(left_margin, row_y + 3),
|
|
||||||
label_name,
|
|
||||||
fill='black',
|
|
||||||
font=label_font
|
|
||||||
)
|
|
||||||
|
|
||||||
# Draw barcode if available
|
|
||||||
if barcode_img:
|
|
||||||
# Resize barcode to fit in row width
|
|
||||||
barcode_width = label_width - left_margin - 10
|
|
||||||
barcode_height = row_height - 25
|
|
||||||
# Use high-quality resampling for crisp barcodes
|
|
||||||
try:
|
|
||||||
# Try newer Pillow API first
|
|
||||||
from PIL.Image import Resampling
|
|
||||||
barcode_resized = barcode_img.resize((barcode_width, barcode_height), Resampling.LANCZOS)
|
|
||||||
except (ImportError, AttributeError):
|
|
||||||
# Fallback for older Pillow versions
|
|
||||||
barcode_resized = barcode_img.resize((barcode_width, barcode_height), Image.LANCZOS)
|
|
||||||
label_img.paste(barcode_resized, (left_margin, row_y + 20))
|
|
||||||
else:
|
|
||||||
# Fallback: show value as text
|
|
||||||
draw.text(
|
|
||||||
(left_margin, row_y + 25),
|
|
||||||
value if value else "(empty)",
|
|
||||||
fill='black',
|
|
||||||
font=value_font
|
|
||||||
)
|
|
||||||
|
|
||||||
# Clean up temporary barcode files
|
|
||||||
try:
|
|
||||||
if os.path.exists('temp_barcode.png'):
|
|
||||||
os.remove('temp_barcode.png')
|
|
||||||
except:
|
|
||||||
pass
|
|
||||||
|
|
||||||
return label_img
|
|
||||||
|
|
||||||
|
|
||||||
def create_label_pdf(text, svg_template=None):
|
def create_label_pdf(text, svg_template=None):
|
||||||
"""
|
"""
|
||||||
Create a high-quality PDF label with 3 rows: label + barcode for each field.
|
Create a high-quality PDF label with 3 rows: label + barcode for each field.
|
||||||
@@ -259,99 +158,154 @@ def create_label_pdf(text, svg_template=None):
|
|||||||
return generator.create_label_pdf(article, nr_art, serial, pdf_filename, image_path, selected_template)
|
return generator.create_label_pdf(article, nr_art, serial, pdf_filename, image_path, selected_template)
|
||||||
|
|
||||||
|
|
||||||
def configure_printer_quality(printer_name, width_mm=35, height_mm=25):
|
def _print_pdf_windows(file_path, printer_name, copies=1):
|
||||||
"""
|
"""
|
||||||
Configure printer for high quality label printing (Windows only).
|
Print a PDF on Windows using pymupdf (fitz) to render and win32print/GDI to send.
|
||||||
Sets paper size, orientation, and QUALITY settings.
|
All copies are sent as multiple pages within ONE print job so the printer
|
||||||
|
never sees a gap (which causes blank labels on thermal printers).
|
||||||
Args:
|
No external application is launched. Falls back to SumatraPDF if pymupdf
|
||||||
printer_name (str): Name of the printer
|
is unavailable.
|
||||||
width_mm (int): Label width in millimeters (default 35)
|
|
||||||
height_mm (int): Label height in millimeters (default 25)
|
Returns True on success, False on failure.
|
||||||
|
|
||||||
Returns:
|
|
||||||
bool: True if successful
|
|
||||||
"""
|
"""
|
||||||
if SYSTEM != "Windows" or not WIN32_AVAILABLE:
|
copies = max(1, int(copies))
|
||||||
return False
|
_write_print_log(f"_print_pdf_windows called: printer={printer_name!r} copies={copies} file={file_path!r}")
|
||||||
|
|
||||||
|
# ── Method 1: pure-Python GDI (pymupdf + win32print) ─────────────────
|
||||||
try:
|
try:
|
||||||
|
import fitz # pymupdf
|
||||||
import win32print
|
import win32print
|
||||||
import pywintypes
|
import win32ui
|
||||||
|
import win32con
|
||||||
hprinter = win32print.OpenPrinter(printer_name)
|
from PIL import ImageWin, Image as PILImage
|
||||||
|
|
||||||
try:
|
_write_print_log("pymupdf + win32 imports OK – using GDI method")
|
||||||
# Get current printer properties
|
|
||||||
props = win32print.GetPrinter(hprinter, 2)
|
doc = fitz.open(file_path)
|
||||||
devmode = props.get("pDevMode")
|
if doc.page_count == 0:
|
||||||
|
_write_print_log("PDF has no pages – aborting")
|
||||||
if devmode is None:
|
return False
|
||||||
print("Could not get printer DEVMODE")
|
page = doc[0]
|
||||||
return False
|
|
||||||
|
# Get the printer's native resolution
|
||||||
# CRITICAL: Set print quality to HIGHEST
|
hdc = win32ui.CreateDC()
|
||||||
# This prevents dotted/pixelated text
|
hdc.CreatePrinterDC(printer_name)
|
||||||
try:
|
x_dpi = hdc.GetDeviceCaps(win32con.LOGPIXELSX)
|
||||||
devmode.PrintQuality = 600 # 600 DPI (high quality)
|
y_dpi = hdc.GetDeviceCaps(win32con.LOGPIXELSY)
|
||||||
except:
|
_write_print_log(f"Printer DPI={x_dpi}x{y_dpi}")
|
||||||
try:
|
|
||||||
devmode.PrintQuality = 4 # DMRES_HIGH
|
# Render PDF page at printer DPI (PDF uses 72 pt/inch)
|
||||||
except:
|
mat = fitz.Matrix(x_dpi / 72.0, y_dpi / 72.0)
|
||||||
pass
|
pix = page.get_pixmap(matrix=mat, alpha=False)
|
||||||
|
img = PILImage.frombytes("RGB", [pix.width, pix.height], pix.samples)
|
||||||
# Set custom paper size
|
|
||||||
try:
|
# Read physical page size before closing the document
|
||||||
devmode.PaperSize = 256 # DMPAPER_USER (custom size)
|
pdf_page_w_pts = page.rect.width # PDF points (1pt = 1/72 inch)
|
||||||
devmode.PaperLength = height_mm * 10 # Height in 0.1mm units
|
pdf_page_h_pts = page.rect.height
|
||||||
devmode.PaperWidth = width_mm * 10 # Width in 0.1mm units
|
doc.close()
|
||||||
except:
|
dest_w = int(round(pdf_page_w_pts * x_dpi / 72.0))
|
||||||
pass
|
dest_h = int(round(pdf_page_h_pts * y_dpi / 72.0))
|
||||||
|
_write_print_log(
|
||||||
# Set orientation to landscape
|
f"PDF page={pdf_page_w_pts:.1f}x{pdf_page_h_pts:.1f}pt "
|
||||||
try:
|
f"rendered={pix.width}x{pix.height}px dest={dest_w}x{dest_h}px"
|
||||||
devmode.Orientation = 2 # Landscape
|
)
|
||||||
except:
|
|
||||||
pass
|
# Draw at exact physical size – NOT stretched to the driver's paper area.
|
||||||
|
# All copies go into ONE print job to prevent blank labels between jobs.
|
||||||
# Set additional quality settings
|
hdc.StartDoc(os.path.basename(file_path))
|
||||||
try:
|
dib = ImageWin.Dib(img)
|
||||||
devmode.Color = 1 # Monochrome for labels
|
for copy_idx in range(copies):
|
||||||
except:
|
hdc.StartPage()
|
||||||
pass
|
dib.draw(hdc.GetHandleOutput(), (0, 0, dest_w, dest_h))
|
||||||
|
hdc.EndPage()
|
||||||
try:
|
hdc.EndDoc()
|
||||||
devmode.TTOption = 2 # DMTT_BITMAP - print TrueType as graphics (sharper)
|
hdc.DeleteDC()
|
||||||
except:
|
|
||||||
pass
|
_write_print_log(f"GDI print SUCCESS → {printer_name} ({copies} cop{'y' if copies==1 else 'ies'} in 1 job)")
|
||||||
|
return True
|
||||||
# Apply settings
|
|
||||||
try:
|
except ImportError as ie:
|
||||||
props["pDevMode"] = devmode
|
_write_print_log(f"GDI method unavailable ({ie}) – trying SumatraPDF fallback")
|
||||||
win32print.SetPrinter(hprinter, 2, props, 0)
|
|
||||||
print(f"Printer configured: {width_mm}x{height_mm}mm @ HIGH QUALITY")
|
|
||||||
return True
|
|
||||||
except Exception as set_err:
|
|
||||||
print(f"Could not apply printer settings: {set_err}")
|
|
||||||
return False
|
|
||||||
|
|
||||||
finally:
|
|
||||||
win32print.ClosePrinter(hprinter)
|
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
print(f"Could not configure printer quality: {e}")
|
_write_print_log(f"GDI print error: {e}")
|
||||||
return False
|
try:
|
||||||
|
hdc.DeleteDC()
|
||||||
|
except Exception:
|
||||||
|
pass
|
||||||
|
|
||||||
|
# ── Method 2: SumatraPDF fallback ────────────────────────────────────
|
||||||
|
_write_print_log("Attempting SumatraPDF fallback")
|
||||||
|
sumatra_paths = []
|
||||||
|
if getattr(sys, 'frozen', False):
|
||||||
|
if hasattr(sys, '_MEIPASS'):
|
||||||
|
sumatra_paths.append(os.path.join(sys._MEIPASS, 'SumatraPDF.exe'))
|
||||||
|
app_dir = os.path.dirname(sys.executable)
|
||||||
|
sumatra_paths.append(os.path.join(app_dir, 'conf', 'SumatraPDF.exe'))
|
||||||
|
sumatra_paths.append(os.path.join(app_dir, 'SumatraPDF.exe'))
|
||||||
|
else:
|
||||||
|
app_dir = os.path.dirname(os.path.abspath(__file__))
|
||||||
|
sumatra_paths.append(os.path.join(app_dir, 'conf', 'SumatraPDF.exe'))
|
||||||
|
sumatra_paths.append(os.path.join(app_dir, 'SumatraPDF.exe'))
|
||||||
|
sumatra_paths += [
|
||||||
|
r"C:\Program Files\SumatraPDF\SumatraPDF.exe",
|
||||||
|
r"C:\Program Files (x86)\SumatraPDF\SumatraPDF.exe",
|
||||||
|
]
|
||||||
|
_write_print_log(f"SumatraPDF search paths: {sumatra_paths}")
|
||||||
|
|
||||||
|
for sumatra_path in sumatra_paths:
|
||||||
|
_write_print_log(f"Checking: {sumatra_path} → exists={os.path.exists(sumatra_path)}")
|
||||||
|
if os.path.exists(sumatra_path):
|
||||||
|
try:
|
||||||
|
# Find conf folder with SumatraPDF-settings.txt
|
||||||
|
settings_candidates = []
|
||||||
|
if getattr(sys, 'frozen', False):
|
||||||
|
if hasattr(sys, '_MEIPASS'):
|
||||||
|
settings_candidates.append(os.path.join(sys._MEIPASS, 'conf'))
|
||||||
|
settings_candidates.append(os.path.join(os.path.dirname(sys.executable), 'conf'))
|
||||||
|
else:
|
||||||
|
settings_candidates.append(os.path.join(os.path.dirname(os.path.abspath(__file__)), 'conf'))
|
||||||
|
settings_candidates.append(os.path.dirname(sumatra_path))
|
||||||
|
|
||||||
|
appdata_dir = next(
|
||||||
|
(d for d in settings_candidates
|
||||||
|
if os.path.exists(os.path.join(d, 'SumatraPDF-settings.txt'))),
|
||||||
|
None
|
||||||
|
)
|
||||||
|
_write_print_log(f"SumatraPDF settings dir: {appdata_dir}")
|
||||||
|
|
||||||
|
cmd = [sumatra_path, "-print-to", printer_name,
|
||||||
|
"-print-settings", "noscale",
|
||||||
|
"-silent", "-exit-when-done"]
|
||||||
|
if appdata_dir:
|
||||||
|
cmd += ["-appdata-dir", appdata_dir]
|
||||||
|
cmd.append(file_path)
|
||||||
|
|
||||||
|
_write_print_log(f"SumatraPDF cmd: {' '.join(cmd)}")
|
||||||
|
result = subprocess.run(
|
||||||
|
cmd, check=False,
|
||||||
|
creationflags=subprocess.CREATE_NO_WINDOW,
|
||||||
|
capture_output=True, text=True, timeout=30)
|
||||||
|
_write_print_log(f"SumatraPDF exit={result.returncode} "
|
||||||
|
f"stdout={result.stdout.strip()!r} "
|
||||||
|
f"stderr={result.stderr.strip()!r}")
|
||||||
|
return True # treat any completed run as spooled
|
||||||
|
except Exception as se:
|
||||||
|
_write_print_log(f"SumatraPDF error: {se}")
|
||||||
|
|
||||||
|
_write_print_log("All print methods failed")
|
||||||
|
return False
|
||||||
|
|
||||||
|
|
||||||
def print_to_printer(printer_name, file_path):
|
def print_to_printer(printer_name, file_path, copies=1):
|
||||||
"""
|
"""
|
||||||
Print file to printer (cross-platform).
|
Print file to printer (cross-platform).
|
||||||
Uses SumatraPDF for silent printing on Windows.
|
Uses pymupdf+GDI for silent printing on Windows with all copies in one job.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
printer_name (str): Name of printer or "PDF" for PDF output
|
printer_name (str): Name of printer or "PDF" for PDF output
|
||||||
file_path (str): Path to file to print
|
file_path (str): Path to file to print
|
||||||
|
copies (int): Number of copies to print in a single print job
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
bool: True if successful
|
bool: True if successful
|
||||||
"""
|
"""
|
||||||
@@ -369,87 +323,14 @@ def print_to_printer(printer_name, file_path):
|
|||||||
return True
|
return True
|
||||||
|
|
||||||
elif SYSTEM == "Windows":
|
elif SYSTEM == "Windows":
|
||||||
# Windows: Print PDF silently without any viewer opening
|
# Windows: Print PDF using Python GDI (pymupdf + win32print).
|
||||||
try:
|
# No external viewer is launched at any point.
|
||||||
if WIN32_AVAILABLE:
|
if file_path.endswith('.pdf'):
|
||||||
import win32print
|
return _print_pdf_windows(file_path, printer_name, copies=copies)
|
||||||
import win32api
|
else:
|
||||||
|
subprocess.run(['notepad', '/p', file_path],
|
||||||
if file_path.endswith('.pdf'):
|
check=False,
|
||||||
# Try silent printing methods (no viewer opens)
|
creationflags=subprocess.CREATE_NO_WINDOW)
|
||||||
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"))
|
|
||||||
sumatra_paths.append(os.path.join(app_dir, "conf", "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:
|
|
||||||
# Use noscale with paper size specification for thermal printers
|
|
||||||
# Format: "noscale,paper=<size>" where paper size matches PDF (35mm x 25mm)
|
|
||||||
# SumatraPDF will use the PDF's page size when noscale is used
|
|
||||||
subprocess.run([
|
|
||||||
sumatra_path,
|
|
||||||
"-print-to",
|
|
||||||
printer_name,
|
|
||||||
file_path,
|
|
||||||
"-print-settings",
|
|
||||||
"noscale", # Preserve exact PDF page dimensions
|
|
||||||
"-silent",
|
|
||||||
"-exit-when-done"
|
|
||||||
], check=False, creationflags=subprocess.CREATE_NO_WINDOW)
|
|
||||||
print(f"Label sent to printer via SumatraPDF: {printer_name}")
|
|
||||||
print(f"Note: Printer '{printer_name}' should be configured for 35mm x 25mm labels")
|
|
||||||
printed = True
|
|
||||||
break
|
|
||||||
except Exception as e:
|
|
||||||
print(f"SumatraPDF error: {e}")
|
|
||||||
|
|
||||||
# Do not launch default PDF viewers (Adobe/Edge/etc.) as fallback.
|
|
||||||
if not printed:
|
|
||||||
print("SumatraPDF not found or failed. PDF saved as backup only (no viewer launched).")
|
|
||||||
return False
|
|
||||||
|
|
||||||
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
|
|
||||||
except Exception as e:
|
|
||||||
print(f"Windows print error: {e}")
|
|
||||||
print("PDF backup saved as fallback")
|
|
||||||
return True
|
return True
|
||||||
|
|
||||||
elif SYSTEM == "Darwin":
|
elif SYSTEM == "Darwin":
|
||||||
@@ -469,73 +350,44 @@ def print_to_printer(printer_name, file_path):
|
|||||||
return True
|
return True
|
||||||
|
|
||||||
|
|
||||||
def print_label_standalone(value, printer, preview=0, use_pdf=True, svg_template=None):
|
def print_label_standalone(value, printer, preview=0, svg_template=None, copies=1):
|
||||||
"""
|
"""
|
||||||
Print a label with the specified text on the specified printer.
|
Generate a PDF label, save it to pdf_backup/, and print it on the printer.
|
||||||
Always generates a PDF backup in pdf_backup and prints that PDF.
|
All copies are sent in a single print job to avoid blank labels on thermal
|
||||||
|
printers that eject a label between separate jobs.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
value (str): The text to print on the label
|
value (str): Label data in format "article;nr_art;serial;status"
|
||||||
printer (str): The name of the printer to use
|
printer (str): Printer name (or "PDF" to skip physical printing)
|
||||||
preview (int): 0 = no preview, 1-3 = 3s preview, >3 = 5s preview
|
preview (int): 0 = print immediately; 1-3 = 3 s delay; >3 = 5 s delay
|
||||||
use_pdf (bool): False to also generate a PNG if PDF generation fails
|
svg_template (str): Path to SVG template (optional; auto-selected if None)
|
||||||
svg_template (str): Path to specific SVG template to use (optional)
|
copies (int): Number of copies to print in one job (default 1)
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
bool: True if printing was successful, False otherwise
|
bool: True if sending to printer succeeded, False otherwise
|
||||||
"""
|
"""
|
||||||
# Track generated files
|
copies = max(1, int(copies))
|
||||||
file_created = False
|
|
||||||
temp_file = None
|
|
||||||
pdf_file = None
|
pdf_file = None
|
||||||
|
|
||||||
try:
|
try:
|
||||||
# Debug output
|
# Step 1 – Generate and save PDF to pdf_backup/
|
||||||
print(f"Preview value: {preview}")
|
|
||||||
print(f"Preview type: {type(preview)}")
|
|
||||||
print(f"Using format: {'PDF' if use_pdf else 'PNG'}")
|
|
||||||
|
|
||||||
# Always generate a PDF backup and print that PDF for verification
|
|
||||||
try:
|
try:
|
||||||
pdf_file = create_label_pdf(value, svg_template)
|
pdf_file = create_label_pdf(value, svg_template)
|
||||||
if pdf_file and os.path.exists(pdf_file):
|
if pdf_file and os.path.exists(pdf_file):
|
||||||
print(f"PDF label created: {pdf_file}")
|
print(f"PDF label created: {pdf_file}")
|
||||||
print(f"PDF backup saved to: {pdf_file}")
|
|
||||||
else:
|
else:
|
||||||
print("PDF generation returned no file path")
|
print("PDF generation failed – no output file")
|
||||||
|
return False
|
||||||
except Exception as pdf_err:
|
except Exception as pdf_err:
|
||||||
print(f"PDF generation failed: {pdf_err}")
|
print(f"PDF generation error: {pdf_err}")
|
||||||
|
|
||||||
# Optionally also create the label image (PNG)
|
|
||||||
if not pdf_file or not os.path.exists(pdf_file):
|
|
||||||
if not use_pdf:
|
|
||||||
label_img = create_label_image(value)
|
|
||||||
temp_file = 'final_label.png'
|
|
||||||
label_img.save(temp_file)
|
|
||||||
print(f"PNG label created: {temp_file}")
|
|
||||||
else:
|
|
||||||
temp_file = pdf_file
|
|
||||||
|
|
||||||
file_created = True
|
|
||||||
|
|
||||||
if not temp_file or not os.path.exists(temp_file):
|
|
||||||
print("No label file created for printing")
|
|
||||||
return False
|
return False
|
||||||
|
|
||||||
# Convert preview to int if it's a string
|
# Step 2 – Optional countdown before printing
|
||||||
if isinstance(preview, str):
|
if isinstance(preview, str):
|
||||||
preview = int(preview)
|
preview = int(preview)
|
||||||
|
|
||||||
if preview > 0: # Any value above 0 shows a preview message
|
if preview > 0:
|
||||||
# Calculate preview duration in seconds
|
preview_sec = 3 if 1 <= preview <= 3 else 5
|
||||||
if 1 <= preview <= 3:
|
print(f"Printing in {preview_sec} seconds… (Ctrl+C to cancel)")
|
||||||
preview_sec = 3 # 3 seconds
|
|
||||||
else: # preview > 3
|
|
||||||
preview_sec = 5 # 5 seconds
|
|
||||||
|
|
||||||
print(f"Printing in {preview_sec} seconds... (Press Ctrl+C to cancel)")
|
|
||||||
|
|
||||||
# Simple countdown timer using time.sleep
|
|
||||||
try:
|
try:
|
||||||
for i in range(preview_sec, 0, -1):
|
for i in range(preview_sec, 0, -1):
|
||||||
print(f" {i}...", end=" ", flush=True)
|
print(f" {i}...", end=" ", flush=True)
|
||||||
@@ -544,25 +396,20 @@ def print_label_standalone(value, printer, preview=0, use_pdf=True, svg_template
|
|||||||
except KeyboardInterrupt:
|
except KeyboardInterrupt:
|
||||||
print("\nCancelled by user")
|
print("\nCancelled by user")
|
||||||
return False
|
return False
|
||||||
|
|
||||||
# Print after preview
|
# Step 3 – Send to printer (all copies in one job)
|
||||||
print("Sending to printer...")
|
print(f"Sending to printer ({copies} cop{'y' if copies==1 else 'ies'})...")
|
||||||
return print_to_printer(printer, temp_file)
|
return print_to_printer(printer, pdf_file, copies=copies)
|
||||||
else:
|
|
||||||
print("Direct printing without preview...")
|
|
||||||
# Direct printing without preview (preview = 0)
|
|
||||||
return print_to_printer(printer, temp_file)
|
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
print(f"Error printing label: {str(e)}")
|
print(f"Error printing label: {str(e)}")
|
||||||
return False
|
return False
|
||||||
|
|
||||||
finally:
|
finally:
|
||||||
# This block always executes, ensuring cleanup
|
|
||||||
if pdf_file and os.path.exists(pdf_file):
|
if pdf_file and os.path.exists(pdf_file):
|
||||||
print("Cleanup complete - PDF backup saved to pdf_backup folder")
|
print("Cleanup complete – PDF backup saved to pdf_backup/")
|
||||||
else:
|
else:
|
||||||
print("Cleanup complete - label file retained for reference")
|
print("Cleanup complete")
|
||||||
|
|
||||||
|
|
||||||
# Main code removed - import this module or run as part of the Kivy GUI application
|
# Main code removed - import this module or run as part of the Kivy GUI application
|
||||||
|
|||||||
@@ -49,8 +49,8 @@ class PDFLabelGenerator:
|
|||||||
"""
|
"""
|
||||||
self.label_width = label_width * cm
|
self.label_width = label_width * cm
|
||||||
self.label_height = label_height * cm
|
self.label_height = label_height * cm
|
||||||
# Force landscape: ensure width > height
|
# label_width (3.5 cm) > label_height (2.5 cm) → page is already landscape
|
||||||
self.page_size = landscape((self.label_height, self.label_width)) if self.label_width > self.label_height else (self.label_width, self.label_height)
|
self.page_size = (self.label_width, self.label_height)
|
||||||
self.dpi = dpi
|
self.dpi = dpi
|
||||||
self.margin = 1 * mm # Minimal margin
|
self.margin = 1 * mm # Minimal margin
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user