pix/
el.rs

1// el.rs        Pixel format.
2//
3// Copyright (c) 2018-2023  Douglas P Lau
4// Copyright (c) 2019-2020  Jeron Aldaron Lau
5//
6//! Module for `pix::el` items
7use crate::chan::{Alpha, Channel, Gamma, Linear, Premultiplied};
8use crate::matte::Matte;
9use crate::ops::Blend;
10use crate::private::Sealed;
11use crate::rgb::Rgb;
12use crate::ColorModel;
13use std::any::TypeId;
14use std::fmt::Debug;
15use std::marker::PhantomData;
16
17/// Pixel [channel], [color model], [alpha] and [gamma] mode.
18///
19/// A pixel can be converted to another format using the [convert] method.
20///
21/// [alpha]: ../chan/trait.Alpha.html
22/// [channel]: ../chan/trait.Channel.html
23/// [color model]: ../trait.ColorModel.html
24/// [convert]: #method.convert
25/// [gamma]: ../chan/trait.Gamma.html
26///
27/// ### Type Alias Naming Scheme
28///
29/// * _Gamma_: `S` for [sRGB] gamma encoding; [linear] if omitted.
30/// * _Color model_: [`Rgb`] / [`Bgr`] / [`Gray`] / [`Cmy`] / [`Hsv`] /
31///                  [`Hsl`] / [`Hwb`] / [`YCbCr`] / [`Matte`].
32/// * _Alpha_: `a` to include alpha channel enabling translucent pixels.
33/// * _Bit depth_: `8` / `16` / `32` for 8-bit integer, 16-bit integer and
34///   32-bit floating-point [channels].
35/// * _Alpha mode_: `p` for [premultiplied]; [straight] if omitted.
36///
37/// [`bgr`]: ../bgr/struct.Bgr.html
38/// [channels]: ../chan/trait.Channel.html
39/// [`cmy`]: ../cmy/struct.Cmy.html
40/// [`gray`]: ../gray/struct.Gray.html
41/// [`hsl`]: ../hsl/struct.Hsl.html
42/// [`hsv`]: ../hsv/struct.Hsv.html
43/// [`hwb`]: ../hwb/struct.Hwb.html
44/// [linear]: ../chan/struct.Linear.html
45/// [`matte`]: ../matte/struct.Matte.html
46/// [premultiplied]: ../chan/struct.Premultiplied.html
47/// [`Rgb`]: ../rgb/struct.Rgb.html
48/// [sRGB]: ../chan/struct.Srgb.html
49/// [straight]: ../chan/struct.Straight.html
50/// [`YCbCr`]: ../ycc/struct.YCbCr.html
51///
52/// This trait is *sealed*, and cannot be implemented outside of this crate.
53pub trait Pixel: Clone + Copy + Debug + Default + PartialEq + Sealed {
54    /// Channel type
55    type Chan: Channel;
56
57    /// Color model
58    type Model: ColorModel;
59
60    /// Alpha mode
61    type Alpha: Alpha;
62
63    /// Gamma mode
64    type Gamma: Gamma;
65
66    /// Make a pixel from a slice of channels.
67    fn from_channels(ch: &[Self::Chan]) -> Self;
68
69    /// Convert from a pixel with a different bit depth.
70    fn from_bit_depth<P>(p: P) -> Self
71    where
72        P: Pixel,
73        Self::Chan: From<P::Chan>;
74
75    /// Get the channels.
76    fn channels(&self) -> &[Self::Chan];
77
78    /// Get the channels mutably.
79    fn channels_mut(&mut self) -> &mut [Self::Chan];
80
81    /// Get the first channel.
82    fn one(self) -> Self::Chan {
83        *self.channels().first().unwrap_or(&Self::Chan::MAX)
84    }
85
86    /// Get a mutable reference to the first channel
87    fn one_mut(&mut self) -> &mut Self::Chan {
88        &mut self.channels_mut()[0]
89    }
90
91    /// Get the second channel.
92    fn two(self) -> Self::Chan {
93        *self.channels().get(1).unwrap_or(&Self::Chan::MAX)
94    }
95
96    /// Get a mutable reference to the second channel
97    fn two_mut(&mut self) -> &mut Self::Chan {
98        &mut self.channels_mut()[1]
99    }
100
101    /// Get the third channel.
102    fn three(self) -> Self::Chan {
103        *self.channels().get(2).unwrap_or(&Self::Chan::MAX)
104    }
105
106    /// Get a mutable reference to the third channel
107    fn three_mut(&mut self) -> &mut Self::Chan {
108        &mut self.channels_mut()[2]
109    }
110
111    /// Get the fourth channel.
112    fn four(self) -> Self::Chan {
113        *self.channels().get(3).unwrap_or(&Self::Chan::MAX)
114    }
115
116    /// Get a mutable reference to the fourth channel
117    fn four_mut(&mut self) -> &mut Self::Chan {
118        &mut self.channels_mut()[3]
119    }
120
121    /// Get the *alpha* channel.
122    ///
123    /// # Example: Get Alpha
124    /// ```
125    /// use pix::chan::Ch16;
126    /// use pix::el::Pixel;
127    /// use pix::gray::Graya16;
128    ///
129    /// let p = Graya16::new(0x7090, 0x6010);
130    /// assert_eq!(p.alpha(), Ch16::new(0x6010));
131    /// ```
132    fn alpha(self) -> Self::Chan {
133        let chan = self.channels();
134        *chan.get(Self::Model::ALPHA).unwrap_or(&Self::Chan::MAX)
135    }
136
137    /// Get a mutable reference to the *alpha* channel.
138    ///
139    /// # Panics
140    ///
141    /// Panics if the pixel does not contain an alpha channel.
142    ///
143    /// # Example: Set Alpha
144    /// ```
145    /// use pix::chan::Ch8;
146    /// use pix::el::Pixel;
147    /// use pix::rgb::Rgba8;
148    ///
149    /// let mut p = Rgba8::new(0xFF, 0x40, 0x80, 0xA5);
150    /// *p.alpha_mut() = Ch8::new(0x4B);
151    /// assert_eq!(p.alpha(), Ch8::new(0x4B));
152    /// ```
153    fn alpha_mut(&mut self) -> &mut Self::Chan {
154        let chan = self.channels_mut();
155        chan.get_mut(Self::Model::ALPHA).unwrap()
156    }
157
158    /// Convert a pixel to another format
159    ///
160    /// * `D` Destination format.
161    fn convert<D>(self) -> D
162    where
163        D: Pixel,
164        D::Chan: From<Self::Chan>,
165    {
166        if TypeId::of::<Self::Model>() == TypeId::of::<D::Model>() {
167            convert_same_model::<D, Self>(self)
168        } else {
169            convert_thru_rgba::<D, Self>(self)
170        }
171    }
172
173    /// Copy a color to a pixel slice
174    fn copy_color(dst: &mut [Self], clr: &Self) {
175        for d in dst.iter_mut() {
176            *d = *clr;
177        }
178    }
179
180    /// Copy a slice to another
181    fn copy_slice(dst: &mut [Self], src: &[Self]) {
182        for (d, s) in dst.iter_mut().zip(src) {
183            *d = *s;
184        }
185    }
186
187    /// Composite a color with a pixel slice
188    fn composite_color<O>(dst: &mut [Self], clr: &Self, op: O)
189    where
190        Self: Pixel<Alpha = Premultiplied, Gamma = Linear>,
191        O: Blend,
192    {
193        for d in dst.iter_mut() {
194            d.composite_channels(clr, op);
195        }
196    }
197
198    /// Composite matte with color to destination pixel slice
199    fn composite_matte<M, O>(dst: &mut [Self], src: &[M], clr: &Self, op: O)
200    where
201        Self: Pixel<Alpha = Premultiplied, Gamma = Linear>,
202        M: Pixel<Chan = Self::Chan, Model = Matte, Gamma = Linear>,
203        O: Blend,
204    {
205        for (d, s) in dst.iter_mut().zip(src) {
206            d.composite_channels_alpha(clr, op, &s.alpha());
207        }
208    }
209
210    /// Composite two slices of pixels
211    fn composite_slice<O>(dst: &mut [Self], src: &[Self], op: O)
212    where
213        Self: Pixel<Alpha = Premultiplied, Gamma = Linear>,
214        O: Blend,
215    {
216        for (d, s) in dst.iter_mut().zip(src) {
217            d.composite_channels(s, op);
218        }
219    }
220
221    /// Composite the channels of two pixels
222    fn composite_channels<O>(&mut self, src: &Self, op: O)
223    where
224        Self: Pixel<Alpha = Premultiplied, Gamma = Linear>,
225        O: Blend,
226    {
227        let da1 = Self::Chan::MAX - self.alpha();
228        let sa1 = Self::Chan::MAX - src.alpha();
229        // circular channels
230        let d_chan = &mut self.channels_mut()[Self::Model::CIRCULAR];
231        let s_chan = &src.channels()[Self::Model::CIRCULAR];
232        d_chan
233            .iter_mut()
234            .zip(s_chan)
235            .for_each(|(d, s)| circ_composite(d, da1, *s, sa1, op));
236        // linear channels
237        let d_chan = &mut self.channels_mut()[Self::Model::LINEAR];
238        let s_chan = &src.channels()[Self::Model::LINEAR];
239        d_chan
240            .iter_mut()
241            .zip(s_chan)
242            .for_each(|(d, s)| O::composite(d, da1, s, sa1));
243        O::composite(self.alpha_mut(), da1, &src.alpha(), sa1);
244    }
245
246    /// Composite the channels of two pixels with alpha
247    fn composite_channels_alpha<O>(
248        &mut self,
249        src: &Self,
250        op: O,
251        alpha: &Self::Chan,
252    ) where
253        Self: Pixel<Alpha = Premultiplied, Gamma = Linear>,
254        O: Blend,
255    {
256        let da1 = Self::Chan::MAX - self.alpha();
257        let sa1 = Self::Chan::MAX - *alpha;
258        // circular channels
259        let d_chan = &mut self.channels_mut()[Self::Model::CIRCULAR];
260        let s_chan = &src.channels()[Self::Model::CIRCULAR];
261        d_chan
262            .iter_mut()
263            .zip(s_chan)
264            .for_each(|(d, s)| circ_composite(d, da1, *s * *alpha, sa1, op));
265        // linear channels
266        let d_chan = &mut self.channels_mut()[Self::Model::LINEAR];
267        let s_chan = &src.channels()[Self::Model::LINEAR];
268        d_chan
269            .iter_mut()
270            .zip(s_chan)
271            .for_each(|(d, s)| O::composite(d, da1, &(*s * *alpha), sa1));
272        O::composite(self.alpha_mut(), da1, &(src.alpha() * *alpha), sa1);
273    }
274}
275
276/// Calculate composite for a circular channel
277#[inline]
278fn circ_composite<C, O>(d: &mut C, da1: C, mut s: C, sa1: C, _op: O)
279where
280    C: Channel,
281    O: Blend,
282{
283    // Circular channels are not premultiplied, so here's the algorithm:
284    // 1. Calcualte `t`, ranging from MIN (dst) to MAX (src), using composite
285    let mut t = C::MIN;
286    O::composite(&mut t, da1, &(C::MAX - sa1), sa1);
287    // 2. If difference > 180 degrees, rotate both by 180 degrees
288    let rotate = s.max(*d) - s.min(*d) > C::MID;
289    if rotate {
290        if s > *d {
291            s = s - C::MID;
292            *d = *d + C::MID;
293        } else {
294            s = s + C::MID;
295            *d = *d - C::MID;
296        }
297    }
298    // 3. Lerp between src and dest.
299    *d = d.lerp(s, t);
300    // 4. If rotated, rotate by 180 degrees
301    if rotate {
302        if *d < C::MID {
303            *d = *d + C::MID;
304        } else {
305            *d = *d - C::MID;
306        }
307    }
308}
309
310/// Rgba pixel type for color model conversions
311pub type PixRgba<P> =
312    Pix4<<P as Pixel>::Chan, Rgb, <P as Pixel>::Alpha, <P as Pixel>::Gamma>;
313
314/// Convert a pixel to another format with the same color model.
315///
316/// * `D` Destination pixel format.
317/// * `S` Source pixel format.
318/// * `src` Source pixel.
319fn convert_same_model<D, S>(src: S) -> D
320where
321    D: Pixel,
322    S: Pixel,
323    D::Chan: From<S::Chan>,
324{
325    let mut dst = D::from_bit_depth(src);
326    if TypeId::of::<S::Alpha>() != TypeId::of::<D::Alpha>()
327        || TypeId::of::<S::Gamma>() != TypeId::of::<D::Gamma>()
328    {
329        let alpha = dst.alpha();
330        let channels = dst.channels_mut();
331        convert_alpha_gamma::<D, S>(channels, alpha);
332    }
333    dst
334}
335
336/// Convert *alpha* / *gamma* to another pixel format
337fn convert_alpha_gamma<D, S>(channels: &mut [D::Chan], alpha: D::Chan)
338where
339    D: Pixel,
340    S: Pixel,
341{
342    for c in channels[D::Model::LINEAR].iter_mut() {
343        *c = S::Gamma::to_linear(*c);
344        if TypeId::of::<S::Alpha>() != TypeId::of::<D::Alpha>() {
345            *c = S::Alpha::decode(*c, alpha);
346            *c = D::Alpha::encode(*c, alpha);
347        }
348        *c = D::Gamma::from_linear(*c);
349    }
350}
351
352/// Convert a pixel to another format thru RGBA.
353///
354/// * `D` Destination pixel format.
355/// * `S` Source pixel format.
356/// * `src` Source pixel.
357fn convert_thru_rgba<D, S>(src: S) -> D
358where
359    D: Pixel,
360    S: Pixel,
361    D::Chan: From<S::Chan>,
362{
363    let rgba = S::Model::into_rgba::<S>(src);
364    let rgba = convert_same_model::<PixRgba<D>, PixRgba<S>>(rgba);
365    D::Model::from_rgba::<D>(rgba)
366}
367
368/// [Pixel] with one [channel] in its [color model].
369///
370/// [channel]: ../chan/trait.Channel.html
371/// [color model]: ../trait.ColorModel.html
372/// [pixel]: trait.Pixel.html
373#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
374#[repr(C)]
375pub struct Pix1<C, M, A, G>
376where
377    C: Channel,
378    M: ColorModel,
379    A: Alpha,
380    G: Gamma,
381{
382    channels: [C; 1],
383    _model: PhantomData<M>,
384    _alpha: PhantomData<A>,
385    _gamma: PhantomData<G>,
386}
387
388impl<C, M, A, G> Pix1<C, M, A, G>
389where
390    C: Channel,
391    M: ColorModel,
392    A: Alpha,
393    G: Gamma,
394{
395    /// Create a one-channel color.
396    ///
397    /// ## Example
398    /// ```
399    /// use pix::gray::Gray8;
400    ///
401    /// let opaque_gray = Gray8::new(128);
402    /// ```
403    pub fn new<H>(one: H) -> Self
404    where
405        C: From<H>,
406    {
407        let channels = [C::from(one); 1];
408        Pix1 {
409            channels,
410            _model: PhantomData,
411            _alpha: PhantomData,
412            _gamma: PhantomData,
413        }
414    }
415}
416
417impl<C, M, A, G> Pixel for Pix1<C, M, A, G>
418where
419    C: Channel,
420    M: ColorModel,
421    A: Alpha,
422    G: Gamma,
423{
424    type Chan = C;
425    type Model = M;
426    type Alpha = A;
427    type Gamma = G;
428
429    fn from_channels(ch: &[C]) -> Self {
430        let one = ch[0];
431        Self::new::<C>(one)
432    }
433
434    fn from_bit_depth<P>(p: P) -> Self
435    where
436        P: Pixel,
437        Self::Chan: From<P::Chan>,
438    {
439        debug_assert_eq!(TypeId::of::<Self::Model>(), TypeId::of::<P::Model>());
440        let one = Self::Chan::from(p.one());
441        Self::new::<Self::Chan>(one)
442    }
443
444    fn channels(&self) -> &[Self::Chan] {
445        &self.channels
446    }
447
448    fn channels_mut(&mut self) -> &mut [Self::Chan] {
449        &mut self.channels
450    }
451}
452
453/// [Pixel] with two [channel]s in its [color model].
454///
455/// [channel]: ../chan/trait.Channel.html
456/// [color model]: ../trait.ColorModel.html
457/// [pixel]: trait.Pixel.html
458#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
459#[repr(C)]
460pub struct Pix2<C, M, A, G>
461where
462    C: Channel,
463    M: ColorModel,
464    A: Alpha,
465    G: Gamma,
466{
467    channels: [C; 2],
468    _model: PhantomData<M>,
469    _alpha: PhantomData<A>,
470    _gamma: PhantomData<G>,
471}
472
473impl<C, M, A, G> Pix2<C, M, A, G>
474where
475    C: Channel,
476    M: ColorModel,
477    A: Alpha,
478    G: Gamma,
479{
480    /// Create a two-channel color.
481    ///
482    /// ## Example
483    /// ```
484    /// use pix::gray::Graya8;
485    ///
486    /// let translucent_gray = Graya8::new(128, 200);
487    /// ```
488    pub fn new<H>(one: H, two: H) -> Self
489    where
490        C: From<H>,
491    {
492        let one = C::from(one);
493        let two = C::from(two);
494        let channels = [one, two];
495        Pix2 {
496            channels,
497            _model: PhantomData,
498            _alpha: PhantomData,
499            _gamma: PhantomData,
500        }
501    }
502}
503
504impl<C, M, A, G> Pixel for Pix2<C, M, A, G>
505where
506    C: Channel,
507    M: ColorModel,
508    A: Alpha,
509    G: Gamma,
510{
511    type Chan = C;
512    type Model = M;
513    type Alpha = A;
514    type Gamma = G;
515
516    fn from_channels(ch: &[C]) -> Self {
517        let one = ch[0];
518        let two = ch[1];
519        Self::new::<C>(one, two)
520    }
521
522    fn from_bit_depth<P>(p: P) -> Self
523    where
524        P: Pixel,
525        Self::Chan: From<P::Chan>,
526    {
527        debug_assert_eq!(TypeId::of::<Self::Model>(), TypeId::of::<P::Model>());
528        let one = Self::Chan::from(p.one());
529        let two = Self::Chan::from(p.two());
530        Self::new::<Self::Chan>(one, two)
531    }
532
533    fn channels(&self) -> &[Self::Chan] {
534        &self.channels
535    }
536
537    fn channels_mut(&mut self) -> &mut [Self::Chan] {
538        &mut self.channels
539    }
540}
541
542/// [Pixel] with three [channel]s in its [color model].
543///
544/// [channel]: ../chan/trait.Channel.html
545/// [color model]: ../trait.ColorModel.html
546/// [pixel]: trait.Pixel.html
547#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
548#[repr(C)]
549pub struct Pix3<C, M, A, G>
550where
551    C: Channel,
552    M: ColorModel,
553    A: Alpha,
554    G: Gamma,
555{
556    channels: [C; 3],
557    _model: PhantomData<M>,
558    _alpha: PhantomData<A>,
559    _gamma: PhantomData<G>,
560}
561
562impl<C, M, A, G> Pix3<C, M, A, G>
563where
564    C: Channel,
565    M: ColorModel,
566    A: Alpha,
567    G: Gamma,
568{
569    /// Create a three-channel color.
570    ///
571    /// ## Example
572    /// ```
573    /// use pix::rgb::Rgb8;
574    ///
575    /// let rgb = Rgb8::new(128, 200, 255);
576    /// ```
577    pub fn new<H>(one: H, two: H, three: H) -> Self
578    where
579        C: From<H>,
580    {
581        let one = C::from(one);
582        let two = C::from(two);
583        let three = C::from(three);
584        let channels = [one, two, three];
585        Pix3 {
586            channels,
587            _model: PhantomData,
588            _alpha: PhantomData,
589            _gamma: PhantomData,
590        }
591    }
592}
593
594impl<C, M, A, G> Pixel for Pix3<C, M, A, G>
595where
596    C: Channel,
597    M: ColorModel,
598    A: Alpha,
599    G: Gamma,
600{
601    type Chan = C;
602    type Model = M;
603    type Alpha = A;
604    type Gamma = G;
605
606    fn from_channels(ch: &[C]) -> Self {
607        let one = ch[0];
608        let two = ch[1];
609        let three = ch[2];
610        Self::new::<C>(one, two, three)
611    }
612
613    fn from_bit_depth<P>(p: P) -> Self
614    where
615        P: Pixel,
616        Self::Chan: From<P::Chan>,
617    {
618        debug_assert_eq!(TypeId::of::<Self::Model>(), TypeId::of::<P::Model>());
619        let one = Self::Chan::from(p.one());
620        let two = Self::Chan::from(p.two());
621        let three = Self::Chan::from(p.three());
622        Self::new::<Self::Chan>(one, two, three)
623    }
624
625    fn channels(&self) -> &[Self::Chan] {
626        &self.channels
627    }
628
629    fn channels_mut(&mut self) -> &mut [Self::Chan] {
630        &mut self.channels
631    }
632}
633
634/// [Pixel] with four [channel]s in its [color model].
635///
636/// [channel]: ../chan/trait.Channel.html
637/// [color model]: ../trait.ColorModel.html
638/// [pixel]: trait.Pixel.html
639#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
640#[repr(C)]
641pub struct Pix4<C, M, A, G>
642where
643    C: Channel,
644    M: ColorModel,
645    A: Alpha,
646    G: Gamma,
647{
648    channels: [C; 4],
649    _model: PhantomData<M>,
650    _alpha: PhantomData<A>,
651    _gamma: PhantomData<G>,
652}
653
654impl<C, M, A, G> Pix4<C, M, A, G>
655where
656    C: Channel,
657    M: ColorModel,
658    A: Alpha,
659    G: Gamma,
660{
661    /// Create a four-channel color.
662    ///
663    /// ## Example
664    /// ```
665    /// use pix::rgb::Rgba8;
666    ///
667    /// let rgba = Rgba8::new(128, 200, 255, 128);
668    /// ```
669    pub fn new<H>(one: H, two: H, three: H, four: H) -> Self
670    where
671        C: From<H>,
672    {
673        let one = C::from(one);
674        let two = C::from(two);
675        let three = C::from(three);
676        let four = C::from(four);
677        let channels = [one, two, three, four];
678        Pix4 {
679            channels,
680            _model: PhantomData,
681            _alpha: PhantomData,
682            _gamma: PhantomData,
683        }
684    }
685}
686
687impl<C, M, A, G> Pixel for Pix4<C, M, A, G>
688where
689    C: Channel,
690    M: ColorModel,
691    A: Alpha,
692    G: Gamma,
693{
694    type Chan = C;
695    type Model = M;
696    type Alpha = A;
697    type Gamma = G;
698
699    fn from_channels(ch: &[C]) -> Self {
700        let one = ch[0];
701        let two = ch[1];
702        let three = ch[2];
703        let four = ch[3];
704        Self::new::<C>(one, two, three, four)
705    }
706
707    fn from_bit_depth<P>(p: P) -> Self
708    where
709        P: Pixel,
710        Self::Chan: From<P::Chan>,
711    {
712        debug_assert_eq!(TypeId::of::<Self::Model>(), TypeId::of::<P::Model>());
713        let one = Self::Chan::from(p.one());
714        let two = Self::Chan::from(p.two());
715        let three = Self::Chan::from(p.three());
716        let four = Self::Chan::from(p.four());
717        Self::new::<Self::Chan>(one, two, three, four)
718    }
719
720    fn channels(&self) -> &[Self::Chan] {
721        &self.channels
722    }
723
724    fn channels_mut(&mut self) -> &mut [Self::Chan] {
725        &mut self.channels
726    }
727}
728
729#[cfg(test)]
730mod test {
731    use crate::el::*;
732    use crate::gray::*;
733    use crate::matte::*;
734    use crate::rgb::*;
735
736    #[test]
737    fn check_sizes() {
738        assert_eq!(std::mem::size_of::<Matte8>(), 1);
739        assert_eq!(std::mem::size_of::<Matte16>(), 2);
740        assert_eq!(std::mem::size_of::<Matte32>(), 4);
741        assert_eq!(std::mem::size_of::<SGray8>(), 1);
742        assert_eq!(std::mem::size_of::<SGray16>(), 2);
743        assert_eq!(std::mem::size_of::<SGray32>(), 4);
744        assert_eq!(std::mem::size_of::<SGraya8>(), 2);
745        assert_eq!(std::mem::size_of::<SGraya16>(), 4);
746        assert_eq!(std::mem::size_of::<SGraya32>(), 8);
747        assert_eq!(std::mem::size_of::<Rgb8>(), 3);
748        assert_eq!(std::mem::size_of::<Rgb16>(), 6);
749        assert_eq!(std::mem::size_of::<Rgb32>(), 12);
750        assert_eq!(std::mem::size_of::<Rgba8>(), 4);
751        assert_eq!(std::mem::size_of::<Rgba16>(), 8);
752        assert_eq!(std::mem::size_of::<Rgba32>(), 16);
753    }
754
755    #[test]
756    fn gray_to_rgb() {
757        assert_eq!(SRgb8::new(0xD9, 0xD9, 0xD9), SGray8::new(0xD9).convert(),);
758        assert_eq!(
759            SRgb8::new(0x33, 0x33, 0x33),
760            SGray16::new(0x337F).convert(),
761        );
762        assert_eq!(SRgb8::new(0x40, 0x40, 0x40), SGray32::new(0.25).convert(),);
763        assert_eq!(
764            SRgb16::new(0x2929, 0x2929, 0x2929),
765            SGray8::new(0x29).convert(),
766        );
767        assert_eq!(
768            SRgb16::new(0x5593, 0x5593, 0x5593),
769            SGray16::new(0x5593).convert(),
770        );
771        assert_eq!(
772            SRgb16::new(0xFFFF, 0xFFFF, 0xFFFF),
773            SGray32::new(1.0).convert(),
774        );
775        assert_eq!(
776            SRgb32::new(0.5019608, 0.5019608, 0.5019608),
777            SGray8::new(0x80).convert(),
778        );
779        assert_eq!(
780            SRgb32::new(0.75001144, 0.75001144, 0.75001144),
781            SGray16::new(0xC000).convert(),
782        );
783        assert_eq!(SRgb32::new(0.33, 0.33, 0.33), SGray32::new(0.33).convert(),);
784    }
785
786    #[test]
787    fn linear_to_srgb() {
788        assert_eq!(
789            SRgb8::new(0xEF, 0x8C, 0xC7),
790            Rgb8::new(0xDC, 0x43, 0x91).convert()
791        );
792        assert_eq!(
793            SRgb8::new(0x66, 0xF4, 0xB5),
794            Rgb16::new(0x2205, 0xE699, 0x7654).convert()
795        );
796        assert_eq!(
797            SRgb8::new(0xBC, 0x89, 0xE0),
798            Rgb32::new(0.5, 0.25, 0.75).convert()
799        );
800    }
801
802    #[test]
803    fn srgb_to_linear() {
804        assert_eq!(
805            Rgb8::new(0xDC, 0x43, 0x92),
806            SRgb8::new(0xEF, 0x8C, 0xC7).convert(),
807        );
808        assert_eq!(
809            Rgb8::new(0x22, 0xE7, 0x76),
810            SRgb16::new(0x6673, 0xF453, 0xB593).convert(),
811        );
812        assert_eq!(
813            Rgb8::new(0x37, 0x0D, 0x85),
814            SRgb32::new(0.5, 0.25, 0.75).convert(),
815        );
816    }
817
818    #[test]
819    fn straight_to_premultiplied() {
820        assert_eq!(
821            Rgba8p::new(0x10, 0x20, 0x40, 0x80),
822            Rgba8::new(0x20, 0x40, 0x80, 0x80).convert(),
823        );
824        assert_eq!(
825            Rgba8p::new(0x04, 0x10, 0x20, 0x40),
826            Rgba16::new(0x1000, 0x4000, 0x8000, 0x4000).convert(),
827        );
828        assert_eq!(
829            Rgba8p::new(0x60, 0xBF, 0x8F, 0xBF),
830            Rgba32::new(0.5, 1.0, 0.75, 0.75).convert(),
831        );
832    }
833
834    #[test]
835    fn premultiplied_to_straight() {
836        assert_eq!(
837            Rgba8::new(0x40, 0x80, 0xFF, 0x80),
838            Rgba8p::new(0x20, 0x40, 0x80, 0x80).convert(),
839        );
840        assert_eq!(
841            Rgba8::new(0x40, 0xFF, 0x80, 0x40),
842            Rgba16p::new(0x1000, 0x4000, 0x2000, 0x4000).convert(),
843        );
844        assert_eq!(
845            Rgba8::new(0xAB, 0x55, 0xFF, 0xBF),
846            Rgba32p::new(0.5, 0.25, 0.75, 0.75).convert(),
847        );
848    }
849
850    #[test]
851    fn straight_to_premultiplied_srgb() {
852        assert_eq!(
853            SRgba8p::new(0x16, 0x2A, 0x5C, 0x80),
854            SRgba8::new(0x20, 0x40, 0x80, 0x80).convert(),
855        );
856        assert_eq!(
857            SRgba8p::new(0x0D, 0x1C, 0x40, 0x40),
858            SRgba16::new(0x2000, 0x4000, 0x8000, 0x4000).convert(),
859        );
860        assert_eq!(
861            SRgba8p::new(0x70, 0xE0, 0xA7, 0xBF),
862            SRgba32::new(0.5, 1.0, 0.75, 0.75).convert(),
863        );
864    }
865}