use crate::sample::SampleType;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
#[non_exhaustive]
pub enum PixelLayout {
Rgb,
Rgba,
Gray,
}
impl PixelLayout {
#[must_use]
pub const fn channels(self) -> usize {
match self {
Self::Rgb => 3,
Self::Rgba => 4,
Self::Gray => 1,
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
#[non_exhaustive]
pub enum PixelFormat {
Rgb8,
Rgba8,
Gray8,
Rgb16,
Rgba16,
Gray16,
RgbI16,
RgbaI16,
GrayI16,
}
impl PixelFormat {
#[must_use]
pub const fn layout(self) -> PixelLayout {
match self {
Self::Rgb8 | Self::Rgb16 | Self::RgbI16 => PixelLayout::Rgb,
Self::Rgba8 | Self::Rgba16 | Self::RgbaI16 => PixelLayout::Rgba,
Self::Gray8 | Self::Gray16 | Self::GrayI16 => PixelLayout::Gray,
}
}
#[must_use]
pub const fn sample(self) -> SampleType {
match self {
Self::Rgb8 | Self::Rgba8 | Self::Gray8 => SampleType::U8,
Self::Rgb16 | Self::Rgba16 | Self::Gray16 => SampleType::U16,
Self::RgbI16 | Self::RgbaI16 | Self::GrayI16 => SampleType::I16,
}
}
#[must_use]
pub const fn channels(self) -> usize {
self.layout().channels()
}
#[must_use]
pub const fn bytes_per_sample(self) -> usize {
match self.sample() {
SampleType::U8 => 1,
SampleType::U16 | SampleType::I16 => 2,
}
}
#[must_use]
pub const fn bytes_per_pixel(self) -> usize {
self.channels() * self.bytes_per_sample()
}
}
#[cfg(test)]
mod tests {
use super::{PixelFormat, PixelLayout};
use crate::SampleType;
#[test]
fn signed_sixteen_bit_formats_preserve_layout_and_size() {
for (format, layout, channels) in [
(PixelFormat::RgbI16, PixelLayout::Rgb, 3),
(PixelFormat::RgbaI16, PixelLayout::Rgba, 4),
(PixelFormat::GrayI16, PixelLayout::Gray, 1),
] {
assert_eq!(format.layout(), layout);
assert_eq!(format.sample(), SampleType::I16);
assert_eq!(format.channels(), channels);
assert_eq!(format.bytes_per_sample(), 2);
assert_eq!(format.bytes_per_pixel(), channels * 2);
}
}
}