mirror of
https://github.com/starovoid/rxing.git
synced 2026-07-26 04:12:34 +00:00
partial working code39
This commit is contained in:
@@ -74,10 +74,6 @@ fn impl_one_d_reader_macro(ast: &syn::DeriveInput) -> TokenStream {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn reset(&mut self) {
|
|
||||||
// do nothing
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
gen.into()
|
gen.into()
|
||||||
|
|||||||
@@ -16,6 +16,8 @@
|
|||||||
|
|
||||||
//package com.google.zxing;
|
//package com.google.zxing;
|
||||||
|
|
||||||
|
use std::collections::HashSet;
|
||||||
|
|
||||||
use crate::{BarcodeFormat, RXingResultPointCallback};
|
use crate::{BarcodeFormat, RXingResultPointCallback};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -141,7 +143,7 @@ pub enum DecodeHintValue {
|
|||||||
* Image is known to be of one of a few possible formats.
|
* Image is known to be of one of a few possible formats.
|
||||||
* Maps to a {@link List} of {@link BarcodeFormat}s.
|
* Maps to a {@link List} of {@link BarcodeFormat}s.
|
||||||
*/
|
*/
|
||||||
PossibleFormats(Vec<BarcodeFormat>),
|
PossibleFormats(HashSet<BarcodeFormat>),
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Spend more time to try to find a barcode; optimize for accuracy, not speed.
|
* Spend more time to try to find a barcode; optimize for accuracy, not speed.
|
||||||
|
|||||||
@@ -18,8 +18,8 @@ use std::collections::HashMap;
|
|||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
aztec::AztecReader, datamatrix::DataMatrixReader, maxicode::MaxiCodeReader,
|
aztec::AztecReader, datamatrix::DataMatrixReader, maxicode::MaxiCodeReader,
|
||||||
qrcode::QRCodeReader, BarcodeFormat, BinaryBitmap, DecodeHintType, DecodeHintValue,
|
oned::MultiFormatOneDReader, qrcode::QRCodeReader, BarcodeFormat, BinaryBitmap, DecodeHintType,
|
||||||
DecodingHintDictionary, Exceptions, RXingResult, Reader,
|
DecodeHintValue, DecodingHintDictionary, Exceptions, RXingResult, Reader,
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -124,8 +124,7 @@ impl MultiFormatReader {
|
|||||||
|| formats.contains(&BarcodeFormat::RSS_EXPANDED);
|
|| formats.contains(&BarcodeFormat::RSS_EXPANDED);
|
||||||
// Put 1D readers upfront in "normal" mode
|
// Put 1D readers upfront in "normal" mode
|
||||||
if addOneDReader && !tryHarder {
|
if addOneDReader && !tryHarder {
|
||||||
unimplemented!("");
|
readers.push(Box::new(MultiFormatOneDReader::new(hints)));
|
||||||
// readers.push(new MultiFormatOneDReader(hints));
|
|
||||||
}
|
}
|
||||||
if formats.contains(&BarcodeFormat::QR_CODE) {
|
if formats.contains(&BarcodeFormat::QR_CODE) {
|
||||||
readers.push(Box::new(QRCodeReader {}));
|
readers.push(Box::new(QRCodeReader {}));
|
||||||
@@ -145,13 +144,12 @@ impl MultiFormatReader {
|
|||||||
}
|
}
|
||||||
// At end in "try harder" mode
|
// At end in "try harder" mode
|
||||||
if addOneDReader && tryHarder {
|
if addOneDReader && tryHarder {
|
||||||
unimplemented!("");
|
readers.push(Box::new(MultiFormatOneDReader::new(hints)));
|
||||||
// readers.push( MultiFormatOneDReader::new(hints));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if readers.is_empty() {
|
if readers.is_empty() {
|
||||||
if !tryHarder {
|
if !tryHarder {
|
||||||
// readers.push( MultiFormatOneDReader::new(hints));
|
readers.push(Box::new(MultiFormatOneDReader::new(hints)));
|
||||||
//TODO: ADD MultiformatOneDReader here
|
//TODO: ADD MultiformatOneDReader here
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -163,7 +161,7 @@ impl MultiFormatReader {
|
|||||||
// unimplemented!("");
|
// unimplemented!("");
|
||||||
|
|
||||||
if tryHarder {
|
if tryHarder {
|
||||||
// readers.push( Box::new(MultiFormatOneDReader::new(hints)));
|
readers.push(Box::new(MultiFormatOneDReader::new(hints)));
|
||||||
//TODO: ADD MultiformatOneDReader here
|
//TODO: ADD MultiformatOneDReader here
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,340 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2008 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.oned;
|
|
||||||
|
|
||||||
import com.google.zxing.BarcodeFormat;
|
|
||||||
import com.google.zxing.ChecksumException;
|
|
||||||
import com.google.zxing.DecodeHintType;
|
|
||||||
import com.google.zxing.FormatException;
|
|
||||||
import com.google.zxing.NotFoundException;
|
|
||||||
import com.google.zxing.RXingResult;
|
|
||||||
import com.google.zxing.RXingResultMetadataType;
|
|
||||||
import com.google.zxing.RXingResultPoint;
|
|
||||||
import com.google.zxing.common.BitArray;
|
|
||||||
|
|
||||||
import java.util.Arrays;
|
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* <p>Decodes Code 39 barcodes. Supports "Full ASCII Code 39" if USE_CODE_39_EXTENDED_MODE is set.</p>
|
|
||||||
*
|
|
||||||
* @author Sean Owen
|
|
||||||
* @see Code93Reader
|
|
||||||
*/
|
|
||||||
public final class Code39Reader extends OneDReader {
|
|
||||||
|
|
||||||
static final String ALPHABET_STRING = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ-. $/+%";
|
|
||||||
|
|
||||||
/**
|
|
||||||
* These represent the encodings of characters, as patterns of wide and narrow bars.
|
|
||||||
* The 9 least-significant bits of each int correspond to the pattern of wide and narrow,
|
|
||||||
* with 1s representing "wide" and 0s representing narrow.
|
|
||||||
*/
|
|
||||||
static final int[] CHARACTER_ENCODINGS = {
|
|
||||||
0x034, 0x121, 0x061, 0x160, 0x031, 0x130, 0x070, 0x025, 0x124, 0x064, // 0-9
|
|
||||||
0x109, 0x049, 0x148, 0x019, 0x118, 0x058, 0x00D, 0x10C, 0x04C, 0x01C, // A-J
|
|
||||||
0x103, 0x043, 0x142, 0x013, 0x112, 0x052, 0x007, 0x106, 0x046, 0x016, // K-T
|
|
||||||
0x181, 0x0C1, 0x1C0, 0x091, 0x190, 0x0D0, 0x085, 0x184, 0x0C4, 0x0A8, // U-$
|
|
||||||
0x0A2, 0x08A, 0x02A // /-%
|
|
||||||
};
|
|
||||||
|
|
||||||
static final int ASTERISK_ENCODING = 0x094;
|
|
||||||
|
|
||||||
private final boolean usingCheckDigit;
|
|
||||||
private final boolean extendedMode;
|
|
||||||
private final StringBuilder decodeRowRXingResult;
|
|
||||||
private final int[] counters;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates a reader that assumes all encoded data is data, and does not treat the final
|
|
||||||
* character as a check digit. It will not decoded "extended Code 39" sequences.
|
|
||||||
*/
|
|
||||||
public Code39Reader() {
|
|
||||||
this(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates a reader that can be configured to check the last character as a check digit.
|
|
||||||
* It will not decoded "extended Code 39" sequences.
|
|
||||||
*
|
|
||||||
* @param usingCheckDigit if true, treat the last data character as a check digit, not
|
|
||||||
* data, and verify that the checksum passes.
|
|
||||||
*/
|
|
||||||
public Code39Reader(boolean usingCheckDigit) {
|
|
||||||
this(usingCheckDigit, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates a reader that can be configured to check the last character as a check digit,
|
|
||||||
* or optionally attempt to decode "extended Code 39" sequences that are used to encode
|
|
||||||
* the full ASCII character set.
|
|
||||||
*
|
|
||||||
* @param usingCheckDigit if true, treat the last data character as a check digit, not
|
|
||||||
* data, and verify that the checksum passes.
|
|
||||||
* @param extendedMode if true, will attempt to decode extended Code 39 sequences in the
|
|
||||||
* text.
|
|
||||||
*/
|
|
||||||
public Code39Reader(boolean usingCheckDigit, boolean extendedMode) {
|
|
||||||
this.usingCheckDigit = usingCheckDigit;
|
|
||||||
this.extendedMode = extendedMode;
|
|
||||||
decodeRowRXingResult = new StringBuilder(20);
|
|
||||||
counters = new int[9];
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public RXingResult decodeRow(int rowNumber, BitArray row, Map<DecodeHintType,?> hints)
|
|
||||||
throws NotFoundException, ChecksumException, FormatException {
|
|
||||||
|
|
||||||
int[] theCounters = counters;
|
|
||||||
Arrays.fill(theCounters, 0);
|
|
||||||
StringBuilder result = decodeRowRXingResult;
|
|
||||||
result.setLength(0);
|
|
||||||
|
|
||||||
int[] start = findAsteriskPattern(row, theCounters);
|
|
||||||
// Read off white space
|
|
||||||
int nextStart = row.getNextSet(start[1]);
|
|
||||||
int end = row.getSize();
|
|
||||||
|
|
||||||
char decodedChar;
|
|
||||||
int lastStart;
|
|
||||||
do {
|
|
||||||
recordPattern(row, nextStart, theCounters);
|
|
||||||
int pattern = toNarrowWidePattern(theCounters);
|
|
||||||
if (pattern < 0) {
|
|
||||||
throw NotFoundException.getNotFoundInstance();
|
|
||||||
}
|
|
||||||
decodedChar = patternToChar(pattern);
|
|
||||||
result.append(decodedChar);
|
|
||||||
lastStart = nextStart;
|
|
||||||
for (int counter : theCounters) {
|
|
||||||
nextStart += counter;
|
|
||||||
}
|
|
||||||
// Read off white space
|
|
||||||
nextStart = row.getNextSet(nextStart);
|
|
||||||
} while (decodedChar != '*');
|
|
||||||
result.setLength(result.length() - 1); // remove asterisk
|
|
||||||
|
|
||||||
// Look for whitespace after pattern:
|
|
||||||
int lastPatternSize = 0;
|
|
||||||
for (int counter : theCounters) {
|
|
||||||
lastPatternSize += counter;
|
|
||||||
}
|
|
||||||
int whiteSpaceAfterEnd = nextStart - lastStart - lastPatternSize;
|
|
||||||
// If 50% of last pattern size, following last pattern, is not whitespace, fail
|
|
||||||
// (but if it's whitespace to the very end of the image, that's OK)
|
|
||||||
if (nextStart != end && (whiteSpaceAfterEnd * 2) < lastPatternSize) {
|
|
||||||
throw NotFoundException.getNotFoundInstance();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (usingCheckDigit) {
|
|
||||||
int max = result.length() - 1;
|
|
||||||
int total = 0;
|
|
||||||
for (int i = 0; i < max; i++) {
|
|
||||||
total += ALPHABET_STRING.indexOf(decodeRowRXingResult.charAt(i));
|
|
||||||
}
|
|
||||||
if (result.charAt(max) != ALPHABET_STRING.charAt(total % 43)) {
|
|
||||||
throw ChecksumException.getChecksumInstance();
|
|
||||||
}
|
|
||||||
result.setLength(max);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (result.length() == 0) {
|
|
||||||
// false positive
|
|
||||||
throw NotFoundException.getNotFoundInstance();
|
|
||||||
}
|
|
||||||
|
|
||||||
String resultString;
|
|
||||||
if (extendedMode) {
|
|
||||||
resultString = decodeExtended(result);
|
|
||||||
} else {
|
|
||||||
resultString = result.toString();
|
|
||||||
}
|
|
||||||
|
|
||||||
float left = (start[1] + start[0]) / 2.0f;
|
|
||||||
float right = lastStart + lastPatternSize / 2.0f;
|
|
||||||
|
|
||||||
RXingResult resultObject = new RXingResult(
|
|
||||||
resultString,
|
|
||||||
null,
|
|
||||||
new RXingResultPoint[]{
|
|
||||||
new RXingResultPoint(left, rowNumber),
|
|
||||||
new RXingResultPoint(right, rowNumber)},
|
|
||||||
BarcodeFormat.CODE_39);
|
|
||||||
resultObject.putMetadata(RXingResultMetadataType.SYMBOLOGY_IDENTIFIER, "]A0");
|
|
||||||
return resultObject;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static int[] findAsteriskPattern(BitArray row, int[] counters) throws NotFoundException {
|
|
||||||
int width = row.getSize();
|
|
||||||
int rowOffset = row.getNextSet(0);
|
|
||||||
|
|
||||||
int counterPosition = 0;
|
|
||||||
int patternStart = rowOffset;
|
|
||||||
boolean isWhite = false;
|
|
||||||
int patternLength = counters.length;
|
|
||||||
|
|
||||||
for (int i = rowOffset; i < width; i++) {
|
|
||||||
if (row.get(i) != isWhite) {
|
|
||||||
counters[counterPosition]++;
|
|
||||||
} else {
|
|
||||||
if (counterPosition == patternLength - 1) {
|
|
||||||
// Look for whitespace before start pattern, >= 50% of width of start pattern
|
|
||||||
if (toNarrowWidePattern(counters) == ASTERISK_ENCODING &&
|
|
||||||
row.isRange(Math.max(0, patternStart - ((i - patternStart) / 2)), patternStart, false)) {
|
|
||||||
return new int[]{patternStart, i};
|
|
||||||
}
|
|
||||||
patternStart += counters[0] + counters[1];
|
|
||||||
System.arraycopy(counters, 2, counters, 0, counterPosition - 1);
|
|
||||||
counters[counterPosition - 1] = 0;
|
|
||||||
counters[counterPosition] = 0;
|
|
||||||
counterPosition--;
|
|
||||||
} else {
|
|
||||||
counterPosition++;
|
|
||||||
}
|
|
||||||
counters[counterPosition] = 1;
|
|
||||||
isWhite = !isWhite;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
throw NotFoundException.getNotFoundInstance();
|
|
||||||
}
|
|
||||||
|
|
||||||
// For efficiency, returns -1 on failure. Not throwing here saved as many as 700 exceptions
|
|
||||||
// per image when using some of our blackbox images.
|
|
||||||
private static int toNarrowWidePattern(int[] counters) {
|
|
||||||
int numCounters = counters.length;
|
|
||||||
int maxNarrowCounter = 0;
|
|
||||||
int wideCounters;
|
|
||||||
do {
|
|
||||||
int minCounter = Integer.MAX_VALUE;
|
|
||||||
for (int counter : counters) {
|
|
||||||
if (counter < minCounter && counter > maxNarrowCounter) {
|
|
||||||
minCounter = counter;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
maxNarrowCounter = minCounter;
|
|
||||||
wideCounters = 0;
|
|
||||||
int totalWideCountersWidth = 0;
|
|
||||||
int pattern = 0;
|
|
||||||
for (int i = 0; i < numCounters; i++) {
|
|
||||||
int counter = counters[i];
|
|
||||||
if (counter > maxNarrowCounter) {
|
|
||||||
pattern |= 1 << (numCounters - 1 - i);
|
|
||||||
wideCounters++;
|
|
||||||
totalWideCountersWidth += counter;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (wideCounters == 3) {
|
|
||||||
// Found 3 wide counters, but are they close enough in width?
|
|
||||||
// We can perform a cheap, conservative check to see if any individual
|
|
||||||
// counter is more than 1.5 times the average:
|
|
||||||
for (int i = 0; i < numCounters && wideCounters > 0; i++) {
|
|
||||||
int counter = counters[i];
|
|
||||||
if (counter > maxNarrowCounter) {
|
|
||||||
wideCounters--;
|
|
||||||
// totalWideCountersWidth = 3 * average, so this checks if counter >= 3/2 * average
|
|
||||||
if ((counter * 2) >= totalWideCountersWidth) {
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return pattern;
|
|
||||||
}
|
|
||||||
} while (wideCounters > 3);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static char patternToChar(int pattern) throws NotFoundException {
|
|
||||||
for (int i = 0; i < CHARACTER_ENCODINGS.length; i++) {
|
|
||||||
if (CHARACTER_ENCODINGS[i] == pattern) {
|
|
||||||
return ALPHABET_STRING.charAt(i);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (pattern == ASTERISK_ENCODING) {
|
|
||||||
return '*';
|
|
||||||
}
|
|
||||||
throw NotFoundException.getNotFoundInstance();
|
|
||||||
}
|
|
||||||
|
|
||||||
private static String decodeExtended(CharSequence encoded) throws FormatException {
|
|
||||||
int length = encoded.length();
|
|
||||||
StringBuilder decoded = new StringBuilder(length);
|
|
||||||
for (int i = 0; i < length; i++) {
|
|
||||||
char c = encoded.charAt(i);
|
|
||||||
if (c == '+' || c == '$' || c == '%' || c == '/') {
|
|
||||||
char next = encoded.charAt(i + 1);
|
|
||||||
char decodedChar = '\0';
|
|
||||||
switch (c) {
|
|
||||||
case '+':
|
|
||||||
// +A to +Z map to a to z
|
|
||||||
if (next >= 'A' && next <= 'Z') {
|
|
||||||
decodedChar = (char) (next + 32);
|
|
||||||
} else {
|
|
||||||
throw FormatException.getFormatInstance();
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case '$':
|
|
||||||
// $A to $Z map to control codes SH to SB
|
|
||||||
if (next >= 'A' && next <= 'Z') {
|
|
||||||
decodedChar = (char) (next - 64);
|
|
||||||
} else {
|
|
||||||
throw FormatException.getFormatInstance();
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case '%':
|
|
||||||
// %A to %E map to control codes ESC to US
|
|
||||||
if (next >= 'A' && next <= 'E') {
|
|
||||||
decodedChar = (char) (next - 38);
|
|
||||||
} else if (next >= 'F' && next <= 'J') {
|
|
||||||
decodedChar = (char) (next - 11);
|
|
||||||
} else if (next >= 'K' && next <= 'O') {
|
|
||||||
decodedChar = (char) (next + 16);
|
|
||||||
} else if (next >= 'P' && next <= 'T') {
|
|
||||||
decodedChar = (char) (next + 43);
|
|
||||||
} else if (next == 'U') {
|
|
||||||
decodedChar = (char) 0;
|
|
||||||
} else if (next == 'V') {
|
|
||||||
decodedChar = '@';
|
|
||||||
} else if (next == 'W') {
|
|
||||||
decodedChar = '`';
|
|
||||||
} else if (next == 'X' || next == 'Y' || next == 'Z') {
|
|
||||||
decodedChar = (char) 127;
|
|
||||||
} else {
|
|
||||||
throw FormatException.getFormatInstance();
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case '/':
|
|
||||||
// /A to /O map to ! to , and /Z maps to :
|
|
||||||
if (next >= 'A' && next <= 'O') {
|
|
||||||
decodedChar = (char) (next - 32);
|
|
||||||
} else if (next == 'Z') {
|
|
||||||
decodedChar = ':';
|
|
||||||
} else {
|
|
||||||
throw FormatException.getFormatInstance();
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
decoded.append(decodedChar);
|
|
||||||
// bump up i again since we read two characters
|
|
||||||
i++;
|
|
||||||
} else {
|
|
||||||
decoded.append(c);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return decoded.toString();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,114 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2008 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.oned;
|
|
||||||
|
|
||||||
import com.google.zxing.BarcodeFormat;
|
|
||||||
import com.google.zxing.DecodeHintType;
|
|
||||||
import com.google.zxing.NotFoundException;
|
|
||||||
import com.google.zxing.Reader;
|
|
||||||
import com.google.zxing.ReaderException;
|
|
||||||
import com.google.zxing.RXingResult;
|
|
||||||
import com.google.zxing.common.BitArray;
|
|
||||||
import com.google.zxing.oned.rss.RSS14Reader;
|
|
||||||
import com.google.zxing.oned.rss.expanded.RSSExpandedReader;
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.Collection;
|
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @author dswitkin@google.com (Daniel Switkin)
|
|
||||||
* @author Sean Owen
|
|
||||||
*/
|
|
||||||
public final class MultiFormatOneDReader extends OneDReader {
|
|
||||||
|
|
||||||
private static final OneDReader[] EMPTY_ONED_ARRAY = new OneDReader[0];
|
|
||||||
|
|
||||||
private final OneDReader[] readers;
|
|
||||||
|
|
||||||
public MultiFormatOneDReader(Map<DecodeHintType,?> hints) {
|
|
||||||
@SuppressWarnings("unchecked")
|
|
||||||
Collection<BarcodeFormat> possibleFormats = hints == null ? null :
|
|
||||||
(Collection<BarcodeFormat>) hints.get(DecodeHintType.POSSIBLE_FORMATS);
|
|
||||||
boolean useCode39CheckDigit = hints != null &&
|
|
||||||
hints.get(DecodeHintType.ASSUME_CODE_39_CHECK_DIGIT) != null;
|
|
||||||
Collection<OneDReader> readers = new ArrayList<>();
|
|
||||||
if (possibleFormats != null) {
|
|
||||||
if (possibleFormats.contains(BarcodeFormat.EAN_13) ||
|
|
||||||
possibleFormats.contains(BarcodeFormat.UPC_A) ||
|
|
||||||
possibleFormats.contains(BarcodeFormat.EAN_8) ||
|
|
||||||
possibleFormats.contains(BarcodeFormat.UPC_E)) {
|
|
||||||
readers.add(new MultiFormatUPCEANReader(hints));
|
|
||||||
}
|
|
||||||
if (possibleFormats.contains(BarcodeFormat.CODE_39)) {
|
|
||||||
readers.add(new Code39Reader(useCode39CheckDigit));
|
|
||||||
}
|
|
||||||
if (possibleFormats.contains(BarcodeFormat.CODE_93)) {
|
|
||||||
readers.add(new Code93Reader());
|
|
||||||
}
|
|
||||||
if (possibleFormats.contains(BarcodeFormat.CODE_128)) {
|
|
||||||
readers.add(new Code128Reader());
|
|
||||||
}
|
|
||||||
if (possibleFormats.contains(BarcodeFormat.ITF)) {
|
|
||||||
readers.add(new ITFReader());
|
|
||||||
}
|
|
||||||
if (possibleFormats.contains(BarcodeFormat.CODABAR)) {
|
|
||||||
readers.add(new CodaBarReader());
|
|
||||||
}
|
|
||||||
if (possibleFormats.contains(BarcodeFormat.RSS_14)) {
|
|
||||||
readers.add(new RSS14Reader());
|
|
||||||
}
|
|
||||||
if (possibleFormats.contains(BarcodeFormat.RSS_EXPANDED)) {
|
|
||||||
readers.add(new RSSExpandedReader());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (readers.isEmpty()) {
|
|
||||||
readers.add(new MultiFormatUPCEANReader(hints));
|
|
||||||
readers.add(new Code39Reader());
|
|
||||||
readers.add(new CodaBarReader());
|
|
||||||
readers.add(new Code93Reader());
|
|
||||||
readers.add(new Code128Reader());
|
|
||||||
readers.add(new ITFReader());
|
|
||||||
readers.add(new RSS14Reader());
|
|
||||||
readers.add(new RSSExpandedReader());
|
|
||||||
}
|
|
||||||
this.readers = readers.toArray(EMPTY_ONED_ARRAY);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public RXingResult decodeRow(int rowNumber,
|
|
||||||
BitArray row,
|
|
||||||
Map<DecodeHintType,?> hints) throws NotFoundException {
|
|
||||||
for (OneDReader reader : readers) {
|
|
||||||
try {
|
|
||||||
return reader.decodeRow(rowNumber, row, hints);
|
|
||||||
} catch (ReaderException re) {
|
|
||||||
// continue
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
throw NotFoundException.getNotFoundInstance();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void reset() {
|
|
||||||
for (Reader reader : readers) {
|
|
||||||
reader.reset();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -137,7 +137,7 @@ impl OneDReader for CodaBarReader {
|
|||||||
// self.decodeRowRXingResult.deleteCharAt(self.decodeRowRXingResult.chars().count() - 1);
|
// self.decodeRowRXingResult.deleteCharAt(self.decodeRowRXingResult.chars().count() - 1);
|
||||||
// self.decodeRowRXingResult.deleteCharAt(0);
|
// self.decodeRowRXingResult.deleteCharAt(0);
|
||||||
self.decodeRowRXingResult =
|
self.decodeRowRXingResult =
|
||||||
self.decodeRowRXingResult[1..self.decodeRowRXingResult.len()-1].to_owned();
|
self.decodeRowRXingResult[1..self.decodeRowRXingResult.len() - 1].to_owned();
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut runningCount = 0;
|
let mut runningCount = 0;
|
||||||
|
|||||||
419
src/oned/code_39_reader.rs
Normal file
419
src/oned/code_39_reader.rs
Normal file
@@ -0,0 +1,419 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2008 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 one_d_reader_derive::OneDReader;
|
||||||
|
|
||||||
|
use crate::common::BitArray;
|
||||||
|
use crate::{BarcodeFormat, Exceptions, RXingResult};
|
||||||
|
|
||||||
|
use super::OneDReader;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>Decodes Code 39 barcodes. Supports "Full ASCII Code 39" if USE_CODE_39_EXTENDED_MODE is set.</p>
|
||||||
|
*
|
||||||
|
* @author Sean Owen
|
||||||
|
* @see Code93Reader
|
||||||
|
*/
|
||||||
|
#[derive(OneDReader)]
|
||||||
|
pub struct Code39Reader {
|
||||||
|
usingCheckDigit: bool,
|
||||||
|
extendedMode: bool,
|
||||||
|
decodeRowRXingResult: String,
|
||||||
|
counters: Vec<u32>,
|
||||||
|
}
|
||||||
|
impl OneDReader for Code39Reader {
|
||||||
|
fn decodeRow(
|
||||||
|
&mut self,
|
||||||
|
rowNumber: u32,
|
||||||
|
row: &crate::common::BitArray,
|
||||||
|
_hints: &DecodingHintDictionary,
|
||||||
|
) -> Result<crate::RXingResult, Exceptions> {
|
||||||
|
// let theCounters = self.counters;
|
||||||
|
self.counters.fill(0);
|
||||||
|
// let result = self.decodeRowRXingResult;
|
||||||
|
// result.setLength(0);
|
||||||
|
self.decodeRowRXingResult.clear();
|
||||||
|
|
||||||
|
let start = Self::findAsteriskPattern(row, &mut self.counters)?;
|
||||||
|
// Read off white space
|
||||||
|
let mut nextStart = row.getNextSet(start[1] as usize);
|
||||||
|
let end = row.getSize();
|
||||||
|
|
||||||
|
let mut decodedChar;
|
||||||
|
let mut lastStart;
|
||||||
|
loop {
|
||||||
|
Self::recordPattern(row, nextStart, &mut self.counters)?;
|
||||||
|
let pattern = Self::toNarrowWidePattern(&self.counters);
|
||||||
|
if pattern < 0 {
|
||||||
|
return Err(Exceptions::NotFoundException("".to_owned()));
|
||||||
|
}
|
||||||
|
decodedChar = Self::patternToChar(pattern as u32)?;
|
||||||
|
self.decodeRowRXingResult.push(decodedChar);
|
||||||
|
lastStart = nextStart;
|
||||||
|
for counter in &self.counters {
|
||||||
|
// for (int counter : theCounters) {
|
||||||
|
nextStart += *counter as usize;
|
||||||
|
}
|
||||||
|
// Read off white space
|
||||||
|
nextStart = row.getNextSet(nextStart);
|
||||||
|
|
||||||
|
if !(decodedChar != '*') {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} //(decodedChar != '*');
|
||||||
|
self.decodeRowRXingResult
|
||||||
|
.truncate(self.decodeRowRXingResult.len() - 1); // remove asterisk
|
||||||
|
|
||||||
|
// Look for whitespace after pattern:
|
||||||
|
let mut lastPatternSize = 0;
|
||||||
|
for counter in &self.counters {
|
||||||
|
// for (int counter : self.counters) {
|
||||||
|
lastPatternSize += *counter;
|
||||||
|
}
|
||||||
|
let whiteSpaceAfterEnd = nextStart - lastStart - lastPatternSize as usize;
|
||||||
|
// If 50% of last pattern size, following last pattern, is not whitespace, fail
|
||||||
|
// (but if it's whitespace to the very end of the image, that's OK)
|
||||||
|
if nextStart != end && (whiteSpaceAfterEnd * 2) < lastPatternSize as usize {
|
||||||
|
return Err(Exceptions::NotFoundException("".to_owned()));
|
||||||
|
}
|
||||||
|
|
||||||
|
if self.usingCheckDigit {
|
||||||
|
let max = self.decodeRowRXingResult.chars().count() - 1;
|
||||||
|
let mut total = 0;
|
||||||
|
for i in 0..max {
|
||||||
|
// for (int i = 0; i < max; i++) {
|
||||||
|
if let Some(pos) =
|
||||||
|
Self::ALPHABET_STRING.find(self.decodeRowRXingResult.chars().nth(i).unwrap())
|
||||||
|
{
|
||||||
|
total += pos;
|
||||||
|
}
|
||||||
|
// total += Self::ALPHABET_STRING.indexOf(self.decodeRowRXingResult.chars().nth(i).unwrap());
|
||||||
|
}
|
||||||
|
if self.decodeRowRXingResult.chars().nth(max).unwrap()
|
||||||
|
!= Self::ALPHABET_STRING.chars().nth(total % 43).unwrap()
|
||||||
|
{
|
||||||
|
return Err(Exceptions::NotFoundException("".to_owned()));
|
||||||
|
}
|
||||||
|
self.decodeRowRXingResult.truncate(max);
|
||||||
|
}
|
||||||
|
|
||||||
|
if self.decodeRowRXingResult.chars().count() == 0 {
|
||||||
|
// false positive
|
||||||
|
return Err(Exceptions::NotFoundException("".to_owned()));
|
||||||
|
}
|
||||||
|
|
||||||
|
let resultString;
|
||||||
|
if self.extendedMode {
|
||||||
|
resultString = Self::decodeExtended(&self.decodeRowRXingResult)?;
|
||||||
|
} else {
|
||||||
|
resultString = self.decodeRowRXingResult.clone();
|
||||||
|
}
|
||||||
|
|
||||||
|
let left = (start[1] + start[0]) as f32 / 2.0;
|
||||||
|
let right = (lastStart + lastPatternSize as usize) as f32 / 2.0;
|
||||||
|
|
||||||
|
let mut resultObject = RXingResult::new(
|
||||||
|
&resultString,
|
||||||
|
Vec::new(),
|
||||||
|
vec![
|
||||||
|
RXingResultPoint::new(left, rowNumber as f32),
|
||||||
|
RXingResultPoint::new(right, rowNumber as f32),
|
||||||
|
],
|
||||||
|
BarcodeFormat::CODE_39,
|
||||||
|
);
|
||||||
|
|
||||||
|
resultObject.putMetadata(
|
||||||
|
RXingResultMetadataType::SYMBOLOGY_IDENTIFIER,
|
||||||
|
RXingResultMetadataValue::SymbologyIdentifier("]A0".to_owned()),
|
||||||
|
);
|
||||||
|
|
||||||
|
Ok(resultObject)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl Code39Reader {
|
||||||
|
const ALPHABET_STRING: &str = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ-. $/+%";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* These represent the encodings of characters, as patterns of wide and narrow bars.
|
||||||
|
* The 9 least-significant bits of each int correspond to the pattern of wide and narrow,
|
||||||
|
* with 1s representing "wide" and 0s representing narrow.
|
||||||
|
*/
|
||||||
|
const CHARACTER_ENCODINGS: [u32; 43] = [
|
||||||
|
0x034, 0x121, 0x061, 0x160, 0x031, 0x130, 0x070, 0x025, 0x124, 0x064, // 0-9
|
||||||
|
0x109, 0x049, 0x148, 0x019, 0x118, 0x058, 0x00D, 0x10C, 0x04C, 0x01C, // A-J
|
||||||
|
0x103, 0x043, 0x142, 0x013, 0x112, 0x052, 0x007, 0x106, 0x046, 0x016, // K-T
|
||||||
|
0x181, 0x0C1, 0x1C0, 0x091, 0x190, 0x0D0, 0x085, 0x184, 0x0C4, 0x0A8, // U-$
|
||||||
|
0x0A2, 0x08A, 0x02A, // /-%
|
||||||
|
];
|
||||||
|
|
||||||
|
const ASTERISK_ENCODING: u32 = 0x094;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a reader that assumes all encoded data is data, and does not treat the final
|
||||||
|
* character as a check digit. It will not decoded "extended Code 39" sequences.
|
||||||
|
*/
|
||||||
|
pub fn new() -> Self {
|
||||||
|
Self::with_use_check_digit(false)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a reader that can be configured to check the last character as a check digit.
|
||||||
|
* It will not decoded "extended Code 39" sequences.
|
||||||
|
*
|
||||||
|
* @param usingCheckDigit if true, treat the last data character as a check digit, not
|
||||||
|
* data, and verify that the checksum passes.
|
||||||
|
*/
|
||||||
|
pub fn with_use_check_digit(usingCheckDigit: bool) -> Self {
|
||||||
|
Self::with_all_config(usingCheckDigit, false)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a reader that can be configured to check the last character as a check digit,
|
||||||
|
* or optionally attempt to decode "extended Code 39" sequences that are used to encode
|
||||||
|
* the full ASCII character set.
|
||||||
|
*
|
||||||
|
* @param usingCheckDigit if true, treat the last data character as a check digit, not
|
||||||
|
* data, and verify that the checksum passes.
|
||||||
|
* @param extendedMode if true, will attempt to decode extended Code 39 sequences in the
|
||||||
|
* text.
|
||||||
|
*/
|
||||||
|
pub fn with_all_config(usingCheckDigit: bool, extendedMode: bool) -> Self {
|
||||||
|
Self {
|
||||||
|
usingCheckDigit,
|
||||||
|
extendedMode,
|
||||||
|
decodeRowRXingResult: String::with_capacity(20),
|
||||||
|
counters: vec![0; 9],
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn findAsteriskPattern(row: &BitArray, counters: &mut [u32]) -> Result<Vec<u32>, Exceptions> {
|
||||||
|
let width = row.getSize();
|
||||||
|
let rowOffset = row.getNextSet(0);
|
||||||
|
|
||||||
|
let mut counterPosition = 0;
|
||||||
|
let mut patternStart = rowOffset;
|
||||||
|
let mut isWhite = false;
|
||||||
|
let patternLength = counters.len();
|
||||||
|
|
||||||
|
for i in rowOffset..width {
|
||||||
|
// for (int i = rowOffset; i < width; i++) {
|
||||||
|
if row.get(i) != isWhite {
|
||||||
|
counters[counterPosition] += 1;
|
||||||
|
} else {
|
||||||
|
if counterPosition == patternLength - 1 {
|
||||||
|
// Look for whitespace before start pattern, >= 50% of width of start pattern
|
||||||
|
if Self::toNarrowWidePattern(counters) == (Self::ASTERISK_ENCODING as i32)
|
||||||
|
&& row.isRange(
|
||||||
|
0.max(
|
||||||
|
patternStart as isize - ((i as isize - patternStart as isize) / 2),
|
||||||
|
) as usize,
|
||||||
|
patternStart,
|
||||||
|
false,
|
||||||
|
)?
|
||||||
|
{
|
||||||
|
return Ok(vec![patternStart as u32, i as u32]);
|
||||||
|
// return new int[]{patternStart, i};
|
||||||
|
}
|
||||||
|
patternStart += (counters[0] + counters[1]) as usize;
|
||||||
|
let slc = counters[0..(counterPosition - 1)].to_vec();
|
||||||
|
counters[2..(counterPosition - 1 + 2)].clone_from_slice(&slc[..]);
|
||||||
|
// System.arraycopy(counters, 2, counters, 0, counterPosition - 1);
|
||||||
|
counters[counterPosition - 1] = 0;
|
||||||
|
counters[counterPosition] = 0;
|
||||||
|
counterPosition -= 1;
|
||||||
|
} else {
|
||||||
|
counterPosition += 1;
|
||||||
|
}
|
||||||
|
counters[counterPosition] = 1;
|
||||||
|
isWhite = !isWhite;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return Err(Exceptions::NotFoundException("".to_owned()));
|
||||||
|
}
|
||||||
|
|
||||||
|
// For efficiency, returns -1 on failure. Not throwing here saved as many as 700 exceptions
|
||||||
|
// per image when using some of our blackbox images.
|
||||||
|
fn toNarrowWidePattern(counters: &[u32]) -> i32 {
|
||||||
|
let numCounters = counters.len();
|
||||||
|
let mut maxNarrowCounter = 0;
|
||||||
|
let mut wideCounters;
|
||||||
|
loop {
|
||||||
|
let mut minCounter = u32::MAX; //Integer.MAX_VALUE;
|
||||||
|
for counter in counters {
|
||||||
|
// for (int counter : counters) {
|
||||||
|
if counter < &minCounter && counter > &maxNarrowCounter {
|
||||||
|
minCounter = *counter;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
maxNarrowCounter = minCounter;
|
||||||
|
wideCounters = 0;
|
||||||
|
let mut totalWideCountersWidth = 0;
|
||||||
|
let mut pattern = 0;
|
||||||
|
for i in 0..numCounters {
|
||||||
|
// for (int i = 0; i < numCounters; i++) {
|
||||||
|
let counter = counters[i];
|
||||||
|
if counter > maxNarrowCounter {
|
||||||
|
pattern |= 1 << (numCounters - 1 - i);
|
||||||
|
wideCounters += 1;
|
||||||
|
totalWideCountersWidth += counter;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if wideCounters == 3 {
|
||||||
|
// Found 3 wide counters, but are they close enough in width?
|
||||||
|
// We can perform a cheap, conservative check to see if any individual
|
||||||
|
// counter is more than 1.5 times the average:
|
||||||
|
let mut i = 0;
|
||||||
|
while i < numCounters && wideCounters > 0 {
|
||||||
|
// for (int i = 0; i < numCounters && wideCounters > 0; i++) {
|
||||||
|
let counter = counters[i];
|
||||||
|
if counter > maxNarrowCounter {
|
||||||
|
wideCounters -= 1;
|
||||||
|
// totalWideCountersWidth = 3 * average, so this checks if counter >= 3/2 * average
|
||||||
|
if (counter * 2) >= totalWideCountersWidth {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
i += 1;
|
||||||
|
}
|
||||||
|
return pattern;
|
||||||
|
}
|
||||||
|
|
||||||
|
if !(wideCounters > 3) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} //while ;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn patternToChar(pattern: u32) -> Result<char, Exceptions> {
|
||||||
|
for i in 0..Self::CHARACTER_ENCODINGS.len() {
|
||||||
|
// for (int i = 0; i < CHARACTER_ENCODINGS.length; i++) {
|
||||||
|
if Self::CHARACTER_ENCODINGS[i] == pattern {
|
||||||
|
return Ok(Self::ALPHABET_STRING.chars().nth(i).unwrap());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if pattern == Self::ASTERISK_ENCODING {
|
||||||
|
return Ok('*');
|
||||||
|
}
|
||||||
|
return Err(Exceptions::NotFoundException("".to_owned()));
|
||||||
|
}
|
||||||
|
|
||||||
|
fn decodeExtended(encoded: &str) -> Result<String, Exceptions> {
|
||||||
|
let length = encoded.chars().count();
|
||||||
|
let mut decoded = String::with_capacity(length); //new StringBuilder(length);
|
||||||
|
let mut i = 0;
|
||||||
|
while i < length {
|
||||||
|
// for i in 0..length {
|
||||||
|
// for (int i = 0; i < length; i++) {
|
||||||
|
let c = encoded.chars().nth(i).unwrap();
|
||||||
|
if c == '+' || c == '$' || c == '%' || c == '/' {
|
||||||
|
let next = encoded.chars().nth(i + 1).unwrap();
|
||||||
|
let mut decodedChar = '\0';
|
||||||
|
match c {
|
||||||
|
'+' => {
|
||||||
|
// +A to +Z map to a to z
|
||||||
|
if next >= 'A' && next <= 'Z' {
|
||||||
|
decodedChar = char::from_u32(next as u32 + 32).unwrap();
|
||||||
|
} else {
|
||||||
|
return Err(Exceptions::NotFoundException("".to_owned()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
'$' => {
|
||||||
|
// $A to $Z map to control codes SH to SB
|
||||||
|
if next >= 'A' && next <= 'Z' {
|
||||||
|
decodedChar = char::from_u32(next as u32 - 64).unwrap();
|
||||||
|
} else {
|
||||||
|
return Err(Exceptions::NotFoundException("".to_owned()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
'%' => {
|
||||||
|
// %A to %E map to control codes ESC to US
|
||||||
|
if next >= 'A' && next <= 'E' {
|
||||||
|
decodedChar = char::from_u32(next as u32 - 38).unwrap();
|
||||||
|
} else if next >= 'F' && next <= 'J' {
|
||||||
|
decodedChar = char::from_u32(next as u32 - 11).unwrap();
|
||||||
|
} else if next >= 'K' && next <= 'O' {
|
||||||
|
decodedChar = char::from_u32(next as u32 + 16).unwrap();
|
||||||
|
} else if next >= 'P' && next <= 'T' {
|
||||||
|
decodedChar = char::from_u32(next as u32 + 43).unwrap();
|
||||||
|
} else if next == 'U' {
|
||||||
|
decodedChar = 0 as char;
|
||||||
|
} else if next == 'V' {
|
||||||
|
decodedChar = '@';
|
||||||
|
} else if next == 'W' {
|
||||||
|
decodedChar = '`';
|
||||||
|
} else if next == 'X' || next == 'Y' || next == 'Z' {
|
||||||
|
decodedChar = 127 as char;
|
||||||
|
} else {
|
||||||
|
return Err(Exceptions::NotFoundException("".to_owned()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
'/' => {
|
||||||
|
// /A to /O map to ! to , and /Z maps to :
|
||||||
|
if next >= 'A' && next <= 'O' {
|
||||||
|
decodedChar = char::from_u32(next as u32 - 32).unwrap();
|
||||||
|
} else if next == 'Z' {
|
||||||
|
decodedChar = ':';
|
||||||
|
} else {
|
||||||
|
return Err(Exceptions::NotFoundException("".to_owned()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
decoded.push(decodedChar);
|
||||||
|
// bump up i again since we read two characters
|
||||||
|
i += 1;
|
||||||
|
} else {
|
||||||
|
decoded.push(c);
|
||||||
|
}
|
||||||
|
i += 1;
|
||||||
|
}
|
||||||
|
Ok(decoded)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod code_39_extended_mode_test_case {
|
||||||
|
use std::collections::HashMap;
|
||||||
|
|
||||||
|
use crate::{
|
||||||
|
common::{BitArray, BitMatrix},
|
||||||
|
oned::{Code39Reader, OneDReader},
|
||||||
|
};
|
||||||
|
#[test]
|
||||||
|
fn testDecodeExtendedMode() {
|
||||||
|
// \b -> 2408 \f -> 000c
|
||||||
|
doTest("\u{0000}\u{0001}\u{0002}\u{0003}\u{0004}\u{0005}\u{0006}\u{0007}\u{0008}\t\n\u{000b}\u{000C}\r\u{000e}\u{000f}\u{0010}\u{0011}\u{0012}\u{0013}\u{0014}\u{0015}\u{0016}\u{0017}\u{0018}\u{0019}\u{001a}\u{001b}\u{001c}\u{001d}\u{001e}\u{001f}",
|
||||||
|
"000001001011011010101001001001011001010101101001001001010110101001011010010010010101011010010110100100100101011011010010101001001001010101011001011010010010010101101011001010100100100101010110110010101001001001010101010011011010010010010101101010011010100100100101010110100110101001001001010101011001101010010010010101101010100110100100100101010110101001101001001001010110110101001010010010010101010110100110100100100101011010110100101001001001010101101101001010010010010101010101100110100100100101011010101100101001001001010101101011001010010010010101010110110010100100100101011001010101101001001001010100110101011010010010010101100110101010100100100101010010110101101001001001010110010110101010010010010101001101101010101001001001011010100101101010010010010101101001011010100100100101101101001010101001001001010101100101101010010010010110101100101010010110110100000");
|
||||||
|
doTest(" !\"#$%&'()*+,-./0123456789:;<=>?",
|
||||||
|
"00000100101101101010011010110101001001010010110101001011010010010100101011010010110100100101001011011010010101001001010010101011001011010010010100101101011001010100100101001010110110010101001001010010101010011011010010010100101101010011010100100101001010110100110101001001010010101011001101010010010100101101010100110100100101001010110101001101001010110110110010101101010010010100101101011010010101001101101011010010101101011001010110110110010101010100110101101101001101010101100110101010100101101101101001011010101100101101010010010100101001101101010101001001001010110110010101010010010010101010011011010100100100101101010011010101001001001010110100110101010010010010101011001101010010110110100000");
|
||||||
|
doTest("@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_",
|
||||||
|
"000010010110110101010010010010100110101011011010100101101011010010110110110100101010101100101101101011001010101101100101010101001101101101010011010101101001101010101100110101101010100110101101010011011011010100101010110100110110101101001010110110100101010101100110110101011001010110101100101010110110010110010101011010011010101101100110101010100101101011011001011010101001101101010101001001001011010101001101010010010010101101010011010100100100101101101010010101001001001010101101001101010010010010110101101001010010110110100000");
|
||||||
|
doTest("`abcdefghijklmnopqrstuvwxyz{|}~",
|
||||||
|
"000001001011011010101001001001011001101010101001010010010110101001011010010100100101011010010110100101001001011011010010101001010010010101011001011010010100100101101011001010100101001001010110110010101001010010010101010011011010010100100101101010011010100101001001010110100110101001010010010101011001101010010100100101101010100110100101001001010110101001101001010010010110110101001010010100100101010110100110100101001001011010110100101001010010010101101101001010010100100101010101100110100101001001011010101100101001010010010101101011001010010100100101010110110010100101001001011001010101101001010010010100110101011010010100100101100110101010100101001001010010110101101001010010010110010110101010010100100101001101101010101001001001010110110100101010010010010101010110011010100100100101101010110010101001001001010110101100101010010010010101011011001010010110110100000");
|
||||||
|
}
|
||||||
|
|
||||||
|
fn doTest(expectedRXingResult: &str, encodedRXingResult: &str) {
|
||||||
|
let mut sut = Code39Reader::with_all_config(false, true);
|
||||||
|
let matrix =
|
||||||
|
BitMatrix::parse_strings(encodedRXingResult, "1", "0").expect("bitmatrix parse");
|
||||||
|
let row = BitArray::with_size(matrix.getWidth() as usize);
|
||||||
|
let row = matrix.getRow(0, &row);
|
||||||
|
let result = sut.decodeRow(0, &row, &HashMap::new()).expect("decode row");
|
||||||
|
assert_eq!(expectedRXingResult, result.getText());
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -8,3 +8,9 @@ pub use ean_manufacturer_org_support::*;
|
|||||||
|
|
||||||
mod coda_bar_reader;
|
mod coda_bar_reader;
|
||||||
pub use coda_bar_reader::*;
|
pub use coda_bar_reader::*;
|
||||||
|
|
||||||
|
mod code_39_reader;
|
||||||
|
pub use code_39_reader::*;
|
||||||
|
|
||||||
|
mod multi_format_one_d_reader;
|
||||||
|
pub use multi_format_one_d_reader::*;
|
||||||
|
|||||||
185
src/oned/multi_format_one_d_reader.rs
Normal file
185
src/oned/multi_format_one_d_reader.rs
Normal file
@@ -0,0 +1,185 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2008 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 one_d_reader_derive::OneDReader;
|
||||||
|
|
||||||
|
use super::CodaBarReader;
|
||||||
|
use super::Code39Reader;
|
||||||
|
use super::OneDReader;
|
||||||
|
use crate::BarcodeFormat;
|
||||||
|
use crate::DecodeHintValue;
|
||||||
|
use crate::Exceptions;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author dswitkin@google.com (Daniel Switkin)
|
||||||
|
* @author Sean Owen
|
||||||
|
*/
|
||||||
|
pub struct MultiFormatOneDReader(Vec<Box<dyn OneDReader>>);
|
||||||
|
impl OneDReader for MultiFormatOneDReader {
|
||||||
|
fn decodeRow(
|
||||||
|
&mut self,
|
||||||
|
rowNumber: u32,
|
||||||
|
row: &crate::common::BitArray,
|
||||||
|
hints: &crate::DecodingHintDictionary,
|
||||||
|
) -> Result<crate::RXingResult, crate::Exceptions> {
|
||||||
|
for reader in self.0.iter_mut() {
|
||||||
|
// for (OneDReader reader : readers) {
|
||||||
|
// try {
|
||||||
|
if let Ok(res) = reader.decodeRow(rowNumber, row, hints) {
|
||||||
|
return Ok(res);
|
||||||
|
}
|
||||||
|
// } catch (ReaderException re) {
|
||||||
|
// continue
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
|
||||||
|
return Err(Exceptions::NotFoundException("".to_owned()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl MultiFormatOneDReader {
|
||||||
|
// private static final OneDReader[] EMPTY_ONED_ARRAY = new OneDReader[0];
|
||||||
|
|
||||||
|
// private final OneDReader[] readers;
|
||||||
|
|
||||||
|
pub fn new(hints: &DecodingHintDictionary) -> Self {
|
||||||
|
let useCode39CheckDigit = hints.contains_key(&DecodeHintType::ASSUME_CODE_39_CHECK_DIGIT);
|
||||||
|
let mut readers: Vec<Box<dyn OneDReader>> = Vec::new();
|
||||||
|
if let Some(DecodeHintValue::PossibleFormats(possibleFormats)) =
|
||||||
|
hints.get(&DecodeHintType::POSSIBLE_FORMATS)
|
||||||
|
{
|
||||||
|
// if let let possibleFormats = hints == null ? null :
|
||||||
|
// (Collection<BarcodeFormat>) hints.get(&DecodeHintType::POSSIBLE_FORMATS);
|
||||||
|
// if (possibleFormats != null) {
|
||||||
|
// if (possibleFormats.contains(&BarcodeFormat::EAN_13) ||
|
||||||
|
// possibleFormats.contains(&BarcodeFormat::UPC_A) ||
|
||||||
|
// possibleFormats.contains(&BarcodeFormat::EAN_8) ||
|
||||||
|
// possibleFormats.contains(&BarcodeFormat::UPC_E)) {
|
||||||
|
// readers.add(new MultiFormatUPCEANReader(hints));
|
||||||
|
// }
|
||||||
|
if possibleFormats.contains(&BarcodeFormat::CODE_39) {
|
||||||
|
readers.push(Box::new(Code39Reader::with_use_check_digit(
|
||||||
|
useCode39CheckDigit,
|
||||||
|
)));
|
||||||
|
}
|
||||||
|
// if (possibleFormats.contains(&BarcodeFormat::CODE_93)) {
|
||||||
|
// readers.add(new Code93Reader());
|
||||||
|
// }
|
||||||
|
// if (possibleFormats.contains(&BarcodeFormat::CODE_128)) {
|
||||||
|
// readers.add(new Code128Reader());
|
||||||
|
// }
|
||||||
|
// if (possibleFormats.contains(&BarcodeFormat::ITF)) {
|
||||||
|
// readers.add(new ITFReader());
|
||||||
|
// }
|
||||||
|
if possibleFormats.contains(&BarcodeFormat::CODABAR) {
|
||||||
|
readers.push(Box::new(CodaBarReader::new()));
|
||||||
|
}
|
||||||
|
// if (possibleFormats.contains(&BarcodeFormat::RSS_14)) {
|
||||||
|
// readers.add(new RSS14Reader());
|
||||||
|
// }
|
||||||
|
// if (possibleFormats.contains(&BarcodeFormat::RSS_EXPANDED)) {
|
||||||
|
// readers.add(new RSSExpandedReader());
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
if readers.is_empty() {
|
||||||
|
// readers.push(new MultiFormatUPCEANReader(hints));
|
||||||
|
readers.push(Box::new(Code39Reader::new()));
|
||||||
|
readers.push(Box::new(CodaBarReader::new()));
|
||||||
|
// readers.push(new Code93Reader());
|
||||||
|
// readers.push(new Code128Reader());
|
||||||
|
// readers.push(new ITFReader());
|
||||||
|
// readers.push(new RSS14Reader());
|
||||||
|
// readers.push(new RSSExpandedReader());
|
||||||
|
}
|
||||||
|
|
||||||
|
Self(readers)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
use crate::result_point::ResultPoint;
|
||||||
|
use crate::DecodeHintType;
|
||||||
|
use crate::DecodingHintDictionary;
|
||||||
|
use crate::RXingResultMetadataType;
|
||||||
|
use crate::RXingResultMetadataValue;
|
||||||
|
use crate::RXingResultPoint;
|
||||||
|
use crate::Reader;
|
||||||
|
use std::collections::HashMap;
|
||||||
|
|
||||||
|
impl Reader for MultiFormatOneDReader {
|
||||||
|
fn decode(&mut self, image: &crate::BinaryBitmap) -> Result<crate::RXingResult, Exceptions> {
|
||||||
|
self.decode_with_hints(image, &HashMap::new())
|
||||||
|
}
|
||||||
|
|
||||||
|
// Note that we don't try rotation without the try harder flag, even if rotation was supported.
|
||||||
|
fn decode_with_hints(
|
||||||
|
&mut self,
|
||||||
|
image: &crate::BinaryBitmap,
|
||||||
|
hints: &DecodingHintDictionary,
|
||||||
|
) -> Result<crate::RXingResult, Exceptions> {
|
||||||
|
if let Ok(res) = self.doDecode(image, hints) {
|
||||||
|
Ok(res)
|
||||||
|
} else {
|
||||||
|
let tryHarder = hints.contains_key(&DecodeHintType::TRY_HARDER);
|
||||||
|
if tryHarder && image.isRotateSupported() {
|
||||||
|
let rotatedImage = image.rotateCounterClockwise();
|
||||||
|
let mut result = self.doDecode(&rotatedImage, hints)?;
|
||||||
|
// Record that we found it rotated 90 degrees CCW / 270 degrees CW
|
||||||
|
let metadata = result.getRXingResultMetadata();
|
||||||
|
let mut orientation = 270;
|
||||||
|
if metadata.contains_key(&RXingResultMetadataType::ORIENTATION) {
|
||||||
|
// But if we found it reversed in doDecode(), add in that result here:
|
||||||
|
orientation = (orientation
|
||||||
|
+ if let Some(crate::RXingResultMetadataValue::Orientation(or)) =
|
||||||
|
metadata.get(&RXingResultMetadataType::ORIENTATION)
|
||||||
|
{
|
||||||
|
*or
|
||||||
|
} else {
|
||||||
|
0
|
||||||
|
})
|
||||||
|
% 360;
|
||||||
|
}
|
||||||
|
result.putMetadata(
|
||||||
|
RXingResultMetadataType::ORIENTATION,
|
||||||
|
RXingResultMetadataValue::Orientation(orientation),
|
||||||
|
);
|
||||||
|
// Update result points
|
||||||
|
// let points = result.getRXingResultPoints();
|
||||||
|
// if points != null {
|
||||||
|
let height = rotatedImage.getHeight();
|
||||||
|
// for point in result.getRXingResultPointsMut().iter_mut() {
|
||||||
|
let total_points = result.getRXingResultPoints().len();
|
||||||
|
let points = result.getRXingResultPointsMut();
|
||||||
|
for i in 0..total_points {
|
||||||
|
// for (int i = 0; i < points.length; i++) {
|
||||||
|
points[i] = RXingResultPoint::new(
|
||||||
|
height as f32 - points[i].getY() - 1.0,
|
||||||
|
points[i].getX(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
// }
|
||||||
|
|
||||||
|
Ok(result)
|
||||||
|
} else {
|
||||||
|
return Err(Exceptions::NotFoundException("".to_owned()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fn reset(&mut self) {
|
||||||
|
for reader in self.0.iter_mut() {
|
||||||
|
// for (Reader reader : readers) {
|
||||||
|
reader.reset();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -159,7 +159,10 @@ pub trait OneDReader: Reader {
|
|||||||
* @throws NotFoundException if counters cannot be filled entirely from row before running out
|
* @throws NotFoundException if counters cannot be filled entirely from row before running out
|
||||||
* of pixels
|
* of pixels
|
||||||
*/
|
*/
|
||||||
fn recordPattern(row: &BitArray, start: usize, counters: &mut [u32]) -> Result<(), Exceptions> {
|
fn recordPattern(row: &BitArray, start: usize, counters: &mut [u32]) -> Result<(), Exceptions>
|
||||||
|
where
|
||||||
|
Self: Sized,
|
||||||
|
{
|
||||||
let numCounters = counters.len();
|
let numCounters = counters.len();
|
||||||
// Arrays.fill(counters, 0, numCounters, 0);
|
// Arrays.fill(counters, 0, numCounters, 0);
|
||||||
counters.fill(0);
|
counters.fill(0);
|
||||||
@@ -196,7 +199,10 @@ pub trait OneDReader: Reader {
|
|||||||
row: &BitArray,
|
row: &BitArray,
|
||||||
start: usize,
|
start: usize,
|
||||||
counters: &mut [u32],
|
counters: &mut [u32],
|
||||||
) -> Result<(), Exceptions> {
|
) -> Result<(), Exceptions>
|
||||||
|
where
|
||||||
|
Self: Sized,
|
||||||
|
{
|
||||||
let mut start = start;
|
let mut start = start;
|
||||||
// This could be more efficient I guess
|
// This could be more efficient I guess
|
||||||
let mut numTransitionsLeft = counters.len() as isize;
|
let mut numTransitionsLeft = counters.len() as isize;
|
||||||
@@ -226,7 +232,10 @@ pub trait OneDReader: Reader {
|
|||||||
* @param maxIndividualVariance The most any counter can differ before we give up
|
* @param maxIndividualVariance The most any counter can differ before we give up
|
||||||
* @return ratio of total variance between counters and pattern compared to total pattern size
|
* @return ratio of total variance between counters and pattern compared to total pattern size
|
||||||
*/
|
*/
|
||||||
fn patternMatchVariance(counters: &[u32], pattern: &[u32], maxIndividualVariance: f32) -> f32 {
|
fn patternMatchVariance(counters: &[u32], pattern: &[u32], maxIndividualVariance: f32) -> f32
|
||||||
|
where
|
||||||
|
Self: Sized,
|
||||||
|
{
|
||||||
let mut maxIndividualVariance = maxIndividualVariance;
|
let mut maxIndividualVariance = maxIndividualVariance;
|
||||||
let numCounters = counters.len();
|
let numCounters = counters.len();
|
||||||
let mut total = 0.0;
|
let mut total = 0.0;
|
||||||
|
|||||||
@@ -66,5 +66,6 @@ pub trait Reader {
|
|||||||
* Resets any internal state the implementation has after a decode, to prepare it
|
* Resets any internal state the implementation has after a decode, to prepare it
|
||||||
* for reuse.
|
* for reuse.
|
||||||
*/
|
*/
|
||||||
fn reset(&mut self);
|
fn reset(&mut self) { /* do nothing */
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,34 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2008 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.oned;
|
|
||||||
|
|
||||||
import com.google.zxing.BarcodeFormat;
|
|
||||||
import com.google.zxing.MultiFormatReader;
|
|
||||||
import com.google.zxing.common.AbstractBlackBoxTestCase;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @author Sean Owen
|
|
||||||
*/
|
|
||||||
public final class Code39BlackBox1TestCase extends AbstractBlackBoxTestCase {
|
|
||||||
|
|
||||||
public Code39BlackBox1TestCase() {
|
|
||||||
super("src/test/resources/blackbox/code39-1", new MultiFormatReader(), BarcodeFormat.CODE_39);
|
|
||||||
addTest(4, 4, 0.0f);
|
|
||||||
addTest(4, 4, 180.0f);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,34 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2008 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.oned;
|
|
||||||
|
|
||||||
import com.google.zxing.BarcodeFormat;
|
|
||||||
import com.google.zxing.MultiFormatReader;
|
|
||||||
import com.google.zxing.common.AbstractBlackBoxTestCase;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @author dswitkin@google.com (Daniel Switkin)
|
|
||||||
*/
|
|
||||||
public final class Code39BlackBox3TestCase extends AbstractBlackBoxTestCase {
|
|
||||||
|
|
||||||
public Code39BlackBox3TestCase() {
|
|
||||||
super("src/test/resources/blackbox/code39-3", new MultiFormatReader(), BarcodeFormat.CODE_39);
|
|
||||||
addTest(17, 17, 0.0f);
|
|
||||||
addTest(17, 17, 180.0f);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,33 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2008 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.oned;
|
|
||||||
|
|
||||||
import com.google.zxing.BarcodeFormat;
|
|
||||||
import com.google.zxing.common.AbstractBlackBoxTestCase;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @author Sean Owen
|
|
||||||
*/
|
|
||||||
public final class Code39ExtendedBlackBox2TestCase extends AbstractBlackBoxTestCase {
|
|
||||||
|
|
||||||
public Code39ExtendedBlackBox2TestCase() {
|
|
||||||
super("src/test/resources/blackbox/code39-2", new Code39Reader(false, true), BarcodeFormat.CODE_39);
|
|
||||||
addTest(2, 2, 0.0f);
|
|
||||||
addTest(2, 2, 180.0f);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,57 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2017 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.oned;
|
|
||||||
|
|
||||||
import org.junit.Assert;
|
|
||||||
import org.junit.Test;
|
|
||||||
|
|
||||||
import com.google.zxing.common.BitMatrix;
|
|
||||||
import com.google.zxing.common.BitArray;
|
|
||||||
import com.google.zxing.ChecksumException;
|
|
||||||
import com.google.zxing.FormatException;
|
|
||||||
import com.google.zxing.NotFoundException;
|
|
||||||
import com.google.zxing.RXingResult;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @author Michael Jahn
|
|
||||||
*/
|
|
||||||
public final class Code39ExtendedModeTestCase extends Assert {
|
|
||||||
|
|
||||||
@SuppressWarnings("checkstyle:lineLength")
|
|
||||||
@Test
|
|
||||||
public void testDecodeExtendedMode() throws FormatException, ChecksumException, NotFoundException {
|
|
||||||
doTest("\u0000\u0001\u0002\u0003\u0004\u0005\u0006\u0007\b\t\n\u000b\f\r\u000e\u000f\u0010\u0011\u0012\u0013\u0014\u0015\u0016\u0017\u0018\u0019\u001a\u001b\u001c\u001d\u001e\u001f",
|
|
||||||
"000001001011011010101001001001011001010101101001001001010110101001011010010010010101011010010110100100100101011011010010101001001001010101011001011010010010010101101011001010100100100101010110110010101001001001010101010011011010010010010101101010011010100100100101010110100110101001001001010101011001101010010010010101101010100110100100100101010110101001101001001001010110110101001010010010010101010110100110100100100101011010110100101001001001010101101101001010010010010101010101100110100100100101011010101100101001001001010101101011001010010010010101010110110010100100100101011001010101101001001001010100110101011010010010010101100110101010100100100101010010110101101001001001010110010110101010010010010101001101101010101001001001011010100101101010010010010101101001011010100100100101101101001010101001001001010101100101101010010010010110101100101010010110110100000");
|
|
||||||
doTest(" !\"#$%&'()*+,-./0123456789:;<=>?",
|
|
||||||
"00000100101101101010011010110101001001010010110101001011010010010100101011010010110100100101001011011010010101001001010010101011001011010010010100101101011001010100100101001010110110010101001001010010101010011011010010010100101101010011010100100101001010110100110101001001010010101011001101010010010100101101010100110100100101001010110101001101001010110110110010101101010010010100101101011010010101001101101011010010101101011001010110110110010101010100110101101101001101010101100110101010100101101101101001011010101100101101010010010100101001101101010101001001001010110110010101010010010010101010011011010100100100101101010011010101001001001010110100110101010010010010101011001101010010110110100000");
|
|
||||||
doTest("@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_",
|
|
||||||
"000010010110110101010010010010100110101011011010100101101011010010110110110100101010101100101101101011001010101101100101010101001101101101010011010101101001101010101100110101101010100110101101010011011011010100101010110100110110101101001010110110100101010101100110110101011001010110101100101010110110010110010101011010011010101101100110101010100101101011011001011010101001101101010101001001001011010101001101010010010010101101010011010100100100101101101010010101001001001010101101001101010010010010110101101001010010110110100000");
|
|
||||||
doTest("`abcdefghijklmnopqrstuvwxyz{|}~",
|
|
||||||
"000001001011011010101001001001011001101010101001010010010110101001011010010100100101011010010110100101001001011011010010101001010010010101011001011010010100100101101011001010100101001001010110110010101001010010010101010011011010010100100101101010011010100101001001010110100110101001010010010101011001101010010100100101101010100110100101001001010110101001101001010010010110110101001010010100100101010110100110100101001001011010110100101001010010010101101101001010010100100101010101100110100101001001011010101100101001010010010101101011001010010100100101010110110010100101001001011001010101101001010010010100110101011010010100100101100110101010100101001001010010110101101001010010010110010110101010010100100101001101101010101001001001010110110100101010010010010101010110011010100100100101101010110010101001001001010110101100101010010010010101011011001010010110110100000");
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void doTest(String expectedRXingResult, String encodedRXingResult)
|
|
||||||
throws FormatException, ChecksumException, NotFoundException {
|
|
||||||
Code39Reader sut = new Code39Reader(false, true);
|
|
||||||
BitMatrix matrix = BitMatrix.parse(encodedRXingResult, "1", "0");
|
|
||||||
BitArray row = new BitArray(matrix.getWidth());
|
|
||||||
matrix.getRow(0, row);
|
|
||||||
RXingResult result = sut.decodeRow(0, row, null);
|
|
||||||
assertEquals(expectedRXingResult, result.getText());
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -14,7 +14,10 @@
|
|||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
use rxing::{BarcodeFormat, MultiFormatReader, oned::{OneDReader, CodaBarReader}};
|
use rxing::{
|
||||||
|
oned::{CodaBarReader, OneDReader},
|
||||||
|
BarcodeFormat, MultiFormatReader,
|
||||||
|
};
|
||||||
|
|
||||||
mod common;
|
mod common;
|
||||||
|
|
||||||
|
|||||||
67
tests/code_39_blackbox_reader.rs
Normal file
67
tests/code_39_blackbox_reader.rs
Normal file
@@ -0,0 +1,67 @@
|
|||||||
|
/**
|
||||||
|
* 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 rxing::{
|
||||||
|
oned::{CodaBarReader, Code39Reader, OneDReader},
|
||||||
|
BarcodeFormat, MultiFormatReader,
|
||||||
|
};
|
||||||
|
|
||||||
|
mod common;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Sean Owen
|
||||||
|
*/
|
||||||
|
#[test]
|
||||||
|
fn code39_black_box1_test_case() {
|
||||||
|
let mut tester = common::AbstractBlackBoxTestCase::new(
|
||||||
|
"test_resources/blackbox/code39-1",
|
||||||
|
MultiFormatReader::default(),
|
||||||
|
BarcodeFormat::CODE_39,
|
||||||
|
);
|
||||||
|
|
||||||
|
// super("src/test/resources/blackbox/code39-1", new MultiFormatReader(), BarcodeFormat.CODE_39);
|
||||||
|
tester.add_test(4, 4, 0.0);
|
||||||
|
tester.add_test(4, 4, 180.0);
|
||||||
|
|
||||||
|
tester.test_black_box();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author dswitkin@google.com (Daniel Switkin)
|
||||||
|
*/
|
||||||
|
#[test]
|
||||||
|
fn code39_black_box3_test_case() {
|
||||||
|
let mut tester = common::AbstractBlackBoxTestCase::new(
|
||||||
|
"test_resources/blackbox/code39-3",
|
||||||
|
MultiFormatReader::default(),
|
||||||
|
BarcodeFormat::CODE_39,
|
||||||
|
);
|
||||||
|
|
||||||
|
// super("src/test/resources/blackbox/code39-3", new MultiFormatReader(), BarcodeFormat.CODE_39);
|
||||||
|
tester.add_test(17, 17, 0.0);
|
||||||
|
tester.add_test(17, 17, 180.0);
|
||||||
|
|
||||||
|
tester.test_black_box();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Sean Owen
|
||||||
|
*/
|
||||||
|
#[test]
|
||||||
|
fn code39_extended_black_box2_test_case() {
|
||||||
|
let mut tester = common::AbstractBlackBoxTestCase::new(
|
||||||
|
"test_resources/blackbox/code39-2",
|
||||||
|
Code39Reader::with_all_config(false, true),
|
||||||
|
BarcodeFormat::CODE_39,
|
||||||
|
);
|
||||||
|
|
||||||
|
// super("src/test/resources/blackbox/code39-2", new Code39Reader(false, true), BarcodeFormat.CODE_39);
|
||||||
|
tester.add_test(2, 2, 0.0);
|
||||||
|
tester.add_test(2, 2, 180.0);
|
||||||
|
|
||||||
|
tester.test_black_box();
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user