1 //! 2 //! qr_code 3 //! 4 //! This crate provides a [QrCode](crate::QrCode) encoder and decoder 5 //! 6 7 #![deny(missing_docs)] 8 #![deny(warnings)] 9 #![allow( 10 clippy::must_use_candidate, // This is just annoying. 11 clippy::use_self, // Rust 1.33 doesn't support Self::EnumVariant, let's try again in 1.37. 12 clippy::match_like_matches_macro, // MSRV is lower than what's needed for matches! 13 clippy::wrong_self_convention, // TODO fix code and remove 14 )] 15 #![cfg_attr(feature = "bench", doc(include = "../README.md"))] 16 // ^ make sure we can test our README.md. 17 // TODO: Avoid using `feature = "bench"` above. 18 #![cfg_attr(docsrs, feature(doc_cfg))] 19 // No `unsafe` please. If `unsafe` is really needed, then please 20 // consider encapsulating it in a separate crates.io crate. 21 #![forbid(unsafe_code)] 22 // Using `#[bench]`, `test::Bencher`, and `cargo bench` requires opting into the unstable `test` 23 // feature. See https://github.com/rust-lang/rust/issues/50297 for more details. Benchmarks 24 // features are only available in the nightly versions of the Rust compiler - to keep stable 25 // builds working we only enable benching behind the "bench" config. To run the benchmarks 26 // use: `RUSTFLAGS='--cfg=bench' cargo +nightly bench --all-features` 27 #![cfg_attr(bench, feature(test))] 28 #[cfg(bench)] 29 extern crate test; 30 31 // Re-exported dependencies. 32 33 #[cfg(feature = "bmp")] 34 /// Allows to create QR codes images using monocrhomatic bitmaps 35 pub extern crate bmp_monochrome; 36 37 use std::ops::Index; 38 39 pub mod bits; 40 pub mod canvas; 41 mod cast; 42 pub mod ec; 43 pub mod optimize; 44 mod render; 45 pub mod types; 46 47 #[cfg(feature = "fuzz")] 48 mod fuzz; 49 #[cfg(feature = "fuzz")] 50 pub use crate::fuzz::{split_merge_rt, QrCodeData}; 51 52 #[cfg(all(feature = "bmp", feature = "decode"))] 53 pub mod decode; 54 pub mod structured; 55 56 pub use crate::types::{Color, EcLevel, QrResult, Version}; 57 58 use crate::cast::As; 59 60 /// The encoded QR code symbol. 61 #[derive(Clone, Debug)] 62 pub struct QrCode { 63 content: Vec<Color>, 64 version: Version, 65 ec_level: EcLevel, 66 width: usize, 67 } 68 69 impl QrCode { 70 /// Constructs a new QR code which automatically encodes the given data. 71 /// 72 /// This method uses the "medium" error correction level and automatically 73 /// chooses the smallest QR code. 74 /// 75 /// use qr_code::QrCode; 76 /// 77 /// let code = QrCode::new(b"Some data").unwrap(); 78 /// 79 /// # Errors 80 /// 81 /// Returns error if the QR code cannot be constructed, e.g. when the data 82 /// is too long. new<D: AsRef<[u8]>>(data: D) -> QrResult<Self>83 pub fn new<D: AsRef<[u8]>>(data: D) -> QrResult<Self> { 84 Self::with_error_correction_level(data, EcLevel::M) 85 } 86 87 /// Constructs a new QR code which automatically encodes the given data at a 88 /// specific error correction level. 89 /// 90 /// This method automatically chooses the smallest QR code. 91 /// 92 /// use qr_code::{QrCode, EcLevel}; 93 /// 94 /// let code = QrCode::with_error_correction_level(b"Some data", EcLevel::H).unwrap(); 95 /// 96 /// # Errors 97 /// 98 /// Returns error if the QR code cannot be constructed, e.g. when the data 99 /// is too long. with_error_correction_level<D: AsRef<[u8]>>( data: D, ec_level: EcLevel, ) -> QrResult<Self>100 pub fn with_error_correction_level<D: AsRef<[u8]>>( 101 data: D, 102 ec_level: EcLevel, 103 ) -> QrResult<Self> { 104 let bits = bits::encode_auto(data.as_ref(), ec_level)?; 105 Self::with_bits(bits, ec_level) 106 } 107 108 /// Constructs a new QR code for the given version and error correction 109 /// level. 110 /// 111 /// use qr_code::{QrCode, Version, EcLevel}; 112 /// 113 /// let code = QrCode::with_version(b"Some data", Version::Normal(5), EcLevel::M).unwrap(); 114 /// 115 /// This method can also be used to generate Micro QR code. 116 /// 117 /// use qr_code::{QrCode, Version, EcLevel}; 118 /// 119 /// let micro_code = QrCode::with_version(b"123", Version::Micro(1), EcLevel::L).unwrap(); 120 /// 121 /// # Errors 122 /// 123 /// Returns error if the QR code cannot be constructed, e.g. when the data 124 /// is too long, or when the version and error correction level are 125 /// incompatible. with_version<D: AsRef<[u8]>>( data: D, version: Version, ec_level: EcLevel, ) -> QrResult<Self>126 pub fn with_version<D: AsRef<[u8]>>( 127 data: D, 128 version: Version, 129 ec_level: EcLevel, 130 ) -> QrResult<Self> { 131 let mut bits = bits::Bits::new(version); 132 bits.push_optimal_data(data.as_ref())?; 133 bits.push_terminator(ec_level)?; 134 Self::with_bits(bits, ec_level) 135 } 136 137 /// Constructs a new QR code with encoded bits. 138 /// 139 /// Use this method only if there are very special need to manipulate the 140 /// raw bits before encoding. Some examples are: 141 /// 142 /// * Encode data using specific character set with ECI 143 /// * Use the FNC1 modes 144 /// * Avoid the optimal segmentation algorithm 145 /// 146 /// See the `Bits` structure for detail. 147 /// 148 /// #![allow(unused_must_use)] 149 /// 150 /// use qr_code::{QrCode, Version, EcLevel}; 151 /// use qr_code::bits::Bits; 152 /// 153 /// let mut bits = Bits::new(Version::Normal(1)); 154 /// bits.push_eci_designator(9); 155 /// bits.push_byte_data(b"\xca\xfe\xe4\xe9\xea\xe1\xf2 QR"); 156 /// bits.push_terminator(EcLevel::L); 157 /// let qrcode = QrCode::with_bits(bits, EcLevel::L); 158 /// 159 /// # Errors 160 /// 161 /// Returns error if the QR code cannot be constructed, e.g. when the bits 162 /// are too long, or when the version and error correction level are 163 /// incompatible. with_bits(bits: bits::Bits, ec_level: EcLevel) -> QrResult<Self>164 pub fn with_bits(bits: bits::Bits, ec_level: EcLevel) -> QrResult<Self> { 165 let version = bits.version(); 166 let data = bits.into_bytes(); 167 let (encoded_data, ec_data) = ec::construct_codewords(&data, version, ec_level)?; 168 let mut canvas = canvas::Canvas::new(version, ec_level); 169 canvas.draw_all_functional_patterns(); 170 canvas.draw_data(&encoded_data, &ec_data); 171 let canvas = canvas.apply_best_mask(); 172 Ok(Self { 173 content: canvas.into_colors(), 174 version, 175 ec_level, 176 width: version.width().as_usize(), 177 }) 178 } 179 180 /// Gets the version of this QR code. version(&self) -> Version181 pub fn version(&self) -> Version { 182 self.version 183 } 184 185 /// Gets the error correction level of this QR code. error_correction_level(&self) -> EcLevel186 pub fn error_correction_level(&self) -> EcLevel { 187 self.ec_level 188 } 189 190 /// Gets the number of modules per side, i.e. the width of this QR code. 191 /// 192 /// The width here does not contain the quiet zone paddings. width(&self) -> usize193 pub fn width(&self) -> usize { 194 self.width 195 } 196 197 /// Gets the maximum number of allowed erratic modules can be introduced 198 /// before the data becomes corrupted. Note that errors should not be 199 /// introduced to functional modules. max_allowed_errors(&self) -> usize200 pub fn max_allowed_errors(&self) -> usize { 201 ec::max_allowed_errors(self.version, self.ec_level).expect("invalid version or ec_level") 202 } 203 204 /// Checks whether a module at coordinate (x, y) is a functional module or 205 /// not. is_functional(&self, x: usize, y: usize) -> bool206 pub fn is_functional(&self, x: usize, y: usize) -> bool { 207 let x = x.as_i16(); 208 let y = y.as_i16(); 209 canvas::is_functional(self.version, self.version.width(), x, y) 210 } 211 212 /// Converts the QR code to a vector of booleans. Each entry represents the 213 /// color of the module, with "true" means dark and "false" means light. to_vec(&self) -> Vec<bool>214 pub fn to_vec(&self) -> Vec<bool> { 215 self.content.iter().map(|c| *c != Color::Light).collect() 216 } 217 218 /// Returns an iterator over QR code vector of colors. iter(&self) -> QrCodeIterator219 pub fn iter(&self) -> QrCodeIterator { 220 QrCodeIterator::new(self) 221 } 222 223 /// Converts the QR code to a vector of colors. into_colors(self) -> Vec<Color>224 pub fn into_colors(self) -> Vec<Color> { 225 self.content 226 } 227 } 228 229 impl Index<(usize, usize)> for QrCode { 230 type Output = Color; 231 index(&self, (x, y): (usize, usize)) -> &Color232 fn index(&self, (x, y): (usize, usize)) -> &Color { 233 let index = y * self.width + x; 234 &self.content[index] 235 } 236 } 237 238 /// Iterate over QR code data without consuming the QR code struct 239 pub struct QrCodeIterator<'a> { 240 qr_code: &'a QrCode, 241 index: usize, 242 } 243 244 impl<'a> QrCodeIterator<'a> { new(qr_code: &'a QrCode) -> Self245 fn new(qr_code: &'a QrCode) -> Self { 246 let index = 0; 247 QrCodeIterator { qr_code, index } 248 } 249 } 250 251 impl<'a> Iterator for QrCodeIterator<'a> { 252 type Item = bool; next(&mut self) -> Option<bool>253 fn next(&mut self) -> Option<bool> { 254 let result = self 255 .qr_code 256 .content 257 .get(self.index) 258 .map(|c| c == &Color::Dark); 259 self.index += 1; 260 result 261 } 262 } 263 264 #[cfg(test)] 265 mod tests { 266 use super::{EcLevel, QrCode, Version}; 267 use crate::types::QrError; 268 use std::time::{Duration, Instant}; 269 270 #[cfg(all(feature = "bmp", feature = "decode"))] 271 #[test] test_roundtrip()272 fn test_roundtrip() { 273 use crate::decode::BmpDecode; 274 use bmp_monochrome::Bmp; 275 use rand::distributions::Alphanumeric; 276 use rand::Rng; 277 use std::io::Cursor; 278 279 let rand_string: String = rand::thread_rng() 280 .sample_iter(&Alphanumeric) 281 .take(30) 282 .collect(); 283 let qr_code = QrCode::new(rand_string.as_bytes()).unwrap(); 284 let mut cursor = Cursor::new(vec![]); 285 qr_code 286 .to_bmp() 287 .mul(3) 288 .unwrap() 289 .add_white_border(3) 290 .unwrap() 291 .write(&mut cursor) 292 .unwrap(); 293 cursor.set_position(0); 294 let bmp = Bmp::read(cursor).unwrap(); 295 let result = bmp.normalize().decode().unwrap(); 296 let decoded = std::str::from_utf8(&result).unwrap(); 297 assert_eq!(rand_string, decoded); 298 } 299 300 #[test] test_with_version()301 fn test_with_version() { 302 let qr_code = QrCode::with_version(b"test", Version::Normal(1), EcLevel::H).unwrap(); 303 304 assert_eq!(qr_code.version(), Version::Normal(1)); 305 assert_eq!(qr_code.error_correction_level(), EcLevel::H); 306 307 // Only a smoke test of `QrCode::max_allowed_errors` - more thorough test coverage is 308 // provided by the tests in the `ec.rs` module. 309 assert_eq!(qr_code.max_allowed_errors(), 8); 310 } 311 312 #[test] test_equivalence_of_pixel_accessors()313 fn test_equivalence_of_pixel_accessors() { 314 let qr_code = QrCode::new(b"test").unwrap(); 315 316 let output_via_iter = qr_code.iter().collect::<Vec<_>>(); 317 let output_via_to_vec = qr_code.to_vec(); 318 319 let mut output_via_index = vec![]; 320 for y in 0..qr_code.width() { 321 for x in 0..qr_code.width() { 322 output_via_index.push(qr_code[(x, y)].select(true, false)); 323 } 324 } 325 326 assert_eq!(output_via_iter.as_slice(), output_via_to_vec.as_slice()); 327 assert_eq!(output_via_iter.as_slice(), output_via_index.as_slice()); 328 } 329 330 #[test] test_very_large_input()331 fn test_very_large_input() { 332 let start = Instant::now(); 333 334 let input = { 335 // It is important that `data` doesn't decompose into single `Segment`, 336 // because this wouldn't sufficiently stress the performance of 337 // `Parser::new` or `optimize_segmentation`. In particular, using 338 // `vec![0; TARGET_LEN]` wouldn't be sufficient to demonstrate the 339 // problem (at least not at the fairly low 10MB `TARGET_LEN`). 340 let stencil = include_bytes!("../test_data/large_base64.in"); 341 342 const TARGET_LEN: usize = 10 * 1024 * 1024; 343 let data = stencil.repeat(TARGET_LEN / stencil.len() + 1); 344 assert!(data.len() >= TARGET_LEN); 345 data 346 }; 347 348 let err = QrCode::new(&*input).unwrap_err(); 349 assert_eq!(err, QrError::DataTooLong); 350 351 // This assertion is probably the most important part of the test - input 352 // that doesn't fit should only take O(1) to reject. 353 assert!(start.elapsed() < Duration::from_secs(1)); 354 } 355 } 356 357 #[cfg(bench)] 358 pub(crate) mod bench { 359 use super::{EcLevel, QrCode}; 360 361 #[bench] bench_qr_code_with_low_ecc(bencher: &mut test::Bencher)362 fn bench_qr_code_with_low_ecc(bencher: &mut test::Bencher) { 363 bencher.iter(|| { 364 let data = include_bytes!("../test_data/large_base64.in"); 365 366 // Using `EcLevel::L` because otherwise the input data won't fit and we'll get 367 // `DataTooLong` error. 368 let qr_code = QrCode::with_error_correction_level(data, EcLevel::L).unwrap(); 369 370 // The code below reads all the QR pixels - this is a haphazard attempt to ensure that 371 // the compiler won't optimize away generation of the data. 372 qr_code.iter().map(|b| if b { 1 } else { 0 }).sum::<usize>() 373 }); 374 } 375 } 376