fast image operations
Diffstat (limited to 'src/scale/algorithms.rs')
-rw-r--r--src/scale/algorithms.rs113
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);