条形码打印--安卓

         最近美团出餐宝要求服务商支持在小票上显示订单一维码信息,时间很赶,抓紧行动。由于我们有多个项目与打印相关。用到的打印机有驱动打印机,网口打印机,蓝牙打印机。不用惊讶,驱动打印机是用于delphi开发的桌面项目。开发的时候,找资料花了很长时间,完全把一维码的生成规则弄明白后,才解决了驱动机打印小票的问题。用delphi的人并不多,我还是先写安卓连接网口打印机和蓝牙打印机打印二维码吧。

 此段代码为条形码转换方式

public class OneDimensionUtil {

    private static String chars = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
    private static int scale = 62;

    /**
     * 数字转62进制
     */
    private static String encode(long num) {
        Long newNum = num;
        StringBuilder sb = new StringBuilder();
        int remainder;
        while (newNum > scale - 1) {
            //对 scale 进行求余,然后将余数追加至 sb 中,由于是从末位开始追加的,因此最后需要反转字符串
            remainder = (int) (newNum % scale);
            sb.append(chars.charAt(remainder));
            //除以进制数,获取下一个末尾数
            newNum /= scale;
        }
        sb.append(chars.charAt(Integer.parseInt(String.valueOf(newNum))));
        return sb.toString();
    }

    /**
     * 添加平台标志M前缀
     */
    public static String encodeM(long num) {
        return "M" + encode(num);
    }
}

打印相关命令如下:

package com.yx.printerexec.bluetoothsdk;

/**
 * author : dawn
 * e-mail : 272398235@qq.com
 * date   : 2021/5/8  15:07
 * desc   : 打印命令
 */
public class CommandConstants {

    /**
     * 复位打印机
     */
    public static byte[] RESET = new byte[]{0x1b, 0x40};

    /**
     * 左对齐
     */
    public static byte[] ALIGN_LEFT = new byte[]{0x1b, 0x61, 0x00};

    /**
     * 中间对齐
     */
    public static byte[] ALIGN_CENTER = new byte[]{0x1b, 0x61, 0x01};

    /**
     * 右对齐
     */
    public static byte[] ALIGN_RIGHT = new byte[]{0x1b, 0x61, 0x02};

    /**
     * 选择加粗模式
     */
    public static byte[] BOLD = new byte[]{0x1b, 0x45, 0x01};

    /**
     * 取消加粗模式
     */
    public static byte[] BOLD_CANCEL = new byte[]{0x1b, 0x45, 0x00};

    /**
     * 宽高加倍
     */
    public static byte[] DOUBLE_HEIGHT_WIDTH = new byte[]{0x1d, 0x21, 0x11};

    /**
     * 宽加倍
     */
    public static byte[] DOUBLE_WIDTH = new byte[]{0x1d, 0x21, 0x10};

    /**
     * 高加倍
     */
    public static byte[] DOUBLE_HEIGHT = new byte[]{0x1d, 0x21, 0x01};

    /**
     * 字体不放大
     */
    public static byte[] NORMAL = new byte[]{0x1d, 0x21, 0x00};

    /**
     * 设置默认行间距
     */
    public static byte[] LINE_SPACING_DEFAULT = new byte[]{0x1b, 0x32};

    /**
     * 设置条形码高
     */
    public static byte[] BAR_CODE_H = new byte[]{0x1d, 0x68,0x6e};

    /**
     * 设置条形码宽
     */
    public static byte[] BAR_CODE_W = new byte[]{0x1d, 0x77, 0x3};

    /**
     * 换行
     */
    public static byte[] WRAP = new byte[]{0x0A};

    /**
     * 走纸(防止内容已打印,包含内容的纸张打印机未全部吐出来)
     */
    public static byte[] PAPER_FEED = new byte[]{0x1b, 0x4a, (byte) 0x96};

    /**
     * 切纸
     */
     public static byte[] PAPER_CUT = new byte[]{0x1d, 0x56, 0x00, 0x30};
}

 1)、android连接网口打印机

        如果是连接网口打印机的话,打印完一定要记得断开连接,否则会导致一直占用其他的程序没有办法正常连接。    

 2)、android连接蓝牙打印机

这个方法里有一个outputStream 有一个outputStream,如果能用蓝牙打印机连接打印,应该知道怎么来的吧。我就直接略过了。只要蓝牙设备连接成功,就会有一个 BluetoothSocket 。

这两种打印机只是连接方式不一样,发送编码的方式完全相同

java发送指令部分   CODE B

  /**
     * 设置打印格式
     *
     * @param command 格式指令
     */
    public void selectCommand(byte[] command) {
        try {
            outputStream.write(command);
            outputStream.flush();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
 private void printBarCode(String content) {
        selectCommand(CommandConstants.BAR_CODE_W);//设置条码的宽
        selectCommand(CommandConstants.BAR_CODE_H);//设置条码的高度
        byte[] headerBytes = new byte[]{29, 107, 73, 00, 123, 66};
        byte[] contentByteArray = createByteCode(content);
        headerBytes[3] = (byte) (contentByteArray.length + headerBytes.length - 4);
        byte[] bytes = new byte[headerBytes.length + contentByteArray.length];
        System.arraycopy(headerBytes, 0, bytes, 0, headerBytes.length);
        System.arraycopy(contentByteArray, 0, bytes, headerBytes.length, contentByteArray.length);
        selectCommand(bytes);
    }
  private byte[] createByteCode(String content) {
        byte[] arr = new byte[content.length()];
        for (int i = 0; i < content.length(); i++) {
            arr[i] = (byte) content.charAt(i);
        }
        return arr;
    }

 Kotlin发送指令部分:CODE C


    /**
     * 打印条形码
     *设置其他值参考ESC/POS指令手册
     *
     * @param content 条码内容
     * @param w 指定条码宽  默认:3
     * @param h 指定条码高  默认:162
     */
    fun printBarCode(content: String, w: Int = 3, h: Int = 162) {
        try {
            val width = byteArrayOf(0X1D, 0X77, w.toByte())
            val height = byteArrayOf(0X1D, 0X68, h.toByte())
            selectCommand(width)//设置条码的宽
            selectCommand(height)//设置条码的高度

            val formats =
                byteArrayOf(29, 107, 73, 0, 123, 66, 78, 111, 46, 123, 67)
            val contentByteArray = splitText(content)
            formats[3] = (contentByteArray.size + 7).toByte()
            val bytes = ByteArray(formats.size + contentByteArray.size)
            System.arraycopy(formats, 0, bytes, 0, formats.size)
            System.arraycopy(contentByteArray, 0, bytes, formats.size, contentByteArray.size)
            selectCommand(bytes)
        } catch (e: IOException) {
            e.printStackTrace()
        }
    }

 /**
     * 按照两位分割字符串
     */
    private fun splitText(content: String): ByteArray {
        val sb = StringBuffer(content)
        var count = 0
        for (i in content.indices) {
            val index = i + 1
            //如果下标是偶数数则加入特殊字符
            if (index % 2 == 0 && index != content.length) {
                sb.insert(index + count, "&")
                count++
            }
        }
        val split = sb.toString().split("&")
        val byteArray = ByteArray(split.size)
        for (i in split.indices) {
            byteArray[i] = split[i].toByte()
        }

        return byteArray
    }

=========================================================================

byte[] headerBytes = new byte[]{29, 107, 73, 00, 123, 66};

应该有人对这句代码有疑惑,待我解释一下。 这还要从我从官网下载下来的编程手册说起。写打印功能的同行,应该对《XP-80X中文编程手册》不陌生。里面关于打印条形码是这么说的。条码类型很多,我只选择了我所熟悉的CODE128

                          

Code128 A码可表示:大写英文字母、数字、控制字符组成的字符串,比如:ABC、ABC123。

Code128 B码可表示:大小写英文字母、数字、字符组成的字符串,比如:Abc123、A-123(B)。

Code128 C码可表示:仅可表示100个“两位”数字编码(00-99),比如:123456、00225869。

 

一般来说,如果条码内容是大写英文字母,用Code128 A码或B码都可以,如果是包含大小写字母就需要用Code128 B码,如果是纯数字的一般用C码。在这里有一点需要注意的是,如果是条码内容位数是“奇数”的纯数字,那么就需要把条码内容给拆分,前面偶数用Code128 C码,后面一位奇数用B码或者A码。比如条码:1234567

拆分后,12、34、56是Code128 C码:,而最后一位7就是B码或者A码。在实际应用中Code 128 A码、Code128 B码和Code128 C码是可以相互组合的。

数据位可以只使用CODE B 编码,也可以只使用CODE C编码,也可以混合编码。需要注意的是,转换编码前需要提前说一下,也就是在真实数据前,注明编码。

混合编码方式:如M15202145

 

 CODE B 编码方式:

  CODE C 编码方式:

 注明一下:以上三张图只是声明传值格式,数据位的内容是随机写的。大家对照着上面的例子看,希望能有所帮助。

      至于要验证从字符转换为编码后是否正确,自行参考https://blog.csdn.net/weixin_30654419/article/details/95916713

    

参考:

https://jingyan.baidu.com/article/b907e6270f790906e6891c14.html   

Code128一维条码中A码、B码、C码的区别

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
好的,这个问题涉及到两个方面,分别是生成条码图片和使用标签机打印,我会分别给出代码示例。 首先是生成条码图片的示例代码,我们可以使用 ZXing 这个开源库来实现: ```java import com.google.zxing.BarcodeFormat; import com.google.zxing.EncodeHintType; import com.google.zxing.WriterException; import com.google.zxing.common.BitMatrix; import com.google.zxing.qrcode.QRCodeWriter; import java.util.HashMap; import java.util.Map; import android.graphics.Bitmap; import android.graphics.Color; public class BarcodeUtils { public static Bitmap generateBarcode(String contents, int width, int height) throws WriterException { Map<EncodeHintType, Object> hints = new HashMap<>(); hints.put(EncodeHintType.CHARACTER_SET, "UTF-8"); BitMatrix matrix = new QRCodeWriter().encode(contents, BarcodeFormat.CODE_128, width, height, hints); Bitmap bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888); for (int x = 0; x < width; x++) { for (int y = 0; y < height; y++) { bitmap.setPixel(x, y, matrix.get(x, y) ? Color.BLACK : Color.WHITE); } } return bitmap; } } ``` 上述代码中,我们使用 `QRCodeWriter` 类来生成条码图片,其中 `BarcodeFormat.CODE_128` 表示生成的是 Code 128 类型的条码。生成的图片大小由 `width` 和 `height` 参数指定。 接下来是使用标签机打印的示例代码,我们可以使用 ZPL 语言来编写标签模板,然后通过网络发送指令给标签机来打印: ```java import java.io.IOException; import java.io.OutputStream; import java.net.Socket; public class LabelPrinter { private static final String LABEL_TEMPLATE = "^XA^FO50,50^BY3^B3N,N,200,Y^FD${barcode}^FS^XZ"; private String ipAddress; private int port; public LabelPrinter(String ipAddress, int port) { this.ipAddress = ipAddress; this.port = port; } public void printBarcode(String contents) throws IOException { String zpl = LABEL_TEMPLATE.replace("${barcode}", contents); Socket socket = new Socket(ipAddress, port); OutputStream out = socket.getOutputStream(); out.write(zpl.getBytes()); out.flush(); out.close(); socket.close(); } } ``` 上述代码中,我们定义了一个标签模板,其中 `${barcode}` 是一个占位符,表示条码内容将在打印时替换为真实的条码内容。在 `printBarcode` 方法中,我们将条码内容替换到标签模板中,然后通过网络发送 ZPL 指令给标签机来打印。 使用时,你需要将生成的条码图片转换为 Base64 编码的字符串,然后调用 `printBarcode` 方法进行打印: ```java String barcodeContents = "1234567890"; Bitmap barcodeBitmap = BarcodeUtils.generateBarcode(barcodeContents, 400, 200); ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); barcodeBitmap.compress(Bitmap.CompressFormat.PNG, 100, outputStream); String barcodeBase64 = Base64.encodeToString(outputStream.toByteArray(), Base64.DEFAULT); LabelPrinter printer = new LabelPrinter("192.168.0.100", 9100); printer.printBarcode(barcodeBase64); ``` 上述代码中,我们生成了一个宽度为 400、高度为 200 的 Code 128 条码图片,并将其转换为 Base64 编码的字符串。然后,我们创建了一个 `LabelPrinter` 对象,传入了标签机的 IP 地址和端口号,并调用 `printBarcode` 方法将条码打印出来。 希望这个示例能帮助到你!

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值