feat(renderer): scene 2 barcodes: whole-dot module fit, alignment in the box, decode tests (P3a) #18

Merged
james.maes merged 2 commits from feat/scene2-barcode-fit into develop 2026-11-13 14:00:13 +00:00
2 Commits
Author SHA1 Message Date
james.maesandClaude Fable 5.2 05518acd02 fix(renderer): scene 2 barcodes after independent review: no symbol reads as another value, rules by symbology, nothing painted over a symbol
maven / build (push) Successful in 6m59s
build / maven (push) Successful in 6m59s
A label is scanned, so a symbol must never read as something other than
the value it was given. Record values are untrusted and stay out of every
diagnostic and exception.

- No value, literal or bound, may hold the two characters an escape of the
  encoder begins with. \<FNC1> in a plain Code 128 value drew a GS1-128 of
  the record's choosing, \<FNC3> set the reader-programming flag, and QR
  dropped the escape. Refused in every symbology, with a count only.
- Interleaved 2 of 5 of an odd number of digits is refused, not padded.
- EAN and UPC values are the whole number with its check digit, which is
  verified; a shorter number is refused, never completed or padded.
- The check digit of every GS1 key in a gs1-128 element string is
  verified: the identifiers the GS1 Syntax Dictionary marks, as the
  bundled Zint carries it.
- VALUE_NOT_ENCODABLE joins the errors for these and for a value a
  symbology cannot hold; SCENE_INVALID is no longer used for a value. A
  symbol of more modules than the encoder draws is BARCODE_DOES_NOT_FIT.
- Quiet zones and the smallest module are a table by symbology
  (scene2/barcode/Symbology), each number with its source. barcodeProfile
  names the rule: none, gs1-general or gs1-logistics; not stated, the
  strictest written for the symbology. A GS1-128 is so held to 0.495 mm
  unless its scene says otherwise, at which a GTIN with a date and a
  serial number fits no label 4 in wide.
- The bars of a linear symbol must be as tall as its symbology asks, and
  the height is part of the fit. minHeight overrides, with the standing
  warning BARCODE_HEIGHT_BELOW_RECOMMENDED.
- QUIET_ZONE_INTRUDED is an error: an element later in the list whose ink
  would enter a symbol or its quiet zones is refused, when a scene is
  validated as when it is rendered.
- A barcode sits in the middle of its box unless the scene says otherwise.
- A bound barcode takes maxLength and is proven at validation in a linear
  symbology. FIT_NOT_PROVEN stays for no length and for two-dimensional
  symbols, whose encoders have no largest symbol of a length.

Codes and property names are added in one change: foundation's
FailureCode and warning set, the preview's sentences, the bridge's
accepted refusals and schema vocabulary, the renderer's vocabulary and
the schema. The three barcode goldens are unchanged byte for byte;
barcode-retail is new.

Co-Authored-By: Claude Fable 5.2 <noreply@anthropic.com>
2026-11-12 18:19:02 -06:00
james.maesandClaude Fable 5.2 f9a5def4f6 feat(renderer): scene 2 barcodes: whole-dot module fit, alignment in the box, decode tests (P3a)
A `barcode` element of a version 2 scene is now drawn into the picture of
the label instead of being refused as RENDERER_TOO_OLD.

- ModuleFit: the module is the largest whole number of dots at which the
  symbol, quiet zones included, fits its box; never under `minModule`
  (default 0.25 mm linear, 0.375 mm two-dimensional, taken up to whole dots)
  and never over `maxModule`. Integer arithmetic only.
- A linear symbol is fitted along its width and its bars take the whole
  height of the box; qr, datamatrix, pdf417 and aztec are fitted on both
  axes. The fitted symbol is placed by `align` and `valign`, turned by
  `rotation`, and paints its own white ground, quiet zones included.
- A value that does not fit at the minimum module is BARCODE_DOES_NOT_FIT,
  validated or rendered, with the modules and dots it needs and the dots
  the box has. A smaller module is drawn only when the scene states one,
  and then with the warning BARCODE_MODULE_BELOW_RECOMMENDED every time.
- The thirteen fit-qualified symbologies, `value` and `valuePath`, the
  dynamic symbology allowlist and the scanner profile are carried over from
  version 1, whose own barcode path is not changed. Every refusal is a
  diagnostic of numbers; what an encoder says about a value is dropped.
- `gs1` and `hri` stay declared; an element that states either is refused
  as RENDERER_TOO_OLD until the package that draws them.

Tests: every symbology at 203, 300 and 600 dpi for a short, a typical and
the longest value, rebuilt from the emitted ZPL and decoded by ZXing
(GS1-128 with FNC1 as `]C1`); seeded properties of the fit and of the
picture; goldens for a GS1-128 on 4 x 1 in, linear and two-dimensional
symbols; the version 2 mutation campaign extended to barcode elements.

Co-Authored-By: Claude Fable 5.2 <noreply@anthropic.com>
2026-11-12 17:25:40 -06:00