fast image operations
Diffstat (limited to 'src/scale/algorithms.rs')
| -rw-r--r-- | src/scale/algorithms.rs | 113 |
1 files changed, 113 insertions, 0 deletions
diff --git a/src/scale/algorithms.rs b/src/scale/algorithms.rs new file mode 100644 index 0000000..eaec38c --- /dev/null +++ b/src/scale/algorithms.rs @@ -0,0 +1,113 @@ +use super::{traits::*, *}; +use std::num::NonZeroU32; + +/// [Nearest Neighbor](https://en.wikipedia.org/wiki/Nearest-neighbor_interpolation) image scaling algorithm. +pub struct Nearest; + +impl ScalingAlgorithm for Nearest { + /// Can be used on non opaque too! (Nearest is special like that). + fn scale_opaque<const N: usize>( + i: Image<&[u8], N>, + w: NonZeroU32, + h: NonZeroU32, + ) -> Image<std::boxed::Box<[u8]>, N> + where + ChannelCount<N>: ToImageView<N>, + { + let mut dst = fr::Image::new(w, h); + // SAFETY: swear, the pixel types are the same + unsafe { + fr::Resizer::new(fr::ResizeAlg::Nearest) + .resize(&ChannelCount::<N>::wrap(i), &mut dst.view_mut()) + }; + + // SAFETY: ctor + unsafe { Image::new(dst.width(), dst.height(), dst.into_vec().into()) } + } + + #[inline] + fn scale_transparent<const N: usize>( + i: Image<&mut [u8], N>, + w: NonZeroU32, + h: NonZeroU32, + ) -> Image<std::boxed::Box<[u8]>, N> + where + ChannelCount<N>: AlphaDiv<N>, + { + Self::scale_opaque(i.as_ref(), w, h) + } +} + +macro_rules! alg { + ($for:ident) => { + impl ScalingAlgorithm for $for { + fn scale_opaque<const N: usize>( + i: Image<&[u8], N>, + w: NonZeroU32, + h: NonZeroU32, + ) -> Image<std::boxed::Box<[u8]>, N> + where + ChannelCount<N>: ToImageView<N>, + { + let mut dst = fr::Image::new(w, h); + // SAFETY: swear, the pixel types are the same + unsafe { + fr::Resizer::new(fr::ResizeAlg::Convolution(fr::FilterType::$for)) + .resize(&ChannelCount::<N>::wrap(i), &mut dst.view_mut()) + }; + + // SAFETY: ctor + unsafe { Image::new(dst.width(), dst.height(), dst.into_vec().into()) } + } + + fn scale_transparent<const N: usize>( + i: Image<&mut [u8], N>, + w: NonZeroU32, + h: NonZeroU32, + ) -> Image<std::boxed::Box<[u8]>, N> + where + ChannelCount<N>: AlphaDiv<N>, + { + let mut dst = fr::Image::new(w, h); + // SAFETY: yes + unsafe { + fr::Resizer::new(fr::ResizeAlg::Convolution(fr::FilterType::$for)) + .resize(&ChannelCount::<N>::handle(i).view(), &mut dst.view_mut()) + } + + ChannelCount::<N>::unhandle(&mut dst); + + // SAFETY: ctor + unsafe { Image::new(dst.width(), dst.height(), dst.into_vec().into()) } + } + } + }; +} + +/// [Lanczos](https://en.wikipedia.org/wiki/Lanczos_resampling) scaling with a filter size (*a*) of 3. +pub struct Lanczos3 {} +alg!(Lanczos3); + +/// [Catmull-Rom](https://en.wikipedia.org/wiki/Centripetal_Catmull%E2%80%93Rom_spline) bicubic filtering. +pub struct CatmullRom {} +alg!(CatmullRom); + +/// Linear interpolation. +pub struct Bilinear {} +alg!(Bilinear); + +/// The opposite of [`Nearest`]. +pub struct Box {} +alg!(Box); + +/// Hamming filtering has the same performance as a [`Bilinear`] filter, while +/// providing image (downscaling) quality comparable to bicubic filters like +/// [`CatmullRom`] or [`Mitchell`]. Creates a sharper image than [`Bilinear`] filtering, +/// and doesn't have dislocations on local level like [`Box`] suffers from. +/// Not recommended for upscaling. +pub struct Hamming {} +alg!(Hamming); + +/// [Mitchell–Netravali](https://en.wikipedia.org/wiki/Mitchell%E2%80%93Netravali_filters) bicubic filtering. +pub struct Mitchell {} +alg!(Mitchell); |