ZPL Programming Guide

Ömer Faruk Bolatan
8 min readJan 4, 2024
Photo by Frida Lannerström on Unsplash

As a software developer, I felt weird when I was asked for an algorithm that automatically produces ZPL output. The question of what ZPL was appeared in my mind, and I did not know where to start.

In this article, I will share my experiences and coping methods in the process of producing automated ZPL outputs. I aim to share practical information about ZPL programming by telling you what methods I have tried and the difficulties I have encountered.

First of all, I want to make a small definition.

ZPL is the abbreviation of “Zebra Programming Language” and is a programming language developed by Zebra Technology. Frequently used in industrial and commercial areas such as logistics, storage, and production sectors, ZPL is a language containing simple commands and labeling features. This language can be used through special printer commands; it is used to send printing instructions to Zebra brand printers.

Now I will explain the topics under the headings.

About Syntax;

The first syntax you will learn when you do a little research is: it will be ^XA and ^XZ. ^XA is the beginning, and ^XZ is the last block of code. These commands determine the functional block within the ZPL code.

Here is an example, if you want to see this example visually, you can visit this address

^XA
^FX outputs "Hello World!" you must see.
^FDHello World!^FS
^XZ

In ZPL programming, blocks starting and ending with ^ are designed to give the same output even if written on a single line. These blocks form the basic logic of the ZPL and are used in compilation operations.

In fact, this syntax will give the same output as above.

^XA^FX outputs "Hello World!" you must see.^FDHello World!^FS^XZ

While ^FX is used to add comments in ZPL outputs, we use blocks each starting with ^FD and ending with ^FS to add text. This structure allows us to obtain an output that simply contains text, although not visual. However, to achieve understandable, visually elegant and aesthetic ZPL outputs, it is important to write ZPL code in an orderly and aesthetic way.

^XA
^CF0,50
^FO20,100
^FDHello World!^FS
^XZ

In the sample ZPL code above, we set the text size with the ^CF0,50 block and changed the text position with the ^FO20,100 block. In this way, we made the ZPL code more understandable.

We suddenly became interested in numerical values, I am aware. I will discuss this issue in the following sections of the article, but since the syntax section is a deep heading, I want to finish it here and move on to other headings. You can find more information about the syntax under the following topics;

About Label Sizing;

Perhaps this may be the most difficult topic when creating my algorithm. This is because the printer does not automatically adjust the ZPL code based on label size and print resolution.

In this case, depending on the model of your printer and the print resolution as well as the dimensions of the label used, you may need to manually adjust your ZPL code according to the label size and resolution.

For example, the coding between a 4 x 4 inch label and a 5 x 10 inch label differs. At the same time, there may be big differences in the positioning you will use in coding between 152 dpi and 600 dpi print resolution. Therefore, it is important to make the correct adjustments when writing your ZPL code, taking into account both label size and print resolution.

I would like to explain this situation with an example.

^XA
^FO10,10
^GB590,590,3^FS
^FO30,260
^CF0,100
^FDHello, World!^FS
^XZ

When you view and size the ZPL code block I mentioned above from this address, if you set the label size to 4 x 4 inches and the dpi to 152, you will get a visually perfect printout.

However, if you change the dpi to 600 while keeping the same label size, the output will appear smaller. This occurs because as print resolution increases, more detail can be packed into the same physical size. That is, as the dpi value increases, more information can be fit on the same size label, but this causes the printout to appear visually smaller.

So how should we code this sizing?

First of all, I would like to return to the sentence I mentioned in the title of my article about the syntax: “We are involved in numerical data and I will explain this later.

Let’s say we’re considering a label draft that’s 4x4 inches with 152 dpi. We can determine the boundaries of this sketch with x and y coordinates. If we write code like ^FO2000,10 and then add ^FDHello, World!^FS, this text will not be displayed because the coordinates (2000,10) exceed the boundaries of the sketch. If we consider the format ^FO(x),(y), the text will not appear in this case because the (x) value is outside the outline.

I think I can convey what I want to say better if you make the adjustments I mentioned and try to view it.

I know this is a bit confusing. This situation is a bit like the sketch we are drawing. We need to think of the paper we print from our printer as a draft. A coordinate outside our sketch will not be displayed.

This situation is complicated even by trial and error, so how do we solve this in our automatic ZPL algorithm?

The first thing we need to start with is to calculate the maximum size of our x and y coordinates. Calculating this will give us the maximum space we can use in our sketch.

Meanwhile, we need to accept the x value as the width and the y value as the height.

We can find the maximum x and y values ​​with the formula “inch * dpi” But we may not always have inch or dpi values. It can be in inch cm type or dpi can be in dpmm type. That’s why I’m adding the formula directly here with formatting.

Width: X
Height: Y

1 cm: 0.39 inch
1 dpmm: 25.39 dpi

Max X: inch * dpi
Max y: inch * dpi

For example, the maximum X and Y values ​​of a template with 4 inches width,
6 inches height and 152dpi are as follows.

X : 4 * 152 (height * dpi) = 608

Y : 6 * 152 (width * dpi) = 912

Now, if you make adjustments at this address with the values ​​in the formula above, that is, the width is 4, the height is 6 and the dpi is 152, and if you want to display the ZPL code below after the adjustments, you will receive the following error “^FO: Value 620 is greater than label width 608; field will not be visible on the label

This is proof of our formula

^XA
^FO620,0^FDHello World!^FS
^XZ

But in ZPL programming, only maximum height and width values are not enough for us. After all, we have an output we want to display here. This output may contain textual values, shapes, symbols, and similar tools.

Even if we change the width value of the ZPL code in the example above to 608, our output will not appear properly because we have text, and there is an area that this text covers.

So how do we adjust the size of our texts?

First of all, we need to use the ^A0N command for our texts. This command actually allows us to automatically adjust the size of our texts.

We have ZPL documentation to calculate the size of the text specified when using ^A0. You can access this document from this page.

To summarize the method stated in the documentation, it is as follows:

Each character has a horizontal numeric value corresponding to its ASCII counterpart. We divide this value by the constant number 8782 and then multiply the specified width value in the ^A0 code by this result. As a result, the numerical value we obtain tells us how much space our character occupies in the determined dimension.

The formulated version looks like this

Size: 50
Character: A
ASCII equivalent: 65
Numeric value: 4879

Space occupied by the character: (4879/8782) * 50 = (int)27

When we create a drawing with a width of 4 and a dpi value of 152, the total area we can use in a single width will be 608. When we subtract the area occupied by character A from this total area and use the result for positioning, we will see a perfect output.

here is an example for this

^XA
^FO581,0
^A0N,50
^FDA^FS
^XZ

So far, we have learned how much space we take up in sizing by following the official documentation. However, a discussion I came across during my research inspired me on this subject, and I focused on how I could create my own formula. As a result, although it is not 100% accurate, I have created a more usable formula.

My own formula is as follows

Number of characters: 2
Size: 50

Space occupied by the characters: (2 * 50 * 4) / 7 = 57

If we need to compare the two formulas, it will be as follows

Size: 50
Characters: ABC
Number of characters: 3

According to the official documentation,
the space occupied by these characters is: 80

According to my own formula,
the area occupied by these characters is: 85

However, going according to the official documentation will always give more accurate results. Now I would like to touch upon the points that need to be considered in programming.

About Programming;

First of all, you will need a zebra printer that you can use in the testing processes of your programming. You can send requests to Zebra printers via socket.

After we came to a certain level about ZPL, it was time to produce automated ZPL outputs that would meet our needs. When I started programming, there were parts of my algorithm that I went back and edited over and over again.

I used PHP when creating my algorithm and actually found a ready-made library, but I gave up using this library because it did not fully meet my needs.

No matter what language you use, if you do not have the opportunity to use a ready-made library or if it does not fully meet your needs, your focus should be on sizing.

Feel free to use design patterns. Try to write your code in its most understandable form.

If you do not have a single ZPL size, keep your ZPL sizes and values ​​such as font size in your database, not in the project. This will give you flexibility in creating excellent ZPL outputs.

If the font type is not important to you, you can have your operations done using a single font. Because the font will also have an effect on text resizing. While doing these, be careful to keep them in a dynamic structure.

I hope this article was useful. Thank you for your time.

--

--