Skip to content

feat(barcodes): GS1-mode QR (#152) - #159

Merged
Tim81 merged 2 commits into
mainfrom
barcodes-gs1-qr
Jul 6, 2026
Merged

feat(barcodes): GS1-mode QR (#152)#159
Tim81 merged 2 commits into
mainfrom
barcodes-gs1-qr

Conversation

@Tim81

@Tim81 Tim81 commented Jul 6, 2026

Copy link
Copy Markdown
Owner

Third symbology PR in the v1.10 barcode expansion (on main, groundwork already merged).

Adds a Gs1 option to the existing QrCode, reusing the QR engine and the merged Gs1ElementString/Gs1DigitalLink helpers — the highest effort-to-value item on the barcode roadmap.

Modes (QrGs1Mode)

  • ElementString — encodes GS1 Application Identifier data with the FNC1-in-first-position mode indicator (0b0101, ISO/IEC 18004 §7.4.8.2). Field separators are carried as raw 0x1D bytes in byte mode; alphanumeric mode is deliberately disabled for GS1 content to avoid the mode-dependent %/%% escaping ambiguity (documented in code, both forms are spec-sanctioned). The 4 FNC1 bits are counted toward version/capacity selection like the ECI header.
  • DigitalLink — encodes the content as a canonical https://id.gs1.org/... Digital Link URI (an ordinary text QR).
  • None (default) — the existing QR path is byte-for-byte unchanged.

GS1 mode requires text content; combining it with the byte-array constructor throws. Alt text surfaces the parenthesized-AI HRI (element string) or the URI (Digital Link).

New public surface (PublicAPI.Unshipped): QrGs1Mode (+ members) and QrCode.Gs1.

Testing

New unit tests (FNC1 indicator + capacity accounting, both modes, None regression guard), alt-text tests, and decode-oracle round-trips:

  • GS1 element-string QR → zxing-cpp decodes format QRCode, content_type == GS1, text (01)09501101020917(17)261231(10)ABC123.
  • Digital Link QR → decodes to https://id.gs1.org/01/09501101020917/17/261231/10/ABC123.

Also fixes a latent BarcodeRendererTests helper that didn't mirror PdfLiteralString's parenthesis escaping (so parenthesized alt text could never match).

Verified locally: dotnet build -c Release (0 warnings), 671 tests pass (oracle ran for real — pdftoppm + zxing-cpp), dotnet format --verify-no-changes clean, clean-room check pass.

Tim81 added 2 commits July 6, 2026 18:23
Add a Gs1 option to QrCode with two modes, reusing the existing QR engine and
the merged GS1 element-string / Digital Link helpers:

- QrGs1Mode.ElementString encodes GS1 Application Identifier data with the
  FNC1-in-first-position mode indicator (ISO/IEC 18004 section 7.4.8.2), field
  separators carried as raw 0x1D bytes in byte mode.
- QrGs1Mode.DigitalLink encodes the content as a canonical id.gs1.org GS1
  Digital Link URI.

The FNC1 indicator is counted toward version and capacity selection like the
ECI header; the non-GS1 path is unchanged. Human-readable alt text shows the
parenthesized-AI form for element strings or the URI for Digital Link.

Decode round-trips verified against zxing-cpp: the element-string symbol
reports content_type GS1, the Digital Link symbol its URI. Also fix a latent
BarcodeRendererTests helper that did not mirror PdfLiteralString paren escaping.
…ntent fix

Per adversarial review of #152: the FNC1 field separator (0x1D) and byte-mode
GS1 payloads had no value-level coverage. Add a separator round-trip oracle
(a multi-variable-AI payload with a real 0x1D separator, decode-verified as
content_type GS1 with correctly reconstructed AI boundaries), a %-in-value
oracle, always-on byte-mode-separator and multi-segment FNC1-exactly-once bit
checks, and a capacity double-count guard.

Also fix the exception contract: empty content with Gs1 set now throws
FormatException (the documented contract) instead of a leaked ArgumentException
from the GS1 parser.
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