1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
use crate::{QrCode, QrImage, QrResult, Version};
use image::{
    imageops::{resize, FilterType},
    DynamicImage, GenericImage, GenericImageView, Rgb, RgbImage,
};

impl QrImage {
    fn target_qr(&self, data: &[u8]) -> QrResult<QrCode> {
        if self.auto_size {
            match QrCode::with_version(data, self.qr_version, self.ec_level) {
                Ok(o) => Ok(o),
                Err(_) => match QrCode::with_error_correction_level(data, self.ec_level) {
                    Ok(o) => Ok(o),
                    Err(_) => QrCode::new(data),
                },
            }
        }
        else {
            QrCode::with_version(data, self.qr_version, self.ec_level)
        }
    }
    pub fn render(&self, data: &[u8], img: &DynamicImage) -> QrResult<DynamicImage> {
        let qr = self.target_qr(data)?;
        let size = qr.width() as u32;
        let out = resize(img, 3 * size, 3 * size, FilterType::Triangle);
        let rgb = unsafe {
            redraw_locations(
                &qr,
                DynamicImage::ImageRgba8(out).into_rgb8(),
                self.dark_color,
                self.light_color,
                self.enhanced,
                !self.enhanced,
            )
        };
        return Ok(DynamicImage::ImageRgb8(rgb));
    }
    pub fn render_frames(&self) {
        unimplemented!()
    }
}

pub unsafe fn get_align_locations(qr: &QrCode) -> Vec<(usize, usize)> {
    let mut aligns = vec![];
    match qr.version() {
        Version::Normal(ver) => {
            let align_location: &[Vec<usize>; 40] = &[
                vec![],
                vec![6, 18],
                vec![6, 22],
                vec![6, 26],
                vec![6, 30],
                vec![6, 34],
                vec![6, 22, 38],
                vec![6, 24, 42],
                vec![6, 26, 46],
                vec![6, 28, 50],
                vec![6, 30, 54],
                vec![6, 32, 58],
                vec![6, 34, 62],
                vec![6, 26, 46, 66],
                vec![6, 26, 48, 70],
                vec![6, 26, 50, 74],
                vec![6, 30, 54, 78],
                vec![6, 30, 56, 82],
                vec![6, 30, 58, 86],
                vec![6, 34, 62, 90],
                vec![6, 28, 50, 72, 94],
                vec![6, 26, 50, 74, 98],
                vec![6, 30, 54, 78, 102],
                vec![6, 28, 54, 80, 106],
                vec![6, 32, 58, 84, 110],
                vec![6, 30, 58, 86, 114],
                vec![6, 34, 62, 90, 118],
                vec![6, 26, 50, 74, 98, 122],
                vec![6, 30, 54, 78, 102, 126],
                vec![6, 26, 52, 78, 104, 130],
                vec![6, 30, 56, 82, 108, 134],
                vec![6, 34, 60, 86, 112, 138],
                vec![6, 30, 58, 86, 114, 142],
                vec![6, 34, 62, 90, 118, 146],
                vec![6, 30, 54, 78, 102, 126, 150],
                vec![6, 24, 50, 76, 102, 128, 154],
                vec![6, 28, 54, 80, 106, 132, 158],
                vec![6, 32, 58, 84, 110, 136, 162],
                vec![6, 26, 54, 82, 110, 138, 166],
                vec![6, 30, 58, 86, 114, 142, 170],
            ];
            let loc = align_location.get_unchecked(ver as usize - 1);
            for a in 0..loc.len() {
                for b in 0..loc.len() {
                    if !((a == 0 || b == 0) || (a == loc.len() - 1 && b == 0) || (a == 0 && b == loc.len() - 1)) {
                        for i in (loc.get_unchecked(a) * 3 - 6)..(loc.get_unchecked(a) * 3 + 9) {
                            for j in (loc.get_unchecked(b) * 3 - 6)..(loc.get_unchecked(b) * 3 + 9) {
                                aligns.push((i, j))
                            }
                        }
                    }
                }
            }
        }
        Version::Micro(ver) => {
            let _ = ver;
            unimplemented!()
        }
    }
    return aligns;
}

#[rustfmt::skip]
pub unsafe fn redraw_locations(qr: &QrCode, bg: RgbImage, dark: Rgb<u8>, light: Rgb<u8>, enhanced: bool, skip_bg: bool) -> RgbImage {
    let aligns = get_align_locations(qr);
    let mut qr_img = qr_render_rgb(qr, dark, light);
    // FIXME:
    // Too slow, maybe the target image should be modified
    for i in 0..qr_img.width() - 0 {
        for j in 0..qr_img.width() - 0 {
            let _ = skip_bg;
            if (i < 21 && j < 21)
            || (i < 21 && j > qr_img.width() - 22)
            || (i > qr_img.width() - 22 && j < 21)
            || (enhanced && [18, 19, 20].contains(&i))
            || (enhanced && [18, 19, 20].contains(&j))
            || (enhanced && aligns.contains(&(i as usize + 0, j as usize + 0)))
            || (i % 3 == 1 && j % 3 == 1)
            //|| (!skip_bg && bg.unsafe_get_pixel(i, j) == dark)
            {
                continue;
            }
            else {
                qr_img.unsafe_put_pixel(i, j, bg.unsafe_get_pixel(i, j))
            }
        }
    }
    return qr_img;
}

pub fn qr_render_rgb(qr: &QrCode, dark: Rgb<u8>, light: Rgb<u8>) -> RgbImage {
    qr.render().quiet_zone(false).module_dimensions(3, 3).dark_color(dark).light_color(light).build()
}