Android打印机--小票打印格式及模板设置

蹉跎莫遣韶光老,人生唯有读书好。这篇文章主要讲述Android打印机--小票打印格式及模板设置相关的知识,希望能为你提供帮助。
小票打印就是向打印设备发送控制打印格式的指令集,而这些打印格式需要去查询对应打印机的API文档,这里我把常用的api给封装了一下

  • 文字对齐方式
  • 打印字体大小
  • 字体是否加粗
  • 打印二维码
  • 打印条形码
  • 切纸
  • 打开钱箱
  • 字符串转字节数组
  • 字符拼接
PrintFormatUtils.java
/** * 打印格式 * Created by john on 17-3-23. */public class PrintFormatUtils { // 对齐方式 public static final int ALIGN_LEFT = 0; // 靠左 public static final int ALIGN_CENTER = 1; // 居中 public static final int ALIGN_RIGHT = 2; // 靠右//字体大小 public static final int FONT_NORMAL = 0; // 正常 public static final int FONT_MIDDLE = 1; // 中等 public static final int FONT_BIG = 2; // 大//加粗模式 public static final int FONT_BOLD = 0; // 字体加粗 public static final int FONT_BOLD_CANCEL = 1; // 取消加粗/** * 打印二维码 * @param qrCode * @return */ public static String getQrCodeCmd(String qrCode) { byte[] data; int store_len = qrCode.length() + 3; byte store_pL = (byte) (store_len % 256); byte store_pH = (byte) (store_len / 256); // QR Code: Select the model //Hex1D286B04003141n1(x32)n2(x00) - size of model // set n1 [49 x31, model 1] [50 x32, model 2] [51 x33, micro qr code] // https://reference.epson-biz.com/modules/ref_escpos/index.php?content_id=140 byte[] modelQR = {(byte)0x1d, (byte)0x28, (byte)0x6b, (byte)0x04, (byte)0x00, (byte)0x31, (byte)0x41, (byte)0x32, (byte)0x00}; // QR Code: Set the size of module // Hex1D286B03003143n // n depends on the printer // https://reference.epson-biz.com/modules/ref_escpos/index.php?content_id=141 byte[] sizeQR = {(byte)0x1d, (byte)0x28, (byte)0x6b, (byte)0x03, (byte)0x00, (byte)0x31, (byte)0x43, (byte)0x08}; //Hex1D286B03003145n // Set n for error correction [48 x30 -> 7%] [49 x31-> 15%] [50 x32 -> 25%] [51 x33 -> 30%] // https://reference.epson-biz.com/modules/ref_escpos/index.php?content_id=142 byte[] errorQR = {(byte)0x1d, (byte)0x28, (byte)0x6b, (byte)0x03, (byte)0x00, (byte)0x31, (byte)0x45, (byte)0x31}; // QR Code: Store the data in the symbol storage area // Hex1D286BpLpH315030d1...dk // https://reference.epson-biz.com/modules/ref_escpos/index.php?content_id=143 //1D286BpLpHcn(49-> x31) fn(80-> x50) m(48-> x30) d1…dk byte[] storeQR = {(byte)0x1d, (byte)0x28, (byte)0x6b, store_pL, store_pH, (byte)0x31, (byte)0x50, (byte)0x30}; // QR Code: Print the symbol data in the symbol storage area // Hex1D286B03003151m // https://reference.epson-biz.com/modules/ref_escpos/index.php?content_id=144 byte[] printQR = {(byte)0x1d, (byte)0x28, (byte)0x6b, (byte)0x03, (byte)0x00, (byte)0x31, (byte)0x51, (byte)0x30}; data = https://www.songbingjia.com/android/byteMerger(modelQR, sizeQR); data = byteMerger(data, errorQR); data = byteMerger(data, storeQR); data = byteMerger(data, qrCode.getBytes()); data = byteMerger(data, printQR); return new String(data); }/** * 打印条码 * @param barcode * @return */ public static String getBarcodeCmd(String barcode) { // 打印 Code-128 条码时需要使用字符集前缀 //"{A" 表示大写字母 // "{B" 表示所有字母,数字,符号 // "{C" 表示数字,可以表示 00 - 99 的范围byte[] data; String btEncode; if (barcode.length() < 18) { // 字符长度小于15的时候直接输出字符串 btEncode = "{B" + barcode; } else { // 否则做一点优化int startPos = 0; btEncode = "{B"; for (int i = 0; i < barcode.length(); i++) { char curChar = barcode.charAt(i); if (curChar < 48 || curChar > 57 || i == (barcode.length() - 1)) { // 如果是非数字或者是最后一个字符if (i - startPos > = 10) { if (startPos == 0) { btEncode = ""; }btEncode += "{C"; boolean isFirst = true; int numCode = 0; for (int j = startPos; j < i; j++) {if (isFirst) { // 处理第一位 numCode = (barcode.charAt(j) - 48) * 10; isFirst = false; } else { // 处理第二位 numCode += (barcode.charAt(j) - 48); btEncode += (char) numCode; isFirst = true; }}btEncode += "{B"; if (!isFirst) { startPos = i - 1; } else { startPos = i; } }for (int k = startPos; k < = i; k++) { btEncode += barcode.charAt(k); } startPos = i + 1; }} }// 设置 HRI 的位置,02 表示下方 byte[] hriPosition = {(byte) 0x1d, (byte) 0x48, (byte) 0x02}; // 最后一个参数表示宽度 取值范围 1-6 如果条码超长则无法打印 byte[] width = {(byte) 0x1d, (byte) 0x77, (byte) 0x02}; byte[] height = {(byte) 0x1d, (byte) 0x68, (byte) 0xfe}; // 最后两个参数 73 : CODE 128 || 编码的长度 byte[] barcodeType = {(byte) 0x1d, (byte) 0x6b, (byte) 73, (byte) btEncode.length()}; byte[] print = {(byte) 10, (byte) 0}; data = https://www.songbingjia.com/android/PrintFormatUtils.byteMerger(hriPosition, width); data = PrintFormatUtils.byteMerger(data, height); data = PrintFormatUtils.byteMerger(data, barcodeType); data = PrintFormatUtils.byteMerger(data, btEncode.getBytes()); data = PrintFormatUtils.byteMerger(data, print); return new String(data); }/** * 切纸 * @return */ public static String getCutPaperCmd() { // 走纸并切纸,最后一个参数控制走纸的长度 byte[] data = {(byte) 0x1d, (byte) 0x56, (byte) 0x42, (byte) 0x15}; return new String(data); }/** * 对齐方式 * @param alignMode * @return */ public static String getAlignCmd(int alignMode) { byte[] data = {(byte) 0x1b, (byte) 0x61, (byte) 0x0}; if (alignMode == ALIGN_LEFT) { data[2] = (byte) 0x00; } else if (alignMode == ALIGN_CENTER) { data[2] = (byte) 0x01; } else if (alignMode == ALIGN_RIGHT) { data[2] = (byte) 0x02; }return new String(data); }/** * 字体大小 * @param fontSize * @return */ public static String getFontSizeCmd(int fontSize) { byte[] data = {(byte) 0x1d, (byte) 0x21, (byte) 0x0}; if (fontSize == FONT_NORMAL) { data[2] = (byte) 0x00; } else if (fontSize == FONT_MIDDLE) { data[2] = (byte) 0x01; } else if (fontSize == FONT_BIG) { data[2] = (byte) 0x11; }return new String(data); }/** * 加粗模式 * @param fontBold * @return */ public static String getFontBoldCmd(int fontBold) { byte[] data = {(byte) 0x1b, (byte) 0x45, (byte) 0x0}; if (fontBold == FONT_BOLD) { data[2] = (byte) 0x01; } else if (fontBold == FONT_BOLD_CANCEL) { data[2] = (byte) 0x00; }return new String(data); }/** * 打开钱箱 * @return */ public static String getOpenDrawerCmd() { byte[] data = new byte[4]; data[0] = 0x10; data[1] = 0x14; data[2] = 0x00; data[3] = 0x00; return new String(data); }/** * 字符串转字节数组 * @param str * @return */ public static byte[] stringToBytes(String str) { byte[] data = null; try { byte[] strBytes = str.getBytes("utf-8"); data = https://www.songbingjia.com/android/(new String(strBytes,"utf-8")).getBytes("gbk"); } catch (UnsupportedEncodingException exception) { exception.printStackTrace(); }return data; }/** * 字节数组合并 * @param bytesA * @param bytesB * @return */ public static byte[] byteMerger(byte[] bytesA, byte[] bytesB) { byte[] bytes = new byte[bytesA.length + bytesB.length]; System.arraycopy(bytesA, 0, bytes, 0, bytesA.length); System.arraycopy(bytesB, 0, bytes, bytesA.length, bytesB.length); return bytes; } }

有了打印格式,还要对具体的打印小票设置打印模板,主要就是利用上面的打印格式工具类,进行字符或字符串拼接,设置文字间空格的长度,以及使用换行符换行等。
【Android打印机--小票打印格式及模板设置】有些小票打印的内容有可能是通用的,比如底部结束语–可能是公司宣传语或广告语,这些内容是否展示需要根据具体需求加以控制,还有二维码、条形码打印,是否切纸等需要根据实际场景取舍,所以最好封装一个打印配置类,以控制打印内容显示。
/** * 打印模板 */ public class PrintContract {/** * 打印内容 */ public static StringBuilder createXxTxt(String ...) {StringBuilder builder = new StringBuilder(); //设置大号字体以及加粗 builder.append(PrintFormatUtils.getFontSizeCmd(PrintFormatUtils.FONT_BIG)); builder.append(PrintFormatUtils.getFontBoldCmd(PrintFormatUtils.FONT_BOLD)); // 标题 builder.append("Title"); //换行,调用次数根据换行数来控制 addLineSeparator(builder); //设置普通字体大小、不加粗 builder.append(PrintFormatUtils.getFontSizeCmd(PrintFormatUtils.FONT_NORMAL)); builder.append(PrintFormatUtils.getFontBoldCmd(PrintFormatUtils.FONT_BOLD_CANCEL)); //内容 ......//设置某两列文字间空格数, x需要计算出来 addIdenticalStrToStringBuilder(builder, x, " "); //切纸 builder.append(PrintFormatUtils.getCutPaperCmd()); return builder; }/** * 向StringBuilder中添加指定数量的相同字符 * * @param printCount添加的字符数量 * @param identicalStr 添加的字符 */private static void addIdenticalStrToStringBuilder(StringBuilder builder, int printCount, String identicalStr) { for (int i = 0; i < printCount; i++) { builder.append(identicalStr); } }/** * 根据字符串截取前指定字节数,按照GBK编码进行截取 * * @param str 原字符串 * @param len 截取的字节数 * @return 截取后的字符串 */ private static String subStringByGBK(String str, int len) { String result = null; if (str != null) { try { byte[] a = str.getBytes("GBK"); if (a.length < = len) { result = str; } else if (len > 0) { result = new String(a, 0, len, "GBK"); int length = result.length(); if (str.charAt(length - 1) != result.charAt(length - 1)) { if (length < 2) { result = null; } else { result = result.substring(0, length - 1); } } } } catch (Exception e) { e.printStackTrace(); } } return result; }/** * 添加换行符 */ private static void addLineSeparator(StringBuilder builder) { builder.append("\n"); }/** * 在GBK编码下,获取其字符串占据的字符个数 */ private static int getCharCountByGBKEncoding(String text) { try { return text.getBytes("GBK").length; } catch (Exception e) { e.printStackTrace(); return 0; } }/** * 打印相关配置 */ public static class PrintConfig { public int maxLength = 30; public boolean printBarcode = false; // 打印条码 public boolean printQrCode = false; // 打印二维码 public boolean printEndText = true; // 打印结束语 public boolean needCutPaper = false; // 是否切纸 }}

有了打印模板,接下来就是调用打印设备打印方法发送打印指令
//调用打印机打印方法,传入上面某个小票打印模板返回的字符串 String str = PrintContract.createXxTxt(...); printer.print(str, null); //打开钱箱方法 printer.print(PrintFormatUtils.getOpenDrawerCmd(), null);


    推荐阅读