From 0560a2490b1a9b4dc13a5253b0ae5acd42945dad Mon Sep 17 00:00:00 2001 From: Henry Schimke Date: Tue, 13 Dec 2022 12:13:59 -0600 Subject: [PATCH] oned writers + tests --- src/oned/EAN13Writer.java | 101 ---------- src/oned/EAN13WriterTestCase.java | 50 ----- src/oned/EAN8Writer.java | 98 ---------- src/oned/EAN8WriterTestCase.java | 48 ----- src/oned/UPCAWriter.java | 53 ----- src/oned/UPCAWriterTestCase.java | 47 ----- src/oned/UPCEWriter.java | 96 --------- src/oned/UPCEWriterTestCase.java | 57 ------ src/oned/ean_13_reader.rs | 2 +- src/oned/ean_13_writer.rs | 184 ++++++++++++++++++ src/oned/ean_8_writer.rs | 169 ++++++++++++++++ src/oned/mod.rs | 15 ++ src/oned/one_d_code_writer.rs | 11 +- src/oned/upc_a_writer.rs | 112 +++++++++++ src/oned/upc_e_reader.rs | 6 +- src/oned/upc_e_writer.rs | 177 +++++++++++++++++ .../{UPCEANWriter.java => upc_ean_writer.rs} | 12 +- 17 files changed, 672 insertions(+), 566 deletions(-) delete mode 100644 src/oned/EAN13Writer.java delete mode 100644 src/oned/EAN13WriterTestCase.java delete mode 100644 src/oned/EAN8Writer.java delete mode 100644 src/oned/EAN8WriterTestCase.java delete mode 100644 src/oned/UPCAWriter.java delete mode 100644 src/oned/UPCAWriterTestCase.java delete mode 100644 src/oned/UPCEWriter.java delete mode 100644 src/oned/UPCEWriterTestCase.java create mode 100644 src/oned/ean_13_writer.rs create mode 100644 src/oned/ean_8_writer.rs create mode 100644 src/oned/upc_a_writer.rs create mode 100644 src/oned/upc_e_writer.rs rename src/oned/{UPCEANWriter.java => upc_ean_writer.rs} (78%) diff --git a/src/oned/EAN13Writer.java b/src/oned/EAN13Writer.java deleted file mode 100644 index 02293f3..0000000 --- a/src/oned/EAN13Writer.java +++ /dev/null @@ -1,101 +0,0 @@ -/* - * Copyright 2009 ZXing authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.google.zxing.oned; - -import com.google.zxing.BarcodeFormat; -import com.google.zxing.FormatException; -import com.google.zxing.common.BitMatrix; - -import java.util.Collection; -import java.util.Collections; - -/** - * This object renders an EAN13 code as a {@link BitMatrix}. - * - * @author aripollak@gmail.com (Ari Pollak) - */ -public final class EAN13Writer extends UPCEANWriter { - - private static final int CODE_WIDTH = 3 + // start guard - (7 * 6) + // left bars - 5 + // middle guard - (7 * 6) + // right bars - 3; // end guard - - @Override - protected Collection getSupportedWriteFormats() { - return Collections.singleton(BarcodeFormat.EAN_13); - } - - @Override - public boolean[] encode(String contents) { - int length = contents.length(); - switch (length) { - case 12: - // No check digit present, calculate it and add it - int check; - try { - check = UPCEANReader.getStandardUPCEANChecksum(contents); - } catch (FormatException fe) { - throw new IllegalArgumentException(fe); - } - contents += check; - break; - case 13: - try { - if (!UPCEANReader.checkStandardUPCEANChecksum(contents)) { - throw new IllegalArgumentException("Contents do not pass checksum"); - } - } catch (FormatException ignored) { - throw new IllegalArgumentException("Illegal contents"); - } - break; - default: - throw new IllegalArgumentException( - "Requested contents should be 12 or 13 digits long, but got " + length); - } - - checkNumeric(contents); - - int firstDigit = Character.digit(contents.charAt(0), 10); - int parities = EAN13Reader.FIRST_DIGIT_ENCODINGS[firstDigit]; - boolean[] result = new boolean[CODE_WIDTH]; - int pos = 0; - - pos += appendPattern(result, pos, UPCEANReader.START_END_PATTERN, true); - - // See EAN13Reader for a description of how the first digit & left bars are encoded - for (int i = 1; i <= 6; i++) { - int digit = Character.digit(contents.charAt(i), 10); - if ((parities >> (6 - i) & 1) == 1) { - digit += 10; - } - pos += appendPattern(result, pos, UPCEANReader.L_AND_G_PATTERNS[digit], false); - } - - pos += appendPattern(result, pos, UPCEANReader.MIDDLE_PATTERN, false); - - for (int i = 7; i <= 12; i++) { - int digit = Character.digit(contents.charAt(i), 10); - pos += appendPattern(result, pos, UPCEANReader.L_PATTERNS[digit], true); - } - appendPattern(result, pos, UPCEANReader.START_END_PATTERN, true); - - return result; - } - -} diff --git a/src/oned/EAN13WriterTestCase.java b/src/oned/EAN13WriterTestCase.java deleted file mode 100644 index 4d49499..0000000 --- a/src/oned/EAN13WriterTestCase.java +++ /dev/null @@ -1,50 +0,0 @@ -/* - * Copyright 2009 ZXing authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.google.zxing.oned; - -import com.google.zxing.BarcodeFormat; -import com.google.zxing.common.BitMatrix; -import com.google.zxing.common.BitMatrixTestCase; -import org.junit.Assert; -import org.junit.Test; - -/** - * @author Ari Pollak - */ -public final class EAN13WriterTestCase extends Assert { - - @Test - public void testEncode() { - String testStr = - "00001010001011010011101100110010011011110100111010101011001101101100100001010111001001110100010010100000"; - BitMatrix result = new EAN13Writer().encode("5901234123457", BarcodeFormat.EAN_13, testStr.length(), 0); - assertEquals(testStr, BitMatrixTestCase.matrixToString(result)); - } - - @Test - public void testAddChecksumAndEncode() { - String testStr = - "00001010001011010011101100110010011011110100111010101011001101101100100001010111001001110100010010100000"; - BitMatrix result = new EAN13Writer().encode("590123412345", BarcodeFormat.EAN_13, testStr.length(), 0); - assertEquals(testStr, BitMatrixTestCase.matrixToString(result)); - } - - @Test(expected = IllegalArgumentException.class) - public void testEncodeIllegalCharacters() { - new EAN13Writer().encode("5901234123abc", BarcodeFormat.EAN_13, 0, 0); - } -} diff --git a/src/oned/EAN8Writer.java b/src/oned/EAN8Writer.java deleted file mode 100644 index 5050141..0000000 --- a/src/oned/EAN8Writer.java +++ /dev/null @@ -1,98 +0,0 @@ -/* - * Copyright 2009 ZXing authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.google.zxing.oned; - -import com.google.zxing.BarcodeFormat; -import com.google.zxing.FormatException; -import com.google.zxing.common.BitMatrix; - -import java.util.Collection; -import java.util.Collections; - -/** - * This object renders an EAN8 code as a {@link BitMatrix}. - * - * @author aripollak@gmail.com (Ari Pollak) - */ -public final class EAN8Writer extends UPCEANWriter { - - private static final int CODE_WIDTH = 3 + // start guard - (7 * 4) + // left bars - 5 + // middle guard - (7 * 4) + // right bars - 3; // end guard - - @Override - protected Collection getSupportedWriteFormats() { - return Collections.singleton(BarcodeFormat.EAN_8); - } - - /** - * @return a byte array of horizontal pixels (false = white, true = black) - */ - @Override - public boolean[] encode(String contents) { - int length = contents.length(); - switch (length) { - case 7: - // No check digit present, calculate it and add it - int check; - try { - check = UPCEANReader.getStandardUPCEANChecksum(contents); - } catch (FormatException fe) { - throw new IllegalArgumentException(fe); - } - contents += check; - break; - case 8: - try { - if (!UPCEANReader.checkStandardUPCEANChecksum(contents)) { - throw new IllegalArgumentException("Contents do not pass checksum"); - } - } catch (FormatException ignored) { - throw new IllegalArgumentException("Illegal contents"); - } - break; - default: - throw new IllegalArgumentException( - "Requested contents should be 7 or 8 digits long, but got " + length); - } - - checkNumeric(contents); - - boolean[] result = new boolean[CODE_WIDTH]; - int pos = 0; - - pos += appendPattern(result, pos, UPCEANReader.START_END_PATTERN, true); - - for (int i = 0; i <= 3; i++) { - int digit = Character.digit(contents.charAt(i), 10); - pos += appendPattern(result, pos, UPCEANReader.L_PATTERNS[digit], false); - } - - pos += appendPattern(result, pos, UPCEANReader.MIDDLE_PATTERN, false); - - for (int i = 4; i <= 7; i++) { - int digit = Character.digit(contents.charAt(i), 10); - pos += appendPattern(result, pos, UPCEANReader.L_PATTERNS[digit], true); - } - appendPattern(result, pos, UPCEANReader.START_END_PATTERN, true); - - return result; - } - -} diff --git a/src/oned/EAN8WriterTestCase.java b/src/oned/EAN8WriterTestCase.java deleted file mode 100644 index 8659822..0000000 --- a/src/oned/EAN8WriterTestCase.java +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Copyright 2009 ZXing authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.google.zxing.oned; - -import com.google.zxing.BarcodeFormat; -import com.google.zxing.common.BitMatrix; -import com.google.zxing.common.BitMatrixTestCase; -import org.junit.Assert; -import org.junit.Test; - -/** - * @author Ari Pollak - */ -public final class EAN8WriterTestCase extends Assert { - - @Test - public void testEncode() { - String testStr = "0000001010001011010111101111010110111010101001110111001010001001011100101000000"; - BitMatrix result = new EAN8Writer().encode("96385074", BarcodeFormat.EAN_8, testStr.length(), 0); - assertEquals(testStr, BitMatrixTestCase.matrixToString(result)); - } - - @Test - public void testAddChecksumAndEncode() { - String testStr = "0000001010001011010111101111010110111010101001110111001010001001011100101000000"; - BitMatrix result = new EAN8Writer().encode("9638507", BarcodeFormat.EAN_8, testStr.length(), 0); - assertEquals(testStr, BitMatrixTestCase.matrixToString(result)); - } - - @Test(expected = IllegalArgumentException.class) - public void testEncodeIllegalCharacters() { - new EAN8Writer().encode("96385abc", BarcodeFormat.EAN_8, 0, 0); - } -} diff --git a/src/oned/UPCAWriter.java b/src/oned/UPCAWriter.java deleted file mode 100644 index c2aa7af..0000000 --- a/src/oned/UPCAWriter.java +++ /dev/null @@ -1,53 +0,0 @@ -/* - * Copyright 2010 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.EncodeHintType; -import com.google.zxing.Writer; -import com.google.zxing.common.BitMatrix; - -import java.util.Map; - -/** - * This object renders a UPC-A code as a {@link BitMatrix}. - * - * @author qwandor@google.com (Andrew Walbran) - */ -public final class UPCAWriter implements Writer { - - private final EAN13Writer subWriter = new EAN13Writer(); - - @Override - public BitMatrix encode(String contents, BarcodeFormat format, int width, int height) { - return encode(contents, format, width, height, null); - } - - @Override - public BitMatrix encode(String contents, - BarcodeFormat format, - int width, - int height, - Map hints) { - if (format != BarcodeFormat.UPC_A) { - throw new IllegalArgumentException("Can only encode UPC-A, but got " + format); - } - // Transform a UPC-A code into the equivalent EAN-13 code and write it that way - return subWriter.encode('0' + contents, BarcodeFormat.EAN_13, width, height, hints); - } - -} diff --git a/src/oned/UPCAWriterTestCase.java b/src/oned/UPCAWriterTestCase.java deleted file mode 100644 index b444479..0000000 --- a/src/oned/UPCAWriterTestCase.java +++ /dev/null @@ -1,47 +0,0 @@ -/* - * Copyright 2010 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.BitMatrix; - -import com.google.zxing.common.BitMatrixTestCase; -import org.junit.Assert; -import org.junit.Test; - -/** - * @author qwandor@google.com (Andrew Walbran) - */ -public final class UPCAWriterTestCase extends Assert { - - @Test - public void testEncode() { - String testStr = - "00001010100011011011101100010001011010111101111010101011100101110100100111011001101101100101110010100000"; - BitMatrix result = new UPCAWriter().encode("485963095124", BarcodeFormat.UPC_A, testStr.length(), 0); - assertEquals(testStr, BitMatrixTestCase.matrixToString(result)); - } - - @Test - public void testAddChecksumAndEncode() { - String testStr = - "00001010011001001001101111010100011011000101011110101010001001001000111010011100101100110110110010100000"; - BitMatrix result = new UPCAWriter().encode("12345678901", BarcodeFormat.UPC_A, testStr.length(), 0); - assertEquals(testStr, BitMatrixTestCase.matrixToString(result)); - } - -} diff --git a/src/oned/UPCEWriter.java b/src/oned/UPCEWriter.java deleted file mode 100644 index 48bac6f..0000000 --- a/src/oned/UPCEWriter.java +++ /dev/null @@ -1,96 +0,0 @@ -/* - * Copyright 2009 ZXing authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.google.zxing.oned; - -import java.util.Collection; -import java.util.Collections; - -import com.google.zxing.BarcodeFormat; -import com.google.zxing.FormatException; -import com.google.zxing.common.BitMatrix; - -/** - * This object renders an UPC-E code as a {@link BitMatrix}. - * - * @author 0979097955s@gmail.com (RX) - */ -public final class UPCEWriter extends UPCEANWriter { - - private static final int CODE_WIDTH = 3 + // start guard - (7 * 6) + // bars - 6; // end guard - - @Override - protected Collection getSupportedWriteFormats() { - return Collections.singleton(BarcodeFormat.UPC_E); - } - - @Override - public boolean[] encode(String contents) { - int length = contents.length(); - switch (length) { - case 7: - // No check digit present, calculate it and add it - int check; - try { - check = UPCEANReader.getStandardUPCEANChecksum(UPCEReader.convertUPCEtoUPCA(contents)); - } catch (FormatException fe) { - throw new IllegalArgumentException(fe); - } - contents += check; - break; - case 8: - try { - if (!UPCEANReader.checkStandardUPCEANChecksum(UPCEReader.convertUPCEtoUPCA(contents))) { - throw new IllegalArgumentException("Contents do not pass checksum"); - } - } catch (FormatException ignored) { - throw new IllegalArgumentException("Illegal contents"); - } - break; - default: - throw new IllegalArgumentException( - "Requested contents should be 7 or 8 digits long, but got " + length); - } - - checkNumeric(contents); - - int firstDigit = Character.digit(contents.charAt(0), 10); - if (firstDigit != 0 && firstDigit != 1) { - throw new IllegalArgumentException("Number system must be 0 or 1"); - } - - int checkDigit = Character.digit(contents.charAt(7), 10); - int parities = UPCEReader.NUMSYS_AND_CHECK_DIGIT_PATTERNS[firstDigit][checkDigit]; - boolean[] result = new boolean[CODE_WIDTH]; - - int pos = appendPattern(result, 0, UPCEANReader.START_END_PATTERN, true); - - for (int i = 1; i <= 6; i++) { - int digit = Character.digit(contents.charAt(i), 10); - if ((parities >> (6 - i) & 1) == 1) { - digit += 10; - } - pos += appendPattern(result, pos, UPCEANReader.L_AND_G_PATTERNS[digit], false); - } - - appendPattern(result, pos, UPCEANReader.END_PATTERN, false); - - return result; - } - -} diff --git a/src/oned/UPCEWriterTestCase.java b/src/oned/UPCEWriterTestCase.java deleted file mode 100644 index 3a7a9e0..0000000 --- a/src/oned/UPCEWriterTestCase.java +++ /dev/null @@ -1,57 +0,0 @@ -/* - * Copyright 2016 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.BitMatrix; -import com.google.zxing.common.BitMatrixTestCase; -import org.junit.Assert; -import org.junit.Test; - -/** - * Tests {@link UPCEWriter}. - */ -public final class UPCEWriterTestCase extends Assert { - - @Test - public void testEncode() { - doTest("05096893", - "0000000000010101110010100111000101101011110110111001011101010100000000000"); - } - - @Test - public void testEncodeSystem1() { - doTest("12345670", - "0000000000010100100110111101010001101110010000101001000101010100000000000"); - } - - @Test - public void testAddChecksumAndEncode() { - doTest("0509689", - "0000000000010101110010100111000101101011110110111001011101010100000000000"); - } - - private static void doTest(String content, String encoding) { - BitMatrix result = new UPCEWriter().encode(content, BarcodeFormat.UPC_E, encoding.length(), 0); - assertEquals(encoding, BitMatrixTestCase.matrixToString(result)); - } - - @Test(expected = IllegalArgumentException.class) - public void testEncodeIllegalCharacters() { - new UPCEWriter().encode("05096abc", BarcodeFormat.UPC_E, 0, 0); - } -} diff --git a/src/oned/ean_13_reader.rs b/src/oned/ean_13_reader.rs index fd66124..5a1eca4 100644 --- a/src/oned/ean_13_reader.rs +++ b/src/oned/ean_13_reader.rs @@ -130,7 +130,7 @@ impl EAN13Reader { // in binary: // 0 1 1 0 0 1 == 0x19 // - const FIRST_DIGIT_ENCODINGS: [usize; 10] = + pub const FIRST_DIGIT_ENCODINGS: [usize; 10] = [0x00, 0x0B, 0x0D, 0xE, 0x13, 0x19, 0x1C, 0x15, 0x16, 0x1A]; /** diff --git a/src/oned/ean_13_writer.rs b/src/oned/ean_13_writer.rs new file mode 100644 index 0000000..8f7ac16 --- /dev/null +++ b/src/oned/ean_13_writer.rs @@ -0,0 +1,184 @@ +/* + * Copyright 2009 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +use one_d_reader_derive::OneDWriter; + +use crate::{ + oned::{upc_ean_reader, EAN13Reader}, + BarcodeFormat, +}; + +use super::{OneDimensionalCodeWriter, UPCEANReader, UPCEANWriter}; + +/** + * This object renders an EAN13 code as a {@link BitMatrix}. + * + * @author aripollak@gmail.com (Ari Pollak) + */ +#[derive(OneDWriter)] +pub struct EAN13Writer; +impl UPCEANWriter for EAN13Writer {} + +impl OneDimensionalCodeWriter for EAN13Writer { + fn encode_oned(&self, contents: &str) -> Result, crate::Exceptions> { + let reader: EAN13Reader = EAN13Reader::default(); + let mut contents = contents.to_owned(); + let length = contents.chars().count(); + match length { + 12 => { + // No check digit present, calculate it and add it + let check; + // try { + check = reader.getStandardUPCEANChecksum(&contents)?; + // } catch (FormatException fe) { + // throw new IllegalArgumentException(fe); + // } + contents.push_str(&check.to_string()); + } + 13 => { + //try { + if !reader.checkStandardUPCEANChecksum(&contents)? { + return Err(Exceptions::IllegalArgumentException( + "Contents do not pass checksum".to_owned(), + )); + } + //} catch (FormatException ignored) { + //return Err( Exceptions::IllegalArgumentException("Illegal contents".to_owned())); + //} + } + _ => { + return Err(Exceptions::IllegalArgumentException(format!( + "Requested contents should be 12 or 13 digits long, but got {}", + length + ))) + } + } + + EAN13Writer::checkNumeric(&contents); + + let firstDigit = contents.chars().nth(0).unwrap().to_digit(10).unwrap() as usize; //, 10); + let parities = EAN13Reader::FIRST_DIGIT_ENCODINGS[firstDigit]; + let mut result = [false; CODE_WIDTH]; + let mut pos = 0; + + pos += + EAN13Writer::appendPattern(&mut result, pos, &upc_ean_reader::START_END_PATTERN, true) + as usize; + + // See EAN13Reader for a description of how the first digit & left bars are encoded + for i in 1..=6 { + // for (int i = 1; i <= 6; i++) { + let mut digit = contents.chars().nth(i).unwrap().to_digit(10).unwrap() as usize; //Character.digit(contents.charAt(i), 10); + if (parities >> (6 - i) & 1) == 1 { + digit += 10; + } + pos += EAN13Writer::appendPattern( + &mut result, + pos, + &upc_ean_reader::L_AND_G_PATTERNS[digit], + false, + ) as usize; + } + + pos += EAN13Writer::appendPattern(&mut result, pos, &upc_ean_reader::MIDDLE_PATTERN, false) + as usize; + + for i in 7..=12 { + // for (int i = 7; i <= 12; i++) { + // let digit = Character.digit(contents.charAt(i), 10); + let digit = contents.chars().nth(i).unwrap().to_digit(10).unwrap() as usize; //Character.digit(contents.charAt(i), 10); + + pos += EAN13Writer::appendPattern( + &mut result, + pos, + &upc_ean_reader::L_PATTERNS[digit], + true, + ) as usize; + } + EAN13Writer::appendPattern(&mut result, pos, &upc_ean_reader::START_END_PATTERN, true); + + Ok(result.to_vec()) + } + + fn getSupportedWriteFormats(&self) -> Option> { + Some(vec![BarcodeFormat::EAN_13]) + } + + fn getDefaultMargin(&self) -> u32 { + // CodaBar spec requires a side margin to be more than ten times wider than narrow space. + // This seems like a decent idea for a default for all formats. + Self::DEFAULT_MARGIN + } +} +impl Default for EAN13Writer { + fn default() -> Self { + Self {} + } +} + +const CODE_WIDTH: usize = 3 + // start guard + (7 * 6) + // left bars + 5 + // middle guard + (7 * 6) + // right bars + 3; // end guard + +/** + * @author Ari Pollak + */ +#[cfg(test)] +mod EAN13WriterTestCase { + use crate::{common::BitMatrixTestCase, BarcodeFormat, Writer}; + + use super::EAN13Writer; + + #[test] + fn testEncode() { + let testStr = + "00001010001011010011101100110010011011110100111010101011001101101100100001010111001001110100010010100000"; + let result = EAN13Writer::default() + .encode( + "5901234123457", + &BarcodeFormat::EAN_13, + testStr.chars().count() as i32, + 0, + ) + .expect("exist"); + assert_eq!(testStr, BitMatrixTestCase::matrix_to_string(&result)); + } + + #[test] + fn testAddChecksumAndEncode() { + let testStr = + "00001010001011010011101100110010011011110100111010101011001101101100100001010111001001110100010010100000"; + let result = EAN13Writer::default() + .encode( + "590123412345", + &BarcodeFormat::EAN_13, + testStr.chars().count() as i32, + 0, + ) + .expect("exist"); + assert_eq!(testStr, BitMatrixTestCase::matrix_to_string(&result)); + } + + #[test] + #[should_panic] + fn testEncodeIllegalCharacters() { + EAN13Writer::default() + .encode("5901234123abc", &BarcodeFormat::EAN_13, 0, 0) + .expect("encode"); + } +} diff --git a/src/oned/ean_8_writer.rs b/src/oned/ean_8_writer.rs new file mode 100644 index 0000000..cca8007 --- /dev/null +++ b/src/oned/ean_8_writer.rs @@ -0,0 +1,169 @@ +/* + * Copyright 2009 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +use one_d_reader_derive::OneDWriter; + +use crate::{ + oned::{EAN8Reader, UPCEANReader}, + BarcodeFormat, +}; + +use super::{upc_ean_reader, OneDimensionalCodeWriter, UPCEANWriter}; + +/** + * This object renders an EAN8 code as a {@link BitMatrix}. + * + * @author aripollak@gmail.com (Ari Pollak) + */ +#[derive(OneDWriter)] +pub struct EAN8Writer; + +const CODE_WIDTH: usize = 3 + // start guard + (7 * 4) + // left bars + 5 + // middle guard + (7 * 4) + // right bars + 3; // end guard + +impl Default for EAN8Writer { + fn default() -> Self { + Self {} + } +} +impl UPCEANWriter for EAN8Writer {} +impl OneDimensionalCodeWriter for EAN8Writer { + /** + * @return a byte array of horizontal pixels (false = white, true = black) + */ + fn encode_oned(&self, contents: &str) -> Result, Exceptions> { + let length = contents.chars().count(); + let reader = EAN8Reader::default(); + let mut contents = contents.to_owned(); + match length { + 7 => { + // No check digit present, calculate it and add it + let check = reader.getStandardUPCEANChecksum(&contents)?; + // try { + // check = UPCEANReader.getStandardUPCEANChecksum(contents); + // } catch (FormatException fe) { + // throw new IllegalArgumentException(fe); + // } + contents.push_str(&check.to_string()); + } + 8 => + // try { + { + if !EAN8Reader.checkStandardUPCEANChecksum(&contents)? { + return Err(Exceptions::IllegalArgumentException( + "Contents do not pass checksum".to_owned(), + )); + } + } + // } catch (FormatException ignored) { + // throw new IllegalArgumentException("Illegal contents"); + // }}, + _ => { + return Err(Exceptions::IllegalArgumentException(format!( + "Requested contents should be 7 or 8 digits long, but got {}", + length + ))) + } + } + + Self::checkNumeric(&contents)?; + + let mut result = [false; CODE_WIDTH]; //new boolean[CODE_WIDTH]; + let mut pos = 0; + + pos += Self::appendPattern(&mut result, pos, &upc_ean_reader::START_END_PATTERN, true) + as usize; + + for i in 0..=3 { + // for (int i = 0; i <= 3; i++) { + let digit = contents.chars().nth(i).unwrap().to_digit(10).unwrap() as usize; //Character.digit(contents.charAt(i), 10); + pos += Self::appendPattern(&mut result, pos, &upc_ean_reader::L_PATTERNS[digit], false) + as usize; + } + + pos += + Self::appendPattern(&mut result, pos, &upc_ean_reader::MIDDLE_PATTERN, false) as usize; + + for i in 4..=7 { + // for (int i = 4; i <= 7; i++) { + let digit = contents.chars().nth(i).unwrap().to_digit(10).unwrap() as usize; //Character.digit(contents.charAt(i), 10); + pos += Self::appendPattern(&mut result, pos, &upc_ean_reader::L_PATTERNS[digit], true) + as usize; + } + Self::appendPattern(&mut result, pos, &upc_ean_reader::START_END_PATTERN, true); + + Ok(result.to_vec()) + } + + fn getSupportedWriteFormats(&self) -> Option> { + Some(vec![BarcodeFormat::EAN_8]) + } + + fn getDefaultMargin(&self) -> u32 { + Self::DEFAULT_MARGIN + } +} + +/** + * @author Ari Pollak + */ +#[cfg(test)] +mod EAN8WriterTestCase { + use crate::{common::BitMatrixTestCase, BarcodeFormat, Writer}; + + use super::EAN8Writer; + + #[test] + fn testEncode() { + let testStr = + "0000001010001011010111101111010110111010101001110111001010001001011100101000000"; + let result = EAN8Writer::default() + .encode( + "96385074", + &BarcodeFormat::EAN_8, + testStr.chars().count() as i32, + 0, + ) + .expect("ok"); + assert_eq!(testStr, BitMatrixTestCase::matrix_to_string(&result)); + } + + #[test] + fn testAddChecksumAndEncode() { + let testStr = + "0000001010001011010111101111010110111010101001110111001010001001011100101000000"; + let result = EAN8Writer::default() + .encode( + "9638507", + &BarcodeFormat::EAN_8, + testStr.chars().count() as i32, + 0, + ) + .expect("ok"); + assert_eq!(testStr, BitMatrixTestCase::matrix_to_string(&result)); + } + + #[test] + #[should_panic] + fn testEncodeIllegalCharacters() { + EAN8Writer::default() + .encode("96385abc", &BarcodeFormat::EAN_8, 0, 0) + .expect("ok"); + } +} diff --git a/src/oned/mod.rs b/src/oned/mod.rs index 24cd73d..e195fcf 100644 --- a/src/oned/mod.rs +++ b/src/oned/mod.rs @@ -70,3 +70,18 @@ pub use code_128_writer::*; #[cfg(test)] mod code_128_writer_test_tase; + +mod upc_a_writer; +pub use upc_a_writer::*; + +mod ean_13_writer; +pub use ean_13_writer::*; + +mod upc_ean_writer; +pub use upc_ean_writer::*; + +mod ean_8_writer; +pub use ean_8_writer::*; + +mod upc_e_writer; +pub use upc_e_writer::*; diff --git a/src/oned/one_d_code_writer.rs b/src/oned/one_d_code_writer.rs index 22f2c06..115d01d 100644 --- a/src/oned/one_d_code_writer.rs +++ b/src/oned/one_d_code_writer.rs @@ -118,18 +118,23 @@ pub trait OneDimensionalCodeWriter: Writer { * @param startColor starting color - false for white, true for black * @return the number of elements added to target. */ - fn appendPattern(target: &mut [bool], pos: usize, pattern: &[usize], startColor: bool) -> u32 { + fn appendPattern + Copy>( + target: &mut [bool], + pos: usize, + pattern: &[T], + startColor: bool, + ) -> u32 { let mut color = startColor; let mut numAdded = 0; let mut pos = pos; for len in pattern { // for (int len : pattern) { - for _j in 0..*len { + for _j in 0..TryInto::::try_into(*len).unwrap_or_default() { // for (int j = 0; j < len; j++) { target[pos] = color; pos += 1; } - numAdded += len; + numAdded += TryInto::::try_into(*len).unwrap_or_default(); color = !color; // flip color after each segment } numAdded as u32 diff --git a/src/oned/upc_a_writer.rs b/src/oned/upc_a_writer.rs new file mode 100644 index 0000000..3e50764 --- /dev/null +++ b/src/oned/upc_a_writer.rs @@ -0,0 +1,112 @@ +/* + * Copyright 2010 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 std::collections::HashMap; + +use crate::{BarcodeFormat, Exceptions, Writer}; + +use super::EAN13Writer; + +/** + * This object renders a UPC-A code as a {@link BitMatrix}. + * + * @author qwandor@google.com (Andrew Walbran) + */ +pub struct UPCAWriter(EAN13Writer); + +impl Default for UPCAWriter { + fn default() -> Self { + Self(Default::default()) + } +} + +impl Writer for UPCAWriter { + fn encode( + &self, + contents: &str, + format: &crate::BarcodeFormat, + width: i32, + height: i32, + ) -> Result { + self.encode_with_hints(contents, format, width, height, &HashMap::new()) + } + + fn encode_with_hints( + &self, + contents: &str, + format: &crate::BarcodeFormat, + width: i32, + height: i32, + hints: &crate::EncodingHintDictionary, + ) -> Result { + if format != &BarcodeFormat::UPC_A { + return Err(Exceptions::IllegalArgumentException(format!( + "Can only encode UPC-A, but got {:?}", + format + ))); + } + // Transform a UPC-A code into the equivalent EAN-13 code and write it that way + self.0.encode_with_hints( + &format!("0{}", contents), + &BarcodeFormat::EAN_13, + width, + height, + &hints, + ) + } +} + +// private final EAN13Writer subWriter = new EAN13Writer(); + +/** + * @author qwandor@google.com (Andrew Walbran) + */ +#[cfg(test)] +mod UPCAWriterTestCase { + use crate::{common::BitMatrixTestCase, BarcodeFormat, Writer}; + + use super::UPCAWriter; + + #[test] + fn testEncode() { + let testStr = + "00001010100011011011101100010001011010111101111010101011100101110100100111011001101101100101110010100000"; + let result = UPCAWriter::default() + .encode( + "485963095124", + &BarcodeFormat::UPC_A, + testStr.chars().count() as i32, + 0, + ) + .expect("ok"); + assert_eq!(testStr, BitMatrixTestCase::matrix_to_string(&result)); + } + + #[test] + fn testAddChecksumAndEncode() { + let testStr = + "00001010011001001001101111010100011011000101011110101010001001001000111010011100101100110110110010100000"; + let result = UPCAWriter::default() + .encode( + "12345678901", + &BarcodeFormat::UPC_A, + testStr.chars().count() as i32, + 0, + ) + .expect("ok"); + assert_eq!(testStr, BitMatrixTestCase::matrix_to_string(&result)); + } +} diff --git a/src/oned/upc_e_reader.rs b/src/oned/upc_e_reader.rs index e0e1ba6..f7e31b4 100644 --- a/src/oned/upc_e_reader.rs +++ b/src/oned/upc_e_reader.rs @@ -95,7 +95,7 @@ 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]; + pub 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. @@ -126,7 +126,7 @@ impl UPCEReader { * 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] = [ + pub 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], ]; @@ -157,7 +157,7 @@ impl UPCEReader { * @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]; + let upceChars = &upce[1..7]; //['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()); diff --git a/src/oned/upc_e_writer.rs b/src/oned/upc_e_writer.rs new file mode 100644 index 0000000..61950a0 --- /dev/null +++ b/src/oned/upc_e_writer.rs @@ -0,0 +1,177 @@ +/* + * Copyright 2009 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +use one_d_reader_derive::OneDWriter; + +use crate::BarcodeFormat; + +use super::{ + upc_e_reader, upc_ean_reader, OneDimensionalCodeWriter, UPCEANReader, UPCEANWriter, UPCEReader, +}; + +const CODE_WIDTH: usize = 3 + // start guard + (7 * 6) + // bars + 6; // end guard + +/** + * This object renders an UPC-E code as a {@link BitMatrix}. + * + * @author 0979097955s@gmail.com (RX) + */ +#[derive(OneDWriter)] +pub struct UPCEWriter; + +impl UPCEANWriter for UPCEWriter {} +impl Default for UPCEWriter { + fn default() -> Self { + Self {} + } +} +impl OneDimensionalCodeWriter for UPCEWriter { + fn encode_oned(&self, contents: &str) -> Result, Exceptions> { + let length = contents.chars().count(); + let mut contents = contents.to_owned(); + let reader = UPCEReader::default(); + match length { + 7 => { + // No check digit present, calculate it and add it + let check = reader + .getStandardUPCEANChecksum(&upc_e_reader::convertUPCEtoUPCA(&contents))?; + // try { + // check = UPCEANReader.getStandardUPCEANChecksum(UPCEReader.convertUPCEtoUPCA(contents)); + // } catch (FormatException fe) { + // throw new IllegalArgumentException(fe); + // } + contents.push_str(&check.to_string()); + } + 8 => + // try { + { + if !reader + .checkStandardUPCEANChecksum(&upc_e_reader::convertUPCEtoUPCA(&contents))? + { + return Err(Exceptions::IllegalArgumentException( + "Contents do not pass checksum".to_owned(), + )); + } + } + // } catch (FormatException ignored) { + // throw new IllegalArgumentException("Illegal contents"); + // }}, + _ => { + return Err(Exceptions::IllegalArgumentException(format!( + "Requested contents should be 7 or 8 digits long, but got {}", + length + ))) + } + } + + Self::checkNumeric(&contents)?; + + let firstDigit = contents.chars().nth(0).unwrap().to_digit(10).unwrap() as usize; //Character.digit(contents.charAt(0), 10); + if firstDigit != 0 && firstDigit != 1 { + return Err(Exceptions::IllegalArgumentException( + "Number system must be 0 or 1".to_owned(), + )); + } + + let checkDigit = contents.chars().nth(7).unwrap().to_digit(10).unwrap() as usize; //Character.digit(contents.charAt(7), 10); + let parities = UPCEReader::NUMSYS_AND_CHECK_DIGIT_PATTERNS[firstDigit][checkDigit]; + let mut result = [false; CODE_WIDTH]; + + let mut pos = + Self::appendPattern(&mut result, 0, &upc_ean_reader::START_END_PATTERN, true) as usize; + + for i in 1..=6 { + // for (int i = 1; i <= 6; i++) { + let mut digit = contents.chars().nth(i).unwrap().to_digit(10).unwrap() as usize; //Character.digit(contents.charAt(i), 10); + if (parities >> (6 - i) & 1) == 1 { + digit += 10; + } + pos += Self::appendPattern( + &mut result, + pos, + &upc_ean_reader::L_AND_G_PATTERNS[digit], + false, + ) as usize; + } + + Self::appendPattern(&mut result, pos, &upc_ean_reader::END_PATTERN, false) as usize; + + Ok(result.to_vec()) + } + + fn getSupportedWriteFormats(&self) -> Option> { + Some(vec![BarcodeFormat::UPC_E]) + } + fn getDefaultMargin(&self) -> u32 { + Self::DEFAULT_MARGIN + } +} + +/** + * Tests {@link UPCEWriter}. + */ +#[cfg(test)] +mod UPCEWriterTestCase { + use crate::{common::BitMatrixTestCase, BarcodeFormat, Writer}; + + use super::UPCEWriter; + + #[test] + fn testEncode() { + doTest( + "05096893", + "0000000000010101110010100111000101101011110110111001011101010100000000000", + ); + } + + #[test] + fn testEncodeSystem1() { + doTest( + "12345670", + "0000000000010100100110111101010001101110010000101001000101010100000000000", + ); + } + + #[test] + fn testAddChecksumAndEncode() { + doTest( + "0509689", + "0000000000010101110010100111000101101011110110111001011101010100000000000", + ); + } + + fn doTest(content: &str, encoding: &str) { + let result = UPCEWriter::default() + .encode( + content, + &BarcodeFormat::UPC_E, + encoding.chars().count() as i32, + 0, + ) + .expect("ok"); + assert_eq!(encoding, BitMatrixTestCase::matrix_to_string(&result)); + } + + #[test] + #[should_panic] + fn testEncodeIllegalCharacters() { + UPCEWriter::default() + .encode("05096abc", &BarcodeFormat::UPC_E, 0, 0) + .expect("ok"); + } +} diff --git a/src/oned/UPCEANWriter.java b/src/oned/upc_ean_writer.rs similarity index 78% rename from src/oned/UPCEANWriter.java rename to src/oned/upc_ean_writer.rs index 6e9907a..138f700 100644 --- a/src/oned/UPCEANWriter.java +++ b/src/oned/upc_ean_writer.rs @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.google.zxing.oned; +use super::OneDimensionalCodeWriter; /** *

Encapsulates functionality and implementation that is common to UPC and EAN families @@ -23,12 +23,6 @@ package com.google.zxing.oned; * @author aripollak@gmail.com (Ari Pollak) * @author dsbnatut@gmail.com (Kazuki Nishiura) */ -public abstract class UPCEANWriter extends OneDimensionalCodeWriter { - - @Override - public int getDefaultMargin() { - // Use a different default more appropriate for UPC/EAN - return 9; - } - +pub trait UPCEANWriter: OneDimensionalCodeWriter { + const DEFAULT_MARGIN: u32 = 9; }