mirror of
https://github.com/starovoid/rxing.git
synced 2026-07-26 04:12:34 +00:00
Cleanup of many components of the code.
Many unwraps, expects, and panics removed or handled. More rustification of the codebase. Squashed commit of the following: commit 80c6483cf8c819496a7b781f9e3a149d1f18d5fe Author: Henry <henry@azule.info> Date: Fri Feb 10 20:36:57 2023 -0600 add other parsed result option commit 412d92ae585e7bf194697f5282dbc045e448bace Author: Henry <henry@azule.info> Date: Fri Feb 10 19:06:34 2023 -0600 fix some panics commit 9108d3e931aadec00fc0bf346ebc52d24e5d8146 Author: Henry <henry@azule.info> Date: Fri Feb 10 18:56:30 2023 -0600 clippy --fix commit 8cd89d314323f54f342f15fc73297b62d418ac79 Author: Henry <henry@azule.info> Date: Fri Feb 10 18:55:45 2023 -0600 some more cleanup in aztec commit fb7f9242e273b85a4bb212f22a185a0dcbfafc36 Author: Henry <henry@azule.info> Date: Fri Feb 10 18:19:54 2023 -0600 cleanup root commit 4fb7c0639830869149332b29be789e891eade3e7 Author: Henry Schimke <henry@azule.info> Date: Fri Feb 10 16:50:15 2023 -0600 format commit 3ac271af657b25fbe5ee39cbdf8859e5aa38ea41 Author: Henry Schimke <henry@azule.info> Date: Fri Feb 10 16:43:14 2023 -0600 clippy --fix commit 0c5b4c1477159db93a9da9645039f51cd1a7c574 Author: Henry Schimke <henry@azule.info> Date: Fri Feb 10 16:04:31 2023 -0600 qrcode cleanup complete commit 70c1d107cc672e45d46567c650c46fece7e7da9c Author: Henry Schimke <henry@azule.info> Date: Fri Feb 10 13:28:25 2023 -0600 clippy --fix commit e13263d0f1f2a13dbb59b6e60d8b871a32babc92 Author: Henry Schimke <henry@azule.info> Date: Fri Feb 10 13:27:44 2023 -0600 qrcode detector cleanup commit f7f2855099e469fe1091868c6099196705d0ae83 Author: Henry Schimke <henry@azule.info> Date: Fri Feb 10 11:48:13 2023 -0600 qrcode decoder commit bdbaaba597b3479639c2ed3726465a69e3004471 Author: Henry Schimke <henry@azule.info> Date: Fri Feb 10 11:13:18 2023 -0600 clippy --fix commit fd6dbcaeb1f45dc91ae98f0e7c58aad48d67df78 Author: Henry Schimke <henry@azule.info> Date: Fri Feb 10 11:12:28 2023 -0600 pdf417 cleanup complete commit 7bbd47604c2639a5eb61bdb5533e71be3bce95a1 Author: Henry Schimke <henry@azule.info> Date: Fri Feb 10 10:39:28 2023 -0600 clippy --fix commit 8f4962b7bb5f133524fe4d3d4948e5672a88c545 Author: Henry Schimke <henry@azule.info> Date: Fri Feb 10 10:39:00 2023 -0600 cleanup on pdf417 hie commit 254c8243953776d3c8704dd81529aadd05d5a94e Author: Henry <henry@azule.info> Date: Fri Feb 10 02:51:21 2023 +0000 partway through pdf417 hle commit d4a5b00fde8c0282b0c6e4175a21c1e111b11533 Author: Henry <henry@azule.info> Date: Wed Feb 8 21:35:25 2023 +0000 clippy --fix commit 2bd4a8e218aa963a88997b50bc5a198f9a88205e Author: Henry <henry@azule.info> Date: Wed Feb 8 21:31:55 2023 +0000 pdf417 decode and detect cleanup commit 05130ac54a72c2303045d64507bf6185aa74e531 Author: Henry Schimke <henry@azule.info> Date: Tue Feb 7 08:06:25 2023 -0600 at decodeTextCompaction in decoded_bit_straem_parser commit 924c023a7d2339dfffa6ef0c4a805fb192576796 Author: Henry Schimke <henry@azule.info> Date: Mon Feb 6 18:22:02 2023 -0600 clippy --fix commit 5cfb81a885c22b4b5ec937a79be31d0815def211 Author: Henry Schimke <henry@azule.info> Date: Mon Feb 6 18:20:22 2023 -0600 oned cleanup commit 0649b64854baf56a8e3314728d4f6cf4063db8b2 Author: Henry Schimke <henry@azule.info> Date: Mon Feb 6 11:47:28 2023 -0600 rss cleanup commit 2d3127898fc11f7e65d590e983cda799b798b646 Author: Henry Schimke <henry@azule.info> Date: Mon Feb 6 10:19:56 2023 -0600 multi cleanup commit 7e8b43a159083a2096123e6204d4d1d359c59981 Author: Henry <henry@azule.info> Date: Sun Feb 5 21:41:59 2023 -0600 cargo fmt commit df8285e8da07b4bffd48ca6e596de3f010eb8d9e Author: Henry <henry@azule.info> Date: Sun Feb 5 21:41:29 2023 -0600 maxicode cleanup commit a51f923a14016eb416ca202b2194258808dde3e7 Author: Henry <henry@azule.info> Date: Sun Feb 5 21:27:57 2023 -0600 cargo fmt commit 332d7eef4a25318611025a3fcb0b70c604d917be Author: Henry <henry@azule.info> Date: Sun Feb 5 21:27:48 2023 -0600 cleanup datamatrix commit eb2311c476a9c9993f271ab6cf9fd359aedca26f Author: Henry <henry@azule.info> Date: Sun Feb 5 21:27:26 2023 -0600 cargo clippy --fix commit 2abaa4c51d287f619d4c7a438f85ba2a30f159cf Author: Henry <henry@azule.info> Date: Sun Feb 5 19:13:02 2023 -0600 finish cleanup in parsers commit 716aa2fbf728716cff36657a5fd80e7bca5276b7 Author: Henry Schimke <henry@azule.info> Date: Sun Feb 5 17:44:56 2023 -0600 cleanup continues commit 7d843788a49fa9cc82c4616d226c0f882e73612b Author: Henry Schimke <henry@azule.info> Date: Sun Feb 5 15:15:09 2023 -0600 common cleanup commit fd251866c68f22d450dd428c93d7a3620bf1be27 Author: Henry Schimke <henry@azule.info> Date: Sun Feb 5 10:24:54 2023 -0600 cleanup reedsolomon commit 132e27ed1468f5c1ce998516ff5a00687217c3e6 Author: Henry Schimke <henry@azule.info> Date: Sun Feb 5 09:52:04 2023 -0600 make MathUtils more generic commit d8352b7fff4cb4f9ecc8e8a969710d26ef410e8b Author: Henry Schimke <henry@azule.info> Date: Sun Feb 5 09:29:33 2023 -0600 cleanup some string handling in ResultParser There may still be some edge cases where multi-byte characters break the parser
This commit is contained in:
@@ -58,13 +58,15 @@ impl BitMatrixParser {
|
||||
*/
|
||||
pub fn readFormatInformation(&mut self) -> Result<&FormatInformation, Exceptions> {
|
||||
if self.parsedFormatInfo.is_some() {
|
||||
return Ok(self.parsedFormatInfo.as_ref().unwrap());
|
||||
return self
|
||||
.parsedFormatInfo
|
||||
.as_ref()
|
||||
.ok_or(Exceptions::ParseException(None));
|
||||
}
|
||||
|
||||
// Read top-left format info bits
|
||||
let mut formatInfoBits1 = 0;
|
||||
for i in 0..6 {
|
||||
// for (int i = 0; i < 6; i++) {
|
||||
formatInfoBits1 = self.copyBit(i, 8, formatInfoBits1);
|
||||
}
|
||||
// .. and skip a bit in the timing pattern ...
|
||||
@@ -73,7 +75,6 @@ impl BitMatrixParser {
|
||||
formatInfoBits1 = self.copyBit(8, 7, formatInfoBits1);
|
||||
// .. and skip a bit in the timing pattern ...
|
||||
for j in (0..=5).rev() {
|
||||
// for (int j = 5; j >= 0; j--) {
|
||||
formatInfoBits1 = self.copyBit(8, j, formatInfoBits1);
|
||||
}
|
||||
|
||||
@@ -82,20 +83,18 @@ impl BitMatrixParser {
|
||||
let mut formatInfoBits2 = 0;
|
||||
let jMin = dimension - 7;
|
||||
for j in (jMin..=dimension - 1).rev() {
|
||||
// for (int j = dimension - 1; j >= jMin; j--) {
|
||||
formatInfoBits2 = self.copyBit(8, j, formatInfoBits2);
|
||||
}
|
||||
for i in (dimension - 8)..dimension {
|
||||
// for (int i = dimension - 8; i < dimension; i++) {
|
||||
formatInfoBits2 = self.copyBit(i, 8, formatInfoBits2);
|
||||
}
|
||||
|
||||
self.parsedFormatInfo =
|
||||
FormatInformation::decodeFormatInformation(formatInfoBits1, formatInfoBits2);
|
||||
if let Some(pfi) = &self.parsedFormatInfo {
|
||||
return Ok(pfi);
|
||||
}
|
||||
Err(Exceptions::FormatException(None))
|
||||
|
||||
self.parsedFormatInfo
|
||||
.as_ref()
|
||||
.ok_or(Exceptions::FormatException(None))
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -121,9 +120,7 @@ impl BitMatrixParser {
|
||||
let mut versionBits = 0;
|
||||
let ijMin = dimension - 11;
|
||||
for j in (0..=5).rev() {
|
||||
// for (int j = 5; j >= 0; j--) {
|
||||
for i in (ijMin..(dimension - 8)).rev() {
|
||||
// for (int i = dimension - 9; i >= ijMin; i--) {
|
||||
versionBits = self.copyBit(i, j, versionBits);
|
||||
}
|
||||
}
|
||||
@@ -138,9 +135,7 @@ impl BitMatrixParser {
|
||||
// Hmm, failed. Try bottom left: 6 wide by 3 tall
|
||||
versionBits = 0;
|
||||
for i in (0..=5).rev() {
|
||||
// for (int i = 5; i >= 0; i--) {
|
||||
for j in (ijMin..(dimension - 5)).rev() {
|
||||
// for (int j = dimension - 9; j >= ijMin; j--) {
|
||||
versionBits = self.copyBit(i, j, versionBits);
|
||||
}
|
||||
}
|
||||
@@ -160,6 +155,7 @@ impl BitMatrixParser {
|
||||
} else {
|
||||
self.bitMatrix.get(i, j)
|
||||
};
|
||||
|
||||
if bit {
|
||||
(versionBits << 1) | 0x1
|
||||
} else {
|
||||
@@ -176,12 +172,11 @@ impl BitMatrixParser {
|
||||
* @throws FormatException if the exact number of bytes expected is not read
|
||||
*/
|
||||
pub fn readCodewords(&mut self) -> Result<Vec<u8>, Exceptions> {
|
||||
// let formatInfo = self.readFormatInformation()?;
|
||||
let version = self.readVersion()?;
|
||||
|
||||
// Get the data mask for the format used in this QR Code. This will exclude
|
||||
// some bits from reading as we wind through the bit matrix.
|
||||
let dataMask: DataMask = self.readFormatInformation()?.getDataMask().try_into()?; //DataMask.values()[formatInfo.getDataMask()];
|
||||
let dataMask: DataMask = self.readFormatInformation()?.getDataMask().try_into()?;
|
||||
let dimension = self.bitMatrix.getHeight();
|
||||
dataMask.unmaskBitMatrix(&mut self.bitMatrix, dimension);
|
||||
|
||||
@@ -195,7 +190,6 @@ impl BitMatrixParser {
|
||||
// Read columns in pairs, from right to left
|
||||
let mut j = dimension as i32 - 1;
|
||||
while j > 0 {
|
||||
// for (int j = dimension - 1; j > 0; j -= 2) {
|
||||
if j == 6 {
|
||||
// Skip whole column with vertical alignment pattern;
|
||||
// saves time and makes the other code proceed more cleanly
|
||||
@@ -203,14 +197,12 @@ impl BitMatrixParser {
|
||||
}
|
||||
// Read alternatingly from bottom to top then top to bottom
|
||||
for count in 0..dimension {
|
||||
// for (int count = 0; count < dimension; count++) {
|
||||
let i = if readingUp {
|
||||
dimension - 1 - count
|
||||
} else {
|
||||
count
|
||||
};
|
||||
for col in 0..2 {
|
||||
// for (int col = 0; col < 2; col++) {
|
||||
// Ignore bits covered by the function pattern
|
||||
if !functionPattern.get(j as u32 - col, i) {
|
||||
// Read a bit
|
||||
@@ -243,20 +235,15 @@ impl BitMatrixParser {
|
||||
/**
|
||||
* Revert the mask removal done while reading the code words. The bit matrix should revert to its original state.
|
||||
*/
|
||||
pub fn remask(&mut self) {
|
||||
pub fn remask(&mut self) -> Result<(), Exceptions> {
|
||||
if let Some(pfi) = &self.parsedFormatInfo {
|
||||
let dataMask: DataMask = pfi.getDataMask().try_into().unwrap(); // DataMask.values()[self.parsedFormatInfo.getDataMask()];
|
||||
let dataMask: DataMask = pfi.getDataMask().try_into()?;
|
||||
let dimension = self.bitMatrix.getHeight();
|
||||
dataMask.unmaskBitMatrix(&mut self.bitMatrix, dimension);
|
||||
} else {
|
||||
// We have no format information, and have no data mask
|
||||
}
|
||||
// if self.parsedFormatInfo.is_none() {
|
||||
// return; // We have no format information, and have no data mask
|
||||
// }
|
||||
// let dataMask = self.parsedFormatInfo.getDataMask()// DataMask.values()[self.parsedFormatInfo.getDataMask()];
|
||||
// let dimension = self.bitMatrix.getHeight();
|
||||
// dataMask.unmaskBitMatrix(self.bitMatrix, dimension);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -276,9 +263,7 @@ impl BitMatrixParser {
|
||||
/** Mirror the bit matrix in order to attempt a second reading. */
|
||||
pub fn mirror(&mut self) {
|
||||
for x in 0..self.bitMatrix.getWidth() {
|
||||
// for (int x = 0; x < bitMatrix.getWidth(); x++) {
|
||||
for y in (x + 1)..self.bitMatrix.getHeight() {
|
||||
// for (int y = x + 1; y < bitMatrix.getHeight(); y++) {
|
||||
if self.bitMatrix.get(x, y) != self.bitMatrix.get(y, x) {
|
||||
self.bitMatrix.flip_coords(y, x);
|
||||
self.bitMatrix.flip_coords(x, y);
|
||||
|
||||
@@ -66,7 +66,6 @@ impl DataBlock {
|
||||
let mut _totalBlocks = 0;
|
||||
let ecBlockArray = ecBlocks.getECBlocks();
|
||||
for ecBlock in ecBlockArray {
|
||||
// for (Version.ECB ecBlock : ecBlockArray) {
|
||||
_totalBlocks += ecBlock.getCount();
|
||||
}
|
||||
|
||||
@@ -74,12 +73,9 @@ impl DataBlock {
|
||||
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],
|
||||
@@ -93,8 +89,8 @@ impl DataBlock {
|
||||
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;
|
||||
}
|
||||
@@ -108,10 +104,7 @@ impl DataBlock {
|
||||
// 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 result_j in result.iter_mut().take(numRXingResultBlocks) {
|
||||
// for j in 0..numRXingResultBlocks {
|
||||
// for (int j = 0; j < numRXingResultBlocks; j++) {
|
||||
result_j.codewords[i] = rawCodewords[rawCodewordsOffset];
|
||||
rawCodewordsOffset += 1;
|
||||
}
|
||||
@@ -122,17 +115,13 @@ impl DataBlock {
|
||||
.take(numRXingResultBlocks)
|
||||
.skip(longerBlocksStartAt)
|
||||
{
|
||||
// for j in longerBlocksStartAt..numRXingResultBlocks {
|
||||
// for (int j = longerBlocksStartAt; j < numRXingResultBlocks; j++) {
|
||||
res.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, res) in result.iter_mut().enumerate().take(numRXingResultBlocks) {
|
||||
// for (int j = 0; j < numRXingResultBlocks; j++) {
|
||||
let iOffset = if j < longerBlocksStartAt { i } else { i + 1 };
|
||||
res.codewords[iOffset] = rawCodewords[rawCodewordsOffset];
|
||||
rawCodewordsOffset += 1;
|
||||
|
||||
@@ -85,9 +85,7 @@ impl DataMask {
|
||||
*/
|
||||
pub fn unmaskBitMatrix(&self, bits: &mut BitMatrix, dimension: u32) {
|
||||
for i in 0..dimension {
|
||||
// for (int i = 0; i < dimension; i++) {
|
||||
for j in 0..dimension {
|
||||
// for (int j = 0; j < dimension; j++) {
|
||||
if self.isMasked(i, j) {
|
||||
bits.flip_coords(j, i);
|
||||
}
|
||||
|
||||
@@ -92,7 +92,7 @@ fn testMaskAcrossDimensions(mask: DataMask, condition: MaskCondition) {
|
||||
}
|
||||
|
||||
fn testMask(mask: DataMask, dimension: u32, condition: MaskCondition) {
|
||||
let mut bits = BitMatrix::with_single_dimension(dimension);
|
||||
let mut bits = BitMatrix::with_single_dimension(dimension).expect("new");
|
||||
mask.unmaskBitMatrix(&mut bits, dimension);
|
||||
for i in 0..dimension {
|
||||
// for (int i = 0; i < dimension; i++) {
|
||||
|
||||
@@ -50,9 +50,7 @@ pub fn decode(
|
||||
let mut byteSegments = vec![vec![0u8; 0]; 0];
|
||||
let mut symbolSequence = -1i32;
|
||||
let mut parityData = -1i32;
|
||||
let symbologyModifier;
|
||||
|
||||
// try {
|
||||
let mut currentCharacterSetECI = None;
|
||||
let mut fc1InEffect = false;
|
||||
let mut hasFNC1first = false;
|
||||
@@ -93,7 +91,7 @@ pub fn decode(
|
||||
Mode::ECI => {
|
||||
// Count doesn't apply to ECI
|
||||
let value = parseECIValue(&mut bits)?;
|
||||
currentCharacterSetECI = Some(CharacterSetECI::getCharacterSetECIByValue(value)?);
|
||||
currentCharacterSetECI = CharacterSetECI::getCharacterSetECIByValue(value).ok();
|
||||
if currentCharacterSetECI.is_none() {
|
||||
return Err(Exceptions::FormatException(Some(format!(
|
||||
"Value of {value} not valid"
|
||||
@@ -144,26 +142,21 @@ pub fn decode(
|
||||
}
|
||||
}
|
||||
|
||||
if currentCharacterSetECI.is_some() {
|
||||
let symbologyModifier = if currentCharacterSetECI.is_some() {
|
||||
if hasFNC1first {
|
||||
symbologyModifier = 4;
|
||||
4
|
||||
} else if hasFNC1second {
|
||||
symbologyModifier = 6;
|
||||
6
|
||||
} else {
|
||||
symbologyModifier = 2;
|
||||
2
|
||||
}
|
||||
} else if hasFNC1first {
|
||||
symbologyModifier = 3;
|
||||
3
|
||||
} else if hasFNC1second {
|
||||
symbologyModifier = 5;
|
||||
5
|
||||
} else {
|
||||
symbologyModifier = 1;
|
||||
}
|
||||
|
||||
// } catch (IllegalArgumentException iae) {
|
||||
// // from readBits() calls
|
||||
// throw FormatException.getFormatInstance();
|
||||
// }
|
||||
1
|
||||
};
|
||||
|
||||
Ok(DecoderRXingResult::with_all(
|
||||
bytes.to_owned(),
|
||||
@@ -207,18 +200,20 @@ fn decodeHanziSegment(
|
||||
// In the 0xB0A1 to 0xFAFE range
|
||||
assembledTwoBytes += 0x0A6A1;
|
||||
}
|
||||
// buffer[offset] = ((assembledTwoBytes >> 8) & 0xFF);
|
||||
// buffer[offset + 1] = (assembledTwoBytes & 0xFF);
|
||||
|
||||
buffer[offset] = (assembledTwoBytes >> 8) as u8;
|
||||
buffer[offset + 1] = assembledTwoBytes as u8;
|
||||
offset += 2;
|
||||
count -= 1;
|
||||
}
|
||||
|
||||
let gb_encoder = encoding::label::encoding_from_whatwg_label("GBK").unwrap();
|
||||
let gb_encoder = encoding::label::encoding_from_whatwg_label("GBK")
|
||||
.ok_or(Exceptions::IllegalStateException(None))?;
|
||||
let encode_string = gb_encoder
|
||||
.decode(&buffer, encoding::DecoderTrap::Strict)
|
||||
.unwrap();
|
||||
.map_err(|e| {
|
||||
Exceptions::ParseException(Some(format!("unable to decode buffer {buffer:?}: {e}")))
|
||||
})?;
|
||||
result.push_str(&encode_string);
|
||||
Ok(())
|
||||
}
|
||||
@@ -261,27 +256,29 @@ fn decodeKanjiSegment(
|
||||
let encoder = {
|
||||
let _ = currentCharacterSetECI;
|
||||
let _ = hints;
|
||||
encoding::label::encoding_from_whatwg_label("SJIS").unwrap()
|
||||
encoding::label::encoding_from_whatwg_label("SJIS")
|
||||
.ok_or(Exceptions::FormatException(None))?
|
||||
};
|
||||
|
||||
#[cfg(feature = "allow_forced_iso_ied_18004_compliance")]
|
||||
let encoder = if let Some(DecodeHintValue::QrAssumeSpecConformInput(true)) =
|
||||
hints.get(&DecodeHintType::QR_ASSUME_SPEC_CONFORM_INPUT)
|
||||
{
|
||||
// if (hints != null && hints.containsKey(DecodeHintType.QR_ASSUME_SPEC_CONFORM_INPUT)) {
|
||||
if let Some(ccse) = ¤tCharacterSetECI {
|
||||
// if (currentCharacterSetECI == null) {
|
||||
CharacterSetECI::getCharset(ccse)
|
||||
} else {
|
||||
encoding::all::ISO_8859_1
|
||||
}
|
||||
} else {
|
||||
encoding::label::encoding_from_whatwg_label("SJIS").unwrap()
|
||||
encoding::label::encoding_from_whatwg_label("SJIS")
|
||||
.ok_or(Exceptions::FormatException(None))?
|
||||
};
|
||||
|
||||
let encode_string = encoder
|
||||
.decode(&buffer, encoding::DecoderTrap::Strict)
|
||||
.unwrap();
|
||||
.map_err(|e| {
|
||||
Exceptions::ParseException(Some(format!("unable to decode buffer {buffer:?}: {e}")))
|
||||
})?;
|
||||
|
||||
result.push_str(&encode_string);
|
||||
|
||||
@@ -304,8 +301,6 @@ fn decodeByteSegment(
|
||||
let mut readBytes = vec![0u8; count];
|
||||
|
||||
for byte in readBytes.iter_mut().take(count) {
|
||||
// for i in 0..count {
|
||||
// for (int i = 0; i < count; i++) {
|
||||
*byte = bits.readBits(8)? as u8;
|
||||
}
|
||||
let encoding = if currentCharacterSetECI.is_none() {
|
||||
@@ -317,6 +312,7 @@ fn decodeByteSegment(
|
||||
{
|
||||
#[cfg(not(feature = "allow_forced_iso_ied_18004_compliance"))]
|
||||
StringUtils::guessCharset(&readBytes, hints)
|
||||
.ok_or(Exceptions::IllegalStateException(None))?
|
||||
}
|
||||
|
||||
#[cfg(feature = "allow_forced_iso_ied_18004_compliance")]
|
||||
@@ -328,11 +324,18 @@ fn decodeByteSegment(
|
||||
StringUtils::guessCharset(&readBytes, hints)
|
||||
}
|
||||
} else {
|
||||
CharacterSetECI::getCharset(currentCharacterSetECI.as_ref().unwrap())
|
||||
CharacterSetECI::getCharset(
|
||||
currentCharacterSetECI
|
||||
.as_ref()
|
||||
.ok_or(Exceptions::IllegalStateException(None))?,
|
||||
)
|
||||
};
|
||||
|
||||
let encode_string = if currentCharacterSetECI.is_some()
|
||||
&& currentCharacterSetECI.as_ref().unwrap() == &CharacterSetECI::Cp437
|
||||
&& currentCharacterSetECI
|
||||
.as_ref()
|
||||
.ok_or(Exceptions::IllegalStateException(None))?
|
||||
== &CharacterSetECI::Cp437
|
||||
{
|
||||
{
|
||||
use codepage_437::BorrowFromCp437;
|
||||
@@ -343,12 +346,13 @@ fn decodeByteSegment(
|
||||
} else {
|
||||
encoding
|
||||
.decode(&readBytes, encoding::DecoderTrap::Strict)
|
||||
.unwrap()
|
||||
.map_err(|e| {
|
||||
Exceptions::ParseException(Some(format!(
|
||||
"unable to decode buffer {readBytes:?}: {e}"
|
||||
)))
|
||||
})?
|
||||
};
|
||||
|
||||
// let encode_string = encoding
|
||||
// .decode(&readBytes, encoding::DecoderTrap::Strict)
|
||||
// .unwrap();
|
||||
result.push_str(&encode_string);
|
||||
byteSegments.push(readBytes);
|
||||
|
||||
@@ -359,7 +363,11 @@ fn toAlphaNumericChar(value: u32) -> Result<char, Exceptions> {
|
||||
if value as usize >= ALPHANUMERIC_CHARS.len() {
|
||||
return Err(Exceptions::FormatException(None));
|
||||
}
|
||||
Ok(ALPHANUMERIC_CHARS.chars().nth(value as usize).unwrap())
|
||||
|
||||
ALPHANUMERIC_CHARS
|
||||
.chars()
|
||||
.nth(value as usize)
|
||||
.ok_or(Exceptions::FormatException(None))
|
||||
}
|
||||
|
||||
fn decodeAlphanumericSegment(
|
||||
@@ -391,16 +399,24 @@ fn decodeAlphanumericSegment(
|
||||
if fc1InEffect {
|
||||
// We need to massage the result a bit if in an FNC1 mode:
|
||||
for i in start..result.len() {
|
||||
// for (int i = start; i < result.length(); i++) {
|
||||
if result.chars().nth(i).unwrap() == '%' {
|
||||
if i < result.len() - 1 && result.chars().nth(i + 1).unwrap() == '%' {
|
||||
if result
|
||||
.chars()
|
||||
.nth(i)
|
||||
.ok_or(Exceptions::IndexOutOfBoundsException(None))?
|
||||
== '%'
|
||||
{
|
||||
if i < result.len() - 1
|
||||
&& result
|
||||
.chars()
|
||||
.nth(i + 1)
|
||||
.ok_or(Exceptions::IndexOutOfBoundsException(None))?
|
||||
== '%'
|
||||
{
|
||||
// %% is rendered as %
|
||||
result.remove(i + 1);
|
||||
// result.deleteCharAt(i + 1);
|
||||
} else {
|
||||
// In alpha mode, % should be converted to FNC1 separator 0x1D
|
||||
result.replace_range(i..i + 1, "\u{1D}");
|
||||
// result.setCharAt(i, 0x1D);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -114,7 +114,3 @@ impl FromStr for ErrorCorrectionLevel {
|
||||
))));
|
||||
}
|
||||
}
|
||||
|
||||
//private static final ErrorCorrectionLevel[] FOR_BITS = {M, L, H, Q};
|
||||
|
||||
//private final int bits;
|
||||
|
||||
@@ -14,6 +14,8 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
use crate::Exceptions;
|
||||
|
||||
use super::ErrorCorrectionLevel;
|
||||
|
||||
const FORMAT_INFO_MASK_QR: u32 = 0x5412;
|
||||
@@ -71,16 +73,15 @@ pub struct FormatInformation {
|
||||
}
|
||||
|
||||
impl FormatInformation {
|
||||
fn new(format_info: u8) -> Self {
|
||||
fn new(format_info: u8) -> Result<Self, Exceptions> {
|
||||
// Bits 3,4
|
||||
let errorCorrectionLevel =
|
||||
ErrorCorrectionLevel::forBits((format_info >> 3) & 0x03).expect("pass in valid bits");
|
||||
let errorCorrectionLevel = ErrorCorrectionLevel::forBits((format_info >> 3) & 0x03)?;
|
||||
// Bottom 3 bits
|
||||
let dataMask = format_info & 0x07;
|
||||
Self {
|
||||
Ok(Self {
|
||||
error_correction_level: errorCorrectionLevel,
|
||||
data_mask: dataMask,
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
pub fn numBitsDiffering(a: u32, b: u32) -> u32 {
|
||||
@@ -120,11 +121,10 @@ impl FormatInformation {
|
||||
let mut best_difference = u32::MAX;
|
||||
let mut best_format_info = 0;
|
||||
for decodeInfo in FORMAT_INFO_DECODE_LOOKUP {
|
||||
// for (int[] decodeInfo : FORMAT_INFO_DECODE_LOOKUP) {
|
||||
let targetInfo = decodeInfo[0];
|
||||
if targetInfo == masked_format_info1 || targetInfo == masked_format_info2 {
|
||||
// Found an exact match
|
||||
return Some(FormatInformation::new(decodeInfo[1] as u8));
|
||||
return FormatInformation::new(decodeInfo[1] as u8).ok();
|
||||
}
|
||||
let mut bits_difference = Self::numBitsDiffering(masked_format_info1, targetInfo);
|
||||
if bits_difference < best_difference {
|
||||
@@ -143,7 +143,7 @@ impl FormatInformation {
|
||||
// Hamming distance of the 32 masked codes is 7, by construction, so <= 3 bits
|
||||
// differing means we found a match
|
||||
if best_difference <= 3 {
|
||||
return Some(FormatInformation::new(best_format_info));
|
||||
return FormatInformation::new(best_format_info).ok();
|
||||
}
|
||||
None
|
||||
}
|
||||
|
||||
@@ -94,7 +94,7 @@ pub fn decode_bitmatrix_with_hints(
|
||||
|
||||
let mut trying = || -> Result<DecoderRXingResult, Exceptions> {
|
||||
// Revert the bit matrix
|
||||
parser.remask();
|
||||
parser.remask()?;
|
||||
|
||||
// Will be attempting a mirrored reading of the version and format info.
|
||||
parser.setMirror(true);
|
||||
@@ -129,20 +129,12 @@ pub fn decode_bitmatrix_with_hints(
|
||||
if let Some(fe) = fe {
|
||||
Err(fe)
|
||||
} else {
|
||||
Err(ce.unwrap())
|
||||
Err(ce.unwrap_or(Exceptions::ChecksumException(None)))
|
||||
}
|
||||
}
|
||||
_ => Err(er),
|
||||
},
|
||||
}
|
||||
|
||||
// catch (FormatException | ChecksumException e) {
|
||||
// // Throw the exception from the original reading
|
||||
// if (fe != null) {
|
||||
// throw fe;
|
||||
// }
|
||||
// throw ce; // If fe is null, this can't be
|
||||
// }
|
||||
}
|
||||
|
||||
fn decode_bitmatrix_parser_with_hints(
|
||||
@@ -167,14 +159,11 @@ fn decode_bitmatrix_parser_with_hints(
|
||||
|
||||
// Error-correct and copy data blocks together into a stream of bytes
|
||||
for dataBlock in &dataBlocks {
|
||||
// for (DataBlock dataBlock : dataBlocks) {
|
||||
let mut codewordBytes = dataBlock.getCodewords().to_vec();
|
||||
let numDataCodewords = dataBlock.getNumDataCodewords() as usize;
|
||||
correctErrors(&mut codewordBytes, numDataCodewords)?;
|
||||
for codeword_byte in codewordBytes.iter().take(numDataCodewords) {
|
||||
// for i in 0..numDataCodewords {
|
||||
// for (int i = 0; i < numDataCodewords; i++) {
|
||||
resultBytes[resultOffset] = *codeword_byte; //codewordBytes[i];
|
||||
resultBytes[resultOffset] = *codeword_byte;
|
||||
resultOffset += 1;
|
||||
}
|
||||
}
|
||||
@@ -195,10 +184,6 @@ fn correctErrors(codewordBytes: &mut [u8], numDataCodewords: usize) -> Result<()
|
||||
let numCodewords = codewordBytes.len();
|
||||
// First read into an array of ints
|
||||
let mut codewordsInts = vec![0u8; numCodewords];
|
||||
// for i in 0..numCodewords {
|
||||
// // for (int i = 0; i < numCodewords; i++) {
|
||||
// codewordsInts[i] = codewordBytes[i]; // & 0xFF;
|
||||
// }
|
||||
codewordsInts[..numCodewords].copy_from_slice(&codewordBytes[..numCodewords]);
|
||||
|
||||
let mut sending_code_words: Vec<i32> = codewordsInts.iter().map(|x| *x as i32).collect();
|
||||
@@ -207,9 +192,7 @@ fn correctErrors(codewordBytes: &mut [u8], numDataCodewords: usize) -> Result<()
|
||||
&mut sending_code_words,
|
||||
(codewordBytes.len() - numDataCodewords) as i32,
|
||||
) {
|
||||
// if let Exceptions::ReedSolomonException(error_str) = e {
|
||||
return Err(Exceptions::ChecksumException(error_str));
|
||||
// }
|
||||
}
|
||||
|
||||
// Copy back into array of bytes -- only need to worry about the bytes that were data
|
||||
|
||||
@@ -58,8 +58,6 @@ impl Version {
|
||||
let ecbArray = ecBlocks[0].getECBlocks();
|
||||
let mut i = 0;
|
||||
while i < ecbArray.len() {
|
||||
// for ecBlock in ecbArray {
|
||||
// for (ECB ecBlock : ecbArray) {
|
||||
total += ecbArray[i].getCount() * (ecbArray[i].getDataCodewords() + ecCodewords);
|
||||
i += 1;
|
||||
}
|
||||
@@ -108,11 +106,6 @@ impl Version {
|
||||
)));
|
||||
}
|
||||
Self::getVersionForNumber((dimension - 17) / 4)
|
||||
// try {
|
||||
// return getVersionForNumber((dimension - 17) / 4);
|
||||
// } catch (IllegalArgumentException ignored) {
|
||||
// throw FormatException.getFormatInstance();
|
||||
// }
|
||||
}
|
||||
|
||||
pub fn getVersionForNumber(versionNumber: u32) -> Result<&'static Version, Exceptions> {
|
||||
@@ -128,7 +121,6 @@ impl Version {
|
||||
let mut bestDifference = u32::MAX;
|
||||
let mut bestVersion = 0;
|
||||
for i in 0..VERSION_DECODE_INFO.len() as u32 {
|
||||
// for (int i = 0; i < VERSION_DECODE_INFO.length; i++) {
|
||||
let targetVersion = VERSION_DECODE_INFO[i as usize];
|
||||
// Do the version info bits match exactly? done.
|
||||
if targetVersion == versionBits {
|
||||
@@ -156,7 +148,7 @@ impl Version {
|
||||
*/
|
||||
pub fn buildFunctionPattern(&self) -> Result<BitMatrix, Exceptions> {
|
||||
let dimension = self.getDimensionForVersion();
|
||||
let mut bitMatrix = BitMatrix::with_single_dimension(dimension);
|
||||
let mut bitMatrix = BitMatrix::with_single_dimension(dimension)?;
|
||||
|
||||
// Top left finder pattern + separator + format
|
||||
bitMatrix.setRegion(0, 0, 9, 9)?;
|
||||
@@ -168,10 +160,8 @@ impl Version {
|
||||
// Alignment patterns
|
||||
let max = self.alignmentPatternCenters.len();
|
||||
for x in 0..max {
|
||||
// for (int x = 0; x < max; x++) {
|
||||
let i = self.alignmentPatternCenters[x] - 2;
|
||||
for y in 0..max {
|
||||
// for (int y = 0; y < max; y++) {
|
||||
if (x != 0 || (y != 0 && y != max - 1)) && (x != max - 1 || y != 0) {
|
||||
bitMatrix.setRegion(self.alignmentPatternCenters[y] - 2, i, 5, 5)?;
|
||||
}
|
||||
@@ -950,7 +940,6 @@ impl ECBlocks {
|
||||
pub fn getNumBlocks(&self) -> u32 {
|
||||
let mut total = 0;
|
||||
for ecBlock in &self.ecBlocks {
|
||||
// for (ECB ecBlock : ecBlocks) {
|
||||
total += ecBlock.getCount();
|
||||
}
|
||||
total
|
||||
|
||||
@@ -91,9 +91,8 @@ impl AlignmentPatternFinder {
|
||||
let middleI = self.startY + (height / 2);
|
||||
// We are looking for black/white/black modules in 1:1:1 ratio;
|
||||
// this tracks the number of black/white/black modules seen so far
|
||||
let mut stateCount = vec![0u32; 3];
|
||||
let mut stateCount = [0u32; 3];
|
||||
for iGen in 0..height {
|
||||
// for (int iGen = 0; iGen < height; iGen++) {
|
||||
// Search from middle outwards
|
||||
let i = (middleI as i32
|
||||
+ (if (iGen & 0x01) == 0 {
|
||||
@@ -101,9 +100,9 @@ impl AlignmentPatternFinder {
|
||||
} else {
|
||||
-((iGen as i32 + 1) / 2)
|
||||
})) as u32;
|
||||
stateCount[0] = 0;
|
||||
stateCount[1] = 0;
|
||||
stateCount[2] = 0;
|
||||
|
||||
stateCount.fill(0);
|
||||
|
||||
let mut j = startX;
|
||||
// Burn off leading white pixels before anything else; if we start in the middle of
|
||||
// a white run, it doesn't make sense to count its length, since we don't know if the
|
||||
@@ -159,10 +158,13 @@ impl AlignmentPatternFinder {
|
||||
// Hmm, nothing we saw was observed and confirmed twice. If we had
|
||||
// any guess at all, return it.
|
||||
if !self.possibleCenters.is_empty() {
|
||||
return Ok(*self.possibleCenters.get(0).unwrap());
|
||||
Ok(*(self
|
||||
.possibleCenters
|
||||
.get(0)
|
||||
.ok_or(Exceptions::IndexOutOfBoundsException(None)))?)
|
||||
} else {
|
||||
Err(Exceptions::NotFoundException(None))
|
||||
}
|
||||
|
||||
Err(Exceptions::NotFoundException(None))
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -182,8 +184,6 @@ impl AlignmentPatternFinder {
|
||||
let moduleSize = self.moduleSize;
|
||||
let maxVariance = moduleSize / 2.0;
|
||||
for state in stateCount.iter().take(3) {
|
||||
// for i in 0..3 {
|
||||
// for (int i = 0; i < 3; i++) {
|
||||
if (moduleSize - *state as f32).abs() >= maxVariance {
|
||||
return false;
|
||||
}
|
||||
@@ -212,10 +212,7 @@ impl AlignmentPatternFinder {
|
||||
let image = &self.image;
|
||||
|
||||
let maxI = image.getHeight();
|
||||
// let mut stateCount = &self.crossCheckStateCount;
|
||||
self.crossCheckStateCount[0] = 0;
|
||||
self.crossCheckStateCount[1] = 0;
|
||||
self.crossCheckStateCount[2] = 0;
|
||||
self.crossCheckStateCount.fill(0);
|
||||
|
||||
// Start counting up from center
|
||||
let mut i = startI as i32;
|
||||
@@ -303,7 +300,6 @@ impl AlignmentPatternFinder {
|
||||
if !centerI.is_nan() {
|
||||
let estimatedModuleSize = (stateCount[0] + stateCount[1] + stateCount[2]) as f32 / 3.0;
|
||||
for center in &self.possibleCenters {
|
||||
// for (AlignmentPattern center : possibleCenters) {
|
||||
// Look for about the same center and module size:
|
||||
if center.aboutEquals(estimatedModuleSize, centerI, centerJ) {
|
||||
return Some(center.combineEstimate(centerI, centerJ, estimatedModuleSize));
|
||||
@@ -311,13 +307,11 @@ impl AlignmentPatternFinder {
|
||||
}
|
||||
// Hadn't found this before; save it
|
||||
let point = AlignmentPattern::new(centerJ, centerI, estimatedModuleSize);
|
||||
if self.resultPointCallback.is_some() {
|
||||
self.resultPointCallback.as_ref().unwrap()(&point);
|
||||
if let Some(rpc) = self.resultPointCallback.clone() {
|
||||
rpc(&point);
|
||||
}
|
||||
|
||||
self.possibleCenters.push(point);
|
||||
// if self.resultPointCallback.is_some() {
|
||||
// self.resultPointCallback.as_ref().unwrap()(point.as_RXingResultPoint());
|
||||
// }
|
||||
}
|
||||
|
||||
None
|
||||
|
||||
@@ -33,7 +33,7 @@ fn test_encode_decode(value: &str) {
|
||||
let byt_matrix = qr_code.getMatrix().as_ref().unwrap().clone();
|
||||
// dbg!(BitMatrix::from(byt_matrix.clone()).to_string());
|
||||
// let mut detector = Detector::new(make_larger(&byt_matrix.into(),5));
|
||||
let new_matrix: &BitMatrix = &byt_matrix.into();
|
||||
let new_matrix: &BitMatrix = &byt_matrix.try_into().expect("convert");
|
||||
let mut detector = Detector::new(new_matrix);
|
||||
let detected_points = detector.detect().expect("must detect");
|
||||
let decoded =
|
||||
@@ -46,7 +46,7 @@ fn test_encode_decode(value: &str) {
|
||||
#[allow(dead_code)]
|
||||
fn make_larger(input: &BitMatrix, factor: u32) -> BitMatrix {
|
||||
let width = input.getWidth();
|
||||
let mut output = BitMatrix::with_single_dimension(width * factor);
|
||||
let mut output = BitMatrix::with_single_dimension(width * factor).expect("new");
|
||||
for inputY in 0..width {
|
||||
// for (int inputY = 0; inputY < width; inputY++) {
|
||||
for inputX in 0..width {
|
||||
|
||||
@@ -75,9 +75,10 @@ impl FinderPattern {
|
||||
pub fn aboutEquals(&self, moduleSize: f32, i: f32, j: f32) -> bool {
|
||||
if (i - self.getY()).abs() <= moduleSize && (j - self.getX()).abs() <= moduleSize {
|
||||
let moduleSizeDiff = (moduleSize - self.estimatedModuleSize).abs();
|
||||
return moduleSizeDiff <= 1.0 || moduleSizeDiff <= self.estimatedModuleSize;
|
||||
moduleSizeDiff <= 1.0 || moduleSizeDiff <= self.estimatedModuleSize
|
||||
} else {
|
||||
false
|
||||
}
|
||||
false
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -15,8 +15,8 @@
|
||||
*/
|
||||
|
||||
use crate::{
|
||||
common::BitMatrix, result_point_utils, DecodeHintType, DecodingHintDictionary, Exceptions,
|
||||
RXingResultPointCallback, ResultPoint,
|
||||
common::BitMatrix, result_point_utils, DecodeHintType, DecodeHintValue, DecodingHintDictionary,
|
||||
Exceptions, RXingResultPointCallback, ResultPoint,
|
||||
};
|
||||
|
||||
use super::{FinderPattern, FinderPatternInfo};
|
||||
@@ -29,16 +29,15 @@ use super::{FinderPattern, FinderPatternInfo};
|
||||
*
|
||||
* @author Sean Owen
|
||||
*/
|
||||
pub struct FinderPatternFinder {
|
||||
image: BitMatrix,
|
||||
pub struct FinderPatternFinder<'a> {
|
||||
image: &'a BitMatrix,
|
||||
possibleCenters: Vec<FinderPattern>,
|
||||
hasSkipped: bool,
|
||||
crossCheckStateCount: [u32; 5],
|
||||
resultPointCallback: Option<RXingResultPointCallback>,
|
||||
}
|
||||
impl FinderPatternFinder {
|
||||
impl<'a> FinderPatternFinder<'_> {
|
||||
pub const CENTER_QUORUM: usize = 2;
|
||||
// private static final EstimatedModuleComparator moduleComparator = new EstimatedModuleComparator();
|
||||
pub const MIN_SKIP: u32 = 3; // 1 pixel/module times 3 modules/center
|
||||
pub const MAX_MODULES: u32 = 97; // support up to version 20 for mobile clients
|
||||
|
||||
@@ -47,15 +46,15 @@ impl FinderPatternFinder {
|
||||
*
|
||||
* @param image image to search
|
||||
*/
|
||||
pub fn new(image: BitMatrix) -> Self {
|
||||
pub fn new(image: &'a BitMatrix) -> FinderPatternFinder<'a> {
|
||||
Self::with_callback(image, None)
|
||||
}
|
||||
|
||||
pub fn with_callback(
|
||||
image: BitMatrix,
|
||||
image: &'a BitMatrix,
|
||||
resultPointCallback: Option<RXingResultPointCallback>,
|
||||
) -> Self {
|
||||
Self {
|
||||
) -> FinderPatternFinder<'a> {
|
||||
FinderPatternFinder {
|
||||
image,
|
||||
possibleCenters: Vec::new(),
|
||||
hasSkipped: false,
|
||||
@@ -65,7 +64,7 @@ impl FinderPatternFinder {
|
||||
}
|
||||
|
||||
pub fn getImage(&self) -> &BitMatrix {
|
||||
&self.image
|
||||
self.image
|
||||
}
|
||||
|
||||
pub fn getPossibleCenters(&self) -> &Vec<FinderPattern> {
|
||||
@@ -76,7 +75,10 @@ impl FinderPatternFinder {
|
||||
&mut self,
|
||||
hints: &DecodingHintDictionary,
|
||||
) -> Result<FinderPatternInfo, Exceptions> {
|
||||
let tryHarder = hints.contains_key(&DecodeHintType::TRY_HARDER);
|
||||
let tryHarder = matches!(
|
||||
hints.get(&DecodeHintType::TRY_HARDER),
|
||||
Some(DecodeHintValue::TryHarder(true))
|
||||
);
|
||||
let maxI = self.image.getHeight();
|
||||
let maxJ = self.image.getWidth();
|
||||
// We are looking for black/white/black/white/black modules in
|
||||
@@ -95,13 +97,11 @@ impl FinderPatternFinder {
|
||||
let mut stateCount = [0u32; 5];
|
||||
let mut i = iSkip as i32 - 1;
|
||||
while i < maxI as i32 && !done {
|
||||
// for (int i = iSkip - 1; i < maxI && !done; i += iSkip) {
|
||||
// Get a row of black/white values
|
||||
FinderPatternFinder::doClearCounts(&mut stateCount);
|
||||
let mut currentState = 0;
|
||||
let mut j = 0;
|
||||
while j < maxJ {
|
||||
// for (int j = 0; j < maxJ; j++) {
|
||||
if self.image.get(j, i as u32) {
|
||||
// Black pixel
|
||||
if (currentState & 1) == 1 {
|
||||
@@ -203,9 +203,6 @@ impl FinderPatternFinder {
|
||||
pub fn foundPatternCross(stateCount: &[u32]) -> bool {
|
||||
let mut totalModuleSize = 0;
|
||||
for count in stateCount.iter().take(5) {
|
||||
// for i in 0..5 {
|
||||
// for (int i = 0; i < 5; i++) {
|
||||
// let count = *state;
|
||||
if *count == 0 {
|
||||
return false;
|
||||
}
|
||||
@@ -232,8 +229,6 @@ impl FinderPatternFinder {
|
||||
pub fn foundPatternDiagonal(stateCount: &[u32]) -> bool {
|
||||
let mut totalModuleSize = 0;
|
||||
for count in stateCount.iter().take(5) {
|
||||
// for i in 0..5 {
|
||||
// for (int i = 0; i < 5; i++) {
|
||||
if *count == 0 {
|
||||
return false;
|
||||
}
|
||||
@@ -367,8 +362,6 @@ impl FinderPatternFinder {
|
||||
maxCount: u32,
|
||||
originalStateCountTotal: u32,
|
||||
) -> f32 {
|
||||
// let image = &self.image;
|
||||
|
||||
let maxI = self.image.getHeight() as i32;
|
||||
let _stateCount = self.getCrossCheckStateCount();
|
||||
|
||||
@@ -435,11 +428,8 @@ impl FinderPatternFinder {
|
||||
|
||||
// If we found a finder-pattern-like section, but its size is more than 40% different than
|
||||
// the original, assume it's a false positive
|
||||
let stateCountTotal = self.crossCheckStateCount[0]
|
||||
+ self.crossCheckStateCount[1]
|
||||
+ self.crossCheckStateCount[2]
|
||||
+ self.crossCheckStateCount[3]
|
||||
+ self.crossCheckStateCount[4];
|
||||
let stateCountTotal = self.crossCheckStateCount.iter().sum::<u32>();
|
||||
|
||||
if 5 * (stateCountTotal as i64 - originalStateCountTotal as i64)
|
||||
>= 2 * originalStateCountTotal as i64
|
||||
{
|
||||
@@ -465,8 +455,6 @@ impl FinderPatternFinder {
|
||||
maxCount: u32,
|
||||
originalStateCountTotal: u32,
|
||||
) -> f32 {
|
||||
// let image = &self.image;
|
||||
|
||||
let maxJ = self.image.getWidth();
|
||||
let _stateCount = self.getCrossCheckStateCount();
|
||||
|
||||
@@ -478,6 +466,7 @@ impl FinderPatternFinder {
|
||||
if j < 0 {
|
||||
return f32::NAN;
|
||||
}
|
||||
|
||||
while j >= 0
|
||||
&& !self.image.get(j as u32, centerI)
|
||||
&& self.crossCheckStateCount[1] <= maxCount
|
||||
@@ -488,6 +477,7 @@ impl FinderPatternFinder {
|
||||
if j < 0 || self.crossCheckStateCount[1] > maxCount {
|
||||
return f32::NAN;
|
||||
}
|
||||
|
||||
while j >= 0
|
||||
&& self.image.get(j as u32, centerI)
|
||||
&& self.crossCheckStateCount[0] <= maxCount
|
||||
@@ -507,6 +497,7 @@ 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
|
||||
@@ -517,6 +508,7 @@ impl FinderPatternFinder {
|
||||
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
|
||||
@@ -530,11 +522,8 @@ impl FinderPatternFinder {
|
||||
|
||||
// If we found a finder-pattern-like section, but its size is significantly different than
|
||||
// the original, assume it's a false positive
|
||||
let stateCountTotal = self.crossCheckStateCount[0]
|
||||
+ self.crossCheckStateCount[1]
|
||||
+ self.crossCheckStateCount[2]
|
||||
+ self.crossCheckStateCount[3]
|
||||
+ self.crossCheckStateCount[4];
|
||||
let stateCountTotal = self.crossCheckStateCount.iter().sum::<u32>();
|
||||
|
||||
if 5 * (stateCountTotal as i64 - originalStateCountTotal as i64)
|
||||
>= originalStateCountTotal as i64
|
||||
{
|
||||
@@ -604,13 +593,10 @@ impl FinderPatternFinder {
|
||||
{
|
||||
let estimatedModuleSize = stateCountTotal as f32 / 7.0;
|
||||
let mut found = false;
|
||||
for index in 0..self.possibleCenters.len() {
|
||||
// for (int index = 0; index < possibleCenters.size(); index++) {
|
||||
let center = self.possibleCenters.get(index).unwrap();
|
||||
for center in self.possibleCenters.iter_mut() {
|
||||
// Look for about the same center and module size:
|
||||
if center.aboutEquals(estimatedModuleSize, centerI, centerJ) {
|
||||
self.possibleCenters[index] =
|
||||
center.combineEstimate(centerI, centerJ, estimatedModuleSize);
|
||||
*center = center.combineEstimate(centerI, centerJ, estimatedModuleSize);
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
@@ -618,8 +604,8 @@ impl FinderPatternFinder {
|
||||
if !found {
|
||||
let point = FinderPattern::new(centerJ, centerI, estimatedModuleSize);
|
||||
self.possibleCenters.push(point);
|
||||
if self.resultPointCallback.is_some() {
|
||||
self.resultPointCallback.as_ref().unwrap()(&point);
|
||||
if let Some(rpc) = self.resultPointCallback.clone() {
|
||||
rpc(&point);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
@@ -641,7 +627,6 @@ impl FinderPatternFinder {
|
||||
}
|
||||
let mut firstConfirmedCenter: Option<&FinderPattern> = None;
|
||||
for center in &self.possibleCenters {
|
||||
// for (FinderPattern center : possibleCenters) {
|
||||
if center.getCount() >= Self::CENTER_QUORUM {
|
||||
if let Some(fnp) = firstConfirmedCenter {
|
||||
// We have two confirmed centers
|
||||
@@ -655,7 +640,7 @@ impl FinderPatternFinder {
|
||||
/ 2.0)
|
||||
.floor() as u32;
|
||||
} else {
|
||||
firstConfirmedCenter = Some(center);
|
||||
firstConfirmedCenter.replace(center);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -672,7 +657,6 @@ impl FinderPatternFinder {
|
||||
let mut totalModuleSize = 0.0;
|
||||
let max = self.possibleCenters.len();
|
||||
for pattern in &self.possibleCenters {
|
||||
// for (FinderPattern pattern : possibleCenters) {
|
||||
if pattern.getCount() >= Self::CENTER_QUORUM {
|
||||
confirmedCount += 1;
|
||||
totalModuleSize += pattern.getEstimatedModuleSize();
|
||||
@@ -715,50 +699,32 @@ impl FinderPatternFinder {
|
||||
return Err(Exceptions::NotFoundException(None));
|
||||
}
|
||||
|
||||
// for (Iterator<FinderPattern> it = possibleCenters.iterator(); it.hasNext();) {
|
||||
// if (it.next().getCount() < CENTER_QUORUM) {
|
||||
// it.remove();
|
||||
// }
|
||||
// }
|
||||
|
||||
self.possibleCenters
|
||||
.retain(|fp| fp.getCount() >= Self::CENTER_QUORUM);
|
||||
|
||||
self.possibleCenters.sort_by(|x, y| {
|
||||
self.possibleCenters.sort_unstable_by(|x, y| {
|
||||
x.getEstimatedModuleSize()
|
||||
.partial_cmp(&y.getEstimatedModuleSize())
|
||||
.unwrap()
|
||||
// Float.compare(center1.getEstimatedModuleSize(), center2.getEstimatedModuleSize());
|
||||
.unwrap_or(std::cmp::Ordering::Less) // we are making a weird assumption that uncomparable items are result in Less
|
||||
});
|
||||
|
||||
// self.possibleCenters.sort(self.moduleComparator);
|
||||
|
||||
let mut distortion = f64::MAX;
|
||||
let mut bestPatterns = [None; 3];
|
||||
|
||||
for i in 0..self.possibleCenters.len() {
|
||||
// for (int i = 0; i < possibleCenters.size() - 2; i++) {
|
||||
let fpi = if let Some(f) = self.possibleCenters.get(i) {
|
||||
f
|
||||
} else {
|
||||
let Some(fpi) = self.possibleCenters.get(i) else {
|
||||
return Err(Exceptions::NotFoundException(None));
|
||||
};
|
||||
let minModuleSize = fpi.getEstimatedModuleSize();
|
||||
|
||||
for j in (i + 1)..(self.possibleCenters.len() - 1) {
|
||||
// for (int j = i + 1; j < possibleCenters.size() - 1; j++) {
|
||||
let fpj = if let Some(f) = self.possibleCenters.get(j) {
|
||||
f
|
||||
} else {
|
||||
let Some(fpj) = self.possibleCenters.get(j) else {
|
||||
return Err(Exceptions::NotFoundException(None));
|
||||
};
|
||||
let squares0 = Self::squaredDistance(fpi, fpj);
|
||||
|
||||
for k in (j + 1)..(self.possibleCenters.len()) {
|
||||
// for (int k = j + 1; k < possibleCenters.size(); k++) {
|
||||
let fpk = if let Some(f) = self.possibleCenters.get(k) {
|
||||
f
|
||||
} else {
|
||||
let Some(fpk) = self.possibleCenters.get(k) else {
|
||||
return Err(Exceptions::NotFoundException(None));
|
||||
};
|
||||
let maxModuleSize = fpk.getEstimatedModuleSize();
|
||||
@@ -805,9 +771,6 @@ impl FinderPatternFinder {
|
||||
if d < distortion {
|
||||
distortion = d;
|
||||
bestPatterns = [Some(*fpi), Some(*fpj), Some(*fpk)];
|
||||
// bestPatterns[0] = *fpi;
|
||||
// bestPatterns[1] = *fpj;
|
||||
// bestPatterns[2] = *fpk;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -821,20 +784,10 @@ impl FinderPatternFinder {
|
||||
return Err(Exceptions::NotFoundException(None));
|
||||
}
|
||||
|
||||
let p1 = bestPatterns[0].unwrap();
|
||||
let p2 = bestPatterns[1].unwrap();
|
||||
let p3 = bestPatterns[2].unwrap();
|
||||
let p1 = bestPatterns[0].ok_or(Exceptions::NotFoundException(None))?;
|
||||
let p2 = bestPatterns[1].ok_or(Exceptions::NotFoundException(None))?;
|
||||
let p3 = bestPatterns[2].ok_or(Exceptions::NotFoundException(None))?;
|
||||
|
||||
Ok([p1, p2, p3])
|
||||
}
|
||||
}
|
||||
|
||||
// /**
|
||||
// * <p>Orders by {@link FinderPattern#getEstimatedModuleSize()}</p>
|
||||
// */
|
||||
// private static final class EstimatedModuleComparator implements Comparator<FinderPattern>, Serializable {
|
||||
// @Override
|
||||
// public int compare(FinderPattern center1, FinderPattern center2) {
|
||||
// return Float.compare(center1.getEstimatedModuleSize(), center2.getEstimatedModuleSize());
|
||||
// }
|
||||
// }
|
||||
|
||||
@@ -29,6 +29,7 @@ pub struct FinderPatternInfo {
|
||||
}
|
||||
|
||||
impl FinderPatternInfo {
|
||||
/// Expects the order to be [bottom_left, top_left, top_right]
|
||||
pub fn new(patternCenters: [FinderPattern; 3]) -> Self {
|
||||
let [a, b, c] = patternCenters;
|
||||
Self {
|
||||
|
||||
@@ -83,23 +83,13 @@ impl<'a> Detector<'_> {
|
||||
self.resultPointCallback = if let Some(DecodeHintValue::NeedResultPointCallback(cb)) =
|
||||
hints.get(&DecodeHintType::NEED_RESULT_POINT_CALLBACK)
|
||||
{
|
||||
// if let DecodeHintValue::NeedResultPointCallback(cb) = nrpc {
|
||||
Some(cb.clone())
|
||||
// } else {
|
||||
// None
|
||||
// }
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
// self.resultPointCallback = hints.get(&DecodeHintType::NEED_RESULT_POINT_CALLBACK);
|
||||
// resultPointCallback = hints == null ? null :
|
||||
// (RXingResultPointCallback) hints.get(DecodeHintType.NEED_RESULT_POINT_CALLBACK);
|
||||
|
||||
let mut finder = FinderPatternFinder::with_callback(
|
||||
self.image.clone(),
|
||||
self.resultPointCallback.clone(),
|
||||
);
|
||||
let mut finder =
|
||||
FinderPatternFinder::with_callback(self.image, self.resultPointCallback.clone());
|
||||
let info = finder.find(hints)?;
|
||||
|
||||
self.processFinderPatternInfo(info)
|
||||
@@ -139,51 +129,41 @@ impl<'a> Detector<'_> {
|
||||
// Kind of arbitrary -- expand search radius before giving up
|
||||
let mut i = 4;
|
||||
while i <= 16 {
|
||||
// for (int i = 4; i <= 16; i <<= 1) {
|
||||
if let Ok(ap) =
|
||||
self.findAlignmentInRegion(moduleSize, estAlignmentX, estAlignmentY, i as f32)
|
||||
{
|
||||
alignmentPattern = Some(ap);
|
||||
break;
|
||||
}
|
||||
// try {
|
||||
// alignmentPattern = findAlignmentInRegion(moduleSize,
|
||||
// estAlignmentX,
|
||||
// estAlignmentY,
|
||||
// i);
|
||||
// break;
|
||||
// } catch (NotFoundException re) {
|
||||
// // try next round
|
||||
// }
|
||||
i <<= 1;
|
||||
}
|
||||
// If we didn't find alignment pattern... well try anyway without it
|
||||
}
|
||||
|
||||
let ap_ref = if alignmentPattern.is_some() {
|
||||
Some(alignmentPattern.as_ref().unwrap())
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
let transform = Self::createTransform(topLeft, topRight, bottomLeft, ap_ref, dimension);
|
||||
let transform = Self::createTransform(
|
||||
topLeft,
|
||||
topRight,
|
||||
bottomLeft,
|
||||
alignmentPattern.as_ref(),
|
||||
dimension,
|
||||
)
|
||||
.ok_or(Exceptions::NotFoundException(None))?;
|
||||
|
||||
let bits = Detector::sampleGrid(self.image, &transform, dimension)?;
|
||||
|
||||
let points = if alignmentPattern.is_none() {
|
||||
vec![
|
||||
bottomLeft.into_rxing_result_point(),
|
||||
topLeft.into_rxing_result_point(),
|
||||
topRight.into_rxing_result_point(),
|
||||
]
|
||||
} else {
|
||||
vec![
|
||||
bottomLeft.into_rxing_result_point(),
|
||||
topLeft.into_rxing_result_point(),
|
||||
topRight.into_rxing_result_point(),
|
||||
alignmentPattern.unwrap().into_rxing_result_point(),
|
||||
]
|
||||
};
|
||||
let mut points = vec![
|
||||
bottomLeft.into_rxing_result_point(),
|
||||
topLeft.into_rxing_result_point(),
|
||||
topRight.into_rxing_result_point(),
|
||||
];
|
||||
|
||||
if alignmentPattern.is_some() {
|
||||
points.push(
|
||||
alignmentPattern
|
||||
.ok_or(Exceptions::NotFoundException(None))?
|
||||
.into_rxing_result_point(),
|
||||
)
|
||||
}
|
||||
|
||||
Ok(QRCodeDetectorResult::new(bits, points))
|
||||
}
|
||||
@@ -194,14 +174,14 @@ impl<'a> Detector<'_> {
|
||||
bottomLeft: &T,
|
||||
alignmentPattern: Option<&X>,
|
||||
dimension: u32,
|
||||
) -> PerspectiveTransform {
|
||||
) -> Option<PerspectiveTransform> {
|
||||
let dimMinusThree = dimension as f32 - 3.5;
|
||||
let bottomRightX: f32;
|
||||
let bottomRightY: f32;
|
||||
let sourceBottomRightX: f32;
|
||||
let sourceBottomRightY: f32;
|
||||
if alignmentPattern.is_some() {
|
||||
let alignmentPattern = alignmentPattern.as_ref().unwrap();
|
||||
let alignmentPattern = alignmentPattern?;
|
||||
bottomRightX = alignmentPattern.getX();
|
||||
bottomRightY = alignmentPattern.getY();
|
||||
sourceBottomRightX = dimMinusThree - 3.0;
|
||||
@@ -214,7 +194,7 @@ impl<'a> Detector<'_> {
|
||||
sourceBottomRightY = dimMinusThree;
|
||||
}
|
||||
|
||||
PerspectiveTransform::quadrilateralToQuadrilateral(
|
||||
Some(PerspectiveTransform::quadrilateralToQuadrilateral(
|
||||
3.5,
|
||||
3.5,
|
||||
dimMinusThree,
|
||||
@@ -231,7 +211,7 @@ impl<'a> Detector<'_> {
|
||||
bottomRightY,
|
||||
bottomLeft.getX(),
|
||||
bottomLeft.getY(),
|
||||
)
|
||||
))
|
||||
}
|
||||
|
||||
fn sampleGrid(
|
||||
@@ -264,17 +244,6 @@ impl<'a> Detector<'_> {
|
||||
3 => return Err(Exceptions::NotFoundException(None)),
|
||||
_ => {}
|
||||
}
|
||||
// switch (dimension & 0x03) { // mod 4
|
||||
// case 0:
|
||||
// dimension++;
|
||||
// break;
|
||||
// // 1? do nothing
|
||||
// case 2:
|
||||
// dimension--;
|
||||
// break;
|
||||
// case 3:
|
||||
// return Err(Exceptions::NotFoundException("not found".to_owned()))
|
||||
// }
|
||||
Ok(dimension as u32)
|
||||
}
|
||||
|
||||
@@ -401,7 +370,6 @@ impl<'a> Detector<'_> {
|
||||
let mut x: i32 = fromX as i32;
|
||||
let mut y: i32 = fromY as i32;
|
||||
while x != xLimit {
|
||||
// for (int x = fromX, y = fromY; x != xLimit; x += xstep) {
|
||||
let realX = if steep { y } else { x };
|
||||
let realY = if steep { x } else { y };
|
||||
|
||||
@@ -410,7 +378,7 @@ impl<'a> Detector<'_> {
|
||||
// color, advance to next state or end if we are in state 2 already
|
||||
if (state == 1) == self.image.get(realX as u32, realY as u32) {
|
||||
if state == 2 {
|
||||
return MathUtils::distance_int(x, y, fromX as i32, fromY as i32);
|
||||
return MathUtils::distance(x, y, fromX as i32, fromY as i32);
|
||||
}
|
||||
state += 1;
|
||||
}
|
||||
@@ -430,12 +398,7 @@ impl<'a> Detector<'_> {
|
||||
// is "white" so this last point at (toX+xStep,toY) is the right ending. This is really a
|
||||
// small approximation; (toX+xStep,toY+yStep) might be really correct. Ignore this.
|
||||
if state == 2 {
|
||||
return MathUtils::distance_int(
|
||||
toX as i32 + xstep,
|
||||
toY as i32,
|
||||
fromX as i32,
|
||||
fromY as i32,
|
||||
);
|
||||
return MathUtils::distance(toX as i32 + xstep, toY as i32, fromX as i32, fromY as i32);
|
||||
}
|
||||
// else we didn't find even black-white-black; no estimate is really possible
|
||||
f32::NAN
|
||||
|
||||
@@ -79,7 +79,13 @@ fn test_digits_only() {
|
||||
let test_data = "374833744734397449";
|
||||
let data = qrcode_encoder::encode(test_data, ErrorCorrectionLevel::H).expect("encode");
|
||||
let decode = crate::qrcode::decoder::qrcode_decoder::decode_bitmatrix(
|
||||
&data.getMatrix().as_ref().unwrap().clone().into(),
|
||||
&data
|
||||
.getMatrix()
|
||||
.as_ref()
|
||||
.unwrap()
|
||||
.clone()
|
||||
.try_into()
|
||||
.expect("convert"),
|
||||
)
|
||||
.expect("decode");
|
||||
assert_eq!(test_data, decode.getText());
|
||||
@@ -743,7 +749,7 @@ fn testAppendKanjiBytes() {
|
||||
#[test]
|
||||
fn testGenerateECBytes() {
|
||||
let dataBytes = &[32, 65, 205, 69, 41, 220, 46, 128, 236];
|
||||
let ecBytes = qrcode_encoder::generateECBytes(dataBytes, 17);
|
||||
let ecBytes = qrcode_encoder::generateECBytes(dataBytes, 17).expect("ecb");
|
||||
let expected = [
|
||||
42, 159, 74, 221, 244, 169, 239, 150, 138, 70, 237, 85, 224, 96, 74, 219, 61,
|
||||
];
|
||||
@@ -755,7 +761,7 @@ fn testGenerateECBytes() {
|
||||
let dataBytes = &[
|
||||
67, 70, 22, 38, 54, 70, 86, 102, 118, 134, 150, 166, 182, 198, 214,
|
||||
];
|
||||
let ecBytes = qrcode_encoder::generateECBytes(dataBytes, 18);
|
||||
let ecBytes = qrcode_encoder::generateECBytes(dataBytes, 18).expect("ecb");
|
||||
let expected = &[
|
||||
175, 80, 155, 64, 178, 45, 214, 233, 65, 209, 12, 155, 117, 31, 140, 214, 27, 187,
|
||||
];
|
||||
@@ -766,7 +772,7 @@ fn testGenerateECBytes() {
|
||||
}
|
||||
// High-order zero coefficient case.
|
||||
let dataBytes = &[32, 49, 205, 69, 42, 20, 0, 236, 17];
|
||||
let ecBytes = qrcode_encoder::generateECBytes(dataBytes, 17);
|
||||
let ecBytes = qrcode_encoder::generateECBytes(dataBytes, 17).expect("ecb");
|
||||
let expected = &[
|
||||
0, 3, 130, 179, 194, 0, 55, 211, 110, 79, 98, 72, 170, 96, 211, 137, 213,
|
||||
];
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
|
||||
use std::fmt;
|
||||
|
||||
use crate::common::BitMatrix;
|
||||
use crate::{common::BitMatrix, Exceptions};
|
||||
|
||||
/**
|
||||
* JAVAPORT: The original code was a 2D array of ints, but since it only ever gets assigned
|
||||
@@ -38,7 +38,6 @@ impl ByteMatrix {
|
||||
width,
|
||||
height,
|
||||
}
|
||||
// bytes = new byte[height][width];
|
||||
}
|
||||
|
||||
pub fn getHeight(&self) -> u32 {
|
||||
@@ -64,21 +63,14 @@ impl ByteMatrix {
|
||||
self.bytes[y as usize][x as usize] = value;
|
||||
}
|
||||
|
||||
// pub fn set(int x, int y, int value) {
|
||||
// bytes[y][x] = (byte) value;
|
||||
// }
|
||||
|
||||
pub fn set_bool(&mut self, x: u32, y: u32, value: bool) {
|
||||
self.bytes[y as usize][x as usize] = u8::from(value); //if value { 1 } else { 0 };
|
||||
}
|
||||
|
||||
pub fn clear(&mut self, value: u8) {
|
||||
for row in self.bytes.iter_mut() {
|
||||
*row = vec![value; row.len()];
|
||||
row.fill(value);
|
||||
}
|
||||
// for (byte[] aByte : bytes) {
|
||||
// Arrays.fill(aByte, value);
|
||||
// }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -86,27 +78,13 @@ impl fmt::Display for ByteMatrix {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
let mut result = String::with_capacity(2 * self.width as usize * self.height as usize + 2);
|
||||
for y in 0..self.height as usize {
|
||||
// for (int y = 0; y < height; ++y) {
|
||||
let bytesY = &self.bytes[y];
|
||||
for byte in bytesY.iter().take(self.width as usize) {
|
||||
// for x in 0..self.width as usize {
|
||||
// for (int x = 0; x < width; ++x) {
|
||||
match *byte {
|
||||
0 => result.push_str(" 0"),
|
||||
1 => result.push_str(" 1"),
|
||||
_ => result.push_str(" "),
|
||||
};
|
||||
// switch (bytesY[x]) {
|
||||
// case 0:
|
||||
// result.append(" 0");
|
||||
// break;
|
||||
// case 1:
|
||||
// result.append(" 1");
|
||||
// break;
|
||||
// default:
|
||||
// result.append(" ");
|
||||
// break;
|
||||
// }
|
||||
}
|
||||
result.push('\n');
|
||||
}
|
||||
@@ -114,16 +92,18 @@ impl fmt::Display for ByteMatrix {
|
||||
}
|
||||
}
|
||||
|
||||
impl From<ByteMatrix> for BitMatrix {
|
||||
fn from(bm: ByteMatrix) -> Self {
|
||||
let mut bit_matrix = BitMatrix::new(bm.getWidth(), bm.getHeight()).unwrap();
|
||||
for y in 0..bm.getHeight() {
|
||||
for x in 0..bm.getWidth() {
|
||||
if bm.get(x, y) > 0 {
|
||||
impl TryFrom<ByteMatrix> for BitMatrix {
|
||||
type Error = Exceptions;
|
||||
|
||||
fn try_from(value: ByteMatrix) -> Result<Self, Self::Error> {
|
||||
let mut bit_matrix = BitMatrix::new(value.getWidth(), value.getHeight())?;
|
||||
for y in 0..value.getHeight() {
|
||||
for x in 0..value.getWidth() {
|
||||
if value.get(x, y) > 0 {
|
||||
bit_matrix.set(x, y);
|
||||
}
|
||||
}
|
||||
}
|
||||
bit_matrix
|
||||
Ok(bit_matrix)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -49,10 +49,8 @@ pub fn applyMaskPenaltyRule2(matrix: &ByteMatrix) -> u32 {
|
||||
let width = matrix.getWidth();
|
||||
let height = matrix.getHeight();
|
||||
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 (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] {
|
||||
penalty += 1;
|
||||
@@ -73,9 +71,7 @@ pub fn applyMaskPenaltyRule3(matrix: &ByteMatrix) -> u32 {
|
||||
let width = matrix.getWidth();
|
||||
let height = matrix.getHeight();
|
||||
for y in 0..height as usize {
|
||||
// for (int y = 0; y < height; y++) {
|
||||
for x in 0..width as usize {
|
||||
// for (int x = 0; x < width; x++) {
|
||||
let arrayY = &array[y]; // We can at least optimize this access
|
||||
if x + 6 < width as usize
|
||||
&& arrayY[x] == 1
|
||||
@@ -113,7 +109,6 @@ pub fn isWhiteHorizontal(rowArray: &[u8], from: i32, to: u32) -> bool {
|
||||
return false;
|
||||
}
|
||||
for i in from..to as i32 {
|
||||
// for (int i = from; i < to; i++) {
|
||||
if rowArray[i as usize] == 1 {
|
||||
return false;
|
||||
}
|
||||
@@ -126,7 +121,6 @@ pub fn isWhiteVertical(array: &Vec<Vec<u8>>, col: u32, from: i32, to: u32) -> bo
|
||||
return false;
|
||||
}
|
||||
for i in from..to as i32 {
|
||||
// for (int i = from; i < to; i++) {
|
||||
if array[i as usize][col as usize] == 1 {
|
||||
return false;
|
||||
}
|
||||
@@ -144,12 +138,7 @@ pub fn applyMaskPenaltyRule4(matrix: &ByteMatrix) -> u32 {
|
||||
let width = matrix.getWidth();
|
||||
let height = matrix.getHeight();
|
||||
for val_y in array.iter().take(height as usize) {
|
||||
// for y in 0..height as usize {
|
||||
// for (int y = 0; y < height; y++) {
|
||||
// let arrayY = val_y;
|
||||
for val_x in val_y.iter().take(width as usize) {
|
||||
// for x in 0..width as usize {
|
||||
// for (int x = 0; x < width; x++) {
|
||||
if val_x == &1 {
|
||||
numDarkCells += 1;
|
||||
}
|
||||
@@ -242,12 +231,9 @@ fn applyMaskPenaltyRule1Internal(matrix: &ByteMatrix, isHorizontal: bool) -> u32
|
||||
};
|
||||
let array = matrix.getArray();
|
||||
for i in 0..iLimit as usize {
|
||||
// for (int i = 0; i < iLimit; i++) {
|
||||
let mut numSameBitCells = 0;
|
||||
// let prevBit = -1;
|
||||
let mut prevBit = 0;
|
||||
for j in 0..jLimit as usize {
|
||||
// for (int j = 0; j < jLimit; j++) {
|
||||
let bit = if isHorizontal {
|
||||
array[i][j]
|
||||
} else {
|
||||
|
||||
@@ -176,7 +176,6 @@ pub fn embedTypeInfo(
|
||||
.enumerate()
|
||||
.take(typeInfoBits.getSize())
|
||||
{
|
||||
// for (int i = 0; i < typeInfoBits.getSize(); ++i) {
|
||||
// Place bits in LSB to MSB order. LSB (least significant bit) is the last value in
|
||||
// "typeInfoBits".
|
||||
let bit = typeInfoBits.get(typeInfoBits.getSize() - 1 - i);
|
||||
@@ -215,9 +214,7 @@ pub fn maybeEmbedVersionInfo(version: &Version, matrix: &mut ByteMatrix) -> Resu
|
||||
|
||||
let mut bitIndex = 6 * 3 - 1; // It will decrease from 17 to 0.
|
||||
for i in 0..6 {
|
||||
// for (int i = 0; i < 6; ++i) {
|
||||
for j in 0..3 {
|
||||
// for (int j = 0; j < 3; ++j) {
|
||||
// Place bits in LSB (least significant bit) to MSB order.
|
||||
let bit = versionInfoBits.get(bitIndex);
|
||||
bitIndex = bitIndex.saturating_sub(1);
|
||||
@@ -250,7 +247,6 @@ pub fn embedDataBits(
|
||||
}
|
||||
while y >= 0 && y < matrix.getHeight() as i32 {
|
||||
for i in 0..2 {
|
||||
// for (int i = 0; i < 2; ++i) {
|
||||
let xx = x - i;
|
||||
// Skip the cell if it's not empty.
|
||||
if !isEmpty(matrix.get(xx as u32, y as u32)) {
|
||||
@@ -431,7 +427,6 @@ pub fn embedHorizontalSeparationPattern(
|
||||
matrix: &mut ByteMatrix,
|
||||
) -> Result<(), Exceptions> {
|
||||
for x in 0..8 {
|
||||
// for (int x = 0; x < 8; ++x) {
|
||||
if !isEmpty(matrix.get(xStart + x, yStart)) {
|
||||
return Err(Exceptions::WriterException(None));
|
||||
}
|
||||
@@ -446,10 +441,8 @@ pub fn embedVerticalSeparationPattern(
|
||||
matrix: &mut ByteMatrix,
|
||||
) -> Result<(), Exceptions> {
|
||||
for y in 0..7 {
|
||||
// for (int y = 0; y < 7; ++y) {
|
||||
if !isEmpty(matrix.get(xStart, yStart + y)) {
|
||||
return Err(Exceptions::WriterException(None));
|
||||
// throw new WriterException();
|
||||
}
|
||||
matrix.set(xStart, yStart + y, 0);
|
||||
}
|
||||
@@ -458,11 +451,7 @@ pub fn embedVerticalSeparationPattern(
|
||||
|
||||
pub fn embedPositionAdjustmentPattern(xStart: u32, yStart: u32, matrix: &mut ByteMatrix) {
|
||||
for (y, patternY) in POSITION_ADJUSTMENT_PATTERN.iter().enumerate() {
|
||||
// for y in 0..5 {
|
||||
// for (int y = 0; y < 5; ++y) {
|
||||
// let patternY = POSITION_ADJUSTMENT_PATTERN[y];
|
||||
for x in 0..5 {
|
||||
// for (int x = 0; x < 5; ++x) {
|
||||
matrix.set(xStart + x, yStart + y as u32, patternY[x as usize]);
|
||||
}
|
||||
}
|
||||
@@ -470,11 +459,7 @@ pub fn embedPositionAdjustmentPattern(xStart: u32, yStart: u32, matrix: &mut Byt
|
||||
|
||||
pub fn embedPositionDetectionPattern(xStart: u32, yStart: u32, matrix: &mut ByteMatrix) {
|
||||
for (y, patternY) in POSITION_DETECTION_PATTERN.iter().enumerate() {
|
||||
// for y in 0..7 {
|
||||
// for (int y = 0; y < 7; ++y) {
|
||||
// let patternY = POSITION_DETECTION_PATTERN[y];
|
||||
for x in 0..7 {
|
||||
// for (int x = 0; x < 7; ++x) {
|
||||
matrix.set(xStart + x, yStart + y as u32, patternY[x as usize]);
|
||||
}
|
||||
}
|
||||
@@ -523,10 +508,8 @@ pub fn maybeEmbedPositionAdjustmentPatterns(version: &Version, matrix: &mut Byte
|
||||
let index = version.getVersionNumber() - 1;
|
||||
let coordinates = POSITION_ADJUSTMENT_PATTERN_COORDINATE_TABLE[index as usize];
|
||||
for y in coordinates {
|
||||
// for (int y : coordinates) {
|
||||
if y >= 0 {
|
||||
for x in coordinates {
|
||||
// for (int x : coordinates) {
|
||||
if x >= 0 && isEmpty(matrix.get(x as u32, y as u32)) {
|
||||
// If the cell is unset, we embed the position adjustment pattern here.
|
||||
// -2 is necessary since the x/y coordinates point to the center of the pattern, not the
|
||||
|
||||
@@ -120,8 +120,6 @@ impl MinimalEncoder {
|
||||
encoders: ECIEncoderSet::new(stringToEncode, priorityCharset, None),
|
||||
ecLevel,
|
||||
}
|
||||
|
||||
// let encoders = ECIEncoderSet::new(&stringToEncode, priorityCharset, -1);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -157,7 +155,7 @@ impl MinimalEncoder {
|
||||
let result = self.encodeSpecificVersion(version)?;
|
||||
if !qrcode_encoder::willFit(
|
||||
result.getSize(),
|
||||
Self::getVersion(Self::getVersionSize(result.getVersion())),
|
||||
Self::getVersion(Self::getVersionSize(result.getVersion()))?,
|
||||
&self.ecLevel,
|
||||
) {
|
||||
return Err(Exceptions::WriterException(Some(format!(
|
||||
@@ -168,9 +166,9 @@ impl MinimalEncoder {
|
||||
} else {
|
||||
// compute minimal encoding trying the three version sizes.
|
||||
let versions = [
|
||||
Self::getVersion(VersionSize::SMALL),
|
||||
Self::getVersion(VersionSize::MEDIUM),
|
||||
Self::getVersion(VersionSize::LARGE),
|
||||
Self::getVersion(VersionSize::SMALL)?,
|
||||
Self::getVersion(VersionSize::MEDIUM)?,
|
||||
Self::getVersion(VersionSize::LARGE)?,
|
||||
];
|
||||
let results = [
|
||||
self.encodeSpecificVersion(versions[0])?,
|
||||
@@ -180,7 +178,6 @@ impl MinimalEncoder {
|
||||
let mut smallestSize = u32::MAX;
|
||||
let mut smallestRXingResult: i32 = -1;
|
||||
for i in 0..3 {
|
||||
// for (int i = 0; i < 3; i++) {
|
||||
let size = results[i].getSize();
|
||||
if qrcode_encoder::willFit(size, versions[i], &self.ecLevel) && size < smallestSize
|
||||
{
|
||||
@@ -198,40 +195,28 @@ impl MinimalEncoder {
|
||||
}
|
||||
|
||||
pub fn getVersionSize(version: VersionRef) -> VersionSize {
|
||||
if version.getVersionNumber() <= 9 {
|
||||
VersionSize::SMALL
|
||||
} else if version.getVersionNumber() <= 26 {
|
||||
VersionSize::MEDIUM
|
||||
} else {
|
||||
VersionSize::LARGE
|
||||
match version.getVersionNumber() {
|
||||
0..=9 => VersionSize::SMALL,
|
||||
10..=26 => VersionSize::MEDIUM,
|
||||
_ => VersionSize::LARGE,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn getVersion(versionSize: VersionSize) -> VersionRef {
|
||||
pub fn getVersion(versionSize: VersionSize) -> Result<VersionRef, Exceptions> {
|
||||
match versionSize {
|
||||
VersionSize::SMALL => Version::getVersionForNumber(9).expect("should always exist"),
|
||||
VersionSize::MEDIUM => Version::getVersionForNumber(26).expect("should always exist"),
|
||||
VersionSize::LARGE => Version::getVersionForNumber(40).expect("should always exist"),
|
||||
VersionSize::SMALL => Version::getVersionForNumber(9),
|
||||
VersionSize::MEDIUM => Version::getVersionForNumber(26),
|
||||
VersionSize::LARGE => Version::getVersionForNumber(40),
|
||||
}
|
||||
// switch (versionSize) {
|
||||
// case SMALL:
|
||||
// return Version.getVersionForNumber(9);
|
||||
// case MEDIUM:
|
||||
// return Version.getVersionForNumber(26);
|
||||
// case LARGE:
|
||||
// default:
|
||||
// return Version.getVersionForNumber(40);
|
||||
// }
|
||||
}
|
||||
|
||||
pub fn isNumeric(c: &str) -> bool {
|
||||
if c.len() == 1 {
|
||||
let ch = c.chars().next().unwrap();
|
||||
('0'..='9').contains(&ch)
|
||||
} else {
|
||||
false
|
||||
if let Some(ch) = c.chars().next() {
|
||||
return ('0'..='9').contains(&ch);
|
||||
}
|
||||
}
|
||||
// return c >= '0' && c <= '9';
|
||||
false
|
||||
}
|
||||
|
||||
pub fn isDoubleByteKanji(c: &str) -> bool {
|
||||
@@ -240,12 +225,11 @@ impl MinimalEncoder {
|
||||
|
||||
pub fn isAlphanumeric(c: &str) -> bool {
|
||||
if c.len() == 1 {
|
||||
let ch = c.chars().next().unwrap();
|
||||
qrcode_encoder::getAlphanumericCode(ch as u32) != -1
|
||||
} else {
|
||||
false
|
||||
if let Some(ch) = c.chars().next() {
|
||||
return qrcode_encoder::getAlphanumericCode(ch as u32) != -1;
|
||||
}
|
||||
}
|
||||
// return encoder::getAlphanumericCode(c as u8 as u32) != -1;
|
||||
false
|
||||
}
|
||||
|
||||
pub fn canEncode(&self, mode: &Mode, c: &str) -> bool {
|
||||
@@ -260,30 +244,15 @@ impl MinimalEncoder {
|
||||
}
|
||||
|
||||
pub fn getCompactedOrdinal(mode: Option<Mode>) -> Result<u32, Exceptions> {
|
||||
if mode.is_none() {
|
||||
return Ok(0);
|
||||
}
|
||||
match &mode.unwrap() {
|
||||
Mode::NUMERIC => Ok(2),
|
||||
Mode::ALPHANUMERIC => Ok(1),
|
||||
Mode::BYTE => Ok(3),
|
||||
Mode::KANJI => Ok(0),
|
||||
match mode {
|
||||
Some(Mode::NUMERIC) => Ok(2),
|
||||
Some(Mode::ALPHANUMERIC) => Ok(1),
|
||||
Some(Mode::BYTE) => Ok(3),
|
||||
Some(Mode::KANJI) | None => Ok(0),
|
||||
_ => Err(Exceptions::IllegalArgumentException(Some(format!(
|
||||
"Illegal mode {mode:?}"
|
||||
)))),
|
||||
}
|
||||
// switch (mode) {
|
||||
// case KANJI:
|
||||
// return 0;
|
||||
// case ALPHANUMERIC:
|
||||
// return 1;
|
||||
// case NUMERIC:
|
||||
// return 2;
|
||||
// case BYTE:
|
||||
// return 3;
|
||||
// default:
|
||||
// throw new IllegalStateException("Illegal mode " + mode);
|
||||
// }
|
||||
}
|
||||
|
||||
pub fn addEdge(
|
||||
@@ -291,17 +260,33 @@ impl MinimalEncoder {
|
||||
edges: &mut [Vec<Vec<Option<Rc<Edge>>>>],
|
||||
position: usize,
|
||||
edge: Option<Rc<Edge>>,
|
||||
) {
|
||||
let vertexIndex = position + edge.as_ref().unwrap().characterLength as usize;
|
||||
let modeEdges = &mut edges[vertexIndex][edge.as_ref().unwrap().charsetEncoderIndex];
|
||||
let modeOrdinal =
|
||||
Self::getCompactedOrdinal(Some(edge.as_ref().unwrap().mode)).expect("value") as usize;
|
||||
) -> Result<(), Exceptions> {
|
||||
let vertexIndex = position
|
||||
+ edge
|
||||
.as_ref()
|
||||
.ok_or(Exceptions::FormatException(None))?
|
||||
.characterLength as usize;
|
||||
let modeEdges = &mut edges[vertexIndex][edge
|
||||
.as_ref()
|
||||
.ok_or(Exceptions::FormatException(None))?
|
||||
.charsetEncoderIndex];
|
||||
let modeOrdinal = Self::getCompactedOrdinal(Some(
|
||||
edge.as_ref().ok_or(Exceptions::FormatException(None))?.mode,
|
||||
))? as usize;
|
||||
if modeEdges[modeOrdinal].is_none()
|
||||
|| modeEdges[modeOrdinal].as_ref().unwrap().cachedTotalSize
|
||||
> edge.as_ref().unwrap().cachedTotalSize
|
||||
|| modeEdges[modeOrdinal]
|
||||
.as_ref()
|
||||
.ok_or(Exceptions::FormatException(None))?
|
||||
.cachedTotalSize
|
||||
> edge
|
||||
.as_ref()
|
||||
.ok_or(Exceptions::FormatException(None))?
|
||||
.cachedTotalSize
|
||||
{
|
||||
modeEdges[modeOrdinal] = edge;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn addEdges(
|
||||
@@ -310,116 +295,162 @@ impl MinimalEncoder {
|
||||
edges: &mut [Vec<Vec<Option<Rc<Edge>>>>],
|
||||
from: usize,
|
||||
previous: Option<Rc<Edge>>,
|
||||
) {
|
||||
) -> Result<(), Exceptions> {
|
||||
let mut start = 0;
|
||||
let mut end = self.encoders.len();
|
||||
let priorityEncoderIndex = self.encoders.getPriorityEncoderIndex();
|
||||
if priorityEncoderIndex.is_some()
|
||||
&& self.encoders.canEncode(
|
||||
// self.stringToEncode.chars().nth(from as usize).unwrap() as i16,
|
||||
&self.stringToEncode[from],
|
||||
priorityEncoderIndex.unwrap(),
|
||||
)
|
||||
&& self
|
||||
.encoders
|
||||
.canEncode(
|
||||
&self.stringToEncode[from],
|
||||
priorityEncoderIndex.ok_or(Exceptions::FormatException(None))?,
|
||||
)
|
||||
.ok_or(Exceptions::FormatException(None))?
|
||||
{
|
||||
start = priorityEncoderIndex.unwrap();
|
||||
end = priorityEncoderIndex.unwrap() + 1;
|
||||
start = priorityEncoderIndex.ok_or(Exceptions::FormatException(None))?;
|
||||
end = priorityEncoderIndex.ok_or(Exceptions::FormatException(None))? + 1;
|
||||
}
|
||||
|
||||
for i in start..end {
|
||||
// for (int i = start; i < end; i++) {
|
||||
if self
|
||||
.encoders
|
||||
.canEncode(self.stringToEncode.get(from).unwrap(), i)
|
||||
.canEncode(
|
||||
self.stringToEncode
|
||||
.get(from)
|
||||
.ok_or(Exceptions::IndexOutOfBoundsException(None))?,
|
||||
i,
|
||||
)
|
||||
.ok_or(Exceptions::FormatException(None))?
|
||||
{
|
||||
self.addEdge(
|
||||
edges,
|
||||
from,
|
||||
Some(Rc::new(Edge::new(
|
||||
Mode::BYTE,
|
||||
Some(Rc::new(
|
||||
Edge::new(
|
||||
Mode::BYTE,
|
||||
from,
|
||||
i,
|
||||
1,
|
||||
previous.clone(),
|
||||
version,
|
||||
self.encoders.clone(),
|
||||
self.stringToEncode.clone(),
|
||||
)
|
||||
.ok_or(Exceptions::WriterException(None))?,
|
||||
)),
|
||||
)?;
|
||||
}
|
||||
}
|
||||
|
||||
if self.canEncode(
|
||||
&Mode::KANJI,
|
||||
self.stringToEncode
|
||||
.get(from)
|
||||
.ok_or(Exceptions::FormatException(None))?,
|
||||
) {
|
||||
self.addEdge(
|
||||
edges,
|
||||
from,
|
||||
Some(Rc::new(
|
||||
Edge::new(
|
||||
Mode::KANJI,
|
||||
from,
|
||||
i,
|
||||
0,
|
||||
1,
|
||||
previous.clone(),
|
||||
version,
|
||||
self.encoders.clone(),
|
||||
self.stringToEncode.clone(),
|
||||
))),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
if self.canEncode(&Mode::KANJI, self.stringToEncode.get(from).unwrap()) {
|
||||
self.addEdge(
|
||||
edges,
|
||||
from,
|
||||
Some(Rc::new(Edge::new(
|
||||
Mode::KANJI,
|
||||
from,
|
||||
0,
|
||||
1,
|
||||
previous.clone(),
|
||||
version,
|
||||
self.encoders.clone(),
|
||||
self.stringToEncode.clone(),
|
||||
))),
|
||||
);
|
||||
)
|
||||
.ok_or(Exceptions::WriterException(None))?,
|
||||
)),
|
||||
)?;
|
||||
}
|
||||
|
||||
let inputLength = self.stringToEncode.len();
|
||||
if self.canEncode(&Mode::ALPHANUMERIC, self.stringToEncode.get(from).unwrap()) {
|
||||
if self.canEncode(
|
||||
&Mode::ALPHANUMERIC,
|
||||
self.stringToEncode
|
||||
.get(from)
|
||||
.ok_or(Exceptions::IndexOutOfBoundsException(None))?,
|
||||
) {
|
||||
self.addEdge(
|
||||
edges,
|
||||
from,
|
||||
Some(Rc::new(Edge::new(
|
||||
Mode::ALPHANUMERIC,
|
||||
from,
|
||||
0,
|
||||
if from + 1 >= inputLength
|
||||
|| !self.canEncode(
|
||||
&Mode::ALPHANUMERIC,
|
||||
self.stringToEncode.get(from + 1).unwrap(),
|
||||
)
|
||||
{
|
||||
1
|
||||
} else {
|
||||
2
|
||||
},
|
||||
previous.clone(),
|
||||
version,
|
||||
self.encoders.clone(),
|
||||
self.stringToEncode.clone(),
|
||||
))),
|
||||
);
|
||||
Some(Rc::new(
|
||||
Edge::new(
|
||||
Mode::ALPHANUMERIC,
|
||||
from,
|
||||
0,
|
||||
if from + 1 >= inputLength
|
||||
|| !self.canEncode(
|
||||
&Mode::ALPHANUMERIC,
|
||||
self.stringToEncode
|
||||
.get(from + 1)
|
||||
.ok_or(Exceptions::IndexOutOfBoundsException(None))?,
|
||||
)
|
||||
{
|
||||
1
|
||||
} else {
|
||||
2
|
||||
},
|
||||
previous.clone(),
|
||||
version,
|
||||
self.encoders.clone(),
|
||||
self.stringToEncode.clone(),
|
||||
)
|
||||
.ok_or(Exceptions::WriterException(None))?,
|
||||
)),
|
||||
)?;
|
||||
}
|
||||
|
||||
if self.canEncode(&Mode::NUMERIC, self.stringToEncode.get(from).unwrap()) {
|
||||
if self.canEncode(
|
||||
&Mode::NUMERIC,
|
||||
self.stringToEncode
|
||||
.get(from)
|
||||
.ok_or(Exceptions::IndexOutOfBoundsException(None))?,
|
||||
) {
|
||||
self.addEdge(
|
||||
edges,
|
||||
from,
|
||||
Some(Rc::new(Edge::new(
|
||||
Mode::NUMERIC,
|
||||
from,
|
||||
0,
|
||||
if from + 1 >= inputLength
|
||||
|| !self
|
||||
.canEncode(&Mode::NUMERIC, self.stringToEncode.get(from + 1).unwrap())
|
||||
{
|
||||
1
|
||||
} else if from + 2 >= inputLength
|
||||
|| !self
|
||||
.canEncode(&Mode::NUMERIC, self.stringToEncode.get(from + 2).unwrap())
|
||||
{
|
||||
2
|
||||
} else {
|
||||
3
|
||||
},
|
||||
previous,
|
||||
version,
|
||||
self.encoders.clone(),
|
||||
self.stringToEncode.clone(),
|
||||
))),
|
||||
);
|
||||
Some(Rc::new(
|
||||
Edge::new(
|
||||
Mode::NUMERIC,
|
||||
from,
|
||||
0,
|
||||
if from + 1 >= inputLength
|
||||
|| !self.canEncode(
|
||||
&Mode::NUMERIC,
|
||||
self.stringToEncode
|
||||
.get(from + 1)
|
||||
.ok_or(Exceptions::IndexOutOfBoundsException(None))?,
|
||||
)
|
||||
{
|
||||
1
|
||||
} else if from + 2 >= inputLength
|
||||
|| !self.canEncode(
|
||||
&Mode::NUMERIC,
|
||||
self.stringToEncode
|
||||
.get(from + 2)
|
||||
.ok_or(Exceptions::IndexOutOfBoundsException(None))?,
|
||||
)
|
||||
{
|
||||
2
|
||||
} else {
|
||||
3
|
||||
},
|
||||
previous,
|
||||
version,
|
||||
self.encoders.clone(),
|
||||
self.stringToEncode.clone(),
|
||||
)
|
||||
.ok_or(Exceptions::WriterException(None))?,
|
||||
)),
|
||||
)?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
pub fn encodeSpecificVersion(
|
||||
&self,
|
||||
@@ -544,18 +575,15 @@ impl MinimalEncoder {
|
||||
|
||||
// The last dimension in the array below encodes the 4 modes KANJI, ALPHANUMERIC, NUMERIC and BYTE via the
|
||||
// function getCompactedOrdinal(Mode)
|
||||
let mut edges = vec![vec![vec![None; 4]; self.encoders.len()]; inputLength + 1]; //new Edge[inputLength + 1][encoders.length()][4];
|
||||
self.addEdges(version, &mut edges, 0, None);
|
||||
let mut edges = vec![vec![vec![None; 4]; self.encoders.len()]; inputLength + 1];
|
||||
self.addEdges(version, &mut edges, 0, None)?;
|
||||
|
||||
for i in 1..=inputLength {
|
||||
// for (int i = 1; i <= inputLength; i++) {
|
||||
for j in 0..self.encoders.len() {
|
||||
// for (int j = 0; j < encoders.length(); j++) {
|
||||
for k in 0..4 {
|
||||
// for (int k = 0; k < 4; k++) {
|
||||
if edges[i][j][k].is_some() && i < inputLength {
|
||||
let e = edges[i][j][k].clone();
|
||||
self.addEdges(version, &mut edges, i, e);
|
||||
self.addEdges(version, &mut edges, i, e)?;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -564,11 +592,8 @@ impl MinimalEncoder {
|
||||
let mut minimalK = None;
|
||||
let mut minimalSize = u32::MAX;
|
||||
for j in 0..self.encoders.len() {
|
||||
// for (int j = 0; j < encoders.length(); j++) {
|
||||
for k in 0..4 {
|
||||
// for (int k = 0; k < 4; k++) {
|
||||
if edges[inputLength][j][k].is_some() {
|
||||
let edge = edges[inputLength][j][k].as_ref().unwrap();
|
||||
if let Some(edge) = &edges[inputLength][j][k] {
|
||||
if edge.cachedTotalSize < minimalSize {
|
||||
minimalSize = edge.cachedTotalSize;
|
||||
minimalJ = Some(j);
|
||||
@@ -577,26 +602,29 @@ impl MinimalEncoder {
|
||||
}
|
||||
}
|
||||
}
|
||||
if minimalJ.is_none() {
|
||||
return Err(Exceptions::WriterException(Some(format!(
|
||||
|
||||
if let Some((minJ, minK)) = minimalJ.zip(minimalK) {
|
||||
Ok(RXingResultList::new(
|
||||
version,
|
||||
edges[inputLength][minJ][minK]
|
||||
.as_ref()
|
||||
.ok_or(Exceptions::WriterException(None))?
|
||||
.clone(),
|
||||
self.isGS1,
|
||||
&self.ecLevel,
|
||||
self.encoders.clone(),
|
||||
self.stringToEncode.clone(),
|
||||
)
|
||||
.ok_or(Exceptions::WriterException(None))?)
|
||||
} else {
|
||||
Err(Exceptions::WriterException(Some(format!(
|
||||
r#"Internal error: failed to encode "{}"#,
|
||||
self.stringToEncode
|
||||
.iter()
|
||||
.map(String::from)
|
||||
.collect::<String>() //fold("", |acc,x| [acc,&x].concat())
|
||||
))));
|
||||
.collect::<String>()
|
||||
))))
|
||||
}
|
||||
Ok(RXingResultList::new(
|
||||
version,
|
||||
edges[inputLength][minimalJ.unwrap()][minimalK.unwrap()]
|
||||
.as_ref()
|
||||
.unwrap()
|
||||
.clone(),
|
||||
self.isGS1,
|
||||
&self.ecLevel,
|
||||
self.encoders.clone(),
|
||||
self.stringToEncode.clone(),
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -621,13 +649,14 @@ impl Edge {
|
||||
version: VersionRef,
|
||||
encoders: ECIEncoderSet,
|
||||
stringToEncode: Vec<String>,
|
||||
) -> Self {
|
||||
) -> Option<Self> {
|
||||
let nci = if mode == Mode::BYTE || previous.is_none() {
|
||||
charsetEncoderIndex
|
||||
} else {
|
||||
previous.as_ref().unwrap().charsetEncoderIndex
|
||||
previous.as_ref()?.charsetEncoderIndex
|
||||
};
|
||||
Self {
|
||||
|
||||
Some(Self {
|
||||
mode,
|
||||
fromPosition,
|
||||
charsetEncoderIndex: nci,
|
||||
@@ -636,16 +665,16 @@ impl Edge {
|
||||
_stringToEncode: stringToEncode.clone(),
|
||||
cachedTotalSize: {
|
||||
let mut size = if previous.is_some() {
|
||||
previous.as_ref().unwrap().cachedTotalSize
|
||||
previous.as_ref()?.cachedTotalSize
|
||||
} else {
|
||||
0
|
||||
};
|
||||
|
||||
let needECI = mode == Mode::BYTE &&
|
||||
(previous.is_none() && nci != 0) || // at the beginning and charset is not ISO-8859-1
|
||||
(previous.is_some() && nci != previous.as_ref().unwrap().charsetEncoderIndex);
|
||||
(previous.is_some() && nci != previous.as_ref()?.charsetEncoderIndex);
|
||||
|
||||
if previous.is_none() || mode != previous.as_ref().unwrap().mode || needECI {
|
||||
if previous.is_none() || mode != previous.as_ref()?.mode || needECI {
|
||||
size += 4 + mode.getCharacterCountBits(version) as u32;
|
||||
}
|
||||
match mode {
|
||||
@@ -666,14 +695,7 @@ impl Edge {
|
||||
.take(characterLength as usize)
|
||||
.map(String::from)
|
||||
.collect();
|
||||
size += 8 * encoders.encode_string(&n, charsetEncoderIndex).len() as u32;
|
||||
// size += 8 * encoders
|
||||
// .encode_string(
|
||||
// &stringToEncode[fromPosition as usize
|
||||
// ..(fromPosition + characterLength as usize)],
|
||||
// charsetEncoderIndex as usize,
|
||||
// )
|
||||
// .len() as u32;
|
||||
size += 8 * encoders.encode_string(&n, charsetEncoderIndex)?.len() as u32;
|
||||
if needECI {
|
||||
size += 4 + 8; // the ECI assignment numbers for ISO-8859-x, UTF-8 and UTF-16 are all 8 bit long
|
||||
}
|
||||
@@ -681,63 +703,10 @@ impl Edge {
|
||||
Mode::KANJI => size += 13,
|
||||
_ => {}
|
||||
}
|
||||
// switch (mode) {
|
||||
// case KANJI:
|
||||
// size += 13;
|
||||
// break;
|
||||
// case ALPHANUMERIC:
|
||||
// size += characterLength == 1 ? 6 : 11;
|
||||
// break;
|
||||
// case NUMERIC:
|
||||
// size += characterLength == 1 ? 4 : characterLength == 2 ? 7 : 10;
|
||||
// break;
|
||||
// case BYTE:
|
||||
// size += 8 * encoders.encode(stringToEncode.substring(fromPosition, fromPosition + characterLength),
|
||||
// charsetEncoderIndex).length;
|
||||
// if (needECI) {
|
||||
// size += 4 + 8; // the ECI assignment numbers for ISO-8859-x, UTF-8 and UTF-16 are all 8 bit long
|
||||
// }
|
||||
// break;
|
||||
// }
|
||||
size
|
||||
},
|
||||
_encoders: encoders,
|
||||
}
|
||||
// this.mode = mode;
|
||||
// this.fromPosition = fromPosition;
|
||||
// this.charsetEncoderIndex = mode == Mode.BYTE || previous == null ? charsetEncoderIndex :
|
||||
// previous.charsetEncoderIndex; // inherit the encoding if not of type BYTE
|
||||
// this.characterLength = characterLength;
|
||||
// this.previous = previous;
|
||||
|
||||
// int size = previous != null ? previous.cachedTotalSize : 0;
|
||||
|
||||
// boolean needECI = mode == Mode.BYTE &&
|
||||
// (previous == null && this.charsetEncoderIndex != 0) || // at the beginning and charset is not ISO-8859-1
|
||||
// (previous != null && this.charsetEncoderIndex != previous.charsetEncoderIndex);
|
||||
|
||||
// if (previous == null || mode != previous.mode || needECI) {
|
||||
// size += 4 + mode.getCharacterCountBits(version);
|
||||
// }
|
||||
// switch (mode) {
|
||||
// case KANJI:
|
||||
// size += 13;
|
||||
// break;
|
||||
// case ALPHANUMERIC:
|
||||
// size += characterLength == 1 ? 6 : 11;
|
||||
// break;
|
||||
// case NUMERIC:
|
||||
// size += characterLength == 1 ? 4 : characterLength == 2 ? 7 : 10;
|
||||
// break;
|
||||
// case BYTE:
|
||||
// size += 8 * encoders.encode(stringToEncode.substring(fromPosition, fromPosition + characterLength),
|
||||
// charsetEncoderIndex).length;
|
||||
// if (needECI) {
|
||||
// size += 4 + 8; // the ECI assignment numbers for ISO-8859-x, UTF-8 and UTF-16 are all 8 bit long
|
||||
// }
|
||||
// break;
|
||||
// }
|
||||
// cachedTotalSize = size;
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -754,32 +723,29 @@ impl RXingResultList {
|
||||
ecLevel: &ErrorCorrectionLevel,
|
||||
encoders: ECIEncoderSet,
|
||||
stringToEncode: Vec<String>,
|
||||
) -> Self {
|
||||
) -> Option<Self> {
|
||||
let mut length = 0;
|
||||
let mut current = Some(solution);
|
||||
let mut containsECI = false;
|
||||
let mut list = Vec::new();
|
||||
|
||||
while current.is_some() {
|
||||
length += current.as_ref().unwrap().characterLength;
|
||||
let previous = current.as_ref().unwrap().previous.clone();
|
||||
while let Some(loop_current) = ¤t {
|
||||
length += loop_current.characterLength;
|
||||
let previous = current.as_ref()?.previous.clone();
|
||||
|
||||
let needECI = current.as_ref().unwrap().mode == Mode::BYTE &&
|
||||
(previous.is_none() && current.as_ref().unwrap().charsetEncoderIndex != 0) || // at the beginning and charset is not ISO-8859-1
|
||||
(previous.is_some() && current.as_ref().unwrap().charsetEncoderIndex != previous.as_ref().unwrap().charsetEncoderIndex);
|
||||
let needECI = loop_current.mode == Mode::BYTE &&
|
||||
(previous.is_none() && loop_current.charsetEncoderIndex != 0) || // at the beginning and charset is not ISO-8859-1
|
||||
(previous.is_some() && loop_current.charsetEncoderIndex != previous.as_ref()?.charsetEncoderIndex);
|
||||
|
||||
if needECI {
|
||||
containsECI = true;
|
||||
}
|
||||
|
||||
if previous.is_none()
|
||||
|| previous.as_ref().unwrap().mode != current.as_ref().unwrap().mode
|
||||
|| needECI
|
||||
{
|
||||
if previous.is_none() || previous.as_ref()?.mode != loop_current.mode || needECI {
|
||||
list.push(RXingResultNode::new(
|
||||
current.as_ref().unwrap().mode,
|
||||
current.as_ref().unwrap().fromPosition,
|
||||
current.as_ref().unwrap().charsetEncoderIndex,
|
||||
loop_current.mode,
|
||||
loop_current.fromPosition,
|
||||
loop_current.charsetEncoderIndex,
|
||||
length,
|
||||
encoders.clone(),
|
||||
stringToEncode.clone(),
|
||||
@@ -791,8 +757,8 @@ impl RXingResultList {
|
||||
if needECI {
|
||||
list.push(RXingResultNode::new(
|
||||
Mode::ECI,
|
||||
current.as_ref().unwrap().fromPosition,
|
||||
current.as_ref().unwrap().charsetEncoderIndex,
|
||||
loop_current.fromPosition,
|
||||
loop_current.charsetEncoderIndex,
|
||||
0,
|
||||
encoders.clone(),
|
||||
stringToEncode.clone(),
|
||||
@@ -806,7 +772,6 @@ impl RXingResultList {
|
||||
// If there is no ECI at the beginning then we put an ECI to the default charset (ISO-8859-1)
|
||||
if isGS1 {
|
||||
if let Some(first) = list.get(0) {
|
||||
// if first != null && first.mode != Mode.ECI && containsECI {
|
||||
if first.mode != Mode::ECI && containsECI {
|
||||
// prepend a default character set ECI
|
||||
list.push(RXingResultNode::new(
|
||||
@@ -820,37 +785,30 @@ 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 {
|
||||
list.insert(
|
||||
if first.as_ref().unwrap().mode != Mode::ECI {
|
||||
//first
|
||||
list.len()
|
||||
} else {
|
||||
//second
|
||||
list.len() - 1
|
||||
},
|
||||
RXingResultNode::new(
|
||||
Mode::FNC1_FIRST_POSITION,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
encoders,
|
||||
stringToEncode,
|
||||
version,
|
||||
),
|
||||
);
|
||||
// list.push(RXingResultNode::new(
|
||||
// Mode::FNC1_FIRST_POSITION,
|
||||
// 0,
|
||||
// 0,
|
||||
// 0,
|
||||
// encoders.clone(),
|
||||
// stringToEncode.clone(),
|
||||
// version,
|
||||
// ));
|
||||
|
||||
if let Some(first) = list.get(0) {
|
||||
// prepend or insert a FNC1_FIRST_POSITION after the ECI (if any)
|
||||
if first.mode != Mode::ECI {
|
||||
//&& containsECI {
|
||||
list.insert(
|
||||
if first.mode != Mode::ECI {
|
||||
//first
|
||||
list.len()
|
||||
} else {
|
||||
//second
|
||||
list.len() - 1
|
||||
},
|
||||
RXingResultNode::new(
|
||||
Mode::FNC1_FIRST_POSITION,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
encoders,
|
||||
stringToEncode,
|
||||
version,
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -861,29 +819,13 @@ impl RXingResultList {
|
||||
VersionSize::MEDIUM => (10, 26),
|
||||
_ => (27, 40),
|
||||
};
|
||||
// let lowerLimit;
|
||||
// let upperLimit;
|
||||
// switch (getVersionSize(version)) {
|
||||
// case SMALL:
|
||||
// lowerLimit = 1;
|
||||
// upperLimit = 9;
|
||||
// break;
|
||||
// case MEDIUM:
|
||||
// lowerLimit = 10;
|
||||
// upperLimit = 26;
|
||||
// break;
|
||||
// case LARGE:
|
||||
// default:
|
||||
// lowerLimit = 27;
|
||||
// upperLimit = 40;
|
||||
// break;
|
||||
// }
|
||||
|
||||
let size = Self::internal_static_get_size(version, &list);
|
||||
// increase version if needed
|
||||
while versionNumber < upperLimit
|
||||
&& !qrcode_encoder::willFit(
|
||||
size,
|
||||
Version::getVersionForNumber(versionNumber).unwrap(),
|
||||
Version::getVersionForNumber(versionNumber).ok()?,
|
||||
ecLevel,
|
||||
)
|
||||
{
|
||||
@@ -893,15 +835,15 @@ impl RXingResultList {
|
||||
while versionNumber > lowerLimit
|
||||
&& qrcode_encoder::willFit(
|
||||
size,
|
||||
Version::getVersionForNumber(versionNumber - 1).unwrap(),
|
||||
Version::getVersionForNumber(versionNumber - 1).ok()?,
|
||||
ecLevel,
|
||||
)
|
||||
{
|
||||
versionNumber -= 1;
|
||||
}
|
||||
let version = Version::getVersionForNumber(versionNumber).unwrap();
|
||||
let version = Version::getVersionForNumber(versionNumber).ok()?;
|
||||
list.reverse();
|
||||
Self { list, version }
|
||||
Some(Self { list, version })
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -912,18 +854,15 @@ impl RXingResultList {
|
||||
}
|
||||
|
||||
fn getSizeLocal(&self, version: VersionRef) -> u32 {
|
||||
let mut result = 0;
|
||||
for resultNode in &self.list {
|
||||
result += resultNode.getSize(version);
|
||||
}
|
||||
let result = self
|
||||
.list
|
||||
.iter()
|
||||
.fold(0, |acc, node| acc + node.getSize(version));
|
||||
result
|
||||
}
|
||||
|
||||
fn internal_static_get_size(version: VersionRef, list: &Vec<RXingResultNode>) -> u32 {
|
||||
let mut result = 0;
|
||||
for resultNode in list {
|
||||
result += resultNode.getSize(version);
|
||||
}
|
||||
let result = list.iter().fold(0, |acc, node| acc + node.getSize(version));
|
||||
result
|
||||
}
|
||||
|
||||
@@ -1050,9 +989,6 @@ impl RXingResultNode {
|
||||
if self.mode == Mode::BYTE {
|
||||
self.encoders
|
||||
.encode_string(
|
||||
// &self.stringToEncode[self.fromPosition as usize
|
||||
// ..(self.fromPosition + self.characterLength as usize)],
|
||||
// self.stringToEncode.get(self.fromPosition).unwrap(),
|
||||
&(self
|
||||
.stringToEncode
|
||||
.iter()
|
||||
@@ -1062,6 +998,7 @@ impl RXingResultNode {
|
||||
.collect::<String>()),
|
||||
self.charsetEncoderIndex,
|
||||
)
|
||||
.unwrap_or_default()
|
||||
.len() as u32
|
||||
} else {
|
||||
self.characterLength
|
||||
@@ -1085,18 +1022,18 @@ impl RXingResultNode {
|
||||
} else if self.characterLength > 0 {
|
||||
// append data
|
||||
qrcode_encoder::appendBytes(
|
||||
// &self.stringToEncode[self.fromPosition as usize
|
||||
// ..(self.fromPosition + self.characterLength as usize)],
|
||||
&(self
|
||||
.stringToEncode
|
||||
.iter()
|
||||
.skip(self.fromPosition)
|
||||
.take(self.characterLength as usize)
|
||||
.map(|s| s.as_str())
|
||||
.collect::<String>()), //self.stringToEncode.get(self.fromPosition).unwrap(),
|
||||
.collect::<String>()),
|
||||
self.mode,
|
||||
bits,
|
||||
self.encoders.getCharset(self.charsetEncoderIndex),
|
||||
self.encoders
|
||||
.getCharset(self.charsetEncoderIndex)
|
||||
.ok_or(Exceptions::WriterException(None))?,
|
||||
)?;
|
||||
}
|
||||
Ok(())
|
||||
@@ -1104,12 +1041,11 @@ impl RXingResultNode {
|
||||
|
||||
fn makePrintable(s: &str) -> String {
|
||||
let mut result = String::new();
|
||||
for i in 0..s.chars().count() {
|
||||
// for (int i = 0; i < s.length(); i++) {
|
||||
if (s.chars().nth(i).unwrap() as u32) < 32 || (s.chars().nth(i).unwrap() as u32) > 126 {
|
||||
for ch in s.chars() {
|
||||
if (ch as u32) < 32 || (ch as u32) > 126 {
|
||||
result.push('.');
|
||||
} else {
|
||||
result.push(s.chars().nth(i).unwrap());
|
||||
result.push(ch);
|
||||
}
|
||||
}
|
||||
result
|
||||
@@ -1122,7 +1058,12 @@ impl fmt::Display for RXingResultNode {
|
||||
result.push_str(&format!("{:?}", self.mode));
|
||||
result.push('(');
|
||||
if self.mode == Mode::ECI {
|
||||
result.push_str(self.encoders.getCharset(self.charsetEncoderIndex).name());
|
||||
result.push_str(
|
||||
self.encoders
|
||||
.getCharset(self.charsetEncoderIndex)
|
||||
.ok_or(fmt::Error)?
|
||||
.name(),
|
||||
);
|
||||
} else {
|
||||
let sub_string: String = self
|
||||
.stringToEncode
|
||||
|
||||
@@ -102,21 +102,21 @@ impl fmt::Display for QRCode {
|
||||
result.push_str("<<\n");
|
||||
result.push_str(" mode: ");
|
||||
if self.mode.is_some() {
|
||||
result.push_str(&format!("{:?}", self.mode.as_ref().unwrap()));
|
||||
result.push_str(&format!("{:?}", self.mode.as_ref().ok_or(fmt::Error)?));
|
||||
} 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()));
|
||||
result.push_str(&format!("{:?}", self.ecLevel.as_ref().ok_or(fmt::Error)?));
|
||||
} 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()));
|
||||
result.push_str(&format!("{}", self.version.as_ref().ok_or(fmt::Error)?));
|
||||
} else {
|
||||
result.push_str("null");
|
||||
}
|
||||
@@ -127,7 +127,7 @@ impl fmt::Display for QRCode {
|
||||
} else {
|
||||
result.push_str("\n matrix:\n");
|
||||
if self.matrix.is_some() {
|
||||
result.push_str(&format!("{}", self.matrix.as_ref().unwrap()));
|
||||
result.push_str(&format!("{}", self.matrix.as_ref().ok_or(fmt::Error)?));
|
||||
} else {
|
||||
result.push_str("null");
|
||||
}
|
||||
|
||||
@@ -79,16 +79,15 @@ pub fn encode_with_hints(
|
||||
let mut header_and_data_bits;
|
||||
let mode;
|
||||
|
||||
let has_gs1_format_hint = hints.contains_key(&EncodeHintType::GS1_FORMAT)
|
||||
&& if let EncodeHintValue::Gs1Format(v) = hints.get(&EncodeHintType::GS1_FORMAT).unwrap() {
|
||||
*v
|
||||
} else {
|
||||
false
|
||||
};
|
||||
let has_compaction_hint = hints.contains_key(&EncodeHintType::QR_COMPACT)
|
||||
&& if let EncodeHintValue::QrCompact(v) = hints.get(&EncodeHintType::QR_COMPACT).unwrap() {
|
||||
if let Ok(vb) = v.parse::<bool>() {
|
||||
vb
|
||||
let has_gs1_format_hint = matches!(
|
||||
hints.get(&EncodeHintType::GS1_FORMAT),
|
||||
Some(EncodeHintValue::Gs1Format(true))
|
||||
);
|
||||
|
||||
let has_compaction_hint =
|
||||
if let Some(EncodeHintValue::QrCompact(vb)) = hints.get(&EncodeHintType::QR_COMPACT) {
|
||||
if let Ok(v) = vb.parse::<bool>() {
|
||||
v
|
||||
} else {
|
||||
false
|
||||
}
|
||||
@@ -100,11 +99,12 @@ pub fn encode_with_hints(
|
||||
let mut encoding = None; //DEFAULT_BYTE_MODE_ENCODING;
|
||||
let mut has_encoding_hint = hints.contains_key(&EncodeHintType::CHARACTER_SET);
|
||||
if has_encoding_hint {
|
||||
if let EncodeHintValue::CharacterSet(v) = hints.get(&EncodeHintType::CHARACTER_SET).unwrap()
|
||||
{
|
||||
encoding = Some(encoding::label::encoding_from_whatwg_label(v).unwrap())
|
||||
if let Some(EncodeHintValue::CharacterSet(v)) = hints.get(&EncodeHintType::CHARACTER_SET) {
|
||||
encoding = Some(
|
||||
encoding::label::encoding_from_whatwg_label(v)
|
||||
.ok_or(Exceptions::WriterException(None))?,
|
||||
)
|
||||
}
|
||||
// encoding = encoding::label::encoding_from_whatwg_label(hints.get(&EncodeHintType::CHARACTER_SET).unwrap());
|
||||
}
|
||||
|
||||
if has_compaction_hint {
|
||||
@@ -146,9 +146,8 @@ pub fn encode_with_hints(
|
||||
|
||||
// Append ECI segment if applicable
|
||||
if mode == Mode::BYTE && has_encoding_hint {
|
||||
let eci = CharacterSetECI::getCharacterSetECI(encoding);
|
||||
if eci.is_some() {
|
||||
appendECI(&eci.unwrap(), &mut header_bits)?;
|
||||
if let Some(eci) = CharacterSetECI::getCharacterSetECI(encoding) {
|
||||
appendECI(&eci, &mut header_bits)?;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -167,8 +166,8 @@ pub fn encode_with_hints(
|
||||
appendBytes(content, mode, &mut data_bits, encoding)?;
|
||||
|
||||
if hints.contains_key(&EncodeHintType::QR_VERSION) {
|
||||
let versionNumber = if let EncodeHintValue::QrVersion(v) =
|
||||
hints.get(&EncodeHintType::QR_VERSION).unwrap()
|
||||
let versionNumber = if let Some(EncodeHintValue::QrVersion(v)) =
|
||||
hints.get(&EncodeHintType::QR_VERSION)
|
||||
{
|
||||
if let Ok(vb) = v.parse::<u32>() {
|
||||
vb
|
||||
@@ -178,7 +177,7 @@ pub fn encode_with_hints(
|
||||
} else {
|
||||
0
|
||||
};
|
||||
// let versionNumber = Integer.parseInt(hints.get(&EncodeHintType::QR_VERSION).unwrap()());
|
||||
|
||||
version = Version::getVersionForNumber(versionNumber)?;
|
||||
let bitsNeeded = calculateBitsNeeded(mode, &header_bits, &data_bits, version);
|
||||
if !willFit(bitsNeeded, version, &ec_level) {
|
||||
@@ -229,19 +228,13 @@ pub fn encode_with_hints(
|
||||
|
||||
// Enable manual selection of the pattern to be used via hint
|
||||
let mut mask_pattern = -1;
|
||||
if hints.contains_key(&EncodeHintType::QR_MASK_PATTERN) {
|
||||
let hint_mask_pattern = if let EncodeHintValue::QrMaskPattern(v) =
|
||||
hints.get(&EncodeHintType::QR_MASK_PATTERN).unwrap()
|
||||
{
|
||||
if let Ok(vb) = v.parse::<i32>() {
|
||||
vb
|
||||
} else {
|
||||
-1
|
||||
}
|
||||
if let Some(EncodeHintValue::QrMaskPattern(v)) = hints.get(&EncodeHintType::QR_MASK_PATTERN) {
|
||||
let hint_mask_pattern = if let Ok(vb) = v.parse::<i32>() {
|
||||
vb
|
||||
} else {
|
||||
-1
|
||||
};
|
||||
// let hintMaskPattern = Integer.parseInt(hints.get(&EncodeHintType::QR_MASK_PATTERN).unwrap());
|
||||
|
||||
mask_pattern = if QRCode::isValidMaskPattern(hint_mask_pattern) {
|
||||
hint_mask_pattern
|
||||
} else {
|
||||
@@ -322,15 +315,12 @@ pub fn chooseMode(content: &str) -> Mode {
|
||||
*/
|
||||
fn chooseModeWithEncoding(content: &str, encoding: EncodingRef) -> Mode {
|
||||
if SHIFT_JIS_CHARSET.name() == encoding.name() && isOnlyDoubleByteKanji(content) {
|
||||
// if (StringUtils.SHIFT_JIS_CHARSET.equals(encoding) && isOnlyDoubleByteKanji(content)) {
|
||||
// Choose Kanji mode if all input are double-byte characters
|
||||
return Mode::KANJI;
|
||||
}
|
||||
let mut has_numeric = false;
|
||||
let mut has_alphanumeric = false;
|
||||
for i in 0..content.len() {
|
||||
// for (int i = 0; i < content.length(); ++i) {
|
||||
let c = content.chars().nth(i).unwrap();
|
||||
for c in content.chars() {
|
||||
if ('0'..='9').contains(&c) {
|
||||
has_numeric = true;
|
||||
} else if getAlphanumericCode(c as u32) != -1 {
|
||||
@@ -354,13 +344,13 @@ pub fn isOnlyDoubleByteKanji(content: &str) -> bool {
|
||||
} else {
|
||||
return false;
|
||||
};
|
||||
|
||||
let length = bytes.len();
|
||||
if length % 2 != 0 {
|
||||
return false;
|
||||
}
|
||||
let mut i = 0;
|
||||
while i < length {
|
||||
// for (int i = 0; i < length; i += 2) {
|
||||
let byte1 = bytes[i];
|
||||
if !(0x81..=0x9F).contains(&byte1) && !(0xE0..=0xEB).contains(&byte1) {
|
||||
return false;
|
||||
@@ -380,7 +370,6 @@ fn chooseMaskPattern(
|
||||
let mut best_mask_pattern = -1;
|
||||
// We try all mask patterns to choose the best one.
|
||||
for maskPattern in 0..QRCode::NUM_MASK_PATTERNS {
|
||||
// for (int maskPattern = 0; maskPattern < QRCode.NUM_MASK_PATTERNS; maskPattern++) {
|
||||
let mut matrix = matrix.clone();
|
||||
matrix_util::buildMatrix(bits, ec_level, version, maskPattern, &mut matrix)?;
|
||||
let penalty = calculateMaskPenalty(&matrix);
|
||||
@@ -397,13 +386,14 @@ fn chooseVersion(
|
||||
ecLevel: &ErrorCorrectionLevel,
|
||||
) -> Result<VersionRef, Exceptions> {
|
||||
for versionNum in 1..=40 {
|
||||
// for (int versionNum = 1; versionNum <= 40; versionNum++) {
|
||||
let version = Version::getVersionForNumber(versionNum)?;
|
||||
if willFit(numInputBits, version, ecLevel) {
|
||||
return Ok(version);
|
||||
}
|
||||
}
|
||||
Err(Exceptions::WriterException(Some("Data too big".to_owned())))
|
||||
Err(Exceptions::WriterException(Some(format!(
|
||||
"data too big {numInputBits}/{ecLevel:?}"
|
||||
))))
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -432,16 +422,12 @@ pub fn terminateBits(num_data_bytes: u32, bits: &mut BitArray) -> Result<(), Exc
|
||||
return Err(Exceptions::WriterException(Some(format!(
|
||||
"data bits cannot fit in the QR Code{capacity} > "
|
||||
))));
|
||||
// throw new WriterException("data bits cannot fit in the QR Code" + bits.getSize() + " > " +
|
||||
// capacity);
|
||||
}
|
||||
// Append Mode.TERMINATE if there is enough space (value is 0000)
|
||||
for _i in 0..4 {
|
||||
if bits.getSize() >= capacity as usize {
|
||||
break;
|
||||
}
|
||||
// }
|
||||
// for (int i = 0; i < 4 && bits.getSize() < capacity; ++i) {
|
||||
bits.appendBit(false);
|
||||
}
|
||||
// Append termination bits. See 8.4.8 of JISX0510:2004 (p.24) for details.
|
||||
@@ -449,7 +435,6 @@ pub fn terminateBits(num_data_bytes: u32, bits: &mut BitArray) -> Result<(), Exc
|
||||
let num_bits_in_last_byte = bits.getSize() & 0x07;
|
||||
if num_bits_in_last_byte > 0 {
|
||||
for _i in num_bits_in_last_byte..8 {
|
||||
// for (int i = numBitsInLastByte; i < 8; i++) {
|
||||
bits.appendBit(false);
|
||||
}
|
||||
}
|
||||
@@ -459,14 +444,12 @@ pub fn terminateBits(num_data_bytes: u32, bits: &mut BitArray) -> Result<(), Exc
|
||||
if i >= num_padding_bytes {
|
||||
break;
|
||||
}
|
||||
// for (int i = 0; i < numPaddingBytes; ++i) {
|
||||
bits.appendBits(if (i & 0x01) == 0 { 0xEC } else { 0x11 }, 8)?;
|
||||
}
|
||||
if bits.getSize() != capacity as usize {
|
||||
return Err(Exceptions::WriterException(Some(
|
||||
"Bits size does not equal capacity".to_owned(),
|
||||
)));
|
||||
// throw new WriterException("Bits size does not equal capacity");
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
@@ -488,7 +471,6 @@ pub fn getNumDataBytesAndNumECBytesForBlockID(
|
||||
return Err(Exceptions::WriterException(Some(
|
||||
"Block ID too large".to_owned(),
|
||||
)));
|
||||
// throw new WriterException("Block ID too large");
|
||||
}
|
||||
// numRsBlocksInGroup2 = 196 % 5 = 1
|
||||
let num_rs_blocks_in_group2 = num_total_bytes % num_rsblocks;
|
||||
@@ -512,15 +494,12 @@ pub fn getNumDataBytesAndNumECBytesForBlockID(
|
||||
return Err(Exceptions::WriterException(Some(
|
||||
"EC bytes mismatch".to_owned(),
|
||||
)));
|
||||
// throw new WriterException("EC bytes mismatch");
|
||||
}
|
||||
// 5 = 4 + 1.
|
||||
if num_rsblocks != num_rs_blocks_in_group1 + num_rs_blocks_in_group2 {
|
||||
return Err(Exceptions::WriterException(Some(
|
||||
"RS blocks mismatch".to_owned(),
|
||||
)));
|
||||
|
||||
// throw new WriterException("RS blocks mismatch");
|
||||
}
|
||||
// 196 = (13 + 26) * 4 + (14 + 26) * 1
|
||||
if num_total_bytes
|
||||
@@ -530,8 +509,6 @@ pub fn getNumDataBytesAndNumECBytesForBlockID(
|
||||
return Err(Exceptions::WriterException(Some(
|
||||
"total bytes mismatch".to_owned(),
|
||||
)));
|
||||
|
||||
// throw new WriterException("Total bytes mismatch");
|
||||
}
|
||||
|
||||
Ok(if block_id < num_rs_blocks_in_group1 {
|
||||
@@ -568,9 +545,6 @@ pub fn interleaveWithECBytes(
|
||||
let mut blocks = Vec::new();
|
||||
|
||||
for i in 0..num_rsblocks {
|
||||
// for (int i = 0; i < numRSBlocks; ++i) {
|
||||
// let mut numDataBytesInBlock = vec![0; 1]; //new int[1];
|
||||
// let mut numEcBytesInBlock = vec![0; 1]; //new int[1];
|
||||
let (numDataBytesInBlock, numEcBytesInBlock) = getNumDataBytesAndNumECBytesForBlockID(
|
||||
num_total_bytes,
|
||||
num_data_bytes,
|
||||
@@ -583,7 +557,7 @@ pub fn interleaveWithECBytes(
|
||||
let size = numDataBytesInBlock;
|
||||
let mut dataBytes = vec![0u8; size as usize];
|
||||
bits.toBytes(8 * data_bytes_offset, &mut dataBytes, 0, size as usize);
|
||||
let ec_bytes = generateECBytes(&dataBytes, numEcBytesInBlock as usize);
|
||||
let ec_bytes = generateECBytes(&dataBytes, numEcBytesInBlock as usize)?;
|
||||
blocks.push(BlockPair::new(dataBytes, ec_bytes.clone()));
|
||||
|
||||
max_num_data_bytes = max_num_data_bytes.max(size);
|
||||
@@ -600,9 +574,7 @@ pub fn interleaveWithECBytes(
|
||||
|
||||
// First, place data blocks.
|
||||
for i in 0..max_num_data_bytes as usize {
|
||||
// for (int i = 0; i < maxNumDataBytes; ++i) {
|
||||
for block in &blocks {
|
||||
// for (BlockPair block : blocks) {
|
||||
let data_bytes = block.getDataBytes();
|
||||
if i < data_bytes.len() {
|
||||
result.appendBits(data_bytes[i] as u32, 8)?;
|
||||
@@ -611,9 +583,7 @@ pub fn interleaveWithECBytes(
|
||||
}
|
||||
// Then, place error correction blocks.
|
||||
for i in 0..max_num_ec_bytes {
|
||||
// for (int i = 0; i < maxNumEcBytes; ++i) {
|
||||
for block in &blocks {
|
||||
// for (BlockPair block : blocks) {
|
||||
let ec_bytes = block.getErrorCorrectionBytes();
|
||||
if i < ec_bytes.len() {
|
||||
result.appendBits(ec_bytes[i] as u32, 8)?;
|
||||
@@ -627,41 +597,38 @@ pub fn interleaveWithECBytes(
|
||||
num_total_bytes,
|
||||
result.getSizeInBytes()
|
||||
))));
|
||||
// throw new WriterException("Interleaving error: " + numTotalBytes + " and " +
|
||||
// result.getSizeInBytes() + " differ.");
|
||||
}
|
||||
|
||||
Ok(result)
|
||||
}
|
||||
|
||||
pub fn generateECBytes(dataBytes: &[u8], num_ec_bytes_in_block: usize) -> Vec<u8> {
|
||||
pub fn generateECBytes(
|
||||
dataBytes: &[u8],
|
||||
num_ec_bytes_in_block: usize,
|
||||
) -> Result<Vec<u8>, Exceptions> {
|
||||
let num_data_bytes = dataBytes.len();
|
||||
let mut to_encode = vec![0; num_data_bytes + num_ec_bytes_in_block];
|
||||
for i in 0..num_data_bytes {
|
||||
// for (int i = 0; i < numDataBytes; i++) {
|
||||
to_encode[i] = dataBytes[i] as i32;
|
||||
}
|
||||
|
||||
ReedSolomonEncoder::new(get_predefined_genericgf(
|
||||
PredefinedGenericGF::QrCodeField256,
|
||||
))
|
||||
.encode(&mut to_encode, num_ec_bytes_in_block)
|
||||
.expect("rs encode must complete");
|
||||
))?
|
||||
.encode(&mut to_encode, num_ec_bytes_in_block)?;
|
||||
|
||||
let mut ecBytes = vec![0u8; num_ec_bytes_in_block];
|
||||
for i in 0..num_ec_bytes_in_block {
|
||||
// for (int i = 0; i < numEcBytesInBlock; i++) {
|
||||
ecBytes[i] = to_encode[num_data_bytes + i] as u8;
|
||||
}
|
||||
ecBytes
|
||||
Ok(ecBytes)
|
||||
}
|
||||
|
||||
/**
|
||||
* Append mode info. On success, store the result in "bits".
|
||||
*/
|
||||
pub fn appendModeInfo(mode: Mode, bits: &mut BitArray) -> Result<(), Exceptions> {
|
||||
bits.appendBits(mode.getBits() as u32, 4)?;
|
||||
Ok(())
|
||||
bits.appendBits(mode.getBits() as u32, 4)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -681,8 +648,7 @@ pub fn appendLengthInfo(
|
||||
((1 << numBits) - 1)
|
||||
))));
|
||||
}
|
||||
bits.appendBits(num_letters, numBits as usize)?;
|
||||
Ok(())
|
||||
bits.appendBits(num_letters, numBits as usize)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -703,38 +669,38 @@ pub fn appendBytes(
|
||||
"Invalid mode: {mode:?}"
|
||||
)))),
|
||||
}
|
||||
// switch (mode) {
|
||||
// case NUMERIC:
|
||||
// appendNumericBytes(content, bits);
|
||||
// break;
|
||||
// case ALPHANUMERIC:
|
||||
// appendAlphanumericBytes(content, bits);
|
||||
// break;
|
||||
// case BYTE:
|
||||
// append8BitBytes(content, bits, encoding);
|
||||
// break;
|
||||
// case KANJI:
|
||||
// appendKanjiBytes(content, bits);
|
||||
// break;
|
||||
// default:
|
||||
// throw new WriterException("Invalid mode: " + mode);
|
||||
// }
|
||||
}
|
||||
|
||||
pub fn appendNumericBytes(content: &str, bits: &mut BitArray) -> Result<(), Exceptions> {
|
||||
let length = content.len();
|
||||
let mut i = 0;
|
||||
while i < length {
|
||||
let num1 = content.chars().nth(i).unwrap() as u8 - b'0';
|
||||
let num1 = content
|
||||
.chars()
|
||||
.nth(i)
|
||||
.ok_or(Exceptions::IndexOutOfBoundsException(None))? as u8
|
||||
- b'0';
|
||||
if i + 2 < length {
|
||||
// Encode three numeric letters in ten bits.
|
||||
let num2 = content.chars().nth(i + 1).unwrap() as u8 - b'0';
|
||||
let num3 = content.chars().nth(i + 2).unwrap() as u8 - b'0';
|
||||
let num2 = content
|
||||
.chars()
|
||||
.nth(i + 1)
|
||||
.ok_or(Exceptions::IndexOutOfBoundsException(None))? as u8
|
||||
- b'0';
|
||||
let num3 = content
|
||||
.chars()
|
||||
.nth(i + 2)
|
||||
.ok_or(Exceptions::IndexOutOfBoundsException(None))? as u8
|
||||
- b'0';
|
||||
bits.appendBits(num1 as u32 * 100 + num2 as u32 * 10 + num3 as u32, 10)?;
|
||||
i += 3;
|
||||
} else if i + 1 < length {
|
||||
// Encode two numeric letters in seven bits.
|
||||
let num2 = content.chars().nth(i + 1).unwrap() as u8 - b'0';
|
||||
let num2 = content
|
||||
.chars()
|
||||
.nth(i + 1)
|
||||
.ok_or(Exceptions::IndexOutOfBoundsException(None))? as u8
|
||||
- b'0';
|
||||
bits.appendBits(num1 as u32 * 10 + num2 as u32, 7)?;
|
||||
i += 2;
|
||||
} else {
|
||||
@@ -750,12 +716,22 @@ pub fn appendAlphanumericBytes(content: &str, bits: &mut BitArray) -> Result<(),
|
||||
let length = content.len();
|
||||
let mut i = 0;
|
||||
while i < length {
|
||||
let code1 = getAlphanumericCode(content.chars().nth(i).unwrap() as u32);
|
||||
let code1 = getAlphanumericCode(
|
||||
content
|
||||
.chars()
|
||||
.nth(i)
|
||||
.ok_or(Exceptions::IndexOutOfBoundsException(None))? as u32,
|
||||
);
|
||||
if code1 == -1 {
|
||||
return Err(Exceptions::WriterException(None));
|
||||
}
|
||||
if i + 1 < length {
|
||||
let code2 = getAlphanumericCode(content.chars().nth(i + 1).unwrap() as u32);
|
||||
let code2 = getAlphanumericCode(
|
||||
content
|
||||
.chars()
|
||||
.nth(i + 1)
|
||||
.ok_or(Exceptions::IndexOutOfBoundsException(None))? as u32,
|
||||
);
|
||||
if code2 == -1 {
|
||||
return Err(Exceptions::WriterException(None));
|
||||
}
|
||||
@@ -778,22 +754,19 @@ pub fn append8BitBytes(
|
||||
) -> Result<(), Exceptions> {
|
||||
let bytes = encoding
|
||||
.encode(content, encoding::EncoderTrap::Strict)
|
||||
.expect("should encode");
|
||||
// let bytes = content.getBytes(encoding);
|
||||
.map_err(|e| Exceptions::WriterException(Some(format!("error {e}"))))?;
|
||||
for b in bytes {
|
||||
// for (byte b : bytes) {
|
||||
bits.appendBits(b as u32, 8)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn appendKanjiBytes(content: &str, bits: &mut BitArray) -> Result<(), Exceptions> {
|
||||
let sjis = &SHIFT_JIS_CHARSET; //encoding::label::encoding_from_whatwg_label("SJIS").unwrap();
|
||||
let sjis = &SHIFT_JIS_CHARSET;
|
||||
|
||||
let bytes = sjis
|
||||
.encode(content, encoding::EncoderTrap::Strict)
|
||||
.expect("should encode fine");
|
||||
// let bytes = content.getBytes(StringUtils::SHIFT_JIS_CHARSET);
|
||||
.map_err(|e| Exceptions::WriterException(Some(format!("error {e}"))))?;
|
||||
if bytes.len() % 2 != 0 {
|
||||
return Err(Exceptions::WriterException(Some(
|
||||
"Kanji byte size not even".to_owned(),
|
||||
@@ -802,7 +775,6 @@ pub fn appendKanjiBytes(content: &str, bits: &mut BitArray) -> Result<(), Except
|
||||
let max_i = bytes.len() - 1; // bytes.length must be even
|
||||
let mut i = 0;
|
||||
while i < max_i {
|
||||
// for (int i = 0; i < maxI; i += 2) {
|
||||
let byte1 = bytes[i]; // & 0xFF;
|
||||
let byte2 = bytes[i + 1]; // & 0xFF;
|
||||
let code: u16 = ((byte1 as u16) << 8u16) | byte2 as u16;
|
||||
@@ -828,6 +800,5 @@ pub fn appendKanjiBytes(content: &str, bits: &mut BitArray) -> Result<(), Except
|
||||
fn appendECI(eci: &CharacterSetECI, bits: &mut BitArray) -> Result<(), Exceptions> {
|
||||
bits.appendBits(Mode::ECI.getBits() as u32, 4)?;
|
||||
// This is correct for values up to 127, which is all we need now.
|
||||
bits.appendBits(eci.getValueSelf(), 8)?;
|
||||
Ok(())
|
||||
bits.appendBits(eci.getValueSelf(), 8)
|
||||
}
|
||||
|
||||
@@ -18,8 +18,8 @@ use std::collections::HashMap;
|
||||
|
||||
use crate::{
|
||||
common::{BitMatrix, DecoderRXingResult, DetectorRXingResult},
|
||||
BarcodeFormat, DecodeHintType, Exceptions, RXingResult, RXingResultMetadataType,
|
||||
RXingResultMetadataValue, RXingResultPoint, Reader,
|
||||
BarcodeFormat, DecodeHintType, DecodeHintValue, Exceptions, RXingResult,
|
||||
RXingResultMetadataType, RXingResultMetadataValue, RXingResultPoint, Reader,
|
||||
};
|
||||
|
||||
use super::{
|
||||
@@ -62,7 +62,10 @@ impl Reader for QRCodeReader {
|
||||
) -> Result<crate::RXingResult, crate::Exceptions> {
|
||||
let decoderRXingResult: DecoderRXingResult;
|
||||
let mut points: Vec<RXingResultPoint>;
|
||||
if hints.contains_key(&DecodeHintType::PURE_BARCODE) {
|
||||
if matches!(
|
||||
hints.get(&DecodeHintType::PURE_BARCODE),
|
||||
Some(DecodeHintValue::PureBarcode(true))
|
||||
) {
|
||||
let bits = Self::extractPureBits(image.getBlackMatrix())?;
|
||||
decoderRXingResult = qrcode_decoder::decode_bitmatrix_with_hints(&bits, hints)?;
|
||||
points = Vec::new();
|
||||
@@ -80,9 +83,8 @@ impl Reader for QRCodeReader {
|
||||
// if (decoderRXingResult.getOther() instanceof QRCodeDecoderMetaData) {
|
||||
other
|
||||
.downcast_ref::<QRCodeDecoderMetaData>()
|
||||
.unwrap()
|
||||
.ok_or(Exceptions::IllegalStateException(None))?
|
||||
.applyMirroredCorrection(&mut points);
|
||||
// ((QRCodeDecoderMetaData) decoderRXingResult.getOther()).applyMirroredCorrection(points);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -92,6 +94,7 @@ impl Reader for QRCodeReader {
|
||||
points,
|
||||
BarcodeFormat::QR_CODE,
|
||||
);
|
||||
|
||||
let byteSegments = decoderRXingResult.getByteSegments();
|
||||
if !byteSegments.is_empty() {
|
||||
result.putMetadata(
|
||||
@@ -99,6 +102,7 @@ impl Reader for QRCodeReader {
|
||||
RXingResultMetadataValue::ByteSegments(byteSegments.clone()),
|
||||
);
|
||||
}
|
||||
|
||||
let ecLevel = decoderRXingResult.getECLevel();
|
||||
if !ecLevel.is_empty() {
|
||||
result.putMetadata(
|
||||
@@ -106,6 +110,7 @@ impl Reader for QRCodeReader {
|
||||
RXingResultMetadataValue::ErrorCorrectionLevel(ecLevel.to_owned()),
|
||||
);
|
||||
}
|
||||
|
||||
if decoderRXingResult.hasStructuredAppend() {
|
||||
result.putMetadata(
|
||||
RXingResultMetadataType::STRUCTURED_APPEND_SEQUENCE,
|
||||
@@ -120,6 +125,7 @@ impl Reader for QRCodeReader {
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
result.putMetadata(
|
||||
RXingResultMetadataType::SYMBOLOGY_IDENTIFIER,
|
||||
RXingResultMetadataValue::SymbologyIdentifier(format!(
|
||||
@@ -130,10 +136,6 @@ impl Reader for QRCodeReader {
|
||||
|
||||
Ok(result)
|
||||
}
|
||||
|
||||
fn reset(&mut self) {
|
||||
// nothing
|
||||
}
|
||||
}
|
||||
|
||||
impl QRCodeReader {
|
||||
@@ -154,8 +156,9 @@ impl QRCodeReader {
|
||||
return Err(Exceptions::NotFoundException(None));
|
||||
}
|
||||
|
||||
let leftTopBlack = leftTopBlack.unwrap();
|
||||
let rightBottomBlack = rightBottomBlack.unwrap();
|
||||
let leftTopBlack = leftTopBlack.ok_or(Exceptions::IndexOutOfBoundsException(None))?;
|
||||
let rightBottomBlack =
|
||||
rightBottomBlack.ok_or(Exceptions::IndexOutOfBoundsException(None))?;
|
||||
|
||||
let moduleSize = Self::moduleSize(&leftTopBlack, image)?;
|
||||
|
||||
@@ -220,10 +223,8 @@ impl QRCodeReader {
|
||||
// Now just read off the bits
|
||||
let mut bits = BitMatrix::new(matrixWidth, matrixHeight)?;
|
||||
for y in 0..matrixHeight {
|
||||
// for (int y = 0; y < matrixHeight; y++) {
|
||||
let iOffset = top + ((y as f32) * moduleSize) as i32;
|
||||
for x in 0..matrixWidth {
|
||||
// for (int x = 0; x < matrixWidth; x++) {
|
||||
if image.get(left as u32 + (x as f32 * moduleSize) as u32, iOffset as u32) {
|
||||
bits.set(x, y);
|
||||
}
|
||||
|
||||
@@ -59,46 +59,39 @@ impl Writer for QRCodeWriter {
|
||||
) -> Result<crate::common::BitMatrix, crate::Exceptions> {
|
||||
if contents.is_empty() {
|
||||
return Err(Exceptions::IllegalArgumentException(Some(
|
||||
"Found empty contents".to_owned(),
|
||||
"found empty contents".to_owned(),
|
||||
)));
|
||||
// throw new IllegalArgumentException("Found empty contents");
|
||||
}
|
||||
|
||||
if format != &BarcodeFormat::QR_CODE {
|
||||
return Err(Exceptions::IllegalArgumentException(Some(format!(
|
||||
"Can only encode QR_CODE, but got {format:?}"
|
||||
"can only encode QR_CODE, but got {format:?}"
|
||||
))));
|
||||
// throw new IllegalArgumentException("Can only encode QR_CODE, but got " + format);
|
||||
}
|
||||
|
||||
if width < 0 || height < 0 {
|
||||
return Err(Exceptions::IllegalArgumentException(Some(format!(
|
||||
"Requested dimensions are too small: {width}x{height}"
|
||||
"requested dimensions are too small: {width}x{height}"
|
||||
))));
|
||||
// throw new IllegalArgumentException("Requested dimensions are too small: " + width + 'x' +
|
||||
// height);
|
||||
}
|
||||
|
||||
let mut errorCorrectionLevel = ErrorCorrectionLevel::L;
|
||||
let mut quietZone = QUIET_ZONE_SIZE;
|
||||
// if (hints != null) {
|
||||
if hints.contains_key(&EncodeHintType::ERROR_CORRECTION) {
|
||||
if let EncodeHintValue::ErrorCorrection(ec_level) =
|
||||
hints.get(&EncodeHintType::ERROR_CORRECTION).unwrap()
|
||||
{
|
||||
errorCorrectionLevel = ec_level.parse()?;
|
||||
}
|
||||
// errorCorrectionLevel = ErrorCorrectionLevel.valueOf(hints.get(EncodeHintType.ERROR_CORRECTION).toString());
|
||||
}
|
||||
if hints.contains_key(&EncodeHintType::MARGIN) {
|
||||
if let EncodeHintValue::Margin(margin) = hints.get(&EncodeHintType::MARGIN).unwrap() {
|
||||
quietZone = margin.parse().unwrap();
|
||||
// quietZone = Integer.parseInt(hints.get(EncodeHintType.MARGIN).toString());
|
||||
}
|
||||
let errorCorrectionLevel = if let Some(EncodeHintValue::ErrorCorrection(ec_level)) =
|
||||
hints.get(&EncodeHintType::ERROR_CORRECTION)
|
||||
{
|
||||
ec_level.parse()?
|
||||
} else {
|
||||
ErrorCorrectionLevel::L
|
||||
};
|
||||
|
||||
// quietZone = Integer.parseInt(hints.get(EncodeHintType.MARGIN).toString());
|
||||
}
|
||||
// }
|
||||
let quietZone =
|
||||
if let Some(EncodeHintValue::Margin(margin)) = hints.get(&EncodeHintType::MARGIN) {
|
||||
margin.parse::<i32>().map_err(|e| {
|
||||
Exceptions::ParseException(Some(format!("could not parse {margin}: {e}")))
|
||||
})?
|
||||
} else {
|
||||
QUIET_ZONE_SIZE
|
||||
};
|
||||
|
||||
let code = qrcode_encoder::encode_with_hints(contents, errorCorrectionLevel, hints)?;
|
||||
|
||||
@@ -120,10 +113,11 @@ impl QRCodeWriter {
|
||||
return Err(Exceptions::IllegalStateException(Some(
|
||||
"matrix is empty".to_owned(),
|
||||
)));
|
||||
// throw new IllegalStateException();
|
||||
}
|
||||
|
||||
let input = input.as_ref().unwrap();
|
||||
let input = input
|
||||
.as_ref()
|
||||
.ok_or(Exceptions::IllegalStateException(None))?;
|
||||
|
||||
let inputWidth = input.getWidth() as i32;
|
||||
let inputHeight = input.getHeight() as i32;
|
||||
|
||||
Reference in New Issue
Block a user