use crate::image::Rgba;
pub trait Filter: Send + Sync + 'static {
#[must_use]
fn test(&self, pixel: &Rgba) -> bool;
#[must_use]
fn composite<F>(self, other: F) -> CompositeFilter<Self, F>
where
Self: Sized,
F: Filter,
{
CompositeFilter::new(self, other)
}
}
impl<F> Filter for F
where
F: Fn(&Rgba) -> bool + Send + Sync + 'static,
{
#[inline(always)]
fn test(&self, pixel: &Rgba) -> bool {
self(pixel)
}
}
#[derive(Debug)]
pub struct CompositeFilter<F1, F2>
where
F1: Filter,
F2: Filter,
{
first: F1,
second: F2,
}
impl<F1, F2> CompositeFilter<F1, F2>
where
F1: Filter,
F2: Filter,
{
#[must_use]
pub fn new(first: F1, second: F2) -> Self {
Self { first, second }
}
}
impl<F1, F2> Filter for CompositeFilter<F1, F2>
where
F1: Filter,
F2: Filter,
{
#[inline(always)]
fn test(&self, pixel: &Rgba) -> bool {
self.first.test(pixel) && self.second.test(pixel)
}
}
#[derive(Debug)]
pub struct AlphaFilter {
threshold: u8,
}
impl AlphaFilter {
#[must_use]
pub fn new(threshold: u8) -> Self {
Self { threshold }
}
}
impl Filter for AlphaFilter {
#[inline(always)]
fn test(&self, pixel: &Rgba) -> bool {
pixel[3] > self.threshold
}
}
impl Default for AlphaFilter {
fn default() -> Self {
Self::new(0)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_closure_filter() {
let filter = |pixel: &Rgba| pixel[0] > 128; assert_eq!(filter.test(&[255, 0, 0, 255]), true);
assert_eq!(filter.test(&[129, 0, 0, 255]), true);
assert_eq!(filter.test(&[128, 0, 0, 255]), false);
assert_eq!(filter.test(&[0, 0, 0, 255]), false);
}
#[test]
fn test_composite_filter() {
let alpha_filter = |pixel: &Rgba| pixel[3] != 0;
let green_filter = |pixel: &Rgba| pixel[1] >= 128;
let filter = alpha_filter.composite(green_filter);
assert_eq!(filter.test(&[255, 127, 255, 0]), false); assert_eq!(filter.test(&[255, 255, 255, 0]), false); assert_eq!(filter.test(&[255, 127, 255, 255]), false); assert_eq!(filter.test(&[255, 128, 255, 255]), true); assert_eq!(filter.test(&[255, 255, 255, 255]), true); }
#[test]
fn test_alpha_filter() {
let filter = AlphaFilter::new(127);
assert_eq!(filter.test(&[255, 0, 0, 255]), true);
assert_eq!(filter.test(&[255, 0, 0, 128]), true);
assert_eq!(filter.test(&[255, 0, 0, 127]), false);
assert_eq!(filter.test(&[255, 0, 0, 0]), false);
}
}