mirror of
https://github.com/zxing/zxing.git
synced 2024-11-09 20:44:03 -08:00
Minimal encoding for Code-128 (2nd, less intrusive version) (#1484)
* 2nd version of Code128 minimal encoding.
This commit is contained in:
parent
6c2ea9e6bc
commit
94fb277607
|
@ -145,4 +145,12 @@ public enum EncodeHintType {
|
||||||
* Valid values are "A", "B", "C".
|
* Valid values are "A", "B", "C".
|
||||||
*/
|
*/
|
||||||
FORCE_CODE_SET,
|
FORCE_CODE_SET,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Specifies whether to use compact mode for Code-128 code (type {@link Boolean}, or "true" or "false"
|
||||||
|
* This can yield slightly smaller bar codes. This option and {@link #FORCE_CODE_SET} are mutually
|
||||||
|
* exclusive options.
|
||||||
|
*/
|
||||||
|
CODE128_COMPACT,
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -72,6 +72,16 @@ public final class Code128Writer extends OneDimensionalCodeWriter {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected boolean[] encode(String contents, Map<EncodeHintType,?> hints) {
|
protected boolean[] encode(String contents, Map<EncodeHintType,?> hints) {
|
||||||
|
|
||||||
|
int forcedCodeSet = check(contents, hints);
|
||||||
|
|
||||||
|
boolean hasCompactionHint = hints != null && hints.containsKey(EncodeHintType.CODE128_COMPACT) &&
|
||||||
|
Boolean.parseBoolean(hints.get(EncodeHintType.CODE128_COMPACT).toString());
|
||||||
|
|
||||||
|
return hasCompactionHint ? new MinimalEncoder().encode(contents) : encodeFast(contents, hints, forcedCodeSet);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static int check(String contents, Map<EncodeHintType,?> hints) {
|
||||||
int length = contents.length();
|
int length = contents.length();
|
||||||
// Check length
|
// Check length
|
||||||
if (length < 1 || length > 80) {
|
if (length < 1 || length > 80) {
|
||||||
|
@ -139,6 +149,11 @@ public final class Code128Writer extends OneDimensionalCodeWriter {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return forcedCodeSet;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static boolean[] encodeFast(String contents, Map<EncodeHintType,?> hints, int forcedCodeSet) {
|
||||||
|
int length = contents.length();
|
||||||
|
|
||||||
Collection<int[]> patterns = new ArrayList<>(); // temporary storage for patterns
|
Collection<int[]> patterns = new ArrayList<>(); // temporary storage for patterns
|
||||||
int checkSum = 0;
|
int checkSum = 0;
|
||||||
|
@ -234,7 +249,10 @@ public final class Code128Writer extends OneDimensionalCodeWriter {
|
||||||
checkWeight++;
|
checkWeight++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return produceResult(patterns, checkSum);
|
||||||
|
}
|
||||||
|
|
||||||
|
static boolean[] produceResult(Collection<int[]> patterns, int checkSum) {
|
||||||
// Compute and append checksum
|
// Compute and append checksum
|
||||||
checkSum %= 103;
|
checkSum %= 103;
|
||||||
patterns.add(Code128Reader.CODE_PATTERNS[checkSum]);
|
patterns.add(Code128Reader.CODE_PATTERNS[checkSum]);
|
||||||
|
@ -344,4 +362,205 @@ public final class Code128Writer extends OneDimensionalCodeWriter {
|
||||||
return CODE_CODE_B;
|
return CODE_CODE_B;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Encodes minimally using Divide-And-Conquer with Memoization
|
||||||
|
**/
|
||||||
|
private static class MinimalEncoder {
|
||||||
|
private enum Charset { A, B, C, NONE };
|
||||||
|
private enum Latch { A, B, C, SHIFT, NONE };
|
||||||
|
|
||||||
|
static final String A = " !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_\u0000\u0001\u0002" +
|
||||||
|
"\u0003\u0004\u0005\u0006\u0007\u0008\u0009\n\u000B\u000C\r\u000E\u000F\u0010\u0011" +
|
||||||
|
"\u0012\u0013\u0014\u0015\u0016\u0017\u0018\u0019\u001A\u001B\u001C\u001D\u001E\u001F" +
|
||||||
|
"\u00FF";
|
||||||
|
static final String B = " !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqr" +
|
||||||
|
"stuvwxyz{|}~\u007F\u00FF";
|
||||||
|
|
||||||
|
private static final int CODE_SHIFT = 98;
|
||||||
|
|
||||||
|
private int[][] memoizedCost;
|
||||||
|
private Latch[][] minPath;
|
||||||
|
|
||||||
|
private boolean[] encode(String contents) {
|
||||||
|
memoizedCost = new int[4][contents.length()];
|
||||||
|
minPath = new Latch[4][contents.length()];
|
||||||
|
|
||||||
|
encode(contents, Charset.NONE, 0);
|
||||||
|
|
||||||
|
Collection<int[]> patterns = new ArrayList<>();
|
||||||
|
int[] checkSum = new int[] {0};
|
||||||
|
int[] checkWeight = new int[] {1};
|
||||||
|
int length = contents.length();
|
||||||
|
Charset charset = Charset.NONE;
|
||||||
|
for (int i = 0; i < length; i++) {
|
||||||
|
Latch latch = minPath[charset.ordinal()][i];
|
||||||
|
switch (latch) {
|
||||||
|
case A:
|
||||||
|
charset = Charset.A;
|
||||||
|
addPattern(patterns, i == 0 ? CODE_START_A : CODE_CODE_A, checkSum, checkWeight, i);
|
||||||
|
break;
|
||||||
|
case B:
|
||||||
|
charset = Charset.B;
|
||||||
|
addPattern(patterns, i == 0 ? CODE_START_B : CODE_CODE_B, checkSum, checkWeight, i);
|
||||||
|
break;
|
||||||
|
case C:
|
||||||
|
charset = Charset.C;
|
||||||
|
addPattern(patterns, i == 0 ? CODE_START_C : CODE_CODE_C, checkSum, checkWeight, i);
|
||||||
|
break;
|
||||||
|
case SHIFT:
|
||||||
|
addPattern(patterns, CODE_SHIFT, checkSum, checkWeight, i);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (charset == Charset.C) {
|
||||||
|
if (contents.charAt(i) == ESCAPE_FNC_1) {
|
||||||
|
addPattern(patterns, CODE_FNC_1, checkSum, checkWeight, i);
|
||||||
|
} else {
|
||||||
|
addPattern(patterns, Integer.parseInt(contents.substring(i, i + 2)), checkSum, checkWeight, i);
|
||||||
|
assert i + 1 < length; //the algorithm never leads to a single trailing digit in character set C
|
||||||
|
if (i + 1 < length) {
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else { // charset A or B
|
||||||
|
int patternIndex;
|
||||||
|
switch (contents.charAt(i)) {
|
||||||
|
case ESCAPE_FNC_1:
|
||||||
|
patternIndex = CODE_FNC_1;
|
||||||
|
break;
|
||||||
|
case ESCAPE_FNC_2:
|
||||||
|
patternIndex = CODE_FNC_2;
|
||||||
|
break;
|
||||||
|
case ESCAPE_FNC_3:
|
||||||
|
patternIndex = CODE_FNC_3;
|
||||||
|
break;
|
||||||
|
case ESCAPE_FNC_4:
|
||||||
|
if ((charset == Charset.A && latch != Latch.SHIFT) ||
|
||||||
|
(charset == Charset.B && latch == Latch.SHIFT)) {
|
||||||
|
patternIndex = CODE_FNC_4_A;
|
||||||
|
} else {
|
||||||
|
patternIndex = CODE_FNC_4_B;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
patternIndex = contents.charAt(i) - ' ';
|
||||||
|
}
|
||||||
|
if ((charset == Charset.A && latch != Latch.SHIFT) ||
|
||||||
|
(charset == Charset.B && latch == Latch.SHIFT)) {
|
||||||
|
if (patternIndex < 0) {
|
||||||
|
patternIndex += '`';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
addPattern(patterns, patternIndex, checkSum, checkWeight, i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
memoizedCost = null;
|
||||||
|
minPath = null;
|
||||||
|
return produceResult(patterns, checkSum[0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void addPattern(Collection<int[]> patterns,
|
||||||
|
int patternIndex,
|
||||||
|
int[] checkSum,
|
||||||
|
int[] checkWeight,
|
||||||
|
int position) {
|
||||||
|
patterns.add(Code128Reader.CODE_PATTERNS[patternIndex]);
|
||||||
|
if (position != 0) {
|
||||||
|
checkWeight[0]++;
|
||||||
|
}
|
||||||
|
checkSum[0] += patternIndex * checkWeight[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
private static boolean isDigit(char c) {
|
||||||
|
return c >= '0' && c <= '9';
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean canEncode(CharSequence contents, Charset charset,int position) {
|
||||||
|
char c = contents.charAt(position);
|
||||||
|
switch (charset) {
|
||||||
|
case A: return c == ESCAPE_FNC_1 ||
|
||||||
|
c == ESCAPE_FNC_2 ||
|
||||||
|
c == ESCAPE_FNC_3 ||
|
||||||
|
c == ESCAPE_FNC_4 ||
|
||||||
|
A.indexOf(c) >= 0;
|
||||||
|
case B: return c == ESCAPE_FNC_1 ||
|
||||||
|
c == ESCAPE_FNC_2 ||
|
||||||
|
c == ESCAPE_FNC_3 ||
|
||||||
|
c == ESCAPE_FNC_4 ||
|
||||||
|
B.indexOf(c) >= 0;
|
||||||
|
case C: return c == ESCAPE_FNC_1 ||
|
||||||
|
(position + 1 < contents.length() &&
|
||||||
|
isDigit(c) &&
|
||||||
|
isDigit(contents.charAt(position + 1)));
|
||||||
|
default: return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Encode the string starting at position position starting with the character set charset
|
||||||
|
**/
|
||||||
|
private int encode(CharSequence contents, Charset charset, int position) {
|
||||||
|
assert position < contents.length();
|
||||||
|
int mCost = memoizedCost[charset.ordinal()][position];
|
||||||
|
if (mCost > 0) {
|
||||||
|
return mCost;
|
||||||
|
}
|
||||||
|
|
||||||
|
int minCost = Integer.MAX_VALUE;
|
||||||
|
Latch minLatch = Latch.NONE;
|
||||||
|
boolean atEnd = position + 1 >= contents.length();
|
||||||
|
|
||||||
|
final Charset[] sets = new Charset[] { Charset.A,Charset.B };
|
||||||
|
for (int i = 0; i <= 1; i++) {
|
||||||
|
if (canEncode(contents, sets[i], position)) {
|
||||||
|
int cost = 1;
|
||||||
|
Latch latch = Latch.NONE;
|
||||||
|
if (charset != sets[i]) {
|
||||||
|
cost++;
|
||||||
|
latch = Latch.valueOf(sets[i].toString());
|
||||||
|
}
|
||||||
|
if (!atEnd) {
|
||||||
|
cost += encode(contents, sets[i], position + 1);
|
||||||
|
}
|
||||||
|
if (cost < minCost) {
|
||||||
|
minCost = cost;
|
||||||
|
minLatch = latch;
|
||||||
|
}
|
||||||
|
cost = 1;
|
||||||
|
if (charset == sets[(i + 1) % 2]) {
|
||||||
|
cost++;
|
||||||
|
latch = Latch.SHIFT;
|
||||||
|
if (!atEnd) {
|
||||||
|
cost += encode(contents, charset, position + 1);
|
||||||
|
}
|
||||||
|
if (cost < minCost) {
|
||||||
|
minCost = cost;
|
||||||
|
minLatch = latch;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (canEncode(contents, Charset.C, position)) {
|
||||||
|
int cost = 1;
|
||||||
|
Latch latch = Latch.NONE;
|
||||||
|
if (charset != Charset.C) {
|
||||||
|
cost++;
|
||||||
|
latch = Latch.C;
|
||||||
|
}
|
||||||
|
int advance = contents.charAt(position) == ESCAPE_FNC_1 ? 1 : 2;
|
||||||
|
if (position + advance < contents.length()) {
|
||||||
|
cost += encode(contents, Charset.C, position + advance);
|
||||||
|
}
|
||||||
|
if (cost < minCost) {
|
||||||
|
minCost = cost;
|
||||||
|
minLatch = latch;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (minCost == Integer.MAX_VALUE) {
|
||||||
|
throw new IllegalArgumentException("Bad character in input: ASCII value=" + (int) contents.charAt(position));
|
||||||
|
}
|
||||||
|
memoizedCost[charset.ordinal()][position] = minCost;
|
||||||
|
minPath[charset.ordinal()][position] = minLatch;
|
||||||
|
return minCost;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -25,7 +25,6 @@ import com.google.zxing.BarcodeFormat;
|
||||||
import com.google.zxing.EncodeHintType;
|
import com.google.zxing.EncodeHintType;
|
||||||
import com.google.zxing.Result;
|
import com.google.zxing.Result;
|
||||||
import com.google.zxing.Writer;
|
import com.google.zxing.Writer;
|
||||||
import com.google.zxing.WriterException;
|
|
||||||
import com.google.zxing.common.BitArray;
|
import com.google.zxing.common.BitArray;
|
||||||
import com.google.zxing.common.BitMatrix;
|
import com.google.zxing.common.BitMatrix;
|
||||||
|
|
||||||
|
@ -61,42 +60,57 @@ public class Code128WriterTestCase extends Assert {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testEncodeWithFunc3() throws WriterException {
|
public void testEncodeWithFunc3() throws Exception {
|
||||||
String toEncode = "\u00f3" + "123";
|
String toEncode = "\u00f3" + "123";
|
||||||
String expected = QUIET_SPACE + START_CODE_B + FNC3 +
|
String expected = QUIET_SPACE + START_CODE_B + FNC3 +
|
||||||
// "1" "2" "3" check digit 51
|
// "1" "2" "3" check digit 51
|
||||||
"10011100110" + "11001110010" + "11001011100" + "11101000110" + STOP + QUIET_SPACE;
|
"10011100110" + "11001110010" + "11001011100" + "11101000110" + STOP + QUIET_SPACE;
|
||||||
|
|
||||||
BitMatrix result = writer.encode(toEncode, BarcodeFormat.CODE_128, 0, 0);
|
BitMatrix result = encode(toEncode, false, "123");
|
||||||
|
|
||||||
String actual = BitMatrixTestCase.matrixToString(result);
|
String actual = BitMatrixTestCase.matrixToString(result);
|
||||||
assertEquals(expected, actual);
|
assertEquals(expected, actual);
|
||||||
|
|
||||||
|
int width = result.getWidth();
|
||||||
|
result = encode(toEncode, true, "123");
|
||||||
|
|
||||||
|
assertEquals(width, result.getWidth());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testEncodeWithFunc2() throws WriterException {
|
public void testEncodeWithFunc2() throws Exception {
|
||||||
String toEncode = "\u00f2" + "123";
|
String toEncode = "\u00f2" + "123";
|
||||||
String expected = QUIET_SPACE + START_CODE_B + FNC2 +
|
String expected = QUIET_SPACE + START_CODE_B + FNC2 +
|
||||||
// "1" "2" "3" check digit 56
|
// "1" "2" "3" check digit 56
|
||||||
"10011100110" + "11001110010" + "11001011100" + "11100010110" + STOP + QUIET_SPACE;
|
"10011100110" + "11001110010" + "11001011100" + "11100010110" + STOP + QUIET_SPACE;
|
||||||
|
|
||||||
BitMatrix result = writer.encode(toEncode, BarcodeFormat.CODE_128, 0, 0);
|
BitMatrix result = encode(toEncode, false, "123");
|
||||||
|
|
||||||
String actual = BitMatrixTestCase.matrixToString(result);
|
String actual = BitMatrixTestCase.matrixToString(result);
|
||||||
assertEquals(expected, actual);
|
assertEquals(expected, actual);
|
||||||
|
|
||||||
|
int width = result.getWidth();
|
||||||
|
result = encode(toEncode, true, "123");
|
||||||
|
|
||||||
|
assertEquals(width, result.getWidth());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testEncodeWithFunc1() throws WriterException {
|
public void testEncodeWithFunc1() throws Exception {
|
||||||
String toEncode = "\u00f1" + "123";
|
String toEncode = "\u00f1" + "123";
|
||||||
String expected = QUIET_SPACE + START_CODE_C + FNC1 +
|
String expected = QUIET_SPACE + START_CODE_C + FNC1 +
|
||||||
// "12" "3" check digit 92
|
// "12" "3" check digit 92
|
||||||
"10110011100" + SWITCH_CODE_B + "11001011100" + "10101111000" + STOP + QUIET_SPACE;
|
"10110011100" + SWITCH_CODE_B + "11001011100" + "10101111000" + STOP + QUIET_SPACE;
|
||||||
|
|
||||||
BitMatrix result = writer.encode(toEncode, BarcodeFormat.CODE_128, 0, 0);
|
BitMatrix result = encode(toEncode, false, "123");
|
||||||
|
|
||||||
String actual = BitMatrixTestCase.matrixToString(result);
|
String actual = BitMatrixTestCase.matrixToString(result);
|
||||||
assertEquals(expected, actual);
|
assertEquals(expected, actual);
|
||||||
|
|
||||||
|
int width = result.getWidth();
|
||||||
|
result = encode(toEncode, true, "123");
|
||||||
|
|
||||||
|
assertEquals(width, result.getWidth());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ -104,24 +118,88 @@ public class Code128WriterTestCase extends Assert {
|
||||||
String toEncode = "\u00f1" + "10958" + "\u00f1" + "17160526";
|
String toEncode = "\u00f1" + "10958" + "\u00f1" + "17160526";
|
||||||
String expected = "1095817160526";
|
String expected = "1095817160526";
|
||||||
|
|
||||||
BitMatrix encResult = writer.encode(toEncode, BarcodeFormat.CODE_128, 0, 0);
|
BitMatrix encResult = encode(toEncode, false, expected);
|
||||||
BitArray row = encResult.getRow(0, null);
|
|
||||||
Result rtResult = reader.decodeRow(0, row, null);
|
int width = encResult.getWidth();
|
||||||
String actual = rtResult.getText();
|
encResult = encode(toEncode, true, expected);
|
||||||
assertEquals(expected, actual);
|
//Compact encoding has one latch less and encodes as STARTA,FNC1,1,CODEC,09,58,FNC1,17,16,05,26
|
||||||
|
assertEquals(width, encResult.getWidth() + 11);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testEncodeWithFunc4() throws WriterException {
|
public void testLongCompact() throws Exception {
|
||||||
|
//test longest possible input
|
||||||
|
String toEncode = "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA";
|
||||||
|
BitMatrix result = encode(toEncode, true, toEncode);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testShift() throws Exception {
|
||||||
|
//compare fast to compact
|
||||||
|
String toEncode = "a\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\n";
|
||||||
|
BitMatrix result = encode(toEncode, false, toEncode);
|
||||||
|
|
||||||
|
int width = result.getWidth();
|
||||||
|
result = encode(toEncode, true, toEncode);
|
||||||
|
|
||||||
|
//big difference since the fast algoritm doesn't make use of SHIFT
|
||||||
|
assertEquals(width, result.getWidth() + 253);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testDigitMixCompaction() throws Exception {
|
||||||
|
//compare fast to compact
|
||||||
|
String toEncode = "A1A12A123A1234A12345AA1AA12AA123AA1234AA1235";
|
||||||
|
BitMatrix result = encode(toEncode, false, toEncode);
|
||||||
|
|
||||||
|
int width = result.getWidth();
|
||||||
|
result = encode(toEncode, true, toEncode);
|
||||||
|
|
||||||
|
//very good, no difference
|
||||||
|
assertEquals(width, result.getWidth());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testCompaction1() throws Exception {
|
||||||
|
//compare fast to compact
|
||||||
|
String toEncode = "AAAAAAAAAAA12AAAAAAAAA";
|
||||||
|
BitMatrix result = encode(toEncode, false, toEncode);
|
||||||
|
|
||||||
|
int width = result.getWidth();
|
||||||
|
result = encode(toEncode, true, toEncode);
|
||||||
|
|
||||||
|
//very good, no difference
|
||||||
|
assertEquals(width, result.getWidth());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testCompaction2() throws Exception {
|
||||||
|
//compare fast to compact
|
||||||
|
String toEncode = "AAAAAAAAAAA1212aaaaaaaaa";
|
||||||
|
BitMatrix result = encode(toEncode, false, toEncode);
|
||||||
|
|
||||||
|
int width = result.getWidth();
|
||||||
|
result = encode(toEncode, true, toEncode);
|
||||||
|
|
||||||
|
//very good, no difference
|
||||||
|
assertEquals(width, result.getWidth());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testEncodeWithFunc4() throws Exception {
|
||||||
String toEncode = "\u00f4" + "123";
|
String toEncode = "\u00f4" + "123";
|
||||||
String expected = QUIET_SPACE + START_CODE_B + FNC4B +
|
String expected = QUIET_SPACE + START_CODE_B + FNC4B +
|
||||||
// "1" "2" "3" check digit 59
|
// "1" "2" "3" check digit 59
|
||||||
"10011100110" + "11001110010" + "11001011100" + "11100011010" + STOP + QUIET_SPACE;
|
"10011100110" + "11001110010" + "11001011100" + "11100011010" + STOP + QUIET_SPACE;
|
||||||
|
|
||||||
BitMatrix result = writer.encode(toEncode, BarcodeFormat.CODE_128, 0, 0);
|
BitMatrix result = encode(toEncode, false, null);
|
||||||
|
|
||||||
String actual = BitMatrixTestCase.matrixToString(result);
|
String actual = BitMatrixTestCase.matrixToString(result);
|
||||||
assertEquals(expected, actual);
|
assertEquals(expected, actual);
|
||||||
|
|
||||||
|
int width = result.getWidth();
|
||||||
|
result = encode(toEncode, true, null);
|
||||||
|
assertEquals(width, result.getWidth());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ -131,11 +209,15 @@ public class Code128WriterTestCase extends Assert {
|
||||||
String expected = QUIET_SPACE + START_CODE_A + LF + FNC1 + FNC4A +
|
String expected = QUIET_SPACE + START_CODE_A + LF + FNC1 + FNC4A +
|
||||||
"10011100110" + LF + "10101111000" + STOP + QUIET_SPACE;
|
"10011100110" + LF + "10101111000" + STOP + QUIET_SPACE;
|
||||||
|
|
||||||
BitMatrix result = writer.encode(toEncode, BarcodeFormat.CODE_128, 0, 0);
|
BitMatrix result = encode(toEncode, false, null);
|
||||||
|
|
||||||
String actual = BitMatrixTestCase.matrixToString(result);
|
String actual = BitMatrixTestCase.matrixToString(result);
|
||||||
|
|
||||||
assertEquals(expected, actual);
|
assertEquals(expected, actual);
|
||||||
|
|
||||||
|
int width = result.getWidth();
|
||||||
|
result = encode(toEncode, true, null);
|
||||||
|
assertEquals(width, result.getWidth());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ -148,6 +230,7 @@ public class Code128WriterTestCase extends Assert {
|
||||||
SWITCH_CODE_A + "10100111100" + "11001110100" + STOP + QUIET_SPACE);
|
SWITCH_CODE_A + "10100111100" + "11001110100" + STOP + QUIET_SPACE);
|
||||||
|
|
||||||
// start with B switch to A and back to B
|
// start with B switch to A and back to B
|
||||||
|
// the compact encoder encodes this shorter as STARTB,a,b,SHIFT,NUL,a,b
|
||||||
testEncode("ab\0ab", QUIET_SPACE + START_CODE_B +
|
testEncode("ab\0ab", QUIET_SPACE + START_CODE_B +
|
||||||
// "a" "b" Switch to A "\0" Switch to B
|
// "a" "b" Switch to A "\0" Switch to B
|
||||||
"10010110000" + "10010000110" + SWITCH_CODE_A + "10100001100" + SWITCH_CODE_B +
|
"10010110000" + "10010000110" + SWITCH_CODE_A + "10100001100" + SWITCH_CODE_B +
|
||||||
|
@ -156,15 +239,15 @@ public class Code128WriterTestCase extends Assert {
|
||||||
}
|
}
|
||||||
|
|
||||||
private void testEncode(String toEncode, String expected) throws Exception {
|
private void testEncode(String toEncode, String expected) throws Exception {
|
||||||
BitMatrix result = writer.encode(toEncode, BarcodeFormat.CODE_128, 0, 0);
|
BitMatrix result = encode(toEncode, false, toEncode);
|
||||||
|
|
||||||
String actual = BitMatrixTestCase.matrixToString(result);
|
String actual = BitMatrixTestCase.matrixToString(result);
|
||||||
assertEquals(toEncode, expected, actual);
|
assertEquals(toEncode, expected, actual);
|
||||||
|
|
||||||
BitArray row = result.getRow(0, null);
|
|
||||||
Result rtResult = reader.decodeRow(0, row, null);
|
int width = result.getWidth();
|
||||||
String actualRoundtripResultText = rtResult.getText();
|
result = encode(toEncode, true, toEncode);
|
||||||
assertEquals(toEncode, actualRoundtripResultText);
|
assert result.getWidth() <= width;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test(expected = IllegalArgumentException.class)
|
@Test(expected = IllegalArgumentException.class)
|
||||||
|
@ -248,4 +331,29 @@ public class Code128WriterTestCase extends Assert {
|
||||||
String actual = BitMatrixTestCase.matrixToString(result);
|
String actual = BitMatrixTestCase.matrixToString(result);
|
||||||
assertEquals(expected, actual);
|
assertEquals(expected, actual);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private BitMatrix encode(String toEncode, boolean compact, String expectedLoopback) throws Exception {
|
||||||
|
Map<EncodeHintType, Object> hints = new EnumMap<>(EncodeHintType.class);
|
||||||
|
if (compact) {
|
||||||
|
hints.put(EncodeHintType.CODE128_COMPACT, Boolean.TRUE);
|
||||||
|
}
|
||||||
|
BitMatrix encResult = writer.encode(toEncode, BarcodeFormat.CODE_128, 0, 0, hints);
|
||||||
|
if (expectedLoopback != null) {
|
||||||
|
BitArray row = encResult.getRow(0, null);
|
||||||
|
Result rtResult = reader.decodeRow(0, row, null);
|
||||||
|
String actual = rtResult.getText();
|
||||||
|
assertEquals(expectedLoopback, actual);
|
||||||
|
}
|
||||||
|
if (compact) {
|
||||||
|
//check that what is encoded compactly yields the same on loopback as what was encoded fast.
|
||||||
|
BitArray row = encResult.getRow(0, null);
|
||||||
|
Result rtResult = reader.decodeRow(0, row, null);
|
||||||
|
String actual = rtResult.getText();
|
||||||
|
BitMatrix encResultFast = writer.encode(toEncode, BarcodeFormat.CODE_128, 0, 0);
|
||||||
|
row = encResultFast.getRow(0, null);
|
||||||
|
rtResult = reader.decodeRow(0, row, null);
|
||||||
|
assertEquals(rtResult.getText(), actual);
|
||||||
|
}
|
||||||
|
return encResult;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue