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

如何用Groovy通过ESC/POS指令在Star MC-Print3打印机打印图片?

问题:Groovy脚本实现Star MC-Print3热敏打印机的ESC/POS图片打印

我正在编写Groovy脚本,使用Star MC-Print3热敏打印机和ESC/POS指令打印票据。目前已成功实现文本对齐、文本打印、切纸等基础打印功能,但在使用ESC/POS指令打印图片时遇到困难。

我需要在票据上打印图片(接收的是位图的Base64字符串),但不清楚如何向打印机发送图像数据。我知道ESC/POS支持位图打印,但不确定将图像转换为所需格式并正确发送到打印机的具体步骤。

以下是我当前未包含图片打印功能的脚本:

def printTicket(String ticketNumber) {
    println 'Printer'

    // Replace with your printer's IP address and port
    def PRINTER_IP = '192.168.1.3'
    def PRINTER_PORT = 9100

    try {
        // Create a socket connection to the printer
        Socket client = new Socket(PRINTER_IP, PRINTER_PORT)
        println 'Connected to printer'

        OutputStream out = client.getOutputStream()

        // Example ESC/POS commands for a basic ticket
        byte[] initPrinter = [0x1B, 0x40] // Initialize printer
        byte[] centerAlign = [0x1B, 0x1D, 0x61, 0x01] // Center alignment
        byte[] text = 'Hello, Star Printer!\n'.getBytes('UTF-8') // Ticket text
        byte[] ticketText = ticketNumber.getBytes('UTF-8') // Ticket number
        byte[] lineFeed = [0x0A] // Line feed
        byte[] cutPaper = [0x1B, 0x64, 0x03] // Cut paper

        // Send commands to printer
        out.write(initPrinter)  // Initialize printer
        out.write(centerAlign)  // Set alignment to center
        out.write(text)         // Print text
        out.write(lineFeed)     // Add line feed
        out.write(ticketText)   // Print ticket text
        out.write(lineFeed)     // Add another line feed
        out.write(cutPaper)     // Cut paper

        // Close the connection
        out.close()
        client.close()
        println 'Connection to printer closed'

    } catch (Exception e) {
        println "Printer connection error: ${e.message}"
    }
}

问题说明

我在打印图片时遇到困难。据了解ESC/POS支持位图打印,但我不知道如何:

  1. 将图像(如PNG/JPG或位图的Base64字符串)转换为打印机可识别的合适字节数组。
  2. 使用ESC/POS指令将该图像数据发送到打印机。

已尝试的操作

我知道需要将图像转换为单色(1位每像素)的位图格式,也查到了用于打印位图的GS v 0指令,但不确定如何构造图像数据或处理不同的图像格式。

所需帮助

  • 图像转换:如何将图像转换为ESC/POS所需的正确字节数组格式?是否需要先转换为单色?
  • ESC/POS指令:需要使用哪些指令将图像数据发送到打印机?
  • Groovy/Java实现:希望获得Groovy/Java语言的图片打印示例或代码片段。

解答

一、图像转换:必须转为单色位图

ESC/POS打印机仅支持1位单色位图(黑/白,无灰度),转换步骤如下:

  1. 解码Base64:将Base64字符串转为字节数组,再生成BufferedImage对象。
  2. 调整尺寸:根据打印机最大打印宽度缩放图像(Star MC-Print3通常支持最大576点宽度,对应80mm纸)。
  3. 转为单色:将图像转为1位灰度图,通过亮度阈值判断(比如亮度低于128的像素设为黑色,否则白色)。
  4. 字节打包:把单色图像的像素按字节打包,每8个像素组成1个字节(从左到右,高位对应左侧像素)。

二、ESC/POS图像打印指令:GS v 0

使用GS v 0指令(十六进制:0x1D 0x76 0x30),指令格式为:

GS v 0 <m> <xL> <xH> <yL> <yH> <图像数据>

各参数说明:

  • m:打印模式,固定为0x00(正常打印)
  • xL/xH:图像宽度(单位:点)的低/高字节,总宽度 = xL + xH*256
  • yL/yH:图像高度(单位:点)的低/高字节,总高度 = yL + yH*256
  • 图像数据:打包后的单色像素字节数组

三、Groovy实现完整示例

以下是集成图片打印的完整脚本,包含Base64图像解码、转换、打印的逻辑:

import java.awt.image.BufferedImage
import java.io.ByteArrayInputStream
import java.net.Socket
import javax.imageio.ImageIO

def printTicket(String ticketNumber, String base64Image) {
    println 'Printer'

    def PRINTER_IP = '192.168.1.3'
    def PRINTER_PORT = 9100

    try {
        Socket client = new Socket(PRINTER_IP, PRINTER_PORT)
        println 'Connected to printer'
        OutputStream out = client.getOutputStream()

        // 初始化打印机
        out.write([0x1B, 0x40] as byte[])
        // 设置居中对齐
        out.write([0x1B, 0x1D, 0x61, 0x01] as byte[])

        // 处理并打印图片
        byte[] imageBytes = Base64.getDecoder().decode(base64Image)
        BufferedImage originalImage = ImageIO.read(new ByteArrayInputStream(imageBytes))
        
        // 转换为ESC/POS兼容的字节数组
        byte[] printImageData = convertToEscPosImage(originalImage)
        // 发送图像打印指令
        sendEscPosImage(out, printImageData, originalImage.width, originalImage.height)

        // 打印文本和切纸
        out.write('Hello, Star Printer!\n'.getBytes('UTF-8'))
        out.write(ticketNumber.getBytes('UTF-8'))
        out.write([0x0A] as byte[])
        out.write([0x1B, 0x64, 0x03] as byte[])

        out.close()
        client.close()
        println 'Connection to printer closed'

    } catch (Exception e) {
        println "Printer connection error: ${e.message}"
        e.printStackTrace()
    }
}

// 将BufferedImage转为ESC/POS兼容的字节数组
def byte[] convertToEscPosImage(BufferedImage image) {
    int width = image.width
    int height = image.height
    // 计算每行需要的字节数(向上取整)
    int bytesPerLine = (width + 7) / 8
    byte[] imageData = new byte[bytesPerLine * height]

    for (int y = 0; y < height; y++) {
        int byteIndex = y * bytesPerLine
        for (int x = 0; x < width; x++) {
            // 获取像素亮度,转为黑白(阈值128)
            int rgb = image.getRGB(x, y)
            int brightness = (rgb >> 16 & 0xFF) * 0.299 + (rgb >> 8 & 0xFF) * 0.587 + (rgb & 0xFF) * 0.114
            boolean isBlack = brightness < 128

            // 打包到字节中:每8个像素一个字节,高位对应左侧像素
            int bitPosition = 7 - (x % 8)
            if (isBlack) {
                imageData[byteIndex + (x / 8)] |= (1 << bitPosition)
            }
        }
    }
    return imageData
}

// 发送ESC/POS图像打印指令
def void sendEscPosImage(OutputStream out, byte[] imageData, int width, int height) {
    byte m = 0x00
    byte xL = (byte) (width & 0xFF)
    byte xH = (byte) ((width >> 8) & 0xFF)
    byte yL = (byte) (height & 0xFF)
    byte yH = (byte) ((height >> 8) & 0xFF)

    // 构造指令头
    byte[] commandHeader = [0x1D, 0x76, 0x30, m, xL, xH, yL, yH] as byte[]
    out.write(commandHeader)
    // 发送图像数据
    out.write(imageData)
    // 换行
    out.write([0x0A] as byte[])
}

注意事项

  1. 若图像宽度不是8的倍数,转换时会自动补位(右侧补白),避免打印异常。
  2. Star MC-Print3支持的最大打印宽度为576点,若原图超过此宽度,需先缩放。
  3. 测试时建议先使用小尺寸图像,避免数据量过大导致打印卡顿。

内容的提问来源于stack exchange,提问作者Kamal Perera

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.15 06:15:12