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 designer3Software drawing labels can be exported to different programming languages

  • GK888tCorresponding ZPL
  • GK888t(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

  1. The preparatory work
  • Import zebra SDK:ZSDK_API.jar(Provided at the end of the article)
  1. 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,^XZIs a pair of instructions that represent the beginning and end of a ZPL command, between which all other ZPL instructions are written.
  • ^LHRepresents 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

  1. 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.^FOCan 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 rectangle
    • 700: Length of rectangle
    • 200: Height of the rectangle
    • 6: Width of the side of the rectangle
  • ^FSThis directive has two main functions
    • The separation between other instructions
    • ZPL comments, java-like line comments //
  1. 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
  • 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.

  1. cross
    • It’s easy, just set the height of the rectangle to 1
  2. vertical
    • Similarly, set the length of the rectangle to 1
  3. 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 (^FOThe preceding line segment is also used to set the coordinates.
  • ^ A0, 55 zhongguo kuangye daxue
    • ^A: Used to select fonts, there are two ways.
      1. ^ @ A font nameAs 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.
      2. ^A number or letter (a-z,0-9):^AThe 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^CWCommand. Such as^CW1,E:SIMSUN.FNT, is used^A1It stands for the text behind itE:SIMSUN.FNTFont, we assign a font to the number 1.We’ll talk about it later when we talk about Chinese fonts
    • The first one55: stretches the character along the Y-axis
    • The second55: 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 printing
    • 14: Can only print each line in Chinese
    • 26: Each line can be printed in both Chinese and English
    • 28: 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.FNTUse:SIMSUN.FNTAs a font for printing, and identify the font with the number 1. And then you can use^A1To call this font. You can also identify the font with any number of 2 or 3.
    1. How do I know what font to use?

      General Use of ChineseSIMSUN.FNT(宋体).
    2. 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.
  • ^A1: 1 is the font we configured to use for this line of words.

Chinese print effect

usejavaDraw the Chinese label DEMO
  1. Java image transfer ZPL directive
  • callgetFont2ImgZPL(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^XZFor easy concatenation with other ZPL instructions, you can modify the relevant code yourself
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
  1. Draw label images using Java and spliced them into printable ZPL instructions
    • useGraphics2Dclass
    • usegetMyTag()Method to return the full ZPL directive that needs to be printed
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
  1. useJavaDisadvantages 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 fontzebra designer3Draw 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
  1. 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 label
    • 2.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 will
    • 100: 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.code128Code, 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
  1. 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

  1. 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
  2. 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…