fast image operations
Diffstat (limited to 'src/indexed.rs')
| -rw-r--r-- | src/indexed.rs | 67 |
1 files changed, 67 insertions, 0 deletions
diff --git a/src/indexed.rs b/src/indexed.rs new file mode 100644 index 0000000..ac56eb6 --- /dev/null +++ b/src/indexed.rs @@ -0,0 +1,67 @@ +//! indexed images! whoo! (palette and `Image<[u8], 1>`, basically.) +#![allow(private_bounds)] +mod builder; + +use crate::Image; + +#[allow(non_camel_case_types)] +trait uint: Copy + TryInto<usize> { + fn nat(self) -> usize { + self.try_into().ok().unwrap() + } +} + +macro_rules! int { + ($($t:ty)+) => { + $(impl uint for $t {})+ + }; +} +int!(u8 u16 u32 u64 u128); + +/// An image with a palette. +#[derive(Clone)] +pub struct IndexedImage<INDEX, PALETTE> { + // likely Box<[u8]>, … + // safety invariant: when INDEX<impl uint>, and PALETTE: Buffer, U must be < len(PALETTE) + buffer: Image<INDEX, 1>, + palette: PALETTE, // likely Box<[[f32; 4]]>, … +} + +impl<I, P> IndexedImage<I, P> { + /// Indexes the palette with each index. + pub fn to<PIXEL: Copy, INDEX: uint, const CHANNELS: usize>( + &self, + ) -> Image<Box<[PIXEL]>, CHANNELS> + where + P: AsRef<[[PIXEL; CHANNELS]]>, + I: AsRef<[INDEX]>, + { + unsafe { + self.buffer.map(|x| { + x.as_ref() + .iter() + .flat_map(|x| self.palette.as_ref()[x.nat()]) + .collect() + }) + } + } + + /// Provides the buffer and palette of this image. + pub fn into_raw_parts(self) -> (Image<I, 1>, P) { + (self.buffer, self.palette) + } + + /// Creates a indexed image from its 1 channel image representation and palette. + pub fn from_raw_parts<INDEX: uint, PIXEL>( + buffer: Image<I, 1>, + palette: P, + ) -> Result<Self, &'static str> + where + I: AsRef<[INDEX]>, + P: AsRef<[PIXEL]>, + { + let good = buffer.chunked().all(|[x]| x.nat() < palette.as_ref().len()); + good.then_some(Self { buffer, palette }) + .ok_or("not all indexes are in palette") + } +} |