"Fossies" - the Fresh Open Source Software Archive  

Source code changes of the file "core/src/main/java/com/google/zxing/oned/Code128Writer.java" between
zxing-zxing-3.4.1.tar.gz and zxing-zxing-3.5.0.tar.gz

About: ZXing ("zebra crossing") is a multi-format 1D/2D barcode image processing library implemented in Java, with ports to other languages. Info: Project is in maintenance mode (no active development).

Code128Writer.java  (zxing-zxing-3.4.1):Code128Writer.java  (zxing-zxing-3.5.0)
skipping to change at line 20 skipping to change at line 20
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package com.google.zxing.oned; package com.google.zxing.oned;
import com.google.zxing.BarcodeFormat; import com.google.zxing.BarcodeFormat;
import com.google.zxing.EncodeHintType;
import com.google.zxing.common.BitMatrix; import com.google.zxing.common.BitMatrix;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collection; import java.util.Collection;
import java.util.Collections; import java.util.Collections;
import java.util.Map;
/** /**
* This object renders a CODE128 code as a {@link BitMatrix}. * This object renders a CODE128 code as a {@link BitMatrix}.
* *
* @author erik.barbara@gmail.com (Erik Barbara) * @author erik.barbara@gmail.com (Erik Barbara)
*/ */
public final class Code128Writer extends OneDimensionalCodeWriter { public final class Code128Writer extends OneDimensionalCodeWriter {
private static final int CODE_START_A = 103; private static final int CODE_START_A = 103;
private static final int CODE_START_B = 104; private static final int CODE_START_B = 104;
skipping to change at line 68 skipping to change at line 70
FNC_1 FNC_1
} }
@Override @Override
protected Collection<BarcodeFormat> getSupportedWriteFormats() { protected Collection<BarcodeFormat> getSupportedWriteFormats() {
return Collections.singleton(BarcodeFormat.CODE_128); return Collections.singleton(BarcodeFormat.CODE_128);
} }
@Override @Override
public boolean[] encode(String contents) { public boolean[] encode(String contents) {
return encode(contents, null);
}
@Override
protected boolean[] encode(String contents, Map<EncodeHintType,?> hints) {
int forcedCodeSet = check(contents, hints);
boolean hasCompactionHint = hints != null && hints.containsKey(EncodeHintTyp
e.CODE128_COMPACT) &&
Boolean.parseBoolean(hints.get(EncodeHintType.CODE128_COMPACT).toString(
));
return hasCompactionHint ? new MinimalEncoder().encode(contents) : encodeFas
t(contents, 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) {
throw new IllegalArgumentException( throw new IllegalArgumentException(
"Contents length should be between 1 and 80 characters, but got " + le ngth); "Contents length should be between 1 and 80 characters, but got " + le ngth);
} }
// Check for forced code set hint.
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: " + cod
eSetHint);
}
}
// Check content // Check content
for (int i = 0; i < length; i++) { for (int i = 0; i < length; i++) {
char c = contents.charAt(i); char c = contents.charAt(i);
// check for non ascii characters that are not special GS1 characters
switch (c) { switch (c) {
// special function characters
case ESCAPE_FNC_1: case ESCAPE_FNC_1:
case ESCAPE_FNC_2: case ESCAPE_FNC_2:
case ESCAPE_FNC_3: case ESCAPE_FNC_3:
case ESCAPE_FNC_4: case ESCAPE_FNC_4:
break; break;
// non ascii characters
default: default:
if (c > 127) { if (c > 127) {
// support for FNC4 isn't implemented, no full Latin-1 character set // no full Latin-1 character set available at the moment
available at the moment // shift and manual code change are not supported
throw new IllegalArgumentException("Bad character in input: " + c); throw new IllegalArgumentException("Bad character in input: ASCII va
lue=" + (int) c);
} }
} }
// check characters for compatibility with forced code set
switch (forcedCodeSet) {
case CODE_CODE_A:
// allows no ascii above 95 (no lower caps, no special symbols)
if (c > 95 && c <= 127) {
throw new IllegalArgumentException("Bad character in input for force
d code set A: ASCII value=" + (int) c);
}
break;
case CODE_CODE_B:
// allows no ascii below 32 (terminal symbols)
if (c <= 32) {
throw new IllegalArgumentException("Bad character in input for force
d code set B: ASCII value=" + (int) c);
}
break;
case CODE_CODE_C:
// allows only numbers and no FNC 2/3/4
if (c < 48 || (c > 57 && c <= 127) || c == ESCAPE_FNC_2 || c == ESCAPE
_FNC_3 || c == ESCAPE_FNC_4) {
throw new IllegalArgumentException("Bad character in input for force
d code set C: ASCII value=" + (int) c);
}
break;
}
} }
return forcedCodeSet;
}
private static boolean[] encodeFast(String contents, int forcedCodeSet) {
int length = contents.length();
Collection<int[]> patterns = new ArrayList<>(); // temporary storage for pat terns Collection<int[]> patterns = new ArrayList<>(); // temporary storage for pat terns
int checkSum = 0; int checkSum = 0;
int checkWeight = 1; int checkWeight = 1;
int codeSet = 0; // selected code (CODE_CODE_B or CODE_CODE_C) int codeSet = 0; // selected code (CODE_CODE_B or CODE_CODE_C)
int position = 0; // position in contents int position = 0; // position in contents
while (position < length) { while (position < length) {
//Select code to use //Select code to use
int newCodeSet = chooseCode(contents, position, codeSet); int newCodeSet;
if (forcedCodeSet == -1) {
newCodeSet = chooseCode(contents, position, codeSet);
} else {
newCodeSet = forcedCodeSet;
}
//Get the pattern index //Get the pattern index
int patternIndex; int patternIndex;
if (newCodeSet == codeSet) { if (newCodeSet == codeSet) {
// Encode the current character // Encode the current character
// First handle escapes // First handle escapes
switch (contents.charAt(position)) { switch (contents.charAt(position)) {
case ESCAPE_FNC_1: case ESCAPE_FNC_1:
patternIndex = CODE_FNC_1; patternIndex = CODE_FNC_1;
break; break;
skipping to change at line 138 skipping to change at line 210
if (patternIndex < 0) { if (patternIndex < 0) {
// everything below a space character comes behind the undersc ore in the code patterns table // everything below a space character comes behind the undersc ore in the code patterns table
patternIndex += '`'; patternIndex += '`';
} }
break; break;
case CODE_CODE_B: case CODE_CODE_B:
patternIndex = contents.charAt(position) - ' '; patternIndex = contents.charAt(position) - ' ';
break; break;
default: default:
// CODE_CODE_C // CODE_CODE_C
if (position + 1 == length) {
// this is the last character, but the encoding is C, which al
ways encodes two characers
throw new IllegalArgumentException("Bad number of characters f
or digit only encoding.");
}
patternIndex = Integer.parseInt(contents.substring(position, pos ition + 2)); patternIndex = Integer.parseInt(contents.substring(position, pos ition + 2));
position++; // Also incremented below position++; // Also incremented below
break; break;
} }
} }
position++; position++;
} else { } else {
// Should we change the current code? // Should we change the current code?
// Do we have a code set? // Do we have a code set?
if (codeSet == 0) { if (codeSet == 0) {
skipping to change at line 176 skipping to change at line 252
// Get the pattern // Get the pattern
patterns.add(Code128Reader.CODE_PATTERNS[patternIndex]); patterns.add(Code128Reader.CODE_PATTERNS[patternIndex]);
// Compute checksum // Compute checksum
checkSum += patternIndex * checkWeight; checkSum += patternIndex * checkWeight;
if (position != 0) { if (position != 0) {
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]);
// Append stop code // Append stop code
patterns.add(Code128Reader.CODE_PATTERNS[CODE_STOP]); patterns.add(Code128Reader.CODE_PATTERNS[CODE_STOP]);
// Compute code width // Compute code width
int codeWidth = 0; int codeWidth = 0;
for (int[] pattern : patterns) { for (int[] pattern : patterns) {
skipping to change at line 227 skipping to change at line 306
c = value.charAt(start + 1); c = value.charAt(start + 1);
if (c < '0' || c > '9') { if (c < '0' || c > '9') {
return CType.ONE_DIGIT; return CType.ONE_DIGIT;
} }
return CType.TWO_DIGITS; return CType.TWO_DIGITS;
} }
private static int chooseCode(CharSequence value, int start, int oldCode) { private static int chooseCode(CharSequence value, int start, int oldCode) {
CType lookahead = findCType(value, start); CType lookahead = findCType(value, start);
if (lookahead == CType.ONE_DIGIT) { if (lookahead == CType.ONE_DIGIT) {
if (oldCode == CODE_CODE_A) { if (oldCode == CODE_CODE_A) {
return CODE_CODE_A; return CODE_CODE_A;
} }
return CODE_CODE_B; return CODE_CODE_B;
} }
if (lookahead == CType.UNCODABLE) { if (lookahead == CType.UNCODABLE) {
if (start < value.length()) { if (start < value.length()) {
char c = value.charAt(start); char c = value.charAt(start);
if (c < ' ' || (oldCode == CODE_CODE_A && (c < '`' || (c >= ESCAPE_FNC_1 && c <= ESCAPE_FNC_4)))) { if (c < ' ' || (oldCode == CODE_CODE_A && (c < '`' || (c >= ESCAPE_FNC_1 && c <= ESCAPE_FNC_4)))) {
// can continue in code A, encodes ASCII 0 to 95 or FNC1 to FNC4 // can continue in code A, encodes ASCII 0 to 95 or FNC1 to FNC4
return CODE_CODE_A; return CODE_CODE_A;
} }
} }
return CODE_CODE_B; // no choice return CODE_CODE_B; // no choice
skipping to change at line 286 skipping to change at line 365
// Here oldCode == 0, which means we are choosing the initial code // Here oldCode == 0, which means we are choosing the initial code
if (lookahead == CType.FNC_1) { // ignore FNC_1 if (lookahead == CType.FNC_1) { // ignore FNC_1
lookahead = findCType(value, start + 1); lookahead = findCType(value, start + 1);
} }
if (lookahead == CType.TWO_DIGITS) { // at least two digits, start in code C if (lookahead == CType.TWO_DIGITS) { // at least two digits, start in code C
return CODE_CODE_C; return CODE_CODE_C;
} }
return CODE_CODE_B; return CODE_CODE_B;
} }
/**
* Encodes minimally using Divide-And-Conquer with Memoization
**/
private static final class MinimalEncoder {
private enum Charset { A, B, C, NONE }
private enum Latch { A, B, C, SHIFT, NONE }
static final String A = " !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQ
RSTUVWXYZ[\\]^_\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\u0
01A\u001B\u001C\u001D\u001E\u001F" +
"\u00FF";
static final String B = " !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQ
RSTUVWXYZ[\\]^_`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 trail
ing 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 positio
n) {
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 charact
er 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();
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;
}
}
} }
 End of changes. 16 change blocks. 
8 lines changed or deleted 311 lines changed or added

Home  |  About  |  Features  |  All  |  Newest  |  Dox  |  Diffs  |  RSS Feeds  |  Screenshots  |  Comments  |  Imprint  |  Privacy  |  HTTP(S)