use qrcode::QrCode;
use crate::{CorrectionLevel, Error, Result};
pub const DEFAULT_MAX_MODULES: usize = 117;
pub fn qr_module_count(
message: &[u8],
correction: CorrectionLevel,
) -> Result<usize> {
let matrix = QrMatrix::encode(message, correction)?;
Ok(matrix.width())
}
pub fn check_qr_density(module_count: usize, max_modules: usize) -> Result<()> {
if module_count > max_modules {
Err(Error::QrCodeTooDense { module_count, max_modules })
} else {
Ok(())
}
}
pub struct QrMatrix {
modules: Vec<bool>,
width: usize,
}
impl QrMatrix {
pub fn encode(message: &[u8], correction: CorrectionLevel) -> Result<Self> {
let code = QrCode::with_error_correction_level(
message,
correction.to_qrcode(),
)
.map_err(|e| Error::QrEncode(e.to_string()))?;
let width = code.width();
let modules: Vec<bool> = code
.to_colors()
.into_iter()
.map(|c| c == qrcode::Color::Dark)
.collect();
Ok(Self { modules, width })
}
pub fn width(&self) -> usize { self.width }
pub fn is_dark(&self, col: usize, row: usize) -> bool {
self.modules[row * self.width + col]
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn encode_small() {
let m = QrMatrix::encode(b"HELLO", CorrectionLevel::Low).unwrap();
assert_eq!(m.width(), 21);
assert_eq!(m.modules.len(), 21 * 21);
}
#[test]
fn encode_ur_string() {
let ur = "UR:BYTES/HDCXDWINVEZM";
let m = QrMatrix::encode(ur.as_bytes(), CorrectionLevel::Low).unwrap();
assert!(m.width() >= 21);
}
}