Android打印机--小票打印格式及模板设置实例代码

小票打印就是向打印设备发送控制打印格式的指令集,而这些打印格式需要去查询对应打印机的API文档,这里我把常用的api给封装了一下

  1. 文字对齐方式
  2. 打印字体大小
  3. 字体是否加粗
  4. 打印二维码
  5. 打印条形码
  6. 切纸
  7. 打开钱箱
  8. 字符串转字节数组
  9. 字符拼接

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
    //       Hex   1D   28   6B   04   00   31   41   n1(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
    // Hex   1D   28   6B   03   00   31   43   n
    // 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};

    //     Hex   1D   28   6B   03   00   31   45   n
    // 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
    // Hex   1D   28   6B   pL   pH   31   50   30   d1...dk
    // https://reference.epson-biz.com/modules/ref_escpos/index.php?content_id=143
    //            1D     28     6B     pL     pH cn(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
    // Hex   1D   28   6B   03   00   31   51   m
    // 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 = 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 = 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 = (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;
  }
}

有了打印格式,还要对具体的打印小票设置打印模板,主要就是利用上面的打印格式工具类,进行字符或字符串拼接,设置文字间空格的长度,以及使用换行符换行等。

有些小票打印的内容有可能是通用的,比如底部结束语–可能是公司宣传语或广告语,这些内容是否展示需要根据具体需求加以控制,还有二维码、条形码打印,是否切纸等需要根据实际场景取舍,所以最好封装一个打印配置类,以控制打印内容显示。

/**
 * 打印模板
 */
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);

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持我们。

(0)

相关推荐

  • Android进阶——安卓调用ESC/POS打印机打印实例

    前言 前一段时间由于工作需要,要研究一下安卓程序调用打印机打印小票,并且要求不能使用蓝牙调用,研究了一下,可以利用socket连接,来实现打印功能.写了个Demo,分享一下. 工具:一台打印机(芯烨XP-80XX),一台安卓测试机 开发环境:Android Studio 1.5 需求:点击按钮,实现打印小票功能,小票上除必要文字外,还要有二维码. 封装了一个Pos打印工具类: package com.example.haoguibao.myapplication; import java.io.

  • Android手机通过蓝牙连接佳博打印机的实例代码

    所使用的打印机为佳博打印机,支持蓝牙.wifi.usb我所使用的是通过蓝牙来连接. 在网上找到一个佳博官方针对安卓开发的App源码,但是各种的跳转,没有看太懂,所以又去问度娘,找到了一个不错的文章 Android对于蓝牙开发从2.0版本的sdk才开始支持,而且模拟器不支持,测试至少需要两部手机,所以制约了很多技术人员的开发. 1. 首先,要操作蓝牙,先要在AndroidManifest.xml里加入权限 // 管理蓝牙设备的权限 <uses-permissionandroid:name="

  • Android打印机--小票打印格式及模板设置实例代码

    小票打印就是向打印设备发送控制打印格式的指令集,而这些打印格式需要去查询对应打印机的API文档,这里我把常用的api给封装了一下 文字对齐方式 打印字体大小 字体是否加粗 打印二维码 打印条形码 切纸 打开钱箱 字符串转字节数组 字符拼接 PrintFormatUtils.Java /** * 打印格式 * Created by john on 17-3-23. */ public class PrintFormatUtils { // 对齐方式 public static final int

  • Android 系统语言切换监听和设置实例代码

    最近项目上产品经理提了个需求,要求关闭语言国际化,不管手机系统设置那个国家的语言,都要显示汉语,好吧,既然有需求,那就做吧.但是项目中已经有英文的配置了,且是作为默认String提供的,这么多翻译好的文字,直接删除掉替换成中文为默认String又感觉弃之可惜.故网上Google下解决方案.就开始往下看吧. 一.代码中动态设置应用显示语言(手动控制使用values-zh-rCN下字符串) 这个方法是通过改变Resource中的配置来实现的,代码如下: public static void init

  • SpringMVC中使用Thymeleaf模板引擎实例代码

    本文研究的主要是SpringMVC中使用Thymeleaf模板引擎的相关内容,具体介绍如下. Thymeleaf提供了一组Spring集成,允许您将其用作Spring MVC应用程序中全面替代JSP的功能. Maven依赖 <!-- thymeleaf-spring4 --> <dependency> <groupId>org.thymeleaf</groupId> <artifactId>thymeleaf-spring4</artifa

  • Android加载loading对话框的功能及实例代码(不退出沉浸式效果)

    一.自定义Dialog 在沉浸式效果下,当界面弹出对话框时,对话框将获取到焦点,这将导致界面退出沉浸式效果,那么是不是能通过屏蔽对话框获取焦点来达到不退出沉浸式的目的呢.说干就干,我们先来看一下改善后的效果图. 普通对话框弹出效果 LoadingDialog弹出效果 自定义LoadingDialog public class LoadingDialog extends Dialog { public LoadingDialog(Context context) { super(context);

  • 三种Java打印PDF文档的实例代码

    以下内容归纳了通过Java程序打印PDF文档时的3种情形.即: 1 静默打印 2 显示打印对话框打印 3 打印PDF时自定义纸张大小 使用工具:Spire.PDF for Java Jar文件获取及导入: 方法1:下载jar包.下载后,解压文件,并将lib文件夹下的Spire.Pdf.jar导入java程序. 方法2:可通过maven库导入.参考导入方法. Java代码示例 [示例1]静默打印 即通过使用默认打印机直接打印PDF文档.打印时,我们可以设置打印份数,设置纸张打印页边距等. impo

  • Android利用ZXing扫描二维码的实例代码解析

    相关阅读: Android开发框架之自定义ZXing二维码扫描界面并解决取景框拉伸问题 此项目源码地址:请点击这里 看一下zxing的项目结构,我这里直接拿过来用的 看一下扫码的activity: package com.fanyafeng.barcode.activity; import android.content.Intent; import android.graphics.Bitmap; import android.net.Uri; import android.os.Bundle

  • Android仿美团下拉菜单(商品选购)实例代码

    美团电商应用平台大家使用非常频繁,下面小编通过本文给大家介绍电商应用平台中常用的选择类别下拉列表的实现.先给大家展示下效果图: 一.下拉列表的实现 其实实现方法有很多,这时实现的也没有什么技术含量,只是总结下自己在项目中的做法,也提供一个思路. 首先是列表的数据,一般数据都是从后台读过来,这里因为没有后台,所以写死在客户端: private void initMenuData() { menuData = new ArrayList<map<string, string=""

  • Android 中TabLayout自定义选择背景滑块的实例代码

    TabLayout是Android 的Material Design包中的一个控件,可以和V4包中的ViewPager搭配产生一个联动的效果.这里我自定义了一个滑块能够跟随TabLayout进行滑动选择的SliderLayout.效果见下图(白色方框): 下面是SliderLayout的源码: import android.content.Context; import android.content.res.TypedArray; import android.graphics.drawabl

  • Android自定义View实现箭头沿圆转动实例代码

    具体代码如下所示: //MyCircleView类 public class MyCircleView extends View{ //当前画笔画圆的颜色 private int CurrenCircleBoundColor; private Paint paint; ////从xml中获取的颜色 private int circleBundColor; private float circleBoundWidth; private float pivotX; private float piv

  • Android 自定义弹出菜单和对话框功能实例代码

    Android 开发当中,可能会存在许多自定义布局的需求,比如自定义弹出菜单(popupWindow),以及自定义对话框(Dialog). 话不多说,直接上图片. 先讲第一种,自定义PopUpWindow 1.popupWindow protected void showPopWindow(View view, final int pos){ WindowManager wm= (WindowManager) myContext.getSystemService(Context.WINDOW_S

随机推荐