use crate::*;
use bitvec::prelude::*;
pub struct QrBuilder {
pub version: Version,
pub mask: Option<Mask>,
pub ecl: ECLevel,
pub mode: Mode,
pub matrix: Matrix,
}
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub enum Error {
UnsupportedMode,
MessageTooLong,
IncompleteBuilder,
}
impl QrBuilder {
pub fn new() -> QrBuilder {
QrBuilder {
version: Version::new(3),
mask: None,
ecl: ECLevel::L,
mode: Mode::Byte,
matrix: Matrix::new(0),
}
}
pub fn version(mut self, v: Version) -> Self {
self.matrix = Matrix::new(v.size());
self.version = v;
self
}
pub fn mask(mut self, mask: Mask) -> Self {
self.mask = Some(mask);
self
}
pub fn ecl(mut self, ecl: ECLevel) -> Self {
self.ecl = ecl;
self
}
pub fn mode(mut self, mode: Mode) -> Self {
self.mode = mode;
self
}
pub fn into(mut self, s: &str) -> Result<Qr, Error> {
self.add_all(s)?;
self.into_qr()
}
pub fn into_qr(self) -> Result<Qr, Error> {
if !self.complete() {
return Err(Error::IncompleteBuilder);
}
Ok(Qr {
matrix: self.matrix,
version: self.version,
ecl: self.ecl,
mode: self.mode,
mask: self.mask.unwrap(),
})
}
pub fn add_all(&mut self, s: &str) -> Result<(), Error> {
self.ensure_settings()?;
self.add_fun_patterns();
self.add_data(s)?;
self.mask_data();
self.add_info();
Ok(())
}
pub fn add_fun_patterns(&mut self) {
self.add_finders();
self.add_alignments();
self.add_timing_patterns();
self.add_dark_module();
self.add_reserved_areas();
}
pub fn add_data(&mut self, s: &str) -> Result<(), Error> {
self.ensure_settings()?;
let version = self.version;
let mode = self.mode;
let v = data::encode_with_mode(s, mode, version);
let v = ec::add(v, self.version);
self.add_raw_data(&v);
Ok(())
}
pub fn add_raw_data(&mut self, v: &BitVec<Lsb0, u8>) {
let mut vi = 0;
for (x, y) in ZigZagIt::new(self.matrix.size) {
if self.matrix.is_fun(x, y) {
continue;
}
self.matrix.set_data(x, y, v[vi]);
vi += 1;
}
assert_eq!(vi, v.len());
}
pub fn mask_data(&mut self) {
if let Some(mask) = self.mask {
self.mask_with(mask);
} else {
self.mask_best();
}
}
pub fn mask_best(&mut self) {
let (mask, masked) = mask::mask(&self.matrix);
self.mask = Some(mask);
self.matrix = masked;
}
pub fn mask_with(&mut self, mask: Mask) {
self.mask = Some(mask);
self.matrix = mask::apply_mask(mask, &self.matrix);
}
pub fn add_info(&mut self) {
self.add_format_info();
}
pub fn add_format_info(&mut self) {
let format = info::format_info(self.mask.unwrap());
self.add_format(&format);
}
fn complete(&self) -> bool {
if self.mask.is_none() {
return false;
}
if self.matrix.size == 0 {
return false;
}
self.matrix.complete()
}
fn ensure_settings(&mut self) -> Result<(), Error> {
if self.matrix.size == 0 {
self.matrix = Matrix::new(self.version.size());
}
Ok(())
}
fn add_finders(&mut self) {
let size = self.matrix.size;
self.add_finder(0, 0);
self.add_separator(0, 7, 7, 7);
self.add_separator(7, 0, 7, 7);
self.add_finder(size - 7, 0);
self.add_separator(size - 8, 7, size - 1, 7);
self.add_separator(size - 8, 0, size - 8, 7);
self.add_finder(0, size - 7);
self.add_separator(0, size - 8, 7, size - 8);
self.add_separator(7, size - 8, 7, size - 1);
}
fn add_finder(&mut self, x: usize, y: usize) {
self.matrix.set_square(x, y, 7, Module::Function(true));
self.matrix
.set_square_outline(x + 1, y + 1, 5, Module::Function(false));
}
fn add_separator(&mut self, x0: usize, y0: usize, x1: usize, y1: usize) {
for a in x0..x1 + 1 {
for b in y0..y1 + 1 {
self.matrix.set(a, b, Module::Function(false));
}
}
}
fn add_alignments(&mut self) {
let locations = &[6, 22];
for x in locations.iter() {
for y in locations.iter() {
self.try_add_alignment(*x, *y);
}
}
}
fn try_add_alignment(&mut self, cx: usize, cy: usize) {
let x = cx - 2;
let y = cy - 2;
if !self.matrix.any_in_square(x, y, 4) {
self.matrix.set_square(x, y, 5, Module::Function(true));
self.matrix
.set_square_outline(x + 1, y + 1, 3, Module::Function(false));
}
}
fn add_timing_patterns(&mut self) {
let offset = 6;
for i in offset..self.matrix.size - offset {
let v = i % 2 == 0;
self.set_timing(i, offset, v);
self.set_timing(offset, i, v);
}
}
fn set_timing(&mut self, x: usize, y: usize, v: bool) {
if self.matrix.is_fun(x, y) {
assert_eq!(self.matrix.is_dark(x, y), v, "timing overlap {},{}", x, y);
}
self.matrix.set(x, y, Module::Function(v));
}
fn add_dark_module(&mut self) {
let (x, y) = self.version.dark_module_pos();
self.matrix.set(x, y, Module::Function(true));
}
fn add_reserved_areas(&mut self) {
let size = self.matrix.size;
self.reserve_rect(0, 8, 5, 8);
self.reserve_rect(7, 8, 8, 8);
self.reserve_rect(8, 0, 8, 5);
self.reserve_rect(8, 7, 8, 7);
self.reserve_rect(size - 8, 8, size - 1, 8);
self.reserve_rect(8, size - 7, 8, size - 1);
if self.version.extra_version_areas() {
self.reserve_rect(0, size - 11, 5, size - 9);
self.reserve_rect(size - 11, 0, size - 9, 5);
}
}
fn reserve_rect(&mut self, x0: usize, y0: usize, x1: usize, y1: usize) {
assert!(!self.matrix.any_in_rect(x0, y0, x1, y1));
self.matrix.set_rect(x0, y0, x1, y1, Module::Reserved);
}
fn add_format(&mut self, bv: &BitVec<Lsb0, u8>) {
assert_eq!(bv.len(), 15);
let size = self.matrix.size;
let mut iter = bv.iter();
for x in 0..8 {
if x == 6 {
continue;
}
self.matrix.set_fun(x, 8, *iter.next().unwrap());
}
for y in (0..9).rev() {
if y == 6 {
continue;
}
self.matrix.set_fun(8, y, *iter.next().unwrap());
}
assert_eq!(iter.next(), None);
iter = bv.iter();
for y in (size - 7..size).rev() {
self.matrix.set_fun(8, y, *iter.next().unwrap());
}
for x in (size - 8)..size {
self.matrix.set_fun(x, 8, *iter.next().unwrap());
}
assert_eq!(iter.next(), None);
}
pub fn to_dbg_string(&self) -> String {
rendercommons::to_dbg_string(&self.matrix)
}
}
struct ZigZagIt {
size: usize,
horizontal_next: bool,
upwards: bool,
x: usize,
y: usize,
valid: bool,
}
impl ZigZagIt {
fn new(size: usize) -> Self {
Self {
size: size,
horizontal_next: true,
upwards: true,
x: size - 1,
y: size - 1,
valid: true,
}
}
fn advance(&mut self) {
if self.horizontal_next {
self.move_horizontally();
} else {
self.move_vertically();
}
}
fn move_horizontally(&mut self) {
match self.x {
0 => self.valid = false,
6 => self.x -= 2,
_ => self.x -= 1,
}
self.horizontal_next = false;
}
fn move_vertically(&mut self) {
if (self.upwards && self.y == 0) || (!self.upwards && self.y == self.size - 1) {
self.upwards = !self.upwards;
self.move_horizontally();
} else {
if self.upwards {
self.y -= 1;
} else {
self.y += 1;
}
self.x += 1;
}
self.horizontal_next = true;
}
}
impl Iterator for ZigZagIt {
type Item = (usize, usize);
fn next(&mut self) -> Option<Self::Item> {
if !self.valid {
return None;
}
let res = Some((self.x, self.y));
self.advance();
res
}
}