zplCore.comzplCore.com

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.

Live-Editor öffnen Schnellstart Render-API

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.

LieferformWas Sie bekommenFür wen
NuGet ZplCore.DesignerAddZplCoreDesigner() + 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/designerLauffertiger Container (distroless, ohne Root) mit Editor und API, konfiguriert über Umgebungsvariablen; Helm-ChartTeams ohne .NET, Kubernetes, Einbettung per iframe
JavaScript-SDK zplcore-designer.jsZplCoreDesigner.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 WebAssemblyBlazor-Anwendungen
DesktopDer Designer-Host auf Loopback + WebView2 (WPF, WinForms) oder die MAUI-WebViewDesktop-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).

Anmeldung. Die API verlangt einen angemeldeten Benutzer Ihrer Anwendung (Ihre Standard-Autorisierungsrichtlinie). Offenen Zugriff gibt es nur ausdrücklich mit 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.

VariableBedeutung
ZPLCORE_DESIGNER__PATHBASERouten-Präfix von Editor und API, Standard /designer
ZPLCORE_DESIGNER__AUTH__MODEPflicht: apikey, jwt (OIDC) oder none (ausdrücklich, nur hinter eigenem Proxy; das Log warnt)
…__AUTH__APIKEYS__0 … · …__AUTH__APIKEYHEADERAPI-Schlüssel (mindestens 16 Zeichen, aus einem Secret) · Header, Standard X-Api-Key
…__AUTH__AUTHORITY, __AUDIENCE, __REQUIREDROLE, __REQUIREHTTPSMETADATAJWT / 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=trueX-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.

ParameterBedeutung
BaseUrl (Pflicht)URL des Editors (Präfix von MapZplCoreDesigner oder Container-URL)
Design / DesignChangedDesign-Dokument, in beide Richtungen mit @bind-Design
DataDatensätze für die Bindung (eine neue Collection-Instanz wird gesendet)
Locale, Theme, ReadOnlyJederzeit änderbar
Unit, Tab, Features, Autosave, RequestHeaders, AllowedOrigins, SdkUrlBeim Einbinden gelesen
OnChange, OnSelectionChange, OnValidation, OnReady, OnErrorEreignisse (OnValidation schaltet die Prüfung ein)
Height, Class, Title, MaxResultBytesHost-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.

OptionStandardBedeutung
PathBase/designerPräfix für MapZplCoreDesigner() ohne Argument
AllowedOriginsleerUrsprünge, die den Editor einrahmen und die API ursprungsübergreifend aufrufen dürfen; leer = nur derselbe Ursprung
AllowAnonymousfalseAPI 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) / .ProviderkeineDruckerspeicher-Grafiken (^XG) für Arbeitsfläche und Rendern
Icons.AddDirectory(dir) / .ProviderkeineEigene SVG-Icons neben der eingebauten Bibliothek
Templates.AddDirectory(dir) / .ProviderkeineDesign-Vorlagen (id.json, Übersetzungen id.de.json)
SvgFonts.AddDirectory(dir)keineSVG-Schriften und Glyphen-Sets für den Schriften-Reiter
Limitssiehe untenSchutzgrenzen
Features.*alle trueZpl, 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.FileProvidereingebettete OberflächeEinen angepassten Build der Editor-Oberfläche ausliefern

Grenzen

GrenzeStandard
MaxRequestBodyBytes16 MB
MaxRecordsPerRequest500
MaxItemsPerDesign2.000
MaxInkItemsPerRequest · MaxInkBatchRequests · MaxInkBatchItems60 · 50 · 1.000
MaxImageBytes · MaxImagePixels10 MB · 40 MP
MaxSvgBytes · MaxGraphicDots2 MB · 16 Mio. Dots
MaxZplElementBytes · MaxLabelMm1 MB · 1.000 mm
MaxConcurrentRenders · MaxQueuedRenders · QueueTimeoutAnzahl CPUs · 4 × Anzahl CPUs · 10 s
RenderTimeout30 s
ItemInkCacheEntries20.000
RateLimit.PermitsPerWindow · RateLimit.Window0 (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" } ]
}
RouteBodyErgebnis
POST /zpldocument, records?{ "zpl": "^XA…^XZ" }, ein Format je Datensatz
POST /render/pngdocument, record? oder records? (erster)image/png, ein Etikett
POST /render/pdfdocument, records?application/pdf, eine Seite je Datensatz
POST /render/svgdocument, records? (erster)image/svg+xml (Vektor)
POST /render/previewwie pngimage/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

RouteZweck
POST /item-ink · POST /item-ink/batchGedruckte 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-elementVorschau 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.TTFSchriftdateien für die Arbeitsfläche
GET /printer-graphics · /printer-graphics/png?name=E:LOGO.GRFDruckerspeicher-Grafiken des Hosts
POST /barcode/readabilityRücklese-Prüfung gestalteter Barcodes (findings AR001–AR010)

Umwandeln und Analysieren

RouteZweck
POST /image/convertBild (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/optimizeSVG → ^GFA / optimiertes SVG (Skripte, Event-Handler, externe Verweise entfernt)
POST /zpl/analyse · POST /zpl/lintZPL-Analyser (Befehle, Druckzeit) und Linter (Hinweise mit Lösung)
POST /zpl/design · POST /zpl/decodeZPL → Design-Dokument (Import) · Bytes einer ZPL-Datei → Text
POST /barcode/generateEinzelner Barcode als ZPL + PNG (Generator-Reiter)
GET /icons · /icons/{id} · /svg-fonts/{path} · /templates · /templates/{id}/design · /templates/{id}/thumbInhalte des Hosts

Fehler

{ "error": "The request body is larger than 16,777,216 bytes.", "code": "too_large" }
HTTPcodeWann
400invalid_request · render_failedUnlesbare oder ungültige Anfrage · das Design ließ sich nicht rendern
401 / 403forbidden · license_invalidAnmeldung von Host / Container, Autorisierungs-Hook, Lizenzprüfung
404not_foundUnbekannte Schrift, Grafik, Icon, Vorlage oder Route, oder Endpunkt abgeschaltet
413too_largeÜber einer Grenze (die Meldung nennt sie)
415unsupported_media_typeBildformat außer PNG/JPEG/GIF/BMP
429rate_limitedAnfragegrenze; Header Retry-After
503 · 504busy · timeoutAlle 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.

OptionStandardBedeutung
baseUrl– (Pflicht)URL des Editors, z. B. /designer/ oder https://labels.example.com/designer/
designStart-DesignDesign-Dokument, Label-JSON oder JSON-Text
datadesign.recordsDatensätze für die Bindung
locale · theme · unit · tabgespeichert / Browser · auto · mm · –10 Sprachen · light / dark / auto · mm / inch · Start-Reiter (pdf, zpl, data …)
featuresalle anTeile 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
readOnlyfalseNur ansehen, Vorschau und Export
autosavefalseEntwurf 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 …
allowedOriginsUrsprung von baseUrlUrsprünge, deren Nachrichten angenommen werden
timeout · readyTimeout30.000 msZeitlimit 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)

MethodeErgebnis
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" }
}
TeilInhaltWirkt auf den Druck
labelDas zplCore-Label-Modell (label.schema.json, Schema-Version 4) – dasselbe JSON, das das SDK mit Label.FromJson liestja
editorZustand des Designers, eigene Version editor.version (fehlt = 1)teilweise (siehe unten)
recordsBeispiel-Datensätze; Feldnamen sind die Bindungsnamen; reserviert ist metadata[itemName].isRendered = false, das ein Element für diesen Datensatz ausblendetja (Ausblenden)
uiSettingsOptionaler Oberflächen-Zustand: vsplit, split, theme, zoom, tab, gridSize, snapDistancenein

Der Teil editor

EigenschaftTyp · StartwertBedeutung
versionGanzzahl · 1Version des Editor-Teils
dpiGanzzahl · 203Auflösung der Vorschau; Ersatzwert, wenn kein Drucker-dpi übergeben wird – wirkt auf das ZPL
debugLabelboolean · falseDebug-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]ObjektJe 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.schemaVersion oder editor.version) mit Migrationsschritt; jede Version liest alle älteren.
  • Unbekannte Eigenschaften in editor bleiben 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ücklich none.
  • Einbettung: frame-ancestors und CORS aus AllowedOrigins; 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 Meter ZplCore.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 app ohne 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.