qoi/
types.rs

1use core::convert::TryFrom;
2
3use crate::error::{Error, Result};
4use crate::utils::unlikely;
5
6/// Image color space.
7///
8/// Note: the color space is purely informative. Although it is saved to the
9/// file header, it does not affect encoding/decoding in any way.
10#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, PartialOrd, Ord)]
11#[repr(u8)]
12pub enum ColorSpace {
13    /// sRGB with linear alpha
14    Srgb = 0,
15    /// All channels are linear
16    Linear = 1,
17}
18
19impl ColorSpace {
20    /// Returns true if the color space is sRGB with linear alpha.
21    pub const fn is_srgb(self) -> bool {
22        matches!(self, Self::Srgb)
23    }
24
25    /// Returns true is all channels are linear.
26    pub const fn is_linear(self) -> bool {
27        matches!(self, Self::Linear)
28    }
29
30    /// Converts to an integer (0 if sRGB, 1 if all linear).
31    pub const fn as_u8(self) -> u8 {
32        self as u8
33    }
34}
35
36impl Default for ColorSpace {
37    fn default() -> Self {
38        Self::Srgb
39    }
40}
41
42impl From<ColorSpace> for u8 {
43    #[inline]
44    fn from(colorspace: ColorSpace) -> Self {
45        colorspace as Self
46    }
47}
48
49impl TryFrom<u8> for ColorSpace {
50    type Error = Error;
51
52    #[inline]
53    fn try_from(colorspace: u8) -> Result<Self> {
54        if unlikely(colorspace | 1 != 1) {
55            Err(Error::InvalidColorSpace { colorspace })
56        } else {
57            Ok(if colorspace == 0 { Self::Srgb } else { Self::Linear })
58        }
59    }
60}
61
62/// Number of 8-bit channels in a pixel.
63#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, PartialOrd, Ord)]
64#[repr(u8)]
65pub enum Channels {
66    /// Three 8-bit channels (RGB)
67    Rgb = 3,
68    /// Four 8-bit channels (RGBA)
69    Rgba = 4,
70}
71
72impl Channels {
73    /// Returns true if there are 3 channels (RGB).
74    pub const fn is_rgb(self) -> bool {
75        matches!(self, Self::Rgb)
76    }
77
78    /// Returns true if there are 4 channels (RGBA).
79    pub const fn is_rgba(self) -> bool {
80        matches!(self, Self::Rgba)
81    }
82
83    /// Converts to an integer (3 if RGB, 4 if RGBA).
84    pub const fn as_u8(self) -> u8 {
85        self as u8
86    }
87}
88
89impl Default for Channels {
90    fn default() -> Self {
91        Self::Rgb
92    }
93}
94
95impl From<Channels> for u8 {
96    #[inline]
97    fn from(channels: Channels) -> Self {
98        channels as Self
99    }
100}
101
102impl TryFrom<u8> for Channels {
103    type Error = Error;
104
105    #[inline]
106    fn try_from(channels: u8) -> Result<Self> {
107        if unlikely(channels != 3 && channels != 4) {
108            Err(Error::InvalidChannels { channels })
109        } else {
110            Ok(if channels == 3 { Self::Rgb } else { Self::Rgba })
111        }
112    }
113}