15317bbafSopenharmony_ci/* 25317bbafSopenharmony_ci * QR Code generator library (Rust) 35317bbafSopenharmony_ci * 45317bbafSopenharmony_ci * Copyright (c) Project Nayuki. (MIT License) 55317bbafSopenharmony_ci * https://www.nayuki.io/page/qr-code-generator-library 65317bbafSopenharmony_ci * 75317bbafSopenharmony_ci * Permission is hereby granted, free of charge, to any person obtaining a copy of 85317bbafSopenharmony_ci * this software and associated documentation files (the "Software"), to deal in 95317bbafSopenharmony_ci * the Software without restriction, including without limitation the rights to 105317bbafSopenharmony_ci * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 115317bbafSopenharmony_ci * the Software, and to permit persons to whom the Software is furnished to do so, 125317bbafSopenharmony_ci * subject to the following conditions: 135317bbafSopenharmony_ci * - The above copyright notice and this permission notice shall be included in 145317bbafSopenharmony_ci * all copies or substantial portions of the Software. 155317bbafSopenharmony_ci * - The Software is provided "as is", without warranty of any kind, express or 165317bbafSopenharmony_ci * implied, including but not limited to the warranties of merchantability, 175317bbafSopenharmony_ci * fitness for a particular purpose and noninfringement. In no event shall the 185317bbafSopenharmony_ci * authors or copyright holders be liable for any claim, damages or other 195317bbafSopenharmony_ci * liability, whether in an action of contract, tort or otherwise, arising from, 205317bbafSopenharmony_ci * out of or in connection with the Software or the use or other dealings in the 215317bbafSopenharmony_ci * Software. 225317bbafSopenharmony_ci */ 235317bbafSopenharmony_ci 245317bbafSopenharmony_ci 255317bbafSopenharmony_ci//! Generates QR Codes from text strings and byte arrays. 265317bbafSopenharmony_ci//! 275317bbafSopenharmony_ci//! This project aims to be the best, clearest QR Code generator library. 285317bbafSopenharmony_ci//! The primary goals are flexible options and absolute correctness. 295317bbafSopenharmony_ci//! Secondary goals are compact implementation size and good documentation comments. 305317bbafSopenharmony_ci//! 315317bbafSopenharmony_ci//! Home page with live JavaScript demo, extensive descriptions, and competitor comparisons: 325317bbafSopenharmony_ci//! [https://www.nayuki.io/page/qr-code-generator-library](https://www.nayuki.io/page/qr-code-generator-library) 335317bbafSopenharmony_ci//! 345317bbafSopenharmony_ci//! # Features 355317bbafSopenharmony_ci//! 365317bbafSopenharmony_ci//! Core features: 375317bbafSopenharmony_ci//! 385317bbafSopenharmony_ci//! - Significantly shorter code but more documentation comments compared to competing libraries 395317bbafSopenharmony_ci//! - Supports encoding all 40 versions (sizes) and all 4 error correction levels, as per the QR Code Model 2 standard 405317bbafSopenharmony_ci//! - Output format: Raw modules/pixels of the QR symbol 415317bbafSopenharmony_ci//! - Detects finder-like penalty patterns more accurately than other implementations 425317bbafSopenharmony_ci//! - Encodes numeric and special-alphanumeric text in less space than general text 435317bbafSopenharmony_ci//! - Open-source code under the permissive MIT License 445317bbafSopenharmony_ci//! 455317bbafSopenharmony_ci//! Manual parameters: 465317bbafSopenharmony_ci//! 475317bbafSopenharmony_ci//! - User can specify minimum and maximum version numbers allowed, then library will automatically choose smallest version in the range that fits the data 485317bbafSopenharmony_ci//! - User can specify mask pattern manually, otherwise library will automatically evaluate all 8 masks and select the optimal one 495317bbafSopenharmony_ci//! - User can specify absolute error correction level, or allow the library to boost it if it doesn't increase the version number 505317bbafSopenharmony_ci//! - User can create a list of data segments manually and add ECI segments 515317bbafSopenharmony_ci//! 525317bbafSopenharmony_ci//! More information about QR Code technology and this library's design can be found on the project home page. 535317bbafSopenharmony_ci//! 545317bbafSopenharmony_ci//! # Examples 555317bbafSopenharmony_ci//! 565317bbafSopenharmony_ci//! ``` 575317bbafSopenharmony_ci//! extern crate qrcodegen; 585317bbafSopenharmony_ci//! use qrcodegen::Mask; 595317bbafSopenharmony_ci//! use qrcodegen::QrCode; 605317bbafSopenharmony_ci//! use qrcodegen::QrCodeEcc; 615317bbafSopenharmony_ci//! use qrcodegen::QrSegment; 625317bbafSopenharmony_ci//! use qrcodegen::Version; 635317bbafSopenharmony_ci//! ``` 645317bbafSopenharmony_ci//! 655317bbafSopenharmony_ci//! Simple operation: 665317bbafSopenharmony_ci//! 675317bbafSopenharmony_ci//! ``` 685317bbafSopenharmony_ci//! let qr = QrCode::encode_text("Hello, world!", 695317bbafSopenharmony_ci//! QrCodeEcc::Medium).unwrap(); 705317bbafSopenharmony_ci//! let svg = to_svg_string(&qr, 4); // See qrcodegen-demo 715317bbafSopenharmony_ci//! ``` 725317bbafSopenharmony_ci//! 735317bbafSopenharmony_ci//! Manual operation: 745317bbafSopenharmony_ci//! 755317bbafSopenharmony_ci//! ``` 765317bbafSopenharmony_ci//! let text: &str = "3141592653589793238462643383"; 775317bbafSopenharmony_ci//! let segs = QrSegment::make_segments(text); 785317bbafSopenharmony_ci//! let qr = QrCode::encode_segments_advanced(&segs, QrCodeEcc::High, 795317bbafSopenharmony_ci//! Version::new(5), Version::new(5), Some(Mask::new(2)), false).unwrap(); 805317bbafSopenharmony_ci//! for y in 0 .. qr.size() { 815317bbafSopenharmony_ci//! for x in 0 .. qr.size() { 825317bbafSopenharmony_ci//! (... paint qr.get_module(x, y) ...) 835317bbafSopenharmony_ci//! } 845317bbafSopenharmony_ci//! } 855317bbafSopenharmony_ci//! ``` 865317bbafSopenharmony_ci 875317bbafSopenharmony_ci 885317bbafSopenharmony_ci#![forbid(unsafe_code)] 895317bbafSopenharmony_ciuse std::convert::TryFrom; 905317bbafSopenharmony_ci 915317bbafSopenharmony_ci 925317bbafSopenharmony_ci/*---- QrCode functionality ----*/ 935317bbafSopenharmony_ci 945317bbafSopenharmony_ci/// A QR Code symbol, which is a type of two-dimension barcode. 955317bbafSopenharmony_ci/// 965317bbafSopenharmony_ci/// Invented by Denso Wave and described in the ISO/IEC 18004 standard. 975317bbafSopenharmony_ci/// 985317bbafSopenharmony_ci/// Instances of this struct represent an immutable square grid of dark and light cells. 995317bbafSopenharmony_ci/// The impl provides static factory functions to create a QR Code from text or binary data. 1005317bbafSopenharmony_ci/// The struct and impl cover the QR Code Model 2 specification, supporting all versions 1015317bbafSopenharmony_ci/// (sizes) from 1 to 40, all 4 error correction levels, and 4 character encoding modes. 1025317bbafSopenharmony_ci/// 1035317bbafSopenharmony_ci/// Ways to create a QR Code object: 1045317bbafSopenharmony_ci/// 1055317bbafSopenharmony_ci/// - High level: Take the payload data and call `QrCode::encode_text()` or `QrCode::encode_binary()`. 1065317bbafSopenharmony_ci/// - Mid level: Custom-make the list of segments and call 1075317bbafSopenharmony_ci/// `QrCode::encode_segments()` or `QrCode::encode_segments_advanced()`. 1085317bbafSopenharmony_ci/// - Low level: Custom-make the array of data codeword bytes (including segment 1095317bbafSopenharmony_ci/// headers and final padding, excluding error correction codewords), supply the 1105317bbafSopenharmony_ci/// appropriate version number, and call the `QrCode::encode_codewords()` constructor. 1115317bbafSopenharmony_ci/// 1125317bbafSopenharmony_ci/// (Note that all ways require supplying the desired error correction level.) 1135317bbafSopenharmony_ci#[derive(Clone, PartialEq, Eq)] 1145317bbafSopenharmony_cipub struct QrCode { 1155317bbafSopenharmony_ci 1165317bbafSopenharmony_ci // Scalar parameters: 1175317bbafSopenharmony_ci 1185317bbafSopenharmony_ci // The version number of this QR Code, which is between 1 and 40 (inclusive). 1195317bbafSopenharmony_ci // This determines the size of this barcode. 1205317bbafSopenharmony_ci version: Version, 1215317bbafSopenharmony_ci 1225317bbafSopenharmony_ci // The width and height of this QR Code, measured in modules, between 1235317bbafSopenharmony_ci // 21 and 177 (inclusive). This is equal to version * 4 + 17. 1245317bbafSopenharmony_ci size: i32, 1255317bbafSopenharmony_ci 1265317bbafSopenharmony_ci // The error correction level used in this QR Code. 1275317bbafSopenharmony_ci errorcorrectionlevel: QrCodeEcc, 1285317bbafSopenharmony_ci 1295317bbafSopenharmony_ci // The index of the mask pattern used in this QR Code, which is between 0 and 7 (inclusive). 1305317bbafSopenharmony_ci // Even if a QR Code is created with automatic masking requested (mask = None), 1315317bbafSopenharmony_ci // the resulting object still has a mask value between 0 and 7. 1325317bbafSopenharmony_ci mask: Mask, 1335317bbafSopenharmony_ci 1345317bbafSopenharmony_ci // Grids of modules/pixels, with dimensions of size*size: 1355317bbafSopenharmony_ci 1365317bbafSopenharmony_ci // The modules of this QR Code (false = light, true = dark). 1375317bbafSopenharmony_ci // Immutable after constructor finishes. Accessed through get_module(). 1385317bbafSopenharmony_ci modules: Vec<bool>, 1395317bbafSopenharmony_ci 1405317bbafSopenharmony_ci // Indicates function modules that are not subjected to masking. Discarded when constructor finishes. 1415317bbafSopenharmony_ci isfunction: Vec<bool>, 1425317bbafSopenharmony_ci 1435317bbafSopenharmony_ci} 1445317bbafSopenharmony_ci 1455317bbafSopenharmony_ci 1465317bbafSopenharmony_ciimpl QrCode { 1475317bbafSopenharmony_ci 1485317bbafSopenharmony_ci /*---- Static factory functions (high level) ----*/ 1495317bbafSopenharmony_ci 1505317bbafSopenharmony_ci /// Returns a QR Code representing the given Unicode text string at the given error correction level. 1515317bbafSopenharmony_ci /// 1525317bbafSopenharmony_ci /// As a conservative upper bound, this function is guaranteed to succeed for strings that have 738 or fewer Unicode 1535317bbafSopenharmony_ci /// code points (not UTF-8 code units) if the low error correction level is used. The smallest possible 1545317bbafSopenharmony_ci /// QR Code version is automatically chosen for the output. The ECC level of the result may be higher than 1555317bbafSopenharmony_ci /// the ecl argument if it can be done without increasing the version. 1565317bbafSopenharmony_ci /// 1575317bbafSopenharmony_ci /// Returns a wrapped `QrCode` if successful, or `Err` if the 1585317bbafSopenharmony_ci /// data is too long to fit in any version at the given ECC level. 1595317bbafSopenharmony_ci pub fn encode_text(text: &str, ecl: QrCodeEcc) -> Result<Self,DataTooLong> { 1605317bbafSopenharmony_ci let segs: Vec<QrSegment> = QrSegment::make_segments(text); 1615317bbafSopenharmony_ci QrCode::encode_segments(&segs, ecl) 1625317bbafSopenharmony_ci } 1635317bbafSopenharmony_ci 1645317bbafSopenharmony_ci 1655317bbafSopenharmony_ci /// Returns a QR Code representing the given binary data at the given error correction level. 1665317bbafSopenharmony_ci /// 1675317bbafSopenharmony_ci /// This function always encodes using the binary segment mode, not any text mode. The maximum number of 1685317bbafSopenharmony_ci /// bytes allowed is 2953. The smallest possible QR Code version is automatically chosen for the output. 1695317bbafSopenharmony_ci /// The ECC level of the result may be higher than the ecl argument if it can be done without increasing the version. 1705317bbafSopenharmony_ci /// 1715317bbafSopenharmony_ci /// Returns a wrapped `QrCode` if successful, or `Err` if the 1725317bbafSopenharmony_ci /// data is too long to fit in any version at the given ECC level. 1735317bbafSopenharmony_ci pub fn encode_binary(data: &[u8], ecl: QrCodeEcc) -> Result<Self,DataTooLong> { 1745317bbafSopenharmony_ci let segs: [QrSegment; 1] = [QrSegment::make_bytes(data)]; 1755317bbafSopenharmony_ci QrCode::encode_segments(&segs, ecl) 1765317bbafSopenharmony_ci } 1775317bbafSopenharmony_ci 1785317bbafSopenharmony_ci 1795317bbafSopenharmony_ci /*---- Static factory functions (mid level) ----*/ 1805317bbafSopenharmony_ci 1815317bbafSopenharmony_ci /// Returns a QR Code representing the given segments at the given error correction level. 1825317bbafSopenharmony_ci /// 1835317bbafSopenharmony_ci /// The smallest possible QR Code version is automatically chosen for the output. The ECC level 1845317bbafSopenharmony_ci /// of the result may be higher than the ecl argument if it can be done without increasing the version. 1855317bbafSopenharmony_ci /// 1865317bbafSopenharmony_ci /// This function allows the user to create a custom sequence of segments that switches 1875317bbafSopenharmony_ci /// between modes (such as alphanumeric and byte) to encode text in less space. 1885317bbafSopenharmony_ci /// This is a mid-level API; the high-level API is `encode_text()` and `encode_binary()`. 1895317bbafSopenharmony_ci /// 1905317bbafSopenharmony_ci /// Returns a wrapped `QrCode` if successful, or `Err` if the 1915317bbafSopenharmony_ci /// data is too long to fit in any version at the given ECC level. 1925317bbafSopenharmony_ci pub fn encode_segments(segs: &[QrSegment], ecl: QrCodeEcc) -> Result<Self,DataTooLong> { 1935317bbafSopenharmony_ci QrCode::encode_segments_advanced(segs, ecl, Version::MIN, Version::MAX, None, true) 1945317bbafSopenharmony_ci } 1955317bbafSopenharmony_ci 1965317bbafSopenharmony_ci 1975317bbafSopenharmony_ci /// Returns a QR Code representing the given segments with the given encoding parameters. 1985317bbafSopenharmony_ci /// 1995317bbafSopenharmony_ci /// The smallest possible QR Code version within the given range is automatically 2005317bbafSopenharmony_ci /// chosen for the output. Iff boostecl is `true`, then the ECC level of the result 2015317bbafSopenharmony_ci /// may be higher than the ecl argument if it can be done without increasing the 2025317bbafSopenharmony_ci /// version. The mask number is either between 0 to 7 (inclusive) to force that 2035317bbafSopenharmony_ci /// mask, or `None` to automatically choose an appropriate mask (which may be slow). 2045317bbafSopenharmony_ci /// 2055317bbafSopenharmony_ci /// This function allows the user to create a custom sequence of segments that switches 2065317bbafSopenharmony_ci /// between modes (such as alphanumeric and byte) to encode text in less space. 2075317bbafSopenharmony_ci /// This is a mid-level API; the high-level API is `encode_text()` and `encode_binary()`. 2085317bbafSopenharmony_ci /// 2095317bbafSopenharmony_ci /// Returns a wrapped `QrCode` if successful, or `Err` if the data is too 2105317bbafSopenharmony_ci /// long to fit in any version in the given range at the given ECC level. 2115317bbafSopenharmony_ci pub fn encode_segments_advanced(segs: &[QrSegment], mut ecl: QrCodeEcc, 2125317bbafSopenharmony_ci minversion: Version, maxversion: Version, mask: Option<Mask>, boostecl: bool) 2135317bbafSopenharmony_ci -> Result<Self,DataTooLong> { 2145317bbafSopenharmony_ci 2155317bbafSopenharmony_ci assert!(minversion <= maxversion, "Invalid value"); 2165317bbafSopenharmony_ci 2175317bbafSopenharmony_ci // Find the minimal version number to use 2185317bbafSopenharmony_ci let mut version: Version = minversion; 2195317bbafSopenharmony_ci let datausedbits: usize = loop { 2205317bbafSopenharmony_ci let datacapacitybits: usize = QrCode::get_num_data_codewords(version, ecl) * 8; // Number of data bits available 2215317bbafSopenharmony_ci let dataused: Option<usize> = QrSegment::get_total_bits(segs, version); 2225317bbafSopenharmony_ci if dataused.map_or(false, |n| n <= datacapacitybits) { 2235317bbafSopenharmony_ci break dataused.unwrap(); // This version number is found to be suitable 2245317bbafSopenharmony_ci } else if version >= maxversion { // All versions in the range could not fit the given data 2255317bbafSopenharmony_ci return Err(match dataused { 2265317bbafSopenharmony_ci None => DataTooLong::SegmentTooLong, 2275317bbafSopenharmony_ci Some(n) => DataTooLong::DataOverCapacity(n, datacapacitybits), 2285317bbafSopenharmony_ci }); 2295317bbafSopenharmony_ci } else { 2305317bbafSopenharmony_ci version = Version::new(version.value() + 1); 2315317bbafSopenharmony_ci } 2325317bbafSopenharmony_ci }; 2335317bbafSopenharmony_ci 2345317bbafSopenharmony_ci // Increase the error correction level while the data still fits in the current version number 2355317bbafSopenharmony_ci for &newecl in &[QrCodeEcc::Medium, QrCodeEcc::Quartile, QrCodeEcc::High] { // From low to high 2365317bbafSopenharmony_ci if boostecl && datausedbits <= QrCode::get_num_data_codewords(version, newecl) * 8 { 2375317bbafSopenharmony_ci ecl = newecl; 2385317bbafSopenharmony_ci } 2395317bbafSopenharmony_ci } 2405317bbafSopenharmony_ci 2415317bbafSopenharmony_ci // Concatenate all segments to create the data bit string 2425317bbafSopenharmony_ci let mut bb = BitBuffer(Vec::new()); 2435317bbafSopenharmony_ci for seg in segs { 2445317bbafSopenharmony_ci bb.append_bits(seg.mode.mode_bits(), 4); 2455317bbafSopenharmony_ci bb.append_bits(u32::try_from(seg.numchars).unwrap(), seg.mode.num_char_count_bits(version)); 2465317bbafSopenharmony_ci bb.0.extend_from_slice(&seg.data); 2475317bbafSopenharmony_ci } 2485317bbafSopenharmony_ci debug_assert_eq!(bb.0.len(), datausedbits); 2495317bbafSopenharmony_ci 2505317bbafSopenharmony_ci // Add terminator and pad up to a byte if applicable 2515317bbafSopenharmony_ci let datacapacitybits: usize = QrCode::get_num_data_codewords(version, ecl) * 8; 2525317bbafSopenharmony_ci debug_assert!(bb.0.len() <= datacapacitybits); 2535317bbafSopenharmony_ci let numzerobits: usize = std::cmp::min(4, datacapacitybits - bb.0.len()); 2545317bbafSopenharmony_ci bb.append_bits(0, u8::try_from(numzerobits).unwrap()); 2555317bbafSopenharmony_ci let numzerobits: usize = bb.0.len().wrapping_neg() & 7; 2565317bbafSopenharmony_ci bb.append_bits(0, u8::try_from(numzerobits).unwrap()); 2575317bbafSopenharmony_ci debug_assert_eq!(bb.0.len() % 8, 0); 2585317bbafSopenharmony_ci 2595317bbafSopenharmony_ci // Pad with alternating bytes until data capacity is reached 2605317bbafSopenharmony_ci for &padbyte in [0xEC, 0x11].iter().cycle() { 2615317bbafSopenharmony_ci if bb.0.len() >= datacapacitybits { 2625317bbafSopenharmony_ci break; 2635317bbafSopenharmony_ci } 2645317bbafSopenharmony_ci bb.append_bits(padbyte, 8); 2655317bbafSopenharmony_ci } 2665317bbafSopenharmony_ci 2675317bbafSopenharmony_ci // Pack bits into bytes in big endian 2685317bbafSopenharmony_ci let mut datacodewords = vec![0u8; bb.0.len() / 8]; 2695317bbafSopenharmony_ci for (i, &bit) in bb.0.iter().enumerate() { 2705317bbafSopenharmony_ci datacodewords[i >> 3] |= u8::from(bit) << (7 - (i & 7)); 2715317bbafSopenharmony_ci } 2725317bbafSopenharmony_ci 2735317bbafSopenharmony_ci // Create the QR Code object 2745317bbafSopenharmony_ci Ok(QrCode::encode_codewords(version, ecl, &datacodewords, mask)) 2755317bbafSopenharmony_ci } 2765317bbafSopenharmony_ci 2775317bbafSopenharmony_ci 2785317bbafSopenharmony_ci /*---- Constructor (low level) ----*/ 2795317bbafSopenharmony_ci 2805317bbafSopenharmony_ci /// Creates a new QR Code with the given version number, 2815317bbafSopenharmony_ci /// error correction level, data codeword bytes, and mask number. 2825317bbafSopenharmony_ci /// 2835317bbafSopenharmony_ci /// This is a low-level API that most users should not use directly. 2845317bbafSopenharmony_ci /// A mid-level API is the `encode_segments()` function. 2855317bbafSopenharmony_ci pub fn encode_codewords(ver: Version, ecl: QrCodeEcc, datacodewords: &[u8], mut msk: Option<Mask>) -> Self { 2865317bbafSopenharmony_ci // Initialize fields 2875317bbafSopenharmony_ci let size = usize::from(ver.value()) * 4 + 17; 2885317bbafSopenharmony_ci let mut result = Self { 2895317bbafSopenharmony_ci version: ver, 2905317bbafSopenharmony_ci size: size as i32, 2915317bbafSopenharmony_ci mask: Mask::new(0), // Dummy value 2925317bbafSopenharmony_ci errorcorrectionlevel: ecl, 2935317bbafSopenharmony_ci modules : vec![false; size * size], // Initially all light 2945317bbafSopenharmony_ci isfunction: vec![false; size * size], 2955317bbafSopenharmony_ci }; 2965317bbafSopenharmony_ci 2975317bbafSopenharmony_ci // Compute ECC, draw modules 2985317bbafSopenharmony_ci result.draw_function_patterns(); 2995317bbafSopenharmony_ci let allcodewords: Vec<u8> = result.add_ecc_and_interleave(datacodewords); 3005317bbafSopenharmony_ci result.draw_codewords(&allcodewords); 3015317bbafSopenharmony_ci 3025317bbafSopenharmony_ci // Do masking 3035317bbafSopenharmony_ci if msk.is_none() { // Automatically choose best mask 3045317bbafSopenharmony_ci let mut minpenalty = std::i32::MAX; 3055317bbafSopenharmony_ci for i in 0u8 .. 8 { 3065317bbafSopenharmony_ci let i = Mask::new(i); 3075317bbafSopenharmony_ci result.apply_mask(i); 3085317bbafSopenharmony_ci result.draw_format_bits(i); 3095317bbafSopenharmony_ci let penalty: i32 = result.get_penalty_score(); 3105317bbafSopenharmony_ci if penalty < minpenalty { 3115317bbafSopenharmony_ci msk = Some(i); 3125317bbafSopenharmony_ci minpenalty = penalty; 3135317bbafSopenharmony_ci } 3145317bbafSopenharmony_ci result.apply_mask(i); // Undoes the mask due to XOR 3155317bbafSopenharmony_ci } 3165317bbafSopenharmony_ci } 3175317bbafSopenharmony_ci let msk: Mask = msk.unwrap(); 3185317bbafSopenharmony_ci result.mask = msk; 3195317bbafSopenharmony_ci result.apply_mask(msk); // Apply the final choice of mask 3205317bbafSopenharmony_ci result.draw_format_bits(msk); // Overwrite old format bits 3215317bbafSopenharmony_ci 3225317bbafSopenharmony_ci result.isfunction.clear(); 3235317bbafSopenharmony_ci result.isfunction.shrink_to_fit(); 3245317bbafSopenharmony_ci result 3255317bbafSopenharmony_ci } 3265317bbafSopenharmony_ci 3275317bbafSopenharmony_ci 3285317bbafSopenharmony_ci /*---- Public methods ----*/ 3295317bbafSopenharmony_ci 3305317bbafSopenharmony_ci /// Returns this QR Code's version, in the range [1, 40]. 3315317bbafSopenharmony_ci pub fn version(&self) -> Version { 3325317bbafSopenharmony_ci self.version 3335317bbafSopenharmony_ci } 3345317bbafSopenharmony_ci 3355317bbafSopenharmony_ci 3365317bbafSopenharmony_ci /// Returns this QR Code's size, in the range [21, 177]. 3375317bbafSopenharmony_ci pub fn size(&self) -> i32 { 3385317bbafSopenharmony_ci self.size 3395317bbafSopenharmony_ci } 3405317bbafSopenharmony_ci 3415317bbafSopenharmony_ci 3425317bbafSopenharmony_ci /// Returns this QR Code's error correction level. 3435317bbafSopenharmony_ci pub fn error_correction_level(&self) -> QrCodeEcc { 3445317bbafSopenharmony_ci self.errorcorrectionlevel 3455317bbafSopenharmony_ci } 3465317bbafSopenharmony_ci 3475317bbafSopenharmony_ci 3485317bbafSopenharmony_ci /// Returns this QR Code's mask, in the range [0, 7]. 3495317bbafSopenharmony_ci pub fn mask(&self) -> Mask { 3505317bbafSopenharmony_ci self.mask 3515317bbafSopenharmony_ci } 3525317bbafSopenharmony_ci 3535317bbafSopenharmony_ci 3545317bbafSopenharmony_ci /// Returns the color of the module (pixel) at the given coordinates, 3555317bbafSopenharmony_ci /// which is `false` for light or `true` for dark. 3565317bbafSopenharmony_ci /// 3575317bbafSopenharmony_ci /// The top left corner has the coordinates (x=0, y=0). If the given 3585317bbafSopenharmony_ci /// coordinates are out of bounds, then `false` (light) is returned. 3595317bbafSopenharmony_ci pub fn get_module(&self, x: i32, y: i32) -> bool { 3605317bbafSopenharmony_ci (0 .. self.size).contains(&x) && (0 .. self.size).contains(&y) && self.module(x, y) 3615317bbafSopenharmony_ci } 3625317bbafSopenharmony_ci 3635317bbafSopenharmony_ci 3645317bbafSopenharmony_ci // Returns the color of the module at the given coordinates, which must be in bounds. 3655317bbafSopenharmony_ci fn module(&self, x: i32, y: i32) -> bool { 3665317bbafSopenharmony_ci self.modules[(y * self.size + x) as usize] 3675317bbafSopenharmony_ci } 3685317bbafSopenharmony_ci 3695317bbafSopenharmony_ci 3705317bbafSopenharmony_ci // Returns a mutable reference to the module's color at the given coordinates, which must be in bounds. 3715317bbafSopenharmony_ci fn module_mut(&mut self, x: i32, y: i32) -> &mut bool { 3725317bbafSopenharmony_ci &mut self.modules[(y * self.size + x) as usize] 3735317bbafSopenharmony_ci } 3745317bbafSopenharmony_ci 3755317bbafSopenharmony_ci 3765317bbafSopenharmony_ci /*---- Private helper methods for constructor: Drawing function modules ----*/ 3775317bbafSopenharmony_ci 3785317bbafSopenharmony_ci // Reads this object's version field, and draws and marks all function modules. 3795317bbafSopenharmony_ci fn draw_function_patterns(&mut self) { 3805317bbafSopenharmony_ci // Draw horizontal and vertical timing patterns 3815317bbafSopenharmony_ci let size: i32 = self.size; 3825317bbafSopenharmony_ci for i in 0 .. size { 3835317bbafSopenharmony_ci self.set_function_module(6, i, i % 2 == 0); 3845317bbafSopenharmony_ci self.set_function_module(i, 6, i % 2 == 0); 3855317bbafSopenharmony_ci } 3865317bbafSopenharmony_ci 3875317bbafSopenharmony_ci // Draw 3 finder patterns (all corners except bottom right; overwrites some timing modules) 3885317bbafSopenharmony_ci self.draw_finder_pattern(3, 3); 3895317bbafSopenharmony_ci self.draw_finder_pattern(size - 4, 3); 3905317bbafSopenharmony_ci self.draw_finder_pattern(3, size - 4); 3915317bbafSopenharmony_ci 3925317bbafSopenharmony_ci // Draw numerous alignment patterns 3935317bbafSopenharmony_ci let alignpatpos: Vec<i32> = self.get_alignment_pattern_positions(); 3945317bbafSopenharmony_ci let numalign: usize = alignpatpos.len(); 3955317bbafSopenharmony_ci for i in 0 .. numalign { 3965317bbafSopenharmony_ci for j in 0 .. numalign { 3975317bbafSopenharmony_ci // Don't draw on the three finder corners 3985317bbafSopenharmony_ci if !(i == 0 && j == 0 || i == 0 && j == numalign - 1 || i == numalign - 1 && j == 0) { 3995317bbafSopenharmony_ci self.draw_alignment_pattern(alignpatpos[i], alignpatpos[j]); 4005317bbafSopenharmony_ci } 4015317bbafSopenharmony_ci } 4025317bbafSopenharmony_ci } 4035317bbafSopenharmony_ci 4045317bbafSopenharmony_ci // Draw configuration data 4055317bbafSopenharmony_ci self.draw_format_bits(Mask::new(0)); // Dummy mask value; overwritten later in the constructor 4065317bbafSopenharmony_ci self.draw_version(); 4075317bbafSopenharmony_ci } 4085317bbafSopenharmony_ci 4095317bbafSopenharmony_ci 4105317bbafSopenharmony_ci // Draws two copies of the format bits (with its own error correction code) 4115317bbafSopenharmony_ci // based on the given mask and this object's error correction level field. 4125317bbafSopenharmony_ci fn draw_format_bits(&mut self, mask: Mask) { 4135317bbafSopenharmony_ci // Calculate error correction code and pack bits 4145317bbafSopenharmony_ci let bits: u32 = { 4155317bbafSopenharmony_ci // errcorrlvl is uint2, mask is uint3 4165317bbafSopenharmony_ci let data: u32 = u32::from(self.errorcorrectionlevel.format_bits() << 3 | mask.value()); 4175317bbafSopenharmony_ci let mut rem: u32 = data; 4185317bbafSopenharmony_ci for _ in 0 .. 10 { 4195317bbafSopenharmony_ci rem = (rem << 1) ^ ((rem >> 9) * 0x537); 4205317bbafSopenharmony_ci } 4215317bbafSopenharmony_ci (data << 10 | rem) ^ 0x5412 // uint15 4225317bbafSopenharmony_ci }; 4235317bbafSopenharmony_ci debug_assert_eq!(bits >> 15, 0); 4245317bbafSopenharmony_ci 4255317bbafSopenharmony_ci // Draw first copy 4265317bbafSopenharmony_ci for i in 0 .. 6 { 4275317bbafSopenharmony_ci self.set_function_module(8, i, get_bit(bits, i)); 4285317bbafSopenharmony_ci } 4295317bbafSopenharmony_ci self.set_function_module(8, 7, get_bit(bits, 6)); 4305317bbafSopenharmony_ci self.set_function_module(8, 8, get_bit(bits, 7)); 4315317bbafSopenharmony_ci self.set_function_module(7, 8, get_bit(bits, 8)); 4325317bbafSopenharmony_ci for i in 9 .. 15 { 4335317bbafSopenharmony_ci self.set_function_module(14 - i, 8, get_bit(bits, i)); 4345317bbafSopenharmony_ci } 4355317bbafSopenharmony_ci 4365317bbafSopenharmony_ci // Draw second copy 4375317bbafSopenharmony_ci let size: i32 = self.size; 4385317bbafSopenharmony_ci for i in 0 .. 8 { 4395317bbafSopenharmony_ci self.set_function_module(size - 1 - i, 8, get_bit(bits, i)); 4405317bbafSopenharmony_ci } 4415317bbafSopenharmony_ci for i in 8 .. 15 { 4425317bbafSopenharmony_ci self.set_function_module(8, size - 15 + i, get_bit(bits, i)); 4435317bbafSopenharmony_ci } 4445317bbafSopenharmony_ci self.set_function_module(8, size - 8, true); // Always dark 4455317bbafSopenharmony_ci } 4465317bbafSopenharmony_ci 4475317bbafSopenharmony_ci 4485317bbafSopenharmony_ci // Draws two copies of the version bits (with its own error correction code), 4495317bbafSopenharmony_ci // based on this object's version field, iff 7 <= version <= 40. 4505317bbafSopenharmony_ci fn draw_version(&mut self) { 4515317bbafSopenharmony_ci if self.version.value() < 7 { 4525317bbafSopenharmony_ci return; 4535317bbafSopenharmony_ci } 4545317bbafSopenharmony_ci 4555317bbafSopenharmony_ci // Calculate error correction code and pack bits 4565317bbafSopenharmony_ci let bits: u32 = { 4575317bbafSopenharmony_ci let data = u32::from(self.version.value()); // uint6, in the range [7, 40] 4585317bbafSopenharmony_ci let mut rem: u32 = data; 4595317bbafSopenharmony_ci for _ in 0 .. 12 { 4605317bbafSopenharmony_ci rem = (rem << 1) ^ ((rem >> 11) * 0x1F25); 4615317bbafSopenharmony_ci } 4625317bbafSopenharmony_ci data << 12 | rem // uint18 4635317bbafSopenharmony_ci }; 4645317bbafSopenharmony_ci debug_assert_eq!(bits >> 18, 0); 4655317bbafSopenharmony_ci 4665317bbafSopenharmony_ci // Draw two copies 4675317bbafSopenharmony_ci for i in 0 .. 18 { 4685317bbafSopenharmony_ci let bit: bool = get_bit(bits, i); 4695317bbafSopenharmony_ci let a: i32 = self.size - 11 + i % 3; 4705317bbafSopenharmony_ci let b: i32 = i / 3; 4715317bbafSopenharmony_ci self.set_function_module(a, b, bit); 4725317bbafSopenharmony_ci self.set_function_module(b, a, bit); 4735317bbafSopenharmony_ci } 4745317bbafSopenharmony_ci } 4755317bbafSopenharmony_ci 4765317bbafSopenharmony_ci 4775317bbafSopenharmony_ci // Draws a 9*9 finder pattern including the border separator, 4785317bbafSopenharmony_ci // with the center module at (x, y). Modules can be out of bounds. 4795317bbafSopenharmony_ci fn draw_finder_pattern(&mut self, x: i32, y: i32) { 4805317bbafSopenharmony_ci for dy in -4 ..= 4 { 4815317bbafSopenharmony_ci for dx in -4 ..= 4 { 4825317bbafSopenharmony_ci let xx: i32 = x + dx; 4835317bbafSopenharmony_ci let yy: i32 = y + dy; 4845317bbafSopenharmony_ci if (0 .. self.size).contains(&xx) && (0 .. self.size).contains(&yy) { 4855317bbafSopenharmony_ci let dist: i32 = std::cmp::max(dx.abs(), dy.abs()); // Chebyshev/infinity norm 4865317bbafSopenharmony_ci self.set_function_module(xx, yy, dist != 2 && dist != 4); 4875317bbafSopenharmony_ci } 4885317bbafSopenharmony_ci } 4895317bbafSopenharmony_ci } 4905317bbafSopenharmony_ci } 4915317bbafSopenharmony_ci 4925317bbafSopenharmony_ci 4935317bbafSopenharmony_ci // Draws a 5*5 alignment pattern, with the center module 4945317bbafSopenharmony_ci // at (x, y). All modules must be in bounds. 4955317bbafSopenharmony_ci fn draw_alignment_pattern(&mut self, x: i32, y: i32) { 4965317bbafSopenharmony_ci for dy in -2 ..= 2 { 4975317bbafSopenharmony_ci for dx in -2 ..= 2 { 4985317bbafSopenharmony_ci self.set_function_module(x + dx, y + dy, std::cmp::max(dx.abs(), dy.abs()) != 1); 4995317bbafSopenharmony_ci } 5005317bbafSopenharmony_ci } 5015317bbafSopenharmony_ci } 5025317bbafSopenharmony_ci 5035317bbafSopenharmony_ci 5045317bbafSopenharmony_ci // Sets the color of a module and marks it as a function module. 5055317bbafSopenharmony_ci // Only used by the constructor. Coordinates must be in bounds. 5065317bbafSopenharmony_ci fn set_function_module(&mut self, x: i32, y: i32, isdark: bool) { 5075317bbafSopenharmony_ci *self.module_mut(x, y) = isdark; 5085317bbafSopenharmony_ci self.isfunction[(y * self.size + x) as usize] = true; 5095317bbafSopenharmony_ci } 5105317bbafSopenharmony_ci 5115317bbafSopenharmony_ci 5125317bbafSopenharmony_ci /*---- Private helper methods for constructor: Codewords and masking ----*/ 5135317bbafSopenharmony_ci 5145317bbafSopenharmony_ci // Returns a new byte string representing the given data with the appropriate error correction 5155317bbafSopenharmony_ci // codewords appended to it, based on this object's version and error correction level. 5165317bbafSopenharmony_ci fn add_ecc_and_interleave(&self, data: &[u8]) -> Vec<u8> { 5175317bbafSopenharmony_ci let ver: Version = self.version; 5185317bbafSopenharmony_ci let ecl: QrCodeEcc = self.errorcorrectionlevel; 5195317bbafSopenharmony_ci assert_eq!(data.len(), QrCode::get_num_data_codewords(ver, ecl), "Illegal argument"); 5205317bbafSopenharmony_ci 5215317bbafSopenharmony_ci // Calculate parameter numbers 5225317bbafSopenharmony_ci let numblocks: usize = QrCode::table_get(&NUM_ERROR_CORRECTION_BLOCKS, ver, ecl); 5235317bbafSopenharmony_ci let blockecclen: usize = QrCode::table_get(&ECC_CODEWORDS_PER_BLOCK , ver, ecl); 5245317bbafSopenharmony_ci let rawcodewords: usize = QrCode::get_num_raw_data_modules(ver) / 8; 5255317bbafSopenharmony_ci let numshortblocks: usize = numblocks - rawcodewords % numblocks; 5265317bbafSopenharmony_ci let shortblocklen: usize = rawcodewords / numblocks; 5275317bbafSopenharmony_ci 5285317bbafSopenharmony_ci // Split data into blocks and append ECC to each block 5295317bbafSopenharmony_ci let mut blocks = Vec::<Vec<u8>>::with_capacity(numblocks); 5305317bbafSopenharmony_ci let rsdiv: Vec<u8> = QrCode::reed_solomon_compute_divisor(blockecclen); 5315317bbafSopenharmony_ci let mut k: usize = 0; 5325317bbafSopenharmony_ci for i in 0 .. numblocks { 5335317bbafSopenharmony_ci let datlen: usize = shortblocklen - blockecclen + usize::from(i >= numshortblocks); 5345317bbafSopenharmony_ci let mut dat = data[k .. k+datlen].to_vec(); 5355317bbafSopenharmony_ci k += datlen; 5365317bbafSopenharmony_ci let ecc: Vec<u8> = QrCode::reed_solomon_compute_remainder(&dat, &rsdiv); 5375317bbafSopenharmony_ci if i < numshortblocks { 5385317bbafSopenharmony_ci dat.push(0); 5395317bbafSopenharmony_ci } 5405317bbafSopenharmony_ci dat.extend_from_slice(&ecc); 5415317bbafSopenharmony_ci blocks.push(dat); 5425317bbafSopenharmony_ci } 5435317bbafSopenharmony_ci 5445317bbafSopenharmony_ci // Interleave (not concatenate) the bytes from every block into a single sequence 5455317bbafSopenharmony_ci let mut result = Vec::<u8>::with_capacity(rawcodewords); 5465317bbafSopenharmony_ci for i in 0 ..= shortblocklen { 5475317bbafSopenharmony_ci for (j, block) in blocks.iter().enumerate() { 5485317bbafSopenharmony_ci // Skip the padding byte in short blocks 5495317bbafSopenharmony_ci if i != shortblocklen - blockecclen || j >= numshortblocks { 5505317bbafSopenharmony_ci result.push(block[i]); 5515317bbafSopenharmony_ci } 5525317bbafSopenharmony_ci } 5535317bbafSopenharmony_ci } 5545317bbafSopenharmony_ci result 5555317bbafSopenharmony_ci } 5565317bbafSopenharmony_ci 5575317bbafSopenharmony_ci 5585317bbafSopenharmony_ci // Draws the given sequence of 8-bit codewords (data and error correction) onto the entire 5595317bbafSopenharmony_ci // data area of this QR Code. Function modules need to be marked off before this is called. 5605317bbafSopenharmony_ci fn draw_codewords(&mut self, data: &[u8]) { 5615317bbafSopenharmony_ci assert_eq!(data.len(), QrCode::get_num_raw_data_modules(self.version) / 8, "Illegal argument"); 5625317bbafSopenharmony_ci 5635317bbafSopenharmony_ci let mut i: usize = 0; // Bit index into the data 5645317bbafSopenharmony_ci // Do the funny zigzag scan 5655317bbafSopenharmony_ci let mut right: i32 = self.size - 1; 5665317bbafSopenharmony_ci while right >= 1 { // Index of right column in each column pair 5675317bbafSopenharmony_ci if right == 6 { 5685317bbafSopenharmony_ci right = 5; 5695317bbafSopenharmony_ci } 5705317bbafSopenharmony_ci for vert in 0 .. self.size { // Vertical counter 5715317bbafSopenharmony_ci for j in 0 .. 2 { 5725317bbafSopenharmony_ci let x: i32 = right - j; // Actual x coordinate 5735317bbafSopenharmony_ci let upward: bool = (right + 1) & 2 == 0; 5745317bbafSopenharmony_ci let y: i32 = if upward { self.size - 1 - vert } else { vert }; // Actual y coordinate 5755317bbafSopenharmony_ci if !self.isfunction[(y * self.size + x) as usize] && i < data.len() * 8 { 5765317bbafSopenharmony_ci *self.module_mut(x, y) = get_bit(u32::from(data[i >> 3]), 7 - ((i as i32) & 7)); 5775317bbafSopenharmony_ci i += 1; 5785317bbafSopenharmony_ci } 5795317bbafSopenharmony_ci // If this QR Code has any remainder bits (0 to 7), they were assigned as 5805317bbafSopenharmony_ci // 0/false/light by the constructor and are left unchanged by this method 5815317bbafSopenharmony_ci } 5825317bbafSopenharmony_ci } 5835317bbafSopenharmony_ci right -= 2; 5845317bbafSopenharmony_ci } 5855317bbafSopenharmony_ci debug_assert_eq!(i, data.len() * 8); 5865317bbafSopenharmony_ci } 5875317bbafSopenharmony_ci 5885317bbafSopenharmony_ci 5895317bbafSopenharmony_ci // XORs the codeword modules in this QR Code with the given mask pattern. 5905317bbafSopenharmony_ci // The function modules must be marked and the codeword bits must be drawn 5915317bbafSopenharmony_ci // before masking. Due to the arithmetic of XOR, calling apply_mask() with 5925317bbafSopenharmony_ci // the same mask value a second time will undo the mask. A final well-formed 5935317bbafSopenharmony_ci // QR Code needs exactly one (not zero, two, etc.) mask applied. 5945317bbafSopenharmony_ci fn apply_mask(&mut self, mask: Mask) { 5955317bbafSopenharmony_ci for y in 0 .. self.size { 5965317bbafSopenharmony_ci for x in 0 .. self.size { 5975317bbafSopenharmony_ci let invert: bool = match mask.value() { 5985317bbafSopenharmony_ci 0 => (x + y) % 2 == 0, 5995317bbafSopenharmony_ci 1 => y % 2 == 0, 6005317bbafSopenharmony_ci 2 => x % 3 == 0, 6015317bbafSopenharmony_ci 3 => (x + y) % 3 == 0, 6025317bbafSopenharmony_ci 4 => (x / 3 + y / 2) % 2 == 0, 6035317bbafSopenharmony_ci 5 => x * y % 2 + x * y % 3 == 0, 6045317bbafSopenharmony_ci 6 => (x * y % 2 + x * y % 3) % 2 == 0, 6055317bbafSopenharmony_ci 7 => ((x + y) % 2 + x * y % 3) % 2 == 0, 6065317bbafSopenharmony_ci _ => unreachable!(), 6075317bbafSopenharmony_ci }; 6085317bbafSopenharmony_ci *self.module_mut(x, y) ^= invert & !self.isfunction[(y * self.size + x) as usize]; 6095317bbafSopenharmony_ci } 6105317bbafSopenharmony_ci } 6115317bbafSopenharmony_ci } 6125317bbafSopenharmony_ci 6135317bbafSopenharmony_ci 6145317bbafSopenharmony_ci // Calculates and returns the penalty score based on state of this QR Code's current modules. 6155317bbafSopenharmony_ci // This is used by the automatic mask choice algorithm to find the mask pattern that yields the lowest score. 6165317bbafSopenharmony_ci fn get_penalty_score(&self) -> i32 { 6175317bbafSopenharmony_ci let mut result: i32 = 0; 6185317bbafSopenharmony_ci let size: i32 = self.size; 6195317bbafSopenharmony_ci 6205317bbafSopenharmony_ci // Adjacent modules in row having same color, and finder-like patterns 6215317bbafSopenharmony_ci for y in 0 .. size { 6225317bbafSopenharmony_ci let mut runcolor = false; 6235317bbafSopenharmony_ci let mut runx: i32 = 0; 6245317bbafSopenharmony_ci let mut runhistory = FinderPenalty::new(size); 6255317bbafSopenharmony_ci for x in 0 .. size { 6265317bbafSopenharmony_ci if self.module(x, y) == runcolor { 6275317bbafSopenharmony_ci runx += 1; 6285317bbafSopenharmony_ci if runx == 5 { 6295317bbafSopenharmony_ci result += PENALTY_N1; 6305317bbafSopenharmony_ci } else if runx > 5 { 6315317bbafSopenharmony_ci result += 1; 6325317bbafSopenharmony_ci } 6335317bbafSopenharmony_ci } else { 6345317bbafSopenharmony_ci runhistory.add_history(runx); 6355317bbafSopenharmony_ci if !runcolor { 6365317bbafSopenharmony_ci result += runhistory.count_patterns() * PENALTY_N3; 6375317bbafSopenharmony_ci } 6385317bbafSopenharmony_ci runcolor = self.module(x, y); 6395317bbafSopenharmony_ci runx = 1; 6405317bbafSopenharmony_ci } 6415317bbafSopenharmony_ci } 6425317bbafSopenharmony_ci result += runhistory.terminate_and_count(runcolor, runx) * PENALTY_N3; 6435317bbafSopenharmony_ci } 6445317bbafSopenharmony_ci // Adjacent modules in column having same color, and finder-like patterns 6455317bbafSopenharmony_ci for x in 0 .. size { 6465317bbafSopenharmony_ci let mut runcolor = false; 6475317bbafSopenharmony_ci let mut runy: i32 = 0; 6485317bbafSopenharmony_ci let mut runhistory = FinderPenalty::new(size); 6495317bbafSopenharmony_ci for y in 0 .. size { 6505317bbafSopenharmony_ci if self.module(x, y) == runcolor { 6515317bbafSopenharmony_ci runy += 1; 6525317bbafSopenharmony_ci if runy == 5 { 6535317bbafSopenharmony_ci result += PENALTY_N1; 6545317bbafSopenharmony_ci } else if runy > 5 { 6555317bbafSopenharmony_ci result += 1; 6565317bbafSopenharmony_ci } 6575317bbafSopenharmony_ci } else { 6585317bbafSopenharmony_ci runhistory.add_history(runy); 6595317bbafSopenharmony_ci if !runcolor { 6605317bbafSopenharmony_ci result += runhistory.count_patterns() * PENALTY_N3; 6615317bbafSopenharmony_ci } 6625317bbafSopenharmony_ci runcolor = self.module(x, y); 6635317bbafSopenharmony_ci runy = 1; 6645317bbafSopenharmony_ci } 6655317bbafSopenharmony_ci } 6665317bbafSopenharmony_ci result += runhistory.terminate_and_count(runcolor, runy) * PENALTY_N3; 6675317bbafSopenharmony_ci } 6685317bbafSopenharmony_ci 6695317bbafSopenharmony_ci // 2*2 blocks of modules having same color 6705317bbafSopenharmony_ci for y in 0 .. size-1 { 6715317bbafSopenharmony_ci for x in 0 .. size-1 { 6725317bbafSopenharmony_ci let color: bool = self.module(x, y); 6735317bbafSopenharmony_ci if color == self.module(x + 1, y) && 6745317bbafSopenharmony_ci color == self.module(x, y + 1) && 6755317bbafSopenharmony_ci color == self.module(x + 1, y + 1) { 6765317bbafSopenharmony_ci result += PENALTY_N2; 6775317bbafSopenharmony_ci } 6785317bbafSopenharmony_ci } 6795317bbafSopenharmony_ci } 6805317bbafSopenharmony_ci 6815317bbafSopenharmony_ci // Balance of dark and light modules 6825317bbafSopenharmony_ci let dark: i32 = self.modules.iter().copied().map(i32::from).sum(); 6835317bbafSopenharmony_ci let total: i32 = size * size; // Note that size is odd, so dark/total != 1/2 6845317bbafSopenharmony_ci // Compute the smallest integer k >= 0 such that (45-5k)% <= dark/total <= (55+5k)% 6855317bbafSopenharmony_ci let k: i32 = ((dark * 20 - total * 10).abs() + total - 1) / total - 1; 6865317bbafSopenharmony_ci debug_assert!(0 <= k && k <= 9); 6875317bbafSopenharmony_ci result += k * PENALTY_N4; 6885317bbafSopenharmony_ci debug_assert!(0 <= result && result <= 2568888); // Non-tight upper bound based on default values of PENALTY_N1, ..., N4 6895317bbafSopenharmony_ci result 6905317bbafSopenharmony_ci } 6915317bbafSopenharmony_ci 6925317bbafSopenharmony_ci 6935317bbafSopenharmony_ci /*---- Private helper functions ----*/ 6945317bbafSopenharmony_ci 6955317bbafSopenharmony_ci // Returns an ascending list of positions of alignment patterns for this version number. 6965317bbafSopenharmony_ci // Each position is in the range [0,177), and are used on both the x and y axes. 6975317bbafSopenharmony_ci // This could be implemented as lookup table of 40 variable-length lists of unsigned bytes. 6985317bbafSopenharmony_ci fn get_alignment_pattern_positions(&self) -> Vec<i32> { 6995317bbafSopenharmony_ci let ver: u8 = self.version.value(); 7005317bbafSopenharmony_ci if ver == 1 { 7015317bbafSopenharmony_ci vec![] 7025317bbafSopenharmony_ci } else { 7035317bbafSopenharmony_ci let numalign = i32::from(ver) / 7 + 2; 7045317bbafSopenharmony_ci let step: i32 = if ver == 32 { 26 } else 7055317bbafSopenharmony_ci {(i32::from(ver) * 4 + numalign * 2 + 1) / (numalign * 2 - 2) * 2}; 7065317bbafSopenharmony_ci let mut result: Vec<i32> = (0 .. numalign-1).map( 7075317bbafSopenharmony_ci |i| self.size - 7 - i * step).collect(); 7085317bbafSopenharmony_ci result.push(6); 7095317bbafSopenharmony_ci result.reverse(); 7105317bbafSopenharmony_ci result 7115317bbafSopenharmony_ci } 7125317bbafSopenharmony_ci } 7135317bbafSopenharmony_ci 7145317bbafSopenharmony_ci 7155317bbafSopenharmony_ci // Returns the number of data bits that can be stored in a QR Code of the given version number, after 7165317bbafSopenharmony_ci // all function modules are excluded. This includes remainder bits, so it might not be a multiple of 8. 7175317bbafSopenharmony_ci // The result is in the range [208, 29648]. This could be implemented as a 40-entry lookup table. 7185317bbafSopenharmony_ci fn get_num_raw_data_modules(ver: Version) -> usize { 7195317bbafSopenharmony_ci let ver = usize::from(ver.value()); 7205317bbafSopenharmony_ci let mut result: usize = (16 * ver + 128) * ver + 64; 7215317bbafSopenharmony_ci if ver >= 2 { 7225317bbafSopenharmony_ci let numalign: usize = ver / 7 + 2; 7235317bbafSopenharmony_ci result -= (25 * numalign - 10) * numalign - 55; 7245317bbafSopenharmony_ci if ver >= 7 { 7255317bbafSopenharmony_ci result -= 36; 7265317bbafSopenharmony_ci } 7275317bbafSopenharmony_ci } 7285317bbafSopenharmony_ci debug_assert!((208 ..= 29648).contains(&result)); 7295317bbafSopenharmony_ci result 7305317bbafSopenharmony_ci } 7315317bbafSopenharmony_ci 7325317bbafSopenharmony_ci 7335317bbafSopenharmony_ci // Returns the number of 8-bit data (i.e. not error correction) codewords contained in any 7345317bbafSopenharmony_ci // QR Code of the given version number and error correction level, with remainder bits discarded. 7355317bbafSopenharmony_ci // This stateless pure function could be implemented as a (40*4)-cell lookup table. 7365317bbafSopenharmony_ci fn get_num_data_codewords(ver: Version, ecl: QrCodeEcc) -> usize { 7375317bbafSopenharmony_ci QrCode::get_num_raw_data_modules(ver) / 8 7385317bbafSopenharmony_ci - QrCode::table_get(&ECC_CODEWORDS_PER_BLOCK , ver, ecl) 7395317bbafSopenharmony_ci * QrCode::table_get(&NUM_ERROR_CORRECTION_BLOCKS, ver, ecl) 7405317bbafSopenharmony_ci } 7415317bbafSopenharmony_ci 7425317bbafSopenharmony_ci 7435317bbafSopenharmony_ci // Returns an entry from the given table based on the given values. 7445317bbafSopenharmony_ci fn table_get(table: &'static [[i8; 41]; 4], ver: Version, ecl: QrCodeEcc) -> usize { 7455317bbafSopenharmony_ci table[ecl.ordinal()][usize::from(ver.value())] as usize 7465317bbafSopenharmony_ci } 7475317bbafSopenharmony_ci 7485317bbafSopenharmony_ci 7495317bbafSopenharmony_ci // Returns a Reed-Solomon ECC generator polynomial for the given degree. This could be 7505317bbafSopenharmony_ci // implemented as a lookup table over all possible parameter values, instead of as an algorithm. 7515317bbafSopenharmony_ci fn reed_solomon_compute_divisor(degree: usize) -> Vec<u8> { 7525317bbafSopenharmony_ci assert!((1 ..= 255).contains(°ree), "Degree out of range"); 7535317bbafSopenharmony_ci // Polynomial coefficients are stored from highest to lowest power, excluding the leading term which is always 1. 7545317bbafSopenharmony_ci // For example the polynomial x^3 + 255x^2 + 8x + 93 is stored as the uint8 array [255, 8, 93]. 7555317bbafSopenharmony_ci let mut result = vec![0u8; degree - 1]; 7565317bbafSopenharmony_ci result.push(1); // Start off with the monomial x^0 7575317bbafSopenharmony_ci 7585317bbafSopenharmony_ci // Compute the product polynomial (x - r^0) * (x - r^1) * (x - r^2) * ... * (x - r^{degree-1}), 7595317bbafSopenharmony_ci // and drop the highest monomial term which is always 1x^degree. 7605317bbafSopenharmony_ci // Note that r = 0x02, which is a generator element of this field GF(2^8/0x11D). 7615317bbafSopenharmony_ci let mut root: u8 = 1; 7625317bbafSopenharmony_ci for _ in 0 .. degree { // Unused variable i 7635317bbafSopenharmony_ci // Multiply the current product by (x - r^i) 7645317bbafSopenharmony_ci for j in 0 .. degree { 7655317bbafSopenharmony_ci result[j] = QrCode::reed_solomon_multiply(result[j], root); 7665317bbafSopenharmony_ci if j + 1 < result.len() { 7675317bbafSopenharmony_ci result[j] ^= result[j + 1]; 7685317bbafSopenharmony_ci } 7695317bbafSopenharmony_ci } 7705317bbafSopenharmony_ci root = QrCode::reed_solomon_multiply(root, 0x02); 7715317bbafSopenharmony_ci } 7725317bbafSopenharmony_ci result 7735317bbafSopenharmony_ci } 7745317bbafSopenharmony_ci 7755317bbafSopenharmony_ci 7765317bbafSopenharmony_ci // Returns the Reed-Solomon error correction codeword for the given data and divisor polynomials. 7775317bbafSopenharmony_ci fn reed_solomon_compute_remainder(data: &[u8], divisor: &[u8]) -> Vec<u8> { 7785317bbafSopenharmony_ci let mut result = vec![0u8; divisor.len()]; 7795317bbafSopenharmony_ci for b in data { // Polynomial division 7805317bbafSopenharmony_ci let factor: u8 = b ^ result.remove(0); 7815317bbafSopenharmony_ci result.push(0); 7825317bbafSopenharmony_ci for (x, &y) in result.iter_mut().zip(divisor.iter()) { 7835317bbafSopenharmony_ci *x ^= QrCode::reed_solomon_multiply(y, factor); 7845317bbafSopenharmony_ci } 7855317bbafSopenharmony_ci } 7865317bbafSopenharmony_ci result 7875317bbafSopenharmony_ci } 7885317bbafSopenharmony_ci 7895317bbafSopenharmony_ci 7905317bbafSopenharmony_ci // Returns the product of the two given field elements modulo GF(2^8/0x11D). 7915317bbafSopenharmony_ci // All inputs are valid. This could be implemented as a 256*256 lookup table. 7925317bbafSopenharmony_ci fn reed_solomon_multiply(x: u8, y: u8) -> u8 { 7935317bbafSopenharmony_ci // Russian peasant multiplication 7945317bbafSopenharmony_ci let mut z: u8 = 0; 7955317bbafSopenharmony_ci for i in (0 .. 8).rev() { 7965317bbafSopenharmony_ci z = (z << 1) ^ ((z >> 7) * 0x1D); 7975317bbafSopenharmony_ci z ^= ((y >> i) & 1) * x; 7985317bbafSopenharmony_ci } 7995317bbafSopenharmony_ci z 8005317bbafSopenharmony_ci } 8015317bbafSopenharmony_ci 8025317bbafSopenharmony_ci} 8035317bbafSopenharmony_ci 8045317bbafSopenharmony_ci 8055317bbafSopenharmony_ci/*---- Helper struct for get_penalty_score() ----*/ 8065317bbafSopenharmony_ci 8075317bbafSopenharmony_cistruct FinderPenalty { 8085317bbafSopenharmony_ci qr_size: i32, 8095317bbafSopenharmony_ci run_history: [i32; 7], 8105317bbafSopenharmony_ci} 8115317bbafSopenharmony_ci 8125317bbafSopenharmony_ci 8135317bbafSopenharmony_ciimpl FinderPenalty { 8145317bbafSopenharmony_ci 8155317bbafSopenharmony_ci pub fn new(size: i32) -> Self { 8165317bbafSopenharmony_ci Self { 8175317bbafSopenharmony_ci qr_size: size, 8185317bbafSopenharmony_ci run_history: [0i32; 7], 8195317bbafSopenharmony_ci } 8205317bbafSopenharmony_ci } 8215317bbafSopenharmony_ci 8225317bbafSopenharmony_ci 8235317bbafSopenharmony_ci // Pushes the given value to the front and drops the last value. 8245317bbafSopenharmony_ci pub fn add_history(&mut self, mut currentrunlength: i32) { 8255317bbafSopenharmony_ci if self.run_history[0] == 0 { 8265317bbafSopenharmony_ci currentrunlength += self.qr_size; // Add light border to initial run 8275317bbafSopenharmony_ci } 8285317bbafSopenharmony_ci let rh = &mut self.run_history; 8295317bbafSopenharmony_ci for i in (0 .. rh.len()-1).rev() { 8305317bbafSopenharmony_ci rh[i + 1] = rh[i]; 8315317bbafSopenharmony_ci } 8325317bbafSopenharmony_ci rh[0] = currentrunlength; 8335317bbafSopenharmony_ci } 8345317bbafSopenharmony_ci 8355317bbafSopenharmony_ci 8365317bbafSopenharmony_ci // Can only be called immediately after a light run is added, and returns either 0, 1, or 2. 8375317bbafSopenharmony_ci pub fn count_patterns(&self) -> i32 { 8385317bbafSopenharmony_ci let rh = &self.run_history; 8395317bbafSopenharmony_ci let n = rh[1]; 8405317bbafSopenharmony_ci debug_assert!(n <= self.qr_size * 3); 8415317bbafSopenharmony_ci let core = n > 0 && rh[2] == n && rh[3] == n * 3 && rh[4] == n && rh[5] == n; 8425317bbafSopenharmony_ci ( i32::from(core && rh[0] >= n * 4 && rh[6] >= n) 8435317bbafSopenharmony_ci + i32::from(core && rh[6] >= n * 4 && rh[0] >= n)) 8445317bbafSopenharmony_ci } 8455317bbafSopenharmony_ci 8465317bbafSopenharmony_ci 8475317bbafSopenharmony_ci // Must be called at the end of a line (row or column) of modules. 8485317bbafSopenharmony_ci pub fn terminate_and_count(mut self, currentruncolor: bool, mut currentrunlength: i32) -> i32 { 8495317bbafSopenharmony_ci if currentruncolor { // Terminate dark run 8505317bbafSopenharmony_ci self.add_history(currentrunlength); 8515317bbafSopenharmony_ci currentrunlength = 0; 8525317bbafSopenharmony_ci } 8535317bbafSopenharmony_ci currentrunlength += self.qr_size; // Add light border to final run 8545317bbafSopenharmony_ci self.add_history(currentrunlength); 8555317bbafSopenharmony_ci self.count_patterns() 8565317bbafSopenharmony_ci } 8575317bbafSopenharmony_ci 8585317bbafSopenharmony_ci} 8595317bbafSopenharmony_ci 8605317bbafSopenharmony_ci 8615317bbafSopenharmony_ci/*---- Constants and tables ----*/ 8625317bbafSopenharmony_ci 8635317bbafSopenharmony_ci// For use in get_penalty_score(), when evaluating which mask is best. 8645317bbafSopenharmony_ciconst PENALTY_N1: i32 = 3; 8655317bbafSopenharmony_ciconst PENALTY_N2: i32 = 3; 8665317bbafSopenharmony_ciconst PENALTY_N3: i32 = 40; 8675317bbafSopenharmony_ciconst PENALTY_N4: i32 = 10; 8685317bbafSopenharmony_ci 8695317bbafSopenharmony_ci 8705317bbafSopenharmony_cistatic ECC_CODEWORDS_PER_BLOCK: [[i8; 41]; 4] = [ 8715317bbafSopenharmony_ci // Version: (note that index 0 is for padding, and is set to an illegal value) 8725317bbafSopenharmony_ci //0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40 Error correction level 8735317bbafSopenharmony_ci [-1, 7, 10, 15, 20, 26, 18, 20, 24, 30, 18, 20, 24, 26, 30, 22, 24, 28, 30, 28, 28, 28, 28, 30, 30, 26, 28, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30], // Low 8745317bbafSopenharmony_ci [-1, 10, 16, 26, 18, 24, 16, 18, 22, 22, 26, 30, 22, 22, 24, 24, 28, 28, 26, 26, 26, 26, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28], // Medium 8755317bbafSopenharmony_ci [-1, 13, 22, 18, 26, 18, 24, 18, 22, 20, 24, 28, 26, 24, 20, 30, 24, 28, 28, 26, 30, 28, 30, 30, 30, 30, 28, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30], // Quartile 8765317bbafSopenharmony_ci [-1, 17, 28, 22, 16, 22, 28, 26, 26, 24, 28, 24, 28, 22, 24, 24, 30, 28, 28, 26, 28, 30, 24, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30], // High 8775317bbafSopenharmony_ci]; 8785317bbafSopenharmony_ci 8795317bbafSopenharmony_cistatic NUM_ERROR_CORRECTION_BLOCKS: [[i8; 41]; 4] = [ 8805317bbafSopenharmony_ci // Version: (note that index 0 is for padding, and is set to an illegal value) 8815317bbafSopenharmony_ci //0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40 Error correction level 8825317bbafSopenharmony_ci [-1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 4, 4, 4, 4, 4, 6, 6, 6, 6, 7, 8, 8, 9, 9, 10, 12, 12, 12, 13, 14, 15, 16, 17, 18, 19, 19, 20, 21, 22, 24, 25], // Low 8835317bbafSopenharmony_ci [-1, 1, 1, 1, 2, 2, 4, 4, 4, 5, 5, 5, 8, 9, 9, 10, 10, 11, 13, 14, 16, 17, 17, 18, 20, 21, 23, 25, 26, 28, 29, 31, 33, 35, 37, 38, 40, 43, 45, 47, 49], // Medium 8845317bbafSopenharmony_ci [-1, 1, 1, 2, 2, 4, 4, 6, 6, 8, 8, 8, 10, 12, 16, 12, 17, 16, 18, 21, 20, 23, 23, 25, 27, 29, 34, 34, 35, 38, 40, 43, 45, 48, 51, 53, 56, 59, 62, 65, 68], // Quartile 8855317bbafSopenharmony_ci [-1, 1, 1, 2, 4, 4, 4, 5, 6, 8, 8, 11, 11, 16, 16, 18, 16, 19, 21, 25, 25, 25, 34, 30, 32, 35, 37, 40, 42, 45, 48, 51, 54, 57, 60, 63, 66, 70, 74, 77, 81], // High 8865317bbafSopenharmony_ci]; 8875317bbafSopenharmony_ci 8885317bbafSopenharmony_ci 8895317bbafSopenharmony_ci 8905317bbafSopenharmony_ci/*---- QrCodeEcc functionality ----*/ 8915317bbafSopenharmony_ci 8925317bbafSopenharmony_ci/// The error correction level in a QR Code symbol. 8935317bbafSopenharmony_ci#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Debug)] 8945317bbafSopenharmony_cipub enum QrCodeEcc { 8955317bbafSopenharmony_ci /// The QR Code can tolerate about 7% erroneous codewords. 8965317bbafSopenharmony_ci Low , 8975317bbafSopenharmony_ci /// The QR Code can tolerate about 15% erroneous codewords. 8985317bbafSopenharmony_ci Medium , 8995317bbafSopenharmony_ci /// The QR Code can tolerate about 25% erroneous codewords. 9005317bbafSopenharmony_ci Quartile, 9015317bbafSopenharmony_ci /// The QR Code can tolerate about 30% erroneous codewords. 9025317bbafSopenharmony_ci High , 9035317bbafSopenharmony_ci} 9045317bbafSopenharmony_ci 9055317bbafSopenharmony_ci 9065317bbafSopenharmony_ciimpl QrCodeEcc { 9075317bbafSopenharmony_ci 9085317bbafSopenharmony_ci // Returns an unsigned 2-bit integer (in the range 0 to 3). 9095317bbafSopenharmony_ci fn ordinal(self) -> usize { 9105317bbafSopenharmony_ci use QrCodeEcc::*; 9115317bbafSopenharmony_ci match self { 9125317bbafSopenharmony_ci Low => 0, 9135317bbafSopenharmony_ci Medium => 1, 9145317bbafSopenharmony_ci Quartile => 2, 9155317bbafSopenharmony_ci High => 3, 9165317bbafSopenharmony_ci } 9175317bbafSopenharmony_ci } 9185317bbafSopenharmony_ci 9195317bbafSopenharmony_ci 9205317bbafSopenharmony_ci // Returns an unsigned 2-bit integer (in the range 0 to 3). 9215317bbafSopenharmony_ci fn format_bits(self) -> u8 { 9225317bbafSopenharmony_ci use QrCodeEcc::*; 9235317bbafSopenharmony_ci match self { 9245317bbafSopenharmony_ci Low => 1, 9255317bbafSopenharmony_ci Medium => 0, 9265317bbafSopenharmony_ci Quartile => 3, 9275317bbafSopenharmony_ci High => 2, 9285317bbafSopenharmony_ci } 9295317bbafSopenharmony_ci } 9305317bbafSopenharmony_ci 9315317bbafSopenharmony_ci} 9325317bbafSopenharmony_ci 9335317bbafSopenharmony_ci 9345317bbafSopenharmony_ci 9355317bbafSopenharmony_ci/*---- QrSegment functionality ----*/ 9365317bbafSopenharmony_ci 9375317bbafSopenharmony_ci/// A segment of character/binary/control data in a QR Code symbol. 9385317bbafSopenharmony_ci/// 9395317bbafSopenharmony_ci/// Instances of this struct are immutable. 9405317bbafSopenharmony_ci/// 9415317bbafSopenharmony_ci/// The mid-level way to create a segment is to take the payload data 9425317bbafSopenharmony_ci/// and call a static factory function such as `QrSegment::make_numeric()`. 9435317bbafSopenharmony_ci/// The low-level way to create a segment is to custom-make the bit buffer 9445317bbafSopenharmony_ci/// and call the `QrSegment::new()` constructor with appropriate values. 9455317bbafSopenharmony_ci/// 9465317bbafSopenharmony_ci/// This segment struct imposes no length restrictions, but QR Codes have restrictions. 9475317bbafSopenharmony_ci/// Even in the most favorable conditions, a QR Code can only hold 7089 characters of data. 9485317bbafSopenharmony_ci/// Any segment longer than this is meaningless for the purpose of generating QR Codes. 9495317bbafSopenharmony_ci#[derive(Clone, PartialEq, Eq)] 9505317bbafSopenharmony_cipub struct QrSegment { 9515317bbafSopenharmony_ci 9525317bbafSopenharmony_ci // The mode indicator of this segment. Accessed through mode(). 9535317bbafSopenharmony_ci mode: QrSegmentMode, 9545317bbafSopenharmony_ci 9555317bbafSopenharmony_ci // The length of this segment's unencoded data. Measured in characters for 9565317bbafSopenharmony_ci // numeric/alphanumeric/kanji mode, bytes for byte mode, and 0 for ECI mode. 9575317bbafSopenharmony_ci // Not the same as the data's bit length. Accessed through num_chars(). 9585317bbafSopenharmony_ci numchars: usize, 9595317bbafSopenharmony_ci 9605317bbafSopenharmony_ci // The data bits of this segment. Accessed through data(). 9615317bbafSopenharmony_ci data: Vec<bool>, 9625317bbafSopenharmony_ci 9635317bbafSopenharmony_ci} 9645317bbafSopenharmony_ci 9655317bbafSopenharmony_ci 9665317bbafSopenharmony_ciimpl QrSegment { 9675317bbafSopenharmony_ci 9685317bbafSopenharmony_ci /*---- Static factory functions (mid level) ----*/ 9695317bbafSopenharmony_ci 9705317bbafSopenharmony_ci /// Returns a segment representing the given binary data encoded in byte mode. 9715317bbafSopenharmony_ci /// 9725317bbafSopenharmony_ci /// All input byte slices are acceptable. 9735317bbafSopenharmony_ci /// 9745317bbafSopenharmony_ci /// Any text string can be converted to UTF-8 bytes and encoded as a byte mode segment. 9755317bbafSopenharmony_ci pub fn make_bytes(data: &[u8]) -> Self { 9765317bbafSopenharmony_ci let mut bb = BitBuffer(Vec::with_capacity(data.len() * 8)); 9775317bbafSopenharmony_ci for &b in data { 9785317bbafSopenharmony_ci bb.append_bits(u32::from(b), 8); 9795317bbafSopenharmony_ci } 9805317bbafSopenharmony_ci QrSegment::new(QrSegmentMode::Byte, data.len(), bb.0) 9815317bbafSopenharmony_ci } 9825317bbafSopenharmony_ci 9835317bbafSopenharmony_ci 9845317bbafSopenharmony_ci /// Returns a segment representing the given string of decimal digits encoded in numeric mode. 9855317bbafSopenharmony_ci /// 9865317bbafSopenharmony_ci /// Panics if the string contains non-digit characters. 9875317bbafSopenharmony_ci pub fn make_numeric(text: &str) -> Self { 9885317bbafSopenharmony_ci let mut bb = BitBuffer(Vec::with_capacity(text.len() * 3 + (text.len() + 2) / 3)); 9895317bbafSopenharmony_ci let mut accumdata: u32 = 0; 9905317bbafSopenharmony_ci let mut accumcount: u8 = 0; 9915317bbafSopenharmony_ci for b in text.bytes() { 9925317bbafSopenharmony_ci assert!((b'0' ..= b'9').contains(&b), "String contains non-numeric characters"); 9935317bbafSopenharmony_ci accumdata = accumdata * 10 + u32::from(b - b'0'); 9945317bbafSopenharmony_ci accumcount += 1; 9955317bbafSopenharmony_ci if accumcount == 3 { 9965317bbafSopenharmony_ci bb.append_bits(accumdata, 10); 9975317bbafSopenharmony_ci accumdata = 0; 9985317bbafSopenharmony_ci accumcount = 0; 9995317bbafSopenharmony_ci } 10005317bbafSopenharmony_ci } 10015317bbafSopenharmony_ci if accumcount > 0 { // 1 or 2 digits remaining 10025317bbafSopenharmony_ci bb.append_bits(accumdata, accumcount * 3 + 1); 10035317bbafSopenharmony_ci } 10045317bbafSopenharmony_ci QrSegment::new(QrSegmentMode::Numeric, text.len(), bb.0) 10055317bbafSopenharmony_ci } 10065317bbafSopenharmony_ci 10075317bbafSopenharmony_ci 10085317bbafSopenharmony_ci /// Returns a segment representing the given text string encoded in alphanumeric mode. 10095317bbafSopenharmony_ci /// 10105317bbafSopenharmony_ci /// The characters allowed are: 0 to 9, A to Z (uppercase only), space, 10115317bbafSopenharmony_ci /// dollar, percent, asterisk, plus, hyphen, period, slash, colon. 10125317bbafSopenharmony_ci /// 10135317bbafSopenharmony_ci /// Panics if the string contains non-encodable characters. 10145317bbafSopenharmony_ci pub fn make_alphanumeric(text: &str) -> Self { 10155317bbafSopenharmony_ci let mut bb = BitBuffer(Vec::with_capacity(text.len() * 5 + (text.len() + 1) / 2)); 10165317bbafSopenharmony_ci let mut accumdata: u32 = 0; 10175317bbafSopenharmony_ci let mut accumcount: u32 = 0; 10185317bbafSopenharmony_ci for c in text.chars() { 10195317bbafSopenharmony_ci let i: usize = ALPHANUMERIC_CHARSET.find(c) 10205317bbafSopenharmony_ci .expect("String contains unencodable characters in alphanumeric mode"); 10215317bbafSopenharmony_ci accumdata = accumdata * 45 + u32::try_from(i).unwrap(); 10225317bbafSopenharmony_ci accumcount += 1; 10235317bbafSopenharmony_ci if accumcount == 2 { 10245317bbafSopenharmony_ci bb.append_bits(accumdata, 11); 10255317bbafSopenharmony_ci accumdata = 0; 10265317bbafSopenharmony_ci accumcount = 0; 10275317bbafSopenharmony_ci } 10285317bbafSopenharmony_ci } 10295317bbafSopenharmony_ci if accumcount > 0 { // 1 character remaining 10305317bbafSopenharmony_ci bb.append_bits(accumdata, 6); 10315317bbafSopenharmony_ci } 10325317bbafSopenharmony_ci QrSegment::new(QrSegmentMode::Alphanumeric, text.len(), bb.0) 10335317bbafSopenharmony_ci } 10345317bbafSopenharmony_ci 10355317bbafSopenharmony_ci 10365317bbafSopenharmony_ci /// Returns a list of zero or more segments to represent the given Unicode text string. 10375317bbafSopenharmony_ci /// 10385317bbafSopenharmony_ci /// The result may use various segment modes and switch 10395317bbafSopenharmony_ci /// modes to optimize the length of the bit stream. 10405317bbafSopenharmony_ci pub fn make_segments(text: &str) -> Vec<Self> { 10415317bbafSopenharmony_ci if text.is_empty() { 10425317bbafSopenharmony_ci vec![] 10435317bbafSopenharmony_ci } else { 10445317bbafSopenharmony_ci vec![ 10455317bbafSopenharmony_ci if QrSegment::is_numeric(text) { 10465317bbafSopenharmony_ci QrSegment::make_numeric(text) 10475317bbafSopenharmony_ci } else if QrSegment::is_alphanumeric(text) { 10485317bbafSopenharmony_ci QrSegment::make_alphanumeric(text) 10495317bbafSopenharmony_ci } else { 10505317bbafSopenharmony_ci QrSegment::make_bytes(text.as_bytes()) 10515317bbafSopenharmony_ci } 10525317bbafSopenharmony_ci ] 10535317bbafSopenharmony_ci } 10545317bbafSopenharmony_ci } 10555317bbafSopenharmony_ci 10565317bbafSopenharmony_ci 10575317bbafSopenharmony_ci /// Returns a segment representing an Extended Channel Interpretation 10585317bbafSopenharmony_ci /// (ECI) designator with the given assignment value. 10595317bbafSopenharmony_ci pub fn make_eci(assignval: u32) -> Self { 10605317bbafSopenharmony_ci let mut bb = BitBuffer(Vec::with_capacity(24)); 10615317bbafSopenharmony_ci if assignval < (1 << 7) { 10625317bbafSopenharmony_ci bb.append_bits(assignval, 8); 10635317bbafSopenharmony_ci } else if assignval < (1 << 14) { 10645317bbafSopenharmony_ci bb.append_bits(0b10, 2); 10655317bbafSopenharmony_ci bb.append_bits(assignval, 14); 10665317bbafSopenharmony_ci } else if assignval < 1_000_000 { 10675317bbafSopenharmony_ci bb.append_bits(0b110, 3); 10685317bbafSopenharmony_ci bb.append_bits(assignval, 21); 10695317bbafSopenharmony_ci } else { 10705317bbafSopenharmony_ci panic!("ECI assignment value out of range"); 10715317bbafSopenharmony_ci } 10725317bbafSopenharmony_ci QrSegment::new(QrSegmentMode::Eci, 0, bb.0) 10735317bbafSopenharmony_ci } 10745317bbafSopenharmony_ci 10755317bbafSopenharmony_ci 10765317bbafSopenharmony_ci /*---- Constructor (low level) ----*/ 10775317bbafSopenharmony_ci 10785317bbafSopenharmony_ci /// Creates a new QR Code segment with the given attributes and data. 10795317bbafSopenharmony_ci /// 10805317bbafSopenharmony_ci /// The character count (numchars) must agree with the mode and 10815317bbafSopenharmony_ci /// the bit buffer length, but the constraint isn't checked. 10825317bbafSopenharmony_ci pub fn new(mode: QrSegmentMode, numchars: usize, data: Vec<bool>) -> Self { 10835317bbafSopenharmony_ci Self { mode, numchars, data } 10845317bbafSopenharmony_ci } 10855317bbafSopenharmony_ci 10865317bbafSopenharmony_ci 10875317bbafSopenharmony_ci /*---- Instance field getters ----*/ 10885317bbafSopenharmony_ci 10895317bbafSopenharmony_ci /// Returns the mode indicator of this segment. 10905317bbafSopenharmony_ci pub fn mode(&self) -> QrSegmentMode { 10915317bbafSopenharmony_ci self.mode 10925317bbafSopenharmony_ci } 10935317bbafSopenharmony_ci 10945317bbafSopenharmony_ci 10955317bbafSopenharmony_ci /// Returns the character count field of this segment. 10965317bbafSopenharmony_ci pub fn num_chars(&self) -> usize { 10975317bbafSopenharmony_ci self.numchars 10985317bbafSopenharmony_ci } 10995317bbafSopenharmony_ci 11005317bbafSopenharmony_ci 11015317bbafSopenharmony_ci /// Returns the data bits of this segment. 11025317bbafSopenharmony_ci pub fn data(&self) -> &Vec<bool> { 11035317bbafSopenharmony_ci &self.data 11045317bbafSopenharmony_ci } 11055317bbafSopenharmony_ci 11065317bbafSopenharmony_ci 11075317bbafSopenharmony_ci /*---- Other static functions ----*/ 11085317bbafSopenharmony_ci 11095317bbafSopenharmony_ci // Calculates and returns the number of bits needed to encode the given 11105317bbafSopenharmony_ci // segments at the given version. The result is None if a segment has too many 11115317bbafSopenharmony_ci // characters to fit its length field, or the total bits exceeds usize::MAX. 11125317bbafSopenharmony_ci fn get_total_bits(segs: &[Self], version: Version) -> Option<usize> { 11135317bbafSopenharmony_ci let mut result: usize = 0; 11145317bbafSopenharmony_ci for seg in segs { 11155317bbafSopenharmony_ci let ccbits: u8 = seg.mode.num_char_count_bits(version); 11165317bbafSopenharmony_ci // ccbits can be as large as 16, but usize can be as small as 16 11175317bbafSopenharmony_ci if let Some(limit) = 1usize.checked_shl(ccbits.into()) { 11185317bbafSopenharmony_ci if seg.numchars >= limit { 11195317bbafSopenharmony_ci return None; // The segment's length doesn't fit the field's bit width 11205317bbafSopenharmony_ci } 11215317bbafSopenharmony_ci } 11225317bbafSopenharmony_ci result = result.checked_add(4 + usize::from(ccbits))?; 11235317bbafSopenharmony_ci result = result.checked_add(seg.data.len())?; 11245317bbafSopenharmony_ci } 11255317bbafSopenharmony_ci Some(result) 11265317bbafSopenharmony_ci } 11275317bbafSopenharmony_ci 11285317bbafSopenharmony_ci 11295317bbafSopenharmony_ci /// Tests whether the given string can be encoded as a segment in numeric mode. 11305317bbafSopenharmony_ci /// 11315317bbafSopenharmony_ci /// A string is encodable iff each character is in the range 0 to 9. 11325317bbafSopenharmony_ci pub fn is_numeric(text: &str) -> bool { 11335317bbafSopenharmony_ci text.chars().all(|c| ('0' ..= '9').contains(&c)) 11345317bbafSopenharmony_ci } 11355317bbafSopenharmony_ci 11365317bbafSopenharmony_ci 11375317bbafSopenharmony_ci /// Tests whether the given string can be encoded as a segment in alphanumeric mode. 11385317bbafSopenharmony_ci /// 11395317bbafSopenharmony_ci /// A string is encodable iff each character is in the following set: 0 to 9, A to Z 11405317bbafSopenharmony_ci /// (uppercase only), space, dollar, percent, asterisk, plus, hyphen, period, slash, colon. 11415317bbafSopenharmony_ci pub fn is_alphanumeric(text: &str) -> bool { 11425317bbafSopenharmony_ci text.chars().all(|c| ALPHANUMERIC_CHARSET.contains(c)) 11435317bbafSopenharmony_ci } 11445317bbafSopenharmony_ci 11455317bbafSopenharmony_ci} 11465317bbafSopenharmony_ci 11475317bbafSopenharmony_ci 11485317bbafSopenharmony_ci// The set of all legal characters in alphanumeric mode, 11495317bbafSopenharmony_ci// where each character value maps to the index in the string. 11505317bbafSopenharmony_cistatic ALPHANUMERIC_CHARSET: &str = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ $%*+-./:"; 11515317bbafSopenharmony_ci 11525317bbafSopenharmony_ci 11535317bbafSopenharmony_ci 11545317bbafSopenharmony_ci/*---- QrSegmentMode functionality ----*/ 11555317bbafSopenharmony_ci 11565317bbafSopenharmony_ci/// Describes how a segment's data bits are interpreted. 11575317bbafSopenharmony_ci#[derive(Clone, Copy, PartialEq, Eq, Debug)] 11585317bbafSopenharmony_cipub enum QrSegmentMode { 11595317bbafSopenharmony_ci Numeric, 11605317bbafSopenharmony_ci Alphanumeric, 11615317bbafSopenharmony_ci Byte, 11625317bbafSopenharmony_ci Kanji, 11635317bbafSopenharmony_ci Eci, 11645317bbafSopenharmony_ci} 11655317bbafSopenharmony_ci 11665317bbafSopenharmony_ci 11675317bbafSopenharmony_ciimpl QrSegmentMode { 11685317bbafSopenharmony_ci 11695317bbafSopenharmony_ci // Returns an unsigned 4-bit integer value (range 0 to 15) 11705317bbafSopenharmony_ci // representing the mode indicator bits for this mode object. 11715317bbafSopenharmony_ci fn mode_bits(self) -> u32 { 11725317bbafSopenharmony_ci use QrSegmentMode::*; 11735317bbafSopenharmony_ci match self { 11745317bbafSopenharmony_ci Numeric => 0x1, 11755317bbafSopenharmony_ci Alphanumeric => 0x2, 11765317bbafSopenharmony_ci Byte => 0x4, 11775317bbafSopenharmony_ci Kanji => 0x8, 11785317bbafSopenharmony_ci Eci => 0x7, 11795317bbafSopenharmony_ci } 11805317bbafSopenharmony_ci } 11815317bbafSopenharmony_ci 11825317bbafSopenharmony_ci 11835317bbafSopenharmony_ci // Returns the bit width of the character count field for a segment in this mode 11845317bbafSopenharmony_ci // in a QR Code at the given version number. The result is in the range [0, 16]. 11855317bbafSopenharmony_ci fn num_char_count_bits(self, ver: Version) -> u8 { 11865317bbafSopenharmony_ci use QrSegmentMode::*; 11875317bbafSopenharmony_ci (match self { 11885317bbafSopenharmony_ci Numeric => [10, 12, 14], 11895317bbafSopenharmony_ci Alphanumeric => [ 9, 11, 13], 11905317bbafSopenharmony_ci Byte => [ 8, 16, 16], 11915317bbafSopenharmony_ci Kanji => [ 8, 10, 12], 11925317bbafSopenharmony_ci Eci => [ 0, 0, 0], 11935317bbafSopenharmony_ci })[usize::from((ver.value() + 7) / 17)] 11945317bbafSopenharmony_ci } 11955317bbafSopenharmony_ci 11965317bbafSopenharmony_ci} 11975317bbafSopenharmony_ci 11985317bbafSopenharmony_ci 11995317bbafSopenharmony_ci 12005317bbafSopenharmony_ci/*---- Bit buffer functionality ----*/ 12015317bbafSopenharmony_ci 12025317bbafSopenharmony_ci/// An appendable sequence of bits (0s and 1s). 12035317bbafSopenharmony_ci/// 12045317bbafSopenharmony_ci/// Mainly used by QrSegment. 12055317bbafSopenharmony_cipub struct BitBuffer(pub Vec<bool>); 12065317bbafSopenharmony_ci 12075317bbafSopenharmony_ci 12085317bbafSopenharmony_ciimpl BitBuffer { 12095317bbafSopenharmony_ci /// Appends the given number of low-order bits of the given value to this buffer. 12105317bbafSopenharmony_ci /// 12115317bbafSopenharmony_ci /// Requires len ≤ 31 and val < 2<sup>len</sup>. 12125317bbafSopenharmony_ci pub fn append_bits(&mut self, val: u32, len: u8) { 12135317bbafSopenharmony_ci assert!(len <= 31 && val >> len == 0, "Value out of range"); 12145317bbafSopenharmony_ci self.0.extend((0 .. i32::from(len)).rev().map(|i| get_bit(val, i))); // Append bit by bit 12155317bbafSopenharmony_ci } 12165317bbafSopenharmony_ci} 12175317bbafSopenharmony_ci 12185317bbafSopenharmony_ci 12195317bbafSopenharmony_ci 12205317bbafSopenharmony_ci/*---- Miscellaneous values ----*/ 12215317bbafSopenharmony_ci 12225317bbafSopenharmony_ci/// The error type when the supplied data does not fit any QR Code version. 12235317bbafSopenharmony_ci/// 12245317bbafSopenharmony_ci/// Ways to handle this exception include: 12255317bbafSopenharmony_ci/// 12265317bbafSopenharmony_ci/// - Decrease the error correction level if it was greater than `QrCodeEcc::Low`. 12275317bbafSopenharmony_ci/// - If the `encode_segments_advanced()` function was called, then increase the maxversion 12285317bbafSopenharmony_ci/// argument if it was less than `Version::MAX`. (This advice does not apply to the 12295317bbafSopenharmony_ci/// other factory functions because they search all versions up to `Version::MAX`.) 12305317bbafSopenharmony_ci/// - Split the text data into better or optimal segments in order to reduce the number of bits required. 12315317bbafSopenharmony_ci/// - Change the text or binary data to be shorter. 12325317bbafSopenharmony_ci/// - Change the text to fit the character set of a particular segment mode (e.g. alphanumeric). 12335317bbafSopenharmony_ci/// - Propagate the error upward to the caller/user. 12345317bbafSopenharmony_ci#[derive(Debug, Clone)] 12355317bbafSopenharmony_cipub enum DataTooLong { 12365317bbafSopenharmony_ci SegmentTooLong, 12375317bbafSopenharmony_ci DataOverCapacity(usize, usize), 12385317bbafSopenharmony_ci} 12395317bbafSopenharmony_ci 12405317bbafSopenharmony_ciimpl std::error::Error for DataTooLong {} 12415317bbafSopenharmony_ci 12425317bbafSopenharmony_ciimpl std::fmt::Display for DataTooLong { 12435317bbafSopenharmony_ci fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { 12445317bbafSopenharmony_ci match *self { 12455317bbafSopenharmony_ci Self::SegmentTooLong => write!(f, "Segment too long"), 12465317bbafSopenharmony_ci Self::DataOverCapacity(datalen, maxcapacity) => 12475317bbafSopenharmony_ci write!(f, "Data length = {} bits, Max capacity = {} bits", datalen, maxcapacity), 12485317bbafSopenharmony_ci } 12495317bbafSopenharmony_ci } 12505317bbafSopenharmony_ci} 12515317bbafSopenharmony_ci 12525317bbafSopenharmony_ci 12535317bbafSopenharmony_ci/// A number between 1 and 40 (inclusive). 12545317bbafSopenharmony_ci#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug)] 12555317bbafSopenharmony_cipub struct Version(u8); 12565317bbafSopenharmony_ci 12575317bbafSopenharmony_ciimpl Version { 12585317bbafSopenharmony_ci /// The minimum version number supported in the QR Code Model 2 standard. 12595317bbafSopenharmony_ci pub const MIN: Version = Version( 1); 12605317bbafSopenharmony_ci 12615317bbafSopenharmony_ci /// The maximum version number supported in the QR Code Model 2 standard. 12625317bbafSopenharmony_ci pub const MAX: Version = Version(40); 12635317bbafSopenharmony_ci 12645317bbafSopenharmony_ci /// Creates a version object from the given number. 12655317bbafSopenharmony_ci /// 12665317bbafSopenharmony_ci /// Panics if the number is outside the range [1, 40]. 12675317bbafSopenharmony_ci pub fn new(ver: u8) -> Self { 12685317bbafSopenharmony_ci assert!((Version::MIN.value() ..= Version::MAX.value()).contains(&ver), "Version number out of range"); 12695317bbafSopenharmony_ci Self(ver) 12705317bbafSopenharmony_ci } 12715317bbafSopenharmony_ci 12725317bbafSopenharmony_ci /// Returns the value, which is in the range [1, 40]. 12735317bbafSopenharmony_ci pub fn value(self) -> u8 { 12745317bbafSopenharmony_ci self.0 12755317bbafSopenharmony_ci } 12765317bbafSopenharmony_ci} 12775317bbafSopenharmony_ci 12785317bbafSopenharmony_ci 12795317bbafSopenharmony_ci/// A number between 0 and 7 (inclusive). 12805317bbafSopenharmony_ci#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug)] 12815317bbafSopenharmony_cipub struct Mask(u8); 12825317bbafSopenharmony_ci 12835317bbafSopenharmony_ciimpl Mask { 12845317bbafSopenharmony_ci /// Creates a mask object from the given number. 12855317bbafSopenharmony_ci /// 12865317bbafSopenharmony_ci /// Panics if the number is outside the range [0, 7]. 12875317bbafSopenharmony_ci pub fn new(mask: u8) -> Self { 12885317bbafSopenharmony_ci assert!(mask <= 7, "Mask value out of range"); 12895317bbafSopenharmony_ci Self(mask) 12905317bbafSopenharmony_ci } 12915317bbafSopenharmony_ci 12925317bbafSopenharmony_ci /// Returns the value, which is in the range [0, 7]. 12935317bbafSopenharmony_ci pub fn value(self) -> u8 { 12945317bbafSopenharmony_ci self.0 12955317bbafSopenharmony_ci } 12965317bbafSopenharmony_ci} 12975317bbafSopenharmony_ci 12985317bbafSopenharmony_ci 12995317bbafSopenharmony_ci// Returns true iff the i'th bit of x is set to 1. 13005317bbafSopenharmony_cifn get_bit(x: u32, i: i32) -> bool { 13015317bbafSopenharmony_ci (x >> i) & 1 != 0 13025317bbafSopenharmony_ci} 1303