xref: /aosp_15_r20/external/cronet/third_party/rust/chromium_crates_io/vendor/qr_code-2.0.0/src/lib.rs (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
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