微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

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

如何解决打印图像时热敏打印机停止

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

其中一台打印机不支持通过 GS ( k .. 49 发送 QR 码,因此我通过将 file.bmp 加载到 Bitmap kotlin 类中然后通过 GS v 0 作为图像发送来进行打印。>

我面临的问题是,当我打印 QR 图像时,另一台打印机停止在图像中间。

我必须重新启动打印机才能正常工作,否则会打印垃圾


文件具有以下特点:

  • 82x82 像素
  • 2.9x2.9 厘米的打印尺寸(必须为 3 厘米)
  • 每像素 24 位
  • 2 种颜色

它被加载到一个 kotlin Bitmap 中:

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 似乎对尺寸没有任何影响(可能用于屏幕渲染?)。 rawBmp 对象具有以下特征:

  • 82x82 像素
  • 总字节数:26896
  • 每行字节数:328
  • 每像素字节数:4

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

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

这将特性更改为

  • 264x264 像素
  • 总字节数 278784
  • 每行字节数 1056
  • 每像素字节数 4

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

然后我设置 GS v 0 标头:

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()),imageBytes,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
    }
}

最后的参数是:

  • 米:0
  • xL:33 个字节
  • xH:0 字节
  • yL:8 个点
  • yH:1 个点
  • k:8712
  • 数据:8720 字节 (8+k)

然后我将它发送到蓝牙插座的 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()

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

解决方法

结果证明问题不在打印机缓冲区、缺少 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()

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。