use bytemuck::{Pod, Zeroable};
use crate::mode::PixelMode;
const _: () = assert!(std::mem::size_of::<Rgb8>() == Rgb8::BYTES);
const _: () = assert!(std::mem::size_of::<Rgba8>() == Rgba8::BYTES);
const _: () = assert!(std::mem::size_of::<Gray8>() == Gray8::BYTES);
const _: () = assert!(std::mem::size_of::<Cmyk8>() == Cmyk8::BYTES);
const _: () = assert!(std::mem::size_of::<DeviceN8>() == DeviceN8::BYTES);
pub trait Pixel: Copy + Pod + Zeroable + Send + Sync + 'static {
const MODE: PixelMode;
const BYTES: usize;
}
#[repr(C)]
#[derive(Copy, Clone, Debug, PartialEq, Eq, Default, Pod, Zeroable)]
pub struct Rgb8 {
pub r: u8,
pub g: u8,
pub b: u8,
}
impl Pixel for Rgb8 {
const MODE: PixelMode = PixelMode::Rgb8;
const BYTES: usize = 3;
}
#[repr(C)]
#[derive(Copy, Clone, Debug, PartialEq, Eq, Default, Pod, Zeroable)]
pub struct Rgba8 {
pub r: u8,
pub g: u8,
pub b: u8,
pub a: u8,
}
impl Pixel for Rgba8 {
const MODE: PixelMode = PixelMode::Xbgr8;
const BYTES: usize = 4;
}
#[repr(C)]
#[derive(Copy, Clone, Debug, PartialEq, Eq, Default, Pod, Zeroable)]
pub struct Gray8 {
pub v: u8,
}
impl Pixel for Gray8 {
const MODE: PixelMode = PixelMode::Mono8;
const BYTES: usize = 1;
}
#[repr(C)]
#[derive(Copy, Clone, Debug, PartialEq, Eq, Default, Pod, Zeroable)]
pub struct Cmyk8 {
pub c: u8,
pub m: u8,
pub y: u8,
pub k: u8,
}
impl Pixel for Cmyk8 {
const MODE: PixelMode = PixelMode::Cmyk8;
const BYTES: usize = 4;
}
#[repr(C)]
#[derive(Copy, Clone, Debug, PartialEq, Eq, Default, Pod, Zeroable)]
pub struct DeviceN8 {
pub cmyk: Cmyk8,
pub spots: [u8; 4],
}
impl Pixel for DeviceN8 {
const MODE: PixelMode = PixelMode::DeviceN8;
const BYTES: usize = 8;
}
#[derive(Copy, Clone, Debug, Default)]
pub struct AnyColor {
pub bytes: [u8; 8],
pub mode: PixelMode,
}
impl AnyColor {
#[must_use]
pub const fn black(mode: PixelMode) -> Self {
Self {
bytes: [0; 8],
mode,
}
}
#[must_use]
pub const fn white(mode: PixelMode) -> Self {
let mut bytes = [0u8; 8];
match mode {
PixelMode::Mono1 | PixelMode::Mono8 => bytes[0] = 255,
PixelMode::Rgb8 | PixelMode::Bgr8 => {
bytes[0] = 255;
bytes[1] = 255;
bytes[2] = 255;
}
PixelMode::Xbgr8 => {
bytes[0] = 255;
bytes[1] = 255;
bytes[2] = 255;
bytes[3] = 255;
}
PixelMode::Cmyk8 | PixelMode::DeviceN8 => {}
}
Self { bytes, mode }
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn sizes_match_bytes_const() {
assert_eq!(std::mem::size_of::<Rgb8>(), Rgb8::BYTES);
assert_eq!(std::mem::size_of::<Rgba8>(), Rgba8::BYTES);
assert_eq!(std::mem::size_of::<Gray8>(), Gray8::BYTES);
assert_eq!(std::mem::size_of::<Cmyk8>(), Cmyk8::BYTES);
assert_eq!(std::mem::size_of::<DeviceN8>(), DeviceN8::BYTES);
}
#[test]
fn cmyk8_black() {
let px = Cmyk8 {
c: 0,
m: 0,
y: 0,
k: 255,
};
let (r, g, b) = crate::convert::cmyk_to_rgb(px.c, px.m, px.y, px.k);
assert_eq!((r, g, b), (0, 0, 0));
}
#[test]
fn any_color_white_mono1_is_all_bits_set() {
let w = AnyColor::white(PixelMode::Mono1);
assert_eq!(w.bytes[0], 0xFF, "Mono1 white must be 0xFF (all bits = 1)");
}
#[test]
fn any_color_white_xbgr8_sets_padding_byte() {
let w = AnyColor::white(PixelMode::Xbgr8);
assert_eq!(w.bytes, [255, 255, 255, 255, 0, 0, 0, 0]);
}
#[test]
fn any_color_white_cmyk_is_zero() {
let w = AnyColor::white(PixelMode::Cmyk8);
assert_eq!(w.bytes, [0u8; 8]);
}
}