Articolo tecnico

Generare codici a barre scansionabili in PDF con HotPDF in Delphi

Un codice a barre non è un'immagine con cui decorare un documento. È una misurazione, e lo scanner è lo strumento che la legge. Questo cambio di prospettiva decide quasi tutto su come dovreste disegnarne uno in un PDF. Le barre non trasportano informazione con la loro nerezza; l'informazione vive nel rapporto tra le larghezze delle barre e le larghezze degli spazi, e un lettore la recupera cronometrando le transizioni mentre un laser o un sensore le attraversa. Comprimete quella geometria, sfocatela o affollatene i margini, e otterrete qualcosa che assomiglia esattamente a un codice a barre ma si scansiona come una sbavatura. HotPDF vi offre due modi per metterne uno su una pagina, e la differenza tra i due è precisamente la differenza tra controllare quella geometria e abbandonarla al caso

Una pagina PDF che mostra una griglia di codici a barre lineari in diverse simbologie disegnati da HotPDF in Delphi
Simbologie di codici a barre lineari disegnate in un unico PDF con HotPDF

Cosa può codificare HotPDF

HotPDF disegna simbologie lineari (monodimensionali), e l'insieme è più ampio di quanto la maggior parte dei progetti richieda. L'enumerazione THPDFBarcodeType copre la famiglia Code 2 of 5 nelle sue forme interleaved, industrial e matrix; Code 39 e la sua variante estesa; i tre sottoinsiemi di Code 128 A, B e C; Code 93 semplice ed esteso; MSI; PostNet; Codabar; il gruppo retail UPC ed EAN, ossia EAN-8, EAN-13, UPC-A, i compressi UPC-E0 e UPC-E1 e i supplementi UPC a 2 e 5 cifre; nonché i sottoinsiemi GS1-128 (EAN-128). È abbastanza da coprire le etichette della supply chain, i punti vendita retail e i vecchi codici industriali ancora vivi nei magazzini

Quello che non disegna è la famiglia bidimensionale. Qui non c'è QR, Data Matrix né PDF417. Quelli codificano byte in una griglia con una propria matematica di correzione degli errori, e se un requisito ne nomina uno, questo è lo strumento sbagliato ed è meglio saperlo prima di costruirci sopra piuttosto che dopo. Per i codici monodimensionali la domanda pratica è più ristretta: quale simbologia accetta i dati che avete realmente, perché le codifiche non sono intercambiabili

I vincoli sui dati sono reali e mordono al momento della generazione. Le varianti Code 2 of 5 e MSI accettano solo cifre. Code 39 trasporta lettere maiuscole, cifre e una manciata di segni di punteggiatura; se vi servono le minuscole o l'intera gamma ASCII, servono Code 39 Extended o un sottoinsieme di Code 128. Code 128C impacchetta due cifre in ogni simbolo per densità, quindi vuole una stringa numerica di lunghezza pari e nient'altro. EAN-13 si aspetta dodici cifre e calcola la tredicesima come controllo; EAN-8 ne attende sette e calcola l'ottava; UPC-A ne prende dodici. Passate a una simbologia dati che non può rappresentare e non otterrete un'eccezione utile, otterrete un codice a barre che codifica spazzatura, il che è peggio, perché sembra a posto finché qualcuno non lo scansiona a una cassa

Due percorsi di disegno, due livelli di controllo

Il metodo da preferire in produzione è DrawBarcode, sull'oggetto pagina. Accetta la simbologia, una posizione, un'altezza e un parametro che conta più degli altri: MUnit, la larghezza del modulo. Il modulo è la larghezza della barra più stretta, l'atomo di cui ogni altra misura nel codice è un multiplo, e qui è espresso in punti. Tutto ciò che determina se il risultato stampato si scansiona risale a quel singolo intero

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;

Due argomenti meritano uno sguardo più attento. UseCheckSum aggiunge la cifra di controllo modulo-10 che la simbologia si aspetta, e per i codici retail lo volete quasi sempre True; disattivatelo solo quando i vostri dati contengono già un controllo precalcolato, altrimenti otterrete una cifra duplicata. I colori di barre e sfondo sono gli ultimi due parametri, e la tentazione di essere creativi lì è una trappola discussa più avanti. Notate anche l'origine delle coordinate: come ogni altra chiamata di disegno in HotPDF, X e Y si misurano dall'angolo inferiore sinistro della pagina in punti, con Y crescente verso l'alto, la stessa convenzione illustrata nell'esempio Hello World

Il secondo percorso è DirectDrawBarcode, che accetta i dati e un riquadro di delimitazione, X, Y, Width, Height, e scala il pattern di barre per riempire quella larghezza. È comodo per disporre codici su una griglia perché indicate l'ingombro e il metodo vi adatta le barre. Quella comodità è anche il suo pericolo. Quando gli date una larghezza, non state più impostando la dimensione del modulo; il metodo divide lo spazio che concedete tra quante barre servono ai dati, e la barra più stretta diventa quel che risulta da quella divisione. Chiedete una stringa Code 128 densa dentro un riquadro troppo stretto e i moduli si rimpiccioliscono sotto ciò che qualsiasi scanner può risolvere, silenziosamente. Per tutto ciò che deve scansionarsi in modo affidabile, preferite DrawBarcode e impostate MUnit deliberatamente. Riservate DirectDrawBarcode alle anteprime e alle disposizioni in cui avete misurato che le barre risultanti restano leggibili

La larghezza del modulo è una decisione di risoluzione

Ecco l'aritmetica che determina se la vostra etichetta funziona. Uno scanner laser e una fotocamera hanno entrambi una caratteristica minima che riescono a distinguere, e la barra stretta deve collocarsi comodamente al di sopra di essa dopo la stampa. Il limite inferiore citato più spesso per i codici lineari di uso generale è una barra stretta da 13 mil, circa 0,33 mm, e molte guide retail e industriali lo trattano come un minimo piuttosto che come un obiettivo. Traducetelo in unità PDF: un punto è 1/72 di pollice, circa 0,353 mm, quindi un singolo punto di larghezza del modulo si trova proprio su quel limite. Ecco perché MUnit := 1 è il valore più piccolo di cui dovreste fidarvi per un codice destinato a uno scanner reale, e perché raddoppiarlo a 2 compra un margine che non costa quasi nulla su un'etichetta con spazio da vendere

Ora collegate questo alla risoluzione di output, perché il modulo deve anche sopravvivere alla stampante. Su una stampante laser a 300 DPI un punto del dispositivo è 1/300 di pollice, quindi un modulo da un punto è largo circa quattro punti dispositivo. Quattro punti sono appena sufficienti a rendere un bordo pulito; la diffusione del toner e un leggero errore di registrazione lo erodono, e la barra che misurava un punto nel vostro PDF si stampa più grassa o più magra di quanto la specifica consenta. Alzate il modulo a 2 punti e avete otto punti dispositivo con cui lavorare, il che assorbe quel rumore. La regola da interiorizzare: la larghezza del modulo che impostate in punti deve corrispondere a un numero intero e comodo di punti del dispositivo alla vostra reale risoluzione di stampa, non alla risoluzione che vorreste avere. Un codice che si scansiona impeccabilmente sullo schermo e fallisce sulla stampante del magazzino quasi sempre ha fallito questa verifica

La zona di quiete fa parte del simbolo

La ragione singola più comune per cui un codice a barre correttamente codificato non si scansiona è la zona di quiete, il margine bianco su ciascun lato delle barre. Gli scanner usano quel vuoto per individuare dove il codice inizia e finisce; senza di esso, il lettore non può distinguere la prima barra da qualsiasi cosa le stia accanto sulla pagina. Gli standard sono specifici. La maggior parte delle simbologie lineari vuole una zona di quiete di almeno dieci volte la larghezza del modulo su ciascun lato, e i codici retail UPC ed EAN richiedono nove moduli a sinistra e sette a destra. Con un modulo da un punto sono circa dieci punti, circa un settimo di pollice, di spazio bianco garantito ai fianchi delle barre

HotPDF disegna le barre e nient'altro. Non riserva la zona di quiete per voi, il che significa che la responsabilità è vostra ed è facile dimenticarsene. La modalità di fallimento è subdola: piazzate un codice a barre a filo del bordo di una cella di tabella, o lasciate che il layout della pagina gli accosti un logo, e il codice che superava ogni test su una pagina bianca smette di scansionarsi nel momento in cui viene spedito dentro un documento reale. Preventivate il margine esplicitamente. Prima di chiamare DrawBarcode, lasciate almeno dieci larghezze di modulo di spazio libero su entrambi i lati, e trattate qualsiasi grafica, filetto o testo che invada quella fascia come un difetto, non come una scelta estetica

Colore, contrasto e la riga leggibile dall'uomo

I colori di barre e sfondo esistono perché possiate abbinare una palette di brand, e sono il modo più rapido per rompere un codice funzionante. Gli scanner leggono il contrasto, classicamente con luce rossa, e si aspettano barre scure su campo chiaro. Nero su bianco è l'unica combinazione da usare senza test. Blu scuro o verde scuro su bianco possono passare; qualsiasi cosa con basso contrasto di luminanza, e in particolare le barre rosse, che uno scanner a luce rossa vede come sfondo, no. Se un designer chiede codici a barre colorati, la risposta onesta è che le barre restano nere e il colore va da qualche altra parte sull'etichetta

Il percorso DrawBarcode può anche rendere il testo leggibile dall'uomo sotto le barre, le cifre che un addetto digita quando una scansione fallisce. Quel testo è un ripiego, non una decorazione, quindi quando posizionate una didascalia vostra tenetela lontana dalla zona di quiete; un'etichetta della simbologia stipata nel margine laterale vanifica lo stesso spazio bianco da cui lo scanner dipende. I campi dell'esempio qui, incluso TextOut per eventuali etichette circostanti, sono le stesse chiamate di disegno trattate nella guida all'output di report, che è il posto dove andare quando il codice a barre è un elemento in una pagina composita più ampia

Una breve abitudine di verifica

Le barre vettoriali sono un vantaggio che vale la pena nominare. Poiché DrawBarcode scrive il codice come operatori di disegno PDF anziché come immagine rasterizzata, le barre restano nitide a qualsiasi zoom e il file non porta con sé alcuna risoluzione propria; l'unica risoluzione che conta è quella della stampante. Questo non vi esonera dai test, significa solo che il test deve avvenire su carta. Generate un campione, stampatelo sul dispositivo a risoluzione più bassa che i vostri codici incontreranno davvero e scansionatelo con la stessa classe di lettore che i vostri utenti hanno in mano, non con l'imager di fascia alta sulla vostra scrivania. Controllate le zone di quiete con un righello sulla stampa, confermate che la larghezza del modulo sia sopravvissuta al viaggio dai punti ai punti dispositivo e verificate che il valore decodificato corrisponda a ciò che avete codificato, cifra di controllo compresa. Cinque minuti con uno scanner reale intercettano ogni fallimento descritto sopra, e li intercettano prima che lo faccia un pallet di merce etichettata male

I metodi DrawBarcode e DirectDrawBarcode mostrati qui fanno parte del HotPDF Component per Delphi e C++Builder