diff --git a/src/common/decoder_rxing_result.rs b/src/common/decoder_rxing_result.rs index e5f197d..9a30124 100644 --- a/src/common/decoder_rxing_result.rs +++ b/src/common/decoder_rxing_result.rs @@ -35,7 +35,7 @@ pub struct DecoderRXingResult { ecLevel: String, errorsCorrected: usize, erasures: usize, - other: Rc, + other: Option>, structuredAppendParity: i32, structuredAppendSequenceNumber: i32, symbologyModifier: u32, @@ -106,7 +106,7 @@ impl DecoderRXingResult { ecLevel, errorsCorrected: 0, erasures: 0, - other: Rc::new(false), + other: None, structuredAppendParity: saParity, structuredAppendSequenceNumber: saSequence, symbologyModifier, @@ -182,11 +182,11 @@ impl DecoderRXingResult { /** * @return arbitrary additional metadata */ - pub fn getOther(&self) -> Rc { + pub fn getOther(&self) -> Option> { self.other.clone() } - pub fn setOther(&mut self, other: Rc) { + pub fn setOther(&mut self, other: Option>) { self.other = other } diff --git a/src/multi/qrcode/qr_code_multi_reader.rs b/src/multi/qrcode/qr_code_multi_reader.rs index 5a3d4ed..b01f31b 100644 --- a/src/multi/qrcode/qr_code_multi_reader.rs +++ b/src/multi/qrcode/qr_code_multi_reader.rs @@ -59,13 +59,13 @@ impl MultipleBarcodeReader for QRCodeMultiReader { )?; let mut points = detectorRXingResult.getPoints().clone(); // If the code was mirrored: swap the bottom-left and the top-right points. - let other = decoderRXingResult.getOther(); + if let Some( other) = decoderRXingResult.getOther(){ if other.is::() { (other .downcast::() .expect("must downcast to QRCodeDecoderMetaData")) .applyMirroredCorrection(&mut points); - } + }} // if (decoderRXingResult.getOther() instanceof QRCodeDecoderMetaData) { // ((QRCodeDecoderMetaData) decoderRXingResult.getOther()).applyMirroredCorrection(points); // } diff --git a/src/pdf417/decoder/PDF417DecoderTestCase.java b/src/pdf417/decoder/PDF417DecoderTestCase.java deleted file mode 100644 index 86672c7..0000000 --- a/src/pdf417/decoder/PDF417DecoderTestCase.java +++ /dev/null @@ -1,468 +0,0 @@ -/* - * Copyright 2009 ZXing authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.google.zxing.pdf417.decoder; - -import com.google.zxing.FormatException; -import com.google.zxing.WriterException; -import com.google.zxing.pdf417.PDF417RXingResultMetadata; -import com.google.zxing.common.DecoderRXingResult; -import com.google.zxing.pdf417.encoder.Compaction; -import com.google.zxing.pdf417.encoder.PDF417HighLevelEncoderTestAdapter; - -import org.junit.Assert; -import org.junit.Test; -import java.nio.charset.Charset; -import java.nio.charset.StandardCharsets; -import java.util.Random; - -/** - * Tests {@link DecodedBitStreamParser}. - */ -public class PDF417DecoderTestCase extends Assert { - - /** - * Tests the first sample given in ISO/IEC 15438:2015(E) - Annex H.4 - */ - @Test - public void testStandardSample1() throws FormatException { - PDF417RXingResultMetadata resultMetadata = new PDF417RXingResultMetadata(); - int[] sampleCodes = {20, 928, 111, 100, 17, 53, 923, 1, 111, 104, 923, 3, 64, 416, 34, 923, 4, 258, 446, 67, - // we should never reach these - 1000, 1000, 1000}; - - DecodedBitStreamParser.decodeMacroBlock(sampleCodes, 2, resultMetadata); - - assertEquals(0, resultMetadata.getSegmentIndex()); - assertEquals("017053", resultMetadata.getFileId()); - assertFalse(resultMetadata.isLastSegment()); - assertEquals(4, resultMetadata.getSegmentCount()); - assertEquals("CEN BE", resultMetadata.getSender()); - assertEquals("ISO CH", resultMetadata.getAddressee()); - - @SuppressWarnings("deprecation") - int[] optionalData = resultMetadata.getOptionalData(); - assertEquals("first element of optional array should be the first field identifier", 1, optionalData[0]); - assertEquals("last element of optional array should be the last codeword of the last field", - 67, optionalData[optionalData.length - 1]); - } - - - /** - * Tests the second given in ISO/IEC 15438:2015(E) - Annex H.4 - */ - @Test - public void testStandardSample2() throws FormatException { - PDF417RXingResultMetadata resultMetadata = new PDF417RXingResultMetadata(); - int[] sampleCodes = {11, 928, 111, 103, 17, 53, 923, 1, 111, 104, 922, - // we should never reach these - 1000, 1000, 1000}; - - DecodedBitStreamParser.decodeMacroBlock(sampleCodes, 2, resultMetadata); - - assertEquals(3, resultMetadata.getSegmentIndex()); - assertEquals("017053", resultMetadata.getFileId()); - assertTrue(resultMetadata.isLastSegment()); - assertEquals(4, resultMetadata.getSegmentCount()); - assertNull(resultMetadata.getAddressee()); - assertNull(resultMetadata.getSender()); - - @SuppressWarnings("deprecation") - int[] optionalData = resultMetadata.getOptionalData(); - assertEquals("first element of optional array should be the first field identifier", 1, optionalData[0]); - assertEquals("last element of optional array should be the last codeword of the last field", - 104, optionalData[optionalData.length - 1]); - } - - - /** - * Tests the example given in ISO/IEC 15438:2015(E) - Annex H.6 - */ - @Test - public void testStandardSample3() throws FormatException { - PDF417RXingResultMetadata resultMetadata = new PDF417RXingResultMetadata(); - int[] sampleCodes = {7, 928, 111, 100, 100, 200, 300, - 0}; // Final dummy ECC codeword required to avoid ArrayIndexOutOfBounds - - DecodedBitStreamParser.decodeMacroBlock(sampleCodes, 2, resultMetadata); - - assertEquals(0, resultMetadata.getSegmentIndex()); - assertEquals("100200300", resultMetadata.getFileId()); - assertFalse(resultMetadata.isLastSegment()); - assertEquals(-1, resultMetadata.getSegmentCount()); - assertNull(resultMetadata.getAddressee()); - assertNull(resultMetadata.getSender()); - assertNull(resultMetadata.getOptionalData()); - - // Check that symbol containing no data except Macro is accepted (see note in Annex H.2) - DecoderRXingResult decoderRXingResult = DecodedBitStreamParser.decode(sampleCodes, "0"); - assertEquals("", decoderRXingResult.getText()); - assertNotNull(decoderRXingResult.getOther()); - } - - @Test - public void testSampleWithFilename() throws FormatException { - int[] sampleCodes = {23, 477, 928, 111, 100, 0, 252, 21, 86, 923, 0, 815, 251, 133, 12, 148, 537, 593, - 599, 923, 1, 111, 102, 98, 311, 355, 522, 920, 779, 40, 628, 33, 749, 267, 506, 213, 928, 465, 248, - 493, 72, 780, 699, 780, 493, 755, 84, 198, 628, 368, 156, 198, 809, 19, 113}; - PDF417RXingResultMetadata resultMetadata = new PDF417RXingResultMetadata(); - - DecodedBitStreamParser.decodeMacroBlock(sampleCodes, 3, resultMetadata); - - assertEquals(0, resultMetadata.getSegmentIndex()); - assertEquals("000252021086", resultMetadata.getFileId()); - assertFalse(resultMetadata.isLastSegment()); - assertEquals(2, resultMetadata.getSegmentCount()); - assertNull(resultMetadata.getAddressee()); - assertNull(resultMetadata.getSender()); - assertEquals("filename.txt", resultMetadata.getFileName()); - } - - @Test - public void testSampleWithNumericValues() throws FormatException { - int[] sampleCodes = {25, 477, 928, 111, 100, 0, 252, 21, 86, 923, 2, 2, 0, 1, 0, 0, 0, 923, 5, 130, 923, - 6, 1, 500, 13, 0}; - PDF417RXingResultMetadata resultMetadata = new PDF417RXingResultMetadata(); - - DecodedBitStreamParser.decodeMacroBlock(sampleCodes, 3, resultMetadata); - - assertEquals(0, resultMetadata.getSegmentIndex()); - assertEquals("000252021086", resultMetadata.getFileId()); - assertFalse(resultMetadata.isLastSegment()); - - assertEquals(180980729000000L, resultMetadata.getTimestamp()); - assertEquals(30, resultMetadata.getFileSize()); - assertEquals(260013, resultMetadata.getChecksum()); - } - - @Test - public void testSampleWithMacroTerminatorOnly() throws FormatException { - int[] sampleCodes = {7, 477, 928, 222, 198, 0, 922}; - PDF417RXingResultMetadata resultMetadata = new PDF417RXingResultMetadata(); - - DecodedBitStreamParser.decodeMacroBlock(sampleCodes, 3, resultMetadata); - - assertEquals(99998, resultMetadata.getSegmentIndex()); - assertEquals("000", resultMetadata.getFileId()); - assertTrue(resultMetadata.isLastSegment()); - assertEquals(-1, resultMetadata.getSegmentCount()); - assertNull(resultMetadata.getOptionalData()); - } - - @Test(expected = FormatException.class) - public void testSampleWithBadSequenceIndexMacro() throws FormatException { - int[] sampleCodes = {3, 928, 222, 0}; - PDF417RXingResultMetadata resultMetadata = new PDF417RXingResultMetadata(); - DecodedBitStreamParser.decodeMacroBlock(sampleCodes, 2, resultMetadata); - } - - @Test(expected = FormatException.class) - public void testSampleWithNoFileIdMacro() throws FormatException { - int[] sampleCodes = {4, 928, 222, 198, 0}; - PDF417RXingResultMetadata resultMetadata = new PDF417RXingResultMetadata(); - DecodedBitStreamParser.decodeMacroBlock(sampleCodes, 2, resultMetadata); - } - - @Test(expected = FormatException.class) - public void testSampleWithNoDataNoMacro() throws FormatException { - int[] sampleCodes = {3, 899, 899, 0}; - DecodedBitStreamParser.decode(sampleCodes, "0"); - } - - @Test - public void testUppercase() throws WriterException, FormatException { - //encodeDecode("", 0); - performEncodeTest('A', new int[] { 3, 4, 5, 6, 4, 4, 5, 5}); - } - - @Test - public void testNumeric() throws WriterException, FormatException { - performEncodeTest('1', new int[] { 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 7, 7, 8, 8, 8, 9, 9, 9, 10, 10}); - } - - @Test - public void testByte() throws WriterException, FormatException { - performEncodeTest('\u00c4', new int[] { 3, 4, 5, 6, 7, 7, 8}); - } - - @Test - public void testUppercaseLowercaseMix1() throws WriterException, FormatException { - encodeDecode("aA", 4); - encodeDecode("aAa", 5); - encodeDecode("Aa", 4); - encodeDecode("Aaa", 5); - encodeDecode("AaA", 5); - encodeDecode("AaaA", 6); - encodeDecode("Aaaa", 6); - encodeDecode("AaAaA", 5); - encodeDecode("AaaAaaA", 6); - encodeDecode("AaaAAaaA", 7); - } - - @Test - public void testPunctuation() throws WriterException, FormatException { - performEncodeTest(';', new int[] { 3, 4, 5, 6, 6, 7, 8}); - encodeDecode(";;;;;;;;;;;;;;;;", 17); - } - - @Test - public void testUppercaseLowercaseMix2() throws WriterException, FormatException { - performPermutationTest(new char[] {'A', 'a'}, 10, 8972); - } - - @Test - public void testUppercaseNumericMix() throws WriterException, FormatException { - performPermutationTest(new char[] {'A', '1'}, 14, 192510); - } - - @Test - public void testUppercaseMixedMix() throws WriterException, FormatException { - performPermutationTest(new char[] {'A', '1', ' ', ';'}, 7, 106060); - } - - @Test - public void testUppercasePunctuationMix() throws WriterException, FormatException { - performPermutationTest(new char[] {'A', ';'}, 10, 8967); - } - - @Test - public void testUppercaseByteMix() throws WriterException, FormatException { - performPermutationTest(new char[] {'A', '\u00c4'}, 10, 11222); - } - - @Test - public void testLowercaseByteMix() throws WriterException, FormatException { - performPermutationTest(new char[] {'a', '\u00c4'}, 10, 11233); - } - - public void testUppercaseLowercaseNumericMix() throws WriterException, FormatException { - performPermutationTest(new char[] {'A', 'a', '1'}, 7, 15491); - } - - @Test - public void testUppercaseLowercasePunctuationMix() throws WriterException, FormatException { - performPermutationTest(new char[] {'A', 'a', ';'}, 7, 15491); - } - - @Test - public void testUppercaseLowercaseByteMix() throws WriterException, FormatException { - performPermutationTest(new char[] {'A', 'a', '\u00c4'}, 7, 17288); - } - - @Test - public void testLowercasePunctuationByteMix() throws WriterException, FormatException { - performPermutationTest(new char[] {'a', ';', '\u00c4'}, 7, 17427); - } - - @Test - public void testUppercaseLowercaseNumericPunctuationMix() throws WriterException, FormatException { - performPermutationTest(new char[] {'A', 'a', '1', ';'}, 7, 120479); - } - - @Test - public void testBinaryData() throws WriterException, FormatException { - byte[] bytes = new byte[500]; - Random random = new Random(0); - int total = 0; - for (int i = 0; i < 10000; i++) { - random.nextBytes(bytes); - total += encodeDecode(new String(bytes, StandardCharsets.ISO_8859_1)); - } - assertEquals(4190044, total); - } - - @Test - public void testECIEnglishHiragana() throws Exception { - //multi ECI UTF-8, UTF-16 and ISO-8859-1 - performECITest(new char[] {'a', '1', '\u3040'}, new float[] {20f, 1f, 10f}, 105825, 110914); - } - - @Test - public void testECIEnglishKatakana() throws Exception { - //multi ECI UTF-8, UTF-16 and ISO-8859-1 - performECITest(new char[] {'a', '1', '\u30a0'}, new float[] {20f, 1f, 10f}, 109177, 110914); - } - - @Test - public void testECIEnglishHalfWidthKatakana() throws Exception { - //single ECI - performECITest(new char[] {'a', '1', '\uff80'}, new float[] {20f, 1f, 10f}, 80617, 110914); - } - - @Test - public void testECIEnglishChinese() throws Exception { - //single ECI - performECITest(new char[] {'a', '1', '\u4e00'}, new float[] {20f, 1f, 10f}, 95797, 110914); - } - - @Test - public void testECIGermanCyrillic() throws Exception { - //single ECI since the German Umlaut is in ISO-8859-1 - performECITest(new char[] {'a', '1', '\u00c4', '\u042f'}, new float[] {20f, 1f, 1f, 10f}, 80755, 96007); - } - - @Test - public void testECIEnglishCzechCyrillic1() throws Exception { - //multi ECI between ISO-8859-2 and ISO-8859-5 - performECITest(new char[] {'a', '1', '\u010c', '\u042f'}, new float[] {10f, 1f, 10f, 10f}, 102824, 124525); - } - - @Test - public void testECIEnglishCzechCyrillic2() throws Exception { - //multi ECI between ISO-8859-2 and ISO-8859-5 - performECITest(new char[] {'a', '1', '\u010c', '\u042f'}, new float[] {40f, 1f, 10f, 10f}, 81321, 88236); - } - - @Test - public void testECIEnglishArabicCyrillic() throws Exception { - //multi ECI between UTF-8 (ISO-8859-6 is excluded in CharacterSetECI) and ISO-8859-5 - performECITest(new char[] {'a', '1', '\u0620', '\u042f'}, new float[] {10f, 1f, 10f, 10f}, 118510, 124525); - } - - @Test - public void testBinaryMultiECI() throws Exception { - //Test the cases described in 5.5.5.3 "ECI and Byte Compaction mode using latch 924 and 901" - performDecodeTest(new int[] {5, 927, 4, 913, 200}, "\u010c"); - performDecodeTest(new int[] {9, 927, 4, 913, 200, 927, 7, 913, 207}, "\u010c\u042f"); - performDecodeTest(new int[] {9, 927, 4, 901, 200, 927, 7, 901, 207}, "\u010c\u042f"); - performDecodeTest(new int[] {8, 927, 4, 901, 200, 927, 7, 207}, "\u010c\u042f"); - performDecodeTest(new int[] {14, 927, 4, 901, 200, 927, 7, 207, 927, 4, 200, 927, 7, 207}, - "\u010c\u042f\u010c\u042f"); - performDecodeTest(new int[] {16, 927, 4, 924, 336, 432, 197, 51, 300, 927, 7, 348, 231, 311, 858, 567}, - "\u010c\u010c\u010c\u010c\u010c\u010c\u042f\u042f\u042f\u042f\u042f\u042f"); - } - - private static void encodeDecode(String input, int expectedLength) throws WriterException, FormatException { - assertEquals(expectedLength, encodeDecode(input)); - } - - private static int encodeDecode(String input) throws WriterException, FormatException { - return encodeDecode(input, null, false, true); - } - - private static int encodeDecode(String input, Charset charset, boolean autoECI, boolean decode) - throws WriterException, FormatException { - String s = PDF417HighLevelEncoderTestAdapter.encodeHighLevel(input, Compaction.AUTO, charset, autoECI); - if (decode) { - int[] codewords = new int[s.length() + 1]; - codewords[0] = codewords.length; - for (int i = 1; i < codewords.length; i++) { - codewords[i] = s.charAt(i - 1); - } - performDecodeTest(codewords, input); - } - return s.length() + 1; - } - - private static int getEndIndex(int length, char[] chars) { - double decimalLength = Math.log10(chars.length); - return (int) Math.ceil(Math.pow(10, decimalLength * length)); - } - - private static String generatePermutation(int index, int length, char[] chars) { - int N = chars.length; - String baseNNumber = Integer.toString(index, N); - while (baseNNumber.length() < length) { - baseNNumber = "0" + baseNNumber; - } - String prefix = ""; - for (int i = 0; i < baseNNumber.length(); i++) { - prefix += chars[baseNNumber.charAt(i) - '0']; - } - return prefix; - } - - private static void performPermutationTest(char[] chars, int length, int expectedTotal) throws WriterException, - FormatException { - int endIndex = getEndIndex(length, chars); - int total = 0; - for (int i = 0; i < endIndex; i++) { - total += encodeDecode(generatePermutation(i, length, chars)); - } - assertEquals(expectedTotal, total); - } - - private static void performEncodeTest(char c, int[] expectedLengths) throws WriterException, FormatException { - for (int i = 0; i < expectedLengths.length; i++) { - StringBuilder sb = new StringBuilder(); - for (int j = 0; j <= i; j++) { - sb.append(c); - } - encodeDecode(sb.toString(), expectedLengths[i]); - } - } - - private static void performDecodeTest(int[] codewords, String expectedRXingResult) throws FormatException { - DecoderRXingResult result = DecodedBitStreamParser.decode(codewords, "0"); - assertEquals(expectedRXingResult, result.getText()); - } - - private static void performECITest(char[] chars, - float[] weights, - int expectedMinLength, - int expectedUTFLength) throws WriterException, FormatException { - Random random = new Random(0); - int minLength = 0; - int utfLength = 0; - for (int i = 0; i < 1000; i++) { - String s = generateText(random, 100, chars, weights); - minLength += encodeDecode(s, null, true, true); - utfLength += encodeDecode(s, StandardCharsets.UTF_8, false, true); - } - assertEquals(expectedMinLength, minLength); - assertEquals(expectedUTFLength, utfLength); - } - - private static String generateText(Random random, int maxWidth, char[] chars, float[] weights) { - StringBuilder result = new StringBuilder(); - final int maxWordWidth = 7; - float total = 0; - for (int i = 0; i < weights.length; i++) { - total += weights[i]; - } - for (int i = 0; i < weights.length; i++) { - weights[i] /= total; - } - int cnt = 0; - do { - float maxValue = 0; - int maxIndex = 0; - for (int j = 0; j < weights.length; j++) { - float value = random.nextFloat() * weights[j]; - if (value > maxValue) { - maxValue = value; - maxIndex = j; - } - } - final float wordLength = maxWordWidth * random.nextFloat(); - if (wordLength > 0 && result.length() > 0) { - result.append(' '); - } - for (int j = 0; j < wordLength; j++) { - char c = chars[maxIndex]; - if (j == 0 && c >= 'a' && c <= 'z' && random.nextBoolean()) { - c = (char) (c - 'a' + 'A'); - } - result.append(c); - } - if (cnt % 2 != 0 && random.nextBoolean()) { - result.append('.'); - } - cnt++; - } while (result.length() < maxWidth - maxWordWidth); - return result.toString(); - } -} diff --git a/src/pdf417/decoder/decoded_bit_stream_parser.rs b/src/pdf417/decoder/decoded_bit_stream_parser.rs index 2b43c1a..319aa31 100644 --- a/src/pdf417/decoder/decoded_bit_stream_parser.rs +++ b/src/pdf417/decoder/decoded_bit_stream_parser.rs @@ -189,7 +189,7 @@ pub fn decode(codewords: &[u32], ecLevel: &str) -> Result [u8;500] { + let mut bytes = [0_u8;500]; + let mut random = rand::thread_rng(); + for i in 0..500 { + bytes[i] = random.gen(); + } + bytes + } + + #[test] + fn testECIEnglishHiragana(){ + //multi ECI UTF-8, UTF-16 and ISO-8859-1 + performECITest(&['a', '1', '\u{3040}'], &mut [20.0, 1.0, 10.0], 105825, 110914); + } + + #[test] + fn testECIEnglishKatakana() { + //multi ECI UTF-8, UTF-16 and ISO-8859-1 + performECITest(&['a', '1', '\u{30a0}'], &mut [20.0, 1.0, 10.0], 109177, 110914); + } + + #[test] + fn testECIEnglishHalfWidthKatakana(){ + //single ECI + performECITest(&['a', '1', '\u{ff80}'], &mut [20.0, 1.0, 10.0], 80617, 110914); + } + + #[test] + fn testECIEnglishChinese() { + //single ECI + performECITest(&['a', '1', '\u{4e00}'], &mut [20.0, 1.0, 10.0], 95797, 110914); + } + + #[test] + fn testECIGermanCyrillic(){ + //single ECI since the German Umlaut is in ISO-8859-1 + performECITest(&['a', '1', '\u{00c4}', '\u{042f}'], &mut [20.0, 1.0, 1.0, 10.0], 80755, 96007); + } + + #[test] + fn testECIEnglishCzechCyrillic1() { + //multi ECI between ISO-8859-2 and ISO-8859-5 + performECITest(&['a', '1', '\u{010c}', '\u{042f}'], &mut [10.0, 1.0, 10.0, 10.0], 102824, 124525); + } + + #[test] + fn testECIEnglishCzechCyrillic2() { + //multi ECI between ISO-8859-2 and ISO-8859-5 + performECITest(&['a', '1', '\u{010c}', '\u{042f}'], &mut [40.0, 1.0, 10.0, 10.0], 81321, 88236); + } + + #[test] + fn testECIEnglishArabicCyrillic() { + //multi ECI between UTF-8 (ISO-8859-6 is excluded in CharacterSetECI) and ISO-8859-5 + performECITest(&['a', '1', '\u{0620}', '\u{042f}'], &mut [10.0, 1.0, 10.0, 10.0], 118510, 124525); + } + + #[test] + fn testBinaryMultiECI() { + //Test the cases described in 5.5.5.3 "ECI and Byte Compaction mode using latch 924 and 901" + performDecodeTest(&[5, 927, 4, 913, 200], "\u{010c}"); + performDecodeTest(&[9, 927, 4, 913, 200, 927, 7, 913, 207], "\u{010c}\u{042f}"); + performDecodeTest(&[9, 927, 4, 901, 200, 927, 7, 901, 207], "\u{010c}\u{042f}"); + performDecodeTest(&[8, 927, 4, 901, 200, 927, 7, 207], "\u{010c}\u{042f}"); + performDecodeTest(&[14, 927, 4, 901, 200, 927, 7, 207, 927, 4, 200, 927, 7, 207], + "\u{010c}\u{042f}\u{010c}\u{042f}"); + performDecodeTest(&[16, 927, 4, 924, 336, 432, 197, 51, 300, 927, 7, 348, 231, 311, 858, 567], + "\u{010c}\u{010c}\u{010c}\u{010c}\u{010c}\u{010c}\u{042f}\u{042f}\u{042f}\u{042f}\u{042f}\u{042f}"); + } + + fn encodeDecodeWithLength( input:&str, expectedLength:u32) { + assert_eq!(expectedLength, encodeDecode(input)); + } + + fn encodeDecode( input:&str) -> u32 { + return encodeDecodeWithAll(input, None, false, true); + } + + fn encodeDecodeWithAll( input:&str, charset:Option, autoECI:bool, decode:bool) + -> u32 { + let s = pdf_417_high_level_encoder_test_adapter::encodeHighLevel(input, Compaction::AUTO, charset, autoECI).expect("encode"); + if decode { + let mut codewords = vec![0_u32;s.chars().count() + 1]; + codewords[0] = codewords.len() as u32; + for i in 1..codewords.len() { + // for (int i = 1; i < codewords.length; i++) { + codewords[i] = s.chars().nth(i - 1).unwrap() as u32; + } + performDecodeTest(&codewords, input); + } + s.chars().count() as u32 + 1 + } + + fn getEndIndex( length:u32, chars:&[char]) -> u32{ + let decimalLength : f64 = (chars.len() as f64).log10(); //Math.log10(chars.length); + (decimalLength*length as f64).powi(10).ceil() as u32 + // Math.ceil(Math.pow(10, decimalLength * length)) + } + + fn generatePermutation( index:u32, length:u32, chars:&[char]) -> String{ + let N = chars.len() as u32; + // let baseNNumber = Integer.toString(index, N); + let mut baseNNumber= int_to_string(index,N); + while baseNNumber.chars().count() < length as usize { + baseNNumber.insert(0, '0'); + // baseNNumber = "0" + baseNNumber; + } + let mut prefix = String::from(""); + for ch in baseNNumber.chars() { + prefix.push(chars[ch as usize - '0' as usize]); + } + // for i in 0..baseNNumber.chars().count() { + // // for (int i = 0; i < baseNNumber.length(); i++) { + // prefix += chars[baseNNumber.charAt(i) - '0']; + // } + + + prefix + } + + fn performPermutationTest( chars:&[char], length:u32, expectedTotal:u32) { + let endIndex = getEndIndex(length, chars); + let mut total = 0; + for i in 0..endIndex { + // for (int i = 0; i < endIndex; i++) { + total += encodeDecode(&generatePermutation(i, length, chars)); + } + assert_eq!(expectedTotal, total); + } + + fn performEncodeTest( c:char, expectedLengths:&[u32]) { + for i in 0..expectedLengths.len() { + // for (int i = 0; i < expectedLengths.length; i++) { + let mut sb = String::new();//new StringBuilder(); + for j in 0..=i { + // for (int j = 0; j <= i; j++) { + sb.push(c); + } + encodeDecodeWithLength(&sb, expectedLengths[i]); + } + } + + fn performDecodeTest(codewords:&[u32], expectedRXingResult:&str) { + let result = decoded_bit_stream_parser::decode(codewords, "0").expect("decode"); + assert_eq!(expectedRXingResult, result.getText()); + } + + fn performECITest( chars:&[char], + weights:&mut [f32], + expectedMinLength:u32, + expectedUTFLength:u32) { + let mut random = rand::thread_rng(); + let mut minLength = 0; + let mut utfLength = 0; + for i in 0..1000 { + // for (int i = 0; i < 1000; i++) { + let s = generateText(&mut random, 100, chars, weights); + minLength += encodeDecodeWithAll(&s, None, true, true); + utfLength += encodeDecodeWithAll(&s, Some(encoding::all::UTF_8), false, true); + } + assert_eq!(expectedMinLength, minLength); + assert_eq!(expectedUTFLength, utfLength); + } + + fn generateText( random:&mut ThreadRng, maxWidth:u32, chars:&[char], weights:&mut [f32]) -> String{ + let mut result = String::new();//new StringBuilder(); + let maxWordWidth = 7; + let mut total = 0.0; + // for (int i = 0; i < weights.length; i++) { + // total += weights[i]; + // } + total += weights.iter().sum::(); + + for i in 0..weights.len() { + // for (int i = 0; i < weights.length; i++) { + weights[i] /= total; + } + let mut cnt = 0; + loop { + let mut maxValue = 0.0; + let mut maxIndex = 0; + for j in 0..weights.len() { + // for (int j = 0; j < weights.length; j++) { + let value = random.gen::() * weights[j]; + if value > maxValue { + maxValue = value; + maxIndex = j; + } + } + let wordLength = (maxWordWidth as f32 * random.gen::()) as i32; + if wordLength > 0 && result.chars().count() > 0 { + result.push(' '); + } + for j in 0..wordLength { + // for (int j = 0; j < wordLength; j++) { + let mut c = chars[maxIndex]; + if j == 0 && c >= 'a' && c <= 'z' && random.gen::() { + c = char::from_u32(c as u32- 'a' as u32 + 'A' as u32).unwrap(); + } + result.push(c); + } + if cnt % 2 != 0 && random.gen_bool(0.51) { + result.push('.'); + } + cnt+=1; + + if !(result.chars().count() < (maxWidth as isize - maxWordWidth as isize) as usize) { break } + } //while (result.length() < maxWidth - maxWordWidth); + + result + } + + + fn int_to_string(x: u32, radix: u32) -> String { + let mut x = x; + // Handle the special case of 0 + if x == 0 { + return "0".to_string(); + } + + // Build the string by repeatedly dividing the number by the radix and + // adding the remainder to the beginning of the string + let mut s = String::new(); + while x > 0 { + let remainder = (x % radix) as u8; + s = (remainder as char).to_string() + &s; + x /= radix; + } + + s +} + diff --git a/src/qrcode/decoder/decoder.rs b/src/qrcode/decoder/decoder.rs index 2e4691f..fbff7f2 100644 --- a/src/qrcode/decoder/decoder.rs +++ b/src/qrcode/decoder/decoder.rs @@ -115,7 +115,7 @@ pub fn decode_bitmatrix_with_hints( let mut result = decode_bitmatrix_parser_with_hints(&mut parser, hints)?; // Success! Notify the caller that the code was mirrored. - result.setOther(Rc::new(QRCodeDecoderMetaData::new(true))); + result.setOther(Some(Rc::new(QRCodeDecoderMetaData::new(true)))); Ok(result) }; diff --git a/src/qrcode/qr_code_reader.rs b/src/qrcode/qr_code_reader.rs index ea69252..7992aee 100644 --- a/src/qrcode/qr_code_reader.rs +++ b/src/qrcode/qr_code_reader.rs @@ -74,15 +74,15 @@ impl Reader for QRCodeReader { } // If the code was mirrored: swap the bottom-left and the top-right points. - if decoderRXingResult.getOther().is::() { + if let Some(other) = decoderRXingResult.getOther() { + if other.is::() { // if (decoderRXingResult.getOther() instanceof QRCodeDecoderMetaData) { - decoderRXingResult - .getOther() + other .downcast_ref::() .unwrap() .applyMirroredCorrection(&mut points); // ((QRCodeDecoderMetaData) decoderRXingResult.getOther()).applyMirroredCorrection(points); - } + }} let mut result = RXingResult::new( decoderRXingResult.getText(),