热敏打印机实现打印小票

最近公司需要用热敏打印机POS88V实现打印小票。本文采用Kotlin 语言来实现

首先看看SP-POS88Ⅴ系列开发手册.pdf。你会发现这文档只有一堆的指令说明,而且是无序的。按道理应该先初始化设备,所以找到初始化打印机地方

ESC @
[名称] 初始化打印机
[格式] ASCII ESC @
Hex 1B 40
Decimal 27 64
[描述] 清除打印缓冲区数据,打印模式被设为上电时的默认值模式。
[注释] · DIP开关的设置不进行再次检测。
· 接收缓冲区内容保留。
· 宏定义保留。
· flash位图数据不擦除。
· flash用户数据不擦除。
· 维护计数器值不擦除。
· 由GS ( E 指定的设置值不擦除。

它支持3指令格式,分别是ASCII ,Hex ,Decimal 。 我喜欢用hex ,所以建个HexCommands 类维护各种指令

/**
 * 采用16进制定义指令
 */
enum class HexCommands(vararg parameters: Int) {
    
    
    /**
     * 初始化打印机
     */
    INIT_PRINTER(0x1B, 0x40),
    /**
     * 选择标准模式
     */
    STANDARD_MODE(0x1B, 0x53),
    /**
     * 进纸并且半切纸
     */
    FEED_AND_CUT(0x1D, 0x56, 65),
    /**
     * 设置绝对打印位置
     */
    PRINT_ABSOLUTE_LOCATION(0x1B, 0x24),
    /**
     * 选择/取消加粗模式
     */
    TEXT_BOLD(0x1B, 0x45),
    /**
     * 选择字符对齐模式
     */
    TEXT_ALIGNMENT(0x1B, 0x61);

    val hexValues = parameters
}

建立连接

如何建立连接呢?我这里采用网络方式,用socket 很方便实现

class PosPrinter {
    
    

    var encoding: String = "GBK"

    private lateinit var client: Socket
    private lateinit var writer: PrintWriter

    @Throws(IOException::class, UnsupportedEncodingException::class)
    fun connect(ip: String, port: Int = 9100, timeout: Long = 1, timeUnit: TimeUnit = TimeUnit.SECONDS) {
        client = Socket()
        client.connect(InetSocketAddress(ip, port), TimeUnit.MILLISECONDS.convert(timeout, timeUnit).toInt())
        writer = PrintWriter(BufferedWriter(OutputStreamWriter(client.getOutputStream(), encoding)))
    }

    @Throws(IOException::class)
    fun disconnect() {
        writer.close()
        client.close()
    }

    private fun write(hexCommands: HexCommands, vararg moreHexValues: Int) {
        hexCommands.hexValues.forEach {
            writer.write(it)
        }
        moreHexValues.forEach {
            writer.write(it)
        }
        writer.flush()
    }

    fun initPosPrinter(): PosPrinter {
        write(HexCommands.INIT_PRINTER)
        return this
    }

    fun selectStandardMode(): PosPrinter {
        write(HexCommands.STANDARD_MODE)
        return this
    }

    fun printText(text: String): PosPrinter {
        writer.write(text)
        writer.flush()
        return this
    }

    fun printLine(line: Int = 1): PosPrinter {
        for (i in 0 until line) {
            writer.write("\n")
            writer.flush()
        }
        return this
    }

    fun printTextLine(text: String, line: Int = 1): PosPrinter {
        printLine(line)
        printText(text)
        return this
    }

    fun innerPrint(function: PosPrinter.() -> PosPrinter): PosPrinter {
        function(this)
        return this
    }

    /**
     * 打印空白(size个汉字的位置)
     */
    fun printWordSpace(size: Int): PosPrinter {
        for (i in 0 until size) {
            writer.write("  ")
        }
        writer.flush()
        return this
    }

    /**
     * 选择字符对齐模式
     */
    fun setTextBold(isBold: Boolean = false): PosPrinter {
        write(HexCommands.TEXT_BOLD, if (isBold) 1 else 0)
        return this
    }

    /**
     * 选择字符对齐模式
     */
    fun setTextAlignment(@TextAlignment textAlignment: Long): PosPrinter {
        write(HexCommands.TEXT_ALIGNMENT, textAlignment.toInt())
        return this
    }

    /**
     * 设置绝对打印位置
     */
    fun setTextAbsoluteLocation(@IntRange(from = 0, to = 255) offsetX: Int,
                                @IntRange(from = 0, to = 255) offsetY: Int = 1): PosPrinter {
        write(HexCommands.PRINT_ABSOLUTE_LOCATION, offsetX, offsetY)
        return this
    }


    fun feedAndCut(length: Int = 100): PosPrinter {
        write(HexCommands.FEED_AND_CUT, length)
        return this
    }

    companion object {
    
    
        /**
         * Align to the start of the paragraph, e.g. ALIGN_LEFT.
         *
         * Use with [.setTextAlignment]
         */
        const val TEXT_ALIGNMENT_TEXT_START = 0L

        /**
         * Center the paragraph, e.g. ALIGN_CENTER.
         *
         * Use with [.setTextAlignment]
         */
        const val TEXT_ALIGNMENT_CENTER = 1L

        /**
         * Align to the end of the paragraph, e.g. ALIGN_RIGHT.
         *
         * Use with [.setTextAlignment]
         */
        const val TEXT_ALIGNMENT_TEXT_END = 2L

        @IntDef(TEXT_ALIGNMENT_TEXT_START, TEXT_ALIGNMENT_CENTER, TEXT_ALIGNMENT_TEXT_END)
        @Retention(AnnotationRetention.SOURCE)
        annotation class TextAlignment
    }
}

安卓设备上打印小票

    //订单菜品集合
    private var goodsBean: MutableList<GoodsBean>? = null


    private var posPrinter: PosPrinter? = null

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        doAsync {
            //初始化订单数据
            initData()

            posPrinter = PosPrinter()
            posPrinter!!.connect("192.168.2.150")
            posPrinter!!.initPosPrinter()
                    .selectStandardMode()
                    .setTextBold(true)
                    .setTextAlignment(PosPrinter.TEXT_ALIGNMENT_CENTER)
                    .printText("*** 天龙店铺 ***")
                    .printLine()
                    .setTextBold(false)
                    .setTextAlignment(PosPrinter.TEXT_ALIGNMENT_TEXT_START)
                    .printTextLine("订单编号:1005199")
                    .printTextLine("交易机台:test")
                    .printTextLine("交易时间:2016/2/19 12:34:53")
                    .printTextLine("支付方式:微信支付")
                    .printLine(2)
                    .printText("商品")
                    .setTextAbsoluteLocation(20)
                    .printText("单价")
                    .printWordSpace(3)
                    .printText("数量")
                    .printWordSpace(3)
                    .printText("小计")
                    .printTextLine("----------------------------------------------")
                    .innerPrint({
                        for (foods in goodsBean!!) {
                            printTextLine(foods.name)
                            setTextAbsoluteLocation(20)
                            printText(foods.price)
                            printWordSpace(3)
                            printText(foods.number)
                            printWordSpace(3)
                            printText(foods.sum)
                        }
                        this
                    })
                    .printTextLine("----------------------------------------------")
                    .printLine()
                    .printText("总计(人民币):")
                    .printText("80.00")
                    .printLine()
                    .feedAndCut(50)

        }


    }

    private fun initData() {
        goodsBean = ArrayList()
        (0..1).map { GoodsBean("测试商品" + it, "10.00", "2", "20.00") }
                .forEach { goodsBean!!.add(it) }
    }

    data class GoodsBean(val name: String, val price: String, val number: String, val sum: String)

这里写图片描述

猜你喜欢

转载自blog.csdn.net/CSDNno/article/details/79449195