ZPL-Forge
A fast, memory-safe ZPL (Zebra Programming Language) parser and renderer for Rust. It converts ZPL code into PNG images or native, selectable vector PDFs.
The Purpose
ZPL-Forge provides a quick and simple alternative for creating documents like shipping guides, delivery receipts, and tickets. It is optimized for use cases where speed and ease of integration are preferred over extreme document complexity.
The Results
| Standard Complex Label | Custom Image Extensions |
|---|---|
Check out the Visual Documentation (EXAMPLES.md) for more ready-to-run code samples and their generated output images.
Performance
ZPL-Forge is engineered to deliver enterprise-grade performance and ultra-low latency, making it perfect for both instant single-label previews and high-throughput bulk generation.
Single Label Render Times (Measured in release mode using the embedded 130 KB TeX Gyre Heros Cn font):
- Routing/Dispatch Label (
test_02):- PNG Output (
PngBackend): 0.68 ms - Native PDF Output (
PdfNativeBackend): 2.18 ms
- PNG Output (
- Standard Shipping Label (
test_01):- PNG Output (
PngBackend): 5.37 ms - Native PDF Output (
PdfNativeBackend): 4.83 ms
- PNG Output (
Massive Bulk Batching (Measured in release mode):
- Native Vector PDF (1,000 Combined Labels via
render_pages): 69.74 ms total time (0.07 ms / page), producing a compact, searchable file of only 0.86 MB (a throughput of over 14,300 pages per second!).
Installation
Add this to your Cargo.toml:
[]
= "0.3.1"
Cargo Features
| Feature | Default | Enables |
|---|---|---|
png |
✅ | PngBackend raster output (image, imageproc) |
pdf |
✅ | PdfNativeBackend vector output (lopdf, flate2) |
tracing |
❌ | Internal debug logging via the tracing crate |
If you only need one output format, disable default features to cut compile time and binary size:
[]
= { = "0.3.1", = false, = ["pdf"] }
Quick Start
The library provides two backends for different needs.
1. Render to PNG
Best for web previews or raster printing. Gated under the png cargo feature.
use HashMap;
use ;
use PngBackend;
2. Render to Native Vector PDF
Outputs selectable text and native vector graphics. Ultra-fast, extremely small file size, and requires zero rasterization. Gated under the pdf cargo feature.
use HashMap;
use ;
use PdfNativeBackend;
Advanced Usage
Templating (Variables)
Inject dynamic data into your ZPL without extra allocations. Simply use the {{variable_name}} syntax in your ZPL code and pass a variables map to .render().
use HashMap;
use ;
use PngBackend;
Conditional Rendering (^IFC)
A custom extension to render elements only if a variable matches a specific value.
let zpl = "^XA^FO50,50^IFCuser_type,admin^A0N,50,50^FDAdmin Only Area^FS^XZ";
// "Admin Only Area" will only render if a variable ("user_type", "admin") is passed to render.
Multi-Page PDF Batching & Compression
You can combine multiple physical labels into a single multi-page PDF document simply by concatenating multiple ^XA...^XZ blocks in your ZPL input. The PdfNativeBackend automatically treats each block as a separate page, drawing it natively. You can also customize the zlib compression level using flate2::Compression.
use HashMap;
use ;
use PdfNativeBackend;
use Compression;
Template-Based Multi-Page PDF Generation (render_pages)
If you have a single template with placeholders and want to render multiple pages with different sets of variables efficiently, you can use the render_pages method. This parses and builds the AST exactly once and renders multiple pages using a list of variable maps, which is significantly faster and uses less memory than concatenating raw ZPL.
use HashMap;
use ;
use PdfNativeBackend;
Custom Fonts
ZPL-Forge ships with embedded high-quality open-source fonts mapped to ZPL identifiers so it works out of the box with zero system dependencies:
| Font | ZPL identifiers | Role | License |
|---|---|---|---|
| TeX Gyre Heros Cn | 0–9 |
Scalable sans (^A0, ^CF0) — Helvetica-style condensed |
GUST Font License |
| Iosevka Term Slab | A–Z |
Monospace / bitmap-font emulation | SIL OFL 1.1 |
| OCR-B | E |
Machine-readable standard (Zebra E) |
Free (Schwarz) |
| OCR-A | H |
Industrial OCR standard (Zebra H) |
BSD-3-Clause |
All embedded fonts are free to use, modify, and redistribute; their full license texts and copyright notices ship with the crate in src/assets/.
To use your own typography, register TrueType (.ttf) or OpenType (.otf) bytes on a FontManager and attach it to the engine. Each font is bound to a range of ZPL identifiers (A–Z, 0–9) and selected from ZPL with ^A or ^CF.
use HashMap;
use Arc;
use ;
use PngBackend;
See examples/custom_fonts.rs for a runnable demo that registers ten different families at once.
Weights and styles (Light / Regular / Bold)
ZPL-Forge does not synthesize weights or slants — the glyphs come straight from the font file. To offer multiple weights, register one static instance per weight under its own identifier and pick it from ZPL:
fonts.register_font?; // ^ALN,40,40
fonts.register_font?; // ^ARN,40,40
fonts.register_font?; // ^ABN,40,40
Variable fonts: axes (
wght,wdth,MONO, …) are not supported — a variable TTF renders at its default instance only. Export static instances first, e.g. with fonttools:fonttools varLib.instancer Font-VF.ttf wght=700 -o Font-Bold.ttf.
Condensation (horizontal scale)
Two ways to condense or expand text:
- The
wparameter of^A— glyphs are scaled horizontally by thew/hratio, exactly like a Zebra printer.^A0N,60,40renders 60-dot-tall glyphs compressed to ⅔ of their natural width;^A0N,60,90expands them 1.5×. Omittingwkeeps the font's natural proportions. - Register a naturally condensed family (e.g., Saira Condensed, Archivo Narrow) when you want true condensed letterforms instead of a geometric squeeze.
Identifier semantics: bitmap vs scalable
To match real printer output, identifiers A–H emulate Zebra's built-in bitmap fonts: heights snap to integer magnifications of the original dot-matrix cell (font A is 9×5 dots) and the glyphs are stretched to the fixed cell aspect — this is what makes ^CFA,30 look exactly like Labelary/hardware. Identifiers 0–9 and I–Z use the scalable model (any height, natural glyph proportions, capital letters spanning ~75% of the ^A height).
Register decorative or brand fonts on scalable identifiers (
0–9,I–Z). A custom font placed onA–Hinherits the bitmap cell geometry and will look artificially stretched.
Supported ZPL Commands
| Command | Name | Parameters | Description |
|---|---|---|---|
^A |
Font Spec | f,o,h,w |
Specifies font (A..Z, 0..9), orientation (N, R, I, B — text rotation supported), height, and width in dots. |
^B2 |
Interleaved 2/5 | o,h,f,g,e |
Interleaved 2 of 5 Barcode (cartons, ITF-14). |
^B3 |
Code 39 | o,e,h,f,g |
Code 39 Barcode. |
^B7 |
PDF417 | o,h,s,c,r,t |
PDF417 two-dimensional Barcode. |
^BA |
Code 93 | o,h,f,g,e |
Code 93 Barcode. |
^BC |
Code 128 | o,h,f,g,e,m |
Code 128 Barcode. |
^BE |
EAN-13 | o,h,f,g |
EAN-13 Barcode (retail). |
^BQ |
QR Code | o,m,s,e,k |
QR Code (Model 1 or 2). |
^BU |
UPC-A | o,h,f,g,e |
UPC-A Barcode (retail). |
^BX |
Data Matrix | o,h,s,c,r |
Data Matrix (ECC 200) two-dimensional Barcode. |
^BY |
Barcode Default | w,r,h |
Sets default values for barcodes (module width, ratio, and height). |
^CF |
Change Def. Font | f,h,w |
Changes the default alphanumeric font. |
^FB |
Field Block | w,l,s,j,i |
Wraps text in a block: width, max lines, line spacing, justification (L/C/R), indent. \& breaks lines. |
^FD |
Field Data | d |
Data to print in the current field. |
^FO |
Field Origin | x,y |
Sets the top-left corner of the field. |
^FR |
Field Reverse | N/A | Inverts the field color (white on black). |
^FS |
Field Separator | N/A | Indicates the end of a field definition. |
^FT |
Field Typeset | x,y |
Sets field position relative to the text baseline. |
^GB |
Graphic Box | w,h,t,c,r |
Draws a box, line, or rectangle with rounded corners. |
^GC |
Graphic Circle | d,t,c |
Draws a circle by specifying its diameter. |
^GD |
Graphic Diagonal | w,h,t,c,o |
Draws a diagonal line (/ or \). |
^GE |
Graphic Ellipse | w,h,t,c |
Draws an ellipse. |
^GF |
Graphic Field | c,b,f,p,d |
Renders a bitmap image (supports A/Hex type compression). |
^XA |
Start Format | N/A | Indicates the start of a label. Multiple ^XA...^XZ blocks become pages in the native PDF backend. |
^XZ |
End Format | N/A | Indicates the end of a label. |
Custom Commands (Extensions)
| Command | Name | Parameters | Description |
|---|---|---|---|
^GIC |
Custom Image | w,h,d |
Renders a color image. w and h define size. d is the binary (PNG/JPG) in Base64. |
^GLC |
Line Color | c |
Sets the color for graphic elements in hexadecimal format (e.g., #FF0000). |
^GTC |
Text Color | c |
Sets the color for text fields in hexadecimal format (e.g., #0000FF). |
^IFC |
Cond. Render | var,val |
If Condition Custom: Evaluates if a variable matches a specific value. If false, the field won't be rendered. Scope limited up to the next ^FS command. |
Security and Limits
ZPL-Forge imposes reasonable limits to prevent resource exhaustion from malformed or malicious ZPL inputs.
- Maximum Document Size: Bounded to prevent memory overflow on excessively large labels.
- Graphic Field Maximums: Prevents malicious
^GFcommands from allocating unlimited memory. - Maximum Text Size: Prevents excessively large font sizes.
License
Dual-licensed under either:
- MIT License (LICENSE-MIT or http://opensource.org/licenses/MIT)
- Apache License, Version 2.0 (LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0)
At your option.
Embedded font licenses
The fonts embedded in the binary keep their own permissive licenses, all of which allow free use, modification, and redistribution (including commercial). Full texts and copyright notices are shipped in src/assets/:
- TeX Gyre Heros Cn — GUST Font License, GUST e-foundry / URW++ (
TEX_GYRE_HEROS_LICENSE.txt) - Iosevka Term Slab — SIL Open Font License 1.1 (
IOSEVKA_LICENSE.txt,OFL.txt) - OCR-A — BSD-3-Clause, SFO Museum (
OCRA_LICENSE.txt) - OCR-B — freely distributable without limitation, N. Schwarz / Z. Wagner (
OCRB_LICENSE.txt)