Un code-barres sur une étiquette d'expédition ou une facture n'a qu'une seule fonction : être lu par un scanner dès le premier passage. Qu'il survive ou non à cette épreuve se décide bien avant que le colis n'arrive à quai. Cela dépend de la manière dont le symbole a été apposé sur la page. L'erreur la plus classique dans un flux de rapports Delphi consiste à générer le code-barres sous forme de bitmap ailleurs et à insérer cette image dans le PDF. Le rendu semble correct à l'écran sous un certain niveau de zoom, puis se dégrade partout ailleurs.
L'alternative consiste à dessiner le symbole sous forme de contenu vectoriel, directement dans la page. PDFlibPas expose pour cela un ensemble de fonctions de dessin, couvrant les symboles matriciels 2D QR, PDF417 et DataMatrix, les familles linéaires Code128 et GS1-128, ainsi que l'USPS Intelligent Mail pour l'automatisation postale. Le choix du vectoriel n'est pas d'ordre esthétique. Il garantit que les barres se placent exactement là où le scanner les attend.
Pourquoi le vectoriel l'emporte sur l'image bitmap
Un code-barres est une alternance 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 élément qui fausse ces rapports constitue un bruit qui entame le budget de correction d'erreurs du symbole. Une image matricielle de code-barres est figée en pixels. Lorsque le PDF est envoyé à une imprimante dont les points ne se divisent pas uniformément selon la grille de l'image, le tramage doit rééchantillonner, et les bordures de modules qui devraient être nettes se répartissent sur deux pixels physiques. Une barre étroite peut s'élargir, un espace adjacent s'amincir, et le rapport de largeur dont dépend le décodeur s'altère.
Dessiné sous forme vectorielle, le même symbole est constitué d'un ensemble de rectangles pleins décrits dans les coordonnées de l'espace utilisateur PDF. Il n'y a pas de grille de pixels fixe à gérer. Lors de l'impression, le périphérique restitue chaque rectangle à sa résolution propre, de sorte que chaque bordure de module est aussi nette que le matériel le permet, à n'importe quelle échelle et taille d'impression. Agrandissez un symbole vectoriel pour une étiquette de palette ou réduisez-le pour un colis, sa géométrie reste exacte. Cette précision garantit un taux élevé de lecture dès le premier passage, ce qui est le but recherché en plaçant 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 simultanément, ce qui lui permet de concentrer beaucoup de données dans un petit carré. Sa tolérance aux dommages provient d'une correction d'erreurs Reed-Solomon, proposée sur quatre niveaux. Le niveau L récupère environ 7 pour cent des mots de code, le niveau M environ 15 pour cent, le niveau Q environ 25 pour cent et le niveau H environ 30 pour cent. Une correction supérieure n'est pas gratuite. Les mots de code de récupération occupent de l'espace de modules. Ainsi, pour une quantité de données fixe, un niveau plus élevé nécessite un symbole plus dense ou physiquement plus grand.
Le compromis dépend de l'environnement dans lequel le symbole va exister. Un document numérique propre qui sera uniquement scanné sur un écran peut se contenter du niveau L et rester compact. Une étiquette qui sera imprimée, manipulée, éraflée et potentiellement recouverte de ruban adhésif demande un niveau Q ou H, car cette redondance accrue permet au décodeur de reconstruire les données d'un symbole altéré. DrawQRCode prend en paramètre la position, un SymbolSize déterminant la largeur et la hauteur dessinées, ainsi qu'une valeur EncodeOptions sélectionnant le mode de données (0 pour automatique, ou les variantes numérique, alphanumérique, ISO-8859-1 et UTF-8) et un 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 ajuster les données au symbole demandé. Si vous avez besoin d'un niveau élevé garanti pour un environnement difficile, prévoyez des dimensions de symbole généreuses afin que l'encodeur dispose du budget de modules nécessaire pour la redondance au lieu d'être contraint de le réduire.
Le PDF417 pour les cartes d'identité et les étiquettes d'expédition
Le PDF417 est un symbole linéaire empilé. Chaque ligne est un court code-barres linéaire, et ces lignes s'empilent pour former un bloc. C'est pourquoi on le trouve sur les permis de conduire, les cartes d'embarquement et les étiquettes d'expédition, où un volume important de données doit tenir dans un espace rectangulaire. Sa correction d'erreurs s'étend de 0 à 8. Chaque palier double approximativement le nombre de mots de code de correction. Ainsi, le niveau 5 intègre beaucoup plus de redondance que le niveau 1, au coût d'un plus grand nombre de mots de code sur la page.
La forme d'un bloc PDF417 est ajustable, ce qui est crucial car l'étiquette a une surface définie à remplir. La fonction DrawPDF417SymbolEx expose les contrôles absents de l'appel de base. FixedColumns et FixedRows figent le nombre de colonnes et de lignes de données, la valeur 0 laissant l'encodeur décider. ErrorLevel prend la valeur -1 pour un choix automatique ou une valeur explicite de 0 à 8. ModuleSize représente la largeur de l'élément le plus étroit dans l'unité de mesure courante, et HeightWidthRatio détermine la hauteur de chaque module par rapport à sa largeur, ce qui permet de rendre le bloc large et bas ou haut et étroit selon l'espace disponible.
// 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
Figer les colonnes est la méthode habituelle pour les modèles d'étiquettes. Un nombre constant de colonnes donne au bloc une largeur prévisible, garantissant que la mise en page environnante ne se décale pas lorsque la longueur des données encodées varie d'un document à l'autre, l'encodeur ajoutant simplement des lignes vers le bas pour compenser la différence.
Le DataMatrix pour les marquages de petite taille
Le DataMatrix est le symbole idéal lorsque le marquage doit être minuscule. Il s'agit d'une grille 2D compacte utilisant le schéma Reed-Solomon moderne ECC 200, et il reste lisible à des tailles où un symbole QR de contenu équivalent serait trop grand. Cela en fait le choix par défaut pour le marquage direct de pièces, les petits composants électroniques et les étiquettes logistiques denses.
La fonction DrawDataMatrixSymbol prend en paramètre un ModuleSize pour le pas des points, un Encoding à 1 pour l'ASCII, et un SymbolSize valant soit 0 pour automatique, soit l'une des dimensions standard carrées ou rectangulaires, de 10x10 à 132x132. Le paramètre Options combine l'orientation et la largeur de la zone tranquille (quiet zone), où l'ajout d'une valeur de 100 à 400 définit une bordure blanche d'un à quatre modules. La zone tranquille n'est pas un élément décoratif. Un décodeur a besoin de cette marge vierge pour identifier le motif de recherche du symbole, et un symbole accolé à un autre tracé est un symbole qui ne sera pas détecté.
// 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
Les domaines où les codes-barres 1D restent dominants
Les symboles bidimensionnels captent l'attention, mais les codes-barres linéaires dominent encore de larges pans du commerce de détail et de la logistique en raison du parc installé de lecteurs laser fonctionnant par balayage unique. Le Code128 est le standard pour les données alphanumériques. 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 la plage ASCII imprimable complète, et le jeu C est celui qui convient aux chiffres. Le sous-ensemble C encode une paire de chiffres dans un seul caractère du symbole. Ainsi, une série de données numériques occupe deux fois moins de caractères qu'avec le jeu A ou B. C'est la méthode la plus compacte pour représenter un long code-barres numérique, et l'implémentation du Code128 dans PDFlibPas combine automatiquement les jeux B et C pour y parvenir.
Le GS1-128, norme anciennement appelée EAN-128, s'appuie sur le Code128 en transportant des identifiants d'application (Application Identifiers), ces préfixes entre crochets qui indiquent au système de réception si les chiffres suivants correspondent à un numéro de série, un code de lot ou une date d'expiration. La structure est signalée par FNC1, un caractère spécial hors données qui identifie le symbole comme 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] inséré 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, l'USPS Intelligent Mail, également appelé OneCode, encode les données d'acheminement et de suivi dans un unique code-barres à hauteur modulée destiné à l'automatisation postale. DrawIntelligentMailBarcode prend en paramètre des cotes géométriques explicites pour la largeur des barres, la hauteur totale des barres, la hauteur du tracker (tracker height) et la largeur des espaces, les données étant fournies sous forme d'une chaîne composée uniquement de 20, 25, 29 ou 31 chiffres. Ces hauteurs explicites de barres et de trackers s'expliquent par le fait que le symbole transmet des informations selon que chaque élément est une barre pleine, une ascendante ou une descendante, le lecteur postal dépendant de la conformité de ces hauteurs aux spécifications.
Dessiner dans la page et mesurer pour la mise en page
Chaque appel présenté ici dessine directement dans le contenu de la page actuellement sélectionnée, la surface même qui reçoit vos textes et vos images. Le code-barres est ainsi produit dans le cadre du processus normal de génération de documents, plutôt que d'être importé comme une ressource externe. Comme les symboles sont au format vectoriel, les données qu'ils encodent et l'espace qu'ils occupent sont tous deux connus lors du dessin, ce qui permet de les placer de manière déterministe.
Pour les familles linéaires, il ést préférable de mesurer la largeur d'abord. GetBarcodeWidth renvoie la largeur totale dessinée d'un code-barres pour une largeur de barre étroite et un type donnés. Cela permet de réserver l'espace horizontal exact avant de valider le dessin, plutôt que de deviner et de constater un chevauchement après la construction de la page. Les symboles 2D sont plus simples à positionner car vous définissez leur taille directement via SymbolSize ou ModuleSize, le symbole occupant tout cet espace. Dans tous les cas, la méthode reste identique : déterminer la dimension physique requise par l'environnement de lecture, s'assurer que le symbole loge dans l'emplacement imparti, et laisser la géométrie vectorielle conserver la netteté de chaque tracé, de l'aperçu écran à l'impression finale.
Concernant le processus global de création de pages dans lequel s'insèrent ces codes-barres, les techniques de notre article sur l'extraction de texte, d'images et de polices couvrent la lecture de contenu depuis un PDF, et le guide sur la fusion et le découpage de documents volumineux par accès direct décrit l'assemblage efficace de documents à fort volume. Ces deux aspects s'associent naturellement à l'API de dessin présentée ici, fournie dans la bibliothèque PDF Delphi pour Delphi et C++Builder, aux côtés des API de texte, graphismes, formulaires et signatures abordées sur ce blog.