美文网首页
EscPos 小票打印机模板设计

EscPos 小票打印机模板设计

作者: 索易开发 | 来源:发表于2017-04-28 22:15 被阅读0次

    https://github.com/SubLuLu/thermal_printer

    小票打印机, 目前主要有这么几个宽度规格 58mm 70mm 80mm,常见的58mm和80mm为用得比较多, 对于模板的设计来说,其中的区别基本上只在于每行可以显示多少个字符。58mm的小票热敏纸,一行最大可以显示32个半角字符,而80mm的则可以显示48个半角字符。

    EscPos 为目前主流小票打印机都支持的一种打印机控制命令集, 而其很重要的一个特点是无需驱动支持。 有以下两种方式可以向一台打印机发送这种命令。

    1. USB连接的情况下,直接向 LPT1 这个设备写入命令(或者COM口)。在windows下,外接设备被映射到系统中,其实也有其自己的路径, 不过这个路径和一般的文件路径不一样罢了, 如果从Linux的/dev/sda0 => /mnt/sda0 这样来理解可能会好理解点。那么使用CreateFile(设备路径), 获取一个缓冲区地址,然后往这个缓冲区写入数据,数据就会被发送到设备,以实现通讯

    2. 网线连接。一般的小票打印机都可以插网线,同时开放了9100这个端口, 可以通过socket建立连接,向这个端口发送数据,也同样可以和设备建立通讯连接


    以上为一些基本,接下来分享如何设计模板。

    由于小票的适用范围, 其实可以归结为以下几点:

    1. 小票可以看作是一行一行的字符拼接成完整的小票, 按照布局上来说, 那么就像是一个只有一栏的表格, 只要决定了每一行是什么样子, 整体的样子就有了

    2. 由于小票一般都不是很宽,那么一个字符或者一个字符串在当前行的某个具体位置并不重要,只需要 居左 居中 居右 三种位置属性即可,即使有, 横向的布局也应该是横向的填充布局

    3. 小票不需要很多很花的样式

    。。。

    基于以上几点, 将小票分为三个部分

    头的部分,主要显示标题、打印时间、单号等信息
    体的部分,主要显示项目明细,从一个List里按顺序输出每行即可
    尾的部分,一些其他内容,可以是文本,可以是链接

    按照上面github的这个库里所说, 把内容类型分为 文本 条形码 二维码 和图片,黑白的情况下,图片并不是很有必要

    "header": [
            {
                "text": "{$shopname}",
                "size": 2,
                "bold": true,
                "format": 1,
                "line": 2,
                "underline": true,
                "type": 0
            },
        ]
    

    以一个json数组存储头的部分内容,不同的类型的内容拥有不同的属性,最关键的是占位符,{$shopname} 这样的字符 可以使用 \{\$(.+?)\} 这个正则来匹配, 匹配到之后,根据每个占位符的内容不同,替换成不同的实际数据,如果不使用占位符,也可以直接填入完整的数据。这个数组里的元素,会按照顺序一行一行地打印出来,即这个数组里每个json对象都代表着一行。

    "goods": [
            {
                "name": "商品名",
                "width": 24,
                "format": 0,
                "variable": "name"
            }
        ],
    

    这里的每一个对象, 表示的是明细部分的一列, 标识出了列名,列宽,列标题的位置,还有一个则是表示该列的数据存取的字段名,例如后面拿到了name的数据,那么去这个模板里查找,来指定其格式和位置

        "bill": [
            {
                "text": "实收现金",
                "size": 3,
                "bold": true,
                "format": 1,
                "line": 2,
                "underline": false,
                "type": 0
            },
            {
                "text": "{$cash}",
                "size": 3,
                "bold": true,
                "format": 1,
                "line": 2,
                "underline": false,
                "type": 0
            }
        ],
    

    这里的结构和header还有footer的是一样的,你当然也可以加入其他类型的内容,比如adv 广告什么的。

    模板的解析,对于java等语言来说很是简单,因为他们都有动态类型这样的东西。但是对于Delphi来说,TObject如果不在TJson.JsonToObject的时候指定其类型,那么反序列化是没用的。不过可以使用TJsonObject或者TJsonArray来替代,对于动态的json,就不能像其他语言那么方便地直接操作对象了,用TJsonObject的方法来替代即可。
    例如, goods的子对象里有一个type字段,根据这个字段,可以判断出当前这个对象的类型,有了具体的类型,

    if goods[i].GetValue<Integer>('type') =0 then
    begin
        thegoods := TJson.JsonToObject<TText>(goods[i].ToJson());
    end;
    
    

    这样就可以获得具体的实例了.

    最后,也是关键的一步就是打印了,当把整个模板转换为一行行的字符串之后,不能直接发送。首先是需要异步发送, 否则阻塞主线程必然不是个好实践,然后,每个字符串需要按顺序发送。

    那么需要一个有序的队列来处理整个发送。Delphi自带的TQueue是个好的选择,不过由于其存储的是指针,那么可以对其进行一层封装,例如把一个包含每一行字符串的 Record的地址Push入队列,这里需要注意,每次Push需要 New(TPrintObj), 否则最终队列中都是同样的内容了。

    另外还有几个队列可以选择

    http://blog.sina.com.cn/s/blog_722bc92e0101gngd.html
    这个队列据说很快

    DIOCP v5中有一个TSafeQueue,也比较看好

    还有一个

    http://blog.qdac.cc/?p=148
    无锁队列也可以进行尝试。

    当然了,一味追求效率没有必要,那一点点时间的提升,不如拿来保证整个服务的稳定

    相关文章

      网友评论

          本文标题:EscPos 小票打印机模板设计

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