feat: 格式信息 BCH(15,5) + 版本信息 BCH(18,6)
This commit is contained in:
@@ -120,6 +120,77 @@ pub fn reserve_version_areas(matrix: &mut Matrix) {
|
||||
}
|
||||
}
|
||||
|
||||
/// 格式信息编码: EC 级别 (2 bit) + 掩码编号 (3 bit) → BCH(15,5) → 15 bit
|
||||
/// 然后与掩码 0x5412 XOR
|
||||
pub fn encode_format_info(ec_bits: u8, mask: u8) -> u16 {
|
||||
let data = ((ec_bits & 0x03) << 3) | (mask & 0x07);
|
||||
|
||||
// BCH(15,5): 生成多项式 x¹⁰ + x⁸ + x⁵ + x⁴ + x² + x + 1 = 0x537
|
||||
let gen: u16 = 0x537;
|
||||
let mut val = (data as u16) << 10;
|
||||
for i in (10..=14).rev() {
|
||||
if (val >> i) & 1 == 1 {
|
||||
val ^= gen << (i - 10);
|
||||
}
|
||||
}
|
||||
|
||||
// XOR 掩码
|
||||
((data as u16) << 10) | (val & 0x3FF) ^ 0x5412
|
||||
}
|
||||
|
||||
/// 将格式信息写入矩阵(两处镜像放置)
|
||||
pub fn place_format_info(matrix: &mut Matrix, format: u16) {
|
||||
let size = matrix.size;
|
||||
|
||||
// 第一组:左上角定位图案旁
|
||||
let coords1: [(u8, u8); 15] = [
|
||||
(0, 8), (1, 8), (2, 8), (3, 8), (4, 8), (5, 8), (7, 8), (8, 8),
|
||||
(8, 7), (8, 5), (8, 4), (8, 3), (8, 2), (8, 1), (8, 0),
|
||||
];
|
||||
|
||||
// 第二组:右下角,拆分为右上角旁 + 左下角旁
|
||||
let coords2: [(u8, u8); 15] = [
|
||||
(size - 1, 8), (size - 2, 8), (size - 3, 8), (size - 4, 8),
|
||||
(size - 5, 8), (size - 6, 8), (size - 7, 8), (size - 8, 8),
|
||||
(8, size - 7), (8, size - 6), (8, size - 5), (8, size - 4),
|
||||
(8, size - 3), (8, size - 2), (8, size - 1),
|
||||
];
|
||||
|
||||
for i in 0..15 {
|
||||
let bit = (format >> (14 - i)) & 1 == 1;
|
||||
let (x1, y1) = coords1[i];
|
||||
let (x2, y2) = coords2[i];
|
||||
matrix.set(x1, y1, bit);
|
||||
matrix.set(x2, y2, bit);
|
||||
}
|
||||
}
|
||||
|
||||
/// 版本信息编码 (版本 ≥ 7): BCH(18,6)
|
||||
pub fn encode_version_info(version: u8) -> u32 {
|
||||
let gen: u32 = 0x1F25; // x¹² + x¹¹ + x¹⁰ + x⁹ + x⁸ + x⁵ + x² + 1
|
||||
let mut val = (version as u32) << 12;
|
||||
for i in (12..=17).rev() {
|
||||
if (val >> i) & 1 == 1 {
|
||||
val ^= gen << (i - 12);
|
||||
}
|
||||
}
|
||||
((version as u32) << 12) | (val & 0xFFF)
|
||||
}
|
||||
|
||||
/// 将版本信息写入矩阵(两处放置)
|
||||
pub fn place_version_info(matrix: &mut Matrix, version_info: u32) {
|
||||
let size = matrix.size;
|
||||
for i in 0..6u8 {
|
||||
for j in 0..3u8 {
|
||||
let bit = (version_info >> (17 - (i * 3 + j) as u32)) & 1 == 1;
|
||||
// 右上角旁边 (在定位图案下方)
|
||||
matrix.set(size - 11 + j, i, bit);
|
||||
// 左下角旁边 (在定位图案右侧)
|
||||
matrix.set(i, size - 11 + j, bit);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
@@ -165,4 +236,24 @@ mod tests {
|
||||
assert!(!m.is_reserved(6, 18), "(6,18) 与左下定位图案重叠");
|
||||
assert!(!m.is_reserved(18, 6), "(18,6) 与右上定位图案重叠");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_format_info_nonzero() {
|
||||
let info = encode_format_info(0b00, 0b011); // M level, mask 3
|
||||
assert!(info > 0);
|
||||
assert!(info < 0x8000); // 15-bit
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_format_info_different_masks() {
|
||||
let f0 = encode_format_info(0b00, 0);
|
||||
let f1 = encode_format_info(0b00, 1);
|
||||
assert_ne!(f0, f1); // 不同掩码应产生不同格式信息
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_version_info_known() {
|
||||
let info = encode_version_info(7);
|
||||
assert_eq!((info >> 12) & 0x3F, 7); // 前 6 bit 是版本号
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user