Всем привет.

На текущем месте работы, в один момент, мне пришлось экстренно разобраться с печатью этикеток на принтеры Zebra. Так как информации в сети(особенно на русском) оказалось не так много, я как добросовестный программист обратился к документации. В этой статье хотелось бы сделать выжимку, для таких же счастливчиков как я, о том, что такое язык ZPL, как с ним работать и с чем я столкнулся в процессе своих познаний.

Как же всё работает

Если вкратце, то принтер Zebra и ему подобные, эмулирующие в себе ZPL, принимают на вход специальную строку с ПК, обрабатывают её и выводят на печать. Всё просто. Но вот как эту самую строку корректно сформировать, чтобы принтер всё понял?

Пример этикетки с QR-кодом

^XA
^FO50,80^A0,30,50 ^FDSamsung Galaxy S22^FS
^FO50,130^A0,30,50 ^FDSM-S908BDRHSKZ^FS
^FO50,180^A0,30,50 ^FDExynos 2200^FS
^FO50,230^A0,30,50 ^FDXclipse 920^FS
^FX Для примера этикетки взял информацию о смартфоне.
^FO490,30 ^BY5,2.0,50 ^BQN,2,6 ^FD   Смартфон Samsung Galaxy S22 Ultra^FS
^BY5,2,270
^FO50,280^BC^FD12345678^FS
^XZ

И вот что у нас получилось:

Что же мы имеем?

Исходя из представленного выше кода, управляющий символ в ZPL это "^". После него следует команда отвечающая за тот или иной аспект настройки этикетки.

Давайте же узнаем о них.

^XA и ^XZ - открывающий и закрывающий символ.

^FOx,y - отступ от левого верхнего края, принимает значение от 0 до 32000

^Af,h,w - изменение шрифта для последующего текста
f - сам шрифт, может быть в значении 0-9 либо A-Z
h - высота (от 1 до 32000)
w - ширина (от 1 до 32000)
Так же после f, перед запятой можно использовать символ вращения R - 90°, I - 180°, B - 270°

^FDdata - символ начала поля данных

^FS - символ конца определения поля

^FX - комментарий

Используя эти символы можно начать выводить простые текстовые этикетки.
Например:

^XA
^FO50,80^A0,30,50 ^FDSamsung Galaxy S22^FS
^FO50,150^AEI,5,5 ^FDSamsung Galaxy S22^FS
^FO50,230^AVR,30,50 ^FDSamsung Galaxy S22^FS
^FO180,230^AAB,50,20 ^FDSamsung Galaxy S22^FS
^XZ

Но стоит знать то, что не каждый шрифт поддаётся редактированию по размеру!
Получим:

^FB maxWidth, maxLines, lineSpacing, alignment, hangingIndent
maxWidth - ширина (от 0 до 9999)
maxLines - количество строк (от 1 до 9999)
lineSpacing - пробелы между строками (от -9999 до 9999)
alignment - выравнивание ( L (по левому краю), R (по правому краю), C (по центру),
J (растянуть текст по ширине поля) Дефолтное значение - L
hangingIndent - отступ от строки (от 0 до 9999)

Теперь добавим это в наш код и посмотрим, что будет:

^XA
^FB200,5,5,C
^FO50,80^A0,30,50 ^FDSamsung Galaxy S22^FS
^FB400,5,5,J
^FO50,220^A0,30,50 ^FDSamsung Galaxy S22^FS
^XZ

Первый текст получил "окно" шириной 200 точек и максимальным количеством строк = 5 с выравниванием по центру. В 200 точек влезало только одно слово, из-за этого текст разбился на 3 строки
А второй тест получил 400 точек и выравнивание по ширине поля. Два слова влезли в первую строку, но получился большой пробел, в который, однако, не влезло третье слово

Как видно, меняя эти параметры можно получить тест абсолютно любого формата

Штрих-коды

Штрих-кодов в документации описано огромное количество, но я для себя выделил 4 основных:

  1. ^BC - orientation, height, line, lineAbove, checkDigit, mode - Code 128 Bar code
    orientation - вращение (R - 90°, I - 180°, B - 270°)
    height - высота (от 1 до 32000)
    line - печатать ли расшифровку (Y,N)
    lineAbove - расшифровка сверху (Y,N)

^XA
^BY5,2,200
^FO50,50^BCN,,Y^FD12345678^FS
^XZ

Сразу опишу настройки, применимые ко всем штрих-кодам:
^BY width, widthRatio, height
width - ширина (от 1 до 100)
widthRatio - соотношение толщин линий (от 2.0 до 3.0 шаг 0.1)
height - высота (любое положительное число)
^FD - кодируемая информация

  1. ^BE - EAN-13 Bar Code
    Настройки такие же, что и у ^BC

^XA
^FO50,50^BY3
^BEN,80,Y
^FD000012345678^FS
^XZ
  1. ^BQ orientation, model, magnification, errorCorrection- QR Code Bar code
    orientation - вращение QR (R - 90°, I - 180°, B - 270°)
    model - обычный или улучшенyый QR (1 или 2) Важно! Современными принтерами Zebra, model(1) не воспринимается, рекомендовано использовать (2)
    magnification - увеличение QR (от 1 до 10)
    errorCorrection - H = ultra-high reliability level, Q = high reliability level, M = standard level L = high density level (Рекомендую использовать H)

    Ещё один важный момент
    По какой-то причине, некоторые принтеры не хотят воспринимать последний параметр после ^BQ, но воспринимают его после ^FD:

^FX вместо:
^XA
^FO50,50
^BQN,2,3,H
^FDSamsung Galaxy S22^FS
^XZ

^FX используй:
^XA
^FO50,50
^BQN,2,3
^FDH,Samsung Galaxy S22^FS
^XZ
  1. ^BX - orientation, height, quality, columns, rows, format, escape - Data Matrix
    orientation - думаю, тут уже понятно))
    height - высота (от 1 до размера листа)
    quality - качество DM (0, 50, 80, 100, 140, 200) рекомендованный - 200
    columns, rows - количество кодируемых колонок и строк (от 1 до 144)
    format - формат DM (от 0 до 6) не используется при качестве 200
    escape - эскейп символ, может использоваться любой символ, дефолтное значение тильда (~). При массовой печати стоит смотреть, не будет ли ваш эскейп символ передаваться в кодируемой информации. Я обычно использую бэкслеш (\)

С обычной кодировкой Data Matrix нет ничего сложного, просто передаётся информация и настраиваются параметры DM.
Например:

^XA
^FO50,50
^BXN,5,200,
^FDZPL (programming language) 
ZPL (short for Z-level Programming Language) is an array programming 
language designed to replace C and C++ programming languages in engineering 
and scientific applications. Because its design goal was to obtain 
cross-platform high performance, ZPL programs run fast on both sequential 
and parallel computers. Highly-parallel ZPL programs are simple 
and easy to write because it exclusively uses implicit parallelism.^FS
^XZ

Но как вам может быть известно, в России есть такая организация как "Честный знак" и они используют Data Matrix для маркировки товара(сигареты, алкоголь, обувь, лекарства)
В кодировку для Честного знака передаётся несколько полей, используя специальные разделители и передаваться они должны не просто строкой. DM то конечно составится, но только через проверку Честного знака он не пройдёт
В честном знаке используется открывающий символ FNC1 и разделители GS
Чтобы поставить FNC1 в начало строки необходимо использовать ваш ескейп символ и "1"
Т.е. ^BXN,5,200,,,,\,1 ^FD\1 и далее зашифрованный код маркировки
Символы GS как правило передаются внутри и прописывать из отдельно не приходится

Пример реальной этикетки Data Matrix:
P.S. Не обращайте внимание на непонятные символы переданные вместо текста, принтеры клиента лишь эмулируют ZPL, из-за чего не удалось установить на них драйвера для русского языка, в данном примере русские буквы пришлось зашифровать в URL.

^XA ^CI28
			^CFP,5,10 ^FO20,2 ^FH^FD_D0_9D_D0_B0_D0_B8_D0_BC_D0_B5_D0_BD_D0_BE_D0_B2_D0_B0_D0_BD_D0_B8_D0_B5 _D0_BF_D1_80_D0_BE_D0_B4_D1_83_D0_BA_D1_86_D0_B8_D0_B8: _D0_A0_D0_B5_D0_B7_D0_B8_D0_BD_D0_BE_D0_B2_D1_8B_D0_B5 _D0_A7_D0_81_D0_A0_D0_9D_D0_AB_D0_99^FS
			^CFP,5,10 ^FO20,20 ^FH^FD_D0_9C_D0_B0_D1_80_D0_BA_D0_B0_2F_D0_90_D1_80_D1_82_D0_B8_D0_BA_D1_83_D0_BB: Lemon Jelly/GRAD^FS
			^CFP,5,10 ^FO20,38 ^FH^FD_D0_A1_D0_BE_D1_81_D1_82_D0_B0_D0_B2 _D0_92_D0_B5_D1_80_D1_85_2F_D0_9F_D0_BE_D0_B4_D0_BA_D0_BB_D0_B0_D0_B4_D0_BA_D0_B0_2F_D0_9D_D0_B8_D0_B7: _D0_BF_D0_BE_D0_BB_D0_B8_D0_BC_D0_B5_D1_80_2F_D1_82_D0_B5_D0_BA_D1_81_D1_82_D0_B8_D0_BB_D1_8C_2F_D1_80_D0_B5_D0_B7_D0_B8_D0_BD_D0_B0^FS
			^CFP,5,10 ^FO20,56 ^FH^FD_D0_94_D0_B0_D1_82_D0_B0 _D0_B8_D0_B7_D0_B3: 202204 _D0_93_D0_B0_D1_80_D0_B0_D0_BD_D1_82_D0_B8_D0_B9_D0_BD_D1_8B_D0_B9 _D1_81_D1_80_D0_BE_D0_BA:30^FS
			^CFP,5,10 ^FO20,74 ^FH^FD_D0_A1_D1_82_D1_80_D0_B0_D0_BD_D0_B0 _D0_B8_D0_B7_D0_B3_D0_BE_D1_82_D0_BE_D0_B2_D0_B8_D1_82_D0_B5_D0_BB_D1_8C: _D0_9F_D0_9E_D0_A0_D0_A2_D0_A3_D0_93_D0_90_D0_9B_D0_98_D0_AF^FS
			^CFP,5,10 ^FO20,92 ^FH^FD_D0_9F_D1_80_D0_BE_D0_B8_D0_B7_D0_B2_D0_BE_D0_B4_D0_B8_D1_82_D0_B5_D0_BB_D1_8C: Design e More, S.A.^FS
			^CFP,5,10 ^FO20,110 ^FH^FD_D0_90_D0_B4_D1_80_D0_B5_D1_81 _D0_BF_D1_80_D0_BE_D0_B8_D0_B7_D0_B2_D0_BE_D0_B4_D0_B8_D1_82_D0_B5_D0_BB_D1_8F: Rua das Casas Queimadas n 567.4415-439 Grijo V/N Gaia, Portugal^FS
			^CFP,5,10 ^FO20,128 ^FH^FD_D0_9F_D1_80_D0_BE_D0_B4_D0_B0_D0_B2_D0_B5_D1_86 _D1_8E_D1_80_D0_B0_D0_B4_D1_80_D0_B5_D1_81 _D0_9E_D0_9E_D0_9E _D0_90_D0_A0_D0_95_D0_9D_D0_90 115 093 _D0_9C_D0_BE_D1_81_D0_BA_D0_B2_D0_B0 _D0_9F_D0_B0_D1_80_D1_82_D0_B8_D0_B9_D0_BD_D1_8B_D0_B9 _D0_BF_D0_B5_D1_80 _D0_B4 1^FS
			^CFP,5,10 ^FO20,146 ^FH^FD_D0_BA_D0_BE_D1_80_D0_BF 11 _D1_8D_D1_82_D0_B0_D0_B6 3 _D0_BA_D0_BE_D0_BC_D0_BD №34 _D0_98_D0_BD_D1_81_D1_82_D1_80_D1_83_D0_BA_D1_86_D0_B8_D1_8F _D0_BF_D0_BE _D1_83_D1_85_D0_BE_D0_B4_D1_83 _D0_B7_D0_B0 _D0_B8_D0_B7_D0_B4_D0_B5_D0_BB_D0_B8_D0_B5_D0_BC _D0_BF_D1_80_D0_B8_D0_BB_D0_B0_D0_B3_D0_B0_D0_B5_D1_82_D1_81_D1_8F^FS
			^CFP,5,10 ^FO20,164 ^FH^FD_D0_A0_D0_B5_D0_B7_D0_B8_D0_BD_D0_BE_D0_B2_D1_8B_D0_B5 _D0_A7_D0_81_D0_A0_D0_9D_D0_AB_D0_99^FS
			^CFP,5,10 ^FO20,182 ^FH^FDLemon Jelly^FS
			^CFP,5,10 ^FO20,200 ^FH^FDGRAD/231 11^FS
			^CFP,5,10 ^FO20,218 ^FH^FD02 black^FS
			^CFP,5,10 ^FO560,310 ^FH^FD04630162491475^FS
            ^CFP,5,10 ^FO560,330 ^FH^FD5aWoWlascYnb8^FS
			^FO 45,270 ^BY4 ^BEN,60,Y,N  ^FD2000016664232^FS 
			^FO465,265^GFA,294,294,7,,::1IF87FFE1IF8:::1EI0781E1E,:::::::::::1IF87FFE1E,:::1EI0781E1E,::::::::::::1IF8781E1IF8:::,: ^FS
			^CFT,5,10 ^FO600,25 ^FH^FD_D0_A0_D0_B0_D0_B7_D0_BC_D0_B5_D1_80^FS
			^CFT,5,10 ^FO635,100  ^FD037^FS
			^FO560,150 ^BXN,4,200,,,,\,1 ^FD\10104630162491475215aWoWlascYnb89100BE929+ipgNo9UkRCzC7IfwA5bk1MhoLw3tpy9377HN7wpKFuOnG3KAfasNiHNDjwjR019xcThmlABPWm1VJFj3dl1w==^FS
			^XZ

Отсканировав данный Data Matrix с помощью приложения Checkmark или Честный знак, вы увидите что он принадлежит Резиновым сапогам

P.P.S. для редактирования этикеток без печати я использую: Labelary Online ZPL Viewer
Там есть подсказки, для начала работы с ZPL это очень удобно.

Так же приложу ссылку на документацию: ZPL II Programming Guide (servopack.de)

Спасибо за уделённое время, буду рад вашим советам

Комментарии (13)


  1. sepetov
    10.08.2022 10:50
    +1

    Статья размещена в хабах .net и Microsoft SQL Server, но о них в статье не упомянуто. Если возможно, неплохо было бы развить и эту тему, а то сейчас в статье только о ZPL.

    Например, было бы интересно услышать о том, на каком подходе вы остановились при хранении в таблицах datamatrix-ов: бинарный image/blob или текст, если текст, то вырезаете ли FNC1 или он вам неудобств в хранении не доставляет?


    1. Emulyator
      10.08.2022 14:50

      А почему бы не генерировать qr-код и этикетку автоматически при печати, зачем хранить?


      1. sepetov
        10.08.2022 18:15

        Один раз только видел хранение в blob-е и не было возможности спросить причину. Возможно, она всё-таки существует :-)

        Лично я храню в тексте и без управляющих символов - они только мешают. При печати подставляю их автоматически. Если интересно, чем мешают, то немногим:

        1. Управляющие символы трудно набрать с клавиатуры, поэтому неудобно вручную делать запросы "SELECT * FROM table_name WHERE barcode='xxx'". Это приходится делать часто при разборе ошибок, а при внедрении - вообще ежедневно.

        2. Управляющие символы часто "теряются" при передаче между разными приложениями. Например, приходилось импортировать штрихкоды из какой-то старой версии 1С, которая не могла передать FNC1 ни в каком виде: ни в файлах, ни через внешние источники данных, ни через post-запрос.

        3. Иногда приходится пользоваться сканерами, работающими в разрыв клавиатуры, а они в нём не умеют их передавать.

        Мой опыт кратенько выглядит как-то так.


  1. slepmog
    10.08.2022 11:10
    +4

    ^FOx,y — отступ от левого верхнего края, принимает значение от 0 до 32000

    А измеряются x и y в единицах, заданных последней командой ^MU. По умолчанию это точки, чей размер зависит от разрешения принтера. Для создания этикеток, одинаково выглядящих на принтерах с разным разрешением, удобно работать в миллиметрах, ^MUm.


    При этом стоит всегда возвращать единицы к точкам в конце этикетки: ^MUd^XZ.
    Это потому, что драйверы Zebra, когда транслируют печать из обычного приложения в ZPL, обнуляют все персистентные параметры, а единицы измерения обнулить забывают. (Писали про это в поддержку; не удалось попасть на кого-то, кто понял бы, о чём мы вообще.)
    В результате драйвер выдаёт команду напечатать что-то по координатам, скажем, (1000, 500), думая, что это в точках. Но поскольку последний заданный режим был в миллиметрах, картинка рисуется на метр вправо от границы этикетки, и этикетка выходит пустой.


    При этом в режиме без поворотов, отражений и справаналевости ^FO определяет левый верхний угол результирующей строки/картинки/штрихкода. ^FT определят левый нижний. Иногда удобно одно, иногда другое.


    ^FDdata — символ начала текстового поля

    Нет, это символ начала поля данных. Эти данные могут принадлежать чему угодно, не только текстовому полю. В частности, это может быть наполнение штрих-кода.


    ^FS — символ конца строки

    Нет, это символ конца определения поля, начатого ранее. Концы строк сами по себе никак не маркируются.


    ^FB maxWidth, maxLines, lineSpacing, alignment, hangingIndent

    Полезно помнить, что ^FB — уникальная команда, которая недокументированно игнорирует единицы измерения, заданные в ^MU, и трактует все свои измерения как заданные в точках.
    Полезно также помнить, что если текст не уместится в maxLines, то весь не уместившийся текст будет печататься поверх последней строки, снова и снова, пока не кончится.


    Тема ^TB, улучшенной версии ^FB, не раскрыта!


    По какой-то причине, некоторые принтеры не хотят воспринимать последний параметр после ^BQ, но воспринимают его после ^FD:

    Потому что документировано, что для ^BQ строка данных ^FD должна начинаться с дескриптора, описывающего характеристики QR. Если его опустить, могут быть потеряны первые три символа данных.


    1. kudlitzz Автор
      10.08.2022 12:43
      +1

      Спасибо за развёрнутый комментарий.
      Исправил указанные Вами неточности.
      С ^TB не сталкивался, поэтому не описал в статье, учту в дальнейшей работе.


  1. slavius
    10.08.2022 12:20
    +1

    Отдельное спасибо за

    для редактирования этикеток без печати я использую: Labelary Online ZPL Viewer


    1. tooler
      10.08.2022 14:11

      Во внутреннем вебинтерфейсе принтера тоже есть предпросмотр из кода, но на этом сайте намного удобнее работает. Содержимое каталога, создать сценарий, изменить, предварительный просмотр наклейки.


      1. kudlitzz Автор
        10.08.2022 14:29

        Да, так же мне показалась удобной возможность передать изображение сразу при написании этикетки


  1. kurilovigor
    11.08.2022 12:07

    Тоже начинали с ZPL, потом перешли на печать через драйвер печати. Отказ ZPL помог легко перейти на дешевые и качественные китайские принтеры


    1. sepetov
      11.08.2022 12:53

      Под Linux не пробовали?


      1. kurilovigor
        11.08.2022 18:23

        на линуксе имею опыт печати на зебру только ZPL через SMB


  1. ioncorpse
    11.08.2022 17:37
    +2

    Где же вы раньше были?

    Не читал, но одобряю. Не читал т.к. 4 месяца назад мне вот ровно вот это все нужно было для Честного Знака, генератор ZPL команд писал. Пришел к тем же ресурсам и всей информации в итоге, что и вы. Особенно тогда пригодилась бы инфа про FNC1 и GS.


  1. sukhe
    11.08.2022 20:48
    +2

    Штрихкоды — ерунда. Вот с печатью картинок на этикетках коллеги знатно помучились. Особенно, когда кроме Зебры одновременно используются ещё и другие аналогичные принтеры, которые хотя и совместимы, но есть нюансы.

    Картинки — это всякие там рюмочки (хрупкое), стрелочки, указывающие направление верха, знаки переработки, значки стантдартов и прочее.

    Отдельный квест — подбор этикеток и риббонов (красящих лент). Когда расход измеряется в сотнях километров, хочется подешевле; но тогда уже качество страдает. Ну и этикетки разные нужны — в гарантийный талон и обычные подойдут, а на изделия нужны устойчивые к истиранию и мойке.