Skip to content

Validate LabelManager Wireless PnP support (fixes #81) - #156

Open
willumpie82 wants to merge 3 commits into
labelle-org:developfrom
willumpie82:fix/labelmanager-wireless-pnp-develop
Open

Validate LabelManager Wireless PnP support (fixes #81)#156
willumpie82 wants to merge 3 commits into
labelle-org:developfrom
willumpie82:fix/labelmanager-wireless-pnp-develop

Conversation

@willumpie82

Copy link
Copy Markdown

Summary

Picks up where #81 left off, per @maresb's request there to target develop instead of main. Thanks to @thinkl33t for the original groundwork — the auto-cut and 24mm-support ideas here build directly on that PR.

  • Validates this model's DeviceConfig. It's carried a print_head_px=64/print_head_mm=9 placeholder (~7.1 px/mm, copy-pasted from other models) since it was added, marked # ToDo: Validate config! and never confirmed — this is exactly the "squished output" Support for LabelManager Wireless PnP #81 reported. Measured on real hardware three independent ways (a printed calibration bar's physical width for a known pixel count, the tape distance covered by a fixed-size print batch, and a canvas height that visually filled a 24mm tape edge-to-edge), all agreeing on ~10.5–10.67 px/mm, and independently corroborated by a decoded USB capture of DYMO's own Windows software using the same scale. print_head_px=256, print_head_mm=24 matches (256/24 ≈ 10.667 px/mm).
  • Adds 24mm to supported_tape_sizes_mm (physically supported per this model's own datasheet).
  • Wires up _cut as an opt-in cut param (print/print_label/_raw_print_label) plus a new --cut CLI flag, defaulting off — Support for LabelManager Wireless PnP #81 found unconditional cut crashes printers without a cutter.
  • Fixes an infinite loop in _send_command's chunk-boundary search: it stopped at the synwait-th SYN character rather than past it, so for synwait=1 the boundary always landed back on the current read position — an empty chunk, no progress, forever. Verified with a 3000-trial fuzz test before touching real hardware.
  • Sends print lines sparsely instead of always at full canvas width from dot_tab 0. Real labels are usually mostly blank outside a thin band of content; reverse-engineered from a USB capture of DYMO's own software, which never sends a full-height line. Same printed image, far less data per job — likely why this device's small firmware buffer showed visible banding under the previous encoding, independent of USB-level flow control.
  • Fixes text vertical centering to use the actual ink bounding box instead of PIL's font ascent/descent metrics, which visibly shifts any text without descenders (names, acronyms, single words in caps) toward the top of the canvas.

Test plan

  • Full render_engines test suite (48/48; a python-barcode version mismatch in my sandbox caused unrelated pre-existing failures there, not a regression from this PR)
  • 3000-trial fuzz test on the corrected chunking algorithm (no infinite loop, no data loss, correct per-chunk line counts) prior to hardware testing
  • Exercised end-to-end on a real LabelManager Wireless PnP: correct centering, correct sizing on 24mm tape, no banding on long labels, clean cut via the new --cut flag
  • ruff check / ruff format --check clean

🤖 Generated with Claude Code

Willem Oldemans added 3 commits August 28, 2026 22:22
PIL's "mm" anchor centers multiline text using the font's line metrics
(ascent + descent), not the rendered glyphs' actual bounding box. Text
with no descenders (no g/j/p/q/y) then renders visibly shifted toward
the top of the canvas, since the reserved descender space below it
stays blank. This affects essentially any short label -- names,
acronyms, single words in caps.

Measure the real ink bounding box via multiline_textbbox and center on
that instead.
_send_command's chunk-boundary search stopped AT the synwait-th SYN
character rather than at the start of the line after it, so a "chunk
of synwait lines" actually contained one line fewer than intended --
and for synwait=1, that boundary always landed back on the current
read position, sending an empty chunk and making no progress: an
infinite loop, not merely an off-by-one. Fix the boundary search
(verified with a 3000-trial fuzz test against random command streams
before touching real hardware: no infinite loop, no data loss, correct
per-chunk line counts).

Separately, _raw_print_label always sent every line at full canvas
width starting from dot_tab 0, whatever fraction of that line was
actually ink. Real labels are usually mostly blank outside a thin
vertical band of content, so this sends far more data than necessary
on every single line. Reverse-engineered from a USB capture of DYMO's
own Windows software (which never sends a full-height line): trim each
line to the byte range containing ink, position it with the
(previously unused) _dot_tab command, and batch runs of fully blank
lines into a single _skip_lines call instead of full-width zero bytes.
Produces the exact same printed image, just far less data per job --
on hardware with a small firmware buffer, the previous encoding could
overrun it mid-print and produce visible banding purely from data
volume, independent of any USB-level flow control strategy.

_dot_tab's bounds check used the generic _max_bytes_per_line(tape_size)
formula, which is calibrated for the models it was originally written
against; a model with a much larger real addressable range (like the
LabelManager Wireless PnP, see the following commit) would have valid
dot_tab values incorrectly rejected. DymoLabelerFunctions now accepts
an optional max_bytes_per_line override (DymoLabeler._functions passes
its DeviceConfig's own print_head_px), falling back to the old formula
when not given. It also now skips re-sending ESC B when the value
hasn't changed (matching the existing optimization on _bytes_per_line),
avoiding redundant commands for the (common) case of several
consecutive lines with identical ink extent.

Also wires up the existing but previously-unused _cut command as an
opt-in `cut` parameter on `print`/`print_label`/`_raw_print_label`
(and a new --cut CLI flag), defaulting to False/off to preserve
existing behavior for callers/devices that don't want it -- see labelle-org#81,
which reported this crashing printers with no cutter when sent
unconditionally.
This model's entry has carried a print_head_px=64/print_head_mm=9
placeholder (copy-pasted from other models, ~7.1 px/mm) since it was
added, marked "ToDo: Validate config!" and never confirmed -- matching
exactly the "squished" output labelle-org#81 reported from this same placeholder.

Measured on real hardware three independent ways -- a printed
calibration bar's physical width for a known pixel count, the tape
distance covered by a fixed-size print batch, and a canvas height that
visually filled a 24mm tape edge-to-edge -- all agreeing on ~10.5-10.67
px/mm, and independently corroborated by a decoded USB capture of
DYMO's own Windows software using the same scale. print_head_px=256,
print_head_mm=24 matches (256/24 ≈ 10.667 px/mm).

Also adds 24mm to supported_tape_sizes_mm (physically supported per
this model's own datasheet; labelle-org#81 attempted this too, globally rather
than per-device) and sets distance_between_print_head_and_cutter_px
from this model's own calibration (previously defaulted to a value
derived from other models' scale) -- confirmed on hardware to clear
the cutter with no content loss, alongside the sparse-encoding and
cut fixes from the previous commit.

Removes the "not confirmed to work" messaging given the above, plus a
full print pipeline exercised end to end on real hardware including
the new --cut flag.

test_horizontally_combined_render_engine_multiple's golden image is
regenerated for the text-centering fix two commits back (unrelated to
this commit, just landing in the same golden-image-refresh pass): it
renders "Render labelle-org#1/2/3", none of which have descenders, so its
previous reference was affected by that same bug. Full render_engines
suite: 48/48 (barcode-related tests separately fail in the sandbox
this was verified in due to an unrelated python-barcode version
mismatch, not a regression here).

Thanks to @thinkl33t for the original groundwork in labelle-org#81 -- the auto-cut
and 24mm-support ideas here build directly on that; this picks up
where it left off per @maresb's request to target develop.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant