Skip to content

Feat/zpl bs and hri refactor#90

Merged
u8array merged 4 commits into
mainfrom
feat/zpl-bs-and-hri-refactor
May 24, 2026
Merged

Feat/zpl bs and hri refactor#90
u8array merged 4 commits into
mainfrom
feat/zpl-bs-and-hri-refactor

Conversation

@u8array
Copy link
Copy Markdown
Owner

@u8array u8array commented May 24, 2026

No description provided.

u8array added 3 commits May 23, 2026 20:46
New standalone object type for the ^BS supplement printed alongside
UPC-A / EAN-13. Common uses: 5-digit ISBN price code on books,
2-digit issue number on magazines. The user positions it manually
next to the main barcode (separate object), mirroring how the rest
of the registry works (one type per ZPL command, no cross-cutting
props on existing types).

ZPL: single ^BS{o},{h},{f} command for both lengths. Canvas:
bwip-js bcid resolved from content.length (ean2 vs ean5) since
bwip splits what ZPL unifies. bwip needs explicit includetext +
textyalign='above' to match Zebra firmware, which prints the
human-readable digits above the bars (unlike main EAN/UPC where
they sit below).

Bbox math matches Labelary:
- printInterpretation=Y: bbox extends UPC_SUPP_TEXT_ZONE_DOTS (18)
  above the FO anchor; bars sit at obj.y, text above
- printInterpretation=N: bbox = bar height (no guard, unlike main
  EAN/UPC which always reserves 13)
The canvas y-shift handles the above-anchor placement in
BarcodeObject; tests special-case visualY for the supplement.

Validation: ContentSpec gained `validLengths` for soft-warning when
the field isn't a valid length set. UPC/EAN supplement spec uses
[2, 5]; the PropertiesPanel surfaces an inline amber hint when the
length is wrong (no input blocking, since the user has to pass
through invalid lengths to reach 5).

Parser, generator, locale entries for all 32 locales (best-effort
quality tier), support matrix update (BS unsupported -> supported),
public roadmap entry moved from Coming soon to Supported.

Coverage: round-trip tests for both lengths and rotation;
bcid-resolution test in bwipHelpers; contentSpec validation tests;
Labelary visual-regression and bbox-sync fixtures for both supps
(bars-only N variant so the bwip-vs-Zebra font difference doesn't
break the strict pixel diff).

Known limitation: bwip-js ean2 renders 19 modules where Zebra
prints 20, a 2-dot width delta documented at hasBwipSizeMismatch
in labelarySync.test.ts.
Three changes that all centre on the rotated 1D HRI overlay:

1. Extract getRotatedTextAnchor in bwipHelpers. The previous per-rotation
   sideX math (-textGap / w+textGap) anchored against the bbox edge,
   which silently double-counted the firmware text zone (EAN/UPC: 13
   dots, logmars: 20 dots). The helper anchors against the bar
   sub-rectangle so the gap is exactly textGap regardless of which side
   the zone sits on. Fixes a pre-existing spacing bug on rotated
   logmars + ean13/upca/ean8/upce.

2. Switch ^BS (upcEanExtension) HRI from bwip-embedded text to a Konva
   overlay, matching the logmars pattern. bwip's includetext bakes the
   text into the bitmap, which then rotates as a unit and lands on the
   wrong side for R/B/I; the overlay positions correctly via the
   helper. Drops the fillFullBbox special case and the upcEanExtension
   exclusion from showText.

3. Per-type above-bars gap. logmars keeps its wider 10-dot air gap
   (LOGMARS_TEXT_ABOVE_GAP_DOTS); ^BS sits very tight to the bars
   (UPC_SUPP_TEXT_ABOVE_GAP_DOTS = 2) per Labelary. Also anchor the
   upright text-above against btY so the firmware-reserved text zone
   isn't added on top of the visual gap.

HRI text now renders bold across all 1D types, slightly closer to the
Zebra HRI weight than plain Courier New.
Replace the obj.type-string chains in BarcodeObject (isTextAbove,
aboveGap, displayText) with an `hri?: HriBehavior` field on each 1D
leaf. New `hri` fields wired for ean13/ean8/upca/upce/code39/logmars/
upcEanExtension; defaults preserve behaviour for the remaining 1D
types (raw content, below bars, textGap).

Per-type formatters live in registry/hriFormatters.ts. Check-digit
math (eanCheckDigit / upceCheckDigit) moved from Canvas/bwipHelpers
to lib/barcodeCheckDigits.ts so the registry can import without
crossing into the Canvas layer; bwipHelpers re-exports for
backwards compat.

The EAN/UPC multi-Text digit-split branches consume displayText
directly instead of recomputing the formatted string inline, so the
registry's formatHri is the single source of truth for HRI content.

Net effect: adding a new 1D symbology no longer touches BarcodeObject
to wire up its HRI behaviour; everything lives in the leaf.
Copy link
Copy Markdown

@gemini-code-assist gemini-code-assist Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request implements support for the ^BS UPC/EAN supplement barcode, including its 2-digit and 5-digit variants. The changes involve updating the ZPL parser and generator, adding localization strings across multiple languages, and introducing a new HriBehavior configuration to handle human-readable interpretation (HRI) text positioning (specifically for text rendered above bars). Additionally, check-digit logic was moved to a pure utility file for better reusability. A critical issue was identified in the bounding box calculation for logmars barcodes, where the isTextAbove flag needs to be applied to ensure correct rendering bounds.

Comment thread src/components/Canvas/bwipHelpers.ts Outdated
bwipHelpers.getDisplaySize was hardcoding `isTextAbove` to
upcEanExtension only, leaving logmars treated as text-below. The bbox
reserved the firmware text zone at the bottom while BarcodeObject
drew the HRI overlay above the bars at negative y — text leaked
outside the selection bbox. Reading hri.textAbove from the registry
fixes logmars and matches the source of truth BarcodeObject already
consumes. Bug spotted by gemini review on PR #90.

Also pick up the remaining nits from the prior round:
- JSDoc on HriBehavior points at logmars / upcEanExtension as
  canonical examples for new contributors
- Unit tests for hriFormatters cover happy path + edge cases
  (invalid chars in LOGMARS charset, short inputs, length-driven
  routing in ^BS) — 15 new tests
@u8array u8array merged commit 78f883a into main May 24, 2026
2 checks passed
@u8array u8array deleted the feat/zpl-bs-and-hri-refactor branch May 24, 2026 11:04
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