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

常用的打印命令介绍

初始化打印机

  1. ASCII ESC @
  2. 十进制码 27 64

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

  1. byte [] esc_init=new byte[]{27,64};
  2. mDeviceConnection.bulkTransfer(endpointOut, esc_init, esc_init.length, TIME_OUT);

设置对齐方式

  1. ASCII ESC a n
  2. 十进制码 27 97 n
n 对齐方式
0,48 左对齐
1,49 中间对齐
2,50 右对齐
  1. byte [] esc_gravity=new byte[] {27,97,0}//左对齐
  2. mDeviceConnection.bulkTransfer(endpointOut, esc_gravity, esc_gravity.length, TIME_OUT);

字体加粗

  1. ASCII ESC n
  2. 十进制码 27 33 n
n 效果
0 取消加粗
8 加粗
  1. byte [] esc_bold=new byte[] {27,33,8}//加粗
  2. mDeviceConnection.bulkTransfer(endpointOut, esc_bold, esc_bold.length, TIME_OUT);

字体倍高倍宽

  1. ASCII ESC n
  2. 十进制码 27 33 n
n 效果
0 正常
16 倍高
32 倍宽

走纸

  1. ASCII ESC d n
  2. 十进制码 27 100 n

参数含义:0<=n<=255
说明:打印缓冲区中的数据并向前走纸n行

打印光栅位图

  1. ASCII GS v 0 m xL xH yL yH d1...dk
  2. 十进制码 29 118 48 m xL xH yL yH d1...dk

m :指的是打印模式

m值 打印模式
0,48 正常
1,49 倍宽
2,50 倍高
3,51 倍宽倍高

xL:位图宽度以双字节表示的低位数值
XH:位图宽度以双字节表示的高位数值
比如位图宽度是200,宽度占的字节数=200/8=25;
为什么除以8?因为待打印位图的位图是灰度图,一个像素占用一个字节。后面解释什么是灰度图。
25的二进制表示是00000000 00011001。所以xL=0(高8位),xH=25(低8位);
所以水平方向位图点数为 (xL+xH_256)_8
yL:位图高度以双字节表示的低位数值
yH:位图高度以双字节表示的高位数值
竖直方向位图点数为 yL+yH256
比如位图高度是200
200的二进制表示是 00000000 11001000。所以yL=200,yH=0;
d1…dk:代表位图数据,每个字节相应位为1表示打印该点,为0不打印该点。
举例:
假设图片尺寸200px_200px
那么(xL+xH_256)=25
yL+yH
256=200;

1 2 3 23 24 25
26 27 28 48 49 50
4976 4977 4978 4998 4999 5000

其中每个小格由横向的8位组成,相应位为1表示打印该点,为0不打印该点。

规范化位图

用户传入的位图的尺寸是随意的,需要将位图的宽度规范化为8的整数倍。

  1. private Bitmap resizeImage(Bitmap bitmap, int requestWidth) {
  2. //将位图宽度规范化为8的整数倍
  3. int legalWidth=(requestWidth+7)/8*8;
  4. int height= (int) (legalWidth*bitmap.getHeight()/(float)bitmap.getWidth());
  5. return Bitmap.createScaledBitmap(bitmap,legalWidth,height,true);
  6. }

图像的灰度化

首先什么是灰度化?
在RGB模型中,当R=G=B时,则彩色表示一种灰度颜色,其中R=G=B的值叫灰度值。因此,灰度图每个像素只需一个字节存放灰度值,灰度范围为0-255.一般有分量法 、最大值法、平均值法、加权平均法对彩色图像进行灰度化。
说一下加权平均法:
由于人眼对绿色的敏感最高,对蓝色敏感最低,因此,按下式对RGB三分量进行加权平均能得到比较合理的灰度图像。
Gray=0.30_R+0.59_G+0.11B
程序实现

  1. private int grayPixle(int pixel) {
  2. int red=(pixel & 0x00ff0000) >> 16;//获取r分量
  3. int green= (pixel & 0x0000ff00) >> 8;//获取g分量
  4. int blue= pixel & 0x000000ff;//获取b分量
  5. return (int) (red*0.3f+green*0.59f+blue*0.11f);//加权平均法进行灰度化
  6. }

灰度图的二值化

图像的二值化就是将图像上的像素点的灰度值设置为0或或者255,也就是将整个图像呈现出明显的黑白效果的过程。所有灰度大于或等于阈值的像素被判定为属于特定物体,其灰度值为255表示,否则这些像素点被排除在物体区域以外,灰度值为0,表示背景或者例外的物体区域。
阈值的选取是至关重要,直接影响着二值化后的图片的质量。对于我们的打印程序选128就行,要求不高。

  1. //存储位图数据d1...dk
  2. byte[] data = new byte[width * height];
  3. int index = 0;
  4. int temp = 0;
  5. int part[]=new int[8];
  6. //for循环顺序不要错了,外层遍历高度,内层遍历宽度,因为横向每8个像素点组成一个字节。
  7. for (int j=0;j<bitmap.getHeight();j++){
  8. for (int i=0;i<bitmap.getWidth();i+=8){
  9. //横向每8个像素点组成一个字节。
  10. for(int k=0;k<8;k++) {
  11. int pixel = bitmap.getPixel(i+k, j);
  12. int grayPixle = grayPixle(pixel);
  13. if (grayPixle >128) {
  14. //灰度值大于128位 白色 为第k位0不打印
  15. part[k]=0;
  16. } else {
  17. part[k]=1;
  18. }
  19. }
  20. //128千万不要写成2^7,^是异或操作符
  21. temp=part[0]*128+
  22. part[1]*64+
  23. part[2]*32+
  24. part[3]*16+
  25. part[4]*8+
  26. part[5]*4+
  27. part[6]*2+
  28. part[7]*1;
  29. data[index++] = (byte) temp;
  30. }
  31. }

以上就获得了d1…dk位图数据
完整的代码

  1. // 使用光栅位图的打印方式
  2. public void printBitmap(Bitmap bitmap,int requestWidth) throws Exception {
  3. // GS v 0 m xL xH yL yH d1...dk
  4. if (bitmap == null) {
  5. throw new Exception("bitmap is null");
  6. }
  7. //规范化位图宽高
  8. bitmap=resizeImage(bitmap,requestWidth);
  9. int width = bitmap.getWidth() / 8;
  10. int height = bitmap.getHeight();
  11. byte []cmd= new byte[width * height+4+4];
  12. cmd[0]=29;
  13. cmd[1]=118;
  14. cmd[2]=48;
  15. cmd[3]=0;
  16. cmd[4]= (byte) (width % 256);//计算xL
  17. cmd[5]=(byte) (width / 256);//计算xH
  18. cmd[6]= (byte) (height % 256);//计算yL
  19. cmd[7]=(byte) (height / 256);//计算yH
  20. int index = 8;
  21. int temp = 0;
  22. int part[]=new int[8];
  23. for (int j=0;j<bitmap.getHeight();j++){
  24. for (int i=0;i<bitmap.getWidth();i+=8){
  25. //横向每8个像素点组成一个字节。
  26. for(int k=0;k<8;k++) {
  27. int pixel = bitmap.getPixel(i+k, j);
  28. int grayPixle = grayPixle(pixel);
  29. if (grayPixle >128) {
  30. //灰度值大于128位 白色 为第k位0不打印
  31. part[k]=0;
  32. } else {
  33. part[k]=1;
  34. }
  35. }
  36. //128千万不要写成2^7,^是异或操作符
  37. temp=part[0]*128+
  38. part[1]*64+
  39. part[2]*32+
  40. part[3]*16+
  41. part[4]*8+
  42. part[5]*4+
  43. part[6]*2+
  44. part[7]*1;
  45. cmd[index++] = (byte) temp;
  46. }
  47. }
  48. mDeviceConnection.bulkTransfer(endpointOut, cmd, esc_bold.length, TIME_OUT);
  49. }