From 11c0ac5a81bccca5cfc34ad870bfce94491b7b3d Mon Sep 17 00:00:00 2001 From: Henry Schimke Date: Sat, 10 Dec 2022 10:31:41 -0600 Subject: [PATCH] upce integration --- src/oned/UPCEReader.java | 182 ------------------ src/oned/mod.rs | 3 + src/oned/upc_e_reader.rs | 194 ++++++++++++++++++++ tests/UPCEANExtensionBlackBox1TestCase.java | 33 ---- tests/UPCEBlackBox1TestCase.java | 34 ---- tests/UPCEBlackBox2TestCase.java | 34 ---- tests/UPCEBlackBox3ReflectiveTestCase.java | 34 ---- tests/upc_e_blackbox_tests.rs | 79 ++++++++ 8 files changed, 276 insertions(+), 317 deletions(-) delete mode 100644 src/oned/UPCEReader.java create mode 100644 src/oned/upc_e_reader.rs delete mode 100644 tests/UPCEANExtensionBlackBox1TestCase.java delete mode 100644 tests/UPCEBlackBox1TestCase.java delete mode 100644 tests/UPCEBlackBox2TestCase.java delete mode 100644 tests/UPCEBlackBox3ReflectiveTestCase.java create mode 100644 tests/upc_e_blackbox_tests.rs diff --git a/src/oned/UPCEReader.java b/src/oned/UPCEReader.java deleted file mode 100644 index ab8e39c..0000000 --- a/src/oned/UPCEReader.java +++ /dev/null @@ -1,182 +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.FormatException; -import com.google.zxing.NotFoundException; -import com.google.zxing.common.BitArray; - -/** - *

Implements decoding of the UPC-E format.

- *

This is a great reference for - * UPC-E information.

- * - * @author Sean Owen - */ -public final class UPCEReader extends UPCEANReader { - - /** - * The pattern that marks the middle, and end, of a UPC-E pattern. - * There is no "second half" to a UPC-E barcode. - */ - private static final int[] MIDDLE_END_PATTERN = {1, 1, 1, 1, 1, 1}; - - // For an UPC-E barcode, the final digit is represented by the parities used - // to encode the middle six digits, according to the table below. - // - // Parity of next 6 digits - // Digit 0 1 2 3 4 5 - // 0 Even Even Even Odd Odd Odd - // 1 Even Even Odd Even Odd Odd - // 2 Even Even Odd Odd Even Odd - // 3 Even Even Odd Odd Odd Even - // 4 Even Odd Even Even Odd Odd - // 5 Even Odd Odd Even Even Odd - // 6 Even Odd Odd Odd Even Even - // 7 Even Odd Even Odd Even Odd - // 8 Even Odd Even Odd Odd Even - // 9 Even Odd Odd Even Odd Even - // - // The encoding is represented by the following array, which is a bit pattern - // using Odd = 0 and Even = 1. For example, 5 is represented by: - // - // Odd Even Even Odd Odd Even - // in binary: - // 0 1 1 0 0 1 == 0x19 - // - - /** - * See {@link #L_AND_G_PATTERNS}; these values similarly represent patterns of - * even-odd parity encodings of digits that imply both the number system (0 or 1) - * used, and the check digit. - */ - static final int[][] NUMSYS_AND_CHECK_DIGIT_PATTERNS = { - {0x38, 0x34, 0x32, 0x31, 0x2C, 0x26, 0x23, 0x2A, 0x29, 0x25}, - {0x07, 0x0B, 0x0D, 0x0E, 0x13, 0x19, 0x1C, 0x15, 0x16, 0x1A} - }; - - private final int[] decodeMiddleCounters; - - public UPCEReader() { - decodeMiddleCounters = new int[4]; - } - - @Override - protected int decodeMiddle(BitArray row, int[] startRange, StringBuilder result) - throws NotFoundException { - int[] counters = decodeMiddleCounters; - counters[0] = 0; - counters[1] = 0; - counters[2] = 0; - counters[3] = 0; - int end = row.getSize(); - int rowOffset = startRange[1]; - - int lgPatternFound = 0; - - for (int x = 0; x < 6 && rowOffset < end; x++) { - int bestMatch = decodeDigit(row, counters, rowOffset, L_AND_G_PATTERNS); - result.append((char) ('0' + bestMatch % 10)); - for (int counter : counters) { - rowOffset += counter; - } - if (bestMatch >= 10) { - lgPatternFound |= 1 << (5 - x); - } - } - - determineNumSysAndCheckDigit(result, lgPatternFound); - - return rowOffset; - } - - @Override - protected int[] decodeEnd(BitArray row, int endStart) throws NotFoundException { - return findGuardPattern(row, endStart, true, MIDDLE_END_PATTERN); - } - - @Override - protected boolean checkChecksum(String s) throws FormatException { - return super.checkChecksum(convertUPCEtoUPCA(s)); - } - - private static void determineNumSysAndCheckDigit(StringBuilder resultString, int lgPatternFound) - throws NotFoundException { - - for (int numSys = 0; numSys <= 1; numSys++) { - for (int d = 0; d < 10; d++) { - if (lgPatternFound == NUMSYS_AND_CHECK_DIGIT_PATTERNS[numSys][d]) { - resultString.insert(0, (char) ('0' + numSys)); - resultString.append((char) ('0' + d)); - return; - } - } - } - throw NotFoundException.getNotFoundInstance(); - } - - @Override - BarcodeFormat getBarcodeFormat() { - return BarcodeFormat.UPC_E; - } - - /** - * Expands a UPC-E value back into its full, equivalent UPC-A code value. - * - * @param upce UPC-E code as string of digits - * @return equivalent UPC-A code as string of digits - */ - public static String convertUPCEtoUPCA(String upce) { - char[] upceChars = new char[6]; - upce.getChars(1, 7, upceChars, 0); - StringBuilder result = new StringBuilder(12); - result.append(upce.charAt(0)); - char lastChar = upceChars[5]; - switch (lastChar) { - case '0': - case '1': - case '2': - result.append(upceChars, 0, 2); - result.append(lastChar); - result.append("0000"); - result.append(upceChars, 2, 3); - break; - case '3': - result.append(upceChars, 0, 3); - result.append("00000"); - result.append(upceChars, 3, 2); - break; - case '4': - result.append(upceChars, 0, 4); - result.append("00000"); - result.append(upceChars[4]); - break; - default: - result.append(upceChars, 0, 5); - result.append("0000"); - result.append(lastChar); - break; - } - // Only append check digit in conversion if supplied - if (upce.length() >= 8) { - result.append(upce.charAt(7)); - } - return result.toString(); - } - -} diff --git a/src/oned/mod.rs b/src/oned/mod.rs index df85e96..4a4fc3e 100644 --- a/src/oned/mod.rs +++ b/src/oned/mod.rs @@ -43,3 +43,6 @@ pub use ean_13_reader::*; mod upc_a_reader; pub use upc_a_reader::*; + +mod upc_e_reader; +pub use upc_e_reader::*; diff --git a/src/oned/upc_e_reader.rs b/src/oned/upc_e_reader.rs new file mode 100644 index 0000000..1c7a185 --- /dev/null +++ b/src/oned/upc_e_reader.rs @@ -0,0 +1,194 @@ +/* + * 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 super::{OneDReader, UPCEANReader, L_AND_G_PATTERNS}; +use crate::{BarcodeFormat, Exceptions}; +use one_d_reader_derive::{EANReader, OneDReader}; + +/** + *

Implements decoding of the UPC-E format.

+ *

This is a great reference for + * UPC-E information.

+ * + * @author Sean Owen + */ +#[derive(OneDReader, EANReader)] +pub struct UPCEReader; + +impl UPCEANReader for UPCEReader { + fn getBarcodeFormat(&self) -> crate::BarcodeFormat { + BarcodeFormat::UPC_E + } + + fn decodeMiddle( + &self, + row: &crate::common::BitArray, + startRange: &[usize; 2], + resultString: &mut String, + ) -> Result { + let mut counters = [0_u32; 4]; //decodeMiddleCounters; + // counters[0] = 0; + // counters[1] = 0; + // counters[2] = 0; + // counters[3] = 0; + let end = row.getSize(); + let mut rowOffset = startRange[1]; + + let mut lgPatternFound = 0; + + let mut x = 0; + while x < 6 && rowOffset < end { + // for (int x = 0; x < 6 && rowOffset < end; x++) { + let bestMatch = Self::decodeDigit(row, &mut counters, rowOffset, &L_AND_G_PATTERNS)?; + resultString.push(char::from_u32('0' as u32 + bestMatch as u32 % 10).unwrap()); + // for (int counter : counters) { + // rowOffset += counter; + // } + rowOffset += counters.iter().sum::() as usize; + + if bestMatch >= 10 { + lgPatternFound |= 1 << (5 - x); + } + + x += 1; + } + + Self::determineNumSysAndCheckDigit(resultString, lgPatternFound)?; + + Ok(rowOffset) + } + + fn checkChecksum(&self, s: &str) -> Result { + Self::checkStandardUPCEANChecksum(&convertUPCEtoUPCA(s)) + } + + fn decodeEnd(row: &crate::common::BitArray, endStart: usize) -> Result<[usize; 2], Exceptions> + where + Self: Sized, + { + Self::findGuardPattern(row, endStart, true, &Self::MIDDLE_END_PATTERN) + } +} + +impl Default for UPCEReader { + fn default() -> Self { + Self {} + } +} + +impl UPCEReader { + /** + * The pattern that marks the middle, and end, of a UPC-E pattern. + * There is no "second half" to a UPC-E barcode. + */ + const MIDDLE_END_PATTERN: [u32; 6] = [1, 1, 1, 1, 1, 1]; + + // For an UPC-E barcode, the final digit is represented by the parities used + // to encode the middle six digits, according to the table below. + // + // Parity of next 6 digits + // Digit 0 1 2 3 4 5 + // 0 Even Even Even Odd Odd Odd + // 1 Even Even Odd Even Odd Odd + // 2 Even Even Odd Odd Even Odd + // 3 Even Even Odd Odd Odd Even + // 4 Even Odd Even Even Odd Odd + // 5 Even Odd Odd Even Even Odd + // 6 Even Odd Odd Odd Even Even + // 7 Even Odd Even Odd Even Odd + // 8 Even Odd Even Odd Odd Even + // 9 Even Odd Odd Even Odd Even + // + // The encoding is represented by the following array, which is a bit pattern + // using Odd = 0 and Even = 1. For example, 5 is represented by: + // + // Odd Even Even Odd Odd Even + // in binary: + // 0 1 1 0 0 1 == 0x19 + // + + /** + * See {@link #L_AND_G_PATTERNS}; these values similarly represent patterns of + * even-odd parity encodings of digits that imply both the number system (0 or 1) + * used, and the check digit. + */ + const NUMSYS_AND_CHECK_DIGIT_PATTERNS: [[usize; 10]; 2] = [ + [0x38, 0x34, 0x32, 0x31, 0x2C, 0x26, 0x23, 0x2A, 0x29, 0x25], + [0x07, 0x0B, 0x0D, 0x0E, 0x13, 0x19, 0x1C, 0x15, 0x16, 0x1A], + ]; + + fn determineNumSysAndCheckDigit( + resultString: &mut String, + lgPatternFound: usize, + ) -> Result<(), Exceptions> { + for numSys in 0..=1 { + // for (int numSys = 0; numSys <= 1; numSys++) { + for d in 0..10 { + // for (int d = 0; d < 10; d++) { + if lgPatternFound == Self::NUMSYS_AND_CHECK_DIGIT_PATTERNS[numSys][d] { + resultString.insert(0, char::from_u32('0' as u32 + numSys as u32).unwrap()); + resultString.push(char::from_u32('0' as u32 + d as u32).unwrap()); + return Ok(()); + } + } + } + return Err(Exceptions::NotFoundException("".to_owned())); + } +} + +/** + * Expands a UPC-E value back into its full, equivalent UPC-A code value. + * + * @param upce UPC-E code as string of digits + * @return equivalent UPC-A code as string of digits + */ +pub fn convertUPCEtoUPCA(upce: &str) -> String { + let upceChars = &upce[1..8]; //['0';6];//new char[6]; + //upce.getChars(1, 7, upceChars, 0); + let mut result = String::with_capacity(12); //new StringBuilder(12); + result.push(upce.chars().nth(0).unwrap()); + let lastChar = upceChars.chars().nth(5).unwrap(); + match lastChar { + '0' | '1' | '2' => { + result.push_str(&upceChars[0..2]); + // result.push(upceChars, 0, 2); + result.push(lastChar); + result.push_str("0000"); + result.push_str(&upceChars[2..3 + 2]); + } + '3' => { + result.push_str(&upceChars[0..3]); + result.push_str("00000"); + result.push_str(&upceChars[3..2 + 3]); + } + '4' => { + result.push_str(&upceChars[0..4]); + result.push_str("00000"); + result.push(upceChars.chars().nth(4).unwrap()); + } + _ => { + result.push_str(&upceChars[0..5]); + result.push_str("0000"); + result.push(lastChar); + } + } + // Only append check digit in conversion if supplied + if upce.chars().count() >= 8 { + result.push(upce.chars().nth(7).unwrap()); + } + + result +} diff --git a/tests/UPCEANExtensionBlackBox1TestCase.java b/tests/UPCEANExtensionBlackBox1TestCase.java deleted file mode 100644 index 020bba1..0000000 --- a/tests/UPCEANExtensionBlackBox1TestCase.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.MultiFormatReader; -import com.google.zxing.common.AbstractBlackBoxTestCase; - -/** - * @author Sean Owen - */ -public final class UPCEANExtensionBlackBox1TestCase extends AbstractBlackBoxTestCase { - - public UPCEANExtensionBlackBox1TestCase() { - super("src/test/resources/blackbox/upcean-extension-1", new MultiFormatReader(), BarcodeFormat.EAN_13); - addTest(2, 2, 0.0f); - } - -} \ No newline at end of file diff --git a/tests/UPCEBlackBox1TestCase.java b/tests/UPCEBlackBox1TestCase.java deleted file mode 100644 index a36fa0b..0000000 --- a/tests/UPCEBlackBox1TestCase.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 UPCEBlackBox1TestCase extends AbstractBlackBoxTestCase { - - public UPCEBlackBox1TestCase() { - super("src/test/resources/blackbox/upce-1", new MultiFormatReader(), BarcodeFormat.UPC_E); - addTest(3, 3, 0.0f); - addTest(3, 3, 180.0f); - } - -} \ No newline at end of file diff --git a/tests/UPCEBlackBox2TestCase.java b/tests/UPCEBlackBox2TestCase.java deleted file mode 100644 index 49d7c17..0000000 --- a/tests/UPCEBlackBox2TestCase.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 UPCEBlackBox2TestCase extends AbstractBlackBoxTestCase { - - public UPCEBlackBox2TestCase() { - super("src/test/resources/blackbox/upce-2", new MultiFormatReader(), BarcodeFormat.UPC_E); - addTest(31, 35, 0, 1, 0.0f); - addTest(31, 35, 1, 1, 180.0f); - } - -} diff --git a/tests/UPCEBlackBox3ReflectiveTestCase.java b/tests/UPCEBlackBox3ReflectiveTestCase.java deleted file mode 100644 index bbf522a..0000000 --- a/tests/UPCEBlackBox3ReflectiveTestCase.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 UPCEBlackBox3ReflectiveTestCase extends AbstractBlackBoxTestCase { - - public UPCEBlackBox3ReflectiveTestCase() { - super("src/test/resources/blackbox/upce-3", new MultiFormatReader(), BarcodeFormat.UPC_E); - addTest(6, 8, 0.0f); - addTest(6, 8, 180.0f); - } - -} diff --git a/tests/upc_e_blackbox_tests.rs b/tests/upc_e_blackbox_tests.rs new file mode 100644 index 0000000..e6266e0 --- /dev/null +++ b/tests/upc_e_blackbox_tests.rs @@ -0,0 +1,79 @@ +/* + * 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 rxing::{ + oned::{EAN13Reader, UPCEReader}, + BarcodeFormat, MultiFormatReader, +}; + +mod common; + +/** + * @author Sean Owen + */ +#[test] +fn upceblack_box1_test_case() { + let mut tester = common::AbstractBlackBoxTestCase::new( + "test_resources/blackbox/upce-1", + // MultiFormatReader::default(), + UPCEReader::default(), + BarcodeFormat::UPC_E, + ); + + // super("src/test/resources/blackbox/upce-1", new MultiFormatReader(), BarcodeFormat.UPC_E); + tester.add_test(3, 3, 0.0); + tester.add_test(3, 3, 180.0); + + tester.test_black_box() +} + +/** + * @author dswitkin@google.com (Daniel Switkin) + */ +#[test] +fn upceblack_box2_test_case() { + let mut tester = common::AbstractBlackBoxTestCase::new( + "test_resources/blackbox/upce-2", + // MultiFormatReader::default(), + UPCEReader::default(), + BarcodeFormat::UPC_E, + ); + + // super("src/test/resources/blackbox/upce-2", new MultiFormatReader(), BarcodeFormat.UPC_E); + tester.add_test_complex(31, 35, 0, 1, 0.0); + tester.add_test_complex(31, 35, 1, 1, 180.0); + + tester.test_black_box() +} + +/** + * @author dswitkin@google.com (Daniel Switkin) + */ +#[test] +fn upceblack_box3_reflective_test_case() { + let mut tester = common::AbstractBlackBoxTestCase::new( + "test_resources/blackbox/upce-3", + // MultiFormatReader::default(), + UPCEReader::default(), + BarcodeFormat::UPC_E, + ); + + // super("src/test/resources/blackbox/upce-3", new MultiFormatReader(), BarcodeFormat.UPC_E); + tester.add_test(6, 8, 0.0); + tester.add_test(6, 8, 180.0); + + tester.test_black_box() +}