image/
color.rs

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