1 | use core::convert::TryFrom; |
2 | |
3 | use crate::error::{Error, Result}; |
4 | use 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)] |
12 | pub enum ColorSpace { |
13 | /// sRGB with linear alpha |
14 | Srgb = 0, |
15 | /// All channels are linear |
16 | Linear = 1, |
17 | } |
18 | |
19 | impl 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 | |
36 | impl Default for ColorSpace { |
37 | fn default() -> Self { |
38 | Self::Srgb |
39 | } |
40 | } |
41 | |
42 | impl From<ColorSpace> for u8 { |
43 | #[inline ] |
44 | fn from(colorspace: ColorSpace) -> Self { |
45 | colorspace as Self |
46 | } |
47 | } |
48 | |
49 | impl 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)] |
65 | pub enum Channels { |
66 | /// Three 8-bit channels (RGB) |
67 | Rgb = 3, |
68 | /// Four 8-bit channels (RGBA) |
69 | Rgba = 4, |
70 | } |
71 | |
72 | impl 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 | |
89 | impl Default for Channels { |
90 | fn default() -> Self { |
91 | Self::Rgb |
92 | } |
93 | } |
94 | |
95 | impl From<Channels> for u8 { |
96 | #[inline ] |
97 | fn from(channels: Channels) -> Self { |
98 | channels as Self |
99 | } |
100 | } |
101 | |
102 | impl 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 | |