use crate::convolution::{HorizontalFilterPass, VerticalConvolutionPass};
use crate::image_store::CheckStoreDensity;
use crate::math::WeightsGenerator;
use crate::plan::superresolution::plan_intermediate_sizes;
use crate::plan::supersampling::{supersampling_intermediate_size, supersampling_prefilter};
use crate::plan::{MultiStepResamplePlan, ResampleNearestPlan};
use crate::{
ImageSize, ImageStore, ImageStoreMut, PicScaleError, Resampling, ResamplingFunction, Scaler,
};
use std::fmt::Debug;
use std::marker::PhantomData;
use std::sync::Arc;
pub(crate) struct DefaultPlanner {}
impl DefaultPlanner {
fn plan_multi_step_upscale_simple<T, W, const N: usize>(
scaler: &Scaler,
source_size: ImageSize,
destination_size: ImageSize,
bit_depth: usize,
intermediates: &[ImageSize],
) -> Result<Arc<Resampling<T, N>>, PicScaleError>
where
T: Clone + Copy + Debug + Send + Sync + Default + WeightsGenerator<W> + 'static,
for<'a> ImageStore<'a, T, N>:
VerticalConvolutionPass<T, W, N> + HorizontalFilterPass<T, W, N>,
for<'a> ImageStoreMut<'a, T, N>: CheckStoreDensity,
{
let mut steps: Vec<Arc<Resampling<T, N>>> = Vec::new();
let mut prev_size = source_size;
for &next_size in intermediates
.iter()
.chain(std::iter::once(&destination_size))
{
let sub_plan =
scaler.build_single_step_plan::<T, W, N>(prev_size, next_size, bit_depth)?;
steps.push(sub_plan);
prev_size = next_size;
}
Ok(Arc::new(MultiStepResamplePlan::new(
steps,
source_size,
destination_size,
)))
}
fn plan_supersampling_simple<T, W, const N: usize>(
scaler: &Scaler,
source_size: ImageSize,
destination_size: ImageSize,
bit_depth: usize,
prefilter: ResamplingFunction,
) -> Result<Arc<Resampling<T, N>>, PicScaleError>
where
T: Clone + Copy + Debug + Send + Sync + Default + WeightsGenerator<W> + 'static,
for<'a> ImageStore<'a, T, N>:
VerticalConvolutionPass<T, W, N> + HorizontalFilterPass<T, W, N>,
for<'a> ImageStoreMut<'a, T, N>: CheckStoreDensity,
{
let intermediate = supersampling_intermediate_size(source_size, destination_size);
let pre_scaler = Scaler {
function: prefilter,
threading_policy: scaler.threading_policy,
workload_strategy: scaler.workload_strategy,
multi_step_upscaling: false,
supersampling: false,
};
let pre_plan =
pre_scaler.build_single_step_plan::<T, W, N>(source_size, intermediate, bit_depth)?;
let quality_plan =
scaler.build_single_step_plan::<T, W, N>(intermediate, destination_size, bit_depth)?;
Ok(Arc::new(MultiStepResamplePlan::new(
vec![pre_plan, quality_plan],
source_size,
destination_size,
)))
}
pub(crate) fn plan_generic_resize<T, W, const N: usize>(
scaler: &Scaler,
source_size: ImageSize,
destination_size: ImageSize,
bit_depth: usize,
) -> Result<Arc<Resampling<T, N>>, PicScaleError>
where
T: Clone + Copy + Debug + Send + Sync + Default + WeightsGenerator<W> + 'static,
for<'a> ImageStore<'a, T, N>:
VerticalConvolutionPass<T, W, N> + HorizontalFilterPass<T, W, N>,
for<'a> ImageStoreMut<'a, T, N>: CheckStoreDensity,
{
if scaler.function == ResamplingFunction::Nearest {
return Ok(Arc::new(ResampleNearestPlan {
source_size,
target_size: destination_size,
threading_policy: scaler.threading_policy,
_phantom_data: PhantomData,
}));
}
let is_upscale = destination_size.width >= source_size.width
&& destination_size.height >= source_size.height;
if scaler.multi_step_upscaling && is_upscale {
let intermediates =
plan_intermediate_sizes(source_size, destination_size, scaler.function);
if !intermediates.is_empty() {
return Self::plan_multi_step_upscale_simple::<T, W, N>(
scaler,
source_size,
destination_size,
bit_depth,
&intermediates,
);
}
}
let is_downscale = destination_size.width <= source_size.width
&& destination_size.height <= source_size.height;
if scaler.supersampling && is_downscale {
let ratio_w = source_size.width as f64 / destination_size.width as f64;
let ratio_h = source_size.height as f64 / destination_size.height as f64;
if let Some(prefilter) = supersampling_prefilter(ratio_w, ratio_h) {
let intermediate = supersampling_intermediate_size(source_size, destination_size);
if intermediate.width < source_size.width
|| intermediate.height < source_size.height
{
return Self::plan_supersampling_simple::<T, W, N>(
scaler,
source_size,
destination_size,
bit_depth,
prefilter,
);
}
}
}
scaler.build_single_step_plan::<T, W, N>(source_size, destination_size, bit_depth)
}
}