use crate::{
BarcodeFormat, EncodeHints, Writer,
common::{BitMatrix, CharacterSet, Result},
exceptions::Exceptions,
};
use super::encoder::{AztecCode, aztec_encoder};
const MARGINS_SIZE: u32 = 0;
#[derive(Default)]
pub struct AztecWriter;
impl Writer for AztecWriter {
fn encode(
&self,
contents: &str,
format: &crate::BarcodeFormat,
width: i32,
height: i32,
) -> Result<crate::common::BitMatrix> {
self.encode_with_hints(contents, format, width, height, &EncodeHints::default())
}
fn encode_with_hints(
&self,
contents: &str,
format: &crate::BarcodeFormat,
width: i32,
height: i32,
hints: &EncodeHints,
) -> Result<crate::common::BitMatrix> {
let mut charset = None; let mut ecc_percent = aztec_encoder::DEFAULT_EC_PERCENT;
let mut layers = aztec_encoder::DEFAULT_AZTEC_LAYERS;
if let Some(cset_name) = &hints.CharacterSet {
if cset_name.to_lowercase() != "iso-8859-1" {
charset = CharacterSet::get_character_set_by_name(cset_name);
}
}
if let Some(ecc_level) = &hints.ErrorCorrection {
ecc_percent = ecc_level.parse().unwrap_or(23);
}
if let Some(az_layers) = hints.AztecLayers {
layers = az_layers;
}
let margins = if let Some(margin) = &hints.Margin {
margin
.parse::<u32>()
.map_err(|e| Exceptions::parse_with(format!("could not parse {margin}: {e}")))?
} else {
MARGINS_SIZE
};
encode(
contents,
*format,
width as u32,
height as u32,
margins,
charset,
ecc_percent,
layers,
)
}
}
#[allow(clippy::too_many_arguments)]
fn encode(
contents: &str,
format: BarcodeFormat,
width: u32,
height: u32,
margins: u32,
charset: Option<CharacterSet>,
ecc_percent: u32,
layers: i32,
) -> Result<BitMatrix> {
if format != BarcodeFormat::AZTEC {
return Err(Exceptions::illegal_argument_with(format!(
"can only encode AZTEC, but got {format:?}"
)));
}
let aztec = if let Some(cset) = charset {
aztec_encoder::encode_with_charset(contents, ecc_percent, layers, cset)?
} else {
aztec_encoder::encode(contents, ecc_percent, layers)?
};
renderRXingResult(&aztec, width, height, margins)
}
fn renderRXingResult(code: &AztecCode, width: u32, height: u32, margins: u32) -> Result<BitMatrix> {
let input = code.getMatrix();
let input_width = input.getWidth();
let input_height = input.getHeight();
let padded_width = input_width + (margins * 2);
let padded_height = input_height + (margins * 2);
let output_width = width.max(padded_width);
let output_height = height.max(padded_height);
let multiple = (output_width / padded_width).min(output_height / padded_height);
let left_padding = (output_width - (input_width * multiple)) / 2;
let top_padding = (output_height - (input_height * multiple)) / 2;
let mut output = BitMatrix::new(output_width, output_height)?;
let mut input_y = 0;
let mut output_y = top_padding;
while input_y < input_height {
let mut input_x = 0;
let mut output_x = left_padding;
while input_x < input_width {
if input.get(input_x, input_y) {
output.setRegion(output_x, output_y, multiple, multiple)?;
}
input_x += 1;
output_x += multiple;
}
input_y += 1;
output_y += multiple
}
Ok(output)
}