qrcode_rs/render/
string.rs

1//! String rendering support.
2
3use crate::cast::As;
4use crate::render::{Canvas as RenderCanvas, Pixel};
5use crate::types::Color;
6
7pub trait Element: Copy {
8    fn default_color(color: Color) -> Self;
9    fn strlen(self) -> usize;
10    fn append_to_string(self, string: &mut String);
11}
12
13impl Element for char {
14    fn default_color(color: Color) -> Self {
15        color.select('\u{2588}', ' ')
16    }
17
18    fn strlen(self) -> usize {
19        self.len_utf8()
20    }
21
22    fn append_to_string(self, string: &mut String) {
23        string.push(self);
24    }
25}
26
27impl<'a> Element for &'a str {
28    fn default_color(color: Color) -> Self {
29        color.select("\u{2588}", " ")
30    }
31
32    fn strlen(self) -> usize {
33        self.len()
34    }
35
36    fn append_to_string(self, string: &mut String) {
37        string.push_str(self);
38    }
39}
40
41#[doc(hidden)]
42pub struct Canvas<P: Element> {
43    buffer: Vec<P>,
44    width: usize,
45    dark_pixel: P,
46    dark_cap_inc: isize,
47    capacity: isize,
48}
49
50impl<P: Element> Pixel for P {
51    type Image = String;
52    type Canvas = Canvas<Self>;
53
54    fn default_unit_size() -> (u32, u32) {
55        (1, 1)
56    }
57
58    fn default_color(color: Color) -> Self {
59        <Self as Element>::default_color(color)
60    }
61}
62
63impl<P: Element> RenderCanvas for Canvas<P> {
64    type Pixel = P;
65    type Image = String;
66
67    fn new(width: u32, height: u32, dark_pixel: P, light_pixel: P) -> Self {
68        let width = width.as_usize();
69        let height = height.as_isize();
70        let dark_cap = dark_pixel.strlen().as_isize();
71        let light_cap = light_pixel.strlen().as_isize();
72        Self {
73            buffer: vec![light_pixel; width * height.as_usize()],
74            width,
75            dark_pixel,
76            dark_cap_inc: dark_cap - light_cap,
77            capacity: light_cap * width.as_isize() * height + (height - 1),
78        }
79    }
80
81    fn draw_dark_pixel(&mut self, x: u32, y: u32) {
82        let x = x.as_usize();
83        let y = y.as_usize();
84        self.capacity += self.dark_cap_inc;
85        self.buffer[x + y * self.width] = self.dark_pixel;
86    }
87
88    fn into_image(self) -> String {
89        let mut result = String::with_capacity(self.capacity.as_usize());
90        for (i, pixel) in self.buffer.into_iter().enumerate() {
91            if i != 0 && i % self.width == 0 {
92                result.push('\n');
93            }
94            pixel.append_to_string(&mut result);
95        }
96        result
97    }
98}
99
100#[test]
101fn test_render_to_string() {
102    use crate::render::Renderer;
103
104    let colors = &[Color::Dark, Color::Light, Color::Light, Color::Dark];
105    let image: String = Renderer::<char>::new(colors, 2, 1).build();
106    assert_eq!(&image, "    \n \u{2588}  \n  \u{2588} \n    ");
107
108    let image2 = Renderer::new(colors, 2, 1).light_color("A").dark_color("!B!").module_dimensions(2, 2).build();
109
110    assert_eq!(
111        &image2,
112        "AAAAAAAA\n\
113         AAAAAAAA\n\
114         AA!B!!B!AAAA\n\
115         AA!B!!B!AAAA\n\
116         AAAA!B!!B!AA\n\
117         AAAA!B!!B!AA\n\
118         AAAAAAAA\n\
119         AAAAAAAA"
120    );
121}