Добрый день, Хабрахабр.


Благодаря тепло принятой прошлой публикации, я могу опубликовать здесь эту статью. Спасибо всем, кто ставил плюсы.
По долгу службы мне частенько приходится формировать отчеты для этикеточных принтеров семейства Zebra.

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

Пример:
^XA
^FO 0,10
^GB632,0,2^FS
^FO0,25
^FB632,1,0,C,0
^ASN,70,70
^FDWAR INC.^FS
^FO0,100
^GB632,0,2^FS
^FO0,120
^FB632,1,0,C,0
^ASN,60,60
^FDGoose^FS
^FO0,180
^FB632,1,0,C,0
^ASN,60,60
^FDWild^FS
^FO0,240
^GB632,0,2^FS
^FO120,260
^BY2
^BCN,70,N,N,N
^FDSECRECTCODE^FS - 
^XZ

А на печать выводится такой аккуратный бейджик:

Давайте разберемся, что же написано в этом коде, и рассмотрим основные элементы.
Первую часть своего выступления я посвящу разбору синтаксиса этого языка, в объеме достаточном для создания этикеток удовлетворительного качества. Во-второй части, приведу примеры кода на Java и VisualBasic, для того, чтобы отправить этикетку на печать самостоятельно. На основе этих примеров, вы сможете самостоятельно построить свою програму, для печати.

Часть 1. Синтаксис ZPL

Во первых, все измерения в ZPL указываются в точках (points). Поэтому, для более ясного представления вы должны посмотреть в документации на принтер, какая у вас плотность точек на единицу измерения длины.
Сначала кратко пробежимся по основным командам, затем рассмотрим их более подробно в связке.
1. Начало и конец ZPL-кода:
^XA – начало кода, ^XZ – конец кода;

2.Отступы для последующего содержимого:
^FO x,y где: x – отступ от левого края, y – отступ сверху;

3.Разделитель полей:
^FS — обозначает конец определения поля. Буквально можно считать его сигналом конца строки;

4.Масштабируемый текст. Состоит из двух частей, выбор шрифта и ввод текста:
4.1. Выбор шрифта:
^A<название шрифта><ориентация текста>,<высота шрифта в точках>,<ширина в точках>:
<название шрифта> – по-умолчанию стоит A. Точнее ее даже не надо вводить, другие шрифты можно взять из официальной документации:

<ориентация текста>:
N – нормальная ориентация; R – повернуто на 90 градусов по часовой стрелке;
I – перевернуто на 180 градусов; B – повернуто на 270 градусов;

4.2. Вывод текста с параметрами указанными в предыдущем пункте:
^FD<текст>

Примеры:
^XA
^FO20,20  - отступ по 20 точек от верхнего и левого края этикетки
^ASN,70,70 - нормальная ориентация, шрифт S, высота и ширина 70 точек
^FDWAR INC.^FS – содержание текста WAR INC.
^XZ



Повернем, и изменим шрифт:
^XA
^FO20,20  - отступ по 20 точек от верхнего и левого края этикетки
^ABB,30,30 - повернуто на 270 градусов, шрифт B, высота и ширина 30 точек
^FDWAR INC.^FS – содержание текста WAR INC.
^XZ



Изменим шрифт на S:
^XA
^FO20,20  - отступ по 20 точек от верхнего и левого края этикетки
^ASB,30,30 - повернуто на 270 градусов, шрифт S, высота и ширина 30 точек 
^FDWAR INC.^FS – содержание текста WAR INC.
^XZ



Обязательно запомните, что разные шрифты могут выглядеть по разному, в отношении размеров, как можно видеть выше. Я чаще всего использую шрифт S.
5.Блок текста:

^FB<ширина>,<количество строк>,<пробелы между строками>,<выравнивание текста>,< отступ для второй или последующей строки>
<положение текста> — может принимать значения: L(по левому краю), R (по правому краю), C (по центру), J (растянуть текст по ширине поля);
Обычно я использовал данную команду для центрирования текста, или если необходимо разместить текст в несколько строчек. Если текст не умещается в строку, он начинает накладываться сам на себя. И получается так:
^XA
^FO 20,20
^FB400,1,0,C,0
^AVN,70,70
^FDWAR INC WILD GOOSE^FS
^XZ



Изменим код, чтобы было две строки, и расстояние между строчками сделаем в 10 точек:
^XA
^FO 20,20
^FB400,2,10,C,0
^AVN,70,70
^FDWAR INC WILD GOOSE^FS
^XZ



А теперь сделаем отступ для второй строки в 30 точек влево:
^XA
^FO 20,20
^FB400,2,10,L,30
^AVN,70,70
^FDWAR INC WILD GOOSE^FS
^XZ



6. Рисование прямоугольников:

^GB<ширина>,<высота>,<толщина линии>, (<цвет линии>, <скругление углов>)
В скобках указаны не обязательные параметры.
Цвет линии: B (черный) или W (белый)
Скругление углов указывается цифрой от 0, до 8 (сильное скругление)
Примеры:
С сильным скруглением:
^XA
^FO20,20 
^GB300,100,2,B,8^FS
^XZ



Без скругления:
^XA
^FO20,20 
^GB300,100,2^FS
^XZ



Если хотим нарисовать просто линию, то рисуем прямоугольник с высотой равной 0:
^XA
^FO20,20 
^GB300,0,2^FS
^XZ



7.Штрихкод состоит из трех команд – первая задает его размеры, вторая настройки и третья — содержание:

7.1.Размеры штрихкода:
^BY<ширина>, (<cоотношение толщин линий>, <высота штрихкода>)

7.2. Настройки штрихкода:
^BC<ориентация>,<высота штрихкода в точках>, <печатать ли расшифровку кода>, <расшифровка кода над штрихкодом>, <режим>
<ориентация> — N – нормальная ориентация; R – повернуто на 90 градусов по часовой стрелке; I – перевернуто на 180 градусов; B – повернуто на 270 градусов;
<печатать ли расшифровку кода>, <расшифровка кода над штрихкодом> — принимают значения Y (да) или N (нет);
<режим> — с этим полем я не разобрался, по умолчанию N;
^BC – штрихкод в стандарте 128 (подробнее Code_128); Есть также еще несколько форматов, но ввиду того, что мне не приходилось ими пользоваться, в данной статье они рассматриваться не будут, и рекомендую посмотреть информацию по ним в официальной документации поставляемой к принтерам Zebra;


7.3. Вывод штрихкода на печать:
^FD<кодируемая информация>
К сожалению, штрихкод нельзя поместить в «коробку», как текст, чтобы отцентрировать по ширине этикетки, и поэтому приходится шаманить с полями и отступами.


Примеры:
^XA
^FO 20,20
^BY3
^BCN,100,Y,N,N 
^FD123456789^FS 
^XZ



Перевернем, и укажем печатать расшифровку сверху (сейчас получилось снизу):
^XA
^FO 20,20
^BY3
^BCI,100,Y,Y,N 
^FD123456789^FS 
^XZ



На этом остановимся на рассмотрении основных элементов ZPL, и перейдем к части второй, в которой вкратце рассмотрим механизм отправки информации на принтер.

Часть 2. Печать

Механизм передачи проще некуда. Для этого, мы должны знать IP, где находится принтер, и порт. Далее, формируем поток, который отправляем по указанному адресу, и получаем на выходе этикетку.
Пример на Visual Basic:
Dim i As Double
        Dim SSCC As String
        Dim ipAddress As String = "127.0.0.1"
        Dim port As Integer = 1234
        Dim ZPLString As String
      
        Try
         'Открываем соединение
        Dim client As New System.Net.Sockets.TcpClient    
        client.Connect(ipAddress, port)
        Dim writer As New System.IO.StreamWriter(client.GetStream())
       'Формируем ZPL-строку         
        ZPLString=  
        "^XA" &
	"^BY2" & 
	"^FO0,200" &
	"^FB632,2,0,C,0" &
	"^ASN,60,60" &
	"^FDHELLO HABRAHABR!!!^FS" &
	"^XZ"

      writer.Write(ZPLString)
      writer.Flush()
      'закрываем соединение
      writer.Close()
      client.Close()

Catch ex As Exception
End Try  
 

Пример на Java:
import java.io.IOException;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.net.Socket;

public class PrintToZebra {

	public static void main(String[] args) throws IOException {
		System.out.println("Готовлю к печати");
		try(Socket s = new Socket("127.0.0.1", 1234)){
		OutputStream out = s.getOutputStream();
		PrintWriter writer = new PrintWriter(out, true);
	      String ZPLString=  
	                "^XA" +
	                "^BY2" +              
	                "^FO0,200" +
	                "^FB632,2,0,C,0" +
	                "^ASN,60,60" +
	                "^FDHELLO HABRAHABR!!!^FS" +
	                "^XZ";
	        writer.println(ZPLString);
	        writer.flush();
	        System.out.println("Отправил на печать");
		}
	}
}

Как видите, ничего сложного. Надеюсь, что моя статья, облегчит путь отважным укротителям Зебр.
Засим позвольте откланяться. Жду советов, критики и поддержки.

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


  1. Alexufo
    11.09.2015 16:20

    Помоему в документации все прекрасно расписано и так с примерами. :-)
    Да и этот инструмент очень выручает
    labelary.com/viewer.html
    Хотя он и не воспроизводит все что требуется и может глючить с размерами шрифтов.


    1. Snakecatcher
      11.09.2015 16:43

      Пробовал этот инструмент. Увы, глючит не только со шрифтами, но и с размерами этикетки.
      Кстати, вы можете тестировать без сторонних инструментов, в полном объеме возможностей вашего принтера.
      Вводите в адресную строку своего браузера сетевой адрес принтера (например 123.4.5.67), выбираете пункт «Directory Listing», внизу нажимаете на небольшую кнопку «Create New Script», затем кнопку «Edit». В появившемся окне вводите ZPL код, нажимаете на кнопку «Preview label», и видите сформированную этикетку. Можете распечатать ее нажав кнопку «Print». Чтобы вернуться к коду, опять нажмите «Edit».


      1. Alexufo
        11.09.2015 20:52

        У нас на usb и печать через расширение к лисе с сайта, увы. LAN принтеры чуть дороже и чуть сложнее в интеграции в нашем случае.


  1. bitlz
    13.09.2015 04:45

    А как обстоят дела с печатью картинок?


    1. Snakecatcher
      13.09.2015 10:40

      К сожалению сам не разобрался. Вроде картинка заливается во внутреннюю память принтера, и прописывается путь в GraphicBox. Если кто-то разобрался в этом вопросе, подскажите, как вы делаете?


  1. Invision70
    13.09.2015 11:55

    Пытаемся реализовать печать zpl2 с браузера, есть у кого идеи? Java апплеты не вариант (хром прикрыл).


  1. FireStorm
    14.09.2015 20:07

    IMHO, CPCL попроще будет для освоения.