1#[cfg(not(feature = "std"))]
31#[allow(unused_imports)]
32use alloc::{
33 borrow::ToOwned,
34 format,
35 string::{String, ToString},
36 vec,
37 vec::Vec,
38};
39
40use core::cmp::{max, min};
41
42use crate::cast::As;
43use crate::types::{Color, EcLevel, Version};
44
45#[derive(PartialEq, Eq, Clone, Copy, Debug)]
50pub enum Module {
51 Empty,
53
54 Masked(Color),
57
58 Unmasked(Color),
60}
61
62impl From<Module> for Color {
63 fn from(module: Module) -> Self {
64 match module {
65 Module::Empty => Color::Light,
66 Module::Masked(c) | Module::Unmasked(c) => c,
67 }
68 }
69}
70
71impl Module {
72 pub fn is_dark(self) -> bool {
74 Color::from(self) == Color::Dark
75 }
76
77 #[must_use]
89 pub fn mask(self, should_invert: bool) -> Self {
90 match (self, should_invert) {
91 (Module::Empty, true) => Module::Masked(Color::Dark),
92 (Module::Empty, false) => Module::Masked(Color::Light),
93 (Module::Unmasked(c), true) => Module::Masked(!c),
94 (Module::Unmasked(c), false) | (Module::Masked(c), _) => Module::Masked(c),
95 }
96 }
97}
98
99#[derive(Clone)]
106pub struct Canvas {
107 width: i16,
109
110 version: Version,
112
113 ec_level: EcLevel,
115
116 modules: Vec<Module>,
119}
120
121impl Canvas {
122 pub fn new(version: Version, ec_level: EcLevel) -> Self {
124 let width = version.width();
125 Self { width, version, ec_level, modules: vec![Module::Empty; (width * width).as_usize()] }
126 }
127
128 #[cfg(test)]
130 fn to_debug_str(&self) -> String {
131 let width = self.width;
132 let mut res = String::with_capacity((width * (width + 1)).as_usize());
133 for y in 0..width {
134 res.push('\n');
135 for x in 0..width {
136 res.push(match self.get(x, y) {
137 Module::Empty => '?',
138 Module::Masked(Color::Light) => '.',
139 Module::Masked(Color::Dark) => '#',
140 Module::Unmasked(Color::Light) => '-',
141 Module::Unmasked(Color::Dark) => '*',
142 });
143 }
144 }
145 res
146 }
147
148 fn coords_to_index(&self, x: i16, y: i16) -> usize {
149 let x = if x < 0 { x + self.width } else { x }.as_usize();
150 let y = if y < 0 { y + self.width } else { y }.as_usize();
151 y * self.width.as_usize() + x
152 }
153
154 pub fn get(&self, x: i16, y: i16) -> Module {
157 self.modules[self.coords_to_index(x, y)]
158 }
159
160 pub fn get_mut(&mut self, x: i16, y: i16) -> &mut Module {
163 let index = self.coords_to_index(x, y);
164 &mut self.modules[index]
165 }
166
167 pub fn put(&mut self, x: i16, y: i16, color: Color) {
170 *self.get_mut(x, y) = Module::Masked(color);
171 }
172}
173
174#[cfg(test)]
175mod basic_canvas_tests {
176 use crate::canvas::{Canvas, Module};
177 use crate::types::{Color, EcLevel, Version};
178
179 #[test]
180 fn test_index() {
181 let mut c = Canvas::new(Version::Normal(1), EcLevel::L);
182
183 assert_eq!(c.get(0, 4), Module::Empty);
184 assert_eq!(c.get(-1, -7), Module::Empty);
185 assert_eq!(c.get(21 - 1, 21 - 7), Module::Empty);
186
187 c.put(0, 0, Color::Dark);
188 c.put(-1, -7, Color::Light);
189 assert_eq!(c.get(0, 0), Module::Masked(Color::Dark));
190 assert_eq!(c.get(21 - 1, -7), Module::Masked(Color::Light));
191 assert_eq!(c.get(-1, 21 - 7), Module::Masked(Color::Light));
192 }
193
194 #[test]
195 fn test_debug_str() {
196 let mut c = Canvas::new(Version::Normal(1), EcLevel::L);
197
198 for i in 3_i16..20 {
199 for j in 3_i16..20 {
200 *c.get_mut(i, j) = match ((i * 3) ^ j) % 5 {
201 0 => Module::Empty,
202 1 => Module::Masked(Color::Light),
203 2 => Module::Masked(Color::Dark),
204 3 => Module::Unmasked(Color::Light),
205 4 => Module::Unmasked(Color::Dark),
206 _ => unreachable!(),
207 };
208 }
209 }
210
211 assert_eq!(
212 &*c.to_debug_str(),
213 "\n\
214 ?????????????????????\n\
215 ?????????????????????\n\
216 ?????????????????????\n\
217 ?????####****....---?\n\
218 ???--.##-..##?..#??.?\n\
219 ???#*?-.*?#.-*#?-*.??\n\
220 ?????*?*?****-*-*---?\n\
221 ???*.-.-.-?-?#?#?#*#?\n\
222 ???.*#.*.*#.*#*#.*#*?\n\
223 ?????.#-#--??.?.#---?\n\
224 ???-.?*.-#?-.?#*-#?.?\n\
225 ???##*??*..##*--*..??\n\
226 ?????-???--??---?---?\n\
227 ???*.#.*.#**.#*#.#*#?\n\
228 ???##.-##..##..?#..??\n\
229 ???.-?*.-?#.-?#*-?#*?\n\
230 ????-.#?-.**#?-.#?-.?\n\
231 ???**?-**??--**?-**??\n\
232 ???#?*?#?*#.*-.-*-.-?\n\
233 ???..-...--??###?###?\n\
234 ?????????????????????"
235 );
236 }
237}
238
239impl Canvas {
244 fn draw_finder_pattern_at(&mut self, x: i16, y: i16) {
246 let (dx_left, dx_right) = if x >= 0 { (-3, 4) } else { (-4, 3) };
247 let (dy_top, dy_bottom) = if y >= 0 { (-3, 4) } else { (-4, 3) };
248 for j in dy_top..=dy_bottom {
249 for i in dx_left..=dx_right {
250 self.put(
251 x + i,
252 y + j,
253 #[allow(clippy::match_same_arms)]
254 match (i, j) {
255 (4 | -4, _) | (_, 4 | -4) => Color::Light,
256 (3 | -3, _) | (_, 3 | -3) => Color::Dark,
257 (2 | -2, _) | (_, 2 | -2) => Color::Light,
258 _ => Color::Dark,
259 },
260 );
261 }
262 }
263 }
264
265 fn draw_finder_patterns(&mut self) {
271 self.draw_finder_pattern_at(3, 3);
272
273 match self.version {
274 Version::Micro(_) => {}
275 Version::Normal(_) => {
276 self.draw_finder_pattern_at(-4, 3);
277 self.draw_finder_pattern_at(3, -4);
278 }
279 }
280 }
281}
282
283#[cfg(test)]
284mod finder_pattern_tests {
285 use crate::canvas::Canvas;
286 use crate::types::{EcLevel, Version};
287
288 #[test]
289 fn test_qr() {
290 let mut c = Canvas::new(Version::Normal(1), EcLevel::L);
291 c.draw_finder_patterns();
292 assert_eq!(
293 &*c.to_debug_str(),
294 "\n\
295 #######.?????.#######\n\
296 #.....#.?????.#.....#\n\
297 #.###.#.?????.#.###.#\n\
298 #.###.#.?????.#.###.#\n\
299 #.###.#.?????.#.###.#\n\
300 #.....#.?????.#.....#\n\
301 #######.?????.#######\n\
302 ........?????........\n\
303 ?????????????????????\n\
304 ?????????????????????\n\
305 ?????????????????????\n\
306 ?????????????????????\n\
307 ?????????????????????\n\
308 ........?????????????\n\
309 #######.?????????????\n\
310 #.....#.?????????????\n\
311 #.###.#.?????????????\n\
312 #.###.#.?????????????\n\
313 #.###.#.?????????????\n\
314 #.....#.?????????????\n\
315 #######.?????????????"
316 );
317 }
318
319 #[test]
320 fn test_micro_qr() {
321 let mut c = Canvas::new(Version::Micro(1), EcLevel::L);
322 c.draw_finder_patterns();
323 assert_eq!(
324 &*c.to_debug_str(),
325 "\n\
326 #######.???\n\
327 #.....#.???\n\
328 #.###.#.???\n\
329 #.###.#.???\n\
330 #.###.#.???\n\
331 #.....#.???\n\
332 #######.???\n\
333 ........???\n\
334 ???????????\n\
335 ???????????\n\
336 ???????????"
337 );
338 }
339}
340
341impl Canvas {
346 fn draw_alignment_pattern_at(&mut self, x: i16, y: i16) {
348 if self.get(x, y) != Module::Empty {
349 return;
350 }
351 for j in -2..=2 {
352 for i in -2..=2 {
353 self.put(
354 x + i,
355 y + j,
356 match (i, j) {
357 (2 | -2, _) | (_, 2 | -2) | (0, 0) => Color::Dark,
358 _ => Color::Light,
359 },
360 );
361 }
362 }
363 }
364
365 fn draw_alignment_patterns(&mut self) {
370 match self.version {
371 Version::Micro(_) | Version::Normal(1) => {}
372 Version::Normal(a @ 2..=40) => {
373 let positions = alignment_pattern_positions(a);
374 for x in positions {
375 for y in positions {
376 self.draw_alignment_pattern_at(*x, *y);
377 }
378 }
379 }
380 Version::Normal(_) => {}
381 }
382 }
383}
384
385#[cfg(test)]
386mod alignment_pattern_tests {
387 use crate::canvas::{Canvas, alignment_pattern_positions};
388 use crate::types::{EcLevel, Version};
389
390 #[test]
391 fn test_draw_alignment_patterns_1() {
392 let mut c = Canvas::new(Version::Normal(1), EcLevel::L);
393 c.draw_finder_patterns();
394 c.draw_alignment_patterns();
395 assert_eq!(
396 &*c.to_debug_str(),
397 "\n\
398 #######.?????.#######\n\
399 #.....#.?????.#.....#\n\
400 #.###.#.?????.#.###.#\n\
401 #.###.#.?????.#.###.#\n\
402 #.###.#.?????.#.###.#\n\
403 #.....#.?????.#.....#\n\
404 #######.?????.#######\n\
405 ........?????........\n\
406 ?????????????????????\n\
407 ?????????????????????\n\
408 ?????????????????????\n\
409 ?????????????????????\n\
410 ?????????????????????\n\
411 ........?????????????\n\
412 #######.?????????????\n\
413 #.....#.?????????????\n\
414 #.###.#.?????????????\n\
415 #.###.#.?????????????\n\
416 #.###.#.?????????????\n\
417 #.....#.?????????????\n\
418 #######.?????????????"
419 );
420 }
421
422 #[test]
423 fn test_draw_alignment_patterns_3() {
424 let mut c = Canvas::new(Version::Normal(3), EcLevel::L);
425 c.draw_finder_patterns();
426 c.draw_alignment_patterns();
427 assert_eq!(
428 &*c.to_debug_str(),
429 "\n\
430 #######.?????????????.#######\n\
431 #.....#.?????????????.#.....#\n\
432 #.###.#.?????????????.#.###.#\n\
433 #.###.#.?????????????.#.###.#\n\
434 #.###.#.?????????????.#.###.#\n\
435 #.....#.?????????????.#.....#\n\
436 #######.?????????????.#######\n\
437 ........?????????????........\n\
438 ?????????????????????????????\n\
439 ?????????????????????????????\n\
440 ?????????????????????????????\n\
441 ?????????????????????????????\n\
442 ?????????????????????????????\n\
443 ?????????????????????????????\n\
444 ?????????????????????????????\n\
445 ?????????????????????????????\n\
446 ?????????????????????????????\n\
447 ?????????????????????????????\n\
448 ?????????????????????????????\n\
449 ?????????????????????????????\n\
450 ????????????????????#####????\n\
451 ........????????????#...#????\n\
452 #######.????????????#.#.#????\n\
453 #.....#.????????????#...#????\n\
454 #.###.#.????????????#####????\n\
455 #.###.#.?????????????????????\n\
456 #.###.#.?????????????????????\n\
457 #.....#.?????????????????????\n\
458 #######.?????????????????????"
459 );
460 }
461
462 #[test]
463 fn test_draw_alignment_patterns_7() {
464 let mut c = Canvas::new(Version::Normal(7), EcLevel::L);
465 c.draw_finder_patterns();
466 c.draw_alignment_patterns();
467 assert_eq!(
468 &*c.to_debug_str(),
469 "\n\
470 #######.?????????????????????????????.#######\n\
471 #.....#.?????????????????????????????.#.....#\n\
472 #.###.#.?????????????????????????????.#.###.#\n\
473 #.###.#.?????????????????????????????.#.###.#\n\
474 #.###.#.????????????#####????????????.#.###.#\n\
475 #.....#.????????????#...#????????????.#.....#\n\
476 #######.????????????#.#.#????????????.#######\n\
477 ........????????????#...#????????????........\n\
478 ????????????????????#####????????????????????\n\
479 ?????????????????????????????????????????????\n\
480 ?????????????????????????????????????????????\n\
481 ?????????????????????????????????????????????\n\
482 ?????????????????????????????????????????????\n\
483 ?????????????????????????????????????????????\n\
484 ?????????????????????????????????????????????\n\
485 ?????????????????????????????????????????????\n\
486 ?????????????????????????????????????????????\n\
487 ?????????????????????????????????????????????\n\
488 ?????????????????????????????????????????????\n\
489 ?????????????????????????????????????????????\n\
490 ????#####???????????#####???????????#####????\n\
491 ????#...#???????????#...#???????????#...#????\n\
492 ????#.#.#???????????#.#.#???????????#.#.#????\n\
493 ????#...#???????????#...#???????????#...#????\n\
494 ????#####???????????#####???????????#####????\n\
495 ?????????????????????????????????????????????\n\
496 ?????????????????????????????????????????????\n\
497 ?????????????????????????????????????????????\n\
498 ?????????????????????????????????????????????\n\
499 ?????????????????????????????????????????????\n\
500 ?????????????????????????????????????????????\n\
501 ?????????????????????????????????????????????\n\
502 ?????????????????????????????????????????????\n\
503 ?????????????????????????????????????????????\n\
504 ?????????????????????????????????????????????\n\
505 ?????????????????????????????????????????????\n\
506 ????????????????????#####???????????#####????\n\
507 ........????????????#...#???????????#...#????\n\
508 #######.????????????#.#.#???????????#.#.#????\n\
509 #.....#.????????????#...#???????????#...#????\n\
510 #.###.#.????????????#####???????????#####????\n\
511 #.###.#.?????????????????????????????????????\n\
512 #.###.#.?????????????????????????????????????\n\
513 #.....#.?????????????????????????????????????\n\
514 #######.?????????????????????????????????????"
515 );
516 }
517
518 #[test]
519 fn generated_alignment_pattern_positions_match_known_versions() {
520 assert_eq!(alignment_pattern_positions(1), &[]);
521 assert_eq!(alignment_pattern_positions(2), &[6, 18]);
522 assert_eq!(alignment_pattern_positions(7), &[6, 22, 38]);
523 assert_eq!(alignment_pattern_positions(14), &[6, 26, 46, 66]);
524 assert_eq!(alignment_pattern_positions(32), &[6, 34, 60, 86, 112, 138]);
525 assert_eq!(alignment_pattern_positions(40), &[6, 30, 58, 86, 114, 142, 170]);
526 }
527}
528
529static ALIGNMENT_PATTERN_POSITIONS: [AlignmentPatternPositions; 40] = generate_alignment_pattern_positions();
533const MAX_ALIGNMENT_PATTERNS: usize = 7;
534
535#[derive(Clone, Copy)]
536struct AlignmentPatternPositions {
537 positions: [i16; MAX_ALIGNMENT_PATTERNS],
538 len: usize,
539}
540
541impl AlignmentPatternPositions {
542 fn as_slice(&self) -> &[i16] {
543 &self.positions[..self.len]
544 }
545}
546
547fn alignment_pattern_positions(version: i16) -> &'static [i16] {
548 match version {
549 1..=40 => ALIGNMENT_PATTERN_POSITIONS[(version - 1) as usize].as_slice(),
550 _ => &[],
551 }
552}
553
554const fn generate_alignment_pattern_positions() -> [AlignmentPatternPositions; 40] {
555 let mut table = [AlignmentPatternPositions { positions: [0; MAX_ALIGNMENT_PATTERNS], len: 0 }; 40];
556 let mut version = 1;
557 while version <= 40 {
558 table[(version - 1) as usize] = compute_alignment_pattern_positions(version);
559 version += 1;
560 }
561 table
562}
563
564const fn compute_alignment_pattern_positions(version: i16) -> AlignmentPatternPositions {
565 let count = if version == 1 { 0 } else { version / 7 + 2 };
566 let mut result = AlignmentPatternPositions { positions: [0; MAX_ALIGNMENT_PATTERNS], len: count as usize };
567 if count == 0 {
568 return result;
569 }
570
571 let width = version * 4 + 17;
572 let step = alignment_pattern_step(version, count);
573 let mut index = count - 1;
574 let mut position = width - 7;
575 while index > 0 {
576 result.positions[index as usize] = position;
577 position -= step;
578 index -= 1;
579 }
580 result.positions[0] = 6;
581 result
582}
583
584const fn alignment_pattern_step(version: i16, count: i16) -> i16 {
585 if version == 32 { 26 } else { ((version * 4 + count * 2 + 1) / (count * 2 - 2)) * 2 }
586}
587
588impl Canvas {
593 fn draw_line(&mut self, x1: i16, y1: i16, x2: i16, y2: i16, color_even: Color, color_odd: Color) {
604 debug_assert!(x1 == x2 || y1 == y2);
605
606 if y1 == y2 {
607 for x in x1..=x2 {
609 self.put(x, y1, if x % 2 == 0 { color_even } else { color_odd });
610 }
611 } else {
612 for y in y1..=y2 {
614 self.put(x1, y, if y % 2 == 0 { color_even } else { color_odd });
615 }
616 }
617 }
618
619 fn draw_timing_patterns(&mut self) {
625 let width = self.width;
626 let (y, x1, x2) = match self.version {
627 Version::Micro(_) => (0, 8, width - 1),
628 Version::Normal(_) => (6, 8, width - 9),
629 };
630 self.draw_line(x1, y, x2, y, Color::Dark, Color::Light);
631 self.draw_line(y, x1, y, x2, Color::Dark, Color::Light);
632 }
633}
634
635#[cfg(test)]
636mod timing_pattern_tests {
637 use crate::canvas::Canvas;
638 use crate::types::{EcLevel, Version};
639
640 #[test]
641 fn test_draw_timing_patterns_qr() {
642 let mut c = Canvas::new(Version::Normal(1), EcLevel::L);
643 c.draw_timing_patterns();
644 assert_eq!(
645 &*c.to_debug_str(),
646 "\n\
647 ?????????????????????\n\
648 ?????????????????????\n\
649 ?????????????????????\n\
650 ?????????????????????\n\
651 ?????????????????????\n\
652 ?????????????????????\n\
653 ????????#.#.#????????\n\
654 ?????????????????????\n\
655 ??????#??????????????\n\
656 ??????.??????????????\n\
657 ??????#??????????????\n\
658 ??????.??????????????\n\
659 ??????#??????????????\n\
660 ?????????????????????\n\
661 ?????????????????????\n\
662 ?????????????????????\n\
663 ?????????????????????\n\
664 ?????????????????????\n\
665 ?????????????????????\n\
666 ?????????????????????\n\
667 ?????????????????????"
668 );
669 }
670
671 #[test]
672 fn test_draw_timing_patterns_micro_qr() {
673 let mut c = Canvas::new(Version::Micro(1), EcLevel::L);
674 c.draw_timing_patterns();
675 assert_eq!(
676 &*c.to_debug_str(),
677 "\n\
678 ????????#.#\n\
679 ???????????\n\
680 ???????????\n\
681 ???????????\n\
682 ???????????\n\
683 ???????????\n\
684 ???????????\n\
685 ???????????\n\
686 #??????????\n\
687 .??????????\n\
688 #??????????"
689 );
690 }
691}
692
693impl Canvas {
698 fn draw_number(&mut self, number: u32, bits: u32, on_color: Color, off_color: Color, coords: &[(i16, i16)]) {
705 let mut mask = 1 << (bits - 1);
706 for &(x, y) in coords {
707 let color = if (mask & number) == 0 { off_color } else { on_color };
708 self.put(x, y, color);
709 mask >>= 1;
710 }
711 }
712
713 fn draw_format_info_patterns_with_number(&mut self, format_info: u16) {
715 let format_info = u32::from(format_info);
716 match self.version {
717 Version::Micro(_) => {
718 self.draw_number(format_info, 15, Color::Dark, Color::Light, &FORMAT_INFO_COORDS_MICRO_QR);
719 }
720 Version::Normal(_) => {
721 self.draw_number(format_info, 15, Color::Dark, Color::Light, &FORMAT_INFO_COORDS_QR_MAIN);
722 self.draw_number(format_info, 15, Color::Dark, Color::Light, &FORMAT_INFO_COORDS_QR_SIDE);
723 self.put(8, -8, Color::Dark); }
725 }
726 }
727
728 fn draw_reserved_format_info_patterns(&mut self) {
730 self.draw_format_info_patterns_with_number(0);
731 }
732
733 fn draw_version_info_patterns(&mut self) {
735 match self.version {
736 Version::Micro(_) | Version::Normal(1..=6) => {}
737 Version::Normal(a) => {
738 let version_info = VERSION_INFOS[(a - 7).as_usize()];
739 self.draw_number(version_info, 18, Color::Dark, Color::Light, &VERSION_INFO_COORDS_BL);
740 self.draw_number(version_info, 18, Color::Dark, Color::Light, &VERSION_INFO_COORDS_TR);
741 }
742 }
743 }
744}
745
746#[cfg(test)]
747mod draw_version_info_tests {
748 use crate::canvas::Canvas;
749 use crate::types::{Color, EcLevel, Version};
750
751 #[test]
752 fn test_draw_number() {
753 let mut c = Canvas::new(Version::Micro(1), EcLevel::L);
754 c.draw_number(0b1010_1101, 8, Color::Dark, Color::Light, &[(0, 0), (0, -1), (-2, -2), (-2, 0)]);
755 assert_eq!(
756 &*c.to_debug_str(),
757 "\n\
758 #????????.?\n\
759 ???????????\n\
760 ???????????\n\
761 ???????????\n\
762 ???????????\n\
763 ???????????\n\
764 ???????????\n\
765 ???????????\n\
766 ???????????\n\
767 ?????????#?\n\
768 .??????????"
769 );
770 }
771
772 #[test]
773 fn test_draw_version_info_1() {
774 let mut c = Canvas::new(Version::Normal(1), EcLevel::L);
775 c.draw_version_info_patterns();
776 assert_eq!(
777 &*c.to_debug_str(),
778 "\n\
779 ?????????????????????\n\
780 ?????????????????????\n\
781 ?????????????????????\n\
782 ?????????????????????\n\
783 ?????????????????????\n\
784 ?????????????????????\n\
785 ?????????????????????\n\
786 ?????????????????????\n\
787 ?????????????????????\n\
788 ?????????????????????\n\
789 ?????????????????????\n\
790 ?????????????????????\n\
791 ?????????????????????\n\
792 ?????????????????????\n\
793 ?????????????????????\n\
794 ?????????????????????\n\
795 ?????????????????????\n\
796 ?????????????????????\n\
797 ?????????????????????\n\
798 ?????????????????????\n\
799 ?????????????????????"
800 );
801 }
802
803 #[test]
804 fn test_draw_version_info_7() {
805 let mut c = Canvas::new(Version::Normal(7), EcLevel::L);
806 c.draw_version_info_patterns();
807
808 assert_eq!(
809 &*c.to_debug_str(),
810 "\n\
811 ??????????????????????????????????..#????????\n\
812 ??????????????????????????????????.#.????????\n\
813 ??????????????????????????????????.#.????????\n\
814 ??????????????????????????????????.##????????\n\
815 ??????????????????????????????????###????????\n\
816 ??????????????????????????????????...????????\n\
817 ?????????????????????????????????????????????\n\
818 ?????????????????????????????????????????????\n\
819 ?????????????????????????????????????????????\n\
820 ?????????????????????????????????????????????\n\
821 ?????????????????????????????????????????????\n\
822 ?????????????????????????????????????????????\n\
823 ?????????????????????????????????????????????\n\
824 ?????????????????????????????????????????????\n\
825 ?????????????????????????????????????????????\n\
826 ?????????????????????????????????????????????\n\
827 ?????????????????????????????????????????????\n\
828 ?????????????????????????????????????????????\n\
829 ?????????????????????????????????????????????\n\
830 ?????????????????????????????????????????????\n\
831 ?????????????????????????????????????????????\n\
832 ?????????????????????????????????????????????\n\
833 ?????????????????????????????????????????????\n\
834 ?????????????????????????????????????????????\n\
835 ?????????????????????????????????????????????\n\
836 ?????????????????????????????????????????????\n\
837 ?????????????????????????????????????????????\n\
838 ?????????????????????????????????????????????\n\
839 ?????????????????????????????????????????????\n\
840 ?????????????????????????????????????????????\n\
841 ?????????????????????????????????????????????\n\
842 ?????????????????????????????????????????????\n\
843 ?????????????????????????????????????????????\n\
844 ?????????????????????????????????????????????\n\
845 ....#.???????????????????????????????????????\n\
846 .####.???????????????????????????????????????\n\
847 #..##.???????????????????????????????????????\n\
848 ?????????????????????????????????????????????\n\
849 ?????????????????????????????????????????????\n\
850 ?????????????????????????????????????????????\n\
851 ?????????????????????????????????????????????\n\
852 ?????????????????????????????????????????????\n\
853 ?????????????????????????????????????????????\n\
854 ?????????????????????????????????????????????\n\
855 ?????????????????????????????????????????????"
856 );
857 }
858
859 #[test]
860 fn test_draw_reserved_format_info_patterns_qr() {
861 let mut c = Canvas::new(Version::Normal(1), EcLevel::L);
862 c.draw_reserved_format_info_patterns();
863 assert_eq!(
864 &*c.to_debug_str(),
865 "\n\
866 ????????.????????????\n\
867 ????????.????????????\n\
868 ????????.????????????\n\
869 ????????.????????????\n\
870 ????????.????????????\n\
871 ????????.????????????\n\
872 ?????????????????????\n\
873 ????????.????????????\n\
874 ......?..????........\n\
875 ?????????????????????\n\
876 ?????????????????????\n\
877 ?????????????????????\n\
878 ?????????????????????\n\
879 ????????#????????????\n\
880 ????????.????????????\n\
881 ????????.????????????\n\
882 ????????.????????????\n\
883 ????????.????????????\n\
884 ????????.????????????\n\
885 ????????.????????????\n\
886 ????????.????????????"
887 );
888 }
889
890 #[test]
891 fn test_draw_reserved_format_info_patterns_micro_qr() {
892 let mut c = Canvas::new(Version::Micro(1), EcLevel::L);
893 c.draw_reserved_format_info_patterns();
894 assert_eq!(
895 &*c.to_debug_str(),
896 "\n\
897 ???????????\n\
898 ????????.??\n\
899 ????????.??\n\
900 ????????.??\n\
901 ????????.??\n\
902 ????????.??\n\
903 ????????.??\n\
904 ????????.??\n\
905 ?........??\n\
906 ???????????\n\
907 ???????????"
908 );
909 }
910}
911
912static VERSION_INFO_COORDS_BL: [(i16, i16); 18] = [
913 (5, -9),
914 (5, -10),
915 (5, -11),
916 (4, -9),
917 (4, -10),
918 (4, -11),
919 (3, -9),
920 (3, -10),
921 (3, -11),
922 (2, -9),
923 (2, -10),
924 (2, -11),
925 (1, -9),
926 (1, -10),
927 (1, -11),
928 (0, -9),
929 (0, -10),
930 (0, -11),
931];
932
933static VERSION_INFO_COORDS_TR: [(i16, i16); 18] = [
934 (-9, 5),
935 (-10, 5),
936 (-11, 5),
937 (-9, 4),
938 (-10, 4),
939 (-11, 4),
940 (-9, 3),
941 (-10, 3),
942 (-11, 3),
943 (-9, 2),
944 (-10, 2),
945 (-11, 2),
946 (-9, 1),
947 (-10, 1),
948 (-11, 1),
949 (-9, 0),
950 (-10, 0),
951 (-11, 0),
952];
953
954static FORMAT_INFO_COORDS_QR_MAIN: [(i16, i16); 15] = [
955 (0, 8),
956 (1, 8),
957 (2, 8),
958 (3, 8),
959 (4, 8),
960 (5, 8),
961 (7, 8),
962 (8, 8),
963 (8, 7),
964 (8, 5),
965 (8, 4),
966 (8, 3),
967 (8, 2),
968 (8, 1),
969 (8, 0),
970];
971
972static FORMAT_INFO_COORDS_QR_SIDE: [(i16, i16); 15] = [
973 (8, -1),
974 (8, -2),
975 (8, -3),
976 (8, -4),
977 (8, -5),
978 (8, -6),
979 (8, -7),
980 (-8, 8),
981 (-7, 8),
982 (-6, 8),
983 (-5, 8),
984 (-4, 8),
985 (-3, 8),
986 (-2, 8),
987 (-1, 8),
988];
989
990static FORMAT_INFO_COORDS_MICRO_QR: [(i16, i16); 15] = [
991 (1, 8),
992 (2, 8),
993 (3, 8),
994 (4, 8),
995 (5, 8),
996 (6, 8),
997 (7, 8),
998 (8, 8),
999 (8, 7),
1000 (8, 6),
1001 (8, 5),
1002 (8, 4),
1003 (8, 3),
1004 (8, 2),
1005 (8, 1),
1006];
1007
1008static VERSION_INFOS: [u32; 34] = [
1009 0x07c94, 0x085bc, 0x09a99, 0x0a4d3, 0x0bbf6, 0x0c762, 0x0d847, 0x0e60d, 0x0f928, 0x10b78, 0x1145d, 0x12a17,
1010 0x13532, 0x149a6, 0x15683, 0x168c9, 0x177ec, 0x18ec4, 0x191e1, 0x1afab, 0x1b08e, 0x1cc1a, 0x1d33f, 0x1ed75,
1011 0x1f250, 0x209d5, 0x216f0, 0x228ba, 0x2379f, 0x24b0b, 0x2542e, 0x26a64, 0x27541, 0x28c69,
1012];
1013
1014impl Canvas {
1019 pub fn draw_all_functional_patterns(&mut self) {
1026 self.draw_finder_patterns();
1027 self.draw_alignment_patterns();
1028 self.draw_reserved_format_info_patterns();
1029 self.draw_timing_patterns();
1030 self.draw_version_info_patterns();
1031 }
1032}
1033
1034pub fn is_functional(version: Version, width: i16, x: i16, y: i16) -> bool {
1037 debug_assert!(width == version.width());
1038
1039 let x = if x < 0 { x + width } else { x };
1040 let y = if y < 0 { y + width } else { y };
1041
1042 match version {
1043 Version::Micro(_) => x == 0 || y == 0 || (x < 9 && y < 9),
1044 Version::Normal(a) => {
1045 let non_alignment_test = x == 6 || y == 6 || (x < 9 && y < 9) || (x < 9 && y >= width - 8) || (x >= width - 8 && y < 9); match a {
1050 _ if non_alignment_test => true,
1051 1 => false,
1052 2..=40 => {
1053 let positions = alignment_pattern_positions(a);
1054 let last = positions.len() - 1;
1055 for (i, align_x) in positions.iter().enumerate() {
1056 for (j, align_y) in positions.iter().enumerate() {
1057 if i == 0 && (j == 0 || j == last) || (i == last && j == 0) {
1058 continue;
1059 }
1060 if (*align_x - x).abs() <= 2 && (*align_y - y).abs() <= 2 {
1061 return true;
1062 }
1063 }
1064 }
1065 false
1066 }
1067 _ => false,
1068 }
1069 }
1070 }
1071}
1072
1073#[cfg(test)]
1074mod all_functional_patterns_tests {
1075 use crate::canvas::{Canvas, is_functional};
1076 use crate::types::{EcLevel, Version};
1077
1078 #[test]
1079 fn test_all_functional_patterns_qr() {
1080 let mut c = Canvas::new(Version::Normal(2), EcLevel::L);
1081 c.draw_all_functional_patterns();
1082 assert_eq!(
1083 &*c.to_debug_str(),
1084 "\n\
1085 #######..????????.#######\n\
1086 #.....#..????????.#.....#\n\
1087 #.###.#..????????.#.###.#\n\
1088 #.###.#..????????.#.###.#\n\
1089 #.###.#..????????.#.###.#\n\
1090 #.....#..????????.#.....#\n\
1091 #######.#.#.#.#.#.#######\n\
1092 .........????????........\n\
1093 ......#..????????........\n\
1094 ??????.??????????????????\n\
1095 ??????#??????????????????\n\
1096 ??????.??????????????????\n\
1097 ??????#??????????????????\n\
1098 ??????.??????????????????\n\
1099 ??????#??????????????????\n\
1100 ??????.??????????????????\n\
1101 ??????#?????????#####????\n\
1102 ........#???????#...#????\n\
1103 #######..???????#.#.#????\n\
1104 #.....#..???????#...#????\n\
1105 #.###.#..???????#####????\n\
1106 #.###.#..????????????????\n\
1107 #.###.#..????????????????\n\
1108 #.....#..????????????????\n\
1109 #######..????????????????"
1110 );
1111 }
1112
1113 #[test]
1114 fn test_all_functional_patterns_micro_qr() {
1115 let mut c = Canvas::new(Version::Micro(1), EcLevel::L);
1116 c.draw_all_functional_patterns();
1117 assert_eq!(
1118 &*c.to_debug_str(),
1119 "\n\
1120 #######.#.#\n\
1121 #.....#..??\n\
1122 #.###.#..??\n\
1123 #.###.#..??\n\
1124 #.###.#..??\n\
1125 #.....#..??\n\
1126 #######..??\n\
1127 .........??\n\
1128 #........??\n\
1129 .??????????\n\
1130 #??????????"
1131 );
1132 }
1133
1134 #[test]
1135 fn test_is_functional_qr_1() {
1136 let version = Version::Normal(1);
1137 assert!(is_functional(version, version.width(), 0, 0));
1138 assert!(is_functional(version, version.width(), 10, 6));
1139 assert!(!is_functional(version, version.width(), 10, 5));
1140 assert!(!is_functional(version, version.width(), 14, 14));
1141 assert!(is_functional(version, version.width(), 6, 11));
1142 assert!(!is_functional(version, version.width(), 4, 11));
1143 assert!(is_functional(version, version.width(), 4, 13));
1144 assert!(is_functional(version, version.width(), 17, 7));
1145 assert!(!is_functional(version, version.width(), 17, 17));
1146 }
1147
1148 #[test]
1149 fn test_is_functional_qr_3() {
1150 let version = Version::Normal(3);
1151 assert!(is_functional(version, version.width(), 0, 0));
1152 assert!(!is_functional(version, version.width(), 25, 24));
1153 assert!(is_functional(version, version.width(), 24, 24));
1154 assert!(!is_functional(version, version.width(), 9, 25));
1155 assert!(!is_functional(version, version.width(), 20, 0));
1156 assert!(is_functional(version, version.width(), 21, 0));
1157 }
1158
1159 #[test]
1160 fn test_is_functional_qr_7() {
1161 let version = Version::Normal(7);
1162 assert!(is_functional(version, version.width(), 21, 4));
1163 assert!(is_functional(version, version.width(), 7, 21));
1164 assert!(is_functional(version, version.width(), 22, 22));
1165 assert!(is_functional(version, version.width(), 8, 8));
1166 assert!(!is_functional(version, version.width(), 19, 5));
1167 assert!(!is_functional(version, version.width(), 36, 3));
1168 assert!(!is_functional(version, version.width(), 4, 36));
1169 assert!(is_functional(version, version.width(), 38, 38));
1170 }
1171
1172 #[test]
1173 fn test_is_functional_micro() {
1174 let version = Version::Micro(1);
1175 assert!(is_functional(version, version.width(), 8, 0));
1176 assert!(is_functional(version, version.width(), 10, 0));
1177 assert!(!is_functional(version, version.width(), 10, 1));
1178 assert!(is_functional(version, version.width(), 8, 8));
1179 assert!(is_functional(version, version.width(), 0, 9));
1180 assert!(!is_functional(version, version.width(), 1, 9));
1181 }
1182}
1183
1184struct DataModuleIter {
1189 x: i16,
1190 y: i16,
1191 width: i16,
1192 timing_pattern_column: i16,
1193}
1194
1195impl DataModuleIter {
1196 fn new(version: Version) -> Self {
1197 let width = version.width();
1198 Self {
1199 x: width - 1,
1200 y: width - 1,
1201 width,
1202 timing_pattern_column: match version {
1203 Version::Micro(_) => 0,
1204 Version::Normal(_) => 6,
1205 },
1206 }
1207 }
1208}
1209
1210impl Iterator for DataModuleIter {
1211 type Item = (i16, i16);
1212
1213 fn next(&mut self) -> Option<(i16, i16)> {
1214 let adjusted_ref_col = if self.x <= self.timing_pattern_column { self.x + 1 } else { self.x };
1215 if adjusted_ref_col <= 0 {
1216 return None;
1217 }
1218
1219 let res = (self.x, self.y);
1220 let column_type = (self.width - adjusted_ref_col) % 4;
1221
1222 match column_type {
1223 2 if self.y > 0 => {
1224 self.y -= 1;
1225 self.x += 1;
1226 }
1227 0 if self.y < self.width - 1 => {
1228 self.y += 1;
1229 self.x += 1;
1230 }
1231 0 | 2 if self.x == self.timing_pattern_column + 1 => {
1232 self.x -= 2;
1233 }
1234 _ => {
1235 self.x -= 1;
1236 }
1237 }
1238
1239 Some(res)
1240 }
1241}
1242
1243#[cfg(test)]
1244#[rustfmt::skip] mod data_iter_tests {
1246 use crate::canvas::DataModuleIter;
1247 use crate::types::Version;
1248
1249 #[test]
1250 fn test_qr() {
1251 let res = DataModuleIter::new(Version::Normal(1)).collect::<Vec<(i16, i16)>>();
1252 assert_eq!(res, vec![
1253 (20, 20), (19, 20), (20, 19), (19, 19), (20, 18), (19, 18),
1254 (20, 17), (19, 17), (20, 16), (19, 16), (20, 15), (19, 15),
1255 (20, 14), (19, 14), (20, 13), (19, 13), (20, 12), (19, 12),
1256 (20, 11), (19, 11), (20, 10), (19, 10), (20, 9), (19, 9),
1257 (20, 8), (19, 8), (20, 7), (19, 7), (20, 6), (19, 6),
1258 (20, 5), (19, 5), (20, 4), (19, 4), (20, 3), (19, 3),
1259 (20, 2), (19, 2), (20, 1), (19, 1), (20, 0), (19, 0),
1260 (18, 0), (17, 0), (18, 1), (17, 1), (18, 2), (17, 2),
1261 (18, 3), (17, 3), (18, 4), (17, 4), (18, 5), (17, 5),
1262 (18, 6), (17, 6), (18, 7), (17, 7), (18, 8), (17, 8),
1263 (18, 9), (17, 9), (18, 10), (17, 10), (18, 11), (17, 11),
1264 (18, 12), (17, 12), (18, 13), (17, 13), (18, 14), (17, 14),
1265 (18, 15), (17, 15), (18, 16), (17, 16), (18, 17), (17, 17),
1266 (18, 18), (17, 18), (18, 19), (17, 19), (18, 20), (17, 20),
1267 (16, 20), (15, 20), (16, 19), (15, 19), (16, 18), (15, 18),
1268 (16, 17), (15, 17), (16, 16), (15, 16), (16, 15), (15, 15),
1269 (16, 14), (15, 14), (16, 13), (15, 13), (16, 12), (15, 12),
1270 (16, 11), (15, 11), (16, 10), (15, 10), (16, 9), (15, 9),
1271 (16, 8), (15, 8), (16, 7), (15, 7), (16, 6), (15, 6),
1272 (16, 5), (15, 5), (16, 4), (15, 4), (16, 3), (15, 3),
1273 (16, 2), (15, 2), (16, 1), (15, 1), (16, 0), (15, 0),
1274 (14, 0), (13, 0), (14, 1), (13, 1), (14, 2), (13, 2),
1275 (14, 3), (13, 3), (14, 4), (13, 4), (14, 5), (13, 5),
1276 (14, 6), (13, 6), (14, 7), (13, 7), (14, 8), (13, 8),
1277 (14, 9), (13, 9), (14, 10), (13, 10), (14, 11), (13, 11),
1278 (14, 12), (13, 12), (14, 13), (13, 13), (14, 14), (13, 14),
1279 (14, 15), (13, 15), (14, 16), (13, 16), (14, 17), (13, 17),
1280 (14, 18), (13, 18), (14, 19), (13, 19), (14, 20), (13, 20),
1281 (12, 20), (11, 20), (12, 19), (11, 19), (12, 18), (11, 18),
1282 (12, 17), (11, 17), (12, 16), (11, 16), (12, 15), (11, 15),
1283 (12, 14), (11, 14), (12, 13), (11, 13), (12, 12), (11, 12),
1284 (12, 11), (11, 11), (12, 10), (11, 10), (12, 9), (11, 9),
1285 (12, 8), (11, 8), (12, 7), (11, 7), (12, 6), (11, 6),
1286 (12, 5), (11, 5), (12, 4), (11, 4), (12, 3), (11, 3),
1287 (12, 2), (11, 2), (12, 1), (11, 1), (12, 0), (11, 0),
1288 (10, 0), (9, 0), (10, 1), (9, 1), (10, 2), (9, 2),
1289 (10, 3), (9, 3), (10, 4), (9, 4), (10, 5), (9, 5),
1290 (10, 6), (9, 6), (10, 7), (9, 7), (10, 8), (9, 8),
1291 (10, 9), (9, 9), (10, 10), (9, 10), (10, 11), (9, 11),
1292 (10, 12), (9, 12), (10, 13), (9, 13), (10, 14), (9, 14),
1293 (10, 15), (9, 15), (10, 16), (9, 16), (10, 17), (9, 17),
1294 (10, 18), (9, 18), (10, 19), (9, 19), (10, 20), (9, 20),
1295 (8, 20), (7, 20), (8, 19), (7, 19), (8, 18), (7, 18),
1296 (8, 17), (7, 17), (8, 16), (7, 16), (8, 15), (7, 15),
1297 (8, 14), (7, 14), (8, 13), (7, 13), (8, 12), (7, 12),
1298 (8, 11), (7, 11), (8, 10), (7, 10), (8, 9), (7, 9),
1299 (8, 8), (7, 8), (8, 7), (7, 7), (8, 6), (7, 6),
1300 (8, 5), (7, 5), (8, 4), (7, 4), (8, 3), (7, 3),
1301 (8, 2), (7, 2), (8, 1), (7, 1), (8, 0), (7, 0),
1302 (5, 0), (4, 0), (5, 1), (4, 1), (5, 2), (4, 2),
1303 (5, 3), (4, 3), (5, 4), (4, 4), (5, 5), (4, 5),
1304 (5, 6), (4, 6), (5, 7), (4, 7), (5, 8), (4, 8),
1305 (5, 9), (4, 9), (5, 10), (4, 10), (5, 11), (4, 11),
1306 (5, 12), (4, 12), (5, 13), (4, 13), (5, 14), (4, 14),
1307 (5, 15), (4, 15), (5, 16), (4, 16), (5, 17), (4, 17),
1308 (5, 18), (4, 18), (5, 19), (4, 19), (5, 20), (4, 20),
1309 (3, 20), (2, 20), (3, 19), (2, 19), (3, 18), (2, 18),
1310 (3, 17), (2, 17), (3, 16), (2, 16), (3, 15), (2, 15),
1311 (3, 14), (2, 14), (3, 13), (2, 13), (3, 12), (2, 12),
1312 (3, 11), (2, 11), (3, 10), (2, 10), (3, 9), (2, 9),
1313 (3, 8), (2, 8), (3, 7), (2, 7), (3, 6), (2, 6),
1314 (3, 5), (2, 5), (3, 4), (2, 4), (3, 3), (2, 3),
1315 (3, 2), (2, 2), (3, 1), (2, 1), (3, 0), (2, 0),
1316 (1, 0), (0, 0), (1, 1), (0, 1), (1, 2), (0, 2),
1317 (1, 3), (0, 3), (1, 4), (0, 4), (1, 5), (0, 5),
1318 (1, 6), (0, 6), (1, 7), (0, 7), (1, 8), (0, 8),
1319 (1, 9), (0, 9), (1, 10), (0, 10), (1, 11), (0, 11),
1320 (1, 12), (0, 12), (1, 13), (0, 13), (1, 14), (0, 14),
1321 (1, 15), (0, 15), (1, 16), (0, 16), (1, 17), (0, 17),
1322 (1, 18), (0, 18), (1, 19), (0, 19), (1, 20), (0, 20),
1323 ]);
1324 }
1325
1326 #[test]
1327 fn test_micro_qr() {
1328 let res = DataModuleIter::new(Version::Micro(1)).collect::<Vec<(i16, i16)>>();
1329 assert_eq!(res, vec![
1330 (10, 10), (9, 10), (10, 9), (9, 9), (10, 8), (9, 8),
1331 (10, 7), (9, 7), (10, 6), (9, 6), (10, 5), (9, 5),
1332 (10, 4), (9, 4), (10, 3), (9, 3), (10, 2), (9, 2),
1333 (10, 1), (9, 1), (10, 0), (9, 0),
1334 (8, 0), (7, 0), (8, 1), (7, 1), (8, 2), (7, 2),
1335 (8, 3), (7, 3), (8, 4), (7, 4), (8, 5), (7, 5),
1336 (8, 6), (7, 6), (8, 7), (7, 7), (8, 8), (7, 8),
1337 (8, 9), (7, 9), (8, 10), (7, 10),
1338 (6, 10), (5, 10), (6, 9), (5, 9), (6, 8), (5, 8),
1339 (6, 7), (5, 7), (6, 6), (5, 6), (6, 5), (5, 5),
1340 (6, 4), (5, 4), (6, 3), (5, 3), (6, 2), (5, 2),
1341 (6, 1), (5, 1), (6, 0), (5, 0),
1342 (4, 0), (3, 0), (4, 1), (3, 1), (4, 2), (3, 2),
1343 (4, 3), (3, 3), (4, 4), (3, 4), (4, 5), (3, 5),
1344 (4, 6), (3, 6), (4, 7), (3, 7), (4, 8), (3, 8),
1345 (4, 9), (3, 9), (4, 10), (3, 10),
1346 (2, 10), (1, 10), (2, 9), (1, 9), (2, 8), (1, 8),
1347 (2, 7), (1, 7), (2, 6), (1, 6), (2, 5), (1, 5),
1348 (2, 4), (1, 4), (2, 3), (1, 3), (2, 2), (1, 2),
1349 (2, 1), (1, 1), (2, 0), (1, 0),
1350 ]);
1351 }
1352
1353 #[test]
1354 fn test_micro_qr_2() {
1355 let res = DataModuleIter::new(Version::Micro(2)).collect::<Vec<(i16, i16)>>();
1356 assert_eq!(res, vec![
1357 (12, 12), (11, 12), (12, 11), (11, 11), (12, 10), (11, 10),
1358 (12, 9), (11, 9), (12, 8), (11, 8), (12, 7), (11, 7),
1359 (12, 6), (11, 6), (12, 5), (11, 5), (12, 4), (11, 4),
1360 (12, 3), (11, 3), (12, 2), (11, 2), (12, 1), (11, 1),
1361 (12, 0), (11, 0),
1362 (10, 0), (9, 0), (10, 1), (9, 1), (10, 2), (9, 2),
1363 (10, 3), (9, 3), (10, 4), (9, 4), (10, 5), (9, 5),
1364 (10, 6), (9, 6), (10, 7), (9, 7), (10, 8), (9, 8),
1365 (10, 9), (9, 9), (10, 10), (9, 10), (10, 11), (9, 11),
1366 (10, 12), (9, 12),
1367 (8, 12), (7, 12), (8, 11), (7, 11), (8, 10), (7, 10),
1368 (8, 9), (7, 9), (8, 8), (7, 8), (8, 7), (7, 7),
1369 (8, 6), (7, 6), (8, 5), (7, 5), (8, 4), (7, 4),
1370 (8, 3), (7, 3), (8, 2), (7, 2), (8, 1), (7, 1),
1371 (8, 0), (7, 0),
1372 (6, 0), (5, 0), (6, 1), (5, 1), (6, 2), (5, 2),
1373 (6, 3), (5, 3), (6, 4), (5, 4), (6, 5), (5, 5),
1374 (6, 6), (5, 6), (6, 7), (5, 7), (6, 8), (5, 8),
1375 (6, 9), (5, 9), (6, 10), (5, 10), (6, 11), (5, 11),
1376 (6, 12), (5, 12),
1377 (4, 12), (3, 12), (4, 11), (3, 11), (4, 10), (3, 10),
1378 (4, 9), (3, 9), (4, 8), (3, 8), (4, 7), (3, 7),
1379 (4, 6), (3, 6), (4, 5), (3, 5), (4, 4), (3, 4),
1380 (4, 3), (3, 3), (4, 2), (3, 2), (4, 1), (3, 1),
1381 (4, 0), (3, 0),
1382 (2, 0), (1, 0), (2, 1), (1, 1), (2, 2), (1, 2),
1383 (2, 3), (1, 3), (2, 4), (1, 4), (2, 5), (1, 5),
1384 (2, 6), (1, 6), (2, 7), (1, 7), (2, 8), (1, 8),
1385 (2, 9), (1, 9), (2, 10), (1, 10), (2, 11), (1, 11),
1386 (2, 12), (1, 12),
1387 ]);
1388 }
1389}
1390
1391impl Canvas {
1396 fn draw_codewords<I>(&mut self, codewords: &[u8], is_half_codeword_at_end: bool, coords: &mut I)
1397 where
1398 I: Iterator<Item = (i16, i16)>,
1399 {
1400 let length = codewords.len();
1401 let last_word = if is_half_codeword_at_end { length - 1 } else { length };
1402 for (i, b) in codewords.iter().enumerate() {
1403 let bits_end = if i == last_word { 4 } else { 0 };
1404 'outside: for j in (bits_end..=7).rev() {
1405 let color = if (*b & (1 << j)) == 0 { Color::Light } else { Color::Dark };
1406 for (x, y) in coords.by_ref() {
1407 let r = self.get_mut(x, y);
1408 if *r == Module::Empty {
1409 *r = Module::Unmasked(color);
1410 continue 'outside;
1411 }
1412 }
1413 return;
1414 }
1415 }
1416 }
1417
1418 pub fn draw_data(&mut self, data: &[u8], ec: &[u8]) {
1420 let is_half_codeword_at_end = matches!(
1421 (self.version, self.ec_level),
1422 (Version::Micro(1 | 3), EcLevel::L) | (Version::Micro(3), EcLevel::M)
1423 );
1424
1425 let mut coords = DataModuleIter::new(self.version);
1426 self.draw_codewords(data, is_half_codeword_at_end, &mut coords);
1427 self.draw_codewords(ec, false, &mut coords);
1428 }
1429}
1430
1431#[cfg(test)]
1432mod draw_codewords_test {
1433 use crate::canvas::Canvas;
1434 use crate::types::{EcLevel, Version};
1435
1436 #[test]
1437 fn test_micro_qr_1() {
1438 let mut c = Canvas::new(Version::Micro(1), EcLevel::L);
1439 c.draw_all_functional_patterns();
1440 c.draw_data(b"\x6e\x5d\xe2", b"\x2b\x63");
1441 assert_eq!(
1442 &*c.to_debug_str(),
1443 "\n\
1444 #######.#.#\n\
1445 #.....#..-*\n\
1446 #.###.#..**\n\
1447 #.###.#..*-\n\
1448 #.###.#..**\n\
1449 #.....#..*-\n\
1450 #######..*-\n\
1451 .........-*\n\
1452 #........**\n\
1453 .***-**---*\n\
1454 #---*-*-**-"
1455 );
1456 }
1457
1458 #[test]
1459 fn test_qr_2() {
1460 let mut c = Canvas::new(Version::Normal(2), EcLevel::L);
1461 c.draw_all_functional_patterns();
1462 c.draw_data(
1463 b"\x92I$\x92I$\x92I$\x92I$\x92I$\x92I$\x92I$\x92I$\
1464 \x92I$\x92I$\x92I$\x92I$\x92I$\x92I$\x92I$",
1465 b"",
1466 );
1467 assert_eq!(
1468 &*c.to_debug_str(),
1469 "\n\
1470 #######..--*---*-.#######\n\
1471 #.....#..-*-*-*-*.#.....#\n\
1472 #.###.#..*---*---.#.###.#\n\
1473 #.###.#..--*---*-.#.###.#\n\
1474 #.###.#..-*-*-*-*.#.###.#\n\
1475 #.....#..*---*---.#.....#\n\
1476 #######.#.#.#.#.#.#######\n\
1477 .........--*---*-........\n\
1478 ......#..-*-*-*-*........\n\
1479 --*-*-.-**---*---*--**--*\n\
1480 -*-*--#----*---*---------\n\
1481 *----*.*--*-*-*-*-**--**-\n\
1482 --*-*-#-**---*---*--**--*\n\
1483 -*-*--.----*---*---------\n\
1484 *----*#*--*-*-*-*-**--**-\n\
1485 --*-*-.-**---*---*--**--*\n\
1486 -*-*--#----*---*#####----\n\
1487 ........#-*-*-*-#...#-**-\n\
1488 #######..*---*--#.#.#*--*\n\
1489 #.....#..--*---*#...#----\n\
1490 #.###.#..-*-*-*-#####-**-\n\
1491 #.###.#..*---*--*----*--*\n\
1492 #.###.#..--*------**-----\n\
1493 #.....#..-*-*-**-*--*-**-\n\
1494 #######..*---*--*----*--*"
1495 );
1496 }
1497}
1498#[derive(Debug, Copy, Clone)]
1505pub enum MaskPattern {
1506 Checkerboard = 0b000,
1508
1509 HorizontalLines = 0b001,
1511
1512 VerticalLines = 0b010,
1514
1515 DiagonalLines = 0b011,
1517
1518 LargeCheckerboard = 0b100,
1520
1521 Fields = 0b101,
1523
1524 Diamonds = 0b110,
1526
1527 Meadow = 0b111,
1529}
1530
1531mod mask_functions {
1532 pub fn checkerboard(x: i16, y: i16) -> bool {
1533 (x + y) % 2 == 0
1534 }
1535
1536 pub fn horizontal_lines(_: i16, y: i16) -> bool {
1537 y % 2 == 0
1538 }
1539
1540 pub fn vertical_lines(x: i16, _: i16) -> bool {
1541 x % 3 == 0
1542 }
1543
1544 pub fn diagonal_lines(x: i16, y: i16) -> bool {
1545 (x + y) % 3 == 0
1546 }
1547
1548 pub fn large_checkerboard(x: i16, y: i16) -> bool {
1549 ((y / 2) + (x / 3)) % 2 == 0
1550 }
1551
1552 pub fn fields(x: i16, y: i16) -> bool {
1553 (x * y) % 2 + (x * y) % 3 == 0
1554 }
1555
1556 pub fn diamonds(x: i16, y: i16) -> bool {
1557 ((x * y) % 2 + (x * y) % 3) % 2 == 0
1558 }
1559
1560 pub fn meadow(x: i16, y: i16) -> bool {
1561 ((x + y) % 2 + (x * y) % 3) % 2 == 0
1562 }
1563}
1564
1565fn get_mask_function(pattern: MaskPattern) -> fn(i16, i16) -> bool {
1566 match pattern {
1567 MaskPattern::Checkerboard => mask_functions::checkerboard,
1568 MaskPattern::HorizontalLines => mask_functions::horizontal_lines,
1569 MaskPattern::VerticalLines => mask_functions::vertical_lines,
1570 MaskPattern::DiagonalLines => mask_functions::diagonal_lines,
1571 MaskPattern::LargeCheckerboard => mask_functions::large_checkerboard,
1572 MaskPattern::Fields => mask_functions::fields,
1573 MaskPattern::Diamonds => mask_functions::diamonds,
1574 MaskPattern::Meadow => mask_functions::meadow,
1575 }
1576}
1577
1578impl Canvas {
1579 pub fn apply_mask(&mut self, pattern: MaskPattern) {
1582 let mask_fn = get_mask_function(pattern);
1583 for x in 0..self.width {
1584 for y in 0..self.width {
1585 let module = self.get_mut(x, y);
1586 *module = module.mask(mask_fn(x, y));
1587 }
1588 }
1589
1590 self.draw_format_info_patterns(pattern);
1591 }
1592
1593 fn draw_format_info_patterns(&mut self, pattern: MaskPattern) {
1599 let format_number = match self.version {
1600 Version::Normal(_) => {
1601 let simple_format_number = ((self.ec_level as usize) ^ 1) << 3 | (pattern as usize);
1602 FORMAT_INFOS_QR[simple_format_number]
1603 }
1604 Version::Micro(a) => {
1605 let micro_pattern_number = match pattern {
1606 MaskPattern::HorizontalLines => 0b00,
1607 MaskPattern::LargeCheckerboard => 0b01,
1608 MaskPattern::Diamonds => 0b10,
1609 MaskPattern::Meadow => 0b11,
1610 _ => panic!("Unsupported mask pattern in Micro QR code"),
1611 };
1612 let symbol_number = match (a, self.ec_level) {
1613 (1, EcLevel::L) => 0b000,
1614 (2, EcLevel::L) => 0b001,
1615 (2, EcLevel::M) => 0b010,
1616 (3, EcLevel::L) => 0b011,
1617 (3, EcLevel::M) => 0b100,
1618 (4, EcLevel::L) => 0b101,
1619 (4, EcLevel::M) => 0b110,
1620 (4, EcLevel::Q) => 0b111,
1621 _ => panic!("Unsupported version/ec_level combination in Micro QR code"),
1622 };
1623 let simple_format_number = symbol_number << 2 | micro_pattern_number;
1624 FORMAT_INFOS_MICRO_QR[simple_format_number]
1625 }
1626 };
1627 self.draw_format_info_patterns_with_number(format_number);
1628 }
1629}
1630
1631#[cfg(test)]
1632mod mask_tests {
1633 use crate::canvas::{Canvas, FORMAT_INFOS_MICRO_QR, FORMAT_INFOS_QR, MaskPattern};
1634 use crate::types::{EcLevel, Version};
1635
1636 #[test]
1637 fn test_apply_mask_qr() {
1638 let mut c = Canvas::new(Version::Normal(1), EcLevel::L);
1639 c.draw_all_functional_patterns();
1640 c.apply_mask(MaskPattern::Checkerboard);
1641
1642 assert_eq!(
1643 &*c.to_debug_str(),
1644 "\n\
1645 #######...#.#.#######\n\
1646 #.....#..#.#..#.....#\n\
1647 #.###.#.#.#.#.#.###.#\n\
1648 #.###.#..#.#..#.###.#\n\
1649 #.###.#...#.#.#.###.#\n\
1650 #.....#..#.#..#.....#\n\
1651 #######.#.#.#.#######\n\
1652 ........##.#.........\n\
1653 ###.#####.#.###...#..\n\
1654 .#.#.#.#.#.#.#.#.#.#.\n\
1655 #.#.#.#.#.#.#.#.#.#.#\n\
1656 .#.#.#.#.#.#.#.#.#.#.\n\
1657 #.#.#.#.#.#.#.#.#.#.#\n\
1658 ........##.#.#.#.#.#.\n\
1659 #######.#.#.#.#.#.#.#\n\
1660 #.....#.##.#.#.#.#.#.\n\
1661 #.###.#.#.#.#.#.#.#.#\n\
1662 #.###.#..#.#.#.#.#.#.\n\
1663 #.###.#.#.#.#.#.#.#.#\n\
1664 #.....#.##.#.#.#.#.#.\n\
1665 #######.#.#.#.#.#.#.#"
1666 );
1667 }
1668
1669 #[test]
1670 fn test_draw_format_info_patterns_qr() {
1671 let mut c = Canvas::new(Version::Normal(1), EcLevel::L);
1672 c.draw_format_info_patterns(MaskPattern::LargeCheckerboard);
1673 assert_eq!(
1674 &*c.to_debug_str(),
1675 "\n\
1676 ????????#????????????\n\
1677 ????????#????????????\n\
1678 ????????#????????????\n\
1679 ????????#????????????\n\
1680 ????????.????????????\n\
1681 ????????#????????????\n\
1682 ?????????????????????\n\
1683 ????????.????????????\n\
1684 ##..##?..????..#.####\n\
1685 ?????????????????????\n\
1686 ?????????????????????\n\
1687 ?????????????????????\n\
1688 ?????????????????????\n\
1689 ????????#????????????\n\
1690 ????????.????????????\n\
1691 ????????#????????????\n\
1692 ????????#????????????\n\
1693 ????????.????????????\n\
1694 ????????.????????????\n\
1695 ????????#????????????\n\
1696 ????????#????????????"
1697 );
1698 }
1699
1700 #[test]
1701 fn test_draw_format_info_patterns_micro_qr() {
1702 let mut c = Canvas::new(Version::Micro(2), EcLevel::L);
1703 c.draw_format_info_patterns(MaskPattern::LargeCheckerboard);
1704 assert_eq!(
1705 &*c.to_debug_str(),
1706 "\n\
1707 ?????????????\n\
1708 ????????#????\n\
1709 ????????.????\n\
1710 ????????.????\n\
1711 ????????#????\n\
1712 ????????#????\n\
1713 ????????.????\n\
1714 ????????.????\n\
1715 ?#.#....#????\n\
1716 ?????????????\n\
1717 ?????????????\n\
1718 ?????????????\n\
1719 ?????????????"
1720 );
1721 }
1722
1723 #[test]
1724 fn generated_format_info_tables_match_known_values() {
1725 assert_eq!(FORMAT_INFOS_QR[0], 0x5412);
1726 assert_eq!(FORMAT_INFOS_QR[31], 0x2bed);
1727 assert_eq!(FORMAT_INFOS_MICRO_QR[0], 0x4445);
1728 assert_eq!(FORMAT_INFOS_MICRO_QR[31], 0x3bba);
1729 }
1730}
1731
1732const FORMAT_INFOS_QR: [u16; 32] = generate_format_infos(0x5412);
1733const FORMAT_INFOS_MICRO_QR: [u16; 32] = generate_format_infos(0x4445);
1734const FORMAT_INFO_GENERATOR: u16 = 0x537;
1735
1736const fn generate_format_infos(mask: u16) -> [u16; 32] {
1737 let mut table = [0; 32];
1738 let mut data = 0;
1739 while data < table.len() {
1740 table[data] = format_info(data as u16, mask);
1741 data += 1;
1742 }
1743 table
1744}
1745
1746const fn format_info(data: u16, mask: u16) -> u16 {
1747 let mut remainder = data << 10;
1748 let mut bit = 14;
1749 while bit >= 10 {
1750 if remainder & (1 << bit) != 0 {
1751 remainder ^= FORMAT_INFO_GENERATOR << (bit - 10);
1752 }
1753 if bit == 10 {
1754 break;
1755 }
1756 bit -= 1;
1757 }
1758 ((data << 10) | remainder) ^ mask
1759}
1760
1761impl Canvas {
1766 #[cfg(test)]
1772 fn compute_adjacent_penalty_score(&self, is_horizontal: bool) -> u16 {
1773 compute_adjacent_penalty_score(self.width.as_usize(), &module_bytes(&self.modules), is_horizontal)
1774 }
1775
1776 #[cfg(test)]
1782 fn compute_block_penalty_score(&self) -> u16 {
1783 compute_block_penalty_score(self.width.as_usize(), &module_bytes(&self.modules))
1784 }
1785
1786 #[cfg(test)]
1792 fn compute_finder_penalty_score(&self, is_horizontal: bool) -> u16 {
1793 compute_finder_penalty_score(self.width.as_usize(), &module_bytes(&self.modules), is_horizontal)
1794 }
1795
1796 #[cfg(test)]
1805 fn compute_balance_penalty_score(&self) -> u16 {
1806 compute_balance_penalty_score(&module_bytes(&self.modules))
1807 }
1808
1809 #[cfg(test)]
1817 fn compute_light_side_penalty_score(&self) -> u16 {
1818 compute_light_side_penalty_score(self.width.as_usize(), &module_bytes(&self.modules))
1819 }
1820
1821 #[cfg(test)]
1824 fn compute_total_penalty_scores(&self) -> u16 {
1825 compute_total_penalty_score_scalar(self.version, self.width, &self.modules)
1826 }
1827
1828 fn compute_total_penalty_scores_with_scratch(&self, scratch: &mut Vec<u8>) -> u16 {
1829 debug_assert_eq!((self.width * self.width).as_usize(), self.modules.len());
1830 write_module_bytes(&self.modules, scratch);
1831 compute_total_penalty_score_from_bytes(self.version, self.width.as_usize(), scratch)
1832 }
1833
1834 #[cfg(feature = "bench-internals")]
1835 #[doc(hidden)]
1836 pub fn score_mask_for_bench(&self, scratch: &mut Vec<u8>) -> u16 {
1837 self.compute_total_penalty_scores_with_scratch(scratch)
1838 }
1839
1840 #[cfg(feature = "bench-internals")]
1841 #[doc(hidden)]
1842 pub fn score_mask_scalar_for_bench(&self, scratch: &mut Vec<u8>) -> u16 {
1843 debug_assert_eq!((self.width * self.width).as_usize(), self.modules.len());
1844 write_module_bytes(&self.modules, scratch);
1845 compute_total_penalty_score_from_bytes_scalar(self.version, self.width.as_usize(), scratch)
1846 }
1847}
1848
1849#[cfg(test)]
1850fn module_bytes(modules: &[Module]) -> Vec<u8> {
1851 modules.iter().map(|module| u8::from(module.is_dark())).collect()
1852}
1853
1854fn write_module_bytes(modules: &[Module], output: &mut Vec<u8>) {
1855 output.clear();
1856 output.extend(modules.iter().map(|module| u8::from(module.is_dark())));
1857}
1858
1859fn count_dark_modules(modules: &[u8]) -> usize {
1860 #[cfg(target_arch = "aarch64")]
1861 {
1862 unsafe { count_dark_modules_neon(modules) }
1865 }
1866
1867 #[cfg(target_arch = "x86_64")]
1868 {
1869 if avx2_available() {
1870 return unsafe { count_dark_modules_avx2(modules) };
1873 }
1874
1875 if sse2_available() {
1876 return unsafe { count_dark_modules_sse2(modules) };
1879 }
1880
1881 count_dark_modules_scalar(modules)
1882 }
1883
1884 #[cfg(not(any(target_arch = "aarch64", target_arch = "x86_64")))]
1885 {
1886 count_dark_modules_scalar(modules)
1887 }
1888}
1889
1890fn count_dark_modules_scalar(modules: &[u8]) -> usize {
1891 modules.iter().filter(|&&module| module != 0).count()
1892}
1893
1894fn compute_balance_penalty_score(modules: &[u8]) -> u16 {
1895 let dark_modules = count_dark_modules(modules);
1896 let total_modules = modules.len();
1897 let ratio = dark_modules * 200 / total_modules;
1898 ratio.abs_diff(100).as_u16()
1899}
1900
1901#[cfg(any(test, feature = "bench-internals"))]
1902fn compute_balance_penalty_score_scalar(modules: &[u8]) -> u16 {
1903 let dark_modules = count_dark_modules_scalar(modules);
1904 let total_modules = modules.len();
1905 let ratio = dark_modules * 200 / total_modules;
1906 ratio.abs_diff(100).as_u16()
1907}
1908
1909fn compute_light_side_penalty_score(width: usize, modules: &[u8]) -> u16 {
1910 let bottom_row = &modules[(width - 1) * width..][..width];
1911 let h = (1..width).filter(|&x| bottom_row[x] == 0).count();
1912 let v = (1..width).filter(|&y| modules[y * width + width - 1] == 0).count();
1913
1914 (h + v + 15 * max(h, v)).as_u16()
1915}
1916
1917fn compute_adjacent_penalty_score(width: usize, modules: &[u8], is_horizontal: bool) -> u16 {
1918 if is_horizontal {
1919 compute_horizontal_adjacent_penalty_score(width, modules)
1920 } else {
1921 compute_vertical_adjacent_penalty_score(width, modules)
1922 }
1923}
1924
1925fn compute_horizontal_adjacent_penalty_score(width: usize, modules: &[u8]) -> u16 {
1926 modules.chunks_exact(width).map(compute_line_adjacent_penalty_score).sum()
1927}
1928
1929fn compute_vertical_adjacent_penalty_score(width: usize, modules: &[u8]) -> u16 {
1930 let mut total_score = 0;
1931
1932 for x in 0..width {
1933 let mut last_color = 2;
1934 let mut consecutive_len = 1_u16;
1935
1936 for y in 0..width {
1937 let color = modules[y * width + x];
1938 if color == last_color {
1939 consecutive_len += 1;
1940 } else {
1941 last_color = color;
1942 if consecutive_len >= 5 {
1943 total_score += consecutive_len - 2;
1944 }
1945 consecutive_len = 1;
1946 }
1947 }
1948
1949 total_score += adjacent_run_score(consecutive_len);
1950 }
1951
1952 total_score
1953}
1954
1955fn compute_line_adjacent_penalty_score(line: &[u8]) -> u16 {
1956 let mut total_score = 0;
1957 let mut last_color = 2;
1958 let mut consecutive_len = 1_u16;
1959
1960 for &color in line {
1961 if color == last_color {
1962 consecutive_len += 1;
1963 } else {
1964 last_color = color;
1965 if consecutive_len >= 5 {
1966 total_score += consecutive_len - 2;
1967 }
1968 consecutive_len = 1;
1969 }
1970 }
1971
1972 total_score + adjacent_run_score(consecutive_len)
1973}
1974
1975fn adjacent_run_score(consecutive_len: u16) -> u16 {
1976 if consecutive_len >= 5 { consecutive_len - 2 } else { 0 }
1977}
1978
1979const FINDER_LIKE_PATTERN_BITS: u8 = 0b1011101;
1980const FINDER_LIKE_PATTERN_WIDTH: usize = 7;
1981const FINDER_LIKE_PATTERN_MASK: u8 = (1 << FINDER_LIKE_PATTERN_WIDTH) - 1;
1982
1983fn compute_finder_penalty_score(width: usize, modules: &[u8], is_horizontal: bool) -> u16 {
1984 let total_score = if is_horizontal {
1985 compute_horizontal_finder_penalty_score(width, modules)
1986 } else {
1987 compute_vertical_finder_penalty_score(width, modules)
1988 };
1989
1990 total_score - 360
1991}
1992
1993fn compute_horizontal_finder_penalty_score(width: usize, modules: &[u8]) -> u16 {
1994 modules.chunks_exact(width).map(compute_line_finder_penalty_score).sum()
1995}
1996
1997fn compute_vertical_finder_penalty_score(width: usize, modules: &[u8]) -> u16 {
1998 let mut total_score = 0;
1999
2000 for x in 0..width {
2001 let mut window = initial_vertical_finder_window(width, modules, x);
2002
2003 for y in 0..width.saturating_sub(FINDER_LIKE_PATTERN_WIDTH - 1) {
2004 if y > 0 {
2005 window = roll_finder_window(window, modules[(y + FINDER_LIKE_PATTERN_WIDTH - 1) * width + x]);
2006 }
2007
2008 if window != FINDER_LIKE_PATTERN_BITS {
2009 continue;
2010 }
2011
2012 if !vertical_range_has_dark(width, modules, x, y.saturating_sub(4), y)
2013 || !vertical_range_has_dark(
2014 width,
2015 modules,
2016 x,
2017 y + FINDER_LIKE_PATTERN_WIDTH,
2018 min(y + FINDER_LIKE_PATTERN_WIDTH + 4, width),
2019 )
2020 {
2021 total_score += 40;
2022 }
2023 }
2024 }
2025
2026 total_score
2027}
2028
2029fn compute_line_finder_penalty_score(line: &[u8]) -> u16 {
2030 let mut total_score = 0;
2031 let mut window = initial_finder_window(line);
2032
2033 for offset in 0..line.len().saturating_sub(FINDER_LIKE_PATTERN_WIDTH - 1) {
2034 if offset > 0 {
2035 window = roll_finder_window(window, line[offset + FINDER_LIKE_PATTERN_WIDTH - 1]);
2036 }
2037
2038 if window != FINDER_LIKE_PATTERN_BITS {
2039 continue;
2040 }
2041
2042 if !line_range_has_dark(line, offset.saturating_sub(4), offset)
2043 || !line_range_has_dark(
2044 line,
2045 offset + FINDER_LIKE_PATTERN_WIDTH,
2046 min(offset + FINDER_LIKE_PATTERN_WIDTH + 4, line.len()),
2047 )
2048 {
2049 total_score += 40;
2050 }
2051 }
2052
2053 total_score
2054}
2055
2056fn initial_finder_window(line: &[u8]) -> u8 {
2057 line.iter().take(FINDER_LIKE_PATTERN_WIDTH).fold(0, |window, &module| roll_finder_window(window, module))
2058}
2059
2060fn initial_vertical_finder_window(width: usize, modules: &[u8], x: usize) -> u8 {
2061 (0..min(FINDER_LIKE_PATTERN_WIDTH, width)).fold(0, |window, y| roll_finder_window(window, modules[y * width + x]))
2062}
2063
2064fn roll_finder_window(window: u8, module: u8) -> u8 {
2065 ((window << 1) | (module & 1)) & FINDER_LIKE_PATTERN_MASK
2066}
2067
2068fn vertical_range_has_dark(width: usize, modules: &[u8], x: usize, start: usize, end: usize) -> bool {
2069 (start..end).any(|y| modules[y * width + x] != 0)
2070}
2071
2072fn line_range_has_dark(line: &[u8], start: usize, end: usize) -> bool {
2073 line[start..end].iter().any(|&module| module != 0)
2074}
2075
2076fn compute_block_penalty_score(width: usize, modules: &[u8]) -> u16 {
2077 #[cfg(target_arch = "aarch64")]
2078 {
2079 unsafe { compute_block_penalty_score_neon(width, modules) }
2082 }
2083
2084 #[cfg(target_arch = "x86_64")]
2085 {
2086 if avx2_available() {
2087 return unsafe { compute_block_penalty_score_avx2(width, modules) };
2090 }
2091
2092 if sse2_available() {
2093 return unsafe { compute_block_penalty_score_sse2(width, modules) };
2096 }
2097
2098 compute_block_penalty_score_scalar(width, modules)
2099 }
2100
2101 #[cfg(not(any(target_arch = "aarch64", target_arch = "x86_64")))]
2102 {
2103 compute_block_penalty_score_scalar(width, modules)
2104 }
2105}
2106
2107#[cfg(any(
2108 test,
2109 feature = "bench-internals",
2110 target_arch = "x86_64",
2111 not(any(target_arch = "aarch64", target_arch = "x86_64"))
2112))]
2113fn compute_block_penalty_score_scalar(width: usize, modules: &[u8]) -> u16 {
2114 let mut total_score = 0;
2115
2116 for y in 0..width.saturating_sub(1) {
2117 let row = &modules[y * width..][..width];
2118 let next_row = &modules[(y + 1) * width..][..width];
2119 for x in 0..width.saturating_sub(1) {
2120 let this = row[x];
2121 if this == row[x + 1] && this == next_row[x] && this == next_row[x + 1] {
2122 total_score += 3;
2123 }
2124 }
2125 }
2126
2127 total_score
2128}
2129
2130#[cfg(all(target_arch = "x86_64", feature = "std"))]
2131fn sse2_available() -> bool {
2132 std::is_x86_feature_detected!("sse2")
2133}
2134
2135#[cfg(all(target_arch = "x86_64", not(feature = "std")))]
2136fn sse2_available() -> bool {
2137 true
2138}
2139
2140#[cfg(all(target_arch = "x86_64", feature = "std"))]
2141fn avx2_available() -> bool {
2142 std::is_x86_feature_detected!("avx2")
2143}
2144
2145#[cfg(all(target_arch = "x86_64", not(feature = "std")))]
2146fn avx2_available() -> bool {
2147 false
2148}
2149
2150#[cfg(target_arch = "aarch64")]
2151#[target_feature(enable = "neon")]
2152unsafe fn count_dark_modules_neon(modules: &[u8]) -> usize {
2153 use core::arch::aarch64::{vaddvq_u8, vceqq_u8, vcntq_u8, vdupq_n_u8, vld1q_u8, vmvnq_u8};
2154
2155 let mut count = 0;
2156 let mut offset = 0;
2157 let zero = vdupq_n_u8(0);
2158
2159 while offset + 16 <= modules.len() {
2160 let chunk = unsafe { vld1q_u8(modules.as_ptr().wrapping_add(offset)) };
2163 let nonzero_lanes = vmvnq_u8(vceqq_u8(chunk, zero));
2164 count += (vaddvq_u8(vcntq_u8(nonzero_lanes)) / 8) as usize;
2165 offset += 16;
2166 }
2167
2168 count + count_dark_modules_scalar(&modules[offset..])
2169}
2170
2171#[cfg(target_arch = "x86_64")]
2172#[target_feature(enable = "avx2")]
2173unsafe fn count_dark_modules_avx2(modules: &[u8]) -> usize {
2174 use core::arch::x86_64::{
2175 __m256i, _mm256_cmpeq_epi8, _mm256_loadu_si256, _mm256_movemask_epi8, _mm256_setzero_si256,
2176 };
2177
2178 let mut count = 0;
2179 let mut offset = 0;
2180 let zero = _mm256_setzero_si256();
2181
2182 while offset + 32 <= modules.len() {
2183 let ptr = modules.as_ptr().wrapping_add(offset).cast::<__m256i>();
2184 let chunk = unsafe { _mm256_loadu_si256(ptr) };
2187 let zero_lanes = _mm256_movemask_epi8(_mm256_cmpeq_epi8(chunk, zero)) as u32;
2188 count += 32 - zero_lanes.count_ones() as usize;
2189 offset += 32;
2190 }
2191
2192 count + count_dark_modules_sse2_remainder(&modules[offset..])
2193}
2194
2195#[cfg(target_arch = "x86_64")]
2196#[target_feature(enable = "sse2")]
2197unsafe fn count_dark_modules_sse2(modules: &[u8]) -> usize {
2198 count_dark_modules_sse2_remainder(modules)
2199}
2200
2201#[cfg(target_arch = "x86_64")]
2202#[target_feature(enable = "sse2")]
2203fn count_dark_modules_sse2_remainder(modules: &[u8]) -> usize {
2204 use core::arch::x86_64::{__m128i, _mm_cmpeq_epi8, _mm_loadu_si128, _mm_movemask_epi8, _mm_setzero_si128};
2205
2206 let mut count = 0;
2207 let mut offset = 0;
2208 let zero = _mm_setzero_si128();
2209
2210 while offset + 16 <= modules.len() {
2211 let ptr = modules.as_ptr().wrapping_add(offset).cast::<__m128i>();
2212 let chunk = unsafe { _mm_loadu_si128(ptr) };
2215 let zero_lanes = _mm_movemask_epi8(_mm_cmpeq_epi8(chunk, zero)) as u32;
2216 count += 16 - zero_lanes.count_ones() as usize;
2217 offset += 16;
2218 }
2219
2220 count + count_dark_modules_scalar(&modules[offset..])
2221}
2222
2223#[cfg(target_arch = "aarch64")]
2224#[target_feature(enable = "neon")]
2225unsafe fn compute_block_penalty_score_neon(width: usize, modules: &[u8]) -> u16 {
2226 use core::arch::aarch64::{vaddvq_u8, vandq_u8, vceqq_u8, vcntq_u8, vld1q_u8};
2227
2228 let mut total_score = 0;
2229 for y in 0..width.saturating_sub(1) {
2230 let row = &modules[y * width..][..width];
2231 let next_row = &modules[(y + 1) * width..][..width];
2232 let mut x = 0;
2233
2234 while x + 16 < width {
2235 let row_chunk = unsafe { vld1q_u8(row.as_ptr().wrapping_add(x)) };
2238 let row_right_chunk = unsafe { vld1q_u8(row.as_ptr().wrapping_add(x + 1)) };
2239 let next_chunk = unsafe { vld1q_u8(next_row.as_ptr().wrapping_add(x)) };
2240 let next_right_chunk = unsafe { vld1q_u8(next_row.as_ptr().wrapping_add(x + 1)) };
2241
2242 let horizontal = vceqq_u8(row_chunk, row_right_chunk);
2243 let vertical = vceqq_u8(row_chunk, next_chunk);
2244 let diagonal = vceqq_u8(row_chunk, next_right_chunk);
2245 let blocks = vandq_u8(vandq_u8(horizontal, vertical), diagonal);
2246 total_score += (vaddvq_u8(vcntq_u8(blocks)) / 8) as u16 * 3;
2247 x += 16;
2248 }
2249
2250 total_score += compute_block_penalty_score_scalar_tail(row, next_row, x);
2251 }
2252
2253 total_score
2254}
2255
2256#[cfg(target_arch = "x86_64")]
2257#[target_feature(enable = "avx2")]
2258unsafe fn compute_block_penalty_score_avx2(width: usize, modules: &[u8]) -> u16 {
2259 use core::arch::x86_64::{__m256i, _mm256_and_si256, _mm256_cmpeq_epi8, _mm256_loadu_si256, _mm256_movemask_epi8};
2260
2261 let mut total_score = 0;
2262 for y in 0..width.saturating_sub(1) {
2263 let row = &modules[y * width..][..width];
2264 let next_row = &modules[(y + 1) * width..][..width];
2265 let mut x = 0;
2266
2267 while x + 32 < width {
2268 let row_ptr = row.as_ptr().wrapping_add(x).cast::<__m256i>();
2269 let row_right_ptr = row.as_ptr().wrapping_add(x + 1).cast::<__m256i>();
2270 let next_ptr = next_row.as_ptr().wrapping_add(x).cast::<__m256i>();
2271 let next_right_ptr = next_row.as_ptr().wrapping_add(x + 1).cast::<__m256i>();
2272
2273 let row_chunk = unsafe { _mm256_loadu_si256(row_ptr) };
2276 let row_right_chunk = unsafe { _mm256_loadu_si256(row_right_ptr) };
2277 let next_chunk = unsafe { _mm256_loadu_si256(next_ptr) };
2278 let next_right_chunk = unsafe { _mm256_loadu_si256(next_right_ptr) };
2279
2280 let horizontal = _mm256_cmpeq_epi8(row_chunk, row_right_chunk);
2281 let vertical = _mm256_cmpeq_epi8(row_chunk, next_chunk);
2282 let diagonal = _mm256_cmpeq_epi8(row_chunk, next_right_chunk);
2283 let blocks = _mm256_and_si256(_mm256_and_si256(horizontal, vertical), diagonal);
2284 total_score += (_mm256_movemask_epi8(blocks) as u32).count_ones() as u16 * 3;
2285 x += 32;
2286 }
2287
2288 total_score += compute_block_penalty_score_scalar_tail(row, next_row, x);
2289 }
2290
2291 total_score
2292}
2293
2294#[cfg(target_arch = "x86_64")]
2295#[target_feature(enable = "sse2")]
2296unsafe fn compute_block_penalty_score_sse2(width: usize, modules: &[u8]) -> u16 {
2297 use core::arch::x86_64::{__m128i, _mm_and_si128, _mm_cmpeq_epi8, _mm_loadu_si128, _mm_movemask_epi8};
2298
2299 let mut total_score = 0;
2300 for y in 0..width.saturating_sub(1) {
2301 let row = &modules[y * width..][..width];
2302 let next_row = &modules[(y + 1) * width..][..width];
2303 let mut x = 0;
2304
2305 while x + 16 < width {
2306 let row_ptr = row.as_ptr().wrapping_add(x).cast::<__m128i>();
2307 let row_right_ptr = row.as_ptr().wrapping_add(x + 1).cast::<__m128i>();
2308 let next_ptr = next_row.as_ptr().wrapping_add(x).cast::<__m128i>();
2309 let next_right_ptr = next_row.as_ptr().wrapping_add(x + 1).cast::<__m128i>();
2310
2311 let row_chunk = unsafe { _mm_loadu_si128(row_ptr) };
2314 let row_right_chunk = unsafe { _mm_loadu_si128(row_right_ptr) };
2315 let next_chunk = unsafe { _mm_loadu_si128(next_ptr) };
2316 let next_right_chunk = unsafe { _mm_loadu_si128(next_right_ptr) };
2317
2318 let horizontal = _mm_cmpeq_epi8(row_chunk, row_right_chunk);
2319 let vertical = _mm_cmpeq_epi8(row_chunk, next_chunk);
2320 let diagonal = _mm_cmpeq_epi8(row_chunk, next_right_chunk);
2321 let blocks = _mm_and_si128(_mm_and_si128(horizontal, vertical), diagonal);
2322 total_score += (_mm_movemask_epi8(blocks) as u32).count_ones() as u16 * 3;
2323 x += 16;
2324 }
2325
2326 total_score += compute_block_penalty_score_scalar_tail(row, next_row, x);
2327 }
2328
2329 total_score
2330}
2331
2332#[cfg(any(target_arch = "x86_64", target_arch = "aarch64"))]
2333fn compute_block_penalty_score_scalar_tail(row: &[u8], next_row: &[u8], start: usize) -> u16 {
2334 let mut total_score = 0;
2335 let mut x = start;
2336
2337 while x + 1 < row.len() {
2338 let this = row[x];
2339 if this == row[x + 1] && this == next_row[x] && this == next_row[x + 1] {
2340 total_score += 3;
2341 }
2342 x += 1;
2343 }
2344
2345 total_score
2346}
2347
2348fn compute_total_penalty_score_from_bytes(version: Version, width: usize, modules: &[u8]) -> u16 {
2349 match version {
2350 Version::Normal(_) => {
2351 let s1_a = compute_adjacent_penalty_score(width, modules, true);
2352 let s1_b = compute_adjacent_penalty_score(width, modules, false);
2353 let s2 = compute_block_penalty_score(width, modules);
2354 let s3_a = compute_finder_penalty_score(width, modules, true);
2355 let s3_b = compute_finder_penalty_score(width, modules, false);
2356 let s4 = compute_balance_penalty_score(modules);
2357 s1_a + s1_b + s2 + s3_a + s3_b + s4
2358 }
2359 Version::Micro(_) => compute_light_side_penalty_score(width, modules),
2360 }
2361}
2362
2363#[cfg(any(test, feature = "bench-internals"))]
2364fn compute_total_penalty_score_from_bytes_scalar(version: Version, width: usize, modules: &[u8]) -> u16 {
2365 match version {
2366 Version::Normal(_) => {
2367 let s1_a = compute_adjacent_penalty_score(width, modules, true);
2368 let s1_b = compute_adjacent_penalty_score(width, modules, false);
2369 let s2 = compute_block_penalty_score_scalar(width, modules);
2370 let s3_a = compute_finder_penalty_score(width, modules, true);
2371 let s3_b = compute_finder_penalty_score(width, modules, false);
2372 let s4 = compute_balance_penalty_score_scalar(modules);
2373 s1_a + s1_b + s2 + s3_a + s3_b + s4
2374 }
2375 Version::Micro(_) => compute_light_side_penalty_score(width, modules),
2376 }
2377}
2378
2379#[cfg(test)]
2380fn compute_total_penalty_score_scalar(version: Version, width: i16, modules: &[Module]) -> u16 {
2381 debug_assert_eq!((width * width).as_usize(), modules.len());
2382 let modules = modules.iter().map(|module| u8::from(module.is_dark())).collect::<Vec<_>>();
2383 compute_total_penalty_score_from_bytes_scalar(version, width.as_usize(), &modules)
2384}
2385
2386#[cfg(test)]
2387mod penalty_tests {
2388 use crate::canvas::{
2389 Canvas, MaskPattern, compute_adjacent_penalty_score, compute_balance_penalty_score,
2390 compute_block_penalty_score, compute_block_penalty_score_scalar, compute_finder_penalty_score,
2391 compute_light_side_penalty_score, compute_total_penalty_score_from_bytes,
2392 compute_total_penalty_score_from_bytes_scalar, compute_total_penalty_score_scalar, count_dark_modules,
2393 count_dark_modules_scalar,
2394 };
2395 use crate::cast::As;
2396 use crate::types::{Color, EcLevel, Version};
2397
2398 fn create_test_canvas() -> Canvas {
2399 let mut c = Canvas::new(Version::Normal(1), EcLevel::Q);
2400 c.draw_all_functional_patterns();
2401 c.draw_data(
2402 b"\x20\x5b\x0b\x78\xd1\x72\xdc\x4d\x43\x40\xec\x11\x00",
2403 b"\xa8\x48\x16\x52\xd9\x36\x9c\x00\x2e\x0f\xb4\x7a\x10",
2404 );
2405 c.apply_mask(MaskPattern::Checkerboard);
2406 c
2407 }
2408
2409 #[test]
2410 fn check_penalty_canvas() {
2411 let c = create_test_canvas();
2412 assert_eq!(
2413 &*c.to_debug_str(),
2414 "\n\
2415 #######.##....#######\n\
2416 #.....#.#..#..#.....#\n\
2417 #.###.#.#..##.#.###.#\n\
2418 #.###.#.#.....#.###.#\n\
2419 #.###.#.#.#...#.###.#\n\
2420 #.....#...#...#.....#\n\
2421 #######.#.#.#.#######\n\
2422 ........#............\n\
2423 .##.#.##....#.#.#####\n\
2424 .#......####....#...#\n\
2425 ..##.###.##...#.##...\n\
2426 .##.##.#..##.#.#.###.\n\
2427 #...#.#.#.###.###.#.#\n\
2428 ........##.#..#...#.#\n\
2429 #######.#.#....#.##..\n\
2430 #.....#..#.##.##.#...\n\
2431 #.###.#.#.#...#######\n\
2432 #.###.#..#.#.#.#...#.\n\
2433 #.###.#.#...####.#..#\n\
2434 #.....#.#.##.#...#.##\n\
2435 #######.....####....#"
2436 );
2437 }
2438
2439 #[test]
2440 fn test_penalty_score_adjacent() {
2441 let c = create_test_canvas();
2442 assert_eq!(c.compute_adjacent_penalty_score(true), 88);
2443 assert_eq!(c.compute_adjacent_penalty_score(false), 92);
2444 }
2445
2446 #[test]
2447 fn adjacent_penalty_score_matches_canvas_wrapper() {
2448 let c = create_test_canvas();
2449 let modules = c.modules.iter().map(|module| u8::from(module.is_dark())).collect::<Vec<_>>();
2450 assert_eq!(
2451 compute_adjacent_penalty_score(c.width.as_usize(), &modules, true),
2452 c.compute_adjacent_penalty_score(true)
2453 );
2454 assert_eq!(
2455 compute_adjacent_penalty_score(c.width.as_usize(), &modules, false),
2456 c.compute_adjacent_penalty_score(false)
2457 );
2458 }
2459
2460 #[test]
2461 fn test_penalty_score_block() {
2462 let c = create_test_canvas();
2463 assert_eq!(c.compute_block_penalty_score(), 90);
2464 }
2465
2466 #[test]
2467 fn block_penalty_score_matches_scalar_for_varied_widths() {
2468 for width in [1_usize, 2, 7, 21, 45] {
2469 let modules = (0..width * width).map(|i| u8::from((i + i / width) % 5 < 2)).collect::<Vec<_>>();
2470 assert_eq!(
2471 compute_block_penalty_score(width, &modules),
2472 compute_block_penalty_score_scalar(width, &modules)
2473 );
2474 }
2475 }
2476
2477 #[test]
2478 fn test_penalty_score_finder() {
2479 let c = create_test_canvas();
2480 assert_eq!(c.compute_finder_penalty_score(true), 0);
2481 assert_eq!(c.compute_finder_penalty_score(false), 40);
2482 }
2483
2484 #[test]
2485 fn finder_penalty_score_matches_canvas_wrapper() {
2486 let c = create_test_canvas();
2487 let modules = c.modules.iter().map(|module| u8::from(module.is_dark())).collect::<Vec<_>>();
2488 assert_eq!(
2489 compute_finder_penalty_score(c.width.as_usize(), &modules, true),
2490 c.compute_finder_penalty_score(true)
2491 );
2492 assert_eq!(
2493 compute_finder_penalty_score(c.width.as_usize(), &modules, false),
2494 c.compute_finder_penalty_score(false)
2495 );
2496 }
2497
2498 #[test]
2499 fn test_penalty_score_balance() {
2500 let c = create_test_canvas();
2501 assert_eq!(c.compute_balance_penalty_score(), 2);
2502 }
2503
2504 #[test]
2505 fn balance_penalty_score_matches_canvas_wrapper() {
2506 let c = create_test_canvas();
2507 let modules = c.modules.iter().map(|module| u8::from(module.is_dark())).collect::<Vec<_>>();
2508 assert_eq!(compute_balance_penalty_score(&modules), c.compute_balance_penalty_score());
2509 }
2510
2511 #[test]
2512 fn dark_module_count_matches_scalar_for_varied_lengths() {
2513 for len in 0..65 {
2514 let modules = (0..len).map(|i| u8::from(i % 3 == 0 || i % 7 == 0)).collect::<Vec<_>>();
2515 assert_eq!(count_dark_modules(&modules), count_dark_modules_scalar(&modules));
2516 }
2517 }
2518
2519 #[test]
2520 fn scalar_penalty_score_matches_canvas_wrapper() {
2521 let c = create_test_canvas();
2522 assert_eq!(
2523 compute_total_penalty_score_scalar(c.version, c.width, &c.modules),
2524 c.compute_total_penalty_scores()
2525 );
2526 }
2527
2528 #[test]
2529 fn accelerated_penalty_score_matches_scalar_byte_grid() {
2530 let c = create_test_canvas();
2531 let modules = c.modules.iter().map(|module| u8::from(module.is_dark())).collect::<Vec<_>>();
2532
2533 assert_eq!(
2534 compute_total_penalty_score_from_bytes(c.version, c.width.as_usize(), &modules),
2535 compute_total_penalty_score_from_bytes_scalar(c.version, c.width.as_usize(), &modules)
2536 );
2537 }
2538
2539 #[test]
2540 fn scratch_penalty_score_matches_canvas_wrapper() {
2541 let c = create_test_canvas();
2542 let mut scratch = Vec::new();
2543
2544 assert_eq!(c.compute_total_penalty_scores_with_scratch(&mut scratch), c.compute_total_penalty_scores());
2545 assert_eq!(scratch.len(), c.modules.len());
2546 }
2547
2548 #[test]
2549 fn test_penalty_score_light_sides() {
2550 static HORIZONTAL_SIDE: [Color; 17] = [
2551 Color::Dark,
2552 Color::Light,
2553 Color::Light,
2554 Color::Dark,
2555 Color::Dark,
2556 Color::Dark,
2557 Color::Light,
2558 Color::Light,
2559 Color::Dark,
2560 Color::Light,
2561 Color::Dark,
2562 Color::Light,
2563 Color::Light,
2564 Color::Dark,
2565 Color::Light,
2566 Color::Light,
2567 Color::Light,
2568 ];
2569 static VERTICAL_SIDE: [Color; 17] = [
2570 Color::Dark,
2571 Color::Dark,
2572 Color::Dark,
2573 Color::Light,
2574 Color::Light,
2575 Color::Dark,
2576 Color::Dark,
2577 Color::Light,
2578 Color::Dark,
2579 Color::Light,
2580 Color::Dark,
2581 Color::Light,
2582 Color::Dark,
2583 Color::Light,
2584 Color::Light,
2585 Color::Dark,
2586 Color::Light,
2587 ];
2588
2589 let mut c = Canvas::new(Version::Micro(4), EcLevel::Q);
2590 for i in 0_i16..17 {
2591 c.put(i, -1, HORIZONTAL_SIDE[i.as_usize()]);
2592 c.put(-1, i, VERTICAL_SIDE[i.as_usize()]);
2593 }
2594
2595 assert_eq!(c.compute_light_side_penalty_score(), 168);
2596 }
2597
2598 #[test]
2599 fn light_side_penalty_score_matches_canvas_wrapper() {
2600 let mut c = Canvas::new(Version::Micro(4), EcLevel::Q);
2601 c.draw_all_functional_patterns();
2602 let modules = c.modules.iter().map(|module| u8::from(module.is_dark())).collect::<Vec<_>>();
2603
2604 assert_eq!(
2605 compute_light_side_penalty_score(c.width.as_usize(), &modules),
2606 c.compute_light_side_penalty_score()
2607 );
2608 }
2609}
2610
2611static ALL_PATTERNS_QR: [MaskPattern; 8] = [
2616 MaskPattern::Checkerboard,
2617 MaskPattern::HorizontalLines,
2618 MaskPattern::VerticalLines,
2619 MaskPattern::DiagonalLines,
2620 MaskPattern::LargeCheckerboard,
2621 MaskPattern::Fields,
2622 MaskPattern::Diamonds,
2623 MaskPattern::Meadow,
2624];
2625
2626static ALL_PATTERNS_MICRO_QR: [MaskPattern; 4] =
2627 [MaskPattern::HorizontalLines, MaskPattern::LargeCheckerboard, MaskPattern::Diamonds, MaskPattern::Meadow];
2628
2629impl Canvas {
2630 #[must_use]
2633 pub fn apply_best_mask(&self) -> Self {
2634 let patterns: &[MaskPattern] = match self.version {
2635 Version::Normal(_) => &ALL_PATTERNS_QR,
2636 Version::Micro(_) => &ALL_PATTERNS_MICRO_QR,
2637 };
2638 let mut scratch = Vec::with_capacity(self.modules.len());
2639 let mut best_canvas = None;
2640 let mut best_score = u16::MAX;
2641
2642 for &pattern in patterns {
2643 let mut c = self.clone();
2644 c.apply_mask(pattern);
2645 let score = c.compute_total_penalty_scores_with_scratch(&mut scratch);
2646 if score < best_score {
2647 best_score = score;
2648 best_canvas = Some(c);
2649 }
2650 }
2651
2652 best_canvas.expect("at least one pattern")
2653 }
2654
2655 pub fn into_colors(self) -> Vec<Color> {
2657 self.modules.into_iter().map(Color::from).collect()
2658 }
2659}
2660
2661