You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Kotlin中实现热敏打印机图片打印?附现有文本打印代码

Kotlin 热敏打印机图片打印实现

核心逻辑

热敏打印机遵循ESC/POS指令规范,打印图片需要将图片转换为黑白二值点阵数据,再通过专用指令发送给打印机。核心步骤:

  1. 缩放图片至打印机最大打印宽度(常见为384像素,可按需调整)
  2. 将彩色/灰度图转为黑白二值图
  3. 生成符合ESC/POS标准的图片打印指令字节流
  4. 通过蓝牙输出流发送数据

新增图片打印相关函数

将以下代码整合到你的打印类中:

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.17 21:05:50