Add P-touch Labels for Asset: 63x20 mm label format for PT-E560BT
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.
This commit is contained in:
@@ -0,0 +1,160 @@
|
||||
# PT-E560BT Label Format (63 x 20 mm)
|
||||
|
||||
Three-column label layout for the Brother P-touch EDGE **PT-E560BT**.
|
||||
|
||||
```
|
||||
0 20 mm 45 mm 63 mm
|
||||
+---------+------------+--------+ 0
|
||||
| | static 1 | Q R |
|
||||
| LOGO | static 2 | C O | 1 mm non-printable gutter
|
||||
| 16x16 | static 3 | D E |
|
||||
| | VARIABLE | |
|
||||
+---------+------------+--------+ 20 mm
|
||||
20 mm 25 mm 18 mm
|
||||
```
|
||||
|
||||
## Interface
|
||||
|
||||
Run the new GUI:
|
||||
|
||||
```bash
|
||||
python label_printer_ptouch_gui.py
|
||||
```
|
||||
|
||||
| Element | Purpose |
|
||||
|---|---|
|
||||
| **Inventory number** | The single variable value per label. Becomes the 4th text line **and** is embedded in the QR code. |
|
||||
| **PRINT LABEL** | Generates the PDF and sends it to the selected printer. |
|
||||
| **Preview area** | Renders the label at true print proportions. Updates as you type. |
|
||||
| **Advanced settings** | Logo image, the three static text lines, QR prefix/suffix, QR error correction. Saved to `label_config.json`. |
|
||||
|
||||
The old three-row format is still available via `label_printer_gui.py` and is
|
||||
unchanged.
|
||||
|
||||
## Hardware constraints
|
||||
|
||||
Verified against Brother's published specifications *and* the installed Windows
|
||||
driver (via `GetDeviceCaps`), which agree:
|
||||
|
||||
| Spec | Value | Consequence |
|
||||
|---|---|---|
|
||||
| Print resolution | **180 dpi**, 128-dot head | 128 / 180 x 25.4 = **18.06 mm** is the hard height limit |
|
||||
| Max print height | **18.0 mm**, only with 24 mm tape | A 20 mm design cannot fit; it is not a margin setting |
|
||||
| Max tape width | 24 mm | **24 mm tape required** |
|
||||
|
||||
Because the head reaches only ~18 mm of the 24 mm tape, ~3 mm is unused on each
|
||||
side. The label content is sized to the driver's **printable area**, read at
|
||||
runtime by `print_area.py`, rather than to the nominal media size.
|
||||
|
||||
### Driver resolution modes
|
||||
|
||||
The Brother driver offers two modes, and the choice matters:
|
||||
|
||||
| Mode | xdpi | ydpi | Notes |
|
||||
|---|---|---|---|
|
||||
| 1 | 180 | 180 | symmetric - use this |
|
||||
| 2 | 180 | 360 | **anisotropic**, 2x across the tape |
|
||||
|
||||
In the anisotropic mode the driver reports twice the horizontal dots, and a page
|
||||
authored in millimetres can be scaled by the wrong factor and print short.
|
||||
`set_printer_resolution.py` reads and switches this setting:
|
||||
|
||||
```bash
|
||||
python set_printer_resolution.py # show current mode
|
||||
python set_printer_resolution.py --mode 180 # symmetric (recommended)
|
||||
python set_printer_resolution.py --restore # undo
|
||||
```
|
||||
|
||||
## Why the code is dot-aligned
|
||||
|
||||
A thermal head cannot print a fraction of a dot. If a QR symbol is scaled to an
|
||||
arbitrary size, its modules end up unevenly sized (some 3 dots wide, some 4),
|
||||
which is the usual reason a small QR code will not scan.
|
||||
|
||||
`build_code_bitmap()` snaps the symbol to an integer number of printer dots per
|
||||
module and returns the resulting exact physical size. At 16 mm available and 29
|
||||
modules (a typical short payload), that is **3 dots per module = 12.28 mm**,
|
||||
which scans comfortably.
|
||||
|
||||
`code_density_warning()` estimates density for the current payload and the GUI
|
||||
shows a warning when the code becomes too dense to be reliable, instead of
|
||||
silently printing an unscannable label.
|
||||
|
||||
## Code payload
|
||||
|
||||
The code is composed as **fixed prefix + inventory + fixed suffix**, configured in
|
||||
Advanced settings:
|
||||
|
||||
| Prefix | Inventory | Suffix | Encoded |
|
||||
|---|---|---|---|
|
||||
| `INV-` | `1234` | *(empty)* | `INV-1234` |
|
||||
| `INV-` | `1234` | `-A` | `INV-1234-A` |
|
||||
| *(empty)* | `1234` | *(empty)* | `1234` |
|
||||
|
||||
The `Encodes:` line in Advanced settings shows the exact payload live as you type,
|
||||
so the result can be confirmed before printing.
|
||||
|
||||
A legacy `{inventory}` template (e.g. `INV:{inventory}`) is still accepted and is
|
||||
migrated to prefix/suffix on first save, so older config files keep working.
|
||||
|
||||
**Keep the payload short.** The QR is maximised to fill the printable height
|
||||
(~16.4 mm at 29 modules), which gives **4 printer dots per module** for a short
|
||||
payload. Longer strings raise the QR version, reducing dots per module; the GUI
|
||||
warns before printing a code that would be too dense to scan reliably. Error
|
||||
correction `L` allows a longer string than `M`/`Q`/`H` at the same physical size.
|
||||
|
||||
## Maximising the QR
|
||||
|
||||
By default `qr_maximize` is enabled: the code column takes the full printable
|
||||
height so the symbol is as large as the hardware allows, and the text column
|
||||
shrinks to make room (never below `MIN_TEXT_COL_MM`, so the three static lines
|
||||
keep fitting).
|
||||
|
||||
| Setting | QR size | Dots/module |
|
||||
|---|---|---|
|
||||
| `qr_maximize: false` (16 mm box) | 12.28 mm | 3 |
|
||||
| `qr_maximize: true` (default) | 16.37 mm | 4 |
|
||||
|
||||
The symbol is flush to the right edge of the printable area when maximised. If
|
||||
your unit feeds the tape slightly off-centre, reduce `qr_box_mm` and set
|
||||
`qr_maximize: false` to leave clearance.
|
||||
|
||||
## Logo
|
||||
|
||||
- Formats: PNG, JPG, JPEG, BMP, GIF. Greyscale and alpha are handled (transparent
|
||||
areas are flattened to white).
|
||||
- The logo is scaled to fit the 16 x 16 mm cell preserving aspect ratio.
|
||||
- Thermal transfer printing is 1-bit, so logos should be **black-and-white line
|
||||
art**. Photographs dither poorly. `logo_dither` controls this.
|
||||
|
||||
## Files
|
||||
|
||||
| File | Role |
|
||||
|---|---|
|
||||
| `ptouch_label.py` | Layout engine: geometry, code generation, PDF + preview renderers |
|
||||
| `label_config.py` | Settings persistence (`label_config.json`) |
|
||||
| `label_printer_ptouch_gui.py` | Kivy GUI (this format) |
|
||||
| `print_label.py` | Printer discovery and silent printing (extended) |
|
||||
| `validate_ptouch_layout.py` | Geometry + QR round-trip validation |
|
||||
| `test_ptouch_pipeline.py` | End-to-end test (no hardware needed) |
|
||||
|
||||
## Tests
|
||||
|
||||
```bash
|
||||
python validate_ptouch_layout.py # page size, boxes, QR round-trip
|
||||
python test_ptouch_pipeline.py # config, PDF, printing, QR scaling
|
||||
```
|
||||
|
||||
`validate_ptouch_layout.py` re-reads the rendered QR symbol out of the preview
|
||||
image, module by module, and compares it against the source matrix. That is what
|
||||
proves the preview and the PDF are the same layout, and that the symbol is
|
||||
geometrically intact after dot-alignment.
|
||||
|
||||
## Printing notes
|
||||
|
||||
Only SumatraPDF printing honours the scale setting. The PDF is sent with
|
||||
`-print-settings noscale` because driver-side scaling ("fit to page") would
|
||||
distort the QR module pitch and break scanning.
|
||||
|
||||
In the printer driver, set the media to the **63 x 20 mm** continuous tape and
|
||||
disable any auto-rotate. The TZe tape must be **24 mm**.
|
||||
Reference in New Issue
Block a user