use crate::*;
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[derive(Debug, Clone, PartialEq, PartialOrd)]
pub struct Pixel<C: Color>(Box<[f64]>, std::marker::PhantomData<C>);
impl<C: Color> AsRef<[f64]> for Pixel<C> {
fn as_ref(&self) -> &[f64] {
self.0.as_ref()
}
}
impl<C: Color> AsMut<[f64]> for Pixel<C> {
fn as_mut(&mut self) -> &mut [f64] {
self.0.as_mut()
}
}
impl<C: Color> Default for Pixel<C> {
fn default() -> Self {
Pixel::new()
}
}
impl<C: Color> From<&[f64]> for Pixel<C> {
fn from(data: &[f64]) -> Self {
let mut px = Pixel::new();
px.copy_from_slice(data);
px
}
}
impl<C: Color> From<Vec<f64>> for Pixel<C> {
fn from(data: Vec<f64>) -> Self {
let data = data.into_boxed_slice();
Pixel(data, std::marker::PhantomData)
}
}
impl<C: Color> Pixel<C> {
pub fn new() -> Pixel<C> {
let data = match C::CHANNELS {
1 => Box::new([0.0; 1]) as Box<[f64]>,
2 => Box::new([0.0; 2]),
3 => Box::new([0.0; 3]),
4 => Box::new([0.0; 4]),
5 => Box::new([0.0; 5]),
_ => vec![0.0; C::CHANNELS].into_boxed_slice(),
};
let mut px = Pixel(data, std::marker::PhantomData);
px.with_alpha(1.0);
px
}
pub fn with_color<D: Color>(self) -> Pixel<D> {
assert!(C::CHANNELS == D::CHANNELS);
Pixel(self.0, std::marker::PhantomData)
}
pub fn data(&self) -> Data<f64, C> {
Data::new(self.as_ref())
}
pub fn data_mut(&mut self) -> DataMut<f64, C> {
DataMut::new(self.as_mut())
}
pub fn into_vec(self) -> Vec<f64> {
self.0.into_vec()
}
pub fn to_vec(&self) -> Vec<f64> {
self.0.to_vec()
}
pub fn fill<T: Type>(&mut self, x: T) -> &mut Self {
self.0.iter_mut().for_each(|a| *a = x.to_norm());
self
}
pub fn len(&self) -> Channel {
C::CHANNELS
}
pub fn is_empty(&self) -> bool {
self.len() == 0
}
pub fn clamp(&mut self) -> &mut Self {
self.map(|x| x.clamp(0., 1.))
}
pub fn clamped(mut self) -> Self {
self.clamp();
self
}
pub fn is_alpha(&self, index: Channel) -> bool {
if let Some(alpha) = C::ALPHA {
return alpha == index;
}
false
}
pub fn alpha(&self) -> Option<f64> {
C::ALPHA.map(|x| self[x])
}
pub fn with_alpha(&mut self, value: f64) -> &mut Self {
if let Some(alpha) = C::ALPHA {
(*self)[alpha] = value
}
self
}
pub fn convert_to<D: Color>(&self, dest: &mut Pixel<D>) {
let mut tmp = Pixel::new();
C::to_rgb(self, &mut tmp);
D::from_rgb(&tmp, dest);
}
pub fn convert<D: Color>(&self) -> Pixel<D> {
let mut dest = Pixel::new();
self.convert_to(&mut dest);
dest
}
#[inline]
pub fn copy_from_slice<T: Type>(&mut self, data: impl AsRef<[T]>) -> &mut Self {
let data = data.as_ref();
self.0.iter_mut().enumerate().for_each(|(i, x)| {
*x = data[i].to_norm();
});
self
}
#[inline]
pub fn copy_from_data<T: Type>(&mut self, data: &Data<T, C>) -> &mut Self {
let data = data.as_ref();
self.0.iter_mut().enumerate().for_each(|(i, x)| {
*x = data[i].to_norm();
});
self
}
pub fn convert_from_data<T: Type, D: Color>(&mut self, data: &Data<T, D>) {
Pixel::from_data(data).convert_to(self)
}
pub fn convert_to_data<T: Type, D: Color>(&self, data: &mut DataMut<T, D>) {
let d = self.convert::<D>();
d.copy_to_slice(data)
}
pub fn copy_to_slice<T: Type>(&self, mut data: impl AsMut<[T]>) {
let data = data.as_mut();
self.0.iter().enumerate().for_each(|(i, x)| {
data[i] = T::from_norm(*x);
});
}
pub fn from_slice<T: Type>(data: impl AsRef<[T]>) -> Pixel<C> {
let mut px = Pixel::new();
px.copy_from_slice(data);
px
}
pub fn from_data<T: Type>(data: &Data<T, C>) -> Pixel<C> {
let mut px = Pixel::new();
px.copy_from_slice(data);
px
}
pub fn copy_from(&mut self, other: &Pixel<C>) -> &mut Self {
self.map2(other, |_, b| b)
}
pub fn blend_alpha(&mut self) -> &mut Self {
if let Some(index) = C::ALPHA {
let alpha = self[index];
self.map(|x| x * alpha);
(*self)[index] = 1.0;
}
self
}
pub fn map(&mut self, f: impl Fn(f64) -> f64) -> &mut Self {
self.iter_mut().for_each(|x| *x = f(*x));
self
}
pub fn map2(&mut self, other: &Pixel<C>, f: impl Fn(f64, f64) -> f64) -> &mut Self {
self.iter_mut()
.zip(other.iter())
.for_each(|(x, y)| *x = f(*x, *y));
self
}
pub fn for_each(&self, mut f: impl FnMut(usize, f64)) {
for i in 0..self.len() {
f(i, self[i])
}
}
pub fn iter(&self) -> impl Iterator<Item = &f64> {
let iter = self.0.iter();
let alpha = C::ALPHA.unwrap_or(std::usize::MAX);
iter.enumerate()
.filter_map(move |(idx, item)| if idx != alpha { Some(item) } else { None })
}
pub fn iter_mut(&mut self) -> impl Iterator<Item = &mut f64> {
let iter = self.0.iter_mut();
let alpha = C::ALPHA.unwrap_or(std::usize::MAX);
iter.enumerate()
.filter_map(move |(idx, item)| if idx != alpha { Some(item) } else { None })
}
pub fn gamma(&mut self, value: f64) -> &mut Self {
self.map(|x| x.powf(value))
}
pub fn gamma_log(&mut self) -> &mut Self {
self.gamma(1. / 2.2)
}
pub fn gamma_lin(&mut self) -> &mut Self {
self.gamma(2.2)
}
}
impl<T: Type, C: Color> std::iter::FromIterator<T> for Pixel<C> {
fn from_iter<I: IntoIterator<Item = T>>(iter: I) -> Self {
Pixel(
iter.into_iter().map(|x| x.to_norm()).collect(),
std::marker::PhantomData,
)
}
}
impl<C: Color> IntoIterator for Pixel<C> {
type Item = f64;
type IntoIter = std::vec::IntoIter<Self::Item>;
fn into_iter(self) -> Self::IntoIter {
self.0.into_vec().into_iter()
}
}
impl<C: Color> std::ops::Index<Channel> for Pixel<C> {
type Output = f64;
fn index(&self, index: Channel) -> &f64 {
&self.0[index]
}
}
impl<'a, C: Color> std::ops::Index<Channel> for &'a Pixel<C> {
type Output = f64;
fn index(&self, index: Channel) -> &f64 {
&self.0[index]
}
}
impl<'a, C: Color> std::ops::Index<Channel> for &'a mut Pixel<C> {
type Output = f64;
fn index(&self, index: Channel) -> &f64 {
&self.0[index]
}
}
impl<C: Color> std::ops::IndexMut<Channel> for Pixel<C> {
fn index_mut(&mut self, index: Channel) -> &mut f64 {
&mut self.0[index]
}
}
impl<'a, C: Color> std::ops::IndexMut<Channel> for &'a mut Pixel<C> {
fn index_mut(&mut self, index: Channel) -> &mut f64 {
&mut self.0[index]
}
}
impl<T: Type, C: Color> std::ops::Add<T> for Pixel<C> {
type Output = Pixel<C>;
fn add(mut self, other: T) -> Pixel<C> {
self.map(|x| x + other.to_norm());
self
}
}
impl<'a, T: Type, C: Color> std::ops::Add<T> for &'a Pixel<C> {
type Output = Pixel<C>;
fn add(self, other: T) -> Pixel<C> {
let mut dest = self.clone();
dest.map(|x| x + other.to_norm());
dest
}
}
impl<'a, C: Color> std::ops::Add<&'a Pixel<C>> for Pixel<C> {
type Output = Pixel<C>;
fn add(mut self, other: &'a Pixel<C>) -> Pixel<C> {
self.map2(other, |x, y| x + y);
self
}
}
impl<'a, C: Color> std::ops::Add<&'a Pixel<C>> for &'a Pixel<C> {
type Output = Pixel<C>;
fn add(self, other: &'a Pixel<C>) -> Pixel<C> {
let mut dest = self.clone();
dest.map2(other, |x, y| x + y);
dest
}
}
impl<C: Color> std::ops::Add<Pixel<C>> for Pixel<C> {
type Output = Pixel<C>;
fn add(mut self, other: Pixel<C>) -> Pixel<C> {
self.map2(&other, |x, y| x + y);
self
}
}
impl<C: Color> std::ops::Add<Pixel<C>> for f64 {
type Output = Pixel<C>;
fn add(self, mut px: Pixel<C>) -> Pixel<C> {
px.map(|x| self + x);
px
}
}
impl<'a, C: Color> std::ops::Add<&'a Pixel<C>> for f64 {
type Output = Pixel<C>;
fn add(self, px: &'a Pixel<C>) -> Pixel<C> {
let mut px = px.clone();
px.map(|x| self + x);
px
}
}
impl<T: Type, C: Color> std::ops::Sub<T> for Pixel<C> {
type Output = Pixel<C>;
fn sub(mut self, other: T) -> Pixel<C> {
self.map(|x| x - other.to_norm());
self
}
}
impl<'a, T: Type, C: Color> std::ops::Sub<T> for &'a Pixel<C> {
type Output = Pixel<C>;
fn sub(self, other: T) -> Pixel<C> {
let mut dest = self.clone();
dest.map(|x| x - other.to_norm());
dest
}
}
impl<'a, C: Color> std::ops::Sub<&'a Pixel<C>> for &'a Pixel<C> {
type Output = Pixel<C>;
fn sub(self, other: &'a Pixel<C>) -> Pixel<C> {
let mut dest = self.clone();
dest.map2(other, |x, y| x - y);
dest
}
}
impl<'a, C: Color> std::ops::Sub<&'a Pixel<C>> for Pixel<C> {
type Output = Pixel<C>;
fn sub(mut self, other: &'a Pixel<C>) -> Pixel<C> {
self.map2(other, |x, y| x - y);
self
}
}
impl<C: Color> std::ops::Sub<Pixel<C>> for Pixel<C> {
type Output = Pixel<C>;
fn sub(mut self, other: Pixel<C>) -> Pixel<C> {
self.map2(&other, |x, y| x - y);
self
}
}
impl<C: Color> std::ops::Sub<Pixel<C>> for f64 {
type Output = Pixel<C>;
fn sub(self, mut px: Pixel<C>) -> Pixel<C> {
px.map(|x| self - x);
px
}
}
impl<'a, C: Color> std::ops::Sub<&'a Pixel<C>> for f64 {
type Output = Pixel<C>;
fn sub(self, px: &'a Pixel<C>) -> Pixel<C> {
let mut px = px.clone();
px.map(|x| self - x);
px
}
}
impl<T: Type, C: Color> std::ops::Mul<T> for Pixel<C> {
type Output = Pixel<C>;
fn mul(mut self, other: T) -> Pixel<C> {
self.map(|x| x * other.to_norm());
self
}
}
impl<'a, T: Type, C: Color> std::ops::Mul<T> for &'a Pixel<C> {
type Output = Pixel<C>;
fn mul(self, other: T) -> Pixel<C> {
let mut dest = self.clone();
dest.map(|x| x * other.to_norm());
dest
}
}
impl<'a, C: Color> std::ops::Mul<&'a Pixel<C>> for &'a Pixel<C> {
type Output = Pixel<C>;
fn mul(self, other: &'a Pixel<C>) -> Pixel<C> {
let mut dest = self.clone();
dest.map2(other, |x, y| x * y);
dest
}
}
impl<'a, C: Color> std::ops::Mul<&'a Pixel<C>> for Pixel<C> {
type Output = Pixel<C>;
fn mul(mut self, other: &'a Pixel<C>) -> Pixel<C> {
self.map2(other, |x, y| x * y).clone()
}
}
impl<C: Color> std::ops::Mul<Pixel<C>> for Pixel<C> {
type Output = Pixel<C>;
fn mul(mut self, other: Pixel<C>) -> Pixel<C> {
self.map2(&other, |x, y| x * y).clone()
}
}
impl<C: Color> std::ops::Mul<Pixel<C>> for f64 {
type Output = Pixel<C>;
fn mul(self, mut px: Pixel<C>) -> Pixel<C> {
px.map(|x| self * x);
px
}
}
impl<'a, C: Color> std::ops::Mul<&'a Pixel<C>> for f64 {
type Output = Pixel<C>;
fn mul(self, px: &'a Pixel<C>) -> Pixel<C> {
let mut px = px.clone();
px.map(|x| self * x);
px
}
}
impl<T: Type, C: Color> std::ops::Div<T> for Pixel<C> {
type Output = Pixel<C>;
fn div(mut self, other: T) -> Pixel<C> {
self.map(|x| x / other.to_norm());
self
}
}
impl<'a, T: Type, C: Color> std::ops::Div<T> for &'a Pixel<C> {
type Output = Pixel<C>;
fn div(self, other: T) -> Pixel<C> {
let mut dest = self.clone();
dest.map(|x| x / other.to_norm());
dest
}
}
impl<'a, C: Color> std::ops::Div<&'a Pixel<C>> for Pixel<C> {
type Output = Pixel<C>;
fn div(mut self, other: &'a Pixel<C>) -> Pixel<C> {
self.map2(other, |x, y| x / y);
self
}
}
impl<'a, C: Color> std::ops::Div<&'a Pixel<C>> for &'a Pixel<C> {
type Output = Pixel<C>;
fn div(self, other: &'a Pixel<C>) -> Pixel<C> {
let mut dest = self.clone();
dest.map2(other, |x, y| x / y);
dest
}
}
impl<C: Color> std::ops::Div<Pixel<C>> for Pixel<C> {
type Output = Pixel<C>;
fn div(mut self, other: Pixel<C>) -> Pixel<C> {
self.map2(&other, |x, y| x / y);
self
}
}
impl<C: Color> std::ops::Div<Pixel<C>> for f64 {
type Output = Pixel<C>;
fn div(self, mut px: Pixel<C>) -> Pixel<C> {
px.map(|x| self / x);
px
}
}
impl<'a, C: Color> std::ops::Div<&'a Pixel<C>> for f64 {
type Output = Pixel<C>;
fn div(self, px: &'a Pixel<C>) -> Pixel<C> {
let mut px = px.clone();
px.map(|x| self / x);
px
}
}
impl<T: Type, C: Color> std::ops::Rem<T> for Pixel<C> {
type Output = Pixel<C>;
fn rem(mut self, other: T) -> Pixel<C> {
self.map(|x| x % other.to_norm());
self
}
}
impl<'a, T: Type, C: Color> std::ops::Rem<T> for &'a Pixel<C> {
type Output = Pixel<C>;
fn rem(self, other: T) -> Pixel<C> {
let mut dest = self.clone();
dest.map(|x| x % other.to_norm());
dest
}
}
impl<'a, C: Color> std::ops::Rem<&'a Pixel<C>> for &'a Pixel<C> {
type Output = Pixel<C>;
fn rem(self, other: &'a Pixel<C>) -> Pixel<C> {
let mut dest = self.clone();
dest.map2(other, |x, y| x % y);
dest
}
}
impl<'a, C: Color> std::ops::Rem<&'a Pixel<C>> for Pixel<C> {
type Output = Pixel<C>;
fn rem(mut self, other: &'a Pixel<C>) -> Pixel<C> {
self.map2(other, |x, y| x % y);
self
}
}
impl<C: Color> std::ops::Rem<Pixel<C>> for Pixel<C> {
type Output = Pixel<C>;
fn rem(mut self, other: Pixel<C>) -> Pixel<C> {
self.map2(&other, |x, y| x % y);
self
}
}
impl<C: Color> std::ops::Rem<Pixel<C>> for f64 {
type Output = Pixel<C>;
fn rem(self, mut px: Pixel<C>) -> Pixel<C> {
px.map(|x| self % x);
px
}
}
impl<'a, C: Color> std::ops::Rem<&'a Pixel<C>> for f64 {
type Output = Pixel<C>;
fn rem(self, px: &'a Pixel<C>) -> Pixel<C> {
let mut px = px.clone();
px.map(|x| self % x);
px
}
}
impl<T: Type, C: Color> std::ops::AddAssign<T> for Pixel<C> {
fn add_assign(&mut self, other: T) {
self.map(|x| x + other.to_norm());
}
}
impl<C: Color> std::ops::AddAssign<Pixel<C>> for Pixel<C> {
fn add_assign(&mut self, other: Pixel<C>) {
self.map2(&other, |x, y| x + y);
}
}
impl<'a, C: Color> std::ops::AddAssign<&'a Pixel<C>> for Pixel<C> {
fn add_assign(&mut self, other: &'a Pixel<C>) {
self.map2(other, |x, y| x + y);
}
}
impl<T: Type, C: Color> std::ops::SubAssign<T> for Pixel<C> {
fn sub_assign(&mut self, other: T) {
self.map(|x| x - other.to_norm());
}
}
impl<C: Color> std::ops::SubAssign<Pixel<C>> for Pixel<C> {
fn sub_assign(&mut self, other: Pixel<C>) {
self.map2(&other, |x, y| x - y);
}
}
impl<'a, C: Color> std::ops::SubAssign<&'a Pixel<C>> for Pixel<C> {
fn sub_assign(&mut self, other: &'a Pixel<C>) {
self.map2(other, |x, y| x - y);
}
}
impl<T: Type, C: Color> std::ops::MulAssign<T> for Pixel<C> {
fn mul_assign(&mut self, other: T) {
self.map(|x| x * other.to_norm());
}
}
impl<C: Color> std::ops::MulAssign<Pixel<C>> for Pixel<C> {
fn mul_assign(&mut self, other: Pixel<C>) {
self.map2(&other, |x, y| x * y);
}
}
impl<'a, C: Color> std::ops::MulAssign<&'a Pixel<C>> for Pixel<C> {
fn mul_assign(&mut self, other: &'a Pixel<C>) {
self.map2(other, |x, y| x * y);
}
}
impl<T: Type, C: Color> std::ops::DivAssign<T> for Pixel<C> {
fn div_assign(&mut self, other: T) {
self.map(|x| x / other.to_norm());
}
}
impl<C: Color> std::ops::DivAssign<Pixel<C>> for Pixel<C> {
fn div_assign(&mut self, other: Pixel<C>) {
self.map2(&other, |x, y| x / y);
}
}
impl<'a, C: Color> std::ops::DivAssign<&'a Pixel<C>> for Pixel<C> {
fn div_assign(&mut self, other: &'a Pixel<C>) {
self.map2(other, |x, y| x / y);
}
}
impl<T: Type, C: Color> std::ops::RemAssign<T> for Pixel<C> {
fn rem_assign(&mut self, other: T) {
self.map(|x| x % other.to_norm());
}
}
impl<C: Color> std::ops::RemAssign<Pixel<C>> for Pixel<C> {
fn rem_assign(&mut self, other: Pixel<C>) {
self.map2(&other, |x, y| x % y);
}
}
impl<'a, C: Color> std::ops::RemAssign<&'a Pixel<C>> for Pixel<C> {
fn rem_assign(&mut self, other: &'a Pixel<C>) {
self.map2(other, |x, y| x % y);
}
}