Dès qu’une équipe expédie des produits physiques, elle finit tôt ou tard par imprimer un code-barres GS1-128 qu’un vrai scanner portable doit lire dans une vraie lumière d’entrepôt, à une vraie distance. Le sujet paraît banal. En génération de PDF, c’est pourtant l’un des modes d’échec les plus bruyants.
Ce guide explique ce que signifie vraiment une précision de « 0,1 mm » pour un code-barres GS1-128, pourquoi les moteurs fondés sur HTML/CSS peinent à l’assurer, et quelles règles de conception permettent d’imprimer correctement dès le premier passage chez DHL, FedEx, USPS ou dans les scanners d’ingestion Amazon.
Ce que veut dire la précision d’un code-barres
GS1-128 (anciennement UCC/EAN-128) encode les données avec des largeurs de barres et d’espaces dans des rapports soigneusement définis. L’unité atomique est la X-dimension : la largeur de la barre ou de l’espace le plus étroit. Tout le reste est un multiple de X (1X, 2X, 3X, 4X pour les motifs internes de Code 128).
Les scanners décodent en mesurant des largeurs relatives. Si les largeurs imprimées dérivent, le décodage échoue.
Les deux modes d’échec les plus fréquents en production :
- X-dimension incohérente dans le symbole : le moteur de rendu applique des arrondis sous-pixel différemment sur des barres voisines. Les trois premières barres font 8 px, puis une barre à 7 px apparaît au milieu. Le scanner voit un motif incohérent.
- Longueur totale ou mise à l’échelle incorrecte : le moteur a redimensionné le symbole après rendu, ce qui distord la X-dimension sous le minimum GS1, typiquement 0,495 mm avec un facteur d’agrandissement de 1,0×.
Les deux produisent le même symptôme : le scanner émet un bip sur un échantillon isolé, mais le lot de production affiche un rejet sur trente. Vous ne le voyez pas en QA, parce que le scanner de développement est souvent plus indulgent que celui de l’entrepôt.
La règle des 0,1 mm
La précision pertinente est la longueur totale du code-barres, avec une tolérance de 0,1 mm ou moins par rapport à la cible de la spécification. Ce n’est PAS « chaque barre mesure 0,1 mm » : les barres font généralement 0,495 mm ou plus. La limite de 0,1 mm porte sur la précision dimensionnelle cumulée de tout le symbole.
Pour un GS1-128 typique avec 18 chiffres :
- Le symbole contient environ 120 barres et espaces.
- La longueur totale à 1,0× est proche de 58 mm.
- 0,1 mm de tolérance globale équivaut à environ 0,17 % de précision sur toute la longueur.
- Cela donne un budget de cohérence d’environ 0,001 mm par barre, bien inférieur à la largeur d’une barre individuelle.
C’est pourquoi « le moteur pose une barre de 7 px alors qu’elle devrait faire 7,4 px » est fatal. Les arrondis sous-pixel s’accumulent sur 120 barres, et la tolérance de 0,1 mm est dépassée quelque part entre la barre 50 et la barre 80.
Pourquoi HTML/CSS a du mal
Le chemin classique dans lequel beaucoup d’équipes se retrouvent : encoder les données GS1-128 dans une chaîne, générer un SVG (ou pire, des barres en <div>), l’intégrer dans du HTML, puis rendre le PDF via Puppeteer ou Prince.
Chaque maillon de cette chaîne introduit une dérive.
1. Le navigateur arrondit lors de la rastérisation
Même un SVG dans du HTML subit les arrondis sous-pixel du painter du navigateur, sauf si shape-rendering="crispEdges" est défini, que le conteneur environnant tombe sur une frontière entière de pixels, et que le DPI du PDF multiplie proprement les largeurs de barre. Trois contraintes, toutes faciles à violer sans le voir.
2. La mise en page CSS peut décaler l’échelle
Un transform: scale(0.95) quelque part dans votre feuille de style — ajouté six mois plus tôt pour corriger un autre problème de mise en page — distord silencieusement tous les codes-barres de la page. Aucun avertissement. Le PDF semble correct. Le scanner ne le lit pas.
3. L’émetteur PDF quantifie ses coordonnées
Quand le navigateur sérialise en PDF, il convertit le résultat peint en opérateurs de dessin PDF. Certains émetteurs, notamment Chromium, accrochent les coordonnées à une grille interne fixe. Pour un code-barres SVG placé à des coordonnées qui ne s’alignent pas sur cette grille, le résultat est presque juste, mais l’erreur s’accumule.
4. Les polices Code 128 sont pires
Certaines équipes utilisent une police Code 128 ({ font: "Code128" }), tapent les données et espèrent que tout ira bien. Les polices sont vectorielles et, en théorie, se redimensionnent correctement. Mais le hinting de police à petite taille décale les largeurs pour améliorer l’apparence à l’œil humain : exactement l’inverse de ce que demande un scanner.
L’approche par rendu structuré
gPdf prend les données, calcule le motif barres/espaces depuis la spécification GS1-128 et émet directement des primitives vectorielles PDF : pas de HTML, pas de traduction SVG, pas de hinting de police.
{
"pages": [{
"size": "label_100_150",
"elements": [
{
"type": "barcode",
"format": "gs1128",
"content": "(00)123456789012345678",
"x": 4,
"y": 8,
"width": 58.0,
"height": 18.0,
"barcode_text": { "enabled": true, "position": "bottom" }
}
]
}]
}
Dans un élément barcode, width désigne la longueur totale du symbole en mm, celle que l’on mesure au pied à coulisse sur l’étiquette imprimée. C’est le bon réglage, et c’est ce que garantit width: 58.0 :
- Le moteur calcule la X-dimension en divisant la longueur cible par le nombre de barres du symbole, entièrement déterminé par les données.
- Chaque barre est dessinée avec la même X-dimension.
- Les largeurs sont écrites dans le PDF en coordonnées flottantes (unité PDF = 1/72 inch, plus fine que nécessaire à la résolution de scan).
- Pas de hinting de police, pas d’arrondi de pixels CSS, pas de distorsion par passe de mise en page.
Résultat : la longueur totale reste dans les 0,1 mm de la cible demandée sur toute imprimante qui n’ajoute pas sa propre mise à l’échelle, ce qui est le cas par défaut de la plupart d’entre elles.
Ce qu’il faut imprimer
Trois règles évitent 95 % des échecs de scan en production.
Règle 1 : spécifier la longueur totale, pas la X-dimension
Le champ width est le bon réglage parce qu’il est mesurable : vous pouvez prendre un pied à coulisse, vérifier l’étiquette imprimée et comparer directement. Spécifier la X-dimension signifie que la longueur du symbole dépend des données encodées, ce qui rend la QA des étiquettes plus difficile (SKU différent = largeur de code-barres différente).
Pour les tailles d’étiquettes courantes :
- Étiquette d’expédition 4×6 in : largeur 100 mm, GS1-128 autour de 58 à 72 mm.
- Étiquette de conformité 4×4 in : environ 45 à 58 mm.
- Étiquette carton 2×1 in (Amazon UPC) : ce n’est pas le territoire de GS1-128, utilisez UPC-A.
Règle 2 : quiet zones, toujours
Un GS1-128 exige des quiet zones ≥ 10X des deux côtés : l’espace blanc dont le scanner se sert pour trouver les bords du symbole. À 1,0× (X = 0,495 mm), cela fait au moins 4,95 mm d’espace libre.
Le mode d’échec classique : un développeur place le code-barres à x: 0 pour le faire tenir à côté d’autres éléments de l’étiquette, et le scanner ne trouve plus le début. Le moteur doit réserver les quiet zones automatiquement, ce que fait gPdf ; vérifiez que le vôtre en fait autant.
Règle 3 : tester sur le scanner cible
La caméra d’un téléphone pardonne beaucoup plus qu’un scanner industriel Honeywell ou Zebra. Le chemin QA standard :
- Imprimez 50 étiquettes sur l’imprimante de production, à vitesse de production.
- Faites-les passer dans le type de scanner réel, à la vitesse réelle du convoyeur.
- Un taux de lecture < 99 % signifie que quelque chose ne va pas, souvent la cohérence de la X-dimension.
N’expédiez pas à des partenaires logistiques sur la base de « ça scanne bien avec la caméra de mon MacBook ».
Réalité multi-format
Une étiquette contient rarement seulement GS1-128 :
| Symbole | Usage | Source de spécification |
|---|---|---|
| GS1-128 | Unités logistiques, GTIN + série + lot | GS1 General Specifications |
| QR with FNC1 | E-commerce scannable sur mobile | ISO/IEC 18004 |
| Data Matrix | Pharmaceutique (DSCSA / EU FMD) | ISO/IEC 16022 |
| PDF417 | Permis de conduire, cartes d’embarquement | ISO/IEC 15438 |
| Aztec | Titres de transport | ISO/IEC 24778 |
| MaxiCode | UPS spécifiquement | ISO/IEC 16023 |
Un moteur qui ne gère que GS1-128 finira par vous pousser vers un second outil. Nous intégrons les six formats dans un seul moteur, parce que les flux expédition/logistique ont presque toujours besoin d’au moins deux symbologies.
Diagnostiquer les rejets en production
Si vous êtes déjà en production avec un problème de rejet scanner, l’ordre de diagnostic :
- Échantillonner les étiquettes échouées : ne vous fiez pas aux métriques agrégées. Récupérez l’étiquette physique qui a échoué.
- Mesurer au pied à coulisse : longueur totale et X-dimension. Si elles ne sont pas dans la tolérance de la spécification, c’est votre bug.
- Vérifier le texte lisible par l’humain en dessous : les scanners qui échouent sur les barres tentent souvent un fallback OCR. Si les deux échouent, le symbole est réellement mal formé.
- Vérifier les quiet zones : mesurez l’espace blanc des deux côtés. Si quelque chose est imprimé trop près (logo, ligne de séparation, autre code-barres), c’est le problème.
- Essayer un autre modèle de scanner : certains scanners ont des particularités de firmware. Si le modèle A lit l’étiquette mais pas le modèle B, le sujet est l’interopérabilité, pas seulement votre moteur de rendu.
- Comparer à une étiquette de référence connue : les fournisseurs publient des images de référence aux dimensions exactes. Si la vôtre ne correspond pas visuellement, remontez depuis l’écart.
TL;DR
La précision GS1-128 ne concerne pas la finesse maximale des barres : elle consiste à maintenir une X-dimension cohérente sur tout le symbole, dans une fraction de millimètre. Les moteurs fondés sur HTML/CSS introduisent des dérives sous-pixel à plusieurs étapes du pipeline ; les moteurs structurés qui émettent directement des primitives vectorielles PDF évitent entièrement ces sources de dérive.
Si votre stack PDF produit 1 à 5 % de refus scanner, c’est un signal fort. Le Playground peut rendre un échantillon GS1-128 avec le champ width exactement calé sur votre spécification d’étiquette : imprimez le résultat, mesurez-le au pied à coulisse et comparez.