mirror of
https://github.com/starovoid/rxing.git
synced 2026-07-26 04:12:34 +00:00
cargo fmt
This commit is contained in:
@@ -14,12 +14,9 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
use std::{
|
||||
collections::HashMap,
|
||||
path::{ PathBuf},
|
||||
};
|
||||
use std::{collections::HashMap, path::PathBuf};
|
||||
|
||||
use image::{DynamicImage};
|
||||
use image::DynamicImage;
|
||||
|
||||
use crate::{
|
||||
common::BitMatrix, qrcode::QRCodeWriter, BarcodeFormat, EncodeHintType, EncodeHintValue, Writer,
|
||||
@@ -85,7 +82,7 @@ fn testQRCodeWriter() {
|
||||
// The QR should be multiplied up to fit, with extra padding if necessary
|
||||
let bigEnough = 256;
|
||||
let writer = QRCodeWriter {};
|
||||
let matrix = writer.encode_with_hints(
|
||||
let matrix = writer.encode_with_hints(
|
||||
"http://www.google.com/",
|
||||
&BarcodeFormat::QR_CODE,
|
||||
bigEnough,
|
||||
|
||||
@@ -28,21 +28,18 @@ type MaskCondition = fn(u32, u32) -> bool;
|
||||
fn testMask0() {
|
||||
testMaskAcrossDimensions(DataMask::DATA_MASK_000, |i, j| ((i + j) % 2 == 0));
|
||||
testMaskAcrossDimensionsU8(0, |i, j| ((i + j) % 2 == 0));
|
||||
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn testMask1() {
|
||||
testMaskAcrossDimensions(DataMask::DATA_MASK_001, |i, j| i % 2 == 0);
|
||||
testMaskAcrossDimensionsU8(1, |i, j| i % 2 == 0);
|
||||
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn testMask2() {
|
||||
testMaskAcrossDimensions(DataMask::DATA_MASK_010, |i, j| j % 3 == 0);
|
||||
testMaskAcrossDimensionsU8(2, |i, j| j % 3 == 0);
|
||||
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -62,9 +59,7 @@ fn testMask5() {
|
||||
testMaskAcrossDimensions(DataMask::DATA_MASK_101, |i, j| {
|
||||
(i * j) % 2 + (i * j) % 3 == 0
|
||||
});
|
||||
testMaskAcrossDimensionsU8(5, |i, j| {
|
||||
(i * j) % 2 + (i * j) % 3 == 0
|
||||
});
|
||||
testMaskAcrossDimensionsU8(5, |i, j| (i * j) % 2 + (i * j) % 3 == 0);
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -72,9 +67,7 @@ fn testMask6() {
|
||||
testMaskAcrossDimensions(DataMask::DATA_MASK_110, |i, j| {
|
||||
((i * j) % 2 + (i * j) % 3) % 2 == 0
|
||||
});
|
||||
testMaskAcrossDimensionsU8(6, |i, j| {
|
||||
((i * j) % 2 + (i * j) % 3) % 2 == 0
|
||||
});
|
||||
testMaskAcrossDimensionsU8(6, |i, j| ((i * j) % 2 + (i * j) % 3) % 2 == 0);
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -82,9 +75,7 @@ fn testMask7() {
|
||||
testMaskAcrossDimensions(DataMask::DATA_MASK_111, |i, j| {
|
||||
((i + j) % 2 + (i * j) % 3) % 2 == 0
|
||||
});
|
||||
testMaskAcrossDimensionsU8(7, |i, j| {
|
||||
((i + j) % 2 + (i * j) % 3) % 2 == 0
|
||||
});
|
||||
testMaskAcrossDimensionsU8(7, |i, j| ((i + j) % 2 + (i * j) % 3) % 2 == 0);
|
||||
}
|
||||
|
||||
fn testMaskAcrossDimensionsU8(mask: u8, condition: MaskCondition) {
|
||||
|
||||
@@ -14,57 +14,97 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
use crate::qrcode::decoder::{FormatInformation, ErrorCorrectionLevel};
|
||||
use crate::qrcode::decoder::{ErrorCorrectionLevel, FormatInformation};
|
||||
|
||||
/**
|
||||
* @author Sean Owen
|
||||
*/
|
||||
|
||||
const MASKED_TEST_FORMAT_INFO: u32 = 0x2BED;
|
||||
const UNMASKED_TEST_FORMAT_INFO: u32 = MASKED_TEST_FORMAT_INFO ^ 0x5412;
|
||||
|
||||
const MASKED_TEST_FORMAT_INFO : u32 = 0x2BED;
|
||||
const UNMASKED_TEST_FORMAT_INFO : u32= MASKED_TEST_FORMAT_INFO ^ 0x5412;
|
||||
|
||||
#[test]
|
||||
fn testBitsDiffering() {
|
||||
#[test]
|
||||
fn testBitsDiffering() {
|
||||
assert_eq!(0, FormatInformation::numBitsDiffering(1, 1));
|
||||
assert_eq!(1, FormatInformation::numBitsDiffering(0, 2));
|
||||
assert_eq!(2, FormatInformation::numBitsDiffering(1, 2));
|
||||
assert_eq!(32, FormatInformation::numBitsDiffering(-1i32 as u32, 0));
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn testDecode() {
|
||||
#[test]
|
||||
fn testDecode() {
|
||||
// Normal case
|
||||
let expected =
|
||||
FormatInformation::decodeFormatInformation(MASKED_TEST_FORMAT_INFO, MASKED_TEST_FORMAT_INFO);
|
||||
let expected = FormatInformation::decodeFormatInformation(
|
||||
MASKED_TEST_FORMAT_INFO,
|
||||
MASKED_TEST_FORMAT_INFO,
|
||||
);
|
||||
assert!(expected.is_some());
|
||||
let expected = expected.unwrap();
|
||||
assert_eq!( 0x07, expected.getDataMask());
|
||||
assert_eq!(0x07, expected.getDataMask());
|
||||
assert_eq!(ErrorCorrectionLevel::Q, expected.getErrorCorrectionLevel());
|
||||
// where the code forgot the mask!
|
||||
assert_eq!(expected,
|
||||
FormatInformation::decodeFormatInformation(UNMASKED_TEST_FORMAT_INFO, MASKED_TEST_FORMAT_INFO).expect("return"));
|
||||
}
|
||||
assert_eq!(
|
||||
expected,
|
||||
FormatInformation::decodeFormatInformation(
|
||||
UNMASKED_TEST_FORMAT_INFO,
|
||||
MASKED_TEST_FORMAT_INFO
|
||||
)
|
||||
.expect("return")
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn testDecodeWithBitDifference() {
|
||||
let expected =
|
||||
FormatInformation::decodeFormatInformation(MASKED_TEST_FORMAT_INFO, MASKED_TEST_FORMAT_INFO).unwrap();
|
||||
#[test]
|
||||
fn testDecodeWithBitDifference() {
|
||||
let expected = FormatInformation::decodeFormatInformation(
|
||||
MASKED_TEST_FORMAT_INFO,
|
||||
MASKED_TEST_FORMAT_INFO,
|
||||
)
|
||||
.unwrap();
|
||||
// 1,2,3,4 bits difference
|
||||
assert_eq!(expected, FormatInformation::decodeFormatInformation(
|
||||
MASKED_TEST_FORMAT_INFO ^ 0x01, MASKED_TEST_FORMAT_INFO ^ 0x01).expect("return"));
|
||||
assert_eq!(expected, FormatInformation::decodeFormatInformation(
|
||||
MASKED_TEST_FORMAT_INFO ^ 0x03, MASKED_TEST_FORMAT_INFO ^ 0x03).expect("return"));
|
||||
assert_eq!(expected, FormatInformation::decodeFormatInformation(
|
||||
MASKED_TEST_FORMAT_INFO ^ 0x07, MASKED_TEST_FORMAT_INFO ^ 0x07).expect("return"));
|
||||
assert_eq!(
|
||||
expected,
|
||||
FormatInformation::decodeFormatInformation(
|
||||
MASKED_TEST_FORMAT_INFO ^ 0x01,
|
||||
MASKED_TEST_FORMAT_INFO ^ 0x01
|
||||
)
|
||||
.expect("return")
|
||||
);
|
||||
assert_eq!(
|
||||
expected,
|
||||
FormatInformation::decodeFormatInformation(
|
||||
MASKED_TEST_FORMAT_INFO ^ 0x03,
|
||||
MASKED_TEST_FORMAT_INFO ^ 0x03
|
||||
)
|
||||
.expect("return")
|
||||
);
|
||||
assert_eq!(
|
||||
expected,
|
||||
FormatInformation::decodeFormatInformation(
|
||||
MASKED_TEST_FORMAT_INFO ^ 0x07,
|
||||
MASKED_TEST_FORMAT_INFO ^ 0x07
|
||||
)
|
||||
.expect("return")
|
||||
);
|
||||
assert!(FormatInformation::decodeFormatInformation(
|
||||
MASKED_TEST_FORMAT_INFO ^ 0x0F, MASKED_TEST_FORMAT_INFO ^ 0x0F).is_none());
|
||||
}
|
||||
MASKED_TEST_FORMAT_INFO ^ 0x0F,
|
||||
MASKED_TEST_FORMAT_INFO ^ 0x0F
|
||||
)
|
||||
.is_none());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn testDecodeWithMisread() {
|
||||
let expected =
|
||||
FormatInformation::decodeFormatInformation(MASKED_TEST_FORMAT_INFO, MASKED_TEST_FORMAT_INFO).unwrap();
|
||||
assert_eq!(expected, FormatInformation::decodeFormatInformation(
|
||||
MASKED_TEST_FORMAT_INFO ^ 0x03, MASKED_TEST_FORMAT_INFO ^ 0x0F).unwrap());
|
||||
}
|
||||
#[test]
|
||||
fn testDecodeWithMisread() {
|
||||
let expected = FormatInformation::decodeFormatInformation(
|
||||
MASKED_TEST_FORMAT_INFO,
|
||||
MASKED_TEST_FORMAT_INFO,
|
||||
)
|
||||
.unwrap();
|
||||
assert_eq!(
|
||||
expected,
|
||||
FormatInformation::decodeFormatInformation(
|
||||
MASKED_TEST_FORMAT_INFO ^ 0x03,
|
||||
MASKED_TEST_FORMAT_INFO ^ 0x0F
|
||||
)
|
||||
.unwrap()
|
||||
);
|
||||
}
|
||||
|
||||
@@ -18,34 +18,50 @@ use crate::qrcode::decoder::Version;
|
||||
|
||||
use super::Mode;
|
||||
|
||||
|
||||
/**
|
||||
* @author Sean Owen
|
||||
*/
|
||||
|
||||
#[test]
|
||||
fn testForBits() {
|
||||
#[test]
|
||||
fn testForBits() {
|
||||
assert_eq!(Mode::TERMINATOR, Mode::forBits(0x00).unwrap());
|
||||
assert_eq!(Mode::NUMERIC, Mode::forBits(0x01).unwrap());
|
||||
assert_eq!(Mode::ALPHANUMERIC, Mode::forBits(0x02).unwrap());
|
||||
assert_eq!(Mode::BYTE, Mode::forBits(0x04).unwrap());
|
||||
assert_eq!(Mode::KANJI, Mode::forBits(0x08).unwrap());
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[should_panic]
|
||||
fn testBadMode() {
|
||||
#[test]
|
||||
#[should_panic]
|
||||
fn testBadMode() {
|
||||
assert!(Mode::forBits(0x10).is_ok());
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn testCharacterCount() {
|
||||
#[test]
|
||||
fn testCharacterCount() {
|
||||
// Spot check a few values
|
||||
assert_eq!(10, Mode::NUMERIC.getCharacterCountBits(Version::getVersionForNumber(5).unwrap()));
|
||||
assert_eq!(12, Mode::NUMERIC.getCharacterCountBits(Version::getVersionForNumber(26).unwrap()));
|
||||
assert_eq!(14, Mode::NUMERIC.getCharacterCountBits(Version::getVersionForNumber(40).unwrap()));
|
||||
assert_eq!(9, Mode::ALPHANUMERIC.getCharacterCountBits(Version::getVersionForNumber(6).unwrap()));
|
||||
assert_eq!(8, Mode::BYTE.getCharacterCountBits(Version::getVersionForNumber(7).unwrap()));
|
||||
assert_eq!(8, Mode::KANJI.getCharacterCountBits(Version::getVersionForNumber(8).unwrap()));
|
||||
}
|
||||
|
||||
assert_eq!(
|
||||
10,
|
||||
Mode::NUMERIC.getCharacterCountBits(Version::getVersionForNumber(5).unwrap())
|
||||
);
|
||||
assert_eq!(
|
||||
12,
|
||||
Mode::NUMERIC.getCharacterCountBits(Version::getVersionForNumber(26).unwrap())
|
||||
);
|
||||
assert_eq!(
|
||||
14,
|
||||
Mode::NUMERIC.getCharacterCountBits(Version::getVersionForNumber(40).unwrap())
|
||||
);
|
||||
assert_eq!(
|
||||
9,
|
||||
Mode::ALPHANUMERIC.getCharacterCountBits(Version::getVersionForNumber(6).unwrap())
|
||||
);
|
||||
assert_eq!(
|
||||
8,
|
||||
Mode::BYTE.getCharacterCountBits(Version::getVersionForNumber(7).unwrap())
|
||||
);
|
||||
assert_eq!(
|
||||
8,
|
||||
Mode::KANJI.getCharacterCountBits(Version::getVersionForNumber(8).unwrap())
|
||||
);
|
||||
}
|
||||
|
||||
@@ -14,35 +14,36 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
use crate::{qrcode::decoder::{Version, ErrorCorrectionLevel}, Exceptions};
|
||||
|
||||
use crate::{
|
||||
qrcode::decoder::{ErrorCorrectionLevel, Version},
|
||||
Exceptions,
|
||||
};
|
||||
|
||||
/**
|
||||
* @author Sean Owen
|
||||
*/
|
||||
|
||||
|
||||
#[test]
|
||||
#[should_panic]
|
||||
fn testBadVersion() {
|
||||
#[test]
|
||||
#[should_panic]
|
||||
fn testBadVersion() {
|
||||
assert!(Version::getVersionForNumber(0).is_ok());
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn testVersionForNumber() {
|
||||
#[test]
|
||||
fn testVersionForNumber() {
|
||||
for i in 1..=40 {
|
||||
// for (int i = 1; i <= 40; i++) {
|
||||
checkVersion(Version::getVersionForNumber(i), i, 4 * i + 17);
|
||||
// for (int i = 1; i <= 40; i++) {
|
||||
checkVersion(Version::getVersionForNumber(i), i, 4 * i + 17);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn checkVersion( version:Result<&Version,Exceptions>, number:u32, dimension:u32) {
|
||||
fn checkVersion(version: Result<&Version, Exceptions>, number: u32, dimension: u32) {
|
||||
assert!(version.is_ok());
|
||||
let version = version.unwrap();
|
||||
assert_eq!(number, version.getVersionNumber());
|
||||
// assertNotNull(version.getAlignmentPatternCenters());
|
||||
if number > 1 {
|
||||
assert!(version.getAlignmentPatternCenters().len() > 0);
|
||||
assert!(version.getAlignmentPatternCenters().len() > 0);
|
||||
}
|
||||
assert_eq!(dimension, version.getDimensionForVersion());
|
||||
let _tmp = version.getECBlocksForLevel(ErrorCorrectionLevel::H);
|
||||
@@ -56,18 +57,23 @@ use crate::{qrcode::decoder::{Version, ErrorCorrectionLevel}, Exceptions};
|
||||
// assertNotNull(version.getECBlocksForLevel(ErrorCorrectionLevel::M));
|
||||
// assertNotNull(version.getECBlocksForLevel(ErrorCorrectionLevel::Q));
|
||||
// assertNotNull(version.buildFunctionPattern());
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn testGetProvisionalVersionForDimension() {
|
||||
#[test]
|
||||
fn testGetProvisionalVersionForDimension() {
|
||||
for i in 1..=40 {
|
||||
// for (int i = 1; i <= 40; i++) {
|
||||
assert_eq!(i, Version::getProvisionalVersionForDimension(4 * i + 17).expect("must exist for supplied values").getVersionNumber());
|
||||
// for (int i = 1; i <= 40; i++) {
|
||||
assert_eq!(
|
||||
i,
|
||||
Version::getProvisionalVersionForDimension(4 * i + 17)
|
||||
.expect("must exist for supplied values")
|
||||
.getVersionNumber()
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn testDecodeVersionInformation() {
|
||||
#[test]
|
||||
fn testDecodeVersionInformation() {
|
||||
// Spot check
|
||||
doTestVersion(7, 0x07C94);
|
||||
doTestVersion(12, 0x0C762);
|
||||
@@ -75,11 +81,10 @@ use crate::{qrcode::decoder::{Version, ErrorCorrectionLevel}, Exceptions};
|
||||
doTestVersion(22, 0x168C9);
|
||||
doTestVersion(27, 0x1B08E);
|
||||
doTestVersion(32, 0x209D5);
|
||||
}
|
||||
|
||||
fn doTestVersion( expectedVersion:u32, mask:u32) {
|
||||
}
|
||||
|
||||
fn doTestVersion(expectedVersion: u32, mask: u32) {
|
||||
let version = Version::decodeVersionInformation(mask);
|
||||
assert!(version.is_ok());
|
||||
assert_eq!(expectedVersion, version.unwrap().getVersionNumber());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -82,7 +82,7 @@ impl BitMatrixParser {
|
||||
let dimension = self.bitMatrix.getHeight();
|
||||
let mut formatInfoBits2 = 0;
|
||||
let jMin = dimension - 7;
|
||||
for j in (jMin..=dimension-1).rev() {
|
||||
for j in (jMin..=dimension - 1).rev() {
|
||||
// for (int j = dimension - 1; j >= jMin; j--) {
|
||||
formatInfoBits2 = self.copyBit(8, j, formatInfoBits2);
|
||||
}
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
|
||||
use crate::Exceptions;
|
||||
|
||||
use super::{VersionRef, ErrorCorrectionLevel};
|
||||
use super::{ErrorCorrectionLevel, VersionRef};
|
||||
|
||||
/**
|
||||
* <p>Encapsulates a block of data within a QR Code. QR Codes may split their data into
|
||||
@@ -26,118 +26,120 @@ use super::{VersionRef, ErrorCorrectionLevel};
|
||||
* @author Sean Owen
|
||||
*/
|
||||
pub struct DataBlock {
|
||||
|
||||
numDataCodewords:u32,
|
||||
codewords:Vec<u8>,
|
||||
numDataCodewords: u32,
|
||||
codewords: Vec<u8>,
|
||||
}
|
||||
|
||||
impl DataBlock {
|
||||
|
||||
fn new( numDataCodewords:u32, codewords:Vec<u8>) -> Self{
|
||||
Self{
|
||||
numDataCodewords,
|
||||
codewords,
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>When QR Codes use multiple data blocks, they are actually interleaved.
|
||||
* That is, the first byte of data block 1 to n is written, then the second bytes, and so on. This
|
||||
* method will separate the data into original blocks.</p>
|
||||
*
|
||||
* @param rawCodewords bytes as read directly from the QR Code
|
||||
* @param version version of the QR Code
|
||||
* @param ecLevel error-correction level of the QR Code
|
||||
* @return DataBlocks containing original bytes, "de-interleaved" from representation in the
|
||||
* QR Code
|
||||
*/
|
||||
pub fn getDataBlocks( rawCodewords:&[u8],
|
||||
version:VersionRef,
|
||||
ecLevel:ErrorCorrectionLevel) -> Result<Vec<Self>,Exceptions> {
|
||||
|
||||
if rawCodewords.len() as u32 != version.getTotalCodewords() {
|
||||
return Err(Exceptions::IllegalArgumentException("".to_owned()))
|
||||
fn new(numDataCodewords: u32, codewords: Vec<u8>) -> Self {
|
||||
Self {
|
||||
numDataCodewords,
|
||||
codewords,
|
||||
}
|
||||
}
|
||||
|
||||
// Figure out the number and size of data blocks used by this version and
|
||||
// error correction level
|
||||
let ecBlocks = version.getECBlocksForLevel(ecLevel);
|
||||
/**
|
||||
* <p>When QR Codes use multiple data blocks, they are actually interleaved.
|
||||
* That is, the first byte of data block 1 to n is written, then the second bytes, and so on. This
|
||||
* method will separate the data into original blocks.</p>
|
||||
*
|
||||
* @param rawCodewords bytes as read directly from the QR Code
|
||||
* @param version version of the QR Code
|
||||
* @param ecLevel error-correction level of the QR Code
|
||||
* @return DataBlocks containing original bytes, "de-interleaved" from representation in the
|
||||
* QR Code
|
||||
*/
|
||||
pub fn getDataBlocks(
|
||||
rawCodewords: &[u8],
|
||||
version: VersionRef,
|
||||
ecLevel: ErrorCorrectionLevel,
|
||||
) -> Result<Vec<Self>, Exceptions> {
|
||||
if rawCodewords.len() as u32 != version.getTotalCodewords() {
|
||||
return Err(Exceptions::IllegalArgumentException("".to_owned()));
|
||||
}
|
||||
|
||||
// First count the total number of data blocks
|
||||
let mut _totalBlocks = 0;
|
||||
let ecBlockArray = ecBlocks.getECBlocks();
|
||||
for ecBlock in ecBlockArray {
|
||||
// for (Version.ECB ecBlock : ecBlockArray) {
|
||||
_totalBlocks += ecBlock.getCount();
|
||||
// Figure out the number and size of data blocks used by this version and
|
||||
// error correction level
|
||||
let ecBlocks = version.getECBlocksForLevel(ecLevel);
|
||||
|
||||
// First count the total number of data blocks
|
||||
let mut _totalBlocks = 0;
|
||||
let ecBlockArray = ecBlocks.getECBlocks();
|
||||
for ecBlock in ecBlockArray {
|
||||
// for (Version.ECB ecBlock : ecBlockArray) {
|
||||
_totalBlocks += ecBlock.getCount();
|
||||
}
|
||||
|
||||
// Now establish DataBlocks of the appropriate size and number of data codewords
|
||||
let mut result = Vec::new();
|
||||
let mut numRXingResultBlocks = 0;
|
||||
for ecBlock in ecBlockArray {
|
||||
// for (Version.ECB ecBlock : ecBlockArray) {
|
||||
for _i in 0..ecBlock.getCount() {
|
||||
// for (int i = 0; i < ecBlock.getCount(); i++) {
|
||||
let numDataCodewords = ecBlock.getDataCodewords();
|
||||
let numBlockCodewords = ecBlocks.getECCodewordsPerBlock() + numDataCodewords;
|
||||
// result[numRXingResultBlocks] = DataBlock::new(numDataCodewords, vec![0u8;numBlockCodewords as usize]);
|
||||
result.push(DataBlock::new(
|
||||
numDataCodewords,
|
||||
vec![0u8; numBlockCodewords as usize],
|
||||
));
|
||||
numRXingResultBlocks += 1;
|
||||
}
|
||||
}
|
||||
|
||||
// All blocks have the same amount of data, except that the last n
|
||||
// (where n may be 0) have 1 more byte. Figure out where these start.
|
||||
let shorterBlocksTotalCodewords = result[0].codewords.len();
|
||||
let mut longerBlocksStartAt = result.len() - 1;
|
||||
loop {
|
||||
//while longerBlocksStartAt >= 0 {
|
||||
let numCodewords = result[longerBlocksStartAt].codewords.len();
|
||||
if numCodewords == shorterBlocksTotalCodewords {
|
||||
break;
|
||||
}
|
||||
longerBlocksStartAt -= 1;
|
||||
}
|
||||
longerBlocksStartAt += 1;
|
||||
|
||||
let shorterBlocksNumDataCodewords =
|
||||
shorterBlocksTotalCodewords - ecBlocks.getECCodewordsPerBlock() as usize;
|
||||
// The last elements of result may be 1 element longer;
|
||||
// first fill out as many elements as all of them have
|
||||
let mut rawCodewordsOffset = 0;
|
||||
for i in 0..shorterBlocksNumDataCodewords {
|
||||
// for (int i = 0; i < shorterBlocksNumDataCodewords; i++) {
|
||||
for j in 0..numRXingResultBlocks {
|
||||
// for (int j = 0; j < numRXingResultBlocks; j++) {
|
||||
result[j].codewords[i] = rawCodewords[rawCodewordsOffset];
|
||||
rawCodewordsOffset += 1;
|
||||
}
|
||||
}
|
||||
// Fill out the last data block in the longer ones
|
||||
for j in longerBlocksStartAt..numRXingResultBlocks {
|
||||
// for (int j = longerBlocksStartAt; j < numRXingResultBlocks; j++) {
|
||||
result[j].codewords[shorterBlocksNumDataCodewords] = rawCodewords[rawCodewordsOffset];
|
||||
rawCodewordsOffset += 1;
|
||||
}
|
||||
// Now add in error correction blocks
|
||||
let max = result[0].codewords.len();
|
||||
for i in shorterBlocksNumDataCodewords..max {
|
||||
// for (int i = shorterBlocksNumDataCodewords; i < max; i++) {
|
||||
for j in 0..numRXingResultBlocks {
|
||||
// for (int j = 0; j < numRXingResultBlocks; j++) {
|
||||
let iOffset = if j < longerBlocksStartAt { i } else { i + 1 };
|
||||
result[j].codewords[iOffset] = rawCodewords[rawCodewordsOffset];
|
||||
rawCodewordsOffset += 1;
|
||||
}
|
||||
}
|
||||
Ok(result)
|
||||
}
|
||||
|
||||
// Now establish DataBlocks of the appropriate size and number of data codewords
|
||||
let mut result = Vec::new();
|
||||
let mut numRXingResultBlocks = 0;
|
||||
for ecBlock in ecBlockArray {
|
||||
// for (Version.ECB ecBlock : ecBlockArray) {
|
||||
for _i in 0..ecBlock.getCount() {
|
||||
// for (int i = 0; i < ecBlock.getCount(); i++) {
|
||||
let numDataCodewords = ecBlock.getDataCodewords();
|
||||
let numBlockCodewords = ecBlocks.getECCodewordsPerBlock() + numDataCodewords;
|
||||
// result[numRXingResultBlocks] = DataBlock::new(numDataCodewords, vec![0u8;numBlockCodewords as usize]);
|
||||
result.push( DataBlock::new(numDataCodewords, vec![0u8;numBlockCodewords as usize]));
|
||||
numRXingResultBlocks += 1;
|
||||
}
|
||||
pub fn getNumDataCodewords(&self) -> u32 {
|
||||
self.numDataCodewords
|
||||
}
|
||||
|
||||
// All blocks have the same amount of data, except that the last n
|
||||
// (where n may be 0) have 1 more byte. Figure out where these start.
|
||||
let shorterBlocksTotalCodewords = result[0].codewords.len();
|
||||
let mut longerBlocksStartAt = result.len() - 1;
|
||||
loop {
|
||||
//while longerBlocksStartAt >= 0 {
|
||||
let numCodewords = result[longerBlocksStartAt].codewords.len();
|
||||
if numCodewords == shorterBlocksTotalCodewords {
|
||||
break;
|
||||
}
|
||||
longerBlocksStartAt-=1;
|
||||
pub fn getCodewords(&self) -> &[u8] {
|
||||
&self.codewords
|
||||
}
|
||||
longerBlocksStartAt+=1;
|
||||
|
||||
let shorterBlocksNumDataCodewords = shorterBlocksTotalCodewords - ecBlocks.getECCodewordsPerBlock() as usize;
|
||||
// The last elements of result may be 1 element longer;
|
||||
// first fill out as many elements as all of them have
|
||||
let mut rawCodewordsOffset = 0;
|
||||
for i in 0..shorterBlocksNumDataCodewords {
|
||||
// for (int i = 0; i < shorterBlocksNumDataCodewords; i++) {
|
||||
for j in 0..numRXingResultBlocks {
|
||||
// for (int j = 0; j < numRXingResultBlocks; j++) {
|
||||
result[j].codewords[i] = rawCodewords[rawCodewordsOffset];
|
||||
rawCodewordsOffset += 1;
|
||||
}
|
||||
}
|
||||
// Fill out the last data block in the longer ones
|
||||
for j in longerBlocksStartAt..numRXingResultBlocks{
|
||||
// for (int j = longerBlocksStartAt; j < numRXingResultBlocks; j++) {
|
||||
result[j].codewords[shorterBlocksNumDataCodewords] = rawCodewords[rawCodewordsOffset];
|
||||
rawCodewordsOffset += 1;
|
||||
}
|
||||
// Now add in error correction blocks
|
||||
let max = result[0].codewords.len();
|
||||
for i in shorterBlocksNumDataCodewords..max {
|
||||
// for (int i = shorterBlocksNumDataCodewords; i < max; i++) {
|
||||
for j in 0..numRXingResultBlocks {
|
||||
// for (int j = 0; j < numRXingResultBlocks; j++) {
|
||||
let iOffset = if j < longerBlocksStartAt {i} else {i + 1};
|
||||
result[j].codewords[iOffset] = rawCodewords[rawCodewordsOffset];
|
||||
rawCodewordsOffset += 1;
|
||||
}
|
||||
}
|
||||
Ok(result)
|
||||
}
|
||||
|
||||
pub fn getNumDataCodewords(&self) -> u32{
|
||||
self. numDataCodewords
|
||||
}
|
||||
|
||||
pub fn getCodewords(&self) -> &[u8] {
|
||||
&self.codewords
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -27,7 +27,7 @@ use crate::{common::BitMatrix, Exceptions};
|
||||
*
|
||||
* @author Sean Owen
|
||||
*/
|
||||
#[derive(Copy,Clone,Eq, PartialEq)]
|
||||
#[derive(Copy, Clone, Eq, PartialEq)]
|
||||
pub enum DataMask {
|
||||
// See ISO 18004:2006 6.8.1
|
||||
/**
|
||||
@@ -222,15 +222,18 @@ impl TryFrom<u8> for DataMask {
|
||||
|
||||
fn try_from(value: u8) -> Result<Self, Self::Error> {
|
||||
match value {
|
||||
0=>Ok(DataMask::DATA_MASK_000),
|
||||
1=>Ok(DataMask::DATA_MASK_001),
|
||||
2=>Ok(DataMask::DATA_MASK_010),
|
||||
3=>Ok(DataMask::DATA_MASK_011),
|
||||
4=>Ok(DataMask::DATA_MASK_100),
|
||||
5=>Ok(DataMask::DATA_MASK_101),
|
||||
6=>Ok(DataMask::DATA_MASK_110),
|
||||
7=>Ok(DataMask::DATA_MASK_111),
|
||||
_=>Err(Exceptions::IllegalArgumentException(format!("{} is not between 0 and 7",value))),
|
||||
0 => Ok(DataMask::DATA_MASK_000),
|
||||
1 => Ok(DataMask::DATA_MASK_001),
|
||||
2 => Ok(DataMask::DATA_MASK_010),
|
||||
3 => Ok(DataMask::DATA_MASK_011),
|
||||
4 => Ok(DataMask::DATA_MASK_100),
|
||||
5 => Ok(DataMask::DATA_MASK_101),
|
||||
6 => Ok(DataMask::DATA_MASK_110),
|
||||
7 => Ok(DataMask::DATA_MASK_111),
|
||||
_ => Err(Exceptions::IllegalArgumentException(format!(
|
||||
"{} is not between 0 and 7",
|
||||
value
|
||||
))),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -286,17 +286,19 @@ fn decodeByteSegment(
|
||||
encoding = CharacterSetECI::getCharset(currentCharacterSetECI.as_ref().unwrap());
|
||||
}
|
||||
|
||||
let encode_string = if currentCharacterSetECI.is_some() && currentCharacterSetECI.as_ref().unwrap() == &CharacterSetECI::Cp437 {
|
||||
{
|
||||
use codepage_437::BorrowFromCp437;
|
||||
use codepage_437::CP437_CONTROL;
|
||||
let encode_string = if currentCharacterSetECI.is_some()
|
||||
&& currentCharacterSetECI.as_ref().unwrap() == &CharacterSetECI::Cp437
|
||||
{
|
||||
{
|
||||
use codepage_437::BorrowFromCp437;
|
||||
use codepage_437::CP437_CONTROL;
|
||||
|
||||
String::borrow_from_cp437(&readBytes, &CP437_CONTROL)
|
||||
}
|
||||
}else {
|
||||
encoding
|
||||
.decode(&readBytes, encoding::DecoderTrap::Strict)
|
||||
.unwrap()
|
||||
String::borrow_from_cp437(&readBytes, &CP437_CONTROL)
|
||||
}
|
||||
} else {
|
||||
encoding
|
||||
.decode(&readBytes, encoding::DecoderTrap::Strict)
|
||||
.unwrap()
|
||||
};
|
||||
|
||||
// let encode_string = encoding
|
||||
|
||||
@@ -198,7 +198,7 @@ fn correctErrors(codewordBytes: &mut [u8], numDataCodewords: usize) -> Result<()
|
||||
codewordsInts[i] = codewordBytes[i]; // & 0xFF;
|
||||
}
|
||||
|
||||
let mut sending_code_words : Vec<i32> = codewordsInts.iter().map(|x| *x as i32).collect();
|
||||
let mut sending_code_words: Vec<i32> = codewordsInts.iter().map(|x| *x as i32).collect();
|
||||
|
||||
if let Err(e) = RS_DECODER.decode(
|
||||
&mut sending_code_words,
|
||||
|
||||
@@ -88,15 +88,15 @@ impl From<ErrorCorrectionLevel> for u8 {
|
||||
}
|
||||
|
||||
impl FromStr for ErrorCorrectionLevel {
|
||||
type Err=Exceptions;
|
||||
type Err = Exceptions;
|
||||
|
||||
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||
// First try to see if the string is just the name of the value
|
||||
let as_str = match s.to_uppercase().as_str() {
|
||||
"L" => Some(ErrorCorrectionLevel::L),
|
||||
"M" => Some(ErrorCorrectionLevel::M),
|
||||
"Q" =>Some(ErrorCorrectionLevel::Q),
|
||||
"H" =>Some(ErrorCorrectionLevel::H),
|
||||
"Q" => Some(ErrorCorrectionLevel::Q),
|
||||
"H" => Some(ErrorCorrectionLevel::H),
|
||||
_ => None,
|
||||
};
|
||||
|
||||
@@ -110,7 +110,10 @@ impl FromStr for ErrorCorrectionLevel {
|
||||
return number_possible.unwrap().try_into();
|
||||
}
|
||||
|
||||
return Err(Exceptions::IllegalArgumentException(format!("could not parse {} into an ec level", s)))
|
||||
return Err(Exceptions::IllegalArgumentException(format!(
|
||||
"could not parse {} into an ec level",
|
||||
s
|
||||
)));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -101,12 +101,12 @@ impl FormatInformation {
|
||||
) -> Option<FormatInformation> {
|
||||
let formatInfo = Self::doDecodeFormatInformation(masked_format_info1, masked_format_info2);
|
||||
if formatInfo.is_some() {
|
||||
return formatInfo
|
||||
return formatInfo;
|
||||
}
|
||||
// Should return null, but, some QR codes apparently
|
||||
// do not mask this info. Try again by actually masking the pattern
|
||||
// first
|
||||
Self::doDecodeFormatInformation(
|
||||
Self::doDecodeFormatInformation(
|
||||
masked_format_info1 ^ FORMAT_INFO_MASK_QR,
|
||||
masked_format_info2 ^ FORMAT_INFO_MASK_QR,
|
||||
)
|
||||
|
||||
@@ -1,32 +1,32 @@
|
||||
mod version;
|
||||
mod mode;
|
||||
mod error_correction_level;
|
||||
mod format_information;
|
||||
mod data_block;
|
||||
mod qr_code_decoder_meta_data;
|
||||
mod data_mask;
|
||||
mod bit_matrix_parser;
|
||||
mod data_block;
|
||||
mod data_mask;
|
||||
pub mod decoded_bit_stream_parser;
|
||||
pub mod decoder;
|
||||
mod error_correction_level;
|
||||
mod format_information;
|
||||
mod mode;
|
||||
mod qr_code_decoder_meta_data;
|
||||
mod version;
|
||||
|
||||
#[cfg(test)]
|
||||
mod ErrorCorrectionLevelTestCase;
|
||||
#[cfg(test)]
|
||||
mod ModeTestCase;
|
||||
#[cfg(test)]
|
||||
mod VersionTestCase;
|
||||
#[cfg(test)]
|
||||
mod FormatInformationTestCase;
|
||||
#[cfg(test)]
|
||||
mod DataMaskTestCase;
|
||||
#[cfg(test)]
|
||||
mod DecodedBitStreamParserTestCase;
|
||||
#[cfg(test)]
|
||||
mod ErrorCorrectionLevelTestCase;
|
||||
#[cfg(test)]
|
||||
mod FormatInformationTestCase;
|
||||
#[cfg(test)]
|
||||
mod ModeTestCase;
|
||||
#[cfg(test)]
|
||||
mod VersionTestCase;
|
||||
|
||||
pub use version::*;
|
||||
pub use mode::*;
|
||||
pub use bit_matrix_parser::*;
|
||||
pub use data_block::*;
|
||||
pub use data_mask::*;
|
||||
pub use error_correction_level::*;
|
||||
pub use format_information::*;
|
||||
pub use data_block::*;
|
||||
pub use mode::*;
|
||||
pub use qr_code_decoder_meta_data::*;
|
||||
pub use data_mask::*;
|
||||
pub use bit_matrix_parser::*;
|
||||
pub use version::*;
|
||||
|
||||
@@ -24,31 +24,30 @@ use crate::RXingResultPoint;
|
||||
*/
|
||||
pub struct QRCodeDecoderMetaData(bool);
|
||||
|
||||
impl QRCodeDecoderMetaData {
|
||||
pub fn new( mirrored:bool) -> Self {
|
||||
Self(mirrored)
|
||||
}
|
||||
|
||||
/**
|
||||
* @return true if the QR Code was mirrored.
|
||||
*/
|
||||
pub fn isMirrored(&self) -> bool{
|
||||
self.0
|
||||
}
|
||||
|
||||
/**
|
||||
* Apply the result points' order correction due to mirroring.
|
||||
*
|
||||
* @param points Array of points to apply mirror correction to.
|
||||
*/
|
||||
pub fn applyMirroredCorrection(&self, points : &mut [RXingResultPoint]) {
|
||||
if !self.0 || points.is_empty() || points.len() < 3 {
|
||||
return
|
||||
impl QRCodeDecoderMetaData {
|
||||
pub fn new(mirrored: bool) -> Self {
|
||||
Self(mirrored)
|
||||
}
|
||||
let bottom_left = points[0];
|
||||
points[0] = points[2];
|
||||
points[2] = bottom_left;
|
||||
// No need to 'fix' top-left and alignment pattern.
|
||||
}
|
||||
|
||||
/**
|
||||
* @return true if the QR Code was mirrored.
|
||||
*/
|
||||
pub fn isMirrored(&self) -> bool {
|
||||
self.0
|
||||
}
|
||||
|
||||
/**
|
||||
* Apply the result points' order correction due to mirroring.
|
||||
*
|
||||
* @param points Array of points to apply mirror correction to.
|
||||
*/
|
||||
pub fn applyMirroredCorrection(&self, points: &mut [RXingResultPoint]) {
|
||||
if !self.0 || points.is_empty() || points.len() < 3 {
|
||||
return;
|
||||
}
|
||||
let bottom_left = points[0];
|
||||
points[0] = points[2];
|
||||
points[2] = bottom_left;
|
||||
// No need to 'fix' top-left and alignment pattern.
|
||||
}
|
||||
}
|
||||
|
||||
@@ -156,7 +156,7 @@ impl Version {
|
||||
/**
|
||||
* See ISO 18004:2006 Annex E
|
||||
*/
|
||||
pub fn buildFunctionPattern(&self) -> Result<BitMatrix,Exceptions> {
|
||||
pub fn buildFunctionPattern(&self) -> Result<BitMatrix, Exceptions> {
|
||||
let dimension = self.getDimensionForVersion();
|
||||
let mut bitMatrix = BitMatrix::with_single_dimension(dimension);
|
||||
|
||||
@@ -932,7 +932,7 @@ impl fmt::Display for Version {
|
||||
* will be the same across all blocks within one version.</p>
|
||||
*/
|
||||
#[derive(Debug)]
|
||||
pub struct ECBlocks {
|
||||
pub struct ECBlocks {
|
||||
ecCodewordsPerBlock: u32,
|
||||
ecBlocks: Vec<ECB>,
|
||||
}
|
||||
|
||||
@@ -24,7 +24,7 @@ use crate::{RXingResultPoint, ResultPoint};
|
||||
*
|
||||
* @author Sean Owen
|
||||
*/
|
||||
#[derive(Debug,Clone, Copy,PartialEq)]
|
||||
#[derive(Debug, Clone, Copy, PartialEq)]
|
||||
pub struct AlignmentPattern {
|
||||
estimatedModuleSize: f32,
|
||||
point: (f32, f32),
|
||||
@@ -40,7 +40,10 @@ impl ResultPoint for AlignmentPattern {
|
||||
}
|
||||
|
||||
fn into_rxing_result_point(self) -> RXingResultPoint {
|
||||
RXingResultPoint { x: self.point.0, y: self.point.1 }
|
||||
RXingResultPoint {
|
||||
x: self.point.0,
|
||||
y: self.point.1,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -97,7 +97,7 @@ impl AlignmentPatternFinder {
|
||||
// Search from middle outwards
|
||||
let i = (middleI as i32
|
||||
+ (if (iGen & 0x01) == 0 {
|
||||
(iGen as i32 + 1) / 2
|
||||
(iGen as i32 + 1) / 2
|
||||
} else {
|
||||
-((iGen as i32 + 1) / 2)
|
||||
})) as u32;
|
||||
@@ -172,7 +172,7 @@ impl AlignmentPatternFinder {
|
||||
* figures the location of the center of this black/white/black run.
|
||||
*/
|
||||
fn centerFromEnd(stateCount: &[u32], end: u32) -> f32 {
|
||||
(end as f32 - stateCount[2] as f32) - stateCount[1] as f32 / 2.0
|
||||
(end as f32 - stateCount[2] as f32) - stateCount[1] as f32 / 2.0
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -237,15 +237,21 @@ impl AlignmentPatternFinder {
|
||||
}
|
||||
|
||||
// Now also count down from center
|
||||
i = startI as i32+ 1;
|
||||
while i < maxI as i32 && image.get(centerJ, i as u32) && self.crossCheckStateCount[1] <= maxCount {
|
||||
i = startI as i32 + 1;
|
||||
while i < maxI as i32
|
||||
&& image.get(centerJ, i as u32)
|
||||
&& self.crossCheckStateCount[1] <= maxCount
|
||||
{
|
||||
self.crossCheckStateCount[1] += 1;
|
||||
i += 1;
|
||||
}
|
||||
if i == maxI as i32 || self.crossCheckStateCount[1] > maxCount {
|
||||
return f32::NAN;
|
||||
}
|
||||
while i < maxI as i32 && !image.get(centerJ, i as u32) && self.crossCheckStateCount[2] <= maxCount {
|
||||
while i < maxI as i32
|
||||
&& !image.get(centerJ, i as u32)
|
||||
&& self.crossCheckStateCount[2] <= maxCount
|
||||
{
|
||||
self.crossCheckStateCount[2] += 1;
|
||||
i += 1;
|
||||
}
|
||||
@@ -288,7 +294,7 @@ impl AlignmentPatternFinder {
|
||||
) -> Option<AlignmentPattern> {
|
||||
let stateCountTotal = stateCount[0] + stateCount[1] + stateCount[2];
|
||||
let centerJ = Self::centerFromEnd(stateCount, j);
|
||||
let centerI = self.crossCheckVertical(
|
||||
let centerI = self.crossCheckVertical(
|
||||
i,
|
||||
centerJ.floor() as u32,
|
||||
2 * stateCount[1],
|
||||
|
||||
@@ -18,8 +18,7 @@ use std::collections::HashMap;
|
||||
|
||||
use crate::{
|
||||
common::{
|
||||
detector::MathUtils, BitMatrix, DefaultGridSampler, GridSampler,
|
||||
PerspectiveTransform,
|
||||
detector::MathUtils, BitMatrix, DefaultGridSampler, GridSampler, PerspectiveTransform,
|
||||
},
|
||||
qrcode::decoder::Version,
|
||||
result_point_utils, DecodeHintType, DecodeHintValue, DecodingHintDictionary, Exceptions,
|
||||
@@ -338,10 +337,11 @@ impl Detector {
|
||||
let mut scale = 1.0;
|
||||
let mut otherToX = fromX as i32 - (toX as i32 - fromX as i32);
|
||||
if otherToX < 0 {
|
||||
scale = fromX as f32 / (fromX as i32- otherToX) as f32;
|
||||
scale = fromX as f32 / (fromX as i32 - otherToX) as f32;
|
||||
otherToX = 0;
|
||||
} else if otherToX as u32 >= self.image.getWidth() {
|
||||
scale = (self.image.getWidth() as i32 - 1 - fromX as i32) as f32 / (otherToX - fromX as i32) as f32;
|
||||
scale = (self.image.getWidth() as i32 - 1 - fromX as i32) as f32
|
||||
/ (otherToX - fromX as i32) as f32;
|
||||
otherToX = self.image.getWidth() as i32 - 1;
|
||||
}
|
||||
let mut otherToY = (fromY as f32 - (toY as f32 - fromY as f32) * scale).floor() as i32;
|
||||
@@ -351,12 +351,18 @@ impl Detector {
|
||||
scale = fromY as f32 / (fromY as i32 - otherToY) as f32;
|
||||
otherToY = 0;
|
||||
} else if otherToY as u32 >= self.image.getHeight() {
|
||||
scale = (self.image.getHeight() as i32 - 1 - fromY as i32) as f32 / (otherToY - fromY as i32) as f32;
|
||||
scale = (self.image.getHeight() as i32 - 1 - fromY as i32) as f32
|
||||
/ (otherToY - fromY as i32) as f32;
|
||||
otherToY = self.image.getHeight() as i32 - 1;
|
||||
}
|
||||
otherToX = (fromX as f32+ (otherToX as f32 - fromX as f32) * scale).floor() as i32;
|
||||
otherToX = (fromX as f32 + (otherToX as f32 - fromX as f32) * scale).floor() as i32;
|
||||
|
||||
result += self.sizeOfBlackWhiteBlackRun(fromX as u32, fromY as u32, otherToX as u32, otherToY as u32);
|
||||
result += self.sizeOfBlackWhiteBlackRun(
|
||||
fromX as u32,
|
||||
fromY as u32,
|
||||
otherToX as u32,
|
||||
otherToY as u32,
|
||||
);
|
||||
|
||||
// Middle pixel is double-counted this way; subtract 1
|
||||
return result - 1.0;
|
||||
@@ -462,7 +468,7 @@ impl Detector {
|
||||
// Look for an alignment pattern (3 modules in size) around where it
|
||||
// should be
|
||||
let allowance = (allowanceFactor * overallEstModuleSize) as u32;
|
||||
let alignmentAreaLeftX = 0.max(estAlignmentX as i32- allowance as i32) as u32;
|
||||
let alignmentAreaLeftX = 0.max(estAlignmentX as i32 - allowance as i32) as u32;
|
||||
let alignmentAreaRightX = (self.image.getWidth() - 1).min(estAlignmentX + allowance);
|
||||
if ((alignmentAreaRightX - alignmentAreaLeftX) as f32) < overallEstModuleSize * 3.0 {
|
||||
return Err(Exceptions::NotFoundException("not found".to_owned()));
|
||||
|
||||
@@ -40,7 +40,10 @@ impl ResultPoint for FinderPattern {
|
||||
}
|
||||
|
||||
fn into_rxing_result_point(self) -> RXingResultPoint {
|
||||
RXingResultPoint { x: self.point.0, y: self.point.1 }
|
||||
RXingResultPoint {
|
||||
x: self.point.0,
|
||||
y: self.point.1,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
|
||||
use crate::{
|
||||
common::BitMatrix, result_point_utils, DecodeHintType, DecodingHintDictionary, Exceptions,
|
||||
RXingResultPointCallback, ResultPoint,
|
||||
RXingResultPointCallback, ResultPoint,
|
||||
};
|
||||
|
||||
use super::{FinderPattern, FinderPatternInfo};
|
||||
@@ -76,7 +76,6 @@ impl FinderPatternFinder {
|
||||
&mut self,
|
||||
hints: &DecodingHintDictionary,
|
||||
) -> Result<FinderPatternInfo, Exceptions> {
|
||||
|
||||
let tryHarder = hints.contains_key(&DecodeHintType::TRY_HARDER);
|
||||
let maxI = self.image.getHeight();
|
||||
let maxJ = self.image.getWidth();
|
||||
@@ -136,7 +135,9 @@ impl FinderPatternFinder {
|
||||
// Skip by rowSkip, but back off by stateCount[2] (size of last center
|
||||
// of pattern we saw) to be conservative, and also back off by iSkip which
|
||||
// is about to be re-added
|
||||
i += rowSkip as i32 - stateCount[2] as i32 - iSkip as i32;
|
||||
i += rowSkip as i32
|
||||
- stateCount[2] as i32
|
||||
- iSkip as i32;
|
||||
// i += rowSkip - stateCount[2] - iSkip ;
|
||||
j = maxJ - 1;
|
||||
}
|
||||
@@ -144,7 +145,7 @@ impl FinderPatternFinder {
|
||||
} else {
|
||||
FinderPatternFinder::doShiftCounts2(&mut stateCount);
|
||||
currentState = 3;
|
||||
j+=1;
|
||||
j += 1;
|
||||
continue;
|
||||
}
|
||||
// Clear state to start looking again
|
||||
@@ -164,7 +165,7 @@ impl FinderPatternFinder {
|
||||
stateCount[currentState] += 1;
|
||||
}
|
||||
}
|
||||
j+=1;
|
||||
j += 1;
|
||||
}
|
||||
if FinderPatternFinder::foundPatternCross(&stateCount) {
|
||||
let confirmed = self.handlePossibleCenter(&stateCount, i as u32, maxJ);
|
||||
@@ -379,7 +380,10 @@ impl FinderPatternFinder {
|
||||
if i < 0 {
|
||||
return f32::NAN;
|
||||
}
|
||||
while i >= 0 && !self.image.get(centerJ, i as u32) && self.crossCheckStateCount[1] <= maxCount {
|
||||
while i >= 0
|
||||
&& !self.image.get(centerJ, i as u32)
|
||||
&& self.crossCheckStateCount[1] <= maxCount
|
||||
{
|
||||
self.crossCheckStateCount[1] += 1;
|
||||
i -= 1;
|
||||
}
|
||||
@@ -387,7 +391,10 @@ impl FinderPatternFinder {
|
||||
if i < 0 || self.crossCheckStateCount[1] > maxCount {
|
||||
return f32::NAN;
|
||||
}
|
||||
while i >= 0 && self.image.get(centerJ, i as u32) && self.crossCheckStateCount[0] <= maxCount {
|
||||
while i >= 0
|
||||
&& self.image.get(centerJ, i as u32)
|
||||
&& self.crossCheckStateCount[0] <= maxCount
|
||||
{
|
||||
self.crossCheckStateCount[0] += 1;
|
||||
i -= 1;
|
||||
}
|
||||
@@ -404,14 +411,20 @@ impl FinderPatternFinder {
|
||||
if i == maxI {
|
||||
return f32::NAN;
|
||||
}
|
||||
while i < maxI && !self.image.get(centerJ, i as u32) && self.crossCheckStateCount[3] < maxCount {
|
||||
while i < maxI
|
||||
&& !self.image.get(centerJ, i as u32)
|
||||
&& self.crossCheckStateCount[3] < maxCount
|
||||
{
|
||||
self.crossCheckStateCount[3] += 1;
|
||||
i += 1;
|
||||
}
|
||||
if i == maxI || self.crossCheckStateCount[3] >= maxCount {
|
||||
return f32::NAN;
|
||||
}
|
||||
while i < maxI && self.image.get(centerJ, i as u32) && self.crossCheckStateCount[4] < maxCount {
|
||||
while i < maxI
|
||||
&& self.image.get(centerJ, i as u32)
|
||||
&& self.crossCheckStateCount[4] < maxCount
|
||||
{
|
||||
self.crossCheckStateCount[4] += 1;
|
||||
i += 1;
|
||||
}
|
||||
@@ -426,7 +439,9 @@ impl FinderPatternFinder {
|
||||
+ self.crossCheckStateCount[2]
|
||||
+ self.crossCheckStateCount[3]
|
||||
+ self.crossCheckStateCount[4];
|
||||
if 5 * (stateCountTotal as i64 - originalStateCountTotal as i64) >= 2 * originalStateCountTotal as i64 {
|
||||
if 5 * (stateCountTotal as i64 - originalStateCountTotal as i64)
|
||||
>= 2 * originalStateCountTotal as i64
|
||||
{
|
||||
return f32::NAN;
|
||||
}
|
||||
|
||||
@@ -462,14 +477,20 @@ impl FinderPatternFinder {
|
||||
if j < 0 {
|
||||
return f32::NAN;
|
||||
}
|
||||
while j >= 0 && !self.image.get(j as u32, centerI) && self.crossCheckStateCount[1] <= maxCount {
|
||||
while j >= 0
|
||||
&& !self.image.get(j as u32, centerI)
|
||||
&& self.crossCheckStateCount[1] <= maxCount
|
||||
{
|
||||
self.crossCheckStateCount[1] += 1;
|
||||
j -= 1;
|
||||
}
|
||||
if j < 0 || self.crossCheckStateCount[1] > maxCount {
|
||||
return f32::NAN;
|
||||
}
|
||||
while j >= 0 && self.image.get(j as u32 as u32, centerI) && self.crossCheckStateCount[0] <= maxCount {
|
||||
while j >= 0
|
||||
&& self.image.get(j as u32 as u32, centerI)
|
||||
&& self.crossCheckStateCount[0] <= maxCount
|
||||
{
|
||||
self.crossCheckStateCount[0] += 1;
|
||||
j -= 1;
|
||||
}
|
||||
@@ -485,14 +506,20 @@ impl FinderPatternFinder {
|
||||
if j == maxJ as i32 {
|
||||
return f32::NAN;
|
||||
}
|
||||
while j < maxJ as i32 && !self.image.get(j as u32, centerI) && self.crossCheckStateCount[3] < maxCount {
|
||||
while j < maxJ as i32
|
||||
&& !self.image.get(j as u32, centerI)
|
||||
&& self.crossCheckStateCount[3] < maxCount
|
||||
{
|
||||
self.crossCheckStateCount[3] += 1;
|
||||
j += 1;
|
||||
}
|
||||
if j == (maxJ as i32) || self.crossCheckStateCount[3] >= maxCount {
|
||||
return f32::NAN;
|
||||
}
|
||||
while j < (maxJ as i32) && self.image.get(j as u32, centerI) && self.crossCheckStateCount[4] < maxCount {
|
||||
while j < (maxJ as i32)
|
||||
&& self.image.get(j as u32, centerI)
|
||||
&& self.crossCheckStateCount[4] < maxCount
|
||||
{
|
||||
self.crossCheckStateCount[4] += 1;
|
||||
j += 1;
|
||||
}
|
||||
@@ -507,7 +534,9 @@ impl FinderPatternFinder {
|
||||
+ self.crossCheckStateCount[2]
|
||||
+ self.crossCheckStateCount[3]
|
||||
+ self.crossCheckStateCount[4];
|
||||
if 5 * (stateCountTotal as i64 - originalStateCountTotal as i64) >= originalStateCountTotal as i64 {
|
||||
if 5 * (stateCountTotal as i64 - originalStateCountTotal as i64)
|
||||
>= originalStateCountTotal as i64
|
||||
{
|
||||
return f32::NAN;
|
||||
}
|
||||
|
||||
@@ -559,7 +588,8 @@ impl FinderPatternFinder {
|
||||
let stateCountTotal =
|
||||
stateCount[0] + stateCount[1] + stateCount[2] + stateCount[3] + stateCount[4];
|
||||
let mut centerJ = Self::centerFromEnd(stateCount, j);
|
||||
let centerI = self.crossCheckVertical(i, centerJ.floor() as u32, stateCount[2], stateCountTotal);
|
||||
let centerI =
|
||||
self.crossCheckVertical(i, centerJ.floor() as u32, stateCount[2], stateCountTotal);
|
||||
if !centerI.is_nan() {
|
||||
// Re-cross check
|
||||
centerJ = self.crossCheckHorizontal(
|
||||
@@ -568,7 +598,9 @@ impl FinderPatternFinder {
|
||||
stateCount[2],
|
||||
stateCountTotal,
|
||||
);
|
||||
if !centerJ.is_nan() && self.crossCheckDiagonal(centerI.floor() as u32, centerJ.floor() as u32) {
|
||||
if !centerJ.is_nan()
|
||||
&& self.crossCheckDiagonal(centerI.floor() as u32, centerJ.floor() as u32)
|
||||
{
|
||||
let estimatedModuleSize = stateCountTotal as f32 / 7.0;
|
||||
let mut found = false;
|
||||
for index in 0..self.possibleCenters.len() {
|
||||
|
||||
@@ -1,18 +1,18 @@
|
||||
mod finder_pattern_info;
|
||||
mod finder_pattern;
|
||||
mod alignment_pattern;
|
||||
mod alignment_pattern_finder;
|
||||
mod finder_pattern_finder;
|
||||
mod detector;
|
||||
mod finder_pattern;
|
||||
mod finder_pattern_finder;
|
||||
mod finder_pattern_info;
|
||||
mod qrcode_detector_result;
|
||||
|
||||
pub use finder_pattern_info::*;
|
||||
pub use finder_pattern::*;
|
||||
pub use alignment_pattern::*;
|
||||
pub use alignment_pattern_finder::*;
|
||||
pub use finder_pattern_finder::*;
|
||||
pub use detector::*;
|
||||
pub use finder_pattern::*;
|
||||
pub use finder_pattern_finder::*;
|
||||
pub use finder_pattern_info::*;
|
||||
pub use qrcode_detector_result::*;
|
||||
|
||||
#[cfg(test)]
|
||||
mod DetectorTest;
|
||||
mod DetectorTest;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
use crate::{
|
||||
common::{BitMatrix, DetectorRXingResult},
|
||||
RXingResultPoint,
|
||||
RXingResultPoint,
|
||||
};
|
||||
|
||||
pub struct QRCodeDetectorResult {
|
||||
|
||||
@@ -415,7 +415,8 @@ fn testAppendLengthInfo() {
|
||||
Version::getVersionForNumber(1).unwrap(),
|
||||
Mode::NUMERIC,
|
||||
&mut bits,
|
||||
).expect("ok");
|
||||
)
|
||||
.expect("ok");
|
||||
assert_eq!(" ........ .X", bits.to_string()); // 10 bits.
|
||||
let mut bits = BitArray::new();
|
||||
encoder::appendLengthInfo(
|
||||
@@ -423,7 +424,8 @@ fn testAppendLengthInfo() {
|
||||
Version::getVersionForNumber(10).unwrap(),
|
||||
Mode::ALPHANUMERIC,
|
||||
&mut bits,
|
||||
).expect("ok");
|
||||
)
|
||||
.expect("ok");
|
||||
assert_eq!(" ........ .X.", bits.to_string()); // 11 bits.
|
||||
let mut bits = BitArray::new();
|
||||
encoder::appendLengthInfo(
|
||||
@@ -431,7 +433,8 @@ fn testAppendLengthInfo() {
|
||||
Version::getVersionForNumber(27).unwrap(),
|
||||
Mode::BYTE,
|
||||
&mut bits,
|
||||
).expect("ok");
|
||||
)
|
||||
.expect("ok");
|
||||
assert_eq!(" ........ XXXXXXXX", bits.to_string()); // 16 bits.
|
||||
let mut bits = BitArray::new();
|
||||
encoder::appendLengthInfo(
|
||||
@@ -439,7 +442,8 @@ fn testAppendLengthInfo() {
|
||||
Version::getVersionForNumber(40).unwrap(),
|
||||
Mode::KANJI,
|
||||
&mut bits,
|
||||
).expect("ok");
|
||||
)
|
||||
.expect("ok");
|
||||
assert_eq!(" ..X..... ....", bits.to_string()); // 12 bits.
|
||||
}
|
||||
|
||||
@@ -453,7 +457,8 @@ fn testAppendBytes() {
|
||||
Mode::NUMERIC,
|
||||
&mut bits,
|
||||
encoder::DEFAULT_BYTE_MODE_ENCODING,
|
||||
).expect("ok");
|
||||
)
|
||||
.expect("ok");
|
||||
assert_eq!(" ...X", bits.to_string());
|
||||
// Should use appendAlphanumericBytes.
|
||||
// A = 10 = 0xa = 001010 in 6 bits
|
||||
@@ -463,7 +468,8 @@ fn testAppendBytes() {
|
||||
Mode::ALPHANUMERIC,
|
||||
&mut bits,
|
||||
encoder::DEFAULT_BYTE_MODE_ENCODING,
|
||||
).expect("ok");
|
||||
)
|
||||
.expect("ok");
|
||||
assert_eq!(" ..X.X.", bits.to_string());
|
||||
// Lower letters such as 'a' cannot be encoded in MODE_ALPHANUMERIC.
|
||||
//try {
|
||||
@@ -488,7 +494,8 @@ fn testAppendBytes() {
|
||||
Mode::BYTE,
|
||||
&mut bits,
|
||||
encoder::DEFAULT_BYTE_MODE_ENCODING,
|
||||
).expect("ok");
|
||||
)
|
||||
.expect("ok");
|
||||
assert_eq!(" .XX....X .XX...X. .XX...XX", bits.to_string());
|
||||
// Anything can be encoded in QRCode.MODE_8BIT_BYTE.
|
||||
encoder::appendBytes(
|
||||
@@ -496,7 +503,8 @@ fn testAppendBytes() {
|
||||
Mode::BYTE,
|
||||
&mut bits,
|
||||
encoder::DEFAULT_BYTE_MODE_ENCODING,
|
||||
).expect("ok");
|
||||
)
|
||||
.expect("ok");
|
||||
// Should use appendKanjiBytes.
|
||||
// 0x93, 0x5f
|
||||
let mut bits = BitArray::new();
|
||||
@@ -505,7 +513,8 @@ fn testAppendBytes() {
|
||||
Mode::KANJI,
|
||||
&mut bits,
|
||||
encoder::DEFAULT_BYTE_MODE_ENCODING,
|
||||
).expect("ok");
|
||||
)
|
||||
.expect("ok");
|
||||
assert_eq!(" .XX.XX.. XXXXX", bits.to_string());
|
||||
}
|
||||
|
||||
@@ -540,80 +549,45 @@ fn testTerminateBits() {
|
||||
|
||||
#[test]
|
||||
fn testGetNumDataBytesAndNumECBytesForBlockID() {
|
||||
|
||||
// Version 1-H.
|
||||
let (numDataBytes,numEcBytes) = encoder::getNumDataBytesAndNumECBytesForBlockID(
|
||||
26,
|
||||
9,
|
||||
1,
|
||||
0,
|
||||
).expect("ok");
|
||||
let (numDataBytes, numEcBytes) =
|
||||
encoder::getNumDataBytesAndNumECBytesForBlockID(26, 9, 1, 0).expect("ok");
|
||||
assert_eq!(9, numDataBytes);
|
||||
assert_eq!(17, numEcBytes);
|
||||
|
||||
// Version 3-H. 2 blocks.
|
||||
let (numDataBytes,numEcBytes) =encoder::getNumDataBytesAndNumECBytesForBlockID(
|
||||
70,
|
||||
26,
|
||||
2,
|
||||
0,
|
||||
).expect("ok");
|
||||
let (numDataBytes, numEcBytes) =
|
||||
encoder::getNumDataBytesAndNumECBytesForBlockID(70, 26, 2, 0).expect("ok");
|
||||
assert_eq!(13, numDataBytes);
|
||||
assert_eq!(22, numEcBytes);
|
||||
let (numDataBytes,numEcBytes) =encoder::getNumDataBytesAndNumECBytesForBlockID(
|
||||
70,
|
||||
26,
|
||||
2,
|
||||
1,
|
||||
).expect("ok");
|
||||
let (numDataBytes, numEcBytes) =
|
||||
encoder::getNumDataBytesAndNumECBytesForBlockID(70, 26, 2, 1).expect("ok");
|
||||
assert_eq!(13, numDataBytes);
|
||||
assert_eq!(22, numEcBytes);
|
||||
|
||||
// Version 7-H. (4 + 1) blocks.
|
||||
let (numDataBytes,numEcBytes) =encoder::getNumDataBytesAndNumECBytesForBlockID(
|
||||
196,
|
||||
66,
|
||||
5,
|
||||
0,
|
||||
|
||||
).expect("ok");
|
||||
let (numDataBytes, numEcBytes) =
|
||||
encoder::getNumDataBytesAndNumECBytesForBlockID(196, 66, 5, 0).expect("ok");
|
||||
assert_eq!(13, numDataBytes);
|
||||
assert_eq!(26, numEcBytes);
|
||||
let (numDataBytes,numEcBytes) =encoder::getNumDataBytesAndNumECBytesForBlockID(
|
||||
196,
|
||||
66,
|
||||
5,
|
||||
4,
|
||||
|
||||
).expect("ok");
|
||||
let (numDataBytes, numEcBytes) =
|
||||
encoder::getNumDataBytesAndNumECBytesForBlockID(196, 66, 5, 4).expect("ok");
|
||||
assert_eq!(14, numDataBytes);
|
||||
assert_eq!(26, numEcBytes);
|
||||
|
||||
// Version 40-H. (20 + 61) blocks.
|
||||
let (numDataBytes,numEcBytes) =encoder::getNumDataBytesAndNumECBytesForBlockID(
|
||||
3706,
|
||||
1276,
|
||||
81,
|
||||
0,
|
||||
).expect("ok");
|
||||
let (numDataBytes, numEcBytes) =
|
||||
encoder::getNumDataBytesAndNumECBytesForBlockID(3706, 1276, 81, 0).expect("ok");
|
||||
assert_eq!(15, numDataBytes);
|
||||
assert_eq!(30, numEcBytes);
|
||||
|
||||
let (numDataBytes,numEcBytes) =encoder::getNumDataBytesAndNumECBytesForBlockID(
|
||||
3706,
|
||||
1276,
|
||||
81,
|
||||
20,
|
||||
).expect("ok");
|
||||
|
||||
let (numDataBytes, numEcBytes) =
|
||||
encoder::getNumDataBytesAndNumECBytesForBlockID(3706, 1276, 81, 20).expect("ok");
|
||||
assert_eq!(16, numDataBytes);
|
||||
assert_eq!(30, numEcBytes);
|
||||
|
||||
let (numDataBytes,numEcBytes) =encoder::getNumDataBytesAndNumECBytesForBlockID(
|
||||
3706,
|
||||
1276,
|
||||
81,
|
||||
80,
|
||||
).expect("ok");
|
||||
|
||||
let (numDataBytes, numEcBytes) =
|
||||
encoder::getNumDataBytesAndNumECBytesForBlockID(3706, 1276, 81, 80).expect("ok");
|
||||
assert_eq!(16, numDataBytes);
|
||||
assert_eq!(30, numEcBytes);
|
||||
}
|
||||
@@ -738,7 +712,8 @@ fn testAppendAlphanumericBytes() {
|
||||
fn testAppend8BitBytes() {
|
||||
// 0x61, 0x62, 0x63
|
||||
let mut bits = BitArray::new();
|
||||
encoder::append8BitBytes("abc", &mut bits, encoder::DEFAULT_BYTE_MODE_ENCODING).expect("append");
|
||||
encoder::append8BitBytes("abc", &mut bits, encoder::DEFAULT_BYTE_MODE_ENCODING)
|
||||
.expect("append");
|
||||
assert_eq!(" .XX....X .XX...X. .XX...XX", bits.to_string());
|
||||
// Empty.
|
||||
let mut bits = BitArray::new();
|
||||
|
||||
@@ -254,7 +254,8 @@ fn testBuildMatrix() {
|
||||
Version::getVersionForNumber(1).expect("version"), // Version 1
|
||||
3, // Mask pattern 3
|
||||
&mut matrix,
|
||||
).expect("append");
|
||||
)
|
||||
.expect("append");
|
||||
let expected = r" 1 1 1 1 1 1 1 0 0 1 1 0 0 0 1 1 1 1 1 1 1
|
||||
1 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 1
|
||||
1 0 1 1 1 0 1 0 0 0 0 1 0 0 1 0 1 1 1 0 1
|
||||
|
||||
@@ -14,20 +14,21 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
use crate::qrcode::{decoder::{Mode, ErrorCorrectionLevel, Version}, encoder::ByteMatrix};
|
||||
use crate::qrcode::{
|
||||
decoder::{ErrorCorrectionLevel, Mode, Version},
|
||||
encoder::ByteMatrix,
|
||||
};
|
||||
|
||||
use super::QRCode;
|
||||
|
||||
|
||||
/**
|
||||
* @author satorux@google.com (Satoru Takabayashi) - creator
|
||||
* @author mysen@google.com (Chris Mysen) - ported from C++
|
||||
*/
|
||||
|
||||
|
||||
#[test]
|
||||
fn test() {
|
||||
let mut qrCode = QRCode::new();
|
||||
fn test() {
|
||||
let mut qrCode = QRCode::new();
|
||||
|
||||
// First, test simple setters and getters.
|
||||
// We use numbers of version 7-H.
|
||||
@@ -42,43 +43,43 @@ use super::QRCode;
|
||||
assert_eq!(3, qrCode.getMaskPattern());
|
||||
|
||||
// Prepare the matrix.
|
||||
let mut matrix = ByteMatrix::new(45, 45);
|
||||
let mut matrix = ByteMatrix::new(45, 45);
|
||||
// Just set bogus zero/one values.
|
||||
for y in 0..45 {
|
||||
// for (int y = 0; y < 45; ++y) {
|
||||
for x in 0..45 {
|
||||
// for (int x = 0; x < 45; ++x) {
|
||||
matrix.set(x, y, ((y + x) % 2) as u8);
|
||||
}
|
||||
// for (int y = 0; y < 45; ++y) {
|
||||
for x in 0..45 {
|
||||
// for (int x = 0; x < 45; ++x) {
|
||||
matrix.set(x, y, ((y + x) % 2) as u8);
|
||||
}
|
||||
}
|
||||
|
||||
// Set the matrix.
|
||||
qrCode.setMatrix(matrix.clone());
|
||||
assert_eq!(&matrix, qrCode.getMatrix().as_ref().unwrap());
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn testToString1() {
|
||||
let qrCode = QRCode::new();
|
||||
#[test]
|
||||
fn testToString1() {
|
||||
let qrCode = QRCode::new();
|
||||
let expected =
|
||||
"<<\n mode: null\n ecLevel: null\n version: null\n maskPattern: -1\n matrix: null\n>>\n";
|
||||
assert_eq!(expected, qrCode.to_string());
|
||||
}
|
||||
assert_eq!(expected, qrCode.to_string());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn testToString2() {
|
||||
let mut qrCode = QRCode::new();
|
||||
#[test]
|
||||
fn testToString2() {
|
||||
let mut qrCode = QRCode::new();
|
||||
qrCode.setMode(Mode::BYTE);
|
||||
qrCode.setECLevel(ErrorCorrectionLevel::H);
|
||||
qrCode.setVersion(Version::getVersionForNumber(1).expect("predefined value must exist"));
|
||||
qrCode.setMaskPattern(3);
|
||||
let mut matrix = ByteMatrix::new(21, 21);
|
||||
let mut matrix = ByteMatrix::new(21, 21);
|
||||
for y in 0..21 {
|
||||
// for (int y = 0; y < 21; ++y) {
|
||||
for x in 0..21 {
|
||||
// for (int x = 0; x < 21; ++x) {
|
||||
matrix.set(x, y, ((y + x) % 2) as u8);
|
||||
}
|
||||
// for (int y = 0; y < 21; ++y) {
|
||||
for x in 0..21 {
|
||||
// for (int x = 0; x < 21; ++x) {
|
||||
matrix.set(x, y, ((y + x) % 2) as u8);
|
||||
}
|
||||
}
|
||||
qrCode.setMatrix(matrix);
|
||||
let expected = "<<\n \
|
||||
@@ -110,13 +111,12 @@ use super::QRCode;
|
||||
0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0\n\
|
||||
>>\n";
|
||||
assert_eq!(expected, qrCode.to_string());
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn testIsValidMaskPattern() {
|
||||
#[test]
|
||||
fn testIsValidMaskPattern() {
|
||||
assert!(!QRCode::isValidMaskPattern(-1));
|
||||
assert!(QRCode::isValidMaskPattern(0));
|
||||
assert!(QRCode::isValidMaskPattern(7));
|
||||
assert!(!QRCode::isValidMaskPattern(8));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -43,7 +43,7 @@ use unicode_segmentation::UnicodeSegmentation;
|
||||
use crate::{
|
||||
common::{
|
||||
reedsolomon::{get_predefined_genericgf, PredefinedGenericGF, ReedSolomonEncoder},
|
||||
BitArray, CharacterSetECI,
|
||||
BitArray, CharacterSetECI,
|
||||
},
|
||||
qrcode::decoder::{ErrorCorrectionLevel, Mode, Version, VersionRef},
|
||||
EncodeHintType, EncodeHintValue, EncodingHintDictionary, Exceptions,
|
||||
@@ -155,9 +155,11 @@ pub fn encode_with_hints(
|
||||
let encoding = if encoding.is_some() {
|
||||
encoding.unwrap()
|
||||
} else {
|
||||
if let Ok(_encs) = DEFAULT_BYTE_MODE_ENCODING.encode(content, encoding::EncoderTrap::Strict){
|
||||
if let Ok(_encs) =
|
||||
DEFAULT_BYTE_MODE_ENCODING.encode(content, encoding::EncoderTrap::Strict)
|
||||
{
|
||||
DEFAULT_BYTE_MODE_ENCODING
|
||||
}else {
|
||||
} else {
|
||||
has_encoding_hint = true;
|
||||
encoding::all::UTF_8
|
||||
}
|
||||
@@ -302,8 +304,12 @@ fn recommendVersion(
|
||||
// Hard part: need to know version to know how many bits length takes. But need to know how many
|
||||
// bits it takes to know version. First we take a guess at version by assuming version will be
|
||||
// the minimum, 1:
|
||||
let provisional_bits_needed =
|
||||
calculateBitsNeeded(mode, header_bits, data_bits, Version::getVersionForNumber(1)?);
|
||||
let provisional_bits_needed = calculateBitsNeeded(
|
||||
mode,
|
||||
header_bits,
|
||||
data_bits,
|
||||
Version::getVersionForNumber(1)?,
|
||||
);
|
||||
let provisional_version = chooseVersion(provisional_bits_needed, ec_level)?;
|
||||
|
||||
// Use that guess to calculate the right version. I am still not sure this works in 100% of cases.
|
||||
|
||||
@@ -48,10 +48,10 @@ pub fn applyMaskPenaltyRule2(matrix: &ByteMatrix) -> u32 {
|
||||
let array = matrix.getArray();
|
||||
let width = matrix.getWidth();
|
||||
let height = matrix.getHeight();
|
||||
for y in 0..(height -1) as usize {
|
||||
for y in 0..(height - 1) as usize {
|
||||
// for (int y = 0; y < height - 1; y++) {
|
||||
let arrayY = &array[y];
|
||||
for x in 0..(width -1) as usize {
|
||||
for x in 0..(width - 1) as usize {
|
||||
// for (int x = 0; x < width - 1; x++) {
|
||||
let value = arrayY[x];
|
||||
if value == arrayY[x + 1] && value == array[y + 1][x] && value == array[y + 1][x + 1] {
|
||||
@@ -154,7 +154,8 @@ pub fn applyMaskPenaltyRule4(matrix: &ByteMatrix) -> u32 {
|
||||
}
|
||||
}
|
||||
let numTotalCells = matrix.getHeight() * matrix.getWidth();
|
||||
let fivePercentVariances = (numDarkCells as i64 * 2 - numTotalCells as i64).abs() as u32 * 10 / numTotalCells;
|
||||
let fivePercentVariances =
|
||||
(numDarkCells as i64 * 2 - numTotalCells as i64).abs() as u32 * 10 / numTotalCells;
|
||||
return fivePercentVariances * N4;
|
||||
}
|
||||
|
||||
|
||||
@@ -24,7 +24,7 @@ use crate::{
|
||||
Exceptions,
|
||||
};
|
||||
|
||||
use unicode_segmentation::{ UnicodeSegmentation};
|
||||
use unicode_segmentation::UnicodeSegmentation;
|
||||
|
||||
use super::encoder;
|
||||
|
||||
@@ -834,14 +834,15 @@ impl RXingResultList {
|
||||
}
|
||||
let first = list.get(0);
|
||||
// prepend or insert a FNC1_FIRST_POSITION after the ECI (if any)
|
||||
if first.is_some() && first.as_ref().unwrap().mode != Mode::ECI {//&& containsECI {
|
||||
if first.is_some() && first.as_ref().unwrap().mode != Mode::ECI {
|
||||
//&& containsECI {
|
||||
list.insert(
|
||||
if first.as_ref().unwrap().mode != Mode::ECI {
|
||||
//first
|
||||
list.len()
|
||||
} else {
|
||||
//second
|
||||
list.len()-1
|
||||
list.len() - 1
|
||||
},
|
||||
RXingResultNode::new(
|
||||
Mode::FNC1_FIRST_POSITION,
|
||||
|
||||
@@ -1,23 +1,23 @@
|
||||
mod qr_code;
|
||||
mod byte_matrix;
|
||||
mod block_pair;
|
||||
mod byte_matrix;
|
||||
pub mod encoder;
|
||||
pub mod mask_util;
|
||||
pub mod matrix_util;
|
||||
mod minimal_encoder;
|
||||
pub mod encoder;
|
||||
mod qr_code;
|
||||
|
||||
pub use qr_code::*;
|
||||
pub use byte_matrix::*;
|
||||
pub use block_pair::*;
|
||||
pub use byte_matrix::*;
|
||||
pub use minimal_encoder::*;
|
||||
pub use qr_code::*;
|
||||
|
||||
#[cfg(test)]
|
||||
mod QRCodeTestCase;
|
||||
#[cfg(test)]
|
||||
mod BitVectorTestCase;
|
||||
#[cfg(test)]
|
||||
mod EncoderTestCase;
|
||||
#[cfg(test)]
|
||||
mod MaskUtilTestCase;
|
||||
#[cfg(test)]
|
||||
mod MatrixUtilTestCase;
|
||||
#[cfg(test)]
|
||||
mod EncoderTestCase;
|
||||
mod QRCodeTestCase;
|
||||
|
||||
@@ -16,131 +16,124 @@
|
||||
|
||||
use std::fmt;
|
||||
|
||||
use crate::qrcode::decoder::{Mode, ErrorCorrectionLevel, Version, VersionRef};
|
||||
use crate::qrcode::decoder::{ErrorCorrectionLevel, Mode, Version, VersionRef};
|
||||
|
||||
use super::ByteMatrix;
|
||||
|
||||
|
||||
/**
|
||||
* @author satorux@google.com (Satoru Takabayashi) - creator
|
||||
* @author dswitkin@google.com (Daniel Switkin) - ported from C++
|
||||
*/
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct QRCode {
|
||||
|
||||
// public static final int NUM_MASK_PATTERNS = 8;
|
||||
|
||||
mode:Option<Mode>,
|
||||
ecLevel:Option<ErrorCorrectionLevel>,
|
||||
version:Option<VersionRef>,
|
||||
maskPattern:i32,
|
||||
matrix:Option<ByteMatrix>,
|
||||
|
||||
// public static final int NUM_MASK_PATTERNS = 8;
|
||||
mode: Option<Mode>,
|
||||
ecLevel: Option<ErrorCorrectionLevel>,
|
||||
version: Option<VersionRef>,
|
||||
maskPattern: i32,
|
||||
matrix: Option<ByteMatrix>,
|
||||
}
|
||||
|
||||
impl QRCode {
|
||||
pub const NUM_MASK_PATTERNS : i32 = 8;
|
||||
pub const NUM_MASK_PATTERNS: i32 = 8;
|
||||
|
||||
pub fn new()->Self {
|
||||
Self {
|
||||
mode: None,
|
||||
ecLevel: None,
|
||||
version: None,
|
||||
maskPattern: -1,
|
||||
matrix: None,
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
mode: None,
|
||||
ecLevel: None,
|
||||
version: None,
|
||||
maskPattern: -1,
|
||||
matrix: None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the mode. Not relevant if {@link com.google.zxing.EncodeHintType#QR_COMPACT} is selected.
|
||||
*/
|
||||
pub fn getMode(&self) -> &Option<Mode>{
|
||||
&self.mode
|
||||
}
|
||||
/**
|
||||
* @return the mode. Not relevant if {@link com.google.zxing.EncodeHintType#QR_COMPACT} is selected.
|
||||
*/
|
||||
pub fn getMode(&self) -> &Option<Mode> {
|
||||
&self.mode
|
||||
}
|
||||
|
||||
pub fn getECLevel(&self) -> &Option<ErrorCorrectionLevel>{
|
||||
&self.ecLevel
|
||||
}
|
||||
pub fn getECLevel(&self) -> &Option<ErrorCorrectionLevel> {
|
||||
&self.ecLevel
|
||||
}
|
||||
|
||||
pub fn getVersion(&self) -> &Option<&'static Version>{
|
||||
&self.version
|
||||
}
|
||||
pub fn getVersion(&self) -> &Option<&'static Version> {
|
||||
&self.version
|
||||
}
|
||||
|
||||
pub fn getMaskPattern(&self) -> i32{
|
||||
self.maskPattern
|
||||
}
|
||||
pub fn getMaskPattern(&self) -> i32 {
|
||||
self.maskPattern
|
||||
}
|
||||
|
||||
pub fn getMatrix(&self) ->&Option<ByteMatrix>{
|
||||
&self.matrix
|
||||
}
|
||||
pub fn getMatrix(&self) -> &Option<ByteMatrix> {
|
||||
&self.matrix
|
||||
}
|
||||
|
||||
|
||||
pub fn setMode(&mut self, value: Mode) {
|
||||
self.mode = Some(value);
|
||||
}
|
||||
|
||||
pub fn setMode(&mut self, value:Mode) {
|
||||
self.mode = Some(value);
|
||||
}
|
||||
pub fn setECLevel(&mut self, value: ErrorCorrectionLevel) {
|
||||
self.ecLevel = Some(value);
|
||||
}
|
||||
|
||||
pub fn setECLevel(&mut self, value:ErrorCorrectionLevel) {
|
||||
self.ecLevel = Some(value);
|
||||
}
|
||||
pub fn setVersion(&mut self, version: &'static Version) {
|
||||
self.version = Some(version);
|
||||
}
|
||||
|
||||
pub fn setVersion(&mut self, version:&'static Version) {
|
||||
self.version = Some(version);
|
||||
}
|
||||
pub fn setMaskPattern(&mut self, value: i32) {
|
||||
self.maskPattern = value;
|
||||
}
|
||||
|
||||
pub fn setMaskPattern(&mut self, value:i32) {
|
||||
self.maskPattern = value;
|
||||
}
|
||||
|
||||
pub fn setMatrix(&mut self, value:ByteMatrix) {
|
||||
self.matrix = Some(value);
|
||||
}
|
||||
|
||||
// Check if "mask_pattern" is valid.
|
||||
pub fn isValidMaskPattern( maskPattern:i32) -> bool{
|
||||
maskPattern >= 0 && maskPattern < Self::NUM_MASK_PATTERNS
|
||||
}
|
||||
pub fn setMatrix(&mut self, value: ByteMatrix) {
|
||||
self.matrix = Some(value);
|
||||
}
|
||||
|
||||
// Check if "mask_pattern" is valid.
|
||||
pub fn isValidMaskPattern(maskPattern: i32) -> bool {
|
||||
maskPattern >= 0 && maskPattern < Self::NUM_MASK_PATTERNS
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for QRCode {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
let mut result = String::with_capacity(200);
|
||||
result.push_str("<<\n");
|
||||
result.push_str(" mode: ");
|
||||
if self.mode.is_some() {
|
||||
result.push_str(&format!("{:?}",self.mode.as_ref().unwrap()));
|
||||
}else {
|
||||
result.push_str("null");
|
||||
}
|
||||
// result.push_str(&format!("{:?}", self.mode));
|
||||
result.push_str("\n ecLevel: ");
|
||||
if self.ecLevel.is_some() {
|
||||
result.push_str(&format!("{:?}",self.ecLevel.as_ref().unwrap()));
|
||||
}else {
|
||||
result.push_str("null");
|
||||
}
|
||||
// result.push_str(&format!("{:?}", self.ecLevel));
|
||||
result.push_str("\n version: ");
|
||||
if self.version.is_some() {
|
||||
result.push_str(&format!("{}",self.version.as_ref().unwrap()));
|
||||
}else {
|
||||
result.push_str("null");
|
||||
}
|
||||
result.push_str("\n maskPattern: ");
|
||||
result.push_str(&format!("{}",self.maskPattern));
|
||||
if self.matrix.is_none() {
|
||||
result.push_str("\n matrix: null\n");
|
||||
} else {
|
||||
result.push_str("\n matrix:\n");
|
||||
if self.matrix.is_some() {
|
||||
result.push_str(&format!("{}",self.matrix.as_ref().unwrap()));
|
||||
}else {
|
||||
result.push_str("null");
|
||||
let mut result = String::with_capacity(200);
|
||||
result.push_str("<<\n");
|
||||
result.push_str(" mode: ");
|
||||
if self.mode.is_some() {
|
||||
result.push_str(&format!("{:?}", self.mode.as_ref().unwrap()));
|
||||
} else {
|
||||
result.push_str("null");
|
||||
}
|
||||
}
|
||||
result.push_str(">>\n");
|
||||
|
||||
write!(f, "{}", result)
|
||||
// result.push_str(&format!("{:?}", self.mode));
|
||||
result.push_str("\n ecLevel: ");
|
||||
if self.ecLevel.is_some() {
|
||||
result.push_str(&format!("{:?}", self.ecLevel.as_ref().unwrap()));
|
||||
} else {
|
||||
result.push_str("null");
|
||||
}
|
||||
// result.push_str(&format!("{:?}", self.ecLevel));
|
||||
result.push_str("\n version: ");
|
||||
if self.version.is_some() {
|
||||
result.push_str(&format!("{}", self.version.as_ref().unwrap()));
|
||||
} else {
|
||||
result.push_str("null");
|
||||
}
|
||||
result.push_str("\n maskPattern: ");
|
||||
result.push_str(&format!("{}", self.maskPattern));
|
||||
if self.matrix.is_none() {
|
||||
result.push_str("\n matrix: null\n");
|
||||
} else {
|
||||
result.push_str("\n matrix:\n");
|
||||
if self.matrix.is_some() {
|
||||
result.push_str(&format!("{}", self.matrix.as_ref().unwrap()));
|
||||
} else {
|
||||
result.push_str("null");
|
||||
}
|
||||
}
|
||||
result.push_str(">>\n");
|
||||
|
||||
write!(f, "{}", result)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
pub mod detector;
|
||||
pub mod decoder;
|
||||
pub mod detector;
|
||||
pub mod encoder;
|
||||
|
||||
mod qr_code_reader;
|
||||
@@ -9,4 +9,4 @@ mod qr_code_writer;
|
||||
pub use qr_code_writer::*;
|
||||
|
||||
#[cfg(test)]
|
||||
mod QRCodeWriterTestCase;
|
||||
mod QRCodeWriterTestCase;
|
||||
|
||||
@@ -19,7 +19,7 @@ use std::collections::HashMap;
|
||||
use crate::{
|
||||
common::{BitMatrix, DecoderRXingResult, DetectorRXingResult},
|
||||
BarcodeFormat, DecodeHintType, Exceptions, RXingResult, RXingResultMetadataType,
|
||||
RXingResultMetadataValue, RXingResultPoint, Reader,
|
||||
RXingResultMetadataValue, RXingResultPoint, Reader,
|
||||
};
|
||||
|
||||
use super::{
|
||||
@@ -155,7 +155,7 @@ impl QRCodeReader {
|
||||
let moduleSize = Self::moduleSize(&leftTopBlack, image)?;
|
||||
|
||||
let mut top = leftTopBlack[1] as i32;
|
||||
let bottom = rightBottomBlack[1] as i32;
|
||||
let bottom = rightBottomBlack[1] as i32;
|
||||
let mut left = leftTopBlack[0] as i32;
|
||||
let mut right = rightBottomBlack[0] as i32;
|
||||
|
||||
@@ -193,7 +193,9 @@ impl QRCodeReader {
|
||||
// But careful that this does not sample off the edge
|
||||
// "right" is the farthest-right valid pixel location -- right+1 is not necessarily
|
||||
// This is positive by how much the inner x loop below would be too large
|
||||
let nudgedTooFarRight = left as i32 + ((matrixWidth as i32 - 1) as f32 * moduleSize as f32) as i32 - right as i32;
|
||||
let nudgedTooFarRight = left as i32
|
||||
+ ((matrixWidth as i32 - 1) as f32 * moduleSize as f32) as i32
|
||||
- right as i32;
|
||||
if nudgedTooFarRight > 0 {
|
||||
if nudgedTooFarRight > nudge as i32 {
|
||||
// Neither way fits; abort
|
||||
|
||||
Reference in New Issue
Block a user