Construction
New to these terms? module , check digit , quiet zone , X-dimension , symbology - the linked pages cover each one from first principles.
A family, not a single symbology
ISO/IEC 24724 defines seven distinct DataBar symbologies. They share the same underlying RSS character encoding (16 modules per character, 4 bars and 4 spaces with module widths of 1–8) but differ in how the characters are laid out into a complete symbol.
| Variant | Total modules (width) | Minimum height | Layout notes |
|---|
| DataBar Omnidirectional | 96 modules | 33×X (minimum) | Full GTIN-14, scannable in any orientation at POS. |
|---|
| DataBar Truncated | 96 modules | 13×X (minimum) | Same 96-module width as Omnidirectional; reduced height for raster-only scanners. |
|---|
| DataBar Stacked | 50 modules | 13×X (each row) | Two-row layout: 4 left-half characters above, 4 right-half characters below, separated by a 1-module-wide black bar. |
|---|
| DataBar Stacked Omnidirectional | 50 modules | 33×X (each row) | Stacked layout in full omnidirectional height. |
|---|
| DataBar Limited | 74 modules | 10×X (minimum) | Compact variant restricted to GTIN indicator digits 0 or 1. |
|---|
| DataBar Expanded | 102 modules | 34×X (minimum) | Variable width by content; encodes GTIN + GS1 Application Identifiers. |
|---|
| DataBar Expanded Stacked | 102 modules | multi-row | 1–11 rows of Expanded segments, separated by a 1-module-wide black bar. |
|---|
Source: ISO/IEC 24724:2011. "X" is the X-dimension - the width of a single narrow module.
Symbol structure - DataBar Omnidirectional
The Omnidirectional symbol is built from four RSS-14 data characters plus a finder pattern in the centre. The 14 digits of the GTIN-14 are split into a left half (digits 1–7) and a right half (digits 8–14); each half is encoded by two adjacent RSS characters.
- Left quiet zone - ≥ 1× X-dimension.
- Left outer character - 16 modules.
- Left inner character - 16 modules.
- Finder pattern - 15 modules; one of 9 fixed patterns identifying the finder index - see "Finder pattern" below.
- Right inner character - 16 modules.
- Right outer character - 16 modules.
- Total - 4 × 16 + 15 = 79 data modules; with mandatory single-module guards on each side the printed width is 96 modules.
- Right quiet zone - ≥ 1× X-dimension.
The Truncated variant is the same 96-module pattern with reduced height; the Stacked variants split the four data characters across two rows separated by a 1-module-wide horizontal bar (the separator pattern).
Finder pattern
The finder pattern is a 15-module-wide block of four elements (bar/space/bar/space) inserted between the inner two characters. ISO/IEC 24724 defines a finite set of nine finder patterns (numbered 1–9), and the choice of finder is determined by how the seven left-half digits and seven right-half digits split between the four data characters. The finder serves two purposes:
- It marks the symbol centre, letting omnidirectional scanners locate the symbol regardless of scan-line orientation.
- It carries part of the encoded data - specifically, the partitioning of the 14-digit GTIN among the four characters.
RSS-14 character encoding
Each RSS-14 data character encodes a value 0–Nk drawn from a partition table (the k-out-of-n rule) and renders that value as 16 modules: 4 bars and 4 spaces, each element being 1 to 8 modules wide. The exact module widths for the i-th element depend on the character value and which of the two RSS-14 sub-sets the character belongs to (outer vs inner).
DataBar uses a fixed sum-of-elements rule: the 4 bars must sum to a fixed number of dark modules and the 4 spaces must sum to a fixed number of light modules for the chosen sub-set. This gives the symbol its uniform width regardless of payload - the variable-width property is per-element, not per-symbol.
Internal check character
Every DataBar symbol carries an internal check character distinct from the GS1 mod-10 GTIN check digit. ISO/IEC 24724 specifies a weighted mod-79 checksum computed over the four RSS-14 data character values (with the finder index folded in for Omnidirectional). The check value itself influences which finder pattern is used - the finder doubles as the check carrier - rather than appearing as a separate printed character.
The GS1 mod-10 check digit on the encoded GTIN-14 (see EAN-13 ) is preserved as part of the payload - it is not removed before encoding.
DataBar Expanded
DataBar Expanded is structurally different: it encodes variable-length data using up to 20 RSS-Expanded data characters in a single row (DataBar Expanded) or stacked across 1–11 rows (Expanded Stacked). The payload is a sequence of GS1 Application Identifiers, packed using compaction modes (numeric, alphanumeric, ISO 646) that vary by AI. Like DataBar Omnidirectional, it uses 15-module finder patterns between adjacent character pairs - but Expanded uses 12 distinct finder patterns rather than 9.
X-dimension and quiet zone
GS1 General Specifications set the minimum X-dimension for general retail at 0.264 mm, with reduced values down to 0.170 mm permitted for variants designed for small-item marking (DataBar Limited and Stacked Omnidirectional in particular). Quiet zones are 1× X on each side - significantly less than the 10× quiet zone of EAN/UPC, which is part of what makes DataBar usable on small labels.
Encoder reference
This section captures the algorithmic detail an encoder author needs that isn't immediately obvious from the conceptual description above. The lookup tables it references live in ISO/IEC 24724:2011 Annex A (RSS-14 character set), Annex B (RSS Limited), Annex C (RSS Expanded), and Annex D (Composite component, where DataBar is paired with a 2D barcode). Where a specific numeric table is not embedded inline below, it is marked as a spec-extraction TODO with the relevant Annex reference - the encoder embeds the tables verbatim once extracted.
Character generation - k-out-of-n combinatorial enumeration
Every RSS character is generated by enumerating all 4-element compositions of a fixed module total T where each element is at least 1 module and at most some sub-set-specific maximum. The character value V is the rank of a particular composition in that enumeration. The enumeration uses two interleaved sequences - one for the four bar widths and one for the four space widths - with the choice of which (V_bar, V_space) pair to use determined by lookup tables per sub-set.
The number of compositions of T into k parts each in [1, max] is the well-known restricted-composition count. Its inverse - given a rank V, find the composition - is computed greedily:
// Restricted-composition count: number of ways to write T as
// the sum of k positive integers each ≤ max.
function count(T: number, k: number, max: number): number {
if (k === 0) return T === 0 ? 1 : 0
let total = 0
for (let v = 1; v <= Math.min(max, T); v++) {
total += count(T - v, k - 1, max)
}
return total
}
// Inverse: given a rank V, recover the k widths summing to T.
function rankToWidths(V: number, T: number, k: number, max: number): number[] {
const widths: number[] = []
let remaining = T
let rank = V
for (let i = 0; i < k; i++) {
for (let w = 1; w <= Math.min(max, remaining); w++) {
const tail = count(remaining - w, k - 1 - i, max)
if (rank < tail) { widths.push(w); remaining -= w; break }
rank -= tail
}
}
return widths
}
The actual encoder hard-codes the per-sub-set constants T, max, and the total character count. See ISO/IEC 24724:2011 Annex A.3 for the four RSS-14 sub-set parameters (outer left, outer right, inner left, inner right) and the analogous Annex B for Limited, Annex C for Expanded. The combinatorial recurrence above is identical across all sub-sets - only the constants change.
Finder patterns
A finder pattern is 15 modules wide, structured as four elements bar / space / bar / space whose widths sum to 15. The decoder uses the finder both to lock onto the symbol centre and to recover the partitioning of the encoded value across the four data characters (the finder index).
| Variant | Finder count | Selection rule |
|---|
| RSS-14 Omnidirectional / Truncated / Stacked | 9 | Function of how the 14 GTIN digits split among the four data characters: the (left_outer, left_inner, right_inner, right_outer) partition of the 13-digit value determines the finder index. See ISO/IEC 24724 Table 7. |
|---|
| RSS Limited | 1 (no separate finder) | RSS Limited uses fixed start/stop patterns instead of a centre finder. The two data characters sit between them. |
|---|
| DataBar Expanded | 12 | Sequence of finders chosen per character-pair to encode pair index modulo 12 + parity. See ISO/IEC 24724 Table 17. |
|---|
Finder pattern bit-strings (TODO): the 9 Omnidirectional and 12 Expanded finder patterns are each defined by a (b1, s1, b2, s2) tuple of element widths summing to 15. The specific tuples must be extracted from ISO/IEC 24724 Tables 7 and 17 and embedded as readonly number[][] constants in the encoder. They are short, deterministic, and stable across spec revisions - no algorithm generates them, they are simply tabulated. Do not hand-roll an implementation without the tables in front of you.
Internal check character - weighted modulo 79
The internal check character is computed over the data character values (plus, for Omnidirectional variants, the finder pattern index) using a weighted sum modulo 79. The weight vector W has one entry per data character position; the entries differ per variant. The weights for RSS-14 Omnidirectional are tabulated in ISO/IEC 24724:2011 Annex A.4 Table 6; for Expanded they appear in Annex C.3 Table 14.
// Compute the internal check character for an RSS-14 variant.
// `dataValues` are the four 17-bit RSS-14 character values; `weights`
// is the 4-entry weight vector from ISO/IEC 24724 Annex A.4 Table 6.
function checkCharacter(dataValues: number[], weights: number[]): number {
let sum = 0
for (let i = 0; i < dataValues.length; i++) {
sum += dataValues[i] * weights[i]
}
return sum % 79
}
The check value does not appear as a printed character - it is folded into the finder pattern selection. The finder index F satisfies F = check % 9 for Omnidirectional, so the finder carries the check value implicitly. This is what lets DataBar fit a 14-digit GTIN plus error detection into 96 modules without spending a character cell on a check digit.
DataBar Expanded - compaction sub-modes
DataBar Expanded packs a sequence of GS1 Application Identifiers (AIs) into a bit stream, then groups the bits into 12-bit "characters" of value 0–4095 (each character is then encoded as one 17-module RSS-Expanded character). The encoder switches between four compaction sub-modes via explicit transition codewords; the sub-mode determines how many bits each input character consumes.
| Sub-mode | Bits per input char | Character set | Typical use |
|---|
| Numeric | 10 bits / 3 digits (≈ 3.33 bits/digit) | Digits 0-9 + FNC1 separator | GTIN, batch/lot codes, dates - the densest mode for all-digit AIs. |
|---|
| Alphanumeric | 5 or 6 bits / char | 32-char subset: digits, uppercase A-Z, plus a small punctuation set | Serial numbers and lot codes mixing letters + digits. |
|---|
| ISO/IEC 646 | 7 bits / char | Full ISO/IEC 646 (7-bit ASCII) printable range | Free-text fields where lower case, full punctuation, or non-alphanumeric symbols are required. |
|---|
| General-purpose (FNC1-aware) | Variable | Same as alphanumeric + structured AI prefix handling | Default mode for AI-prefixed payloads; the encoder emits an FNC1 codeword between AIs of variable length to mark boundaries. |
|---|
Sub-mode transitions are signalled by reserved codeword values defined in ISO/IEC 24724:2011 Annex C.6. The encoder must scan ahead to choose the mode that minimises symbol size, which often means staying in Numeric mode for AIs known to be all-digit (AI 01 GTIN, AI 17 expiry date, AI 10 batch when it happens to be numeric) and switching to a wider mode only when a non-digit appears.
Encoder pipeline (DataBar Omnidirectional)
Putting the pieces together, the encoder for a 14-digit GTIN takes the following path:
- Split the 13-digit value (the 14-digit GTIN minus its mod-10 check digit, which is preserved as part of the payload but not re-encoded by DataBar's internal check) into a left half and a right half using the partitioning defined in ISO/IEC 24724 Annex A.2.
- Map each half to a (left_outer, left_inner) or (right_inner, right_outer) character value pair, drawing from the sub-set-specific value range.
- Compute the internal check character via the weighted-mod-79 algorithm above and derive the finder index
F = check % 9. - Emit modules in order: left_outer (16 modules) → left_inner (16) → finder[F] (15) → right_inner (16) → right_outer (16). Each character's 16 modules come from
rankToWidths() applied to the character value with the sub-set's (T, k, max) constants - interleaving bars and spaces as specified in Annex A.3. - Add guards - a single dark module on each side of the data region, then the 1× X-dimension quiet zone.
Stacked variants apply the same pipeline but split the four data characters across two rows separated by a 1-module-high horizontal separator pattern. Expanded follows the same combinatorial-enumeration and finder-selection pattern but with sub-mode-aware bit packing replacing the GTIN-specific value mapping.