Если вы отправляете физические товары, рано или поздно придется напечатать GS1-128, который прочитает реальный ручной сканер в реальном складе. Это выглядит скучной деталью, но в генерации PDF именно она часто дает самые шумные отказы.
Разберем, что означает точность “0,1 mm” для GS1-128, почему цепочка HTML/CSS плохо удерживает такую геометрию и какие правила помогают пройти сканеры DHL, FedEx, USPS и Amazon inbound.
Что такое точность штрихкода
GS1-128 (бывший UCC/EAN-128) кодирует данные через ширину штрихов и промежутков с заданными пропорциями. Базовая единица — X-dimension, ширина самого узкого штриха или пробела. Остальные ширины кратны X.
Сканер измеряет относительные ширины. В production чаще всего ломаются две вещи:
- Непостоянная X-dimension внутри символа: renderer по-разному округляет соседние штрихи на sub-pixel уровне.
- Неверная общая длина или масштаб: символ сначала рисуют, потом масштабируют, и 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
- Возьмите реальные отказавшие этикетки.
- Измерьте штангенциркулем общую длину и X-dimension.
- Проверьте человекочитаемый текст под символом.
- Измерьте quiet zones с обеих сторон.
- Попробуйте другой scanner model.
- Сравните с эталонной этикеткой.
TL;DR
Точность GS1-128 — не про то, насколько тонкий штрих можно напечатать. Она про постоянную X-dimension по всему символу и общую длину в пределах долей миллиметра. HTML/CSS добавляет sub-pixel drift на нескольких этапах; прямые PDF vector primitives убирают эти источники ошибки.
Если текущий PDF stack дает 1–5% отказов сканера, начните здесь. Playground может сгенерировать GS1-128 с width точно по вашей спецификации; распечатайте и измерьте.