mirror of
https://github.com/starovoid/rxing.git
synced 2026-07-26 04:12:34 +00:00
feat: ported qr-model1 support from zxing-cpp
This commit is contained in:
@@ -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,
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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> {
|
||||
|
||||
// }
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
@@ -33,7 +33,7 @@ pub fn hasValidDimension(bitMatrix: &BitMatrix, isMicro: bool) -> bool {
|
||||
pub fn ReadVersion(bitMatrix: &BitMatrix) -> Result<VersionRef> {
|
||||
let dimension = bitMatrix.height();
|
||||
|
||||
let mut version = Version::FromDimension(dimension)?;
|
||||
let mut version = Version::FromDimension(dimension, false)?;
|
||||
|
||||
if version.getVersionNumber() < 7 {
|
||||
return Ok(version);
|
||||
@@ -235,6 +235,111 @@ 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 ReadCodewords(
|
||||
bitMatrix: &BitMatrix,
|
||||
version: VersionRef,
|
||||
@@ -246,6 +351,8 @@ pub fn ReadCodewords(
|
||||
|
||||
if version.isMicroQRCode() {
|
||||
ReadMQRCodewords(bitMatrix, version, formatInfo)
|
||||
} else if formatInfo.isModel1 {
|
||||
ReadQRCodewordsModel1(bitMatrix, version, formatInfo)
|
||||
} else {
|
||||
ReadQRCodewords(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.isQRCodeModel1() {
|
||||
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 {
|
||||
@@ -387,11 +391,21 @@ pub fn DecodeBitStream(
|
||||
.withError(res.err())
|
||||
.withEcLevel(ecLevel.to_string())
|
||||
.withVersionNumber(version.getVersionNumber())
|
||||
.withStructuredAppend(structuredAppend))
|
||||
.withStructuredAppend(structuredAppend)
|
||||
.withIsModel1(version.isQRCodeModel1()))
|
||||
}
|
||||
|
||||
pub fn Decode(bits: &BitMatrix) -> Result<DecoderResult<bool>> {
|
||||
let Ok(pversion) = ReadVersion(bits) else {
|
||||
let isMicroQRCode = bits.height() < 21;
|
||||
let Ok(formatInfo) = ReadFormatInformation(bits, isMicroQRCode) else {
|
||||
return Err(Exceptions::format_with("Invalid format information"));
|
||||
};
|
||||
|
||||
let Ok(pversion) = (if formatInfo.isModel1 {
|
||||
Version::FromDimension(bits.height(), true)
|
||||
} else {
|
||||
ReadVersion(bits)
|
||||
}) else {
|
||||
return Err(Exceptions::format_with("Invalid version"));
|
||||
};
|
||||
let version = pversion;
|
||||
|
||||
@@ -42,7 +42,7 @@ fn SimpleByteMode() {
|
||||
let bytes: Vec<u8> = ba.into();
|
||||
let result = DecodeBitStream(
|
||||
&bytes,
|
||||
Version::FromNumber(1, false).expect("find_version"),
|
||||
Version::FromNumber(1, false, false).expect("find_version"),
|
||||
ErrorCorrectionLevel::M,
|
||||
)
|
||||
.expect("Decode")
|
||||
@@ -64,7 +64,7 @@ fn SimpleSJIS() {
|
||||
let bytes: Vec<u8> = ba.into();
|
||||
let result = DecodeBitStream(
|
||||
&bytes,
|
||||
Version::FromNumber(1, false).unwrap(),
|
||||
Version::FromNumber(1, false, false).unwrap(),
|
||||
ErrorCorrectionLevel::M,
|
||||
)
|
||||
.unwrap()
|
||||
@@ -86,7 +86,7 @@ fn ECI() {
|
||||
let bytes: Vec<u8> = ba.into();
|
||||
let result = DecodeBitStream(
|
||||
&bytes,
|
||||
Version::FromNumber(1, false).unwrap(),
|
||||
Version::FromNumber(1, false, false).unwrap(),
|
||||
ErrorCorrectionLevel::M,
|
||||
)
|
||||
.unwrap()
|
||||
@@ -105,7 +105,7 @@ fn Hanzi() {
|
||||
let bytes: Vec<u8> = ba.into();
|
||||
let result = DecodeBitStream(
|
||||
&bytes,
|
||||
Version::FromNumber(1, false).unwrap(),
|
||||
Version::FromNumber(1, false, false).unwrap(),
|
||||
ErrorCorrectionLevel::M,
|
||||
)
|
||||
.unwrap()
|
||||
@@ -127,7 +127,7 @@ fn HanziLevel1() {
|
||||
|
||||
let result = DecodeBitStream(
|
||||
&bytes,
|
||||
Version::FromNumber(1, false).unwrap(),
|
||||
Version::FromNumber(1, false, false).unwrap(),
|
||||
ErrorCorrectionLevel::M,
|
||||
)
|
||||
.unwrap()
|
||||
@@ -138,7 +138,7 @@ fn HanziLevel1() {
|
||||
|
||||
#[test]
|
||||
fn SymbologyIdentifier() {
|
||||
let version = Version::FromNumber(1, false).unwrap();
|
||||
let version = Version::FromNumber(1, false, false).unwrap();
|
||||
let ecLevel = ErrorCorrectionLevel::M;
|
||||
|
||||
// Plain "ANUM(1) A"
|
||||
|
||||
@@ -63,7 +63,7 @@ fn DecodeWithBitDifference() {
|
||||
MASKED_TEST_FORMAT_INFO2 ^ 0x07,
|
||||
),
|
||||
);
|
||||
assert!(!FormatInformation::DecodeQR(
|
||||
assert!(FormatInformation::DecodeQR(
|
||||
MASKED_TEST_FORMAT_INFO ^ 0x0F,
|
||||
MASKED_TEST_FORMAT_INFO2 ^ 0x0F
|
||||
)
|
||||
|
||||
@@ -27,27 +27,39 @@ fn CharacterCount() {
|
||||
// Spot check a few values
|
||||
assert_eq!(
|
||||
10,
|
||||
Mode::CharacterCountBits(&Mode::NUMERIC, Version::FromNumber(5, false).unwrap())
|
||||
Mode::CharacterCountBits(
|
||||
&Mode::NUMERIC,
|
||||
Version::FromNumber(5, false, false).unwrap()
|
||||
)
|
||||
);
|
||||
assert_eq!(
|
||||
12,
|
||||
Mode::CharacterCountBits(&Mode::NUMERIC, Version::FromNumber(26, false).unwrap())
|
||||
Mode::CharacterCountBits(
|
||||
&Mode::NUMERIC,
|
||||
Version::FromNumber(26, false, false).unwrap()
|
||||
)
|
||||
);
|
||||
assert_eq!(
|
||||
14,
|
||||
Mode::CharacterCountBits(&Mode::NUMERIC, Version::FromNumber(40, false).unwrap())
|
||||
Mode::CharacterCountBits(
|
||||
&Mode::NUMERIC,
|
||||
Version::FromNumber(40, false, false).unwrap()
|
||||
)
|
||||
);
|
||||
assert_eq!(
|
||||
9,
|
||||
Mode::CharacterCountBits(&Mode::ALPHANUMERIC, Version::FromNumber(6, false).unwrap())
|
||||
Mode::CharacterCountBits(
|
||||
&Mode::ALPHANUMERIC,
|
||||
Version::FromNumber(6, false, false).unwrap()
|
||||
)
|
||||
);
|
||||
assert_eq!(
|
||||
8,
|
||||
Mode::CharacterCountBits(&Mode::BYTE, Version::FromNumber(7, false).unwrap())
|
||||
Mode::CharacterCountBits(&Mode::BYTE, Version::FromNumber(7, false, false).unwrap())
|
||||
);
|
||||
assert_eq!(
|
||||
8,
|
||||
Mode::CharacterCountBits(&Mode::KANJI, Version::FromNumber(8, false).unwrap())
|
||||
Mode::CharacterCountBits(&Mode::KANJI, Version::FromNumber(8, false, false).unwrap())
|
||||
);
|
||||
}
|
||||
|
||||
@@ -110,26 +122,29 @@ fn MicroCharacterCount() {
|
||||
// Spot check a few values
|
||||
assert_eq!(
|
||||
3,
|
||||
Mode::CharacterCountBits(&Mode::NUMERIC, Version::FromNumber(1, true).unwrap())
|
||||
Mode::CharacterCountBits(&Mode::NUMERIC, Version::FromNumber(1, true, false).unwrap())
|
||||
);
|
||||
assert_eq!(
|
||||
4,
|
||||
Mode::CharacterCountBits(&Mode::NUMERIC, Version::FromNumber(2, true).unwrap())
|
||||
Mode::CharacterCountBits(&Mode::NUMERIC, Version::FromNumber(2, true, false).unwrap())
|
||||
);
|
||||
assert_eq!(
|
||||
6,
|
||||
Mode::CharacterCountBits(&Mode::NUMERIC, Version::FromNumber(4, true).unwrap())
|
||||
Mode::CharacterCountBits(&Mode::NUMERIC, Version::FromNumber(4, true, false).unwrap())
|
||||
);
|
||||
assert_eq!(
|
||||
3,
|
||||
Mode::CharacterCountBits(&Mode::ALPHANUMERIC, Version::FromNumber(2, true).unwrap())
|
||||
Mode::CharacterCountBits(
|
||||
&Mode::ALPHANUMERIC,
|
||||
Version::FromNumber(2, true, false).unwrap()
|
||||
)
|
||||
);
|
||||
assert_eq!(
|
||||
4,
|
||||
Mode::CharacterCountBits(&Mode::BYTE, Version::FromNumber(3, true).unwrap())
|
||||
Mode::CharacterCountBits(&Mode::BYTE, Version::FromNumber(3, true, false).unwrap())
|
||||
);
|
||||
assert_eq!(
|
||||
4,
|
||||
Mode::CharacterCountBits(&Mode::KANJI, Version::FromNumber(4, true).unwrap())
|
||||
Mode::CharacterCountBits(&Mode::KANJI, Version::FromNumber(4, true, false).unwrap())
|
||||
);
|
||||
}
|
||||
|
||||
@@ -26,13 +26,13 @@ fn DoTestVersion(expectedVersion: u32, mask: i32) {
|
||||
|
||||
#[test]
|
||||
fn VersionForNumber() {
|
||||
let version = Version::FromNumber(0, false);
|
||||
let version = Version::FromNumber(0, false, false);
|
||||
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::FromNumber(i, false, false).expect("version number found"),
|
||||
i,
|
||||
4 * i + 17,
|
||||
);
|
||||
@@ -43,7 +43,7 @@ fn VersionForNumber() {
|
||||
fn GetProvisionalVersionForDimension() {
|
||||
for i in 1..=40 {
|
||||
// for (int i = 1; i <= 40; i++) {
|
||||
let prov = Version::FromDimension(4 * i + 17)
|
||||
let prov = Version::FromDimension(4 * i + 17, false)
|
||||
.unwrap_or_else(|_| panic!("version should exist for {i}"));
|
||||
// assert_ne!(prov, nullptr);
|
||||
assert_eq!(i, prov.getVersionNumber());
|
||||
@@ -63,13 +63,14 @@ fn DecodeVersionInformation() {
|
||||
|
||||
#[test]
|
||||
fn MicroVersionForNumber() {
|
||||
let version = Version::FromNumber(0, true);
|
||||
let version = Version::FromNumber(0, true, false);
|
||||
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::FromNumber(i, true, false)
|
||||
.unwrap_or_else(|_| panic!("version for {i} should exist")),
|
||||
i,
|
||||
2 * i + 9,
|
||||
);
|
||||
@@ -80,7 +81,7 @@ fn MicroVersionForNumber() {
|
||||
fn GetProvisionalMicroVersionForDimension() {
|
||||
for i in 1..=4 {
|
||||
// for (int i = 1; i <= 4; i++) {
|
||||
let prov = Version::FromDimension(2 * i + 9)
|
||||
let prov = Version::FromDimension(2 * i + 9, false)
|
||||
.unwrap_or_else(|_| panic!("version for micro {i} should exist"));
|
||||
// assert_ne!(prov, nullptr);
|
||||
assert_eq!(i, prov.getVersionNumber());
|
||||
@@ -100,7 +101,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::FromNumber(i, true, false).expect("version must be found");
|
||||
let functionPattern = version
|
||||
.buildFunctionPattern()
|
||||
.expect("function pattern must be found");
|
||||
|
||||
@@ -73,6 +73,7 @@ pub struct FormatInformation {
|
||||
pub data_mask: u8,
|
||||
pub microVersion: u32,
|
||||
pub isMirrored: bool,
|
||||
pub isModel1: bool,
|
||||
|
||||
pub index: u8, // = 255;
|
||||
pub bitsIndex: u8, // = 255;
|
||||
@@ -86,6 +87,7 @@ impl Default for FormatInformation {
|
||||
data_mask: Default::default(),
|
||||
microVersion: 0,
|
||||
isMirrored: false,
|
||||
isModel1: false,
|
||||
index: 255,
|
||||
bitsIndex: 255,
|
||||
}
|
||||
@@ -104,6 +106,7 @@ impl FormatInformation {
|
||||
error_correction_level: errorCorrectionLevel,
|
||||
data_mask: dataMask,
|
||||
isMirrored: false,
|
||||
isModel1: false,
|
||||
index: 255,
|
||||
bitsIndex: 255,
|
||||
})
|
||||
|
||||
@@ -29,6 +29,7 @@ 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);
|
||||
|
||||
/**
|
||||
* See ISO 18004:2006 Annex D.
|
||||
@@ -55,6 +56,7 @@ pub struct Version {
|
||||
ecBlocks: Vec<ECBlocks>,
|
||||
totalCodewords: u32,
|
||||
pub(crate) is_micro: bool,
|
||||
pub(crate) is_model1: bool,
|
||||
}
|
||||
impl Version {
|
||||
fn new(versionNumber: u32, alignmentPatternCenters: Vec<u32>, ecBlocks: [ECBlocks; 4]) -> Self {
|
||||
@@ -73,6 +75,7 @@ impl Version {
|
||||
ecBlocks: ecBlocks.to_vec(),
|
||||
totalCodewords: total,
|
||||
is_micro: false,
|
||||
is_model1: false,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -92,9 +95,35 @@ impl Version {
|
||||
ecBlocks,
|
||||
totalCodewords: total,
|
||||
is_micro: true,
|
||||
is_model1: false,
|
||||
}
|
||||
}
|
||||
|
||||
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,
|
||||
is_micro: false,
|
||||
is_model1: true,
|
||||
}
|
||||
}
|
||||
|
||||
// #[inline(always)]
|
||||
// pub(crate) const fn isMicro(ecBlocks: &[ECBlocks; 4]) -> bool {
|
||||
// ecBlocks[0].ecCodewordsPerBlock < 7 || ecBlocks[0].ecCodewordsPerBlock == 8
|
||||
// }
|
||||
|
||||
pub const fn getVersionNumber(&self) -> u32 {
|
||||
self.versionNumber
|
||||
}
|
||||
@@ -970,6 +999,224 @@ impl Version {
|
||||
new ECB::new(61, 16)))
|
||||
]*/
|
||||
}
|
||||
|
||||
/*
|
||||
* {1, {
|
||||
7 , 1, 19, 0, 0,
|
||||
10, 1, 16, 0, 0,
|
||||
13, 1, 13, 0, 0,
|
||||
17, 1, 9 , 0, 0
|
||||
}},
|
||||
{2, {
|
||||
10, 1, 36, 0, 0,
|
||||
16, 1, 30, 0, 0,
|
||||
22, 1, 24, 0, 0,
|
||||
30, 1, 16, 0, 0,
|
||||
}},
|
||||
{3, {
|
||||
15, 1, 57, 0, 0,
|
||||
28, 1, 44, 0, 0,
|
||||
36, 1, 36, 0, 0,
|
||||
48, 1, 24, 0, 0,
|
||||
}},
|
||||
{4, {
|
||||
20, 1, 80, 0, 0,
|
||||
40, 1, 60, 0, 0,
|
||||
50, 1, 50, 0, 0,
|
||||
66, 1, 34, 0, 0,
|
||||
}},
|
||||
{5, {
|
||||
26, 1, 108, 0, 0,
|
||||
52, 1, 82 , 0, 0,
|
||||
66, 1, 68 , 0, 0,
|
||||
88, 2, 46 , 0, 0,
|
||||
}},
|
||||
{6, {
|
||||
34 , 1, 136, 0, 0,
|
||||
63 , 2, 106, 0, 0,
|
||||
84 , 2, 86 , 0, 0,
|
||||
112, 2, 58 , 0, 0,
|
||||
}},
|
||||
{7, {
|
||||
42 , 1, 170, 0, 0,
|
||||
80 , 2, 132, 0, 0,
|
||||
104, 2, 108, 0, 0,
|
||||
138, 3, 72 , 0, 0,
|
||||
}},
|
||||
{8, {
|
||||
48 , 2, 208, 0, 0,
|
||||
96 , 2, 160, 0, 0,
|
||||
128, 2, 128, 0, 0,
|
||||
168, 3, 87 , 0, 0,
|
||||
}},
|
||||
{9, {
|
||||
60 , 2, 246, 0, 0,
|
||||
120, 2, 186, 0, 0,
|
||||
150, 3, 156, 0, 0,
|
||||
204, 3, 102, 0, 0,
|
||||
}},
|
||||
{10, {
|
||||
68 , 2, 290, 0, 0,
|
||||
136, 2, 222, 0, 0,
|
||||
174, 3, 183, 0, 0,
|
||||
232, 4, 124, 0, 0,
|
||||
}},
|
||||
{11, {
|
||||
80 , 2, 336, 0, 0,
|
||||
160, 4, 256, 0, 0,
|
||||
208, 4, 208, 0, 0,
|
||||
270, 5, 145, 0, 0,
|
||||
}},
|
||||
{12, {
|
||||
92 , 2, 384, 0, 0,
|
||||
184, 4, 292, 0, 0,
|
||||
232, 4, 244, 0, 0,
|
||||
310, 5, 165, 0, 0,
|
||||
}},
|
||||
{13, {
|
||||
108, 3, 432, 0, 0,
|
||||
208, 4, 332, 0, 0,
|
||||
264, 4, 276, 0, 0,
|
||||
348, 6, 192, 0, 0,
|
||||
}},
|
||||
{14, {
|
||||
120, 3, 489, 0, 0,
|
||||
240, 4, 368, 0, 0,
|
||||
300, 5, 310, 0, 0,
|
||||
396, 6, 210, 0, 0,
|
||||
}},
|
||||
};
|
||||
*/
|
||||
pub fn build_model1_versions() -> Vec<Version> {
|
||||
Vec::from([
|
||||
Version::new_model1(
|
||||
1,
|
||||
vec![
|
||||
ECBlocks::new(7, vec![ECB::new(1, 19)]),
|
||||
ECBlocks::new(10, vec![ECB::new(1, 16)]),
|
||||
ECBlocks::new(13, vec![ECB::new(1, 13)]),
|
||||
ECBlocks::new(17, vec![ECB::new(1, 9)]),
|
||||
],
|
||||
),
|
||||
Version::new_model1(
|
||||
2,
|
||||
vec![
|
||||
ECBlocks::new(10, vec![ECB::new(1, 36)]),
|
||||
ECBlocks::new(16, vec![ECB::new(1, 30)]),
|
||||
ECBlocks::new(22, vec![ECB::new(1, 24)]),
|
||||
ECBlocks::new(30, vec![ECB::new(1, 16)]),
|
||||
],
|
||||
),
|
||||
Version::new_model1(
|
||||
3,
|
||||
vec![
|
||||
ECBlocks::new(15, vec![ECB::new(1, 57)]),
|
||||
ECBlocks::new(28, vec![ECB::new(1, 44)]),
|
||||
ECBlocks::new(36, vec![ECB::new(1, 36)]),
|
||||
ECBlocks::new(48, vec![ECB::new(1, 24)]),
|
||||
],
|
||||
),
|
||||
Version::new_model1(
|
||||
4,
|
||||
vec![
|
||||
ECBlocks::new(20, vec![ECB::new(1, 80)]),
|
||||
ECBlocks::new(40, vec![ECB::new(1, 60)]),
|
||||
ECBlocks::new(50, vec![ECB::new(1, 50)]),
|
||||
ECBlocks::new(66, vec![ECB::new(1, 34)]),
|
||||
],
|
||||
),
|
||||
Version::new_model1(
|
||||
5,
|
||||
vec![
|
||||
ECBlocks::new(26, vec![ECB::new(1, 108)]),
|
||||
ECBlocks::new(52, vec![ECB::new(1, 82)]),
|
||||
ECBlocks::new(66, vec![ECB::new(1, 68)]),
|
||||
ECBlocks::new(88, vec![ECB::new(2, 46)]),
|
||||
],
|
||||
),
|
||||
Version::new_model1(
|
||||
6,
|
||||
vec![
|
||||
ECBlocks::new(34, vec![ECB::new(1, 136)]),
|
||||
ECBlocks::new(63, vec![ECB::new(2, 106)]),
|
||||
ECBlocks::new(84, vec![ECB::new(2, 86)]),
|
||||
ECBlocks::new(112, vec![ECB::new(2, 58)]),
|
||||
],
|
||||
),
|
||||
Version::new_model1(
|
||||
7,
|
||||
vec![
|
||||
ECBlocks::new(42, vec![ECB::new(1, 170)]),
|
||||
ECBlocks::new(80, vec![ECB::new(2, 132)]),
|
||||
ECBlocks::new(104, vec![ECB::new(2, 108)]),
|
||||
ECBlocks::new(138, vec![ECB::new(3, 72)]),
|
||||
],
|
||||
),
|
||||
Version::new_model1(
|
||||
8,
|
||||
vec![
|
||||
ECBlocks::new(48, vec![ECB::new(2, 208)]),
|
||||
ECBlocks::new(96, vec![ECB::new(2, 160)]),
|
||||
ECBlocks::new(128, vec![ECB::new(2, 128)]),
|
||||
ECBlocks::new(168, vec![ECB::new(3, 87)]),
|
||||
],
|
||||
),
|
||||
Version::new_model1(
|
||||
9,
|
||||
vec![
|
||||
ECBlocks::new(60, vec![ECB::new(2, 246)]),
|
||||
ECBlocks::new(120, vec![ECB::new(2, 186)]),
|
||||
ECBlocks::new(150, vec![ECB::new(3, 156)]),
|
||||
ECBlocks::new(204, vec![ECB::new(3, 102)]),
|
||||
],
|
||||
),
|
||||
Version::new_model1(
|
||||
10,
|
||||
vec![
|
||||
ECBlocks::new(68, vec![ECB::new(2, 290)]),
|
||||
ECBlocks::new(136, vec![ECB::new(2, 222)]),
|
||||
ECBlocks::new(174, vec![ECB::new(3, 183)]),
|
||||
ECBlocks::new(232, vec![ECB::new(4, 124)]),
|
||||
],
|
||||
),
|
||||
Version::new_model1(
|
||||
11,
|
||||
vec![
|
||||
ECBlocks::new(80, vec![ECB::new(2, 336)]),
|
||||
ECBlocks::new(160, vec![ECB::new(4, 256)]),
|
||||
ECBlocks::new(208, vec![ECB::new(4, 208)]),
|
||||
ECBlocks::new(270, vec![ECB::new(5, 145)]),
|
||||
],
|
||||
),
|
||||
Version::new_model1(
|
||||
12,
|
||||
vec![
|
||||
ECBlocks::new(92, vec![ECB::new(2, 384)]),
|
||||
ECBlocks::new(184, vec![ECB::new(4, 292)]),
|
||||
ECBlocks::new(232, vec![ECB::new(4, 244)]),
|
||||
ECBlocks::new(310, vec![ECB::new(5, 165)]),
|
||||
],
|
||||
),
|
||||
Version::new_model1(
|
||||
13,
|
||||
vec![
|
||||
ECBlocks::new(108, vec![ECB::new(3, 432)]),
|
||||
ECBlocks::new(208, vec![ECB::new(4, 332)]),
|
||||
ECBlocks::new(264, vec![ECB::new(4, 276)]),
|
||||
ECBlocks::new(348, vec![ECB::new(6, 192)]),
|
||||
],
|
||||
),
|
||||
Version::new_model1(
|
||||
14,
|
||||
vec![
|
||||
ECBlocks::new(120, vec![ECB::new(3, 489)]),
|
||||
ECBlocks::new(240, vec![ECB::new(4, 368)]),
|
||||
ECBlocks::new(300, vec![ECB::new(5, 310)]),
|
||||
ECBlocks::new(396, vec![ECB::new(6, 210)]),
|
||||
],
|
||||
),
|
||||
])
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for Version {
|
||||
|
||||
@@ -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
|
||||
@@ -198,10 +198,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;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user