Blog

GS1-128-barcodes met 0,1 mm precisie in JSON: een praktische gids

GS1-128 lijkt eenvoudig totdat de scanner bij 240 dpi niet meer leest. Een praktische gids over totale-lengteprecisie, X-dimensie, quiet zones en waarom HTML/CSS dit moeilijk maakt.

Als u fysieke goederen verzendt, moet u vroeg of laat een GS1-128-barcode printen die een echte handscanner in echt magazijnlicht en op echte afstand kan lezen. Dat klinkt saai. In PDF-generatie is het juist een van de luidruchtigere foutmodi.

Dit artikel legt uit wat “0,1 mm precisie” werkelijk betekent voor een GS1-128-barcode, waarom HTML/CSS-gebaseerde renderengines moeite hebben om dat betrouwbaar te halen, en welke kleine set ontwerpregels ervoor zorgt dat een barcode de eerste keer correct print voor scanners bij DHL, FedEx, USPS en Amazon inbound.

Wat barcodeprecisie werkelijk betekent

GS1-128, voorheen UCC/EAN-128, codeert data met balkbreedtes en tussenruimtes in zorgvuldig gekozen verhoudingen. De atomaire eenheid is de X-dimensie: de breedte van de smalste balk of tussenruimte. Alles daarboven is een veelvoud van X: 1X, 2X, 3X en 4X voor de interne patronen van Code 128.

Scanners decoderen door relatieve breedtes te meten. Als de geprinte breedtes wegdrijven, faalt de decodering.

De twee meest voorkomende foutmodi in productie:

  1. Inconsistente X-dimensie binnen het symbool: de renderengine rondt subpixels verschillend af voor aangrenzende balken. De eerste drie balken zijn 8 px, daarna verschijnt middenin een balk van 7 px. De scanner ziet een inconsistent patroon.
  2. Verkeerde totale lengte of schaal: de renderengine schaalt het symbool na het renderen, waardoor de X-dimensie onder het GS1-minimum komt, doorgaans 0,495 mm bij een vergrotingsfactor van 1,0×.

Beide laten hetzelfde symptoom zien: de scanner geeft één piep op één testetiket, maar een productiebatch heeft een afkeurpercentage van 1 op 30. Dat vangt u niet in QA, omdat uw ontwikkelscanner vaak toleranter is dan de magazijnscanner.

De 0,1 mm-regel

De relevante precisie is de totale barcodelengte met een tolerantie van maximaal 0,1 mm ten opzichte van de specificatie. Niet “elke balk is 0,1 mm breed”: balken zijn doorgaans 0,495 mm of groter. De grens van 0,1 mm gaat over de cumulatieve maatnauwkeurigheid van het hele symbool.

Voor een typische GS1-128 met 18 numerieke tekens:

  • het symbool bevat ongeveer 120 balken en tussenruimtes;
  • totale lengte bij 1,0× vergroting: ongeveer 58 mm;
  • 0,1 mm totale tolerantie = ongeveer 0,17% nauwkeurigheid over de hele lengte;
  • dat komt neer op ongeveer 0,001 mm consistentiebudget per balk, ruim onder de breedte van één individuele balk.

Daarom is “de renderengine zet een balk van 7 px neer waar 7,4 px nodig was” fataal. Subpixelafronding stapelt zich op over 120 balken, en ergens tussen balk 50 en balk 80 valt u buiten de tolerantie van 0,1 mm.

Waarom HTML/CSS hier moeite mee heeft

Het pad waarop veel teams vastlopen: GS1-128-data omzetten naar een string, een SVG genereren of erger nog losse <div>-balken maken, die in HTML plaatsen en via Puppeteer of Prince naar PDF renderen.

Elke schakel in die keten introduceert drift:

1. Browser-rasterisatie rondt af

Zelfs SVG-in-HTML wordt door de painter van de browser op subpixels afgerond, tenzij shape-rendering="crispEdges" is ingesteld, én de omliggende container exact op een integer pixelgrens valt, én de PDF-DPI netjes vermenigvuldigt naar de balkbreedtes. Drie voorwaarden, allemaal eenvoudig per ongeluk te breken.

2. CSS-layout kan verschuiven

Een transform: scale(0.95) ergens in uw stylesheet, zes maanden eerder toegevoegd om een ander layoutprobleem op te lossen, vervormt stilletjes elke barcode op de pagina. Er komt geen waarschuwing. De PDF ziet er goed uit. De scanner meet iets anders.

3. De PDF-emitter kwantiseert zelf

Wanneer de browser naar PDF serialiseert, zet hij het geschilderde resultaat om naar PDF-tekenoperators. Sommige emitters, met name die van Chromium, klikken vast op een interne PDF-grid. Bij een SVG-barcode op coördinaten die niet op die grid aansluiten, krijgt u output die bijna klopt maar fout opstapelt.

4. Encoding via fonts is nog riskanter

Sommige teams gebruiken een Code 128-font ({ font: "Code128" }), typen de data en hopen dat het goed komt. Fonts zijn vectorieel en schalen theoretisch, maar font hinting op kleine formaten verschuift breedtes om tekst beter leesbaar te maken voor mensen. Dat is precies verkeerd voor scanners.

De aanpak met gestructureerde rendering

gPdf neemt de data, berekent het balk-/tussenruimtepatroon uit de GS1-128-specificatie en schrijft PDF-vectorprimitieven direct weg: geen HTML, geen SVG-vertaling, geen font hinting.

{
  "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" }
      }
    ]
  }]
}

Voor een barcode-element is width de totale lengte van het symbool in mm: precies wat u met een schuifmaat op het geprinte etiket zou meten. Dat is de juiste knop om in te stellen, en dit is wat width: 58.0 garandeert:

  • de renderengine berekent de X-dimensie door de doellengte te delen door het aantal balken in het symbool, volledig bepaald door de data;
  • elke balk wordt met exact dezelfde X-dimensie getekend;
  • die breedtes worden als floating-point coördinaten in de PDF geschreven, waarbij één PDF-unit 1/72 inch is en dus fijner dan nodig op scanresolutie;
  • geen font hinting, geen CSS-pixelafronding, geen vervorming door een layoutpass.

Het resultaat: de totale lengte blijft binnen 0,1 mm van het gevraagde doel op elke printer die zelf geen extra schaal toepast. De meeste printers doen dat standaard niet.

Wat u daadwerkelijk moet printen

Drie regels voorkomen 95% van de scannerfouten in productie.

Regel 1: specificeer totale lengte, niet X-dimensie

Het veld width is de juiste knop omdat het meetbaar is: u kunt een schuifmaat op een geprint etiket zetten en direct verifiëren. Alleen de X-dimensie specificeren betekent dat de symboollengte afhangt van de lengte van de gecodeerde data, wat QA voor etiketten moeilijker maakt. Een andere SKU geeft dan een andere barcodebreedte.

Voor de meeste etiketformaten:

  • 4×6 in verzendetiket: 100 mm breed, GS1-128 hoort ongeveer 58-72 mm te zijn;
  • 4×4 in vereistenetiket: ongeveer 45-58 mm;
  • 2×1 in kartonetiket (Amazon UPC): geen GS1-128-terrein, gebruik UPC-A.

Regel 2: altijd quiet zones

Een GS1-128 heeft quiet zones van minstens 10X aan beide kanten nodig: lege witte ruimte die de scanner gebruikt om de randen van het symbool te vinden. Bij 1,0× vergroting (X = 0,495 mm) is dat minimaal 4,95 mm vrije ruimte.

De klassieke foutmodus: een ontwikkelaar zet de barcode op x: 0 om hem naast andere etiketelementen te laten passen, waarna de scanner het begin niet kan vinden. De renderengine hoort quiet zones automatisch te reserveren. gPdf doet dat; controleer of uw stack dat ook doet.

Regel 3: test op de echte doelscanner, niet op uw ontwikkelscanner

De camera van een telefoon is toleranter dan een industriële Honeywell- of Zebra-scanner. Het standaard QA-pad:

  1. Print 50 etiketten op de echte productieprinter, op productiesnelheid.
  2. Laat ze door hetzelfde scannertype lopen, op dezelfde transportsnelheid.
  3. Een leesratio onder 99% betekent dat er iets niet klopt, meestal de consistentie van de X-dimensie.

Verzend niet naar logistieke partners op basis van “hij scande prima met mijn MacBook-camera”.

De realiteit met meerdere formaten

Uw etiket heeft waarschijnlijk meer nodig dan alleen GS1-128. Veelvoorkomende combinaties:

Symbool Gebruik Specificatiebron
GS1-128 Logistieke eenheden, GTIN + serial + lot GS1 General Specifications
QR with FNC1 Mobiel scanbare e-commerce ISO/IEC 18004
Data Matrix Farmacie (DSCSA / EU FMD) ISO/IEC 16022
PDF417 Rijbewijzen, boardingpassen ISO/IEC 15438
Aztec Vervoersbewijzen ISO/IEC 24778
MaxiCode Specifiek UPS ISO/IEC 16023

Een renderengine die alleen GS1-128 afhandelt, dwingt u uiteindelijk naar een tweede tool. We bundelen alle zes formaten in één renderengine, omdat verzend- en logistieke processen vrijwel altijd minstens twee formaten nodig hebben.

Scannerafkeur in productie onderzoeken

Als u al in productie zit met scannerafkeur, is dit de diagnosevolgorde:

  1. Neem voorbeelden van de afgekeurde etiketten: vertrouw niet alleen op geaggregeerde metrics. Haal het fysieke etiket op dat faalde.
  2. Meet met een schuifmaat: totale lengte en X-dimensie. Als die niet binnen de specificatietolerantie vallen, is dat de fout.
  3. Controleer de leesbare tekst eronder: scanners die de balken niet lezen, proberen vaak OCR-fallback. Als beide falen, is het symbool echt misvormd.
  4. Verifieer quiet zones: meet de witte ruimte aan beide kanten. Als er iets te dicht bij is geprint, bijvoorbeeld een logo, scheidingslijn of tweede barcode, is dat het probleem.
  5. Probeer een ander scannermodel: sommige scanners hebben firmware-eigenaardigheden. Als model A het etiket leest en model B niet, gaat het om interoperabiliteit, niet alleen om uw PDF-generator.
  6. Vergelijk met een bekende goede referentie: leveranciers publiceren referentiebeelden met exacte specificaties. Als uw output daar visueel van afwijkt, werk dan terug vanaf het verschil.

TL;DR

GS1-128-precisie gaat niet over hoe dun u balken kunt printen. Het gaat erom of de X-dimensie over het hele symbool consistent blijft binnen een fractie van een millimeter. HTML/CSS-gebaseerde renderengines introduceren op meerdere plekken in de pipeline subpixeldrift; gestructureerde renderengines die direct PDF-vectorprimitieven schrijven, slaan die driftbronnen over.

Als u bij uw huidige PDF-stack een scannerafkeur van 1-5% ziet, is dit een duidelijke aanwijzing. De Playground kan een GS1-128-voorbeeld renderen met het veld width exact op uw etiketspecificatie. Meet de geprinte output met een schuifmaat en vergelijk.