mod sample_sealed {
pub trait Sealed {}
impl Sealed for u8 {}
impl Sealed for u16 {}
}
pub trait Sample:
sample_sealed::Sealed + Copy + Default + Ord + core::fmt::Debug + 'static
{
const STORAGE_BITS: u32;
}
impl Sample for u8 {
const STORAGE_BITS: u32 = 8;
}
impl Sample for u16 {
const STORAGE_BITS: u32 = 16;
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
#[non_exhaustive]
pub enum ColorModel {
Gray,
GrayAlpha,
Rgb,
Rgba,
Cmyk,
Bilevel,
Indexed,
}
mod pixel_sealed {
pub trait Sealed {}
}
pub trait Pixel: pixel_sealed::Sealed + Copy + 'static {
type Sample: Sample;
const CHANNELS: usize;
const MODEL: ColorModel;
const BYTES_PER_PIXEL: usize = Self::CHANNELS * core::mem::size_of::<Self::Sample>();
}
macro_rules! define_pixels {
($(
$(#[$meta:meta])*
$name:ident => $sample:ty, $channels:expr, $model:expr;
)*) => {
$(
$(#[$meta])*
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct $name;
impl pixel_sealed::Sealed for $name {}
impl Pixel for $name {
type Sample = $sample;
const CHANNELS: usize = $channels;
const MODEL: ColorModel = $model;
}
)*
};
}
define_pixels! {
Gray8 => u8, 1, ColorModel::Gray;
Bilevel => u8, 1, ColorModel::Bilevel;
Indexed8 => u8, 1, ColorModel::Indexed;
Rgb8 => u8, 3, ColorModel::Rgb;
Rgba8 => u8, 4, ColorModel::Rgba;
Cmyk8 => u8, 4, ColorModel::Cmyk;
Gray16 => u16, 1, ColorModel::Gray;
Rgb16 => u16, 3, ColorModel::Rgb;
Rgba16 => u16, 4, ColorModel::Rgba;
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn sample_storage_bits() {
assert_eq!(<u8 as Sample>::STORAGE_BITS, 8);
assert_eq!(<u16 as Sample>::STORAGE_BITS, 16);
}
#[test]
fn pixel_layout_constants() {
assert_eq!((Gray8::CHANNELS, Gray8::BYTES_PER_PIXEL), (1, 1));
assert_eq!(Gray8::MODEL, ColorModel::Gray);
assert_eq!((Bilevel::CHANNELS, Bilevel::BYTES_PER_PIXEL), (1, 1));
assert_eq!(Bilevel::MODEL, ColorModel::Bilevel);
assert_eq!((Indexed8::CHANNELS, Indexed8::BYTES_PER_PIXEL), (1, 1));
assert_eq!(Indexed8::MODEL, ColorModel::Indexed);
assert_eq!((Rgb8::CHANNELS, Rgb8::BYTES_PER_PIXEL), (3, 3));
assert_eq!(Rgb8::MODEL, ColorModel::Rgb);
assert_eq!((Rgba8::CHANNELS, Rgba8::BYTES_PER_PIXEL), (4, 4));
assert_eq!(Rgba8::MODEL, ColorModel::Rgba);
assert_eq!((Cmyk8::CHANNELS, Cmyk8::BYTES_PER_PIXEL), (4, 4));
assert_eq!(Cmyk8::MODEL, ColorModel::Cmyk);
assert_eq!((Gray16::CHANNELS, Gray16::BYTES_PER_PIXEL), (1, 2));
assert_eq!((Rgb16::CHANNELS, Rgb16::BYTES_PER_PIXEL), (3, 6));
assert_eq!((Rgba16::CHANNELS, Rgba16::BYTES_PER_PIXEL), (4, 8));
}
#[test]
fn distinct_models_share_channel_count() {
assert_eq!(Rgba8::CHANNELS, Cmyk8::CHANNELS);
assert_ne!(Rgba8::MODEL, Cmyk8::MODEL);
assert_eq!(Gray8::CHANNELS, Indexed8::CHANNELS);
assert_ne!(Gray8::MODEL, Indexed8::MODEL);
assert_ne!(Gray8::MODEL, Bilevel::MODEL);
}
}