1use crate::{QrCode, QrImage, QrResult, Version};
2use image::{
3 imageops::{resize, FilterType},
4 DynamicImage, GenericImage, GenericImageView, Rgb, RgbImage,
5};
6
7impl QrImage {
8 fn target_qr(&self, data: &[u8]) -> QrResult<QrCode> {
9 if self.auto_size {
10 match QrCode::with_version(data, self.qr_version, self.ec_level) {
11 Ok(o) => Ok(o),
12 Err(_) => match QrCode::with_error_correction_level(data, self.ec_level) {
13 Ok(o) => Ok(o),
14 Err(_) => QrCode::new(data),
15 },
16 }
17 }
18 else {
19 QrCode::with_version(data, self.qr_version, self.ec_level)
20 }
21 }
22 pub fn render(&self, data: &[u8], img: &DynamicImage) -> QrResult<DynamicImage> {
23 let qr = self.target_qr(data)?;
24 let size = qr.width() as u32;
25 let out = resize(img, 3 * size, 3 * size, FilterType::Triangle);
26 let rgb = unsafe {
27 redraw_locations(
28 &qr,
29 DynamicImage::ImageRgba8(out).into_rgb8(),
30 self.dark_color,
31 self.light_color,
32 self.enhanced,
33 !self.enhanced,
34 )
35 };
36 return Ok(DynamicImage::ImageRgb8(rgb));
37 }
38 pub fn render_frames(&self) {
39 unimplemented!()
40 }
41}
42
43pub unsafe fn get_align_locations(qr: &QrCode) -> Vec<(usize, usize)> {
44 let mut aligns = vec![];
45 match qr.version() {
46 Version::Normal(ver) => {
47 let align_location: &[Vec<usize>; 40] = &[
48 vec![],
49 vec![6, 18],
50 vec![6, 22],
51 vec![6, 26],
52 vec![6, 30],
53 vec![6, 34],
54 vec![6, 22, 38],
55 vec![6, 24, 42],
56 vec![6, 26, 46],
57 vec![6, 28, 50],
58 vec![6, 30, 54],
59 vec![6, 32, 58],
60 vec![6, 34, 62],
61 vec![6, 26, 46, 66],
62 vec![6, 26, 48, 70],
63 vec![6, 26, 50, 74],
64 vec![6, 30, 54, 78],
65 vec![6, 30, 56, 82],
66 vec![6, 30, 58, 86],
67 vec![6, 34, 62, 90],
68 vec![6, 28, 50, 72, 94],
69 vec![6, 26, 50, 74, 98],
70 vec![6, 30, 54, 78, 102],
71 vec![6, 28, 54, 80, 106],
72 vec![6, 32, 58, 84, 110],
73 vec![6, 30, 58, 86, 114],
74 vec![6, 34, 62, 90, 118],
75 vec![6, 26, 50, 74, 98, 122],
76 vec![6, 30, 54, 78, 102, 126],
77 vec![6, 26, 52, 78, 104, 130],
78 vec![6, 30, 56, 82, 108, 134],
79 vec![6, 34, 60, 86, 112, 138],
80 vec![6, 30, 58, 86, 114, 142],
81 vec![6, 34, 62, 90, 118, 146],
82 vec![6, 30, 54, 78, 102, 126, 150],
83 vec![6, 24, 50, 76, 102, 128, 154],
84 vec![6, 28, 54, 80, 106, 132, 158],
85 vec![6, 32, 58, 84, 110, 136, 162],
86 vec![6, 26, 54, 82, 110, 138, 166],
87 vec![6, 30, 58, 86, 114, 142, 170],
88 ];
89 let loc = align_location.get_unchecked(ver as usize - 1);
90 for a in 0..loc.len() {
91 for b in 0..loc.len() {
92 if !((a == 0 || b == 0) || (a == loc.len() - 1 && b == 0) || (a == 0 && b == loc.len() - 1)) {
93 for i in (loc.get_unchecked(a) * 3 - 6)..(loc.get_unchecked(a) * 3 + 9) {
94 for j in (loc.get_unchecked(b) * 3 - 6)..(loc.get_unchecked(b) * 3 + 9) {
95 aligns.push((i, j))
96 }
97 }
98 }
99 }
100 }
101 }
102 Version::Micro(ver) => {
103 let _ = ver;
104 unimplemented!()
105 }
106 }
107 return aligns;
108}
109
110#[rustfmt::skip]
111pub unsafe fn redraw_locations(qr: &QrCode, bg: RgbImage, dark: Rgb<u8>, light: Rgb<u8>, enhanced: bool, skip_bg: bool) -> RgbImage {
112 let aligns = get_align_locations(qr);
113 let mut qr_img = qr_render_rgb(qr, dark, light);
114 for i in 0..qr_img.width() - 0 {
117 for j in 0..qr_img.width() - 0 {
118 let _ = skip_bg;
119 if (i < 21 && j < 21)
120 || (i < 21 && j > qr_img.width() - 22)
121 || (i > qr_img.width() - 22 && j < 21)
122 || (enhanced && [18, 19, 20].contains(&i))
123 || (enhanced && [18, 19, 20].contains(&j))
124 || (enhanced && aligns.contains(&(i as usize + 0, j as usize + 0)))
125 || (i % 3 == 1 && j % 3 == 1)
126 {
128 continue;
129 }
130 else {
131 qr_img.unsafe_put_pixel(i, j, bg.unsafe_get_pixel(i, j))
132 }
133 }
134 }
135 return qr_img;
136}
137
138pub fn qr_render_rgb(qr: &QrCode, dark: Rgb<u8>, light: Rgb<u8>) -> RgbImage {
139 qr.render().quiet_zone(false).module_dimensions(3, 3).dark_color(dark).light_color(light).build()
140}