use std::io::Cursor;
use image::ImageFormat;
use super::{Asset, Context, MediaCategory, ProcessesAssets, ProcessingError};
pub struct ImageResizeProcessor {
width: u32,
height: u32,
}
impl ImageResizeProcessor {
pub fn new(width: u32, height: u32) -> Self {
Self { width, height }
}
}
impl ProcessesAssets for ImageResizeProcessor {
fn process(&self, _context: &mut Context, asset: &mut Asset) -> Result<(), ProcessingError> {
if asset.media_type().category() != MediaCategory::Image {
return Ok(());
}
let asset_path = asset.path().clone();
let image_format = ImageFormat::from_path(asset_path.as_str()).map_err(|e| {
ProcessingError::Malformed {
message: e.to_string().into(),
}
})?;
let image_bytes = asset.as_mut_bytes()?;
let image =
image::load_from_memory(image_bytes).map_err(|e| ProcessingError::Malformed {
message: e.to_string().into(),
})?;
if image.width() <= self.width && image.height() <= self.height {
return Ok(());
}
tracing::trace!("image: {}", asset_path);
let image = image.resize(
self.width,
self.height,
image::imageops::FilterType::Lanczos3,
);
image_bytes.clear();
let mut cursor = Cursor::new(image_bytes);
image
.write_to(&mut cursor, image_format)
.map_err(|e| ProcessingError::Malformed {
message: e.to_string().into(),
})?;
Ok(())
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test_log::test]
#[test_log(default_log_filter = "debug")]
fn resizes_image() {
let _ = tracing_subscriber::fmt()
.with_max_level(tracing::Level::DEBUG)
.with_test_writer()
.try_init();
let source_bytes = std::fs::read("test/example.png").unwrap();
let mut asset = Asset::new("test/example.png".into(), source_bytes.clone());
let (width, height) = (300, 300);
ImageResizeProcessor { width, height }
.process(&mut Context::default(), &mut asset)
.unwrap();
let resized_image = image::load_from_memory(asset.as_bytes()).unwrap();
assert_eq!(width, resized_image.width());
assert_eq!(243, resized_image.height());
}
}