pub mod config;
use crate::{Config, Result, Template, masked_rng::MaskedRng, template::chunk::Marker};
use rand::Rng;
#[derive(Debug)]
pub struct ImageGenerator<'t> {
template: &'t Template,
}
impl ImageGenerator<'_> {
#[allow(clippy::cast_possible_truncation)]
#[allow(clippy::cast_precision_loss)]
#[allow(clippy::cast_sign_loss)]
pub fn emit<T: Rng>(&self, mut config: Config<T>) -> Result<Vec<u8>> {
let template = self.template.choose(&mut config.rng)?;
let mut bytes = Vec::with_capacity(template.minimum_size);
let mut masked_rng: MaskedRng<T, 0x6d6d_6d6d_6d6d_6d6d> = config.rng.into();
for chunk in &template.chunks {
bytes.extend(&chunk.data);
if chunk.remaining > 0 {
let size = masked_rng.random_range(
chunk.remaining
..=(chunk.remaining as f64 * config.options.size_variance) as usize,
);
let mut garbage = vec![0; size];
masked_rng.fill_bytes(&mut garbage);
bytes.append(&mut garbage);
}
}
if let Some(comment) = &config.options.comment {
bytes.extend(Marker::COM.to_be_bytes());
bytes.extend(((comment.len() + 2) as u16).to_be_bytes());
bytes.extend(comment.as_bytes());
}
bytes.extend(Marker::EOI.to_be_bytes());
Ok(bytes)
}
}
impl<'t> From<&'t Template> for ImageGenerator<'t> {
fn from(template: &'t Template) -> Self {
Self { template }
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn parse_generated_image() {
let source = std::fs::read("benches/data/1024x1024.jpg").unwrap();
let template = Template::try_from(source).unwrap();
let image = ImageGenerator::from(&template)
.emit(Config::default())
.unwrap();
assert!(
Template::try_from(image).is_ok(),
"Generated image could not be parsed back"
);
}
}