1use crate::{JxrError, JxrErrorKind};
4
5#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
7pub enum ChromaSampling {
8 Cs420,
9 Cs422,
10 Cs444,
11}
12
13#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
15pub enum ColorFormat {
16 Luma,
17 Yuv(ChromaSampling),
18 Rgb,
19 Cmyk,
20 CmykDirect,
21 YuvK,
22 Rgbe,
23 NComponent(u16),
24}
25
26impl ColorFormat {
27 #[must_use]
29 pub const fn component_count(self) -> Option<u16> {
30 match self {
31 Self::Luma => Some(1),
32 Self::Yuv(_) | Self::Rgb | Self::Rgbe => Some(3),
33 Self::Cmyk | Self::CmykDirect | Self::YuvK => Some(4),
34 Self::NComponent(0) => None,
35 Self::NComponent(count) => Some(count),
36 }
37 }
38}
39
40#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
42pub enum SampleFormat {
43 Bit1,
44 Unsigned { bits: u8 },
45 Signed { bits: u8 },
46 FixedPoint { bits: u8, fractional_bits: u8 },
47 Float16,
48 Float32,
49}
50
51#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
53pub enum ChannelLayout {
54 Luma,
55 LumaAlpha,
56 Yuv(ChromaSampling),
58 Yuva(ChromaSampling),
60 Rgb,
61 Rgbx,
63 Rgba,
64 Bgr,
65 Bgrx,
67 Bgra,
68 Cmyk,
69 Cmyka,
70 NComponent(u16),
71 NComponentAlpha(u16),
72}
73
74impl ChannelLayout {
75 #[must_use]
76 pub const fn channel_count(self) -> u16 {
77 match self {
78 Self::Luma => 1,
79 Self::LumaAlpha => 2,
80 Self::Yuv(_) | Self::Rgb | Self::Bgr => 3,
81 Self::Yuva(_) | Self::Rgbx | Self::Rgba | Self::Bgrx | Self::Bgra | Self::Cmyk => 4,
82 Self::Cmyka => 5,
83 Self::NComponent(count) => count,
84 Self::NComponentAlpha(count) => count.saturating_add(1),
85 }
86 }
87}
88
89#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
91pub enum StorageKind {
92 BitPacked,
93 U8,
94 U16,
95 I16,
96 I32,
97 F16Bits,
98 F32,
99 PackedU16,
100 PackedU32,
101}
102
103#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
105pub enum PixelFormat {
106 BitPacked(ChannelLayout),
107 U8(ChannelLayout),
108 U16(ChannelLayout),
109 I16(ChannelLayout),
110 I32(ChannelLayout),
111 F16(ChannelLayout),
112 F32(ChannelLayout),
113 Rgb555,
114 Rgb565,
115 Rgb101010,
116 Rgbe,
117}
118
119impl PixelFormat {
120 #[must_use]
121 pub const fn channel_count(self) -> u16 {
122 match self {
123 Self::BitPacked(layout)
124 | Self::U8(layout)
125 | Self::U16(layout)
126 | Self::I16(layout)
127 | Self::I32(layout)
128 | Self::F16(layout)
129 | Self::F32(layout) => layout.channel_count(),
130 Self::Rgb555 | Self::Rgb565 | Self::Rgb101010 | Self::Rgbe => 3,
131 }
132 }
133
134 #[must_use]
135 pub const fn storage_kind(self) -> StorageKind {
136 match self {
137 Self::BitPacked(_) => StorageKind::BitPacked,
138 Self::U8(_) => StorageKind::U8,
139 Self::U16(_) => StorageKind::U16,
140 Self::I16(_) => StorageKind::I16,
141 Self::I32(_) => StorageKind::I32,
142 Self::F16(_) => StorageKind::F16Bits,
143 Self::F32(_) => StorageKind::F32,
144 Self::Rgb555 | Self::Rgb565 => StorageKind::PackedU16,
145 Self::Rgb101010 | Self::Rgbe => StorageKind::PackedU32,
146 }
147 }
148
149 pub fn row_bytes(self, width: u32) -> Result<usize, JxrError> {
151 self.row_bytes_for_channels(width, self.channel_count())
152 }
153
154 pub fn row_bytes_for_channels(self, width: u32, channels: u16) -> Result<usize, JxrError> {
159 let channels = usize::from(channels);
160 if channels == 0 {
161 return Err(JxrError::new(
162 JxrErrorKind::InvalidRequest,
163 "output channel layout",
164 ));
165 }
166 let width = usize::try_from(width).map_err(|_| JxrError::arithmetic("output row width"))?;
167 let elements = width
168 .checked_mul(channels)
169 .ok_or_else(|| JxrError::arithmetic("output row elements"))?;
170 match self.storage_kind() {
171 StorageKind::BitPacked => elements
172 .checked_add(7)
173 .map(|bits| bits / 8)
174 .ok_or_else(|| JxrError::arithmetic("bit-packed row size")),
175 StorageKind::U8 => Ok(elements),
176 StorageKind::U16 | StorageKind::I16 | StorageKind::F16Bits => elements
177 .checked_mul(2)
178 .ok_or_else(|| JxrError::arithmetic("16-bit row size")),
179 StorageKind::I32 | StorageKind::F32 => elements
180 .checked_mul(4)
181 .ok_or_else(|| JxrError::arithmetic("32-bit row size")),
182 StorageKind::PackedU16 => width
183 .checked_mul(2)
184 .ok_or_else(|| JxrError::arithmetic("packed 16-bit row size")),
185 StorageKind::PackedU32 => width
186 .checked_mul(4)
187 .ok_or_else(|| JxrError::arithmetic("packed 32-bit row size")),
188 }
189 }
190}
191
192#[cfg(test)]
193mod tests {
194 use super::{ChannelLayout, ChromaSampling, PixelFormat};
195
196 #[test]
197 fn planar_row_size_uses_plane_channel_count() {
198 let format = PixelFormat::U16(ChannelLayout::Yuv(ChromaSampling::Cs420));
199 assert_eq!(format.row_bytes(7).unwrap(), 42);
200 assert_eq!(format.row_bytes_for_channels(4, 1).unwrap(), 8);
201 }
202}
203
204#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
205pub enum AlphaMode {
206 None,
207 Integrated,
208 Separate,
209}
210
211#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
212pub enum Profile {
213 SubBaseline,
214 Baseline,
215 Main,
216 Advanced,
217 Unknown(u8),
218}
219
220#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
221pub struct Level(pub u8);
222
223#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default)]
225pub enum Orientation {
226 #[default]
227 Identity,
228 MirrorHorizontal,
229 Rotate180,
230 MirrorVertical,
231 Transpose,
232 Rotate90,
233 Transverse,
234 Rotate270,
235}
236
237#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
238pub enum BitstreamMode {
239 Spatial,
240 Frequency,
241}
242
243#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
244pub enum BandPresence {
245 DcOnly,
246 NoHighPass,
247 NoFlexbits,
248 All,
249}
250
251impl BandPresence {
252 #[must_use]
253 pub const fn has_low_pass(self) -> bool {
254 !matches!(self, Self::DcOnly)
255 }
256
257 #[must_use]
258 pub const fn has_high_pass(self) -> bool {
259 matches!(self, Self::NoFlexbits | Self::All)
260 }
261
262 #[must_use]
263 pub const fn has_flexbits(self) -> bool {
264 matches!(self, Self::All)
265 }
266}
267
268#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
269#[repr(u8)]
270pub enum OverlapMode {
271 None = 0,
272 One = 1,
273 Two = 2,
274}