qrcode_rs/
canvas.rs

1//! The `canvas` module puts raw bits into the QR code canvas.
2//!
3//!     use qrcode_rs::types::{Version, EcLevel};
4//!     use qrcode_rs::canvas::{Canvas, MaskPattern};
5//!
6//!     let mut c = Canvas::new(Version::Normal(1), EcLevel::L);
7//!     c.draw_all_functional_patterns();
8//!     c.draw_data(b"data_here", b"ec_code_here");
9//!     c.apply_mask(MaskPattern::Checkerboard);
10//!     let bools = c.to_bools();
11
12use std::cmp::max;
13
14use crate::cast::As;
15use crate::types::{Color, EcLevel, Version};
16
17//------------------------------------------------------------------------------
18//{{{ Modules
19
20/// The color of a module (pixel) in the QR code.
21#[derive(PartialEq, Eq, Clone, Copy, Debug)]
22pub enum Module {
23    /// The module is empty.
24    Empty,
25
26    /// The module is of functional patterns which cannot be masked, or pixels
27    /// which have been masked.
28    Masked(Color),
29
30    /// The module is of data and error correction bits before masking.
31    Unmasked(Color),
32}
33
34impl From<Module> for Color {
35    fn from(module: Module) -> Self {
36        match module {
37            Module::Empty => Color::Light,
38            Module::Masked(c) | Module::Unmasked(c) => c,
39        }
40    }
41}
42
43impl Module {
44    /// Checks whether a module is dark.
45    pub fn is_dark(self) -> bool {
46        Color::from(self) == Color::Dark
47    }
48
49    /// Apply a mask to the unmasked modules.
50    ///
51    ///     use qrcode_rs::canvas::Module;
52    ///     use qrcode_rs::types::Color;
53    ///
54    ///     assert_eq!(Module::Unmasked(Color::Light).mask(true), Module::Masked(Color::Dark));
55    ///     assert_eq!(Module::Unmasked(Color::Dark).mask(true), Module::Masked(Color::Light));
56    ///     assert_eq!(Module::Unmasked(Color::Light).mask(false), Module::Masked(Color::Light));
57    ///     assert_eq!(Module::Masked(Color::Dark).mask(true), Module::Masked(Color::Dark));
58    ///     assert_eq!(Module::Masked(Color::Dark).mask(false), Module::Masked(Color::Dark));
59    ///
60    #[must_use]
61    pub fn mask(self, should_invert: bool) -> Self {
62        match (self, should_invert) {
63            (Module::Empty, true) => Module::Masked(Color::Dark),
64            (Module::Empty, false) => Module::Masked(Color::Light),
65            (Module::Unmasked(c), true) => Module::Masked(!c),
66            (Module::Unmasked(c), false) | (Module::Masked(c), _) => Module::Masked(c),
67        }
68    }
69}
70
71//}}}
72//------------------------------------------------------------------------------
73//{{{ Canvas
74
75/// `Canvas` is an intermediate helper structure to render error-corrected data
76/// into a QR code.
77#[derive(Clone)]
78pub struct Canvas {
79    /// The width and height of the canvas (cached as it is needed frequently).
80    width: i16,
81
82    /// The version of the QR code.
83    version: Version,
84
85    /// The error correction level of the QR code.
86    ec_level: EcLevel,
87
88    /// The modules of the QR code. Modules are arranged in left-to-right, then
89    /// top-to-bottom order.
90    modules: Vec<Module>,
91}
92
93impl Canvas {
94    /// Constructs a new canvas big enough for a QR code of the given version.
95    pub fn new(version: Version, ec_level: EcLevel) -> Self {
96        let width = version.width();
97        Self { width, version, ec_level, modules: vec![Module::Empty; (width * width).as_usize()] }
98    }
99
100    /// Converts the canvas into a human-readable string.
101    #[cfg(test)]
102    fn to_debug_str(&self) -> String {
103        let width = self.width;
104        let mut res = String::with_capacity((width * (width + 1)).as_usize());
105        for y in 0..width {
106            res.push('\n');
107            for x in 0..width {
108                res.push(match self.get(x, y) {
109                    Module::Empty => '?',
110                    Module::Masked(Color::Light) => '.',
111                    Module::Masked(Color::Dark) => '#',
112                    Module::Unmasked(Color::Light) => '-',
113                    Module::Unmasked(Color::Dark) => '*',
114                });
115            }
116        }
117        res
118    }
119
120    fn coords_to_index(&self, x: i16, y: i16) -> usize {
121        let x = if x < 0 { x + self.width } else { x }.as_usize();
122        let y = if y < 0 { y + self.width } else { y }.as_usize();
123        y * self.width.as_usize() + x
124    }
125
126    /// Obtains a module at the given coordinates. For convenience, negative
127    /// coordinates will wrap around.
128    pub fn get(&self, x: i16, y: i16) -> Module {
129        self.modules[self.coords_to_index(x, y)]
130    }
131
132    /// Obtains a mutable module at the given coordinates. For convenience,
133    /// negative coordinates will wrap around.
134    pub fn get_mut(&mut self, x: i16, y: i16) -> &mut Module {
135        let index = self.coords_to_index(x, y);
136        &mut self.modules[index]
137    }
138
139    /// Sets the color of a functional module at the given coordinates. For
140    /// convenience, negative coordinates will wrap around.
141    pub fn put(&mut self, x: i16, y: i16, color: Color) {
142        *self.get_mut(x, y) = Module::Masked(color);
143    }
144}
145
146#[cfg(test)]
147mod basic_canvas_tests {
148    use crate::canvas::{Canvas, Module};
149    use crate::types::{Color, EcLevel, Version};
150
151    #[test]
152    fn test_index() {
153        let mut c = Canvas::new(Version::Normal(1), EcLevel::L);
154
155        assert_eq!(c.get(0, 4), Module::Empty);
156        assert_eq!(c.get(-1, -7), Module::Empty);
157        assert_eq!(c.get(21 - 1, 21 - 7), Module::Empty);
158
159        c.put(0, 0, Color::Dark);
160        c.put(-1, -7, Color::Light);
161        assert_eq!(c.get(0, 0), Module::Masked(Color::Dark));
162        assert_eq!(c.get(21 - 1, -7), Module::Masked(Color::Light));
163        assert_eq!(c.get(-1, 21 - 7), Module::Masked(Color::Light));
164    }
165
166    #[test]
167    fn test_debug_str() {
168        let mut c = Canvas::new(Version::Normal(1), EcLevel::L);
169
170        for i in 3_i16..20 {
171            for j in 3_i16..20 {
172                *c.get_mut(i, j) = match ((i * 3) ^ j) % 5 {
173                    0 => Module::Empty,
174                    1 => Module::Masked(Color::Light),
175                    2 => Module::Masked(Color::Dark),
176                    3 => Module::Unmasked(Color::Light),
177                    4 => Module::Unmasked(Color::Dark),
178                    _ => unreachable!(),
179                };
180            }
181        }
182
183        assert_eq!(
184            &*c.to_debug_str(),
185            "\n\
186             ?????????????????????\n\
187             ?????????????????????\n\
188             ?????????????????????\n\
189             ?????####****....---?\n\
190             ???--.##-..##?..#??.?\n\
191             ???#*?-.*?#.-*#?-*.??\n\
192             ?????*?*?****-*-*---?\n\
193             ???*.-.-.-?-?#?#?#*#?\n\
194             ???.*#.*.*#.*#*#.*#*?\n\
195             ?????.#-#--??.?.#---?\n\
196             ???-.?*.-#?-.?#*-#?.?\n\
197             ???##*??*..##*--*..??\n\
198             ?????-???--??---?---?\n\
199             ???*.#.*.#**.#*#.#*#?\n\
200             ???##.-##..##..?#..??\n\
201             ???.-?*.-?#.-?#*-?#*?\n\
202             ????-.#?-.**#?-.#?-.?\n\
203             ???**?-**??--**?-**??\n\
204             ???#?*?#?*#.*-.-*-.-?\n\
205             ???..-...--??###?###?\n\
206             ?????????????????????"
207        );
208    }
209}
210
211//}}}
212//------------------------------------------------------------------------------
213//{{{ Finder patterns
214
215impl Canvas {
216    /// Draws a single finder pattern with the center at (x, y).
217    fn draw_finder_pattern_at(&mut self, x: i16, y: i16) {
218        let (dx_left, dx_right) = if x >= 0 { (-3, 4) } else { (-4, 3) };
219        let (dy_top, dy_bottom) = if y >= 0 { (-3, 4) } else { (-4, 3) };
220        for j in dy_top..=dy_bottom {
221            for i in dx_left..=dx_right {
222                self.put(
223                    x + i,
224                    y + j,
225                    #[allow(clippy::match_same_arms)]
226                    match (i, j) {
227                        (4 | -4, _) | (_, 4 | -4) => Color::Light,
228                        (3 | -3, _) | (_, 3 | -3) => Color::Dark,
229                        (2 | -2, _) | (_, 2 | -2) => Color::Light,
230                        _ => Color::Dark,
231                    },
232                );
233            }
234        }
235    }
236
237    /// Draws the finder patterns.
238    ///
239    /// The finder patterns is are 7×7 square patterns appearing at the three
240    /// corners of a QR code. They allows scanner to locate the QR code and
241    /// determine the orientation.
242    fn draw_finder_patterns(&mut self) {
243        self.draw_finder_pattern_at(3, 3);
244
245        match self.version {
246            Version::Micro(_) => {}
247            Version::Normal(_) => {
248                self.draw_finder_pattern_at(-4, 3);
249                self.draw_finder_pattern_at(3, -4);
250            }
251        }
252    }
253}
254
255#[cfg(test)]
256mod finder_pattern_tests {
257    use crate::canvas::Canvas;
258    use crate::types::{EcLevel, Version};
259
260    #[test]
261    fn test_qr() {
262        let mut c = Canvas::new(Version::Normal(1), EcLevel::L);
263        c.draw_finder_patterns();
264        assert_eq!(
265            &*c.to_debug_str(),
266            "\n\
267             #######.?????.#######\n\
268             #.....#.?????.#.....#\n\
269             #.###.#.?????.#.###.#\n\
270             #.###.#.?????.#.###.#\n\
271             #.###.#.?????.#.###.#\n\
272             #.....#.?????.#.....#\n\
273             #######.?????.#######\n\
274             ........?????........\n\
275             ?????????????????????\n\
276             ?????????????????????\n\
277             ?????????????????????\n\
278             ?????????????????????\n\
279             ?????????????????????\n\
280             ........?????????????\n\
281             #######.?????????????\n\
282             #.....#.?????????????\n\
283             #.###.#.?????????????\n\
284             #.###.#.?????????????\n\
285             #.###.#.?????????????\n\
286             #.....#.?????????????\n\
287             #######.?????????????"
288        );
289    }
290
291    #[test]
292    fn test_micro_qr() {
293        let mut c = Canvas::new(Version::Micro(1), EcLevel::L);
294        c.draw_finder_patterns();
295        assert_eq!(
296            &*c.to_debug_str(),
297            "\n\
298             #######.???\n\
299             #.....#.???\n\
300             #.###.#.???\n\
301             #.###.#.???\n\
302             #.###.#.???\n\
303             #.....#.???\n\
304             #######.???\n\
305             ........???\n\
306             ???????????\n\
307             ???????????\n\
308             ???????????"
309        );
310    }
311}
312
313//}}}
314//------------------------------------------------------------------------------
315//{{{ Alignment patterns
316
317impl Canvas {
318    /// Draws a alignment pattern with the center at (x, y).
319    fn draw_alignment_pattern_at(&mut self, x: i16, y: i16) {
320        if self.get(x, y) != Module::Empty {
321            return;
322        }
323        for j in -2..=2 {
324            for i in -2..=2 {
325                self.put(
326                    x + i,
327                    y + j,
328                    match (i, j) {
329                        (2 | -2, _) | (_, 2 | -2) | (0, 0) => Color::Dark,
330                        _ => Color::Light,
331                    },
332                );
333            }
334        }
335    }
336
337    /// Draws the alignment patterns.
338    ///
339    /// The alignment patterns are 5×5 square patterns inside the QR code symbol
340    /// to help the scanner create the square grid.
341    fn draw_alignment_patterns(&mut self) {
342        match self.version {
343            Version::Micro(_) | Version::Normal(1) => {}
344            Version::Normal(2..=6) => self.draw_alignment_pattern_at(-7, -7),
345            Version::Normal(a) => {
346                let positions = ALIGNMENT_PATTERN_POSITIONS[(a - 7).as_usize()];
347                for x in positions {
348                    for y in positions {
349                        self.draw_alignment_pattern_at(*x, *y);
350                    }
351                }
352            }
353        }
354    }
355}
356
357#[cfg(test)]
358mod alignment_pattern_tests {
359    use crate::canvas::Canvas;
360    use crate::types::{EcLevel, Version};
361
362    #[test]
363    fn test_draw_alignment_patterns_1() {
364        let mut c = Canvas::new(Version::Normal(1), EcLevel::L);
365        c.draw_finder_patterns();
366        c.draw_alignment_patterns();
367        assert_eq!(
368            &*c.to_debug_str(),
369            "\n\
370             #######.?????.#######\n\
371             #.....#.?????.#.....#\n\
372             #.###.#.?????.#.###.#\n\
373             #.###.#.?????.#.###.#\n\
374             #.###.#.?????.#.###.#\n\
375             #.....#.?????.#.....#\n\
376             #######.?????.#######\n\
377             ........?????........\n\
378             ?????????????????????\n\
379             ?????????????????????\n\
380             ?????????????????????\n\
381             ?????????????????????\n\
382             ?????????????????????\n\
383             ........?????????????\n\
384             #######.?????????????\n\
385             #.....#.?????????????\n\
386             #.###.#.?????????????\n\
387             #.###.#.?????????????\n\
388             #.###.#.?????????????\n\
389             #.....#.?????????????\n\
390             #######.?????????????"
391        );
392    }
393
394    #[test]
395    fn test_draw_alignment_patterns_3() {
396        let mut c = Canvas::new(Version::Normal(3), EcLevel::L);
397        c.draw_finder_patterns();
398        c.draw_alignment_patterns();
399        assert_eq!(
400            &*c.to_debug_str(),
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             ?????????????????????????????\n\
419             ?????????????????????????????\n\
420             ?????????????????????????????\n\
421             ?????????????????????????????\n\
422             ????????????????????#####????\n\
423             ........????????????#...#????\n\
424             #######.????????????#.#.#????\n\
425             #.....#.????????????#...#????\n\
426             #.###.#.????????????#####????\n\
427             #.###.#.?????????????????????\n\
428             #.###.#.?????????????????????\n\
429             #.....#.?????????????????????\n\
430             #######.?????????????????????"
431        );
432    }
433
434    #[test]
435    fn test_draw_alignment_patterns_7() {
436        let mut c = Canvas::new(Version::Normal(7), EcLevel::L);
437        c.draw_finder_patterns();
438        c.draw_alignment_patterns();
439        assert_eq!(
440            &*c.to_debug_str(),
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             ?????????????????????????????????????????????\n\
459             ?????????????????????????????????????????????\n\
460             ?????????????????????????????????????????????\n\
461             ?????????????????????????????????????????????\n\
462             ????#####???????????#####???????????#####????\n\
463             ????#...#???????????#...#???????????#...#????\n\
464             ????#.#.#???????????#.#.#???????????#.#.#????\n\
465             ????#...#???????????#...#???????????#...#????\n\
466             ????#####???????????#####???????????#####????\n\
467             ?????????????????????????????????????????????\n\
468             ?????????????????????????????????????????????\n\
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             #######.?????????????????????????????????????"
487        );
488    }
489}
490
491/// `ALIGNMENT_PATTERN_POSITIONS` describes the x- and y-coordinates of the
492/// center of the alignment patterns. Since the QR code is symmetric, only one
493/// coordinate is needed.
494static ALIGNMENT_PATTERN_POSITIONS: [&[i16]; 34] = [
495    &[6, 22, 38],
496    &[6, 24, 42],
497    &[6, 26, 46],
498    &[6, 28, 50],
499    &[6, 30, 54],
500    &[6, 32, 58],
501    &[6, 34, 62],
502    &[6, 26, 46, 66],
503    &[6, 26, 48, 70],
504    &[6, 26, 50, 74],
505    &[6, 30, 54, 78],
506    &[6, 30, 56, 82],
507    &[6, 30, 58, 86],
508    &[6, 34, 62, 90],
509    &[6, 28, 50, 72, 94],
510    &[6, 26, 50, 74, 98],
511    &[6, 30, 54, 78, 102],
512    &[6, 28, 54, 80, 106],
513    &[6, 32, 58, 84, 110],
514    &[6, 30, 58, 86, 114],
515    &[6, 34, 62, 90, 118],
516    &[6, 26, 50, 74, 98, 122],
517    &[6, 30, 54, 78, 102, 126],
518    &[6, 26, 52, 78, 104, 130],
519    &[6, 30, 56, 82, 108, 134],
520    &[6, 34, 60, 86, 112, 138],
521    &[6, 30, 58, 86, 114, 142],
522    &[6, 34, 62, 90, 118, 146],
523    &[6, 30, 54, 78, 102, 126, 150],
524    &[6, 24, 50, 76, 102, 128, 154],
525    &[6, 28, 54, 80, 106, 132, 158],
526    &[6, 32, 58, 84, 110, 136, 162],
527    &[6, 26, 54, 82, 110, 138, 166],
528    &[6, 30, 58, 86, 114, 142, 170],
529];
530
531//}}}
532//------------------------------------------------------------------------------
533//{{{ Timing patterns
534
535impl Canvas {
536    /// Draws a line from (x1, y1) to (x2, y2), inclusively.
537    ///
538    /// The line must be either horizontal or vertical, i.e.
539    /// `x1 == x2 || y1 == y2`. Additionally, the first coordinates must be less
540    /// then the second ones.
541    ///
542    /// On even coordinates, `color_even` will be plotted; on odd coordinates,
543    /// `color_odd` will be plotted instead. Thus the timing pattern can be
544    /// drawn using this method.
545    ///
546    fn draw_line(&mut self, x1: i16, y1: i16, x2: i16, y2: i16, color_even: Color, color_odd: Color) {
547        debug_assert!(x1 == x2 || y1 == y2);
548
549        if y1 == y2 {
550            // Horizontal line.
551            for x in x1..=x2 {
552                self.put(x, y1, if x % 2 == 0 { color_even } else { color_odd });
553            }
554        } else {
555            // Vertical line.
556            for y in y1..=y2 {
557                self.put(x1, y, if y % 2 == 0 { color_even } else { color_odd });
558            }
559        }
560    }
561
562    /// Draws the timing patterns.
563    ///
564    /// The timing patterns are checkboard-colored lines near the edge of the QR
565    /// code symbol, to establish the fine-grained module coordinates when
566    /// scanning.
567    fn draw_timing_patterns(&mut self) {
568        let width = self.width;
569        let (y, x1, x2) = match self.version {
570            Version::Micro(_) => (0, 8, width - 1),
571            Version::Normal(_) => (6, 8, width - 9),
572        };
573        self.draw_line(x1, y, x2, y, Color::Dark, Color::Light);
574        self.draw_line(y, x1, y, x2, Color::Dark, Color::Light);
575    }
576}
577
578#[cfg(test)]
579mod timing_pattern_tests {
580    use crate::canvas::Canvas;
581    use crate::types::{EcLevel, Version};
582
583    #[test]
584    fn test_draw_timing_patterns_qr() {
585        let mut c = Canvas::new(Version::Normal(1), EcLevel::L);
586        c.draw_timing_patterns();
587        assert_eq!(
588            &*c.to_debug_str(),
589            "\n\
590             ?????????????????????\n\
591             ?????????????????????\n\
592             ?????????????????????\n\
593             ?????????????????????\n\
594             ?????????????????????\n\
595             ?????????????????????\n\
596             ????????#.#.#????????\n\
597             ?????????????????????\n\
598             ??????#??????????????\n\
599             ??????.??????????????\n\
600             ??????#??????????????\n\
601             ??????.??????????????\n\
602             ??????#??????????????\n\
603             ?????????????????????\n\
604             ?????????????????????\n\
605             ?????????????????????\n\
606             ?????????????????????\n\
607             ?????????????????????\n\
608             ?????????????????????\n\
609             ?????????????????????\n\
610             ?????????????????????"
611        );
612    }
613
614    #[test]
615    fn test_draw_timing_patterns_micro_qr() {
616        let mut c = Canvas::new(Version::Micro(1), EcLevel::L);
617        c.draw_timing_patterns();
618        assert_eq!(
619            &*c.to_debug_str(),
620            "\n\
621             ????????#.#\n\
622             ???????????\n\
623             ???????????\n\
624             ???????????\n\
625             ???????????\n\
626             ???????????\n\
627             ???????????\n\
628             ???????????\n\
629             #??????????\n\
630             .??????????\n\
631             #??????????"
632        );
633    }
634}
635
636//}}}
637//------------------------------------------------------------------------------
638//{{{ Format info & Version info
639
640impl Canvas {
641    /// Draws a big-endian integer onto the canvas with the given coordinates.
642    ///
643    /// The 1 bits will be plotted with `on_color` and the 0 bits with
644    /// `off_color`. The coordinates will be extracted from the `coords`
645    /// iterator. It will start from the most significant bits first, so
646    /// *trailing* zeros will be ignored.
647    fn draw_number(&mut self, number: u32, bits: u32, on_color: Color, off_color: Color, coords: &[(i16, i16)]) {
648        let mut mask = 1 << (bits - 1);
649        for &(x, y) in coords {
650            let color = if (mask & number) == 0 { off_color } else { on_color };
651            self.put(x, y, color);
652            mask >>= 1;
653        }
654    }
655
656    /// Draws the format info patterns for an encoded number.
657    fn draw_format_info_patterns_with_number(&mut self, format_info: u16) {
658        let format_info = u32::from(format_info);
659        match self.version {
660            Version::Micro(_) => {
661                self.draw_number(format_info, 15, Color::Dark, Color::Light, &FORMAT_INFO_COORDS_MICRO_QR);
662            }
663            Version::Normal(_) => {
664                self.draw_number(format_info, 15, Color::Dark, Color::Light, &FORMAT_INFO_COORDS_QR_MAIN);
665                self.draw_number(format_info, 15, Color::Dark, Color::Light, &FORMAT_INFO_COORDS_QR_SIDE);
666                self.put(8, -8, Color::Dark); // Dark module.
667            }
668        }
669    }
670
671    /// Reserves area to put in the format information.
672    fn draw_reserved_format_info_patterns(&mut self) {
673        self.draw_format_info_patterns_with_number(0);
674    }
675
676    /// Draws the version information patterns.
677    fn draw_version_info_patterns(&mut self) {
678        match self.version {
679            Version::Micro(_) | Version::Normal(1..=6) => {}
680            Version::Normal(a) => {
681                let version_info = VERSION_INFOS[(a - 7).as_usize()];
682                self.draw_number(version_info, 18, Color::Dark, Color::Light, &VERSION_INFO_COORDS_BL);
683                self.draw_number(version_info, 18, Color::Dark, Color::Light, &VERSION_INFO_COORDS_TR);
684            }
685        }
686    }
687}
688
689#[cfg(test)]
690mod draw_version_info_tests {
691    use crate::canvas::Canvas;
692    use crate::types::{Color, EcLevel, Version};
693
694    #[test]
695    fn test_draw_number() {
696        let mut c = Canvas::new(Version::Micro(1), EcLevel::L);
697        c.draw_number(0b1010_1101, 8, Color::Dark, Color::Light, &[(0, 0), (0, -1), (-2, -2), (-2, 0)]);
698        assert_eq!(
699            &*c.to_debug_str(),
700            "\n\
701             #????????.?\n\
702             ???????????\n\
703             ???????????\n\
704             ???????????\n\
705             ???????????\n\
706             ???????????\n\
707             ???????????\n\
708             ???????????\n\
709             ???????????\n\
710             ?????????#?\n\
711             .??????????"
712        );
713    }
714
715    #[test]
716    fn test_draw_version_info_1() {
717        let mut c = Canvas::new(Version::Normal(1), EcLevel::L);
718        c.draw_version_info_patterns();
719        assert_eq!(
720            &*c.to_debug_str(),
721            "\n\
722             ?????????????????????\n\
723             ?????????????????????\n\
724             ?????????????????????\n\
725             ?????????????????????\n\
726             ?????????????????????\n\
727             ?????????????????????\n\
728             ?????????????????????\n\
729             ?????????????????????\n\
730             ?????????????????????\n\
731             ?????????????????????\n\
732             ?????????????????????\n\
733             ?????????????????????\n\
734             ?????????????????????\n\
735             ?????????????????????\n\
736             ?????????????????????\n\
737             ?????????????????????\n\
738             ?????????????????????\n\
739             ?????????????????????\n\
740             ?????????????????????\n\
741             ?????????????????????\n\
742             ?????????????????????"
743        );
744    }
745
746    #[test]
747    fn test_draw_version_info_7() {
748        let mut c = Canvas::new(Version::Normal(7), EcLevel::L);
749        c.draw_version_info_patterns();
750
751        assert_eq!(
752            &*c.to_debug_str(),
753            "\n\
754             ??????????????????????????????????..#????????\n\
755             ??????????????????????????????????.#.????????\n\
756             ??????????????????????????????????.#.????????\n\
757             ??????????????????????????????????.##????????\n\
758             ??????????????????????????????????###????????\n\
759             ??????????????????????????????????...????????\n\
760             ?????????????????????????????????????????????\n\
761             ?????????????????????????????????????????????\n\
762             ?????????????????????????????????????????????\n\
763             ?????????????????????????????????????????????\n\
764             ?????????????????????????????????????????????\n\
765             ?????????????????????????????????????????????\n\
766             ?????????????????????????????????????????????\n\
767             ?????????????????????????????????????????????\n\
768             ?????????????????????????????????????????????\n\
769             ?????????????????????????????????????????????\n\
770             ?????????????????????????????????????????????\n\
771             ?????????????????????????????????????????????\n\
772             ?????????????????????????????????????????????\n\
773             ?????????????????????????????????????????????\n\
774             ?????????????????????????????????????????????\n\
775             ?????????????????????????????????????????????\n\
776             ?????????????????????????????????????????????\n\
777             ?????????????????????????????????????????????\n\
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             ?????????????????????????????????????????????"
799        );
800    }
801
802    #[test]
803    fn test_draw_reserved_format_info_patterns_qr() {
804        let mut c = Canvas::new(Version::Normal(1), EcLevel::L);
805        c.draw_reserved_format_info_patterns();
806        assert_eq!(
807            &*c.to_debug_str(),
808            "\n\
809             ????????.????????????\n\
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             ????????.????????????"
830        );
831    }
832
833    #[test]
834    fn test_draw_reserved_format_info_patterns_micro_qr() {
835        let mut c = Canvas::new(Version::Micro(1), EcLevel::L);
836        c.draw_reserved_format_info_patterns();
837        assert_eq!(
838            &*c.to_debug_str(),
839            "\n\
840             ???????????\n\
841             ????????.??\n\
842             ????????.??\n\
843             ????????.??\n\
844             ????????.??\n\
845             ????????.??\n\
846             ????????.??\n\
847             ????????.??\n\
848             ?........??\n\
849             ???????????\n\
850             ???????????"
851        );
852    }
853}
854
855static VERSION_INFO_COORDS_BL: [(i16, i16); 18] = [
856    (5, -9),
857    (5, -10),
858    (5, -11),
859    (4, -9),
860    (4, -10),
861    (4, -11),
862    (3, -9),
863    (3, -10),
864    (3, -11),
865    (2, -9),
866    (2, -10),
867    (2, -11),
868    (1, -9),
869    (1, -10),
870    (1, -11),
871    (0, -9),
872    (0, -10),
873    (0, -11),
874];
875
876static VERSION_INFO_COORDS_TR: [(i16, i16); 18] = [
877    (-9, 5),
878    (-10, 5),
879    (-11, 5),
880    (-9, 4),
881    (-10, 4),
882    (-11, 4),
883    (-9, 3),
884    (-10, 3),
885    (-11, 3),
886    (-9, 2),
887    (-10, 2),
888    (-11, 2),
889    (-9, 1),
890    (-10, 1),
891    (-11, 1),
892    (-9, 0),
893    (-10, 0),
894    (-11, 0),
895];
896
897static FORMAT_INFO_COORDS_QR_MAIN: [(i16, i16); 15] = [
898    (0, 8),
899    (1, 8),
900    (2, 8),
901    (3, 8),
902    (4, 8),
903    (5, 8),
904    (7, 8),
905    (8, 8),
906    (8, 7),
907    (8, 5),
908    (8, 4),
909    (8, 3),
910    (8, 2),
911    (8, 1),
912    (8, 0),
913];
914
915static FORMAT_INFO_COORDS_QR_SIDE: [(i16, i16); 15] = [
916    (8, -1),
917    (8, -2),
918    (8, -3),
919    (8, -4),
920    (8, -5),
921    (8, -6),
922    (8, -7),
923    (-8, 8),
924    (-7, 8),
925    (-6, 8),
926    (-5, 8),
927    (-4, 8),
928    (-3, 8),
929    (-2, 8),
930    (-1, 8),
931];
932
933static FORMAT_INFO_COORDS_MICRO_QR: [(i16, i16); 15] = [
934    (1, 8),
935    (2, 8),
936    (3, 8),
937    (4, 8),
938    (5, 8),
939    (6, 8),
940    (7, 8),
941    (8, 8),
942    (8, 7),
943    (8, 6),
944    (8, 5),
945    (8, 4),
946    (8, 3),
947    (8, 2),
948    (8, 1),
949];
950
951static VERSION_INFOS: [u32; 34] = [
952    0x07c94, 0x085bc, 0x09a99, 0x0a4d3, 0x0bbf6, 0x0c762, 0x0d847, 0x0e60d, 0x0f928, 0x10b78, 0x1145d, 0x12a17,
953    0x13532, 0x149a6, 0x15683, 0x168c9, 0x177ec, 0x18ec4, 0x191e1, 0x1afab, 0x1b08e, 0x1cc1a, 0x1d33f, 0x1ed75,
954    0x1f250, 0x209d5, 0x216f0, 0x228ba, 0x2379f, 0x24b0b, 0x2542e, 0x26a64, 0x27541, 0x28c69,
955];
956
957//}}}
958//------------------------------------------------------------------------------
959//{{{ All functional patterns before data placement
960
961impl Canvas {
962    /// Draw all functional patterns, before data placement.
963    ///
964    /// All functional patterns (e.g. the finder pattern) *except* the format
965    /// info pattern will be filled in. The format info pattern will be filled
966    /// with light modules instead. Data bits can then put in the empty modules.
967    /// with `.draw_data()`.
968    pub fn draw_all_functional_patterns(&mut self) {
969        self.draw_finder_patterns();
970        self.draw_alignment_patterns();
971        self.draw_reserved_format_info_patterns();
972        self.draw_timing_patterns();
973        self.draw_version_info_patterns();
974    }
975}
976
977/// Gets whether the module at the given coordinates represents a functional
978/// module.
979pub fn is_functional(version: Version, width: i16, x: i16, y: i16) -> bool {
980    debug_assert!(width == version.width());
981
982    let x = if x < 0 { x + width } else { x };
983    let y = if y < 0 { y + width } else { y };
984
985    match version {
986        Version::Micro(_) => x == 0 || y == 0 || (x < 9 && y < 9),
987        Version::Normal(a) => {
988            let non_alignment_test = x == 6 || y == 6 || // Timing patterns
989                (x < 9 && y < 9) ||                  // Top-left finder pattern
990                (x < 9 && y >= width - 8) ||           // Bottom-left finder pattern
991                (x >= width - 8 && y < 9); // Top-right finder pattern
992            match a {
993                _ if non_alignment_test => true,
994                1 => false,
995                2..=6 => (width - 7 - x).abs() <= 2 && (width - 7 - y).abs() <= 2,
996                _ => {
997                    let positions = ALIGNMENT_PATTERN_POSITIONS[(a - 7).as_usize()];
998                    let last = positions.len() - 1;
999                    for (i, align_x) in positions.iter().enumerate() {
1000                        for (j, align_y) in positions.iter().enumerate() {
1001                            if i == 0 && (j == 0 || j == last) || (i == last && j == 0) {
1002                                continue;
1003                            }
1004                            if (*align_x - x).abs() <= 2 && (*align_y - y).abs() <= 2 {
1005                                return true;
1006                            }
1007                        }
1008                    }
1009                    false
1010                }
1011            }
1012        }
1013    }
1014}
1015
1016#[cfg(test)]
1017mod all_functional_patterns_tests {
1018    use crate::canvas::{is_functional, Canvas};
1019    use crate::types::{EcLevel, Version};
1020
1021    #[test]
1022    fn test_all_functional_patterns_qr() {
1023        let mut c = Canvas::new(Version::Normal(2), EcLevel::L);
1024        c.draw_all_functional_patterns();
1025        assert_eq!(
1026            &*c.to_debug_str(),
1027            "\n\
1028             #######..????????.#######\n\
1029             #.....#..????????.#.....#\n\
1030             #.###.#..????????.#.###.#\n\
1031             #.###.#..????????.#.###.#\n\
1032             #.###.#..????????.#.###.#\n\
1033             #.....#..????????.#.....#\n\
1034             #######.#.#.#.#.#.#######\n\
1035             .........????????........\n\
1036             ......#..????????........\n\
1037             ??????.??????????????????\n\
1038             ??????#??????????????????\n\
1039             ??????.??????????????????\n\
1040             ??????#??????????????????\n\
1041             ??????.??????????????????\n\
1042             ??????#??????????????????\n\
1043             ??????.??????????????????\n\
1044             ??????#?????????#####????\n\
1045             ........#???????#...#????\n\
1046             #######..???????#.#.#????\n\
1047             #.....#..???????#...#????\n\
1048             #.###.#..???????#####????\n\
1049             #.###.#..????????????????\n\
1050             #.###.#..????????????????\n\
1051             #.....#..????????????????\n\
1052             #######..????????????????"
1053        );
1054    }
1055
1056    #[test]
1057    fn test_all_functional_patterns_micro_qr() {
1058        let mut c = Canvas::new(Version::Micro(1), EcLevel::L);
1059        c.draw_all_functional_patterns();
1060        assert_eq!(
1061            &*c.to_debug_str(),
1062            "\n\
1063             #######.#.#\n\
1064             #.....#..??\n\
1065             #.###.#..??\n\
1066             #.###.#..??\n\
1067             #.###.#..??\n\
1068             #.....#..??\n\
1069             #######..??\n\
1070             .........??\n\
1071             #........??\n\
1072             .??????????\n\
1073             #??????????"
1074        );
1075    }
1076
1077    #[test]
1078    fn test_is_functional_qr_1() {
1079        let version = Version::Normal(1);
1080        assert!(is_functional(version, version.width(), 0, 0));
1081        assert!(is_functional(version, version.width(), 10, 6));
1082        assert!(!is_functional(version, version.width(), 10, 5));
1083        assert!(!is_functional(version, version.width(), 14, 14));
1084        assert!(is_functional(version, version.width(), 6, 11));
1085        assert!(!is_functional(version, version.width(), 4, 11));
1086        assert!(is_functional(version, version.width(), 4, 13));
1087        assert!(is_functional(version, version.width(), 17, 7));
1088        assert!(!is_functional(version, version.width(), 17, 17));
1089    }
1090
1091    #[test]
1092    fn test_is_functional_qr_3() {
1093        let version = Version::Normal(3);
1094        assert!(is_functional(version, version.width(), 0, 0));
1095        assert!(!is_functional(version, version.width(), 25, 24));
1096        assert!(is_functional(version, version.width(), 24, 24));
1097        assert!(!is_functional(version, version.width(), 9, 25));
1098        assert!(!is_functional(version, version.width(), 20, 0));
1099        assert!(is_functional(version, version.width(), 21, 0));
1100    }
1101
1102    #[test]
1103    fn test_is_functional_qr_7() {
1104        let version = Version::Normal(7);
1105        assert!(is_functional(version, version.width(), 21, 4));
1106        assert!(is_functional(version, version.width(), 7, 21));
1107        assert!(is_functional(version, version.width(), 22, 22));
1108        assert!(is_functional(version, version.width(), 8, 8));
1109        assert!(!is_functional(version, version.width(), 19, 5));
1110        assert!(!is_functional(version, version.width(), 36, 3));
1111        assert!(!is_functional(version, version.width(), 4, 36));
1112        assert!(is_functional(version, version.width(), 38, 38));
1113    }
1114
1115    #[test]
1116    fn test_is_functional_micro() {
1117        let version = Version::Micro(1);
1118        assert!(is_functional(version, version.width(), 8, 0));
1119        assert!(is_functional(version, version.width(), 10, 0));
1120        assert!(!is_functional(version, version.width(), 10, 1));
1121        assert!(is_functional(version, version.width(), 8, 8));
1122        assert!(is_functional(version, version.width(), 0, 9));
1123        assert!(!is_functional(version, version.width(), 1, 9));
1124    }
1125}
1126
1127//}}}
1128//------------------------------------------------------------------------------
1129//{{{ Data placement iterator
1130
1131struct DataModuleIter {
1132    x: i16,
1133    y: i16,
1134    width: i16,
1135    timing_pattern_column: i16,
1136}
1137
1138impl DataModuleIter {
1139    fn new(version: Version) -> Self {
1140        let width = version.width();
1141        Self {
1142            x: width - 1,
1143            y: width - 1,
1144            width,
1145            timing_pattern_column: match version {
1146                Version::Micro(_) => 0,
1147                Version::Normal(_) => 6,
1148            },
1149        }
1150    }
1151}
1152
1153impl Iterator for DataModuleIter {
1154    type Item = (i16, i16);
1155
1156    fn next(&mut self) -> Option<(i16, i16)> {
1157        let adjusted_ref_col = if self.x <= self.timing_pattern_column { self.x + 1 } else { self.x };
1158        if adjusted_ref_col <= 0 {
1159            return None;
1160        }
1161
1162        let res = (self.x, self.y);
1163        let column_type = (self.width - adjusted_ref_col) % 4;
1164
1165        match column_type {
1166            2 if self.y > 0 => {
1167                self.y -= 1;
1168                self.x += 1;
1169            }
1170            0 if self.y < self.width - 1 => {
1171                self.y += 1;
1172                self.x += 1;
1173            }
1174            0 | 2 if self.x == self.timing_pattern_column + 1 => {
1175                self.x -= 2;
1176            }
1177            _ => {
1178                self.x -= 1;
1179            }
1180        }
1181
1182        Some(res)
1183    }
1184}
1185
1186#[cfg(test)]
1187#[rustfmt::skip] // skip to prevent file becoming too long.
1188mod data_iter_tests {
1189    use crate::canvas::DataModuleIter;
1190    use crate::types::Version;
1191
1192    #[test]
1193    fn test_qr() {
1194        let res = DataModuleIter::new(Version::Normal(1)).collect::<Vec<(i16, i16)>>();
1195        assert_eq!(res, vec![
1196            (20, 20), (19, 20), (20, 19), (19, 19), (20, 18), (19, 18),
1197            (20, 17), (19, 17), (20, 16), (19, 16), (20, 15), (19, 15),
1198            (20, 14), (19, 14), (20, 13), (19, 13), (20, 12), (19, 12),
1199            (20, 11), (19, 11), (20, 10), (19, 10), (20, 9), (19, 9),
1200            (20, 8), (19, 8), (20, 7), (19, 7), (20, 6), (19, 6),
1201            (20, 5), (19, 5), (20, 4), (19, 4), (20, 3), (19, 3),
1202            (20, 2), (19, 2), (20, 1), (19, 1), (20, 0), (19, 0),
1203            (18, 0), (17, 0), (18, 1), (17, 1), (18, 2), (17, 2),
1204            (18, 3), (17, 3), (18, 4), (17, 4), (18, 5), (17, 5),
1205            (18, 6), (17, 6), (18, 7), (17, 7), (18, 8), (17, 8),
1206            (18, 9), (17, 9), (18, 10), (17, 10), (18, 11), (17, 11),
1207            (18, 12), (17, 12), (18, 13), (17, 13), (18, 14), (17, 14),
1208            (18, 15), (17, 15), (18, 16), (17, 16), (18, 17), (17, 17),
1209            (18, 18), (17, 18), (18, 19), (17, 19), (18, 20), (17, 20),
1210            (16, 20), (15, 20), (16, 19), (15, 19), (16, 18), (15, 18),
1211            (16, 17), (15, 17), (16, 16), (15, 16), (16, 15), (15, 15),
1212            (16, 14), (15, 14), (16, 13), (15, 13), (16, 12), (15, 12),
1213            (16, 11), (15, 11), (16, 10), (15, 10), (16, 9), (15, 9),
1214            (16, 8), (15, 8), (16, 7), (15, 7), (16, 6), (15, 6),
1215            (16, 5), (15, 5), (16, 4), (15, 4), (16, 3), (15, 3),
1216            (16, 2), (15, 2), (16, 1), (15, 1), (16, 0), (15, 0),
1217            (14, 0), (13, 0), (14, 1), (13, 1), (14, 2), (13, 2),
1218            (14, 3), (13, 3), (14, 4), (13, 4), (14, 5), (13, 5),
1219            (14, 6), (13, 6), (14, 7), (13, 7), (14, 8), (13, 8),
1220            (14, 9), (13, 9), (14, 10), (13, 10), (14, 11), (13, 11),
1221            (14, 12), (13, 12), (14, 13), (13, 13), (14, 14), (13, 14),
1222            (14, 15), (13, 15), (14, 16), (13, 16), (14, 17), (13, 17),
1223            (14, 18), (13, 18), (14, 19), (13, 19), (14, 20), (13, 20),
1224            (12, 20), (11, 20), (12, 19), (11, 19), (12, 18), (11, 18),
1225            (12, 17), (11, 17), (12, 16), (11, 16), (12, 15), (11, 15),
1226            (12, 14), (11, 14), (12, 13), (11, 13), (12, 12), (11, 12),
1227            (12, 11), (11, 11), (12, 10), (11, 10), (12, 9), (11, 9),
1228            (12, 8), (11, 8), (12, 7), (11, 7), (12, 6), (11, 6),
1229            (12, 5), (11, 5), (12, 4), (11, 4), (12, 3), (11, 3),
1230            (12, 2), (11, 2), (12, 1), (11, 1), (12, 0), (11, 0),
1231            (10, 0), (9, 0), (10, 1), (9, 1), (10, 2), (9, 2),
1232            (10, 3), (9, 3), (10, 4), (9, 4), (10, 5), (9, 5),
1233            (10, 6), (9, 6), (10, 7), (9, 7), (10, 8), (9, 8),
1234            (10, 9), (9, 9), (10, 10), (9, 10), (10, 11), (9, 11),
1235            (10, 12), (9, 12), (10, 13), (9, 13), (10, 14), (9, 14),
1236            (10, 15), (9, 15), (10, 16), (9, 16), (10, 17), (9, 17),
1237            (10, 18), (9, 18), (10, 19), (9, 19), (10, 20), (9, 20),
1238            (8, 20), (7, 20), (8, 19), (7, 19), (8, 18), (7, 18),
1239            (8, 17), (7, 17), (8, 16), (7, 16), (8, 15), (7, 15),
1240            (8, 14), (7, 14), (8, 13), (7, 13), (8, 12), (7, 12),
1241            (8, 11), (7, 11), (8, 10), (7, 10), (8, 9), (7, 9),
1242            (8, 8), (7, 8), (8, 7), (7, 7), (8, 6), (7, 6),
1243            (8, 5), (7, 5), (8, 4), (7, 4), (8, 3), (7, 3),
1244            (8, 2), (7, 2), (8, 1), (7, 1), (8, 0), (7, 0),
1245            (5, 0), (4, 0), (5, 1), (4, 1), (5, 2), (4, 2),
1246            (5, 3), (4, 3), (5, 4), (4, 4), (5, 5), (4, 5),
1247            (5, 6), (4, 6), (5, 7), (4, 7), (5, 8), (4, 8),
1248            (5, 9), (4, 9), (5, 10), (4, 10), (5, 11), (4, 11),
1249            (5, 12), (4, 12), (5, 13), (4, 13), (5, 14), (4, 14),
1250            (5, 15), (4, 15), (5, 16), (4, 16), (5, 17), (4, 17),
1251            (5, 18), (4, 18), (5, 19), (4, 19), (5, 20), (4, 20),
1252            (3, 20), (2, 20), (3, 19), (2, 19), (3, 18), (2, 18),
1253            (3, 17), (2, 17), (3, 16), (2, 16), (3, 15), (2, 15),
1254            (3, 14), (2, 14), (3, 13), (2, 13), (3, 12), (2, 12),
1255            (3, 11), (2, 11), (3, 10), (2, 10), (3, 9), (2, 9),
1256            (3, 8), (2, 8), (3, 7), (2, 7), (3, 6), (2, 6),
1257            (3, 5), (2, 5), (3, 4), (2, 4), (3, 3), (2, 3),
1258            (3, 2), (2, 2), (3, 1), (2, 1), (3, 0), (2, 0),
1259            (1, 0), (0, 0), (1, 1), (0, 1), (1, 2), (0, 2),
1260            (1, 3), (0, 3), (1, 4), (0, 4), (1, 5), (0, 5),
1261            (1, 6), (0, 6), (1, 7), (0, 7), (1, 8), (0, 8),
1262            (1, 9), (0, 9), (1, 10), (0, 10), (1, 11), (0, 11),
1263            (1, 12), (0, 12), (1, 13), (0, 13), (1, 14), (0, 14),
1264            (1, 15), (0, 15), (1, 16), (0, 16), (1, 17), (0, 17),
1265            (1, 18), (0, 18), (1, 19), (0, 19), (1, 20), (0, 20),
1266        ]);
1267    }
1268
1269    #[test]
1270    fn test_micro_qr() {
1271        let res = DataModuleIter::new(Version::Micro(1)).collect::<Vec<(i16, i16)>>();
1272        assert_eq!(res, vec![
1273            (10, 10), (9, 10), (10, 9), (9, 9), (10, 8), (9, 8),
1274            (10, 7), (9, 7), (10, 6), (9, 6), (10, 5), (9, 5),
1275            (10, 4), (9, 4), (10, 3), (9, 3), (10, 2), (9, 2),
1276            (10, 1), (9, 1), (10, 0), (9, 0),
1277            (8, 0), (7, 0), (8, 1), (7, 1), (8, 2), (7, 2),
1278            (8, 3), (7, 3), (8, 4), (7, 4), (8, 5), (7, 5),
1279            (8, 6), (7, 6), (8, 7), (7, 7), (8, 8), (7, 8),
1280            (8, 9), (7, 9), (8, 10), (7, 10),
1281            (6, 10), (5, 10), (6, 9), (5, 9), (6, 8), (5, 8),
1282            (6, 7), (5, 7), (6, 6), (5, 6), (6, 5), (5, 5),
1283            (6, 4), (5, 4), (6, 3), (5, 3), (6, 2), (5, 2),
1284            (6, 1), (5, 1), (6, 0), (5, 0),
1285            (4, 0), (3, 0), (4, 1), (3, 1), (4, 2), (3, 2),
1286            (4, 3), (3, 3), (4, 4), (3, 4), (4, 5), (3, 5),
1287            (4, 6), (3, 6), (4, 7), (3, 7), (4, 8), (3, 8),
1288            (4, 9), (3, 9), (4, 10), (3, 10),
1289            (2, 10), (1, 10), (2, 9), (1, 9), (2, 8), (1, 8),
1290            (2, 7), (1, 7), (2, 6), (1, 6), (2, 5), (1, 5),
1291            (2, 4), (1, 4), (2, 3), (1, 3), (2, 2), (1, 2),
1292            (2, 1), (1, 1), (2, 0), (1, 0),
1293        ]);
1294    }
1295
1296    #[test]
1297    fn test_micro_qr_2() {
1298        let res = DataModuleIter::new(Version::Micro(2)).collect::<Vec<(i16, i16)>>();
1299        assert_eq!(res, vec![
1300            (12, 12), (11, 12), (12, 11), (11, 11), (12, 10), (11, 10),
1301            (12, 9), (11, 9), (12, 8), (11, 8), (12, 7), (11, 7),
1302            (12, 6), (11, 6), (12, 5), (11, 5), (12, 4), (11, 4),
1303            (12, 3), (11, 3), (12, 2), (11, 2), (12, 1), (11, 1),
1304            (12, 0), (11, 0),
1305            (10, 0), (9, 0), (10, 1), (9, 1), (10, 2), (9, 2),
1306            (10, 3), (9, 3), (10, 4), (9, 4), (10, 5), (9, 5),
1307            (10, 6), (9, 6), (10, 7), (9, 7), (10, 8), (9, 8),
1308            (10, 9), (9, 9), (10, 10), (9, 10), (10, 11), (9, 11),
1309            (10, 12), (9, 12),
1310            (8, 12), (7, 12), (8, 11), (7, 11), (8, 10), (7, 10),
1311            (8, 9), (7, 9), (8, 8), (7, 8), (8, 7), (7, 7),
1312            (8, 6), (7, 6), (8, 5), (7, 5), (8, 4), (7, 4),
1313            (8, 3), (7, 3), (8, 2), (7, 2), (8, 1), (7, 1),
1314            (8, 0), (7, 0),
1315            (6, 0), (5, 0), (6, 1), (5, 1), (6, 2), (5, 2),
1316            (6, 3), (5, 3), (6, 4), (5, 4), (6, 5), (5, 5),
1317            (6, 6), (5, 6), (6, 7), (5, 7), (6, 8), (5, 8),
1318            (6, 9), (5, 9), (6, 10), (5, 10), (6, 11), (5, 11),
1319            (6, 12), (5, 12),
1320            (4, 12), (3, 12), (4, 11), (3, 11), (4, 10), (3, 10),
1321            (4, 9), (3, 9), (4, 8), (3, 8), (4, 7), (3, 7),
1322            (4, 6), (3, 6), (4, 5), (3, 5), (4, 4), (3, 4),
1323            (4, 3), (3, 3), (4, 2), (3, 2), (4, 1), (3, 1),
1324            (4, 0), (3, 0),
1325            (2, 0), (1, 0), (2, 1), (1, 1), (2, 2), (1, 2),
1326            (2, 3), (1, 3), (2, 4), (1, 4), (2, 5), (1, 5),
1327            (2, 6), (1, 6), (2, 7), (1, 7), (2, 8), (1, 8),
1328            (2, 9), (1, 9), (2, 10), (1, 10), (2, 11), (1, 11),
1329            (2, 12), (1, 12),
1330        ]);
1331    }
1332}
1333
1334//}}}
1335//------------------------------------------------------------------------------
1336//{{{ Data placement
1337
1338impl Canvas {
1339    fn draw_codewords<I>(&mut self, codewords: &[u8], is_half_codeword_at_end: bool, coords: &mut I)
1340    where
1341        I: Iterator<Item = (i16, i16)>,
1342    {
1343        let length = codewords.len();
1344        let last_word = if is_half_codeword_at_end { length - 1 } else { length };
1345        for (i, b) in codewords.iter().enumerate() {
1346            let bits_end = if i == last_word { 4 } else { 0 };
1347            'outside: for j in (bits_end..=7).rev() {
1348                let color = if (*b & (1 << j)) == 0 { Color::Light } else { Color::Dark };
1349                for (x, y) in coords.by_ref() {
1350                    let r = self.get_mut(x, y);
1351                    if *r == Module::Empty {
1352                        *r = Module::Unmasked(color);
1353                        continue 'outside;
1354                    }
1355                }
1356                return;
1357            }
1358        }
1359    }
1360
1361    /// Draws the encoded data and error correction codes to the empty modules.
1362    pub fn draw_data(&mut self, data: &[u8], ec: &[u8]) {
1363        let is_half_codeword_at_end =
1364            matches!((self.version, self.ec_level), (Version::Micro(1), EcLevel::L) | (Version::Micro(3), EcLevel::M));
1365
1366        let mut coords = DataModuleIter::new(self.version);
1367        self.draw_codewords(data, is_half_codeword_at_end, &mut coords);
1368        self.draw_codewords(ec, false, &mut coords);
1369    }
1370}
1371
1372#[cfg(test)]
1373mod draw_codewords_test {
1374    use crate::canvas::Canvas;
1375    use crate::types::{EcLevel, Version};
1376
1377    #[test]
1378    fn test_micro_qr_1() {
1379        let mut c = Canvas::new(Version::Micro(1), EcLevel::L);
1380        c.draw_all_functional_patterns();
1381        c.draw_data(b"\x6e\x5d\xe2", b"\x2b\x63");
1382        assert_eq!(
1383            &*c.to_debug_str(),
1384            "\n\
1385             #######.#.#\n\
1386             #.....#..-*\n\
1387             #.###.#..**\n\
1388             #.###.#..*-\n\
1389             #.###.#..**\n\
1390             #.....#..*-\n\
1391             #######..*-\n\
1392             .........-*\n\
1393             #........**\n\
1394             .***-**---*\n\
1395             #---*-*-**-"
1396        );
1397    }
1398
1399    #[test]
1400    fn test_qr_2() {
1401        let mut c = Canvas::new(Version::Normal(2), EcLevel::L);
1402        c.draw_all_functional_patterns();
1403        c.draw_data(
1404            b"\x92I$\x92I$\x92I$\x92I$\x92I$\x92I$\x92I$\x92I$\
1405              \x92I$\x92I$\x92I$\x92I$\x92I$\x92I$\x92I$",
1406            b"",
1407        );
1408        assert_eq!(
1409            &*c.to_debug_str(),
1410            "\n\
1411             #######..--*---*-.#######\n\
1412             #.....#..-*-*-*-*.#.....#\n\
1413             #.###.#..*---*---.#.###.#\n\
1414             #.###.#..--*---*-.#.###.#\n\
1415             #.###.#..-*-*-*-*.#.###.#\n\
1416             #.....#..*---*---.#.....#\n\
1417             #######.#.#.#.#.#.#######\n\
1418             .........--*---*-........\n\
1419             ......#..-*-*-*-*........\n\
1420             --*-*-.-**---*---*--**--*\n\
1421             -*-*--#----*---*---------\n\
1422             *----*.*--*-*-*-*-**--**-\n\
1423             --*-*-#-**---*---*--**--*\n\
1424             -*-*--.----*---*---------\n\
1425             *----*#*--*-*-*-*-**--**-\n\
1426             --*-*-.-**---*---*--**--*\n\
1427             -*-*--#----*---*#####----\n\
1428             ........#-*-*-*-#...#-**-\n\
1429             #######..*---*--#.#.#*--*\n\
1430             #.....#..--*---*#...#----\n\
1431             #.###.#..-*-*-*-#####-**-\n\
1432             #.###.#..*---*--*----*--*\n\
1433             #.###.#..--*------**-----\n\
1434             #.....#..-*-*-**-*--*-**-\n\
1435             #######..*---*--*----*--*"
1436        );
1437    }
1438}
1439//}}}
1440//------------------------------------------------------------------------------
1441//{{{ Masking
1442
1443/// The mask patterns. Since QR code and Micro QR code do not use the same
1444/// pattern number, we name them according to their shape instead of the number.
1445#[derive(Debug, Copy, Clone)]
1446pub enum MaskPattern {
1447    /// QR code pattern 000: `(x + y) % 2 == 0`.
1448    Checkerboard = 0b000,
1449
1450    /// QR code pattern 001: `y % 2 == 0`.
1451    HorizontalLines = 0b001,
1452
1453    /// QR code pattern 010: `x % 3 == 0`.
1454    VerticalLines = 0b010,
1455
1456    /// QR code pattern 011: `(x + y) % 3 == 0`.
1457    DiagonalLines = 0b011,
1458
1459    /// QR code pattern 100: `((x/3) + (y/2)) % 2 == 0`.
1460    LargeCheckerboard = 0b100,
1461
1462    /// QR code pattern 101: `(x*y)%2 + (x*y)%3 == 0`.
1463    Fields = 0b101,
1464
1465    /// QR code pattern 110: `((x*y)%2 + (x*y)%3) % 2 == 0`.
1466    Diamonds = 0b110,
1467
1468    /// QR code pattern 111: `((x+y)%2 + (x*y)%3) % 2 == 0`.
1469    Meadow = 0b111,
1470}
1471
1472mod mask_functions {
1473    pub fn checkerboard(x: i16, y: i16) -> bool {
1474        (x + y) % 2 == 0
1475    }
1476
1477    pub fn horizontal_lines(_: i16, y: i16) -> bool {
1478        y % 2 == 0
1479    }
1480
1481    pub fn vertical_lines(x: i16, _: i16) -> bool {
1482        x % 3 == 0
1483    }
1484
1485    pub fn diagonal_lines(x: i16, y: i16) -> bool {
1486        (x + y) % 3 == 0
1487    }
1488
1489    pub fn large_checkerboard(x: i16, y: i16) -> bool {
1490        ((y / 2) + (x / 3)) % 2 == 0
1491    }
1492
1493    pub fn fields(x: i16, y: i16) -> bool {
1494        (x * y) % 2 + (x * y) % 3 == 0
1495    }
1496
1497    pub fn diamonds(x: i16, y: i16) -> bool {
1498        ((x * y) % 2 + (x * y) % 3) % 2 == 0
1499    }
1500
1501    pub fn meadow(x: i16, y: i16) -> bool {
1502        ((x + y) % 2 + (x * y) % 3) % 2 == 0
1503    }
1504}
1505
1506fn get_mask_function(pattern: MaskPattern) -> fn(i16, i16) -> bool {
1507    match pattern {
1508        MaskPattern::Checkerboard => mask_functions::checkerboard,
1509        MaskPattern::HorizontalLines => mask_functions::horizontal_lines,
1510        MaskPattern::VerticalLines => mask_functions::vertical_lines,
1511        MaskPattern::DiagonalLines => mask_functions::diagonal_lines,
1512        MaskPattern::LargeCheckerboard => mask_functions::large_checkerboard,
1513        MaskPattern::Fields => mask_functions::fields,
1514        MaskPattern::Diamonds => mask_functions::diamonds,
1515        MaskPattern::Meadow => mask_functions::meadow,
1516    }
1517}
1518
1519impl Canvas {
1520    /// Applies a mask to the canvas. This method will also draw the format info
1521    /// patterns.
1522    pub fn apply_mask(&mut self, pattern: MaskPattern) {
1523        let mask_fn = get_mask_function(pattern);
1524        for x in 0..self.width {
1525            for y in 0..self.width {
1526                let module = self.get_mut(x, y);
1527                *module = module.mask(mask_fn(x, y));
1528            }
1529        }
1530
1531        self.draw_format_info_patterns(pattern);
1532    }
1533
1534    /// Draws the format information to encode the error correction level and
1535    /// mask pattern.
1536    ///
1537    /// If the error correction level or mask pattern is not supported in the
1538    /// current QR code version, this method will fail.
1539    fn draw_format_info_patterns(&mut self, pattern: MaskPattern) {
1540        let format_number = match self.version {
1541            Version::Normal(_) => {
1542                let simple_format_number = ((self.ec_level as usize) ^ 1) << 3 | (pattern as usize);
1543                FORMAT_INFOS_QR[simple_format_number]
1544            }
1545            Version::Micro(a) => {
1546                let micro_pattern_number = match pattern {
1547                    MaskPattern::HorizontalLines => 0b00,
1548                    MaskPattern::LargeCheckerboard => 0b01,
1549                    MaskPattern::Diamonds => 0b10,
1550                    MaskPattern::Meadow => 0b11,
1551                    _ => panic!("Unsupported mask pattern in Micro QR code"),
1552                };
1553                let symbol_number = match (a, self.ec_level) {
1554                    (1, EcLevel::L) => 0b000,
1555                    (2, EcLevel::L) => 0b001,
1556                    (2, EcLevel::M) => 0b010,
1557                    (3, EcLevel::L) => 0b011,
1558                    (3, EcLevel::M) => 0b100,
1559                    (4, EcLevel::L) => 0b101,
1560                    (4, EcLevel::M) => 0b110,
1561                    (4, EcLevel::Q) => 0b111,
1562                    _ => panic!("Unsupported version/ec_level combination in Micro QR code"),
1563                };
1564                let simple_format_number = symbol_number << 2 | micro_pattern_number;
1565                FORMAT_INFOS_MICRO_QR[simple_format_number]
1566            }
1567        };
1568        self.draw_format_info_patterns_with_number(format_number);
1569    }
1570}
1571
1572#[cfg(test)]
1573mod mask_tests {
1574    use crate::canvas::{Canvas, MaskPattern};
1575    use crate::types::{EcLevel, Version};
1576
1577    #[test]
1578    fn test_apply_mask_qr() {
1579        let mut c = Canvas::new(Version::Normal(1), EcLevel::L);
1580        c.draw_all_functional_patterns();
1581        c.apply_mask(MaskPattern::Checkerboard);
1582
1583        assert_eq!(
1584            &*c.to_debug_str(),
1585            "\n\
1586             #######...#.#.#######\n\
1587             #.....#..#.#..#.....#\n\
1588             #.###.#.#.#.#.#.###.#\n\
1589             #.###.#..#.#..#.###.#\n\
1590             #.###.#...#.#.#.###.#\n\
1591             #.....#..#.#..#.....#\n\
1592             #######.#.#.#.#######\n\
1593             ........##.#.........\n\
1594             ###.#####.#.###...#..\n\
1595             .#.#.#.#.#.#.#.#.#.#.\n\
1596             #.#.#.#.#.#.#.#.#.#.#\n\
1597             .#.#.#.#.#.#.#.#.#.#.\n\
1598             #.#.#.#.#.#.#.#.#.#.#\n\
1599             ........##.#.#.#.#.#.\n\
1600             #######.#.#.#.#.#.#.#\n\
1601             #.....#.##.#.#.#.#.#.\n\
1602             #.###.#.#.#.#.#.#.#.#\n\
1603             #.###.#..#.#.#.#.#.#.\n\
1604             #.###.#.#.#.#.#.#.#.#\n\
1605             #.....#.##.#.#.#.#.#.\n\
1606             #######.#.#.#.#.#.#.#"
1607        );
1608    }
1609
1610    #[test]
1611    fn test_draw_format_info_patterns_qr() {
1612        let mut c = Canvas::new(Version::Normal(1), EcLevel::L);
1613        c.draw_format_info_patterns(MaskPattern::LargeCheckerboard);
1614        assert_eq!(
1615            &*c.to_debug_str(),
1616            "\n\
1617             ????????#????????????\n\
1618             ????????#????????????\n\
1619             ????????#????????????\n\
1620             ????????#????????????\n\
1621             ????????.????????????\n\
1622             ????????#????????????\n\
1623             ?????????????????????\n\
1624             ????????.????????????\n\
1625             ##..##?..????..#.####\n\
1626             ?????????????????????\n\
1627             ?????????????????????\n\
1628             ?????????????????????\n\
1629             ?????????????????????\n\
1630             ????????#????????????\n\
1631             ????????.????????????\n\
1632             ????????#????????????\n\
1633             ????????#????????????\n\
1634             ????????.????????????\n\
1635             ????????.????????????\n\
1636             ????????#????????????\n\
1637             ????????#????????????"
1638        );
1639    }
1640
1641    #[test]
1642    fn test_draw_format_info_patterns_micro_qr() {
1643        let mut c = Canvas::new(Version::Micro(2), EcLevel::L);
1644        c.draw_format_info_patterns(MaskPattern::LargeCheckerboard);
1645        assert_eq!(
1646            &*c.to_debug_str(),
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             ?????????????"
1661        );
1662    }
1663}
1664
1665static FORMAT_INFOS_QR: [u16; 32] = [
1666    0x5412, 0x5125, 0x5e7c, 0x5b4b, 0x45f9, 0x40ce, 0x4f97, 0x4aa0, 0x77c4, 0x72f3, 0x7daa, 0x789d, 0x662f, 0x6318,
1667    0x6c41, 0x6976, 0x1689, 0x13be, 0x1ce7, 0x19d0, 0x0762, 0x0255, 0x0d0c, 0x083b, 0x355f, 0x3068, 0x3f31, 0x3a06,
1668    0x24b4, 0x2183, 0x2eda, 0x2bed,
1669];
1670
1671static FORMAT_INFOS_MICRO_QR: [u16; 32] = [
1672    0x4445, 0x4172, 0x4e2b, 0x4b1c, 0x55ae, 0x5099, 0x5fc0, 0x5af7, 0x6793, 0x62a4, 0x6dfd, 0x68ca, 0x7678, 0x734f,
1673    0x7c16, 0x7921, 0x06de, 0x03e9, 0x0cb0, 0x0987, 0x1735, 0x1202, 0x1d5b, 0x186c, 0x2508, 0x203f, 0x2f66, 0x2a51,
1674    0x34e3, 0x31d4, 0x3e8d, 0x3bba,
1675];
1676
1677//}}}
1678//------------------------------------------------------------------------------
1679//{{{ Penalty score
1680
1681impl Canvas {
1682    /// Compute the penalty score for having too many adjacent modules with the
1683    /// same color.
1684    ///
1685    /// Every 5+N adjacent modules in the same column/row having the same color
1686    /// will contribute 3+N points.
1687    fn compute_adjacent_penalty_score(&self, is_horizontal: bool) -> u16 {
1688        let mut total_score = 0;
1689
1690        for i in 0..self.width {
1691            let map_fn = |j| if is_horizontal { self.get(j, i) } else { self.get(i, j) };
1692
1693            let colors = (0..self.width).map(map_fn).chain(Some(Module::Empty).into_iter());
1694            let mut last_color = Module::Empty;
1695            let mut consecutive_len = 1_u16;
1696
1697            for color in colors {
1698                if color == last_color {
1699                    consecutive_len += 1;
1700                } else {
1701                    last_color = color;
1702                    if consecutive_len >= 5 {
1703                        total_score += consecutive_len - 2;
1704                    }
1705                    consecutive_len = 1;
1706                }
1707            }
1708        }
1709
1710        total_score
1711    }
1712
1713    /// Compute the penalty score for having too many rectangles with the same
1714    /// color.
1715    ///
1716    /// Every 2×2 blocks (with overlapping counted) having the same color will
1717    /// contribute 3 points.
1718    fn compute_block_penalty_score(&self) -> u16 {
1719        let mut total_score = 0;
1720
1721        for i in 0..self.width - 1 {
1722            for j in 0..self.width - 1 {
1723                let this = self.get(i, j);
1724                let right = self.get(i + 1, j);
1725                let bottom = self.get(i, j + 1);
1726                let bottom_right = self.get(i + 1, j + 1);
1727                if this == right && right == bottom && bottom == bottom_right {
1728                    total_score += 3;
1729                }
1730            }
1731        }
1732
1733        total_score
1734    }
1735
1736    /// Compute the penalty score for having a pattern similar to the finder
1737    /// pattern in the wrong place.
1738    ///
1739    /// Every pattern that looks like `#.###.#....` in any orientation will add
1740    /// 40 points.
1741    fn compute_finder_penalty_score(&self, is_horizontal: bool) -> u16 {
1742        static PATTERN: [Color; 7] =
1743            [Color::Dark, Color::Light, Color::Dark, Color::Dark, Color::Dark, Color::Light, Color::Dark];
1744
1745        let mut total_score = 0;
1746
1747        for i in 0..self.width {
1748            for j in 0..self.width - 6 {
1749                // TODO a ref to a closure should be enough?
1750                let get: Box<dyn Fn(i16) -> Color> = if is_horizontal {
1751                    Box::new(|k| self.get(k, i).into())
1752                } else {
1753                    Box::new(|k| self.get(i, k).into())
1754                };
1755
1756                if (j..(j + 7)).map(&*get).ne(PATTERN.iter().copied()) {
1757                    continue;
1758                }
1759
1760                let check = |k| 0 <= k && k < self.width && get(k) != Color::Light;
1761                if !((j - 4)..j).any(&check) || !((j + 7)..(j + 11)).any(&check) {
1762                    total_score += 40;
1763                }
1764            }
1765        }
1766
1767        total_score - 360
1768    }
1769
1770    /// Compute the penalty score for having an unbalanced dark/light ratio.
1771    ///
1772    /// The score is given linearly by the deviation from a 50% ratio of dark
1773    /// modules. The highest possible score is 100.
1774    ///
1775    /// Note that this algorithm differs slightly from the standard we do not
1776    /// round the result every 5%, but the difference should be negligible and
1777    /// should not affect which mask is chosen.
1778    fn compute_balance_penalty_score(&self) -> u16 {
1779        let dark_modules = self.modules.iter().filter(|m| m.is_dark()).count();
1780        let total_modules = self.modules.len();
1781        let ratio = dark_modules * 200 / total_modules;
1782        if ratio >= 100 { ratio - 100 } else { 100 - ratio }.as_u16()
1783    }
1784
1785    /// Compute the penalty score for having too many light modules on the sides.
1786    ///
1787    /// This penalty score is exclusive to Micro QR code.
1788    ///
1789    /// Note that the standard gives the formula for *efficiency* score, which
1790    /// has the inverse meaning of this method, but it is very easy to convert
1791    /// between the two (this score is (16×width − standard-score)).
1792    fn compute_light_side_penalty_score(&self) -> u16 {
1793        let h = (1..self.width).filter(|j| !self.get(*j, -1).is_dark()).count();
1794        let v = (1..self.width).filter(|j| !self.get(-1, *j).is_dark()).count();
1795
1796        (h + v + 15 * max(h, v)).as_u16()
1797    }
1798
1799    /// Compute the total penalty scores. A QR code having higher points is less
1800    /// desirable.
1801    fn compute_total_penalty_scores(&self) -> u16 {
1802        match self.version {
1803            Version::Normal(_) => {
1804                let s1_a = self.compute_adjacent_penalty_score(true);
1805                let s1_b = self.compute_adjacent_penalty_score(false);
1806                let s2 = self.compute_block_penalty_score();
1807                let s3_a = self.compute_finder_penalty_score(true);
1808                let s3_b = self.compute_finder_penalty_score(false);
1809                let s4 = self.compute_balance_penalty_score();
1810                s1_a + s1_b + s2 + s3_a + s3_b + s4
1811            }
1812            Version::Micro(_) => self.compute_light_side_penalty_score(),
1813        }
1814    }
1815}
1816
1817#[cfg(test)]
1818mod penalty_tests {
1819    use crate::canvas::{Canvas, MaskPattern};
1820    use crate::cast::As;
1821    use crate::types::{Color, EcLevel, Version};
1822
1823    fn create_test_canvas() -> Canvas {
1824        let mut c = Canvas::new(Version::Normal(1), EcLevel::Q);
1825        c.draw_all_functional_patterns();
1826        c.draw_data(
1827            b"\x20\x5b\x0b\x78\xd1\x72\xdc\x4d\x43\x40\xec\x11\x00",
1828            b"\xa8\x48\x16\x52\xd9\x36\x9c\x00\x2e\x0f\xb4\x7a\x10",
1829        );
1830        c.apply_mask(MaskPattern::Checkerboard);
1831        c
1832    }
1833
1834    #[test]
1835    fn check_penalty_canvas() {
1836        let c = create_test_canvas();
1837        assert_eq!(
1838            &*c.to_debug_str(),
1839            "\n\
1840             #######.##....#######\n\
1841             #.....#.#..#..#.....#\n\
1842             #.###.#.#..##.#.###.#\n\
1843             #.###.#.#.....#.###.#\n\
1844             #.###.#.#.#...#.###.#\n\
1845             #.....#...#...#.....#\n\
1846             #######.#.#.#.#######\n\
1847             ........#............\n\
1848             .##.#.##....#.#.#####\n\
1849             .#......####....#...#\n\
1850             ..##.###.##...#.##...\n\
1851             .##.##.#..##.#.#.###.\n\
1852             #...#.#.#.###.###.#.#\n\
1853             ........##.#..#...#.#\n\
1854             #######.#.#....#.##..\n\
1855             #.....#..#.##.##.#...\n\
1856             #.###.#.#.#...#######\n\
1857             #.###.#..#.#.#.#...#.\n\
1858             #.###.#.#...####.#..#\n\
1859             #.....#.#.##.#...#.##\n\
1860             #######.....####....#"
1861        );
1862    }
1863
1864    #[test]
1865    fn test_penalty_score_adjacent() {
1866        let c = create_test_canvas();
1867        assert_eq!(c.compute_adjacent_penalty_score(true), 88);
1868        assert_eq!(c.compute_adjacent_penalty_score(false), 92);
1869    }
1870
1871    #[test]
1872    fn test_penalty_score_block() {
1873        let c = create_test_canvas();
1874        assert_eq!(c.compute_block_penalty_score(), 90);
1875    }
1876
1877    #[test]
1878    fn test_penalty_score_finder() {
1879        let c = create_test_canvas();
1880        assert_eq!(c.compute_finder_penalty_score(true), 0);
1881        assert_eq!(c.compute_finder_penalty_score(false), 40);
1882    }
1883
1884    #[test]
1885    fn test_penalty_score_balance() {
1886        let c = create_test_canvas();
1887        assert_eq!(c.compute_balance_penalty_score(), 2);
1888    }
1889
1890    #[test]
1891    fn test_penalty_score_light_sides() {
1892        static HORIZONTAL_SIDE: [Color; 17] = [
1893            Color::Dark,
1894            Color::Light,
1895            Color::Light,
1896            Color::Dark,
1897            Color::Dark,
1898            Color::Dark,
1899            Color::Light,
1900            Color::Light,
1901            Color::Dark,
1902            Color::Light,
1903            Color::Dark,
1904            Color::Light,
1905            Color::Light,
1906            Color::Dark,
1907            Color::Light,
1908            Color::Light,
1909            Color::Light,
1910        ];
1911        static VERTICAL_SIDE: [Color; 17] = [
1912            Color::Dark,
1913            Color::Dark,
1914            Color::Dark,
1915            Color::Light,
1916            Color::Light,
1917            Color::Dark,
1918            Color::Dark,
1919            Color::Light,
1920            Color::Dark,
1921            Color::Light,
1922            Color::Dark,
1923            Color::Light,
1924            Color::Dark,
1925            Color::Light,
1926            Color::Light,
1927            Color::Dark,
1928            Color::Light,
1929        ];
1930
1931        let mut c = Canvas::new(Version::Micro(4), EcLevel::Q);
1932        for i in 0_i16..17 {
1933            c.put(i, -1, HORIZONTAL_SIDE[i.as_usize()]);
1934            c.put(-1, i, VERTICAL_SIDE[i.as_usize()]);
1935        }
1936
1937        assert_eq!(c.compute_light_side_penalty_score(), 168);
1938    }
1939}
1940
1941//}}}
1942//------------------------------------------------------------------------------
1943//{{{ Select mask with lowest penalty score
1944
1945static ALL_PATTERNS_QR: [MaskPattern; 8] = [
1946    MaskPattern::Checkerboard,
1947    MaskPattern::HorizontalLines,
1948    MaskPattern::VerticalLines,
1949    MaskPattern::DiagonalLines,
1950    MaskPattern::LargeCheckerboard,
1951    MaskPattern::Fields,
1952    MaskPattern::Diamonds,
1953    MaskPattern::Meadow,
1954];
1955
1956static ALL_PATTERNS_MICRO_QR: [MaskPattern; 4] =
1957    [MaskPattern::HorizontalLines, MaskPattern::LargeCheckerboard, MaskPattern::Diamonds, MaskPattern::Meadow];
1958
1959impl Canvas {
1960    /// Construct a new canvas and apply the best masking that gives the lowest
1961    /// penalty score.
1962    #[must_use]
1963    pub fn apply_best_mask(&self) -> Self {
1964        match self.version {
1965            Version::Normal(_) => ALL_PATTERNS_QR.iter(),
1966            Version::Micro(_) => ALL_PATTERNS_MICRO_QR.iter(),
1967        }
1968        .map(|ptn| {
1969            let mut c = self.clone();
1970            c.apply_mask(*ptn);
1971            c
1972        })
1973        .min_by_key(Self::compute_total_penalty_scores)
1974        .expect("at least one pattern")
1975    }
1976
1977    /// Convert the modules into a vector of booleans.
1978    #[deprecated(since = "0.4.0", note = "use `into_colors()` instead")]
1979    pub fn to_bools(&self) -> Vec<bool> {
1980        self.modules.iter().map(|m| m.is_dark()).collect()
1981    }
1982
1983    /// Convert the modules into a vector of colors.
1984    pub fn into_colors(self) -> Vec<Color> {
1985        self.modules.into_iter().map(Color::from).collect()
1986    }
1987}
1988
1989//}}}
1990//------------------------------------------------------------------------------