32Diagnostics, source positions, limits & threads
Every ZplRenderResult has Diagnostics: ZplDiagnostic with a stable code, severity, message, command and position (offset, line, column). Warnings is kept and contains the messages of all warnings and errors.
Try it online on zplCloud.com: ZPL Linter
| Code | Severity | Meaning |
|---|---|---|
ZPL1001 | Error | Command with invalid parameters ignored (the rest of the label is rendered) |
ZPL1002 | Warning | Field could not be drawn (e.g. invalid barcode data) |
ZPL1003 | Warning | Barcode data longer than any symbology can hold |
ZPL1101 | Warning | ^GF larger than the label or MaxGraphicBytes |
ZPL1102 | Warning | ^GF data cannot be decoded |
ZPL1103 | Warning | ^XG/^IM references a graphic that is not stored |
ZPL1201 | Warning | ^A@ font not found – font A is used, as on a Zebra |
ZPL1301 | Warning | FieldValues key without a matching ^FN (INVALID_FIELD_VALUE_KEY) |
ZPL2001 | Info | Accepted, no effect on the image (^FE, ^FA, RFID operations other than writing) |
With TraceElements, every element carries SourceOffset/SourceLength (its ^FO…^FS block); every parsed ZplCommand has Offset/Length, and ZplParser.LineColumn converts them. Missing ^A@ fonts can be supplied on demand by the FontProvider callback.
var renderer = new ZplRenderer(new ZplRenderSettings
{
TraceElements = true,
FontProvider = name => name == "E:BRAND.TTF" ? File.ReadAllBytes("fonts/Brand.ttf") : null,
});
foreach (var result in renderer.Render(zpl))
{
foreach (ZplDiagnostic d in result.Diagnostics) // e.g. "ZPL1201 warning (3:12): …"
Console.WriteLine($"{d.Code} {d.Severity} {d.Command} Zeile {d.Line}, Spalte {d.Column}: {d.Message}");
foreach (var e in result.Elements) // ^FO…^FS range in the source
Console.WriteLine(zpl.Substring(e.SourceOffset, e.SourceLength));
result.Bitmap.Dispose();
}
Limits for untrusted input & thread safety
Defaults: MaxLabelSide 32000, MaxLabelDots 64 million, MaxQuantity 10000, MaxLabels 100000, MaxGraphicBytes 32 MB (also the Z64 decompression limit against zip bombs), MaxFieldDataLength 1 million, ZplResourceStore.MaxTotalBytes 256 MB. ZplRenderer/EplRenderer hold printer state and are not thread-safe – use one renderer per thread; ZplResourceStore, FontManager, ZplCaches, PropertyPath and configured LabelBindings are. ConcurrencyTests compares the SHA-256 of all outputs from 16 threads with the single-threaded run; samples/FuzzRunner feeds the parser random and mutated input, samples/LeakTest renders 1 million labels and logs heap and RSS. Details: THREADING.md, DIAGNOSTICS.md.
var shared = new ZplResourceStore(); // thread-safe, shareable by many renderers
var safe = new ZplRenderSettings
{
MaxLabelSide = 8000, MaxLabelDots = 16_000_000, MaxQuantity = 100,
MaxLabels = 1000, MaxGraphicBytes = 4 * 1024 * 1024, MaxFieldDataLength = 10_000,
};
Parallel.For(0, 8, _ =>
{
var r = new ZplRenderer(safe) { Store = shared }; // one renderer per thread
r.ProcessCommands(untrusted);
});

