我的编程空间,编程开发者的网络收藏夹
学习永远不晚

Android 蓝牙连接 ESC/POS 热敏打印机打印实例(ESC/POS指令篇)

短信预约 -IT技能 免费直播动态提醒
省份

北京

  • 北京
  • 上海
  • 天津
  • 重庆
  • 河北
  • 山东
  • 辽宁
  • 黑龙江
  • 吉林
  • 甘肃
  • 青海
  • 河南
  • 江苏
  • 湖北
  • 湖南
  • 江西
  • 浙江
  • 广东
  • 云南
  • 福建
  • 海南
  • 山西
  • 四川
  • 陕西
  • 贵州
  • 安徽
  • 广西
  • 内蒙
  • 西藏
  • 新疆
  • 宁夏
  • 兵团
手机号立即预约

请填写图片验证码后获取短信验证码

看不清楚,换张图片

免费获取短信验证码

Android 蓝牙连接 ESC/POS 热敏打印机打印实例(ESC/POS指令篇)

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

1. 构造输出流

首先要明确一点,就是蓝牙连接打印机这种场景下,手机是 Client 端,打印机是 Server 端。

在上一篇的最后,我们从

BluetoothSocket 
得到了一个
OutputStream
。这里我们做一层包装,得到一个
OutputStreamWriter 
对象:


OutputStreamWriter writer = new OutputStreamWriter(outputStream, "GBK");

这样做主要是为了后面可以直接输出字符串,不然只能输出 int 或 byte 数据;

2. 常用打印指令

手机通过蓝牙向打印机发送的都是纯字节流,那么打印机如何知道该打印的是一个文本,还是条形码,还是图片数据呢?

初始化打印机 :

在每次打印开始之前要调用该指令对打印机进行初始化。向打印机发送这条指令对应的代码就是:


 protected void initPrinter() throws IOException { 
    writer.write(0x1B); 
    writer.write(0x40); 
    writer.flush(); 
 }

打印文本:

没有对应指令,直接输出


protected void printText(String text) throws IOException { 
   writer.write(text);
   writer.flush();
 }

设置文本对齐方式:

对应的发送指令的代码:


   
  protected void setAlignPosition(int align) throws IOException { 
    writer.write(0x1B); 
    writer.write(0x61); 
    writer.write(align); 
    writer.flush(); 
  }

与初始化指令不同的是,这条指令带有一个参数n。

换行和制表符:

直接输出对应的字符:


 protected void nextLine() throws IOException { 
   writer.write("\n"); 
   writer.flush(); 
 }
 protected void printTab(int length) throws IOException { 
   for (int i = 0; i < length; i++) { 
     writer.write("\t"); 
   } 
   writer.flush(); 
 }

这两个指令在打印订单详情的时候使用最多。尤其是制表符,可以让每一列的文字对齐。

设置行间距:

n表示行间距为n个像素点,最大值256


protected void setLineGap(int gap) throws IOException { 
    writer.write(0x1B); 
    writer.write(0x33); 
    writer.write(gap); 
    writer.flush(); 
}

这个指令在后面打印图片的时候会用到。

3. 打印图片

很多小票上面都会附上一个二维码,用户扫描之后,可以获得更多的信息。因为热敏打印机只能打印黑白两色,所以首先把图片转成纯黑白的,再调用图片打印指令进行打印。

3.1 打印图片指令


这个指令的参数很多,一个一个来说:

m:取值十进制 0、1、32、33。设置打印精度,0、1对应每行8个点,32、33对应每行24个点,对应最高的打印精度(其实这里也没太搞清楚取值0、1或者取值32、33的区别,只要记住取值33,对应每行24个点,后面还有用) n1, n2 : 表示图片的宽度,为什么有两个?其实只是分成了高位和低位两部分,因为每部分只有8bit,最大表示256。所以 n1 = 图片宽度 % 256,n2 = 图片宽度 / 256。假设图片宽300,那么n1=1,n2=44 d1 d2 ... dk 这部分就是转换成字节流的图像数据了

3.2 图片分辨率调整

如果分辨率过大,超过了打印机可打印的最大宽度,那么超出的部分将无法打印。我试验的这台最大宽度是 384 个像素点,超过这个宽度的数据无法被打印出来。所以在开始打印之前,我们需要调整图片的分辨率。代码如下:


  
  public static Bitmap compressPic(Bitmap bitmap) {
    // 获取这个图片的宽和高
    int width = bitmap.getWidth();
    int height = bitmap.getHeight();
    // 指定调整后的宽度和高度
    int newWidth = 240;
    int newHeight = 240;
    Bitmap targetBmp = Bitmap.createBitmap(newWidth, newHeight, Bitmap.Config.ARGB_8888);
    Canvas targetCanvas = new Canvas(targetBmp);
    targetCanvas.drawColor(0xffffffff);
    targetCanvas.drawBitmap(bitmap, new Rect(0, 0, width, height), new Rect(0, 0, newWidth, newHeight), null);
    return targetBmp;
  }

3.2 图片黑白化处理

因为能够打印的图像只有黑白两色,所以需要先做黑白化的处理。这一部分其实又细分为彩色图片->灰度图片,灰度图片->黑白图片两步。直接上代码:


  
  public static byte px2Byte(int x, int y, Bitmap bit) {
    if (x < bit.getWidth() && y < bit.getHeight()) {
      byte b;
      int pixel = bit.getPixel(x, y);
      int red = (pixel & 0x00ff0000) >> 16; // 取高两位
      int green = (pixel & 0x0000ff00) >> 8; // 取中两位
      int blue = pixel & 0x000000ff; // 取低两位
      int gray = RGB2Gray(red, green, blue);
      if (gray < 128) {
        b = 1;
      } else {
        b = 0;
      }
      return b;
    }
    return 0;
  }
  
  private static int RGB2Gray(int r, int g, int b) {
    int gray = (int) (0.29900 * r + 0.58700 * g + 0.11400 * b); //灰度转化公式
    return gray;
  }

其中的灰度化转换公式是一个广为流传的公式,具体原理不明。我们直接看灰度转化为黑白的函数 px2Byte(int x, int y, Bitmap bit)。对于一个 Bitmap 中的任意一个坐标点,取出其 RGB 三色信息后做灰度化处理,然后对于灰度小于128的,用黑色表示,灰度大于128的,用白色表示。

3.3 逐行打印图片

其实打印图片和打印文本是一样的,也是一行一行的打印。直接上代码吧,注释已经尽量详细了。


  
  
  public static byte[] draw2PxPoint(Bitmap bmp) {
    //用来存储转换后的 bitmap 数据。为什么要再加1000,这是为了应对当图片高度无法   
    //整除24时的情况。比如bitmap 分辨率为 240 * 250,占用 7500 byte,
    //但是实际上要存储11行数据,每一行需要 24 * 240 / 8 =720byte 的空间。再加上一些指令存储的开销,
    //所以多申请 1000byte 的空间是稳妥的,不然运行时会抛出数组访问越界的异常。
    int size = bmp.getWidth() * bmp.getHeight() / 8 + 1000;
    byte[] data = new byte[size];
    int k = 0;
    //设置行距为0的指令
    data[k++] = 0x1B;
    data[k++] = 0x33;
    data[k++] = 0x00;
    // 逐行打印
    for (int j = 0; j < bmp.getHeight() / 24f; j++) {
      //打印图片的指令
      data[k++] = 0x1B;
      data[k++] = 0x2A;
      data[k++] = 33; 
      data[k++] = (byte) (bmp.getWidth() % 256); //nL
      data[k++] = (byte) (bmp.getWidth() / 256); //nH
      //对于每一行,逐列打印
      for (int i = 0; i < bmp.getWidth(); i++) {
        //每一列24个像素点,分为3个字节存储
        for (int m = 0; m < 3; m++) {
          //每个字节表示8个像素点,0表示白色,1表示黑色
          for (int n = 0; n < 8; n++) {
            byte b = px2Byte(i, j * 24 + m * 8 + n, bmp);
            data[k] += data[k] + b;
          }
          k++;
        }
      }
      data[k++] = 10;//换行
    }
    return data;
  }

4. 总结

用两篇介绍了一个比较冷门的应用,纯粹是因为自己花了很多时间去搞懂原理,所以希望记录下来。尤其是图片打印部分,废了好多纸啊哈哈哈,一个字节操作错误,打印出来就是一堆乱码。感觉和 java 的 .class 文件很像,每一个指令占用多少位,每一位表示什么都是严格规定好的,不能超出也不能缺少。

最后希望能帮到需要的人吧,感觉网上这部分资料还是比较少的。也希望大家多多支持编程网。

您可能感兴趣的文章:Android实现PDF预览打印功能Android gradle插件打印时间戳的方法详解Android编程实现计算两个日期之间天数并打印所有日期的方法Android中如何安全地打印日志详解Mac 下 Android Studio 不打印日志的解决办法Android jni调试打印char阵列的实例详解Android下的POS打印机调用的简单实现Android 蓝牙连接 ESC/POS 热敏打印机打印实例(蓝牙连接篇)Android打印机--小票打印格式及模板设置实例代码Android进阶——安卓调用ESC/POS打印机打印实例Android手机通过蓝牙连接佳博打印机的实例代码Android实现系统打印功能


免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

Android 蓝牙连接 ESC/POS 热敏打印机打印实例(ESC/POS指令篇)

下载Word文档到电脑,方便收藏和打印~

下载Word文档

猜你喜欢

Android 蓝牙连接 ESC/POS 热敏打印机打印实例(ESC/POS指令篇)

上一篇 主要介绍了如何通过蓝牙连接到打印机。这一篇,我们就介绍如何向打印机发送打印指令,来打印字符和图片。1. 构造输出流 首先要明确一点,就是蓝牙连接打印机这种场景下,手机是 Client 端,打印机是 Server 端。 在上一篇的最后
2022-06-06

Android 蓝牙连接 ESC/POS 热敏打印机打印实例(蓝牙连接篇)

公司的一个手机端的 CRM 项目最近要增加小票打印的功能,就是我们点外卖的时候经常会见到的那种小票。这里主要涉及到两大块的知识:蓝牙连接及数据传输ESC/POS 打印指令 蓝牙连接不用说了,太常见了,这篇主要介绍这部分的内容。但ESC/PO
2022-06-06

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

前言前一段时间由于工作需要,要研究一下安卓程序调用打印机打印小票,并且要求不能使用蓝牙调用,研究了一下,可以利用socket连接,来实现打印功能。写了个Demo,分享一下。工具:一台打印机(芯烨XP-80XX),一台安卓测试机开发环境:An
2022-06-06

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

所使用的打印机为佳博打印机,支持蓝牙、wifi、usb我所使用的是通过蓝牙来连接。在网上找到一个佳博官方针对安卓开发的App源码,但是各种的跳转,没有看太懂,所以又去问度娘,找到了一个不错的文章Android对于蓝牙开发从2.0版本的sdk
2022-06-06

编程热搜

  • Android:VolumeShaper
    VolumeShaper(支持版本改一下,minsdkversion:26,android8.0(api26)进一步学习对声音的编辑,可以让音频的声音有变化的播放 VolumeShaper.Configuration的三个参数 durati
    Android:VolumeShaper
  • Android崩溃异常捕获方法
    开发中最让人头疼的是应用突然爆炸,然后跳回到桌面。而且我们常常不知道这种状况会何时出现,在应用调试阶段还好,还可以通过调试工具的日志查看错误出现在哪里。但平时使用的时候给你闹崩溃,那你就欲哭无泪了。 那么今天主要讲一下如何去捕捉系统出现的U
    Android崩溃异常捕获方法
  • android开发教程之获取power_profile.xml文件的方法(android运行时能耗值)
    系统的设置–>电池–>使用情况中,统计的能耗的使用情况也是以power_profile.xml的value作为基础参数的1、我的手机中power_profile.xml的内容: HTC t328w代码如下:
    android开发教程之获取power_profile.xml文件的方法(android运行时能耗值)
  • Android SQLite数据库基本操作方法
    程序的最主要的功能在于对数据进行操作,通过对数据进行操作来实现某个功能。而数据库就是很重要的一个方面的,Android中内置了小巧轻便,功能却很强的一个数据库–SQLite数据库。那么就来看一下在Android程序中怎么去操作SQLite数
    Android SQLite数据库基本操作方法
  • ubuntu21.04怎么创建桌面快捷图标?ubuntu软件放到桌面的技巧
    工作的时候为了方便直接打开编辑文件,一些常用的软件或者文件我们会放在桌面,但是在ubuntu20.04下直接直接拖拽文件到桌面根本没有效果,在进入桌面后发现软件列表中的软件只能收藏到面板,无法复制到桌面使用,不知道为什么会这样,似乎并不是很
    ubuntu21.04怎么创建桌面快捷图标?ubuntu软件放到桌面的技巧
  • android获取当前手机号示例程序
    代码如下: public String getLocalNumber() { TelephonyManager tManager =
    android获取当前手机号示例程序
  • Android音视频开发(三)TextureView
    简介 TextureView与SurfaceView类似,可用于显示视频或OpenGL场景。 与SurfaceView的区别 SurfaceView不能使用变换和缩放等操作,不能叠加(Overlay)两个SurfaceView。 Textu
    Android音视频开发(三)TextureView
  • android获取屏幕高度和宽度的实现方法
    本文实例讲述了android获取屏幕高度和宽度的实现方法。分享给大家供大家参考。具体分析如下: 我们需要获取Android手机或Pad的屏幕的物理尺寸,以便于界面的设计或是其他功能的实现。下面就介绍讲一讲如何获取屏幕的物理尺寸 下面的代码即
    android获取屏幕高度和宽度的实现方法
  • Android自定义popupwindow实例代码
    先来看看效果图:一、布局
  • Android第一次实验
    一、实验原理 1.1实验目标 编程实现用户名与密码的存储与调用。 1.2实验要求 设计用户登录界面、登录成功界面、用户注册界面,用户注册时,将其用户名、密码保存到SharedPreference中,登录时输入用户名、密码,读取SharedP
    Android第一次实验

目录