add crop setting, DynamicBendable like the image crate

This commit is contained in:
Breval Ferrari 2025-01-18 22:32:21 -05:00
parent e1edc611bc
commit 3527c0a2af
No known key found for this signature in database
GPG key ID: CEAB625B75A836B2
4 changed files with 130 additions and 22 deletions

View file

@ -13,3 +13,7 @@ keywords.workspace = true
image = { version = "0.25", features = ["rayon"] } image = { version = "0.25", features = ["rayon"] }
num = "0" num = "0"
rayon = "1" rayon = "1"
infer = "0.16"
thiserror = "2.0"
derive-new = "0.7"
strum = { version = "0.26", features = ["derive"] }

View file

@ -13,7 +13,7 @@ impl IntoDataBytes for Bytes {
impl TryFromDataBytes for Bytes { impl TryFromDataBytes for Bytes {
type Error = Infallible; type Error = Infallible;
type Format = (); type Format = ();
fn try_from_bytes(bytes: Bytes, _: Self::Format) -> Result<Self, Self::Error> fn try_from_bytes(bytes: Bytes, _: Self::Format, _: crate::Crop) -> Result<Self, Self::Error>
where where
Self: Sized, Self: Sized,
{ {
@ -26,4 +26,7 @@ impl Bendable for Bytes {
fn map<F: Fn(&Self::Unit) -> Self::Unit + Sync>(self, f: F) -> Self { fn map<F: Fn(&Self::Unit) -> Self::Unit + Sync>(self, f: F) -> Self {
self.into_par_iter().map(|e| f(&e)).collect() self.into_par_iter().map(|e| f(&e)).collect()
} }
fn format() -> crate::Format {
crate::Format::Binary
}
} }

View file

@ -34,24 +34,41 @@ where
{ {
type Error = (); type Error = ();
type Format = Dimensions; type Format = Dimensions;
fn try_from_bytes(bytes: crate::Bytes, format: Self::Format) -> Result<Self, Self::Error> fn try_from_bytes(
bytes: crate::Bytes,
format: Self::Format,
crop: crate::Crop,
) -> Result<Self, Self::Error>
where where
Self: Sized, Self: Sized,
{ {
ImageBuffer::from_raw( ImageBuffer::from_raw(
format.width, format.width,
format.height, format.height,
bytes match crop {
.chunks_exact(P::Subpixel::zero().to_ne_bytes().as_ref().len()) crate::Crop::End => bytes
.map(|p| { .chunks_exact(P::Subpixel::zero().to_ne_bytes().as_ref().len())
P::Subpixel::from_ne_bytes( .map(|p| {
&match <P::Subpixel as FromBytes>::Bytes::try_from(p) { P::Subpixel::from_ne_bytes(
Ok(v) => v, &match <P::Subpixel as FromBytes>::Bytes::try_from(p) {
Err(_) => unreachable!("you messed up chunk size!"), Ok(v) => v,
}, Err(_) => unreachable!("you messed up chunk size!"),
) },
}) )
.collect::<Vec<P::Subpixel>>(), })
.collect::<Vec<P::Subpixel>>(),
crate::Crop::Start => bytes
.rchunks_exact(P::Subpixel::zero().to_ne_bytes().as_ref().len())
.map(|p| {
P::Subpixel::from_ne_bytes(
&match <P::Subpixel as FromBytes>::Bytes::try_from(p) {
Ok(v) => v,
Err(_) => unreachable!("you messed up chunk size!"),
},
)
})
.collect::<Vec<P::Subpixel>>(),
},
) )
.ok_or(()) .ok_or(())
} }
@ -69,6 +86,15 @@ where
self.par_pixels_mut().for_each(|p| *p = f(p)); self.par_pixels_mut().for_each(|p| *p = f(p));
self self
} }
fn format() -> crate::Format {
crate::Format::Image
}
}
impl IntoDataBytes for DynamicImage {
fn into_bytes(self) -> crate::Bytes {
self.into_bytes()
}
} }
#[cfg(test)] #[cfg(test)]
@ -90,7 +116,8 @@ mod tests {
Dimensions { Dimensions {
width: 0, width: 0,
height: 0 height: 0
} },
Default::default()
) )
) )
} }
@ -105,7 +132,8 @@ mod tests {
Dimensions { Dimensions {
width: 3, width: 3,
height: 1 height: 1
} },
Default::default()
) )
) )
} }
@ -121,7 +149,8 @@ mod tests {
Dimensions { Dimensions {
width: 3, width: 3,
height: 1 height: 1
} },
Default::default()
) )
) )
} }
@ -141,7 +170,8 @@ mod tests {
Dimensions { Dimensions {
width: 3, width: 3,
height: 1 height: 1
} },
Default::default()
) )
) )
} }
@ -161,7 +191,8 @@ mod tests {
Dimensions { Dimensions {
width: 3, width: 3,
height: 1 height: 1
} },
Default::default()
) )
) )
} }
@ -181,7 +212,8 @@ mod tests {
Dimensions { Dimensions {
width: 3, width: 3,
height: 1 height: 1
} },
Default::default()
) )
) )
} }

View file

@ -5,31 +5,100 @@ pub mod txt;
pub(crate) type Bytes = Vec<u8>; pub(crate) type Bytes = Vec<u8>;
pub mod dynamic {
use std::{
fs::File,
io::{self, Read},
path::Path,
};
use super::{
img::{self, DynamicImage},
Bytes,
};
use infer::MatcherType;
use strum::EnumDiscriminants;
use thiserror::Error;
#[derive(EnumDiscriminants)]
#[strum_discriminants(name(Format))]
pub enum DynamicBendable {
Image(DynamicImage),
Binary(Bytes),
Sound,
Text,
}
#[derive(Debug, Error)]
pub enum OpenError {
#[error("{0:?}")]
Io(#[from] io::Error),
#[error("{0:?}")]
Image(#[from] img::ImageError),
}
pub fn open<P: AsRef<Path>>(path: P) -> Result<Option<DynamicBendable>, OpenError> {
use MatcherType::*;
if let Some(matcher) = infer::get_from_path(&path)?.map(|t| t.matcher_type()) {
Ok(Some(match matcher {
Image => DynamicBendable::Image(img::open(path)?),
App | Archive => DynamicBendable::Binary({
let mut buf = Vec::new();
File::open(path)?.read_to_end(&mut buf)?;
buf
}),
Audio => todo!(),
Book => todo!(),
Doc => todo!(),
Font => todo!(),
Text => todo!(),
Video => todo!(),
Custom => unimplemented!("I don't even know what this is!"),
}))
} else {
Ok(None)
}
}
}
use dynamic::*;
pub trait Bendable: TryFromDataBytes + IntoDataBytes { pub trait Bendable: TryFromDataBytes + IntoDataBytes {
type Unit; type Unit;
fn bend_into<T: Bendable>( fn bend_into<T: Bendable>(
self, self,
format: <T as TryFromDataBytes>::Format, format: <T as TryFromDataBytes>::Format,
crop: Crop,
) -> Result<T, <T as TryFromDataBytes>::Error> { ) -> Result<T, <T as TryFromDataBytes>::Error> {
T::bend_from(self, format) T::bend_from(self, format, crop)
} }
fn bend_from<T: Bendable>( fn bend_from<T: Bendable>(
b: T, b: T,
format: <Self as TryFromDataBytes>::Format, format: <Self as TryFromDataBytes>::Format,
crop: Crop,
) -> Result<Self, <Self as TryFromDataBytes>::Error> { ) -> Result<Self, <Self as TryFromDataBytes>::Error> {
Self::try_from_bytes(b.into_bytes(), format) Self::try_from_bytes(b.into_bytes(), format, crop)
} }
fn map<F: Fn(&Self::Unit) -> Self::Unit + Sync>(self, f: F) -> Self; fn map<F: Fn(&Self::Unit) -> Self::Unit + Sync>(self, f: F) -> Self;
fn format() -> Format;
} }
pub trait IntoDataBytes: Sized { pub trait IntoDataBytes: Sized {
fn into_bytes(self) -> Bytes; fn into_bytes(self) -> Bytes;
} }
#[derive(Default)]
pub enum Crop {
Start,
#[default]
End,
}
pub trait TryFromDataBytes { pub trait TryFromDataBytes {
type Error; type Error;
type Format; type Format;
fn try_from_bytes(bytes: Bytes, format: Self::Format) -> Result<Self, Self::Error> fn try_from_bytes(bytes: Bytes, format: Self::Format, crop: Crop) -> Result<Self, Self::Error>
where where
Self: Sized; Self: Sized;
} }