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}
114
115#[derive(Copy, Clone, PartialEq, Eq, Debug)]
116pub enum RawChannels {
117    Rgb,
118    Bgr,
119    Rgba,
120    Argb,
121    Rgbx,
122    Xrgb,
123    Bgra,
124    Abgr,
125    Bgrx,
126    Xbgr,
127}
128
129impl From<Channels> for RawChannels {
130    fn from(value: Channels) -> Self {
131        match value {
132            Channels::Rgb => Self::Rgb,
133            Channels::Rgba => Self::Rgba,
134        }
135    }
136}
137
138impl From<RawChannels> for Channels {
139    fn from(value: RawChannels) -> Self {
140        match value {
141            RawChannels::Rgb
142            | RawChannels::Bgr
143            | RawChannels::Rgbx
144            | RawChannels::Xrgb
145            | RawChannels::Bgrx
146            | RawChannels::Xbgr => Self::Rgb,
147            RawChannels::Rgba | RawChannels::Argb | RawChannels::Bgra | RawChannels::Abgr => {
148                Self::Rgba
149            }
150        }
151    }
152}
153
154impl RawChannels {
155    pub(crate) const fn bytes_per_pixel(self) -> usize {
156        match self {
157            Self::Rgb | Self::Bgr => 3,
158            Self::Rgba
159            | Self::Argb
160            | Self::Rgbx
161            | Self::Xrgb
162            | Self::Bgra
163            | Self::Abgr
164            | Self::Bgrx
165            | Self::Xbgr => 4,
166        }
167    }
168}