Čárový kód není žádný obrázek, kterým byste měli dekorovat dokument. Jde o měrný prvek a skener je v tomto případě měřicím přístrojem, který ho čte. Tohle přerámování uvažování rozhoduje zhruba o všem okolo otázky, jak takový kód správně zakreslit do PDF. Samotné čáry nenesou informaci prostřednictvím své černé barvy; informace přežívá uvnitř poměru šířky pruhu k šířce mezery a čtečka ji obnovuje načasováním přechodů v okamžiku, kdy její laser nebo senzor čárový kód přeletí (sweeps across). Pokřivte takovou geometrii, rozmázněte ji nebo ucpěte její okolní okraje a vyprodukujete něco, co sice vypadá přesně jako čárový kód, ale co se skenuje jako pouhá šmouha. HotPDF vám podává k vložení kódu na stránku hned dvě cesty. Rozdíl mezi nimi tkví právě v rozdílu mezi tím, zda máte takovou geometrii plně pod kontrolou, nebo jestli se jí dobrovolně vzdáváte

Co umí HotPDF kódovat
HotPDF kreslí lineární (jednorozměrné) symbologie a celý tento okruh možností je vlastně daleko širší, než kolik toho většina projektů kdy potřebuje. Výčet z THPDFBarcodeType pokrývá celou rodinu Code 2 of 5 ve své prokládané (interleaved), průmyslové (industrial) i maticové (matrix) variantě; Code 39 a jeho rozšířenou variantu (extended); rovnou tři podsady Code 128 (A, B a C); Code 93 v základní i rozšířené formě; MSI; PostNet; Codabar; celou retailovou UPC a EAN skupinu kódů – tedy konkrétně EAN-8, EAN-13, UPC-A, komprimované formáty UPC-E0 s UPC-E1 a také rozšiřující doplňky UPC s 2- i 5-cifernými add-ony; nakonec pak rovněž GS1-128 (předtím známé jako EAN-128) podsady. Toto množství dostačuje pro pokrytí dodavatelských řetězců na štítcích, prodejní pozice na pokladně (POS) i prastaré průmyslové kódy stále křižující skladovými halami
Tato verze ovšem nevykresluje (does not draw) dvojrozměrnou (2D) rodinu kódů. Nenajdete zde žádný QR, Data Matrix ani PDF417. Tyto systémy kódují bajty uvnitř mřížky se svojí vlastní matematikou pro opravu chyb a pokud některá z podmínek a požadavků výslovně některý z nich zmiňuje, držíte k tomu špatný nástroj, o čemž je lepší se přesvědčit raději už předtím, než okolo toho vše stavět a zjistit to až nakonec. Pro jednorozměrné verze (one-dimensional codes) se praktická palčivá otázka smrskne k daleko užší definici: jaká ze symbologií vlastně zvládne přijmout vámi podávaná vstupní reálná data, jelikož se formáty zakódování samotných kódů (encodings) zkrátka navzájem nahradit nedají
Tato datová omezení jsou skutečná a začnou kousat v době generování. Varianty Code 2 of 5 a MSI berou pouze číslice. Code 39 zvládá velká písmena, číslice a hrstku interpunkčních znamének; pokud potřebujete malá písmena nebo celý rozsah ASCII, je k tomu Code 39 Extended nebo některá z podsad Code 128. Code 128C pro dosažení hustoty balí do každého symbolu dvě číslice, takže požaduje numerický řetězec o sudé délce a nic jiného. EAN-13 očekává dvanáct číslic a třináctou vypočítá jako kontrolní; EAN-8 očekává sedm a počítá osmou; UPC-A bere dvanáct. Předáte-li symbologii data, která neumí reprezentovat, nedostanete užitečnou výjimku, ale čárový kód zakódovaný do nesmyslů (garbage), což je mnohem horší. Na pohled totiž vypadá naprosto v pořádku, a to až do chvíle, kdy ho někdo zkusí naskenovat na pokladně
Dvě cesty kreslení, dvě úrovně kontroly
Metodou, po které byste měli v produkci sáhnout, je DrawBarcode na objektu stránky. Bere si za parametry symbologii, pozici, výšku a ještě jeden parametr, na kterém záleží víc než na všech ostatních dohromady: MUnit, čili šířku modulu. Modul je šířka té nejužší čáry – onen atom, jehož násobkem je v daném kódu každá další míra. Je vyjádřený v bodech (points). Vše ohledně toho, zda se vytištěný výsledek podaří naskenovat, se sbíhá právě k tomuto jedinému číslu
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;
Dva parametry si zaslouží bližší pohled. UseCheckSum na konec připojí kontrolní číslici modulo 10, kterou symbologie očekává, a u maloobchodních (retail) kódů tuto volbu budete mít téměř vždy nastavenou na True; vypínejte to pouze v případě, že vaše data už předem vypočítanou kontrolní číslici nesou, jinak na konci dostanete obě číslice zdvojené. Barva čárového kódu a pozadí jsou posledními dvěma parametry, přičemž pokušení být v tomto směru nějak kreativní představuje past, o které se pobavíme níže. Všimněte si také počátku souřadnic: stejně jako u každého jiného kreslicího volání v HotPDF se souřadnice X a Y odměřují od levého dolního rohu stránky v bodech, přičemž hodnota Y stoupá směrem nahoru – je to tedy stejná konvence, kterou prochází Hello World ukázka
Druhou cestou je metoda DirectDrawBarcode. Bere data a ohraničující box s hodnotami X, Y, Width, Height (šířka a výška), načež celý vzor kódových čar po přeškálování napasuje tak, aby vyplnil zadanou šířku. Je to velmi pohodlné pro rozmisťování kódů po mřížce (grid), protože pojmenujete celkový otisk pro zabrání místa a metoda se postará o vměstnání čar přímo dovnitř. Z této pohodlnosti ale pramení ono skryté nebezpečí. Když určujete pevnou šířku, už nenastavujete velikost modulu; metoda jakýkoli vámi povolený prostor rozdělí mezi jakékoli množství potřebných čar vynucených pro vkládaná data. Nejužší čárou se tak stane to, co jednoduše z takového dělení vypadne. Pokud si vyžádáte nahuštěný řetězec v Code 128 uvnitř příliš úzkého boxu, moduly se zcela potichu smrsknou pod hranici toho, co vůbec dokáže nějaký skener rozlišit. Pro cokoli, co se musí dát spolehlivě naskenovat, proto vždy preferujte DrawBarcode a hodnotu MUnit nastavujte s rozmyslem a záměrně. Metodu DirectDrawBarcode si raději šetřete pro náhledy (previews) a pro uspořádání, kde už máte přesně změřeno, že výsledné vykreslené čáry zůstanou čitelné
Šířka modulu je otázkou rozlišení
Tady je aritmetika, která určuje, zda váš štítek bude fungovat. Jak laserový skener, tak fotoaparát mají zkrátka určitý nejmenší detail (feature), který dokážou rozlišit. Úzká čára musí po svém vytištění bezpečně (comfortably) přistát nad touto hodnotou. Široce citované dno pro lineární kódy pro všeobecné použití je úzká čára o velikosti 13 mil, což je zhruba 0,33 mm, a řada maloobchodních i průmyslových manuálů s tímto údajem zachází spíše jako s naprostým minimem, než aby to byl cílový stav. Pokud si to převedeme do jednotek PDF: jeden bod (point) je 1/72 palce, tedy zhruba 0,353 mm. Šířka modulu na jediný bod se tak nachází přesně na samé hranici tohoto dna. Právě proto je MUnit := 1 vůbec tou nejmenší možnou hodnotou, které byste měli u kódu určeného pro reálný skener ještě věřit, a proč její případné zdvojnásobení na hodnotu 2 představuje obrovskou rezervu, jež vás navíc na štítku, který má nějaký prostor nazbyt, nebude téměř nic stát
Nyní to propojte s výstupním rozlišením, protože modul musí samozřejmě přežít i tiskárnu. Na laserové tiskárně s 300 DPI má jedna hardwarová (device) tečka velikost 1/300 palce, takže jednobodový modul má šířku zhruba čtyř takových teček. Čtyři tečky sotva stačí na vykreslení čisté hrany; rozpíjení toneru (toner spread) a drobné chyby z pasování u tisku (registration error) z toho ještě ukousnou. Čára, která ve vašem PDF měřila přesně jeden bod, se pak na papíře vytiskne zkrátka o něco tlustší nebo tenčí, než norma povoluje. Zvětšete modul na 2 body a získáte na práci osm teček, čímž už podobný šum bez potíží absorbujete. Pravidlo, které stojí za to si zvnitřnit, je proto následující: šířka modulu (v bodech), kterou nastavíte, se musí na vašem skutečném tiskovém rozlišení (nikoli tom vytouženém, ale reálném) namapovat na zcela celé a pohodlné číslo tiskových (device) teček. Kód, který se perfektně naskenuje na obrazovce (off the screen) a naopak selže u vytištěného dokladu ze skladové tiskárny (off the warehouse printer), totiž doplatil v drtivé většině případů přesně na opomenutí této jediné kontroly
Ochranná zóna je pevnou součástí symbolu
Tím naprosto nejčastějším důvodem, proč se i správně zakódovaný čárový kód zkrátka nenaskenuje, bývá ochranná zóna (quiet zone) – ten prázdný okraj ležící na obou stranách daných čar. Skenery tuto prázdnotu přímo používají ke zjištění, kde vlastně kód začíná a kde končí; bez toho čtečka nedokáže rozeznat první čáru od všeho, co zrovna sedí hned vedle ní na vytištěné stránce. Standardy hovoří velmi konkrétně. Většina lineárních symbologií vyžaduje ochrannou zónu o velikosti minimálně desetkrát šířky modulu (module width) z obou stran. Maloobchodní UPC a EAN kódy volají po devíti modulech nalevo a sedmi napravo. S použitím jednobodového (one-point) modulu to představuje zhruba deset bodů (points), tedy necelou sedminu palce garantovaného bílého prázdného prostoru, z něhož čáry bezpečně vystupují (flanking)
HotPDF kreslí čistě jenom čáry a nic víc. Ochrannou zónu za vás nijak nerezervuje, což znamená, že zodpovědnost za ni plně přebíráte vy – a velmi snadno se na to zapomíná. Režim selhání bývá nenápadný: položíte čárový kód zarovnaný přímo k okraji tabulkové buňky, nebo necháte stránkové rozvržení, ať k němu těsně přitiskne logo. Kód, který na prázdné zkušební stránce prošel úplně každým testem, tak rázem přestane fungovat v okamžiku, kdy je vyexpedován jako součást reálného finálního dokumentu. Počítejte proto s tímto rozpočtem pro okraj výslovně a předem. Než zavoláte metodu DrawBarcode, nechejte po obou stranách kódu čistý prostor alespoň pro deset šířek modulu. S jakoukoli grafikou, linkou (rule) nebo textem, jež do tohoto vyhrazeného pruhu vnikne (intrudes into that band), pak zkrátka zacházejte jako s defektem – nikoli jako s jakousi kosmetickou volbou designu
Barva, kontrast a řádek pro lidi
Barva čáry a pozadí tu existují od toho, abyste mohli vyhovět firemní paletě barev. Jsou zároveň i tou vůbec nejrychlejší cestou, jak naprosto rozbít doteď dokonale fungující kód. Skenery spoléhají při čtení na kontrast, klasicky využívají červeného světla a celkově očekávají tmavé čáry na světlém poli. Černá na bílé je tou jedinou kombinací, po které byste měli zcela bez obav a jakéhokoli testování sahat. Tmavě modrá nebo tmavě zelená na bílé umí jakžtakž projít (can pass). Cokoliv s nízkým jasovým kontrastem (low luminance contrast), a zvláště pak pakety s červenými čarami – které skener s červeným světlem pochopitelně vnímá zkrátka jako součást pozadí (sees as background) – ty naopak neprojdou. Pokud si designér vyžádá obarvené čárové kódy, zní upřímná odpověď tak, že samotné čáry zůstanou černé a barvy musí jít prostě někam jinam na onom štítku
Metoda DrawBarcode dokáže rovněž sama vypsat onen člověku čitelný (human-readable) text přímo pod čárami. Jsou to přesně ty číslice, které prodavač naťuká na pokladně ve chvíli, kdy čtečka zrovna selže. Tento text plní funkci ústupového či záchranného (fallback) řešení, nejedná se o žádnou ozdobu (decoration). Takže pokud si rozmisťujete vlastní popisky u vizuálu a okrajů, udržujte je bezpečně pryč od samotné ochranné zóny. Pouhý název (label) příslušné symbologie nacpaný (crammed) do postranního okraje totiž okamžitě boří přesně tentýž prázdný prostor, na němž samotný skener pro svou správnou funkčnost tak pevně závisí. Pole v naší ukázce, a to včetně TextOut určeného pro libovolné okolní obklopující (surrounding) popisky, jsou naprosto ta stejná volání pro kreslení, jež probíráme v průvodci pro reportové (report) výstupy. To je totiž přesně to místo, kam byste měli nahlédnout, pokud je čárový kód jen jedním z dalších prvků usazených na daleko větší sestavované a rozvržené (composed) stránce
Drobný zvyk okolo ověřování
Vektorové zobrazení čar představuje výhodu, kterou určitě stojí za to jmenovat. Vzhledem k tomu, že DrawBarcode zapisuje kód přímo pomocí kreslicích (drawing) PDF operátorů, a nikoli jako obyčejný rastrovaný obrázek, zůstávají čáry naprosto ostré při libovolném (at any zoom) přiblížení a samotný soubor v sobě nenese žádné vlastní rozlišení; jediné rozlišení, na kterém doopravdy záleží, je to tiskárnino. To vás ovšem nijak nezbavuje ani neomlouvá (does not excuse you) od testování, jen to prostě znamená, že takový test se musí nevyhnutelně odehrát (happen) až na papíře. Vygenerujte si tedy nejprve ukázku (sample), vytiskněte ji pod tím úplně nejnižším (lowest-resolution) rozlišením, k jakému se u používaných tiskáren vůbec dostanete, a naskenujte ji naprosto stejnou třídou skenovacích čteček, jaké drží v ruce vaši klienti – nikoli vaší špičkovou kamerou a čtečkou, kterou si vy osobně hýčkáte u sebe na stole. Překontrolujte ochranné zóny pouhým pravítkem na výtisku, potvrďte si, že šířka navoleného modulu s přehledem přežila celou tu cestu na transformaci z bodů k tiskovým tečkám, a ověřte taktéž navíc dekódovanou získanou hodnotu proti navolené při kódování, kontrolní číslici i vše ostatní se vším všudy. Pouhých pět minut se skutečným skenerem rovnou podchytí přesně všechna ta selhání vyjmenovaná nahoře a zachytí je ještě předtím, než to udělá až na chodbě paleta (pallet) špatně označeného zboží (stock)
Volání metod DrawBarcode a DirectDrawBarcode zobrazená výše jsou součástí komponenty HotPDF pro Delphi a C++Builder