Un code-barres sur une étiquette d'expédition ou une facture n'a qu'un seul rôle : être lu par un scanner du premier coup. Sa capacité à survivre à ce passage se décide bien avant que le colis n'arrive à quai. Elle dépend de la façon dont le symbole a été placé sur la page. L'erreur la plus courante dans un pipeline de reporting Delphi est de générer le code-barres sous forme de bitmap ailleurs et de placer cette image dans le PDF. Il semble correct à l'écran à un certain niveau de zoom, puis se dégrade partout ailleurs
L'alternative consiste à dessiner le symbole sous forme de contenu vectoriel, directement sur la page. PDFlibPas propose une famille de fonctions de dessin exactement pour cela, couvrant les symboles matriciels 2D QR, PDF417 et DataMatrix, les familles linéaires Code128 et GS1-128, ainsi que USPS Intelligent Mail pour l'automatisation postale. L'argument en faveur du vectoriel n'est pas esthétique. Il s'agit de savoir si les barres atterrissent là où le scanner les attend
Pourquoi le vectoriel surpasse un bitmap inséré
Un code-barres est un motif de barres et d'espaces, ou en deux dimensions, une grille de modules sombres et clairs. Le décodeur fonctionne en mesurant le rapport de ces largeurs. Tout ce qui déforme ces rapports constitue un bruit qui entame le budget d'erreur du symbole. Une image de code-barres matricielle (rastérisée) comporte des pixels fixes. Lorsque le PDF est rendu sur une imprimante dont les points ne se divisent pas uniformément dans la grille de l'image, le rastériseur doit rééchantillonner, et les bords des modules qui devraient être nets s'étalent sur deux pixels de l'appareil. Une barre étroite peut s'épaissir, un espace adjacent peut s'amincir, et le rapport de largeur sur lequel s'appuie le décodeur dérive
Dessiné sous forme de contenu vectoriel, le même symbole est un ensemble de rectangles remplis décrits dans les coordonnées de l'espace utilisateur du PDF. Il n'y a pas de grille de pixels fixe à combattre. Au moment de l'impression, l'appareil rend chaque rectangle à sa résolution réelle, de sorte que chaque bord de module est aussi net que le matériel le permet, à n'importe quelle échelle et à n'importe quelle taille d'impression. Agrandissez un symbole vectoriel pour une étiquette de palette ou réduisez-le pour un colis et la géométrie reste exacte. Cette précision est ce qui maintient le taux de lecture au premier passage élevé, ce qui est le but même de placer un code-barres sur la page
Les codes QR et les quatre niveaux de correction
Le QR est un symbole matriciel 2D lu sur les deux axes à la fois, c'est pourquoi il concentre beaucoup de données dans un petit carré. Sa tolérance aux dommages provient de la correction d'erreur Reed-Solomon, proposée sur quatre niveaux. Le niveau L récupère environ 7 % des mots de code, le M environ 15 %, le Q environ 25 % et le H environ 30 %. Une correction plus élevée n'est pas gratuite. Les mots de code de récupération occupent la capacité des modules, donc pour une quantité fixe de données, un niveau supérieur impose un symbole plus dense ou physiquement plus grand
Le compromis est une question d'environnement dans lequel le symbole évoluera. Un document numérique propre qui ne sera jamais scanné qu'à partir d'un écran peut rester au niveau L et demeurer compact. Une étiquette qui sera imprimée, manipulée, éraflée et éventuellement recouverte en partie par du ruban adhésif nécessite un niveau Q ou H, car la redondance supplémentaire est ce qui permet à un décodeur de reconstruire la charge utile à partir d'un symbole qui n'est plus intact. DrawQRCode prend la position et un SymbolSize qui fixe la largeur et la hauteur dessinées, plus une valeur EncodeOptions qui sélectionne le mode de données (0 pour automatique, ou variantes numériques, alphanumériques, ISO-8859-1 et UTF-8) et une valeur DrawOptions pour l'orientation
var
Pdf: TPDFlib;
begin
Pdf := TPDFlib.Create(nil);
try
Pdf.NewDocument;
Pdf.SetPageSize('A4');
Pdf.SetMeasurementUnits(1); // 1 = millimetres
Pdf.NewPage;
// 30 mm square QR, automatic encoding, normal orientation
Pdf.DrawQRCode(20, 20, 30, 'https://www.loslab.com/', 0, 0);
Pdf.SaveToFile('Label_QR.pdf');
finally
Pdf.Free;
end;
end;
Le niveau de correction lui-même est choisi par l'encodeur pour intégrer les données dans le symbole que vous avez demandé. Si vous avez besoin d'un niveau élevé garanti pour un environnement difficile, dimensionnez généreusement le symbole afin que l'encodeur ait le budget de modules à dépenser sur la redondance plutôt que d'être contraint de le réduire pour s'adapter
PDF417 pour les pièces d'identité et les étiquettes d'expédition
Le PDF417 est un symbole linéaire empilé. Chaque ligne est un code-barres linéaire court, et les lignes s'empilent pour former un bloc, c'est pourquoi il apparaît sur les permis de conduire, les cartes d'embarquement et les étiquettes d'expédition des transporteurs où une bande de données plus large doit s'inscrire dans un espace rectangulaire. Sa correction d'erreur s'échelonne de 0 à 8. Chaque étape double approximativement le nombre de mots de code de correction, ainsi le niveau 5 offre beaucoup plus de redondance que le niveau 1, au prix d'un plus grand nombre de mots de code sur la page
La forme d'un bloc PDF417 est ajustable, ce qui est important car l'étiquette a une zone fixe à remplir. DrawPDF417SymbolEx expose les contrôles que l'appel de base ne propose pas. FixedColumns et FixedRows fixent le nombre de colonnes et de lignes de données, 0 signifiant qu'on laisse l'encodeur décider. ErrorLevel prend -1 pour automatique ou une valeur explicite de 0 à 8. ModuleSize est la largeur de l'élément le plus étroit dans l'unité de mesure actuelle, et HeightWidthRatio définit la hauteur de chaque module par rapport à sa largeur, ce qui permet de rendre le bloc court et large ou grand et étroit pour s'adapter à l'espace dont vous disposez
// Fixed 10 data columns, automatic rows, error level 5,
// module 0.30 mm wide, rows three times the module width tall
Pdf.DrawPDF417SymbolEx(20, 60, 'PDF417 PAYLOAD 0123456789',
0, // Options: 0 = normal orientation
10, // FixedColumns
0, // FixedRows: 0 = automatic
5, // ErrorLevel: 0 to 8
0.30, // ModuleSize, in the current measurement unit
3.0); // HeightWidthRatio
Fixer les colonnes est le levier habituel sur un modèle d'étiquette. Un nombre constant de colonnes donne au bloc une largeur prévisible, de sorte que la mise en page environnante ne se décale pas lorsque la charge utile encodée change de longueur d'un document à l'autre, tandis que l'encodeur ajoute des lignes vers le bas pour absorber la différence
DataMatrix pour les petites marques
Le DataMatrix est le symbole à privilégier lorsque la marque doit être de petite taille. C'est une grille 2D compacte qui utilise l'ECC 200, le système Reed-Solomon moderne, et il reste lisible à des tailles où un symbole QR avec les mêmes données serait peu pratique. Cela en fait le choix standard pour le marquage direct de pièces, les petits composants électroniques et les étiquettes logistiques denses
DrawDataMatrixSymbol prend un ModuleSize pour le pas de point, un Encoding de 1 pour l'ASCII, et un SymbolSize qui est soit 0 pour automatique, soit l'une des dimensions carrées ou rectangulaires standard, de 10x10 jusqu'à 132x132. Le paramètre Options combine l'orientation avec la largeur de la zone de silence, où l'ajout de 100 à 400 définit une bordure blanche de un à quatre modules. La zone de silence n'est pas une décoration. Un décodeur a besoin de cette marge dégagée pour trouver le motif de recherche du symbole, et un symbole entassé contre d'autres encres est un symbole qui ne sera pas acquis
// Auto-sized ASCII DataMatrix, 0.5 mm module, normal orientation
// with a one-module quiet zone (Options 0 + 100)
Pdf.DrawDataMatrixSymbol(20, 110, 0.5, 'DMX-SN-4408812',
1, // Encoding: 1 = ASCII
0, // SymbolSize: 0 = automatic
100); // Options: normal + one-module quiet zone
Là où les codes-barres 1D règnent encore
Les symboles bidimensionnels attirent l'attention, mais les codes-barres linéaires dominent toujours de vastes pans du commerce de détail et de la logistique, en raison de la base installée de scanners laser qui lisent d'un seul balayage. Le Code128 est le cheval de bataille pour les données alphanumériques, et son efficacité provient de trois jeux de caractères. Le jeu A couvre les caractères de contrôle et les majuscules, le jeu B couvre toute la plage ASCII imprimable, et le jeu C est celui qui compte pour les chiffres. Le sous-ensemble C encode une paire de chiffres dans un seul caractère de symbole, ainsi une série de données numériques prend la moitié des caractères de symbole qu'elle prendrait dans le jeu A ou B. C'est la façon la plus compacte de créer un long code-barres numérique, et l'implémentation du Code128 de PDFlibPas combine automatiquement les jeux B et C pour y parvenir
Le GS1-128, la norme anciennement nommée EAN-128, s'appuie sur le Code128 en transportant des identifiants d'application, ces préfixes entre parenthèses qui indiquent à un système de réception si les chiffres suivants sont un numéro de série, un code de lot ou une date d'expiration. La structure est marquée par FNC1, un caractère spécial (non-donnée) qui signale le symbole comme étant encodé en GS1 et sépare les champs de longueur variable. Dans PDFlibPas, vous dessinez un symbole GS1-128 avec DrawBarcode en utilisant le type Code128 et le marqueur littéral [FNC1] placé dans la chaîne de données là où commence chaque identifiant d'application
var
W: Double;
begin
// Code128, with FNC1 markers this becomes a GS1-128 symbol.
// AI 21 (serial) = ABC123, AI 20 (variant) = 13
Pdf.DrawBarcode(20, 150, 60, 18, '[FNC1]21ABC123[FNC1]2013',
3, // Barcode: 3 = Code128
0); // Options: 0 = default drawing
// Measure the rendered width for a 0.30 mm narrow bar before laying out
W := Pdf.GetBarcodeWidth(0.30, '[FNC1]21ABC123[FNC1]2013', 3);
end;
Pour le courrier, USPS Intelligent Mail, également appelé OneCode, encode les données d'acheminement et de suivi dans un seul code-barres modulé en hauteur pour l'automatisation postale. DrawIntelligentMailBarcode prend une géométrie explicite pour la largeur de la barre, la hauteur totale de la barre, la hauteur du traceur et la largeur de l'espace, avec des données fournies sous forme de chaîne de 20, 25, 29 ou 31 chiffres uniquement. Les hauteurs explicites de la barre et du traceur existent car le symbole contient des informations selon que chaque barre est une barre pleine, une barre ascendante ou une barre descendante, et le lecteur postal a besoin que ces hauteurs soient conformes aux spécifications
Dessiner sur la page et mesurer pour la mise en page
Chaque appel illustré ici dessine dans le contenu de la page actuellement sélectionnée, la même surface qui reçoit votre texte et vos images, de sorte qu'un code-barres est produit dans le cadre de la génération normale de document plutôt que d'être importé comme un actif distinct. Étant donné que les symboles sont du contenu vectoriel, les données qu'ils encodent et la géométrie qu'ils occupent sont toutes deux connues au moment du dessin, ce qui vous permet de les placer de manière déterministe
La mise en page pour les familles linéaires gagne à être mesurée au préalable. GetBarcodeWidth renvoie la largeur totale dessinée d'un code-barres pour une largeur de barre étroite et un type de code-barres donnés, afin que vous puissiez réserver l'espace horizontal exact avant de valider le dessin, plutôt que de deviner et de découvrir un chevauchement une fois la page construite. Les symboles 2D sont plus simples à placer car vous définissez leur taille dessinée directement via SymbolSize ou ModuleSize, et le symbole remplit cette empreinte. Dans tous les cas, la discipline est la même. Décidez de la taille physique en fonction de l'environnement de numérisation, confirmez que le symbole s'intègre dans l'emplacement dont vous disposez, et laissez la géométrie vectorielle garder chaque bord net de l'aperçu à l'écran jusqu'à l'impression finale
Pour le flux de création de pages plus large dans lequel s'intègrent ces codes-barres, les techniques présentées dans notre article sur l'extraction de texte, d'image et de police couvrent la relecture du contenu d'un PDF, et le guide sur la fusion et la séparation de PDF volumineux avec accès direct montre comment assembler efficacement des documents à fort volume. Les deux s'associent naturellement à l'API de dessin décrite ici, qui est incluse dans la Bibliothèque PDF Delphi pour Delphi et C++Builder, aux côtés des API de texte, de graphiques, de formulaires et de signatures traitées par ailleurs sur ce blog