2021SC@SDUSC
目录
- Code 39
- Code 93
- Code 128
- Codabar
- ITF
- 参考资料
前言:本篇博客主要介绍一维码。
Code 39
Code39是条形码的一种,也被称为3 of 9 code、USD-3或者LOGMARS,由于编制简单、能够对任意长度的数据进行编码、支持设备广泛等特性而被广泛采用。
特点:
1、能够对任意长度的数据进行编码。其局限在于印刷品的长度和条码阅读器的识别范围。
2、支持设备广泛。目前几乎所有的条形码阅读设备都能阅读Code39码,打印机也是同样情况。
3、编制简单。简单的开发技术就能快速生成相应的编码图像。
4、一般Code39码由5条线和分开它们的4条缝隙共9个元素构成。线和缝隙有宽窄之分,而且无论线还是缝隙仅有3个比其他的元素要宽一定比例。39码因此得名。
编码规则:
1、每五条线表示一个字符;
2、 粗线表示1,细线表示0;
3、 线条间的间隙宽的表示1,窄的表示0;
4、 五条线加上它们之间的四条间隙就是九位二进制编码,而且这九位中必定有三位是1,所以称为39码;
5、 条形码的首尾各一个 * 标识开始和结束。
使用介绍:
Code 39只接受如下43个有效输入字符:
26个大写字母(A - Z),十个数字(0 - 9),连接号(-),句号(.),空格,美圆符号($),斜扛(/),加号(+)以及百分号(%)。
其余的输入将被忽略。
code39通常情况下不需要校验码。但是对於精确度要求高的应用,需要在code39条形码後面增加一个校验码。
由于可以合并两个字符来表达第三个字符.这样就可以用Code39条形码来表示整个ASCII表.这样就产生了Code 39全ASCII码字型.
public boolean[] encode(String contents) {
int length = contents.length();
if (length > 80) {
throw new IllegalArgumentException(
"Requested contents should be less than 80 digits long, but got " + length);
}
for (int i = 0; i < length; i++) {
int indexInString = Code39Reader.ALPHABET_STRING.indexOf(contents.charAt(i));
if (indexInString < 0) {
contents = tryToConvertToExtendedMode(contents);
length = contents.length();
if (length > 80) {
throw new IllegalArgumentException(
"Requested contents should be less than 80 digits long, but got " + length + " (extended full ASCII mode)");
}
break;
}
}
Code 93
Code 93 条码比 Code 39 条码更新、更安全且更紧凑,能读取字母和数字。它用于军事和汽车领域,还被加拿大邮政用来对特殊投递信息进行编码。
规格:Code 93 跟 Code 39 类似,其起始符和终止符不能以常规 ASCII 字符表示,通常指定为“*”。起始符后面是编码的数据。跟 Code 39 一样,每个字母由数值代表。数据后面是两个字符的校验码,用于在手动输入代码时保证准确性。这两个字符被称为“Modulo-47 校验符 C”和“Modulo-47 校验符 K”。代码中特定的数字组合生成一个余数,对应的字母或数字就变成了校验符 C 或 K。校验码后面是终止符,紧接着是终止条纹,表明条码结束。
优势: Code 93 条码比 Code 39 更小巧、更高效,且拥有更大的数据冗余,具备更高的安全性。它还包括 Code 39 中没有的 5 个特殊字符。
缺点:不同于 Code 39,Code 93 不是自检码,因此需要一个校验位。
public boolean[] encode(String contents) {
contents = convertToExtended(contents);
int length = contents.length();
if (length > 80) {
throw new IllegalArgumentException(
"Requested contents should be less than 80 digits long after converting to extended encoding, but got " + length);
}
int codeWidth = (contents.length() + 2 + 2) * 9 + 1;
boolean[] result = new boolean[codeWidth];
int pos = appendPattern(result, 0, Code93Reader.ASTERISK_ENCODING);
for (int i = 0; i < length; i++) {
int indexInString = Code93Reader.ALPHABET_STRING.indexOf(contents.charAt(i));
pos += appendPattern(result, pos, Code93Reader.CHARACTER_ENCODINGS[indexInString]);
}
//添加两个校验和
int check1 = computeChecksumIndex(contents, 20);
pos += appendPattern(result, pos, Code93Reader.CHARACTER_ENCODINGS[check1]);
//追加内容以反映添加的第一个校验和
contents += Code93Reader.ALPHABET_STRING.charAt(check1);
int check2 = computeChecksumIndex(contents, 15);
pos += appendPattern(result, pos, Code93Reader.CHARACTER_ENCODINGS[check2]);
pos += appendPattern(result, pos, Code93Reader.ASTERISK_ENCODING);
result[pos] = true;
return result;
}
Code 128
CODE128码是广泛应用在企业内部管理、生产流程、物流控制系统方面的条码码制,由于其优良的特性在管理信息系统的设计中被广泛使用,CODE128码是应用最广泛的条码码制之一。
CODE128码是1981年引入的一种高密度条码,CODE128 码可表示从 ASCII 0 到ASCII 127 共128个字符,故称128码。其中包含了数字、字母和符号字符。
特点:
●可表示高密度数据和字符串;
●每个字符由3个条、3个空、11个单元构成,字符串可变长;
●符号内含校验码;
●有三种不同的版本:A(数字、大写字母、控制字符)B(数字、大小字母、字符)C(双位数字)
CODE128A:标准数字和大写字母,控制符,特殊字符
CODE128B:标准数字和大写字母,小写字母,特殊字符
CODE128C:[00]-[99]的数字对集合,共100个
●可用128个字符分别在A、B或C三个字符串集合中。
构成:
一个Code 128条形码由六部分组成。
1、空白区域
2、起始标记
3、数据区
4、校验符
5、终止符
6、空白区域
Code 128条码指定相互间隔的3个条形和3个空白(共六个单元)代表一个字符,每个字符由一个条开始,以一个空结束。 在条形码字体中,最后一个条形通常与终止符一起组合成一个更宽的终止符。
Code 128码与Code 39码有很多的相近性,都广泛运用在企业内部管理、生产流程、物流控制系统方面。不同的在于Code 128比Code 39能表现更多的字符,单位长度里的编码密度更高。当单位长度里不能容下Code 39编码或编码字符超出了Code 39的限制时,就可选择Code 128来编码。所以Code 128比Code 39更具灵活性。
由于CODE128码可表示较全面的字符(数字、字母和符号),在同样长度的条码中可容纳的字符长度较长(高密度),条码长度与字符串长度无明显的敏感性,所以CODE128码是企业内部管理系统最为广泛使用的条码码制。
protected boolean[] encode(String contents, Map<EncodeHintType,?> hints) {
int length = contents.length();
// 检查长度
if (length < 1 || length > 80) {
throw new IllegalArgumentException(
"Contents length should be between 1 and 80 characters, but got " + length);
}
// 检查强制代码集提示。
int forcedCodeSet = -1;
if (hints != null && hints.containsKey(EncodeHintType.FORCE_CODE_SET)) {
String codeSetHint = hints.get(EncodeHintType.FORCE_CODE_SET).toString();
switch (codeSetHint) {
case "A":
forcedCodeSet = CODE_CODE_A;
break;
case "B":
forcedCodeSet = CODE_CODE_B;
break;
case "C":
forcedCodeSet = CODE_CODE_C;
break;
default:
throw new IllegalArgumentException("Unsupported code set hint: " + codeSetHint);
}
}
Codabar
库德巴条形码( Codabar):也称“血库用码”,可表示数字0-9,字符$、+、-,还有只能用作起始和终止符的a、b、c、d四个字符,空白区比窄条宽10倍,非连续性条形码,每个字符表示为4条3空,条形码长度可变,没有校验位,主要应用于血站的献血员管理和血库管理,也可作物料管理、图书馆、机场包裹发送中。
public boolean[] encode(String contents) {
if (contents.length() < 2) {
// 无法有开始/结束保护,因此暂时添加默认保护
contents = DEFAULT_GUARD + contents + DEFAULT_GUARD;
} else {
// 验证输入并计算解码长度。
char firstChar = Character.toUpperCase(contents.charAt(0));
char lastChar = Character.toUpperCase(contents.charAt(contents.length() - 1));
boolean startsNormal = CodaBarReader.arrayContains(START_END_CHARS, firstChar);
boolean endsNormal = CodaBarReader.arrayContains(START_END_CHARS, lastChar);
boolean startsAlt = CodaBarReader.arrayContains(ALT_START_END_CHARS, firstChar);
boolean endsAlt = CodaBarReader.arrayContains(ALT_START_END_CHARS, lastChar);
if (startsNormal) {
if (!endsNormal) {
throw new IllegalArgumentException("Invalid start/end guards: " + contents);
}
// 已具有有效的开始/结束
} else if (startsAlt) {
if (!endsAlt) {
throw new IllegalArgumentException("Invalid start/end guards: " + contents);
}
// 已具有有效的开始/结束
} else {
// 不是从guard开始的
if (endsNormal || endsAlt) {
throw new IllegalArgumentException("Invalid start/end guards: " + contents);
}
// 否则也不会以guard结尾,所以添加一个默认值
contents = DEFAULT_GUARD + contents + DEFAULT_GUARD;
}
}
// 起始字符和结束字符分别解码为10个长度。
int resultLength = 20;
for (int i = 1; i < contents.length() - 1; i++) {
if (Character.isDigit(contents.charAt(i)) || contents.charAt(i) == '-' || contents.charAt(i) == '$') {
resultLength += 9;
} else if (CodaBarReader.arrayContains(CHARS_WHICH_ARE_TEN_LENGTH_EACH_AFTER_DECODED, contents.charAt(i))) {
resultLength += 10;
} else {
throw new IllegalArgumentException("Cannot encode : '" + contents.charAt(i) + '\'');
}
}
// 在每个字符之间放置一个空格。
resultLength += contents.length() - 1;
}
ITF
ITF条码,又称交叉二五条码,主要用于运输包装,是印刷条件较差,不允许印刷EAN-13和UPC-A条码时应选用的一种条码。
ITF条码是有别于EAN、UPC条码的另一种形式的条码。在商品运输包装上使用的主要是14位数字字符代表组成的ITF-14条码。
ITF条码是一种连续型、定长、具有自校验功能,并且条、空都表示信息的双向条码。ITF-14条码的条码字符集、条码字符的组成与交插二五码相同。它由矩形保护框、左侧空白区、条码字符、右侧空白区组成.
public boolean[] encode(String contents) {
int length = contents.length();
if (length % 2 != 0) {
throw new IllegalArgumentException("The length of the input should be even");
}
if (length > 80) {
throw new IllegalArgumentException(
"Requested contents should be less than 80 digits long, but got " + length);
}
checkNumeric(contents);
boolean[] result = new boolean[9 + 9 * length];
int pos = appendPattern(result, 0, START_PATTERN, true);
for (int i = 0; i < length; i += 2) {
int one = Character.digit(contents.charAt(i), 10);
int two = Character.digit(contents.charAt(i + 1), 10);
int[] encoding = new int[10];
for (int j = 0; j < 5; j++) {
encoding[2 * j] = PATTERNS[one][j];
encoding[2 * j + 1] = PATTERNS[two][j];
}
pos += appendPattern(result, pos, encoding, true);
}
appendPattern(result, pos, END_PATTERN, true);
return result;
}
参考资料
CODE39
CODE 93 条码
code128
ITF条码