Skip to main content

ai_image/
color.rs

1use core::ops::{Index, IndexMut};
2
3#[cfg(not(feature = "std"))]
4use num_traits::float::FloatCore as _;
5use num_traits::{NumCast, ToPrimitive, Zero};
6
7use crate::{
8    error::TryFromExtendedColorError,
9    traits::{Enlargeable, Pixel, Primitive},
10};
11
12/// An enumeration over supported color types and bit depths
13#[derive(Copy, PartialEq, Eq, Debug, Clone, Hash)]
14#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
15#[non_exhaustive]
16pub enum ColorType {
17    /// Pixel is 8-bit luminance
18    L8,
19    /// Pixel is 8-bit luminance with an alpha channel
20    La8,
21    /// Pixel contains 8-bit R, G and B channels
22    Rgb8,
23    /// Pixel is 8-bit RGB with an alpha channel
24    Rgba8,
25
26    /// Pixel is 16-bit luminance
27    L16,
28    /// Pixel is 16-bit luminance with an alpha channel
29    La16,
30    /// Pixel is 16-bit RGB
31    Rgb16,
32    /// Pixel is 16-bit RGBA
33    Rgba16,
34
35    /// Pixel is 32-bit float RGB
36    Rgb32F,
37    /// Pixel is 32-bit float RGBA
38    Rgba32F,
39}
40
41impl ColorType {
42    /// Returns the number of bytes contained in a pixel of `ColorType` ```c```
43    #[must_use]
44    pub fn bytes_per_pixel(self) -> u8 {
45        match self {
46            ColorType::L8 => 1,
47            ColorType::L16 | ColorType::La8 => 2,
48            ColorType::Rgb8 => 3,
49            ColorType::Rgba8 | ColorType::La16 => 4,
50            ColorType::Rgb16 => 6,
51            ColorType::Rgba16 => 8,
52            ColorType::Rgb32F => 3 * 4,
53            ColorType::Rgba32F => 4 * 4,
54        }
55    }
56
57    /// Returns if there is an alpha channel.
58    #[must_use]
59    pub fn has_alpha(self) -> bool {
60        use ColorType::*;
61        match self {
62            L8 | L16 | Rgb8 | Rgb16 | Rgb32F => false,
63            La8 | Rgba8 | La16 | Rgba16 | Rgba32F => true,
64        }
65    }
66
67    /// Returns false if the color scheme is grayscale, true otherwise.
68    #[must_use]
69    pub fn has_color(self) -> bool {
70        use ColorType::*;
71        match self {
72            L8 | L16 | La8 | La16 => false,
73            Rgb8 | Rgb16 | Rgba8 | Rgba16 | Rgb32F | Rgba32F => true,
74        }
75    }
76
77    /// Returns the number of bits contained in a pixel of `ColorType` ```c``` (which will always be
78    /// a multiple of 8).
79    #[must_use]
80    pub fn bits_per_pixel(self) -> u16 {
81        <u16 as From<u8>>::from(self.bytes_per_pixel()) * 8
82    }
83
84    /// Returns the number of color channels that make up this pixel
85    #[must_use]
86    pub fn channel_count(self) -> u8 {
87        let e: ExtendedColorType = self.into();
88        e.channel_count()
89    }
90}
91
92/// An enumeration of color types encountered in image formats.
93///
94/// This is not exhaustive over all existing image formats but should be granular enough to allow
95/// round tripping of decoding and encoding as much as possible. The variants will be extended as
96/// necessary to enable this.
97///
98/// Another purpose is to advise users of a rough estimate of the accuracy and effort of the
99/// decoding from and encoding to such an image format.
100#[derive(Copy, PartialEq, Eq, Debug, Clone, Hash)]
101#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
102#[non_exhaustive]
103pub enum ExtendedColorType {
104    /// Pixel is 8-bit alpha
105    A8,
106    /// Pixel is 1-bit luminance
107    L1,
108    /// Pixel is 1-bit luminance with an alpha channel
109    La1,
110    /// Pixel contains 1-bit R, G and B channels
111    Rgb1,
112    /// Pixel is 1-bit RGB with an alpha channel
113    Rgba1,
114    /// Pixel is 2-bit luminance
115    L2,
116    /// Pixel is 2-bit luminance with an alpha channel
117    La2,
118    /// Pixel contains 2-bit R, G and B channels
119    Rgb2,
120    /// Pixel is 2-bit RGB with an alpha channel
121    Rgba2,
122    /// Pixel is 4-bit luminance
123    L4,
124    /// Pixel is 4-bit luminance with an alpha channel
125    La4,
126    /// Pixel contains 4-bit R, G and B channels
127    Rgb4,
128    /// Pixel is 4-bit RGB with an alpha channel
129    Rgba4,
130    /// Pixel contains 5-bit R, G and B channels packed into 2 bytes
131    Rgb5x1,
132    /// Pixel is 8-bit luminance
133    L8,
134    /// Pixel is 8-bit luminance with an alpha channel
135    La8,
136    /// Pixel contains 8-bit R, G and B channels
137    Rgb8,
138    /// Pixel is 8-bit RGB with an alpha channel
139    Rgba8,
140    /// Pixel is 16-bit luminance
141    L16,
142    /// Pixel is 16-bit luminance with an alpha channel
143    La16,
144    /// Pixel contains 16-bit R, G and B channels
145    Rgb16,
146    /// Pixel is 16-bit RGB with an alpha channel
147    Rgba16,
148    /// Pixel contains 8-bit B, G and R channels
149    Bgr8,
150    /// Pixel is 8-bit BGR with an alpha channel
151    Bgra8,
152
153    // TODO f16 types?
154    /// Pixel is 32-bit float RGB
155    Rgb32F,
156    /// Pixel is 32-bit float RGBA
157    Rgba32F,
158
159    /// Pixel is 8-bit CMYK
160    Cmyk8,
161    /// Pixel is 16-bit CMYK
162    Cmyk16,
163
164    /// Pixel is of unknown color type with the specified bits per pixel. This can apply to pixels
165    /// which are associated with an external palette. In that case, the pixel value is an index
166    /// into the palette.
167    Unknown(u8),
168}
169
170impl ExtendedColorType {
171    /// Get the number of channels for colors of this type.
172    ///
173    /// Note that the `Unknown` variant returns a value of `1` since pixels can only be treated as
174    /// an opaque datum by the library.
175    #[must_use]
176    pub fn channel_count(self) -> u8 {
177        match self {
178            ExtendedColorType::A8
179            | ExtendedColorType::L1
180            | ExtendedColorType::L2
181            | ExtendedColorType::L4
182            | ExtendedColorType::L8
183            | ExtendedColorType::L16
184            | ExtendedColorType::Unknown(_) => 1,
185            ExtendedColorType::La1
186            | ExtendedColorType::La2
187            | ExtendedColorType::La4
188            | ExtendedColorType::La8
189            | ExtendedColorType::La16 => 2,
190            ExtendedColorType::Rgb1
191            | ExtendedColorType::Rgb2
192            | ExtendedColorType::Rgb4
193            | ExtendedColorType::Rgb5x1
194            | ExtendedColorType::Rgb8
195            | ExtendedColorType::Rgb16
196            | ExtendedColorType::Rgb32F
197            | ExtendedColorType::Bgr8 => 3,
198            ExtendedColorType::Rgba1
199            | ExtendedColorType::Rgba2
200            | ExtendedColorType::Rgba4
201            | ExtendedColorType::Rgba8
202            | ExtendedColorType::Rgba16
203            | ExtendedColorType::Rgba32F
204            | ExtendedColorType::Bgra8
205            | ExtendedColorType::Cmyk8
206            | ExtendedColorType::Cmyk16 => 4,
207        }
208    }
209
210    /// Returns the number of bits per pixel for this color type.
211    #[must_use]
212    pub fn bits_per_pixel(&self) -> u16 {
213        match *self {
214            ExtendedColorType::A8 => 8,
215            ExtendedColorType::L1 => 1,
216            ExtendedColorType::La1 => 2,
217            ExtendedColorType::Rgb1 => 3,
218            ExtendedColorType::Rgba1 => 4,
219            ExtendedColorType::L2 => 2,
220            ExtendedColorType::La2 => 4,
221            ExtendedColorType::Rgb2 => 6,
222            ExtendedColorType::Rgba2 => 8,
223            ExtendedColorType::L4 => 4,
224            ExtendedColorType::La4 => 8,
225            ExtendedColorType::Rgb4 => 12,
226            ExtendedColorType::Rgba4 => 16,
227            ExtendedColorType::Rgb5x1 => 16,
228            ExtendedColorType::L8 => 8,
229            ExtendedColorType::La8 => 16,
230            ExtendedColorType::Rgb8 => 24,
231            ExtendedColorType::Rgba8 => 32,
232            ExtendedColorType::L16 => 16,
233            ExtendedColorType::La16 => 32,
234            ExtendedColorType::Rgb16 => 48,
235            ExtendedColorType::Rgba16 => 64,
236            ExtendedColorType::Rgb32F => 96,
237            ExtendedColorType::Rgba32F => 128,
238            ExtendedColorType::Bgr8 => 24,
239            ExtendedColorType::Bgra8 => 32,
240            ExtendedColorType::Cmyk8 => 32,
241            ExtendedColorType::Cmyk16 => 64,
242            ExtendedColorType::Unknown(bpp) => bpp as u16,
243        }
244    }
245
246    /// Returns the ColorType that is equivalent to this ExtendedColorType.
247    ///
248    /// # Example
249    ///
250    /// ```
251    /// use ai_image::{ColorType, ExtendedColorType};
252    ///
253    /// assert_eq!(Some(ColorType::L8), ExtendedColorType::L8.color_type());
254    /// assert_eq!(None, ExtendedColorType::L1.color_type());
255    /// ```
256    ///
257    /// The method is equivalent to converting via the `TryFrom`/`TryInto` traits except for the
258    /// error path. Choose the more ergonomic option in your usage.
259    ///
260    /// ```
261    /// use ai_image::{ColorType, ExtendedColorType, ImageError};
262    ///
263    /// fn handle_errors() -> Result<(), ImageError> {
264    ///     let color: ColorType = ExtendedColorType::L8.try_into()?;
265    ///     assert_eq!(color, ColorType::L8);
266    ///     # Ok(())
267    /// }
268    /// ```
269    pub fn color_type(&self) -> Option<ColorType> {
270        match *self {
271            ExtendedColorType::L8 => Some(ColorType::L8),
272            ExtendedColorType::La8 => Some(ColorType::La8),
273            ExtendedColorType::Rgb8 => Some(ColorType::Rgb8),
274            ExtendedColorType::Rgba8 => Some(ColorType::Rgba8),
275            ExtendedColorType::L16 => Some(ColorType::L16),
276            ExtendedColorType::La16 => Some(ColorType::La16),
277            ExtendedColorType::Rgb16 => Some(ColorType::Rgb16),
278            ExtendedColorType::Rgba16 => Some(ColorType::Rgba16),
279            ExtendedColorType::Rgb32F => Some(ColorType::Rgb32F),
280            ExtendedColorType::Rgba32F => Some(ColorType::Rgba32F),
281            _ => None,
282        }
283    }
284
285    /// Returns the number of bytes required to hold a width x height image of this color type.
286    #[cfg(any(
287        feature = "png",
288        feature = "jpeg",
289        feature = "gif",
290        feature = "tiff",
291        feature = "tga",
292        feature = "webp",
293        feature = "qoi",
294        feature = "exr",
295        feature = "avif",
296        feature = "bmp",
297        feature = "ico",
298        feature = "pnm"
299    ))]
300    pub(crate) fn buffer_size(self, width: u32, height: u32) -> u64 {
301        let bpp = self.bits_per_pixel() as u64;
302        let row_pitch = (width as u64 * bpp).div_ceil(8);
303        row_pitch.saturating_mul(height as u64)
304    }
305}
306
307impl From<ColorType> for ExtendedColorType {
308    fn from(c: ColorType) -> Self {
309        match c {
310            ColorType::L8 => ExtendedColorType::L8,
311            ColorType::La8 => ExtendedColorType::La8,
312            ColorType::Rgb8 => ExtendedColorType::Rgb8,
313            ColorType::Rgba8 => ExtendedColorType::Rgba8,
314            ColorType::L16 => ExtendedColorType::L16,
315            ColorType::La16 => ExtendedColorType::La16,
316            ColorType::Rgb16 => ExtendedColorType::Rgb16,
317            ColorType::Rgba16 => ExtendedColorType::Rgba16,
318            ColorType::Rgb32F => ExtendedColorType::Rgb32F,
319            ColorType::Rgba32F => ExtendedColorType::Rgba32F,
320        }
321    }
322}
323
324impl TryFrom<ExtendedColorType> for ColorType {
325    type Error = TryFromExtendedColorError;
326
327    fn try_from(value: ExtendedColorType) -> Result<ColorType, Self::Error> {
328        value
329            .color_type()
330            .ok_or(TryFromExtendedColorError { was: value })
331    }
332}
333
334macro_rules! define_colors {
335    {$(
336        $(#[$doc:meta])*
337        pub struct $ident:ident<T: $($bound:ident)*>([T; $channels:expr, $alphas:expr])
338            = $interpretation:literal;
339    )*} => {
340
341$( // START Structure definitions
342
343$(#[$doc])*
344#[derive(PartialEq, Eq, Clone, Debug, Copy, Hash)]
345#[repr(transparent)]
346#[allow(missing_docs)]
347pub struct $ident<T> (pub [T; $channels]);
348
349impl<T: $($bound+)*> Pixel for $ident<T> {
350    type Subpixel = T;
351
352    const CHANNEL_COUNT: u8 = $channels;
353
354    #[inline(always)]
355    fn channels(&self) -> &[T] {
356        &self.0
357    }
358
359    #[inline(always)]
360    fn channels_mut(&mut self) -> &mut [T] {
361        &mut self.0
362    }
363
364    const COLOR_MODEL: &'static str = $interpretation;
365
366    const HAS_ALPHA: bool = $alphas > 0;
367
368    #[inline]
369    fn alpha(&self) -> Self::Subpixel {
370        if Self::HAS_ALPHA {
371            // all our types have alpha channel at the end: RgbA, LumaA
372            *self.channels().last().unwrap()
373        } else {
374            Self::Subpixel::DEFAULT_MAX_VALUE
375        }
376    }
377
378    fn channels4(&self) -> (T, T, T, T) {
379        const CHANNELS: usize = $channels;
380        let mut channels = [T::DEFAULT_MAX_VALUE; 4];
381        channels[0..CHANNELS].copy_from_slice(&self.0);
382        (channels[0], channels[1], channels[2], channels[3])
383    }
384
385    fn from_channels(a: T, b: T, c: T, d: T,) -> $ident<T> {
386        const CHANNELS: usize = $channels;
387        *<$ident<T> as Pixel>::from_slice(&[a, b, c, d][..CHANNELS])
388    }
389
390    fn from_slice(slice: &[T]) -> &$ident<T> {
391        assert_eq!(slice.len(), $channels);
392        unsafe { &*(slice.as_ptr() as *const $ident<T>) }
393    }
394    fn from_slice_mut(slice: &mut [T]) -> &mut $ident<T> {
395        assert_eq!(slice.len(), $channels);
396        unsafe { &mut *(slice.as_mut_ptr() as *mut $ident<T>) }
397    }
398
399    fn to_rgb(&self) -> Rgb<T> {
400        let mut pix = Rgb([Zero::zero(), Zero::zero(), Zero::zero()]);
401        pix.from_color(self);
402        pix
403    }
404
405    fn to_rgba(&self) -> Rgba<T> {
406        let mut pix = Rgba([Zero::zero(), Zero::zero(), Zero::zero(), Zero::zero()]);
407        pix.from_color(self);
408        pix
409    }
410
411    fn to_luma(&self) -> Luma<T> {
412        let mut pix = Luma([Zero::zero()]);
413        pix.from_color(self);
414        pix
415    }
416
417    fn to_luma_alpha(&self) -> LumaA<T> {
418        let mut pix = LumaA([Zero::zero(), Zero::zero()]);
419        pix.from_color(self);
420        pix
421    }
422
423    fn map<F>(& self, f: F) -> $ident<T> where F: FnMut(T) -> T {
424        let mut this = (*self).clone();
425        this.apply(f);
426        this
427    }
428
429    fn apply<F>(&mut self, mut f: F) where F: FnMut(T) -> T {
430        for v in &mut self.0 {
431            *v = f(*v)
432        }
433    }
434
435    fn map_with_alpha<F, G>(&self, f: F, g: G) -> $ident<T> where F: FnMut(T) -> T, G: FnMut(T) -> T {
436        let mut this = (*self).clone();
437        this.apply_with_alpha(f, g);
438        this
439    }
440
441    fn apply_with_alpha<F, G>(&mut self, mut f: F, mut g: G) where F: FnMut(T) -> T, G: FnMut(T) -> T {
442        const ALPHA: usize = $channels - $alphas;
443        for v in self.0[..ALPHA].iter_mut() {
444            *v = f(*v)
445        }
446        // The branch of this match is `const`. This way ensures that no subexpression fails the
447        // `const_err` lint (the expression `self.0[ALPHA]` would).
448        if let Some(v) = self.0.get_mut(ALPHA) {
449            *v = g(*v)
450        }
451    }
452
453    fn map2<F>(&self, other: &Self, f: F) -> $ident<T> where F: FnMut(T, T) -> T {
454        let mut this = (*self).clone();
455        this.apply2(other, f);
456        this
457    }
458
459    fn apply2<F>(&mut self, other: &$ident<T>, mut f: F) where F: FnMut(T, T) -> T {
460        for (a, &b) in self.0.iter_mut().zip(other.0.iter()) {
461            *a = f(*a, b)
462        }
463    }
464
465    fn invert(&mut self) {
466        Invert::invert(self)
467    }
468
469    fn blend(&mut self, other: &$ident<T>) {
470        Blend::blend(self, other)
471    }
472}
473
474impl<T> Index<usize> for $ident<T> {
475    type Output = T;
476    #[inline(always)]
477    fn index(&self, _index: usize) -> &T {
478        &self.0[_index]
479    }
480}
481
482impl<T> IndexMut<usize> for $ident<T> {
483    #[inline(always)]
484    fn index_mut(&mut self, _index: usize) -> &mut T {
485        &mut self.0[_index]
486    }
487}
488
489impl<T> From<[T; $channels]> for $ident<T> {
490    fn from(c: [T; $channels]) -> Self {
491        Self(c)
492    }
493}
494
495)* // END Structure definitions
496
497    }
498}
499
500define_colors! {
501    /// RGB colors.
502    ///
503    /// For the purpose of color conversion, as well as blending, the implementation of `Pixel`
504    /// assumes an `sRGB` color space of its data.
505    pub struct Rgb<T: Primitive Enlargeable>([T; 3, 0]) = "RGB";
506    /// Grayscale colors.
507    pub struct Luma<T: Primitive>([T; 1, 0]) = "Y";
508    /// RGB colors + alpha channel
509    pub struct Rgba<T: Primitive Enlargeable>([T; 4, 1]) = "RGBA";
510    /// Grayscale colors + alpha channel
511    pub struct LumaA<T: Primitive>([T; 2, 1]) = "YA";
512}
513
514/// Convert from one pixel component type to another. For example, convert from `u8` to `f32` pixel values.
515pub trait FromPrimitive<Component> {
516    /// Converts from any pixel component type to this type.
517    fn from_primitive(component: Component) -> Self;
518}
519
520impl<T: Primitive> FromPrimitive<T> for T {
521    fn from_primitive(sample: T) -> Self {
522        sample
523    }
524}
525
526// from f32:
527// Note that in to-integer-conversion we are performing rounding but NumCast::from is implemented
528// as truncate towards zero. We emulate rounding by adding a bias.
529
530// All other special values are clamped inbetween 0.0 and 1.0 (infinities and subnormals)
531// NaN however always maps to NaN therefore we have to force it towards some value.
532// 1.0 (white) was picked as firefox and chrome choose to map NaN to that.
533#[inline]
534fn normalize_float(float: f32, max: f32) -> f32 {
535    #[allow(clippy::neg_cmp_op_on_partial_ord)]
536    let clamped = if !(float < 1.0) { 1.0 } else { float.max(0.0) };
537    (clamped * max).round()
538}
539
540impl FromPrimitive<f32> for u8 {
541    fn from_primitive(float: f32) -> Self {
542        NumCast::from(normalize_float(float, u8::MAX as f32)).unwrap()
543    }
544}
545
546impl FromPrimitive<f32> for u16 {
547    fn from_primitive(float: f32) -> Self {
548        NumCast::from(normalize_float(float, u16::MAX as f32)).unwrap()
549    }
550}
551
552// from u16:
553
554impl FromPrimitive<u16> for u8 {
555    fn from_primitive(c16: u16) -> Self {
556        fn from(c: impl Into<u32>) -> u32 {
557            c.into()
558        }
559        // The input c is the numerator of `c / u16::MAX`.
560        // Derive numerator of `num / u8::MAX`, with rounding.
561        //
562        // This method is based on the inverse (see FromPrimitive<u8> for u16) and was tested
563        // exhaustively in Python. It's the same as the reference function:
564        //  round(c * (2**8 - 1) / (2**16 - 1))
565        NumCast::from((from(c16) + 128) / 257).unwrap()
566    }
567}
568
569impl FromPrimitive<u16> for f32 {
570    fn from_primitive(int: u16) -> Self {
571        (int as f32 / u16::MAX as f32).clamp(0.0, 1.0)
572    }
573}
574
575// from u8:
576
577impl FromPrimitive<u8> for f32 {
578    fn from_primitive(int: u8) -> Self {
579        (int as f32 / u8::MAX as f32).clamp(0.0, 1.0)
580    }
581}
582
583impl FromPrimitive<u8> for u16 {
584    fn from_primitive(c8: u8) -> Self {
585        let x = c8.to_u64().unwrap();
586        NumCast::from((x << 8) | x).unwrap()
587    }
588}
589
590/// Provides color conversions for the different pixel types.
591pub trait FromColor<Other> {
592    /// Changes `self` to represent `Other` in the color space of `Self`
593    #[allow(clippy::wrong_self_convention)]
594    fn from_color(&mut self, _: &Other);
595}
596
597/// Copy-based conversions to target pixel types using `FromColor`.
598// FIXME: this trait should be removed and replaced with real color space models
599// rather than assuming sRGB.
600pub(crate) trait IntoColor<Other> {
601    /// Constructs a pixel of the target type and converts this pixel into it.
602    #[allow(clippy::wrong_self_convention)]
603    fn into_color(&self) -> Other;
604}
605
606impl<O, S> IntoColor<O> for S
607where
608    O: Pixel + FromColor<S>,
609{
610    #[allow(clippy::wrong_self_convention)]
611    fn into_color(&self) -> O {
612        // Note we cannot use Pixel::CHANNELS_COUNT here to directly construct
613        // the pixel due to a current bug/limitation of consts.
614        #[allow(deprecated)]
615        let mut pix = O::from_channels(Zero::zero(), Zero::zero(), Zero::zero(), Zero::zero());
616        pix.from_color(self);
617        pix
618    }
619}
620
621/// Coefficients to transform from sRGB to a CIE Y (luminance) value.
622const SRGB_LUMA: [u32; 3] = [2126, 7152, 722];
623const SRGB_LUMA_DIV: u32 = 10000;
624
625#[inline]
626fn rgb_to_luma<T: Primitive + Enlargeable>(rgb: &[T]) -> T {
627    let l = <T::Larger as NumCast>::from(SRGB_LUMA[0]).unwrap() * rgb[0].to_larger()
628        + <T::Larger as NumCast>::from(SRGB_LUMA[1]).unwrap() * rgb[1].to_larger()
629        + <T::Larger as NumCast>::from(SRGB_LUMA[2]).unwrap() * rgb[2].to_larger();
630    T::clamp_from(l / <T::Larger as NumCast>::from(SRGB_LUMA_DIV).unwrap())
631}
632
633// `FromColor` for Luma
634impl<S: Primitive, T: Primitive> FromColor<Luma<S>> for Luma<T>
635where
636    T: FromPrimitive<S>,
637{
638    fn from_color(&mut self, other: &Luma<S>) {
639        let own = self.channels_mut();
640        let other = other.channels();
641        own[0] = T::from_primitive(other[0]);
642    }
643}
644
645impl<S: Primitive, T: Primitive> FromColor<LumaA<S>> for Luma<T>
646where
647    T: FromPrimitive<S>,
648{
649    fn from_color(&mut self, other: &LumaA<S>) {
650        self.channels_mut()[0] = T::from_primitive(other.channels()[0]);
651    }
652}
653
654impl<S: Primitive + Enlargeable, T: Primitive> FromColor<Rgb<S>> for Luma<T>
655where
656    T: FromPrimitive<S>,
657{
658    fn from_color(&mut self, other: &Rgb<S>) {
659        let gray = self.channels_mut();
660        let rgb = other.channels();
661        gray[0] = T::from_primitive(rgb_to_luma(rgb));
662    }
663}
664
665impl<S: Primitive + Enlargeable, T: Primitive> FromColor<Rgba<S>> for Luma<T>
666where
667    T: FromPrimitive<S>,
668{
669    fn from_color(&mut self, other: &Rgba<S>) {
670        let gray = self.channels_mut();
671        let rgb = other.channels();
672        let l = rgb_to_luma(rgb);
673        gray[0] = T::from_primitive(l);
674    }
675}
676
677// `FromColor` for LumaA
678
679impl<S: Primitive, T: Primitive> FromColor<LumaA<S>> for LumaA<T>
680where
681    T: FromPrimitive<S>,
682{
683    fn from_color(&mut self, other: &LumaA<S>) {
684        let own = self.channels_mut();
685        let other = other.channels();
686        own[0] = T::from_primitive(other[0]);
687        own[1] = T::from_primitive(other[1]);
688    }
689}
690
691impl<S: Primitive + Enlargeable, T: Primitive> FromColor<Rgb<S>> for LumaA<T>
692where
693    T: FromPrimitive<S>,
694{
695    fn from_color(&mut self, other: &Rgb<S>) {
696        let gray_a = self.channels_mut();
697        let rgb = other.channels();
698        gray_a[0] = T::from_primitive(rgb_to_luma(rgb));
699        gray_a[1] = T::DEFAULT_MAX_VALUE;
700    }
701}
702
703impl<S: Primitive + Enlargeable, T: Primitive> FromColor<Rgba<S>> for LumaA<T>
704where
705    T: FromPrimitive<S>,
706{
707    fn from_color(&mut self, other: &Rgba<S>) {
708        let gray_a = self.channels_mut();
709        let rgba = other.channels();
710        gray_a[0] = T::from_primitive(rgb_to_luma(rgba));
711        gray_a[1] = T::from_primitive(rgba[3]);
712    }
713}
714
715impl<S: Primitive, T: Primitive> FromColor<Luma<S>> for LumaA<T>
716where
717    T: FromPrimitive<S>,
718{
719    fn from_color(&mut self, other: &Luma<S>) {
720        let gray_a = self.channels_mut();
721        gray_a[0] = T::from_primitive(other.channels()[0]);
722        gray_a[1] = T::DEFAULT_MAX_VALUE;
723    }
724}
725
726// `FromColor` for RGBA
727
728impl<S: Primitive, T: Primitive> FromColor<Rgba<S>> for Rgba<T>
729where
730    T: FromPrimitive<S>,
731{
732    fn from_color(&mut self, other: &Rgba<S>) {
733        let own = &mut self.0;
734        let other = &other.0;
735        own[0] = T::from_primitive(other[0]);
736        own[1] = T::from_primitive(other[1]);
737        own[2] = T::from_primitive(other[2]);
738        own[3] = T::from_primitive(other[3]);
739    }
740}
741
742impl<S: Primitive, T: Primitive> FromColor<Rgb<S>> for Rgba<T>
743where
744    T: FromPrimitive<S>,
745{
746    fn from_color(&mut self, other: &Rgb<S>) {
747        let rgba = &mut self.0;
748        let rgb = &other.0;
749        rgba[0] = T::from_primitive(rgb[0]);
750        rgba[1] = T::from_primitive(rgb[1]);
751        rgba[2] = T::from_primitive(rgb[2]);
752        rgba[3] = T::DEFAULT_MAX_VALUE;
753    }
754}
755
756impl<S: Primitive, T: Primitive> FromColor<LumaA<S>> for Rgba<T>
757where
758    T: FromPrimitive<S>,
759{
760    fn from_color(&mut self, gray: &LumaA<S>) {
761        let rgba = &mut self.0;
762        let gray = &gray.0;
763        rgba[0] = T::from_primitive(gray[0]);
764        rgba[1] = T::from_primitive(gray[0]);
765        rgba[2] = T::from_primitive(gray[0]);
766        rgba[3] = T::from_primitive(gray[1]);
767    }
768}
769
770impl<S: Primitive, T: Primitive> FromColor<Luma<S>> for Rgba<T>
771where
772    T: FromPrimitive<S>,
773{
774    fn from_color(&mut self, gray: &Luma<S>) {
775        let rgba = &mut self.0;
776        let gray = gray.0[0];
777        rgba[0] = T::from_primitive(gray);
778        rgba[1] = T::from_primitive(gray);
779        rgba[2] = T::from_primitive(gray);
780        rgba[3] = T::DEFAULT_MAX_VALUE;
781    }
782}
783
784// `FromColor` for RGB
785
786impl<S: Primitive, T: Primitive> FromColor<Rgb<S>> for Rgb<T>
787where
788    T: FromPrimitive<S>,
789{
790    fn from_color(&mut self, other: &Rgb<S>) {
791        let own = &mut self.0;
792        let other = &other.0;
793        own[0] = T::from_primitive(other[0]);
794        own[1] = T::from_primitive(other[1]);
795        own[2] = T::from_primitive(other[2]);
796    }
797}
798
799impl<S: Primitive, T: Primitive> FromColor<Rgba<S>> for Rgb<T>
800where
801    T: FromPrimitive<S>,
802{
803    fn from_color(&mut self, other: &Rgba<S>) {
804        let rgb = &mut self.0;
805        let rgba = &other.0;
806        rgb[0] = T::from_primitive(rgba[0]);
807        rgb[1] = T::from_primitive(rgba[1]);
808        rgb[2] = T::from_primitive(rgba[2]);
809    }
810}
811
812impl<S: Primitive, T: Primitive> FromColor<LumaA<S>> for Rgb<T>
813where
814    T: FromPrimitive<S>,
815{
816    fn from_color(&mut self, other: &LumaA<S>) {
817        let rgb = &mut self.0;
818        let gray = other.0[0];
819        rgb[0] = T::from_primitive(gray);
820        rgb[1] = T::from_primitive(gray);
821        rgb[2] = T::from_primitive(gray);
822    }
823}
824
825impl<S: Primitive, T: Primitive> FromColor<Luma<S>> for Rgb<T>
826where
827    T: FromPrimitive<S>,
828{
829    fn from_color(&mut self, other: &Luma<S>) {
830        let rgb = &mut self.0;
831        let gray = other.0[0];
832        rgb[0] = T::from_primitive(gray);
833        rgb[1] = T::from_primitive(gray);
834        rgb[2] = T::from_primitive(gray);
835    }
836}
837
838/// Blends a color inter another one
839pub(crate) trait Blend {
840    /// Blends a color in-place.
841    fn blend(&mut self, other: &Self);
842}
843
844impl<T: Primitive> Blend for LumaA<T> {
845    fn blend(&mut self, other: &LumaA<T>) {
846        let max_t = T::DEFAULT_MAX_VALUE;
847        let max_t = max_t.to_f32().unwrap();
848        let (bg_luma, bg_a) = (self.0[0], self.0[1]);
849        let (fg_luma, fg_a) = (other.0[0], other.0[1]);
850
851        let (bg_luma, bg_a) = (
852            bg_luma.to_f32().unwrap() / max_t,
853            bg_a.to_f32().unwrap() / max_t,
854        );
855        let (fg_luma, fg_a) = (
856            fg_luma.to_f32().unwrap() / max_t,
857            fg_a.to_f32().unwrap() / max_t,
858        );
859
860        let alpha_final = bg_a + fg_a - bg_a * fg_a;
861        if alpha_final == 0.0 {
862            return;
863        };
864        let bg_luma_a = bg_luma * bg_a;
865        let fg_luma_a = fg_luma * fg_a;
866
867        let out_luma_a = fg_luma_a + bg_luma_a * (1.0 - fg_a);
868        let out_luma = out_luma_a / alpha_final;
869
870        *self = LumaA([
871            NumCast::from(max_t * out_luma).unwrap(),
872            NumCast::from(max_t * alpha_final).unwrap(),
873        ]);
874    }
875}
876
877impl<T: Primitive> Blend for Luma<T> {
878    fn blend(&mut self, other: &Luma<T>) {
879        *self = *other;
880    }
881}
882
883impl<T: Primitive> Blend for Rgba<T> {
884    fn blend(&mut self, other: &Rgba<T>) {
885        // http://stackoverflow.com/questions/7438263/alpha-compositing-algorithm-blend-modes#answer-11163848
886
887        if other.0[3].is_zero() {
888            return;
889        }
890        if other.0[3] == T::DEFAULT_MAX_VALUE {
891            *self = *other;
892            return;
893        }
894
895        // First, as we don't know what type our pixel is, we have to convert to floats between 0.0 and 1.0
896        let max_t = T::DEFAULT_MAX_VALUE;
897        let max_t = max_t.to_f32().unwrap();
898        let (bg_r, bg_g, bg_b, bg_a) = (self.0[0], self.0[1], self.0[2], self.0[3]);
899        let (fg_r, fg_g, fg_b, fg_a) = (other.0[0], other.0[1], other.0[2], other.0[3]);
900        let (bg_r, bg_g, bg_b, bg_a) = (
901            bg_r.to_f32().unwrap() / max_t,
902            bg_g.to_f32().unwrap() / max_t,
903            bg_b.to_f32().unwrap() / max_t,
904            bg_a.to_f32().unwrap() / max_t,
905        );
906        let (fg_r, fg_g, fg_b, fg_a) = (
907            fg_r.to_f32().unwrap() / max_t,
908            fg_g.to_f32().unwrap() / max_t,
909            fg_b.to_f32().unwrap() / max_t,
910            fg_a.to_f32().unwrap() / max_t,
911        );
912
913        // Work out what the final alpha level will be
914        let alpha_final = bg_a + fg_a - bg_a * fg_a;
915        if alpha_final == 0.0 {
916            return;
917        };
918
919        // We premultiply our channels by their alpha, as this makes it easier to calculate
920        let (bg_r_a, bg_g_a, bg_b_a) = (bg_r * bg_a, bg_g * bg_a, bg_b * bg_a);
921        let (fg_r_a, fg_g_a, fg_b_a) = (fg_r * fg_a, fg_g * fg_a, fg_b * fg_a);
922
923        // Standard formula for src-over alpha compositing
924        let (out_r_a, out_g_a, out_b_a) = (
925            fg_r_a + bg_r_a * (1.0 - fg_a),
926            fg_g_a + bg_g_a * (1.0 - fg_a),
927            fg_b_a + bg_b_a * (1.0 - fg_a),
928        );
929
930        // Unmultiply the channels by our resultant alpha channel
931        let (out_r, out_g, out_b) = (
932            out_r_a / alpha_final,
933            out_g_a / alpha_final,
934            out_b_a / alpha_final,
935        );
936
937        // Cast back to our initial type on return
938        *self = Rgba([
939            NumCast::from(max_t * out_r).unwrap(),
940            NumCast::from(max_t * out_g).unwrap(),
941            NumCast::from(max_t * out_b).unwrap(),
942            NumCast::from(max_t * alpha_final).unwrap(),
943        ]);
944    }
945}
946
947impl<T: Primitive> Blend for Rgb<T> {
948    fn blend(&mut self, other: &Rgb<T>) {
949        *self = *other;
950    }
951}
952
953/// Invert a color
954pub(crate) trait Invert {
955    /// Inverts a color in-place.
956    fn invert(&mut self);
957}
958
959impl<T: Primitive> Invert for LumaA<T> {
960    fn invert(&mut self) {
961        let l = self.0;
962        let max = T::DEFAULT_MAX_VALUE;
963
964        *self = LumaA([max - l[0], l[1]]);
965    }
966}
967
968impl<T: Primitive> Invert for Luma<T> {
969    fn invert(&mut self) {
970        let l = self.0;
971
972        let max = T::DEFAULT_MAX_VALUE;
973        let l1 = max - l[0];
974
975        *self = Luma([l1]);
976    }
977}
978
979impl<T: Primitive> Invert for Rgba<T> {
980    fn invert(&mut self) {
981        let rgba = self.0;
982
983        let max = T::DEFAULT_MAX_VALUE;
984
985        *self = Rgba([max - rgba[0], max - rgba[1], max - rgba[2], rgba[3]]);
986    }
987}
988
989impl<T: Primitive> Invert for Rgb<T> {
990    fn invert(&mut self) {
991        let rgb = self.0;
992
993        let max = T::DEFAULT_MAX_VALUE;
994
995        let r1 = max - rgb[0];
996        let g1 = max - rgb[1];
997        let b1 = max - rgb[2];
998
999        *self = Rgb([r1, g1, b1]);
1000    }
1001}
1002
1003#[cfg(test)]
1004mod tests {
1005    use super::{Luma, LumaA, Pixel, Rgb, Rgba};
1006
1007    #[test]
1008    fn test_apply_with_alpha_rgba() {
1009        let mut rgba = Rgba([0, 0, 0, 0]);
1010        rgba.apply_with_alpha(|s| s, |_| 0xFF);
1011        assert_eq!(rgba, Rgba([0, 0, 0, 0xFF]));
1012    }
1013
1014    #[test]
1015    fn test_apply_with_alpha_rgb() {
1016        let mut rgb = Rgb([0, 0, 0]);
1017        rgb.apply_with_alpha(|s| s, |_| panic!("bug"));
1018        assert_eq!(rgb, Rgb([0, 0, 0]));
1019    }
1020
1021    #[test]
1022    fn test_map_with_alpha_rgba() {
1023        let rgba = Rgba([0, 0, 0, 0]).map_with_alpha(|s| s, |_| 0xFF);
1024        assert_eq!(rgba, Rgba([0, 0, 0, 0xFF]));
1025    }
1026
1027    #[test]
1028    fn test_map_with_alpha_rgb() {
1029        let rgb = Rgb([0, 0, 0]).map_with_alpha(|s| s, |_| panic!("bug"));
1030        assert_eq!(rgb, Rgb([0, 0, 0]));
1031    }
1032
1033    #[test]
1034    fn test_blend_luma_alpha() {
1035        let a = &mut LumaA([255_u8, 255]);
1036        let b = LumaA([255_u8, 255]);
1037        a.blend(&b);
1038        assert_eq!(a.0[0], 255);
1039        assert_eq!(a.0[1], 255);
1040
1041        let a = &mut LumaA([255_u8, 0]);
1042        let b = LumaA([255_u8, 255]);
1043        a.blend(&b);
1044        assert_eq!(a.0[0], 255);
1045        assert_eq!(a.0[1], 255);
1046
1047        let a = &mut LumaA([255_u8, 255]);
1048        let b = LumaA([255_u8, 0]);
1049        a.blend(&b);
1050        assert_eq!(a.0[0], 255);
1051        assert_eq!(a.0[1], 255);
1052
1053        let a = &mut LumaA([255_u8, 0]);
1054        let b = LumaA([255_u8, 0]);
1055        a.blend(&b);
1056        assert_eq!(a.0[0], 255);
1057        assert_eq!(a.0[1], 0);
1058    }
1059
1060    #[test]
1061    fn test_blend_rgba() {
1062        let a = &mut Rgba([255_u8, 255, 255, 255]);
1063        let b = Rgba([255_u8, 255, 255, 255]);
1064        a.blend(&b);
1065        assert_eq!(a.0, [255, 255, 255, 255]);
1066
1067        let a = &mut Rgba([255_u8, 255, 255, 0]);
1068        let b = Rgba([255_u8, 255, 255, 255]);
1069        a.blend(&b);
1070        assert_eq!(a.0, [255, 255, 255, 255]);
1071
1072        let a = &mut Rgba([255_u8, 255, 255, 255]);
1073        let b = Rgba([255_u8, 255, 255, 0]);
1074        a.blend(&b);
1075        assert_eq!(a.0, [255, 255, 255, 255]);
1076
1077        let a = &mut Rgba([255_u8, 255, 255, 0]);
1078        let b = Rgba([255_u8, 255, 255, 0]);
1079        a.blend(&b);
1080        assert_eq!(a.0, [255, 255, 255, 0]);
1081    }
1082
1083    #[test]
1084    fn test_apply_without_alpha_rgba() {
1085        let mut rgba = Rgba([0, 0, 0, 0]);
1086        rgba.apply_without_alpha(|s| s + 1);
1087        assert_eq!(rgba, Rgba([1, 1, 1, 0]));
1088    }
1089
1090    #[test]
1091    fn test_apply_without_alpha_rgb() {
1092        let mut rgb = Rgb([0, 0, 0]);
1093        rgb.apply_without_alpha(|s| s + 1);
1094        assert_eq!(rgb, Rgb([1, 1, 1]));
1095    }
1096
1097    #[test]
1098    fn test_map_without_alpha_rgba() {
1099        let rgba = Rgba([0, 0, 0, 0]).map_without_alpha(|s| s + 1);
1100        assert_eq!(rgba, Rgba([1, 1, 1, 0]));
1101    }
1102
1103    #[test]
1104    fn test_map_without_alpha_rgb() {
1105        let rgb = Rgb([0, 0, 0]).map_without_alpha(|s| s + 1);
1106        assert_eq!(rgb, Rgb([1, 1, 1]));
1107    }
1108
1109    macro_rules! test_lossless_conversion {
1110        ($a:ty, $b:ty, $c:ty) => {
1111            let a: $a = [<$a as Pixel>::Subpixel::DEFAULT_MAX_VALUE >> 2;
1112                <$a as Pixel>::CHANNEL_COUNT as usize]
1113                .into();
1114            let b: $b = a.into_color();
1115            let c: $c = b.into_color();
1116            assert_eq!(a.channels(), c.channels());
1117        };
1118    }
1119
1120    #[test]
1121    fn test_lossless_conversions() {
1122        use super::IntoColor;
1123        use crate::traits::Primitive;
1124
1125        test_lossless_conversion!(Luma<u8>, Luma<u16>, Luma<u8>);
1126        test_lossless_conversion!(LumaA<u8>, LumaA<u16>, LumaA<u8>);
1127        test_lossless_conversion!(Rgb<u8>, Rgb<u16>, Rgb<u8>);
1128        test_lossless_conversion!(Rgba<u8>, Rgba<u16>, Rgba<u8>);
1129    }
1130
1131    #[test]
1132    fn accuracy_conversion() {
1133        use super::{Luma, Pixel, Rgb};
1134        let pixel = Rgb::from([13, 13, 13]);
1135        let Luma([luma]) = pixel.to_luma();
1136        assert_eq!(luma, 13);
1137    }
1138}