palette/blend/
compose.rs

1use crate::{
2    cast::ArrayCast,
3    clamp,
4    num::{Arithmetics, Clamp, One, Real, Zero},
5    stimulus::Stimulus,
6    Alpha,
7};
8
9use super::{blend_alpha, zip_colors, PreAlpha, Premultiply};
10
11/// The Porter Duff composition operators, [as described by
12/// W3C](https://www.w3.org/TR/compositing-1/#porterduffcompositingoperators).
13///
14/// This set of operators exclude the variants where source and destination are
15/// swapped, as well as the "clear", "copy" and "destination" operators. Those
16/// can easily be achieved using other means.
17pub trait Compose {
18    /// Place `self` over `other`. This is the good old common alpha composition
19    /// equation.
20    #[must_use]
21    fn over(self, other: Self) -> Self;
22
23    /// Results in the parts of `self` that overlaps the visible parts of
24    /// `other`.
25    #[must_use]
26    fn inside(self, other: Self) -> Self;
27
28    /// Results in the parts of `self` that lies outside the visible parts of
29    /// `other`.
30    #[must_use]
31    fn outside(self, other: Self) -> Self;
32
33    /// Place `self` over only the visible parts of `other`.
34    #[must_use]
35    fn atop(self, other: Self) -> Self;
36
37    /// Results in either `self` or `other`, where they do not overlap.
38    #[must_use]
39    fn xor(self, other: Self) -> Self;
40
41    /// Add `self` and `other`. This uses the alpha component to regulate the
42    /// effect, so it's not just plain component wise addition.
43    #[must_use]
44    fn plus(self, other: Self) -> Self;
45}
46
47impl<C, T, const N: usize> Compose for PreAlpha<C>
48where
49    C: ArrayCast<Array = [T; N]> + Premultiply<Scalar = T>,
50    T: Real + Zero + One + Arithmetics + Clamp + Clone,
51{
52    #[inline]
53    fn over(self, mut other: Self) -> Self {
54        for (src, dst) in zip_colors(self.color, &mut other.color) {
55            *dst = src + (T::one() - &self.alpha) * &*dst;
56        }
57
58        other.alpha = blend_alpha(self.alpha, other.alpha);
59
60        other
61    }
62
63    #[inline]
64    fn inside(self, mut other: Self) -> Self {
65        for (src, dst) in zip_colors(self.color, &mut other.color) {
66            *dst = src * &other.alpha;
67        }
68
69        other.alpha = clamp(self.alpha * other.alpha, T::zero(), T::one());
70
71        other
72    }
73
74    #[inline]
75    fn outside(self, mut other: Self) -> Self {
76        for (src, dst) in zip_colors(self.color, &mut other.color) {
77            *dst = src * (T::one() - &other.alpha);
78        }
79
80        other.alpha = clamp(self.alpha * (T::one() - other.alpha), T::zero(), T::one());
81
82        other
83    }
84
85    #[inline]
86    fn atop(self, mut other: Self) -> Self {
87        for (src, dst) in zip_colors(self.color, &mut other.color) {
88            *dst = src * &other.alpha + (T::one() - &self.alpha) * &*dst;
89        }
90
91        other.alpha = clamp(other.alpha, T::zero(), T::one());
92
93        other
94    }
95
96    #[inline]
97    fn xor(self, mut other: Self) -> Self {
98        let two = || T::one() + T::one();
99
100        for (src, dst) in zip_colors(self.color, &mut other.color) {
101            *dst = src * (T::one() - &other.alpha) + (T::one() - &self.alpha) * &*dst;
102        }
103
104        other.alpha = clamp(
105            self.alpha.clone() + &other.alpha - two() * self.alpha * other.alpha,
106            T::zero(),
107            T::one(),
108        );
109
110        other
111    }
112
113    #[inline]
114    fn plus(self, mut other: Self) -> Self {
115        for (src, dst) in zip_colors(self.color, &mut other.color) {
116            *dst = src + &*dst;
117        }
118
119        other.alpha = clamp(self.alpha + other.alpha, T::zero(), T::one());
120
121        other
122    }
123}
124
125impl<C> Compose for Alpha<C, C::Scalar>
126where
127    C: Premultiply,
128    PreAlpha<C>: Compose,
129{
130    #[inline]
131    fn over(self, other: Self) -> Self {
132        self.premultiply().over(other.premultiply()).unpremultiply()
133    }
134
135    #[inline]
136    fn inside(self, other: Self) -> Self {
137        self.premultiply()
138            .inside(other.premultiply())
139            .unpremultiply()
140    }
141
142    #[inline]
143    fn outside(self, other: Self) -> Self {
144        self.premultiply()
145            .outside(other.premultiply())
146            .unpremultiply()
147    }
148
149    #[inline]
150    fn atop(self, other: Self) -> Self {
151        self.premultiply().atop(other.premultiply()).unpremultiply()
152    }
153
154    #[inline]
155    fn xor(self, other: Self) -> Self {
156        self.premultiply().xor(other.premultiply()).unpremultiply()
157    }
158
159    #[inline]
160    fn plus(self, other: Self) -> Self {
161        self.premultiply().plus(other.premultiply()).unpremultiply()
162    }
163}
164
165impl<C> Compose for C
166where
167    C: Premultiply,
168    C::Scalar: Stimulus,
169    PreAlpha<C>: Compose,
170{
171    #[inline]
172    fn over(self, other: Self) -> Self {
173        PreAlpha::new_opaque(self)
174            .over(PreAlpha::new_opaque(other))
175            .unpremultiply()
176            .color
177    }
178
179    #[inline]
180    fn inside(self, other: Self) -> Self {
181        PreAlpha::new_opaque(self)
182            .inside(PreAlpha::new_opaque(other))
183            .unpremultiply()
184            .color
185    }
186
187    #[inline]
188    fn outside(self, other: Self) -> Self {
189        PreAlpha::new_opaque(self)
190            .outside(PreAlpha::new_opaque(other))
191            .unpremultiply()
192            .color
193    }
194
195    #[inline]
196    fn atop(self, other: Self) -> Self {
197        PreAlpha::new_opaque(self)
198            .atop(PreAlpha::new_opaque(other))
199            .unpremultiply()
200            .color
201    }
202
203    #[inline]
204    fn xor(self, other: Self) -> Self {
205        PreAlpha::new_opaque(self)
206            .xor(PreAlpha::new_opaque(other))
207            .unpremultiply()
208            .color
209    }
210
211    #[inline]
212    fn plus(self, other: Self) -> Self {
213        PreAlpha::new_opaque(self)
214            .plus(PreAlpha::new_opaque(other))
215            .unpremultiply()
216            .color
217    }
218}