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
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
//! Create a QR code
//! ```
//! use qrcode_png::{QrCode, QrCodeEcc, Color};
//!
//! let mut qrcode = QrCode::new(b"Hello Rust !", QrCodeEcc::Medium).unwrap();
//!
//! qrcode.zoom(10).margin(10);
//!
//! // -------- Bitmap
//! let buf = qrcode.generate(Color::Bitmap(false, true)).unwrap();
//! std::fs::write("./qrcode.bitmap.png", buf).unwrap();
//!
//! // -------- Grayscale
//! let buf = qrcode.generate(Color::Grayscale(0, 255)).unwrap();
//! std::fs::write("./qrcode.grayscale.png", buf).unwrap();
//!
//! // -------- RGB
//! let buf = qrcode
//!     .generate(Color::Rgb([3, 169, 244], [113, 140, 0]))
//!     .unwrap();
//! std::fs::write("./qrcode.rgb.png", buf).unwrap();
//!
//! // -------- RGBA
//! let buf = qrcode
//!     .generate(Color::Rgba([137, 89, 168, 255], [255, 255, 255, 0]))
//!     .unwrap();
//! std::fs::write("./qrcode.rgba.png", buf).unwrap();
//! ```

mod image;

pub use image::Color;
use image::Png;
use png::EncodingError;
pub use qrcodegen::QrCodeEcc;
use qrcodegen::{DataTooLong, QrCode as QrCode_};

/// Define QR code
#[derive(Clone)]
pub struct QrCode {
    // QR Code
    qr: QrCode_,
    // Zoom factor
    zoom: u32,
    // Margin of the QR code from the picture
    margin: u32,
}

impl QrCode {
    /// Create a QR code
    pub fn new<T: AsRef<[u8]>>(content: T, ecl: QrCodeEcc) -> Result<Self, DataTooLong> {
        let qr = QrCode_::encode_binary(content.as_ref(), ecl)?;

        Ok(Self {
            qr,
            zoom: 1,
            margin: 0,
        })
    }

    /// Enlarge the QR code according to the original scale,
    /// Default value: 1
    pub fn zoom(&mut self, zoom: u32) -> &mut Self {
        assert_ne!(zoom, 0, "The minimum value is 1");
        self.zoom = zoom;
        self
    }

    /// Set the distance between the QR code and the edge of the picture
    pub fn margin(&mut self, margin: u32) -> &mut Self {
        self.margin = margin;
        self
    }

    /// Get png data of QR code
    pub fn generate(&self, color: Color) -> Result<Vec<u8>, EncodingError> {
        let size = self.qr.size() as u32 * self.zoom + self.margin * 2;

        let mut image = Png::new(size as usize, size as usize, color);

        for x in 0..self.qr.size() {
            for y in 0..self.qr.size() {
                if self.qr.get_module(x, y) {
                    let x_start = (x as u32 * self.zoom) + self.margin;
                    let y_start = (y as u32 * self.zoom) + self.margin;

                    for x in x_start..x_start + self.zoom {
                        for y in y_start..y_start + self.zoom {
                            image.set_color(x as usize, y as usize);
                        }
                    }
                }
            }
        }

        image.encode()
    }
}