Files
label_printer/documentation/PTOUCH_63x20.md
T
ske087 93afa3c417 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.
2026-09-25 17:30:11 +03:00

6.2 KiB

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:

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:

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.

  • 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

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.