如何在Kotlin中实现热敏打印机图片打印?附现有文本打印代码
Kotlin 热敏打印机图片打印实现
核心逻辑
热敏打印机遵循ESC/POS指令规范,打印图片需要将图片转换为黑白二值点阵数据,再通过专用指令发送给打印机。核心步骤:
- 缩放图片至打印机最大打印宽度(常见为384像素,可按需调整)
- 将彩色/灰度图转为黑白二值图
- 生成符合ESC/POS标准的图片打印指令字节流
- 通过蓝牙输出流发送数据
新增图片打印相关函数
将以下代码整合到你的打印类中:
import android.graphics.Bitmap import android.graphics.Canvas import android.graphics.ColorMatrix import android.graphics.ColorMatrixColorFilter import android.graphics.Paint import java.io.ByteArrayOutputStream import java.io.IOException // 打印图片入口函数 private fun printImage(bitmap: Bitmap) { val scope = CoroutineScope(Dispatchers.IO) scope.launch { try { val mmOutStream = mBluetoothSocket.outputStream // 设置图片居中对齐(可选,可替换为左/右对齐) mmOutStream.write(Formatter.centerAlign()) // 转换图片为ESC/POS格式字节流 val imageBytes = convertBitmapToEscPosData(bitmap) // 发送图片数据 mmOutStream.write(imageBytes) // 打印换行,分隔图片与后续文本 mmOutStream.write("\n".toByteArray()) } catch (e: IOException) { Log.e("PrintActivity", "图片打印失败", e) } } } // 将Bitmap转换为ESC/POS打印所需的字节流 private fun convertBitmapToEscPosData(bitmap: Bitmap): ByteArray { // 打印机宽度(根据你的设备调整,常见384/576像素) val printerMaxWidth = 384 // 缩放图片到打印机宽度,保持比例 val scaledBitmap = resizeBitmapToPrinterWidth(bitmap, printerMaxWidth) // 转为黑白二值图 val binarizedBitmap = convertToBlackWhite(scaledBitmap) val width = binarizedBitmap.width val height = binarizedBitmap.height // 每行占用字节数(1字节对应8个像素,向上取整) val bytesPerLine = (width + 7) / 8 val output = ByteArrayOutputStream() try { // ESC/POS 图片打印指令:GS v 0 output.write(byteArrayOf(0x1D, 0x76, 0x30, 0x00)) // 写入图片宽度(低字节、高字节) output.write((bytesPerLine % 256).toByte()) output.write((bytesPerLine / 256).toByte()) // 写入图片高度(低字节、高字节) output.write((height % 256).toByte()) output.write((height / 256).toByte()) // 逐行生成点阵数据 for (y in 0 until height) { for (x in 0 until bytesPerLine) { var byte = 0 for (bit in 0 until 8) { val pixelX = x * 8 + bit if (pixelX < width) { val pixel = binarizedBitmap.getPixel(pixelX, y) // 黑色像素标记为1(热敏打印机打印该位置),白色为0 if (pixel == 0xFF000000.toInt()) { byte = byte or (0x80 shr bit) } } } output.write(byte.toByte()) } } } catch (e: IOException) { Log.e("PrintActivity", "图片字节转换失败", e) } return output.toByteArray() } // 缩放图片至打印机宽度 private fun resizeBitmapToPrinterWidth(bitmap: Bitmap, targetWidth: Int): Bitmap { val scale = targetWidth.toFloat() / bitmap.width val targetHeight = (bitmap.height * scale).toInt() return Bitmap.createScaledBitmap(bitmap, targetWidth, targetHeight, true) } // 将图片转为黑白二值图 private fun convertToBlackWhite(bitmap: Bitmap): Bitmap { val binarizedBitmap = Bitmap.createBitmap(bitmap.width, bitmap.height, Bitmap.Config.ARGB_8888) val canvas = Canvas(binarizedBitmap) val paint = Paint() // 先转为灰度图 val grayMatrix = ColorMatrix().apply { setSaturation(0f) } paint.colorFilter = ColorMatrixColorFilter(grayMatrix) canvas.drawBitmap(bitmap, 0f, 0f, paint) // 二值化处理(阈值127,可根据图片清晰度调整) val pixels = IntArray(bitmap.width * bitmap.height) binarizedBitmap.getPixels(pixels, 0, bitmap.width, 0, 0, bitmap.width, bitmap.height) pixels.forEachIndexed { index, pixel -> val grayValue = pixel and 0xFF pixels[index] = if (grayValue < 127) 0xFF000000.toInt() else 0xFFFFFFFF.toInt() } binarizedBitmap.setPixels(pixels, 0, bitmap.width, 0, 0, bitmap.width, bitmap.height) return binarizedBitmap }
调用示例
在你的p1函数中,插入图片打印逻辑(比如在打印店名之前):
// 从资源加载图片(也可从文件/网络获取Bitmap) val storeLogo = BitmapFactory.decodeResource(resources, R.drawable.store_logo) printImage(storeLogo)
注意事项
printerMaxWidth需匹配你的打印机型号,常见值为384(80mm纸宽)或203(58mm纸宽)- 二值化阈值(127)可根据图片明暗调整,让打印效果更清晰
- 确保Bitmap对象已正确加载,避免空指针异常
内容的提问来源于stack exchange,提问作者love To Code
相关产品推荐
相关产品推荐

