^B4 - Code 49 Bar Code
Stacked alphanumeric symbology from the 1980s, superseded by PDF417 and Data Matrix.
^B4 prints a Code 49 symbol: two to eight stacked rows, each four symbol
characters wide, with one-module bars between the rows. It encodes the full
128-character ASCII set. Code 49 was an early attempt to put a large amount of
data into a small area, and ^B7 PDF417 and ^BX Data Matrix replaced it
completely. There is no reason to choose Code 49 for new work.
Syntax
^B4o,h,f,mSupport
Recognised as valid ZPL and not implemented, with no plan to.
Labelary does not implement ^B4 either, so there is no compatibility target to match and no plan to add one. The renderer draws nothing and reports a diagnostic. Use ^B7 PDF417 or ^BX Data Matrix instead; both hold more data and scan more reliably. — pinned by test_b4_does_not_fall_back_to_text, test_b4_draws_nothing_at_all, test_b4_reports_an_unrendered_barcode_diagnostic, test_b4_reports_once_per_field
Labelary does not implement it either, so there is no parity reference.
Parameters
oBar code orientationoptional · one of a setRotation of the symbol and interpretation line.
- Default
- the orientation set by
^FW, which itself defaults toN - Invalid value
- discarded, and the default applies. The renderer reports an unrecognized character as invalid, and uses the default.
- Test coverage
- No documented value is exercised by a test (N, R, I, B). The invalid-value rule is not pinned by a test.
N- No rotation (default)
R- Rotated 90° clockwise
I- Rotated 180°. The symbol reads upside down
B- Rotated 270° clockwise
hRow height multiplieroptional · integerThe renderer multiplies it by the ^BY module width for the height of one row.
- Default
- 1
- Accepted range
- 1 to the label height
- Invalid value
- not documented, and we have not measured it. The stated range is "1 to the label height", which is not a static bound. Labelary does not implement
^B4, so no measurement target exists. - Test coverage
- No test at the minimum, maximum or one step outside the range.
fInterpretation lineoptional · one of a setWhere the renderer places the human-readable text. Unlike the linear symbologies, this is one argument rather than two flags.
- Default
- N
- Invalid value
- discarded, and the default applies. The renderer reports an unrecognized character. The renderer prints no text.
- Test coverage
- No documented value is exercised by a test (N, A, B). The invalid-value rule is not pinned by a test.
N- No text (default)
A- Above the symbol
B- Below the symbol
mStarting modeoptional · one of a setWhich Code 49 encoding mode the data starts in.
- Default
- A
- Invalid value
- discarded, and the default applies. An unrecognized value defaults to automatic optimization.
- Test coverage
- No documented value is exercised by a test (0, 1, 2, 3, 4, 5, A). The invalid-value rule is not pinned by a test.
0- Regular alphanumeric mode
1- Multiple-read alphanumeric mode
2- Numeric mode
3- Group alphanumeric mode
4- Alphanumeric shift 1
5- Alphanumeric shift 2
A- Automatic optimization (default)
Behavior
Two details set Code 49 apart from the linear symbologies. The interpretation
line is one argument with three values and not two flags: A and B place the
line above or below the symbol, and N removes it. A scanner can also read the
rows in any order, because each row carries its own position.
The starting mode is the usual source of trouble in a Code 49 format. At the
default A the printer analyzes the field data, chooses the mode, makes the
character shifts and compacts the data. A mode from 0 to 5 requires the field
data to be valid Code 49 internal characters, which are not ASCII. Lower case and
most punctuation need a two-character sequence of a shift character and an
unshifted character, so a lower-case a is sent as >A.
An invalid sequence is not an error. The formatter stops there and prints a symbol with only the data before it.
The height argument is a multiplier and not a height. The printer multiplies it
by the ^BY module width to get the height of one row. The guide does not
recommend the value 1. Code 49 has a fixed print ratio, so the ^BY ratio
argument has no effect.
Code 49 offers no alternative of its own. Use ^B7 PDF417 or ^BX Data Matrix.
Both hold more data, scan more reliably, and render today.
Tested behavior
Differences from the specification
Labelary against the ZPL II guide
Where Labelary — our compatibility target — behaves differently from the printed specification.
- The guide gives the row-height multiplier default as the value that
^BYsets. Labelary documents a default of 1. Neither engine implements the command, so no measurement exists. — not pinned by a test
zpl.tools against the ZPL II guide
Where our renderer behaves differently from the specification.
- The guide takes the default orientation from
^FW. The renderer applies^FWto text fields only. A barcode after^FWRprints unrotated unless its ownoargument rotates it. — not pinned by a test
zpl.tools against Labelary
Where our output differs from Labelary for the same input. These are the differences that break a migration.
- Labelary does not draw a symbol either, but prints the field data on the label as an ordinary text run with no warning (measured 2026-07-30). The renderer draws nothing and reports a diagnostic, so a label that looks plausible on Labelary comes back empty. — not pinned by a test
Example
The guide's own example, in automatic mode with the interpretation line above the symbol:
^XA
^FO50,50^BY3
^B4N,20,A,A
^FD12345ABCDE^FS
^XZ
Related commands
^B7PDF417 Bar CodeStacked two-dimensional symbology that holds several hundred bytes, used on driving licenses and shipping documents.^BXData Matrix Bar CodeCompact two-dimensional symbology used for small-part marking and GS1 DataMatrix.^BBCodablock Bar CodeStacked Code 128 variant that holds more data than one linear row, superseded by PDF417.