斑马打印中文和特殊符号

国内的斑马打印机一般自带了宋体,打印中文是没有问题,但是发现不能打印类似这样的C₁₂H₁₆Cl₂N₂ 化学式下标。

还有看惯了手机和电脑上的黑体,宋体有点不习惯,本文也教你如何上传思源黑体(英语:Source Han Sans,Google公司则称Noto Sans CJK)是Adobe与Google所合作开发的开源字体家族,属于无衬线黑体。

查字体里的字符

在将字体下载到打印机之前,可以通过Windows的“字符映射表”工具,选中对应的字体,输入字符的Unicode编码

20240731130438

比如下标1的Unicode码是U+2081,如上图所示,该字体中没有对应的字符编码,离它最近的是U+20A9

再看另一个有该字符的字体

20240731130232

打印机安卓系统集成

打印机可以采用USB,蓝牙,网络连接到安卓系统。从官网下载打印机的安卓开发SDK,下面共享一段打印机发现的代码:

package com.zhaoxinsoft.lab.doamin.setting

import android.content.Context
import com.zebra.sdk.btleComm.BluetoothLeDiscoverer
import com.zebra.sdk.printer.discovery.BluetoothDiscoverer
import com.zebra.sdk.printer.discovery.DiscoveredPrinter
import com.zebra.sdk.printer.discovery.DiscoveryHandler
import com.zebra.sdk.printer.discovery.NetworkDiscoverer
import com.zebra.sdk.printer.discovery.UsbDiscoverer
import kotlinx.coroutines.suspendCancellableCoroutine
import kotlin.coroutines.resume

class ZebraPrinterDiscover(private val context: Context) {

  enum class PrinterType {
    USB, BLUETOOTH, NETWORK, BLUETOOTH_LE
  }

  /**
   * 按指定类型查找打印机,此函数应当在Dispatchers.IO中调用
   * @param type 打印机类型
   */
  suspend fun discover(type: PrinterType): Result<List<DiscoveredPrinter>> =
    suspendCancellableCoroutine { continuation ->
      val printers = mutableListOf<DiscoveredPrinter>()
      val handler = object : DiscoveryHandler {
        override fun foundPrinter(printer: DiscoveredPrinter) {
          printers.add(printer)
        }

        override fun discoveryFinished() {
          if (continuation.isCancelled) return
          continuation.resume(Result.success(printers))
        }

        override fun discoveryError(message: String) {
          if (continuation.isCancelled) return
          continuation.resume(Result.failure(Exception(message)))
        }
      }
      when (type) {
        PrinterType.USB -> UsbDiscoverer.findPrinters(context, handler)
        PrinterType.BLUETOOTH -> BluetoothDiscoverer.findPrinters(context, handler)
        PrinterType.NETWORK -> NetworkDiscoverer.findPrinters(handler)
        else -> BluetoothLeDiscoverer.findPrinters(context, handler)
      }

      continuation.invokeOnCancellation {
        continuation.resume(Result.failure(Exception("Cancelled")))
      }
    }
}

字体下载

字体准备

斑马打印机支持TTF字体,但是网上下载的很多TTF字体都是可变TTF(一个文件包含多种粗细的),例如这里下载的这个简体版的NotoSansSC[wght].ttf

安装fonttools工具可以提取其中一种需要的粗细

pip install fonttools

输入以下命令导出变体表

ttx -t fvar "NotoSansSC[wght].ttf"

得到NotoSansSC[wght].ttx文件,是一个XML文件,里面指明了字体文件里包含哪些粗细,数字越大越粗。这里我们选择400

fonttools varLib.instancer "NotoSansSC[wght].ttf" wght=400 -o "NOTOSC_400.ttf"

提取到可变字体的一种,这个文件就可以用来传给打印机了。

下载字体

这里所说的下载和斑马文档里面的关于字体Download其实说把字体下载到打印机里面去的意思。其实说上传可能好理解一些。

使用指令下载字体文件,这里以kotlin举例

// 上传 NOTOSC_400.ttf
val file = Helper.getFileFromAssets(context, "zebra/NOTOSC_400.ttf")
val zpl = "~DYE:NTSANSSC.TTF,B,T,10238812,,"
// 注意:字体文件名最好不要超过8个字,否则会出奇怪问题,后面数字是文件大小,再有两个逗号不能省
conn.sendAndWaitForResponse(
    zpl.toByteArray(), 0, 0, null
)
_printer?.sendFileContents(file.absolutePath) { writen, total ->
	Log.d(TAG, "NTSANSSC.TTF Uploading $writen/$total")
}

其实用Windows的打印机属性窗口也可以,先用“发送命令”,注意那串数字是字体文件的大小

20240731131858

再用“发送文件”,把选择文件传上去就行。

ZPL打印标签

话不多说了,直接看例子,下面是安卓开发里面kotlin的例子

val zpl = """
^XA
^MMT
^PW839
^LL655
^LS0
^CWR,E:NTSANSSC.TTF
^CWL,E:NTSANS_L.TTF
^SEE:GB18030.DAT^CI26
^FT1,100^ARN,73,74^FB838,1,0,C^^FD乙二胺盐^FS
^FPH,6^FT0,200^ALN,66,65^FB839,1,35,C^^FDC₁₂H₁₆Cl₂N₂^FS
^BY6,3,257^FT84,525^BCN,,N,N,,A
^FD40050010000003^FS
^FT0,620^ALN,56,56^FB838,1,30,C^FD40050010000003^FS
^PQ1,,,Y
^XZ
"""
_printer?.connection?.write(zpl.toByteArray(Charset.forName("GB18030")))

注意ZPL里面需要用^SEE:GB18030.DAT^CI26加载编码文件,然后指令发出的时候也要用GB18030进行编码。

下面是python的例子

# -*- coding: utf-8 -*-
import socket

s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect(('192.168.1.29', 9100))
zpl = '''
^XA
^MMT
^PW839
^LL655
^LS0
^CWR,E:NTSANSSC.TTF
^CWL,E:NTSANS_L.TTF
^SEE:GB18030.DAT^CI26
^FT1,100^ARN,73,74^FB838,1,0,C^FD乙二胺盐^FS
^FPH,6^FT0,200^ALN,66,65^FB839,1,35,C^FDC₁₂H₁₆Cl₂^FS
^BY6,3,257^FT84,525^BCN,,N,N,,A
^FD40050010000003^FS
^FT0,620^ALN,56,56^FB838,1,30,C^FD40050010000003^FS
^PQ1,,,Y
^XZ
'''
s.send(zpl.encode(encoding='gb18030'))
s.close()

最后附上打印效果

20240731133742

常用ZPL指令备忘录

  • ^XA^HWE:*.TTF^XZ 输出TTF字体文件列表,结果不打印在纸上
  • ^XA^IDE:MIC000.TTF^XZ 删除指定文件
  • ~JR 开机重置用于重置打印机的所有内部软件,执行开机自检 (POST),清除缓存和 DRAM,并重置通信参数和默认值。发出 ~JR 命令所实现的功能与手动开机重置实现 的功能相同。(遇到指令总也不听使唤的时候有奇效)