use image::{Luma, LumaA, Pixel, Primitive, Rgb, Rgba};
use crate::definitions::Image;
pub trait WithChannel<C: Primitive>: Pixel {
type Pixel: Pixel<Subpixel = C>;
}
pub type ChannelMap<Pix, Sub> = <Pix as WithChannel<Sub>>::Pixel;
impl<T, U> WithChannel<U> for Rgb<T>
where
Rgb<T>: Pixel<Subpixel = T>,
Rgb<U>: Pixel<Subpixel = U>,
T: Primitive,
U: Primitive,
{
type Pixel = Rgb<U>;
}
impl<T, U> WithChannel<U> for Rgba<T>
where
Rgba<T>: Pixel<Subpixel = T>,
Rgba<U>: Pixel<Subpixel = U>,
T: Primitive,
U: Primitive,
{
type Pixel = Rgba<U>;
}
impl<T, U> WithChannel<U> for Luma<T>
where
T: Primitive,
U: Primitive,
{
type Pixel = Luma<U>;
}
impl<T, U> WithChannel<U> for LumaA<T>
where
T: Primitive,
U: Primitive,
{
type Pixel = LumaA<U>;
}
pub fn map_subpixels<P, F, S>(image: &Image<P>, f: F) -> Image<ChannelMap<P, S>>
where
P: WithChannel<S>,
S: Primitive,
F: Fn(P::Subpixel) -> S,
{
Image::from_vec(
image.width(),
image.height(),
image.iter().map(|subpixel| f(*subpixel)).collect(),
)
.expect("of course the length is good, it's just a map")
}
#[doc=generate_mut_doc_comment!("map_subpixels")]
pub fn map_subpixels_mut<P, F>(image: &mut Image<P>, f: F)
where
P: Pixel,
F: Fn(P::Subpixel) -> P::Subpixel,
{
image
.iter_mut()
.for_each(|subpixel| *subpixel = f(*subpixel));
}
#[cfg(feature = "rayon")]
#[doc = generate_parallel_doc_comment!("map_subpixels")]
pub fn map_subpixels_parallel<P, F, S>(image: &Image<P>, f: F) -> Image<ChannelMap<P, S>>
where
P: WithChannel<S>,
P::Subpixel: Sync,
S: Primitive + Send,
F: Fn(P::Subpixel) -> S + Sync,
{
use rayon::iter::IntoParallelRefIterator;
use rayon::iter::ParallelIterator;
Image::from_vec(
image.width(),
image.height(),
image.par_iter().map(|subpixel| f(*subpixel)).collect(),
)
.expect("of course the length is good, it's just a map")
}
#[cfg(feature = "rayon")]
#[doc = generate_parallel_doc_comment!("map_subpixels_mut")]
pub fn map_subpixels_mut_parallel<P, F>(image: &mut Image<P>, f: F)
where
P: Pixel,
P::Subpixel: Send,
F: Fn(P::Subpixel) -> P::Subpixel + Sync,
{
use rayon::iter::IntoParallelRefMutIterator;
use rayon::iter::ParallelIterator;
image
.par_iter_mut()
.for_each(|subpixel| *subpixel = f(*subpixel));
}
pub fn map_pixels<P, Q, F>(image: &Image<P>, f: F) -> Image<Q>
where
P: Pixel,
Q: Pixel,
F: Fn(P) -> Q,
{
Image::from_vec(
image.width(),
image.height(),
image
.pixels()
.flat_map(|pixel| f(*pixel).channels().to_vec())
.collect(),
)
.expect("of course the length is good, it's just a map")
}
#[doc=generate_mut_doc_comment!("map_pixels")]
pub fn map_pixels_mut<P, F>(image: &mut Image<P>, f: F)
where
P: Pixel,
F: Fn(P) -> P,
{
image.pixels_mut().for_each(|pixel| *pixel = f(*pixel))
}
#[cfg(feature = "rayon")]
#[doc = generate_parallel_doc_comment!("map_pixels")]
pub fn map_pixels_parallel<P, Q, F>(image: &Image<P>, f: F) -> Image<Q>
where
P: Pixel + Sync,
P::Subpixel: Sync,
Q: Pixel,
Q::Subpixel: Send,
F: Fn(P) -> Q + Sync,
{
use rayon::iter::ParallelIterator;
Image::from_vec(
image.width(),
image.height(),
image
.par_pixels()
.flat_map(|pixel| f(*pixel).channels().to_vec())
.collect(),
)
.expect("of course the length is good, it's just a map")
}
#[cfg(feature = "rayon")]
#[doc = generate_parallel_doc_comment!("map_pixels_mut")]
pub fn map_pixels_mut_parallel<P, F>(image: &mut Image<P>, f: F)
where
P: Pixel + Sync + Send,
P::Subpixel: Sync + Send,
F: Fn(P) -> P + Sync,
{
use rayon::iter::ParallelIterator;
image.par_pixels_mut().for_each(|pixel| *pixel = f(*pixel));
}
pub fn map_enumerated_pixels<P, Q, F>(image: &Image<P>, f: F) -> Image<Q>
where
P: Pixel,
Q: Pixel,
F: Fn(u32, u32, P) -> Q,
{
Image::from_vec(
image.width(),
image.height(),
image
.enumerate_pixels()
.flat_map(|(x, y, pixel)| f(x, y, *pixel).channels().to_vec())
.collect(),
)
.expect("of course the length is good, it's just a map")
}
#[doc=generate_mut_doc_comment!("map_enumerated_pixels")]
pub fn map_enumerated_pixels_mut<P, F>(image: &mut Image<P>, f: F)
where
P: Pixel,
F: Fn(u32, u32, P) -> P,
{
image
.enumerate_pixels_mut()
.for_each(|(x, y, pixel)| *pixel = f(x, y, *pixel))
}
#[cfg(feature = "rayon")]
#[doc = generate_parallel_doc_comment!("map_enumerated_pixels")]
pub fn map_enumerated_pixels_parallel<P, Q, F>(image: &Image<P>, f: F) -> Image<Q>
where
P: Pixel + Sync,
P::Subpixel: Sync,
Q: Pixel,
Q::Subpixel: Send,
F: Fn(u32, u32, P) -> Q + Sync,
{
use rayon::iter::ParallelIterator;
Image::from_vec(
image.width(),
image.height(),
image
.par_enumerate_pixels()
.flat_map(|(x, y, pixel)| f(x, y, *pixel).channels().to_vec())
.collect(),
)
.expect("of course the length is good, it's just a map")
}
#[cfg(feature = "rayon")]
#[doc = generate_parallel_doc_comment!("map_enumerated_pixels_mut")]
pub fn map_enumerated_pixels_mut_parallel<P, F>(image: &mut Image<P>, f: F)
where
P: Pixel + Sync + Send,
P::Subpixel: Sync + Send,
F: Fn(u32, u32, P) -> P + Sync,
{
use rayon::iter::ParallelIterator;
image
.par_enumerate_pixels_mut()
.for_each(|(x, y, pixel)| *pixel = f(x, y, *pixel));
}
pub fn map_pixels2<P, Q, R, F>(image1: &Image<P>, image2: &Image<Q>, f: F) -> Image<R>
where
P: Pixel,
Q: Pixel,
R: Pixel,
F: Fn(P, Q) -> R,
{
Image::from_vec(
image1.width(),
image2.height(),
image1
.pixels()
.zip(image2.pixels())
.flat_map(|(pixel1, pixel2)| f(*pixel1, *pixel2).channels().to_vec())
.collect(),
)
.expect("of course the length is good, it's just a map")
}
pub fn into_red_channel<C>(image: &Image<Rgb<C>>) -> Image<Luma<C>>
where
Rgb<C>: Pixel<Subpixel = C>,
C: Primitive,
{
map_pixels(image, |p| Luma([p[0]]))
}
pub fn from_red_channel<C>(image: &Image<Luma<C>>) -> Image<Rgb<C>>
where
Rgb<C>: Pixel<Subpixel = C>,
C: Primitive,
{
map_pixels(image, |p| Rgb([p.0[0], C::zero(), C::zero()]))
}
pub fn into_green_channel<C>(image: &Image<Rgb<C>>) -> Image<Luma<C>>
where
Rgb<C>: Pixel<Subpixel = C>,
C: Primitive,
{
map_pixels(image, |p| Luma([p[1]]))
}
pub fn from_green_channel<C>(image: &Image<Luma<C>>) -> Image<Rgb<C>>
where
Rgb<C>: Pixel<Subpixel = C>,
C: Primitive,
{
map_pixels(image, |p| Rgb([C::zero(), p.0[0], C::zero()]))
}
pub fn into_blue_channel<C>(image: &Image<Rgb<C>>) -> Image<Luma<C>>
where
Rgb<C>: Pixel<Subpixel = C>,
C: Primitive,
{
map_pixels(image, |p| Luma([p[2]]))
}
pub fn from_blue_channel<C>(image: &Image<Luma<C>>) -> Image<Rgb<C>>
where
Rgb<C>: Pixel<Subpixel = C>,
C: Primitive,
{
map_pixels(image, |p| Rgb([C::zero(), C::zero(), p.0[0]]))
}