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
11pub trait Compose {
18 #[must_use]
21 fn over(self, other: Self) -> Self;
22
23 #[must_use]
26 fn inside(self, other: Self) -> Self;
27
28 #[must_use]
31 fn outside(self, other: Self) -> Self;
32
33 #[must_use]
35 fn atop(self, other: Self) -> Self;
36
37 #[must_use]
39 fn xor(self, other: Self) -> Self;
40
41 #[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}