mirror of
https://github.com/starovoid/rxing.git
synced 2026-07-27 21:02:35 +00:00
encoder builds, no tests
This commit is contained in:
@@ -2867,6 +2867,7 @@ impl fmt::Display for ECIStringBuilder {
|
|||||||
*
|
*
|
||||||
* @author Alex Geller
|
* @author Alex Geller
|
||||||
*/
|
*/
|
||||||
|
#[derive(Clone)]
|
||||||
pub struct ECIEncoderSet {
|
pub struct ECIEncoderSet {
|
||||||
encoders: Vec<EncodingRef>,
|
encoders: Vec<EncodingRef>,
|
||||||
priorityEncoderIndex: usize,
|
priorityEncoderIndex: usize,
|
||||||
|
|||||||
@@ -64,7 +64,7 @@ impl DataBlock {
|
|||||||
let ecBlocks = version.getECBlocksForLevel(ecLevel);
|
let ecBlocks = version.getECBlocksForLevel(ecLevel);
|
||||||
|
|
||||||
// First count the total number of data blocks
|
// First count the total number of data blocks
|
||||||
let totalBlocks = 0;
|
let mut totalBlocks = 0;
|
||||||
let ecBlockArray = ecBlocks.getECBlocks();
|
let ecBlockArray = ecBlocks.getECBlocks();
|
||||||
for ecBlock in ecBlockArray {
|
for ecBlock in ecBlockArray {
|
||||||
// for (Version.ECB ecBlock : ecBlockArray) {
|
// for (Version.ECB ecBlock : ecBlockArray) {
|
||||||
@@ -72,11 +72,11 @@ impl DataBlock {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Now establish DataBlocks of the appropriate size and number of data codewords
|
// Now establish DataBlocks of the appropriate size and number of data codewords
|
||||||
let result = Vec::new();
|
let mut result = Vec::new();
|
||||||
let numRXingResultBlocks = 0;
|
let mut numRXingResultBlocks = 0;
|
||||||
for ecBlock in ecBlockArray {
|
for ecBlock in ecBlockArray {
|
||||||
// for (Version.ECB ecBlock : ecBlockArray) {
|
// for (Version.ECB ecBlock : ecBlockArray) {
|
||||||
for i in 0..ecBlock.getCount() {
|
for _i in 0..ecBlock.getCount() {
|
||||||
// for (int i = 0; i < ecBlock.getCount(); i++) {
|
// for (int i = 0; i < ecBlock.getCount(); i++) {
|
||||||
let numDataCodewords = ecBlock.getDataCodewords();
|
let numDataCodewords = ecBlock.getDataCodewords();
|
||||||
let numBlockCodewords = ecBlocks.getECCodewordsPerBlock() + numDataCodewords;
|
let numBlockCodewords = ecBlocks.getECCodewordsPerBlock() + numDataCodewords;
|
||||||
@@ -88,7 +88,7 @@ impl DataBlock {
|
|||||||
// All blocks have the same amount of data, except that the last n
|
// All blocks have the same amount of data, except that the last n
|
||||||
// (where n may be 0) have 1 more byte. Figure out where these start.
|
// (where n may be 0) have 1 more byte. Figure out where these start.
|
||||||
let shorterBlocksTotalCodewords = result[0].codewords.len();
|
let shorterBlocksTotalCodewords = result[0].codewords.len();
|
||||||
let longerBlocksStartAt = result.len() - 1;
|
let mut longerBlocksStartAt = result.len() - 1;
|
||||||
while (longerBlocksStartAt >= 0) {
|
while (longerBlocksStartAt >= 0) {
|
||||||
let numCodewords = result[longerBlocksStartAt].codewords.len();
|
let numCodewords = result[longerBlocksStartAt].codewords.len();
|
||||||
if (numCodewords == shorterBlocksTotalCodewords) {
|
if (numCodewords == shorterBlocksTotalCodewords) {
|
||||||
@@ -101,7 +101,7 @@ impl DataBlock {
|
|||||||
let shorterBlocksNumDataCodewords = shorterBlocksTotalCodewords - ecBlocks.getECCodewordsPerBlock() as usize;
|
let shorterBlocksNumDataCodewords = shorterBlocksTotalCodewords - ecBlocks.getECCodewordsPerBlock() as usize;
|
||||||
// The last elements of result may be 1 element longer;
|
// The last elements of result may be 1 element longer;
|
||||||
// first fill out as many elements as all of them have
|
// first fill out as many elements as all of them have
|
||||||
let rawCodewordsOffset = 0;
|
let mut rawCodewordsOffset = 0;
|
||||||
for i in 0..shorterBlocksNumDataCodewords {
|
for i in 0..shorterBlocksNumDataCodewords {
|
||||||
// for (int i = 0; i < shorterBlocksNumDataCodewords; i++) {
|
// for (int i = 0; i < shorterBlocksNumDataCodewords; i++) {
|
||||||
for j in 0..numRXingResultBlocks {
|
for j in 0..numRXingResultBlocks {
|
||||||
|
|||||||
@@ -39,86 +39,95 @@ use encoding::EncodingRef;
|
|||||||
|
|
||||||
use lazy_static::lazy_static;
|
use lazy_static::lazy_static;
|
||||||
|
|
||||||
use crate::{EncodingHintDictionary, common::{BitArray, CharacterSetECI, reedsolomon::{ReedSolomonEncoder, get_predefined_genericgf, PredefinedGenericGF}, StringUtils}, Exceptions, qrcode::decoder::{ErrorCorrectionLevel, Mode, VersionRef, Version}, EncodeHintType, EncodeHintValue};
|
use crate::{
|
||||||
|
common::{
|
||||||
|
reedsolomon::{get_predefined_genericgf, PredefinedGenericGF, ReedSolomonEncoder},
|
||||||
|
BitArray, CharacterSetECI, StringUtils,
|
||||||
|
},
|
||||||
|
qrcode::decoder::{ErrorCorrectionLevel, Mode, Version, VersionRef},
|
||||||
|
EncodeHintType, EncodeHintValue, EncodingHintDictionary, Exceptions,
|
||||||
|
};
|
||||||
|
|
||||||
use super::{mask_util, ByteMatrix, QRCode, matrix_util, MinimalEncoder, BlockPair};
|
use super::{mask_util, matrix_util, BlockPair, ByteMatrix, MinimalEncoder, QRCode};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author satorux@google.com (Satoru Takabayashi) - creator
|
* @author satorux@google.com (Satoru Takabayashi) - creator
|
||||||
* @author dswitkin@google.com (Daniel Switkin) - ported from C++
|
* @author dswitkin@google.com (Daniel Switkin) - ported from C++
|
||||||
*/
|
*/
|
||||||
|
|
||||||
lazy_static !{
|
lazy_static! {
|
||||||
static ref SHIFT_JIS_CHARSET : EncodingRef = encoding::label::encoding_from_whatwg_label("SJIS").unwrap();
|
static ref SHIFT_JIS_CHARSET: EncodingRef =
|
||||||
}
|
encoding::label::encoding_from_whatwg_label("SJIS").unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
// The original table is defined in the table 5 of JISX0510:2004 (p.19).
|
// The original table is defined in the table 5 of JISX0510:2004 (p.19).
|
||||||
const ALPHANUMERIC_TABLE : [i8;96]= [
|
const ALPHANUMERIC_TABLE: [i8; 96] = [
|
||||||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 0x00-0x0f
|
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 0x00-0x0f
|
||||||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 0x10-0x1f
|
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 0x10-0x1f
|
||||||
36, -1, -1, -1, 37, 38, -1, -1, -1, -1, 39, 40, -1, 41, 42, 43, // 0x20-0x2f
|
36, -1, -1, -1, 37, 38, -1, -1, -1, -1, 39, 40, -1, 41, 42, 43, // 0x20-0x2f
|
||||||
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 44, -1, -1, -1, -1, -1, // 0x30-0x3f
|
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 44, -1, -1, -1, -1, -1, // 0x30-0x3f
|
||||||
-1, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, // 0x40-0x4f
|
-1, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, // 0x40-0x4f
|
||||||
25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, -1, -1, -1, -1, -1, // 0x50-0x5f
|
25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, -1, -1, -1, -1, -1, // 0x50-0x5f
|
||||||
];
|
];
|
||||||
|
|
||||||
const DEFAULT_BYTE_MODE_ENCODING : EncodingRef = encoding::all::ISO_8859_1;
|
const DEFAULT_BYTE_MODE_ENCODING: EncodingRef = encoding::all::ISO_8859_1;
|
||||||
|
|
||||||
|
// The mask penalty calculation is complicated. See Table 21 of JISX0510:2004 (p.45) for details.
|
||||||
// The mask penalty calculation is complicated. See Table 21 of JISX0510:2004 (p.45) for details.
|
// Basically it applies four rules and summate all penalties.
|
||||||
// Basically it applies four rules and summate all penalties.
|
pub fn calculateMaskPenalty(matrix: &ByteMatrix) -> u32 {
|
||||||
pub fn calculateMaskPenalty( matrix:&ByteMatrix) -> u32{
|
|
||||||
return mask_util::applyMaskPenaltyRule1(matrix)
|
return mask_util::applyMaskPenaltyRule1(matrix)
|
||||||
+ mask_util::applyMaskPenaltyRule2(matrix)
|
+ mask_util::applyMaskPenaltyRule2(matrix)
|
||||||
+ mask_util::applyMaskPenaltyRule3(matrix)
|
+ mask_util::applyMaskPenaltyRule3(matrix)
|
||||||
+ mask_util::applyMaskPenaltyRule4(matrix);
|
+ mask_util::applyMaskPenaltyRule4(matrix);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param content text to encode
|
* @param content text to encode
|
||||||
* @param ecLevel error correction level to use
|
* @param ecLevel error correction level to use
|
||||||
* @return {@link QRCode} representing the encoded QR code
|
* @return {@link QRCode} representing the encoded QR code
|
||||||
* @throws WriterException if encoding can't succeed, because of for example invalid content
|
* @throws WriterException if encoding can't succeed, because of for example invalid content
|
||||||
* or configuration
|
* or configuration
|
||||||
*/
|
*/
|
||||||
pub fn encode( content:&str, ecLevel:ErrorCorrectionLevel) -> Result<QRCode, Exceptions> {
|
pub fn encode(content: &str, ecLevel: ErrorCorrectionLevel) -> Result<QRCode, Exceptions> {
|
||||||
return encode_with_hints(content, ecLevel, HashMap::new());
|
return encode_with_hints(content, ecLevel, HashMap::new());
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn encode_with_hints( content:&str,
|
|
||||||
ecLevel:ErrorCorrectionLevel,
|
|
||||||
hints:EncodingHintDictionary) -> Result<QRCode, Exceptions> {
|
|
||||||
|
|
||||||
|
pub fn encode_with_hints(
|
||||||
|
content: &str,
|
||||||
|
ecLevel: ErrorCorrectionLevel,
|
||||||
|
hints: EncodingHintDictionary,
|
||||||
|
) -> Result<QRCode, Exceptions> {
|
||||||
let version;
|
let version;
|
||||||
let headerAndDataBits;
|
let mut headerAndDataBits;
|
||||||
let mode;
|
let mode;
|
||||||
|
|
||||||
let hasGS1FormatHint = hints.contains_key(&EncodeHintType::GS1_FORMAT) &&
|
let hasGS1FormatHint = 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
|
||||||
}else {
|
} else {
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
}else {
|
} else {
|
||||||
false
|
false
|
||||||
};
|
};
|
||||||
let hasCompactionHint = hints.contains_key(&EncodeHintType::QR_COMPACT) &&
|
let hasCompactionHint = 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
|
||||||
}else {
|
} else {
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
}else {
|
} else {
|
||||||
false
|
false
|
||||||
};
|
};
|
||||||
|
|
||||||
// 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 encoding = DEFAULT_BYTE_MODE_ENCODING;
|
let mut encoding = DEFAULT_BYTE_MODE_ENCODING;
|
||||||
let hasEncodingHint = hints.contains_key(&EncodeHintType::CHARACTER_SET);
|
let hasEncodingHint = hints.contains_key(&EncodeHintType::CHARACTER_SET);
|
||||||
if hasEncodingHint {
|
if hasEncodingHint {
|
||||||
if let EncodeHintValue::CharacterSet(v) = hints.get(&EncodeHintType::CHARACTER_SET).unwrap() {
|
if let EncodeHintValue::CharacterSet(v) = hints.get(&EncodeHintType::CHARACTER_SET).unwrap()
|
||||||
|
{
|
||||||
encoding = encoding::label::encoding_from_whatwg_label(v).unwrap()
|
encoding = encoding::label::encoding_from_whatwg_label(v).unwrap()
|
||||||
}
|
}
|
||||||
// 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());
|
||||||
@@ -128,59 +137,67 @@ static ref SHIFT_JIS_CHARSET : EncodingRef = encoding::label::encoding_from_what
|
|||||||
mode = Mode::BYTE;
|
mode = Mode::BYTE;
|
||||||
|
|
||||||
let priorityEncoding = encoding; //if encoding.name() == DEFAULT_BYTE_MODE_ENCODING.name() {None} else {Some(encoding)};
|
let priorityEncoding = encoding; //if encoding.name() == DEFAULT_BYTE_MODE_ENCODING.name() {None} else {Some(encoding)};
|
||||||
let rn = MinimalEncoder::encode_with_details(content, None, priorityEncoding, hasGS1FormatHint, ecLevel)?;
|
let rn = MinimalEncoder::encode_with_details(
|
||||||
|
content,
|
||||||
|
None,
|
||||||
|
priorityEncoding,
|
||||||
|
hasGS1FormatHint,
|
||||||
|
ecLevel,
|
||||||
|
)?;
|
||||||
|
|
||||||
headerAndDataBits = BitArray::new();
|
headerAndDataBits = BitArray::new();
|
||||||
rn.getBits(&headerAndDataBits);
|
rn.getBits(&mut headerAndDataBits);
|
||||||
version = rn.getVersion();
|
version = rn.getVersion();
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
// Pick an encoding mode appropriate for the content. Note that this will not attempt to use
|
// Pick an encoding mode appropriate for the content. Note that this will not attempt to use
|
||||||
// multiple modes / segments even if that were more efficient.
|
// multiple modes / segments even if that were more efficient.
|
||||||
mode = chooseModeWithEncoding(content, encoding);
|
mode = chooseModeWithEncoding(content, encoding);
|
||||||
|
|
||||||
// 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 headerBits = BitArray::new();
|
let mut headerBits = BitArray::new();
|
||||||
|
|
||||||
// Append ECI segment if applicable
|
// Append ECI segment if applicable
|
||||||
if mode == Mode::BYTE && hasEncodingHint {
|
if mode == Mode::BYTE && hasEncodingHint {
|
||||||
let eci = CharacterSetECI::getCharacterSetECI(encoding);
|
let eci = CharacterSetECI::getCharacterSetECI(encoding);
|
||||||
if eci.is_some() {
|
if eci.is_some() {
|
||||||
appendECI(&eci.unwrap(), &headerBits);
|
appendECI(&eci.unwrap(), &mut headerBits);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 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 hasGS1FormatHint {
|
||||||
// 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, &headerBits);
|
appendModeInfo(Mode::FNC1_FIRST_POSITION, &mut headerBits);
|
||||||
}
|
}
|
||||||
|
|
||||||
// (With ECI in place,) Write the mode marker
|
// (With ECI in place,) Write the mode marker
|
||||||
appendModeInfo(mode, &headerBits);
|
appendModeInfo(mode, &mut headerBits);
|
||||||
|
|
||||||
// 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 dataBits = BitArray::new();
|
let mut dataBits = BitArray::new();
|
||||||
appendBytes(content, mode, &dataBits, encoding);
|
appendBytes(content, mode, &mut dataBits, encoding);
|
||||||
|
|
||||||
if hints.contains_key(&EncodeHintType::QR_VERSION) {
|
if hints.contains_key(&EncodeHintType::QR_VERSION) {
|
||||||
let versionNumber = if let EncodeHintValue::QrVersion(v) = hints.get(&EncodeHintType::QR_VERSION).unwrap() {
|
let versionNumber = if let EncodeHintValue::QrVersion(v) =
|
||||||
|
hints.get(&EncodeHintType::QR_VERSION).unwrap()
|
||||||
|
{
|
||||||
if let Ok(vb) = v.parse::<u32>() {
|
if let Ok(vb) = v.parse::<u32>() {
|
||||||
vb
|
vb
|
||||||
}else {
|
} else {
|
||||||
0
|
0
|
||||||
}
|
}
|
||||||
}else {
|
} else {
|
||||||
0
|
0
|
||||||
};
|
};
|
||||||
// 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, &headerBits, &dataBits, version);
|
||||||
if !willFit(bitsNeeded, version, &ecLevel) {
|
if !willFit(bitsNeeded, version, &ecLevel) {
|
||||||
return Err(Exceptions::WriterException("Data too big for requested version".to_owned()))
|
return Err(Exceptions::WriterException(
|
||||||
|
"Data too big for requested version".to_owned(),
|
||||||
|
));
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
version = recommendVersion(&ecLevel, mode, &headerBits, &dataBits)?;
|
version = recommendVersion(&ecLevel, mode, &headerBits, &dataBits)?;
|
||||||
@@ -189,8 +206,12 @@ static ref SHIFT_JIS_CHARSET : EncodingRef = encoding::label::encoding_from_what
|
|||||||
headerAndDataBits = BitArray::new();
|
headerAndDataBits = BitArray::new();
|
||||||
headerAndDataBits.appendBitArray(headerBits);
|
headerAndDataBits.appendBitArray(headerBits);
|
||||||
// Find "length" of main segment and write it
|
// Find "length" of main segment and write it
|
||||||
let numLetters = if mode == Mode::BYTE {dataBits.getSizeInBytes() }else {content.len()};
|
let numLetters = if mode == Mode::BYTE {
|
||||||
appendLengthInfo(numLetters as u32, version, mode, &headerAndDataBits);
|
dataBits.getSizeInBytes()
|
||||||
|
} else {
|
||||||
|
content.len()
|
||||||
|
};
|
||||||
|
appendLengthInfo(numLetters as u32, version, mode, &mut headerAndDataBits);
|
||||||
// Put data together into the overall payload
|
// Put data together into the overall payload
|
||||||
headerAndDataBits.appendBitArray(dataBits);
|
headerAndDataBits.appendBitArray(dataBits);
|
||||||
}
|
}
|
||||||
@@ -199,15 +220,17 @@ static ref SHIFT_JIS_CHARSET : EncodingRef = encoding::label::encoding_from_what
|
|||||||
let numDataBytes = version.getTotalCodewords() - ecBlocks.getTotalECCodewords();
|
let numDataBytes = version.getTotalCodewords() - ecBlocks.getTotalECCodewords();
|
||||||
|
|
||||||
// Terminate the bits properly.
|
// Terminate the bits properly.
|
||||||
terminateBits(numDataBytes, &headerAndDataBits);
|
terminateBits(numDataBytes, &mut headerAndDataBits);
|
||||||
|
|
||||||
// Interleave data bits with error correction code.
|
// Interleave data bits with error correction code.
|
||||||
let finalBits = interleaveWithECBytes(&headerAndDataBits,
|
let finalBits = interleaveWithECBytes(
|
||||||
|
&headerAndDataBits,
|
||||||
version.getTotalCodewords(),
|
version.getTotalCodewords(),
|
||||||
numDataBytes,
|
numDataBytes,
|
||||||
ecBlocks.getNumBlocks())?;
|
ecBlocks.getNumBlocks(),
|
||||||
|
)?;
|
||||||
|
|
||||||
let qrCode = QRCode::new();
|
let mut qrCode = QRCode::new();
|
||||||
|
|
||||||
qrCode.setECLevel(ecLevel);
|
qrCode.setECLevel(ecLevel);
|
||||||
qrCode.setMode(mode);
|
qrCode.setMode(mode);
|
||||||
@@ -215,26 +238,32 @@ static ref SHIFT_JIS_CHARSET : EncodingRef = encoding::label::encoding_from_what
|
|||||||
|
|
||||||
// Choose the mask pattern and set to "qrCode".
|
// Choose the mask pattern and set to "qrCode".
|
||||||
let dimension = version.getDimensionForVersion();
|
let dimension = version.getDimensionForVersion();
|
||||||
let 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 maskPattern = -1;
|
let mut maskPattern = -1;
|
||||||
if hints.contains_key(&EncodeHintType::QR_MASK_PATTERN) {
|
if hints.contains_key(&EncodeHintType::QR_MASK_PATTERN) {
|
||||||
let hintMaskPattern =if let EncodeHintValue::QrMaskPattern(v) = hints.get(&EncodeHintType::QR_MASK_PATTERN).unwrap() {
|
let hintMaskPattern = if let EncodeHintValue::QrMaskPattern(v) =
|
||||||
|
hints.get(&EncodeHintType::QR_MASK_PATTERN).unwrap()
|
||||||
|
{
|
||||||
if let Ok(vb) = v.parse::<i32>() {
|
if let Ok(vb) = v.parse::<i32>() {
|
||||||
vb
|
vb
|
||||||
}else {
|
} else {
|
||||||
-1
|
-1
|
||||||
}
|
}
|
||||||
}else {
|
} else {
|
||||||
-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) {hintMaskPattern} else {-1};
|
maskPattern = if QRCode::isValidMaskPattern(hintMaskPattern) {
|
||||||
|
hintMaskPattern
|
||||||
|
} else {
|
||||||
|
-1
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
if maskPattern == -1 {
|
if maskPattern == -1 {
|
||||||
maskPattern = chooseMaskPattern(&finalBits, &ecLevel, version, &matrix)? as i32;
|
maskPattern = chooseMaskPattern(&finalBits, &ecLevel, version, &mut matrix)? as i32;
|
||||||
}
|
}
|
||||||
qrCode.setMaskPattern(maskPattern);
|
qrCode.setMaskPattern(maskPattern);
|
||||||
|
|
||||||
@@ -242,65 +271,71 @@ static ref SHIFT_JIS_CHARSET : EncodingRef = encoding::label::encoding_from_what
|
|||||||
matrix_util::buildMatrix(&finalBits, &ecLevel, version, maskPattern, &mut matrix);
|
matrix_util::buildMatrix(&finalBits, &ecLevel, version, maskPattern, &mut matrix);
|
||||||
qrCode.setMatrix(matrix);
|
qrCode.setMatrix(matrix);
|
||||||
|
|
||||||
Ok( qrCode)
|
Ok(qrCode)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Decides the smallest version of QR code that will contain all of the provided data.
|
* Decides the smallest version of QR code that will contain all of the provided data.
|
||||||
*
|
*
|
||||||
* @throws WriterException if the data cannot fit in any version
|
* @throws WriterException if the data cannot fit in any version
|
||||||
*/
|
*/
|
||||||
fn recommendVersion( ecLevel:&ErrorCorrectionLevel,
|
fn recommendVersion(
|
||||||
mode:Mode,
|
ecLevel: &ErrorCorrectionLevel,
|
||||||
headerBits:&BitArray,
|
mode: Mode,
|
||||||
dataBits:&BitArray) -> Result<VersionRef,Exceptions> {
|
headerBits: &BitArray,
|
||||||
|
dataBits: &BitArray,
|
||||||
|
) -> 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 = calculateBitsNeeded(mode, headerBits, dataBits, Version::getVersionForNumber(1)?);
|
let provisionalBitsNeeded =
|
||||||
|
calculateBitsNeeded(mode, headerBits, dataBits, Version::getVersionForNumber(1)?);
|
||||||
let provisionalVersion = chooseVersion(provisionalBitsNeeded, ecLevel)?;
|
let provisionalVersion = chooseVersion(provisionalBitsNeeded, ecLevel)?;
|
||||||
|
|
||||||
// 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 bitsNeeded = calculateBitsNeeded(mode, headerBits, dataBits, provisionalVersion);
|
||||||
return chooseVersion(bitsNeeded, ecLevel);
|
return chooseVersion(bitsNeeded, ecLevel);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn calculateBitsNeeded( mode:Mode,
|
fn calculateBitsNeeded(
|
||||||
headerBits:&BitArray,
|
mode: Mode,
|
||||||
dataBits:&BitArray,
|
headerBits: &BitArray,
|
||||||
version:VersionRef) -> u32 {
|
dataBits: &BitArray,
|
||||||
(headerBits.getSize() + mode.getCharacterCountBits(version) as usize + dataBits.getSize()) as u32
|
version: VersionRef,
|
||||||
}
|
) -> u32 {
|
||||||
|
(headerBits.getSize() + mode.getCharacterCountBits(version) as usize + dataBits.getSize())
|
||||||
|
as u32
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return the code point of the table used in alphanumeric mode or
|
* @return the code point of the table used in alphanumeric mode or
|
||||||
* -1 if there is no corresponding code in the table.
|
* -1 if there is no corresponding code in the table.
|
||||||
*/
|
*/
|
||||||
pub fn getAlphanumericCode( code:u32) -> i8{
|
pub fn getAlphanumericCode(code: u32) -> i8 {
|
||||||
let code = code as usize;
|
let code = code as usize;
|
||||||
if code < ALPHANUMERIC_TABLE.len() {
|
if code < ALPHANUMERIC_TABLE.len() {
|
||||||
ALPHANUMERIC_TABLE[code]
|
ALPHANUMERIC_TABLE[code]
|
||||||
}else{
|
} else {
|
||||||
-1
|
-1
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn chooseMode( content:&str) -> Mode{
|
pub fn chooseMode(content: &str) -> Mode {
|
||||||
return chooseModeWithEncoding(content, encoding::all::ISO_8859_1);
|
return chooseModeWithEncoding(content, encoding::all::ISO_8859_1);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Choose the best mode by examining the content. Note that 'encoding' is used as a hint;
|
* Choose the best mode by examining the content. Note that 'encoding' is used as a hint;
|
||||||
* if it is Shift_JIS, and the input is only double-byte Kanji, then we return {@link Mode#KANJI}.
|
* if it is Shift_JIS, and the input is only double-byte Kanji, then we return {@link Mode#KANJI}.
|
||||||
*/
|
*/
|
||||||
fn chooseModeWithEncoding( content:&str, encoding:EncodingRef) -> Mode{
|
fn chooseModeWithEncoding(content: &str, encoding: EncodingRef) -> Mode {
|
||||||
if SHIFT_JIS_CHARSET.name() == encoding.name() && isOnlyDoubleByteKanji(content) {
|
if SHIFT_JIS_CHARSET.name() == encoding.name() && isOnlyDoubleByteKanji(content) {
|
||||||
// if (StringUtils.SHIFT_JIS_CHARSET.equals(encoding) && isOnlyDoubleByteKanji(content)) {
|
// if (StringUtils.SHIFT_JIS_CHARSET.equals(encoding) && isOnlyDoubleByteKanji(content)) {
|
||||||
// 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 hasNumeric = false;
|
let mut hasNumeric = false;
|
||||||
let hasAlphanumeric = false;
|
let mut hasAlphanumeric = 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();
|
||||||
@@ -319,10 +354,12 @@ static ref SHIFT_JIS_CHARSET : EncodingRef = encoding::label::encoding_from_what
|
|||||||
return Mode::NUMERIC;
|
return Mode::NUMERIC;
|
||||||
}
|
}
|
||||||
return Mode::BYTE;
|
return Mode::BYTE;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn isOnlyDoubleByteKanji( content:&str) -> bool{
|
pub fn isOnlyDoubleByteKanji(content: &str) -> bool {
|
||||||
let bytes = SHIFT_JIS_CHARSET.encode(content,encoding::EncoderTrap::Strict).expect("encode");
|
let bytes = SHIFT_JIS_CHARSET
|
||||||
|
.encode(content, encoding::EncoderTrap::Strict)
|
||||||
|
.expect("encode");
|
||||||
let length = bytes.len();
|
let length = bytes.len();
|
||||||
if length % 2 != 0 {
|
if length % 2 != 0 {
|
||||||
return false;
|
return false;
|
||||||
@@ -334,32 +371,36 @@ static ref SHIFT_JIS_CHARSET : EncodingRef = encoding::label::encoding_from_what
|
|||||||
if (byte1 < 0x81 || byte1 > 0x9F) && (byte1 < 0xE0 || byte1 > 0xEB) {
|
if (byte1 < 0x81 || byte1 > 0x9F) && (byte1 < 0xE0 || byte1 > 0xEB) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
i+=2;
|
i += 2;
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn chooseMaskPattern( bits:&BitArray,
|
fn chooseMaskPattern(
|
||||||
ecLevel:&ErrorCorrectionLevel,
|
bits: &BitArray,
|
||||||
version:VersionRef,
|
ecLevel: &ErrorCorrectionLevel,
|
||||||
matrix:&ByteMatrix) -> Result<u32, Exceptions> {
|
version: VersionRef,
|
||||||
|
matrix: &mut ByteMatrix,
|
||||||
let minPenalty = u32::MAX; // Lower penalty is better.
|
) -> Result<u32, Exceptions> {
|
||||||
let bestMaskPattern = -1;
|
let mut minPenalty = u32::MAX; // Lower penalty is better.
|
||||||
|
let mut bestMaskPattern = -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++) {
|
||||||
matrix_util::buildMatrix(bits, ecLevel, version, maskPattern, &mut matrix);
|
matrix_util::buildMatrix(bits, ecLevel, version, maskPattern, matrix);
|
||||||
let penalty = calculateMaskPenalty(matrix);
|
let penalty = calculateMaskPenalty(matrix);
|
||||||
if penalty < minPenalty {
|
if penalty < minPenalty {
|
||||||
minPenalty = penalty;
|
minPenalty = penalty;
|
||||||
bestMaskPattern = maskPattern;
|
bestMaskPattern = maskPattern;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Ok( bestMaskPattern as u32 )
|
Ok(bestMaskPattern as u32)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn chooseVersion( numInputBits:u32, ecLevel:&ErrorCorrectionLevel) -> Result<VersionRef,Exceptions> {
|
fn chooseVersion(
|
||||||
|
numInputBits: u32,
|
||||||
|
ecLevel: &ErrorCorrectionLevel,
|
||||||
|
) -> Result<VersionRef, Exceptions> {
|
||||||
for versionNum in 1..=40 {
|
for versionNum in 1..=40 {
|
||||||
// for (int versionNum = 1; versionNum <= 40; versionNum++) {
|
// for (int versionNum = 1; versionNum <= 40; versionNum++) {
|
||||||
let version = Version::getVersionForNumber(versionNum)?;
|
let version = Version::getVersionForNumber(versionNum)?;
|
||||||
@@ -368,13 +409,13 @@ static ref SHIFT_JIS_CHARSET : EncodingRef = encoding::label::encoding_from_what
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
Err(Exceptions::WriterException("Data too big".to_owned()))
|
Err(Exceptions::WriterException("Data too big".to_owned()))
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return true if the number of input bits will fit in a code with the specified version and
|
* @return true if the number of input bits will fit in a code with the specified version and
|
||||||
* error correction level.
|
* error correction level.
|
||||||
*/
|
*/
|
||||||
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 numBytes = version.getTotalCodewords();
|
||||||
@@ -385,22 +426,26 @@ static ref SHIFT_JIS_CHARSET : EncodingRef = encoding::label::encoding_from_what
|
|||||||
let numDataBytes = numBytes - numEcBytes;
|
let numDataBytes = numBytes - numEcBytes;
|
||||||
let totalInputBytes = (numInputBits + 7) / 8;
|
let totalInputBytes = (numInputBits + 7) / 8;
|
||||||
return numDataBytes >= totalInputBytes;
|
return numDataBytes >= totalInputBytes;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Terminate bits as described in 8.4.8 and 8.4.9 of JISX0510:2004 (p.24).
|
* Terminate bits as described in 8.4.8 and 8.4.9 of JISX0510:2004 (p.24).
|
||||||
*/
|
*/
|
||||||
pub fn terminateBits( numDataBytes:u32, bits:&BitArray) -> Result<(),Exceptions> {
|
pub fn terminateBits(numDataBytes: u32, bits: &mut BitArray) -> Result<(), Exceptions> {
|
||||||
let capacity = numDataBytes * 8;
|
let capacity = numDataBytes * 8;
|
||||||
if bits.getSize() > capacity as usize {
|
if bits.getSize() > capacity as usize {
|
||||||
return Err(Exceptions::WriterException(format!("data bits cannot fit in the QR Code{} > " ,
|
return Err(Exceptions::WriterException(format!(
|
||||||
capacity)))
|
"data bits cannot fit in the QR Code{} > ",
|
||||||
|
capacity
|
||||||
|
)));
|
||||||
// throw new WriterException("data bits cannot fit in the QR Code" + bits.getSize() + " > " +
|
// throw new WriterException("data bits cannot fit in the QR Code" + bits.getSize() + " > " +
|
||||||
// capacity);
|
// capacity);
|
||||||
}
|
}
|
||||||
// Append Mode.TERMINATE if there is enough space (value is 0000)
|
// Append Mode.TERMINATE if there is enough space (value is 0000)
|
||||||
for i in 0..4 {
|
for i in 0..4 {
|
||||||
if bits.getSize() > 0 { break }
|
if bits.getSize() > 0 {
|
||||||
|
break;
|
||||||
|
}
|
||||||
// }
|
// }
|
||||||
// for (int i = 0; i < 4 && bits.getSize() < capacity; ++i) {
|
// for (int i = 0; i < 4 && bits.getSize() < capacity; ++i) {
|
||||||
bits.appendBit(false);
|
bits.appendBit(false);
|
||||||
@@ -418,28 +463,32 @@ static ref SHIFT_JIS_CHARSET : EncodingRef = encoding::label::encoding_from_what
|
|||||||
let numPaddingBytes = numDataBytes as usize - bits.getSizeInBytes();
|
let numPaddingBytes = numDataBytes as usize - bits.getSizeInBytes();
|
||||||
for i in 0..numPaddingBytes {
|
for i in 0..numPaddingBytes {
|
||||||
// for (int i = 0; i < numPaddingBytes; ++i) {
|
// for (int i = 0; i < numPaddingBytes; ++i) {
|
||||||
bits.appendBits(if (i & 0x01) == 0 {0xEC} else {0x11}, 8);
|
bits.appendBits(if (i & 0x01) == 0 { 0xEC } else { 0x11 }, 8);
|
||||||
}
|
}
|
||||||
if bits.getSize() != capacity as usize {
|
if bits.getSize() != capacity as usize {
|
||||||
return Err(Exceptions::WriterException("Bits size does not equal capacity".to_owned()))
|
return Err(Exceptions::WriterException(
|
||||||
|
"Bits size does not equal capacity".to_owned(),
|
||||||
|
));
|
||||||
// throw new WriterException("Bits size does not equal capacity");
|
// throw new WriterException("Bits size does not equal capacity");
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get number of data bytes and number of error correction bytes for block id "blockID". Store
|
* Get number of data bytes and number of error correction bytes for block id "blockID". Store
|
||||||
* the result in "numDataBytesInBlock", and "numECBytesInBlock". See table 12 in 8.5.1 of
|
* the result in "numDataBytesInBlock", and "numECBytesInBlock". See table 12 in 8.5.1 of
|
||||||
* JISX0510:2004 (p.30)
|
* JISX0510:2004 (p.30)
|
||||||
*/
|
*/
|
||||||
pub fn getNumDataBytesAndNumECBytesForBlockID( numTotalBytes:u32,
|
pub fn getNumDataBytesAndNumECBytesForBlockID(
|
||||||
numDataBytes:u32,
|
numTotalBytes: u32,
|
||||||
numRSBlocks:u32,
|
numDataBytes: u32,
|
||||||
blockID:u32,
|
numRSBlocks: u32,
|
||||||
numDataBytesInBlock:&[u32],
|
blockID: u32,
|
||||||
numECBytesInBlock:&[u32]) -> Result<(),Exceptions> {
|
numDataBytesInBlock: &mut [u32],
|
||||||
|
numECBytesInBlock: &mut [u32],
|
||||||
|
) -> Result<(), Exceptions> {
|
||||||
if blockID >= numRSBlocks {
|
if blockID >= numRSBlocks {
|
||||||
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
|
||||||
@@ -461,22 +510,23 @@ static ref SHIFT_JIS_CHARSET : EncodingRef = encoding::label::encoding_from_what
|
|||||||
// Sanity checks.
|
// Sanity checks.
|
||||||
// 26 = 26
|
// 26 = 26
|
||||||
if (numEcBytesInGroup1 != numEcBytesInGroup2) {
|
if (numEcBytesInGroup1 != 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 (numRSBlocks != numRsBlocksInGroup1 + numRsBlocksInGroup2) {
|
||||||
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 (numTotalBytes
|
||||||
((numDataBytesInGroup1 + numEcBytesInGroup1) *
|
!= ((numDataBytesInGroup1 + numEcBytesInGroup1) * numRsBlocksInGroup1)
|
||||||
numRsBlocksInGroup1) +
|
+ ((numDataBytesInGroup2 + numEcBytesInGroup2) * numRsBlocksInGroup2))
|
||||||
((numDataBytesInGroup2 + numEcBytesInGroup2) *
|
{
|
||||||
numRsBlocksInGroup2)) {
|
return Err(Exceptions::WriterException(
|
||||||
return Err(Exceptions::WriterException("Total bytes mismatch".to_owned()))
|
"Total bytes mismatch".to_owned(),
|
||||||
|
));
|
||||||
|
|
||||||
// throw new WriterException("Total bytes mismatch");
|
// throw new WriterException("Total bytes mismatch");
|
||||||
}
|
}
|
||||||
@@ -489,59 +539,69 @@ static ref SHIFT_JIS_CHARSET : EncodingRef = encoding::label::encoding_from_what
|
|||||||
numECBytesInBlock[0] = numEcBytesInGroup2;
|
numECBytesInBlock[0] = numEcBytesInGroup2;
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Interleave "bits" with corresponding error correction bytes. On success, store the result in
|
* Interleave "bits" with corresponding error correction bytes. On success, store the result in
|
||||||
* "result". The interleave rule is complicated. See 8.6 of JISX0510:2004 (p.37) for details.
|
* "result". The interleave rule is complicated. See 8.6 of JISX0510:2004 (p.37) for details.
|
||||||
*/
|
*/
|
||||||
pub fn interleaveWithECBytes( bits:&BitArray,
|
pub fn interleaveWithECBytes(
|
||||||
numTotalBytes:u32,
|
bits: &BitArray,
|
||||||
numDataBytes:u32,
|
numTotalBytes: u32,
|
||||||
numRSBlocks:u32) -> Result<BitArray,Exceptions> {
|
numDataBytes: u32,
|
||||||
|
numRSBlocks: u32,
|
||||||
|
) -> 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 != numDataBytes {
|
||||||
return Err(Exceptions::WriterException("Number of bits and data bytes does not match".to_owned()))
|
return Err(Exceptions::WriterException(
|
||||||
|
"Number of bits and data bytes does not match".to_owned(),
|
||||||
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
// 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 dataBytesOffset = 0;
|
let mut dataBytesOffset = 0;
|
||||||
let maxNumDataBytes = 0;
|
let mut maxNumDataBytes = 0;
|
||||||
let maxNumEcBytes = 0;
|
let mut maxNumEcBytes = 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 blocks = Vec::new();
|
let mut blocks = Vec::new();
|
||||||
|
|
||||||
for i in 0..numRSBlocks {
|
for i in 0..numRSBlocks {
|
||||||
// for (int i = 0; i < numRSBlocks; ++i) {
|
// for (int i = 0; i < numRSBlocks; ++i) {
|
||||||
let numDataBytesInBlock = vec![0;1];//new int[1];
|
let mut numDataBytesInBlock = vec![0; 1]; //new int[1];
|
||||||
let numEcBytesInBlock = vec![0;1];//new int[1];
|
let mut numEcBytesInBlock = vec![0; 1]; //new int[1];
|
||||||
getNumDataBytesAndNumECBytesForBlockID(
|
getNumDataBytesAndNumECBytesForBlockID(
|
||||||
numTotalBytes, numDataBytes, numRSBlocks, i,
|
numTotalBytes,
|
||||||
&numDataBytesInBlock, &numEcBytesInBlock);
|
numDataBytes,
|
||||||
|
numRSBlocks,
|
||||||
|
i,
|
||||||
|
&mut numDataBytesInBlock,
|
||||||
|
&mut numEcBytesInBlock,
|
||||||
|
);
|
||||||
|
|
||||||
let size = numDataBytesInBlock[0];
|
let size = numDataBytesInBlock[0];
|
||||||
let 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 * dataBytesOffset, &mut dataBytes, 0, size as usize);
|
||||||
let ecBytes = generateECBytes(&dataBytes, numEcBytesInBlock[0] as usize);
|
let ecBytes = generateECBytes(&dataBytes, numEcBytesInBlock[0] as usize);
|
||||||
blocks.push( BlockPair::new(dataBytes, ecBytes));
|
blocks.push(BlockPair::new(dataBytes, ecBytes.clone()));
|
||||||
|
|
||||||
maxNumDataBytes = maxNumDataBytes.max( size);
|
maxNumDataBytes = maxNumDataBytes.max(size);
|
||||||
maxNumEcBytes = maxNumEcBytes.max( ecBytes.len());
|
maxNumEcBytes = maxNumEcBytes.max(ecBytes.len());
|
||||||
dataBytesOffset += numDataBytesInBlock[0] as usize;
|
dataBytesOffset += numDataBytesInBlock[0] as usize;
|
||||||
}
|
}
|
||||||
if numDataBytes != dataBytesOffset as u32 {
|
if numDataBytes != dataBytesOffset as u32 {
|
||||||
return Err(Exceptions::WriterException("Data bytes does not match offset".to_owned()))
|
return Err(Exceptions::WriterException(
|
||||||
|
"Data bytes does not match offset".to_owned(),
|
||||||
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
let 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..maxNumDataBytes 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 dataBytes = block.getDataBytes();
|
||||||
if i < dataBytes.len() {
|
if i < dataBytes.len() {
|
||||||
@@ -552,7 +612,7 @@ static ref SHIFT_JIS_CHARSET : EncodingRef = encoding::label::encoding_from_what
|
|||||||
// Then, place error correction blocks.
|
// Then, place error correction blocks.
|
||||||
for i in 0..maxNumEcBytes {
|
for i in 0..maxNumEcBytes {
|
||||||
// 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 ecBytes = block.getErrorCorrectionBytes();
|
||||||
if (i < ecBytes.len()) {
|
if (i < ecBytes.len()) {
|
||||||
@@ -560,75 +620,91 @@ static ref SHIFT_JIS_CHARSET : EncodingRef = encoding::label::encoding_from_what
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (numTotalBytes != result.getSizeInBytes() as u32) { // Should be same.
|
if (numTotalBytes != result.getSizeInBytes() as u32) {
|
||||||
return Err(
|
// Should be same.
|
||||||
Exceptions::WriterException(
|
return Err(Exceptions::WriterException(format!(
|
||||||
format!(
|
|
||||||
"Interleaving error: {} and {} differ.",
|
"Interleaving error: {} and {} differ.",
|
||||||
numTotalBytes,result.getSizeInBytes()
|
numTotalBytes,
|
||||||
)
|
result.getSizeInBytes()
|
||||||
)
|
)));
|
||||||
)
|
|
||||||
// throw new WriterException("Interleaving error: " + numTotalBytes + " and " +
|
// throw new WriterException("Interleaving error: " + numTotalBytes + " and " +
|
||||||
// result.getSizeInBytes() + " differ.");
|
// result.getSizeInBytes() + " differ.");
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(result)
|
Ok(result)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn generateECBytes( dataBytes:&[u8], numEcBytesInBlock:usize) -> Vec<u8> {
|
pub fn generateECBytes(dataBytes: &[u8], numEcBytesInBlock: usize) -> Vec<u8> {
|
||||||
let numDataBytes = dataBytes.len();
|
let numDataBytes = dataBytes.len();
|
||||||
let toEncode = vec![0;numDataBytes + numEcBytesInBlock];
|
let mut toEncode = vec![0; numDataBytes + numEcBytesInBlock];
|
||||||
for i in 0..numDataBytes {
|
for i in 0..numDataBytes {
|
||||||
// for (int i = 0; i < numDataBytes; i++) {
|
// for (int i = 0; i < numDataBytes; i++) {
|
||||||
toEncode[i] = dataBytes[i] as i32;
|
toEncode[i] = dataBytes[i] as i32;
|
||||||
}
|
}
|
||||||
|
|
||||||
ReedSolomonEncoder::new(get_predefined_genericgf(PredefinedGenericGF::QrCodeField256)).encode(&mut toEncode, numEcBytesInBlock);
|
ReedSolomonEncoder::new(get_predefined_genericgf(
|
||||||
|
PredefinedGenericGF::QrCodeField256,
|
||||||
|
))
|
||||||
|
.encode(&mut toEncode, numEcBytesInBlock);
|
||||||
|
|
||||||
let ecBytes = vec![0u8;numEcBytesInBlock];
|
let mut ecBytes = vec![0u8; numEcBytesInBlock];
|
||||||
for i in 0..numEcBytesInBlock {
|
for i in 0..numEcBytesInBlock {
|
||||||
// for (int i = 0; i < numEcBytesInBlock; i++) {
|
// for (int i = 0; i < numEcBytesInBlock; i++) {
|
||||||
ecBytes[i] = toEncode[numDataBytes + i] as u8;
|
ecBytes[i] = toEncode[numDataBytes + i] as u8;
|
||||||
}
|
}
|
||||||
return ecBytes;
|
return ecBytes;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Append mode info. On success, store the result in "bits".
|
* Append mode info. On success, store the result in "bits".
|
||||||
*/
|
*/
|
||||||
pub fn appendModeInfo( mode:Mode, bits:&BitArray) {
|
pub fn appendModeInfo(mode: Mode, bits: &mut BitArray) {
|
||||||
bits.appendBits(mode.getBits() as u32, 4);
|
bits.appendBits(mode.getBits() as u32, 4);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
/**
|
|
||||||
* Append length info. On success, store the result in "bits".
|
* Append length info. On success, store the result in "bits".
|
||||||
*/
|
*/
|
||||||
pub fn appendLengthInfo( numLetters:u32, version:VersionRef, mode:Mode, bits:&BitArray) -> Result<(),Exceptions> {
|
pub fn appendLengthInfo(
|
||||||
|
numLetters: u32,
|
||||||
|
version: VersionRef,
|
||||||
|
mode: Mode,
|
||||||
|
bits: &mut BitArray,
|
||||||
|
) -> Result<(), Exceptions> {
|
||||||
let numBits = mode.getCharacterCountBits(version);
|
let numBits = mode.getCharacterCountBits(version);
|
||||||
if numLetters >= (1 << numBits) {
|
if numLetters >= (1 << numBits) {
|
||||||
return Err(Exceptions::WriterException(format!("{} is bigger than {}" ,numLetters , ((1 << numBits) - 1))))
|
return Err(Exceptions::WriterException(format!(
|
||||||
|
"{} is bigger than {}",
|
||||||
|
numLetters,
|
||||||
|
((1 << numBits) - 1)
|
||||||
|
)));
|
||||||
}
|
}
|
||||||
bits.appendBits(numLetters, numBits as usize);
|
bits.appendBits(numLetters, numBits as usize);
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Append "bytes" in "mode" mode (encoding) into "bits". On success, store the result in "bits".
|
* Append "bytes" in "mode" mode (encoding) into "bits". On success, store the result in "bits".
|
||||||
*/
|
*/
|
||||||
pub fn appendBytes( content:&str,
|
pub fn appendBytes(
|
||||||
mode:Mode,
|
content: &str,
|
||||||
bits:&BitArray,
|
mode: Mode,
|
||||||
encoding:EncodingRef) -> Result<(),Exceptions>{
|
bits: &mut BitArray,
|
||||||
|
encoding: EncodingRef,
|
||||||
|
) -> Result<(), Exceptions> {
|
||||||
match mode {
|
match mode {
|
||||||
Mode::NUMERIC => appendNumericBytes(content, bits),
|
Mode::NUMERIC => appendNumericBytes(content, bits),
|
||||||
Mode::ALPHANUMERIC => appendAlphanumericBytes(content, bits)?,
|
Mode::ALPHANUMERIC => appendAlphanumericBytes(content, bits)?,
|
||||||
Mode::BYTE => append8BitBytes(content, bits, encoding),
|
Mode::BYTE => append8BitBytes(content, bits, encoding),
|
||||||
Mode::KANJI => appendKanjiBytes(content, bits)?,
|
Mode::KANJI => appendKanjiBytes(content, bits)?,
|
||||||
_=> return Err(Exceptions::WriterException(format!("Invalid mode: {:?}" , mode)))
|
_ => {
|
||||||
|
return Err(Exceptions::WriterException(format!(
|
||||||
|
"Invalid mode: {:?}",
|
||||||
|
mode
|
||||||
|
)))
|
||||||
|
}
|
||||||
};
|
};
|
||||||
Ok(())
|
Ok(())
|
||||||
// switch (mode) {
|
// switch (mode) {
|
||||||
// case NUMERIC:
|
// case NUMERIC:
|
||||||
// appendNumericBytes(content, bits);
|
// appendNumericBytes(content, bits);
|
||||||
@@ -645,11 +721,11 @@ Ok(())
|
|||||||
// default:
|
// default:
|
||||||
// throw new WriterException("Invalid mode: " + mode);
|
// throw new WriterException("Invalid mode: " + mode);
|
||||||
// }
|
// }
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn appendNumericBytes( content:&str, bits:&BitArray) {
|
pub fn appendNumericBytes(content: &str, bits: &mut BitArray) {
|
||||||
let length = content.len();
|
let length = content.len();
|
||||||
let i = 0;
|
let mut i = 0;
|
||||||
while i < length {
|
while i < length {
|
||||||
let num1 = content.chars().nth(i).unwrap() as u8 - b'0';
|
let num1 = content.chars().nth(i).unwrap() as u8 - b'0';
|
||||||
if i + 2 < length {
|
if i + 2 < length {
|
||||||
@@ -666,14 +742,14 @@ Ok(())
|
|||||||
} else {
|
} else {
|
||||||
// Encode one numeric letter in four bits.
|
// Encode one numeric letter in four bits.
|
||||||
bits.appendBits(num1 as u32, 4);
|
bits.appendBits(num1 as u32, 4);
|
||||||
i+=1;
|
i += 1;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn appendAlphanumericBytes( content:&str, bits:&BitArray) -> Result<(),Exceptions> {
|
pub fn appendAlphanumericBytes(content: &str, bits: &mut BitArray) -> Result<(), Exceptions> {
|
||||||
let length = content.len();
|
let length = content.len();
|
||||||
let i = 0;
|
let mut i = 0;
|
||||||
while i < length {
|
while i < length {
|
||||||
let code1 = getAlphanumericCode(content.chars().nth(i).unwrap() as u32);
|
let code1 = getAlphanumericCode(content.chars().nth(i).unwrap() as u32);
|
||||||
if code1 == -1 {
|
if code1 == -1 {
|
||||||
@@ -683,7 +759,6 @@ Ok(())
|
|||||||
let code2 = getAlphanumericCode(content.chars().nth(i + 1).unwrap() as u32);
|
let code2 = getAlphanumericCode(content.chars().nth(i + 1).unwrap() as u32);
|
||||||
if (code2 == -1) {
|
if (code2 == -1) {
|
||||||
return Err(Exceptions::WriterException("".to_owned()));
|
return Err(Exceptions::WriterException("".to_owned()));
|
||||||
|
|
||||||
}
|
}
|
||||||
// Encode two alphanumeric letters in 11 bits.
|
// Encode two alphanumeric letters in 11 bits.
|
||||||
bits.appendBits((code1 * 45 + code2) as u32, 11);
|
bits.appendBits((code1 * 45 + code2) as u32, 11);
|
||||||
@@ -691,56 +766,63 @@ Ok(())
|
|||||||
} else {
|
} else {
|
||||||
// Encode one alphanumeric letter in six bits.
|
// Encode one alphanumeric letter in six bits.
|
||||||
bits.appendBits(code1 as u32, 6);
|
bits.appendBits(code1 as u32, 6);
|
||||||
i+=1;
|
i += 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn append8BitBytes( content:&str, bits:&BitArray, encoding:EncodingRef) {
|
fn append8BitBytes(content: &str, bits: &mut BitArray, encoding: EncodingRef) {
|
||||||
let bytes = encoding.encode(content, encoding::EncoderTrap::Strict).expect("should encode");
|
let bytes = encoding
|
||||||
|
.encode(content, encoding::EncoderTrap::Strict)
|
||||||
|
.expect("should encode");
|
||||||
// let bytes = content.getBytes(encoding);
|
// let bytes = content.getBytes(encoding);
|
||||||
for b in bytes {
|
for b in bytes {
|
||||||
// for (byte b : bytes) {
|
// for (byte b : bytes) {
|
||||||
bits.appendBits(b as u32, 8);
|
bits.appendBits(b as u32, 8);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn appendKanjiBytes( content:&str, bits:&BitArray) -> Result<(),Exceptions> {
|
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; //encoding::label::encoding_from_whatwg_label("SJIS").unwrap();
|
||||||
|
|
||||||
let bytes = sjis.encode(content, encoding::EncoderTrap::Strict).expect("should encode fine");
|
let bytes = sjis
|
||||||
|
.encode(content, encoding::EncoderTrap::Strict)
|
||||||
|
.expect("should encode fine");
|
||||||
// let bytes = content.getBytes(StringUtils::SHIFT_JIS_CHARSET);
|
// let bytes = content.getBytes(StringUtils::SHIFT_JIS_CHARSET);
|
||||||
if bytes.len() % 2 != 0 {
|
if bytes.len() % 2 != 0 {
|
||||||
return Err(Exceptions::WriterException("Kanji byte size not even".to_owned()))
|
return Err(Exceptions::WriterException(
|
||||||
|
"Kanji byte size not even".to_owned(),
|
||||||
|
));
|
||||||
}
|
}
|
||||||
let maxI = bytes.len() - 1; // bytes.length must be even
|
let maxI = bytes.len() - 1; // bytes.length must be even
|
||||||
let mut i = 0;
|
let mut i = 0;
|
||||||
while i < maxI {
|
while i < maxI {
|
||||||
// for (int i = 0; i < maxI; i += 2) {
|
// for (int i = 0; i < maxI; i += 2) {
|
||||||
let byte1 = bytes[i] & 0xFF;
|
let byte1 = bytes[i];// & 0xFF;
|
||||||
let byte2 = bytes[i + 1] & 0xFF;
|
let byte2 = bytes[i + 1];// & 0xFF;
|
||||||
let code = (byte1 << 8) | byte2;
|
let code:u16 = ((byte1 as u16) << 8u16) | byte2 as u16;
|
||||||
let subtracted:i32 = -1;
|
let mut subtracted: i32 = -1;
|
||||||
if code >= 0x8140 && code <= 0x9ffc {
|
if code >= 0x8140 && code <= 0x9ffc {
|
||||||
subtracted = code as i32 - 0x8140;
|
subtracted = code as i32 - 0x8140;
|
||||||
} else if code >= 0xe040 && code <= 0xebbf {
|
} else if code >= 0xe040 && code <= 0xebbf {
|
||||||
subtracted = code as i32 - 0xc140;
|
subtracted = code as i32 - 0xc140;
|
||||||
}
|
}
|
||||||
if subtracted == -1 {
|
if subtracted == -1 {
|
||||||
return Err(Exceptions::WriterException("Invalid byte sequence".to_owned()))
|
return Err(Exceptions::WriterException(
|
||||||
|
"Invalid byte sequence".to_owned(),
|
||||||
|
));
|
||||||
}
|
}
|
||||||
let encoded = ((subtracted >> 8) * 0xc0) + (subtracted & 0xff);
|
let encoded = ((subtracted >> 8) * 0xc0) + (subtracted & 0xff);
|
||||||
bits.appendBits(encoded as u32, 13);
|
bits.appendBits(encoded as u32, 13);
|
||||||
|
|
||||||
i+=2;
|
i += 2;
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn appendECI( eci:&CharacterSetECI, bits:&BitArray) {
|
fn appendECI(eci: &CharacterSetECI, bits: &mut BitArray) {
|
||||||
bits.appendBits(Mode::ECI.getBits() as u32, 4);
|
bits.appendBits(Mode::ECI.getBits() as u32, 4);
|
||||||
// This is correct for values up to 127, which is all we need now.
|
// This is correct for values up to 127, which is all we need now.
|
||||||
bits.appendBits(eci.getValueSelf(), 8);
|
bits.appendBits(eci.getValueSelf(), 8);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -18,15 +18,18 @@ use std::{fmt, rc::Rc};
|
|||||||
|
|
||||||
use encoding::EncodingRef;
|
use encoding::EncodingRef;
|
||||||
|
|
||||||
use crate::{common::{ECIEncoderSet, BitArray}, qrcode::decoder::{ErrorCorrectionLevel, Version, Mode, VersionRef}, Exceptions};
|
use crate::{
|
||||||
|
common::{BitArray, ECIEncoderSet},
|
||||||
|
qrcode::decoder::{ErrorCorrectionLevel, Mode, Version, VersionRef},
|
||||||
|
Exceptions,
|
||||||
|
};
|
||||||
|
|
||||||
use super::encoder;
|
use super::encoder;
|
||||||
|
|
||||||
|
pub enum VersionSize {
|
||||||
enum VersionSize {
|
SMALL, //("version 1-9"),
|
||||||
SMALL,//("version 1-9"),
|
MEDIUM, //("version 10-26"),
|
||||||
MEDIUM,//("version 10-26"),
|
LARGE, //("version 27-40");
|
||||||
LARGE,//("version 27-40");
|
|
||||||
|
|
||||||
// private final String description;
|
// private final String description;
|
||||||
|
|
||||||
@@ -41,15 +44,18 @@ enum VersionSize {
|
|||||||
|
|
||||||
impl fmt::Display for VersionSize {
|
impl fmt::Display for VersionSize {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
write!( f, "{}", match self {
|
write!(
|
||||||
|
f,
|
||||||
|
"{}",
|
||||||
|
match self {
|
||||||
VersionSize::SMALL => "version 1-9",
|
VersionSize::SMALL => "version 1-9",
|
||||||
VersionSize::MEDIUM => "version 10-26",
|
VersionSize::MEDIUM => "version 10-26",
|
||||||
VersionSize::LARGE => "version 27-40",
|
VersionSize::LARGE => "version 27-40",
|
||||||
})
|
}
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Encoder that encodes minimally
|
* Encoder that encodes minimally
|
||||||
*
|
*
|
||||||
@@ -77,16 +83,14 @@ impl fmt::Display for VersionSize {
|
|||||||
*
|
*
|
||||||
* @author Alex Geller
|
* @author Alex Geller
|
||||||
*/
|
*/
|
||||||
pub struct MinimalEncoder<'a> {
|
pub struct MinimalEncoder {
|
||||||
|
stringToEncode: String,
|
||||||
stringToEncode: &'a str,
|
|
||||||
isGS1: bool,
|
isGS1: bool,
|
||||||
encoders: ECIEncoderSet,
|
encoders: ECIEncoderSet,
|
||||||
ecLevel:ErrorCorrectionLevel,
|
ecLevel: ErrorCorrectionLevel,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl MinimalEncoder<'_> {
|
impl MinimalEncoder {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a MinimalEncoder
|
* Creates a MinimalEncoder
|
||||||
*
|
*
|
||||||
@@ -99,16 +103,20 @@ impl MinimalEncoder<'_> {
|
|||||||
* @param ecLevel The error correction level.
|
* @param ecLevel The error correction level.
|
||||||
* @see RXingResultList#getVersion
|
* @see RXingResultList#getVersion
|
||||||
*/
|
*/
|
||||||
pub fn new( stringToEncode:&str, priorityCharset: EncodingRef, isGS1:bool, ecLevel:ErrorCorrectionLevel) -> Self {
|
pub fn new(
|
||||||
|
stringToEncode: &str,
|
||||||
|
priorityCharset: EncodingRef,
|
||||||
|
isGS1: bool,
|
||||||
|
ecLevel: ErrorCorrectionLevel,
|
||||||
|
) -> Self {
|
||||||
Self {
|
Self {
|
||||||
stringToEncode,
|
stringToEncode: String::from(stringToEncode),
|
||||||
isGS1,
|
isGS1,
|
||||||
encoders: ECIEncoderSet::new(&stringToEncode, priorityCharset, -1),
|
encoders: ECIEncoderSet::new(&stringToEncode, priorityCharset, -1),
|
||||||
ecLevel,
|
ecLevel,
|
||||||
}
|
}
|
||||||
|
|
||||||
// let encoders = ECIEncoderSet::new(&stringToEncode, priorityCharset, -1);
|
// let encoders = ECIEncoderSet::new(&stringToEncode, priorityCharset, -1);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -128,21 +136,31 @@ impl MinimalEncoder<'_> {
|
|||||||
* @see RXingResultList#getVersion
|
* @see RXingResultList#getVersion
|
||||||
* @see RXingResultList#getSize
|
* @see RXingResultList#getSize
|
||||||
*/
|
*/
|
||||||
pub fn encode_with_details<'a>( stringToEncode:&str, version:Option<VersionRef>, priorityCharset:EncodingRef, isGS1:bool,
|
pub fn encode_with_details(
|
||||||
ecLevel:ErrorCorrectionLevel) -> Result<RXingResultList<'a>,Exceptions> {
|
stringToEncode: &str,
|
||||||
|
version: Option<VersionRef>,
|
||||||
|
priorityCharset: EncodingRef,
|
||||||
|
isGS1: bool,
|
||||||
|
ecLevel: ErrorCorrectionLevel,
|
||||||
|
) -> Result<RXingResultList, Exceptions> {
|
||||||
MinimalEncoder::new(stringToEncode, priorityCharset, isGS1, ecLevel).encode(version)
|
MinimalEncoder::new(stringToEncode, priorityCharset, isGS1, ecLevel).encode(version)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn encode(&self, version:Option<VersionRef>) -> Result<RXingResultList,Exceptions> {
|
pub fn encode(&self, version: Option<VersionRef>) -> Result<RXingResultList, Exceptions> {
|
||||||
if version.is_none() { // compute minimal encoding trying the three version sizes.
|
if version.is_none() {
|
||||||
let versions = [ Self::getVersion(VersionSize::SMALL),
|
// compute minimal encoding trying the three version sizes.
|
||||||
|
let versions = [
|
||||||
|
Self::getVersion(VersionSize::SMALL),
|
||||||
Self::getVersion(VersionSize::MEDIUM),
|
Self::getVersion(VersionSize::MEDIUM),
|
||||||
Self::getVersion(VersionSize::LARGE) ];
|
Self::getVersion(VersionSize::LARGE),
|
||||||
let results = [ self.encodeSpecificVersion(&versions[0])?,
|
];
|
||||||
|
let results = [
|
||||||
|
self.encodeSpecificVersion(&versions[0])?,
|
||||||
self.encodeSpecificVersion(&versions[1])?,
|
self.encodeSpecificVersion(&versions[1])?,
|
||||||
self.encodeSpecificVersion(&versions[2])? ];
|
self.encodeSpecificVersion(&versions[2])?,
|
||||||
let smallestSize = u32::MAX;
|
];
|
||||||
let smallestRXingResult:i32 = -1;
|
let mut smallestSize = u32::MAX;
|
||||||
|
let mut smallestRXingResult: i32 = -1;
|
||||||
for i in 0..3 {
|
for i in 0..3 {
|
||||||
// for (int i = 0; i < 3; i++) {
|
// for (int i = 0; i < 3; i++) {
|
||||||
let size = results[i].getSize();
|
let size = results[i].getSize();
|
||||||
@@ -152,25 +170,42 @@ impl MinimalEncoder<'_> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if smallestRXingResult < 0 {
|
if smallestRXingResult < 0 {
|
||||||
return Err(Exceptions::WriterException("Data too big for any version".to_owned()));
|
return Err(Exceptions::WriterException(
|
||||||
|
"Data too big for any version".to_owned(),
|
||||||
|
));
|
||||||
}
|
}
|
||||||
Ok(results[smallestRXingResult as usize])
|
Ok(results[smallestRXingResult as usize].clone())
|
||||||
} else { // compute minimal encoding for a given version
|
} else {
|
||||||
|
// compute minimal encoding for a given version
|
||||||
let version = version.unwrap();
|
let version = version.unwrap();
|
||||||
let result = self.encodeSpecificVersion(version)?;
|
let result = self.encodeSpecificVersion(version)?;
|
||||||
if !encoder::willFit(result.getSize(), Self::getVersion(Self::getVersionSize(result.getVersion())), &self.ecLevel) {
|
if !encoder::willFit(
|
||||||
return Err(Exceptions::WriterException(format!("Data too big for version {}" , version)));
|
result.getSize(),
|
||||||
|
Self::getVersion(Self::getVersionSize(result.getVersion())),
|
||||||
|
&self.ecLevel,
|
||||||
|
) {
|
||||||
|
return Err(Exceptions::WriterException(format!(
|
||||||
|
"Data too big for version {}",
|
||||||
|
version
|
||||||
|
)));
|
||||||
}
|
}
|
||||||
Ok(result)
|
Ok(result)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn getVersionSize( version:&Version) -> VersionSize {
|
pub fn getVersionSize(version: VersionRef) -> VersionSize {
|
||||||
return if version.getVersionNumber() <= 9 { VersionSize::SMALL} else {if version.getVersionNumber() <= 26
|
return if version.getVersionNumber() <= 9 {
|
||||||
{VersionSize::MEDIUM} else {VersionSize::LARGE}};
|
VersionSize::SMALL
|
||||||
|
} else {
|
||||||
|
if version.getVersionNumber() <= 26 {
|
||||||
|
VersionSize::MEDIUM
|
||||||
|
} else {
|
||||||
|
VersionSize::LARGE
|
||||||
|
}
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn getVersion( versionSize:VersionSize)->VersionRef {
|
pub fn getVersion(versionSize: VersionSize) -> VersionRef {
|
||||||
match versionSize {
|
match versionSize {
|
||||||
VersionSize::SMALL => Version::getVersionForNumber(9).expect("should always exist"),
|
VersionSize::SMALL => Version::getVersionForNumber(9).expect("should always exist"),
|
||||||
VersionSize::MEDIUM => Version::getVersionForNumber(26).expect("should always exist"),
|
VersionSize::MEDIUM => Version::getVersionForNumber(26).expect("should always exist"),
|
||||||
@@ -187,31 +222,31 @@ impl MinimalEncoder<'_> {
|
|||||||
// }
|
// }
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn isNumeric( c:char) -> bool{
|
pub fn isNumeric(c: char) -> bool {
|
||||||
return c >= '0' && c <= '9';
|
return c >= '0' && c <= '9';
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn isDoubleByteKanji( c:char) -> bool{
|
pub fn isDoubleByteKanji(c: char) -> bool {
|
||||||
return encoder::isOnlyDoubleByteKanji(&String::from(c));
|
return encoder::isOnlyDoubleByteKanji(&String::from(c));
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn isAlphanumeric( c: char) -> bool{
|
pub fn isAlphanumeric(c: char) -> bool {
|
||||||
return encoder::getAlphanumericCode(c as u8 as u32) != -1;
|
return encoder::getAlphanumericCode(c as u8 as u32) != -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn canEncode(&self, mode:&Mode, c:char) -> bool {
|
pub fn canEncode(&self, mode: &Mode, c: char) -> bool {
|
||||||
match mode {
|
match mode {
|
||||||
Mode::NUMERIC => Self::isNumeric(c),
|
Mode::NUMERIC => Self::isNumeric(c),
|
||||||
Mode::ALPHANUMERIC => Self::isAlphanumeric(c),
|
Mode::ALPHANUMERIC => Self::isAlphanumeric(c),
|
||||||
Mode::STRUCTURED_APPEND => todo!(),
|
Mode::STRUCTURED_APPEND => todo!(),
|
||||||
Mode::BYTE => true,
|
Mode::BYTE => true,
|
||||||
Mode::KANJI => Self::isDoubleByteKanji(c),
|
Mode::KANJI => Self::isDoubleByteKanji(c),
|
||||||
_=> false,// any character can be encoded as byte(s). Up to the caller to manage splitting into
|
_ => false, // any character can be encoded as byte(s). Up to the caller to manage splitting into
|
||||||
// multiple bytes when String.getBytes(Charset) return more than one byte.
|
// multiple bytes when String.getBytes(Charset) return more than one byte.
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn getCompactedOrdinal( mode:Option<Mode>) -> Result<u32,Exceptions>{
|
pub fn getCompactedOrdinal(mode: Option<Mode>) -> Result<u32, Exceptions> {
|
||||||
if mode.is_none() {
|
if mode.is_none() {
|
||||||
return Ok(0);
|
return Ok(0);
|
||||||
}
|
}
|
||||||
@@ -220,7 +255,10 @@ impl MinimalEncoder<'_> {
|
|||||||
Mode::ALPHANUMERIC => Ok(1),
|
Mode::ALPHANUMERIC => Ok(1),
|
||||||
Mode::BYTE => Ok(3),
|
Mode::BYTE => Ok(3),
|
||||||
Mode::KANJI => Ok(0),
|
Mode::KANJI => Ok(0),
|
||||||
_=> Err(Exceptions::IllegalArgumentException(format!("Illegal mode {:?}", mode))),
|
_ => Err(Exceptions::IllegalArgumentException(format!(
|
||||||
|
"Illegal mode {:?}",
|
||||||
|
mode
|
||||||
|
))),
|
||||||
}
|
}
|
||||||
// switch (mode) {
|
// switch (mode) {
|
||||||
// case KANJI:
|
// case KANJI:
|
||||||
@@ -236,49 +274,157 @@ impl MinimalEncoder<'_> {
|
|||||||
// }
|
// }
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn addEdge(&self, edges:&Vec<Vec<Vec<Option<&'_ Edge>>>>, position:usize, edge:Option<&Edge>) {
|
pub fn addEdge(
|
||||||
|
&self,
|
||||||
|
edges: &mut Vec<Vec<Vec<Option<Rc<Edge>>>>>,
|
||||||
|
position: usize,
|
||||||
|
edge: Option<Rc<Edge>>,
|
||||||
|
) {
|
||||||
let vertexIndex = position + edge.as_ref().unwrap().characterLength as usize;
|
let vertexIndex = position + edge.as_ref().unwrap().characterLength as usize;
|
||||||
let modeEdges = edges[vertexIndex as usize][edge.as_ref().unwrap().charsetEncoderIndex as usize];
|
let modeEdges =
|
||||||
let modeOrdinal = Self::getCompactedOrdinal(Some(edge.as_ref().unwrap().mode)).expect("value") as usize;
|
&mut edges[vertexIndex as usize][edge.as_ref().unwrap().charsetEncoderIndex as usize];
|
||||||
if modeEdges[modeOrdinal].is_none() || modeEdges[modeOrdinal].as_ref().unwrap().cachedTotalSize > (&edge).unwrap().cachedTotalSize {
|
let modeOrdinal =
|
||||||
|
Self::getCompactedOrdinal(Some(edge.as_ref().unwrap().mode)).expect("value") as usize;
|
||||||
|
if modeEdges[modeOrdinal].is_none()
|
||||||
|
|| modeEdges[modeOrdinal].as_ref().unwrap().cachedTotalSize
|
||||||
|
> edge.as_ref().unwrap().cachedTotalSize
|
||||||
|
{
|
||||||
modeEdges[modeOrdinal] = edge;
|
modeEdges[modeOrdinal] = edge;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn addEdges( &self, version:VersionRef, edges:&Vec<Vec<Vec<Option<&Edge>>>>, from:usize, previous:Option<&Edge>) {
|
pub fn addEdges(
|
||||||
let start = 0;
|
&self,
|
||||||
let end = self.encoders.len();
|
version: VersionRef,
|
||||||
|
edges: &mut Vec<Vec<Vec<Option<Rc<Edge>>>>>,
|
||||||
|
from: usize,
|
||||||
|
previous: Option<Rc<Edge>>,
|
||||||
|
) {
|
||||||
|
let mut start = 0;
|
||||||
|
let mut end = self.encoders.len();
|
||||||
let priorityEncoderIndex = self.encoders.getPriorityEncoderIndex();
|
let priorityEncoderIndex = self.encoders.getPriorityEncoderIndex();
|
||||||
if priorityEncoderIndex >= 0 && self.encoders.canEncode(self.stringToEncode.chars().nth(from as usize).unwrap() as i16,priorityEncoderIndex) {
|
if priorityEncoderIndex >= 0
|
||||||
|
&& self.encoders.canEncode(
|
||||||
|
self.stringToEncode.chars().nth(from as usize).unwrap() as i16,
|
||||||
|
priorityEncoderIndex,
|
||||||
|
)
|
||||||
|
{
|
||||||
start = priorityEncoderIndex;
|
start = priorityEncoderIndex;
|
||||||
end = priorityEncoderIndex + 1;
|
end = priorityEncoderIndex + 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
for i in start..end {
|
for i in start..end {
|
||||||
// for (int i = start; i < end; i++) {
|
// for (int i = start; i < end; i++) {
|
||||||
if self.encoders.canEncode(self.stringToEncode.chars().nth(from).unwrap() as i16, i) {
|
if self
|
||||||
self.addEdge(edges, from, Some(&Edge::new(Mode::BYTE, from, i, 1, previous, version,&self.encoders,&self.stringToEncode)));
|
.encoders
|
||||||
|
.canEncode(self.stringToEncode.chars().nth(from).unwrap() as i16, i)
|
||||||
|
{
|
||||||
|
self.addEdge(
|
||||||
|
edges,
|
||||||
|
from,
|
||||||
|
Some(Rc::new(Edge::new(
|
||||||
|
Mode::BYTE,
|
||||||
|
from,
|
||||||
|
i,
|
||||||
|
1,
|
||||||
|
previous.clone(),
|
||||||
|
version,
|
||||||
|
self.encoders.clone(),
|
||||||
|
&self.stringToEncode,
|
||||||
|
))),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if self.canEncode(&Mode::KANJI, self.stringToEncode.chars().nth(from).unwrap()) {
|
if self.canEncode(&Mode::KANJI, self.stringToEncode.chars().nth(from).unwrap()) {
|
||||||
self.addEdge(edges, from, Some(&Edge::new(Mode::KANJI, from, 0, 1, previous, version,&self.encoders,&self.stringToEncode)));
|
self.addEdge(
|
||||||
|
edges,
|
||||||
|
from,
|
||||||
|
Some(Rc::new(Edge::new(
|
||||||
|
Mode::KANJI,
|
||||||
|
from,
|
||||||
|
0,
|
||||||
|
1,
|
||||||
|
previous.clone(),
|
||||||
|
version,
|
||||||
|
self.encoders.clone(),
|
||||||
|
&self.stringToEncode,
|
||||||
|
))),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
let inputLength = self.stringToEncode.len();
|
let inputLength = self.stringToEncode.len();
|
||||||
if self.canEncode(&Mode::ALPHANUMERIC, self.stringToEncode.chars().nth(from).unwrap()) {
|
if self.canEncode(
|
||||||
self.addEdge(edges, from, Some(&Edge::new(Mode::ALPHANUMERIC, from, 0, if from + 1 >= inputLength ||
|
&Mode::ALPHANUMERIC,
|
||||||
!self.canEncode(&Mode::ALPHANUMERIC, self.stringToEncode.chars().nth(from + 1).unwrap()) {1} else {2}, previous, version,&self.encoders,&self.stringToEncode)));
|
self.stringToEncode.chars().nth(from).unwrap(),
|
||||||
|
) {
|
||||||
|
self.addEdge(
|
||||||
|
edges,
|
||||||
|
from,
|
||||||
|
Some(Rc::new(Edge::new(
|
||||||
|
Mode::ALPHANUMERIC,
|
||||||
|
from,
|
||||||
|
0,
|
||||||
|
if from + 1 >= inputLength
|
||||||
|
|| !self.canEncode(
|
||||||
|
&Mode::ALPHANUMERIC,
|
||||||
|
self.stringToEncode.chars().nth(from + 1).unwrap(),
|
||||||
|
)
|
||||||
|
{
|
||||||
|
1
|
||||||
|
} else {
|
||||||
|
2
|
||||||
|
},
|
||||||
|
previous.clone(),
|
||||||
|
version,
|
||||||
|
self.encoders.clone(),
|
||||||
|
&self.stringToEncode,
|
||||||
|
))),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
if self.canEncode(&Mode::NUMERIC, self.stringToEncode.chars().nth(from).unwrap()) {
|
if self.canEncode(
|
||||||
self.addEdge(edges, from, Some(&Edge::new(Mode::NUMERIC, from, 0, if from + 1 >= inputLength ||
|
&Mode::NUMERIC,
|
||||||
!self.canEncode(&Mode::NUMERIC, self.stringToEncode.chars().nth(from + 1).unwrap()) {1} else {if from + 2 >= inputLength ||
|
self.stringToEncode.chars().nth(from).unwrap(),
|
||||||
!self.canEncode(&Mode::NUMERIC, self.stringToEncode.chars().nth(from + 2).unwrap()) {2} else {3}}, previous, version,&self.encoders,&self.stringToEncode)));
|
) {
|
||||||
|
self.addEdge(
|
||||||
|
edges,
|
||||||
|
from,
|
||||||
|
Some(Rc::new(Edge::new(
|
||||||
|
Mode::NUMERIC,
|
||||||
|
from,
|
||||||
|
0,
|
||||||
|
if from + 1 >= inputLength
|
||||||
|
|| !self.canEncode(
|
||||||
|
&Mode::NUMERIC,
|
||||||
|
self.stringToEncode.chars().nth(from + 1).unwrap(),
|
||||||
|
)
|
||||||
|
{
|
||||||
|
1
|
||||||
|
} else {
|
||||||
|
if from + 2 >= inputLength
|
||||||
|
|| !self.canEncode(
|
||||||
|
&Mode::NUMERIC,
|
||||||
|
self.stringToEncode.chars().nth(from + 2).unwrap(),
|
||||||
|
)
|
||||||
|
{
|
||||||
|
2
|
||||||
|
} else {
|
||||||
|
3
|
||||||
|
}
|
||||||
|
},
|
||||||
|
previous.clone(),
|
||||||
|
version,
|
||||||
|
self.encoders.clone(),
|
||||||
|
&self.stringToEncode,
|
||||||
|
))),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
pub fn encodeSpecificVersion(&self, version:VersionRef) ->Result< RXingResultList, Exceptions >{
|
pub fn encodeSpecificVersion(
|
||||||
|
&self,
|
||||||
|
version: VersionRef,
|
||||||
|
) -> Result<RXingResultList, Exceptions> {
|
||||||
// @SuppressWarnings("checkstyle:lineLength")
|
// @SuppressWarnings("checkstyle:lineLength")
|
||||||
/* A vertex represents a tuple of a position in the input, a mode and a character encoding where position 0
|
/* A vertex represents a tuple of a position in the input, a mode and a character encoding where position 0
|
||||||
* denotes the position left of the first character, 1 the position left of the second character and so on.
|
* denotes the position left of the first character, 1 the position left of the second character and so on.
|
||||||
@@ -397,8 +543,8 @@ impl MinimalEncoder<'_> {
|
|||||||
|
|
||||||
// The last dimension in the array below encodes the 4 modes KANJI, ALPHANUMERIC, NUMERIC and BYTE via the
|
// The last dimension in the array below encodes the 4 modes KANJI, ALPHANUMERIC, NUMERIC and BYTE via the
|
||||||
// function getCompactedOrdinal(Mode)
|
// function getCompactedOrdinal(Mode)
|
||||||
let edges = vec![vec![vec![None;4];self.encoders.len()];inputLength+1];//new Edge[inputLength + 1][encoders.length()][4];
|
let mut edges = vec![vec![vec![None; 4]; self.encoders.len()]; inputLength + 1]; //new Edge[inputLength + 1][encoders.length()][4];
|
||||||
self. addEdges(version, &edges, 0, None);
|
self.addEdges(version, &mut edges, 0, None);
|
||||||
|
|
||||||
for i in 1..=inputLength {
|
for i in 1..=inputLength {
|
||||||
// for (int i = 1; i <= inputLength; i++) {
|
// for (int i = 1; i <= inputLength; i++) {
|
||||||
@@ -407,15 +553,15 @@ impl MinimalEncoder<'_> {
|
|||||||
for k in 0..4 {
|
for k in 0..4 {
|
||||||
// for (int k = 0; k < 4; k++) {
|
// for (int k = 0; k < 4; k++) {
|
||||||
if edges[i][j][k].is_some() && i < inputLength {
|
if edges[i][j][k].is_some() && i < inputLength {
|
||||||
self.addEdges(version, &edges, i, edges[i][j][k]);
|
let e = edges[i][j][k].clone();
|
||||||
|
self.addEdges(version, &mut edges, i, e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
let minimalJ = None;
|
let mut minimalJ = None;
|
||||||
let minimalK = None;
|
let mut minimalK = None;
|
||||||
let minimalSize = u32::MAX;
|
let mut minimalSize = u32::MAX;
|
||||||
for j in 0..self.encoders.len() {
|
for j in 0..self.encoders.len() {
|
||||||
// for (int j = 0; j < encoders.length(); j++) {
|
// for (int j = 0; j < encoders.length(); j++) {
|
||||||
for k in 0..4 {
|
for k in 0..4 {
|
||||||
@@ -431,58 +577,96 @@ impl MinimalEncoder<'_> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if minimalJ.is_none() {
|
if minimalJ.is_none() {
|
||||||
return Err(Exceptions::WriterException(format!(r#"Internal error: failed to encode "{}"#,self.stringToEncode)));
|
return Err(Exceptions::WriterException(format!(
|
||||||
|
r#"Internal error: failed to encode "{}"#,
|
||||||
|
self.stringToEncode
|
||||||
|
)));
|
||||||
}
|
}
|
||||||
Ok(RXingResultList::new(version, edges[inputLength][minimalJ.unwrap()][minimalK.unwrap()].unwrap(),self.isGS1,&self.ecLevel, &self.encoders, &self.stringToEncode))
|
Ok(RXingResultList::new(
|
||||||
|
version,
|
||||||
|
edges[inputLength][minimalJ.unwrap()][minimalK.unwrap()].as_ref().unwrap().clone(),
|
||||||
|
self.isGS1,
|
||||||
|
&self.ecLevel,
|
||||||
|
self.encoders.clone(),
|
||||||
|
&self.stringToEncode,
|
||||||
|
))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub struct Edge {
|
||||||
struct Edge<'a> {
|
pub mode: Mode,
|
||||||
pub mode:Mode,
|
fromPosition: usize,
|
||||||
fromPosition:usize,
|
charsetEncoderIndex: usize,
|
||||||
charsetEncoderIndex:usize,
|
characterLength: u32,
|
||||||
characterLength:u32,
|
previous: Option<Rc<Edge>>,
|
||||||
previous:Option<&'a Edge<'a>>,
|
cachedTotalSize: u32,
|
||||||
cachedTotalSize:u32,
|
encoders: ECIEncoderSet,
|
||||||
encoders:&'a ECIEncoderSet,
|
stringToEncode: String,
|
||||||
stringToEncode: &'a str,
|
|
||||||
}
|
}
|
||||||
impl Edge<'_> {
|
impl Edge {
|
||||||
|
pub fn new(
|
||||||
pub fn new( mode:Mode, fromPosition:usize, charsetEncoderIndex:usize, characterLength:u32, previous:Option<&'_ Edge>,
|
mode: Mode,
|
||||||
version:&Version, encoders: &'_ ECIEncoderSet, stringToEncode: &'_ str) -> Self {
|
fromPosition: usize,
|
||||||
let nci = if mode == Mode::BYTE || previous.is_none() {charsetEncoderIndex} else
|
charsetEncoderIndex: usize,
|
||||||
{previous.as_ref().unwrap().charsetEncoderIndex};
|
characterLength: u32,
|
||||||
|
previous: Option<Rc<Edge>>,
|
||||||
|
version: VersionRef,
|
||||||
|
encoders: ECIEncoderSet,
|
||||||
|
stringToEncode: &'_ str,
|
||||||
|
) -> Self {
|
||||||
|
let nci = if mode == Mode::BYTE || previous.is_none() {
|
||||||
|
charsetEncoderIndex
|
||||||
|
} else {
|
||||||
|
previous.as_ref().unwrap().charsetEncoderIndex
|
||||||
|
};
|
||||||
Self {
|
Self {
|
||||||
mode,
|
mode,
|
||||||
fromPosition,
|
fromPosition,
|
||||||
charsetEncoderIndex: nci,
|
charsetEncoderIndex: nci,
|
||||||
characterLength,
|
characterLength,
|
||||||
previous,
|
previous: previous.clone(),
|
||||||
stringToEncode,
|
stringToEncode: String::from(stringToEncode),
|
||||||
cachedTotalSize: {
|
cachedTotalSize: {
|
||||||
let size = if previous.is_some() {previous.as_ref().unwrap().cachedTotalSize} else {0};
|
let mut size = if previous.is_some() {
|
||||||
|
previous.as_ref().unwrap().cachedTotalSize
|
||||||
|
} else {
|
||||||
|
0
|
||||||
|
};
|
||||||
|
|
||||||
let needECI = mode == Mode::BYTE &&
|
let needECI = mode == Mode::BYTE &&
|
||||||
(previous.is_none() && nci != 0) || // at the beginning and charset is not ISO-8859-1
|
(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().unwrap().charsetEncoderIndex);
|
||||||
|
|
||||||
if previous.is_none()|| mode != previous.as_ref().unwrap().mode || needECI {
|
if previous.is_none() || mode != previous.as_ref().unwrap().mode || needECI {
|
||||||
size += 4 + mode.getCharacterCountBits(&version) as u32;
|
size += 4 + mode.getCharacterCountBits(&version) as u32;
|
||||||
}
|
}
|
||||||
match mode {
|
match mode {
|
||||||
Mode::NUMERIC => size += if characterLength == 1 {4} else {if characterLength == 2 {7} else {10}},
|
Mode::NUMERIC => {
|
||||||
Mode::ALPHANUMERIC => size += if characterLength == 1 {6} else {11},
|
size += if characterLength == 1 {
|
||||||
Mode::BYTE =>{
|
4
|
||||||
size += 8 * encoders.encode_string(&stringToEncode[fromPosition as usize..(fromPosition + characterLength as usize)],
|
} else {
|
||||||
charsetEncoderIndex as usize).len() as u32;
|
if characterLength == 2 {
|
||||||
|
7
|
||||||
|
} else {
|
||||||
|
10
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Mode::ALPHANUMERIC => size += if characterLength == 1 { 6 } else { 11 },
|
||||||
|
Mode::BYTE => {
|
||||||
|
size += 8 * encoders
|
||||||
|
.encode_string(
|
||||||
|
&stringToEncode[fromPosition as usize
|
||||||
|
..(fromPosition + characterLength as usize)],
|
||||||
|
charsetEncoderIndex as usize,
|
||||||
|
)
|
||||||
|
.len() as u32;
|
||||||
if needECI {
|
if needECI {
|
||||||
size += 4 + 8; // the ECI assignment numbers for ISO-8859-x, UTF-8 and UTF-16 are all 8 bit long
|
size += 4 + 8; // the ECI assignment numbers for ISO-8859-x, UTF-8 and UTF-16 are all 8 bit long
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
Mode::KANJI => size += 13,
|
Mode::KANJI => size += 13,
|
||||||
_=> {},
|
_ => {}
|
||||||
}
|
}
|
||||||
// switch (mode) {
|
// switch (mode) {
|
||||||
// case KANJI:
|
// case KANJI:
|
||||||
@@ -504,7 +688,7 @@ impl Edge<'_> {
|
|||||||
// }
|
// }
|
||||||
size
|
size
|
||||||
},
|
},
|
||||||
encoders
|
encoders,
|
||||||
}
|
}
|
||||||
// this.mode = mode;
|
// this.mode = mode;
|
||||||
// this.fromPosition = fromPosition;
|
// this.fromPosition = fromPosition;
|
||||||
@@ -544,21 +728,28 @@ impl Edge<'_> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct RXingResultList<'a> {
|
#[derive(Clone)]
|
||||||
list: Vec<RXingResultNode<'a>>,
|
pub struct RXingResultList {
|
||||||
|
list: Vec<RXingResultNode>,
|
||||||
version: VersionRef,
|
version: VersionRef,
|
||||||
}
|
}
|
||||||
impl RXingResultList<'_> {
|
impl RXingResultList {
|
||||||
|
pub fn new(
|
||||||
pub fn new( version:VersionRef, solution:&'_ Edge, isGS1:bool, ecLevel: &ErrorCorrectionLevel, encoders:&'_ ECIEncoderSet, stringToEncode: &'_ str) -> Self {
|
version: VersionRef,
|
||||||
let length = 0;
|
solution: Rc<Edge>,
|
||||||
let current = Some(solution);
|
isGS1: bool,
|
||||||
let containsECI = false;
|
ecLevel: &ErrorCorrectionLevel,
|
||||||
let list = Vec::new();
|
encoders: ECIEncoderSet,
|
||||||
|
stringToEncode: &str,
|
||||||
|
) -> Self {
|
||||||
|
let mut length = 0;
|
||||||
|
let mut current = Some(solution);
|
||||||
|
let mut containsECI = false;
|
||||||
|
let mut list = Vec::new();
|
||||||
|
|
||||||
while current.is_some() {
|
while current.is_some() {
|
||||||
length += current.as_ref().unwrap().characterLength;
|
length += current.as_ref().unwrap().characterLength;
|
||||||
let previous = current.as_ref().unwrap().previous;
|
let previous = current.as_ref().unwrap().previous.clone();
|
||||||
|
|
||||||
let needECI = current.as_ref().unwrap().mode == Mode::BYTE &&
|
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_none() && current.as_ref().unwrap().charsetEncoderIndex != 0) || // at the beginning and charset is not ISO-8859-1
|
||||||
@@ -568,13 +759,32 @@ impl RXingResultList<'_> {
|
|||||||
containsECI = true;
|
containsECI = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if previous.is_none() || previous.as_ref().unwrap().mode != current.as_ref().unwrap().mode || needECI {
|
if previous.is_none()
|
||||||
list.push( RXingResultNode::new(current.as_ref().unwrap().mode, current.as_ref().unwrap().fromPosition, current.as_ref().unwrap().charsetEncoderIndex, length,encoders,stringToEncode, version));
|
|| previous.as_ref().unwrap().mode != current.as_ref().unwrap().mode
|
||||||
|
|| needECI
|
||||||
|
{
|
||||||
|
list.push(RXingResultNode::new(
|
||||||
|
current.as_ref().unwrap().mode,
|
||||||
|
current.as_ref().unwrap().fromPosition,
|
||||||
|
current.as_ref().unwrap().charsetEncoderIndex,
|
||||||
|
length,
|
||||||
|
encoders.clone(),
|
||||||
|
stringToEncode,
|
||||||
|
version,
|
||||||
|
));
|
||||||
length = 0;
|
length = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if needECI {
|
if needECI {
|
||||||
list.push( RXingResultNode::new(Mode::ECI, current.as_ref().unwrap().fromPosition, current.as_ref().unwrap().charsetEncoderIndex, 0,encoders,stringToEncode, version));
|
list.push(RXingResultNode::new(
|
||||||
|
Mode::ECI,
|
||||||
|
current.as_ref().unwrap().fromPosition,
|
||||||
|
current.as_ref().unwrap().charsetEncoderIndex,
|
||||||
|
0,
|
||||||
|
encoders.clone(),
|
||||||
|
stringToEncode,
|
||||||
|
version,
|
||||||
|
));
|
||||||
}
|
}
|
||||||
current = previous;
|
current = previous;
|
||||||
}
|
}
|
||||||
@@ -582,26 +792,41 @@ impl RXingResultList<'_> {
|
|||||||
// prepend FNC1 if needed. If the bits contain an ECI then the FNC1 must be preceeded by an ECI.
|
// prepend FNC1 if needed. If the bits contain an ECI then the FNC1 must be preceeded by an ECI.
|
||||||
// If there is no ECI at the beginning then we put an ECI to the default charset (ISO-8859-1)
|
// If there is no ECI at the beginning then we put an ECI to the default charset (ISO-8859-1)
|
||||||
if isGS1 {
|
if isGS1 {
|
||||||
if let Some(first) = list.get(0){
|
if let Some(first) = list.get(0) {
|
||||||
// if first != null && first.mode != Mode.ECI && containsECI {
|
// if first != null && first.mode != Mode.ECI && containsECI {
|
||||||
if first.mode != Mode::ECI && containsECI {
|
if first.mode != Mode::ECI && containsECI {
|
||||||
// prepend a default character set ECI
|
// prepend a default character set ECI
|
||||||
list.push( RXingResultNode::new(Mode::ECI, 0, 0, 0,encoders,stringToEncode,version));
|
list.push(RXingResultNode::new(
|
||||||
}}
|
Mode::ECI,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
encoders.clone(),
|
||||||
|
stringToEncode,
|
||||||
|
version,
|
||||||
|
));
|
||||||
|
}
|
||||||
|
}
|
||||||
let first = list.get(0).unwrap();
|
let first = list.get(0).unwrap();
|
||||||
// prepend or insert a FNC1_FIRST_POSITION after the ECI (if any)
|
// prepend or insert a FNC1_FIRST_POSITION after the ECI (if any)
|
||||||
// if first != null && first.mode != Mode.ECI && containsECI {
|
// if first != null && first.mode != Mode.ECI && containsECI {
|
||||||
list.push( 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,
|
||||||
|
version,
|
||||||
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
// set version to smallest version into which the bits fit.
|
// set version to smallest version into which the bits fit.
|
||||||
let versionNumber = version.getVersionNumber();
|
let mut versionNumber = version.getVersionNumber();
|
||||||
let (lowerLimit,upperLimit) =
|
let (lowerLimit, upperLimit) = match MinimalEncoder::getVersionSize(&version) {
|
||||||
match MinimalEncoder::getVersionSize(&version) {
|
VersionSize::SMALL => (1, 9),
|
||||||
VersionSize::SMALL =>
|
VersionSize::MEDIUM => (10, 26),
|
||||||
(1,9),
|
_ => (27, 40),
|
||||||
VersionSize::MEDIUM=>(10,26),
|
|
||||||
_=>(27,40),
|
|
||||||
};
|
};
|
||||||
// let lowerLimit;
|
// let lowerLimit;
|
||||||
// let upperLimit;
|
// let upperLimit;
|
||||||
@@ -620,41 +845,48 @@ impl RXingResultList<'_> {
|
|||||||
// upperLimit = 40;
|
// upperLimit = 40;
|
||||||
// break;
|
// break;
|
||||||
// }
|
// }
|
||||||
let size = Self::internal_static_get_size(version,&list);
|
let size = Self::internal_static_get_size(version, &list);
|
||||||
// increase version if needed
|
// increase version if needed
|
||||||
while versionNumber < upperLimit && !encoder::willFit(size, Version::getVersionForNumber(versionNumber).unwrap(),
|
while versionNumber < upperLimit
|
||||||
ecLevel) {
|
&& !encoder::willFit(
|
||||||
versionNumber+=1;
|
size,
|
||||||
|
Version::getVersionForNumber(versionNumber).unwrap(),
|
||||||
|
ecLevel,
|
||||||
|
)
|
||||||
|
{
|
||||||
|
versionNumber += 1;
|
||||||
}
|
}
|
||||||
// shrink version if possible
|
// shrink version if possible
|
||||||
while versionNumber > lowerLimit && encoder::willFit(size, Version::getVersionForNumber(versionNumber - 1).unwrap(),
|
while versionNumber > lowerLimit
|
||||||
ecLevel) {
|
&& encoder::willFit(
|
||||||
versionNumber-=1;
|
size,
|
||||||
|
Version::getVersionForNumber(versionNumber - 1).unwrap(),
|
||||||
|
ecLevel,
|
||||||
|
)
|
||||||
|
{
|
||||||
|
versionNumber -= 1;
|
||||||
}
|
}
|
||||||
let version = Version::getVersionForNumber(versionNumber).unwrap();
|
let version = Version::getVersionForNumber(versionNumber).unwrap();
|
||||||
Self {
|
Self { list, version }
|
||||||
list,
|
|
||||||
version,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* returns the size in bits
|
* returns the size in bits
|
||||||
*/
|
*/
|
||||||
pub fn getSize(&self) -> u32{
|
pub fn getSize(&self) -> u32 {
|
||||||
self. getSizeLocal(self.version)
|
self.getSizeLocal(self.version)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn getSizeLocal(&self, version:VersionRef) -> u32{
|
fn getSizeLocal(&self, version: VersionRef) -> u32 {
|
||||||
let result = 0;
|
let mut result = 0;
|
||||||
for resultNode in &self.list {
|
for resultNode in &self.list {
|
||||||
result += resultNode.getSize(version);
|
result += resultNode.getSize(version);
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn internal_static_get_size(version:VersionRef, list: &Vec<RXingResultNode>) -> u32 {
|
fn internal_static_get_size(version: VersionRef, list: &Vec<RXingResultNode>) -> u32 {
|
||||||
let result = 0;
|
let mut result = 0;
|
||||||
for resultNode in list {
|
for resultNode in list {
|
||||||
result += resultNode.getSize(version);
|
result += resultNode.getSize(version);
|
||||||
}
|
}
|
||||||
@@ -664,22 +896,22 @@ impl RXingResultList<'_> {
|
|||||||
/**
|
/**
|
||||||
* appends the bits
|
* appends the bits
|
||||||
*/
|
*/
|
||||||
pub fn getBits(&self, bits:&BitArray) -> Result<(),Exceptions> {
|
pub fn getBits(&self, bits: &mut BitArray) -> Result<(), Exceptions> {
|
||||||
for resultNode in &self.list {
|
for resultNode in &self.list {
|
||||||
resultNode.getBits(bits);
|
resultNode.getBits(bits);
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn getVersion(&self) -> &Version{
|
pub fn getVersion(&self) -> VersionRef {
|
||||||
&self. version
|
self.version
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl fmt::Display for RXingResultList<'_> {
|
impl fmt::Display for RXingResultList {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
let mut result = String::new();
|
let mut result = String::new();
|
||||||
let previous = None;
|
let mut previous = None;
|
||||||
for current in &self.list {
|
for current in &self.list {
|
||||||
// for (RXingResultNode current : list) {
|
// for (RXingResultNode current : list) {
|
||||||
if previous.is_some() {
|
if previous.is_some() {
|
||||||
@@ -688,31 +920,38 @@ impl fmt::Display for RXingResultList<'_> {
|
|||||||
result.push_str(¤t.to_string());
|
result.push_str(¤t.to_string());
|
||||||
previous = Some(current);
|
previous = Some(current);
|
||||||
}
|
}
|
||||||
write!(f,"{}", result)
|
write!(f, "{}", result)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct RXingResultNode<'a> {
|
#[derive(Clone)]
|
||||||
|
struct RXingResultNode {
|
||||||
mode:Mode,
|
mode: Mode,
|
||||||
fromPosition:usize,
|
fromPosition: usize,
|
||||||
charsetEncoderIndex:usize,
|
charsetEncoderIndex: usize,
|
||||||
characterLength:u32,
|
characterLength: u32,
|
||||||
encoders:&'a ECIEncoderSet,
|
encoders: ECIEncoderSet,
|
||||||
version: VersionRef,
|
version: VersionRef,
|
||||||
stringToEncode: &'a str,
|
stringToEncode: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl RXingResultNode<'_> {
|
impl RXingResultNode {
|
||||||
|
pub fn new(
|
||||||
pub fn new( mode:Mode, fromPosition:usize, charsetEncoderIndex:usize, characterLength:u32, encoders:&'_ ECIEncoderSet, stringToEncode: &'_ str, version: &'_ Version) -> Self {
|
mode: Mode,
|
||||||
|
fromPosition: usize,
|
||||||
|
charsetEncoderIndex: usize,
|
||||||
|
characterLength: u32,
|
||||||
|
encoders: ECIEncoderSet,
|
||||||
|
stringToEncode: &str,
|
||||||
|
version: VersionRef,
|
||||||
|
) -> Self {
|
||||||
Self {
|
Self {
|
||||||
mode,
|
mode,
|
||||||
fromPosition,
|
fromPosition,
|
||||||
charsetEncoderIndex,
|
charsetEncoderIndex,
|
||||||
characterLength,
|
characterLength,
|
||||||
encoders,
|
encoders,
|
||||||
stringToEncode,
|
stringToEncode: String::from(stringToEncode),
|
||||||
version,
|
version,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -720,22 +959,34 @@ impl RXingResultNode<'_> {
|
|||||||
/**
|
/**
|
||||||
* returns the size in bits
|
* returns the size in bits
|
||||||
*/
|
*/
|
||||||
fn getSize(&self, version:&Version) -> u32{
|
fn getSize(&self, version: &Version) -> u32 {
|
||||||
let size = 4 + self.mode.getCharacterCountBits(version) as u32;
|
let mut size = 4 + self.mode.getCharacterCountBits(version) as u32;
|
||||||
match self.mode {
|
match self.mode {
|
||||||
Mode::NUMERIC => {
|
Mode::NUMERIC => {
|
||||||
size += (self.characterLength / 3) * 10;
|
size += (self.characterLength / 3) * 10;
|
||||||
let rest = self.characterLength % 3;
|
let rest = self.characterLength % 3;
|
||||||
size += if rest == 1 {4} else { if rest == 2 {7} else {0}};
|
size += if rest == 1 {
|
||||||
},
|
4
|
||||||
|
} else {
|
||||||
|
if rest == 2 {
|
||||||
|
7
|
||||||
|
} else {
|
||||||
|
0
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
Mode::ALPHANUMERIC => {
|
Mode::ALPHANUMERIC => {
|
||||||
size += (self.characterLength / 2) * 11;
|
size += (self.characterLength / 2) * 11;
|
||||||
size += if (self.characterLength % 2) == 1 {6} else {0};
|
size += if (self.characterLength % 2) == 1 {
|
||||||
},
|
6
|
||||||
|
} else {
|
||||||
|
0
|
||||||
|
};
|
||||||
|
}
|
||||||
Mode::BYTE => size += 8 * self.getCharacterCountIndicator(),
|
Mode::BYTE => size += 8 * self.getCharacterCountIndicator(),
|
||||||
Mode::ECI => size += 8,
|
Mode::ECI => size += 8,
|
||||||
Mode::KANJI => size += 13 * self.characterLength,
|
Mode::KANJI => size += 13 * self.characterLength,
|
||||||
_ => {},
|
_ => {}
|
||||||
}
|
}
|
||||||
// switch (mode) {
|
// switch (mode) {
|
||||||
// case KANJI:
|
// case KANJI:
|
||||||
@@ -763,32 +1014,51 @@ impl RXingResultNode<'_> {
|
|||||||
* returns the length in characters according to the specification (differs from getCharacterLength() in BYTE mode
|
* returns the length in characters according to the specification (differs from getCharacterLength() in BYTE mode
|
||||||
* for multi byte encoded characters)
|
* for multi byte encoded characters)
|
||||||
*/
|
*/
|
||||||
fn getCharacterCountIndicator(&self) -> u32{
|
fn getCharacterCountIndicator(&self) -> u32 {
|
||||||
if self.mode == Mode::BYTE
|
if self.mode == Mode::BYTE {
|
||||||
{self.encoders.encode_string(&self.stringToEncode[self.fromPosition as usize..(self.fromPosition + self.characterLength as usize)],
|
self.encoders
|
||||||
self.charsetEncoderIndex as usize).len() as u32} else {self.characterLength}
|
.encode_string(
|
||||||
|
&self.stringToEncode[self.fromPosition as usize
|
||||||
|
..(self.fromPosition + self.characterLength as usize)],
|
||||||
|
self.charsetEncoderIndex as usize,
|
||||||
|
)
|
||||||
|
.len() as u32
|
||||||
|
} else {
|
||||||
|
self.characterLength
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* appends the bits
|
* appends the bits
|
||||||
*/
|
*/
|
||||||
fn getBits(&self, bits:&BitArray) -> Result<(),Exceptions> {
|
fn getBits(&self, bits: &mut BitArray) -> Result<(), Exceptions> {
|
||||||
bits.appendBits(self.mode.getBits() as u32, 4);
|
bits.appendBits(self.mode.getBits() as u32, 4);
|
||||||
if self.characterLength > 0 {
|
if self.characterLength > 0 {
|
||||||
let length = self.getCharacterCountIndicator();
|
let length = self.getCharacterCountIndicator();
|
||||||
bits.appendBits(length, self.mode.getCharacterCountBits(self.version) as usize);
|
bits.appendBits(
|
||||||
|
length,
|
||||||
|
self.mode.getCharacterCountBits(self.version) as usize,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
if self.mode == Mode::ECI {
|
if self.mode == Mode::ECI {
|
||||||
bits.appendBits(self.encoders.getECIValue(self.charsetEncoderIndex as usize), 8);
|
bits.appendBits(
|
||||||
|
self.encoders.getECIValue(self.charsetEncoderIndex as usize),
|
||||||
|
8,
|
||||||
|
);
|
||||||
} else if self.characterLength > 0 {
|
} else if self.characterLength > 0 {
|
||||||
// append data
|
// append data
|
||||||
encoder::appendBytes(&self.stringToEncode[self.fromPosition as usize..(self.fromPosition + self.characterLength as usize)], self.mode, bits,
|
encoder::appendBytes(
|
||||||
self.encoders.getCharset(self.charsetEncoderIndex as usize));
|
&self.stringToEncode[self.fromPosition as usize
|
||||||
|
..(self.fromPosition + self.characterLength as usize)],
|
||||||
|
self.mode,
|
||||||
|
bits,
|
||||||
|
self.encoders.getCharset(self.charsetEncoderIndex as usize),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn makePrintable( s:&str) -> String {
|
fn makePrintable(s: &str) -> String {
|
||||||
let mut result = String::new();
|
let mut result = String::new();
|
||||||
for i in 0..s.chars().count() {
|
for i in 0..s.chars().count() {
|
||||||
// for (int i = 0; i < s.length(); i++) {
|
// for (int i = 0; i < s.length(); i++) {
|
||||||
@@ -800,20 +1070,27 @@ impl RXingResultNode<'_> {
|
|||||||
}
|
}
|
||||||
result
|
result
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl fmt::Display for RXingResultNode<'_> {
|
impl fmt::Display for RXingResultNode {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
let result = String::new();
|
let mut result = String::new();
|
||||||
result.push_str(&format!("{:?}",self.mode));
|
result.push_str(&format!("{:?}", self.mode));
|
||||||
result.push('(');
|
result.push('(');
|
||||||
if self.mode == Mode::ECI {
|
if self.mode == Mode::ECI {
|
||||||
result.push_str(self.encoders.getCharset(self.charsetEncoderIndex as usize).name());
|
result.push_str(
|
||||||
|
self.encoders
|
||||||
|
.getCharset(self.charsetEncoderIndex as usize)
|
||||||
|
.name(),
|
||||||
|
);
|
||||||
} else {
|
} else {
|
||||||
result.push_str(&Self::makePrintable(&self.stringToEncode[self.fromPosition as usize..(self.fromPosition + self.characterLength as usize)]));
|
result.push_str(&Self::makePrintable(
|
||||||
|
&self.stringToEncode[self.fromPosition as usize
|
||||||
|
..(self.fromPosition + self.characterLength as usize)],
|
||||||
|
));
|
||||||
}
|
}
|
||||||
result.push(')');
|
result.push(')');
|
||||||
|
|
||||||
write!(f,"{}", result)
|
write!(f, "{}", result)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user