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