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:
AlexGeller1 2022-01-05 16:32:36 +01:00 committed by GitHub
parent 9b972bbb07
commit c4266bf09c
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23

View file

@ -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;
}
}
}