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