feat: 格式信息 BCH(15,5) + 版本信息 BCH(18,6)

This commit is contained in:
2026-06-16 23:48:53 +08:00
parent 6e1980696d
commit 778b0ee1fa
+91
View File
@@ -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 是版本号
}
}