1. 程式人生 > >熱敏印表機實現列印小票

熱敏印表機實現列印小票

最近公司需要用熱敏印表機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)

這裡寫圖片描述