mirror of
https://github.com/starovoid/rxing.git
synced 2026-07-27 21:02:35 +00:00
port qrcode metadata struct
This commit is contained in:
@@ -3,6 +3,7 @@ mod mode;
|
|||||||
mod error_correction_level;
|
mod error_correction_level;
|
||||||
mod format_information;
|
mod format_information;
|
||||||
mod data_block;
|
mod data_block;
|
||||||
|
mod qr_code_decoder_metaData;
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod ErrorCorrectionLevelTestCase;
|
mod ErrorCorrectionLevelTestCase;
|
||||||
@@ -15,4 +16,5 @@ pub use version::*;
|
|||||||
pub use mode::*;
|
pub use mode::*;
|
||||||
pub use error_correction_level::*;
|
pub use error_correction_level::*;
|
||||||
pub use format_information::*;
|
pub use format_information::*;
|
||||||
pub use data_block::*;
|
pub use data_block::*;
|
||||||
|
pub use qr_code_decoder_metaData::*;
|
||||||
@@ -14,9 +14,7 @@
|
|||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package com.google.zxing.qrcode.decoder;
|
use crate::RXingResultPoint;
|
||||||
|
|
||||||
import com.google.zxing.RXingResultPoint;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Meta-data container for QR Code decoding. Instances of this class may be used to convey information back to the
|
* Meta-data container for QR Code decoding. Instances of this class may be used to convey information back to the
|
||||||
@@ -24,19 +22,18 @@ import com.google.zxing.RXingResultPoint;
|
|||||||
*
|
*
|
||||||
* @see com.google.zxing.common.DecoderRXingResult#getOther()
|
* @see com.google.zxing.common.DecoderRXingResult#getOther()
|
||||||
*/
|
*/
|
||||||
public final class QRCodeDecoderMetaData {
|
pub struct QRCodeDecoderMetaData(bool);
|
||||||
|
|
||||||
private final boolean mirrored;
|
impl QRCodeDecoderMetaData {
|
||||||
|
pub fn new( mirrored:bool) -> Self {
|
||||||
QRCodeDecoderMetaData(boolean mirrored) {
|
Self(mirrored)
|
||||||
this.mirrored = mirrored;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return true if the QR Code was mirrored.
|
* @return true if the QR Code was mirrored.
|
||||||
*/
|
*/
|
||||||
public boolean isMirrored() {
|
pub fn isMirrored(&self) -> bool{
|
||||||
return mirrored;
|
self.0
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -44,13 +41,13 @@ public final class QRCodeDecoderMetaData {
|
|||||||
*
|
*
|
||||||
* @param points Array of points to apply mirror correction to.
|
* @param points Array of points to apply mirror correction to.
|
||||||
*/
|
*/
|
||||||
public void applyMirroredCorrection(RXingResultPoint[] points) {
|
pub fn applyMirroredCorrection(&self, points : &mut [RXingResultPoint]) {
|
||||||
if (!mirrored || points == null || points.length < 3) {
|
if !self.0 || points.is_empty() || points.len() < 3 {
|
||||||
return;
|
return
|
||||||
}
|
}
|
||||||
RXingResultPoint bottomLeft = points[0];
|
let bottom_left = points[0];
|
||||||
points[0] = points[2];
|
points[0] = points[2];
|
||||||
points[2] = bottomLeft;
|
points[2] = bottom_left;
|
||||||
// No need to 'fix' top-left and alignment pattern.
|
// No need to 'fix' top-left and alignment pattern.
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -95,14 +95,14 @@ pub fn encode(content: &str, ecLevel: ErrorCorrectionLevel) -> Result<QRCode, Ex
|
|||||||
|
|
||||||
pub fn encode_with_hints(
|
pub fn encode_with_hints(
|
||||||
content: &str,
|
content: &str,
|
||||||
ecLevel: ErrorCorrectionLevel,
|
ec_level: ErrorCorrectionLevel,
|
||||||
hints: &EncodingHintDictionary,
|
hints: &EncodingHintDictionary,
|
||||||
) -> Result<QRCode, Exceptions> {
|
) -> Result<QRCode, Exceptions> {
|
||||||
let version;
|
let version;
|
||||||
let mut headerAndDataBits;
|
let mut header_and_data_bits;
|
||||||
let mode;
|
let mode;
|
||||||
|
|
||||||
let hasGS1FormatHint = hints.contains_key(&EncodeHintType::GS1_FORMAT)
|
let has_gs1_format_hint = hints.contains_key(&EncodeHintType::GS1_FORMAT)
|
||||||
&& if let EncodeHintValue::Gs1Format(v) = hints.get(&EncodeHintType::GS1_FORMAT).unwrap() {
|
&& if let EncodeHintValue::Gs1Format(v) = hints.get(&EncodeHintType::GS1_FORMAT).unwrap() {
|
||||||
if let Ok(vb) = v.parse::<bool>() {
|
if let Ok(vb) = v.parse::<bool>() {
|
||||||
vb
|
vb
|
||||||
@@ -112,7 +112,7 @@ pub fn encode_with_hints(
|
|||||||
} else {
|
} else {
|
||||||
false
|
false
|
||||||
};
|
};
|
||||||
let hasCompactionHint = hints.contains_key(&EncodeHintType::QR_COMPACT)
|
let has_compaction_hint = hints.contains_key(&EncodeHintType::QR_COMPACT)
|
||||||
&& if let EncodeHintValue::QrCompact(v) = hints.get(&EncodeHintType::QR_COMPACT).unwrap() {
|
&& if let EncodeHintValue::QrCompact(v) = hints.get(&EncodeHintType::QR_COMPACT).unwrap() {
|
||||||
if let Ok(vb) = v.parse::<bool>() {
|
if let Ok(vb) = v.parse::<bool>() {
|
||||||
vb
|
vb
|
||||||
@@ -125,8 +125,8 @@ pub fn encode_with_hints(
|
|||||||
|
|
||||||
// Determine what character encoding has been specified by the caller, if any
|
// Determine what character encoding has been specified by the caller, if any
|
||||||
let mut encoding = None; //DEFAULT_BYTE_MODE_ENCODING;
|
let mut encoding = None; //DEFAULT_BYTE_MODE_ENCODING;
|
||||||
let hasEncodingHint = hints.contains_key(&EncodeHintType::CHARACTER_SET);
|
let has_encoding_hint = hints.contains_key(&EncodeHintType::CHARACTER_SET);
|
||||||
if hasEncodingHint {
|
if has_encoding_hint {
|
||||||
if let EncodeHintValue::CharacterSet(v) = hints.get(&EncodeHintType::CHARACTER_SET).unwrap()
|
if let EncodeHintValue::CharacterSet(v) = hints.get(&EncodeHintType::CHARACTER_SET).unwrap()
|
||||||
{
|
{
|
||||||
encoding = Some(encoding::label::encoding_from_whatwg_label(v).unwrap())
|
encoding = Some(encoding::label::encoding_from_whatwg_label(v).unwrap())
|
||||||
@@ -134,21 +134,21 @@ pub fn encode_with_hints(
|
|||||||
// encoding = encoding::label::encoding_from_whatwg_label(hints.get(&EncodeHintType::CHARACTER_SET).unwrap());
|
// encoding = encoding::label::encoding_from_whatwg_label(hints.get(&EncodeHintType::CHARACTER_SET).unwrap());
|
||||||
}
|
}
|
||||||
|
|
||||||
if hasCompactionHint {
|
if has_compaction_hint {
|
||||||
mode = Mode::BYTE;
|
mode = Mode::BYTE;
|
||||||
|
|
||||||
// dbg!("consider this a huge risk, not sure if it should be defaulting to default");
|
// dbg!("consider this a huge risk, not sure if it should be defaulting to default");
|
||||||
let priorityEncoding = encoding; //if encoding.name() == DEFAULT_BYTE_MODE_ENCODING.name() {None} else {Some(encoding)};
|
let priority_encoding = encoding; //if encoding.name() == DEFAULT_BYTE_MODE_ENCODING.name() {None} else {Some(encoding)};
|
||||||
let rn = MinimalEncoder::encode_with_details(
|
let rn = MinimalEncoder::encode_with_details(
|
||||||
content,
|
content,
|
||||||
None,
|
None,
|
||||||
priorityEncoding,
|
priority_encoding,
|
||||||
hasGS1FormatHint,
|
has_gs1_format_hint,
|
||||||
ecLevel,
|
ec_level,
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
headerAndDataBits = BitArray::new();
|
header_and_data_bits = BitArray::new();
|
||||||
rn.getBits(&mut headerAndDataBits)?;
|
rn.getBits(&mut header_and_data_bits)?;
|
||||||
version = rn.getVersion();
|
version = rn.getVersion();
|
||||||
} else {
|
} else {
|
||||||
//Switch to default encoding
|
//Switch to default encoding
|
||||||
@@ -164,29 +164,29 @@ pub fn encode_with_hints(
|
|||||||
|
|
||||||
// This will store the header information, like mode and
|
// This will store the header information, like mode and
|
||||||
// length, as well as "header" segments like an ECI segment.
|
// length, as well as "header" segments like an ECI segment.
|
||||||
let mut headerBits = BitArray::new();
|
let mut header_bits = BitArray::new();
|
||||||
|
|
||||||
// Append ECI segment if applicable
|
// Append ECI segment if applicable
|
||||||
if mode == Mode::BYTE && hasEncodingHint {
|
if mode == Mode::BYTE && has_encoding_hint {
|
||||||
let eci = CharacterSetECI::getCharacterSetECI(encoding);
|
let eci = CharacterSetECI::getCharacterSetECI(encoding);
|
||||||
if eci.is_some() {
|
if eci.is_some() {
|
||||||
appendECI(&eci.unwrap(), &mut headerBits)?;
|
appendECI(&eci.unwrap(), &mut header_bits)?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Append the FNC1 mode header for GS1 formatted data if applicable
|
// Append the FNC1 mode header for GS1 formatted data if applicable
|
||||||
if hasGS1FormatHint {
|
if has_gs1_format_hint {
|
||||||
// GS1 formatted codes are prefixed with a FNC1 in first position mode header
|
// GS1 formatted codes are prefixed with a FNC1 in first position mode header
|
||||||
appendModeInfo(Mode::FNC1_FIRST_POSITION, &mut headerBits)?;
|
appendModeInfo(Mode::FNC1_FIRST_POSITION, &mut header_bits)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
// (With ECI in place,) Write the mode marker
|
// (With ECI in place,) Write the mode marker
|
||||||
appendModeInfo(mode, &mut headerBits)?;
|
appendModeInfo(mode, &mut header_bits)?;
|
||||||
|
|
||||||
// Collect data within the main segment, separately, to count its size if needed. Don't add it to
|
// Collect data within the main segment, separately, to count its size if needed. Don't add it to
|
||||||
// main payload yet.
|
// main payload yet.
|
||||||
let mut dataBits = BitArray::new();
|
let mut data_bits = BitArray::new();
|
||||||
appendBytes(content, mode, &mut dataBits, encoding)?;
|
appendBytes(content, mode, &mut data_bits, encoding)?;
|
||||||
|
|
||||||
if hints.contains_key(&EncodeHintType::QR_VERSION) {
|
if hints.contains_key(&EncodeHintType::QR_VERSION) {
|
||||||
let versionNumber = if let EncodeHintValue::QrVersion(v) =
|
let versionNumber = if let EncodeHintValue::QrVersion(v) =
|
||||||
@@ -202,46 +202,46 @@ pub fn encode_with_hints(
|
|||||||
};
|
};
|
||||||
// let versionNumber = Integer.parseInt(hints.get(&EncodeHintType::QR_VERSION).unwrap()());
|
// let versionNumber = Integer.parseInt(hints.get(&EncodeHintType::QR_VERSION).unwrap()());
|
||||||
version = Version::getVersionForNumber(versionNumber)?;
|
version = Version::getVersionForNumber(versionNumber)?;
|
||||||
let bitsNeeded = calculateBitsNeeded(mode, &headerBits, &dataBits, version);
|
let bitsNeeded = calculateBitsNeeded(mode, &header_bits, &data_bits, version);
|
||||||
if !willFit(bitsNeeded, version, &ecLevel) {
|
if !willFit(bitsNeeded, version, &ec_level) {
|
||||||
return Err(Exceptions::WriterException(
|
return Err(Exceptions::WriterException(
|
||||||
"Data too big for requested version".to_owned(),
|
"Data too big for requested version".to_owned(),
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
version = recommendVersion(&ecLevel, mode, &headerBits, &dataBits)?;
|
version = recommendVersion(&ec_level, mode, &header_bits, &data_bits)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
headerAndDataBits = BitArray::new();
|
header_and_data_bits = BitArray::new();
|
||||||
headerAndDataBits.appendBitArray(headerBits);
|
header_and_data_bits.appendBitArray(header_bits);
|
||||||
// Find "length" of main segment and write it
|
// Find "length" of main segment and write it
|
||||||
let numLetters = if mode == Mode::BYTE {
|
let num_letters = if mode == Mode::BYTE {
|
||||||
dataBits.getSizeInBytes()
|
data_bits.getSizeInBytes()
|
||||||
} else {
|
} else {
|
||||||
content.graphemes(true).count()
|
content.graphemes(true).count()
|
||||||
};
|
};
|
||||||
appendLengthInfo(numLetters as u32, version, mode, &mut headerAndDataBits)?;
|
appendLengthInfo(num_letters as u32, version, mode, &mut header_and_data_bits)?;
|
||||||
// Put data together into the overall payload
|
// Put data together into the overall payload
|
||||||
headerAndDataBits.appendBitArray(dataBits);
|
header_and_data_bits.appendBitArray(data_bits);
|
||||||
}
|
}
|
||||||
|
|
||||||
let ecBlocks = version.getECBlocksForLevel(ecLevel);
|
let ec_blocks = version.getECBlocksForLevel(ec_level);
|
||||||
let numDataBytes = version.getTotalCodewords() - ecBlocks.getTotalECCodewords();
|
let num_data_bytes = version.getTotalCodewords() - ec_blocks.getTotalECCodewords();
|
||||||
|
|
||||||
// Terminate the bits properly.
|
// Terminate the bits properly.
|
||||||
terminateBits(numDataBytes, &mut headerAndDataBits)?;
|
terminateBits(num_data_bytes, &mut header_and_data_bits)?;
|
||||||
|
|
||||||
// Interleave data bits with error correction code.
|
// Interleave data bits with error correction code.
|
||||||
let finalBits = interleaveWithECBytes(
|
let final_bits = interleaveWithECBytes(
|
||||||
&headerAndDataBits,
|
&header_and_data_bits,
|
||||||
version.getTotalCodewords(),
|
version.getTotalCodewords(),
|
||||||
numDataBytes,
|
num_data_bytes,
|
||||||
ecBlocks.getNumBlocks(),
|
ec_blocks.getNumBlocks(),
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
let mut qrCode = QRCode::new();
|
let mut qrCode = QRCode::new();
|
||||||
|
|
||||||
qrCode.setECLevel(ecLevel);
|
qrCode.setECLevel(ec_level);
|
||||||
qrCode.setMode(mode);
|
qrCode.setMode(mode);
|
||||||
qrCode.setVersion(version);
|
qrCode.setVersion(version);
|
||||||
|
|
||||||
@@ -250,9 +250,9 @@ pub fn encode_with_hints(
|
|||||||
let mut matrix = ByteMatrix::new(dimension, dimension);
|
let mut matrix = ByteMatrix::new(dimension, dimension);
|
||||||
|
|
||||||
// Enable manual selection of the pattern to be used via hint
|
// Enable manual selection of the pattern to be used via hint
|
||||||
let mut maskPattern = -1;
|
let mut mask_pattern = -1;
|
||||||
if hints.contains_key(&EncodeHintType::QR_MASK_PATTERN) {
|
if hints.contains_key(&EncodeHintType::QR_MASK_PATTERN) {
|
||||||
let hintMaskPattern = if let EncodeHintValue::QrMaskPattern(v) =
|
let hint_mask_pattern = if let EncodeHintValue::QrMaskPattern(v) =
|
||||||
hints.get(&EncodeHintType::QR_MASK_PATTERN).unwrap()
|
hints.get(&EncodeHintType::QR_MASK_PATTERN).unwrap()
|
||||||
{
|
{
|
||||||
if let Ok(vb) = v.parse::<i32>() {
|
if let Ok(vb) = v.parse::<i32>() {
|
||||||
@@ -264,20 +264,20 @@ pub fn encode_with_hints(
|
|||||||
-1
|
-1
|
||||||
};
|
};
|
||||||
// let hintMaskPattern = Integer.parseInt(hints.get(&EncodeHintType::QR_MASK_PATTERN).unwrap());
|
// let hintMaskPattern = Integer.parseInt(hints.get(&EncodeHintType::QR_MASK_PATTERN).unwrap());
|
||||||
maskPattern = if QRCode::isValidMaskPattern(hintMaskPattern) {
|
mask_pattern = if QRCode::isValidMaskPattern(hint_mask_pattern) {
|
||||||
hintMaskPattern
|
hint_mask_pattern
|
||||||
} else {
|
} else {
|
||||||
-1
|
-1
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
if maskPattern == -1 {
|
if mask_pattern == -1 {
|
||||||
maskPattern = chooseMaskPattern(&finalBits, &ecLevel, version, &mut matrix)? as i32;
|
mask_pattern = chooseMaskPattern(&final_bits, &ec_level, version, &mut matrix)? as i32;
|
||||||
}
|
}
|
||||||
qrCode.setMaskPattern(maskPattern);
|
qrCode.setMaskPattern(mask_pattern);
|
||||||
|
|
||||||
// Build the matrix and set it to "qrCode".
|
// Build the matrix and set it to "qrCode".
|
||||||
matrix_util::buildMatrix(&finalBits, &ecLevel, version, maskPattern, &mut matrix)?;
|
matrix_util::buildMatrix(&final_bits, &ec_level, version, mask_pattern, &mut matrix)?;
|
||||||
qrCode.setMatrix(matrix);
|
qrCode.setMatrix(matrix);
|
||||||
|
|
||||||
Ok(qrCode)
|
Ok(qrCode)
|
||||||
@@ -289,31 +289,31 @@ pub fn encode_with_hints(
|
|||||||
* @throws WriterException if the data cannot fit in any version
|
* @throws WriterException if the data cannot fit in any version
|
||||||
*/
|
*/
|
||||||
fn recommendVersion(
|
fn recommendVersion(
|
||||||
ecLevel: &ErrorCorrectionLevel,
|
ec_level: &ErrorCorrectionLevel,
|
||||||
mode: Mode,
|
mode: Mode,
|
||||||
headerBits: &BitArray,
|
header_bits: &BitArray,
|
||||||
dataBits: &BitArray,
|
data_bits: &BitArray,
|
||||||
) -> Result<VersionRef, Exceptions> {
|
) -> Result<VersionRef, Exceptions> {
|
||||||
// Hard part: need to know version to know how many bits length takes. But need to know how many
|
// Hard part: need to know version to know how many bits length takes. But need to know how many
|
||||||
// bits it takes to know version. First we take a guess at version by assuming version will be
|
// bits it takes to know version. First we take a guess at version by assuming version will be
|
||||||
// the minimum, 1:
|
// the minimum, 1:
|
||||||
let provisionalBitsNeeded =
|
let provisional_bits_needed =
|
||||||
calculateBitsNeeded(mode, headerBits, dataBits, Version::getVersionForNumber(1)?);
|
calculateBitsNeeded(mode, header_bits, data_bits, Version::getVersionForNumber(1)?);
|
||||||
let provisionalVersion = chooseVersion(provisionalBitsNeeded, ecLevel)?;
|
let provisional_version = chooseVersion(provisional_bits_needed, ec_level)?;
|
||||||
|
|
||||||
// Use that guess to calculate the right version. I am still not sure this works in 100% of cases.
|
// Use that guess to calculate the right version. I am still not sure this works in 100% of cases.
|
||||||
let bitsNeeded = calculateBitsNeeded(mode, headerBits, dataBits, provisionalVersion);
|
let bits_needed = calculateBitsNeeded(mode, header_bits, data_bits, provisional_version);
|
||||||
|
|
||||||
chooseVersion(bitsNeeded, ecLevel)
|
chooseVersion(bits_needed, ec_level)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn calculateBitsNeeded(
|
fn calculateBitsNeeded(
|
||||||
mode: Mode,
|
mode: Mode,
|
||||||
headerBits: &BitArray,
|
header_bits: &BitArray,
|
||||||
dataBits: &BitArray,
|
data_bits: &BitArray,
|
||||||
version: VersionRef,
|
version: VersionRef,
|
||||||
) -> u32 {
|
) -> u32 {
|
||||||
(headerBits.getSize() + mode.getCharacterCountBits(version) as usize + dataBits.getSize())
|
(header_bits.getSize() + mode.getCharacterCountBits(version) as usize + data_bits.getSize())
|
||||||
as u32
|
as u32
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -344,23 +344,23 @@ fn chooseModeWithEncoding(content: &str, encoding: EncodingRef) -> Mode {
|
|||||||
// Choose Kanji mode if all input are double-byte characters
|
// Choose Kanji mode if all input are double-byte characters
|
||||||
return Mode::KANJI;
|
return Mode::KANJI;
|
||||||
}
|
}
|
||||||
let mut hasNumeric = false;
|
let mut has_numeric = false;
|
||||||
let mut hasAlphanumeric = false;
|
let mut has_alphanumeric = false;
|
||||||
for i in 0..content.len() {
|
for i in 0..content.len() {
|
||||||
// for (int i = 0; i < content.length(); ++i) {
|
// for (int i = 0; i < content.length(); ++i) {
|
||||||
let c = content.chars().nth(i).unwrap();
|
let c = content.chars().nth(i).unwrap();
|
||||||
if c >= '0' && c <= '9' {
|
if c >= '0' && c <= '9' {
|
||||||
hasNumeric = true;
|
has_numeric = true;
|
||||||
} else if getAlphanumericCode(c as u32) != -1 {
|
} else if getAlphanumericCode(c as u32) != -1 {
|
||||||
hasAlphanumeric = true;
|
has_alphanumeric = true;
|
||||||
} else {
|
} else {
|
||||||
return Mode::BYTE;
|
return Mode::BYTE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if hasAlphanumeric {
|
if has_alphanumeric {
|
||||||
return Mode::ALPHANUMERIC;
|
return Mode::ALPHANUMERIC;
|
||||||
}
|
}
|
||||||
if hasNumeric {
|
if has_numeric {
|
||||||
return Mode::NUMERIC;
|
return Mode::NUMERIC;
|
||||||
}
|
}
|
||||||
return Mode::BYTE;
|
return Mode::BYTE;
|
||||||
@@ -390,24 +390,24 @@ pub fn isOnlyDoubleByteKanji(content: &str) -> bool {
|
|||||||
|
|
||||||
fn chooseMaskPattern(
|
fn chooseMaskPattern(
|
||||||
bits: &BitArray,
|
bits: &BitArray,
|
||||||
ecLevel: &ErrorCorrectionLevel,
|
ec_level: &ErrorCorrectionLevel,
|
||||||
version: VersionRef,
|
version: VersionRef,
|
||||||
matrix: &mut ByteMatrix,
|
matrix: &mut ByteMatrix,
|
||||||
) -> Result<u32, Exceptions> {
|
) -> Result<u32, Exceptions> {
|
||||||
let mut minPenalty = u32::MAX; // Lower penalty is better.
|
let mut min_penalty = u32::MAX; // Lower penalty is better.
|
||||||
let mut bestMaskPattern = -1;
|
let mut best_mask_pattern = -1;
|
||||||
// We try all mask patterns to choose the best one.
|
// We try all mask patterns to choose the best one.
|
||||||
for maskPattern in 0..QRCode::NUM_MASK_PATTERNS {
|
for maskPattern in 0..QRCode::NUM_MASK_PATTERNS {
|
||||||
// for (int maskPattern = 0; maskPattern < QRCode.NUM_MASK_PATTERNS; maskPattern++) {
|
// for (int maskPattern = 0; maskPattern < QRCode.NUM_MASK_PATTERNS; maskPattern++) {
|
||||||
let mut matrix = matrix.clone();
|
let mut matrix = matrix.clone();
|
||||||
matrix_util::buildMatrix(bits, ecLevel, version, maskPattern, &mut matrix)?;
|
matrix_util::buildMatrix(bits, ec_level, version, maskPattern, &mut matrix)?;
|
||||||
let penalty = calculateMaskPenalty(&matrix);
|
let penalty = calculateMaskPenalty(&matrix);
|
||||||
if penalty < minPenalty {
|
if penalty < min_penalty {
|
||||||
minPenalty = penalty;
|
min_penalty = penalty;
|
||||||
bestMaskPattern = maskPattern;
|
best_mask_pattern = maskPattern;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Ok(bestMaskPattern as u32)
|
Ok(best_mask_pattern as u32)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn chooseVersion(
|
fn chooseVersion(
|
||||||
@@ -431,14 +431,14 @@ fn chooseVersion(
|
|||||||
pub fn willFit(numInputBits: u32, version: VersionRef, ecLevel: &ErrorCorrectionLevel) -> bool {
|
pub fn willFit(numInputBits: u32, version: VersionRef, ecLevel: &ErrorCorrectionLevel) -> bool {
|
||||||
// In the following comments, we use numbers of Version 7-H.
|
// In the following comments, we use numbers of Version 7-H.
|
||||||
// numBytes = 196
|
// numBytes = 196
|
||||||
let numBytes = version.getTotalCodewords();
|
let num_bytes = version.getTotalCodewords();
|
||||||
// getNumECBytes = 130
|
// getNumECBytes = 130
|
||||||
let ecBlocks = version.getECBlocksForLevel(*ecLevel);
|
let ec_blocks = version.getECBlocksForLevel(*ecLevel);
|
||||||
let numEcBytes = ecBlocks.getTotalECCodewords();
|
let num_ec_bytes = ec_blocks.getTotalECCodewords();
|
||||||
// getNumDataBytes = 196 - 130 = 66
|
// getNumDataBytes = 196 - 130 = 66
|
||||||
let numDataBytes = numBytes - numEcBytes;
|
let num_data_bytes = num_bytes - num_ec_bytes;
|
||||||
let totalInputBytes = (numInputBits + 7) / 8;
|
let total_input_bytes = (numInputBits + 7) / 8;
|
||||||
return numDataBytes >= totalInputBytes;
|
return num_data_bytes >= total_input_bytes;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -496,49 +496,49 @@ pub fn terminateBits(num_data_bytes: u32, bits: &mut BitArray) -> Result<(), Exc
|
|||||||
* JISX0510:2004 (p.30)
|
* JISX0510:2004 (p.30)
|
||||||
*/
|
*/
|
||||||
pub fn getNumDataBytesAndNumECBytesForBlockID(
|
pub fn getNumDataBytesAndNumECBytesForBlockID(
|
||||||
numTotalBytes: u32,
|
num_total_bytes: u32,
|
||||||
numDataBytes: u32,
|
num_data_bytes: u32,
|
||||||
numRSBlocks: u32,
|
num_rsblocks: u32,
|
||||||
blockID: u32,
|
block_id: u32,
|
||||||
// numDataBytesInBlock: &mut [u32],
|
// numDataBytesInBlock: &mut [u32],
|
||||||
// numECBytesInBlock: &mut [u32],
|
// numECBytesInBlock: &mut [u32],
|
||||||
) -> Result<(u32, u32), Exceptions> {
|
) -> Result<(u32, u32), Exceptions> {
|
||||||
if blockID >= numRSBlocks {
|
if block_id >= num_rsblocks {
|
||||||
return Err(Exceptions::WriterException("Block ID too large".to_owned()));
|
return Err(Exceptions::WriterException("Block ID too large".to_owned()));
|
||||||
// throw new WriterException("Block ID too large");
|
// throw new WriterException("Block ID too large");
|
||||||
}
|
}
|
||||||
// numRsBlocksInGroup2 = 196 % 5 = 1
|
// numRsBlocksInGroup2 = 196 % 5 = 1
|
||||||
let numRsBlocksInGroup2 = numTotalBytes % numRSBlocks;
|
let num_rs_blocks_in_group2 = num_total_bytes % num_rsblocks;
|
||||||
// numRsBlocksInGroup1 = 5 - 1 = 4
|
// numRsBlocksInGroup1 = 5 - 1 = 4
|
||||||
let numRsBlocksInGroup1 = numRSBlocks - numRsBlocksInGroup2;
|
let num_rs_blocks_in_group1 = num_rsblocks - num_rs_blocks_in_group2;
|
||||||
// numTotalBytesInGroup1 = 196 / 5 = 39
|
// numTotalBytesInGroup1 = 196 / 5 = 39
|
||||||
let numTotalBytesInGroup1 = numTotalBytes / numRSBlocks;
|
let num_total_bytes_in_group1 = num_total_bytes / num_rsblocks;
|
||||||
// numTotalBytesInGroup2 = 39 + 1 = 40
|
// numTotalBytesInGroup2 = 39 + 1 = 40
|
||||||
let numTotalBytesInGroup2 = numTotalBytesInGroup1 + 1;
|
let num_total_bytes_in_group2 = num_total_bytes_in_group1 + 1;
|
||||||
// numDataBytesInGroup1 = 66 / 5 = 13
|
// numDataBytesInGroup1 = 66 / 5 = 13
|
||||||
let numDataBytesInGroup1 = numDataBytes / numRSBlocks;
|
let num_data_bytes_in_group1 = num_data_bytes / num_rsblocks;
|
||||||
// numDataBytesInGroup2 = 13 + 1 = 14
|
// numDataBytesInGroup2 = 13 + 1 = 14
|
||||||
let numDataBytesInGroup2 = numDataBytesInGroup1 + 1;
|
let num_data_bytes_in_group2 = num_data_bytes_in_group1 + 1;
|
||||||
// numEcBytesInGroup1 = 39 - 13 = 26
|
// numEcBytesInGroup1 = 39 - 13 = 26
|
||||||
let numEcBytesInGroup1 = numTotalBytesInGroup1 - numDataBytesInGroup1;
|
let num_ec_bytes_in_group1 = num_total_bytes_in_group1 - num_data_bytes_in_group1;
|
||||||
// numEcBytesInGroup2 = 40 - 14 = 26
|
// numEcBytesInGroup2 = 40 - 14 = 26
|
||||||
let numEcBytesInGroup2 = numTotalBytesInGroup2 - numDataBytesInGroup2;
|
let numEcBytesInGroup2 = num_total_bytes_in_group2 - num_data_bytes_in_group2;
|
||||||
// Sanity checks.
|
// Sanity checks.
|
||||||
// 26 = 26
|
// 26 = 26
|
||||||
if numEcBytesInGroup1 != numEcBytesInGroup2 {
|
if num_ec_bytes_in_group1 != numEcBytesInGroup2 {
|
||||||
return Err(Exceptions::WriterException("EC bytes mismatch".to_owned()));
|
return Err(Exceptions::WriterException("EC bytes mismatch".to_owned()));
|
||||||
// throw new WriterException("EC bytes mismatch");
|
// throw new WriterException("EC bytes mismatch");
|
||||||
}
|
}
|
||||||
// 5 = 4 + 1.
|
// 5 = 4 + 1.
|
||||||
if numRSBlocks != numRsBlocksInGroup1 + numRsBlocksInGroup2 {
|
if num_rsblocks != num_rs_blocks_in_group1 + num_rs_blocks_in_group2 {
|
||||||
return Err(Exceptions::WriterException("RS blocks mismatch".to_owned()));
|
return Err(Exceptions::WriterException("RS blocks mismatch".to_owned()));
|
||||||
|
|
||||||
// throw new WriterException("RS blocks mismatch");
|
// throw new WriterException("RS blocks mismatch");
|
||||||
}
|
}
|
||||||
// 196 = (13 + 26) * 4 + (14 + 26) * 1
|
// 196 = (13 + 26) * 4 + (14 + 26) * 1
|
||||||
if numTotalBytes
|
if num_total_bytes
|
||||||
!= ((numDataBytesInGroup1 + numEcBytesInGroup1) * numRsBlocksInGroup1)
|
!= ((num_data_bytes_in_group1 + num_ec_bytes_in_group1) * num_rs_blocks_in_group1)
|
||||||
+ ((numDataBytesInGroup2 + numEcBytesInGroup2) * numRsBlocksInGroup2)
|
+ ((num_data_bytes_in_group2 + numEcBytesInGroup2) * num_rs_blocks_in_group2)
|
||||||
{
|
{
|
||||||
return Err(Exceptions::WriterException(
|
return Err(Exceptions::WriterException(
|
||||||
"Total bytes mismatch".to_owned(),
|
"Total bytes mismatch".to_owned(),
|
||||||
@@ -547,10 +547,10 @@ pub fn getNumDataBytesAndNumECBytesForBlockID(
|
|||||||
// throw new WriterException("Total bytes mismatch");
|
// throw new WriterException("Total bytes mismatch");
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(if blockID < numRsBlocksInGroup1 {
|
Ok(if block_id < num_rs_blocks_in_group1 {
|
||||||
(numDataBytesInGroup1, numEcBytesInGroup1)
|
(num_data_bytes_in_group1, num_ec_bytes_in_group1)
|
||||||
} else {
|
} else {
|
||||||
(numDataBytesInGroup2, numEcBytesInGroup2)
|
(num_data_bytes_in_group2, numEcBytesInGroup2)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -560,12 +560,12 @@ pub fn getNumDataBytesAndNumECBytesForBlockID(
|
|||||||
*/
|
*/
|
||||||
pub fn interleaveWithECBytes(
|
pub fn interleaveWithECBytes(
|
||||||
bits: &BitArray,
|
bits: &BitArray,
|
||||||
numTotalBytes: u32,
|
num_total_bytes: u32,
|
||||||
numDataBytes: u32,
|
num_data_bytes: u32,
|
||||||
numRSBlocks: u32,
|
num_rsblocks: u32,
|
||||||
) -> Result<BitArray, Exceptions> {
|
) -> Result<BitArray, Exceptions> {
|
||||||
// "bits" must have "getNumDataBytes" bytes of data.
|
// "bits" must have "getNumDataBytes" bytes of data.
|
||||||
if bits.getSizeInBytes() as u32 != numDataBytes {
|
if bits.getSizeInBytes() as u32 != num_data_bytes {
|
||||||
return Err(Exceptions::WriterException(
|
return Err(Exceptions::WriterException(
|
||||||
"Number of bits and data bytes does not match".to_owned(),
|
"Number of bits and data bytes does not match".to_owned(),
|
||||||
));
|
));
|
||||||
@@ -573,21 +573,21 @@ pub fn interleaveWithECBytes(
|
|||||||
|
|
||||||
// Step 1. Divide data bytes into blocks and generate error correction bytes for them. We'll
|
// Step 1. Divide data bytes into blocks and generate error correction bytes for them. We'll
|
||||||
// store the divided data bytes blocks and error correction bytes blocks into "blocks".
|
// store the divided data bytes blocks and error correction bytes blocks into "blocks".
|
||||||
let mut dataBytesOffset = 0;
|
let mut data_bytes_offset = 0;
|
||||||
let mut maxNumDataBytes = 0;
|
let mut max_num_data_bytes = 0;
|
||||||
let mut maxNumEcBytes = 0;
|
let mut max_num_ec_bytes = 0;
|
||||||
|
|
||||||
// Since, we know the number of reedsolmon blocks, we can initialize the vector with the number.
|
// Since, we know the number of reedsolmon blocks, we can initialize the vector with the number.
|
||||||
let mut blocks = Vec::new();
|
let mut blocks = Vec::new();
|
||||||
|
|
||||||
for i in 0..numRSBlocks {
|
for i in 0..num_rsblocks {
|
||||||
// for (int i = 0; i < numRSBlocks; ++i) {
|
// for (int i = 0; i < numRSBlocks; ++i) {
|
||||||
// let mut numDataBytesInBlock = vec![0; 1]; //new int[1];
|
// let mut numDataBytesInBlock = vec![0; 1]; //new int[1];
|
||||||
// let mut numEcBytesInBlock = vec![0; 1]; //new int[1];
|
// let mut numEcBytesInBlock = vec![0; 1]; //new int[1];
|
||||||
let (numDataBytesInBlock, numEcBytesInBlock) = getNumDataBytesAndNumECBytesForBlockID(
|
let (numDataBytesInBlock, numEcBytesInBlock) = getNumDataBytesAndNumECBytesForBlockID(
|
||||||
numTotalBytes,
|
num_total_bytes,
|
||||||
numDataBytes,
|
num_data_bytes,
|
||||||
numRSBlocks,
|
num_rsblocks,
|
||||||
i,
|
i,
|
||||||
// &mut numDataBytesInBlock,
|
// &mut numDataBytesInBlock,
|
||||||
// &mut numEcBytesInBlock,
|
// &mut numEcBytesInBlock,
|
||||||
@@ -595,15 +595,15 @@ pub fn interleaveWithECBytes(
|
|||||||
|
|
||||||
let size = numDataBytesInBlock;
|
let size = numDataBytesInBlock;
|
||||||
let mut dataBytes = vec![0u8; size as usize];
|
let mut dataBytes = vec![0u8; size as usize];
|
||||||
bits.toBytes(8 * dataBytesOffset, &mut dataBytes, 0, size as usize);
|
bits.toBytes(8 * data_bytes_offset, &mut dataBytes, 0, size as usize);
|
||||||
let ecBytes = generateECBytes(&dataBytes, numEcBytesInBlock as usize);
|
let ec_bytes = generateECBytes(&dataBytes, numEcBytesInBlock as usize);
|
||||||
blocks.push(BlockPair::new(dataBytes, ecBytes.clone()));
|
blocks.push(BlockPair::new(dataBytes, ec_bytes.clone()));
|
||||||
|
|
||||||
maxNumDataBytes = maxNumDataBytes.max(size);
|
max_num_data_bytes = max_num_data_bytes.max(size);
|
||||||
maxNumEcBytes = maxNumEcBytes.max(ecBytes.len());
|
max_num_ec_bytes = max_num_ec_bytes.max(ec_bytes.len());
|
||||||
dataBytesOffset += numDataBytesInBlock as usize;
|
data_bytes_offset += numDataBytesInBlock as usize;
|
||||||
}
|
}
|
||||||
if numDataBytes != dataBytesOffset as u32 {
|
if num_data_bytes != data_bytes_offset as u32 {
|
||||||
return Err(Exceptions::WriterException(
|
return Err(Exceptions::WriterException(
|
||||||
"Data bytes does not match offset".to_owned(),
|
"Data bytes does not match offset".to_owned(),
|
||||||
));
|
));
|
||||||
@@ -612,32 +612,32 @@ pub fn interleaveWithECBytes(
|
|||||||
let mut result = BitArray::new();
|
let mut result = BitArray::new();
|
||||||
|
|
||||||
// First, place data blocks.
|
// First, place data blocks.
|
||||||
for i in 0..maxNumDataBytes as usize {
|
for i in 0..max_num_data_bytes as usize {
|
||||||
// for (int i = 0; i < maxNumDataBytes; ++i) {
|
// for (int i = 0; i < maxNumDataBytes; ++i) {
|
||||||
for block in &blocks {
|
for block in &blocks {
|
||||||
// for (BlockPair block : blocks) {
|
// for (BlockPair block : blocks) {
|
||||||
let dataBytes = block.getDataBytes();
|
let data_bytes = block.getDataBytes();
|
||||||
if i < dataBytes.len() {
|
if i < data_bytes.len() {
|
||||||
result.appendBits(dataBytes[i] as u32, 8)?;
|
result.appendBits(data_bytes[i] as u32, 8)?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Then, place error correction blocks.
|
// Then, place error correction blocks.
|
||||||
for i in 0..maxNumEcBytes {
|
for i in 0..max_num_ec_bytes {
|
||||||
// for (int i = 0; i < maxNumEcBytes; ++i) {
|
// for (int i = 0; i < maxNumEcBytes; ++i) {
|
||||||
for block in &blocks {
|
for block in &blocks {
|
||||||
// for (BlockPair block : blocks) {
|
// for (BlockPair block : blocks) {
|
||||||
let ecBytes = block.getErrorCorrectionBytes();
|
let ec_bytes = block.getErrorCorrectionBytes();
|
||||||
if i < ecBytes.len() {
|
if i < ec_bytes.len() {
|
||||||
result.appendBits(ecBytes[i] as u32, 8)?;
|
result.appendBits(ec_bytes[i] as u32, 8)?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if numTotalBytes != result.getSizeInBytes() as u32 {
|
if num_total_bytes != result.getSizeInBytes() as u32 {
|
||||||
// Should be same.
|
// Should be same.
|
||||||
return Err(Exceptions::WriterException(format!(
|
return Err(Exceptions::WriterException(format!(
|
||||||
"Interleaving error: {} and {} differ.",
|
"Interleaving error: {} and {} differ.",
|
||||||
numTotalBytes,
|
num_total_bytes,
|
||||||
result.getSizeInBytes()
|
result.getSizeInBytes()
|
||||||
)));
|
)));
|
||||||
// throw new WriterException("Interleaving error: " + numTotalBytes + " and " +
|
// throw new WriterException("Interleaving error: " + numTotalBytes + " and " +
|
||||||
@@ -647,24 +647,24 @@ pub fn interleaveWithECBytes(
|
|||||||
Ok(result)
|
Ok(result)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn generateECBytes(dataBytes: &[u8], numEcBytesInBlock: usize) -> Vec<u8> {
|
pub fn generateECBytes(dataBytes: &[u8], num_ec_bytes_in_block: usize) -> Vec<u8> {
|
||||||
let numDataBytes = dataBytes.len();
|
let num_data_bytes = dataBytes.len();
|
||||||
let mut toEncode = vec![0; numDataBytes + numEcBytesInBlock];
|
let mut to_encode = vec![0; num_data_bytes + num_ec_bytes_in_block];
|
||||||
for i in 0..numDataBytes {
|
for i in 0..num_data_bytes {
|
||||||
// for (int i = 0; i < numDataBytes; i++) {
|
// for (int i = 0; i < numDataBytes; i++) {
|
||||||
toEncode[i] = dataBytes[i] as i32;
|
to_encode[i] = dataBytes[i] as i32;
|
||||||
}
|
}
|
||||||
|
|
||||||
ReedSolomonEncoder::new(get_predefined_genericgf(
|
ReedSolomonEncoder::new(get_predefined_genericgf(
|
||||||
PredefinedGenericGF::QrCodeField256,
|
PredefinedGenericGF::QrCodeField256,
|
||||||
))
|
))
|
||||||
.encode(&mut toEncode, numEcBytesInBlock)
|
.encode(&mut to_encode, num_ec_bytes_in_block)
|
||||||
.expect("rs encode must complete");
|
.expect("rs encode must complete");
|
||||||
|
|
||||||
let mut ecBytes = vec![0u8; numEcBytesInBlock];
|
let mut ecBytes = vec![0u8; num_ec_bytes_in_block];
|
||||||
for i in 0..numEcBytesInBlock {
|
for i in 0..num_ec_bytes_in_block {
|
||||||
// for (int i = 0; i < numEcBytesInBlock; i++) {
|
// for (int i = 0; i < numEcBytesInBlock; i++) {
|
||||||
ecBytes[i] = toEncode[numDataBytes + i] as u8;
|
ecBytes[i] = to_encode[num_data_bytes + i] as u8;
|
||||||
}
|
}
|
||||||
return ecBytes;
|
return ecBytes;
|
||||||
}
|
}
|
||||||
@@ -681,20 +681,20 @@ pub fn appendModeInfo(mode: Mode, bits: &mut BitArray) -> Result<(), Exceptions>
|
|||||||
* Append length info. On success, store the result in "bits".
|
* Append length info. On success, store the result in "bits".
|
||||||
*/
|
*/
|
||||||
pub fn appendLengthInfo(
|
pub fn appendLengthInfo(
|
||||||
numLetters: u32,
|
num_letters: u32,
|
||||||
version: VersionRef,
|
version: VersionRef,
|
||||||
mode: Mode,
|
mode: Mode,
|
||||||
bits: &mut BitArray,
|
bits: &mut BitArray,
|
||||||
) -> Result<(), Exceptions> {
|
) -> Result<(), Exceptions> {
|
||||||
let numBits = mode.getCharacterCountBits(version);
|
let numBits = mode.getCharacterCountBits(version);
|
||||||
if numLetters >= (1 << numBits) {
|
if num_letters >= (1 << numBits) {
|
||||||
return Err(Exceptions::WriterException(format!(
|
return Err(Exceptions::WriterException(format!(
|
||||||
"{} is bigger than {}",
|
"{} is bigger than {}",
|
||||||
numLetters,
|
num_letters,
|
||||||
((1 << numBits) - 1)
|
((1 << numBits) - 1)
|
||||||
)));
|
)));
|
||||||
}
|
}
|
||||||
bits.appendBits(numLetters, numBits as usize)?;
|
bits.appendBits(num_letters, numBits as usize)?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user