palette/blend/blend_with.rs
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89
use crate::{stimulus::Stimulus, Alpha};
use super::{BlendFunction, PreAlpha, Premultiply};
/// Blending with a custom blend function.
///
/// This is a convenience trait that makes it possible to use [`BlendFunction`]
/// via a method on the source color. This makes custom blending more similar to
/// how the [`Compose`][super::Compose] and [`Blend`][super::Blend] are used,
/// including automatic pre-multiplication.
pub trait BlendWith {
/// The base color type of `Self`.
type Color: Premultiply;
/// Blend self, as the source color, with `destination`, using
/// `blend_function`. Anything that implements [`BlendFunction`] is
/// acceptable, including functions and closures.
///
/// ```
/// use palette::{LinSrgb, LinSrgba};
/// use palette::blend::{BlendWith, PreAlpha};
///
/// type PreRgba = PreAlpha<LinSrgb<f32>>;
///
/// fn blend_mode(a: PreRgba, b: PreRgba) -> PreRgba {
/// PreAlpha {
/// color: LinSrgb::new(a.red * b.green, a.green * b.blue, a.blue * b.red),
/// alpha: a.alpha * b.alpha,
/// }
/// }
///
/// let a = LinSrgba::new(0.2, 0.5, 0.1, 0.8);
/// let b = LinSrgba::new(0.6, 0.3, 0.5, 0.1);
/// let c = a.blend_with(b, blend_mode);
/// ```
#[must_use]
fn blend_with<F>(self, destination: Self, blend_function: F) -> Self
where
F: BlendFunction<Self::Color>;
}
impl<C> BlendWith for PreAlpha<C>
where
C: Premultiply,
{
type Color = C;
#[inline]
fn blend_with<F>(self, other: Self, blend_function: F) -> Self
where
F: BlendFunction<Self::Color>,
{
blend_function.apply_to(self, other)
}
}
impl<C> BlendWith for Alpha<C, C::Scalar>
where
C: Premultiply,
{
type Color = C;
fn blend_with<F>(self, destination: Self, blend_function: F) -> Self
where
F: crate::blend::BlendFunction<Self::Color>,
{
self.premultiply()
.blend_with(destination.premultiply(), blend_function)
.unpremultiply()
}
}
impl<C> BlendWith for C
where
C: Premultiply,
C::Scalar: Stimulus,
{
type Color = C;
fn blend_with<F>(self, other: Self, blend_function: F) -> Self
where
F: BlendFunction<Self::Color>,
{
PreAlpha::new_opaque(self)
.blend_with(PreAlpha::new_opaque(other), blend_function)
.unpremultiply()
.color
}
}