///|
fn choose_version(
segments : Array[Segment],
ec : EcLevel,
min_version : Int32,
max_version : Int32,
) -> Int32 raise QrError {
if min_version < 1 || min_version > 40 {
raise QrError::InvalidVersion(min_version)
}
if max_version < min_version || max_version > 40 {
raise QrError::InvalidVersion(max_version)
}
let mut chosen = 0
for v in min_version..<=max_version {
let bits = bits_needed(segments, v)
if chosen == 0 && bits <= data_capacity_bits(v, ec) {
chosen = v
}
}
if chosen == 0 {
raise QrError::DataTooLong(
needed=bits_needed(segments, max_version),
capacity=data_capacity_bits(max_version, ec),
version=max_version,
ec_level=ec,
)
}
chosen
}
///|
/// Splits data codewords into RS blocks, appends parity, and interleaves both.
///
/// 将数据码字拆分为 RS 块,追加校验字节,并交错排列。
fn interleave_blocks(
data : Array[Byte],
version : Int32,
ec : EcLevel,
) -> Array[Byte] {
let nblocks = block_count(version, ec)
let ecc_len = ecc_codewords(version, ec)
let raw_len = data.length()
let short_len = raw_len / nblocks
let num_short = nblocks - raw_len % nblocks
let blocks : Array[Array[Byte]] = []
let eccs : Array[Array[Byte]] = []
let mut offset = 0
for i in 0.. QrCode {
{
version_: Version(version),
ec_level_: ec,
mask_: mask,
size_: m.size,
modules_: m.modules.copy(),
}
}
///|
/// Encodes `text` as a QR Model 2 symbol.
///
/// 将 `text` 编码为 QR Model 2 符号。
///
/// `ec_level` defaults to M, version range to 1..40, mode is chosen
/// automatically, and the mask is selected by minimizing the Annex J penalty.
///
/// `ec_level` 默认为 M,版本范围为 1..40,模式自动选择,
/// 掩码通过最小化 Annex J 惩罚分选出。
///
/// # Example
/// ```mbt check
/// test "encode hello world" {
/// let qr = @core.encode("HELLO WORLD") // V1-M
/// assert_eq(qr.size(), 21)
/// assert_eq(qr.version().value(), 1)
/// }
/// ```
pub fn encode(
text : String,
ec_level~ : EcLevel = EcLevel::M,
min_version~ : Int32 = 1,
max_version~ : Int32 = 40,
mode? : Mode,
mask? : Mask,
) -> QrCode raise QrError {
let segments = match mode {
Some(m) => split_segments(text, mode=m)
None => split_segments(text)
}
let version = choose_version(segments, ec_level, min_version, max_version)
let capacity_bytes = data_codewords(version, ec_level)
let buf = BitBuffer::new()
for seg in segments {
append_segment(buf, seg, version)
}
buf.pad_to(capacity_bytes)
let codewords = interleave_blocks(buf.to_bytes(), version, ec_level)
let base = build_matrix(version, codewords)
match mask {
Some(m) => make_qr(version, ec_level, m, apply_mask(base, m, ec_level))
None => {
let (best, best_mask) = choose_best_mask(base, ec_level)
make_qr(version, ec_level, best_mask, best)
}
}
}