mirror of
https://github.com/starovoid/rxing.git
synced 2026-07-26 04:12:34 +00:00
port: migrate to new cpp Version / FormatInformation
This commit is contained in:
@@ -1,43 +1,48 @@
|
|||||||
use crate::qrcode::decoder::{
|
use crate::qrcode::{
|
||||||
ErrorCorrectionLevel, FormatInformation, FORMAT_INFO_DECODE_LOOKUP, FORMAT_INFO_MASK_QR,
|
cpp_port::Type,
|
||||||
|
decoder::{
|
||||||
|
ErrorCorrectionLevel, FormatInformation, FORMAT_INFO_DECODE_LOOKUP,
|
||||||
|
FORMAT_INFO_MASK_MODEL2, FORMAT_INFO_MASK_QR,
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
pub const FORMAT_INFO_MASK_QR_MODEL1: u32 = 0x2825;
|
pub const FORMAT_INFO_MASK_QR_MODEL1: u32 = 0x2825;
|
||||||
|
pub const FORMAT_INFO_MASK_MICRO: u32 = 0x4445;
|
||||||
|
|
||||||
pub const FORMAT_INFO_DECODE_LOOKUP_MICRO: [[u32; 2]; 32] = [
|
// pub const FORMAT_INFO_DECODE_LOOKUP_MICRO: [u32 ;32] = [
|
||||||
[0x4445, 0x00],
|
// 0x4445,
|
||||||
[0x4172, 0x01],
|
// 0x4172,
|
||||||
[0x4E2B, 0x02],
|
// 0x4E2B,
|
||||||
[0x4B1C, 0x03],
|
// 0x4B1C,
|
||||||
[0x55AE, 0x04],
|
// 0x55AE,
|
||||||
[0x5099, 0x05],
|
// 0x5099,
|
||||||
[0x5FC0, 0x06],
|
// 0x5FC0,
|
||||||
[0x5AF7, 0x07],
|
// 0x5AF7,
|
||||||
[0x6793, 0x08],
|
// 0x6793,
|
||||||
[0x62A4, 0x09],
|
// 0x62A4,
|
||||||
[0x6DFD, 0x0A],
|
// 0x6DFD,
|
||||||
[0x68CA, 0x0B],
|
// 0x68CA,
|
||||||
[0x7678, 0x0C],
|
// 0x7678,
|
||||||
[0x734F, 0x0D],
|
// 0x734F,
|
||||||
[0x7C16, 0x0E],
|
// 0x7C16,
|
||||||
[0x7921, 0x0F],
|
// 0x7921,
|
||||||
[0x06DE, 0x10],
|
// 0x06DE,
|
||||||
[0x03E9, 0x11],
|
// 0x03E9,
|
||||||
[0x0CB0, 0x12],
|
// 0x0CB0,
|
||||||
[0x0987, 0x13],
|
// 0x0987,
|
||||||
[0x1735, 0x14],
|
// 0x1735,
|
||||||
[0x1202, 0x15],
|
// 0x1202,
|
||||||
[0x1D5B, 0x16],
|
// 0x1D5B,
|
||||||
[0x186C, 0x17],
|
// 0x186C,
|
||||||
[0x2508, 0x18],
|
// 0x2508,
|
||||||
[0x203F, 0x19],
|
// 0x203F,
|
||||||
[0x2F66, 0x1A],
|
// 0x2F66,
|
||||||
[0x2A51, 0x1B],
|
// 0x2A51,
|
||||||
[0x34E3, 0x1C],
|
// 0x34E3,
|
||||||
[0x31D4, 0x1D],
|
// 0x31D4,
|
||||||
[0x3E8D, 0x1E],
|
// 0x3E8D,
|
||||||
[0x3BBA, 0x1F],
|
// 0x3BBA,
|
||||||
];
|
// ];
|
||||||
|
|
||||||
impl FormatInformation {
|
impl FormatInformation {
|
||||||
/**
|
/**
|
||||||
@@ -51,9 +56,9 @@ impl FormatInformation {
|
|||||||
);
|
);
|
||||||
let formatInfoBits2 =
|
let formatInfoBits2 =
|
||||||
((formatInfoBits2 >> 1) & 0b111111100000000) | (formatInfoBits2 & 0b11111111);
|
((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(
|
let mut fi = Self::FindBestFormatInfo(
|
||||||
&[0, FORMAT_INFO_MASK_QR],
|
&[FORMAT_INFO_MASK_QR, 0, FORMAT_INFO_MASK_QR_MODEL1],
|
||||||
FORMAT_INFO_DECODE_LOOKUP,
|
|
||||||
&[
|
&[
|
||||||
formatInfoBits1,
|
formatInfoBits1,
|
||||||
formatInfoBits2,
|
formatInfoBits2,
|
||||||
@@ -62,26 +67,10 @@ 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.
|
// Use bits 3/4 for error correction, and 0-2 for mask.
|
||||||
fi.error_correction_level =
|
fi.error_correction_level =
|
||||||
ErrorCorrectionLevel::ECLevelFromBits((fi.index >> 3) & 0x03, false);
|
ErrorCorrectionLevel::ECLevelFromBits((fi.data >> 3) as u8 & 0x03, false);
|
||||||
fi.data_mask = fi.index & 0x07;
|
fi.data_mask = fi.data as u8 & 0x07;
|
||||||
fi.isMirrored = fi.bitsIndex > 1;
|
fi.isMirrored = fi.bitsIndex > 1;
|
||||||
|
|
||||||
fi
|
fi
|
||||||
@@ -90,8 +79,7 @@ impl FormatInformation {
|
|||||||
pub fn DecodeMQR(formatInfoBits: u32) -> Self {
|
pub fn DecodeMQR(formatInfoBits: u32) -> Self {
|
||||||
// We don't use the additional masking (with 0x4445) to work around potentially non complying MicroQRCode encoders
|
// We don't use the additional masking (with 0x4445) to work around potentially non complying MicroQRCode encoders
|
||||||
let mut fi = Self::FindBestFormatInfo(
|
let mut fi = Self::FindBestFormatInfo(
|
||||||
&[0],
|
&[FORMAT_INFO_MASK_MICRO, 0],
|
||||||
FORMAT_INFO_DECODE_LOOKUP_MICRO,
|
|
||||||
&[formatInfoBits, Self::MirrorBits(formatInfoBits)],
|
&[formatInfoBits, Self::MirrorBits(formatInfoBits)],
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -99,9 +87,9 @@ impl FormatInformation {
|
|||||||
|
|
||||||
// Bits 2/3/4 contain both error correction level and version, 0/1 contain mask.
|
// Bits 2/3/4 contain both error correction level and version, 0/1 contain mask.
|
||||||
fi.error_correction_level =
|
fi.error_correction_level =
|
||||||
ErrorCorrectionLevel::ECLevelFromBits((fi.index >> 2) & 0x07, true);
|
ErrorCorrectionLevel::ECLevelFromBits((fi.data >> 2) as u8 & 0x07, true);
|
||||||
fi.data_mask = fi.index & 0x03;
|
fi.data_mask = fi.data as u8 & 0x03;
|
||||||
fi.microVersion = BITS_TO_VERSION[((fi.index >> 2) & 0x07) as usize] as u32;
|
fi.microVersion = BITS_TO_VERSION[((fi.data >> 2) as u8 & 0x07) as usize] as u32;
|
||||||
fi.isMirrored = fi.bitsIndex == 1;
|
fi.isMirrored = fi.bitsIndex == 1;
|
||||||
|
|
||||||
fi
|
fi
|
||||||
@@ -112,21 +100,30 @@ impl FormatInformation {
|
|||||||
(bits.reverse_bits()) >> 17
|
(bits.reverse_bits()) >> 17
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn FindBestFormatInfo(masks: &[u32], lookup: [[u32; 2]; 32], bits: &[u32]) -> Self {
|
pub fn FindBestFormatInfo(masks: &[u32], bits: &[u32]) -> Self {
|
||||||
let mut fi = FormatInformation::default();
|
let mut fi = FormatInformation::default();
|
||||||
|
|
||||||
// Some QR codes apparently do not apply the XOR mask. Try without and with additional masking.
|
// 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 mask in masks {
|
||||||
// for (auto mask : {0, mask})
|
// for (auto mask : masks)
|
||||||
for (bitsIndex, bit_set) in bits.iter().enumerate() {
|
for bitsIndex in 0..bits.len() {
|
||||||
// for (int bitsIndex = 0; bitsIndex < Size(bits); ++bitsIndex)
|
// for (int bitsIndex = 0; bitsIndex < Size(bits); ++bitsIndex)
|
||||||
for [pattern, index] in lookup {
|
for ref_pattern in MODEL2_MASKED_PATTERNS {
|
||||||
// for (const auto& [pattern, index] : lookup) {
|
// for (uint32_t pattern : MODEL2_MASKED_PATTERNS) {
|
||||||
// Find the int in lookup with fewest bits differing
|
// 'unmask' the pattern first to get the original 5-data bits + 10-ec bits back
|
||||||
let hammingDist = ((bit_set ^ mask) ^ pattern).count_ones();
|
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 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.index = index as u8;
|
fi.data = pattern >> 10; // drop the 10 BCH error correction bits
|
||||||
fi.hammingDistance = hammingDist;
|
fi.hammingDistance = hammingDist;
|
||||||
fi.bitsIndex = bitsIndex as u8;
|
fi.bitsIndex = bitsIndex as u8;
|
||||||
}
|
}
|
||||||
@@ -134,9 +131,37 @@ 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
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn qr_type(&self) -> Type {
|
||||||
|
match self.mask {
|
||||||
|
FORMAT_INFO_MASK_QR_MODEL1 => Type::Model1,
|
||||||
|
FORMAT_INFO_MASK_MICRO => Type::Micro,
|
||||||
|
_ => Type::Model2,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Hamming distance of the 32 masked codes is 7, by construction, so <= 3 bits differing means we found a match
|
// 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 isValid(&self) -> bool {
|
||||||
self.hammingDistance <= 3
|
self.hammingDistance <= 3
|
||||||
@@ -145,5 +170,6 @@ impl FormatInformation {
|
|||||||
pub fn cpp_eq(&self, other: &Self) -> bool {
|
pub fn cpp_eq(&self, other: &Self) -> bool {
|
||||||
self.data_mask == other.data_mask
|
self.data_mask == other.data_mask
|
||||||
&& self.error_correction_level == other.error_correction_level
|
&& self.error_correction_level == other.error_correction_level
|
||||||
|
&& self.qr_type() == other.qr_type()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,60 +1,40 @@
|
|||||||
use crate::common::Result;
|
/*
|
||||||
|
* Copyright 2016 Nu-book Inc.
|
||||||
|
* Copyright 2016 ZXing authors
|
||||||
|
* Copyright 2023 Axel Waggershauser
|
||||||
|
*/
|
||||||
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
|
use crate::common::{BitMatrix, Result};
|
||||||
|
use crate::qrcode::cpp_port::Type;
|
||||||
use crate::qrcode::decoder::{
|
use crate::qrcode::decoder::{
|
||||||
Version, VersionRef, MICRO_VERSIONS, MODEL1_VERSIONS, VERSIONS, VERSION_DECODE_INFO,
|
Version, VersionRef, MICRO_VERSIONS, MODEL1_VERSIONS, VERSIONS, VERSION_DECODE_INFO,
|
||||||
};
|
};
|
||||||
use crate::Exceptions;
|
use crate::Exceptions;
|
||||||
|
|
||||||
// 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;
|
|
||||||
// }
|
|
||||||
|
|
||||||
impl Version {
|
impl Version {
|
||||||
pub fn FromDimension(dimension: u32, is_model1: bool) -> Result<VersionRef> {
|
pub fn Model1(version_number: u32) -> Result<VersionRef> {
|
||||||
let isMicro = dimension < 21;
|
if version_number < 1 || version_number > 14 {
|
||||||
if dimension % Self::DimensionStep(isMicro) != 1 {
|
Err(Exceptions::ILLEGAL_ARGUMENT)
|
||||||
//throw std::invalid_argument("Unexpected dimension");
|
} else {
|
||||||
return Err(Exceptions::ILLEGAL_ARGUMENT);
|
Ok(&MODEL1_VERSIONS[version_number as usize - 1])
|
||||||
}
|
}
|
||||||
Self::FromNumber(
|
|
||||||
(dimension - Self::DimensionOffset(isMicro)) / Self::DimensionStep(isMicro),
|
|
||||||
isMicro,
|
|
||||||
is_model1,
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn FromNumber(versionNumber: u32, is_micro: bool, is_model1: bool) -> Result<VersionRef> {
|
pub fn Model2(version_number: u32) -> Result<VersionRef> {
|
||||||
if versionNumber < 1
|
if version_number < 1 || version_number > 40 {
|
||||||
|| versionNumber
|
Err(Exceptions::ILLEGAL_ARGUMENT)
|
||||||
> (if is_micro {
|
|
||||||
4
|
|
||||||
} else {
|
} else {
|
||||||
if is_model1 {
|
Ok(&VERSIONS[version_number as usize - 1])
|
||||||
14
|
|
||||||
} else {
|
|
||||||
40
|
|
||||||
}
|
}
|
||||||
})
|
|
||||||
{
|
|
||||||
//throw std::invalid_argument("Version should be in range [1-40].");
|
|
||||||
return Err(Exceptions::ILLEGAL_ARGUMENT);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(if is_micro {
|
pub fn Micro(version_number: u32) -> Result<VersionRef> {
|
||||||
&MICRO_VERSIONS[versionNumber as usize - 1]
|
if version_number < 1 || version_number > 4 {
|
||||||
} else if is_model1 {
|
Err(Exceptions::ILLEGAL_ARGUMENT)
|
||||||
&MODEL1_VERSIONS[versionNumber as usize - 1]
|
|
||||||
} else {
|
} else {
|
||||||
&VERSIONS[versionNumber as usize - 1]
|
Ok(&MICRO_VERSIONS[version_number as usize - 1])
|
||||||
})
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn DimensionOfVersion(version: u32, is_micro: bool) -> u32 {
|
pub fn DimensionOfVersion(version: u32, is_micro: bool) -> u32 {
|
||||||
@@ -80,13 +60,6 @@ impl Version {
|
|||||||
let mut bestDifference = u32::MAX;
|
let mut bestDifference = u32::MAX;
|
||||||
let mut bestVersion = 0;
|
let mut bestVersion = 0;
|
||||||
for (i, targetVersion) in VERSION_DECODE_INFO.into_iter().enumerate() {
|
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 bits in [versionBitsA, versionBitsB] {
|
||||||
// for (int bits : {versionBitsA, versionBitsB}) {
|
// for (int bits : {versionBitsA, versionBitsB}) {
|
||||||
let bitsDifference = ((bits as u32) ^ targetVersion).count_ones(); //BitHacks::CountBitsSet(bits ^ targetVersion);
|
let bitsDifference = ((bits as u32) ^ targetVersion).count_ones(); //BitHacks::CountBitsSet(bits ^ targetVersion);
|
||||||
@@ -95,6 +68,9 @@ impl Version {
|
|||||||
bestDifference = bitsDifference;
|
bestDifference = bitsDifference;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if bestDifference == 0 {
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
// We can tolerate up to 3 bits of error since no two version info codewords will
|
// We can tolerate up to 3 bits of error since no two version info codewords will
|
||||||
// differ in less than 8 bits.
|
// differ in less than 8 bits.
|
||||||
@@ -105,11 +81,34 @@ impl Version {
|
|||||||
Err(Exceptions::ILLEGAL_STATE)
|
Err(Exceptions::ILLEGAL_STATE)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub const fn isMicroQRCode(&self) -> bool {
|
pub const fn isMicro(&self) -> bool {
|
||||||
self.is_micro
|
Type::const_eq(self.qr_type, Type::Micro)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub const fn isQRCodeModel1(&self) -> bool {
|
pub const fn isModel1(&self) -> bool {
|
||||||
self.is_model1
|
Type::const_eq(self.qr_type, Type::Model1)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub const fn isModel2(&self) -> bool {
|
||||||
|
Type::const_eq(self.qr_type, Type::Model2)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn HasMicroSize(bitMatrix: &BitMatrix) -> bool {
|
||||||
|
let size = bitMatrix.height();
|
||||||
|
size >= 11 && size <= 17 && (size % 2) == 1
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn HasValidSize(bitMatrix: &BitMatrix) -> bool {
|
||||||
|
let size = bitMatrix.height();
|
||||||
|
Self::HasMicroSize(bitMatrix) || (size >= 21 && size <= 177 && (size % 4) == 1)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn Number(bitMatrix: &BitMatrix) -> u32 {
|
||||||
|
if !Self::HasValidSize(bitMatrix) {
|
||||||
|
0
|
||||||
|
} else {
|
||||||
|
let isMicro = Self::HasMicroSize(bitMatrix);
|
||||||
|
(bitMatrix.height() - Self::DimensionOffset(isMicro)) / Self::DimensionStep(isMicro)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ use crate::{
|
|||||||
Exceptions,
|
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 {
|
pub fn getBit(bitMatrix: &BitMatrix, x: u32, y: u32, mirrored: Option<bool>) -> bool {
|
||||||
let mirrored = mirrored.unwrap_or(false);
|
let mirrored = mirrored.unwrap_or(false);
|
||||||
@@ -21,24 +21,27 @@ pub fn getBit(bitMatrix: &BitMatrix, x: u32, y: u32, mirrored: Option<bool>) ->
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn hasValidDimension(bitMatrix: &BitMatrix, isMicro: bool) -> bool {
|
pub fn ReadVersion(bitMatrix: &BitMatrix, qr_type: Type) -> Result<VersionRef> {
|
||||||
let dimension = bitMatrix.height();
|
if !Version::HasValidSize(bitMatrix) {
|
||||||
if isMicro {
|
return Err(Exceptions::FORMAT);
|
||||||
(11..=17).contains(&dimension) && (dimension % 2) == 1
|
|
||||||
} else {
|
|
||||||
(21..=177).contains(&dimension) && (dimension % 4) == 1
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn ReadVersion(bitMatrix: &BitMatrix) -> Result<VersionRef> {
|
let number = Version::Number(bitMatrix);
|
||||||
let dimension = bitMatrix.height();
|
|
||||||
|
|
||||||
let mut version = Version::FromDimension(dimension, false)?;
|
match qr_type {
|
||||||
|
Type::Model1 => return Version::Model1(number),
|
||||||
|
|
||||||
|
Type::Micro => return Version::Micro(number),
|
||||||
|
Type::Model2 => {}
|
||||||
|
}
|
||||||
|
let mut version = Version::Model2(number)?;
|
||||||
|
|
||||||
if version.getVersionNumber() < 7 {
|
if version.getVersionNumber() < 7 {
|
||||||
return Ok(version);
|
return Ok(version);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let dimension = bitMatrix.height();
|
||||||
|
|
||||||
for mirror in [false, true] {
|
for mirror in [false, true] {
|
||||||
// for (bool mirror : {false, true}) {
|
// for (bool mirror : {false, true}) {
|
||||||
// Read top-right/bottom-left version info: 3 wide by 6 tall (depending on mirrored)
|
// Read top-right/bottom-left version info: 3 wide by 6 tall (depending on mirrored)
|
||||||
@@ -60,12 +63,8 @@ pub fn ReadVersion(bitMatrix: &BitMatrix) -> Result<VersionRef> {
|
|||||||
Err(Exceptions::FORMAT)
|
Err(Exceptions::FORMAT)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn ReadFormatInformation(bitMatrix: &BitMatrix, isMicro: bool) -> Result<FormatInformation> {
|
pub fn ReadFormatInformation(bitMatrix: &BitMatrix) -> Result<FormatInformation> {
|
||||||
if !hasValidDimension(bitMatrix, isMicro) {
|
if Version::HasMicroSize(bitMatrix) {
|
||||||
return Err(Exceptions::FORMAT);
|
|
||||||
}
|
|
||||||
|
|
||||||
if isMicro {
|
|
||||||
// Read top-left format info bits
|
// Read top-left format info bits
|
||||||
let mut formatInfoBits = 0;
|
let mut formatInfoBits = 0;
|
||||||
for x in 1..9 {
|
for x in 1..9 {
|
||||||
@@ -345,15 +344,9 @@ pub fn ReadCodewords(
|
|||||||
version: VersionRef,
|
version: VersionRef,
|
||||||
formatInfo: &FormatInformation,
|
formatInfo: &FormatInformation,
|
||||||
) -> Result<Vec<u8>> {
|
) -> Result<Vec<u8>> {
|
||||||
if !hasValidDimension(bitMatrix, version.isMicroQRCode()) {
|
match version.qr_type {
|
||||||
return Err(Exceptions::FORMAT);
|
Type::Model1 => ReadQRCodewordsModel1(bitMatrix, version, formatInfo),
|
||||||
}
|
Type::Model2 => ReadQRCodewords(bitMatrix, version, formatInfo),
|
||||||
|
Type::Micro => ReadMQRCodewords(bitMatrix, version, formatInfo),
|
||||||
if version.isMicroQRCode() {
|
|
||||||
ReadMQRCodewords(bitMatrix, version, formatInfo)
|
|
||||||
} else if formatInfo.isModel1 {
|
|
||||||
ReadQRCodewordsModel1(bitMatrix, version, formatInfo)
|
|
||||||
} else {
|
|
||||||
ReadQRCodewords(bitMatrix, version, formatInfo)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,6 +17,8 @@ use crate::qrcode::cpp_port::bitmatrix_parser::{
|
|||||||
use crate::qrcode::decoder::{DataBlock, ErrorCorrectionLevel, Mode, Version};
|
use crate::qrcode::decoder::{DataBlock, ErrorCorrectionLevel, Mode, Version};
|
||||||
use crate::Exceptions;
|
use crate::Exceptions;
|
||||||
|
|
||||||
|
use super::Type;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* <p>Given data and error-correction codewords received, possibly corrupted by errors, attempts to
|
* <p>Given data and error-correction codewords received, possibly corrupted by errors, attempts to
|
||||||
* correct the errors in-place using Reed-Solomon error correction.</p>
|
* correct the errors in-place using Reed-Solomon error correction.</p>
|
||||||
@@ -299,7 +301,7 @@ pub fn DecodeBitStream(
|
|||||||
let mut structuredAppend = StructuredAppendInfo::default();
|
let mut structuredAppend = StructuredAppendInfo::default();
|
||||||
let modeBitLength = Mode::get_codec_mode_bits_length(version);
|
let modeBitLength = Mode::get_codec_mode_bits_length(version);
|
||||||
|
|
||||||
if version.isQRCodeModel1() {
|
if version.isModel1() {
|
||||||
bits.readBits(4)?; /* Model 1 is leading with 4 0-bits -> drop them */
|
bits.readBits(4)?; /* Model 1 is leading with 4 0-bits -> drop them */
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -310,7 +312,7 @@ pub fn DecodeBitStream(
|
|||||||
} else {
|
} else {
|
||||||
Mode::CodecModeForBits(
|
Mode::CodecModeForBits(
|
||||||
bits.readBits(modeBitLength as usize)?,
|
bits.readBits(modeBitLength as usize)?,
|
||||||
Some(version.isMicroQRCode()),
|
Some(version.isMicro()),
|
||||||
)?
|
)?
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -392,25 +394,23 @@ pub fn DecodeBitStream(
|
|||||||
.withEcLevel(ecLevel.to_string())
|
.withEcLevel(ecLevel.to_string())
|
||||||
.withVersionNumber(version.getVersionNumber())
|
.withVersionNumber(version.getVersionNumber())
|
||||||
.withStructuredAppend(structuredAppend)
|
.withStructuredAppend(structuredAppend)
|
||||||
.withIsModel1(version.isQRCodeModel1()))
|
.withIsModel1(version.isModel1()))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn Decode(bits: &BitMatrix) -> Result<DecoderResult<bool>> {
|
pub fn Decode(bits: &BitMatrix) -> Result<DecoderResult<bool>> {
|
||||||
let isMicroQRCode = bits.height() < 21;
|
if !Version::HasValidSize(bits) {
|
||||||
let Ok(formatInfo) = ReadFormatInformation(bits, isMicroQRCode) else {
|
return Err(Exceptions::format_with("Invalid symbol size"));
|
||||||
|
}
|
||||||
|
let Ok(formatInfo) = ReadFormatInformation(bits) else {
|
||||||
return Err(Exceptions::format_with("Invalid format information"));
|
return Err(Exceptions::format_with("Invalid format information"));
|
||||||
};
|
};
|
||||||
|
|
||||||
let Ok(pversion) = (if formatInfo.isModel1 {
|
let Ok(pversion) = ReadVersion(bits, formatInfo.qr_type()) else {
|
||||||
Version::FromDimension(bits.height(), true)
|
|
||||||
} else {
|
|
||||||
ReadVersion(bits)
|
|
||||||
}) else {
|
|
||||||
return Err(Exceptions::format_with("Invalid version"));
|
return Err(Exceptions::format_with("Invalid version"));
|
||||||
};
|
};
|
||||||
let version = pversion;
|
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"));
|
return Err(Exceptions::format_with("Invalid format information"));
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -7,5 +7,8 @@ pub use qr_cpp_reader::QrReader;
|
|||||||
|
|
||||||
mod bitmatrix_parser;
|
mod bitmatrix_parser;
|
||||||
|
|
||||||
|
mod qr_type;
|
||||||
|
pub use qr_type::Type;
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod test;
|
mod test;
|
||||||
|
|||||||
14
src/qrcode/cpp_port/qr_type.rs
Normal file
14
src/qrcode/cpp_port/qr_type.rs
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
#[derive(Debug, Hash, PartialEq, Eq, Clone, Copy)]
|
||||||
|
pub enum Type {
|
||||||
|
Model1,
|
||||||
|
Model2,
|
||||||
|
Micro,
|
||||||
|
}
|
||||||
|
|
||||||
|
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");
|
.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());
|
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");
|
let codewords = ReadCodewords(&bitMatrix, version, &format).expect("could not read codewords");
|
||||||
assert_eq!(17, codewords.len());
|
assert_eq!(17, codewords.len());
|
||||||
assert_eq!(0x0, codewords[10]);
|
assert_eq!(0x0, codewords[10]);
|
||||||
@@ -67,10 +67,10 @@ X X XXXX XXX
|
|||||||
)
|
)
|
||||||
.unwrap();
|
.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());
|
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");
|
let codewords = ReadCodewords(&bitMatrix, version, &format).expect("could not read codewords");
|
||||||
assert_eq!(17, codewords.len());
|
assert_eq!(17, codewords.len());
|
||||||
assert_eq!(0x0, codewords[8]);
|
assert_eq!(0x0, codewords[8]);
|
||||||
|
|||||||
@@ -42,7 +42,7 @@ fn SimpleByteMode() {
|
|||||||
let bytes: Vec<u8> = ba.into();
|
let bytes: Vec<u8> = ba.into();
|
||||||
let result = DecodeBitStream(
|
let result = DecodeBitStream(
|
||||||
&bytes,
|
&bytes,
|
||||||
Version::FromNumber(1, false, false).expect("find_version"),
|
Version::Model2(1).expect("find_version"),
|
||||||
ErrorCorrectionLevel::M,
|
ErrorCorrectionLevel::M,
|
||||||
)
|
)
|
||||||
.expect("Decode")
|
.expect("Decode")
|
||||||
@@ -62,11 +62,7 @@ fn SimpleSJIS() {
|
|||||||
ba.appendBits(0xA3, 8).expect("append");
|
ba.appendBits(0xA3, 8).expect("append");
|
||||||
ba.appendBits(0xD0, 8).expect("append");
|
ba.appendBits(0xD0, 8).expect("append");
|
||||||
let bytes: Vec<u8> = ba.into();
|
let bytes: Vec<u8> = ba.into();
|
||||||
let result = DecodeBitStream(
|
let result = DecodeBitStream(&bytes, Version::Model2(1).unwrap(), ErrorCorrectionLevel::M)
|
||||||
&bytes,
|
|
||||||
Version::FromNumber(1, false, false).unwrap(),
|
|
||||||
ErrorCorrectionLevel::M,
|
|
||||||
)
|
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.content()
|
.content()
|
||||||
.to_string();
|
.to_string();
|
||||||
@@ -84,11 +80,7 @@ fn ECI() {
|
|||||||
ba.appendBits(0xA2, 8).expect("append");
|
ba.appendBits(0xA2, 8).expect("append");
|
||||||
ba.appendBits(0xA3, 8).expect("append");
|
ba.appendBits(0xA3, 8).expect("append");
|
||||||
let bytes: Vec<u8> = ba.into();
|
let bytes: Vec<u8> = ba.into();
|
||||||
let result = DecodeBitStream(
|
let result = DecodeBitStream(&bytes, Version::Model2(1).unwrap(), ErrorCorrectionLevel::M)
|
||||||
&bytes,
|
|
||||||
Version::FromNumber(1, false, false).unwrap(),
|
|
||||||
ErrorCorrectionLevel::M,
|
|
||||||
)
|
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.content()
|
.content()
|
||||||
.to_string();
|
.to_string();
|
||||||
@@ -103,11 +95,7 @@ fn Hanzi() {
|
|||||||
ba.appendBits(0x01, 8).expect("append"); // 1 characters
|
ba.appendBits(0x01, 8).expect("append"); // 1 characters
|
||||||
ba.appendBits(0x03C1, 13).expect("append");
|
ba.appendBits(0x03C1, 13).expect("append");
|
||||||
let bytes: Vec<u8> = ba.into();
|
let bytes: Vec<u8> = ba.into();
|
||||||
let result = DecodeBitStream(
|
let result = DecodeBitStream(&bytes, Version::Model2(1).unwrap(), ErrorCorrectionLevel::M)
|
||||||
&bytes,
|
|
||||||
Version::FromNumber(1, false, false).unwrap(),
|
|
||||||
ErrorCorrectionLevel::M,
|
|
||||||
)
|
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.content()
|
.content()
|
||||||
.to_string();
|
.to_string();
|
||||||
@@ -125,11 +113,7 @@ fn HanziLevel1() {
|
|||||||
|
|
||||||
let bytes: Vec<u8> = ba.into();
|
let bytes: Vec<u8> = ba.into();
|
||||||
|
|
||||||
let result = DecodeBitStream(
|
let result = DecodeBitStream(&bytes, Version::Model2(1).unwrap(), ErrorCorrectionLevel::M)
|
||||||
&bytes,
|
|
||||||
Version::FromNumber(1, false, false).unwrap(),
|
|
||||||
ErrorCorrectionLevel::M,
|
|
||||||
)
|
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.content()
|
.content()
|
||||||
.to_string();
|
.to_string();
|
||||||
@@ -138,7 +122,7 @@ fn HanziLevel1() {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn SymbologyIdentifier() {
|
fn SymbologyIdentifier() {
|
||||||
let version = Version::FromNumber(1, false, false).unwrap();
|
let version = Version::Model2(1).unwrap();
|
||||||
let ecLevel = ErrorCorrectionLevel::M;
|
let ecLevel = ErrorCorrectionLevel::M;
|
||||||
|
|
||||||
// Plain "ANUM(1) A"
|
// Plain "ANUM(1) A"
|
||||||
|
|||||||
@@ -4,7 +4,10 @@
|
|||||||
*/
|
*/
|
||||||
// SPDX-License-Identifier: Apache-2.0
|
// 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_INFO: u32 = 0x2BED;
|
||||||
const MASKED_TEST_FORMAT_INFO2: u32 =
|
const MASKED_TEST_FORMAT_INFO2: u32 =
|
||||||
@@ -63,11 +66,12 @@ fn DecodeWithBitDifference() {
|
|||||||
MASKED_TEST_FORMAT_INFO2 ^ 0x07,
|
MASKED_TEST_FORMAT_INFO2 ^ 0x07,
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
assert!(FormatInformation::DecodeQR(
|
let unexpected = FormatInformation::DecodeQR(
|
||||||
MASKED_TEST_FORMAT_INFO ^ 0x0F,
|
MASKED_TEST_FORMAT_INFO ^ 0x0F,
|
||||||
MASKED_TEST_FORMAT_INFO2 ^ 0x0F
|
MASKED_TEST_FORMAT_INFO2 ^ 0x0F,
|
||||||
)
|
);
|
||||||
.isValid());
|
assert!(!&expected.cpp_eq(&unexpected));
|
||||||
|
assert!(!(unexpected.isValid() && unexpected.qr_type() == Type::Model2));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
|||||||
@@ -27,39 +27,27 @@ fn CharacterCount() {
|
|||||||
// Spot check a few values
|
// Spot check a few values
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
10,
|
10,
|
||||||
Mode::CharacterCountBits(
|
Mode::CharacterCountBits(&Mode::NUMERIC, Version::Model2(5).unwrap())
|
||||||
&Mode::NUMERIC,
|
|
||||||
Version::FromNumber(5, false, false).unwrap()
|
|
||||||
)
|
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
12,
|
12,
|
||||||
Mode::CharacterCountBits(
|
Mode::CharacterCountBits(&Mode::NUMERIC, Version::Model2(26).unwrap())
|
||||||
&Mode::NUMERIC,
|
|
||||||
Version::FromNumber(26, false, false).unwrap()
|
|
||||||
)
|
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
14,
|
14,
|
||||||
Mode::CharacterCountBits(
|
Mode::CharacterCountBits(&Mode::NUMERIC, Version::Model2(40).unwrap())
|
||||||
&Mode::NUMERIC,
|
|
||||||
Version::FromNumber(40, false, false).unwrap()
|
|
||||||
)
|
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
9,
|
9,
|
||||||
Mode::CharacterCountBits(
|
Mode::CharacterCountBits(&Mode::ALPHANUMERIC, Version::Model2(6).unwrap())
|
||||||
&Mode::ALPHANUMERIC,
|
|
||||||
Version::FromNumber(6, false, false).unwrap()
|
|
||||||
)
|
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
8,
|
8,
|
||||||
Mode::CharacterCountBits(&Mode::BYTE, Version::FromNumber(7, false, false).unwrap())
|
Mode::CharacterCountBits(&Mode::BYTE, Version::Model2(7).unwrap())
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
8,
|
8,
|
||||||
Mode::CharacterCountBits(&Mode::KANJI, Version::FromNumber(8, false, false).unwrap())
|
Mode::CharacterCountBits(&Mode::KANJI, Version::Model2(8).unwrap())
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -122,29 +110,26 @@ fn MicroCharacterCount() {
|
|||||||
// Spot check a few values
|
// Spot check a few values
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
3,
|
3,
|
||||||
Mode::CharacterCountBits(&Mode::NUMERIC, Version::FromNumber(1, true, false).unwrap())
|
Mode::CharacterCountBits(&Mode::NUMERIC, Version::Micro(1).unwrap())
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
4,
|
4,
|
||||||
Mode::CharacterCountBits(&Mode::NUMERIC, Version::FromNumber(2, true, false).unwrap())
|
Mode::CharacterCountBits(&Mode::NUMERIC, Version::Micro(2).unwrap())
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
6,
|
6,
|
||||||
Mode::CharacterCountBits(&Mode::NUMERIC, Version::FromNumber(4, true, false).unwrap())
|
Mode::CharacterCountBits(&Mode::NUMERIC, Version::Micro(4).unwrap())
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
3,
|
3,
|
||||||
Mode::CharacterCountBits(
|
Mode::CharacterCountBits(&Mode::ALPHANUMERIC, Version::Micro(2).unwrap())
|
||||||
&Mode::ALPHANUMERIC,
|
|
||||||
Version::FromNumber(2, true, false).unwrap()
|
|
||||||
)
|
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
4,
|
4,
|
||||||
Mode::CharacterCountBits(&Mode::BYTE, Version::FromNumber(3, true, false).unwrap())
|
Mode::CharacterCountBits(&Mode::BYTE, Version::Micro(3).unwrap())
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
4,
|
4,
|
||||||
Mode::CharacterCountBits(&Mode::KANJI, Version::FromNumber(4, true, false).unwrap())
|
Mode::CharacterCountBits(&Mode::KANJI, Version::Micro(4).unwrap())
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ use crate::{
|
|||||||
fn CheckVersion(version: VersionRef, number: u32, dimension: u32) {
|
fn CheckVersion(version: VersionRef, number: u32, dimension: u32) {
|
||||||
// assert_ne!(version, nullptr);
|
// assert_ne!(version, nullptr);
|
||||||
assert_eq!(number, version.getVersionNumber());
|
assert_eq!(number, version.getVersionNumber());
|
||||||
if number > 1 && !version.isMicroQRCode() {
|
if number > 1 && version.isModel2() {
|
||||||
assert!(!version.getAlignmentPatternCenters().is_empty());
|
assert!(!version.getAlignmentPatternCenters().is_empty());
|
||||||
}
|
}
|
||||||
assert_eq!(dimension, version.getDimensionForVersion());
|
assert_eq!(dimension, version.getDimensionForVersion());
|
||||||
@@ -26,13 +26,13 @@ fn DoTestVersion(expectedVersion: u32, mask: i32) {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn VersionForNumber() {
|
fn VersionForNumber() {
|
||||||
let version = Version::FromNumber(0, false, false);
|
let version = Version::Model2(0);
|
||||||
assert!(version.is_err(), "There is version with number 0");
|
assert!(version.is_err(), "There is version with number 0");
|
||||||
|
|
||||||
for i in 1..=40 {
|
for i in 1..=40 {
|
||||||
// for (int i = 1; i <= 40; i++) {
|
// for (int i = 1; i <= 40; i++) {
|
||||||
CheckVersion(
|
CheckVersion(
|
||||||
Version::FromNumber(i, false, false).expect("version number found"),
|
Version::Model2(i).expect("version number found"),
|
||||||
i,
|
i,
|
||||||
4 * i + 17,
|
4 * i + 17,
|
||||||
);
|
);
|
||||||
@@ -43,10 +43,13 @@ fn VersionForNumber() {
|
|||||||
fn GetProvisionalVersionForDimension() {
|
fn GetProvisionalVersionForDimension() {
|
||||||
for i in 1..=40 {
|
for i in 1..=40 {
|
||||||
// for (int i = 1; i <= 40; i++) {
|
// for (int i = 1; i <= 40; i++) {
|
||||||
let prov = Version::FromDimension(4 * i + 17, false)
|
|
||||||
.unwrap_or_else(|_| panic!("version should exist for {i}"));
|
|
||||||
// assert_ne!(prov, nullptr);
|
// 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,14 +66,13 @@ fn DecodeVersionInformation() {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn MicroVersionForNumber() {
|
fn MicroVersionForNumber() {
|
||||||
let version = Version::FromNumber(0, true, false);
|
let version = Version::Micro(0);
|
||||||
assert!(version.is_err(), "There is version with number 0");
|
assert!(version.is_err(), "There is version with number 0");
|
||||||
|
|
||||||
for i in 1..=4 {
|
for i in 1..=4 {
|
||||||
// for (int i = 1; i <= 4; i++) {
|
// for (int i = 1; i <= 4; i++) {
|
||||||
CheckVersion(
|
CheckVersion(
|
||||||
Version::FromNumber(i, true, false)
|
Version::Micro(i).unwrap_or_else(|_| panic!("version for {i} should exist")),
|
||||||
.unwrap_or_else(|_| panic!("version for {i} should exist")),
|
|
||||||
i,
|
i,
|
||||||
2 * i + 9,
|
2 * i + 9,
|
||||||
);
|
);
|
||||||
@@ -81,10 +83,12 @@ fn MicroVersionForNumber() {
|
|||||||
fn GetProvisionalMicroVersionForDimension() {
|
fn GetProvisionalMicroVersionForDimension() {
|
||||||
for i in 1..=4 {
|
for i in 1..=4 {
|
||||||
// for (int i = 1; i <= 4; i++) {
|
// for (int i = 1; i <= 4; i++) {
|
||||||
let prov = Version::FromDimension(2 * i + 9, false)
|
assert_eq!(
|
||||||
.unwrap_or_else(|_| panic!("version for micro {i} should exist"));
|
i,
|
||||||
// assert_ne!(prov, nullptr);
|
Version::Number(
|
||||||
assert_eq!(i, prov.getVersionNumber());
|
&BitMatrix::with_single_dimension(2 * i + 9).expect("must create bitmatrix")
|
||||||
|
)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -101,7 +105,7 @@ fn FunctionPattern() {
|
|||||||
};
|
};
|
||||||
for i in 1..=4 {
|
for i in 1..=4 {
|
||||||
// for (int i = 1; i <= 4; i++) {
|
// for (int i = 1; i <= 4; i++) {
|
||||||
let version = Version::FromNumber(i, true, false).expect("version must be found");
|
let version = Version::Micro(i).expect("version must be found");
|
||||||
let functionPattern = version
|
let functionPattern = version
|
||||||
.buildFunctionPattern()
|
.buildFunctionPattern()
|
||||||
.expect("function pattern must be found");
|
.expect("function pattern must be found");
|
||||||
|
|||||||
@@ -19,6 +19,7 @@ use crate::common::Result;
|
|||||||
use super::ErrorCorrectionLevel;
|
use super::ErrorCorrectionLevel;
|
||||||
|
|
||||||
pub const FORMAT_INFO_MASK_QR: u32 = 0x5412;
|
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
|
* See ISO 18004:2006, Annex C, Table C.1
|
||||||
@@ -73,9 +74,9 @@ pub struct FormatInformation {
|
|||||||
pub data_mask: u8,
|
pub data_mask: u8,
|
||||||
pub microVersion: u32,
|
pub microVersion: u32,
|
||||||
pub isMirrored: bool,
|
pub isMirrored: bool,
|
||||||
pub isModel1: bool,
|
|
||||||
|
|
||||||
pub index: u8, // = 255;
|
pub mask: u32, // = 0
|
||||||
|
pub data: u32, // = 255
|
||||||
pub bitsIndex: u8, // = 255;
|
pub bitsIndex: u8, // = 255;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -87,8 +88,8 @@ impl Default for FormatInformation {
|
|||||||
data_mask: Default::default(),
|
data_mask: Default::default(),
|
||||||
microVersion: 0,
|
microVersion: 0,
|
||||||
isMirrored: false,
|
isMirrored: false,
|
||||||
isModel1: false,
|
mask: 0,
|
||||||
index: 255,
|
data: 255,
|
||||||
bitsIndex: 255,
|
bitsIndex: 255,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -106,9 +107,9 @@ impl FormatInformation {
|
|||||||
error_correction_level: errorCorrectionLevel,
|
error_correction_level: errorCorrectionLevel,
|
||||||
data_mask: dataMask,
|
data_mask: dataMask,
|
||||||
isMirrored: false,
|
isMirrored: false,
|
||||||
isModel1: false,
|
mask: 0,
|
||||||
index: 255,
|
|
||||||
bitsIndex: 255,
|
bitsIndex: 255,
|
||||||
|
data: 255,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -123,14 +123,14 @@ impl Mode {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub const fn get_terminator_bit_length(version: &Version) -> u8 {
|
pub const fn get_terminator_bit_length(version: &Version) -> u8 {
|
||||||
(if version.isMicroQRCode() {
|
(if version.isMicro() {
|
||||||
version.getVersionNumber() * 2 + 1
|
version.getVersionNumber() * 2 + 1
|
||||||
} else {
|
} else {
|
||||||
4
|
4
|
||||||
}) as u8
|
}) as u8
|
||||||
}
|
}
|
||||||
pub const fn get_codec_mode_bits_length(version: &Version) -> u8 {
|
pub const fn get_codec_mode_bits_length(version: &Version) -> u8 {
|
||||||
(if version.isMicroQRCode() {
|
(if version.isMicro() {
|
||||||
version.getVersionNumber() - 1
|
version.getVersionNumber() - 1
|
||||||
} else {
|
} else {
|
||||||
4
|
4
|
||||||
@@ -168,7 +168,7 @@ impl Mode {
|
|||||||
*/
|
*/
|
||||||
pub fn CharacterCountBits(&self, version: &Version) -> u32 {
|
pub fn CharacterCountBits(&self, version: &Version) -> u32 {
|
||||||
let number = version.getVersionNumber() as usize;
|
let number = version.getVersionNumber() as usize;
|
||||||
if version.isMicroQRCode() {
|
if version.isMicro() {
|
||||||
match self {
|
match self {
|
||||||
Mode::NUMERIC=> return [3, 4, 5, 6][number - 1],
|
Mode::NUMERIC=> return [3, 4, 5, 6][number - 1],
|
||||||
Mode::ALPHANUMERIC=> return [3, 4, 5][number - 2],
|
Mode::ALPHANUMERIC=> return [3, 4, 5][number - 2],
|
||||||
|
|||||||
@@ -18,6 +18,7 @@ use std::fmt;
|
|||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
common::{BitMatrix, Result},
|
common::{BitMatrix, Result},
|
||||||
|
qrcode::cpp_port::Type,
|
||||||
Exceptions,
|
Exceptions,
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -55,8 +56,7 @@ pub struct Version {
|
|||||||
alignmentPatternCenters: Vec<u32>,
|
alignmentPatternCenters: Vec<u32>,
|
||||||
ecBlocks: Vec<ECBlocks>,
|
ecBlocks: Vec<ECBlocks>,
|
||||||
totalCodewords: u32,
|
totalCodewords: u32,
|
||||||
pub(crate) is_micro: bool,
|
pub(crate) qr_type: Type,
|
||||||
pub(crate) is_model1: bool,
|
|
||||||
}
|
}
|
||||||
impl Version {
|
impl Version {
|
||||||
fn new(versionNumber: u32, alignmentPatternCenters: Vec<u32>, ecBlocks: [ECBlocks; 4]) -> Self {
|
fn new(versionNumber: u32, alignmentPatternCenters: Vec<u32>, ecBlocks: [ECBlocks; 4]) -> Self {
|
||||||
@@ -74,8 +74,7 @@ impl Version {
|
|||||||
alignmentPatternCenters,
|
alignmentPatternCenters,
|
||||||
ecBlocks: ecBlocks.to_vec(),
|
ecBlocks: ecBlocks.to_vec(),
|
||||||
totalCodewords: total,
|
totalCodewords: total,
|
||||||
is_micro: false,
|
qr_type: Type::Model2,
|
||||||
is_model1: false,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -94,8 +93,7 @@ impl Version {
|
|||||||
alignmentPatternCenters: Vec::default(),
|
alignmentPatternCenters: Vec::default(),
|
||||||
ecBlocks,
|
ecBlocks,
|
||||||
totalCodewords: total,
|
totalCodewords: total,
|
||||||
is_micro: true,
|
qr_type: Type::Micro,
|
||||||
is_model1: false,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -114,8 +112,7 @@ impl Version {
|
|||||||
alignmentPatternCenters: Vec::default(),
|
alignmentPatternCenters: Vec::default(),
|
||||||
ecBlocks,
|
ecBlocks,
|
||||||
totalCodewords: total,
|
totalCodewords: total,
|
||||||
is_micro: false,
|
qr_type: Type::Model1,
|
||||||
is_model1: true,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -137,7 +134,7 @@ impl Version {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn getDimensionForVersion(&self) -> u32 {
|
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
|
// 17 + 4 * self.versionNumber
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -205,7 +202,7 @@ impl Version {
|
|||||||
// Top left finder pattern + separator + format
|
// Top left finder pattern + separator + format
|
||||||
bitMatrix.setRegion(0, 0, 9, 9)?;
|
bitMatrix.setRegion(0, 0, 9, 9)?;
|
||||||
|
|
||||||
if !self.is_micro {
|
if self.qr_type != Type::Micro {
|
||||||
// Top right finder pattern + separator + format
|
// Top right finder pattern + separator + format
|
||||||
bitMatrix.setRegion(dimension - 8, 0, 8, 9)?;
|
bitMatrix.setRegion(dimension - 8, 0, 8, 9)?;
|
||||||
// Bottom left finder pattern + separator + format
|
// Bottom left finder pattern + separator + format
|
||||||
|
|||||||
Reference in New Issue
Block a user