feb5ae709f
- C1: placement.rs 删除列偏移特殊处理 (col==6→5),place_bit 已自动跳过保留区 - C2: version.rs V5-H 纠错表 h_g1: 4→2 (总码字数 200→134) - C3: mode.rs Kanji 编码删除冗余 if/else 重复分支 - C4: galois.rs div() 返回 Option<u8> 替代 panic!
1353 lines
28 KiB
Rust
1353 lines
28 KiB
Rust
use serde::Serialize;
|
||
use std::sync::OnceLock;
|
||
|
||
/// 纠错级别
|
||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize)]
|
||
pub enum EcLevel {
|
||
L, // 约 7%
|
||
M, // 约 15%
|
||
Q, // 约 25%
|
||
H, // 约 30%
|
||
}
|
||
|
||
impl EcLevel {
|
||
/// 格式信息中使用的指示位
|
||
pub fn indicator_bits(self) -> u8 {
|
||
match self {
|
||
EcLevel::L => 0b01,
|
||
EcLevel::M => 0b00,
|
||
EcLevel::Q => 0b11,
|
||
EcLevel::H => 0b10,
|
||
}
|
||
}
|
||
}
|
||
|
||
/// 版本号 1~40
|
||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize)]
|
||
pub struct Version(pub u8);
|
||
|
||
impl Version {
|
||
pub fn new(v: u8) -> Option<Self> {
|
||
if (1..=40).contains(&v) {
|
||
Some(Version(v))
|
||
} else {
|
||
None
|
||
}
|
||
}
|
||
|
||
/// QR 码边长(模块数)
|
||
pub fn size(self) -> u8 {
|
||
17 + self.0 * 4
|
||
}
|
||
|
||
/// 对齐图案位置列表
|
||
pub fn alignment_positions(self) -> &'static [u8] {
|
||
ALIGNMENT_POSITIONS[self.0 as usize - 1]
|
||
}
|
||
|
||
/// 获取该版本+级别的纠错信息
|
||
pub fn ec_info(self, level: EcLevel) -> EcInfo {
|
||
let row = &VERSION_TABLE[self.0 as usize - 1];
|
||
let (total, ec_per_block, g1_blocks, g1_data, g2_blocks, g2_data) = match level {
|
||
EcLevel::L => (
|
||
row.l_total,
|
||
row.l_ec,
|
||
row.l_g1,
|
||
row.l_g1_data,
|
||
row.l_g2,
|
||
row.l_g2_data,
|
||
),
|
||
EcLevel::M => (
|
||
row.m_total,
|
||
row.m_ec,
|
||
row.m_g1,
|
||
row.m_g1_data,
|
||
row.m_g2,
|
||
row.m_g2_data,
|
||
),
|
||
EcLevel::Q => (
|
||
row.q_total,
|
||
row.q_ec,
|
||
row.q_g1,
|
||
row.q_g1_data,
|
||
row.q_g2,
|
||
row.q_g2_data,
|
||
),
|
||
EcLevel::H => (
|
||
row.h_total,
|
||
row.h_ec,
|
||
row.h_g1,
|
||
row.h_g1_data,
|
||
row.h_g2,
|
||
row.h_g2_data,
|
||
),
|
||
};
|
||
EcInfo {
|
||
total_codewords: total,
|
||
ec_per_block,
|
||
blocks: vec![
|
||
BlockInfo {
|
||
count: g1_blocks,
|
||
data_codewords: g1_data,
|
||
},
|
||
BlockInfo {
|
||
count: g2_blocks,
|
||
data_codewords: g2_data,
|
||
},
|
||
],
|
||
}
|
||
}
|
||
}
|
||
|
||
pub struct EcInfo {
|
||
pub total_codewords: u16,
|
||
pub ec_per_block: u8,
|
||
pub blocks: Vec<BlockInfo>,
|
||
}
|
||
|
||
pub struct BlockInfo {
|
||
pub count: u16,
|
||
pub data_codewords: u16,
|
||
}
|
||
|
||
/// 单行版本数据
|
||
struct VersionRow {
|
||
l_total: u16,
|
||
l_ec: u8,
|
||
l_g1: u16,
|
||
l_g1_data: u16,
|
||
l_g2: u16,
|
||
l_g2_data: u16,
|
||
m_total: u16,
|
||
m_ec: u8,
|
||
m_g1: u16,
|
||
m_g1_data: u16,
|
||
m_g2: u16,
|
||
m_g2_data: u16,
|
||
q_total: u16,
|
||
q_ec: u8,
|
||
q_g1: u16,
|
||
q_g1_data: u16,
|
||
q_g2: u16,
|
||
q_g2_data: u16,
|
||
h_total: u16,
|
||
h_ec: u8,
|
||
h_g1: u16,
|
||
h_g1_data: u16,
|
||
h_g2: u16,
|
||
h_g2_data: u16,
|
||
}
|
||
|
||
/// ISO 18004 附录 I — 40 版本 × 4 纠错级别的容量表
|
||
/// 格式: (总码字数, EC码字/块, 组1块数, 组1数据码字数, 组2块数, 组2数据码字数)
|
||
/// 当 g2_data == 0 时,表示仅有一组
|
||
static VERSION_TABLE: [VersionRow; 40] = [
|
||
// 版本 1
|
||
VersionRow {
|
||
l_total: 26,
|
||
l_ec: 7,
|
||
l_g1: 1,
|
||
l_g1_data: 19,
|
||
l_g2: 0,
|
||
l_g2_data: 0,
|
||
m_total: 26,
|
||
m_ec: 10,
|
||
m_g1: 1,
|
||
m_g1_data: 16,
|
||
m_g2: 0,
|
||
m_g2_data: 0,
|
||
q_total: 26,
|
||
q_ec: 13,
|
||
q_g1: 1,
|
||
q_g1_data: 13,
|
||
q_g2: 0,
|
||
q_g2_data: 0,
|
||
h_total: 26,
|
||
h_ec: 17,
|
||
h_g1: 1,
|
||
h_g1_data: 9,
|
||
h_g2: 0,
|
||
h_g2_data: 0,
|
||
},
|
||
// 版本 2
|
||
VersionRow {
|
||
l_total: 44,
|
||
l_ec: 10,
|
||
l_g1: 1,
|
||
l_g1_data: 34,
|
||
l_g2: 0,
|
||
l_g2_data: 0,
|
||
m_total: 44,
|
||
m_ec: 16,
|
||
m_g1: 1,
|
||
m_g1_data: 28,
|
||
m_g2: 0,
|
||
m_g2_data: 0,
|
||
q_total: 44,
|
||
q_ec: 22,
|
||
q_g1: 1,
|
||
q_g1_data: 22,
|
||
q_g2: 0,
|
||
q_g2_data: 0,
|
||
h_total: 44,
|
||
h_ec: 28,
|
||
h_g1: 1,
|
||
h_g1_data: 16,
|
||
h_g2: 0,
|
||
h_g2_data: 0,
|
||
},
|
||
// 版本 3
|
||
VersionRow {
|
||
l_total: 70,
|
||
l_ec: 15,
|
||
l_g1: 1,
|
||
l_g1_data: 55,
|
||
l_g2: 0,
|
||
l_g2_data: 0,
|
||
m_total: 70,
|
||
m_ec: 26,
|
||
m_g1: 1,
|
||
m_g1_data: 44,
|
||
m_g2: 0,
|
||
m_g2_data: 0,
|
||
q_total: 70,
|
||
q_ec: 18,
|
||
q_g1: 2,
|
||
q_g1_data: 17,
|
||
q_g2: 0,
|
||
q_g2_data: 0,
|
||
h_total: 70,
|
||
h_ec: 22,
|
||
h_g1: 2,
|
||
h_g1_data: 13,
|
||
h_g2: 0,
|
||
h_g2_data: 0,
|
||
},
|
||
// 版本 4
|
||
VersionRow {
|
||
l_total: 100,
|
||
l_ec: 20,
|
||
l_g1: 1,
|
||
l_g1_data: 80,
|
||
l_g2: 0,
|
||
l_g2_data: 0,
|
||
m_total: 100,
|
||
m_ec: 18,
|
||
m_g1: 2,
|
||
m_g1_data: 32,
|
||
m_g2: 0,
|
||
m_g2_data: 0,
|
||
q_total: 100,
|
||
q_ec: 26,
|
||
q_g1: 2,
|
||
q_g1_data: 24,
|
||
q_g2: 0,
|
||
q_g2_data: 0,
|
||
h_total: 100,
|
||
h_ec: 16,
|
||
h_g1: 4,
|
||
h_g1_data: 9,
|
||
h_g2: 0,
|
||
h_g2_data: 0,
|
||
},
|
||
// 版本 5
|
||
VersionRow {
|
||
l_total: 134,
|
||
l_ec: 26,
|
||
l_g1: 1,
|
||
l_g1_data: 108,
|
||
l_g2: 0,
|
||
l_g2_data: 0,
|
||
m_total: 134,
|
||
m_ec: 24,
|
||
m_g1: 2,
|
||
m_g1_data: 43,
|
||
m_g2: 0,
|
||
m_g2_data: 0,
|
||
q_total: 134,
|
||
q_ec: 18,
|
||
q_g1: 2,
|
||
q_g1_data: 15,
|
||
q_g2: 2,
|
||
q_g2_data: 16,
|
||
h_total: 134,
|
||
h_ec: 22,
|
||
h_g1: 2,
|
||
h_g1_data: 11,
|
||
h_g2: 2,
|
||
h_g2_data: 12,
|
||
},
|
||
// 版本 6
|
||
VersionRow {
|
||
l_total: 172,
|
||
l_ec: 18,
|
||
l_g1: 2,
|
||
l_g1_data: 68,
|
||
l_g2: 0,
|
||
l_g2_data: 0,
|
||
m_total: 172,
|
||
m_ec: 16,
|
||
m_g1: 4,
|
||
m_g1_data: 27,
|
||
m_g2: 0,
|
||
m_g2_data: 0,
|
||
q_total: 172,
|
||
q_ec: 24,
|
||
q_g1: 4,
|
||
q_g1_data: 19,
|
||
q_g2: 0,
|
||
q_g2_data: 0,
|
||
h_total: 172,
|
||
h_ec: 28,
|
||
h_g1: 4,
|
||
h_g1_data: 15,
|
||
h_g2: 0,
|
||
h_g2_data: 0,
|
||
},
|
||
// 版本 7
|
||
VersionRow {
|
||
l_total: 196,
|
||
l_ec: 20,
|
||
l_g1: 2,
|
||
l_g1_data: 78,
|
||
l_g2: 0,
|
||
l_g2_data: 0,
|
||
m_total: 196,
|
||
m_ec: 18,
|
||
m_g1: 4,
|
||
m_g1_data: 31,
|
||
m_g2: 0,
|
||
m_g2_data: 0,
|
||
q_total: 196,
|
||
q_ec: 18,
|
||
q_g1: 2,
|
||
q_g1_data: 14,
|
||
q_g2: 4,
|
||
q_g2_data: 15,
|
||
h_total: 196,
|
||
h_ec: 26,
|
||
h_g1: 4,
|
||
h_g1_data: 13,
|
||
h_g2: 1,
|
||
h_g2_data: 14,
|
||
},
|
||
// 版本 8
|
||
VersionRow {
|
||
l_total: 242,
|
||
l_ec: 24,
|
||
l_g1: 2,
|
||
l_g1_data: 97,
|
||
l_g2: 0,
|
||
l_g2_data: 0,
|
||
m_total: 242,
|
||
m_ec: 22,
|
||
m_g1: 2,
|
||
m_g1_data: 38,
|
||
m_g2: 2,
|
||
m_g2_data: 39,
|
||
q_total: 242,
|
||
q_ec: 22,
|
||
q_g1: 4,
|
||
q_g1_data: 18,
|
||
q_g2: 2,
|
||
q_g2_data: 19,
|
||
h_total: 242,
|
||
h_ec: 26,
|
||
h_g1: 4,
|
||
h_g1_data: 14,
|
||
h_g2: 2,
|
||
h_g2_data: 15,
|
||
},
|
||
// 版本 9
|
||
VersionRow {
|
||
l_total: 292,
|
||
l_ec: 30,
|
||
l_g1: 2,
|
||
l_g1_data: 116,
|
||
l_g2: 0,
|
||
l_g2_data: 0,
|
||
m_total: 292,
|
||
m_ec: 22,
|
||
m_g1: 3,
|
||
m_g1_data: 36,
|
||
m_g2: 2,
|
||
m_g2_data: 37,
|
||
q_total: 292,
|
||
q_ec: 20,
|
||
q_g1: 4,
|
||
q_g1_data: 16,
|
||
q_g2: 4,
|
||
q_g2_data: 17,
|
||
h_total: 292,
|
||
h_ec: 24,
|
||
h_g1: 4,
|
||
h_g1_data: 12,
|
||
h_g2: 4,
|
||
h_g2_data: 13,
|
||
},
|
||
// 版本 10
|
||
VersionRow {
|
||
l_total: 346,
|
||
l_ec: 18,
|
||
l_g1: 2,
|
||
l_g1_data: 68,
|
||
l_g2: 2,
|
||
l_g2_data: 69,
|
||
m_total: 346,
|
||
m_ec: 26,
|
||
m_g1: 4,
|
||
m_g1_data: 43,
|
||
m_g2: 1,
|
||
m_g2_data: 44,
|
||
q_total: 346,
|
||
q_ec: 24,
|
||
q_g1: 6,
|
||
q_g1_data: 19,
|
||
q_g2: 2,
|
||
q_g2_data: 20,
|
||
h_total: 346,
|
||
h_ec: 28,
|
||
h_g1: 6,
|
||
h_g1_data: 15,
|
||
h_g2: 2,
|
||
h_g2_data: 16,
|
||
},
|
||
// 版本 11
|
||
VersionRow {
|
||
l_total: 404,
|
||
l_ec: 20,
|
||
l_g1: 4,
|
||
l_g1_data: 81,
|
||
l_g2: 0,
|
||
l_g2_data: 0,
|
||
m_total: 404,
|
||
m_ec: 30,
|
||
m_g1: 1,
|
||
m_g1_data: 50,
|
||
m_g2: 4,
|
||
m_g2_data: 51,
|
||
q_total: 404,
|
||
q_ec: 28,
|
||
q_g1: 4,
|
||
q_g1_data: 22,
|
||
q_g2: 4,
|
||
q_g2_data: 23,
|
||
h_total: 404,
|
||
h_ec: 24,
|
||
h_g1: 3,
|
||
h_g1_data: 12,
|
||
h_g2: 8,
|
||
h_g2_data: 13,
|
||
},
|
||
// 版本 12
|
||
VersionRow {
|
||
l_total: 466,
|
||
l_ec: 24,
|
||
l_g1: 2,
|
||
l_g1_data: 92,
|
||
l_g2: 2,
|
||
l_g2_data: 93,
|
||
m_total: 466,
|
||
m_ec: 22,
|
||
m_g1: 6,
|
||
m_g1_data: 36,
|
||
m_g2: 2,
|
||
m_g2_data: 37,
|
||
q_total: 466,
|
||
q_ec: 26,
|
||
q_g1: 4,
|
||
q_g1_data: 20,
|
||
q_g2: 6,
|
||
q_g2_data: 21,
|
||
h_total: 466,
|
||
h_ec: 28,
|
||
h_g1: 7,
|
||
h_g1_data: 14,
|
||
h_g2: 4,
|
||
h_g2_data: 15,
|
||
},
|
||
// 版本 13
|
||
VersionRow {
|
||
l_total: 532,
|
||
l_ec: 26,
|
||
l_g1: 4,
|
||
l_g1_data: 107,
|
||
l_g2: 0,
|
||
l_g2_data: 0,
|
||
m_total: 532,
|
||
m_ec: 22,
|
||
m_g1: 8,
|
||
m_g1_data: 37,
|
||
m_g2: 1,
|
||
m_g2_data: 38,
|
||
q_total: 532,
|
||
q_ec: 24,
|
||
q_g1: 8,
|
||
q_g1_data: 20,
|
||
q_g2: 4,
|
||
q_g2_data: 21,
|
||
h_total: 532,
|
||
h_ec: 22,
|
||
h_g1: 12,
|
||
h_g1_data: 11,
|
||
h_g2: 4,
|
||
h_g2_data: 12,
|
||
},
|
||
// 版本 14
|
||
VersionRow {
|
||
l_total: 581,
|
||
l_ec: 30,
|
||
l_g1: 3,
|
||
l_g1_data: 115,
|
||
l_g2: 1,
|
||
l_g2_data: 116,
|
||
m_total: 581,
|
||
m_ec: 24,
|
||
m_g1: 4,
|
||
m_g1_data: 40,
|
||
m_g2: 5,
|
||
m_g2_data: 41,
|
||
q_total: 581,
|
||
q_ec: 20,
|
||
q_g1: 11,
|
||
q_g1_data: 16,
|
||
q_g2: 5,
|
||
q_g2_data: 17,
|
||
h_total: 581,
|
||
h_ec: 24,
|
||
h_g1: 11,
|
||
h_g1_data: 12,
|
||
h_g2: 5,
|
||
h_g2_data: 13,
|
||
},
|
||
// 版本 15
|
||
VersionRow {
|
||
l_total: 655,
|
||
l_ec: 22,
|
||
l_g1: 5,
|
||
l_g1_data: 87,
|
||
l_g2: 1,
|
||
l_g2_data: 88,
|
||
m_total: 655,
|
||
m_ec: 24,
|
||
m_g1: 5,
|
||
m_g1_data: 41,
|
||
m_g2: 5,
|
||
m_g2_data: 42,
|
||
q_total: 655,
|
||
q_ec: 30,
|
||
q_g1: 5,
|
||
q_g1_data: 24,
|
||
q_g2: 7,
|
||
q_g2_data: 25,
|
||
h_total: 655,
|
||
h_ec: 24,
|
||
h_g1: 11,
|
||
h_g1_data: 12,
|
||
h_g2: 7,
|
||
h_g2_data: 13,
|
||
},
|
||
// 版本 16
|
||
VersionRow {
|
||
l_total: 733,
|
||
l_ec: 24,
|
||
l_g1: 5,
|
||
l_g1_data: 98,
|
||
l_g2: 1,
|
||
l_g2_data: 99,
|
||
m_total: 733,
|
||
m_ec: 28,
|
||
m_g1: 7,
|
||
m_g1_data: 45,
|
||
m_g2: 3,
|
||
m_g2_data: 46,
|
||
q_total: 733,
|
||
q_ec: 24,
|
||
q_g1: 15,
|
||
q_g1_data: 19,
|
||
q_g2: 2,
|
||
q_g2_data: 20,
|
||
h_total: 733,
|
||
h_ec: 30,
|
||
h_g1: 3,
|
||
h_g1_data: 15,
|
||
h_g2: 13,
|
||
h_g2_data: 16,
|
||
},
|
||
// 版本 17
|
||
VersionRow {
|
||
l_total: 815,
|
||
l_ec: 28,
|
||
l_g1: 1,
|
||
l_g1_data: 107,
|
||
l_g2: 5,
|
||
l_g2_data: 108,
|
||
m_total: 815,
|
||
m_ec: 28,
|
||
m_g1: 10,
|
||
m_g1_data: 46,
|
||
m_g2: 1,
|
||
m_g2_data: 47,
|
||
q_total: 815,
|
||
q_ec: 28,
|
||
q_g1: 1,
|
||
q_g1_data: 22,
|
||
q_g2: 15,
|
||
q_g2_data: 23,
|
||
h_total: 815,
|
||
h_ec: 28,
|
||
h_g1: 2,
|
||
h_g1_data: 14,
|
||
h_g2: 17,
|
||
h_g2_data: 15,
|
||
},
|
||
// 版本 18
|
||
VersionRow {
|
||
l_total: 901,
|
||
l_ec: 30,
|
||
l_g1: 5,
|
||
l_g1_data: 120,
|
||
l_g2: 1,
|
||
l_g2_data: 121,
|
||
m_total: 901,
|
||
m_ec: 26,
|
||
m_g1: 9,
|
||
m_g1_data: 43,
|
||
m_g2: 4,
|
||
m_g2_data: 44,
|
||
q_total: 901,
|
||
q_ec: 28,
|
||
q_g1: 17,
|
||
q_g1_data: 22,
|
||
q_g2: 1,
|
||
q_g2_data: 23,
|
||
h_total: 901,
|
||
h_ec: 28,
|
||
h_g1: 2,
|
||
h_g1_data: 14,
|
||
h_g2: 19,
|
||
h_g2_data: 15,
|
||
},
|
||
// 版本 19
|
||
VersionRow {
|
||
l_total: 991,
|
||
l_ec: 28,
|
||
l_g1: 3,
|
||
l_g1_data: 113,
|
||
l_g2: 4,
|
||
l_g2_data: 114,
|
||
m_total: 991,
|
||
m_ec: 26,
|
||
m_g1: 3,
|
||
m_g1_data: 44,
|
||
m_g2: 11,
|
||
m_g2_data: 45,
|
||
q_total: 991,
|
||
q_ec: 26,
|
||
q_g1: 17,
|
||
q_g1_data: 21,
|
||
q_g2: 4,
|
||
q_g2_data: 22,
|
||
h_total: 991,
|
||
h_ec: 26,
|
||
h_g1: 9,
|
||
h_g1_data: 13,
|
||
h_g2: 16,
|
||
h_g2_data: 14,
|
||
},
|
||
// 版本 20
|
||
VersionRow {
|
||
l_total: 1085,
|
||
l_ec: 28,
|
||
l_g1: 3,
|
||
l_g1_data: 107,
|
||
l_g2: 5,
|
||
l_g2_data: 108,
|
||
m_total: 1085,
|
||
m_ec: 26,
|
||
m_g1: 3,
|
||
m_g1_data: 41,
|
||
m_g2: 13,
|
||
m_g2_data: 42,
|
||
q_total: 1085,
|
||
q_ec: 30,
|
||
q_g1: 15,
|
||
q_g1_data: 24,
|
||
q_g2: 5,
|
||
q_g2_data: 25,
|
||
h_total: 1085,
|
||
h_ec: 28,
|
||
h_g1: 15,
|
||
h_g1_data: 15,
|
||
h_g2: 10,
|
||
h_g2_data: 16,
|
||
},
|
||
// 版本 21
|
||
VersionRow {
|
||
l_total: 1156,
|
||
l_ec: 28,
|
||
l_g1: 4,
|
||
l_g1_data: 116,
|
||
l_g2: 4,
|
||
l_g2_data: 117,
|
||
m_total: 1156,
|
||
m_ec: 26,
|
||
m_g1: 17,
|
||
m_g1_data: 42,
|
||
m_g2: 0,
|
||
m_g2_data: 0,
|
||
q_total: 1156,
|
||
q_ec: 28,
|
||
q_g1: 17,
|
||
q_g1_data: 22,
|
||
q_g2: 6,
|
||
q_g2_data: 23,
|
||
h_total: 1156,
|
||
h_ec: 30,
|
||
h_g1: 19,
|
||
h_g1_data: 16,
|
||
h_g2: 6,
|
||
h_g2_data: 17,
|
||
},
|
||
// 版本 22
|
||
VersionRow {
|
||
l_total: 1258,
|
||
l_ec: 28,
|
||
l_g1: 2,
|
||
l_g1_data: 111,
|
||
l_g2: 7,
|
||
l_g2_data: 112,
|
||
m_total: 1258,
|
||
m_ec: 28,
|
||
m_g1: 17,
|
||
m_g1_data: 46,
|
||
m_g2: 0,
|
||
m_g2_data: 0,
|
||
q_total: 1258,
|
||
q_ec: 30,
|
||
q_g1: 7,
|
||
q_g1_data: 24,
|
||
q_g2: 16,
|
||
q_g2_data: 25,
|
||
h_total: 1258,
|
||
h_ec: 24,
|
||
h_g1: 34,
|
||
h_g1_data: 13,
|
||
h_g2: 0,
|
||
h_g2_data: 0,
|
||
},
|
||
// 版本 23
|
||
VersionRow {
|
||
l_total: 1364,
|
||
l_ec: 30,
|
||
l_g1: 4,
|
||
l_g1_data: 121,
|
||
l_g2: 5,
|
||
l_g2_data: 122,
|
||
m_total: 1364,
|
||
m_ec: 28,
|
||
m_g1: 4,
|
||
m_g1_data: 47,
|
||
m_g2: 14,
|
||
m_g2_data: 48,
|
||
q_total: 1364,
|
||
q_ec: 30,
|
||
q_g1: 11,
|
||
q_g1_data: 24,
|
||
q_g2: 14,
|
||
q_g2_data: 25,
|
||
h_total: 1364,
|
||
h_ec: 30,
|
||
h_g1: 16,
|
||
h_g1_data: 15,
|
||
h_g2: 14,
|
||
h_g2_data: 16,
|
||
},
|
||
// 版本 24
|
||
VersionRow {
|
||
l_total: 1474,
|
||
l_ec: 30,
|
||
l_g1: 6,
|
||
l_g1_data: 117,
|
||
l_g2: 4,
|
||
l_g2_data: 118,
|
||
m_total: 1474,
|
||
m_ec: 28,
|
||
m_g1: 6,
|
||
m_g1_data: 45,
|
||
m_g2: 14,
|
||
m_g2_data: 46,
|
||
q_total: 1474,
|
||
q_ec: 30,
|
||
q_g1: 11,
|
||
q_g1_data: 24,
|
||
q_g2: 16,
|
||
q_g2_data: 25,
|
||
h_total: 1474,
|
||
h_ec: 30,
|
||
h_g1: 30,
|
||
h_g1_data: 16,
|
||
h_g2: 2,
|
||
h_g2_data: 17,
|
||
},
|
||
// 版本 25
|
||
VersionRow {
|
||
l_total: 1588,
|
||
l_ec: 26,
|
||
l_g1: 8,
|
||
l_g1_data: 106,
|
||
l_g2: 4,
|
||
l_g2_data: 107,
|
||
m_total: 1588,
|
||
m_ec: 28,
|
||
m_g1: 8,
|
||
m_g1_data: 47,
|
||
m_g2: 13,
|
||
m_g2_data: 48,
|
||
q_total: 1588,
|
||
q_ec: 30,
|
||
q_g1: 7,
|
||
q_g1_data: 24,
|
||
q_g2: 22,
|
||
q_g2_data: 25,
|
||
h_total: 1588,
|
||
h_ec: 30,
|
||
h_g1: 22,
|
||
h_g1_data: 15,
|
||
h_g2: 13,
|
||
h_g2_data: 16,
|
||
},
|
||
// 版本 26
|
||
VersionRow {
|
||
l_total: 1706,
|
||
l_ec: 28,
|
||
l_g1: 10,
|
||
l_g1_data: 114,
|
||
l_g2: 2,
|
||
l_g2_data: 115,
|
||
m_total: 1706,
|
||
m_ec: 28,
|
||
m_g1: 19,
|
||
m_g1_data: 46,
|
||
m_g2: 4,
|
||
m_g2_data: 47,
|
||
q_total: 1706,
|
||
q_ec: 28,
|
||
q_g1: 28,
|
||
q_g1_data: 22,
|
||
q_g2: 6,
|
||
q_g2_data: 23,
|
||
h_total: 1706,
|
||
h_ec: 30,
|
||
h_g1: 33,
|
||
h_g1_data: 16,
|
||
h_g2: 4,
|
||
h_g2_data: 17,
|
||
},
|
||
// 版本 27
|
||
VersionRow {
|
||
l_total: 1828,
|
||
l_ec: 30,
|
||
l_g1: 8,
|
||
l_g1_data: 122,
|
||
l_g2: 4,
|
||
l_g2_data: 123,
|
||
m_total: 1828,
|
||
m_ec: 28,
|
||
m_g1: 22,
|
||
m_g1_data: 45,
|
||
m_g2: 3,
|
||
m_g2_data: 46,
|
||
q_total: 1828,
|
||
q_ec: 30,
|
||
q_g1: 8,
|
||
q_g1_data: 23,
|
||
q_g2: 26,
|
||
q_g2_data: 24,
|
||
h_total: 1828,
|
||
h_ec: 30,
|
||
h_g1: 12,
|
||
h_g1_data: 15,
|
||
h_g2: 28,
|
||
h_g2_data: 16,
|
||
},
|
||
// 版本 28
|
||
VersionRow {
|
||
l_total: 1921,
|
||
l_ec: 30,
|
||
l_g1: 3,
|
||
l_g1_data: 117,
|
||
l_g2: 10,
|
||
l_g2_data: 118,
|
||
m_total: 1921,
|
||
m_ec: 28,
|
||
m_g1: 3,
|
||
m_g1_data: 45,
|
||
m_g2: 23,
|
||
m_g2_data: 46,
|
||
q_total: 1921,
|
||
q_ec: 30,
|
||
q_g1: 4,
|
||
q_g1_data: 24,
|
||
q_g2: 31,
|
||
q_g2_data: 25,
|
||
h_total: 1921,
|
||
h_ec: 30,
|
||
h_g1: 11,
|
||
h_g1_data: 15,
|
||
h_g2: 31,
|
||
h_g2_data: 16,
|
||
},
|
||
// 版本 29
|
||
VersionRow {
|
||
l_total: 2051,
|
||
l_ec: 30,
|
||
l_g1: 7,
|
||
l_g1_data: 116,
|
||
l_g2: 7,
|
||
l_g2_data: 117,
|
||
m_total: 2051,
|
||
m_ec: 28,
|
||
m_g1: 21,
|
||
m_g1_data: 45,
|
||
m_g2: 7,
|
||
m_g2_data: 46,
|
||
q_total: 2051,
|
||
q_ec: 30,
|
||
q_g1: 1,
|
||
q_g1_data: 23,
|
||
q_g2: 37,
|
||
q_g2_data: 24,
|
||
h_total: 2051,
|
||
h_ec: 30,
|
||
h_g1: 19,
|
||
h_g1_data: 15,
|
||
h_g2: 26,
|
||
h_g2_data: 16,
|
||
},
|
||
// 版本 30
|
||
VersionRow {
|
||
l_total: 2185,
|
||
l_ec: 30,
|
||
l_g1: 5,
|
||
l_g1_data: 115,
|
||
l_g2: 10,
|
||
l_g2_data: 116,
|
||
m_total: 2185,
|
||
m_ec: 28,
|
||
m_g1: 19,
|
||
m_g1_data: 47,
|
||
m_g2: 10,
|
||
m_g2_data: 48,
|
||
q_total: 2185,
|
||
q_ec: 30,
|
||
q_g1: 15,
|
||
q_g1_data: 24,
|
||
q_g2: 25,
|
||
q_g2_data: 25,
|
||
h_total: 2185,
|
||
h_ec: 30,
|
||
h_g1: 23,
|
||
h_g1_data: 15,
|
||
h_g2: 25,
|
||
h_g2_data: 16,
|
||
},
|
||
// 版本 31
|
||
VersionRow {
|
||
l_total: 2323,
|
||
l_ec: 30,
|
||
l_g1: 13,
|
||
l_g1_data: 115,
|
||
l_g2: 3,
|
||
l_g2_data: 116,
|
||
m_total: 2323,
|
||
m_ec: 28,
|
||
m_g1: 2,
|
||
m_g1_data: 46,
|
||
m_g2: 29,
|
||
m_g2_data: 47,
|
||
q_total: 2323,
|
||
q_ec: 30,
|
||
q_g1: 42,
|
||
q_g1_data: 24,
|
||
q_g2: 1,
|
||
q_g2_data: 25,
|
||
h_total: 2323,
|
||
h_ec: 30,
|
||
h_g1: 23,
|
||
h_g1_data: 15,
|
||
h_g2: 28,
|
||
h_g2_data: 16,
|
||
},
|
||
// 版本 32
|
||
VersionRow {
|
||
l_total: 2465,
|
||
l_ec: 30,
|
||
l_g1: 17,
|
||
l_g1_data: 115,
|
||
l_g2: 0,
|
||
l_g2_data: 0,
|
||
m_total: 2465,
|
||
m_ec: 28,
|
||
m_g1: 10,
|
||
m_g1_data: 46,
|
||
m_g2: 23,
|
||
m_g2_data: 47,
|
||
q_total: 2465,
|
||
q_ec: 30,
|
||
q_g1: 10,
|
||
q_g1_data: 24,
|
||
q_g2: 35,
|
||
q_g2_data: 25,
|
||
h_total: 2465,
|
||
h_ec: 30,
|
||
h_g1: 19,
|
||
h_g1_data: 15,
|
||
h_g2: 35,
|
||
h_g2_data: 16,
|
||
},
|
||
// 版本 33
|
||
VersionRow {
|
||
l_total: 2611,
|
||
l_ec: 30,
|
||
l_g1: 17,
|
||
l_g1_data: 115,
|
||
l_g2: 1,
|
||
l_g2_data: 116,
|
||
m_total: 2611,
|
||
m_ec: 28,
|
||
m_g1: 14,
|
||
m_g1_data: 46,
|
||
m_g2: 21,
|
||
m_g2_data: 47,
|
||
q_total: 2611,
|
||
q_ec: 30,
|
||
q_g1: 29,
|
||
q_g1_data: 24,
|
||
q_g2: 19,
|
||
q_g2_data: 25,
|
||
h_total: 2611,
|
||
h_ec: 30,
|
||
h_g1: 11,
|
||
h_g1_data: 15,
|
||
h_g2: 46,
|
||
h_g2_data: 16,
|
||
},
|
||
// 版本 34
|
||
VersionRow {
|
||
l_total: 2761,
|
||
l_ec: 30,
|
||
l_g1: 13,
|
||
l_g1_data: 115,
|
||
l_g2: 6,
|
||
l_g2_data: 116,
|
||
m_total: 2761,
|
||
m_ec: 28,
|
||
m_g1: 14,
|
||
m_g1_data: 46,
|
||
m_g2: 23,
|
||
m_g2_data: 47,
|
||
q_total: 2761,
|
||
q_ec: 30,
|
||
q_g1: 44,
|
||
q_g1_data: 24,
|
||
q_g2: 7,
|
||
q_g2_data: 25,
|
||
h_total: 2761,
|
||
h_ec: 30,
|
||
h_g1: 59,
|
||
h_g1_data: 16,
|
||
h_g2: 1,
|
||
h_g2_data: 17,
|
||
},
|
||
// 版本 35
|
||
VersionRow {
|
||
l_total: 2876,
|
||
l_ec: 30,
|
||
l_g1: 12,
|
||
l_g1_data: 121,
|
||
l_g2: 7,
|
||
l_g2_data: 122,
|
||
m_total: 2876,
|
||
m_ec: 28,
|
||
m_g1: 12,
|
||
m_g1_data: 47,
|
||
m_g2: 26,
|
||
m_g2_data: 48,
|
||
q_total: 2876,
|
||
q_ec: 30,
|
||
q_g1: 39,
|
||
q_g1_data: 24,
|
||
q_g2: 14,
|
||
q_g2_data: 25,
|
||
h_total: 2876,
|
||
h_ec: 30,
|
||
h_g1: 22,
|
||
h_g1_data: 15,
|
||
h_g2: 41,
|
||
h_g2_data: 16,
|
||
},
|
||
// 版本 36
|
||
VersionRow {
|
||
l_total: 3034,
|
||
l_ec: 30,
|
||
l_g1: 6,
|
||
l_g1_data: 121,
|
||
l_g2: 14,
|
||
l_g2_data: 122,
|
||
m_total: 3034,
|
||
m_ec: 28,
|
||
m_g1: 6,
|
||
m_g1_data: 47,
|
||
m_g2: 34,
|
||
m_g2_data: 48,
|
||
q_total: 3034,
|
||
q_ec: 30,
|
||
q_g1: 46,
|
||
q_g1_data: 24,
|
||
q_g2: 10,
|
||
q_g2_data: 25,
|
||
h_total: 3034,
|
||
h_ec: 30,
|
||
h_g1: 2,
|
||
h_g1_data: 15,
|
||
h_g2: 64,
|
||
h_g2_data: 16,
|
||
},
|
||
// 版本 37
|
||
VersionRow {
|
||
l_total: 3196,
|
||
l_ec: 30,
|
||
l_g1: 17,
|
||
l_g1_data: 122,
|
||
l_g2: 4,
|
||
l_g2_data: 123,
|
||
m_total: 3196,
|
||
m_ec: 28,
|
||
m_g1: 29,
|
||
m_g1_data: 46,
|
||
m_g2: 14,
|
||
m_g2_data: 47,
|
||
q_total: 3196,
|
||
q_ec: 30,
|
||
q_g1: 49,
|
||
q_g1_data: 24,
|
||
q_g2: 10,
|
||
q_g2_data: 25,
|
||
h_total: 3196,
|
||
h_ec: 30,
|
||
h_g1: 24,
|
||
h_g1_data: 15,
|
||
h_g2: 46,
|
||
h_g2_data: 16,
|
||
},
|
||
// 版本 38
|
||
VersionRow {
|
||
l_total: 3362,
|
||
l_ec: 30,
|
||
l_g1: 4,
|
||
l_g1_data: 122,
|
||
l_g2: 18,
|
||
l_g2_data: 123,
|
||
m_total: 3362,
|
||
m_ec: 28,
|
||
m_g1: 13,
|
||
m_g1_data: 46,
|
||
m_g2: 32,
|
||
m_g2_data: 47,
|
||
q_total: 3362,
|
||
q_ec: 30,
|
||
q_g1: 48,
|
||
q_g1_data: 24,
|
||
q_g2: 14,
|
||
q_g2_data: 25,
|
||
h_total: 3362,
|
||
h_ec: 30,
|
||
h_g1: 42,
|
||
h_g1_data: 15,
|
||
h_g2: 32,
|
||
h_g2_data: 16,
|
||
},
|
||
// 版本 39
|
||
VersionRow {
|
||
l_total: 3532,
|
||
l_ec: 30,
|
||
l_g1: 20,
|
||
l_g1_data: 117,
|
||
l_g2: 4,
|
||
l_g2_data: 118,
|
||
m_total: 3532,
|
||
m_ec: 28,
|
||
m_g1: 40,
|
||
m_g1_data: 47,
|
||
m_g2: 7,
|
||
m_g2_data: 48,
|
||
q_total: 3532,
|
||
q_ec: 30,
|
||
q_g1: 43,
|
||
q_g1_data: 24,
|
||
q_g2: 22,
|
||
q_g2_data: 25,
|
||
h_total: 3532,
|
||
h_ec: 30,
|
||
h_g1: 10,
|
||
h_g1_data: 15,
|
||
h_g2: 67,
|
||
h_g2_data: 16,
|
||
},
|
||
// 版本 40
|
||
VersionRow {
|
||
l_total: 3706,
|
||
l_ec: 30,
|
||
l_g1: 19,
|
||
l_g1_data: 118,
|
||
l_g2: 6,
|
||
l_g2_data: 119,
|
||
m_total: 3706,
|
||
m_ec: 28,
|
||
m_g1: 18,
|
||
m_g1_data: 47,
|
||
m_g2: 31,
|
||
m_g2_data: 48,
|
||
q_total: 3706,
|
||
q_ec: 30,
|
||
q_g1: 34,
|
||
q_g1_data: 24,
|
||
q_g2: 34,
|
||
q_g2_data: 25,
|
||
h_total: 3706,
|
||
h_ec: 30,
|
||
h_g1: 20,
|
||
h_g1_data: 15,
|
||
h_g2: 61,
|
||
h_g2_data: 16,
|
||
},
|
||
];
|
||
|
||
// 对齐图案中心位置表(每个版本的坐标数组)
|
||
static ALIGNMENT_POSITIONS: [&[u8]; 40] = [
|
||
&[], // v1 (无对齐图案)
|
||
&[6, 18], // v2
|
||
&[6, 22], // v3
|
||
&[6, 26], // v4
|
||
&[6, 30], // v5
|
||
&[6, 34], // v6
|
||
&[6, 22, 38], // v7
|
||
&[6, 24, 42], // v8
|
||
&[6, 26, 46], // v9
|
||
&[6, 28, 50], // v10
|
||
&[6, 30, 54], // v11
|
||
&[6, 32, 58], // v12
|
||
&[6, 34, 62], // v13
|
||
&[6, 26, 46, 66], // v14
|
||
&[6, 26, 48, 70], // v15
|
||
&[6, 26, 50, 74], // v16
|
||
&[6, 30, 54, 78], // v17
|
||
&[6, 30, 56, 82], // v18
|
||
&[6, 30, 58, 86], // v19
|
||
&[6, 34, 62, 90], // v20
|
||
&[6, 28, 50, 72, 94], // v21
|
||
&[6, 26, 50, 74, 98], // v22
|
||
&[6, 30, 54, 78, 102], // v23
|
||
&[6, 28, 54, 80, 106], // v24
|
||
&[6, 32, 58, 84, 110], // v25
|
||
&[6, 30, 58, 86, 114], // v26
|
||
&[6, 34, 62, 90, 118], // v27
|
||
&[6, 26, 50, 74, 98, 122], // v28
|
||
&[6, 30, 54, 78, 102, 126], // v29
|
||
&[6, 26, 52, 78, 104, 130], // v30
|
||
&[6, 30, 56, 82, 108, 134], // v31
|
||
&[6, 34, 60, 86, 112, 138], // v32
|
||
&[6, 30, 58, 86, 114, 142], // v33
|
||
&[6, 34, 62, 90, 118, 146], // v34
|
||
&[6, 30, 54, 78, 102, 126, 150], // v35
|
||
&[6, 24, 50, 76, 102, 128, 154], // v36
|
||
&[6, 28, 54, 80, 106, 132, 158], // v37
|
||
&[6, 32, 58, 84, 110, 136, 162], // v38
|
||
&[6, 26, 54, 82, 110, 138, 166], // v39
|
||
&[6, 30, 58, 86, 114, 142, 170], // v40
|
||
];
|
||
|
||
/// 获取某版本+级别的数据码字容量
|
||
fn init_capacity_table() -> [[u16; 4]; 40] {
|
||
let mut table = [[0u16; 4]; 40];
|
||
for v in 1..=40u8 {
|
||
let ver = Version(v);
|
||
let li: [EcLevel; 4] = [EcLevel::L, EcLevel::M, EcLevel::Q, EcLevel::H];
|
||
for (idx, &level) in li.iter().enumerate() {
|
||
let info = ver.ec_info(level);
|
||
let total_data: u16 = info.blocks.iter().map(|b| b.count * b.data_codewords).sum();
|
||
table[v as usize - 1][idx] = total_data;
|
||
}
|
||
}
|
||
table
|
||
}
|
||
|
||
pub fn get_data_capacity(version: Version, level: EcLevel) -> u16 {
|
||
static CAPACITY: OnceLock<[[u16; 4]; 40]> = OnceLock::new();
|
||
let cap = CAPACITY.get_or_init(init_capacity_table);
|
||
cap[version.0 as usize - 1][level as usize]
|
||
}
|
||
|
||
/// 自动选择最小版本:返回能容纳 data_bits 比特的最小版本
|
||
pub fn pick_version(data_bits: u16, level: EcLevel) -> Option<Version> {
|
||
for v in 1..=40 {
|
||
let cap_bits = get_data_capacity(Version(v), level) * 8;
|
||
if cap_bits >= data_bits {
|
||
return Some(Version(v));
|
||
}
|
||
}
|
||
None
|
||
}
|
||
|
||
#[cfg(test)]
|
||
mod tests {
|
||
use super::*;
|
||
|
||
#[test]
|
||
fn test_version_size() {
|
||
assert_eq!(Version(1).size(), 21);
|
||
assert_eq!(Version(40).size(), 177);
|
||
assert_eq!(Version(2).size(), 25);
|
||
}
|
||
|
||
#[test]
|
||
fn test_version_new_out_of_range() {
|
||
assert!(Version::new(0).is_none());
|
||
assert!(Version::new(41).is_none());
|
||
}
|
||
|
||
#[test]
|
||
fn test_pick_version_l() {
|
||
// Version 1 L 级: 19 数据码字 = 152 bits
|
||
let v = pick_version(152, EcLevel::L);
|
||
assert_eq!(v, Some(Version(1)));
|
||
}
|
||
|
||
#[test]
|
||
fn test_pick_version_none() {
|
||
// 超过 version 40 容量
|
||
let v = pick_version(30000, EcLevel::H);
|
||
assert!(v.is_none());
|
||
}
|
||
|
||
#[test]
|
||
fn test_ec_info_blocks() {
|
||
let info = Version(1).ec_info(EcLevel::M);
|
||
// Version 1 M: 1 block × 16 data codewords, 10 ec per block
|
||
assert_eq!(info.total_codewords, 26);
|
||
assert_eq!(info.ec_per_block, 10);
|
||
assert_eq!(info.blocks.len(), 2);
|
||
assert_eq!(info.blocks[0].count, 1);
|
||
assert_eq!(info.blocks[0].data_codewords, 16);
|
||
}
|
||
|
||
#[test]
|
||
fn test_indicator_bits() {
|
||
assert_eq!(EcLevel::L.indicator_bits(), 0b01);
|
||
assert_eq!(EcLevel::M.indicator_bits(), 0b00);
|
||
assert_eq!(EcLevel::Q.indicator_bits(), 0b11);
|
||
assert_eq!(EcLevel::H.indicator_bits(), 0b10);
|
||
}
|
||
}
|