一、效果图
二、作用
用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、很少见过类似的条形码。