印表機模組
調用流程
使用 APOLLO 中內置的打印機打印收據或報告很簡單。
設置
創建一個實例,並通過 getControllerInstance()
and connectController()
連接到終端。
如果發生任何錯誤,應通過 onError
通知應用程序。
abstract class ApolloPrinter(private val context: Context) : PrinterDelegate {
private var printerController: PrinterController? = null
private val printerFixedWidth = 384
private lateinit var printData: ByteArray
fun connect(): Boolean {
try {
if (printerController == null) {
// get instance
printerController = getControllerInstance(context, this)
// enable debug log display in console
SPDeviceController.enableDebugLog(true)
}
// establish the communication channel with terminal
printerController?.connectController()
} catch (ex: Exception) {
return false
}
return true
}
fun disconnect() {
printerController?.disconnectController()
printerController?.releaseControllerInstance()
}
override fun onError(errorType: ControllerError.Error?, message: String?) {
// handle error here
}
}
打印流程
準備打印數據
APOLLO 熱打印機有 384 點/行。在發送到打印機之前,應用程序應將收據或報告轉換為 byte array 字節數組。
一種簡單的方法是首先使用 HTML 創建收據或報告並將其轉換為 bitmap 位圖。在應用程序的 build.gradle
,添加 html2bitMap。
dependencies {
//HTML to bitmap library
implementation 'com.izettle:html2bitmap:1.6'
}
在 ApolloPrinter
类中,有一个将位图转换为 ByteArray 的示例。
/**
* Input bitmap can be any size but preferred use APOLLO printer width or scaling is needed
*/
private fun bitmapTo1bppByteArray(bitmap: Bitmap): ByteArray {
val bFilter = true
val bmpResult: Bitmap
var width = bitmap.width
var height = bitmap.height
val widthNew = printerFixedWidth
val dataLen = ceil((width * height).toDouble() / 8).toInt()
val paddedData = ByteArray(dataLen)
/* First do a scale to make sure width match apollo criteria */
if (widthNew != bitmap.width) {
val scaleWidthFactor = widthNew.toDouble() / width
val dstHeight = (height * scaleWidthFactor).toInt()
bmpResult = Bitmap.createScaledBitmap(bitmap, widthNew, dstHeight, bFilter)
} else {
bmpResult = bitmap
}
//Change to B&W and RGB565
val convertedBitmap = Bitmap.createBitmap(bmpResult.width, bmpResult.height, Bitmap.Config.RGB_565)
val canvas = Canvas(convertedBitmap)
val ma = ColorMatrix()
ma.setSaturation(0f)
val paint = Paint()
paint.colorFilter = ColorMatrixColorFilter(ma)
canvas.drawBitmap(bitmap, 0f, 0f, paint)
width = convertedBitmap.width
height = convertedBitmap.height
val bb: ByteBuffer = ByteBuffer.allocate(convertedBitmap.byteCount)
convertedBitmap.copyPixelsToBuffer(bb)
val byteStream = ByteArrayInputStream(bb.array())
var bitPosition = 0
var bytePosition = 0
for (y in 0 until height) {
for (x in 0 until width) {
//Read 2 bytes from byte stream, beware of endian
val rgb565 = byteStream.read() or (byteStream.read() shl 8)
//Here for simplicity just use Red value (5bits) and threshold set to 16 which assume the input bitmap already in Grey scale
val red = (rgb565 shr 11)
//get binary value
var value: Byte
value = if (red <= 16) {
0x01.toByte()
} else {
0x00.toByte()
}
paddedData[bytePosition] = paddedData[bytePosition] or (value.toInt() shl bitPosition).toByte()
bitPosition++
if (bitPosition == 8) {
bitPosition = 0
bytePosition++
}
}
}
return paddedData
}
您可以通過 bitmapTo1bppByteArray
將位圖轉換為 byteArray。
// data that feed to the printer later
private lateinit var printData: ByteArray
// pass your html string
fun preparePrintData(html: String) {
val bitmap = Html2Bitmap.Builder()
.setContext(context)
.setBitmapWidth(printerFixedWidth) // 384
.setContent(WebViewContent.html(html))
.build().bitmap
printData = bitmapTo1bppByteArray(bitmap)
}
發送打印數據
應用程序應在 getControllerInstance()
和 connectController()
之後接收 onPrintDataRequested
。應用程序應通過 sendPrinterData
將字節數組格式的 printData
傳遞給打印機。
override fun onPrintDataRequested() {
printerController?.sendPrinterData(printData)
}
打印狀態
應用程序應接收 onPrinterStatus
和 onPrinterCompleted
以獲取打印機狀態。
override fun onPrinterStatus(p0: PrintStatus?) {
when (p0) {
PrintStatus.OVERHEAT -> {
// printer overheat, please wait
}
PrintStatus.NO_PAPER_OR_COVER_OPENED -> {
// no paper or the cover is opened, please re-fill the paper roll and close the cover properly
}
PrintStatus.PRINTER_LOWBATTERY -> {
// battery is low, please charge the APOLLO
}
PrintStatus.SUCCESS -> {
// print success
}
else -> {
}
}
}
override fun onPrinterCompleted() {
// do something
}