83 lines
2.1 KiB
Rust
83 lines
2.1 KiB
Rust
use std::fmt::Display;
|
|
|
|
use image::{DynamicImage, imageops::FilterType};
|
|
|
|
use crate::{pixeldim::PixelDim, transformers::ImageTransformer};
|
|
|
|
#[derive(Debug, Clone, PartialEq)]
|
|
pub struct MaxDimTransformer {
|
|
w: PixelDim,
|
|
h: PixelDim,
|
|
}
|
|
|
|
impl MaxDimTransformer {
|
|
pub fn new(w: PixelDim, h: PixelDim) -> Self {
|
|
Self { w, h }
|
|
}
|
|
|
|
fn target_dim(&self, img_width: u32, img_height: u32) -> (u32, u32) {
|
|
let max_width = match self.w {
|
|
PixelDim::Pixels(w) => Some(w),
|
|
PixelDim::WidthPercent(pct) => Some(((img_width as f32) * pct / 100.0) as u32),
|
|
PixelDim::HeightPercent(_) => None,
|
|
};
|
|
|
|
let max_height = match self.h {
|
|
PixelDim::Pixels(h) => Some(h),
|
|
PixelDim::HeightPercent(pct) => Some(((img_height as f32) * pct / 100.0) as u32),
|
|
PixelDim::WidthPercent(_) => None,
|
|
};
|
|
|
|
if max_width.map(|x| img_width <= x).unwrap_or(true)
|
|
&& max_height.map(|x| img_height <= x).unwrap_or(true)
|
|
{
|
|
return (img_width, img_height);
|
|
}
|
|
|
|
let width_ratio = max_width
|
|
.map(|x| x as f32 / img_width as f32)
|
|
.unwrap_or(1.0);
|
|
|
|
let height_ratio = max_height
|
|
.map(|x| x as f32 / img_height as f32)
|
|
.unwrap_or(1.0);
|
|
|
|
let ratio = width_ratio.min(height_ratio);
|
|
|
|
(
|
|
(img_width as f32 * ratio) as u32,
|
|
(img_height as f32 * ratio) as u32,
|
|
)
|
|
}
|
|
}
|
|
|
|
impl Display for MaxDimTransformer {
|
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
|
write!(f, "maxdim({},{})", self.w, self.h)
|
|
}
|
|
}
|
|
|
|
impl ImageTransformer for MaxDimTransformer {
|
|
fn parse_args(args: &str) -> Result<Self, String> {
|
|
let args: Vec<&str> = args.split(",").collect();
|
|
if args.len() != 2 {
|
|
return Err(format!("expected 2 args, got {}", args.len()));
|
|
}
|
|
|
|
let w = args[0].parse::<PixelDim>()?;
|
|
let h = args[1].parse::<PixelDim>()?;
|
|
|
|
Ok(Self { w, h })
|
|
}
|
|
|
|
fn transform(&self, input: &mut DynamicImage) {
|
|
let (img_width, img_height) = (input.width(), input.height());
|
|
let (target_width, target_height) = self.target_dim(img_width, img_height);
|
|
|
|
// Only resize if needed
|
|
if target_width != img_width || target_height != img_height {
|
|
*input = input.resize(target_width, target_height, FilterType::Lanczos3);
|
|
}
|
|
}
|
|
}
|