diff --git a/Cargo.toml b/Cargo.toml index 7b5b2f3..a696b38 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "rxing" -version = "0.5.3" +version = "0.5.4" description="A rust port of the zxing barcode library." license="Apache-2.0" repository="https://github.com/rxing-core/rxing" diff --git a/src/barcode_format.rs b/src/barcode_format.rs index 2946991..70fd962 100644 --- a/src/barcode_format.rs +++ b/src/barcode_format.rs @@ -67,6 +67,8 @@ pub enum BarcodeFormat { MICRO_QR_CODE, + RECTANGULAR_MICRO_QR_CODE, + /** RSS 14 */ RSS_14, @@ -108,6 +110,7 @@ impl Display for BarcodeFormat { BarcodeFormat::PDF_417 => "pdf 417", BarcodeFormat::QR_CODE => "qrcode", BarcodeFormat::MICRO_QR_CODE => "mqr", + BarcodeFormat::RECTANGULAR_MICRO_QR_CODE => "rmqr", BarcodeFormat::RSS_14 => "rss 14", BarcodeFormat::RSS_EXPANDED => "rss expanded", BarcodeFormat::TELEPEN => "telepen", @@ -150,6 +153,9 @@ impl From<&str> for BarcodeFormat { "mqr" | "microqr" | "micro_qr" | "micro_qrcode" | "micro_qr_code" | "mqr_code" => { BarcodeFormat::MICRO_QR_CODE } + "rmqr" | "rectangular_mqr" | "rectangular_micro_qr" | "rmqr_code" => { + BarcodeFormat::RECTANGULAR_MICRO_QR_CODE + } "rss 14" | "rss_14" | "rss14" | "gs1 databar" | "gs1 databar coupon" | "gs1_databar_coupon" => BarcodeFormat::RSS_14, "rss expanded" | "expanded rss" | "rss_expanded" => BarcodeFormat::RSS_EXPANDED, diff --git a/src/common/bit_matrix.rs b/src/common/bit_matrix.rs index 01b63c4..9a30749 100644 --- a/src/common/bit_matrix.rs +++ b/src/common/bit_matrix.rs @@ -636,7 +636,7 @@ impl BitMatrix { self.width() } - pub fn width(&self) -> u32 { + pub const fn width(&self) -> u32 { self.width } @@ -647,7 +647,7 @@ impl BitMatrix { self.height() } - pub fn height(&self) -> u32 { + pub const fn height(&self) -> u32 { self.height } diff --git a/src/common/cpp_essentials/base_extentions/qr_formatinformation.rs b/src/common/cpp_essentials/base_extentions/qr_formatinformation.rs index 398a54b..1e2ca2d 100644 --- a/src/common/cpp_essentials/base_extentions/qr_formatinformation.rs +++ b/src/common/cpp_essentials/base_extentions/qr_formatinformation.rs @@ -1,41 +1,49 @@ -use crate::qrcode::decoder::{ - ErrorCorrectionLevel, FormatInformation, FORMAT_INFO_DECODE_LOOKUP, FORMAT_INFO_MASK_QR, +use crate::qrcode::{ + cpp_port::Type, + decoder::{ + ErrorCorrectionLevel, FormatInformation, FORMAT_INFO_MASK_MODEL2, FORMAT_INFO_MASK_QR, + }, }; -pub const FORMAT_INFO_DECODE_LOOKUP_MICRO: [[u32; 2]; 32] = [ - [0x4445, 0x00], - [0x4172, 0x01], - [0x4E2B, 0x02], - [0x4B1C, 0x03], - [0x55AE, 0x04], - [0x5099, 0x05], - [0x5FC0, 0x06], - [0x5AF7, 0x07], - [0x6793, 0x08], - [0x62A4, 0x09], - [0x6DFD, 0x0A], - [0x68CA, 0x0B], - [0x7678, 0x0C], - [0x734F, 0x0D], - [0x7C16, 0x0E], - [0x7921, 0x0F], - [0x06DE, 0x10], - [0x03E9, 0x11], - [0x0CB0, 0x12], - [0x0987, 0x13], - [0x1735, 0x14], - [0x1202, 0x15], - [0x1D5B, 0x16], - [0x186C, 0x17], - [0x2508, 0x18], - [0x203F, 0x19], - [0x2F66, 0x1A], - [0x2A51, 0x1B], - [0x34E3, 0x1C], - [0x31D4, 0x1D], - [0x3E8D, 0x1E], - [0x3BBA, 0x1F], -]; +pub const FORMAT_INFO_MASK_QR_MODEL1: u32 = 0x2825; +pub const FORMAT_INFO_MASK_MICRO: u32 = 0x4445; +pub const FORMAT_INFO_MASK_RMQR: u32 = 0x1FAB2; // Finder pattern side +pub const FORMAT_INFO_MASK_RMQR_SUB: u32 = 0x20A7B; // Finder sub pattern side + +// pub const FORMAT_INFO_DECODE_LOOKUP_MICRO: [u32 ;32] = [ +// 0x4445, +// 0x4172, +// 0x4E2B, +// 0x4B1C, +// 0x55AE, +// 0x5099, +// 0x5FC0, +// 0x5AF7, +// 0x6793, +// 0x62A4, +// 0x6DFD, +// 0x68CA, +// 0x7678, +// 0x734F, +// 0x7C16, +// 0x7921, +// 0x06DE, +// 0x03E9, +// 0x0CB0, +// 0x0987, +// 0x1735, +// 0x1202, +// 0x1D5B, +// 0x186C, +// 0x2508, +// 0x203F, +// 0x2F66, +// 0x2A51, +// 0x34E3, +// 0x31D4, +// 0x3E8D, +// 0x3BBA, +// ]; impl FormatInformation { /** @@ -49,9 +57,9 @@ impl FormatInformation { ); let formatInfoBits2 = ((formatInfoBits2 >> 1) & 0b111111100000000) | (formatInfoBits2 & 0b11111111); + // Some (Model2) QR codes apparently do not apply the XOR mask. Try with (standard) and without (quirk) masking. let mut fi = Self::FindBestFormatInfo( - FORMAT_INFO_MASK_QR, - FORMAT_INFO_DECODE_LOOKUP, + &[FORMAT_INFO_MASK_QR, 0, FORMAT_INFO_MASK_QR_MODEL1], &[ formatInfoBits1, formatInfoBits2, @@ -62,8 +70,8 @@ impl FormatInformation { // Use bits 3/4 for error correction, and 0-2 for mask. fi.error_correction_level = - ErrorCorrectionLevel::ECLevelFromBits((fi.index >> 3) & 0x03, false); - fi.data_mask = fi.index & 0x07; + ErrorCorrectionLevel::ECLevelFromBits((fi.data >> 3) as u8 & 0x03, false); + fi.data_mask = fi.data as u8 & 0x07; fi.isMirrored = fi.bitsIndex > 1; fi @@ -72,8 +80,7 @@ impl FormatInformation { pub fn DecodeMQR(formatInfoBits: u32) -> Self { // We don't use the additional masking (with 0x4445) to work around potentially non complying MicroQRCode encoders let mut fi = Self::FindBestFormatInfo( - 0, - FORMAT_INFO_DECODE_LOOKUP_MICRO, + &[FORMAT_INFO_MASK_MICRO, 0], &[formatInfoBits, Self::MirrorBits(formatInfoBits)], ); @@ -81,34 +88,67 @@ impl FormatInformation { // Bits 2/3/4 contain both error correction level and version, 0/1 contain mask. fi.error_correction_level = - ErrorCorrectionLevel::ECLevelFromBits((fi.index >> 2) & 0x07, true); - fi.data_mask = fi.index & 0x03; - fi.microVersion = BITS_TO_VERSION[((fi.index >> 2) & 0x07) as usize] as u32; + ErrorCorrectionLevel::ECLevelFromBits((fi.data >> 2) as u8 & 0x07, true); + fi.data_mask = fi.data as u8 & 0x03; + fi.microVersion = BITS_TO_VERSION[((fi.data >> 2) as u8 & 0x07) as usize] as u32; fi.isMirrored = fi.bitsIndex == 1; fi } + /** + * @param formatInfoBits1 format info indicator, with mask still applied + * @param formatInfoBits2 second copy of same info; both are checked at the same time to establish best match + */ + pub fn DecodeRMQR(formatInfoBits1: u32, formatInfoBits2: u32) -> Self { + //FormatInformation fi; + + let mut fi = if formatInfoBits2 != 0 { + Self::FindBestFormatInfoRMQR(&[formatInfoBits1], &[formatInfoBits2]) + } else { + // TODO probably remove if `sampleRMQR()` done properly + Self::FindBestFormatInfoRMQR(&[formatInfoBits1], &[]) + }; + + // Bit 6 is error correction (M/H), and bits 0-5 version. + fi.error_correction_level = + ErrorCorrectionLevel::ECLevelFromBits(((fi.data >> 5) as u8 & 1) << 1, false); // Shift to match QRCode M/H + fi.data_mask = 4; // ((y / 2) + (x / 3)) % 2 == 0 + fi.microVersion = (fi.data & 0x1F) + 1; + fi.isMirrored = false; // TODO: implement mirrored format bit reading + + fi + } + #[inline(always)] pub fn MirrorBits(bits: u32) -> u32 { (bits.reverse_bits()) >> 17 } - pub fn FindBestFormatInfo(mask: u32, lookup: [[u32; 2]; 32], bits: &[u32]) -> Self { + pub fn FindBestFormatInfo(masks: &[u32], bits: &[u32]) -> Self { let mut fi = FormatInformation::default(); - // Some QR codes apparently do not apply the XOR mask. Try without and with additional masking. - for mask in [0, mask] { - // for (auto mask : {0, mask}) - for (bitsIndex, bit_set) in bits.iter().enumerate() { + // See ISO 18004:2015, Annex C, Table C.1 + const MODEL2_MASKED_PATTERNS: [u32; 32] = [ + 0x5412, 0x5125, 0x5E7C, 0x5B4B, 0x45F9, 0x40CE, 0x4F97, 0x4AA0, 0x77C4, 0x72F3, 0x7DAA, + 0x789D, 0x662F, 0x6318, 0x6C41, 0x6976, 0x1689, 0x13BE, 0x1CE7, 0x19D0, 0x0762, 0x0255, + 0x0D0C, 0x083B, 0x355F, 0x3068, 0x3F31, 0x3A06, 0x24B4, 0x2183, 0x2EDA, 0x2BED, + ]; + + for mask in masks { + // for (auto mask : masks) + for bitsIndex in 0..bits.len() { // for (int bitsIndex = 0; bitsIndex < Size(bits); ++bitsIndex) - for [pattern, index] in lookup { - // for (const auto& [pattern, index] : lookup) { - // Find the int in lookup with fewest bits differing - let hammingDist = ((bit_set ^ mask) ^ pattern).count_ones(); + for ref_pattern in MODEL2_MASKED_PATTERNS { + // for (uint32_t pattern : MODEL2_MASKED_PATTERNS) { + // 'unmask' the pattern first to get the original 5-data bits + 10-ec bits back + let pattern = ref_pattern ^ FORMAT_INFO_MASK_MODEL2; + // Find the pattern with fewest bits differing + let hammingDist = ((bits[bitsIndex] ^ mask) ^ pattern).count_ones(); + // if (int hammingDist = BitHacks::CountBitsSet((bits[bitsIndex] ^ mask) ^ pattern); if hammingDist < fi.hammingDistance { - // if (int hammingDist = BitHacks::CountBitsSet((bits[bitsIndex] ^ mask) ^ pattern); hammingDist < fi.hammingDistance) { - fi.index = index as u8; + fi.mask = *mask; // store the used mask to discriminate between types/models + fi.data = pattern >> 10; // drop the 10 BCH error correction bits fi.hammingDistance = hammingDist; fi.bitsIndex = bitsIndex as u8; } @@ -116,16 +156,102 @@ impl FormatInformation { } } + // // Some QR codes apparently do not apply the XOR mask. Try without and with additional masking. + // for mask in masks { + // // for (auto mask : {0, mask}) + // for (bitsIndex, bit_set) in bits.iter().enumerate() { + // // for (int bitsIndex = 0; bitsIndex < Size(bits); ++bitsIndex) + // for [pattern, _index] in FORMAT_INFO_DECODE_LOOKUP { + // // for (const auto& [pattern, index] : lookup) { + // // Find the int in lookup with fewest bits differing + // let hammingDist = ((bit_set ^ mask) ^ pattern).count_ones(); + // if hammingDist < fi.hammingDistance { + // // if (int hammingDist = BitHacks::CountBitsSet((bits[bitsIndex] ^ mask) ^ pattern); hammingDist < fi.hammingDistance) { + // fi.mask = *mask; // store the used mask to discriminate between types/models + // fi.data = pattern >> 10; // drop the 10 BCH error correction bits + // fi.hammingDistance = hammingDist; + // fi.bitsIndex = bitsIndex as u8; + // } + // } + // } + // } + fi } - // Hamming distance of the 32 masked codes is 7, by construction, so <= 3 bits differing means we found a match - pub fn isValid(&self) -> bool { + pub fn FindBestFormatInfoRMQR(bits: &[u32], subbits: &[u32]) -> Self { + // See ISO/IEC 23941:2022, Annex C, Table C.1 - Valid format information sequences + const MASKED_PATTERNS: [u32; 64] = [ + // Finder pattern side + 0x1FAB2, 0x1E597, 0x1DBDD, 0x1C4F8, 0x1B86C, 0x1A749, 0x19903, 0x18626, 0x17F0E, + 0x1602B, 0x15E61, 0x14144, 0x13DD0, 0x122F5, 0x11CBF, 0x1039A, 0x0F1CA, 0x0EEEF, + 0x0D0A5, 0x0CF80, 0x0B314, 0x0AC31, 0x0927B, 0x08D5E, 0x07476, 0x06B53, 0x05519, + 0x04A3C, 0x036A8, 0x0298D, 0x017C7, 0x008E2, 0x3F367, 0x3EC42, 0x3D208, 0x3CD2D, + 0x3B1B9, 0x3AE9C, 0x390D6, 0x38FF3, 0x376DB, 0x369FE, 0x357B4, 0x34891, 0x33405, + 0x32B20, 0x3156A, 0x30A4F, 0x2F81F, 0x2E73A, 0x2D970, 0x2C655, 0x2BAC1, 0x2A5E4, + 0x29BAE, 0x2848B, 0x27DA3, 0x26286, 0x25CCC, 0x243E9, 0x23F7D, 0x22058, 0x21E12, + 0x20137, + ]; + const MASKED_PATTERNS_SUB: [u32; 64] = [ + // Finder sub pattern side + 0x20A7B, 0x2155E, 0x22B14, 0x23431, 0x248A5, 0x25780, 0x269CA, 0x276EF, 0x28FC7, + 0x290E2, 0x2AEA8, 0x2B18D, 0x2CD19, 0x2D23C, 0x2EC76, 0x2F353, 0x30103, 0x31E26, + 0x3206C, 0x33F49, 0x343DD, 0x35CF8, 0x362B2, 0x37D97, 0x384BF, 0x39B9A, 0x3A5D0, + 0x3BAF5, 0x3C661, 0x3D944, 0x3E70E, 0x3F82B, 0x003AE, 0x01C8B, 0x022C1, 0x03DE4, + 0x04170, 0x05E55, 0x0601F, 0x07F3A, 0x08612, 0x09937, 0x0A77D, 0x0B858, 0x0C4CC, + 0x0DBE9, 0x0E5A3, 0x0FA86, 0x108D6, 0x117F3, 0x129B9, 0x1369C, 0x14A08, 0x1552D, + 0x16B67, 0x17442, 0x18D6A, 0x1924F, 0x1AC05, 0x1B320, 0x1CFB4, 0x1D091, 0x1EEDB, + 0x1F1FE, + ]; + + let mut fi = FormatInformation::default(); + + let mut best = |bits: &[u32], &patterns: &[u32; 64], mask: u32| { + for bitsIndex in 0..bits.len() { + // for (int bitsIndex = 0; bitsIndex < Size(bits); ++bitsIndex) { + for l_pattern in patterns { + // for (uint32_t pattern : patterns) { + // 'unmask' the pattern first to get the original 6-data bits + 12-ec bits back + let pattern = l_pattern ^ mask; + // Find the pattern with fewest bits differing + let hammingDist = ((bits[bitsIndex] ^ mask) ^ pattern).count_ones(); + if hammingDist < fi.hammingDistance { + fi.mask = mask; // store the used mask to discriminate between types/models + fi.data = pattern >> 12; // drop the 12 BCH error correction bits + fi.hammingDistance = hammingDist; + fi.bitsIndex = bitsIndex as u8; + } + } + } + }; + + best(bits, &MASKED_PATTERNS, FORMAT_INFO_MASK_RMQR); + if !subbits.is_empty() + // TODO probably remove if `sampleRMQR()` done properly + { + best(subbits, &MASKED_PATTERNS_SUB, FORMAT_INFO_MASK_RMQR_SUB); + } + + fi + } + + pub const fn qr_type(&self) -> Type { + match self.mask { + FORMAT_INFO_MASK_QR_MODEL1 => Type::Model1, + FORMAT_INFO_MASK_MICRO => Type::Micro, + FORMAT_INFO_MASK_RMQR | FORMAT_INFO_MASK_RMQR_SUB => Type::RectMicro, + _ => Type::Model2, + } + } + + // Hamming distance of the 32 masked codes is 7 (64 and 8 for rMQR), by construction, so <= 3 bits differing means we found a match + pub const fn isValid(&self) -> bool { self.hammingDistance <= 3 } pub fn cpp_eq(&self, other: &Self) -> bool { self.data_mask == other.data_mask && self.error_correction_level == other.error_correction_level + && self.qr_type() == other.qr_type() } } diff --git a/src/common/cpp_essentials/base_extentions/qrcode_version.rs b/src/common/cpp_essentials/base_extentions/qrcode_version.rs index 892352f..4700b1e 100644 --- a/src/common/cpp_essentials/base_extentions/qrcode_version.rs +++ b/src/common/cpp_essentials/base_extentions/qrcode_version.rs @@ -1,51 +1,94 @@ -use crate::common::Result; -use crate::qrcode::decoder::{Version, VersionRef, MICRO_VERSIONS, VERSIONS, VERSION_DECODE_INFO}; -use crate::Exceptions; +/* +* Copyright 2016 Nu-book Inc. +* Copyright 2016 ZXing authors +* Copyright 2023 Axel Waggershauser +*/ +// SPDX-License-Identifier: Apache-2.0 -// const Version* Version::AllMicroVersions() -// { -// /** -// * See ISO 18004:2006 6.5.1 Table 9 -// */ -// static const Version allVersions[] = { -// {1, {2, 1, 3, 0, 0}}, -// {2, {5, 1, 5, 0, 0, 6, 1, 4, 0, 0}}, -// {3, {6, 1, 11, 0, 0, 8, 1, 9, 0, 0}}, -// {4, {8, 1, 16, 0, 0, 10, 1, 14, 0, 0, 14, 1, 10, 0, 0}}}; -// return allVersions; -// } +use num::Integer; + +use crate::common::{BitMatrix, Result}; +use crate::qrcode::cpp_port::Type; +use crate::qrcode::decoder::{ + Version, VersionRef, MICRO_VERSIONS, MODEL1_VERSIONS, RMQR_VERSIONS, VERSIONS, + VERSION_DECODE_INFO, +}; +use crate::{point, Exceptions, PointI}; + +const RMQR_SIZES: [PointI; 32] = [ + point(43, 7), + point(59, 7), + point(77, 7), + point(99, 7), + point(139, 7), + point(43, 9), + point(59, 9), + point(77, 9), + point(99, 9), + point(139, 9), + point(27, 11), + point(43, 11), + point(59, 11), + point(77, 11), + point(99, 11), + point(139, 11), + point(27, 13), + point(43, 13), + point(59, 13), + point(77, 13), + point(99, 13), + point(139, 13), + point(43, 15), + point(59, 15), + point(77, 15), + point(99, 15), + point(139, 15), + point(43, 17), + point(59, 17), + point(77, 17), + point(99, 17), + point(139, 17), +]; impl Version { - pub fn FromDimension(dimension: u32) -> Result { - let isMicro = dimension < 21; - if dimension % Self::DimensionStep(isMicro) != 1 { - //throw std::invalid_argument("Unexpected dimension"); - return Err(Exceptions::ILLEGAL_ARGUMENT); - } - Self::FromNumber( - (dimension - Self::DimensionOffset(isMicro)) / Self::DimensionStep(isMicro), - isMicro, - ) - } - - pub fn FromNumber(versionNumber: u32, is_micro: bool) -> Result { - if versionNumber < 1 || versionNumber > (if is_micro { 4 } else { 40 }) { - //throw std::invalid_argument("Version should be in range [1-40]."); - return Err(Exceptions::ILLEGAL_ARGUMENT); - } - - Ok(if is_micro { - &MICRO_VERSIONS[versionNumber as usize - 1] + pub fn Model1(version_number: u32) -> Result { + if !(1..=14).contains(&version_number) { + Err(Exceptions::ILLEGAL_ARGUMENT) } else { - &VERSIONS[versionNumber as usize - 1] - }) + Ok(&MODEL1_VERSIONS[version_number as usize - 1]) + } } - pub fn DimensionOfVersion(version: u32, is_micro: bool) -> u32 { + pub fn Model2(version_number: u32) -> Result { + if !(1..=40).contains(&version_number) { + Err(Exceptions::ILLEGAL_ARGUMENT) + } else { + Ok(&VERSIONS[version_number as usize - 1]) + } + } + + pub fn Micro(version_number: u32) -> Result { + if !(1..=4).contains(&version_number) { + Err(Exceptions::ILLEGAL_ARGUMENT) + } else { + Ok(&MICRO_VERSIONS[version_number as usize - 1]) + } + } + + pub fn rMQR(version_number: u32) -> Result { + let version_number = version_number as usize; + if version_number < 1 || version_number > (RMQR_VERSIONS.len()) { + Err(Exceptions::ILLEGAL_ARGUMENT) + } else { + Ok(&RMQR_VERSIONS[version_number - 1]) + } + } + + pub const fn DimensionOfVersion(version: u32, is_micro: bool) -> u32 { Self::DimensionOffset(is_micro) + Self::DimensionStep(is_micro) * version } - pub fn DimensionOffset(is_micro: bool) -> u32 { + pub const fn DimensionOffset(is_micro: bool) -> u32 { match is_micro { true => 9, false => 17, @@ -53,7 +96,7 @@ impl Version { // return std::array{17, 9}[isMicro]; } - pub fn DimensionStep(is_micro: bool) -> u32 { + pub const fn DimensionStep(is_micro: bool) -> u32 { match is_micro { true => 2, false => 4, @@ -64,13 +107,6 @@ impl Version { let mut bestDifference = u32::MAX; let mut bestVersion = 0; for (i, targetVersion) in VERSION_DECODE_INFO.into_iter().enumerate() { - // for (int targetVersion : VERSION_DECODE_INFO) { - // Do the version info bits match exactly? done. - if targetVersion == versionBitsA as u32 || targetVersion == versionBitsB as u32 { - return Self::getVersionForNumber(i as u32 + 7); - } - // Otherwise see if this is the closest to a real version info bit string - // we have seen so far for bits in [versionBitsA, versionBitsB] { // for (int bits : {versionBitsA, versionBitsB}) { let bitsDifference = ((bits as u32) ^ targetVersion).count_ones(); //BitHacks::CountBitsSet(bits ^ targetVersion); @@ -79,6 +115,9 @@ impl Version { bestDifference = bitsDifference; } } + if bestDifference == 0 { + break; + } } // We can tolerate up to 3 bits of error since no two version info codewords will // differ in less than 8 bits. @@ -89,7 +128,112 @@ impl Version { Err(Exceptions::ILLEGAL_STATE) } - pub const fn isMicroQRCode(&self) -> bool { - self.is_micro + pub const fn isMicro(&self) -> bool { + Type::const_eq(self.qr_type, Type::Micro) + } + + pub const fn isModel1(&self) -> bool { + Type::const_eq(self.qr_type, Type::Model1) + } + + pub const fn isModel2(&self) -> bool { + Type::const_eq(self.qr_type, Type::Model2) + } + + pub const fn isRMQR(&self) -> bool { + Type::const_eq(self.qr_type, Type::RectMicro) + } + + pub fn SymbolSize(version: u32, qr_type: Type) -> PointI { + let version = version as i32; + + let square = |s: i32| point(s, s); + let valid = |v: i32, max: i32| v >= 1 && v <= max; + + match qr_type { + Type::Model1 => { + if valid(version, 32) { + square(17 + 4 * version) + } else { + PointI::default() + } + } + Type::Model2 => { + if valid(version, 40) { + square(17 + 4 * version) + } else { + PointI::default() + } + } + Type::Micro => { + if valid(version, 4) { + square(9 + 2 * version) + } else { + PointI::default() + } + } + Type::RectMicro => { + if valid(version, 32) { + RMQR_SIZES[(version - 1) as usize] + } else { + PointI::default() + } + } + } + } + + pub fn IsValidSize(size: PointI, qr_type: Type) -> bool { + match qr_type { + Type::Model1 => size.x == size.y && size.x >= 21 && size.x <= 145 && (size.x % 4 == 1), + Type::Model2 => size.x == size.y && size.x >= 21 && size.x <= 177 && (size.x % 4 == 1), + Type::Micro => size.x == size.y && size.x >= 11 && size.x <= 17 && (size.x % 2 == 1), + Type::RectMicro => { + size.x != size.y + && size.x.is_odd() + && size.y.is_odd() + && size.x >= 27 + && size.x <= 139 + && size.y >= 7 + && size.y <= 17 + && Self::IndexOf(&RMQR_SIZES, size) != -1 + } + } + } + pub fn HasValidSizeType(bitMatrix: &BitMatrix, qr_type: Type) -> bool { + Self::IsValidSize( + point(bitMatrix.width() as i32, bitMatrix.height() as i32), + qr_type, + ) + } + + pub fn HasValidSize(matrix: &BitMatrix) -> bool { + Self::HasValidSizeType(matrix, Type::Model1) + || Self::HasValidSizeType(matrix, Type::Model2) + || Self::HasValidSizeType(matrix, Type::Micro) + || Self::HasValidSizeType(matrix, Type::RectMicro) + } + + fn IndexOf(_points: &[PointI], search: PointI) -> i32 { + RMQR_SIZES + .iter() + .position(|p| *p == search) + .map(|x| x as i32) + .unwrap_or(-1) + } + + pub fn NumberPoint(size: PointI) -> u32 { + if size.x != size.y { + (Self::IndexOf(&RMQR_SIZES, size) + 1) as u32 + } else if Self::IsValidSize(size, Type::Model2) { + ((size.x - 17) / 4) as u32 + } else if Self::IsValidSize(size, Type::Micro) { + ((size.x - 9) / 2) as u32 + } else { + 0 + } + } + + pub fn Number(bitMatrix: &BitMatrix) -> u32 { + Self::NumberPoint(point(bitMatrix.width() as i32, bitMatrix.height() as i32)) } } diff --git a/src/common/cpp_essentials/decoder_result.rs b/src/common/cpp_essentials/decoder_result.rs index bd0967c..3504747 100644 --- a/src/common/cpp_essentials/decoder_result.rs +++ b/src/common/cpp_essentials/decoder_result.rs @@ -157,6 +157,13 @@ where self } + pub fn withIsModel1(mut self, is_model_1: bool) -> DecoderResult { + if is_model_1 { + self.content.symbology.modifier = 48 + } + self + } + // pub fn build(self) -> DecoderResult { // } diff --git a/src/common/eci_string_builder.rs b/src/common/eci_string_builder.rs index 657906a..031bcff 100644 --- a/src/common/eci_string_builder.rs +++ b/src/common/eci_string_builder.rs @@ -38,7 +38,7 @@ pub struct ECIStringBuilder { pub has_eci: bool, eci_result: Option, bytes: Vec, - eci_positions: Vec<(Eci, usize, usize)>, // (Eci, start, end) + pub(crate) eci_positions: Vec<(Eci, usize, usize)>, // (Eci, start, end) pub symbology: SymbologyIdentifier, eci_list: HashSet, } diff --git a/src/common/perspective_transform.rs b/src/common/perspective_transform.rs index a0a05b5..03695fe 100644 --- a/src/common/perspective_transform.rs +++ b/src/common/perspective_transform.rs @@ -29,7 +29,7 @@ use super::Quadrilateral; * * @author Sean Owen */ -#[derive(Debug, Copy, Clone, PartialEq)] +#[derive(Debug, Copy, Clone, PartialEq, Default)] pub struct PerspectiveTransform { a11: f32, a12: f32, diff --git a/src/multi_format_reader.rs b/src/multi_format_reader.rs index 2d3e99e..9583d6c 100644 --- a/src/multi_format_reader.rs +++ b/src/multi_format_reader.rs @@ -183,6 +183,9 @@ impl MultiFormatReader { } } BarcodeFormat::MICRO_QR_CODE => QrReader.decode_with_hints(image, &self.hints), + BarcodeFormat::RECTANGULAR_MICRO_QR_CODE => { + QrReader.decode_with_hints(image, &self.hints) + } BarcodeFormat::DATA_MATRIX => { DataMatrixReader.decode_with_hints(image, &self.hints) } diff --git a/src/qrcode/cpp_port/bitmatrix_parser.rs b/src/qrcode/cpp_port/bitmatrix_parser.rs index 58a92bc..b625a02 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::{data_mask::GetDataMaskBit, detector::AppendBit}; +use super::{data_mask::GetDataMaskBit, detector::AppendBit, Type}; pub fn getBit(bitMatrix: &BitMatrix, x: u32, y: u32, mirrored: Option) -> bool { let mirrored = mirrored.unwrap_or(false); @@ -21,51 +21,23 @@ pub fn getBit(bitMatrix: &BitMatrix, x: u32, y: u32, mirrored: Option) -> } } -pub fn hasValidDimension(bitMatrix: &BitMatrix, isMicro: bool) -> bool { - let dimension = bitMatrix.height(); - if isMicro { - (11..=17).contains(&dimension) && (dimension % 2) == 1 - } else { - (21..=177).contains(&dimension) && (dimension % 4) == 1 - } -} - -pub fn ReadVersion(bitMatrix: &BitMatrix) -> Result { - let dimension = bitMatrix.height(); - - let mut version = Version::FromDimension(dimension)?; - - if version.getVersionNumber() < 7 { - return Ok(version); - } - - for mirror in [false, true] { - // for (bool mirror : {false, true}) { - // Read top-right/bottom-left version info: 3 wide by 6 tall (depending on mirrored) - let mut versionBits = 0; - for y in (0..=5).rev() { - // for (int y = 5; y >= 0; --y) { - for x in ((dimension - 11)..=(dimension - 9)).rev() { - // for (int x = dimension - 9; x >= dimension - 11; --x) { - AppendBit(&mut versionBits, getBit(bitMatrix, x, y, Some(mirror))); - } - } - - version = Version::DecodeVersionInformation(versionBits, 0)?; // THIS MIGHT BE WRONG todo!() - if version.getDimensionForVersion() == dimension { - return Ok(version); - } - } - - Err(Exceptions::FORMAT) -} - -pub fn ReadFormatInformation(bitMatrix: &BitMatrix, isMicro: bool) -> Result { - if !hasValidDimension(bitMatrix, isMicro) { +pub fn ReadVersion(bitMatrix: &BitMatrix, qr_type: Type) -> Result { + if !Version::HasValidSize(bitMatrix) { return Err(Exceptions::FORMAT); } - if isMicro { + let number = Version::Number(bitMatrix); + + match qr_type { + Type::Model1 => Version::Model1(number), + Type::Micro => Version::Micro(number), + Type::Model2 => Version::Model2(number), + Type::RectMicro => Version::rMQR(number), + } +} + +pub fn ReadFormatInformation(bitMatrix: &BitMatrix) -> Result { + if Version::HasValidSizeType(bitMatrix, Type::Micro) { // Read top-left format info bits let mut formatInfoBits = 0; for x in 1..9 { @@ -80,6 +52,47 @@ pub fn ReadFormatInformation(bitMatrix: &BitMatrix, isMicro: bool) -> Result= 1; y--){ + AppendBit(&mut formatInfoBits1, getBit(bitMatrix, 11, y, None)); + } + for x in (8..=10).rev() { + // for (int x = 10; x >= 8; x--){ + for y in (1..=5).rev() { + // for (int y = 5; y >= 1; y--){ + AppendBit(&mut formatInfoBits1, getBit(bitMatrix, x, y, None)); + } + } + // Read bottom-right format info bits + let mut formatInfoBits2 = 0; + let width = bitMatrix.width(); + let height = bitMatrix.height(); + for x in 3..=5 { + // for (int x = 3; x <= 5; x++){ + AppendBit( + &mut formatInfoBits2, + getBit(bitMatrix, width - x, height - 6, None), + ); + } + for x in 6..=8 { + // for (int x = 6; x <= 8; x++){ + for y in 2..=6 { + // for (int y = 2; y <= 6; y++){ + AppendBit( + &mut formatInfoBits2, + getBit(bitMatrix, width - x, height - y, None), + ); + } + } + return Ok(FormatInformation::DecodeRMQR( + formatInfoBits1 as u32, + formatInfoBits2 as u32, + )); + } + // Read top-left format info bits let mut formatInfoBits1 = 0; for x in 0..6 { @@ -235,18 +248,173 @@ pub fn ReadMQRCodewords( Ok(result.iter().copied().map(|x| x as u8).collect()) } +pub fn ReadQRCodewordsModel1( + bitMatrix: &BitMatrix, + version: VersionRef, + formatInfo: &FormatInformation, +) -> Result> { + let mut result = Vec::with_capacity(version.getTotalCodewords() as usize); + let dimension = bitMatrix.height(); + let columns = dimension / 4 + 1 + 2; + for j in 0..columns { + // for (int j = 0; j < columns; j++) { + if j <= 1 { + // vertical symbols on the right side + let rows = (dimension - 8) / 4; + for i in 0..rows { + // for (int i = 0; i < rows; i++) { + if j == 0 && i % 2 == 0 && i > 0 && i < rows - 1 + // extension + { + continue; + } + let x = (dimension - 1) - (j * 2); + let y = (dimension - 1) - (i * 4); + let mut currentByte = 0; + for b in 0..8 { + // for (int b = 0; b < 8; b++) { + AppendBit( + &mut currentByte, + GetDataMaskBit(formatInfo.data_mask as u32, x - b % 2, y - (b / 2), None)? + != getBit( + bitMatrix, + x - b % 2, + y - (b / 2), + Some(formatInfo.isMirrored), + ), + ); + } + result.push(currentByte); + } + } else if columns - j <= 4 { + // vertical symbols on the left side + let rows = (dimension - 16) / 4; + for i in 0..rows { + // for (int i = 0; i < rows; i++) { + let x = (columns - j - 1) * 2 + 1 + (if columns - j == 4 { 1 } else { 0 }); // timing + let y = (dimension - 1) - 8 - (i * 4); + let mut currentByte = 0; + for b in 0..8 { + // for (int b = 0; b < 8; b++) { + AppendBit( + &mut currentByte, + GetDataMaskBit(formatInfo.data_mask as u32, x - b % 2, y - (b / 2), None)? + != getBit( + bitMatrix, + x - b % 2, + y - (b / 2), + Some(formatInfo.isMirrored), + ), + ); + } + result.push(currentByte); + } + } else { + // horizontal symbols + let rows = dimension / 2; + for i in 0..rows { + // for (int i = 0; i < rows; i++) { + if j == 2 && i >= rows - 4 + // alignment & finder + { + continue; + } + if i == 0 && j % 2 == 1 && j + 1 != columns - 4 + // extension + { + continue; + } + let x = (dimension - 1) - (2 * 2) - (j - 2) * 4; + let y = (dimension - 1) - (i * 2) - (if i >= rows - 3 { 1 } else { 0 }); // timing + let mut currentByte = 0; + for b in 0..8 { + // for (int b = 0; b < 8; b++) { + AppendBit( + &mut currentByte, + GetDataMaskBit(formatInfo.data_mask as u32, x - b % 4, y - (b / 4), None)? + != getBit( + bitMatrix, + x - b % 4, + y - (b / 4), + Some(formatInfo.isMirrored), + ), + ); + } + result.push(currentByte); + } + } + } + + result[0] &= 0xf; // ignore corner + if (result.len()) != version.getTotalCodewords() as usize { + return Err(Exceptions::FORMAT); + } + + Ok(result.iter().copied().map(|x| x as u8).collect()) +} + +pub fn ReadRMQRCodewords( + bitMatrix: &BitMatrix, + version: VersionRef, + formatInfo: &FormatInformation, +) -> Result> { + let functionPattern = version.buildFunctionPattern()?; + + let mut result = Vec::with_capacity(version.getTotalCodewords() as usize); + let mut currentByte = 0; + let mut readingUp = true; + let mut bitsRead = 0; + let width = bitMatrix.width(); + let height = bitMatrix.height(); + // Read columns in pairs, from right to left + let mut x = width as i32 - 1 - 1; + while x > 0 { + // for (int x = width - 1 - 1; x > 0; x -= 2) { // Skip right edge alignment + // Read alternatingly from bottom to top then top to bottom + for row in 0..height { + // for (int row = 0; row < height; row++) { + let y = if readingUp { height - 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 as u32, y) { + // Read a bit + AppendBit( + &mut currentByte, + GetDataMaskBit(formatInfo.data_mask as u32, xx as u32, y, None)? + != getBit(bitMatrix, xx as u32, y, Some(formatInfo.isMirrored)), + ); + // If we've made a whole byte, save it off + bitsRead += 1; + if bitsRead % 8 == 0 { + // if (++bitsRead % 8 == 0){ + result.push(currentByte); + currentByte = 0; + } + } + } + } + readingUp = !readingUp; // switch directions + + 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 ReadCodewords( bitMatrix: &BitMatrix, version: VersionRef, formatInfo: &FormatInformation, ) -> Result> { - if !hasValidDimension(bitMatrix, version.isMicroQRCode()) { - return Err(Exceptions::FORMAT); - } - - if version.isMicroQRCode() { - ReadMQRCodewords(bitMatrix, version, formatInfo) - } else { - ReadQRCodewords(bitMatrix, version, formatInfo) + match version.qr_type { + Type::Model1 => ReadQRCodewordsModel1(bitMatrix, version, formatInfo), + Type::Model2 => ReadQRCodewords(bitMatrix, version, formatInfo), + Type::Micro => ReadMQRCodewords(bitMatrix, version, formatInfo), + Type::RectMicro => ReadRMQRCodewords(bitMatrix, version, formatInfo), } } diff --git a/src/qrcode/cpp_port/decoder.rs b/src/qrcode/cpp_port/decoder.rs index 12aab65..a454902 100644 --- a/src/qrcode/cpp_port/decoder.rs +++ b/src/qrcode/cpp_port/decoder.rs @@ -299,6 +299,10 @@ pub fn DecodeBitStream( let mut structuredAppend = StructuredAppendInfo::default(); let modeBitLength = Mode::get_codec_mode_bits_length(version); + if version.isModel1() { + bits.readBits(4)?; /* Model 1 is leading with 4 0-bits -> drop them */ + } + let res = (|| { while !IsEndOfStream(&mut bits, version)? { let mode: Mode = if modeBitLength == 0 { @@ -306,7 +310,7 @@ pub fn DecodeBitStream( } else { Mode::CodecModeForBits( bits.readBits(modeBitLength as usize)?, - Some(version.isMicroQRCode()), + Some(version.qr_type), )? }; @@ -387,16 +391,24 @@ pub fn DecodeBitStream( .withError(res.err()) .withEcLevel(ecLevel.to_string()) .withVersionNumber(version.getVersionNumber()) - .withStructuredAppend(structuredAppend)) + .withStructuredAppend(structuredAppend) + .withIsModel1(version.isModel1())) } pub fn Decode(bits: &BitMatrix) -> Result> { - let Ok(pversion) = ReadVersion(bits) else { + if !Version::HasValidSize(bits) { + return Err(Exceptions::format_with("Invalid symbol size")); + } + let Ok(formatInfo) = ReadFormatInformation(bits) else { + return Err(Exceptions::format_with("Invalid format information")); + }; + + let Ok(pversion) = ReadVersion(bits, formatInfo.qr_type()) else { return Err(Exceptions::format_with("Invalid version")); }; let version = pversion; - let Ok(formatInfo) = ReadFormatInformation(bits, version.isMicroQRCode()) else { + let Ok(formatInfo) = ReadFormatInformation(bits) else { return Err(Exceptions::format_with("Invalid format information")); }; diff --git a/src/qrcode/cpp_port/detector.rs b/src/qrcode/cpp_port/detector.rs index 61f7ea1..0bcc48f 100644 --- a/src/qrcode/cpp_port/detector.rs +++ b/src/qrcode/cpp_port/detector.rs @@ -2,10 +2,11 @@ use crate::{ common::{ cpp_essentials::{ CenterOfRing, DMRegressionLine, FindConcentricPatternCorners, FindLeftGuardBy, Matrix, + Value, }, DefaultGridSampler, GridSampler, Result, SamplerControl, }, - point_i, + point, point_i, qrcode::{ decoder::{FormatInformation, Version, VersionRef}, detector::QRCodeDetectorResult, @@ -26,6 +27,8 @@ use crate::{ point_f, Point, }; +use super::Type; + #[derive(Copy, Clone, Default, Debug, PartialEq, Eq)] pub struct FinderPatternSet { pub bl: ConcentricPattern, @@ -567,7 +570,7 @@ pub fn SampleQR(image: &BitMatrix, fp: &FinderPatternSet) -> Result= Version::DimensionOfVersion(7, false) as i32 { + if dimension >= Version::SymbolSize(7, Type::Model2).x { let version = ReadVersion(image, dimension as u32, mod2Pix); // if the version bits are garbage -> discard the detection @@ -796,10 +799,9 @@ pub fn DetectPureQR(image: &BitMatrix) -> Result { // SaveAsPBM(image, "weg.pbm"); // #endif - let MIN_MODULES: u32 = Version::DimensionOfVersion(1, false); - let MAX_MODULES: u32 = Version::DimensionOfVersion(40, false); + let MIN_MODULES: i32 = Version::SymbolSize(1, Type::Model2).x; - let (found, left, top, width, height) = image.findBoundingBox(0, 0, 0, 0, MIN_MODULES); + let (found, left, top, width, height) = image.findBoundingBox(0, 0, 0, 0, MIN_MODULES as u32); if !found || (width as i32 - height as i32).abs() > 1 { return Err(Exceptions::NOT_FOUND); @@ -843,8 +845,7 @@ pub fn DetectPureQR(image: &BitMatrix) -> Result { .dim; let moduleSize: f32 = ((width) as f32) / dimension as f32; - if dimension < MIN_MODULES as i32 - || dimension > MAX_MODULES as i32 + if !Version::IsValidSize(point(dimension, dimension), Type::Model2) || !image.is_in(point_f( left as f32 + moduleSize / 2.0 + (dimension - 1) as f32 * moduleSize, top as f32 + moduleSize / 2.0 + (dimension - 1) as f32 * moduleSize, @@ -885,10 +886,9 @@ pub fn DetectPureQR(image: &BitMatrix) -> Result { pub fn DetectPureMQR(image: &BitMatrix) -> Result { type Pattern = [PatternType; 5]; - let MIN_MODULES = Version::DimensionOfVersion(1, true); - let MAX_MODULES = Version::DimensionOfVersion(4, true); + let MIN_MODULES: i32 = Version::SymbolSize(1, Type::Micro).x; - let (found, left, top, width, height) = image.findBoundingBox(0, 0, 0, 0, MIN_MODULES); + let (found, left, top, width, height) = image.findBoundingBox(0, 0, 0, 0, MIN_MODULES as u32); // int left, top, width, height; if !found || (width as i32 - height as i32).abs() > 1 { @@ -911,8 +911,7 @@ pub fn DetectPureMQR(image: &BitMatrix) -> Result { let moduleSize: f32 = (fpWidth as f32) / 7.0; let dimension = (width as f32 / moduleSize).floor() as u32; - if dimension < MIN_MODULES - || dimension > MAX_MODULES + if !Version::IsValidSize(point(dimension as i32, dimension as i32), Type::Micro) || !image.is_in(point_f( left as f32 + moduleSize / 2.0 + (dimension - 1) as f32 * moduleSize, top as f32 + moduleSize / 2.0 + (dimension - 1) as f32 * moduleSize, @@ -949,6 +948,109 @@ pub fn DetectPureMQR(image: &BitMatrix) -> Result { // {{left, top}, {right, top}, {right, bottom}, {left, bottom}}}; } +pub fn DetectPureRMQR(image: &BitMatrix) -> Result { + const SUBPATTERN: FixedPattern<4, 4> = FixedPattern::new([1, 1, 1, 1]); + const TIMINGPATTERN: FixedPattern<10, 10> = FixedPattern::new([1, 1, 1, 1, 1, 1, 1, 1, 1, 1]); + + type Pattern = [PatternType; 5]; //std::array; + // type SubPattern = [PatternType; 5]; //std::array; + // type CornerEdgePattern = [PatternType; 2]; //std::array; + + type SubPattern = [PatternType; 4]; + type TimingPattern = [PatternType; 10]; + + // #ifdef PRINT_DEBUG + // SaveAsPBM(image, "weg.pbm"); + // #endif + + let MIN_MODULES: i32 = Version::SymbolSize(1, Type::RectMicro).y; + + let (found, left, top, width, height) = image.findBoundingBox(0, 0, 0, 0, MIN_MODULES as u32); + + if !found || height >= width { + return Err(Exceptions::NOT_FOUND); + } + let right = left + width - 1; + let bottom = top + height - 1; + + let tl = point_i(left, top); + let tr = point_i(right, top); + let br = point_i(right, bottom); + let bl = point_i(left, bottom); + + // allow corners be moved one pixel inside to accommodate for possible aliasing artifacts + let diagonal: Pattern = EdgeTracer::new(image, tl, point_i(1, 1)) + .readPatternFromBlack(1, None) + .ok_or(Exceptions::ILLEGAL_STATE)?; + let diag_hld = diagonal.to_vec().into(); + let view = PatternView::new(&diag_hld); + if IsPattern::(&view, &PATTERN, None, 0.0, 0.0) == 0.0 { + return Err(Exceptions::NOT_FOUND); + } + + // Finder sub pattern + let subdiagonal: SubPattern = EdgeTracer::new(image, br, point_i(-1, -1)) + .readPatternFromBlack(1, None) + .ok_or(Exceptions::ILLEGAL_STATE)?; + let subdiagonal_hld = subdiagonal.to_vec().into(); + let view = PatternView::new(&subdiagonal_hld); + if IsPattern::(&view, &SUBPATTERN, None, 0.0, 0.0) == 0.0 { + return Err(Exceptions::NOT_FOUND); + } + + let mut moduleSize: f32 = + (diagonal.iter().sum::() + subdiagonal.iter().sum::()) as f32; + + // Vertical corner finder patterns + // Horizontal timing patterns + for (p, d) in [ + (tr, point(-1, 0)), + (bl, point(1, 0)), + (tl, point(1, 0)), + (br, point(-1, 0)), + ] { + let mut cur = EdgeTracer::new(image, p, d.into()); + // skip corner / finder / sub pattern edge + cur.stepToEdge(Some(2 + i32::from(cur.isWhite())), None, None); + let timing: TimingPattern = cur.readPattern(None).ok_or(Exceptions::ILLEGAL_STATE)?; + let timing_hld = timing.to_vec().into(); + let view = PatternView::new(&timing_hld); + if IsPattern::(&view, &TIMINGPATTERN, None, 0.0, 0.0) == 0.0 { + return Err(Exceptions::NOT_FOUND); + } + moduleSize += timing.iter().sum::() as f32; + } + + moduleSize /= (7 + 4 + 4 * 10) as f32; // fp + sub + 4 x timing + let dimW = (width as f32 / moduleSize).round() as i32; + let dimH = (height as f32 / moduleSize).round() as i32; + + if !Version::IsValidSize(point(dimW, dimH), Type::RectMicro) { + return Err(Exceptions::NOT_FOUND); + } + + // #ifdef PRINT_DEBUG + // LogMatrix log; + // LogMatrixWriter lmw(log, image, 5, "grid2.pnm"); + // for (int y = 0; y < dimH; y++) + // for (int x = 0; x < dimW; x++) + // log(PointF(left + (x + .5f) * moduleSize, top + (y + .5f) * moduleSize)); + // #endif + + // Now just read off the bits (this is a crop + subsample) + Ok(QRCodeDetectorResult::new( + image.Deflate( + dimW as u32, + dimH as u32, + top as f32 + moduleSize / 2.0, + left as f32 + moduleSize / 2.0, + moduleSize, + )?, + vec![tl, tr, br, bl], + )) + // return {Deflate(image, dimW, dimH, top + moduleSize / 2, left + moduleSize / 2, moduleSize), {tl, tr, br, bl}}; +} + pub fn SampleMQR(image: &BitMatrix, fp: ConcentricPattern) -> Result { let Some(fpQuad) = FindConcentricPatternCorners(image, fp.p, fp.size, 2) else { return Err(Exceptions::NOT_FOUND); @@ -986,6 +1088,7 @@ pub fn SampleMQR(image: &BitMatrix, fp: ConcentricPattern) -> Result Result Result Result 2 * dim / 3 { @@ -1057,3 +1160,214 @@ pub fn SampleMQR(image: &BitMatrix, fp: ConcentricPattern) -> Result Result { + // TODO proper + let Some(fpQuad) = FindConcentricPatternCorners(image, fp.p, fp.size, 2) else { + return Err(Exceptions::NOT_FOUND); + }; + + let srcQuad = Quadrilateral::rectangle(7, 7, Some(0.5)); + + let FORMAT_INFO_EDGE_COORDS: [Point; 4] = + [point_i(8, 0), point_i(9, 0), point_i(10, 0), point_i(11, 0)]; + let FORMAT_INFO_COORDS: [Point; 18] = [ + point_i(11, 3), + point_i(11, 2), + point_i(11, 1), + point_i(10, 5), + point_i(10, 4), + point_i(10, 3), + point_i(10, 2), + point_i(10, 1), + point_i(9, 5), + point_i(9, 4), + point_i(9, 3), + point_i(9, 2), + point_i(9, 1), + point_i(8, 5), + point_i(8, 4), + point_i(8, 3), + point_i(8, 2), + point_i(8, 1), + ]; + + let mut bestFI: FormatInformation = FormatInformation::default(); + let mut bestPT: PerspectiveTransform = PerspectiveTransform::default(); + let cur = EdgeTracer::new(image, Point::default(), Point::default()); + + for i in 0..4 { + // for (int i = 0; i < 4; ++i) { + let mod2Pix = PerspectiveTransform::quadrilateralToQuadrilateral( + srcQuad, + fpQuad.rotated_corners(Some(i), None), + )?; + + let check = |i: usize, on: bool| { + // let p = mod2Pix.transform_point(Point::centered(FORMAT_INFO_EDGE_COORDS[i])); + // image.is_in(p) && image.get_point(p) == on + + cur.testAt(mod2Pix.transform_point(Point::centered(FORMAT_INFO_EDGE_COORDS[i]))) + == Value::from(on) + }; + + // check that we see top edge timing pattern modules + if !check(0, true) || !check(1, false) || !check(2, true) || !check(3, false) { + continue; + } + + let mut formatInfoBits = 0; + for coord in FORMAT_INFO_COORDS { + // for i in 0..FORMAT_INFO_COORDS.len() { + // for (int i = 0; i < Size(FORMAT_INFO_COORDS); ++i) + AppendBit( + &mut formatInfoBits, + cur.blackAt(mod2Pix.transform_point(Point::centered(coord))), + ); + } + + let fi = FormatInformation::DecodeRMQR(formatInfoBits as u32, 0 /*formatInfoBits2*/); + if fi.hammingDistance < bestFI.hammingDistance { + bestFI = fi; + bestPT = mod2Pix; + } + } + + if !bestFI.isValid() { + return Err(Exceptions::NOT_FOUND); + } + + let dim = Version::SymbolSize(bestFI.microVersion, Type::RectMicro); + + // TODO: this is a WIP + let intersectQuads = |a: &Quadrilateral, b: &Quadrilateral| -> Result { + let tl = a.center(); + let br = b.center(); + // rotate points such that topLeft of a is furthest away from b and topLeft of b is closest to a + // let dist2B = /*[c = br]*/| &a, &b| { Some(Point::distance(a, br).partial_cmp(&Point::distance(b, br))) }; + + let offsetATarget = + a.0.iter() + .max_by(|a, b| { + Point::distance(**a, br) + .partial_cmp(&Point::distance(**b, br)) + .unwrap_or(std::cmp::Ordering::Less) + }) + .ok_or(Exceptions::FORMAT)?; + let offsetA = + a.0.iter() + .position(|x| x == offsetATarget) + .ok_or(Exceptions::FORMAT)? as i32; + // let offsetA = std::max_element(a.begin(), a.end(), dist2B) - a.begin(); + // let dist2A = /*[c = tl]*/| a, b| { Point::distance(a, tl) < Point::distance(b, tl) }; + let offsetBTarget = + b.0.iter() + .min_by(|a, b| { + Point::distance(**a, tl) + .partial_cmp(&Point::distance(**b, tl)) + .unwrap_or(std::cmp::Ordering::Less) + }) + .ok_or(Exceptions::FORMAT)?; + let offsetB = + b.0.iter() + .position(|x| x == offsetBTarget) + .ok_or(Exceptions::FORMAT)? as i32; + // let offsetB = std::min_element(b.begin(), b.end(), dist2A) - b.begin(); + + let a = a.rotated_corners(Some(offsetA), None); + let b = b.rotated_corners(Some(offsetB), None); + // a = RotatedCorners(a, offsetA); + // b = RotatedCorners(b, offsetB); + let tr = (RegressionLine::intersect( + &RegressionLine::with_two_points(a[0], a[1]), + &RegressionLine::with_two_points(b[1], b[2]), + ) + .ok_or(Exceptions::FORMAT)? + + RegressionLine::intersect( + &RegressionLine::with_two_points(a[3], a[2]), + &RegressionLine::with_two_points(b[0], b[3]), + ) + .ok_or(Exceptions::FORMAT)?) + / 2.0; + + // let tr = (intersect(RegressionLine(a[0], a[1]), RegressionLine(b[1], b[2])) + // + intersect(RegressionLine(a[3], a[2]), RegressionLine(b[0], b[3]))) + // / 2; + let bl = (RegressionLine::intersect( + &RegressionLine::with_two_points(a[0], a[3]), + &RegressionLine::with_two_points(b[2], b[3]), + ) + .ok_or(Exceptions::FORMAT)? + + RegressionLine::intersect( + &RegressionLine::with_two_points(a[1], a[2]), + &RegressionLine::with_two_points(b[0], b[1]), + ) + .ok_or(Exceptions::FORMAT)?) + / 2.0; + // let bl = (intersect(RegressionLine(a[0], a[3]), RegressionLine(b[2], b[3])) + // + intersect(RegressionLine(a[1], a[2]), RegressionLine(b[0], b[1]))) + // / 2; + + // log(tr, 2); + // log(bl, 2); + + Ok(Quadrilateral::from([tl, tr, br, bl])) + }; + + if let Some(found) = LocateAlignmentPattern( + image, + fp.size / 7, + bestPT.transform_point(Into::::into(dim) - point_f(3.0, 3.0)), + ) { + // if ( found ) { + // log(*found, 2); + if let Some(spQuad) = FindConcentricPatternCorners(image, found, fp.size / 2, 1) { + // if (auto spQuad = FindConcentricPatternCorners(image, *found, fp.size / 2, 1)) { + let mut dest = intersectQuads(&fpQuad, &spQuad)?; + if dim.y <= 9 { + bestPT = PerspectiveTransform::quadrilateralToQuadrilateral( + Quadrilateral::from([ + point(6.5, 0.5), + point(dim.x as f32 - 1.5, dim.y as f32 - 3.5), + point(dim.x as f32 - 1.5, dim.y as f32 - 1.5), + point(6.5, 6.5), + ]), + Quadrilateral::from([ + *fpQuad.top_right(), + *spQuad.top_right(), + *spQuad.bottom_right(), + *fpQuad.bottom_right(), + ]), + )?; + // bestPT = PerspectiveTransform({{6.5, 0.5}, {dim.x - 1.5, dim.y - 3.5}, {dim.x - 1.5, dim.y - 1.5}, {6.5, 6.5}}, + // {fpQuad->topRight(), spQuad->topRight(), spQuad->bottomRight(), fpQuad->bottomRight()}); + } else { + dest[0] = fp.p; + dest[2] = found; + bestPT = PerspectiveTransform::quadrilateralToQuadrilateral( + Quadrilateral::from([ + point(3.5, 3.5), + point(dim.x as f32 - 2.5, 3.5), + point(dim.x as f32 - 2.5, dim.y as f32 - 2.5), + point(3.5, dim.y as f32 - 2.5), + ]), + dest, + )?; + } + } + } + + let grid_sampler = DefaultGridSampler; + let (sample, rps) = grid_sampler.sample_grid( + image, + dim.x as u32, + dim.y as u32, + &[SamplerControl { + p1: point_i(dim.x, dim.y), + p0: point_i(0, 0), + transform: bestPT, + }], + )?; + Ok(QRCodeDetectorResult::new(sample, rps.to_vec())) + // SampleGrid(image, dim.x, dim.y, bestPT) +} diff --git a/src/qrcode/cpp_port/mod.rs b/src/qrcode/cpp_port/mod.rs index f18f038..8b9931e 100644 --- a/src/qrcode/cpp_port/mod.rs +++ b/src/qrcode/cpp_port/mod.rs @@ -7,5 +7,8 @@ pub use qr_cpp_reader::QrReader; mod bitmatrix_parser; +mod qr_type; +pub use qr_type::Type; + #[cfg(test)] mod test; diff --git a/src/qrcode/cpp_port/qr_cpp_reader.rs b/src/qrcode/cpp_port/qr_cpp_reader.rs index 6d711a2..bf72010 100644 --- a/src/qrcode/cpp_port/qr_cpp_reader.rs +++ b/src/qrcode/cpp_port/qr_cpp_reader.rs @@ -127,8 +127,8 @@ use crate::{ use super::{ decoder::Decode, detector::{ - DetectPureMQR, DetectPureQR, FindFinderPatterns, GenerateFinderPatternSets, SampleMQR, - SampleQR, + DetectPureMQR, DetectPureQR, DetectPureRMQR, FindFinderPatterns, GenerateFinderPatternSets, + SampleMQR, SampleQR, SampleRMQR, }, }; @@ -179,10 +179,15 @@ impl Reader for QrReader { if formats.contains(&BarcodeFormat::MICRO_QR_CODE) && detectorResult.is_err() { detectorResult = DetectPureMQR(binImg); } + if formats.contains(&BarcodeFormat::RECTANGULAR_MICRO_QR_CODE) + && detectorResult.is_err() + { + detectorResult = DetectPureRMQR(binImg); + } } if detectorResult.is_err() { - for decode_function in [DetectPureQR, DetectPureMQR] { + for decode_function in [DetectPureQR, DetectPureMQR, DetectPureRMQR] { detectorResult = decode_function(binImg); if detectorResult.is_ok() { break; @@ -208,25 +213,14 @@ impl Reader for QrReader { Ok(RXingResult::with_decoder_result( decoderResult, position, - if detectorResult.getBits().width() < 21 { + if detectorResult.getBits().width() != detectorResult.getBits().height() { + BarcodeFormat::RECTANGULAR_MICRO_QR_CODE + } else if detectorResult.getBits().width() < 21 { BarcodeFormat::MICRO_QR_CODE } else { BarcodeFormat::QR_CODE }, )) - - // Ok(RXingResult::new( - // &decoderResult.content().to_string(), - // decoderResult.content().bytes().to_vec(), - // position.to_vec(), - // if detectorResult.getBits().width() < 21 { - // BarcodeFormat::MICRO_QR_CODE - // } else { - // BarcodeFormat::QR_CODE - // }, - // )) - // return Result(std::move(decoderResult), std::move(position), - // detectorResult.bits().width() < 21 ? BarcodeFormat::MICRO_QR_CODE : BarcodeFormat::QR_CODE); } } @@ -276,16 +270,18 @@ impl QrReader { let mut usedFPs: Vec = Vec::new(); let mut results: Vec = Vec::new(); - let (check_qr, check_mqr) = if let Some(DecodeHintValue::PossibleFormats(formats)) = - hints.get(&DecodeHintType::POSSIBLE_FORMATS) - { - ( - formats.contains(&BarcodeFormat::QR_CODE), - formats.contains(&BarcodeFormat::MICRO_QR_CODE), - ) - } else { - (true, true) - }; + let (check_qr, check_mqr, check_rmqr) = + if let Some(DecodeHintValue::PossibleFormats(formats)) = + hints.get(&DecodeHintType::POSSIBLE_FORMATS) + { + ( + formats.contains(&BarcodeFormat::QR_CODE), + formats.contains(&BarcodeFormat::MICRO_QR_CODE), + formats.contains(&BarcodeFormat::RECTANGULAR_MICRO_QR_CODE), + ) + } else { + (true, true, true) + }; if check_qr { // if (_hints.hasFormat(BarcodeFormat::QRCode)) { @@ -314,18 +310,11 @@ impl QrReader { } if decoderResult.isValid() { - // results.push(RXingResult::new( - // &decoderResult.content().to_string(), - // decoderResult.content().bytes().to_vec(), - // position.to_vec(), - // BarcodeFormat::QR_CODE, - // )); results.push(RXingResult::with_decoder_result( decoderResult, position, BarcodeFormat::QR_CODE, )); - // results.emplace_back(std::move(decoderResult), std::move(position), BarcodeFormat::QR_CODE); if maxSymbols != 0 && (results.len() as u32) == maxSymbols { break; @@ -337,13 +326,13 @@ impl QrReader { } if check_mqr && !(maxSymbols != 0 && (results.len() as u32) == maxSymbols) { // if (_hints.hasFormat(BarcodeFormat::MicroQRCode) && !(maxSymbols && Size(results) == maxSymbols)) { - for fp in allFPs { + for fp in &allFPs { // for (const auto& fp : allFPs) { - if usedFPs.contains(&fp) { + if usedFPs.contains(fp) { continue; } - let detectorResult = SampleMQR(binImg, fp); + let detectorResult = SampleMQR(binImg, *fp); if let Ok(detectorResult) = detectorResult { // if (detectorResult.is_ok()) { let decoderResult = Decode(detectorResult.getBits()); @@ -355,13 +344,34 @@ impl QrReader { position, BarcodeFormat::MICRO_QR_CODE, )); - // results.push(RXingResult::new( - // &decoderResult.content().to_string(), - // decoderResult.content().bytes().to_vec(), - // position.to_vec(), - // BarcodeFormat::MICRO_QR_CODE, - // )); - // results.emplace_back(std::move(decoderResult), std::move(position), BarcodeFormat::MICRO_QR_CODE); + + if maxSymbols != 0 && (results.len() as u32) == maxSymbols { + break; + } + } + } + } + } + } + if check_rmqr && !(maxSymbols != 0 && (results.len() as u32) == maxSymbols) { + for fp in &allFPs { + // for (const auto& fp : allFPs) { + if usedFPs.contains(fp) { + continue; + } + + let detectorResult = SampleRMQR(binImg, *fp); + if let Ok(detectorResult) = detectorResult { + // if (detectorResult.is_ok()) { + let decoderResult = Decode(detectorResult.getBits()); + let position = detectorResult.getPoints(); + if let Ok(decoderResult) = decoderResult { + if decoderResult.isValid() { + results.push(RXingResult::with_decoder_result( + decoderResult, + position, + BarcodeFormat::RECTANGULAR_MICRO_QR_CODE, + )); if maxSymbols != 0 && (results.len() as u32) == maxSymbols { break; diff --git a/src/qrcode/cpp_port/qr_type.rs b/src/qrcode/cpp_port/qr_type.rs new file mode 100644 index 0000000..7988e16 --- /dev/null +++ b/src/qrcode/cpp_port/qr_type.rs @@ -0,0 +1,15 @@ +#[derive(Debug, Hash, PartialEq, Eq, Clone, Copy)] +pub enum Type { + Model1, + Model2, + Micro, + RectMicro, +} + +impl Type { + pub const fn const_eq(a: Type, b: Type) -> bool { + let (a, b) = (a as u8, b as u8); + + a == b + } +} diff --git a/src/qrcode/cpp_port/test/QRBitMatrixParserTest.rs b/src/qrcode/cpp_port/test/QRBitMatrixParserTest.rs index f6610e3..1c04e9a 100644 --- a/src/qrcode/cpp_port/test/QRBitMatrixParserTest.rs +++ b/src/qrcode/cpp_port/test/QRBitMatrixParserTest.rs @@ -33,10 +33,10 @@ XXX XX X X XXXX ) .expect("parse must parse"); - let version = ReadVersion(&bitMatrix).unwrap(); + let format = ReadFormatInformation(&bitMatrix).expect("could not read format information"); + let version = ReadVersion(&bitMatrix, format.qr_type()).expect("version found"); assert_eq!(3, version.getVersionNumber()); - let format = - ReadFormatInformation(&bitMatrix, true).expect("could not read format information"); + let codewords = ReadCodewords(&bitMatrix, version, &format).expect("could not read codewords"); assert_eq!(17, codewords.len()); assert_eq!(0x0, codewords[10]); @@ -67,10 +67,10 @@ X X XXXX XXX ) .unwrap(); - let version = ReadVersion(&bitMatrix).unwrap(); + let format = ReadFormatInformation(&bitMatrix).expect("could not read format information"); + let version = ReadVersion(&bitMatrix, format.qr_type()).expect("could not read version"); assert_eq!(3, version.getVersionNumber()); - let format = - ReadFormatInformation(&bitMatrix, true).expect("could not read format information"); + let codewords = ReadCodewords(&bitMatrix, version, &format).expect("could not read codewords"); assert_eq!(17, codewords.len()); assert_eq!(0x0, codewords[8]); diff --git a/src/qrcode/cpp_port/test/QRDecodedBitStreamParserTest.rs b/src/qrcode/cpp_port/test/QRDecodedBitStreamParserTest.rs index 68c19b1..2b5bc74 100644 --- a/src/qrcode/cpp_port/test/QRDecodedBitStreamParserTest.rs +++ b/src/qrcode/cpp_port/test/QRDecodedBitStreamParserTest.rs @@ -42,7 +42,7 @@ fn SimpleByteMode() { let bytes: Vec = ba.into(); let result = DecodeBitStream( &bytes, - Version::FromNumber(1, false).expect("find_version"), + Version::Model2(1).expect("find_version"), ErrorCorrectionLevel::M, ) .expect("Decode") @@ -62,14 +62,10 @@ fn SimpleSJIS() { ba.appendBits(0xA3, 8).expect("append"); ba.appendBits(0xD0, 8).expect("append"); let bytes: Vec = ba.into(); - let result = DecodeBitStream( - &bytes, - Version::FromNumber(1, false).unwrap(), - ErrorCorrectionLevel::M, - ) - .unwrap() - .content() - .to_string(); + let result = DecodeBitStream(&bytes, Version::Model2(1).unwrap(), ErrorCorrectionLevel::M) + .unwrap() + .content() + .to_string(); assert_eq!("\u{ff61}\u{ff62}\u{ff63}\u{ff90}", result); } @@ -84,14 +80,10 @@ fn ECI() { ba.appendBits(0xA2, 8).expect("append"); ba.appendBits(0xA3, 8).expect("append"); let bytes: Vec = ba.into(); - let result = DecodeBitStream( - &bytes, - Version::FromNumber(1, false).unwrap(), - ErrorCorrectionLevel::M, - ) - .unwrap() - .content() - .to_string(); + let result = DecodeBitStream(&bytes, Version::Model2(1).unwrap(), ErrorCorrectionLevel::M) + .unwrap() + .content() + .to_string(); assert_eq!("\u{ED}\u{F3}\u{FA}", result); } @@ -103,14 +95,10 @@ fn Hanzi() { ba.appendBits(0x01, 8).expect("append"); // 1 characters ba.appendBits(0x03C1, 13).expect("append"); let bytes: Vec = ba.into(); - let result = DecodeBitStream( - &bytes, - Version::FromNumber(1, false).unwrap(), - ErrorCorrectionLevel::M, - ) - .unwrap() - .content() - .to_string(); + let result = DecodeBitStream(&bytes, Version::Model2(1).unwrap(), ErrorCorrectionLevel::M) + .unwrap() + .content() + .to_string(); assert_eq!("\u{963f}", result); } @@ -125,20 +113,16 @@ fn HanziLevel1() { let bytes: Vec = ba.into(); - let result = DecodeBitStream( - &bytes, - Version::FromNumber(1, false).unwrap(), - ErrorCorrectionLevel::M, - ) - .unwrap() - .content() - .to_string(); + let result = DecodeBitStream(&bytes, Version::Model2(1).unwrap(), ErrorCorrectionLevel::M) + .unwrap() + .content() + .to_string(); assert_eq!("\u{30a2}", result); } #[test] fn SymbologyIdentifier() { - let version = Version::FromNumber(1, false).unwrap(); + let version = Version::Model2(1).unwrap(); let ecLevel = ErrorCorrectionLevel::M; // Plain "ANUM(1) A" diff --git a/src/qrcode/cpp_port/test/QRFormatInformationTest.rs b/src/qrcode/cpp_port/test/QRFormatInformationTest.rs index 67f326a..3177acc 100644 --- a/src/qrcode/cpp_port/test/QRFormatInformationTest.rs +++ b/src/qrcode/cpp_port/test/QRFormatInformationTest.rs @@ -4,7 +4,10 @@ */ // SPDX-License-Identifier: Apache-2.0 -use crate::qrcode::decoder::{ErrorCorrectionLevel, FormatInformation}; +use crate::qrcode::{ + cpp_port::Type, + decoder::{ErrorCorrectionLevel, FormatInformation}, +}; const MASKED_TEST_FORMAT_INFO: u32 = 0x2BED; const MASKED_TEST_FORMAT_INFO2: u32 = @@ -12,6 +15,13 @@ const MASKED_TEST_FORMAT_INFO2: u32 = const UNMASKED_TEST_FORMAT_INFO: u32 = MASKED_TEST_FORMAT_INFO ^ 0x5412; const MICRO_MASKED_TEST_FORMAT_INFO: u32 = 0x3BBA; // const MICRO_UNMASKED_TEST_FORMAT_INFO: u32 = MICRO_MASKED_TEST_FORMAT_INFO ^ 0x4445; +const RMQR_MASKED_TEST_FORMAT_INFO: u32 = 0x20137; +const RMQR_MASKED_TEST_FORMAT_INFO_SUB: u32 = 0x1F1FE; + +const FORMAT_INFO_MASK_QR_MODEL1: u32 = 0x2825; +const FORMAT_INFO_MASK_MICRO: u32 = 0x4445; +const FORMAT_INFO_MASK_RMQR: u32 = 0x1FAB2; // Finder pattern side +const FORMAT_INFO_MASK_RMQR_SUB: u32 = 0x20A7B; // Finder sub pattern side fn DoFormatInformationTest(formatInfo: u32, expectedMask: u8, expectedECL: ErrorCorrectionLevel) { let parsedFormat = FormatInformation::DecodeMQR(formatInfo); @@ -20,6 +30,27 @@ fn DoFormatInformationTest(formatInfo: u32, expectedMask: u8, expectedECL: Error assert_eq!(expectedECL, parsedFormat.error_correction_level); } +// Helper for rMQR to unset `numBits` number of bits +fn RMQRUnsetBits(formatInfoBits: u32, numBits: u32) -> u32 { + let mut formatInfoBits = formatInfoBits; + let mut numBits = numBits as i32; + for i in 0..18 { + // for (int i = 0; i < 18 && numBits; i++) { + if (formatInfoBits & (1 << i)) != 0 { + formatInfoBits ^= 1 << i; + numBits -= 1; + } + if numBits == 0 { + break; + } + } + formatInfoBits +} + +fn cpp_eq(rhs: &FormatInformation, lhs: &FormatInformation) { + assert!(rhs.cpp_eq(lhs)) +} + #[test] fn Decode() { // Normal case @@ -63,11 +94,12 @@ fn DecodeWithBitDifference() { MASKED_TEST_FORMAT_INFO2 ^ 0x07, ), ); - assert!(!FormatInformation::DecodeQR( + let unexpected = FormatInformation::DecodeQR( MASKED_TEST_FORMAT_INFO ^ 0x0F, - MASKED_TEST_FORMAT_INFO2 ^ 0x0F - ) - .isValid()); + MASKED_TEST_FORMAT_INFO2 ^ 0x0F, + ); + assert!(!&expected.cpp_eq(&unexpected)); + assert!(!(unexpected.isValid() && unexpected.qr_type() == Type::Model2)); } #[test] @@ -127,6 +159,85 @@ fn DecodeMicroWithBitDifference() { // FormatInformation::DecodeFormatInformation(MICRO_MASKED_TEST_FORMAT_INFO ^ 0x3f).errorCorrectionLevel()); } -fn cpp_eq(rhs: &FormatInformation, lhs: &FormatInformation) { - assert!(rhs.cpp_eq(lhs)) +#[test] +fn DecodeRMQR() { + // Normal case + let expected = FormatInformation::DecodeRMQR( + RMQR_MASKED_TEST_FORMAT_INFO, + RMQR_MASKED_TEST_FORMAT_INFO_SUB, + ); + assert!(expected.isValid()); + assert_eq!(4, expected.data_mask); + assert_eq!(ErrorCorrectionLevel::H, expected.error_correction_level); + assert_eq!(FORMAT_INFO_MASK_RMQR, expected.mask); + // Not catered for: where the code forgot the mask! +} + +#[test] +fn DecodeRMQRWithBitDifference() { + let expected = FormatInformation::DecodeRMQR( + RMQR_MASKED_TEST_FORMAT_INFO, + RMQR_MASKED_TEST_FORMAT_INFO_SUB, + ); + assert_eq!(expected.error_correction_level, ErrorCorrectionLevel::H); + // 1,2,3,4,5 bits difference + cpp_eq( + &expected, + &FormatInformation::DecodeRMQR( + RMQRUnsetBits(RMQR_MASKED_TEST_FORMAT_INFO, 1), + RMQRUnsetBits(RMQR_MASKED_TEST_FORMAT_INFO_SUB, 1), + ), + ); + cpp_eq( + &expected, + &FormatInformation::DecodeRMQR( + RMQRUnsetBits(RMQR_MASKED_TEST_FORMAT_INFO, 2), + RMQRUnsetBits(RMQR_MASKED_TEST_FORMAT_INFO_SUB, 2), + ), + ); + cpp_eq( + &expected, + &FormatInformation::DecodeRMQR( + RMQRUnsetBits(RMQR_MASKED_TEST_FORMAT_INFO, 3), + RMQRUnsetBits(RMQR_MASKED_TEST_FORMAT_INFO_SUB, 3), + ), + ); + cpp_eq( + &expected, + &FormatInformation::DecodeRMQR( + RMQRUnsetBits(RMQR_MASKED_TEST_FORMAT_INFO, 4), + RMQRUnsetBits(RMQR_MASKED_TEST_FORMAT_INFO_SUB, 4), + ), + ); + let unexpected = FormatInformation::DecodeRMQR( + RMQRUnsetBits(RMQR_MASKED_TEST_FORMAT_INFO, 5), + RMQRUnsetBits(RMQR_MASKED_TEST_FORMAT_INFO_SUB, 5), + ); + assert!(!(expected == unexpected)); + assert!(!(unexpected.isValid())); + assert!(unexpected.qr_type() == Type::RectMicro); // Note `mask` (used to determine type) set regardless +} + +#[test] +fn DecodeRMQRWithMisread() { + let expected = FormatInformation::DecodeRMQR( + RMQR_MASKED_TEST_FORMAT_INFO, + RMQR_MASKED_TEST_FORMAT_INFO_SUB, + ); + { + let actual = FormatInformation::DecodeRMQR( + RMQRUnsetBits(RMQR_MASKED_TEST_FORMAT_INFO, 2), + RMQRUnsetBits(RMQR_MASKED_TEST_FORMAT_INFO_SUB, 4), + ); + cpp_eq(&expected, &actual); + assert_eq!(actual.mask, FORMAT_INFO_MASK_RMQR); + } + { + let actual = FormatInformation::DecodeRMQR( + RMQRUnsetBits(RMQR_MASKED_TEST_FORMAT_INFO, 5), + RMQRUnsetBits(RMQR_MASKED_TEST_FORMAT_INFO_SUB, 4), + ); + cpp_eq(&expected, &actual); + assert_eq!(actual.mask, FORMAT_INFO_MASK_RMQR_SUB); + } } diff --git a/src/qrcode/cpp_port/test/QRModeTest.rs b/src/qrcode/cpp_port/test/QRModeTest.rs index fa356a0..52ccb7c 100644 --- a/src/qrcode/cpp_port/test/QRModeTest.rs +++ b/src/qrcode/cpp_port/test/QRModeTest.rs @@ -4,22 +4,34 @@ */ // SPDX-License-Identifier: Apache-2.0 -use crate::qrcode::decoder::{Mode, Version}; +use crate::qrcode::{ + cpp_port::Type, + decoder::{Mode, Version}, +}; #[test] fn ForBits() { assert_eq!( Mode::TERMINATOR, - Mode::CodecModeForBits(0x00, None).unwrap() + Mode::CodecModeForBits(0x00, Some(Type::Model2)).unwrap() + ); + assert_eq!( + Mode::NUMERIC, + Mode::CodecModeForBits(0x01, Some(Type::Model2)).unwrap() ); - assert_eq!(Mode::NUMERIC, Mode::CodecModeForBits(0x01, None).unwrap()); assert_eq!( Mode::ALPHANUMERIC, - Mode::CodecModeForBits(0x02, None).unwrap() + Mode::CodecModeForBits(0x02, Some(Type::Model2)).unwrap() ); - assert_eq!(Mode::BYTE, Mode::CodecModeForBits(0x04, None).unwrap()); - assert_eq!(Mode::KANJI, Mode::CodecModeForBits(0x08, None).unwrap()); - assert!(Mode::CodecModeForBits(0x10, None).is_err()); + assert_eq!( + Mode::BYTE, + Mode::CodecModeForBits(0x04, Some(Type::Model2)).unwrap() + ); + assert_eq!( + Mode::KANJI, + Mode::CodecModeForBits(0x08, Some(Type::Model2)).unwrap() + ); + assert!(Mode::CodecModeForBits(0x10, Some(Type::Model2)).is_err()); } #[test] @@ -27,27 +39,27 @@ fn CharacterCount() { // Spot check a few values assert_eq!( 10, - Mode::CharacterCountBits(&Mode::NUMERIC, Version::FromNumber(5, false).unwrap()) + Mode::CharacterCountBits(&Mode::NUMERIC, Version::Model2(5).unwrap()) ); assert_eq!( 12, - Mode::CharacterCountBits(&Mode::NUMERIC, Version::FromNumber(26, false).unwrap()) + Mode::CharacterCountBits(&Mode::NUMERIC, Version::Model2(26).unwrap()) ); assert_eq!( 14, - Mode::CharacterCountBits(&Mode::NUMERIC, Version::FromNumber(40, false).unwrap()) + Mode::CharacterCountBits(&Mode::NUMERIC, Version::Model2(40).unwrap()) ); assert_eq!( 9, - Mode::CharacterCountBits(&Mode::ALPHANUMERIC, Version::FromNumber(6, false).unwrap()) + Mode::CharacterCountBits(&Mode::ALPHANUMERIC, Version::Model2(6).unwrap()) ); assert_eq!( 8, - Mode::CharacterCountBits(&Mode::BYTE, Version::FromNumber(7, false).unwrap()) + Mode::CharacterCountBits(&Mode::BYTE, Version::Model2(7).unwrap()) ); assert_eq!( 8, - Mode::CharacterCountBits(&Mode::KANJI, Version::FromNumber(8, false).unwrap()) + Mode::CharacterCountBits(&Mode::KANJI, Version::Model2(8).unwrap()) ); } @@ -56,53 +68,53 @@ fn MicroForBits() { // M1 assert_eq!( Mode::NUMERIC, - Mode::CodecModeForBits(0x00, Some(true)).unwrap() + Mode::CodecModeForBits(0x00, Some(Type::Micro)).unwrap() ); // M2 assert_eq!( Mode::NUMERIC, - Mode::CodecModeForBits(0x00, Some(true)).unwrap() + Mode::CodecModeForBits(0x00, Some(Type::Micro)).unwrap() ); assert_eq!( Mode::ALPHANUMERIC, - Mode::CodecModeForBits(0x01, Some(true)).unwrap() + Mode::CodecModeForBits(0x01, Some(Type::Micro)).unwrap() ); // M3 assert_eq!( Mode::NUMERIC, - Mode::CodecModeForBits(0x00, Some(true)).unwrap() + Mode::CodecModeForBits(0x00, Some(Type::Micro)).unwrap() ); assert_eq!( Mode::ALPHANUMERIC, - Mode::CodecModeForBits(0x01, Some(true)).unwrap() + Mode::CodecModeForBits(0x01, Some(Type::Micro)).unwrap() ); assert_eq!( Mode::BYTE, - Mode::CodecModeForBits(0x02, Some(true)).unwrap() + Mode::CodecModeForBits(0x02, Some(Type::Micro)).unwrap() ); assert_eq!( Mode::KANJI, - Mode::CodecModeForBits(0x03, Some(true)).unwrap() + Mode::CodecModeForBits(0x03, Some(Type::Micro)).unwrap() ); // M4 assert_eq!( Mode::NUMERIC, - Mode::CodecModeForBits(0x00, Some(true)).unwrap() + Mode::CodecModeForBits(0x00, Some(Type::Micro)).unwrap() ); assert_eq!( Mode::ALPHANUMERIC, - Mode::CodecModeForBits(0x01, Some(true)).unwrap() + Mode::CodecModeForBits(0x01, Some(Type::Micro)).unwrap() ); assert_eq!( Mode::BYTE, - Mode::CodecModeForBits(0x02, Some(true)).unwrap() + Mode::CodecModeForBits(0x02, Some(Type::Micro)).unwrap() ); assert_eq!( Mode::KANJI, - Mode::CodecModeForBits(0x03, Some(true)).unwrap() + Mode::CodecModeForBits(0x03, Some(Type::Micro)).unwrap() ); - assert!(Mode::CodecModeForBits(0x04, Some(true)).is_err()); + assert!(Mode::CodecModeForBits(0x04, Some(Type::Micro)).is_err()); } #[test] @@ -110,26 +122,110 @@ fn MicroCharacterCount() { // Spot check a few values assert_eq!( 3, - Mode::CharacterCountBits(&Mode::NUMERIC, Version::FromNumber(1, true).unwrap()) + Mode::CharacterCountBits(&Mode::NUMERIC, Version::Micro(1).unwrap()) ); assert_eq!( 4, - Mode::CharacterCountBits(&Mode::NUMERIC, Version::FromNumber(2, true).unwrap()) + Mode::CharacterCountBits(&Mode::NUMERIC, Version::Micro(2).unwrap()) ); assert_eq!( 6, - Mode::CharacterCountBits(&Mode::NUMERIC, Version::FromNumber(4, true).unwrap()) + Mode::CharacterCountBits(&Mode::NUMERIC, Version::Micro(4).unwrap()) ); assert_eq!( 3, - Mode::CharacterCountBits(&Mode::ALPHANUMERIC, Version::FromNumber(2, true).unwrap()) + Mode::CharacterCountBits(&Mode::ALPHANUMERIC, Version::Micro(2).unwrap()) ); assert_eq!( 4, - Mode::CharacterCountBits(&Mode::BYTE, Version::FromNumber(3, true).unwrap()) + Mode::CharacterCountBits(&Mode::BYTE, Version::Micro(3).unwrap()) ); assert_eq!( 4, - Mode::CharacterCountBits(&Mode::KANJI, Version::FromNumber(4, true).unwrap()) + Mode::CharacterCountBits(&Mode::KANJI, Version::Micro(4).unwrap()) + ); +} + +#[test] +fn RMQRForBits() { + assert_eq!( + Mode::TERMINATOR, + Mode::CodecModeForBits(0x00, Some(Type::RectMicro)).expect("could not decode 0x00") + ); + assert_eq!( + Mode::NUMERIC, + Mode::CodecModeForBits(0x01, Some(Type::RectMicro)).expect("could not decode 0x01") + ); + assert_eq!( + Mode::ALPHANUMERIC, + Mode::CodecModeForBits(0x02, Some(Type::RectMicro)).expect("could not decode 0x02") + ); + assert_eq!( + Mode::BYTE, + Mode::CodecModeForBits(0x03, Some(Type::RectMicro)).expect("could not decode 0x03") + ); + assert_eq!( + Mode::KANJI, + Mode::CodecModeForBits(0x04, Some(Type::RectMicro)).expect("could not decode 0x04") + ); + assert_eq!( + Mode::FNC1_FIRST_POSITION, + Mode::CodecModeForBits(0x05, Some(Type::RectMicro)).expect("could not decode 0x05") + ); + assert_eq!( + Mode::FNC1_SECOND_POSITION, + Mode::CodecModeForBits(0x06, Some(Type::RectMicro)).expect("could not decode 0x06") + ); + assert_eq!( + Mode::ECI, + Mode::CodecModeForBits(0x07, Some(Type::RectMicro)).expect("could not decode 0x07") + ); + assert!(Mode::CodecModeForBits(0x08, Some(Type::RectMicro)).is_err()); +} + +#[test] +fn RMQRCharacterCount() { + // Spot check a few values + assert_eq!( + 7, + Mode::CharacterCountBits( + &Mode::NUMERIC, + Version::rMQR(5).expect("should return version") + ) + ); + assert_eq!( + 8, + Mode::CharacterCountBits( + &Mode::NUMERIC, + Version::rMQR(26).expect("should return version") + ) + ); + assert_eq!( + 9, + Mode::CharacterCountBits( + &Mode::NUMERIC, + Version::rMQR(32).expect("should return version") + ) + ); + assert_eq!( + 5, + Mode::CharacterCountBits( + &Mode::ALPHANUMERIC, + Version::rMQR(6).expect("should return version") + ) + ); + assert_eq!( + 5, + Mode::CharacterCountBits( + &Mode::BYTE, + Version::rMQR(7).expect("should return version") + ) + ); + assert_eq!( + 5, + Mode::CharacterCountBits( + &Mode::KANJI, + Version::rMQR(8).expect("should return version") + ) ); } diff --git a/src/qrcode/cpp_port/test/QRVersionTest.rs b/src/qrcode/cpp_port/test/QRVersionTest.rs index 6decf1b..69f84b4 100644 --- a/src/qrcode/cpp_port/test/QRVersionTest.rs +++ b/src/qrcode/cpp_port/test/QRVersionTest.rs @@ -6,13 +6,16 @@ use crate::{ common::BitMatrix, - qrcode::decoder::{Version, VersionRef}, + qrcode::{ + cpp_port::Type, + decoder::{Version, VersionRef}, + }, }; fn CheckVersion(version: VersionRef, number: u32, dimension: u32) { // assert_ne!(version, nullptr); assert_eq!(number, version.getVersionNumber()); - if number > 1 && !version.isMicroQRCode() { + if number > 1 && version.isModel2() { assert!(!version.getAlignmentPatternCenters().is_empty()); } assert_eq!(dimension, version.getDimensionForVersion()); @@ -26,13 +29,13 @@ fn DoTestVersion(expectedVersion: u32, mask: i32) { #[test] fn VersionForNumber() { - let version = Version::FromNumber(0, false); + let version = Version::Model2(0); assert!(version.is_err(), "There is version with number 0"); for i in 1..=40 { // for (int i = 1; i <= 40; i++) { CheckVersion( - Version::FromNumber(i, false).expect("version number found"), + Version::Model2(i).expect("version number found"), i, 4 * i + 17, ); @@ -43,10 +46,13 @@ fn VersionForNumber() { fn GetProvisionalVersionForDimension() { for i in 1..=40 { // for (int i = 1; i <= 40; i++) { - let prov = Version::FromDimension(4 * i + 17) - .unwrap_or_else(|_| panic!("version should exist for {i}")); // assert_ne!(prov, nullptr); - assert_eq!(i, prov.getVersionNumber()); + assert_eq!( + i, + Version::Number( + &BitMatrix::with_single_dimension(4 * i + 17).expect("must create bitmatrix") + ) + ); } } @@ -63,13 +69,13 @@ fn DecodeVersionInformation() { #[test] fn MicroVersionForNumber() { - let version = Version::FromNumber(0, true); + let version = Version::Micro(0); assert!(version.is_err(), "There is version with number 0"); for i in 1..=4 { // for (int i = 1; i <= 4; i++) { CheckVersion( - Version::FromNumber(i, true).unwrap_or_else(|_| panic!("version for {i} should exist")), + Version::Micro(i).unwrap_or_else(|_| panic!("version for {i} should exist")), i, 2 * i + 9, ); @@ -80,10 +86,12 @@ fn MicroVersionForNumber() { fn GetProvisionalMicroVersionForDimension() { for i in 1..=4 { // for (int i = 1; i <= 4; i++) { - let prov = Version::FromDimension(2 * i + 9) - .unwrap_or_else(|_| panic!("version for micro {i} should exist")); - // assert_ne!(prov, nullptr); - assert_eq!(i, prov.getVersionNumber()); + assert_eq!( + i, + Version::Number( + &BitMatrix::with_single_dimension(2 * i + 9).expect("must create bitmatrix") + ) + ); } } @@ -100,7 +108,7 @@ fn FunctionPattern() { }; for i in 1..=4 { // for (int i = 1; i <= 4; i++) { - let version = Version::FromNumber(i, true).expect("version must be found"); + let version = Version::Micro(i).expect("version must be found"); let functionPattern = version .buildFunctionPattern() .expect("function pattern must be found"); @@ -120,3 +128,130 @@ fn FunctionPattern() { } } } + +fn CheckRMQRVersion(version: VersionRef, number: u32) { + assert_eq!(number, version.getVersionNumber()); + assert_eq!( + Version::SymbolSize(number, Type::RectMicro).x == 27, + version.getAlignmentPatternCenters().is_empty() + ); +} + +#[test] +fn RMQRVersionForNumber() { + let version = Version::rMQR(0); + assert!(version.is_err(), "There is version with number 0"); + + for i in 1..=32 { + // for (int i = 1; i <= 32; i++) { + CheckRMQRVersion(Version::rMQR(i).expect("version {i} should exist"), i); + } +} + +#[test] +fn RMQRFunctionPattern1() { + { + let expected = BitMatrix::parse_strings( + r"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +XXXXXXXXXXXX XXX XXXXXXXX +XXXXXXXXXXXX XXX XXXXXXXX +XXXXXXXXXXXX X XXXXXXXX +XXXXXXXXXXX XXX XXXXXXXX +XXXXXXXXXXX XXX XXXXXXXX +XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +", + "X", + " ", + ) + .unwrap(); + let version = Version::rMQR(1).unwrap(); // R7x43 + let functionPattern = version.buildFunctionPattern().unwrap(); + assert_eq!(expected, functionPattern); + } + { + let expected = BitMatrix::parse_strings( + r"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +XXXXXXXXXXXX XXX XX +XXXXXXXXXXXX XXX X +XXXXXXXXXXXX X XXXXXX X +XXXXXXXXXXX X XXXXXXXX +XXXXXXXXXXX X XXXXXXXX +XXXXXXXX XXX XXXXXXXX +XXXXXXXX XXX XXXXXXXX +XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +", + "X", + " ", + ) + .unwrap(); + let version = Version::rMQR(6).unwrap(); // R9x43 + let functionPattern = version.buildFunctionPattern().unwrap(); + assert_eq!(expected, functionPattern); + } + { + let expected = BitMatrix::parse_strings( + r"XXXXXXXXXXXXXXXXXXXXXXXXXXX +XXXXXXXXXXXX XX +XXXXXXXXXXXX X +XXXXXXXXXXXX X +XXXXXXXXXXX X +XXXXXXXXXXX XXXXXX X +XXXXXXXX XXXXXXXX +XXXXXXXX XXXXXXXX +X XXXXXXXX +XX XXXXXXXX +XXXXXXXXXXXXXXXXXXXXXXXXXXX +", + "X", + " ", + ) + .unwrap(); + let version = Version::rMQR(11).unwrap(); // R11x27 + let functionPattern = version.buildFunctionPattern().unwrap(); + assert_eq!(expected, functionPattern); + } + { + let expected = BitMatrix::parse_strings( + r"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +XXXXXXXXXXXX XXX XX +XXXXXXXXXXXX XXX X +XXXXXXXXXXXX X X +XXXXXXXXXXX X X +XXXXXXXXXXX X XXXXXX X +XXXXXXXX X XXXXXXXX +XXXXXXXX X XXXXXXXX +X XXX XXXXXXXX +XX XXX XXXXXXXX +XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +", + "X", + " ", + ) + .unwrap(); + let version = Version::rMQR(12).unwrap(); // R11x43 + let functionPattern = version.buildFunctionPattern().unwrap(); + assert_eq!(expected, functionPattern); + } + { + let expected = BitMatrix::parse_strings( + "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +XXXXXXXXXXXX XXX XXX XX +XXXXXXXXXXXX XXX XXX X +XXXXXXXXXXXX X X X +XXXXXXXXXXX X X X +XXXXXXXXXXX X X XXXXXX X +XXXXXXXX X X XXXXXXXX +XXXXXXXX X X XXXXXXXX +X XXX XXX XXXXXXXX +XX XXX XXX XXXXXXXX +XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +", + "X", + " ", + ) + .unwrap(); + let version = Version::rMQR(13).unwrap(); // R11x59 + let functionPattern = version.buildFunctionPattern().unwrap(); + assert_eq!(expected, functionPattern); + } +} diff --git a/src/qrcode/cpp_port/test/RMQRDecoderTest.rs b/src/qrcode/cpp_port/test/RMQRDecoderTest.rs new file mode 100644 index 0000000..ad88dac --- /dev/null +++ b/src/qrcode/cpp_port/test/RMQRDecoderTest.rs @@ -0,0 +1,250 @@ +/* + * Copyright 2023 gitlost +*/ +// SPDX-License-Identifier: Apache-2.0 + +use crate::{ + common::{BitMatrix, Eci}, + qrcode::cpp_port::decoder::Decode, + Exceptions, +}; + +#[test] +fn RMQRCodeR7x43M() { + let bitMatrix = BitMatrix::parse_strings( + r"XXXXXXX X X X X X X XXX X X X X X X X X XXX +X X X XXX XXXXX XXX X X XX X X +X XXX X X XXX X X X XXXX XXXX X X XXXXXXXX +X XXX X XX XXXXX XXXXXX X X X X +X XXX X XX XXX XXXXXXX X X XX X X X +X X XXXXX XXX XXX XXXXX XXXXXX X X +XXXXXXX X X X X X X XXX X X X X X X X XXXXX +", + "X", + " ", + ) + .unwrap(); + + let result = Decode(&bitMatrix).unwrap(); + // assert!(result.isValid()); + + assert_eq!(result.text(), "ABCDEFG"); +} + +#[test] +fn RMQRCodeR7x43MError6Bits() { + let bitMatrix = BitMatrix::parse_strings( + r"XXXXXXX X X X X X X XXX X X X X X X X X XXX +X X X XXX XXXXX XXX X X XX X X +X XXX X X XXX X X XXXX XXXX XX X XXXXXXXX +X XXX X XX XXXXX X XXXXXX X X X X +X XXX X XX XXX XXXXXXX X X XXX X X X +X X XXXXX XXX XXX XXXX X XXXXXX X X +XXXXXXX X X X X X X XXX X X X X X X X XXXXX +", + "X", + " ", + ) + .unwrap(); + + let result = Decode(&bitMatrix); + + assert!(matches!( + result.err(), + Some(Exceptions::ReedSolomonException(_)) + )); + // assert_eq!(Error::Checksum, result.error()); + // assert!(result.text().empty()); + // assert!(result.content().text(TextMode::Plain).empty()); +} + +#[test] +fn RMQRCodeR7x139H() { + let bitMatrix = BitMatrix::parse_strings( +r"XXXXXXX X X X X X X X X X XXX X X X X X X X X X X X X XXX X X X X X X X X X X X X XXX X X X X X X X X X X X X XXX X X X X X X X X X X X XXX +X X XX XXX X X X X X XX XX X X X XXX XX XXXX XXX XX XX XX X XX X X X XXX X XX XX XX X X XX X XX XXXX X X X +X XXX X X XXXXX X XXXXX X X XXX XX X XXX X XX XXX XX X XXX X X XXXX X XXXXXXX X XX XXX X X X XXX X XXXXX +X XXX X XXXX X XX X X XX XX X XX XX X XXX XX X XX X XX X X XX X X XXX X X X X X X X XX X XX XX X X X +X XXX X XXXX XXXXX X X XXXXXX XX X XXXX X XXXX X XXX XXXX X XXXXXXX XXX XXXXXX X X XX X XXX X XXXXXXXXX X XXXX X X X X X +X X X XX XX X X XX X X X XXXX X X X XX X XXX X X X X X XXX XX XXX X X XX XXXX XX X X X X XXXXX XXX XX X XX X +XXXXXXX X X X X X X X X X XXX X X X X X X X X X X X X XXX X X X X X X X X X X X X XXX X X X X X X X X X X X X XXX X X X X X X X X X X XXXXX +", +"X", +" ", +) +.unwrap(); + + let result = Decode(&bitMatrix).unwrap(); + // assert!(result.isValid()); + assert_eq!(result.text(), "1234567890,ABCDEFGHIJKLMOPQRSTUVW"); +} + +#[test] +fn RMQRCodeR9x59H() { + let bitMatrix = BitMatrix::parse_strings( + r"XXXXXXX X X X X X XXX X X X X X X X X XXX X X X X X X X XXX +X X X XXXXX XXX X X XXXXXXXX X X X X XXXX X X +X XXX X XX XXX X XXX XXXX X XXXXXXX X XXXXX X X +X XXX X XXXX X XX X XX XXXX XX XX X X X XXX X +X XXX X X X XX XXXXXX X X XX X XX X X XXXX XXXXX +X X X X X X XXX X X X XX X XXXX XX X X X X +XXXXXXX XXXXX XXXXXX X XX XXX X XXXX X X X XX X X + XXX XXXX XX XXX X XXXXXXX X XX XXX XX XX X +XXX X X X X X X X XXX X X X X X X X X XXX X X X X X X XXXXX +", + "X", + " ", + ) + .unwrap(); + + let result = Decode(&bitMatrix).unwrap(); + // assert!(result.isValid()); + assert_eq!(result.text(), "ABCDEFGHIJKLMN"); +} + +#[test] +fn RMQRCodeR9x77M() { + let bitMatrix = BitMatrix::parse_strings( + r"XXXXXXX X X X X X X X X XXX X X X X X X X X X X X XXX X X X X X X X X X X XXX +X X XXX XX XXX XXX XXXX XXX XX X XXXXXXXXX X XXX XXXX X XXXX XX XXX X +X XXX X X X X XXX X XXXX XX XX X XX XX XXX XXXX X X XX X X XX X +X XXX X X X XXXXXX X XX XXXX X XXX X XX X XX XX XX X XXX X X XXX XX +X XXX X XXXX X X XXXX XXXX XX XXX X XX XXXXXX X X XXX XX XXXXX +X X X X XX XXX X X XX X X XX XXX X X X X X XX XXXXX X +XXXXXXX X XX XX X XXXX X X X X X XX XXX X XX X XXX XX X X + X XXXXX XX X XXXXXX XX XXXXX X XX XX XXXXX XXX X +XXX X X X X X X X X X X XXX X X X X X X X X X X X XXX X X X X X X X X X XXXXX +", + "X", + " ", + ) + .unwrap(); + + let result = Decode(&bitMatrix).unwrap(); + // assert!(result.isValid()); + assert_eq!(result.text(), "__ABCDEFGH__1234567890___ABCDEFGHIJK"); +} + +#[test] +fn RMQRCodeR11x27H() { + let bitMatrix = BitMatrix::parse_strings( + r"XXXXXXX X X X X X X X X XXX +X X XX X X X X +X XXX X X XX X X XX +X XXX X XXXX XX X XXXXXX +X XXX X X X XX XX XXX X +X X XXX X XX XXXX X +XXXXXXX X XX X XXXXX + X X X X X +XXXX X X X XX XXXXXX X X +X XX XXXXXX XXX XXXX X X +XXX X X X X X X X X X XXXXX +", + "X", + " ", + ) + .unwrap(); + + let result = Decode(&bitMatrix).unwrap(); + // assert!(result.isValid()); + assert_eq!(result.text(), "ABCDEF"); +} + +#[test] +fn RMQRCodeR13x27M_ECI() { + let bitMatrix = BitMatrix::parse_strings( + r"XXXXXXX X X X X X X X X XXX +X X XX XX XXX XX X +X XXX X XX X XX XX XXX X +X XXX X XX X XX X X XX +X XXX X XXXXXXX X X XX +X X XX X XXX XX XX +XXXXXXX X X X X XXX + XXX XX X XX XXX +XXX XX XX X X XX XX XXXXX + XXX X X X X X X +X XX X X XX X XX X X X X +X X X X X X X X X +XXX X X X X X X X X X XXXXX +", + "X", + " ", + ) + .unwrap(); + + let result = Decode(&bitMatrix).unwrap(); + // assert!(result.isValid()); + assert_eq!(result.text(), "AB貫12345AB"); + assert!(result.content().has_eci); + assert_eq!(result.content().eci_positions[0].0, Eci::Shift_JIS); + // assert_eq!(result.symbologyIdentifier(), "]Q2"); // Shouldn't this be Q1 TODO: Fix +} + +#[test] +fn RMQRCodeR15x59H_GS1() { + let bitMatrix = BitMatrix::parse_strings( + r"XXXXXXX X X X X X XXX X X X X X X X X XXX X X X X X X X XXX +X X XXX XXX X XXXXX XX XXX X X X X X X XXX X +X XXX X XXX XX X XXX XXX X X XXX XXXXX XX XXX XX +X XXX X X X XX X X XXX X X X XXXXX XX XXX +X XXX X XX XXX XX X X X XX XX XX XXX XXXX X XXXX +X X X X X X X XXX XXX XXXX X XXX XX X X +XXXXXXX X XXX XXXX X XX XXXX X X XX XXX XXXXX X + X XXX X XXXXX X XX XXXX XX X +XX XX X X X XXXXX XX X X XX XX X XX X X XX X + XX XX X XXXXXX XXX XX X X XX XXX X X XXX +X X XX XXXXXXXXXX XX X X XX XX XX X XXXX XX XXXXXX + XX X XX X XXX X X X XXX X XXX X X XXX XXXX X +XXXX X X XX XXX X X X XX XXXXX XX X XX XXX X X +X X X XX XXX XXXXXXX XXX X XXX XX X X X XX X +XXX X X X X X X X XXX X X X X X X X X XXX X X X X X X XXXXX +", + "X", + " ", + ) + .unwrap(); + + let _result = Decode(&bitMatrix).unwrap(); + // assert!(result.isValid()); + // assert!(result.content().type() == ContentType::GS1); + // assert_eq!( + // result.text(), + // "(01)09524000059109(21)12345678p901(10)1234567p(17)231120" + // ); + // TODO: Right now we aren't properly handling the parsing of this, but we can just check that + // the data comes back as valid, it's not perfect, but it works ok. +} + +#[test] +fn RMQRCodeR17x99H() { + let bitMatrix = BitMatrix::parse_strings( +r"XXXXXXX X X X X X X X XXX X X X X X X X X X X X XXX X X X X X X X X X X X XXX X X X X X X X X X XXX +X X X XXXXX XXX X X X XX X X XX XXXXX X XX X XX XXX X X XX X X XXX X X XX X X X +X XXX X X X XXX XXX X XXX XXX X X XX XXXX X X X X XXX XXXXX X X XX X XX X X +X XXX X XX X XX X X XX X XXXX X XXXXX X X XX X XXX XX X X X X XXXXXX X +X XXX X X XX X X X X X X X X XXX XX XXXXXX X X XXX X XXXXXX X X X X X X X XX X +X X XX X X XXXXX XX X XXX X XX X X XXX X XXX XXX X XXXX XX X X X XX XXXX +XXXXXXX X XX X XX X X XXX XX X XXXX X X XXX X X XX X XXXX XX X X X XX X XXXX + XX XX XX XX X XX X X X XXX XX X X XXX XXXX XX X X X X XX XX XXX +XX X XXX X X XXXX XXX XXXXX XXX XXX X X X X X XXX X XX XX X X X X XX X XXX + X XXXXX X X XXXXX X XX X XX XXXX X X XXXXX X XX X XX X XX X XX XX +X XX XX X XX XXX XX XXXXXX X XXXXX XX XXXX X X X X XXXX XX X X XXXXXX XX X X + XXX XX XXX XX XX X X X XX X X X X XX XXX XXXX X XX XXX X X X XXXX XXXXX X XXX +X X XX X XX XX XX X X XX X X X XX XXXXXXXX X XX XX X X X X X XX X X XXXXXXXXXXX + X X X XX X X X XX XXXX X XXX X XX X X X X X XXX XXXXX XX X X X XXXXX X X X +XXXX XX XX X XXXX XXXX X XX X XX XX XX XXXX XXX X X XX XX X XXXX X XXX XX X XX X X +X XXX XX XXX X X X XXX X XXX X XXXX XX X X XXXXX X XX X X X X X X X X XXXX XXXX X +XXX X X X X X X X X X XXX X X X X X X X X X X X XXX X X X X X X X X X X X XXX X X X X X X X X XXXXX +", +"X", +" ", +) +.unwrap(); + + let result = Decode(&bitMatrix).unwrap(); + // assert!(result.isValid()); + assert_eq!( + result.text(), + "1234567890ABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890________________________" + ); +} diff --git a/src/qrcode/cpp_port/test/mod.rs b/src/qrcode/cpp_port/test/mod.rs index 4dd3017..4df88c0 100644 --- a/src/qrcode/cpp_port/test/mod.rs +++ b/src/qrcode/cpp_port/test/mod.rs @@ -12,3 +12,5 @@ mod QRDataMaskTest; mod QRBitMatrixParserTest; mod MQRDecoderTest; + +mod RMQRDecoderTest; diff --git a/src/qrcode/decoder/format_information.rs b/src/qrcode/decoder/format_information.rs index 492b445..4591cc9 100644 --- a/src/qrcode/decoder/format_information.rs +++ b/src/qrcode/decoder/format_information.rs @@ -19,6 +19,7 @@ use crate::common::Result; use super::ErrorCorrectionLevel; pub const FORMAT_INFO_MASK_QR: u32 = 0x5412; +pub const FORMAT_INFO_MASK_MODEL2: u32 = FORMAT_INFO_MASK_QR; /** * See ISO 18004:2006, Annex C, Table C.1 @@ -74,7 +75,8 @@ pub struct FormatInformation { pub microVersion: u32, pub isMirrored: bool, - pub index: u8, // = 255; + pub mask: u32, // = 0 + pub data: u32, // = 255 pub bitsIndex: u8, // = 255; } @@ -86,7 +88,8 @@ impl Default for FormatInformation { data_mask: Default::default(), microVersion: 0, isMirrored: false, - index: 255, + mask: 0, + data: 255, bitsIndex: 255, } } @@ -104,8 +107,9 @@ impl FormatInformation { error_correction_level: errorCorrectionLevel, data_mask: dataMask, isMirrored: false, - index: 255, + mask: 0, bitsIndex: 255, + data: 255, }) } diff --git a/src/qrcode/decoder/mod.rs b/src/qrcode/decoder/mod.rs index 835abd7..2e3285a 100644 --- a/src/qrcode/decoder/mod.rs +++ b/src/qrcode/decoder/mod.rs @@ -8,6 +8,7 @@ mod mode; mod qr_code_decoder_meta_data; pub mod qrcode_decoder; mod version; +mod version_build_versions_arrays; #[cfg(test)] mod DecodedBitStreamParserTestCase; diff --git a/src/qrcode/decoder/mode.rs b/src/qrcode/decoder/mode.rs index 858f4ba..ec81330 100644 --- a/src/qrcode/decoder/mode.rs +++ b/src/qrcode/decoder/mode.rs @@ -15,6 +15,7 @@ */ use crate::common::Result; +use crate::qrcode::cpp_port::Type; use crate::Exceptions; use super::Version; @@ -82,6 +83,7 @@ impl Mode { */ pub fn getCharacterCountBits(&self, version: &Version) -> u8 { let number = version.getVersionNumber(); + let offset = if number <= 9 { 0 } else if number <= 26 { @@ -122,18 +124,19 @@ impl Mode { } } - pub const fn get_terminator_bit_length(version: &Version) -> u8 { - (if version.isMicroQRCode() { + pub fn get_terminator_bit_length(version: &Version) -> u8 { + (if version.isMicro() { version.getVersionNumber() * 2 + 1 } else { - 4 + 4 - u32::from(version.isRMQR()) }) as u8 } - pub const fn get_codec_mode_bits_length(version: &Version) -> u8 { - (if version.isMicroQRCode() { + + pub fn get_codec_mode_bits_length(version: &Version) -> u8 { + (if version.isMicro() { version.getVersionNumber() - 1 } else { - 4 + 4 - u32::from(version.isRMQR()) }) as u8 } /** @@ -142,20 +145,32 @@ impl Mode { * @return Mode encoded by these bits * @throws FormatError if bits do not correspond to a known mode */ - pub fn CodecModeForBits(bits: u32, isMicro: Option) -> Result { - let isMicro = isMicro.unwrap_or(false); - const BITS_2_MODE_LEN: usize = 4; + pub fn CodecModeForBits(bits: u32, qr_type: Option) -> Result { + let qr_type = qr_type.unwrap_or(Type::Model2); + let bits = bits as usize; - if !isMicro { - if (0x00..=0x05).contains(&bits) || (0x07..=0x09).contains(&bits) || bits == 0x0d { - return Mode::try_from(bits); - } - } else { - const BITS_2_MODE: [Mode; BITS_2_MODE_LEN] = + if qr_type == Type::Micro { + const Bits2Mode: [Mode; 4] = [Mode::NUMERIC, Mode::ALPHANUMERIC, Mode::BYTE, Mode::KANJI]; - if (bits as usize) < BITS_2_MODE_LEN { - return Ok(BITS_2_MODE[bits as usize]); + if bits < (Bits2Mode.len()) { + return Ok(Bits2Mode[bits]); } + } else if qr_type == Type::RectMicro { + const Bits2Mode: [Mode; 8] = [ + Mode::TERMINATOR, + Mode::NUMERIC, + Mode::ALPHANUMERIC, + Mode::BYTE, + Mode::KANJI, + Mode::FNC1_FIRST_POSITION, + Mode::FNC1_SECOND_POSITION, + Mode::ECI, + ]; + if bits < (Bits2Mode.len()) { + return Ok(Bits2Mode[bits]); + } + } else if (0x00..=0x05).contains(&bits) || (0x07..=0x09).contains(&bits) || bits == 0x0d { + return Mode::try_from(bits as u32); } Err(Exceptions::format_with("Invalid codec mode")) @@ -168,7 +183,7 @@ impl Mode { */ pub fn CharacterCountBits(&self, version: &Version) -> u32 { let number = version.getVersionNumber() as usize; - if version.isMicroQRCode() { + if version.isMicro() { match self { Mode::NUMERIC=> return [3, 4, 5, 6][number - 1], Mode::ALPHANUMERIC=> return [3, 4, 5][number - 2], @@ -179,6 +194,33 @@ impl Mode { } } + if version.isRMQR() { + // See ISO/IEC 23941:2022 7.4.1, Table 3 - Number of bits of character count indicator + const numeric: [u32; 32] = [ + 4, 5, 6, 7, 7, 5, 6, 7, 7, 8, 4, 6, 7, 7, 8, 8, 5, 6, 7, 7, 8, 8, 7, 7, 8, 8, 9, 7, + 8, 8, 8, 9, + ]; + const alphanum: [u32; 32] = [ + 3, 5, 5, 6, 6, 5, 5, 6, 6, 7, 4, 5, 6, 6, 7, 7, 5, 6, 6, 7, 7, 8, 6, 7, 7, 7, 8, 6, + 7, 7, 8, 8, + ]; + const byte: [u32; 32] = [ + 3, 4, 5, 5, 6, 4, 5, 5, 6, 6, 3, 5, 5, 6, 6, 7, 4, 5, 6, 6, 7, 7, 6, 6, 7, 7, 7, 6, + 6, 7, 7, 8, + ]; + const kanji: [u32; 32] = [ + 2, 3, 4, 5, 5, 3, 4, 5, 5, 6, 2, 4, 5, 5, 6, 6, 3, 5, 5, 6, 6, 7, 5, 5, 6, 6, 7, 5, + 6, 6, 6, 7, + ]; + match self { + Mode::NUMERIC => return numeric[number - 1], + Mode::ALPHANUMERIC => return alphanum[number - 1], + Mode::BYTE => return byte[number - 1], + Mode::KANJI => return kanji[number - 1], + _ => return 0, + } + } + let i = if number <= 9 { 0 } else if number <= 26 { diff --git a/src/qrcode/decoder/version.rs b/src/qrcode/decoder/version.rs index aeb58c7..9cf3892 100755 --- a/src/qrcode/decoder/version.rs +++ b/src/qrcode/decoder/version.rs @@ -18,6 +18,7 @@ use std::fmt; use crate::{ common::{BitMatrix, Result}, + qrcode::cpp_port::Type, Exceptions, }; @@ -29,6 +30,8 @@ pub type VersionRef = &'static Version; pub static VERSIONS: Lazy> = Lazy::new(Version::buildVersions); pub static MICRO_VERSIONS: Lazy> = Lazy::new(Version::build_micro_versions); +pub static MODEL1_VERSIONS: Lazy> = Lazy::new(Version::build_model1_versions); +pub static RMQR_VERSIONS: Lazy> = Lazy::new(Version::build_rmqr_versions); /** * See ISO 18004:2006 Annex D. @@ -54,17 +57,22 @@ pub struct Version { alignmentPatternCenters: Vec, ecBlocks: Vec, totalCodewords: u32, - pub(crate) is_micro: bool, + pub(crate) qr_type: Type, } impl Version { - fn new(versionNumber: u32, alignmentPatternCenters: Vec, ecBlocks: [ECBlocks; 4]) -> Self { + pub(super) fn new( + versionNumber: u32, + alignmentPatternCenters: Vec, + ecBlocks: [ECBlocks; 4], + ) -> Self { let mut total = 0; - let ecCodewords = ecBlocks[0].getECCodewordsPerBlock(); - let ecbArray = ecBlocks[0].getECBlocks(); - let mut i = 0; - while i < ecbArray.len() { - total += ecbArray[i].getCount() * (ecbArray[i].getDataCodewords() + ecCodewords); - i += 1; + let ecCodewords = ecBlocks[1].getECCodewordsPerBlock(); + let ecbArray = ecBlocks[1].getECBlocks(); + // let mut i = 0; + for ecb in ecbArray { + // while i < ecbArray.len() { + total += ecb.getCount() * (ecb.getDataCodewords() + ecCodewords); + // i += 1; } Self { @@ -72,11 +80,15 @@ impl Version { alignmentPatternCenters, ecBlocks: ecBlocks.to_vec(), totalCodewords: total, - is_micro: false, + qr_type: if ecBlocks[0].getECCodewordsPerBlock() != 0 { + Type::Model2 + } else { + Type::RectMicro + }, } } - fn new_micro(versionNumber: u32, ecBlocks: Vec) -> Self { + pub(super) fn new_micro(versionNumber: u32, ecBlocks: Vec) -> Self { let mut total = 0; let ecCodewords = ecBlocks[0].getECCodewordsPerBlock(); let ecbArray = ecBlocks[0].getECBlocks(); @@ -91,7 +103,26 @@ impl Version { alignmentPatternCenters: Vec::default(), ecBlocks, totalCodewords: total, - is_micro: true, + qr_type: Type::Micro, + } + } + + pub(super) fn new_model1(versionNumber: u32, ecBlocks: Vec) -> Self { + let mut total = 0; + let ecCodewords = ecBlocks[0].getECCodewordsPerBlock(); + let ecbArray = ecBlocks[0].getECBlocks(); + let mut i = 0; + while i < ecbArray.len() { + total += ecbArray[i].getCount() * (ecbArray[i].getDataCodewords() + ecCodewords); + i += 1; + } + + Self { + versionNumber, + alignmentPatternCenters: Vec::default(), + ecBlocks, + totalCodewords: total, + qr_type: Type::Model1, } } @@ -108,7 +139,7 @@ impl Version { } pub fn getDimensionForVersion(&self) -> u32 { - Self::DimensionOfVersion(self.versionNumber, self.is_micro) + Self::DimensionOfVersion(self.versionNumber, self.qr_type == Type::Micro) // 17 + 4 * self.versionNumber } @@ -170,13 +201,55 @@ impl Version { * See ISO 18004:2006 Annex E */ pub fn buildFunctionPattern(&self) -> Result { + if self.isRMQR() { + let size = Version::SymbolSize(self.versionNumber, Type::RectMicro); + let mut bitMatrix = BitMatrix::new(size.x as u32, size.y as u32)?; + + // Set edge timing patterns + bitMatrix.setRegion(0, 0, size.x as u32, 1)?; // Top + bitMatrix.setRegion(0, (size.y - 1) as u32, size.x as u32, 1)?; // Bottom + bitMatrix.setRegion(0, 1, 1, (size.y - 2) as u32)?; // Left + bitMatrix.setRegion((size.x - 1) as u32, 1, 1, (size.y - 2) as u32)?; // Right + + // Set vertical timing and alignment patterns + let max = self.alignmentPatternCenters.len(); // Same as vertical timing column + for x in 0..max { + // for (size_t x = 0; x < max; ++x) { + let cx = self.alignmentPatternCenters[x]; + bitMatrix.setRegion(cx - 1, 1, 3, 2)?; // Top alignment pattern + bitMatrix.setRegion(cx - 1, (size.y - 3) as u32, 3, 2)?; // Bottom alignment pattern + bitMatrix.setRegion(cx, 3, 1, (size.y - 6) as u32)?; // Vertical timing pattern + } + + // Top left finder pattern + separator + bitMatrix.setRegion(1, 1, 8 - 1, 8 - 1 - u32::from(size.y == 7))?; // R7 finder bottom flush with edge + // Top left format + bitMatrix.setRegion(8, 1, 3, 5)?; + bitMatrix.setRegion(11, 1, 1, 3)?; + + // Bottom right finder subpattern + bitMatrix.setRegion((size.x - 5) as u32, (size.y - 5) as u32, 5 - 1, 5 - 1)?; + // Bottom right format + bitMatrix.setRegion((size.x - 8) as u32, (size.y - 6) as u32, 3, 5)?; + bitMatrix.setRegion((size.x - 5) as u32, (size.y - 6) as u32, 3, 1)?; + + // Top right corner finder + bitMatrix.set((size.x - 2) as u32, 1); + if size.y > 9 { + // Bottom left corner finder + bitMatrix.set(1, (size.y - 2) as u32); + } + + return Ok(bitMatrix); + } + let dimension = self.getDimensionForVersion(); let mut bitMatrix = BitMatrix::with_single_dimension(dimension)?; // Top left finder pattern + separator + format bitMatrix.setRegion(0, 0, 9, 9)?; - if !self.is_micro { + if self.qr_type != Type::Micro { // Top right finder pattern + separator + format bitMatrix.setRegion(dimension - 8, 0, 8, 9)?; // Bottom left finder pattern + separator + format @@ -215,761 +288,6 @@ impl Version { Ok(bitMatrix) } - - pub fn build_micro_versions() -> Vec { - vec![ - Version::new_micro(1, vec![ECBlocks::new(2, vec![ECB::new(1, 3)])]), - Version::new_micro( - 2, - vec![ - ECBlocks::new(5, vec![ECB::new(1, 5)]), - ECBlocks::new(6, vec![ECB::new(1, 4)]), - ], - ), - Version::new_micro( - 3, - vec![ - ECBlocks::new(6, vec![ECB::new(1, 11)]), - ECBlocks::new(8, vec![ECB::new(1, 9)]), - ], - ), - Version::new_micro( - 4, - vec![ - ECBlocks::new(8, vec![ECB::new(1, 16)]), - ECBlocks::new(10, vec![ECB::new(1, 14)]), - ECBlocks::new(14, vec![ECB::new(1, 10)]), - ], - ), - ] - // static const Version allVersions[] = { - // {1, {2, 1, 3, 0, 0}}, - // {2, {5, 1, 5, 0, 0, 6, 1, 4, 0, 0}}, - // {3, {6, 1, 11, 0, 0, 8, 1, 9, 0, 0}}, - // {4, {8, 1, 16, 0, 0, 10, 1, 14, 0, 0, 14, 1, 10, 0, 0}}}; - } - - /** - * See ISO 18004:2006 6.5.1 Table 9 - */ - pub fn buildVersions() -> Vec { - Vec::from([ - Version::new( - 1, - Vec::from([]), - [ - ECBlocks::new(7, Vec::from([ECB::new(1, 19)])), - ECBlocks::new(10, Vec::from([ECB::new(1, 16)])), - ECBlocks::new(13, Vec::from([ECB::new(1, 13)])), - ECBlocks::new(17, Vec::from([ECB::new(1, 9)])), - ], - ), - Version::new( - 2, - Vec::from([6, 18]), - [ - ECBlocks::new(10, Vec::from([ECB::new(1, 34)])), - ECBlocks::new(16, Vec::from([ECB::new(1, 28)])), - ECBlocks::new(22, Vec::from([ECB::new(1, 22)])), - ECBlocks::new(28, Vec::from([ECB::new(1, 16)])), - ], - ), - Version::new( - 3, - Vec::from([6, 22]), - [ - ECBlocks::new(15, Vec::from([ECB::new(1, 55)])), - ECBlocks::new(26, Vec::from([ECB::new(1, 44)])), - ECBlocks::new(18, Vec::from([ECB::new(2, 17)])), - ECBlocks::new(22, Vec::from([ECB::new(2, 13)])), - ], - ), - Version::new( - 4, - Vec::from([6, 26]), - [ - ECBlocks::new(20, Vec::from([ECB::new(1, 80)])), - ECBlocks::new(18, Vec::from([ECB::new(2, 32)])), - ECBlocks::new(26, Vec::from([ECB::new(2, 24)])), - ECBlocks::new(16, Vec::from([ECB::new(4, 9)])), - ], - ), - Version::new( - 5, - Vec::from([6, 30]), - [ - ECBlocks::new(26, Vec::from([ECB::new(1, 108)])), - ECBlocks::new(24, Vec::from([ECB::new(2, 43)])), - ECBlocks::new(18, Vec::from([ECB::new(2, 15), ECB::new(2, 16)])), - ECBlocks::new(22, Vec::from([ECB::new(2, 11), ECB::new(2, 12)])), - ], - ), - Version::new( - 6, - Vec::from([6, 34]), - [ - ECBlocks::new(18, Vec::from([ECB::new(2, 68)])), - ECBlocks::new(16, Vec::from([ECB::new(4, 27)])), - ECBlocks::new(24, Vec::from([ECB::new(4, 19)])), - ECBlocks::new(28, Vec::from([ECB::new(4, 15)])), - ], - ), - Version::new( - 7, - Vec::from([6, 22, 38]), - [ - ECBlocks::new(20, Vec::from([ECB::new(2, 78)])), - ECBlocks::new(18, Vec::from([ECB::new(4, 31)])), - ECBlocks::new(18, Vec::from([ECB::new(2, 14), ECB::new(4, 15)])), - ECBlocks::new(26, Vec::from([ECB::new(4, 13), ECB::new(1, 14)])), - ], - ), - Version::new( - 8, - Vec::from([6, 24, 42]), - [ - ECBlocks::new(24, Vec::from([ECB::new(2, 97)])), - ECBlocks::new(22, Vec::from([ECB::new(2, 38), ECB::new(2, 39)])), - ECBlocks::new(22, Vec::from([ECB::new(4, 18), ECB::new(2, 19)])), - ECBlocks::new(26, Vec::from([ECB::new(4, 14), ECB::new(2, 15)])), - ], - ), - Version::new( - 9, - Vec::from([6, 26, 46]), - [ - ECBlocks::new(30, Vec::from([ECB::new(2, 116)])), - ECBlocks::new(22, Vec::from([ECB::new(3, 36), ECB::new(2, 37)])), - ECBlocks::new(20, Vec::from([ECB::new(4, 16), ECB::new(4, 17)])), - ECBlocks::new(24, Vec::from([ECB::new(4, 12), ECB::new(4, 13)])), - ], - ), - Version::new( - 10, - Vec::from([6, 28, 50]), - [ - ECBlocks::new(18, Vec::from([ECB::new(2, 68), ECB::new(2, 69)])), - ECBlocks::new(26, Vec::from([ECB::new(4, 43), ECB::new(1, 44)])), - ECBlocks::new(24, Vec::from([ECB::new(6, 19), ECB::new(2, 20)])), - ECBlocks::new(28, Vec::from([ECB::new(6, 15), ECB::new(2, 16)])), - ], - ), - Version::new( - 11, - Vec::from([6, 30, 54]), - [ - ECBlocks::new(20, Vec::from([ECB::new(4, 81)])), - ECBlocks::new(30, Vec::from([ECB::new(1, 50), ECB::new(4, 51)])), - ECBlocks::new(28, Vec::from([ECB::new(4, 22), ECB::new(4, 23)])), - ECBlocks::new(24, Vec::from([ECB::new(3, 12), ECB::new(8, 13)])), - ], - ), - Version::new( - 12, - Vec::from([6, 32, 58]), - [ - ECBlocks::new(24, Vec::from([ECB::new(2, 92), ECB::new(2, 93)])), - ECBlocks::new(22, Vec::from([ECB::new(6, 36), ECB::new(2, 37)])), - ECBlocks::new(26, Vec::from([ECB::new(4, 20), ECB::new(6, 21)])), - ECBlocks::new(28, Vec::from([ECB::new(7, 14), ECB::new(4, 15)])), - ], - ), - Version::new( - 13, - Vec::from([6, 34, 62]), - [ - ECBlocks::new(26, Vec::from([ECB::new(4, 107)])), - ECBlocks::new(22, Vec::from([ECB::new(8, 37), ECB::new(1, 38)])), - ECBlocks::new(24, Vec::from([ECB::new(8, 20), ECB::new(4, 21)])), - ECBlocks::new(22, Vec::from([ECB::new(12, 11), ECB::new(4, 12)])), - ], - ), - Version::new( - 14, - Vec::from([6, 26, 46, 66]), - [ - ECBlocks::new(30, Vec::from([ECB::new(3, 115), ECB::new(1, 116)])), - ECBlocks::new(24, Vec::from([ECB::new(4, 40), ECB::new(5, 41)])), - ECBlocks::new(20, Vec::from([ECB::new(11, 16), ECB::new(5, 17)])), - ECBlocks::new(24, Vec::from([ECB::new(11, 12), ECB::new(5, 13)])), - ], - ), - Version::new( - 15, - Vec::from([6, 26, 48, 70]), - [ - ECBlocks::new(22, Vec::from([ECB::new(5, 87), ECB::new(1, 88)])), - ECBlocks::new(24, Vec::from([ECB::new(5, 41), ECB::new(5, 42)])), - ECBlocks::new(30, Vec::from([ECB::new(5, 24), ECB::new(7, 25)])), - ECBlocks::new(24, Vec::from([ECB::new(11, 12), ECB::new(7, 13)])), - ], - ), - Version::new( - 16, - Vec::from([6, 26, 50, 74]), - [ - ECBlocks::new(24, Vec::from([ECB::new(5, 98), ECB::new(1, 99)])), - ECBlocks::new(28, Vec::from([ECB::new(7, 45), ECB::new(3, 46)])), - ECBlocks::new(24, Vec::from([ECB::new(15, 19), ECB::new(2, 20)])), - ECBlocks::new(30, Vec::from([ECB::new(3, 15), ECB::new(13, 16)])), - ], - ), - Version::new( - 17, - Vec::from([6, 30, 54, 78]), - [ - ECBlocks::new(28, Vec::from([ECB::new(1, 107), ECB::new(5, 108)])), - ECBlocks::new(28, Vec::from([ECB::new(10, 46), ECB::new(1, 47)])), - ECBlocks::new(28, Vec::from([ECB::new(1, 22), ECB::new(15, 23)])), - ECBlocks::new(28, Vec::from([ECB::new(2, 14), ECB::new(17, 15)])), - ], - ), - Version::new( - 18, - Vec::from([6, 30, 56, 82]), - [ - ECBlocks::new(30, Vec::from([ECB::new(5, 120), ECB::new(1, 121)])), - ECBlocks::new(26, Vec::from([ECB::new(9, 43), ECB::new(4, 44)])), - ECBlocks::new(28, Vec::from([ECB::new(17, 22), ECB::new(1, 23)])), - ECBlocks::new(28, Vec::from([ECB::new(2, 14), ECB::new(19, 15)])), - ], - ), - Version::new( - 19, - Vec::from([6, 30, 58, 86]), - [ - ECBlocks::new(28, Vec::from([ECB::new(3, 113), ECB::new(4, 114)])), - ECBlocks::new(26, Vec::from([ECB::new(3, 44), ECB::new(11, 45)])), - ECBlocks::new(26, Vec::from([ECB::new(17, 21), ECB::new(4, 22)])), - ECBlocks::new(26, Vec::from([ECB::new(9, 13), ECB::new(16, 14)])), - ], - ), - Version::new( - 20, - Vec::from([6, 34, 62, 90]), - [ - ECBlocks::new(28, Vec::from([ECB::new(3, 107), ECB::new(5, 108)])), - ECBlocks::new(26, Vec::from([ECB::new(3, 41), ECB::new(13, 42)])), - ECBlocks::new(30, Vec::from([ECB::new(15, 24), ECB::new(5, 25)])), - ECBlocks::new(28, Vec::from([ECB::new(15, 15), ECB::new(10, 16)])), - ], - ), - Version::new( - 21, - Vec::from([6, 28, 50, 72, 94]), - [ - ECBlocks::new(28, Vec::from([ECB::new(4, 116), ECB::new(4, 117)])), - ECBlocks::new(26, Vec::from([ECB::new(17, 42)])), - ECBlocks::new(28, Vec::from([ECB::new(17, 22), ECB::new(6, 23)])), - ECBlocks::new(30, Vec::from([ECB::new(19, 16), ECB::new(6, 17)])), - ], - ), - Version::new( - 22, - Vec::from([6, 26, 50, 74, 98]), - [ - ECBlocks::new(28, Vec::from([ECB::new(2, 111), ECB::new(7, 112)])), - ECBlocks::new(28, Vec::from([ECB::new(17, 46)])), - ECBlocks::new(30, Vec::from([ECB::new(7, 24), ECB::new(16, 25)])), - ECBlocks::new(24, Vec::from([ECB::new(34, 13)])), - ], - ), - Version::new( - 23, - Vec::from([6, 30, 54, 78, 102]), - [ - ECBlocks::new(30, Vec::from([ECB::new(4, 121), ECB::new(5, 122)])), - ECBlocks::new(28, Vec::from([ECB::new(4, 47), ECB::new(14, 48)])), - ECBlocks::new(30, Vec::from([ECB::new(11, 24), ECB::new(14, 25)])), - ECBlocks::new(30, Vec::from([ECB::new(16, 15), ECB::new(14, 16)])), - ], - ), - Version::new( - 24, - Vec::from([6, 28, 54, 80, 106]), - [ - ECBlocks::new(30, Vec::from([ECB::new(6, 117), ECB::new(4, 118)])), - ECBlocks::new(28, Vec::from([ECB::new(6, 45), ECB::new(14, 46)])), - ECBlocks::new(30, Vec::from([ECB::new(11, 24), ECB::new(16, 25)])), - ECBlocks::new(30, Vec::from([ECB::new(30, 16), ECB::new(2, 17)])), - ], - ), - Version::new( - 25, - Vec::from([6, 32, 58, 84, 110]), - [ - ECBlocks::new(26, Vec::from([ECB::new(8, 106), ECB::new(4, 107)])), - ECBlocks::new(28, Vec::from([ECB::new(8, 47), ECB::new(13, 48)])), - ECBlocks::new(30, Vec::from([ECB::new(7, 24), ECB::new(22, 25)])), - ECBlocks::new(30, Vec::from([ECB::new(22, 15), ECB::new(13, 16)])), - ], - ), - Version::new( - 26, - Vec::from([6, 30, 58, 86, 114]), - [ - ECBlocks::new(28, Vec::from([ECB::new(10, 114), ECB::new(2, 115)])), - ECBlocks::new(28, Vec::from([ECB::new(19, 46), ECB::new(4, 47)])), - ECBlocks::new(28, Vec::from([ECB::new(28, 22), ECB::new(6, 23)])), - ECBlocks::new(30, Vec::from([ECB::new(33, 16), ECB::new(4, 17)])), - ], - ), - Version::new( - 27, - Vec::from([6, 34, 62, 90, 118]), - [ - ECBlocks::new(30, Vec::from([ECB::new(8, 122), ECB::new(4, 123)])), - ECBlocks::new(28, Vec::from([ECB::new(22, 45), ECB::new(3, 46)])), - ECBlocks::new(30, Vec::from([ECB::new(8, 23), ECB::new(26, 24)])), - ECBlocks::new(30, Vec::from([ECB::new(12, 15), ECB::new(28, 16)])), - ], - ), - Version::new( - 28, - Vec::from([6, 26, 50, 74, 98, 122]), - [ - ECBlocks::new(30, Vec::from([ECB::new(3, 117), ECB::new(10, 118)])), - ECBlocks::new(28, Vec::from([ECB::new(3, 45), ECB::new(23, 46)])), - ECBlocks::new(30, Vec::from([ECB::new(4, 24), ECB::new(31, 25)])), - ECBlocks::new(30, Vec::from([ECB::new(11, 15), ECB::new(31, 16)])), - ], - ), - Version::new( - 29, - Vec::from([6, 30, 54, 78, 102, 126]), - [ - ECBlocks::new(30, Vec::from([ECB::new(7, 116), ECB::new(7, 117)])), - ECBlocks::new(28, Vec::from([ECB::new(21, 45), ECB::new(7, 46)])), - ECBlocks::new(30, Vec::from([ECB::new(1, 23), ECB::new(37, 24)])), - ECBlocks::new(30, Vec::from([ECB::new(19, 15), ECB::new(26, 16)])), - ], - ), - Version::new( - 30, - Vec::from([6, 26, 52, 78, 104, 130]), - [ - ECBlocks::new(30, Vec::from([ECB::new(5, 115), ECB::new(10, 116)])), - ECBlocks::new(28, Vec::from([ECB::new(19, 47), ECB::new(10, 48)])), - ECBlocks::new(30, Vec::from([ECB::new(15, 24), ECB::new(25, 25)])), - ECBlocks::new(30, Vec::from([ECB::new(23, 15), ECB::new(25, 16)])), - ], - ), - Version::new( - 31, - Vec::from([6, 30, 56, 82, 108, 134]), - [ - ECBlocks::new(30, Vec::from([ECB::new(13, 115), ECB::new(3, 116)])), - ECBlocks::new(28, Vec::from([ECB::new(2, 46), ECB::new(29, 47)])), - ECBlocks::new(30, Vec::from([ECB::new(42, 24), ECB::new(1, 25)])), - ECBlocks::new(30, Vec::from([ECB::new(23, 15), ECB::new(28, 16)])), - ], - ), - Version::new( - 32, - Vec::from([6, 34, 60, 86, 112, 138]), - [ - ECBlocks::new(30, Vec::from([ECB::new(17, 115)])), - ECBlocks::new(28, Vec::from([ECB::new(10, 46), ECB::new(23, 47)])), - ECBlocks::new(30, Vec::from([ECB::new(10, 24), ECB::new(35, 25)])), - ECBlocks::new(30, Vec::from([ECB::new(19, 15), ECB::new(35, 16)])), - ], - ), - Version::new( - 33, - Vec::from([6, 30, 58, 86, 114, 142]), - [ - ECBlocks::new(30, Vec::from([ECB::new(17, 115), ECB::new(1, 116)])), - ECBlocks::new(28, Vec::from([ECB::new(14, 46), ECB::new(21, 47)])), - ECBlocks::new(30, Vec::from([ECB::new(29, 24), ECB::new(19, 25)])), - ECBlocks::new(30, Vec::from([ECB::new(11, 15), ECB::new(46, 16)])), - ], - ), - Version::new( - 34, - Vec::from([6, 34, 62, 90, 118, 146]), - [ - ECBlocks::new(30, Vec::from([ECB::new(13, 115), ECB::new(6, 116)])), - ECBlocks::new(28, Vec::from([ECB::new(14, 46), ECB::new(23, 47)])), - ECBlocks::new(30, Vec::from([ECB::new(44, 24), ECB::new(7, 25)])), - ECBlocks::new(30, Vec::from([ECB::new(59, 16), ECB::new(1, 17)])), - ], - ), - Version::new( - 35, - Vec::from([6, 30, 54, 78, 102, 126, 150]), - [ - ECBlocks::new(30, Vec::from([ECB::new(12, 121), ECB::new(7, 122)])), - ECBlocks::new(28, Vec::from([ECB::new(12, 47), ECB::new(26, 48)])), - ECBlocks::new(30, Vec::from([ECB::new(39, 24), ECB::new(14, 25)])), - ECBlocks::new(30, Vec::from([ECB::new(22, 15), ECB::new(41, 16)])), - ], - ), - Version::new( - 36, - Vec::from([6, 24, 50, 76, 102, 128, 154]), - [ - ECBlocks::new(30, Vec::from([ECB::new(6, 121), ECB::new(14, 122)])), - ECBlocks::new(28, Vec::from([ECB::new(6, 47), ECB::new(34, 48)])), - ECBlocks::new(30, Vec::from([ECB::new(46, 24), ECB::new(10, 25)])), - ECBlocks::new(30, Vec::from([ECB::new(2, 15), ECB::new(64, 16)])), - ], - ), - Version::new( - 37, - Vec::from([6, 28, 54, 80, 106, 132, 158]), - [ - ECBlocks::new(30, Vec::from([ECB::new(17, 122), ECB::new(4, 123)])), - ECBlocks::new(28, Vec::from([ECB::new(29, 46), ECB::new(14, 47)])), - ECBlocks::new(30, Vec::from([ECB::new(49, 24), ECB::new(10, 25)])), - ECBlocks::new(30, Vec::from([ECB::new(24, 15), ECB::new(46, 16)])), - ], - ), - Version::new( - 38, - Vec::from([6, 32, 58, 84, 110, 136, 162]), - [ - ECBlocks::new(30, Vec::from([ECB::new(4, 122), ECB::new(18, 123)])), - ECBlocks::new(28, Vec::from([ECB::new(13, 46), ECB::new(32, 47)])), - ECBlocks::new(30, Vec::from([ECB::new(48, 24), ECB::new(14, 25)])), - ECBlocks::new(30, Vec::from([ECB::new(42, 15), ECB::new(32, 16)])), - ], - ), - Version::new( - 39, - Vec::from([6, 26, 54, 82, 110, 138, 166]), - [ - ECBlocks::new(30, Vec::from([ECB::new(20, 117), ECB::new(4, 118)])), - ECBlocks::new(28, Vec::from([ECB::new(40, 47), ECB::new(7, 48)])), - ECBlocks::new(30, Vec::from([ECB::new(43, 24), ECB::new(22, 25)])), - ECBlocks::new(30, Vec::from([ECB::new(10, 15), ECB::new(67, 16)])), - ], - ), - Version::new( - 40, - Vec::from([6, 30, 58, 86, 114, 142, 170]), - [ - ECBlocks::new(30, Vec::from([ECB::new(19, 118), ECB::new(6, 119)])), - ECBlocks::new(28, Vec::from([ECB::new(18, 47), ECB::new(31, 48)])), - ECBlocks::new(30, Vec::from([ECB::new(34, 24), ECB::new(34, 25)])), - ECBlocks::new(30, Vec::from([ECB::new(20, 15), ECB::new(61, 16)])), - ], - ), - ]) /* - new Version(4, new int[]{6, 26}, - new ECBlocks(20, new ECB::new(1, 80)), - new ECBlocks(18, new ECB::new(2, 32)), - new ECBlocks(26, new ECB::new(2, 24)), - new ECBlocks(16, new ECB::new(4, 9))), - new Version(5, new int[]{6, 30}, - new ECBlocks(26, new ECB::new(1, 108)), - new ECBlocks(24, new ECB::new(2, 43)), - new ECBlocks(18, new ECB::new(2, 15), - new ECB::new(2, 16)), - new ECBlocks(22, new ECB::new(2, 11), - new ECB::new(2, 12))), - new Version(6, new int[]{6, 34}, - new ECBlocks(18, new ECB::new(2, 68)), - new ECBlocks(16, new ECB::new(4, 27)), - new ECBlocks(24, new ECB::new(4, 19)), - new ECBlocks(28, new ECB::new(4, 15))), - new Version(7, new int[]{6, 22, 38}, - new ECBlocks(20, new ECB::new(2, 78)), - new ECBlocks(18, new ECB::new(4, 31)), - new ECBlocks(18, new ECB::new(2, 14), - new ECB::new(4, 15)), - new ECBlocks(26, new ECB::new(4, 13), - new ECB::new(1, 14))), - new Version(8, new int[]{6, 24, 42}, - new ECBlocks(24, new ECB::new(2, 97)), - new ECBlocks(22, new ECB::new(2, 38), - new ECB::new(2, 39)), - new ECBlocks(22, new ECB::new(4, 18), - new ECB::new(2, 19)), - new ECBlocks(26, new ECB::new(4, 14), - new ECB::new(2, 15))), - new Version(9, new int[]{6, 26, 46}, - new ECBlocks(30, new ECB::new(2, 116)), - new ECBlocks(22, new ECB::new(3, 36), - new ECB::new(2, 37)), - new ECBlocks(20, new ECB::new(4, 16), - new ECB::new(4, 17)), - new ECBlocks(24, new ECB::new(4, 12), - new ECB::new(4, 13))), - new Version(10, new int[]{6, 28, 50}, - new ECBlocks(18, new ECB::new(2, 68), - new ECB::new(2, 69)), - new ECBlocks(26, new ECB::new(4, 43), - new ECB::new(1, 44)), - new ECBlocks(24, new ECB::new(6, 19), - new ECB::new(2, 20)), - new ECBlocks(28, new ECB::new(6, 15), - new ECB::new(2, 16))), - new Version(11, new int[]{6, 30, 54}, - new ECBlocks(20, new ECB::new(4, 81)), - new ECBlocks(30, new ECB::new(1, 50), - new ECB::new(4, 51)), - new ECBlocks(28, new ECB::new(4, 22), - new ECB::new(4, 23)), - new ECBlocks(24, new ECB::new(3, 12), - new ECB::new(8, 13))), - new Version(12, new int[]{6, 32, 58}, - new ECBlocks(24, new ECB::new(2, 92), - new ECB::new(2, 93)), - new ECBlocks(22, new ECB::new(6, 36), - new ECB::new(2, 37)), - new ECBlocks(26, new ECB::new(4, 20), - new ECB::new(6, 21)), - new ECBlocks(28, new ECB::new(7, 14), - new ECB::new(4, 15))), - new Version(13, new int[]{6, 34, 62}, - new ECBlocks(26, new ECB::new(4, 107)), - new ECBlocks(22, new ECB::new(8, 37), - new ECB::new(1, 38)), - new ECBlocks(24, new ECB::new(8, 20), - new ECB::new(4, 21)), - new ECBlocks(22, new ECB::new(12, 11), - new ECB::new(4, 12))), - new Version(14, new int[]{6, 26, 46, 66}, - new ECBlocks(30, new ECB::new(3, 115), - new ECB::new(1, 116)), - new ECBlocks(24, new ECB::new(4, 40), - new ECB::new(5, 41)), - new ECBlocks(20, new ECB::new(11, 16), - new ECB::new(5, 17)), - new ECBlocks(24, new ECB::new(11, 12), - new ECB::new(5, 13))), - new Version(15, new int[]{6, 26, 48, 70}, - new ECBlocks(22, new ECB::new(5, 87), - new ECB::new(1, 88)), - new ECBlocks(24, new ECB::new(5, 41), - new ECB::new(5, 42)), - new ECBlocks(30, new ECB::new(5, 24), - new ECB::new(7, 25)), - new ECBlocks(24, new ECB::new(11, 12), - new ECB::new(7, 13))), - new Version(16, new int[]{6, 26, 50, 74}, - new ECBlocks(24, new ECB::new(5, 98), - new ECB::new(1, 99)), - new ECBlocks(28, new ECB::new(7, 45), - new ECB::new(3, 46)), - new ECBlocks(24, new ECB::new(15, 19), - new ECB::new(2, 20)), - new ECBlocks(30, new ECB::new(3, 15), - new ECB::new(13, 16))), - new Version(17, new int[]{6, 30, 54, 78}, - new ECBlocks(28, new ECB::new(1, 107), - new ECB::new(5, 108)), - new ECBlocks(28, new ECB::new(10, 46), - new ECB::new(1, 47)), - new ECBlocks(28, new ECB::new(1, 22), - new ECB::new(15, 23)), - new ECBlocks(28, new ECB::new(2, 14), - new ECB::new(17, 15))), - new Version(18, new int[]{6, 30, 56, 82}, - new ECBlocks(30, new ECB::new(5, 120), - new ECB::new(1, 121)), - new ECBlocks(26, new ECB::new(9, 43), - new ECB::new(4, 44)), - new ECBlocks(28, new ECB::new(17, 22), - new ECB::new(1, 23)), - new ECBlocks(28, new ECB::new(2, 14), - new ECB::new(19, 15))), - new Version(19, new int[]{6, 30, 58, 86}, - new ECBlocks(28, new ECB::new(3, 113), - new ECB::new(4, 114)), - new ECBlocks(26, new ECB::new(3, 44), - new ECB::new(11, 45)), - new ECBlocks(26, new ECB::new(17, 21), - new ECB::new(4, 22)), - new ECBlocks(26, new ECB::new(9, 13), - new ECB::new(16, 14))), - new Version(20, new int[]{6, 34, 62, 90}, - new ECBlocks(28, new ECB::new(3, 107), - new ECB::new(5, 108)), - new ECBlocks(26, new ECB::new(3, 41), - new ECB::new(13, 42)), - new ECBlocks(30, new ECB::new(15, 24), - new ECB::new(5, 25)), - new ECBlocks(28, new ECB::new(15, 15), - new ECB::new(10, 16))), - new Version(21, new int[]{6, 28, 50, 72, 94}, - new ECBlocks(28, new ECB::new(4, 116), - new ECB::new(4, 117)), - new ECBlocks(26, new ECB::new(17, 42)), - new ECBlocks(28, new ECB::new(17, 22), - new ECB::new(6, 23)), - new ECBlocks(30, new ECB::new(19, 16), - new ECB::new(6, 17))), - new Version(22, new int[]{6, 26, 50, 74, 98}, - new ECBlocks(28, new ECB::new(2, 111), - new ECB::new(7, 112)), - new ECBlocks(28, new ECB::new(17, 46)), - new ECBlocks(30, new ECB::new(7, 24), - new ECB::new(16, 25)), - new ECBlocks(24, new ECB::new(34, 13))), - new Version(23, new int[]{6, 30, 54, 78, 102}, - new ECBlocks(30, new ECB::new(4, 121), - new ECB::new(5, 122)), - new ECBlocks(28, new ECB::new(4, 47), - new ECB::new(14, 48)), - new ECBlocks(30, new ECB::new(11, 24), - new ECB::new(14, 25)), - new ECBlocks(30, new ECB::new(16, 15), - new ECB::new(14, 16))), - new Version(24, new int[]{6, 28, 54, 80, 106}, - new ECBlocks(30, new ECB::new(6, 117), - new ECB::new(4, 118)), - new ECBlocks(28, new ECB::new(6, 45), - new ECB::new(14, 46)), - new ECBlocks(30, new ECB::new(11, 24), - new ECB::new(16, 25)), - new ECBlocks(30, new ECB::new(30, 16), - new ECB::new(2, 17))), - new Version(25, new int[]{6, 32, 58, 84, 110}, - new ECBlocks(26, new ECB::new(8, 106), - new ECB::new(4, 107)), - new ECBlocks(28, new ECB::new(8, 47), - new ECB::new(13, 48)), - new ECBlocks(30, new ECB::new(7, 24), - new ECB::new(22, 25)), - new ECBlocks(30, new ECB::new(22, 15), - new ECB::new(13, 16))), - new Version(26, new int[]{6, 30, 58, 86, 114}, - new ECBlocks(28, new ECB::new(10, 114), - new ECB::new(2, 115)), - new ECBlocks(28, new ECB::new(19, 46), - new ECB::new(4, 47)), - new ECBlocks(28, new ECB::new(28, 22), - new ECB::new(6, 23)), - new ECBlocks(30, new ECB::new(33, 16), - new ECB::new(4, 17))), - new Version(27, new int[]{6, 34, 62, 90, 118}, - new ECBlocks(30, new ECB::new(8, 122), - new ECB::new(4, 123)), - new ECBlocks(28, new ECB::new(22, 45), - new ECB::new(3, 46)), - new ECBlocks(30, new ECB::new(8, 23), - new ECB::new(26, 24)), - new ECBlocks(30, new ECB::new(12, 15), - new ECB::new(28, 16))), - new Version(28, new int[]{6, 26, 50, 74, 98, 122}, - new ECBlocks(30, new ECB::new(3, 117), - new ECB::new(10, 118)), - new ECBlocks(28, new ECB::new(3, 45), - new ECB::new(23, 46)), - new ECBlocks(30, new ECB::new(4, 24), - new ECB::new(31, 25)), - new ECBlocks(30, new ECB::new(11, 15), - new ECB::new(31, 16))), - new Version(29, new int[]{6, 30, 54, 78, 102, 126}, - new ECBlocks(30, new ECB::new(7, 116), - new ECB::new(7, 117)), - new ECBlocks(28, new ECB::new(21, 45), - new ECB::new(7, 46)), - new ECBlocks(30, new ECB::new(1, 23), - new ECB::new(37, 24)), - new ECBlocks(30, new ECB::new(19, 15), - new ECB::new(26, 16))), - new Version(30, new int[]{6, 26, 52, 78, 104, 130}, - new ECBlocks(30, new ECB::new(5, 115), - new ECB::new(10, 116)), - new ECBlocks(28, new ECB::new(19, 47), - new ECB::new(10, 48)), - new ECBlocks(30, new ECB::new(15, 24), - new ECB::new(25, 25)), - new ECBlocks(30, new ECB::new(23, 15), - new ECB::new(25, 16))), - new Version(31, new int[]{6, 30, 56, 82, 108, 134}, - new ECBlocks(30, new ECB::new(13, 115), - new ECB::new(3, 116)), - new ECBlocks(28, new ECB::new(2, 46), - new ECB::new(29, 47)), - new ECBlocks(30, new ECB::new(42, 24), - new ECB::new(1, 25)), - new ECBlocks(30, new ECB::new(23, 15), - new ECB::new(28, 16))), - new Version(32, new int[]{6, 34, 60, 86, 112, 138}, - new ECBlocks(30, new ECB::new(17, 115)), - new ECBlocks(28, new ECB::new(10, 46), - new ECB::new(23, 47)), - new ECBlocks(30, new ECB::new(10, 24), - new ECB::new(35, 25)), - new ECBlocks(30, new ECB::new(19, 15), - new ECB::new(35, 16))), - new Version(33, new int[]{6, 30, 58, 86, 114, 142}, - new ECBlocks(30, new ECB::new(17, 115), - new ECB::new(1, 116)), - new ECBlocks(28, new ECB::new(14, 46), - new ECB::new(21, 47)), - new ECBlocks(30, new ECB::new(29, 24), - new ECB::new(19, 25)), - new ECBlocks(30, new ECB::new(11, 15), - new ECB::new(46, 16))), - new Version(34, new int[]{6, 34, 62, 90, 118, 146}, - new ECBlocks(30, new ECB::new(13, 115), - new ECB::new(6, 116)), - new ECBlocks(28, new ECB::new(14, 46), - new ECB::new(23, 47)), - new ECBlocks(30, new ECB::new(44, 24), - new ECB::new(7, 25)), - new ECBlocks(30, new ECB::new(59, 16), - new ECB::new(1, 17))), - new Version(35, new int[]{6, 30, 54, 78, 102, 126, 150}, - new ECBlocks(30, new ECB::new(12, 121), - new ECB::new(7, 122)), - new ECBlocks(28, new ECB::new(12, 47), - new ECB::new(26, 48)), - new ECBlocks(30, new ECB::new(39, 24), - new ECB::new(14, 25)), - new ECBlocks(30, new ECB::new(22, 15), - new ECB::new(41, 16))), - new Version(36, new int[]{6, 24, 50, 76, 102, 128, 154}, - new ECBlocks(30, new ECB::new(6, 121), - new ECB::new(14, 122)), - new ECBlocks(28, new ECB::new(6, 47), - new ECB::new(34, 48)), - new ECBlocks(30, new ECB::new(46, 24), - new ECB::new(10, 25)), - new ECBlocks(30, new ECB::new(2, 15), - new ECB::new(64, 16))), - new Version(37, new int[]{6, 28, 54, 80, 106, 132, 158}, - new ECBlocks(30, new ECB::new(17, 122), - new ECB::new(4, 123)), - new ECBlocks(28, new ECB::new(29, 46), - new ECB::new(14, 47)), - new ECBlocks(30, new ECB::new(49, 24), - new ECB::new(10, 25)), - new ECBlocks(30, new ECB::new(24, 15), - new ECB::new(46, 16))), - new Version(38, new int[]{6, 32, 58, 84, 110, 136, 162}, - new ECBlocks(30, new ECB::new(4, 122), - new ECB::new(18, 123)), - new ECBlocks(28, new ECB::new(13, 46), - new ECB::new(32, 47)), - new ECBlocks(30, new ECB::new(48, 24), - new ECB::new(14, 25)), - new ECBlocks(30, new ECB::new(42, 15), - new ECB::new(32, 16))), - new Version(39, new int[]{6, 26, 54, 82, 110, 138, 166}, - new ECBlocks(30, new ECB::new(20, 117), - new ECB::new(4, 118)), - new ECBlocks(28, new ECB::new(40, 47), - new ECB::new(7, 48)), - new ECBlocks(30, new ECB::new(43, 24), - new ECB::new(22, 25)), - new ECBlocks(30, new ECB::new(10, 15), - new ECB::new(67, 16))), - new Version(40, new int[]{6, 30, 58, 86, 114, 142, 170}, - new ECBlocks(30, new ECB::new(19, 118), - new ECB::new(6, 119)), - new ECBlocks(28, new ECB::new(18, 47), - new ECB::new(31, 48)), - new ECBlocks(30, new ECB::new(34, 24), - new ECB::new(34, 25)), - new ECBlocks(30, new ECB::new(20, 15), - new ECB::new(61, 16))) - ]*/ - } } impl fmt::Display for Version { diff --git a/src/qrcode/decoder/version_build_versions_arrays.rs b/src/qrcode/decoder/version_build_versions_arrays.rs new file mode 100644 index 0000000..bbc6598 --- /dev/null +++ b/src/qrcode/decoder/version_build_versions_arrays.rs @@ -0,0 +1,1547 @@ +use super::{ECBlocks, Version, ECB}; + +impl Version { + pub fn build_micro_versions() -> Vec { + vec![ + Version::new_micro(1, vec![ECBlocks::new(2, vec![ECB::new(1, 3)])]), + Version::new_micro( + 2, + vec![ + ECBlocks::new(5, vec![ECB::new(1, 5)]), + ECBlocks::new(6, vec![ECB::new(1, 4)]), + ], + ), + Version::new_micro( + 3, + vec![ + ECBlocks::new(6, vec![ECB::new(1, 11)]), + ECBlocks::new(8, vec![ECB::new(1, 9)]), + ], + ), + Version::new_micro( + 4, + vec![ + ECBlocks::new(8, vec![ECB::new(1, 16)]), + ECBlocks::new(10, vec![ECB::new(1, 14)]), + ECBlocks::new(14, vec![ECB::new(1, 10)]), + ], + ), + ] + // static const Version allVersions[] = { + // {1, {2, 1, 3, 0, 0}}, + // {2, {5, 1, 5, 0, 0, 6, 1, 4, 0, 0}}, + // {3, {6, 1, 11, 0, 0, 8, 1, 9, 0, 0}}, + // {4, {8, 1, 16, 0, 0, 10, 1, 14, 0, 0, 14, 1, 10, 0, 0}}}; + } + + /** + * See ISO 18004:2006 6.5.1 Table 9 + */ + pub fn buildVersions() -> Vec { + Vec::from([ + Version::new( + 1, + Vec::from([]), + [ + ECBlocks::new(7, Vec::from([ECB::new(1, 19)])), + ECBlocks::new(10, Vec::from([ECB::new(1, 16)])), + ECBlocks::new(13, Vec::from([ECB::new(1, 13)])), + ECBlocks::new(17, Vec::from([ECB::new(1, 9)])), + ], + ), + Version::new( + 2, + Vec::from([6, 18]), + [ + ECBlocks::new(10, Vec::from([ECB::new(1, 34)])), + ECBlocks::new(16, Vec::from([ECB::new(1, 28)])), + ECBlocks::new(22, Vec::from([ECB::new(1, 22)])), + ECBlocks::new(28, Vec::from([ECB::new(1, 16)])), + ], + ), + Version::new( + 3, + Vec::from([6, 22]), + [ + ECBlocks::new(15, Vec::from([ECB::new(1, 55)])), + ECBlocks::new(26, Vec::from([ECB::new(1, 44)])), + ECBlocks::new(18, Vec::from([ECB::new(2, 17)])), + ECBlocks::new(22, Vec::from([ECB::new(2, 13)])), + ], + ), + Version::new( + 4, + Vec::from([6, 26]), + [ + ECBlocks::new(20, Vec::from([ECB::new(1, 80)])), + ECBlocks::new(18, Vec::from([ECB::new(2, 32)])), + ECBlocks::new(26, Vec::from([ECB::new(2, 24)])), + ECBlocks::new(16, Vec::from([ECB::new(4, 9)])), + ], + ), + Version::new( + 5, + Vec::from([6, 30]), + [ + ECBlocks::new(26, Vec::from([ECB::new(1, 108)])), + ECBlocks::new(24, Vec::from([ECB::new(2, 43)])), + ECBlocks::new(18, Vec::from([ECB::new(2, 15), ECB::new(2, 16)])), + ECBlocks::new(22, Vec::from([ECB::new(2, 11), ECB::new(2, 12)])), + ], + ), + Version::new( + 6, + Vec::from([6, 34]), + [ + ECBlocks::new(18, Vec::from([ECB::new(2, 68)])), + ECBlocks::new(16, Vec::from([ECB::new(4, 27)])), + ECBlocks::new(24, Vec::from([ECB::new(4, 19)])), + ECBlocks::new(28, Vec::from([ECB::new(4, 15)])), + ], + ), + Version::new( + 7, + Vec::from([6, 22, 38]), + [ + ECBlocks::new(20, Vec::from([ECB::new(2, 78)])), + ECBlocks::new(18, Vec::from([ECB::new(4, 31)])), + ECBlocks::new(18, Vec::from([ECB::new(2, 14), ECB::new(4, 15)])), + ECBlocks::new(26, Vec::from([ECB::new(4, 13), ECB::new(1, 14)])), + ], + ), + Version::new( + 8, + Vec::from([6, 24, 42]), + [ + ECBlocks::new(24, Vec::from([ECB::new(2, 97)])), + ECBlocks::new(22, Vec::from([ECB::new(2, 38), ECB::new(2, 39)])), + ECBlocks::new(22, Vec::from([ECB::new(4, 18), ECB::new(2, 19)])), + ECBlocks::new(26, Vec::from([ECB::new(4, 14), ECB::new(2, 15)])), + ], + ), + Version::new( + 9, + Vec::from([6, 26, 46]), + [ + ECBlocks::new(30, Vec::from([ECB::new(2, 116)])), + ECBlocks::new(22, Vec::from([ECB::new(3, 36), ECB::new(2, 37)])), + ECBlocks::new(20, Vec::from([ECB::new(4, 16), ECB::new(4, 17)])), + ECBlocks::new(24, Vec::from([ECB::new(4, 12), ECB::new(4, 13)])), + ], + ), + Version::new( + 10, + Vec::from([6, 28, 50]), + [ + ECBlocks::new(18, Vec::from([ECB::new(2, 68), ECB::new(2, 69)])), + ECBlocks::new(26, Vec::from([ECB::new(4, 43), ECB::new(1, 44)])), + ECBlocks::new(24, Vec::from([ECB::new(6, 19), ECB::new(2, 20)])), + ECBlocks::new(28, Vec::from([ECB::new(6, 15), ECB::new(2, 16)])), + ], + ), + Version::new( + 11, + Vec::from([6, 30, 54]), + [ + ECBlocks::new(20, Vec::from([ECB::new(4, 81)])), + ECBlocks::new(30, Vec::from([ECB::new(1, 50), ECB::new(4, 51)])), + ECBlocks::new(28, Vec::from([ECB::new(4, 22), ECB::new(4, 23)])), + ECBlocks::new(24, Vec::from([ECB::new(3, 12), ECB::new(8, 13)])), + ], + ), + Version::new( + 12, + Vec::from([6, 32, 58]), + [ + ECBlocks::new(24, Vec::from([ECB::new(2, 92), ECB::new(2, 93)])), + ECBlocks::new(22, Vec::from([ECB::new(6, 36), ECB::new(2, 37)])), + ECBlocks::new(26, Vec::from([ECB::new(4, 20), ECB::new(6, 21)])), + ECBlocks::new(28, Vec::from([ECB::new(7, 14), ECB::new(4, 15)])), + ], + ), + Version::new( + 13, + Vec::from([6, 34, 62]), + [ + ECBlocks::new(26, Vec::from([ECB::new(4, 107)])), + ECBlocks::new(22, Vec::from([ECB::new(8, 37), ECB::new(1, 38)])), + ECBlocks::new(24, Vec::from([ECB::new(8, 20), ECB::new(4, 21)])), + ECBlocks::new(22, Vec::from([ECB::new(12, 11), ECB::new(4, 12)])), + ], + ), + Version::new( + 14, + Vec::from([6, 26, 46, 66]), + [ + ECBlocks::new(30, Vec::from([ECB::new(3, 115), ECB::new(1, 116)])), + ECBlocks::new(24, Vec::from([ECB::new(4, 40), ECB::new(5, 41)])), + ECBlocks::new(20, Vec::from([ECB::new(11, 16), ECB::new(5, 17)])), + ECBlocks::new(24, Vec::from([ECB::new(11, 12), ECB::new(5, 13)])), + ], + ), + Version::new( + 15, + Vec::from([6, 26, 48, 70]), + [ + ECBlocks::new(22, Vec::from([ECB::new(5, 87), ECB::new(1, 88)])), + ECBlocks::new(24, Vec::from([ECB::new(5, 41), ECB::new(5, 42)])), + ECBlocks::new(30, Vec::from([ECB::new(5, 24), ECB::new(7, 25)])), + ECBlocks::new(24, Vec::from([ECB::new(11, 12), ECB::new(7, 13)])), + ], + ), + Version::new( + 16, + Vec::from([6, 26, 50, 74]), + [ + ECBlocks::new(24, Vec::from([ECB::new(5, 98), ECB::new(1, 99)])), + ECBlocks::new(28, Vec::from([ECB::new(7, 45), ECB::new(3, 46)])), + ECBlocks::new(24, Vec::from([ECB::new(15, 19), ECB::new(2, 20)])), + ECBlocks::new(30, Vec::from([ECB::new(3, 15), ECB::new(13, 16)])), + ], + ), + Version::new( + 17, + Vec::from([6, 30, 54, 78]), + [ + ECBlocks::new(28, Vec::from([ECB::new(1, 107), ECB::new(5, 108)])), + ECBlocks::new(28, Vec::from([ECB::new(10, 46), ECB::new(1, 47)])), + ECBlocks::new(28, Vec::from([ECB::new(1, 22), ECB::new(15, 23)])), + ECBlocks::new(28, Vec::from([ECB::new(2, 14), ECB::new(17, 15)])), + ], + ), + Version::new( + 18, + Vec::from([6, 30, 56, 82]), + [ + ECBlocks::new(30, Vec::from([ECB::new(5, 120), ECB::new(1, 121)])), + ECBlocks::new(26, Vec::from([ECB::new(9, 43), ECB::new(4, 44)])), + ECBlocks::new(28, Vec::from([ECB::new(17, 22), ECB::new(1, 23)])), + ECBlocks::new(28, Vec::from([ECB::new(2, 14), ECB::new(19, 15)])), + ], + ), + Version::new( + 19, + Vec::from([6, 30, 58, 86]), + [ + ECBlocks::new(28, Vec::from([ECB::new(3, 113), ECB::new(4, 114)])), + ECBlocks::new(26, Vec::from([ECB::new(3, 44), ECB::new(11, 45)])), + ECBlocks::new(26, Vec::from([ECB::new(17, 21), ECB::new(4, 22)])), + ECBlocks::new(26, Vec::from([ECB::new(9, 13), ECB::new(16, 14)])), + ], + ), + Version::new( + 20, + Vec::from([6, 34, 62, 90]), + [ + ECBlocks::new(28, Vec::from([ECB::new(3, 107), ECB::new(5, 108)])), + ECBlocks::new(26, Vec::from([ECB::new(3, 41), ECB::new(13, 42)])), + ECBlocks::new(30, Vec::from([ECB::new(15, 24), ECB::new(5, 25)])), + ECBlocks::new(28, Vec::from([ECB::new(15, 15), ECB::new(10, 16)])), + ], + ), + Version::new( + 21, + Vec::from([6, 28, 50, 72, 94]), + [ + ECBlocks::new(28, Vec::from([ECB::new(4, 116), ECB::new(4, 117)])), + ECBlocks::new(26, Vec::from([ECB::new(17, 42)])), + ECBlocks::new(28, Vec::from([ECB::new(17, 22), ECB::new(6, 23)])), + ECBlocks::new(30, Vec::from([ECB::new(19, 16), ECB::new(6, 17)])), + ], + ), + Version::new( + 22, + Vec::from([6, 26, 50, 74, 98]), + [ + ECBlocks::new(28, Vec::from([ECB::new(2, 111), ECB::new(7, 112)])), + ECBlocks::new(28, Vec::from([ECB::new(17, 46)])), + ECBlocks::new(30, Vec::from([ECB::new(7, 24), ECB::new(16, 25)])), + ECBlocks::new(24, Vec::from([ECB::new(34, 13)])), + ], + ), + Version::new( + 23, + Vec::from([6, 30, 54, 78, 102]), + [ + ECBlocks::new(30, Vec::from([ECB::new(4, 121), ECB::new(5, 122)])), + ECBlocks::new(28, Vec::from([ECB::new(4, 47), ECB::new(14, 48)])), + ECBlocks::new(30, Vec::from([ECB::new(11, 24), ECB::new(14, 25)])), + ECBlocks::new(30, Vec::from([ECB::new(16, 15), ECB::new(14, 16)])), + ], + ), + Version::new( + 24, + Vec::from([6, 28, 54, 80, 106]), + [ + ECBlocks::new(30, Vec::from([ECB::new(6, 117), ECB::new(4, 118)])), + ECBlocks::new(28, Vec::from([ECB::new(6, 45), ECB::new(14, 46)])), + ECBlocks::new(30, Vec::from([ECB::new(11, 24), ECB::new(16, 25)])), + ECBlocks::new(30, Vec::from([ECB::new(30, 16), ECB::new(2, 17)])), + ], + ), + Version::new( + 25, + Vec::from([6, 32, 58, 84, 110]), + [ + ECBlocks::new(26, Vec::from([ECB::new(8, 106), ECB::new(4, 107)])), + ECBlocks::new(28, Vec::from([ECB::new(8, 47), ECB::new(13, 48)])), + ECBlocks::new(30, Vec::from([ECB::new(7, 24), ECB::new(22, 25)])), + ECBlocks::new(30, Vec::from([ECB::new(22, 15), ECB::new(13, 16)])), + ], + ), + Version::new( + 26, + Vec::from([6, 30, 58, 86, 114]), + [ + ECBlocks::new(28, Vec::from([ECB::new(10, 114), ECB::new(2, 115)])), + ECBlocks::new(28, Vec::from([ECB::new(19, 46), ECB::new(4, 47)])), + ECBlocks::new(28, Vec::from([ECB::new(28, 22), ECB::new(6, 23)])), + ECBlocks::new(30, Vec::from([ECB::new(33, 16), ECB::new(4, 17)])), + ], + ), + Version::new( + 27, + Vec::from([6, 34, 62, 90, 118]), + [ + ECBlocks::new(30, Vec::from([ECB::new(8, 122), ECB::new(4, 123)])), + ECBlocks::new(28, Vec::from([ECB::new(22, 45), ECB::new(3, 46)])), + ECBlocks::new(30, Vec::from([ECB::new(8, 23), ECB::new(26, 24)])), + ECBlocks::new(30, Vec::from([ECB::new(12, 15), ECB::new(28, 16)])), + ], + ), + Version::new( + 28, + Vec::from([6, 26, 50, 74, 98, 122]), + [ + ECBlocks::new(30, Vec::from([ECB::new(3, 117), ECB::new(10, 118)])), + ECBlocks::new(28, Vec::from([ECB::new(3, 45), ECB::new(23, 46)])), + ECBlocks::new(30, Vec::from([ECB::new(4, 24), ECB::new(31, 25)])), + ECBlocks::new(30, Vec::from([ECB::new(11, 15), ECB::new(31, 16)])), + ], + ), + Version::new( + 29, + Vec::from([6, 30, 54, 78, 102, 126]), + [ + ECBlocks::new(30, Vec::from([ECB::new(7, 116), ECB::new(7, 117)])), + ECBlocks::new(28, Vec::from([ECB::new(21, 45), ECB::new(7, 46)])), + ECBlocks::new(30, Vec::from([ECB::new(1, 23), ECB::new(37, 24)])), + ECBlocks::new(30, Vec::from([ECB::new(19, 15), ECB::new(26, 16)])), + ], + ), + Version::new( + 30, + Vec::from([6, 26, 52, 78, 104, 130]), + [ + ECBlocks::new(30, Vec::from([ECB::new(5, 115), ECB::new(10, 116)])), + ECBlocks::new(28, Vec::from([ECB::new(19, 47), ECB::new(10, 48)])), + ECBlocks::new(30, Vec::from([ECB::new(15, 24), ECB::new(25, 25)])), + ECBlocks::new(30, Vec::from([ECB::new(23, 15), ECB::new(25, 16)])), + ], + ), + Version::new( + 31, + Vec::from([6, 30, 56, 82, 108, 134]), + [ + ECBlocks::new(30, Vec::from([ECB::new(13, 115), ECB::new(3, 116)])), + ECBlocks::new(28, Vec::from([ECB::new(2, 46), ECB::new(29, 47)])), + ECBlocks::new(30, Vec::from([ECB::new(42, 24), ECB::new(1, 25)])), + ECBlocks::new(30, Vec::from([ECB::new(23, 15), ECB::new(28, 16)])), + ], + ), + Version::new( + 32, + Vec::from([6, 34, 60, 86, 112, 138]), + [ + ECBlocks::new(30, Vec::from([ECB::new(17, 115)])), + ECBlocks::new(28, Vec::from([ECB::new(10, 46), ECB::new(23, 47)])), + ECBlocks::new(30, Vec::from([ECB::new(10, 24), ECB::new(35, 25)])), + ECBlocks::new(30, Vec::from([ECB::new(19, 15), ECB::new(35, 16)])), + ], + ), + Version::new( + 33, + Vec::from([6, 30, 58, 86, 114, 142]), + [ + ECBlocks::new(30, Vec::from([ECB::new(17, 115), ECB::new(1, 116)])), + ECBlocks::new(28, Vec::from([ECB::new(14, 46), ECB::new(21, 47)])), + ECBlocks::new(30, Vec::from([ECB::new(29, 24), ECB::new(19, 25)])), + ECBlocks::new(30, Vec::from([ECB::new(11, 15), ECB::new(46, 16)])), + ], + ), + Version::new( + 34, + Vec::from([6, 34, 62, 90, 118, 146]), + [ + ECBlocks::new(30, Vec::from([ECB::new(13, 115), ECB::new(6, 116)])), + ECBlocks::new(28, Vec::from([ECB::new(14, 46), ECB::new(23, 47)])), + ECBlocks::new(30, Vec::from([ECB::new(44, 24), ECB::new(7, 25)])), + ECBlocks::new(30, Vec::from([ECB::new(59, 16), ECB::new(1, 17)])), + ], + ), + Version::new( + 35, + Vec::from([6, 30, 54, 78, 102, 126, 150]), + [ + ECBlocks::new(30, Vec::from([ECB::new(12, 121), ECB::new(7, 122)])), + ECBlocks::new(28, Vec::from([ECB::new(12, 47), ECB::new(26, 48)])), + ECBlocks::new(30, Vec::from([ECB::new(39, 24), ECB::new(14, 25)])), + ECBlocks::new(30, Vec::from([ECB::new(22, 15), ECB::new(41, 16)])), + ], + ), + Version::new( + 36, + Vec::from([6, 24, 50, 76, 102, 128, 154]), + [ + ECBlocks::new(30, Vec::from([ECB::new(6, 121), ECB::new(14, 122)])), + ECBlocks::new(28, Vec::from([ECB::new(6, 47), ECB::new(34, 48)])), + ECBlocks::new(30, Vec::from([ECB::new(46, 24), ECB::new(10, 25)])), + ECBlocks::new(30, Vec::from([ECB::new(2, 15), ECB::new(64, 16)])), + ], + ), + Version::new( + 37, + Vec::from([6, 28, 54, 80, 106, 132, 158]), + [ + ECBlocks::new(30, Vec::from([ECB::new(17, 122), ECB::new(4, 123)])), + ECBlocks::new(28, Vec::from([ECB::new(29, 46), ECB::new(14, 47)])), + ECBlocks::new(30, Vec::from([ECB::new(49, 24), ECB::new(10, 25)])), + ECBlocks::new(30, Vec::from([ECB::new(24, 15), ECB::new(46, 16)])), + ], + ), + Version::new( + 38, + Vec::from([6, 32, 58, 84, 110, 136, 162]), + [ + ECBlocks::new(30, Vec::from([ECB::new(4, 122), ECB::new(18, 123)])), + ECBlocks::new(28, Vec::from([ECB::new(13, 46), ECB::new(32, 47)])), + ECBlocks::new(30, Vec::from([ECB::new(48, 24), ECB::new(14, 25)])), + ECBlocks::new(30, Vec::from([ECB::new(42, 15), ECB::new(32, 16)])), + ], + ), + Version::new( + 39, + Vec::from([6, 26, 54, 82, 110, 138, 166]), + [ + ECBlocks::new(30, Vec::from([ECB::new(20, 117), ECB::new(4, 118)])), + ECBlocks::new(28, Vec::from([ECB::new(40, 47), ECB::new(7, 48)])), + ECBlocks::new(30, Vec::from([ECB::new(43, 24), ECB::new(22, 25)])), + ECBlocks::new(30, Vec::from([ECB::new(10, 15), ECB::new(67, 16)])), + ], + ), + Version::new( + 40, + Vec::from([6, 30, 58, 86, 114, 142, 170]), + [ + ECBlocks::new(30, Vec::from([ECB::new(19, 118), ECB::new(6, 119)])), + ECBlocks::new(28, Vec::from([ECB::new(18, 47), ECB::new(31, 48)])), + ECBlocks::new(30, Vec::from([ECB::new(34, 24), ECB::new(34, 25)])), + ECBlocks::new(30, Vec::from([ECB::new(20, 15), ECB::new(61, 16)])), + ], + ), + ]) /* + new Version(4, new int[]{6, 26}, + new ECBlocks(20, new ECB::new(1, 80)), + new ECBlocks(18, new ECB::new(2, 32)), + new ECBlocks(26, new ECB::new(2, 24)), + new ECBlocks(16, new ECB::new(4, 9))), + new Version(5, new int[]{6, 30}, + new ECBlocks(26, new ECB::new(1, 108)), + new ECBlocks(24, new ECB::new(2, 43)), + new ECBlocks(18, new ECB::new(2, 15), + new ECB::new(2, 16)), + new ECBlocks(22, new ECB::new(2, 11), + new ECB::new(2, 12))), + new Version(6, new int[]{6, 34}, + new ECBlocks(18, new ECB::new(2, 68)), + new ECBlocks(16, new ECB::new(4, 27)), + new ECBlocks(24, new ECB::new(4, 19)), + new ECBlocks(28, new ECB::new(4, 15))), + new Version(7, new int[]{6, 22, 38}, + new ECBlocks(20, new ECB::new(2, 78)), + new ECBlocks(18, new ECB::new(4, 31)), + new ECBlocks(18, new ECB::new(2, 14), + new ECB::new(4, 15)), + new ECBlocks(26, new ECB::new(4, 13), + new ECB::new(1, 14))), + new Version(8, new int[]{6, 24, 42}, + new ECBlocks(24, new ECB::new(2, 97)), + new ECBlocks(22, new ECB::new(2, 38), + new ECB::new(2, 39)), + new ECBlocks(22, new ECB::new(4, 18), + new ECB::new(2, 19)), + new ECBlocks(26, new ECB::new(4, 14), + new ECB::new(2, 15))), + new Version(9, new int[]{6, 26, 46}, + new ECBlocks(30, new ECB::new(2, 116)), + new ECBlocks(22, new ECB::new(3, 36), + new ECB::new(2, 37)), + new ECBlocks(20, new ECB::new(4, 16), + new ECB::new(4, 17)), + new ECBlocks(24, new ECB::new(4, 12), + new ECB::new(4, 13))), + new Version(10, new int[]{6, 28, 50}, + new ECBlocks(18, new ECB::new(2, 68), + new ECB::new(2, 69)), + new ECBlocks(26, new ECB::new(4, 43), + new ECB::new(1, 44)), + new ECBlocks(24, new ECB::new(6, 19), + new ECB::new(2, 20)), + new ECBlocks(28, new ECB::new(6, 15), + new ECB::new(2, 16))), + new Version(11, new int[]{6, 30, 54}, + new ECBlocks(20, new ECB::new(4, 81)), + new ECBlocks(30, new ECB::new(1, 50), + new ECB::new(4, 51)), + new ECBlocks(28, new ECB::new(4, 22), + new ECB::new(4, 23)), + new ECBlocks(24, new ECB::new(3, 12), + new ECB::new(8, 13))), + new Version(12, new int[]{6, 32, 58}, + new ECBlocks(24, new ECB::new(2, 92), + new ECB::new(2, 93)), + new ECBlocks(22, new ECB::new(6, 36), + new ECB::new(2, 37)), + new ECBlocks(26, new ECB::new(4, 20), + new ECB::new(6, 21)), + new ECBlocks(28, new ECB::new(7, 14), + new ECB::new(4, 15))), + new Version(13, new int[]{6, 34, 62}, + new ECBlocks(26, new ECB::new(4, 107)), + new ECBlocks(22, new ECB::new(8, 37), + new ECB::new(1, 38)), + new ECBlocks(24, new ECB::new(8, 20), + new ECB::new(4, 21)), + new ECBlocks(22, new ECB::new(12, 11), + new ECB::new(4, 12))), + new Version(14, new int[]{6, 26, 46, 66}, + new ECBlocks(30, new ECB::new(3, 115), + new ECB::new(1, 116)), + new ECBlocks(24, new ECB::new(4, 40), + new ECB::new(5, 41)), + new ECBlocks(20, new ECB::new(11, 16), + new ECB::new(5, 17)), + new ECBlocks(24, new ECB::new(11, 12), + new ECB::new(5, 13))), + new Version(15, new int[]{6, 26, 48, 70}, + new ECBlocks(22, new ECB::new(5, 87), + new ECB::new(1, 88)), + new ECBlocks(24, new ECB::new(5, 41), + new ECB::new(5, 42)), + new ECBlocks(30, new ECB::new(5, 24), + new ECB::new(7, 25)), + new ECBlocks(24, new ECB::new(11, 12), + new ECB::new(7, 13))), + new Version(16, new int[]{6, 26, 50, 74}, + new ECBlocks(24, new ECB::new(5, 98), + new ECB::new(1, 99)), + new ECBlocks(28, new ECB::new(7, 45), + new ECB::new(3, 46)), + new ECBlocks(24, new ECB::new(15, 19), + new ECB::new(2, 20)), + new ECBlocks(30, new ECB::new(3, 15), + new ECB::new(13, 16))), + new Version(17, new int[]{6, 30, 54, 78}, + new ECBlocks(28, new ECB::new(1, 107), + new ECB::new(5, 108)), + new ECBlocks(28, new ECB::new(10, 46), + new ECB::new(1, 47)), + new ECBlocks(28, new ECB::new(1, 22), + new ECB::new(15, 23)), + new ECBlocks(28, new ECB::new(2, 14), + new ECB::new(17, 15))), + new Version(18, new int[]{6, 30, 56, 82}, + new ECBlocks(30, new ECB::new(5, 120), + new ECB::new(1, 121)), + new ECBlocks(26, new ECB::new(9, 43), + new ECB::new(4, 44)), + new ECBlocks(28, new ECB::new(17, 22), + new ECB::new(1, 23)), + new ECBlocks(28, new ECB::new(2, 14), + new ECB::new(19, 15))), + new Version(19, new int[]{6, 30, 58, 86}, + new ECBlocks(28, new ECB::new(3, 113), + new ECB::new(4, 114)), + new ECBlocks(26, new ECB::new(3, 44), + new ECB::new(11, 45)), + new ECBlocks(26, new ECB::new(17, 21), + new ECB::new(4, 22)), + new ECBlocks(26, new ECB::new(9, 13), + new ECB::new(16, 14))), + new Version(20, new int[]{6, 34, 62, 90}, + new ECBlocks(28, new ECB::new(3, 107), + new ECB::new(5, 108)), + new ECBlocks(26, new ECB::new(3, 41), + new ECB::new(13, 42)), + new ECBlocks(30, new ECB::new(15, 24), + new ECB::new(5, 25)), + new ECBlocks(28, new ECB::new(15, 15), + new ECB::new(10, 16))), + new Version(21, new int[]{6, 28, 50, 72, 94}, + new ECBlocks(28, new ECB::new(4, 116), + new ECB::new(4, 117)), + new ECBlocks(26, new ECB::new(17, 42)), + new ECBlocks(28, new ECB::new(17, 22), + new ECB::new(6, 23)), + new ECBlocks(30, new ECB::new(19, 16), + new ECB::new(6, 17))), + new Version(22, new int[]{6, 26, 50, 74, 98}, + new ECBlocks(28, new ECB::new(2, 111), + new ECB::new(7, 112)), + new ECBlocks(28, new ECB::new(17, 46)), + new ECBlocks(30, new ECB::new(7, 24), + new ECB::new(16, 25)), + new ECBlocks(24, new ECB::new(34, 13))), + new Version(23, new int[]{6, 30, 54, 78, 102}, + new ECBlocks(30, new ECB::new(4, 121), + new ECB::new(5, 122)), + new ECBlocks(28, new ECB::new(4, 47), + new ECB::new(14, 48)), + new ECBlocks(30, new ECB::new(11, 24), + new ECB::new(14, 25)), + new ECBlocks(30, new ECB::new(16, 15), + new ECB::new(14, 16))), + new Version(24, new int[]{6, 28, 54, 80, 106}, + new ECBlocks(30, new ECB::new(6, 117), + new ECB::new(4, 118)), + new ECBlocks(28, new ECB::new(6, 45), + new ECB::new(14, 46)), + new ECBlocks(30, new ECB::new(11, 24), + new ECB::new(16, 25)), + new ECBlocks(30, new ECB::new(30, 16), + new ECB::new(2, 17))), + new Version(25, new int[]{6, 32, 58, 84, 110}, + new ECBlocks(26, new ECB::new(8, 106), + new ECB::new(4, 107)), + new ECBlocks(28, new ECB::new(8, 47), + new ECB::new(13, 48)), + new ECBlocks(30, new ECB::new(7, 24), + new ECB::new(22, 25)), + new ECBlocks(30, new ECB::new(22, 15), + new ECB::new(13, 16))), + new Version(26, new int[]{6, 30, 58, 86, 114}, + new ECBlocks(28, new ECB::new(10, 114), + new ECB::new(2, 115)), + new ECBlocks(28, new ECB::new(19, 46), + new ECB::new(4, 47)), + new ECBlocks(28, new ECB::new(28, 22), + new ECB::new(6, 23)), + new ECBlocks(30, new ECB::new(33, 16), + new ECB::new(4, 17))), + new Version(27, new int[]{6, 34, 62, 90, 118}, + new ECBlocks(30, new ECB::new(8, 122), + new ECB::new(4, 123)), + new ECBlocks(28, new ECB::new(22, 45), + new ECB::new(3, 46)), + new ECBlocks(30, new ECB::new(8, 23), + new ECB::new(26, 24)), + new ECBlocks(30, new ECB::new(12, 15), + new ECB::new(28, 16))), + new Version(28, new int[]{6, 26, 50, 74, 98, 122}, + new ECBlocks(30, new ECB::new(3, 117), + new ECB::new(10, 118)), + new ECBlocks(28, new ECB::new(3, 45), + new ECB::new(23, 46)), + new ECBlocks(30, new ECB::new(4, 24), + new ECB::new(31, 25)), + new ECBlocks(30, new ECB::new(11, 15), + new ECB::new(31, 16))), + new Version(29, new int[]{6, 30, 54, 78, 102, 126}, + new ECBlocks(30, new ECB::new(7, 116), + new ECB::new(7, 117)), + new ECBlocks(28, new ECB::new(21, 45), + new ECB::new(7, 46)), + new ECBlocks(30, new ECB::new(1, 23), + new ECB::new(37, 24)), + new ECBlocks(30, new ECB::new(19, 15), + new ECB::new(26, 16))), + new Version(30, new int[]{6, 26, 52, 78, 104, 130}, + new ECBlocks(30, new ECB::new(5, 115), + new ECB::new(10, 116)), + new ECBlocks(28, new ECB::new(19, 47), + new ECB::new(10, 48)), + new ECBlocks(30, new ECB::new(15, 24), + new ECB::new(25, 25)), + new ECBlocks(30, new ECB::new(23, 15), + new ECB::new(25, 16))), + new Version(31, new int[]{6, 30, 56, 82, 108, 134}, + new ECBlocks(30, new ECB::new(13, 115), + new ECB::new(3, 116)), + new ECBlocks(28, new ECB::new(2, 46), + new ECB::new(29, 47)), + new ECBlocks(30, new ECB::new(42, 24), + new ECB::new(1, 25)), + new ECBlocks(30, new ECB::new(23, 15), + new ECB::new(28, 16))), + new Version(32, new int[]{6, 34, 60, 86, 112, 138}, + new ECBlocks(30, new ECB::new(17, 115)), + new ECBlocks(28, new ECB::new(10, 46), + new ECB::new(23, 47)), + new ECBlocks(30, new ECB::new(10, 24), + new ECB::new(35, 25)), + new ECBlocks(30, new ECB::new(19, 15), + new ECB::new(35, 16))), + new Version(33, new int[]{6, 30, 58, 86, 114, 142}, + new ECBlocks(30, new ECB::new(17, 115), + new ECB::new(1, 116)), + new ECBlocks(28, new ECB::new(14, 46), + new ECB::new(21, 47)), + new ECBlocks(30, new ECB::new(29, 24), + new ECB::new(19, 25)), + new ECBlocks(30, new ECB::new(11, 15), + new ECB::new(46, 16))), + new Version(34, new int[]{6, 34, 62, 90, 118, 146}, + new ECBlocks(30, new ECB::new(13, 115), + new ECB::new(6, 116)), + new ECBlocks(28, new ECB::new(14, 46), + new ECB::new(23, 47)), + new ECBlocks(30, new ECB::new(44, 24), + new ECB::new(7, 25)), + new ECBlocks(30, new ECB::new(59, 16), + new ECB::new(1, 17))), + new Version(35, new int[]{6, 30, 54, 78, 102, 126, 150}, + new ECBlocks(30, new ECB::new(12, 121), + new ECB::new(7, 122)), + new ECBlocks(28, new ECB::new(12, 47), + new ECB::new(26, 48)), + new ECBlocks(30, new ECB::new(39, 24), + new ECB::new(14, 25)), + new ECBlocks(30, new ECB::new(22, 15), + new ECB::new(41, 16))), + new Version(36, new int[]{6, 24, 50, 76, 102, 128, 154}, + new ECBlocks(30, new ECB::new(6, 121), + new ECB::new(14, 122)), + new ECBlocks(28, new ECB::new(6, 47), + new ECB::new(34, 48)), + new ECBlocks(30, new ECB::new(46, 24), + new ECB::new(10, 25)), + new ECBlocks(30, new ECB::new(2, 15), + new ECB::new(64, 16))), + new Version(37, new int[]{6, 28, 54, 80, 106, 132, 158}, + new ECBlocks(30, new ECB::new(17, 122), + new ECB::new(4, 123)), + new ECBlocks(28, new ECB::new(29, 46), + new ECB::new(14, 47)), + new ECBlocks(30, new ECB::new(49, 24), + new ECB::new(10, 25)), + new ECBlocks(30, new ECB::new(24, 15), + new ECB::new(46, 16))), + new Version(38, new int[]{6, 32, 58, 84, 110, 136, 162}, + new ECBlocks(30, new ECB::new(4, 122), + new ECB::new(18, 123)), + new ECBlocks(28, new ECB::new(13, 46), + new ECB::new(32, 47)), + new ECBlocks(30, new ECB::new(48, 24), + new ECB::new(14, 25)), + new ECBlocks(30, new ECB::new(42, 15), + new ECB::new(32, 16))), + new Version(39, new int[]{6, 26, 54, 82, 110, 138, 166}, + new ECBlocks(30, new ECB::new(20, 117), + new ECB::new(4, 118)), + new ECBlocks(28, new ECB::new(40, 47), + new ECB::new(7, 48)), + new ECBlocks(30, new ECB::new(43, 24), + new ECB::new(22, 25)), + new ECBlocks(30, new ECB::new(10, 15), + new ECB::new(67, 16))), + new Version(40, new int[]{6, 30, 58, 86, 114, 142, 170}, + new ECBlocks(30, new ECB::new(19, 118), + new ECB::new(6, 119)), + new ECBlocks(28, new ECB::new(18, 47), + new ECB::new(31, 48)), + new ECBlocks(30, new ECB::new(34, 24), + new ECB::new(34, 25)), + new ECBlocks(30, new ECB::new(20, 15), + new ECB::new(61, 16))) + ]*/ + } + + /* + * {1, { + 7 , 1, 19, 0, 0, + 10, 1, 16, 0, 0, + 13, 1, 13, 0, 0, + 17, 1, 9 , 0, 0 + }}, + {2, { + 10, 1, 36, 0, 0, + 16, 1, 30, 0, 0, + 22, 1, 24, 0, 0, + 30, 1, 16, 0, 0, + }}, + {3, { + 15, 1, 57, 0, 0, + 28, 1, 44, 0, 0, + 36, 1, 36, 0, 0, + 48, 1, 24, 0, 0, + }}, + {4, { + 20, 1, 80, 0, 0, + 40, 1, 60, 0, 0, + 50, 1, 50, 0, 0, + 66, 1, 34, 0, 0, + }}, + {5, { + 26, 1, 108, 0, 0, + 52, 1, 82 , 0, 0, + 66, 1, 68 , 0, 0, + 88, 2, 46 , 0, 0, + }}, + {6, { + 34 , 1, 136, 0, 0, + 63 , 2, 106, 0, 0, + 84 , 2, 86 , 0, 0, + 112, 2, 58 , 0, 0, + }}, + {7, { + 42 , 1, 170, 0, 0, + 80 , 2, 132, 0, 0, + 104, 2, 108, 0, 0, + 138, 3, 72 , 0, 0, + }}, + {8, { + 48 , 2, 208, 0, 0, + 96 , 2, 160, 0, 0, + 128, 2, 128, 0, 0, + 168, 3, 87 , 0, 0, + }}, + {9, { + 60 , 2, 246, 0, 0, + 120, 2, 186, 0, 0, + 150, 3, 156, 0, 0, + 204, 3, 102, 0, 0, + }}, + {10, { + 68 , 2, 290, 0, 0, + 136, 2, 222, 0, 0, + 174, 3, 183, 0, 0, + 232, 4, 124, 0, 0, + }}, + {11, { + 80 , 2, 336, 0, 0, + 160, 4, 256, 0, 0, + 208, 4, 208, 0, 0, + 270, 5, 145, 0, 0, + }}, + {12, { + 92 , 2, 384, 0, 0, + 184, 4, 292, 0, 0, + 232, 4, 244, 0, 0, + 310, 5, 165, 0, 0, + }}, + {13, { + 108, 3, 432, 0, 0, + 208, 4, 332, 0, 0, + 264, 4, 276, 0, 0, + 348, 6, 192, 0, 0, + }}, + {14, { + 120, 3, 489, 0, 0, + 240, 4, 368, 0, 0, + 300, 5, 310, 0, 0, + 396, 6, 210, 0, 0, + }}, + }; + */ + pub fn build_model1_versions() -> Vec { + Vec::from([ + Version::new_model1( + 1, + vec![ + ECBlocks::new(7, vec![ECB::new(1, 19)]), + ECBlocks::new(10, vec![ECB::new(1, 16)]), + ECBlocks::new(13, vec![ECB::new(1, 13)]), + ECBlocks::new(17, vec![ECB::new(1, 9)]), + ], + ), + Version::new_model1( + 2, + vec![ + ECBlocks::new(10, vec![ECB::new(1, 36)]), + ECBlocks::new(16, vec![ECB::new(1, 30)]), + ECBlocks::new(22, vec![ECB::new(1, 24)]), + ECBlocks::new(30, vec![ECB::new(1, 16)]), + ], + ), + Version::new_model1( + 3, + vec![ + ECBlocks::new(15, vec![ECB::new(1, 57)]), + ECBlocks::new(28, vec![ECB::new(1, 44)]), + ECBlocks::new(36, vec![ECB::new(1, 36)]), + ECBlocks::new(48, vec![ECB::new(1, 24)]), + ], + ), + Version::new_model1( + 4, + vec![ + ECBlocks::new(20, vec![ECB::new(1, 80)]), + ECBlocks::new(40, vec![ECB::new(1, 60)]), + ECBlocks::new(50, vec![ECB::new(1, 50)]), + ECBlocks::new(66, vec![ECB::new(1, 34)]), + ], + ), + Version::new_model1( + 5, + vec![ + ECBlocks::new(26, vec![ECB::new(1, 108)]), + ECBlocks::new(52, vec![ECB::new(1, 82)]), + ECBlocks::new(66, vec![ECB::new(1, 68)]), + ECBlocks::new(88, vec![ECB::new(2, 46)]), + ], + ), + Version::new_model1( + 6, + vec![ + ECBlocks::new(34, vec![ECB::new(1, 136)]), + ECBlocks::new(63, vec![ECB::new(2, 106)]), + ECBlocks::new(84, vec![ECB::new(2, 86)]), + ECBlocks::new(112, vec![ECB::new(2, 58)]), + ], + ), + Version::new_model1( + 7, + vec![ + ECBlocks::new(42, vec![ECB::new(1, 170)]), + ECBlocks::new(80, vec![ECB::new(2, 132)]), + ECBlocks::new(104, vec![ECB::new(2, 108)]), + ECBlocks::new(138, vec![ECB::new(3, 72)]), + ], + ), + Version::new_model1( + 8, + vec![ + ECBlocks::new(48, vec![ECB::new(2, 208)]), + ECBlocks::new(96, vec![ECB::new(2, 160)]), + ECBlocks::new(128, vec![ECB::new(2, 128)]), + ECBlocks::new(168, vec![ECB::new(3, 87)]), + ], + ), + Version::new_model1( + 9, + vec![ + ECBlocks::new(60, vec![ECB::new(2, 246)]), + ECBlocks::new(120, vec![ECB::new(2, 186)]), + ECBlocks::new(150, vec![ECB::new(3, 156)]), + ECBlocks::new(204, vec![ECB::new(3, 102)]), + ], + ), + Version::new_model1( + 10, + vec![ + ECBlocks::new(68, vec![ECB::new(2, 290)]), + ECBlocks::new(136, vec![ECB::new(2, 222)]), + ECBlocks::new(174, vec![ECB::new(3, 183)]), + ECBlocks::new(232, vec![ECB::new(4, 124)]), + ], + ), + Version::new_model1( + 11, + vec![ + ECBlocks::new(80, vec![ECB::new(2, 336)]), + ECBlocks::new(160, vec![ECB::new(4, 256)]), + ECBlocks::new(208, vec![ECB::new(4, 208)]), + ECBlocks::new(270, vec![ECB::new(5, 145)]), + ], + ), + Version::new_model1( + 12, + vec![ + ECBlocks::new(92, vec![ECB::new(2, 384)]), + ECBlocks::new(184, vec![ECB::new(4, 292)]), + ECBlocks::new(232, vec![ECB::new(4, 244)]), + ECBlocks::new(310, vec![ECB::new(5, 165)]), + ], + ), + Version::new_model1( + 13, + vec![ + ECBlocks::new(108, vec![ECB::new(3, 432)]), + ECBlocks::new(208, vec![ECB::new(4, 332)]), + ECBlocks::new(264, vec![ECB::new(4, 276)]), + ECBlocks::new(348, vec![ECB::new(6, 192)]), + ], + ), + Version::new_model1( + 14, + vec![ + ECBlocks::new(120, vec![ECB::new(3, 489)]), + ECBlocks::new(240, vec![ECB::new(4, 368)]), + ECBlocks::new(300, vec![ECB::new(5, 310)]), + ECBlocks::new(396, vec![ECB::new(6, 210)]), + ], + ), + ]) + } + + pub fn build_rmqr_versions() -> Vec { + Vec::from([ + Version::new( + 1, + Vec::from([21]), + [ + // R7x43 + // 4 `ECBlocks`, one for each `ecLevel` - rMQR only uses M & H but using 2 dummies to keep `ecLevel` index same as QR Code + // Each begins with no. of error correction codewords divided by no. of error correction blocks, followed by 2 `ECBlock`s + // Each `ECBlock` begins with no. of error correction blocks followed by no. of data codewords per block + ECBlocks::new(0, Vec::from([ECB::new(0, 0)])), // L (dummy) - also used to differentiate rMQR from Model2 in `Version::Version()` + ECBlocks::new(7, Vec::from([ECB::new(1, 6)])), // M + ECBlocks::new(0, Vec::from([ECB::new(0, 0)])), // Q (dummy) + ECBlocks::new(10, Vec::from([ECB::new(1, 3)])), // H + ], + ), + Version::new( + 2, + Vec::from([19, 39]), + [ + // R7x59 + ECBlocks::new(0, Vec::from([ECB::new(0, 0)])), + ECBlocks::new(9, Vec::from([ECB::new(1, 12)])), + ECBlocks::new(0, Vec::from([ECB::new(0, 0)])), + ECBlocks::new(14, Vec::from([ECB::new(1, 7)])), + ], + ), + Version::new( + 3, + Vec::from([25, 51]), + [ + // R7x77 + ECBlocks::new(0, Vec::from([ECB::new(0, 0)])), + ECBlocks::new(12, Vec::from([ECB::new(1, 20)])), + ECBlocks::new(0, Vec::from([ECB::new(0, 0)])), + ECBlocks::new(22, Vec::from([ECB::new(1, 10)])), + ], + ), + Version::new( + 4, + Vec::from([23, 49, 75]), + [ + // R7x99 + ECBlocks::new(0, Vec::from([ECB::new(0, 0)])), + ECBlocks::new(16, Vec::from([ECB::new(1, 28)])), + ECBlocks::new(0, Vec::from([ECB::new(0, 0)])), + ECBlocks::new(30, Vec::from([ECB::new(1, 14)])), + ], + ), + Version::new( + 5, + Vec::from([27, 55, 83, 111]), + [ + // R7x139 + ECBlocks::new(0, Vec::from([ECB::new(0, 0)])), + ECBlocks::new(24, Vec::from([ECB::new(1, 44)])), + ECBlocks::new(0, Vec::from([ECB::new(0, 0)])), + ECBlocks::new(22, Vec::from([ECB::new(2, 12)])), + ], + ), + Version::new( + 6, + Vec::from([21]), + [ + // R9x43 + ECBlocks::new(0, Vec::from([ECB::new(0, 0)])), + ECBlocks::new(9, Vec::from([ECB::new(1, 12)])), + ECBlocks::new(0, Vec::from([ECB::new(0, 0)])), + ECBlocks::new(14, Vec::from([ECB::new(1, 7)])), + ], + ), + Version::new( + 7, + Vec::from([19, 39]), + [ + // R9x59 + ECBlocks::new(0, Vec::from([ECB::new(0, 0)])), + ECBlocks::new(12, Vec::from([ECB::new(1, 21)])), + ECBlocks::new(0, Vec::from([ECB::new(0, 0)])), + ECBlocks::new(22, Vec::from([ECB::new(1, 11)])), + ], + ), + Version::new( + 8, + Vec::from([25, 51]), + [ + // R9x77 + ECBlocks::new(0, Vec::from([ECB::new(0, 0)])), + ECBlocks::new(18, Vec::from([ECB::new(1, 31)])), + ECBlocks::new(0, Vec::from([ECB::new(0, 0)])), + ECBlocks::new(16, Vec::from([ECB::new(1, 8), ECB::new(1, 9)])), + ], + ), + Version::new( + 9, + Vec::from([23, 49, 75]), + [ + // R9x99 + ECBlocks::new(0, Vec::from([ECB::new(0, 0)])), + ECBlocks::new(24, Vec::from([ECB::new(1, 42)])), + ECBlocks::new(0, Vec::from([ECB::new(0, 0)])), + ECBlocks::new(22, Vec::from([ECB::new(2, 11)])), + ], + ), + Version::new( + 10, + Vec::from([27, 55, 83, 111]), + [ + // R9x139 + ECBlocks::new(0, Vec::from([ECB::new(0, 0)])), + ECBlocks::new(18, Vec::from([ECB::new(1, 31), ECB::new(1, 32)])), + ECBlocks::new(0, Vec::from([ECB::new(0, 0)])), + ECBlocks::new(22, Vec::from([ECB::new(3, 11)])), + ], + ), + Version::new( + 11, + Vec::from([]), + [ + // R11x27 + ECBlocks::new(0, Vec::from([ECB::new(0, 0)])), + ECBlocks::new(8, Vec::from([ECB::new(1, 7)])), + ECBlocks::new(0, Vec::from([ECB::new(0, 0)])), + ECBlocks::new(10, Vec::from([ECB::new(1, 5)])), + ], + ), + Version::new( + 12, + Vec::from([21]), + [ + // R11x43 + ECBlocks::new(0, Vec::from([ECB::new(0, 0)])), + ECBlocks::new(12, Vec::from([ECB::new(1, 19)])), + ECBlocks::new(0, Vec::from([ECB::new(0, 0)])), + ECBlocks::new(20, Vec::from([ECB::new(1, 11)])), + ], + ), + Version::new( + 13, + Vec::from([19, 39]), + [ + // R11x59 + ECBlocks::new(0, Vec::from([ECB::new(0, 0)])), + ECBlocks::new(16, Vec::from([ECB::new(1, 31)])), + ECBlocks::new(0, Vec::from([ECB::new(0, 0)])), + ECBlocks::new(16, Vec::from([ECB::new(1, 7), ECB::new(1, 8)])), + ], + ), + Version::new( + 14, + Vec::from([25, 51]), + [ + // R11x77 + ECBlocks::new(0, Vec::from([ECB::new(0, 0)])), + ECBlocks::new(24, Vec::from([ECB::new(1, 43)])), + ECBlocks::new(0, Vec::from([ECB::new(0, 0)])), + ECBlocks::new(22, Vec::from([ECB::new(1, 11), ECB::new(1, 12)])), + ], + ), + Version::new( + 15, + Vec::from([23, 49, 75]), + [ + // R11x99 + ECBlocks::new(0, Vec::from([ECB::new(0, 0)])), + ECBlocks::new(16, Vec::from([ECB::new(1, 28), ECB::new(1, 29)])), + ECBlocks::new(0, Vec::from([ECB::new(0, 0)])), + ECBlocks::new(30, Vec::from([ECB::new(1, 14), ECB::new(1, 15)])), + ], + ), + Version::new( + 16, + Vec::from([27, 55, 83, 111]), + [ + // R11x139 + ECBlocks::new(0, Vec::from([ECB::new(0, 0)])), + ECBlocks::new(24, Vec::from([ECB::new(2, 42)])), + ECBlocks::new(0, Vec::from([ECB::new(0, 0)])), + ECBlocks::new(30, Vec::from([ECB::new(3, 14)])), + ], + ), + Version::new( + 17, + Vec::from([]), + [ + // R13x27 + ECBlocks::new(0, Vec::from([ECB::new(0, 0)])), + ECBlocks::new(9, Vec::from([ECB::new(1, 12)])), + ECBlocks::new(0, Vec::from([ECB::new(0, 0)])), + ECBlocks::new(14, Vec::from([ECB::new(1, 7)])), + ], + ), + Version::new( + 18, + Vec::from([21]), + [ + // R13x43 + ECBlocks::new(0, Vec::from([ECB::new(0, 0)])), + ECBlocks::new(14, Vec::from([ECB::new(1, 27)])), + ECBlocks::new(0, Vec::from([ECB::new(0, 0)])), + ECBlocks::new(28, Vec::from([ECB::new(1, 13)])), + ], + ), + Version::new( + 19, + Vec::from([19, 39]), + [ + // R13x59 + ECBlocks::new(0, Vec::from([ECB::new(0, 0)])), + ECBlocks::new(22, Vec::from([ECB::new(1, 38)])), + ECBlocks::new(0, Vec::from([ECB::new(0, 0)])), + ECBlocks::new(20, Vec::from([ECB::new(2, 10)])), + ], + ), + Version::new( + 20, + Vec::from([25, 51]), + [ + // R13x77 + ECBlocks::new(0, Vec::from([ECB::new(0, 0)])), + ECBlocks::new(16, Vec::from([ECB::new(1, 26), ECB::new(1, 27)])), + ECBlocks::new(0, Vec::from([ECB::new(0, 0)])), + ECBlocks::new(28, Vec::from([ECB::new(1, 14), ECB::new(1, 15)])), + ], + ), + Version::new( + 21, + Vec::from([23, 49, 75]), + [ + // R13x99 + ECBlocks::new(0, Vec::from([ECB::new(0, 0)])), + ECBlocks::new(20, Vec::from([ECB::new(1, 36), ECB::new(1, 37)])), + ECBlocks::new(0, Vec::from([ECB::new(0, 0)])), + ECBlocks::new(26, Vec::from([ECB::new(1, 11), ECB::new(2, 12)])), + ], + ), + Version::new( + 22, + Vec::from([27, 55, 83, 111]), + [ + // R13x139 + ECBlocks::new(0, Vec::from([ECB::new(0, 0)])), + ECBlocks::new(20, Vec::from([ECB::new(2, 35), ECB::new(1, 36)])), + ECBlocks::new(0, Vec::from([ECB::new(0, 0)])), + ECBlocks::new(28, Vec::from([ECB::new(2, 13), ECB::new(2, 14)])), + ], + ), + Version::new( + 23, + Vec::from([21]), + [ + // R15x43 + ECBlocks::new(0, Vec::from([ECB::new(0, 0)])), + ECBlocks::new(18, Vec::from([ECB::new(1, 33)])), + ECBlocks::new(0, Vec::from([ECB::new(0, 0)])), + ECBlocks::new(18, Vec::from([ECB::new(1, 7), ECB::new(1, 8)])), + ], + ), + Version::new( + 24, + Vec::from([19, 39]), + [ + // R15x59 + ECBlocks::new(0, Vec::from([ECB::new(0, 0)])), + ECBlocks::new(26, Vec::from([ECB::new(1, 48)])), + ECBlocks::new(0, Vec::from([ECB::new(0, 0)])), + ECBlocks::new(24, Vec::from([ECB::new(2, 13)])), + ], + ), + Version::new( + 25, + Vec::from([25, 51]), + [ + // R15x77 + ECBlocks::new(0, Vec::from([ECB::new(0, 0)])), + ECBlocks::new(18, Vec::from([ECB::new(1, 33), ECB::new(1, 34)])), + ECBlocks::new(0, Vec::from([ECB::new(0, 0)])), + ECBlocks::new(24, Vec::from([ECB::new(2, 10), ECB::new(1, 11)])), + ], + ), + Version::new( + 26, + Vec::from([23, 49, 75]), + [ + // R15x99 + ECBlocks::new(0, Vec::from([ECB::new(0, 0)])), + ECBlocks::new(24, Vec::from([ECB::new(2, 44)])), + ECBlocks::new(0, Vec::from([ECB::new(0, 0)])), + ECBlocks::new(22, Vec::from([ECB::new(4, 12)])), + ], + ), + Version::new( + 27, + Vec::from([27, 55, 83, 111]), + [ + // R15x139 + ECBlocks::new(0, Vec::from([ECB::new(0, 0)])), + ECBlocks::new(24, Vec::from([ECB::new(2, 42), ECB::new(1, 43)])), + ECBlocks::new(0, Vec::from([ECB::new(0, 0)])), + ECBlocks::new(26, Vec::from([ECB::new(1, 13), ECB::new(4, 14)])), + ], + ), + Version::new( + 28, + Vec::from([21]), + [ + // R17x43 + ECBlocks::new(0, Vec::from([ECB::new(0, 0)])), + ECBlocks::new(22, Vec::from([ECB::new(1, 39)])), + ECBlocks::new(0, Vec::from([ECB::new(0, 0)])), + ECBlocks::new(20, Vec::from([ECB::new(1, 10), ECB::new(1, 11)])), + ], + ), + Version::new( + 29, + Vec::from([19, 39]), + [ + // R17x59 + ECBlocks::new(0, Vec::from([ECB::new(0, 0)])), + ECBlocks::new(16, Vec::from([ECB::new(2, 28)])), + ECBlocks::new(0, Vec::from([ECB::new(0, 0)])), + ECBlocks::new(30, Vec::from([ECB::new(2, 14)])), + ], + ), + Version::new( + 30, + Vec::from([25, 51]), + [ + // R17x77 + ECBlocks::new(0, Vec::from([ECB::new(0, 0)])), + ECBlocks::new(22, Vec::from([ECB::new(2, 39)])), + ECBlocks::new(0, Vec::from([ECB::new(0, 0)])), + ECBlocks::new(28, Vec::from([ECB::new(1, 12), ECB::new(2, 13)])), + ], + ), + Version::new( + 31, + Vec::from([23, 49, 75]), + [ + // R17x99 + ECBlocks::new(0, Vec::from([ECB::new(0, 0)])), + ECBlocks::new(20, Vec::from([ECB::new(2, 33), ECB::new(1, 34)])), + ECBlocks::new(0, Vec::from([ECB::new(0, 0)])), + ECBlocks::new(26, Vec::from([ECB::new(4, 14)])), + ], + ), + Version::new( + 32, + Vec::from([27, 55, 83, 111]), + [ + // R17x139 + ECBlocks::new(0, Vec::from([ECB::new(0, 0)])), + ECBlocks::new(20, Vec::from([ECB::new(4, 38)])), + ECBlocks::new(0, Vec::from([ECB::new(0, 0)])), + ECBlocks::new(26, Vec::from([ECB::new(2, 12), ECB::new(4, 13)])), + ], + ), + ]) + } +} + +/* + +/** + * See ISO/IEC 23941:2022 Annex D, Table D.1 - Column coordinates of centre module of alignment patterns + * See ISO/IEC 23941:2022 7.5.1, Table 8 - Error correction characteristics for rMQR + */ + static const Version allVersions[] = { + // Version number, alignment pattern centres, `ECBlocks` + { 1, {21}, { // R7x43 + // 4 `ECBlocks`, one for each `ecLevel` - rMQR only uses M & H but using 2 dummies to keep `ecLevel` index same as QR Code + // Each begins with no. of error correction codewords divided by no. of error correction blocks, followed by 2 `ECBlock`s + // Each `ECBlock` begins with no. of error correction blocks followed by no. of data codewords per block + 0, 0, 0, 0, 0, // L (dummy) - also used to differentiate rMQR from Model2 in `Version::Version()` + 7, 1, 6, 0, 0, // M + 0, 0, 0, 0, 0, // Q (dummy) + 10, 1, 3, 0, 0, // H + }}, + { 2, {19, 39}, { // R7x59 + 0, 0, 0, 0, 0, + 9, 1, 12, 0, 0, + 0, 0, 0, 0, 0, + 14, 1, 7, 0, 0, + }}, + { 3, {25, 51}, { // R7x77 + 0, 0, 0, 0, 0, + 12, 1, 20, 0, 0, + 0, 0, 0, 0, 0, + 22, 1, 10, 0, 0, + }}, + { 4, {23, 49, 75}, { // R7x99 + 0, 0, 0, 0, 0, + 16, 1, 28, 0, 0, + 0, 0, 0, 0, 0, + 30, 1, 14, 0, 0, + }}, + { 5, {27, 55, 83, 111}, { // R7x139 + 0, 0, 0, 0, 0, + 24, 1, 44, 0, 0, + 0, 0, 0, 0, 0, + 22, 2, 12, 0, 0, + }}, + { 6, {21}, { // R9x43 + 0, 0, 0, 0, 0, + 9, 1, 12, 0, 0, + 0, 0, 0, 0, 0, + 14, 1, 7, 0, 0, + }}, + { 7, {19, 39}, { // R9x59 + 0, 0, 0, 0, 0, + 12, 1, 21, 0, 0, + 0, 0, 0, 0, 0, + 22, 1, 11, 0, 0, + }}, + { 8, {25, 51}, { // R9x77 + 0, 0, 0, 0, 0, + 18, 1, 31, 0, 0, + 0, 0, 0, 0, 0, + 16, 1, 8, 1, 9, + }}, + { 9, {23, 49, 75}, { // R9x99 + 0, 0, 0, 0, 0, + 24, 1, 42, 0, 0, + 0, 0, 0, 0, 0, + 22, 2, 11, 0, 0, + }}, + {10, {27, 55, 83, 111}, { // R9x139 + 0, 0, 0, 0, 0, + 18, 1, 31, 1, 32, + 0, 0, 0, 0, 0, + 22, 3, 11, 0, 0, + }}, + {11, {}, { // R11x27 + 0, 0, 0, 0, 0, + 8, 1, 7, 0, 0, + 0, 0, 0, 0, 0, + 10, 1, 5, 0, 0, + }}, + {12, {21}, { // R11x43 + 0, 0, 0, 0, 0, + 12, 1, 19, 0, 0, + 0, 0, 0, 0, 0, + 20, 1, 11, 0, 0, + }}, + {13, {19, 39}, { // R11x59 + 0, 0, 0, 0, 0, + 16, 1, 31, 0, 0, + 0, 0, 0, 0, 0, + 16, 1, 7, 1, 8, + }}, + {14, {25, 51}, { // R11x77 + 0, 0, 0, 0, 0, + 24, 1, 43, 0, 0, + 0, 0, 0, 0, 0, + 22, 1, 11, 1, 12, + }}, + {15, {23, 49, 75}, { // R11x99 + 0, 0, 0, 0, 0, + 16, 1, 28, 1, 29, + 0, 0, 0, 0, 0, + 30, 1, 14, 1, 15, + }}, + {16, {27, 55, 83, 111}, { // R11x139 + 0, 0, 0, 0, 0, + 24, 2, 42, 0, 0, + 0, 0, 0, 0, 0, + 30, 3, 14, 0, 0, + }}, + {17, {}, { // R13x27 + 0, 0, 0, 0, 0, + 9, 1, 12, 0, 0, + 0, 0, 0, 0, 0, + 14, 1, 7, 0, 0, + }}, + {18, {21}, { // R13x43 + 0, 0, 0, 0, 0, + 14, 1, 27, 0, 0, + 0, 0, 0, 0, 0, + 28, 1, 13, 0, 0, + }}, + {19, {19, 39}, { // R13x59 + 0, 0, 0, 0, 0, + 22, 1, 38, 0, 0, + 0, 0, 0, 0, 0, + 20, 2, 10, 0, 0, + }}, + {20, {25, 51}, { // R13x77 + 0, 0, 0, 0, 0, + 16, 1, 26, 1, 27, + 0, 0, 0, 0, 0, + 28, 1, 14, 1, 15, + }}, + {21, {23, 49, 75}, { // R13x99 + 0, 0, 0, 0, 0, + 20, 1, 36, 1, 37, + 0, 0, 0, 0, 0, + 26, 1, 11, 2, 12, + }}, + {22, {27, 55, 83, 111}, { // R13x139 + 0, 0, 0, 0, 0, + 20, 2, 35, 1, 36, + 0, 0, 0, 0, 0, + 28, 2, 13, 2, 14, + }}, + {23, {21}, { // R15x43 + 0, 0, 0, 0, 0, + 18, 1, 33, 0, 0, + 0, 0, 0, 0, 0, + 18, 1, 7, 1, 8, + }}, + {24, {19, 39}, { // R15x59 + 0, 0, 0, 0, 0, + 26, 1, 48, 0, 0, + 0, 0, 0, 0, 0, + 24, 2, 13, 0, 0, + }}, + {25, {25, 51}, { // R15x77 + 0, 0, 0, 0, 0, + 18, 1, 33, 1, 34, + 0, 0, 0, 0, 0, + 24, 2, 10, 1, 11, + }}, + {26, {23, 49, 75}, { // R15x99 + 0, 0, 0, 0, 0, + 24, 2, 44, 0, 0, + 0, 0, 0, 0, 0, + 22, 4, 12, 0, 0, + }}, + {27, {27, 55, 83, 111}, { // R15x139 + 0, 0, 0, 0, 0, + 24, 2, 42, 1, 43, + 0, 0, 0, 0, 0, + 26, 1, 13, 4, 14, + }}, + {28, {21}, { // R17x43 + 0, 0, 0, 0, 0, + 22, 1, 39, 0, 0, + 0, 0, 0, 0, 0, + 20, 1, 10, 1, 11, + }}, + {29, {19, 39}, { // R17x59 + 0, 0, 0, 0, 0, + 16, 2, 28, 0, 0, + 0, 0, 0, 0, 0, + 30, 2, 14, 0, 0, + }}, + {30, {25, 51}, { // R17x77 + 0, 0, 0, 0, 0, + 22, 2, 39, 0, 0, + 0, 0, 0, 0, 0, + 28, 1, 12, 2, 13, + }}, + {31, {23, 49, 75}, { // R17x99 + 0, 0, 0, 0, 0, + 20, 2, 33, 1, 34, + 0, 0, 0, 0, 0, + 26, 4, 14, 0, 0, + }}, + {32, {27, 55, 83, 111}, { // R17x139 + 0, 0, 0, 0, 0, + 20, 4, 38, 0, 0, + 0, 0, 0, 0, 0, + 26, 2, 12, 4, 13, + }}, + }; + + if (number < 1 || number > Size(allVersions)) + return nullptr; + return allVersions + number - 1; + +*/ diff --git a/src/rxing_result_point.rs b/src/rxing_result_point.rs index 205dfa1..c0d4450 100644 --- a/src/rxing_result_point.rs +++ b/src/rxing_result_point.rs @@ -90,12 +90,22 @@ impl Hash for Point { } } -impl PartialEq for Point { +// impl PartialEq for Point { +// fn eq(&self, other: &Self) -> bool { +// self.x == other.x && self.y == other.y +// } +// } +// impl Eq for Point {} + +impl PartialEq for PointT +where + T: PartialEq, +{ fn eq(&self, other: &Self) -> bool { self.x == other.x && self.y == other.y } } -impl Eq for Point {} +impl Eq for PointT where T: PartialEq {} impl PointT where diff --git a/test_resources/blackbox/cpp/qrcode-2/qr-model-1.metadata.txt b/test_resources/blackbox/cpp/qrcode-2/qr-model-1.metadata.txt new file mode 100644 index 0000000..7f36347 --- /dev/null +++ b/test_resources/blackbox/cpp/qrcode-2/qr-model-1.metadata.txt @@ -0,0 +1,2 @@ +symbologyIdentifier=]Q0 +ecLevel=M diff --git a/test_resources/blackbox/cpp/qrcode-2/qr-model-1.png b/test_resources/blackbox/cpp/qrcode-2/qr-model-1.png new file mode 100644 index 0000000..4b19990 Binary files /dev/null and b/test_resources/blackbox/cpp/qrcode-2/qr-model-1.png differ diff --git a/test_resources/blackbox/cpp/qrcode-2/qr-model-1.txt b/test_resources/blackbox/cpp/qrcode-2/qr-model-1.txt new file mode 100644 index 0000000..a6bce8d --- /dev/null +++ b/test_resources/blackbox/cpp/qrcode-2/qr-model-1.txt @@ -0,0 +1 @@ +QR Code Model 1 \ No newline at end of file diff --git a/test_resources/blackbox/cpp/rmqrcode-1/R17x139.png b/test_resources/blackbox/cpp/rmqrcode-1/R17x139.png new file mode 100644 index 0000000..19d17e3 Binary files /dev/null and b/test_resources/blackbox/cpp/rmqrcode-1/R17x139.png differ diff --git a/test_resources/blackbox/cpp/rmqrcode-1/R17x139.txt b/test_resources/blackbox/cpp/rmqrcode-1/R17x139.txt new file mode 100644 index 0000000..ea78e30 --- /dev/null +++ b/test_resources/blackbox/cpp/rmqrcode-1/R17x139.txt @@ -0,0 +1 @@ +3.1415926535897932384626433832795028841971693993751058209749445923078164062862089986280348253421170679821480865132823066470938446095505822317253594081 \ No newline at end of file diff --git a/test_resources/blackbox/cpp/rmqrcode-1/R7x43-H.metadata.txt b/test_resources/blackbox/cpp/rmqrcode-1/R7x43-H.metadata.txt new file mode 100644 index 0000000..f29c889 --- /dev/null +++ b/test_resources/blackbox/cpp/rmqrcode-1/R7x43-H.metadata.txt @@ -0,0 +1 @@ +symbologyIdentifier=]Q1 diff --git a/test_resources/blackbox/cpp/rmqrcode-1/R7x43-H.png b/test_resources/blackbox/cpp/rmqrcode-1/R7x43-H.png new file mode 100644 index 0000000..d62eb47 Binary files /dev/null and b/test_resources/blackbox/cpp/rmqrcode-1/R7x43-H.png differ diff --git a/test_resources/blackbox/cpp/rmqrcode-1/R7x43-H.txt b/test_resources/blackbox/cpp/rmqrcode-1/R7x43-H.txt new file mode 100644 index 0000000..8b22b22 --- /dev/null +++ b/test_resources/blackbox/cpp/rmqrcode-1/R7x43-H.txt @@ -0,0 +1 @@ +,, \ No newline at end of file diff --git a/test_resources/blackbox/cpp/rmqrcode-1/R7x43-H_inverted._metadata.txt b/test_resources/blackbox/cpp/rmqrcode-1/R7x43-H_inverted._metadata.txt new file mode 100644 index 0000000..da82284 --- /dev/null +++ b/test_resources/blackbox/cpp/rmqrcode-1/R7x43-H_inverted._metadata.txt @@ -0,0 +1 @@ +isInverted=true diff --git a/test_resources/blackbox/cpp/rmqrcode-1/R7x43-H_inverted.png b/test_resources/blackbox/cpp/rmqrcode-1/R7x43-H_inverted.png new file mode 100644 index 0000000..138a065 Binary files /dev/null and b/test_resources/blackbox/cpp/rmqrcode-1/R7x43-H_inverted.png differ diff --git a/test_resources/blackbox/cpp/rmqrcode-1/R7x43-H_inverted.txt b/test_resources/blackbox/cpp/rmqrcode-1/R7x43-H_inverted.txt new file mode 100644 index 0000000..8b22b22 --- /dev/null +++ b/test_resources/blackbox/cpp/rmqrcode-1/R7x43-H_inverted.txt @@ -0,0 +1 @@ +,, \ No newline at end of file diff --git a/tests/common/abstract_black_box_test_case.rs b/tests/common/abstract_black_box_test_case.rs index 26cbb08..951592a 100644 --- a/tests/common/abstract_black_box_test_case.rs +++ b/tests/common/abstract_black_box_test_case.rs @@ -309,15 +309,6 @@ impl AbstractBlackBoxTestCase { log::fine(format!("could not read at rotation {rotation} w/TH: {e:?}")); } } - // try { - // if (decode(bitmap, rotation, expectedText, expectedMetadata, true)) { - // tryHarderCounts[x]+=1; - // } else { - // tryHarderMisreadCounts[x]+=1; - // } - // } catch (ReaderException ignored) { - // log::fine(format!("could not read at rotation {} w/TH", rotation)); - // } } } @@ -464,8 +455,10 @@ impl AbstractBlackBoxTestCase { ); result = if let Ok(res) = self.barcode_reader.decode_with_hints(source, &pure_hints) { + log::fine(format!("{suffix} - read pure barcode")); Some(res) } else { + // log::fine(format!("{suffix} - could not read pure barcode")); None }; } diff --git a/tests/cpp_qr_code_blackbox_tests.rs b/tests/cpp_qr_code_blackbox_tests.rs index 96deb08..7883373 100644 --- a/tests/cpp_qr_code_blackbox_tests.rs +++ b/tests/cpp_qr_code_blackbox_tests.rs @@ -15,7 +15,9 @@ */ #![cfg(feature = "image")] -use rxing::{qrcode::cpp_port::QrReader, BarcodeFormat, MultiUseMultiFormatReader}; +use rxing::{ + qrcode::cpp_port::QrReader, BarcodeFormat, MultiFormatReader, MultiUseMultiFormatReader, +}; mod common; @@ -207,10 +209,10 @@ fn cpp_qrcode_black_box2_test_case() { BarcodeFormat::QR_CODE, ); - tester.add_test(45, 47, 0.0); - tester.add_test(45, 47, 90.0); - tester.add_test(45, 47, 180.0); - tester.add_test(45, 46, 270.0); + tester.add_test(46, 48, 0.0); + tester.add_test(46, 48, 90.0); + tester.add_test(46, 48, 180.0); + tester.add_test(46, 48, 270.0); tester.ignore_pure = true; @@ -325,3 +327,27 @@ fn cpp_qrcode_black_box7_test_case() { tester.test_black_box(); } + +#[cfg(feature = "image-formats")] +#[test] +fn cpp_rmqr_blackbox_test_case() { + let mut tester = common::AbstractBlackBoxTestCase::new( + "test_resources/blackbox/cpp/rmqrcode-1", + MultiFormatReader::default(), + BarcodeFormat::RECTANGULAR_MICRO_QR_CODE, + ); + // tester.ignore_pure = true; + tester.add_test(3, 3, 0.0); + tester.add_test(3, 3, 90.0); + tester.add_test(3, 3, 180.0); + tester.add_test(3, 3, 270.0); + + tester.add_hint( + rxing::DecodeHintType::ALSO_INVERTED, + rxing::DecodeHintValue::AlsoInverted(true), + ); + + tester.test_black_box(); +} + +//