Technisch artikel

Scanbare Barcodes in PDF Genereren met HotPDF in Delphi

Een barcode is geen plaatje waarmee u een document versiert. Het is een meting, en de scanner is het instrument dat deze leest. Dat nieuwe perspectief bepaalt bijna alles over hoe u er een in een PDF zou moeten tekenen. De balken dragen geen informatie door hun zwartheid; de informatie zit in de verhouding van de breedte van de balken tot de breedte van de ruimtes, en een lezer haalt dit terug door de overgangen te timen terwijl een laser of sensor eroverheen veegt. Knijp die geometrie samen, vervaag deze, of verdring de marges, en u produceert iets dat er precies zo uitziet als een barcode en scant als een vlek. HotPDF geeft u twee manieren om er een op een pagina te plaatsen, en het verschil daartussen is precies het verschil tussen het controleren van die geometrie en het eraan overgeven

Een PDF-pagina met een raster van lineaire barcodes in verschillende symbologieën getekend door HotPDF in Delphi
Lineaire barcode-symbologieën getekend in een enkele PDF met HotPDF

Wat HotPDF kan coderen

HotPDF tekent lineaire (eendimensionale) symbologieën, en de set is breder dan de meeste projecten nodig hebben. De THPDFBarcodeType enumeratie dekt de Code 2 of 5 familie in zijn interleaved, industrial en matrix vormen; Code 39 en zijn uitgebreide variant; de drie Code 128 subsets A, B en C; Code 93 gewoon en uitgebreid; MSI; PostNet; Codabar; de retail UPC en EAN groep, namelijk EAN-8, EAN-13, UPC-A, de gecomprimeerde UPC-E0 en UPC-E1, en de UPC aanvullende 2- en 5-cijferige add-ons; en de GS1-128 (EAN-128) subsets. Dat is genoeg om supply-chain labels, retail point of sale, en de oudere industriële codes die nog steeds in magazijnen leven, te dekken

Wat het niet tekent, is de tweedimensionale familie. Er is hier geen QR, Data Matrix of PDF417. Die coderen bytes in een raster met hun eigen wiskunde voor foutcorrectie, en als een vereiste een daarvan noemt, is dit het verkeerde gereedschap en dat moet u weten voordat u eromheen bouwt, in plaats van erna. Voor eendimensionale codes is de praktische vraag nauwer: welke symbologie accepteert de gegevens die u daadwerkelijk heeft, want de coderingen zijn niet uitwisselbaar

De databeperkingen zijn reëel en ze slaan toe bij het genereren. De Code 2 of 5 varianten en MSI accepteren alleen cijfers. Code 39 bevat hoofdletters, cijfers en een handvol leestekens; als u kleine letters of de volledige ASCII-reeks nodig hebt, dan is dat Code 39 Extended of een Code 128 subset. Code 128C verpakt twee cijfers in elk symbool voor dichtheid, dus het vereist een numerieke string van even lengte en niets anders. EAN-13 verwacht twaalf cijfers en berekent de dertiende als controle; EAN-8 verwacht er zeven en berekent de achtste; UPC-A neemt er twaalf. Geef een symbologie gegevens die deze niet kan representeren en u krijgt geen behulpzame uitzondering, u krijgt een barcode die rommel codeert, wat erger is, omdat het er goed uitziet totdat iemand het aan de kassa scant

Twee tekenpaden, twee controleniveaus

De methode om in productie naar te grijpen is DrawBarcode, op het paginaobject. Het neemt de symbologie, een positie, een hoogte, en één parameter die belangrijker is dan de rest: MUnit, de modulebreedte. De module is de breedte van de smalste balk, het atoom waar elke andere maat in de code een veelvoud van is, en deze wordt hier uitgedrukt in punten. Alles wat betreft de vraag of het geprinte resultaat scant, is te herleiden tot dat ene gehele getal

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;

Twee argumenten verdienen nader onderzoek. UseCheckSum voegt het modulo-10 controlecijfer toe dat de symbologie verwacht, en voor de retailcodes wilt u dit bijna altijd op True hebben; zet dit alleen uit als uw gegevens al een vooraf berekende controle bevatten, anders krijgt u een dubbel cijfer. De balk- en achtergrondkleuren zijn de laatste twee parameters, en de verleiding om daar creatief te zijn, is een valstrik die hieronder wordt besproken. Let ook op de oorsprong van de coördinaten: net als elke andere tekenaanroep in HotPDF, meten de X en Y vanaf de linkerbenedenhoek van de pagina in punten, waarbij Y naar boven groeit, dezelfde conventie die het Hello World voorbeeld doorloopt

Het tweede pad is DirectDrawBarcode, dat de gegevens en een omsluitend kader (bounding box) neemt, X, Y, Width, Height, en het balkenpatroon schaalt om die breedte te vullen. Het is handig voor het opmaken van codes op een raster, omdat u de voetafdruk een naam geeft en de methode de balken erin laat passen. Dat gemak is ook het gevaar ervan. Wanneer u er een breedte aan meegeeft, stelt u de modulegrootte niet langer in; de methode verdeelt de ruimte die u toestaat over de hoeveelheid balken die de gegevens nodig hebben, en de smalste balk wordt wat er ook uit die deling voortkomt. Vraag om een dichte Code 128 string binnen een kader dat te smal is en de modules krimpen tot onder wat een scanner kan oplossen, in stilte. Voor alles dat betrouwbaar moet scannen, geeft u de voorkeur aan DrawBarcode en stelt u MUnit weloverwogen in. Reserveer DirectDrawBarcode voor voorbeelden en voor opstellingen waarbij u hebt gemeten dat de resulterende balken leesbaar blijven

Modulebreedte is een beslissing over resolutie

Hier is de rekenkunde die bepaalt of uw label werkt. Zowel een laserscanner als een camera hebben een kleinste kenmerk dat ze kunnen onderscheiden, en de smalle balk moet na het printen daar ruim boven landen. De veel geciteerde ondergrens voor lineaire codes voor algemeen gebruik is een smalle balk van 13 mil, ongeveer 0,33 mm, en veel retail- en industriële handleidingen behandelen dat als een minimum in plaats van een doel. Vertaal dat naar PDF-eenheden: een punt is 1/72 inch, grofweg 0,353 mm, dus een enkel punt aan modulebreedte bevindt zich precies op die ondergrens. Dat is de reden waarom MUnit := 1 de kleinste waarde is die u zou moeten vertrouwen voor een code die bestemd is voor een echte scanner, en waarom verdubbeling naar 2 een marge koopt die vrijwel niets kost op een label waar nog ruimte over is

Verbind dat nu met de uitvoerresolutie, want de module moet ook de printer overleven. Op een 300 DPI laserprinter is één apparaatpunt 1/300 inch, dus een module van één punt is ongeveer vier punten breed. Vier punten is nauwelijks genoeg om een zuivere rand weer te geven; verspreiding van toner en kleine registratiefouten tasten deze aan, en de balk die in uw PDF één punt mat, wordt dikker of dunner afgedrukt dan de specificatie toestaat. Verhoog de module naar 2 punten en u hebt acht punten om mee te werken, wat die ruis absorbeert. De regel die het waard is om te internaliseren: de modulebreedte die u in punten instelt, moet overeenkomen met een heel, comfortabel aantal apparaatpunten bij uw echte printresolutie, niet de resolutie die u zou wensen. Een code die vlekkeloos vanaf het scherm scant en niet vanaf de printer in het magazijn, is vrijwel altijd gezakt voor deze controle

De rustzone is onderdeel van het symbool

De meest voorkomende reden waarom een correct gecodeerde barcode niet scant, is de rustzone, de blanco marge aan weerszijden van de balken. Scanners gebruiken die leegte om te vinden waar de code begint en eindigt; zonder dit kan de lezer de eerste balk niet onderscheiden van wat er ook maar naast op de pagina staat. De normen zijn specifiek. De meeste lineaire symbologieën vereisen een rustzone van ten minste tien keer de modulebreedte aan weerszijden, en de UPC- en EAN-retailcodes vragen om negen modules links en zeven rechts. Met een module van één punt is dat grofweg tien punten, ongeveer een zevende van een inch, aan gegarandeerde witruimte aan beide kanten van de balken

HotPDF tekent de balken en verder niets. Het reserveert de rustzone niet voor u, wat betekent dat de verantwoordelijkheid bij u ligt en dit gemakkelijk wordt vergeten. De foutmodus is subtiel: u plaatst een barcode direct tegen de rand van een tabelcel aan, of u laat de paginalay-out er een logo naast drukken, en de code die elke test op een blanco pagina heeft doorstaan, stopt met scannen op het moment dat deze in een echt document terechtkomt. Budgetteer de marge expliciet. Voordat u DrawBarcode aanroept, dient u ten minste tien modulebreedtes aan vrije ruimte aan beide zijden open te laten, en behandel elke afbeelding, lijn of tekst die in die band binnendringt als een defect, niet als een cosmetische keuze

Kleur, contrast en de voor mensen leesbare regel

De balk- en achtergrondkleuren bestaan zodat u deze kunt afstemmen op het kleurenpalet van een merk, en ze zijn de snelste manier om een werkende code te breken. Scanners lezen contrast, van oudsher met rood licht, en ze verwachten donkere balken op een licht veld. Zwart op wit is de enige combinatie waarnaar u zou moeten grijpen zonder te testen. Donkerblauw of donkergroen op wit kan slagen; alles met een laag luminantiecontrast, en met name rode balken, die een roodlicht-scanner als achtergrond ziet, zullen niet slagen. Als een ontwerper om gekleurde barcodes vraagt, is het eerlijke antwoord dat de balken zwart blijven en de kleur ergens anders op het label komt

Het DrawBarcode pad kan ook de voor mensen leesbare tekst onder de balken weergeven, de cijfers die een medewerker intypt wanneer een scan mislukt. Die tekst is een terugvaloptie, geen decoratie, dus als u uw eigen bijschrift plaatst, houd dit dan weg uit de rustzone; een label van de symbologie dat in de zijmarge is gepropt, doet de lege ruimte teniet waar de scanner afhankelijk van is. De velden in het voorbeeld hier, inclusief TextOut voor eventuele omringende labels, zijn dezelfde tekenaanroepen die worden behandeld in de report output guide, wat de plek is om naartoe te gaan wanneer de barcode één element is op een grotere, samengestelde pagina

Een korte verificatiegewoonte

Vectorbalken zijn een voordeel dat het benoemen waard is. Omdat DrawBarcode de code wegschrijft als PDF-tekenoperatoren in plaats van als een gerasterde afbeelding, blijven de balken haarscherp bij elke zoom en draagt het bestand geen eigen resolutie mee; de enige resolutie die ertoe doet, is die van de printer. Dat ontslaat u niet van de plicht om te testen, het betekent alleen dat de test op papier moet plaatsvinden. Genereer een proefexemplaar, print het op het apparaat met de laagste resolutie waar uw codes daadwerkelijk mee in aanraking zullen komen, en scan het met dezelfde klasse lezer die uw gebruikers vasthouden, niet de high-end imager op uw bureau. Controleer de rustzones met een liniaal op de print, bevestig dat de modulebreedte de reis van punten naar dots heeft overleefd, en verifieer dat de gedecodeerde waarde overeenkomt met wat u hebt gecodeerd, inclusief controlecijfer. Vijf minuten met een echte scanner spoort elke hierboven beschreven tekortkoming op, en dat nog voordat een pallet met verkeerd gelabelde voorraad dat doet

De hier getoonde DrawBarcode en DirectDrawBarcode methoden maken deel uit van de HotPDF Component voor Delphi en C++Builder