diff --git a/qrcode-rust/Cargo.toml b/qrcode-rust/Cargo.toml deleted file mode 100644 index f442da36..00000000 --- a/qrcode-rust/Cargo.toml +++ /dev/null @@ -1,21 +0,0 @@ -[package] -name = "qrcode" -description = "QR code encoder in Rust" -license = "MIT OR Apache-2.0" -version = "0.12.0" -edition = "2018" -authors = ["kennytm "] -keywords = ["qrcode"] - - -[dependencies] -# checked_int_cast = "1" - - -[features] -default = [] -bench = [] -svg = [] - -[[bin]] -name = "qrencode" diff --git a/qrcode-rust/rustfmt.toml b/qrcode-rust/rustfmt.toml deleted file mode 100644 index acd20212..00000000 --- a/qrcode-rust/rustfmt.toml +++ /dev/null @@ -1,3 +0,0 @@ -max_width = 120 -use_small_heuristics = "Max" -use_field_init_shorthand = true diff --git a/qrcode-rust/src/bin/qrencode.rs b/qrcode-rust/src/bin/qrencode.rs deleted file mode 100644 index 48378288..00000000 --- a/qrcode-rust/src/bin/qrencode.rs +++ /dev/null @@ -1,8 +0,0 @@ -use std::env; - -pub fn main() { - let arg = env::args().nth(1).unwrap(); - let code = qrcode::QrCode::new(arg.as_bytes()).unwrap(); - - print!("{}", code.render().dark_color("\x1b[7m \x1b[0m").light_color("\x1b[49m \x1b[0m").build()); -} diff --git a/qrcode-rust/src/bits.rs b/qrcode-rust/src/bits.rs deleted file mode 100644 index 9cc951cc..00000000 --- a/qrcode-rust/src/bits.rs +++ /dev/null @@ -1,982 +0,0 @@ -//! The `bits` module encodes binary data into raw bits used in a QR code. - -use core::cmp::min; - -#[cfg(feature = "bench")] -extern crate test; - -use alloc::vec::Vec; - -use crate::cast::{As, Truncate}; -use crate::optimize::{total_encoded_len, Optimizer, Parser, Segment}; -use crate::types::{EcLevel, Mode, QrError, QrResult, Version}; - -//------------------------------------------------------------------------------ -//{{{ Bits - -/// The `Bits` structure stores the encoded data for a QR code. -pub struct Bits { - data: Vec, - bit_offset: usize, - version: Version, -} - -impl Bits { - /// Constructs a new, empty bits structure. - pub fn new(version: Version) -> Self { - Self { data: Vec::new(), bit_offset: 0, version } - } - - /// Pushes an N-bit big-endian integer to the end of the bits. - /// - /// Note: It is up to the developer to ensure that `number` really only is - /// `n` bit in size. Otherwise the excess bits may stomp on the existing - /// ones. - fn push_number(&mut self, n: usize, number: u16) { - debug_assert!(n == 16 || n < 16 && number < (1 << n), "{} is too big as a {}-bit number", number, n); - - let b = self.bit_offset + n; - let last_index = self.data.len().wrapping_sub(1); - match (self.bit_offset, b) { - (0, 0..=8) => { - self.data.push((number << (8 - b)).truncate_as_u8()); - } - (0, _) => { - self.data.push((number >> (b - 8)).truncate_as_u8()); - self.data.push((number << (16 - b)).truncate_as_u8()); - } - (_, 0..=8) => { - self.data[last_index] |= (number << (8 - b)).truncate_as_u8(); - } - (_, 9..=16) => { - self.data[last_index] |= (number >> (b - 8)).truncate_as_u8(); - self.data.push((number << (16 - b)).truncate_as_u8()); - } - _ => { - self.data[last_index] |= (number >> (b - 8)).truncate_as_u8(); - self.data.push((number >> (b - 16)).truncate_as_u8()); - self.data.push((number << (24 - b)).truncate_as_u8()); - } - } - self.bit_offset = b & 7; - } - - /// Pushes an N-bit big-endian integer to the end of the bits, and check - /// that the number does not overflow the bits. - /// - /// Returns `Err(QrError::DataTooLong)` on overflow. - fn push_number_checked(&mut self, n: usize, number: usize) -> QrResult<()> { - if n > 16 || number >= (1 << n) { - Err(QrError::DataTooLong) - } else { - self.push_number(n, number.as_u16()); - Ok(()) - } - } - - /// Reserves `n` extra bits of space for pushing. - fn reserve(&mut self, n: usize) { - let extra_bytes = (n + (8 - self.bit_offset) % 8) / 8; - self.data.reserve(extra_bytes); - } - - /// Convert the bits into a bytes vector. - pub fn into_bytes(self) -> Vec { - self.data - } - - /// Total number of bits currently pushed. - pub fn len(&self) -> usize { - if self.bit_offset == 0 { - self.data.len() * 8 - } else { - (self.data.len() - 1) * 8 + self.bit_offset - } - } - - /// Whether there are any bits pushed. - pub fn is_empty(&self) -> bool { - self.data.is_empty() - } - - /// The maximum number of bits allowed by the provided QR code version and - /// error correction level. - /// - /// # Errors - /// - /// Returns `Err(QrError::InvalidVersion)` if it is not valid to use the - /// `ec_level` for the given version (e.g. `Version::Micro(1)` with - /// `EcLevel::H`). - pub fn max_len(&self, ec_level: EcLevel) -> QrResult { - self.version.fetch(ec_level, &DATA_LENGTHS) - } - - /// Version of the QR code. - pub fn version(&self) -> Version { - self.version - } -} - -#[test] -fn test_push_number() { - let mut bits = Bits::new(Version::Normal(1)); - - bits.push_number(3, 0b010); // 0:0 .. 0:3 - bits.push_number(3, 0b110); // 0:3 .. 0:6 - bits.push_number(3, 0b101); // 0:6 .. 1:1 - bits.push_number(7, 0b001_1010); // 1:1 .. 2:0 - bits.push_number(4, 0b1100); // 2:0 .. 2:4 - bits.push_number(12, 0b1011_0110_1101); // 2:4 .. 4:0 - bits.push_number(10, 0b01_1001_0001); // 4:0 .. 5:2 - bits.push_number(15, 0b111_0010_1110_0011); // 5:2 .. 7:1 - - let bytes = bits.into_bytes(); - - assert_eq!( - bytes, - vec![ - 0b0101_1010, // 90 - 0b1001_1010, // 154 - 0b1100_1011, // 203 - 0b0110_1101, // 109 - 0b01_1001_00, // 100 - 0b0111_1001, // 121 - 0b0111_0001, // 113 - 0b1000_0000, // 128 - ] - ); -} - -#[cfg(feature = "bench")] -#[bench] -fn bench_push_splitted_bytes(bencher: &mut test::Bencher) { - bencher.iter(|| { - let mut bits = Bits::new(Version::Normal(40)); - bits.push_number(4, 0b0101); - for _ in 0..1024 { - bits.push_number(8, 0b10101010); - } - bits.into_bytes() - }); -} - -//}}} -//------------------------------------------------------------------------------ -//{{{ Mode indicator - -/// An "extended" mode indicator, includes all indicators supported by QR code -/// beyond those bearing data. -#[derive(Copy, Clone)] -pub enum ExtendedMode { - /// ECI mode indicator, to introduce an ECI designator. - Eci, - - /// The normal mode to introduce data. - Data(Mode), - - /// FNC-1 mode in the first position. - Fnc1First, - - /// FNC-1 mode in the second position. - Fnc1Second, - - /// Structured append. - StructuredAppend, -} - -impl Bits { - /// Push the mode indicator to the end of the bits. - /// - /// # Errors - /// - /// If the mode is not supported in the provided version, this method - /// returns `Err(QrError::UnsupportedCharacterSet)`. - pub fn push_mode_indicator(&mut self, mode: ExtendedMode) -> QrResult<()> { - #[allow(clippy::match_same_arms)] - let number = match (self.version, mode) { - (Version::Micro(1), ExtendedMode::Data(Mode::Numeric)) => return Ok(()), - (Version::Micro(_), ExtendedMode::Data(Mode::Numeric)) => 0, - (Version::Micro(_), ExtendedMode::Data(Mode::Alphanumeric)) => 1, - (Version::Micro(_), ExtendedMode::Data(Mode::Byte)) => 0b10, - (Version::Micro(_), ExtendedMode::Data(Mode::Kanji)) => 0b11, - (Version::Micro(_), _) => return Err(QrError::UnsupportedCharacterSet), - (_, ExtendedMode::Data(Mode::Numeric)) => 0b0001, - (_, ExtendedMode::Data(Mode::Alphanumeric)) => 0b0010, - (_, ExtendedMode::Data(Mode::Byte)) => 0b0100, - (_, ExtendedMode::Data(Mode::Kanji)) => 0b1000, - (_, ExtendedMode::Eci) => 0b0111, - (_, ExtendedMode::Fnc1First) => 0b0101, - (_, ExtendedMode::Fnc1Second) => 0b1001, - (_, ExtendedMode::StructuredAppend) => 0b0011, - }; - let bits = self.version.mode_bits_count(); - self.push_number_checked(bits, number).or(Err(QrError::UnsupportedCharacterSet)) - } -} - -//}}} -//------------------------------------------------------------------------------ -//{{{ ECI - -impl Bits { - /// Push an ECI (Extended Channel Interpretation) designator to the bits. - /// - /// An ECI designator is a 6-digit number to specify the character set of - /// the following binary data. After calling this method, one could call - /// `.push_byte_data()` or similar methods to insert the actual data, e.g. - /// - /// #![allow(unused_must_use)] - /// - /// use qrcode::bits::Bits; - /// use qrcode::types::Version; - /// - /// let mut bits = Bits::new(Version::Normal(1)); - /// bits.push_eci_designator(9); // 9 = ISO-8859-7 (Greek). - /// bits.push_byte_data(b"\xa1\xa2\xa3\xa4\xa5"); // ΑΒΓΔΕ - /// - /// - /// The full list of ECI designator values can be found from - /// . Some example values are: - /// - /// ECI # | Character set - /// ------|------------------------------------- - /// 3 | ISO-8859-1 (Western European) - /// 20 | Shift JIS (Japanese) - /// 23 | Windows 1252 (Latin 1) (Western European) - /// 25 | UTF-16 Big Endian - /// 26 | UTF-8 - /// 28 | Big 5 (Traditional Chinese) - /// 29 | GB-18030 (Simplified Chinese) - /// 30 | EUC-KR (Korean) - /// - /// # Errors - /// - /// If the QR code version does not support ECI, this method will return - /// `Err(QrError::UnsupportedCharacterSet)`. - /// - /// If the designator is outside of the expected range, this method will - /// return `Err(QrError::InvalidECIDesignator)`. - pub fn push_eci_designator(&mut self, eci_designator: u32) -> QrResult<()> { - self.reserve(12); // assume the common case that eci_designator <= 127. - self.push_mode_indicator(ExtendedMode::Eci)?; - match eci_designator { - 0..=127 => { - self.push_number(8, eci_designator.as_u16()); - } - 128..=16383 => { - self.push_number(2, 0b10); - self.push_number(14, eci_designator.as_u16()); - } - 16384..=999_999 => { - self.push_number(3, 0b110); - self.push_number(5, (eci_designator >> 16).as_u16()); - self.push_number(16, (eci_designator & 0xffff).as_u16()); - } - _ => return Err(QrError::InvalidEciDesignator), - } - Ok(()) - } -} - -#[cfg(test)] -mod eci_tests { - use crate::bits::Bits; - use crate::types::{QrError, Version}; - - #[test] - fn test_9() { - let mut bits = Bits::new(Version::Normal(1)); - assert_eq!(bits.push_eci_designator(9), Ok(())); - assert_eq!(bits.into_bytes(), vec![0b0111_0000, 0b1001_0000]); - } - - #[test] - fn test_899() { - let mut bits = Bits::new(Version::Normal(1)); - assert_eq!(bits.push_eci_designator(899), Ok(())); - assert_eq!(bits.into_bytes(), vec![0b0111_1000, 0b00111000, 0b0011_0000]); - } - - #[test] - fn test_999999() { - let mut bits = Bits::new(Version::Normal(1)); - assert_eq!(bits.push_eci_designator(999999), Ok(())); - assert_eq!(bits.into_bytes(), vec![0b0111_1100, 0b11110100, 0b00100011, 0b1111_0000]); - } - - #[test] - fn test_invalid_designator() { - let mut bits = Bits::new(Version::Normal(1)); - assert_eq!(bits.push_eci_designator(1000000), Err(QrError::InvalidEciDesignator)); - } - - #[test] - fn test_unsupported_character_set() { - let mut bits = Bits::new(Version::Micro(4)); - assert_eq!(bits.push_eci_designator(9), Err(QrError::UnsupportedCharacterSet)); - } -} - -//}}} -//------------------------------------------------------------------------------ -//{{{ Mode::Numeric mode - -impl Bits { - fn push_header(&mut self, mode: Mode, raw_data_len: usize) -> QrResult<()> { - let length_bits = mode.length_bits_count(self.version); - self.reserve(length_bits + 4 + mode.data_bits_count(raw_data_len)); - self.push_mode_indicator(ExtendedMode::Data(mode))?; - self.push_number_checked(length_bits, raw_data_len)?; - Ok(()) - } - - /// Encodes a numeric string to the bits. - /// - /// The data should only contain the characters 0 to 9. - /// - /// # Errors - /// - /// Returns `Err(QrError::DataTooLong)` on overflow. - pub fn push_numeric_data(&mut self, data: &[u8]) -> QrResult<()> { - self.push_header(Mode::Numeric, data.len())?; - for chunk in data.chunks(3) { - let number = chunk.iter().map(|b| u16::from(*b - b'0')).fold(0, |a, b| a * 10 + b); - let length = chunk.len() * 3 + 1; - self.push_number(length, number); - } - Ok(()) - } -} - -#[cfg(test)] -mod numeric_tests { - use crate::bits::Bits; - use crate::types::{QrError, Version}; - - #[test] - fn test_iso_18004_2006_example_1() { - let mut bits = Bits::new(Version::Normal(1)); - assert_eq!(bits.push_numeric_data(b"01234567"), Ok(())); - assert_eq!(bits.into_bytes(), vec![0b0001_0000, 0b001000_00, 0b00001100, 0b01010110, 0b0110_0001, 0b1000_0000]); - } - - #[test] - fn test_iso_18004_2000_example_2() { - let mut bits = Bits::new(Version::Normal(1)); - assert_eq!(bits.push_numeric_data(b"0123456789012345"), Ok(())); - assert_eq!( - bits.into_bytes(), - vec![ - 0b0001_0000, - 0b010000_00, - 0b00001100, - 0b01010110, - 0b0110_1010, - 0b0110_1110, - 0b000101_00, - 0b11101010, - 0b0101_0000, - ] - ); - } - - #[test] - fn test_iso_18004_2006_example_2() { - let mut bits = Bits::new(Version::Micro(3)); - assert_eq!(bits.push_numeric_data(b"0123456789012345"), Ok(())); - assert_eq!( - bits.into_bytes(), - vec![0b0010_0000, 0b00000110, 0b0010_1011, 0b0011_0101, 0b0011_0111, 0b0000_1010, 0b01110101, 0b0010_1000,] - ); - } - - #[test] - fn test_data_too_long_error() { - let mut bits = Bits::new(Version::Micro(1)); - assert_eq!(bits.push_numeric_data(b"12345678"), Err(QrError::DataTooLong)); - } -} - -//}}} -//------------------------------------------------------------------------------ -//{{{ Mode::Alphanumeric mode - -/// In QR code `Mode::Alphanumeric` mode, a pair of alphanumeric characters will -/// be encoded as a base-45 integer. `alphanumeric_digit` converts each -/// character into its corresponding base-45 digit. -/// -/// The conversion is specified in ISO/IEC 18004:2006, §8.4.3, Table 5. -#[inline] -fn alphanumeric_digit(character: u8) -> u16 { - match character { - b'0'..=b'9' => u16::from(character - b'0'), - b'A'..=b'Z' => u16::from(character - b'A') + 10, - b' ' => 36, - b'$' => 37, - b'%' => 38, - b'*' => 39, - b'+' => 40, - b'-' => 41, - b'.' => 42, - b'/' => 43, - b':' => 44, - _ => 0, - } -} - -impl Bits { - /// Encodes an alphanumeric string to the bits. - /// - /// The data should only contain the charaters A to Z (excluding lowercase), - /// 0 to 9, space, `$`, `%`, `*`, `+`, `-`, `.`, `/` or `:`. - /// - /// # Errors - /// - /// Returns `Err(QrError::DataTooLong)` on overflow. - pub fn push_alphanumeric_data(&mut self, data: &[u8]) -> QrResult<()> { - self.push_header(Mode::Alphanumeric, data.len())?; - for chunk in data.chunks(2) { - let number = chunk.iter().map(|b| alphanumeric_digit(*b)).fold(0, |a, b| a * 45 + b); - let length = chunk.len() * 5 + 1; - self.push_number(length, number); - } - Ok(()) - } -} - -#[cfg(test)] -mod alphanumeric_tests { - use crate::bits::Bits; - use crate::types::{QrError, Version}; - - #[test] - fn test_iso_18004_2006_example() { - let mut bits = Bits::new(Version::Normal(1)); - assert_eq!(bits.push_alphanumeric_data(b"AC-42"), Ok(())); - assert_eq!(bits.into_bytes(), vec![0b0010_0000, 0b0010_1001, 0b11001110, 0b11100111, 0b0010_0001, 0b0000_0000]); - } - - #[test] - fn test_micro_qr_unsupported() { - let mut bits = Bits::new(Version::Micro(1)); - assert_eq!(bits.push_alphanumeric_data(b"A"), Err(QrError::UnsupportedCharacterSet)); - } - - #[test] - fn test_data_too_long() { - let mut bits = Bits::new(Version::Micro(2)); - assert_eq!(bits.push_alphanumeric_data(b"ABCDEFGH"), Err(QrError::DataTooLong)); - } -} - -//}}} -//------------------------------------------------------------------------------ -//{{{ Mode::Byte mode - -impl Bits { - /// Encodes 8-bit byte data to the bits. - /// - /// # Errors - /// - /// Returns `Err(QrError::DataTooLong)` on overflow. - pub fn push_byte_data(&mut self, data: &[u8]) -> QrResult<()> { - self.push_header(Mode::Byte, data.len())?; - for b in data { - self.push_number(8, u16::from(*b)); - } - Ok(()) - } -} - -#[cfg(test)] -mod byte_tests { - use crate::bits::Bits; - use crate::types::{QrError, Version}; - - #[test] - fn test() { - let mut bits = Bits::new(Version::Normal(1)); - assert_eq!(bits.push_byte_data(b"\x12\x34\x56\x78\x9a\xbc\xde\xf0"), Ok(())); - assert_eq!( - bits.into_bytes(), - vec![ - 0b0100_0000, - 0b1000_0001, - 0b0010_0011, - 0b0100_0101, - 0b0110_0111, - 0b1000_1001, - 0b1010_1011, - 0b1100_1101, - 0b1110_1111, - 0b0000_0000, - ] - ); - } - - #[test] - fn test_micro_qr_unsupported() { - let mut bits = Bits::new(Version::Micro(2)); - assert_eq!(bits.push_byte_data(b"?"), Err(QrError::UnsupportedCharacterSet)); - } - - #[test] - fn test_data_too_long() { - let mut bits = Bits::new(Version::Micro(3)); - assert_eq!(bits.push_byte_data(b"0123456701234567"), Err(QrError::DataTooLong)); - } -} - -//}}} -//------------------------------------------------------------------------------ -//{{{ Mode::Kanji mode - -impl Bits { - /// Encodes Shift JIS double-byte data to the bits. - /// - /// # Errors - /// - /// Returns `Err(QrError::DataTooLong)` on overflow. - /// - /// Returns `Err(QrError::InvalidCharacter)` if the data is not Shift JIS - /// double-byte data (e.g. if the length of data is not an even number). - pub fn push_kanji_data(&mut self, data: &[u8]) -> QrResult<()> { - self.push_header(Mode::Kanji, data.len() / 2)?; - for kanji in data.chunks(2) { - if kanji.len() != 2 { - return Err(QrError::InvalidCharacter); - } - let cp = u16::from(kanji[0]) * 256 + u16::from(kanji[1]); - let bytes = if cp < 0xe040 { cp - 0x8140 } else { cp - 0xc140 }; - let number = (bytes >> 8) * 0xc0 + (bytes & 0xff); - self.push_number(13, number); - } - Ok(()) - } -} - -#[cfg(test)] -mod kanji_tests { - use crate::bits::Bits; - use crate::types::{QrError, Version}; - - #[test] - fn test_iso_18004_example() { - let mut bits = Bits::new(Version::Normal(1)); - assert_eq!(bits.push_kanji_data(b"\x93\x5f\xe4\xaa"), Ok(())); - assert_eq!(bits.into_bytes(), vec![0b1000_0000, 0b0010_0110, 0b11001111, 0b1110_1010, 0b1010_1000]); - } - - #[test] - fn test_micro_qr_unsupported() { - let mut bits = Bits::new(Version::Micro(2)); - assert_eq!(bits.push_kanji_data(b"?"), Err(QrError::UnsupportedCharacterSet)); - } - - #[test] - fn test_data_too_long() { - let mut bits = Bits::new(Version::Micro(3)); - assert_eq!(bits.push_kanji_data(b"\x93_\x93_\x93_\x93_\x93_\x93_\x93_\x93_"), Err(QrError::DataTooLong)); - } -} - -//}}} -//------------------------------------------------------------------------------ -//{{{ FNC1 mode - -impl Bits { - /// Encodes an indicator that the following data are formatted according to - /// the UCC/EAN Application Identifiers standard. - /// - /// #![allow(unused_must_use)] - /// - /// use qrcode::bits::Bits; - /// use qrcode::types::Version; - /// - /// let mut bits = Bits::new(Version::Normal(1)); - /// bits.push_fnc1_first_position(); - /// bits.push_numeric_data(b"01049123451234591597033130128"); - /// bits.push_alphanumeric_data(b"%10ABC123"); - /// - /// In QR code, the character `%` is used as the data field separator (0x1D). - /// - /// # Errors - /// - /// If the mode is not supported in the provided version, this method - /// returns `Err(QrError::UnsupportedCharacterSet)`. - pub fn push_fnc1_first_position(&mut self) -> QrResult<()> { - self.push_mode_indicator(ExtendedMode::Fnc1First) - } - - /// Encodes an indicator that the following data are formatted in accordance - /// with specific industry or application specifications previously agreed - /// with AIM International. - /// - /// #![allow(unused_must_use)] - /// - /// use qrcode::bits::Bits; - /// use qrcode::types::Version; - /// - /// let mut bits = Bits::new(Version::Normal(1)); - /// bits.push_fnc1_second_position(37); - /// bits.push_alphanumeric_data(b"AA1234BBB112"); - /// bits.push_byte_data(b"text text text text\r"); - /// - /// If the application indicator is a single Latin alphabet (a–z / A–Z), - /// please pass in its ASCII value + 100: - /// - /// ```ignore - /// bits.push_fnc1_second_position(b'A' + 100); - /// ``` - /// - /// # Errors - /// - /// If the mode is not supported in the provided version, this method - /// returns `Err(QrError::UnsupportedCharacterSet)`. - pub fn push_fnc1_second_position(&mut self, application_indicator: u8) -> QrResult<()> { - self.push_mode_indicator(ExtendedMode::Fnc1Second)?; - self.push_number(8, u16::from(application_indicator)); - Ok(()) - } -} - -//}}} -//------------------------------------------------------------------------------ -//{{{ Finish - -// This table is copied from ISO/IEC 18004:2006 §6.4.10, Table 7. -static DATA_LENGTHS: [[usize; 4]; 44] = [ - // Normal versions - [152, 128, 104, 72], - [272, 224, 176, 128], - [440, 352, 272, 208], - [640, 512, 384, 288], - [864, 688, 496, 368], - [1088, 864, 608, 480], - [1248, 992, 704, 528], - [1552, 1232, 880, 688], - [1856, 1456, 1056, 800], - [2192, 1728, 1232, 976], - [2592, 2032, 1440, 1120], - [2960, 2320, 1648, 1264], - [3424, 2672, 1952, 1440], - [3688, 2920, 2088, 1576], - [4184, 3320, 2360, 1784], - [4712, 3624, 2600, 2024], - [5176, 4056, 2936, 2264], - [5768, 4504, 3176, 2504], - [6360, 5016, 3560, 2728], - [6888, 5352, 3880, 3080], - [7456, 5712, 4096, 3248], - [8048, 6256, 4544, 3536], - [8752, 6880, 4912, 3712], - [9392, 7312, 5312, 4112], - [10208, 8000, 5744, 4304], - [10960, 8496, 6032, 4768], - [11744, 9024, 6464, 5024], - [12248, 9544, 6968, 5288], - [13048, 10136, 7288, 5608], - [13880, 10984, 7880, 5960], - [14744, 11640, 8264, 6344], - [15640, 12328, 8920, 6760], - [16568, 13048, 9368, 7208], - [17528, 13800, 9848, 7688], - [18448, 14496, 10288, 7888], - [19472, 15312, 10832, 8432], - [20528, 15936, 11408, 8768], - [21616, 16816, 12016, 9136], - [22496, 17728, 12656, 9776], - [23648, 18672, 13328, 10208], - // Micro versions - [20, 0, 0, 0], - [40, 32, 0, 0], - [84, 68, 0, 0], - [128, 112, 80, 0], -]; - -impl Bits { - /// Pushes the ending bits to indicate no more data. - /// - /// # Errors - /// - /// Returns `Err(QrError::DataTooLong)` on overflow. - /// - /// Returns `Err(QrError::InvalidVersion)` if it is not valid to use the - /// `ec_level` for the given version (e.g. `Version::Micro(1)` with - /// `EcLevel::H`). - pub fn push_terminator(&mut self, ec_level: EcLevel) -> QrResult<()> { - let terminator_size = match self.version { - Version::Micro(a) => a.as_usize() * 2 + 1, - _ => 4, - }; - - let cur_length = self.len(); - let data_length = self.max_len(ec_level)?; - if cur_length > data_length { - return Err(QrError::DataTooLong); - } - - let terminator_size = min(terminator_size, data_length - cur_length); - if terminator_size > 0 { - self.push_number(terminator_size, 0); - } - - if self.len() < data_length { - const PADDING_BYTES: &[u8] = &[0b1110_1100, 0b0001_0001]; - - self.bit_offset = 0; - let data_bytes_length = data_length / 8; - let padding_bytes_count = data_bytes_length - self.data.len(); - let padding = PADDING_BYTES.iter().cloned().cycle().take(padding_bytes_count); - self.data.extend(padding); - } - - if self.len() < data_length { - self.data.push(0); - } - - Ok(()) - } -} - -#[cfg(test)] -mod finish_tests { - use crate::bits::Bits; - use crate::types::{EcLevel, QrError, Version}; - - #[test] - fn test_hello_world() { - let mut bits = Bits::new(Version::Normal(1)); - assert_eq!(bits.push_alphanumeric_data(b"HELLO WORLD"), Ok(())); - assert_eq!(bits.push_terminator(EcLevel::Q), Ok(())); - assert_eq!( - bits.into_bytes(), - vec![ - 0b00100000, 0b01011011, 0b00001011, 0b01111000, 0b11010001, 0b01110010, 0b11011100, 0b01001101, - 0b01000011, 0b01000000, 0b11101100, 0b00010001, 0b11101100, - ] - ); - } - - #[test] - fn test_too_long() { - let mut bits = Bits::new(Version::Micro(1)); - assert_eq!(bits.push_numeric_data(b"9999999"), Ok(())); - assert_eq!(bits.push_terminator(EcLevel::L), Err(QrError::DataTooLong)); - } - - #[test] - fn test_no_terminator() { - let mut bits = Bits::new(Version::Micro(1)); - assert_eq!(bits.push_numeric_data(b"99999"), Ok(())); - assert_eq!(bits.push_terminator(EcLevel::L), Ok(())); - assert_eq!(bits.into_bytes(), vec![0b1011_1111, 0b0011_1110, 0b0011_0000]); - } - - #[test] - fn test_no_padding() { - let mut bits = Bits::new(Version::Micro(1)); - assert_eq!(bits.push_numeric_data(b"9999"), Ok(())); - assert_eq!(bits.push_terminator(EcLevel::L), Ok(())); - assert_eq!(bits.into_bytes(), vec![0b1001_1111, 0b0011_1100, 0b1000_0000]); - } - - #[test] - fn test_micro_version_1_half_byte_padding() { - let mut bits = Bits::new(Version::Micro(1)); - assert_eq!(bits.push_numeric_data(b"999"), Ok(())); - assert_eq!(bits.push_terminator(EcLevel::L), Ok(())); - assert_eq!(bits.into_bytes(), vec![0b0111_1111, 0b0011_1000, 0b0000_0000]); - } - - #[test] - fn test_micro_version_1_full_byte_padding() { - let mut bits = Bits::new(Version::Micro(1)); - assert_eq!(bits.push_numeric_data(b""), Ok(())); - assert_eq!(bits.push_terminator(EcLevel::L), Ok(())); - assert_eq!(bits.into_bytes(), vec![0b0000_0000, 0b11101100, 0]); - } -} - -//}}} -//------------------------------------------------------------------------------ -//{{{ Front end. - -impl Bits { - /// Push a segmented data to the bits, and then terminate it. - /// - /// # Errors - /// - /// Returns `Err(QrError::DataTooLong)` on overflow. - /// - /// Returns `Err(QrError::InvalidData)` if the segment refers to incorrectly - /// encoded byte sequence. - pub fn push_segments(&mut self, data: &[u8], segments_iter: I) -> QrResult<()> - where - I: Iterator, - { - for segment in segments_iter { - let slice = &data[segment.begin..segment.end]; - match segment.mode { - Mode::Numeric => self.push_numeric_data(slice), - Mode::Alphanumeric => self.push_alphanumeric_data(slice), - Mode::Byte => self.push_byte_data(slice), - Mode::Kanji => self.push_kanji_data(slice), - }?; - } - Ok(()) - } - - /// Pushes the data the bits, using the optimal encoding. - /// - /// # Errors - /// - /// Returns `Err(QrError::DataTooLong)` on overflow. - pub fn push_optimal_data(&mut self, data: &[u8]) -> QrResult<()> { - let segments = Parser::new(data).optimize(self.version); - self.push_segments(data, segments) - } -} - -#[cfg(test)] -mod encode_tests { - use alloc::vec::Vec; - - use crate::bits::Bits; - use crate::types::{EcLevel, QrError, QrResult, Version}; - - fn encode(data: &[u8], version: Version, ec_level: EcLevel) -> QrResult> { - let mut bits = Bits::new(version); - bits.push_optimal_data(data)?; - bits.push_terminator(ec_level)?; - Ok(bits.into_bytes()) - } - - #[test] - fn test_alphanumeric() { - let res = encode(b"HELLO WORLD", Version::Normal(1), EcLevel::Q); - assert_eq!( - res, - Ok(vec![ - 0b00100000, 0b01011011, 0b00001011, 0b01111000, 0b11010001, 0b01110010, 0b11011100, 0b01001101, - 0b01000011, 0b01000000, 0b11101100, 0b00010001, 0b11101100, - ]) - ); - } - - #[test] - fn test_auto_mode_switch() { - let res = encode(b"123A", Version::Micro(2), EcLevel::L); - assert_eq!(res, Ok(vec![0b0001_1000, 0b1111_0111, 0b0010_0101, 0b0000_0000, 0b11101100])); - } - - #[test] - fn test_too_long() { - let res = encode(b">>>>>>>>", Version::Normal(1), EcLevel::H); - assert_eq!(res, Err(QrError::DataTooLong)); - } -} - -//}}} -//------------------------------------------------------------------------------ -//{{{ Auto version minimization - -/// Automatically determines the minimum version to store the data, and encode -/// the result. -/// -/// This method will not consider any Micro QR code versions. -/// -/// # Errors -/// -/// Returns `Err(QrError::DataTooLong)` if the data is too long to fit even the -/// highest QR code version. -pub fn encode_auto(data: &[u8], ec_level: EcLevel) -> QrResult { - let segments = Parser::new(data).collect::>(); - for version in &[Version::Normal(9), Version::Normal(26), Version::Normal(40)] { - let opt_segments = Optimizer::new(segments.iter().cloned(), *version).collect::>(); - let total_len = total_encoded_len(&opt_segments, *version); - let data_capacity = version.fetch(ec_level, &DATA_LENGTHS).expect("invalid DATA_LENGTHS"); - if total_len <= data_capacity { - let min_version = find_min_version(total_len, ec_level); - let mut bits = Bits::new(min_version); - bits.reserve(total_len); - bits.push_segments(data, opt_segments.into_iter())?; - bits.push_terminator(ec_level)?; - return Ok(bits); - } - } - Err(QrError::DataTooLong) -} - -/// Finds the smallest version (QR code only) that can store N bits of data -/// in the given error correction level. -fn find_min_version(length: usize, ec_level: EcLevel) -> Version { - let mut base = 0_usize; - let mut size = 39; - while size > 1 { - let half = size / 2; - let mid = base + half; - // mid is always in [0, size). - // mid >= 0: by definition - // mid < size: mid = size / 2 + size / 4 + size / 8 ... - base = if DATA_LENGTHS[mid][ec_level as usize] > length { base } else { mid }; - size -= half; - } - // base is always in [0, mid) because base <= mid. - base = if DATA_LENGTHS[base][ec_level as usize] >= length { base } else { base + 1 }; - Version::Normal((base + 1).as_i16()) -} - -#[cfg(test)] -mod encode_auto_tests { - use crate::bits::{encode_auto, find_min_version}; - use crate::types::{EcLevel, Version}; - - #[test] - fn test_find_min_version() { - assert_eq!(find_min_version(60, EcLevel::L), Version::Normal(1)); - assert_eq!(find_min_version(200, EcLevel::L), Version::Normal(2)); - assert_eq!(find_min_version(200, EcLevel::H), Version::Normal(3)); - assert_eq!(find_min_version(20000, EcLevel::L), Version::Normal(37)); - assert_eq!(find_min_version(640, EcLevel::L), Version::Normal(4)); - assert_eq!(find_min_version(641, EcLevel::L), Version::Normal(5)); - assert_eq!(find_min_version(999999, EcLevel::H), Version::Normal(40)); - } - - #[test] - fn test_alpha_q() { - let bits = encode_auto(b"HELLO WORLD", EcLevel::Q).unwrap(); - assert_eq!(bits.version(), Version::Normal(1)); - } - - #[test] - fn test_alpha_h() { - let bits = encode_auto(b"HELLO WORLD", EcLevel::H).unwrap(); - assert_eq!(bits.version(), Version::Normal(2)); - } - - #[test] - fn test_mixed() { - let bits = encode_auto(b"This is a mixed data test. 1234567890", EcLevel::H).unwrap(); - assert_eq!(bits.version(), Version::Normal(4)); - } -} - -#[cfg(feature = "bench")] -#[bench] -fn bench_find_min_version(bencher: &mut test::Bencher) { - use test::black_box; - - bencher.iter(|| { - black_box(find_min_version(60, EcLevel::L)); - black_box(find_min_version(200, EcLevel::L)); - black_box(find_min_version(200, EcLevel::H)); - black_box(find_min_version(20000, EcLevel::L)); - black_box(find_min_version(640, EcLevel::L)); - black_box(find_min_version(641, EcLevel::L)); - black_box(find_min_version(999999, EcLevel::H)); - }) -} - -//}}} -//------------------------------------------------------------------------------ diff --git a/qrcode-rust/src/canvas.rs b/qrcode-rust/src/canvas.rs deleted file mode 100644 index 0e974cec..00000000 --- a/qrcode-rust/src/canvas.rs +++ /dev/null @@ -1,2010 +0,0 @@ -//! The `canvas` module puts raw bits into the QR code canvas. -//! -//! use qrcode::types::{Version, EcLevel}; -//! use qrcode::canvas::{Canvas, MaskPattern}; -//! -//! let mut c = Canvas::new(Version::Normal(1), EcLevel::L); -//! c.draw_all_functional_patterns(); -//! c.draw_data(b"data_here", b"ec_code_here"); -//! c.apply_mask(MaskPattern::Checkerboard); -//! let bools = c.to_bools(); - -use core::cmp::max; - -use alloc::boxed::Box; -use alloc::vec::Vec; - -use crate::cast::As; -use crate::types::{Color, EcLevel, Version}; - -//------------------------------------------------------------------------------ -//{{{ Modules - -/// The color of a module (pixel) in the QR code. -#[derive(PartialEq, Eq, Clone, Copy, Debug)] -pub enum Module { - /// The module is empty. - Empty, - - /// The module is of functional patterns which cannot be masked, or pixels - /// which have been masked. - Masked(Color), - - /// The module is of data and error correction bits before masking. - Unmasked(Color), -} - -impl From for Color { - fn from(module: Module) -> Self { - match module { - Module::Empty => Color::Light, - Module::Masked(c) | Module::Unmasked(c) => c, - } - } -} - -impl Module { - /// Checks whether a module is dark. - pub fn is_dark(self) -> bool { - Color::from(self) == Color::Dark - } - - /// Apply a mask to the unmasked modules. - /// - /// use qrcode::canvas::Module; - /// use qrcode::types::Color; - /// - /// assert_eq!(Module::Unmasked(Color::Light).mask(true), Module::Masked(Color::Dark)); - /// assert_eq!(Module::Unmasked(Color::Dark).mask(true), Module::Masked(Color::Light)); - /// assert_eq!(Module::Unmasked(Color::Light).mask(false), Module::Masked(Color::Light)); - /// assert_eq!(Module::Masked(Color::Dark).mask(true), Module::Masked(Color::Dark)); - /// assert_eq!(Module::Masked(Color::Dark).mask(false), Module::Masked(Color::Dark)); - /// - pub fn mask(self, should_invert: bool) -> Self { - match (self, should_invert) { - (Module::Empty, true) => Module::Masked(Color::Dark), - (Module::Empty, false) => Module::Masked(Color::Light), - (Module::Unmasked(c), true) => Module::Masked(!c), - (Module::Unmasked(c), false) | (Module::Masked(c), _) => Module::Masked(c), - } - } -} - -//}}} -//------------------------------------------------------------------------------ -//{{{ Canvas - -/// `Canvas` is an intermediate helper structure to render error-corrected data -/// into a QR code. -#[derive(Clone)] -pub struct Canvas { - /// The width and height of the canvas (cached as it is needed frequently). - width: i16, - - /// The version of the QR code. - version: Version, - - /// The error correction level of the QR code. - ec_level: EcLevel, - - /// The modules of the QR code. Modules are arranged in left-to-right, then - /// top-to-bottom order. - modules: Vec, -} - -#[cfg(test)] -use alloc::string::String; - -impl Canvas { - /// Constructs a new canvas big enough for a QR code of the given version. - pub fn new(version: Version, ec_level: EcLevel) -> Self { - let width = version.width(); - Self { width, version, ec_level, modules: vec![Module::Empty; (width * width).as_usize()] } - } - - /// Converts the canvas into a human-readable string. - #[cfg(test)] - - fn to_debug_str(&self) -> String { - let width = self.width; - let mut res = String::with_capacity((width * (width + 1)) as usize); - for y in 0..width { - res.push('\n'); - for x in 0..width { - res.push(match self.get(x, y) { - Module::Empty => '?', - Module::Masked(Color::Light) => '.', - Module::Masked(Color::Dark) => '#', - Module::Unmasked(Color::Light) => '-', - Module::Unmasked(Color::Dark) => '*', - }); - } - } - res - } - - fn coords_to_index(&self, x: i16, y: i16) -> usize { - let x = if x < 0 { x + self.width } else { x }.as_usize(); - let y = if y < 0 { y + self.width } else { y }.as_usize(); - y * self.width.as_usize() + x - } - - /// Obtains a module at the given coordinates. For convenience, negative - /// coordinates will wrap around. - pub fn get(&self, x: i16, y: i16) -> Module { - self.modules[self.coords_to_index(x, y)] - } - - /// Obtains a mutable module at the given coordinates. For convenience, - /// negative coordinates will wrap around. - pub fn get_mut(&mut self, x: i16, y: i16) -> &mut Module { - let index = self.coords_to_index(x, y); - &mut self.modules[index] - } - - /// Sets the color of a functional module at the given coordinates. For - /// convenience, negative coordinates will wrap around. - pub fn put(&mut self, x: i16, y: i16, color: Color) { - *self.get_mut(x, y) = Module::Masked(color); - } -} - -#[cfg(test)] -mod basic_canvas_tests { - use crate::canvas::{Canvas, Module}; - use crate::types::{Color, EcLevel, Version}; - - #[test] - fn test_index() { - let mut c = Canvas::new(Version::Normal(1), EcLevel::L); - - assert_eq!(c.get(0, 4), Module::Empty); - assert_eq!(c.get(-1, -7), Module::Empty); - assert_eq!(c.get(21 - 1, 21 - 7), Module::Empty); - - c.put(0, 0, Color::Dark); - c.put(-1, -7, Color::Light); - assert_eq!(c.get(0, 0), Module::Masked(Color::Dark)); - assert_eq!(c.get(21 - 1, -7), Module::Masked(Color::Light)); - assert_eq!(c.get(-1, 21 - 7), Module::Masked(Color::Light)); - } - - #[test] - fn test_debug_str() { - let mut c = Canvas::new(Version::Normal(1), EcLevel::L); - - for i in 3_i16..20 { - for j in 3_i16..20 { - *c.get_mut(i, j) = match ((i * 3) ^ j) % 5 { - 0 => Module::Empty, - 1 => Module::Masked(Color::Light), - 2 => Module::Masked(Color::Dark), - 3 => Module::Unmasked(Color::Light), - 4 => Module::Unmasked(Color::Dark), - _ => unreachable!(), - }; - } - } - - assert_eq!( - &*c.to_debug_str(), - "\n\ - ?????????????????????\n\ - ?????????????????????\n\ - ?????????????????????\n\ - ?????####****....---?\n\ - ???--.##-..##?..#??.?\n\ - ???#*?-.*?#.-*#?-*.??\n\ - ?????*?*?****-*-*---?\n\ - ???*.-.-.-?-?#?#?#*#?\n\ - ???.*#.*.*#.*#*#.*#*?\n\ - ?????.#-#--??.?.#---?\n\ - ???-.?*.-#?-.?#*-#?.?\n\ - ???##*??*..##*--*..??\n\ - ?????-???--??---?---?\n\ - ???*.#.*.#**.#*#.#*#?\n\ - ???##.-##..##..?#..??\n\ - ???.-?*.-?#.-?#*-?#*?\n\ - ????-.#?-.**#?-.#?-.?\n\ - ???**?-**??--**?-**??\n\ - ???#?*?#?*#.*-.-*-.-?\n\ - ???..-...--??###?###?\n\ - ?????????????????????" - ); - } -} - -//}}} -//------------------------------------------------------------------------------ -//{{{ Finder patterns - -impl Canvas { - /// Draws a single finder pattern with the center at (x, y). - fn draw_finder_pattern_at(&mut self, x: i16, y: i16) { - let (dx_left, dx_right) = if x >= 0 { (-3, 4) } else { (-4, 3) }; - let (dy_top, dy_bottom) = if y >= 0 { (-3, 4) } else { (-4, 3) }; - for j in dy_top..=dy_bottom { - for i in dx_left..=dx_right { - self.put( - x + i, - y + j, - #[allow(clippy::match_same_arms)] - match (i, j) { - (4, _) | (_, 4) | (-4, _) | (_, -4) => Color::Light, - (3, _) | (_, 3) | (-3, _) | (_, -3) => Color::Dark, - (2, _) | (_, 2) | (-2, _) | (_, -2) => Color::Light, - _ => Color::Dark, - }, - ); - } - } - } - - /// Draws the finder patterns. - /// - /// The finder patterns is are 7×7 square patterns appearing at the three - /// corners of a QR code. They allows scanner to locate the QR code and - /// determine the orientation. - fn draw_finder_patterns(&mut self) { - self.draw_finder_pattern_at(3, 3); - - match self.version { - Version::Micro(_) => {} - Version::Normal(_) => { - self.draw_finder_pattern_at(-4, 3); - self.draw_finder_pattern_at(3, -4); - } - } - } -} - -#[cfg(test)] -mod finder_pattern_tests { - use crate::canvas::Canvas; - use crate::types::{EcLevel, Version}; - - #[test] - fn test_qr() { - let mut c = Canvas::new(Version::Normal(1), EcLevel::L); - c.draw_finder_patterns(); - assert_eq!( - &*c.to_debug_str(), - "\n\ - #######.?????.#######\n\ - #.....#.?????.#.....#\n\ - #.###.#.?????.#.###.#\n\ - #.###.#.?????.#.###.#\n\ - #.###.#.?????.#.###.#\n\ - #.....#.?????.#.....#\n\ - #######.?????.#######\n\ - ........?????........\n\ - ?????????????????????\n\ - ?????????????????????\n\ - ?????????????????????\n\ - ?????????????????????\n\ - ?????????????????????\n\ - ........?????????????\n\ - #######.?????????????\n\ - #.....#.?????????????\n\ - #.###.#.?????????????\n\ - #.###.#.?????????????\n\ - #.###.#.?????????????\n\ - #.....#.?????????????\n\ - #######.?????????????" - ); - } - - #[test] - fn test_micro_qr() { - let mut c = Canvas::new(Version::Micro(1), EcLevel::L); - c.draw_finder_patterns(); - assert_eq!( - &*c.to_debug_str(), - "\n\ - #######.???\n\ - #.....#.???\n\ - #.###.#.???\n\ - #.###.#.???\n\ - #.###.#.???\n\ - #.....#.???\n\ - #######.???\n\ - ........???\n\ - ???????????\n\ - ???????????\n\ - ???????????" - ); - } -} - -//}}} -//------------------------------------------------------------------------------ -//{{{ Alignment patterns - -impl Canvas { - /// Draws a alignment pattern with the center at (x, y). - fn draw_alignment_pattern_at(&mut self, x: i16, y: i16) { - if self.get(x, y) != Module::Empty { - return; - } - for j in -2..=2 { - for i in -2..=2 { - self.put( - x + i, - y + j, - match (i, j) { - (2, _) | (_, 2) | (-2, _) | (_, -2) | (0, 0) => Color::Dark, - _ => Color::Light, - }, - ); - } - } - } - - /// Draws the alignment patterns. - /// - /// The alignment patterns are 5×5 square patterns inside the QR code symbol - /// to help the scanner create the square grid. - fn draw_alignment_patterns(&mut self) { - match self.version { - Version::Micro(_) | Version::Normal(1) => {} - Version::Normal(2..=6) => self.draw_alignment_pattern_at(-7, -7), - Version::Normal(a) => { - let positions = ALIGNMENT_PATTERN_POSITIONS[(a - 7).as_usize()]; - for x in positions.iter() { - for y in positions.iter() { - self.draw_alignment_pattern_at(*x, *y); - } - } - } - } - } -} - -#[cfg(test)] -mod alignment_pattern_tests { - use crate::canvas::Canvas; - use crate::types::{EcLevel, Version}; - - #[test] - fn test_draw_alignment_patterns_1() { - let mut c = Canvas::new(Version::Normal(1), EcLevel::L); - c.draw_finder_patterns(); - c.draw_alignment_patterns(); - assert_eq!( - &*c.to_debug_str(), - "\n\ - #######.?????.#######\n\ - #.....#.?????.#.....#\n\ - #.###.#.?????.#.###.#\n\ - #.###.#.?????.#.###.#\n\ - #.###.#.?????.#.###.#\n\ - #.....#.?????.#.....#\n\ - #######.?????.#######\n\ - ........?????........\n\ - ?????????????????????\n\ - ?????????????????????\n\ - ?????????????????????\n\ - ?????????????????????\n\ - ?????????????????????\n\ - ........?????????????\n\ - #######.?????????????\n\ - #.....#.?????????????\n\ - #.###.#.?????????????\n\ - #.###.#.?????????????\n\ - #.###.#.?????????????\n\ - #.....#.?????????????\n\ - #######.?????????????" - ); - } - - #[test] - fn test_draw_alignment_patterns_3() { - let mut c = Canvas::new(Version::Normal(3), EcLevel::L); - c.draw_finder_patterns(); - c.draw_alignment_patterns(); - assert_eq!( - &*c.to_debug_str(), - "\n\ - #######.?????????????.#######\n\ - #.....#.?????????????.#.....#\n\ - #.###.#.?????????????.#.###.#\n\ - #.###.#.?????????????.#.###.#\n\ - #.###.#.?????????????.#.###.#\n\ - #.....#.?????????????.#.....#\n\ - #######.?????????????.#######\n\ - ........?????????????........\n\ - ?????????????????????????????\n\ - ?????????????????????????????\n\ - ?????????????????????????????\n\ - ?????????????????????????????\n\ - ?????????????????????????????\n\ - ?????????????????????????????\n\ - ?????????????????????????????\n\ - ?????????????????????????????\n\ - ?????????????????????????????\n\ - ?????????????????????????????\n\ - ?????????????????????????????\n\ - ?????????????????????????????\n\ - ????????????????????#####????\n\ - ........????????????#...#????\n\ - #######.????????????#.#.#????\n\ - #.....#.????????????#...#????\n\ - #.###.#.????????????#####????\n\ - #.###.#.?????????????????????\n\ - #.###.#.?????????????????????\n\ - #.....#.?????????????????????\n\ - #######.?????????????????????" - ); - } - - #[test] - fn test_draw_alignment_patterns_7() { - let mut c = Canvas::new(Version::Normal(7), EcLevel::L); - c.draw_finder_patterns(); - c.draw_alignment_patterns(); - assert_eq!( - &*c.to_debug_str(), - "\n\ - #######.?????????????????????????????.#######\n\ - #.....#.?????????????????????????????.#.....#\n\ - #.###.#.?????????????????????????????.#.###.#\n\ - #.###.#.?????????????????????????????.#.###.#\n\ - #.###.#.????????????#####????????????.#.###.#\n\ - #.....#.????????????#...#????????????.#.....#\n\ - #######.????????????#.#.#????????????.#######\n\ - ........????????????#...#????????????........\n\ - ????????????????????#####????????????????????\n\ - ?????????????????????????????????????????????\n\ - ?????????????????????????????????????????????\n\ - ?????????????????????????????????????????????\n\ - ?????????????????????????????????????????????\n\ - ?????????????????????????????????????????????\n\ - ?????????????????????????????????????????????\n\ - ?????????????????????????????????????????????\n\ - ?????????????????????????????????????????????\n\ - ?????????????????????????????????????????????\n\ - ?????????????????????????????????????????????\n\ - ?????????????????????????????????????????????\n\ - ????#####???????????#####???????????#####????\n\ - ????#...#???????????#...#???????????#...#????\n\ - ????#.#.#???????????#.#.#???????????#.#.#????\n\ - ????#...#???????????#...#???????????#...#????\n\ - ????#####???????????#####???????????#####????\n\ - ?????????????????????????????????????????????\n\ - ?????????????????????????????????????????????\n\ - ?????????????????????????????????????????????\n\ - ?????????????????????????????????????????????\n\ - ?????????????????????????????????????????????\n\ - ?????????????????????????????????????????????\n\ - ?????????????????????????????????????????????\n\ - ?????????????????????????????????????????????\n\ - ?????????????????????????????????????????????\n\ - ?????????????????????????????????????????????\n\ - ?????????????????????????????????????????????\n\ - ????????????????????#####???????????#####????\n\ - ........????????????#...#???????????#...#????\n\ - #######.????????????#.#.#???????????#.#.#????\n\ - #.....#.????????????#...#???????????#...#????\n\ - #.###.#.????????????#####???????????#####????\n\ - #.###.#.?????????????????????????????????????\n\ - #.###.#.?????????????????????????????????????\n\ - #.....#.?????????????????????????????????????\n\ - #######.?????????????????????????????????????" - ); - } -} - -/// `ALIGNMENT_PATTERN_POSITIONS` describes the x- and y-coordinates of the -/// center of the alignment patterns. Since the QR code is symmetric, only one -/// coordinate is needed. -static ALIGNMENT_PATTERN_POSITIONS: [&[i16]; 34] = [ - &[6, 22, 38], - &[6, 24, 42], - &[6, 26, 46], - &[6, 28, 50], - &[6, 30, 54], - &[6, 32, 58], - &[6, 34, 62], - &[6, 26, 46, 66], - &[6, 26, 48, 70], - &[6, 26, 50, 74], - &[6, 30, 54, 78], - &[6, 30, 56, 82], - &[6, 30, 58, 86], - &[6, 34, 62, 90], - &[6, 28, 50, 72, 94], - &[6, 26, 50, 74, 98], - &[6, 30, 54, 78, 102], - &[6, 28, 54, 80, 106], - &[6, 32, 58, 84, 110], - &[6, 30, 58, 86, 114], - &[6, 34, 62, 90, 118], - &[6, 26, 50, 74, 98, 122], - &[6, 30, 54, 78, 102, 126], - &[6, 26, 52, 78, 104, 130], - &[6, 30, 56, 82, 108, 134], - &[6, 34, 60, 86, 112, 138], - &[6, 30, 58, 86, 114, 142], - &[6, 34, 62, 90, 118, 146], - &[6, 30, 54, 78, 102, 126, 150], - &[6, 24, 50, 76, 102, 128, 154], - &[6, 28, 54, 80, 106, 132, 158], - &[6, 32, 58, 84, 110, 136, 162], - &[6, 26, 54, 82, 110, 138, 166], - &[6, 30, 58, 86, 114, 142, 170], -]; - -//}}} -//------------------------------------------------------------------------------ -//{{{ Timing patterns - -impl Canvas { - /// Draws a line from (x1, y1) to (x2, y2), inclusively. - /// - /// The line must be either horizontal or vertical, i.e. - /// `x1 == x2 || y1 == y2`. Additionally, the first coordinates must be less - /// then the second ones. - /// - /// On even coordinates, `color_even` will be plotted; on odd coordinates, - /// `color_odd` will be plotted instead. Thus the timing pattern can be - /// drawn using this method. - /// - fn draw_line(&mut self, x1: i16, y1: i16, x2: i16, y2: i16, color_even: Color, color_odd: Color) { - debug_assert!(x1 == x2 || y1 == y2); - - if y1 == y2 { - // Horizontal line. - for x in x1..=x2 { - self.put(x, y1, if x % 2 == 0 { color_even } else { color_odd }); - } - } else { - // Vertical line. - for y in y1..=y2 { - self.put(x1, y, if y % 2 == 0 { color_even } else { color_odd }); - } - } - } - - /// Draws the timing patterns. - /// - /// The timing patterns are checkboard-colored lines near the edge of the QR - /// code symbol, to establish the fine-grained module coordinates when - /// scanning. - fn draw_timing_patterns(&mut self) { - let width = self.width; - let (y, x1, x2) = match self.version { - Version::Micro(_) => (0, 8, width - 1), - Version::Normal(_) => (6, 8, width - 9), - }; - self.draw_line(x1, y, x2, y, Color::Dark, Color::Light); - self.draw_line(y, x1, y, x2, Color::Dark, Color::Light); - } -} - -#[cfg(test)] -mod timing_pattern_tests { - use crate::canvas::Canvas; - use crate::types::{EcLevel, Version}; - - #[test] - fn test_draw_timing_patterns_qr() { - let mut c = Canvas::new(Version::Normal(1), EcLevel::L); - c.draw_timing_patterns(); - assert_eq!( - &*c.to_debug_str(), - "\n\ - ?????????????????????\n\ - ?????????????????????\n\ - ?????????????????????\n\ - ?????????????????????\n\ - ?????????????????????\n\ - ?????????????????????\n\ - ????????#.#.#????????\n\ - ?????????????????????\n\ - ??????#??????????????\n\ - ??????.??????????????\n\ - ??????#??????????????\n\ - ??????.??????????????\n\ - ??????#??????????????\n\ - ?????????????????????\n\ - ?????????????????????\n\ - ?????????????????????\n\ - ?????????????????????\n\ - ?????????????????????\n\ - ?????????????????????\n\ - ?????????????????????\n\ - ?????????????????????" - ); - } - - #[test] - fn test_draw_timing_patterns_micro_qr() { - let mut c = Canvas::new(Version::Micro(1), EcLevel::L); - c.draw_timing_patterns(); - assert_eq!( - &*c.to_debug_str(), - "\n\ - ????????#.#\n\ - ???????????\n\ - ???????????\n\ - ???????????\n\ - ???????????\n\ - ???????????\n\ - ???????????\n\ - ???????????\n\ - #??????????\n\ - .??????????\n\ - #??????????" - ); - } -} - -//}}} -//------------------------------------------------------------------------------ -//{{{ Format info & Version info - -impl Canvas { - /// Draws a big-endian integer onto the canvas with the given coordinates. - /// - /// The 1 bits will be plotted with `on_color` and the 0 bits with - /// `off_color`. The coordinates will be extracted from the `coords` - /// iterator. It will start from the most significant bits first, so - /// *trailing* zeros will be ignored. - fn draw_number(&mut self, number: u32, bits: u32, on_color: Color, off_color: Color, coords: &[(i16, i16)]) { - let mut mask = 1 << (bits - 1); - for &(x, y) in coords { - let color = if (mask & number) == 0 { off_color } else { on_color }; - self.put(x, y, color); - mask >>= 1; - } - } - - /// Draws the format info patterns for an encoded number. - fn draw_format_info_patterns_with_number(&mut self, format_info: u16) { - let format_info = u32::from(format_info); - match self.version { - Version::Micro(_) => { - self.draw_number(format_info, 15, Color::Dark, Color::Light, &FORMAT_INFO_COORDS_MICRO_QR); - } - Version::Normal(_) => { - self.draw_number(format_info, 15, Color::Dark, Color::Light, &FORMAT_INFO_COORDS_QR_MAIN); - self.draw_number(format_info, 15, Color::Dark, Color::Light, &FORMAT_INFO_COORDS_QR_SIDE); - self.put(8, -8, Color::Dark); // Dark module. - } - } - } - - /// Reserves area to put in the format information. - fn draw_reserved_format_info_patterns(&mut self) { - self.draw_format_info_patterns_with_number(0); - } - - /// Draws the version information patterns. - fn draw_version_info_patterns(&mut self) { - match self.version { - Version::Micro(_) | Version::Normal(1..=6) => {} - Version::Normal(a) => { - let version_info = VERSION_INFOS[(a - 7).as_usize()]; - self.draw_number(version_info, 18, Color::Dark, Color::Light, &VERSION_INFO_COORDS_BL); - self.draw_number(version_info, 18, Color::Dark, Color::Light, &VERSION_INFO_COORDS_TR); - } - } - } -} - -#[cfg(test)] -mod draw_version_info_tests { - use crate::canvas::Canvas; - use crate::types::{Color, EcLevel, Version}; - - #[test] - fn test_draw_number() { - let mut c = Canvas::new(Version::Micro(1), EcLevel::L); - c.draw_number(0b10101101, 8, Color::Dark, Color::Light, &[(0, 0), (0, -1), (-2, -2), (-2, 0)]); - assert_eq!( - &*c.to_debug_str(), - "\n\ - #????????.?\n\ - ???????????\n\ - ???????????\n\ - ???????????\n\ - ???????????\n\ - ???????????\n\ - ???????????\n\ - ???????????\n\ - ???????????\n\ - ?????????#?\n\ - .??????????" - ); - } - - #[test] - fn test_draw_version_info_1() { - let mut c = Canvas::new(Version::Normal(1), EcLevel::L); - c.draw_version_info_patterns(); - assert_eq!( - &*c.to_debug_str(), - "\n\ - ?????????????????????\n\ - ?????????????????????\n\ - ?????????????????????\n\ - ?????????????????????\n\ - ?????????????????????\n\ - ?????????????????????\n\ - ?????????????????????\n\ - ?????????????????????\n\ - ?????????????????????\n\ - ?????????????????????\n\ - ?????????????????????\n\ - ?????????????????????\n\ - ?????????????????????\n\ - ?????????????????????\n\ - ?????????????????????\n\ - ?????????????????????\n\ - ?????????????????????\n\ - ?????????????????????\n\ - ?????????????????????\n\ - ?????????????????????\n\ - ?????????????????????" - ); - } - - #[test] - fn test_draw_version_info_7() { - let mut c = Canvas::new(Version::Normal(7), EcLevel::L); - c.draw_version_info_patterns(); - - assert_eq!( - &*c.to_debug_str(), - "\n\ - ??????????????????????????????????..#????????\n\ - ??????????????????????????????????.#.????????\n\ - ??????????????????????????????????.#.????????\n\ - ??????????????????????????????????.##????????\n\ - ??????????????????????????????????###????????\n\ - ??????????????????????????????????...????????\n\ - ?????????????????????????????????????????????\n\ - ?????????????????????????????????????????????\n\ - ?????????????????????????????????????????????\n\ - ?????????????????????????????????????????????\n\ - ?????????????????????????????????????????????\n\ - ?????????????????????????????????????????????\n\ - ?????????????????????????????????????????????\n\ - ?????????????????????????????????????????????\n\ - ?????????????????????????????????????????????\n\ - ?????????????????????????????????????????????\n\ - ?????????????????????????????????????????????\n\ - ?????????????????????????????????????????????\n\ - ?????????????????????????????????????????????\n\ - ?????????????????????????????????????????????\n\ - ?????????????????????????????????????????????\n\ - ?????????????????????????????????????????????\n\ - ?????????????????????????????????????????????\n\ - ?????????????????????????????????????????????\n\ - ?????????????????????????????????????????????\n\ - ?????????????????????????????????????????????\n\ - ?????????????????????????????????????????????\n\ - ?????????????????????????????????????????????\n\ - ?????????????????????????????????????????????\n\ - ?????????????????????????????????????????????\n\ - ?????????????????????????????????????????????\n\ - ?????????????????????????????????????????????\n\ - ?????????????????????????????????????????????\n\ - ?????????????????????????????????????????????\n\ - ....#.???????????????????????????????????????\n\ - .####.???????????????????????????????????????\n\ - #..##.???????????????????????????????????????\n\ - ?????????????????????????????????????????????\n\ - ?????????????????????????????????????????????\n\ - ?????????????????????????????????????????????\n\ - ?????????????????????????????????????????????\n\ - ?????????????????????????????????????????????\n\ - ?????????????????????????????????????????????\n\ - ?????????????????????????????????????????????\n\ - ?????????????????????????????????????????????" - ); - } - - #[test] - fn test_draw_reserved_format_info_patterns_qr() { - let mut c = Canvas::new(Version::Normal(1), EcLevel::L); - c.draw_reserved_format_info_patterns(); - assert_eq!( - &*c.to_debug_str(), - "\n\ - ????????.????????????\n\ - ????????.????????????\n\ - ????????.????????????\n\ - ????????.????????????\n\ - ????????.????????????\n\ - ????????.????????????\n\ - ?????????????????????\n\ - ????????.????????????\n\ - ......?..????........\n\ - ?????????????????????\n\ - ?????????????????????\n\ - ?????????????????????\n\ - ?????????????????????\n\ - ????????#????????????\n\ - ????????.????????????\n\ - ????????.????????????\n\ - ????????.????????????\n\ - ????????.????????????\n\ - ????????.????????????\n\ - ????????.????????????\n\ - ????????.????????????" - ); - } - - #[test] - fn test_draw_reserved_format_info_patterns_micro_qr() { - let mut c = Canvas::new(Version::Micro(1), EcLevel::L); - c.draw_reserved_format_info_patterns(); - assert_eq!( - &*c.to_debug_str(), - "\n\ - ???????????\n\ - ????????.??\n\ - ????????.??\n\ - ????????.??\n\ - ????????.??\n\ - ????????.??\n\ - ????????.??\n\ - ????????.??\n\ - ?........??\n\ - ???????????\n\ - ???????????" - ); - } -} - -static VERSION_INFO_COORDS_BL: [(i16, i16); 18] = [ - (5, -9), - (5, -10), - (5, -11), - (4, -9), - (4, -10), - (4, -11), - (3, -9), - (3, -10), - (3, -11), - (2, -9), - (2, -10), - (2, -11), - (1, -9), - (1, -10), - (1, -11), - (0, -9), - (0, -10), - (0, -11), -]; - -static VERSION_INFO_COORDS_TR: [(i16, i16); 18] = [ - (-9, 5), - (-10, 5), - (-11, 5), - (-9, 4), - (-10, 4), - (-11, 4), - (-9, 3), - (-10, 3), - (-11, 3), - (-9, 2), - (-10, 2), - (-11, 2), - (-9, 1), - (-10, 1), - (-11, 1), - (-9, 0), - (-10, 0), - (-11, 0), -]; - -static FORMAT_INFO_COORDS_QR_MAIN: [(i16, i16); 15] = [ - (0, 8), - (1, 8), - (2, 8), - (3, 8), - (4, 8), - (5, 8), - (7, 8), - (8, 8), - (8, 7), - (8, 5), - (8, 4), - (8, 3), - (8, 2), - (8, 1), - (8, 0), -]; - -static FORMAT_INFO_COORDS_QR_SIDE: [(i16, i16); 15] = [ - (8, -1), - (8, -2), - (8, -3), - (8, -4), - (8, -5), - (8, -6), - (8, -7), - (-8, 8), - (-7, 8), - (-6, 8), - (-5, 8), - (-4, 8), - (-3, 8), - (-2, 8), - (-1, 8), -]; - -static FORMAT_INFO_COORDS_MICRO_QR: [(i16, i16); 15] = [ - (1, 8), - (2, 8), - (3, 8), - (4, 8), - (5, 8), - (6, 8), - (7, 8), - (8, 8), - (8, 7), - (8, 6), - (8, 5), - (8, 4), - (8, 3), - (8, 2), - (8, 1), -]; - -static VERSION_INFOS: [u32; 34] = [ - 0x07c94, 0x085bc, 0x09a99, 0x0a4d3, 0x0bbf6, 0x0c762, 0x0d847, 0x0e60d, 0x0f928, 0x10b78, 0x1145d, 0x12a17, - 0x13532, 0x149a6, 0x15683, 0x168c9, 0x177ec, 0x18ec4, 0x191e1, 0x1afab, 0x1b08e, 0x1cc1a, 0x1d33f, 0x1ed75, - 0x1f250, 0x209d5, 0x216f0, 0x228ba, 0x2379f, 0x24b0b, 0x2542e, 0x26a64, 0x27541, 0x28c69, -]; - -//}}} -//------------------------------------------------------------------------------ -//{{{ All functional patterns before data placement - -impl Canvas { - /// Draw all functional patterns, before data placement. - /// - /// All functional patterns (e.g. the finder pattern) *except* the format - /// info pattern will be filled in. The format info pattern will be filled - /// with light modules instead. Data bits can then put in the empty modules. - /// with `.draw_data()`. - pub fn draw_all_functional_patterns(&mut self) { - self.draw_finder_patterns(); - self.draw_alignment_patterns(); - self.draw_reserved_format_info_patterns(); - self.draw_timing_patterns(); - self.draw_version_info_patterns(); - } -} - -/// Gets whether the module at the given coordinates represents a functional -/// module. -pub fn is_functional(version: Version, width: i16, x: i16, y: i16) -> bool { - debug_assert!(width == version.width()); - - let x = if x < 0 { x + width } else { x }; - let y = if y < 0 { y + width } else { y }; - - match version { - Version::Micro(_) => x == 0 || y == 0 || (x < 9 && y < 9), - Version::Normal(a) => { - let non_alignment_test = x == 6 || y == 6 || // Timing patterns - (x < 9 && y < 9) || // Top-left finder pattern - (x < 9 && y >= width-8) || // Bottom-left finder pattern - (x >= width-8 && y < 9); // Top-right finder pattern - if non_alignment_test { - true - } else if a == 1 { - false - } else if (2..=6).contains(&a) { - (width - 7 - x).abs() <= 2 && (width - 7 - y).abs() <= 2 - } else { - let positions = ALIGNMENT_PATTERN_POSITIONS[(a - 7).as_usize()]; - let last = positions.len() - 1; - for (i, align_x) in positions.iter().enumerate() { - for (j, align_y) in positions.iter().enumerate() { - if i == 0 && (j == 0 || j == last) || (i == last && j == 0) { - continue; - } - if (*align_x - x).abs() <= 2 && (*align_y - y).abs() <= 2 { - return true; - } - } - } - false - } - } - } -} - -#[cfg(test)] -mod all_functional_patterns_tests { - use crate::canvas::{is_functional, Canvas}; - use crate::types::{EcLevel, Version}; - - #[test] - fn test_all_functional_patterns_qr() { - let mut c = Canvas::new(Version::Normal(2), EcLevel::L); - c.draw_all_functional_patterns(); - assert_eq!( - &*c.to_debug_str(), - "\n\ - #######..????????.#######\n\ - #.....#..????????.#.....#\n\ - #.###.#..????????.#.###.#\n\ - #.###.#..????????.#.###.#\n\ - #.###.#..????????.#.###.#\n\ - #.....#..????????.#.....#\n\ - #######.#.#.#.#.#.#######\n\ - .........????????........\n\ - ......#..????????........\n\ - ??????.??????????????????\n\ - ??????#??????????????????\n\ - ??????.??????????????????\n\ - ??????#??????????????????\n\ - ??????.??????????????????\n\ - ??????#??????????????????\n\ - ??????.??????????????????\n\ - ??????#?????????#####????\n\ - ........#???????#...#????\n\ - #######..???????#.#.#????\n\ - #.....#..???????#...#????\n\ - #.###.#..???????#####????\n\ - #.###.#..????????????????\n\ - #.###.#..????????????????\n\ - #.....#..????????????????\n\ - #######..????????????????" - ); - } - - #[test] - fn test_all_functional_patterns_micro_qr() { - let mut c = Canvas::new(Version::Micro(1), EcLevel::L); - c.draw_all_functional_patterns(); - assert_eq!( - &*c.to_debug_str(), - "\n\ - #######.#.#\n\ - #.....#..??\n\ - #.###.#..??\n\ - #.###.#..??\n\ - #.###.#..??\n\ - #.....#..??\n\ - #######..??\n\ - .........??\n\ - #........??\n\ - .??????????\n\ - #??????????" - ); - } - - #[test] - fn test_is_functional_qr_1() { - let version = Version::Normal(1); - assert!(is_functional(version, version.width(), 0, 0)); - assert!(is_functional(version, version.width(), 10, 6)); - assert!(!is_functional(version, version.width(), 10, 5)); - assert!(!is_functional(version, version.width(), 14, 14)); - assert!(is_functional(version, version.width(), 6, 11)); - assert!(!is_functional(version, version.width(), 4, 11)); - assert!(is_functional(version, version.width(), 4, 13)); - assert!(is_functional(version, version.width(), 17, 7)); - assert!(!is_functional(version, version.width(), 17, 17)); - } - - #[test] - fn test_is_functional_qr_3() { - let version = Version::Normal(3); - assert!(is_functional(version, version.width(), 0, 0)); - assert!(!is_functional(version, version.width(), 25, 24)); - assert!(is_functional(version, version.width(), 24, 24)); - assert!(!is_functional(version, version.width(), 9, 25)); - assert!(!is_functional(version, version.width(), 20, 0)); - assert!(is_functional(version, version.width(), 21, 0)); - } - - #[test] - fn test_is_functional_qr_7() { - let version = Version::Normal(7); - assert!(is_functional(version, version.width(), 21, 4)); - assert!(is_functional(version, version.width(), 7, 21)); - assert!(is_functional(version, version.width(), 22, 22)); - assert!(is_functional(version, version.width(), 8, 8)); - assert!(!is_functional(version, version.width(), 19, 5)); - assert!(!is_functional(version, version.width(), 36, 3)); - assert!(!is_functional(version, version.width(), 4, 36)); - assert!(is_functional(version, version.width(), 38, 38)); - } - - #[test] - fn test_is_functional_micro() { - let version = Version::Micro(1); - assert!(is_functional(version, version.width(), 8, 0)); - assert!(is_functional(version, version.width(), 10, 0)); - assert!(!is_functional(version, version.width(), 10, 1)); - assert!(is_functional(version, version.width(), 8, 8)); - assert!(is_functional(version, version.width(), 0, 9)); - assert!(!is_functional(version, version.width(), 1, 9)); - } -} - -//}}} -//------------------------------------------------------------------------------ -//{{{ Data placement iterator - -struct DataModuleIter { - x: i16, - y: i16, - width: i16, - timing_pattern_column: i16, -} - -impl DataModuleIter { - fn new(version: Version) -> Self { - let width = version.width(); - Self { - x: width - 1, - y: width - 1, - width, - timing_pattern_column: match version { - Version::Micro(_) => 0, - Version::Normal(_) => 6, - }, - } - } -} - -impl Iterator for DataModuleIter { - type Item = (i16, i16); - - fn next(&mut self) -> Option<(i16, i16)> { - let adjusted_ref_col = if self.x <= self.timing_pattern_column { self.x + 1 } else { self.x }; - if adjusted_ref_col <= 0 { - return None; - } - - let res = (self.x, self.y); - let column_type = (self.width - adjusted_ref_col) % 4; - - match column_type { - 2 if self.y > 0 => { - self.y -= 1; - self.x += 1; - } - 0 if self.y < self.width - 1 => { - self.y += 1; - self.x += 1; - } - 0 | 2 if self.x == self.timing_pattern_column + 1 => { - self.x -= 2; - } - _ => { - self.x -= 1; - } - } - - Some(res) - } -} - -#[cfg(test)] -#[rustfmt::skip] // skip to prevent file becoming too long. -mod data_iter_tests { - use alloc::vec::{Vec}; - - use crate::canvas::DataModuleIter; - use crate::types::Version; - - #[test] - fn test_qr() { - let res = DataModuleIter::new(Version::Normal(1)).collect::>(); - assert_eq!(res, vec![ - (20, 20), (19, 20), (20, 19), (19, 19), (20, 18), (19, 18), - (20, 17), (19, 17), (20, 16), (19, 16), (20, 15), (19, 15), - (20, 14), (19, 14), (20, 13), (19, 13), (20, 12), (19, 12), - (20, 11), (19, 11), (20, 10), (19, 10), (20, 9), (19, 9), - (20, 8), (19, 8), (20, 7), (19, 7), (20, 6), (19, 6), - (20, 5), (19, 5), (20, 4), (19, 4), (20, 3), (19, 3), - (20, 2), (19, 2), (20, 1), (19, 1), (20, 0), (19, 0), - - (18, 0), (17, 0), (18, 1), (17, 1), (18, 2), (17, 2), - (18, 3), (17, 3), (18, 4), (17, 4), (18, 5), (17, 5), - (18, 6), (17, 6), (18, 7), (17, 7), (18, 8), (17, 8), - (18, 9), (17, 9), (18, 10), (17, 10), (18, 11), (17, 11), - (18, 12), (17, 12), (18, 13), (17, 13), (18, 14), (17, 14), - (18, 15), (17, 15), (18, 16), (17, 16), (18, 17), (17, 17), - (18, 18), (17, 18), (18, 19), (17, 19), (18, 20), (17, 20), - - (16, 20), (15, 20), (16, 19), (15, 19), (16, 18), (15, 18), - (16, 17), (15, 17), (16, 16), (15, 16), (16, 15), (15, 15), - (16, 14), (15, 14), (16, 13), (15, 13), (16, 12), (15, 12), - (16, 11), (15, 11), (16, 10), (15, 10), (16, 9), (15, 9), - (16, 8), (15, 8), (16, 7), (15, 7), (16, 6), (15, 6), - (16, 5), (15, 5), (16, 4), (15, 4), (16, 3), (15, 3), - (16, 2), (15, 2), (16, 1), (15, 1), (16, 0), (15, 0), - - (14, 0), (13, 0), (14, 1), (13, 1), (14, 2), (13, 2), - (14, 3), (13, 3), (14, 4), (13, 4), (14, 5), (13, 5), - (14, 6), (13, 6), (14, 7), (13, 7), (14, 8), (13, 8), - (14, 9), (13, 9), (14, 10), (13, 10), (14, 11), (13, 11), - (14, 12), (13, 12), (14, 13), (13, 13), (14, 14), (13, 14), - (14, 15), (13, 15), (14, 16), (13, 16), (14, 17), (13, 17), - (14, 18), (13, 18), (14, 19), (13, 19), (14, 20), (13, 20), - - (12, 20), (11, 20), (12, 19), (11, 19), (12, 18), (11, 18), - (12, 17), (11, 17), (12, 16), (11, 16), (12, 15), (11, 15), - (12, 14), (11, 14), (12, 13), (11, 13), (12, 12), (11, 12), - (12, 11), (11, 11), (12, 10), (11, 10), (12, 9), (11, 9), - (12, 8), (11, 8), (12, 7), (11, 7), (12, 6), (11, 6), - (12, 5), (11, 5), (12, 4), (11, 4), (12, 3), (11, 3), - (12, 2), (11, 2), (12, 1), (11, 1), (12, 0), (11, 0), - - (10, 0), (9, 0), (10, 1), (9, 1), (10, 2), (9, 2), - (10, 3), (9, 3), (10, 4), (9, 4), (10, 5), (9, 5), - (10, 6), (9, 6), (10, 7), (9, 7), (10, 8), (9, 8), - (10, 9), (9, 9), (10, 10), (9, 10), (10, 11), (9, 11), - (10, 12), (9, 12), (10, 13), (9, 13), (10, 14), (9, 14), - (10, 15), (9, 15), (10, 16), (9, 16), (10, 17), (9, 17), - (10, 18), (9, 18), (10, 19), (9, 19), (10, 20), (9, 20), - - (8, 20), (7, 20), (8, 19), (7, 19), (8, 18), (7, 18), - (8, 17), (7, 17), (8, 16), (7, 16), (8, 15), (7, 15), - (8, 14), (7, 14), (8, 13), (7, 13), (8, 12), (7, 12), - (8, 11), (7, 11), (8, 10), (7, 10), (8, 9), (7, 9), - (8, 8), (7, 8), (8, 7), (7, 7), (8, 6), (7, 6), - (8, 5), (7, 5), (8, 4), (7, 4), (8, 3), (7, 3), - (8, 2), (7, 2), (8, 1), (7, 1), (8, 0), (7, 0), - - (5, 0), (4, 0), (5, 1), (4, 1), (5, 2), (4, 2), - (5, 3), (4, 3), (5, 4), (4, 4), (5, 5), (4, 5), - (5, 6), (4, 6), (5, 7), (4, 7), (5, 8), (4, 8), - (5, 9), (4, 9), (5, 10), (4, 10), (5, 11), (4, 11), - (5, 12), (4, 12), (5, 13), (4, 13), (5, 14), (4, 14), - (5, 15), (4, 15), (5, 16), (4, 16), (5, 17), (4, 17), - (5, 18), (4, 18), (5, 19), (4, 19), (5, 20), (4, 20), - - (3, 20), (2, 20), (3, 19), (2, 19), (3, 18), (2, 18), - (3, 17), (2, 17), (3, 16), (2, 16), (3, 15), (2, 15), - (3, 14), (2, 14), (3, 13), (2, 13), (3, 12), (2, 12), - (3, 11), (2, 11), (3, 10), (2, 10), (3, 9), (2, 9), - (3, 8), (2, 8), (3, 7), (2, 7), (3, 6), (2, 6), - (3, 5), (2, 5), (3, 4), (2, 4), (3, 3), (2, 3), - (3, 2), (2, 2), (3, 1), (2, 1), (3, 0), (2, 0), - - (1, 0), (0, 0), (1, 1), (0, 1), (1, 2), (0, 2), - (1, 3), (0, 3), (1, 4), (0, 4), (1, 5), (0, 5), - (1, 6), (0, 6), (1, 7), (0, 7), (1, 8), (0, 8), - (1, 9), (0, 9), (1, 10), (0, 10), (1, 11), (0, 11), - (1, 12), (0, 12), (1, 13), (0, 13), (1, 14), (0, 14), - (1, 15), (0, 15), (1, 16), (0, 16), (1, 17), (0, 17), - (1, 18), (0, 18), (1, 19), (0, 19), (1, 20), (0, 20), - ]); - } - - #[test] - fn test_micro_qr() { - let res = DataModuleIter::new(Version::Micro(1)).collect::>(); - assert_eq!(res, vec![ - (10, 10), (9, 10), (10, 9), (9, 9), (10, 8), (9, 8), - (10, 7), (9, 7), (10, 6), (9, 6), (10, 5), (9, 5), - (10, 4), (9, 4), (10, 3), (9, 3), (10, 2), (9, 2), - (10, 1), (9, 1), (10, 0), (9, 0), - - (8, 0), (7, 0), (8, 1), (7, 1), (8, 2), (7, 2), - (8, 3), (7, 3), (8, 4), (7, 4), (8, 5), (7, 5), - (8, 6), (7, 6), (8, 7), (7, 7), (8, 8), (7, 8), - (8, 9), (7, 9), (8, 10), (7, 10), - - (6, 10), (5, 10), (6, 9), (5, 9), (6, 8), (5, 8), - (6, 7), (5, 7), (6, 6), (5, 6), (6, 5), (5, 5), - (6, 4), (5, 4), (6, 3), (5, 3), (6, 2), (5, 2), - (6, 1), (5, 1), (6, 0), (5, 0), - - (4, 0), (3, 0), (4, 1), (3, 1), (4, 2), (3, 2), - (4, 3), (3, 3), (4, 4), (3, 4), (4, 5), (3, 5), - (4, 6), (3, 6), (4, 7), (3, 7), (4, 8), (3, 8), - (4, 9), (3, 9), (4, 10), (3, 10), - - (2, 10), (1, 10), (2, 9), (1, 9), (2, 8), (1, 8), - (2, 7), (1, 7), (2, 6), (1, 6), (2, 5), (1, 5), - (2, 4), (1, 4), (2, 3), (1, 3), (2, 2), (1, 2), - (2, 1), (1, 1), (2, 0), (1, 0), - ]); - } - - #[test] - fn test_micro_qr_2() { - let res = DataModuleIter::new(Version::Micro(2)).collect::>(); - assert_eq!(res, vec![ - (12, 12), (11, 12), (12, 11), (11, 11), (12, 10), (11, 10), - (12, 9), (11, 9), (12, 8), (11, 8), (12, 7), (11, 7), - (12, 6), (11, 6), (12, 5), (11, 5), (12, 4), (11, 4), - (12, 3), (11, 3), (12, 2), (11, 2), (12, 1), (11, 1), - (12, 0), (11, 0), - - (10, 0), (9, 0), (10, 1), (9, 1), (10, 2), (9, 2), - (10, 3), (9, 3), (10, 4), (9, 4), (10, 5), (9, 5), - (10, 6), (9, 6), (10, 7), (9, 7), (10, 8), (9, 8), - (10, 9), (9, 9), (10, 10), (9, 10), (10, 11), (9, 11), - (10, 12), (9, 12), - - (8, 12), (7, 12), (8, 11), (7, 11), (8, 10), (7, 10), - (8, 9), (7, 9), (8, 8), (7, 8), (8, 7), (7, 7), - (8, 6), (7, 6), (8, 5), (7, 5), (8, 4), (7, 4), - (8, 3), (7, 3), (8, 2), (7, 2), (8, 1), (7, 1), - (8, 0), (7, 0), - - (6, 0), (5, 0), (6, 1), (5, 1), (6, 2), (5, 2), - (6, 3), (5, 3), (6, 4), (5, 4), (6, 5), (5, 5), - (6, 6), (5, 6), (6, 7), (5, 7), (6, 8), (5, 8), - (6, 9), (5, 9), (6, 10), (5, 10), (6, 11), (5, 11), - (6, 12), (5, 12), - - (4, 12), (3, 12), (4, 11), (3, 11), (4, 10), (3, 10), - (4, 9), (3, 9), (4, 8), (3, 8), (4, 7), (3, 7), - (4, 6), (3, 6), (4, 5), (3, 5), (4, 4), (3, 4), - (4, 3), (3, 3), (4, 2), (3, 2), (4, 1), (3, 1), - (4, 0), (3, 0), - - (2, 0), (1, 0), (2, 1), (1, 1), (2, 2), (1, 2), - (2, 3), (1, 3), (2, 4), (1, 4), (2, 5), (1, 5), - (2, 6), (1, 6), (2, 7), (1, 7), (2, 8), (1, 8), - (2, 9), (1, 9), (2, 10), (1, 10), (2, 11), (1, 11), - (2, 12), (1, 12), - ]); - } -} - -//}}} -//------------------------------------------------------------------------------ -//{{{ Data placement - -impl Canvas { - fn draw_codewords(&mut self, codewords: &[u8], is_half_codeword_at_end: bool, coords: &mut I) - where - I: Iterator, - { - let length = codewords.len(); - let last_word = if is_half_codeword_at_end { length - 1 } else { length }; - for (i, b) in codewords.iter().enumerate() { - let bits_end = if i == last_word { 4 } else { 0 }; - 'outside: for j in (bits_end..=7).rev() { - let color = if (*b & (1 << j)) == 0 { Color::Light } else { Color::Dark }; - for (x, y) in coords.by_ref() { - let r = self.get_mut(x, y); - if *r == Module::Empty { - *r = Module::Unmasked(color); - continue 'outside; - } - } - return; - } - } - } - - /// Draws the encoded data and error correction codes to the empty modules. - pub fn draw_data(&mut self, data: &[u8], ec: &[u8]) { - let is_half_codeword_at_end = match (self.version, self.ec_level) { - (Version::Micro(1), EcLevel::L) | (Version::Micro(3), EcLevel::M) => true, - _ => false, - }; - - let mut coords = DataModuleIter::new(self.version); - self.draw_codewords(data, is_half_codeword_at_end, &mut coords); - self.draw_codewords(ec, false, &mut coords); - } -} - -#[cfg(test)] -mod draw_codewords_test { - use crate::canvas::Canvas; - use crate::types::{EcLevel, Version}; - - #[test] - fn test_micro_qr_1() { - let mut c = Canvas::new(Version::Micro(1), EcLevel::L); - c.draw_all_functional_patterns(); - c.draw_data(b"\x6e\x5d\xe2", b"\x2b\x63"); - assert_eq!( - &*c.to_debug_str(), - "\n\ - #######.#.#\n\ - #.....#..-*\n\ - #.###.#..**\n\ - #.###.#..*-\n\ - #.###.#..**\n\ - #.....#..*-\n\ - #######..*-\n\ - .........-*\n\ - #........**\n\ - .***-**---*\n\ - #---*-*-**-" - ); - } - - #[test] - fn test_qr_2() { - let mut c = Canvas::new(Version::Normal(2), EcLevel::L); - c.draw_all_functional_patterns(); - c.draw_data( - b"\x92I$\x92I$\x92I$\x92I$\x92I$\x92I$\x92I$\x92I$\ - \x92I$\x92I$\x92I$\x92I$\x92I$\x92I$\x92I$", - b"", - ); - assert_eq!( - &*c.to_debug_str(), - "\n\ - #######..--*---*-.#######\n\ - #.....#..-*-*-*-*.#.....#\n\ - #.###.#..*---*---.#.###.#\n\ - #.###.#..--*---*-.#.###.#\n\ - #.###.#..-*-*-*-*.#.###.#\n\ - #.....#..*---*---.#.....#\n\ - #######.#.#.#.#.#.#######\n\ - .........--*---*-........\n\ - ......#..-*-*-*-*........\n\ - --*-*-.-**---*---*--**--*\n\ - -*-*--#----*---*---------\n\ - *----*.*--*-*-*-*-**--**-\n\ - --*-*-#-**---*---*--**--*\n\ - -*-*--.----*---*---------\n\ - *----*#*--*-*-*-*-**--**-\n\ - --*-*-.-**---*---*--**--*\n\ - -*-*--#----*---*#####----\n\ - ........#-*-*-*-#...#-**-\n\ - #######..*---*--#.#.#*--*\n\ - #.....#..--*---*#...#----\n\ - #.###.#..-*-*-*-#####-**-\n\ - #.###.#..*---*--*----*--*\n\ - #.###.#..--*------**-----\n\ - #.....#..-*-*-**-*--*-**-\n\ - #######..*---*--*----*--*" - ); - } -} -//}}} -//------------------------------------------------------------------------------ -//{{{ Masking - -/// The mask patterns. Since QR code and Micro QR code do not use the same -/// pattern number, we name them according to their shape instead of the number. -#[derive(Debug, Copy, Clone)] -pub enum MaskPattern { - /// QR code pattern 000: `(x + y) % 2 == 0`. - Checkerboard = 0b000, - - /// QR code pattern 001: `y % 2 == 0`. - HorizontalLines = 0b001, - - /// QR code pattern 010: `x % 3 == 0`. - VerticalLines = 0b010, - - /// QR code pattern 011: `(x + y) % 3 == 0`. - DiagonalLines = 0b011, - - /// QR code pattern 100: `((x/3) + (y/2)) % 2 == 0`. - LargeCheckerboard = 0b100, - - /// QR code pattern 101: `(x*y)%2 + (x*y)%3 == 0`. - Fields = 0b101, - - /// QR code pattern 110: `((x*y)%2 + (x*y)%3) % 2 == 0`. - Diamonds = 0b110, - - /// QR code pattern 111: `((x+y)%2 + (x*y)%3) % 2 == 0`. - Meadow = 0b111, -} - -mod mask_functions { - pub fn checkerboard(x: i16, y: i16) -> bool { - (x + y) % 2 == 0 - } - pub fn horizontal_lines(_: i16, y: i16) -> bool { - y % 2 == 0 - } - pub fn vertical_lines(x: i16, _: i16) -> bool { - x % 3 == 0 - } - pub fn diagonal_lines(x: i16, y: i16) -> bool { - (x + y) % 3 == 0 - } - pub fn large_checkerboard(x: i16, y: i16) -> bool { - ((y / 2) + (x / 3)) % 2 == 0 - } - pub fn fields(x: i16, y: i16) -> bool { - (x * y) % 2 + (x * y) % 3 == 0 - } - pub fn diamonds(x: i16, y: i16) -> bool { - ((x * y) % 2 + (x * y) % 3) % 2 == 0 - } - pub fn meadow(x: i16, y: i16) -> bool { - ((x + y) % 2 + (x * y) % 3) % 2 == 0 - } -} - -fn get_mask_function(pattern: MaskPattern) -> fn(i16, i16) -> bool { - match pattern { - MaskPattern::Checkerboard => mask_functions::checkerboard, - MaskPattern::HorizontalLines => mask_functions::horizontal_lines, - MaskPattern::VerticalLines => mask_functions::vertical_lines, - MaskPattern::DiagonalLines => mask_functions::diagonal_lines, - MaskPattern::LargeCheckerboard => mask_functions::large_checkerboard, - MaskPattern::Fields => mask_functions::fields, - MaskPattern::Diamonds => mask_functions::diamonds, - MaskPattern::Meadow => mask_functions::meadow, - } -} - -impl Canvas { - /// Applies a mask to the canvas. This method will also draw the format info - /// patterns. - pub fn apply_mask(&mut self, pattern: MaskPattern) { - let mask_fn = get_mask_function(pattern); - for x in 0..self.width { - for y in 0..self.width { - let module = self.get_mut(x, y); - *module = module.mask(mask_fn(x, y)); - } - } - - self.draw_format_info_patterns(pattern); - } - - /// Draws the format information to encode the error correction level and - /// mask pattern. - /// - /// If the error correction level or mask pattern is not supported in the - /// current QR code version, this method will fail. - fn draw_format_info_patterns(&mut self, pattern: MaskPattern) { - let format_number = match self.version { - Version::Normal(_) => { - let simple_format_number = ((self.ec_level as usize) ^ 1) << 3 | (pattern as usize); - FORMAT_INFOS_QR[simple_format_number] - } - Version::Micro(a) => { - let micro_pattern_number = match pattern { - MaskPattern::HorizontalLines => 0b00, - MaskPattern::LargeCheckerboard => 0b01, - MaskPattern::Diamonds => 0b10, - MaskPattern::Meadow => 0b11, - _ => panic!("Unsupported mask pattern in Micro QR code"), - }; - let symbol_number = match (a, self.ec_level) { - (1, EcLevel::L) => 0b000, - (2, EcLevel::L) => 0b001, - (2, EcLevel::M) => 0b010, - (3, EcLevel::L) => 0b011, - (3, EcLevel::M) => 0b100, - (4, EcLevel::L) => 0b101, - (4, EcLevel::M) => 0b110, - (4, EcLevel::Q) => 0b111, - _ => panic!("Unsupported version/ec_level combination in Micro QR code"), - }; - let simple_format_number = symbol_number << 2 | micro_pattern_number; - FORMAT_INFOS_MICRO_QR[simple_format_number] - } - }; - self.draw_format_info_patterns_with_number(format_number); - } -} - -#[cfg(test)] -mod mask_tests { - use crate::canvas::{Canvas, MaskPattern}; - use crate::types::{EcLevel, Version}; - - #[test] - fn test_apply_mask_qr() { - let mut c = Canvas::new(Version::Normal(1), EcLevel::L); - c.draw_all_functional_patterns(); - c.apply_mask(MaskPattern::Checkerboard); - - assert_eq!( - &*c.to_debug_str(), - "\n\ - #######...#.#.#######\n\ - #.....#..#.#..#.....#\n\ - #.###.#.#.#.#.#.###.#\n\ - #.###.#..#.#..#.###.#\n\ - #.###.#...#.#.#.###.#\n\ - #.....#..#.#..#.....#\n\ - #######.#.#.#.#######\n\ - ........##.#.........\n\ - ###.#####.#.###...#..\n\ - .#.#.#.#.#.#.#.#.#.#.\n\ - #.#.#.#.#.#.#.#.#.#.#\n\ - .#.#.#.#.#.#.#.#.#.#.\n\ - #.#.#.#.#.#.#.#.#.#.#\n\ - ........##.#.#.#.#.#.\n\ - #######.#.#.#.#.#.#.#\n\ - #.....#.##.#.#.#.#.#.\n\ - #.###.#.#.#.#.#.#.#.#\n\ - #.###.#..#.#.#.#.#.#.\n\ - #.###.#.#.#.#.#.#.#.#\n\ - #.....#.##.#.#.#.#.#.\n\ - #######.#.#.#.#.#.#.#" - ); - } - - #[test] - fn test_draw_format_info_patterns_qr() { - let mut c = Canvas::new(Version::Normal(1), EcLevel::L); - c.draw_format_info_patterns(MaskPattern::LargeCheckerboard); - assert_eq!( - &*c.to_debug_str(), - "\n\ - ????????#????????????\n\ - ????????#????????????\n\ - ????????#????????????\n\ - ????????#????????????\n\ - ????????.????????????\n\ - ????????#????????????\n\ - ?????????????????????\n\ - ????????.????????????\n\ - ##..##?..????..#.####\n\ - ?????????????????????\n\ - ?????????????????????\n\ - ?????????????????????\n\ - ?????????????????????\n\ - ????????#????????????\n\ - ????????.????????????\n\ - ????????#????????????\n\ - ????????#????????????\n\ - ????????.????????????\n\ - ????????.????????????\n\ - ????????#????????????\n\ - ????????#????????????" - ); - } - - #[test] - fn test_draw_format_info_patterns_micro_qr() { - let mut c = Canvas::new(Version::Micro(2), EcLevel::L); - c.draw_format_info_patterns(MaskPattern::LargeCheckerboard); - assert_eq!( - &*c.to_debug_str(), - "\n\ - ?????????????\n\ - ????????#????\n\ - ????????.????\n\ - ????????.????\n\ - ????????#????\n\ - ????????#????\n\ - ????????.????\n\ - ????????.????\n\ - ?#.#....#????\n\ - ?????????????\n\ - ?????????????\n\ - ?????????????\n\ - ?????????????" - ); - } -} - -static FORMAT_INFOS_QR: [u16; 32] = [ - 0x5412, 0x5125, 0x5e7c, 0x5b4b, 0x45f9, 0x40ce, 0x4f97, 0x4aa0, 0x77c4, 0x72f3, 0x7daa, 0x789d, 0x662f, 0x6318, - 0x6c41, 0x6976, 0x1689, 0x13be, 0x1ce7, 0x19d0, 0x0762, 0x0255, 0x0d0c, 0x083b, 0x355f, 0x3068, 0x3f31, 0x3a06, - 0x24b4, 0x2183, 0x2eda, 0x2bed, -]; - -static FORMAT_INFOS_MICRO_QR: [u16; 32] = [ - 0x4445, 0x4172, 0x4e2b, 0x4b1c, 0x55ae, 0x5099, 0x5fc0, 0x5af7, 0x6793, 0x62a4, 0x6dfd, 0x68ca, 0x7678, 0x734f, - 0x7c16, 0x7921, 0x06de, 0x03e9, 0x0cb0, 0x0987, 0x1735, 0x1202, 0x1d5b, 0x186c, 0x2508, 0x203f, 0x2f66, 0x2a51, - 0x34e3, 0x31d4, 0x3e8d, 0x3bba, -]; - -//}}} -//------------------------------------------------------------------------------ -//{{{ Penalty score - -impl Canvas { - /// Compute the penalty score for having too many adjacent modules with the - /// same color. - /// - /// Every 5+N adjacent modules in the same column/row having the same color - /// will contribute 3+N points. - fn compute_adjacent_penalty_score(&self, is_horizontal: bool) -> u16 { - let mut total_score = 0; - - for i in 0..self.width { - let map_fn = |j| if is_horizontal { self.get(j, i) } else { self.get(i, j) }; - - let colors = (0..self.width).map(map_fn).chain(Some(Module::Empty).into_iter()); - let mut last_color = Module::Empty; - let mut consecutive_len = 1_u16; - - for color in colors { - if color == last_color { - consecutive_len += 1; - } else { - last_color = color; - if consecutive_len >= 5 { - total_score += consecutive_len - 2; - } - consecutive_len = 1; - } - } - } - - total_score - } - - /// Compute the penalty score for having too many rectangles with the same - /// color. - /// - /// Every 2×2 blocks (with overlapping counted) having the same color will - /// contribute 3 points. - fn compute_block_penalty_score(&self) -> u16 { - let mut total_score = 0; - - for i in 0..self.width - 1 { - for j in 0..self.width - 1 { - let this = self.get(i, j); - let right = self.get(i + 1, j); - let bottom = self.get(i, j + 1); - let bottom_right = self.get(i + 1, j + 1); - if this == right && right == bottom && bottom == bottom_right { - total_score += 3; - } - } - } - - total_score - } - - /// Compute the penalty score for having a pattern similar to the finder - /// pattern in the wrong place. - /// - /// Every pattern that looks like `#.###.#....` in any orientation will add - /// 40 points. - fn compute_finder_penalty_score(&self, is_horizontal: bool) -> u16 { - static PATTERN: [Color; 7] = - [Color::Dark, Color::Light, Color::Dark, Color::Dark, Color::Dark, Color::Light, Color::Dark]; - - let mut total_score = 0; - - for i in 0..self.width { - for j in 0..self.width - 6 { - // TODO a ref to a closure should be enough? - let get: Box Color> = if is_horizontal { - Box::new(|k| self.get(k, i).into()) - } else { - Box::new(|k| self.get(i, k).into()) - }; - - if (j..(j + 7)).map(&*get).ne(PATTERN.iter().cloned()) { - continue; - } - - let check = |k| 0 <= k && k < self.width && get(k) != Color::Light; - if !((j - 4)..j).any(&check) || !((j + 7)..(j + 11)).any(&check) { - total_score += 40; - } - } - } - - total_score - 360 - } - - /// Compute the penalty score for having an unbalanced dark/light ratio. - /// - /// The score is given linearly by the deviation from a 50% ratio of dark - /// modules. The highest possible score is 100. - /// - /// Note that this algorithm differs slightly from the standard we do not - /// round the result every 5%, but the difference should be negligible and - /// should not affect which mask is chosen. - fn compute_balance_penalty_score(&self) -> u16 { - let dark_modules = self.modules.iter().filter(|m| m.is_dark()).count(); - let total_modules = self.modules.len(); - let ratio = dark_modules * 200 / total_modules; - if ratio >= 100 { ratio - 100 } else { 100 - ratio }.as_u16() - } - - /// Compute the penalty score for having too many light modules on the sides. - /// - /// This penalty score is exclusive to Micro QR code. - /// - /// Note that the standard gives the formula for *efficiency* score, which - /// has the inverse meaning of this method, but it is very easy to convert - /// between the two (this score is (16×width − standard-score)). - fn compute_light_side_penalty_score(&self) -> u16 { - let h = (1..self.width).filter(|j| !self.get(*j, -1).is_dark()).count(); - let v = (1..self.width).filter(|j| !self.get(-1, *j).is_dark()).count(); - - (h + v + 15 * max(h, v)).as_u16() - } - - /// Compute the total penalty scores. A QR code having higher points is less - /// desirable. - fn compute_total_penalty_scores(&self) -> u16 { - match self.version { - Version::Normal(_) => { - let s1_a = self.compute_adjacent_penalty_score(true); - let s1_b = self.compute_adjacent_penalty_score(false); - let s2 = self.compute_block_penalty_score(); - let s3_a = self.compute_finder_penalty_score(true); - let s3_b = self.compute_finder_penalty_score(false); - let s4 = self.compute_balance_penalty_score(); - s1_a + s1_b + s2 + s3_a + s3_b + s4 - } - Version::Micro(_) => self.compute_light_side_penalty_score(), - } - } -} - -#[cfg(test)] -mod penalty_tests { - use crate::canvas::{Canvas, MaskPattern}; - use crate::types::{Color, EcLevel, Version}; - - fn create_test_canvas() -> Canvas { - let mut c = Canvas::new(Version::Normal(1), EcLevel::Q); - c.draw_all_functional_patterns(); - c.draw_data( - b"\x20\x5b\x0b\x78\xd1\x72\xdc\x4d\x43\x40\xec\x11\x00", - b"\xa8\x48\x16\x52\xd9\x36\x9c\x00\x2e\x0f\xb4\x7a\x10", - ); - c.apply_mask(MaskPattern::Checkerboard); - c - } - - #[test] - fn check_penalty_canvas() { - let c = create_test_canvas(); - assert_eq!( - &*c.to_debug_str(), - "\n\ - #######.##....#######\n\ - #.....#.#..#..#.....#\n\ - #.###.#.#..##.#.###.#\n\ - #.###.#.#.....#.###.#\n\ - #.###.#.#.#...#.###.#\n\ - #.....#...#...#.....#\n\ - #######.#.#.#.#######\n\ - ........#............\n\ - .##.#.##....#.#.#####\n\ - .#......####....#...#\n\ - ..##.###.##...#.##...\n\ - .##.##.#..##.#.#.###.\n\ - #...#.#.#.###.###.#.#\n\ - ........##.#..#...#.#\n\ - #######.#.#....#.##..\n\ - #.....#..#.##.##.#...\n\ - #.###.#.#.#...#######\n\ - #.###.#..#.#.#.#...#.\n\ - #.###.#.#...####.#..#\n\ - #.....#.#.##.#...#.##\n\ - #######.....####....#" - ); - } - - #[test] - fn test_penalty_score_adjacent() { - let c = create_test_canvas(); - assert_eq!(c.compute_adjacent_penalty_score(true), 88); - assert_eq!(c.compute_adjacent_penalty_score(false), 92); - } - - #[test] - fn test_penalty_score_block() { - let c = create_test_canvas(); - assert_eq!(c.compute_block_penalty_score(), 90); - } - - #[test] - fn test_penalty_score_finder() { - let c = create_test_canvas(); - assert_eq!(c.compute_finder_penalty_score(true), 0); - assert_eq!(c.compute_finder_penalty_score(false), 40); - } - - #[test] - fn test_penalty_score_balance() { - let c = create_test_canvas(); - assert_eq!(c.compute_balance_penalty_score(), 2); - } - - #[test] - fn test_penalty_score_light_sides() { - static HORIZONTAL_SIDE: [Color; 17] = [ - Color::Dark, - Color::Light, - Color::Light, - Color::Dark, - Color::Dark, - Color::Dark, - Color::Light, - Color::Light, - Color::Dark, - Color::Light, - Color::Dark, - Color::Light, - Color::Light, - Color::Dark, - Color::Light, - Color::Light, - Color::Light, - ]; - static VERTICAL_SIDE: [Color; 17] = [ - Color::Dark, - Color::Dark, - Color::Dark, - Color::Light, - Color::Light, - Color::Dark, - Color::Dark, - Color::Light, - Color::Dark, - Color::Light, - Color::Dark, - Color::Light, - Color::Dark, - Color::Light, - Color::Light, - Color::Dark, - Color::Light, - ]; - - let mut c = Canvas::new(Version::Micro(4), EcLevel::Q); - for i in 0_i16..17 { - c.put(i, -1, HORIZONTAL_SIDE[i as usize]); - c.put(-1, i, VERTICAL_SIDE[i as usize]); - } - - assert_eq!(c.compute_light_side_penalty_score(), 168); - } -} - -//}}} -//------------------------------------------------------------------------------ -//{{{ Select mask with lowest penalty score - -static ALL_PATTERNS_QR: [MaskPattern; 8] = [ - MaskPattern::Checkerboard, - MaskPattern::HorizontalLines, - MaskPattern::VerticalLines, - MaskPattern::DiagonalLines, - MaskPattern::LargeCheckerboard, - MaskPattern::Fields, - MaskPattern::Diamonds, - MaskPattern::Meadow, -]; - -static ALL_PATTERNS_MICRO_QR: [MaskPattern; 4] = - [MaskPattern::HorizontalLines, MaskPattern::LargeCheckerboard, MaskPattern::Diamonds, MaskPattern::Meadow]; - -impl Canvas { - /// Construct a new canvas and apply the best masking that gives the lowest - /// penalty score. - pub fn apply_best_mask(&self) -> Self { - match self.version { - Version::Normal(_) => ALL_PATTERNS_QR.iter(), - Version::Micro(_) => ALL_PATTERNS_MICRO_QR.iter(), - } - .map(|ptn| { - let mut c = self.clone(); - c.apply_mask(*ptn); - c - }) - .min_by_key(Self::compute_total_penalty_scores) - .expect("at least one pattern") - } - - /// Convert the modules into a vector of booleans. - #[deprecated(since = "0.4.0", note = "use `into_colors()` instead")] - pub fn to_bools(&self) -> Vec { - self.modules.iter().map(|m| m.is_dark()).collect() - } - - /// Convert the modules into a vector of colors. - pub fn into_colors(self) -> Vec { - self.modules.into_iter().map(Color::from).collect() - } -} - -//}}} -//------------------------------------------------------------------------------ diff --git a/qrcode-rust/src/cast.rs b/qrcode-rust/src/cast.rs deleted file mode 100644 index a4b19547..00000000 --- a/qrcode-rust/src/cast.rs +++ /dev/null @@ -1,87 +0,0 @@ -use core::fmt::Display; - -pub trait Truncate { - fn truncate_as_u8(self) -> u8; -} - -impl Truncate for u16 { - #[allow(clippy::cast_possible_truncation)] - fn truncate_as_u8(self) -> u8 { - (self & 0xff) as u8 - } -} - -pub trait As { - fn as_u16(self) -> u16; - fn as_i16(self) -> i16; - fn as_u32(self) -> u32; - fn as_usize(self) -> usize; - fn as_isize(self) -> isize; -} - -trait ExpectOrOverflow { - type Output; - fn expect_or_overflow(self, value: D, ty: &str) -> Self::Output; -} - -impl ExpectOrOverflow for Option { - type Output = T; - fn expect_or_overflow(self, value: D, ty: &str) -> Self::Output { - match self { - Some(v) => v, - None => panic!("{} overflows {}", value, ty), - } - } -} - -macro_rules! impl_as { - ($ty:ty) => { - #[allow(unconditional_recursion)] // idk why - #[cfg(debug_assertions)] - impl As for $ty { - fn as_u16(self) -> u16 { - self.as_u16() - } - - fn as_i16(self) -> i16 { - self.as_i16() - } - - fn as_u32(self) -> u32 { - self.as_u32() - } - - fn as_usize(self) -> usize { - self.as_usize() - } - - fn as_isize(self) -> isize { - self.as_isize() - } - } - - #[cfg(not(debug_assertions))] - impl As for $ty { - fn as_u16(self) -> u16 { - self as u16 - } - fn as_i16(self) -> i16 { - self as i16 - } - fn as_u32(self) -> u32 { - self as u32 - } - fn as_usize(self) -> usize { - self as usize - } - fn as_isize(self) -> isize { - self as isize - } - } - }; -} - -impl_as!(i16); -impl_as!(u32); -impl_as!(usize); -impl_as!(isize); diff --git a/qrcode-rust/src/ec.rs b/qrcode-rust/src/ec.rs deleted file mode 100644 index 7903abbe..00000000 --- a/qrcode-rust/src/ec.rs +++ /dev/null @@ -1,488 +0,0 @@ -//! The `ec` module applies the Reed-Solomon error correction codes. - -use core::ops::Deref; - -use alloc::vec::Vec; - -use crate::types::{EcLevel, QrResult, Version}; - -//------------------------------------------------------------------------------ -//{{{ Error correction primitive - -/// Creates the error correction code in N bytes. -/// -/// This method only supports computing the error-correction code up to -/// 69 bytes. Longer blocks will result in task panic. -/// -/// This method treats the data as a polynomial of the form -/// (a\[0\] xm+n + a\[1\] xm+n-1 + … + a\[m\] xn) -/// in GF(28), and then computes the polynomial modulus with a -/// generator polynomial of degree N. -pub fn create_error_correction_code(data: &[u8], ec_code_size: usize) -> Vec { - let data_len = data.len(); - let log_den = GENERATOR_POLYNOMIALS[ec_code_size]; - - let mut res = data.to_vec(); - res.resize(ec_code_size + data_len, 0); - - // rust-lang-nursery/rust-clippy#2213 - for i in 0..data_len { - let lead_coeff = res[i] as usize; - if lead_coeff == 0 { - continue; - } - - let log_lead_coeff = usize::from(LOG_TABLE[lead_coeff]); - for (u, v) in res[i + 1..].iter_mut().zip(log_den.iter()) { - *u ^= EXP_TABLE[(usize::from(*v) + log_lead_coeff) % 255]; - } - } - - res.split_off(data_len) -} - -#[cfg(test)] -mod ec_tests { - use crate::ec::create_error_correction_code; - - #[test] - fn test_poly_mod_1() { - let res = create_error_correction_code(b" [\x0bx\xd1r\xdcMC@\xec\x11\xec\x11\xec\x11", 10); - assert_eq!(&*res, b"\xc4#'w\xeb\xd7\xe7\xe2]\x17"); - } - - #[test] - fn test_poly_mod_2() { - let res = create_error_correction_code(b" [\x0bx\xd1r\xdcMC@\xec\x11\xec", 13); - assert_eq!(&*res, b"\xa8H\x16R\xd96\x9c\x00.\x0f\xb4z\x10"); - } - - #[test] - fn test_poly_mod_3() { - let res = create_error_correction_code(b"CUF\x86W&U\xc2w2\x06\x12\x06g&", 18); - assert_eq!(&*res, b"\xd5\xc7\x0b-s\xf7\xf1\xdf\xe5\xf8\x9au\x9aoV\xa1o'"); - } -} - -//}}} -//------------------------------------------------------------------------------ -//{{{ Interleave support - -/// This method interleaves a vector of slices into a single vector. -/// -/// It will first insert all the first elements of the slices in `blocks`, then -/// all the second elements, then all the third elements, and so on. -/// -/// The longest slice must be at the last of `blocks`, and `blocks` must not be -/// empty. -fn interleave>(blocks: &[V]) -> Vec { - let last_block_len = blocks.last().expect("non-empty blocks").len(); - let mut res = Vec::with_capacity(last_block_len * blocks.len()); - for i in 0..last_block_len { - for t in blocks { - if i < t.len() { - res.push(t[i]); - } - } - } - res -} - -#[test] -fn test_interleave() { - let res = interleave(&[&b"1234"[..], b"5678", b"abcdef", b"ghijkl"]); - assert_eq!(&*res, b"15ag26bh37ci48djekfl"); -} - -//}}} -//------------------------------------------------------------------------------ -//{{{ QR code error correction - -/// Constructs data and error correction codewords ready to be put in the QR -/// code matrix. -/// -/// # Errors -/// -/// Returns `Err(QrError::InvalidVersion)` if it is not valid to use the -/// `ec_level` for the given version (e.g. `Version::Micro(1)` with -/// `EcLevel::H`). -pub fn construct_codewords(rawbits: &[u8], version: Version, ec_level: EcLevel) -> QrResult<(Vec, Vec)> { - let (block_1_size, block_1_count, block_2_size, block_2_count) = version.fetch(ec_level, &DATA_BYTES_PER_BLOCK)?; - - let blocks_count = block_1_count + block_2_count; - let block_1_end = block_1_size * block_1_count; - let total_size = block_1_end + block_2_size * block_2_count; - - debug_assert_eq!(rawbits.len(), total_size); - - // Divide the data into blocks. - let mut blocks = Vec::with_capacity(blocks_count); - blocks.extend(rawbits[..block_1_end].chunks(block_1_size)); - if block_2_size > 0 { - blocks.extend(rawbits[block_1_end..].chunks(block_2_size)); - } - - // Generate EC codes. - let ec_bytes = version.fetch(ec_level, &EC_BYTES_PER_BLOCK)?; - let ec_codes = blocks.iter().map(|block| create_error_correction_code(block, ec_bytes)).collect::>>(); - - let blocks_vec = interleave(&blocks); - let ec_vec = interleave(&ec_codes); - - Ok((blocks_vec, ec_vec)) -} - -#[cfg(test)] -mod construct_codewords_test { - use crate::ec::construct_codewords; - use crate::types::{EcLevel, Version}; - - #[test] - fn test_add_ec_simple() { - let msg = b" [\x0bx\xd1r\xdcMC@\xec\x11\xec\x11\xec\x11"; - let (blocks_vec, ec_vec) = construct_codewords(msg, Version::Normal(1), EcLevel::M).unwrap(); - assert_eq!(&*blocks_vec, msg); - assert_eq!(&*ec_vec, b"\xc4#'w\xeb\xd7\xe7\xe2]\x17"); - } - - #[test] - fn test_add_ec_complex() { - let msg = b"CUF\x86W&U\xc2w2\x06\x12\x06g&\xf6\xf6B\x07v\x86\xf2\x07&V\x16\xc6\xc7\x92\x06\ - \xb6\xe6\xf7w2\x07v\x86W&R\x06\x86\x972\x07F\xf7vV\xc2\x06\x972\x10\xec\x11\xec\ - \x11\xec\x11\xec"; - let expected_blocks = b"C\xf6\xb6FU\xf6\xe6\xf7FB\xf7v\x86\x07wVWv2\xc2&\x86\x07\x06U\xf2v\ - \x97\xc2\x07\x862w&W\x102V&\xec\x06\x16R\x11\x12\xc6\x06\xec\x06\ - \xc7\x86\x11g\x92\x97\xec&\x062\x11\x07\xec"; - let expected_ec = b"\xd5W\x94\xeb\xc7\xcct\x9f\x0b`\xb1\x05-<\xd4\xads\xcaL\x18\xf7\xb6\x85\ - \x93\xf1|K;\xdf\x9d\xf2!\xe5\xc8\xeej\xf8\x86L(\x9a\x1b\xc3\xffu\x81\ - \xe6\xac\x9a\xd1\xbdRo\x11\n\x02V\xa3l\x83\xa1\xa3\xf0 ox\xc0\xb2'\x85\ - \x8d\xec"; - - let (blocks_vec, ec_vec) = construct_codewords(msg, Version::Normal(5), EcLevel::Q).unwrap(); - assert_eq!(&*blocks_vec, &expected_blocks[..]); - assert_eq!(&*ec_vec, &expected_ec[..]); - } -} - -//}}} -//------------------------------------------------------------------------------ -//{{{ Number of allowed errors - -/// Computes the maximum allowed number of erratic modules can be introduced to -/// the QR code, before the data becomes truly corrupted. -/// -/// # Errors -/// -/// Returns `Err(QrError::InvalidVersion)` if it is not valid to use the -/// `ec_level` for the given version (e.g. `Version::Micro(1)` with -/// `EcLevel::H`). -pub fn max_allowed_errors(version: Version, ec_level: EcLevel) -> QrResult { - use crate::EcLevel::{L, M}; - use crate::Version::{Micro, Normal}; - - let p = match (version, ec_level) { - (Micro(2), L) | (Normal(1), L) => 3, - (Micro(_), L) | (Normal(2), L) | (Micro(2), M) | (Normal(1), M) => 2, - (Normal(1), _) | (Normal(3), L) => 1, - _ => 0, - }; - - let ec_bytes_per_block = version.fetch(ec_level, &EC_BYTES_PER_BLOCK)?; - let (_, count1, _, count2) = version.fetch(ec_level, &DATA_BYTES_PER_BLOCK)?; - let ec_bytes = (count1 + count2) * ec_bytes_per_block; - - Ok((ec_bytes - p) / 2) -} - -#[cfg(test)] -mod max_allowed_errors_test { - use crate::ec::max_allowed_errors; - use crate::types::{EcLevel, Version}; - - #[test] - fn test_low_versions() { - assert_eq!(Ok(0), max_allowed_errors(Version::Micro(1), EcLevel::L)); - - assert_eq!(Ok(1), max_allowed_errors(Version::Micro(2), EcLevel::L)); - assert_eq!(Ok(2), max_allowed_errors(Version::Micro(2), EcLevel::M)); - - assert_eq!(Ok(2), max_allowed_errors(Version::Micro(3), EcLevel::L)); - assert_eq!(Ok(4), max_allowed_errors(Version::Micro(3), EcLevel::M)); - - assert_eq!(Ok(3), max_allowed_errors(Version::Micro(4), EcLevel::L)); - assert_eq!(Ok(5), max_allowed_errors(Version::Micro(4), EcLevel::M)); - assert_eq!(Ok(7), max_allowed_errors(Version::Micro(4), EcLevel::Q)); - - assert_eq!(Ok(2), max_allowed_errors(Version::Normal(1), EcLevel::L)); - assert_eq!(Ok(4), max_allowed_errors(Version::Normal(1), EcLevel::M)); - assert_eq!(Ok(6), max_allowed_errors(Version::Normal(1), EcLevel::Q)); - assert_eq!(Ok(8), max_allowed_errors(Version::Normal(1), EcLevel::H)); - - assert_eq!(Ok(4), max_allowed_errors(Version::Normal(2), EcLevel::L)); - assert_eq!(Ok(8), max_allowed_errors(Version::Normal(2), EcLevel::M)); - assert_eq!(Ok(11), max_allowed_errors(Version::Normal(2), EcLevel::Q)); - assert_eq!(Ok(14), max_allowed_errors(Version::Normal(2), EcLevel::H)); - - assert_eq!(Ok(7), max_allowed_errors(Version::Normal(3), EcLevel::L)); - assert_eq!(Ok(13), max_allowed_errors(Version::Normal(3), EcLevel::M)); - assert_eq!(Ok(18), max_allowed_errors(Version::Normal(3), EcLevel::Q)); - assert_eq!(Ok(22), max_allowed_errors(Version::Normal(3), EcLevel::H)); - - assert_eq!(Ok(10), max_allowed_errors(Version::Normal(4), EcLevel::L)); - assert_eq!(Ok(18), max_allowed_errors(Version::Normal(4), EcLevel::M)); - assert_eq!(Ok(26), max_allowed_errors(Version::Normal(4), EcLevel::Q)); - assert_eq!(Ok(32), max_allowed_errors(Version::Normal(4), EcLevel::H)); - } - - #[test] - fn test_high_versions() { - assert_eq!(Ok(375), max_allowed_errors(Version::Normal(40), EcLevel::L)); - assert_eq!(Ok(686), max_allowed_errors(Version::Normal(40), EcLevel::M)); - assert_eq!(Ok(1020), max_allowed_errors(Version::Normal(40), EcLevel::Q)); - assert_eq!(Ok(1215), max_allowed_errors(Version::Normal(40), EcLevel::H)); - } -} - -//}}} -//------------------------------------------------------------------------------ -//{{{ Precomputed tables for GF(256). - -/// `EXP_TABLE` encodes the value of 2n in the Galois Field GF(256). -static EXP_TABLE: &[u8] = b"\ -\x01\x02\x04\x08\x10\x20\x40\x80\x1d\x3a\x74\xe8\xcd\x87\x13\x26\ -\x4c\x98\x2d\x5a\xb4\x75\xea\xc9\x8f\x03\x06\x0c\x18\x30\x60\xc0\ -\x9d\x27\x4e\x9c\x25\x4a\x94\x35\x6a\xd4\xb5\x77\xee\xc1\x9f\x23\ -\x46\x8c\x05\x0a\x14\x28\x50\xa0\x5d\xba\x69\xd2\xb9\x6f\xde\xa1\ -\x5f\xbe\x61\xc2\x99\x2f\x5e\xbc\x65\xca\x89\x0f\x1e\x3c\x78\xf0\ -\xfd\xe7\xd3\xbb\x6b\xd6\xb1\x7f\xfe\xe1\xdf\xa3\x5b\xb6\x71\xe2\ -\xd9\xaf\x43\x86\x11\x22\x44\x88\x0d\x1a\x34\x68\xd0\xbd\x67\xce\ -\x81\x1f\x3e\x7c\xf8\xed\xc7\x93\x3b\x76\xec\xc5\x97\x33\x66\xcc\ -\x85\x17\x2e\x5c\xb8\x6d\xda\xa9\x4f\x9e\x21\x42\x84\x15\x2a\x54\ -\xa8\x4d\x9a\x29\x52\xa4\x55\xaa\x49\x92\x39\x72\xe4\xd5\xb7\x73\ -\xe6\xd1\xbf\x63\xc6\x91\x3f\x7e\xfc\xe5\xd7\xb3\x7b\xf6\xf1\xff\ -\xe3\xdb\xab\x4b\x96\x31\x62\xc4\x95\x37\x6e\xdc\xa5\x57\xae\x41\ -\x82\x19\x32\x64\xc8\x8d\x07\x0e\x1c\x38\x70\xe0\xdd\xa7\x53\xa6\ -\x51\xa2\x59\xb2\x79\xf2\xf9\xef\xc3\x9b\x2b\x56\xac\x45\x8a\x09\ -\x12\x24\x48\x90\x3d\x7a\xf4\xf5\xf7\xf3\xfb\xeb\xcb\x8b\x0b\x16\ -\x2c\x58\xb0\x7d\xfa\xe9\xcf\x83\x1b\x36\x6c\xd8\xad\x47\x8e\x01"; - -/// `LOG_TABLE` is the inverse function of `EXP_TABLE`. -static LOG_TABLE: &[u8] = b"\ -\xff\x00\x01\x19\x02\x32\x1a\xc6\x03\xdf\x33\xee\x1b\x68\xc7\x4b\ -\x04\x64\xe0\x0e\x34\x8d\xef\x81\x1c\xc1\x69\xf8\xc8\x08\x4c\x71\ -\x05\x8a\x65\x2f\xe1\x24\x0f\x21\x35\x93\x8e\xda\xf0\x12\x82\x45\ -\x1d\xb5\xc2\x7d\x6a\x27\xf9\xb9\xc9\x9a\x09\x78\x4d\xe4\x72\xa6\ -\x06\xbf\x8b\x62\x66\xdd\x30\xfd\xe2\x98\x25\xb3\x10\x91\x22\x88\ -\x36\xd0\x94\xce\x8f\x96\xdb\xbd\xf1\xd2\x13\x5c\x83\x38\x46\x40\ -\x1e\x42\xb6\xa3\xc3\x48\x7e\x6e\x6b\x3a\x28\x54\xfa\x85\xba\x3d\ -\xca\x5e\x9b\x9f\x0a\x15\x79\x2b\x4e\xd4\xe5\xac\x73\xf3\xa7\x57\ -\x07\x70\xc0\xf7\x8c\x80\x63\x0d\x67\x4a\xde\xed\x31\xc5\xfe\x18\ -\xe3\xa5\x99\x77\x26\xb8\xb4\x7c\x11\x44\x92\xd9\x23\x20\x89\x2e\ -\x37\x3f\xd1\x5b\x95\xbc\xcf\xcd\x90\x87\x97\xb2\xdc\xfc\xbe\x61\ -\xf2\x56\xd3\xab\x14\x2a\x5d\x9e\x84\x3c\x39\x53\x47\x6d\x41\xa2\ -\x1f\x2d\x43\xd8\xb7\x7b\xa4\x76\xc4\x17\x49\xec\x7f\x0c\x6f\xf6\ -\x6c\xa1\x3b\x52\x29\x9d\x55\xaa\xfb\x60\x86\xb1\xbb\xcc\x3e\x5a\ -\xcb\x59\x5f\xb0\x9c\xa9\xa0\x51\x0b\xf5\x16\xeb\x7a\x75\x2c\xd7\ -\x4f\xae\xd5\xe9\xe6\xe7\xad\xe8\x74\xd6\xf4\xea\xa8\x50\x58\xaf"; - -/// The generator polynomial list. -/// -/// `GENERATOR_POLYNOMIALS[i]` is the polynomial for `i` error correction code -/// words. Each entry encodes the log coefficients of the expanded polynomial -/// (x − 20)(x − 21)…(x − 2i-1). Each entry is -/// used as the denominator for polynomial division to obtain the modulus which -/// is the Reed-Solomon error correction code. -/// -/// A partial list can be found from ISO/IEC 18004:2006 Annex A. -#[rustfmt::skip] -// ^ this attribute is currently useless, see rust-lang-nursery/rustfmt#1080 and 1298 -static GENERATOR_POLYNOMIALS: [&[u8]; 70] = [ - b"", - b"\x00", - b"\x19\x01", - b"\xc6\xc7\x03", - b"\x4b\xf9\x4e\x06", - b"\x71\xa4\xa6\x77\x0a", - b"\xa6\x00\x86\x05\xb0\x0f", - b"\x57\xe5\x92\x95\xee\x66\x15", - b"\xaf\xee\xd0\xf9\xd7\xfc\xc4\x1c", - b"\x5f\xf6\x89\xe7\xeb\x95\x0b\x7b\x24", - b"\xfb\x43\x2e\x3d\x76\x46\x40\x5e\x20\x2d", - b"\xdc\xc0\x5b\xc2\xac\xb1\xd1\x74\xe3\x0a\x37", - b"\x66\x2b\x62\x79\xbb\x71\xc6\x8f\x83\x57\x9d\x42", - b"\x4a\x98\xb0\x64\x56\x64\x6a\x68\x82\xda\xce\x8c\x4e", - b"\xc7\xf9\x9b\x30\xbe\x7c\xda\x89\xd8\x57\xcf\x3b\x16\x5b", - b"\x08\xb7\x3d\x5b\xca\x25\x33\x3a\x3a\xed\x8c\x7c\x05\x63\x69", - b"\x78\x68\x6b\x6d\x66\xa1\x4c\x03\x5b\xbf\x93\xa9\xb6\xc2\xe1\x78", - b"\x2b\x8b\xce\x4e\x2b\xef\x7b\xce\xd6\x93\x18\x63\x96\x27\xf3\xa3\x88", - b"\xd7\xea\x9e\x5e\xb8\x61\x76\xaa\x4f\xbb\x98\x94\xfc\xb3\x05\x62\x60\x99", - b"\x43\x03\x69\x99\x34\x5a\x53\x11\x96\x9f\x2c\x80\x99\x85\xfc\xde\x8a\xdc\xab", - b"\x11\x3c\x4f\x32\x3d\xa3\x1a\xbb\xca\xb4\xdd\xe1\x53\xef\x9c\xa4\xd4\xd4\xbc\xbe", - b"\xf0\xe9\x68\xf7\xb5\x8c\x43\x62\x55\xc8\xd2\x73\x94\x89\xe6\x24\x7a\xfe\x94\xaf\xd2", - b"\xd2\xab\xf7\xf2\x5d\xe6\x0e\x6d\xdd\x35\xc8\x4a\x08\xac\x62\x50\xdb\x86\xa0\x69\xa5\xe7", - b"\xab\x66\x92\x5b\x31\x67\x41\x11\xc1\x96\x0e\x19\xb7\xf8\x5e\xa4\xe0\xc0\x01\x4e\x38\x93\xfd", - b"\xe5\x79\x87\x30\xd3\x75\xfb\x7e\x9f\xb4\xa9\x98\xc0\xe2\xe4\xda\x6f\x00\x75\xe8\x57\x60\xe3\x15", - b"\xe7\xb5\x9c\x27\xaa\x1a\x0c\x3b\x0f\x94\xc9\x36\x42\xed\xd0\x63\xa7\x90\xb6\x5f\xf3\x81\xb2\xfc\x2d", - b"\xad\x7d\x9e\x02\x67\xb6\x76\x11\x91\xc9\x6f\x1c\xa5\x35\xa1\x15\xf5\x8e\x0d\x66\x30\xe3\x99\x91\xda\x46", - b"\x4f\xe4\x08\xa5\xe3\x15\xb4\x1d\x09\xed\x46\x63\x2d\x3a\x8a\x87\x49\x7e\xac\x5e\xd8\xc1\x9d\x1a\x11\x95\x60", - b"\xa8\xdf\xc8\x68\xe0\xea\x6c\xb4\x6e\xbe\xc3\x93\xcd\x1b\xe8\xc9\x15\x2b\xf5\x57\x2a\xc3\xd4\x77\xf2\x25\x09\x7b", - b"\x9c\x2d\xb7\x1d\x97\xdb\x36\x60\xf9\x18\x88\x05\xf1\xaf\xbd\x1c\x4b\xea\x96\x94\x17\x09\xca\xa2\x44\xfa\x8c\x18\x97", - b"\x29\xad\x91\x98\xd8\x1f\xb3\xb6\x32\x30\x6e\x56\xef\x60\xde\x7d\x2a\xad\xe2\xc1\xe0\x82\x9c\x25\xfb\xd8\xee\x28\xc0\xb4", - b"\x14\x25\xfc\x5d\x3f\x4b\xe1\x1f\x73\x53\x71\x27\x2c\x49\x7a\x89\x76\x77\x90\xf8\xf8\x37\x01\xe1\x69\x7b\xb7\x75\xbb\xc8\xd2", - b"\x0a\x06\x6a\xbe\xf9\xa7\x04\x43\xd1\x8a\x8a\x20\xf2\x7b\x59\x1b\x78\xb9\x50\x9c\x26\x45\xab\x3c\x1c\xde\x50\x34\xfe\xb9\xdc\xf1", - b"\xf5\xe7\x37\x18\x47\x4e\x4c\x51\xe1\xd4\xad\x25\xd7\x2e\x77\xe5\xf5\xa7\x7e\x48\xb5\x5e\xa5\xd2\x62\x7d\x9f\xb8\xa9\xe8\xb9\xe7\x12", - b"\x6f\x4d\x92\x5e\x1a\x15\x6c\x13\x69\x5e\x71\xc1\x56\x8c\xa3\x7d\x3a\x9e\xe5\xef\xda\x67\x38\x46\x72\x3d\xb7\x81\xa7\x0d\x62\x3e\x81\x33", - b"\x07\x5e\x8f\x51\xf7\x7f\xca\xca\xc2\x7d\x92\x1d\x8a\xa2\x99\x41\x69\x7a\x74\xee\x1a\x24\xd8\x70\x7d\xe4\x0f\x31\x08\xa2\x1e\x7e\x6f\x3a\x55", - b"\xc8\xb7\x62\x10\xac\x1f\xf6\xea\x3c\x98\x73\x00\xa7\x98\x71\xf8\xee\x6b\x12\x3f\xda\x25\x57\xd2\x69\xb1\x78\x4a\x79\xc4\x75\xfb\x71\xe9\x1e\x78", - b"\x9a\x4b\x8d\xb4\x3d\xa5\x68\xe8\x2e\xe3\x60\xb2\x5c\x87\x39\xa2\x78\xc2\xd4\xae\xfc\xb7\x2a\x23\x9d\x6f\x17\x85\x64\x08\x69\x25\xc0\xbd\x9f\x13\x9c", - b"\x9f\x22\x26\xe4\xe6\x3b\xf3\x5f\x31\xda\xb0\xa4\x14\x41\x2d\x6f\x27\x51\x31\x76\x71\xde\xc1\xfa\xf2\xa8\xd9\x29\xa4\xf7\xb1\x1e\xee\x12\x78\x99\x3c\xc1", - b"\x51\xd8\xae\x2f\xc8\x96\x3b\x9c\x59\x8f\x59\xa6\xb7\xaa\x98\x15\xa5\xb1\x71\x84\xea\x05\x9a\x44\x7c\xaf\xc4\x9d\xf9\xe9\x53\x18\x99\xf1\x7e\x24\x74\x13\xe7", - b"\x3b\x74\x4f\xa1\xfc\x62\x80\xcd\x80\xa1\xf7\x39\xa3\x38\xeb\x6a\x35\x1a\xbb\xae\xe2\x68\xaa\x07\xaf\x23\xb5\x72\x58\x29\x2f\xa3\x7d\x86\x48\x14\xe8\x35\x23\x0f", - b"\x84\xa7\x34\x8b\xb8\xdf\x95\x5c\xfa\x12\x53\x21\x7f\x6d\xc2\x07\xd3\xf2\x6d\x42\x56\xa9\x57\x60\xbb\x9f\x72\xac\x76\xd0\xb7\xc8\x52\xb3\x26\x27\x22\xf2\x8e\x93\x37", - b"\xfa\x67\xdd\xe6\x19\x12\x89\xe7\x00\x03\x3a\xf2\xdd\xbf\x6e\x54\xe6\x08\xbc\x6a\x60\x93\x0f\x83\x8b\x22\x65\xdf\x27\x65\xd5\xc7\xed\xfe\xc9\x7b\xab\xa2\xc2\x75\x32\x60", - b"\x60\x43\x03\xf5\xd9\xd7\x21\x41\xf0\x6d\x90\x3f\x15\x83\x26\x65\x99\x80\x37\x1f\xed\x03\x5e\xa0\x14\x57\x4d\x38\xbf\x7b\xcf\x4b\x52\x00\x7a\x84\x65\x91\xd7\x0f\x79\xc0\x8a", - b"\xbe\x07\x3d\x79\x47\xf6\x45\x37\xa8\xbc\x59\xf3\xbf\x19\x48\x7b\x09\x91\x0e\xf7\x01\xee\x2c\x4e\x8f\x3e\xe0\x7e\x76\x72\x44\xa3\x34\xc2\xd9\x93\xcc\xa9\x25\x82\x71\x66\x49\xb5", - b"\x06\xac\x48\xfa\x12\xab\xab\xa2\xe5\xbb\xef\x04\xbb\x0b\x25\xe4\x66\x48\x66\x16\x21\x49\x5f\x63\x84\x01\x0f\x59\x04\x70\x82\x5f\xd3\xeb\xe3\x3a\x23\x58\x84\x17\x2c\xa5\x36\xbb\xe1", - b"\x70\x5e\x58\x70\xfd\xe0\xca\x73\xbb\x63\x59\x05\x36\x71\x81\x2c\x3a\x10\x87\xd8\xa9\xd3\x24\x01\x04\x60\x3c\xf1\x49\x68\xea\x08\xf9\xf5\x77\xae\x34\x19\x9d\xe0\x2b\xca\xdf\x13\x52\x0f", - b"\x4c\xa4\xe5\x5c\x4f\xa8\xdb\x6e\x68\x15\xdc\x4a\x13\xc7\xc3\x64\x5d\xbf\x2b\xd5\x48\x38\x8a\xa1\x7d\xbb\x77\xfa\xbd\x89\xbe\x4c\x7e\xf7\x5d\x1e\x84\x06\x3a\xd5\xd0\xa5\xe0\x98\x85\x5b\x3d", - b"\xe4\x19\xc4\x82\xd3\x92\x3c\x18\xfb\x5a\x27\x66\xf0\x3d\xb2\x3f\x2e\x7b\x73\x12\xdd\x6f\x87\xa0\xb6\xcd\x6b\xce\x5f\x96\x78\xb8\x5b\x15\xf7\x9c\x8c\xee\xbf\x0b\x5e\xe3\x54\x32\xa3\x27\x22\x6c", - b"\xac\x79\x01\x29\xc1\xde\xed\x40\x6d\xb5\x34\x78\xd4\xe2\xef\xf5\xd0\x14\xf6\x22\xe1\xcc\x86\x65\x7d\xce\x45\x8a\xfa\x00\x4d\x3a\x8f\xb9\xdc\xfe\xd2\xbe\x70\x58\x5b\x39\x5a\x6d\x05\x0d\xb5\x19\x9c", - b"\xe8\x7d\x9d\xa1\xa4\x09\x76\x2e\xd1\x63\xcb\xc1\x23\x03\xd1\x6f\xc3\xf2\xcb\xe1\x2e\x0d\x20\xa0\x7e\xd1\x82\xa0\xf2\xd7\xf2\x4b\x4d\x2a\xbd\x20\x71\x41\x7c\x45\xe4\x72\xeb\xaf\x7c\xaa\xd7\xe8\x85\xcd", - b"\xd5\xa6\x8e\x2b\x0a\xd8\x8d\xa3\xac\xb4\x66\x46\x59\x3e\xde\x3e\x2a\xd2\x97\xa3\xda\x46\x4d\x27\xa6\xbf\x72\xca\xf5\xbc\xb7\xdd\x4b\xd4\x1b\xed\x7f\xcc\xeb\x3e\xbe\xe8\x12\x2e\xab\x0f\x62\xf7\x42\xa3\x00", - b"\x74\x32\x56\xba\x32\xdc\xfb\x59\xc0\x2e\x56\x7f\x7c\x13\xb8\xe9\x97\xd7\x16\x0e\x3b\x91\x25\xf2\xcb\x86\xfe\x59\xbe\x5e\x3b\x41\x7c\x71\x64\xe9\xeb\x79\x16\x4c\x56\x61\x27\xf2\xc8\xdc\x65\x21\xef\xfe\x74\x33", - b"\x7a\xd6\xe7\x88\xc7\x0b\x06\xcd\x7c\x48\xd5\x75\xbb\x3c\x93\xc9\x49\x4b\x21\x92\xab\xf7\x76\xd0\x9d\xb1\xcb\xeb\x53\x2d\xe2\xca\xe5\xa8\x07\x39\xed\xeb\xc8\x7c\x6a\xfe\xa5\x0e\x93\x00\x39\x2a\x1f\xb2\xd5\xad\x67", - b"\xb7\x1a\xc9\x57\xd2\xdd\x71\x15\x2e\x41\x2d\x32\xee\xb8\xf9\xe1\x66\x3a\xd1\xda\x6d\xa5\x1a\x5f\xb8\xc0\x34\xf5\x23\xfe\xee\xaf\xac\x4f\x7b\x19\x7a\x2b\x78\x6c\xd7\x50\x80\xc9\xeb\x08\x99\x3b\x65\x1f\xc6\x4c\x1f\x9c", - b"\x26\xc5\x7b\xa7\x10\x57\xb2\xee\xe3\x61\x94\xf7\x1a\x5a\xe4\xb6\xec\xc5\x2f\xf9\x24\xd5\x36\x71\xb5\x4a\xb1\xcc\x9b\x3d\x2f\x2a\x00\x84\x90\xfb\xc8\x26\x26\x8a\x36\x2c\x40\x13\x16\xce\x10\x0a\xe4\xd3\xa1\xab\x2c\xc2\xd2", - b"\x6a\x78\x6b\x9d\xa4\xd8\x70\x74\x02\x5b\xf8\xa3\x24\xc9\xca\xe5\x06\x90\xfe\x9b\x87\xd0\xaa\xd1\x0c\x8b\x7f\x8e\xb6\xf9\xb1\xae\xbe\x1c\x0a\x55\xef\xb8\x65\x7c\x98\xce\x60\x17\xa3\x3d\x1b\xc4\xf7\x97\x9a\xca\xcf\x14\x3d\x0a", - b"\x3a\x8c\xed\x5d\x6a\x3d\xc1\x02\x57\x49\xc2\xd7\x9f\xa3\x0a\x9b\x05\x79\x99\x3b\xf8\x04\x75\x16\x3c\xb1\x90\x2c\x48\xe4\x3e\x01\x13\xaa\x71\x9e\x19\xaf\xc7\x8b\x5a\x01\xd2\x07\x77\x9a\x59\x9f\x82\x7a\x2e\x93\xbe\x87\x5e\x44\x42", - b"\x52\x74\x1a\xf7\x42\x1b\x3e\x6b\xfc\xb6\xc8\xb9\xeb\x37\xfb\xf2\xd2\x90\x9a\xed\xb0\x8d\xc0\xf8\x98\xf9\xce\x55\xfd\x8e\x41\xa5\x7d\x17\x18\x1e\x7a\xf0\xd6\x06\x81\xda\x1d\x91\x7f\x86\xce\xf5\x75\x1d\x29\x3f\x9f\x8e\xe9\x7d\x94\x7b", - b"\x39\x73\xe8\x0b\xc3\xd9\x03\xce\x4d\x43\x1d\xa6\xb4\x6a\x76\xcb\x11\x45\x98\xd5\x4a\x2c\x31\x2b\x62\x3d\xfd\x7a\x0e\x2b\xd1\x8f\x09\x68\x6b\xab\xe0\x39\xfe\xfb\xe2\xe8\xdd\xc2\xf0\x75\xa1\x52\xb2\xf6\xb2\x21\x32\x56\xd7\xef\xb4\xb4\xb5", - b"\x6b\x8c\x1a\x0c\x09\x8d\xf3\xc5\xe2\xc5\xdb\x2d\xd3\x65\xdb\x78\x1c\xb5\x7f\x06\x64\xf7\x02\xcd\xc6\x39\x73\xdb\x65\x6d\xa0\x52\x25\x26\xee\x31\xa0\xd1\x79\x56\x0b\x7c\x1e\xb5\x54\x19\xc2\x57\x41\x66\xbe\xdc\x46\x1b\xd1\x10\x59\x07\x21\xf0", - b"\xa1\xf4\x69\x73\x40\x09\xdd\xec\x10\x91\x94\x22\x90\xba\x0d\x14\xfe\xf6\x26\x23\xca\x48\x04\xd4\x9f\xd3\xa5\x87\xfc\xfa\x19\x57\x1e\x78\xe2\xea\x5c\xc7\x48\x07\x9b\xda\xe7\x2c\x7d\xb2\x9c\xae\x7c\x2b\x64\x1f\x38\x65\xcc\x40\xaf\xe1\xa9\x92\x2d", - b"\x41\xca\x71\x62\x47\xdf\xf8\x76\xd6\x5e\x00\x7a\x25\x17\x02\xe4\x3a\x79\x07\x69\x87\x4e\xf3\x76\x46\x4c\xdf\x59\x48\x32\x46\x6f\xc2\x11\xd4\x7e\xb5\x23\xdd\x75\xeb\x0b\xe5\x95\x93\x7b\xd5\x28\x73\x06\xc8\x64\x1a\xf6\xb6\xda\x7f\xd7\x24\xba\x6e\x6a", - b"\x1e\x47\x24\x47\x13\xc3\xac\x6e\x3d\x02\xa9\xc2\x5a\x88\x3b\xb6\xe7\x91\x66\x27\xaa\xe7\xd6\x43\xc4\xcf\x35\x70\xf6\x5a\x5a\x79\xb7\x92\x4a\x4d\x26\x59\x16\xe7\x37\x38\xf2\x70\xd9\x6e\x7b\x3e\xc9\xd9\x80\xa5\x3c\xb5\x25\xa1\xf6\x84\xf6\x12\x73\x88\xa8", - b"\x2d\x33\xaf\x09\x07\x9e\x9f\x31\x44\x77\x5c\x7b\xb1\xcc\xbb\xfe\xc8\x4e\x8d\x95\x77\x1a\x7f\x35\xa0\x5d\xc7\xd4\x1d\x18\x91\x9c\xd0\x96\xda\xd1\x04\xd8\x5b\x2f\xb8\x92\x2f\x8c\xc3\xc3\x7d\xf2\xee\x3f\x63\x6c\x8c\xe6\xf2\x1f\xcc\x0b\xb2\xf3\xd9\x9c\xd5\xe7", - b"\x89\x9e\xf7\xf0\x25\xee\xd6\x80\x63\xda\x2e\x8a\xc6\x80\x5c\xdb\x6d\x8b\xa6\x19\x42\x43\x0e\x3a\xee\x95\xb1\xc3\xdd\x9a\xab\x30\x50\x0c\x3b\xbe\xe4\x13\x37\xd0\x5c\x70\xe5\x25\x3c\x0a\x2f\x51\x00\xc0\x25\xab\xaf\x93\x80\x49\xa6\x3d\x95\x0c\x18\x5f\x46\x71\x28", - b"\x05\x76\xde\xb4\x88\x88\xa2\x33\x2e\x75\x0d\xd7\x51\x11\x8b\xf7\xc5\xab\x5f\xad\x41\x89\xb2\x44\x6f\x5f\x65\x29\x48\xd6\xa9\xc5\x5f\x07\x2c\x9a\x4d\x6f\xec\x28\x79\x8f\x3f\x57\x50\xfd\xf0\x7e\xd9\x4d\x22\xe8\x6a\x32\xa8\x52\x4c\x92\x43\x6a\xab\x19\x84\x5d\x2d\x69", - b"\xbf\xac\x71\x56\x07\xa6\xf6\xb9\x9b\xfa\x62\x71\x59\x56\xd6\xe1\x9c\xbe\x3a\x21\x90\x43\xb3\xa3\x34\x9a\xe9\x97\x68\xfb\xa0\x7e\xaf\xd0\xe1\x46\xe3\x92\x04\x98\x8b\x67\x19\x6b\x3d\xcc\x9f\xfa\xc1\xe1\x69\xa0\x62\xa7\x02\x35\x10\xf2\x53\xd2\xc4\x67\xf8\x56\xd3\x29\xab", - b"\xf7\x9f\xdf\x21\xe0\x5d\x4d\x46\x5a\xa0\x20\xfe\x2b\x96\x54\x65\xbe\xcd\x85\x34\x3c\xca\xa5\xdc\xcb\x97\x5d\x54\x0f\x54\xfd\xad\xa0\x59\xe3\x34\xc7\x61\x5f\xe7\x34\xb1\x29\x7d\x89\xf1\xa6\xe1\x76\x02\x36\x20\x52\xd7\xaf\xc6\x2b\xee\xeb\x1b\x65\xb8\x7f\x03\x05\x08\xa3\xee", - b"\x69\x49\x44\x01\x1d\xa8\x75\x0e\x58\xd0\x37\x2e\x2a\xd9\x06\x54\xb3\x61\x06\xf0\xc0\xe7\x9e\x40\x76\xa0\xcb\x39\x3d\x6c\xc7\x7c\x41\xbb\xdd\xa7\x27\xb6\x9f\xb4\xf4\xcb\xe4\xfe\x0d\xaf\x3d\x5a\xce\x28\xc7\x5e\x43\x39\x51\xe5\x2e\x7b\x59\x25\x1f\xca\x42\xfa\x23\xaa\xf3\x58\x33", -]; - -//}}} -//------------------------------------------------------------------------------ -//{{{ Tables for error correction sizes - -/// `EC_BYTES_PER_BLOCK` provides the number of codewords (bytes) used for error -/// correction per block in each version. -/// -/// This is a copy of ISO/IEC 18004:2006, §6.5.1, Table 9 (The 4th column divide -/// by the sum of the 6th column). -static EC_BYTES_PER_BLOCK: [[usize; 4]; 44] = [ - // Normal versions. - [7, 10, 13, 17], // 1 - [10, 16, 22, 28], // 2 - [15, 26, 18, 22], // 3 - [20, 18, 26, 16], // 4 - [26, 24, 18, 22], // 5 - [18, 16, 24, 28], // 6 - [20, 18, 18, 26], // 7 - [24, 22, 22, 26], // 8 - [30, 22, 20, 24], // 9 - [18, 26, 24, 28], // 10 - [20, 30, 28, 24], // 11 - [24, 22, 26, 28], // 12 - [26, 22, 24, 22], // 13 - [30, 24, 20, 24], // 14 - [22, 24, 30, 24], // 15 - [24, 28, 24, 30], // 16 - [28, 28, 28, 28], // 17 - [30, 26, 28, 28], // 18 - [28, 26, 26, 26], // 19 - [28, 26, 30, 28], // 20 - [28, 26, 28, 30], // 21 - [28, 28, 30, 24], // 22 - [30, 28, 30, 30], // 23 - [30, 28, 30, 30], // 24 - [26, 28, 30, 30], // 25 - [28, 28, 28, 30], // 26 - [30, 28, 30, 30], // 27 - [30, 28, 30, 30], // 28 - [30, 28, 30, 30], // 29 - [30, 28, 30, 30], // 30 - [30, 28, 30, 30], // 31 - [30, 28, 30, 30], // 32 - [30, 28, 30, 30], // 33 - [30, 28, 30, 30], // 34 - [30, 28, 30, 30], // 35 - [30, 28, 30, 30], // 36 - [30, 28, 30, 30], // 37 - [30, 28, 30, 30], // 38 - [30, 28, 30, 30], // 39 - [30, 28, 30, 30], // 40 - // Micro versions. - [2, 0, 0, 0], // M1 - [5, 6, 0, 0], // M2 - [6, 8, 0, 0], // M3 - [8, 10, 14, 0], // M4 -]; - -/// `DATA_BYTES_PER_BLOCK` provides the number of codewords (bytes) used for -/// real data per block in each version. -/// -/// This is a copy of ISO/IEC 18004:2006, §6.5.1, Table 9 (The value "k" of the -/// 7th column, followed by the 6th column). -/// -/// Every entry is a 4-tuple. Take `DATA_BYTES_PER_BLOCK[39][3] == (15, 20, 16, 61)` -/// as an example, this means in version 40 with correction level H, there are -/// 20 blocks with 15 bytes in size, and 61 blocks with 16 bytes in size. -static DATA_BYTES_PER_BLOCK: [[(usize, usize, usize, usize); 4]; 44] = [ - // Normal versions. - [(19, 1, 0, 0), (16, 1, 0, 0), (13, 1, 0, 0), (9, 1, 0, 0)], // 1 - [(34, 1, 0, 0), (28, 1, 0, 0), (22, 1, 0, 0), (16, 1, 0, 0)], // 2 - [(55, 1, 0, 0), (44, 1, 0, 0), (17, 2, 0, 0), (13, 2, 0, 0)], // 3 - [(80, 1, 0, 0), (32, 2, 0, 0), (24, 2, 0, 0), (9, 4, 0, 0)], // 4 - [(108, 1, 0, 0), (43, 2, 0, 0), (15, 2, 16, 2), (11, 2, 12, 2)], // 5 - [(68, 2, 0, 0), (27, 4, 0, 0), (19, 4, 0, 0), (15, 4, 0, 0)], // 6 - [(78, 2, 0, 0), (31, 4, 0, 0), (14, 2, 15, 4), (13, 4, 14, 1)], // 7 - [(97, 2, 0, 0), (38, 2, 39, 2), (18, 4, 19, 2), (14, 4, 15, 2)], // 8 - [(116, 2, 0, 0), (36, 3, 37, 2), (16, 4, 17, 4), (12, 4, 13, 4)], // 9 - [(68, 2, 69, 2), (43, 4, 44, 1), (19, 6, 20, 2), (15, 6, 16, 2)], // 10 - [(81, 4, 0, 0), (50, 1, 51, 4), (22, 4, 23, 4), (12, 3, 13, 8)], // 11 - [(92, 2, 93, 2), (36, 6, 37, 2), (20, 4, 21, 6), (14, 7, 15, 4)], // 12 - [(107, 4, 0, 0), (37, 8, 38, 1), (20, 8, 21, 4), (11, 12, 12, 4)], // 13 - [(115, 3, 116, 1), (40, 4, 41, 5), (16, 11, 17, 5), (12, 11, 13, 5)], // 14 - [(87, 5, 88, 1), (41, 5, 42, 5), (24, 5, 25, 7), (12, 11, 13, 7)], // 15 - [(98, 5, 99, 1), (45, 7, 46, 3), (19, 15, 20, 2), (15, 3, 16, 13)], // 16 - [(107, 1, 108, 5), (46, 10, 47, 1), (22, 1, 23, 15), (14, 2, 15, 17)], // 17 - [(120, 5, 121, 1), (43, 9, 44, 4), (22, 17, 23, 1), (14, 2, 15, 19)], // 18 - [(113, 3, 114, 4), (44, 3, 45, 11), (21, 17, 22, 4), (13, 9, 14, 16)], // 19 - [(107, 3, 108, 5), (41, 3, 42, 13), (24, 15, 25, 5), (15, 15, 16, 10)], // 20 - [(116, 4, 117, 4), (42, 17, 0, 0), (22, 17, 23, 6), (16, 19, 17, 6)], // 21 - [(111, 2, 112, 7), (46, 17, 0, 0), (24, 7, 25, 16), (13, 34, 0, 0)], // 22 - [(121, 4, 122, 5), (47, 4, 48, 14), (24, 11, 25, 14), (15, 16, 16, 14)], // 23 - [(117, 6, 118, 4), (45, 6, 46, 14), (24, 11, 25, 16), (16, 30, 17, 2)], // 24 - [(106, 8, 107, 4), (47, 8, 48, 13), (24, 7, 25, 22), (15, 22, 16, 13)], // 25 - [(114, 10, 115, 2), (46, 19, 47, 4), (22, 28, 23, 6), (16, 33, 17, 4)], // 26 - [(122, 8, 123, 4), (45, 22, 46, 3), (23, 8, 24, 26), (15, 12, 16, 28)], // 27 - [(117, 3, 118, 10), (45, 3, 46, 23), (24, 4, 25, 31), (15, 11, 16, 31)], // 28 - [(116, 7, 117, 7), (45, 21, 46, 7), (23, 1, 24, 37), (15, 19, 16, 26)], // 29 - [(115, 5, 116, 10), (47, 19, 48, 10), (24, 15, 25, 25), (15, 23, 16, 25)], // 30 - [(115, 13, 116, 3), (46, 2, 47, 29), (24, 42, 25, 1), (15, 23, 16, 28)], // 31 - [(115, 17, 0, 0), (46, 10, 47, 23), (24, 10, 25, 35), (15, 19, 16, 35)], // 32 - [(115, 17, 116, 1), (46, 14, 47, 21), (24, 29, 25, 19), (15, 11, 16, 46)], // 33 - [(115, 13, 116, 6), (46, 14, 47, 23), (24, 44, 25, 7), (16, 59, 17, 1)], // 34 - [(121, 12, 122, 7), (47, 12, 48, 26), (24, 39, 25, 14), (15, 22, 16, 41)], // 35 - [(121, 6, 122, 14), (47, 6, 48, 34), (24, 46, 25, 10), (15, 2, 16, 64)], // 36 - [(122, 17, 123, 4), (46, 29, 47, 14), (24, 49, 25, 10), (15, 24, 16, 46)], // 37 - [(122, 4, 123, 18), (46, 13, 47, 32), (24, 48, 25, 14), (15, 42, 16, 32)], // 38 - [(117, 20, 118, 4), (47, 40, 48, 7), (24, 43, 25, 22), (15, 10, 16, 67)], // 39 - [(118, 19, 119, 6), (47, 18, 48, 31), (24, 34, 25, 34), (15, 20, 16, 61)], // 40 - // Micro versions. - [(3, 1, 0, 0), (0, 0, 0, 0), (0, 0, 0, 0), (0, 0, 0, 0)], // M1 - [(5, 1, 0, 0), (4, 1, 0, 0), (0, 0, 0, 0), (0, 0, 0, 0)], // M2 - [(11, 1, 0, 0), (9, 1, 0, 0), (0, 0, 0, 0), (0, 0, 0, 0)], // M3 - [(16, 1, 0, 0), (14, 1, 0, 0), (10, 1, 0, 0), (0, 0, 0, 0)], // M4 -]; - -//}}} diff --git a/qrcode-rust/src/lib.rs b/qrcode-rust/src/lib.rs deleted file mode 100644 index f7346d94..00000000 --- a/qrcode-rust/src/lib.rs +++ /dev/null @@ -1,382 +0,0 @@ -//! QRCode encoder -//! -//! This crate provides a QR code and Micro QR code encoder for binary data. -//! -//! -//! - -#![no_std] -#![cfg_attr(feature = "image", doc = "```rust")] -#![cfg_attr(not(feature = "image"), doc = "```ignore")] -//! use qrcode::QrCode; -//! use image::Luma; -//! -//! // Encode some data into bits. -//! let code = QrCode::new(b"01234567").unwrap(); -//! -//! // Render the bits into an image. -//! let image = code.render::>().build(); -//! -//! // Save the image. -//! # if cfg!(unix) { -//! image.save("/tmp/qrcode.png").unwrap(); -//! # } -//! -//! // You can also render it into a string. -//! let string = code.render() -//! .light_color(' ') -//! .dark_color('#') -//! .build(); -//! println!("{}", string); -//! ``` - -#![cfg_attr(feature = "bench", feature(test, external_doc))] // Unstable libraries -// #![deny(warnings, clippy::pedantic)] -#![allow( - clippy::must_use_candidate, // This is just annoying. - clippy::use_self, // Rust 1.33 doesn't support Self::EnumVariant, let's try again in 1.37. -)] -#![cfg_attr(feature = "bench", doc(include = "../README.md"))] -// ^ make sure we can test our README.md. - -#[macro_use] -extern crate alloc; - -use core::ops::Index; - -pub mod bits; -pub mod canvas; -mod cast; -pub mod ec; -pub mod optimize; -pub mod render; -pub mod types; - -pub use crate::types::{Color, EcLevel, QrResult, Version}; - -use crate::cast::As; -use crate::render::{Pixel, Renderer}; -use alloc::string::String; -use alloc::vec::Vec; -// use checked_int_cast::CheckedIntCast; - -/// The encoded QR code symbol. -#[derive(Clone)] -pub struct QrCode { - content: Vec, - version: Version, - ec_level: EcLevel, - width: usize, -} - -impl QrCode { - /// Constructs a new QR code which automatically encodes the given data. - /// - /// This method uses the "medium" error correction level and automatically - /// chooses the smallest QR code. - /// - /// use qrcode::QrCode; - /// - /// let code = QrCode::new(b"Some data").unwrap(); - /// - /// # Errors - /// - /// Returns error if the QR code cannot be constructed, e.g. when the data - /// is too long. - pub fn new>(data: D) -> QrResult { - Self::with_error_correction_level(data, EcLevel::M) - } - - /// Constructs a new QR code which automatically encodes the given data at a - /// specific error correction level. - /// - /// This method automatically chooses the smallest QR code. - /// - /// use qrcode::{QrCode, EcLevel}; - /// - /// let code = QrCode::with_error_correction_level(b"Some data", EcLevel::H).unwrap(); - /// - /// # Errors - /// - /// Returns error if the QR code cannot be constructed, e.g. when the data - /// is too long. - pub fn with_error_correction_level>(data: D, ec_level: EcLevel) -> QrResult { - let bits = bits::encode_auto(data.as_ref(), ec_level)?; - Self::with_bits(bits, ec_level) - } - - /// Constructs a new QR code for the given version and error correction - /// level. - /// - /// use qrcode::{QrCode, Version, EcLevel}; - /// - /// let code = QrCode::with_version(b"Some data", Version::Normal(5), EcLevel::M).unwrap(); - /// - /// This method can also be used to generate Micro QR code. - /// - /// use qrcode::{QrCode, Version, EcLevel}; - /// - /// let micro_code = QrCode::with_version(b"123", Version::Micro(1), EcLevel::L).unwrap(); - /// - /// # Errors - /// - /// Returns error if the QR code cannot be constructed, e.g. when the data - /// is too long, or when the version and error correction level are - /// incompatible. - pub fn with_version>(data: D, version: Version, ec_level: EcLevel) -> QrResult { - let mut bits = bits::Bits::new(version); - bits.push_optimal_data(data.as_ref())?; - bits.push_terminator(ec_level)?; - Self::with_bits(bits, ec_level) - } - - /// Constructs a new QR code with encoded bits. - /// - /// Use this method only if there are very special need to manipulate the - /// raw bits before encoding. Some examples are: - /// - /// * Encode data using specific character set with ECI - /// * Use the FNC1 modes - /// * Avoid the optimal segmentation algorithm - /// - /// See the `Bits` structure for detail. - /// - /// #![allow(unused_must_use)] - /// - /// use qrcode::{QrCode, Version, EcLevel}; - /// use qrcode::bits::Bits; - /// - /// let mut bits = Bits::new(Version::Normal(1)); - /// bits.push_eci_designator(9); - /// bits.push_byte_data(b"\xca\xfe\xe4\xe9\xea\xe1\xf2 QR"); - /// bits.push_terminator(EcLevel::L); - /// let qrcode = QrCode::with_bits(bits, EcLevel::L); - /// - /// # Errors - /// - /// Returns error if the QR code cannot be constructed, e.g. when the bits - /// are too long, or when the version and error correction level are - /// incompatible. - pub fn with_bits(bits: bits::Bits, ec_level: EcLevel) -> QrResult { - let version = bits.version(); - let data = bits.into_bytes(); - let (encoded_data, ec_data) = ec::construct_codewords(&data, version, ec_level)?; - let mut canvas = canvas::Canvas::new(version, ec_level); - canvas.draw_all_functional_patterns(); - canvas.draw_data(&encoded_data, &ec_data); - let canvas = canvas.apply_best_mask(); - Ok(Self { content: canvas.into_colors(), version, ec_level, width: version.width().as_usize() }) - } - - /// Gets the version of this QR code. - pub fn version(&self) -> Version { - self.version - } - - /// Gets the error correction level of this QR code. - pub fn error_correction_level(&self) -> EcLevel { - self.ec_level - } - - /// Gets the number of modules per side, i.e. the width of this QR code. - /// - /// The width here does not contain the quiet zone paddings. - pub fn width(&self) -> usize { - self.width - } - - /// Gets the maximum number of allowed erratic modules can be introduced - /// before the data becomes corrupted. Note that errors should not be - /// introduced to functional modules. - pub fn max_allowed_errors(&self) -> usize { - ec::max_allowed_errors(self.version, self.ec_level).expect("invalid version or ec_level") - } - - /// Checks whether a module at coordinate (x, y) is a functional module or - /// not. - pub fn is_functional(&self, x: usize, y: usize) -> bool { - let x: i16 = x.as_i16(); - let y: i16 = y.as_i16(); - canvas::is_functional(self.version, self.version.width(), x, y) - } - - /// Converts the QR code into a human-readable string. This is mainly for - /// debugging only. - pub fn to_debug_str(&self, on_char: char, off_char: char) -> String { - self.render().quiet_zone(false).dark_color(on_char).light_color(off_char).build() - } - - /// Converts the QR code to a vector of booleans. Each entry represents the - /// color of the module, with "true" means dark and "false" means light. - #[deprecated(since = "0.4.0", note = "use `to_colors()` instead")] - pub fn to_vec(&self) -> Vec { - self.content.iter().map(|c| *c != Color::Light).collect() - } - - /// Converts the QR code to a vector of booleans. Each entry represents the - /// color of the module, with "true" means dark and "false" means light. - #[deprecated(since = "0.4.0", note = "use `into_colors()` instead")] - pub fn into_vec(self) -> Vec { - self.content.into_iter().map(|c| c != Color::Light).collect() - } - - /// Converts the QR code to a vector of colors. - pub fn to_colors(&self) -> Vec { - self.content.clone() - } - - /// Converts the QR code to a vector of colors. - pub fn into_colors(self) -> Vec { - self.content - } - - /// Renders the QR code into an image. The result is an image builder, which - /// you may do some additional configuration before copying it into a - /// concrete image. - /// - /// # Examples - /// - #[cfg_attr(feature = "image", doc = " ```rust")] - #[cfg_attr(not(feature = "image"), doc = " ```ignore")] - /// # use qrcode::QrCode; - /// # use image::Rgb; - /// - /// let image = QrCode::new(b"hello").unwrap() - /// .render() - /// .dark_color(Rgb([0, 0, 128])) - /// .light_color(Rgb([224, 224, 224])) // adjust colors - /// .quiet_zone(false) // disable quiet zone (white border) - /// .min_dimensions(300, 300) // sets minimum image size - /// .build(); - /// ``` - /// - /// Note: the `image` crate itself also provides method to rotate the image, - /// or overlay a logo on top of the QR code. - pub fn render(&self) -> Renderer

{ - let quiet_zone = if self.version.is_micro() { 2 } else { 4 }; - Renderer::new(&self.content, self.width, quiet_zone) - } -} - -impl Index<(usize, usize)> for QrCode { - type Output = Color; - - fn index(&self, (x, y): (usize, usize)) -> &Color { - let index = y * self.width + x; - &self.content[index] - } -} - -#[cfg(test)] -mod tests { - use crate::{EcLevel, QrCode, Version}; - - #[test] - fn test_annex_i_qr() { - // This uses the ISO Annex I as test vector. - let code = QrCode::with_version(b"01234567", Version::Normal(1), EcLevel::M).unwrap(); - assert_eq!( - &*code.to_debug_str('#', '.'), - "\ - #######..#.##.#######\n\ - #.....#..####.#.....#\n\ - #.###.#.#.....#.###.#\n\ - #.###.#.##....#.###.#\n\ - #.###.#.#.###.#.###.#\n\ - #.....#.#...#.#.....#\n\ - #######.#.#.#.#######\n\ - ........#..##........\n\ - #.#####..#..#.#####..\n\ - ...#.#.##.#.#..#.##..\n\ - ..#...##.#.#.#..#####\n\ - ....#....#.....####..\n\ - ...######..#.#..#....\n\ - ........#.#####..##..\n\ - #######..##.#.##.....\n\ - #.....#.#.#####...#.#\n\ - #.###.#.#...#..#.##..\n\ - #.###.#.##..#..#.....\n\ - #.###.#.#.##.#..#.#..\n\ - #.....#........##.##.\n\ - #######.####.#..#.#.." - ); - } - - #[test] - fn test_annex_i_micro_qr() { - let code = QrCode::with_version(b"01234567", Version::Micro(2), EcLevel::L).unwrap(); - assert_eq!( - &*code.to_debug_str('#', '.'), - "\ - #######.#.#.#\n\ - #.....#.###.#\n\ - #.###.#..##.#\n\ - #.###.#..####\n\ - #.###.#.###..\n\ - #.....#.#...#\n\ - #######..####\n\ - .........##..\n\ - ##.#....#...#\n\ - .##.#.#.#.#.#\n\ - ###..#######.\n\ - ...#.#....##.\n\ - ###.#..##.###" - ); - } -} - -#[cfg(all(test, feature = "image"))] -mod image_tests { - use crate::{EcLevel, QrCode, Version}; - use image::{load_from_memory, Luma, Rgb}; - - #[test] - fn test_annex_i_qr_as_image() { - let code = QrCode::new(b"01234567").unwrap(); - let image = code.render::>().build(); - let expected = load_from_memory(include_bytes!("test_annex_i_qr_as_image.png")).unwrap().to_luma(); - assert_eq!(image.dimensions(), expected.dimensions()); - assert_eq!(image.into_raw(), expected.into_raw()); - } - - #[test] - fn test_annex_i_micro_qr_as_image() { - let code = QrCode::with_version(b"01234567", Version::Micro(2), EcLevel::L).unwrap(); - let image = code - .render() - .min_dimensions(200, 200) - .dark_color(Rgb([128, 0, 0])) - .light_color(Rgb([255, 255, 128])) - .build(); - let expected = load_from_memory(include_bytes!("test_annex_i_micro_qr_as_image.png")).unwrap().to_rgb(); - assert_eq!(image.dimensions(), expected.dimensions()); - assert_eq!(image.into_raw(), expected.into_raw()); - } -} - -#[cfg(all(test, feature = "svg"))] -mod svg_tests { - use crate::render::svg::Color as SvgColor; - use crate::{EcLevel, QrCode, Version}; - - #[test] - fn test_annex_i_qr_as_svg() { - let code = QrCode::new(b"01234567").unwrap(); - let image = code.render::().build(); - let expected = include_str!("test_annex_i_qr_as_svg.svg"); - assert_eq!(&image, expected); - } - - #[test] - fn test_annex_i_micro_qr_as_svg() { - let code = QrCode::with_version(b"01234567", Version::Micro(2), EcLevel::L).unwrap(); - let image = code - .render() - .min_dimensions(200, 200) - .dark_color(SvgColor("#800000")) - .light_color(SvgColor("#ffff80")) - .build(); - let expected = include_str!("test_annex_i_micro_qr_as_svg.svg"); - assert_eq!(&image, expected); - } -} diff --git a/qrcode-rust/src/main.rs b/qrcode-rust/src/main.rs deleted file mode 100644 index 67946c80..00000000 --- a/qrcode-rust/src/main.rs +++ /dev/null @@ -1,11 +0,0 @@ -use qrcode::{render::unicode, QrCode}; - -fn main() { - let code = QrCode::new("https://www.youtube.com/watch?v=p7YXXieghto").unwrap(); - let image = code - .render::() - .dark_color(unicode::Dense1x2::Light) - .light_color(unicode::Dense1x2::Dark) - .build(); - println!("{}", image); -} diff --git a/qrcode-rust/src/optimize.rs b/qrcode-rust/src/optimize.rs deleted file mode 100644 index 1d3af2cf..00000000 --- a/qrcode-rust/src/optimize.rs +++ /dev/null @@ -1,684 +0,0 @@ -//! Find the optimal data mode sequence to encode a piece of data. -use crate::types::{Mode, Version}; - -use core::slice::Iter; - -#[cfg(feature = "bench")] -extern crate test; - -//------------------------------------------------------------------------------ -//{{{ Segment - -/// A segment of data committed to an encoding mode. -#[derive(PartialEq, Eq, Debug, Copy, Clone)] -pub struct Segment { - /// The encoding mode of the segment of data. - pub mode: Mode, - - /// The start index of the segment. - pub begin: usize, - - /// The end index (exclusive) of the segment. - pub end: usize, -} - -impl Segment { - /// Compute the number of bits (including the size of the mode indicator and - /// length bits) when this segment is encoded. - pub fn encoded_len(&self, version: Version) -> usize { - let byte_size = self.end - self.begin; - let chars_count = if self.mode == Mode::Kanji { byte_size / 2 } else { byte_size }; - - let mode_bits_count = version.mode_bits_count(); - let length_bits_count = self.mode.length_bits_count(version); - let data_bits_count = self.mode.data_bits_count(chars_count); - - mode_bits_count + length_bits_count + data_bits_count - } -} - -//}}} -//------------------------------------------------------------------------------ -//{{{ Parser - -/// This iterator is basically equivalent to -/// -/// ```ignore -/// data.map(|c| ExclCharSet::from_u8(*c)) -/// .chain(Some(ExclCharSet::End).move_iter()) -/// .enumerate() -/// ``` -/// -/// But the type is too hard to write, thus the new type. -/// -struct EcsIter { - base: I, - index: usize, - ended: bool, -} - -impl<'a, I: Iterator> Iterator for EcsIter { - type Item = (usize, ExclCharSet); - - fn next(&mut self) -> Option<(usize, ExclCharSet)> { - if self.ended { - return None; - } - - match self.base.next() { - None => { - self.ended = true; - Some((self.index, ExclCharSet::End)) - } - Some(c) => { - let old_index = self.index; - self.index += 1; - Some((old_index, ExclCharSet::from_u8(*c))) - } - } - } -} - -/// QR code data parser to classify the input into distinct segments. -pub struct Parser<'a> { - ecs_iter: EcsIter>, - state: State, - begin: usize, - pending_single_byte: bool, -} - -impl<'a> Parser<'a> { - /// Creates a new iterator which parse the data into segments that only - /// contains their exclusive subsets. No optimization is done at this point. - /// - /// use qrcode::optimize::{Parser, Segment}; - /// use qrcode::types::Mode::{Alphanumeric, Numeric, Byte}; - /// - /// let parse_res = Parser::new(b"ABC123abcd").collect::>(); - /// assert_eq!(parse_res, vec![Segment { mode: Alphanumeric, begin: 0, end: 3 }, - /// Segment { mode: Numeric, begin: 3, end: 6 }, - /// Segment { mode: Byte, begin: 6, end: 10 }]); - /// - pub fn new(data: &[u8]) -> Parser { - Parser { - ecs_iter: EcsIter { base: data.iter(), index: 0, ended: false }, - state: State::Init, - begin: 0, - pending_single_byte: false, - } - } -} - -impl<'a> Iterator for Parser<'a> { - type Item = Segment; - - fn next(&mut self) -> Option { - if self.pending_single_byte { - self.pending_single_byte = false; - self.begin += 1; - return Some(Segment { mode: Mode::Byte, begin: self.begin - 1, end: self.begin }); - } - - loop { - let (i, ecs) = match self.ecs_iter.next() { - None => return None, - Some(a) => a, - }; - let (next_state, action) = STATE_TRANSITION[self.state as usize + ecs as usize]; - self.state = next_state; - - let old_begin = self.begin; - let push_mode = match action { - Action::Idle => continue, - Action::Numeric => Mode::Numeric, - Action::Alpha => Mode::Alphanumeric, - Action::Byte => Mode::Byte, - Action::Kanji => Mode::Kanji, - Action::KanjiAndSingleByte => { - let next_begin = i - 1; - if self.begin == next_begin { - Mode::Byte - } else { - self.pending_single_byte = true; - self.begin = next_begin; - return Some(Segment { mode: Mode::Kanji, begin: old_begin, end: next_begin }); - } - } - }; - - self.begin = i; - return Some(Segment { mode: push_mode, begin: old_begin, end: i }); - } - } -} - -#[cfg(test)] -mod parse_tests { - use alloc::vec::Vec; - - use crate::optimize::{Parser, Segment}; - use crate::types::Mode; - - fn parse(data: &[u8]) -> Vec { - Parser::new(data).collect() - } - - #[test] - fn test_parse_1() { - let segs = parse(b"01049123451234591597033130128%10ABC123"); - assert_eq!( - segs, - vec![ - Segment { mode: Mode::Numeric, begin: 0, end: 29 }, - Segment { mode: Mode::Alphanumeric, begin: 29, end: 30 }, - Segment { mode: Mode::Numeric, begin: 30, end: 32 }, - Segment { mode: Mode::Alphanumeric, begin: 32, end: 35 }, - Segment { mode: Mode::Numeric, begin: 35, end: 38 }, - ] - ); - } - - #[test] - fn test_parse_shift_jis_example_1() { - let segs = parse(b"\x82\xa0\x81\x41\x41\xb1\x81\xf0"); // "あ、AアÅ" - assert_eq!( - segs, - vec![ - Segment { mode: Mode::Kanji, begin: 0, end: 4 }, - Segment { mode: Mode::Alphanumeric, begin: 4, end: 5 }, - Segment { mode: Mode::Byte, begin: 5, end: 6 }, - Segment { mode: Mode::Kanji, begin: 6, end: 8 }, - ] - ); - } - - #[test] - fn test_parse_utf_8() { - // Mojibake? - let segs = parse(b"\xe3\x81\x82\xe3\x80\x81A\xef\xbd\xb1\xe2\x84\xab"); - assert_eq!( - segs, - vec![ - Segment { mode: Mode::Kanji, begin: 0, end: 4 }, - Segment { mode: Mode::Byte, begin: 4, end: 5 }, - Segment { mode: Mode::Kanji, begin: 5, end: 7 }, - Segment { mode: Mode::Byte, begin: 7, end: 10 }, - Segment { mode: Mode::Kanji, begin: 10, end: 12 }, - Segment { mode: Mode::Byte, begin: 12, end: 13 }, - ] - ); - } - - #[test] - fn test_not_kanji_1() { - let segs = parse(b"\x81\x30"); - assert_eq!( - segs, - vec![Segment { mode: Mode::Byte, begin: 0, end: 1 }, Segment { mode: Mode::Numeric, begin: 1, end: 2 },] - ); - } - - #[test] - fn test_not_kanji_2() { - // Note that it's implementation detail that the byte seq is split into - // two. Perhaps adjust the test to check for this. - let segs = parse(b"\xeb\xc0"); - assert_eq!( - segs, - vec![Segment { mode: Mode::Byte, begin: 0, end: 1 }, Segment { mode: Mode::Byte, begin: 1, end: 2 },] - ); - } - - #[test] - fn test_not_kanji_3() { - let segs = parse(b"\x81\x7f"); - assert_eq!( - segs, - vec![Segment { mode: Mode::Byte, begin: 0, end: 1 }, Segment { mode: Mode::Byte, begin: 1, end: 2 },] - ); - } - - #[test] - fn test_not_kanji_4() { - let segs = parse(b"\x81\x40\x81"); - assert_eq!( - segs, - vec![Segment { mode: Mode::Kanji, begin: 0, end: 2 }, Segment { mode: Mode::Byte, begin: 2, end: 3 },] - ); - } -} - -//}}} -//------------------------------------------------------------------------------ -//{{{ Optimizer - -pub struct Optimizer { - parser: I, - last_segment: Segment, - last_segment_size: usize, - version: Version, - ended: bool, -} - -impl> Optimizer { - /// Optimize the segments by combining adjacent segments when possible. - /// - /// Currently this method uses a greedy algorithm by combining segments from - /// left to right until the new segment is longer than before. This method - /// does *not* use Annex J from the ISO standard. - /// - pub fn new(mut segments: I, version: Version) -> Self { - match segments.next() { - None => Self { - parser: segments, - last_segment: Segment { mode: Mode::Numeric, begin: 0, end: 0 }, - last_segment_size: 0, - version, - ended: true, - }, - Some(segment) => Self { - parser: segments, - last_segment: segment, - last_segment_size: segment.encoded_len(version), - version, - ended: false, - }, - } - } -} - -impl<'a> Parser<'a> { - pub fn optimize(self, version: Version) -> Optimizer> { - Optimizer::new(self, version) - } -} - -impl> Iterator for Optimizer { - type Item = Segment; - - fn next(&mut self) -> Option { - if self.ended { - return None; - } - - loop { - match self.parser.next() { - None => { - self.ended = true; - return Some(self.last_segment); - } - Some(segment) => { - let seg_size = segment.encoded_len(self.version); - - let new_segment = Segment { - mode: self.last_segment.mode.max(segment.mode), - begin: self.last_segment.begin, - end: segment.end, - }; - let new_size = new_segment.encoded_len(self.version); - - if self.last_segment_size + seg_size >= new_size { - self.last_segment = new_segment; - self.last_segment_size = new_size; - } else { - let old_segment = self.last_segment; - self.last_segment = segment; - self.last_segment_size = seg_size; - return Some(old_segment); - } - } - } - } - } -} - -/// Computes the total encoded length of all segments. -pub fn total_encoded_len(segments: &[Segment], version: Version) -> usize { - segments.iter().map(|seg| seg.encoded_len(version)).sum() -} - -#[cfg(test)] -mod optimize_tests { - use alloc::vec::Vec; - - use crate::optimize::{total_encoded_len, Optimizer, Segment}; - use crate::types::{Mode, Version}; - - fn test_optimization_result(given: Vec, expected: Vec, version: Version) { - let prev_len = total_encoded_len(&given, version); - let opt_segs = Optimizer::new(given.iter().copied(), version).collect::>(); - let new_len = total_encoded_len(&opt_segs, version); - if given != opt_segs { - assert!(prev_len > new_len, "{} > {}", prev_len, new_len); - } - assert!( - opt_segs == expected, - "Optimization gave something better: {} < {} ({:?})", - new_len, - total_encoded_len(&expected, version), - opt_segs - ); - } - - #[test] - fn test_example_1() { - test_optimization_result( - vec![ - Segment { mode: Mode::Alphanumeric, begin: 0, end: 3 }, - Segment { mode: Mode::Numeric, begin: 3, end: 6 }, - Segment { mode: Mode::Byte, begin: 6, end: 10 }, - ], - vec![ - Segment { mode: Mode::Alphanumeric, begin: 0, end: 6 }, - Segment { mode: Mode::Byte, begin: 6, end: 10 }, - ], - Version::Normal(1), - ); - } - - #[test] - fn test_example_2() { - test_optimization_result( - vec![ - Segment { mode: Mode::Numeric, begin: 0, end: 29 }, - Segment { mode: Mode::Alphanumeric, begin: 29, end: 30 }, - Segment { mode: Mode::Numeric, begin: 30, end: 32 }, - Segment { mode: Mode::Alphanumeric, begin: 32, end: 35 }, - Segment { mode: Mode::Numeric, begin: 35, end: 38 }, - ], - vec![ - Segment { mode: Mode::Numeric, begin: 0, end: 29 }, - Segment { mode: Mode::Alphanumeric, begin: 29, end: 38 }, - ], - Version::Normal(9), - ); - } - - #[test] - fn test_example_3() { - test_optimization_result( - vec![ - Segment { mode: Mode::Kanji, begin: 0, end: 4 }, - Segment { mode: Mode::Alphanumeric, begin: 4, end: 5 }, - Segment { mode: Mode::Byte, begin: 5, end: 6 }, - Segment { mode: Mode::Kanji, begin: 6, end: 8 }, - ], - vec![Segment { mode: Mode::Byte, begin: 0, end: 8 }], - Version::Normal(1), - ); - } - - #[test] - fn test_example_4() { - test_optimization_result( - vec![Segment { mode: Mode::Kanji, begin: 0, end: 10 }, Segment { mode: Mode::Byte, begin: 10, end: 11 }], - vec![Segment { mode: Mode::Kanji, begin: 0, end: 10 }, Segment { mode: Mode::Byte, begin: 10, end: 11 }], - Version::Normal(1), - ); - } - - #[test] - fn test_annex_j_guideline_1a() { - test_optimization_result( - vec![ - Segment { mode: Mode::Numeric, begin: 0, end: 3 }, - Segment { mode: Mode::Alphanumeric, begin: 3, end: 4 }, - ], - vec![ - Segment { mode: Mode::Numeric, begin: 0, end: 3 }, - Segment { mode: Mode::Alphanumeric, begin: 3, end: 4 }, - ], - Version::Micro(2), - ); - } - - #[test] - fn test_annex_j_guideline_1b() { - test_optimization_result( - vec![ - Segment { mode: Mode::Numeric, begin: 0, end: 2 }, - Segment { mode: Mode::Alphanumeric, begin: 2, end: 4 }, - ], - vec![Segment { mode: Mode::Alphanumeric, begin: 0, end: 4 }], - Version::Micro(2), - ); - } - - #[test] - fn test_annex_j_guideline_1c() { - test_optimization_result( - vec![ - Segment { mode: Mode::Numeric, begin: 0, end: 3 }, - Segment { mode: Mode::Alphanumeric, begin: 3, end: 4 }, - ], - vec![Segment { mode: Mode::Alphanumeric, begin: 0, end: 4 }], - Version::Micro(3), - ); - } -} - -#[cfg(feature = "bench")] -#[bench] -fn bench_optimize(bencher: &mut test::Bencher) { - use crate::types::Version; - - let data = b"QR\x83R\x81[\x83h\x81i\x83L\x83\x85\x81[\x83A\x81[\x83\x8b\x83R\x81[\x83h\x81j\ - \x82\xc6\x82\xcd\x81A1994\x94N\x82\xc9\x83f\x83\x93\x83\\\x81[\x82\xcc\x8aJ\ - \x94\xad\x95\x94\x96\xe5\x81i\x8c\xbb\x8d\xdd\x82\xcd\x95\xaa\x97\xa3\x82\xb5\x83f\ - \x83\x93\x83\\\x81[\x83E\x83F\x81[\x83u\x81j\x82\xaa\x8aJ\x94\xad\x82\xb5\x82\xbd\ - \x83}\x83g\x83\x8a\x83b\x83N\x83X\x8c^\x93\xf1\x8e\x9f\x8c\xb3\x83R\x81[\x83h\ - \x82\xc5\x82\xa0\x82\xe9\x81B\x82\xc8\x82\xa8\x81AQR\x83R\x81[\x83h\x82\xc6\ - \x82\xa2\x82\xa4\x96\xbc\x8f\xcc\x81i\x82\xa8\x82\xe6\x82\xd1\x92P\x8c\xea\x81j\ - \x82\xcd\x83f\x83\x93\x83\\\x81[\x83E\x83F\x81[\x83u\x82\xcc\x93o\x98^\x8f\xa4\ - \x95W\x81i\x91\xe64075066\x8d\x86\x81j\x82\xc5\x82\xa0\x82\xe9\x81BQR\x82\xcd\ - Quick Response\x82\xc9\x97R\x97\x88\x82\xb5\x81A\x8d\x82\x91\xac\x93\xc7\x82\xdd\ - \x8e\xe6\x82\xe8\x82\xaa\x82\xc5\x82\xab\x82\xe9\x82\xe6\x82\xa4\x82\xc9\x8aJ\ - \x94\xad\x82\xb3\x82\xea\x82\xbd\x81B\x93\x96\x8f\x89\x82\xcd\x8e\xa9\x93\xae\ - \x8e\xd4\x95\x94\x95i\x8dH\x8f\xea\x82\xe2\x94z\x91\x97\x83Z\x83\x93\x83^\x81[\ - \x82\xc8\x82\xc7\x82\xc5\x82\xcc\x8eg\x97p\x82\xf0\x94O\x93\xaa\x82\xc9\x8aJ\ - \x94\xad\x82\xb3\x82\xea\x82\xbd\x82\xaa\x81A\x8c\xbb\x8d\xdd\x82\xc5\x82\xcd\x83X\ - \x83}\x81[\x83g\x83t\x83H\x83\x93\x82\xcc\x95\x81\x8by\x82\xc8\x82\xc7\x82\xc9\ - \x82\xe6\x82\xe8\x93\xfa\x96{\x82\xc9\x8c\xc0\x82\xe7\x82\xb8\x90\xa2\x8aE\x93I\ - \x82\xc9\x95\x81\x8by\x82\xb5\x82\xc4\x82\xa2\x82\xe9\x81B"; - bencher.iter(|| Parser::new(data).optimize(Version::Normal(15))); -} - -//}}} -//------------------------------------------------------------------------------ -//{{{ Internal types and data for parsing - -/// All values of `u8` can be split into 9 different character sets when -/// determining which encoding to use. This enum represents these groupings for -/// parsing purpose. -#[derive(Copy, Clone)] -enum ExclCharSet { - /// The end of string. - End = 0, - - /// All symbols supported by the Alphanumeric encoding, i.e. space, `$`, `%`, - /// `*`, `+`, `-`, `.`, `/` and `:`. - Symbol = 1, - - /// All numbers (0–9). - Numeric = 2, - - /// All uppercase letters (A–Z). These characters may also appear in the - /// second byte of a Shift JIS 2-byte encoding. - Alpha = 3, - - /// The first byte of a Shift JIS 2-byte encoding, in the range 0x81–0x9f. - KanjiHi1 = 4, - - /// The first byte of a Shift JIS 2-byte encoding, in the range 0xe0–0xea. - KanjiHi2 = 5, - - /// The first byte of a Shift JIS 2-byte encoding, of value 0xeb. This is - /// different from the other two range that the second byte has a smaller - /// range. - KanjiHi3 = 6, - - /// The second byte of a Shift JIS 2-byte encoding, in the range 0x40–0xbf, - /// excluding letters (covered by `Alpha`), 0x81–0x9f (covered by `KanjiHi1`), - /// and the invalid byte 0x7f. - KanjiLo1 = 7, - - /// The second byte of a Shift JIS 2-byte encoding, in the range 0xc0–0xfc, - /// excluding the range 0xe0–0xeb (covered by `KanjiHi2` and `KanjiHi3`). - /// This half of byte-pair cannot appear as the second byte leaded by - /// `KanjiHi3`. - KanjiLo2 = 8, - - /// Any other values not covered by the above character sets. - Byte = 9, -} - -impl ExclCharSet { - /// Determines which character set a byte is in. - fn from_u8(c: u8) -> Self { - match c { - 0x20 | 0x24 | 0x25 | 0x2a | 0x2b | 0x2d..=0x2f | 0x3a => ExclCharSet::Symbol, - 0x30..=0x39 => ExclCharSet::Numeric, - 0x41..=0x5a => ExclCharSet::Alpha, - 0x81..=0x9f => ExclCharSet::KanjiHi1, - 0xe0..=0xea => ExclCharSet::KanjiHi2, - 0xeb => ExclCharSet::KanjiHi3, - 0x40 | 0x5b..=0x7e | 0x80 | 0xa0..=0xbf => ExclCharSet::KanjiLo1, - 0xc0..=0xdf | 0xec..=0xfc => ExclCharSet::KanjiLo2, - _ => ExclCharSet::Byte, - } - } -} - -/// The current parsing state. -#[derive(Copy, Clone)] -enum State { - /// Just initialized. - Init = 0, - - /// Inside a string that can be exclusively encoded as Numeric. - Numeric = 10, - - /// Inside a string that can be exclusively encoded as Alphanumeric. - Alpha = 20, - - /// Inside a string that can be exclusively encoded as 8-Bit Byte. - Byte = 30, - - /// Just encountered the first byte of a Shift JIS 2-byte sequence of the - /// set `KanjiHi1` or `KanjiHi2`. - KanjiHi12 = 40, - - /// Just encountered the first byte of a Shift JIS 2-byte sequence of the - /// set `KanjiHi3`. - KanjiHi3 = 50, - - /// Inside a string that can be exclusively encoded as Kanji. - Kanji = 60, -} - -/// What should the parser do after a state transition. -#[derive(Copy, Clone)] -enum Action { - /// The parser should do nothing. - Idle, - - /// Push the current segment as a Numeric string, and reset the marks. - Numeric, - - /// Push the current segment as an Alphanumeric string, and reset the marks. - Alpha, - - /// Push the current segment as a 8-Bit Byte string, and reset the marks. - Byte, - - /// Push the current segment as a Kanji string, and reset the marks. - Kanji, - - /// Push the current segment excluding the last byte as a Kanji string, then - /// push the remaining single byte as a Byte string, and reset the marks. - KanjiAndSingleByte, -} - -static STATE_TRANSITION: [(State, Action); 70] = [ - // STATE_TRANSITION[current_state + next_character] == (next_state, what_to_do) - - // Init state: - (State::Init, Action::Idle), // End - (State::Alpha, Action::Idle), // Symbol - (State::Numeric, Action::Idle), // Numeric - (State::Alpha, Action::Idle), // Alpha - (State::KanjiHi12, Action::Idle), // KanjiHi1 - (State::KanjiHi12, Action::Idle), // KanjiHi2 - (State::KanjiHi3, Action::Idle), // KanjiHi3 - (State::Byte, Action::Idle), // KanjiLo1 - (State::Byte, Action::Idle), // KanjiLo2 - (State::Byte, Action::Idle), // Byte - // Numeric state: - (State::Init, Action::Numeric), // End - (State::Alpha, Action::Numeric), // Symbol - (State::Numeric, Action::Idle), // Numeric - (State::Alpha, Action::Numeric), // Alpha - (State::KanjiHi12, Action::Numeric), // KanjiHi1 - (State::KanjiHi12, Action::Numeric), // KanjiHi2 - (State::KanjiHi3, Action::Numeric), // KanjiHi3 - (State::Byte, Action::Numeric), // KanjiLo1 - (State::Byte, Action::Numeric), // KanjiLo2 - (State::Byte, Action::Numeric), // Byte - // Alpha state: - (State::Init, Action::Alpha), // End - (State::Alpha, Action::Idle), // Symbol - (State::Numeric, Action::Alpha), // Numeric - (State::Alpha, Action::Idle), // Alpha - (State::KanjiHi12, Action::Alpha), // KanjiHi1 - (State::KanjiHi12, Action::Alpha), // KanjiHi2 - (State::KanjiHi3, Action::Alpha), // KanjiHi3 - (State::Byte, Action::Alpha), // KanjiLo1 - (State::Byte, Action::Alpha), // KanjiLo2 - (State::Byte, Action::Alpha), // Byte - // Byte state: - (State::Init, Action::Byte), // End - (State::Alpha, Action::Byte), // Symbol - (State::Numeric, Action::Byte), // Numeric - (State::Alpha, Action::Byte), // Alpha - (State::KanjiHi12, Action::Byte), // KanjiHi1 - (State::KanjiHi12, Action::Byte), // KanjiHi2 - (State::KanjiHi3, Action::Byte), // KanjiHi3 - (State::Byte, Action::Idle), // KanjiLo1 - (State::Byte, Action::Idle), // KanjiLo2 - (State::Byte, Action::Idle), // Byte - // KanjiHi12 state: - (State::Init, Action::KanjiAndSingleByte), // End - (State::Alpha, Action::KanjiAndSingleByte), // Symbol - (State::Numeric, Action::KanjiAndSingleByte), // Numeric - (State::Kanji, Action::Idle), // Alpha - (State::Kanji, Action::Idle), // KanjiHi1 - (State::Kanji, Action::Idle), // KanjiHi2 - (State::Kanji, Action::Idle), // KanjiHi3 - (State::Kanji, Action::Idle), // KanjiLo1 - (State::Kanji, Action::Idle), // KanjiLo2 - (State::Byte, Action::KanjiAndSingleByte), // Byte - // KanjiHi3 state: - (State::Init, Action::KanjiAndSingleByte), // End - (State::Alpha, Action::KanjiAndSingleByte), // Symbol - (State::Numeric, Action::KanjiAndSingleByte), // Numeric - (State::Kanji, Action::Idle), // Alpha - (State::Kanji, Action::Idle), // KanjiHi1 - (State::KanjiHi12, Action::KanjiAndSingleByte), // KanjiHi2 - (State::KanjiHi3, Action::KanjiAndSingleByte), // KanjiHi3 - (State::Kanji, Action::Idle), // KanjiLo1 - (State::Byte, Action::KanjiAndSingleByte), // KanjiLo2 - (State::Byte, Action::KanjiAndSingleByte), // Byte - // Kanji state: - (State::Init, Action::Kanji), // End - (State::Alpha, Action::Kanji), // Symbol - (State::Numeric, Action::Kanji), // Numeric - (State::Alpha, Action::Kanji), // Alpha - (State::KanjiHi12, Action::Idle), // KanjiHi1 - (State::KanjiHi12, Action::Idle), // KanjiHi2 - (State::KanjiHi3, Action::Idle), // KanjiHi3 - (State::Byte, Action::Kanji), // KanjiLo1 - (State::Byte, Action::Kanji), // KanjiLo2 - (State::Byte, Action::Kanji), // Byte -]; - -//}}} diff --git a/qrcode-rust/src/render/image.rs b/qrcode-rust/src/render/image.rs deleted file mode 100644 index 5a3974c8..00000000 --- a/qrcode-rust/src/render/image.rs +++ /dev/null @@ -1,150 +0,0 @@ -#![cfg(feature = "image")] - -use crate::render::{Canvas, Pixel}; -use crate::types::Color; - -use image::{ImageBuffer, Luma, LumaA, Pixel as ImagePixel, Primitive, Rgb, Rgba}; - -macro_rules! impl_pixel_for_image_pixel { - ($p:ident<$s:ident>: $c:pat => $d:expr) => { - impl<$s: Primitive + 'static> Pixel for $p<$s> { - type Image = ImageBuffer>; - type Canvas = (Self, Self::Image); - - fn default_color(color: Color) -> Self { - match color.select($s::zero(), $s::max_value()) { - $c => $p($d), - } - } - } - }; -} - -impl_pixel_for_image_pixel! { Luma: p => [p] } -impl_pixel_for_image_pixel! { LumaA: p => [p, S::max_value()] } -impl_pixel_for_image_pixel! { Rgb: p => [p, p, p] } -impl_pixel_for_image_pixel! { Rgba: p => [p, p, p, S::max_value()] } - -impl Canvas for (P, ImageBuffer>) { - type Pixel = P; - type Image = ImageBuffer>; - - fn new(width: u32, height: u32, dark_pixel: P, light_pixel: P) -> Self { - (dark_pixel, ImageBuffer::from_pixel(width, height, light_pixel)) - } - - fn draw_dark_pixel(&mut self, x: u32, y: u32) { - self.1.put_pixel(x, y, self.0); - } - - fn into_image(self) -> ImageBuffer> { - self.1 - } -} - -#[cfg(test)] -mod render_tests { - use crate::render::Renderer; - use crate::types::Color; - use image::{Luma, Rgba}; - - #[test] - fn test_render_luma8_unsized() { - let image = Renderer::>::new( - &[ - Color::Light, - Color::Dark, - Color::Dark, - // - Color::Dark, - Color::Light, - Color::Light, - // - Color::Light, - Color::Dark, - Color::Light, - ], - 3, - 1, - ) - .module_dimensions(1, 1) - .build(); - - #[rustfmt::skip] - let expected = [ - 255, 255, 255, 255, 255, - 255, 255, 0, 0, 255, - 255, 0, 255, 255, 255, - 255, 255, 0, 255, 255, - 255, 255, 255, 255, 255, - ]; - assert_eq!(image.into_raw(), expected); - } - - #[test] - fn test_render_rgba_unsized() { - let image = Renderer::>::new(&[Color::Light, Color::Dark, Color::Dark, Color::Dark], 2, 1) - .module_dimensions(1, 1) - .build(); - - #[rustfmt::skip] - let expected: &[u8] = &[ - 255,255,255,255, 255,255,255,255, 255,255,255,255, 255,255,255,255, - 255,255,255,255, 255,255,255,255, 0, 0, 0,255, 255,255,255,255, - 255,255,255,255, 0, 0, 0,255, 0, 0, 0,255, 255,255,255,255, - 255,255,255,255, 255,255,255,255, 255,255,255,255, 255,255,255,255, - ]; - - assert_eq!(image.into_raw(), expected); - } - - #[test] - fn test_render_resized_min() { - let image = Renderer::>::new(&[Color::Dark, Color::Light, Color::Light, Color::Dark], 2, 1) - .min_dimensions(10, 10) - .build(); - - #[rustfmt::skip] - let expected: &[u8] = &[ - 255,255,255, 255,255,255, 255,255,255, 255,255,255, - 255,255,255, 255,255,255, 255,255,255, 255,255,255, - 255,255,255, 255,255,255, 255,255,255, 255,255,255, - - 255,255,255, 0, 0, 0, 255,255,255, 255,255,255, - 255,255,255, 0, 0, 0, 255,255,255, 255,255,255, - 255,255,255, 0, 0, 0, 255,255,255, 255,255,255, - - 255,255,255, 255,255,255, 0, 0, 0, 255,255,255, - 255,255,255, 255,255,255, 0, 0, 0, 255,255,255, - 255,255,255, 255,255,255, 0, 0, 0, 255,255,255, - - 255,255,255, 255,255,255, 255,255,255, 255,255,255, - 255,255,255, 255,255,255, 255,255,255, 255,255,255, - 255,255,255, 255,255,255, 255,255,255, 255,255,255, - ]; - - assert_eq!(image.dimensions(), (12, 12)); - assert_eq!(image.into_raw(), expected); - } - - #[test] - fn test_render_resized_max() { - let image = Renderer::>::new(&[Color::Dark, Color::Light, Color::Light, Color::Dark], 2, 1) - .max_dimensions(10, 5) - .build(); - - #[rustfmt::skip] - let expected: &[u8] = &[ - 255,255, 255,255, 255,255, 255,255, - - 255,255, 0, 0, 255,255, 255,255, - - 255,255, 255,255, 0, 0, 255,255, - - 255,255, 255,255, 255,255, 255,255, - ]; - - assert_eq!(image.dimensions(), (8, 4)); - assert_eq!(image.into_raw(), expected); - } -} diff --git a/qrcode-rust/src/render/mod.rs b/qrcode-rust/src/render/mod.rs deleted file mode 100644 index 71f4306a..00000000 --- a/qrcode-rust/src/render/mod.rs +++ /dev/null @@ -1,191 +0,0 @@ -//! Render a QR code into image. - -use crate::cast::As; -use crate::types::Color; -use core::cmp::max; - -pub mod image; -pub mod string; -pub mod svg; -pub mod unicode; - -//------------------------------------------------------------------------------ -//{{{ Pixel trait - -/// Abstraction of an image pixel. -pub trait Pixel: Copy + Sized { - /// Type of the finalized image. - type Image: Sized + 'static; - - /// The type that stores an intermediate buffer before finalizing to a - /// concrete image - type Canvas: Canvas; - - /// Obtains the default module size. The result must be at least 1×1. - fn default_unit_size() -> (u32, u32) { - (8, 8) - } - - /// Obtains the default pixel color when a module is dark or light. - fn default_color(color: Color) -> Self; -} - -/// Rendering canvas of a QR code image. -pub trait Canvas: Sized { - type Pixel: Sized; - type Image: Sized; - - /// Constructs a new canvas of the given dimensions. - fn new(width: u32, height: u32, dark_pixel: Self::Pixel, light_pixel: Self::Pixel) -> Self; - - /// Draws a single dark pixel at the (x, y) coordinate. - fn draw_dark_pixel(&mut self, x: u32, y: u32); - - fn draw_dark_rect(&mut self, left: u32, top: u32, width: u32, height: u32) { - for y in top..(top + height) { - for x in left..(left + width) { - self.draw_dark_pixel(x, y); - } - } - } - - /// Finalize the canvas to a real image. - fn into_image(self) -> Self::Image; -} - -//}}} -//------------------------------------------------------------------------------ -//{{{ Renderer - -/// A QR code renderer. This is a builder type which converts a bool-vector into -/// an image. -pub struct Renderer<'a, P: Pixel> { - content: &'a [Color], - modules_count: u32, // <- we call it `modules_count` here to avoid ambiguity of `width`. - quiet_zone: u32, - module_size: (u32, u32), - - dark_color: P, - light_color: P, - has_quiet_zone: bool, -} - -impl<'a, P: Pixel> Renderer<'a, P> { - /// Creates a new renderer. - pub fn new(content: &'a [Color], modules_count: usize, quiet_zone: u32) -> Renderer<'a, P> { - assert!(modules_count * modules_count == content.len()); - Renderer { - content, - modules_count: modules_count.as_u32(), - quiet_zone, - module_size: P::default_unit_size(), - dark_color: P::default_color(Color::Dark), - light_color: P::default_color(Color::Light), - has_quiet_zone: true, - } - } - - /// Sets color of a dark module. Default is opaque black. - pub fn dark_color(&mut self, color: P) -> &mut Self { - self.dark_color = color; - self - } - - /// Sets color of a light module. Default is opaque white. - pub fn light_color(&mut self, color: P) -> &mut Self { - self.light_color = color; - self - } - - /// Whether to include the quiet zone in the generated image. - pub fn quiet_zone(&mut self, has_quiet_zone: bool) -> &mut Self { - self.has_quiet_zone = has_quiet_zone; - self - } - - /// Sets the size of each module in pixels. Default is 8px. - #[deprecated(since = "0.4.0", note = "use `.module_dimensions(width, width)` instead")] - pub fn module_size(&mut self, width: u32) -> &mut Self { - self.module_dimensions(width, width) - } - - /// Sets the size of each module in pixels. Default is 8×8. - pub fn module_dimensions(&mut self, width: u32, height: u32) -> &mut Self { - self.module_size = (max(width, 1), max(height, 1)); - self - } - - #[deprecated(since = "0.4.0", note = "use `.min_dimensions(width, width)` instead")] - pub fn min_width(&mut self, width: u32) -> &mut Self { - self.min_dimensions(width, width) - } - - /// Sets the minimum total image size in pixels, including the quiet zone if - /// applicable. The renderer will try to find the dimension as small as - /// possible, such that each module in the QR code has uniform size (no - /// distortion). - /// - /// For instance, a version 1 QR code has 19 modules across including the - /// quiet zone. If we request an image of size ≥200×200, we get that each - /// module's size should be 11×11, so the actual image size will be 209×209. - pub fn min_dimensions(&mut self, width: u32, height: u32) -> &mut Self { - let quiet_zone = if self.has_quiet_zone { 2 } else { 0 } * self.quiet_zone; - let width_in_modules = self.modules_count + quiet_zone; - let unit_width = (width + width_in_modules - 1) / width_in_modules; - let unit_height = (height + width_in_modules - 1) / width_in_modules; - self.module_dimensions(unit_width, unit_height) - } - - /// Sets the maximum total image size in pixels, including the quiet zone if - /// applicable. The renderer will try to find the dimension as large as - /// possible, such that each module in the QR code has uniform size (no - /// distortion). - /// - /// For instance, a version 1 QR code has 19 modules across including the - /// quiet zone. If we request an image of size ≤200×200, we get that each - /// module's size should be 10×10, so the actual image size will be 190×190. - /// - /// The module size is at least 1×1, so if the restriction is too small, the - /// final image *can* be larger than the input. - pub fn max_dimensions(&mut self, width: u32, height: u32) -> &mut Self { - let quiet_zone = if self.has_quiet_zone { 2 } else { 0 } * self.quiet_zone; - let width_in_modules = self.modules_count + quiet_zone; - let unit_width = width / width_in_modules; - let unit_height = height / width_in_modules; - self.module_dimensions(unit_width, unit_height) - } - - /// Renders the QR code into an image. - #[deprecated(since = "0.4.0", note = "renamed to `.build()` to de-emphasize the image connection")] - pub fn to_image(&self) -> P::Image { - self.build() - } - - /// Renders the QR code into an image. - pub fn build(&self) -> P::Image { - let w = self.modules_count; - let qz = if self.has_quiet_zone { self.quiet_zone } else { 0 }; - let width = w + 2 * qz; - - let (mw, mh) = self.module_size; - let real_width = width * mw; - let real_height = width * mh; - - let mut canvas = P::Canvas::new(real_width, real_height, self.dark_color, self.light_color); - let mut i = 0; - for y in 0..width { - for x in 0..width { - if qz <= x && x < w + qz && qz <= y && y < w + qz { - if self.content[i] != Color::Light { - canvas.draw_dark_rect(x * mw, y * mh, mw, mh); - } - i += 1; - } - } - } - - canvas.into_image() - } -} - -//}}} diff --git a/qrcode-rust/src/render/string.rs b/qrcode-rust/src/render/string.rs deleted file mode 100644 index a7ae42ce..00000000 --- a/qrcode-rust/src/render/string.rs +++ /dev/null @@ -1,125 +0,0 @@ -//! String rendering support. - -use alloc::string::String; -use alloc::vec::Vec; - -use crate::cast::As; -use crate::render::{Canvas as RenderCanvas, Pixel}; -use crate::types::Color; - -pub trait Element: Copy { - fn default_color(color: Color) -> Self; - fn strlen(self) -> usize; - fn append_to_string(self, string: &mut String); -} - -impl Element for char { - fn default_color(color: Color) -> Self { - color.select('█', ' ') - } - - fn strlen(self) -> usize { - self.len_utf8() - } - - fn append_to_string(self, string: &mut String) { - string.push(self) - } -} - -impl<'a> Element for &'a str { - fn default_color(color: Color) -> Self { - color.select("\u{2588}", " ") - } - - fn strlen(self) -> usize { - self.len() - } - - fn append_to_string(self, string: &mut String) { - string.push_str(self) - } -} - -#[doc(hidden)] -pub struct Canvas { - buffer: Vec

, - width: usize, - dark_pixel: P, - dark_cap_inc: isize, - capacity: isize, -} - -impl Pixel for P { - type Canvas = Canvas; - type Image = String; - - fn default_unit_size() -> (u32, u32) { - (1, 1) - } - - fn default_color(color: Color) -> Self { - ::default_color(color) - } -} - -impl RenderCanvas for Canvas

{ - type Pixel = P; - type Image = String; - - fn new(width: u32, height: u32, dark_pixel: P, light_pixel: P) -> Self { - let width = width.as_usize(); - let height = height.as_isize(); - let dark_cap = dark_pixel.strlen().as_isize(); - let light_cap = light_pixel.strlen().as_isize(); - - Self { - buffer: vec![light_pixel; width * height.as_usize()], - width, - dark_pixel, - dark_cap_inc: dark_cap - light_cap, - capacity: light_cap * width.as_isize() * height + (height - 1), - } - } - - fn draw_dark_pixel(&mut self, x: u32, y: u32) { - let x = x.as_usize(); - let y = y.as_usize(); - self.capacity += self.dark_cap_inc; - self.buffer[x + y * self.width] = self.dark_pixel; - } - - fn into_image(self) -> String { - let mut result = String::with_capacity(self.capacity.as_usize()); - for (i, pixel) in self.buffer.into_iter().enumerate() { - if i != 0 && i % self.width == 0 { - result.push('\n'); - } - pixel.append_to_string(&mut result); - } - result - } -} - -#[test] -fn test_render_to_string() { - use crate::render::Renderer; - - let colors = &[Color::Dark, Color::Light, Color::Light, Color::Dark]; - let image: String = Renderer::::new(colors, 2, 1).build(); - assert_eq!(&image, " \n \u{2588} \n \u{2588} \n "); - - let image2 = Renderer::new(colors, 2, 1).light_color("A").dark_color("!B!").module_dimensions(2, 2).build(); - - assert_eq!( - &image2, - "AAAAAAAA\n\ - AAAAAAAA\n\ - AA!B!!B!AAAA\n\ - AA!B!!B!AAAA\n\ - AAAA!B!!B!AA\n\ - AAAA!B!!B!AA\n\ - AAAAAAAA\n\ - AAAAAAAA" - ); -} diff --git a/qrcode-rust/src/render/svg.rs b/qrcode-rust/src/render/svg.rs deleted file mode 100644 index ba85fbd4..00000000 --- a/qrcode-rust/src/render/svg.rs +++ /dev/null @@ -1,76 +0,0 @@ -//! SVG rendering support. -//! -//! # Example -//! -//! ``` -//! use qrcode::QrCode; -//! use qrcode::render::svg; -//! -//! let code = QrCode::new(b"Hello").unwrap(); -//! let svg_xml = code.render::().build(); -//! println!("{}", svg_xml); - -#![cfg(feature = "svg")] - -use std::fmt::Write; -use std::marker::PhantomData; - -use crate::render::{Canvas as RenderCanvas, Pixel}; -use crate::types::Color as ModuleColor; - -/// An SVG color. -#[derive(Copy, Clone, Default, PartialEq, Eq, PartialOrd, Ord, Hash)] -pub struct Color<'a>(pub &'a str); - -impl<'a> Pixel for Color<'a> { - type Canvas = Canvas<'a>; - type Image = String; - - fn default_color(color: ModuleColor) -> Self { - Color(color.select("#000", "#fff")) - } -} - -#[doc(hidden)] -pub struct Canvas<'a> { - svg: String, - marker: PhantomData>, -} - -impl<'a> RenderCanvas for Canvas<'a> { - type Pixel = Color<'a>; - type Image = String; - - fn new(width: u32, height: u32, dark_pixel: Color<'a>, light_pixel: Color<'a>) -> Self { - Canvas { - svg: format!( - concat!( - r#""#, - r#""#, - r#""#, - r#" String { - self.svg.push_str(r#""/>"#); - self.svg - } -} diff --git a/qrcode-rust/src/render/unicode.rs b/qrcode-rust/src/render/unicode.rs deleted file mode 100644 index 11e7a2c0..00000000 --- a/qrcode-rust/src/render/unicode.rs +++ /dev/null @@ -1,142 +0,0 @@ -//! UTF-8 rendering, with 2 pixels per symbol. - -use crate::render::{Canvas as RenderCanvas, Color, Pixel}; -use alloc::{string::String, vec::Vec}; - -const CODEPAGE: [&str; 4] = [" ", "\u{2584}", "\u{2580}", "\u{2588}"]; - -#[derive(Copy, Clone, PartialEq, Eq)] -pub enum Dense1x2 { - Dark, - Light, -} - -impl Pixel for Dense1x2 { - type Image = String; - type Canvas = Canvas1x2; - fn default_color(color: Color) -> Dense1x2 { - color.select(Dense1x2::Dark, Dense1x2::Light) - } - fn default_unit_size() -> (u32, u32) { - (1, 1) - } -} - -impl Dense1x2 { - fn value(self) -> u8 { - match self { - Dense1x2::Dark => 1, - Dense1x2::Light => 0, - } - } - fn parse_2_bits(sym: u8) -> &'static str { - CODEPAGE[usize::from(sym)] - } -} - -pub struct Canvas1x2 { - canvas: Vec, - width: u32, - dark_pixel: u8, -} - -impl RenderCanvas for Canvas1x2 { - type Pixel = Dense1x2; - type Image = String; - - fn new(width: u32, height: u32, dark_pixel: Dense1x2, light_pixel: Dense1x2) -> Self { - let a = vec![light_pixel.value(); (width * height) as usize]; - Canvas1x2 { width, canvas: a, dark_pixel: dark_pixel.value() } - } - - fn draw_dark_pixel(&mut self, x: u32, y: u32) { - self.canvas[(x + y * self.width) as usize] = self.dark_pixel; - } - - fn into_image(self) -> String { - self.canvas - // Chopping array into 1-line sized fragments - .chunks_exact(self.width as usize) - .collect::>() - // And then glueing every 2 lines. - .chunks(2) - .map(|rows| { - { - // Then zipping those 2 lines together into a single 2-bit number list. - if rows.len() == 2 { - rows[0].iter().zip(rows[1]).map(|(top, bot)| (top * 2 + bot)).collect::>() - } else { - rows[0].iter().map(|top| (top * 2)).collect::>() - } - } - .into_iter() - // Mapping those 2-bit numbers to corresponding pixels. - .map(Dense1x2::parse_2_bits) - .collect::>() - .concat() - }) - .collect::>() - .join("\n") - } -} - -#[test] -fn test_render_to_utf8_string() { - use crate::render::Renderer; - let colors = &[Color::Dark, Color::Light, Color::Light, Color::Dark]; - let image: String = Renderer::::new(colors, 2, 1).build(); - - assert_eq!(&image, " ▄ \n ▀ "); - - let image2 = Renderer::::new(colors, 2, 1).module_dimensions(2, 2).build(); - - assert_eq!(&image2, " \n ██ \n ██ \n "); -} - -#[test] -fn integration_render_utf8_1x2() { - use crate::render::unicode::Dense1x2; - use crate::{EcLevel, QrCode, Version}; - - let code = QrCode::with_version(b"09876542", Version::Micro(2), EcLevel::L).unwrap(); - let image = code.render::().module_dimensions(1, 1).build(); - assert_eq!( - image, - String::new() - + " \n" - + " █▀▀▀▀▀█ ▀ █ ▀ \n" - + " █ ███ █ ▀ █ \n" - + " █ ▀▀▀ █ ▀█ █ \n" - + " ▀▀▀▀▀▀▀ ▄▀▀ █ \n" - + " ▀█ ▀▀▀▀▀██▀▀▄ \n" - + " ▀███▄ ▀▀ █ ██ \n" - + " ▀▀▀ ▀ ▀▀ ▀ ▀ \n" - + " " - ) -} - -#[test] -fn integration_render_utf8_1x2_inverted() { - use crate::render::unicode::Dense1x2; - use crate::{EcLevel, QrCode, Version}; - - let code = QrCode::with_version(b"12345678", Version::Micro(2), EcLevel::L).unwrap(); - let image = code - .render::() - .dark_color(Dense1x2::Light) - .light_color(Dense1x2::Dark) - .module_dimensions(1, 1) - .build(); - assert_eq!( - image, - "█████████████████\n\ - ██ ▄▄▄▄▄ █▄▀▄█▄██\n\ - ██ █ █ █ █ ██\n\ - ██ █▄▄▄█ █▄▄██▀██\n\ - ██▄▄▄▄▄▄▄█▄▄▄▀ ██\n\ - ██▄ ▀ ▀ ▀▄▄ ████\n\ - ██▄▄▀▄█ ▀▀▀ ▀▄▄██\n\ - ██▄▄▄█▄▄█▄██▄█▄██\n\ - ▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀" - ); -} diff --git a/qrcode-rust/src/test_annex_i_micro_qr_as_image.png b/qrcode-rust/src/test_annex_i_micro_qr_as_image.png deleted file mode 100644 index 43cb1f7a..00000000 Binary files a/qrcode-rust/src/test_annex_i_micro_qr_as_image.png and /dev/null differ diff --git a/qrcode-rust/src/test_annex_i_micro_qr_as_svg.svg b/qrcode-rust/src/test_annex_i_micro_qr_as_svg.svg deleted file mode 100644 index efac9184..00000000 --- a/qrcode-rust/src/test_annex_i_micro_qr_as_svg.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/qrcode-rust/src/test_annex_i_qr_as_image.png b/qrcode-rust/src/test_annex_i_qr_as_image.png deleted file mode 100644 index 4d5e5d69..00000000 Binary files a/qrcode-rust/src/test_annex_i_qr_as_image.png and /dev/null differ diff --git a/qrcode-rust/src/test_annex_i_qr_as_svg.svg b/qrcode-rust/src/test_annex_i_qr_as_svg.svg deleted file mode 100644 index 6f374468..00000000 --- a/qrcode-rust/src/test_annex_i_qr_as_svg.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/qrcode-rust/src/types.rs b/qrcode-rust/src/types.rs deleted file mode 100644 index 0bca0459..00000000 --- a/qrcode-rust/src/types.rs +++ /dev/null @@ -1,326 +0,0 @@ -use crate::cast::As; -use core::cmp::{Ordering, PartialOrd}; -use core::default::Default; -use core::fmt::{Display, Error, Formatter}; -use core::ops::Not; - -//------------------------------------------------------------------------------ -//{{{ QrResult - -/// `QrError` encodes the error encountered when generating a QR code. -#[derive(Debug, PartialEq, Eq, Copy, Clone)] -pub enum QrError { - /// The data is too long to encode into a QR code for the given version. - DataTooLong, - - /// The provided version / error correction level combination is invalid. - InvalidVersion, - - /// Some characters in the data cannot be supported by the provided QR code - /// version. - UnsupportedCharacterSet, - - /// The provided ECI designator is invalid. A valid designator should be - /// between 0 and 999999. - InvalidEciDesignator, - - /// A character not belonging to the character set is found. - InvalidCharacter, -} - -impl Display for QrError { - fn fmt(&self, fmt: &mut Formatter) -> Result<(), Error> { - let msg = match *self { - QrError::DataTooLong => "data too long", - QrError::InvalidVersion => "invalid version", - QrError::UnsupportedCharacterSet => "unsupported character set", - QrError::InvalidEciDesignator => "invalid ECI designator", - QrError::InvalidCharacter => "invalid character", - }; - fmt.write_str(msg) - } -} - -/// `QrResult` is a convenient alias for a QR code generation result. -pub type QrResult = Result; - -//}}} -//------------------------------------------------------------------------------ -//{{{ Color - -/// The color of a module. -#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)] -pub enum Color { - /// The module is light colored. - Light, - /// The module is dark colored. - Dark, -} - -impl Color { - /// Selects a value according to color of the module. Equivalent to - /// `if self != Color::Light { dark } else { light }`. - /// - /// # Examples - /// - /// ```rust - /// # use qrcode::types::Color; - /// assert_eq!(Color::Light.select(1, 0), 0); - /// assert_eq!(Color::Dark.select("black", "white"), "black"); - /// ``` - pub fn select(self, dark: T, light: T) -> T { - match self { - Color::Light => light, - Color::Dark => dark, - } - } -} - -impl Not for Color { - type Output = Self; - fn not(self) -> Self { - match self { - Color::Light => Color::Dark, - Color::Dark => Color::Light, - } - } -} - -//}}} -//------------------------------------------------------------------------------ -//{{{ Error correction level - -/// The error correction level. It allows the original information be recovered -/// even if parts of the code is damaged. -#[derive(Debug, PartialEq, Eq, Copy, Clone, PartialOrd, Ord)] -pub enum EcLevel { - /// Low error correction. Allows up to 7% of wrong blocks. - L = 0, - - /// Medium error correction (default). Allows up to 15% of wrong blocks. - M = 1, - - /// "Quartile" error correction. Allows up to 25% of wrong blocks. - Q = 2, - - /// High error correction. Allows up to 30% of wrong blocks. - H = 3, -} - -//}}} -//------------------------------------------------------------------------------ -//{{{ Version - -/// In QR code terminology, `Version` means the size of the generated image. -/// Larger version means the size of code is larger, and therefore can carry -/// more information. -/// -/// The smallest version is `Version::Normal(1)` of size 21×21, and the largest -/// is `Version::Normal(40)` of size 177×177. -#[derive(Debug, PartialEq, Eq, Copy, Clone)] -pub enum Version { - /// A normal QR code version. The parameter should be between 1 and 40. - Normal(i16), - - /// A Micro QR code version. The parameter should be between 1 and 4. - Micro(i16), -} - -impl Version { - /// Get the number of "modules" on each size of the QR code, i.e. the width - /// and height of the code. - pub fn width(self) -> i16 { - match self { - Version::Normal(v) => v * 4 + 17, - Version::Micro(v) => v * 2 + 9, - } - } - - /// Obtains an object from a hard-coded table. - /// - /// The table must be a 44×4 array. The outer array represents the content - /// for each version. The first 40 entry corresponds to QR code versions 1 - /// to 40, and the last 4 corresponds to Micro QR code version 1 to 4. The - /// inner array represents the content in each error correction level, in - /// the order [L, M, Q, H]. - /// - /// # Errors - /// - /// If the entry compares equal to the default value of `T`, this method - /// returns `Err(QrError::InvalidVersion)`. - pub fn fetch(self, ec_level: EcLevel, table: &[[T; 4]]) -> QrResult - where - T: PartialEq + Default + Copy, - { - match self { - Version::Normal(v @ 1..=40) => { - return Ok(table[(v - 1).as_usize()][ec_level as usize]); - } - Version::Micro(v @ 1..=4) => { - let obj = table[(v + 39).as_usize()][ec_level as usize]; - if obj != T::default() { - return Ok(obj); - } - } - _ => {} - } - Err(QrError::InvalidVersion) - } - - /// The number of bits needed to encode the mode indicator. - pub fn mode_bits_count(self) -> usize { - match self { - Version::Micro(a) => (a - 1).as_usize(), - _ => 4, - } - } - - /// Checks whether is version refers to a Micro QR code. - pub fn is_micro(self) -> bool { - match self { - Version::Normal(_) => false, - Version::Micro(_) => true, - } - } -} - -//}}} -//------------------------------------------------------------------------------ -//{{{ Mode indicator - -/// The mode indicator, which specifies the character set of the encoded data. -#[derive(Debug, PartialEq, Eq, Copy, Clone)] -pub enum Mode { - /// The data contains only characters 0 to 9. - Numeric, - - /// The data contains only uppercase letters (A–Z), numbers (0–9) and a few - /// punctuations marks (space, `$`, `%`, `*`, `+`, `-`, `.`, `/`, `:`). - Alphanumeric, - - /// The data contains arbitrary binary data. - Byte, - - /// The data contains Shift-JIS-encoded double-byte text. - Kanji, -} - -impl Mode { - /// Computes the number of bits needed to encode the data length. - /// - /// use qrcode::types::{Version, Mode}; - /// - /// assert_eq!(Mode::Numeric.length_bits_count(Version::Normal(1)), 10); - /// - /// This method will return `Err(QrError::UnsupportedCharacterSet)` if the - /// mode is not supported in the given version. - pub fn length_bits_count(self, version: Version) -> usize { - match version { - Version::Micro(a) => { - let a = a.as_usize(); - match self { - Mode::Numeric => 2 + a, - Mode::Alphanumeric | Mode::Byte => 1 + a, - Mode::Kanji => a, - } - } - Version::Normal(1..=9) => match self { - Mode::Numeric => 10, - Mode::Alphanumeric => 9, - Mode::Byte | Mode::Kanji => 8, - }, - Version::Normal(10..=26) => match self { - Mode::Numeric => 12, - Mode::Alphanumeric => 11, - Mode::Byte => 16, - Mode::Kanji => 10, - }, - Version::Normal(_) => match self { - Mode::Numeric => 14, - Mode::Alphanumeric => 13, - Mode::Byte => 16, - Mode::Kanji => 12, - }, - } - } - - /// Computes the number of bits needed to some data of a given raw length. - /// - /// use qrcode::types::Mode; - /// - /// assert_eq!(Mode::Numeric.data_bits_count(7), 24); - /// - /// Note that in Kanji mode, the `raw_data_len` is the number of Kanjis, - /// i.e. half the total size of bytes. - pub fn data_bits_count(self, raw_data_len: usize) -> usize { - match self { - Mode::Numeric => (raw_data_len * 10 + 2) / 3, - Mode::Alphanumeric => (raw_data_len * 11 + 1) / 2, - Mode::Byte => raw_data_len * 8, - Mode::Kanji => raw_data_len * 13, - } - } - - /// Find the lowest common mode which both modes are compatible with. - /// - /// use qrcode::types::Mode; - /// - /// let a = Mode::Numeric; - /// let b = Mode::Kanji; - /// let c = a.max(b); - /// assert!(a <= c); - /// assert!(b <= c); - /// - pub fn max(self, other: Self) -> Self { - match self.partial_cmp(&other) { - Some(Ordering::Less) | Some(Ordering::Equal) => other, - Some(Ordering::Greater) => self, - None => Mode::Byte, - } - } -} - -impl PartialOrd for Mode { - /// Defines a partial ordering between modes. If `a <= b`, then `b` contains - /// a superset of all characters supported by `a`. - fn partial_cmp(&self, other: &Self) -> Option { - match (*self, *other) { - (Mode::Numeric, Mode::Alphanumeric) - | (Mode::Numeric, Mode::Byte) - | (Mode::Alphanumeric, Mode::Byte) - | (Mode::Kanji, Mode::Byte) => Some(Ordering::Less), - (Mode::Alphanumeric, Mode::Numeric) - | (Mode::Byte, Mode::Numeric) - | (Mode::Byte, Mode::Alphanumeric) - | (Mode::Byte, Mode::Kanji) => Some(Ordering::Greater), - (a, b) if a == b => Some(Ordering::Equal), - _ => None, - } - } -} - -#[cfg(test)] -mod mode_tests { - use crate::types::Mode::{Alphanumeric, Byte, Kanji, Numeric}; - - #[test] - fn test_mode_order() { - assert!(Numeric < Alphanumeric); - assert!(Byte > Kanji); - assert!(!(Numeric < Kanji)); - assert!(!(Numeric >= Kanji)); - } - - #[test] - fn test_max() { - assert_eq!(Byte.max(Kanji), Byte); - assert_eq!(Numeric.max(Alphanumeric), Alphanumeric); - assert_eq!(Alphanumeric.max(Alphanumeric), Alphanumeric); - assert_eq!(Numeric.max(Kanji), Byte); - assert_eq!(Kanji.max(Numeric), Byte); - assert_eq!(Alphanumeric.max(Numeric), Alphanumeric); - assert_eq!(Kanji.max(Kanji), Kanji); - } -} - -//}}}