use super::{QRMatrix, Module};
use crate::error_correction::ECCLevel;
const FORMAT_CODEWORDS: [[u16; 8]; 4] = [
[0x77C4, 0x72F3, 0x7DAA, 0x789D, 0x662F, 0x6318, 0x6C41, 0x6976],
[0x5412, 0x5125, 0x5E7C, 0x5B4B, 0x45F9, 0x40CE, 0x4F97, 0x4AA0],
[0x355F, 0x3068, 0x3F31, 0x3A06, 0x24B4, 0x2183, 0x2EDA, 0x2BED],
[0x1689, 0x13BE, 0x1CE7, 0x19D0, 0x0762, 0x0255, 0x0D0C, 0x083B],
];
fn ecc_index(ecc: ECCLevel) -> usize {
match ecc {
ECCLevel::L => 0,
ECCLevel::M => 1,
ECCLevel::Q => 2,
ECCLevel::H => 3,
}
}
pub fn encode_format_info(ecc: ECCLevel, mask_id: u8) -> u16 {
FORMAT_CODEWORDS[ecc_index(ecc)][mask_id as usize]
}
pub fn all_format_info_positions(s: usize) -> Vec<(usize, usize)> {
use std::collections::BTreeSet;
let mut set = BTreeSet::new();
for k in 0..15 {
let (c, r) = tl_position(k);
set.insert((c, r));
let (c, r) = other_position(k, s);
set.insert((c, r));
}
set.into_iter().collect()
}
pub fn place_format_info(matrix: &mut QRMatrix, ecc: ECCLevel, mask_id: u8) {
let code = encode_format_info(ecc, mask_id);
let s = matrix.size;
for k in 0..15 {
let bit_val = ((code >> (14 - k)) & 1) != 0;
let (tl_col, tl_row) = tl_position(k);
matrix.set(tl_col, tl_row, Module::FormatInfo(bit_val));
let (other_col, other_row) = other_position(k, s);
matrix.set(other_col, other_row, Module::FormatInfo(bit_val));
}
matrix.set(8, s - 8, Module::FormatInfo(true));
}
pub fn tl_position(k: usize) -> (usize, usize) {
match k {
0 => (0, 8),
1 => (1, 8),
2 => (2, 8),
3 => (3, 8),
4 => (4, 8),
5 => (5, 8),
6 => (7, 8),
7 => (8, 8),
8 => (8, 7),
9 => (8, 5),
10 => (8, 4),
11 => (8, 3),
12 => (8, 2),
13 => (8, 1),
14 => (8, 0),
_ => unreachable!(),
}
}
fn other_position(k: usize, s: usize) -> (usize, usize) {
match k {
0 => (8, s - 1),
1 => (8, s - 2),
2 => (8, s - 3),
3 => (8, s - 4),
4 => (8, s - 5),
5 => (8, s - 6),
6 => (8, s - 7),
7 => (s - 8, 8),
8 => (s - 7, 8),
9 => (s - 6, 8),
10 => (s - 5, 8),
11 => (s - 4, 8),
12 => (s - 3, 8),
13 => (s - 2, 8),
14 => (s - 1, 8),
_ => unreachable!(),
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn known_codewords() {
assert_eq!(encode_format_info(ECCLevel::L, 0), 0x77C4);
assert_eq!(encode_format_info(ECCLevel::M, 5), 0x40CE);
assert_eq!(encode_format_info(ECCLevel::H, 7), 0x083B);
}
}