From 4c51e2611c3e61da33b0866aac3fa1a1cdb84301 Mon Sep 17 00:00:00 2001 From: Henry Schimke Date: Wed, 5 Oct 2022 13:44:51 -0500 Subject: [PATCH] qrcode encoder pass --- src/qrcode/decoder/error_correction_level.rs | 9 +++ src/qrcode/decoder/version.rs | 2 +- src/qrcode/encoder/encoder.rs | 70 +++++++++++--------- 3 files changed, 50 insertions(+), 31 deletions(-) diff --git a/src/qrcode/decoder/error_correction_level.rs b/src/qrcode/decoder/error_correction_level.rs index 7030cd4..908c8a5 100644 --- a/src/qrcode/decoder/error_correction_level.rs +++ b/src/qrcode/decoder/error_correction_level.rs @@ -60,6 +60,15 @@ impl ErrorCorrectionLevel { ErrorCorrectionLevel::H => 0x02, } } + + pub fn get_ordinal(&self) -> u8 { + match self { + ErrorCorrectionLevel::L => 0, + ErrorCorrectionLevel::M => 1, + ErrorCorrectionLevel::Q => 2, + ErrorCorrectionLevel::H => 3, + } + } } impl TryFrom for ErrorCorrectionLevel { diff --git a/src/qrcode/decoder/version.rs b/src/qrcode/decoder/version.rs index a3285b6..3ecdc50 100755 --- a/src/qrcode/decoder/version.rs +++ b/src/qrcode/decoder/version.rs @@ -90,7 +90,7 @@ impl Version { } pub fn getECBlocksForLevel(&self, ecLevel: ErrorCorrectionLevel) -> &ECBlocks { - &self.ecBlocks[ecLevel.get_value() as usize] + &self.ecBlocks[ecLevel.get_ordinal() as usize] } /** diff --git a/src/qrcode/encoder/encoder.rs b/src/qrcode/encoder/encoder.rs index 99640a1..4caec1f 100644 --- a/src/qrcode/encoder/encoder.rs +++ b/src/qrcode/encoder/encoder.rs @@ -38,6 +38,7 @@ use std::collections::HashMap; use encoding::EncodingRef; use lazy_static::lazy_static; +use unicode_segmentation::UnicodeSegmentation; use crate::{ common::{ @@ -123,7 +124,7 @@ pub fn encode_with_hints( }; // Determine what character encoding has been specified by the caller, if any - let mut encoding = None;//DEFAULT_BYTE_MODE_ENCODING; + let mut encoding = None; //DEFAULT_BYTE_MODE_ENCODING; let hasEncodingHint = hints.contains_key(&EncodeHintType::CHARACTER_SET); if hasEncodingHint { if let EncodeHintValue::CharacterSet(v) = hints.get(&EncodeHintType::CHARACTER_SET).unwrap() @@ -151,7 +152,11 @@ pub fn encode_with_hints( version = rn.getVersion(); } else { //Switch to default encoding - let encoding = if encoding.is_some() { encoding.unwrap() } else { DEFAULT_BYTE_MODE_ENCODING }; + let encoding = if encoding.is_some() { + encoding.unwrap() + } else { + DEFAULT_BYTE_MODE_ENCODING + }; // 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. @@ -213,7 +218,7 @@ pub fn encode_with_hints( let numLetters = if mode == Mode::BYTE { dataBits.getSizeInBytes() } else { - content.len() + content.graphemes(true).count() }; appendLengthInfo(numLetters as u32, version, mode, &mut headerAndDataBits)?; // Put data together into the overall payload @@ -298,7 +303,7 @@ fn recommendVersion( // 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); - + chooseVersion(bitsNeeded, ecLevel) } @@ -362,12 +367,11 @@ fn chooseModeWithEncoding(content: &str, encoding: EncodingRef) -> Mode { } pub fn isOnlyDoubleByteKanji(content: &str) -> bool { - let bytes = if let Ok(byt) = SHIFT_JIS_CHARSET - .encode(content, encoding::EncoderTrap::Strict) { - byt - }else { - return false - }; + let bytes = if let Ok(byt) = SHIFT_JIS_CHARSET.encode(content, encoding::EncoderTrap::Strict) { + byt + } else { + return false; + }; let length = bytes.len(); if length % 2 != 0 { return false; @@ -395,8 +399,9 @@ fn chooseMaskPattern( // We try all mask patterns to choose the best one. for maskPattern in 0..QRCode::NUM_MASK_PATTERNS { // for (int maskPattern = 0; maskPattern < QRCode.NUM_MASK_PATTERNS; maskPattern++) { - matrix_util::buildMatrix(bits, ecLevel, version, maskPattern, matrix)?; - let penalty = calculateMaskPenalty(matrix); + let mut matrix = matrix.clone(); + matrix_util::buildMatrix(bits, ecLevel, version, maskPattern, &mut matrix)?; + let penalty = calculateMaskPenalty(&matrix); if penalty < minPenalty { minPenalty = penalty; bestMaskPattern = maskPattern; @@ -470,7 +475,9 @@ pub fn terminateBits(num_data_bytes: u32, bits: &mut BitArray) -> Result<(), Exc // If we have more space, we'll fill the space with padding patterns defined in 8.4.9 (p.24). let num_padding_bytes = num_data_bytes as isize - bits.getSizeInBytes() as isize; for i in 0..num_padding_bytes { - if i >= num_padding_bytes{ break } + if i >= num_padding_bytes { + break; + } // for (int i = 0; i < numPaddingBytes; ++i) { bits.appendBits(if (i & 0x01) == 0 { 0xEC } else { 0x11 }, 8)?; } @@ -495,7 +502,7 @@ pub fn getNumDataBytesAndNumECBytesForBlockID( blockID: u32, // numDataBytesInBlock: &mut [u32], // numECBytesInBlock: &mut [u32], -) -> Result<(u32,u32), Exceptions> { +) -> Result<(u32, u32), Exceptions> { if blockID >= numRSBlocks { return Err(Exceptions::WriterException("Block ID too large".to_owned())); // throw new WriterException("Block ID too large"); @@ -541,9 +548,9 @@ pub fn getNumDataBytesAndNumECBytesForBlockID( } Ok(if blockID < numRsBlocksInGroup1 { - (numDataBytesInGroup1,numEcBytesInGroup1) + (numDataBytesInGroup1, numEcBytesInGroup1) } else { - (numDataBytesInGroup2,numEcBytesInGroup2) + (numDataBytesInGroup2, numEcBytesInGroup2) }) } @@ -651,7 +658,8 @@ pub fn generateECBytes(dataBytes: &[u8], numEcBytesInBlock: usize) -> Vec { ReedSolomonEncoder::new(get_predefined_genericgf( PredefinedGenericGF::QrCodeField256, )) - .encode(&mut toEncode, numEcBytesInBlock).expect("rs encode must complete"); + .encode(&mut toEncode, numEcBytesInBlock) + .expect("rs encode must complete"); let mut ecBytes = vec![0u8; numEcBytesInBlock]; for i in 0..numEcBytesInBlock { @@ -664,7 +672,7 @@ pub fn generateECBytes(dataBytes: &[u8], numEcBytesInBlock: usize) -> Vec { /** * Append mode info. On success, store the result in "bits". */ -pub fn appendModeInfo(mode: Mode, bits: &mut BitArray) -> Result<(),Exceptions> { +pub fn appendModeInfo(mode: Mode, bits: &mut BitArray) -> Result<(), Exceptions> { bits.appendBits(mode.getBits() as u32, 4)?; Ok(()) } @@ -704,12 +712,10 @@ pub fn appendBytes( Mode::ALPHANUMERIC => appendAlphanumericBytes(content, bits), Mode::BYTE => append8BitBytes(content, bits, encoding), Mode::KANJI => appendKanjiBytes(content, bits), - _ => { - Err(Exceptions::WriterException(format!( - "Invalid mode: {:?}", - mode - ))) - } + _ => Err(Exceptions::WriterException(format!( + "Invalid mode: {:?}", + mode + ))), } // switch (mode) { // case NUMERIC: @@ -729,7 +735,7 @@ pub fn appendBytes( // } } -pub fn appendNumericBytes(content: &str, bits: &mut BitArray) -> Result<(),Exceptions> { +pub fn appendNumericBytes(content: &str, bits: &mut BitArray) -> Result<(), Exceptions> { let length = content.len(); let mut i = 0; while i < length { @@ -779,7 +785,11 @@ pub fn appendAlphanumericBytes(content: &str, bits: &mut BitArray) -> Result<(), Ok(()) } -pub fn append8BitBytes(content: &str, bits: &mut BitArray, encoding: EncodingRef) -> Result<(),Exceptions> { +pub fn append8BitBytes( + content: &str, + bits: &mut BitArray, + encoding: EncodingRef, +) -> Result<(), Exceptions> { let bytes = encoding .encode(content, encoding::EncoderTrap::Strict) .expect("should encode"); @@ -807,9 +817,9 @@ pub fn appendKanjiBytes(content: &str, bits: &mut BitArray) -> Result<(), Except let mut i = 0; while i < max_i { // for (int i = 0; i < maxI; i += 2) { - let byte1 = bytes[i];// & 0xFF; - let byte2 = bytes[i + 1];// & 0xFF; - let code:u16 = ((byte1 as u16) << 8u16) | byte2 as u16; + let byte1 = bytes[i]; // & 0xFF; + let byte2 = bytes[i + 1]; // & 0xFF; + let code: u16 = ((byte1 as u16) << 8u16) | byte2 as u16; let mut subtracted: i32 = -1; if code >= 0x8140 && code <= 0x9ffc { subtracted = code as i32 - 0x8140; @@ -829,7 +839,7 @@ pub fn appendKanjiBytes(content: &str, bits: &mut BitArray) -> Result<(), Except Ok(()) } -fn appendECI(eci: &CharacterSetECI, bits: &mut BitArray) -> Result<(),Exceptions>{ +fn appendECI(eci: &CharacterSetECI, bits: &mut BitArray) -> Result<(), Exceptions> { bits.appendBits(Mode::ECI.getBits() as u32, 4)?; // This is correct for values up to 127, which is all we need now. bits.appendBits(eci.getValueSelf(), 8)?;