android 热敏打印机统一接口

作者: cgrass | 来源:发表于2017-03-19 00:42 被阅读3253次

    android开发中接触热敏打印机的开发比较少,然而我换了2份工作老是碰到,乘着有点时间我在这边做下归类和总结,希望对大家开发有所帮助。

    一.热敏打印机分类介绍

    本人接触过的热敏打印机大体分成2个类别,驱动型打印机和无驱动型热敏打印机。

    驱动型打印机

    其实就是打印机产商提供打印的接口,这种开发就比较容易,快速,基本上产商都把你所需要做的事情都做了差不多了,不需要进行多于的学习和编程。

    无驱动型打印机

    这个就是本编文章所要处理的事情,没有产商的协助,从零开搞,为了实现多类型(wifi,蓝牙,串口),多产商(a,b,c型打印机)打印需求所以我在这边进行设计和封装了打印接口,以便适应市场上的大多数热敏打印机进行开发工作。

    二.热敏打印机接口介绍

    这边的设计采用了工厂设计模型,设计通用型wifi连接打印机的这种打印类型的接口(目前本人就接触了蓝牙,wifi,驱动打印机),由于蓝牙因为手头没有机器无法进行验证接口是否可行,所以不提供这方面的相关代码。
    本人初步设计的接口如下:

       void InitPrint();//初始化打印
        boolean preparePrint();//准备打印操作,
        void endPrint();//打印结束释放内存等.
        void releasePrint();//释放打印资源
        void printText(String content, PrintFormat format);//打印文本内容
        void printBitmap(Bitmap bitmap, PrintFormat format, int widthPix, int heightPix);//打印图片
        void pinrtBrandCode(String content, PrintFormat format, int widthPix, int heightPix);//打印条形码
        void printQrCode(String content, PrintFormat format, Bitmap logo, int widthPix, int heightPix);//打印二维码
        void feedPaper(int rownum, int num);//走纸,第一个是走纸n行,第二个是走纸的向前走纸的 数目,
        void cutPaper();//裁剪纸张,部分打印机没有这个功能
        void printEnter();// 打印换行
        boolean startPrint(boolean cutpaper);//开始打印
    

    列举了一些常用的方法。
    以下是我的项目地址,有需要的可以去看看,或者加入我的邪恶组织,一起完成统一接口的这个长远目标(组织的目的,开发个通用型打印接口)。
    工程内注释很详细,如果有不明的可以通过站内信息联系到我。
    https://github.com/GrassQing/CommonPrintProvider

    二.打印原理介绍和实现

    如果感觉我上面那个项目提供的接口或者写的东西实在太难看了又正在开发热敏打印机打印功能的高手们,不妨看看热敏打印机打印命令和实现方式。

    打印指令传输

    通过socket进行连接

     private boolean SendMsgCommand(final String ip, final int port)
                throws UnknownHostException, IOException {
    
    
            try {
    
                socket = new Socket(ip, port);
                outputStream = socket.getOutputStream();
                //这边是输入指令根据自己的需求进行输入
                for (int i = 0; i < eCmd.getbList().size(); i++) {
                    outputStream.write(eCmd.getbList().get(i));
                }
              
                outputStream.flush();
                outputStream.close();
                socket.close();
                return true;
            } catch (UnknownHostException e) {
                e.printStackTrace();
                if (socket != null)
                    socket.close();
                return false;
            } catch (IOException e) {
                e.printStackTrace();
                if (socket != null)
                    socket.close();
                return false;
            }
        }
    

    初始化打印机

    部分打印机必须初始化
    初始化指令初始化new byte[] {ESC, '@'};,byte ESC = 0x1B;

     /**
         * 初始化打印机
         */
        public void esc_init() {
            byteList.add(Command.ESC_INIT);
        }
    

    文本打印

    文本打印指令:new byte[] {FS, '&'};进入汉字模式,byte FS = 0x1C;
    接着输入打印内容的byte[] 类型数据,最后结束汉字模式
    new byte[] {FS, '.'};

    /**
         * 中文模式 打印GBK模式的文本
         *
         * @param text
         */
        public void esc_text(String text, String encoding) {
            
            byteList.add(Command.ESC_CN_MODE);
            try {
                byteList.add(text.getBytes(encoding));
            } catch (UnsupportedEncodingException e) {
                // TODO Auto-generated catch block
                throw new RuntimeException("port " + text + " is invalid, ", e);
            }
            byteList.add(Command.ESC_CN_MODE_OFF);
        }
    

    字体加粗

    粗 :new byte[]{ESC, 'G', 0x01},byte ESC = 0x1B;
    不加粗:new byte[]{ESC, 'G', 0x00};
    对于打印的字体加粗时必须设置在文本打印之前,打印完必须复原。
    例如:
    settext(粗),esc_text("打印"),settext(不加粗),继续打印。其他格式设置类似。

    字体大小

    普通字体:
    new byte[]{GS, '!', 0x00},byte GS = 0x1D;
    双倍高:
    new byte[]{GS, '!', 0x01},byte GS = 0x1D;
    双倍宽:
    new byte[]{GS, '!', 0x10},byte GS = 0x1D;
    双倍高宽:
    new byte[]{GS, '!', 0x11},byte GS = 0x1D;

    图片打印

    这一部分当初还是通过简书方面查找到资料,自己稍微做了下改动,使其更加的稳定了些,可能对部分打印机存在兼容问题。

    public static byte[] draw2PxPoint(Bitmap bmp) {
            //用来存储转换后的 bitmap 数据。为什么要再加1000,这是为了应对当图片高度无法
            //整除24时的情况。比如bitmap 分辨率为 240 * 250,占用 7500 byte,5:5455,3,5447,4,5427
            //但是实际上要存储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;//换行
            }
            //   long a=System.currentTimeMillis();
            byte[] data1 = new byte[k];
            System.arraycopy(data, 0, data1, 0, k);
            // long b=System.currentTimeMillis();
            //  System.out.println("结束字节:"+k+"---"+data.length+"耗时:"+(b-a));
            return data1;
        }
    

    二维码,条形码打印

    二维码打印部分其实本身也有相应的指令进行打印,本菜鸟感觉有点难,有兴趣的人可以进行摸索下,这边是通过zxing生成相应的二维码,条形码转化成图片进行打印的。上面的接口工厂中,提供了中间无logo,有logo的二维码打印接口,以及各种类型的条形码打印。

    其他辅助指令

    换行
    new byte[]{Command.CR, Command.LF} , byte LF = 0x0A; byte CR = 0x0D;
    或者直接调用打印文本的接口打印个"/n"即可。
    打印走纸
    new byte[]{Command.LF},
    new byte[]{GS, 'V', 0x00};

    结束

    希望对大家有所帮助,详细代码在我的github上面
    https://github.com/GrassQing/CommonPrintProvider
    里面编写的指令基本上都是通用的。

    Tip

    1.有人问能不能打印可变的图片,据我所知是不行的。
    2.我问了公司的打印机的开发的人,他们是这样打印图片的,图片大小什么的都是没有多大的限制,基本宽度合理,长度没限制。基本每次只能打印图片的一部分,例如图片300k,打印机每次打印3k的大小,就是打印的时候提前把图片横向切割成100份依次打印,大概意思是这样的。我想其他厂家的打印机也应该差不多。
    3.另外指令也是重打印机部门那边扣出来的,基本不会有多大的问题,还是通用的。

    相关文章

      网友评论

      • 9ac0b73d7717:你好 请问可以连接多台打印机吗
      • 7e7398cb3655:你好,打印出来的东西都是乱码要怎么解决呀
      • 夏沐尧:请问重连这部分您是怎么做的?
        夏沐尧:@cgrass 没事没事,这里搞完了
        cgrass:@尧沐 异步,连接,若异常 ,重连几次,再异常提示其他操作。。基本重连都是这样弄的
      • 陆陆陆陆_9d5f:老哥我打印图片时候,图片分成三分左边右边各有一条空白的,事为啥呢
        cgrass:@陆陆陆陆_9d5f ......没见过
      • 黑眸之瞳:我文字后面接着打印图片 图片就就被分成了2部分一部分在文字后面 一部分在左边,这个怎么解决呢
        cgrass:@黑眸之瞳 这个得看打印机
        黑眸之瞳:@cgrass 还有个问题 我设置行距 但是不生效 不知道为什么
        cgrass:@黑眸之瞳 换行打印
      • 1fedf803175e:图片打印的宽高为240*240,但是打印出来的宽高比例不一样,高度会变高,这又是啥情况??
      • 1fedf803175e:图片打印到一半就切纸了,这时什么情况呢
        cgrass:··········· 你这样叫我怎么分析。。下面那个问题也是一样的
      • yqyzxd:可以直接用usb连接然后打印吗
        cgrass:理论上是 可以的,就是 usb连接的这部分要你自己 写了,指令什么都是通用的
      • 实心棒棒糖:楼主你好,请问一下如何监听打印是否成功,比方说没纸或者中间打印机故障了,如何判断是否已经打印成功了?
        cgrass:@MyAngelZt 有个比较土的方法,就是先不管打印是否有没有纸张,或者打印机挂了,先调用打印的接口进行打印,打印方法结束后进行检测打印机状态,然后做相应的提示。
      • 826c36c7483b:博主,你好,是否可以直接打印pdf文档?
        cgrass:@Monty_吴 没有这个功能
      • be757fadea9d:PO主您好 测试DEMO的时候 打印条码报错 ,打印图片则是打印一半就切纸了然后接着继续打印 请问是哪里的问题?
        cgrass:@issac9 刚刚看了下文档,没有发现有两段对齐的。两段对齐的话字体不多的可能导致 文字间隔 被拉伸,你不会是想弄居中吧???如果确定是要拉伸,在没有指令的情况下,可以参数对字符串进行填充空格达到 2端对齐的效果。。。
        be757fadea9d:@cgrass 谢谢,已经解决了 另外再请问一下关于文字对其格式想要做到两端对齐应该怎么做?
        cgrass:@issac9 和打印机有关系,打印图片完后打印空格打印几行 然后再切纸 就应该不会出现切纸一半的问题,打印条码报错:可能是图片太大了,或者内容太长,就这2个情况了
      • 思雨瑞橙工业标识:您好刚好我司想开发一款热敏打印机感兴趣加我Q1499251730
      • 小孩程序员:博主,我的图片高度是随时改变的,要是高度过高的话就会闪退为啥???
        cgrass:@小孩程序员 额不好意思,老长时间没上来了,你这种情况还真没见过。我这边用的都是固定的高度
      • Samuel0827:大兄弟,用你demo试了下,打印出来的文本是乱码,gbk、utf-8编码格式都是乱码。
        cgrass:建议在上面,怎么没有直接@的功能呢
        cgrass:这个就不是打印功能的问题了,应该是编码格式的问题,我那边编译环境都是utf-8的 编码格式,打印的时候 会转化成gbk的 编码格式,可能是你这个打印机 不支持这个 格式,你可以下载下源码然后 修改打印文本的选项,把编码格式改下,试试
        cgrass:@11e1ee052f3c 文本打印的 时候是gbk的。还真没发现 有这方面的问题。
      • 虚通磨忍:大牛,左边是打印logo图片,右边是打印一维码 这种怎么处理
        cgrass:@刚刚好1016 首选确认下,是否是打印图片的方法有问题,找个小的图片,就几k 的那种,如果可以打印,那么看下你生成的一维码是不是有问题,例如图片太大,或者尺寸过大,部分打印机针对尺寸,图片太大是打不出来的。
        虚通磨忍:@cgrass 用zxing生成一维码图片bitmap再用图片打印方法 打印出来的是全黑的,没有一维码的样子
        cgrass:@刚刚好1016 有办法解决,正常是不能打印的,必须是logo先打印,接着打印一维码,现在你要做的事情是把logo和一维码图片先拼成一个bitmap,然后进行打印,这样就解决问题了
      • 何儒:大兄弟,用这种支持 wifi 的热敏打印机,是否就不会限制操作系统呢,比如我用 web 平台传递数据进行打印,是否可以行得通呢?
        cgrass:虽然web的确实没做过,但是我也只能给你这些意见
        cgrass:@何儒 不会限制操作系统,根据我的估测,你只要能做到 2个机器一个网段,然后能把打印指令发给打印机就可以了,指令都是通用的。
      • RaySu:大兄弟,你好叼:grin:
      • 造轮子: //初始化
        InitPrint(ESC_SYTLE.MODE_PRINT.WIFI_PRINT, "192.168.0.1","12345");

        初始化这个IP地址是哪里来的呢? 默认的给手机设置的吗?蓝牙热敏打印机只看到物理地址;谢谢
        cgrass:如果搞完开发的话有意愿的话,我可以把第一手开发资料和我之前写的补充进去,完善这个项目。。我是因为开发太久了怕扔上去坑了你们才没弄上去。
        cgrass:不懂的直接和我交流交流,刚刚旁边有个同事在搞蓝牙打印最近,有第一手资料:pensive:
        cgrass:其实 你 提的这个只是 我通过wifi连接打印的初始化动作,,,蓝牙和wifi链接打印的区别就是连接的方式 其他都差不多,你只要把第一步做了 剩下的我提供的接口就可以实现了,因为蓝牙开发的时间过早,加上手上已经没有机器了,所以我就没搞进去。。。
      • 造轮子:哥们,谢谢您, 刚好要学习蓝牙打印的知识,谢谢
      • 妙法莲花1234:厉害厉害
        cgrass:O(∩_∩)O~

      本文标题:android 热敏打印机统一接口

      本文链接:https://www.haomeiwen.com/subject/ainxnttx.html