spritely 0.1.0

Sprite-related utils for the Image crate.
Documentation
use std::{
    collections::BTreeSet,
    hash::Hash,
    ops::{Deref, DerefMut},
};

use image::{ImageBuffer, Pixel};

use crate::color::Color;
use crate::palette::Palette;

pub trait ImageColors<P: Pixel> {
    fn colors(&self) -> Vec<Color<P>>;
}

pub trait ImageRecolorMut<P: Pixel> {
    fn recolor(&mut self, palette: &Palette<P>);
    fn into_recolored(self, palette: &Palette<P>) -> Self;
}

pub trait ImageRecolorClone<P: Pixel> {
    fn clone_recolored(&self, palette: &Palette<P>) -> Self;
}

impl<P, Container> ImageColors<P> for ImageBuffer<P, Container>
where
    P: Pixel,
    Container: Deref<Target = [P::Subpixel]>,
{
    fn colors(&self) -> Vec<Color<P>> {
        let mut set = BTreeSet::new();

        for pixel in self.pixels() {
            set.insert(Color::from(*pixel));
        }

        set.into_iter().collect()
    }
}

impl<P, Container> ImageRecolorMut<P> for ImageBuffer<P, Container>
where
    P: Pixel,
    P::Subpixel: Hash,
    Container: DerefMut<Target = [P::Subpixel]>,
{
    fn recolor(&mut self, palette: &Palette<P>) {
        for pixel in self.pixels_mut() {
            if let Some(new) = palette.get(&Color::from(*pixel)) {
                pixel.apply2(&new.value(), |_, other| other);
            }
        }
    }

    fn into_recolored(mut self, palette: &Palette<P>) -> Self {
        self.recolor(palette);
        self
    }
}

impl<P, C> ImageRecolorClone<P> for ImageBuffer<P, C>
where
    P: Pixel,
    P::Subpixel: Hash,
    C: Deref<Target = [P::Subpixel]> + DerefMut<Target = [P::Subpixel]> + Clone,
{
    fn clone_recolored(&self, palette: &Palette<P>) -> Self {
        let mut result = self.clone();
        result.recolor(palette);
        result
    }
}