qrcode/
lib.rs

1//! QRCode encoder
2//!
3//! This crate provides a QR code and Micro QR code encoder for binary data.
4//!
5#![cfg_attr(feature = "image", doc = "```rust")]
6#![cfg_attr(not(feature = "image"), doc = "```ignore")]
7//! use qrcode::QrCode;
8//! use image::Luma;
9//!
10//! // Encode some data into bits.
11//! let code = QrCode::new(b"01234567").unwrap();
12//!
13//! // Render the bits into an image.
14//! let image = code.render::<Luma<u8>>().build();
15//!
16//! // Save the image.
17//! # if cfg!(unix) {
18//! image.save("/tmp/qrcode.png").unwrap();
19//! # }
20//!
21//! // You can also render it into a string.
22//! let string = code.render()
23//!     .light_color(' ')
24//!     .dark_color('#')
25//!     .build();
26//! println!("{}", string);
27//! ```
28
29#![cfg_attr(feature = "bench", feature(test, external_doc))] // Unstable libraries
30#![deny(warnings, clippy::pedantic)]
31#![allow(
32    clippy::must_use_candidate, // This is just annoying.
33    clippy::use_self, // Rust 1.33 doesn't support Self::EnumVariant, let's try again in 1.37.
34)]
35#![cfg_attr(feature = "bench", doc(include = "../README.md"))]
36// ^ make sure we can test our README.md.
37
38use std::ops::Index;
39
40pub mod bits;
41pub mod canvas;
42mod cast;
43pub mod ec;
44pub mod optimize;
45pub mod render;
46pub mod types;
47
48pub use crate::types::{Color, EcLevel, QrResult, Version};
49
50use crate::cast::As;
51use crate::render::{Pixel, Renderer};
52use checked_int_cast::CheckedIntCast;
53
54/// The encoded QR code symbol.
55#[derive(Clone)]
56pub struct QrCode {
57    content: Vec<Color>,
58    version: Version,
59    ec_level: EcLevel,
60    width: usize,
61}
62
63impl QrCode {
64    /// Constructs a new QR code which automatically encodes the given data.
65    ///
66    /// This method uses the "medium" error correction level and automatically
67    /// chooses the smallest QR code.
68    ///
69    ///     use qrcode::QrCode;
70    ///
71    ///     let code = QrCode::new(b"Some data").unwrap();
72    ///
73    /// # Errors
74    ///
75    /// Returns error if the QR code cannot be constructed, e.g. when the data
76    /// is too long.
77    pub fn new<D: AsRef<[u8]>>(data: D) -> QrResult<Self> {
78        Self::with_error_correction_level(data, EcLevel::M)
79    }
80
81    /// Constructs a new QR code which automatically encodes the given data at a
82    /// specific error correction level.
83    ///
84    /// This method automatically chooses the smallest QR code.
85    ///
86    ///     use qrcode::{QrCode, EcLevel};
87    ///
88    ///     let code = QrCode::with_error_correction_level(b"Some data", EcLevel::H).unwrap();
89    ///
90    /// # Errors
91    ///
92    /// Returns error if the QR code cannot be constructed, e.g. when the data
93    /// is too long.
94    pub fn with_error_correction_level<D: AsRef<[u8]>>(data: D, ec_level: EcLevel) -> QrResult<Self> {
95        let bits = bits::encode_auto(data.as_ref(), ec_level)?;
96        Self::with_bits(bits, ec_level)
97    }
98
99    /// Constructs a new QR code for the given version and error correction
100    /// level.
101    ///
102    ///     use qrcode::{QrCode, Version, EcLevel};
103    ///
104    ///     let code = QrCode::with_version(b"Some data", Version::Normal(5), EcLevel::M).unwrap();
105    ///
106    /// This method can also be used to generate Micro QR code.
107    ///
108    ///     use qrcode::{QrCode, Version, EcLevel};
109    ///
110    ///     let micro_code = QrCode::with_version(b"123", Version::Micro(1), EcLevel::L).unwrap();
111    ///
112    /// # Errors
113    ///
114    /// Returns error if the QR code cannot be constructed, e.g. when the data
115    /// is too long, or when the version and error correction level are
116    /// incompatible.
117    pub fn with_version<D: AsRef<[u8]>>(data: D, version: Version, ec_level: EcLevel) -> QrResult<Self> {
118        let mut bits = bits::Bits::new(version);
119        bits.push_optimal_data(data.as_ref())?;
120        bits.push_terminator(ec_level)?;
121        Self::with_bits(bits, ec_level)
122    }
123
124    /// Constructs a new QR code with encoded bits.
125    ///
126    /// Use this method only if there are very special need to manipulate the
127    /// raw bits before encoding. Some examples are:
128    ///
129    /// * Encode data using specific character set with ECI
130    /// * Use the FNC1 modes
131    /// * Avoid the optimal segmentation algorithm
132    ///
133    /// See the `Bits` structure for detail.
134    ///
135    ///     #![allow(unused_must_use)]
136    ///
137    ///     use qrcode::{QrCode, Version, EcLevel};
138    ///     use qrcode::bits::Bits;
139    ///
140    ///     let mut bits = Bits::new(Version::Normal(1));
141    ///     bits.push_eci_designator(9);
142    ///     bits.push_byte_data(b"\xca\xfe\xe4\xe9\xea\xe1\xf2 QR");
143    ///     bits.push_terminator(EcLevel::L);
144    ///     let qrcode = QrCode::with_bits(bits, EcLevel::L);
145    ///
146    /// # Errors
147    ///
148    /// Returns error if the QR code cannot be constructed, e.g. when the bits
149    /// are too long, or when the version and error correction level are
150    /// incompatible.
151    pub fn with_bits(bits: bits::Bits, ec_level: EcLevel) -> QrResult<Self> {
152        let version = bits.version();
153        let data = bits.into_bytes();
154        let (encoded_data, ec_data) = ec::construct_codewords(&*data, version, ec_level)?;
155        let mut canvas = canvas::Canvas::new(version, ec_level);
156        canvas.draw_all_functional_patterns();
157        canvas.draw_data(&*encoded_data, &*ec_data);
158        let canvas = canvas.apply_best_mask();
159        Ok(Self { content: canvas.into_colors(), version, ec_level, width: version.width().as_usize() })
160    }
161
162    /// Gets the version of this QR code.
163    pub fn version(&self) -> Version {
164        self.version
165    }
166
167    /// Gets the error correction level of this QR code.
168    pub fn error_correction_level(&self) -> EcLevel {
169        self.ec_level
170    }
171
172    /// Gets the number of modules per side, i.e. the width of this QR code.
173    ///
174    /// The width here does not contain the quiet zone paddings.
175    pub fn width(&self) -> usize {
176        self.width
177    }
178
179    /// Gets the maximum number of allowed erratic modules can be introduced
180    /// before the data becomes corrupted. Note that errors should not be
181    /// introduced to functional modules.
182    pub fn max_allowed_errors(&self) -> usize {
183        ec::max_allowed_errors(self.version, self.ec_level).expect("invalid version or ec_level")
184    }
185
186    /// Checks whether a module at coordinate (x, y) is a functional module or
187    /// not.
188    pub fn is_functional(&self, x: usize, y: usize) -> bool {
189        let x = x.as_i16_checked().expect("coordinate is too large for QR code");
190        let y = y.as_i16_checked().expect("coordinate is too large for QR code");
191        canvas::is_functional(self.version, self.version.width(), x, y)
192    }
193
194    /// Converts the QR code into a human-readable string. This is mainly for
195    /// debugging only.
196    pub fn to_debug_str(&self, on_char: char, off_char: char) -> String {
197        self.render().quiet_zone(false).dark_color(on_char).light_color(off_char).build()
198    }
199
200    /// Converts the QR code to a vector of booleans. Each entry represents the
201    /// color of the module, with "true" means dark and "false" means light.
202    #[deprecated(since = "0.4.0", note = "use `to_colors()` instead")]
203    pub fn to_vec(&self) -> Vec<bool> {
204        self.content.iter().map(|c| *c != Color::Light).collect()
205    }
206
207    /// Converts the QR code to a vector of booleans. Each entry represents the
208    /// color of the module, with "true" means dark and "false" means light.
209    #[deprecated(since = "0.4.0", note = "use `into_colors()` instead")]
210    pub fn into_vec(self) -> Vec<bool> {
211        self.content.into_iter().map(|c| c != Color::Light).collect()
212    }
213
214    /// Converts the QR code to a vector of colors.
215    pub fn to_colors(&self) -> Vec<Color> {
216        self.content.clone()
217    }
218
219    /// Converts the QR code to a vector of colors.
220    pub fn into_colors(self) -> Vec<Color> {
221        self.content
222    }
223
224    /// Renders the QR code into an image. The result is an image builder, which
225    /// you may do some additional configuration before copying it into a
226    /// concrete image.
227    ///
228    /// # Examples
229    ///
230    #[cfg_attr(feature = "image", doc = " ```rust")]
231    #[cfg_attr(not(feature = "image"), doc = " ```ignore")]
232    /// # use qrcode::QrCode;
233    /// # use image::Rgb;
234    ///
235    /// let image = QrCode::new(b"hello").unwrap()
236    ///                     .render()
237    ///                     .dark_color(Rgb([0, 0, 128]))
238    ///                     .light_color(Rgb([224, 224, 224])) // adjust colors
239    ///                     .quiet_zone(false)          // disable quiet zone (white border)
240    ///                     .min_dimensions(300, 300)   // sets minimum image size
241    ///                     .build();
242    /// ```
243    ///
244    /// Note: the `image` crate itself also provides method to rotate the image,
245    /// or overlay a logo on top of the QR code.
246    pub fn render<P: Pixel>(&self) -> Renderer<P> {
247        let quiet_zone = if self.version.is_micro() { 2 } else { 4 };
248        Renderer::new(&self.content, self.width, quiet_zone)
249    }
250}
251
252impl Index<(usize, usize)> for QrCode {
253    type Output = Color;
254
255    fn index(&self, (x, y): (usize, usize)) -> &Color {
256        let index = y * self.width + x;
257        &self.content[index]
258    }
259}
260
261#[cfg(test)]
262mod tests {
263    use crate::{EcLevel, QrCode, Version};
264
265    #[test]
266    fn test_annex_i_qr() {
267        // This uses the ISO Annex I as test vector.
268        let code = QrCode::with_version(b"01234567", Version::Normal(1), EcLevel::M).unwrap();
269        assert_eq!(
270            &*code.to_debug_str('#', '.'),
271            "\
272             #######..#.##.#######\n\
273             #.....#..####.#.....#\n\
274             #.###.#.#.....#.###.#\n\
275             #.###.#.##....#.###.#\n\
276             #.###.#.#.###.#.###.#\n\
277             #.....#.#...#.#.....#\n\
278             #######.#.#.#.#######\n\
279             ........#..##........\n\
280             #.#####..#..#.#####..\n\
281             ...#.#.##.#.#..#.##..\n\
282             ..#...##.#.#.#..#####\n\
283             ....#....#.....####..\n\
284             ...######..#.#..#....\n\
285             ........#.#####..##..\n\
286             #######..##.#.##.....\n\
287             #.....#.#.#####...#.#\n\
288             #.###.#.#...#..#.##..\n\
289             #.###.#.##..#..#.....\n\
290             #.###.#.#.##.#..#.#..\n\
291             #.....#........##.##.\n\
292             #######.####.#..#.#.."
293        );
294    }
295
296    #[test]
297    fn test_annex_i_micro_qr() {
298        let code = QrCode::with_version(b"01234567", Version::Micro(2), EcLevel::L).unwrap();
299        assert_eq!(
300            &*code.to_debug_str('#', '.'),
301            "\
302             #######.#.#.#\n\
303             #.....#.###.#\n\
304             #.###.#..##.#\n\
305             #.###.#..####\n\
306             #.###.#.###..\n\
307             #.....#.#...#\n\
308             #######..####\n\
309             .........##..\n\
310             ##.#....#...#\n\
311             .##.#.#.#.#.#\n\
312             ###..#######.\n\
313             ...#.#....##.\n\
314             ###.#..##.###"
315        );
316    }
317}
318
319#[cfg(all(test, feature = "image"))]
320mod image_tests {
321    use crate::{EcLevel, QrCode, Version};
322    use image::{load_from_memory, Luma, Rgb};
323
324    #[test]
325    fn test_annex_i_qr_as_image() {
326        let code = QrCode::new(b"01234567").unwrap();
327        let image = code.render::<Luma<u8>>().build();
328        let expected = load_from_memory(include_bytes!("test_annex_i_qr_as_image.png")).unwrap().to_luma();
329        assert_eq!(image.dimensions(), expected.dimensions());
330        assert_eq!(image.into_raw(), expected.into_raw());
331    }
332
333    #[test]
334    fn test_annex_i_micro_qr_as_image() {
335        let code = QrCode::with_version(b"01234567", Version::Micro(2), EcLevel::L).unwrap();
336        let image = code
337            .render()
338            .min_dimensions(200, 200)
339            .dark_color(Rgb([128, 0, 0]))
340            .light_color(Rgb([255, 255, 128]))
341            .build();
342        let expected = load_from_memory(include_bytes!("test_annex_i_micro_qr_as_image.png")).unwrap().to_rgb();
343        assert_eq!(image.dimensions(), expected.dimensions());
344        assert_eq!(image.into_raw(), expected.into_raw());
345    }
346}
347
348#[cfg(all(test, feature = "svg"))]
349mod svg_tests {
350    use crate::render::svg::Color as SvgColor;
351    use crate::{EcLevel, QrCode, Version};
352
353    #[test]
354    fn test_annex_i_qr_as_svg() {
355        let code = QrCode::new(b"01234567").unwrap();
356        let image = code.render::<SvgColor>().build();
357        let expected = include_str!("test_annex_i_qr_as_svg.svg");
358        assert_eq!(&image, expected);
359    }
360
361    #[test]
362    fn test_annex_i_micro_qr_as_svg() {
363        let code = QrCode::with_version(b"01234567", Version::Micro(2), EcLevel::L).unwrap();
364        let image = code
365            .render()
366            .min_dimensions(200, 200)
367            .dark_color(SvgColor("#800000"))
368            .light_color(SvgColor("#ffff80"))
369            .build();
370        let expected = include_str!("test_annex_i_micro_qr_as_svg.svg");
371        assert_eq!(&image, expected);
372    }
373}