zpl.tools
Labelary extensions

~BI - Background Image

A Labelary extension, not a ZPL command: draws a Base64-encoded image behind the label to simulate colored or pre-printed stock.

~BI is not a ZPL command. Labelary added it to its own renderer so that a preview can show colored or pre-printed stock. It registers a Base64-encoded image, usually a PNG, and draws it behind the label. No Zebra printer implements it, it appears in no Zebra reference, and it is absent even from Labelary's own 230-row command table. The only place that documents it is Labelary's command reference, which flags it as a Labelary extension, one of exactly two alongside ~BR. A format that contains it is therefore not portable: on real hardware the BI mnemonic is ^BI, the industrial 2 of 5 bar code.

Syntax

~BIx,y,m,image

Support

Not implemented yetparsed: none · state: none · rendered: none

Recognised as valid ZPL and not implemented yet, so it has no effect on the output.

A Labelary-specific extension rather than ZPL, so no Zebra printer accepts it and it appears in no Zebra reference and in no Labelary command table. It draws a background, so it would change the rendered label. That makes it a real gap, not a safe command to ignore, and nothing schedules it yet. The renderer also does not recognize its own name. The dispatcher matches the two-character mnemonic without the prefix, so the parser reads it as ^BI industrial 2 of 5. It reports no unknown command; see the recorded deviations. — not pinned by a test

Absent from Labelary's command table.

Parameters

xHorizontal positionoptional · dots

Left edge of the image, measured from the left edge of the label.

Default
0
Accepted range
0 to the label width dots
Invalid value
not documented, and we have not measured it. Labelary documents the bounds but not what a position past the label edge does; the renderer does not implement the command.
Test coverage
No test at the minimum, maximum or one step outside the range.
yVertical positionoptional · dots

Top edge of the image, measured from the top of the label.

Default
0
Accepted range
0 to the label height dots
Invalid value
not documented, and we have not measured it. Labelary documents the bounds but not what a position past the label edge does; the renderer does not implement the command.
Test coverage
No test at the minimum, maximum or one step outside the range.
mMagnificationoptional · decimal

Scale for the image before the renderer draws it. The range starts below 1, so the image can shrink as well as grow; ^XG's magnification starts at 1.

Default
1
Accepted range
0.1 to 10 ×
Invalid value
not documented, and we have not measured it. Labelary documents the bounds but not the behavior outside them; the renderer does not implement the command.
Test coverage
No test at the minimum, maximum or one step outside the range.
imageImage dataoptional · text

The background image, usually a PNG, Base64-encoded. A ~BI with no arguments clears every background image registered so far.

Default
absent, which clears the registered background images
Invalid value
not documented, and we have not measured it. Labelary does not document what undecodable data or an unsupported image format does; the renderer does not implement the command.
Test coverage

Behavior

It registers an image, it is not a field

^FO and ^FT do not position ~BI, ^FS does not close it, and it belongs to no one label. Labelary registers the image and draws it behind every label it renders from then on. Measured against api.labelary.com at 8dpmm on 2026-07-29:

  • Registration outlives ^XZ. A ~BI before the first ^XA of a two-label format tints the second label as well as the first.
  • Registrations accumulate. Two ~BI commands draw two images, and the second does not replace the first.
  • ~BI with no arguments at all clears every image registered so far, and the labels after it come out plain. That is the only way to remove one.
  • Either side of ^XA works. A ~BI inside the format draws the same background as a ~BI before it.

Size and layers

One pixel of the image becomes one dot on the label, multiplied by the magnification: a 16 by 16 pixel PNG at magnification 10 covers 160 by 160 dots. Magnification goes down to 0.1, so ~BI can shrink an image as well as enlarge it. The equivalent range of ^XG starts at 1 and only enlarges.

The image sits behind everything the format prints. Text and bar codes drawn over it stay black and legible, and no field can go underneath it.

What this service does

The renderer draws no background, so the label renders on plain white. It reports the command once, as valid ZPL this renderer does not support yet, and reads nothing else out of it.

Until August 2026 the parser dispatched on the two-character mnemonic alone and did not check the prefix, so ~BI… reached the code path for ^BI industrial 2 of 5. That read the coordinates and the Base64 payload as bar code arguments. It answered six warnings about a bar code that is not there. Inside ^XA^XZ it also made the next field a bar code field, so ~BI0,0,10,… followed by ^FO70,90^A0N,30,30^FDColoured stock^FS drew nothing at all. ~BI is now its own command and neither happens.

Colored stock in production

ZPL cannot do it. A thermal printer marks the media in a single color, and the language has no color model. The color argument of ^GB chooses between black ink and white erasure, not between hues. Color comes from the media: order colored or pre-printed stock and let the printer put black on top of it. Keep ~BI for previews if it helps, and strip it before the format reaches a printer.

Differences from the specification

Labelary against the ZPL II guide

Where Labelary — our compatibility target — behaves differently from the printed specification.

  • The command is not in the ZPL II guide, and it is in no Labelary command table either. It is Labelary's own extension, one of exactly two, and only the engine's behavior documents 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 draws the image behind the label; the renderer draws no background, so the label renders on plain white. — not pinned by a test
  • The parser dispatches on the two-character mnemonic without the prefix, so ~BI reaches the ^BI industrial 2 of 5 arm. It reads the coordinates and Base64 payload as bar code arguments. No diagnostic reports the mismatch. The renderer instead reports six argument warnings against ~BI. We measured this on 2026-07-29 with ~BI50,50,10,<png>: they read Value '50' is too long and was trimmed to '5' and Value '5' is not a supported value for this argument and was ignored. — not pinned by a test
  • Because ^BI is a bar code command, a ~BI inside ^XA^XZ makes the next field a bar code field. We measured this on 2026-07-29: the following ^FDColored stock^FS draws nothing instead of text, so the label comes out blank. Before ^XA, where Labelary's own examples put it, the misparse costs only the warnings and the label renders normally. — not pinned by a test

Example

A 16 by 16 pixel yellow PNG at magnification 10, so it covers 160 by 160 dots starting at (50, 50), with a line of text printed over it:

~BI50,50,10,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAIAAACQkWg2AAAAFklEQVR42mP486eSJMQwqmFUw/DVAADGI3Efc+IpFwAAAABJRU5ErkJggg==
^XA
^FO70,90^A0N,30,30^FDBackground image^FS
^XZ

Open in viewer