diff --git a/one-d-reader-derive/src/lib.rs b/one-d-reader-derive/src/lib.rs index 60279c2..917f14c 100644 --- a/one-d-reader-derive/src/lib.rs +++ b/one-d-reader-derive/src/lib.rs @@ -74,10 +74,6 @@ fn impl_one_d_reader_macro(ast: &syn::DeriveInput) -> TokenStream { } } } - - fn reset(&mut self) { - // do nothing - } } }; gen.into() diff --git a/src/decode_hints.rs b/src/decode_hints.rs index 1ab7ac3..0c1d65f 100644 --- a/src/decode_hints.rs +++ b/src/decode_hints.rs @@ -16,6 +16,8 @@ //package com.google.zxing; +use std::collections::HashSet; + use crate::{BarcodeFormat, RXingResultPointCallback}; /** @@ -141,7 +143,7 @@ pub enum DecodeHintValue { * Image is known to be of one of a few possible formats. * Maps to a {@link List} of {@link BarcodeFormat}s. */ - PossibleFormats(Vec), + PossibleFormats(HashSet), /** * Spend more time to try to find a barcode; optimize for accuracy, not speed. diff --git a/src/multi_format_reader.rs b/src/multi_format_reader.rs index a7126b3..f1e273c 100644 --- a/src/multi_format_reader.rs +++ b/src/multi_format_reader.rs @@ -18,8 +18,8 @@ use std::collections::HashMap; use crate::{ aztec::AztecReader, datamatrix::DataMatrixReader, maxicode::MaxiCodeReader, - qrcode::QRCodeReader, BarcodeFormat, BinaryBitmap, DecodeHintType, DecodeHintValue, - DecodingHintDictionary, Exceptions, RXingResult, Reader, + oned::MultiFormatOneDReader, qrcode::QRCodeReader, BarcodeFormat, BinaryBitmap, DecodeHintType, + DecodeHintValue, DecodingHintDictionary, Exceptions, RXingResult, Reader, }; /** @@ -124,8 +124,7 @@ impl MultiFormatReader { || formats.contains(&BarcodeFormat::RSS_EXPANDED); // Put 1D readers upfront in "normal" mode if addOneDReader && !tryHarder { - unimplemented!(""); - // readers.push(new MultiFormatOneDReader(hints)); + readers.push(Box::new(MultiFormatOneDReader::new(hints))); } if formats.contains(&BarcodeFormat::QR_CODE) { readers.push(Box::new(QRCodeReader {})); @@ -145,13 +144,12 @@ impl MultiFormatReader { } // At end in "try harder" mode if addOneDReader && tryHarder { - unimplemented!(""); - // readers.push( MultiFormatOneDReader::new(hints)); + readers.push(Box::new(MultiFormatOneDReader::new(hints))); } } if readers.is_empty() { if !tryHarder { - // readers.push( MultiFormatOneDReader::new(hints)); + readers.push(Box::new(MultiFormatOneDReader::new(hints))); //TODO: ADD MultiformatOneDReader here } @@ -163,7 +161,7 @@ impl MultiFormatReader { // unimplemented!(""); if tryHarder { - // readers.push( Box::new(MultiFormatOneDReader::new(hints))); + readers.push(Box::new(MultiFormatOneDReader::new(hints))); //TODO: ADD MultiformatOneDReader here } } diff --git a/src/oned/Code39Reader.java b/src/oned/Code39Reader.java deleted file mode 100644 index a74ae93..0000000 --- a/src/oned/Code39Reader.java +++ /dev/null @@ -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; - -/** - *

Decodes Code 39 barcodes. Supports "Full ASCII Code 39" if USE_CODE_39_EXTENDED_MODE is set.

- * - * @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 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(); - } - -} diff --git a/src/oned/MultiFormatOneDReader.java b/src/oned/MultiFormatOneDReader.java deleted file mode 100644 index 66d45de..0000000 --- a/src/oned/MultiFormatOneDReader.java +++ /dev/null @@ -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 hints) { - @SuppressWarnings("unchecked") - Collection possibleFormats = hints == null ? null : - (Collection) hints.get(DecodeHintType.POSSIBLE_FORMATS); - boolean useCode39CheckDigit = hints != null && - hints.get(DecodeHintType.ASSUME_CODE_39_CHECK_DIGIT) != null; - Collection 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 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(); - } - } - -} diff --git a/src/oned/coda_bar_reader.rs b/src/oned/coda_bar_reader.rs index 6ee2450..eafdfff 100644 --- a/src/oned/coda_bar_reader.rs +++ b/src/oned/coda_bar_reader.rs @@ -137,7 +137,7 @@ impl OneDReader for CodaBarReader { // self.decodeRowRXingResult.deleteCharAt(self.decodeRowRXingResult.chars().count() - 1); // self.decodeRowRXingResult.deleteCharAt(0); self.decodeRowRXingResult = - self.decodeRowRXingResult[1..self.decodeRowRXingResult.len()-1].to_owned(); + self.decodeRowRXingResult[1..self.decodeRowRXingResult.len() - 1].to_owned(); } let mut runningCount = 0; diff --git a/src/oned/code_39_reader.rs b/src/oned/code_39_reader.rs new file mode 100644 index 0000000..613645f --- /dev/null +++ b/src/oned/code_39_reader.rs @@ -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; + +/** + *

Decodes Code 39 barcodes. Supports "Full ASCII Code 39" if USE_CODE_39_EXTENDED_MODE is set.

+ * + * @author Sean Owen + * @see Code93Reader + */ +#[derive(OneDReader)] +pub struct Code39Reader { + usingCheckDigit: bool, + extendedMode: bool, + decodeRowRXingResult: String, + counters: Vec, +} +impl OneDReader for Code39Reader { + fn decodeRow( + &mut self, + rowNumber: u32, + row: &crate::common::BitArray, + _hints: &DecodingHintDictionary, + ) -> Result { + // 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, 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 { + 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 { + 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()); + } +} diff --git a/src/oned/mod.rs b/src/oned/mod.rs index a91ecac..041d646 100644 --- a/src/oned/mod.rs +++ b/src/oned/mod.rs @@ -8,3 +8,9 @@ pub use ean_manufacturer_org_support::*; mod 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::*; diff --git a/src/oned/multi_format_one_d_reader.rs b/src/oned/multi_format_one_d_reader.rs new file mode 100644 index 0000000..3292fde --- /dev/null +++ b/src/oned/multi_format_one_d_reader.rs @@ -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>); +impl OneDReader for MultiFormatOneDReader { + fn decodeRow( + &mut self, + rowNumber: u32, + row: &crate::common::BitArray, + hints: &crate::DecodingHintDictionary, + ) -> Result { + 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> = Vec::new(); + if let Some(DecodeHintValue::PossibleFormats(possibleFormats)) = + hints.get(&DecodeHintType::POSSIBLE_FORMATS) + { + // if let let possibleFormats = hints == null ? null : + // (Collection) 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 { + 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 { + 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(); + } + } +} diff --git a/src/oned/one_d_reader.rs b/src/oned/one_d_reader.rs index 3186ad8..bec3a67 100644 --- a/src/oned/one_d_reader.rs +++ b/src/oned/one_d_reader.rs @@ -159,7 +159,10 @@ pub trait OneDReader: Reader { * @throws NotFoundException if counters cannot be filled entirely from row before running out * 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(); // Arrays.fill(counters, 0, numCounters, 0); counters.fill(0); @@ -196,7 +199,10 @@ pub trait OneDReader: Reader { row: &BitArray, start: usize, counters: &mut [u32], - ) -> Result<(), Exceptions> { + ) -> Result<(), Exceptions> + where + Self: Sized, + { let mut start = start; // This could be more efficient I guess 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 * @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 numCounters = counters.len(); let mut total = 0.0; diff --git a/src/reader.rs b/src/reader.rs index bee916c..20e35fb 100644 --- a/src/reader.rs +++ b/src/reader.rs @@ -66,5 +66,6 @@ pub trait Reader { * Resets any internal state the implementation has after a decode, to prepare it * for reuse. */ - fn reset(&mut self); + fn reset(&mut self) { /* do nothing */ + } } diff --git a/tests/Code39BlackBox1TestCase.java b/tests/Code39BlackBox1TestCase.java deleted file mode 100644 index b2b6553..0000000 --- a/tests/Code39BlackBox1TestCase.java +++ /dev/null @@ -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); - } - -} \ No newline at end of file diff --git a/tests/Code39BlackBox3TestCase.java b/tests/Code39BlackBox3TestCase.java deleted file mode 100644 index 3d35941..0000000 --- a/tests/Code39BlackBox3TestCase.java +++ /dev/null @@ -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); - } - -} \ No newline at end of file diff --git a/tests/Code39ExtendedBlackBox2TestCase.java b/tests/Code39ExtendedBlackBox2TestCase.java deleted file mode 100644 index 6b045e3..0000000 --- a/tests/Code39ExtendedBlackBox2TestCase.java +++ /dev/null @@ -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); - } - -} \ No newline at end of file diff --git a/tests/Code39ExtendedModeTestCase.java b/tests/Code39ExtendedModeTestCase.java deleted file mode 100644 index a56fe8e..0000000 --- a/tests/Code39ExtendedModeTestCase.java +++ /dev/null @@ -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()); - } - -} diff --git a/tests/codabar_blackbox_1_test_case.rs b/tests/codabar_blackbox_1_test_case.rs index e632cbb..21f6f84 100644 --- a/tests/codabar_blackbox_1_test_case.rs +++ b/tests/codabar_blackbox_1_test_case.rs @@ -14,7 +14,10 @@ * limitations under the License. */ -use rxing::{BarcodeFormat, MultiFormatReader, oned::{OneDReader, CodaBarReader}}; +use rxing::{ + oned::{CodaBarReader, OneDReader}, + BarcodeFormat, MultiFormatReader, +}; mod common; diff --git a/tests/code_39_blackbox_reader.rs b/tests/code_39_blackbox_reader.rs new file mode 100644 index 0000000..61af5e8 --- /dev/null +++ b/tests/code_39_blackbox_reader.rs @@ -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(); +}