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 a212329..533a6c3 100644 --- a/src/common/cpp_essentials/base_extentions/qr_formatinformation.rs +++ b/src/common/cpp_essentials/base_extentions/qr_formatinformation.rs @@ -7,6 +7,8 @@ use crate::qrcode::{ 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, @@ -94,6 +96,33 @@ impl FormatInformation { 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 mirror18Bits = |bits: u32| bits.reverse_bits() >> 14; + let mut fi = if (formatInfoBits2 != 0) { + Self::FindBestFormatInfoRMQR( + &[formatInfoBits1, mirror18Bits(formatInfoBits1)], + &[formatInfoBits2, mirror18Bits(formatInfoBits2)], + ) + } else { + // TODO probably remove if `sampleRMQR()` done properly + Self::FindBestFormatInfoRMQR(&[formatInfoBits1, mirror18Bits(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.rMQRVersion = fi.data as u8 & 0x1F; + fi.isMirrored = fi.bitsIndex > 1; + + fi + } + #[inline(always)] pub fn MirrorBits(bits: u32) -> u32 { (bits.reverse_bits()) >> 17 @@ -153,16 +182,73 @@ impl FormatInformation { fi } - pub fn qr_type(&self) -> Type { + 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, by construction, so <= 3 bits differing means we found a match - pub fn isValid(&self) -> bool { + // 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 } diff --git a/src/common/cpp_essentials/base_extentions/qrcode_version.rs b/src/common/cpp_essentials/base_extentions/qrcode_version.rs index ab779bd..2ba7059 100644 --- a/src/common/cpp_essentials/base_extentions/qrcode_version.rs +++ b/src/common/cpp_essentials/base_extentions/qrcode_version.rs @@ -8,9 +8,45 @@ use crate::common::{BitMatrix, Result}; use crate::qrcode::cpp_port::Type; use crate::qrcode::decoder::{ - Version, VersionRef, MICRO_VERSIONS, MODEL1_VERSIONS, VERSIONS, VERSION_DECODE_INFO, + Version, VersionRef, MICRO_VERSIONS, MODEL1_VERSIONS, RMQR_VERSIONS, VERSIONS, + VERSION_DECODE_INFO, }; -use crate::Exceptions; +use crate::{point, Exceptions, PointI}; + +const dimsVersionRMQR: [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 Model1(version_number: u32) -> Result { @@ -37,11 +73,20 @@ impl Version { } } - pub fn DimensionOfVersion(version: u32, is_micro: bool) -> u32 { + 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 as usize - 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, @@ -49,7 +94,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, @@ -93,22 +138,65 @@ impl Version { Type::const_eq(self.qr_type, Type::Model2) } + pub const fn isRMQR(&self) -> bool { + Type::const_eq(self.qr_type, Type::RectMicro) + } + pub fn HasMicroSize(bitMatrix: &BitMatrix) -> bool { let size = bitMatrix.height(); - (11..=17).contains(&size) && (size % 2) == 1 + size == bitMatrix.width() && size >= 11 && size <= 17 && (size % 2) == 1 + } + + pub fn HasRMQRSize(bitMatrix: &BitMatrix) -> bool { + Self::getVersionRMQR(bitMatrix) != -1 } pub fn HasValidSize(bitMatrix: &BitMatrix) -> bool { let size = bitMatrix.height(); - Self::HasMicroSize(bitMatrix) || ((21..=177).contains(&size) && (size % 4) == 1) + if bitMatrix.width() != size { + Self::HasRMQRSize(bitMatrix) + } else { + Self::HasMicroSize(bitMatrix) || ((21..=177).contains(&size) && (size % 4) == 1) + } } pub fn Number(bitMatrix: &BitMatrix) -> u32 { - if !Self::HasValidSize(bitMatrix) { + if bitMatrix.width() != bitMatrix.height() { + Self::getVersionRMQR(bitMatrix) as u32 + 1 + } else if !Self::HasValidSize(bitMatrix) { 0 } else { let isMicro = Self::HasMicroSize(bitMatrix); (bitMatrix.height() - Self::DimensionOffset(isMicro)) / Self::DimensionStep(isMicro) } } + + pub fn DimensionOfVersionRMQR(version_number: u32) -> PointI { + if version_number < 1 || version_number as usize > dimsVersionRMQR.len() { + point(0, 0) + } else { + dimsVersionRMQR[version_number as usize - 1] + } + } + + fn getVersionRMQR(bitMatrix: &BitMatrix) -> i32 { + let width = bitMatrix.width() as i32; + let height = bitMatrix.height() as i32; + if width != height + && (width & 1 != 0) + && (height & 1 != 0) + && width >= 27 + && width <= 139 + && height >= 7 + && height <= 17 + { + for i in 0..dimsVersionRMQR.len() { + // for (int i = 0; i < Size(dimsVersionRMQR); i++){ + if width == dimsVersionRMQR[i].x && height == dimsVersionRMQR[i].y { + return i as i32; + } + } + } + return -1; + } } 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/qrcode/cpp_port/bitmatrix_parser.rs b/src/qrcode/cpp_port/bitmatrix_parser.rs index 393f021..a0c9f31 100644 --- a/src/qrcode/cpp_port/bitmatrix_parser.rs +++ b/src/qrcode/cpp_port/bitmatrix_parser.rs @@ -32,6 +32,7 @@ pub fn ReadVersion(bitMatrix: &BitMatrix, qr_type: Type) -> Result { Type::Model1 => Version::Model1(number), Type::Micro => Version::Micro(number), Type::Model2 => Version::Model2(number), + Type::RectMicro => Version::rMQR(number), } } @@ -51,6 +52,47 @@ pub fn ReadFormatInformation(bitMatrix: &BitMatrix) -> Result return Ok(FormatInformation::DecodeMQR(formatInfoBits as u32)); } + if (Version::HasRMQRSize(bitMatrix)) { + // Read top-left format info bits + let mut formatInfoBits1 = 0; + for y in (1..=3).rev() { + // for (int y = 3; y >= 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 { @@ -311,6 +353,59 @@ pub fn ReadQRCodewordsModel1( 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, @@ -320,5 +415,6 @@ pub fn ReadCodewords( 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 f9b3c84..a454902 100644 --- a/src/qrcode/cpp_port/decoder.rs +++ b/src/qrcode/cpp_port/decoder.rs @@ -310,7 +310,7 @@ pub fn DecodeBitStream( } else { Mode::CodecModeForBits( bits.readBits(modeBitLength as usize)?, - Some(version.isMicro()), + Some(version.qr_type), )? }; diff --git a/src/qrcode/cpp_port/detector.rs b/src/qrcode/cpp_port/detector.rs index 61f7ea1..a43fb52 100644 --- a/src/qrcode/cpp_port/detector.rs +++ b/src/qrcode/cpp_port/detector.rs @@ -5,14 +5,15 @@ use crate::{ }, DefaultGridSampler, GridSampler, Result, SamplerControl, }, - point_i, + point, point_i, qrcode::{ decoder::{FormatInformation, Version, VersionRef}, detector::QRCodeDetectorResult, }, - Exceptions, + Exceptions, PointF, }; use multimap::MultiMap; +use num::Integer; use crate::{ common::{ @@ -23,7 +24,7 @@ use crate::{ }, BitMatrix, PerspectiveTransform, Quadrilateral, }, - point_f, Point, + point_f, Point, PointI, }; #[derive(Copy, Clone, Default, Debug, PartialEq, Eq)] @@ -39,6 +40,8 @@ pub type FinderPatternSets = Vec; const LEN: usize = 5; const SUM: usize = 7; const PATTERN: FixedPattern = FixedPattern::new([1, 1, 3, 1, 1]); +const SUBPATTERN_RMQR: FixedPattern<5, 5, false> = FixedPattern::new([1, 1, 1, 1, 1]); +const CORNER_EDGE_RMQR: FixedPattern<2, 4, false> = FixedPattern::new([3, 1]); const E2E: bool = true; fn FindPattern(view: PatternView<'_>) -> Result> { @@ -885,8 +888,8 @@ 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); + const MIN_MODULES: u32 = Version::DimensionOfVersion(1, true); + const MAX_MODULES: u32 = Version::DimensionOfVersion(4, true); let (found, left, top, width, height) = image.findBoundingBox(0, 0, 0, 0, MIN_MODULES); @@ -949,6 +952,139 @@ pub fn DetectPureMQR(image: &BitMatrix) -> Result { // {{left, top}, {right, top}, {right, bottom}, {left, bottom}}}; } +pub fn DetectPureRMQR(image: &BitMatrix) -> Result { + type Pattern = [PatternType; 5]; //std::array; + type SubPattern = [PatternType; 5]; //std::array; + type CornerEdgePattern = [PatternType; 2]; //std::array; + + // #ifdef PRINT_DEBUG + // SaveAsPBM(image, "weg.pbm"); + // #endif + + const MIN_MODULES: u32 = 7; + const MIN_MODULES_W: u32 = 27; + const MIN_MODULES_H: u32 = 7; + const MAX_MODULES_W: u32 = 139; + const MAX_MODULES_H: u32 = 17; + + let (found, left, top, width, height) = image.findBoundingBox(0, 0, 0, 0, MIN_MODULES); + + if (!found) { + 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 mut subdiagonal: SubPattern = EdgeTracer::new(image, br, point_i(-1, -1)) + .readPatternFromBlack(1, None) + .ok_or(Exceptions::ILLEGAL_STATE)?; + if (subdiagonal.len() == 5 && subdiagonal[4] > subdiagonal[3]) { + // Sub pattern has no separator so can run off along the diagonal + subdiagonal[4] = subdiagonal[3]; // Hack it back to previous + } + let subdiagonal_hld = subdiagonal.to_vec().into(); + let view = PatternView::new(&subdiagonal_hld); + if !(IsPattern::(&view, &SUBPATTERN_RMQR, None, 0.0, 0.0) != 0.0) { + return Err(Exceptions::NOT_FOUND); + } + + // Horizontal corner finder patterns (for vertical ones see below) + for (p, d) in [(tr, point_i(-1, 0)), (bl, point_i(1, 0))] { + // for (auto [p, d] : {std::pair(tr, PointI{-1, 0}), {bl, {1, 0}}}) { + let corner: CornerEdgePattern = EdgeTracer::new(image, p, d) + .readPatternFromBlack(1, None) + .ok_or(Exceptions::ILLEGAL_STATE)?; + let corner_hld = corner.to_vec().into(); + let view = PatternView::new(&corner_hld); + if !(IsPattern::(&view, &CORNER_EDGE_RMQR, None, 0.0, 0.0) != 0.0) { + { + return Err(Exceptions::NOT_FOUND); + } + } + } + + let fpWidth = (diagonal).into_iter().sum::(); + let moduleSize = (fpWidth as f32) / 7.0; + let dimW = (width as f32 / moduleSize as f32).floor() as u32; + let dimH = (height as f32 / moduleSize as f32).floor() as u32; + + if (dimW == dimH + || dimW.is_even() + || dimH.is_even() + || dimW < MIN_MODULES_W + || dimW > MAX_MODULES_W + || dimH < MIN_MODULES_H + || dimH > MAX_MODULES_H + || !image.is_in(point_f( + left as f32 + moduleSize / 2.0 + (dimW as f32 - 1.0) * moduleSize, + top as f32 + moduleSize / 2.0 + (dimH as f32 - 1.0) * moduleSize, + ))) + { + return Err(Exceptions::NOT_FOUND); + } + + // Vertical corner finder patterns + if (dimH > 7) { + // None for R7 + let corner: CornerEdgePattern = EdgeTracer::new(image, tr, point_i(0, 1)) + .readPatternFromBlack(1, None) + .ok_or(Exceptions::ILLEGAL_STATE)?; + let corner_hld = corner.to_vec().into(); + let view = PatternView::new(&corner_hld); + if !(IsPattern::(&view, &CORNER_EDGE_RMQR, None, 0.0, 0.0) != 0.0) { + return Err(Exceptions::NOT_FOUND); + } + if (dimH > 9) { + // No bottom left for R9 + let corner: CornerEdgePattern = EdgeTracer::new(image, bl, point_i(0, -1)) + .readPatternFromBlack(1, None) + .ok_or(Exceptions::ILLEGAL_STATE)?; + let corner_hld = corner.to_vec().into(); + let view = PatternView::new(&corner_hld); + if !(IsPattern::(&view, &CORNER_EDGE_RMQR, None, 0.0, 0.0) != 0.0) { + 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, + dimH, + 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); @@ -1057,3 +1193,91 @@ 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(8, 1), + point_i(8, 2), + point_i(8, 3), + point_i(8, 4), + point_i(8, 5), + point_i(9, 1), + point_i(9, 2), + point_i(9, 3), + point_i(9, 4), + point_i(9, 5), + point_i(10, 1), + point_i(10, 2), + point_i(10, 3), + point_i(10, 4), + point_i(10, 5), + point_i(11, 1), + point_i(11, 2), + point_i(11, 3), + ]; + + let mut bestFI: FormatInformation = FormatInformation::default(); + let mut bestPT: PerspectiveTransform = PerspectiveTransform::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 + }; + + // 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 i in 0..FORMAT_INFO_COORDS.len() { + // for (int i = 0; i < Size(FORMAT_INFO_COORDS); ++i) + AppendBit( + &mut formatInfoBits, + image.get_point(mod2Pix.transform_point(Point::centered(FORMAT_INFO_COORDS[i]))), + ); + } + + 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::DimensionOfVersionRMQR(bestFI.rMQRVersion as u32 + 1); + + 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/qr_cpp_reader.rs b/src/qrcode/cpp_port/qr_cpp_reader.rs index 6d711a2..d1bab45 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,16 @@ impl Reader for QrReader { Ok(RXingResult::with_decoder_result( decoderResult, position, - if detectorResult.getBits().width() < 21 { - BarcodeFormat::MICRO_QR_CODE + if detectorResult.getBits().width() != detectorResult.getBits().height() { + BarcodeFormat::RECTANGULAR_MICRO_QR_CODE } else { - BarcodeFormat::QR_CODE + 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 +272,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 +312,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 +328,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 +346,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 index 610d741..7988e16 100644 --- a/src/qrcode/cpp_port/qr_type.rs +++ b/src/qrcode/cpp_port/qr_type.rs @@ -3,6 +3,7 @@ pub enum Type { Model1, Model2, Micro, + RectMicro, } impl Type { diff --git a/src/qrcode/cpp_port/test/QRFormatInformationTest.rs b/src/qrcode/cpp_port/test/QRFormatInformationTest.rs index 352329c..3177acc 100644 --- a/src/qrcode/cpp_port/test/QRFormatInformationTest.rs +++ b/src/qrcode/cpp_port/test/QRFormatInformationTest.rs @@ -15,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); @@ -23,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 @@ -131,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 324f06a..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] @@ -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] @@ -133,3 +145,87 @@ fn MicroCharacterCount() { 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 d5d0b1e..b2214d3 100644 --- a/src/qrcode/cpp_port/test/QRVersionTest.rs +++ b/src/qrcode/cpp_port/test/QRVersionTest.rs @@ -125,3 +125,130 @@ fn FunctionPattern() { } } } + +fn CheckRMQRVersion(version: VersionRef, number: u32) { + assert_eq!(number, version.getVersionNumber()); + assert_eq!( + Version::DimensionOfVersionRMQR(number).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..13e12ab --- /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 4591cc9..879edd0 100644 --- a/src/qrcode/decoder/format_information.rs +++ b/src/qrcode/decoder/format_information.rs @@ -75,9 +75,10 @@ pub struct FormatInformation { pub microVersion: u32, pub isMirrored: bool, - pub mask: u32, // = 0 - pub data: u32, // = 255 - pub bitsIndex: u8, // = 255; + pub mask: u32, // = 0 + pub data: u32, // = 255 + pub bitsIndex: u8, // = 255; + pub rMQRVersion: u8, //= 0; } impl Default for FormatInformation { @@ -91,6 +92,7 @@ impl Default for FormatInformation { mask: 0, data: 255, bitsIndex: 255, + rMQRVersion: 0, } } } @@ -110,6 +112,7 @@ impl FormatInformation { mask: 0, bitsIndex: 255, data: 255, + rMQRVersion: 0, }) } 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 c6cb3ad..7c6f032 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 { + 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 { + + 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,19 +145,33 @@ 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); + if (qr_type == Type::Micro) { + const Bits2Mode: [Mode; 4] = + [Mode::NUMERIC, Mode::ALPHANUMERIC, Mode::BYTE, Mode::KANJI]; + 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 { - const BITS_2_MODE: [Mode; BITS_2_MODE_LEN] = - [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 >= 0x00 && bits <= 0x05) || (bits >= 0x07 && bits <= 0x09) || bits == 0x0d) { + return Mode::try_from(bits as u32); } } @@ -179,6 +196,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 59e22af..1b0a8ff 100755 --- a/src/qrcode/decoder/version.rs +++ b/src/qrcode/decoder/version.rs @@ -31,6 +31,7 @@ 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. @@ -59,14 +60,19 @@ pub struct Version { 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 { @@ -74,11 +80,15 @@ impl Version { alignmentPatternCenters, ecBlocks: ecBlocks.to_vec(), totalCodewords: total, - qr_type: Type::Model2, + 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(); @@ -97,7 +107,7 @@ impl Version { } } - fn new_model1(versionNumber: u32, ecBlocks: Vec) -> Self { + pub(super) fn new_model1(versionNumber: u32, ecBlocks: Vec) -> Self { let mut total = 0; let ecCodewords = ecBlocks[0].getECCodewordsPerBlock(); let ecbArray = ecBlocks[0].getECBlocks(); @@ -116,11 +126,6 @@ impl Version { } } - // #[inline(always)] - // pub(crate) const fn isMicro(ecBlocks: &[ECBlocks; 4]) -> bool { - // ecBlocks[0].ecCodewordsPerBlock < 7 || ecBlocks[0].ecCodewordsPerBlock == 8 - // } - pub const fn getVersionNumber(&self) -> u32 { self.versionNumber } @@ -196,6 +201,53 @@ impl Version { * See ISO 18004:2006 Annex E */ pub fn buildFunctionPattern(&self) -> Result { + if (self.isRMQR()) { + let dimension = Version::DimensionOfVersionRMQR(self.versionNumber); + let mut bitMatrix = BitMatrix::new(dimension.x as u32, dimension.y as u32)?; + + // Set edge timing patterns + bitMatrix.setRegion(0, 0, dimension.x as u32, 1)?; // Top + bitMatrix.setRegion(0, (dimension.y - 1) as u32, dimension.x as u32, 1)?; // Bottom + bitMatrix.setRegion(0, 1, 1, (dimension.y - 2) as u32)?; // Left + bitMatrix.setRegion((dimension.x - 1) as u32, 1, 1, (dimension.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, (dimension.y - 3) as u32, 3, 2)?; // Bottom alignment pattern + bitMatrix.setRegion(cx, 3, 1, (dimension.y - 6) as u32)?; // Vertical timing pattern + } + + // Top left finder pattern + separator + bitMatrix.setRegion(1, 1, 8 - 1, 8 - 1 - u32::from(dimension.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( + (dimension.x - 5) as u32, + (dimension.y - 5) as u32, + 5 - 1, + 5 - 1, + )?; + // Bottom right format + bitMatrix.setRegion((dimension.x - 8) as u32, (dimension.y - 6) as u32, 3, 5)?; + bitMatrix.setRegion((dimension.x - 5) as u32, (dimension.y - 6) as u32, 3, 1)?; + + // Top right corner finder + bitMatrix.set((dimension.x - 2) as u32, 1); + if (dimension.y > 9) { + // Bottom left corner finder + bitMatrix.set(1, (dimension.y - 2) as u32); + } + + return Ok(bitMatrix); + } + let dimension = self.getDimensionForVersion(); let mut bitMatrix = BitMatrix::with_single_dimension(dimension)?; @@ -241,979 +293,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))) - ]*/ - } - - /* - * {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)]), - ], - ), - ]) - } } 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/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/cpp_qr_code_blackbox_tests.rs b/tests/cpp_qr_code_blackbox_tests.rs index 7c9f076..6ea0892 100644 --- a/tests/cpp_qr_code_blackbox_tests.rs +++ b/tests/cpp_qr_code_blackbox_tests.rs @@ -311,3 +311,18 @@ fn cpp_qrcode_black_box7_test_case() { tester.test_black_box(); } + +#[test] +fn cpp_rmqr_blackbox_test_case() { + let mut tester = common::AbstractBlackBoxTestCase::new( + "test_resources/blackbox/cpp/rmqrcode-1", + QrReader, + BarcodeFormat::RECTANGULAR_MICRO_QR_CODE, + ); + tester.add_test(1, 1, 0.0); + tester.add_test(1, 1, 90.0); + tester.add_test(1, 1, 180.0); + tester.add_test(1, 1, 270.0); + + tester.test_black_box(); +}