zpl_renderer
Offline ZPL to PNG/PDF renderer for Ruby and Rails.
Add the gem, render labels, and get barcodes/QR codes that scanners can decode. No Labelary account, no network calls, no printer hardware required.
Install
# Gemfile
gem "zpl_renderer"
bundle install
Precompiled renderer binaries ship for common platforms (Linux/macOS/Windows). If your platform is missing a binary, build it once:
cd renderer && cargo build --release
bundle exec rake build_renderer
Or point to a binary explicitly:
export ZPL_RENDERER_BINARY=/absolute/path/to/zpl-renderer
Quick start
require "zpl_renderer"
zpl = <<~ZPL
^XA
^FO50,50^A0N,40,40^FDHello^FS
^FO50,120^BY3
^BCN,100,Y,N,N
^FDTRACK123456789^FS
^FO50,280^BQN,2,6
^FDQA,https://example.com/track/ABC123^FS
^XZ
ZPL
png = ZplRenderer.render(zpl, format: :png, width: 4, height: 6, dpi: 203)
File.binwrite("label.png", png)
pdf = ZplRenderer.render(zpl, format: :pdf, width: 4, height: 6, dpi: 300)
File.binwrite("label.pdf", pdf)
Rails
png = ZplRenderer.render(@label.zpl, format: :png, width: 4, height: 6, dpi: 203)
send_data png,
type: ZplRenderer.content_type(:png),
disposition: "inline",
filename: "label.png"
See examples/rails_controller.rb.
CLI
zpl-render label.zpl -o label.png --dpi 203 --width 4 --height 6
zpl-render label.zpl -o label.pdf --format pdf --dpi 300
zpl-render --validate-only label.zpl
Options
| Option | Default | Notes |
|---|---|---|
format |
:png |
:png or :pdf |
width / height |
4 / 6 |
Inches by default |
unit |
:inches |
:inches or :mm |
dpi |
203 |
203, 300, or 600 |
dpmm |
derived | 8, 12, or 24 (overrides dpi) |
index |
0 |
Multi-label ^XA...^XZ selection |
timeout |
30 |
Seconds |
strict |
true |
Raise on unsupported commands |
clip_to_print_width |
false |
Emulate printer ^PW clipping instead of widening |
Canvas size is printer-dot accurate: ceil(mm * dpmm).
Accuracy and barcodes
This gem targets common shipping-label ZPL, not every Zebra firmware quirk.
Supported first-release command set and barcode guidance live in
COMPATIBILITY.md.
Carrier quirks are sanitized automatically before render: bad field origins such
as ^FO464,--, and ^PW values narrower than the canvas that would clip
rotated text at the right edge. Inspect repairs with
ZplRenderer.sanitize(zpl, canvas_dots: 813).
Barcode/QR payloads are independently verified in CI with a ZXing-based decoder:
hits = ZplRenderer.decode_png(png)
hits.map(&:text)
# => ["TRACK123456789", "https://example.com/track/ABC123"]
Scanner tips
- Prefer
^BY3(or wider) at 203 DPI - Prefer QR magnification
>= 4for handheld scanners - Keep quiet zones clear of text/graphics
- Avoid clipping barcodes with tiny
^PW/ label widths
Development
bundle install
source "$HOME/.cargo/env" # if needed
bundle exec rake build_renderer
bundle exec rake golden
bundle exec rspec
cd renderer && cargo test
Fixtures under spec/fixtures/ must stay synthetic. Do not commit real customer
or production ZPL/PNG samples.
Packaging
bundle exec rake build_renderer
gem build zpl_renderer.gemspec
Platform CI builds native binaries for Linux/macOS/Windows and packages them under
vendor/bin/<rust-triple>/.
Publishing to RubyGems is intentional and separate from local gem builds.
License
MIT. Renderer engine depends on labelize (MIT).