palette/blend/
pre_alpha.rs

1use core::ops::{Add, AddAssign, Deref, DerefMut, Div, DivAssign, Mul, MulAssign, Sub, SubAssign};
2
3#[cfg(feature = "approx")]
4use approx::{AbsDiffEq, RelativeEq, UlpsEq};
5
6use crate::{
7    cast::ArrayCast,
8    clamp,
9    num::{self, Arithmetics, One, Real, Zero},
10    stimulus::Stimulus,
11    Alpha, ArrayExt, Mix, MixAssign, NextArray,
12};
13
14use super::Premultiply;
15
16/// Premultiplied alpha wrapper.
17///
18/// Premultiplied, or alpha masked, or associated alpha colors have had their
19/// component values multiplied with their alpha value. They are commonly used
20/// in composition algorithms and as output from computer generated graphics. It
21/// may also be preferred when interpolating between colors and in other image
22/// manipulation operations, such as blurring or resizing images.
23///
24/// ```
25/// use palette::{LinSrgb, LinSrgba};
26/// use palette::blend::{Blend, PreAlpha};
27///
28/// let a = PreAlpha::from(LinSrgba::new(0.4, 0.5, 0.5, 0.3));
29/// let b = PreAlpha::from(LinSrgba::new(0.3, 0.8, 0.4, 0.4));
30/// let c = PreAlpha::from(LinSrgba::new(0.7, 0.1, 0.8, 0.8));
31///
32/// let res: LinSrgba = a.screen(b).overlay(c).into();
33/// ```
34///
35/// Note that converting to and from premultiplied alpha will cause the alpha
36/// component to be clamped to [0.0, 1.0], and fully transparent colors will
37/// become black.
38#[derive(Clone, Copy, Debug)]
39#[repr(C)]
40pub struct PreAlpha<C: Premultiply> {
41    /// The premultiplied color components (`original.color * original.alpha`).
42    pub color: C,
43
44    /// The transparency component. 0.0 is fully transparent and 1.0 is fully
45    /// opaque.
46    pub alpha: C::Scalar,
47}
48
49impl<C> PreAlpha<C>
50where
51    C: Premultiply,
52{
53    /// Alpha mask `color` with `alpha`.
54    pub fn new(color: C, alpha: C::Scalar) -> Self {
55        color.premultiply(alpha)
56    }
57
58    /// Create an opaque alpha masked color.
59    pub fn new_opaque(color: C) -> Self
60    where
61        C::Scalar: Stimulus,
62    {
63        Self {
64            color,
65            alpha: C::Scalar::max_intensity(),
66        }
67    }
68
69    /// Alpha unmask the color.
70    pub fn unpremultiply(self) -> Alpha<C, C::Scalar> {
71        let (color, alpha) = C::unpremultiply(self);
72        Alpha { color, alpha }
73    }
74}
75
76impl<C> PartialEq for PreAlpha<C>
77where
78    C: PartialEq + Premultiply,
79    C::Scalar: PartialEq,
80{
81    fn eq(&self, other: &Self) -> bool {
82        self.color == other.color && self.alpha == other.alpha
83    }
84}
85
86impl<C> Eq for PreAlpha<C>
87where
88    C: Eq + Premultiply,
89    C::Scalar: Eq,
90{
91}
92
93impl<C> From<Alpha<C, C::Scalar>> for PreAlpha<C>
94where
95    C: Premultiply,
96{
97    #[inline]
98    fn from(color: Alpha<C, C::Scalar>) -> Self {
99        color.color.premultiply(color.alpha)
100    }
101}
102
103impl<C> From<PreAlpha<C>> for Alpha<C, C::Scalar>
104where
105    C: Premultiply,
106{
107    #[inline]
108    fn from(color: PreAlpha<C>) -> Self {
109        let (color, alpha) = C::unpremultiply(color);
110        Alpha { color, alpha }
111    }
112}
113
114impl<C> From<C> for PreAlpha<C>
115where
116    C: Premultiply,
117    C::Scalar: Stimulus,
118{
119    fn from(color: C) -> Self {
120        color.premultiply(C::Scalar::max_intensity())
121    }
122}
123
124impl<C, T> Mix for PreAlpha<C>
125where
126    C: Mix<Scalar = T> + Premultiply<Scalar = T>,
127    T: Real + Zero + One + num::Clamp + Arithmetics + Clone,
128{
129    type Scalar = T;
130
131    #[inline]
132    fn mix(mut self, other: Self, factor: T) -> Self {
133        let factor = clamp(factor, T::zero(), T::one());
134
135        self.color = self.color.mix(other.color, factor.clone());
136        self.alpha = self.alpha.clone() + factor * (other.alpha - self.alpha);
137
138        self
139    }
140}
141
142impl<C, T> MixAssign for PreAlpha<C>
143where
144    C: MixAssign<Scalar = T> + Premultiply<Scalar = T>,
145    T: Real + Zero + One + num::Clamp + Arithmetics + AddAssign + Clone,
146{
147    type Scalar = T;
148
149    #[inline]
150    fn mix_assign(&mut self, other: Self, factor: T) {
151        let factor = clamp(factor, T::zero(), T::one());
152
153        self.color.mix_assign(other.color, factor.clone());
154        self.alpha += factor * (other.alpha - self.alpha.clone());
155    }
156}
157
158unsafe impl<C, T> ArrayCast for PreAlpha<C>
159where
160    C: ArrayCast + Premultiply<Scalar = T>,
161    C::Array: NextArray + ArrayExt<Item = T>,
162{
163    type Array = <C::Array as NextArray>::Next;
164}
165
166impl<C> Default for PreAlpha<C>
167where
168    C: Default + Premultiply,
169    C::Scalar: Stimulus,
170{
171    fn default() -> PreAlpha<C> {
172        PreAlpha {
173            color: C::default(),
174            alpha: C::Scalar::max_intensity(),
175        }
176    }
177}
178
179#[cfg(feature = "approx")]
180impl<C, T> AbsDiffEq for PreAlpha<C>
181where
182    C: AbsDiffEq<Epsilon = T::Epsilon> + Premultiply<Scalar = T>,
183    T: AbsDiffEq,
184    T::Epsilon: Clone,
185{
186    type Epsilon = T::Epsilon;
187
188    fn default_epsilon() -> Self::Epsilon {
189        T::default_epsilon()
190    }
191
192    fn abs_diff_eq(&self, other: &PreAlpha<C>, epsilon: Self::Epsilon) -> bool {
193        self.color.abs_diff_eq(&other.color, epsilon.clone())
194            && self.alpha.abs_diff_eq(&other.alpha, epsilon)
195    }
196}
197
198#[cfg(feature = "approx")]
199impl<C, T> RelativeEq for PreAlpha<C>
200where
201    C: RelativeEq<Epsilon = T::Epsilon> + Premultiply<Scalar = T>,
202    T: RelativeEq,
203    T::Epsilon: Clone,
204{
205    fn default_max_relative() -> Self::Epsilon {
206        T::default_max_relative()
207    }
208
209    fn relative_eq(
210        &self,
211        other: &PreAlpha<C>,
212        epsilon: Self::Epsilon,
213        max_relative: Self::Epsilon,
214    ) -> bool {
215        self.color
216            .relative_eq(&other.color, epsilon.clone(), max_relative.clone())
217            && self.alpha.relative_eq(&other.alpha, epsilon, max_relative)
218    }
219}
220
221#[cfg(feature = "approx")]
222impl<C, T> UlpsEq for PreAlpha<C>
223where
224    C: UlpsEq<Epsilon = T::Epsilon> + Premultiply<Scalar = T>,
225    T: UlpsEq,
226    T::Epsilon: Clone,
227{
228    fn default_max_ulps() -> u32 {
229        T::default_max_ulps()
230    }
231
232    fn ulps_eq(&self, other: &PreAlpha<C>, epsilon: Self::Epsilon, max_ulps: u32) -> bool {
233        self.color.ulps_eq(&other.color, epsilon.clone(), max_ulps)
234            && self.alpha.ulps_eq(&other.alpha, epsilon, max_ulps)
235    }
236}
237
238macro_rules! impl_binop {
239    (
240        $op_trait:ident::$op_trait_fn:ident,
241        $op_assign_trait:ident::$op_assign_trait_fn:ident
242    ) => {
243        impl<C> $op_trait for PreAlpha<C>
244        where
245            C: $op_trait<Output = C> + Premultiply,
246            C::Scalar: $op_trait<Output = C::Scalar>,
247        {
248            type Output = PreAlpha<C>;
249
250            fn $op_trait_fn(self, other: PreAlpha<C>) -> Self::Output {
251                PreAlpha {
252                    color: self.color.$op_trait_fn(other.color),
253                    alpha: self.alpha.$op_trait_fn(other.alpha),
254                }
255            }
256        }
257
258        impl<C> $op_assign_trait for PreAlpha<C>
259        where
260            C: $op_assign_trait + Premultiply,
261            C::Scalar: $op_assign_trait + Real,
262        {
263            fn $op_assign_trait_fn(&mut self, other: PreAlpha<C>) {
264                self.color.$op_assign_trait_fn(other.color);
265                self.alpha.$op_assign_trait_fn(other.alpha);
266            }
267        }
268    };
269}
270
271impl_binop!(Add::add, AddAssign::add_assign);
272impl_binop!(Sub::sub, SubAssign::sub_assign);
273impl_binop!(Mul::mul, MulAssign::mul_assign);
274impl_binop!(Div::div, DivAssign::div_assign);
275
276macro_rules! impl_scalar_binop {
277    (
278        $op_trait:ident::$op_trait_fn:ident,
279        $op_assign_trait:ident::$op_assign_trait_fn:ident,
280        [$($ty:ident),+]
281    ) => {
282        $(
283            impl<C> $op_trait<$ty> for PreAlpha<C>
284            where
285                C: $op_trait<$ty, Output = C> + Premultiply<Scalar = $ty>,
286            {
287                type Output = PreAlpha<C>;
288
289                fn $op_trait_fn(self, c: $ty) -> Self::Output {
290                    PreAlpha {
291                        color: self.color.$op_trait_fn(c),
292                        alpha: self.alpha.$op_trait_fn(c),
293                    }
294                }
295            }
296
297            // // Disabled as work-around for https://github.com/Ogeon/palette/issues/283
298            // // Blocked by https://github.com/rust-lang/rust/issues/80542
299            // impl<C> $op_trait<PreAlpha<C>> for $ty
300            // where
301            //     C: Premultiply<Scalar = $ty>,
302            //     $ty: $op_trait<$ty, Output = $ty> + $op_trait<C, Output = C>,
303            // {
304            //     type Output = PreAlpha<C>;
305            //
306            //     fn $op_trait_fn(self, color: PreAlpha<C>) -> Self::Output {
307            //         PreAlpha {
308            //             color: $op_trait::<C>::$op_trait_fn(self, color.color),
309            //             alpha: $op_trait::<$ty>::$op_trait_fn(self, color.alpha),
310            //         }
311            //     }
312            // }
313
314            impl<C> $op_assign_trait<$ty> for PreAlpha<C>
315            where
316                C: $op_assign_trait<$ty> + Premultiply<Scalar = $ty>,
317            {
318                fn $op_assign_trait_fn(&mut self, c: $ty) {
319                    self.color.$op_assign_trait_fn(c);
320                    self.alpha.$op_assign_trait_fn(c);
321                }
322            }
323        )+
324    };
325}
326
327impl_scalar_binop!(Add::add, AddAssign::add_assign, [f32, f64]);
328impl_scalar_binop!(Sub::sub, SubAssign::sub_assign, [f32, f64]);
329impl_scalar_binop!(Mul::mul, MulAssign::mul_assign, [f32, f64]);
330impl_scalar_binop!(Div::div, DivAssign::div_assign, [f32, f64]);
331
332impl_array_casts!([C: Premultiply, const N: usize] PreAlpha<C>, [C::Scalar; N], where PreAlpha<C>: ArrayCast<Array = [C::Scalar; N]>);
333
334impl<C: Premultiply> Deref for PreAlpha<C> {
335    type Target = C;
336
337    fn deref(&self) -> &C {
338        &self.color
339    }
340}
341
342impl<C: Premultiply> DerefMut for PreAlpha<C> {
343    fn deref_mut(&mut self) -> &mut C {
344        &mut self.color
345    }
346}
347
348#[cfg(feature = "serializing")]
349impl<C> serde::Serialize for PreAlpha<C>
350where
351    C: Premultiply + serde::Serialize,
352    C::Scalar: serde::Serialize,
353{
354    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
355    where
356        S: serde::Serializer,
357    {
358        self.color.serialize(crate::serde::AlphaSerializer {
359            inner: serializer,
360            alpha: &self.alpha,
361        })
362    }
363}
364
365#[cfg(feature = "serializing")]
366impl<'de, C> serde::Deserialize<'de> for PreAlpha<C>
367where
368    C: Premultiply + serde::Deserialize<'de>,
369    C::Scalar: serde::Deserialize<'de>,
370{
371    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
372    where
373        D: serde::Deserializer<'de>,
374    {
375        let mut alpha: Option<C::Scalar> = None;
376
377        let color = C::deserialize(crate::serde::AlphaDeserializer {
378            inner: deserializer,
379            alpha: &mut alpha,
380        })?;
381
382        if let Some(alpha) = alpha {
383            Ok(Self { color, alpha })
384        } else {
385            Err(serde::de::Error::missing_field("alpha"))
386        }
387    }
388}
389
390#[cfg(feature = "bytemuck")]
391unsafe impl<C> bytemuck::Zeroable for PreAlpha<C>
392where
393    C: bytemuck::Zeroable + Premultiply,
394    C::Scalar: bytemuck::Zeroable,
395{
396}
397
398// Safety:
399//
400// See `Alpha<C, T>`'s implementation of `Pod`.
401#[cfg(feature = "bytemuck")]
402unsafe impl<C> bytemuck::Pod for PreAlpha<C>
403where
404    C: bytemuck::Pod + ArrayCast + Premultiply,
405    C::Scalar: bytemuck::Pod,
406{
407}
408
409#[cfg(test)]
410#[cfg(feature = "serializing")]
411mod test {
412    use super::PreAlpha;
413    use crate::LinSrgb;
414
415    #[cfg(feature = "serializing")]
416    #[test]
417    fn serialize() {
418        let color = PreAlpha {
419            color: LinSrgb::new(0.3, 0.8, 0.1),
420            alpha: 0.5,
421        };
422
423        assert_eq!(
424            serde_json::to_string(&color).unwrap(),
425            r#"{"red":0.3,"green":0.8,"blue":0.1,"alpha":0.5}"#
426        );
427
428        assert_eq!(
429            ron::to_string(&color).unwrap(),
430            r#"(red:0.3,green:0.8,blue:0.1,alpha:0.5)"#
431        );
432    }
433
434    #[cfg(feature = "serializing")]
435    #[test]
436    fn deserialize() {
437        let color = PreAlpha {
438            color: LinSrgb::new(0.3, 0.8, 0.1),
439            alpha: 0.5,
440        };
441
442        assert_eq!(
443            serde_json::from_str::<PreAlpha<LinSrgb>>(
444                r#"{"alpha":0.5,"red":0.3,"green":0.8,"blue":0.1}"#
445            )
446            .unwrap(),
447            color
448        );
449
450        assert_eq!(
451            ron::from_str::<PreAlpha<LinSrgb>>(r#"(alpha:0.5,red:0.3,green:0.8,blue:0.1)"#)
452                .unwrap(),
453            color
454        );
455
456        assert_eq!(
457            ron::from_str::<PreAlpha<LinSrgb>>(r#"Rgb(alpha:0.5,red:0.3,green:0.8,blue:0.1)"#)
458                .unwrap(),
459            color
460        );
461    }
462}