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.FormatException;
|
||||||
import com.google.zxing.common.BitSource;
|
import com.google.zxing.common.BitSource;
|
||||||
import com.google.zxing.common.DecoderResult;
|
import com.google.zxing.common.DecoderResult;
|
||||||
|
import com.google.zxing.common.CharacterSetECI;
|
||||||
|
|
||||||
import java.nio.charset.StandardCharsets;
|
import java.nio.charset.StandardCharsets;
|
||||||
|
import java.nio.charset.Charset;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
|
@ -87,7 +89,7 @@ final class DecodedBitStreamParser {
|
||||||
|
|
||||||
static DecoderResult decode(byte[] bytes) throws FormatException {
|
static DecoderResult decode(byte[] bytes) throws FormatException {
|
||||||
BitSource bits = new BitSource(bytes);
|
BitSource bits = new BitSource(bytes);
|
||||||
StringBuilder result = new StringBuilder(100);
|
ECIStringBuilder result = new ECIStringBuilder(100);
|
||||||
StringBuilder resultTrailer = new StringBuilder(0);
|
StringBuilder resultTrailer = new StringBuilder(0);
|
||||||
List<byte[]> byteSegments = new ArrayList<>(1);
|
List<byte[]> byteSegments = new ArrayList<>(1);
|
||||||
Mode mode = Mode.ASCII_ENCODE;
|
Mode mode = Mode.ASCII_ENCODE;
|
||||||
|
@ -116,6 +118,7 @@ final class DecodedBitStreamParser {
|
||||||
decodeBase256Segment(bits, result, byteSegments);
|
decodeBase256Segment(bits, result, byteSegments);
|
||||||
break;
|
break;
|
||||||
case ECI_ENCODE:
|
case ECI_ENCODE:
|
||||||
|
decodeECISegment(bits, result);
|
||||||
isECIencoded = true; // ECI detection only, atm continue decoding as ASCII
|
isECIencoded = true; // ECI detection only, atm continue decoding as ASCII
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
|
@ -158,7 +161,7 @@ final class DecodedBitStreamParser {
|
||||||
* See ISO 16022:2006, 5.2.3 and Annex C, Table C.2
|
* See ISO 16022:2006, 5.2.3 and Annex C, Table C.2
|
||||||
*/
|
*/
|
||||||
private static Mode decodeAsciiSegment(BitSource bits,
|
private static Mode decodeAsciiSegment(BitSource bits,
|
||||||
StringBuilder result,
|
ECIStringBuilder result,
|
||||||
StringBuilder resultTrailer,
|
StringBuilder resultTrailer,
|
||||||
Set<Integer> fnc1positions) throws FormatException {
|
Set<Integer> fnc1positions) throws FormatException {
|
||||||
boolean upperShift = false;
|
boolean upperShift = false;
|
||||||
|
@ -231,7 +234,7 @@ final class DecodedBitStreamParser {
|
||||||
/**
|
/**
|
||||||
* See ISO 16022:2006, 5.2.5 and Annex C, Table C.1
|
* 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 {
|
throws FormatException {
|
||||||
// Three C40 values are encoded in a 16-bit value as
|
// Three C40 values are encoded in a 16-bit value as
|
||||||
// (1600 * C1) + (40 * C2) + C3 + 1
|
// (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
|
* 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 {
|
throws FormatException {
|
||||||
// Three Text values are encoded in a 16-bit value as
|
// Three Text values are encoded in a 16-bit value as
|
||||||
// (1600 * C1) + (40 * C2) + C3 + 1
|
// (1600 * C1) + (40 * C2) + C3 + 1
|
||||||
|
@ -421,7 +424,7 @@ final class DecodedBitStreamParser {
|
||||||
* See ISO 16022:2006, 5.2.7
|
* See ISO 16022:2006, 5.2.7
|
||||||
*/
|
*/
|
||||||
private static void decodeAnsiX12Segment(BitSource bits,
|
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
|
// Three ANSI X12 values are encoded in a 16-bit value as
|
||||||
// (1600 * C1) + (40 * C2) + C3 + 1
|
// (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
|
* 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 {
|
do {
|
||||||
// If there is only two or less bytes left then it will be encoded as ASCII
|
// If there is only two or less bytes left then it will be encoded as ASCII
|
||||||
if (bits.available() <= 16) {
|
if (bits.available() <= 16) {
|
||||||
|
@ -512,7 +515,7 @@ final class DecodedBitStreamParser {
|
||||||
* See ISO 16022:2006, 5.2.9 and Annex B, B.2
|
* See ISO 16022:2006, 5.2.9 and Annex B, B.2
|
||||||
*/
|
*/
|
||||||
private static void decodeBase256Segment(BitSource bits,
|
private static void decodeBase256Segment(BitSource bits,
|
||||||
StringBuilder result,
|
ECIStringBuilder result,
|
||||||
Collection<byte[]> byteSegments)
|
Collection<byte[]> byteSegments)
|
||||||
throws FormatException {
|
throws FormatException {
|
||||||
// Figure out how long the Base 256 Segment is.
|
// 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));
|
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
|
* See ISO 16022:2006, Annex B, B.2
|
||||||
*/
|
*/
|
||||||
|
@ -555,4 +588,70 @@ final class DecodedBitStreamParser {
|
||||||
return tempVariable >= 0 ? tempVariable : tempVariable + 256;
|
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