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 finder patterns.

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

impl Canvas {
    /// Draws a single finder pattern with the center at (x, y).
    fn draw_finder_pattern_at(&mut self, x: i16, y: i16) {
        let (dx_left, dx_right) = if x >= 0 { (-3, 4) } else { (-4, 3) };
        let (dy_top, dy_bottom) = if self.height == 7 {
            (-3, 3)
        } else if y >= 0 {
            (-3, 4)
        } else {
            (-4, 3)
        };
        for j in dy_top..=dy_bottom {
            for i in dx_left..=dx_right {
                self.put(
                    x + i,
                    y + j,
                    match (i, j) {
                        (4 | -4, _) | (_, 4 | -4) => Color::Light,
                        (3 | -3, _) | (_, 3 | -3) => Color::Dark,
                        (2 | -2, _) | (_, 2 | -2) => Color::Light,
                        _ => Color::Dark,
                    },
                );
            }
        }
    }

    /// Draws a single finder pattern for rMQR code.
    ///
    /// In rMQR code, there is one finder pattern that has the same shape as the
    /// alignment pattern located in the bottom right corner.
    fn draw_finder_pattern_rmqr_at(&mut self) {
        self.draw_alignment_pattern_at(self.width - 3, self.height - 3);
    }

    /// Draws the finder patterns.
    ///
    /// The finder patterns is are 7×7 square patterns appearing at the three
    /// corners of a QR code. They allows scanner to locate the QR code and
    /// determine the orientation.
    pub(super) fn draw_finder_patterns(&mut self) {
        self.draw_finder_pattern_at(3, 3);

        match self.version {
            Version::Micro(_) => {}
            Version::Normal(_) => {
                self.draw_finder_pattern_at(-4, 3);
                self.draw_finder_pattern_at(3, -4);
            }
            Version::RectMicro(..) => self.draw_finder_pattern_rmqr_at(),
        }
    }
}

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

    #[test]
    fn test_qr() {
        let mut c = Canvas::new(Version::Normal(1), EcLevel::L);
        c.draw_finder_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_micro_qr() {
        let mut c = Canvas::new(Version::Micro(1), EcLevel::L);
        c.draw_finder_patterns();
        assert_eq!(
            c.to_debug_str(),
            concat!(
                "\n",
                "#######.???\n",
                "#.....#.???\n",
                "#.###.#.???\n",
                "#.###.#.???\n",
                "#.###.#.???\n",
                "#.....#.???\n",
                "#######.???\n",
                "........???\n",
                "???????????\n",
                "???????????\n",
                "???????????"
            )
        );
    }

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