Technischer Artikel

Scanbare Barcodes in PDF mit HotPDF in Delphi erzeugen

Ein Barcode ist kein Bild, mit dem man ein Dokument dekoriert. Er ist eine Messgröße, und der Scanner ist das Instrument, das sie abliest. Diese Umdeutung entscheidet fast alles darüber, wie man einen Barcode in ein PDF zeichnen sollte. Die Balken tragen keine Information durch ihre Schwärze; die Information steckt im Verhältnis der Balkenbreiten zu den Lückenbreiten, und ein Lesegerät gewinnt sie zurück, indem es die Übergänge zeitlich misst, während ein Laser oder Sensor darüberstreicht. Staucht man diese Geometrie, verwischt sie oder drängt ihre Ränder zu, entsteht etwas, das exakt wie ein Barcode aussieht und wie ein Fleck scannt. HotPDF bietet zwei Wege, einen Barcode auf eine Seite zu bringen, und der Unterschied zwischen beiden ist genau der Unterschied zwischen der Kontrolle über diese Geometrie und ihrer Aufgabe

Eine PDF-Seite mit einem Raster linearer Barcodes in verschiedenen Symbologien, gezeichnet von HotPDF in Delphi
Lineare Barcode-Symbologien, mit HotPDF in ein einziges PDF gezeichnet

Was HotPDF kodieren kann

HotPDF zeichnet lineare (eindimensionale) Symbologien, und die Auswahl ist breiter, als die meisten Projekte benötigen. Die Enumeration THPDFBarcodeType deckt die Code-2-of-5-Familie in ihren Interleaved-, Industrial- und Matrix-Formen ab; Code 39 und seine erweiterte Variante; die drei Code-128-Untergruppen A, B und C; Code 93 in normaler und erweiterter Form; MSI; PostNet; Codabar; die Einzelhandelsgruppe UPC und EAN, nämlich EAN-8, EAN-13, UPC-A, die komprimierten UPC-E0 und UPC-E1 sowie die 2- und 5-stelligen UPC-Zusatzcodes; und die GS1-128-Untergruppen (EAN-128). Das reicht für Lieferketten-Etiketten, den Einzelhandelskassenbereich und die älteren Industriecodes, die in Lagern noch im Einsatz sind

Was HotPDF nicht zeichnet, ist die zweidimensionale Familie. Es gibt hier kein QR, Data Matrix oder PDF417. Diese kodieren Bytes in einem Raster mit eigener Fehlerkorrektur-Mathematik, und wenn eine Anforderung einen davon nennt, ist dies das falsche Werkzeug — das sollten Sie wissen, bevor Sie darauf aufbauen, nicht danach. Für eindimensionale Codes ist die praktische Frage enger gefasst: Welche Symbologie akzeptiert die Daten, die Sie tatsächlich haben, denn die Kodierungen sind nicht austauschbar

Die Datenbeschränkungen sind real und schlagen zur Generierungszeit zu. Die Code-2-of-5-Varianten und MSI nehmen ausschließlich Ziffern. Code 39 trägt Großbuchstaben, Ziffern und eine Handvoll Satzzeichen; wer Kleinbuchstaben oder den vollen ASCII-Bereich braucht, greift zu Code 39 Extended oder einer Code-128-Untergruppe. Code 128C packt aus Dichtegründen zwei Ziffern in jedes Symbol, verlangt also eine numerische Zeichenfolge gerader Länge und nichts anderes. EAN-13 erwartet zwölf Ziffern und berechnet die dreizehnte als Prüfziffer; EAN-8 erwartet sieben und berechnet die achte; UPC-A nimmt zwölf. Übergibt man einer Symbologie Daten, die sie nicht darstellen kann, erhält man keine hilfreiche Exception, sondern einen Barcode, der Müll kodiert — was schlimmer ist, denn er sieht gut aus, bis ihn jemand an einer Kasse scannt

Zwei Zeichenwege, zwei Kontrollstufen

Die Methode der Wahl für die Produktion ist DrawBarcode am Seitenobjekt. Sie nimmt die Symbologie, eine Position, eine Höhe und einen Parameter, der wichtiger ist als alle anderen: MUnit, die Modulbreite. Das Modul ist die Breite des schmalsten Balkens, das Atom, von dem jedes andere Maß im Code ein Vielfaches ist, und es wird hier in Punkten angegeben. Alles, was darüber entscheidet, ob das gedruckte Ergebnis scannt, führt auf diese eine Ganzzahl zurück

var
  Pdf: THotPDF;
begin
  Pdf := THotPDF.Create(nil);
  try
    Pdf.FileName := 'label.pdf';
    Pdf.BeginDoc;

    // BCType, X, Y, Height, MUnit (module width in points), angle,
    // data, UseCheckSum, bar color, background color.
    Pdf.CurrentPage.DrawBarcode(
      bcCodeEAN13,           // symbology
      72, 680,               // X, Y in points from the bottom-left
      60,                    // bar height
      1,                     // MUnit: 1pt narrowest bar
      0,                     // no rotation
      '123456789012',        // 12 digits; the 13th is the check
      True,                  // append the modulo-10 check digit
      clBlack, clWhite);     // bars black, background white

    Pdf.EndDoc;
  finally
    Pdf.Free;
  end;
end;

Zwei Argumente verdienen einen genaueren Blick. UseCheckSum hängt die Modulo-10-Prüfziffer an, die die Symbologie erwartet, und für die Einzelhandelscodes will man sie fast immer auf True; schalten Sie sie nur ab, wenn Ihre Daten bereits eine vorberechnete Prüfziffer tragen, sonst erhalten Sie eine verdoppelte Ziffer. Balken- und Hintergrundfarbe sind die letzten beiden Parameter, und die Versuchung, dort kreativ zu werden, ist eine Falle, die weiter unten besprochen wird. Beachten Sie auch den Koordinatenursprung: Wie jeder andere Zeichenaufruf in HotPDF messen X und Y in Punkten von der linken unteren Ecke der Seite, mit nach oben wachsendem Y — dieselbe Konvention, die das Hello-World-Beispiel durchgeht

Der zweite Weg ist DirectDrawBarcode, das die Daten und einen Begrenzungsrahmen nimmt, X, Y, Width, Height, und das Balkenmuster so skaliert, dass es diese Breite füllt. Das ist praktisch, um Codes in einem Raster anzuordnen, weil Sie die Stellfläche vorgeben und die Methode die Balken einpasst. Diese Bequemlichkeit ist zugleich ihre Gefahr. Wenn Sie eine Breite vorgeben, legen Sie die Modulgröße nicht mehr selbst fest; die Methode teilt den erlaubten Raum unter so vielen Balken auf, wie die Daten benötigen, und der schmalste Balken wird zu dem, was bei dieser Division herausfällt. Verlangen Sie eine dichte Code-128-Zeichenfolge in einem zu schmalen Rahmen, schrumpfen die Module stillschweigend unter das, was ein Scanner auflösen kann. Für alles, was zuverlässig scannen muss, bevorzugen Sie DrawBarcode und setzen MUnit bewusst. Reservieren Sie DirectDrawBarcode für Vorschauen und für Anordnungen, bei denen Sie nachgemessen haben, dass die resultierenden Balken lesbar bleiben

Modulbreite ist eine Auflösungsentscheidung

Hier ist die Rechnung, die darüber entscheidet, ob Ihr Etikett funktioniert. Ein Laserscanner und eine Kamera haben beide ein kleinstes Merkmal, das sie unterscheiden können, und der schmale Balken muss nach dem Druck komfortabel darüber liegen. Die vielzitierte Untergrenze für lineare Allzweckcodes ist ein 13-Mil-Schmalbalken, etwa 0,33 mm, und viele Einzelhandels- und Industrieleitfäden behandeln das als Minimum, nicht als Ziel. Übersetzt in PDF-Einheiten: Ein Punkt ist 1/72 Zoll, rund 0,353 mm, sodass ein Punkt Modulbreite genau an dieser Untergrenze liegt. Deshalb ist MUnit := 1 der kleinste Wert, dem Sie für einen Code trauen sollten, der für einen echten Scanner bestimmt ist, und deshalb kauft die Verdopplung auf 2 eine Reserve, die auf einem Etikett mit Platzreserve fast nichts kostet

Verbinden Sie das nun mit der Ausgabeauflösung, denn das Modul muss auch den Drucker überleben. Auf einem 300-DPI-Laserdrucker ist ein Gerätepunkt 1/300 Zoll, ein Ein-Punkt-Modul also etwa vier Punkte breit. Vier Punkte reichen kaum für eine saubere Kante; Tonerausbreitung und leichte Registrierungsfehler zehren daran, und der Balken, der in Ihrem PDF einen Punkt maß, druckt dicker oder dünner, als die Spezifikation erlaubt. Erhöhen Sie das Modul auf 2 Punkte, haben Sie acht Gerätepunkte zur Verfügung, was dieses Rauschen absorbiert. Die Regel, die man sich einprägen sollte: Die in Punkten gesetzte Modulbreite muss bei Ihrer realen Druckauflösung auf eine ganze, komfortable Anzahl von Gerätepunkten abbilden — nicht bei der Auflösung, die Sie sich wünschen. Ein Code, der vom Bildschirm makellos scannt und vom Lagerdrucker versagt, ist fast immer an dieser Prüfung gescheitert

Die Ruhezone ist Teil des Symbols

Der mit Abstand häufigste Grund, warum ein korrekt kodierter Barcode nicht scannt, ist die Ruhezone, der leere Rand auf beiden Seiten der Balken. Scanner nutzen diese Leere, um zu erkennen, wo der Code beginnt und endet; ohne sie kann das Lesegerät den ersten Balken nicht von dem unterscheiden, was daneben auf der Seite steht. Die Normen sind konkret. Die meisten linearen Symbologien verlangen eine Ruhezone von mindestens dem Zehnfachen der Modulbreite auf jeder Seite, und die Einzelhandelscodes UPC und EAN fordern neun Module links und sieben rechts. Bei einem Ein-Punkt-Modul sind das rund zehn Punkte, etwa ein Siebtel Zoll, garantierter Weißraum beiderseits der Balken

HotPDF zeichnet die Balken und sonst nichts. Es reserviert die Ruhezone nicht für Sie, die Verantwortung liegt also bei Ihnen, und sie ist leicht zu vergessen. Der Fehlermodus ist subtil: Sie platzieren einen Barcode bündig an eine Tabellenzellengrenze, oder das Seitenlayout drängt ein Logo daneben, und der Code, der auf einer leeren Seite jeden Test bestand, hört auf zu scannen, sobald er in einem echten Dokument ausgeliefert wird. Budgetieren Sie den Rand explizit. Lassen Sie vor dem Aufruf von DrawBarcode mindestens zehn Modulbreiten freien Raum auf beiden Seiten, und behandeln Sie jede Grafik, Linie oder jeden Text, der in dieses Band eindringt, als Defekt, nicht als kosmetische Entscheidung

Farbe, Kontrast und die Klarschriftzeile

Die Balken- und Hintergrundfarben existieren, damit Sie eine Markenpalette treffen können, und sie sind der schnellste Weg, einen funktionierenden Code zu zerstören. Scanner lesen Kontrast, klassisch mit rotem Licht, und sie erwarten dunkle Balken auf hellem Grund. Schwarz auf Weiß ist die einzige Kombination, zu der Sie ohne Test greifen sollten. Dunkelblau oder Dunkelgrün auf Weiß kann bestehen; alles mit geringem Luminanzkontrast — und insbesondere rote Balken, die ein Rotlichtscanner als Hintergrund sieht — besteht nicht. Wenn ein Designer farbige Barcodes verlangt, lautet die ehrliche Antwort, dass die Balken schwarz bleiben und die Farbe an anderer Stelle auf dem Etikett landet

Der DrawBarcode-Weg kann auch den Klarschrifttext unter den Balken rendern, die Ziffern, die eine Kassenkraft eintippt, wenn ein Scan fehlschlägt. Dieser Text ist ein Fallback, keine Dekoration; wenn Sie eine eigene Beschriftung platzieren, halten Sie sie von der Ruhezone fern — eine in den Seitenrand gequetschte Symbologiebeschriftung macht genau den Weißraum zunichte, auf den der Scanner angewiesen ist. Die Felder in diesem Beispiel, einschließlich TextOut für umgebende Beschriftungen, sind dieselben Zeichenaufrufe, die der Leitfaden zur Berichtsausgabe behandelt — die richtige Anlaufstelle, wenn der Barcode nur ein Element einer größeren komponierten Seite ist

Eine kurze Verifikationsroutine

Vektorbalken sind ein Vorteil, den man beim Namen nennen sollte. Weil DrawBarcode den Code als PDF-Zeichenoperatoren schreibt statt als gerastertes Bild, bleiben die Balken bei jedem Zoom gestochen scharf, und die Datei trägt keine eigene Auflösung; die einzige Auflösung, die zählt, ist die des Druckers. Das entbindet Sie nicht vom Testen, es bedeutet nur, dass der Test auf Papier stattfinden muss. Erzeugen Sie ein Muster, drucken Sie es auf dem Gerät mit der niedrigsten Auflösung, dem Ihre Codes tatsächlich begegnen, und scannen Sie es mit derselben Geräteklasse, die Ihre Anwender in der Hand halten, nicht mit dem High-End-Imager auf Ihrem Schreibtisch. Prüfen Sie die Ruhezonen mit einem Lineal auf dem Ausdruck, bestätigen Sie, dass die Modulbreite die Reise von Punkten zu Gerätepunkten überstanden hat, und verifizieren Sie, dass der dekodierte Wert dem kodierten entspricht, Prüfziffer inklusive. Fünf Minuten mit einem echten Scanner fangen jeden oben beschriebenen Fehler ab — und zwar bevor es eine Palette falsch etikettierter Ware tut

Die hier gezeigten Methoden DrawBarcode und DirectDrawBarcode sind Teil der HotPDF Component für Delphi und C++Builder