Module: ZplRender

Defined in:
lib/zpl_render.rb,
lib/zpl_render/font.rb,
lib/zpl_render/canvas.rb,
lib/zpl_render/parser.rb,
lib/zpl_render/version.rb,
lib/zpl_render/renderer.rb,
lib/zpl_render/truetype.rb,
lib/zpl_render/font_data.rb,
lib/zpl_render/barcode/qr.rb,
lib/zpl_render/output/pdf.rb,
lib/zpl_render/output/png.rb,
lib/zpl_render/graphic_field.rb,
lib/zpl_render/barcode/code39.rb,
lib/zpl_render/barcode/pdf417.rb,
lib/zpl_render/barcode/code128.rb,
lib/zpl_render/helvetica_metrics.rb,
lib/zpl_render/barcode/pdf417_tables.rb,
lib/zpl_render/barcode/interleaved2of5.rb

Overview

Render ZPL II label programs to PNG or PDF.

png = ZplRender.to_png(zpl, dpmm: 8, width_in: 4, height_in: 6)
pdf = ZplRender.to_pdf(zpl, dpmm: 8, width_in: 4, height_in: 6)

dpmm is the printer density in dots per millimeter:

6 = 152 dpi, 8 = 203 dpi (most common), 12 = 300 dpi, 24 = 600 dpi

Error handling: every failure the library raises intentionally is a ZplRender::Error. By default rendering is lenient: recoverable problems (a field that fails to render, an unsupported command) are recorded in the optional warnings array and rendering continues, like a printer. Pass strict: true to raise ZplRender::Error on the first problem instead, for pipelines that must not silently drop label content.

Defined Under Namespace

Modules: Barcode, Font, GraphicField, Output Classes: Canvas, Error, Parser, Renderer, TrueType

Constant Summary collapse

VERSION =
"0.2.0"
FONT8X8 =

one per row, LSB = leftmost pixel.

[

  [0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00],
  [0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00],
  [0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00],
  [0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00],
  [0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00],
  [0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00],
  [0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00],
  [0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00],
  [0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00],
  [0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00],
  [0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00],
  [0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00],
  [0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00],
  [0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00],
  [0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00],
  [0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00],
  # ^ 0x00-0x0f
  [0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00],
  [0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00],
  [0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00],
  [0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00],
  [0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00],
  [0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00],
  [0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00],
  [0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00],
  [0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00],
  [0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00],
  [0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00],
  [0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00],
  [0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00],
  [0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00],
  [0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00],
  [0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00],
  # ^ 0x10-0x1f
  [0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00],
  [0x18, 0x3C, 0x3C, 0x18, 0x18, 0x00, 0x18, 0x00],
  [0x36, 0x36, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00],
  [0x36, 0x36, 0x7F, 0x36, 0x7F, 0x36, 0x36, 0x00],
  [0x0C, 0x3E, 0x03, 0x1E, 0x30, 0x1F, 0x0C, 0x00],
  [0x00, 0x63, 0x33, 0x18, 0x0C, 0x66, 0x63, 0x00],
  [0x1C, 0x36, 0x1C, 0x6E, 0x3B, 0x33, 0x6E, 0x00],
  [0x06, 0x06, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00],
  [0x18, 0x0C, 0x06, 0x06, 0x06, 0x0C, 0x18, 0x00],
  [0x06, 0x0C, 0x18, 0x18, 0x18, 0x0C, 0x06, 0x00],
  [0x00, 0x66, 0x3C, 0xFF, 0x3C, 0x66, 0x00, 0x00],
  [0x00, 0x0C, 0x0C, 0x3F, 0x0C, 0x0C, 0x00, 0x00],
  [0x00, 0x00, 0x00, 0x00, 0x00, 0x0C, 0x0C, 0x06],
  [0x00, 0x00, 0x00, 0x3F, 0x00, 0x00, 0x00, 0x00],
  [0x00, 0x00, 0x00, 0x00, 0x00, 0x0C, 0x0C, 0x00],
  [0x60, 0x30, 0x18, 0x0C, 0x06, 0x03, 0x01, 0x00],
  # ^ 0x20-0x2f
  [0x3E, 0x63, 0x73, 0x7B, 0x6F, 0x67, 0x3E, 0x00],
  [0x0C, 0x0E, 0x0C, 0x0C, 0x0C, 0x0C, 0x3F, 0x00],
  [0x1E, 0x33, 0x30, 0x1C, 0x06, 0x33, 0x3F, 0x00],
  [0x1E, 0x33, 0x30, 0x1C, 0x30, 0x33, 0x1E, 0x00],
  [0x38, 0x3C, 0x36, 0x33, 0x7F, 0x30, 0x78, 0x00],
  [0x3F, 0x03, 0x1F, 0x30, 0x30, 0x33, 0x1E, 0x00],
  [0x1C, 0x06, 0x03, 0x1F, 0x33, 0x33, 0x1E, 0x00],
  [0x3F, 0x33, 0x30, 0x18, 0x0C, 0x0C, 0x0C, 0x00],
  [0x1E, 0x33, 0x33, 0x1E, 0x33, 0x33, 0x1E, 0x00],
  [0x1E, 0x33, 0x33, 0x3E, 0x30, 0x18, 0x0E, 0x00],
  [0x00, 0x0C, 0x0C, 0x00, 0x00, 0x0C, 0x0C, 0x00],
  [0x00, 0x0C, 0x0C, 0x00, 0x00, 0x0C, 0x0C, 0x06],
  [0x18, 0x0C, 0x06, 0x03, 0x06, 0x0C, 0x18, 0x00],
  [0x00, 0x00, 0x3F, 0x00, 0x00, 0x3F, 0x00, 0x00],
  [0x06, 0x0C, 0x18, 0x30, 0x18, 0x0C, 0x06, 0x00],
  [0x1E, 0x33, 0x30, 0x18, 0x0C, 0x00, 0x0C, 0x00],
  # ^ 0x30-0x3f
  [0x3E, 0x63, 0x7B, 0x7B, 0x7B, 0x03, 0x1E, 0x00],
  [0x0C, 0x1E, 0x33, 0x33, 0x3F, 0x33, 0x33, 0x00],
  [0x3F, 0x66, 0x66, 0x3E, 0x66, 0x66, 0x3F, 0x00],
  [0x3C, 0x66, 0x03, 0x03, 0x03, 0x66, 0x3C, 0x00],
  [0x1F, 0x36, 0x66, 0x66, 0x66, 0x36, 0x1F, 0x00],
  [0x7F, 0x46, 0x16, 0x1E, 0x16, 0x46, 0x7F, 0x00],
  [0x7F, 0x46, 0x16, 0x1E, 0x16, 0x06, 0x0F, 0x00],
  [0x3C, 0x66, 0x03, 0x03, 0x73, 0x66, 0x7C, 0x00],
  [0x33, 0x33, 0x33, 0x3F, 0x33, 0x33, 0x33, 0x00],
  [0x1E, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x1E, 0x00],
  [0x78, 0x30, 0x30, 0x30, 0x33, 0x33, 0x1E, 0x00],
  [0x67, 0x66, 0x36, 0x1E, 0x36, 0x66, 0x67, 0x00],
  [0x0F, 0x06, 0x06, 0x06, 0x46, 0x66, 0x7F, 0x00],
  [0x63, 0x77, 0x7F, 0x7F, 0x6B, 0x63, 0x63, 0x00],
  [0x63, 0x67, 0x6F, 0x7B, 0x73, 0x63, 0x63, 0x00],
  [0x1C, 0x36, 0x63, 0x63, 0x63, 0x36, 0x1C, 0x00],
  # ^ 0x40-0x4f
  [0x3F, 0x66, 0x66, 0x3E, 0x06, 0x06, 0x0F, 0x00],
  [0x1E, 0x33, 0x33, 0x33, 0x3B, 0x1E, 0x38, 0x00],
  [0x3F, 0x66, 0x66, 0x3E, 0x36, 0x66, 0x67, 0x00],
  [0x1E, 0x33, 0x07, 0x0E, 0x38, 0x33, 0x1E, 0x00],
  [0x3F, 0x2D, 0x0C, 0x0C, 0x0C, 0x0C, 0x1E, 0x00],
  [0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x3F, 0x00],
  [0x33, 0x33, 0x33, 0x33, 0x33, 0x1E, 0x0C, 0x00],
  [0x63, 0x63, 0x63, 0x6B, 0x7F, 0x77, 0x63, 0x00],
  [0x63, 0x63, 0x36, 0x1C, 0x1C, 0x36, 0x63, 0x00],
  [0x33, 0x33, 0x33, 0x1E, 0x0C, 0x0C, 0x1E, 0x00],
  [0x7F, 0x63, 0x31, 0x18, 0x4C, 0x66, 0x7F, 0x00],
  [0x1E, 0x06, 0x06, 0x06, 0x06, 0x06, 0x1E, 0x00],
  [0x03, 0x06, 0x0C, 0x18, 0x30, 0x60, 0x40, 0x00],
  [0x1E, 0x18, 0x18, 0x18, 0x18, 0x18, 0x1E, 0x00],
  [0x08, 0x1C, 0x36, 0x63, 0x00, 0x00, 0x00, 0x00],
  [0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF],
  # ^ 0x50-0x5f
  [0x0C, 0x0C, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00],
  [0x00, 0x00, 0x1E, 0x30, 0x3E, 0x33, 0x6E, 0x00],
  [0x07, 0x06, 0x06, 0x3E, 0x66, 0x66, 0x3B, 0x00],
  [0x00, 0x00, 0x1E, 0x33, 0x03, 0x33, 0x1E, 0x00],
  [0x38, 0x30, 0x30, 0x3e, 0x33, 0x33, 0x6E, 0x00],
  [0x00, 0x00, 0x1E, 0x33, 0x3f, 0x03, 0x1E, 0x00],
  [0x1C, 0x36, 0x06, 0x0f, 0x06, 0x06, 0x0F, 0x00],
  [0x00, 0x00, 0x6E, 0x33, 0x33, 0x3E, 0x30, 0x1F],
  [0x07, 0x06, 0x36, 0x6E, 0x66, 0x66, 0x67, 0x00],
  [0x0C, 0x00, 0x0E, 0x0C, 0x0C, 0x0C, 0x1E, 0x00],
  [0x30, 0x00, 0x30, 0x30, 0x30, 0x33, 0x33, 0x1E],
  [0x07, 0x06, 0x66, 0x36, 0x1E, 0x36, 0x67, 0x00],
  [0x0E, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x1E, 0x00],
  [0x00, 0x00, 0x33, 0x7F, 0x7F, 0x6B, 0x63, 0x00],
  [0x00, 0x00, 0x1F, 0x33, 0x33, 0x33, 0x33, 0x00],
  [0x00, 0x00, 0x1E, 0x33, 0x33, 0x33, 0x1E, 0x00],
  # ^ 0x60-0x6f
  [0x00, 0x00, 0x3B, 0x66, 0x66, 0x3E, 0x06, 0x0F],
  [0x00, 0x00, 0x6E, 0x33, 0x33, 0x3E, 0x30, 0x78],
  [0x00, 0x00, 0x3B, 0x6E, 0x66, 0x06, 0x0F, 0x00],
  [0x00, 0x00, 0x3E, 0x03, 0x1E, 0x30, 0x1F, 0x00],
  [0x08, 0x0C, 0x3E, 0x0C, 0x0C, 0x2C, 0x18, 0x00],
  [0x00, 0x00, 0x33, 0x33, 0x33, 0x33, 0x6E, 0x00],
  [0x00, 0x00, 0x33, 0x33, 0x33, 0x1E, 0x0C, 0x00],
  [0x00, 0x00, 0x63, 0x6B, 0x7F, 0x7F, 0x36, 0x00],
  [0x00, 0x00, 0x63, 0x36, 0x1C, 0x36, 0x63, 0x00],
  [0x00, 0x00, 0x33, 0x33, 0x33, 0x3E, 0x30, 0x1F],
  [0x00, 0x00, 0x3F, 0x19, 0x0C, 0x26, 0x3F, 0x00],
  [0x38, 0x0C, 0x0C, 0x07, 0x0C, 0x0C, 0x38, 0x00],
  [0x18, 0x18, 0x18, 0x00, 0x18, 0x18, 0x18, 0x00],
  [0x07, 0x0C, 0x0C, 0x38, 0x0C, 0x0C, 0x07, 0x00],
  [0x6E, 0x3B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00],
  [0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00],
  # ^ 0x70-0x7f
].each(&:freeze).freeze
HELVETICA_WIDTHS =

Helvetica advance widths (1/1000 em) for ASCII 32-126, from the Adobe Core 14 AFM metrics. Used to approximate Zebra's scalable CG Triumvirate (font 0), which shares Helvetica's metrics closely.

[
  278, 278, 355, 556, 556, 889, 667, 222, 333, 333, 389, 584,
  278, 333, 278, 278, 556, 556, 556, 556, 556, 556, 556, 556,
  556, 556, 278, 278, 584, 584, 584, 556, 1015, 667, 667, 722,
  722, 667, 611, 778, 722, 278, 500, 667, 556, 833, 722, 778,
  667, 778, 722, 667, 611, 722, 667, 944, 667, 667, 611, 278,
  278, 278, 469, 556, 222, 556, 556, 500, 556, 556, 278, 556,
  556, 222, 222, 500, 222, 833, 556, 556, 556, 556, 333, 500,
  278, 556, 500, 722, 500, 500, 500, 334, 260, 334, 584
].freeze

Class Method Summary collapse

Class Method Details

.decode_base64(data) ⇒ Object

Decode a Base64-encoded ZPL payload into the ZPL string. Accepts the standard and URL-safe alphabets, tolerates whitespace/newlines and missing padding, and raises ZplRender::Error when the input is not base64 or does not decode to ZPL. Useful when labels are stored base64-encoded (WMS exports, database columns, API payloads).

Raises:



42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
# File 'lib/zpl_render.rb', line 42

def decode_base64(data)
  raise Error, "base64 input must be a String (got #{data.class})" unless data.respond_to?(:to_str)

  compact = data.to_str.gsub(/\s+/, "").tr("-_", "+/")
  compact += "=" * ((4 - compact.length % 4) % 4)
  unless !compact.empty? && compact.match?(%r{\A[A-Za-z0-9+/]+={0,2}\z}) && (compact.length % 4).zero?
    raise Error, "input is not valid base64"
  end

  zpl = begin
    compact.unpack1("m0")
  rescue ArgumentError => e
    raise Error, "input is not valid base64: #{e.message}"
  end
  zpl.force_encoding(Encoding::UTF_8)
  zpl.force_encoding(Encoding::BINARY) unless zpl.valid_encoding?
  raise Error, "decoded base64 does not contain any ZPL commands" unless zpl.match?(/[\^~]/)

  zpl
end

.render(zpl, dpmm: 8, width_in: 4.0, height_in: 6.0, strict: false, base64: false, warnings: nil) ⇒ Object

Render every ^XA..^XZ format to a Canvas (dot matrix). Pass base64: true when zpl is a Base64-encoded ZPL payload.

Raises:



65
66
67
68
69
70
71
72
73
# File 'lib/zpl_render.rb', line 65

def render(zpl, dpmm: 8, width_in: 4.0, height_in: 6.0, strict: false, base64: false, warnings: nil)
  raise Error, "zpl must be a String (got #{zpl.class})" unless zpl.respond_to?(:to_str)

  zpl = base64 ? decode_base64(zpl) : zpl.to_str
  renderer = Renderer.new(dpmm: dpmm, width_in: width_in, height_in: height_in, strict: strict)
  labels = renderer.render(zpl)
  warnings.concat(renderer.warnings) if warnings
  labels
end

.to_pdf(zpl, dpmm: 8, width_in: 4.0, height_in: 6.0, strict: false, base64: false, warnings: nil) ⇒ Object

PDF bytes, one page per label, at exact physical size.

Raises:



92
93
94
95
96
97
98
# File 'lib/zpl_render.rb', line 92

def to_pdf(zpl, dpmm: 8, width_in: 4.0, height_in: 6.0, strict: false, base64: false, warnings: nil)
  labels = render(zpl, dpmm: dpmm, width_in: width_in, height_in: height_in,
                       strict: strict, base64: base64, warnings: warnings)
  raise Error, "no ^XA..^XZ label formats found" if labels.empty?

  Output::Pdf.encode(labels, dpmm: dpmm)
end

.to_png(zpl, dpmm: 8, width_in: 4.0, height_in: 6.0, scale: 1, strict: false, base64: false, warnings: nil) ⇒ Object

PNG bytes for the first label.

Raises:



76
77
78
79
80
81
82
# File 'lib/zpl_render.rb', line 76

def to_png(zpl, dpmm: 8, width_in: 4.0, height_in: 6.0, scale: 1, strict: false, base64: false, warnings: nil)
  labels = render(zpl, dpmm: dpmm, width_in: width_in, height_in: height_in,
                       strict: strict, base64: base64, warnings: warnings)
  raise Error, "no ^XA..^XZ label formats found" if labels.empty?

  Output::Png.encode(labels.first, scale: scale)
end

.to_pngs(zpl, dpmm: 8, width_in: 4.0, height_in: 6.0, scale: 1, strict: false, base64: false, warnings: nil) ⇒ Object

PNG bytes for every label.



85
86
87
88
89
# File 'lib/zpl_render.rb', line 85

def to_pngs(zpl, dpmm: 8, width_in: 4.0, height_in: 6.0, scale: 1, strict: false, base64: false, warnings: nil)
  render(zpl, dpmm: dpmm, width_in: width_in, height_in: height_in,
              strict: strict, base64: base64, warnings: warnings)
    .map { |canvas| Output::Png.encode(canvas, scale: scale) }
end