diff --git a/src/common/cpp_essentials/base_extentions/qr_formatinformation.rs b/src/common/cpp_essentials/base_extentions/qr_formatinformation.rs index 414cfa2..15001e6 100644 --- a/src/common/cpp_essentials/base_extentions/qr_formatinformation.rs +++ b/src/common/cpp_essentials/base_extentions/qr_formatinformation.rs @@ -24,7 +24,7 @@ impl FormatInformation { pub fn DecodeMQR(formatInfoBits: u32) -> Self { todo!() // // We don't use the additional masking (with 0x4445) to work around potentially non complying MicroQRCode encoders - // auto fi = FindBestFormatInfo(0, FORMAT_INFO_DECODE_LOOKUP_MICRO, {formatInfoBits, MirrorBits(formatInfoBits)}); + // let fi = FindBestFormatInfo(0, FORMAT_INFO_DECODE_LOOKUP_MICRO, {formatInfoBits, MirrorBits(formatInfoBits)}); // constexpr uint8_t BITS_TO_VERSION[] = {1, 2, 2, 3, 3, 4, 4, 4}; @@ -37,6 +37,30 @@ impl FormatInformation { // return fi; } + pub fn MirrorBits(bits: u32) -> u32 { + todo!() + // return BitHacks::Reverse(bits) >> 17; + } + + pub fn FindBestFormatInfo(mask: u32, lookup: [(u32, u32); 32], bits: &[u32]) -> Self { + todo!() + // FormatInformation fi; + + // // Some QR codes apparently do not apply the XOR mask. Try without and with additional masking. + // for (auto mask : {0, mask}) + // for (int bitsIndex = 0; bitsIndex < Size(bits); ++bitsIndex) + // for (const auto& [pattern, index] : lookup) { + // // Find the int in lookup with fewest bits differing + // if (int hammingDist = BitHacks::CountBitsSet((bits[bitsIndex] ^ mask) ^ pattern); hammingDist < fi.hammingDistance) { + // fi.index = index; + // fi.hammingDistance = hammingDist; + // fi.bitsIndex = bitsIndex; + // } + // } + + // return fi; + } + pub fn isValid(&self) -> bool { todo!() } diff --git a/src/qrcode/cpp_port/bitmatrix_parser.rs b/src/qrcode/cpp_port/bitmatrix_parser.rs index 2eafb77..275c75d 100644 --- a/src/qrcode/cpp_port/bitmatrix_parser.rs +++ b/src/qrcode/cpp_port/bitmatrix_parser.rs @@ -10,7 +10,7 @@ use crate::{ Exceptions, }; -use super::detector::AppendBit; +use super::{data_mask::GetDataMaskBit, detector::AppendBit}; pub fn getBit(bitMatrix: &BitMatrix, x: u32, y: u32, mirrored: Option) -> bool { let mirrored = mirrored.unwrap_or(false); @@ -121,42 +121,54 @@ pub fn ReadQRCodewords( version: VersionRef, formatInfo: &FormatInformation, ) -> Result> { - todo!() - // BitMatrix functionPattern = version.buildFunctionPattern(); + let functionPattern: BitMatrix = version.buildFunctionPattern()?; - // ByteArray result; - // result.reserve(version.totalCodewords()); - // uint8_t currentByte = 0; - // bool readingUp = true; - // int bitsRead = 0; - // int dimension = bitMatrix.height(); - // // Read columns in pairs, from right to left - // for (int x = dimension - 1; x > 0; x -= 2) { - // // Skip whole column with vertical timing pattern. - // if (x == 6) - // x--; - // // Read alternatingly from bottom to top then top to bottom - // for (int row = 0; row < dimension; row++) { - // int y = readingUp ? dimension - 1 - row : row; - // for (int col = 0; col < 2; col++) { - // int xx = x - col; - // // Ignore bits covered by the function pattern - // if (!functionPattern.get(xx, y)) { - // // Read a bit - // AppendBit(currentByte, - // GetDataMaskBit(formatInfo.dataMask, xx, y) != getBit(bitMatrix, xx, y, formatInfo.isMirrored)); - // // If we've made a whole byte, save it off - // if (++bitsRead % 8 == 0) - // result.push_back(std::exchange(currentByte, 0)); - // } - // } - // } - // readingUp = !readingUp; // switch directions - // } - // if (Size(result) != version.totalCodewords()) - // return {}; + let mut result = Vec::new(); + result.reserve(version.getTotalCodewords() as usize); + let mut currentByte = 0; + let mut readingUp = true; + let mut bitsRead = 0; + let dimension = bitMatrix.height(); + // Read columns in pairs, from right to left + let mut x = dimension - 1; + while x > 0 { + // for (int x = dimension - 1; x > 0; x -= 2) { + // Skip whole column with vertical timing pattern. + if (x == 6) { + x -= 1; + } + // Read alternatingly from bottom to top then top to bottom + for row in 0..dimension { + // for (int row = 0; row < dimension; row++) { + let y = if readingUp { dimension - 1 - row } else { row }; + for col in 0..2 { + // for (int col = 0; col < 2; col++) { + let xx = x - col; + // Ignore bits covered by the function pattern + if (!functionPattern.get(xx, y)) { + // Read a bit + AppendBit( + &mut currentByte, + GetDataMaskBit(formatInfo.data_mask as u32, xx, y, None) + != getBit(bitMatrix, xx, y, Some(formatInfo.isMirrored)), + ); + // If we've made a whole byte, save it off + bitsRead += 1; + if (bitsRead % 8 == 0) { + result.push(std::mem::take(&mut currentByte)); + } + } + } + } + readingUp = !readingUp; // switch directions - // return result; + x -= 2; + } + if ((result.len()) != version.getTotalCodewords() as usize) { + return Err(Exceptions::FORMAT); + } + + Ok(result.iter().copied().map(|x| x as u8).collect()) } pub fn ReadMQRCodewords( diff --git a/src/qrcode/cpp_port/data_mask.rs b/src/qrcode/cpp_port/data_mask.rs new file mode 100644 index 0000000..1db71c3 --- /dev/null +++ b/src/qrcode/cpp_port/data_mask.rs @@ -0,0 +1,47 @@ +/* +* Copyright 2016 Nu-book Inc. +* Copyright 2016 ZXing authors +*/ +// SPDX-License-Identifier: Apache-2.0 + +use crate::common::BitMatrix; + +/** +*

Encapsulates data masks for the data bits in a QR and micro QR code, per ISO 18004:2006 6.8.

+* +*

Note that the diagram in section 6.8.1 is misleading since it indicates that i is column position +* and j is row position. In fact, as the text says, i is row position and j is column position.

+*/ + +pub fn GetDataMaskBit(maskIndex: u32, x: u32, y: u32, isMicro: Option) -> bool { + let isMicro = isMicro.unwrap_or(false); + todo!() + // if (isMicro) { + // if (maskIndex < 0 || maskIndex >= 4) + // throw std::invalid_argument("QRCode maskIndex out of range"); + // maskIndex = std::array{1, 4, 6, 7}[maskIndex]; // map from MQR to QR indices + // } + + // switch (maskIndex) { + // case 0: return (y + x) % 2 == 0; + // case 1: return y % 2 == 0; + // case 2: return x % 3 == 0; + // case 3: return (y + x) % 3 == 0; + // case 4: return ((y / 2) + (x / 3)) % 2 == 0; + // case 5: return (y * x) % 6 == 0; + // case 6: return ((y * x) % 6) < 3; + // case 7: return (y + x + ((y * x) % 3)) % 2 == 0; + // } + + // throw std::invalid_argument("QRCode maskIndex out of range"); +} + +pub fn GetMaskedBit( + bits: &BitMatrix, + x: u32, + y: u32, + maskIndex: u32, + isMicro: Option, +) -> bool { + return GetDataMaskBit(maskIndex, x, y, isMicro) != bits.get(x, y); +} diff --git a/src/qrcode/cpp_port/mod.rs b/src/qrcode/cpp_port/mod.rs index 464babf..2893c1b 100644 --- a/src/qrcode/cpp_port/mod.rs +++ b/src/qrcode/cpp_port/mod.rs @@ -1,3 +1,4 @@ +mod data_mask; pub mod decoder; pub mod detector;