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