条形码二维码由于规则简单,读取效率,在目前人们生活中应用广泛。一般情况下,不必了解原理,就可以借助ZXING和BARCODE,ZBAR等各种开发库实现。在某些特殊场合或者特别要求的场合下,比如发明一种特殊的条形码,比如改进编码规则,比如对特别识别过程优化等情况。CODE128应用十分广泛,这里从CODE128的编码规则并从规则出发开发相应的二维码生成和识别程序来抛砖引玉。
CODE128简介
CODE128 码于 1981 年推出,是一种长度可变、连续性的字母数字条码。与其他一维条码比 较起来,相对较为复杂,支持的宇元也相对较多,又有不同的编码为式可供交互运用,因此其应 用弹性也较大。
CODE 128 特性
1、具有 A、 B、 C 三种不同的编码类型,可提供标准 ASC II中 128 个宇元的编码使用; 2、允许双向扫描;
3、可自行决定是否加上校验位;
4、条码长度可调,但包括开始位和结束位在内,不可超过 232 个字元;
5、同一个 CODE128 码可以由 A、 B、 C 三种不同编码规则互换,既可扩大字元选择的范围, 也可缩短编码的长度。
CODE 128 编码方式的编码范围
1、 CODE128A:标准数字、大写字母、控制符及特殊宇符;
2、 CODE128B:标准数字、大写宇母、小写字母及特殊字符;
3、 CODE128C/EAN128: [ 00]~[ 99]的数字对集合,共 100 个,既只能表示偶数位长 度的数字。
CODE 128 编码规则
开始位+[ FNC1(为 EAN128 码时附加)]+数据位+校验位+结束位
CODE128 校验位计算
(开始位对应 ID+每位数据在整个数据中的位置×每位数据对应的 ID 值) % 103
CODE 128 编码表如下,
横向依次对应索引ID, ABC三种编码字符,BANDCODE和二进制编码表,纵向对支持的字符,C码只支持数字,B码支持数字,字母和特殊字符,A码支持数字,字母,特殊字符和控制字符
A B C A B C
00 SP SP 00 11011001100
01 ! ! 01 11001101100
02 " " 02 11001100110
03 # # 03 10010011000
04 $ $ 04 10010001100
05 % % 05 10001001100
06 & & 06 10011001000
07 /' /' 07 10011000100
08 ( ( 08 10001100100
09 ) ) 09 11001001000
10 * * 10 11001000100
11 + + 11 11000100100
12 , , 12 10110011100
13 - - 13 10011011100
14 . . 14 10011001110
15 / / 15 10111001100
16 0 0 16 10011101100
17 1 1 17 10011100110
18 2 2 18 11001110010
19 3 3 19 11001011100
20 4 4 20 11001001110
21 5 5 21 11011100100
22 6 6 22 11001110100
23 7 7 23 11101101110
24 8 8 24 11101001100
25 9 9 25 11100101100
26 : : 26 11100100110
27 ; ; 27 11101100100
28 < < 28 11100110100
29 = = 29 11100110010
30 > > 30 11011011000
31 ? ? 31 11011000110
32 @ @ 32 11000110110
33 A A 33 10100011000
34 B B 34 10001011000
35 C C 35 10001000110
36 D D 36 10110001000
37 E E 37 10001101000
38 F F 38 10001100010
39 G G 39 11010001000
40 H H 40 11000101000
41 I I 41 11000100010
42 J J 42 10110111000
43 K K 43 10110001110
44 L L 44 10001101110
45 M M 45 10111011000
46 N N 46 10111000110
47 O O 47 10001110110
48 P P 48 11101110110
49 Q Q 49 11010001110
50 R R 50 11000101110
51 S S 51 11011101000
52 T T 52 11011100010
53 U U 53 11011101110
54 V V 54 11101011000
55 W W 55 11101000110
56 X X 56 11100010110
57 Y Y 57 11101101000
58 Z Z 58 11101100010
59 [ [ 59 11100011010
60 // // 60 11101111010
61 ] ] 61 11001000010
62 ^ ^ 62 11110001010
63 _ _ 63 10100110000
64 NUL ` 64 10100001100
65 SOH a 65 10010110000
66 STX b 66 10010000110
67 ETX c 67 10000101100
68 EOT d 68 10000100110
69 ENQ e 69 10110010000
70 ACK f 70 10110000100
71 BEL g 71 10011010000
72 BS h 72 10011000010
73 HT I 73 10000110100
74 LF j 74 10000110010
75 VT k 75 11000010010
76 FF l 76 11001010000
76 FF l 76 11001010000
77 CR m 77 11110111010
78 SO n 78 11000010100
79 SI o 79 10001111010
80 DLE p 80 10100111100
81 DC1 q 81 10010111100
82 DC2 r 82 10010011110
83 DC3 s 83 10111100100
84 DC4 t 84 10011110100
85 NAK u 85 10011110010
86 SYN v 86 11110100100
87 ETB w 87 11110010100
88 CAN x 88 11110010010
89 EM y 89 11011011110
90 SUB z 90 11011110110
91 ESC { 91 11110110110
92 FS | 92 10101111000
93 GS } 93 10100011110
94 RS ~ 94 10001011110
95 US DEL 95 10111101000
96 FNC3 FNC3 96 10111100010
97 FNC2 FNC2 97 11110101000
98 SHIFT SHIFT 98 11110100010
99 CodeC CodeC 99 10111011110
100 CodeB FNC4 CodeB 10111101110
101 FNC4 CodeA CodeA 11101011110
102 FNC1 FNC1 FNC1 11110101110
103 STARTA STARTA STARTA 11010000100
104 STARTB STARTB STARTB 11010010000
105 STARTC STARTC STARTC 11010011100
终止符 STOP STOP STOP 1100011101011
编程实现,创建一个二维数组表,把编码表存入,数组第0列A码,第1列B码,第2列C码,第3列bandcode,第4列对就二进制编码值,整体算法十分简单,把要编码的内容读入,按照下表转为二进制编码值,生成数据位,最后按照规则,开始位+[FNC1(为 EAN128 码时附加)]+数据位+校验位+结束位组合成完整二进制编码数据,最后调用平台GUI函数按照合成的完整二进制码,1对应白色竖线,0对应黑色竖线绘制出来,线高和线宽可以根据需要调整,下面给出完整的JAVA代码和android代码,java绘图使用AWT图形库。
public class TestCode128C {
String[][] code128 = { { " ", " ", "00", "212222", "11011001100" },
{ "!", "!", "01", "222122", "11001101100" },
{ "\"", "\"", "02", "222221", "11001100110" },
{ "#", "#", "03", "121223", "10010011000" },
{ "$", "$", "04", "121322", "10010001100" },
{ "%", "%", "05", "131222", "10001001100" },
{ "&", "&", "06", "122213", "10011001000" },
{ "'", "'", "07", "122312", "10011000100", },
{ "(", "(", "08", "132212", "10001100100" },
{ ")", ")", "09", "221213", "11001001000" },
{ "*", "*", "10", "221312", "11001000100" },
{ "+", "+", "11", "231212", "11000100100" },
{ ",", ",", "12", "112232", "10110011100" },
{ "-", "-", "13", "122132", "10011011100" },
{ ".", ".", "14", "122231", "10011001110" },
{ "/", "/", "15", "113222", "10111001100" },
{ "0", "0", "16", "123122", "10011101100" },
{ "1", "1", "17", "123221", "10011100110" },
{ "2", "2", "18", "223211", "11001110010", },
{ "3", "3", "19", "221132", "11001011100" },
{ "4", "4", "20", "221231", "11001001110", },
{ "5", "5", "21", "213212", "11011100100" },
{ "6", "6", "22", "223112", "11001110100" },
{ "7", "7", "23", "312131", "11101101110" },
{ "8", "8", "24", "311222", "11101001100" },
{ "9", "9", "25", "321122", "11100101100" },
{ ":", ":", "26", "321221", "11100100110" },
{ ";", ";", "27", "312212", "11101100100" },
{ "<", "<", "28", "322112", "11100110100" },
{ "=", "=", "29", "322211", "11100110010" },
{ ">", ">", "30", "212123", "11011011000" },
{ "?", "?", "31", "212321", "11011000110" },
{ "@", "@", "32", "232121", "11000110110" },
{ "A", "A", "33", "111323", "10100011000" },
{ "B", "B", "34", "131123", "10001011000" },
{ "C", "C", "35", "131321", "10001000110" },
{ "D", "D", "36", "112313", "10110001000" },
{ "E", "E", "37", "132113", "10001101000" },
{ "F", "F", "38", "132311", "10001100010" },
{ "G", "G", "39", "211313", "11010001000" },
{ "H", "H", "40", "231113", "11000101000" },
{ "I", "I", "41", "231311", "11000100010" },
{ "J", "J", "42", "112133", "10110111000" },
{ "K", "K", "43", "112331", "10110001110" },
{ "L", "L", "44", "132131", "10001101110" },
{ "M", "M", "45", "113123", "10111011000" },
{ "N", "N", "46", "113321", "10111000110" },
{ "O", "O", "47", "133121", "10001110110" },
{ "P", "P", "48", "313121", "11101110110" },
{ "Q", "Q", "49", "211331", "11010001110" },
{ "R", "R", "50", "231131", "11000101110" },
{ "S", "S", "51", "213113", "11011101000" },
{ "T", "T", "52", "213311", "11011100010" },
{ "U", "U", "53", "213131", "11011101110" },
{ "V", "V", "54", "311123", "11101011000" },
{ "W", "W", "55", "311321", "11101000110" },
{ "X", "X", "56", "331121", "11100010110" },
{ "Y", "Y", "57", "312113", "11101101000" },
{ "Z", "Z", "58", "312311", "11101100010" },
{ "[", "[", "59", "332111", "11100011010" },
{ "\\", "\\", "60", "314111", "11101111010" },
{ "]", "]", "61", "221411", "11001000010" },
{ "^", "^", "62", "431111", "11110001010" },
{ "_", "_", "63", "111224", "10100110000" },
{ "NUL", "`", "64", "111422", "10100001100" },
{ "SOH", "a", "65", "121124", "10010110000" },
{ "STX", "b", "66", "121421", "10010000110" },
{ "ETX", "c", "67", "141122", "10000101100" },
{ "EOT", "d", "68", "141221", "10000100110" },
{ "ENQ", "e", "69", "112214", "10110010000" },
{ "ACK", "f", "70", "112412", "10110000100" },
{ "BEL", "g", "71", "122114", "10011010000" },
{ "BS", "h", "72", "122411", "10011000010" },
{ "HT", "i", "73", "142112", "10000110100" },
{ "LF", "j", "74", "142211", "10000110010" },
{ "VT", "k", "75", "241211", "11000010010" },
{ "FF", "I", "76", "221114", "11001010000" },
{ "CR", "m", "77", "413111", "11110111010" },
{ "SO", "n", "78", "241112", "11000010100" },
{ "SI", "o", "79", "134111", "10001111010" },
{ "DLE", "p", "80", "111242", "10100111100" },
{ "DC1", "q", "81", "121142", "10010111100" },
{ "DC2", "r", "82", "121241", "10010011110" },
{ "DC3", "s", "83", "114212", "10111100100" },
{ "DC4", "t", "84", "124112", "10011110100" },
{ "NAK", "u", "85", "124211", "10011110010" },
{ "SYN", "v", "86", "411212", "11110100100" },
{ "ETB", "w", "87", "421112", "11110010100" },
{ "CAN", "x", "88", "421211", "11110010010" },
{ "EM", "y", "89", "212141", "11011011110" },
{ "SUB", "z", "90", "214121", "11011110110" },
{ "ESC", "{", "91", "412121", "11110110110" },
{ "FS", "|", "92", "111143", "10101111000" },
{ "GS", "},", "93", "111341", "10100011110" },
{ "RS", "~", "94", "131141", "10001011110" },
{ "US", "DEL", "95", "114113", "10111101000" },
{ "FNC3", "FNC3", "96", "114311", "10111100010" },
{ "FNC2", "FNC2", "97", "411113", "11110101000" },
{ "SHIFT", "SHIFT", "98", "411311", "11110100010" },
{ "CODEC", "CODEC", "99", "113141", "10111011110" },
{ "CODEB", "FNC4", "CODEB", "114131", "10111101110" },
{ "FNC4", "CODEA", "CODEA", "311141", "11101011110" },
{ "FNC1", "FNC1", "FNC1", "411131", "11110101110" },
{ "StartA", "StartA", "StartA", "211412", "11010000100" },
{ "StartB", "StartB", "StartB", "211214", "11010010000" },
{ "StartC", "StartC", "StartC", "211232", "11010011100" },
{ "Stop", "Stop", "Stop", "2331112", "1100011101011" }, };
/**
* 生产Code128的条形码的code
*
* @param barCode
* @param encode
* @return
*/
public String getCode(String barCode, String encode) {
String _Text = "";// 返回的参数
List _TextNumb = new ArrayList();// 2截取位的组合
int _Examine = 105; // 首位
// 编码不能是奇数
if (!((barCode.length() & 1) == 0))
return "";
while (barCode.length() != 0) {
int _Temp = 0;
try {
// Code128 编码必须为数字
_Temp = Integer.valueOf(barCode.substring(0, 2));
} catch (Exception e) {
e.printStackTrace();
return "";
}
// 获得条纹
_Text += getValue(barCode, barCode.substring(0, 2), _Temp);
_TextNumb.add(_Temp);
// 条码截取2个就需要去掉用过的前二位
barCode = barCode.substring(2);
}
if (_TextNumb.size() == 0) {
return "";
}
_Text = getValue(_Examine) + _Text; // 获取开始位
for (int i = 0; i != _TextNumb.size(); i++) {
_Examine += _TextNumb.get(i) * (i + 1);
}
_Examine = _Examine % 103; // 获得校验位
_Text += getValue(_Examine); // 获取校验位
_Text += "1100011101011"; // 结束位
return _Text;
}
/**
* 根据编号获得条纹
*
* @param encode
* @param p_Value
* @param p_SetID
* @return
*/
private String getValue(String encode, String p_Value, int p_SetID) {
return code128[p_SetID][4];
}
// /
// / 根据编号获得条纹
// /
// /
// /
private String getValue(int p_CodeId) {
return code128[p_CodeId][4];
}
private int m_nImageHeight = 40; // 条码的高度像素数
public static void main(String[] args) throws Exception {
TestCode128C c = new TestCode128C();
String barCode = c.getCode("118842807789", "");
c.kiCode128C(barCode, 500, "D:/code128C.jpg");
}
// /
// / 生成条码
// /
// / 条码模式字符串
// / 生成的条码高度
// / 条码图形
public void kiCode128C(String barString, int Height, String path) {
try {
//File myPNG = new File(path);
m_nImageHeight = Height;
OutputStream out = new FileOutputStream(path);
if (null == barString || null == out || 0 == barString.length())
return;
int nImageWidth = 0;
char[] cs = barString.toCharArray();
for (int i = 0; i != cs.length; i++) {
nImageWidth = cs.length*10;
}
BufferedImage bi = new BufferedImage(nImageWidth, m_nImageHeight,
BufferedImage.TYPE_INT_RGB);
Graphics g = bi.getGraphics();
for (int i = 0; i < cs.length; i++) {
if ("1".equals(cs[i] + "")) {
g.setColor(Color.BLACK);
g.fillRect(i*10, 0, 10, m_nImageHeight);
} else {
g.setColor(Color.WHITE);
g.fillRect(i*10, 0, 10, m_nImageHeight);
}
}
//JPEGImageEncoder encoder = JPEGCodec.createJPEGEncoder(out);
//encoder.encode(bi);
ImageIO.write(bi, "jpg", out);
out.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}
public class MyView extends View {
public MyView(Context context) {
super(context);
}
public MyView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public MyView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
String barCode = Code128C.getCode("118842807789", "");
int m_nImageHeight = 100;
char[] cs = barCode.toCharArray();
Paint p = new Paint();
for (int i = 0; i < cs.length; i++) {
if ("1".equals(cs[i] + "")) {
//g.setColor(Color.BLACK);
//g.fillRect(i, 0, 1, m_nImageHeight);
p.setColor(Color.BLACK);
//canvas.drawRect(i*10, 0, i*10+10, m_nImageHeight, p);
} else {
//g.setColor(Color.WHITE);
//g.fillRect(i, 0, 1, m_nImageHeight);
p.setColor(Color.WHITE);
//canvas.drawRect(i*10, 0, i*10+10, m_nImageHeight, p);
}
canvas.drawRect(i*10, 0, i*10+10, m_nImageHeight, p);
}
}
}