Blog

Kody kreskowe GS1-128 z dokładnością 0,1 mm w JSON: praktyczny przewodnik

GS1-128 wygląda prosto, dopóki skaner nie przestaje czytać przy 240 dpi. Praktyczny przewodnik po długości całkowitej, X-dimension, strefach ciszy i tym, dlaczego HTML/CSS utrudnia sprawę.

Jeżeli wysyłasz fizyczne towary, prędzej czy później musisz wydrukować kod kreskowy GS1-128, który realny skaner ręczny odczyta w prawdziwym magazynowym świetle i z prawdziwej odległości. Brzmi jak nudny detal. W praktyce to jeden z głośniejszych trybów awarii przy generowaniu PDF.

Ten artykuł wyjaśnia, co “dokładność 0,1 mm” naprawdę oznacza dla kodu GS1-128, dlaczego generatory oparte na HTML/CSS mają problem z jej utrzymaniem oraz jaki zestaw prostych reguł sprawia, że kod kreskowy drukuje się poprawnie za pierwszym razem dla skanerów przyjęciowych DHL, FedEx, USPS i Amazon.

Co naprawdę oznacza “precyzja kodu kreskowego”

GS1-128 (dawniej UCC/EAN-128) koduje dane za pomocą szerokości kresek i przerw dobranych w ścisłych proporcjach. Jednostką bazową jest X-dimension — szerokość najwęższej kreski lub przerwy. Wszystkie pozostałe wymiary są jej wielokrotnościami (1X, 2X, 3X, 4X dla wewnętrznych wzorców Code 128).

Skanery dekodują symbol, mierząc relatywne szerokości. Jeżeli wydrukowane szerokości odpłyną, dekodowanie się nie powiedzie.

Dwa najczęstsze tryby awarii w produkcji:

  1. Niespójna X-dimension w obrębie symbolu — generator zaokrągla wartości subpikselowe inaczej dla sąsiednich kresek. Pierwsze trzy kreski mają 8 px, po czym w środku pojawia się kreska 7 px. Skaner widzi niespójny wzorzec.
  2. Zła długość całkowita albo skalowanie — symbol został przeskalowany po wyrenderowaniu, przez co X-dimension spadła poniżej minimum GS1 (zwykle 0,495 mm przy współczynniku powiększenia 1,0×).

Oba przypadki dają ten sam objaw: skaner zapiszczy na pojedynczej próbce, ale w partii produkcyjnej pojawi się odrzut rzędu 1 na 30. QA tego nie wychwyci, bo skaner deweloperski bywa bardziej wyrozumiały niż skaner w magazynie.

Reguła 0,1 mm

Istotna precyzja to długość całego kodu kreskowego w tolerancji ≤ 0,1 mm względem celu ze specyfikacji. NIE chodzi o to, że “każda kreska ma 0,1 mm szerokości” — kreski mają zwykle 0,495 mm albo więcej. Granica 0,1 mm dotyczy skumulowanej dokładności wymiarowej całego symbolu.

Dla typowego GS1-128 z 18 cyframi:

  • Symbol zawiera około 120 kresek i przerw
  • Długość całkowita przy powiększeniu 1,0×: około 58 mm
  • Tolerancja 0,1 mm na całej długości = około 0,17% dokładności
  • W przeliczeniu daje to około 0,001 mm budżetu spójności na kreskę — znacznie mniej niż szerokość pojedynczej kreski

Właśnie dlatego sytuacja “generator rysuje kreskę 7 px tam, gdzie powinna mieć 7,4 px” jest krytyczna. Zaokrąglenia subpikselowe kumulują się przez około 120 kresek i gdzieś między kreską 50 a 80 przekraczasz tolerancję 0,1 mm.

Dlaczego HTML/CSS ma z tym problem

Ścieżka, na której potyka się wiele zespołów: zakodować dane GS1-128 do ciągu, wygenerować SVG (albo gorzej, osobne kreski jako <div>), osadzić w HTML i wyrenderować PDF przez Puppeteer albo Prince.

Każde ogniwo tego łańcucha może wprowadzić dryf.

1. Przeglądarka zaokrągla podczas rasteryzacji

Nawet SVG osadzone w HTML jest zaokrąglane subpikselowo przez mechanizm malowania przeglądarki, chyba że ustawisz shape-rendering="crispEdges", otaczający kontener trafi w całkowitą granicę pikseli, a DPI PDF czysto mnoży się do szerokości kresek. To trzy warunki, które łatwo przypadkowo złamać.

2. CSS przesuwa układ

transform: scale(0.95) gdzieś w arkuszu stylów — dodane pół roku wcześniej, żeby naprawić zupełnie inny problem układu — po cichu zniekształci każdy kod kreskowy na stronie. Nie ma ostrzeżenia. PDF wygląda dobrze. Skaner nie.

3. Emiter PDF ma własną kwantyzację

Gdy przeglądarka zapisuje wynik do PDF, konwertuje namalowany obraz na operatory rysowania PDF. Niektóre emitery, zwłaszcza Chromium, przyciągają wartości do stałej wewnętrznej siatki PDF. Dla kodu SVG ustawionego na współrzędnych niepasujących do tej siatki wynik jest prawie poprawny, ale błąd się kumuluje.

4. Kodowanie fontem jest jeszcze gorsze

Niektóre zespoły używają fontu Code 128 ({ font: "Code128" }), wpisują dane i liczą, że będzie dobrze. Fonty są wektorowe i teoretycznie skalowalne, ale hinting fontów przy małych rozmiarach przesuwa szerokości tak, by wyglądały lepiej dla ludzi — dokładnie odwrotnie niż potrzebuje skaner.

Podejście ze strukturalnym renderowaniem

gPdf przyjmuje dane, oblicza wzorzec kresek i przerw ze specyfikacji GS1-128, a następnie emituje prymitywy wektorowe PDF bezpośrednio — bez HTML, bez tłumaczenia SVG i bez hintingu fontów:

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

Dla elementu barcode pole width oznacza całkowitą długość symbolu (w mm) — dokładnie to, co zmierzysz suwmiarką na wydrukowanej etykiecie. To właściwe pokrętło sterujące i to właśnie gwarantuje width: 58.0:

  • Generator oblicza X-dimension, dzieląc docelową długość przez liczbę kresek symbolu, która wynika w pełni z danych.
  • Każda kreska jest rysowana z dokładnie tą samą X-dimension.
  • Szerokości trafiają do PDF jako współrzędne zmiennoprzecinkowe (jednostka PDF = 1/72 cala, czyli dokładniej, niż potrzeba przy rozdzielczości skanowania).
  • Bez hintingu fontów, bez zaokrąglania pikseli CSS i bez zniekształcenia przez przebieg układu.

Rezultat: długość całkowita mieści się w ≤ 0,1 mm od żądanego celu na każdej drukarce, która nie dodaje własnego skalowania (większość domyślnie tego nie robi).

Co faktycznie drukować

Trzy reguły zapobiegają 95% produkcyjnych problemów ze skanowaniem.

Reguła 1: podawaj długość całkowitą, nie X-dimension

Pole width jest właściwym parametrem, bo jest mierzalne — można przyłożyć suwmiarkę do wydrukowanej etykiety i sprawdzić je bezpośrednio. Podanie samej X-dimension oznacza, że długość symbolu zależy od długości zakodowanych danych, co utrudnia QA etykiet (inny SKU = inna szerokość kodu).

Dla większości rozmiarów etykiet:

  • Etykieta wysyłkowa 4×6 in: 100 mm szerokości, GS1-128 powinien mieć około 58-72 mm
  • Etykieta zgodności 4×4 in: około 45-58 mm
  • Etykieta kartonu 2×1 in (Amazon UPC): to nie obszar GS1-128, użyj UPC-A

Reguła 2: strefy ciszy, zawsze

GS1-128 potrzebuje stref ciszy ≥ 10X po obu stronach — pustej białej przestrzeni, której skaner używa do znalezienia krawędzi symbolu. Przy powiększeniu 1,0× (X = 0,495 mm) oznacza to ≥ 4,95 mm wolnego miejsca.

Klasyczny tryb awarii: deweloper ustawia kod kreskowy na x: 0, żeby zmieścić go obok innych elementów etykiety, a skaner nie może znaleźć początku. Generator powinien automatycznie rezerwować strefy ciszy (gPdf to robi); warto sprawdzić własny.

Reguła 3: testuj na docelowym skanerze, nie deweloperskim

Skaner w aparacie telefonu jest bardziej wyrozumiały niż przemysłowy Honeywell albo Zebra. Standardowa ścieżka QA:

  1. Wydrukuj 50 etykiet na realnej drukarce produkcyjnej, z produkcyjną prędkością.
  2. Przepuść je przez realny typ skanera, przy realnej prędkości przenośnika.
  3. Skuteczność odczytu < 99% oznacza, że coś jest nie tak — zwykle spójność X-dimension.

Nie wysyłaj partii do partnerów logistycznych na podstawie “u mnie skanuje się kamerą MacBooka”.

Rzeczywistość wielu formatów

Etykieta prawdopodobnie potrzebuje więcej niż samego GS1-128. Typowe kombinacje:

Symbol Zastosowanie Źródło specyfikacji
GS1-128 Jednostki logistyczne, GTIN + numer seryjny + partia GS1 General Specifications
QR z FNC1 Ecommerce skanowany urządzeniem mobilnym ISO/IEC 18004
Data Matrix Farmacja (DSCSA / EU FMD) ISO/IEC 16022
PDF417 Prawa jazdy, karty pokładowe ISO/IEC 15438
Aztec Bilety transportowe ISO/IEC 24778
MaxiCode Szczególnie UPS ISO/IEC 16023

Generator obsługujący tylko GS1-128 prędzej czy później zmusi Cię do drugiego narzędzia. W jednym silniku obsługujemy wszystkie sześć formatów, bo procesy wysyłkowe i logistyczne prawie zawsze potrzebują co najmniej dwóch.

Obsługa odrzuceń skanera w produkcji

Jeżeli masz już na produkcji problem z odrzuceniami skanera, kolejność diagnostyki jest następująca:

  1. Pobierz próbki nieudanych etykiet — nie polegaj wyłącznie na metrykach zbiorczych. Zdobądź fizyczną etykietę, która nie przeszła.
  2. Zmierz suwmiarką — długość całkowitą i X-dimension. Jeżeli nie mieszczą się w tolerancji specyfikacji, to jest błąd.
  3. Sprawdź tekst czytelny dla człowieka poniżej — skanery, które nie czytają kresek, często próbują OCR jako ścieżkę awaryjną. Jeżeli oba odczyty zawodzą, symbol jest faktycznie wadliwy.
  4. Zweryfikuj strefy ciszy — zmierz białą przestrzeń po obu stronach. Jeżeli coś wydrukowało się zbyt blisko (logo, linia podziału, inny kod kreskowy), to jest problem.
  5. Spróbuj innego modelu skanera — niektóre skanery mają osobliwości firmware’u. Jeżeli model A czyta etykietę, a model B nie, problemem jest interoperacyjność, nie sam generator.
  6. Porównaj ze znaną poprawną etykietą referencyjną — dostawcy publikują obrazy referencyjne w dokładnych specyfikacjach. Jeżeli Twoja etykieta nie wygląda tak samo, pracuj wstecz od różnicy.

TL;DR

Precyzja GS1-128 nie polega na tym, jak cienkie kreski potrafisz wydrukować — chodzi o to, czy X-dimension pozostaje spójna w całym symbolu w granicach ułamka milimetra. Generatory oparte na HTML/CSS wprowadzają dryf subpikselowy na kilku etapach; strukturalne generatory emitujące bezpośrednio prymitywy wektorowe PDF pomijają te źródła dryfu.

Jeżeli w obecnym stosie PDF widzisz 1-5% odrzuceń skanera, to jest główny podejrzany. Playground potrafi wyrenderować próbkę GS1-128 z polem width ustawionym dokładnie pod specyfikację etykiety — wydrukuj wynik, zmierz suwmiarką i porównaj.