Skip to main content

j2k_core/
pixel.rs

1// SPDX-License-Identifier: MIT OR Apache-2.0
2
3use crate::sample::SampleType;
4
5/// Channel layout independent of sample width.
6#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
7#[non_exhaustive]
8pub enum PixelLayout {
9    /// Three-channel red, green, blue layout.
10    Rgb,
11    /// Four-channel red, green, blue, alpha layout.
12    Rgba,
13    /// Single-channel grayscale layout.
14    Gray,
15}
16
17impl PixelLayout {
18    /// Return the number of channels in this layout.
19    #[must_use]
20    pub const fn channels(self) -> usize {
21        match self {
22            Self::Rgb => 3,
23            Self::Rgba => 4,
24            Self::Gray => 1,
25        }
26    }
27}
28
29/// Concrete interleaved pixel format.
30#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
31#[non_exhaustive]
32pub enum PixelFormat {
33    /// Interleaved 8-bit RGB.
34    Rgb8,
35    /// Interleaved 8-bit RGBA.
36    Rgba8,
37    /// 8-bit grayscale.
38    Gray8,
39    /// Interleaved 16-bit RGB.
40    Rgb16,
41    /// Interleaved 16-bit RGBA.
42    Rgba16,
43    /// 16-bit grayscale.
44    Gray16,
45    /// Interleaved signed 16-bit RGB.
46    RgbI16,
47    /// Interleaved signed 16-bit RGBA.
48    RgbaI16,
49    /// Signed 16-bit grayscale.
50    GrayI16,
51}
52
53impl PixelFormat {
54    /// Return the channel layout for this pixel format.
55    #[must_use]
56    pub const fn layout(self) -> PixelLayout {
57        match self {
58            Self::Rgb8 | Self::Rgb16 | Self::RgbI16 => PixelLayout::Rgb,
59            Self::Rgba8 | Self::Rgba16 | Self::RgbaI16 => PixelLayout::Rgba,
60            Self::Gray8 | Self::Gray16 | Self::GrayI16 => PixelLayout::Gray,
61        }
62    }
63
64    /// Return the integer sample type for this pixel format.
65    #[must_use]
66    pub const fn sample(self) -> SampleType {
67        match self {
68            Self::Rgb8 | Self::Rgba8 | Self::Gray8 => SampleType::U8,
69            Self::Rgb16 | Self::Rgba16 | Self::Gray16 => SampleType::U16,
70            Self::RgbI16 | Self::RgbaI16 | Self::GrayI16 => SampleType::I16,
71        }
72    }
73
74    /// Return the number of channels per pixel.
75    #[must_use]
76    pub const fn channels(self) -> usize {
77        self.layout().channels()
78    }
79
80    /// Return the number of bytes in one channel sample.
81    #[must_use]
82    pub const fn bytes_per_sample(self) -> usize {
83        match self.sample() {
84            SampleType::U8 => 1,
85            SampleType::U16 | SampleType::I16 => 2,
86        }
87    }
88
89    /// Return the number of bytes in one interleaved pixel.
90    #[must_use]
91    pub const fn bytes_per_pixel(self) -> usize {
92        self.channels() * self.bytes_per_sample()
93    }
94}
95
96#[cfg(test)]
97mod tests {
98    use super::{PixelFormat, PixelLayout};
99    use crate::SampleType;
100
101    #[test]
102    fn signed_sixteen_bit_formats_preserve_layout_and_size() {
103        for (format, layout, channels) in [
104            (PixelFormat::RgbI16, PixelLayout::Rgb, 3),
105            (PixelFormat::RgbaI16, PixelLayout::Rgba, 4),
106            (PixelFormat::GrayI16, PixelLayout::Gray, 1),
107        ] {
108            assert_eq!(format.layout(), layout);
109            assert_eq!(format.sample(), SampleType::I16);
110            assert_eq!(format.channels(), channels);
111            assert_eq!(format.bytes_per_sample(), 2);
112            assert_eq!(format.bytes_per_pixel(), channels * 2);
113        }
114    }
115}