What is the ZPL language?
ZPL
ZPL is the programming language used for industrial models of zebra bar code printers. Using these programming languages, a printed instruction set is edited and sent to a bar code printer, which prints the labels drawn by ZPL.
EPL
EPL is also a programming language for Zebra printers, mainly used for bar code printer desktop small machines. When installing zebra drive, you can see that the drive is divided into GK888t and GK888t(EPL) two drives.
Note that after installing different types of drivers, use the official oneszebra designer3
Software drawing labels can be exported to different programming languages
GK888t
Corresponding ZPLGK888t(EPL)
Corresponding to the EPL
EPL looks like a bunch of gibberish, so you don’t need to know too much about it. Next, the basic syntax of the ZPL language is described in detail
Print using the ZPL directive
Starting point: Using Java to execute ZPL commands
- The preparatory work
- Import zebra SDK:
ZSDK_API.jar
(Provided at the end of the article)
- Code case
Static final String theIpAddress = "10.10.40.200"; Public static void printZPL() throws Exception {// Connection thePrinterConn = new TcpConnection(theIpAddress, TcpConnection.DEFAULT_ZPL_TCP_PORT); try { thePrinterConn.open(); ZebraPrinter zebraPrinter = ZebraPrinterFactory.getInstance(thePrinterConn); The arguments in the sendCommand() method are ZPL command strings. Here I passed the method returns ZPL zebraPrinter sendCommand (ZPLCodeConverter. GetTag05_2 (" 1 ", "1", "1", "12", "218", "1280", "8000", "07151-3A", "2020-11-11")); zebraPrinter.sendCommand(ZPLCodeConverter.getTag05_2_cn( "1","1","1", "12", "218", "1280", "8000", "07151-3A", "2020-11-11")); } catch (Exception e) { e.printStackTrace(); } } public staic void main(String[] arges) { printZPL(); }Copy the code
ZPL grammar
Overall TAB page configuration
^XA // Label start ^LH0,0 // Label top left coordinates (x axis, Y axis) ^MD10 // Print label color depth (range 0 to 30) ^PR // Print speed ^LL // Label length ^PW // Label width ^LR // Label reversal (' y '/'N') ^XZ // Label endCopy the code
^XA
,^XZ
Is a pair of instructions that represent the beginning and end of a ZPL command, between which all other ZPL instructions are written.^LH
Represents the coordinates of the top left corner of the label. With this command, you can define the position of the label on the paper^ LH10, 20
: indicates that the upper margin of the label is 10 and the left margin is 20
^MD10
: Indicates the color depth of the label. The greater the value, the darker the color. Range: 0 to 30. In practice, this command may not take effect depending on the font.^PR
: Label printing speed, this command is basically not used^LL
: Label length. The value can be adjusted according to the length of the label^LL500
: The label length is 500
^PW
: Label width^PW800
: The label width is 800
^LR
: Label reversal, which controls the direction of the label displayed on the paper. Value: ‘Y’/’ N ‘
Rectangle –> lines
With the instructions that control the overall style of the tag, it’s time to start with how to draw the tag.
General label will use horizontal and vertical to build the label frame, in ZPL use ^FO, ^GB instructions to draw lines
rectangular
- Let me draw a rectangle
- The following command draws a rectangle
^FO(X-axis), (Y-axis)^GB(X-axis stretch), (Y-axis stretch), (line width)^FSCopy the code
^ FO50, 500
: represents the coordinates of the upper-left corner of the element in the tag.^FO
Can be interpreted as identifying an element (e.g., line, character, picture)^ GB700, 200, 6
: Sets the length and height of the rectangle and the width of the sides of the rectangle700
: Length of rectangle200
: Height of the rectangle6
: Width of the side of the rectangle
^FS
This directive has two main functions- The separation between other instructions
- ZPL comments, java-like line comments //
- case
- Pay attention to: It’s not in the ZPL
//
Use it for comments just for convenience (^FS is too messy!). - If you are testing with case code, remove comments
- Pay attention to: It’s not in the ZPL
- code
^MD10 // label print depth // a top left coordinate of (50,50), length 700, width 200, Rectangle ^FO50,50^GB700,200,9^FS ^XZ with side width 9 // label endCopy the code
- The effect
Horizontal, vertical
Now that I’ve drawn the rectangle, how do I draw a vertical or a horizontal? Leave it as a thought for later.
- cross
- It’s easy, just set the height of the rectangle to 1
- vertical
- Similarly, set the length of the rectangle to 1
- case
- code
^XA ^PW1000 ^LL800 ^LH0,0 ^MD10 ^FO50,50^GB700,200,9^FS // rectangle ^FO50,300^GB700,1,9^FS // horizontal 1 ^FO50,350^GB700,1,9^FS // horizontal 2 ^FO50,400^GB1,100,9^FS // up 1 ^FO100,400^GB1,100,9^FS // up 2 ^FO150,400^GB1,100,9^FS // up 3 ^FO200,400^GB1,100,9^FS // up 4 ^XZCopy the code
- The effect
character
After you build the frame, you need to fill in the content. There are some fonts stored inside the Zebra printer, and you can choose different fonts to print.
For English and symbols, use the default Zebra 0 font, allowing you to change the font size, format, and so on
But for Chinese processing, zebra offers only one font: simsun.fnt, which stands for 宋体. The problem with this type is that characters can only be scaled up in multiples, not as large or small as you might think. And the font format business can’t change as desired. Therefore, there are two ways of processing Chinese characters:
- Adjust the label structure to fit the font size
- Use high-level language to draw a picture of the label, convert the picture to the format of the ZPL command, and then print the picture.
The second method will be introduced separately
The English characters
case
^XA ^PW1000 ^LL800 ^LH0,0 ^MD10 ^FO50,50^A0,55,55^FDSERENITY to accept the things^FS ^FO50,120^A0,130,55^FD I cannot Change ^FS ^FO50,300^A0,55 ^FDCOURAGE to change the things^FS ^FO50,370^A0,55,130^FD I can^FS ^FO50,550^A0,55 ^FDWISDOM to know the differenceCopy the code
^ FO50, 50
: represents the coordinates in the upper left corner of the text (^FO
The preceding line segment is also used to set the coordinates.^ A0, 55 zhongguo kuangye daxue
^A
: Used to select fonts, there are two ways.^ @ A font name
As for the font name, you can print the configuration information of the printer, which contains the fonts currently installed by the printer. As for how to print, you can see the section on installing the printer above.^A number or letter (a-z,0-9)
:^A
The default font is followed by the number 0, which is used in the example above. We can customize the following number, we need to use^CW
Command. Such as^CW1,E:SIMSUN.FNT
, is used^A1
It stands for the text behind itE:SIMSUN.FNT
Font, we assign a font to the number 1.We’ll talk about it later when we talk about Chinese fonts
- The first one
55
: stretches the character along the Y-axis - The second
55
: Stretch the font along the X-axis
^FD
: Followed by the text you need to print^FS
: used to split ZPL instructions
English print effect
Chinese characters
Some problems exist in ZPL instruction printing Chinese characters
For Chinese, we need to use the Chinese font provided by zebra, which is simsun.fnt (宋体).
Unlike the default English font, there is no way to control the character size by number. For example, setting the font size to 30-35 is the same. Set it to 36-45 and the font size is the same. It can be interpreted as having the same font size in an interval.
In this case, you can use a high-level language to draw a picture of the label, convert the picture to a ZPL directive, and then print the ZPL directive.
Print Chinese using ZPL instructions
case
FNT ^PW1000 ^LL800 ^LH0,0 ^MD10\n ^FO50,50^A1,55 ^FD Grant me peace, ^FS ^FO50,120^A1,55 ^FD Accept what I cannot change. ^FS ^FO50,300^A1,55,55^FD give me courage ^FS ^FO50,370^A1,55,80^FD give me wisdom ^FS ^ 50,500^A1,55,55^FD To tell the difference between the twoCopy the code
^CI28
: calls the international character set used for printing14
: Can only print each line in Chinese26
: Each line can be printed in both Chinese and English28
: stands for UTF-8 character set, which is commonly used for Chinese printing- After testing, printing Chinese is only 28 useful, using other character sets may be garbled.
^CW1,E:SIMSUN.FNT
Use:SIMSUN.FNT
As a font for printing, and identify the font with the number 1. And then you can use^A1
To call this font. You can also identify the font with any number of 2 or 3.- How do I know what font to use?
General Use of ChineseSIMSUN.FNT
(宋体). - What fonts does the printer contain? Now that you’ve seen this, you know how to print the configuration information for this printer, and the fonts that this printer has are included there, so you can use them as you like.
- How do I know what font to use?
^A1
: 1 is the font we configured to use for this line of words.
Chinese print effect
usejava
Draw the Chinese label DEMO
- Java image transfer ZPL directive
- call
getFont2ImgZPL(arg1,arg2,arg3)
The Java image stream () method replaces a ZPL directive with a Java image stream- So I’ve got rid of the label
^XA
, and represents the coordinates of the picture^FOX,Y
, and represents the end of the tag^XZ
For easy concatenation with other ZPL instructions, you can modify the relevant code yourself
- So I’ve got rid of the label
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.HashMap;
import java.util.Map;
import javax.imageio.ImageIO;
public class ZPLConveter {
private int blackLimit = 380;
private int total;
private int widthBytes;
private boolean compressHex = false;
private static Map<Integer, String> mapCode = new HashMap<Integer, String>();
{
mapCode.put(1, "G");
mapCode.put(2, "H");
mapCode.put(3, "I");
mapCode.put(4, "J");
mapCode.put(5, "K");
mapCode.put(6, "L");
mapCode.put(7, "M");
mapCode.put(8, "N");
mapCode.put(9, "O");
mapCode.put(10, "P");
mapCode.put(11, "Q");
mapCode.put(12, "R");
mapCode.put(13, "S");
mapCode.put(14, "T");
mapCode.put(15, "U");
mapCode.put(16, "V");
mapCode.put(17, "W");
mapCode.put(18, "X");
mapCode.put(19, "Y");
mapCode.put(20, "g");
mapCode.put(40, "h");
mapCode.put(60, "i");
mapCode.put(80, "j");
mapCode.put(100, "k");
mapCode.put(120, "l");
mapCode.put(140, "m");
mapCode.put(160, "n");
mapCode.put(180, "o");
mapCode.put(200, "p");
mapCode.put(220, "q");
mapCode.put(240, "r");
mapCode.put(260, "s");
mapCode.put(280, "t");
mapCode.put(300, "u");
mapCode.put(320, "v");
mapCode.put(340, "w");
mapCode.put(360, "x");
mapCode.put(380, "y");
mapCode.put(400, "z");
}
private static class SingletonHolder {
private static final ZPLConveter INSTANCE = new ZPLConveter();
}
private ZPLConveter (){}
public static final ZPLConveter getInstance() {
return SingletonHolder.INSTANCE;
}
public String convertfromImg(BufferedImage image) throws IOException {
String cuerpo = createBody(image);
if(compressHex)
cuerpo = encodeHexAscii(cuerpo);
return headDoc() + cuerpo + footDoc();
}
private String createBody(BufferedImage orginalImage) throws IOException {
StringBuffer sb = new StringBuffer();
Graphics2D graphics = orginalImage.createGraphics();
graphics.drawImage(orginalImage, 0, 0, null);
int height = orginalImage.getHeight();
int width = orginalImage.getWidth();
int rgb, red, green, blue, index=0;
char auxBinaryChar[] = {'0', '0', '0', '0', '0', '0', '0', '0'};
widthBytes = width/8;
if(width%8>0){
widthBytes= (((int)(width/8))+1);
} else {
widthBytes= width/8;
}
this.total = widthBytes*height;
for (int h = 0; h<height; h++)
{
for (int w = 0; w<width; w++)
{
rgb = orginalImage.getRGB(w, h);
red = (rgb >> 16 ) & 0x000000FF;
green = (rgb >> 8 ) & 0x000000FF;
blue = (rgb) & 0x000000FF;
char auxChar = '1';
int totalColor = red + green + blue;
if(totalColor>blackLimit){
auxChar = '0';
}
auxBinaryChar[index] = auxChar;
index++;
if(index==8 || w==(width-1)){
sb.append(fourByteBinary(new String(auxBinaryChar)));
auxBinaryChar = new char[]{'0', '0', '0', '0', '0', '0', '0', '0'};
index=0;
}
}
sb.append("\n");
}
return sb.toString();
}
private String fourByteBinary(String binaryStr){
int decimal = Integer.parseInt(binaryStr,2);
if (decimal>15){
return Integer.toString(decimal,16).toUpperCase();
} else {
return "0" + Integer.toString(decimal,16).toUpperCase();
}
}
private String encodeHexAscii(String code){
int maxlinea = widthBytes * 2;
StringBuffer sbCode = new StringBuffer();
StringBuffer sbLinea = new StringBuffer();
String previousLine = null;
int counter = 1;
char aux = code.charAt(0);
boolean firstChar = false;
for(int i = 1; i< code.length(); i++ ){
if(firstChar){
aux = code.charAt(i);
firstChar = false;
continue;
}
if(code.charAt(i)=='\n'){
if(counter>=maxlinea && aux=='0'){
sbLinea.append(",");
} else if(counter>=maxlinea && aux=='F'){
sbLinea.append("!");
} else if (counter>20){
int multi20 = (counter/20)*20;
int resto20 = (counter%20);
sbLinea.append(mapCode.get(multi20));
if(resto20!=0){
sbLinea.append(mapCode.get(resto20) + aux);
} else {
sbLinea.append(aux);
}
} else {
sbLinea.append(mapCode.get(counter) + aux);
if(mapCode.get(counter)==null){
}
}
counter = 1;
firstChar = true;
if(sbLinea.toString().equals(previousLine)){
sbCode.append(":");
} else {
sbCode.append(sbLinea.toString());
}
previousLine = sbLinea.toString();
sbLinea.setLength(0);
continue;
}
if(aux == code.charAt(i)){
counter++;
} else {
if(counter>20){
int multi20 = (counter/20)*20;
int resto20 = (counter%20);
sbLinea.append(mapCode.get(multi20));
if(resto20!=0){
sbLinea.append(mapCode.get(resto20) + aux);
} else {
sbLinea.append(aux);
}
} else {
sbLinea.append(mapCode.get(counter) + aux);
}
counter = 1;
aux = code.charAt(i);
}
}
return sbCode.toString();
}
private String headDoc(){
// String str = "^XA " +
// "^FO0,0^GFA,"+ total + ","+ total + "," + widthBytes +", ";
String str = "^GFA,"+ total + ","+ total + "," + widthBytes +", ";
return str;
}
private String footDoc(){
// String str = "^FS"+
// "^XZ";
String str = "^FS";
return str;
}
public void setCompressHex(boolean compressHex) {
this.compressHex = compressHex;
}
public void setBlacknessLimitPercentage(int percentage){
blackLimit = (percentage * 768 / 100);
}
/**
*
* @param inputStream 图片流
* @param compressHex 直接填true即可
* @param blacknessLimitPercentage 直接填50即可
* @return 返回ZPL指令
*/
public static String getFont2ImgZPL(InputStream inputStream, Boolean compressHex, int blacknessLimitPercentage) throws IOException {
SingletonHolder.INSTANCE.setBlacknessLimitPercentage(blacknessLimitPercentage);
SingletonHolder.INSTANCE.setCompressHex(compressHex);
BufferedImage orginalImage = ImageIO.read(inputStream);
// System.out.println(SingletonHolder.INSTANCE.convertfromImg(orginalImage));
return SingletonHolder.INSTANCE.convertfromImg(orginalImage);
}
public static void main(String[] args) throws Exception {
// BufferedImage orginalImage = ImageIO.read(new File("d:/a.png"));
// ZPLConveter zp = new ZPLConveter();
// zp.setCompressHex(true);
// zp.setBlacknessLimitPercentage(50);
// System.out.println(zp.convertfromImg(orginalImage));
FileInputStream fileInputStream = new FileInputStream(new File("d:\\a.png"));
// String font2ImgZPL = ZPLConveter.getFont2ImgZPL(FontImage.createImage("请在这里输入文字", new Font("宋体", Font.PLAIN, 32), 500, 64), true, 50);
String font2ImgZPL = ZPLConveter.getFont2ImgZPL(fileInputStream, true, 50);
System.out.println(font2ImgZPL);
}
}
Copy the code
- Draw label images using Java and spliced them into printable ZPL instructions
- use
Graphics2D
class - use
getMyTag()
Method to return the full ZPL directive that needs to be printed
- use
public static String getMyTag(String type, String grade, String color, String rolls, String thickness, String grossWeight, String width, String length, String rollNO, String date) throws IOException {
// Create the image
BufferedImage image = new BufferedImage(1000.800, BufferedImage.TYPE_INT_BGR);
Graphics2D g2d = (Graphics2D) image.getGraphics();
/ / anti-aliasing
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
g2d.setColor(Color.WHITE);
g2d.fillRect(0.0.1000.800);
// Set the brush color
g2d.setColor(Color.BLACK);
// Line in order
myDrawLine(g2d, 3.10.10.760.10);
myDrawLine(g2d, 3.10.160.760.160);
myDrawLine(g2d, 3.10.240.760.240);
myDrawLine(g2d, 3.10.320.760.320);
myDrawLine(g2d, 3.10.400.760.400);
myDrawLine(g2d, 3.10.480.760.480);
myDrawLine(g2d, 3.10.650.760.650);
// Vertical lines in order
myDrawLine(g2d, 3.10.10.10.650);
myDrawLine(g2d, 3.197.160.197.480);
myDrawLine(g2d, 3.384.160.384.480);
myDrawLine(g2d, 3.571.160.571.480);
myDrawLine(g2d, 3.760.10.760.650);
// In order of words
/ / 3
myDrawString(g2d, 20.new Font("宋体", Font.BOLD, 53), type, 210.230.1);
myDrawString(g2d, 20.new Font("宋体", Font.PLAIN, 53), grade, 640.230.1);
/ / line 4
myDrawString(g2d, 20.new Font("宋体", Font.PLAIN, 53), color, 210.310.1);
myDrawString(g2d, 20.new Font("宋体", Font.PLAIN, 53), rolls + " ROLL".579.310.0.89);
/ / line 5
myDrawString(g2d, 20.new Font("宋体", Font.PLAIN, 53), thickness + "mic".210.390.0.89);
myDrawString(g2d, 20.new Font("宋体", Font.PLAIN, 53), grossWeight + " KG".579.390.0.89);
/ / line 6
myDrawString(g2d, 20.new Font("宋体", Font.PLAIN, 53), width + "mm".210.470.1);
myDrawString(g2d, 20.new Font("宋体", Font.BOLD, 53), length + "M".579.470.0.89);
g2d.dispose();
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
ImageIO.write(image, "png", outputStream);// Output a PNG image
ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(outputStream.toByteArray());
String code =
"^XA\n" +
"^MMT\n" +
"^PW767\n" +
"^LL0687\n" +
"^LS0\n" +
"^ FO0, 0" + ZPLConveter.getFont2ImgZPL(byteArrayInputStream, true , 50) + "\n" +
"^ BY4, 3,84 ^ FT124, 595 ^ BCN,, Y, N \ N" + / / barcode
"^FD>; 123456123456123456^FS\n" +
"^ PQ1, 0, 1, Y" +
"^XZ\n";
return code;
}
/** * draw a line *@paramG2d Graph2D object *@paramFontSize Line width *@paramSWidth line starting x-coordinate *@paramSHeight line starting Y coordinate *@paramEWidth line end X coordinate *@paramThe Y coordinate at the end of the eHeight line */
public static void myDrawLine(Graphics2D g2d, Integer fontSize, Integer sWidth, Integer sHeight, Integer eWidth, Integer eHeight) {
// Set the width of the line
BasicStroke bs1 = new BasicStroke(fontSize);
g2d.setStroke(bs1);
g2d.drawLine(sWidth, sHeight, eWidth, eHeight);
}
/** * Use rate to control the spacing of the fonts, but it does not stretch the fonts and may cause them to overlap@paramG2d Graph2D object *@paramFontSize Brush width *@paramFont format *@paramSTR * The input word *@paramThe X-axis of the word x *@paramThe Y-axis of the y word star@paramRate Word space (normally 1) */
public static void myDrawString(Graphics2D g2d, Integer fontSize, Font font, String str, Integer x, Integer y, double rate) {
g2d.setFont(font);
String tempStr=new String();
int orgStringWight=g2d.getFontMetrics().stringWidth(str);
int orgStringLength=str.length();
int tempx=x;
int tempy=y;
while(str.length()>0)
{
tempStr=str.substring(0.1);
str=str.substring(1, str.length());
g2d.drawString(tempStr, tempx, tempy);
tempx=(int)(tempx+(double)orgStringWight/(double)orgStringLength*rate); }}Copy the code
- use
Java
Disadvantages of drawing labels
Java’s Graphics2D class can only resize a font, not stretch it to the X or Y axis.
In the method of drawing characters in the DEMO above, you can adjust the spacing between fonts by using the rate parameter, but if the spacing is too low, the characters will overlap.
How to solve it?
- Draw labels in other ways
- Use small fonts
- For fixed header data, use if you need to stretch the font
zebra designer3
Draw the words, export the ZPL, and concatenate the ZPL into the print method. These exported ZPL instructions are pretty much pictures
The barcode
There are many types of bar codes. Here we take common CODE128 code as an example.
Example: Print labels using ZPL
- Let me draw a bar code
600100 ^ ^ BY2.5, FO25, 480 BC ^ ^ FD123456123456 ^ FSCopy the code
^ BY2.5, 600100
: Prints a bar code with the width of 2.5 and height of 100^BY
: Controls the style of the label2.5
: Label width. This parameter is similar to the parameter used to control the Chinese font size. Labels can only be scaled up or down, but cannot be accurately controlled by changing the numeric size.600
: Has no actual meaning and can be filled in at will100
: Indicates the bar code length
^ FO25, 480 BC ^ ^ FD123456123456 ^ FS
^ F025, 480
: Set the coordinates of the top left label to (25,480)^BC
: Indicates use.code128
Code, you can replace this command to output bar codes in different coding formats^FD123456123456
: Generates a bar code based on the text or number following ^FD^FS
: used to split ZPL instructions
- The effect
Problems with using ZPL to print labels
As mentioned above, we can’t change the number after ^BY to achieve precise label width control (we can only scale up the label). For some styles of tags, using ZPL alone is not enough. Here are two ideas
- First, use Java or other languages to generate tag images, convert the secondary images into ZPL commands through code, and then splicing the ZPL commands into the total ZPL commands
- Use Zebra Designer to draw the picture, export the ZPL, and splice this ZPL code into the main ZPL code. You should see the label text in the code generated by Zebra Designer, which you can replace.
Source: github.com/btmood/zbre…