From fb60cfc5a3b63d703386a3dec6ae9df89c85ef38 Mon Sep 17 00:00:00 2001 From: Henry Schimke Date: Wed, 1 Feb 2023 12:23:00 -0600 Subject: [PATCH] fix issue with metadata testing --- src/common/decoder_rxing_result.rs | 38 ++++++++++++- src/common/eci_string_builder.rs | 10 ++-- src/datamatrix/data_matrix_reader.rs | 25 +++++++++ src/datamatrix/decoder/datamatrix_decoder.rs | 11 ++-- .../decoder/decoded_bit_stream_parser.rs | 55 ++++++++++++++----- src/maxicode/detector.rs | 2 +- .../decoder/decoded_bit_stream_parser.rs | 2 + src/rxing_result_metadata.rs | 42 ++++++++++---- .../datamatrix-1/0123456789.result.txt | 2 - ...t.txt => abcd-36x12-mirrored.metadata.txt} | 0 tests/common/abstract_black_box_test_case.rs | 16 ++++-- tests/common/pdf_417_multiimage_span.rs | 11 +++- 12 files changed, 169 insertions(+), 45 deletions(-) delete mode 100644 test_resources/blackbox/datamatrix-1/0123456789.result.txt rename test_resources/blackbox/datamatrix-1/{abcd-36x12-mirrored.result.txt => abcd-36x12-mirrored.metadata.txt} (100%) diff --git a/src/common/decoder_rxing_result.rs b/src/common/decoder_rxing_result.rs index 9a30124..503eed1 100644 --- a/src/common/decoder_rxing_result.rs +++ b/src/common/decoder_rxing_result.rs @@ -39,6 +39,8 @@ pub struct DecoderRXingResult { structuredAppendParity: i32, structuredAppendSequenceNumber: i32, symbologyModifier: u32, + contentType: String, + isMirrored: bool, } impl DecoderRXingResult { @@ -48,7 +50,17 @@ impl DecoderRXingResult { byteSegments: Vec>, ecLevel: String, ) -> Self { - Self::with_all(rawBytes, text, byteSegments, ecLevel, -2, -2, 0) + Self::with_all( + rawBytes, + text, + byteSegments, + ecLevel, + -2, + -2, + 0, + String::default(), + false, + ) } pub fn with_symbology( @@ -66,6 +78,8 @@ impl DecoderRXingResult { -1, -1, symbologyModifier, + String::default(), + false, ) } @@ -85,6 +99,8 @@ impl DecoderRXingResult { saSequence, saParity, 0, + String::default(), + false, ) } @@ -96,6 +112,8 @@ impl DecoderRXingResult { saSequence: i32, saParity: i32, symbologyModifier: u32, + contentType: String, + isMirrored: bool, ) -> Self { let nb = rawBytes.len(); Self { @@ -110,6 +128,8 @@ impl DecoderRXingResult { structuredAppendParity: saParity, structuredAppendSequenceNumber: saSequence, symbologyModifier, + contentType, + isMirrored, } } @@ -205,4 +225,20 @@ impl DecoderRXingResult { pub fn getSymbologyModifier(&self) -> u32 { self.symbologyModifier } + + pub fn getContentType(&self) -> &str { + &self.contentType + } + + pub fn setContentType(&mut self, content_type: String) { + self.contentType = content_type + } + + pub fn getIsMirrored(&self) -> bool { + self.isMirrored + } + + pub fn setIsMirrored(&mut self, is_mirrored: bool) { + self.isMirrored = is_mirrored + } } diff --git a/src/common/eci_string_builder.rs b/src/common/eci_string_builder.rs index 0d44278..050af39 100644 --- a/src/common/eci_string_builder.rs +++ b/src/common/eci_string_builder.rs @@ -107,11 +107,11 @@ impl ECIStringBuilder { self.encodeCurrentBytesIfAny(); if let Ok(character_set_eci) = CharacterSetECI::getCharacterSetECIByValue(value) { - dbg!( - character_set_eci, - CharacterSetECI::getCharset(&character_set_eci).name(), - CharacterSetECI::getCharset(&character_set_eci).whatwg_name() - ); + // dbg!( + // character_set_eci, + // CharacterSetECI::getCharset(&character_set_eci).name(), + // CharacterSetECI::getCharset(&character_set_eci).whatwg_name() + // ); self.current_charset = Some(CharacterSetECI::getCharset(&character_set_eci)); } else { self.current_charset = None diff --git a/src/datamatrix/data_matrix_reader.rs b/src/datamatrix/data_matrix_reader.rs index 48a66d0..5e24893 100644 --- a/src/datamatrix/data_matrix_reader.rs +++ b/src/datamatrix/data_matrix_reader.rs @@ -131,6 +131,31 @@ impl Reader for DataMatrixReader { RXingResultMetadataValue::ErrorCorrectionLevel(ecLevel.to_string()), ); } + let other_meta = decoderRXingResult.getOther(); + if let Some(other) = other_meta { + if let Some(dcr) = other.downcast_ref::() { + result.putMetadata( + RXingResultMetadataType::OTHER, + RXingResultMetadataValue::OTHER(dcr.to_owned()), + ); + } + } + let contentType = decoderRXingResult.getContentType(); + if !contentType.is_empty() { + result.putMetadata( + RXingResultMetadataType::CONTENT_TYPE, + RXingResultMetadataValue::ContentType(contentType.to_owned()), + ); + } + + let mirrored = decoderRXingResult.getIsMirrored(); + if mirrored { + result.putMetadata( + RXingResultMetadataType::IS_MIRRORED, + RXingResultMetadataValue::IsMirrored(mirrored), + ); + } + result.putMetadata( RXingResultMetadataType::SYMBOLOGY_IDENTIFIER, RXingResultMetadataValue::SymbologyIdentifier(format!( diff --git a/src/datamatrix/decoder/datamatrix_decoder.rs b/src/datamatrix/decoder/datamatrix_decoder.rs index b8eb97a..b1f4eef 100644 --- a/src/datamatrix/decoder/datamatrix_decoder.rs +++ b/src/datamatrix/decoder/datamatrix_decoder.rs @@ -50,12 +50,12 @@ impl Decoder { * @throws ChecksumException if error correction fails */ pub fn decode(&self, bits: &BitMatrix) -> Result { - let decoded = self.perform_decode(bits, false); + let decoded = self.perform_decode(bits, false, false); if decoded.is_ok() { return decoded; } - self.perform_decode(&Self::flip_bitmatrix(bits)?, false) + self.perform_decode(&Self::flip_bitmatrix(bits)?, false, true) } fn flip_bitmatrix(bits: &BitMatrix) -> Result { @@ -85,7 +85,7 @@ impl Decoder { * @throws ChecksumException if error correction fails */ pub fn decode_bools(&self, image: &Vec>) -> Result { - self.perform_decode(&BitMatrix::parse_bools(image), false) + self.perform_decode(&BitMatrix::parse_bools(image), false, false) } /** @@ -101,6 +101,7 @@ impl Decoder { &self, bits: &BitMatrix, fix259: bool, + is_flipped: bool, ) -> Result { // Construct a parser and read version, error-correction level let mut parser = BitMatrixParser::new(bits)?; @@ -129,7 +130,7 @@ impl Decoder { let numDataCodewords = dataBlock.getNumDataCodewords() as usize; let errors_corrected = self.correctErrors(&mut codewordBytes, numDataCodewords as u32); if errors_corrected.is_err() && !fix259 { - return self.perform_decode(bits, true); + return self.perform_decode(bits, true, is_flipped); } else if errors_corrected.is_err() { return Err(errors_corrected.err().unwrap()); } @@ -141,7 +142,7 @@ impl Decoder { } // Decode the contents of that stream of bytes - decoded_bit_stream_parser::decode(&resultBytes) + decoded_bit_stream_parser::decode(&resultBytes, is_flipped) } /** diff --git a/src/datamatrix/decoder/decoded_bit_stream_parser.rs b/src/datamatrix/decoder/decoded_bit_stream_parser.rs index 08aed33..a169fa4 100644 --- a/src/datamatrix/decoder/decoded_bit_stream_parser.rs +++ b/src/datamatrix/decoder/decoded_bit_stream_parser.rs @@ -110,7 +110,7 @@ const INSERT_STRING_CONST: &str = "\u{001E}\u{0004}"; const VALUE_236: &str = "[)>\u{001E}05\u{001D}"; const VALUE_237: &str = "[)>\u{001E}06\u{001D}"; -pub fn decode(bytes: &[u8]) -> Result { +pub fn decode(bytes: &[u8], is_flipped: bool) -> Result { let mut bits = BitSource::new(bytes.to_vec()); let mut result = ECIStringBuilder::with_capacity(100); let mut resultTrailer = String::new(); @@ -120,6 +120,8 @@ pub fn decode(bytes: &[u8]) -> Result { let mut fnc1Positions = Vec::new(); let symbologyModifier; let mut isECIencoded = false; + let mut known_eci = true; + let mut is_gs1 = false; loop { match mode { Mode::ASCII_ENCODE => { @@ -128,6 +130,7 @@ pub fn decode(bytes: &[u8]) -> Result { &mut result, &mut resultTrailer, &mut fnc1Positions, + &mut is_gs1, )? } Mode::C40_ENCODE => { @@ -151,7 +154,7 @@ pub fn decode(bytes: &[u8]) -> Result { mode = Mode::ASCII_ENCODE; } Mode::ECI_ENCODE => { - decodeECISegment(&mut bits, &mut result)?; + known_eci &= decodeECISegment(&mut bits, &mut result)?; isECIencoded = true; // ECI detection only, atm continue decoding as ASCII mode = Mode::ASCII_ENCODE; } @@ -165,7 +168,7 @@ pub fn decode(bytes: &[u8]) -> Result { if !resultTrailer.is_empty() { result.appendCharacters(&resultTrailer); } - if isECIencoded { + if isECIencoded && known_eci { // Examples for this numbers can be found in this documentation of a hardware barcode scanner: // https://honeywellaidc.force.com/supportppr/s/article/List-of-barcode-symbology-AIM-Identifiers if fnc1Positions.contains(&0) || fnc1Positions.contains(&4) { @@ -183,13 +186,26 @@ pub fn decode(bytes: &[u8]) -> Result { symbologyModifier = 1; } - Ok(DecoderRXingResult::with_symbology( + let mut result = DecoderRXingResult::with_symbology( bytes.to_vec(), result.build_result().to_string(), byteSegments, String::new(), symbologyModifier, - )) + ); + if is_gs1 { + result.setContentType(String::from("GS1")); + } + + if !known_eci { + result.setContentType(String::from("UnknownECI")); + } + + if is_flipped { + result.setIsMirrored(is_flipped); + } + + Ok(result) // return new DecoderRXingResult(bytes, // result.toString(), @@ -206,6 +222,7 @@ fn decodeAsciiSegment( result: &mut ECIStringBuilder, resultTrailer: &mut String, fnc1positions: &mut Vec, + is_gs1: &mut bool, ) -> Result { let mut upperShift = false; let mut firstFNC1Position = 1; @@ -247,16 +264,20 @@ fn decodeAsciiSegment( } 232 => { // FNC1 - if bits.getByteOffset() == firstFNC1Position { /*result.symbology.modifier = '2';*/ + if bits.getByteOffset() == firstFNC1Position { + /*result.symbology.modifier = '2';*/ + *is_gs1 = true; } // GS1 - else if bits.getByteOffset() == firstFNC1Position + 1 { /*result.symbology.modifier = '3';*/ + else if bits.getByteOffset() == firstFNC1Position + 1 { + /*result.symbology.modifier = '3';*/ } // AIM, note no AIM Application Indicator format defined, ISO 16022:2006 11.2 else { - fnc1positions.push(result.len()); result.append_char(29 as char); } // translate as ASCII 29 + + fnc1positions.push(result.len()); } 233 => // Structured Append @@ -727,20 +748,26 @@ fn decodeBase256Segment( /** * See ISO 16022:2007, 5.4.1 */ -fn decodeECISegment(bits: &mut BitSource, result: &mut ECIStringBuilder) -> Result<(), Exceptions> { +fn decodeECISegment( + bits: &mut BitSource, + result: &mut ECIStringBuilder, +) -> Result { let firstByte = bits.readBits(8)?; if firstByte <= 127 { - return result.appendECI(firstByte - 1); + result.appendECI(firstByte - 1)?; + return Ok(true); } let secondByte = bits.readBits(8)?; if firstByte <= 191 { - return result.appendECI((firstByte - 128) * 254 + 127 + secondByte - 1); + result.appendECI((firstByte - 128) * 254 + 127 + secondByte - 1)?; + return Ok((firstByte - 128) * 254 + 127 + secondByte - 1 > 900); } let thirdByte = bits.readBits(8)?; - result.appendECI((firstByte - 192) * 64516 + 16383 + (secondByte - 1) * 254 + thirdByte - 1) + result.appendECI((firstByte - 192) * 64516 + 16383 + (secondByte - 1) * 254 + thirdByte - 1)?; + return Ok((firstByte - 192) * 64516 + 16383 + (secondByte - 1) * 254 + thirdByte - 1 > 900); // if bits.available() < 8 { // return Err(Exceptions::FormatException(None)); @@ -839,7 +866,7 @@ mod tests { (b'C' + 1), ]; let decodedString = String::from( - decoded_bit_stream_parser::decode(&bytes) + decoded_bit_stream_parser::decode(&bytes, false) .expect("decode") .getText(), ); @@ -851,7 +878,7 @@ mod tests { // ASCII double digit (00 - 99) Numeric Value + 130 let bytes = [130, (1 + 130), (98 + 130), (99 + 130)]; let decodedString = String::from( - decoded_bit_stream_parser::decode(&bytes) + decoded_bit_stream_parser::decode(&bytes, false) .expect("decode") .getText(), ); diff --git a/src/maxicode/detector.rs b/src/maxicode/detector.rs index 720edf7..2dfc56d 100644 --- a/src/maxicode/detector.rs +++ b/src/maxicode/detector.rs @@ -432,7 +432,7 @@ fn find_concentric_circles(image: &BitMatrix) -> Option> { // false alarm, go on with the row let new_column = center - radius + (radius / 4); if new_column == current_column { - // this is necessary because sometimes the loop can get + // this is necessary because sometimes the loop can get // stuck when the result always comes out the same. row += ROW_SCAN_SKIP; break; diff --git a/src/qrcode/decoder/decoded_bit_stream_parser.rs b/src/qrcode/decoder/decoded_bit_stream_parser.rs index 905d2a0..fdba93a 100644 --- a/src/qrcode/decoder/decoded_bit_stream_parser.rs +++ b/src/qrcode/decoder/decoded_bit_stream_parser.rs @@ -173,6 +173,8 @@ pub fn decode( symbolSequence, parityData, symbologyModifier, + String::default(), + false, )) } diff --git a/src/rxing_result_metadata.rs b/src/rxing_result_metadata.rs index 01dca20..58ac8c9 100644 --- a/src/rxing_result_metadata.rs +++ b/src/rxing_result_metadata.rs @@ -108,23 +108,39 @@ pub enum RXingResultMetadataType { * when prepending to the barcode content. */ SYMBOLOGY_IDENTIFIER, + + IS_MIRRORED, + + CONTENT_TYPE, } impl From for RXingResultMetadataType { fn from(in_str: String) -> Self { - match in_str.as_str() { + match in_str.to_uppercase().as_str() { "OTHER" => RXingResultMetadataType::OTHER, "ORIENTATION" => RXingResultMetadataType::ORIENTATION, - "BYTE_SEGMENTS" => RXingResultMetadataType::BYTE_SEGMENTS, - "ERROR_CORRECTION_LEVEL" => RXingResultMetadataType::ERROR_CORRECTION_LEVEL, - "ISSUE_NUMBER" => RXingResultMetadataType::ISSUE_NUMBER, - "SUGGESTED_PRICE" => RXingResultMetadataType::SUGGESTED_PRICE, - "POSSIBLE_COUNTRY" => RXingResultMetadataType::POSSIBLE_COUNTRY, - "UPC_EAN_EXTENSION" => RXingResultMetadataType::UPC_EAN_EXTENSION, - "PDF417_EXTRA_METADATA" => RXingResultMetadataType::PDF417_EXTRA_METADATA, - "STRUCTURED_APPEND_SEQUENCE" => RXingResultMetadataType::STRUCTURED_APPEND_SEQUENCE, - "STRUCTURED_APPEND_PARITY" => RXingResultMetadataType::STRUCTURED_APPEND_PARITY, - "SYMBOLOGY_IDENTIFIER" => RXingResultMetadataType::SYMBOLOGY_IDENTIFIER, + "BYTE_SEGMENTS" | "BYTESEGMENTS" => RXingResultMetadataType::BYTE_SEGMENTS, + "ERROR_CORRECTION_LEVEL" | "ERRORCORRECTIONLEVEL" => { + RXingResultMetadataType::ERROR_CORRECTION_LEVEL + } + "ISSUE_NUMBER" | "ISSUENUMBER" => RXingResultMetadataType::ISSUE_NUMBER, + "SUGGESTED_PRICE" | "SUGGESTEDPRICE" => RXingResultMetadataType::SUGGESTED_PRICE, + "POSSIBLE_COUNTRY" | "POSSIBLECOUNTRY" => RXingResultMetadataType::POSSIBLE_COUNTRY, + "UPC_EAN_EXTENSION" | "UPCEANEXTENSION" => RXingResultMetadataType::UPC_EAN_EXTENSION, + "PDF417_EXTRA_METADATA" | "PDF417EXTRAMETADATA" => { + RXingResultMetadataType::PDF417_EXTRA_METADATA + } + "STRUCTURED_APPEND_SEQUENCE" | "STRUCTUREDAPPENDSEQUENCE" => { + RXingResultMetadataType::STRUCTURED_APPEND_SEQUENCE + } + "STRUCTURED_APPEND_PARITY" | "STRUCTUREDAPPENDPARITY" => { + RXingResultMetadataType::STRUCTURED_APPEND_PARITY + } + "SYMBOLOGY_IDENTIFIER" | "SYMBOLOGYIDENTIFIER" => { + RXingResultMetadataType::SYMBOLOGY_IDENTIFIER + } + "IS_MIRRORED" | "ISMIRRORED" => RXingResultMetadataType::IS_MIRRORED, + "CONTENT_TYPE" | "CONTENTTYPE" => RXingResultMetadataType::CONTENT_TYPE, _ => RXingResultMetadataType::OTHER, } } @@ -209,4 +225,8 @@ pub enum RXingResultMetadataValue { * when prepending to the barcode content. */ SymbologyIdentifier(String), + + IsMirrored(bool), + + ContentType(String), } diff --git a/test_resources/blackbox/datamatrix-1/0123456789.result.txt b/test_resources/blackbox/datamatrix-1/0123456789.result.txt deleted file mode 100644 index 771cae7..0000000 --- a/test_resources/blackbox/datamatrix-1/0123456789.result.txt +++ /dev/null @@ -1,2 +0,0 @@ -symbologyIdentifier=]d1 -isMirrored=false diff --git a/test_resources/blackbox/datamatrix-1/abcd-36x12-mirrored.result.txt b/test_resources/blackbox/datamatrix-1/abcd-36x12-mirrored.metadata.txt similarity index 100% rename from test_resources/blackbox/datamatrix-1/abcd-36x12-mirrored.result.txt rename to test_resources/blackbox/datamatrix-1/abcd-36x12-mirrored.metadata.txt diff --git a/tests/common/abstract_black_box_test_case.rs b/tests/common/abstract_black_box_test_case.rs index 5faa5c3..90d71c2 100644 --- a/tests/common/abstract_black_box_test_case.rs +++ b/tests/common/abstract_black_box_test_case.rs @@ -175,8 +175,9 @@ impl AbstractBlackBoxTestCase { .unwrap(); let mut expected_metadata_file: PathBuf = self.test_base.clone().to_path_buf(); - expected_metadata_file.push(format!("{}.metadata", file_base_name.to_str().unwrap())); - expected_metadata_file.set_extension("txt"); + expected_metadata_file + .push(format!("{}.metadata.txt", file_base_name.to_str().unwrap())); + // expected_metadata_file.set_extension("txt"); let expected_metadata_unfinished = if expected_metadata_file.exists() { java_properties::read( std::fs::File::open(expected_metadata_file) @@ -189,10 +190,10 @@ impl AbstractBlackBoxTestCase { } else { HashMap::new() }; - let expected_metadata = HashMap::new(); + let mut expected_metadata = HashMap::new(); for (k, v) in expected_metadata_unfinished { let new_k = RXingResultMetadataType::from(k); - let _new_v = match new_k { + let new_v = match new_k { RXingResultMetadataType::OTHER => RXingResultMetadataValue::OTHER(v), RXingResultMetadataType::ORIENTATION => { RXingResultMetadataValue::Orientation(v.parse().unwrap_or_default()) @@ -233,7 +234,14 @@ impl AbstractBlackBoxTestCase { RXingResultMetadataType::SYMBOLOGY_IDENTIFIER => { RXingResultMetadataValue::SymbologyIdentifier(v) } + RXingResultMetadataType::IS_MIRRORED => { + RXingResultMetadataValue::IsMirrored(v.parse().unwrap()) + } + RXingResultMetadataType::CONTENT_TYPE => { + RXingResultMetadataValue::ContentType(v) + } }; + expected_metadata.insert(new_k, new_v); } for x in 0..test_count { diff --git a/tests/common/pdf_417_multiimage_span.rs b/tests/common/pdf_417_multiimage_span.rs index 5e2f600..1da26d5 100644 --- a/tests/common/pdf_417_multiimage_span.rs +++ b/tests/common/pdf_417_multiimage_span.rs @@ -334,10 +334,10 @@ impl PDF417MultiImageSpanAbstractBlackBoxTest } else { HashMap::new() }; - let expected_metadata = HashMap::new(); + let mut expected_metadata = HashMap::new(); for (k, v) in expected_metadata_unfinished { let new_k = RXingResultMetadataType::from(k); - let _new_v = match new_k { + let new_v = match new_k { RXingResultMetadataType::OTHER => RXingResultMetadataValue::OTHER(v), RXingResultMetadataType::ORIENTATION => { RXingResultMetadataValue::Orientation(v.parse().unwrap_or_default()) @@ -378,7 +378,14 @@ impl PDF417MultiImageSpanAbstractBlackBoxTest RXingResultMetadataType::SYMBOLOGY_IDENTIFIER => { RXingResultMetadataValue::SymbologyIdentifier(v) } + RXingResultMetadataType::IS_MIRRORED => { + RXingResultMetadataValue::IsMirrored(v.parse().unwrap()) + } + RXingResultMetadataType::CONTENT_TYPE => { + RXingResultMetadataValue::ContentType(v) + } }; + expected_metadata.insert(new_k, new_v); } for x in 0..test_count {