93afa3c417
New three-column label format for Brother P-touch EDGE PT-E560BT asset tags:
logo | three static lines + variable field | QR code.
Layout and rendering
- ptouch_label.py: geometry engine with PDF and preview renderers. Both
consume the same geometry, so the preview matches the print exactly.
- Code symbols are snapped to whole printer dots per module. Fractional
modules are the usual reason a small QR code will not scan.
- QR is maximised to the printable height by default (16.4 mm, 4 dots per
module) instead of a fixed 16 mm box (12.3 mm, 3 dots per module).
- Code payload is composed as prefix + inventory + suffix. A legacy
{inventory} template is migrated on first save.
Hardware handling
- print_area.py reads the driver's real printable area via GetDeviceCaps.
The PT-E560BT head is 128 dots at 180 dpi, so the maximum print height is
18.06 mm even on 24 mm tape; the driver reports media as 65x24 mm but only
about 61x18 mm is reachable. Content is fitted to the reachable area,
otherwise the driver silently crops it.
- set_printer_resolution.py reads/switches the driver's resolution mode. The
driver offers 180x180 (symmetric) and 180x360 (anisotropic, 2x across the
tape); the anisotropic mode scaled output incorrectly.
GUI
- label_printer_ptouch_gui.py: 600x300 two-column panel - controls on the
left, live preview on the right. Advanced settings for logo, static lines,
code prefix/suffix and error correction.
- native_file_dialog.py: the standard Windows file picker, run in a
subprocess because Tk and Kivy both want the main event loop.
Printing
- Print failures are reported honestly. print_to_printer previously returned
True unconditionally, so a failed print claimed success and was logged as
SUCCESS.
- SumatraPDF exit codes are now checked (4 = no printer, 5 = driver error).
- The PDF is sent with noscale so driver-side scaling cannot distort the QR
module pitch.
Tests
- validate_ptouch_layout.py decodes the QR back out of the rendered preview
module by module, proving the preview and PDF are the same layout.
- test_ptouch_pipeline.py writes to a temp config so it cannot overwrite
operator settings.
- test_gui_layout.py exercises the real app class headlessly.
- test_print_reporting.py covers the failure paths.
Diagnostics: check_print_area.py, check_print_geometry.py, check_devmode.py,
print_calibration.py, print_measure_scale.py, capture_print_job.py.
57 lines
1.8 KiB
Python
57 lines
1.8 KiB
Python
"""
|
|
Send one test label to the PT-E560BT.
|
|
|
|
Generates the 63 x 20 mm label and prints it through SumatraPDF with noscale so
|
|
the QR module pitch reaches the tape unmangled. Reports the real printer exit
|
|
status rather than assuming success.
|
|
"""
|
|
|
|
import os
|
|
import sys
|
|
|
|
sys.path.insert(0, os.path.dirname(os.path.abspath(__file__)))
|
|
os.chdir(os.path.dirname(os.path.abspath(__file__)))
|
|
|
|
from label_config import load_config, save_config
|
|
from print_label import print_ptouch_label
|
|
from ptouch_label import code_density_warning
|
|
|
|
PRINTER = "Brother PT-E560BT"
|
|
TEST_INVENTORY = sys.argv[1] if len(sys.argv) > 1 else "INV-0001"
|
|
|
|
|
|
def main() -> int:
|
|
cfg = load_config()
|
|
|
|
# Only seed defaults on the very first run so operator settings are kept.
|
|
if not os.path.exists("label_config.json"):
|
|
print("No saved settings - writing defaults (edit them in Advanced settings).")
|
|
cfg.static_lines = ["MOTO ADV SRL", "Articol: CABLU", "Rev: 2026-09"]
|
|
cfg.qr_prefix = "INV-"
|
|
save_config(cfg)
|
|
|
|
print(f"Printer : {PRINTER}")
|
|
print(f"Inventory : {TEST_INVENTORY}")
|
|
print(f"QR string : {cfg.build_code_payload(TEST_INVENTORY)!r}")
|
|
print(f"Logo : {cfg.logo_path or '(none set)'}")
|
|
print(f"Send opts : {cfg.sumatra_settings}")
|
|
|
|
warning = code_density_warning(cfg, TEST_INVENTORY)
|
|
if warning:
|
|
print(f"\nWARNING: {warning}")
|
|
|
|
print("\nGenerating and printing...")
|
|
success, pdf_path, warning = print_ptouch_label(TEST_INVENTORY, PRINTER, cfg)
|
|
|
|
print("\n" + "=" * 62)
|
|
print(f"PDF : {pdf_path}")
|
|
print(f"Result : {'SUCCESS' if success else 'FAILED'}")
|
|
if warning:
|
|
print(f"Warning : {warning}")
|
|
print("=" * 62)
|
|
return 0 if success else 1
|
|
|
|
|
|
if __name__ == "__main__":
|
|
raise SystemExit(main())
|