Dokumentation · zplCore Designer
zplCore Designer
der einbettbare Etiketten-Editor.
Der zplCore Designer ist ein WYSIWYG-Editor für ZPL-Etiketten, den Sie selbst betreiben und in Ihre eigene Anwendung einbetten: Design-JSON und Daten rein, Design-JSON, ZPL, PDF, PNG und SVG raus. Die Arbeitsfläche zeigt, was der Drucker druckt, denn jede Vorschau ist das gerenderte ZPL des zplCore.com-Engines. Der Editor speichert nichts und druckt nichts – Ihre Anwendung behält das Design und druckt selbst. Diese Seite beschreibt die Schnellstarts (NuGet, Docker, JavaScript, Web Component, Blazor, WPF, MAUI), alle Optionen, die Render-API, die JavaScript-API, das Design-Schema und den Betrieb.
01Überblick
Der Designer besteht aus zwei Teilen, die immer zusammen laufen: der Editor-Oberfläche (statische Dateien, eine Angular-App ohne externe Aufrufe) und einer zustandslosen Render-API in .NET, die Vorschauen rendert, für die Arbeitsfläche die gedruckte Geometrie jedes Elements misst und Bilder und SVGs umwandelt. Beides liefert eine ASP.NET-Core-Bibliothek; der Container ist diese Bibliothek mit einem minimalen Host.
| Lieferform | Was Sie bekommen | Für wen |
|---|---|---|
NuGet ZplCore.Designer | AddZplCoreDesigner() + MapZplCoreDesigner("/designer"): Editor-Oberfläche (im Paket enthalten) und Render-API in Ihrer ASP.NET-Core-Anwendung, hinter Ihrer eigenen Anmeldung | .NET-Teams, die den Editor in ihre Web-Anwendung einbauen |
Docker zplcore/designer | Lauffertiger Container (distroless, ohne Root) mit Editor und API, konfiguriert über Umgebungsvariablen; Helm-Chart | Teams ohne .NET, Kubernetes, Einbettung per iframe |
JavaScript-SDK zplcore-designer.js | ZplCoreDesigner.mount(…): iframe-Einbettung mit Promise-API, von jedem Designer-Host ausgeliefert (und als npm-Paket @zplcore/designer) | Jede Web-Anwendung (React, Vue, Angular, serverseitig gerendert) |
Web Component <zplcore-designer> | Derselbe Editor als Custom Element (schlanke Hülle um das SDK, keine Angular-Runtime in Ihrer Seite) | Seiten, die ein HTML-Tag statt eines Skriptaufrufs bevorzugen |
Blazor ZplCore.Designer.Blazor | <ZplCoreDesigner @bind-Design="…" /> für Blazor Server und WebAssembly | Blazor-Anwendungen |
| Desktop | Der Designer-Host auf Loopback + WebView2 (WPF, WinForms) oder die MAUI-WebView | Desktop-Anwendungen |
Was enthalten ist
- Arbeitsfläche mit allen Elementtypen: Text, Barcode (1D/2D, GS1, gestaltete Codes), Rechteck, Linie, Kreis/Ellipse, Bild, Druckerspeicher-Grafik, SVG-Icon, ZPL-Element, Tabelle, RFID.
- Eigenschaften-Panel, Elementliste, Gruppen, mehrere Seiten, Raster, Lineale, Fang, Zoom, Rückgängig/Wiederholen, Zwischenablage, Tastaturkürzel.
- Datenbindung mit JSON-Datensätzen (aus Ihrer Anwendung oder im Editor bearbeitet), Vorschau je Datensatz, Ausblenden je Datensatz, Ausdrücke und Zahlenformate.
- Vorschauen: ZPL, PDF, PNG, SVG; ZPL-Analyser und -Linter; GS1-Assistent, RFID-Felder, Bild → ZPL, SVG → ZPL, Icon-Bibliothek.
- 10 Oberflächensprachen (en, de, zh, ja, es, fr, pt, it, ar, hi), Hell und Dunkel, mm / Zoll / Dots, 203 / 300 / 600 dpi.
Was bewusst nicht enthalten ist
- Drucken jeder Art – Ihre Anwendung sendet das ZPL (zum Beispiel mit dem zplCore-SDK).
- Speichern, Konten, Versionen oder Teams – Ihre Anwendung bekommt das JSON und speichert es.
- Datenquellen-Konnektoren – Daten kommen als JSON-Datensätze aus Ihrer Anwendung.
- Ein KI-Copilot und das alte zplCloud-Designformat
{ label, fields }(vorher umwandeln).
02Schnellstart: NuGet (ASP.NET Core)
dotnet add package ZplCore.Designer
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddAuthentication(/* your scheme */);
builder.Services.AddAuthorization();
builder.Services.AddZplCoreDesigner(o =>
{
o.Fonts.AddDirectory("fonts"); // optional: your TTF/OTF printer fonts (E:NAME.TTF)
o.PrinterGraphics.AddDirectory("graphics"); // optional: your printer-memory graphics (E:NAME.GRF)
o.Limits.MaxRecordsPerRequest = 500;
});
var app = builder.Build();
app.UseAuthentication();
app.UseAuthorization();
app.MapZplCoreDesigner("/designer")
.RequireAuthorization("label-editors"); // your auth – the designer brings none of its own
app.Run();
Der Editor liegt nun unter /designer/, die API unter /designer/api/…, das OpenAPI-Dokument unter /designer/api/openapi/zplcore-designer.json und eine Statusantwort unter /designer/healthz. MapZplCoreDesigner liefert einen Convention-Builder: .RequireAuthorization(…) schützt Oberfläche und API, .Api und .Ui sprechen je einen Teil an (zum Beispiel öffentliche Oberfläche mit geschützter API).
o.AllowAnonymous = true – etwa hinter Ihrem eigenen Proxy oder für eine öffentliche Demo wie den Live-Editor.03Schnellstart: Docker
docker run -d -p 8080:8080 --read-only --tmpfs /tmp \ -e ZPLCORE_DESIGNER__AUTH__MODE=apikey \ -e ZPLCORE_DESIGNER__AUTH__APIKEYS__0=<Schlüssel mit mindestens 16 Zeichen> \ -e ZPLCORE_DESIGNER__ALLOWEDORIGINS__0=https://app.example.com \ -v ./fonts:/fonts:ro -v ./graphics:/graphics:ro \ zplcore/designer
Der Editor liegt unter http://localhost:8080/designer/. Das Image ist distroless (Azure Linux), läuft als Benutzer app ohne Root-Rechte auf Port 8080 und funktioniert mit schreibgeschütztem Root-Dateisystem und beschreibbarem /tmp; es wird für linux/amd64 und linux/arm64 gebaut. Der Container wird über den Abschnitt Designer als Umgebungsvariablen ZPLCORE_DESIGNER__… konfiguriert (doppelter Unterstrich = Verschachtelung, __0 = erster Listeneintrag); jede Option aus Abschnitt 09 lässt sich so setzen, zum Beispiel ZPLCORE_DESIGNER__LIMITS__MAXRECORDSPERREQUEST=200.
| Variable | Bedeutung |
|---|---|
ZPLCORE_DESIGNER__PATHBASE | Routen-Präfix von Editor und API, Standard /designer |
ZPLCORE_DESIGNER__AUTH__MODE | Pflicht: apikey, jwt (OIDC) oder none (ausdrücklich, nur hinter eigenem Proxy; das Log warnt) |
…__AUTH__APIKEYS__0 … · …__AUTH__APIKEYHEADER | API-Schlüssel (mindestens 16 Zeichen, aus einem Secret) · Header, Standard X-Api-Key |
…__AUTH__AUTHORITY, __AUDIENCE, __REQUIREDROLE, __REQUIREHTTPSMETADATA | JWT / OIDC (Header Authorization: Bearer …) |
…__ALLOWEDORIGINS__0 … | Ursprünge, die den Editor einbetten (frame-ancestors) und die API aus dem Browser aufrufen dürfen (CORS); leer = nur derselbe Ursprung |
…__LIMITS__* | Schutzgrenzen, siehe Grenzen, inkl. RATELIMIT__PERMITSPERWINDOW |
…__FEATURES__* | false schaltet einen Endpunkt (und seinen Reiter) ab |
…__UI__BRANDING__* | Titel, Logo, Favicon, ausgeblendete Reiter des Editors |
OTEL_EXPORTER_OTLP_ENDPOINT (+ OTEL_*) | OpenTelemetry-Export von Metriken, Traces und Logs; nicht gesetzt = aus |
ASPNETCORE_FORWARDEDHEADERS_ENABLED=true | X-Forwarded-* Ihres Ingress vertrauen (Client-IP für die Anfragegrenze) |
Eingebundene Ordner (alle optional, nur lesend genügt): /fonts Druckerspeicher-Schriften, /graphics Druckerspeicher-Grafiken, /templates Design-Vorlagen (*.json), /icons eigene SVG-Icons, /svg-fonts SVG-Schriften und Glyphen-Sets, /graphic-fonts für Grafiktext freigegebene Schriften (ZPLCORE_DESIGNER__FOLDERS__* für andere Pfade). Liveness /healthz, Readiness /readyz (rendert ein kleines Etikett). Die API braucht Schlüssel oder Token; die statische Oberfläche und {prefix}/healthz bleiben öffentlich.
Kubernetes: das Helm-Chart deploy/helm/zplcore-designer (API-Schlüssel nur aus einem vorhandenen Secret, ohne Root, schreibgeschütztes Root-Dateisystem, Probes, optional HPA und Network Policy):
kubectl create secret generic designer-api-keys --from-literal=key1=<key> helm install designer deploy/helm/zplcore-designer \ --set auth.apiKey.existingSecret=designer-api-keys \ --set designer.allowedOrigins[0]=https://app.example.com
04Einbetten mit JavaScript (iframe)
Jeder Designer-Host liefert das SDK unter {baseUrl}/sdk/zplcore-designer.js aus (ohne Abhängigkeiten, ohne CDN); mit einem Bundler nehmen Sie das npm-Paket @zplcore/designer. Das SDK legt ein iframe auf den Editor an und spricht mit ihm über postMessage; das iframe trennt Stile und Skripte vollständig von Ihrer Seite.
<div id="editor" style="height: 720px"></div>
<script src="https://labels.example.com/designer/sdk/zplcore-designer.js"></script> <!-- global ZplCoreDesigner -->
<script type="module">
const editor = await ZplCoreDesigner.mount('#editor', {
baseUrl: 'https://labels.example.com/designer/',
design, // design document { label, editor, records } or only the label JSON
data: [{ name: 'Anna', ean: '9506000134352' }],
locale: 'de', theme: 'auto', unit: 'mm',
requestHeaders: { 'X-Api-Key': key }, // container with API key; travels by postMessage, never in a URL
onChange: (doc) => save(doc) // user edits only, debounced, incl. records
});
const zpl = await editor.getZpl(); // the same ZPL the server prints
</script>
// with a bundler
import { mount } from '@zplcore/designer';
const editor = await mount('#editor', { baseUrl: '/designer/' });
Läuft der Editor auf einem anderen Ursprung als Ihre Anwendung, tragen Sie Ihren Ursprung in AllowedOrigins des Designer-Hosts ein; ursprungsübergreifend laden Sie das klassische Skript (das ES-Modul von einem anderen Ursprung bräuchte CORS). Fertige Hüllen für React 19, Vue 3 und Angular liegen in examples/ des SDK. Alle Optionen, Methoden und Ereignisse: Abschnitt 11.
05Einbetten als Web Component
<script src="/designer/sdk/zplcore-designer.js"></script> <!-- defines <zplcore-designer> -->
<zplcore-designer base-url="/designer/" locale="de" theme="auto" unit="mm"
features="-gs1,-rfid" style="display: block; height: 720px"></zplcore-designer>
<script type="module">
const el = document.querySelector('zplcore-designer');
el.design = doc; // or the attribute design='{"label":…}'
el.data = rows;
el.addEventListener('zplcore-change', (e) => save(e.detail.design));
const zpl = await el.getZpl();
</script>
Mit einem Bundler: import '@zplcore/designer/element'. Das Element ist eine schlanke Hülle um das iframe-SDK (Shadow DOM, das iframe ist der Part frame): Attribute base-url, design, locale, theme, unit, tab, features, read-only, autosave, allowed-origins, timeout, title; Properties design, data, requestHeaders; Ereignisse (bubbling, composed) zplcore-ready, zplcore-change, zplcore-selection-change, zplcore-validation, zplcore-error; alle SDK-Methoden am Element. Es funktioniert in jedem Framework, das Custom Elements rendert.
06Blazor
dotnet add package ZplCore.Designer.Blazor
<ZplCoreDesigner @ref="editor" @bind-Design="design" Data="rows" BaseUrl="/designer"
Locale="de" Theme="DesignerTheme.Auto" ReadOnly="false" Height="720px"
OnChange="OnChange" OnSelectionChange="OnSelection" />
@code {
ZplCoreDesigner? editor;
JsonObject? design; // DesignDocument { schemaVersion, label, editor, records }
List<object> rows = [new Dictionary<string, object?> { ["name"] = "Anna", ["ean"] = "9506000134352" }];
async Task Export()
{
string zpl = await editor!.GetZplAsync();
byte[] pdf = await editor.GetPdfAsync();
}
}
// same host (Blazor Server or a hosted WebAssembly app)
builder.Services.AddZplCoreDesigner();
app.MapZplCoreDesigner("/designer").RequireAuthorization(); // your auth
Die Komponente hüllt das JavaScript-SDK für Blazor Server und WebAssembly ein (interaktive Render-Modi; beim Prerendering passiert nichts). Den Editor liefert ein ZplCore.Designer-Host in derselben Anwendung oder der Container: BaseUrl="https://labels.example.com/designer", Ihre Anwendung in ZPLCORE_DESIGNER__ALLOWEDORIGINS__0 eintragen und den Schlüssel mit RequestHeaders übergeben. Designs, ZPL und PDFs kommen als Byte-Streams zurück, die SignalR-Nachrichtengrenze von Blazor Server greift daher nicht.
| Parameter | Bedeutung |
|---|---|
BaseUrl (Pflicht) | URL des Editors (Präfix von MapZplCoreDesigner oder Container-URL) |
Design / DesignChanged | Design-Dokument, in beide Richtungen mit @bind-Design |
Data | Datensätze für die Bindung (eine neue Collection-Instanz wird gesendet) |
Locale, Theme, ReadOnly | Jederzeit änderbar |
Unit, Tab, Features, Autosave, RequestHeaders, AllowedOrigins, SdkUrl | Beim Einbinden gelesen |
OnChange, OnSelectionChange, OnValidation, OnReady, OnError | Ereignisse (OnValidation schaltet die Prüfung ein) |
Height, Class, Title, MaxResultBytes | Host-Element, iframe-Titel, größtes zurückgelesenes Ergebnis (64 MB) |
Methoden: GetDesignAsync, SetDesignAsync, SetDataAsync, GetZplAsync, GetPdfAsync, GetPngAsync, GetSelectionAsync, ValidateAsync, UndoAsync, RedoAsync, SetLocaleAsync, SetThemeAsync, SetRequestHeadersAsync.
07WPF / WinForms mit WebView2
Eine Desktop-Anwendung startet den Designer im eigenen Prozess (NuGet ZplCore.Designer, Kestrel auf einem zufälligen 127.0.0.1-Port) und zeigt ihn in WebView2. Eine kleine Bridge-Seite bindet den Editor mit dem JavaScript-SDK ein und reicht Befehle und Ereignisse zwischen C# (CoreWebView2.PostWebMessageAsString / WebMessageReceived) und dem Editor weiter. Die API antwortet nur auf Anfragen mit einem zufälligen Token des Prozesses, andere Programme auf dem Rechner können den Port also nicht nutzen; nichts verlässt den Rechner.
// samples/DesignerWpf: host on a random loopback port, API only with a per-process token
var host = await LocalDesignerHost.StartAsync(Path.Combine(AppContext.BaseDirectory, "bridge"));
await Web.EnsureCoreWebView2Async();
var core = Web.CoreWebView2;
var bridge = new DesignerBridge(json => { core.PostWebMessageAsString(json); return Task.CompletedTask; });
core.WebMessageReceived += (_, e) => bridge.OnMessage(e.TryGetWebMessageAsString());
core.Navigate(host.BridgePageUrl); // the bridge page mounts the editor with the JS SDK
await bridge.InitAsync(host.DesignerUrl, design, data, "de", headers: host.Headers);
string zpl = await bridge.GetZplAsync();
JsonObject? doc = await bridge.GetDesignAsync();
Das Beispiel samples/DesignerWpf (gemeinsame Teile in samples/designer-embed: Bridge-Seite, DesignerBridge, LocalDesignerHost, Datensatz-Import aus JSON oder CSV) öffnet und speichert Designs, lädt Datensätze, exportiert ZPL und PDF und bietet Rückgängig/Wiederholen und die Sprachwahl. Es braucht die WebView2-Laufzeit.
08.NET MAUI
Eine HybridWebView zeigt dieselbe Bridge-Seite; Befehle und Ereignisse laufen über DesignerBridge. Unter Windows läuft der Designer-Host in der App (LocalDesignerHost); unter Android, iOS und Mac Catalyst nutzt die App einen Designer-Host oder den Container in Ihrem Netz – dort den Ursprung der Seite erlauben:
ZPLCORE_DESIGNER__ALLOWEDORIGINS__0=https://0.0.0.1 # Android ZPLCORE_DESIGNER__ALLOWEDORIGINS__1=app://0.0.0.1 # iOS / Mac Catalyst
Das Beispiel samples/DesignerMaui braucht die MAUI-Workloads (dotnet workload install maui-windows maui-android) und gehört nicht zur Solution. Die Arbeitsfläche ist für Maus und Stift ausgelegt; auf Touch-Geräten funktioniert der Editor mit Einschränkungen.
09Optionen und Konfiguration
AddZplCoreDesigner(o => …) konfiguriert ZplCoreDesignerOptions; der Container bindet dasselbe Objekt aus dem Abschnitt Designer.
| Option | Standard | Bedeutung |
|---|---|---|
PathBase | /designer | Präfix für MapZplCoreDesigner() ohne Argument |
AllowedOrigins | leer | Ursprünge, die den Editor einrahmen und die API ursprungsübergreifend aufrufen dürfen; leer = nur derselbe Ursprung |
AllowAnonymous | false | API ohne angemeldeten Benutzer öffnen (nur ausdrücklich) |
Fonts.AddDirectory(dir, "E") | – | Druckerspeicher-Schriften (TTF/OTF) als E:NAME.TTF; Fonts.Providers für eigene IFontProvider |
Fonts.AddGraphicDirectory(dir) | – | Für Grafiktext freigegebene Schriften (müssen auch auf dem Server installiert sein); Systemschriften werden nie ausgeliefert |
PrinterGraphics.AddDirectory(dir) / .Provider | keine | Druckerspeicher-Grafiken (^XG) für Arbeitsfläche und Rendern |
Icons.AddDirectory(dir) / .Provider | keine | Eigene SVG-Icons neben der eingebauten Bibliothek |
Templates.AddDirectory(dir) / .Provider | keine | Design-Vorlagen (id.json, Übersetzungen id.de.json) |
SvgFonts.AddDirectory(dir) | keine | SVG-Schriften und Glyphen-Sets für den Schriften-Reiter |
Limits | siehe unten | Schutzgrenzen |
Features.* | alle true | Zpl, Png, Pdf, Svg, Preview, ItemInk, ZplElement, Fonts, PrinterGraphics, ImageConvert, SvgConvert, SvgOptimize, Icons, Templates, ZplAnalyse, ZplLint, SvgFonts, ZplImport, BarcodeGenerate, BarcodeReadability, OpenApi, Ui – false legt den Endpunkt nicht an (404) und blendet seinen Reiter aus |
Ui.Branding | – | Title, PlatformTitle, Logo, LogoAlt, Favicon, HideTabs, HideHeaderLinks |
Ui.FileProvider | eingebettete Oberfläche | Einen angepassten Build der Editor-Oberfläche ausliefern |
Grenzen
| Grenze | Standard |
|---|---|
MaxRequestBodyBytes | 16 MB |
MaxRecordsPerRequest | 500 |
MaxItemsPerDesign | 2.000 |
MaxInkItemsPerRequest · MaxInkBatchRequests · MaxInkBatchItems | 60 · 50 · 1.000 |
MaxImageBytes · MaxImagePixels | 10 MB · 40 MP |
MaxSvgBytes · MaxGraphicDots | 2 MB · 16 Mio. Dots |
MaxZplElementBytes · MaxLabelMm | 1 MB · 1.000 mm |
MaxConcurrentRenders · MaxQueuedRenders · QueueTimeout | Anzahl CPUs · 4 × Anzahl CPUs · 10 s |
RenderTimeout | 30 s |
ItemInkCacheEntries | 20.000 |
RateLimit.PermitsPerWindow · RateLimit.Window | 0 (aus) · 1 min, je Client-IP |
Erweiterungspunkte
Schnittstellen, die Sie in der DI registrieren oder in den Optionen übergeben: IFontProvider, IPrinterGraphicsProvider, IIconProvider, ITemplateProvider (Inhalte), IDesignerAuthorization (eine Operation je Anfrage erlauben oder ablehnen), IRenderObserver (Logging, Metriken) und IDesignerLicenseValidator (Lizenzprüfung).
Konfiguration der Editor-Oberfläche
Die Oberfläche liest, spätere Quellen gewinnen: {prefix}/config.json des Servers (Funktionen, Einbettungs-Ursprünge, Branding – keine Geheimnisse) → window.__ZPLCORE_DESIGNER__ einer Host-Seite → den Query-String nur für Anzeigeoptionen (locale, theme, unit, tab, autosave=0, features=-images,-fonts). API-Basis, Request-Header und Ursprünge kommen nie aus der URL. autosave (Standard an) hält einen Entwurf im lokalen Speicher des Browsers unter dem Präfix zplcore.designer.; schalten Sie es ab, wenn Ihre Anwendung das Design speichert.
10Render-API-Referenz
Alle Routen sind relativ zu {prefix}/api (z. B. /designer/api). Anfragen und Antworten sind UTF-8-JSON mit camelCase-Namen; jede Anfrage ist in sich vollständig, nichts wird gespeichert. Antworten tragen X-ZplCore-Designer-Api: 1. Der Editor nutzt diese API; Ihr Backend kann sie direkt aufrufen (mit der Anmeldung des Hosts oder dem API-Schlüssel des Containers).
Design rendern
{
"document": { "label": { "unit": "Mm", "width": 60, "height": 40, "items": [
{ "type": "text", "name": "name", "x": 3, "y": 3, "dataField": "name", "fontSize": 14 } ] } },
"records": [ { "name": "Anna" }, { "name": "Ben" } ]
}
| Route | Body | Ergebnis |
|---|---|---|
POST /zpl | document, records? | { "zpl": "^XA…^XZ" }, ein Format je Datensatz |
POST /render/png | document, record? oder records? (erster) | image/png, ein Etikett |
POST /render/pdf | document, records? | application/pdf, eine Seite je Datensatz |
POST /render/svg | document, records? (erster) | image/svg+xml (Vektor) |
POST /render/preview | wie png | image/png – Druckbild für die Überlagerung auf der Arbeitsfläche |
document ist ein Design-Dokument (oder { "label": … }); das Label wird streng gelesen (unbekannte Eigenschaften → 400). Die Werte kommen aus records/record, nicht aus document.records. Jedes Bild ist das gerenderte /zpl-Ergebnis: Vorschau = Druck.
curl -X POST https://labels.example.com/designer/api/zpl \ -H "X-Api-Key: $DESIGNER_API_KEY" -H "Content-Type: application/json" \ -d @request.json
Helfer für die Arbeitsfläche
| Route | Zweck |
|---|---|
POST /item-ink · POST /item-ink/batch | Gedruckte Geometrie jedes Elements in Dots (x, y, width, height, bei linearen Barcodes auch bars*) – hält die Arbeitsfläche deckungsgleich mit dem Druck; auf dem Server zwischengespeichert |
POST /zpl-element | Vorschau eines ZPL-Elements: { zpl, dpi, widthMm, heightMm } → { empty, x, y, width, height, png } |
GET /fonts | { graphic: [Familien], printer: [{ name, family }] } |
GET /fonts/font0 · /fonts/mono · /fonts/printer?name=E:X.TTF | Schriftdateien für die Arbeitsfläche |
GET /printer-graphics · /printer-graphics/png?name=E:LOGO.GRF | Druckerspeicher-Grafiken des Hosts |
POST /barcode/readability | Rücklese-Prüfung gestalteter Barcodes (findings AR001–AR010) |
Umwandeln und Analysieren
| Route | Zweck |
|---|---|
POST /image/convert | Bild (base64 PNG/JPEG/GIF/BMP) → grf und zpl, mit Zuschnitt, Drehen, Spiegeln, Größe und Schwärzung; zustandslos, kein Upload |
POST /svg/convert · POST /svg/optimize | SVG → ^GFA / optimiertes SVG (Skripte, Event-Handler, externe Verweise entfernt) |
POST /zpl/analyse · POST /zpl/lint | ZPL-Analyser (Befehle, Druckzeit) und Linter (Hinweise mit Lösung) |
POST /zpl/design · POST /zpl/decode | ZPL → Design-Dokument (Import) · Bytes einer ZPL-Datei → Text |
POST /barcode/generate | Einzelner Barcode als ZPL + PNG (Generator-Reiter) |
GET /icons · /icons/{id} · /svg-fonts/{path} · /templates · /templates/{id}/design · /templates/{id}/thumb | Inhalte des Hosts |
Fehler
{ "error": "The request body is larger than 16,777,216 bytes.", "code": "too_large" }
| HTTP | code | Wann |
|---|---|---|
| 400 | invalid_request · render_failed | Unlesbare oder ungültige Anfrage · das Design ließ sich nicht rendern |
| 401 / 403 | forbidden · license_invalid | Anmeldung von Host / Container, Autorisierungs-Hook, Lizenzprüfung |
| 404 | not_found | Unbekannte Schrift, Grafik, Icon, Vorlage oder Route, oder Endpunkt abgeschaltet |
| 413 | too_large | Über einer Grenze (die Meldung nennt sie) |
| 415 | unsupported_media_type | Bildformat außer PNG/JPEG/GIF/BMP |
| 429 | rate_limited | Anfragegrenze; Header Retry-After |
| 503 · 504 | busy · timeout | Alle Render-Plätze belegt (Retry-After) · Rendern länger als RenderTimeout |
Serveroptionen für die Oberfläche: GET {prefix}/config.json; Status: GET {prefix}/healthz → { status, version, buildTimeUtc }. Die vollständige OpenAPI-Beschreibung liefert Ihr eigener Host unter {prefix}/api/openapi/zplcore-designer.json.
11JavaScript-API
ZplCoreDesigner.mount(target, options)
Legt den Editor in target an (Element oder Selektor) und liefert ein Editor-Objekt, sobald der Editor antwortet.
| Option | Standard | Bedeutung |
|---|---|---|
baseUrl | – (Pflicht) | URL des Editors, z. B. /designer/ oder https://labels.example.com/designer/ |
design | Start-Design | Design-Dokument, Label-JSON oder JSON-Text |
data | design.records | Datensätze für die Bindung |
locale · theme · unit · tab | gespeichert / Browser · auto · mm · – | 10 Sprachen · light / dark / auto · mm / inch · Start-Reiter (pdf, zpl, data …) |
features | alle an | Teile abschalten: { gs1: false }, ['-gs1'] oder '-gs1,-rfid' – gs1 rfid images icons fonts zplElement jsonTab testData templates pdfPreview svgPreview pngPreview zplTab zplAnalyser zplLinter zplToDesign dpiCalc generator serverStatus commandPalette fileMenu |
readOnly | false | Nur ansehen, Vorschau und Export |
autosave | false | Entwurf im Browser halten (Ihre Anwendung speichert über onChange) |
requestHeaders | – | Header der API-Aufrufe des Editors (Objekt oder async-Funktion), z. B. { 'X-Api-Key': … } oder Authorization: Bearer … |
allowedOrigins | Ursprung von baseUrl | Ursprünge, deren Nachrichten angenommen werden |
timeout · readyTimeout | 30.000 ms | Zeitlimit eines Befehls (jeder Aufruf nimmt auch { timeout }) · bis der Editor bereit ist |
title, className | – | iframe-Titel (Barrierefreiheit) und CSS-Klasse |
onChange · onSelectionChange · onValidation · onReady · onError | – | Ereignisse: Bearbeitung durch den Nutzer (entprellt, vollständiges Design inkl. Datensätze; nicht Ihr eigenes setDesign/setData) · { names, items } · Linter-Ergebnis des Servers nach jeder Änderung · bereit · { code, message } |
Methoden (alle liefern Promises)
| Methode | Ergebnis |
|---|---|
getDesign() · setDesign(doc, records?) | Design-Dokument ({ label, editor, … }) · ein Design laden (Dokument oder Label-JSON) |
setData(records) | Datensätze ersetzen |
getZpl({ records? }) | ZPL für alle (oder die übergebenen) Datensätze – dasselbe ZPL, das der Server druckt |
getPdf({ records? }) · getPng({ record: 0 }) | Blob des PDFs / eines Etiketts als PNG |
undo() · redo() | Verlauf |
setLocale(l) · setTheme(t) · setReadOnly(on) · setRequestHeaders(h) | Sprache, Farbschema, Lesemodus, neues Token |
getSelection() · validate() | { names, items } · { valid, errorCount, warningCount, infoCount, issues } |
ping() · whenReady() · on(event, fn) / off(event, fn) | Lebenszeichen, Bereitschaft, Ereignisse nach dem Einbinden |
destroy() | iframe und alle Listener entfernen |
Alle Methoden liefern Promises; Fehler lehnen mit ZplCoreDesignerError ab (code: timeout, command_failed, ready_timeout, destroyed, invalid_options …). createDesigner() liefert die Instanz sofort (Befehle warten, bis sie bereit ist).
Das postMessage-Protokoll
Ohne SDK können Sie direkt mit dem iframe sprechen (Protokollversion 2). Host → Editor: { source: 'zplcore-host', type, id, payload }; Editor → Host: { source: 'zplcore', type: 'result', id, payload } und die Ereignisse ready und change (entprellt, { design, records }). Befehle: ping, getDesign, setDesign { design, records? }, setData { records }, getZpl { records? }, getPdf, getPng { record? } (beide { mimeType, base64 }), undo, redo, setLocale { locale }, setTheme { theme }. Der erste gültige Absender legt den Host-Ursprung fest (oder die Allow-List AllowedOrigins); Antworten gehen nur an diesen Ursprung, nie an *. Das SDK nutzt zusätzlich einen Start-Handshake (?embed=sdk: der Editor sendet hello, das SDK antwortet mit init samt Headern, Lesemodus, Design und Datensätzen vor dem ersten API-Aufruf) sowie die Befehle setReadOnly, setRequestHeaders, getSelection, setValidation, validate mit den Ereignissen selectionChange, validation und error. Der Live-Editor dieser Website nutzt genau dieses Protokoll.
12Schema des Design-Dokuments
Ein Design ist ein JSON-Dokument mit fünf Teilen. Pflicht ist nur label; der Editor schreibt nur Werte, die vom Startwert abweichen.
{
"schemaVersion": 4,
"label": { "unit": "Mm", "width": 100, "height": 50, "items": [ … ] },
"editor": { "version": 1, "dpi": 203, "items": { "ean": { "locked": true } }, "groups": [] },
"records": [ { "name": "Anna", "metadata": { "promo": { "isRendered": false } } } ],
"uiSettings": { "zoom": 120, "tab": "pdf" }
}
| Teil | Inhalt | Wirkt auf den Druck |
|---|---|---|
label | Das zplCore-Label-Modell (label.schema.json, Schema-Version 4) – dasselbe JSON, das das SDK mit Label.FromJson liest | ja |
editor | Zustand des Designers, eigene Version editor.version (fehlt = 1) | teilweise (siehe unten) |
records | Beispiel-Datensätze; Feldnamen sind die Bindungsnamen; reserviert ist metadata[itemName].isRendered = false, das ein Element für diesen Datensatz ausblendet | ja (Ausblenden) |
uiSettings | Optionaler Oberflächen-Zustand: vsplit, split, theme, zoom, tab, gridSize, snapDistance | nein |
Der Teil editor
| Eigenschaft | Typ · Startwert | Bedeutung |
|---|---|---|
version | Ganzzahl · 1 | Version des Editor-Teils |
dpi | Ganzzahl · 203 | Auflösung der Vorschau; Ersatzwert, wenn kein Drucker-dpi übergeben wird – wirkt auf das ZPL |
debugLabel | boolean · false | Debug-Etikett (Rahmen, Mittelkreuz, 10-mm-Marken, Zeitstempel) – wirkt auf das ZPL |
cutAfterLastLabelMode | "delayed" | "cutter" | Wie label.cutAfterLastLabel gedruckt wird – wirkt auf das ZPL |
grid | { enabled } | Raster an/aus (weitere Eigenschaften erlaubt) |
items[name] | Objekt | Je Element (Schlüssel = label.items[].name, Groß-/Kleinschreibung zählt): locked, groupId, gs1 (elements[{ai, value}], encoding bracket / encoded / digitalLink, domain), textFit (auto / clip / wrap / shrink), rfidLockApply und rfidPermaLockApply (wirken auf das ZPL) |
groups | [{ id, name }] | Gruppen der Elementliste |
Kompatibilitätszusage
- Innerhalb einer Schema-Version nur additive Änderungen: neue optionale Eigenschaften, deren Startwert den bisherigen Druck und das bisherige Verhalten erhält.
- Umbenennen, Entfernen, neuer Typ, neue Bedeutung oder neuer Startwert ⇒ neue Version (
label.schemaVersionodereditor.version) mit Migrationsschritt; jede Version liest alle älteren. - Unbekannte Eigenschaften in
editorbleiben erhalten und werden zurückgeschrieben, damit ein älterer Host ein neueres Design nie beschädigt. An API-Grenzen wird das Label streng gelesen.
13Sicherheit und Betrieb
- Keine eigene Benutzerverwaltung. NuGet: Ihre Anmeldung und Richtlinien. Container:
apikey,jwt(OIDC) oder ausdrücklichnone. - Einbettung:
frame-ancestorsund CORS ausAllowedOrigins; postMessage-Antworten gehen nur an den festgelegten Host-Ursprung. - Eingaben: Größengrenzen je Anfrage, Render-Plätze mit Warteschlange und Zeitlimit, optionale Anfragegrenze je IP; SVGs werden bereinigt (keine Skripte, keine externen Verweise), der Server ruft nie URLs ab, ZPL-Elemente werden nur gerendert.
- Keine Speicherung, keine Telemetrie: Der Server behält zwischen Anfragen nichts (nur Zwischenspeicher gemessener Geometrie); kein Nach-Hause-Telefonieren, kein CDN – die Oberfläche lädt jede Datei von Ihrem Host.
- Skalierung: zustandslos, also beliebig viele Instanzen ohne Sticky Sessions. Native Abhängigkeiten (SkiaSharp, HarfBuzz, PDFium, ZXing) unterstützen Linux x64/arm64 (glibc), Windows und macOS.
- Überwachung: Status
{prefix}/healthz(Container zusätzlich/healthz,/readyz), Metriken im MeterZplCore.Designer(zplcore.designer.requests,zplcore.designer.duration,zplcore.designer.records), OpenTelemetry-Export (OTEL_EXPORTER_OTLP_ENDPOINT) und strukturierte JSON-Logs im Container. - Container: distroless-Basis (Azure Linux), Benutzer
appohne Root, schreibgeschütztes Root-Dateisystem mit beschreibbarem/tmp; Helm-Chart mit entzogenen Capabilities, seccomp und optionaler Network Policy. - Datenschutz: Designs und Datensätze bleiben in Ihrer Anwendung; der Entwurf des Editors liegt nur im Browser des Benutzers und lässt sich abschalten (
autosave=0).
14Lizenz
Der zplCore Designer gehört zur kommerziellen Produktfamilie von zplCore.com. Lizenzmodell und Preise sind noch nicht veröffentlicht; sprechen Sie uns an für eine Testversion oder ein Angebot. Den Live-Editor dieser Website können Sie mit Demo-Grenzen kostenlos ausprobieren.

