mirror of
https://github.com/zxing/zxing.git
synced 2025-01-12 11:47:26 -08:00
Share the ECI string builder of the data matrix decoder with the PDF417 decoder (#1508)
* Shared the ECI string builder of the datamatrix decoder with the PDF417 decoder
This commit is contained in:
parent
ce1a1a53cf
commit
8265242784
124
core/src/main/java/com/google/zxing/common/ECIStringBuilder.java
Normal file
124
core/src/main/java/com/google/zxing/common/ECIStringBuilder.java
Normal file
|
@ -0,0 +1,124 @@
|
|||
/*
|
||||
* Copyright 2022 ZXing authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.google.zxing.common;
|
||||
|
||||
import com.google.zxing.FormatException;
|
||||
|
||||
import java.nio.charset.Charset;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
|
||||
/**
|
||||
* Class that converts a sequence of ECIs and bytes into a string
|
||||
*
|
||||
* @author Alex Geller
|
||||
*/
|
||||
public final class ECIStringBuilder {
|
||||
private StringBuilder currentBytes;
|
||||
private StringBuilder result;
|
||||
private Charset currentCharset = StandardCharsets.ISO_8859_1;
|
||||
|
||||
public ECIStringBuilder() {
|
||||
currentBytes = new StringBuilder();
|
||||
}
|
||||
public ECIStringBuilder(int initialCapacity) {
|
||||
currentBytes = new StringBuilder(initialCapacity);
|
||||
}
|
||||
|
||||
/**
|
||||
* Appends {@code value} as a byte value
|
||||
*/
|
||||
public void append(char value) {
|
||||
currentBytes.append((char) (value & 0xff));
|
||||
}
|
||||
|
||||
/**
|
||||
* Appends {@code value} as a byte value (not its string representation)
|
||||
*/
|
||||
public void append(byte value) {
|
||||
currentBytes.append((char) (value & 0xff));
|
||||
}
|
||||
|
||||
/**
|
||||
* Appends the characters in {@code value} as bytes values
|
||||
*/
|
||||
public void append(String value) {
|
||||
currentBytes.append(value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Append the string repesentation of {@code value} (short for {@code append(String.valueOf(value))})
|
||||
*/
|
||||
public void append(int value) {
|
||||
append(String.valueOf(value));
|
||||
}
|
||||
|
||||
public void appendECI(int value) throws FormatException {
|
||||
encodeCurrentBytesIfAny();
|
||||
CharacterSetECI characterSetECI = CharacterSetECI.getCharacterSetECIByValue(value);
|
||||
if (characterSetECI == null) {
|
||||
throw FormatException.getFormatInstance();
|
||||
}
|
||||
currentCharset = characterSetECI.getCharset();
|
||||
}
|
||||
|
||||
private void encodeCurrentBytesIfAny() {
|
||||
if (currentCharset.equals(StandardCharsets.ISO_8859_1)) {
|
||||
if (currentBytes.length() > 0) {
|
||||
if (result == null) {
|
||||
result = currentBytes;
|
||||
currentBytes = new StringBuilder();
|
||||
} else {
|
||||
result.append(currentBytes);
|
||||
currentBytes = new StringBuilder();
|
||||
}
|
||||
}
|
||||
} else if (currentBytes.length() > 0) {
|
||||
byte[] bytes = currentBytes.toString().getBytes(StandardCharsets.ISO_8859_1);
|
||||
currentBytes = new StringBuilder();
|
||||
if (result == null) {
|
||||
result = new StringBuilder(new String(bytes, currentCharset));
|
||||
} else {
|
||||
result.append(new String(bytes, currentCharset));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Appends the characters from {@code value} (unlike all other append methods of this class who append bytes)
|
||||
*/
|
||||
public void appendCharacters(StringBuilder value) {
|
||||
encodeCurrentBytesIfAny();
|
||||
result.append(value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Short for {@code toString().length()} (if possible, use {@link #isEmpty()} instead)
|
||||
*/
|
||||
public int length() {
|
||||
return toString().length();
|
||||
}
|
||||
|
||||
public boolean isEmpty() {
|
||||
return currentBytes.length() == 0 && (result == null || result.length() == 0);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
encodeCurrentBytesIfAny();
|
||||
return result == null ? "" : result.toString();
|
||||
}
|
||||
}
|
|
@ -19,10 +19,9 @@ 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 com.google.zxing.common.ECIStringBuilder;
|
||||
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.nio.charset.Charset;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.HashSet;
|
||||
|
@ -128,7 +127,7 @@ final class DecodedBitStreamParser {
|
|||
}
|
||||
} while (mode != Mode.PAD_ENCODE && bits.available() > 0);
|
||||
if (resultTrailer.length() > 0) {
|
||||
result.append(resultTrailer);
|
||||
result.appendCharacters(resultTrailer);
|
||||
}
|
||||
if (isECIencoded) {
|
||||
// Examples for this numbers can be found in this documentation of a hardware barcode scanner:
|
||||
|
@ -588,70 +587,4 @@ 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -17,14 +17,12 @@
|
|||
package com.google.zxing.pdf417.decoder;
|
||||
|
||||
import com.google.zxing.FormatException;
|
||||
import com.google.zxing.common.CharacterSetECI;
|
||||
import com.google.zxing.common.ECIStringBuilder;
|
||||
import com.google.zxing.common.DecoderResult;
|
||||
import com.google.zxing.pdf417.PDF417ResultMetadata;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.math.BigInteger;
|
||||
import java.util.Arrays;
|
||||
import java.io.UnsupportedEncodingException;
|
||||
|
||||
/**
|
||||
* <p>This class contains the methods for decoding the PDF417 codewords.</p>
|
||||
|
@ -100,7 +98,7 @@ final class DecodedBitStreamParser {
|
|||
}
|
||||
|
||||
static DecoderResult decode(int[] codewords, String ecLevel) throws FormatException {
|
||||
ECIOutput result = new ECIOutput(codewords.length * 2);
|
||||
ECIStringBuilder result = new ECIStringBuilder(codewords.length * 2);
|
||||
int codeIndex = textCompaction(codewords, 1, result);
|
||||
PDF417ResultMetadata resultMetadata = new PDF417ResultMetadata();
|
||||
while (codeIndex < codewords[0]) {
|
||||
|
@ -205,37 +203,37 @@ final class DecodedBitStreamParser {
|
|||
codeIndex++;
|
||||
switch (codewords[codeIndex]) {
|
||||
case MACRO_PDF417_OPTIONAL_FIELD_FILE_NAME:
|
||||
ECIOutput fileName = new ECIOutput();
|
||||
ECIStringBuilder fileName = new ECIStringBuilder();
|
||||
codeIndex = textCompaction(codewords, codeIndex + 1, fileName);
|
||||
resultMetadata.setFileName(fileName.toString());
|
||||
break;
|
||||
case MACRO_PDF417_OPTIONAL_FIELD_SENDER:
|
||||
ECIOutput sender = new ECIOutput();
|
||||
ECIStringBuilder sender = new ECIStringBuilder();
|
||||
codeIndex = textCompaction(codewords, codeIndex + 1, sender);
|
||||
resultMetadata.setSender(sender.toString());
|
||||
break;
|
||||
case MACRO_PDF417_OPTIONAL_FIELD_ADDRESSEE:
|
||||
ECIOutput addressee = new ECIOutput();
|
||||
ECIStringBuilder addressee = new ECIStringBuilder();
|
||||
codeIndex = textCompaction(codewords, codeIndex + 1, addressee);
|
||||
resultMetadata.setAddressee(addressee.toString());
|
||||
break;
|
||||
case MACRO_PDF417_OPTIONAL_FIELD_SEGMENT_COUNT:
|
||||
ECIOutput segmentCount = new ECIOutput();
|
||||
ECIStringBuilder segmentCount = new ECIStringBuilder();
|
||||
codeIndex = numericCompaction(codewords, codeIndex + 1, segmentCount);
|
||||
resultMetadata.setSegmentCount(Integer.parseInt(segmentCount.toString()));
|
||||
break;
|
||||
case MACRO_PDF417_OPTIONAL_FIELD_TIME_STAMP:
|
||||
ECIOutput timestamp = new ECIOutput();
|
||||
ECIStringBuilder timestamp = new ECIStringBuilder();
|
||||
codeIndex = numericCompaction(codewords, codeIndex + 1, timestamp);
|
||||
resultMetadata.setTimestamp(Long.parseLong(timestamp.toString()));
|
||||
break;
|
||||
case MACRO_PDF417_OPTIONAL_FIELD_CHECKSUM:
|
||||
ECIOutput checksum = new ECIOutput();
|
||||
ECIStringBuilder checksum = new ECIStringBuilder();
|
||||
codeIndex = numericCompaction(codewords, codeIndex + 1, checksum);
|
||||
resultMetadata.setChecksum(Integer.parseInt(checksum.toString()));
|
||||
break;
|
||||
case MACRO_PDF417_OPTIONAL_FIELD_FILE_SIZE:
|
||||
ECIOutput fileSize = new ECIOutput();
|
||||
ECIStringBuilder fileSize = new ECIStringBuilder();
|
||||
codeIndex = numericCompaction(codewords, codeIndex + 1, fileSize);
|
||||
resultMetadata.setFileSize(Long.parseLong(fileSize.toString()));
|
||||
break;
|
||||
|
@ -276,7 +274,7 @@ final class DecodedBitStreamParser {
|
|||
* @param result The decoded data is appended to the result.
|
||||
* @return The next index into the codeword array.
|
||||
*/
|
||||
private static int textCompaction(int[] codewords, int codeIndex, ECIOutput result) throws FormatException {
|
||||
private static int textCompaction(int[] codewords, int codeIndex, ECIStringBuilder result) throws FormatException {
|
||||
// 2 character per codeword
|
||||
int[] textCompactionData = new int[(codewords[0] - codeIndex) * 2];
|
||||
// Used to hold the byte compaction value if there is a mode shift
|
||||
|
@ -353,7 +351,7 @@ final class DecodedBitStreamParser {
|
|||
private static Mode decodeTextCompaction(int[] textCompactionData,
|
||||
int[] byteCompactionData,
|
||||
int length,
|
||||
ECIOutput result,
|
||||
ECIStringBuilder result,
|
||||
Mode startMode) {
|
||||
// Beginning from an initial state
|
||||
// The default compaction mode for PDF417 in effect at the start of each symbol shall always be Text
|
||||
|
@ -547,7 +545,7 @@ final class DecodedBitStreamParser {
|
|||
private static int byteCompaction(int mode,
|
||||
int[] codewords,
|
||||
int codeIndex,
|
||||
ECIOutput result) throws FormatException {
|
||||
ECIStringBuilder result) throws FormatException {
|
||||
boolean end = false;
|
||||
|
||||
while (codeIndex < codewords[0] && !end) {
|
||||
|
@ -602,7 +600,7 @@ final class DecodedBitStreamParser {
|
|||
* @param result The decoded data is appended to the result.
|
||||
* @return The next index into the codeword array.
|
||||
*/
|
||||
private static int numericCompaction(int[] codewords, int codeIndex, ECIOutput result) throws FormatException {
|
||||
private static int numericCompaction(int[] codewords, int codeIndex, ECIStringBuilder result) throws FormatException {
|
||||
int count = 0;
|
||||
boolean end = false;
|
||||
|
||||
|
@ -697,67 +695,4 @@ final class DecodedBitStreamParser {
|
|||
return resultString.substring(1);
|
||||
}
|
||||
|
||||
private static final class ECIOutput {
|
||||
private boolean needFlush = false;
|
||||
private String encodingName = "ISO-8859-1";
|
||||
private ByteArrayOutputStream bytes = new ByteArrayOutputStream();
|
||||
private StringBuilder result;
|
||||
|
||||
private ECIOutput() {
|
||||
result = new StringBuilder();
|
||||
}
|
||||
|
||||
private ECIOutput(int size) {
|
||||
result = new StringBuilder(size);
|
||||
}
|
||||
|
||||
private void append(byte value) {
|
||||
bytes.write(value);
|
||||
needFlush = true;
|
||||
}
|
||||
|
||||
private void append(char value) {
|
||||
bytes.write(value & 0xff);
|
||||
needFlush = true;
|
||||
}
|
||||
|
||||
private void append(String s) {
|
||||
for (int i = 0; i < s.length(); i++) {
|
||||
append(s.charAt(i));
|
||||
}
|
||||
}
|
||||
|
||||
private void appendECI(int value) throws FormatException {
|
||||
flush();
|
||||
bytes = new ByteArrayOutputStream();
|
||||
CharacterSetECI charsetECI = CharacterSetECI.getCharacterSetECIByValue(value);
|
||||
if (charsetECI == null) {
|
||||
throw FormatException.getFormatInstance();
|
||||
}
|
||||
encodingName = charsetECI.name();
|
||||
}
|
||||
|
||||
private void flush() {
|
||||
if (needFlush) {
|
||||
needFlush = false;
|
||||
try {
|
||||
result.append(bytes.toString(encodingName));
|
||||
} catch (UnsupportedEncodingException uee) {
|
||||
// can't happen
|
||||
throw new IllegalStateException(uee);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isEmpty() {
|
||||
return !needFlush && result.length() == 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
flush();
|
||||
return result.toString();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue