| 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 | |