use image::{Bgr, Bgra, GenericImage, ImageBuffer, Luma, LumaA, Pixel, Primitive, Rgb, Rgba};
use crate::definitions::Image;
pub trait WithChannel<C: Primitive>: Pixel {
type Pixel: Pixel<Subpixel = C> + 'static;
}
pub type ChannelMap<Pix, Sub> = <Pix as WithChannel<Sub>>::Pixel;
impl<T, U> WithChannel<U> for Rgb<T>
where
T: Primitive + 'static,
U: Primitive + 'static,
{
type Pixel = Rgb<U>;
}
impl<T, U> WithChannel<U> for Rgba<T>
where
T: Primitive + 'static,
U: Primitive + 'static,
{
type Pixel = Rgba<U>;
}
impl<T, U> WithChannel<U> for Bgr<T>
where
T: Primitive + 'static,
U: Primitive + 'static,
{
type Pixel = Bgr<U>;
}
impl<T, U> WithChannel<U> for Bgra<T>
where
T: Primitive + 'static,
U: Primitive + 'static,
{
type Pixel = Bgra<U>;
}
impl<T, U> WithChannel<U> for Luma<T>
where
T: Primitive + 'static,
U: Primitive + 'static,
{
type Pixel = Luma<U>;
}
impl<T, U> WithChannel<U> for LumaA<T>
where
T: Primitive + 'static,
U: Primitive + 'static,
{
type Pixel = LumaA<U>;
}
pub fn map_subpixels<I, P, F, S>(image: &I, f: F) -> Image<ChannelMap<P, S>>
where
I: GenericImage<Pixel = P>,
P: WithChannel<S> + 'static,
S: Primitive + 'static,
F: Fn(P::Subpixel) -> S,
{
let (width, height) = image.dimensions();
let mut out: ImageBuffer<ChannelMap<P, S>, Vec<S>> = ImageBuffer::new(width, height);
for y in 0..height {
for x in 0..width {
let out_channels = out.get_pixel_mut(x, y).channels_mut();
for c in 0..P::CHANNEL_COUNT {
out_channels[c as usize] = f(unsafe {
*image
.unsafe_get_pixel(x, y)
.channels()
.get_unchecked(c as usize)
});
}
}
}
out
}
pub fn map_colors<I, P, Q, F>(image: &I, f: F) -> Image<Q>
where
I: GenericImage<Pixel = P>,
P: Pixel,
Q: Pixel + 'static,
F: Fn(P) -> Q,
{
let (width, height) = image.dimensions();
let mut out: ImageBuffer<Q, Vec<Q::Subpixel>> = ImageBuffer::new(width, height);
for y in 0..height {
for x in 0..width {
unsafe {
let pix = image.unsafe_get_pixel(x, y);
out.unsafe_put_pixel(x, y, f(pix));
}
}
}
out
}
pub fn map_colors2<I, J, P, Q, R, F>(image1: &I, image2: &J, f: F) -> Image<R>
where
I: GenericImage<Pixel = P>,
J: GenericImage<Pixel = Q>,
P: Pixel,
Q: Pixel,
R: Pixel + 'static,
F: Fn(P, Q) -> R,
{
assert_eq!(image1.dimensions(), image2.dimensions());
let (width, height) = image1.dimensions();
let mut out: ImageBuffer<R, Vec<R::Subpixel>> = ImageBuffer::new(width, height);
for y in 0..height {
for x in 0..width {
unsafe {
let p = image1.unsafe_get_pixel(x, y);
let q = image2.unsafe_get_pixel(x, y);
out.unsafe_put_pixel(x, y, f(p, q));
}
}
}
out
}
pub fn map_pixels<I, P, Q, F>(image: &I, f: F) -> Image<Q>
where
I: GenericImage<Pixel = P>,
P: Pixel,
Q: Pixel + 'static,
F: Fn(u32, u32, P) -> Q,
{
let (width, height) = image.dimensions();
let mut out: ImageBuffer<Q, Vec<Q::Subpixel>> = ImageBuffer::new(width, height);
for y in 0..height {
for x in 0..width {
unsafe {
let pix = image.unsafe_get_pixel(x, y);
out.unsafe_put_pixel(x, y, f(x, y, pix));
}
}
}
out
}
pub fn red_channel<I, C>(image: &I) -> Image<Luma<C>>
where
I: GenericImage<Pixel = Rgb<C>>,
C: Primitive + 'static,
{
map_colors(image, |p| Luma([p[0]]))
}
pub fn as_red_channel<I, C>(image: &I) -> Image<Rgb<C>>
where
I: GenericImage<Pixel = Luma<C>>,
C: Primitive + 'static,
{
map_colors(image, |p| {
let mut cs = [C::zero(); 3];
cs[0] = p[0];
Rgb(cs)
})
}
pub fn green_channel<I, C>(image: &I) -> Image<Luma<C>>
where
I: GenericImage<Pixel = Rgb<C>>,
C: Primitive + 'static,
{
map_colors(image, |p| Luma([p[1]]))
}
pub fn as_green_channel<I, C>(image: &I) -> Image<Rgb<C>>
where
I: GenericImage<Pixel = Luma<C>>,
C: Primitive + 'static,
{
map_colors(image, |p| {
let mut cs = [C::zero(); 3];
cs[1] = p[0];
Rgb(cs)
})
}
pub fn blue_channel<I, C>(image: &I) -> Image<Luma<C>>
where
I: GenericImage<Pixel = Rgb<C>>,
C: Primitive + 'static,
{
map_colors(image, |p| Luma([p[2]]))
}
pub fn as_blue_channel<I, C>(image: &I) -> Image<Rgb<C>>
where
I: GenericImage<Pixel = Luma<C>>,
C: Primitive + 'static,
{
map_colors(image, |p| {
let mut cs = [C::zero(); 3];
cs[2] = p[0];
Rgb(cs)
})
}