feat: ported qr-model1 support from zxing-cpp

This commit is contained in:
Henry Schimke
2024-01-11 12:53:04 -06:00
parent d2b3bf6c1e
commit eea448ae94
17 changed files with 485 additions and 41 deletions

View File

@@ -2,6 +2,8 @@ use crate::qrcode::decoder::{
ErrorCorrectionLevel, FormatInformation, FORMAT_INFO_DECODE_LOOKUP, FORMAT_INFO_MASK_QR,
};
pub const FORMAT_INFO_MASK_QR_MODEL1: u32 = 0x2825;
pub const FORMAT_INFO_DECODE_LOOKUP_MICRO: [[u32; 2]; 32] = [
[0x4445, 0x00],
[0x4172, 0x01],
@@ -50,7 +52,7 @@ impl FormatInformation {
let formatInfoBits2 =
((formatInfoBits2 >> 1) & 0b111111100000000) | (formatInfoBits2 & 0b11111111);
let mut fi = Self::FindBestFormatInfo(
FORMAT_INFO_MASK_QR,
&[0, FORMAT_INFO_MASK_QR],
FORMAT_INFO_DECODE_LOOKUP,
&[
formatInfoBits1,
@@ -60,6 +62,22 @@ impl FormatInformation {
],
);
let mut fi_model1 = Self::FindBestFormatInfo(
&[FORMAT_INFO_MASK_QR ^ FORMAT_INFO_MASK_QR_MODEL1],
FORMAT_INFO_DECODE_LOOKUP,
&[
formatInfoBits1,
formatInfoBits2,
Self::MirrorBits(formatInfoBits1),
mirroredFormatInfoBits2,
],
);
if fi_model1.hammingDistance < fi.hammingDistance {
fi_model1.isModel1 = true;
fi = fi_model1;
}
// Use bits 3/4 for error correction, and 0-2 for mask.
fi.error_correction_level =
ErrorCorrectionLevel::ECLevelFromBits((fi.index >> 3) & 0x03, false);
@@ -72,7 +90,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,
&[0],
FORMAT_INFO_DECODE_LOOKUP_MICRO,
&[formatInfoBits, Self::MirrorBits(formatInfoBits)],
);
@@ -94,11 +112,11 @@ impl FormatInformation {
(bits.reverse_bits()) >> 17
}
pub fn FindBestFormatInfo(mask: u32, lookup: [[u32; 2]; 32], bits: &[u32]) -> Self {
pub fn FindBestFormatInfo(masks: &[u32], lookup: [[u32; 2]; 32], 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 mask in masks {
// for (auto mask : {0, mask})
for (bitsIndex, bit_set) in bits.iter().enumerate() {
// for (int bitsIndex = 0; bitsIndex < Size(bits); ++bitsIndex)

View File

@@ -1,5 +1,7 @@
use crate::common::Result;
use crate::qrcode::decoder::{Version, VersionRef, MICRO_VERSIONS, VERSIONS, VERSION_DECODE_INFO};
use crate::qrcode::decoder::{
Version, VersionRef, MICRO_VERSIONS, MODEL1_VERSIONS, VERSIONS, VERSION_DECODE_INFO,
};
use crate::Exceptions;
// const Version* Version::AllMicroVersions()
@@ -16,7 +18,7 @@ use crate::Exceptions;
// }
impl Version {
pub fn FromDimension(dimension: u32) -> Result<VersionRef> {
pub fn FromDimension(dimension: u32, is_model1: bool) -> Result<VersionRef> {
let isMicro = dimension < 21;
if dimension % Self::DimensionStep(isMicro) != 1 {
//throw std::invalid_argument("Unexpected dimension");
@@ -25,17 +27,31 @@ impl Version {
Self::FromNumber(
(dimension - Self::DimensionOffset(isMicro)) / Self::DimensionStep(isMicro),
isMicro,
is_model1,
)
}
pub fn FromNumber(versionNumber: u32, is_micro: bool) -> Result<VersionRef> {
if versionNumber < 1 || versionNumber > (if is_micro { 4 } else { 40 }) {
pub fn FromNumber(versionNumber: u32, is_micro: bool, is_model1: bool) -> Result<VersionRef> {
if versionNumber < 1
|| versionNumber
> (if is_micro {
4
} else {
if is_model1 {
14
} 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]
} else if is_model1 {
&MODEL1_VERSIONS[versionNumber as usize - 1]
} else {
&VERSIONS[versionNumber as usize - 1]
})
@@ -92,4 +108,8 @@ impl Version {
pub const fn isMicroQRCode(&self) -> bool {
self.is_micro
}
pub const fn isQRCodeModel1(&self) -> bool {
self.is_model1
}
}

View File

@@ -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> {
// }