Android 蓝牙/wifi云打印机 ESC/POS热敏打印机打印(ESC/POS指令篇)

您所在的位置:网站首页 热敏打印机怎么设置打印机连接方式 Android 蓝牙/wifi云打印机 ESC/POS热敏打印机打印(ESC/POS指令篇)

Android 蓝牙/wifi云打印机 ESC/POS热敏打印机打印(ESC/POS指令篇)

2024-07-15 23:19| 来源: 网络整理| 查看: 265

上一篇主要介绍了如何通过蓝牙打印机和wifi云打印机的连接与数据发送,这一篇,我们就介绍向打印机发送打印指令,来打印字符和图片。

由于公司暂且买了两台打印机,一台佳博GP-58MIII,一台GP-SH584。

我们先来看一下最终票据打印效果图:

一、ESC/POS指令

ESC/POS指令体系是由EPSON发明的一套专有POS打印机指令系统,市面上绝大部分打印机兼容ESC/POS指令。

由于我使用的是佳博的蓝牙打印机,我们来看一下佳博打印机背后的型号说明:

上图可见,两台打印机是58mm纸宽的打印机,一台支持USB和蓝牙连接,一台支持USB和wifi云,并且都支持ESC/POS命令。

二、常用的打印命令

手机通过蓝牙或者ip端口向打印机发送的都是纯字节流。打印机通过遵循ESC/POS指令控制打印。

2.1 初始化打印机

指令:该指令会清除打印缓冲区中的数据,但是接收缓冲区的数据并不会清除,一般开始打印的时候需要调用。

ASCII码 ESC @ 十进制码 27 64 十六进制码 1B 40

佳博SDK将ESC指令封装成了一个EsCommand类,对应的代码如下:

EscCommand esc = new EscCommand(); esc.addInitializePrinter();//初始化打印机 //SDK源码内部 public void addInitializePrinter() { byte[] command = new byte[]{27, 64}; this.addArrayToCommand(command); } //此处省略了部分核心代码 outputStream.write(esc.getCommand , offset, len); ... 2.2 打印文本

没有对应指令,直接输出文本

// 打印文字 esc.addText("发货单\n"); public void addText(String text) { this.addStrToCommand(text); } 2.3  打印多列文本

通用打印纸都是有固定宽度的,比如58mm打印纸最大宽度为384个像素店,80mm打印纸最大宽度为576个像素点。经过大量测试结果表明,一般最大字节数是32个字节(总宽度 = 左侧宽度 + 右侧宽度)

/** * 左侧宽度 + 右侧宽度 = 打印纸总宽度 * 打印纸一行最大的字节 */ private static final int LINE_BYTE_SIZE = 32; /** * 打印三列时,中间一列的中心线距离打印纸左侧的距离 */ private static final int LEFT_LENGTH = 16; /** * 打印三列时,中间一列的中心线距离打印纸右侧的距离 */ private static final int RIGHT_LENGTH = 16; /** * 打印四列时,第一列居左,第二列居中,第四列居右,第三列位于第二列和第四列中间 * 第三列距离第二列的距离 */ private static final int MIDDLE_RIGHT_MIDDLE_LENGTH = 8; /** * 打印四列时,第一列居左,第二列居中,第四列居右,第三列位于第二列和第四列中间 * 第三列距离第四列的距离 */ private static final int MIDDLE_RIGHT_MIDDLE_RIGHT = 8; /** * 打印三列时,第一列汉字最多显示几个文字 */ private static final int LEFT_TEXT_MAX_LENGTH = 5;

当我们打印两列时,一列居左,一列居右;打印三列时,一列居左,一列居中,一列居右。那两列之间的空格,我们用下面的方法可以完美的计算出来剩余空格。这样就不用手动添加多个空格了。

/** * 获取数据长度 * * @param msg * @return */ @SuppressLint("NewApi") private static int getBytesLength(String msg) { return msg.getBytes(Charset.forName("GB2312")).length; } /** * 打满一列列 * * @return */ @SuppressLint("NewApi") public static String printOneFullData() { StringBuilder sb = new StringBuilder(); for (int i = 0; i < LINE_BYTE_SIZE; i++) { sb.append("-"); } return sb.toString(); } /** * 打印两列 * * @param leftText 左侧文字 * @param rightText 右侧文字 * @return */ @SuppressLint("NewApi") public static String printTwoData(String leftText, String rightText) { StringBuilder sb = new StringBuilder(); int leftTextLength = getBytesLength(leftText); int rightTextLength = getBytesLength(rightText); sb.append(leftText); // 计算两侧文字中间的空格 int marginBetweenMiddleAndRight = LINE_BYTE_SIZE - leftTextLength - rightTextLength; for (int i = 0; i < marginBetweenMiddleAndRight; i++) { sb.append(" "); } sb.append(rightText); return sb.toString(); } /** * 打印三列 * * @param leftText 左侧文字 * @param middleText 中间文字 * @param rightText 右侧文字 * @return */ @SuppressLint("NewApi") public static String printThreeData(String leftText, String middleText, String rightText) { StringBuilder sb = new StringBuilder(); // 左边最多显示 LEFT_TEXT_MAX_LENGTH 个汉字 + 两个点 if (leftText.length() > LEFT_TEXT_MAX_LENGTH) { leftText = leftText.substring(0, LEFT_TEXT_MAX_LENGTH) + ".."; } int leftTextLength = getBytesLength(leftText); int middleTextLength = getBytesLength(middleText); int rightTextLength = getBytesLength(rightText); sb.append(leftText); // 计算左侧文字和中间文字的空格长度 int marginBetweenLeftAndMiddle = LEFT_LENGTH - leftTextLength - middleTextLength / 2; for (int i = 0; i < marginBetweenLeftAndMiddle; i++) { sb.append(" "); } sb.append(middleText); // 计算右侧文字和中间文字的空格长度 int marginBetweenMiddleAndRight = RIGHT_LENGTH - middleTextLength / 2 - rightTextLength; for (int i = 0; i < marginBetweenMiddleAndRight; i++) { sb.append(" "); } // 打印的时候发现,最右边的文字总是偏右一个字符,所以需要删除一个空格 sb.delete(sb.length() - 1, sb.length()).append(rightText); return sb.toString(); } /** * 打印四列 * * @param leftText 左侧文字 * @param middleText 中间文字 * @param middleAndThirdText 中间与右侧中间的文字 * @param rightText 右侧文字 * @return */ @SuppressLint("NewApi") public static String printFourData(String leftText, String middleText, String middleAndThirdText, String rightText) { StringBuilder sb = new StringBuilder(); // 左边最多显示 LEFT_TEXT_MAX_LENGTH 个汉字 + 两个点 if (leftText.length() > LEFT_TEXT_MAX_LENGTH) { leftText = leftText.substring(0, LEFT_TEXT_MAX_LENGTH) + ".."; } int leftTextLength = getBytesLength(leftText); int middleTextLength = getBytesLength(middleText); int rightTextLength = getBytesLength(rightText); int middleAndThirdTextLength = getBytesLength(middleAndThirdText); sb.append(leftText); // 计算左侧文字和中间文字的空格长度 int marginBetweenLeftAndMiddle = LEFT_LENGTH - leftTextLength - (middleTextLength > 1 ? middleTextLength / 2 : 1); for (int i = 0; i < marginBetweenLeftAndMiddle; i++) { sb.append(" "); } sb.append(middleText); //计算中间文字和第三列文字的空格长度 int marginBetweenMiddleAndThirdText = MIDDLE_RIGHT_MIDDLE_LENGTH - (middleTextLength > 1 ? middleTextLength / 2 : 1) - (middleAndThirdTextLength > 1 ? middleAndThirdTextLength / 2 : 1); for (int i = 0; i < marginBetweenMiddleAndThirdText; i++) { sb.append(" "); } sb.append(middleAndThirdText); // 计算第三列文字文字和右侧文字的空格长度 int marginBetweenThirdTextAndRight = MIDDLE_RIGHT_MIDDLE_RIGHT - (middleAndThirdTextLength > 1 ? middleAndThirdTextLength / 2 : 1) - rightTextLength; for (int i = 0; i < marginBetweenThirdTextAndRight; i++) { sb.append(" "); } // 打印的时候发现,最右边的文字总是偏右一个字符,所以需要删除一个空格 // sb.delete(sb.length() - 1, sb.length()).append(rightText); sb.append(rightText); return sb.toString(); }

 

2.4 设置对齐方式

指令:

ASCII码 ESC a n 十进制码 27 97 n 十六进制码 1B 61 n

n的取值,0左对齐,1中间对齐,2右对齐。

// 设置打印居中 esc.addSelectJustification(EscCommand.JUSTIFICATION.CENTER); public void addSelectJustification(EscCommand.JUSTIFICATION just) { byte[] command = new byte[]{27, 97, just.getValue()}; this.addArrayToCommand(command); } public static enum JUSTIFICATION { LEFT(0),//左对齐 CENTER(1),//居中 RIGHT(2);//右对齐 private final int value; private JUSTIFICATION(int value) { this.value = value; } public byte getValue() { return (byte)this.value; } } 2.5 字体倍高倍宽

指令:

ASCII码 ESC ! n 十进制码 27 33 n 十六进制码 1B 21 n

n的取值,0正常,16倍高,32倍宽,128下划线

// 设置为倍高倍宽 esc.addSelectPrintModes(EscCommand.FONT.FONTA, EscCommand.ENABLE.OFF, EscCommand.ENABLE.ON, EscCommand.ENABLE.ON, EscCommand.ENABLE.OFF); // 取消倍高倍宽 esc.addSelectPrintModes(EscCommand.FONT.FONTA, EscCommand.ENABLE.OFF, EscCommand.ENABLE.OFF, EscCommand.ENABLE.OFF, EscCommand.ENABLE.OFF); //SDK源码 public void addSelectPrintModes(EscCommand.FONT font, EscCommand.ENABLE emphasized, EscCommand.ENABLE doubleheight, EscCommand.ENABLE doublewidth, EscCommand.ENABLE underline) { byte temp = 0; if (font == EscCommand.FONT.FONTB) { temp = 1; } if (emphasized == EscCommand.ENABLE.ON) { temp = (byte)(temp | 8); } if (doubleheight == EscCommand.ENABLE.ON) { temp = (byte)(temp | 16); } if (doublewidth == EscCommand.ENABLE.ON) { temp = (byte)(temp | 32); } if (underline == EscCommand.ENABLE.ON) { temp = (byte)(temp | 128); } byte[] command = new byte[]{27, 33, temp}; this.addArrayToCommand(command); } 2.6 打印并走纸n行

指令:

ASCII码    ESC   d  n 十进制码    27  100  n 十六进制码  1B   64  n //打印走纸多少行 esc.addPrintAndFeedLines((byte) 3); //SDK源码 public void addPrintAndFeedLines(byte n) { byte[] command = new byte[]{27, 100, n}; this.addArrayToCommand(command); } 三、打印条码 3.1 条码高度指令 ASCII码    GS   h  n 十进制码    29 104  n 十六进制码  1D  68  n

n介于1到255之间,n默认值为162

public void addSetBarcodeHeight(byte height) { byte[] command = new byte[]{29, 104, height}; this.addArrayToCommand(command); } 3.2 条码宽度指令 ASCII码    GS   w  n 十进制码    29 119  n 十六进制码  1D  77  n

n介于2到6之间,默认n=3

public void addSetBarcodeHeight(byte height) { byte[] command = new byte[]{29, 104, height}; this.addArrayToCommand(command); } 3.3 打印条码 esc.addSetBarcodeHeight((byte) 80); //设置条码高度为80点 esc.addSetBarcodeWidth((byte) 3); // 设置条码单元宽度为3 esc.addCODE128(esc.genCode128("201811080001")); public void addCODE128(String content) { byte[] command = new byte[]{29, 107, 73, (byte)content.length()}; this.addArrayToCommand(command); this.addStrToCommand(content, command[3]); } 四、打印二维码

QRCode命令打印,此命令只在支持QRCode命令打印的机型才能使用。 在不支持二维码指令打印的机型上,则需要发送二维条码图片。

// 设置纠错等级 esc.addSelectErrorCorrectionLevelForQRCode((byte) 0x31); // 设置qrcode模块大小 esc.addSelectSizeOfModuleForQRCode((byte) 10); // 设置qrcode内容 esc.addStoreQRCodeData("www.whoot.com"); // 打印QRCode esc.addPrintQRCode(); 五、打印图片

很多小票上面会附上二维码或者logo,当打印机不支持二维码指令时,可以打印二维码的图片。由于热敏打印机只能打印黑白两色,所以首先需要把图片转成纯黑白的,再调用图片打印指令进行打印。

5.1 图片分辨率调整

58mm的热敏打印机,可打印区域最大宽度时384个像素点。80mm打印机可打印区域最大宽度为576个像素点。如果分辨率过大,超出了打印机可打印的最大宽度,那么超出部分将无法打印。所以在打印之前,我们需要调整图片的分辨率。

Bitmap b = BitmapFactory.decodeResource(App.getContext().getResources(), R.drawable.gprinter); esc.addRastBitImage(b, 384, 0); public void addRastBitImage(Bitmap bitmap, int nWidth, int nMode) { if (bitmap != null) { //因为横向每8个像素店组成一个字节,这里将位图宽度规范化为8的整数倍 int width = (nWidth + 7) / 8 * 8; int height = bitmap.getHeight() * width / bitmap.getWidth(); Bitmap grayBitmap = GpUtils.toGrayscale(bitmap); Bitmap rszBitmap = GpUtils.resizeImage(grayBitmap, width, height); byte[] src = GpUtils.bitmapToBWPix(rszBitmap); byte[] command = new byte[8]; height = src.length / width; command[0] = 29; command[1] = 118; command[2] = 48; command[3] = (byte)(nMode & 1); command[4] = (byte)(width / 8 % 256); command[5] = (byte)(width / 8 / 256); command[6] = (byte)(height % 256); command[7] = (byte)(height / 256); this.addArrayToCommand(command); byte[] codecontent = GpUtils.pixToEscRastBitImageCmd(src); for(int k = 0; k < codecontent.length; ++k) { this.Command.add(codecontent[k]); } } else { Log.d("BMP", "bmp. null "); } } /** * 图片去色,返回灰度图片 * */ public static Bitmap toGrayscale(Bitmap bmpOriginal) { int height = bmpOriginal.getHeight(); int width = bmpOriginal.getWidth(); Bitmap bmpGrayscale = Bitmap.createBitmap(width, height, Config.RGB_565); Canvas c = new Canvas(bmpGrayscale); Paint paint = new Paint(); ColorMatrix cm = new ColorMatrix(); cm.setSaturation(0.0F); ColorMatrixColorFilter f = new ColorMatrixColorFilter(cm); paint.setColorFilter(f); c.drawBitmap(bmpOriginal, 0.0F, 0.0F, paint); return bmpGrayscale; }

github地址:https://github.com/zoujin6649/PrinterDemo



【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3