自定义Java生成UPC-A条形码的工具类

一、效果图

   

 

 

二、作用

      用Java代码生成12位的UPC–A条形码。

      生成的图片保存在磁盘文件中。

 

 

三、主要代码

package org.code.util;

import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;

/**
 * UPC-A编码方案:
 *   能表示12位数字;
 *
 * @version 1.0.0
 * <p>
 * date: 2025/5/5
 **/
public class UPCUtil {

    /**
     *  条形码宽度的像素单位
     */
    private final static int unit = 2;

    /**
     *  起始X坐标
     */
    private final static int start_x = 5;

    /**
     * 起始Y坐标
     */
    private final static int start_y = 5;

    /**
     * 左边的数据
     */
    private static String leftData = "";

    /**
     * 右边的数据
     */
    private static String rightData = "";

    /**
     * 1位系统码
     */
    private static String scode = "";

    private static String sysCode = "";

    /**
     * 起始码
     */
    private final static String startCode = "101";

    /**
     * 中间码
     */
    private final static String midCode = "01010";

    /**
     * 终止码
     */
    private final static String endCode = "101";

    /**
     * 检查码
     */
    private static String checkCode = "";

    /**
     * 偏移量
     */
    private static int offset = 0;

    private static void init(String data){
        offset = 0;
        leftData = data.substring(1, 6);
        rightData = data.substring(6);
        checkCode = getCheckCode(data);
        scode = String.valueOf(data.charAt(0));
        sysCode = mapValue(data.charAt(0) - 48, true);
    }

    /**
     * UPC分为数字码、起始码、中间码、终止码;
     *
     *    0是空白、1是线条;
     *    0就是偏移一个单位;
     *    1就是代表画一个单位的宽度;
     *    左右各自有9位空白码
     * @param data 条形码的数据(总11位,有一位是校验码)
     * @param width 宽度值(单位像素)
     * @param height 高度值(单位像素)
     * @param storePath 保存路径
     */
    public static void generate(String data, int width, int height, String storePath){
        // 初始化
        init(data);

        // 图形格式为整型RGB类型;
        BufferedImage bufferedImage = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
        Graphics graphics = bufferedImage.getGraphics();

        graphics.setColor(Color.WHITE);
        graphics.fillRect(0, 0, width, height);

        int barHeight = (int)(height * 0.7);

        // 画9个空白码
        drawBar(graphics, "000000000", barHeight);

        // 画起始模组
        drawBar(graphics, startCode, barHeight + 10);

        // 画系统码
        drawBar(graphics, sysCode, barHeight);

        // 左边5位数据码
        // 1位数据7个模组
        String leftDataCode = translate(leftData, true);
        drawBar(graphics, leftDataCode, barHeight);

        // 画中间码
        drawBar(graphics, midCode, barHeight);

        // 右边5位数据码
        String rightDataCode = translate(rightData, false);

        // 画右边数据码
        drawBar(graphics, rightDataCode, barHeight);

        // 画校验码
        drawBar(graphics, mapValue(Integer.parseInt(checkCode), false), barHeight + 10);

        // 画终止码
        drawBar(graphics, endCode, barHeight);

        // 画9个空白码
        drawBar(graphics, "000000000", barHeight);

        drawDigit(graphics, barHeight + 12);

        try {
            ImageIO.write(bufferedImage, "jpg", new File(storePath));
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    /**
     * 绘制一个条形模块
     * @param graphics
     * @param height
     */
    private static void drawBar(Graphics graphics, String code, int height){
        char[] array = code.toCharArray();
        for (int k = 0; k < array.length; k++) {
            if (array[k] == '1'){
                graphics.setColor(Color.BLACK);
                graphics.fillRect(start_x + offset, start_y, unit, height);
            } else if (array[k] == '0'){
                // 增加偏移量
                graphics.setColor(Color.WHITE);
                graphics.fillRect(start_x + offset, start_y, unit, height);
            }

            // 增加偏移量
            offset = offset + unit;
        }
    }

    /**
     * 画可见的数字
     */
    private static void drawDigit(Graphics graphics, int height){
        graphics.setColor(Color.BLACK);

        Font font = graphics.getFont();
        graphics.setFont(new Font(font.getFontName(), Font.BOLD, 14));

        // 1、画系统码
        graphics.drawString(scode, start_x + (3 * unit), start_y + height);

        // 2、画左边数据
        graphics.drawString(addSpace(leftData), start_x + (9 + 3 + 4 + 4) * unit , start_y + height);

        // 3、画右边数据
        graphics.drawString(addSpace(rightData), start_x + (9 + 3 + 7 + 2 + 5 + 5 * 7) * unit , start_y + height);

        // 4、画校验码
        graphics.drawString(checkCode, start_x + (9 + 3 + 7 + 2 + 5 + 5 * 7 * 2 + 5) * unit , start_y + height);
    }

    private static String addSpace(String str){
        StringBuffer buffer = new StringBuffer();
        char[] charArray = str.toCharArray();
        for (int k = 0; k < charArray.length; k++){
            buffer.append(charArray[k] + " ");
        }
        return buffer.toString();
    }

    private static String translate(String rawData, boolean isLeft){
        StringBuffer buffer = new StringBuffer();
        char[] array = rawData.toCharArray();
        for (int k = 0; k < array.length; k++){
            int digit = array[k] - 48;
            buffer.append(mapValue(digit, isLeft));
        }
        return buffer.toString();
    }

    /**
     * 返回二进制码
     * @param num 单位数字
     * @param isLeft 是否为左边
     * @return
     */
    private static String mapValue(int num, boolean isLeft){

        String code = "";

        switch (num){
            case 0: code = (isLeft) ? "0001101" : "1110010"; break;
            case 1: code = (isLeft) ? "0011001" : "1100110"; break;
            case 2: code = (isLeft) ? "0011011" : "1101100"; break;
            case 3: code = (isLeft) ? "0111101" : "1000010"; break;
            case 4: code = (isLeft) ? "0100011" : "1011100"; break;
            case 5: code = (isLeft) ? "0110001" : "1001110"; break;
            case 6: code = (isLeft) ? "0101111" : "1010000"; break;
            case 7: code = (isLeft) ? "0111011" : "1000100"; break;
            case 8: code = (isLeft) ? "0110111" : "1001000"; break;
            case 9: code = (isLeft) ? "0001011" : "1110100"; break;
        }
        return code;
    }


    /**
     * 求校验码
     *   公式:  CC = (N1+N3+N5+N7+N9+N11) * 3 + (N2+N4+N6+N8+N10)
     *   取个位:
     *     C=10-CC(如果C值为10,则取0)。
     * @param str 数据字符
     * @return
     */
    private static String getCheckCode(String str) {
        char[] array = str.toCharArray();

        int oddTotal = 0;
        int evenTotal = 0;
        for (int i = 0; i < array.length; i++) {
            if ((i + 1) % 2 == 1){
                oddTotal = oddTotal + (array[i] - 48);
            } else if ((i + 1) % 2 == 0) {
                evenTotal = evenTotal + (array[i] - 48);
            }
        }

        int CC = oddTotal  + evenTotal * 3;

        // 获取个位
        CC = CC % 10;

        int result = 10 - CC;
        if (result == 10) {
            result = 0;
        }
        return String.valueOf(result);
    }
}

 

 

四、测试案例

public class UPCTest {

    public static void main(String[] args) {
        // 编码是"92116855010"
        // 长度231,高度87,保存路径"D:/upc-a.jpg"

        UPCUtil.generate("92116855010", 231, 87, "D:/upc-a.jpg");

    }
}

 

 

五、说明

  1、本人没有验证过是否正确生成。

  2、很少见过类似的条形码。

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值