mirror of
https://github.com/starovoid/rxing.git
synced 2026-07-26 04:12:34 +00:00
parser builds
This commit is contained in:
@@ -33,8 +33,8 @@ pub struct DecoderRXingResult {
|
||||
text: String,
|
||||
byteSegments: Vec<Vec<u8>>,
|
||||
ecLevel: String,
|
||||
errorsCorrected: u64,
|
||||
erasures: u64,
|
||||
errorsCorrected: usize,
|
||||
erasures: usize,
|
||||
other: Rc<dyn Any>,
|
||||
structuredAppendParity: i32,
|
||||
structuredAppendSequenceNumber: i32,
|
||||
@@ -160,22 +160,22 @@ impl DecoderRXingResult {
|
||||
/**
|
||||
* @return number of errors corrected, or {@code null} if not applicable
|
||||
*/
|
||||
pub fn getErrorsCorrected(&self) -> u64 {
|
||||
pub fn getErrorsCorrected(&self) -> usize {
|
||||
self.errorsCorrected
|
||||
}
|
||||
|
||||
pub fn setErrorsCorrected(&mut self, errorsCorrected: u64) {
|
||||
pub fn setErrorsCorrected(&mut self, errorsCorrected: usize) {
|
||||
self.errorsCorrected = errorsCorrected;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return number of erasures corrected, or {@code null} if not applicable
|
||||
*/
|
||||
pub fn getErasures(&self) -> u64 {
|
||||
pub fn getErasures(&self) -> usize {
|
||||
self.erasures
|
||||
}
|
||||
|
||||
pub fn setErasures(&mut self, erasures: u64) {
|
||||
pub fn setErasures(&mut self, erasures: usize) {
|
||||
self.erasures = erasures
|
||||
}
|
||||
|
||||
|
||||
@@ -1,171 +0,0 @@
|
||||
/*
|
||||
* Copyright 2013 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.pdf417;
|
||||
|
||||
/**
|
||||
* @author Guenther Grau
|
||||
*/
|
||||
public final class PDF417RXingResultMetadata {
|
||||
|
||||
private int segmentIndex;
|
||||
private String fileId;
|
||||
private boolean lastSegment;
|
||||
private int segmentCount = -1;
|
||||
private String sender;
|
||||
private String addressee;
|
||||
private String fileName;
|
||||
private long fileSize = -1;
|
||||
private long timestamp = -1;
|
||||
private int checksum = -1;
|
||||
private int[] optionalData;
|
||||
|
||||
/**
|
||||
* The Segment ID represents the segment of the whole file distributed over different symbols.
|
||||
*
|
||||
* @return File segment index
|
||||
*/
|
||||
public int getSegmentIndex() {
|
||||
return segmentIndex;
|
||||
}
|
||||
|
||||
public void setSegmentIndex(int segmentIndex) {
|
||||
this.segmentIndex = segmentIndex;
|
||||
}
|
||||
|
||||
/**
|
||||
* Is the same for each related PDF417 symbol
|
||||
*
|
||||
* @return File ID
|
||||
*/
|
||||
public String getFileId() {
|
||||
return fileId;
|
||||
}
|
||||
|
||||
public void setFileId(String fileId) {
|
||||
this.fileId = fileId;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return always null
|
||||
* @deprecated use dedicated already parsed fields
|
||||
*/
|
||||
@Deprecated
|
||||
public int[] getOptionalData() {
|
||||
return optionalData;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param optionalData old optional data format as int array
|
||||
* @deprecated parse and use new fields
|
||||
*/
|
||||
@Deprecated
|
||||
public void setOptionalData(int[] optionalData) {
|
||||
this.optionalData = optionalData;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return true if it is the last segment
|
||||
*/
|
||||
public boolean isLastSegment() {
|
||||
return lastSegment;
|
||||
}
|
||||
|
||||
public void setLastSegment(boolean lastSegment) {
|
||||
this.lastSegment = lastSegment;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return count of segments, -1 if not set
|
||||
*/
|
||||
public int getSegmentCount() {
|
||||
return segmentCount;
|
||||
}
|
||||
|
||||
public void setSegmentCount(int segmentCount) {
|
||||
this.segmentCount = segmentCount;
|
||||
}
|
||||
|
||||
public String getSender() {
|
||||
return sender;
|
||||
}
|
||||
|
||||
public void setSender(String sender) {
|
||||
this.sender = sender;
|
||||
}
|
||||
|
||||
public String getAddressee() {
|
||||
return addressee;
|
||||
}
|
||||
|
||||
public void setAddressee(String addressee) {
|
||||
this.addressee = addressee;
|
||||
}
|
||||
|
||||
/**
|
||||
* Filename of the encoded file
|
||||
*
|
||||
* @return filename
|
||||
*/
|
||||
public String getFileName() {
|
||||
return fileName;
|
||||
}
|
||||
|
||||
public void setFileName(String fileName) {
|
||||
this.fileName = fileName;
|
||||
}
|
||||
|
||||
/**
|
||||
* filesize in bytes of the encoded file
|
||||
*
|
||||
* @return filesize in bytes, -1 if not set
|
||||
*/
|
||||
public long getFileSize() {
|
||||
return fileSize;
|
||||
}
|
||||
|
||||
public void setFileSize(long fileSize) {
|
||||
this.fileSize = fileSize;
|
||||
}
|
||||
|
||||
/**
|
||||
* 16-bit CRC checksum using CCITT-16
|
||||
*
|
||||
* @return crc checksum, -1 if not set
|
||||
*/
|
||||
public int getChecksum() {
|
||||
return checksum;
|
||||
}
|
||||
|
||||
public void setChecksum(int checksum) {
|
||||
this.checksum = checksum;
|
||||
}
|
||||
|
||||
/**
|
||||
* unix epock timestamp, elapsed seconds since 1970-01-01
|
||||
*
|
||||
* @return elapsed seconds, -1 if not set
|
||||
*/
|
||||
public long getTimestamp() {
|
||||
return timestamp;
|
||||
}
|
||||
|
||||
public void setTimestamp(long timestamp) {
|
||||
this.timestamp = timestamp;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,698 +0,0 @@
|
||||
/*
|
||||
* Copyright 2009 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.pdf417.decoder;
|
||||
|
||||
import com.google.zxing.FormatException;
|
||||
import com.google.zxing.common.ECIStringBuilder;
|
||||
import com.google.zxing.common.DecoderRXingResult;
|
||||
import com.google.zxing.pdf417.PDF417RXingResultMetadata;
|
||||
|
||||
import java.math.BigInteger;
|
||||
import java.util.Arrays;
|
||||
|
||||
/**
|
||||
* <p>This class contains the methods for decoding the PDF417 codewords.</p>
|
||||
*
|
||||
* @author SITA Lab (kevin.osullivan@sita.aero)
|
||||
* @author Guenther Grau
|
||||
*/
|
||||
final class DecodedBitStreamParser {
|
||||
|
||||
private enum Mode {
|
||||
ALPHA,
|
||||
LOWER,
|
||||
MIXED,
|
||||
PUNCT,
|
||||
ALPHA_SHIFT,
|
||||
PUNCT_SHIFT
|
||||
}
|
||||
|
||||
private static final int TEXT_COMPACTION_MODE_LATCH = 900;
|
||||
private static final int BYTE_COMPACTION_MODE_LATCH = 901;
|
||||
private static final int NUMERIC_COMPACTION_MODE_LATCH = 902;
|
||||
private static final int BYTE_COMPACTION_MODE_LATCH_6 = 924;
|
||||
private static final int ECI_USER_DEFINED = 925;
|
||||
private static final int ECI_GENERAL_PURPOSE = 926;
|
||||
private static final int ECI_CHARSET = 927;
|
||||
private static final int BEGIN_MACRO_PDF417_CONTROL_BLOCK = 928;
|
||||
private static final int BEGIN_MACRO_PDF417_OPTIONAL_FIELD = 923;
|
||||
private static final int MACRO_PDF417_TERMINATOR = 922;
|
||||
private static final int MODE_SHIFT_TO_BYTE_COMPACTION_MODE = 913;
|
||||
private static final int MAX_NUMERIC_CODEWORDS = 15;
|
||||
|
||||
private static final int MACRO_PDF417_OPTIONAL_FIELD_FILE_NAME = 0;
|
||||
private static final int MACRO_PDF417_OPTIONAL_FIELD_SEGMENT_COUNT = 1;
|
||||
private static final int MACRO_PDF417_OPTIONAL_FIELD_TIME_STAMP = 2;
|
||||
private static final int MACRO_PDF417_OPTIONAL_FIELD_SENDER = 3;
|
||||
private static final int MACRO_PDF417_OPTIONAL_FIELD_ADDRESSEE = 4;
|
||||
private static final int MACRO_PDF417_OPTIONAL_FIELD_FILE_SIZE = 5;
|
||||
private static final int MACRO_PDF417_OPTIONAL_FIELD_CHECKSUM = 6;
|
||||
|
||||
private static final int PL = 25;
|
||||
private static final int LL = 27;
|
||||
private static final int AS = 27;
|
||||
private static final int ML = 28;
|
||||
private static final int AL = 28;
|
||||
private static final int PS = 29;
|
||||
private static final int PAL = 29;
|
||||
|
||||
private static final char[] PUNCT_CHARS =
|
||||
";<>@[\\]_`~!\r\t,:\n-.$/\"|*()?{}'".toCharArray();
|
||||
|
||||
private static final char[] MIXED_CHARS =
|
||||
"0123456789&\r\t,:#-.$/+%*=^".toCharArray();
|
||||
|
||||
/**
|
||||
* Table containing values for the exponent of 900.
|
||||
* This is used in the numeric compaction decode algorithm.
|
||||
*/
|
||||
private static final BigInteger[] EXP900;
|
||||
|
||||
static {
|
||||
EXP900 = new BigInteger[16];
|
||||
EXP900[0] = BigInteger.ONE;
|
||||
BigInteger nineHundred = BigInteger.valueOf(900);
|
||||
EXP900[1] = nineHundred;
|
||||
for (int i = 2; i < EXP900.length; i++) {
|
||||
EXP900[i] = EXP900[i - 1].multiply(nineHundred);
|
||||
}
|
||||
}
|
||||
|
||||
private static final int NUMBER_OF_SEQUENCE_CODEWORDS = 2;
|
||||
|
||||
private DecodedBitStreamParser() {
|
||||
}
|
||||
|
||||
static DecoderRXingResult decode(int[] codewords, String ecLevel) throws FormatException {
|
||||
ECIStringBuilder result = new ECIStringBuilder(codewords.length * 2);
|
||||
int codeIndex = textCompaction(codewords, 1, result);
|
||||
PDF417RXingResultMetadata resultMetadata = new PDF417RXingResultMetadata();
|
||||
while (codeIndex < codewords[0]) {
|
||||
int code = codewords[codeIndex++];
|
||||
switch (code) {
|
||||
case TEXT_COMPACTION_MODE_LATCH:
|
||||
codeIndex = textCompaction(codewords, codeIndex, result);
|
||||
break;
|
||||
case BYTE_COMPACTION_MODE_LATCH:
|
||||
case BYTE_COMPACTION_MODE_LATCH_6:
|
||||
codeIndex = byteCompaction(code, codewords, codeIndex, result);
|
||||
break;
|
||||
case MODE_SHIFT_TO_BYTE_COMPACTION_MODE:
|
||||
result.append((char) codewords[codeIndex++]);
|
||||
break;
|
||||
case NUMERIC_COMPACTION_MODE_LATCH:
|
||||
codeIndex = numericCompaction(codewords, codeIndex, result);
|
||||
break;
|
||||
case ECI_CHARSET:
|
||||
result.appendECI(codewords[codeIndex++]);
|
||||
break;
|
||||
case ECI_GENERAL_PURPOSE:
|
||||
// Can't do anything with generic ECI; skip its 2 characters
|
||||
codeIndex += 2;
|
||||
break;
|
||||
case ECI_USER_DEFINED:
|
||||
// Can't do anything with user ECI; skip its 1 character
|
||||
codeIndex++;
|
||||
break;
|
||||
case BEGIN_MACRO_PDF417_CONTROL_BLOCK:
|
||||
codeIndex = decodeMacroBlock(codewords, codeIndex, resultMetadata);
|
||||
break;
|
||||
case BEGIN_MACRO_PDF417_OPTIONAL_FIELD:
|
||||
case MACRO_PDF417_TERMINATOR:
|
||||
// Should not see these outside a macro block
|
||||
throw FormatException.getFormatInstance();
|
||||
default:
|
||||
// Default to text compaction. During testing numerous barcodes
|
||||
// appeared to be missing the starting mode. In these cases defaulting
|
||||
// to text compaction seems to work.
|
||||
codeIndex--;
|
||||
codeIndex = textCompaction(codewords, codeIndex, result);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (result.isEmpty() && resultMetadata.getFileId() == null) {
|
||||
throw FormatException.getFormatInstance();
|
||||
}
|
||||
DecoderRXingResult decoderRXingResult = new DecoderRXingResult(null, result.toString(), null, ecLevel);
|
||||
decoderRXingResult.setOther(resultMetadata);
|
||||
return decoderRXingResult;
|
||||
}
|
||||
|
||||
@SuppressWarnings("deprecation")
|
||||
static int decodeMacroBlock(int[] codewords, int codeIndex, PDF417RXingResultMetadata resultMetadata)
|
||||
throws FormatException {
|
||||
if (codeIndex + NUMBER_OF_SEQUENCE_CODEWORDS > codewords[0]) {
|
||||
// we must have at least two bytes left for the segment index
|
||||
throw FormatException.getFormatInstance();
|
||||
}
|
||||
int[] segmentIndexArray = new int[NUMBER_OF_SEQUENCE_CODEWORDS];
|
||||
for (int i = 0; i < NUMBER_OF_SEQUENCE_CODEWORDS; i++, codeIndex++) {
|
||||
segmentIndexArray[i] = codewords[codeIndex];
|
||||
}
|
||||
String segmentIndexString = decodeBase900toBase10(segmentIndexArray, NUMBER_OF_SEQUENCE_CODEWORDS);
|
||||
if (segmentIndexString.isEmpty()) {
|
||||
resultMetadata.setSegmentIndex(0);
|
||||
} else {
|
||||
try {
|
||||
resultMetadata.setSegmentIndex(Integer.parseInt(segmentIndexString));
|
||||
} catch (NumberFormatException nfe) {
|
||||
// too large; bad input?
|
||||
throw FormatException.getFormatInstance();
|
||||
}
|
||||
}
|
||||
|
||||
// Decoding the fileId codewords as 0-899 numbers, each 0-filled to width 3. This follows the spec
|
||||
// (See ISO/IEC 15438:2015 Annex H.6) and preserves all info, but some generators (e.g. TEC-IT) write
|
||||
// the fileId using text compaction, so in those cases the fileId will appear mangled.
|
||||
StringBuilder fileId = new StringBuilder();
|
||||
while (codeIndex < codewords[0] &&
|
||||
codeIndex < codewords.length &&
|
||||
codewords[codeIndex] != MACRO_PDF417_TERMINATOR &&
|
||||
codewords[codeIndex] != BEGIN_MACRO_PDF417_OPTIONAL_FIELD) {
|
||||
fileId.append(String.format("%03d", codewords[codeIndex]));
|
||||
codeIndex++;
|
||||
}
|
||||
if (fileId.length() == 0) {
|
||||
// at least one fileId codeword is required (Annex H.2)
|
||||
throw FormatException.getFormatInstance();
|
||||
}
|
||||
resultMetadata.setFileId(fileId.toString());
|
||||
|
||||
int optionalFieldsStart = -1;
|
||||
if (codewords[codeIndex] == BEGIN_MACRO_PDF417_OPTIONAL_FIELD) {
|
||||
optionalFieldsStart = codeIndex + 1;
|
||||
}
|
||||
|
||||
while (codeIndex < codewords[0]) {
|
||||
switch (codewords[codeIndex]) {
|
||||
case BEGIN_MACRO_PDF417_OPTIONAL_FIELD:
|
||||
codeIndex++;
|
||||
switch (codewords[codeIndex]) {
|
||||
case MACRO_PDF417_OPTIONAL_FIELD_FILE_NAME:
|
||||
ECIStringBuilder fileName = new ECIStringBuilder();
|
||||
codeIndex = textCompaction(codewords, codeIndex + 1, fileName);
|
||||
resultMetadata.setFileName(fileName.toString());
|
||||
break;
|
||||
case MACRO_PDF417_OPTIONAL_FIELD_SENDER:
|
||||
ECIStringBuilder sender = new ECIStringBuilder();
|
||||
codeIndex = textCompaction(codewords, codeIndex + 1, sender);
|
||||
resultMetadata.setSender(sender.toString());
|
||||
break;
|
||||
case MACRO_PDF417_OPTIONAL_FIELD_ADDRESSEE:
|
||||
ECIStringBuilder addressee = new ECIStringBuilder();
|
||||
codeIndex = textCompaction(codewords, codeIndex + 1, addressee);
|
||||
resultMetadata.setAddressee(addressee.toString());
|
||||
break;
|
||||
case MACRO_PDF417_OPTIONAL_FIELD_SEGMENT_COUNT:
|
||||
ECIStringBuilder segmentCount = new ECIStringBuilder();
|
||||
codeIndex = numericCompaction(codewords, codeIndex + 1, segmentCount);
|
||||
resultMetadata.setSegmentCount(Integer.parseInt(segmentCount.toString()));
|
||||
break;
|
||||
case MACRO_PDF417_OPTIONAL_FIELD_TIME_STAMP:
|
||||
ECIStringBuilder timestamp = new ECIStringBuilder();
|
||||
codeIndex = numericCompaction(codewords, codeIndex + 1, timestamp);
|
||||
resultMetadata.setTimestamp(Long.parseLong(timestamp.toString()));
|
||||
break;
|
||||
case MACRO_PDF417_OPTIONAL_FIELD_CHECKSUM:
|
||||
ECIStringBuilder checksum = new ECIStringBuilder();
|
||||
codeIndex = numericCompaction(codewords, codeIndex + 1, checksum);
|
||||
resultMetadata.setChecksum(Integer.parseInt(checksum.toString()));
|
||||
break;
|
||||
case MACRO_PDF417_OPTIONAL_FIELD_FILE_SIZE:
|
||||
ECIStringBuilder fileSize = new ECIStringBuilder();
|
||||
codeIndex = numericCompaction(codewords, codeIndex + 1, fileSize);
|
||||
resultMetadata.setFileSize(Long.parseLong(fileSize.toString()));
|
||||
break;
|
||||
default:
|
||||
throw FormatException.getFormatInstance();
|
||||
}
|
||||
break;
|
||||
case MACRO_PDF417_TERMINATOR:
|
||||
codeIndex++;
|
||||
resultMetadata.setLastSegment(true);
|
||||
break;
|
||||
default:
|
||||
throw FormatException.getFormatInstance();
|
||||
}
|
||||
}
|
||||
|
||||
// copy optional fields to additional options
|
||||
if (optionalFieldsStart != -1) {
|
||||
int optionalFieldsLength = codeIndex - optionalFieldsStart;
|
||||
if (resultMetadata.isLastSegment()) {
|
||||
// do not include terminator
|
||||
optionalFieldsLength--;
|
||||
}
|
||||
resultMetadata.setOptionalData(
|
||||
Arrays.copyOfRange(codewords, optionalFieldsStart, optionalFieldsStart + optionalFieldsLength));
|
||||
}
|
||||
|
||||
return codeIndex;
|
||||
}
|
||||
|
||||
/**
|
||||
* Text Compaction mode (see 5.4.1.5) permits all printable ASCII characters to be
|
||||
* encoded, i.e. values 32 - 126 inclusive in accordance with ISO/IEC 646 (IRV), as
|
||||
* well as selected control characters.
|
||||
*
|
||||
* @param codewords The array of codewords (data + error)
|
||||
* @param codeIndex The current index into the codeword array.
|
||||
* @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, 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
|
||||
int[] byteCompactionData = new int[(codewords[0] - codeIndex) * 2];
|
||||
|
||||
int index = 0;
|
||||
boolean end = false;
|
||||
Mode subMode = Mode.ALPHA;
|
||||
while ((codeIndex < codewords[0]) && !end) {
|
||||
int code = codewords[codeIndex++];
|
||||
if (code < TEXT_COMPACTION_MODE_LATCH) {
|
||||
textCompactionData[index] = code / 30;
|
||||
textCompactionData[index + 1] = code % 30;
|
||||
index += 2;
|
||||
} else {
|
||||
switch (code) {
|
||||
case TEXT_COMPACTION_MODE_LATCH:
|
||||
// reinitialize text compaction mode to alpha sub mode
|
||||
textCompactionData[index++] = TEXT_COMPACTION_MODE_LATCH;
|
||||
break;
|
||||
case BYTE_COMPACTION_MODE_LATCH:
|
||||
case BYTE_COMPACTION_MODE_LATCH_6:
|
||||
case NUMERIC_COMPACTION_MODE_LATCH:
|
||||
case BEGIN_MACRO_PDF417_CONTROL_BLOCK:
|
||||
case BEGIN_MACRO_PDF417_OPTIONAL_FIELD:
|
||||
case MACRO_PDF417_TERMINATOR:
|
||||
codeIndex--;
|
||||
end = true;
|
||||
break;
|
||||
case MODE_SHIFT_TO_BYTE_COMPACTION_MODE:
|
||||
// The Mode Shift codeword 913 shall cause a temporary
|
||||
// switch from Text Compaction mode to Byte Compaction mode.
|
||||
// This switch shall be in effect for only the next codeword,
|
||||
// after which the mode shall revert to the prevailing sub-mode
|
||||
// of the Text Compaction mode. Codeword 913 is only available
|
||||
// in Text Compaction mode; its use is described in 5.4.2.4.
|
||||
textCompactionData[index] = MODE_SHIFT_TO_BYTE_COMPACTION_MODE;
|
||||
code = codewords[codeIndex++];
|
||||
byteCompactionData[index] = code;
|
||||
index++;
|
||||
break;
|
||||
case ECI_CHARSET:
|
||||
subMode = decodeTextCompaction(textCompactionData, byteCompactionData, index, result, subMode);
|
||||
result.appendECI(codewords[codeIndex++]);
|
||||
textCompactionData = new int[(codewords[0] - codeIndex) * 2];
|
||||
byteCompactionData = new int[(codewords[0] - codeIndex) * 2];
|
||||
index = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
decodeTextCompaction(textCompactionData, byteCompactionData, index, result, subMode);
|
||||
return codeIndex;
|
||||
}
|
||||
|
||||
/**
|
||||
* The Text Compaction mode includes all the printable ASCII characters
|
||||
* (i.e. values from 32 to 126) and three ASCII control characters: HT or tab
|
||||
* (ASCII value 9), LF or line feed (ASCII value 10), and CR or carriage
|
||||
* return (ASCII value 13). The Text Compaction mode also includes various latch
|
||||
* and shift characters which are used exclusively within the mode. The Text
|
||||
* Compaction mode encodes up to 2 characters per codeword. The compaction rules
|
||||
* for converting data into PDF417 codewords are defined in 5.4.2.2. The sub-mode
|
||||
* switches are defined in 5.4.2.3.
|
||||
*
|
||||
* @param textCompactionData The text compaction data.
|
||||
* @param byteCompactionData The byte compaction data if there
|
||||
* was a mode shift.
|
||||
* @param length The size of the text compaction and byte compaction data.
|
||||
* @param result The decoded data is appended to the result.
|
||||
* @param startMode The mode in which decoding starts
|
||||
* @return The mode in which decoding ended
|
||||
*/
|
||||
private static Mode decodeTextCompaction(int[] textCompactionData,
|
||||
int[] byteCompactionData,
|
||||
int length,
|
||||
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
|
||||
// Compaction mode Alpha sub-mode (uppercase alphabetic). A latch codeword from another mode to the Text
|
||||
// Compaction mode shall always switch to the Text Compaction Alpha sub-mode.
|
||||
Mode subMode = startMode;
|
||||
Mode priorToShiftMode = startMode;
|
||||
Mode latchedMode = startMode;
|
||||
int i = 0;
|
||||
while (i < length) {
|
||||
int subModeCh = textCompactionData[i];
|
||||
char ch = 0;
|
||||
switch (subMode) {
|
||||
case ALPHA:
|
||||
// Alpha (uppercase alphabetic)
|
||||
if (subModeCh < 26) {
|
||||
// Upper case Alpha Character
|
||||
ch = (char) ('A' + subModeCh);
|
||||
} else {
|
||||
switch (subModeCh) {
|
||||
case 26:
|
||||
ch = ' ';
|
||||
break;
|
||||
case LL:
|
||||
subMode = Mode.LOWER;
|
||||
latchedMode = subMode;
|
||||
break;
|
||||
case ML:
|
||||
subMode = Mode.MIXED;
|
||||
latchedMode = subMode;
|
||||
break;
|
||||
case PS:
|
||||
// Shift to punctuation
|
||||
priorToShiftMode = subMode;
|
||||
subMode = Mode.PUNCT_SHIFT;
|
||||
break;
|
||||
case MODE_SHIFT_TO_BYTE_COMPACTION_MODE:
|
||||
result.append((char) byteCompactionData[i]);
|
||||
break;
|
||||
case TEXT_COMPACTION_MODE_LATCH:
|
||||
subMode = Mode.ALPHA;
|
||||
latchedMode = subMode;
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case LOWER:
|
||||
// Lower (lowercase alphabetic)
|
||||
if (subModeCh < 26) {
|
||||
ch = (char) ('a' + subModeCh);
|
||||
} else {
|
||||
switch (subModeCh) {
|
||||
case 26:
|
||||
ch = ' ';
|
||||
break;
|
||||
case AS:
|
||||
// Shift to alpha
|
||||
priorToShiftMode = subMode;
|
||||
subMode = Mode.ALPHA_SHIFT;
|
||||
break;
|
||||
case ML:
|
||||
subMode = Mode.MIXED;
|
||||
latchedMode = subMode;
|
||||
break;
|
||||
case PS:
|
||||
// Shift to punctuation
|
||||
priorToShiftMode = subMode;
|
||||
subMode = Mode.PUNCT_SHIFT;
|
||||
break;
|
||||
case MODE_SHIFT_TO_BYTE_COMPACTION_MODE:
|
||||
result.append((char) byteCompactionData[i]);
|
||||
break;
|
||||
case TEXT_COMPACTION_MODE_LATCH:
|
||||
subMode = Mode.ALPHA;
|
||||
latchedMode = subMode;
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case MIXED:
|
||||
// Mixed (numeric and some punctuation)
|
||||
if (subModeCh < PL) {
|
||||
ch = MIXED_CHARS[subModeCh];
|
||||
} else {
|
||||
switch (subModeCh) {
|
||||
case PL:
|
||||
subMode = Mode.PUNCT;
|
||||
latchedMode = subMode;
|
||||
break;
|
||||
case 26:
|
||||
ch = ' ';
|
||||
break;
|
||||
case LL:
|
||||
subMode = Mode.LOWER;
|
||||
latchedMode = subMode;
|
||||
break;
|
||||
case AL:
|
||||
case TEXT_COMPACTION_MODE_LATCH:
|
||||
subMode = Mode.ALPHA;
|
||||
latchedMode = subMode;
|
||||
break;
|
||||
case PS:
|
||||
// Shift to punctuation
|
||||
priorToShiftMode = subMode;
|
||||
subMode = Mode.PUNCT_SHIFT;
|
||||
break;
|
||||
case MODE_SHIFT_TO_BYTE_COMPACTION_MODE:
|
||||
result.append((char) byteCompactionData[i]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case PUNCT:
|
||||
// Punctuation
|
||||
if (subModeCh < PAL) {
|
||||
ch = PUNCT_CHARS[subModeCh];
|
||||
} else {
|
||||
switch (subModeCh) {
|
||||
case PAL:
|
||||
case TEXT_COMPACTION_MODE_LATCH:
|
||||
subMode = Mode.ALPHA;
|
||||
latchedMode = subMode;
|
||||
break;
|
||||
case MODE_SHIFT_TO_BYTE_COMPACTION_MODE:
|
||||
result.append((char) byteCompactionData[i]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case ALPHA_SHIFT:
|
||||
// Restore sub-mode
|
||||
subMode = priorToShiftMode;
|
||||
if (subModeCh < 26) {
|
||||
ch = (char) ('A' + subModeCh);
|
||||
} else {
|
||||
switch (subModeCh) {
|
||||
case 26:
|
||||
ch = ' ';
|
||||
break;
|
||||
case TEXT_COMPACTION_MODE_LATCH:
|
||||
subMode = Mode.ALPHA;
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case PUNCT_SHIFT:
|
||||
// Restore sub-mode
|
||||
subMode = priorToShiftMode;
|
||||
if (subModeCh < PAL) {
|
||||
ch = PUNCT_CHARS[subModeCh];
|
||||
} else {
|
||||
switch (subModeCh) {
|
||||
case PAL:
|
||||
case TEXT_COMPACTION_MODE_LATCH:
|
||||
subMode = Mode.ALPHA;
|
||||
break;
|
||||
case MODE_SHIFT_TO_BYTE_COMPACTION_MODE:
|
||||
// PS before Shift-to-Byte is used as a padding character,
|
||||
// see 5.4.2.4 of the specification
|
||||
result.append((char) byteCompactionData[i]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
if (ch != 0) {
|
||||
// Append decoded character to result
|
||||
result.append(ch);
|
||||
}
|
||||
i++;
|
||||
}
|
||||
return latchedMode;
|
||||
}
|
||||
|
||||
/**
|
||||
* Byte Compaction mode (see 5.4.3) permits all 256 possible 8-bit byte values to be encoded.
|
||||
* This includes all ASCII characters value 0 to 127 inclusive and provides for international
|
||||
* character set support.
|
||||
*
|
||||
* @param mode The byte compaction mode i.e. 901 or 924
|
||||
* @param codewords The array of codewords (data + error)
|
||||
* @param codeIndex The current index into the codeword array.
|
||||
* @param result The decoded data is appended to the result.
|
||||
* @return The next index into the codeword array.
|
||||
*/
|
||||
private static int byteCompaction(int mode,
|
||||
int[] codewords,
|
||||
int codeIndex,
|
||||
ECIStringBuilder result) throws FormatException {
|
||||
boolean end = false;
|
||||
|
||||
while (codeIndex < codewords[0] && !end) {
|
||||
//handle leading ECIs
|
||||
while (codeIndex < codewords[0] && codewords[codeIndex] == ECI_CHARSET) {
|
||||
result.appendECI(codewords[++codeIndex]);
|
||||
codeIndex++;
|
||||
}
|
||||
|
||||
if (codeIndex >= codewords[0] || codewords[codeIndex] >= TEXT_COMPACTION_MODE_LATCH) {
|
||||
end = true;
|
||||
} else {
|
||||
//decode one block of 5 codewords to 6 bytes
|
||||
long value = 0;
|
||||
int count = 0;
|
||||
do {
|
||||
value = 900 * value + codewords[codeIndex++];
|
||||
count++;
|
||||
} while (count < 5 &&
|
||||
codeIndex < codewords[0] &&
|
||||
codewords[codeIndex] < TEXT_COMPACTION_MODE_LATCH);
|
||||
if (count == 5 && (mode == BYTE_COMPACTION_MODE_LATCH_6 ||
|
||||
codeIndex < codewords[0] &&
|
||||
codewords[codeIndex] < TEXT_COMPACTION_MODE_LATCH)) {
|
||||
for (int i = 0; i < 6; i++) {
|
||||
result.append((byte) (value >> (8 * (5 - i))));
|
||||
}
|
||||
} else {
|
||||
codeIndex -= count;
|
||||
while ((codeIndex < codewords[0]) && !end) {
|
||||
int code = codewords[codeIndex++];
|
||||
if (code < TEXT_COMPACTION_MODE_LATCH) {
|
||||
result.append((byte) code);
|
||||
} else if (code == ECI_CHARSET) {
|
||||
result.appendECI(codewords[codeIndex++]);
|
||||
} else {
|
||||
codeIndex--;
|
||||
end = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return codeIndex;
|
||||
}
|
||||
|
||||
/**
|
||||
* Numeric Compaction mode (see 5.4.4) permits efficient encoding of numeric data strings.
|
||||
*
|
||||
* @param codewords The array of codewords (data + error)
|
||||
* @param codeIndex The current index into the codeword array.
|
||||
* @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, ECIStringBuilder result) throws FormatException {
|
||||
int count = 0;
|
||||
boolean end = false;
|
||||
|
||||
int[] numericCodewords = new int[MAX_NUMERIC_CODEWORDS];
|
||||
|
||||
while (codeIndex < codewords[0] && !end) {
|
||||
int code = codewords[codeIndex++];
|
||||
if (codeIndex == codewords[0]) {
|
||||
end = true;
|
||||
}
|
||||
if (code < TEXT_COMPACTION_MODE_LATCH) {
|
||||
numericCodewords[count] = code;
|
||||
count++;
|
||||
} else {
|
||||
switch (code) {
|
||||
case TEXT_COMPACTION_MODE_LATCH:
|
||||
case BYTE_COMPACTION_MODE_LATCH:
|
||||
case BYTE_COMPACTION_MODE_LATCH_6:
|
||||
case BEGIN_MACRO_PDF417_CONTROL_BLOCK:
|
||||
case BEGIN_MACRO_PDF417_OPTIONAL_FIELD:
|
||||
case MACRO_PDF417_TERMINATOR:
|
||||
case ECI_CHARSET:
|
||||
codeIndex--;
|
||||
end = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if ((count % MAX_NUMERIC_CODEWORDS == 0 || code == NUMERIC_COMPACTION_MODE_LATCH || end) && count > 0) {
|
||||
// Re-invoking Numeric Compaction mode (by using codeword 902
|
||||
// while in Numeric Compaction mode) serves to terminate the
|
||||
// current Numeric Compaction mode grouping as described in 5.4.4.2,
|
||||
// and then to start a new one grouping.
|
||||
result.append(decodeBase900toBase10(numericCodewords, count));
|
||||
count = 0;
|
||||
}
|
||||
}
|
||||
return codeIndex;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert a list of Numeric Compacted codewords from Base 900 to Base 10.
|
||||
*
|
||||
* @param codewords The array of codewords
|
||||
* @param count The number of codewords
|
||||
* @return The decoded string representing the Numeric data.
|
||||
*/
|
||||
/*
|
||||
EXAMPLE
|
||||
Encode the fifteen digit numeric string 000213298174000
|
||||
Prefix the numeric string with a 1 and set the initial value of
|
||||
t = 1 000 213 298 174 000
|
||||
Calculate codeword 0
|
||||
d0 = 1 000 213 298 174 000 mod 900 = 200
|
||||
|
||||
t = 1 000 213 298 174 000 div 900 = 1 111 348 109 082
|
||||
Calculate codeword 1
|
||||
d1 = 1 111 348 109 082 mod 900 = 282
|
||||
|
||||
t = 1 111 348 109 082 div 900 = 1 234 831 232
|
||||
Calculate codeword 2
|
||||
d2 = 1 234 831 232 mod 900 = 632
|
||||
|
||||
t = 1 234 831 232 div 900 = 1 372 034
|
||||
Calculate codeword 3
|
||||
d3 = 1 372 034 mod 900 = 434
|
||||
|
||||
t = 1 372 034 div 900 = 1 524
|
||||
Calculate codeword 4
|
||||
d4 = 1 524 mod 900 = 624
|
||||
|
||||
t = 1 524 div 900 = 1
|
||||
Calculate codeword 5
|
||||
d5 = 1 mod 900 = 1
|
||||
t = 1 div 900 = 0
|
||||
Codeword sequence is: 1, 624, 434, 632, 282, 200
|
||||
|
||||
Decode the above codewords involves
|
||||
1 x 900 power of 5 + 624 x 900 power of 4 + 434 x 900 power of 3 +
|
||||
632 x 900 power of 2 + 282 x 900 power of 1 + 200 x 900 power of 0 = 1000213298174000
|
||||
|
||||
Remove leading 1 => RXingResult is 000213298174000
|
||||
*/
|
||||
private static String decodeBase900toBase10(int[] codewords, int count) throws FormatException {
|
||||
BigInteger result = BigInteger.ZERO;
|
||||
for (int i = 0; i < count; i++) {
|
||||
result = result.add(EXP900[count - i - 1].multiply(BigInteger.valueOf(codewords[i])));
|
||||
}
|
||||
String resultString = result.toString();
|
||||
if (resultString.charAt(0) != '1') {
|
||||
throw FormatException.getFormatInstance();
|
||||
}
|
||||
return resultString.substring(1);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -19,6 +19,7 @@ use std::collections::HashMap;
|
||||
/**
|
||||
* @author Guenther Grau
|
||||
*/
|
||||
#[derive(Clone)]
|
||||
pub struct BarcodeValue(HashMap<u32, u32>);
|
||||
// private final Map<Integer,Integer> values = new HashMap<>();
|
||||
|
||||
|
||||
@@ -14,14 +14,16 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
use std::rc::Rc;
|
||||
|
||||
use crate::{common::BitMatrix, Exceptions, RXingResultPoint, ResultPoint};
|
||||
|
||||
/**
|
||||
* @author Guenther Grau
|
||||
*/
|
||||
#[derive(Clone)]
|
||||
pub struct BoundingBox<'a> {
|
||||
image: &'a BitMatrix,
|
||||
pub struct BoundingBox {
|
||||
image: Rc<BitMatrix>,
|
||||
topLeft: RXingResultPoint,
|
||||
bottomLeft: RXingResultPoint,
|
||||
topRight: RXingResultPoint,
|
||||
@@ -31,14 +33,14 @@ pub struct BoundingBox<'a> {
|
||||
minY: u32,
|
||||
maxY: u32,
|
||||
}
|
||||
impl<'a> BoundingBox<'_> {
|
||||
impl BoundingBox {
|
||||
pub fn new(
|
||||
image: &'a BitMatrix,
|
||||
image: Rc<BitMatrix>,
|
||||
topLeft: Option<RXingResultPoint>,
|
||||
bottomLeft: Option<RXingResultPoint>,
|
||||
topRight: Option<RXingResultPoint>,
|
||||
bottomRight: Option<RXingResultPoint>,
|
||||
) -> Result<BoundingBox<'a>, Exceptions> {
|
||||
) -> Result<BoundingBox, Exceptions> {
|
||||
let leftUnspecified = topLeft.is_none() || bottomLeft.is_none();
|
||||
let rightUnspecified = topRight.is_none() || bottomRight.is_none();
|
||||
if leftUnspecified && rightUnspecified {
|
||||
@@ -81,9 +83,9 @@ impl<'a> BoundingBox<'_> {
|
||||
})
|
||||
}
|
||||
|
||||
pub fn from_other(boundingBox: &'a BoundingBox) -> BoundingBox<'a> {
|
||||
pub fn from_other(boundingBox: Rc<BoundingBox>) -> BoundingBox {
|
||||
BoundingBox {
|
||||
image: boundingBox.image,
|
||||
image: boundingBox.image.clone(),
|
||||
topLeft: boundingBox.topLeft,
|
||||
bottomLeft: boundingBox.bottomLeft,
|
||||
topRight: boundingBox.topRight,
|
||||
@@ -96,14 +98,14 @@ impl<'a> BoundingBox<'_> {
|
||||
}
|
||||
|
||||
pub fn merge(
|
||||
leftBox: Option<&'a BoundingBox>,
|
||||
rightBox: Option<&'a BoundingBox>,
|
||||
) -> Result<BoundingBox<'a>, Exceptions> {
|
||||
leftBox: Option<BoundingBox>,
|
||||
rightBox: Option<BoundingBox>,
|
||||
) -> Result<BoundingBox, Exceptions> {
|
||||
if leftBox.is_none() {
|
||||
return Ok(rightBox.unwrap().clone());
|
||||
return Ok(rightBox.as_ref().unwrap().clone());
|
||||
}
|
||||
if rightBox.is_none() {
|
||||
return Ok(leftBox.unwrap().clone());
|
||||
return Ok(leftBox.as_ref().unwrap().clone());
|
||||
}
|
||||
let leftBox = leftBox.unwrap();
|
||||
let rightBox = rightBox.unwrap();
|
||||
@@ -161,7 +163,7 @@ impl<'a> BoundingBox<'_> {
|
||||
}
|
||||
|
||||
BoundingBox::new(
|
||||
self.image,
|
||||
self.image.clone(),
|
||||
Some(newTopLeft),
|
||||
Some(newBottomLeft),
|
||||
Some(newTopRight),
|
||||
|
||||
797
src/pdf417/decoder/decoded_bit_stream_parser.rs
Normal file
797
src/pdf417/decoder/decoded_bit_stream_parser.rs
Normal file
@@ -0,0 +1,797 @@
|
||||
/*
|
||||
* Copyright 2009 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.
|
||||
*/
|
||||
|
||||
use num::{self, bigint::ToBigUint, BigUint};
|
||||
use std::rc::Rc;
|
||||
|
||||
use crate::{
|
||||
common::{DecoderRXingResult, ECIStringBuilder},
|
||||
pdf417::PDF417RXingResultMetadata,
|
||||
Exceptions,
|
||||
};
|
||||
|
||||
/**
|
||||
* <p>This class contains the methods for decoding the PDF417 codewords.</p>
|
||||
*
|
||||
* @author SITA Lab (kevin.osullivan@sita.aero)
|
||||
* @author Guenther Grau
|
||||
*/
|
||||
|
||||
#[derive(Clone, Copy, PartialEq, Eq)]
|
||||
enum Mode {
|
||||
ALPHA,
|
||||
LOWER,
|
||||
MIXED,
|
||||
PUNCT,
|
||||
ALPHA_SHIFT,
|
||||
PUNCT_SHIFT,
|
||||
}
|
||||
|
||||
const TEXT_COMPACTION_MODE_LATCH: u32 = 900;
|
||||
const BYTE_COMPACTION_MODE_LATCH: u32 = 901;
|
||||
const NUMERIC_COMPACTION_MODE_LATCH: u32 = 902;
|
||||
const BYTE_COMPACTION_MODE_LATCH_6: u32 = 924;
|
||||
const ECI_USER_DEFINED: u32 = 925;
|
||||
const ECI_GENERAL_PURPOSE: u32 = 926;
|
||||
const ECI_CHARSET: u32 = 927;
|
||||
const BEGIN_MACRO_PDF417_CONTROL_BLOCK: u32 = 928;
|
||||
const BEGIN_MACRO_PDF417_OPTIONAL_FIELD: u32 = 923;
|
||||
const MACRO_PDF417_TERMINATOR: u32 = 922;
|
||||
const MODE_SHIFT_TO_BYTE_COMPACTION_MODE: u32 = 913;
|
||||
const MAX_NUMERIC_CODEWORDS: usize = 15;
|
||||
|
||||
const MACRO_PDF417_OPTIONAL_FIELD_FILE_NAME: u32 = 0;
|
||||
const MACRO_PDF417_OPTIONAL_FIELD_SEGMENT_COUNT: u32 = 1;
|
||||
const MACRO_PDF417_OPTIONAL_FIELD_TIME_STAMP: u32 = 2;
|
||||
const MACRO_PDF417_OPTIONAL_FIELD_SENDER: u32 = 3;
|
||||
const MACRO_PDF417_OPTIONAL_FIELD_ADDRESSEE: u32 = 4;
|
||||
const MACRO_PDF417_OPTIONAL_FIELD_FILE_SIZE: u32 = 5;
|
||||
const MACRO_PDF417_OPTIONAL_FIELD_CHECKSUM: u32 = 6;
|
||||
|
||||
const PL: u32 = 25;
|
||||
const LL: u32 = 27;
|
||||
const AS: u32 = 27;
|
||||
const ML: u32 = 28;
|
||||
const AL: u32 = 28;
|
||||
const PS: u32 = 29;
|
||||
const PAL: u32 = 29;
|
||||
|
||||
const PUNCT_CHARS: [char; 29] = [
|
||||
';', '<', '>', '@', '[', '\\', ']', '_', '`', '~', '!', '\r', '\t', ',', ':', '\n', '-', '.',
|
||||
'$', '/', '"', '|', '*', '(', ')', '?', '{', '}', '\'',
|
||||
];
|
||||
|
||||
const MIXED_CHARS: [char; 25] = [
|
||||
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '&', '\r', '\t', ',', ':', '#', '-', '.',
|
||||
'$', '/', '+', '%', '*', '=', '^',
|
||||
];
|
||||
|
||||
use lazy_static::lazy_static;
|
||||
|
||||
lazy_static! {
|
||||
/**
|
||||
* Table containing values for the exponent of 900.
|
||||
* This is used in the numeric compaction decode algorithm.
|
||||
*/
|
||||
static ref EXP900 : Vec<BigUint> = {
|
||||
const EXP_LEN :usize= 16;
|
||||
let mut exp900 = Vec::with_capacity(EXP_LEN); //[0;16];
|
||||
exp900.push(ToBigUint::to_biguint(&1).unwrap());
|
||||
let nineHundred = ToBigUint::to_biguint(&900).unwrap();
|
||||
exp900.push(nineHundred);
|
||||
let mut i = 2;
|
||||
while i < EXP_LEN {
|
||||
// for (int i = 2; i < EXP900.length; i++) {
|
||||
exp900.push( &exp900[i - 1] * 900_u32);
|
||||
|
||||
i+=1;
|
||||
}
|
||||
|
||||
exp900
|
||||
};
|
||||
}
|
||||
|
||||
// /**
|
||||
// * Table containing values for the exponent of 900.
|
||||
// * This is used in the numeric compaction decode algorithm.
|
||||
// */
|
||||
// const EXP900 : [u128;16] =
|
||||
|
||||
// {
|
||||
// let mut exp900 = [0;16];
|
||||
// exp900[0] = 1;
|
||||
// let nineHundred = 900;
|
||||
// exp900[1] = nineHundred;
|
||||
// let mut i = 2;
|
||||
// while i < exp900.len() {
|
||||
// // for (int i = 2; i < EXP900.length; i++) {
|
||||
// exp900[i] = exp900[i - 1] * (nineHundred);
|
||||
|
||||
// i+=1;
|
||||
// }
|
||||
|
||||
// exp900
|
||||
// };
|
||||
|
||||
const NUMBER_OF_SEQUENCE_CODEWORDS: usize = 2;
|
||||
|
||||
pub fn decode(codewords: &[u32], ecLevel: &str) -> Result<DecoderRXingResult, Exceptions> {
|
||||
let mut result = ECIStringBuilder::with_capacity(codewords.len() * 2);
|
||||
let mut codeIndex = textCompaction(codewords, 1, &mut result)? as usize;
|
||||
let mut resultMetadata = PDF417RXingResultMetadata::default();
|
||||
while codeIndex < codewords[0] as usize {
|
||||
let code = codewords[codeIndex];
|
||||
codeIndex += 1;
|
||||
match code {
|
||||
TEXT_COMPACTION_MODE_LATCH => {
|
||||
codeIndex = textCompaction(codewords, codeIndex, &mut result)?
|
||||
}
|
||||
BYTE_COMPACTION_MODE_LATCH | BYTE_COMPACTION_MODE_LATCH_6 => {
|
||||
codeIndex = byteCompaction(code, codewords, codeIndex, &mut result)?
|
||||
}
|
||||
MODE_SHIFT_TO_BYTE_COMPACTION_MODE => {
|
||||
result.append_char(char::from_u32(codewords[codeIndex]).unwrap());
|
||||
codeIndex += 1;
|
||||
}
|
||||
NUMERIC_COMPACTION_MODE_LATCH => {
|
||||
codeIndex = numericCompaction(codewords, codeIndex, &mut result)?
|
||||
}
|
||||
ECI_CHARSET => {
|
||||
result.appendECI(codewords[codeIndex])?;
|
||||
codeIndex += 1;
|
||||
}
|
||||
ECI_GENERAL_PURPOSE =>
|
||||
// Can't do anything with generic ECI; skip its 2 characters
|
||||
{
|
||||
codeIndex += 2
|
||||
}
|
||||
ECI_USER_DEFINED =>
|
||||
// Can't do anything with user ECI; skip its 1 character
|
||||
{
|
||||
codeIndex += 1
|
||||
}
|
||||
BEGIN_MACRO_PDF417_CONTROL_BLOCK => {
|
||||
codeIndex = decodeMacroBlock(codewords, codeIndex, &mut resultMetadata)?
|
||||
}
|
||||
BEGIN_MACRO_PDF417_OPTIONAL_FIELD | MACRO_PDF417_TERMINATOR =>
|
||||
// Should not see these outside a macro block
|
||||
{
|
||||
return Err(Exceptions::FormatException("".to_owned()))
|
||||
}
|
||||
_ => {
|
||||
// Default to text compaction. During testing numerous barcodes
|
||||
// appeared to be missing the starting Mode:: In these cases defaulting
|
||||
// to text compaction seems to work.
|
||||
codeIndex -= 1;
|
||||
codeIndex = textCompaction(codewords, codeIndex, &mut result)?;
|
||||
}
|
||||
}
|
||||
}
|
||||
if result.is_empty() && resultMetadata.getFileId().is_empty() {
|
||||
return Err(Exceptions::FormatException("".to_owned()));
|
||||
}
|
||||
let mut decoderRXingResult = DecoderRXingResult::new(
|
||||
Vec::new(),
|
||||
result.to_string(),
|
||||
Vec::new(),
|
||||
ecLevel.to_owned(),
|
||||
);
|
||||
decoderRXingResult.setOther(Rc::new(resultMetadata));
|
||||
|
||||
Ok(decoderRXingResult)
|
||||
}
|
||||
|
||||
pub fn decodeMacroBlock(
|
||||
codewords: &[u32],
|
||||
codeIndex: usize,
|
||||
resultMetadata: &mut PDF417RXingResultMetadata,
|
||||
) -> Result<usize, Exceptions> {
|
||||
let mut codeIndex = codeIndex;
|
||||
if codeIndex + NUMBER_OF_SEQUENCE_CODEWORDS > codewords[0] as usize {
|
||||
// we must have at least two bytes left for the segment index
|
||||
return Err(Exceptions::FormatException("".to_owned()));
|
||||
}
|
||||
let mut segmentIndexArray = [0; NUMBER_OF_SEQUENCE_CODEWORDS];
|
||||
for i in 0..NUMBER_OF_SEQUENCE_CODEWORDS {
|
||||
// for (int i = 0; i < NUMBER_OF_SEQUENCE_CODEWORDS; i++, codeIndex++) {
|
||||
segmentIndexArray[i] = codewords[codeIndex];
|
||||
codeIndex += 1;
|
||||
}
|
||||
let segmentIndexString =
|
||||
decodeBase900toBase10(&segmentIndexArray, NUMBER_OF_SEQUENCE_CODEWORDS)?;
|
||||
if segmentIndexString.is_empty() {
|
||||
resultMetadata.setSegmentIndex(0);
|
||||
} else {
|
||||
if let Ok(parsed_int) = segmentIndexString.parse::<usize>() {
|
||||
resultMetadata.setSegmentIndex(parsed_int);
|
||||
} else {
|
||||
// too large; bad input?
|
||||
return Err(Exceptions::FormatException("".to_owned()));
|
||||
}
|
||||
}
|
||||
|
||||
// Decoding the fileId codewords as 0-899 numbers, each 0-filled to width 3. This follows the spec
|
||||
// (See ISO/IEC 15438:2015 Annex H.6) and preserves all info, but some generators (e.g. TEC-IT) write
|
||||
// the fileId using text compaction, so in those cases the fileId will appear mangled.
|
||||
let mut fileId = String::new();
|
||||
while codeIndex < codewords[0] as usize
|
||||
&& codeIndex < codewords.len()
|
||||
&& codewords[codeIndex] != MACRO_PDF417_TERMINATOR
|
||||
&& codewords[codeIndex] != BEGIN_MACRO_PDF417_OPTIONAL_FIELD
|
||||
{
|
||||
fileId.push_str(&format!("{:0>3}", codewords[codeIndex])/*String.format("%03d", codewords[codeIndex])*/);
|
||||
codeIndex += 1;
|
||||
}
|
||||
if fileId.chars().count() == 0 {
|
||||
// at least one fileId codeword is required (Annex H.2)
|
||||
return Err(Exceptions::FormatException("".to_owned()));
|
||||
}
|
||||
resultMetadata.setFileId(fileId);
|
||||
|
||||
let mut optionalFieldsStart = -1_isize;
|
||||
if codewords[codeIndex] == BEGIN_MACRO_PDF417_OPTIONAL_FIELD {
|
||||
optionalFieldsStart = codeIndex as isize + 1;
|
||||
}
|
||||
|
||||
while codeIndex < codewords[0] as usize {
|
||||
match codewords[codeIndex] {
|
||||
BEGIN_MACRO_PDF417_OPTIONAL_FIELD => {
|
||||
codeIndex += 1;
|
||||
match codewords[codeIndex] {
|
||||
MACRO_PDF417_OPTIONAL_FIELD_FILE_NAME => {
|
||||
let mut fileName = ECIStringBuilder::new();
|
||||
codeIndex = textCompaction(codewords, codeIndex + 1, &mut fileName)?;
|
||||
resultMetadata.setFileName(fileName.to_string());
|
||||
}
|
||||
MACRO_PDF417_OPTIONAL_FIELD_SENDER => {
|
||||
let mut sender = ECIStringBuilder::new();
|
||||
codeIndex = textCompaction(codewords, codeIndex + 1, &mut sender)?;
|
||||
resultMetadata.setSender(sender.to_string());
|
||||
}
|
||||
MACRO_PDF417_OPTIONAL_FIELD_ADDRESSEE => {
|
||||
let mut addressee = ECIStringBuilder::new();
|
||||
codeIndex = textCompaction(codewords, codeIndex + 1, &mut addressee)?;
|
||||
resultMetadata.setAddressee(addressee.to_string());
|
||||
}
|
||||
MACRO_PDF417_OPTIONAL_FIELD_SEGMENT_COUNT => {
|
||||
let mut segmentCount = ECIStringBuilder::new();
|
||||
codeIndex = numericCompaction(codewords, codeIndex + 1, &mut segmentCount)?;
|
||||
resultMetadata.setSegmentCount(segmentCount.to_string().parse().unwrap());
|
||||
}
|
||||
MACRO_PDF417_OPTIONAL_FIELD_TIME_STAMP => {
|
||||
let mut timestamp = ECIStringBuilder::new();
|
||||
codeIndex = numericCompaction(codewords, codeIndex + 1, &mut timestamp)?;
|
||||
resultMetadata.setTimestamp(timestamp.to_string().parse().unwrap());
|
||||
}
|
||||
MACRO_PDF417_OPTIONAL_FIELD_CHECKSUM => {
|
||||
let mut checksum = ECIStringBuilder::new();
|
||||
codeIndex = numericCompaction(codewords, codeIndex + 1, &mut checksum)?;
|
||||
resultMetadata.setChecksum(checksum.to_string().parse().unwrap());
|
||||
}
|
||||
MACRO_PDF417_OPTIONAL_FIELD_FILE_SIZE => {
|
||||
let mut fileSize = ECIStringBuilder::new();
|
||||
codeIndex = numericCompaction(codewords, codeIndex + 1, &mut fileSize)?;
|
||||
resultMetadata.setFileSize(fileSize.to_string().parse().unwrap());
|
||||
}
|
||||
_ => return Err(Exceptions::FormatException("".to_owned())),
|
||||
}
|
||||
}
|
||||
MACRO_PDF417_TERMINATOR => {
|
||||
codeIndex += 1;
|
||||
resultMetadata.setLastSegment(true);
|
||||
}
|
||||
_ => return Err(Exceptions::FormatException("".to_owned())),
|
||||
}
|
||||
}
|
||||
|
||||
// copy optional fields to additional options
|
||||
if optionalFieldsStart != -1 {
|
||||
let mut optionalFieldsLength = codeIndex - optionalFieldsStart as usize;
|
||||
if resultMetadata.isLastSegment() {
|
||||
// do not include terminator
|
||||
optionalFieldsLength -= 1;
|
||||
}
|
||||
// resultMetadata.setOptionalData(
|
||||
// Arrays.copyOfRange(codewords, optionalFieldsStart, optionalFieldsStart + optionalFieldsLength));
|
||||
resultMetadata.setOptionalData(
|
||||
codewords[optionalFieldsStart as usize
|
||||
..(optionalFieldsStart + optionalFieldsLength as isize) as usize]
|
||||
.to_vec(),
|
||||
);
|
||||
}
|
||||
|
||||
Ok(codeIndex)
|
||||
}
|
||||
|
||||
/**
|
||||
* Text Compaction mode (see 5.4.1.5) permits all printable ASCII characters to be
|
||||
* encoded, i.e. values 32 - 126 inclusive in accordance with ISO/IEC 646 (IRV), as
|
||||
* well as selected control characters.
|
||||
*
|
||||
* @param codewords The array of codewords (data + error)
|
||||
* @param codeIndex The current index into the codeword array.
|
||||
* @param result The decoded data is appended to the result.
|
||||
* @return The next index into the codeword array.
|
||||
*/
|
||||
fn textCompaction(
|
||||
codewords: &[u32],
|
||||
codeIndex: usize,
|
||||
result: &mut ECIStringBuilder,
|
||||
) -> Result<usize, Exceptions> {
|
||||
let mut codeIndex = codeIndex;
|
||||
// 2 character per codeword
|
||||
let mut textCompactionData = vec![0; (codewords[0] as usize - codeIndex) as usize * 2];
|
||||
// Used to hold the byte compaction value if there is a mode shift
|
||||
let mut byteCompactionData = vec![0; (codewords[0] as usize - codeIndex) as usize * 2];
|
||||
|
||||
let mut index = 0;
|
||||
let mut end = false;
|
||||
let mut subMode = Mode::ALPHA;
|
||||
while (codeIndex < codewords[0] as usize) && !end {
|
||||
let mut code = codewords[codeIndex];
|
||||
codeIndex += 1;
|
||||
if code < TEXT_COMPACTION_MODE_LATCH {
|
||||
textCompactionData[index] = code / 30;
|
||||
textCompactionData[index + 1] = code % 30;
|
||||
index += 2;
|
||||
} else {
|
||||
match code {
|
||||
TEXT_COMPACTION_MODE_LATCH => {
|
||||
// reinitialize text compaction mode to alpha sub mode
|
||||
textCompactionData[index] = TEXT_COMPACTION_MODE_LATCH;
|
||||
index += 1;
|
||||
}
|
||||
BYTE_COMPACTION_MODE_LATCH
|
||||
| BYTE_COMPACTION_MODE_LATCH_6
|
||||
| NUMERIC_COMPACTION_MODE_LATCH
|
||||
| BEGIN_MACRO_PDF417_CONTROL_BLOCK
|
||||
| BEGIN_MACRO_PDF417_OPTIONAL_FIELD
|
||||
| MACRO_PDF417_TERMINATOR => {
|
||||
codeIndex -= 1;
|
||||
end = true;
|
||||
}
|
||||
MODE_SHIFT_TO_BYTE_COMPACTION_MODE => {
|
||||
// The Mode Shift codeword 913 shall cause a temporary
|
||||
// switch from Text Compaction mode to Byte Compaction Mode::
|
||||
// This switch shall be in effect for only the next codeword,
|
||||
// after which the mode shall revert to the prevailing sub-mode
|
||||
// of the Text Compaction Mode:: Codeword 913 is only available
|
||||
// in Text Compaction mode; its use is described in 5.4.2.4.
|
||||
textCompactionData[index] = MODE_SHIFT_TO_BYTE_COMPACTION_MODE;
|
||||
code = codewords[codeIndex];
|
||||
codeIndex += 1;
|
||||
byteCompactionData[index] = code;
|
||||
index += 1;
|
||||
}
|
||||
ECI_CHARSET => {
|
||||
subMode = decodeTextCompaction(
|
||||
&textCompactionData,
|
||||
&byteCompactionData,
|
||||
index,
|
||||
result,
|
||||
subMode,
|
||||
);
|
||||
result.appendECI(codewords[codeIndex])?;
|
||||
codeIndex += 1;
|
||||
textCompactionData = vec![0; (codewords[0] as usize - codeIndex) * 2];
|
||||
byteCompactionData = vec![0; (codewords[0] as usize - codeIndex) * 2];
|
||||
index = 0;
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
decodeTextCompaction(
|
||||
&textCompactionData,
|
||||
&byteCompactionData,
|
||||
index,
|
||||
result,
|
||||
subMode,
|
||||
);
|
||||
|
||||
Ok(codeIndex)
|
||||
}
|
||||
|
||||
/**
|
||||
* The Text Compaction mode includes all the printable ASCII characters
|
||||
* (i.e. values from 32 to 126) and three ASCII control characters: HT or tab
|
||||
* (ASCII value 9), LF or line feed (ASCII value 10), and CR or carriage
|
||||
* return (ASCII value 13). The Text Compaction mode also includes various latch
|
||||
* and shift characters which are used exclusively within the Mode:: The Text
|
||||
* Compaction mode encodes up to 2 characters per codeword. The compaction rules
|
||||
* for converting data into PDF417 codewords are defined in 5.4.2.2. The sub-mode
|
||||
* switches are defined in 5.4.2.3.
|
||||
*
|
||||
* @param textCompactionData The text compaction data.
|
||||
* @param byteCompactionData The byte compaction data if there
|
||||
* was a mode shift.
|
||||
* @param length The size of the text compaction and byte compaction data.
|
||||
* @param result The decoded data is appended to the result.
|
||||
* @param startMode The mode in which decoding starts
|
||||
* @return The mode in which decoding ended
|
||||
*/
|
||||
fn decodeTextCompaction(
|
||||
textCompactionData: &[u32],
|
||||
byteCompactionData: &[u32],
|
||||
length: usize,
|
||||
result: &mut ECIStringBuilder,
|
||||
startMode: Mode,
|
||||
) -> Mode {
|
||||
// Beginning from an initial state
|
||||
// The default compaction mode for PDF417 in effect at the start of each symbol shall always be Text
|
||||
// Compaction mode Alpha sub-mode (uppercase alphabetic). A latch codeword from another mode to the Text
|
||||
// Compaction mode shall always switch to the Text Compaction Alpha sub-Mode::
|
||||
let mut subMode = startMode;
|
||||
let mut priorToShiftMode = startMode;
|
||||
let mut latchedMode = startMode;
|
||||
let mut i = 0;
|
||||
while i < length {
|
||||
let subModeCh = textCompactionData[i];
|
||||
let mut ch = 0 as char;
|
||||
match subMode {
|
||||
Mode::ALPHA =>
|
||||
// Alpha (uppercase alphabetic)
|
||||
{
|
||||
if subModeCh < 26 {
|
||||
// Upper case Alpha Character
|
||||
ch = char::from_u32('A' as u32 + subModeCh).unwrap();
|
||||
} else {
|
||||
match subModeCh {
|
||||
26 => ch = ' ',
|
||||
LL => {
|
||||
subMode = Mode::LOWER;
|
||||
latchedMode = subMode;
|
||||
}
|
||||
ML => {
|
||||
subMode = Mode::MIXED;
|
||||
latchedMode = subMode;
|
||||
}
|
||||
PS => {
|
||||
// Shift to punctuation
|
||||
priorToShiftMode = subMode;
|
||||
subMode = Mode::PUNCT_SHIFT;
|
||||
}
|
||||
MODE_SHIFT_TO_BYTE_COMPACTION_MODE => {
|
||||
result.append_char(char::from_u32(byteCompactionData[i]).unwrap())
|
||||
}
|
||||
TEXT_COMPACTION_MODE_LATCH => {
|
||||
subMode = Mode::ALPHA;
|
||||
latchedMode = subMode;
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Mode::LOWER =>
|
||||
// Lower (lowercase alphabetic)
|
||||
{
|
||||
if subModeCh < 26 {
|
||||
ch = char::from_u32('a' as u32 + subModeCh).unwrap();
|
||||
} else {
|
||||
match subModeCh {
|
||||
26 => ch = ' ',
|
||||
AS => {
|
||||
// Shift to alpha
|
||||
priorToShiftMode = subMode;
|
||||
subMode = Mode::ALPHA_SHIFT;
|
||||
}
|
||||
ML => {
|
||||
subMode = Mode::MIXED;
|
||||
latchedMode = subMode;
|
||||
}
|
||||
PS => {
|
||||
// Shift to punctuation
|
||||
priorToShiftMode = subMode;
|
||||
subMode = Mode::PUNCT_SHIFT;
|
||||
}
|
||||
MODE_SHIFT_TO_BYTE_COMPACTION_MODE => {
|
||||
result.append_char(char::from_u32(byteCompactionData[i]).unwrap())
|
||||
}
|
||||
TEXT_COMPACTION_MODE_LATCH => {
|
||||
subMode = Mode::ALPHA;
|
||||
latchedMode = subMode;
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Mode::MIXED =>
|
||||
// Mixed (numeric and some punctuation)
|
||||
{
|
||||
if subModeCh < PL {
|
||||
ch = MIXED_CHARS[subModeCh as usize];
|
||||
} else {
|
||||
match subModeCh {
|
||||
PL => {
|
||||
subMode = Mode::PUNCT;
|
||||
latchedMode = subMode;
|
||||
}
|
||||
26 => ch = ' ',
|
||||
LL => {
|
||||
subMode = Mode::LOWER;
|
||||
latchedMode = subMode;
|
||||
}
|
||||
AL | TEXT_COMPACTION_MODE_LATCH => {
|
||||
subMode = Mode::ALPHA;
|
||||
latchedMode = subMode;
|
||||
}
|
||||
PS => {
|
||||
// Shift to punctuation
|
||||
priorToShiftMode = subMode;
|
||||
subMode = Mode::PUNCT_SHIFT;
|
||||
}
|
||||
MODE_SHIFT_TO_BYTE_COMPACTION_MODE => {
|
||||
result.append_char(char::from_u32(byteCompactionData[i]).unwrap())
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Mode::PUNCT =>
|
||||
// Punctuation
|
||||
{
|
||||
if subModeCh < PAL {
|
||||
ch = PUNCT_CHARS[subModeCh as usize];
|
||||
} else {
|
||||
match subModeCh {
|
||||
PAL | TEXT_COMPACTION_MODE_LATCH => {
|
||||
subMode = Mode::ALPHA;
|
||||
latchedMode = subMode;
|
||||
}
|
||||
MODE_SHIFT_TO_BYTE_COMPACTION_MODE => {
|
||||
result.append_char(char::from_u32(byteCompactionData[i]).unwrap())
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Mode::ALPHA_SHIFT => {
|
||||
// Restore sub-mode
|
||||
subMode = priorToShiftMode;
|
||||
if subModeCh < 26 {
|
||||
ch = char::from_u32('A' as u32 + subModeCh).unwrap();
|
||||
} else {
|
||||
match subModeCh {
|
||||
26 => ch = ' ',
|
||||
TEXT_COMPACTION_MODE_LATCH => subMode = Mode::ALPHA,
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Mode::PUNCT_SHIFT => {
|
||||
// Restore sub-mode
|
||||
subMode = priorToShiftMode;
|
||||
if subModeCh < PAL {
|
||||
ch = PUNCT_CHARS[subModeCh as usize];
|
||||
} else {
|
||||
match subModeCh {
|
||||
PAL | TEXT_COMPACTION_MODE_LATCH => subMode = Mode::ALPHA,
|
||||
MODE_SHIFT_TO_BYTE_COMPACTION_MODE =>
|
||||
// PS before Shift-to-Byte is used as a padding character,
|
||||
// see 5.4.2.4 of the specification
|
||||
{
|
||||
result.append_char(char::from_u32(byteCompactionData[i]).unwrap())
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if ch as u32 != 0 {
|
||||
// Append decoded character to result
|
||||
result.append_char(ch);
|
||||
}
|
||||
i += 1;
|
||||
}
|
||||
return latchedMode;
|
||||
}
|
||||
|
||||
/**
|
||||
* Byte Compaction mode (see 5.4.3) permits all 256 possible 8-bit byte values to be encoded.
|
||||
* This includes all ASCII characters value 0 to 127 inclusive and provides for international
|
||||
* character set support.
|
||||
*
|
||||
* @param mode The byte compaction mode i.e. 901 or 924
|
||||
* @param codewords The array of codewords (data + error)
|
||||
* @param codeIndex The current index into the codeword array.
|
||||
* @param result The decoded data is appended to the result.
|
||||
* @return The next index into the codeword array.
|
||||
*/
|
||||
fn byteCompaction(
|
||||
mode: u32,
|
||||
codewords: &[u32],
|
||||
codeIndex: usize,
|
||||
result: &mut ECIStringBuilder,
|
||||
) -> Result<usize, Exceptions> {
|
||||
let mut end = false;
|
||||
let mut codeIndex = codeIndex;
|
||||
|
||||
while codeIndex < codewords[0] as usize && !end {
|
||||
//handle leading ECIs
|
||||
while codeIndex < codewords[0] as usize && codewords[codeIndex] == ECI_CHARSET {
|
||||
codeIndex += 1;
|
||||
result.appendECI(codewords[codeIndex])?;
|
||||
codeIndex += 1;
|
||||
}
|
||||
|
||||
if codeIndex >= codewords[0] as usize || codewords[codeIndex] >= TEXT_COMPACTION_MODE_LATCH
|
||||
{
|
||||
end = true;
|
||||
} else {
|
||||
//decode one block of 5 codewords to 6 bytes
|
||||
let mut value: u64 = 0;
|
||||
let mut count = 0;
|
||||
loop {
|
||||
value = 900 * value + codewords[codeIndex] as u64;
|
||||
codeIndex += 1;
|
||||
count += 1;
|
||||
if !(count < 5
|
||||
&& codeIndex < codewords[0] as usize
|
||||
&& codewords[codeIndex] < TEXT_COMPACTION_MODE_LATCH)
|
||||
{
|
||||
break;
|
||||
}
|
||||
} /*while (count < 5 &&
|
||||
codeIndex < codewords[0] &&
|
||||
codewords[codeIndex] < TEXT_COMPACTION_MODE_LATCH);*/
|
||||
if count == 5
|
||||
&& (mode == BYTE_COMPACTION_MODE_LATCH_6
|
||||
|| codeIndex < codewords[0] as usize
|
||||
&& codewords[codeIndex] < TEXT_COMPACTION_MODE_LATCH)
|
||||
{
|
||||
for i in 0..6 {
|
||||
// for (int i = 0; i < 6; i++) {
|
||||
result.append_byte((value >> (8 * (5 - i))) as u8);
|
||||
}
|
||||
} else {
|
||||
codeIndex -= count;
|
||||
while (codeIndex < codewords[0] as usize) && !end {
|
||||
let code = codewords[codeIndex];
|
||||
codeIndex += 1;
|
||||
if code < TEXT_COMPACTION_MODE_LATCH {
|
||||
result.append_byte(code as u8);
|
||||
} else if code == ECI_CHARSET {
|
||||
result.appendECI(codewords[codeIndex])?;
|
||||
codeIndex += 1;
|
||||
} else {
|
||||
codeIndex -= 1;
|
||||
end = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Ok(codeIndex)
|
||||
}
|
||||
|
||||
/**
|
||||
* Numeric Compaction mode (see 5.4.4) permits efficient encoding of numeric data strings.
|
||||
*
|
||||
* @param codewords The array of codewords (data + error)
|
||||
* @param codeIndex The current index into the codeword array.
|
||||
* @param result The decoded data is appended to the result.
|
||||
* @return The next index into the codeword array.
|
||||
*/
|
||||
fn numericCompaction(
|
||||
codewords: &[u32],
|
||||
codeIndex: usize,
|
||||
result: &mut ECIStringBuilder,
|
||||
) -> Result<usize, Exceptions> {
|
||||
let mut count = 0;
|
||||
let mut end = false;
|
||||
let mut codeIndex = codeIndex;
|
||||
|
||||
let mut numericCodewords = [0; MAX_NUMERIC_CODEWORDS];
|
||||
|
||||
while codeIndex < codewords[0] as usize && !end {
|
||||
let code = codewords[codeIndex];
|
||||
codeIndex += 1;
|
||||
if codeIndex == codewords[0] as usize {
|
||||
end = true;
|
||||
}
|
||||
if code < TEXT_COMPACTION_MODE_LATCH {
|
||||
numericCodewords[count] = code;
|
||||
count += 1;
|
||||
} else {
|
||||
match code {
|
||||
TEXT_COMPACTION_MODE_LATCH
|
||||
| BYTE_COMPACTION_MODE_LATCH
|
||||
| BYTE_COMPACTION_MODE_LATCH_6
|
||||
| BEGIN_MACRO_PDF417_CONTROL_BLOCK
|
||||
| BEGIN_MACRO_PDF417_OPTIONAL_FIELD
|
||||
| MACRO_PDF417_TERMINATOR
|
||||
| ECI_CHARSET => {
|
||||
codeIndex -= 1;
|
||||
end = true;
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
if (count % MAX_NUMERIC_CODEWORDS == 0 || code == NUMERIC_COMPACTION_MODE_LATCH || end)
|
||||
&& count > 0
|
||||
{
|
||||
// Re-invoking Numeric Compaction mode (by using codeword 902
|
||||
// while in Numeric Compaction mode) serves to terminate the
|
||||
// current Numeric Compaction mode grouping as described in 5.4.4.2,
|
||||
// and then to start a new one grouping.
|
||||
result.append_string(&decodeBase900toBase10(&numericCodewords, count)?);
|
||||
count = 0;
|
||||
}
|
||||
}
|
||||
Ok(codeIndex)
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert a list of Numeric Compacted codewords from Base 900 to Base 10.
|
||||
*
|
||||
* @param codewords The array of codewords
|
||||
* @param count The number of codewords
|
||||
* @return The decoded string representing the Numeric data.
|
||||
*/
|
||||
/*
|
||||
EXAMPLE
|
||||
Encode the fifteen digit numeric string 000213298174000
|
||||
Prefix the numeric string with a 1 and set the initial value of
|
||||
t = 1 000 213 298 174 000
|
||||
Calculate codeword 0
|
||||
d0 = 1 000 213 298 174 000 mod 900 = 200
|
||||
|
||||
t = 1 000 213 298 174 000 div 900 = 1 111 348 109 082
|
||||
Calculate codeword 1
|
||||
d1 = 1 111 348 109 082 mod 900 = 282
|
||||
|
||||
t = 1 111 348 109 082 div 900 = 1 234 831 232
|
||||
Calculate codeword 2
|
||||
d2 = 1 234 831 232 mod 900 = 632
|
||||
|
||||
t = 1 234 831 232 div 900 = 1 372 034
|
||||
Calculate codeword 3
|
||||
d3 = 1 372 034 mod 900 = 434
|
||||
|
||||
t = 1 372 034 div 900 = 1 524
|
||||
Calculate codeword 4
|
||||
d4 = 1 524 mod 900 = 624
|
||||
|
||||
t = 1 524 div 900 = 1
|
||||
Calculate codeword 5
|
||||
d5 = 1 mod 900 = 1
|
||||
t = 1 div 900 = 0
|
||||
Codeword sequence is: 1, 624, 434, 632, 282, 200
|
||||
|
||||
Decode the above codewords involves
|
||||
1 x 900 power of 5 + 624 x 900 power of 4 + 434 x 900 power of 3 +
|
||||
632 x 900 power of 2 + 282 x 900 power of 1 + 200 x 900 power of 0 = 1000213298174000
|
||||
|
||||
Remove leading 1 => RXingResult is 000213298174000
|
||||
*/
|
||||
fn decodeBase900toBase10(codewords: &[u32], count: usize) -> Result<String, Exceptions> {
|
||||
let mut result = 0.to_biguint().unwrap();
|
||||
for i in 0..count {
|
||||
// for (int i = 0; i < count; i++) {
|
||||
result += &EXP900[count - i - 1] * (codewords[i].to_biguint().unwrap());
|
||||
// result = result.add(EXP900[count - i - 1].multiply(BigInteger.valueOf(codewords[i])));
|
||||
}
|
||||
let resultString = result.to_string();
|
||||
if resultString.chars().nth(0).unwrap() != '1' {
|
||||
return Err(Exceptions::FormatException("".to_owned()));
|
||||
}
|
||||
Ok(resultString[1..].to_owned())
|
||||
}
|
||||
@@ -14,13 +14,13 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
use std::fmt::Display;
|
||||
use std::{fmt::Display, rc::Rc};
|
||||
|
||||
use crate::pdf417::pdf_417_common;
|
||||
|
||||
use super::{
|
||||
BarcodeMetadata, BoundingBox, Codeword, DetectionRXingResultColumn,
|
||||
DetectionRXingResultRowIndicatorColumn,
|
||||
DetectionRXingResultColumnTrait, DetectionRXingResultRowIndicatorColumn,
|
||||
};
|
||||
|
||||
const ADJUST_ROW_NUMBER_SKIP: u32 = 2;
|
||||
@@ -28,21 +28,25 @@ const ADJUST_ROW_NUMBER_SKIP: u32 = 2;
|
||||
/**
|
||||
* @author Guenther Grau
|
||||
*/
|
||||
pub struct DetectionRXingResult<'a> {
|
||||
pub struct DetectionRXingResult {
|
||||
barcodeMetadata: BarcodeMetadata,
|
||||
detectionRXingResultColumns: Vec<Option<DetectionRXingResultColumn<'a>>>,
|
||||
boundingBox: BoundingBox<'a>,
|
||||
detectionRXingResultColumns: Vec<Option<Box<dyn DetectionRXingResultColumnTrait>>>,
|
||||
boundingBox: Rc<BoundingBox>,
|
||||
barcodeColumnCount: usize,
|
||||
}
|
||||
|
||||
impl<'a> DetectionRXingResult<'_> {
|
||||
impl DetectionRXingResult {
|
||||
pub fn new(
|
||||
barcodeMetadata: BarcodeMetadata,
|
||||
boundingBox: BoundingBox<'a>,
|
||||
) -> DetectionRXingResult<'a> {
|
||||
boundingBox: Rc<BoundingBox>,
|
||||
) -> DetectionRXingResult {
|
||||
let mut columns = Vec::new();
|
||||
for i in 0..(barcodeMetadata.getColumnCount() as usize + 2) {
|
||||
columns.push(None);
|
||||
}
|
||||
DetectionRXingResult {
|
||||
barcodeColumnCount: barcodeMetadata.getColumnCount() as usize,
|
||||
detectionRXingResultColumns: vec![None; barcodeMetadata.getColumnCount() as usize + 2],
|
||||
detectionRXingResultColumns: columns, //vec![None; barcodeMetadata.getColumnCount() as usize + 2],
|
||||
barcodeMetadata,
|
||||
boundingBox,
|
||||
}
|
||||
@@ -52,7 +56,9 @@ impl<'a> DetectionRXingResult<'_> {
|
||||
// detectionRXingResultColumns = new DetectionRXingResultColumn[barcodeColumnCount + 2];
|
||||
}
|
||||
|
||||
pub fn getDetectionRXingResultColumns(&mut self) -> &Vec<Option<DetectionRXingResultColumn>> {
|
||||
pub fn getDetectionRXingResultColumns(
|
||||
&mut self,
|
||||
) -> &Vec<Option<Box<dyn DetectionRXingResultColumnTrait>>> {
|
||||
self.adjustIndicatorColumnRowNumbers(0);
|
||||
let pos = self.barcodeColumnCount + 1;
|
||||
self.adjustIndicatorColumnRowNumbers(pos);
|
||||
@@ -81,6 +87,7 @@ impl<'a> DetectionRXingResult<'_> {
|
||||
self.detectionRXingResultColumns[pos]
|
||||
.as_mut()
|
||||
.unwrap()
|
||||
.as_indicator_row()
|
||||
.adjustCompleteIndicatorColumnRowNumbers(&self.barcodeMetadata);
|
||||
}
|
||||
}
|
||||
@@ -515,27 +522,35 @@ impl<'a> DetectionRXingResult<'_> {
|
||||
self.barcodeMetadata.getErrorCorrectionLevel()
|
||||
}
|
||||
|
||||
// pub fn setBoundingBox(&'a mut self, boundingBox:BoundingBox<'a>) {
|
||||
// self.boundingBox = boundingBox;
|
||||
// }
|
||||
|
||||
pub fn getBoundingBox(&self) -> &BoundingBox {
|
||||
&self.boundingBox
|
||||
pub fn setBoundingBox(&mut self, boundingBox: Rc<BoundingBox>) {
|
||||
self.boundingBox = boundingBox;
|
||||
}
|
||||
|
||||
// pub fn setDetectionRXingResultColumn(&mut self, barcodeColumn:usize, detectionRXingResultColumn:Option<DetectionRXingResultColumn<'a>>) {
|
||||
// self.detectionRXingResultColumns[barcodeColumn] = detectionRXingResultColumn;
|
||||
// }
|
||||
pub fn getBoundingBox(&self) -> Rc<BoundingBox> {
|
||||
self.boundingBox.clone()
|
||||
}
|
||||
|
||||
pub fn setDetectionRXingResultColumn(
|
||||
&mut self,
|
||||
barcodeColumn: usize,
|
||||
detectionRXingResultColumn: Option<impl DetectionRXingResultRowIndicatorColumn + 'static>,
|
||||
) {
|
||||
self.detectionRXingResultColumns[barcodeColumn] = if detectionRXingResultColumn.is_none() {
|
||||
None
|
||||
} else {
|
||||
Some(Box::new(detectionRXingResultColumn.unwrap()))
|
||||
};
|
||||
}
|
||||
|
||||
pub fn getDetectionRXingResultColumn(
|
||||
&self,
|
||||
barcodeColumn: usize,
|
||||
) -> &Option<DetectionRXingResultColumn> {
|
||||
) -> &Option<Box<dyn DetectionRXingResultColumnTrait>> {
|
||||
&self.detectionRXingResultColumns[barcodeColumn]
|
||||
}
|
||||
}
|
||||
|
||||
impl Display for DetectionRXingResult<'_> {
|
||||
impl Display for DetectionRXingResult {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
todo!()
|
||||
}
|
||||
|
||||
@@ -14,26 +14,43 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
use std::fmt::Display;
|
||||
use std::{fmt::Display, rc::Rc};
|
||||
|
||||
use super::{BoundingBox, Codeword, DetectionRXingResultRowIndicatorColumn};
|
||||
|
||||
const MAX_NEARBY_DISTANCE: u32 = 5;
|
||||
|
||||
pub trait DetectionRXingResultColumnTrait {
|
||||
fn new(boundingBox: Rc<BoundingBox>) -> DetectionRXingResultColumn
|
||||
where
|
||||
Self: Sized;
|
||||
fn new_with_is_left(boundingBox: Rc<BoundingBox>, isLeft: bool) -> DetectionRXingResultColumn
|
||||
where
|
||||
Self: Sized;
|
||||
fn getCodewordNearby(&self, imageRow: u32) -> &Option<Codeword>;
|
||||
fn imageRowToCodewordIndex(&self, imageRow: u32) -> usize;
|
||||
fn setCodeword(&mut self, imageRow: u32, codeword: Codeword);
|
||||
fn getCodeword(&self, imageRow: u32) -> &Option<Codeword>;
|
||||
fn getBoundingBox(&self) -> &BoundingBox;
|
||||
fn getCodewords(&self) -> &[Option<Codeword>];
|
||||
fn getCodewordsMut(&mut self) -> &mut [Option<Codeword>];
|
||||
fn as_indicator_row(&mut self) -> &mut dyn DetectionRXingResultRowIndicatorColumn;
|
||||
}
|
||||
|
||||
/**
|
||||
* @author Guenther Grau
|
||||
*/
|
||||
#[derive(Clone)]
|
||||
pub struct DetectionRXingResultColumn<'a> {
|
||||
boundingBox: BoundingBox<'a>,
|
||||
pub struct DetectionRXingResultColumn {
|
||||
boundingBox: BoundingBox,
|
||||
codewords: Vec<Option<Codeword>>,
|
||||
pub(super) isLeft: Option<bool>,
|
||||
}
|
||||
|
||||
impl<'a> DetectionRXingResultColumn<'_> {
|
||||
pub fn new(boundingBox: &'a BoundingBox) -> DetectionRXingResultColumn<'a> {
|
||||
impl DetectionRXingResultColumnTrait for DetectionRXingResultColumn {
|
||||
fn new(boundingBox: Rc<BoundingBox>) -> DetectionRXingResultColumn {
|
||||
DetectionRXingResultColumn {
|
||||
boundingBox: BoundingBox::from_other(boundingBox),
|
||||
boundingBox: BoundingBox::from_other(boundingBox.clone()),
|
||||
codewords: vec![None; (boundingBox.getMaxY() - boundingBox.getMinY() + 1) as usize],
|
||||
isLeft: None,
|
||||
}
|
||||
@@ -41,18 +58,15 @@ impl<'a> DetectionRXingResultColumn<'_> {
|
||||
// codewords = new Codeword[boundingBox.getMaxY() - boundingBox.getMinY() + 1];
|
||||
}
|
||||
|
||||
pub fn new_with_is_left(
|
||||
boundingBox: &'a BoundingBox,
|
||||
isLeft: bool,
|
||||
) -> DetectionRXingResultColumn<'a> {
|
||||
fn new_with_is_left(boundingBox: Rc<BoundingBox>, isLeft: bool) -> DetectionRXingResultColumn {
|
||||
DetectionRXingResultColumn {
|
||||
boundingBox: BoundingBox::from_other(boundingBox),
|
||||
boundingBox: BoundingBox::from_other(boundingBox.clone()),
|
||||
codewords: vec![None; (boundingBox.getMaxY() - boundingBox.getMinY() + 1) as usize],
|
||||
isLeft: Some(isLeft),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn getCodewordNearby(&self, imageRow: u32) -> &Option<Codeword> {
|
||||
fn getCodewordNearby(&self, imageRow: u32) -> &Option<Codeword> {
|
||||
let mut codeword = self.getCodeword(imageRow);
|
||||
if codeword.is_some() {
|
||||
return codeword;
|
||||
@@ -77,35 +91,40 @@ impl<'a> DetectionRXingResultColumn<'_> {
|
||||
&None
|
||||
}
|
||||
|
||||
pub fn imageRowToCodewordIndex(&self, imageRow: u32) -> usize {
|
||||
fn imageRowToCodewordIndex(&self, imageRow: u32) -> usize {
|
||||
(imageRow - self.boundingBox.getMinY()) as usize
|
||||
}
|
||||
|
||||
pub fn setCodeword(&mut self, imageRow: u32, codeword: Codeword) {
|
||||
fn setCodeword(&mut self, imageRow: u32, codeword: Codeword) {
|
||||
let pos = self.imageRowToCodewordIndex(imageRow);
|
||||
self.codewords[pos] = Some(codeword);
|
||||
}
|
||||
|
||||
pub fn getCodeword(&self, imageRow: u32) -> &Option<Codeword> {
|
||||
fn getCodeword(&self, imageRow: u32) -> &Option<Codeword> {
|
||||
&self.codewords[self.imageRowToCodewordIndex(imageRow)]
|
||||
}
|
||||
|
||||
pub fn getBoundingBox(&self) -> &BoundingBox {
|
||||
fn getBoundingBox(&self) -> &BoundingBox {
|
||||
&self.boundingBox
|
||||
}
|
||||
|
||||
pub fn getCodewords(&self) -> &[Option<Codeword>] {
|
||||
fn getCodewords(&self) -> &[Option<Codeword>] {
|
||||
&self.codewords
|
||||
}
|
||||
pub(super) fn getCodewordsMut(&mut self) -> &mut [Option<Codeword>] {
|
||||
|
||||
fn getCodewordsMut(&mut self) -> &mut [Option<Codeword>] {
|
||||
&mut self.codewords
|
||||
}
|
||||
|
||||
fn as_indicator_row(&mut self) -> &mut dyn DetectionRXingResultRowIndicatorColumn {
|
||||
self as &mut dyn DetectionRXingResultRowIndicatorColumn
|
||||
}
|
||||
// pub fn as_row_indicator(&self) -> DetectionRXingResultRowIndicatorColumn {
|
||||
// DetectionRXingResultRowIndicatorColumn::new(&self.boundingBox, false)
|
||||
// }
|
||||
}
|
||||
|
||||
impl Display for DetectionRXingResultColumn<'_> {
|
||||
impl Display for DetectionRXingResultColumn {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
if self.isLeft.is_some() {
|
||||
write!(f, "IsLeft: {} \n", self.isLeft.as_ref().unwrap());
|
||||
|
||||
@@ -18,12 +18,15 @@ use std::fmt::Display;
|
||||
|
||||
use crate::{pdf417::pdf_417_common, ResultPoint};
|
||||
|
||||
use super::{BarcodeMetadata, BarcodeValue, BoundingBox, Codeword, DetectionRXingResultColumn};
|
||||
use super::{
|
||||
BarcodeMetadata, BarcodeValue, BoundingBox, Codeword, DetectionRXingResultColumn,
|
||||
DetectionRXingResultColumnTrait,
|
||||
};
|
||||
|
||||
/**
|
||||
* @author Guenther Grau
|
||||
*/
|
||||
pub trait DetectionRXingResultRowIndicatorColumn {
|
||||
pub trait DetectionRXingResultRowIndicatorColumn: DetectionRXingResultColumnTrait {
|
||||
// TODO implement properly
|
||||
// TODO maybe we should add missing codewords to store the correct row number to make
|
||||
// finding row numbers for other columns easier
|
||||
@@ -34,7 +37,7 @@ pub trait DetectionRXingResultRowIndicatorColumn {
|
||||
fn isLeft(&self) -> bool;
|
||||
}
|
||||
|
||||
impl<'a> DetectionRXingResultRowIndicatorColumn for DetectionRXingResultColumn<'_> {
|
||||
impl DetectionRXingResultRowIndicatorColumn for DetectionRXingResultColumn {
|
||||
// private final boolean isLeft;
|
||||
|
||||
// TODO implement properly
|
||||
|
||||
@@ -23,4 +23,5 @@ pub use detection_result_row_indicator_column::*;
|
||||
mod detection_result;
|
||||
pub use detection_result::*;
|
||||
|
||||
// pub mod pdf_417_scanning_decoder;
|
||||
pub mod decoded_bit_stream_parser;
|
||||
pub mod pdf_417_scanning_decoder;
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -3,3 +3,6 @@ pub mod detector;
|
||||
pub mod encoder;
|
||||
|
||||
pub mod pdf_417_common;
|
||||
|
||||
mod pdf_417_result_metadata;
|
||||
pub use pdf_417_result_metadata::*;
|
||||
|
||||
@@ -43,18 +43,18 @@ pub fn getBitCountSum(moduleBitCount: &[u32]) -> u32 {
|
||||
moduleBitCount.iter().sum::<u32>()
|
||||
}
|
||||
|
||||
pub fn toIntArray(list: Vec<u32>) -> Vec<u32> {
|
||||
// if (list == null || list.isEmpty()) {
|
||||
// return EMPTY_INT_ARRAY;
|
||||
// }
|
||||
// int[] result = new int[list.size()];
|
||||
// int i = 0;
|
||||
// for (Integer integer : list) {
|
||||
// result[i++] = integer;
|
||||
// }
|
||||
// return result;
|
||||
list
|
||||
}
|
||||
// pub fn toIntArray(list: Vec<u32>) -> Vec<u32> {
|
||||
// // if (list == null || list.isEmpty()) {
|
||||
// // return EMPTY_INT_ARRAY;
|
||||
// // }
|
||||
// // int[] result = new int[list.size()];
|
||||
// // int i = 0;
|
||||
// // for (Integer integer : list) {
|
||||
// // result[i++] = integer;
|
||||
// // }
|
||||
// // return result;
|
||||
// list
|
||||
// }
|
||||
|
||||
/**
|
||||
* @param symbol encoded symbol to translate to a codeword
|
||||
|
||||
186
src/pdf417/pdf_417_result_metadata.rs
Normal file
186
src/pdf417/pdf_417_result_metadata.rs
Normal file
@@ -0,0 +1,186 @@
|
||||
/*
|
||||
* Copyright 2013 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.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @author Guenther Grau
|
||||
*/
|
||||
pub struct PDF417RXingResultMetadata {
|
||||
segmentIndex: usize,
|
||||
fileId: String,
|
||||
lastSegment: bool,
|
||||
segmentCount: isize,
|
||||
sender: String,
|
||||
addressee: String,
|
||||
fileName: String,
|
||||
fileSize: i64,
|
||||
timestamp: i64,
|
||||
checksum: i32,
|
||||
optionalData: Vec<u32>,
|
||||
}
|
||||
|
||||
impl Default for PDF417RXingResultMetadata {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
segmentIndex: Default::default(),
|
||||
fileId: Default::default(),
|
||||
lastSegment: Default::default(),
|
||||
segmentCount: -1,
|
||||
sender: Default::default(),
|
||||
addressee: Default::default(),
|
||||
fileName: Default::default(),
|
||||
fileSize: -1,
|
||||
timestamp: -1,
|
||||
checksum: -1,
|
||||
optionalData: Default::default(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl PDF417RXingResultMetadata {
|
||||
/**
|
||||
* The Segment ID represents the segment of the whole file distributed over different symbols.
|
||||
*
|
||||
* @return File segment index
|
||||
*/
|
||||
pub fn getSegmentIndex(&self) -> usize {
|
||||
self.segmentIndex
|
||||
}
|
||||
|
||||
pub fn setSegmentIndex(&mut self, segmentIndex: usize) {
|
||||
self.segmentIndex = segmentIndex;
|
||||
}
|
||||
|
||||
/**
|
||||
* Is the same for each related PDF417 symbol
|
||||
*
|
||||
* @return File ID
|
||||
*/
|
||||
pub fn getFileId(&self) -> &str {
|
||||
&self.fileId
|
||||
}
|
||||
|
||||
pub fn setFileId(&mut self, fileId: String) {
|
||||
self.fileId = fileId;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return always null
|
||||
* @deprecated use dedicated already parsed fields
|
||||
*/
|
||||
#[deprecated]
|
||||
pub fn getOptionalData(&self) -> &[u32] {
|
||||
&self.optionalData
|
||||
}
|
||||
|
||||
/**
|
||||
* @param optionalData old optional data format as int array
|
||||
* @deprecated parse and use new fields
|
||||
*/
|
||||
#[deprecated]
|
||||
pub fn setOptionalData(&mut self, optionalData: Vec<u32>) {
|
||||
self.optionalData = optionalData;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return true if it is the last segment
|
||||
*/
|
||||
pub fn isLastSegment(&self) -> bool {
|
||||
self.lastSegment
|
||||
}
|
||||
|
||||
pub fn setLastSegment(&mut self, lastSegment: bool) {
|
||||
self.lastSegment = lastSegment;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return count of segments, -1 if not set
|
||||
*/
|
||||
pub fn getSegmentCount(&self) -> isize {
|
||||
self.segmentCount
|
||||
}
|
||||
|
||||
pub fn setSegmentCount(&mut self, segmentCount: isize) {
|
||||
self.segmentCount = segmentCount;
|
||||
}
|
||||
|
||||
pub fn getSender(&self) -> &str {
|
||||
&self.sender
|
||||
}
|
||||
|
||||
pub fn setSender(&mut self, sender: String) {
|
||||
self.sender = sender;
|
||||
}
|
||||
|
||||
pub fn getAddressee(&self) -> &str {
|
||||
&self.addressee
|
||||
}
|
||||
|
||||
pub fn setAddressee(&mut self, addressee: String) {
|
||||
self.addressee = addressee;
|
||||
}
|
||||
|
||||
/**
|
||||
* Filename of the encoded file
|
||||
*
|
||||
* @return filename
|
||||
*/
|
||||
pub fn getFileName(&self) -> &str {
|
||||
&self.fileName
|
||||
}
|
||||
|
||||
pub fn setFileName(&mut self, fileName: String) {
|
||||
self.fileName = fileName;
|
||||
}
|
||||
|
||||
/**
|
||||
* filesize in bytes of the encoded file
|
||||
*
|
||||
* @return filesize in bytes, -1 if not set
|
||||
*/
|
||||
pub fn getFileSize(&self) -> i64 {
|
||||
self.fileSize
|
||||
}
|
||||
|
||||
pub fn setFileSize(&mut self, fileSize: i64) {
|
||||
self.fileSize = fileSize;
|
||||
}
|
||||
|
||||
/**
|
||||
* 16-bit CRC checksum using CCITT-16
|
||||
*
|
||||
* @return crc checksum, -1 if not set
|
||||
*/
|
||||
pub fn getChecksum(&self) -> i32 {
|
||||
self.checksum
|
||||
}
|
||||
|
||||
pub fn setChecksum(&mut self, checksum: i32) {
|
||||
self.checksum = checksum;
|
||||
}
|
||||
|
||||
/**
|
||||
* unix epock timestamp, elapsed seconds since 1970-01-01
|
||||
*
|
||||
* @return elapsed seconds, -1 if not set
|
||||
*/
|
||||
pub fn getTimestamp(&self) -> i64 {
|
||||
self.timestamp
|
||||
}
|
||||
|
||||
pub fn setTimestamp(&mut self, timestamp: i64) {
|
||||
self.timestamp = timestamp;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user