qrcode2 0.18.0

A QR code encoding library
Documentation
// SPDX-FileCopyrightText: 2014 kennytm
// SPDX-FileCopyrightText: 2018 Ignas Anikevicius
// SPDX-FileCopyrightText: 2023 Nakanishi
// SPDX-FileCopyrightText: 2025 Shun Sakai
//
// SPDX-License-Identifier: Apache-2.0 OR MIT

//! Implementation of features related to the alignment patterns.

use super::{Canvas, Module};
use crate::{
    cast::As,
    types::{Color, Version},
};

impl Canvas {
    /// Draws a alignment pattern with the center at (x, y).
    pub(super) fn draw_alignment_pattern_at(&mut self, x: i16, y: i16) {
        if self.get(x, y) != Module::Empty {
            return;
        }
        for j in -2..=2 {
            for i in -2..=2 {
                self.put(
                    x + i,
                    y + j,
                    match (i, j) {
                        (2 | -2, _) | (_, 2 | -2) | (0, 0) => Color::Dark,
                        _ => Color::Light,
                    },
                );
            }
        }
    }

    /// Draws a alignment pattern in rMQR code with the center at (x, y).
    fn draw_alignment_pattern_rmqr_at(&mut self, x: i16, y: i16) {
        if self.get(x, y) != Module::Empty {
            return;
        }
        for j in -1..=1 {
            for i in -1..=1 {
                self.put(x + i, y + j, Color::Dark);
            }
        }
        self.put(x, y, Color::Light);
    }

    /// Draws the alignment patterns except for rMQR code.
    ///
    /// The alignment patterns are 5×5 square patterns inside the QR code symbol
    /// to help the scanner create the square grid.
    pub(super) fn draw_alignment_patterns(&mut self) {
        match self.version {
            Version::Micro(_) | Version::Normal(1) | Version::RectMicro(..) => {}
            Version::Normal(2..=6) => self.draw_alignment_pattern_at(-7, -7),
            Version::Normal(a) => {
                let positions = ALIGNMENT_PATTERN_POSITIONS[(a - 7).as_usize()];
                for x in positions {
                    for y in positions {
                        self.draw_alignment_pattern_at(*x, *y);
                    }
                }
            }
        }
    }

    /// Draws the alignment patterns in rMQR code.
    pub(super) fn draw_alignment_patterns_rmqr(&mut self) {
        if self.version.is_rect_micro() {
            let index = self.version.rect_micro_width_index().unwrap() + 34;
            let x_positons = ALIGNMENT_PATTERN_POSITIONS[index];
            for x in x_positons {
                self.draw_alignment_pattern_rmqr_at(*x, 1);
                self.draw_alignment_pattern_rmqr_at(*x, self.height - 2);
            }
        }
    }
}

/// `ALIGNMENT_PATTERN_POSITIONS` describes the x- and y-coordinates of the
/// center of the alignment patterns. Since the QR code is symmetric, only one
/// coordinate is needed. rMQR code is symmetrically placed at the top and
/// bottom, so only one coordinate is needed.
pub static ALIGNMENT_PATTERN_POSITIONS: [&[i16]; 40] = [
    &[6, 22, 38],
    &[6, 24, 42],
    &[6, 26, 46],
    &[6, 28, 50],
    &[6, 30, 54],
    &[6, 32, 58],
    &[6, 34, 62],
    &[6, 26, 46, 66],
    &[6, 26, 48, 70],
    &[6, 26, 50, 74],
    &[6, 30, 54, 78],
    &[6, 30, 56, 82],
    &[6, 30, 58, 86],
    &[6, 34, 62, 90],
    &[6, 28, 50, 72, 94],
    &[6, 26, 50, 74, 98],
    &[6, 30, 54, 78, 102],
    &[6, 28, 54, 80, 106],
    &[6, 32, 58, 84, 110],
    &[6, 30, 58, 86, 114],
    &[6, 34, 62, 90, 118],
    &[6, 26, 50, 74, 98, 122],
    &[6, 30, 54, 78, 102, 126],
    &[6, 26, 52, 78, 104, 130],
    &[6, 30, 56, 82, 108, 134],
    &[6, 34, 60, 86, 112, 138],
    &[6, 30, 58, 86, 114, 142],
    &[6, 34, 62, 90, 118, 146],
    &[6, 30, 54, 78, 102, 126, 150],
    &[6, 24, 50, 76, 102, 128, 154],
    &[6, 28, 54, 80, 106, 132, 158],
    &[6, 32, 58, 84, 110, 136, 162],
    &[6, 26, 54, 82, 110, 138, 166],
    &[6, 30, 58, 86, 114, 142, 170],
    // rMQR versions.
    // 27
    &[],
    // 43
    &[21],
    // 59
    &[19, 39],
    // 77
    &[25, 51],
    // 99
    &[23, 49, 75],
    // 139
    &[27, 55, 83, 111],
];

#[cfg(test)]
mod tests {
    use super::*;
    use crate::types::EcLevel;

    #[test]
    fn test_draw_alignment_patterns_1() {
        let mut c = Canvas::new(Version::Normal(1), EcLevel::L);
        c.draw_finder_patterns();
        c.draw_alignment_patterns();
        assert_eq!(
            c.to_debug_str(),
            concat!(
                "\n",
                "#######.?????.#######\n",
                "#.....#.?????.#.....#\n",
                "#.###.#.?????.#.###.#\n",
                "#.###.#.?????.#.###.#\n",
                "#.###.#.?????.#.###.#\n",
                "#.....#.?????.#.....#\n",
                "#######.?????.#######\n",
                "........?????........\n",
                "?????????????????????\n",
                "?????????????????????\n",
                "?????????????????????\n",
                "?????????????????????\n",
                "?????????????????????\n",
                "........?????????????\n",
                "#######.?????????????\n",
                "#.....#.?????????????\n",
                "#.###.#.?????????????\n",
                "#.###.#.?????????????\n",
                "#.###.#.?????????????\n",
                "#.....#.?????????????\n",
                "#######.?????????????"
            )
        );
    }

    #[test]
    fn test_draw_alignment_patterns_3() {
        let mut c = Canvas::new(Version::Normal(3), EcLevel::L);
        c.draw_finder_patterns();
        c.draw_alignment_patterns();
        assert_eq!(
            c.to_debug_str(),
            concat!(
                "\n",
                "#######.?????????????.#######\n",
                "#.....#.?????????????.#.....#\n",
                "#.###.#.?????????????.#.###.#\n",
                "#.###.#.?????????????.#.###.#\n",
                "#.###.#.?????????????.#.###.#\n",
                "#.....#.?????????????.#.....#\n",
                "#######.?????????????.#######\n",
                "........?????????????........\n",
                "?????????????????????????????\n",
                "?????????????????????????????\n",
                "?????????????????????????????\n",
                "?????????????????????????????\n",
                "?????????????????????????????\n",
                "?????????????????????????????\n",
                "?????????????????????????????\n",
                "?????????????????????????????\n",
                "?????????????????????????????\n",
                "?????????????????????????????\n",
                "?????????????????????????????\n",
                "?????????????????????????????\n",
                "????????????????????#####????\n",
                "........????????????#...#????\n",
                "#######.????????????#.#.#????\n",
                "#.....#.????????????#...#????\n",
                "#.###.#.????????????#####????\n",
                "#.###.#.?????????????????????\n",
                "#.###.#.?????????????????????\n",
                "#.....#.?????????????????????\n",
                "#######.?????????????????????"
            )
        );
    }

    #[test]
    fn test_draw_alignment_patterns_7() {
        let mut c = Canvas::new(Version::Normal(7), EcLevel::L);
        c.draw_finder_patterns();
        c.draw_alignment_patterns();
        assert_eq!(
            c.to_debug_str(),
            concat!(
                "\n",
                "#######.?????????????????????????????.#######\n",
                "#.....#.?????????????????????????????.#.....#\n",
                "#.###.#.?????????????????????????????.#.###.#\n",
                "#.###.#.?????????????????????????????.#.###.#\n",
                "#.###.#.????????????#####????????????.#.###.#\n",
                "#.....#.????????????#...#????????????.#.....#\n",
                "#######.????????????#.#.#????????????.#######\n",
                "........????????????#...#????????????........\n",
                "????????????????????#####????????????????????\n",
                "?????????????????????????????????????????????\n",
                "?????????????????????????????????????????????\n",
                "?????????????????????????????????????????????\n",
                "?????????????????????????????????????????????\n",
                "?????????????????????????????????????????????\n",
                "?????????????????????????????????????????????\n",
                "?????????????????????????????????????????????\n",
                "?????????????????????????????????????????????\n",
                "?????????????????????????????????????????????\n",
                "?????????????????????????????????????????????\n",
                "?????????????????????????????????????????????\n",
                "????#####???????????#####???????????#####????\n",
                "????#...#???????????#...#???????????#...#????\n",
                "????#.#.#???????????#.#.#???????????#.#.#????\n",
                "????#...#???????????#...#???????????#...#????\n",
                "????#####???????????#####???????????#####????\n",
                "?????????????????????????????????????????????\n",
                "?????????????????????????????????????????????\n",
                "?????????????????????????????????????????????\n",
                "?????????????????????????????????????????????\n",
                "?????????????????????????????????????????????\n",
                "?????????????????????????????????????????????\n",
                "?????????????????????????????????????????????\n",
                "?????????????????????????????????????????????\n",
                "?????????????????????????????????????????????\n",
                "?????????????????????????????????????????????\n",
                "?????????????????????????????????????????????\n",
                "????????????????????#####???????????#####????\n",
                "........????????????#...#???????????#...#????\n",
                "#######.????????????#.#.#???????????#.#.#????\n",
                "#.....#.????????????#...#???????????#...#????\n",
                "#.###.#.????????????#####???????????#####????\n",
                "#.###.#.?????????????????????????????????????\n",
                "#.###.#.?????????????????????????????????????\n",
                "#.....#.?????????????????????????????????????\n",
                "#######.?????????????????????????????????????"
            )
        );
    }

    #[test]
    fn test_draw_alignment_patterns_rmqr_7x77() {
        let mut c = Canvas::new(Version::RectMicro(7, 77), EcLevel::L);
        c.draw_finder_patterns();
        c.draw_alignment_patterns_rmqr();
        assert_eq!(
            c.to_debug_str(),
            concat!(
                "\n",
                "#######.????????????????###???????????????????????###????????????????????????\n",
                "#.....#.????????????????#.#???????????????????????#.#????????????????????????\n",
                "#.###.#.????????????????###???????????????????????###???????????????????#####\n",
                "#.###.#.????????????????????????????????????????????????????????????????#...#\n",
                "#.###.#.????????????????###???????????????????????###???????????????????#.#.#\n",
                "#.....#.????????????????#.#???????????????????????#.#???????????????????#...#\n",
                "#######.????????????????###???????????????????????###???????????????????#####"
            )
        );
    }
}