mirror of
https://github.com/zxing/zxing.git
synced 2025-02-21 02:55:27 -08:00
Add support for multiple character-ECIs in data matrix decoder (#1474)
* Added support for multiple character-ECIs * - Changed from ArrayList<Byte> to ByteArrayOutputStream - Added blank lines * Improved performance for the general case (without ECI)
This commit is contained in:
parent
9b972bbb07
commit
c4266bf09c
|
@ -19,8 +19,10 @@ package com.google.zxing.datamatrix.decoder;
|
|||
import com.google.zxing.FormatException;
|
||||
import com.google.zxing.common.BitSource;
|
||||
import com.google.zxing.common.DecoderResult;
|
||||
import com.google.zxing.common.CharacterSetECI;
|
||||
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.nio.charset.Charset;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.HashSet;
|
||||
|
@ -87,7 +89,7 @@ final class DecodedBitStreamParser {
|
|||
|
||||
static DecoderResult decode(byte[] bytes) throws FormatException {
|
||||
BitSource bits = new BitSource(bytes);
|
||||
StringBuilder result = new StringBuilder(100);
|
||||
ECIStringBuilder result = new ECIStringBuilder(100);
|
||||
StringBuilder resultTrailer = new StringBuilder(0);
|
||||
List<byte[]> byteSegments = new ArrayList<>(1);
|
||||
Mode mode = Mode.ASCII_ENCODE;
|
||||
|
@ -116,6 +118,7 @@ final class DecodedBitStreamParser {
|
|||
decodeBase256Segment(bits, result, byteSegments);
|
||||
break;
|
||||
case ECI_ENCODE:
|
||||
decodeECISegment(bits, result);
|
||||
isECIencoded = true; // ECI detection only, atm continue decoding as ASCII
|
||||
break;
|
||||
default:
|
||||
|
@ -158,7 +161,7 @@ final class DecodedBitStreamParser {
|
|||
* See ISO 16022:2006, 5.2.3 and Annex C, Table C.2
|
||||
*/
|
||||
private static Mode decodeAsciiSegment(BitSource bits,
|
||||
StringBuilder result,
|
||||
ECIStringBuilder result,
|
||||
StringBuilder resultTrailer,
|
||||
Set<Integer> fnc1positions) throws FormatException {
|
||||
boolean upperShift = false;
|
||||
|
@ -231,7 +234,7 @@ final class DecodedBitStreamParser {
|
|||
/**
|
||||
* See ISO 16022:2006, 5.2.5 and Annex C, Table C.1
|
||||
*/
|
||||
private static void decodeC40Segment(BitSource bits, StringBuilder result, Set<Integer> fnc1positions)
|
||||
private static void decodeC40Segment(BitSource bits, ECIStringBuilder result, Set<Integer> fnc1positions)
|
||||
throws FormatException {
|
||||
// Three C40 values are encoded in a 16-bit value as
|
||||
// (1600 * C1) + (40 * C2) + C3 + 1
|
||||
|
@ -323,7 +326,7 @@ final class DecodedBitStreamParser {
|
|||
/**
|
||||
* See ISO 16022:2006, 5.2.6 and Annex C, Table C.2
|
||||
*/
|
||||
private static void decodeTextSegment(BitSource bits, StringBuilder result, Set<Integer> fnc1positions)
|
||||
private static void decodeTextSegment(BitSource bits, ECIStringBuilder result, Set<Integer> fnc1positions)
|
||||
throws FormatException {
|
||||
// Three Text values are encoded in a 16-bit value as
|
||||
// (1600 * C1) + (40 * C2) + C3 + 1
|
||||
|
@ -421,7 +424,7 @@ final class DecodedBitStreamParser {
|
|||
* See ISO 16022:2006, 5.2.7
|
||||
*/
|
||||
private static void decodeAnsiX12Segment(BitSource bits,
|
||||
StringBuilder result) throws FormatException {
|
||||
ECIStringBuilder result) throws FormatException {
|
||||
// Three ANSI X12 values are encoded in a 16-bit value as
|
||||
// (1600 * C1) + (40 * C2) + C3 + 1
|
||||
|
||||
|
@ -480,7 +483,7 @@ final class DecodedBitStreamParser {
|
|||
/**
|
||||
* See ISO 16022:2006, 5.2.8 and Annex C Table C.3
|
||||
*/
|
||||
private static void decodeEdifactSegment(BitSource bits, StringBuilder result) {
|
||||
private static void decodeEdifactSegment(BitSource bits, ECIStringBuilder result) {
|
||||
do {
|
||||
// If there is only two or less bytes left then it will be encoded as ASCII
|
||||
if (bits.available() <= 16) {
|
||||
|
@ -512,7 +515,7 @@ final class DecodedBitStreamParser {
|
|||
* See ISO 16022:2006, 5.2.9 and Annex B, B.2
|
||||
*/
|
||||
private static void decodeBase256Segment(BitSource bits,
|
||||
StringBuilder result,
|
||||
ECIStringBuilder result,
|
||||
Collection<byte[]> byteSegments)
|
||||
throws FormatException {
|
||||
// Figure out how long the Base 256 Segment is.
|
||||
|
@ -545,6 +548,36 @@ final class DecodedBitStreamParser {
|
|||
result.append(new String(bytes, StandardCharsets.ISO_8859_1));
|
||||
}
|
||||
|
||||
/**
|
||||
* See ISO 16022:2007, 5.4.1
|
||||
*/
|
||||
private static void decodeECISegment(BitSource bits,
|
||||
ECIStringBuilder result)
|
||||
throws FormatException {
|
||||
if (bits.available() < 8) {
|
||||
throw FormatException.getFormatInstance();
|
||||
}
|
||||
int c1 = bits.readBits(8);
|
||||
if (c1 <= 127) {
|
||||
result.appendECI(c1 - 1);
|
||||
}
|
||||
//currently we only support character set ECIs
|
||||
/*} else {
|
||||
if (bits.available() < 8) {
|
||||
throw FormatException.getFormatInstance();
|
||||
}
|
||||
int c2 = bits.readBits(8);
|
||||
if (c1 >= 128 && c1 <= 191) {
|
||||
} else {
|
||||
if (bits.available() < 8) {
|
||||
throw FormatException.getFormatInstance();
|
||||
}
|
||||
int c3 = bits.readBits(8);
|
||||
}
|
||||
}*/
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* See ISO 16022:2006, Annex B, B.2
|
||||
*/
|
||||
|
@ -555,4 +588,70 @@ final class DecodedBitStreamParser {
|
|||
return tempVariable >= 0 ? tempVariable : tempVariable + 256;
|
||||
}
|
||||
|
||||
private static final class ECIStringBuilder {
|
||||
private StringBuilder currentBytes;
|
||||
private StringBuilder currentChars;
|
||||
private Charset currentCharset = StandardCharsets.ISO_8859_1;
|
||||
private String result = null;
|
||||
private boolean hadECI = false;
|
||||
|
||||
private ECIStringBuilder(int initialCapacity) {
|
||||
currentBytes = new StringBuilder(initialCapacity);
|
||||
}
|
||||
|
||||
private void append(char value) {
|
||||
currentBytes.append(value);
|
||||
}
|
||||
|
||||
private void append(String value) {
|
||||
currentBytes.append(value);
|
||||
}
|
||||
|
||||
private void append(int value) {
|
||||
currentBytes.append(value);
|
||||
}
|
||||
|
||||
private void appendECI(int value) throws FormatException {
|
||||
encodeCurrentBytesIfAny();
|
||||
CharacterSetECI characterSetECI = CharacterSetECI.getCharacterSetECIByValue(value);
|
||||
if (characterSetECI == null) {
|
||||
throw FormatException.getFormatInstance(new RuntimeException("Unsupported ECI value " + value));
|
||||
}
|
||||
currentCharset = characterSetECI.getCharset();
|
||||
}
|
||||
|
||||
private void encodeCurrentBytesIfAny() {
|
||||
if (!hadECI) {
|
||||
currentChars = currentBytes;
|
||||
currentBytes = new StringBuilder();
|
||||
hadECI = true;
|
||||
} else if (currentBytes.length() > 0) {
|
||||
byte[] bytes = new byte[currentBytes.length()];
|
||||
for (int i = 0; i < bytes.length; i++) {
|
||||
bytes[i] = (byte) (currentBytes.charAt(i) & 0xff);
|
||||
}
|
||||
currentChars.append(new String(bytes, currentCharset));
|
||||
currentBytes.setLength(0);
|
||||
}
|
||||
}
|
||||
|
||||
private void append(StringBuilder value) {
|
||||
encodeCurrentBytesIfAny();
|
||||
currentChars.append(value);
|
||||
}
|
||||
|
||||
/**
|
||||
* returns the length of toString()
|
||||
*/
|
||||
public int length() {
|
||||
return toString().length();
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
encodeCurrentBytesIfAny();
|
||||
result = result == null ? currentChars.toString() : result + currentChars.toString();
|
||||
currentChars.setLength(0);
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue