zpl.tools
Fonts and text

^PA - Advanced Text Properties

Turns on bidirectional layout, character shaping and OpenType features.

^PA switches on the parts of text layout that go beyond one glyph after another:

  • the reorder of right-to-left runs
  • the contextual form of a letter
  • the OpenType tables of a font

Arabic, Hebrew and the Indic scripts need at least one of them to be readable. All four settings are off by default, so the ZPL default is the naive one: bytes in, glyphs out, left to right.

Syntax

^PAa,b,c,d

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.

The renderer does not parse this command yet. No font here carries a Hebrew or Indic glyph, so those scripts draw nothing; Arabic draws unjoined isolated forms on the faces that carry it. — not pinned by a test

Labelary renders this command. Scheduled for milestone 5.9.

Parameters

aDefault glyphoptional · one of a set

What to print where the font has no glyph for a character.

Default
the previously set value, or 0
Invalid value
discarded, and the current value is kept
Test coverage
No documented value is exercised by a test (0, 1). The invalid-value rule is not pinned by a test.
0
Print a space for a character the font lacks (default)
1
Print the font's own default glyph for a missing character
bBidirectional text layoutoptional · one of a set

Whether the renderer applies the Unicode bidirectional algorithm.

Default
the previously set value, or 0
Invalid value
discarded, and the current value is kept
Test coverage
No documented value is exercised by a test (0, 1). The invalid-value rule is not pinned by a test.
0
Off. Characters print in the order they appear (default)
1
On. The renderer reorders right-to-left runs for display
cCharacter shapingoptional · one of a set

Whether the renderer substitutes glyphs by their neighbors.

Default
the previously set value, or 0
Invalid value
discarded, and the current value is kept
Test coverage
No documented value is exercised by a test (0, 1). The invalid-value rule is not pinned by a test.
0
Off (default)
1
On. The renderer selects contextual forms, as Arabic requires
dOpenType table supportoptional · one of a set

Whether the renderer applies OpenType layout features.

Default
the previously set value, or 0
Invalid value
discarded, and the current value is kept
Test coverage
No documented value is exercised by a test (0, 1). The invalid-value rule is not pinned by a test.
0
Off (default)
1
On. The renderer uses the font's OpenType layout tables

Behavior

The command sets printer state rather than field state: it applies to the fields that follow, and stays in force until the next ^PA changes it. Each argument is independent, and an omitted argument keeps the previous value rather than defaults to 0, so ^PA,,1 turns shaping on and leaves the rest alone.

The first argument is a diagnostic aid as much as a layout switch. ^PA0 prints a space for a character the font has no glyph for, and that space looks like an intended one. ^PA1 prints the font's .notdef glyph instead, usually an empty box, which makes a missing glyph visible. Turn it on where text comes out unexpectedly short.

Measured against Labelary on 2026-08-22: the third argument covers both the joining of letterforms and the placement of combining marks, and the fourth changed nothing on any probe. A value outside 0 and 1 is named and dropped, as in Value 2 is not a valid bidi layout flag (0/1) and was ignored.

Shaping and bidirectional layout are properties of the layout engine, not of the encoding, so ^PA is not a substitute for ^CI28. Neither command is a substitute for a font that contains the glyphs, which for these scripts means a ~DU download.

Differences from the specification

Labelary against the ZPL II guide

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

  • ^PA is absent from the 2006 guide; Labelary's reference is the only description of it used here. — 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 honors the default-glyph argument: with ^PA1, a character the font has no glyph for prints as the font's .notdef box. We measured that the renderer ignores ^PA, so such a character always prints as a space. — not pinned by a test
  • No font in this renderer holds a Hebrew glyph, so a Hebrew field draws nothing where Labelary's scalable faces draw the word. Measured 2026-08-22: ^CI28^FDשלום at 150 dots is 13,712 dots of ink on Labelary's face 0 and blank here. — not pinned: the only case that exercises it records a known issue (test_pa_hebrew_prints_nothing_where_labelary_prints_the_word)
  • Face A is DejaVu Sans Mono, which carries isolated Arabic, so an Arabic field draws unjoined letterforms in logical order here. Labelary has no face that can show Arabic at all and answers Field data contains characters which the field font cannot display. — not pinned: the only case that exercises it records a known issue (test_pa_arabic_on_face_a_draws_isolated_forms)
  • Labelary reorders a right-to-left run when the bidirectional layout flag is 1, pixel for pixel as if the string were written backwards. We do not read the flag, so the run keeps its logical order. — not pinned: the only case that exercises it records a known issue (test_pa_bidi_flag_leaves_the_run_in_logical_order)
  • Labelary joins Arabic letterforms and stacks combining marks over their bases when the character shaping flag is 1, measured against a downloaded TrueType font. We do not read the flag, and no glyph substitution or mark positioning happens here. — not pinned by a test
  • Labelary names each flag it rejects, as in Value 2 is not a valid bidi layout flag (0/1) and was ignored, and keeps the previous value. We report the command unsupported and read none of its four arguments. — pinned by test_pa_out_of_range_flags_go_unreported

Example

The same field twice, once with the .notdef glyph turned on and once with it off.

^XA
^CI28
^PA1
^FO50,40^A0N,40^FDprice العربية each^FS
^PA0
^FO50,110^A0N,40^FDprice العربية each^FS
^XZ

Open in viewer