Τεχνικό Άρθρο

Σαρώσιμοι γραμμωτοί κώδικες σε PDF με το HotPDF στη Delphi

Ένας γραμμωτός κώδικας δεν είναι εικόνα με την οποία διακοσμείτε ένα έγγραφο. Είναι μια μέτρηση, και ο σαρωτής είναι το όργανο που τη διαβάζει. Αυτή η επαναδιατύπωση κρίνει σχεδόν τα πάντα για το πώς πρέπει να τον σχεδιάσετε μέσα σε ένα PDF. Οι γραμμές δεν μεταφέρουν πληροφορία με τη μαυρίλα τους· η πληροφορία ζει στον λόγο των πλατών των γραμμών προς τα πλάτη των κενών, και ένας αναγνώστης την ανακτά χρονομετρώντας τις μεταβάσεις καθώς ένα λέιζερ ή ένας αισθητήρας σαρώνει κατά μήκος. Στριμώξτε αυτή τη γεωμετρία, θολώστε την ή στοιβάξτε πράγματα στα περιθώριά της, και παράγετε κάτι που μοιάζει ακριβώς με γραμμωτό κώδικα και σαρώνεται σαν μουτζούρα. Το HotPDF σας δίνει δύο τρόπους να βάλετε έναν σε μια σελίδα, και η διαφορά τους είναι ακριβώς η διαφορά ανάμεσα στο να ελέγχετε αυτή τη γεωμετρία και στο να την παραδίδετε

Μια σελίδα PDF που δείχνει ένα πλέγμα γραμμικών κωδίκων σε διαφορετικές συμβολολογίες σχεδιασμένων από το HotPDF σε Delphi
Συμβολολογίες γραμμικών κωδίκων σχεδιασμένες σε ένα ενιαίο PDF με το HotPDF

Τι μπορεί να κωδικοποιήσει το HotPDF

Το HotPDF σχεδιάζει γραμμικές (μονοδιάστατες) συμβολολογίες, και το σύνολο είναι ευρύτερο από όσο χρειάζονται τα περισσότερα έργα. Η απαρίθμηση THPDFBarcodeType καλύπτει την οικογένεια Code 2 of 5 στις μορφές interleaved, industrial και matrix· το Code 39 και την εκτεταμένη παραλλαγή του· τα τρία υποσύνολα A, B και C του Code 128· το Code 93 απλό και εκτεταμένο· το MSI· το PostNet· το Codabar· την ομάδα λιανικής UPC και EAN, δηλαδή τα EAN-8, EAN-13, UPC-A, τα συμπιεσμένα UPC-E0 και UPC-E1, και τα συμπληρωματικά UPC των 2 και 5 ψηφίων· και τα υποσύνολα GS1-128 (EAN-128). Αυτό αρκεί για ετικέτες εφοδιαστικής αλυσίδας, σημεία πώλησης λιανικής και τους παλαιότερους βιομηχανικούς κώδικες που ζουν ακόμη στις αποθήκες

Αυτό που δεν σχεδιάζει είναι η δισδιάστατη οικογένεια. Δεν υπάρχει εδώ QR, Data Matrix ή PDF417. Εκείνοι κωδικοποιούν bytes σε πλέγμα με δικά τους μαθηματικά διόρθωσης σφαλμάτων, και αν μια απαίτηση κατονομάζει κάποιον από αυτούς, αυτό είναι λάθος εργαλείο και καλό είναι να το ξέρετε πριν χτίσετε γύρω του και όχι μετά. Για τους μονοδιάστατους κώδικες το πρακτικό ερώτημα είναι στενότερο: ποια συμβολολογία δέχεται τα δεδομένα που πραγματικά έχετε, επειδή οι κωδικοποιήσεις δεν είναι εναλλάξιμες

Οι περιορισμοί δεδομένων είναι υπαρκτοί και δαγκώνουν τη στιγμή της παραγωγής. Οι παραλλαγές Code 2 of 5 και το MSI δέχονται μόνο ψηφία. Το Code 39 μεταφέρει κεφαλαία γράμματα, ψηφία και μια χούφτα σημεία στίξης· αν χρειάζεστε πεζά ή ολόκληρο το εύρος ASCII, αυτό είναι δουλειά του Code 39 Extended ή ενός υποσυνόλου Code 128. Το Code 128C στοιβάζει δύο ψηφία σε κάθε σύμβολο για πυκνότητα, οπότε θέλει αριθμητική συμβολοσειρά άρτιου μήκους και τίποτα άλλο. Το EAN-13 περιμένει δώδεκα ψηφία και υπολογίζει το δέκατο τρίτο ως έλεγχο· το EAN-8 περιμένει επτά και υπολογίζει το όγδοο· το UPC-A παίρνει δώδεκα. Δώστε σε μια συμβολολογία δεδομένα που δεν μπορεί να αναπαραστήσει και δεν παίρνετε μια χρήσιμη εξαίρεση, παίρνετε έναν γραμμωτό κώδικα που κωδικοποιεί σκουπίδια, πράγμα χειρότερο, επειδή δείχνει μια χαρά μέχρι να τον σαρώσει κάποιος σε ένα ταμείο

Δύο διαδρομές σχεδίασης, δύο επίπεδα ελέγχου

Η μέθοδος για την οποία απλώνετε το χέρι στην παραγωγή είναι η DrawBarcode, πάνω στο αντικείμενο σελίδας. Δέχεται τη συμβολολογία, μια θέση, ένα ύψος, και μία παράμετρο που μετράει περισσότερο από τις υπόλοιπες: το MUnit, το πλάτος του module. Το module είναι το πλάτος της στενότερης γραμμής, το άτομο του οποίου πολλαπλάσιο είναι κάθε άλλο μέτρο του κώδικα, και εκφράζεται εδώ σε σημεία. Οτιδήποτε αφορά το αν το τυπωμένο αποτέλεσμα σαρώνεται ανάγεται σε αυτόν τον έναν ακέραιο

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

    // BCType, X, Y, Height, MUnit (πλάτος module σε σημεία), γωνία,
    // δεδομένα, UseCheckSum, χρώμα γραμμών, χρώμα φόντου.
    Pdf.CurrentPage.DrawBarcode(
      bcCodeEAN13,           // συμβολολογία
      72, 680,               // X, Y σε σημεία από την κάτω αριστερή γωνία
      60,                    // ύψος γραμμών
      1,                     // MUnit: στενότερη γραμμή 1pt
      0,                     // χωρίς περιστροφή
      '123456789012',        // 12 ψηφία, το 13ο είναι ο έλεγχος
      True,                  // προσάρτηση του ψηφίου ελέγχου modulo-10
      clBlack, clWhite);     // γραμμές μαύρες, φόντο λευκό

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

Δύο ορίσματα αξίζουν πιο προσεκτικό βλέμμα. Το UseCheckSum προσαρτά το ψηφίο ελέγχου modulo-10 που περιμένει η συμβολολογία, και για τους κώδικες λιανικής σχεδόν πάντα το θέλετε True· απενεργοποιήστε το μόνο όταν τα δεδομένα σας κουβαλούν ήδη προϋπολογισμένο έλεγχο, αλλιώς θα πάρετε διπλό ψηφίο. Τα χρώματα γραμμών και φόντου είναι οι δύο τελευταίες παράμετροι, και ο πειρασμός να γίνετε δημιουργικοί εκεί είναι παγίδα που συζητείται παρακάτω. Σημειώστε επίσης την αρχή των συντεταγμένων: όπως κάθε άλλη κλήση σχεδίασης στο HotPDF, τα X και Y μετρώνται από την κάτω αριστερή γωνία της σελίδας σε σημεία, με το Y να μεγαλώνει προς τα πάνω, η ίδια σύμβαση που διατρέχει το παράδειγμα Hello World

Η δεύτερη διαδρομή είναι η DirectDrawBarcode, η οποία δέχεται τα δεδομένα και ένα πλαίσιο οριοθέτησης, X, Y, Width, Height, και κλιμακώνει το μοτίβο γραμμών ώστε να γεμίσει αυτό το πλάτος. Είναι βολική για τη διάταξη κωδίκων σε πλέγμα, επειδή εσείς ονομάζετε το αποτύπωμα και η μέθοδος ταιριάζει τις γραμμές μέσα σε αυτό. Αυτή η βολικότητα είναι και ο κίνδυνός της. Όταν της δίνετε πλάτος, δεν ορίζετε πια το μέγεθος του module· η μέθοδος μοιράζει όσο χώρο επιτρέπετε ανάμεσα σε όσες γραμμές χρειάζονται τα δεδομένα, και η στενότερη γραμμή γίνεται ό,τι προκύψει από αυτή τη διαίρεση. Ζητήστε μια πυκνή συμβολοσειρά Code 128 μέσα σε πολύ στενό πλαίσιο και τα modules συρρικνώνονται κάτω από όσο μπορεί να διακρίνει οποιοσδήποτε σαρωτής, σιωπηλά. Για οτιδήποτε πρέπει να σαρώνεται αξιόπιστα, προτιμήστε το DrawBarcode και ορίστε το MUnit συνειδητά. Κρατήστε το DirectDrawBarcode για προεπισκοπήσεις και για διατάξεις όπου έχετε μετρήσει ότι οι γραμμές που προκύπτουν παραμένουν ευανάγνωστες

Το πλάτος του module είναι απόφαση ανάλυσης

Να η αριθμητική που κρίνει αν η ετικέτα σας δουλεύει. Ένας σαρωτής λέιζερ και μια κάμερα έχουν και οι δύο ένα ελάχιστο χαρακτηριστικό που μπορούν να ξεχωρίσουν, και η στενή γραμμή πρέπει να προσγειώνεται άνετα πάνω από αυτό μετά την εκτύπωση. Το ευρέως αναφερόμενο κατώφλι για γραμμικούς κώδικες γενικής χρήσης είναι στενή γραμμή 13 mil, περίπου 0,33 mm, και πολλοί οδηγοί λιανικής και βιομηχανίας το αντιμετωπίζουν ως ελάχιστο και όχι ως στόχο. Μεταφράστε το σε μονάδες PDF: ένα σημείο είναι 1/72 της ίντσας, περίπου 0,353 mm, οπότε ένα μόνο σημείο πλάτους module κάθεται ακριβώς πάνω σε αυτό το κατώφλι. Γι αυτό το MUnit := 1 είναι η μικρότερη τιμή που πρέπει να εμπιστεύεστε για κώδικα που προορίζεται για πραγματικό σαρωτή, και γι αυτό ο διπλασιασμός του στο 2 αγοράζει περιθώριο που δεν κοστίζει σχεδόν τίποτα σε μια ετικέτα με χώρο να διαθέσει

Τώρα συνδέστε το με την ανάλυση εξόδου, επειδή το module πρέπει επίσης να επιβιώσει από τον εκτυπωτή. Σε έναν εκτυπωτή λέιζερ 300 DPI μία κουκκίδα συσκευής είναι 1/300 της ίντσας, οπότε ένα module του ενός σημείου έχει πλάτος περίπου τέσσερις κουκκίδες. Τέσσερις κουκκίδες μόλις που φτάνουν για να αποδοθεί καθαρή ακμή· η εξάπλωση του τόνερ και μικρό σφάλμα ευθυγράμμισης τρώνε από αυτές, και η γραμμή που μετρούσε ένα σημείο στο PDF σας τυπώνεται παχύτερη ή λεπτότερη από όσο επιτρέπει η προδιαγραφή. Ανεβάστε το module στα 2 σημεία και έχετε οκτώ κουκκίδες να δουλέψετε, που απορροφούν αυτόν τον θόρυβο. Ο κανόνας που αξίζει να εσωτερικεύσετε: το πλάτος module που ορίζετε σε σημεία πρέπει να αντιστοιχεί σε ακέραιο, άνετο αριθμό κουκκίδων συσκευής στην πραγματική σας ανάλυση εκτύπωσης, όχι στην ανάλυση που θα θέλατε να είχατε. Ένας κώδικας που σαρώνεται άψογα από την οθόνη και αποτυγχάνει από τον εκτυπωτή της αποθήκης σχεδόν πάντα απέτυχε σε αυτόν τον έλεγχο

Η ήσυχη ζώνη είναι μέρος του συμβόλου

Ο πιο συνηθισμένος λόγος που ένας σωστά κωδικοποιημένος γραμμωτός κώδικας δεν σαρώνεται είναι η ήσυχη ζώνη, το κενό περιθώριο σε κάθε πλευρά των γραμμών. Οι σαρωτές χρησιμοποιούν αυτό το κενό για να βρουν πού αρχίζει και πού τελειώνει ο κώδικας· χωρίς αυτό, ο αναγνώστης δεν μπορεί να ξεχωρίσει την πρώτη γραμμή από ό,τι κάθεται δίπλα της στη σελίδα. Τα πρότυπα είναι συγκεκριμένα. Οι περισσότερες γραμμικές συμβολολογίες θέλουν ήσυχη ζώνη τουλάχιστον δεκαπλάσια του πλάτους module σε κάθε πλευρά, και οι κώδικες λιανικής UPC και EAN ζητούν εννέα modules αριστερά και επτά δεξιά. Με module του ενός σημείου αυτό είναι περίπου δέκα σημεία, περίπου ένα έβδομο της ίντσας, εγγυημένου λευκού χώρου εκατέρωθεν των γραμμών

Το HotPDF σχεδιάζει τις γραμμές και τίποτε άλλο. Δεν κρατά την ήσυχη ζώνη για λογαριασμό σας, πράγμα που σημαίνει ότι η ευθύνη είναι δική σας και ξεχνιέται εύκολα. Ο τρόπος αστοχίας είναι λεπτός: τοποθετείτε έναν γραμμωτό κώδικα κολλητά σε ένα περίγραμμα κελιού πίνακα, ή αφήνετε τη διάταξη της σελίδας να στριμώξει ένα λογότυπο δίπλα του, και ο κώδικας που πέρασε κάθε δοκιμή σε λευκή σελίδα σταματά να σαρώνεται τη στιγμή που φεύγει μέσα σε πραγματικό έγγραφο. Προϋπολογίστε ρητά το περιθώριο. Πριν καλέσετε το DrawBarcode, αφήστε τουλάχιστον δέκα πλάτη module ελεύθερου χώρου και στις δύο πλευρές, και θεωρήστε κάθε γραφικό, γραμμή ή κείμενο που εισβάλλει σε αυτή τη ζώνη ελάττωμα, όχι αισθητική επιλογή

Χρώμα, αντίθεση και η ανθρωπίνως αναγνώσιμη γραμμή

Τα χρώματα γραμμών και φόντου υπάρχουν για να ταιριάζετε μια παλέτα μάρκας, και είναι ο ταχύτερος τρόπος να χαλάσετε έναν κώδικα που δουλεύει. Οι σαρωτές διαβάζουν αντίθεση, κλασικά με κόκκινο φως, και περιμένουν σκούρες γραμμές πάνω σε ανοιχτόχρωμο πεδίο. Το μαύρο στο λευκό είναι ο μόνος συνδυασμός για τον οποίο μπορείτε να απλώσετε το χέρι χωρίς δοκιμή. Το σκούρο μπλε ή το σκούρο πράσινο στο λευκό μπορεί να περάσουν· οτιδήποτε με χαμηλή φωτεινοτική αντίθεση, και ιδίως κόκκινες γραμμές, τις οποίες ένας σαρωτής κόκκινου φωτός βλέπει ως φόντο, δεν θα περάσει. Αν κάποιος σχεδιαστής ζητήσει έγχρωμους γραμμωτούς κώδικες, η ειλικρινής απάντηση είναι ότι οι γραμμές μένουν μαύρες και το χρώμα πάει κάπου αλλού στην ετικέτα

Η διαδρομή του DrawBarcode μπορεί επίσης να αποδώσει το ανθρωπίνως αναγνώσιμο κείμενο κάτω από τις γραμμές, τα ψηφία που πληκτρολογεί ένας υπάλληλος όταν αποτύχει η σάρωση. Αυτό το κείμενο είναι εφεδρεία, όχι διακόσμηση, οπότε όταν τοποθετείτε δική σας λεζάντα κρατήστε την μακριά από την ήσυχη ζώνη· μια ένδειξη της συμβολολογίας στριμωγμένη στο πλαϊνό περιθώριο ακυρώνει τον ίδιο λευκό χώρο από τον οποίο εξαρτάται ο σαρωτής. Τα πεδία στο παράδειγμα εδώ, μαζί με το TextOut για όποιες γύρω ετικέτες, είναι οι ίδιες κλήσεις σχεδίασης που καλύπτονται στον οδηγό εξόδου αναφορών, που είναι το σημείο στο οποίο πηγαίνετε όταν ο γραμμωτός κώδικας είναι ένα στοιχείο μέσα σε μια μεγαλύτερη συντεθειμένη σελίδα

Μια σύντομη συνήθεια επαλήθευσης

Οι διανυσματικές γραμμές είναι πλεονέκτημα που αξίζει να κατονομαστεί. Επειδή το DrawBarcode γράφει τον κώδικα ως τελεστές σχεδίασης PDF και όχι ως ραστεροποιημένη εικόνα, οι γραμμές μένουν ευκρινείς σε οποιοδήποτε ζουμ και το αρχείο δεν κουβαλά δική του ανάλυση· η μόνη ανάλυση που μετράει είναι του εκτυπωτή. Αυτό δεν σας απαλλάσσει από τη δοκιμή, απλώς σημαίνει ότι η δοκιμή πρέπει να γίνει στο χαρτί. Παραγάγετε ένα δείγμα, τυπώστε το στη συσκευή με τη χαμηλότερη ανάλυση που θα συναντήσουν πραγματικά οι κώδικές σας, και σαρώστε το με την ίδια κατηγορία αναγνώστη που κρατούν οι χρήστες σας, όχι με τον κορυφαίο απεικονιστή στο γραφείο σας. Ελέγξτε τις ήσυχες ζώνες με χάρακα πάνω στο τυπωμένο, επιβεβαιώστε ότι το πλάτος module επιβίωσε από το ταξίδι από σημεία σε κουκκίδες, και επαληθεύστε ότι η αποκωδικοποιημένη τιμή ταιριάζει με αυτό που κωδικοποιήσατε, μαζί με το ψηφίο ελέγχου. Πέντε λεπτά με πραγματικό σαρωτή πιάνουν κάθε αστοχία που περιγράφηκε παραπάνω, και τις πιάνουν πριν τις πιάσει μια παλέτα με λάθος ετικέτες

Οι μέθοδοι DrawBarcode και DirectDrawBarcode που παρουσιάζονται εδώ αποτελούν μέρος του HotPDF Delphi Component για Delphi και C++Builder