打印图像时热敏打印机停止

thermal printer stalls when printing image

我有两台蓝牙热敏打印机和一台集成设备。

其中一台打印机不支持通过 GS ( k .. 49, so I'm printing by loading a file.bmp into a Bitmap kotlin class and then sending as image via GS v 0 的二维码。

我面临的问题是,当我打印 QR 图像时,另一台打印机停止运行 mid-image。

我必须重启打印机才能正常工作,否则会打印乱码。


源文件具有以下特点:

它像这样加载到 kotlin 位图中:

var bfo = BitmapFactory.Options()
bfo.outHeight = 20
bfo.outWidth = 20
bfo.inJustDecodeBounds = false

val fRawBmp = File(qrCodeRawFilePath)
val rawBmp = BitmapFactory.decodeFile(fRawBmp.absolutePath, bfo)

.outHeight.outWidth 似乎对尺寸没有任何影响(可能用于屏幕渲染?)。 rawBmpobject具有以下特点:

由于宽度太小,必须按比例缩放:

if(inBmp.width < 264) {
    val startTime = System.nanoTime()
    qrBmp = Bitmap.createScaledBitmap(inBmp, 264, 264, true)
    val endTime = System.nanoTime()
    val duration = endTime - startTime
    wasScaled = true
}

这会将特征更改为

因为宽度是 8 的倍数,所以不需要填充。

然后我设置 GS v 0 header:

val bytesPerLine = ceil((widthInPx.toFloat() / 8f).toDouble()).toInt()
val m  = 0 // 0-3
val xH = bytesPerLine / 256
val xL = bytesPerLine - xH * 256
val yH = heightInPx / 256
val yL = heightInPx - yH * 256
val imageBytes = ByteArray(8 + bytesPerLine * heightInPx)
System.arraycopy(byteArrayOf(0x1D, 0x76, 0x30, m.toByte(), xL.toByte(), xH.toByte(), yL.toByte(), yH.toByte()), 0, imageBytes, 0, 8)

每个像素必须有 1 位,否则图像会失真。我是这样实现的(改编自 ESCPOS-ThermalPrinter):

var i = 8
for (posY in 0 until heightInPx) {
    var jj = 0
    while (jj < widthInPx) {
        val stringBinary = StringBuilder()
        for (k in 0..7) {
            val posX = jj + k
            if (posX < widthInPx) {
                val color: Int = qrBmp.getPixel(posX, posY)
                val r = color shr 16 and 0xff
                val g = color shr 8 and 0xff
                val b = color and 0xff
                if (r > 160 && g > 160 && b > 160) {
                    stringBinary.append("0")
                } else {
                    stringBinary.append("1")
                }
            } else {
                stringBinary.append("0")
            }
        }
        imageBytes[i++] = stringBinary.toString().toInt(2).toByte()
        jj += 8
    }
}

最终参数为:

然后我将它发送到蓝牙插座的 OutputStream,打印机在图像上扼流圈。


我正在使用具有不同 Android 版本、ABI、蓝牙版本和架构的多台设备进行测试 - 偶尔 它会在一台或另一台设备上打印,必须它大多失败了。

如果使用来自网络的一些演示应用程序,打印机会打印图像,所以我认为我做错了什么。

也许图片对于缓冲区来说太大了?


编辑 1

在使用 text1 + image + text2 的简单测试中,如果我刷新流,它将打印 text1 和 image;但不会打印 text2,即:

bt.outStream!!.write(byteArrayOf(0x1B, 0x74, 0x02)) // ESC t codepage PC437 USA Standard Europe
bt.outStream?.write("text1\n".toByteArray(Charsets.ISO_8859_1))
br.outStream?.flush()

var bfo = BitmapFactory.Options()
bfo.inJustDecodeBounds = false
val fRawBmp = File(path2file)
val rawBmp = BitmapFactory.decodeFile(fRawBmp.absolutePath, bfo)
bt.outStream?.write(bmp2Bytes(rawBmp))
bt.outStream?.flush()

bt.outStream?.write("text2\n\n\n".toByteArray(Charsets.ISO_8859_1))
bt.outStream?.flush()
bt.outStream?.close()
bt.inStream?.close()
bt.socket?.close()

QR 代码可读,但我仍必须重新启动打印机。所以我一定是溢出了一些东西...

原来问题不在打印机缓冲区,缺少 ESC/POS 命令或数据大小。

关闭蓝牙套接字之前必须等待,否则可能有未发送的数据。

所以,

Thread.sleep(400) // 200ms is enough for _most_ devices I tested
bt.outStream?.write("text2\n\n\n".toByteArray(Charsets.ISO_8859_1))
bt.outStream?.flush()
bt.outStream?.close()
bt.inStream?.close()
bt.socket?.close()