Блог

GS1-128 с точностью 0,1 mm из JSON

GS1-128 кажется простым, пока сканер не перестает читать этикетку на 240 dpi. Практика по общей длине, X-dimension, quiet zones и ограничениям HTML/CSS.

Если вы отправляете физические товары, рано или поздно придется напечатать GS1-128, который прочитает реальный ручной сканер в реальном складе. Это выглядит скучной деталью, но в генерации PDF именно она часто дает самые шумные отказы.

Разберем, что означает точность “0,1 mm” для GS1-128, почему цепочка HTML/CSS плохо удерживает такую геометрию и какие правила помогают пройти сканеры DHL, FedEx, USPS и Amazon inbound.

Что такое точность штрихкода

GS1-128 (бывший UCC/EAN-128) кодирует данные через ширину штрихов и промежутков с заданными пропорциями. Базовая единица — X-dimension, ширина самого узкого штриха или пробела. Остальные ширины кратны X.

Сканер измеряет относительные ширины. В production чаще всего ломаются две вещи:

  1. Непостоянная X-dimension внутри символа: renderer по-разному округляет соседние штрихи на sub-pixel уровне.
  2. Неверная общая длина или масштаб: символ сначала рисуют, потом масштабируют, и X-dimension падает ниже минимума GS1, обычно 0,495 mm при 1,0×.

Одна тестовая этикетка может сканироваться, а партия даст отказы 1 из 30. Складской сканер обычно менее снисходителен, чем устройство разработчика.

Правило 0,1 mm

Важна общая длина штрихкода с допуском до 0,1 mm от целевого размера. Это не значит, что каждый штрих имеет ширину 0,1 mm; обычно он 0,495 mm или больше.

Для типичного GS1-128 с 18 цифрами:

  • В символе около 120 штрихов и промежутков
  • Общая длина при 1,0× около 58 mm
  • 0,1 mm допуска — это примерно 0,17% по всей длине
  • На один штрих остается около 0,001 mm бюджета

Поэтому штрих, который должен был быть 7,4 px, но стал 7 px, уже опасен. Ошибка округления накапливается по всему символу.

Почему HTML/CSS здесь слабое место

Типичный путь: сгенерировать SVG, вставить в HTML и превратить страницу в PDF через Puppeteer или Prince. На каждом шаге может появиться геометрический дрейф.

1. Браузер округляет при rasterisation

Даже SVG внутри HTML проходит через painter браузера. Нужны shape-rendering="crispEdges", целочисленные границы пикселей и чистое соответствие DPI ширине штриха. Это легко случайно нарушить.

2. CSS может незаметно масштабировать

Старый transform: scale(0.95) в stylesheet искажает все barcode на странице. PDF выглядит нормально, но сканер измеряет уже другую геометрию.

3. PDF emitter квантует координаты

Некоторые движки при записи PDF привязывают координаты к внутренней сетке. Результат почти правильный, но ошибка копится.

4. Шрифтовой Code 128 еще хуже

Шрифт векторный, но hinting меняет малые ширины ради визуального качества для человека. Для сканера это неправильная оптимизация.

Структурный рендеринг

gPdf вычисляет pattern штрихов и промежутков по спецификации GS1-128 и пишет PDF vector primitives напрямую: без HTML, без SVG translation и без 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" }
      }
    ]
  }]
}

Для элемента barcode поле width — это общая длина символа в mm, которую можно измерить штангенциркулем на распечатанной этикетке. width: 58.0 означает:

  • Renderer вычисляет X-dimension из целевой длины и числа модулей.
  • Каждый штрих рисуется с одной и той же X-dimension.
  • Ширины записываются в PDF floating-point координатами.
  • Нет CSS pixel rounding, layout scaling и font hinting.

Если принтер сам не применяет масштабирование, общая длина остается в пределах 0,1 mm от цели.

Что реально печатать

Правило 1: задавайте общую длину

width — правильный параметр, потому что его можно измерить. Если задавать только X-dimension, длина символа будет меняться с данными.

  • Shipping label 4×6 in: ширина 100 mm, GS1-128 обычно ~58–72 mm
  • Compliance label 4×4 in: ~45–58 mm
  • Carton label 2×1 in (Amazon UPC): это не GS1-128, используйте UPC-A

Правило 2: quiet zones всегда

GS1-128 требует quiet zones ≥ 10X с обеих сторон. При 1,0× (X = 0,495 mm) это минимум 4,95 mm чистого белого поля. Размещение в x: 0 часто ломает поиск начала символа. gPdf резервирует эти зоны автоматически.

Правило 3: тестируйте на целевом сканере

Камера телефона прощает больше, чем промышленный Honeywell или Zebra. Напечатайте 50 этикеток на production printer, в реальной скорости, и прогоните через реальный scanner. Read rate ниже 99% обычно указывает на X-dimension.

Многоформатная реальность

Этикетке часто нужен не только GS1-128:

Symbol Назначение Источник спецификации
GS1-128 Логистические единицы, GTIN + serial + lot GS1 General Specifications
QR with FNC1 Ecommerce, сканирование с телефона ISO/IEC 18004
Data Matrix Фармацевтика (DSCSA / EU FMD) ISO/IEC 16022
PDF417 Водительские права, посадочные талоны ISO/IEC 15438
Aztec Транспортные билеты ISO/IEC 24778
MaxiCode Конкретно UPS ISO/IEC 16023

Renderer только для GS1-128 со временем потребует вторую систему. В логистике почти всегда нужны минимум два формата.

Диагностика отказов в production

  1. Возьмите реальные отказавшие этикетки.
  2. Измерьте штангенциркулем общую длину и X-dimension.
  3. Проверьте человекочитаемый текст под символом.
  4. Измерьте quiet zones с обеих сторон.
  5. Попробуйте другой scanner model.
  6. Сравните с эталонной этикеткой.

TL;DR

Точность GS1-128 — не про то, насколько тонкий штрих можно напечатать. Она про постоянную X-dimension по всему символу и общую длину в пределах долей миллиметра. HTML/CSS добавляет sub-pixel drift на нескольких этапах; прямые PDF vector primitives убирают эти источники ошибки.

Если текущий PDF stack дает 1–5% отказов сканера, начните здесь. Playground может сгенерировать GS1-128 с width точно по вашей спецификации; распечатайте и измерьте.