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