1use crate::render::{Canvas as RenderCanvas, Color, Pixel};
4
5const CODEPAGE: [&str; 4] = [" ", "\u{2584}", "\u{2580}", "\u{2588}"];
6
7#[derive(Copy, Clone, PartialEq)]
8pub enum Dense1x2 {
9 Dark,
10 Light,
11}
12
13impl Pixel for Dense1x2 {
14 type Image = String;
15 type Canvas = Canvas1x2;
16 fn default_color(color: Color) -> Dense1x2 {
17 color.select(Dense1x2::Dark, Dense1x2::Light)
18 }
19 fn default_unit_size() -> (u32, u32) {
20 (1, 1)
21 }
22}
23
24impl Dense1x2 {
25 fn value(self) -> u8 {
26 match self {
27 Dense1x2::Dark => 1,
28 Dense1x2::Light => 0,
29 }
30 }
31 fn parse_2_bits(sym: u8) -> &'static str {
32 CODEPAGE[usize::from(sym)]
33 }
34}
35
36pub struct Canvas1x2 {
37 canvas: Vec<u8>,
38 width: u32,
39 dark_pixel: u8,
40}
41
42impl RenderCanvas for Canvas1x2 {
43 type Pixel = Dense1x2;
44 type Image = String;
45
46 fn new(width: u32, height: u32, dark_pixel: Dense1x2, light_pixel: Dense1x2) -> Self {
47 let a = vec![light_pixel.value(); (width * height) as usize];
48 Canvas1x2 { width, canvas: a, dark_pixel: dark_pixel.value() }
49 }
50
51 fn draw_dark_pixel(&mut self, x: u32, y: u32) {
52 self.canvas[(x + y * self.width) as usize] = self.dark_pixel;
53 }
54
55 fn into_image(self) -> String {
56 self.canvas
57 .chunks_exact(self.width as usize)
59 .collect::<Vec<&[u8]>>()
60 .chunks(2)
62 .map(|rows| {
63 {
64 if rows.len() == 2 {
66 rows[0].iter().zip(rows[1]).map(|(top, bot)| (top * 2 + bot)).collect::<Vec<u8>>()
67 } else {
68 rows[0].iter().map(|top| (top * 2)).collect::<Vec<u8>>()
69 }
70 }
71 .into_iter()
72 .map(Dense1x2::parse_2_bits)
74 .collect::<Vec<&str>>()
75 .concat()
76 })
77 .collect::<Vec<String>>()
78 .join("\n")
79 }
80}
81
82#[test]
83fn test_render_to_utf8_string() {
84 use crate::render::Renderer;
85 let colors = &[Color::Dark, Color::Light, Color::Light, Color::Dark];
86 let image: String = Renderer::<Dense1x2>::new(colors, 2, 1).build();
87
88 assert_eq!(&image, " ▄ \n ▀ ");
89
90 let image2 = Renderer::<Dense1x2>::new(colors, 2, 1).module_dimensions(2, 2).build();
91
92 assert_eq!(&image2, " \n ██ \n ██ \n ");
93}
94
95#[test]
96fn integration_render_utf8_1x2() {
97 use crate::render::unicode::Dense1x2;
98 use crate::{EcLevel, QrCode, Version};
99
100 let code = QrCode::with_version(b"09876542", Version::Micro(2), EcLevel::L).unwrap();
101 let image = code.render::<Dense1x2>().module_dimensions(1, 1).build();
102 assert_eq!(
103 image,
104 String::new()
105 + " \n"
106 + " █▀▀▀▀▀█ ▀ █ ▀ \n"
107 + " █ ███ █ ▀ █ \n"
108 + " █ ▀▀▀ █ ▀█ █ \n"
109 + " ▀▀▀▀▀▀▀ ▄▀▀ █ \n"
110 + " ▀█ ▀▀▀▀▀██▀▀▄ \n"
111 + " ▀███▄ ▀▀ █ ██ \n"
112 + " ▀▀▀ ▀ ▀▀ ▀ ▀ \n"
113 + " "
114 )
115}
116
117#[test]
118fn integration_render_utf8_1x2_inverted() {
119 use crate::render::unicode::Dense1x2;
120 use crate::{EcLevel, QrCode, Version};
121
122 let code = QrCode::with_version(b"12345678", Version::Micro(2), EcLevel::L).unwrap();
123 let image = code
124 .render::<Dense1x2>()
125 .dark_color(Dense1x2::Light)
126 .light_color(Dense1x2::Dark)
127 .module_dimensions(1, 1)
128 .build();
129 assert_eq!(
130 image,
131 "█████████████████\n\
132 ██ ▄▄▄▄▄ █▄▀▄█▄██\n\
133 ██ █ █ █ █ ██\n\
134 ██ █▄▄▄█ █▄▄██▀██\n\
135 ██▄▄▄▄▄▄▄█▄▄▄▀ ██\n\
136 ██▄ ▀ ▀ ▀▄▄ ████\n\
137 ██▄▄▀▄█ ▀▀▀ ▀▄▄██\n\
138 ██▄▄▄█▄▄█▄██▄█▄██\n\
139 ▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀"
140 );
141}