Skip to main content

jxr_core/
format.rs

1//! JPEG XR source and decoded-output format descriptors.
2
3use crate::{JxrError, JxrErrorKind};
4
5/// Chroma sampling relative to the luma plane.
6#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
7pub enum ChromaSampling {
8    Cs420,
9    Cs422,
10    Cs444,
11}
12
13/// Color organization represented by a JPEG XR image plane.
14#[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    /// Return the number of components, if the declaration is valid.
28    #[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/// Source sample representation before output packing.
41#[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/// Logical ordering of output channels.
52#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
53pub enum ChannelLayout {
54    Luma,
55    LumaAlpha,
56    /// Interleaved Y, U, and V channels at the declared sampling geometry.
57    Yuv(ChromaSampling),
58    /// Interleaved Y, U, V, and alpha channels.
59    Yuva(ChromaSampling),
60    Rgb,
61    /// RGB followed by one zero-valued storage padding component.
62    Rgbx,
63    Rgba,
64    Bgr,
65    /// BGR followed by one zero-valued storage padding component.
66    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/// Type of host storage backing decoded samples.
90#[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/// Requested decoded pixel representation.
104#[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    /// Return the tightly packed byte count for one row.
150    pub fn row_bytes(self, width: u32) -> Result<usize, JxrError> {
151        self.row_bytes_for_channels(width, self.channel_count())
152    }
153
154    /// Return the tightly packed byte count for one plane row.
155    ///
156    /// Planar formats pass the number of interleaved channels stored in that
157    /// plane rather than the channel count of the complete pixel format.
158    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/// Display orientation metadata. Decoders report but do not apply it.
224#[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}