diff --git a/core/src/matrix/patterns.rs b/core/src/matrix/patterns.rs index 5ce8eb7..fa8a0ed 100644 --- a/core/src/matrix/patterns.rs +++ b/core/src/matrix/patterns.rs @@ -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 是版本号 + } }